浏览代码

Move hero/Next hero buttons being blocked when they should (#204)

yupsi 14 年之前
父节点
当前提交
583aca8912
共有 5 个文件被更改,包括 88 次插入23 次删除
  1. 68 20
      client/CAdvmapInterface.cpp
  2. 5 1
      client/CAdvmapInterface.h
  3. 12 1
      client/CPlayerInterface.cpp
  4. 1 1
      client/CPlayerInterface.h
  5. 2 0
      client/GUIClasses.cpp

+ 68 - 20
client/CAdvmapInterface.cpp

@@ -1099,7 +1099,13 @@ void CAdvMapInt::fsleepWake()
 	setHeroSleeping(h, newSleep);
 	updateSleepWake(h);
 	if (newSleep)
+	{
 		fnextHero();
+
+		//moveHero.block(true); 
+		//uncomment to enable original HoMM3 behaviour:
+		//move button is disabled for hero going to sleep, even though it's enabled when you reselect him
+	}
 }
 
 void CAdvMapInt::fmoveHero()
@@ -1134,19 +1140,10 @@ void CAdvMapInt::fsystemOptions()
 
 void CAdvMapInt::fnextHero()
 {
-	if(!LOCPLINT->wanderingHeroes.size()) //no wandering heroes
-		return; 
-
-	int start = heroList.selected;
-	int i = start;
-
-	do 
-	{
-		i++;
-		if(i >= LOCPLINT->wanderingHeroes.size())
-			i = 0;
-	} while ((!LOCPLINT->wanderingHeroes[i]->movement || isHeroSleeping(LOCPLINT->wanderingHeroes[i])) && i!=start);
-	heroList.select(i);
+	int next = getNextHeroIndex(heroList.selected);
+	if (next < 0)
+		return;
+	heroList.select(next);
 }
 
 void CAdvMapInt::fendTurn()
@@ -1155,7 +1152,7 @@ void CAdvMapInt::fendTurn()
 		return;
 
 	for (int i = 0; i < LOCPLINT->wanderingHeroes.size(); i++)
-		if (!isHeroSleeping(LOCPLINT->wanderingHeroes[i]) && (LOCPLINT->wanderingHeroes[i]->movement > 0)) // some other minimal threshold probably?
+		if (!isHeroSleeping(LOCPLINT->wanderingHeroes[i]) && (LOCPLINT->wanderingHeroes[i]->movement > 0)) 
 		{
 			LOCPLINT->showYesNoDialog(CGI->generaltexth->allTexts[55], std::vector<SComponent*>(), boost::bind(&CAdvMapInt::endingTurn, this), 0, false);
 			return;
@@ -1175,6 +1172,54 @@ void CAdvMapInt::updateSleepWake(const CGHeroInstance *h)
 	sleepWake.update();
 }
 
+void CAdvMapInt::updateMoveHero(const CGHeroInstance *h, tribool hasPath)
+{
+	//default value is for everywhere but CPlayerInterface::moveHero, because paths are not updated from there immediately
+	if (hasPath == tribool::indeterminate_value) 
+		 hasPath = LOCPLINT->paths[h].nodes.size() ? true : false;
+	if (!h)
+	{
+		moveHero.block(true);	
+		return;
+	}
+	moveHero.block(!hasPath || (h->movement == 0));
+}
+
+int CAdvMapInt::getNextHeroIndex(int startIndex)
+{
+	if (LOCPLINT->wanderingHeroes.size() == 0)
+		return -1;
+	if (startIndex < 0)
+		startIndex = 0;
+	int i = startIndex;
+	do 
+	{
+		i++;
+		if (i >= LOCPLINT->wanderingHeroes.size())
+			i = 0;
+	} 
+	while (((LOCPLINT->wanderingHeroes[i]->movement == 0) || isHeroSleeping(LOCPLINT->wanderingHeroes[i])) && (i != startIndex));
+
+	if ((LOCPLINT->wanderingHeroes[i]->movement > 0) && !isHeroSleeping(LOCPLINT->wanderingHeroes[i]))
+		return i;
+	else
+		return -1;
+}
+
+void CAdvMapInt::updateNextHero(const CGHeroInstance *h)
+{
+	int start = heroList.getPosOfHero(h); 
+	int next = getNextHeroIndex(start);
+	if (next < 0)
+	{
+		nextHero.block(true);
+		return;
+	}
+	const CGHeroInstance *nextH = LOCPLINT->wanderingHeroes[next];
+	bool noActiveHeroes = (next == start) && ((nextH->movement == 0) || isHeroSleeping(nextH));
+	nextHero.block(noActiveHeroes);
+}
+
 void CAdvMapInt::activate()
 {
 	if(isActive())
@@ -1279,6 +1324,7 @@ void CAdvMapInt::setHeroSleeping(const CGHeroInstance *hero, bool sleep)
 		LOCPLINT->sleepingHeroes += hero;
 	else
 		LOCPLINT->sleepingHeroes -= hero;
+	updateNextHero(NULL);
 }
 
 void CAdvMapInt::show(SDL_Surface *to)
@@ -1548,18 +1594,15 @@ void CAdvMapInt::select(const CArmedInstance *sel, bool centerView /*= true*/)
 	terrain.currentPath = NULL;
 	if(sel->ID==TOWNI_TYPE)
 	{
-		updateSleepWake(NULL);
-
 		int pos = vstd::findPos(LOCPLINT->towns,sel);
 		townList.selected = pos;
 		townList.fixPos();
+		updateSleepWake(NULL);
+		updateMoveHero(NULL);
 	}
 	else //hero selected
 	{
 		const CGHeroInstance *h = static_cast<const CGHeroInstance*>(sel);
-
-		updateSleepWake(h);
-
 		if(LOCPLINT->getWHero(heroList.selected) != h)
 		{
 			heroList.selected = heroList.getPosOfHero(h);
@@ -1567,6 +1610,9 @@ void CAdvMapInt::select(const CArmedInstance *sel, bool centerView /*= true*/)
 		}
 
 		terrain.currentPath = LOCPLINT->getAndVerifyPath(h);
+
+		updateSleepWake(h);
+		updateMoveHero(h);
 	}
 	townList.draw(screen);
 	heroList.draw(screen);
@@ -1725,7 +1771,9 @@ void CAdvMapInt::tileLClicked(const int3 &mp)
 			{
 				CGPath &path = LOCPLINT->paths[currentHero];
 				terrain.currentPath = &path;
-				if(!LOCPLINT->cb->getPath2(mp, path)) //try getting path, erase if failed
+				bool gotPath = LOCPLINT->cb->getPath2(mp, path); //try getting path, erase if failed
+				updateMoveHero(currentHero); 	
+				if (!gotPath)
 					LOCPLINT->eraseCurrentPathOf(currentHero);
 				else
 					return;

+ 5 - 1
client/CAdvmapInterface.h

@@ -235,6 +235,7 @@ public:
 
 	bool isHeroSleeping(const CGHeroInstance *hero);
 	void setHeroSleeping(const CGHeroInstance *hero, bool sleep);
+	int getNextHeroIndex(int startIndex); //for Next Hero button - cycles awake heroes with movement only
 
 	void setPlayer(int Player);
 	void startHotSeatWait(int Player);
@@ -248,7 +249,10 @@ public:
 	const CGHeroInstance * curHero() const;
 	const CGTownInstance * curTown() const;
 	const IShipyard * ourInaccessibleShipyard(const CGObjectInstance *obj) const; //checks if obj is our ashipyard and cursor is 0,0 -> returns shipyard or NULL else
-	void updateSleepWake(const CGHeroInstance *h); //button update
+	//button updates
+	void updateSleepWake(const CGHeroInstance *h); 
+	void updateMoveHero(const CGHeroInstance *h, tribool hasPath = tribool::indeterminate_value);
+	void updateNextHero(const CGHeroInstance *h);
 };
 
 extern CAdvMapInt *adventureInt;

+ 12 - 1
client/CPlayerInterface.cpp

@@ -488,6 +488,7 @@ void CPlayerInterface::heroInGarrisonChange(const CGTownInstance *town)
 		CGI->mh->printObject(town->visitingHero);
 		wanderingHeroes.push_back(town->visitingHero);
 	}
+	adventureInt->updateNextHero(NULL);
 
 	if(CCastleInterface *c = castleInt)
 	{
@@ -1142,6 +1143,7 @@ bool CPlayerInterface::moveHero( const CGHeroInstance *h, CGPath path )
 		//but no authentic button click/sound ;-)
 	}
 	
+	int i = 1;
 	//evil...
 	eventsM.unlock();
 	pim->unlock();
@@ -1159,7 +1161,7 @@ bool CPlayerInterface::moveHero( const CGHeroInstance *h, CGPath path )
 
 		const TerrainTile * curTile = cb->getTile(CGHeroInstance::convertPosition(h->pos, false));
 
-		for(int i=path.nodes.size()-1; i>0 && (stillMoveHero.data == CONTINUE_MOVE || curTile->blocked); i--)
+		for(i=path.nodes.size()-1; i>0 && (stillMoveHero.data == CONTINUE_MOVE || curTile->blocked); i--)
 		{
 			//changing z coordinate means we're moving through subterranean gate -> it's done automatically upon the visit, so we don't have to request that move here
 			if(path.nodes[i-1].coord.z != path.nodes[i].coord.z)
@@ -1209,6 +1211,13 @@ bool CPlayerInterface::moveHero( const CGHeroInstance *h, CGPath path )
 	cb->getGsMutex().lock_shared();
 	pim->lock();
 	eventsM.lock();
+
+	if (adventureInt)
+	{
+		// (i == 0) means hero went through all the path
+		adventureInt->updateMoveHero(h, (i != 0)); 
+		adventureInt->updateNextHero(h);
+	}
 	return result;
 }
 
@@ -1336,6 +1345,8 @@ void CPlayerInterface::recreateHeroTownList()
 	std::vector<const CGTownInstance*> townInfo = cb->getTownsInfo();
 	for(size_t i = 0; i < townInfo.size(); i++)
 		towns.push_back(townInfo[i]);
+
+	adventureInt->updateNextHero(NULL);
 }
 
 const CGHeroInstance * CPlayerInterface::getWHero( int pos )

+ 1 - 1
client/CPlayerInterface.h

@@ -141,7 +141,7 @@ public:
 	std::vector<const CGHeroInstance *> wanderingHeroes; //our heroes on the adventure map (not the garrisoned ones)
 	std::vector<const CGTownInstance *> towns; //our heroes on the adventure map (not the garrisoned ones)
 	std::map<const CGHeroInstance *, CGPath> paths; //maps hero => selected path in adventure map
-	std::vector<const CGHeroInstance *> sleepingHeroes; 
+	std::vector<const CGHeroInstance *> sleepingHeroes; //if hero is in here, he's sleeping
 
 	struct SpellbookLastSetting
 	{

+ 2 - 0
client/GUIClasses.cpp

@@ -1355,6 +1355,8 @@ void CHeroList::updateHList(const CGHeroInstance *toRemove)
 		else
 			select(selected);
 	}
+
+	adventureInt->updateNextHero(NULL);
 }
 
 void CHeroList::updateMove(const CGHeroInstance* which) //draws move points bar