فهرست منبع

Implemented "main menu" in-game option.

Frank Zago 16 سال پیش
والد
کامیت
6b5feb63e6
11فایلهای تغییر یافته به همراه160 افزوده شده و 97 حذف شده
  1. 1 0
      CGameInterface.h
  2. 1 1
      client/CAdvmapInterface.cpp
  3. 28 50
      client/CMT.cpp
  4. 11 1
      client/CPlayerInterface.cpp
  5. 4 0
      client/CPlayerInterface.h
  6. 14 10
      client/CPreGame.cpp
  7. 70 25
      client/Client.cpp
  8. 6 3
      client/Client.h
  9. 4 2
      client/GUIBase.cpp
  10. 17 4
      client/GUIClasses.cpp
  11. 4 1
      client/GUIClasses.h

+ 1 - 0
CGameInterface.h

@@ -72,6 +72,7 @@ public:
 	int playerID, serialID;
 	std::string dllName;
 
+	virtual ~CGameInterface() {};
 	virtual void buildChanged(const CGTownInstance *town, int buildingID, int what){}; //what: 1 - built, 2 - demolished
 	virtual void garrisonChanged(const CGObjectInstance * obj){};
 	virtual void heroArtifactSetChanged(const CGHeroInstance*hero){};

+ 1 - 1
client/CAdvmapInterface.cpp

@@ -1667,7 +1667,7 @@ void CAdvMapInt::deactivate()
 	townList.deactivate();
 	terrain.deactivate();
 	if(std::find(GH.timeinterested.begin(),GH.timeinterested.end(),&infoBar)!=GH.timeinterested.end())
-		GH.timeinterested.erase(std::find(GH.timeinterested.begin(),GH.timeinterested.end(),&infoBar));
+		infoBar.deactivate();
 	infoBar.mode=-1;
 
 	LOCPLINT->cingconsole->deactivate();

+ 28 - 50
client/CMT.cpp

@@ -61,7 +61,7 @@
 std::string NAME_AFFIX = "client";
 std::string NAME = NAME_VER + std::string(" (") + NAME_AFFIX + ')'; //application name
 CGuiHandler GH;
-CClient *client = NULL;
+static CClient *client;
 SDL_Surface *screen = NULL, //main screen surface 
 	*screen2 = NULL,//and hlp surface (used to store not-active interfaces layer) 
 	*screenBuf = screen; //points to screen (if only advmapint is present) or screen2 (else) - should be used when updating controls which are not regularly redrawed
@@ -79,8 +79,7 @@ void processCommand(const std::string &message);
 static void setScreenRes(int w, int h, int bpp, bool fullscreen);
 void dispose();
 void playIntro();
-void listenForEvents();
-void startGame(StartInfo * options);
+static void listenForEvents();
 
 void init()
 {
@@ -209,8 +208,9 @@ int main(int argc, char** argv)
 	loading.join();
 	tlog0<<"Initialization of VCMI (together): "<<total.getDif()<<std::endl;
 
-	new CGPreGame; //will set CGP pointer to itself
 	CGI->musich->playMusic(musicBase::mainMenu, -1);
+
+	new CGPreGame; //will set CGP pointer to itself
 	hhh = new boost::thread(&CGPreGame::run, CGP);
 	listenForEvents();
 
@@ -284,9 +284,10 @@ void processCommand(const std::string &message)
 	//}
 	else if(cn=="load")
 	{
+		// TODO: this code should end the running game and manage to call startGame instead
 		std::string fname;
 		readed >> fname;
-		client->load(fname);
+		client->loadGame(fname);
 	}
 	//else if(cn=="ln")
 	//{
@@ -433,29 +434,26 @@ static void setScreenRes(int w, int h, int bpp, bool fullscreen)
 	screenBuf = bufOnScreen ? screen : screen2;
 }
 
-void listenForEvents()
+static void listenForEvents()
 {
-	SDL_Event *ev = NULL;
 	while(1) //main SDL events loop
 	{
-		ev = new SDL_Event();
+		SDL_Event *ev = new SDL_Event();
 
 		//tlog0 << "Waiting... ";
 		int ret = SDL_WaitEvent(ev);
 		//tlog0 << "got " << (int)ev->type;
-		if(ret == 0 || (ev->type==SDL_QUIT)  ||  (ev->type == SDL_KEYDOWN && ev->key.keysym.sym==SDLK_F4 && (ev->key.keysym.mod & KMOD_ALT)))
+		if (ret == 0 || (ev->type==SDL_QUIT) ||
+			(ev->type == SDL_KEYDOWN && ev->key.keysym.sym==SDLK_F4 && (ev->key.keysym.mod & KMOD_ALT)))
 		{
-			if(LOCPLINT)
-				LOCPLINT->pim->lock();
 			if (client)
-				client->close();
+				client->stop();
 			if (hhh) {
 				CGP->terminate = true;
 				hhh->join();
 				delete hhh;
 				hhh = NULL;
 			}
-			console->end();
 			delete console;
 			console = NULL;
 			SDL_Delay(750);
@@ -470,6 +468,8 @@ void listenForEvents()
 			bool full = !(screen->flags&SDL_FULLSCREEN);
 			setScreenRes(conf.cc.resx,conf.cc.resy,conf.cc.bpp,full);
 			GH.totalRedraw();
+			delete ev;
+			continue;
 		}
 		else if(ev->type == SDL_USEREVENT && ev->user.code == 1)
 		{
@@ -477,6 +477,12 @@ void listenForEvents()
 			delete ev;
 			continue;
 		}
+		else if (ev->type == SDL_USEREVENT && ev->user.code == 2) {
+			client->stop();
+			delete ev;
+			continue;
+		}
+
 		//tlog0 << " pushing ";
 		eventsM.lock();
 		events.push(ev);
@@ -507,47 +513,19 @@ void startGame(StartInfo * options)
 	CClient cl;
 	if(options->mode == 0) //new game
 	{
-		timeHandler pomtime;
-		char portc[10];
-		SDL_itoa(conf.cc.port,portc,10);
-		CClient::runServer(portc);
-		tlog0<<"Preparing shared memory and starting server: "<<pomtime.getDif()<<std::endl;
-
-		pomtime.getDif();//reset timers
-
-		CConnection *c=NULL;
-		//wait until server is ready
-		tlog0<<"Waiting for server... ";
-		cl.waitForServer();
-		tlog0 << pomtime.getDif()<<std::endl;
-		while(!c)
-		{
-			try
-			{
-				tlog0 << "Establishing connection...\n";
-				c = new CConnection(conf.cc.server,portc,NAME);
-			}
-			catch(...)
-			{
-				tlog1 << "\nCannot establish connection! Retrying within 2 seconds" <<std::endl;
-				SDL_Delay(2000);
-			}
-		}
-		THC tlog0<<"\tConnecting to the server: "<<pomtime.getDif()<<std::endl;
-		cl.newGame(c,options);
-		client = &cl;
-		CGI->musich->stopMusic();
-		client->run();
-		//boost::thread t(boost::bind(&CClient::run,&cl));
+		cl.newGame(NULL, options);
 	}
 	else //load game
 	{
 		std::string fname = options->mapname;
 		boost::algorithm::erase_last(fname,".vlgm1");
-		cl.load(fname);
-		client = &cl;
-		CGI->musich->stopMusic();
-		client->run();
-		//boost::thread t(boost::bind(&CClient::run,&cl));
+		cl.loadGame(fname);
 	}
+
+	client = &cl;
+	CGI->musich->stopMusic();
+	client->run();
+	LOCPLINT->terminate_cond.waitUntil(true);
+	client->endGame();
+	client = NULL;
 }

+ 11 - 1
client/CPlayerInterface.cpp

@@ -100,6 +100,8 @@ CPlayerInterface::CPlayerInterface(int Player, int serial)
 	SDL_setFramerate(mainFPSmng, 48);
 	//framerate keeper initialized
 	cingconsole = new CInGameConsole;
+	terminate = false;
+	terminate_cond.set(false);
 }
 CPlayerInterface::~CPlayerInterface()
 {
@@ -116,6 +118,8 @@ CPlayerInterface::~CPlayerInterface()
 	for(std::map<int,SDL_Surface*>::iterator i=graphics->townWins.begin(); i!= graphics->townWins.end(); i++)
 		SDL_FreeSurface(i->second);
 	graphics->townWins.clear();
+
+	LOCPLINT = NULL;
 }
 void CPlayerInterface::init(ICallback * CB)
 {
@@ -179,6 +183,9 @@ void CPlayerInterface::yourTurn()
 
 		while(makingTurn) // main loop
 		{
+			if (terminate)
+				break;
+
 			pim->lock();
 
 			//if there are any waiting dialogs, show them
@@ -208,7 +215,10 @@ void CPlayerInterface::yourTurn()
 		GH.popInt(adventureInt);
 
 		cb->endTurn();
-	} HANDLE_EXCEPTION
+	} HANDLE_EXCEPTION;
+
+	if (terminate)
+		terminate_cond.set(true);
 }
 
 inline void subRect(const int & x, const int & y, const int & z, const SDL_Rect & r, const int & hid)

+ 4 - 0
client/CPlayerInterface.h

@@ -2,6 +2,7 @@
 #define __CPLAYERINTERFACE_H__
 #include "../global.h"
 #include "../CGameInterface.h"
+#include "../lib/CondSh.h"
 #include "SDL_framerate.h"
 #include <map>
 #include <list>
@@ -204,6 +205,9 @@ public:
 	CPlayerInterface(int Player, int serial);//c-tor
 	~CPlayerInterface();//d-tor
 
+	bool terminate;				 // tell to terminate
+	CondSh<bool> terminate_cond; // confirm termination
+
 	//////////////////////////////////////////////////////////////////////////
 
 	template <typename Handler> void serializeTempl(Handler &h, const int version);

+ 14 - 10
client/CPreGame.cpp

@@ -44,13 +44,18 @@ using boost::ref;
 void startGame(StartInfo * options);
 
 CGPreGame * CGP;
-static const CMapHeader *curMap = NULL;
-static StartInfo *curOpts = NULL;
+static const CMapHeader *curMap;
+static StartInfo *curOpts;
 static int playerColor, playerSerial;
 
 static std::string selectedName; //set when game is started/loaded
 
-extern void do_quit();
+static void do_quit()
+{
+	SDL_Event event;
+	event.quit.type = SDL_QUIT;
+	SDL_PushEvent(&event);
+}
 
 CMenuScreen::CMenuScreen( EState which )
 {
@@ -126,15 +131,15 @@ void CGPreGame::run()
 	CGI->videoh->open("ACREDIT.SMK", true, false);
 #endif
 
-	GH.pushInt(scrs[mainMenu]);
-
 	while(!terminate)
 	{
+		if (GH.listInt.size() == 0)
+			GH.pushInt(scrs[mainMenu]);
+
 		CGI->curh->draw1();
 		SDL_Flip(screen);
 		CGI->curh->draw2();
 		SDL_Delay(20); //give time for other apps
-
 		GH.topInt()->show(screen);
 		GH.updateTime();
 		GH.handleEvents();
@@ -362,12 +367,11 @@ void CSelectionScreen::startGame()
 
 		selectedName = sInfo.mapname;
 		StartInfo *si = new StartInfo(sInfo);
-		GH.popIntTotally(this);
-		GH.popIntTotally(GH.topInt());
+		GH.popInt(this);
+		GH.popInt(GH.topInt());
 		curMap = NULL;
 		curOpts = NULL;
 		::startGame(si);
-		delete si; //rather won't be called...
 	}
 	else
 	{
@@ -376,7 +380,7 @@ void CSelectionScreen::startGame()
 
 		selectedName = GVCMIDirs.UserPath + "/Games/" + sel->txt->text + ".vlgm1";
 		LOCPLINT->cb->save(sel->txt->text);
-		GH.popIntTotally(this);
+		GH.popInt(this);
 	}
 }
 

+ 70 - 25
client/Client.cpp

@@ -20,6 +20,7 @@
 #include "../mapHandler.h"
 #include "CConfigHandler.h"
 #include "Client.h"
+#include "GUIBase.h"
 #include <boost/bind.hpp>
 #include <boost/foreach.hpp>
 #include <boost/thread.hpp>
@@ -88,7 +89,7 @@ void CClient::init()
 	serv = NULL;
 	gs = NULL;
 	cb = NULL;
-	must_close = false;
+	terminate = false;
 	try
 	{
 		shared = new SharedMem();
@@ -129,10 +130,8 @@ void CClient::run()
 		CPack *pack;
 		while(1)
 		{
-			if (must_close) {
-				serv->close();
-				tlog3 << "Our socket has been closed.\n";
-				return;
+			if (terminate) {
+				break;
 			}
 
 			//get the package from the server
@@ -143,6 +142,11 @@ void CClient::run()
 				tlog5 << "\treceived server message of type " << typeid(*pack).name() << std::endl;
 			}
 
+			if (terminate) {
+				delete pack;
+				break;
+			}
+
 			CBaseForCLApply *apply = applier->apps[typeList.getTypeID(pack)]; //find the applier
 			if(apply)
 			{
@@ -163,16 +167,12 @@ void CClient::run()
 	} HANDLE_EXCEPTION(tlog1 << "Lost connection to server, ending listening thread!\n");
 }
 
-void CClient::close()
+void CClient::stop()
 {
-	if(!serv)
-		return;
-
-	tlog3 << "Connection has been requested to be closed.\n";
-	boost::unique_lock<boost::mutex>(*serv->wmx);
-	*serv << &CloseServer();
-	tlog3 << "Sent closing signal to the server\n";
-	must_close = true;
+	// Game is ending
+	// Tell the network thread and interface thread to reach a stable state
+	terminate = true;
+	LOCPLINT->terminate = true;
 }
 
 void CClient::save(const std::string & fname)
@@ -186,29 +186,45 @@ void CClient::save(const std::string & fname)
 	*serv << &SaveGame(fname);
 }
 
-void CClient::load( const std::string & fname )
+void CClient::endGame()
 {
-	tlog0 <<"\n\nLoading procedure started!\n\n";
-
-	timeHandler tmh;
-	close(); //kill server
-	tlog0 <<"Sent kill signal to the server: "<<tmh.getDif()<<std::endl;
+	tlog0 << "\n\nEnding current game!" << std::endl;
 
 	delete CGI->mh;
-	delete CGI->state;
-	VLC->clear(); //delete old handlers
+	CGI->mh = NULL;
 
+	delete CGI->state;
+	CGI->state = NULL;
 
-	for(std::map<ui8,CGameInterface *>::iterator i = playerint.begin(); i!=playerint.end(); i++)
+	while (!playerint.empty())
 	{
-		delete i->second; //delete player interfaces
+		delete playerint.begin()->second;
+		playerint.erase(playerint.begin());
 	}
 
 	BOOST_FOREACH(CCallback *cb, callbacks)
 	{
 		delete cb;
 	}
-	tlog0 <<"Deleting old data: "<<tmh.getDif()<<std::endl;
+
+	if (serv) {
+		tlog3 << "Connection has been requested to be closed.\n";
+		boost::unique_lock<boost::mutex>(*serv->wmx);
+		*serv << &CloseServer();
+		tlog3 << "Sent closing signal to the server\n";
+
+		serv->close();
+		delete serv;
+		serv = NULL;
+		tlog3 << "Our socket has been closed." << std::endl;
+	}
+}
+
+void CClient::loadGame( const std::string & fname )
+{
+	tlog0 <<"\n\nLoading procedure started!\n\n";
+
+	timeHandler tmh;
 
 	char portc[10];
 	SDL_itoa(conf.cc.port,portc,10);
@@ -300,6 +316,35 @@ int CClient::getSelectedHero()
 
 void CClient::newGame( CConnection *con, StartInfo *si )
 {
+	if (con == NULL) {
+		timeHandler pomtime;
+		char portc[10];
+		SDL_itoa(conf.cc.port,portc,10);
+		CClient::runServer(portc);
+		tlog0<<"Preparing shared memory and starting server: "<<pomtime.getDif()<<std::endl;
+
+		pomtime.getDif();//reset timers
+
+		//wait until server is ready
+		tlog0<<"Waiting for server... ";
+		waitForServer();
+		tlog0 << pomtime.getDif()<<std::endl;
+		while(!con)
+		{
+			try
+			{
+				tlog0 << "Establishing connection...\n";
+				con = new CConnection(conf.cc.server,portc,NAME);
+			}
+			catch(...)
+			{
+				tlog1 << "\nCannot establish connection! Retrying within 2 seconds" <<std::endl;
+				SDL_Delay(2000);
+			}
+		}
+		THC tlog0<<"\tConnecting to the server: "<<pomtime.getDif()<<std::endl;
+	}
+
 	timeHandler tmh;
 	CGI->state = new CGameState();
 	tlog0 <<"\tGamestate: "<<tmh.getDif()<<std::endl;

+ 6 - 3
client/Client.h

@@ -61,7 +61,6 @@ public:
 	std::set<CCallback*> callbacks; //callbacks given to player interfaces
 	std::map<ui8,CGameInterface *> playerint;
 	CConnection *serv;
-	bool must_close;
 	SharedMem *shared;
 	BattleAction *curbaction;
 	CPathsInfo *pathInfo;
@@ -75,11 +74,15 @@ public:
 	~CClient(void);
 
 	void init();
-	void close();
 	void newGame(CConnection *con, StartInfo *si); //con - connection to server
+	void endGame();
 	void save(const std::string & fname);
-	void load(const std::string & fname);
+	void loadGame(const std::string & fname);
 	void run();
+	void stop();
+
+	bool terminate;				 // tell to terminate
+
 	//////////////////////////////////////////////////////////////////////////
 	//from IGameCallback
 	int getCurrentPlayer();

+ 4 - 2
client/GUIBase.cpp

@@ -521,13 +521,15 @@ void CIntObject::deactivate()
 		deactivateMouseMove();
 	if(used & KEYBOARD)
 		deactivateKeys();
-	if(used & TIME)
+	if(active & TIME)			// TIME is special
 		deactivateTimer();
 	if(used & WHEEL)
 		deactivateWheel();
 	if(used & DOUBLECLICK)
 		deactivateDClick();
 
+	assert(!active);
+
 	if(defActions & DEACTIVATE)
 		for(size_t i = 0; i < children.size(); i++)
 			if(children[i]->recActions & DEACTIVATE)
@@ -768,4 +770,4 @@ bool isNumKey( SDLKey key, bool number )
 bool isArrowKey( SDLKey key )
 {
 	return key >= SDLK_UP && key <= SDLK_LEFT;
-}
+}

+ 17 - 4
client/GUIClasses.cpp

@@ -2840,13 +2840,15 @@ CSystemOptionsWindow::CSystemOptionsWindow(const SDL_Rect &pos, CPlayerInterface
 	CSDL_Ext::printAt(CGI->generaltexth->allTexts[577], 283, 217, GEOR16, zwykly, background); //spell book animation
 
 	//setting up buttons
-	save = new AdventureMapButton (CGI->generaltexth->zelp[321].first, CGI->generaltexth->zelp[321].second, boost::bind(&CSystemOptionsWindow::bsavef, this), pos.x+357, pos.y+297, "SOSAVE.DEF", SDLK_s);
+	save = new AdventureMapButton (CGI->generaltexth->zelp[322].first, CGI->generaltexth->zelp[322].second, boost::bind(&CSystemOptionsWindow::bsavef, this), pos.x+357, pos.y+297, "SOSAVE.DEF", SDLK_s);
 	std::swap(save->imgs[0][0], save->imgs[0][1]);
 	quitGame = new AdventureMapButton (CGI->generaltexth->zelp[324].first, CGI->generaltexth->zelp[324].second, boost::bind(&CSystemOptionsWindow::bquitf, this), pos.x+246, pos.y+414, "soquit.def", SDLK_q);
 	std::swap(quitGame->imgs[0][0], quitGame->imgs[0][1]);
 	backToMap = new AdventureMapButton (CGI->generaltexth->zelp[325].first, CGI->generaltexth->zelp[325].second, boost::bind(&CSystemOptionsWindow::breturnf, this), pos.x+357, pos.y+414, "soretrn.def", SDLK_RETURN);
+	mainMenu = new AdventureMapButton (CGI->generaltexth->zelp[320].first, CGI->generaltexth->zelp[320].second, boost::bind(&CSystemOptionsWindow::bmainmenuf, this), pos.x+357, pos.y+357, "SOMAIN.DEF", SDLK_RETURN);
 	backToMap->assignedKeys.insert(SDLK_ESCAPE);
 	std::swap(backToMap->imgs[0][0], backToMap->imgs[0][1]);
+	std::swap(mainMenu->imgs[0][0], mainMenu->imgs[0][1]);
 
 	heroMoveSpeed = new CHighlightableButtonsGroup(0);
 	heroMoveSpeed->addButton(boost::assign::map_list_of(0,CGI->generaltexth->zelp[349].second),CGI->generaltexth->zelp[349].second, "sysopb1.def", pos.x+28, pos.y+77, 1);
@@ -2887,22 +2889,26 @@ CSystemOptionsWindow::~CSystemOptionsWindow()
 	delete save;
 	delete quitGame;
 	delete backToMap;
+	delete mainMenu;
 	delete heroMoveSpeed;
 	delete mapScrollSpeed;
 	delete musicVolume;
 	delete effectsVolume;
 }
 
-void do_quit()
+void CSystemOptionsWindow::pushSDLEvent(int type, int usercode)
 {
+	GH.popIntTotally(this);
+
 	SDL_Event event;
-	event.quit.type = SDL_QUIT;
+	event.type = type;
+	event.user.code = usercode;	// not necessarily used
 	SDL_PushEvent(&event);
 }
 
 void CSystemOptionsWindow::bquitf()
 {
-	LOCPLINT->showYesNoDialog(CGI->generaltexth->allTexts[578], std::vector<SComponent*>(), do_quit, 0, false);
+	LOCPLINT->showYesNoDialog(CGI->generaltexth->allTexts[578], std::vector<SComponent*>(), boost::bind(&CSystemOptionsWindow::pushSDLEvent, this, SDL_QUIT, 0), 0, false);
 }
 
 void CSystemOptionsWindow::breturnf()
@@ -2910,6 +2916,10 @@ void CSystemOptionsWindow::breturnf()
 	GH.popIntTotally(this);
 }
 
+void CSystemOptionsWindow::bmainmenuf()
+{
+	LOCPLINT->showYesNoDialog(CGI->generaltexth->allTexts[578], std::vector<SComponent*>(), boost::bind(&CSystemOptionsWindow::pushSDLEvent, this, SDL_USEREVENT, 2), 0, false);
+}
 
 void CSystemOptionsWindow::bsavef()
 {
@@ -2929,6 +2939,7 @@ void CSystemOptionsWindow::activate()
 	save->activate();
 	quitGame->activate();
 	backToMap->activate();
+	mainMenu->activate();
 	heroMoveSpeed->activate();
 	mapScrollSpeed->activate();
 	musicVolume->activate();
@@ -2940,6 +2951,7 @@ void CSystemOptionsWindow::deactivate()
 	save->deactivate();
 	quitGame->deactivate();
 	backToMap->deactivate();
+	mainMenu->deactivate();
 	heroMoveSpeed->deactivate();
 	mapScrollSpeed->deactivate();
 	musicVolume->deactivate();
@@ -2953,6 +2965,7 @@ void CSystemOptionsWindow::show(SDL_Surface *to)
 	save->show(to);
 	quitGame->show(to);
 	backToMap->show(to);
+	mainMenu->show(to);
 	heroMoveSpeed->show(to);
 	mapScrollSpeed->show(to);
 	musicVolume->show(to);

+ 4 - 1
client/GUIClasses.h

@@ -503,7 +503,7 @@ class CSystemOptionsWindow : public CIntObject
 {
 private:
 	SDL_Surface * background; //background of window
-	AdventureMapButton *load, *save, *restart, *mainMenu, * quitGame, * backToMap; //load, restart and main menu are not used yet
+	AdventureMapButton *load, *save, *restart, *mainMenu, *quitGame, *backToMap; //load and restart are not used yet
 	CHighlightableButtonsGroup * heroMoveSpeed;
 	CHighlightableButtonsGroup * mapScrollSpeed;
 	CHighlightableButtonsGroup * musicVolume, * effectsVolume;
@@ -515,6 +515,9 @@ public:
 	void bsavef(); //save game
 	void bquitf(); //quit game
 	void breturnf(); //return to game
+	void bmainmenuf(); //return to main menu
+
+	void pushSDLEvent(int type, int usercode);
 
 	void activate();
 	void deactivate();