Support revealing a small area of the map

This commit is contained in:
Atrik 2026-05-01 20:02:33 +02:00 committed by Dunedan
parent 4125e5b645
commit 839226d542
3 changed files with 80 additions and 0 deletions

View file

@ -277,6 +277,35 @@ struct EntityData
static_assert(sizeof(EntityData) == 24);
// Convert world-space circle to tile-space bounds
struct TileCircle
{
std::int32_t centerX, centerZ;
std::int32_t radius;
std::int32_t squaredRadius;
std::int32_t minX, maxX, minZ, maxZ;
};
// Apply an action to every tile within the circle
template<typename Func>
void ForEachTileInCircle(const TileCircle& circle, Func&& func)
{
for (std::int32_t tileZ = circle.minZ; tileZ <= circle.maxZ; ++tileZ)
{
const std::int32_t deltaZ{tileZ - circle.centerZ};
const std::int32_t squaredDeltaZ{deltaZ * deltaZ};
for (std::int32_t tileX = circle.minX; tileX <= circle.maxX; ++tileX)
{
const std::int32_t deltaX{tileX - circle.centerX};
if (deltaX * deltaX + squaredDeltaZ > circle.squaredRadius)
continue;
func(tileX, tileZ);
}
}
}
/**
* Functor for sorting entities by distance from a source point.
* It must only be passed entities that are in 'entities'
@ -2130,6 +2159,50 @@ public:
SeeExploredEntities(p);
}
TileCircle WorldToTileCircle(entity_pos_t worldX, entity_pos_t worldZ, fixed radius)
{
const std::int32_t centerTileX{(worldX / LOS_TILE_SIZE).ToInt_RoundToNearest()};
const std::int32_t centerTileZ{(worldZ / LOS_TILE_SIZE).ToInt_RoundToNearest()};
const std::int32_t tileRadius{(radius / LOS_TILE_SIZE).ToInt_RoundToInfinity()};
return TileCircle{
.centerX = centerTileX,
.centerZ = centerTileZ,
.radius = tileRadius,
.squaredRadius = tileRadius * tileRadius,
.minX = std::max(centerTileX - tileRadius, 0),
.maxX = std::min(centerTileX + tileRadius, m_LosVerticesPerSide - 1),
.minZ = std::max(centerTileZ - tileRadius, 0),
.maxZ = std::min(centerTileZ + tileRadius, m_LosVerticesPerSide - 1)
};
}
void ExploreCircle(player_id_t playerId, entity_pos_t worldX, entity_pos_t worldZ, fixed 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);
ForEachTileInCircle(circle,
[&](std::int32_t tileX, std::int32_t tileZ)
{
if (LosIsOffWorld(tileX, tileZ))
return;
u32& losState = m_LosState.get(tileX, tileZ);
if (losState & exploredBitMask)
return;
losState |= exploredBitMask;
++exploredCount;
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, fixed radius) = 0;
/**
* Reveal the shore for specified player p.
* This works like for entities: if RevealShore is called multiple times with enabled, it