فهرست منبع

* INFINITE_DIST is now enum, it should cause least trouble that way. Uh, it's so hard to fight magic values these days.
* Fixed crashes in battles after loading game
* Fixed crash in battle AI, when stack is blocked and stands next to an enemy
* Fixes problem when server's moveStack is called with dest==position
* Above should cover #1053.

Michał W. Urbańczyk 13 سال پیش
والد
کامیت
7c09f73402
5فایلهای تغییر یافته به همراه51 افزوده شده و 42 حذف شده
  1. 4 2
      AI/StupidAI/StupidAI.cpp
  2. 1 1
      client/Client.cpp
  3. 1 1
      lib/CBattleCallback.cpp
  4. 6 6
      lib/CBattleCallback.h
  5. 39 32
      server/CGameHandler.cpp

+ 4 - 2
AI/StupidAI/StupidAI.cpp

@@ -98,7 +98,6 @@ BattleAction CStupidAI::activeStack( const CStack * stack )
 {
 	//boost::this_thread::sleep(boost::posix_time::seconds(2));
 	print("activeStack called for " + stack->nodeName());
-	std::vector<BattleHex> avHexes = cb->battleGetAvailableHexes(stack, false);
 	auto dists = cb->battleGetDistances(stack);
 	std::vector<EnemyInfo> enemiesShootable, enemiesReachable, enemiesUnreachable;
 
@@ -123,6 +122,9 @@ BattleAction CStupidAI::activeStack( const CStack * stack )
 		}
 		else
 		{
+			std::vector<BattleHex> avHexes = cb->battleGetAvailableHexes(stack, false);
+			boost::copy(stack->getHexes(), std::back_inserter(avHexes)); //add current stack position - we can attack from it
+
 			BOOST_FOREACH(BattleHex hex, avHexes)
 			{
 				if(CStack::isMeleeAttackPossible(stack, s, hex))
@@ -156,7 +158,7 @@ BattleAction CStupidAI::activeStack( const CStack * stack )
 	else
 	{
 		const EnemyInfo &ei= *std::min_element(enemiesUnreachable.begin(), enemiesUnreachable.end(), boost::bind(isCloser, _1, _2, boost::ref(dists)));
-		if(distToNearestNeighbour(ei.s->position, dists) < GameConstants::BFIELD_SIZE) //FIXME: rare crash when AI attacks banks
+		if(distToNearestNeighbour(ei.s->position, dists) < GameConstants::BFIELD_SIZE)
 		{
 			return goTowards(stack, ei.s->position);
 		}

+ 1 - 1
client/Client.cpp

@@ -473,7 +473,7 @@ void CClient::serialize( Handler &h, const int version )
 			else
 				nInt = new CPlayerInterface(pid);
 
-			callbacks[pid] = make_shared<CCallback>(gs,pid,this);
+			battleCallbacks[pid] = callbacks[pid] = make_shared<CCallback>(gs,pid,this);
 			battleints[pid] = playerint[pid] = nInt;
 			nInt->init(callbacks[pid].get());
 			nInt->serialize(h, version);

+ 1 - 1
lib/CBattleCallback.cpp

@@ -1086,7 +1086,7 @@ ReachabilityInfo CBattleInfoCallback::makeBFS(const AccessibilityInfo &accessibi
 	ret.params = params;
 
 	ret.predecessors.fill(BattleHex::INVALID);
-	ret.distances.fill(static_cast<int>(ReachabilityInfo::INFINITE_DIST));
+	ret.distances.fill(ReachabilityInfo::INFINITE_DIST);
 
 	const std::set<BattleHex> quicksands = getStoppers(params.perspective);
 	//const bool twoHexCreature = params.doubleWide;

+ 6 - 6
lib/CBattleCallback.h

@@ -36,10 +36,10 @@ protected:
 	int player; // -1 gives access to all information, otherwise callback provides only information "visible" for player
 
 	CCallbackBase(CGameState *GS, int Player)
-		: gs(GS), player(Player)
+		: gs(GS), player(Player), battle(nullptr)
 	{}
 	CCallbackBase()
-		: gs(NULL), player(-1)
+		: gs(NULL), player(-1), battle(nullptr)
 	{}
 	
 	void setBattle(const BattleInfo *B);
@@ -104,7 +104,7 @@ struct DLL_LINKAGE ReachabilityInfo
 	typedef std::array<int, GameConstants::BFIELD_SIZE> TDistances;
 	typedef std::array<BattleHex, GameConstants::BFIELD_SIZE> TPredecessors;
 
-	static const int INFINITE_DIST = 1000000;
+	enum { 	INFINITE_DIST = 1000000 };
 
 	struct DLL_LINKAGE Parameters
 	{
@@ -128,7 +128,7 @@ struct DLL_LINKAGE ReachabilityInfo
 
 	ReachabilityInfo()
 	{
-		distances.fill(static_cast<int>(INFINITE_DIST));
+		distances.fill(INFINITE_DIST);
 		predecessors.fill(BattleHex::INVALID);
 	}
 
@@ -191,8 +191,8 @@ public:
 	void battleGetStackQueue(std::vector<const CStack *> &out, const int howMany, const int turn = 0, int lastMoved = -1) const;
 	void battleGetStackCountOutsideHexes(bool *ac) const; // returns hexes which when in front of a stack cause us to move the amount box back
 
-	//void getStackQueue( std::vector<const CStack *> &out, int howMany ) const; //returns vector of stack in order of their move sequence
-	std::vector<BattleHex> battleGetAvailableHexes(const CStack * stack, bool addOccupiable, std::vector<BattleHex> * attackable = NULL) const; //returns numbers of hexes reachable by creature with id ID
+
+	std::vector<BattleHex> battleGetAvailableHexes(const CStack * stack, bool addOccupiable, std::vector<BattleHex> * attackable = NULL) const; //returns hexes reachable by creature with id ID (valid movement destinations), does not contain stack current position
 
 	int battleGetSurrenderCost(int 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 = NULL) const; //returns vector of distances to [dest hex number]

+ 39 - 32
server/CGameHandler.cpp

@@ -935,6 +935,9 @@ int CGameHandler::moveStack(int stack, BattleHex dest)
 		assert(gs->curB->isInTacticRange(dest));
 	}
 
+	if(curStack->position == dest)
+		return 0;
+
 	//initing necessary tables
 	auto accessibility = getAccesibility();
 
@@ -3255,7 +3258,10 @@ bool CGameHandler::makeBattleAction( BattleAction &ba )
 		{
 			StartAction start_action(ba);
 			sendAndApply(&start_action); //start movement
-			moveStack(ba.stackNumber,ba.destinationTile); //move
+			int walkedTiles = moveStack(ba.stackNumber,ba.destinationTile); //move
+			if(!walkedTiles)
+				complain("Stack failed movement!");
+
 			sendAndApply(&end_action);
 			break;
 		}
@@ -3306,26 +3312,25 @@ bool CGameHandler::makeBattleAction( BattleAction &ba )
 		{
 			StartAction start_action(ba);
 			sendAndApply(&start_action); //start movement and attack
-			int startingPos = gs->curB->battleGetStackByID(ba.stackNumber)->position;
+			int startingPos = stack->position;
 			int distance = moveStack(ba.stackNumber, ba.destinationTile);
-			const CStack *curStack = gs->curB->battleGetStackByID(ba.stackNumber),
-				*stackAtEnd = gs->curB->battleGetStackByPos(ba.additionalInfo);
+			const CStack *stackAtEnd = gs->curB->battleGetStackByPos(ba.additionalInfo);
 
-			if(!curStack || !stackAtEnd)
+			if(!stack || !stackAtEnd)
 			{
 				sendAndApply(&end_action);
 				break;
 			}
 
-			tlog5 << curStack->nodeName() << " will attack " << stackAtEnd->nodeName() << std::endl;
+			tlog5 << stack->nodeName() << " will attack " << stackAtEnd->nodeName() << std::endl;
 
-			if(curStack->position != ba.destinationTile //we wasn't able to reach destination tile
-				&& !(curStack->doubleWide()
-					&&  ( curStack->position == ba.destinationTile + (curStack->attackerOwned ?  +1 : -1 ) )
+			if(stack->position != ba.destinationTile //we wasn't able to reach destination tile
+				&& !(stack->doubleWide()
+					&&  ( stack->position == ba.destinationTile + (stack->attackerOwned ?  +1 : -1 ) )
 						) //nor occupy specified hex
 				)
 			{
-				std::string problem = "We cannot move this stack to its destination " + curStack->getCreature()->namePl;
+				std::string problem = "We cannot move this stack to its destination " + stack->getCreature()->namePl;
 				tlog3 << problem << std::endl;
 				complain(problem);
 				ok = false;
@@ -3333,7 +3338,7 @@ bool CGameHandler::makeBattleAction( BattleAction &ba )
 				break;
 			}
 
-			if(stackAtEnd && curStack->ID == stackAtEnd->ID) //we should just move, it will be handled by following check
+			if(stackAtEnd && stack->ID == stackAtEnd->ID) //we should just move, it will be handled by following check
 			{
 				stackAtEnd = NULL;
 			}
@@ -3346,7 +3351,7 @@ bool CGameHandler::makeBattleAction( BattleAction &ba )
 				break;
 			}
 
-			if( !CStack::isMeleeAttackPossible(curStack, stackAtEnd) )
+			if( !CStack::isMeleeAttackPossible(stack, stackAtEnd) )
 			{
 				complain("Attack cannot be performed!");
 				sendAndApply(&end_action);
@@ -3357,39 +3362,39 @@ bool CGameHandler::makeBattleAction( BattleAction &ba )
 			//attack
 			{
 				BattleAttack bat;
-				prepareAttack(bat, curStack, stackAtEnd, distance, ba.additionalInfo);
+				prepareAttack(bat, stack, stackAtEnd, distance, ba.additionalInfo);
 				handleAttackBeforeCasting(bat); //only before first attack
 				sendAndApply(&bat);
 				handleAfterAttackCasting(bat);
 			}
 
 			//counterattack
-			if(!curStack->hasBonusOfType(Bonus::BLOCKS_RETALIATION)
+			if(!stack->hasBonusOfType(Bonus::BLOCKS_RETALIATION)
 				&& stackAtEnd->ableToRetaliate()
-				&& curStack->alive()) //attacker may have died (fire shield)
+				&& stack->alive()) //attacker may have died (fire shield)
 			{
 				BattleAttack bat;
-				prepareAttack(bat, stackAtEnd, curStack, 0, curStack->position);
+				prepareAttack(bat, stackAtEnd, stack, 0, stack->position);
 				bat.flags |= BattleAttack::COUNTER;
 				sendAndApply(&bat);
 				handleAfterAttackCasting(bat);
 			}
 
 			//second attack
-			if(curStack //FIXME: clones tend to dissapear during actions
-				&& curStack->valOfBonuses(Bonus::ADDITIONAL_ATTACK) > 0
-				&& !curStack->hasBonusOfType(Bonus::SHOOTER)
-				&& curStack->alive()
+			if(stack //FIXME: clones tend to dissapear during actions
+				&& stack->valOfBonuses(Bonus::ADDITIONAL_ATTACK) > 0
+				&& !stack->hasBonusOfType(Bonus::SHOOTER)
+				&& stack->alive()
 				&& stackAtEnd->alive()  )
 			{
 				BattleAttack bat;
-				prepareAttack(bat, curStack, stackAtEnd, 0, ba.additionalInfo);
+				prepareAttack(bat, stack, stackAtEnd, 0, ba.additionalInfo);
 				sendAndApply(&bat);
 				handleAfterAttackCasting(bat);
 			}
 
 			//return
-			if(curStack->hasBonusOfType(Bonus::RETURN_AFTER_STRIKE) && startingPos != curStack->position && curStack->alive())
+			if(stack->hasBonusOfType(Bonus::RETURN_AFTER_STRIKE) && startingPos != stack->position && stack->alive())
 			{
 				moveStack(ba.stackNumber, startingPos);
 				//NOTE: curStack->ID == ba.stackNumber (rev 1431)
@@ -3399,10 +3404,12 @@ bool CGameHandler::makeBattleAction( BattleAction &ba )
 		}
 	case BattleAction::SHOOT: //shoot
 		{
-			const CStack *curStack = gs->curB->battleGetStackByID(ba.stackNumber),
-				*destStack= gs->curB->battleGetStackByPos(ba.destinationTile);
-			if( !gs->curB->battleCanShoot(curStack, ba.destinationTile) )
+			const CStack *destStack= gs->curB->battleGetStackByPos(ba.destinationTile);
+			if( !gs->curB->battleCanShoot(stack, ba.destinationTile) )
+			{
+				complain("Cannot shoot!");
 				break;
+			}
 
 			StartAction start_action(ba);
 			sendAndApply(&start_action); //start shooting
@@ -3410,30 +3417,30 @@ bool CGameHandler::makeBattleAction( BattleAction &ba )
 			{
 				BattleAttack bat;
 				bat.flags |= BattleAttack::SHOT;
-				prepareAttack(bat, curStack, destStack, 0, ba.destinationTile);
+				prepareAttack(bat, stack, destStack, 0, ba.destinationTile);
 				handleAttackBeforeCasting(bat);
 				sendAndApply(&bat);
 				handleAfterAttackCasting(bat);
 			}
 
 			//ballista & artillery handling
-			if(destStack->alive() && curStack->getCreature()->idNumber == 146)
+			if(destStack->alive() && stack->getCreature()->idNumber == 146)
 			{
 				BattleAttack bat2;
 				bat2.flags |= BattleAttack::SHOT;
-				prepareAttack(bat2, curStack, destStack, 0, ba.destinationTile);
+				prepareAttack(bat2, stack, destStack, 0, ba.destinationTile);
 				sendAndApply(&bat2);
 			}
 			//TODO: allow more than one additional attack
-			if(curStack->valOfBonuses(Bonus::ADDITIONAL_ATTACK) > 0 //if unit shots twice let's make another shot
-				&& curStack->alive()
+			if(stack->valOfBonuses(Bonus::ADDITIONAL_ATTACK) > 0 //if unit shots twice let's make another shot
+				&& stack->alive()
 				&& destStack->alive()
-				&& curStack->shots
+				&& stack->shots
 				)
 			{
 				BattleAttack bat;
 				bat.flags |= BattleAttack::SHOT;
-				prepareAttack(bat, curStack, destStack, 0, ba.destinationTile);
+				prepareAttack(bat, stack, destStack, 0, ba.destinationTile);
 				sendAndApply(&bat);
 				handleAfterAttackCasting(bat);
 			}