feat(newgame): the seeded creation pipeline

construct() takes a seed, not a stat block. It rebuilds the RNG and rolls the
attributes itself, so it never trusts a number handed to it (§2) and the same seed
yields an identical character, hidden Luck included (§10). The whole character is
reproducible from four primitives: seed, race_id, calling_id, spend. The rng
parameter is dropped — the seed is now the only source of randomness.

The roll is 3d6 with a hard floor of 8. Straight 3d6 puts ~9% on a primary the +3
pool cannot rescue, and a character bad at the one thing he is FOR is not grit —
it is the fine §7 forbids, paid for twenty hours.

LCK is unspendable, not merely hidden: spending on it is a validation error.
GameState.stats becomes GameState.sheet.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QYa9u7Kdxv5gX4AnwWexy8
This commit is contained in:
2026-07-12 20:43:51 -05:00
parent eba706b906
commit bd49e118d5
5 changed files with 298 additions and 70 deletions

View File

@@ -3,6 +3,12 @@ extends "res://addons/gut/test.gd"
const GameState = preload("res://scripts/state/game_state.gd")
func test_state_holds_a_sheet_not_a_stat_bag():
var gs = GameState.new()
assert_null(gs.sheet, "the sheet is built by NewGame.construct")
assert_false("stats" in gs, "the flat stats Dictionary is gone")
func test_add_item_accumulates():
var s = GameState.new()
s.add_item("worn_shortsword", 3)