From b196e67f4042518e53e924677088156cd15d1b5b Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 10 Aug 2022 23:45:29 +0200 Subject: [PATCH] ported SHA-1: 82e3f6af9367200853fe2af1b9665dd0c53b4f05 from NBlood * - Change gBusyCount limit to a higher value since xsector limit raised. gModernMap: - The return of the event causer (kChannelEventCauser, TXID 50). - Fix flags for kModernPropertiesChanger type. - Add new modern type kModernVelocityChanger. - New features for kMarkerWarpDest type. - New features for kModernSectorFXChanger type. - Fix sector condition 58. - Fix sprite hitscan conditions (35 - 38). - Add new command (kCmdEventKillFull). - Misc changes. # Conflicts: # source/games/blood/src/actor.cpp # source/games/blood/src/nnexts.cpp --- source/common/objects/dobjgc.h | 18 +- source/games/blood/src/actor.cpp | 44 +- source/games/blood/src/aicult.cpp | 4 +- source/games/blood/src/aiunicult.cpp | 6 +- source/games/blood/src/callback.cpp | 4 +- source/games/blood/src/eventq.cpp | 96 +++- source/games/blood/src/eventq.h | 9 +- source/games/blood/src/nnexts.cpp | 788 ++++++++++++++++++++------- source/games/blood/src/nnexts.h | 16 +- source/games/blood/src/triggers.cpp | 237 ++++---- source/games/blood/src/triggers.h | 12 +- source/games/blood/src/weapon.cpp | 16 +- 12 files changed, 853 insertions(+), 397 deletions(-) diff --git a/source/common/objects/dobjgc.h b/source/common/objects/dobjgc.h index a1695b8ef..7997145b7 100644 --- a/source/common/objects/dobjgc.h +++ b/source/common/objects/dobjgc.h @@ -107,6 +107,16 @@ namespace GC return obj = NULL; } + // Handles a read barrier for a const pointer. This does not alter the source data, but only returns NULL if the object is destroyed. + template inline T* ReadBarrier(const T*& obj) + { + if (obj == NULL || !(obj->ObjectFlags & OF_EuthanizeMe)) + { + return obj; + } + return NULL; + } + // Check if it's time to collect, and do a collection step if it is. static inline void CheckGC() { @@ -214,7 +224,13 @@ public: return GC::ReadBarrier(pp); } - constexpr T ForceGet() noexcept //for situations where the read barrier needs to be skipped. + constexpr T Get() const noexcept + { + auto ppp = pp; + return GC::ReadBarrier(ppp); + } + + constexpr T ForceGet() const noexcept //for situations where the read barrier needs to be skipped. { return pp; } diff --git a/source/games/blood/src/actor.cpp b/source/games/blood/src/actor.cpp index 25d5d9e29..8d22ca14e 100644 --- a/source/games/blood/src/actor.cpp +++ b/source/games/blood/src/actor.cpp @@ -3410,7 +3410,7 @@ void actKillDude(DBloodActor* killerActor, DBloodActor* actor, DAMAGE_TYPE damag gPlayer[p].fragger = nullptr; } if (actor->spr.type != kDudeCultistBeast) - trTriggerSprite(actor, kCmdOff); + trTriggerSprite(actor, kCmdOff, killerActor); actor->spr.flags |= 7; checkAddFrag(killerActor, actor); @@ -3690,7 +3690,7 @@ static int actDamageThing(DBloodActor* source, DBloodActor* actor, int damage, D break; } - trTriggerSprite(actor, kCmdOff); + trTriggerSprite(actor, kCmdOff, source); switch (actor->spr.type) { @@ -4087,7 +4087,7 @@ static void actImpactMissile(DBloodActor* missileActor, int hitCode) #ifdef NOONE_EXTENSIONS if (gModernMap && actorHit && actorHit->hasX() && actorHit->xspr.state != actorHit->xspr.restState && actorHit->xspr.Impact) - trTriggerSprite(actorHit, kCmdSpriteImpact); + trTriggerSprite(actorHit, kCmdSpriteImpact, missileActor); #endif missileActor->spr.cstat &= ~CSTAT_SPRITE_BLOCK_ALL; } @@ -4470,8 +4470,7 @@ static void ProcessTouchObjects(DBloodActor* actor) if (actor2 && actor2->hasX()) { - if (actor2->xspr.Touch && !actor2->xspr.isTriggered && (!actor2->xspr.DudeLockout || actor->IsPlayerActor())) - trTriggerSprite(actor2, kCmdSpriteTouch); + triggerTouchSprite(actor, actor2); } // Touch walls @@ -4482,14 +4481,9 @@ static void ProcessTouchObjects(DBloodActor* actor) pHWall = coll.hitWall; if (pHWall && pHWall->hasX()) { - if (pHWall->xw().triggerTouch && !pHWall->xw().isTriggered && (!pHWall->xw().dudeLockout || actor->IsPlayerActor())) - trTriggerWall(pHWall, kCmdWallTouch); + triggerTouchWall(actor, pHWall); } } - - // enough to reset SpriteHit values - if (pHWall != nullptr || actor2) actor->vel.X += 5; - } #endif } @@ -4804,14 +4798,14 @@ void MoveDude(DBloodActor* actor) } #ifdef NOONE_EXTENSIONS if (!gModernMap && hitActor->hasX() && hitActor->xspr.Touch && !hitActor->xspr.state && !hitActor->xspr.isTriggered) - trTriggerSprite(coll.actor(), kCmdSpriteTouch); + trTriggerSprite(coll.actor(), kCmdSpriteTouch, actor); #else if (hitActor->hasX() && hitActor->xspr.Touch && !hitActor->xspr.state && !hitActor->xspr.isTriggered) trTriggerSprite(coll.actor, kCmdSpriteTouch); #endif if (pDudeInfo->lockOut && hitActor->hasX() && hitActor->xspr.Push && !hitActor->xspr.key && !hitActor->xspr.DudeLockout && !hitActor->xspr.state && !hitActor->xspr.busy && !pPlayer) - trTriggerSprite(coll.actor(), kCmdSpritePush); + trTriggerSprite(coll.actor(), kCmdSpritePush, actor); break; } @@ -4822,7 +4816,7 @@ void MoveDude(DBloodActor* actor) if (pHitWall->hasX()) pHitXWall = &pHitWall->xw(); if (pDudeInfo->lockOut && pHitXWall && pHitXWall->triggerPush && !pHitXWall->key && !pHitXWall->dudeLockout && !pHitXWall->state && !pHitXWall->busy && !pPlayer) - trTriggerWall(pHitWall, kCmdWallPush); + trTriggerWall(pHitWall, kCmdWallPush, actor); if (pHitWall->twoSided()) { @@ -4830,7 +4824,7 @@ void MoveDude(DBloodActor* actor) XSECTOR* pHitXSector = pHitSector->hasX() ? &pHitSector->xs() : nullptr; if (pDudeInfo->lockOut && pHitXSector && pHitXSector->Wallpush && !pHitXSector->Key && !pHitXSector->dudeLockout && !pHitXSector->state && !pHitXSector->busy && !pPlayer) - trTriggerSector(pHitSector, kCmdSectorPush); + trTriggerSector(pHitSector, kCmdSectorPush, actor); if (top < pHitSector->ceilingz || bottom > pHitSector->floorz) { @@ -4857,14 +4851,14 @@ void MoveDude(DBloodActor* actor) XSECTOR* pXOldSector = pOldSector->hasX() ? &pOldSector->xs() : nullptr; if (pXOldSector && pXOldSector->Exit && (pPlayer || !pXOldSector->dudeLockout)) - trTriggerSector(pOldSector, kCmdSectorExit); + trTriggerSector(pOldSector, kCmdSectorExit, actor); ChangeActorSect(actor, pSector); if (pXSector && pXSector->Enter && (pPlayer || !pXSector->dudeLockout)) { if (pSector->type == kSectorTeleport) pXSector->actordata = actor; - trTriggerSector(pSector, kCmdSectorEnter); + trTriggerSector(pSector, kCmdSectorEnter, actor); } pSector = actor->sector(); @@ -5306,7 +5300,7 @@ int MoveMissile(DBloodActor* actor) XWALL* pXWall = &pWall->xw(); if (pXWall->triggerVector) { - trTriggerWall(pWall, kCmdWallImpact); + trTriggerWall(pWall, kCmdWallImpact, Owner? Owner : actor); if (!(pWall->cstat & CSTAT_WALL_BLOCK_HITSCAN)) { cliptype = -1; @@ -5638,7 +5632,7 @@ static void actCheckProximity() break; } if (actor->GetOwner() == nullptr) actor->SetOwner(dudeactor); - trTriggerSprite(actor, kCmdSpriteProximity); + trTriggerSprite(actor, kCmdSpriteProximity, dudeactor); } } } @@ -5702,7 +5696,7 @@ static void actCheckThings() Collision hit = MoveThing(actor); if (hit.type) { - if (actor->xspr.Impact) trTriggerSprite(actor, kCmdOff); + if (actor->xspr.Impact) trTriggerSprite(actor, kCmdOff, hit.type == kHitSprite? hit.safeActor() : nullptr); switch (actor->spr.type) { @@ -5814,7 +5808,7 @@ static void actCheckExplosion() for (auto pWall : affectedXWalls) { - trTriggerWall(pWall, kCmdWallImpact); + trTriggerWall(pWall, kCmdWallImpact, Owner); } BloodStatIterator it1(kStatDude); @@ -5906,7 +5900,7 @@ static void actCheckExplosion() if (!CheckSector(sectorMap, impactactor) || !CheckProximity(impactactor, x, y, z, pSector, radius)) continue; - trTriggerSprite(impactactor, kCmdSpriteImpact); + trTriggerSprite(impactactor, kCmdSpriteImpact, Owner); } } @@ -6043,7 +6037,7 @@ static void actCheckDudes() if (actor2->IsPlayerActor() && (unsigned int)actor2->xspr.health > 0) { if (CheckProximity(actor2, actor->spr.pos.X, actor->spr.pos.Y, actor->spr.pos.Z, actor->sector(), 128)) - trTriggerSprite(actor, kCmdSpriteProximity); + trTriggerSprite(actor, kCmdSpriteProximity, actor2); } } } @@ -6772,7 +6766,7 @@ void actFireVector(DBloodActor* shooter, int a2, int a3, int a4, int a5, int a6, if (pWall->hasX()) { if (pWall->xw().triggerVector) - trTriggerWall(pWall, kCmdWallImpact); + trTriggerWall(pWall, kCmdWallImpact, shooter); } break; } @@ -6787,7 +6781,7 @@ void actFireVector(DBloodActor* shooter, int a2, int a3, int a4, int a5, int a6, if (vectorType == kVectorTine && !actor->IsPlayerActor()) shift = 3; actDamageSprite(shooter, actor, pVectorData->dmgType, pVectorData->dmg << shift); - if (actor->hasX() && actor->xspr.Vector) trTriggerSprite(actor, kCmdSpriteImpact); + if (actor->hasX() && actor->xspr.Vector) trTriggerSprite(actor, kCmdSpriteImpact, shooter); if (actor->spr.statnum == kStatThing) { diff --git a/source/games/blood/src/aicult.cpp b/source/games/blood/src/aicult.cpp index b949d95c2..fc1b9effe 100644 --- a/source/games/blood/src/aicult.cpp +++ b/source/games/blood/src/aicult.cpp @@ -142,7 +142,7 @@ void cultThrowSeqCallback(int, DBloodActor* actor) if (v4) pMissile->xspr.Impact = 1; else - evPostActor(pMissile, 120 * (1 + Random(2)), kCmdOn); + evPostActor(pMissile, 120 * (1 + Random(2)), kCmdOn, actor); } void sub_68170(int, DBloodActor* actor) @@ -152,7 +152,7 @@ void sub_68170(int, DBloodActor* actor) nMissile = kThingArmedTNTBundle; sfxPlay3DSound(actor, 455, -1, 0); auto pMissile = actFireThing(actor, 0, 0, actor->dudeSlope - 9460, nMissile, 0x133333); - evPostActor(pMissile, 120 * (2 + Random(2)), kCmdOn); + evPostActor(pMissile, 120 * (2 + Random(2)), kCmdOn, actor); } void sub_68230(int, DBloodActor* actor) diff --git a/source/games/blood/src/aiunicult.cpp b/source/games/blood/src/aiunicult.cpp index 66c1c41cf..cdb498d8b 100644 --- a/source/games/blood/src/aiunicult.cpp +++ b/source/games/blood/src/aiunicult.cpp @@ -387,7 +387,7 @@ static void ThrowThing(DBloodActor* actor, bool impact) if (impact == true && dist <= 7680) spawned->xspr.Impact = true; else { spawned->xspr.Impact = false; - evPostActor(spawned, 120 * Random(2) + 120, kCmdOn); + evPostActor(spawned, 120 * Random(2) + 120, kCmdOn, actor); } } @@ -1973,7 +1973,7 @@ void genDudeTransform(DBloodActor* actor) if (actIncarnation == NULL) { if (actor->xspr.sysData1 == kGenDudeTransformStatus) actor->xspr.sysData1 = 0; - trTriggerSprite(actor, kCmdOff); + trTriggerSprite(actor, kCmdOff, actor); return; } @@ -1988,7 +1988,7 @@ void genDudeTransform(DBloodActor* actor) actIncarnation->xspr.triggerOff = false; // trigger dude death before transform - trTriggerSprite(actor, kCmdOff); + trTriggerSprite(actor, kCmdOff, actor); actor->spr.type = actor->spr.inittype = actIncarnation->spr.type; actor->spr.flags = actIncarnation->spr.flags; diff --git a/source/games/blood/src/callback.cpp b/source/games/blood/src/callback.cpp index 4e33d35e8..843648622 100644 --- a/source/games/blood/src/callback.cpp +++ b/source/games/blood/src/callback.cpp @@ -593,13 +593,13 @@ void returnFlagToBase(DBloodActor* actor, sectortype*) // 17 switch (actor->spr.type) { case kItemFlagA: - trTriggerSprite(aOwner, kCmdOn); + trTriggerSprite(aOwner, kCmdOn, aOwner); sndStartSample(8003, 255, 2, 0); gBlueFlagDropped = false; viewSetMessage("Blue Flag returned to base."); break; case kItemFlagB: - trTriggerSprite(aOwner, kCmdOn); + trTriggerSprite(aOwner, kCmdOn, aOwner); sndStartSample(8002, 255, 2, 0); gRedFlagDropped = false; viewSetMessage("Red Flag returned to base."); diff --git a/source/games/blood/src/eventq.cpp b/source/games/blood/src/eventq.cpp index 06e5c4b21..cd09be389 100644 --- a/source/games/blood/src/eventq.cpp +++ b/source/games/blood/src/eventq.cpp @@ -349,7 +349,7 @@ static bool evGetSourceState(EventObject& eob) // //--------------------------------------------------------------------------- -void evSend(EventObject& eob, int rxId, COMMAND_ID command) +void evSend(EventObject& eob, int rxId, COMMAND_ID command, DBloodActor* initiator) { switch (command) { case kCmdState: @@ -365,6 +365,7 @@ void evSend(EventObject& eob, int rxId, COMMAND_ID command) EVENT event; event.target = eob; event.cmd = command; + event.initiator = gModernMap? initiator : nullptr; switch (rxId) { case kChannelTextOver: @@ -459,17 +460,46 @@ void evSend(EventObject& eob, int rxId, COMMAND_ID command) if (playerRXRngIsFine(rxId)) { if ((pPlayer = getPlayerById((rxId - kChannelPlayer7) + kMaxPlayers)) != nullptr) - trMessageSprite(pPlayer->actor, event); + { + if (command == kCmdEventKillFull) + evKillActor(pPlayer->actor); + else + trMessageSprite(pPlayer->actor, event); + } } else if (rxId == kChannelAllPlayers) { for (int i = 0; i < kMaxPlayers; i++) { if ((pPlayer = getPlayerById(i)) != nullptr) - trMessageSprite(pPlayer->actor, event); + { + if (command == kCmdEventKillFull) + evKillActor(pPlayer->actor); + else + trMessageSprite(pPlayer->actor, event); + } } return; } + // send command on sprite which created the event sequence + else if (rxId == kChannelEventCauser && event.initiator != nullptr) + { + DBloodActor* einitiator = event.initiator; + if (!(einitiator->spr.flags & kHitagFree) && !(einitiator->spr.flags & kHitagRespawn)) + { + if (command == kCmdEventKillFull) + evKillActor(einitiator); + else + trMessageSprite(einitiator, event); + } + + return; + } + else if (command == kCmdEventKillFull) + { + killEvents(rxId, command); + return; + } } #endif @@ -506,12 +536,12 @@ void evSend(EventObject& eob, int rxId, COMMAND_ID command) // //--------------------------------------------------------------------------- -void evPost_(EventObject& eob, unsigned int nDelta, COMMAND_ID command) +void evPost_(EventObject& eob, unsigned int nDelta, COMMAND_ID command, DBloodActor* initiator) { assert(command != kCmdCallback); if (command == kCmdState) command = evGetSourceState(eob) ? kCmdOn : kCmdOff; else if (command == kCmdNotState) command = evGetSourceState(eob) ? kCmdOff : kCmdOn; - EVENT evn = { eob, (int8_t)command, 0, PlayClock + (int)nDelta }; + EVENT evn = { eob, (int8_t)command, 0, PlayClock + (int)nDelta, MakeObjPtr(gModernMap ? initiator : nullptr) }; queue.insert(evn); } @@ -522,10 +552,10 @@ void evPost_(const EventObject& eob, unsigned int nDelta, CALLBACK_ID callback) } -void evPostActor(DBloodActor* actor, unsigned int nDelta, COMMAND_ID command) +void evPostActor(DBloodActor* actor, unsigned int nDelta, COMMAND_ID command, DBloodActor* initiator) { auto ev = EventObject(actor); - evPost_(ev, nDelta, command); + evPost_(ev, nDelta, command, initiator); } void evPostActor(DBloodActor* actor, unsigned int nDelta, CALLBACK_ID callback) @@ -533,10 +563,10 @@ void evPostActor(DBloodActor* actor, unsigned int nDelta, CALLBACK_ID callback) evPost_(EventObject(actor), nDelta, callback); } -void evPostSector(sectortype* sect, unsigned int nDelta, COMMAND_ID command) +void evPostSector(sectortype* sect, unsigned int nDelta, COMMAND_ID command, DBloodActor* initiator) { auto ev = EventObject(sect); - evPost_(ev, nDelta, command); + evPost_(ev, nDelta, command, initiator); } void evPostSector(sectortype* sect, unsigned int nDelta, CALLBACK_ID callback) @@ -544,10 +574,10 @@ void evPostSector(sectortype* sect, unsigned int nDelta, CALLBACK_ID callback) evPost_(EventObject(sect), nDelta, callback); } -void evPostWall(walltype* wal, unsigned int nDelta, COMMAND_ID command) +void evPostWall(walltype* wal, unsigned int nDelta, COMMAND_ID command, DBloodActor* initiator) { auto ev = EventObject(wal); - evPost_(ev, nDelta, command); + evPost_(ev, nDelta, command, initiator); } @@ -566,6 +596,15 @@ void evKill_(const EventObject& eob) } } +void evKill_(const EventObject& eob, DBloodActor* initiator) +{ + for (auto ev = queue.begin(); ev != queue.end();) + { + if (ev->event_isObject(eob) && ev->initiator.ForceGet() == initiator) ev = queue.erase(ev); + else ev++; + } +} + void evKill_(const EventObject& eob, CALLBACK_ID cb) { for (auto ev = queue.begin(); ev != queue.end();) @@ -580,6 +619,14 @@ void evKillActor(DBloodActor* actor) evKill_(EventObject(actor)); } +void evKillActor(DBloodActor* actor, DBloodActor* initiator) +{ + if (!gModernMap) + evKill_(EventObject(actor)); + else + evKill_(EventObject(actor), initiator); +} + void evKillActor(DBloodActor* actor, CALLBACK_ID cb) { evKill_(EventObject(actor)); @@ -595,29 +642,39 @@ void evKillSector(sectortype* sec) evKill_(EventObject(sec)); } +void evKillWall(walltype* wal, DBloodActor* initiator) +{ + evKill_(EventObject(wal), initiator); +} + +void evKillSector(sectortype* sec, DBloodActor* initiator) +{ + evKill_(EventObject(sec), initiator); +} + // these have no target. -void evSendGame(int rxId, COMMAND_ID command) +void evSendGame(int rxId, COMMAND_ID command, DBloodActor* initiator = nullptr) { auto ev = EventObject(nullptr); - evSend(ev, rxId, command); + evSend(ev, rxId, command, initiator); } -void evSendActor(DBloodActor* actor, int rxId, COMMAND_ID command) +void evSendActor(DBloodActor* actor, int rxId, COMMAND_ID command, DBloodActor* initiator = nullptr) { auto ev = EventObject(actor); - evSend(ev, rxId, command); + evSend(ev, rxId, command, initiator); } -void evSendSector(sectortype* sect, int rxId, COMMAND_ID command) +void evSendSector(sectortype* sect, int rxId, COMMAND_ID command, DBloodActor* initiator = nullptr) { auto ev = EventObject(sect); - evSend(ev, rxId, command); + evSend(ev, rxId, command, initiator); } -void evSendWall(walltype* wal, int rxId, COMMAND_ID command) +void evSendWall(walltype* wal, int rxId, COMMAND_ID command, DBloodActor* initiator = nullptr) { auto ev = EventObject(wal); - evSend(ev, rxId, command); + evSend(ev, rxId, command, initiator); } //--------------------------------------------------------------------------- @@ -703,6 +760,7 @@ FSerializer& Serialize(FSerializer& arc, const char* keyname, EVENT& w, EVENT* d ("command", w.cmd) ("func", w.funcID) ("prio", w.priority) + ("initiator",w.initiator) .EndObject(); } return arc; diff --git a/source/games/blood/src/eventq.h b/source/games/blood/src/eventq.h index e09c14086..83b1ba4a0 100644 --- a/source/games/blood/src/eventq.h +++ b/source/games/blood/src/eventq.h @@ -158,6 +158,7 @@ enum COMMAND_ID { kCmdSectorMotionPause = 13, // stops motion of the sector kCmdSectorMotionContinue = 14, // continues motion of the sector kCmdDudeFlagsSet = 15, // copy dudeFlags from sprite to dude + kCmdEventKillFull = 16, // immediately kill the pending object events kCmdModernUse = 53, // used by most of modern types #endif @@ -192,6 +193,7 @@ struct EVENT int8_t cmd; int16_t funcID; int priority; + TObjPtr initiator; bool operator<(const EVENT& other) const { @@ -238,16 +240,17 @@ struct EVENT }; void evInit(TArray& actors); -void evPostActor(DBloodActor*, unsigned int nDelta, COMMAND_ID command); +void evPostActor(DBloodActor*, unsigned int nDelta, COMMAND_ID command, DBloodActor* initiator); void evPostActor(DBloodActor*, unsigned int nDelta, CALLBACK_ID callback); -void evPostSector(sectortype* index, unsigned int nDelta, COMMAND_ID command); +void evPostSector(sectortype* index, unsigned int nDelta, COMMAND_ID command, DBloodActor* initiator); void evPostSector(sectortype* index, unsigned int nDelta, CALLBACK_ID callback); -void evPostWall(walltype* index, unsigned int nDelta, COMMAND_ID command); +void evPostWall(walltype* index, unsigned int nDelta, COMMAND_ID command, DBloodActor* initiator); void evProcess(unsigned int nTime); void evKillActor(DBloodActor*); +void evKillActor(DBloodActor*, DBloodActor* initiator); void evKillActor(DBloodActor*, CALLBACK_ID a3); END_BLD_NS diff --git a/source/games/blood/src/nnexts.cpp b/source/games/blood/src/nnexts.cpp index b0be85e96..768843d75 100644 --- a/source/games/blood/src/nnexts.cpp +++ b/source/games/blood/src/nnexts.cpp @@ -436,21 +436,21 @@ bool nnExtEraseModernStuff(DBloodActor* actor) // //--------------------------------------------------------------------------- -void nnExtTriggerObject(EventObject& eob, int command) +void nnExtTriggerObject(EventObject& eob, int command, DBloodActor* initiator) { if (eob.isSector()) { - trTriggerSector(eob.sector(), command); + trTriggerSector(eob.sector(), command, initiator); } else if (eob.isWall()) { - trTriggerWall(eob.wall(), command); + trTriggerWall(eob.wall(), command, initiator); } else if (eob.isActor()) { auto objActor = eob.actor(); if (!objActor || !objActor->hasX()) return; - trTriggerSprite(objActor, command); + trTriggerSprite(objActor, command, initiator); } } @@ -695,7 +695,7 @@ void nnExtInitModernStuff(TArray& actors) break; } case 67: // play qav animation - if (actor->xspr.txID && !actor->xspr.waitTime) actor->xspr.waitTime = 1; + if (actor->xspr.txID >= kChannelUser && !actor->xspr.waitTime) actor->xspr.waitTime = 1; ChangeActorStat(actor, kStatModernQavScene); break; } @@ -758,7 +758,7 @@ void nnExtInitModernStuff(TArray& actors) case kStatFX: case kStatExplosion: case kStatItem: case kStatPurge: case kStatSpares: case kStatFlare: case kStatInactive: case kStatFree: case kStatMarker: - case kStatPathMarker: case kStatThing: case kStatDude: + case kStatThing: case kStatDude: case kStatModernPlayerLinker: break; default: @@ -777,7 +777,7 @@ void nnExtInitModernStuff(TArray& actors) case kStatFX: case kStatExplosion: case kStatItem: case kStatPurge: case kStatSpares: case kStatFlare: case kStatInactive: case kStatFree: case kStatMarker: - case kStatPathMarker: case kStatModernPlayerLinker: + case kStatModernPlayerLinker: break; default: gSightSpritesList[gSightSpritesCount++] = actor; @@ -795,7 +795,7 @@ void nnExtInitModernStuff(TArray& actors) case kStatFX: case kStatExplosion: case kStatItem: case kStatPurge: case kStatSpares: case kStatFlare: case kStatInactive: case kStatFree: case kStatMarker: - case kStatPathMarker: case kStatModernPlayerLinker: + case kStatModernPlayerLinker: break; default: gImpactSpritesList[gImpactSpritesCount++] = actor; @@ -1102,6 +1102,7 @@ void nnExtProcessSuperSprites() evn.target = pCond->obj[k].obj; evn.cmd = pCond->obj[k].cmd; evn.funcID = kCallbackMax; + evn.initiator = nullptr; useCondition(pCond->actor, evn); } } @@ -1111,6 +1112,7 @@ void nnExtProcessSuperSprites() evn.target = EventObject(pCond->actor); evn.cmd = (int8_t)aCond->xspr.command; evn.funcID = kCallbackMax; + evn.initiator = nullptr; useCondition(pCond->actor, evn); } @@ -1193,7 +1195,7 @@ void nnExtProcessSuperSprites() if (!affected->hasX() || affected->xspr.health <= 0) continue; else if (CheckProximity(affected, x, y, z, pSect, okDist)) { - trTriggerSprite(pProx, kCmdSpriteProximity); + trTriggerSprite(pProx, kCmdSpriteProximity, affected); break; } } @@ -1208,8 +1210,7 @@ void nnExtProcessSuperSprites() if (pPlayer->actor->xspr.health > 0 && CheckProximity(gPlayer->actor, x, y, z, pSect, okDist)) { - trTriggerSprite(pProx, kCmdSpriteProximity); - break; + trTriggerSprite(pProx, kCmdSpriteProximity, pPlayer->actor); } } } @@ -1253,8 +1254,7 @@ void nnExtProcessSuperSprites() { if (pSight->xspr.Sight) { - trTriggerSprite(pSight, kCmdSpriteSight); - break; + trTriggerSprite(pSight, kCmdSpriteSight, plActor); } if (pSight->xspr.unused3 & kTriggerSpriteAim) @@ -1270,8 +1270,7 @@ void nnExtProcessSuperSprites() if (gHitInfo.actor() == pSight) { - trTriggerSprite(gHitInfo.actor(), kCmdSpriteSight); - break; + trTriggerSprite(gHitInfo.actor(), kCmdSpriteSight, plActor); } } } @@ -1854,7 +1853,7 @@ void debrisMove(int listIndex) if (actor->spr.type >= kThingBase && actor->spr.type < kThingMax) ChangeActorStat(actor, kStatThing); - trTriggerSprite(actor, kCmdToggle); + trTriggerSprite(actor, kCmdToggle, actor); } if (!actor->vel.X && !actor->vel.Y) return; @@ -2584,6 +2583,7 @@ void usePropertiesChanger(DBloodActor* sourceactor, int objType, sectortype* pSe // data4 = set wall cstat if (valueIsBetween(data4, -1, 65535)) { + auto old = pWall->cstat; // relative if (flag1) { @@ -2593,7 +2593,6 @@ void usePropertiesChanger(DBloodActor* sourceactor, int objType, sectortype* pSe // absolute else { - auto old = pWall->cstat; pWall->cstat = EWallFlags::FromInt(data4); if (!flag2) { @@ -2613,6 +2612,7 @@ void usePropertiesChanger(DBloodActor* sourceactor, int objType, sectortype* pSe // data3 = set sprite hitag if (valueIsBetween(data3, -1, 32767)) { + old = targetactor->spr.flags; // relative if (flag1) { @@ -2622,7 +2622,6 @@ void usePropertiesChanger(DBloodActor* sourceactor, int objType, sectortype* pSe // absolute else { - old = targetactor->spr.flags; targetactor->spr.flags = data3; } @@ -3021,6 +3020,167 @@ void usePropertiesChanger(DBloodActor* sourceactor, int objType, sectortype* pSe // //--------------------------------------------------------------------------- +void useVelocityChanger(DBloodActor* actor, sectortype* sect, DBloodActor* initiator, DBloodActor* pSprite) +//void useVelocityChanger(XSPRITE* pXSource, int causerID, short objType, int objIndex) +{ +#define kVelShift 8 +#define kScaleVal 0x10000 + + int t, r = 0, nAng = 0, vAng = 0; + int xv = 0, yv = 0, zv = 0; + + bool relative = (actor->spr.flags & kModernTypeFlag1); + bool toDstAng = (actor->spr.flags & kModernTypeFlag2); + bool toSrcAng = (actor->spr.flags & kModernTypeFlag4); + bool toRndAng = (actor->spr.flags & kModernTypeFlag8); + bool chgDstAng = !(actor->spr.flags & kModernTypeFlag16); + bool toEvnAng = (toDstAng && toSrcAng && initiator != NULL); + bool toAng = (toDstAng || toSrcAng || toEvnAng || toRndAng); + bool toAng180 = (toRndAng && (toDstAng || toSrcAng || toEvnAng)); + + if (actor) + { + if ((r = MulScale(actor->xspr.data4 << kVelShift, kScaleVal, 14)) != 0) + r = nnExtRandom(-r, r); + + if (valueIsBetween(actor->xspr.data3, -32767, 32767)) + { + if ((zv = MulScale(actor->xspr.data3 << kVelShift, kScaleVal, 14)) != 0) + zv += r; + } + + if (!toAng) + { + if (valueIsBetween(actor->xspr.data1, -32767, 32767)) + { + if ((xv = MulScale(actor->xspr.data1 << kVelShift, kScaleVal, 14)) != 0) + xv += r; + } + + if (valueIsBetween(actor->xspr.data2, -32767, 32767)) + { + if ((yv = MulScale(actor->xspr.data2 << kVelShift, kScaleVal, 14)) != 0) + yv += r; + } + } + else + { + if (toEvnAng) nAng = initiator->spr.ang; + else if (toSrcAng) nAng = actor->spr.ang; + else nAng = pSprite->spr.ang; + + nAng = nAng & 2047; + + if (!toAng180 && toRndAng) + { + t = nAng; + while (t == nAng) + nAng = nnExtRandom(0, kAng360); + } + + if (chgDstAng) + changeSpriteAngle(pSprite, nAng); + + if ((t = (actor->xspr.data1 << kVelShift)) != 0) + t += r; + + xv = MulScale(t, Cos(nAng) >> 16, 14); + yv = MulScale(t, Sin(nAng) >> 16, 14); + } + + if (actor->xspr.physAttr) + { + t = 1; + switch (pSprite->spr.statnum) { + case kStatThing: + break; + case kStatFX: + t = 0; + [[fallthrough]]; + case kStatDude: + case kStatProjectile: + if (actor->xspr.physAttr & kPhysMove) pSprite->spr.flags |= kPhysMove; else pSprite->spr.flags &= ~kPhysMove; + if (actor->xspr.physAttr & kPhysGravity) pSprite->spr.flags |= kPhysGravity; else pSprite->spr.flags &= ~kPhysGravity; + if (actor->xspr.physAttr & kPhysFalling) pSprite->spr.flags |= kPhysFalling; else pSprite->spr.flags &= ~kPhysFalling; + break; + } + + // debris physics for sprites that is allowed + if (t && ((t = debrisGetIndex(pSprite)) >= 0 || (t = debrisGetFreeIndex()) >= 0)) + { + pSprite->addX(); + + if (pSprite->spr.statnum == kStatThing) + { + pSprite->spr.flags &= ~(kPhysMove | kPhysGravity | kPhysFalling); + ChangeActorStat(pSprite, 0); + } + + pSprite->xspr.physAttr = actor->xspr.physAttr, gPhysSpritesList[t] = pSprite; + + getSpriteMassBySize(pSprite); + if (t >= gPhysSpritesCount) + gPhysSpritesCount++; + } + } + + if (relative) + { + pSprite->vel.X += xv; + pSprite->vel.Y += yv; + pSprite->vel.Z += zv; + } + else + { + pSprite->vel.X = xv; + pSprite->vel.Y = yv; + pSprite->vel.Z = zv; + } + + vAng = getVelocityAngle(pSprite); + + if (toAng) + { + if (toAng180) + RotatePoint(&pSprite->vel.X, &pSprite->vel.Y, kAng180, pSprite->spr.pos.X, pSprite->spr.pos.Y); + else + RotatePoint(&pSprite->vel.X, &pSprite->vel.Y, (nAng - vAng) & 2047, pSprite->spr.pos.X, pSprite->spr.pos.Y); + + + vAng = getVelocityAngle(pSprite); + } + + if (chgDstAng) + changeSpriteAngle(pSprite, vAng); + + if (pSprite->ownerActor) + { + // hack to make player projectiles damage it's owner + if (pSprite->spr.statnum == kStatProjectile && pSprite->IsPlayerActor()) + pSprite->ownerActor = pSprite; + } + + viewCorrectPrediction(); + + //if (pXSource->rxID == 157) + //viewSetSystemMessage("%d: %d / %d / %d, C: %d", pSprite->spr.sectnum, pSprite->vel.X, pSprite->vel.Y, pSprite->vel.Z, sprite[causerID].type); + } + else if (sect) + { + BloodSectIterator it(sect); + while(auto act = it.Next()) + { + useVelocityChanger(actor, nullptr, initiator, act); + } + } +} + +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + void useTeleportTarget(DBloodActor* sourceactor, DBloodActor* actor) { PLAYER* pPlayer = getPlayerById(actor->spr.type); @@ -3047,7 +3207,7 @@ void useTeleportTarget(DBloodActor* sourceactor, DBloodActor* actor) { if (pXSector->Enter && (pPlayer || (isDude && !pXSector->dudeLockout))) - trTriggerSector(sourceactor->sector(), kCmdSectorEnter); + trTriggerSector(sourceactor->sector(), kCmdSectorEnter, actor); if (pXSector->Underwater) { @@ -3106,7 +3266,7 @@ void useTeleportTarget(DBloodActor* sourceactor, DBloodActor* actor) aiInitSprite(actor); - if (target != nullptr) + if (target != nullptr && target->IsDudeActor()) { actor->xspr.TargetPos.X = x; actor->xspr.TargetPos.Y = y; @@ -3116,6 +3276,7 @@ void useTeleportTarget(DBloodActor* sourceactor, DBloodActor* actor) } } +#if 0 if (sourceactor->xspr.data2 == 1) { if (pPlayer) @@ -3126,9 +3287,27 @@ void useTeleportTarget(DBloodActor* sourceactor, DBloodActor* actor) else if (isDude) sourceactor->xspr.goalAng = actor->spr.ang = sourceactor->spr.ang; else actor->spr.ang = sourceactor->spr.ang; } +#endif if (sourceactor->xspr.data3 == 1) + { actor->vel.X = actor->vel.Y = actor->vel.Z = 0; + } + else if (sourceactor->xspr.data3 > 0) + { + // change movement direction according source angle + if (sourceactor->xspr.data3 & kModernTypeFlag2) + { + int vAng = getVelocityAngle(actor); + RotatePoint(&actor->vel.X, &actor->vel.Y, (sourceactor->spr.ang - vAng) & 2047, actor->spr.pos.X, actor->spr.pos.Y); + } + + if (sourceactor->xspr.data3 & kModernTypeFlag4) + actor->vel.Z = 0; + } + + if (sourceactor->xspr.data2 == 1) + changeSpriteAngle(actor, sourceactor->spr.ang); viewBackupSpriteLoc(actor); @@ -3185,9 +3364,16 @@ void useEffectGen(DBloodActor* sourceactor, DBloodActor* actor) break; case 3: case 4: - if (!actor->insector()) pos = top; - else pos = (sourceactor->xspr.data4 == 3) ? actor->sector()->floorz : actor->sector()->ceilingz; - break; + if (actor->insector()) + { + if (sourceactor->xspr.data4 == 3) + pos = getflorzofslopeptr(actor->sector(), actor->spr.pos.X, actor->spr.pos.Y); + else + pos = getceilzofslopeptr(actor->sector(), actor->spr.pos.X, actor->spr.pos.Y); + + break; + } + [[fallthrough]]; default: pos = top; break; @@ -3619,7 +3805,9 @@ void useSeqSpawnerGen(DBloodActor* sourceactor, int objType, sectortype* pSector case 5: case 6: if (!iactor->insector()) spawned->spr.pos.Z = top; - else spawned->spr.pos.Z = (sourceactor->xspr.data3 == 5) ? spawned->sector()->floorz : spawned->sector()->ceilingz; + else spawned->spr.pos.Z = ((sourceactor->xspr.data3 == 5) ? + getflorzofslopeptr(spawned->sector(), spawned->spr.pos.X, spawned->spr.pos.Y) : + getceilzofslopeptr(spawned->sector(), spawned->spr.pos.X, spawned->spr.pos.Y)); break; } @@ -3810,8 +3998,8 @@ bool condCheckMixed(DBloodActor* aCond, const EVENT& event, int cmpOp, bool PUSH case 25: return condCmp(pObj->picnum, arg1, arg2, cmpOp); case 26: return condCmp(pObj->pal, arg1, arg2, cmpOp); case 27: return condCmp(pObj->shade, arg1, arg2, cmpOp); - case 28: return (pObj->cstat & EWallFlags::FromInt(arg1)); - case 29: return (pObj->hitag & arg1); + case 28: return (arg3) ? condCmp((pObj->cstat & EWallFlags::FromInt(arg3)), arg1, arg2, cmpOp) : (pObj->cstat & EWallFlags::FromInt(arg1)); + case 29: return (arg3) ? condCmp((pObj->hitag & arg3), arg1, arg2, cmpOp) : (pObj->hitag & arg1); case 30: return condCmp(pObj->xrepeat, arg1, arg2, cmpOp); case 31: return condCmp(pObj->xpan(), arg1, arg2, cmpOp); case 32: return condCmp(pObj->yrepeat, arg1, arg2, cmpOp); @@ -3828,8 +4016,8 @@ bool condCheckMixed(DBloodActor* aCond, const EVENT& event, int cmpOp, bool PUSH case 25: return condCmp(actor->spr.picnum, arg1, arg2, cmpOp); case 26: return condCmp(actor->spr.pal, arg1, arg2, cmpOp); case 27: return condCmp(actor->spr.shade, arg1, arg2, cmpOp); - case 28: return (actor->spr.cstat & ESpriteFlags::FromInt(arg1)); - case 29: return (actor->spr.flags & arg1); + case 28: return (arg3) ? condCmp((actor->spr.cstat & ESpriteFlags::FromInt(arg3)), arg1, arg2, cmpOp) : (actor->spr.cstat & ESpriteFlags::FromInt(arg1)); + case 29: return (arg3) ? condCmp((actor->spr.hitag & arg3), arg1, arg2, cmpOp) : (actor->spr.hitag & arg1); case 30: return condCmp(actor->spr.xrepeat, arg1, arg2, cmpOp); case 31: return condCmp(actor->spr.xoffset, arg1, arg2, cmpOp); case 32: return condCmp(actor->spr.yrepeat, arg1, arg2, cmpOp); @@ -3884,7 +4072,7 @@ bool condCheckMixed(DBloodActor* aCond, const EVENT& event, int cmpOp, bool PUSH } break; } - case 29: return (pObj->hitag & arg1); + case 29: return (arg3) ? condCmp((pObj->hitag & arg3), arg1, arg2, cmpOp) : (pObj->hitag & arg1); case 30: return condCmp(pObj->floorxpan(), arg1, arg2, cmpOp); case 31: return condCmp(pObj->ceilingxpan(), arg1, arg2, cmpOp); case 32: return condCmp(pObj->floorypan(), arg1, arg2, cmpOp); @@ -4476,9 +4664,9 @@ bool condCheckSprite(DBloodActor* aCond, int cmpOp, bool PUSH) var = HitScan(objActor, pPlayer->zWeapon, pPlayer->aim.dx, pPlayer->aim.dy, pPlayer->aim.dz, arg1, arg3 << 1); else if (objActor->IsDudeActor()) var = HitScan(objActor, objActor->spr.pos.Z, bcos(objActor->spr.ang), bsin(objActor->spr.ang), (!objActor->hasX()) ? 0 : objActor->dudeSlope, arg1, arg3 << 1); - else if ((var2 & CSTAT_SPRITE_ALIGNMENT_MASK) == CSTAT_SPRITE_ALIGNMENT_FLOOR) + else if ((objActor->spr.cstat & CSTAT_SPRITE_ALIGNMENT_MASK) == CSTAT_SPRITE_ALIGNMENT_FLOOR) { - var3 = (var2 & 0x0008) ? 0x10000 << 1 : -(0x10000 << 1); + var3 = (objActor->spr.cstat & CSTAT_SPRITE_YFLIP) ? 0x10000 << 1 : -(0x10000 << 1); var = HitScan(objActor, objActor->spr.pos.Z, Cos(objActor->spr.ang) >> 16, Sin(objActor->spr.ang) >> 16, var3, arg1, arg3 << 1); } else @@ -4486,26 +4674,28 @@ bool condCheckSprite(DBloodActor* aCond, int cmpOp, bool PUSH) var = HitScan(objActor, objActor->spr.pos.Z, bcos(objActor->spr.ang), bsin(objActor->spr.ang), 0, arg1, arg3 << 1); } - if (var >= 0) - { - switch (cond) - { - case 35: retn = (var == 1); break; - case 36: retn = (var == 2); break; - case 37: retn = (var == 0 || var == 4); break; - case 38: retn = (var == 3); break; - } - - if (!PUSH) return retn; - switch (var) - { - case 0: case 4: condPush(aCond, gHitInfo.hitWall); break; - case 1: case 2: condPush(aCond, gHitInfo.hitSector); break; - case 3: condPush(aCond, gHitInfo.actor()); break; - } + if (var < 0) + return false; + switch (cond) { + case 35: + if (var != 1) return false; + else if (PUSH) condPush(aCond, gHitInfo.hitSector); + return true; + case 36: + if (var != 2) return false; + else if (PUSH) condPush(aCond, gHitInfo.hitSector); + return true; + case 37: + if (var != 0 && var != 4) return false; + else if (PUSH) condPush(aCond, gHitInfo.hitWall); + return true; + case 38: + if (var != 3) return false; + else if (PUSH) condPush(aCond, gHitInfo.actor()); + return true; } - return retn; + break; case 45: // this sprite is a target of some dude? BloodStatIterator it(kStatDude); @@ -4564,10 +4754,10 @@ bool condCheckSprite(DBloodActor* aCond, int cmpOp, bool PUSH) if (objActor->hit.ceilhit.type == kHitSprite) actorvar = objActor->hit.ceilhit.safeActor(); break; } - if (actorvar == nullptr) + if (actorvar == nullptr && objActor->insector()) { // check if something is touching this sprite - BloodSpriteIterator it; + BloodSectIterator it(objActor->sector()); while (auto iactor = it.Next()) { if (iactor->spr.flags & kHitagRespawn) continue; @@ -4675,7 +4865,7 @@ void condUpdateObjectIndex(DBloodActor* oldActor, DBloodActor* newActor) // //--------------------------------------------------------------------------- -bool modernTypeSetSpriteState(DBloodActor* actor, int nState) +bool modernTypeSetSpriteState(DBloodActor* actor, int nState, DBloodActor* initiator) { if ((actor->xspr.busy & 0xffff) == 0 && actor->xspr.state == nState) return false; @@ -4683,12 +4873,12 @@ bool modernTypeSetSpriteState(DBloodActor* actor, int nState) actor->xspr.busy = IntToFixed(nState); actor->xspr.state = nState; - evKillActor(actor); + evKillActor(actor, initiator); if (actor->xspr.restState != nState && actor->xspr.waitTime > 0) - evPostActor(actor, (actor->xspr.waitTime * 120) / 10, actor->xspr.restState ? kCmdOn : kCmdOff); + evPostActor(actor, (actor->xspr.waitTime * 120) / 10, actor->xspr.restState ? kCmdOn : kCmdOff, initiator); if (actor->xspr.txID != 0 && ((actor->xspr.triggerOn && actor->xspr.state) || (actor->xspr.triggerOff && !actor->xspr.state))) - modernTypeSendCommand(actor, actor->xspr.txID, (COMMAND_ID)actor->xspr.command); + modernTypeSendCommand(actor, actor->xspr.txID, (COMMAND_ID)actor->xspr.command, initiator); return true; } @@ -4699,20 +4889,20 @@ bool modernTypeSetSpriteState(DBloodActor* actor, int nState) // //--------------------------------------------------------------------------- -void modernTypeSendCommand(DBloodActor* actor, int destChannel, COMMAND_ID command) +void modernTypeSendCommand(DBloodActor* actor, int destChannel, COMMAND_ID command, DBloodActor* initiator) { switch (command) { case kCmdLink: - evSendActor(actor, destChannel, kCmdModernUse); // just send command to change properties + evSendActor(actor, destChannel, kCmdModernUse, initiator); // just send command to change properties return; case kCmdUnlock: - evSendActor(actor, destChannel, command); // send normal command first - evSendActor(actor, destChannel, kCmdModernUse); // then send command to change properties + evSendActor(actor, destChannel, command, initiator); // send normal command first + evSendActor(actor, destChannel, kCmdModernUse, initiator); // then send command to change properties return; default: - evSendActor(actor, destChannel, kCmdModernUse); // send first command to change properties - evSendActor(actor, destChannel, command); // then send normal command + evSendActor(actor, destChannel, kCmdModernUse, initiator); // send first command to change properties + evSendActor(actor, destChannel, command, initiator); // then send normal command return; } } @@ -4744,6 +4934,7 @@ void modernTypeTrigger(int destObjType, sectortype* destSect, walltype* destWall // allow redirect events received from some modern types. // example: it allows to spawn FX effect if event was received from kModernEffectGen // on many TX channels instead of just one. + DBloodActor* initiator = event.initiator; switch (destactor->spr.type) { case kModernRandomTX: @@ -4752,19 +4943,19 @@ void modernTypeTrigger(int destObjType, sectortype* destSect, walltype* destWall switch (destactor->spr.type) { case kModernRandomTX: - useRandomTx(destactor, (COMMAND_ID)sourceactor->xspr.command, false); // set random TX id + useRandomTx(destactor, (COMMAND_ID)sourceactor->xspr.command, false, initiator); // set random TX id break; case kModernSequentialTX: if (destactor->spr.flags & kModernTypeFlag1) { - seqTxSendCmdAll(destactor, sourceactor, (COMMAND_ID)sourceactor->xspr.command, true); + seqTxSendCmdAll(destactor, sourceactor, (COMMAND_ID)sourceactor->xspr.command, true, initiator); return; } - useSequentialTx(destactor, (COMMAND_ID)sourceactor->xspr.command, false); // set next TX id + useSequentialTx(destactor, (COMMAND_ID)sourceactor->xspr.command, false, initiator); // set next TX id break; } if (destactor->xspr.txID <= 0 || destactor->xspr.txID >= kChannelUserMax) return; - modernTypeSendCommand(sourceactor, destactor->xspr.txID, (COMMAND_ID)sourceactor->xspr.command); + modernTypeSendCommand(sourceactor, destactor->xspr.txID, (COMMAND_ID)sourceactor->xspr.command, initiator); return; } break; @@ -4845,6 +5036,15 @@ void modernTypeTrigger(int destObjType, sectortype* destSect, walltype* destWall usePropertiesChanger(sourceactor, destObjType, destSect, destWall, destactor); break; // updated vanilla sound gen that now allows to play sounds on TX ID sprites + // change velocity of the sprite + case kModernVelocityChanger: + switch (destObjType) { + case OBJ_SPRITE: + case OBJ_SECTOR: + useVelocityChanger(sourceactor, destSect, event.initiator, destactor); + break; + } + break; case kGenModernSound: if (destObjType != OBJ_SPRITE) break; useSoundGen(sourceactor, destactor); @@ -5226,13 +5426,13 @@ void sectorKillSounds(sectortype* pSector) // //--------------------------------------------------------------------------- -void sectorPauseMotion(sectortype* pSector) +void sectorPauseMotion(sectortype* pSector, DBloodActor* initiator) { if (!pSector->hasX()) return; XSECTOR* pXSector = &pSector->xs(); pXSector->unused1 = 1; - evKillSector(pSector); + evKillSector(pSector, initiator); sectorKillSounds(pSector); if ((pXSector->busy == 0 && !pXSector->state) || (pXSector->busy == 65536 && pXSector->state)) @@ -5279,7 +5479,7 @@ void sectorContinueMotion(sectortype* pSector, EVENT event) case kCmdOff: if (pXSector->busy == 0) { - if (pXSector->reTriggerB && waitTimeB) evPostSector(pSector, (waitTimeB * 120) / 10, kCmdOff); + if (pXSector->reTriggerB && waitTimeB) evPostSector(pSector, (waitTimeB * 120) / 10, kCmdOff, event.initiator); return; } pXSector->state = 1; @@ -5289,7 +5489,7 @@ void sectorContinueMotion(sectortype* pSector, EVENT event) case kCmdOn: if (pXSector->busy == 65536) { - if (pXSector->reTriggerA && waitTimeA) evPostSector(pSector, (waitTimeA * 120) / 10, kCmdOn); + if (pXSector->reTriggerA && waitTimeA) evPostSector(pSector, (waitTimeA * 120) / 10, kCmdOn, event.initiator); return; } pXSector->state = 0; @@ -5364,7 +5564,7 @@ bool modernTypeOperateSector(sectortype* pSector, const EVENT& event) { case kSectorCounter: if (pXSector->locked != 1) break; - SetSectorState(pSector, 0); + SetSectorState(pSector, 0, event.initiator.Get()); evPostSector(pSector, 0, kCallbackCounterCheck); break; } @@ -5388,7 +5588,7 @@ bool modernTypeOperateSector(sectortype* pSector, const EVENT& event) } else if (event.cmd == kCmdSectorMotionPause) { - sectorPauseMotion(pSector); + sectorPauseMotion(pSector, event.initiator.Get()); return true; } return false; @@ -5408,7 +5608,7 @@ void useCustomDudeSpawn(DBloodActor* pSource, DBloodActor* pActor) void useDudeSpawn(DBloodActor* pSource, DBloodActor* pActor) { if (randomSpawnDude(pSource, pActor, pActor->spr.clipdist << 1, 0) == nullptr) - nnExtSpawnDude(pSource, pActor, pSource->xspr.data1, pActor->spr.clipdist << 1, 0); + nnExtSpawnDude(pSource, pActor, pActor->xspr.data1, pActor->spr.clipdist << 1, 0); } //--------------------------------------------------------------------------- @@ -5419,6 +5619,7 @@ void useDudeSpawn(DBloodActor* pSource, DBloodActor* pActor) bool modernTypeOperateSprite(DBloodActor* actor, EVENT& event) { + DBloodActor* initiator = event.initiator; if (event.cmd >= kCmdLock && event.cmd <= kCmdToggleLock) { switch (event.cmd) @@ -5470,10 +5671,10 @@ bool modernTypeOperateSprite(DBloodActor* actor, EVENT& event) switch (event.cmd) { case kCmdOff: - if (actor->xspr.state) SetSpriteState(actor, 0); + if (actor->xspr.state) SetSpriteState(actor, 0, initiator); break; case kCmdOn: - if (!actor->xspr.state) SetSpriteState(actor, 1); + if (!actor->xspr.state) SetSpriteState(actor, 1, initiator); if (!actor->IsDudeActor() || actor->IsPlayerActor() || actor->xspr.health <= 0) break; else if (actor->xspr.aiState->stateType >= kAiStatePatrolBase && actor->xspr.aiState->stateType < kAiStatePatrolMax) break; @@ -5497,8 +5698,8 @@ bool modernTypeOperateSprite(DBloodActor* actor, EVENT& event) break; default: - if (!actor->xspr.state) evPostActor(actor, 0, kCmdOn); - else evPostActor(actor, 0, kCmdOff); + if (!actor->xspr.state) evPostActor(actor, 0, kCmdOn, initiator); + else evPostActor(actor, 0, kCmdOff, initiator); break; } return true; @@ -5527,13 +5728,13 @@ bool modernTypeOperateSprite(DBloodActor* actor, EVENT& event) case kMarkerDudeSpawn: if (!gGameOptions.nMonsterSettings) return true; else if (!(actor->spr.flags & kModernTypeFlag4)) useDudeSpawn(actor, actor); - else if (actor->xspr.txID) evSendActor(actor, actor->xspr.txID, kCmdModernUse); + else if (actor->xspr.txID) evSendActor(actor, actor->xspr.txID, kCmdModernUse, initiator); return true; case kModernCustomDudeSpawn: if (!gGameOptions.nMonsterSettings) return true; else if (!(actor->spr.flags & kModernTypeFlag4)) useCustomDudeSpawn(actor, actor); - else if (actor->xspr.txID) evSendActor(actor, actor->xspr.txID, kCmdModernUse); + else if (actor->xspr.txID) evSendActor(actor, actor->xspr.txID, kCmdModernUse, initiator); return true; case kModernRandomTX: // random Event Switch takes random data field and uses it as TX ID @@ -5542,12 +5743,12 @@ bool modernTypeOperateSprite(DBloodActor* actor, EVENT& event) switch (actor->spr.type) { case kModernRandomTX: - useRandomTx(actor, (COMMAND_ID)actor->xspr.command, true); + useRandomTx(actor, (COMMAND_ID)actor->xspr.command, true, initiator); break; case kModernSequentialTX: - if (!(actor->spr.flags & kModernTypeFlag1)) useSequentialTx(actor, (COMMAND_ID)actor->xspr.command, true); - else seqTxSendCmdAll(actor, actor, (COMMAND_ID)actor->xspr.command, false); + if (!(actor->spr.flags & kModernTypeFlag1)) useSequentialTx(actor, (COMMAND_ID)actor->xspr.command, true, initiator); + else seqTxSendCmdAll(actor, actor, (COMMAND_ID)actor->xspr.command, false, initiator); break; } return true; @@ -5556,14 +5757,14 @@ bool modernTypeOperateSprite(DBloodActor* actor, EVENT& event) switch (event.cmd) { case kCmdOff: - if (actor->xspr.state == 1) SetSpriteState(actor, 0); + if (actor->xspr.state == 1) SetSpriteState(actor, 0, initiator); break; case kCmdOn: evKillActor(actor); // queue overflow protect - if (actor->xspr.state == 0) SetSpriteState(actor, 1); + if (actor->xspr.state == 0) SetSpriteState(actor, 1, initiator); [[fallthrough]]; case kCmdRepeat: - if (actor->xspr.txID > 0) modernTypeSendCommand(actor, actor->xspr.txID, (COMMAND_ID)actor->xspr.command); + if (actor->xspr.txID > 0) modernTypeSendCommand(actor, actor->xspr.txID, (COMMAND_ID)actor->xspr.command, initiator); else if (actor->xspr.data1 == 0 && actor->insector()) useSpriteDamager(actor, OBJ_SECTOR, actor->sector(), nullptr); else if (actor->xspr.data1 >= 666 && actor->xspr.data1 < 669) useSpriteDamager(actor, -1, nullptr, nullptr); else @@ -5574,21 +5775,21 @@ bool modernTypeOperateSprite(DBloodActor* actor, EVENT& event) } if (actor->xspr.busyTime > 0) - evPostActor(actor, actor->xspr.busyTime, kCmdRepeat); + evPostActor(actor, actor->xspr.busyTime, kCmdRepeat, initiator); break; default: - if (actor->xspr.state == 0) evPostActor(actor, 0, kCmdOn); - else evPostActor(actor, 0, kCmdOff); + if (actor->xspr.state == 0) evPostActor(actor, 0, kCmdOn, initiator); + else evPostActor(actor, 0, kCmdOff, initiator); break; } return true; case kMarkerWarpDest: - if (actor->xspr.txID <= 0) { - + if (actor->xspr.txID <= 0) + { PLAYER* pPlayer = getPlayerById(actor->xspr.data1); - if (pPlayer != NULL && SetSpriteState(actor, actor->xspr.state ^ 1) == 1) + if (pPlayer != NULL && SetSpriteState(actor, actor->xspr.state ^ 1, initiator) == 1) useTeleportTarget(actor, pPlayer->actor); return true; } @@ -5596,7 +5797,7 @@ bool modernTypeOperateSprite(DBloodActor* actor, EVENT& event) case kModernObjPropertiesChanger: if (actor->xspr.txID <= 0) { - if (SetSpriteState(actor, actor->xspr.state ^ 1) == 1) + if (SetSpriteState(actor, actor->xspr.state ^ 1, initiator) == 1) usePropertiesChanger(actor, -1, nullptr, nullptr, nullptr); return true; } @@ -5606,7 +5807,7 @@ bool modernTypeOperateSprite(DBloodActor* actor, EVENT& event) case kModernObjPicnumChanger: case kModernSectorFXChanger: case kModernObjDataChanger: - modernTypeSetSpriteState(actor, actor->xspr.state ^ 1); + modernTypeSetSpriteState(actor, actor->xspr.state ^ 1, initiator); return true; case kModernSeqSpawner: @@ -5614,24 +5815,24 @@ bool modernTypeOperateSprite(DBloodActor* actor, EVENT& event) switch (event.cmd) { case kCmdOff: - if (actor->xspr.state == 1) SetSpriteState(actor, 0); + if (actor->xspr.state == 1) SetSpriteState(actor, 0, initiator); break; case kCmdOn: - evKillActor(actor); // queue overflow protect - if (actor->xspr.state == 0) SetSpriteState(actor, 1); + evKillActor(actor, initiator); // queue overflow protect + if (actor->xspr.state == 0) SetSpriteState(actor, 1, initiator); if (actor->spr.type == kModernSeqSpawner) seqSpawnerOffSameTx(actor); [[fallthrough]]; case kCmdRepeat: - if (actor->xspr.txID > 0) modernTypeSendCommand(actor, actor->xspr.txID, (COMMAND_ID)actor->xspr.command); + if (actor->xspr.txID > 0) modernTypeSendCommand(actor, actor->xspr.txID, (COMMAND_ID)actor->xspr.command, initiator); else if (actor->spr.type == kModernSeqSpawner) useSeqSpawnerGen(actor, OBJ_SPRITE, nullptr, nullptr, actor); else useEffectGen(actor, nullptr); if (actor->xspr.busyTime > 0) - evPostActor(actor, ClipLow((int(actor->xspr.busyTime) + Random2(actor->xspr.data1)) * 120 / 10, 0), kCmdRepeat); + evPostActor(actor, ClipLow((int(actor->xspr.busyTime) + Random2(actor->xspr.data1)) * 120 / 10, 0), kCmdRepeat, initiator); break; default: - if (actor->xspr.state == 0) evPostActor(actor, 0, kCmdOn); - else evPostActor(actor, 0, kCmdOff); + if (actor->xspr.state == 0) evPostActor(actor, 0, kCmdOn, initiator); + else evPostActor(actor, 0, kCmdOff, initiator); break; } return true; @@ -5641,24 +5842,46 @@ bool modernTypeOperateSprite(DBloodActor* actor, EVENT& event) { case kCmdOff: windGenStopWindOnSectors(actor); - if (actor->xspr.state == 1) SetSpriteState(actor, 0); + if (actor->xspr.state == 1) SetSpriteState(actor, 0, initiator); break; case kCmdOn: - evKillActor(actor); // queue overflow protect - if (actor->xspr.state == 0) SetSpriteState(actor, 1); + evKillActor(actor, initiator); // queue overflow protect + if (actor->xspr.state == 0) SetSpriteState(actor, 1, initiator); [[fallthrough]]; case kCmdRepeat: - if (actor->xspr.txID > 0) modernTypeSendCommand(actor, actor->xspr.txID, (COMMAND_ID)actor->xspr.command); + if (actor->xspr.txID > 0) modernTypeSendCommand(actor, actor->xspr.txID, (COMMAND_ID)actor->xspr.command, initiator); else useSectorWindGen(actor, nullptr); - - if (actor->xspr.busyTime > 0) evPostActor(actor, actor->xspr.busyTime, kCmdRepeat); + if (actor->xspr.busyTime > 0) evPostActor(actor, actor->xspr.busyTime, kCmdRepeat, initiator); break; default: - if (actor->xspr.state == 0) evPostActor(actor, 0, kCmdOn); - else evPostActor(actor, 0, kCmdOff); + if (actor->xspr.state == 0) evPostActor(actor, 0, kCmdOn, initiator); + else evPostActor(actor, 0, kCmdOff, initiator); break; } return true; + + case kModernVelocityChanger: + switch (event.cmd) + { + case kCmdOff: + if (actor->xspr.state == 1) SetSpriteState(actor, 0, initiator); + break; + case kCmdOn: + evKillActor(actor, initiator); // queue overflow protect + if (actor->xspr.state == 0) SetSpriteState(actor, 1, initiator); + [[fallthrough]]; + case kCmdRepeat: + if (actor->xspr.txID > 0) modernTypeSendCommand(actor, actor->xspr.txID, (COMMAND_ID)actor->xspr.command, initiator); + else useVelocityChanger(actor, actor->sector(), initiator, nullptr); + if (actor->xspr.busyTime > 0) evPostActor(actor, actor->xspr.busyTime, kCmdRepeat, initiator); + break; + default: + if (actor->xspr.state == 0) evPostActor(actor, 0, kCmdOn, initiator); + else evPostActor(actor, 0, kCmdOff, initiator); + break; + } + return true; + case kModernDudeTargetChanger: // this one is required if data4 of generator was dynamically changed @@ -5670,57 +5893,79 @@ bool modernTypeOperateSprite(DBloodActor* actor, EVENT& event) { case kCmdOff: if (actor->xspr.data4 == 3) aiFightActivateDudes(actor->xspr.txID); - if (actor->xspr.state == 1) SetSpriteState(actor, 0); + if (actor->xspr.state == 1) SetSpriteState(actor, 0, initiator); break; case kCmdOn: - evKillActor(actor); // queue overflow protect - if (actor->xspr.state == 0) SetSpriteState(actor, 1); + evKillActor(actor, initiator); // queue overflow protect + if (actor->xspr.state == 0) SetSpriteState(actor, 1, initiator); [[fallthrough]]; case kCmdRepeat: if (actor->xspr.txID <= 0 || !aiFightGetDudesForBattle(actor)) { aiFightFreeAllTargets(actor); - evPostActor(actor, 0, kCmdOff); + evPostActor(actor, 0, kCmdOff, initiator); break; } else { - modernTypeSendCommand(actor, actor->xspr.txID, (COMMAND_ID)actor->xspr.command); + modernTypeSendCommand(actor, actor->xspr.txID, (COMMAND_ID)actor->xspr.command, initiator); } - if (actor->xspr.busyTime > 0) evPostActor(actor, actor->xspr.busyTime, kCmdRepeat); + if (actor->xspr.busyTime > 0) evPostActor(actor, actor->xspr.busyTime, kCmdRepeat, initiator); break; default: - if (actor->xspr.state == 0) evPostActor(actor, 0, kCmdOn); - else evPostActor(actor, 0, kCmdOff); + if (actor->xspr.state == 0) evPostActor(actor, 0, kCmdOn, initiator); + else evPostActor(actor, 0, kCmdOff, initiator); break; } actor->xspr.dropMsg = uint8_t(actor->xspr.data4); return true; + case kGenTrigger: + if (!(actor->spr.flags & kModernTypeFlag1)) return false; // work as vanilla generator + switch (event.cmd) { // work as fast generator + case kCmdOff: + if (actor->xspr.state == 1) SetSpriteState(actor, 0, initiator); + break; + case kCmdOn: + evKillActor(actor, initiator); // queue overflow protect + if (actor->xspr.state == 0) SetSpriteState(actor, 1, initiator); + [[fallthrough]]; + case kCmdRepeat: + if (actor->xspr.txID) + evSendActor(actor, actor->xspr.txID, (COMMAND_ID)actor->xspr.command, initiator); + if (actor->xspr.busyTime > 0) evPostActor(actor, actor->xspr.busyTime, kCmdRepeat, initiator); + break; + default: + if (actor->xspr.state == 0) evPostActor(actor, 0, kCmdOn, initiator); + else evPostActor(actor, 0, kCmdOff, initiator); + break; + } + return true; + case kModernObjDataAccumulator: switch (event.cmd) { case kCmdOff: - if (actor->xspr.state == 1) SetSpriteState(actor, 0); + if (actor->xspr.state == 1) SetSpriteState(actor, 0, initiator); break; case kCmdOn: - evKillActor(actor); // queue overflow protect - if (actor->xspr.state == 0) SetSpriteState(actor, 1); + evKillActor(actor, initiator); // queue overflow protect + if (actor->xspr.state == 0) SetSpriteState(actor, 1, initiator); [[fallthrough]]; case kCmdRepeat: // force OFF after *all* TX objects reach the goal value if (actor->spr.flags == kModernTypeFlag0 && incDecGoalValueIsReached(actor)) { - evPostActor(actor, 0, kCmdOff); + evPostActor(actor, 0, kCmdOff, initiator); break; } - modernTypeSendCommand(actor, actor->xspr.txID, (COMMAND_ID)actor->xspr.command); - if (actor->xspr.busyTime > 0) evPostActor(actor, actor->xspr.busyTime, kCmdRepeat); + modernTypeSendCommand(actor, actor->xspr.txID, (COMMAND_ID)actor->xspr.command, initiator); + if (actor->xspr.busyTime > 0) evPostActor(actor, actor->xspr.busyTime, kCmdRepeat, initiator); break; default: - if (actor->xspr.state == 0) evPostActor(actor, 0, kCmdOn); - else evPostActor(actor, 0, kCmdOff); + if (actor->xspr.state == 0) evPostActor(actor, 0, kCmdOn, initiator); + else evPostActor(actor, 0, kCmdOff, initiator); break; } return true; @@ -5729,20 +5974,20 @@ bool modernTypeOperateSprite(DBloodActor* actor, EVENT& event) switch (event.cmd) { case kCmdOff: - if (actor->xspr.state == 1) SetSpriteState(actor, 0); + if (actor->xspr.state == 1) SetSpriteState(actor, 0, initiator); break; case kCmdOn: - evKillActor(actor); // queue overflow protect - if (actor->xspr.state == 0) SetSpriteState(actor, 1); + evKillActor(actor, initiator); // queue overflow protect + if (actor->xspr.state == 0) SetSpriteState(actor, 1, initiator); [[fallthrough]]; case kCmdRepeat: useRandomItemGen(actor); if (actor->xspr.busyTime > 0) - evPostActor(actor, (120 * actor->xspr.busyTime) / 10, kCmdRepeat); + evPostActor(actor, (120 * actor->xspr.busyTime) / 10, kCmdRepeat, initiator); break; default: - if (actor->xspr.state == 0) evPostActor(actor, 0, kCmdOn); - else evPostActor(actor, 0, kCmdOff); + if (actor->xspr.state == 0) evPostActor(actor, 0, kCmdOn, initiator); + else evPostActor(actor, 0, kCmdOff, initiator); break; } return true; @@ -5755,7 +6000,7 @@ bool modernTypeOperateSprite(DBloodActor* actor, EVENT& event) case kCmdSpriteProximity: if (actor->xspr.state) break; sfxPlay3DSound(actor, 452, 0, 0); - evPostActor(actor, 30, kCmdOff); + evPostActor(actor, 30, kCmdOff, nullptr); actor->xspr.state = 1; [[fallthrough]]; case kCmdOn: @@ -5771,10 +6016,20 @@ bool modernTypeOperateSprite(DBloodActor* actor, EVENT& event) case kModernThingEnemyLifeLeech: dudeLeechOperate(actor, event); return true; - case kModernPlayerControl: { // WIP - PLAYER* pPlayer = NULL; int cmd = (event.cmd >= kCmdNumberic) ? event.cmd : actor->xspr.command; - if ((pPlayer = getPlayerById(actor->xspr.data1)) == NULL - || ((cmd < 67 || cmd > 68) && !modernTypeSetSpriteState(actor, actor->xspr.state ^ 1))) + case kModernPlayerControl: + { // WIP + PLAYER* pPlayer = NULL; + int cmd = (event.cmd >= kCmdNumberic) ? event.cmd : actor->xspr.command; + + + int playerID; + if ((actor->xspr.txID == kChannelEventCauser || actor->xspr.data1 == 0) && initiator && initiator->IsPlayerActor()) + playerID = initiator->spr.type; + else + playerID = actor->xspr.data1; + + if ((pPlayer = getPlayerById(playerID)) == NULL + || ((cmd < 67 || cmd > 68) && !modernTypeSetSpriteState(actor, actor->xspr.state ^ 1, initiator))) return true; TRPLAYERCTRL* pCtrl = &gPlayerCtrl[pPlayer->nPlayer]; @@ -5875,22 +6130,22 @@ bool modernTypeOperateSprite(DBloodActor* actor, EVENT& event) case kGenModernSound: switch (event.cmd) { case kCmdOff: - if (actor->xspr.state == 1) SetSpriteState(actor, 0); + if (actor->xspr.state == 1) SetSpriteState(actor, 0, initiator); break; case kCmdOn: - evKillActor(actor); // queue overflow protect - if (actor->xspr.state == 0) SetSpriteState(actor, 1); + evKillActor(actor, initiator); // queue overflow protect + if (actor->xspr.state == 0) SetSpriteState(actor, 1, initiator); [[fallthrough]]; case kCmdRepeat: - if (actor->xspr.txID) modernTypeSendCommand(actor, actor->xspr.txID, (COMMAND_ID)actor->xspr.command); + if (actor->xspr.txID) modernTypeSendCommand(actor, actor->xspr.txID, (COMMAND_ID)actor->xspr.command, initiator); else useSoundGen(actor, actor); if (actor->xspr.busyTime > 0) - evPostActor(actor, (120 * actor->xspr.busyTime) / 10, kCmdRepeat); + evPostActor(actor, (120 * actor->xspr.busyTime) / 10, kCmdRepeat, initiator); break; default: - if (actor->xspr.state == 0) evPostActor(actor, 0, kCmdOn); - else evPostActor(actor, 0, kCmdOff); + if (actor->xspr.state == 0) evPostActor(actor, 0, kCmdOn, initiator); + else evPostActor(actor, 0, kCmdOff, initiator); break; } return true; @@ -5898,23 +6153,23 @@ bool modernTypeOperateSprite(DBloodActor* actor, EVENT& event) switch (event.cmd) { case kCmdOff: - if (actor->xspr.state == 1) SetSpriteState(actor, 0); + if (actor->xspr.state == 1) SetSpriteState(actor, 0, initiator); break; case kCmdOn: - evKillActor(actor); // queue overflow protect - if (actor->xspr.state == 0) SetSpriteState(actor, 1); + evKillActor(actor, initiator); // queue overflow protect + if (actor->xspr.state == 0) SetSpriteState(actor, 1, initiator); [[fallthrough]]; case kCmdRepeat: - if (actor->xspr.txID) modernTypeSendCommand(actor, actor->xspr.txID, (COMMAND_ID)actor->xspr.command); + if (actor->xspr.txID) modernTypeSendCommand(actor, actor->xspr.txID, (COMMAND_ID)actor->xspr.command, initiator); else useUniMissileGen(actor, actor); if (actor->xspr.busyTime > 0) - evPostActor(actor, (120 * actor->xspr.busyTime) / 10, kCmdRepeat); + evPostActor(actor, (120 * actor->xspr.busyTime) / 10, kCmdRepeat, initiator); break; default: - if (actor->xspr.state == 0) evPostActor(actor, 0, kCmdOn); - else evPostActor(actor, 0, kCmdOff); + if (actor->xspr.state == 0) evPostActor(actor, 0, kCmdOn, initiator); + else evPostActor(actor, 0, kCmdOff, initiator); break; } return true; @@ -5929,18 +6184,19 @@ bool modernTypeOperateSprite(DBloodActor* actor, EVENT& event) bool modernTypeOperateWall(walltype* pWall, const EVENT& event) { + DBloodActor* initiator = event.initiator.Get(); switch (pWall->type) { case kSwitchOneWay: switch (event.cmd) { case kCmdOff: - SetWallState(pWall, 0); + SetWallState(pWall, 0, initiator); break; case kCmdOn: - SetWallState(pWall, 1); + SetWallState(pWall, 1, initiator); break; default: - SetWallState(pWall, pWall->xw().restState ^ 1); + SetWallState(pWall, pWall->xw().restState ^ 1, initiator); break; } return true; @@ -5977,7 +6233,7 @@ bool txIsRanged(DBloodActor* sourceactor) // //--------------------------------------------------------------------------- -void seqTxSendCmdAll(DBloodActor* sourceactor, DBloodActor* actor, COMMAND_ID cmd, bool modernSend) +void seqTxSendCmdAll(DBloodActor* sourceactor, DBloodActor* actor, COMMAND_ID cmd, bool modernSend, DBloodActor* initiator) { bool ranged = txIsRanged(sourceactor); if (ranged) @@ -5985,8 +6241,8 @@ void seqTxSendCmdAll(DBloodActor* sourceactor, DBloodActor* actor, COMMAND_ID cm for (sourceactor->xspr.txID = sourceactor->xspr.data1; sourceactor->xspr.txID <= sourceactor->xspr.data4; sourceactor->xspr.txID++) { if (sourceactor->xspr.txID <= 0 || sourceactor->xspr.txID >= kChannelUserMax) continue; - else if (!modernSend) evSendActor(actor, sourceactor->xspr.txID, cmd); - else modernTypeSendCommand(actor, sourceactor->xspr.txID, cmd); + else if (!modernSend) evSendActor(actor, sourceactor->xspr.txID, cmd, initiator); + else modernTypeSendCommand(actor, sourceactor->xspr.txID, cmd, initiator); } } else @@ -5995,8 +6251,8 @@ void seqTxSendCmdAll(DBloodActor* sourceactor, DBloodActor* actor, COMMAND_ID cm { sourceactor->xspr.txID = GetDataVal(sourceactor, i); if (sourceactor->xspr.txID <= 0 || sourceactor->xspr.txID >= kChannelUserMax) continue; - else if (!modernSend) evSendActor(actor, sourceactor->xspr.txID, cmd); - else modernTypeSendCommand(actor, sourceactor->xspr.txID, cmd); + else if (!modernSend) evSendActor(actor, sourceactor->xspr.txID, cmd, initiator); + else modernTypeSendCommand(actor, sourceactor->xspr.txID, cmd, initiator); } } sourceactor->xspr.txID = sourceactor->xspr.sysData1 = 0; @@ -6008,7 +6264,7 @@ void seqTxSendCmdAll(DBloodActor* sourceactor, DBloodActor* actor, COMMAND_ID cm // //--------------------------------------------------------------------------- -void useRandomTx(DBloodActor* sourceactor, COMMAND_ID cmd, bool setState) +void useRandomTx(DBloodActor* sourceactor, COMMAND_ID cmd, bool setState, DBloodActor* initiator) { int tx = 0; int maxRetries = kMaxRandomizeRetries; @@ -6031,7 +6287,7 @@ void useRandomTx(DBloodActor* sourceactor, COMMAND_ID cmd, bool setState) sourceactor->xspr.txID = (tx > 0 && tx < kChannelUserMax) ? tx : 0; if (setState) - SetSpriteState(sourceactor, sourceactor->xspr.state ^ 1); + SetSpriteState(sourceactor, sourceactor->xspr.state ^ 1, initiator); //evSendActor(sourceactor->spr.index, sourceactor->xspr.txID, (COMMAND_ID)sourceactor->xspr.command); } @@ -6041,7 +6297,7 @@ void useRandomTx(DBloodActor* sourceactor, COMMAND_ID cmd, bool setState) // //--------------------------------------------------------------------------- -void useSequentialTx(DBloodActor* sourceactor, COMMAND_ID cmd, bool setState) +void useSequentialTx(DBloodActor* sourceactor, COMMAND_ID cmd, bool setState, DBloodActor* initiator) { bool range = txIsRanged(sourceactor); int cnt = 3; int tx = 0; @@ -6103,7 +6359,7 @@ void useSequentialTx(DBloodActor* sourceactor, COMMAND_ID cmd, bool setState) sourceactor->xspr.txID = (tx > 0 && tx < kChannelUserMax) ? tx : 0; if (setState) - SetSpriteState(sourceactor, sourceactor->xspr.state ^ 1); + SetSpriteState(sourceactor, sourceactor->xspr.state ^ 1, initiator); //evSendActor(sourceactor->spr.index, sourceactor->xspr.txID, (COMMAND_ID)sourceactor->xspr.command); } @@ -6163,7 +6419,7 @@ int useCondition(DBloodActor* sourceactor, EVENT& event) { sourceactor->xspr.restState = 1; evKillActor(sourceactor); - evPostActor(sourceactor, (sourceactor->xspr.waitTime * 120) / 10, kCmdRepeat); + evPostActor(sourceactor, (sourceactor->xspr.waitTime * 120) / 10, kCmdRepeat, event.initiator); return -1; } } @@ -6186,21 +6442,23 @@ int useCondition(DBloodActor* sourceactor, EVENT& event) // send command to rx bucket if (sourceactor->xspr.txID) - evSendActor(sourceactor, sourceactor->xspr.txID, (COMMAND_ID)sourceactor->xspr.command); + { + evSendActor(sourceactor, sourceactor->xspr.txID, (COMMAND_ID)sourceactor->xspr.command, sourceactor->condition[0].isActor()? sourceactor->condition[0].actor() : nullptr); + } if (sourceactor->spr.flags) { // send it for object currently in the focus if (sourceactor->spr.flags & kModernTypeFlag1) { - nnExtTriggerObject(event.target, sourceactor->xspr.command); + nnExtTriggerObject(event.target, sourceactor->xspr.command, sourceactor); } // send it for initial object if ((sourceactor->spr.flags & kModernTypeFlag2) && (sourceactor->condition[0] != sourceactor->condition[1] || !(sourceactor->spr.hitag & kModernTypeFlag1))) { auto co = condGet(sourceactor); - nnExtTriggerObject(co, sourceactor->xspr.command); + nnExtTriggerObject(co, sourceactor->xspr.command, sourceactor); } } } @@ -6599,28 +6857,19 @@ void useSlopeChanger(DBloodActor* sourceactor, int objType, sectortype* pSect, D void useDataChanger(DBloodActor* sourceactor, int objType, sectortype* pSector, walltype* pWall, DBloodActor* objActor) { - switch (objType) - { + bool flag1 = (sourceactor->spr.flags & kModernTypeFlag1); + switch (objType) { case OBJ_SECTOR: - if ((sourceactor->spr.flags & kModernTypeFlag1) || (sourceactor->xspr.data1 != -1 && sourceactor->xspr.data1 != 32767)) - setDataValueOfObject(objType, pSector, pWall, nullptr, 1, sourceactor->xspr.data1); + if (flag1 || valueIsBetween(sourceactor->xspr.data1, -1, 32767)) setDataValueOfObject(objType, pSector, pWall, nullptr, 1, sourceactor->xspr.data1); break; case OBJ_SPRITE: - if ((sourceactor->spr.flags & kModernTypeFlag1) || (sourceactor->xspr.data1 != -1 && sourceactor->xspr.data1 != 32767)) - setDataValueOfObject(objType, pSector, pWall, objActor, 1, sourceactor->xspr.data1); - - if ((sourceactor->spr.flags & kModernTypeFlag1) || (sourceactor->xspr.data2 != -1 && sourceactor->xspr.data2 != 32767)) - setDataValueOfObject(objType, pSector, pWall, objActor, 2, sourceactor->xspr.data2); - - if ((sourceactor->spr.flags & kModernTypeFlag1) || (sourceactor->xspr.data3 != -1 && sourceactor->xspr.data3 != 32767)) - setDataValueOfObject(objType, pSector, pWall, objActor, 3, sourceactor->xspr.data3); - - if ((sourceactor->spr.flags & kModernTypeFlag1) || sourceactor->xspr.data4 != 65535) - setDataValueOfObject(objType, pSector, pWall, objActor, 4, sourceactor->xspr.data4); + if (flag1 || valueIsBetween(sourceactor->xspr.data1, -1, 32767)) setDataValueOfObject(objType, pSector, pWall, objActor, 1, sourceactor->xspr.data1); + if (flag1 || valueIsBetween(sourceactor->xspr.data2, -1, 32767)) setDataValueOfObject(objType, pSector, pWall, objActor, 2, sourceactor->xspr.data1); + if (flag1 || valueIsBetween(sourceactor->xspr.data3, -1, 32767)) setDataValueOfObject(objType, pSector, pWall, objActor, 3, sourceactor->xspr.data1); + if (flag1 || valueIsBetween(sourceactor->xspr.data4, -1, 65535)) setDataValueOfObject(objType, pSector, pWall, objActor, 4, sourceactor->xspr.data1); break; case OBJ_WALL: - if ((sourceactor->spr.flags & kModernTypeFlag1) || (sourceactor->xspr.data1 != -1 && sourceactor->xspr.data1 != 32767)) - setDataValueOfObject(objType, pSector, pWall, nullptr, 1, sourceactor->xspr.data1); + if (flag1 || valueIsBetween(sourceactor->xspr.data1, -1, 32767)) setDataValueOfObject(objType, pSector, pWall, nullptr, 1, sourceactor->xspr.data1); break; } } @@ -6631,31 +6880,71 @@ void useDataChanger(DBloodActor* sourceactor, int objType, sectortype* pSector, // //--------------------------------------------------------------------------- + void useSectorLightChanger(DBloodActor* sourceactor, sectortype* pSector) { + bool relative = (sourceactor->spr.flags & kModernTypeFlag16); auto pXSector = &pSector->xs(); if (valueIsBetween(sourceactor->xspr.data1, -1, 32767)) - pXSector->wave = ClipHigh(sourceactor->xspr.data1, 11); + { + if (relative) + pXSector->wave = ClipHigh(pXSector->wave + sourceactor->xspr.data1, 11); + else + pXSector->wave = ClipHigh(sourceactor->xspr.data1, 11); + } - int oldAmplitude = pXSector->amplitude; if (valueIsBetween(sourceactor->xspr.data2, -128, 128)) - pXSector->amplitude = uint8_t(sourceactor->xspr.data2); + { + if (relative) + pXSector->amplitude = ClipRange(pXSector->amplitude + sourceactor->xspr.data2, -127, 127); + else + pXSector->amplitude = sourceactor->xspr.data2; + } if (valueIsBetween(sourceactor->xspr.data3, -1, 32767)) - pXSector->freq = ClipHigh(sourceactor->xspr.data3, 255); + { + if (relative) + pXSector->freq = ClipHigh(pXSector->freq + sourceactor->xspr.data3, 255); + else + pXSector->freq = ClipHigh(sourceactor->xspr.data3, 255); + } if (valueIsBetween(sourceactor->xspr.data4, -1, 65535)) - pXSector->phase = ClipHigh(sourceactor->xspr.data4, 255); + { + if (relative) + pXSector->phase = ClipHigh(pXSector->phase + sourceactor->xspr.data4, 255); + else + pXSector->phase = ClipHigh(sourceactor->xspr.data4, 255); + } if (sourceactor->spr.flags) { if (sourceactor->spr.flags != kModernTypeFlag1) { - pXSector->shadeAlways = (sourceactor->spr.flags & 0x0001) ? true : false; - pXSector->shadeFloor = (sourceactor->spr.flags & 0x0002) ? true : false; - pXSector->shadeCeiling = (sourceactor->spr.flags & 0x0004) ? true : false; - pXSector->shadeWalls = (sourceactor->spr.flags & 0x0008) ? true : false; + pXSector->shadeAlways = (sourceactor->spr.flags & kModernTypeFlag1) ? true : false; + pXSector->shadeFloor = (sourceactor->spr.flags & kModernTypeFlag2) ? true : false; + pXSector->shadeCeiling = (sourceactor->spr.flags & kModernTypeFlag4) ? true : false; + pXSector->shadeWalls = (sourceactor->spr.flags & kModernTypeFlag8) ? true : false; + pXSector->color = (sourceactor->spr.pal) ? true : false; + + auto cstat = sourceactor->spr.cstat; + if ((cstat & CSTAT_SPRITE_ALIGNMENT_MASK) == CSTAT_SPRITE_ALIGNMENT_FLOOR) + { + // !!! xsector pal bits must be extended + if (cstat & CSTAT_SPRITE_ONE_SIDE) + { + if (cstat & CSTAT_SPRITE_YFLIP) + pXSector->ceilpal = sourceactor->spr.pal; + else + pXSector->floorpal = sourceactor->spr.pal; + } + else + { + pXSector->floorpal = sourceactor->spr.pal; + pXSector->ceilpal = sourceactor->spr.pal; + } + } } else { @@ -6663,12 +6952,9 @@ void useSectorLightChanger(DBloodActor* sourceactor, sectortype* pSector) } } - // add to shadeList if amplitude was set to 0 previously - if (oldAmplitude != pXSector->amplitude) - { - if (!shadeList.Contains(pSector)) - shadeList.Push(pSector); - } + // add to shadeList + if (!shadeList.Contains(pSector)) + shadeList.Push(pSector); } //--------------------------------------------------------------------------- @@ -7034,7 +7320,7 @@ void playerQavSceneProcess(PLAYER* pPlayer, QAVSCENE* pQavScene) } } - nnExtTriggerObject(rxBucket[i], initiator->xspr.command); + nnExtTriggerObject(rxBucket[i], initiator->xspr.command, pPlayer->actor); } } @@ -7359,8 +7645,8 @@ bool setDataValueOfObject(int objType, sectortype* sect, walltype* wal, DBloodAc switch (type) { case kSwitchCombo: - if (value == objActor->xspr.data2) SetSpriteState(objActor, 1); - else SetSpriteState(objActor, 0); + if (value == objActor->xspr.data2) SetSpriteState(objActor, 1, nullptr); + else SetSpriteState(objActor, 0, nullptr); break; case kDudeModernCustom: case kDudeModernCustomBurning: @@ -8402,7 +8688,7 @@ DBloodActor* aiPatrolSearchTargets(DBloodActor* actor) // trigger this region if target gonna be spot if (steal->xspr.txID && actor->xspr.data3 + hearChance + seeChance >= kMaxPatrolSpotValue) - trTriggerSprite(steal, kCmdToggle); + trTriggerSprite(steal, kCmdToggle, pPlayer->actor); // continue search another stealth regions to affect chances } @@ -8472,7 +8758,7 @@ void aiPatrolFlagsMgr(DBloodActor* sourceactor, DBloodActor* destactor, bool cop } // do init - if (init) + if (init && destactor->IsDudeActor() && !destactor->IsPlayerActor()) { if (!destactor->xspr.dudeFlag4) { @@ -8572,7 +8858,7 @@ void aiPatrolThink(DBloodActor* actor) // send command if (markeractor->xspr.txID) { - evSendActor(markeractor, markeractor->xspr.txID, (COMMAND_ID)markeractor->xspr.command); + evSendActor(markeractor, markeractor->xspr.txID, (COMMAND_ID)markeractor->xspr.command, actor); // copy dude flags for current dude } @@ -8643,7 +8929,7 @@ void aiPatrolThink(DBloodActor* actor) // send command if (markeractor->xspr.txID) { - evSendActor(markeractor, markeractor->xspr.txID, (COMMAND_ID)markeractor->xspr.command); + evSendActor(markeractor, markeractor->xspr.txID, (COMMAND_ID)markeractor->xspr.command, actor); } else if (markeractor->xspr.command == kCmdDudeFlagsSet) { @@ -8677,11 +8963,11 @@ void aiPatrolThink(DBloodActor* actor) { // send command at arrival if (markeractor->xspr.triggerOn) - evSendActor(markeractor, markeractor->xspr.txID, (COMMAND_ID)markeractor->xspr.command); + evSendActor(markeractor, markeractor->xspr.txID, (COMMAND_ID)markeractor->xspr.command, actor); // send command at departure if (markeractor->xspr.triggerOff) - evSendActor(markeractor, markeractor->xspr.txID, (COMMAND_ID)markeractor->xspr.command); + evSendActor(markeractor, markeractor->xspr.txID, (COMMAND_ID)markeractor->xspr.command, actor); // copy dude flags for current dude } @@ -8884,14 +9170,17 @@ bool incDecGoalValueIsReached(DBloodActor* actor) void seqSpawnerOffSameTx(DBloodActor* actor) { - BloodSpriteIterator it; - while (auto iactor = it.Next()) + for (auto§ : sector) { - if (iactor->spr.type != kModernSeqSpawner || !iactor->hasX() || iactor == actor) continue; - if (iactor->xspr.txID == actor->xspr.txID && iactor->xspr.state == 1) + BloodSectIterator it(§); + while (auto iactor = it.Next()) { - evKillActor(iactor); - iactor->xspr.state = 0; + if (iactor->spr.type != kModernSeqSpawner || !iactor->hasX() || iactor == actor) continue; + if (/*iactor->xspr.txID == actor->xspr.txID &&*/ iactor->xspr.state == 1) + { + evKillActor(iactor); + iactor->xspr.state = 0; + } } } } @@ -9001,6 +9290,83 @@ void clampSprite(DBloodActor* actor, int which) } +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +void killEvents(int nRx, int nCmd) +{ + for (int i = bucketHead[nRx]; i < bucketHead[nRx + 1]; i++) + { + if (nCmd == kCmdEventKillFull) + evKill_(rxBucket[i]); + } +} + +void triggerTouchSprite(DBloodActor* actor, DBloodActor* hActor) +{ + if (hActor && hActor->hasX()) + { + if (hActor->xspr.Touch && !hActor->xspr.isTriggered && (!hActor->xspr.DudeLockout || actor->IsPlayerActor())) + trTriggerSprite(hActor, kCmdSpriteTouch, actor); + + // enough to reset gSpriteHit values + actor->vel.X += 5; + } +} + +void triggerTouchWall(DBloodActor* actor, walltype* pHWall) +{ + if (pHWall && pHWall->hasX()) + { + if (pHWall->xw().triggerTouch && !pHWall->xw().isTriggered && (!pHWall->xw().dudeLockout || actor->IsPlayerActor())) + trTriggerWall(pHWall, kCmdWallTouch, actor); + + // enough to reset gSpriteHit values + actor->vel.X += 5; + } +} + +void changeSpriteAngle(DBloodActor* pSpr, int nAng) +{ + if (!pSpr->IsDudeActor()) + pSpr->spr.ang = nAng; + else + { + PLAYER* pPlayer = getPlayerById(pSpr->spr.type); + if (pPlayer) + pPlayer->angle.ang = buildang(nAng); + else + { + pSpr->spr.ang = nAng; + if (pSpr->hasX()) + pSpr->xspr.goalAng = pSpr->spr.ang; + } + } +} + +int getVelocityAngle(DBloodActor* pSpr) +{ + return getangle(pSpr->vel.X >> 12, pSpr->vel.Y >> 12); +} + +#if 0 +bool xsprIsFine(DBloodActor* pSpr) +{ + if (pSpr && pSpr->hasX() && !(pSpr->spr.flags & kHitagFree)) + { + if (!(pSpr->spr.flags & kHitagRespawn) || (pSpr->spr.statnum != kStatThing && pSpr->spr.statnum != kStatDude)) + return true; + } + + return false; +} +#endif + + + //--------------------------------------------------------------------------- // // diff --git a/source/games/blood/src/nnexts.h b/source/games/blood/src/nnexts.h index 80bb74c97..172edc499 100644 --- a/source/games/blood/src/nnexts.h +++ b/source/games/blood/src/nnexts.h @@ -64,6 +64,7 @@ enum kModernTypeFlag4 = 0x0004, kModernTypeFlag8 = 0x0008, kModernTypeFlag16 = 0x0010, + kModernTypeFlag64 = 0x0040, kMaxRandomizeRetries = 16, kPercFull = 100, @@ -139,6 +140,7 @@ enum { kModernCondition = 501, /// WIP, sends command only if specified conditions == true kModernConditionFalse = 502, /// WIP, sends command only if specified conditions != true kModernSlopeChanger = 504, + kModernVelocityChanger = 506, kGenModernMissileUniversal = 704, kGenModernSound = 708, }; @@ -322,11 +324,12 @@ void useDataChanger(DBloodActor* sourceactor, int objType, sectortype* pSector, void useSectorLightChanger(DBloodActor* pXSource, sectortype* pSector); void useTargetChanger(DBloodActor* sourceactor, DBloodActor* actor); void usePictureChanger(DBloodActor* sourceactor, int objType, sectortype*, walltype*, DBloodActor* objActor); -void useSequentialTx(DBloodActor* pXSource, COMMAND_ID cmd, bool setState); -void useRandomTx(DBloodActor* sourceactor, COMMAND_ID cmd, bool setState); +void useSequentialTx(DBloodActor* pXSource, COMMAND_ID cmd, bool setState, DBloodActor* initiator); +void useRandomTx(DBloodActor* sourceactor, COMMAND_ID cmd, bool setState, DBloodActor* initiator); void useDudeSpawn(DBloodActor* pXSource, DBloodActor* pSprite); void useCustomDudeSpawn(DBloodActor* pXSource, DBloodActor* pSprite); -void seqTxSendCmdAll(DBloodActor* pXSource, DBloodActor* nIndex, COMMAND_ID cmd, bool modernSend); +void useVelocityChanger(DBloodActor* pXSource, sectortype* sect, DBloodActor* causerID, DBloodActor* pSprite); +void seqTxSendCmdAll(DBloodActor* pXSource, DBloodActor* nIndex, COMMAND_ID cmd, bool modernSend, DBloodActor* initiator); // ------------------------------------------------------------------------- // void trPlayerCtrlLink(DBloodActor* pXSource, PLAYER* pPlayer, bool checkCondition); void trPlayerCtrlStopScene(PLAYER* pPlayer); @@ -335,7 +338,7 @@ void modernTypeTrigger(int type, sectortype* sect, walltype* wal, DBloodActor* a bool modernTypeOperateSector(sectortype* pSector, const EVENT& event); bool modernTypeOperateSprite(DBloodActor*, EVENT& event); bool modernTypeOperateWall(walltype* pWall, const EVENT& event); -void modernTypeSendCommand(DBloodActor* nSprite, int channel, COMMAND_ID command); +void modernTypeSendCommand(DBloodActor* nSprite, int channel, COMMAND_ID command, DBloodActor* initiator); // ------------------------------------------------------------------------- // bool playerSizeShrink(PLAYER* pPlayer, int divider); bool playerSizeGrow(PLAYER* pPlayer, int multiplier); @@ -371,6 +374,11 @@ void condError(DBloodActor* pXCond, const char* pzFormat, ...); void condUpdateObjectIndex(DBloodActor* oldplayer, DBloodActor* newplayer); DBloodActor* evrListRedirectors(int objType, sectortype*, walltype*, DBloodActor* objActor, DBloodActor* pXRedir, int* tx); void seqSpawnerOffSameTx(DBloodActor* actor); +void triggerTouchSprite(DBloodActor* pSprite, DBloodActor* nHSprite); +void triggerTouchWall(DBloodActor* pSprite, walltype* nHWall); +void killEvents(int nRx, int nCmd); +void changeSpriteAngle(DBloodActor* pSpr, int nAng); +int getVelocityAngle(DBloodActor* pSpr); // ------------------------------------------------------------------------- // void aiPatrolSetMarker(DBloodActor* actor); void aiPatrolThink(DBloodActor* actor); diff --git a/source/games/blood/src/triggers.cpp b/source/games/blood/src/triggers.cpp index e8ae9f0df..bd1f7307c 100644 --- a/source/games/blood/src/triggers.cpp +++ b/source/games/blood/src/triggers.cpp @@ -60,13 +60,13 @@ unsigned int GetWaveValue(unsigned int nPhase, int nType) // //--------------------------------------------------------------------------- -bool SetSpriteState(DBloodActor* actor, int nState) +bool SetSpriteState(DBloodActor* actor, int nState, DBloodActor* initiator) { if ((actor->xspr.busy & 0xffff) == 0 && actor->xspr.state == nState) return 0; actor->xspr.busy = IntToFixed(nState); actor->xspr.state = nState; - evKillActor(actor); + evKillActor(actor, initiator); if ((actor->spr.flags & kHitagRespawn) != 0 && actor->spr.inittype >= kDudeBase && actor->spr.inittype < kDudeMax) { actor->xspr.respawnPending = 3; @@ -74,13 +74,13 @@ bool SetSpriteState(DBloodActor* actor, int nState) return 1; } if (actor->xspr.restState != nState && actor->xspr.waitTime > 0) - evPostActor(actor, (actor->xspr.waitTime * 120) / 10, actor->xspr.restState ? kCmdOn : kCmdOff); + evPostActor(actor, (actor->xspr.waitTime * 120) / 10, actor->xspr.restState ? kCmdOn : kCmdOff, initiator); if (actor->xspr.txID) { if (actor->xspr.command != kCmdLink && actor->xspr.triggerOn && actor->xspr.state) - evSendActor(actor, actor->xspr.txID, (COMMAND_ID)actor->xspr.command); + evSendActor(actor, actor->xspr.txID, (COMMAND_ID)actor->xspr.command, initiator); if (actor->xspr.command != kCmdLink && actor->xspr.triggerOff && !actor->xspr.state) - evSendActor(actor, actor->xspr.txID, (COMMAND_ID)actor->xspr.command); + evSendActor(actor, actor->xspr.txID, (COMMAND_ID)actor->xspr.command, initiator); } return 1; } @@ -91,22 +91,22 @@ bool SetSpriteState(DBloodActor* actor, int nState) // //--------------------------------------------------------------------------- -bool SetWallState(walltype* pWall, int nState) +bool SetWallState(walltype* pWall, int nState, DBloodActor* initiator) { auto pXWall = &pWall->xw(); if ((pXWall->busy & 0xffff) == 0 && pXWall->state == nState) return 0; pXWall->busy = IntToFixed(nState); pXWall->state = nState; - evKillWall(pWall); + evKillWall(pWall, initiator); if (pXWall->restState != nState && pXWall->waitTime > 0) - evPostWall(pWall, (pXWall->waitTime * 120) / 10, pXWall->restState ? kCmdOn : kCmdOff); + evPostWall(pWall, (pXWall->waitTime * 120) / 10, pXWall->restState ? kCmdOn : kCmdOff, initiator); if (pXWall->txID) { if (pXWall->command != kCmdLink && pXWall->triggerOn && pXWall->state) - evSendWall(pWall, pXWall->txID, (COMMAND_ID)pXWall->command); + evSendWall(pWall, pXWall->txID, (COMMAND_ID)pXWall->command, initiator); if (pXWall->command != kCmdLink && pXWall->triggerOff && !pXWall->state) - evSendWall(pWall, pXWall->txID, (COMMAND_ID)pXWall->command); + evSendWall(pWall, pXWall->txID, (COMMAND_ID)pXWall->command, initiator); } return 1; } @@ -117,7 +117,7 @@ bool SetWallState(walltype* pWall, int nState) // //--------------------------------------------------------------------------- -bool SetSectorState(sectortype* pSector, int nState) +bool SetSectorState(sectortype* pSector, int nState, DBloodActor* initiator) { assert(pSector->hasX()); auto pXSector = &pSector->xs(); @@ -125,30 +125,30 @@ bool SetSectorState(sectortype* pSector, int nState) return 0; pXSector->busy = IntToFixed(nState); pXSector->state = nState; - evKillSector(pSector); + evKillSector(pSector, initiator); if (nState == 1) { if (pXSector->command != kCmdLink && pXSector->triggerOn && pXSector->txID) - evSendSector(pSector, pXSector->txID, (COMMAND_ID)pXSector->command); + evSendSector(pSector, pXSector->txID, (COMMAND_ID)pXSector->command, initiator); if (pXSector->stopOn) { pXSector->stopOn = 0; pXSector->stopOff = 0; } else if (pXSector->reTriggerA) - evPostSector(pSector, (pXSector->waitTimeA * 120) / 10, kCmdOff); + evPostSector(pSector, (pXSector->waitTimeA * 120) / 10, kCmdOff, initiator); } else { if (pXSector->command != kCmdLink && pXSector->triggerOff && pXSector->txID) - evSendSector(pSector, pXSector->txID, (COMMAND_ID)pXSector->command); + evSendSector(pSector, pXSector->txID, (COMMAND_ID)pXSector->command, initiator); if (pXSector->stopOff) { pXSector->stopOn = 0; pXSector->stopOff = 0; } else if (pXSector->reTriggerB) - evPostSector(pSector, (pXSector->waitTimeB * 120) / 10, kCmdOn); + evPostSector(pSector, (pXSector->waitTimeB * 120) / 10, kCmdOn, initiator); } return 1; } @@ -172,6 +172,7 @@ void AddBusy(sectortype* pSector, BUSYID a2, int nDelta) return; } } + if (VanillaMode() && gBusy.Size() == 128) return; BUSY b = { pSector, nDelta, nDelta > 0 ? 0 : 65536, a2 }; gBusy.Push(b); } @@ -228,7 +229,8 @@ unsigned int GetSourceBusy(EVENT& a1) void LifeLeechOperate(DBloodActor* actor, EVENT event) { - switch (event.cmd) { + switch (event.cmd) + { case kCmdSpritePush: { int nPlayer = actor->xspr.data4; @@ -317,6 +319,7 @@ void ActivateGenerator(DBloodActor*); void OperateSprite(DBloodActor* actor, EVENT event) { + DBloodActor* initiator = event.initiator; #ifdef NOONE_EXTENSIONS if (gModernMap && modernTypeOperateSprite(actor, event)) return; @@ -338,7 +341,7 @@ void OperateSprite(DBloodActor* actor, EVENT event) switch (event.cmd) { case kCmdOff: - SetSpriteState(actor, 0); + SetSpriteState(actor, 0, initiator); break; case kCmdSpriteProximity: if (actor->xspr.state) break; @@ -346,7 +349,7 @@ void OperateSprite(DBloodActor* actor, EVENT event) case kCmdOn: case kCmdSpritePush: case kCmdSpriteTouch: - if (!actor->xspr.state) SetSpriteState(actor, 1); + if (!actor->xspr.state) SetSpriteState(actor, 1, initiator); aiActivateDude(actor); break; } @@ -360,11 +363,11 @@ void OperateSprite(DBloodActor* actor, EVENT event) if (actor->xspr.health <= 0) break; switch (event.cmd) { case kCmdOff: - if (!SetSpriteState(actor, 0)) break; + if (!SetSpriteState(actor, 0, initiator)) break; seqSpawn(40, actor, -1); break; case kCmdOn: - if (!SetSpriteState(actor, 1)) break; + if (!SetSpriteState(actor, 1, initiator)) break; seqSpawn(38, actor, nMGunOpenClient); if (actor->xspr.data1 > 0) actor->xspr.data2 = actor->xspr.data1; @@ -372,15 +375,15 @@ void OperateSprite(DBloodActor* actor, EVENT event) } break; case kThingFallingRock: - if (SetSpriteState(actor, 1)) + if (SetSpriteState(actor, 1, initiator)) actor->spr.flags |= 7; break; case kThingWallCrack: - if (SetSpriteState(actor, 0)) + if (SetSpriteState(actor, 0, initiator)) actPostSprite(actor, kStatFree); break; case kThingCrateFace: - if (SetSpriteState(actor, 0)) + if (SetSpriteState(actor, 0, initiator)) actPostSprite(actor, kStatFree); break; case kTrapZapSwitchable: @@ -405,12 +408,12 @@ void OperateSprite(DBloodActor* actor, EVENT event) case kTrapFlame: switch (event.cmd) { case kCmdOff: - if (!SetSpriteState(actor, 0)) break; + if (!SetSpriteState(actor, 0, initiator)) break; seqSpawn(40, actor, -1); sfxKill3DSound(actor, 0, -1); break; case kCmdOn: - if (!SetSpriteState(actor, 1)) break; + if (!SetSpriteState(actor, 1, initiator)) break; seqSpawn(38, actor, -1); sfxPlay3DSound(actor, 441, 0, 0); break; @@ -419,14 +422,14 @@ void OperateSprite(DBloodActor* actor, EVENT event) case kSwitchPadlock: switch (event.cmd) { case kCmdOff: - SetSpriteState(actor, 0); + SetSpriteState(actor, 0, initiator); break; case kCmdOn: - if (!SetSpriteState(actor, 1)) break; + if (!SetSpriteState(actor, 1, initiator)) break; seqSpawn(37, actor, -1); break; default: - SetSpriteState(actor, actor->xspr.state ^ 1); + SetSpriteState(actor, actor->xspr.state ^ 1, initiator); if (actor->xspr.state) seqSpawn(37, actor, -1); break; } @@ -434,15 +437,15 @@ void OperateSprite(DBloodActor* actor, EVENT event) case kSwitchToggle: switch (event.cmd) { case kCmdOff: - if (!SetSpriteState(actor, 0)) break; + if (!SetSpriteState(actor, 0, initiator)) break; sfxPlay3DSound(actor, actor->xspr.data2, 0, 0); break; case kCmdOn: - if (!SetSpriteState(actor, 1)) break; + if (!SetSpriteState(actor, 1, initiator)) break; sfxPlay3DSound(actor, actor->xspr.data1, 0, 0); break; default: - if (!SetSpriteState(actor, actor->xspr.state ^ 1)) break; + if (!SetSpriteState(actor, actor->xspr.state ^ 1, initiator)) break; if (actor->xspr.state) sfxPlay3DSound(actor, actor->xspr.data1, 0, 0); else sfxPlay3DSound(actor, actor->xspr.data2, 0, 0); break; @@ -451,15 +454,15 @@ void OperateSprite(DBloodActor* actor, EVENT event) case kSwitchOneWay: switch (event.cmd) { case kCmdOff: - if (!SetSpriteState(actor, 0)) break; + if (!SetSpriteState(actor, 0, initiator)) break; sfxPlay3DSound(actor, actor->xspr.data2, 0, 0); break; case kCmdOn: - if (!SetSpriteState(actor, 1)) break; + if (!SetSpriteState(actor, 1, initiator)) break; sfxPlay3DSound(actor, actor->xspr.data1, 0, 0); break; default: - if (!SetSpriteState(actor, actor->xspr.restState ^ 1)) break; + if (!SetSpriteState(actor, actor->xspr.restState ^ 1, initiator)) break; if (actor->xspr.state) sfxPlay3DSound(actor, actor->xspr.data1, 0, 0); else sfxPlay3DSound(actor, actor->xspr.data2, 0, 0); break; @@ -482,12 +485,12 @@ void OperateSprite(DBloodActor* actor, EVENT event) sfxPlay3DSound(actor, actor->xspr.data4, -1, 0); if (actor->xspr.command == kCmdLink && actor->xspr.txID > 0) - evSendActor(actor, actor->xspr.txID, kCmdLink); + evSendActor(actor, actor->xspr.txID, kCmdLink, initiator); if (actor->xspr.data1 == actor->xspr.data2) - SetSpriteState(actor, 1); + SetSpriteState(actor, 1, initiator); else - SetSpriteState(actor, 0); + SetSpriteState(actor, 0, initiator); break; case kMarkerDudeSpawn: @@ -518,7 +521,7 @@ void OperateSprite(DBloodActor* actor, EVENT event) case kMarkerEarthQuake: actor->xspr.triggerOn = 0; actor->xspr.isTriggered = 1; - SetSpriteState(actor, 1); + SetSpriteState(actor, 1, initiator); for (int p = connecthead; p >= 0; p = connectpoint2[p]) { auto vec = actor->spr.pos - gPlayer[p].actor->spr.pos; int dx = (vec.X) >> 4; @@ -539,7 +542,7 @@ void OperateSprite(DBloodActor* actor, EVENT event) case kTrapExploder: switch (event.cmd) { case kCmdOn: - SetSpriteState(actor, 1); + SetSpriteState(actor, 1, initiator); break; default: actor->spr.cstat &= ~CSTAT_SPRITE_INVISIBLE; @@ -552,7 +555,7 @@ void OperateSprite(DBloodActor* actor, EVENT event) if (event.cmd != kCmdOn) actExplodeSprite(actor); else { sfxPlay3DSound(actor, 454, 0, 0); - evPostActor(actor, 18, kCmdOff); + evPostActor(actor, 18, kCmdOff, initiator); } } break; @@ -562,7 +565,7 @@ void OperateSprite(DBloodActor* actor, EVENT event) case kCmdSpriteProximity: if (actor->xspr.state) break; sfxPlay3DSound(actor, 452, 0, 0); - evPostActor(actor, 30, kCmdOff); + evPostActor(actor, 30, kCmdOff, initiator); actor->xspr.state = 1; [[fallthrough]]; case kCmdOn: @@ -589,20 +592,20 @@ void OperateSprite(DBloodActor* actor, EVENT event) case kGenSound: switch (event.cmd) { case kCmdOff: - SetSpriteState(actor, 0); + SetSpriteState(actor, 0, initiator); break; case kCmdRepeat: if (actor->spr.type != kGenTrigger) ActivateGenerator(actor); - if (actor->xspr.txID) evSendActor(actor, actor->xspr.txID, (COMMAND_ID)actor->xspr.command); + if (actor->xspr.txID) evSendActor(actor, actor->xspr.txID, (COMMAND_ID)actor->xspr.command, initiator); if (actor->xspr.busyTime > 0) { int nRand = Random2(actor->xspr.data1); - evPostActor(actor, 120 * (nRand + actor->xspr.busyTime) / 10, kCmdRepeat); + evPostActor(actor, 120 * (nRand + actor->xspr.busyTime) / 10, kCmdRepeat, initiator); } break; default: if (!actor->xspr.state) { - SetSpriteState(actor, 1); - evPostActor(actor, 0, kCmdRepeat); + SetSpriteState(actor, 1, initiator); + evPostActor(actor, 0, kCmdRepeat, initiator); } break; } @@ -623,15 +626,15 @@ void OperateSprite(DBloodActor* actor, EVENT event) case kThingZombieHead: switch (event.cmd) { case kCmdOff: - if (!SetSpriteState(actor, 0)) break; + if (!SetSpriteState(actor, 0, initiator)) break; actActivateGibObject(actor); break; case kCmdOn: - if (!SetSpriteState(actor, 1)) break; + if (!SetSpriteState(actor, 1, initiator)) break; actActivateGibObject(actor); break; default: - if (!SetSpriteState(actor, actor->xspr.state ^ 1)) break; + if (!SetSpriteState(actor, actor->xspr.state ^ 1, initiator)) break; actActivateGibObject(actor); break; } @@ -639,13 +642,13 @@ void OperateSprite(DBloodActor* actor, EVENT event) default: switch (event.cmd) { case kCmdOff: - SetSpriteState(actor, 0); + SetSpriteState(actor, 0, initiator); break; case kCmdOn: - SetSpriteState(actor, 1); + SetSpriteState(actor, 1, initiator); break; default: - SetSpriteState(actor, actor->xspr.state ^ 1); + SetSpriteState(actor, actor->xspr.state ^ 1, initiator); break; } break; @@ -694,7 +697,9 @@ void SetupGibWallState(walltype* pWall, XWALL* pXWall) // //--------------------------------------------------------------------------- -void OperateWall(walltype* pWall, EVENT event) { +void OperateWall(walltype* pWall, EVENT event) +{ + DBloodActor* initiator = event.initiator; auto pXWall = &pWall->xw(); switch (event.cmd) { @@ -720,13 +725,13 @@ void OperateWall(walltype* pWall, EVENT event) { switch (event.cmd) { case kCmdOn: case kCmdWallImpact: - bStatus = SetWallState(pWall, 1); + bStatus = SetWallState(pWall, 1, initiator); break; case kCmdOff: - bStatus = SetWallState(pWall, 0); + bStatus = SetWallState(pWall, 0, initiator); break; default: - bStatus = SetWallState(pWall, pXWall->state ^ 1); + bStatus = SetWallState(pWall, pXWall->state ^ 1, initiator); break; } @@ -743,13 +748,13 @@ void OperateWall(walltype* pWall, EVENT event) { default: switch (event.cmd) { case kCmdOff: - SetWallState(pWall, 0); + SetWallState(pWall, 0, initiator); break; case kCmdOn: - SetWallState(pWall, 1); + SetWallState(pWall, 1, initiator); break; default: - SetWallState(pWall, pXWall->state ^ 1); + SetWallState(pWall, pXWall->state ^ 1, initiator); break; } return; @@ -1175,7 +1180,7 @@ DBloodActor* GetCrushedSpriteExtents(sectortype* pSector, int* pzTop, int* pzBot // //--------------------------------------------------------------------------- -int VCrushBusy(sectortype* pSector, unsigned int a2) +int VCrushBusy(sectortype* pSector, unsigned int a2, DBloodActor* initiator) { assert(pSector && pSector->hasX()); XSECTOR* pXSector = &pSector->xs(); @@ -1202,10 +1207,10 @@ int VCrushBusy(sectortype* pSector, unsigned int a2) pSector->setfloorz(v10); pXSector->busy = a2; if (pXSector->command == kCmdLink && pXSector->txID) - evSendSector(pSector, pXSector->txID, kCmdLink); + evSendSector(pSector, pXSector->txID, kCmdLink, initiator); if ((a2 & 0xffff) == 0) { - SetSectorState(pSector, FixedToInt(a2)); + SetSectorState(pSector, FixedToInt(a2), initiator); SectorEndSound(pSector, FixedToInt(a2)); return 3; } @@ -1218,7 +1223,7 @@ int VCrushBusy(sectortype* pSector, unsigned int a2) // //--------------------------------------------------------------------------- -int VSpriteBusy(sectortype* pSector, unsigned int a2) +int VSpriteBusy(sectortype* pSector, unsigned int a2, DBloodActor* initiator) { assert(pSector && pSector->hasX()); XSECTOR* pXSector = &pSector->xs(); @@ -1255,10 +1260,10 @@ int VSpriteBusy(sectortype* pSector, unsigned int a2) } pXSector->busy = a2; if (pXSector->command == kCmdLink && pXSector->txID) - evSendSector(pSector, pXSector->txID, kCmdLink); + evSendSector(pSector, pXSector->txID, kCmdLink, initiator); if ((a2 & 0xffff) == 0) { - SetSectorState(pSector, FixedToInt(a2)); + SetSectorState(pSector, FixedToInt(a2), initiator); SectorEndSound(pSector, FixedToInt(a2)); return 3; } @@ -1271,7 +1276,7 @@ int VSpriteBusy(sectortype* pSector, unsigned int a2) // //--------------------------------------------------------------------------- -int VDoorBusy(sectortype* pSector, unsigned int a2) +int VDoorBusy(sectortype* pSector, unsigned int a2, DBloodActor* initiator) { assert(pSector && pSector->hasX()); XSECTOR* pXSector = &pSector->xs(); @@ -1354,10 +1359,10 @@ int VDoorBusy(sectortype* pSector, unsigned int a2) ZTranslateSector(pSector, pXSector, a2, nWave); pXSector->busy = a2; if (pXSector->command == kCmdLink && pXSector->txID) - evSendSector(pSector, pXSector->txID, kCmdLink); + evSendSector(pSector, pXSector->txID, kCmdLink, initiator); if ((a2 & 0xffff) == 0) { - SetSectorState(pSector, FixedToInt(a2)); + SetSectorState(pSector, FixedToInt(a2), initiator); SectorEndSound(pSector, FixedToInt(a2)); return 3; } @@ -1370,7 +1375,7 @@ int VDoorBusy(sectortype* pSector, unsigned int a2) // //--------------------------------------------------------------------------- -int HDoorBusy(sectortype* pSector, unsigned int a2) +int HDoorBusy(sectortype* pSector, unsigned int a2, DBloodActor* initiator) { assert(pSector && pSector->hasX()); XSECTOR* pXSector = &pSector->xs(); @@ -1386,10 +1391,10 @@ int HDoorBusy(sectortype* pSector, unsigned int a2) ZTranslateSector(pSector, pXSector, a2, nWave); pXSector->busy = a2; if (pXSector->command == kCmdLink && pXSector->txID) - evSendSector(pSector, pXSector->txID, kCmdLink); + evSendSector(pSector, pXSector->txID, kCmdLink, initiator); if ((a2 & 0xffff) == 0) { - SetSectorState(pSector, FixedToInt(a2)); + SetSectorState(pSector, FixedToInt(a2), initiator); SectorEndSound(pSector, FixedToInt(a2)); return 3; } @@ -1402,7 +1407,7 @@ int HDoorBusy(sectortype* pSector, unsigned int a2) // //--------------------------------------------------------------------------- -int RDoorBusy(sectortype* pSector, unsigned int a2) +int RDoorBusy(sectortype* pSector, unsigned int a2, DBloodActor* initiator) { assert(pSector && pSector->hasX()); XSECTOR* pXSector = &pSector->xs(); @@ -1417,10 +1422,10 @@ int RDoorBusy(sectortype* pSector, unsigned int a2) ZTranslateSector(pSector, pXSector, a2, nWave); pXSector->busy = a2; if (pXSector->command == kCmdLink && pXSector->txID) - evSendSector(pSector, pXSector->txID, kCmdLink); + evSendSector(pSector, pXSector->txID, kCmdLink, initiator); if ((a2 & 0xffff) == 0) { - SetSectorState(pSector, FixedToInt(a2)); + SetSectorState(pSector, FixedToInt(a2), initiator); SectorEndSound(pSector, FixedToInt(a2)); return 3; } @@ -1433,7 +1438,7 @@ int RDoorBusy(sectortype* pSector, unsigned int a2) // //--------------------------------------------------------------------------- -int StepRotateBusy(sectortype* pSector, unsigned int a2) +int StepRotateBusy(sectortype* pSector, unsigned int a2, DBloodActor* initiator) { assert(pSector && pSector->hasX()); XSECTOR* pXSector = &pSector->xs(); @@ -1454,10 +1459,10 @@ int StepRotateBusy(sectortype* pSector, unsigned int a2) } pXSector->busy = a2; if (pXSector->command == kCmdLink && pXSector->txID) - evSendSector(pSector, pXSector->txID, kCmdLink); + evSendSector(pSector, pXSector->txID, kCmdLink, initiator); if ((a2 & 0xffff) == 0) { - SetSectorState(pSector, FixedToInt(a2)); + SetSectorState(pSector, FixedToInt(a2), initiator); SectorEndSound(pSector, FixedToInt(a2)); pXSector->data = vbp & 2047; return 3; @@ -1471,16 +1476,16 @@ int StepRotateBusy(sectortype* pSector, unsigned int a2) // //--------------------------------------------------------------------------- -int GenSectorBusy(sectortype* pSector, unsigned int a2) +int GenSectorBusy(sectortype* pSector, unsigned int a2, DBloodActor* initiator) { assert(pSector && pSector->hasX()); XSECTOR* pXSector = &pSector->xs(); pXSector->busy = a2; if (pXSector->command == kCmdLink && pXSector->txID) - evSendSector(pSector, pXSector->txID, kCmdLink); + evSendSector(pSector, pXSector->txID, kCmdLink, initiator); if ((a2 & 0xffff) == 0) { - SetSectorState(pSector, FixedToInt(a2)); + SetSectorState(pSector, FixedToInt(a2), initiator); SectorEndSound(pSector, FixedToInt(a2)); return 3; } @@ -1493,7 +1498,7 @@ int GenSectorBusy(sectortype* pSector, unsigned int a2) // //--------------------------------------------------------------------------- -int PathBusy(sectortype* pSector, unsigned int a2) +int PathBusy(sectortype* pSector, unsigned int a2, DBloodActor* initiator) { assert(pSector && pSector->hasX()); XSECTOR* pXSector = &pSector->xs(); @@ -1509,7 +1514,7 @@ int PathBusy(sectortype* pSector, unsigned int a2) pXSector->busy = a2; if ((a2 & 0xffff) == 0) { - evPostSector(pSector, (120 * marker1->xspr.waitTime) / 10, kCmdOn); + evPostSector(pSector, (120 * marker1->xspr.waitTime) / 10, kCmdOn, initiator); pXSector->state = 0; pXSector->busy = 0; if (marker0->xspr.data4) @@ -1676,7 +1681,7 @@ void OperatePath(sectortype* pSector, EVENT event) // trigger marker after it gets reached #ifdef NOONE_EXTENSIONS if (gModernMap && marker0->xspr.state != 1) - trTriggerSprite(pXSector->marker0, kCmdOn); + trTriggerSprite(pXSector->marker0, kCmdOn, event.initiator); #endif if (actor == nullptr) { @@ -1778,17 +1783,18 @@ void OperateSector(sectortype* pSector, EVENT event) OperatePath(pSector, event); break; default: - if (!pXSector->busyTimeA && !pXSector->busyTimeB) { - + if (!pXSector->busyTimeA && !pXSector->busyTimeB) + { + DBloodActor* initiator = event.initiator; switch (event.cmd) { case kCmdOff: - SetSectorState(pSector, 0); + SetSectorState(pSector, 0, initiator); break; case kCmdOn: - SetSectorState(pSector, 1); + SetSectorState(pSector, 1, initiator); break; default: - SetSectorState(pSector, pXSector->state ^ 1); + SetSectorState(pSector, pXSector->state ^ 1, initiator); break; } @@ -1835,7 +1841,7 @@ void InitPath(sectortype* pSector, XSECTOR* pXSector) pXSector->basePath = pXSector->marker0 = actor; if (pXSector->state) - evPostSector(pSector, 0, kCmdOn); + evPostSector(pSector, 0, kCmdOn, nullptr); } //--------------------------------------------------------------------------- @@ -1846,27 +1852,28 @@ void InitPath(sectortype* pSector, XSECTOR* pXSector) void LinkSector(sectortype* pSector, EVENT event) { + DBloodActor* initiator = event.initiator; auto pXSector = &pSector->xs(); int nBusy = GetSourceBusy(event); switch (pSector->type) { case kSectorZMotionSprite: - VSpriteBusy(pSector, nBusy); + VSpriteBusy(pSector, nBusy, initiator); break; case kSectorZMotion: - VDoorBusy(pSector, nBusy); + VDoorBusy(pSector, nBusy, initiator); break; case kSectorSlideMarked: case kSectorSlide: - HDoorBusy(pSector, nBusy); + HDoorBusy(pSector, nBusy, initiator); break; case kSectorRotateMarked: case kSectorRotate: - RDoorBusy(pSector, nBusy); + RDoorBusy(pSector, nBusy, initiator); break; default: pXSector->busy = nBusy; if ((pXSector->busy & 0xffff) == 0) - SetSectorState(pSector, FixedToInt(nBusy)); + SetSectorState(pSector, FixedToInt(nBusy), initiator); break; } } @@ -1879,6 +1886,7 @@ void LinkSector(sectortype* pSector, EVENT event) void LinkSprite(DBloodActor* actor, EVENT event) { + DBloodActor* initiator = event.initiator; int nBusy = GetSourceBusy(event); switch (actor->spr.type) { @@ -1890,9 +1898,9 @@ void LinkSprite(DBloodActor* actor, EVENT event) actor->xspr.data1 = actor2 && actor2->hasX() ? actor2->xspr.data1 : 0; if (actor->xspr.data1 == actor->xspr.data2) - SetSpriteState(actor, 1); + SetSpriteState(actor, 1, initiator); else - SetSpriteState(actor, 0); + SetSpriteState(actor, 0, initiator); } } break; @@ -1900,7 +1908,7 @@ void LinkSprite(DBloodActor* actor, EVENT event) { actor->xspr.busy = nBusy; if ((actor->xspr.busy & 0xffff) == 0) - SetSpriteState(actor, FixedToInt(nBusy)); + SetSpriteState(actor, FixedToInt(nBusy), initiator); } break; } @@ -1917,7 +1925,7 @@ void LinkWall(walltype* pWall, EVENT& event) int nBusy = GetSourceBusy(event); pWall->xw().busy = nBusy; if ((pWall->xw().busy & 0xffff) == 0) - SetWallState(pWall, FixedToInt(nBusy)); + SetWallState(pWall, FixedToInt(nBusy), event.initiator); } //--------------------------------------------------------------------------- @@ -1926,7 +1934,7 @@ void LinkWall(walltype* pWall, EVENT& event) // //--------------------------------------------------------------------------- -void trTriggerSector(sectortype* pSector, int command) +void trTriggerSector(sectortype* pSector, int command, DBloodActor* initiator) { auto pXSector = &pSector->xs(); if (!pXSector->locked && !pXSector->isTriggered) { @@ -1935,11 +1943,12 @@ void trTriggerSector(sectortype* pSector, int command) pXSector->isTriggered = 1; if (pXSector->decoupled && pXSector->txID > 0) - evSendSector(pSector, pXSector->txID, (COMMAND_ID)pXSector->command); + evSendSector(pSector, pXSector->txID, (COMMAND_ID)pXSector->command, initiator); else { EVENT event; event.cmd = command; + event.initiator = gModernMap? initiator : nullptr; OperateSector(pSector, event); } @@ -1952,7 +1961,7 @@ void trTriggerSector(sectortype* pSector, int command) // //--------------------------------------------------------------------------- -void trTriggerWall(walltype* pWall, int command) +void trTriggerWall(walltype* pWall, int command, DBloodActor* initiator) { if (!pWall->hasX()) return; auto pXWall = &pWall->xw(); @@ -1962,11 +1971,12 @@ void trTriggerWall(walltype* pWall, int command) pXWall->isTriggered = 1; if (pXWall->decoupled && pXWall->txID > 0) - evSendWall(pWall, pXWall->txID, (COMMAND_ID)pXWall->command); + evSendWall(pWall, pXWall->txID, (COMMAND_ID)pXWall->command, initiator); else { EVENT event; event.cmd = command; + event.initiator = gModernMap ? initiator : nullptr; OperateWall(pWall, event); } @@ -1979,7 +1989,7 @@ void trTriggerWall(walltype* pWall, int command) // //--------------------------------------------------------------------------- -void trTriggerSprite(DBloodActor* actor, int command) +void trTriggerSprite(DBloodActor* actor, int command, DBloodActor* initiator) { if (!actor->xspr.locked && !actor->xspr.isTriggered) { @@ -1987,11 +1997,12 @@ void trTriggerSprite(DBloodActor* actor, int command) actor->xspr.isTriggered = 1; if (actor->xspr.Decoupled && actor->xspr.txID > 0) - evSendActor(actor, actor->xspr.txID, (COMMAND_ID)actor->xspr.command); + evSendActor(actor, actor->xspr.txID, (COMMAND_ID)actor->xspr.command, initiator); else { EVENT event; event.cmd = command; + event.initiator = gModernMap ? initiator : nullptr; OperateSprite(actor, event); } @@ -2198,7 +2209,7 @@ void AlignSlopes(void) // //--------------------------------------------------------------------------- -int(*gBusyProc[])(sectortype*, unsigned int) = +int(*gBusyProc[])(sectortype*, unsigned int, DBloodActor*) = { VCrushBusy, VSpriteBusy, @@ -2222,7 +2233,7 @@ void trProcessBusy(void) int oldBusy = gBusy[i].busy; gBusy[i].busy = ClipRange(oldBusy + gBusy[i].delta * 4, 0, 65536); #ifdef NOONE_EXTENSIONS - if (!gModernMap || !gBusy[i].sect->xs().unused1) nStatus = gBusyProc[gBusy[i].type](gBusy[i].sect, gBusy[i].busy); + if (!gModernMap || !gBusy[i].sect->xs().unused1) nStatus = gBusyProc[gBusy[i].type](gBusy[i].sect, gBusy[i].busy, nullptr); else nStatus = 3; // allow to pause/continue motion for sectors any time by sending special command #else nStatus = gBusyProc[gBusy[i].type](gBusy[i].at0, gBusy[i].at8); @@ -2382,9 +2393,9 @@ void trInit(TArray& actors) case kModernRandom2: if (!gModernMap || actor->xspr.state == actor->xspr.restState) break; - evPostActor(actor, (120 * actor->xspr.busyTime) / 10, kCmdRepeat); + evPostActor(actor, (120 * actor->xspr.busyTime) / 10, kCmdRepeat, actor); if (actor->xspr.waitTime > 0) - evPostActor(actor, (actor->xspr.waitTime * 120) / 10, actor->xspr.restState ? kCmdOn : kCmdOff); + evPostActor(actor, (actor->xspr.waitTime * 120) / 10, actor->xspr.restState ? kCmdOn : kCmdOff, actor); break; case kModernSeqSpawner: case kModernObjDataAccumulator: @@ -2392,9 +2403,9 @@ void trInit(TArray& actors) case kModernEffectSpawner: case kModernWindGenerator: if (actor->xspr.state == actor->xspr.restState) break; - evPostActor(actor, 0, kCmdRepeat); + evPostActor(actor, 0, kCmdRepeat, actor); if (actor->xspr.waitTime > 0) - evPostActor(actor, (actor->xspr.waitTime * 120) / 10, actor->xspr.restState ? kCmdOn : kCmdOff); + evPostActor(actor, (actor->xspr.waitTime * 120) / 10, actor->xspr.restState ? kCmdOn : kCmdOff, actor); break; #endif case kGenTrigger: @@ -2473,7 +2484,7 @@ void InitGenerator(DBloodActor* actor) break; } if (actor->xspr.state != actor->xspr.restState && actor->xspr.busyTime > 0) - evPostActor(actor, (120 * (actor->xspr.busyTime + Random2(actor->xspr.data1))) / 10, kCmdRepeat); + evPostActor(actor, (120 * (actor->xspr.busyTime + Random2(actor->xspr.data1))) / 10, kCmdRepeat, actor); } //--------------------------------------------------------------------------- @@ -2550,7 +2561,7 @@ void MGunFireSeqCallback(int, DBloodActor* actor) { actor->xspr.data2--; if (actor->xspr.data2 == 0) - evPostActor(actor, 1, kCmdOff); + evPostActor(actor, 1, kCmdOff, actor); } int dx = bcos(actor->spr.ang) + Random2(1000); int dy = bsin(actor->spr.ang) + Random2(1000); diff --git a/source/games/blood/src/triggers.h b/source/games/blood/src/triggers.h index 75471edf0..2cf64b8ff 100644 --- a/source/games/blood/src/triggers.h +++ b/source/games/blood/src/triggers.h @@ -51,18 +51,18 @@ struct BUSY { extern TArray gBusy; -void trTriggerSector(sectortype* pSector, int command); +void trTriggerSector(sectortype* pSector, int command, DBloodActor* initiator = nullptr); void trMessageSector(sectortype* pSector, EVENT event); -void trTriggerWall(walltype*, int command); +void trTriggerWall(walltype*, int command, DBloodActor* initiator = nullptr); void trMessageWall(walltype* pWall, EVENT& event); -void trTriggerSprite(DBloodActor* actor, int command); +void trTriggerSprite(DBloodActor* actor, int command, DBloodActor* initiator = nullptr); void trMessageSprite(DBloodActor* actor, EVENT event); void trProcessBusy(void); void trInit(TArray& actors); void trTextOver(int nId); -bool SetSpriteState(DBloodActor* actor, int nState); -bool SetWallState(walltype* pWall, int nState); -bool SetSectorState(sectortype* pSector, int nState); +bool SetSpriteState(DBloodActor* actor, int nState, DBloodActor* initiator); +bool SetWallState(walltype* pWall, int nState, DBloodActor* initiator); +bool SetSectorState(sectortype* pSector, int nState, DBloodActor* initiator); void TeleFrag(DBloodActor* killer, sectortype* pSector); void SectorStartSound(sectortype* pSector, int nState); void SectorEndSound(sectortype* pSector, int nState); diff --git a/source/games/blood/src/weapon.cpp b/source/games/blood/src/weapon.cpp index 9fc8256f5..08966aa14 100644 --- a/source/games/blood/src/weapon.cpp +++ b/source/games/blood/src/weapon.cpp @@ -1198,7 +1198,7 @@ void ThrowCan(int, PLAYER* pPlayer) { sfxPlay3DSound(spawned, 441, 0, 0); spawned->spr.shade = -128; - evPostActor(spawned, pPlayer->fuseTime, kCmdOn); + evPostActor(spawned, pPlayer->fuseTime, kCmdOn, pPlayer->actor); spawned->xspr.Impact = 1; UseAmmo(pPlayer, 6, gAmmoItemData[0].count); pPlayer->throwPower = 0; @@ -1217,7 +1217,7 @@ void DropCan(int, PLAYER* pPlayer) auto spawned = playerFireThing(pPlayer, 0, 0, kThingArmedSpray, 0); if (spawned) { - evPostActor(spawned, pPlayer->fuseTime, kCmdOn); + evPostActor(spawned, pPlayer->fuseTime, kCmdOn, pPlayer->actor); UseAmmo(pPlayer, 6, gAmmoItemData[0].count); } } @@ -1234,7 +1234,7 @@ void ExplodeCan(int, PLAYER* pPlayer) auto spawned = playerFireThing(pPlayer, 0, 0, kThingArmedSpray, 0); if (spawned) { - evPostActor(spawned, 0, kCmdOn); + evPostActor(spawned, 0, kCmdOn, pPlayer->actor); UseAmmo(pPlayer, 6, gAmmoItemData[0].count); StartQAV(pPlayer, kQAVCANBOOM); pPlayer->curWeapon = kWeapNone; @@ -1259,7 +1259,7 @@ void ThrowBundle(int, PLAYER* pPlayer) if (pPlayer->fuseTime < 0) spawned->xspr.Impact = 1; else - evPostActor(spawned, pPlayer->fuseTime, kCmdOn); + evPostActor(spawned, pPlayer->fuseTime, kCmdOn, pPlayer->actor); UseAmmo(pPlayer, 5, 1); pPlayer->throwPower = 0; } @@ -1277,7 +1277,7 @@ void DropBundle(int, PLAYER* pPlayer) auto spawned = playerFireThing(pPlayer, 0, 0, kThingArmedTNTBundle, 0); if (spawned) { - evPostActor(spawned, pPlayer->fuseTime, kCmdOn); + evPostActor(spawned, pPlayer->fuseTime, kCmdOn, pPlayer->actor); UseAmmo(pPlayer, 5, 1); } } @@ -1294,7 +1294,7 @@ void ExplodeBundle(int, PLAYER* pPlayer) auto spawned = playerFireThing(pPlayer, 0, 0, kThingArmedTNTBundle, 0); if (spawned) { - evPostActor(spawned, 0, kCmdOn); + evPostActor(spawned, 0, kCmdOn, pPlayer->actor); UseAmmo(pPlayer, 5, 1); StartQAV(pPlayer, kQAVDYNEXPLO); pPlayer->curWeapon = kWeapNone; @@ -1315,7 +1315,7 @@ void ThrowProx(int, PLAYER* pPlayer) auto spawned = playerFireThing(pPlayer, 0, -9460, kThingArmedProxBomb, nSpeed); if (spawned) { - evPostActor(spawned, 240, kCmdOn); + evPostActor(spawned, 240, kCmdOn, pPlayer->actor); UseAmmo(pPlayer, 10, 1); pPlayer->throwPower = 0; } @@ -1332,7 +1332,7 @@ void DropProx(int, PLAYER* pPlayer) auto spawned = playerFireThing(pPlayer, 0, 0, kThingArmedProxBomb, 0); if (spawned) { - evPostActor(spawned, 240, kCmdOn); + evPostActor(spawned, 240, kCmdOn, pPlayer->actor); UseAmmo(pPlayer, 10, 1); } }