refactor(m4c): rename GameFlow coordinator to Main, move to scenes/Main.tscn
The entry-point coordinator read as an internal name ("GameFlow" buried in
scenes/flow/), so it wasn't obvious THIS is the scene that boots first — the
title screen looked like the entry point. Renamed to the Godot-conventional
Main (scenes/Main.tscn + scripts/main.gd) so the boot scene is self-evident.
TitleScreen is unchanged and still shown BY Main as its first screen.
Also drops the hand-written gd_scene uid (now matches sibling scenes) —
closes the Minor review finding. Full suite 327/327 green.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -13,26 +13,13 @@ config_version=5
|
|||||||
config/name="coc-rpg"
|
config/name="coc-rpg"
|
||||||
config/description="AI-driven single-player party RPG. Code owns state. AI owns text."
|
config/description="AI-driven single-player party RPG. Code owns state. AI owns text."
|
||||||
config/version="0.01-alpha"
|
config/version="0.01-alpha"
|
||||||
run/main_scene="res://scenes/flow/GameFlow.tscn"
|
run/main_scene="res://scenes/Main.tscn"
|
||||||
config/features=PackedStringArray("4.7")
|
config/features=PackedStringArray("4.7")
|
||||||
|
|
||||||
[display]
|
[display]
|
||||||
|
|
||||||
; The DESIGN CANVAS stays 1920x1080 — the mockups (§16) are authored there, and every
|
|
||||||
; .tscn's offsets are in those coordinates. It is a logical canvas, not a demand on the
|
|
||||||
; monitor: canvas_items + keep scales it uniformly into whatever window it is given, so
|
|
||||||
; the UI never reflows, it only gets smaller. Nothing below changes a layout number.
|
|
||||||
window/size/viewport_width=1920
|
window/size/viewport_width=1920
|
||||||
window/size/viewport_height=1080
|
window/size/viewport_height=1080
|
||||||
; The WINDOW is what the laptop has to fit, and it is a different question. 1600x900 was
|
|
||||||
; larger than a 1600x900 laptop's *usable* area once the WM took its panel and titlebar,
|
|
||||||
; so the window manager clamped it to 1589x752 and the run came up pillarboxed. 1280x720
|
|
||||||
; is 16:9 and fits any laptop this ships to; the window is resizable (Godot's default),
|
|
||||||
; and canvas_items rescales the canvas live on every resize.
|
|
||||||
window/size/window_width_override=1280
|
window/size/window_width_override=1280
|
||||||
window/size/window_height_override=720
|
window/size/window_height_override=720
|
||||||
window/size/resizable=true
|
|
||||||
window/stretch/mode="canvas_items"
|
window/stretch/mode="canvas_items"
|
||||||
; keep = letterbox rather than distort or reflow. This IS Godot 4's default, so the editor
|
|
||||||
; prunes the line whenever it rewrites this file — that is cosmetic, not a behaviour change.
|
|
||||||
window/stretch/aspect="keep"
|
|
||||||
|
|||||||
6
client/scenes/Main.tscn
Normal file
6
client/scenes/Main.tscn
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
[gd_scene load_steps=2 format=3]
|
||||||
|
|
||||||
|
[ext_resource type="Script" path="res://scripts/main.gd" id="1"]
|
||||||
|
|
||||||
|
[node name="Main" type="Node"]
|
||||||
|
script = ExtResource("1")
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
[gd_scene load_steps=2 format=3 uid="uid://coc_gameflow"]
|
|
||||||
|
|
||||||
[ext_resource type="Script" path="res://scripts/ui/flow/game_flow.gd" id="1"]
|
|
||||||
|
|
||||||
[node name="GameFlow" type="Node"]
|
|
||||||
script = ExtResource("1")
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
class_name GameFlow
|
class_name Main
|
||||||
extends Node
|
extends Node
|
||||||
## The single home for the game's screen sequence: Title → Creation → Shell.
|
## The single home for the game's screen sequence: Title → Creation → Shell.
|
||||||
## Script-first by design — a pure coordinator with no Control layout, so ADR 0001's
|
## Script-first by design — a pure coordinator with no Control layout, so ADR 0001's
|
||||||
@@ -88,6 +88,6 @@ func _start_campaign(creation: Dictionary) -> void:
|
|||||||
if not result.get("ok", false):
|
if not result.get("ok", false):
|
||||||
# Unreachable via the UI (the CTA gates on validate), but §2 forbids trusting
|
# Unreachable via the UI (the CTA gates on validate), but §2 forbids trusting
|
||||||
# the caller and §13 forbids surfacing an error. Log and stay put.
|
# the caller and §13 forbids surfacing an error. Log and stay put.
|
||||||
push_error("GameFlow: construct rejected a creation: %s" % str(result.get("errors", [])))
|
push_error("Main: construct rejected a creation: %s" % str(result.get("errors", [])))
|
||||||
return
|
return
|
||||||
_show_shell(result["log"], result["state"])
|
_show_shell(result["log"], result["state"])
|
||||||
1
client/scripts/main.gd.uid
Normal file
1
client/scripts/main.gd.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://du7rwup648n60
|
||||||
@@ -1 +0,0 @@
|
|||||||
uid://cy0r08ct0jugt
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
uid://buyyn7tbjctb
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
extends "res://addons/gut/test.gd"
|
extends "res://addons/gut/test.gd"
|
||||||
|
|
||||||
const SCENE := "res://scenes/flow/GameFlow.tscn"
|
const SCENE := "res://scenes/Main.tscn"
|
||||||
const ContentDB = preload("res://scripts/content/content_db.gd")
|
const ContentDB = preload("res://scripts/content/content_db.gd")
|
||||||
const FakeTransport = preload("res://tests/doubles/fake_transport.gd")
|
const FakeTransport = preload("res://tests/doubles/fake_transport.gd")
|
||||||
const DmResponse = preload("res://scripts/net/dm_response.gd")
|
const DmResponse = preload("res://scripts/net/dm_response.gd")
|
||||||
@@ -31,7 +31,7 @@ func _creation() -> Dictionary:
|
|||||||
|
|
||||||
func test_boots_into_the_title():
|
func test_boots_into_the_title():
|
||||||
var flow := _flow()
|
var flow := _flow()
|
||||||
assert_true(flow._current is TitleScreen, "GameFlow opens on the title")
|
assert_true(flow._current is TitleScreen, "Main opens on the title")
|
||||||
|
|
||||||
|
|
||||||
func test_new_game_shows_creation():
|
func test_new_game_shows_creation():
|
||||||
@@ -53,7 +53,7 @@ func _assert_stays_on_creation(bad: Dictionary, why: String) -> void:
|
|||||||
var flow := _flow()
|
var flow := _flow()
|
||||||
flow._current.emit_signal("menu_activated", &"new_game")
|
flow._current.emit_signal("menu_activated", &"new_game")
|
||||||
# Drive the REAL signal with an invalid dict. The CTA gates this out via the UI,
|
# Drive the REAL signal with an invalid dict. The CTA gates this out via the UI,
|
||||||
# but §2 forbids GameFlow trusting the caller and §13 forbids surfacing an error.
|
# but §2 forbids Main trusting the caller and §13 forbids surfacing an error.
|
||||||
flow._current.emit_signal("creation_confirmed", bad)
|
flow._current.emit_signal("creation_confirmed", bad)
|
||||||
assert_false(flow._current is MainWindowShell, "a failed construct never reaches the shell (§13): %s" % why)
|
assert_false(flow._current is MainWindowShell, "a failed construct never reaches the shell (§13): %s" % why)
|
||||||
assert_true(flow._current is CharacterCreation, "the player stays on the valid creation screen: %s" % why)
|
assert_true(flow._current is CharacterCreation, "the player stays on the valid creation screen: %s" % why)
|
||||||
1
client/tests/unit/test_main.gd.uid
Normal file
1
client/tests/unit/test_main.gd.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://17abdh3almry
|
||||||
Reference in New Issue
Block a user