diff --git a/src/map.cpp b/src/map.cpp
index 81985be..d79f910 100644
--- a/src/map.cpp
+++ b/src/map.cpp
@@ -495,27 +495,51 @@ TileOwner VoxelWorld::GetTileOwner(uint16 x, uint16 y)
return this->GetStack(x, y)->owner;
}
-/** Map of imploded base ground slope to mask of fence nibbles at the base voxel. */
+/**
+ * At ground level of each voxel stack are 4 fences, one at each edge (ordered as #EDGE_NE .. # EDGE_NW).
+ * Due to slopes, some fences are at the bottom voxel (the base voxel) of the ground level, the other
+ * fences are at the top voxel. The rule for placement is
+ * - Both fences near the top edge of a steep slope are in the top voxel.
+ * - Both fences near the bottom edge of a steep slope are in the bottom voxel.
+ * - Fences on edges of non-steep slopes with both corners raised are in the top voxel.
+ * - Other fences of non-steep slopes are in the bottom voxel.
+ *
+ * Each voxel has the possibility to store 4 fences (one at each edge). In the general case with a
+ * base voxel and a top voxel, there are 8 positions for fences, where 4 of them are used to store
+ * ground level fences. Below is the mask for getting the fences at base voxel level, for each non-top slope.
+ * A \c 0xF nibble means the fence is stored in the base voxel, a \c 0x0 nibble means the fence is stored
+ * in the top voxel. (Top-slopes make no sense to include here, as they only describe the top voxel.)
+ *
+ * To work with the masks, the following functions exist:
+ * - #MergeGroundFencesAtBase sets the given fences for the base voxel.
+ * - #HasTopVoxelFences tells whether the slope has any fences in the top voxel (that is, does it have a top voxel at all?)
+ * - #MergeGroundFencesAtTop sets the given fences for the top voxel.
+ *
+ * The following functions interact with the map.
+ * - #GetGroundFencesFromMap gets the fences at ground level from a voxel stack.
+ * - #AddGroundFencesToMap sets the fences to a voxel stack.
+ *
+ */
static const uint16 _fences_mask_at_base[] = {
- 0xFFFF, // 0
- 0xFFFF, // 1
- 0xFFFF, // 2
- 0xFFF0, // 3
- 0xFFFF, // 4
- 0xFFFF, // 5
- 0xFF0F, // 6
- 0xFF00, // 7
- 0xFFFF, // 8
- 0x0FFF, // 9
- 0xFFFF, // 10
- 0x0FF0, // 11
- 0xF0FF, // 12
- 0x00FF, // 13
- 0xF00F, // 14
- 0x0FF0, // 15 base steep north
- 0xFF00, // 16 base steep east
- 0xF00F, // 17 base steep south
- 0x00FF, // 18 base steep west
+ 0xFFFF, // Imploded ground slope 0
+ 0xFFFF, // Imploded ground slope 1
+ 0xFFFF, // Imploded ground slope 2
+ 0xFFF0, // Imploded ground slope 3
+ 0xFFFF, // Imploded ground slope 4
+ 0xFFFF, // Imploded ground slope 5
+ 0xFF0F, // Imploded ground slope 6
+ 0xFF00, // Imploded ground slope 7
+ 0xFFFF, // Imploded ground slope 8
+ 0x0FFF, // Imploded ground slope 9
+ 0xFFFF, // Imploded ground slope 10
+ 0x0FF0, // Imploded ground slope 11
+ 0xF0FF, // Imploded ground slope 12
+ 0x00FF, // Imploded ground slope 13
+ 0xF00F, // Imploded ground slope 14
+ 0x0FF0, // Imploded ground slope 15 (base steep north)
+ 0xFF00, // Imploded ground slope 16 (base steep east)
+ 0xF00F, // Imploded ground slope 17 (base steep south)
+ 0x00FF, // Imploded ground slope 18 (base steep west)
};
/**
@@ -529,8 +553,8 @@ uint16 MergeGroundFencesAtBase(uint16 vxbase_fences, uint16 fences, uint8 base_t
{
assert(base_tile_slope < lengthof(_fences_mask_at_base)); // Top steep slopes are not allowed.
uint16 mask = _fences_mask_at_base[base_tile_slope];
- fences &= mask;
- mask ^= 0xFFFF;
+ fences &= mask; // Kill any fence not in the base voxel.
+ mask ^= 0xFFFF; // Swap mask to keep only non-fences of the current voxel data.
return (vxbase_fences & mask) | fences;
}
@@ -556,8 +580,8 @@ uint16 MergeGroundFencesAtTop(uint16 vxtop_fences, uint16 fences, uint8 base_til
{
assert(base_tile_slope < lengthof(_fences_mask_at_base)); // Top steep slopes are not allowed.
uint16 mask = _fences_mask_at_base[base_tile_slope];
- vxtop_fences &= mask;
- mask ^= 0xFFFF;
+ vxtop_fences &= mask; // Keep fences of top voxel that are at ground level in the base voxel.
+ mask ^= 0xFFFF; // Swap mask to keep fences that belong in the top voxel.
return (fences & mask) | vxtop_fences;
}
@@ -592,12 +616,12 @@ uint16 GetGroundFencesFromMap(const VoxelStack *stack, int base_z)
assert(slope < lengthof(_fences_mask_at_base)); // Top steep slopes are not allowed.
uint16 mask = _fences_mask_at_base[slope];
- uint16 fences = v->GetFences() & mask;
+ uint16 fences = v->GetFences() & mask; // Get ground level fences of the base voxel.
if (HasTopVoxelFences(slope)) {
v = stack->Get(base_z + 1);
uint top_fences = (v != nullptr) ? v->GetFences() : ALL_INVALID_FENCES;
- mask ^= 0xFFFF;
- fences |= top_fences & mask;
+ mask ^= 0xFFFF; // Swap all bits to top voxel mask.
+ fences |= top_fences & mask; // Add fences of the top voxel.
}
return fences;
}