1
0
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:
Michał W. Urbańczyk 2013-09-27 19:42:17 +00:00
parent 0e5a59e2a5
commit 4f29b526ca
5 changed files with 38 additions and 30 deletions

View File

@ -85,7 +85,9 @@ CBattleStackAnimation::CBattleStackAnimation(CBattleInterface * owner, const CSt
: CBattleAnimation(owner),
myAnim(owner->creAnims[stack->ID]),
stack(stack)
{}
{
assert(myAnim);
}
void CAttackAnimation::nextFrame()
{

View File

@ -153,7 +153,7 @@ CBattleInterface::CBattleInterface(const CCreatureSet * army1, const CCreatureSe
//initializing armies
this->army1 = army1;
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)
{
newStack(s);
@ -3651,7 +3651,7 @@ void CBattleInterface::showPiecesOfWall(SDL_Surface * to, std::vector<int> piece
const CStack *turret = nullptr;
for(auto & stack : curInt->cb->battleGetAllStacks())
for(auto & stack : curInt->cb->battleGetAllStacks(true))
{
if(stack->position == stackPos)
{

View File

@ -177,11 +177,14 @@ bool CBattleInfoEssentials::battleHasNativeStack(ui8 side) const
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;
RETURN_IF_NOT_BATTLE(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;
}
@ -245,7 +248,7 @@ const CStack* CBattleInfoEssentials::battleGetStackByID(int ID, bool onlyAlive)
{
RETURN_IF_NOT_BATTLE(nullptr);
for(auto s : battleGetAllStacks())
for(auto s : battleGetAllStacks(true))
if(s->ID == ID && (!onlyAlive || s->alive()))
return s;
@ -512,7 +515,7 @@ SpellID CBattleInfoCallback::battleGetRandomStackSpell(const CStack * stack, ERa
const CStack* CBattleInfoCallback::battleGetStackByPos(BattleHex pos, bool onlyAlive) const
{
RETURN_IF_NOT_BATTLE(nullptr);
for(auto s : battleGetAllStacks())
for(auto s : battleGetAllStacks(true))
if(vstd::contains(s->getHexes(), pos) && (!onlyAlive || s->alive()))
return s;
@ -594,7 +597,7 @@ void CBattleInfoCallback::battleGetStackQueue(std::vector<const CStack *> &out,
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
{
//No stack will be able to move, battle is over.
@ -602,7 +605,7 @@ void CBattleInfoCallback::battleGetStackQueue(std::vector<const CStack *> &out,
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
|| (turn > 0 && !s->canMove(turn)) //stack won't be able to move in later rounds

View File

@ -168,7 +168,7 @@ public:
ETerrainType battleTerrainType() 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
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;
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

View File

@ -3249,13 +3249,18 @@ static EndAction end_action;
bool CGameHandler::makeBattleAction( BattleAction &ba )
{
logGlobal->errorStream() << "\tMaking action of type " << ba.actionType;
bool ok = true;
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());
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)
{
@ -3366,8 +3371,7 @@ bool CGameHandler::makeBattleAction( BattleAction &ba )
StartAction start_action(ba);
sendAndApply(&start_action); //start movement and attack
const CStack *stackAtEnd = gs->curB->battleGetStackByPos(ba.additionalInfo);
if(!stack || !stackAtEnd)
if(!stack || !destinationStack)
{
sendAndApply(&end_action);
break;
@ -3376,7 +3380,7 @@ bool CGameHandler::makeBattleAction( BattleAction &ba )
BattleHex startingPos = stack->position;
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
&& !(stack->doubleWide()
@ -3392,12 +3396,12 @@ bool CGameHandler::makeBattleAction( BattleAction &ba )
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));
ok = false;
@ -3405,7 +3409,7 @@ bool CGameHandler::makeBattleAction( BattleAction &ba )
break;
}
if( !CStack::isMeleeAttackPossible(stack, stackAtEnd) )
if( !CStack::isMeleeAttackPossible(stack, destinationStack) )
{
complain("Attack cannot be performed!");
sendAndApply(&end_action);
@ -3422,10 +3426,10 @@ bool CGameHandler::makeBattleAction( BattleAction &ba )
{
if (stack &&
stack->alive() && //move can cause death, eg. by walking into the moat
stackAtEnd->alive())
destinationStack->alive())
{
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);
handleAttackBeforeCasting(bat); //only before first attack
sendAndApply(&bat);
@ -3433,13 +3437,13 @@ bool CGameHandler::makeBattleAction( BattleAction &ba )
}
//counterattack
if (stackAtEnd
if (destinationStack
&& !stack->hasBonusOfType(Bonus::BLOCKS_RETALIATION)
&& stackAtEnd->ableToRetaliate()
&& destinationStack->ableToRetaliate()
&& stack->alive()) //attacker may have died (fire shield)
{
BattleAttack bat;
prepareAttack(bat, stackAtEnd, stack, 0, stack->position);
prepareAttack(bat, destinationStack, stack, 0, stack->position);
bat.flags |= BattleAttack::COUNTER;
sendAndApply(&bat);
handleAfterAttackCasting(bat);
@ -3458,7 +3462,6 @@ bool CGameHandler::makeBattleAction( BattleAction &ba )
}
case Battle::SHOOT:
{
const CStack *destStack= gs->curB->battleGetStackByPos(ba.destinationTile);
if( !gs->curB->battleCanShoot(stack, ba.destinationTile) )
{
complain("Cannot shoot!");
@ -3471,7 +3474,7 @@ bool CGameHandler::makeBattleAction( BattleAction &ba )
{
BattleAttack bat;
bat.flags |= BattleAttack::SHOT;
prepareAttack(bat, stack, destStack, 0, ba.destinationTile);
prepareAttack(bat, stack, destinationStack, 0, ba.destinationTile);
handleAttackBeforeCasting(bat);
sendAndApply(&bat);
handleAfterAttackCasting(bat);
@ -3481,14 +3484,14 @@ bool CGameHandler::makeBattleAction( BattleAction &ba )
const CGHeroInstance * attackingHero = gs->curB->battleGetFightingHero(ba.side);
if( destStack->alive()
if( destinationStack->alive()
&& (stack->getCreature()->idNumber == CreatureID::BALLISTA)
&& (attackingHero->getSecSkillLevel(SecondarySkill::ARTILLERY) >= SecSkillLevel::ADVANCED)
)
{
BattleAttack bat2;
bat2.flags |= BattleAttack::SHOT;
prepareAttack(bat2, stack, destStack, 0, ba.destinationTile);
prepareAttack(bat2, stack, destinationStack, 0, ba.destinationTile);
sendAndApply(&bat2);
}
//allow more than one additional attack
@ -3499,13 +3502,13 @@ bool CGameHandler::makeBattleAction( BattleAction &ba )
{
if(
stack->alive()
&& destStack->alive()
&& destinationStack->alive()
&& stack->shots
)
{
BattleAttack bat;
bat.flags |= BattleAttack::SHOT;
prepareAttack(bat, stack, destStack, 0, ba.destinationTile);
prepareAttack(bat, stack, destinationStack, 0, ba.destinationTile);
sendAndApply(&bat);
handleAfterAttackCasting(bat);
}