mirror of
https://github.com/vcmi/vcmi.git
synced 2025-08-13 19:54:17 +02:00
* fixed possible corruption of pack sent by server when player request is rejected
* BattleAI will restore callback to its previous state, fixes freeze after battle #1104 * BattleAI won't lose turn when unable to correctly evaluate a spell * VCAI will correctly recognize hero standing on town entrance * War machines of defender will have correctly set side * Faction 9 as neutral causes crashes, changing to -1 as used elsewhere in the code
This commit is contained in:
@@ -70,6 +70,10 @@ CBattleAI::CBattleAI(void)
|
|||||||
CBattleAI::~CBattleAI(void)
|
CBattleAI::~CBattleAI(void)
|
||||||
{
|
{
|
||||||
print("destroyed");
|
print("destroyed");
|
||||||
|
|
||||||
|
//Restore previous state of CB - it may be shared with the main AI (like VCAI)
|
||||||
|
cb->waitTillRealize = wasWaitingForRealize;
|
||||||
|
cb->unlockGsWhenWaiting = wasUnlockingGs;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CBattleAI::init( CBattleCallback * CB )
|
void CBattleAI::init( CBattleCallback * CB )
|
||||||
@@ -77,6 +81,9 @@ void CBattleAI::init( CBattleCallback * CB )
|
|||||||
print("init called, saving ptr to IBattleCallback");
|
print("init called, saving ptr to IBattleCallback");
|
||||||
cbc = cb = CB;
|
cbc = cb = CB;
|
||||||
playerID = CB->getPlayerID();; //TODO should be sth in callback
|
playerID = CB->getPlayerID();; //TODO should be sth in callback
|
||||||
|
|
||||||
|
wasWaitingForRealize = cb->waitTillRealize;
|
||||||
|
wasUnlockingGs = CB->unlockGsWhenWaiting;
|
||||||
CB->waitTillRealize = true;
|
CB->waitTillRealize = true;
|
||||||
CB->unlockGsWhenWaiting = false;
|
CB->unlockGsWhenWaiting = false;
|
||||||
}
|
}
|
||||||
@@ -322,6 +329,14 @@ struct PotentialTargets
|
|||||||
|
|
||||||
return *vstd::maxElementByFun(possibleAttacks, [](const AttackPossibility &ap) { return ap.damageDiff(); } );
|
return *vstd::maxElementByFun(possibleAttacks, [](const AttackPossibility &ap) { return ap.damageDiff(); } );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int bestActionValue() const
|
||||||
|
{
|
||||||
|
if(possibleAttacks.empty())
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return bestAction().damageDiff();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
BattleAction CBattleAI::activeStack( const CStack * stack )
|
BattleAction CBattleAI::activeStack( const CStack * stack )
|
||||||
@@ -335,6 +350,12 @@ BattleAction CBattleAI::activeStack( const CStack * stack )
|
|||||||
if(cb->battleCanCastSpell())
|
if(cb->battleCanCastSpell())
|
||||||
attemptCastingSpell();
|
attemptCastingSpell();
|
||||||
|
|
||||||
|
if(cb->battleGetStacks(CBattleInfoEssentials::ONLY_ENEMY).empty())
|
||||||
|
{
|
||||||
|
//We apparently won battle by casting spell, return defend... (accessing cb may cause trouble)
|
||||||
|
return BattleAction::makeDefend(stack);
|
||||||
|
}
|
||||||
|
|
||||||
ThreatMap threatsToUs(stack);
|
ThreatMap threatsToUs(stack);
|
||||||
PotentialTargets targets(stack);
|
PotentialTargets targets(stack);
|
||||||
|
|
||||||
@@ -673,7 +694,7 @@ void CBattleAI::attemptCastingSpell()
|
|||||||
BOOST_FOREACH(auto stack, cb->battleGetStacks())
|
BOOST_FOREACH(auto stack, cb->battleGetStacks())
|
||||||
{
|
{
|
||||||
PotentialTargets pt(stack);
|
PotentialTargets pt(stack);
|
||||||
valueOfStack[stack] = pt.bestAction().attackValue();
|
valueOfStack[stack] = pt.bestActionValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto evaluateSpellcast = [&] (const PossibleSpellcast &ps) -> int
|
auto evaluateSpellcast = [&] (const PossibleSpellcast &ps) -> int
|
||||||
@@ -730,7 +751,7 @@ void CBattleAI::attemptCastingSpell()
|
|||||||
state.bonusesOfStacks[swb.stack] = &swb;
|
state.bonusesOfStacks[swb.stack] = &swb;
|
||||||
|
|
||||||
PotentialTargets pt(swb.stack, state);
|
PotentialTargets pt(swb.stack, state);
|
||||||
auto newValue = pt.bestAction().attackValue();
|
auto newValue = pt.bestActionValue();
|
||||||
auto oldValue = valueOfStack[swb.stack];
|
auto oldValue = valueOfStack[swb.stack];
|
||||||
auto gain = newValue - oldValue;
|
auto gain = newValue - oldValue;
|
||||||
if(swb.stack->owner != playerID) //enemy
|
if(swb.stack->owner != playerID) //enemy
|
||||||
|
@@ -9,6 +9,9 @@ class CBattleAI : public CBattleGameInterface
|
|||||||
int side;
|
int side;
|
||||||
CBattleCallback *cb;
|
CBattleCallback *cb;
|
||||||
|
|
||||||
|
//Previous setting of cb
|
||||||
|
bool wasWaitingForRealize, wasUnlockingGs;
|
||||||
|
|
||||||
void print(const std::string &text) const;
|
void print(const std::string &text) const;
|
||||||
public:
|
public:
|
||||||
CBattleAI(void);
|
CBattleAI(void);
|
||||||
|
@@ -359,7 +359,12 @@ ui64 evaluateDanger(crint3 tile, const CGHeroInstance *visitor)
|
|||||||
|
|
||||||
ui64 objectDanger = 0, guardDanger = 0;
|
ui64 objectDanger = 0, guardDanger = 0;
|
||||||
|
|
||||||
if(const CGObjectInstance * dangerousObject = backOrNull(cb->getVisitableObjs(tile)))
|
auto visitableObjects = cb->getVisitableObjs(tile);
|
||||||
|
// in some scenarios hero happens to be "under" the object (eg town). Then we consider ONLY the hero.
|
||||||
|
if(vstd::contains_if(visitableObjects, objWithID<Obj::HERO>))
|
||||||
|
erase_if(visitableObjects, ! boost::bind(objWithID<Obj::HERO>, _1));
|
||||||
|
|
||||||
|
if(const CGObjectInstance * dangerousObject = backOrNull(visitableObjects))
|
||||||
{
|
{
|
||||||
objectDanger = evaluateDanger(dangerousObject); //unguarded objects can also be dangerous or unhandled
|
objectDanger = evaluateDanger(dangerousObject); //unguarded objects can also be dangerous or unhandled
|
||||||
if (objectDanger)
|
if (objectDanger)
|
||||||
|
@@ -513,7 +513,7 @@ BattleInfo * BattleInfo::setupBattle( int3 tile, int terrain, int battlefieldTyp
|
|||||||
auto handleWarMachine= [&](int side, int artslot, int cretype, int hex)
|
auto handleWarMachine= [&](int side, int artslot, int cretype, int hex)
|
||||||
{
|
{
|
||||||
if(heroes[side] && heroes[side]->getArt(artslot))
|
if(heroes[side] && heroes[side]->getArt(artslot))
|
||||||
stacks.push_back(curB->generateNewStack(CStackBasicDescriptor(cretype, 1), true, 255, hex));
|
stacks.push_back(curB->generateNewStack(CStackBasicDescriptor(cretype, 1), !side, 255, hex));
|
||||||
};
|
};
|
||||||
|
|
||||||
handleWarMachine(0, 13, 146, 52); //ballista
|
handleWarMachine(0, 13, 146, 52); //ballista
|
||||||
|
@@ -123,7 +123,7 @@ CCreature * CModHandler::loadCreature (const JsonNode &node)
|
|||||||
cre->cost = Res::ResourceSet(node["cost"]);
|
cre->cost = Res::ResourceSet(node["cost"]);
|
||||||
|
|
||||||
cre->level = node["level"].Float();
|
cre->level = node["level"].Float();
|
||||||
cre->faction = 9; //neutral faction is 9 for now. Will be replaced by string -> id conversion
|
cre->faction = -1; //neutral faction is 9 for now. Will be replaced by string -> id conversion
|
||||||
//TODO: node["faction"].String() to id
|
//TODO: node["faction"].String() to id
|
||||||
cre->fightValue = node["fightValue"].Float();
|
cre->fightValue = node["fightValue"].Float();
|
||||||
cre->AIValue = node["aiValue"].Float();
|
cre->AIValue = node["aiValue"].Float();
|
||||||
|
@@ -14,6 +14,7 @@
|
|||||||
#define ERROR_AND_RETURN \
|
#define ERROR_AND_RETURN \
|
||||||
do { if(c) { \
|
do { if(c) { \
|
||||||
SystemMessage temp_message("You are not allowed to perform this action!"); \
|
SystemMessage temp_message("You are not allowed to perform this action!"); \
|
||||||
|
boost::unique_lock<boost::mutex> lock(*c->wmx); \
|
||||||
*c << &temp_message; \
|
*c << &temp_message; \
|
||||||
} \
|
} \
|
||||||
tlog1<<"Player is not allowed to perform this action!\n"; \
|
tlog1<<"Player is not allowed to perform this action!\n"; \
|
||||||
@@ -22,7 +23,7 @@
|
|||||||
#define WRONG_PLAYER_MSG(expectedplayer) do {std::ostringstream oss;\
|
#define WRONG_PLAYER_MSG(expectedplayer) do {std::ostringstream oss;\
|
||||||
oss << "You were identified as player " << (int)gh->getPlayerAt(c) << " while expecting " << (int)expectedplayer;\
|
oss << "You were identified as player " << (int)gh->getPlayerAt(c) << " while expecting " << (int)expectedplayer;\
|
||||||
tlog1 << oss.str() << std::endl; \
|
tlog1 << oss.str() << std::endl; \
|
||||||
if(c) { SystemMessage temp_message(oss.str()); *c << &temp_message; } } while(0)
|
if(c) { SystemMessage temp_message(oss.str()); boost::unique_lock<boost::mutex> lock(*c->wmx); *c << &temp_message; } } while(0)
|
||||||
|
|
||||||
#define ERROR_IF_NOT_OWNS(id) do{if(!PLAYER_OWNS(id)){WRONG_PLAYER_MSG(gh->getOwner(id)); ERROR_AND_RETURN; }}while(0)
|
#define ERROR_IF_NOT_OWNS(id) do{if(!PLAYER_OWNS(id)){WRONG_PLAYER_MSG(gh->getOwner(id)); ERROR_AND_RETURN; }}while(0)
|
||||||
#define ERROR_IF_NOT(player) do{if(player != gh->getPlayerAt(c)){WRONG_PLAYER_MSG(player); ERROR_AND_RETURN; }}while(0)
|
#define ERROR_IF_NOT(player) do{if(player != gh->getPlayerAt(c)){WRONG_PLAYER_MSG(player); ERROR_AND_RETURN; }}while(0)
|
||||||
|
Reference in New Issue
Block a user