Browse Source

Mostly finished pregame part of hot-seat mode.

Michał W. Urbańczyk 15 years ago
parent
commit
4035155969
9 changed files with 177 additions and 101 deletions
  1. 11 1
      StartInfo.h
  2. 95 37
      client/CPreGame.cpp
  3. 1 2
      client/CPreGame.h
  4. 8 8
      client/GUIBase.cpp
  5. 1 1
      client/GUIBase.h
  6. 44 6
      client/GUIClasses.cpp
  7. 17 5
      client/GUIClasses.h
  8. 0 38
      mapHandler.cpp
  9. 0 3
      mapHandler.h

+ 11 - 1
StartInfo.h

@@ -3,6 +3,7 @@
 
 #include "global.h"
 #include <vector>
+#include <string>
 
 /*
  * StartInfo.h, part of VCMI engine
@@ -53,7 +54,7 @@ struct StartInfo
 {
 	ui8 mode; //0 - new game; 1 - load game
 	ui8 difficulty; //0=easy; 4=impossible
-	std::vector<PlayerSettings> playerInfos;
+	std::vector<PlayerSettings> playerInfos; //serial indexed
 	ui8 turnTime; //in minutes, 0=unlimited
 	std::string mapname;
 	PlayerSettings & getIthPlayersSettings(int no)
@@ -63,8 +64,17 @@ struct StartInfo
 				return playerInfos[i];
 		tlog1 << "Cannot find info about player " << no <<". Throwing...\n";
 		throw std::string("Cannot find info about player");
+	}
 
+	PlayerSettings *getPlayersSettings(const std::string &name)
+	{
+		for(unsigned int i=0; i<playerInfos.size(); ++i)
+			if(playerInfos[i].name == name)
+				return &playerInfos[i];
+
+		return NULL;
 	}
+
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{
 		h & mode;

+ 95 - 37
client/CPreGame.cpp

@@ -51,7 +51,8 @@ void startGame(StartInfo * options);
 CGPreGame * CGP;
 static const CMapInfo *curMap;
 static StartInfo *curOpts;
-static int playerColor, playerSerial;
+static int playerColor, playerSerial; //if more than one player - applies to the first
+static std::vector<std::string> playerNames; // serial id of name <-> player name
 
 static std::string selectedName; //set when game is started/loaded
 
@@ -211,9 +212,8 @@ CGPreGame::~CGPreGame()
 
 void CGPreGame::openSel( CMenuScreen::EState type )
 {
-	std::vector<std::string> names;
-	names.push_back(CGI->generaltexth->allTexts[434]);
-	GH.pushInt(new CSelectionScreen(type, names));
+	playerNames.push_back(CGI->generaltexth->allTexts[434]); //we have only one player and his name is "Player"
+	GH.pushInt(new CSelectionScreen(type));
 }
 
 void CGPreGame::loadGraphics()
@@ -257,8 +257,7 @@ void CGPreGame::update()
 	GH.handleEvents();
 }
 
-CSelectionScreen::CSelectionScreen( CMenuScreen::EState Type, const std::vector<std::string> &PlayerNames )
-:playerNames(PlayerNames)
+CSelectionScreen::CSelectionScreen(CMenuScreen::EState Type)
 {
 	OBJ_CONSTRUCTION_CAPTURING_ALL;
 	IShowActivable::type = BLOCK_ADV_HOTKEYS;
@@ -358,6 +357,7 @@ CSelectionScreen::~CSelectionScreen()
 	curMap = NULL;
 	curOpts = NULL;
 	playerSerial = playerColor = -1;
+	playerNames.clear();
 }
 
 void CSelectionScreen::toggleTab(CIntObject *tab)
@@ -396,6 +396,25 @@ void CSelectionScreen::changeSelection( const CMapInfo *to )
 	}
 }
 
+void setPlayer(PlayerSettings &pset, unsigned player) 
+{
+	if(player < playerNames.size())
+	{
+		pset.name = playerNames[player];
+		pset.human = true;
+		if(playerColor < 0)
+		{
+			playerColor = pset.color;
+			playerSerial = pset.serial;
+		}
+	}
+	else
+	{
+		pset.name = CGI->generaltexth->allTexts[468];//Computer
+		pset.human = false;
+	}
+}
+
 void CSelectionScreen::updateStartInfo( const CMapInfo * to )
 {
 	sInfo.playerInfos.clear();
@@ -405,7 +424,7 @@ void CSelectionScreen::updateStartInfo( const CMapInfo * to )
 	sInfo.playerInfos.resize(to->playerAmnt);
 	sInfo.mapname = to->filename;
 	playerSerial = playerColor = -1;
-	int placedPlayers = 0;
+	ui8 placedPlayers = 0;
 
 	int serialC=0;
 	for (int i = 0; i < PLAYER_LIMIT; i++)
@@ -419,22 +438,7 @@ void CSelectionScreen::updateStartInfo( const CMapInfo * to )
 		PlayerSettings &pset = sInfo.playerInfos[serialC];
 		pset.color = i;
 		pset.serial = serialC++;
-
-		if (pinfo.canHumanPlay && placedPlayers < playerNames.size())
-		{
-			pset.name = playerNames[placedPlayers++];
-			pset.human = true;
-			if(playerColor < 0)
-			{
-				playerColor = i;
-				playerSerial = pset.serial;
-			}
-		}
-		else
-		{
-			pset.name = CGI->generaltexth->allTexts[468];//Computer
-			pset.human = false;
-		}
+		setPlayer(pset, placedPlayers++);
 
 		for (int j = 0; j < F_NUMBER  &&  pset.castle != -1; j++) //we start with none and find matching faction. if more than one, then set to random
 		{
@@ -1479,22 +1483,77 @@ void OptionsTab::setTurnLength( int npos )
 
 void OptionsTab::flagPressed( int player )
 {
-	if(player == playerSerial) //that color is already selected, no action needed
-		return;
+	static std::pair<int, int> playerToRestore(-1, -1); //<color serial, player name serial> 
+
+	PlayerSettings &clicked =  curOpts->playerInfos[player];
+	PlayerSettings *old = NULL;
+
+	if(playerNames.size() == 1) //single player -> swap
+	{
+		if(player == playerSerial) //that color is already selected, no action needed
+			return;
+
 
-	PlayerSettings &s =  curOpts->playerInfos[player],
-		&old = curOpts->playerInfos[playerSerial];
+		old = &curOpts->playerInfos[playerSerial];
+		std::swap(old->human, clicked.human);
+		std::swap(old->name, clicked.name);
+		playerColor = clicked.color;
+		playerSerial = player;
+	}
+	else
+	{
+		//identify clicked player
+		int curNameID = clicked.human 
+						? vstd::findPos(playerNames, clicked.name) 
+						: -1;
+
+ 		if(curNameID >= 0  &&  playerToRestore.second == curNameID) //player to restore is about to being replaced -> put him back to the old place
+		{
+			PlayerSettings &restPos = curOpts->playerInfos[playerToRestore.first];
+ 			setPlayer(restPos, playerToRestore.second);
+			playerToRestore.first = playerToRestore.second = 0;
+		}
+
+ 		//who will be put here?
+ 		if(curNameID < 0) //if possible replace computer with unallocated player
+		{
+			for(int i = 0; i < playerNames.size(); i++)
+			{
+				if(!curOpts->getPlayersSettings(playerNames[i])) 
+				{
+					curNameID = i-1; //-1 because it'll incremented soon
+					break;
+				}
+			}
+		}
 
-	std::swap(old.human, s.human);
-	std::swap(old.name, s.name);
-	playerColor = s.color;
+ 		setPlayer(clicked, ++curNameID); //simply next player
 
-	if(!entries[playerSerial]->fixedHero)
-		old.hero = -1;
+		//if that player was somewhere else, we need to replace him with computer
+		if(curNameID < playerNames.size())
+		{
+			for(std::vector<PlayerSettings>::iterator i = curOpts->playerInfos.begin(); i != curOpts->playerInfos.end(); i++)
+			{
+				if(i->serial != player  &&  i->name == playerNames[curNameID])
+				{
+					assert(i->human);
+					playerToRestore.first = i->serial;
+					playerToRestore.second = vstd::findPos(playerNames, i->name);
+					setPlayer(*i, -1); //set computer
+					old = &*i;
+					break;
+				}
+			}
+		}
+	}
 
-	playerSerial = player;
-	entries[s.serial]->selectButtons();
-	entries[old.serial]->selectButtons();
+	entries[clicked.serial]->selectButtons();
+	if(old)
+	{
+		entries[old->serial]->selectButtons();
+		if(!entries[playerSerial]->fixedHero)
+			old->hero = -1;
+	}
 	GH.totalRedraw();
 }
 
@@ -1991,13 +2050,12 @@ CHotSeatPlayers::CHotSeatPlayers(const std::string &firstPlayer)
 
 void CHotSeatPlayers::enterSelectionScreen()
 {
-	std::vector<std::string> playerNames;
 	for(int i = 0; i < ARRAY_COUNT(txt); i++)
 		if(txt[i]->text.length())
 			playerNames.push_back(txt[i]->text);
 
 	GH.popInts(2);
-	GH.pushInt(new CSelectionScreen(CMenuScreen::newGame, playerNames));
+	GH.pushInt(new CSelectionScreen(CMenuScreen::newGame));
 }
 
 CBonusSelection::CBonusSelection( const CCampaign * ourCampaign, int whichMap )

+ 1 - 2
client/CPreGame.h

@@ -206,9 +206,8 @@ public:
 	const CMapInfo *current;
 	StartInfo sInfo;
 	CIntObject *curTab;
-	std::vector<std::string> playerNames;
 
-	CSelectionScreen(CMenuScreen::EState Type, const std::vector<std::string> &PlayerNames = std::vector<std::string>());
+	CSelectionScreen(CMenuScreen::EState Type);
 	~CSelectionScreen();
 	void toggleTab(CIntObject *tab);
 	void changeSelection(const CMapInfo *to);

+ 8 - 8
client/GUIBase.cpp

@@ -156,7 +156,7 @@ void CGuiHandler::handleEvent(SDL_Event *sEvent)
 		}
 
 		bool keysCaptured = false;
-		for(std::list<CIntObject*>::iterator i=keyinterested.begin(); i != keyinterested.end();i++)
+		for(std::list<CIntObject*>::iterator i=keyinterested.begin(); i != keyinterested.end() && current; i++)
 		{
 			if((*i)->captureAllKeys)
 			{
@@ -166,7 +166,7 @@ void CGuiHandler::handleEvent(SDL_Event *sEvent)
 		}
 
 		std::list<CIntObject*> miCopy = keyinterested;
-		for(std::list<CIntObject*>::iterator i=miCopy.begin(); i != miCopy.end();i++)
+		for(std::list<CIntObject*>::iterator i=miCopy.begin(); i != miCopy.end() && current; i++)
 			if(vstd::contains(keyinterested,*i) && (!keysCaptured || (*i)->captureAllKeys))
 				(**i).keyPressed(key);
 	}
@@ -183,7 +183,7 @@ void CGuiHandler::handleEvent(SDL_Event *sEvent)
 			if(lastClick == sEvent->motion  &&  (SDL_GetTicks() - lastClickTime) < 300)
 			{
 				std::list<CIntObject*> hlp = doubleClickInterested;
-				for(std::list<CIntObject*>::iterator i=hlp.begin(); i != hlp.end();i++)
+				for(std::list<CIntObject*>::iterator i=hlp.begin(); i != hlp.end() && current; i++)
 				{
 					if(!vstd::contains(doubleClickInterested,*i)) continue;
 					if (isItIn(&(*i)->pos,sEvent->motion.x,sEvent->motion.y))
@@ -198,7 +198,7 @@ void CGuiHandler::handleEvent(SDL_Event *sEvent)
 			lastClickTime = SDL_GetTicks();
 
 			std::list<CIntObject*> hlp = lclickable;
-			for(std::list<CIntObject*>::iterator i=hlp.begin(); i != hlp.end();i++)
+			for(std::list<CIntObject*>::iterator i=hlp.begin(); i != hlp.end() && current; i++)
 			{
 				if(!vstd::contains(lclickable,*i)) continue;
 				if (isItIn(&(*i)->pos,sEvent->motion.x,sEvent->motion.y))
@@ -212,7 +212,7 @@ void CGuiHandler::handleEvent(SDL_Event *sEvent)
 		else if (sEvent->button.button == SDL_BUTTON_RIGHT)
 		{
 			std::list<CIntObject*> hlp = rclickable;
-			for(std::list<CIntObject*>::iterator i=hlp.begin(); i != hlp.end();i++)
+			for(std::list<CIntObject*>::iterator i=hlp.begin(); i != hlp.end() && current; i++)
 			{
 				if(!vstd::contains(rclickable,*i)) continue;
 				if (isItIn(&(*i)->pos,sEvent->motion.x,sEvent->motion.y))
@@ -226,7 +226,7 @@ void CGuiHandler::handleEvent(SDL_Event *sEvent)
 		else if(sEvent->button.button == SDL_BUTTON_WHEELDOWN || sEvent->button.button == SDL_BUTTON_WHEELUP)
 		{
 			std::list<CIntObject*> hlp = wheelInterested;
-			for(std::list<CIntObject*>::iterator i=hlp.begin(); i != hlp.end();i++)
+			for(std::list<CIntObject*>::iterator i=hlp.begin(); i != hlp.end() && current; i++)
 			{
 				if(!vstd::contains(wheelInterested,*i)) continue;
 				(*i)->wheelScrolled(sEvent->button.button == SDL_BUTTON_WHEELDOWN, isItIn(&(*i)->pos,sEvent->motion.x,sEvent->motion.y));
@@ -236,7 +236,7 @@ void CGuiHandler::handleEvent(SDL_Event *sEvent)
 	else if ((sEvent->type==SDL_MOUSEBUTTONUP) && (sEvent->button.button == SDL_BUTTON_LEFT))
 	{
 		std::list<CIntObject*> hlp = lclickable;
-		for(std::list<CIntObject*>::iterator i=hlp.begin(); i != hlp.end();i++)
+		for(std::list<CIntObject*>::iterator i=hlp.begin(); i != hlp.end() && current; i++)
 		{
 			if(!vstd::contains(lclickable,*i)) continue;
 			prev = (*i)->pressedL;
@@ -252,7 +252,7 @@ void CGuiHandler::handleEvent(SDL_Event *sEvent)
 	else if ((sEvent->type==SDL_MOUSEBUTTONUP) && (sEvent->button.button == SDL_BUTTON_RIGHT))
 	{
 		std::list<CIntObject*> hlp = rclickable;
-		for(std::list<CIntObject*>::iterator i=hlp.begin(); i != hlp.end();i++)
+		for(std::list<CIntObject*>::iterator i=hlp.begin(); i != hlp.end() && current; i++)
 		{
 			if(!vstd::contains(rclickable,*i)) continue;
 			prev = (*i)->pressedR;

+ 1 - 1
client/GUIBase.h

@@ -460,7 +460,7 @@ public:
 	//objs to blit
 	std::vector<IShowable*> objsToBlit;
 
-	SDL_Event * current; //current event
+	SDL_Event * current; //current event - can be set to NULL to stop handling event
 	IUpdateable *curInt;
 
 	Point lastClick;

+ 44 - 6
client/GUIClasses.cpp

@@ -62,7 +62,8 @@ using namespace CSDL_Ext;
 extern std::queue<SDL_Event*> events;
 extern boost::mutex eventsM;
 
-CTextInput * CTextInput::inputWithFocus;
+std::list<CFocusable*> CFocusable::focusables;
+CFocusable * CFocusable::inputWithFocus;
 
 #undef min
 #undef max
@@ -5174,8 +5175,9 @@ void CGStatusBar::init()
 }
 
 CTextInput::CTextInput( const Rect &Pos, const Point &bgOffset, const std::string &bgName, const CFunctionList<void(const std::string &)> &CB )
-:cb(CB), focus(false)
+:cb(CB)
 {
+	focus = false;
 	pos += Pos;
 	OBJ_CONSTRUCTION;
 	bg = new CPicture(bgName, bgOffset.x, bgOffset.y);
@@ -5184,8 +5186,8 @@ CTextInput::CTextInput( const Rect &Pos, const Point &bgOffset, const std::strin
 }
 
 CTextInput::CTextInput(const Rect &Pos, SDL_Surface *srf)
-: focus(false)
 {
+	focus = false;
 	pos += Pos;
 	OBJ_CONSTRUCTION;
 	bg = new CPicture(Pos, 0, true);
@@ -5213,7 +5215,16 @@ void CTextInput::clickLeft( tribool down, bool previousState )
 
 void CTextInput::keyPressed( const SDL_KeyboardEvent & key )
 {
-	if(!focus || key.state != SDL_PRESSED) return;
+	if(!focus || key.state != SDL_PRESSED) 
+		return;
+
+	if(key.keysym.sym == SDLK_TAB)
+	{
+		moveFocus();
+		GH.current = NULL;
+		return;
+	}
+
 	switch(key.keysym.sym)
 	{
 	case SDLK_BACKSPACE:
@@ -5240,12 +5251,22 @@ void CTextInput::setText( const std::string &nText, bool callCb )
 }
 
 CTextInput::~CTextInput()
+{
+}
+
+CFocusable::CFocusable()
+{
+	focusables.push_back(this);
+}
+
+CFocusable::~CFocusable()
 {
 	if(inputWithFocus == this)
 		inputWithFocus = NULL;
-}
 
-void CTextInput::giveFocus()
+	focusables -= this;
+}
+void CFocusable::giveFocus()
 {
 	if(inputWithFocus)
 	{
@@ -5257,3 +5278,20 @@ void CTextInput::giveFocus()
 	inputWithFocus = this;
 	redraw();
 }
+
+void CFocusable::moveFocus()
+{
+	std::list<CFocusable*>::iterator i = vstd::find(focusables, this),
+									ourIt = i;
+	for(i++; i != ourIt; i++)
+	{
+		if(i == focusables.end())
+			i = focusables.begin();
+
+		if((*i)->active)
+		{
+			(*i)->giveFocus();
+			break;;
+		}
+	}
+}

+ 17 - 5
client/GUIClasses.h

@@ -261,7 +261,7 @@ public:
 };
 
 class CLabel
-	: public CIntObject
+	: public virtual CIntObject
 {
 public:
 	enum EAlignment {TOPLEFT, CENTER, BOTTOMRIGHT} alignment;
@@ -296,12 +296,26 @@ public:
 	~CGStatusBar();
 };
 
+class CFocusable 
+	: public virtual CIntObject
+{
+public:
+	bool focus; //only one focusable control can have focus at one moment
+
+	void giveFocus(); //captures focus
+	void moveFocus(); //moves focus to next active control (may be used for tab switching)
+
+	static std::list<CFocusable*> focusables; //all existing objs
+	static CFocusable *inputWithFocus; //who has focus now
+	CFocusable();
+	~CFocusable();
+};
 
-class CTextInput : public CLabel
+class CTextInput
+	: public CLabel, public CFocusable
 {
 public:
 	CFunctionList<void(const std::string &)> cb;
-	bool focus; //only one text input may have focus at once
 
 	void setText(const std::string &nText, bool callCb = false);
 
@@ -311,8 +325,6 @@ public:
 	void showAll(SDL_Surface * to);
 	void clickLeft(tribool down, bool previousState);
 	void keyPressed(const SDL_KeyboardEvent & key);
-	void giveFocus();
-	static CTextInput *inputWithFocus;
 };
 
 class CList : public CIntObject

+ 0 - 38
mapHandler.cpp

@@ -1069,44 +1069,6 @@ SDL_Surface * CMapHandler::getVisBitmap(int x, int y, const std::vector< std::ve
 	return fullHide->ourImages[0].bitmap; //this case should never happen, but it is better to hide too much than reveal it....
 }
 
-int CMapHandler::getCost(int3 &a, int3 &b, const CGHeroInstance *hero)
-{
-	int ret=-1;
-	if(a.x>=CGI->mh->map->width && a.y>=CGI->mh->map->height)
-		ret = hero->type->heroClass->terrCosts[CGI->mh->ttiles[CGI->mh->map->width-1][CGI->mh->map->width-1][a.z].tileInfo->malle];
-	else if(a.x>=CGI->mh->map->width && a.y<CGI->mh->map->height)
-		ret = hero->type->heroClass->terrCosts[CGI->mh->ttiles[CGI->mh->map->width-1][a.y][a.z].tileInfo->malle];
-	else if(a.x<CGI->mh->map->width && a.y>=CGI->mh->map->height)
-		ret = hero->type->heroClass->terrCosts[CGI->mh->ttiles[a.x][CGI->mh->map->width-1][a.z].tileInfo->malle];
-	else
-		ret = hero->type->heroClass->terrCosts[CGI->mh->ttiles[a.x][a.y][a.z].tileInfo->malle];
-	if(!(a.x==b.x || a.y==b.y))
-		ret*=1.41421;
-
-	//TODO: use hero's pathfinding skill during calculating cost
-	return ret;
-}
-
-//std::vector < CGObjectInstance * > CMapHandler::getVisitableObjs(int3 pos)
-//{
-//	std::vector < CGObjectInstance * > ret;
-//	for(int h=0; h<ttiles[pos.x][pos.y][pos.z].objects.size(); ++h)
-//	{
-//		CGObjectInstance * curi = ttiles[pos.x][pos.y][pos.z].objects[h].first;
-//		if(curi->visitableAt(- curi->pos.x + pos.x + curi->getWidth() - 1, -curi->pos.y + pos.y + curi->getHeight() - 1))
-//			ret.push_back(curi);
-//	}
-//	return ret;
-//}
-
-std::string CMapHandler::getDefName(int id, int subid)
-{
-	CGDefInfo* temp = CGI->dobjinfo->gobjs[id][subid];
-	if(temp)
-		return temp->name;
-	throw std::string("Def not found.");
-}
-
 bool CMapHandler::printObject(const CGObjectInstance *obj)
 {
 	const SDL_Surface *bitmap = obj->defInfo->handler->ourImages[0].bitmap;

+ 0 - 3
mapHandler.h

@@ -117,11 +117,8 @@ public:
 	void loadDefs();
 	SDL_Surface * getVisBitmap(int x, int y, const std::vector< std::vector< std::vector<unsigned char> > > & visibilityMap, int lvl);
 
-	int getCost(int3 & a, int3 & b, const CGHeroInstance * hero);
 	std::vector< std::string > getObjDescriptions(int3 pos); //returns desriptions of objects blocking given position
-	//std::vector< CGObjectInstance * > getVisitableObjs(int3 pos); //returns vector of visitable objects at certain position
 	CGObjectInstance * createObject(int id, int subid, int3 pos, int owner=254); //creates a new object with a certain id and subid
-	std::string getDefName(int id, int subid); //returns name of def for object with given id and subid
 	bool printObject(const CGObjectInstance * obj); //puts appropriate things to ttiles, so obj will be visible on map
 	bool hideObject(const CGObjectInstance * obj); //removes appropriate things from ttiles, so obj will be no longer visible on map (but still will exist)
 	bool removeObject(CGObjectInstance * obj); //removes object from each place in VCMI (I hope)