diff --git a/source/games/blood/src/actor.cpp b/source/games/blood/src/actor.cpp index 66a7ee868..33b54bc7e 100644 --- a/source/games/blood/src/actor.cpp +++ b/source/games/blood/src/actor.cpp @@ -5089,7 +5089,7 @@ void MoveDude(DBloodActor* actor) #ifdef NOONE_EXTENSIONS if (actor->IsDudeActor() && pXSprite->health > 0 && aiInPatrolState(nAiStateType)) - aiPatrolState(pSprite, kAiStatePatrolMoveL); // continue patrol when going from water + aiPatrolState(actor, kAiStatePatrolMoveL); // continue patrol when going from water #endif } break; @@ -5192,7 +5192,7 @@ void MoveDude(DBloodActor* actor) // continue patrol when fall into water if (actor->IsDudeActor() && pXSprite->health > 0 && aiInPatrolState(nAiStateType)) - aiPatrolState(pSprite, kAiStatePatrolMoveW); + aiPatrolState(actor, kAiStatePatrolMoveW); } #endif @@ -5632,7 +5632,7 @@ void actExplodeSprite(DBloodActor* actor) pSprite->flags &= ~3; pSprite->type = nType; const EXPLOSION* pExplodeInfo = &explodeInfo[nType]; - pXSprite->target_i = 0; + actor->SetTarget(nullptr); pXSprite->data1 = pExplodeInfo->ticks; pXSprite->data2 = pExplodeInfo->quakeEffect; pXSprite->data3 = pExplodeInfo->flashEffect; diff --git a/source/games/blood/src/ai.cpp b/source/games/blood/src/ai.cpp index b2cb5554e..8a4d43640 100644 --- a/source/games/blood/src/ai.cpp +++ b/source/games/blood/src/ai.cpp @@ -1978,21 +1978,22 @@ void aiInitSprite(DBloodActor* actor) // make dude follow the markers bool uwater = spriteIsUnderwater(actor); - if (pXSprite->target_i <= 0 || sprite[pXSprite->target_i].type != kMarkerPath) + if (actor->GetTarget() == nullptr || actor->GetTarget()->s().type != kMarkerPath) { actor->SetTarget(nullptr); aiPatrolSetMarker(pSprite, pXSprite); } - if (stateTimer > 0) { - if (uwater) aiPatrolState(pSprite, kAiStatePatrolWaitW); - else if (pXSprite->unused1 & kDudeFlagCrouch) aiPatrolState(pSprite, kAiStatePatrolWaitC); - else aiPatrolState(pSprite, kAiStatePatrolWaitL); + if (stateTimer > 0) + { + if (uwater) aiPatrolState(actor, kAiStatePatrolWaitW); + else if (pXSprite->unused1 & kDudeFlagCrouch) aiPatrolState(actor, kAiStatePatrolWaitC); + else aiPatrolState(actor, kAiStatePatrolWaitL); pXSprite->stateTimer = stateTimer; // restore state timer } - else if (uwater) aiPatrolState(pSprite, kAiStatePatrolMoveW); - else if (pXSprite->unused1 & kDudeFlagCrouch) aiPatrolState(pSprite, kAiStatePatrolMoveC); - else aiPatrolState(pSprite, kAiStatePatrolMoveL); + else if (uwater) aiPatrolState(actor, kAiStatePatrolMoveW); + else if (pXSprite->unused1 & kDudeFlagCrouch) aiPatrolState(actor, kAiStatePatrolMoveC); + else aiPatrolState(actor, kAiStatePatrolMoveL); } } #endif diff --git a/source/games/blood/src/nnexts.cpp b/source/games/blood/src/nnexts.cpp index f8e0d6e70..077523dfe 100644 --- a/source/games/blood/src/nnexts.cpp +++ b/source/games/blood/src/nnexts.cpp @@ -4299,15 +4299,17 @@ bool condCheckDude(XSPRITE* pXCond, int cmpOp, bool PUSH) { case 9: return (pXSpr->unused1 & kDudeFlagStealth); case 10: // check if the marker is busy with another dude case 11: // check if the marker is reached - if (!pXSpr->dudeFlag4 || !spriRangeIsFine(pXSpr->target_i) || sprite[pXSpr->target_i].type != kMarkerPath) return false; + if (!pXSpr->dudeFlag4 || !actor->GetTarget() || actor->GetTarget()->s().type != kMarkerPath) return false; switch (cond) { case 10: - var = aiPatrolMarkerBusy(pSpr->index, pXSpr->target_i); - if (!spriRangeIsFine(var)) return false; - else if (PUSH) condPush(pXCond, OBJ_SPRITE, var); + { + auto var = aiPatrolMarkerBusy(actor, actor->GetTarget()); + if (!var) return false; + else if (PUSH) condPush(pXCond, OBJ_SPRITE, var->s().index); break; + } case 11: - if (!aiPatrolMarkerReached(pSpr, pXSpr)) return false; + if (!aiPatrolMarkerReached(actor)) return false; else if (PUSH) condPush(pXCond, OBJ_SPRITE, pXSpr->target_i); break; } @@ -7541,18 +7543,23 @@ void nnExtAiSetDirection(DBloodActor* actor, int a3) } +//--------------------------------------------------------------------------- +// /// patrol functions -// ------------------------------------------------ -void aiPatrolState(spritetype* pSprite, int state) { - auto actor = &bloodActors[pSprite->index]; +// +//--------------------------------------------------------------------------- - assert(pSprite->type >= kDudeBase && pSprite->type < kDudeMax); +void aiPatrolState(DBloodActor* actor, int state) +{ + spritetype* pSprite = &actor->s(); + assert(pSprite->type >= kDudeBase && pSprite->type < kDudeMax && actor->hasX()); + assert(actor->GetTarget()); - XSPRITE* pXSprite = &xsprite[pSprite->extra]; - assert(pXSprite->target_i >= 0 && pXSprite->target_i < kMaxSprites); + XSPRITE* pXSprite = &actor->x(); - spritetype* pMarker = &sprite[pXSprite->target_i]; - XSPRITE* pXMarker = &xsprite[pMarker->extra]; + auto markeractor = actor->GetTarget(); + spritetype* pMarker = &markeractor->s(); + XSPRITE* pXMarker = &markeractor->x(); assert(pMarker->type == kMarkerPath); bool nSeqOverride = false, crouch = false; @@ -7610,82 +7617,91 @@ void aiPatrolState(spritetype* pSprite, int state) { if (seq < 0) return aiPatrolStop(pSprite, -1); - for (i = start; i < end; i++) { - + for (i = start; i < end; i++) + { AISTATE* newState = &genPatrolStates[i]; if (newState->stateType != state || (!nSeqOverride && seq != newState->seqId)) continue; if (pSprite->type == kDudeModernCustom) aiGenDudeNewState(actor, newState); - else aiNewState(&bloodActors[pXSprite->reference], newState); + else aiNewState(actor, newState); if (crouch) pXSprite->unused1 |= kDudeFlagCrouch; else pXSprite->unused1 &= ~kDudeFlagCrouch; if (nSeqOverride) - seqSpawn(seq, OBJ_SPRITE, pSprite->extra); + seqSpawn(seq, actor); return; - } - if (i == end) { - viewSetSystemMessage("No patrol state #%d found for dude #%d (type = %d)", state, pSprite->index, pSprite->type); + if (i == end) + { + viewSetSystemMessage("No patrol state #%d found for dude #%d (type = %d)", state, actor->GetIndex(), pSprite->type); aiPatrolStop(pSprite, -1); } } +//--------------------------------------------------------------------------- +// // check if some dude already follows the given marker -int aiPatrolMarkerBusy(int nExcept, int nMarker) { - for (int i = headspritestat[kStatDude]; i != -1; i = nextspritestat[i]) { - if (!IsDudeSprite(&sprite[i]) || sprite[i].index == nExcept || !xspriRangeIsFine(sprite[i].extra)) +// +//--------------------------------------------------------------------------- + +DBloodActor* aiPatrolMarkerBusy(DBloodActor* except, DBloodActor* marker) +{ + BloodStatIterator it(kStatDude); + while (auto actor = it.Next()) + { + if (!actor->IsDudeActor() || actor == except || !actor->hasX()) continue; - XSPRITE* pXDude = &xsprite[sprite[i].extra]; - if (pXDude->health > 0 && pXDude->target_i >= 0 && sprite[pXDude->target_i].type == kMarkerPath && pXDude->target_i == nMarker) - return sprite[i].index; + auto targ = actor->GetTarget(); + if (actor->x().health > 0 && targ != nullptr && targ->s().type == kMarkerPath && targ == marker) + return actor; } - - return -1; + return nullptr; } +//--------------------------------------------------------------------------- +// +// check if some dude already follows the given marker +// +//--------------------------------------------------------------------------- -bool aiPatrolMarkerReached(spritetype* pSprite, XSPRITE* pXSprite) { - +bool aiPatrolMarkerReached(DBloodActor* actor) +{ + spritetype* pSprite = &actor->s(); + XSPRITE* pXSprite = &actor->x(); assert(pSprite->type >= kDudeBase && pSprite->type < kDudeMax); - auto actor = &bloodActors[pSprite->index]; const DUDEINFO_EXTRA* pExtra = &gDudeInfoExtra[pSprite->type - kDudeBase]; - if (spriRangeIsFine(pXSprite->target_i) && sprite[pXSprite->target_i].type == kMarkerPath) { - - spritetype* pMarker = &sprite[pXSprite->target_i]; - short okDist = ClipLow(pMarker->clipdist << 1, 4); + auto markeractor = actor->GetTarget(); + if (markeractor && markeractor->s().type == kMarkerPath) + { + spritetype* pMarker = &markeractor->s(); + int okDist = ClipLow(pMarker->clipdist << 1, 4); int oX = abs(pMarker->x - pSprite->x) >> 4; int oY = abs(pMarker->y - pSprite->y) >> 4; - if (approxDist(oX, oY) <= okDist) { - - if (spriteIsUnderwater(actor) || pExtra->flying) { - + if (approxDist(oX, oY) <= okDist) + { + if (spriteIsUnderwater(actor) || pExtra->flying) + { okDist = pMarker->clipdist << 4; int ztop, zbot, ztop2, zbot2; - GetSpriteExtents(pSprite, &ztop, &zbot); - GetSpriteExtents(pMarker, &ztop2, &zbot2); + GetActorExtents(actor, &ztop, &zbot); + GetActorExtents(markeractor, &ztop2, &zbot2); int oZ1 = abs(zbot - ztop2) >> 6; int oZ2 = abs(ztop - zbot2) >> 6; if (oZ1 > okDist && oZ2 > okDist) return false; - } - return true; } - } - return false; - } int findNextMarker(XSPRITE* pXMark, bool back) { @@ -7793,7 +7809,7 @@ void aiPatrolSetMarker(spritetype* pSprite, XSPRITE* pXSprite) { continue; if (firstFinePath == -1) firstFinePath = pXNext->reference; - if (aiPatrolMarkerBusy(pSprite->index, pXNext->reference) >= 0 && !Chance(0x0010)) continue; + if (aiPatrolMarkerBusy(&bloodActors[pSprite->index], &bloodActors[pXNext->reference]) && !Chance(0x0010)) continue; else path = pXNext->reference; breakChance += nnExtRandom(1, 5); @@ -7941,12 +7957,11 @@ void aiPatrolMove(DBloodActor* actor) { int nAng = ((pXSprite->goalAng + 1024 - pSprite->ang) & 2047) - 1024; pSprite->ang = (pSprite->ang + ClipRange(nAng, -nTurnRange, nTurnRange)) & 2047; - if (abs(nAng) > goalAng || ((pXTarget->waitTime > 0 || pXTarget->data1 == pXTarget->data2) && aiPatrolMarkerReached(pSprite, pXSprite))) { - + if (abs(nAng) > goalAng || ((pXTarget->waitTime > 0 || pXTarget->data1 == pXTarget->data2) && aiPatrolMarkerReached(actor))) + { actor->xvel() = 0; actor->yvel() = 0; return; - } if (gSpriteHit[pSprite->extra].hit.type == kHitSprite) @@ -8473,8 +8488,8 @@ void aiPatrolFlagsMgr(spritetype* pSource, XSPRITE* pXSource, spritetype* pDest, aiPatrolSetMarker(pDest, pXDest); - if (spriteIsUnderwater(destactor)) aiPatrolState(pDest, kAiStatePatrolWaitW); - else aiPatrolState(pDest, kAiStatePatrolWaitL); + if (spriteIsUnderwater(destactor)) aiPatrolState(destactor, kAiStatePatrolWaitW); + else aiPatrolState(destactor, kAiStatePatrolWaitL); pXDest->data3 = 0; // reset the spot progress } @@ -8534,9 +8549,9 @@ void aiPatrolThink(DBloodActor* actor) { if (--pXSprite->unused4 <= 0) { - if (uwater) aiPatrolState(pSprite, kAiStatePatrolTurnW); - else if (crouch) aiPatrolState(pSprite, kAiStatePatrolTurnC); - else aiPatrolState(pSprite, kAiStatePatrolTurnL); + if (uwater) aiPatrolState(actor, kAiStatePatrolTurnW); + else if (crouch) aiPatrolState(actor, kAiStatePatrolTurnC); + else aiPatrolState(actor, kAiStatePatrolTurnL); pXSprite->unused4 = kMinPatrolTurnDelay + Random(kPatrolTurnDelayRange); } @@ -8587,9 +8602,9 @@ void aiPatrolThink(DBloodActor* actor) { // save imer for waiting stateTimer = pXSprite->stateTimer; - if (uwater) aiPatrolState(pSprite, kAiStatePatrolWaitW); - else if (crouch) aiPatrolState(pSprite, kAiStatePatrolWaitC); - else aiPatrolState(pSprite, kAiStatePatrolWaitL); + if (uwater) aiPatrolState(actor, kAiStatePatrolWaitW); + else if (crouch) aiPatrolState(actor, kAiStatePatrolWaitC); + else aiPatrolState(actor, kAiStatePatrolWaitL); // must restore it pXSprite->stateTimer = stateTimer; @@ -8599,7 +8614,7 @@ void aiPatrolThink(DBloodActor* actor) { return; - } else if ((reached = aiPatrolMarkerReached(pSprite, pXSprite)) == true) { + } else if ((reached = aiPatrolMarkerReached(actor)) == true) { pXMarker->isTriggered = pXMarker->triggerOnce; // can't select this marker for path anymore if true @@ -8622,8 +8637,8 @@ void aiPatrolThink(DBloodActor* actor) { } - if (pMarker->owner == pSprite->index) - pMarker->owner = aiPatrolMarkerBusy(pSprite->index, pMarker->index); + if (markeractor->GetOwner() == actor) + markeractor->SetOwner(aiPatrolMarkerBusy(actor, markeractor)); // trigger at arrival if (pXMarker->triggerOn) { @@ -8644,9 +8659,9 @@ void aiPatrolThink(DBloodActor* actor) { } - if (uwater) aiPatrolState(pSprite, kAiStatePatrolWaitW); - else if (crouch) aiPatrolState(pSprite, kAiStatePatrolWaitC); - else aiPatrolState(pSprite, kAiStatePatrolWaitL); + if (uwater) aiPatrolState(actor, kAiStatePatrolWaitW); + else if (crouch) aiPatrolState(actor, kAiStatePatrolWaitC); + else aiPatrolState(actor, kAiStatePatrolWaitL); if (pXMarker->waitTime) pXSprite->stateTimer = (pXMarker->waitTime * 120) / 10; @@ -8660,9 +8675,9 @@ void aiPatrolThink(DBloodActor* actor) { } else { - if (pMarker->owner == pSprite->index) - pMarker->owner = aiPatrolMarkerBusy(pSprite->index, pMarker->index); - + if (markeractor->GetOwner() == actor) + markeractor->SetOwner(aiPatrolMarkerBusy(actor, markeractor)); + if (pXMarker->triggerOn || pXMarker->triggerOff) { if (pXMarker->txID) { @@ -8702,9 +8717,9 @@ void aiPatrolThink(DBloodActor* actor) { nnExtAiSetDirection(actor, getangle(pMarker->x - pSprite->x, pMarker->y - pSprite->y)); if (aiPatrolMoving(pXSprite->aiState) && !reached) return; - else if (uwater) aiPatrolState(pSprite, kAiStatePatrolMoveW); - else if (crouch) aiPatrolState(pSprite, kAiStatePatrolMoveC); - else aiPatrolState(pSprite, kAiStatePatrolMoveL); + else if (uwater) aiPatrolState(actor, kAiStatePatrolMoveW); + else if (crouch) aiPatrolState(actor, kAiStatePatrolMoveC); + else aiPatrolState(actor, kAiStatePatrolMoveL); return; } diff --git a/source/games/blood/src/nnexts.h b/source/games/blood/src/nnexts.h index 9708ba92c..3b9645143 100644 --- a/source/games/blood/src/nnexts.h +++ b/source/games/blood/src/nnexts.h @@ -393,10 +393,10 @@ void aiPatrolThink(DBloodActor* actor); void aiPatrolStop(spritetype* pSprite, int target, bool alarm = false); void aiPatrolAlarmFull(spritetype* pSprite, XSPRITE* pXTarget, bool chain); void aiPatrolAlarmLite(spritetype* pSprite, XSPRITE* pXTarget); -void aiPatrolState(spritetype* pSprite, int state); +void aiPatrolState(DBloodActor* pSprite, int state); void aiPatrolMove(DBloodActor* actor); -int aiPatrolMarkerBusy(int nExcept, int nMarker); -bool aiPatrolMarkerReached(spritetype* pSprite, XSPRITE* pXSprite); +DBloodActor* aiPatrolMarkerBusy(DBloodActor* except, DBloodActor* marker); +bool aiPatrolMarkerReached(DBloodActor*); bool aiPatrolGetPathDir(XSPRITE* pXSprite, XSPRITE* pXMarker); void aiPatrolFlagsMgr(spritetype* pSource, XSPRITE* pXSource, spritetype* pDest, XSPRITE* pXDest, bool copy, bool init); void aiPatrolRandGoalAng(DBloodActor* actor);