1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015 |
- #include <stdlib.h>
- #include <string.h>
- #include <io.h>
- #include <fcntl.h>
- #include "engine.h"
- #include "debug4g.h"
- #include "db.h"
- #include "error.h"
- #include "misc.h"
- #include "resource.h"
- #include "iob.h"
- #include "names.h"
- #include "globals.h"
- #include "trig.h"
- #include <memcheck.h>
- /***********************************************************************
- * Constants
- **********************************************************************/
- #define kBloodMapExt ".MAP"
- #define kBloodMapSig "BLM\x1A"
- #define kBloodMapVersion 0x0600
- #define kMajorVersionMask 0xFF00
- #define kMinorVersionMask 0x00FF
- #define kFreeHead 0
- /***********************************************************************
- * Structures and typedefs
- **********************************************************************/
- struct HEADER
- {
- char signature[4];
- short version;
- };
- // version 6.x header
- struct INFO
- {
- long x, y, z;
- ushort angle;
- ushort sector;
- ushort pskybits;
- long visibility;
- int songId;
- uchar parallax;
- int mapRevisions;
- ushort numsectors;
- ushort numwalls;
- ushort numsprites;
- };
- /*******************************************************************************
- File format:
- HEADER
- INFO
- name[]
- author[]
- sector[]
- wall[]
- sprite[]
- xsprite[]
- xwall[]
- xsector[]
- CRC
- *******************************************************************************/
- /***********************************************************************
- * Global Variables / MPX related strings
- **********************************************************************/
- char *gItemText[ kItemMax - kItemBase ] = {
- // items which will probably not change
- "Key 1", // kItemKey1
- "Key 2", // kItemKey2
- "Key 3", // kItemKey3
- "Key 4", // kItemKey4
- "Key 5", // kItemKey5
- "Key 6", // kItemKey6
- "Key 7", // kItemKey7
- "Doctor's Bag", // kItemDoctorBag
- "Medicine Pouch", // kItemMedPouch
- "Life Essence", // kItemLifeEssence
- "Life Seed", // kItemLifeSeed
- "Red Potion", // kItemPotion1
- "Feather Fall", // kItemFeatherFall
- "Limited Invisibility", // kItemLtdInvisibility
- "INVULNERABILITY", // kItemInvulnerability
- "Boots of Jumping", // kItemJumpBoots
- "Raven Flight", // kItemRavenFlight
- "Guns Akimbo", // kItemGunsAkimbo
- "Diving Suit", // kItemDivingSuit
- "Gas mask", // kItemGasMask
- "Clone", // kItemClone
- "Crystal Ball", // kItemCrystalBall
- "Decoy", // kItemDecoy
- "Doppleganger", // kItemDoppleganger
- "Reflective shots", // kItemReflectiveShots
- "Rose colored glasses", // kItemRoseGlasses
- "ShadowCloak", // kItemShadowCloak
- "Rage shroom", // kItemShroomRage
- "Delirium Shroom", // kItemShroomDelirium
- "Grow shroom", // kItemShroomGrow
- "Shrink shroom", // kItemShroomShrink
- "Death mask", // kItemDeathMask
- "Wine Goblet", // kItemWineGoblet
- "Wine Bottle", // kItemWineBottle
- "Skull Grail", // kItemSkullGrail
- "Silver Grail", // kItemSilverGrail
- "Tome", // kItemTome
- "Black Chest", // kItemBlackChest
- "Wooden Chest", // kItemWoodenChest
- "Asbestos Armor", // kItemAsbestosArmor
- };
- char *gAmmoText[kAmmoItemMax - kAmmoItemBase] = {
- "Spray can",
- "Stick of TNT",
- "Bundle of TNT",
- "Case of TNT",
- "Proximity Detonator",
- "Remote Detonator",
- "Timed Detonator",
- "4 shotgun shells",
- "Box of shotgun shells",
- "A few bullets",
- "Box of bullets",
- "Armor piercing bullets",
- "Full drum of bullets",
- "Speargun spear",
- "6 speargun spears",
- "Explosive spears",
- "Flares",
- "Explosive flares",
- "Burst flares",
- };
- char *gWeaponText[kWeaponItemMax - kWeaponItemBase] =
- {
- "RandomWeapon", // kWeaponItemRandom
- "SawedOff", // kWeaponItemShotgun
- "TommyGun", // kWeaponItemTommyGun
- "FlareGun", // kWeaponItemFlareGun
- "VoodooDoll", // kWeaponItemVoodooDoll
- "SpearGun", // kWeaponItemSpearGun
- "EctoBlaster", // kWeaponItemShadowGun
- "Pitchfork", // kWeaponItemPitchfork
- "SprayCan", // kWeaponItemSprayCan
- "TNT" // kWeaponItemTNT
- };
- /***********************************************************************
- * Variables
- **********************************************************************/
- XSPRITE xsprite[kMaxXSprites];
- XWALL xwall[kMaxXWalls];
- XSECTOR xsector[kMaxXSectors];
- ushort nextXSprite[kMaxXSprites];
- ushort nextXWall[kMaxXWalls];
- ushort nextXSector[kMaxXSectors];
- int gMapRev;
- int gSongId;
- ulong gMapCRC;
- int gSkyCount;
- /*******************************************************************************
- Replace engine sprite list functions
- *******************************************************************************/
- void InsertSpriteSect( short nSprite, short nSector )
- {
- dassert(nSprite >= 0 && nSprite < kMaxSprites);
- dassert(nSector >= 0 && nSector < kMaxSectors);
- int nOldHead = headspritesect[nSector];
- if (nOldHead >= 0)
- {
- // insert sprite at the tail of the list
- prevspritesect[nSprite] = prevspritesect[nOldHead];
- nextspritesect[nSprite] = -1;
- nextspritesect[prevspritesect[nOldHead]] = nSprite;
- prevspritesect[nOldHead] = nSprite;
- }
- else
- {
- prevspritesect[nSprite] = nSprite;
- nextspritesect[nSprite] = -1;
- headspritesect[nSector] = nSprite;
- }
- sprite[nSprite].sectnum = nSector;
- }
- void RemoveSpriteSect( int nSprite )
- {
- dassert(nSprite >= 0 && nSprite < kMaxSprites);
- int nSector = sprite[nSprite].sectnum;
- dassert(nSector >= 0 && nSector < kMaxSectors);
- if ( nextspritesect[nSprite] >= 0 )
- prevspritesect[nextspritesect[nSprite]] = prevspritesect[nSprite];
- else
- prevspritesect[headspritesect[nSector]] = prevspritesect[nSprite];
- if ( headspritesect[nSector] != nSprite )
- nextspritesect[prevspritesect[nSprite]] = nextspritesect[nSprite];
- else
- headspritesect[nSector] = nextspritesect[nSprite];
- sprite[nSprite].sectnum = -1;
- }
- void InsertSpriteStat( short nSprite, short nStat )
- {
- dassert(nSprite >= 0 && nSprite < kMaxSprites);
- dassert(nStat >= 0 && nStat <= kMaxStatus);
- int nHead = headspritestat[nStat];
- if (nHead >= 0)
- {
- nextspritestat[nSprite] = -1;
- prevspritestat[nSprite] = prevspritestat[nHead];
- nextspritestat[prevspritestat[nHead]] = nSprite;
- prevspritestat[nHead] = nSprite;
- }
- else
- {
- prevspritestat[nSprite] = nSprite;
- nextspritestat[nSprite] = -1;
- headspritestat[nStat] = nSprite;
- }
- sprite[nSprite].statnum = nStat;
- }
- void RemoveSpriteStat( int nSprite )
- {
- dassert(nSprite >= 0 && nSprite < kMaxSprites);
- int nStat = sprite[nSprite].statnum;
- dassert(nStat >= 0 && nStat <= kMaxStatus);
- if ( nextspritestat[nSprite] >= 0 )
- prevspritestat[nextspritestat[nSprite]] = prevspritestat[nSprite];
- else
- prevspritestat[headspritestat[nStat]] = prevspritestat[nSprite];
- if (headspritestat[nStat] != nSprite )
- nextspritestat[prevspritestat[nSprite]] = nextspritestat[nSprite];
- else
- headspritestat[nStat] = nextspritestat[nSprite];
- sprite[nSprite].statnum = -1;
- }
- void initspritelists()
- {
- short i;
- //Init doubly-linked sprite sector lists
- for (i = 0; i <= kMaxSectors; i++)
- headspritesect[i] = -1;
- for (i = 0; i <= kMaxStatus; i++)
- headspritestat[i] = -1;
- for (i = 0; i < kMaxSprites; i++)
- {
- sprite[i].sectnum = -1;
- InsertSpriteStat(i, kStatFree); // add to free list
- }
- }
- //long debugNumSprites = 0;
- short insertsprite( short nSector, short nStatus )
- {
- short nSprite;
- // debugNumSprites++;
- // dprintf("insertsprite: debugNumSprites=%i\n",debugNumSprites);
- nSprite = headspritestat[kStatFree];
- if (nSprite >= 0)
- {
- RemoveSpriteStat(nSprite);
- InsertSpriteStat(nSprite, nStatus);
- InsertSpriteSect(nSprite, nSector);
- sprite[nSprite].cstat = kSpriteOriginAlign;
- sprite[nSprite].shade = 0;
- sprite[nSprite].pal = 0;
- sprite[nSprite].clipdist = 32;
- sprite[nSprite].xrepeat = 64;
- sprite[nSprite].yrepeat = 64;
- sprite[nSprite].xoffset = 0;
- sprite[nSprite].yoffset = 0;
- sprite[nSprite].picnum = 0;
- sprite[nSprite].ang = 0;
- sprite[nSprite].xvel = 0;
- sprite[nSprite].yvel = 0;
- sprite[nSprite].zvel = 0;
- sprite[nSprite].owner = -1;
- sprite[nSprite].type = 0;
- sprite[nSprite].flags = 0;
- sprite[nSprite].extra = -1;
- }
- if ( nSprite < 0 )
- {
- dprintf("sprite status linked list:\n");
- for ( int i = 0; i <= kMaxStatus; i++ )
- dprintf("head[%4d]=%4d\n", i, headspritestat[i]);
- for ( i = 0; i <= kMaxSprites; i++ )
- dprintf("%4d: prev=%4d next=%4d\n", i, prevspritestat[i], nextspritestat[i]);
- dassert(nSprite >= 0);
- }
- return nSprite;
- }
- void deletesprite( short nSprite )
- {
- // debugNumSprites--;
- // dprintf("deletesprite: debugNumSprites=%i\n",debugNumSprites);
- if ( sprite[nSprite].extra > 0 )
- dbDeleteXSprite(sprite[nSprite].extra);
- dassert(sprite[nSprite].statnum >= 0 && sprite[nSprite].statnum < kMaxStatus);
- RemoveSpriteStat(nSprite);
- dassert(sprite[nSprite].sectnum >= 0 && sprite[nSprite].sectnum < kMaxSectors);
- RemoveSpriteSect(nSprite);
- InsertSpriteStat(nSprite, kStatFree);
- }
- int changespritesect( short nSprite, short nSector )
- {
- dassert(nSprite >= 0 && nSprite < kMaxSprites);
- dassert(nSector >= 0 && nSector < kMaxSectors);
- dassert(sprite[nSprite].statnum >= 0 && sprite[nSprite].statnum < kMaxStatus);
- dassert(sprite[nSprite].sectnum >= 0 && sprite[nSprite].sectnum < kMaxSectors);
- // changing to same sector is a valid operation, and will put sprite at tail of list
- RemoveSpriteSect(nSprite);
- InsertSpriteSect(nSprite, nSector);
- return 0;
- }
- int changespritestat( short nSprite, short nStatus )
- {
- dassert(nSprite >= 0 && nSprite < kMaxSprites);
- dassert(nStatus >= 0 && nStatus < kMaxStatus);
- dassert(sprite[nSprite].statnum >= 0 && sprite[nSprite].statnum < kMaxStatus);
- dassert(sprite[nSprite].sectnum >= 0 && sprite[nSprite].sectnum < kMaxSectors);
- // changing to same status is a valid operation, and will put sprite at tail of list
- RemoveSpriteStat(nSprite);
- InsertSpriteStat(nSprite, nStatus);
- return 0;
- }
- /*******************************************************************************
- These functions are for manipulating the xobject lists
- *******************************************************************************/
- void InitFreeList( ushort xlist[], int xlistSize )
- {
- for (int i = 1; i < xlistSize; i++)
- xlist[i] = (ushort)(i - 1);
- xlist[kFreeHead] = (ushort)(xlistSize - 1);
- }
- inline ushort RemoveFree( ushort next[] )
- {
- ushort n = next[kFreeHead];
- next[kFreeHead] = next[n];
- return n;
- }
- inline void InsertFree( ushort next[], int n )
- {
- next[n] = next[kFreeHead];
- next[kFreeHead] = (ushort)n;
- }
- ushort dbInsertXSprite( int nSprite )
- {
- ushort nXSprite = RemoveFree(nextXSprite);
- if (nXSprite == 0)
- ThrowError("Out of free XSprites", ES_ERROR);
- memset(&xsprite[nXSprite], 0, sizeof(XSPRITE));
- sprite[nSprite].extra = nXSprite;
- xsprite[nXSprite].reference = nSprite;
- return nXSprite;
- }
- void dbDeleteXSprite( int nXSprite )
- {
- dassert(xsprite[nXSprite].reference >= 0);
- dassert(sprite[xsprite[nXSprite].reference].extra == nXSprite);
- InsertFree( nextXSprite, nXSprite );
- // clear the references
- sprite[xsprite[nXSprite].reference].extra = -1;
- xsprite[nXSprite].reference = -1;
- }
- ushort dbInsertXWall( int nWall )
- {
- ushort nXWall = RemoveFree(nextXWall);
- if (nXWall == 0)
- ThrowError("Out of free XWalls", ES_ERROR);
- memset(&xwall[nXWall], 0, sizeof(XWALL));
- wall[nWall].extra = nXWall;
- xwall[nXWall].reference = nWall;
- return nXWall;
- }
- void dbDeleteXWall( int nXWall )
- {
- dassert(xwall[nXWall].reference >= 0);
- InsertFree( nextXWall, nXWall );
- // clear the references
- wall[xwall[nXWall].reference].extra = -1;
- xwall[nXWall].reference = -1;
- }
- ushort dbInsertXSector( int nSector )
- {
- ushort nXSector = RemoveFree(nextXSector);
- if (nXSector == 0)
- ThrowError("Out of free XSectors", ES_ERROR);
- memset(&xsector[nXSector], 0, sizeof(XSECTOR));
- sector[nSector].extra = nXSector;
- xsector[nXSector].reference = nSector;
- return nXSector;
- }
- void dbDeleteXSector( int nXSector )
- {
- dassert(xsector[nXSector].reference >= 0);
- InsertFree( nextXSector, nXSector );
- // clear the references
- sector[xsector[nXSector].reference].extra = -1;
- xsector[nXSector].reference = -1; // clear the reference
- }
- /***********************************************************************
- * dbXSpriteClean()
- *
- * Clean up the xsprite list: clone duplicate references & delete orphans
- **********************************************************************/
- void dbXSpriteClean(void)
- {
- int nSprite, nXSprite;
- // clone duplicate references
- for ( nSprite = 0; nSprite < kMaxSprites; nSprite++ )
- {
- nXSprite = sprite[nSprite].extra;
- if (nXSprite == 0)
- sprite[nSprite].extra = -1;
- if ( sprite[nSprite].statnum < kMaxStatus && nXSprite > 0 )
- {
- dassert(nXSprite < kMaxXSprites);
- if ( xsprite[nXSprite].reference != nSprite )
- {
- // make a copy of the xsprite entry
- int newXSprite = dbInsertXSprite(nSprite);
- xsprite[newXSprite] = xsprite[nXSprite];
- xsprite[newXSprite].reference = nSprite; // fix reference after copying
- }
- }
- }
- // remove orphans
- for ( nXSprite = 1; nXSprite < kMaxXSprites; nXSprite++ )
- {
- nSprite = xsprite[nXSprite].reference;
- if (nSprite >= 0)
- {
- dassert(nSprite < kMaxSprites);
- if (sprite[nSprite].statnum >= kMaxStatus || sprite[nSprite].extra != nXSprite)
- {
- // delete manually so we don't assert from a mismatched reference
- InsertFree( nextXSprite, nXSprite );
- xsprite[nXSprite].reference = -1;
- }
- }
- }
- }
- /***********************************************************************
- * dbXWallClean()
- *
- * Clean up the xwall list: clone duplicate references & delete orphans
- **********************************************************************/
- void dbXWallClean(void)
- {
- int nWall, nXWall;
- // back propagate references
- for ( nWall = 0; nWall < numwalls; nWall++ )
- {
- nXWall = wall[nWall].extra;
- if (nXWall == 0)
- wall[nWall].extra = -1;
- if ( nXWall > 0 )
- {
- dassert(nXWall < kMaxXWalls);
- // wall points to a freed xwall
- if (xwall[nXWall].reference == -1)
- {
- wall[nWall].extra = -1;
- continue;
- }
- // probably just moved the wall around
- xwall[nXWall].reference = nWall;
- }
- }
- // clone duplicate references
- for ( nWall = 0; nWall < numwalls; nWall++ )
- {
- if ( wall[nWall].extra > 0 )
- {
- nXWall = wall[nWall].extra;
- dassert(nXWall < kMaxXWalls);
- if ( xwall[nXWall].reference != nWall )
- {
- // make a copy of the xwall entry
- int newXWall = dbInsertXWall(nWall);
- xwall[newXWall] = xwall[nXWall];
- xwall[newXWall].reference = nWall; // fix reference after copying
- }
- }
- }
- // remove orphans
- for ( nXWall = 1; nXWall < kMaxXWalls; nXWall++ )
- {
- nWall = xwall[nXWall].reference;
- if (nWall >= 0)
- {
- dassert(nWall < kMaxWalls);
- if ( nWall >= numwalls || wall[nWall].extra != nXWall )
- {
- // delete manually so we don't assert from a mismatched reference
- InsertFree( nextXWall, nXWall );
- xwall[nXWall].reference = -1;
- }
- }
- }
- }
- /***********************************************************************
- * dbXSectorClean()
- *
- * Clean up the xsector list: clone duplicate references & delete orphans
- **********************************************************************/
- void dbXSectorClean(void)
- {
- int nSector, nXSector;
- // back propagate references
- for ( nSector = 0; nSector < numsectors; nSector++ )
- {
- nXSector = sector[nSector].extra;
- if (nXSector == 0)
- sector[nSector].extra = -1;
- if ( nXSector > 0 )
- {
- dassert(nXSector < kMaxXSectors);
- // sector points to a freed xsector
- if (xsector[nXSector].reference == -1)
- {
- sector[nSector].extra = -1;
- continue;
- }
- // probably just moved the sector around
- xsector[nXSector].reference = nSector;
- }
- }
- // clone duplicate references
- for ( nSector = 0; nSector < numsectors; nSector++ )
- {
- if ( sector[nSector].extra > 0 )
- {
- nXSector = sector[nSector].extra;
- dassert(nXSector < kMaxXSectors);
- if ( xsector[nXSector].reference != nSector )
- {
- // make a copy of the xsector entry
- int newXSector = dbInsertXSector(nSector);
- xsector[newXSector] = xsector[nXSector];
- xsector[newXSector].reference = nSector; // fix reference after copying
- }
- }
- }
- // remove orphans
- for ( nXSector = 1; nXSector < kMaxXSectors; nXSector++ )
- {
- nSector = xsector[nXSector].reference;
- if (nSector >= 0)
- {
- dassert(nSector < kMaxSectors);
- if ( nSector >= numsectors || sector[nSector].extra != nXSector )
- {
- // delete manually so we don't assert from a mismatched reference
- InsertFree( nextXSector, nXSector );
- xsector[nXSector].reference = -1;
- }
- }
- }
- }
- void dbInit( void )
- {
- int i;
- // memset(sprite, 0, sizeof(sprite));
- // memset(wall, 0, sizeof(wall));
- // memset(sector, 0, sizeof(sector));
- InitFreeList(nextXSprite, kMaxXSprites);
- for (i = 1; i < kMaxXSprites; i++)
- xsprite[i].reference = -1;
- InitFreeList(nextXWall, kMaxXWalls);
- for (i = 1; i < kMaxXWalls; i++)
- xwall[i].reference = -1;
- InitFreeList(nextXSector, kMaxXSectors);
- for (i = 1; i < kMaxXSectors; i++)
- xsector[i].reference = -1;
- initspritelists();
- // initialize default cstat for sprites
- for (i = 0; i < kMaxSprites; i++)
- sprite[i].cstat = kSpriteOriginAlign;
- }
- /*******************************************************************************
- FUNCTION: PropagateMarkerReferences()
- DESCRIPTION: Fixed sector references based on marker sprite references.
- NOTES: This function assumes that the owner references in the
- marker sprites are correct. This function should be called
- from loadboard, where we know that sprites are rearranged.
- *******************************************************************************/
- void PropagateMarkerReferences( void )
- {
- int nSprite, j;
- int nSector, nXSector;
- for (nSprite = headspritestat[kStatMarker]; nSprite != -1; nSprite = j)
- {
- j = nextspritestat[nSprite];
- switch (sprite[nSprite].type)
- {
- case kMarkerWarpDest:
- nSector = sprite[nSprite].owner;
- if (nSector < 0 || nSector >= numsectors)
- break;
- nXSector = sector[nSector].extra;
- if (nXSector <= 0 || nXSector >= kMaxXSectors)
- break;
- xsector[nXSector].marker0 = nSprite;
- continue;
- case kMarkerOff:
- nSector = sprite[nSprite].owner;
- if (nSector < 0 || nSector >= numsectors)
- break;
- nXSector = sector[nSector].extra;
- if (nXSector <= 0 || nXSector >= kMaxXSectors)
- break;
- xsector[nXSector].marker0 = nSprite;
- continue;
- case kMarkerOn:
- nSector = sprite[nSprite].owner;
- if (nSector < 0 || nSector >= numsectors)
- break;
- nXSector = sector[nSector].extra;
- if (nXSector <= 0 || nXSector >= kMaxXSectors)
- break;
- xsector[nXSector].marker1 = nSprite;
- continue;
- case kMarkerAxis:
- nSector = sprite[nSprite].owner;
- if (nSector < 0 || nSector >= numsectors)
- break;
- nXSector = sector[nSector].extra;
- if (nXSector <= 0 || nXSector >= kMaxXSectors)
- break;
- xsector[nXSector].marker0 = nSprite;
- continue;
- }
- dprintf("Deleting invalid marker sprite\n");
- deletesprite((short)nSprite);
- }
- }
- /***********************************************************************
- * dbLoadMap()
- **********************************************************************/
- void dbLoadMap(const char *mapname, long *x, long *y, long *z, short *angle, short *nSector)
- {
- char filename[_MAX_PATH];
- int i, numsprites;
- int length;
- HEADER header;
- INFO info;
- BYTE *buffer;
- // these eventually need to be added to the save game format
- // memset(show2dsector, 0, sizeof(show2dsector));
- // memset(show2dwall, 0, sizeof(show2dwall));
- // memset(show2dsprite, 0, sizeof(show2dsprite));
- strcpy(filename, mapname);
- // clear any extension
- char *p = strchr(filename, '.');
- if ( p != NULL)
- *p = '\0';
- RESHANDLE hMap = gSysRes.Lookup(filename, ".MAP");
- if ( hMap == NULL )
- ThrowError("Error opening map file", ES_ERROR);
- length = gSysRes.Size(hMap);
- buffer = (BYTE *)gSysRes.Lock(hMap);
- IOBuffer iob(buffer, length);
- iob.Read(&header, sizeof(HEADER));
- if (memcmp(header.signature, kBloodMapSig, sizeof(header.signature)) != 0)
- ThrowError("Map file corrupted", ES_ERROR);
- if ( (header.version & kMajorVersionMask) != (kBloodMapVersion & kMajorVersionMask) )
- ThrowError("Map file is wrong version", ES_ERROR);
- iob.Read(&info, sizeof(INFO));
- *x = info.x;
- *y = info.y;
- *z = info.z;
- *angle = info.angle;
- *nSector = info.sector;
- pskybits = info.pskybits;
- visibility = info.visibility;
- gSongId = info.songId;
- parallaxtype = info.parallax;
- gMapRev = info.mapRevisions;
- numsectors = info.numsectors;
- numwalls = info.numwalls;
- numsprites = info.numsprites;
- dbInit();
- gSkyCount = 1 << pskybits;
- iob.Read(pskyoff, gSkyCount * sizeof(pskyoff[0]));
- for (i = 0; i < numsectors; i++)
- {
- SECTOR *pSector = §or[i];
- iob.Read(§or[i], sizeof(SECTOR));
- if (sector[i].extra > 0)
- {
- iob.Read(&xsector[dbInsertXSector(i)], sizeof(XSECTOR));
- xsector[sector[i].extra].reference = i;
- xsector[sector[i].extra].busy = xsector[sector[i].extra].state << 16;
- }
- }
- for (i = 0; i < numwalls; i++)
- {
- iob.Read(&wall[i], sizeof(WALL));
- if (wall[i].extra > 0)
- {
- iob.Read(&xwall[dbInsertXWall(i)], sizeof(XWALL));
- xwall[wall[i].extra].reference = i;
- xwall[wall[i].extra].busy = xwall[wall[i].extra].state << 16;
- }
- }
- initspritelists();
- for (i = 0; i < numsprites; i++)
- {
- RemoveSpriteStat((short)i); // remove it from the free list
- iob.Read(&sprite[i], sizeof(SPRITE));
- // insert sprite on appropriate lists
- InsertSpriteSect((short)i, sprite[i].sectnum);
- InsertSpriteStat((short)i, sprite[i].statnum);
- // debugNumSprites++;
- if (sprite[i].extra > 0)
- {
- iob.Read(&xsprite[dbInsertXSprite(i)], sizeof(XSPRITE));
- xsprite[sprite[i].extra].reference = i;
- xsprite[sprite[i].extra].busy = xsprite[sprite[i].extra].state << 16;
- }
- }
- iob.Read(&gMapCRC, sizeof(gMapCRC));
- if ( gMapCRC != CRC32(buffer, length - sizeof(gMapCRC)) )
- ThrowError("File does not match CRC", ES_ERROR);
- gSysRes.Unlock(hMap);
- PropagateMarkerReferences();
- }
- /***********************************************************************
- * dbSaveMap()
- **********************************************************************/
- void dbSaveMap(const char *mapname, long x, long y, long z, short angle, short nSector)
- {
- char filename[_MAX_PATH];
- char bakfilename[_MAX_PATH];
- int hFile;
- HEADER header;
- INFO info;
- int length;
- BYTE *buffer;
- int numsprites = 0;
- int i;
- gSkyCount = 1 << pskybits;
- gMapRev++;
- strcpy(filename, mapname);
- strcpy(bakfilename, mapname);
- ChangeExtension(filename, kBloodMapExt);
- ChangeExtension(bakfilename, ".BAK");
- // add up all the elements in the file to determine the size of the buffer
- length = 0;
- length += sizeof(HEADER);
- length += sizeof(INFO);
- length += gSkyCount * sizeof(pskyoff[0]);
- length += numsectors * sizeof(SECTOR);
- for (i = 0; i < numsectors; i++)
- {
- if (sector[i].extra > 0)
- length += sizeof(XSECTOR);
- }
- length += numwalls * sizeof(WALL);
- for (i = 0; i < numwalls; i++)
- {
- if (wall[i].extra > 0)
- length += sizeof(XWALL);
- }
- for (i = 0; i < kMaxSprites; i++)
- {
- if (sprite[i].statnum < kMaxStatus)
- {
- numsprites++;
- if (sprite[i].extra > 0)
- length += sizeof(XSPRITE);
- }
- }
- length += numsprites * sizeof(SPRITE);
- length += 4; // CRC
- buffer = (BYTE *)Resource::Alloc(length);
- IOBuffer iob(buffer, length);
- memcpy(header.signature, kBloodMapSig, sizeof(header.signature));
- header.version = kBloodMapVersion;
- iob.Write(&header, sizeof(header));
- info.x = x;
- info.y = y;
- info.z = z;
- info.angle = angle;
- info.sector = nSector;
- info.pskybits = pskybits;
- info.visibility = visibility;
- info.songId = gSongId;
- info.parallax = parallaxtype;
- info.mapRevisions = gMapRev;
- info.numsectors = numsectors;
- info.numwalls = numwalls;
- info.numsprites = (short)numsprites;
- iob.Write(&info, sizeof(INFO));
- iob.Write(pskyoff, gSkyCount * sizeof(pskyoff[0]));
- for (i = 0; i < numsectors; i++)
- {
- iob.Write(§or[i], sizeof(SECTOR));
- if (sector[i].extra > 0)
- iob.Write(&xsector[sector[i].extra], sizeof(XSECTOR));
- }
- for (i = 0; i < numwalls; i++)
- {
- iob.Write(&wall[i], sizeof(WALL));
- if (wall[i].extra > 0)
- iob.Write(&xwall[wall[i].extra], sizeof(XWALL));
- }
- for (i = 0; i < kMaxSprites; i++)
- {
- if (sprite[i].statnum < kMaxStatus)
- {
- iob.Write(&sprite[i], sizeof(SPRITE));
- if (sprite[i].extra > 0)
- iob.Write(&xsprite[sprite[i].extra], sizeof(XSPRITE));
- }
- }
- gMapCRC = CRC32(buffer, length - sizeof(gMapCRC));
- iob.Write(&gMapCRC, sizeof(gMapCRC));
- // backup the map file
- unlink(bakfilename);
- rename(filename, bakfilename);
- hFile = open(filename, O_CREAT | O_TRUNC | O_WRONLY | O_BINARY, S_IWUSR);
- if ( hFile == -1 )
- ThrowError("Error opening MAP file", ES_ERROR);
- if (write(hFile, buffer, length) != length)
- ThrowError("Error writing MAP file", ES_ERROR);
- close(hFile);
- Resource::Free(buffer);
- // make sure we don't leave a stale copy of the map on the heap
- char *p = strchr(filename, '.');
- if ( p != NULL)
- *p = '\0';
- gSysRes.AddExternalResource(filename, ".MAP", length);
- }
|