瀏覽代碼

* fixed crash on closing application
* unified yes/no and selection dialog interface calls
* VCMI won't anymore be always giving all three stacks in the starting armies
* fix for drawing starting army creatures count
* support for School of Magic
* support for School of War
* support for Pillar of Fire
* minor changes

Michał W. Urbańczyk 16 年之前
父節點
當前提交
d72d988a9c

+ 6 - 0
AI/GeniusAI/CGeniusAI.cpp

@@ -63,6 +63,12 @@ void CGeniusAI::heroGotLevel(const CGHeroInstance *hero, int pskill, std::vector
 {
 	callback(rand() % skills.size());
 }
+
+void CGeniusAI::showBlockingDialog( const std::string &text, const std::vector<Component> &components, ui32 askID, bool selection, bool cancel )
+{
+	m_cb->selectionMade(cancel ? 0 : 1, askID);
+}
+
 /**
  * occurs AFTER every action taken by any stack or by the hero
  */

+ 1 - 0
AI/GeniusAI/CGeniusAI.h

@@ -190,6 +190,7 @@ public:
 	virtual void heroMoved(const HeroMoveDetails &);
 	virtual void heroPrimarySkillChanged(const CGHeroInstance * hero, int which, int val) {};
 	virtual void showSelDialog(std::string text, std::vector<CSelectableComponent*> & components, int askID){};
+	virtual void showBlockingDialog(const std::string &text, const std::vector<Component> &components, ui32 askID, bool selection, bool cancel); 
 	virtual void tileRevealed(int3 pos){};
 	virtual void tileHidden(int3 pos){};
 	virtual void heroGotLevel(const CGHeroInstance *hero, int pskill, std::vector<ui16> &skills, boost::function<void(ui32)> &callback);

+ 9 - 0
CAdvmapInterface.cpp

@@ -1245,6 +1245,7 @@ endTurn(CGI->generaltexth->zelp[302].first,CGI->generaltexth->zelp[302].second,
 heroList(ADVOPT.hlistSize),
 townList(ADVOPT.tlistSize,ADVOPT.tlistX,ADVOPT.tlistY,ADVOPT.tlistAU,ADVOPT.tlistAD)//(5,&genRect(192,48,747,196),747,196,747,372),
 {
+	active = 0;
 	subInt = NULL;
 	selection = NULL;
 	townList.fun = boost::bind(&CAdvMapInt::selectionChanged,this);
@@ -1363,6 +1364,10 @@ void CAdvMapInt::fendTurn()
 
 void CAdvMapInt::activate()
 {
+	if(active++)
+	{
+		tlog1 << "Error: advmapint already active...\n";
+	}
 	if(subInt == heroWindow)
 	{
 		heroWindow->activate();
@@ -1392,6 +1397,10 @@ void CAdvMapInt::activate()
 }
 void CAdvMapInt::deactivate()
 {
+	if(--active)
+	{
+		tlog1 << "Error: advmapint still active...\n";
+	}
 	if(subInt == heroWindow)
 	{
 		heroWindow->deactivate();

+ 1 - 1
CAdvmapInterface.h

@@ -107,7 +107,7 @@ public:
 	~CAdvMapInt();
 
 	int3 position; //top left corner of visible map part
-	int player;
+	int player, active;
 
 	std::vector<CDefHandler *> gems;
 

+ 1 - 0
CCallback.h

@@ -32,6 +32,7 @@ class ICallback
 {
 public:
 	virtual bool moveHero(const CGHeroInstance *h, int3 dst) const =0; //dst must be free, neighbouring tile (this function can move hero only by one tile)
+	virtual void selectionMade(int selection, int asker) =0;
 	virtual int swapCreatures(const CGObjectInstance *s1, const CGObjectInstance *s2, int p1, int p2)=0;//swaps creatures between two posiibly different garrisons // TODO: AI-unsafe code - fix it!
 	virtual int mergeStacks(const CGObjectInstance *s1, const CGObjectInstance *s2, int p1, int p2)=0;//joins first stack tothe second (creatures must be same type)
 	virtual int splitStack(const CGObjectInstance *s1, const CGObjectInstance *s2, int p1, int p2, int val)=0;//split creatures from the first stack

+ 3 - 2
CGameInterface.h

@@ -69,8 +69,9 @@ public:
 	virtual void init(ICallback * CB){};
 	virtual void receivedResource(int type, int val){};
 	virtual void showInfoDialog(const std::string &text, const std::vector<Component*> &components){};
-	virtual void showSelDialog(const std::string &text, const std::vector<Component*> &components, ui32 askID){};
-	virtual void showYesNoDialog(const std::string &text, const std::vector<Component*> &components, ui32 askID){};
+	//virtual void showSelDialog(const std::string &text, const std::vector<Component*> &components, ui32 askID){};
+	//virtual void showYesNoDialog(const std::string &text, const std::vector<Component*> &components, ui32 askID){};
+	virtual void showBlockingDialog(const std::string &text, const std::vector<Component> &components, ui32 askID, bool selection, bool cancel) = 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 tileHidden(const std::set<int3> &pos){};
 	virtual void tileRevealed(const std::set<int3> &pos){};
 	virtual void yourTurn(){};

+ 6 - 3
CMT.cpp

@@ -45,11 +45,14 @@
 #if __MINGW32__
 #undef main
 #endif
-std::string NAME = NAME_VER + std::string(" (client)");
-SDL_Surface * screen, * screen2;
+std::string NAME = NAME_VER + std::string(" (client)"); //application name
+SDL_Surface * screen; //main screen surface
+
 std::queue<SDL_Event*> events;
 boost::mutex eventsM;
+
 TTF_Font * TNRB16, *TNR, *GEOR13, *GEORXX, *GEORM, *GEOR16;
+
 void processCommand(const std::string &message, CClient *&client);
 #ifndef __GNUC__
 int _tmain(int argc, _TCHAR* argv[])
@@ -196,11 +199,11 @@ int main(int argc, char** argv)
 			SDL_WaitEvent(ev);
 			if((ev->type==SDL_QUIT)  ||  (ev->type == SDL_KEYDOWN && ev->key.keysym.sym==SDLK_F4 && (ev->key.keysym.mod & KMOD_ALT)))
 			{
+				LOCPLINT->pim->lock();
 				cl.close();
 #ifndef __unix__
 				::console->killConsole(console->native_handle());
 #endif
-				LOCPLINT->pim->lock();
 				SDL_Delay(750);
 				tlog0 << "Ending...\n";
 				exit(EXIT_SUCCESS);

+ 141 - 128
CPlayerInterface.cpp

@@ -564,16 +564,16 @@ void CGarrisonInt::deactivate()
 
 CInfoWindow::CInfoWindow(std::string text, int player, int charperline, const std::vector<SComponent*> &comps, std::vector<std::pair<std::string,CFunctionList<void()> > > &Buttons)
 {
+	ID = -1;
 	for(int i=0;i<Buttons.size();i++)
 	{
 		buttons.push_back(new AdventureMapButton("","",Buttons[i].second,0,0,Buttons[i].first));
-		if(!Buttons[i].second) //if no function, then by default we'll set it to close
-		{
-			buttons[i]->assignedKeys.insert(SDLK_RETURN);
-			buttons[i]->assignedKeys.insert(SDLK_ESCAPE);
-			buttons[i]->callback += boost::bind(&CInfoWindow::close,this);
-		}
+		buttons[i]->callback += boost::bind(&CInfoWindow::close,this); //each button will close the window apart from call-defined actions
 	}
+
+	buttons.front()->assignedKeys.insert(SDLK_RETURN); //first button - reacts on enter
+	buttons.back()->assignedKeys.insert(SDLK_ESCAPE); //last button - reacts on escape
+
 	for(int i=0;i<comps.size();i++)
 	{
 		components.push_back(comps[i]);
@@ -582,6 +582,7 @@ CInfoWindow::CInfoWindow(std::string text, int player, int charperline, const st
 }
 CInfoWindow::CInfoWindow() 
 {
+	ID = -1;
 }
 void CInfoWindow::close()
 {
@@ -906,15 +907,22 @@ void CSelWindow::selectionChange(unsigned to)
 		blitAt(pom->getImg(),pom->pos.x-pos.x,pom->pos.y-pos.y,bitmap);
 	}
 }
-CSelWindow::CSelWindow(std::string text, int player, int charperline, std::vector<CSelectableComponent*> &comps, std::vector<std::pair<std::string,boost::function<void()> > > &Buttons)
+CSelWindow::CSelWindow(const std::string &text, int player, int charperline, const std::vector<CSelectableComponent*> &comps, const std::vector<std::pair<std::string,CFunctionList<void()> > > &Buttons, int askID)
 {
+	ID = askID;
 	for(int i=0;i<Buttons.size();i++)
 	{
-		buttons.push_back(new AdventureMapButton("","",(Buttons[i].second)?(Buttons[i].second):(boost::bind(&CInfoWindow::close,this)),0,0,Buttons[i].first));
+		buttons.push_back(new AdventureMapButton("","",Buttons[i].second,0,0,Buttons[i].first));
+		if(!i  &&  askID >= 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
 	}
 
-	if(Buttons.size() == 1) //only one button - assign enter to it
-		buttons[0]->assignedKeys.insert(SDLK_RETURN);
+	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
+		buttons.back()->callback += boost::bind(&ICallback::selectionMade,LOCPLINT->cb,0,askID);
 
 	for(int i=0;i<comps.size();i++)
 	{
@@ -928,6 +936,14 @@ CSelWindow::CSelWindow(std::string text, int player, int charperline, std::vecto
 void CSelWindow::close()
 {
 	deactivate();
+	LOCPLINT->showingDialog->setn(false);
+	delete this;
+}
+
+void CSelWindow::madeChoice()
+{
+	if(ID < 0)
+		return;
 	int ret = -1;
 	for (int i=0;i<components.size();i++)
 	{
@@ -936,11 +952,9 @@ void CSelWindow::close()
 			ret = i;
 		}
 	}
-	LOCPLINT->curint->activate();
-	LOCPLINT->showingDialog->setn(false);
-	LOCPLINT->cb->selectionMade(ret,ID);
-	delete this;
+	LOCPLINT->cb->selectionMade(ret+1,ID);
 }
+
 CButtonBase::CButtonBase()
 {
 	bitmapOffset = 0;
@@ -1130,95 +1144,102 @@ void CPlayerInterface::init(ICallback * CB)
 }
 void CPlayerInterface::yourTurn()
 {
-	LOCPLINT = this;
-	makingTurn = true;
-
-	for(std::map<int,SDL_Surface*>::iterator i=graphics->heroWins.begin(); i!=graphics->heroWins.end();i++) //redraw hero infoboxes
-		SDL_FreeSurface(i->second);
-	graphics->heroWins.clear();
-	std::vector <const CGHeroInstance *> hh = cb->getHeroesInfo(false);
-	for(int i=0;i<hh.size();i++)
+	try
 	{
-		SDL_Surface * pom = infoWin(hh[i]);
-		graphics->heroWins.insert(std::pair<int,SDL_Surface*>(hh[i]->subID,pom));
-	}
-
-	adventureInt->infoBar.newDay(cb->getDate(1));
+		LOCPLINT = this;
+		makingTurn = true;
 
-	//select first hero if available.
-	//TODO: check if hero is slept
-	if(adventureInt->heroList.items.size())
-		adventureInt->select(adventureInt->heroList.items[0].first);
-	else
-		adventureInt->select(adventureInt->townList.items[0]);
-	adventureInt->activate();
+		static int autosaveCount = 0;
+		LOCPLINT->cb->save("Autosave_" + boost::lexical_cast<std::string>(autosaveCount++ + 1));
+		autosaveCount %= 5;
 
+		for(std::map<int,SDL_Surface*>::iterator i=graphics->heroWins.begin(); i!=graphics->heroWins.end();i++) //redraw hero infoboxes
+			SDL_FreeSurface(i->second);
+		graphics->heroWins.clear();
+		std::vector <const CGHeroInstance *> hh = cb->getHeroesInfo(false);
+		for(int i=0;i<hh.size();i++)
+		{
+			SDL_Surface * pom = infoWin(hh[i]);
+			graphics->heroWins.insert(std::pair<int,SDL_Surface*>(hh[i]->subID,pom));
+		}
 
-	timeHandler th;
-	th.getDif();
-	for(;makingTurn;) // main loop
-	{
+		adventureInt->infoBar.newDay(cb->getDate(1));
 
-		updateWater();
-		pim->lock();
+		//select first hero if available.
+		//TODO: check if hero is slept
+		if(adventureInt->heroList.items.size())
+			adventureInt->select(adventureInt->heroList.items[0].first);
+		else
+			adventureInt->select(adventureInt->townList.items[0]);
+		adventureInt->activate();
 
 
-		//if there are any waiting dialogs, show them
-		if(dialogs.size() && !showingDialog->get())
+		timeHandler th;
+		th.getDif();
+		while(makingTurn) // main loop
 		{
-			dialogs.front()->buttons[0]->callback += boost::bind(&IActivable::activate,LOCPLINT->curint);
-			showingDialog->set(true);
-			curint->deactivate(); //dezaktywacja starego interfejsu
-			dialogs.front()->activate();
-			LOCPLINT->objsToBlit.push_back(dialogs.front());
-			dialogs.pop_front();
-		}
 
-		int tv = th.getDif();
-		std::list<TimeInterested*> hlp = timeinterested;
-		for (std::list<TimeInterested*>::iterator i=hlp.begin(); i != hlp.end();i++)
-		{
-			if(!vstd::contains(timeinterested,*i)) continue;
-			if ((*i)->toNextTick>=0)
-				(*i)->toNextTick-=tv;
-			if ((*i)->toNextTick<0)
-				(*i)->tick();
-		}
-		LOCPLINT->adventureInt->updateScreen = false;
+			updateWater();
+			pim->lock();
 
-		while(true)
-		{
-			SDL_Event *ev = NULL;
+
+			//if there are any waiting dialogs, show them
+			if(dialogs.size() && !showingDialog->get())
 			{
-				boost::unique_lock<boost::mutex> lock(eventsM);
-				if(!events.size())
-				{
-					break;
-				}
-				else
+				dialogs.front()->buttons[0]->callback += boost::bind(&IActivable::activate,LOCPLINT->curint);
+				showingDialog->set(true);
+				curint->deactivate(); //dezaktywacja starego interfejsu
+				dialogs.front()->activate();
+				LOCPLINT->objsToBlit.push_back(dialogs.front());
+				dialogs.pop_front();
+			}
+
+			int tv = th.getDif();
+			std::list<TimeInterested*> hlp = timeinterested;
+			for (std::list<TimeInterested*>::iterator i=hlp.begin(); i != hlp.end();i++)
+			{
+				if(!vstd::contains(timeinterested,*i)) continue;
+				if ((*i)->toNextTick>=0)
+					(*i)->toNextTick-=tv;
+				if ((*i)->toNextTick<0)
+					(*i)->tick();
+			}
+			LOCPLINT->adventureInt->updateScreen = false;
+
+			while(true)
+			{
+				SDL_Event *ev = NULL;
 				{
-					ev = events.front();
-					events.pop();
+					boost::unique_lock<boost::mutex> lock(eventsM);
+					if(!events.size())
+					{
+						break;
+					}
+					else
+					{
+						ev = events.front();
+						events.pop();
+					}
 				}
+				handleEvent(ev);
+				delete ev;
 			}
-			handleEvent(ev);
-			delete ev;
-		}
 
-		if (curint == adventureInt) //stuff for advMapInt
-		{
-			adventureInt->update();
+			if (curint == adventureInt) //stuff for advMapInt
+			{
+				adventureInt->update();
+			}
+			for(int i=0;i<objsToBlit.size();i++)
+				objsToBlit[i]->show();
+			CGI->curh->draw1();
+			CSDL_Ext::update(screen);
+			CGI->curh->draw2();
+			pim->unlock();
+			SDL_framerateDelay(mainFPSmng);
 		}
-		for(int i=0;i<objsToBlit.size();i++)
-			objsToBlit[i]->show();
-		CGI->curh->draw1();
-		CSDL_Ext::update(screen);
-		CGI->curh->draw2();
-		pim->unlock();
-		SDL_framerateDelay(mainFPSmng);
-	}
-	adventureInt->deactivate();
-	cb->endTurn();
+		adventureInt->deactivate();
+		cb->endTurn();
+	} HANDLE_EXCEPTION
 }
 
 inline void subRect(const int & x, const int & y, const int & z, const SDL_Rect & r, const int & hid)
@@ -2033,24 +2054,6 @@ void CPlayerInterface::receivedResource(int type, int val)
 		castleInt->resdatabar->draw();
 }
 
-void CPlayerInterface::showSelDialog(const std::string &text, const std::vector<Component*> &components, ui32 askID)
-//void CPlayerInterface::showSelDialog(std::string text, std::vector<CSelectableComponent*> & components, int askID)
-{
-	boost::unique_lock<boost::recursive_mutex> un(*pim);
-	LOCPLINT->showingDialog->setn(true);
-	adventureInt->deactivate(); //dezaktywacja starego interfejsu
-	std::vector<CSelectableComponent*> intComps;
-	for(int i=0;i<components.size();i++)
-		intComps.push_back(new CSelectableComponent(*components[i])); //will be deleted by CSelWindow::close
-	std::vector<std::pair<std::string,boost::function<void()> > > pom;
-	pom.push_back(std::pair<std::string,boost::function<void()> >("IOKAY.DEF",0));
-
-	CSelWindow * temp = new CSelWindow(text,playerID,35,intComps,pom);
-	LOCPLINT->objsToBlit.push_back(temp);
-	temp->activate();
-	temp->ID = askID;
-	intComps[0]->clickLeft(true);
-}
 void CPlayerInterface::heroGotLevel(const CGHeroInstance *hero, int pskill, std::vector<ui16>& skills, boost::function<void(ui32)> &callback)
 {
 	{
@@ -2424,6 +2427,7 @@ void CPlayerInterface::showInfoDialog(const std::string &text, const std::vector
 		dialogs.push_back(temp);
 	}
 }
+
 void CPlayerInterface::showYesNoDialog(const std::string &text, const std::vector<SComponent*> & components, CFunctionList<void()> onYes, CFunctionList<void()> onNo, bool deactivateCur, bool DelComps)
 {
 	boost::unique_lock<boost::recursive_mutex> un(*pim);
@@ -2431,8 +2435,8 @@ void CPlayerInterface::showYesNoDialog(const std::string &text, const std::vecto
 	if(deactivateCur)
 		curint->deactivate(); //dezaktywacja starego interfejsu
 	std::vector<std::pair<std::string,CFunctionList<void()> > > pom;
-	pom.push_back(std::pair<std::string,CFunctionList<void()> >("IOKAY.DEF",0));
-	pom.push_back(std::pair<std::string,CFunctionList<void()> >("ICANCEL.DEF",0));
+	pom.push_back(std::pair<std::string,CFunctionList<void()> >("IOKAY.DEF",boost::bind(&IActivable::activate,curint)));
+	pom.push_back(std::pair<std::string,CFunctionList<void()> >("ICANCEL.DEF",boost::bind(&IActivable::activate,curint)));
 	CInfoWindow * temp = new CInfoWindow(text,playerID,36,components,pom);
 	temp->delComps = DelComps;
 	for(int i=0;i<onYes.funcs.size();i++)
@@ -2440,37 +2444,46 @@ void CPlayerInterface::showYesNoDialog(const std::string &text, const std::vecto
 	for(int i=0;i<onNo.funcs.size();i++)
 		temp->buttons[1]->callback += onNo.funcs[i];
 
-	//if(onYes)
-	//	temp->buttons[0]->callback += boost::bind(&CInfoWindow::close,temp);
-	//if(onNo)
-	//	temp->buttons[1]->callback += boost::bind(&CInfoWindow::close,temp);
 	temp->activate();
 	LOCPLINT->objsToBlit.push_back(temp);
 }
 
-void CPlayerInterface::showYesNoDialog(const  std::string &text, const std::vector<Component*> &components, ui32 askID )
+void CPlayerInterface::showBlockingDialog( const std::string &text, const std::vector<Component> &components, ui32 askID, bool selection, bool cancel )
 {
 	boost::unique_lock<boost::recursive_mutex> un(*pim);
-	LOCPLINT->showingDialog->setn(false);
-	curint->deactivate(); //dezaktywacja starego interfejsu
 
-	std::vector<SComponent*> intComps;
-	for(int i=0;i<components.size();i++)
-		intComps.push_back(new SComponent(*components[i])); //will be deleted by CSelWindow::close
-	std::vector<std::pair<std::string,CFunctionList<void()> > > pom;
-	pom.push_back(std::pair<std::string,CFunctionList<void()> >("IOKAY.DEF",0));
-	pom.push_back(std::pair<std::string,CFunctionList<void()> >("ICANCEL.DEF",0));
 
-	CInfoWindow * temp = new CInfoWindow(text,playerID,36,intComps,pom);
-	temp->buttons[0]->callback += boost::bind(&IActivable::activate,curint);
-	temp->buttons[1]->callback += boost::bind(&IActivable::activate,curint);
-	temp->buttons[0]->callback += boost::bind(&CCallback::selectionMade,cb,0,askID);
-	temp->buttons[1]->callback += boost::bind(&CCallback::selectionMade,cb,1,askID);
-	temp->delComps = true;
+	if(!selection && cancel) //simple yes/no dialog
+	{
+		std::vector<SComponent*> intComps;
+		for(int i=0;i<components.size();i++)
+			intComps.push_back(new SComponent(components[i])); //will be deleted by close in window
+
+		showYesNoDialog(text,intComps,boost::bind(&CCallback::selectionMade,cb,1,askID),boost::bind(&CCallback::selectionMade,cb,0,askID),true,true);
+	}
+	else if(selection)
+	{
+		std::vector<CSelectableComponent*> intComps;
+		for(int i=0;i<components.size();i++)
+			intComps.push_back(new CSelectableComponent(components[i])); //will be deleted by CSelWindow::close
+
+		adventureInt->deactivate(); //dezaktywacja starego interfejsu
+
+		std::vector<std::pair<std::string,CFunctionList<void()> > > pom;
+		pom.push_back(std::pair<std::string,CFunctionList<void()> >("IOKAY.DEF",boost::bind(&IActivable::activate,curint)));
+		if(cancel)
+		{
+			pom.push_back(std::pair<std::string,CFunctionList<void()> >("ICANCEL.DEF",boost::bind(&IActivable::activate,curint)));
+		}
+
+		CSelWindow * temp = new CSelWindow(text,playerID,35,intComps,pom,askID);
+		LOCPLINT->objsToBlit.push_back(temp);
+		temp->activate();
+		intComps[0]->clickLeft(true);
+	}
 
-	temp->activate();
-	LOCPLINT->objsToBlit.push_back(temp);
 }
+
 void CPlayerInterface::removeObjToBlit(IShowable* obj)
 {
 	boost::unique_lock<boost::recursive_mutex> un(*pim);

+ 5 - 3
CPlayerInterface.h

@@ -358,7 +358,8 @@ class CSelWindow : public CInfoWindow //component selection window
 public:
 	void selectionChange(unsigned to);
 	void close();
-	CSelWindow(std::string text, int player, int charperline, std::vector<CSelectableComponent*> &comps, std::vector<std::pair<std::string,boost::function<void()> > > &Buttons); //c-tor
+	void madeChoice(); //looks for selected component and calls callback
+	CSelWindow(const std::string& text, int player, int charperline ,const std::vector<CSelectableComponent*> &comps, const std::vector<std::pair<std::string,CFunctionList<void()> > > &Buttons, int askID); //c-tor
 	CSelWindow(){}; //c-tor
 	//notification - this class inherits important destructor from CInfoWindow
 };
@@ -544,8 +545,9 @@ public:
 	void heroVisitsTown(const CGHeroInstance* hero, const CGTownInstance * town);
 	void receivedResource(int type, int val);
 	void showInfoDialog(const std::string &text, const std::vector<Component*> &components);
-	void showSelDialog(const std::string &text, const std::vector<Component*> &components, ui32 askID);
-	void showYesNoDialog(const std::string &text, const std::vector<Component*> &components, ui32 askID);
+	//void showSelDialog(const std::string &text, const std::vector<Component*> &components, ui32 askID);
+	//void showYesNoDialog(const std::string &text, const std::vector<Component*> &components, ui32 askID);
+	void showBlockingDialog(const std::string &text, const std::vector<Component> &components, ui32 askID, bool selection, bool cancel); //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 tileHidden(const std::set<int3> &pos);
 	void tileRevealed(const std::set<int3> &pos);
 	void yourTurn();

+ 23 - 20
client/Client.cpp

@@ -109,29 +109,32 @@ void CClient::waitForMoveAndSend(int color)
 }
 void CClient::run()
 {
-	CPack *pack;
-	while(1)
+	try
 	{
-		tlog5 << "Listening... ";
-		*serv >> pack;
-		tlog5 << "\treceived server message of type " << typeid(*pack).name() << std::endl;
-		CBaseForCLApply *apply = applier->apps[typeList.getTypeID(pack)];
-		if(apply)
-		{
-			apply->applyOnClBefore(this,pack);
-			tlog5 << "\tMade first apply on cl\n";
-			gs->apply(pack);
-			tlog5 << "\tApplied on gs\n";
-			apply->applyOnClAfter(this,pack);
-			tlog5 << "\tMade second apply on cl\n";
-		}
-		else
+		CPack *pack;
+		while(1)
 		{
-			tlog5 << "Message cannot be applied, cannot find applier!\n";
+			tlog5 << "Listening... ";
+			*serv >> pack;
+			tlog5 << "\treceived server message of type " << typeid(*pack).name() << std::endl;
+			CBaseForCLApply *apply = applier->apps[typeList.getTypeID(pack)];
+			if(apply)
+			{
+				apply->applyOnClBefore(this,pack);
+				tlog5 << "\tMade first apply on cl\n";
+				gs->apply(pack);
+				tlog5 << "\tApplied on gs\n";
+				apply->applyOnClAfter(this,pack);
+				tlog5 << "\tMade second apply on cl\n";
+			}
+			else
+			{
+				tlog5 << "Message cannot be applied, cannot find applier!\n";
+			}
+			delete pack;
+			pack = NULL;
 		}
-		delete pack;
-		pack = NULL;
-	}
+	} HANDLE_EXCEPTION(tlog1 << "Lost connection to server, ending listening thread!\n");
 }
 
 void CClient::close()

+ 2 - 2
client/Client.h

@@ -77,8 +77,8 @@ public:
 	void changePrimSkill(int ID, int which, int val, bool abs=false){};
 	void changeSecSkill(int ID, int which, int val, bool abs=false){}; 
 	void showInfoDialog(InfoWindow *iw){};
-	void showYesNoDialog(YesNoDialog *iw, const CFunctionList<void(ui32)> &callback){};
-	void showSelectionDialog(SelectionDialog *iw, const CFunctionList<void(ui32)> &callback){}; //returns question id
+	void showBlockingDialog(BlockingDialog *iw, const CFunctionList<void(ui32)> &callback){};
+	ui32 showBlockingDialog(BlockingDialog *iw){return 0;}; //synchronous version of above
 	void giveResource(int player, int which, int val){};
 	void showCompInfo(ShowInInfobox * comp){};
 	void heroVisitCastle(int obj, int heroID){};

+ 3 - 20
client/NetPacksClient.cpp

@@ -282,28 +282,11 @@ void HeroLevelUp::applyCl( CClient *cl )
 	}
 }
 
-void SelectionDialog::applyCl( CClient *cl )
+void BlockingDialog::applyCl( CClient *cl )
 {
-	std::vector<Component*> comps;
-	for(size_t i=0; i < components.size(); ++i) {
-		comps.push_back(&components[i]);
-	}
-	std::string str = toString(text);
-	if(vstd::contains(cl->playerint,player))
-		cl->playerint[player]->showSelDialog(str,comps,id);
-	else
-		tlog2 << "We received SelectionDialog for not our player...\n";
-}
-
-void YesNoDialog::applyCl( CClient *cl )
-{
-	std::vector<Component*> comps;
-	for(size_t i=0; i < components.size(); ++i) {
-		comps.push_back(&components[i]);
-	}
 	std::string str = toString(text);
 	if(vstd::contains(cl->playerint,player))
-		cl->playerint[player]->showYesNoDialog(str,comps,id);
+		cl->playerint[player]->showBlockingDialog(str,components,id,selection(),cancel());
 	else
 		tlog2 << "We received YesNoDialog for not our player...\n";
 }
@@ -417,7 +400,7 @@ void EndAction::applyCl( CClient *cl )
 void SystemMessage::applyCl( CClient *cl )
 {
 	std::ostringstream str;
-	str << "System message from server: " << text;
+	str << "System message: " << text;
 
 	tlog4 << str.str() << std::endl;
 	if(LOCPLINT)

+ 90 - 27
hch/CObjectHandler.cpp

@@ -511,6 +511,16 @@ void CGHeroInstance::initHero()
 	if (!army.slots.size()) //standard army//initial army
 	{
 		int pom, pom2=0;
+
+		int x = 0; //how many stacks will hero receives <1 - 3>
+		pom = ran()%100;
+		if(pom < 5)
+			x = 1;
+		else if(pom < 67)
+			x = 2;
+		else
+			x = 3;
+
 		for(int x=0;x<3;x++)
 		{
 			pom = (VLC->creh->nameToID[type->refTypeStack[x]]);
@@ -529,10 +539,8 @@ void CGHeroInstance::initHero()
 				continue;
 			}
 			army.slots[x-pom2].first = pom;
-			if((pom = (type->highStack[x]-type->lowStack[x])) > 0)
-				army.slots[x-pom2].second = (ran()%pom)+type->lowStack[x];
-			else 
-				army.slots[x-pom2].second = +type->lowStack[x];
+			pom = type->highStack[x] - type->lowStack[x];
+			army.slots[x-pom2].second = ran()%(pom+1) + type->lowStack[x];
 			army.formation = false;
 		}
 	}
@@ -540,7 +548,7 @@ void CGHeroInstance::initHero()
 	boost::algorithm::replace_first(hoverName,"%s",name);
 	boost::algorithm::replace_first(hoverName,"%s", type->heroClass->name);
 
-	//clear all bonuses from artifacts and give those from artifacts
+	//clear all bonuses from artifacts (if present) and give them again
 	std::remove_if(bonuses.begin(), bonuses.end(), boost::bind(HeroBonus::IsFrom,_1,HeroBonus::ARTIFACT,0xffffff));
 	for (std::map<ui16,ui32>::iterator ari = artifWorn.begin(); ari != artifWorn.end(); ari++)
 	{
@@ -928,8 +936,18 @@ void CGVisitableOPH::onHeroVisit( const CGHeroInstance * h ) const
 	if(visitors.find(h->id)==visitors.end())
 	{
 		onNAHeroVisit(h->id, false);
-		if(ID != 102  &&  ID!=4  && ID!=41) //not tree nor arena nor library of enlightenment
+		switch(ID)
+		{
+		case 102: //tree
+		case 4: //arena
+		case 41://library
+		case 47: //School of Magic
+		case 107://School of War
+			break;
+		default:
 			cb->setObjProperty(id,4,h->id); //add to the visitors
+			break;
+		}
 	}
 	else
 	{
@@ -947,7 +965,7 @@ void CGVisitableOPH::initObj()
 
 void CGVisitableOPH::treeSelected( int heroID, int resType, int resVal, int expVal, ui32 result ) const
 {
-	if(result==0) //player agreed to give res for exp
+	if(result) //player agreed to give res for exp
 	{
 		cb->giveResource(cb->getOwner(heroID),resType,-resVal); //take resource
 		cb->changePrimSkill(heroID,4,expVal); //give exp
@@ -992,6 +1010,12 @@ void CGVisitableOPH::onNAHeroVisit(int heroID, bool alreadyVisited) const
 	case 41:
 		ot = 66;
 		break;
+	case 47: //School of Magic
+		ot = 71;
+		break;
+	case 107://School of War
+		ot = 158;
+		break;
 	}
 	if (!alreadyVisited)
 	{
@@ -999,12 +1023,12 @@ void CGVisitableOPH::onNAHeroVisit(int heroID, bool alreadyVisited) const
 		{
 		case 4: //arena
 			{
-				SelectionDialog sd;
+				BlockingDialog sd(false,true);
 				sd.text << std::pair<ui8,ui32>(11,ot);
 				sd.components.push_back(Component(0,0,2,0));
 				sd.components.push_back(Component(0,1,2,0));
 				sd.player = cb->getOwner(heroID);
-				cb->showSelectionDialog(&sd,boost::bind(&CGVisitableOPH::arenaSelected,this,heroID,_1));
+				cb->showBlockingDialog(&sd,boost::bind(&CGVisitableOPH::arenaSelected,this,heroID,_1));
 				return;
 			}
 		case 51:
@@ -1030,7 +1054,7 @@ void CGVisitableOPH::onNAHeroVisit(int heroID, bool alreadyVisited) const
 				cb->changePrimSkill(heroID,4,val);
 				break;
 			}
-		case 102:
+		case 102://tree
 			{
 				const CGHeroInstance *h = cb->getHero(heroID);
 				val = VLC->heroh->reqExp(h->level+val) - VLC->heroh->reqExp(h->level);
@@ -1071,15 +1095,15 @@ void CGVisitableOPH::onNAHeroVisit(int heroID, bool alreadyVisited) const
 						return;
 					}
 
-					YesNoDialog sd;
+					BlockingDialog sd(true,false);
 					sd.player = cb->getOwner(heroID);
 					sd.text << std::pair<ui8,ui32>(11,ot);
 					sd.components.push_back(Component(id,subid,val,0));
-					cb->showYesNoDialog(&sd,boost::bind(&CGVisitableOPH::treeSelected,this,heroID,res,resval,val,_1));
+					cb->showBlockingDialog(&sd,boost::bind(&CGVisitableOPH::treeSelected,this,heroID,res,resval,val,_1));
 				}
 				break;
 			}
-		case 41:
+		case 41://library of enlightenment
 			{
 				const CGHeroInstance *h = cb->getHero(heroID);
 				if(h->level  <  10 - 2*h->getSecSkillLevel(4)) //not enough level
@@ -1103,6 +1127,28 @@ void CGVisitableOPH::onNAHeroVisit(int heroID, bool alreadyVisited) const
 				}
 				break;
 			}
+		case 47: //School of Magic
+		case 107://School of War
+			{
+				int skill = (ID==47 ? 2 : 0);
+				if(cb->getResource(cb->getOwner(heroID),6) < 1000) //not enough resources
+				{
+					InfoWindow iw;
+					iw.player = cb->getOwner(heroID);
+					iw.text << std::pair<ui8,ui32>(MetaString::ADVOB_TXT,ot+2);
+					cb->showInfoDialog(&iw);
+				}
+				else
+				{
+					BlockingDialog sd(true,true);
+					sd.player = cb->getOwner(heroID);
+					sd.text << std::pair<ui8,ui32>(11,ot);
+					sd.components.push_back(Component(Component::PRIM_SKILL, skill, +1, 0));
+					sd.components.push_back(Component(Component::PRIM_SKILL, skill+1, +1, 0));
+					cb->showBlockingDialog(&sd,boost::bind(&CGVisitableOPH::schoolSelected,this,heroID,_1));
+				}
+			}
+			break;
 		}
 	}
 	else
@@ -1143,6 +1189,12 @@ const std::string & CGVisitableOPH::getHoverText() const
 		break;
 	case 41:
 		break;
+	case 47: //School of Magic
+		pom = 9;
+		break;
+	case 107://School of War
+		pom = 10;
+		break;
 	default:
 		throw std::string("Wrong CGVisitableOPH object ID!\n");
 	}
@@ -1163,7 +1215,7 @@ const std::string & CGVisitableOPH::getHoverText() const
 void CGVisitableOPH::arenaSelected( int heroID, int primSkill ) const
 {
 	cb->setObjProperty(id,4,heroID); //add to the visitors
-	cb->changePrimSkill(heroID,primSkill,2);
+	cb->changePrimSkill(heroID,primSkill-1,2);
 }
 
 void CGVisitableOPH::setPropertyDer( ui8 what, ui32 val )
@@ -1172,6 +1224,17 @@ void CGVisitableOPH::setPropertyDer( ui8 what, ui32 val )
 		visitors.insert(val);
 }
 
+void CGVisitableOPH::schoolSelected(int heroID, ui32 which) const
+{
+	if(!which) //player refused to pay
+		return;
+
+	int base = (ID == 47  ?  2  :  0);
+	cb->setObjProperty(id,4,heroID); //add to the visitors
+	cb->giveResource(cb->getOwner(heroID),6,-1000); //take 1000 gold
+	cb->changePrimSkill(heroID, base + which-1, +1); //give appropriate skill
+}
+
 bool CArmedInstance::needsLastStack() const
 {
 	return false;
@@ -1302,10 +1365,10 @@ void CGResource::onHeroVisit( const CGHeroInstance * h ) const
 	{
 		if(message.size())
 		{
-			YesNoDialog ynd;
+			BlockingDialog ynd(true,false);
 			ynd.player = h->getOwner();
 			ynd.text << message;
-			cb->showYesNoDialog(&ynd,boost::bind(&CGResource::fightForRes,this,_1,h));
+			cb->showBlockingDialog(&ynd,boost::bind(&CGResource::fightForRes,this,_1,h));
 		}
 		else
 		{
@@ -1337,9 +1400,9 @@ void CGResource::collectRes( int player ) const
 	cb->removeObject(id);
 }
 
-void CGResource::fightForRes(ui32 refusedFight, const CGHeroInstance *h) const
+void CGResource::fightForRes(ui32 agreed, const CGHeroInstance *h) const
 {
-	if(!refusedFight)
+	if(agreed)
 		cb->startBattleI(h->id,army,pos,boost::bind(&CGResource::endBattle,this,_1,h));
 }
 
@@ -1519,10 +1582,10 @@ void CGArtifact::onHeroVisit( const CGHeroInstance * h ) const
 	{
 		if(message.size())
 		{
-			YesNoDialog ynd;
+			BlockingDialog ynd(true,false);
 			ynd.player = h->getOwner();
 			ynd.text << message;
-			cb->showYesNoDialog(&ynd,boost::bind(&CGArtifact::fightForArt,this,_1,h));
+			cb->showBlockingDialog(&ynd,boost::bind(&CGArtifact::fightForArt,this,_1,h));
 		}
 		else
 		{
@@ -1544,9 +1607,9 @@ void CGArtifact::pick(const CGHeroInstance * h) const
 	cb->removeObject(id);
 }
 
-void CGArtifact::fightForArt( ui32 refusedFight, const CGHeroInstance *h ) const
+void CGArtifact::fightForArt( ui32 agreed, const CGHeroInstance *h ) const
 {
-	if(!refusedFight)
+	if(agreed)
 		cb->startBattleI(h->id,army,pos,boost::bind(&CGArtifact::endBattle,this,_1,h));
 }
 
@@ -1632,13 +1695,13 @@ void CGPickable::onHeroVisit( const CGHeroInstance * h ) const
 			}
 			else
 			{
-				SelectionDialog sd;
+				BlockingDialog sd(false,true);
 				sd.player = h->tempOwner;
 				sd.text << std::pair<ui8,ui32>(11,146);
 				sd.components.push_back(Component(2,6,val1,0));
 				sd.components.push_back(Component(5,0,val2,0));
 				boost::function<void(ui32)> fun = boost::bind(&CGPickable::chosen,this,_1,h->id);
-				cb->showSelectionDialog(&sd,fun);
+				cb->showBlockingDialog(&sd,fun);
 				return;
 			}
 		}
@@ -1650,10 +1713,10 @@ void CGPickable::chosen( int which, int heroID ) const
 {
 	switch(which)
 	{
-	case 0: //player pick gold
+	case 1: //player pick gold
 		cb->giveResource(cb->getOwner(heroID),6,val1);
 		break;
-	case 1: //player pick exp
+	case 2: //player pick exp
 		cb->changePrimSkill(heroID, 4, val2);
 		break;
 	default:
@@ -1930,7 +1993,7 @@ void CGObservatory::onHeroVisit( const CGHeroInstance * h ) const
 
 	InfoWindow iw;
 	iw.player = h->tempOwner;
-	iw.text.addTxt(MetaString::ADVOB_TXT,98);
+	iw.text.addTxt(MetaString::ADVOB_TXT,98 + (ID==60));
 	cb->showInfoDialog(&iw);
 }
 

+ 3 - 2
hch/CObjectHandler.h

@@ -352,6 +352,7 @@ public:
 	void onNAHeroVisit(int heroID, bool alreadyVisited) const;
 	void initObj();
 	void treeSelected(int heroID, int resType, int resVal, int expVal, ui32 result) const; //handle player's anwer to the Tree of Knowledge dialog
+	void schoolSelected(int heroID, ui32 which) const;
 	void arenaSelected(int heroID, int primSkill) const;
 
 	template <typename Handler> void serialize(Handler &h, const int version)
@@ -498,7 +499,7 @@ public:
 	std::string message;
 	ui32 spell; //if it's spell scroll
 	void onHeroVisit(const CGHeroInstance * h) const;
-	void fightForArt(ui32 refusedFight, const CGHeroInstance *h) const;
+	void fightForArt(ui32 agreed, const CGHeroInstance *h) const;
 	void endBattle(BattleResult *result, const CGHeroInstance *h) const;
 	void pick( const CGHeroInstance * h ) const;
 	void initObj();	
@@ -519,7 +520,7 @@ public:
 	void onHeroVisit(const CGHeroInstance * h) const;
 	void collectRes(int player) const;
 	void initObj();
-	void fightForRes(ui32 refusedFight, const CGHeroInstance *h) const;
+	void fightForRes(ui32 agreed, const CGHeroInstance *h) const;
 	void endBattle(BattleResult *result, const CGHeroInstance *h) const;
 
 	template <typename Handler> void serialize(Handler &h, const int version)

+ 3 - 4
lib/IGameCallback.h

@@ -11,8 +11,7 @@ struct GiveBonus;
 class CGObjectInstance;
 class CGTownInstance;
 class CGHeroInstance;
-struct SelectionDialog;
-struct YesNoDialog;
+struct BlockingDialog;
 struct InfoWindow;
 struct MetaString;
 struct ShowInInfobox;
@@ -52,8 +51,8 @@ public:
 	virtual void changePrimSkill(int ID, int which, int val, bool abs=false)=0;
 	virtual void changeSecSkill(int ID, int which, int val, bool abs=false)=0; 
 	virtual void showInfoDialog(InfoWindow *iw)=0;
-	virtual void showYesNoDialog(YesNoDialog *iw, const CFunctionList<void(ui32)> &callback)=0;
-	virtual void showSelectionDialog(SelectionDialog *iw, const CFunctionList<void(ui32)> &callback)=0; //returns question id
+	virtual void showBlockingDialog(BlockingDialog *iw, const CFunctionList<void(ui32)> &callback)=0;
+	virtual ui32 showBlockingDialog(BlockingDialog *iw) =0; //synchronous version of above
 	virtual void giveResource(int player, int which, int val)=0;
 	virtual void showCompInfo(ShowInInfobox * comp)=0;
 	virtual void heroVisitCastle(int obj, int heroID)=0;

+ 24 - 16
lib/NetPacks.h

@@ -555,35 +555,43 @@ struct HeroLevelUp : public Query//2000
 	}
 };
 
-struct SelectionDialog : public Query//2001
+//A dialog that requires making decision by player - it may contain components to choose between or has yes/no options
+//Client responds with QueryReply, where answer: 0 - cancel pressed, choice doesn't matter; 1/2/...  - first/second/... component selected and OK pressed
+//Until sending reply player won't be allowed to take any actions
+struct BlockingDialog : public Query//2003
 {
+	enum {ALLOW_CANCEL = 1, SELECTION = 2};
+
 	void applyCl(CClient *cl);
 
 	MetaString text;
 	std::vector<Component> components;
 	ui8 player;
+	ui8 flags;
 
-	SelectionDialog(){type = 2001;};
-	
-	template <typename Handler> void serialize(Handler &h, const int version)
+	bool cancel() const
 	{
-		h & id & text & components & player;
+		return flags & ALLOW_CANCEL;
+	}
+	bool selection() const
+	{
+		return flags & SELECTION;
 	}
-};
-
-struct YesNoDialog : public Query//2002
-{
-	void applyCl(CClient *cl);
-
-	MetaString text;
-	std::vector<Component> components;
-	ui8 player;
 
-	YesNoDialog(){type = 2002;};
+	BlockingDialog(bool yesno, bool Selection)
+	{
+		type = 2003; 
+		if(yesno) flags |= ALLOW_CANCEL;
+		if(Selection) flags |= SELECTION;
+	}
+	BlockingDialog()
+	{
+		type = 2003;
+	};
 
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{
-		h & id & text & components & player;
+		h & id & text & components & player & flags;
 	}
 };
 

+ 1 - 2
lib/RegisterTypes.cpp

@@ -67,8 +67,7 @@ void registerTypes2(Serializer &s)
 	s.template registerType<SetObjectProperty>();
 	s.template registerType<SetHoverName>();
 	s.template registerType<HeroLevelUp>();
-	s.template registerType<SelectionDialog>();
-	s.template registerType<YesNoDialog>();
+	s.template registerType<BlockingDialog>();
 	s.template registerType<BattleStart>();
 	s.template registerType<BattleNextRound>();
 	s.template registerType<BattleSetActiveStack>();

+ 4 - 1
map.cpp

@@ -1413,7 +1413,7 @@ void Mapa::readObjects( unsigned char * bufor, int &i)
 				loadHero(nobj, bufor, i);
 				break;
 			}
-		case 4: //arena
+		case 4: //Arena
 		case 51: //Mercenary Camp
 		case 23: //Marletto Tower
 		case 61: // Star Axis
@@ -1421,6 +1421,8 @@ void Mapa::readObjects( unsigned char * bufor, int &i)
 		case 100: //Learning Stone
 		case 102: //Tree of Knowledge
 		case 41: //Library of Enlightenment
+		case 47: //School of Magic
+		case 107: //School of War
 			{
 				nobj = new CGVisitableOPH();
 				break;
@@ -1784,6 +1786,7 @@ void Mapa::readObjects( unsigned char * bufor, int &i)
 				break;
 			}
 		case 58: //Redwood Observatory
+		case 60: //Pillar of Fire
 			{
 				nobj = new CGObservatory();
 				break;

+ 29 - 11
server/CGameHandler.cpp

@@ -1208,14 +1208,27 @@ void CGameHandler::showInfoDialog(InfoWindow *iw)
 {
 	sendToAllClients(iw);
 }
-void CGameHandler::showYesNoDialog( YesNoDialog *iw, const CFunctionList<void(ui32)> &callback )
+void CGameHandler::showBlockingDialog( BlockingDialog *iw, const CFunctionList<void(ui32)> &callback )
 {
 	ask(iw,iw->player,callback);
 }
-void CGameHandler::showSelectionDialog(SelectionDialog *iw, const CFunctionList<void(ui32)> &callback)
+
+ui32 CGameHandler::showBlockingDialog( BlockingDialog *iw )
 {
-	ask(iw,iw->player,callback);
+	//TODO
+
+	//gsm.lock();
+	//int query = QID++;
+	//states.addQuery(player,query);
+	//sendToAllClients(iw);
+	//gsm.unlock();
+	//ui32 ret = getQueryResult(iw->player, query);
+	//gsm.lock();
+	//states.removeQuery(player, query);
+	//gsm.unlock();
+	return 0;
 }
+
 int CGameHandler::getCurrentPlayer()
 {
 	return gs->currentPlayer;
@@ -1439,8 +1452,11 @@ void CGameHandler::save( const std::string &fname )
 
 void CGameHandler::close()
 {
-	tlog0 << "We have been requested to close.\n";
-	exit(0);
+	tlog0 << "We have been requested to close.\n";	
+	//BOOST_FOREACH(CConnection *cc, conns)
+	//	if(cc && cc->socket && cc->socket->is_open())
+	//		cc->socket->close();
+	//exit(0);
 }
 
 void CGameHandler::arrangeStacks(si32 id1, si32 id2, ui8 what, ui8 p1, ui8 p2, si32 val)
@@ -2300,8 +2316,9 @@ void CGameHandler::makeCustomAction( BattleAction &ba )
 			case 52: //misfortune
 			case 53: //haste
 			case 54: //slow
+			case 61: //forgetfulness
 				{
-					SPELL_CAST_TEMPLATE_1(ba.additionalInfo, h->getPrimSkillLevel(2))
+					SPELL_CAST_TEMPLATE_1(ba.additionalInfo, h->getPrimSkillLevel(2) + h->valOfBonuses(HeroBonus::SPELL_DURATION) )
 						break;
 				}
 			case 56: //frenzy
@@ -2309,11 +2326,6 @@ void CGameHandler::makeCustomAction( BattleAction &ba )
 					SPELL_CAST_TEMPLATE_1(ba.additionalInfo, 1)
 						break;
 				}
-			case 61: //forgetfulness
-				{
-					SPELL_CAST_TEMPLATE_1(ba.additionalInfo, h->getPrimSkillLevel(2))
-						break;
-				}
 			}
 			sendAndApply(&EndAction());
 		}
@@ -2380,4 +2392,10 @@ bool CGameHandler::complain( const std::string &problem )
 	sendMessageToAll("Server encountered a problem: " + problem);
 	tlog1 << problem << std::endl;
 	return true;
+}
+
+ui32 CGameHandler::getQueryResult( ui8 player, int queryID )
+{
+	//TODO: write
+	return 0;
 }

+ 3 - 2
server/CGameHandler.h

@@ -93,8 +93,8 @@ public:
 	void changePrimSkill(int ID, int which, int val, bool abs=false);
 	void changeSecSkill(int ID, int which, int val, bool abs=false); 
 	void showInfoDialog(InfoWindow *iw);
-	void showYesNoDialog(YesNoDialog *iw, const CFunctionList<void(ui32)> &callback);
-	void showSelectionDialog(SelectionDialog *iw, const CFunctionList<void(ui32)> &callback); //returns question id
+	void showBlockingDialog(BlockingDialog *iw, const CFunctionList<void(ui32)> &callback);
+	ui32 showBlockingDialog(BlockingDialog *iw); //synchronous version of above
 	void giveResource(int player, int which, int val);
 	void showCompInfo(ShowInInfobox * comp);
 	void heroVisitCastle(int obj, int heroID);
@@ -142,6 +142,7 @@ public:
 		h & QID & states;
 	}
 
+	ui32 getQueryResult(ui8 player, int queryID);
 	void sendMessageToAll(const std::string &message);
 	void sendMessageTo(CConnection &c, const std::string &message);
 	void applyAndAsk(Query * sel, ui8 player, boost::function<void(ui32)> &callback);