mirror of
https://github.com/vcmi/vcmi.git
synced 2025-06-23 00:28:08 +02:00
* 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.
This commit is contained in:
@ -98,7 +98,6 @@ BattleAction CStupidAI::activeStack( const CStack * stack )
|
|||||||
{
|
{
|
||||||
//boost::this_thread::sleep(boost::posix_time::seconds(2));
|
//boost::this_thread::sleep(boost::posix_time::seconds(2));
|
||||||
print("activeStack called for " + stack->nodeName());
|
print("activeStack called for " + stack->nodeName());
|
||||||
std::vector<BattleHex> avHexes = cb->battleGetAvailableHexes(stack, false);
|
|
||||||
auto dists = cb->battleGetDistances(stack);
|
auto dists = cb->battleGetDistances(stack);
|
||||||
std::vector<EnemyInfo> enemiesShootable, enemiesReachable, enemiesUnreachable;
|
std::vector<EnemyInfo> enemiesShootable, enemiesReachable, enemiesUnreachable;
|
||||||
|
|
||||||
@ -123,6 +122,9 @@ BattleAction CStupidAI::activeStack( const CStack * stack )
|
|||||||
}
|
}
|
||||||
else
|
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)
|
BOOST_FOREACH(BattleHex hex, avHexes)
|
||||||
{
|
{
|
||||||
if(CStack::isMeleeAttackPossible(stack, s, hex))
|
if(CStack::isMeleeAttackPossible(stack, s, hex))
|
||||||
@ -156,7 +158,7 @@ BattleAction CStupidAI::activeStack( const CStack * stack )
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
const EnemyInfo &ei= *std::min_element(enemiesUnreachable.begin(), enemiesUnreachable.end(), boost::bind(isCloser, _1, _2, boost::ref(dists)));
|
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);
|
return goTowards(stack, ei.s->position);
|
||||||
}
|
}
|
||||||
|
@ -473,7 +473,7 @@ void CClient::serialize( Handler &h, const int version )
|
|||||||
else
|
else
|
||||||
nInt = new CPlayerInterface(pid);
|
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;
|
battleints[pid] = playerint[pid] = nInt;
|
||||||
nInt->init(callbacks[pid].get());
|
nInt->init(callbacks[pid].get());
|
||||||
nInt->serialize(h, version);
|
nInt->serialize(h, version);
|
||||||
|
@ -1086,7 +1086,7 @@ ReachabilityInfo CBattleInfoCallback::makeBFS(const AccessibilityInfo &accessibi
|
|||||||
ret.params = params;
|
ret.params = params;
|
||||||
|
|
||||||
ret.predecessors.fill(BattleHex::INVALID);
|
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 std::set<BattleHex> quicksands = getStoppers(params.perspective);
|
||||||
//const bool twoHexCreature = params.doubleWide;
|
//const bool twoHexCreature = params.doubleWide;
|
||||||
|
@ -36,10 +36,10 @@ protected:
|
|||||||
int player; // -1 gives access to all information, otherwise callback provides only information "visible" for player
|
int player; // -1 gives access to all information, otherwise callback provides only information "visible" for player
|
||||||
|
|
||||||
CCallbackBase(CGameState *GS, int Player)
|
CCallbackBase(CGameState *GS, int Player)
|
||||||
: gs(GS), player(Player)
|
: gs(GS), player(Player), battle(nullptr)
|
||||||
{}
|
{}
|
||||||
CCallbackBase()
|
CCallbackBase()
|
||||||
: gs(NULL), player(-1)
|
: gs(NULL), player(-1), battle(nullptr)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
void setBattle(const BattleInfo *B);
|
void setBattle(const BattleInfo *B);
|
||||||
@ -104,7 +104,7 @@ struct DLL_LINKAGE ReachabilityInfo
|
|||||||
typedef std::array<int, GameConstants::BFIELD_SIZE> TDistances;
|
typedef std::array<int, GameConstants::BFIELD_SIZE> TDistances;
|
||||||
typedef std::array<BattleHex, GameConstants::BFIELD_SIZE> TPredecessors;
|
typedef std::array<BattleHex, GameConstants::BFIELD_SIZE> TPredecessors;
|
||||||
|
|
||||||
static const int INFINITE_DIST = 1000000;
|
enum { INFINITE_DIST = 1000000 };
|
||||||
|
|
||||||
struct DLL_LINKAGE Parameters
|
struct DLL_LINKAGE Parameters
|
||||||
{
|
{
|
||||||
@ -128,7 +128,7 @@ struct DLL_LINKAGE ReachabilityInfo
|
|||||||
|
|
||||||
ReachabilityInfo()
|
ReachabilityInfo()
|
||||||
{
|
{
|
||||||
distances.fill(static_cast<int>(INFINITE_DIST));
|
distances.fill(INFINITE_DIST);
|
||||||
predecessors.fill(BattleHex::INVALID);
|
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 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 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
|
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]
|
ReachabilityInfo::TDistances battleGetDistances(const CStack * stack, BattleHex hex = BattleHex::INVALID, BattleHex * predecessors = NULL) const; //returns vector of distances to [dest hex number]
|
||||||
|
@ -935,6 +935,9 @@ int CGameHandler::moveStack(int stack, BattleHex dest)
|
|||||||
assert(gs->curB->isInTacticRange(dest));
|
assert(gs->curB->isInTacticRange(dest));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(curStack->position == dest)
|
||||||
|
return 0;
|
||||||
|
|
||||||
//initing necessary tables
|
//initing necessary tables
|
||||||
auto accessibility = getAccesibility();
|
auto accessibility = getAccesibility();
|
||||||
|
|
||||||
@ -3255,7 +3258,10 @@ bool CGameHandler::makeBattleAction( BattleAction &ba )
|
|||||||
{
|
{
|
||||||
StartAction start_action(ba);
|
StartAction start_action(ba);
|
||||||
sendAndApply(&start_action); //start movement
|
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);
|
sendAndApply(&end_action);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -3306,26 +3312,25 @@ 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
|
||||||
int startingPos = gs->curB->battleGetStackByID(ba.stackNumber)->position;
|
int startingPos = stack->position;
|
||||||
int distance = moveStack(ba.stackNumber, ba.destinationTile);
|
int distance = moveStack(ba.stackNumber, ba.destinationTile);
|
||||||
const CStack *curStack = gs->curB->battleGetStackByID(ba.stackNumber),
|
const CStack *stackAtEnd = gs->curB->battleGetStackByPos(ba.additionalInfo);
|
||||||
*stackAtEnd = gs->curB->battleGetStackByPos(ba.additionalInfo);
|
|
||||||
|
|
||||||
if(!curStack || !stackAtEnd)
|
if(!stack || !stackAtEnd)
|
||||||
{
|
{
|
||||||
sendAndApply(&end_action);
|
sendAndApply(&end_action);
|
||||||
break;
|
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
|
if(stack->position != ba.destinationTile //we wasn't able to reach destination tile
|
||||||
&& !(curStack->doubleWide()
|
&& !(stack->doubleWide()
|
||||||
&& ( curStack->position == ba.destinationTile + (curStack->attackerOwned ? +1 : -1 ) )
|
&& ( stack->position == ba.destinationTile + (stack->attackerOwned ? +1 : -1 ) )
|
||||||
) //nor occupy specified hex
|
) //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;
|
tlog3 << problem << std::endl;
|
||||||
complain(problem);
|
complain(problem);
|
||||||
ok = false;
|
ok = false;
|
||||||
@ -3333,7 +3338,7 @@ bool CGameHandler::makeBattleAction( BattleAction &ba )
|
|||||||
break;
|
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;
|
stackAtEnd = NULL;
|
||||||
}
|
}
|
||||||
@ -3346,7 +3351,7 @@ bool CGameHandler::makeBattleAction( BattleAction &ba )
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( !CStack::isMeleeAttackPossible(curStack, stackAtEnd) )
|
if( !CStack::isMeleeAttackPossible(stack, stackAtEnd) )
|
||||||
{
|
{
|
||||||
complain("Attack cannot be performed!");
|
complain("Attack cannot be performed!");
|
||||||
sendAndApply(&end_action);
|
sendAndApply(&end_action);
|
||||||
@ -3357,39 +3362,39 @@ bool CGameHandler::makeBattleAction( BattleAction &ba )
|
|||||||
//attack
|
//attack
|
||||||
{
|
{
|
||||||
BattleAttack bat;
|
BattleAttack bat;
|
||||||
prepareAttack(bat, curStack, stackAtEnd, distance, ba.additionalInfo);
|
prepareAttack(bat, stack, stackAtEnd, distance, ba.additionalInfo);
|
||||||
handleAttackBeforeCasting(bat); //only before first attack
|
handleAttackBeforeCasting(bat); //only before first attack
|
||||||
sendAndApply(&bat);
|
sendAndApply(&bat);
|
||||||
handleAfterAttackCasting(bat);
|
handleAfterAttackCasting(bat);
|
||||||
}
|
}
|
||||||
|
|
||||||
//counterattack
|
//counterattack
|
||||||
if(!curStack->hasBonusOfType(Bonus::BLOCKS_RETALIATION)
|
if(!stack->hasBonusOfType(Bonus::BLOCKS_RETALIATION)
|
||||||
&& stackAtEnd->ableToRetaliate()
|
&& stackAtEnd->ableToRetaliate()
|
||||||
&& curStack->alive()) //attacker may have died (fire shield)
|
&& stack->alive()) //attacker may have died (fire shield)
|
||||||
{
|
{
|
||||||
BattleAttack bat;
|
BattleAttack bat;
|
||||||
prepareAttack(bat, stackAtEnd, curStack, 0, curStack->position);
|
prepareAttack(bat, stackAtEnd, stack, 0, stack->position);
|
||||||
bat.flags |= BattleAttack::COUNTER;
|
bat.flags |= BattleAttack::COUNTER;
|
||||||
sendAndApply(&bat);
|
sendAndApply(&bat);
|
||||||
handleAfterAttackCasting(bat);
|
handleAfterAttackCasting(bat);
|
||||||
}
|
}
|
||||||
|
|
||||||
//second attack
|
//second attack
|
||||||
if(curStack //FIXME: clones tend to dissapear during actions
|
if(stack //FIXME: clones tend to dissapear during actions
|
||||||
&& curStack->valOfBonuses(Bonus::ADDITIONAL_ATTACK) > 0
|
&& stack->valOfBonuses(Bonus::ADDITIONAL_ATTACK) > 0
|
||||||
&& !curStack->hasBonusOfType(Bonus::SHOOTER)
|
&& !stack->hasBonusOfType(Bonus::SHOOTER)
|
||||||
&& curStack->alive()
|
&& stack->alive()
|
||||||
&& stackAtEnd->alive() )
|
&& stackAtEnd->alive() )
|
||||||
{
|
{
|
||||||
BattleAttack bat;
|
BattleAttack bat;
|
||||||
prepareAttack(bat, curStack, stackAtEnd, 0, ba.additionalInfo);
|
prepareAttack(bat, stack, stackAtEnd, 0, ba.additionalInfo);
|
||||||
sendAndApply(&bat);
|
sendAndApply(&bat);
|
||||||
handleAfterAttackCasting(bat);
|
handleAfterAttackCasting(bat);
|
||||||
}
|
}
|
||||||
|
|
||||||
//return
|
//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);
|
moveStack(ba.stackNumber, startingPos);
|
||||||
//NOTE: curStack->ID == ba.stackNumber (rev 1431)
|
//NOTE: curStack->ID == ba.stackNumber (rev 1431)
|
||||||
@ -3399,10 +3404,12 @@ bool CGameHandler::makeBattleAction( BattleAction &ba )
|
|||||||
}
|
}
|
||||||
case BattleAction::SHOOT: //shoot
|
case BattleAction::SHOOT: //shoot
|
||||||
{
|
{
|
||||||
const CStack *curStack = gs->curB->battleGetStackByID(ba.stackNumber),
|
const CStack *destStack= gs->curB->battleGetStackByPos(ba.destinationTile);
|
||||||
*destStack= gs->curB->battleGetStackByPos(ba.destinationTile);
|
if( !gs->curB->battleCanShoot(stack, ba.destinationTile) )
|
||||||
if( !gs->curB->battleCanShoot(curStack, ba.destinationTile) )
|
{
|
||||||
|
complain("Cannot shoot!");
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
StartAction start_action(ba);
|
StartAction start_action(ba);
|
||||||
sendAndApply(&start_action); //start shooting
|
sendAndApply(&start_action); //start shooting
|
||||||
@ -3410,30 +3417,30 @@ bool CGameHandler::makeBattleAction( BattleAction &ba )
|
|||||||
{
|
{
|
||||||
BattleAttack bat;
|
BattleAttack bat;
|
||||||
bat.flags |= BattleAttack::SHOT;
|
bat.flags |= BattleAttack::SHOT;
|
||||||
prepareAttack(bat, curStack, destStack, 0, ba.destinationTile);
|
prepareAttack(bat, stack, destStack, 0, ba.destinationTile);
|
||||||
handleAttackBeforeCasting(bat);
|
handleAttackBeforeCasting(bat);
|
||||||
sendAndApply(&bat);
|
sendAndApply(&bat);
|
||||||
handleAfterAttackCasting(bat);
|
handleAfterAttackCasting(bat);
|
||||||
}
|
}
|
||||||
|
|
||||||
//ballista & artillery handling
|
//ballista & artillery handling
|
||||||
if(destStack->alive() && curStack->getCreature()->idNumber == 146)
|
if(destStack->alive() && stack->getCreature()->idNumber == 146)
|
||||||
{
|
{
|
||||||
BattleAttack bat2;
|
BattleAttack bat2;
|
||||||
bat2.flags |= BattleAttack::SHOT;
|
bat2.flags |= BattleAttack::SHOT;
|
||||||
prepareAttack(bat2, curStack, destStack, 0, ba.destinationTile);
|
prepareAttack(bat2, stack, destStack, 0, ba.destinationTile);
|
||||||
sendAndApply(&bat2);
|
sendAndApply(&bat2);
|
||||||
}
|
}
|
||||||
//TODO: allow more than one additional attack
|
//TODO: allow more than one additional attack
|
||||||
if(curStack->valOfBonuses(Bonus::ADDITIONAL_ATTACK) > 0 //if unit shots twice let's make another shot
|
if(stack->valOfBonuses(Bonus::ADDITIONAL_ATTACK) > 0 //if unit shots twice let's make another shot
|
||||||
&& curStack->alive()
|
&& stack->alive()
|
||||||
&& destStack->alive()
|
&& destStack->alive()
|
||||||
&& curStack->shots
|
&& stack->shots
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
BattleAttack bat;
|
BattleAttack bat;
|
||||||
bat.flags |= BattleAttack::SHOT;
|
bat.flags |= BattleAttack::SHOT;
|
||||||
prepareAttack(bat, curStack, destStack, 0, ba.destinationTile);
|
prepareAttack(bat, stack, destStack, 0, ba.destinationTile);
|
||||||
sendAndApply(&bat);
|
sendAndApply(&bat);
|
||||||
handleAfterAttackCasting(bat);
|
handleAfterAttackCasting(bat);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user