Files
TheriapolisV3/Theriapolis.Godot/Main.cs
T
Christopher Wiebe 2db442be7e M6.20: TitleScreen entry point with parchment-themed button stack
Default boot now lands on a centered title screen instead of the M0
hello-world label. Vertical button stack — New Character, Continue,
Quit — over the codex parchment field, with the H1 codex title and a
PORT / GODOT · M6.20 version chip in the bottom-right.

Continue is disabled until user://character.json exists; clicking it
prints a placeholder until the M7 play loop can pick the persisted
state up. New Character swaps the title for the wizard scene under
the Main parent. The wizard's existing "← Title" back-button on
Step 0 now actually does something — TitleScreen wires its
BackToTitle signal to a parent-side swap that reinstates the title
screen when the player backs out.

--wizard command-line flag still skips straight to the wizard for
fast-path development. Layout uses SetAnchorsAndOffsetsPreset
(LayoutPreset.FullRect) on the backing panel and CenterContainer —
manual AnchorRight = 1 doesn't fill in code because Godot's anchor
setters preserve visual position by adjusting offsets, leaving the
control at 0×0.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-09 22:01:51 -07:00

152 lines
5.0 KiB
C#

using Godot;
using Theriapolis.GodotHost.Platform;
using Theriapolis.GodotHost.Rendering;
using Theriapolis.GodotHost.Scenes;
using Theriapolis.GodotHost.UI;
namespace Theriapolis.GodotHost;
// Control (not Node) so child Control scenes (Wizard, KitchenSink, etc.)
// can anchor to a real rect that fills the viewport. With a plain Node
// parent, anchors are ignored and Controls sit at (0,0) at intrinsic min
// size, which causes wide content to overflow off the right edge.
public partial class Main : Control
{
public override void _Ready()
{
// GetCmdlineArgs returns every arg (Godot's own flags + ours);
// GetCmdlineUserArgs only returns args after a "--" separator.
// Use the union so users don't have to remember the separator.
var userArgs = OS.GetCmdlineUserArgs();
var allArgs = OS.GetCmdlineArgs();
var args = new string[userArgs.Length + allArgs.Length];
userArgs.CopyTo(args, 0);
allArgs.CopyTo(args, userArgs.Length);
ulong? smokeTestSeed = null;
ulong? worldMapSeed = null;
bool runAssetTest = false;
bool runCodexTest = false;
bool runWizard = false;
(ulong seed, int tx, int ty)? tacticalArgs = null;
for (int i = 0; i < args.Length; i++)
{
if (args[i] == "--codex-test")
{
runCodexTest = true;
break;
}
if (args[i] == "--wizard")
{
runWizard = true;
break;
}
if (args[i] == "--smoke-test")
{
ulong seed = 12345UL;
if (i + 1 < args.Length && ulong.TryParse(args[i + 1], out var parsed))
seed = parsed;
smokeTestSeed = seed;
break;
}
if (args[i] == "--asset-test")
{
runAssetTest = true;
break;
}
if (args[i] == "--world-map")
{
ulong seed = 12345UL;
if (i + 1 < args.Length && ulong.TryParse(args[i + 1], out var parsed))
seed = parsed;
worldMapSeed = seed;
break;
}
if (args[i] == "--tactical")
{
ulong seed = 12345UL;
int tx = 128, ty = 128;
if (i + 1 < args.Length && ulong.TryParse(args[i + 1], out var s))
seed = s;
if (i + 2 < args.Length && int.TryParse(args[i + 2], out var x))
tx = x;
if (i + 3 < args.Length && int.TryParse(args[i + 3], out var y))
ty = y;
tacticalArgs = (seed, tx, ty);
break;
}
}
if (smokeTestSeed.HasValue)
{
int code = SmokeTest.Run(smokeTestSeed.Value);
GetTree().Quit(code);
return;
}
if (runAssetTest)
{
int code = AssetTest.Run();
GetTree().Quit(code);
return;
}
if (worldMapSeed.HasValue)
{
// M4: unified seamless-zoom view. --world-map starts zoomed out
// (fit-to-viewport, initialZoom=0 = compute fit), --tactical
// starts at native sprite zoom 32 with the player at the given
// tile. Wheel between them seamlessly.
foreach (Node child in GetChildren())
child.QueueFree();
AddChild(new WorldView(worldMapSeed.Value));
return;
}
if (tacticalArgs.HasValue)
{
foreach (Node child in GetChildren())
child.QueueFree();
var (seed, tx, ty) = tacticalArgs.Value;
AddChild(new WorldView(seed, tx, ty, initialZoom: 32f));
return;
}
if (runCodexTest)
{
foreach (Node child in GetChildren())
child.QueueFree();
AddChild(new KitchenSink());
return;
}
if (runWizard)
{
foreach (Node child in GetChildren())
child.QueueFree();
var packed = ResourceLoader.Load<PackedScene>("res://Scenes/Wizard.tscn");
AddChild(packed.Instantiate());
return;
}
// Default entry point — TitleScreen. M0's hello-world Label is no
// longer the boot UI; the title swaps itself for the wizard when
// "New Character" is clicked, or shuts the engine down on Quit.
foreach (Node child in GetChildren())
child.QueueFree();
AddChild(new TitleScreen());
}
public override void _UnhandledInput(InputEvent @event)
{
if (@event.IsActionPressed("ui_toggle_fullscreen"))
{
var mode = DisplayServer.WindowGetMode();
DisplayServer.WindowSetMode(
mode == DisplayServer.WindowMode.Fullscreen
? DisplayServer.WindowMode.Windowed
: DisplayServer.WindowMode.Fullscreen);
}
}
}