1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-11-24 08:32:34 +02:00

* fixed crash related to cammander's SPELL_AFTER_ATTACK spell id not initialized properly (text id was resolved on copy of bonus)

* fixed duels, added no-GUI mode for automatic AI testing
* minor things
This commit is contained in:
Michał W. Urbańczyk 2013-06-17 15:45:55 +00:00
parent 30fb552fb4
commit 6a88604937
20 changed files with 182 additions and 86 deletions

View File

@ -354,15 +354,16 @@ BattleAction CBattleAI::activeStack( const CStack * stack )
if(cb->battleCanCastSpell())
attemptCastingSpell();
if(auto action = considerFleeingOrSurrendering())
return *action;
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);
PotentialTargets targets(stack);
if(targets.possibleAttacks.size())
{
auto hlp = targets.bestAction();
@ -375,6 +376,7 @@ BattleAction CBattleAI::activeStack( const CStack * stack )
{
if(stack->waited())
{
ThreatMap threatsToUs(stack);
auto dists = cbc->battleGetDistances(stack);
const EnemyInfo &ei= *range::min_element(targets.unreachableEnemies, boost::bind(isCloser, _1, _2, boost::ref(dists)));
if(distToNearestNeighbour(ei.s->position, dists) < GameConstants::BFIELD_SIZE)
@ -749,3 +751,16 @@ std::vector<BattleHex> CBattleAI::getTargetsToConsider( const CSpell *spell ) co
return cbc->battleGetPossibleTargets(playerID, spell);
}
}
boost::optional<BattleAction> CBattleAI::considerFleeingOrSurrendering()
{
if(cb->battleCanSurrender(playerID))
{
}
if(cb->battleCanFlee())
{
}
return boost::none;
}

View File

@ -42,6 +42,8 @@ public:
BattleAction goTowards(const CStack * stack, BattleHex hex );
BattleAction useCatapult(const CStack * stack);
boost::optional<BattleAction> considerFleeingOrSurrendering();
void attemptCastingSpell();
std::vector<BattleHex> getTargetsToConsider(const CSpell *spell) const;
};

View File

@ -239,8 +239,8 @@ void CCreatureWindow::init(const CStackInstance *Stack, const CBonusSystemNode *
else
{
selectableSkill->pos = Rect (95, 256, 55, 55); //TODO: scroll
Bonus b = CGI->creh->skillRequirements[option-100].first;
bonusItems.push_back (new CBonusItem (genRect(0, 0, 251, 57), stack->bonusToString(&b, false), stack->bonusToString(&b, true), stack->bonusToGraphics(&b)));
const Bonus *b = CGI->creh->skillRequirements[option-100].first;
bonusItems.push_back (new CBonusItem (genRect(0, 0, 251, 57), stack->bonusToString(b, false), stack->bonusToString(b, true), stack->bonusToGraphics(b)));
selectableBonuses.push_back (selectableSkill); //insert these before other bonuses
}
}

View File

@ -47,6 +47,7 @@
#endif
#include "../lib/CDefObjInfoHandler.h"
#include "../lib/UnlockGuard.h"
#include "CMT.h"
#if __MINGW32__
#undef main
@ -76,6 +77,7 @@ static boost::thread *mainGUIThread;
std::queue<SDL_Event> events;
boost::mutex eventsM;
bool gNoGUI = false;
static bool gOnlyAI = false;
//static bool setResolution = false; //set by event handling thread after resolution is adjusted
@ -146,20 +148,23 @@ void init()
logGlobal->infoStream()<<"Initializing VCMI_Lib: "<<tmh.getDiff();
pomtime.getDiff();
CCS->curh = new CCursorHandler;
graphics = new Graphics(); // should be before curh->init()
if(!gNoGUI)
{
CCS->curh = new CCursorHandler;
graphics = new Graphics(); // should be before curh->init()
CCS->curh->initCursor();
CCS->curh->show();
logGlobal->infoStream()<<"Screen handler: "<<pomtime.getDiff();
pomtime.getDiff();
CCS->curh->initCursor();
CCS->curh->show();
logGlobal->infoStream()<<"Screen handler: "<<pomtime.getDiff();
pomtime.getDiff();
graphics->loadHeroAnims();
logGlobal->infoStream()<<"\tMain graphics: "<<tmh.getDiff();
logGlobal->infoStream()<<"Initializing game graphics: "<<tmh.getDiff();
graphics->loadHeroAnims();
logGlobal->infoStream()<<"\tMain graphics: "<<tmh.getDiff();
logGlobal->infoStream()<<"Initializing game graphics: "<<tmh.getDiff();
CMessage::init();
logGlobal->infoStream()<<"Message handler: "<<tmh.getDiff();
CMessage::init();
logGlobal->infoStream()<<"Message handler: "<<tmh.getDiff();
}
}
static void prog_version(void)
@ -219,7 +224,8 @@ int main(int argc, char** argv)
("version,v", "display version information and exit")
("battle,b", po::value<std::string>(), "runs game in duel mode (battle-only")
("start", po::value<std::string>(), "starts game from saved StartInfo file")
("onlyAI", "runs without GUI, all players will be default AI")
("onlyAI", "runs without human player, all players will be default AI")
("noGUI", "runs without GUI, implies --onlyAI")
("oneGoodAI", "puts one default AI and the rest will be EmptyAI")
("autoSkip", "automatically skip turns in GUI")
("disable-video", "disable video player")
@ -249,6 +255,11 @@ int main(int argc, char** argv)
prog_version();
return 0;
}
if(vm.count("noGUI"))
{
gNoGUI = true;
vm["onlyAI"];
}
//Set environment vars to make window centered. Sometimes work, sometimes not. :/
putenv((char*)"SDL_VIDEO_WINDOW_POS");
@ -303,16 +314,7 @@ int main(int argc, char** argv)
logGlobal->infoStream() << NAME;
srand ( time(NULL) );
CCS = new CClientState;
CGI = new CGameInfo; //contains all global informations about game (texts, lodHandlers, map handler etc.)
if(SDL_Init(SDL_INIT_VIDEO|SDL_INIT_TIMER|SDL_INIT_AUDIO))
{
logGlobal->errorStream()<<"Something was wrong: "<< SDL_GetError();
exit(-1);
}
atexit(SDL_Quit);
const JsonNode& video = settings["video"];
const JsonNode& res = video["screenRes"];
@ -328,15 +330,26 @@ int main(int argc, char** argv)
exit(EXIT_FAILURE);
}
setScreenRes(res["width"].Float(), res["height"].Float(), video["bitsPerPixel"].Float(), video["fullscreen"].Bool());
if(!gNoGUI)
{
if(SDL_Init(SDL_INIT_VIDEO|SDL_INIT_TIMER|SDL_INIT_AUDIO))
{
logGlobal->errorStream()<<"Something was wrong: "<< SDL_GetError();
exit(-1);
}
atexit(SDL_Quit);
setScreenRes(res["width"].Float(), res["height"].Float(), video["bitsPerPixel"].Float(), video["fullscreen"].Bool());
logGlobal->infoStream() <<"\tInitializing screen: "<<pomtime.getDiff();
}
logGlobal->infoStream() <<"\tInitializing screen: "<<pomtime.getDiff();
CCS = new CClientState;
CGI = new CGameInfo; //contains all global informations about game (texts, lodHandlers, map handler etc.)
// Initialize video
#if DISABLE_VIDEO
CCS->videoh = new CEmptyVideoPlayer;
#else
if (!vm.count("disable-video"))
if (!gNoGUI && !vm.count("disable-video"))
CCS->videoh = new CVideoPlayer;
else
CCS->videoh = new CEmptyVideoPlayer;
@ -344,13 +357,18 @@ int main(int argc, char** argv)
logGlobal->infoStream()<<"\tInitializing video: "<<pomtime.getDiff();
//we can properly play intro only in the main thread, so we have to move loading to the separate thread
boost::thread loading(init);
if(!vm.count("battle") && !vm.count("nointro"))
playIntro();
if(!gNoGUI )
{
if(!vm.count("battle") && !vm.count("nointro"))
playIntro();
SDL_FillRect(screen,NULL,0);
}
SDL_FillRect(screen,NULL,0);
CSDL_Ext::update(screen);
loading.join();
logGlobal->infoStream()<<"Initialization of VCMI (together): "<<total.getDiff();
@ -387,8 +405,17 @@ int main(int argc, char** argv)
si->playerInfos[PlayerColor(1)].color = PlayerColor(1);
startGame(si);
}
mainGUIThread = new boost::thread(&CGuiHandler::run, boost::ref(GH));
listenForEvents();
if(!gNoGUI)
{
mainGUIThread = new boost::thread(&CGuiHandler::run, boost::ref(GH));
listenForEvents();
}
else
{
while(true)
boost::this_thread::sleep(boost::posix_time::milliseconds(1000));
}
return 0;
}
@ -822,20 +849,7 @@ static void listenForEvents()
if (ret == 0 || (ev.type==SDL_QUIT) ||
(ev.type == SDL_KEYDOWN && ev.key.keysym.sym==SDLK_F4 && (ev.key.keysym.mod & KMOD_ALT)))
{
if (client)
client->endGame();
if (mainGUIThread)
{
GH.terminate = true;
mainGUIThread->join();
delete mainGUIThread;
mainGUIThread = NULL;
}
delete console;
console = NULL;
SDL_Delay(750);
SDL_Quit();
std::cout << "Ending...";
handleQuit();
break;
}
else if(LOCPLINT && ev.type == SDL_KEYDOWN && ev.key.keysym.sym==SDLK_F4)
@ -929,3 +943,24 @@ void startGame(StartInfo * options, CConnection *serv/* = NULL*/)
client->connectionHandler = new boost::thread(&CClient::run, client);
}
void handleQuit()
{
if (client)
client->endGame();
if (mainGUIThread)
{
GH.terminate = true;
mainGUIThread->join();
delete mainGUIThread;
mainGUIThread = NULL;
}
delete console;
console = NULL;
boost::this_thread::sleep(boost::posix_time::milliseconds(750));
if(!gNoGUI)
SDL_Quit();
std::cout << "Ending...";
exit(0);
}

View File

@ -2,4 +2,8 @@
extern SDL_Surface *screen; // main screen surface
extern SDL_Surface *screen2; // and hlp surface (used to store not-active interfaces layer)
extern SDL_Surface *screenBuf; // points to screen (if only advmapint is present) or screen2 (else) - should be used when updating controls which are not regularly redrawed
extern SDL_Surface *screenBuf; // points to screen (if only advmapint is present) or screen2 (else) - should be used when updating controls which are not regularly redrawed
extern bool gNoGUI; //if true there is no client window and game is silently played between AIs
void handleQuit();

View File

@ -34,6 +34,7 @@
#include "../lib/CScriptingModule.h"
#include "../lib/RegisterTypes.h"
#include "gui/CGuiHandler.h"
#include "CMT.h"
extern std::string NAME;
namespace intpr = boost::interprocess;
@ -419,15 +420,18 @@ void CClient::newGame( CConnection *con, StartInfo *si )
if(si->mode == StartInfo::DUEL)
{
boost::unique_lock<boost::recursive_mutex> un(*LOCPLINT->pim);
CPlayerInterface *p = new CPlayerInterface(PlayerColor::NEUTRAL); //TODO: check if neutral really works -- was -1, but CPlayerInterface seems to cooperate with this value not too well
p->observerInDuelMode = true;
battleints[PlayerColor::UNFLAGGABLE] = playerint[PlayerColor::UNFLAGGABLE] = p;
privilagedBattleEventReceivers.push_back(p);
GH.curInt = p;
auto cb = make_shared<CCallback>(gs, boost::optional<PlayerColor>(), this);
battleCallbacks[PlayerColor::NEUTRAL] = callbacks[PlayerColor::NEUTRAL] = cb;
p->init(cb.get());
if(!gNoGUI)
{
boost::unique_lock<boost::recursive_mutex> un(*LOCPLINT->pim);
CPlayerInterface *p = new CPlayerInterface(PlayerColor::NEUTRAL);
p->observerInDuelMode = true;
battleints[PlayerColor::UNFLAGGABLE] = playerint[PlayerColor::UNFLAGGABLE] = p;
privilagedBattleEventReceivers.push_back(p);
GH.curInt = p;
auto cb = make_shared<CCallback>(gs, boost::optional<PlayerColor>(), this);
battleCallbacks[PlayerColor::NEUTRAL] = callbacks[PlayerColor::NEUTRAL] = cb;
p->init(cb.get());
}
battleStarted(gs->curB);
}
else
@ -616,7 +620,7 @@ void CClient::battleStarted(const BattleInfo * info)
else
def = NULL;
if(att || def || gs->scenarioOps->mode == StartInfo::DUEL)
if(!gNoGUI && (att || def || gs->scenarioOps->mode == StartInfo::DUEL))
{
boost::unique_lock<boost::recursive_mutex> un(*LOCPLINT->pim);
new CBattleInterface(info->belligerents[0], info->belligerents[1], info->heroes[0], info->heroes[1],

View File

@ -27,6 +27,7 @@
#include "../lib/BattleState.h"
#include "../lib/GameConstants.h"
#include "gui/CGuiHandler.h"
#include "CMT.h"
//macros to avoid code duplication - calls given method with given arguments if interface for specific player is present
//awaiting variadic templates...
@ -705,9 +706,7 @@ void BattleResultsApplied::applyCl( CClient *cl )
INTERFACE_CALL_IF_PRESENT(PlayerColor::UNFLAGGABLE, battleResultsApplied);
if(GS(cl)->initialOpts->mode == StartInfo::DUEL)
{
cl->terminate = true;
CloseServer cs;
*cl->serv << &cs;
handleQuit();
}
}

View File

@ -204,8 +204,8 @@ CBattleInterface::CBattleInterface(const CCreatureSet * army1, const CCreatureSe
bOptions = new CAdventureMapButton (CGI->generaltexth->zelp[381].first, CGI->generaltexth->zelp[381].second, boost::bind(&CBattleInterface::bOptionsf,this), 3, 561, "icm003.def", SDLK_o);
bSurrender = new CAdventureMapButton (CGI->generaltexth->zelp[379].first, CGI->generaltexth->zelp[379].second, boost::bind(&CBattleInterface::bSurrenderf,this), 54, 561, "icm001.def", SDLK_s);
bFlee = new CAdventureMapButton (CGI->generaltexth->zelp[380].first, CGI->generaltexth->zelp[380].second, boost::bind(&CBattleInterface::bFleef,this), 105, 561, "icm002.def", SDLK_r);
bFlee->block(!curInt->cb->battleCanFlee());
bSurrender->block(curInt->cb->battleGetSurrenderCost() < 0);
bFlee->block(!curInt->cb->getMyColor() || !curInt->cb->battleCanFlee());
bSurrender->block(!curInt->cb->getMyColor() || curInt->cb->battleGetSurrenderCost() < 0);
bAutofight = new CAdventureMapButton (CGI->generaltexth->zelp[382].first, CGI->generaltexth->zelp[382].second, boost::bind(&CBattleInterface::bAutofightf,this), 157, 561, "icm004.def", SDLK_a);
bSpell = new CAdventureMapButton (CGI->generaltexth->zelp[385].first, CGI->generaltexth->zelp[385].second, boost::bind(&CBattleInterface::bSpellf,this), 645, 561, "icm005.def", SDLK_c);
bSpell->block(true);

View File

@ -942,6 +942,11 @@ TDmgRange CBattleInfoCallback::calculateDmgRange(const BattleAttackInfo &info) c
multBonus *= 0.5;
}
// TODO attack on petrified unit 50%
// psychic elementals versus mind immune units 50%
// blinded unit retaliates
minDmg *= additiveBonus * multBonus;
maxDmg *= additiveBonus * multBonus;
@ -2268,7 +2273,10 @@ TStacks CPlayerBattleCallback::battleGetStacks(EStackOwnership whose /*= MINE_AN
{
TStacks ret;
RETURN_IF_NOT_BATTLE(ret);
ASSERT_IF_CALLED_WITH_PLAYER
if(whose != MINE_AND_ENEMY)
{
ASSERT_IF_CALLED_WITH_PLAYER
}
vstd::copy_if(battleGetAllStacks(), std::back_inserter(ret), [=](const CStack *s) -> bool
{
const bool ownerMatches = (whose == MINE_AND_ENEMY)

View File

@ -128,7 +128,7 @@ CBonusTypeHandler::~CBonusTypeHandler()
//dtor
}
std::string CBonusTypeHandler::bonusToString(Bonus *bonus, const IBonusBearer *bearer, bool description) const
std::string CBonusTypeHandler::bonusToString(const Bonus *bonus, const IBonusBearer *bearer, bool description) const
{
auto getValue = [=](const std::string &name) -> std::string
{
@ -171,7 +171,7 @@ std::string CBonusTypeHandler::bonusToString(Bonus *bonus, const IBonusBearer *b
return text;
}
std::string CBonusTypeHandler::bonusToGraphics(Bonus* bonus) const
std::string CBonusTypeHandler::bonusToGraphics(const Bonus* bonus) const
{
std::string fileName;
bool fullPath = false;

View File

@ -75,8 +75,8 @@ public:
CBonusTypeHandler();
virtual ~CBonusTypeHandler();
std::string bonusToString(Bonus *bonus, const IBonusBearer *bearer, bool description) const override;
std::string bonusToGraphics(Bonus *bonus) const override;
std::string bonusToString(const Bonus *bonus, const IBonusBearer *bearer, bool description) const override;
std::string bonusToGraphics(const Bonus *bonus) const override;
void load();
void load(const JsonNode& config);

View File

@ -212,8 +212,8 @@ void CCreatureHandler::loadCommanders()
BOOST_FOREACH (auto ability, config["abilityRequirements"].Vector())
{
std::pair <Bonus, std::pair <ui8, ui8> > a;
a.first = *JsonUtils::parseBonus (ability["ability"].Vector());
std::pair <Bonus*, std::pair <ui8, ui8> > a;
a.first = JsonUtils::parseBonus (ability["ability"].Vector());
a.second.first = ability["skills"].Vector()[0].Float();
a.second.second = ability["skills"].Vector()[1].Float();
skillRequirements.push_back (a);

View File

@ -181,7 +181,7 @@ public:
//Commanders
BonusList commanderLevelPremy; //bonus values added with each level-up
std::vector< std::vector <ui8> > skillLevels; //how much of a bonus will be given to commander with every level. SPELL_POWER also gives CASTS and RESISTANCE
std::vector <std::pair <Bonus, std::pair <ui8, ui8> > > skillRequirements; // first - Bonus, second - which two skills are needed to use it
std::vector <std::pair <Bonus*, std::pair <ui8, ui8> > > skillRequirements; // first - Bonus, second - which two skills are needed to use it
void deserializationFix();
CreatureID pickRandomMonster(const boost::function<int()> &randGen = 0, int tier = -1) const; //tier <1 - CREATURES_PER_TOWN> or -1 for any

View File

@ -565,7 +565,7 @@ void CStackInstance::setType(const CCreature *c)
if(type)
attachTo(const_cast<CCreature*>(type));
}
std::string CStackInstance::bonusToString(Bonus *bonus, bool description) const
std::string CStackInstance::bonusToString(const Bonus *bonus, bool description) const
{
if(Bonus::MAGIC_RESISTANCE == bonus->type)
{
@ -578,7 +578,7 @@ std::string CStackInstance::bonusToString(Bonus *bonus, bool description) const
}
std::string CStackInstance::bonusToGraphics(Bonus *bonus) const
std::string CStackInstance::bonusToGraphics(const Bonus *bonus) const
{
return VLC->getBth()->bonusToGraphics(bonus);
}

View File

@ -56,8 +56,8 @@ public:
}
//overrides CBonusSystemNode
std::string bonusToString(Bonus *bonus, bool description) const override; // how would bonus description look for this particular type of node
std::string bonusToGraphics(Bonus *bonus) const; //file name of graphics from StackSkills , in future possibly others
std::string bonusToString(const Bonus *bonus, bool description) const override; // how would bonus description look for this particular type of node
std::string bonusToGraphics(const Bonus *bonus) const; //file name of graphics from StackSkills , in future possibly others
virtual ui64 getPower() const;
int getQuantityID() const;

View File

@ -619,7 +619,7 @@ public:
//bool isLimitedOnUs(Bonus *b) const; //if bonus should be removed from list acquired from this node
void popBonuses(const CSelector &s);
virtual std::string bonusToString(Bonus *bonus, bool description) const {return "";}; //description or bonus name
virtual std::string bonusToString(const Bonus *bonus, bool description) const {return "";}; //description or bonus name
virtual std::string nodeName() const;
void deserializationFix();

View File

@ -20,6 +20,6 @@ class IBonusTypeHandler
public:
virtual ~IBonusTypeHandler(){};
virtual std::string bonusToString(Bonus *bonus, const IBonusBearer *bearer, bool description) const = 0;
virtual std::string bonusToGraphics(Bonus *bonus) const = 0;
virtual std::string bonusToString(const Bonus *bonus, const IBonusBearer *bearer, bool description) const = 0;
virtual std::string bonusToGraphics(const Bonus *bonus) const = 0;
};

View File

@ -293,7 +293,7 @@ void CGameHandler::levelUpCommander (const CCommanderInstance * c, int skill)
else if (skill >= 100)
{
scp.which = SetCommanderProperty::SPECIAL_SKILL;
scp.accumulatedBonus = VLC->creh->skillRequirements[skill-100].first;
scp.accumulatedBonus = *VLC->creh->skillRequirements[skill-100].first;
scp.additionalInfo = skill; //unnormalized
sendAndApply (&scp);
}
@ -435,17 +435,22 @@ void CGameHandler::endBattle(int3 tile, const CGHeroInstance *hero1, const CGHer
return nullptr;
};
const auto battleQuery = findBattleQuery();
auto battleQuery = findBattleQuery();
if(!battleQuery)
{
logGlobal->errorStream() << "Cannot find battle query!";
if(gs->initialOpts->mode == StartInfo::DUEL)
{
battleQuery = make_shared<CBattleQuery>(gs->curB);
}
}
if(battleQuery != queries.topQuery(gs->curB->sides[0]))
complain("Player " + boost::lexical_cast<std::string>(gs->curB->sides[0]) + " although in battle has no battle query at the top!");
battleQuery->result = *battleResult.data;
//Check how many battle queries were created (number of players blocked by battle)
const int queriedPlayers = boost::count(queries.allQueries(), battleQuery);
const int queriedPlayers = battleQuery ? boost::count(queries.allQueries(), battleQuery) : 0;
finishingBattle = make_unique<FinishingBattleHelper>(battleQuery, gs->initialOpts->mode == StartInfo::DUEL, queriedPlayers);
@ -592,7 +597,13 @@ void CGameHandler::endBattle(int3 tile, const CGHeroInstance *hero1, const CGHer
}
if(finishingBattle->duel)
{
BattleResultsApplied resultsApplied;
resultsApplied.player1 = finishingBattle->victor;
resultsApplied.player2 = finishingBattle->loser;
sendAndApply(&resultsApplied);
return;
}
cab1.takeFromArmy(this); cab2.takeFromArmy(this); //take casualties after battle is deleted
@ -826,6 +837,12 @@ void CGameHandler::handleConnection(std::set<PlayerColor> players, CConnection &
{
boost::unique_lock<boost::mutex> lock(*c.rmx);
c >> player >> requestID >> pack; //get the package
if(!pack)
{
logGlobal ->errorStream() << boost::format("Received a null package marked as request %d from player %d") % requestID % player;
}
packType = typeList.getTypeID(pack); //get the id of type
logGlobal->traceStream() << boost::format("Received client message (request %d by player %d) of type with ID=%d (%s).\n")
@ -1427,6 +1444,8 @@ void CGameHandler::newTurn()
}
void CGameHandler::run(bool resume)
{
LOG_TRACE_PARAMS(logGlobal, "resume=%d", resume);
using namespace boost::posix_time;
BOOST_FOREACH(CConnection *cc, conns)
{
@ -1468,6 +1487,12 @@ void CGameHandler::run(bool resume)
if(gs->scenarioOps->mode == StartInfo::DUEL)
{
runBattle();
end2 = true;
while(conns.size() && (*conns.begin())->isOpen())
boost::this_thread::sleep(boost::posix_time::milliseconds(5)); //give time client to close socket
return;
}

View File

@ -265,7 +265,7 @@ public:
FinishingBattleHelper();
FinishingBattleHelper(shared_ptr<const CBattleQuery> Query, bool Duel, int RemainingBattleQueriesCount);
shared_ptr<const CBattleQuery> query;
//shared_ptr<const CBattleQuery> query;
const CGHeroInstance *winnerHero, *loserHero;
PlayerColor victor, loser;
bool duel;
@ -274,7 +274,7 @@ public:
template <typename Handler> void serialize(Handler &h, const int version)
{
h & query & winnerHero & loserHero & victor & loser & duel & remainingBattleQueriesCount;
h & /*query & */winnerHero & loserHero & victor & loser & duel & remainingBattleQueriesCount;
}
};

View File

@ -179,6 +179,10 @@ QueryPtr Queries::topQuery(PlayerColor player)
void Queries::popIfTop(QueryPtr query)
{
LOG_TRACE_PARAMS(logGlobal, "query='%d'", query);
if(!query)
logGlobal->errorStream() << "The query is nullptr! Ignoring.";
popIfTop(*query);
}