mirror of
				https://github.com/vcmi/vcmi.git
				synced 2025-10-31 00:07:39 +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:
		| @@ -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; | ||||
| } | ||||
|   | ||||
| @@ -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; | ||||
| }; | ||||
|   | ||||
| @@ -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 | ||||
| 				} | ||||
| 			} | ||||
|   | ||||
							
								
								
									
										123
									
								
								client/CMT.cpp
									
									
									
									
									
								
							
							
						
						
									
										123
									
								
								client/CMT.cpp
									
									
									
									
									
								
							| @@ -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); | ||||
| } | ||||
|   | ||||
| @@ -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(); | ||||
| @@ -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], | ||||
|   | ||||
| @@ -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(); | ||||
| 	} | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -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); | ||||
|   | ||||
| @@ -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) | ||||
|   | ||||
| @@ -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; | ||||
|   | ||||
| @@ -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); | ||||
|   | ||||
| @@ -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); | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
| @@ -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); | ||||
| } | ||||
|   | ||||
| @@ -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; | ||||
|   | ||||
| @@ -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(); | ||||
|   | ||||
| @@ -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; | ||||
| }; | ||||
|   | ||||
| @@ -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; | ||||
| 	} | ||||
|  | ||||
|   | ||||
| @@ -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; | ||||
| 		} | ||||
| 	}; | ||||
|  | ||||
|   | ||||
| @@ -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); | ||||
| } | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user