112
99
/* Number of entries in the sqrt(1/(1+x*x)) table for aaLine */
113
100
#define ROOT_TABLE_SIZE 1024
115
/* aaLine direction bits and tables */
116
#define DIR_STEEP 1 /* set when abs(dy) > abs(dx) */
117
#define DIR_NEGY 2 /* set whey dy < 0 */
119
102
/* The size and contents of the map */
120
103
UDWORD mapWidth = 0, mapHeight = 0;
121
104
MAPTILE *psMapTiles = NULL;
148
131
if (width*height > MAP_MAXAREA)
150
debug( LOG_ERROR, "mapNew: map too large : %d %d\n", width, height );
133
debug(LOG_ERROR, "map too large : %u %u", width, height);
138
psMapTiles = calloc(width * height, sizeof(MAPTILE));
139
if (psMapTiles == NULL)
141
debug(LOG_ERROR, "Out of memory");
155
psMapTiles = calloc(width * height, sizeof(MAPTILE));
156
ASSERT(psMapTiles != NULL, "mapNew: Out of memory")
158
146
psTile = psMapTiles;
159
147
for (i = 0; i < width * height; i++)
187
175
static BOOL mapLoadV3(char *pFileData, UDWORD fileSize)
190
MAP_SAVETILEV2 *psTileData;
178
MAP_SAVETILE *psTileData;
191
179
GATEWAY_SAVEHEADER *psGateHeader;
192
180
GATEWAY_SAVE *psGate;
193
ZONEMAP_SAVEHEADER *psZoneHeader;
198
182
/* Load in the map data */
199
psTileData = (MAP_SAVETILEV2 *)(pFileData + SAVE_HEADER_SIZE);
183
psTileData = (MAP_SAVETILE *)(pFileData + SAVE_HEADER_SIZE);
200
184
for(i=0; i< mapWidth * mapHeight; i++)
203
187
endian_uword(&psTileData->texture);
205
189
psMapTiles[i].texture = psTileData->texture;
223
207
for(i=0; i<psGateHeader->numGateways; i++) {
224
208
if (!gwNewGateway(psGate->x0,psGate->y0, psGate->x1,psGate->y1)) {
225
209
debug( LOG_ERROR, "mapLoadV3: Unable to add gateway" );
232
psZoneHeader = (ZONEMAP_SAVEHEADER*)psGate;
234
/* ZONEMAP_SAVEHEADER */
235
endian_uword(&psZoneHeader->version);
236
endian_uword(&psZoneHeader->numZones);
237
endian_uword(&psZoneHeader->numEquivZones);
238
endian_uword(&psZoneHeader->pad);
240
ASSERT(psZoneHeader->version == 1
241
|| psZoneHeader->version == 2
242
|| psZoneHeader->version == 3, "Invalid zone map version: %u", psZoneHeader->version);
244
/* Special case due to r4637: a version 2 with numZones and
245
* numEquivZones set to zero is actually version 3.
247
if (psZoneHeader->version == 2
248
&& psZoneHeader->numZones == 0
249
&& psZoneHeader->numEquivZones == 0)
251
psZoneHeader->version = 3;
254
if(!gwNewZoneMap()) {
258
// This is a bit nasty but should work fine.
259
if (psZoneHeader->version == 1)
261
// version 1 so add the size of a version 1 header.
262
pZone = ((UBYTE*)psZoneHeader) + sizeof(ZONEMAP_SAVEHEADER_V1);
264
else if (psZoneHeader->version == 2)
266
// version 2 so add the size of a version 2 header.
267
pZone = ((UBYTE*)psZoneHeader) + sizeof(ZONEMAP_SAVEHEADER);
269
/* Loading of savegames with ZONEMAP_SAVEHEADER structure versions of 3
270
* or larger is not supported (and for version 3 cannot be supported as
271
* long as we depend on zones).
273
else if (psZoneHeader->version == 3)
275
debug(LOG_ERROR, "Unsupported savegame (zone map version 3): this savegame cannot be loaded with this version of warzone because \"zone map\" version 3 fails to provide required data. NOTE: Warzone 2100 2.2 will most likely support this savegame anyway.");
283
for(i=0; i<psZoneHeader->numZones; i++) {
284
ZoneSize = *((UWORD*)(pZone));
285
endian_uword(&ZoneSize);
287
pDestZone = gwNewZoneLine(i,ZoneSize);
289
if(pDestZone == NULL) {
293
for(j=0; j<ZoneSize; j++) {
294
pDestZone[j] = pZone[2+j];
300
// Version 2 has the zone equivelancy lists tacked on the end.
301
if(psZoneHeader->version == 2) {
303
if(psZoneHeader->numEquivZones > 0) {
304
// Load in the zone equivelance lists.
305
if(!gwNewEquivTable(psZoneHeader->numEquivZones)) {
306
debug( LOG_ERROR, "gwNewEquivTable failed" );
311
for(i=0; i<psZoneHeader->numEquivZones; i++) {
313
if(!gwSetZoneEquiv(i, (SDWORD)*pZone, pZone+1)) {
314
debug( LOG_ERROR, "gwSetZoneEquiv failed" );
319
pZone += ((UDWORD)*pZone)+1;
324
if ((char *)pZone - pFileData > fileSize)
326
debug( LOG_ERROR, "mapLoadV3: unexpected end of file" );
331
LOADBARCALLBACK(); // loadingScreenCallback();
333
if ((apEquivZones != NULL) &&
334
!gwGenerateLinkGates())
339
LOADBARCALLBACK(); // loadingScreenCallback();
341
//add new map initialise
342
if (!gwLinkGateways())
347
LOADBARCALLBACK(); // loadingScreenCallback();
379
241
/* Check the file version */
380
242
if (psHeader->version <= VERSION_9)
382
ASSERT(false, "MapLoad: unsupported save format version %d", psHeader->version);
244
ASSERT(false, "Unsupported save format version %d", psHeader->version);
386
248
else if (psHeader->version > CURRENT_VERSION_NUM)
388
ASSERT(false, "MapLoad: undefined save format version %d", psHeader->version);
250
ASSERT(false, "Undefined save format version %d", psHeader->version);
407
269
/* Allocate the memory for the map */
408
270
psMapTiles = calloc(width * height, sizeof(MAPTILE));
409
ASSERT(psMapTiles != NULL, "mapLoad: Out of memory" );
271
ASSERT(psMapTiles != NULL, "Out of memory" );
411
273
mapWidth = width;
412
274
mapHeight = height;
414
276
//load in the map data itself
415
if (!mapLoadV3(pFileData, fileSize))
277
mapLoadV3(pFileData, fileSize);
496
357
for (i = 0; i < num; i++)
498
359
tagWrite(0x01, asWeaps[i].nStat);
499
tagWrite(0x02, rotation[i]);
500
tagWrite(0x03, pitch[i]);
501
tagWrite(0x04, asWeaps[i].hitPoints);
360
tagWrite(0x02, asWeaps[i].rotation);
361
tagWrite(0x03, asWeaps[i].pitch);
502
362
tagWrite(0x05, asWeaps[i].ammo);
503
363
tagWrite(0x06, asWeaps[i].lastFired);
504
364
tagWrite(0x07, asWeaps[i].recoilValue);
523
383
objectSaveTagged((BASE_OBJECT *)psDroid); /* 0x01 */
524
384
objectSensorTagged(psDroid->sensorRange, psDroid->sensorPower, 0, psDroid->ECMMod); /* 0x02 */
525
385
objectStatTagged((BASE_OBJECT *)psDroid, psDroid->originalBody, psDroid->resistance); /* 0x03 */
526
objectWeaponTagged(psDroid->numWeaps, psDroid->turretRotation, psDroid->turretPitch, psDroid->asWeaps, psDroid->psActionTarget);
386
objectWeaponTagged(psDroid->numWeaps, psDroid->asWeaps, psDroid->psActionTarget);
528
388
/* DROID GROUP */
530
390
tagWriteEnter(0x0a, 1);
531
391
tagWrite(0x01, psDroid->droidType);
532
for (i = 0; i < DROID_MAXCOMP; i++)
392
for (i = 0; i < ARRAY_SIZE(v); ++i)
534
394
v[i] = psDroid->asBits[i].nStat;
536
tagWrite16v(0x02, DROID_MAXCOMP, v);
396
tagWrite16v(0x02, ARRAY_SIZE(v), v);
537
397
// transporter droid in the mission list
538
398
if (psDroid->droidType == DROID_TRANSPORTER && apsDroidLists[plr] == mission.apsDroidLists[plr])
645
505
objectSaveTagged((BASE_OBJECT *)psStruct); /* 0x01 */
646
506
objectSensorTagged(psStruct->sensorRange, psStruct->sensorPower, 0, psStruct->ECMMod); /* 0x02 */
647
507
objectStatTagged((BASE_OBJECT *)psStruct, psStruct->pStructureType->bodyPoints, psStruct->resistance); /* 0x03 */
648
objectWeaponTagged(psStruct->numWeaps, psStruct->turretRotation, psStruct->turretPitch, psStruct->asWeaps, psStruct->psTarget);
508
objectWeaponTagged(psStruct->numWeaps, psStruct->asWeaps, psStruct->psTarget);
650
510
/* STRUCTURE GROUP */
865
725
tagWrite(0x03, TRI_FLIPPED(psTile));
866
726
tagWrite(0x04, psTile->texture & TILE_XFLIP);
867
727
tagWrite(0x05, psTile->texture & TILE_YFLIP);
868
tagWrite(0x06, TILE_IS_NOTBLOCKING(psTile));
728
tagWrite(0x06, TileIsNotBlocking(psTile)); // Redundant, since already included in tileInfoBits
869
729
tagWrite(0x08, psTile->height);
870
730
tagWrite(0x09, psTile->tileVisBits);
871
731
tagWrite(0x0a, psTile->tileInfoBits);
732
tagWrite(0x0b, (psTile->texture & TILE_ROTMASK) >> TILE_ROTSHIFT);
1100
961
tagWriteLeave(0x0f);
1102
tagWriteEnter(0x10, gwNumZoneLines()); // gateway zone lines
1103
for (i = 0; i < gwNumZoneLines(); i++)
1105
// binary blob for now... ugh, this is ugly, but no worse than it was
1106
tagWrite(0x01, gwZoneLineSize(i));
1107
tagWrite8v(0x02, gwZoneLineSize(i), apRLEZones[i]);
1110
tagWriteLeave(0x10);
1112
tagWriteEnter(0x11, gwNumZones); // gateway equivalency zones
1113
for (i = 0; i < gwNumZones; i++)
1115
tagWrite(0x01, aNumEquiv[i]);
1118
// another ugly blob job
1119
tagWrite8v(0x02, aNumEquiv[i], apEquivZones[i]);
1123
tagWriteLeave(0x11);
1218
1054
*pFileSize = SAVE_HEADER_SIZE + mapWidth*mapHeight * SAVE_TILE_SIZE;
1219
1055
// Add on the size of the gateway data.
1220
1056
*pFileSize += sizeof(GATEWAY_SAVEHEADER) + sizeof(GATEWAY_SAVE)*numGateways;
1221
// Add on the size of the zone data header.
1057
// Add on the size of the zone data header. For backwards compatibility.
1222
1058
*pFileSize += sizeof(ZONEMAP_SAVEHEADER);
1223
// Add on the size of the zone data.
1224
for(i=0; i<gwNumZoneLines(); i++) {
1225
*pFileSize += 2+gwZoneLineSize(i);
1227
// Add on the size of the equivalency lists.
1228
for(i=0; i<(UDWORD)gwNumZones; i++) {
1229
*pFileSize += 1+aNumEquiv[i];
1232
1060
*ppFileData = (char*)malloc(*pFileSize);
1233
1061
if (*ppFileData == NULL)
1308
1133
endian_uword(&psZoneHeader->numEquivZones);
1309
1134
endian_uword(&psZoneHeader->pad);
1311
// Put the zone data.
1312
psZone = (UBYTE*)(psZoneHeader+1);
1313
for(i=0; i<gwNumZoneLines(); i++) {
1314
psLastZone = psZone;
1315
*((UWORD*)psZone) = (UWORD)gwZoneLineSize(i);
1316
endian_uword(((UWORD *) psZone));
1318
psZone += sizeof(UWORD);
1319
memcpy(psZone,apRLEZones[i],gwZoneLineSize(i));
1320
psZone += gwZoneLineSize(i);
1323
// Put the equivalency lists.
1324
if(gwNumZones > 0) {
1325
for(i=0; i<(UDWORD)gwNumZones; i++) {
1326
psLastZone = psZone;
1327
*psZone = aNumEquiv[i];
1330
memcpy(psZone,apEquivZones[i],aNumEquiv[i]);
1331
psZone += aNumEquiv[i];
1336
ASSERT( (intptr_t)psLastZone - (intptr_t)*ppFileData < (intptr_t)*pFileSize, "Buffer overflow saving map" );
1361
1159
ASSERT(x >= 0, "map_Height: Negative x value");
1362
1160
ASSERT(y >= 0, "map_Height: Negative y value");
1364
x = x >= world_coord(mapWidth) ? world_coord(mapWidth - 1) : x;
1365
y = y >= world_coord(mapHeight) ? world_coord(mapHeight - 1) : y;
1162
x = (x >= world_coord(mapWidth) ? world_coord(mapWidth - 1) : x);
1163
y = (y >= world_coord(mapHeight) ? world_coord(mapHeight - 1) : y);
1367
1165
/* Turn into tile coordinates */
1368
1166
tileX = map_coord(x);
1689
1487
static void astarTest(const char *name, int x1, int y1, int x2, int y2)
1693
1491
int x = world_coord(x1);
1694
1492
int y = world_coord(y1);
1695
1493
int endx = world_coord(x2);
1696
1494
int endy = world_coord(y2);
1698
1496
clock_t start = clock();
1702
1499
retval = levLoadData(name, NULL, 0);
1703
1500
ASSERT(retval, "Could not load %s", name);
1501
route.asPath = NULL;
1705
1502
for (i = 0; i < 100; i++)
1708
1506
route.numPoints = 0;
1709
1507
astarResetCounters();
1710
ASSERT(astarInner == 0, "astarInner not reset");
1711
asret = fpathAStarRoute(ASR_NEWROUTE, &route, x, y, endx, endy);
1712
while (asret == ASR_PARTIAL)
1714
astarResetCounters();
1715
ASSERT(astarInner == 0, "astarInner not reset");
1716
asret = fpathAStarRoute(ASR_CONTINUE, &route, x, y, endx, endy);
1512
job.propulsion = PROPULSION_TYPE_WHEELED;
1514
asret = fpathAStarRoute(&route, &job);
1516
route.asPath = NULL;
1720
1518
stop = clock();
1721
fprintf(stdout, "\t\tPath-finding timing %s: %.02f (%d nodes, %d iterations)\n", name,
1722
(double)(stop - start) / (double)CLOCKS_PER_SEC, route.numPoints, iterations);
1519
fprintf(stdout, "\t\tA* timing %s: %.02f (%d nodes)\n", name,
1520
(double)(stop - start) / (double)CLOCKS_PER_SEC, route.numPoints);
1522
fpathTest(x, y, endx, endy);
1524
fprintf(stdout, "\t\tfPath timing %s: %.02f (%d nodes)\n", name,
1525
(double)(stop - start) / (double)CLOCKS_PER_SEC, route.numPoints);
1526
retval = levReleaseAll();
1733
1537
fprintf(stdout, "\tMap self-test: PASSED\n");
1541
/** Check if tile contained within the given world coordinates is burning. */
1542
bool fireOnLocation(unsigned int x, unsigned int y)
1544
const int posX = map_coord(x);
1545
const int posY = map_coord(y);
1546
const MAPTILE *psTile = mapTile(posX, posY);
1548
ASSERT(psTile, "Checking fire on tile outside the map (%d, %d)", posX, posY);
1549
return psTile != NULL && TileIsBurning(psTile);