diff --git a/AI/StupidAI/StupidAI.cpp b/AI/StupidAI/StupidAI.cpp index b6825dbee..1df9b8310 100644 --- a/AI/StupidAI/StupidAI.cpp +++ b/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 avHexes = cb->battleGetAvailableHexes(stack, false); auto dists = cb->battleGetDistances(stack); std::vector enemiesShootable, enemiesReachable, enemiesUnreachable; @@ -123,6 +122,9 @@ BattleAction CStupidAI::activeStack( const CStack * stack ) } else { + std::vector 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); } diff --git a/client/Client.cpp b/client/Client.cpp index 6027a717a..6cbf7bc53 100644 --- a/client/Client.cpp +++ b/client/Client.cpp @@ -473,7 +473,7 @@ void CClient::serialize( Handler &h, const int version ) else nInt = new CPlayerInterface(pid); - callbacks[pid] = make_shared(gs,pid,this); + battleCallbacks[pid] = callbacks[pid] = make_shared(gs,pid,this); battleints[pid] = playerint[pid] = nInt; nInt->init(callbacks[pid].get()); nInt->serialize(h, version); diff --git a/lib/CBattleCallback.cpp b/lib/CBattleCallback.cpp index 77fd98c8f..ef6c81f27 100644 --- a/lib/CBattleCallback.cpp +++ b/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(ReachabilityInfo::INFINITE_DIST)); + ret.distances.fill(ReachabilityInfo::INFINITE_DIST); const std::set quicksands = getStoppers(params.perspective); //const bool twoHexCreature = params.doubleWide; diff --git a/lib/CBattleCallback.h b/lib/CBattleCallback.h index 404638489..534e58b86 100644 --- a/lib/CBattleCallback.h +++ b/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 TDistances; typedef std::array 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(INFINITE_DIST)); + distances.fill(INFINITE_DIST); predecessors.fill(BattleHex::INVALID); } @@ -191,8 +191,8 @@ public: void battleGetStackQueue(std::vector &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 &out, int howMany ) const; //returns vector of stack in order of their move sequence - std::vector battleGetAvailableHexes(const CStack * stack, bool addOccupiable, std::vector * attackable = NULL) const; //returns numbers of hexes reachable by creature with id ID + + std::vector battleGetAvailableHexes(const CStack * stack, bool addOccupiable, std::vector * 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] diff --git a/server/CGameHandler.cpp b/server/CGameHandler.cpp index 9ea78699a..ae08131d4 100644 --- a/server/CGameHandler.cpp +++ b/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); }