Files
Battle-for-Tismo/scripts/classes/terrain_stats.gd
T
adrien c49899a2fd Initial commit
Server-authoritative Godot 4.6 strategy game.

Includes the headless WebSocket game server, the browser client, and
Nix packaging (server and web-export derivations plus a NixOS module)
for deployment.
2026-09-15 14:48:34 +02:00

90 lines
3.1 KiB
GDScript

class_name TerrainStats
extends RefCounted
## Reads the per-terrain-type figures authored on the terrain TileSet's custom
## data layers. The tile types themselves (and their Land/Sea classification)
## still live in the TileSet; this class only looks the numbers up.
##
## Three layers are recognised:
## population_multiplier (float) scales the tile's base population
## gdp_multiplier (float) scales the tile's base GDP per capita
## movement_cost_multiplier (float) multiplier applied to a unit's travel time
##
## A value of 0 (the default for an unfilled layer) means "not authored". The
## callers pick the fallback in that case, so the game keeps running while the
## layers are being filled in.
const POPULATION_MULTIPLIER_LAYER := "population_multiplier"
const GDP_MULTIPLIER_LAYER := "gdp_multiplier"
const MOVEMENT_COST_MULTIPLIER_LAYER := "movement_cost_multiplier"
## Travel-time multiplier used for tiles with no authored movement cost.
const DEFAULT_MOVEMENT_COST_MULTIPLIER := 1.0
var _layer: TileMapLayer
var _tiles: Dictionary = {}
var _use_tiles: bool = false
func _init(layer: TileMapLayer) -> void:
_layer = layer
## Builds a stats reader from generated tile dictionaries (coords -> tile data)
## instead of a live TileMapLayer. This keeps the simulation independent of the
## scene tree.
static func from_tiles(tiles: Dictionary) -> TerrainStats:
var stats := TerrainStats.new(null)
stats._tiles = tiles
stats._use_tiles = true
return stats
## Authored population multiplier, or 0.0 when the layer is empty.
func population_multiplier(coords: Vector2i) -> float:
return float(_value(coords, POPULATION_MULTIPLIER_LAYER))
## Authored GDP multiplier, or 0.0 when the layer is empty.
func gdp_multiplier(coords: Vector2i) -> float:
return float(_value(coords, GDP_MULTIPLIER_LAYER))
## Travel-time multiplier for the tile. Unset or non-positive values fall back
## to a normal cost so a unit is never frozen.
func movement_cost_multiplier(coords: Vector2i) -> float:
var value := float(_value(coords, MOVEMENT_COST_MULTIPLIER_LAYER))
return value if value > 0.0 else DEFAULT_MOVEMENT_COST_MULTIPLIER
## Cheapest authored movement cost across every tile in use. The A* heuristic
## uses it so it never overestimates the cost of a path that runs over a
## terrain that is faster than normal.
func min_movement_cost_multiplier() -> float:
var cells: Array = _tiles.keys() if _use_tiles else (
_layer.get_used_cells() if _layer != null else []
)
if cells.is_empty():
return DEFAULT_MOVEMENT_COST_MULTIPLIER
var cheapest := INF
for coords in cells:
cheapest = minf(cheapest, movement_cost_multiplier(coords))
return cheapest if cheapest < INF else DEFAULT_MOVEMENT_COST_MULTIPLIER
func _value(coords: Vector2i, layer_name: String) -> Variant:
if _use_tiles:
var tile: Dictionary = _tiles.get(coords, {})
return tile.get(layer_name, 0)
var data := _tile_data(coords)
if data == null:
return 0
return data.get_custom_data(layer_name)
func _tile_data(coords: Vector2i) -> TileData:
if _layer == null:
return null
return _layer.get_cell_tile_data(coords)