Initial commit: Theriapolis baseline at port/godot branch point

Captures the pre-Godot-port state of the codebase. This is the rollback
anchor for the Godot port (M0 of theriapolis-rpg-implementation-plan-godot-port.md).
All Phase 0 through Phase 6.5 work is included; Phase 7 is in flight.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Christopher Wiebe
2026-04-30 20:40:51 -07:00
commit b451f83174
525 changed files with 75786 additions and 0 deletions
+114
View File
@@ -0,0 +1,114 @@
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Myra;
using Myra.Graphics2D.UI;
namespace Theriapolis.Game.Screens;
/// <summary>
/// Title screen: game logo text, "New World" button, optional seed input field.
/// Uses Myra for all UI widgets.
/// </summary>
public sealed class TitleScreen : IScreen
{
private Game1 _game = null!;
private Desktop _desktop = null!;
private TextBox? _seedInput;
public void Initialize(Game1 game)
{
_game = game;
BuildUI();
}
private void BuildUI()
{
var root = new VerticalStackPanel
{
Spacing = 12,
HorizontalAlignment = HorizontalAlignment.Center,
VerticalAlignment = VerticalAlignment.Center,
};
// Title label
var title = new Label
{
Text = "THERIAPOLIS",
HorizontalAlignment = HorizontalAlignment.Center,
};
root.Widgets.Add(title);
// Sub-title
var sub = new Label
{
Text = "Veldara awaits.",
HorizontalAlignment = HorizontalAlignment.Center,
};
root.Widgets.Add(sub);
// Spacer
root.Widgets.Add(new Label { Text = " " });
// Seed row
var seedRow = new HorizontalStackPanel { Spacing = 8 };
seedRow.Widgets.Add(new Label { Text = "Seed:", VerticalAlignment = VerticalAlignment.Center });
_seedInput = new TextBox
{
Text = "",
Width = 160,
};
seedRow.Widgets.Add(_seedInput);
root.Widgets.Add(seedRow);
// New World button
var newWorldBtn = new TextButton
{
Text = "New World",
Width = 180,
HorizontalAlignment = HorizontalAlignment.Center,
};
newWorldBtn.Click += OnNewWorldClicked;
root.Widgets.Add(newWorldBtn);
var loadBtn = new TextButton
{
Text = "Load Game",
Width = 180,
HorizontalAlignment = HorizontalAlignment.Center,
};
loadBtn.Click += (_, _) => _game.Screens.Push(new SaveLoadScreen());
root.Widgets.Add(loadBtn);
_desktop = new Desktop { Root = root };
}
private void OnNewWorldClicked(object? sender, EventArgs e)
{
ulong seed;
string raw = _seedInput?.Text?.Trim() ?? "";
if (string.IsNullOrEmpty(raw))
{
// Random seed from system time
seed = (ulong)DateTime.UtcNow.Ticks;
}
else if (!ulong.TryParse(raw, out seed))
{
// Hash the string to a seed
seed = 0;
foreach (char c in raw) seed = seed * 31 + c;
}
_game.Screens.Push(new CodexUI.Screens.CodexCharacterCreationScreen(seed));
}
public void Update(GameTime gameTime) { }
public void Draw(GameTime gameTime, SpriteBatch spriteBatch)
{
_game.GraphicsDevice.Clear(new Color(20, 20, 30));
_desktop.Render();
}
public void Deactivate() { }
public void Reactivate() { }
}