Jelajahi Sumber

Working version of SoD dimension door spell

Dydzio 1 tahun lalu
induk
melakukan
982e67cea8

+ 19 - 12
client/adventureMap/AdventureMapInterface.cpp

@@ -506,14 +506,14 @@ void AdventureMapInterface::onTileLeftClicked(const int3 &mapPos)
 	if(!shortcuts->optionMapViewActive())
 		return;
 
-	//FIXME: this line breaks H3 behavior for Dimension Door
 	if(!LOCPLINT->cb->isVisible(mapPos))
-		return;
+    {
+        if(!spellBeingCasted || spellBeingCasted->id != SpellID::DIMENSION_DOOR)
+		    return;
+    }
 	if(!LOCPLINT->makingTurn)
 		return;
 
-	const TerrainTile *tile = LOCPLINT->cb->getTile(mapPos);
-
 	const CGObjectInstance *topBlocking = getActiveObject(mapPos);
 
 	int3 selPos = LOCPLINT->localState->getCurrentArmy()->getSightCenter();
@@ -533,7 +533,8 @@ void AdventureMapInterface::onTileLeftClicked(const int3 &mapPos)
 				performSpellcasting(mapPos);
 			break;
 		case SpellID::DIMENSION_DOOR:
-			if(!tile || tile->isClear(heroTile))
+            const TerrainTile *targetTile = LOCPLINT->cb->getTileForDimensionDoor(mapPos, LOCPLINT->localState->getCurrentHero());
+			if(targetTile && targetTile->isClear(heroTile))
 				performSpellcasting(mapPos);
 			break;
 		}
@@ -614,12 +615,18 @@ void AdventureMapInterface::onTileHovered(const int3 &mapPos)
 
 	if(!LOCPLINT->cb->isVisible(mapPos))
 	{
-		CCS->curh->set(Cursor::Map::POINTER);
-		GH.statusbar()->clear();
-		return;
+        GH.statusbar()->clear();
+
+        if(!spellBeingCasted || spellBeingCasted->id != SpellID::DIMENSION_DOOR)
+        {
+            CCS->curh->set(Cursor::Map::POINTER);
+            return;
+        }
 	}
+
 	auto objRelations = PlayerRelations::ALLIES;
-	const CGObjectInstance *objAtTile = getActiveObject(mapPos);
+
+	const CGObjectInstance *objAtTile = LOCPLINT->cb->isVisible(mapPos) ? getActiveObject(mapPos) : nullptr;
 	if(objAtTile)
 	{
 		objRelations = LOCPLINT->cb->getPlayerRelations(LOCPLINT->playerID, objAtTile->tempOwner);
@@ -649,9 +656,9 @@ void AdventureMapInterface::onTileHovered(const int3 &mapPos)
 			}
 		case SpellID::DIMENSION_DOOR:
 			{
-				const TerrainTile * t = LOCPLINT->cb->getTile(mapPos, false);
-				int3 hpos = LOCPLINT->localState->getCurrentArmy()->getSightCenter();
-				if((!t || t->isClear(LOCPLINT->cb->getTile(hpos))) && isInScreenRange(hpos, mapPos))
+				const TerrainTile * t = LOCPLINT->cb->getTileForDimensionDoor(mapPos, LOCPLINT->localState->getCurrentHero());
+				int3 heroPosition = LOCPLINT->localState->getCurrentArmy()->getSightCenter();
+				if(t && t->isClear(LOCPLINT->cb->getTile(heroPosition))/* && isInScreenRange(hpos, mapPos)*/)
 					CCS->curh->set(Cursor::Map::TELEPORT);
 				else
 					CCS->curh->set(Cursor::Map::POINTER);

+ 28 - 1
lib/CGameInfoCallback.cpp

@@ -500,7 +500,7 @@ std::vector<const CGHeroInstance *> CGameInfoCallback::getAvailableHeroes(const
 	return ret;
 }
 
-const TerrainTile * CGameInfoCallback::getTile( int3 tile, bool verbose) const
+const TerrainTile * CGameInfoCallback::getTile(int3 tile, bool verbose) const
 {
 	if(isVisible(tile))
 		return &gs->map->getTile(tile);
@@ -510,6 +510,33 @@ const TerrainTile * CGameInfoCallback::getTile( int3 tile, bool verbose) const
 	return nullptr;
 }
 
+const TerrainTile * CGameInfoCallback::getTileForDimensionDoor(int3 tile, const CGHeroInstance * castingHero) const
+{
+    auto outputTile = getTile(tile, false);
+
+    if(outputTile == nullptr)
+    {
+        if(castingHero->canCastThisSpell(static_cast<SpellID>(SpellID::DIMENSION_DOOR).toSpell())
+            && isInScreenRange(castingHero->pos, tile)) //TODO: check if > 0 casts left
+        {
+            //we are allowed to get basic blocked/water invisible nearby tile date when casting DD spell
+            TerrainTile targetTile = gs->map->getTile(tile);
+            auto obfuscatedTile = std::make_shared<TerrainTile>();
+            obfuscatedTile->visitable = false;
+            obfuscatedTile->blocked = targetTile.blocked || targetTile.visitable;
+            obfuscatedTile->terType = (targetTile.blocked || targetTile.visitable)
+                ? VLC->terrainTypeHandler->getById(TerrainId::ROCK)
+                : targetTile.isWater()
+                    ? VLC->terrainTypeHandler->getById(TerrainId::WATER)
+                    : VLC->terrainTypeHandler->getById(TerrainId::GRASS);
+
+            outputTile = obfuscatedTile.get();
+        }
+    }
+
+    return outputTile;
+}
+
 EDiggingStatus CGameInfoCallback::getTileDigStatus(int3 tile, bool verbose) const
 {
 	if(!isVisible(tile))

+ 1 - 0
lib/CGameInfoCallback.h

@@ -196,6 +196,7 @@ public:
 	virtual const CMapHeader * getMapHeader()const;
 	virtual int3 getMapSize() const; //returns size of map - z is 1 for one - level map and 2 for two level map
 	virtual const TerrainTile * getTile(int3 tile, bool verbose = true) const;
+    virtual const TerrainTile * getTileForDimensionDoor(int3 tile, const CGHeroInstance * castingHero) const;
 	virtual std::shared_ptr<const boost::multi_array<TerrainTile*, 3>> getAllVisibleTiles() const;
 	virtual bool isInTheMap(const int3 &pos) const;
 	virtual void getVisibleTilesInRange(std::unordered_set<int3> &tiles, int3 pos, int radious, int3::EDistanceFormula distanceFormula = int3::DIST_2D) const;