diff --git a/lib/BattleState.cpp b/lib/BattleState.cpp index 553b806c9..13e29841e 100644 --- a/lib/BattleState.cpp +++ b/lib/BattleState.cpp @@ -1139,9 +1139,24 @@ std::string CStack::getName() const return (count > 1) ? type->namePl : type->nameSing; //War machines can't use base } -bool CStack::isValidTarget(bool allowDead/* = false*/) const /*alive non-turret stacks (can be attacked or be object of magic effect) */ +bool CStack::isValidTarget(bool allowDead/* = false*/) const { - return !isGhost() && (alive() || allowDead) && position.isValid(); + return (alive() || (allowDead && isDead())) && position.isValid() && !isTurret(); +} + +bool CStack::isDead() const +{ + return !alive() && !isGhost(); +} + +bool CStack::isGhost() const +{ + return vstd::contains(state,EBattleStackState::GHOST); +} + +bool CStack::isTurret() const +{ + return type->idNumber == CreatureID::ARROW_TOWERS; } bool CStack::canBeHealed() const diff --git a/lib/BattleState.h b/lib/BattleState.h index 66e8580ac..a30bde3ff 100644 --- a/lib/BattleState.h +++ b/lib/BattleState.h @@ -289,11 +289,11 @@ public: { return vstd::contains(state,EBattleStackState::ALIVE); } - bool isGhost() const //determines if stack was removed - { - return vstd::contains(state,EBattleStackState::GHOST); - } - bool isValidTarget(bool allowDead = false) const; //alive non-turret stacks (can be attacked or be object of magic effect) + + bool isDead() const; + bool isGhost() const; //determines if stack was removed + bool isValidTarget(bool allowDead = false) const; //non-turret non-ghost stacks (can be attacked or be object of magic effect) + bool isTurret() const; }; class DLL_LINKAGE CMP_stack diff --git a/lib/CBattleCallback.cpp b/lib/CBattleCallback.cpp index 1f5d482b2..bfcdfabd9 100644 --- a/lib/CBattleCallback.cpp +++ b/lib/CBattleCallback.cpp @@ -180,33 +180,33 @@ bool CBattleInfoEssentials::battleHasNativeStack(ui8 side) const TStacks CBattleInfoEssentials::battleGetAllStacks(bool includeTurrets /*= false*/) const { - return battleGetStacksIf([](const CStack * s){return true;},includeTurrets); + return battleGetStacksIf([=](const CStack * s) + { + return !s->isGhost() && (includeTurrets || !s->isTurret()); + }); } -TStacks CBattleInfoEssentials::battleGetStacksIf(TStackFilter predicate, bool includeTurrets /*= false*/) const +TStacks CBattleInfoEssentials::battleGetStacksIf(TStackFilter predicate) const { TStacks ret; RETURN_IF_NOT_BATTLE(ret); - vstd::copy_if(getBattle()->stacks, std::back_inserter(ret), [=](const CStack * s){ - return predicate(s) && (!s->isGhost()) && (includeTurrets || !(s->type->idNumber == CreatureID::ARROW_TOWERS)); - }); + vstd::copy_if(getBattle()->stacks, std::back_inserter(ret), predicate); return ret; } - TStacks CBattleInfoEssentials::battleAliveStacks() const { return battleGetStacksIf([](const CStack * s){ - return s->alive(); + return s->isValidTarget(false); }); } TStacks CBattleInfoEssentials::battleAliveStacks(ui8 side) const { return battleGetStacksIf([=](const CStack * s){ - return s->alive() && s->attackerOwned == !side; + return s->isValidTarget(false) && s->attackerOwned == !side; }); } @@ -1304,8 +1304,8 @@ std::pair CBattleInfoCallback::getNearestStack(const std::vector possibleStacks = battleGetStacksIf([=](const CStack * s) { - return s != closest && s->alive() && (boost::logic::indeterminate(attackerOwned) || s->attackerOwned == attackerOwned); - }, false); + return s->isValidTarget(false) && s != closest && (boost::logic::indeterminate(attackerOwned) || s->attackerOwned == attackerOwned); + }); for(const CStack * st : possibleStacks) for(BattleHex hex : avHexes) @@ -2225,8 +2225,8 @@ TStacks CPlayerBattleCallback::battleGetStacks(EStackOwnership whose /*= MINE_AN const bool ownerMatches = (whose == MINE_AND_ENEMY) || (whose == ONLY_MINE && s->owner == player) || (whose == ONLY_ENEMY && s->owner != player); - const bool alivenessMatches = s->alive() || !onlyAlive; - return ownerMatches && alivenessMatches; + + return ownerMatches && s->isValidTarget(!onlyAlive); }); } diff --git a/lib/CBattleCallback.h b/lib/CBattleCallback.h index 289efa7e7..fdf7be1df 100644 --- a/lib/CBattleCallback.h +++ b/lib/CBattleCallback.h @@ -56,7 +56,7 @@ protected: CCallbackBase() : battle(nullptr), gs(nullptr) {} - + void setBattle(const BattleInfo *B); bool duringBattle() const; @@ -83,8 +83,8 @@ namespace EAccessibility { enum EAccessibility { - ACCESSIBLE, - ALIVE_STACK, + ACCESSIBLE, + ALIVE_STACK, OBSTACLE, DESTRUCTIBLE_WALL, GATE, //sieges -> gate opens only for defender stacks @@ -125,7 +125,7 @@ struct DLL_LINKAGE ReachabilityInfo struct DLL_LINKAGE Parameters { const CStack *stack; //stack for which calculation is mage => not required (kept for debugging mostly), following variables are enough - + bool attackerOwned; bool doubleWide; bool flying; @@ -171,15 +171,15 @@ public: ETerrainType battleTerrainType() const; BFieldType battleGetBattlefieldType() const; std::vector > battleGetAllObstacles(boost::optional perspective = boost::none) const; //returns all obstacles on the battlefield - + /** @brief Main method for getting battle stacks * * @param predicate Functor that shall return true for desired stack * @return filtered stacks * - */ - TStacks battleGetStacksIf(TStackFilter predicate, bool includeTurrets = false) const; - + */ + TStacks battleGetStacksIf(TStackFilter predicate) const; + bool battleHasNativeStack(ui8 side) const; int battleGetMoatDmg() const; //what dmg unit will suffer if ending turn in the moat const CGTownInstance * battleGetDefendedTown() const; //returns defended town if current battle is a siege, nullptr instead @@ -193,7 +193,7 @@ public: bool battleHasHero(ui8 side) const; int battleCastSpells(ui8 side) const; //how many spells has given side cast const CGHeroInstance * battleGetFightingHero(ui8 side) const; //depracated for players callback, easy to get wrong - const CArmedInstance * battleGetArmyObject(ui8 side) const; + const CArmedInstance * battleGetArmyObject(ui8 side) const; InfoAboutHero battleGetHeroInfo(ui8 side) const; // for determining state of a part of the wall; format: parameter [0] - keep, [1] - bottom tower, [2] - bottom wall, @@ -204,7 +204,7 @@ public: //helpers ///returns all stacks, alive or dead or undead or mechanical :) TStacks battleGetAllStacks(bool includeTurrets = false) const; - + ///returns all alive stacks excluding turrets TStacks battleAliveStacks() const; ///returns all alive stacks from particular side excluding turrets @@ -255,12 +255,12 @@ public: int battleGetSurrenderCost(PlayerColor Player) const; //returns cost of surrendering battle, -1 if surrendering is not possible ReachabilityInfo::TDistances battleGetDistances(const CStack * stack, BattleHex hex = BattleHex::INVALID, BattleHex * predecessors = nullptr) const; //returns vector of distances to [dest hex number] std::set battleGetAttackedHexes(const CStack* attacker, BattleHex destinationTile, BattleHex attackerPos = BattleHex::INVALID) const; - + bool battleCanAttack(const CStack * stack, const CStack * target, BattleHex dest) const; //determines if stack with given ID can attack target at the selected destination bool battleCanShoot(const CStack * stack, BattleHex dest) const; //determines if stack with given ID shoot at the selected destination bool battleIsStackBlocked(const CStack * stack) const; //returns true if there is neighboring enemy stack std::set batteAdjacentCreatures (const CStack * stack) const; - + TDmgRange calculateDmgRange(const BattleAttackInfo &info) const; //charge - number of hexes travelled before attack (for champion's jousting); returns pair TDmgRange calculateDmgRange(const CStack* attacker, const CStack* defender, TQuantity attackerCount, bool shooting, ui8 charge, bool lucky, bool unlucky, bool deathBlow, bool ballistaDoubleDmg) const; //charge - number of hexes travelled before attack (for champion's jousting); returns pair TDmgRange calculateDmgRange(const CStack* attacker, const CStack* defender, bool shooting, ui8 charge, bool lucky, bool unlucky, bool deathBlow, bool ballistaDoubleDmg) const; //charge - number of hexes travelled before attack (for champion's jousting); returns pair @@ -278,7 +278,7 @@ public: bool isWallPartPotentiallyAttackable(EWallPart::EWallPart wallPart) const; // returns true if the wall part is potentially attackable (independent of wall state), false if not std::vector getAttackableBattleHexes() const; - //*** MAGIC + //*** MAGIC si8 battleMaxSpellLevel(ui8 side) const; //calculates minimum spell level possible to be cast on battlefield - takes into account artifacts of both heroes; if no effects are set, 0 is returned ui32 battleGetSpellCost(const CSpell * sp, const CGHeroInstance * caster) const; //returns cost of given spell ESpellCastProblem::ESpellCastProblem battleCanCastSpell(PlayerColor player, ECastingMode::ECastingMode mode) const; //returns true if there are no general issues preventing from casting a spell diff --git a/lib/spells/CDefaultSpellMechanics.cpp b/lib/spells/CDefaultSpellMechanics.cpp index c9a788f88..d0906623a 100644 --- a/lib/spells/CDefaultSpellMechanics.cpp +++ b/lib/spells/CDefaultSpellMechanics.cpp @@ -360,9 +360,8 @@ void DefaultSpellMechanics::battleCast(const SpellCastEnvironment * env, BattleS TStacks mirrorTargets = parameters.cb->battleGetStacksIf([this, parameters](const CStack * battleStack) { //Get all enemy stacks. Magic mirror can reflect to immune creature (with no effect) - return battleStack->owner == parameters.casterColor; - }, - true);//turrets included + return battleStack->owner == parameters.casterColor && battleStack->isValidTarget(false); + }); if(!mirrorTargets.empty()) { @@ -711,7 +710,6 @@ std::set DefaultSpellMechanics::getAffectedStacks(SpellTargeting //for massive spells add all targets for (auto stack : stacks) attackedCres.insert(stack); - } else { diff --git a/lib/spells/CSpellHandler.cpp b/lib/spells/CSpellHandler.cpp index dbfc28262..22a2d38c3 100644 --- a/lib/spells/CSpellHandler.cpp +++ b/lib/spells/CSpellHandler.cpp @@ -309,8 +309,9 @@ void CSpell::getEffects(std::vector & lst, const int level) const ESpellCastProblem::ESpellCastProblem CSpell::isImmuneAt(const CBattleInfoCallback * cb, const ISpellCaster * caster, ECastingMode::ECastingMode mode, BattleHex destination) const { // Get all stacks at destination hex. only alive if not rising spell - TStacks stacks = cb->battleGetStacksIf([=](const CStack * s){ - return s->coversPos(destination) && (isRisingSpell() || s->alive()); + TStacks stacks = cb->battleGetStacksIf([=](const CStack * s) + { + return s->coversPos(destination) && s->isValidTarget(isRisingSpell()); }); if(!stacks.empty()) diff --git a/server/CGameHandler.cpp b/server/CGameHandler.cpp index b95071d28..660cedabd 100644 --- a/server/CGameHandler.cpp +++ b/server/CGameHandler.cpp @@ -5703,8 +5703,9 @@ void CGameHandler::runBattle() if(next->getCreature()->idNumber == CreatureID::FIRST_AID_TENT) { - TStacks possibleStacks = battleGetStacksIf([&](const CStack * s){ - return s->owner == next->owner && s->canBeHealed(); + TStacks possibleStacks = battleGetStacksIf([=](const CStack * s) + { + return s->owner == next->owner && s->canBeHealed(); }); if(!possibleStacks.size())