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), : CBattleAnimation(owner),
myAnim(owner->creAnims[stack->ID]), myAnim(owner->creAnims[stack->ID]),
stack(stack) stack(stack)
{} {
assert(myAnim);
}
void CAttackAnimation::nextFrame() void CAttackAnimation::nextFrame()
{ {

View File

@ -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)
{ {

View File

@ -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

View File

@ -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

View File

@ -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);
} }