mirror of
				https://github.com/vcmi/vcmi.git
				synced 2025-10-31 00:07:39 +02:00 
			
		
		
		
	* CTRL+T will open marketplace window * T in adventure map will switch to next town * T in castle window will open a tavern window (if available) * G will open thieves guild window if player owns at least one town with tavern * various minor changes
This commit is contained in:
		
							
								
								
									
										10
									
								
								Global.h
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								Global.h
									
									
									
									
									
								
							| @@ -65,6 +65,7 @@ | ||||
| #include <boost/lexical_cast.hpp> | ||||
| #include <boost/logic/tribool.hpp> | ||||
| #include <boost/program_options.hpp> | ||||
| #include <boost/range/algorithm.hpp> | ||||
| #include <boost/thread.hpp> | ||||
| #include <boost/unordered_set.hpp> | ||||
|  | ||||
| @@ -313,10 +314,15 @@ namespace vstd | ||||
| 		return std::unique_ptr<T>(new T()); | ||||
| 	} | ||||
| 	template<typename T, typename Arg1> | ||||
| 	std::unique_ptr<T> make_unique(Arg1&& arg1) | ||||
| 	std::unique_ptr<T> make_unique(Arg1 &&arg1) | ||||
| 	{ | ||||
| 		return std::unique_ptr<T>(new T(std::forward<Arg1>(arg1))); | ||||
| 	} | ||||
| 	template<typename T, typename Arg1, typename Arg2> | ||||
| 	std::unique_ptr<T> make_unique(Arg1 &&arg1, Arg2 &&arg2) | ||||
| 	{ | ||||
| 		return std::unique_ptr<T>(new T(std::forward<Arg1>(arg1), std::forward<Arg2>(arg2))); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| using std::shared_ptr; | ||||
| @@ -326,6 +332,8 @@ using vstd::make_unique; | ||||
|  | ||||
| using vstd::operator-=; | ||||
|  | ||||
| namespace range = boost::range; | ||||
|  | ||||
| // can be used for counting arrays | ||||
| template<typename T, size_t N> char (&_ArrayCountObj(const T (&)[N]))[N]; | ||||
| #define ARRAY_COUNT(arr)    (sizeof(_ArrayCountObj(arr))) | ||||
|   | ||||
| @@ -1453,6 +1453,19 @@ void CAdvMapInt::keyPressed(const SDL_KeyboardEvent & key) | ||||
|  | ||||
| 	switch(k) | ||||
| 	{ | ||||
| 	case SDLK_g: | ||||
| 		if(key.state != SDL_PRESSED || GH.topInt()->type & BLOCK_ADV_HOTKEYS) | ||||
| 			return; | ||||
|  | ||||
| 		{ | ||||
| 			//find first town with tavern | ||||
| 			auto itr = range::find_if(LOCPLINT->towns, boost::bind(&CGTownInstance::hasBuilt, _1, EBuilding::TAVERN)); | ||||
| 			if(itr != LOCPLINT->towns.end()) | ||||
| 				LOCPLINT->showThievesGuildWindow(*itr); | ||||
| 			else | ||||
| 				LOCPLINT->showInfoDialog("No available town with tavern!"); | ||||
| 		} | ||||
| 		return; | ||||
| 	case SDLK_i: | ||||
| 		if(isActive()) | ||||
| 			CAdventureOptions::showScenarioInfo(); | ||||
| @@ -1503,23 +1516,31 @@ void CAdvMapInt::keyPressed(const SDL_KeyboardEvent & key) | ||||
| 	case SDLK_t: | ||||
| 		{ | ||||
| 			//act on key down if marketplace windows is not already opened | ||||
| 			if(key.state != SDL_PRESSED  || GH.topInt()->type & BLOCK_ADV_HOTKEYS) return; | ||||
| 			if(key.state != SDL_PRESSED || GH.topInt()->type & BLOCK_ADV_HOTKEYS) | ||||
| 				return; | ||||
|  | ||||
| 			//check if we have any marketplace | ||||
| 			const CGTownInstance *townWithMarket = NULL; | ||||
| 			BOOST_FOREACH(const CGTownInstance *t, LOCPLINT->cb->getTownsInfo()) | ||||
| 			if(LOCPLINT->ctrlPressed()) //CTRL + T => open marketplace | ||||
| 			{ | ||||
| 				if(vstd::contains(t->builtBuildings, 14)) | ||||
| 				//check if we have any marketplace | ||||
| 				const CGTownInstance *townWithMarket = NULL; | ||||
| 				BOOST_FOREACH(const CGTownInstance *t, LOCPLINT->cb->getTownsInfo()) | ||||
| 				{ | ||||
| 					townWithMarket = t; | ||||
| 					break; | ||||
| 					if(vstd::contains(t->builtBuildings, 14)) | ||||
| 					{ | ||||
| 						townWithMarket = t; | ||||
| 						break; | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
|  | ||||
| 			if(townWithMarket) //if any town has marketplace, open window | ||||
| 				GH.pushInt(new CMarketplaceWindow(townWithMarket)); | ||||
| 			else //if not - complain | ||||
| 				LOCPLINT->showInfoDialog("No available marketplace!", std::vector<CComponent*>(), soundBase::sound_todo); | ||||
| 				if(townWithMarket) //if any town has marketplace, open window | ||||
| 					GH.pushInt(new CMarketplaceWindow(townWithMarket)); | ||||
| 				else //if not - complain | ||||
| 					LOCPLINT->showInfoDialog("No available marketplace!"); | ||||
| 			} | ||||
| 			else if(isActive()) //no ctrl, advmapint is on the top => switch to town | ||||
| 			{ | ||||
| 				townList.selectNext(); | ||||
| 			} | ||||
| 			return; | ||||
| 		} | ||||
| 	default: | ||||
| @@ -2123,6 +2144,7 @@ void CAdvMapInt::adjustActiveness(bool aiTurnStart) | ||||
| 	if(wasActive)  | ||||
| 		activate(); | ||||
| } | ||||
|  | ||||
| CAdventureOptions::CAdventureOptions() | ||||
| { | ||||
| 	OBJ_CONSTRUCTION_CAPTURING_ALL; | ||||
|   | ||||
| @@ -1257,6 +1257,10 @@ void CCastleInterface::keyPressed( const SDL_KeyboardEvent & key ) | ||||
| 			LOCPLINT->cb->swapGarrisonHero(town); | ||||
| 		} | ||||
| 		break; | ||||
| 	case SDLK_t: | ||||
| 		if(town->hasBuilt(EBuilding::TAVERN)) | ||||
| 			LOCPLINT->showTavernWindow(town); | ||||
| 		break; | ||||
| 	default: | ||||
| 		break; | ||||
| 	} | ||||
|   | ||||
| @@ -1415,6 +1415,12 @@ void CPlayerInterface::showRecruitmentDialog(const CGDwelling *dwelling, const C | ||||
|  | ||||
| void CPlayerInterface::waitWhileDialog(bool unlockPim /*= true*/) | ||||
| { | ||||
| 	if(GH.amIGuiThread()) | ||||
| 	{ | ||||
| 		tlog3 << "Cannot wait for dialogs in gui thread (deadlock risk)!\n"; | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	auto unlock = vstd::makeUnlockGuardIf(*pim, unlockPim); | ||||
| 	boost::unique_lock<boost::mutex> un(showingDialog->mx); | ||||
| 	while(showingDialog->data) | ||||
|   | ||||
| @@ -1332,8 +1332,7 @@ void CTownList::genList() | ||||
|  | ||||
| void CTownList::select(int which) | ||||
| { | ||||
| 	if (which>=LOCPLINT->towns.size()) | ||||
| 		return; | ||||
| 	which %= LOCPLINT->towns.size(); | ||||
| 	selected = which; | ||||
| 	fixPos(); | ||||
| 	if(!fun.empty()) | ||||
| @@ -1528,6 +1527,11 @@ int CTownList::size() | ||||
| 	return LOCPLINT->towns.size(); | ||||
| } | ||||
|  | ||||
| void CTownList::selectNext() | ||||
| { | ||||
| 	select(selected+1); | ||||
| } | ||||
|  | ||||
| CCreaturePic::CCreaturePic(int x, int y, const CCreature *cre, bool Big, bool Animated) | ||||
| { | ||||
| 	OBJ_CONSTRUCTION_CAPTURING_ALL; | ||||
| @@ -5726,7 +5730,7 @@ CUniversityWindow::CUniversityWindow(const CGHeroInstance * _hero, const IMarket | ||||
| 	yellow->recActions = | ||||
| 	red->recActions    = DISPOSE; | ||||
|  | ||||
| 	if ( market->o->ID == 104 ) // this is adventure map university | ||||
| 	if ( market->o->ID == Obj::UNIVERSITY ) // this is adventure map university | ||||
| 	{ | ||||
| 		SDL_Surface * titleImage = BitmapHandler::loadBitmap("UNIVBLDG.PCX"); | ||||
| 		blitAtLoc(titleImage, 232-titleImage->w/2, 76-titleImage->h/2, bg->bg); | ||||
| @@ -6028,6 +6032,7 @@ CThievesGuildWindow::CThievesGuildWindow(const CGObjectInstance * _owner) | ||||
| 	:owner(_owner) | ||||
| { | ||||
| 	OBJ_CONSTRUCTION_CAPTURING_ALL; | ||||
| 	type |= BLOCK_ADV_HOTKEYS; | ||||
|  | ||||
| 	SThievesGuildInfo tgi; //info to be displayed | ||||
| 	LOCPLINT->cb->getThievesGuildInfo(tgi, owner); | ||||
| @@ -6048,9 +6053,10 @@ CThievesGuildWindow::CThievesGuildWindow(const CGObjectInstance * _owner) | ||||
| 	resdatabar->pos.x += pos.x; | ||||
| 	resdatabar->pos.y += pos.y; | ||||
|  | ||||
| 	static std::vector< std::list< ui8 > > SThievesGuildInfo::* fields[] = { &SThievesGuildInfo::numOfTowns, &SThievesGuildInfo::numOfHeroes, &SThievesGuildInfo::gold, | ||||
| 		&SThievesGuildInfo::woodOre, &SThievesGuildInfo::mercSulfCrystGems, &SThievesGuildInfo::obelisks, &SThievesGuildInfo::artifacts, &SThievesGuildInfo::army, | ||||
| 		&SThievesGuildInfo::income}; | ||||
| 	static std::vector< std::list< ui8 > > SThievesGuildInfo::* fields[] =  | ||||
| 		{ &SThievesGuildInfo::numOfTowns, &SThievesGuildInfo::numOfHeroes, &SThievesGuildInfo::gold, | ||||
| 		  &SThievesGuildInfo::woodOre, &SThievesGuildInfo::mercSulfCrystGems, &SThievesGuildInfo::obelisks,  | ||||
| 		  &SThievesGuildInfo::artifacts, &SThievesGuildInfo::army, &SThievesGuildInfo::income }; | ||||
|  | ||||
| 	//printing texts & descriptions to background | ||||
|  | ||||
|   | ||||
| @@ -322,6 +322,7 @@ public: | ||||
| 	~CTownList(); //d-tor | ||||
| 	void genList(); | ||||
| 	void select(int which); //call-in | ||||
| 	void selectNext(); //switches to the next town or the first one if none is selected | ||||
| 	void mouseMoved (const SDL_MouseMotionEvent & sEvent);  //call-in | ||||
| 	void clickLeft(tribool down, bool previousState);  //call-in | ||||
| 	void clickRight(tribool down, bool previousState); //call-in | ||||
|   | ||||
| @@ -12,6 +12,8 @@ extern SDL_Surface * screenBuf, * screen2, * screen; | ||||
| extern std::queue<SDL_Event*> events; | ||||
| extern boost::mutex eventsM; | ||||
|  | ||||
| boost::thread_specific_ptr<bool> inGuiThread; | ||||
|  | ||||
| SObjectConstruction::SObjectConstruction( CIntObject *obj ) | ||||
| :myObj(obj) | ||||
| { | ||||
| @@ -344,6 +346,8 @@ void CGuiHandler::fakeMouseMove() | ||||
| void CGuiHandler::run() | ||||
| { | ||||
| 	setThreadName(-1, "CGuiHandler::run"); | ||||
| 	bool iAmGui = true; | ||||
| 	inGuiThread.reset(&iAmGui); | ||||
| 	try | ||||
| 	{ | ||||
| 		if (settings["video"]["fullscreen"].Bool()) | ||||
| @@ -457,6 +461,10 @@ bool CGuiHandler::isArrowKey( SDLKey key ) | ||||
| 	return key >= SDLK_UP && key <= SDLK_LEFT; | ||||
| } | ||||
|  | ||||
| bool CGuiHandler::amIGuiThread() | ||||
| { | ||||
| 	return inGuiThread.get() && *inGuiThread; | ||||
| } | ||||
|  | ||||
| CFramerateManager::CFramerateManager(int rate) | ||||
| { | ||||
|   | ||||
| @@ -96,6 +96,7 @@ public: | ||||
| 	static SDLKey numToDigit(SDLKey key);//converts numpad digit key to normal digit key | ||||
| 	static bool isNumKey(SDLKey key, bool number = true); //checks if key is on numpad (numbers - check only for numpad digits) | ||||
| 	static bool isArrowKey(SDLKey key);  | ||||
| 	static bool amIGuiThread(); | ||||
| }; | ||||
|  | ||||
| extern CGuiHandler GH; //global gui handler | ||||
|   | ||||
| @@ -248,7 +248,6 @@ void CConnection::sendPackToServer(const CPack &pack, ui8 player, ui32 requestID | ||||
| } | ||||
|  | ||||
| CSaveFile::CSaveFile( const std::string &fname ) | ||||
| 	:sfile(NULL) | ||||
| { | ||||
| 	registerTypes(*this); | ||||
| 	openNextFile(fname); | ||||
| @@ -256,7 +255,6 @@ CSaveFile::CSaveFile( const std::string &fname ) | ||||
|  | ||||
| CSaveFile::~CSaveFile() | ||||
| { | ||||
| 	delete sfile; | ||||
| } | ||||
|  | ||||
| int CSaveFile::write( const void * data, unsigned size ) | ||||
| @@ -265,17 +263,10 @@ int CSaveFile::write( const void * data, unsigned size ) | ||||
| 	return size; | ||||
| } | ||||
|  | ||||
| void CSaveFile::close() | ||||
| { | ||||
| 	delete sfile; | ||||
| 	sfile = NULL; | ||||
| } | ||||
|  | ||||
| void CSaveFile::openNextFile(const std::string &fname) | ||||
| { | ||||
| 	fName = fname; | ||||
| 	close(); | ||||
| 	sfile = new std::ofstream(fname.c_str(),std::ios::binary); | ||||
| 	sfile = make_unique<std::ofstream>(fname.c_str(), std::ios::binary); | ||||
| 	if(!(*sfile)) | ||||
| 	{ | ||||
| 		tlog1 << "Error: cannot open to write " << fname << std::endl; | ||||
| @@ -291,14 +282,13 @@ void CSaveFile::openNextFile(const std::string &fname) | ||||
| void CSaveFile::reportState(CLogger &out) | ||||
| { | ||||
| 	out << "CSaveFile" << std::endl; | ||||
| 	if(sfile && *sfile) | ||||
| 	if(sfile.get() && *sfile) | ||||
| 	{ | ||||
| 		out << "\tOpened " << fName << "\n\tPosition: " << sfile->tellp() << std::endl; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| CLoadFile::CLoadFile(const std::string &fname, int minimalVersion /*= version*/) | ||||
| :sfile(NULL) | ||||
| { | ||||
| 	registerTypes(*this); | ||||
| 	openNextFile(fname, minimalVersion); | ||||
| @@ -306,7 +296,6 @@ CLoadFile::CLoadFile(const std::string &fname, int minimalVersion /*= version*/) | ||||
|  | ||||
| CLoadFile::~CLoadFile() | ||||
| { | ||||
| 	delete sfile; | ||||
| } | ||||
|  | ||||
| int CLoadFile::read( const void * data, unsigned size ) | ||||
| @@ -315,20 +304,14 @@ int CLoadFile::read( const void * data, unsigned size ) | ||||
| 	return size; | ||||
| } | ||||
|  | ||||
| void CLoadFile::close() | ||||
| { | ||||
| 	delete sfile; | ||||
| 	sfile = NULL; | ||||
| } | ||||
|  | ||||
| void CLoadFile::openNextFile(const std::string &fname, int minimalVersion) | ||||
| { | ||||
| 	fName = fname; | ||||
| 	sfile = new std::ifstream(fname.c_str(),std::ios::binary); | ||||
| 	sfile = make_unique<std::ifstream>(fname.c_str(),std::ios::binary); | ||||
| 	if(!(*sfile)) | ||||
| 	{ | ||||
| 		tlog1 << "Error: cannot open to read " << fname << std::endl; | ||||
| 		sfile = NULL; | ||||
| 		sfile.release(); | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| @@ -338,8 +321,7 @@ void CLoadFile::openNextFile(const std::string &fname, int minimalVersion) | ||||
| 		if(std::memcmp(buffer,"VCMI",4)) | ||||
| 		{ | ||||
| 			tlog1 << "Error: not a VCMI file! ( " << fname << " )\n"; | ||||
| 			delete sfile; | ||||
| 			sfile = NULL; | ||||
| 			sfile.release(); | ||||
| 			return; | ||||
| 		} | ||||
|  | ||||
| @@ -347,8 +329,7 @@ void CLoadFile::openNextFile(const std::string &fname, int minimalVersion) | ||||
| 		if(myVersion < minimalVersion) | ||||
| 		{ | ||||
| 			tlog1 << "Error: Old file format! (file " << fname << " )\n"; | ||||
| 			delete sfile; | ||||
| 			sfile = NULL; | ||||
| 			sfile.release(); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| @@ -356,7 +337,7 @@ void CLoadFile::openNextFile(const std::string &fname, int minimalVersion) | ||||
| void CLoadFile::reportState(CLogger &out) | ||||
| { | ||||
| 	out << "CLoadFile" << std::endl; | ||||
| 	if(sfile && *sfile) | ||||
| 	if(!!sfile && *sfile) | ||||
| 	{ | ||||
| 		out << "\tOpened " << fName << "\n\tPosition: " << sfile->tellg() << std::endl; | ||||
| 	} | ||||
|   | ||||
| @@ -845,13 +845,12 @@ class DLL_LINKAGE CSaveFile | ||||
| 	} | ||||
| public: | ||||
| 	std::string fName; | ||||
| 	std::ofstream *sfile; | ||||
| 	unique_ptr<std::ofstream> sfile; | ||||
|  | ||||
| 	CSaveFile(const std::string &fname); | ||||
| 	~CSaveFile(); | ||||
| 	int write(const void * data, unsigned size); | ||||
|  | ||||
| 	void close(); | ||||
| 	void openNextFile(const std::string &fname); | ||||
| 	void reportState(CLogger &out); | ||||
| }; | ||||
| @@ -866,13 +865,12 @@ class DLL_LINKAGE CLoadFile | ||||
| 	} | ||||
| public: | ||||
| 	std::string fName; | ||||
| 	std::ifstream *sfile; | ||||
| 	unique_ptr<std::ifstream> sfile; | ||||
|  | ||||
| 	CLoadFile(const std::string &fname, int minimalVersion = version); | ||||
| 	~CLoadFile(); | ||||
| 	int read(const void * data, unsigned size); | ||||
|  | ||||
| 	void close(); | ||||
| 	void openNextFile(const std::string &fname, int minimalVersion); | ||||
| 	void reportState(CLogger &out); | ||||
| }; | ||||
| @@ -898,7 +896,6 @@ public: | ||||
| 	std::string name; //who uses this connection | ||||
|  | ||||
| 	int connectionID; | ||||
| 	CConnection *c; | ||||
| 	boost::thread *handler; | ||||
|  | ||||
| 	bool receivedStop, sendStop; | ||||
|   | ||||
| @@ -199,6 +199,7 @@ namespace Obj | ||||
| 		STABLES = 94, | ||||
| 		TRADING_POST = 99, | ||||
| 		SUBTERRANEAN_GATE = 103, | ||||
| 		UNIVERSITY = 104, | ||||
| 		SCHOOL_OF_WAR = 107, | ||||
| 		WHIRLPOOL = 111, | ||||
| 		BORDER_GATE = 212, | ||||
|   | ||||
| @@ -234,14 +234,18 @@ void LibClasses::makeNull() | ||||
| LibClasses::LibClasses() | ||||
| { | ||||
| 	//load .lod archives | ||||
| 	CStopWatch pomtime; | ||||
| 	spriteh = new CLodHandler(); | ||||
| 	spriteh->init(GameConstants::DATA_DIR + "/Data/H3sprite.lod", GameConstants::DATA_DIR + "/Sprites"); | ||||
| 	bitmaph = new CLodHandler; | ||||
| 	bitmaph->init(GameConstants::DATA_DIR + "/Data/H3bitmap.lod", GameConstants::DATA_DIR + "/Data"); | ||||
| 	bitmaph_ab = new CLodHandler(); | ||||
| 	bitmaph_ab->init(GameConstants::DATA_DIR + "/Data/H3ab_bmp.lod", GameConstants::DATA_DIR + "/Data"); | ||||
| 	tlog0<<"Loading .lod files: "<<pomtime.getDiff()<<std::endl; | ||||
|  | ||||
| 	if(!spriteh) //don't reload lods if we are starting a secoond game | ||||
| 	{ | ||||
| 		CStopWatch pomtime; | ||||
| 		spriteh = new CLodHandler(); | ||||
| 		spriteh->init(GameConstants::DATA_DIR + "/Data/H3sprite.lod", GameConstants::DATA_DIR + "/Sprites"); | ||||
| 		bitmaph = new CLodHandler; | ||||
| 		bitmaph->init(GameConstants::DATA_DIR + "/Data/H3bitmap.lod", GameConstants::DATA_DIR + "/Data"); | ||||
| 		bitmaph_ab = new CLodHandler(); | ||||
| 		bitmaph_ab->init(GameConstants::DATA_DIR + "/Data/H3ab_bmp.lod", GameConstants::DATA_DIR + "/Data"); | ||||
| 		tlog0<<"Loading .lod files: "<<pomtime.getDiff()<<std::endl; | ||||
| 	} | ||||
|  | ||||
| 	//init pointers to handlers | ||||
| 	makeNull(); | ||||
| @@ -253,3 +257,8 @@ void LibClasses::callWhenDeserializing() | ||||
| 	generaltexth->load(); | ||||
| 	arth->loadArtifacts(true); | ||||
| } | ||||
|  | ||||
| LibClasses::~LibClasses() | ||||
| { | ||||
| 	clear(); | ||||
| } | ||||
| @@ -37,6 +37,7 @@ public: | ||||
| 	CGeneralTextHandler * generaltexth; | ||||
|  | ||||
| 	LibClasses(); //c-tor, loads .lods and NULLs handlers | ||||
| 	~LibClasses(); | ||||
| 	void init(); //uses standard config file | ||||
| 	void clear(); //deletes all handlers and its data | ||||
| 	void makeNull(); //sets all handler (except of lodhs) pointers to null | ||||
|   | ||||
		Reference in New Issue
	
	Block a user