diff --git a/source/blood/src/actor.cpp b/source/blood/src/actor.cpp index be968013a..16ea0df45 100644 --- a/source/blood/src/actor.cpp +++ b/source/blood/src/actor.cpp @@ -2342,6 +2342,9 @@ static const short gPlayerGibThingComments[] = { 734, 735, 736, 737, 738, 739, 740, 741, 3038, 3049 }; +const int DudeDifficulty[5] = { + 512, 384, 256, 208, 160 +}; int gPostCount = 0; @@ -2352,6 +2355,12 @@ struct POSTPONE { POSTPONE gPost[kMaxSprites]; +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + bool IsUnderwaterSector(int nSector) { int nXSector = sector[nSector].extra; @@ -2360,186 +2369,214 @@ bool IsUnderwaterSector(int nSector) return 0; } -const int DudeDifficulty[5] = { - 512, 384, 256, 208, 160 -}; +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- -void actInit(bool bSaveLoad) +void actInitTraps() { - - #ifdef NOONE_EXTENSIONS - if (!gModernMap) - { - //Printf("> This map *does not* provides modern features.\n"); - nnExtResetGlobals(); - } - else - { - //Printf("> This map provides modern features.\n"); - nnExtInitModernStuff(bSaveLoad); - } - #endif - - BloodStatIterator it(kStatItem); - while (auto act = it.Next()) - { - switch (act->s().type) - { - case kItemWeaponVoodooDoll: - act->s().type = kAmmoItemVoodooDoll; - break; - } - } - - it.Reset(kStatTraps); - while (auto act = it.Next()) - { - spritetype *pSprite = &act->s(); - auto x = &act->x(); - switch (pSprite->type) - { - case kTrapExploder: - pSprite->cstat &= ~1; - pSprite->cstat |= CSTAT_SPRITE_INVISIBLE; - if (pSprite->extra <= 0 || pSprite->extra >= kMaxXSprites) continue; - x->waitTime = ClipLow(x->waitTime, 1); - x->state = 0; - break; - } - } - - it.Reset(kStatThing); - while (auto act = it.Next()) - { - if (!act->hasX()) continue; - spritetype* pSprite = &act->s(); - XSPRITE* pXSprite = &act->x(); - - int nType = pSprite->type - kThingBase; - pXSprite->health = thingInfo[nType].startHealth << 4; - #ifdef NOONE_EXTENSIONS - // allow level designer to set custom clipdist. - // this is especially useful for various Gib and Explode objects which have clipdist 1 for some reason predefined, - // but what if it have voxel model...? - if (!gModernMap) - #endif - pSprite->clipdist = thingInfo[nType].clipdist; - - pSprite->flags = thingInfo[nType].flags; - if (pSprite->flags & kPhysGravity) pSprite->flags |= kPhysFalling; - act->xvel() = act->yvel() = act->zvel() = 0; - - switch (pSprite->type) { - case kThingArmedProxBomb: - case kTrapMachinegun: - #ifdef NOONE_EXTENSIONS - case kModernThingTNTProx: - #endif - pXSprite->state = 0; - break; - case kThingBloodChunks: { - SEQINST *pInst = GetInstance(3, pSprite->extra); - if (pInst) - { - auto seq = getSequence(pInst->nSeqID); - if (!seq) break; - seqSpawn(pInst->nSeqID, 3, pSprite->extra); - } - break; - } - default: - pXSprite->state = 1; - break; - } - } - - if (gGameOptions.nMonsterSettings == 0) - { - gKillMgr.SetCount(0); - BloodStatIterator it(kStatDude); - while (auto act = it.Next()) - { - spritetype *pSprite = &act->s(); - if (act->hasX() && act->x().key > 0) // Drop Key - actDropObject(pSprite, kItemKeyBase + (act->x().key - 1)); - DeleteSprite(act); - } - } - else - { - // by NoOne: WTF is this? - /////////////// - char unk[kDudeMax-kDudeBase]; - memset(unk, 0, sizeof(unk)); - BloodStatIterator it(kStatDude); - while (auto act = it.Next()) - { - spritetype *pSprite = &act->s(); - if (pSprite->type < kDudeBase || pSprite->type >= kDudeMax) - I_Error("Non-enemy sprite (%d) in the enemy sprite list.\n", pSprite->index); - unk[pSprite->type - kDudeBase] = 1; - } - - gKillMgr.CountTotalKills(); - /////////////// - - for (int i = 0; i < kDudeMax - kDudeBase; i++) - for (int j = 0; j < 7; j++) - dudeInfo[i].at70[j] = mulscale8(DudeDifficulty[gGameOptions.nDifficulty], dudeInfo[i].startDamage[j]); - - it.Reset(kStatDude); - while (auto act = it.Next()) - { - if (!act->hasX()) continue; - spritetype *pSprite = &act->s(); - XSPRITE *pXSprite = &act->x(); - - int nType = pSprite->type - kDudeBase; - int seqStartId = dudeInfo[nType].seqStartID; - if (!IsPlayerSprite(pSprite)) - { - #ifdef NOONE_EXTENSIONS - switch (pSprite->type) - { - case kDudeModernCustom: - case kDudeModernCustomBurning: - pSprite->cstat |= 4096 + CSTAT_SPRITE_BLOCK_HITSCAN + CSTAT_SPRITE_BLOCK; - seqStartId = genDudeSeqStartId(pXSprite); // Custom Dude stores its SEQ in data2 - pXSprite->sysData1 = pXSprite->data3; // move sndStartId to sysData1, because data3 used by the game; - pXSprite->data3 = 0; - break; - - case kDudePodMother: // FakeDude type (no seq, custom flags, clipdist and cstat) - if (gModernMap) break; - fallthrough__; - default: - pSprite->clipdist = dudeInfo[nType].clipdist; - pSprite->cstat |= 4096 + CSTAT_SPRITE_BLOCK_HITSCAN + CSTAT_SPRITE_BLOCK; - break; - } - #else - pSprite->clipdist = dudeInfo[nType].clipdist; - pSprite->cstat |= 4096 + CSTAT_SPRITE_BLOCK_HITSCAN + CSTAT_SPRITE_BLOCK; - #endif - - act->xvel() = act->yvel() = act->zvel() = 0; - - #ifdef NOONE_EXTENSIONS - // add a way to set custom hp for every enemy - should work only if map just started and not loaded. - if (!gModernMap || pXSprite->sysData2 <= 0) pXSprite->health = dudeInfo[nType].startHealth << 4; - else pXSprite->health = ClipRange(pXSprite->sysData2 << 4, 1, 65535); - #else - pXSprite->health = dudeInfo[nType].startHealth << 4; - #endif - - } - - if (getSequence(seqStartId)) seqSpawn(seqStartId, 3, pSprite->extra); - } - aiInit(); - } + BloodStatIterator it(kStatTraps); + while (auto act = it.Next()) + { + spritetype* pSprite = &act->s(); + if (pSprite->type == kTrapExploder) + { + pSprite->cstat &= ~1; + pSprite->cstat |= CSTAT_SPRITE_INVISIBLE; + if (!act->hasX()) continue; + auto x = &act->x(); + x->waitTime = ClipLow(x->waitTime, 1); + x->state = 0; + } + } } +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +void actInitThings() +{ + BloodStatIterator it(kStatThing); + while (auto act = it.Next()) + { + if (!act->hasX()) continue; + spritetype* pSprite = &act->s(); + XSPRITE* pXSprite = &act->x(); + + int nType = pSprite->type - kThingBase; + pXSprite->health = thingInfo[nType].startHealth << 4; +#ifdef NOONE_EXTENSIONS + // allow level designer to set custom clipdist. + // this is especially useful for various Gib and Explode objects which have clipdist 1 for some reason predefined, + // but what if it have voxel model...? + if (!gModernMap) +#endif + pSprite->clipdist = thingInfo[nType].clipdist; + + pSprite->flags = thingInfo[nType].flags; + if (pSprite->flags & kPhysGravity) pSprite->flags |= kPhysFalling; + act->xvel() = act->yvel() = act->zvel() = 0; + + switch (pSprite->type) { + case kThingArmedProxBomb: + case kTrapMachinegun: +#ifdef NOONE_EXTENSIONS + case kModernThingTNTProx: +#endif + pXSprite->state = 0; + break; + case kThingBloodChunks: { + SEQINST* pInst = GetInstance(3, pSprite->extra); + if (pInst) + { + auto seq = getSequence(pInst->nSeqID); + if (!seq) break; + seqSpawn(pInst->nSeqID, 3, pSprite->extra); + } + break; + } + default: + pXSprite->state = 1; + break; + } + } +} + +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +void actInitDudes() +{ + if (gGameOptions.nMonsterSettings == 0) + { + gKillMgr.SetCount(0); + BloodStatIterator it(kStatDude); + while (auto act = it.Next()) + { + spritetype* pSprite = &act->s(); + if (act->hasX() && act->x().key > 0) // Drop Key + actDropObject(pSprite, kItemKeyBase + (act->x().key - 1)); + DeleteSprite(act); + } + } + else + { + // by NoOne: WTF is this? + /////////////// + char unk[kDudeMax - kDudeBase]; + memset(unk, 0, sizeof(unk)); + BloodStatIterator it(kStatDude); + while (auto act = it.Next()) + { + spritetype* pSprite = &act->s(); + if (pSprite->type < kDudeBase || pSprite->type >= kDudeMax) + I_Error("Non-enemy sprite (%d) in the enemy sprite list.\n", pSprite->index); + unk[pSprite->type - kDudeBase] = 1; + } + + gKillMgr.CountTotalKills(); + /////////////// + + for (int i = 0; i < kDudeMax - kDudeBase; i++) + for (int j = 0; j < 7; j++) + dudeInfo[i].at70[j] = mulscale8(DudeDifficulty[gGameOptions.nDifficulty], dudeInfo[i].startDamage[j]); + + it.Reset(kStatDude); + while (auto act = it.Next()) + { + if (!act->hasX()) continue; + spritetype* pSprite = &act->s(); + XSPRITE* pXSprite = &act->x(); + + int nType = pSprite->type - kDudeBase; + int seqStartId = dudeInfo[nType].seqStartID; + if (!act->IsPlayerActor()) + { +#ifdef NOONE_EXTENSIONS + switch (pSprite->type) + { + case kDudeModernCustom: + case kDudeModernCustomBurning: + pSprite->cstat |= 4096 + CSTAT_SPRITE_BLOCK_HITSCAN + CSTAT_SPRITE_BLOCK; + seqStartId = genDudeSeqStartId(pXSprite); // Custom Dude stores its SEQ in data2 + pXSprite->sysData1 = pXSprite->data3; // move sndStartId to sysData1, because data3 used by the game; + pXSprite->data3 = 0; + break; + + case kDudePodMother: // FakeDude type (no seq, custom flags, clipdist and cstat) + if (gModernMap) break; + [[fallthrough]]; + default: + pSprite->clipdist = dudeInfo[nType].clipdist; + pSprite->cstat |= 4096 + CSTAT_SPRITE_BLOCK_HITSCAN + CSTAT_SPRITE_BLOCK; + break; + } +#else + pSprite->clipdist = dudeInfo[nType].clipdist; + pSprite->cstat |= 4096 + CSTAT_SPRITE_BLOCK_HITSCAN + CSTAT_SPRITE_BLOCK; +#endif + + act->xvel() = act->yvel() = act->zvel() = 0; + +#ifdef NOONE_EXTENSIONS + // add a way to set custom hp for every enemy - should work only if map just started and not loaded. + if (!gModernMap || pXSprite->sysData2 <= 0) pXSprite->health = dudeInfo[nType].startHealth << 4; + else pXSprite->health = ClipRange(pXSprite->sysData2 << 4, 1, 65535); +#else + pXSprite->health = dudeInfo[nType].startHealth << 4; +#endif + + } + + if (getSequence(seqStartId)) seqSpawn(seqStartId, 3, pSprite->extra); + } + aiInit(); + } +} + +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +void actInit(bool bSaveLoad) +{ + + #ifdef NOONE_EXTENSIONS + if (!gModernMap) nnExtResetGlobals(); + else nnExtInitModernStuff(bSaveLoad); + #endif + + BloodStatIterator it(kStatItem); + while (auto act = it.Next()) + { + if (act->s().type == kItemWeaponVoodooDoll) + { + act->s().type = kAmmoItemVoodooDoll; + break; + } + } + + actInitTraps(); + actInitThings(); + actInitDudes(); +} + +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + void ConcussSprite(int a1, spritetype *pSprite, int x, int y, int z, int a6) { assert(pSprite != NULL); diff --git a/source/blood/src/bloodactor.h b/source/blood/src/bloodactor.h index b586c53b9..544bc9c1f 100644 --- a/source/blood/src/bloodactor.h +++ b/source/blood/src/bloodactor.h @@ -25,10 +25,10 @@ public: DBloodActor() :index(int(this - base())) { /*assert(index >= 0 && index < kMaxSprites);*/ } DBloodActor& operator=(const DBloodActor& other) = default; - void Clear() - { - dudeSlope = 0; - } + void Clear() + { + dudeSlope = 0; + } bool hasX() { return sprite[index].extra > 0; } spritetype& s() { return sprite[index]; } XSPRITE& x() { return xsprite[sprite[index].extra]; } // calling this does not validate the xsprite! @@ -42,6 +42,43 @@ public: SPRITEMASS& spriteMass() { return gSpriteMass[sprite[index].extra]; } GENDUDEEXTRA& genDudeExtra() { return Blood::gGenDudeExtra[index]; } POINT3D& basePoint() { return Blood::baseSprite[index]; } + + void SetOwner(DBloodActor* own) + { + s().owner = own? own->s().index : -1; + } + + DBloodActor* GetOwner() + { + if (s().owner == -1) return nullptr; + return base() + s().owner; + } + + bool IsPlayerActor() + { + return s().type >= kDudePlayer1 && s().type <= kDudePlayer8; + } + + bool IsDudeActor() + { + return s().type >= kDudeBase && s().type < kDudeMax; + } + + bool IsItemActor() + { + return s().type >= kItemBase && s().type < kItemMax; + } + + bool IsWeaponActor() + { + return s().type >= kItemWeaponBase && s().type < kItemWeaponMax; + } + + bool IsAmmoActor() + { + return s().type >= kItemAmmoBase && s().type < kItemAmmoMax; + } + }; extern DBloodActor bloodActors[kMaxSprites];