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:
parent
30fb552fb4
commit
6a88604937
@ -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;
|
||||||
|
}
|
||||||
|
@ -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;
|
||||||
};
|
};
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
123
client/CMT.cpp
123
client/CMT.cpp
@ -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);
|
||||||
|
}
|
||||||
|
@ -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();
|
@ -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],
|
||||||
|
@ -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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
@ -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)
|
||||||
|
@ -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;
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
|
@ -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
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
@ -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();
|
||||||
|
@ -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;
|
||||||
};
|
};
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user