When attacking a defender in the Ethereal (alt) layer, the client's combat preview computes damage with the surface biome at the target's coordinates, while the contract resolves the battle biome as Underground (neutral). With the standard ±30% biome bonus, previewed damage can be off by up to 30% per side.
Where it diverges
- Contract: battle biome is resolved from the defender's tile including
alt — contracts/game/src/system_libraries/combat_library.cairo:79-85. Any tile with alt = true is Biome::Underground (id 17), neutral for all three troop types — contracts/game/src/utils/map/biomes.cairo:253-256.
- Client:
client/apps/game/src/ui/features/military/battle/quick-attack-preview.tsx:149 computes the biome with configManager.getBiome(target.hex.x, target.hex.y), which only knows surface procgen. target.alt is available in the same component (line 146, used for tile fetching) but doesn't feed into the biome.
Example: attacking a bitcoin mine's Paladin guards on a coordinate whose surface biome is Grassland previews the guards at +30%, while on chain they fight at 1.0.
Why it's silent
BiomeType (packages/types/src/constants/hex.ts:20-38) has no Underground, so BiomeIdToType[17] is undefined and the tile stream falls back to Grassland (packages/core/src/systems/world-update-listener.ts:820-827). getBiomeCombatBonus returns 1.0 for unknown biomes (packages/core/src/managers/config-manager.ts:456), which happens to match Underground's neutral value — so nothing crashes; the wrong number comes from the preview computing a surface biome, not from the lookup.
Scope
- Reachable in Eternum (spires enabled, 2% bitcoin mine discovery on exploration) — this is the "Army Spire Traversal" flow. Not reachable in Blitz (
spires_max_count: 0, mine probability 0).
Underground entered the contracts in e366cf0 (Jan 2026, ES2 alternate map) without a matching TS change; I found no TODO or existing issue about it, hence this one.
- Two things I couldn't verify: whether the travel-stamina path preview is also affected in practice (underground tiles carry the Grassland fallback into
army-action-manager's cost lookup, but I didn't trace the ethereal-layer movement UI end to end), and whether spires are actually settled in the current live season.
Question
Is the surface-only biome in the preview intentional, or should it resolve through alt? Happy to open a small PR if you want it fixed — roughly: add Underground to BiomeType + the id-17 mapping, neutral rows in the two config-manager tables, and resolve the preview biome to Underground when the defender is in the alt layer.
When attacking a defender in the Ethereal (alt) layer, the client's combat preview computes damage with the surface biome at the target's coordinates, while the contract resolves the battle biome as
Underground(neutral). With the standard ±30% biome bonus, previewed damage can be off by up to 30% per side.Where it diverges
alt—contracts/game/src/system_libraries/combat_library.cairo:79-85. Any tile withalt = trueisBiome::Underground(id 17), neutral for all three troop types —contracts/game/src/utils/map/biomes.cairo:253-256.client/apps/game/src/ui/features/military/battle/quick-attack-preview.tsx:149computes the biome withconfigManager.getBiome(target.hex.x, target.hex.y), which only knows surface procgen.target.altis available in the same component (line 146, used for tile fetching) but doesn't feed into the biome.Example: attacking a bitcoin mine's Paladin guards on a coordinate whose surface biome is Grassland previews the guards at +30%, while on chain they fight at 1.0.
Why it's silent
BiomeType(packages/types/src/constants/hex.ts:20-38) has noUnderground, soBiomeIdToType[17]isundefinedand the tile stream falls back to Grassland (packages/core/src/systems/world-update-listener.ts:820-827).getBiomeCombatBonusreturns 1.0 for unknown biomes (packages/core/src/managers/config-manager.ts:456), which happens to match Underground's neutral value — so nothing crashes; the wrong number comes from the preview computing a surface biome, not from the lookup.Scope
spires_max_count: 0, mine probability 0).Undergroundentered the contracts in e366cf0 (Jan 2026, ES2 alternate map) without a matching TS change; I found no TODO or existing issue about it, hence this one.army-action-manager's cost lookup, but I didn't trace the ethereal-layer movement UI end to end), and whether spires are actually settled in the current live season.Question
Is the surface-only biome in the preview intentional, or should it resolve through
alt? Happy to open a small PR if you want it fixed — roughly: addUndergroundtoBiomeType+ the id-17 mapping, neutral rows in the two config-manager tables, and resolve the preview biome to Underground when the defender is in the alt layer.