diff --git a/source/games/blood/src/nnexts.cpp b/source/games/blood/src/nnexts.cpp index 8d3f336fa..01fec4979 100644 --- a/source/games/blood/src/nnexts.cpp +++ b/source/games/blood/src/nnexts.cpp @@ -4846,17 +4846,17 @@ DBloodActor* aiFightGetTargetInRange(DBloodActor* actor, int minDist, int maxDis BloodStatIterator it(kStatDude); while (auto targactor = it.Next()) { + if (!aiFightDudeCanSeeTarget(actor, pDudeInfo, targactor)) continue; auto pTarget = &targactor->s(); auto pXTarget = &targactor->x(); - if (!aiFightDudeCanSeeTarget(pXSprite, pDudeInfo, pTarget)) continue; int dist = aiFightGetTargetDist(pSprite, pDudeInfo, pTarget); if (dist < minDist || dist > maxDist) continue; else if (actor->GetTarget() == targactor) return targactor; else if (!targactor->IsDudeActor() || targactor == actor || targactor->IsPlayerActor()) continue; else if (IsBurningDude(pTarget) || !IsKillableDude(pTarget) || pTarget->owner == pSprite->index) continue; - else if ((teamMode == 1 && aiFightIsMateOf(pXSprite, pXTarget)) || aiFightMatesHaveSameTarget(pXSprite, pTarget, 1)) continue; + else if ((teamMode == 1 && aiFightIsMateOf(pXSprite, pXTarget)) || aiFightMatesHaveSameTarget(actor, targactor, 1)) continue; else if (data == 666 || pXTarget->data1 == data) { if (actor->GetTarget()) @@ -4879,15 +4879,11 @@ DBloodActor* aiFightGetTargetInRange(DBloodActor* actor, int minDist, int maxDis // //--------------------------------------------------------------------------- -spritetype* aiFightTargetIsPlayer(XSPRITE* pXSprite) +DBloodActor* aiFightTargetIsPlayer(DBloodActor* actor) { - - if (pXSprite->target_i >= 0) { - if (IsPlayerSprite(&sprite[pXSprite->target_i])) - return &sprite[pXSprite->target_i]; - } - - return NULL; + auto targ = actor->GetTarget(); + if (targ && targ->IsPlayerActor()) return targ; + return nullptr; } //--------------------------------------------------------------------------- @@ -4896,9 +4892,9 @@ spritetype* aiFightTargetIsPlayer(XSPRITE* pXSprite) // //--------------------------------------------------------------------------- -spritetype* aiFightGetMateTargets(XSPRITE* pXSprite) +DBloodActor* aiFightGetMateTargets(DBloodActor* actor) { - auto actor = &bloodActors[pXSprite->reference]; + auto pXSprite = &actor->x(); int rx = pXSprite->rxID; for (int i = bucketHead[rx]; i < bucketHead[rx + 1]; i++) @@ -4912,7 +4908,7 @@ spritetype* aiFightGetMateTargets(XSPRITE* pXSprite) if (mate->GetTarget()) { if (!mate->GetTarget()->IsPlayerActor()) - return &mate->GetTarget()->s(); + return mate->GetTarget(); } } } @@ -4925,20 +4921,21 @@ spritetype* aiFightGetMateTargets(XSPRITE* pXSprite) // //--------------------------------------------------------------------------- -bool aiFightMatesHaveSameTarget(XSPRITE* pXLeader, spritetype* pTarget, int allow) { - auto actor = &bloodActors[pXLeader->reference]; - int rx = pXLeader->rxID; spritetype* pMate = NULL; XSPRITE* pXMate = NULL; +bool aiFightMatesHaveSameTarget(DBloodActor* leaderactor, DBloodActor* targetactor, int allow) +{ + auto pXLeader = &leaderactor->x(); + int rx = pXLeader->rxID; for (int i = bucketHead[rx]; i < bucketHead[rx + 1]; i++) { if (rxBucket[i].type != OBJ_SPRITE) continue; - auto mate = rxBucket[i].GetActor(); - if (!mate || !mate->hasX() || mate == actor || !mate->IsDudeActor()) + auto mate = rxBucket[i].actor; + if (!mate || !mate->hasX() || mate == leaderactor || !mate->IsDudeActor()) continue; - if (&(mate->GetTarget()->s()) == pTarget && allow-- <= 0) + if (mate->GetTarget() == targetactor && allow-- <= 0) return true; } return false; @@ -4950,8 +4947,12 @@ bool aiFightMatesHaveSameTarget(XSPRITE* pXLeader, spritetype* pTarget, int allo // //--------------------------------------------------------------------------- -bool aiFightDudeCanSeeTarget(XSPRITE* pXDude, DUDEINFO* pDudeInfo, spritetype* pTarget) { - spritetype* pDude = &sprite[pXDude->reference]; +bool aiFightDudeCanSeeTarget(DBloodActor* dudeactor, DUDEINFO* pDudeInfo, DBloodActor* targetactor) +{ + auto pDude = &dudeactor->s(); + auto pXDude = &dudeactor->x(); + auto pTarget = &targetactor->s(); + int dx = pTarget->x - pDude->x; int dy = pTarget->y - pDude->y; // check target @@ -5000,17 +5001,15 @@ void aiFightActivateDudes(int rx) // //--------------------------------------------------------------------------- -void aiFightFreeTargets(int nSprite) { - int nTarget; - StatIterator it(kStatDude); - while ((nTarget = it.NextIndex()) >= 0) +void aiFightFreeTargets(DBloodActor* actor) +{ + BloodStatIterator it(kStatDude); + while (auto targetactor = it.Next()) { - if (!IsDudeSprite(&sprite[nTarget]) || sprite[nTarget].extra < 0) continue; - else if (xsprite[sprite[nTarget].extra].target_i == nSprite) - aiSetTarget_(&xsprite[sprite[nTarget].extra], sprite[nTarget].x, sprite[nTarget].y, sprite[nTarget].z); + if (!targetactor->IsDudeActor() || !targetactor->hasX()) continue; + else if (targetactor->GetTarget() == actor) + aiSetTarget(targetactor, targetactor->s().x, targetactor->s().y, targetactor->s().z); } - - return; } //--------------------------------------------------------------------------- @@ -5019,14 +5018,14 @@ void aiFightFreeTargets(int nSprite) { // //--------------------------------------------------------------------------- -void aiFightFreeAllTargets(XSPRITE* pXSource) { - if (pXSource->txID <= 0) return; - for (int i = bucketHead[pXSource->txID]; i < bucketHead[pXSource->txID + 1]; i++) - { - if (rxBucket[i].type != OBJ_SPRITE) continue; - auto rxactor = rxBucket[i].GetActor(); - if (rxactor && rxactor->hasX()) - aiFightFreeTargets(rxactor->s().index); +void aiFightFreeAllTargets(DBloodActor* sourceactor) +{ + auto txID = sourceactor->x().txID; + if (txID <= 0) return; + for (int i = bucketHead[txID]; i < bucketHead[txID + 1]; i++) + { + if (rxBucket[i].type == OBJ_SPRITE && rxBucket[i].actor && rxBucket[i].actor->hasX()) + aiFightFreeTargets(rxBucket[i].actor); } } @@ -5089,7 +5088,7 @@ void aiFightAlarmDudesInSight(spritetype* pSprite, int max) { if (pDude->index == pSprite->index || !IsDudeSprite(pDude) || pDude->extra < 0) continue; pXDude = &xsprite[pDude->extra]; - if (aiFightDudeCanSeeTarget(pXSprite, pDudeInfo, pDude)) { + if (aiFightDudeCanSeeTarget(&bloodActors[pXSprite->reference], pDudeInfo, &bloodActors[nSprite])) { if (pXDude->target_i != -1 || pXDude->rxID > 0) continue; @@ -5557,7 +5556,7 @@ bool modernTypeOperateSprite(int nSprite, spritetype* pSprite, XSPRITE* pXSprite [[fallthrough]]; case kCmdRepeat: if (pXSprite->txID <= 0 || !aiFightGetDudesForBattle(pXSprite)) { - aiFightFreeAllTargets(pXSprite); + aiFightFreeAllTargets(actor); evPostActor(actor, 0, kCmdOff); break; } else { @@ -6449,7 +6448,7 @@ void useTargetChanger(XSPRITE* pXSource, spritetype* pSprite) { // make current target and all other dudes not attack this dude anymore case kThingBloodBits: case kThingBloodChunks: - aiFightFreeTargets(pSprite->index); + aiFightFreeTargets(&bloodActors[pSprite->index]); return; default: return; @@ -6484,9 +6483,11 @@ void useTargetChanger(XSPRITE* pXSource, spritetype* pSprite) { } } - spritetype* pPlayer = aiFightTargetIsPlayer(pXSprite); + auto playeractor = aiFightTargetIsPlayer(actor); // special handling for player(s) if target changer data4 > 2. - if (pPlayer != NULL) { + if (playeractor != nullptr) + { + auto pPlayer = &playeractor->s(); auto actLeech = leechIsDropped(actor); if (pXSource->data4 == 3) { aiSetTarget_(pXSprite, pSprite->x, pSprite->y, pSprite->z); @@ -6501,7 +6502,7 @@ void useTargetChanger(XSPRITE* pXSource, spritetype* pSprite) { } int maxAlarmDudes = 8 + Random(8); - if (pXSprite->target_i > -1 && sprite[pXSprite->target_i].extra > -1 && pPlayer == NULL) { + if (pXSprite->target_i > -1 && sprite[pXSprite->target_i].extra > -1 && playeractor == nullptr) { pTarget = &sprite[pXSprite->target_i]; pXTarget = &xsprite[pTarget->extra]; if (aiFightUnitCanFly(pSprite) && aiFightIsMeleeUnit(pTarget) && !aiFightUnitCanFly(pTarget)) @@ -6509,7 +6510,7 @@ void useTargetChanger(XSPRITE* pXSource, spritetype* pSprite) { else if (aiFightUnitCanFly(pSprite)) pSprite->flags &= ~0x0002; - if (!IsDudeSprite(pTarget) || pXTarget->health < 1 || !aiFightDudeCanSeeTarget(pXSprite, pDudeInfo, pTarget)) { + if (!IsDudeSprite(pTarget) || pXTarget->health < 1 || !aiFightDudeCanSeeTarget(actor, pDudeInfo, &bloodActors[pTarget->index])) { aiSetTarget_(pXSprite, pSprite->x, pSprite->y, pSprite->z); } // dude attack or attacked by target that does not fit by data id? @@ -6566,7 +6567,8 @@ void useTargetChanger(XSPRITE* pXSource, spritetype* pSprite) { } // check if targets aims player then force this target to fight with dude - else if (aiFightTargetIsPlayer(pXTarget) != NULL) { + else if (aiFightTargetIsPlayer(actor) != nullptr) + { aiSetTarget_(pXTarget, pSprite->index); } @@ -6608,7 +6610,7 @@ void useTargetChanger(XSPRITE* pXSource, spritetype* pSprite) { } } - if ((pXSprite->target_i < 0 || pPlayer != NULL) && (PlayClock & 32) != 0) { + if ((pXSprite->target_i < 0 || playeractor != nullptr) && (PlayClock & 32) != 0) { // try find first target that dude can see int nSprite; StatIterator it(kStatDude); @@ -6624,14 +6626,15 @@ void useTargetChanger(XSPRITE* pXSource, spritetype* pSprite) { // skip non-dudes and players if (!IsDudeSprite(pTarget) || (IsPlayerSprite(pTarget) && pXSource->data4 > 0) || pTarget->owner == pSprite->index) continue; // avoid self aiming, those who dude can't see, and those who dude own - else if (!aiFightDudeCanSeeTarget(pXSprite, pDudeInfo, pTarget) || pSprite->index == pTarget->index) continue; + else if (!aiFightDudeCanSeeTarget(actor, pDudeInfo, &bloodActors[pTarget->index]) || pSprite->index == pTarget->index) continue; // if Target Changer have data1 = 666, everyone can be target, except AI team mates. else if (pXSource->data1 != 666 && pXSource->data1 != pXTarget->data1) continue; // don't attack immortal, burning dudes and mates if (IsBurningDude(pTarget) || !IsKillableDude(pTarget) || (pXSource->data2 == 1 && aiFightIsMateOf(pXSprite, pXTarget))) continue; - if (pXSource->data2 == 0 || (pXSource->data2 == 1 && !aiFightMatesHaveSameTarget(pXSprite, pTarget, matesPerEnemy))) { + if (pXSource->data2 == 0 || (pXSource->data2 == 1 && !aiFightMatesHaveSameTarget(&bloodActors[pXSprite->reference], &bloodActors[pTarget->index], matesPerEnemy))) + { // Change target for dude aiSetTarget_(pXSprite, pTarget->index); @@ -6641,7 +6644,7 @@ void useTargetChanger(XSPRITE* pXSource, spritetype* pSprite) { // ...and change target of target to dude to force it fight if (pXSource->data3 > 0 && pXTarget->target_i != pSprite->index) { aiSetTarget_(pXTarget, pSprite->index); - if (pPlayer == NULL && !isActive(pTarget->index)) + if (playeractor == NULL && !isActive(pTarget->index)) aiActivateDude(&bloodActors[pXTarget->reference]); if (pXSource->data3 == 2) @@ -6656,11 +6659,13 @@ void useTargetChanger(XSPRITE* pXSource, spritetype* pSprite) { } // got no target - let's ask mates if they have targets - if ((pXSprite->target_i < 0 || pPlayer != NULL) && pXSource->data2 == 1 && (PlayClock & 64) != 0) { - spritetype* pMateTarget = NULL; - if ((pMateTarget = aiFightGetMateTargets(pXSprite)) != NULL && pMateTarget->extra > 0) { - XSPRITE* pXMateTarget = &xsprite[pMateTarget->extra]; - if (aiFightDudeCanSeeTarget(pXSprite, pDudeInfo, pMateTarget)) { + if ((pXSprite->target_i < 0 || playeractor != NULL) && pXSource->data2 == 1 && (PlayClock & 64) != 0) { + DBloodActor* pMateTargetActor = aiFightGetMateTargets(actor); + if (pMateTargetActor != nullptr && pMateTargetActor->hasX()) + { + auto pMateTarget = &pMateTargetActor->s(); + XSPRITE* pXMateTarget = &pMateTargetActor->x(); + if (aiFightDudeCanSeeTarget(actor, pDudeInfo, pMateTargetActor)) { if (pXMateTarget->target_i < 0) { aiSetTarget_(pXMateTarget, pSprite->index); if (IsDudeSprite(pMateTarget) && !isActive(pMateTarget->index)) @@ -6673,7 +6678,7 @@ void useTargetChanger(XSPRITE* pXSource, spritetype* pSprite) { return; // try walk in mate direction in case if not see the target - } else if (pXMateTarget->target_i >= 0 && aiFightDudeCanSeeTarget(pXSprite, pDudeInfo, &sprite[pXMateTarget->target_i])) { + } else if (pXMateTarget->target_i >= 0 && aiFightDudeCanSeeTarget(actor, pDudeInfo, &bloodActors[pXMateTarget->target_i])) { spritetype* pMate = &sprite[pXMateTarget->target_i]; pXSprite->target_i = pMateTarget->index; pXSprite->targetX = pMate->x; diff --git a/source/games/blood/src/nnexts.h b/source/games/blood/src/nnexts.h index e52c4e784..0dce37148 100644 --- a/source/games/blood/src/nnexts.h +++ b/source/games/blood/src/nnexts.h @@ -314,20 +314,15 @@ void aiSetGenIdleState(DBloodActor*); // ------------------------------------------------------------------------- // int aiFightGetTargetDist(spritetype* pSprite, DUDEINFO* pDudeInfo, spritetype* pTarget); int aiFightGetFineTargetDist(spritetype* pSprite, spritetype* pTarget); -bool aiFightDudeCanSeeTarget(XSPRITE* pXDude, DUDEINFO* pDudeInfo, spritetype* pTarget); +bool aiFightDudeCanSeeTarget(DBloodActor* pXDude, DUDEINFO* pDudeInfo, DBloodActor* pTarget); bool aiFightUnitCanFly(spritetype* pDude); bool aiFightIsMeleeUnit(spritetype* pDude); bool aiFightDudeIsAffected(XSPRITE* pXDude); -bool aiFightMatesHaveSameTarget(XSPRITE* pXLeader, spritetype* pTarget, int allow); +bool aiFightMatesHaveSameTarget(DBloodActor* leaderactor, DBloodActor* targetactor, int allow); bool aiFightGetDudesForBattle(XSPRITE* pXSprite); bool aiFightIsMateOf(XSPRITE* pXDude, XSPRITE* pXSprite); void aiFightAlarmDudesInSight(spritetype* pSprite, int max); void aiFightActivateDudes(int rx); -void aiFightFreeTargets(int nSprite); -void aiFightFreeAllTargets(XSPRITE* pXSource); -spritetype* aiFightGetTargetInRange(spritetype* pSprite, int minDist, int maxDist, short data, short teamMode); -spritetype* aiFightTargetIsPlayer(XSPRITE* pXSprite); -spritetype* aiFightGetMateTargets(XSPRITE* pXSprite); // ------------------------------------------------------------------------- // void useSlopeChanger(XSPRITE* pXSource, int objType, int objIndex); void damageSprites(DBloodActor* pXSource, DBloodActor* pSprite);