소스 검색

Introduced strongly typed QueryID.
Exchange between heroes is now a proper first-class query. Fixes #1269. #66 should also be finally fully fixed.
VC projects: /Zm flag to fix compilation issues with recent Boost.

Michał W. Urbańczyk 12 년 전
부모
커밋
79026bdfde

+ 4 - 0
AI/BattleAI/BattleAI.vcxproj

@@ -89,6 +89,7 @@
     <ClCompile>
       <PrecompiledHeader>Use</PrecompiledHeader>
       <PrecompiledHeaderFile>StdInc.h</PrecompiledHeaderFile>
+      <AdditionalOptions>/Zm159 %(AdditionalOptions)</AdditionalOptions>
     </ClCompile>
     <Link>
       <AdditionalDependencies>VCMI_lib.lib;%(AdditionalDependencies)</AdditionalDependencies>
@@ -100,6 +101,7 @@
       <Optimization>Disabled</Optimization>
       <PrecompiledHeader>Use</PrecompiledHeader>
       <PrecompiledHeaderFile>StdInc.h</PrecompiledHeaderFile>
+      <AdditionalOptions>/Zm159 %(AdditionalOptions)</AdditionalOptions>
     </ClCompile>
     <Link>
       <AdditionalDependencies>VCMI_lib.lib;%(AdditionalDependencies)</AdditionalDependencies>
@@ -109,6 +111,7 @@
     <ClCompile>
       <PrecompiledHeader>Use</PrecompiledHeader>
       <PrecompiledHeaderFile>StdInc.h</PrecompiledHeaderFile>
+      <AdditionalOptions>/Zm159 %(AdditionalOptions)</AdditionalOptions>
     </ClCompile>
     <Link>
       <AdditionalDependencies>VCMI_lib.lib;%(AdditionalDependencies)</AdditionalDependencies>
@@ -118,6 +121,7 @@
     <ClCompile>
       <PrecompiledHeader>Use</PrecompiledHeader>
       <PrecompiledHeaderFile>StdInc.h</PrecompiledHeaderFile>
+      <AdditionalOptions>/Zm159 %(AdditionalOptions)</AdditionalOptions>
     </ClCompile>
     <Link>
       <AdditionalDependencies>VCMI_lib.lib;%(AdditionalDependencies)</AdditionalDependencies>

+ 4 - 0
AI/StupidAI/StupidAI.vcxproj

@@ -89,6 +89,7 @@
     <ClCompile>
       <PrecompiledHeader>Use</PrecompiledHeader>
       <PrecompiledHeaderFile>StdInc.h</PrecompiledHeaderFile>
+      <AdditionalOptions>/Zm150 %(AdditionalOptions)</AdditionalOptions>
     </ClCompile>
     <Link>
       <AdditionalDependencies>VCMI_lib.lib;%(AdditionalDependencies)</AdditionalDependencies>
@@ -99,6 +100,7 @@
     <ClCompile>
       <PrecompiledHeader>Use</PrecompiledHeader>
       <PrecompiledHeaderFile>StdInc.h</PrecompiledHeaderFile>
+      <AdditionalOptions>/Zm150 %(AdditionalOptions)</AdditionalOptions>
     </ClCompile>
     <Link>
       <AdditionalDependencies>VCMI_lib.lib;%(AdditionalDependencies)</AdditionalDependencies>
@@ -108,6 +110,7 @@
     <ClCompile>
       <PrecompiledHeader>Use</PrecompiledHeader>
       <PrecompiledHeaderFile>StdInc.h</PrecompiledHeaderFile>
+      <AdditionalOptions>/Zm150 %(AdditionalOptions)</AdditionalOptions>
     </ClCompile>
     <Link>
       <AdditionalDependencies>VCMI_lib.lib;%(AdditionalDependencies)</AdditionalDependencies>
@@ -117,6 +120,7 @@
     <ClCompile>
       <PrecompiledHeader>Use</PrecompiledHeader>
       <PrecompiledHeaderFile>StdInc.h</PrecompiledHeaderFile>
+      <AdditionalOptions>/Zm150 %(AdditionalOptions)</AdditionalOptions>
     </ClCompile>
     <Link>
       <AdditionalDependencies>VCMI_lib.lib;%(AdditionalDependencies)</AdditionalDependencies>

+ 17 - 13
AI/VCAI/VCAI.cpp

@@ -611,7 +611,7 @@ void VCAI::tileRevealed(const boost::unordered_set<int3, ShashInt3> &pos)
 			addVisitableObj(obj);
 }
 
-void VCAI::heroExchangeStarted(ObjectInstanceID hero1, ObjectInstanceID hero2)
+void VCAI::heroExchangeStarted(ObjectInstanceID hero1, ObjectInstanceID hero2, QueryID query)
 {
 	LOG_TRACE(logAi);
 	NET_EVENT_HANDLER;
@@ -619,6 +619,8 @@ void VCAI::heroExchangeStarted(ObjectInstanceID hero1, ObjectInstanceID hero2)
 	auto firstHero = cb->getHero(hero1);
 	auto secondHero = cb->getHero(hero2);
 
+	status.addQuery(query, boost::str(boost::format("Exchange between heroes %s and %s") % firstHero->name % secondHero->name));
+
 	requestActionASAP([=]()
 	{
 		if (firstHero->getHeroStrength() > secondHero->getHeroStrength() && canGetArmy (firstHero, secondHero))
@@ -629,6 +631,8 @@ void VCAI::heroExchangeStarted(ObjectInstanceID hero1, ObjectInstanceID hero2)
 		completeGoal(CGoal(VISIT_HERO).sethero(firstHero)); //TODO: what if we were visited by other hero in the meantime?
 		completeGoal(CGoal(VISIT_HERO).sethero(secondHero));
 		//TODO: exchange artifacts
+
+		answerQuery(query, 0);
 	});
 }
 
@@ -843,7 +847,7 @@ void VCAI::yourTurn()
 	makingTurn = make_unique<boost::thread>(&VCAI::makeTurn, this);
 }
 
-void VCAI::heroGotLevel(const CGHeroInstance *hero, PrimarySkill::PrimarySkill pskill, std::vector<SecondarySkill> &skills, int queryID)
+void VCAI::heroGotLevel(const CGHeroInstance *hero, PrimarySkill::PrimarySkill pskill, std::vector<SecondarySkill> &skills, QueryID queryID)
 {
 	LOG_TRACE_PARAMS(logAi, "queryID '%i'", queryID);
 	NET_EVENT_HANDLER;
@@ -851,7 +855,7 @@ void VCAI::heroGotLevel(const CGHeroInstance *hero, PrimarySkill::PrimarySkill p
 	requestActionASAP([=]{ answerQuery(queryID, 0); });
 }
 
-void VCAI::commanderGotLevel (const CCommanderInstance * commander, std::vector<ui32> skills, int queryID)
+void VCAI::commanderGotLevel (const CCommanderInstance * commander, std::vector<ui32> skills, QueryID queryID)
 {
 	LOG_TRACE_PARAMS(logAi, "queryID '%i'", queryID);
 	NET_EVENT_HANDLER;
@@ -859,7 +863,7 @@ void VCAI::commanderGotLevel (const CCommanderInstance * commander, std::vector<
 	requestActionASAP([=]{ answerQuery(queryID, 0); });
 }
 
-void VCAI::showBlockingDialog(const std::string &text, const std::vector<Component> &components, ui32 askID, const int soundID, bool selection, bool cancel)
+void VCAI::showBlockingDialog(const std::string &text, const std::vector<Component> &components, QueryID askID, const int soundID, bool selection, bool cancel)
 {
 	LOG_TRACE_PARAMS(logAi, "text '%s', askID '%i', soundID '%i', selection '%i', cancel '%i'", text % askID % soundID % selection % cancel);
 	NET_EVENT_HANDLER;
@@ -879,7 +883,7 @@ void VCAI::showBlockingDialog(const std::string &text, const std::vector<Compone
 	});
 }
 
-void VCAI::showGarrisonDialog(const CArmedInstance *up, const CGHeroInstance *down, bool removableUnits, int queryID)
+void VCAI::showGarrisonDialog(const CArmedInstance *up, const CGHeroInstance *down, bool removableUnits, QueryID queryID)
 {
 	LOG_TRACE_PARAMS(logAi, "removableUnits '%i', queryID '%i'", removableUnits % queryID);
 	NET_EVENT_HANDLER;
@@ -2524,10 +2528,10 @@ void VCAI::lostHero(HeroPtr h)
 	erase_if_present(reservedHeroesMap, h);
 }
 
-void VCAI::answerQuery(int queryID, int selection)
+void VCAI::answerQuery(QueryID queryID, int selection)
 {
     logAi->debugStream() << boost::format("I'll answer the query %d giving the choice %d") % queryID % selection;
-	if(queryID != -1)
+	if(queryID != QueryID(-1))
 	{
 		cb->selectionMade(selection, queryID);
 	}
@@ -2597,24 +2601,24 @@ BattleState AIStatus::getBattle()
 	return battle;
 }
 
-void AIStatus::addQuery(int ID, std::string description)
+void AIStatus::addQuery(QueryID ID, std::string description)
 {
 	boost::unique_lock<boost::mutex> lock(mx);
-	if(ID == -1)
+	if(ID == QueryID(-1))
 	{
         logAi->debugStream() << boost::format("The \"query\" has an id %d, it'll be ignored as non-query. Description: %s") % ID % description;
 		return;
 	}
 
 	assert(!vstd::contains(remainingQueries, ID));
-	assert(ID >= 0);
+	assert(ID.getNum() >= 0);
 
 	remainingQueries[ID] = description;
 	cv.notify_all();
     logAi->debugStream() << boost::format("Adding query %d - %s. Total queries count: %d") % ID % description % remainingQueries.size();
 }
 
-void AIStatus::removeQuery(int ID)
+void AIStatus::removeQuery(QueryID ID)
 {
 	boost::unique_lock<boost::mutex> lock(mx);
 	assert(vstd::contains(remainingQueries, ID));
@@ -2658,7 +2662,7 @@ bool AIStatus::haveTurn()
 	return havingTurn;
 }
 
-void AIStatus::attemptedAnsweringQuery(int queryID, int answerRequestID)
+void AIStatus::attemptedAnsweringQuery(QueryID queryID, int answerRequestID)
 {
 	boost::unique_lock<boost::mutex> lock(mx);
 	assert(vstd::contains(remainingQueries, queryID));
@@ -2670,7 +2674,7 @@ void AIStatus::attemptedAnsweringQuery(int queryID, int answerRequestID)
 void AIStatus::receivedAnswerConfirmation(int answerRequestID, int result)
 {
 	assert(vstd::contains(requestToQueryID, answerRequestID));
-	int query = requestToQueryID[answerRequestID];
+	QueryID query = requestToQueryID[answerRequestID];
 	assert(vstd::contains(remainingQueries, query));
 	requestToQueryID.erase(answerRequestID);
 

+ 11 - 11
AI/VCAI/VCAI.h

@@ -73,8 +73,8 @@ class AIStatus
 	boost::condition_variable cv;
 
 	BattleState battle;
-	std::map<int, std::string> remainingQueries;
-	std::map<int, int> requestToQueryID; //IDs of answer-requests sent to server => query ids (so we can match answer confirmation from server to the query)
+	std::map<QueryID, std::string> remainingQueries;
+	std::map<int, QueryID> requestToQueryID; //IDs of answer-requests sent to server => query ids (so we can match answer confirmation from server to the query)
 
 	bool havingTurn;
 
@@ -83,14 +83,14 @@ public:
 	~AIStatus();
 	void setBattle(BattleState BS);
 	BattleState getBattle();
-	void addQuery(int ID, std::string description);
-	void removeQuery(int ID);
+	void addQuery(QueryID ID, std::string description);
+	void removeQuery(QueryID ID);
 	int getQueriesCount();
 	void startedTurn();
 	void madeTurn();
 	void waitTillFree();
 	bool haveTurn();
-	void attemptedAnsweringQuery(int queryID, int answerRequestID);
+	void attemptedAnsweringQuery(QueryID queryID, int answerRequestID);
 	void receivedAnswerConfirmation(int answerRequestID, int result);
 
 
@@ -309,10 +309,10 @@ public:
 	virtual void init(CCallback * CB) OVERRIDE;
 	virtual void yourTurn() OVERRIDE;
 
-	virtual void heroGotLevel(const CGHeroInstance *hero, PrimarySkill::PrimarySkill pskill, std::vector<SecondarySkill> &skills, int queryID) OVERRIDE; //pskill is gained primary skill, interface has to choose one of given skills and call callback with selection id
-	virtual void commanderGotLevel (const CCommanderInstance * commander, std::vector<ui32> skills, int queryID) OVERRIDE; //TODO
-	virtual void showBlockingDialog(const std::string &text, const std::vector<Component> &components, ui32 askID, const int soundID, bool selection, bool cancel) OVERRIDE; //Show a dialog, player must take decision. If selection then he has to choose between one of given components, if cancel he is allowed to not choose. After making choice, CCallback::selectionMade should be called with number of selected component (1 - n) or 0 for cancel (if allowed) and askID.
-	virtual void showGarrisonDialog(const CArmedInstance *up, const CGHeroInstance *down, bool removableUnits, int queryID) OVERRIDE; //all stacks operations between these objects become allowed, interface has to call onEnd when done
+	virtual void heroGotLevel(const CGHeroInstance *hero, PrimarySkill::PrimarySkill pskill, std::vector<SecondarySkill> &skills, QueryID queryID) OVERRIDE; //pskill is gained primary skill, interface has to choose one of given skills and call callback with selection id
+	virtual void commanderGotLevel (const CCommanderInstance * commander, std::vector<ui32> skills, QueryID queryID) OVERRIDE; //TODO
+	virtual void showBlockingDialog(const std::string &text, const std::vector<Component> &components, QueryID askID, const int soundID, bool selection, bool cancel) OVERRIDE; //Show a dialog, player must take decision. If selection then he has to choose between one of given components, if cancel he is allowed to not choose. After making choice, CCallback::selectionMade should be called with number of selected component (1 - n) or 0 for cancel (if allowed) and askID.
+	virtual void showGarrisonDialog(const CArmedInstance *up, const CGHeroInstance *down, bool removableUnits, QueryID queryID) OVERRIDE; //all stacks operations between these objects become allowed, interface has to call onEnd when done
 	virtual void saveGame(COSer<CSaveFile> &h, const int version) OVERRIDE; //saving
 	virtual void loadGame(CISer<CLoadFile> &h, const int version) OVERRIDE; //loading
 	virtual void finish() OVERRIDE;
@@ -339,7 +339,7 @@ public:
 	virtual void availableArtifactsChanged(const CGBlackMarket *bm = NULL) OVERRIDE;
 	virtual void heroVisitsTown(const CGHeroInstance* hero, const CGTownInstance * town) OVERRIDE;
 	virtual void tileRevealed(const boost::unordered_set<int3, ShashInt3> &pos) OVERRIDE;
-	virtual void heroExchangeStarted(ObjectInstanceID hero1, ObjectInstanceID hero2) OVERRIDE;
+	virtual void heroExchangeStarted(ObjectInstanceID hero1, ObjectInstanceID hero2, QueryID query) OVERRIDE;
 	virtual void heroPrimarySkillChanged(const CGHeroInstance * hero, int which, si64 val) OVERRIDE;
 	virtual void showRecruitmentDialog(const CGDwelling *dwelling, const CArmedInstance *dst, int level) OVERRIDE;
 	virtual void heroMovePointsChanged(const CGHeroInstance * hero) OVERRIDE;
@@ -425,7 +425,7 @@ public:
 	void checkHeroArmy (HeroPtr h);
 
 	void requestSent(const CPackForServer *pack, int requestID) OVERRIDE;
-	void answerQuery(int queryID, int selection);
+	void answerQuery(QueryID queryID, int selection);
 	//special function that can be called ONLY from game events handling thread and will send request ASAP
 	void requestActionASAP(boost::function<void()> whatToDo); 
 

+ 2 - 2
CCallback.cpp

@@ -56,10 +56,10 @@ bool CCallback::moveHero(const CGHeroInstance *h, int3 dst)
 	return true;
 }
 
-int CCallback::selectionMade(int selection, int queryID)
+int CCallback::selectionMade(int selection, QueryID queryID)
 {
 	ASSERT_IF_CALLED_WITH_PLAYER
-	if(queryID == -1)
+	if(queryID == QueryID(-1))
 	{
         logGlobal->errorStream() << "Cannot answer the query -1!";
 		return false;

+ 2 - 2
CCallback.h

@@ -56,7 +56,7 @@ public:
 
 	virtual void trade(const CGObjectInstance *market, EMarketMode::EMarketMode mode, int id1, int id2, int val1, const CGHeroInstance *hero = NULL)=0; //mode==0: sell val1 units of id1 resource for id2 resiurce
 
-	virtual int selectionMade(int selection, int queryID) =0;
+	virtual int selectionMade(int selection, QueryID queryID) =0;
 	virtual int swapCreatures(const CArmedInstance *s1, const CArmedInstance *s2, SlotID p1, SlotID p2)=0;//swaps creatures between two possibly different garrisons // TODO: AI-unsafe code - fix it!
 	virtual int mergeStacks(const CArmedInstance *s1, const CArmedInstance *s2, SlotID p1, SlotID p2)=0;//joins first stack to the second (creatures must be same type)
 	virtual int mergeOrSwapStacks(const CArmedInstance *s1, const CArmedInstance *s2, SlotID p1, SlotID p2) =0; //first goes to the second
@@ -117,7 +117,7 @@ public:
 //commands
 	bool moveHero(const CGHeroInstance *h, int3 dst); //dst must be free, neighbouring tile (this function can move hero only by one tile)
 	bool teleportHero(const CGHeroInstance *who, const CGTownInstance *where);
-	int selectionMade(int selection, int queryID);
+	int selectionMade(int selection, QueryID queryID);
 	int swapCreatures(const CArmedInstance *s1, const CArmedInstance *s2, SlotID p1, SlotID p2);
 	int mergeOrSwapStacks(const CArmedInstance *s1, const CArmedInstance *s2, SlotID p1, SlotID p2); //first goes to the second
 	int mergeStacks(const CArmedInstance *s1, const CArmedInstance *s2, SlotID p1, SlotID p2); //first goes to the second

+ 4 - 0
client/CAdvmapInterface.cpp

@@ -843,6 +843,10 @@ void CAdvMapInt::keyPressed(const SDL_KeyboardEvent & key)
 			if(h && key.state == SDL_PRESSED)
 			{
 				auto unlockPim = vstd::makeUnlockGuard(*LOCPLINT->pim);
+				//TODO!!!!!!! possible freeze, when GS mutex is locked and network thread can't apply package
+				//this thread leaves scope and tries to lock pim while holding gs, 
+				//network thread tries to lock gs (appluy cl) while holding pim
+				//this thread should first lock pim, however gs locking/unlocking is done inside cb
 				LOCPLINT->cb->moveHero(h,h->pos);
 			}
 		}

+ 1 - 1
client/CCastleInterface.cpp

@@ -1203,7 +1203,7 @@ void HeroSlots::splitClicked()
 {
 	if(!!town->visitingHero && town->garrisonHero && (visitingHero->selection || garrisonedHero->selection))
 	{
-		LOCPLINT->heroExchangeStarted(town->visitingHero->id, town->garrisonHero->id);
+		LOCPLINT->heroExchangeStarted(town->visitingHero->id, town->garrisonHero->id, QueryID(-1));
 	}
 }
 

+ 6 - 6
client/CPlayerInterface.cpp

@@ -471,7 +471,7 @@ void CPlayerInterface::receivedResource(int type, int val)
 	GH.totalRedraw();
 }
 
-void CPlayerInterface::heroGotLevel(const CGHeroInstance *hero, PrimarySkill::PrimarySkill pskill, std::vector<SecondarySkill>& skills, int queryID)
+void CPlayerInterface::heroGotLevel(const CGHeroInstance *hero, PrimarySkill::PrimarySkill pskill, std::vector<SecondarySkill>& skills, QueryID queryID)
 {
 	EVENT_HANDLER_CALLED_BY_CLIENT;
 	waitWhileDialog();
@@ -481,7 +481,7 @@ void CPlayerInterface::heroGotLevel(const CGHeroInstance *hero, PrimarySkill::Pr
 										[=](ui32 selection){ cb->selectionMade(selection, queryID); });
 	GH.pushInt(lw);
 }
-void CPlayerInterface::commanderGotLevel (const CCommanderInstance * commander, std::vector<ui32> skills, int queryID)
+void CPlayerInterface::commanderGotLevel (const CCommanderInstance * commander, std::vector<ui32> skills, QueryID queryID)
 {
 	EVENT_HANDLER_CALLED_BY_CLIENT;
 	waitWhileDialog();
@@ -1016,7 +1016,7 @@ void CPlayerInterface::showYesNoDialog(const std::string &text, CFunctionList<vo
 	CInfoWindow::showYesNoDialog(text, &components, onYes, onNo, DelComps, playerID);
 }
 
-void CPlayerInterface::showBlockingDialog( const std::string &text, const std::vector<Component> &components, ui32 askID, int soundID, bool selection, bool cancel )
+void CPlayerInterface::showBlockingDialog( const std::string &text, const std::vector<Component> &components, QueryID askID, int soundID, bool selection, bool cancel )
 {
 	EVENT_HANDLER_CALLED_BY_CLIENT;
 	waitWhileDialog();
@@ -1324,7 +1324,7 @@ bool CPlayerInterface::altPressed() const
 	return SDL_GetKeyState(NULL)[SDLK_LALT]  ||  SDL_GetKeyState(NULL)[SDLK_RALT];
 }
 
-void CPlayerInterface::showGarrisonDialog( const CArmedInstance *up, const CGHeroInstance *down, bool removableUnits, int queryID)
+void CPlayerInterface::showGarrisonDialog( const CArmedInstance *up, const CGHeroInstance *down, bool removableUnits, QueryID queryID)
 {
 	EVENT_HANDLER_CALLED_BY_CLIENT;
 	auto onEnd = [=]{ cb->selectionMade(0, queryID); };
@@ -1384,10 +1384,10 @@ void CPlayerInterface::requestRealized( PackageApplied *pa )
 		stillMoveHero.setn(CONTINUE_MOVE);
 }
 
-void CPlayerInterface::heroExchangeStarted(ObjectInstanceID hero1, ObjectInstanceID hero2)
+void CPlayerInterface::heroExchangeStarted(ObjectInstanceID hero1, ObjectInstanceID hero2, QueryID query)
 {
 	EVENT_HANDLER_CALLED_BY_CLIENT;
-	GH.pushInt(new CExchangeWindow(hero1, hero2));
+	GH.pushInt(new CExchangeWindow(hero1, hero2, query));
 }
 
 void CPlayerInterface::objectPropertyChanged(const SetObjectProperty * sop)

+ 5 - 5
client/CPlayerInterface.h

@@ -143,8 +143,8 @@ public:
 	void artifactDisassembled(const ArtifactLocation &al);
 
 	void heroCreated(const CGHeroInstance* hero) OVERRIDE;
-	void heroGotLevel(const CGHeroInstance *hero, PrimarySkill::PrimarySkill pskill, std::vector<SecondarySkill> &skills, int queryID) OVERRIDE;
-	void commanderGotLevel (const CCommanderInstance * commander, std::vector<ui32> skills, int queryID) OVERRIDE;
+	void heroGotLevel(const CGHeroInstance *hero, PrimarySkill::PrimarySkill pskill, std::vector<SecondarySkill> &skills, QueryID queryID) OVERRIDE;
+	void commanderGotLevel (const CCommanderInstance * commander, std::vector<ui32> skills, QueryID queryID) OVERRIDE;
 	void heroInGarrisonChange(const CGTownInstance *town) OVERRIDE;
 	void heroMoved(const TryMoveHero & details) OVERRIDE;
 	void heroPrimarySkillChanged(const CGHeroInstance * hero, int which, si64 val) OVERRIDE;
@@ -156,8 +156,8 @@ public:
 	void showInfoDialog(const std::string &text, const std::vector<Component*> &components, int soundID) OVERRIDE;
 	void showRecruitmentDialog(const CGDwelling *dwelling, const CArmedInstance *dst, int level) OVERRIDE;
 	void showShipyardDialog(const IShipyard *obj) OVERRIDE; //obj may be town or shipyard;
-	void showBlockingDialog(const std::string &text, const std::vector<Component> &components, ui32 askID, int soundID, bool selection, bool cancel) OVERRIDE; //Show a dialog, player must take decision. If selection then he has to choose between one of given components, if cancel he is allowed to not choose. After making choice, CCallback::selectionMade should be called with number of selected component (1 - n) or 0 for cancel (if allowed) and askID.
-	void showGarrisonDialog(const CArmedInstance *up, const CGHeroInstance *down, bool removableUnits, int queryID) OVERRIDE;
+	void showBlockingDialog(const std::string &text, const std::vector<Component> &components, QueryID askID, int soundID, bool selection, bool cancel) OVERRIDE; //Show a dialog, player must take decision. If selection then he has to choose between one of given components, if cancel he is allowed to not choose. After making choice, CCallback::selectionMade should be called with number of selected component (1 - n) or 0 for cancel (if allowed) and askID.
+	void showGarrisonDialog(const CArmedInstance *up, const CGHeroInstance *down, bool removableUnits, QueryID queryID) OVERRIDE;
 	void showPuzzleMap() OVERRIDE;
 	void showMarketWindow(const IMarket *market, const CGHeroInstance *visitor) OVERRIDE;
 	void showUniversityWindow(const IMarket *market, const CGHeroInstance *visitor) OVERRIDE;
@@ -175,7 +175,7 @@ public:
 	void heroBonusChanged(const CGHeroInstance *hero, const Bonus &bonus, bool gain) OVERRIDE;//if gain hero received bonus, else he lost it
 	void playerBonusChanged(const Bonus &bonus, bool gain) OVERRIDE;
 	void requestRealized(PackageApplied *pa) OVERRIDE;
-	void heroExchangeStarted(ObjectInstanceID hero1, ObjectInstanceID hero2) OVERRIDE;
+	void heroExchangeStarted(ObjectInstanceID hero1, ObjectInstanceID hero2, QueryID query) OVERRIDE;
 	void centerView (int3 pos, int focusTime) OVERRIDE;
 	void objectPropertyChanged(const SetObjectProperty * sop) OVERRIDE;
 	void objectRemoved(const CGObjectInstance *obj) OVERRIDE;

+ 10 - 7
client/GUIClasses.cpp

@@ -653,7 +653,7 @@ CInfoWindow::CInfoWindow(std::string Text, PlayerColor player, const TCompsInfo
 	OBJ_CONSTRUCTION_CAPTURING_ALL;
 
 	type |= BLOCK_ADV_HOTKEYS;
-	ID = -1;
+	ID = QueryID(-1);
 	for(int i=0;i<Buttons.size();i++)
 	{
 		CAdventureMapButton *button = new CAdventureMapButton("","",boost::bind(&CInfoWindow::close,this),0,0,Buttons[i].first);
@@ -689,7 +689,7 @@ CInfoWindow::CInfoWindow(std::string Text, PlayerColor player, const TCompsInfo
 
 CInfoWindow::CInfoWindow()
 {
-	ID = -1;
+	ID = QueryID(-1);
 	setDelComps(false);
 	text = NULL;
 }
@@ -1262,14 +1262,14 @@ void CSelWindow::selectionChange(unsigned to)
 	redraw();
 }
 
-CSelWindow::CSelWindow(const std::string &Text, PlayerColor player, int charperline, const std::vector<CSelectableComponent*> &comps, const std::vector<std::pair<std::string,CFunctionList<void()> > > &Buttons, int askID)
+CSelWindow::CSelWindow(const std::string &Text, PlayerColor player, int charperline, const std::vector<CSelectableComponent*> &comps, const std::vector<std::pair<std::string,CFunctionList<void()> > > &Buttons, QueryID askID)
 {
 	OBJ_CONSTRUCTION_CAPTURING_ALL;
 	ID = askID;
 	for(int i=0;i<Buttons.size();i++)
 	{
 		buttons.push_back(new CAdventureMapButton("","",Buttons[i].second,0,0,Buttons[i].first));
-		if(!i  &&  askID >= 0)
+		if(!i  &&  askID.getNum() >= 0)
 			buttons.back()->callback += boost::bind(&CSelWindow::madeChoice,this);
 		buttons[i]->callback += boost::bind(&CInfoWindow::close,this); //each button will close the window apart from call-defined actions
 	}
@@ -1279,7 +1279,7 @@ CSelWindow::CSelWindow(const std::string &Text, PlayerColor player, int charperl
 	buttons.front()->assignedKeys.insert(SDLK_RETURN); //first button - reacts on enter
 	buttons.back()->assignedKeys.insert(SDLK_ESCAPE); //last button - reacts on escape
 
-	if(buttons.size() > 1  &&  askID >= 0) //cancel button functionality
+	if(buttons.size() > 1  &&  askID.getNum() >= 0) //cancel button functionality
 		buttons.back()->callback += boost::bind(&CCallback::selectionMade,LOCPLINT->cb,0,askID);
 
 	for(int i=0;i<comps.size();i++)
@@ -1296,7 +1296,7 @@ CSelWindow::CSelWindow(const std::string &Text, PlayerColor player, int charperl
 
 void CSelWindow::madeChoice()
 {
-	if(ID < 0)
+	if(ID.getNum() < 0)
 		return;
 	int ret = -1;
 	for (int i=0;i<components.size();i++)
@@ -5078,7 +5078,7 @@ void CExchangeWindow::prepareBackground()
 	new CAnimImage("PortraitsLarge", heroInst[1]->portrait, 0, 485, 13);
 }
 
-CExchangeWindow::CExchangeWindow(ObjectInstanceID hero1, ObjectInstanceID hero2):
+CExchangeWindow::CExchangeWindow(ObjectInstanceID hero1, ObjectInstanceID hero2, QueryID queryID):
     CWindowObject(PLAYER_COLORED | BORDERED, "TRADE2")
 {
 	OBJ_CONSTRUCTION_CAPTURING_ALL;
@@ -5165,6 +5165,9 @@ CExchangeWindow::CExchangeWindow(ObjectInstanceID hero1, ObjectInstanceID hero2)
 
 	//buttons
 	quit = new CAdventureMapButton(CGI->generaltexth->zelp[600], boost::bind(&CExchangeWindow::close, this), 732, 567, "IOKAY.DEF", SDLK_RETURN);
+	if(queryID.getNum() > 0)
+		quit->callback += [=]{ LOCPLINT->cb->selectionMade(0, queryID); };
+
 	questlogButton[0] = new CAdventureMapButton(CGI->generaltexth->heroscrn[0], "", boost::bind(&CExchangeWindow::questlog,this, 0), 10,  44, "hsbtns4.def");
 	questlogButton[1] = new CAdventureMapButton(CGI->generaltexth->heroscrn[0], "", boost::bind(&CExchangeWindow::questlog,this, 1), 740, 44, "hsbtns4.def");
 

+ 3 - 3
client/GUIClasses.h

@@ -87,7 +87,7 @@ class CInfoWindow : public CSimpleWindow
 public:
 	typedef std::vector<std::pair<std::string,CFunctionList<void()> > > TButtonsInfo;
 	typedef std::vector<CComponent*> TCompsInfo;
-	int ID; //for identification
+	QueryID ID; //for identification
 	CTextBox *text;
 	std::vector<CAdventureMapButton *> buttons;
 	std::vector<CComponent*> components;
@@ -117,7 +117,7 @@ class CSelWindow : public CInfoWindow
 public:
 	void selectionChange(unsigned to);
 	void madeChoice(); //looks for selected component and calls callback
-	CSelWindow(const std::string& text, PlayerColor player, int charperline ,const std::vector<CSelectableComponent*> &comps, const std::vector<std::pair<std::string,CFunctionList<void()> > > &Buttons, int askID); //c-tor
+	CSelWindow(const std::string& text, PlayerColor player, int charperline ,const std::vector<CSelectableComponent*> &comps, const std::vector<std::pair<std::string,CFunctionList<void()> > > &Buttons, QueryID askID); //c-tor
 	CSelWindow(){}; //c-tor
 	//notification - this class inherits important destructor from CInfoWindow
 };
@@ -1034,7 +1034,7 @@ public:
 
 	void prepareBackground(); //prepares or redraws bg
 
-	CExchangeWindow(ObjectInstanceID hero1, ObjectInstanceID hero2); //c-tor
+	CExchangeWindow(ObjectInstanceID hero1, ObjectInstanceID hero2, QueryID queryID); //c-tor
 	~CExchangeWindow(); //d-tor
 };
 

+ 6 - 8
client/NetPacksClient.cpp

@@ -588,6 +588,12 @@ void GarrisonDialog::applyCl(CClient *cl)
 	cl->playerint[h->getOwner()]->showGarrisonDialog(obj,h,removableUnits,queryID);
 }
 
+void ExchangeDialog::applyCl(CClient *cl)
+{
+	assert(heroes[0] && heroes[1]);
+	INTERFACE_CALL_IF_PRESENT(heroes[0]->tempOwner, heroExchangeStarted, heroes[0]->id, heroes[1]->id, queryID);
+}
+
 void BattleStart::applyCl( CClient *cl )
 {
 	cl->battleStarted(info);
@@ -829,14 +835,6 @@ void OpenWindow::applyCl(CClient *cl)
 {
 	switch(window)
 	{
-	case EXCHANGE_WINDOW:
-		{
-			const CGHeroInstance *h = cl->getHero(ObjectInstanceID(id1));
-			const CGObjectInstance *h2 = cl->getHero(ObjectInstanceID(id2));
-			assert(h && h2);
-			INTERFACE_CALL_IF_PRESENT(h->tempOwner,heroExchangeStarted, ObjectInstanceID(id1), ObjectInstanceID(id2));
-		}
-		break;
 	case RECRUITMENT_FIRST:
 	case RECRUITMENT_ALL:
 		{

+ 5 - 4
client/VCMI_client.vcxproj

@@ -94,13 +94,13 @@
   </PropertyGroup>
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
     <ClCompile>
-      <AdditionalOptions>/MP4 %(AdditionalOptions)</AdditionalOptions>
       <Optimization>
       </Optimization>
       <DisableSpecificWarnings>4251;%(DisableSpecificWarnings)</DisableSpecificWarnings>
       <AssemblerOutput>NoListing</AssemblerOutput>
       <PrecompiledHeader>Use</PrecompiledHeader>
       <PrecompiledHeaderFile>StdInc.h</PrecompiledHeaderFile>
+      <AdditionalOptions>/MP4 /Zm150</AdditionalOptions>
     </ClCompile>
     <Link>
       <AdditionalDependencies>SDL.lib;zlib.lib;SDL_image.lib;SDL_ttf.lib;SDL_mixer.lib;VCMI_lib.lib;%(AdditionalDependencies)</AdditionalDependencies>
@@ -114,13 +114,13 @@
   </ItemDefinitionGroup>
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
     <ClCompile>
-      <AdditionalOptions>/MP4 %(AdditionalOptions)</AdditionalOptions>
       <PreprocessToFile>false</PreprocessToFile>
       <PreprocessSuppressLineNumbers>false</PreprocessSuppressLineNumbers>
       <DisableSpecificWarnings>4251;%(DisableSpecificWarnings)</DisableSpecificWarnings>
       <AssemblerOutput>NoListing</AssemblerOutput>
       <PrecompiledHeader>Use</PrecompiledHeader>
       <PrecompiledHeaderFile>StdInc.h</PrecompiledHeaderFile>
+      <AdditionalOptions>/MP4 /Zm150</AdditionalOptions>
     </ClCompile>
     <Link>
       <AdditionalDependencies>SDL.lib;zlib.lib;SDL_image.lib;SDL_ttf.lib;SDL_mixer.lib;VCMI_lib.lib;%(AdditionalDependencies)</AdditionalDependencies>
@@ -136,6 +136,7 @@
     <ClCompile>
       <PrecompiledHeader>Use</PrecompiledHeader>
       <PrecompiledHeaderFile>StdInc.h</PrecompiledHeaderFile>
+      <AdditionalOptions>/MP4 /Zm150</AdditionalOptions>
     </ClCompile>
     <Link>
       <AdditionalDependencies>SDL.lib;zlib.lib;SDL_image.lib;SDL_ttf.lib;SDL_mixer.lib;VCMI_lib.lib;%(AdditionalDependencies)</AdditionalDependencies>
@@ -147,7 +148,7 @@
   </ItemDefinitionGroup>
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='RD|x64'">
     <ClCompile>
-      <AdditionalOptions>/Oy- %(AdditionalOptions)</AdditionalOptions>
+      <AdditionalOptions>/MP4 /Zm150</AdditionalOptions>
       <PrecompiledHeader>Use</PrecompiledHeader>
       <PrecompiledHeaderFile>StdInc.h</PrecompiledHeaderFile>
     </ClCompile>
@@ -260,4 +261,4 @@
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
   <ImportGroup Label="ExtensionTargets">
   </ImportGroup>
-</Project>
+</Project>

+ 23 - 23
client/VCMI_client.vcxproj.filters

@@ -2,10 +2,6 @@
 <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
   <ItemGroup>
     <ClCompile Include="AdventureMapClasses.cpp" />
-    <ClCompile Include="BattleInterface\CBattleAnimations.cpp" />
-    <ClCompile Include="BattleInterface\CBattleInterface.cpp" />
-    <ClCompile Include="BattleInterface\CBattleInterfaceClasses.cpp" />
-    <ClCompile Include="BattleInterface\CCreatureAnimation.cpp" />
     <ClCompile Include="CAdvmapInterface.cpp" />
     <ClCompile Include="CAnimation.cpp" />
     <ClCompile Include="..\CCallback.cpp" />
@@ -29,22 +25,22 @@
     <ClCompile Include="mapHandler.cpp" />
     <ClCompile Include="NetPacksClient.cpp" />
     <ClCompile Include="StdInc.cpp" />
-    <ClCompile Include="UIFramework\CCursorHandler.cpp" />
-    <ClCompile Include="UIFramework\CGuiHandler.cpp" />
-    <ClCompile Include="UIFramework\CIntObject.cpp" />
-    <ClCompile Include="UIFramework\CIntObjectClasses.cpp" />
-    <ClCompile Include="UIFramework\Geometries.cpp" />
-    <ClCompile Include="UIFramework\SDL_Extensions.cpp" />
     <ClCompile Include="CQuestLog.cpp" />
-    <ClCompile Include="UIFramework\Fonts.cpp" />
+    <ClCompile Include="battle\CBattleAnimations.cpp" />
+    <ClCompile Include="battle\CBattleInterface.cpp" />
+    <ClCompile Include="battle\CBattleInterfaceClasses.cpp" />
+    <ClCompile Include="battle\CCreatureAnimation.cpp" />
+    <ClCompile Include="gui\CCursorHandler.cpp" />
+    <ClCompile Include="gui\CGuiHandler.cpp" />
+    <ClCompile Include="gui\CIntObject.cpp" />
+    <ClCompile Include="gui\CIntObjectClasses.cpp" />
+    <ClCompile Include="gui\Fonts.cpp" />
+    <ClCompile Include="gui\Geometries.cpp" />
+    <ClCompile Include="gui\SDL_Extensions.cpp" />
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="..\Global.h" />
     <ClInclude Include="AdventureMapClasses.h" />
-    <ClInclude Include="BattleInterface\CBattleAnimations.h" />
-    <ClInclude Include="BattleInterface\CBattleInterface.h" />
-    <ClInclude Include="BattleInterface\CBattleInterfaceClasses.h" />
-    <ClInclude Include="BattleInterface\CCreatureAnimation.h" />
     <ClInclude Include="CAdvmapInterface.h" />
     <ClInclude Include="CAnimation.h" />
     <ClInclude Include="CBitmapHandler.h" />
@@ -69,19 +65,23 @@
     <ClInclude Include="GUIClasses.h" />
     <ClInclude Include="resource.h" />
     <ClInclude Include="StdInc.h" />
-    <ClInclude Include="UIFramework\CCursorHandler.h" />
-    <ClInclude Include="UIFramework\CGuiHandler.h" />
-    <ClInclude Include="UIFramework\CIntObject.h" />
-    <ClInclude Include="UIFramework\CIntObjectClasses.h" />
-    <ClInclude Include="UIFramework\Geometries.h" />
-    <ClInclude Include="UIFramework\SDL_Extensions.h" />
-    <ClInclude Include="UIFramework\SDL_Pixels.h" />
     <ClInclude Include="CQuestLog.h" />
     <ClCompile Include="CQuestLog.cpp">
       <Filter>Source Files</Filter>
     </ClCompile>
     <ClInclude Include="mapHandler.h" />
-    <ClInclude Include="UIFramework\Fonts.h" />
+    <ClInclude Include="battle\CBattleAnimations.h" />
+    <ClInclude Include="battle\CBattleInterface.h" />
+    <ClInclude Include="battle\CBattleInterfaceClasses.h" />
+    <ClInclude Include="battle\CCreatureAnimation.h" />
+    <ClInclude Include="gui\CCursorHandler.h" />
+    <ClInclude Include="gui\CGuiHandler.h" />
+    <ClInclude Include="gui\CIntObject.h" />
+    <ClInclude Include="gui\CIntObjectClasses.h" />
+    <ClInclude Include="gui\Fonts.h" />
+    <ClInclude Include="gui\Geometries.h" />
+    <ClInclude Include="gui\SDL_Extensions.h" />
+    <ClInclude Include="gui\SDL_Pixels.h" />
   </ItemGroup>
   <ItemGroup>
     <ResourceCompile Include="VCMI_client.rc" />

+ 4 - 4
lib/CGameInterface.h

@@ -80,16 +80,16 @@ public:
 	virtual void yourTurn(){}; //called AFTER playerStartsTurn(player)
 
 	//pskill is gained primary skill, interface has to choose one of given skills and call callback with selection id
-	virtual void heroGotLevel(const CGHeroInstance *hero, PrimarySkill::PrimarySkill pskill, std::vector<SecondarySkill> &skills, int queryID)=0;
-	virtual	void commanderGotLevel (const CCommanderInstance * commander, std::vector<ui32> skills, int queryID)=0;
+	virtual void heroGotLevel(const CGHeroInstance *hero, PrimarySkill::PrimarySkill pskill, std::vector<SecondarySkill> &skills, QueryID queryID)=0;
+	virtual	void commanderGotLevel (const CCommanderInstance * commander, std::vector<ui32> skills, QueryID queryID)=0;
 
 	// Show a dialog, player must take decision. If selection then he has to choose between one of given components,
 	// if cancel he is allowed to not choose. After making choice, CCallback::selectionMade should be called
 	// with number of selected component (1 - n) or 0 for cancel (if allowed) and askID.
-	virtual void showBlockingDialog(const std::string &text, const std::vector<Component> &components, ui32 askID, const int soundID, bool selection, bool cancel) = 0;
+	virtual void showBlockingDialog(const std::string &text, const std::vector<Component> &components, QueryID askID, const int soundID, bool selection, bool cancel) = 0;
 
 	// all stacks operations between these objects become allowed, interface has to call onEnd when done
-	virtual void showGarrisonDialog(const CArmedInstance *up, const CGHeroInstance *down, bool removableUnits, int queryID) = 0;
+	virtual void showGarrisonDialog(const CArmedInstance *up, const CGHeroInstance *down, bool removableUnits, QueryID queryID) = 0;
 	virtual void finish(){}; //if for some reason we want to end
 };
 

+ 12 - 0
lib/Connection.h

@@ -723,6 +723,12 @@ public:
 		for(ui32 i=0;i<length;i++)
 			*this << data[i];
 	}
+	template <typename T, size_t N>
+	void saveSerializable(const std::array<T, N> &data)
+	{
+		for(ui32 i=0; i < N; i++)
+			*this << data[i];
+	}
 	template <typename T>
 	void saveSerializable(const std::set<T> &data)
 	{
@@ -1077,6 +1083,12 @@ public:
 		for(ui32 i=0;i<length;i++)
 			*this >> data[i];
 	}
+	template <typename T, size_t N>
+	void loadSerializable(std::array<T, N> &data)
+	{
+		for(ui32 i = 0; i < N; i++)
+			*this >> data[i];
+	}
 	template <typename T>
 	void loadSerializable(std::set<T> &data)
 	{

+ 11 - 0
lib/GameConstants.h

@@ -183,6 +183,17 @@ class ArtifactInstanceID : public BaseForID<ArtifactInstanceID, si32>
 };
 
 
+class QueryID : public BaseForID<QueryID, si32>
+{
+	INSTID_LIKE_CLASS_COMMON(QueryID, si32)
+
+	QueryID & operator++()
+	{
+		++num;
+		return *this;
+	}
+};
+
 class ObjectInstanceID : public BaseForID<ObjectInstanceID, si32>
 {
 	INSTID_LIKE_CLASS_COMMON(ObjectInstanceID, si32)

+ 3 - 1
lib/IGameEventsReceiver.h

@@ -124,11 +124,13 @@ public:
 	virtual void playerBonusChanged(const Bonus &bonus, bool gain){};//if gain hero received bonus, else he lost it
 	virtual void requestSent(const CPackForServer *pack, int requestID){};
 	virtual void requestRealized(PackageApplied *pa){};
-	virtual void heroExchangeStarted(ObjectInstanceID hero1, ObjectInstanceID hero2){};
 	virtual void objectPropertyChanged(const SetObjectProperty * sop){}; //eg. mine has been flagged
 	virtual void objectRemoved(const CGObjectInstance *obj){}; //eg. collected resource, picked artifact, beaten hero
 	virtual void playerBlocked(int reason){}; //reason: 0 - upcoming battle
 	virtual void gameOver(PlayerColor player, bool victory){}; //player lost or won the game
 	virtual void playerStartsTurn(PlayerColor player){};
 	virtual void showComp(const Component &comp, std::string message) {}; //display component in the advmapint infobox
+
+	//TODO shouldnt be moved down the tree?
+	virtual void heroExchangeStarted(ObjectInstanceID hero1, ObjectInstanceID hero2, QueryID queryID){};
 };

+ 17 - 4
lib/NetPacks.h

@@ -81,11 +81,10 @@ struct CPackForServer : public CPack
 
 struct Query : public CPackForClient
 {
-	ui32 queryID; // equals to -1 if it is not an actual query (and should not be answered)
+	QueryID queryID; // equals to -1 if it is not an actual query (and should not be answered)
 
 	Query()
 	{
-		queryID = -1;
 	}
 };
 
@@ -1326,6 +1325,19 @@ struct GarrisonDialog : public Query//2004
 	}
 };
 
+struct ExchangeDialog : public Query//2005
+{
+	ExchangeDialog(){type = 2005;}
+	void applyCl(CClient *cl);
+
+	std::array<const CGHeroInstance*, 2> heroes;
+
+	template <typename Handler> void serialize(Handler &h, const int version)
+	{
+		h & queryID & heroes;
+	}
+};
+
 struct BattleInfo;
 struct BattleStart : public CPackForClient//3000
 {
@@ -2053,8 +2065,9 @@ struct BuildBoat : public CPackForServer
 struct QueryReply : public CPackForServer
 {
 	QueryReply(){type = 6000;};
-	QueryReply(ui32 QID, ui32 Answer):qid(QID),answer(Answer){type = 6000;};
-	ui32 qid, answer; //hero and artifact id
+	QueryReply(QueryID QID, ui32 Answer):qid(QID),answer(Answer){type = 6000;};
+	QueryID qid;
+	ui32 answer; //hero and artifact id
 	PlayerColor player;
 
 	bool applyGh(CGameHandler *gh);

+ 1 - 0
lib/RegisterTypes.h

@@ -160,6 +160,7 @@ void registerTypes2(Serializer &s)
 	s.template registerType<SetCommanderProperty>();
 	s.template registerType<BlockingDialog>();
 	s.template registerType<GarrisonDialog>();
+	s.template registerType<ExchangeDialog>();
 	s.template registerType<BattleStart>();
 	s.template registerType<BattleNextRound>();
 	s.template registerType<BattleSetActiveStack>();

+ 4 - 4
lib/VCMI_lib.vcxproj

@@ -95,7 +95,7 @@
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
     <ClCompile>
       <AdditionalOptions>/MP4 %(AdditionalOptions) /bigobj
-</AdditionalOptions>
+ /Zm150</AdditionalOptions>
       <Optimization>Disabled</Optimization>
       <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
       <MinimalRebuild>false</MinimalRebuild>
@@ -119,7 +119,7 @@
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
     <ClCompile>
       <AdditionalOptions>/MP4 %(AdditionalOptions) /bigobj
-</AdditionalOptions>
+ /Zm150</AdditionalOptions>
       <DisableSpecificWarnings>4251;%(DisableSpecificWarnings)</DisableSpecificWarnings>
       <ExpandAttributedSource>false</ExpandAttributedSource>
       <AssemblerOutput>NoListing</AssemblerOutput>
@@ -133,7 +133,7 @@
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='RD|Win32'">
     <ClCompile>
       <AdditionalOptions>/Oy- %(AdditionalOptions) /bigobj
-</AdditionalOptions>
+ /Zm150</AdditionalOptions>
       <PreprocessorDefinitions>VCMI_DLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <PrecompiledHeaderFile>StdInc.h</PrecompiledHeaderFile>
       <PrecompiledHeader>Use</PrecompiledHeader>
@@ -149,7 +149,7 @@
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='RD|x64'">
     <ClCompile>
       <AdditionalOptions>/Oy- %(AdditionalOptions) /bigobj
-</AdditionalOptions>
+ /Zm150</AdditionalOptions>
       <PreprocessorDefinitions>VCMI_DLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <PrecompiledHeader>Use</PrecompiledHeader>
       <PrecompiledHeaderFile>StdInc.h</PrecompiledHeaderFile>

+ 4 - 4
scripting/erm/ERM.vcxproj

@@ -27,27 +27,27 @@
     <ConfigurationType>DynamicLibrary</ConfigurationType>
     <UseDebugLibraries>true</UseDebugLibraries>
     <CharacterSet>MultiByte</CharacterSet>
-    <PlatformToolset>v100</PlatformToolset>
+    <PlatformToolset>v110_xp</PlatformToolset>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
     <ConfigurationType>DynamicLibrary</ConfigurationType>
     <UseDebugLibraries>true</UseDebugLibraries>
     <CharacterSet>MultiByte</CharacterSet>
-    <PlatformToolset>v110</PlatformToolset>
+    <PlatformToolset>v110_xp</PlatformToolset>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='RD|Win32'" Label="Configuration">
     <ConfigurationType>DynamicLibrary</ConfigurationType>
     <UseDebugLibraries>false</UseDebugLibraries>
     <WholeProgramOptimization>true</WholeProgramOptimization>
     <CharacterSet>MultiByte</CharacterSet>
-    <PlatformToolset>v100</PlatformToolset>
+    <PlatformToolset>v110</PlatformToolset>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='RD|x64'" Label="Configuration">
     <ConfigurationType>DynamicLibrary</ConfigurationType>
     <UseDebugLibraries>false</UseDebugLibraries>
     <WholeProgramOptimization>true</WholeProgramOptimization>
     <CharacterSet>MultiByte</CharacterSet>
-    <PlatformToolset>v110_xp</PlatformToolset>
+    <PlatformToolset>v110</PlatformToolset>
   </PropertyGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
   <ImportGroup Label="ExtensionSettings">

+ 9 - 8
server/CGameHandler.cpp

@@ -2119,17 +2119,18 @@ void CGameHandler::useScholarSkill(ObjectInstanceID fromHero, ObjectInstanceID t
 
 void CGameHandler::heroExchange(ObjectInstanceID hero1, ObjectInstanceID hero2)
 {
-	PlayerColor player1 = getHero(hero1)->tempOwner;
-	PlayerColor player2 = getHero(hero2)->tempOwner;
+	auto h1 = getHero(hero1), h2 = getHero(hero2);
 
-	if( gameState()->getPlayerRelations( player1, player2))
+	if( gameState()->getPlayerRelations(h1->getOwner(), h2->getOwner()))
 	{
-		OpenWindow hex;
-		hex.window = OpenWindow::EXCHANGE_WINDOW;
-		hex.id1 = hero1.getNum();
-		hex.id2 = hero2.getNum();
+		auto exchange = make_shared<CGarrisonDialogQuery>(h1, h2);
+		ExchangeDialog hex;
+		hex.queryID = exchange->queryID;
+		hex.heroes[0] = getHero(hero1);
+		hex.heroes[1] = getHero(hero2);
 		sendAndApply(&hex);
 		useScholarSkill(hero1,hero2);
+		queries.addQuery(exchange);
 	}
 }
 
@@ -3204,7 +3205,7 @@ bool CGameHandler::hireHero(const CGObjectInstance *obj, ui8 hid, PlayerColor pl
 	return true;
 }
 
-bool CGameHandler::queryReply(ui32 qid, ui32 answer, PlayerColor player)
+bool CGameHandler::queryReply(QueryID qid, ui32 answer, PlayerColor player)
 {
 	boost::unique_lock<boost::recursive_mutex> lock(gsm);
 

+ 1 - 1
server/CGameHandler.h

@@ -207,7 +207,7 @@ public:
 	void stackTurnTrigger(const CStack * stack);
 	void handleDamageFromObstacle(const CObstacleInstance &obstacle, const CStack * curStack); //checks if obstacle is land mine and handles possible consequences
 	void removeObstacle(const CObstacleInstance &obstacle);
-	bool queryReply( ui32 qid, ui32 answer, PlayerColor player );
+	bool queryReply( QueryID qid, ui32 answer, PlayerColor player );
 	bool hireHero( const CGObjectInstance *obj, ui8 hid, PlayerColor player );
 	bool buildBoat( ObjectInstanceID objid );
 	bool setFormation( ObjectInstanceID hid, ui8 formation );

+ 1 - 1
server/CQuery.cpp

@@ -37,7 +37,7 @@ CQuery::CQuery(void)
 {
 	boost::unique_lock<boost::mutex> l(Queries::mx);
 
-	static TQueryID QID = 1;
+	static QueryID QID = QueryID(1);
 
 	queryID = QID++;
 	logGlobal->traceStream() << "Created a new query with id " << queryID;

+ 2 - 3
server/CQuery.h

@@ -12,7 +12,6 @@ class CObjectVisitQuery;
 struct TryMoveHero;
 class CQuery;
 
-typedef si32 TQueryID;
 typedef shared_ptr<CQuery> QueryPtr;
 
 // This class represents any kind of prolonged interaction that may need to do something special after it is over.
@@ -29,7 +28,7 @@ protected:
 	void addPlayer(PlayerColor color);
 public:
 	std::vector<PlayerColor> players; //players that are affected (often "blocked") by query
-	TQueryID queryID;
+	QueryID queryID;
 
 	CQuery(void);
 
@@ -109,7 +108,7 @@ public:
 	virtual bool blocksPack(const CPack *pack) const OVERRIDE;
 };
 
-class CGarrisonDialogQuery : public CDialogQuery
+class CGarrisonDialogQuery : public CDialogQuery //used also for hero exchange dialogs
 {
 public:
 	std::array<const CArmedInstance *,2> exchangingArmies;

+ 1 - 1
server/NetPacksServer.cpp

@@ -232,7 +232,7 @@ bool QueryReply::applyGh( CGameHandler *gh )
 		COMPLAIN_AND_RETURN("No such player!");
 	if(playerToConnection->second != c)
 		COMPLAIN_AND_RETURN("Message came from wrong connection!");
-	if(qid == -1)
+	if(qid == QueryID(-1))
 		COMPLAIN_AND_RETURN("Cannot answer the query with id -1!");
 
 	assert(vstd::contains(gh->states.players, player));