~ubuntu-branches/ubuntu/lucid/warzone2100/lucid

« back to all changes in this revision

Viewing changes to src/gateway.c

  • Committer: Bazaar Package Importer
  • Author(s): Christoph Egger, Paul Wise, Christoph Egger
  • Date: 2009-06-29 17:12:52 UTC
  • mfrom: (1.1.11 upstream) (2.1.7 squeeze)
  • Revision ID: james.westby@ubuntu.com-20090629171252-5ddnlfg3zfchrega
Tags: 2.2.1+dfsg1-1
[ Paul Wise ]
* New upstream release (Closes: #534962)
* Adjust the flex build-depends to take account of the conflict
  with all the versions of flex 2.5.34 (LP: #372872)
* Make the -music Recommends more strict, 2.1 music doesn't work
  with 2.2.
* Upstream moved the downloads to sourceforge, update the watch file
* Bump Standards-Version, no changes needed
* Drop use of dh_desktop since it no longer does anything
* Recommend the new warzone2100-video package, version 2.2 or similar
* Mention the warzone2100 crash reports in the -dbg package description

[ Christoph Egger ]
* Replace CC-2.0 graphic from cybersphinx, create a new tarball
* Add myself to uploaders

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*
2
2
        This file is part of Warzone 2100.
3
3
        Copyright (C) 1999-2004  Eidos Interactive
4
 
        Copyright (C) 2005-2007  Warzone Resurrection Project
 
4
        Copyright (C) 2005-2009  Warzone Resurrection Project
5
5
 
6
6
        Warzone 2100 is free software; you can redistribute it and/or modify
7
7
        it under the terms of the GNU General Public License as published by
31
31
#include "wrappers.h"
32
32
 
33
33
#include "gateway.h"
34
 
#include "astar.h"
35
 
#include "fpath.h"
36
34
 
37
35
// the list of gateways on the current map
38
36
GATEWAY         *psGateways;
39
37
 
40
 
// the RLE map zones for each tile
41
 
UBYTE           **apRLEZones;
42
 
 
43
 
// the number of map zones
44
 
SDWORD          gwNumZones;
45
 
 
46
 
// The zone equivalence tables - shows which land zones
47
 
// border on a water zone
48
 
UBYTE           *aNumEquiv;
49
 
UBYTE           **apEquivZones;
50
 
 
51
 
// note which zones have a gateway to them and can therefore be reached
52
 
UBYTE           *aZoneReachable;
53
 
 
 
38
/******************************************************************************************************/
 
39
/*                   Gateway data access functions                                                    */
 
40
 
 
41
// get the size of the map
 
42
static SDWORD gwMapWidth(void)
 
43
{
 
44
        return (SDWORD)mapWidth;
 
45
}
 
46
 
 
47
static SDWORD gwMapHeight(void)
 
48
{
 
49
        return (SDWORD)mapHeight;
 
50
}
 
51
 
 
52
// set the gateway flag on a tile
 
53
static void gwSetGatewayFlag(SDWORD x, SDWORD y)
 
54
{
 
55
        mapTile((UDWORD)x,(UDWORD)y)->tileInfoBits |= BITS_GATEWAY;
 
56
}
 
57
 
 
58
// clear the gateway flag on a tile
 
59
static void gwClearGatewayFlag(SDWORD x, SDWORD y)
 
60
{
 
61
        mapTile((UDWORD)x,(UDWORD)y)->tileInfoBits &= ~BITS_GATEWAY;
 
62
}
 
63
 
 
64
 
 
65
/******************************************************************************************************/
 
66
/*                   Gateway functions                                                                */
54
67
 
55
68
// Initialise the gateway system
56
69
BOOL gwInitialise(void)
74
87
                gwFreeGateway(psGateways);
75
88
                psGateways = psNext;
76
89
        }
77
 
 
78
 
        gwFreeZoneMap();
79
 
        gwFreeEquivTable();
80
 
 
81
 
        if (aZoneReachable != NULL)
82
 
        {
83
 
                free(aZoneReachable);
84
 
                aZoneReachable = NULL;
85
 
        }
86
90
}
87
91
 
88
92
 
131
135
        psNew->y1 = (UBYTE)y1;
132
136
        psNew->x2 = (UBYTE)x2;
133
137
        psNew->y2 = (UBYTE)y2;
134
 
        psNew->zone1 = 0;
135
 
        psNew->zone2 = 0;
136
 
        psNew->psLinks = NULL;
137
138
        psNew->flags = 0;
138
139
 
139
140
        // add the gateway to the list
162
163
}
163
164
 
164
165
 
165
 
// Add a land/water link gateway to the system
166
 
BOOL gwNewLinkGateway(SDWORD x, SDWORD y)
167
 
{
168
 
        GATEWAY         *psNew;
169
 
 
170
 
        if ((x < 0) || (x >= gwMapWidth())  ||
171
 
                (y < 0) || (y >= gwMapHeight()))
172
 
        {
173
 
                ASSERT( false,"gwNewLinkGateway: invalid coordinates" );
174
 
                return false;
175
 
        }
176
 
 
177
 
        psNew = (GATEWAY*)malloc(sizeof(GATEWAY));
178
 
        if (!psNew)
179
 
        {
180
 
                debug( LOG_ERROR, "gwNewGateway: out of memory" );
181
 
                abort();
182
 
                return false;
183
 
        }
184
 
 
185
 
        // initialise the gateway
186
 
        psNew->x1 = (UBYTE)x;
187
 
        psNew->y1 = (UBYTE)y;
188
 
        psNew->x2 = (UBYTE)x;
189
 
        psNew->y2 = (UBYTE)y;
190
 
        psNew->zone1 = 0;
191
 
        psNew->zone2 = 0;
192
 
        psNew->psLinks = NULL;
193
 
        psNew->flags = GWR_WATERLINK;
194
 
 
195
 
        // add the gateway to the list
196
 
        psNew->psNext = psGateways;
197
 
        psGateways = psNew;
198
 
 
199
 
        return true;
200
 
}
201
 
 
202
 
 
203
 
static BOOL gwBlockingTile(SDWORD x,SDWORD y)
204
 
{
205
 
        MAPTILE *psTile;
206
 
 
207
 
        if (x <1 || y < 1 || x >= (SDWORD)mapWidth-1 || y >= (SDWORD)mapHeight-1)
208
 
        {
209
 
                // coords off map - auto blocking tile
210
 
                return true;
211
 
        }
212
 
 
213
 
        psTile = mapTile((UDWORD)x, (UDWORD)y);
214
 
        if (terrainType(psTile) == TER_CLIFFFACE)
215
 
        {
216
 
                return true;
217
 
        }
218
 
 
219
 
        return false;
220
 
}
221
 
 
222
 
 
223
 
// scan for a particular zone on the map
224
 
// given a start point
225
 
static BOOL gwFindZone(SDWORD zone, SDWORD cx, SDWORD cy,
226
 
                                           SDWORD *px, SDWORD *py)
227
 
{
228
 
        SDWORD  x,y, dist, maxDist;
229
 
 
230
 
        maxDist = gwMapWidth() > gwMapHeight() ? gwMapWidth() : gwMapHeight();
231
 
 
232
 
        for(dist = 0; dist < maxDist; dist += 1)
233
 
        {
234
 
                // scan accross the top
235
 
                y = cy - dist;
236
 
                for(x = cx - dist; x <= cx + dist; x += 1)
237
 
                {
238
 
                        if (x >= 0 && x < gwMapWidth() &&
239
 
                                y >= 0 && y < gwMapHeight() &&
240
 
                                gwGetZone(x,y) == zone)
241
 
                        {
242
 
                                *px = x;
243
 
                                *py = y;
244
 
                                return true;
245
 
                        }
246
 
                }
247
 
 
248
 
                // scan down the left
249
 
                x = cx - dist;
250
 
                for(y = cy - dist; y <= cy + dist; y += 1)
251
 
                {
252
 
                        if (x >= 0 && x < gwMapWidth() &&
253
 
                                y >= 0 && y < gwMapHeight() &&
254
 
                                gwGetZone(x,y) == zone)
255
 
                        {
256
 
                                *px = x;
257
 
                                *py = y;
258
 
                                return true;
259
 
                        }
260
 
                }
261
 
 
262
 
                // scan down the right
263
 
                x = cx + dist;
264
 
                for(y = cy - dist; y <= cy + dist; y += 1)
265
 
                {
266
 
                        if (x >= 0 && x < gwMapWidth() &&
267
 
                                y >= 0 && y < gwMapHeight() &&
268
 
                                gwGetZone(x,y) == zone)
269
 
                        {
270
 
                                *px = x;
271
 
                                *py = y;
272
 
                                return true;
273
 
                        }
274
 
                }
275
 
 
276
 
                // scan accross the bottom
277
 
                y = cy + dist;
278
 
                for(x = cx - dist; x <= cx + dist; x += 1)
279
 
                {
280
 
                        if (x >= 0 && x < gwMapWidth() &&
281
 
                                y >= 0 && y < gwMapHeight() &&
282
 
                                gwGetZone(x,y) == zone)
283
 
                        {
284
 
                                *px = x;
285
 
                                *py = y;
286
 
                                return true;
287
 
                        }
288
 
                }
289
 
        }
290
 
 
291
 
        return false;
292
 
}
293
 
 
294
 
 
295
 
// find a rough center position for a zone
296
 
static void gwCalcZoneCenter(SDWORD zone, SDWORD *px, SDWORD *py)
297
 
{
298
 
        SDWORD          xsum,ysum, numtiles;
299
 
        SDWORD          x,y;
300
 
 
301
 
        xsum = ysum = numtiles = 0;
302
 
        for(y=0; y<gwMapHeight(); y+= 1)
303
 
        {
304
 
                for(x=0; x<gwMapWidth(); x+= 1)
305
 
                {
306
 
                        if (gwGetZone(x,y) == zone)
307
 
                        {
308
 
                                xsum += x;
309
 
                                ysum += y;
310
 
                                numtiles += 1;
311
 
                        }
312
 
                }
313
 
        }
314
 
 
315
 
        ASSERT( numtiles != 0,
316
 
                "gwCalcZoneCenter: zone not found on map" );
317
 
 
318
 
        x = xsum / numtiles;
319
 
        y = ysum / numtiles;
320
 
 
321
 
        if (!gwFindZone(zone, x,y, px,py))
322
 
        {
323
 
                *px = x;
324
 
                *py = y;
325
 
        }
326
 
}
327
 
 
328
 
 
329
 
// check all the zones are of reasonable sizes
330
 
void gwCheckZoneSizes(void)
331
 
{
332
 
        SDWORD          zone, xsum,ysum, numtiles, inzone;
333
 
        SDWORD          x,y, cx,cy;
334
 
 
335
 
        for(zone=1; zone < UBYTE_MAX; zone += 1)
336
 
        {
337
 
                xsum = ysum = numtiles = inzone = 0;
338
 
                for(y=0; y<gwMapHeight(); y+= 1)
339
 
                {
340
 
                        for(x=0; x<gwMapWidth(); x+= 1)
341
 
                        {
342
 
                                if (gwGetZone(x,y) == zone)
343
 
                                {
344
 
                                        xsum += x;
345
 
                                        ysum += y;
346
 
                                        numtiles += 1;
347
 
                                        if (!gwBlockingTile(x,y))
348
 
                                        {
349
 
                                                inzone += 1;
350
 
                                        }
351
 
                                }
352
 
                        }
353
 
                }
354
 
 
355
 
                if (numtiles > 0)
356
 
                {
357
 
                        x = xsum / numtiles;
358
 
                        y = ysum / numtiles;
359
 
 
360
 
                        if (!gwFindZone(zone, x,y, &cx,&cy))
361
 
                        {
362
 
                                cx = x;
363
 
                                cy = y;
364
 
                        }
365
 
 
366
 
                        if (inzone > FPATH_LOOP_LIMIT)
367
 
                        {
368
 
                                debug(LOG_GATEWAY, "gwCheckZoneSizes: warning zone %d at (%d,%d) is too large %d tiles (max %d)",
369
 
                                      zone, cx, cy, inzone, FPATH_LOOP_LIMIT);
370
 
                        }
371
 
                }
372
 
        }
373
 
}
374
 
 
375
 
 
376
 
// add the land/water link gateways
377
 
BOOL gwGenerateLinkGates(void)
378
 
{
379
 
        SDWORD          zone, cx,cy;
380
 
 
381
 
        ASSERT( apEquivZones != NULL,
382
 
                "gwGenerateLinkGates: no zone equivalence table" );
383
 
 
384
 
        debug( LOG_NEVER, "Generating water link Gateways...." );
385
 
 
386
 
        for(zone=1; zone<gwNumZones; zone += 1)
387
 
        {
388
 
 
389
 
                if (aNumEquiv[zone] > 0)
390
 
                {
391
 
                        LOADBARCALLBACK();      //                      loadingScreenCallback();
392
 
 
393
 
                        // got a water zone that borders on land
394
 
                        // find it's center
395
 
                        gwCalcZoneCenter(zone, &cx,&cy);
396
 
                        if (!gwNewLinkGateway(cx,cy))
397
 
                        {
398
 
                                return false;
399
 
                        }
400
 
                        debug(LOG_GATEWAY, "new water link gateway at (%d,%d) for zone %d", cx, cy, zone);
401
 
                }
402
 
        }
403
 
 
404
 
        debug( LOG_NEVER, "Done\n" );
405
 
 
406
 
        return true;
407
 
}
408
 
 
409
 
 
410
166
// Return the number of gateways.
411
167
UDWORD gwNumGateways(void)
412
168
{
457
213
 
458
214
        }
459
215
 
460
 
        if (psDel->psLinks != NULL)
461
 
        {
462
 
                free(psDel->psLinks);
463
 
        }
464
216
        free(psDel);
465
217
}
466
218
 
495
247
 
496
248
        return true;
497
249
}
498
 
 
499
 
 
500
 
// check if a zone is in the equivalence table for a water zone
501
 
BOOL gwZoneInEquiv(SDWORD mainZone, SDWORD checkZone)
502
 
{
503
 
        SDWORD i;
504
 
 
505
 
        if (apEquivZones == NULL)
506
 
        {
507
 
                return false;
508
 
        }
509
 
 
510
 
        for(i=0; i<aNumEquiv[mainZone]; i+= 1)
511
 
        {
512
 
                if (apEquivZones[mainZone][i] == checkZone)
513
 
                {
514
 
                        return true;
515
 
                }
516
 
        }
517
 
 
518
 
        return false;
519
 
}
520
 
 
521
 
// find a route between two gateways and return
522
 
// its length
523
 
static SDWORD gwRouteLength(GATEWAY *psStart, GATEWAY *psEnd)
524
 
{
525
 
        SDWORD                  ret, sx,sy, ex,ey, xdiff,ydiff, i;
526
 
        ASTAR_ROUTE             sRoute;
527
 
        SDWORD                  routeMode, dist;
528
 
#ifdef DEBUG
529
 
        SDWORD                  zone;
530
 
#endif
531
 
 
532
 
        fpathBlockingTile = gwBlockingTile;
533
 
 
534
 
        sx = (psStart->x1 + psStart->x2)/2;
535
 
        sy = (psStart->y1 + psStart->y2)/2;
536
 
        ex = (psEnd->x1 + psEnd->x2)/2;
537
 
        ey = (psEnd->y1 + psEnd->y2)/2;
538
 
 
539
 
        // force the router to finish a route
540
 
        routeMode = ASR_NEWROUTE;
541
 
        sRoute.asPos[0].x = -1;
542
 
        sRoute.asPos[0].y = -1;
543
 
        do
544
 
        {
545
 
                astarResetCounters();
546
 
                sRoute.numPoints = 0;
547
 
                ret = fpathAStarRoute(routeMode, &sRoute,
548
 
                                        world_coord(sx), world_coord(sy),
549
 
                                        world_coord(ex), world_coord(ey));
550
 
                if (ret == ASR_PARTIAL)
551
 
                {
552
 
                        routeMode = ASR_CONTINUE;
553
 
                }
554
 
        } while (ret == ASR_PARTIAL);
555
 
 
556
 
        ASSERT( ret != ASR_FAILED,
557
 
                "gwRouteLength: no route between gateways at (%d,%d) and (%d,%d)",
558
 
                sx,sy, ex,ey );
559
 
 
560
 
#ifdef DEBUG
561
 
        if (ret == ASR_NEAREST)
562
 
        {
563
 
                zone = (psStart->zone1 == psEnd->zone1) || (psStart->zone1 == psEnd->zone2) ? psStart->zone1 : psStart->zone2;
564
 
                debug( LOG_ERROR, "gwRouteLength: warning only partial route between gateways at %s(%d,%d) and %s(%d,%d) zone %d\n", psStart->flags & GWR_WATERLINK ? "W" : "", sx,sy, psStart->flags & GWR_WATERLINK ? "W" : "", ex, ey, zone );
565
 
        }
566
 
#endif
567
 
 
568
 
        // calculate the length of the route
569
 
        dist = 0;
570
 
        for(i=0; i < sRoute.numPoints; i+= 1)
571
 
        {
572
 
                xdiff = sx - sRoute.asPos[i].x;
573
 
                ydiff = sy - sRoute.asPos[i].y;
574
 
                dist += (SDWORD)sqrtf(xdiff*xdiff + ydiff*ydiff);
575
 
                sx = sRoute.asPos[i].x;
576
 
                sy = sRoute.asPos[i].y;
577
 
        }
578
 
        xdiff = sx - ex;
579
 
        ydiff = sy - ey;
580
 
        dist += (SDWORD)sqrtf(xdiff*xdiff + ydiff*ydiff);
581
 
 
582
 
        fpathBlockingTile = fpathGroundBlockingTile;
583
 
 
584
 
        return dist;
585
 
}
586
 
 
587
 
 
588
 
// check that the initial flood fill tiles are not on a blocking tile
589
 
static BOOL gwCheckFloodTiles(GATEWAY *psGate)
590
 
{
591
 
        SDWORD  floodX,floodY;
592
 
 
593
 
        // first zone is left/above
594
 
        if (psGate->x1 == psGate->x2)
595
 
        {
596
 
                // vertical - go left
597
 
                floodX = psGate->x1 - 1;
598
 
                floodY = (psGate->y2 - psGate->y1)/2 + psGate->y1;
599
 
        }
600
 
        else
601
 
        {
602
 
                // horizontal - go above
603
 
                floodX = (psGate->x2 - psGate->x1)/2 + psGate->x1;
604
 
                floodY = psGate->y1 - 1;
605
 
        }
606
 
 
607
 
        if (gwBlockingTile(floodX,floodY))
608
 
        {
609
 
                return false;
610
 
        }
611
 
 
612
 
        // second zone is right/below
613
 
        if (psGate->x1 == psGate->x2)
614
 
        {
615
 
                // vertical - go right
616
 
                floodX = psGate->x1 + 1;
617
 
                floodY = (psGate->y2 - psGate->y1)/2 + psGate->y1;
618
 
        }
619
 
        else
620
 
        {
621
 
                // horizontal - go below
622
 
                floodX = (psGate->x2 - psGate->x1)/2 + psGate->x1;
623
 
                floodY = psGate->y1 + 1;
624
 
        }
625
 
 
626
 
        if (gwBlockingTile(floodX,floodY))
627
 
        {
628
 
                return false;
629
 
        }
630
 
 
631
 
        return true;
632
 
}
633
 
 
634
 
 
635
 
// link all the gateways together
636
 
BOOL gwLinkGateways(void)
637
 
{
638
 
        GATEWAY         *psCurr, *psLink;
639
 
        SDWORD          x,y, gwX,gwY, zone1Links,zone2Links, link, zone, otherZone;
640
 
        SDWORD          zoneLinks;
641
 
        BOOL            bZone1, bAddLink;
642
 
 
643
 
 
644
 
        // note which zones have a gateway
645
 
        aZoneReachable = (UBYTE*)malloc( sizeof(UBYTE) * gwNumZones );
646
 
        if (aZoneReachable == NULL)
647
 
        {
648
 
                debug( LOG_ERROR, "gwLinkGateways: out of memory" );
649
 
                abort();
650
 
                return false;
651
 
        }
652
 
        memset(aZoneReachable, 0, sizeof(UBYTE) * gwNumZones);
653
 
 
654
 
        // initialise the zones for the gateways
655
 
        for(psCurr = psGateways; psCurr; psCurr = psCurr->psNext)
656
 
        {
657
 
                // a gateway is always in it's own zone1
658
 
                psCurr->zone1 = (UBYTE)gwGetZone(psCurr->x1,psCurr->y1);
659
 
 
660
 
                if (psCurr->flags & GWR_WATERLINK)
661
 
                {
662
 
                        // a water link gateway is only in one zone
663
 
                        x = psCurr->x1;
664
 
                        y = psCurr->y1;
665
 
                }
666
 
                else if (psCurr->x1 == psCurr->x2)
667
 
                {
668
 
                        // vertical - go right
669
 
                        x = psCurr->x1 + 1;
670
 
                        y = (psCurr->y2 - psCurr->y1)/2 + psCurr->y1;
671
 
                }
672
 
                else
673
 
                {
674
 
                        // horizontal - go below
675
 
                        x = (psCurr->x2 - psCurr->x1)/2 + psCurr->x1;
676
 
                        y = psCurr->y1 + 1;
677
 
                }
678
 
                psCurr->zone2 = (UBYTE)gwGetZone(x,y);
679
 
 
680
 
                ASSERT( (psCurr->flags & GWR_WATERLINK) || gwCheckFloodTiles(psCurr),
681
 
                        "gwLinkGateways: Gateway at (%d,%d)->(%d,%d) is too close to a blocking tile. Zones %d, %d",
682
 
                        psCurr->x1,psCurr->y1, psCurr->x2,psCurr->y2,
683
 
                        psCurr->zone1, psCurr->zone2 );
684
 
 
685
 
                aZoneReachable[psCurr->zone1] = true;
686
 
                aZoneReachable[psCurr->zone2] = true;
687
 
        }
688
 
 
689
 
        // now link all the gateways together
690
 
        for(psCurr = psGateways; psCurr; psCurr = psCurr->psNext)
691
 
        {
692
 
                LOADBARCALLBACK();      //              loadingScreenCallback();
693
 
 
694
 
                gwX = (psCurr->x1 + psCurr->x2)/2;
695
 
                gwY = (psCurr->y1 + psCurr->y2)/2;
696
 
 
697
 
                // count the number of links
698
 
                zone1Links = 0;
699
 
                zone2Links = 0;
700
 
                for(psLink=psGateways; psLink; psLink=psLink->psNext)
701
 
                {
702
 
                        if (psLink == psCurr)
703
 
                        {
704
 
                                // don't link a gateway to itself
705
 
                                continue;
706
 
                        }
707
 
                        if ((psLink->zone1 == psCurr->zone1) || (psLink->zone2 == psCurr->zone1) ||
708
 
                                ((psLink->flags & GWR_WATERLINK) &&
709
 
                                 gwZoneInEquiv(psLink->zone1, psCurr->zone1) &&
710
 
                                 !gwZoneInEquiv(psLink->zone1, psCurr->zone2) ))
711
 
                        {
712
 
                                zone1Links += 1;
713
 
                        }
714
 
                        if (psCurr->flags & GWR_WATERLINK)
715
 
                        {
716
 
                                // calculating links for a water link gateway
717
 
                                if (gwZoneInEquiv(psCurr->zone1, psLink->zone1) ||
718
 
                                        gwZoneInEquiv(psCurr->zone1, psLink->zone2))
719
 
                                {
720
 
                                        zone2Links += 1;
721
 
                                }
722
 
                        }
723
 
                        else if ((psLink->zone1 == psCurr->zone2) || (psLink->zone2 == psCurr->zone2) ||
724
 
                                ((psLink->flags & GWR_WATERLINK) &&
725
 
                                 gwZoneInEquiv(psLink->zone1, psCurr->zone2) &&
726
 
                                 !gwZoneInEquiv(psLink->zone1, psCurr->zone1) ))
727
 
                        {
728
 
                                zone2Links += 1;
729
 
                        }
730
 
                }
731
 
                if (zone1Links+zone2Links > 0)
732
 
                {
733
 
                        psCurr->psLinks = (GATEWAY_LINK*)malloc(sizeof(GATEWAY_LINK) * (zone1Links+zone2Links));
734
 
                        if (psCurr->psLinks == NULL)
735
 
                        {
736
 
                                debug( LOG_ERROR, "gwLinkGateways: out of memory" );
737
 
                                abort();
738
 
                                return false;
739
 
                        }
740
 
                }
741
 
                else
742
 
                {
743
 
                        psCurr->psLinks = NULL;
744
 
                }
745
 
                psCurr->zone1Links = (UBYTE)zone1Links;
746
 
                psCurr->zone2Links = (UBYTE)zone2Links;
747
 
 
748
 
                // generate the links starting with all those through zone1
749
 
                link = 0;
750
 
                zone = psCurr->zone1;
751
 
                otherZone = psCurr->zone2;
752
 
                zoneLinks = zone1Links;
753
 
                bZone1 = true;
754
 
                while (link < (zone1Links + zone2Links))
755
 
                {
756
 
                        for(psLink=psGateways; psLink && (link < zoneLinks); psLink=psLink->psNext)
757
 
                        {
758
 
                                if (psLink == psCurr)
759
 
                                {
760
 
                                        // don't link a gateway to itself
761
 
                                        continue;
762
 
                                }
763
 
                                bAddLink = false;
764
 
                                if (!bZone1 && (psCurr->flags & GWR_WATERLINK))
765
 
                                {
766
 
                                        // calculating links for a water link gateway
767
 
                                        if (gwZoneInEquiv(psCurr->zone1, psLink->zone1) ||
768
 
                                                gwZoneInEquiv(psCurr->zone1, psLink->zone2))
769
 
                                        {
770
 
                                                bAddLink = true;
771
 
                                        }
772
 
                                }
773
 
                                else if ((psLink->zone1 == zone) || (psLink->zone2 == zone) ||
774
 
                                                 ((psLink->flags & GWR_WATERLINK) &&
775
 
                                                  gwZoneInEquiv(psLink->zone1, zone) &&
776
 
                                                  !gwZoneInEquiv(psLink->zone1, otherZone) ))
777
 
                                {
778
 
                                        bAddLink = true;
779
 
                                }
780
 
 
781
 
                                if (bAddLink)
782
 
                                {
783
 
//                                      debug( LOG_NEVER, "Linking %sgateway (%d,%d)->(%d,%d) through %s to gateway (%d,%d)->(%d,%d)\n", (psCurr->flags & GWR_WATERLINK) ? "water " : "", psCurr->x1,psCurr->y1, psCurr->x2, psCurr->y2, bZone1 ? "zone1" : "zone2", psLink->x1, psLink->y1, psLink->x2, psLink->y2 );
784
 
                                        psCurr->psLinks[link].psGateway = psLink;
785
 
                                        psCurr->psLinks[link].flags = 0;
786
 
 
787
 
                                        psCurr->psLinks[link].dist = (SWORD)gwRouteLength(psCurr, psLink);
788
 
 
789
 
                                        link += 1;
790
 
                                }
791
 
                        }
792
 
 
793
 
                        // found all the links to zone1, now do it for zone2
794
 
                        zone = psCurr->zone2;
795
 
                        otherZone = psCurr->zone1;
796
 
                        zoneLinks = zone1Links + zone2Links;
797
 
                        bZone1 = false;
798
 
                }
799
 
        }
800
 
 
801
 
        return true;
802
 
}
803
 
 
804
 
 
805
 
/******************************************************************************************************/
806
 
/*                            RLE Zone data access functions                                          */
807
 
 
808
 
 
809
 
// Get number of zone lines.
810
 
UDWORD gwNumZoneLines(void)
811
 
{
812
 
        return gwMapHeight();
813
 
}
814
 
 
815
 
 
816
 
// Get the size of a zone line.
817
 
UDWORD gwZoneLineSize(UDWORD Line)
818
 
{
819
 
        UBYTE *pCode;
820
 
        UDWORD pos = 0;
821
 
        UDWORD x = 0;
822
 
 
823
 
        ASSERT( Line < (UDWORD)gwMapHeight(),"gwNewZoneLine : Invalid line requested" );
824
 
        ASSERT( apRLEZones != NULL,"gwNewZoneLine : NULL Zone map" );
825
 
 
826
 
        pCode = apRLEZones[Line];
827
 
 
828
 
        while (x < (UDWORD)gwMapWidth()) {
829
 
                x += pCode[pos];
830
 
                pos += 2;
831
 
        }
832
 
 
833
 
        return pos;
834
 
}
835
 
 
836
 
 
837
 
// Create a new empty zone map but don't allocate the actual zones yet.
838
 
//
839
 
BOOL gwNewZoneMap(void)
840
 
{
841
 
        UWORD i;
842
 
 
843
 
        if (apRLEZones != NULL)
844
 
        {
845
 
                gwFreeZoneMap();
846
 
        }
847
 
 
848
 
        apRLEZones = (UBYTE**)malloc(sizeof(UBYTE *) * gwMapHeight());
849
 
        if (apRLEZones == NULL)
850
 
        {
851
 
                debug( LOG_ERROR, "gwNewZoneMap: Out of memory" );
852
 
                abort();
853
 
                return false;
854
 
        }
855
 
 
856
 
        for(i=0; i< gwMapHeight(); i++)
857
 
        {
858
 
                apRLEZones[i] = NULL;
859
 
        }
860
 
 
861
 
        return true;
862
 
}
863
 
 
864
 
// Create a new empty zone map line in the zone map.
865
 
//
866
 
UBYTE * gwNewZoneLine(UDWORD Line,UDWORD Size)
867
 
{
868
 
        ASSERT( Line < (UDWORD)gwMapHeight(),"gwNewZoneLine : Invalid line requested" );
869
 
        ASSERT( apRLEZones != NULL,"gwNewZoneLine : NULL Zone map" );
870
 
 
871
 
        if(apRLEZones[Line] != NULL) {
872
 
                free(apRLEZones[Line]);
873
 
        }
874
 
 
875
 
        apRLEZones[Line] = (UBYTE*)malloc(Size);
876
 
        if (apRLEZones[Line] == NULL)
877
 
        {
878
 
                debug( LOG_ERROR, "gwNewZoneLine: Out of memory" );
879
 
                abort();
880
 
                return NULL;
881
 
        }
882
 
 
883
 
        return apRLEZones[Line];
884
 
}
885
 
 
886
 
 
887
 
// Create a NULL zone map for when there is no zone info loaded
888
 
BOOL gwCreateNULLZoneMap(void)
889
 
{
890
 
        SDWORD  y;
891
 
        UBYTE   *pBuf;
892
 
 
893
 
        if (!gwNewZoneMap())
894
 
        {
895
 
                return false;
896
 
        }
897
 
 
898
 
        for(y=0; y<gwMapHeight(); y++)
899
 
        {
900
 
                pBuf = gwNewZoneLine(y, 2);
901
 
                if (!pBuf)
902
 
                {
903
 
                        return false;
904
 
                }
905
 
                pBuf[0] = (UBYTE)gwMapWidth();
906
 
                pBuf[1] = 0;
907
 
        }
908
 
 
909
 
        return true;
910
 
}
911
 
 
912
 
 
913
 
// release the RLE Zone map
914
 
void gwFreeZoneMap(void)
915
 
{
916
 
        SDWORD  i;
917
 
 
918
 
        if (apRLEZones)
919
 
        {
920
 
                for(i=0; i<gwMapHeight(); i++)
921
 
                {
922
 
                        free(apRLEZones[i]);
923
 
                }
924
 
                free(apRLEZones);
925
 
                apRLEZones = NULL;
926
 
        }
927
 
}
928
 
 
929
 
 
930
 
// Look up the zone for a coordinate
931
 
SDWORD gwGetZone(SDWORD x, SDWORD y)
932
 
{
933
 
        ASSERT( x >= 0 && x < gwMapWidth() && y >= 0 && y < gwMapHeight(), "gwGetZone: invalid coordinates" );
934
 
 
935
 
        if ( x >= 0 && x < gwMapWidth() && y >= 0 && y < gwMapHeight() )
936
 
        {
937
 
                SDWORD xPos = 0, zone = 0, rlePos = 0;
938
 
 
939
 
                do
940
 
                {
941
 
                        xPos += apRLEZones[y][rlePos];
942
 
                        zone  = apRLEZones[y][rlePos + 1];
943
 
                        rlePos += 2;
944
 
                } while (xPos <= x); // xPos is where the next zone starts
945
 
 
946
 
                return zone;
947
 
        }
948
 
        else
949
 
        {
950
 
                return 0;
951
 
        }
952
 
}
953
 
 
954
 
 
955
 
/******************************************************************************************************/
956
 
/*                   Zone equivalence data access functions                                           */
957
 
 
958
 
 
959
 
// create an empty equivalence table
960
 
BOOL gwNewEquivTable(SDWORD numZones)
961
 
{
962
 
        SDWORD  i;
963
 
 
964
 
        ASSERT( numZones < UBYTE_MAX,
965
 
                "gwNewEquivTable: invalid number of zones" );
966
 
 
967
 
        gwNumZones = numZones;
968
 
        aNumEquiv = (UBYTE*)malloc(sizeof(UBYTE) * numZones);
969
 
        if (aNumEquiv == NULL)
970
 
        {
971
 
                debug( LOG_ERROR, "gwNewEquivTable: out of memory" );
972
 
                abort();
973
 
                return false;
974
 
        }
975
 
        for(i=0; i<numZones; i+=1)
976
 
        {
977
 
                aNumEquiv[i] = 0;
978
 
        }
979
 
 
980
 
        apEquivZones = (UBYTE**)malloc(sizeof(UBYTE *) * numZones);
981
 
        if (apEquivZones == NULL)
982
 
        {
983
 
                debug( LOG_ERROR, "gwNewEquivTable: out of memory" );
984
 
                abort();
985
 
                return false;
986
 
        }
987
 
        for(i=0; i<numZones; i+=1)
988
 
        {
989
 
                apEquivZones[i] = NULL;
990
 
        }
991
 
 
992
 
        return true;
993
 
}
994
 
 
995
 
// release the equivalence table
996
 
void gwFreeEquivTable(void)
997
 
{
998
 
        SDWORD i;
999
 
 
1000
 
        if (aNumEquiv)
1001
 
        {
1002
 
                free(aNumEquiv);
1003
 
                aNumEquiv = NULL;
1004
 
        }
1005
 
 
1006
 
        if (apEquivZones)
1007
 
        {
1008
 
                for(i=0; i<gwNumZones; i+=1)
1009
 
                {
1010
 
                        if (apEquivZones[i])
1011
 
                        {
1012
 
                                free(apEquivZones[i]);
1013
 
                        }
1014
 
                }
1015
 
                free(apEquivZones);
1016
 
                apEquivZones = NULL;
1017
 
        }
1018
 
        gwNumZones = 0;
1019
 
}
1020
 
 
1021
 
 
1022
 
// set the zone equivalence for a zone
1023
 
BOOL gwSetZoneEquiv(SDWORD zone, SDWORD numEquiv, UBYTE *pEquiv)
1024
 
{
1025
 
        SDWORD i;
1026
 
 
1027
 
        ASSERT( aNumEquiv != NULL && apEquivZones != NULL,
1028
 
                "gwSetZoneEquiv: equivalence arrays not initialised" );
1029
 
        ASSERT( zone < gwNumZones,
1030
 
                "gwSetZoneEquiv: invalid zone" );
1031
 
        ASSERT( numEquiv <= gwNumZones,
1032
 
                "gwSetZoneEquiv: invalid number of zone equivalents" );
1033
 
 
1034
 
        apEquivZones[zone] = (UBYTE*)malloc(sizeof(UBYTE) * numEquiv);
1035
 
        if (apEquivZones[zone] == NULL)
1036
 
        {
1037
 
                debug( LOG_ERROR, "gwSetZoneEquiv: out of memory" );
1038
 
                abort();
1039
 
                return false;
1040
 
        }
1041
 
 
1042
 
        aNumEquiv[zone] = (UBYTE)numEquiv;
1043
 
        for(i=0; i<numEquiv; i+=1)
1044
 
        {
1045
 
                apEquivZones[zone][i] = pEquiv[i];
1046
 
        }
1047
 
 
1048
 
        return true;
1049
 
}
1050
 
 
1051
 
 
1052
 
/******************************************************************************************************/
1053
 
/*                   Gateway data access functions                                                    */
1054
 
 
1055
 
// get the size of the map
1056
 
SDWORD gwMapWidth(void)
1057
 
{
1058
 
        return (SDWORD)mapWidth;
1059
 
}
1060
 
 
1061
 
SDWORD gwMapHeight(void)
1062
 
{
1063
 
        return (SDWORD)mapHeight;
1064
 
}
1065
 
 
1066
 
// set the gateway flag on a tile
1067
 
void gwSetGatewayFlag(SDWORD x, SDWORD y)
1068
 
{
1069
 
        mapTile((UDWORD)x,(UDWORD)y)->tileInfoBits |= BITS_GATEWAY;
1070
 
}
1071
 
 
1072
 
// clear the gateway flag on a tile
1073
 
void gwClearGatewayFlag(SDWORD x, SDWORD y)
1074
 
{
1075
 
        mapTile((UDWORD)x,(UDWORD)y)->tileInfoBits &= ~BITS_GATEWAY;
1076
 
}
1077
 
 
1078
 
// check whether a tile is water
1079
 
BOOL gwTileIsWater(UDWORD x, UDWORD y)
1080
 
{
1081
 
        return terrainType(mapTile(x ,y)) == TER_WATER;
1082
 
}
1083
 
 
1084
 
// see if a zone is reachable
1085
 
BOOL gwZoneReachable(SDWORD zone)
1086
 
{
1087
 
        ASSERT( zone >= 0 && zone < gwNumZones,
1088
 
                "gwZoneReachable: invalid zone" );
1089
 
 
1090
 
        return aZoneReachable[zone];
1091
 
}