mirror of
https://github.com/vcmi/vcmi.git
synced 2025-11-27 22:49:25 +02:00
Merge pull request #197 from vcmi/issue/2304_2418
Issues/2304/2418/2293
This commit is contained in:
@@ -1018,9 +1018,8 @@ void CBattleInterface::stackRemoved(int stackID)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
delete creAnims[stackID];
|
//todo: ensure that ghost stack animation has fadeout effect
|
||||||
creAnims.erase(stackID);
|
|
||||||
creDir.erase(stackID);
|
|
||||||
redrawBackgroundWithHexes(activeStack);
|
redrawBackgroundWithHexes(activeStack);
|
||||||
queue->update();
|
queue->update();
|
||||||
}
|
}
|
||||||
@@ -1071,9 +1070,6 @@ void CBattleInterface::stacksAreAttacked(std::vector<StackAttackedInfo> attacked
|
|||||||
stackRemoved(attackedInfo.defender->ID);
|
stackRemoved(attackedInfo.defender->ID);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* if (attackedInfos.front().cloneKilled) //FIXME: cloned stack is already removed
|
|
||||||
return;*/
|
|
||||||
|
|
||||||
if (targets > 1)
|
if (targets > 1)
|
||||||
printConsoleAttacked(attackedInfos.front().defender, damage, killed, attackedInfos.front().attacker, true); //creatures perish
|
printConsoleAttacked(attackedInfos.front().defender, damage, killed, attackedInfos.front().attacker, true); //creatures perish
|
||||||
else
|
else
|
||||||
@@ -2169,14 +2165,14 @@ void CBattleInterface::handleHex(BattleHex myNumber, int eventType)
|
|||||||
case RISE_DEMONS:
|
case RISE_DEMONS:
|
||||||
if (shere && ourStack && !shere->alive())
|
if (shere && ourStack && !shere->alive())
|
||||||
{
|
{
|
||||||
if(!(shere->hasBonusOfType(Bonus::UNDEAD)
|
if(!(shere->hasBonusOfType(Bonus::UNDEAD)
|
||||||
|| shere->hasBonusOfType(Bonus::NON_LIVING)
|
|| shere->hasBonusOfType(Bonus::NON_LIVING)
|
||||||
|| vstd::contains(shere->state, EBattleStackState::SUMMONED)
|
|| vstd::contains(shere->state, EBattleStackState::SUMMONED)
|
||||||
|| vstd::contains(shere->state, EBattleStackState::CLONED)
|
|| vstd::contains(shere->state, EBattleStackState::CLONED)
|
||||||
|| shere->hasBonusOfType(Bonus::SIEGE_WEAPON)
|
|| shere->hasBonusOfType(Bonus::SIEGE_WEAPON)
|
||||||
))
|
))
|
||||||
legalAction = true;
|
legalAction = true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (legalAction)
|
if (legalAction)
|
||||||
@@ -2334,8 +2330,8 @@ void CBattleInterface::handleHex(BattleHex myNumber, int eventType)
|
|||||||
case RISE_DEMONS:
|
case RISE_DEMONS:
|
||||||
cursorType = ECursor::SPELLBOOK;
|
cursorType = ECursor::SPELLBOOK;
|
||||||
realizeAction = [=]
|
realizeAction = [=]
|
||||||
{
|
{
|
||||||
giveCommand(Battle::DAEMON_SUMMONING, myNumber, activeStack->ID);
|
giveCommand(Battle::DAEMON_SUMMONING, myNumber, activeStack->ID);
|
||||||
};
|
};
|
||||||
break;
|
break;
|
||||||
case CATAPULT:
|
case CATAPULT:
|
||||||
@@ -3411,8 +3407,13 @@ BattleObjectsByHex CBattleInterface::sortObjectsByHex()
|
|||||||
|
|
||||||
BattleObjectsByHex sorted;
|
BattleObjectsByHex sorted;
|
||||||
|
|
||||||
|
auto stacks = curInt->cb->battleGetStacksIf([](const CStack * s)
|
||||||
|
{
|
||||||
|
return !s->isTurret();
|
||||||
|
});
|
||||||
|
|
||||||
// Sort creatures
|
// Sort creatures
|
||||||
for (auto & stack : curInt->cb->battleGetAllStacks())
|
for (auto & stack : stacks)
|
||||||
{
|
{
|
||||||
if(creAnims.find(stack->ID) == creAnims.end()) //e.g. for summoned but not yet handled stacks
|
if(creAnims.find(stack->ID) == creAnims.end()) //e.g. for summoned but not yet handled stacks
|
||||||
continue;
|
continue;
|
||||||
@@ -3420,7 +3421,10 @@ BattleObjectsByHex CBattleInterface::sortObjectsByHex()
|
|||||||
if (stack->position < 0) // turret shooters are handled separately
|
if (stack->position < 0) // turret shooters are handled separately
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if(!creAnims[stack->ID]->isDead())
|
//FIXME: hack to ignore ghost stacks
|
||||||
|
if((creAnims[stack->ID]->getType() == CCreatureAnim::DEAD || creAnims[stack->ID]->getType() == CCreatureAnim::HOLDING) && stack->isGhost())
|
||||||
|
;//ignore
|
||||||
|
else if(!creAnims[stack->ID]->isDead())
|
||||||
{
|
{
|
||||||
if (!creAnims[stack->ID]->isMoving())
|
if (!creAnims[stack->ID]->isMoving())
|
||||||
sorted.hex[stack->position].alive.push_back(stack);
|
sorted.hex[stack->position].alive.push_back(stack);
|
||||||
|
|||||||
@@ -647,16 +647,18 @@ void CSpellWindow::SpellArea::clickLeft(tribool down, bool previousState)
|
|||||||
break;
|
break;
|
||||||
case ESpellCastProblem::ANOTHER_ELEMENTAL_SUMMONED:
|
case ESpellCastProblem::ANOTHER_ELEMENTAL_SUMMONED:
|
||||||
{
|
{
|
||||||
std::string text = CGI->generaltexth->allTexts[538], summoner, elemental, caster;
|
std::string text = CGI->generaltexth->allTexts[538], elemental, caster;
|
||||||
std::vector<const CStack *> stacks = owner->myInt->cb->battleGetStacks();
|
const PlayerColor player = owner->myInt->playerID;
|
||||||
|
|
||||||
|
const TStacks stacks = owner->myInt->cb->battleGetStacksIf([player](const CStack * s)
|
||||||
|
{
|
||||||
|
return s->owner == player
|
||||||
|
&& vstd::contains(s->state, EBattleStackState::SUMMONED)
|
||||||
|
&& !vstd::contains(s->state, EBattleStackState::CLONED);
|
||||||
|
});
|
||||||
for(const CStack * s : stacks)
|
for(const CStack * s : stacks)
|
||||||
{
|
{
|
||||||
if(vstd::contains(s->state, EBattleStackState::SUMMONED))
|
elemental = s->getCreature()->namePl;
|
||||||
{
|
|
||||||
elemental = s->getCreature()->namePl;
|
|
||||||
summoner = owner->myInt->cb->battleGetHeroInfo(!s->attackerOwned).name;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (owner->myHero->type->sex)
|
if (owner->myHero->type->sex)
|
||||||
{ //female
|
{ //female
|
||||||
@@ -666,8 +668,9 @@ void CSpellWindow::SpellArea::clickLeft(tribool down, bool previousState)
|
|||||||
{ //male
|
{ //male
|
||||||
caster = CGI->generaltexth->allTexts[539];
|
caster = CGI->generaltexth->allTexts[539];
|
||||||
}
|
}
|
||||||
text = boost::str(boost::format(text) % summoner % elemental % caster);
|
std::string summoner = owner->myHero->name;
|
||||||
|
|
||||||
|
text = boost::str(boost::format(text) % summoner % elemental % caster);
|
||||||
|
|
||||||
owner->myInt->showInfoDialog(text);
|
owner->myInt->showInfoDialog(text);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -142,26 +142,6 @@ CStack * BattleInfo::generateNewStack(const CStackBasicDescriptor &base, bool at
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
const CStack * BattleInfo::battleGetStack(BattleHex pos, bool onlyAlive)
|
|
||||||
{
|
|
||||||
CStack * stack = nullptr;
|
|
||||||
for(auto & elem : stacks)
|
|
||||||
{
|
|
||||||
if(elem->position == pos
|
|
||||||
|| (elem->doubleWide()
|
|
||||||
&&( (elem->attackerOwned && elem->position-1 == pos)
|
|
||||||
|| (!elem->attackerOwned && elem->position+1 == pos) )
|
|
||||||
) )
|
|
||||||
{
|
|
||||||
if (elem->alive())
|
|
||||||
return elem; //we prefer living stacks - there can be only one stack on the tile, so return it immediately
|
|
||||||
else if (!onlyAlive)
|
|
||||||
stack = elem; //dead stacks are only accessible when there's no alive stack on this tile
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return stack;
|
|
||||||
}
|
|
||||||
|
|
||||||
const CGHeroInstance * BattleInfo::battleGetOwner(const CStack * stack) const
|
const CGHeroInstance * BattleInfo::battleGetOwner(const CStack * stack) const
|
||||||
{
|
{
|
||||||
return sides[!stack->attackerOwned].hero;
|
return sides[!stack->attackerOwned].hero;
|
||||||
@@ -741,11 +721,6 @@ CStack * BattleInfo::getStack(int stackID, bool onlyAlive /*= true*/)
|
|||||||
return const_cast<CStack *>(battleGetStackByID(stackID, onlyAlive));
|
return const_cast<CStack *>(battleGetStackByID(stackID, onlyAlive));
|
||||||
}
|
}
|
||||||
|
|
||||||
CStack * BattleInfo::getStackT(BattleHex tileID, bool onlyAlive /*= true*/)
|
|
||||||
{
|
|
||||||
return const_cast<CStack *>(battleGetStackByPos(tileID, onlyAlive));
|
|
||||||
}
|
|
||||||
|
|
||||||
BattleInfo::BattleInfo()
|
BattleInfo::BattleInfo()
|
||||||
{
|
{
|
||||||
setBattle(this);
|
setBattle(this);
|
||||||
@@ -1159,9 +1134,24 @@ std::string CStack::getName() const
|
|||||||
return (count > 1) ? type->namePl : type->nameSing; //War machines can't use base
|
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 (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
|
bool CStack::canBeHealed() const
|
||||||
@@ -1171,6 +1161,12 @@ bool CStack::canBeHealed() const
|
|||||||
&& !hasBonusOfType(Bonus::SIEGE_WEAPON);
|
&& !hasBonusOfType(Bonus::SIEGE_WEAPON);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CStack::makeGhost()
|
||||||
|
{
|
||||||
|
state.erase(EBattleStackState::ALIVE);
|
||||||
|
state.insert(EBattleStackState::GHOST_PENDING);
|
||||||
|
}
|
||||||
|
|
||||||
ui32 CStack::calculateHealedHealthPoints(ui32 toHeal, const bool resurrect) const
|
ui32 CStack::calculateHealedHealthPoints(ui32 toHeal, const bool resurrect) const
|
||||||
{
|
{
|
||||||
if(!resurrect && !alive())
|
if(!resurrect && !alive())
|
||||||
|
|||||||
@@ -107,12 +107,11 @@ struct DLL_LINKAGE BattleInfo : public CBonusSystemNode, public CBattleInfoCallb
|
|||||||
~BattleInfo(){};
|
~BattleInfo(){};
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
CStack * getStackT(BattleHex tileID, bool onlyAlive = true);
|
|
||||||
CStack * getStack(int stackID, bool onlyAlive = true);
|
CStack * getStack(int stackID, bool onlyAlive = true);
|
||||||
using CBattleInfoEssentials::battleGetArmyObject;
|
using CBattleInfoEssentials::battleGetArmyObject;
|
||||||
CArmedInstance * battleGetArmyObject(ui8 side) const;
|
CArmedInstance * battleGetArmyObject(ui8 side) const;
|
||||||
using CBattleInfoEssentials::battleGetFightingHero;
|
using CBattleInfoEssentials::battleGetFightingHero;
|
||||||
CGHeroInstance * battleGetFightingHero(ui8 side) const;
|
CGHeroInstance * battleGetFightingHero(ui8 side) const;
|
||||||
|
|
||||||
const CStack * getNextStack() const; //which stack will have turn after current one
|
const CStack * getNextStack() const; //which stack will have turn after current one
|
||||||
//void getStackQueue(std::vector<const CStack *> &out, int howMany, int turn = 0, int lastMoved = -1) const; //returns stack in order of their movement action
|
//void getStackQueue(std::vector<const CStack *> &out, int howMany, int turn = 0, int lastMoved = -1) const; //returns stack in order of their movement action
|
||||||
@@ -142,7 +141,6 @@ struct DLL_LINKAGE BattleInfo : public CBonusSystemNode, public CBattleInfoCallb
|
|||||||
|
|
||||||
const CGHeroInstance * getHero(PlayerColor player) const; //returns fighting hero that belongs to given player
|
const CGHeroInstance * getHero(PlayerColor player) const; //returns fighting hero that belongs to given player
|
||||||
|
|
||||||
const CStack * battleGetStack(BattleHex pos, bool onlyAlive); //returns stack at given tile
|
|
||||||
const CGHeroInstance * battleGetOwner(const CStack * stack) const; //returns hero that owns given stack; nullptr if none
|
const CGHeroInstance * battleGetOwner(const CStack * stack) const; //returns hero that owns given stack; nullptr if none
|
||||||
void localInit();
|
void localInit();
|
||||||
|
|
||||||
@@ -247,7 +245,10 @@ public:
|
|||||||
int getEffectValue(const CSpell * spell) const override;
|
int getEffectValue(const CSpell * spell) const override;
|
||||||
|
|
||||||
const PlayerColor getOwner() const override;
|
const PlayerColor getOwner() const override;
|
||||||
|
|
||||||
|
///stack will be ghost in next battle state update
|
||||||
|
void makeGhost();
|
||||||
|
|
||||||
template <typename Handler> void serialize(Handler &h, const int version)
|
template <typename Handler> void serialize(Handler &h, const int version)
|
||||||
{
|
{
|
||||||
assert(isIndependentNode());
|
assert(isIndependentNode());
|
||||||
@@ -288,11 +289,11 @@ public:
|
|||||||
{
|
{
|
||||||
return vstd::contains(state,EBattleStackState::ALIVE);
|
return vstd::contains(state,EBattleStackState::ALIVE);
|
||||||
}
|
}
|
||||||
bool idDeadClone() const //determines if stack is alive
|
|
||||||
{
|
bool isDead() const;
|
||||||
return vstd::contains(state,EBattleStackState::DEAD_CLONE);
|
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 isValidTarget(bool allowDead = false) const; //alive non-turret stacks (can be attacked or be object of magic effect)
|
bool isTurret() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
class DLL_LINKAGE CMP_stack
|
class DLL_LINKAGE CMP_stack
|
||||||
|
|||||||
@@ -180,33 +180,33 @@ bool CBattleInfoEssentials::battleHasNativeStack(ui8 side) const
|
|||||||
|
|
||||||
TStacks CBattleInfoEssentials::battleGetAllStacks(bool includeTurrets /*= false*/) 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;
|
TStacks ret;
|
||||||
RETURN_IF_NOT_BATTLE(ret);
|
RETURN_IF_NOT_BATTLE(ret);
|
||||||
|
|
||||||
vstd::copy_if(getBattle()->stacks, std::back_inserter(ret), [=](const CStack * s){
|
vstd::copy_if(getBattle()->stacks, std::back_inserter(ret), predicate);
|
||||||
return predicate(s) && (includeTurrets || !(s->type->idNumber == CreatureID::ARROW_TOWERS));
|
|
||||||
});
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
TStacks CBattleInfoEssentials::battleAliveStacks() const
|
TStacks CBattleInfoEssentials::battleAliveStacks() const
|
||||||
{
|
{
|
||||||
return battleGetStacksIf([](const CStack * s){
|
return battleGetStacksIf([](const CStack * s){
|
||||||
return s->alive();
|
return s->isValidTarget(false);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
TStacks CBattleInfoEssentials::battleAliveStacks(ui8 side) const
|
TStacks CBattleInfoEssentials::battleAliveStacks(ui8 side) const
|
||||||
{
|
{
|
||||||
return battleGetStacksIf([=](const CStack * s){
|
return battleGetStacksIf([=](const CStack * s){
|
||||||
return s->alive() && s->attackerOwned == !side;
|
return s->isValidTarget(false) && s->attackerOwned == !side;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -256,11 +256,15 @@ const CStack* CBattleInfoEssentials::battleGetStackByID(int ID, bool onlyAlive)
|
|||||||
{
|
{
|
||||||
RETURN_IF_NOT_BATTLE(nullptr);
|
RETURN_IF_NOT_BATTLE(nullptr);
|
||||||
|
|
||||||
for(auto s : battleGetAllStacks(true))
|
auto stacks = battleGetStacksIf([=](const CStack * s)
|
||||||
if(s->ID == ID && (!onlyAlive || s->alive()))
|
{
|
||||||
return s;
|
return s->ID == ID && (!onlyAlive || s->alive());
|
||||||
|
});
|
||||||
|
|
||||||
return nullptr;
|
if(stacks.empty())
|
||||||
|
return nullptr;
|
||||||
|
else
|
||||||
|
return stacks[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CBattleInfoEssentials::battleDoWeKnowAbout(ui8 side) const
|
bool CBattleInfoEssentials::battleDoWeKnowAbout(ui8 side) const
|
||||||
@@ -1304,8 +1308,8 @@ std::pair<const CStack *, BattleHex> CBattleInfoCallback::getNearestStack(const
|
|||||||
|
|
||||||
std::vector<const CStack *> possibleStacks = battleGetStacksIf([=](const CStack * s)
|
std::vector<const CStack *> possibleStacks = battleGetStacksIf([=](const CStack * s)
|
||||||
{
|
{
|
||||||
return s != closest && s->alive() && (boost::logic::indeterminate(attackerOwned) || s->attackerOwned == attackerOwned);
|
return s->isValidTarget(false) && s != closest && (boost::logic::indeterminate(attackerOwned) || s->attackerOwned == attackerOwned);
|
||||||
}, false);
|
});
|
||||||
|
|
||||||
for(const CStack * st : possibleStacks)
|
for(const CStack * st : possibleStacks)
|
||||||
for(BattleHex hex : avHexes)
|
for(BattleHex hex : avHexes)
|
||||||
@@ -2225,8 +2229,8 @@ TStacks CPlayerBattleCallback::battleGetStacks(EStackOwnership whose /*= MINE_AN
|
|||||||
const bool ownerMatches = (whose == MINE_AND_ENEMY)
|
const bool ownerMatches = (whose == MINE_AND_ENEMY)
|
||||||
|| (whose == ONLY_MINE && s->owner == player)
|
|| (whose == ONLY_MINE && s->owner == player)
|
||||||
|| (whose == ONLY_ENEMY && s->owner != player);
|
|| (whose == ONLY_ENEMY && s->owner != player);
|
||||||
const bool alivenessMatches = s->alive() || !onlyAlive;
|
|
||||||
return ownerMatches && alivenessMatches;
|
return ownerMatches && s->isValidTarget(!onlyAlive);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ protected:
|
|||||||
CCallbackBase()
|
CCallbackBase()
|
||||||
: battle(nullptr), gs(nullptr)
|
: battle(nullptr), gs(nullptr)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
void setBattle(const BattleInfo *B);
|
void setBattle(const BattleInfo *B);
|
||||||
bool duringBattle() const;
|
bool duringBattle() const;
|
||||||
|
|
||||||
@@ -83,8 +83,8 @@ namespace EAccessibility
|
|||||||
{
|
{
|
||||||
enum EAccessibility
|
enum EAccessibility
|
||||||
{
|
{
|
||||||
ACCESSIBLE,
|
ACCESSIBLE,
|
||||||
ALIVE_STACK,
|
ALIVE_STACK,
|
||||||
OBSTACLE,
|
OBSTACLE,
|
||||||
DESTRUCTIBLE_WALL,
|
DESTRUCTIBLE_WALL,
|
||||||
GATE, //sieges -> gate opens only for defender stacks
|
GATE, //sieges -> gate opens only for defender stacks
|
||||||
@@ -125,7 +125,7 @@ struct DLL_LINKAGE ReachabilityInfo
|
|||||||
struct DLL_LINKAGE Parameters
|
struct DLL_LINKAGE Parameters
|
||||||
{
|
{
|
||||||
const CStack *stack; //stack for which calculation is mage => not required (kept for debugging mostly), following variables are enough
|
const CStack *stack; //stack for which calculation is mage => not required (kept for debugging mostly), following variables are enough
|
||||||
|
|
||||||
bool attackerOwned;
|
bool attackerOwned;
|
||||||
bool doubleWide;
|
bool doubleWide;
|
||||||
bool flying;
|
bool flying;
|
||||||
@@ -171,15 +171,15 @@ public:
|
|||||||
ETerrainType battleTerrainType() const;
|
ETerrainType battleTerrainType() const;
|
||||||
BFieldType battleGetBattlefieldType() const;
|
BFieldType battleGetBattlefieldType() const;
|
||||||
std::vector<std::shared_ptr<const CObstacleInstance> > battleGetAllObstacles(boost::optional<BattlePerspective::BattlePerspective> perspective = boost::none) const; //returns all obstacles on the battlefield
|
std::vector<std::shared_ptr<const CObstacleInstance> > battleGetAllObstacles(boost::optional<BattlePerspective::BattlePerspective> perspective = boost::none) const; //returns all obstacles on the battlefield
|
||||||
|
|
||||||
/** @brief Main method for getting battle stacks
|
/** @brief Main method for getting battle stacks
|
||||||
*
|
*
|
||||||
* @param predicate Functor that shall return true for desired stack
|
* @param predicate Functor that shall return true for desired stack
|
||||||
* @return filtered stacks
|
* @return filtered stacks
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
TStacks battleGetStacksIf(TStackFilter predicate, bool includeTurrets = false) const;
|
TStacks battleGetStacksIf(TStackFilter predicate) const;
|
||||||
|
|
||||||
bool battleHasNativeStack(ui8 side) const;
|
bool battleHasNativeStack(ui8 side) const;
|
||||||
int battleGetMoatDmg() const; //what dmg unit will suffer if ending turn in the moat
|
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
|
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;
|
bool battleHasHero(ui8 side) const;
|
||||||
int battleCastSpells(ui8 side) const; //how many spells has given side cast
|
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 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;
|
InfoAboutHero battleGetHeroInfo(ui8 side) const;
|
||||||
|
|
||||||
// for determining state of a part of the wall; format: parameter [0] - keep, [1] - bottom tower, [2] - bottom wall,
|
// 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
|
//helpers
|
||||||
///returns all stacks, alive or dead or undead or mechanical :)
|
///returns all stacks, alive or dead or undead or mechanical :)
|
||||||
TStacks battleGetAllStacks(bool includeTurrets = false) const;
|
TStacks battleGetAllStacks(bool includeTurrets = false) const;
|
||||||
|
|
||||||
///returns all alive stacks excluding turrets
|
///returns all alive stacks excluding turrets
|
||||||
TStacks battleAliveStacks() const;
|
TStacks battleAliveStacks() const;
|
||||||
///returns all alive stacks from particular side excluding turrets
|
///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
|
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]
|
ReachabilityInfo::TDistances battleGetDistances(const CStack * stack, BattleHex hex = BattleHex::INVALID, BattleHex * predecessors = nullptr) const; //returns vector of distances to [dest hex number]
|
||||||
std::set<BattleHex> battleGetAttackedHexes(const CStack* attacker, BattleHex destinationTile, BattleHex attackerPos = BattleHex::INVALID) const;
|
std::set<BattleHex> 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 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 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
|
bool battleIsStackBlocked(const CStack * stack) const; //returns true if there is neighboring enemy stack
|
||||||
std::set<const CStack*> batteAdjacentCreatures (const CStack * stack) const;
|
std::set<const CStack*> batteAdjacentCreatures (const CStack * stack) const;
|
||||||
|
|
||||||
TDmgRange calculateDmgRange(const BattleAttackInfo &info) const; //charge - number of hexes travelled before attack (for champion's jousting); returns pair <min dmg, max dmg>
|
TDmgRange calculateDmgRange(const BattleAttackInfo &info) const; //charge - number of hexes travelled before attack (for champion's jousting); returns pair <min dmg, max dmg>
|
||||||
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 <min dmg, max dmg>
|
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 <min dmg, max dmg>
|
||||||
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 <min dmg, max dmg>
|
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 <min dmg, max dmg>
|
||||||
@@ -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
|
bool isWallPartPotentiallyAttackable(EWallPart::EWallPart wallPart) const; // returns true if the wall part is potentially attackable (independent of wall state), false if not
|
||||||
std::vector<BattleHex> getAttackableBattleHexes() const;
|
std::vector<BattleHex> 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
|
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
|
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
|
ESpellCastProblem::ESpellCastProblem battleCanCastSpell(PlayerColor player, ECastingMode::ECastingMode mode) const; //returns true if there are no general issues preventing from casting a spell
|
||||||
|
|||||||
@@ -471,7 +471,7 @@ namespace EBattleStackState
|
|||||||
{
|
{
|
||||||
ALIVE = 180,
|
ALIVE = 180,
|
||||||
SUMMONED, CLONED,
|
SUMMONED, CLONED,
|
||||||
DEAD_CLONE,
|
GHOST, //stack was removed from battlefield
|
||||||
HAD_MORALE,
|
HAD_MORALE,
|
||||||
WAITING,
|
WAITING,
|
||||||
MOVED,
|
MOVED,
|
||||||
@@ -480,7 +480,8 @@ namespace EBattleStackState
|
|||||||
//remember to drain mana only once per turn
|
//remember to drain mana only once per turn
|
||||||
DRAINED_MANA,
|
DRAINED_MANA,
|
||||||
//only for defending animation
|
//only for defending animation
|
||||||
DEFENDING_ANIM
|
DEFENDING_ANIM,
|
||||||
|
GHOST_PENDING// stack will become GHOST in next battle state update
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1308,6 +1308,16 @@ DLL_LINKAGE void BattleStackAttacked::applyGs( CGameState *gs )
|
|||||||
if(killed())
|
if(killed())
|
||||||
{
|
{
|
||||||
at->state -= EBattleStackState::ALIVE;
|
at->state -= EBattleStackState::ALIVE;
|
||||||
|
|
||||||
|
if(at->cloneID >= 0)
|
||||||
|
{
|
||||||
|
//remove clone as well
|
||||||
|
CStack * clone = gs->curB->getStack(at->cloneID);
|
||||||
|
if(clone)
|
||||||
|
clone->makeGhost();
|
||||||
|
|
||||||
|
at->cloneID = -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
//life drain handling
|
//life drain handling
|
||||||
for (auto & elem : healedStacks)
|
for (auto & elem : healedStacks)
|
||||||
@@ -1322,7 +1332,7 @@ DLL_LINKAGE void BattleStackAttacked::applyGs( CGameState *gs )
|
|||||||
if (cloneKilled())
|
if (cloneKilled())
|
||||||
{
|
{
|
||||||
//"hide" killed creatures instead so we keep info about it
|
//"hide" killed creatures instead so we keep info about it
|
||||||
at->state.insert(EBattleStackState::DEAD_CLONE);
|
at->makeGhost();
|
||||||
|
|
||||||
for(CStack * s : gs->curB->stacks)
|
for(CStack * s : gs->curB->stacks)
|
||||||
{
|
{
|
||||||
@@ -1330,6 +1340,12 @@ DLL_LINKAGE void BattleStackAttacked::applyGs( CGameState *gs )
|
|||||||
s->cloneID = -1;
|
s->cloneID = -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//killed summoned creature should be removed like clone
|
||||||
|
if(killed() && vstd::contains(at->state, EBattleStackState::SUMMONED))
|
||||||
|
{
|
||||||
|
at->makeGhost();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DLL_LINKAGE void BattleAttack::applyGs( CGameState *gs )
|
DLL_LINKAGE void BattleAttack::applyGs( CGameState *gs )
|
||||||
@@ -1613,20 +1629,35 @@ DLL_LINKAGE void BattleStacksRemoved::applyGs( CGameState *gs )
|
|||||||
{
|
{
|
||||||
if(!gs->curB)
|
if(!gs->curB)
|
||||||
return;
|
return;
|
||||||
for(ui32 rem_stack : stackIDs)
|
|
||||||
|
while(!stackIDs.empty())
|
||||||
{
|
{
|
||||||
|
ui32 rem_stack = *stackIDs.begin();
|
||||||
|
|
||||||
for(int b=0; b<gs->curB->stacks.size(); ++b) //find it in vector of stacks
|
for(int b=0; b<gs->curB->stacks.size(); ++b) //find it in vector of stacks
|
||||||
{
|
{
|
||||||
if(gs->curB->stacks[b]->ID == rem_stack) //if found
|
if(gs->curB->stacks[b]->ID == rem_stack) //if found
|
||||||
{
|
{
|
||||||
CStack *toRemove = gs->curB->stacks[b];
|
CStack * toRemove = gs->curB->stacks[b];
|
||||||
gs->curB->stacks.erase(gs->curB->stacks.begin() + b); //remove
|
|
||||||
|
toRemove->state.erase(EBattleStackState::ALIVE);
|
||||||
|
toRemove->state.erase(EBattleStackState::GHOST_PENDING);
|
||||||
|
toRemove->state.insert(EBattleStackState::GHOST);
|
||||||
|
toRemove->detachFromAll();//TODO: may be some bonuses should remain
|
||||||
|
|
||||||
|
//stack may be removed instantly (not being killed first)
|
||||||
|
//handle clone remove also here
|
||||||
|
if(toRemove->cloneID >= 0)
|
||||||
|
{
|
||||||
|
stackIDs.insert(toRemove->cloneID);
|
||||||
|
toRemove->cloneID = -1;
|
||||||
|
}
|
||||||
|
|
||||||
toRemove->detachFromAll();
|
|
||||||
delete toRemove;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
stackIDs.erase(rem_stack);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -637,14 +637,13 @@ ESpellCastProblem::ESpellCastProblem SpecialRisingSpellMechanics::isImmuneByStac
|
|||||||
///SummonMechanics
|
///SummonMechanics
|
||||||
ESpellCastProblem::ESpellCastProblem SummonMechanics::canBeCast(const CBattleInfoCallback * cb, PlayerColor player) const
|
ESpellCastProblem::ESpellCastProblem SummonMechanics::canBeCast(const CBattleInfoCallback * cb, PlayerColor player) const
|
||||||
{
|
{
|
||||||
const ui8 side = cb->playerToSide(player);
|
|
||||||
|
|
||||||
//check if there are summoned elementals of other type
|
//check if there are summoned elementals of other type
|
||||||
|
|
||||||
auto otherSummoned = cb->battleGetStacksIf([side, this](const CStack * st)
|
auto otherSummoned = cb->battleGetStacksIf([player, this](const CStack * st)
|
||||||
{
|
{
|
||||||
return (st->attackerOwned == !side)
|
return (st->owner == player)
|
||||||
&& (vstd::contains(st->state, EBattleStackState::SUMMONED))
|
&& (vstd::contains(st->state, EBattleStackState::SUMMONED))
|
||||||
|
&& (!vstd::contains(st->state, EBattleStackState::CLONED))
|
||||||
&& (st->getCreature()->idNumber != creatureToSummon);
|
&& (st->getCreature()->idNumber != creatureToSummon);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -360,9 +360,8 @@ void DefaultSpellMechanics::battleCast(const SpellCastEnvironment * env, BattleS
|
|||||||
TStacks mirrorTargets = parameters.cb->battleGetStacksIf([this, parameters](const CStack * battleStack)
|
TStacks mirrorTargets = parameters.cb->battleGetStacksIf([this, parameters](const CStack * battleStack)
|
||||||
{
|
{
|
||||||
//Get all enemy stacks. Magic mirror can reflect to immune creature (with no effect)
|
//Get all enemy stacks. Magic mirror can reflect to immune creature (with no effect)
|
||||||
return battleStack->owner == parameters.casterColor;
|
return battleStack->owner == parameters.casterColor && battleStack->isValidTarget(false);
|
||||||
},
|
});
|
||||||
true);//turrets included
|
|
||||||
|
|
||||||
if(!mirrorTargets.empty())
|
if(!mirrorTargets.empty())
|
||||||
{
|
{
|
||||||
@@ -711,7 +710,6 @@ std::set<const CStack *> DefaultSpellMechanics::getAffectedStacks(SpellTargeting
|
|||||||
//for massive spells add all targets
|
//for massive spells add all targets
|
||||||
for (auto stack : stacks)
|
for (auto stack : stacks)
|
||||||
attackedCres.insert(stack);
|
attackedCres.insert(stack);
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -309,8 +309,9 @@ void CSpell::getEffects(std::vector<Bonus> & lst, const int level) const
|
|||||||
ESpellCastProblem::ESpellCastProblem CSpell::isImmuneAt(const CBattleInfoCallback * cb, const ISpellCaster * caster, ECastingMode::ECastingMode mode, BattleHex destination) 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
|
// Get all stacks at destination hex. only alive if not rising spell
|
||||||
TStacks stacks = cb->battleGetStacksIf([=](const CStack * s){
|
TStacks stacks = cb->battleGetStacksIf([=](const CStack * s)
|
||||||
return s->coversPos(destination) && (isRisingSpell() || s->alive());
|
{
|
||||||
|
return s->coversPos(destination) && s->isValidTarget(isRisingSpell());
|
||||||
});
|
});
|
||||||
|
|
||||||
if(!stacks.empty())
|
if(!stacks.empty())
|
||||||
|
|||||||
@@ -4400,7 +4400,7 @@ bool CGameHandler::makeCustomAction( BattleAction &ba )
|
|||||||
s->battleCast(spellEnv, parameters);
|
s->battleCast(spellEnv, parameters);
|
||||||
|
|
||||||
sendAndApply(&end_action);
|
sendAndApply(&end_action);
|
||||||
if( !gs->curB->battleGetStackByID(gs->curB->activeStack, true))
|
if( !gs->curB->battleGetStackByID(gs->curB->activeStack))
|
||||||
{
|
{
|
||||||
battleMadeAction.setn(true);
|
battleMadeAction.setn(true);
|
||||||
}
|
}
|
||||||
@@ -5606,24 +5606,26 @@ void CGameHandler::runBattle()
|
|||||||
|
|
||||||
const BattleInfo & curB = *gs->curB;
|
const BattleInfo & curB = *gs->curB;
|
||||||
|
|
||||||
//remove clones after all mechanics and animations are handled!
|
|
||||||
std::set <const CStack*> stacksToRemove;
|
|
||||||
for (auto stack : curB.stacks)
|
|
||||||
{
|
|
||||||
if (stack->idDeadClone())
|
|
||||||
stacksToRemove.insert(stack);
|
|
||||||
}
|
|
||||||
for (auto stack : stacksToRemove)
|
|
||||||
{
|
|
||||||
BattleStacksRemoved bsr;
|
|
||||||
bsr.stackIDs.insert(stack->ID);
|
|
||||||
sendAndApply(&bsr);
|
|
||||||
}
|
|
||||||
//stack loop
|
//stack loop
|
||||||
|
|
||||||
const CStack *next;
|
const CStack *next;
|
||||||
while(!battleResult.get() && (next = curB.getNextStack()) && next->willMove())
|
while(!battleResult.get() && (next = curB.getNextStack()) && next->willMove())
|
||||||
{
|
{
|
||||||
|
|
||||||
|
std::set <const CStack *> stacksToRemove;
|
||||||
|
for(auto stack : curB.stacks)
|
||||||
|
{
|
||||||
|
if(vstd::contains(stack->state, EBattleStackState::GHOST_PENDING))
|
||||||
|
stacksToRemove.insert(stack);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(auto stack : stacksToRemove)
|
||||||
|
{
|
||||||
|
BattleStacksRemoved bsr;
|
||||||
|
bsr.stackIDs.insert(stack->ID);
|
||||||
|
sendAndApply(&bsr);
|
||||||
|
}
|
||||||
|
|
||||||
//check for bad morale => freeze
|
//check for bad morale => freeze
|
||||||
int nextStackMorale = next->MoraleVal();
|
int nextStackMorale = next->MoraleVal();
|
||||||
if( nextStackMorale < 0 &&
|
if( nextStackMorale < 0 &&
|
||||||
@@ -5716,8 +5718,9 @@ void CGameHandler::runBattle()
|
|||||||
|
|
||||||
if(next->getCreature()->idNumber == CreatureID::FIRST_AID_TENT)
|
if(next->getCreature()->idNumber == CreatureID::FIRST_AID_TENT)
|
||||||
{
|
{
|
||||||
TStacks possibleStacks = battleGetStacksIf([&](const CStack * s){
|
TStacks possibleStacks = battleGetStacksIf([=](const CStack * s)
|
||||||
return s->owner == next->owner && s->canBeHealed();
|
{
|
||||||
|
return s->owner == next->owner && s->canBeHealed();
|
||||||
});
|
});
|
||||||
|
|
||||||
if(!possibleStacks.size())
|
if(!possibleStacks.size())
|
||||||
@@ -6091,44 +6094,6 @@ CasualtiesAfterBattle::CasualtiesAfterBattle(const CArmedInstance * _army, Battl
|
|||||||
if(color == PlayerColor::UNFLAGGABLE)
|
if(color == PlayerColor::UNFLAGGABLE)
|
||||||
color = PlayerColor::NEUTRAL;
|
color = PlayerColor::NEUTRAL;
|
||||||
|
|
||||||
auto killStack = [&, this](const SlotID slot, const CStackInstance * instance)
|
|
||||||
{
|
|
||||||
StackLocation sl(army, slot);
|
|
||||||
newStackCounts.push_back(TStackAndItsNewCount(sl, 0));
|
|
||||||
if(nullptr == instance)
|
|
||||||
return;
|
|
||||||
auto c = dynamic_cast <const CCommanderInstance *>(instance);
|
|
||||||
if (c) //switch commander status to dead
|
|
||||||
{
|
|
||||||
auto h = dynamic_cast <const CGHeroInstance *>(army);
|
|
||||||
if (h && h->commander == c)
|
|
||||||
heroWithDeadCommander = army->id; //TODO: unify commander handling
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
//1. Find removed stacks.
|
|
||||||
for(const auto & slotInfo : army->stacks)
|
|
||||||
{
|
|
||||||
const SlotID slot = slotInfo.first;
|
|
||||||
const CStackInstance * instance = slotInfo.second;
|
|
||||||
|
|
||||||
if(nullptr != instance)//just in case
|
|
||||||
{
|
|
||||||
bool found = false;
|
|
||||||
for(const CStack * sta : bat->stacks)
|
|
||||||
{
|
|
||||||
if(sta->base == instance)
|
|
||||||
{
|
|
||||||
found = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//stack in this slot was removed == it is dead
|
|
||||||
if(!found)
|
|
||||||
killStack(slot, instance);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for(CStack *st : bat->stacks)
|
for(CStack *st : bat->stacks)
|
||||||
{
|
{
|
||||||
if(vstd::contains(st->state, EBattleStackState::SUMMONED)) //don't take into account temporary summoned stacks
|
if(vstd::contains(st->state, EBattleStackState::SUMMONED)) //don't take into account temporary summoned stacks
|
||||||
@@ -6144,7 +6109,7 @@ CasualtiesAfterBattle::CasualtiesAfterBattle(const CArmedInstance * _army, Battl
|
|||||||
if(st->slot == SlotID::ARROW_TOWERS_SLOT)
|
if(st->slot == SlotID::ARROW_TOWERS_SLOT)
|
||||||
{
|
{
|
||||||
//do nothing
|
//do nothing
|
||||||
logGlobal->debugStream() << "Ignored arrow towers stack";
|
logGlobal->debug("Ignored arrow towers stack.");
|
||||||
}
|
}
|
||||||
else if(st->slot == SlotID::WAR_MACHINES_SLOT)
|
else if(st->slot == SlotID::WAR_MACHINES_SLOT)
|
||||||
{
|
{
|
||||||
@@ -6157,40 +6122,63 @@ CasualtiesAfterBattle::CasualtiesAfterBattle(const CArmedInstance * _army, Battl
|
|||||||
//catapult artifact remain even if "creature" killed in siege
|
//catapult artifact remain even if "creature" killed in siege
|
||||||
else if(warMachine != ArtifactID::CATAPULT && !st->count)
|
else if(warMachine != ArtifactID::CATAPULT && !st->count)
|
||||||
{
|
{
|
||||||
logGlobal->debugStream() << "War machine has been destroyed";
|
logGlobal->debug("War machine has been destroyed");
|
||||||
auto hero = dynamic_ptr_cast<CGHeroInstance> (army);
|
auto hero = dynamic_ptr_cast<CGHeroInstance> (army);
|
||||||
if (hero)
|
if (hero)
|
||||||
removedWarMachines.push_back (ArtifactLocation(hero, hero->getArtPos(warMachine, true)));
|
removedWarMachines.push_back (ArtifactLocation(hero, hero->getArtPos(warMachine, true)));
|
||||||
else
|
else
|
||||||
logGlobal->errorStream() << "War machine in army without hero";
|
logGlobal->error("War machine in army without hero");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if(st->slot == SlotID::SUMMONED_SLOT_PLACEHOLDER)
|
else if(st->slot == SlotID::SUMMONED_SLOT_PLACEHOLDER)
|
||||||
{
|
{
|
||||||
if(st->alive() && st->count > 0)
|
if(st->alive() && st->count > 0)
|
||||||
{
|
{
|
||||||
logGlobal->debugStream() << "Stack has been permanently summoned";
|
logGlobal->debugStream() << "Permanently summoned " + st->count << " units.";
|
||||||
//this stack was permanently summoned
|
|
||||||
const CreatureID summonedType = st->type->idNumber;
|
const CreatureID summonedType = st->type->idNumber;
|
||||||
summoned[summonedType] += st->count;
|
summoned[summonedType] += st->count;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if(st->slot == SlotID::COMMANDER_SLOT_PLACEHOLDER)
|
||||||
|
{
|
||||||
|
if(nullptr == st->base)
|
||||||
|
{
|
||||||
|
logGlobal->error("Stack with no base in commander slot.");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto c = dynamic_cast <const CCommanderInstance *>(st->base);
|
||||||
|
if(c)
|
||||||
|
{
|
||||||
|
auto h = dynamic_cast <const CGHeroInstance *>(army);
|
||||||
|
if (h && h->commander == c)
|
||||||
|
{
|
||||||
|
logGlobal->debug("Commander is dead.");
|
||||||
|
heroWithDeadCommander = army->id; //TODO: unify commander handling
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
logGlobal->error("Stack with invalid instance in commander slot.");
|
||||||
|
}
|
||||||
|
}
|
||||||
else if(st->base && !army->slotEmpty(st->slot))
|
else if(st->base && !army->slotEmpty(st->slot))
|
||||||
{
|
{
|
||||||
if(st->count == 0 || !st->alive())
|
if(st->count == 0 || !st->alive())
|
||||||
{
|
{
|
||||||
killStack(st->slot, st->base);
|
logGlobal->debug("Stack has been destroyed.");
|
||||||
logGlobal->debugStream() << "Stack has been destroyed";
|
StackLocation sl(army, st->slot);
|
||||||
|
newStackCounts.push_back(TStackAndItsNewCount(sl, 0));
|
||||||
}
|
}
|
||||||
else if(st->count < army->getStackCount(st->slot))
|
else if(st->count < army->getStackCount(st->slot))
|
||||||
{
|
{
|
||||||
|
logGlobal->debugStream() << "Stack lost " << (army->getStackCount(st->slot) - st->count) << " units.";
|
||||||
StackLocation sl(army, st->slot);
|
StackLocation sl(army, st->slot);
|
||||||
newStackCounts.push_back(TStackAndItsNewCount(sl, st->count));
|
newStackCounts.push_back(TStackAndItsNewCount(sl, st->count));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
logGlobal->warnStream() << "Unhandled stack " << st->nodeName();
|
logGlobal->warnStream() << "Unable to process stack: " << st->nodeName();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user