Player (player/player.gd, shared by both island.tscn's real Player and
the player/player.tscn debug prototype via the same script):
- Health (max_health/health, take_damage, heal_full, death via
change_scene_to_file to a new Game Over screen).
- Left-click move-to-point layered onto existing WASD (WASD cancels an
active click-target and takes priority; click-move re-derives the
existing screen-relative animation logic from the world-space
direction instead of duplicating it). New "attack" input action
(Space) does a simple range check against everything in the
"enemies" group. Runs via _unhandled_input so an open interaction
menu naturally takes priority (button consumes the event first).
New systems:
- world/enemy/enemy.gd + .tscn: direct-chase CharacterBody3D (no
pathfinding), contact damage with its own cooldown, reports death to
ArenaManager rather than freeing itself (which owns the live count).
- world/arena/tiles/: 6 placeholder tile scenes (4 plain floor colors,
2 with a simple obstacle pillar) — pure static geometry, same
unshaded-flat-color convention as terrain.gd.
- autoload/arena_manager.gd (new singleton): assembles a 3x3 grid of
random tiles (center forced to plain floor) under a persistent
ArenaRoot positioned far below the island (0,-300,0, group
"arena_root"), rebuilding it fresh on every trigger since only one
arena is ever active. Adds 4 axis-aligned invisible walls (same idea
as terrain.gd's _build_edge_barrier, no rotation needed for a
square). Spawns 3 enemies, teleports the player in. On the last
enemy's death: calls the POI's mark_visited(), reuses
InteractionManager.open_message() (existing, previously-unused code)
for a "Sieg!" message, then teleports the player back after a timer.
- world/poi/poi_arena.gd + .tscn: same Area3D/sprite shell as poi.gd,
but interacting starts an arena directly instead of opening the
generic menu (same divergence pattern poi_gate.gd already
established). Exposes the same duck-typed `visited` field, so
poi_gate.gd's region-gate group check needed zero changes.
- boot/game_over_screen.gd + .tscn: same Control/Panel/Button
structure as main_menu.tscn, one button back to the main menu.
- world/ui/player_hud.gd + .tscn: minimal CanvasLayer HP label.
Content pass: poi.gd gained `event_text` (falls back to the old flat
placeholder if unset); interaction_manager.gd's "explore" case uses it
and "rest" now actually calls player.heal_full(). Applied to region 1:
Ort1/Ort4/Ort6 became arena POIs, Ort2/Ort3/Ort5 got distinct event
text — first concrete proof of the "mix of events and arenas" pattern,
replicating to regions 2-6 is a fast follow-up.
Verified headless via direct method calls (confirmed limitation:
synthetic clicks/keypresses don't reliably drive _unhandled_input in
this harness): start_arena produces 9 tiles + a wall body + 3 enemies
and teleports the player near y=-300; killing all 3 enemies flips the
POI's visited flag and opens the win message; completing the win flow
returns the player next to the original POI; marking the other 5
region-1 POIs visited then correctly unlocks GateR1toR2 (proving the
arena-POI/gate integration without touching poi_gate.gd); player
take_damage(max_health) triggers is_dead and a scene change to
game_over_screen.tscn (confirmed after allowing deferred frames to
process). Also verified an enemy actually closes distance on the
player and lands contact damage over a live physics simulation, and
that the player's attack respects both damage and cooldown.
Not verifiable headlessly, needs in-editor testing: real click-to-move
and Space-bar attack end-to-end, combat feel/balance, arena tile
visuals.
Extends the proven region-1 pattern (6 placeholder POIs + a gate) to
the remaining 5 outer regions, and rewires the gate chain to match the
confirmed progression plan: visit all 6 outer regions in order, then
reach the center — not "region 1 unlocks the center directly" as it
was built initially.
- Repurposed the old GateToCenter into GateR1toR2 (still gated on
region1_pois, now leads into region 2 instead of the center).
- Added GateR2toR3 .. GateR5toR6, each gated on its own region's POI
group, sitting just off the radial ridge between two regions
(2.5 units perpendicular offset — a hard analytical lower bound on
clearance, since border props' jitter+radius can reach at most
~0.75 units off the ridge centerline).
- Added GateR6toCenter (gated on region6_pois) at the region-6 table
edge, using the same positioning approach as the original center
gate.
- 30 new POI instances (R2_Ort1..R6_Ort6), positions computed by
rotating region 1's verified-safe (angle-offset, radius) template by
60° per region rather than re-deriving hex geometry by hand again —
region 1's own Ort6 mistake was exactly this kind of hand-arithmetic
error, not repeating it this time.
Verified headless: all 6 groups have exactly 6 POIs; every gate stays
locked ("Verschlossen", non-interactive) until its whole group is
visited, then unlocks and its "Ja" teleports the player to exactly
target_position — checked for all 6 gates in sequence. Also measured
actual distance from every gate to the nearest border-prop hitbox
across 3 independent runs (border placement is randomized each scene
load) — consistently 1.3-2.2 units clear, no overlaps.
boot/: opening_screen (attribution -> title/flavor text placeholder,
explicitly marked TODO for a later real cinematic, skippable by
keypress/click) -> main_menu (Neues Spiel/Fortsetzen/Optionen/Credits/
Beenden, ConfirmationDialog for overwrite-existing-save) -> options_menu
(TabContainer with 4 empty placeholder categories: Grafik/Sound/
Steuerung/Spieloptionen) and credits_screen, both just navigable stubs.
project.godot's run/main_scene now points at boot/opening_screen.tscn
instead of directly at the gameplay scene.
autoload/save_manager.gd: new SaveManager singleton. Deliberately
minimal — persists only a timestamp to user://savegame.json — but a
real, working has_save()/save_game()/load_game()/start_new_game()
round trip, enough to back the menu's Start/Continue/overwrite-confirm
logic without inventing game state that doesn't exist yet.
player/equipment/: Equipment (Node) + EquipmentItem (Resource) stub
classes per the user's explicit ask for a "class diagram skeleton" to
build on later — exported fields and empty TODO methods, no logic.
Wired as a child of world/island.tscn's real Player (not player.tscn,
which is only a debug prototype scene, not the actual game's player).
player.gd's new `equipment` onready var uses get_node_or_null() since
that child only exists on the real player, not every scene reusing
this script.
Verified headless: all new boot scenes load cleanly, a full boot smoke
test via run/main_scene succeeds, and — since button-click navigation
can't be simulated headlessly — SaveManager's actual save/load/
overwrite/cleanup cycle was exercised directly and behaves correctly
(has_save flips true/false correctly, loaded data matches what was
saved). Manual in-editor check of the menu navigation itself is still
needed and not yet done.
Flat root layout replaced with a domain-based structure:
- autoload/ the two existing singleton scripts (InteractionManager,
InteractionUI) — grouped by role, matching project.godot's
[autoload] section
- world/ the flying island: terrain.gd, and world/poi/ for the POI
marker + gate scripts/scenes
- player/ everything about the player as a character: player.gd/.tscn,
camera_rig.gd (it only exists to follow the player)
- boot/ created empty for now, will hold the opening/menu screens
main.tscn renamed to world/island.tscn — "main" stops making sense once
the actual run/main_scene becomes a boot screen (next commit). Verified
via grep that main.tscn was referenced nowhere else by path (only by UID
elsewhere, which self-heals).
Every .gd got its .uid sidecar moved alongside it. Two ext_resource
entries had no UID (poi_gate.tscn's own script ref, and island.tscn's
ref to poi_gate.tscn) and needed their path= fixed by hand; everything
else is UID-based and resolved itself after a project reimport.
Also removed two untracked-looking but actually committed editor temp
files (preview_scene.tscn*.tmp, leftovers from the unused hterrain
addon, referenced nowhere).
Verified headless: all 8 affected scenes (island, poi, poi_gate,
player, interaction_ui, and the three debug prototypes that reference
moved files) load with exit code 0. No behavior change, pure move.