1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-11-28 08:48:48 +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()) if(cb->battleCanCastSpell())
attemptCastingSpell(); attemptCastingSpell();
if(auto action = considerFleeingOrSurrendering())
return *action;
if(cb->battleGetStacks(CBattleInfoEssentials::ONLY_ENEMY).empty()) if(cb->battleGetStacks(CBattleInfoEssentials::ONLY_ENEMY).empty())
{ {
//We apparently won battle by casting spell, return defend... (accessing cb may cause trouble) //We apparently won battle by casting spell, return defend... (accessing cb may cause trouble)
return BattleAction::makeDefend(stack); return BattleAction::makeDefend(stack);
} }
ThreatMap threatsToUs(stack);
PotentialTargets targets(stack); PotentialTargets targets(stack);
if(targets.possibleAttacks.size()) if(targets.possibleAttacks.size())
{ {
auto hlp = targets.bestAction(); auto hlp = targets.bestAction();
@ -375,6 +376,7 @@ BattleAction CBattleAI::activeStack( const CStack * stack )
{ {
if(stack->waited()) if(stack->waited())
{ {
ThreatMap threatsToUs(stack);
auto dists = cbc->battleGetDistances(stack); auto dists = cbc->battleGetDistances(stack);
const EnemyInfo &ei= *range::min_element(targets.unreachableEnemies, boost::bind(isCloser, _1, _2, boost::ref(dists))); 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) 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); 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 goTowards(const CStack * stack, BattleHex hex );
BattleAction useCatapult(const CStack * stack); BattleAction useCatapult(const CStack * stack);
boost::optional<BattleAction> considerFleeingOrSurrendering();
void attemptCastingSpell(); void attemptCastingSpell();
std::vector<BattleHex> getTargetsToConsider(const CSpell *spell) const; std::vector<BattleHex> getTargetsToConsider(const CSpell *spell) const;
}; };

View File

@ -239,8 +239,8 @@ void CCreatureWindow::init(const CStackInstance *Stack, const CBonusSystemNode *
else else
{ {
selectableSkill->pos = Rect (95, 256, 55, 55); //TODO: scroll selectableSkill->pos = Rect (95, 256, 55, 55); //TODO: scroll
Bonus b = CGI->creh->skillRequirements[option-100].first; 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))); 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 selectableBonuses.push_back (selectableSkill); //insert these before other bonuses
} }
} }

View File

@ -47,6 +47,7 @@
#endif #endif
#include "../lib/CDefObjInfoHandler.h" #include "../lib/CDefObjInfoHandler.h"
#include "../lib/UnlockGuard.h" #include "../lib/UnlockGuard.h"
#include "CMT.h"
#if __MINGW32__ #if __MINGW32__
#undef main #undef main
@ -76,6 +77,7 @@ static boost::thread *mainGUIThread;
std::queue<SDL_Event> events; std::queue<SDL_Event> events;
boost::mutex eventsM; boost::mutex eventsM;
bool gNoGUI = false;
static bool gOnlyAI = false; static bool gOnlyAI = false;
//static bool setResolution = false; //set by event handling thread after resolution is adjusted //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(); logGlobal->infoStream()<<"Initializing VCMI_Lib: "<<tmh.getDiff();
pomtime.getDiff(); pomtime.getDiff();
CCS->curh = new CCursorHandler; if(!gNoGUI)
graphics = new Graphics(); // should be before curh->init() {
CCS->curh = new CCursorHandler;
graphics = new Graphics(); // should be before curh->init()
CCS->curh->initCursor(); CCS->curh->initCursor();
CCS->curh->show(); CCS->curh->show();
logGlobal->infoStream()<<"Screen handler: "<<pomtime.getDiff(); logGlobal->infoStream()<<"Screen handler: "<<pomtime.getDiff();
pomtime.getDiff(); pomtime.getDiff();
graphics->loadHeroAnims(); graphics->loadHeroAnims();
logGlobal->infoStream()<<"\tMain graphics: "<<tmh.getDiff(); logGlobal->infoStream()<<"\tMain graphics: "<<tmh.getDiff();
logGlobal->infoStream()<<"Initializing game graphics: "<<tmh.getDiff(); logGlobal->infoStream()<<"Initializing game graphics: "<<tmh.getDiff();
CMessage::init(); CMessage::init();
logGlobal->infoStream()<<"Message handler: "<<tmh.getDiff(); logGlobal->infoStream()<<"Message handler: "<<tmh.getDiff();
}
} }
static void prog_version(void) static void prog_version(void)
@ -219,7 +224,8 @@ int main(int argc, char** argv)
("version,v", "display version information and exit") ("version,v", "display version information and exit")
("battle,b", po::value<std::string>(), "runs game in duel mode (battle-only") ("battle,b", po::value<std::string>(), "runs game in duel mode (battle-only")
("start", po::value<std::string>(), "starts game from saved StartInfo file") ("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") ("oneGoodAI", "puts one default AI and the rest will be EmptyAI")
("autoSkip", "automatically skip turns in GUI") ("autoSkip", "automatically skip turns in GUI")
("disable-video", "disable video player") ("disable-video", "disable video player")
@ -249,6 +255,11 @@ int main(int argc, char** argv)
prog_version(); prog_version();
return 0; return 0;
} }
if(vm.count("noGUI"))
{
gNoGUI = true;
vm["onlyAI"];
}
//Set environment vars to make window centered. Sometimes work, sometimes not. :/ //Set environment vars to make window centered. Sometimes work, sometimes not. :/
putenv((char*)"SDL_VIDEO_WINDOW_POS"); putenv((char*)"SDL_VIDEO_WINDOW_POS");
@ -303,16 +314,7 @@ int main(int argc, char** argv)
logGlobal->infoStream() << NAME; logGlobal->infoStream() << NAME;
srand ( time(NULL) ); 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& video = settings["video"];
const JsonNode& res = video["screenRes"]; const JsonNode& res = video["screenRes"];
@ -328,15 +330,26 @@ int main(int argc, char** argv)
exit(EXIT_FAILURE); 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 // Initialize video
#if DISABLE_VIDEO #if DISABLE_VIDEO
CCS->videoh = new CEmptyVideoPlayer; CCS->videoh = new CEmptyVideoPlayer;
#else #else
if (!vm.count("disable-video")) if (!gNoGUI && !vm.count("disable-video"))
CCS->videoh = new CVideoPlayer; CCS->videoh = new CVideoPlayer;
else else
CCS->videoh = new CEmptyVideoPlayer; CCS->videoh = new CEmptyVideoPlayer;
@ -344,13 +357,18 @@ int main(int argc, char** argv)
logGlobal->infoStream()<<"\tInitializing video: "<<pomtime.getDiff(); 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 //we can properly play intro only in the main thread, so we have to move loading to the separate thread
boost::thread loading(init); boost::thread loading(init);
if(!vm.count("battle") && !vm.count("nointro")) if(!gNoGUI )
playIntro(); {
if(!vm.count("battle") && !vm.count("nointro"))
playIntro();
SDL_FillRect(screen,NULL,0);
}
SDL_FillRect(screen,NULL,0);
CSDL_Ext::update(screen); CSDL_Ext::update(screen);
loading.join(); loading.join();
logGlobal->infoStream()<<"Initialization of VCMI (together): "<<total.getDiff(); 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); si->playerInfos[PlayerColor(1)].color = PlayerColor(1);
startGame(si); 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; return 0;
} }
@ -822,20 +849,7 @@ static void listenForEvents()
if (ret == 0 || (ev.type==SDL_QUIT) || if (ret == 0 || (ev.type==SDL_QUIT) ||
(ev.type == SDL_KEYDOWN && ev.key.keysym.sym==SDLK_F4 && (ev.key.keysym.mod & KMOD_ALT))) (ev.type == SDL_KEYDOWN && ev.key.keysym.sym==SDLK_F4 && (ev.key.keysym.mod & KMOD_ALT)))
{ {
if (client) handleQuit();
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...";
break; break;
} }
else if(LOCPLINT && ev.type == SDL_KEYDOWN && ev.key.keysym.sym==SDLK_F4) 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); 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 *screen; // main screen surface
extern SDL_Surface *screen2; // and hlp surface (used to store not-active interfaces layer) 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/CScriptingModule.h"
#include "../lib/RegisterTypes.h" #include "../lib/RegisterTypes.h"
#include "gui/CGuiHandler.h" #include "gui/CGuiHandler.h"
#include "CMT.h"
extern std::string NAME; extern std::string NAME;
namespace intpr = boost::interprocess; namespace intpr = boost::interprocess;
@ -419,15 +420,18 @@ void CClient::newGame( CConnection *con, StartInfo *si )
if(si->mode == StartInfo::DUEL) if(si->mode == StartInfo::DUEL)
{ {
boost::unique_lock<boost::recursive_mutex> un(*LOCPLINT->pim); if(!gNoGUI)
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; boost::unique_lock<boost::recursive_mutex> un(*LOCPLINT->pim);
battleints[PlayerColor::UNFLAGGABLE] = playerint[PlayerColor::UNFLAGGABLE] = p; CPlayerInterface *p = new CPlayerInterface(PlayerColor::NEUTRAL);
privilagedBattleEventReceivers.push_back(p); p->observerInDuelMode = true;
GH.curInt = p; battleints[PlayerColor::UNFLAGGABLE] = playerint[PlayerColor::UNFLAGGABLE] = p;
auto cb = make_shared<CCallback>(gs, boost::optional<PlayerColor>(), this); privilagedBattleEventReceivers.push_back(p);
battleCallbacks[PlayerColor::NEUTRAL] = callbacks[PlayerColor::NEUTRAL] = cb; GH.curInt = p;
p->init(cb.get()); auto cb = make_shared<CCallback>(gs, boost::optional<PlayerColor>(), this);
battleCallbacks[PlayerColor::NEUTRAL] = callbacks[PlayerColor::NEUTRAL] = cb;
p->init(cb.get());
}
battleStarted(gs->curB); battleStarted(gs->curB);
} }
else else
@ -616,7 +620,7 @@ void CClient::battleStarted(const BattleInfo * info)
else else
def = NULL; 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); boost::unique_lock<boost::recursive_mutex> un(*LOCPLINT->pim);
new CBattleInterface(info->belligerents[0], info->belligerents[1], info->heroes[0], info->heroes[1], 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/BattleState.h"
#include "../lib/GameConstants.h" #include "../lib/GameConstants.h"
#include "gui/CGuiHandler.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 //macros to avoid code duplication - calls given method with given arguments if interface for specific player is present
//awaiting variadic templates... //awaiting variadic templates...
@ -705,9 +706,7 @@ void BattleResultsApplied::applyCl( CClient *cl )
INTERFACE_CALL_IF_PRESENT(PlayerColor::UNFLAGGABLE, battleResultsApplied); INTERFACE_CALL_IF_PRESENT(PlayerColor::UNFLAGGABLE, battleResultsApplied);
if(GS(cl)->initialOpts->mode == StartInfo::DUEL) if(GS(cl)->initialOpts->mode == StartInfo::DUEL)
{ {
cl->terminate = true; handleQuit();
CloseServer cs;
*cl->serv << &cs;
} }
} }

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); 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); 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 = 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()); bFlee->block(!curInt->cb->getMyColor() || !curInt->cb->battleCanFlee());
bSurrender->block(curInt->cb->battleGetSurrenderCost() < 0); 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); 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 = 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); bSpell->block(true);

View File

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

View File

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

View File

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

View File

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

View File

@ -181,7 +181,7 @@ public:
//Commanders //Commanders
BonusList commanderLevelPremy; //bonus values added with each level-up 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::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(); void deserializationFix();
CreatureID pickRandomMonster(const boost::function<int()> &randGen = 0, int tier = -1) const; //tier <1 - CREATURES_PER_TOWN> or -1 for any 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) if(type)
attachTo(const_cast<CCreature*>(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) 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); return VLC->getBth()->bonusToGraphics(bonus);
} }

View File

@ -56,8 +56,8 @@ public:
} }
//overrides CBonusSystemNode //overrides CBonusSystemNode
std::string bonusToString(Bonus *bonus, bool description) const override; // how would bonus description look for this particular type of node std::string bonusToString(const 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 bonusToGraphics(const Bonus *bonus) const; //file name of graphics from StackSkills , in future possibly others
virtual ui64 getPower() const; virtual ui64 getPower() const;
int getQuantityID() 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 //bool isLimitedOnUs(Bonus *b) const; //if bonus should be removed from list acquired from this node
void popBonuses(const CSelector &s); 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; virtual std::string nodeName() const;
void deserializationFix(); void deserializationFix();

View File

@ -20,6 +20,6 @@ class IBonusTypeHandler
public: public:
virtual ~IBonusTypeHandler(){}; virtual ~IBonusTypeHandler(){};
virtual std::string bonusToString(Bonus *bonus, const IBonusBearer *bearer, bool description) const = 0; virtual std::string bonusToString(const Bonus *bonus, const IBonusBearer *bearer, bool description) const = 0;
virtual std::string bonusToGraphics(Bonus *bonus) 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) else if (skill >= 100)
{ {
scp.which = SetCommanderProperty::SPECIAL_SKILL; 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 scp.additionalInfo = skill; //unnormalized
sendAndApply (&scp); sendAndApply (&scp);
} }
@ -435,17 +435,22 @@ void CGameHandler::endBattle(int3 tile, const CGHeroInstance *hero1, const CGHer
return nullptr; return nullptr;
}; };
const auto battleQuery = findBattleQuery(); auto battleQuery = findBattleQuery();
if(!battleQuery) if(!battleQuery)
{
logGlobal->errorStream() << "Cannot find battle query!"; 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])) 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!"); 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; battleQuery->result = *battleResult.data;
//Check how many battle queries were created (number of players blocked by battle) //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); 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) if(finishingBattle->duel)
{
BattleResultsApplied resultsApplied;
resultsApplied.player1 = finishingBattle->victor;
resultsApplied.player2 = finishingBattle->loser;
sendAndApply(&resultsApplied);
return; return;
}
cab1.takeFromArmy(this); cab2.takeFromArmy(this); //take casualties after battle is deleted 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); boost::unique_lock<boost::mutex> lock(*c.rmx);
c >> player >> requestID >> pack; //get the package 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 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") 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) void CGameHandler::run(bool resume)
{ {
LOG_TRACE_PARAMS(logGlobal, "resume=%d", resume);
using namespace boost::posix_time; using namespace boost::posix_time;
BOOST_FOREACH(CConnection *cc, conns) BOOST_FOREACH(CConnection *cc, conns)
{ {
@ -1468,6 +1487,12 @@ void CGameHandler::run(bool resume)
if(gs->scenarioOps->mode == StartInfo::DUEL) if(gs->scenarioOps->mode == StartInfo::DUEL)
{ {
runBattle(); 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; return;
} }

View File

@ -265,7 +265,7 @@ public:
FinishingBattleHelper(); FinishingBattleHelper();
FinishingBattleHelper(shared_ptr<const CBattleQuery> Query, bool Duel, int RemainingBattleQueriesCount); FinishingBattleHelper(shared_ptr<const CBattleQuery> Query, bool Duel, int RemainingBattleQueriesCount);
shared_ptr<const CBattleQuery> query; //shared_ptr<const CBattleQuery> query;
const CGHeroInstance *winnerHero, *loserHero; const CGHeroInstance *winnerHero, *loserHero;
PlayerColor victor, loser; PlayerColor victor, loser;
bool duel; bool duel;
@ -274,7 +274,7 @@ public:
template <typename Handler> void serialize(Handler &h, const int version) 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) void Queries::popIfTop(QueryPtr query)
{ {
LOG_TRACE_PARAMS(logGlobal, "query='%d'", query);
if(!query)
logGlobal->errorStream() << "The query is nullptr! Ignoring.";
popIfTop(*query); popIfTop(*query);
} }