fix(rules): load_map rejects any square_size_ft other than 5 (SRD Measuring Distance: one grid square is 5 feet; the engine's 5-10-5 geometry, step costs and ranges are hard-coded to that scale) - a map declaring 10-ft squares was loaded silently and mis-scaled; now a fail-fast MapValidationError, with reject/accept tests
This commit is contained in:
@@ -20,6 +20,12 @@ Pos = tuple[int, int] # (row, col), 0-indexed
|
|||||||
|
|
||||||
_ELEVATION_CHARS = frozenset("0123456789.") # digit = height, '.' = ground level
|
_ELEVATION_CHARS = frozenset("0123456789.") # digit = height, '.' = ground level
|
||||||
|
|
||||||
|
# PF1e (SRD, Measuring Distance): one grid square is 5 feet. The engine's
|
||||||
|
# whole geometry (5-10-5 diagonals, step costs, ranges, auras) is hard-coded
|
||||||
|
# to that scale, so a map declaring any other square size is a data error --
|
||||||
|
# fail fast at load instead of silently mis-scaling.
|
||||||
|
_SQUARE_SIZE_FT = 5
|
||||||
|
|
||||||
_COVER_BONUS_LEVELS = frozenset({0, 2, 4, 8}) # PF1e: none / partial / standard / improved
|
_COVER_BONUS_LEVELS = frozenset({0, 2, 4, 8}) # PF1e: none / partial / standard / improved
|
||||||
|
|
||||||
|
|
||||||
@@ -152,6 +158,14 @@ def load_map(path: Path) -> MapSpec:
|
|||||||
except ValidationError as exc:
|
except ValidationError as exc:
|
||||||
raise MapValidationError(path, str(exc)) from exc
|
raise MapValidationError(path, str(exc)) from exc
|
||||||
|
|
||||||
|
if raw.square_size_ft != _SQUARE_SIZE_FT:
|
||||||
|
msg = (
|
||||||
|
f"square_size_ft must be {_SQUARE_SIZE_FT} (one grid square is 5 "
|
||||||
|
"feet, SRD Measuring Distance); the engine geometry is hard-coded "
|
||||||
|
f"to 5-ft squares, got {raw.square_size_ft}"
|
||||||
|
)
|
||||||
|
raise MapValidationError(path, msg)
|
||||||
|
|
||||||
terrain = _split_rows(raw.terrain, "terrain", path)
|
terrain = _split_rows(raw.terrain, "terrain", path)
|
||||||
height, width = len(terrain), len(terrain[0])
|
height, width = len(terrain), len(terrain[0])
|
||||||
unknown = sorted({ch for row in terrain for ch in row if ch not in raw.legend})
|
unknown = sorted({ch for row in terrain for ch in row if ch not in raw.legend})
|
||||||
|
|||||||
@@ -73,6 +73,20 @@ def test_rejects_ragged_rows(tmp_path: Path) -> None:
|
|||||||
load_map(_write(tmp_path, body))
|
load_map(_write(tmp_path, body))
|
||||||
|
|
||||||
|
|
||||||
|
def test_rejects_non_five_foot_square_size(tmp_path: Path) -> None:
|
||||||
|
"""SRD Measuring Distance: one grid square is 5 ft; the engine geometry
|
||||||
|
is hard-coded to that scale, so any other declared size is a load error
|
||||||
|
(fail fast) rather than a silent mis-scaling."""
|
||||||
|
body = _minimal_map().replace('name: "Test"\n', 'name: "Test"\nsquare_size_ft: 10\n')
|
||||||
|
with pytest.raises(MapValidationError, match="square_size_ft must be 5"):
|
||||||
|
load_map(_write(tmp_path, body))
|
||||||
|
|
||||||
|
|
||||||
|
def test_accepts_explicit_five_foot_square_size(tmp_path: Path) -> None:
|
||||||
|
body = _minimal_map().replace('name: "Test"\n', 'name: "Test"\nsquare_size_ft: 5\n')
|
||||||
|
assert load_map(_write(tmp_path, body)).square_size_ft == 5
|
||||||
|
|
||||||
|
|
||||||
def test_rejects_char_missing_from_legend(tmp_path: Path) -> None:
|
def test_rejects_char_missing_from_legend(tmp_path: Path) -> None:
|
||||||
body = _minimal_map().replace(" #.#\n", " #x#\n")
|
body = _minimal_map().replace(" #.#\n", " #x#\n")
|
||||||
with pytest.raises(MapValidationError):
|
with pytest.raises(MapValidationError):
|
||||||
|
|||||||
Reference in New Issue
Block a user