Browse Source

Clicking on blocked tile of a visitable object now builds a path to it

Suggestion from Discord.

If player has hero selected, clicking on a blocked tile of a visitable,
reachable object will now build a path to its visitable position (or
move hero to it, in case of second click / tap).

Objects that have interaction on left click (allied town and shipyards)
are excluded from this change and work as before
Ivan Savenko 8 months ago
parent
commit
7803f7a972

+ 36 - 38
client/adventureMap/AdventureMapInterface.cpp

@@ -531,7 +531,6 @@ void AdventureMapInterface::onTileLeftClicked(const int3 &targetPosition)
 	bool canSelect = topBlocking && topBlocking->ID == Obj::HERO && topBlocking->tempOwner == LOCPLINT->playerID;
 	canSelect |= topBlocking && topBlocking->ID == Obj::TOWN && LOCPLINT->cb->getPlayerRelations(LOCPLINT->playerID, topBlocking->tempOwner) != PlayerRelations::ENEMIES;
 
-	bool isHero = false;
 	if(LOCPLINT->localState->getCurrentArmy()->ID != Obj::HERO) //hero is not selected (presumably town)
 	{
 		if(LOCPLINT->localState->getCurrentArmy() == topBlocking) //selected town clicked
@@ -541,9 +540,10 @@ void AdventureMapInterface::onTileLeftClicked(const int3 &targetPosition)
 	}
 	else if(const CGHeroInstance * currentHero = LOCPLINT->localState->getCurrentHero()) //hero is selected
 	{
-		isHero = true;
-
 		const CGPathNode *pn = LOCPLINT->getPathsInfo(currentHero)->getPathInfo(targetPosition);
+
+		const auto shipyard = dynamic_cast<const IShipyard *>(topBlocking);
+
 		if(currentHero == topBlocking) //clicked selected hero
 		{
 			LOCPLINT->openHeroWindow(currentHero);
@@ -554,10 +554,19 @@ void AdventureMapInterface::onTileLeftClicked(const int3 &targetPosition)
 			LOCPLINT->localState->setSelection(static_cast<const CArmedInstance*>(topBlocking));
 			return;
 		}
+		else if(shipyard != nullptr && pn->turns == 255 && LOCPLINT->cb->getPlayerRelations(LOCPLINT->playerID, topBlocking->tempOwner) != PlayerRelations::ENEMIES)
+		{
+			LOCPLINT->showShipyardDialogOrProblemPopup(shipyard);
+		}
 		else //still here? we need to move hero if we clicked end of already selected path or calculate a new path otherwise
 		{
+			int3 destinationTile = targetPosition;
+
+			if(topBlocking && topBlocking->isVisitable() && !topBlocking->visitableAt(destinationTile) && settings["gameTweaks"]["simpleObjectSelection"].Bool())
+				destinationTile = topBlocking->visitablePos();
+
 			if(LOCPLINT->localState->hasPath(currentHero) &&
-			   LOCPLINT->localState->getPath(currentHero).endPos() == targetPosition &&
+			   LOCPLINT->localState->getPath(currentHero).endPos() == destinationTile &&
 			   !GH.isKeyboardShiftDown())//we'll be moving
 			{
 				assert(!CGI->mh->hasOngoingAnimations());
@@ -574,7 +583,7 @@ void AdventureMapInterface::onTileLeftClicked(const int3 &targetPosition)
 				}
 				else //remove old path and find a new one if we clicked on accessible tile
 				{
-					LOCPLINT->localState->setPath(currentHero, targetPosition);
+					LOCPLINT->localState->setPath(currentHero, destinationTile);
 					onHeroChanged(currentHero);
 				}
 			}
@@ -584,12 +593,6 @@ void AdventureMapInterface::onTileLeftClicked(const int3 &targetPosition)
 	{
 		throw std::runtime_error("Nothing is selected...");
 	}
-
-	const auto shipyard = ourInaccessibleShipyard(topBlocking);
-	if(isHero && shipyard != nullptr)
-	{
-		LOCPLINT->showShipyardDialogOrProblemPopup(shipyard);
-	}
 }
 
 void AdventureMapInterface::onTileHovered(const int3 &targetPosition)
@@ -690,6 +693,28 @@ void AdventureMapInterface::onTileHovered(const int3 &targetPosition)
 			showMoveDetailsInStatusbar(*hero, *pathNode);
 		}
 
+		if (objAtTile && pathNode->action == EPathNodeAction::UNKNOWN)
+		{
+			if(objAtTile->ID == Obj::TOWN && objRelations != PlayerRelations::ENEMIES)
+			{
+				CCS->curh->set(Cursor::Map::TOWN);
+				return;
+			}
+			else if(objAtTile->ID == Obj::HERO && objRelations == PlayerRelations::SAME_PLAYER)
+			{
+				CCS->curh->set(Cursor::Map::HERO);
+				return;
+			}
+			else if (objAtTile->ID == Obj::SHIPYARD && objRelations != PlayerRelations::ENEMIES)
+			{
+				CCS->curh->set(Cursor::Map::T1_SAIL);
+				return;
+			}
+
+			if(objAtTile->isVisitable() && !objAtTile->visitableAt(targetPosition) && settings["gameTweaks"]["simpleObjectSelection"].Bool())
+				pathNode = LOCPLINT->getPathsInfo(hero)->getPathInfo(objAtTile->visitablePos());
+		}
+
 		int turns = pathNode->turns;
 		vstd::amin(turns, 3);
 		switch(pathNode->action)
@@ -741,25 +766,10 @@ void AdventureMapInterface::onTileHovered(const int3 &targetPosition)
 			break;
 
 		default:
-			if(objAtTile && objRelations != PlayerRelations::ENEMIES)
-			{
-				if(objAtTile->ID == Obj::TOWN)
-					CCS->curh->set(Cursor::Map::TOWN);
-				else if(objAtTile->ID == Obj::HERO && objRelations == PlayerRelations::SAME_PLAYER)
-					CCS->curh->set(Cursor::Map::HERO);
-				else
-					CCS->curh->set(Cursor::Map::POINTER);
-			}
-			else
 				CCS->curh->set(Cursor::Map::POINTER);
 			break;
 		}
 	}
-
-	if(ourInaccessibleShipyard(objAtTile))
-	{
-		CCS->curh->set(Cursor::Map::T1_SAIL);
-	}
 }
 
 void AdventureMapInterface::showMoveDetailsInStatusbar(const CGHeroInstance & hero, const CGPathNode & pathNode)
@@ -848,18 +858,6 @@ Rect AdventureMapInterface::terrainAreaPixels() const
 	return widget->getMapView()->pos;
 }
 
-const IShipyard * AdventureMapInterface::ourInaccessibleShipyard(const CGObjectInstance *obj) const
-{
-	const auto *ret = dynamic_cast<const IShipyard *>(obj);
-
-	if(!ret ||
-		obj->tempOwner != currentPlayerID ||
-		(CCS->curh->get<Cursor::Map>() != Cursor::Map::T1_SAIL && CCS->curh->get<Cursor::Map>() != Cursor::Map::POINTER))
-		return nullptr;
-
-	return ret;
-}
-
 void AdventureMapInterface::hotkeyExitWorldView()
 {
 	setState(EAdventureState::MAKING_TURN);

+ 0 - 3
client/adventureMap/AdventureMapInterface.h

@@ -75,9 +75,6 @@ private:
 	/// updates active state of game window whenever game state changes
 	void adjustActiveness();
 
-	/// checks if obj is our ashipyard and cursor is 0,0 -> returns shipyard or nullptr else
-	const IShipyard * ourInaccessibleShipyard(const CGObjectInstance *obj) const;
-
 	/// check and if necessary reacts on scrolling by moving cursor to screen edge
 	void handleMapScrollingUpdate(uint32_t msPassed);
 

+ 5 - 0
config/schemas/settings.json

@@ -719,6 +719,7 @@
 				"skipBattleIntroMusic",
 				"infoBarCreatureManagement",
 				"enableLargeSpellbook",
+				"simpleObjectSelection",
 				"skipAdventureMapAnimations"
 			],
 			"properties" : {
@@ -758,6 +759,10 @@
 					"type": "boolean",
 					"default": true
 				},
+				"simpleObjectSelection" : {
+					"type": "boolean",
+					"default": true
+				},
 				"skipAdventureMapAnimations": {
 					"type": "boolean",
 					"default": false