Support revealing a small area of the map

This commit is contained in:
Atrik 2026-05-01 20:02:33 +02:00
parent 5268cb62a6
commit 4056cb80c9
3 changed files with 89 additions and 0 deletions

View file

@ -2130,6 +2130,88 @@ public:
SeeExploredEntities(p);
}
// Convert world-space circle to tile-space bounds
struct TileCircle
{
i32 centerX, centerZ;
i32 radius;
i32 squaredRadius;
i32 minX, maxX, minZ, maxZ;
};
TileCircle WorldToTileCircle(entity_pos_t worldX, entity_pos_t worldZ, entity_pos_t radius)
{
const i32 centerTileX = (worldX / LOS_TILE_SIZE).ToInt_RoundToNearest();
const i32 centerTileZ = (worldZ / LOS_TILE_SIZE).ToInt_RoundToNearest();
const i32 tileRadius = (radius / LOS_TILE_SIZE).ToInt_RoundToInfinity();
return {
centerTileX,
centerTileZ,
tileRadius,
tileRadius * tileRadius,
std::max(centerTileX - tileRadius, 0),
std::min(centerTileX + tileRadius, m_LosVerticesPerSide - 1),
std::max(centerTileZ - tileRadius, 0),
std::min(centerTileZ + tileRadius, m_LosVerticesPerSide - 1)
};
}
// Apply an action to every tile within the circle
template<typename Func>
void ForEachTileInCircle(const TileCircle& circle, Func&& func)
{
for (i32 tileZ = circle.minZ; tileZ <= circle.maxZ; ++tileZ)
{
const i32 deltaZ = tileZ - circle.centerZ;
const i32 squaredDeltaZ = deltaZ * deltaZ;
for (i32 tileX = circle.minX; tileX <= circle.maxX; ++tileX)
{
if (LosIsOffWorld(tileX, tileZ))
continue;
const i32 deltaX = tileX - circle.centerX;
if (deltaX * deltaX + squaredDeltaZ > circle.squaredRadius)
continue;
func(tileX, tileZ);
}
}
}
void ExploreCircle(player_id_t playerId, entity_pos_t worldX, entity_pos_t worldZ, entity_pos_t radius) override
{
if (playerId <= 0 || playerId > MAX_LOS_PLAYER_ID)
return;
const TileCircle circle = WorldToTileCircle(worldX, worldZ, radius);
const u32 exploredBitMask = static_cast<u32>(LosState::EXPLORED) << (2 * (playerId - 1));
u32& exploredCount = m_ExploredVertices.at(playerId);
bool hasChanges = false;
// Mark newly explored tiles and count them
ForEachTileInCircle(circle, [&](i32 tileX, i32 tileZ)
{
u32& losState = m_LosState.get(tileX, tileZ);
if (!(losState & exploredBitMask))
{
losState |= exploredBitMask;
++exploredCount;
hasChanges = true;
}
});
if (!hasChanges)
return;
// Mark visibility dirty for affected regions
ForEachTileInCircle(circle, [&](i32 tileX, i32 tileZ)
{
MarkVisibilityDirtyAroundTile(playerId, tileX, tileZ);
});
}
/**
* Force any entity in explored territory to appear for player p.
* This is useful for miraging entities inside the territory borders at the beginning of a game,

View file

@ -62,6 +62,7 @@ DEFINE_INTERFACE_METHOD("GetGaiaAndNonGaiaEntities", ICmpRangeManager, GetGaiaAn
DEFINE_INTERFACE_METHOD("SetDebugOverlay", ICmpRangeManager, SetDebugOverlay)
DEFINE_INTERFACE_METHOD("ExploreMap", ICmpRangeManager, ExploreMap)
DEFINE_INTERFACE_METHOD("ExploreTerritories", ICmpRangeManager, ExploreTerritories)
DEFINE_INTERFACE_METHOD("ExploreCircle", ICmpRangeManager, ExploreCircle)
DEFINE_INTERFACE_METHOD("SetLosRevealWholeMap", ICmpRangeManager, SetLosRevealWholeMap)
DEFINE_INTERFACE_METHOD("GetLosRevealWholeMap", ICmpRangeManager, GetLosRevealWholeMap)
DEFINE_INTERFACE_METHOD("SetLosRevealWholeMapForAll", ICmpRangeManager, SetLosRevealWholeMapForAll)

View file

@ -333,6 +333,12 @@ public:
*/
virtual void ExploreTerritories() = 0;
/**
* Explore a circular area of the map for the given player.
* This marks the tiles as explored (fogged) but not necessarily visible.
*/
virtual void ExploreCircle(player_id_t p, entity_pos_t x, entity_pos_t z, entity_pos_t radius) = 0;
/**
* Reveal the shore for specified player p.
* This works like for entities: if RevealShore is called multiple times with enabled, it