Browse Source

CPlayerInterface: all new code for automatic teleport usage

ArseniyShestakov 10 years ago
parent
commit
5233b60243
2 changed files with 66 additions and 26 deletions
  1. 65 26
      client/CPlayerInterface.cpp
  2. 1 0
      client/CPlayerInterface.h

+ 65 - 26
client/CPlayerInterface.cpp

@@ -97,6 +97,7 @@ static bool objectBlitOrderSorter(const TerrainTileObject  & a, const TerrainTil
 CPlayerInterface::CPlayerInterface(PlayerColor Player)
 {
 	logGlobal->traceStream() << "\tHuman player interface for player " << Player << " being constructed";
+	destinationTeleport = ObjectInstanceID();
 	observerInDuelMode = false;
 	howManyPeople++;
 	GH.defActionsDef = 0;
@@ -1141,6 +1142,16 @@ void CPlayerInterface::showBlockingDialog( const std::string &text, const std::v
 
 }
 
+void CPlayerInterface::showTeleportDialog(TeleportChannelID channel, std::vector<ObjectInstanceID> exits, bool impassable, QueryID askID)
+{
+	EVENT_HANDLER_CALLED_BY_CLIENT;
+	ObjectInstanceID choosenExit;
+	if(destinationTeleport != ObjectInstanceID() && vstd::contains(exits, destinationTeleport))
+		choosenExit = destinationTeleport;
+
+	cb->selectionMade(choosenExit.getNum(), askID);
+}
+
 void CPlayerInterface::tileRevealed(const std::unordered_set<int3, ShashInt3> &pos)
 {
 	EVENT_HANDLER_CALLED_BY_CLIENT;
@@ -1389,8 +1400,17 @@ void CPlayerInterface::showArtifactAssemblyDialog (ui32 artifactID, ui32 assembl
 void CPlayerInterface::requestRealized( PackageApplied *pa )
 {
 	EVENT_HANDLER_CALLED_BY_CLIENT;
-	if(pa->packType == typeList.getTypeID<MoveHero>()  &&  stillMoveHero.get() == DURING_MOVE)
+	if(pa->packType == typeList.getTypeID<MoveHero>()  &&  stillMoveHero.get() == DURING_MOVE
+	   && destinationTeleport == ObjectInstanceID())
+		stillMoveHero.setn(CONTINUE_MOVE);
+
+	if(destinationTeleport != ObjectInstanceID()
+	   && pa->packType == typeList.getTypeID<QueryReply>()
+	   && stillMoveHero.get() == DURING_MOVE)
+	{ // After teleportation via CGTeleport object is finished
+		destinationTeleport = ObjectInstanceID();
 		stillMoveHero.setn(CONTINUE_MOVE);
+	}
 }
 
 void CPlayerInterface::heroExchangeStarted(ObjectInstanceID hero1, ObjectInstanceID hero2, QueryID query)
@@ -2624,30 +2644,47 @@ bool CPlayerInterface::capturedAllEvents()
 	return false;
 }
 
-void CPlayerInterface::doMoveHero(const CGHeroInstance* h, CGPath path)
+void CPlayerInterface::doMoveHero(const CGHeroInstance * h, CGPath path)
 {
 	int i = 1;
+	auto getObj = [&](int3 coord, bool ignoreHero = false)
+	{
+		return cb->getTile(CGHeroInstance::convertPosition(coord,false))->topVisitableObj(ignoreHero);
+	};
 
+	boost::unique_lock<boost::mutex> un(stillMoveHero.mx);
+	stillMoveHero.data = CONTINUE_MOVE;
+	auto doMovement = [&](int3 dst, bool transit = false)
 	{
-		path.convert(0);
-		boost::unique_lock<boost::mutex> un(stillMoveHero.mx);
-		stillMoveHero.data = CONTINUE_MOVE;
+		stillMoveHero.data = WAITING_MOVE;
+		cb->moveHero(h, dst, transit);
+		while(stillMoveHero.data != STOP_MOVE && stillMoveHero.data != CONTINUE_MOVE)
+			stillMoveHero.cond.wait(un);
+	};
 
+	{
+		path.convert(0);
 		ETerrainType currentTerrain = ETerrainType::BORDER; // not init yet
 		ETerrainType newTerrain;
 		int sh = -1;
 
-		const TerrainTile * curTile = cb->getTile(CGHeroInstance::convertPosition(h->pos, false));
-
-		for(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); 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)
+			int3 currentCoord = path.nodes[i].coord;
+			int3 nextCoord = path.nodes[i-1].coord;
+
+			auto nextObject = getObj(nextCoord, nextCoord == h->pos);
+			if(CGTeleport::isConnected(getObj(currentCoord, currentCoord == h->pos), nextObject))
+			{
+				CCS->soundh->stopSound(sh);
+				destinationTeleport = nextObject->id;
+				doMovement(h->pos);
+				sh = CCS->soundh->playSound(CCS->soundh->horseSounds[currentTerrain], -1);
 				continue;
+			}
 
-			//stop sending move requests if the next node can't be reached at the current turn (hero exhausted his move points)
 			if(path.nodes[i-1].turns)
-			{
+			{ //stop sending move requests if the next node can't be reached at the current turn (hero exhausted his move points)
 				stillMoveHero.data = STOP_MOVE;
 				break;
 			}
@@ -2655,13 +2692,12 @@ void CPlayerInterface::doMoveHero(const CGHeroInstance* h, CGPath path)
 			// Start a new sound for the hero movement or let the existing one carry on.
 #if 0
 			// TODO
-			if (hero is flying && sh == -1)
+			if(hero is flying && sh == -1)
 				sh = CCS->soundh->playSound(soundBase::horseFlying, -1);
 #endif
 			{
-				newTerrain = cb->getTile(CGHeroInstance::convertPosition(path.nodes[i].coord, false))->terType;
-
-				if (newTerrain != currentTerrain)
+				newTerrain = cb->getTile(CGHeroInstance::convertPosition(currentCoord, false))->terType;
+				if(newTerrain != currentTerrain)
 				{
 					CCS->soundh->stopSound(sh);
 					sh = CCS->soundh->playSound(CCS->soundh->horseSounds[newTerrain], -1);
@@ -2669,19 +2705,22 @@ void CPlayerInterface::doMoveHero(const CGHeroInstance* h, CGPath path)
 				}
 			}
 
-			stillMoveHero.data = WAITING_MOVE;
-
-			int3 endpos(path.nodes[i-1].coord.x, path.nodes[i-1].coord.y, h->pos.z);
-			bool guarded = CGI->mh->map->isInTheMap(cb->getGuardingCreaturePosition(endpos - int3(1, 0, 0)));
-
+			assert(h->pos.z == nextCoord.z); // Z should change only if it's movement via teleporter and in this case this code shouldn't be executed at all
+			int3 endpos(nextCoord.x, nextCoord.y, h->pos.z);
 			logGlobal->traceStream() << "Requesting hero movement to " << endpos;
-			cb->moveHero(h,endpos);
 
-			while(stillMoveHero.data != STOP_MOVE  &&  stillMoveHero.data != CONTINUE_MOVE)
-				stillMoveHero.cond.wait(un);
+			if((i-2 >= 0) // Check there is node after next one; otherwise transit is pointless
+				&& (CGTeleport::isConnected(nextObject, getObj(path.nodes[i-2].coord))
+					|| CGTeleport::isTeleport(nextObject)))
+			{ // Hero should be able to go through object if it's allow transit
+				doMovement(endpos, true);
+			}
+			else
+				doMovement(endpos);
 
 			logGlobal->traceStream() << "Resuming " << __FUNCTION__;
-			if (guarded || showingDialog->get() == true) // Abort movement if a guard was fought or there is a dialog to display (Mantis #1136)
+			bool guarded = cb->isInTheMap(cb->getGuardingCreaturePosition(endpos - int3(1, 0, 0)));
+			if(guarded || showingDialog->get() == true) // Abort movement if a guard was fought or there is a dialog to display (Mantis #1136)
 				break;
 		}
 
@@ -2694,7 +2733,7 @@ void CPlayerInterface::doMoveHero(const CGHeroInstance* h, CGPath path)
 
 
 	//todo: this should be in main thread
-	if (adventureInt)
+	if(adventureInt)
 	{
 		// (i == 0) means hero went through all the path
 		adventureInt->updateMoveHero(h, (i != 0));

+ 1 - 0
client/CPlayerInterface.h

@@ -89,6 +89,7 @@ class CPlayerInterface : public CGameInterface, public ILockedUpdatable
 	const CArmedInstance * currentSelection;
 public:
 	bool observerInDuelMode;
+	ObjectInstanceID destinationTeleport; //contain -1 or object id if teleportation
 
 	//minor interfaces
 	CondSh<bool> *showingDialog; //indicates if dialog box is displayed