Commit graph

13 commits

Author SHA1 Message Date
f30c7a858b reskin wolf as hyena — visual + lean-in flavor
Replaces the procedural brown-rectangle "wolf" with the CraftPix Free
Desert Enemy Sprite Sheets hyena. 48×48, side-view, 2-direction via
horizontal flip. AnimatedSprite2D mounted in Wolf.setup() and
Wolf.from_dict() (same pattern as pawn reskin Slice 1). Anims: idle
(4f @ 5fps) + walk (6f @ 10fps). Attack/hurt/death anims skipped for
MVP scope.

Player-facing copy renamed wolf→hyena in strings.gd (6 entries) and
event_catalog.gd (3 EventDef title/body fields). Internal identifiers
(class Wolf, World.wolves, EventBus.wolf_spawned, save class_id
&"wolf", event IDs like &"lone_wolf") stay the same for save compat
— see header comment in wolf.gd.

MCP runtime verified: hyena AnimatedSprite2D mounted on spawn, idle
anim plays, storyteller modal renders "Lone Hyena — A starving hyena
circles your livestock."

Sprites: CraftPix Free Desert Enemy Sprite Sheets.
License: CraftPix Free (commercial OK, attribution appreciated).
https://free-game-assets.itch.io/free-enemy-sprite-sheets-pixel-art

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-16 21:03:46 +01:00
5a6ec53b12 Tree growth: dedicated stage atlas + tuned WildGrowth rate
Sub-mature stages (0/1/2) now use FG_Tree_Stages.png (a 128×32 atlas
with 8 progressively-larger tree cells from the bundle's "Crops with
Stages 03" pack). Stage 0 = tiny sprout (col 0), Stage 1 = small
leaf (col 1), Stage 2 = small tree (col 3). Stage 3 (Mature) keeps
the existing 64×80 seasonal canopy atlases.

Visually distinct progression replaces the previous scale-down-the-
mature-texture placeholder + procedural sapling dots.

WildGrowth pacing tuned: INTERVAL 1200 → 3000, PROBABILITY 0.30 →
0.12, LIMIT 60 → 80. Previous values flooded the map with saplings
within ~30 seconds of 12× play. New rate gives a slow but visible
regrowth over a season at default speed.

_draw simplified: removed procedural sapling fallback (atlas handles
all stages now). Pending-plant ghosts get the alpha tint via
sprite.modulate.
2026-05-16 16:42:38 +01:00
b4c9541eae Pawn reskin Slice 1 — peasant sprites replace coloured disc
Pawns now render as AnimatedSprite2D children sourced from ElvGames
"Farming Characters Pack" atlases (Pack 1, characters 001-015). Each
pawn picks one of 15 peasants deterministically from name hash:
Bram=004, Cora=013, Edda=001.

Animations: idle_down/left/right/up + walk_down/left/right/up (4 fps
idle, 8 fps walk, looped) + dead (single frame, no loop). Pawn picks
animation each _process tick from (is_downed, is_walking, facing).
Facing is now a Vector2i field updated in _advance_walk; round-trips
through save/load.

Sprite mounting is deferred from _ready() to setup() / from_dict()
because the atlas pick depends on pawn_name, which isn't assigned at
_ready time.  _mount_sprite() is idempotent for the save-load chain.

_atlas_for_pawn(pawn) is the single Slice-2 extension point —
swapping atlases based on equipped armor in a future sprint is a
one-function change.

_draw() stripped of body disc + downed-rotation; now overlay-only
(selection ring + carry indicator). AnimatedSprite2D child uses
z_index=-1 so the overlays stay on top.

45 PNGs copied into art/sprites/characters/ + 45 .import companions.
2026-05-16 15:23:18 +01:00
c97ada80d7 Procedural workbench redraws + 3-season tree variety
Workbenches: replace atlas sprites (which read as chest-of-drawers,
candle base, kitchen stove, cushion stack) with procedural _draw_ methods
following CremationPyre._draw_pyre's pattern. Carpenter shows a wood bench
with saw + log slabs; Smelter a stone furnace with smoking chimney; Hearth
a tall h=2 stone fireplace with arched opening + log fire; Millstone a
wood frame supporting a round grindstone wheel.

Trees: add Summer + Fall atlases alongside Spring (12 visual variants
from 4 silhouettes × 3 seasons). Selection hash mixes season independently
so neighbouring tiles don't all share the same palette.
2026-05-15 20:22:55 +01:00
c93f889ff1 Crop sprites — atlas art + four growable kinds
Replaces the procedural stem-and-circle draw with an ElvGames atlas-backed
Sprite2D. Crops now pick a per-kind 64×32 (or 80×32) sheet from
art/sprites/crops/ and slice cols 0..3 across the SOWN..READY stage range
(TILLED keeps the bare dirt rect). The plant sprite is anchored so its
bottom edge sits at the tile bottom, matching the tree convention.

Four kinds wired in: wheat, potato, corn, strawberry. The boot demo's
crop patch now plants one column per kind so all four show up in the
spring start state. Harvest outputs map: wheat/corn → grain,
potato/strawberry → vegetable.

Tooltip already capitalises crop_kind so 'Corn' / 'Strawberry' show
through with no UI change.
2026-05-15 19:39:57 +01:00
745ab29c51 Door sprite — swap castle gate for 1-tile FG_Village cabin door
The previous 32×32 FG_Fortress arched gate at (4,19) was rejected as 'a
door for a entrance to a castle' — too imposing for a cabin's front door.

Pivot: FG_Village atlas (3, 24) — a single 16×16 olive-wood plank door
with a white U-handle, extracted from the red-roofed cottage template.
Sprite occupies one tile (no overhang, no rising lintel), bottom-anchored
the same as Wall so Y-sort layers pawns correctly.

Verified in MCP play_scene: the door slots cleanly into the demo cabin's
south-wall gap at (47, 28), matching the surrounding stone-brick wall
height. Ghost-alpha pipeline (0.4 in-build → 1.0 on _complete) intact.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 16:11:05 +01:00
7274ada5d1 Item sprites — swap procedural draw for tileset icons
Stone, iron ore, gold, wood, plank now render as ElvGames FG_Abandoned_Mines
sprites instead of hue-hashed coloured squares. Other types fall back to the
procedural square; quality border + stack count badge are layered on top of
whichever base renders.

Atlas coords picked from /tmp/item_finals.png + /tmp/wood_plank_alts.png:
  stone     (5, 33)   rock cluster with stone chunks
  iron_ore  (9, 33)   rock with silver chunks
  gold      (13, 33)  rock with gold chunks
  wood      (20, 13)  chunky brown log pile
  plank     (28, 18)  horizontal-grain plank stack

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 15:43:24 +01:00
c4f94fb543 Workbench sprites — swap procedural draw for tileset art per variant
- Carpenter → FG_Interior (24, 20) 16×32 wood cabinet w/ drawers
- Smelter   → FG_Marketplace (8, 30) anvil + hot metal
- Hearth    → FG_Interior (16, 32) stove w/ burners
- Millstone → FG_Interior (17, 40) wood barrel + procedural wheel overlay

Adds label_text setter so the sprite rebuilds idempotently whether the
caller assigns label before or after setup() (world.gd assigns after,
SaveSystem after). Setter also calls _maybe_build_light() to fix a
pre-existing Phase 11 bug where Hearth never built its PointLight2D
(label_text was still default when _ready fired).

Unrecognised label_texts fall through to _draw_generic so ad-hoc
workbench variants keep rendering.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 15:23:28 +01:00
2396528034 Bed: replace procedural draw with 1×2 vertical bundle sprite
The procedural 3/4-perspective bed (16×16 box of stacked draw_rect calls)
gets replaced with a 16×32 single-column Sprite2D cropped from the ElvGames
House Interior tileset. The sprite spans the bed's tile plus the tile
immediately south — head with rounded pillow + frame in the bed tile, body
and wood foot rail in the foot tile. The foot tile stays walkable in the
pathfinder (Phase-4 simplification, matches small rocks).

Three variants chosen deterministically by tile hash so the same bed renders
the same colour across boots and saves:
  • (32, 22) brown wood frame
  • (35, 22) blue quilt
  • (38, 22) pink quilt
Crops are LEFT-edge columns of the 2-/3-wide bundle beds — visually verified
in /tmp/bed_candidates.png against MIDDLE/RIGHT alternatives. LEFT shows the
clearest pillow shape + visible wood frame in a single column.

Setup work (sprite, position, y-sort) now lives inside setup() not _ready()
because _ready fires inside add_child() before the caller passes in the real
tile — same lesson as BigRock. _build_sprite() is idempotent (drops the
previous Sprite child) so the save-load flow (factory.setup → factory
on_build_tick → from_dict.setup) re-creates the sprite without leaks.

_draw() now renders only the medical-cross overlay when is_medical is true
— sprite handles ghost alpha via modulate. _complete() solidifies the sprite
from 0.4 to 1.0 alpha. The quality-tinted procedural sheets are dropped;
quality still drives sleep mood, just not visual colour.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 14:49:05 +01:00
2de5130ae0 Visual pass 2: tree + rock + stone wall sprite swaps
Replaces three procedural _draw() entities with bundle sprites:

- Tree: was draw_rect trunk + draw_circle canopy. Now Sprite2D using
  FG_Tree_Spring.png (64x80, 4 variants picked deterministically from
  tile coord). Bottom-anchored so trunk base sits at tile bottom, canopy
  rises into the cell above; y_sort_enabled so canopies tuck behind
  pawns south of the trunk. Chop-progress notch overlay retained.
- Rock: was draw_colored_polygon hex. Now Sprite2D reading from the
  existing FG_Grasslands_Spring.png decoration atlas at three eyeballed
  coords (2 gray boulders, 1 brown rock pile). Variant deterministic
  per tile. Mine-progress crack overlay retained.
- Stone wall: was procedural top-band + front-band + mortar lines. Now
  Sprite2D from FG_Fortress.png at (1,1) — clean tan-stone brick fill.
  Bottom-anchored (offset.y=-8) so the 16x16 sprite spans y=-16..0,
  matching the procedural draw box exactly. Ghost state via modulate.a.
  Wood walls still use procedural _draw_wood_wall — no clean 16x16 wood
  tile found in the bundle yet (Pixel Crawler Walls.png is 32x32, would
  need crop+rescale).

Asset additions:
- art/sprites/FG_Tree_Spring.png (Tier 1, Grasslands pack)
- FG_Fortress.png and FG_Grasslands_Spring.png were already in art/tiles
  from earlier passes; this commit just consumes them from new sites.

Headless boots clean, runtime verified: trees look like chunky pixel-art
trees with root flare, rocks read as real boulders, cabin walls show
proper brick texture.

License: all ElvGames Humble bundle — commercial OK with credit.
Credit-string compilation still open.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 14:19:06 +01:00
314c7a70b4 Visual: sprinkle grass+flower decoration overlay (ElvGames bundle)
First visual pass: replaces nothing, adds a decoration TileMapLayer above
Terrain that paints ~8% of cells with random overlay sprites pulled from
FG_Grasslands_Spring.png. Mix of 3 grass-sprout variants, 3 white-with-
colored-center flowers, and 2 scattered-grass-dot patches. ~540 cells
populated on the 80x80 map; deterministic seed so layout is stable.

The bundle's design assumes flat-color terrain + overlay sprites for
visual richness — so this is the cheapest possible win that uses the
art we own. Terrain base, walls, trees, pawns, UI all unchanged.

Implementation lives in world.gd as _build_decoration_tileset() +
_paint_decorations(); the Decoration TileMapLayer is added to
world.tscn at z_index=0 (siblings render in tree order so it draws
between Terrain and Floor). Tileset is built at runtime pointing at
res://art/tiles/FG_Grasslands_Spring.png, mirroring the existing
_build_placeholder_tileset pattern.

Verified MCP runtime: world feels like a meadow now, no perf hit.
Headless boot logs '[world] decoration: painted 541 overlay cells'.

License: ElvGames Humble bundle — commercial use OK with credit (see
docs/art.md). Credit string compilation is still an open audit item.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 14:07:36 +01:00
836dfdd716 Phase 1 — 80² world, 6-layer TileMap, camera rig, tick loop, speed UI
World scene (scenes/world/world.{tscn,gd}):
- 6 TileMapLayer nodes per architecture.md split: Terrain (0), Floor (1),
  Wall (2), Designation (3), Roof (4, hidden), Fog (5, hidden).
- Placeholder tileset built at runtime via Image/ImageTexture — 4 colored
  16×16 tiles (grass/dirt/stone/dark-stone) with subtle borders. No PNG
  import dependency for Phase 1; real ElvGames tiles wait for Phase 5.
- Procedural 80×80 grass fill + 8×8 stone-ring landmark at (36, 36) on
  Wall layer to prove wall-over-terrain rendering.
- Calls camera_rig.set_world_bounds() once map dimensions known.
- ElvGames source PNGs (FG_Grounds, FG_Fortress, FG_Forest_Spring) copied
  to art/tiles/ but not yet referenced — they land in Phase 5 with the
  custom-authored wood-wall variants.

Camera rig (scenes/world/camera_rig.{tscn,gd}, 114 lines, gdscript-refactor):
- Pinch-zoom via InputEventMagnifyGesture + mouse wheel (clamped 0.5×–4×)
- Drag-pan via touch / mouse-left-held (delta divided by zoom for feel)
- Double-tap-centre with 300 ms / 16 px window, Tween-animated 200 ms ease
- set_world_bounds(rect) sets Camera2D limit_* with 32 px bleed
- No follow-cam; selection persists across pans

Tick loop (autoload/sim.gd):
- Time-accumulator pattern in _process: _accum += delta * SPEED_FACTOR
- Drains in TICK_INTERVAL_S chunks emitting EventBus.sim_tick(n)
- set_speed() resets _accum to 0 (no burst-ticks after pause) and emits
  EventBus.speed_changed(int). Boot default = NORMAL.
- Audit.log on every speed transition for runtime diagnostics.
- Early-return guard against redundant set_speed calls.

EventBus (autoload/event_bus.gd):
- New signals: sim_tick(tick_number: int), speed_changed(new_speed: int)

Top bar (scenes/ui/top_bar.{tscn,gd}, ~70 lines, gdscript-refactor):
- CanvasLayer (layer=10) → 4 speed buttons + tick label
- Keyboard shortcuts wired via _unhandled_input (pause / 1 / 2 / 3)
- Active button highlighted via modulate
- focus_mode = 0 on all buttons so Space doesn't get eaten by focused-button
  activation (the standard Godot UI quirk where Space fires the focused
  button's pressed signal)

i18n (autoload/strings.gd):
- 5 new keys: speed.pause/normal/fast/ultra, hud.tick (template with {n})

Main bootstrap (scenes/main/main.{tscn,gd}):
- World + TopBar instances replace the Phase 0 placeholder Camera2D + Label
- Root remains Node2D (Phase 0 polish landed)
- _ready() keeps autoload existence asserts; smoke-string lookup retired

Indoor tint shader (art/shaders/indoor_tint.gdshader):
- Stub: tint_strength = 0 pass-through. Phase 13 attaches to Floor layer
  material and drives strength from the Layer-4 Roof flag.

Acceptance: MCP-verified via play_scene + get_game_screenshot. 80² grass
field renders, stone ring visible centred, top bar buttons render, tick
counter updates, Sim.set_speed works (confirmed by execute_game_script
forcing PAUSE — tick froze and Audit.log emitted the transition line).

Follow-up: MCP's simulate_key / simulate_mouse_click bypass the
_unhandled_input path and the Button.pressed signal — events don't reach
the handler. Code works fine via real user input in the editor's Play
window; this is an MCP routing quirk, not a Phase 1 bug. Documented as
a known limitation when scripting input tests.

Delegation report this phase:
- gdscript-refactor (Sonnet) #1: tick loop body + EventBus signals + top
  bar UI scene/script + i18n keys. ~3 file mods + 2 new files. Headless-
  validated by the subagent.
- gdscript-refactor (Sonnet) #2: camera rig scene + script. 2 new files,
  114 lines GDScript. Headless-validated by the subagent.
- Opus: world scene + procedural tileset + map fill + integration into
  main.tscn + MCP-driven runtime verification.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-10 20:37:02 +01:00
128294c14f Phase 0 scaffold + asset audit findings
Project scaffold:
- project.godot at repo root, GL Compatibility renderer (max mobile reach),
  pixel-snap on, texture filter nearest, sensor_landscape orientation
- 7 autoloads: World, Sim, GameState, EventBus, Strings, Audit, SaveSystem
- scenes/main/main.{tscn,gd} smoke-test scene with autoload assertions
- Folder layout matches tavernkeep idiom: autoload/ at root, scripts
  co-located with scenes/ (not the scripts/autoloads/ mirror originally
  sketched in implementation.md)
- Input map: pause, speed_cycle, speed_normal/fast/ultra, confirm, cancel.
  Mobile gestures (pinch/drag/long-press) handled at script level via
  Godot's InputEventScreenTouch/Drag/MagnifyGesture.
- SaveSystem skeleton: SAVE_VERSION=1, JSON to user://save_slot.json,
  version-mismatch warning. Phase 3 expands to real entity state.
- icon.svg placeholder (cabin silhouette on dark green field)
- README.md points at memory.md / implementation.md / docs/

Headless verification: 'godot --headless --path . --quit' exits 0,
'[main] Phase 0 smoke test online.' prints, no errors. Editor-side
green-dot check still pending — needs human launch of editor.

Asset audit (researcher Haiku, 2026-05-10):
- FG_Houses.png NOT autotile-solvable — pre-built decorative house
  compositions, 4 distinct roof palettes, no modular wall family.
  ~½–1 day per material to author terrain bits on top.
- FG_Fortress.png IS autotile-solvable — ~20–30 modular tan-stone
  pieces. Wang-style Godot 4 terrain works with minimal extra art.
  Iconic Homestead $19.99 fallback not needed.
- No wolf sprite anywhere in the bundle. EvoMonster packs all
  cute/fantasy. Need commission, CC0 source, or Ventilatore check.
- Retro Graveyard 16x16 [Kingdom Explorer] confirmed in Tier 3 with
  full graveyard suite — direct use in Phase 14.

New open questions surfaced in memory.md:
- Player-built wall material strategy (3 options laid out)
- Wolf sprite acquisition path (Phase 10 blocker)

Project move:
- Repo physical location moved from ~/claude/projects/rimlike to
  /mnt/d/godot/rimlike (D: drive, fast for Windows-side editor).
- Symlink at the original WSL path preserves the home-CLAUDE.md
  layout convention. Mirrors tavernkeep's pattern.
- Set core.filemode=false to silence DrvFs's everything-is-0777
  false-positive on git diff.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-10 20:09:11 +01:00