Browse Source

The battle callback method battleGetAllStacks will by default omit the arrow turrets. Fixes #1453, #1455 and related.

Michał W. Urbańczyk 12 years ago
parent
commit
4f29b526ca

+ 3 - 1
client/battle/CBattleAnimations.cpp

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

+ 2 - 2
client/battle/CBattleInterface.cpp

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

+ 8 - 5
lib/CBattleCallback.cpp

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

+ 1 - 1
lib/CBattleCallback.h

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

+ 24 - 21
server/CGameHandler.cpp

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