diff --git a/source/core/version.h b/source/core/version.h index be58e56e4..ab9fe05be 100644 --- a/source/core/version.h +++ b/source/core/version.h @@ -78,6 +78,7 @@ const char *GetVersionString(); #define SAVEVER_BLD 11 #define SAVEVER_SW 12 #define SAVEVER_PS 13 +#define OLD_SAVEGAME 1 // this is to keep writing out the old format in Blood, even when data has been refactored. #define NETGAMEVERSION 1 diff --git a/source/games/blood/src/actor.cpp b/source/games/blood/src/actor.cpp index f7e0a29f2..303963721 100644 --- a/source/games/blood/src/actor.cpp +++ b/source/games/blood/src/actor.cpp @@ -7119,7 +7119,7 @@ void actFireVector(DBloodActor* shooter, int a2, int a3, int a4, int a5, int a6, XSPRITE* pXSprite = &actor->x(); if (pXSprite->physAttr & kPhysDebrisVector) { - int impulse = DivScale(pVectorData->impulse, ClipLow(gSpriteMass[pSprite->extra].mass, 10), 6); + int impulse = DivScale(pVectorData->impulse, ClipLow(actor->spriteMass.mass, 10), 6); actor->xvel() += MulScale(a4, impulse, 16); actor->yvel() += MulScale(a5, impulse, 16); actor->zvel() += MulScale(a6, impulse, 16); diff --git a/source/games/blood/src/aiunicult.cpp b/source/games/blood/src/aiunicult.cpp index ee414876f..408170b2d 100644 --- a/source/games/blood/src/aiunicult.cpp +++ b/source/games/blood/src/aiunicult.cpp @@ -614,7 +614,7 @@ static void unicultThinkChase(DBloodActor* actor) return; } - XSPRITE* pXLeech = &xsprite[pLeech->extra]; + XSPRITE* pXLeech = &actLeech->x(); int ldist = aiFightGetTargetDist(pTarget, pDudeInfo, pLeech); if (ldist > 3 || !cansee(pTarget->x, pTarget->y, pTarget->z, pTarget->sectnum, pLeech->x, pLeech->y, pLeech->z, pLeech->sectnum) || actLeech->GetTarget() == nullptr) @@ -2415,7 +2415,7 @@ bool genDudePrepare(DBloodActor* actor, int propId) case kGenDudePropertyMass: { // to ensure mass gets updated, let's clear all cache - SPRITEMASS* pMass = &gSpriteMass[pSprite->extra]; + SPRITEMASS* pMass = &actor->spriteMass; pMass->seqId = pMass->picnum = pMass->xrepeat = pMass->yrepeat = pMass->clipdist = 0; pMass->mass = pMass->airVel = pMass->fraction = 0; getSpriteMassBySize(pSprite); diff --git a/source/games/blood/src/bloodactor.h b/source/games/blood/src/bloodactor.h index bc5e53dce..187283491 100644 --- a/source/games/blood/src/bloodactor.h +++ b/source/games/blood/src/bloodactor.h @@ -13,6 +13,8 @@ class DBloodActor public: int dudeSlope; DUDEEXTRA dudeExtra; + SPRITEMASS spriteMass; + int cumulDamage; DBloodActor() :index(int(this - base())) { /*assert(index >= 0 && index < kMaxSprites);*/ } @@ -22,6 +24,7 @@ public: { dudeSlope = 0; dudeExtra = {}; + spriteMass = {}; } bool hasX() { return sprite[index].extra > 0; } void addX() @@ -35,7 +38,6 @@ public: int& yvel() { return Blood::yvel[index]; } int& zvel() { return Blood::zvel[index]; } - SPRITEMASS& spriteMass() { return gSpriteMass[sprite[index].extra]; } GENDUDEEXTRA& genDudeExtra() { return Blood::gGenDudeExtra[index]; } POINT3D& basePoint() { return Blood::baseSprite[index]; } diff --git a/source/games/blood/src/loadsave.cpp b/source/games/blood/src/loadsave.cpp index 2b4f227f0..3d4eafc5c 100644 --- a/source/games/blood/src/loadsave.cpp +++ b/source/games/blood/src/loadsave.cpp @@ -446,6 +446,7 @@ FSerializer& Serialize(FSerializer& arc, const char* keyname, DUDEEXTRA& w, DUDE if (arc.BeginObject(keyname)) { +#ifdef OLD_SAVEGAME // Note: birthCounter/thinkTime are a union and share the same value (this is used for savefile backwards compatibility - see correct implementation below) arc("time", w.time, &empty) ("recoil", w.teslaHit, &empty2) @@ -454,7 +455,7 @@ FSerializer& Serialize(FSerializer& arc, const char* keyname, DUDEEXTRA& w, DUDE ("x2", w.stats.thinkTime, &empty) ("x3", w.stats.active, &empty2) .EndObject(); -#if 0 +#else arc("time", w.time, &empty) ("teslaHit", w.teslaHit, &empty2) ("prio", w.prio, &empty) @@ -478,10 +479,17 @@ FSerializer& Serialize(FSerializer& arc, const char* keyname, DBloodActor& w, DB if (arc.BeginObject(keyname)) { // The rest is only relevant if the actor has an xsprite. - if (w.s().extra > 0) + if (w.hasX()) { arc("dudeslope", w.dudeSlope, def->dudeSlope) ("dudeextra", w.dudeExtra, def->dudeExtra); + + if (gModernMap) + { +#ifndef OLD_SAVEGAME + arc("spritemass", w.spriteMass, def->spriteMass); +#endif + } } arc.EndObject(); } diff --git a/source/games/blood/src/nnexts.cpp b/source/games/blood/src/nnexts.cpp index db96068c5..6a13a9c03 100644 --- a/source/games/blood/src/nnexts.cpp +++ b/source/games/blood/src/nnexts.cpp @@ -43,7 +43,6 @@ PATROL_FOUND_SOUNDS patrolBonkles[kMaxPatrolFoundSounds]; bool gAllowTrueRandom = false; bool gEventRedirectsUsed = false; -SPRITEMASS gSpriteMass[]; // cache for getSpriteMassBySize(); DBloodActor* gProxySpritesList[]; // list of additional sprites which can be triggered by Proximity short gProxySpritesCount; // current count DBloodActor* gSightSpritesList[]; // list of additional sprites which can be triggered by Sight @@ -475,16 +474,9 @@ void nnExtResetGlobals() { } // clear sprite mass cache - for (int i = 0; i < kMaxSprites; i++) { - - gSpriteMass[i].seqId = 0; - gSpriteMass[i].picnum = 0; - gSpriteMass[i].xrepeat = 0; - gSpriteMass[i].yrepeat = 0; - gSpriteMass[i].mass = 0; - gSpriteMass[i].airVel = 0; - gSpriteMass[i].fraction = 0; - + for (int i = 0; i < kMaxSprites; i++) + { + bloodActors[i].spriteMass = {}; } } @@ -1273,8 +1265,8 @@ void nnExtProcessSuperSprites() { viewBackupSpriteLoc(idx, pDebris); bool uwater = false; - int mass = gSpriteMass[pDebris->extra].mass; - int airVel = gSpriteMass[pDebris->extra].airVel; + int mass = debrisactor->spriteMass.mass; + int airVel = debrisactor->spriteMass.airVel; int top, bottom; GetSpriteExtents(pDebris, &top, &bottom); @@ -1370,6 +1362,7 @@ void sfxPlayVectorSound(spritetype* pSprite, int vectorId) { } int getSpriteMassBySize(spritetype* pSprite) { + auto actor = &bloodActors[pSprite->index]; int mass = 0; int seqId = -1; int clipDist = pSprite->clipdist; Seq* pSeq = NULL; if (pSprite->extra < 0) { I_Error("getSpriteMassBySize: pSprite->extra < 0"); @@ -1395,7 +1388,7 @@ int getSpriteMassBySize(spritetype* pSprite) { } - SPRITEMASS* cached = &gSpriteMass[pSprite->extra]; + SPRITEMASS* cached = &actor->spriteMass; if (((seqId >= 0 && seqId == cached->seqId) || pSprite->picnum == cached->picnum) && pSprite->xrepeat == cached->xrepeat && pSprite->yrepeat == cached->yrepeat && clipDist == cached->clipdist) { return cached->mass; @@ -1499,16 +1492,17 @@ void debrisConcuss(int nOwner, int listIndex, int x, int y, int z, int dmg) { auto owner = &bloodActors[nOwner]; auto actor = gPhysSpritesList[listIndex]; - spritetype* pSprite = (actor != nullptr) ? &actor->s() : NULL; - if (pSprite != NULL && xspriRangeIsFine(pSprite->extra)) + if (actor != nullptr && actor->hasX()) { + spritetype* pSprite = &actor->s(); int dx = pSprite->x - x; int dy = pSprite->y - y; int dz = (pSprite->z - z) >> 4; dmg = scale(0x40000, dmg, 0x40000 + dx * dx + dy * dy + dz * dz); bool thing = (pSprite->type >= kThingBase && pSprite->type < kThingMax); int size = (tileWidth(pSprite->picnum) * pSprite->xrepeat * tileHeight(pSprite->picnum) * pSprite->yrepeat) >> 1; if (xsprite[pSprite->extra].physAttr & kPhysDebrisExplode) { - if (gSpriteMass[pSprite->extra].mass > 0) { - int t = scale(dmg, size, gSpriteMass[pSprite->extra].mass); + if (actor->spriteMass.mass > 0) + { + int t = scale(dmg, size, actor->spriteMass.mass); xvel[pSprite->index] += MulScale(t, dx, 16); yvel[pSprite->index] += MulScale(t, dy, 16); @@ -1526,8 +1520,9 @@ void debrisConcuss(int nOwner, int listIndex, int x, int y, int z, int dmg) } } -void debrisBubble(int nSprite) { - +void debrisBubble(int nSprite) +{ + spritetype* pSprite = &sprite[nSprite]; int top, bottom; @@ -1578,10 +1573,10 @@ void debrisMove(int listIndex) int floorDist = (bottom - pSprite->z) >> 2; int ceilDist = (pSprite->z - top) >> 2; int clipDist = pSprite->clipdist << 2; - int mass = actor->spriteMass().mass; + int mass = actor->spriteMass.mass; bool uwater = false; - int tmpFraction = gSpriteMass[pSprite->extra].fraction; + int tmpFraction = actor->spriteMass.fraction; if (sector[nSector].extra >= 0 && xsector[sector[nSector].extra].Underwater) { tmpFraction >>= 1; uwater = true; @@ -1666,7 +1661,7 @@ void debrisMove(int listIndex) switch (i) { case kMarkerUpWater: case kMarkerUpGoo: - int pitch = (150000 - (gSpriteMass[pSprite->extra].mass << 9)) + Random3(8192); + int pitch = (150000 - (actor->spriteMass.mass << 9)) + Random3(8192); sfxPlay3DSoundCP(pSprite, 720, -1, 0, pitch, 75 - Random(40)); if (!spriteIsUnderwater(actor)) { evKill(pSprite->index, 3, kCallbackEnemeyBubble); @@ -8001,7 +7996,7 @@ void SerializeNNExts(FSerializer& arc) bool foundsome = false; for (int i = 0; i < kMaxSprites; i++) { - if (activeSprites[i] && (sprite[i].type == kDudeModernCustom || sprite[i].type == kDudeModernCustomBurning)) + if (activeSprites[i] && (sprite[i].type == kDudeModernCustom || sprite[i].type == kDudeModernCustomBurning)) { if (!foundsome) arc.BeginArray("gendudeextra"); foundsome = true; @@ -8009,8 +8004,25 @@ void SerializeNNExts(FSerializer& arc) } } if (foundsome) arc.EndArray(); - arc.SparseArray("spritemass", gSpriteMass, kMaxSprites, activeXSprites) - ("proxyspritescount", gProxySpritesCount) + +#ifdef OLD_SAVEGAME + // In compatibility mode write this out as a sparse array sorted by xsprite index. + SPRITEMASS gSpriteMass[kMaxSprites]; + for (int i = 0; i < kMaxSprites; i++) + { + int x = sprite[i].extra; + if (x <= 0) continue; + gSpriteMass[x] = bloodActors[i].spriteMass; + } + arc.SparseArray("spritemass", gSpriteMass, kMaxSprites, activeXSprites); + for (int i = 0; i < kMaxSprites; i++) + { + int x = sprite[i].extra; + if (x <= 0) continue; + if (activeXSprites[x]) bloodActors[i].spriteMass = gSpriteMass[x]; + } +#endif + arc ("proxyspritescount", gProxySpritesCount) .Array("proxyspriteslist", gProxySpritesList, gProxySpritesCount) ("sightspritescount", gSightSpritesCount) .Array("sightspriteslist", gSightSpritesList, gSightSpritesCount) diff --git a/source/games/blood/src/nnexts.h b/source/games/blood/src/nnexts.h index 365d96c53..0f7abae77 100644 --- a/source/games/blood/src/nnexts.h +++ b/source/games/blood/src/nnexts.h @@ -273,7 +273,6 @@ extern const VECTORINFO_EXTRA gVectorInfoExtra[kVectorMax]; extern const MISSILEINFO_EXTRA gMissileInfoExtra[kMissileMax]; extern const DUDEINFO_EXTRA gDudeInfoExtra[kDudeMax]; extern TRPLAYERCTRL gPlayerCtrl[kMaxPlayers]; -extern SPRITEMASS gSpriteMass[kMaxXSprites]; extern TRCONDITION gCondition[kMaxTrackingConditions]; extern DBloodActor* gProxySpritesList[kMaxSuperXSprites]; extern DBloodActor* gSightSpritesList[kMaxSuperXSprites];