mirror of
https://github.com/vcmi/vcmi.git
synced 2025-01-12 02:28:11 +02:00
The battle callback method battleGetAllStacks will by default omit the arrow turrets. Fixes #1453, #1455 and related.
This commit is contained in:
parent
0e5a59e2a5
commit
4f29b526ca
@ -85,7 +85,9 @@ CBattleStackAnimation::CBattleStackAnimation(CBattleInterface * owner, const CSt
|
|||||||
: CBattleAnimation(owner),
|
: CBattleAnimation(owner),
|
||||||
myAnim(owner->creAnims[stack->ID]),
|
myAnim(owner->creAnims[stack->ID]),
|
||||||
stack(stack)
|
stack(stack)
|
||||||
{}
|
{
|
||||||
|
assert(myAnim);
|
||||||
|
}
|
||||||
|
|
||||||
void CAttackAnimation::nextFrame()
|
void CAttackAnimation::nextFrame()
|
||||||
{
|
{
|
||||||
|
@ -153,7 +153,7 @@ CBattleInterface::CBattleInterface(const CCreatureSet * army1, const CCreatureSe
|
|||||||
//initializing armies
|
//initializing armies
|
||||||
this->army1 = army1;
|
this->army1 = army1;
|
||||||
this->army2 = army2;
|
this->army2 = army2;
|
||||||
std::vector<const CStack*> stacks = curInt->cb->battleGetAllStacks();
|
std::vector<const CStack*> stacks = curInt->cb->battleGetAllStacks(true);
|
||||||
for(const CStack *s : stacks)
|
for(const CStack *s : stacks)
|
||||||
{
|
{
|
||||||
newStack(s);
|
newStack(s);
|
||||||
@ -3651,7 +3651,7 @@ void CBattleInterface::showPiecesOfWall(SDL_Surface * to, std::vector<int> piece
|
|||||||
|
|
||||||
const CStack *turret = nullptr;
|
const CStack *turret = nullptr;
|
||||||
|
|
||||||
for(auto & stack : curInt->cb->battleGetAllStacks())
|
for(auto & stack : curInt->cb->battleGetAllStacks(true))
|
||||||
{
|
{
|
||||||
if(stack->position == stackPos)
|
if(stack->position == stackPos)
|
||||||
{
|
{
|
||||||
|
@ -177,11 +177,14 @@ bool CBattleInfoEssentials::battleHasNativeStack(ui8 side) const
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
TStacks CBattleInfoEssentials::battleGetAllStacks() const /*returns all stacks, alive or dead or undead or mechanical :) */
|
TStacks CBattleInfoEssentials::battleGetAllStacks(bool includeTurrets /*= false*/) const /*returns all stacks, alive or dead or undead or mechanical :) */
|
||||||
{
|
{
|
||||||
TStacks ret;
|
TStacks ret;
|
||||||
RETURN_IF_NOT_BATTLE(ret);
|
RETURN_IF_NOT_BATTLE(ret);
|
||||||
boost::copy(getBattle()->stacks, std::back_inserter(ret));
|
boost::copy(getBattle()->stacks, std::back_inserter(ret));
|
||||||
|
if(!includeTurrets)
|
||||||
|
vstd::erase_if(ret, [](const CStack *stack) { return stack->type->idNumber == CreatureID::ARROW_TOWERS; });
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -245,7 +248,7 @@ const CStack* CBattleInfoEssentials::battleGetStackByID(int ID, bool onlyAlive)
|
|||||||
{
|
{
|
||||||
RETURN_IF_NOT_BATTLE(nullptr);
|
RETURN_IF_NOT_BATTLE(nullptr);
|
||||||
|
|
||||||
for(auto s : battleGetAllStacks())
|
for(auto s : battleGetAllStacks(true))
|
||||||
if(s->ID == ID && (!onlyAlive || s->alive()))
|
if(s->ID == ID && (!onlyAlive || s->alive()))
|
||||||
return s;
|
return s;
|
||||||
|
|
||||||
@ -512,7 +515,7 @@ SpellID CBattleInfoCallback::battleGetRandomStackSpell(const CStack * stack, ERa
|
|||||||
const CStack* CBattleInfoCallback::battleGetStackByPos(BattleHex pos, bool onlyAlive) const
|
const CStack* CBattleInfoCallback::battleGetStackByPos(BattleHex pos, bool onlyAlive) const
|
||||||
{
|
{
|
||||||
RETURN_IF_NOT_BATTLE(nullptr);
|
RETURN_IF_NOT_BATTLE(nullptr);
|
||||||
for(auto s : battleGetAllStacks())
|
for(auto s : battleGetAllStacks(true))
|
||||||
if(vstd::contains(s->getHexes(), pos) && (!onlyAlive || s->alive()))
|
if(vstd::contains(s->getHexes(), pos) && (!onlyAlive || s->alive()))
|
||||||
return s;
|
return s;
|
||||||
|
|
||||||
@ -594,7 +597,7 @@ void CBattleInfoCallback::battleGetStackQueue(std::vector<const CStack *> &out,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto allStacks = battleGetAllStacks();
|
auto allStacks = battleGetAllStacks(true);
|
||||||
if(!vstd::contains_if(allStacks, [](const CStack *stack) { return stack->willMove(100000); })) //little evil, but 100000 should be enough for all effects to disappear
|
if(!vstd::contains_if(allStacks, [](const CStack *stack) { return stack->willMove(100000); })) //little evil, but 100000 should be enough for all effects to disappear
|
||||||
{
|
{
|
||||||
//No stack will be able to move, battle is over.
|
//No stack will be able to move, battle is over.
|
||||||
@ -602,7 +605,7 @@ void CBattleInfoCallback::battleGetStackQueue(std::vector<const CStack *> &out,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for(auto s : battleGetAllStacks())
|
for(auto s : battleGetAllStacks(true))
|
||||||
{
|
{
|
||||||
if((turn <= 0 && !s->willMove()) //we are considering current round and stack won't move
|
if((turn <= 0 && !s->willMove()) //we are considering current round and stack won't move
|
||||||
|| (turn > 0 && !s->canMove(turn)) //stack won't be able to move in later rounds
|
|| (turn > 0 && !s->canMove(turn)) //stack won't be able to move in later rounds
|
||||||
|
@ -168,7 +168,7 @@ public:
|
|||||||
ETerrainType battleTerrainType() const;
|
ETerrainType battleTerrainType() const;
|
||||||
BFieldType battleGetBattlefieldType() const;
|
BFieldType battleGetBattlefieldType() const;
|
||||||
std::vector<shared_ptr<const CObstacleInstance> > battleGetAllObstacles(boost::optional<BattlePerspective::BattlePerspective> perspective = boost::none) const; //returns all obstacles on the battlefield
|
std::vector<shared_ptr<const CObstacleInstance> > battleGetAllObstacles(boost::optional<BattlePerspective::BattlePerspective> perspective = boost::none) const; //returns all obstacles on the battlefield
|
||||||
TStacks battleGetAllStacks() const; //returns all stacks, alive or dead or undead or mechanical :)
|
TStacks battleGetAllStacks(bool includeTurrets = false) const; //returns all stacks, alive or dead or undead or mechanical :)
|
||||||
bool battleHasNativeStack(ui8 side) const;
|
bool battleHasNativeStack(ui8 side) const;
|
||||||
si8 battleGetWallState(int partOfWall) const; //for determining state of a part of the wall; format: parameter [0] - keep, [1] - bottom tower, [2] - bottom wall, [3] - below gate, [4] - over gate, [5] - upper wall, [6] - uppert tower, [7] - gate; returned value: 1 - intact, 2 - damaged, 3 - destroyed; 0 - no battle
|
si8 battleGetWallState(int partOfWall) const; //for determining state of a part of the wall; format: parameter [0] - keep, [1] - bottom tower, [2] - bottom wall, [3] - below gate, [4] - over gate, [5] - upper wall, [6] - uppert tower, [7] - gate; returned value: 1 - intact, 2 - damaged, 3 - destroyed; 0 - no battle
|
||||||
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
|
||||||
|
@ -3249,13 +3249,18 @@ static EndAction end_action;
|
|||||||
|
|
||||||
bool CGameHandler::makeBattleAction( BattleAction &ba )
|
bool CGameHandler::makeBattleAction( BattleAction &ba )
|
||||||
{
|
{
|
||||||
logGlobal->errorStream() << "\tMaking action of type " << ba.actionType;
|
|
||||||
bool ok = true;
|
bool ok = true;
|
||||||
|
|
||||||
|
|
||||||
const CStack *stack = battleGetStackByID(ba.stackNumber); //may be nullptr if action is not about stack
|
const CStack *stack = battleGetStackByID(ba.stackNumber); //may be nullptr if action is not about stack
|
||||||
|
const CStack *destinationStack = ba.actionType == Battle::WALK_AND_ATTACK ? gs->curB->battleGetStackByPos(ba.additionalInfo)
|
||||||
|
: ba.actionType == Battle::SHOOT ? gs->curB->battleGetStackByPos(ba.destinationTile)
|
||||||
|
: nullptr;
|
||||||
const bool isAboutActiveStack = stack && (stack == battleActiveStack());
|
const bool isAboutActiveStack = stack && (stack == battleActiveStack());
|
||||||
|
|
||||||
|
logGlobal->traceStream() << boost::format(
|
||||||
|
"Making action: type=%d; side=%d; stack=%s; dst=%s; additionalInfo=%d; stackAtDst=%s")
|
||||||
|
% ba.actionType % (int)ba.side % (stack ? stack->getName() : std::string("none"))
|
||||||
|
% ba.destinationTile % ba.additionalInfo % (destinationStack ? destinationStack->getName() : std::string("none"));
|
||||||
|
|
||||||
switch(ba.actionType)
|
switch(ba.actionType)
|
||||||
{
|
{
|
||||||
@ -3366,8 +3371,7 @@ bool CGameHandler::makeBattleAction( BattleAction &ba )
|
|||||||
StartAction start_action(ba);
|
StartAction start_action(ba);
|
||||||
sendAndApply(&start_action); //start movement and attack
|
sendAndApply(&start_action); //start movement and attack
|
||||||
|
|
||||||
const CStack *stackAtEnd = gs->curB->battleGetStackByPos(ba.additionalInfo);
|
if(!stack || !destinationStack)
|
||||||
if(!stack || !stackAtEnd)
|
|
||||||
{
|
{
|
||||||
sendAndApply(&end_action);
|
sendAndApply(&end_action);
|
||||||
break;
|
break;
|
||||||
@ -3376,7 +3380,7 @@ bool CGameHandler::makeBattleAction( BattleAction &ba )
|
|||||||
BattleHex startingPos = stack->position;
|
BattleHex startingPos = stack->position;
|
||||||
int distance = moveStack(ba.stackNumber, ba.destinationTile);
|
int distance = moveStack(ba.stackNumber, ba.destinationTile);
|
||||||
|
|
||||||
logGlobal->traceStream() << stack->nodeName() << " will attack " << stackAtEnd->nodeName();
|
logGlobal->traceStream() << stack->nodeName() << " will attack " << destinationStack->nodeName();
|
||||||
|
|
||||||
if(stack->position != ba.destinationTile //we wasn't able to reach destination tile
|
if(stack->position != ba.destinationTile //we wasn't able to reach destination tile
|
||||||
&& !(stack->doubleWide()
|
&& !(stack->doubleWide()
|
||||||
@ -3392,12 +3396,12 @@ bool CGameHandler::makeBattleAction( BattleAction &ba )
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(stackAtEnd && stack->ID == stackAtEnd->ID) //we should just move, it will be handled by following check
|
if(destinationStack && stack->ID == destinationStack->ID) //we should just move, it will be handled by following check
|
||||||
{
|
{
|
||||||
stackAtEnd = nullptr;
|
destinationStack = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!stackAtEnd)
|
if(!destinationStack)
|
||||||
{
|
{
|
||||||
complain(boost::str(boost::format("walk and attack error: no stack at additionalInfo tile (%d)!\n") % ba.additionalInfo));
|
complain(boost::str(boost::format("walk and attack error: no stack at additionalInfo tile (%d)!\n") % ba.additionalInfo));
|
||||||
ok = false;
|
ok = false;
|
||||||
@ -3405,7 +3409,7 @@ bool CGameHandler::makeBattleAction( BattleAction &ba )
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( !CStack::isMeleeAttackPossible(stack, stackAtEnd) )
|
if( !CStack::isMeleeAttackPossible(stack, destinationStack) )
|
||||||
{
|
{
|
||||||
complain("Attack cannot be performed!");
|
complain("Attack cannot be performed!");
|
||||||
sendAndApply(&end_action);
|
sendAndApply(&end_action);
|
||||||
@ -3422,10 +3426,10 @@ bool CGameHandler::makeBattleAction( BattleAction &ba )
|
|||||||
{
|
{
|
||||||
if (stack &&
|
if (stack &&
|
||||||
stack->alive() && //move can cause death, eg. by walking into the moat
|
stack->alive() && //move can cause death, eg. by walking into the moat
|
||||||
stackAtEnd->alive())
|
destinationStack->alive())
|
||||||
{
|
{
|
||||||
BattleAttack bat;
|
BattleAttack bat;
|
||||||
prepareAttack(bat, stack, stackAtEnd, (i ? 0 : distance), ba.additionalInfo); //no distance travelled on second attack
|
prepareAttack(bat, stack, destinationStack, (i ? 0 : distance), ba.additionalInfo); //no distance travelled on second attack
|
||||||
//prepareAttack(bat, stack, stackAtEnd, 0, ba.additionalInfo);
|
//prepareAttack(bat, stack, stackAtEnd, 0, ba.additionalInfo);
|
||||||
handleAttackBeforeCasting(bat); //only before first attack
|
handleAttackBeforeCasting(bat); //only before first attack
|
||||||
sendAndApply(&bat);
|
sendAndApply(&bat);
|
||||||
@ -3433,13 +3437,13 @@ bool CGameHandler::makeBattleAction( BattleAction &ba )
|
|||||||
}
|
}
|
||||||
|
|
||||||
//counterattack
|
//counterattack
|
||||||
if (stackAtEnd
|
if (destinationStack
|
||||||
&& !stack->hasBonusOfType(Bonus::BLOCKS_RETALIATION)
|
&& !stack->hasBonusOfType(Bonus::BLOCKS_RETALIATION)
|
||||||
&& stackAtEnd->ableToRetaliate()
|
&& destinationStack->ableToRetaliate()
|
||||||
&& stack->alive()) //attacker may have died (fire shield)
|
&& stack->alive()) //attacker may have died (fire shield)
|
||||||
{
|
{
|
||||||
BattleAttack bat;
|
BattleAttack bat;
|
||||||
prepareAttack(bat, stackAtEnd, stack, 0, stack->position);
|
prepareAttack(bat, destinationStack, stack, 0, stack->position);
|
||||||
bat.flags |= BattleAttack::COUNTER;
|
bat.flags |= BattleAttack::COUNTER;
|
||||||
sendAndApply(&bat);
|
sendAndApply(&bat);
|
||||||
handleAfterAttackCasting(bat);
|
handleAfterAttackCasting(bat);
|
||||||
@ -3458,7 +3462,6 @@ bool CGameHandler::makeBattleAction( BattleAction &ba )
|
|||||||
}
|
}
|
||||||
case Battle::SHOOT:
|
case Battle::SHOOT:
|
||||||
{
|
{
|
||||||
const CStack *destStack= gs->curB->battleGetStackByPos(ba.destinationTile);
|
|
||||||
if( !gs->curB->battleCanShoot(stack, ba.destinationTile) )
|
if( !gs->curB->battleCanShoot(stack, ba.destinationTile) )
|
||||||
{
|
{
|
||||||
complain("Cannot shoot!");
|
complain("Cannot shoot!");
|
||||||
@ -3471,7 +3474,7 @@ bool CGameHandler::makeBattleAction( BattleAction &ba )
|
|||||||
{
|
{
|
||||||
BattleAttack bat;
|
BattleAttack bat;
|
||||||
bat.flags |= BattleAttack::SHOT;
|
bat.flags |= BattleAttack::SHOT;
|
||||||
prepareAttack(bat, stack, destStack, 0, ba.destinationTile);
|
prepareAttack(bat, stack, destinationStack, 0, ba.destinationTile);
|
||||||
handleAttackBeforeCasting(bat);
|
handleAttackBeforeCasting(bat);
|
||||||
sendAndApply(&bat);
|
sendAndApply(&bat);
|
||||||
handleAfterAttackCasting(bat);
|
handleAfterAttackCasting(bat);
|
||||||
@ -3481,14 +3484,14 @@ bool CGameHandler::makeBattleAction( BattleAction &ba )
|
|||||||
|
|
||||||
const CGHeroInstance * attackingHero = gs->curB->battleGetFightingHero(ba.side);
|
const CGHeroInstance * attackingHero = gs->curB->battleGetFightingHero(ba.side);
|
||||||
|
|
||||||
if( destStack->alive()
|
if( destinationStack->alive()
|
||||||
&& (stack->getCreature()->idNumber == CreatureID::BALLISTA)
|
&& (stack->getCreature()->idNumber == CreatureID::BALLISTA)
|
||||||
&& (attackingHero->getSecSkillLevel(SecondarySkill::ARTILLERY) >= SecSkillLevel::ADVANCED)
|
&& (attackingHero->getSecSkillLevel(SecondarySkill::ARTILLERY) >= SecSkillLevel::ADVANCED)
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
BattleAttack bat2;
|
BattleAttack bat2;
|
||||||
bat2.flags |= BattleAttack::SHOT;
|
bat2.flags |= BattleAttack::SHOT;
|
||||||
prepareAttack(bat2, stack, destStack, 0, ba.destinationTile);
|
prepareAttack(bat2, stack, destinationStack, 0, ba.destinationTile);
|
||||||
sendAndApply(&bat2);
|
sendAndApply(&bat2);
|
||||||
}
|
}
|
||||||
//allow more than one additional attack
|
//allow more than one additional attack
|
||||||
@ -3499,13 +3502,13 @@ bool CGameHandler::makeBattleAction( BattleAction &ba )
|
|||||||
{
|
{
|
||||||
if(
|
if(
|
||||||
stack->alive()
|
stack->alive()
|
||||||
&& destStack->alive()
|
&& destinationStack->alive()
|
||||||
&& stack->shots
|
&& stack->shots
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
BattleAttack bat;
|
BattleAttack bat;
|
||||||
bat.flags |= BattleAttack::SHOT;
|
bat.flags |= BattleAttack::SHOT;
|
||||||
prepareAttack(bat, stack, destStack, 0, ba.destinationTile);
|
prepareAttack(bat, stack, destinationStack, 0, ba.destinationTile);
|
||||||
sendAndApply(&bat);
|
sendAndApply(&bat);
|
||||||
handleAfterAttackCasting(bat);
|
handleAfterAttackCasting(bat);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user