Implement Godot UX scene scaffold
This commit is contained in:
15
src/ReactorMaintenance.Godot/Controls/CellInspector.cs
Normal file
15
src/ReactorMaintenance.Godot/Controls/CellInspector.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
using Godot;
|
||||
|
||||
namespace ReactorMaintenance.Godot.Controls;
|
||||
|
||||
public partial class CellInspector : PanelContainer
|
||||
{
|
||||
public override void _Ready()
|
||||
{
|
||||
AddChild(m_Text);
|
||||
m_Text.Text = "Selected Cell: 0,0\nTerrain: service floor\nProp: none\nHazards: none\nUnderground: hidden";
|
||||
m_Text.AutowrapMode = TextServer.AutowrapMode.WordSmart;
|
||||
}
|
||||
|
||||
private readonly Label m_Text = new();
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
uid://d0d3kglv6s32m
|
||||
33
src/ReactorMaintenance.Godot/Controls/ConfirmDialog.cs
Normal file
33
src/ReactorMaintenance.Godot/Controls/ConfirmDialog.cs
Normal file
@@ -0,0 +1,33 @@
|
||||
using Godot;
|
||||
|
||||
namespace ReactorMaintenance.Godot.Controls;
|
||||
|
||||
public partial class ConfirmDialog : PanelContainer
|
||||
{
|
||||
public event Action? Confirmed;
|
||||
public event Action? Canceled;
|
||||
|
||||
public void Configure(string title, string message, string confirmText = "Confirm")
|
||||
{
|
||||
foreach (var child in GetChildren())
|
||||
child.QueueFree();
|
||||
|
||||
var body = new VBoxContainer();
|
||||
AddChild(body);
|
||||
body.AddChild(new Label { Text = title, HorizontalAlignment = HorizontalAlignment.Center });
|
||||
body.AddChild(new Label { Text = message, AutowrapMode = TextServer.AutowrapMode.WordSmart });
|
||||
|
||||
var actions = new HBoxContainer();
|
||||
body.AddChild(actions);
|
||||
|
||||
var confirm = new PrimaryButton();
|
||||
confirm.Configure(confirmText);
|
||||
confirm.Pressed += () => Confirmed?.Invoke();
|
||||
actions.AddChild(confirm);
|
||||
|
||||
var cancel = new PrimaryButton();
|
||||
cancel.Configure("Cancel");
|
||||
cancel.Pressed += () => Canceled?.Invoke();
|
||||
actions.AddChild(cancel);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
uid://cp5qe2n4nwb32
|
||||
24
src/ReactorMaintenance.Godot/Controls/ForecastList.cs
Normal file
24
src/ReactorMaintenance.Godot/Controls/ForecastList.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
using Godot;
|
||||
|
||||
namespace ReactorMaintenance.Godot.Controls;
|
||||
|
||||
public partial class ForecastList : PanelContainer
|
||||
{
|
||||
public override void _Ready()
|
||||
{
|
||||
AddChild(m_Items);
|
||||
SetForecasts(["Turn +1: Pressure stable", "Turn +2: No forecast warnings"]);
|
||||
}
|
||||
|
||||
public void SetForecasts(IReadOnlyList<string> forecasts)
|
||||
{
|
||||
foreach (var child in m_Items.GetChildren())
|
||||
child.QueueFree();
|
||||
|
||||
m_Items.AddChild(new Label { Text = "Forecasts" });
|
||||
foreach (var forecast in forecasts)
|
||||
m_Items.AddChild(new Label { Text = forecast, AutowrapMode = TextServer.AutowrapMode.WordSmart });
|
||||
}
|
||||
|
||||
private readonly VBoxContainer m_Items = new();
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
uid://bswy75n15jxl5
|
||||
23
src/ReactorMaintenance.Godot/Controls/InventoryStrip.cs
Normal file
23
src/ReactorMaintenance.Godot/Controls/InventoryStrip.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
using Godot;
|
||||
|
||||
namespace ReactorMaintenance.Godot.Controls;
|
||||
|
||||
public partial class InventoryStrip : HBoxContainer
|
||||
{
|
||||
public override void _Ready()
|
||||
{
|
||||
AddChild(CreateItem("Fuel Neutralizer", 2));
|
||||
AddChild(CreateItem("Coolant Neutralizer", 2));
|
||||
AddChild(CreateItem("Electric Neutralizer", 1));
|
||||
AddChild(CreateItem("Heat Shield", 1));
|
||||
}
|
||||
|
||||
private static Label CreateItem(string name, int count)
|
||||
{
|
||||
return new() {
|
||||
Text = $"{name}: {count}",
|
||||
HorizontalAlignment = HorizontalAlignment.Center,
|
||||
SizeFlagsHorizontal = SizeFlags.ExpandFill
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
uid://d1pdwv570am3v
|
||||
33
src/ReactorMaintenance.Godot/Controls/LevelHeader.cs
Normal file
33
src/ReactorMaintenance.Godot/Controls/LevelHeader.cs
Normal file
@@ -0,0 +1,33 @@
|
||||
using Godot;
|
||||
using ReactorMaintenance.Godot.Data;
|
||||
|
||||
namespace ReactorMaintenance.Godot.Controls;
|
||||
|
||||
public partial class LevelHeader : HBoxContainer
|
||||
{
|
||||
public override void _Ready()
|
||||
{
|
||||
AddChild(m_Title);
|
||||
AddChild(m_Progress);
|
||||
AddChild(m_Badge);
|
||||
AddChild(m_Summary);
|
||||
|
||||
m_Title.SizeFlagsHorizontal = SizeFlags.ExpandFill;
|
||||
m_Title.AddThemeFontSizeOverride("font_size", 24);
|
||||
m_Progress.HorizontalAlignment = HorizontalAlignment.Center;
|
||||
m_Summary.HorizontalAlignment = HorizontalAlignment.Right;
|
||||
}
|
||||
|
||||
public void SetLevel(CampaignLevel level, int levelNumber, int levelCount, string state)
|
||||
{
|
||||
m_Title.Text = level.Name;
|
||||
m_Progress.Text = $"Level {levelNumber} / {levelCount}";
|
||||
m_Badge.SetState(state);
|
||||
m_Summary.Text = "Heat nominal | Reactor offline";
|
||||
}
|
||||
|
||||
private readonly StateBadge m_Badge = new();
|
||||
private readonly Label m_Progress = new();
|
||||
private readonly Label m_Summary = new();
|
||||
private readonly Label m_Title = new();
|
||||
}
|
||||
1
src/ReactorMaintenance.Godot/Controls/LevelHeader.cs.uid
Normal file
1
src/ReactorMaintenance.Godot/Controls/LevelHeader.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://cp50vj0rystlk
|
||||
41
src/ReactorMaintenance.Godot/Controls/OutcomeOverlay.cs
Normal file
41
src/ReactorMaintenance.Godot/Controls/OutcomeOverlay.cs
Normal file
@@ -0,0 +1,41 @@
|
||||
using Godot;
|
||||
|
||||
namespace ReactorMaintenance.Godot.Controls;
|
||||
|
||||
public partial class OutcomeOverlay : PanelContainer
|
||||
{
|
||||
public override void _Ready()
|
||||
{
|
||||
CustomMinimumSize = new(420, 220);
|
||||
AddChild(m_Body);
|
||||
m_Body.AddChild(m_Title);
|
||||
m_Body.AddChild(m_Message);
|
||||
m_Body.AddChild(m_Actions);
|
||||
m_Title.HorizontalAlignment = HorizontalAlignment.Center;
|
||||
m_Title.AddThemeFontSizeOverride("font_size", 26);
|
||||
m_Message.AutowrapMode = TextServer.AutowrapMode.WordSmart;
|
||||
m_Message.HorizontalAlignment = HorizontalAlignment.Center;
|
||||
}
|
||||
|
||||
protected void Configure(string title, string message, IReadOnlyList<(string Text, Action Pressed)> actions)
|
||||
{
|
||||
m_Title.Text = title;
|
||||
m_Message.Text = message;
|
||||
|
||||
foreach (var child in m_Actions.GetChildren())
|
||||
child.QueueFree();
|
||||
|
||||
foreach (var action in actions)
|
||||
{
|
||||
var button = new PrimaryButton();
|
||||
button.Configure(action.Text);
|
||||
button.Pressed += action.Pressed;
|
||||
m_Actions.AddChild(button);
|
||||
}
|
||||
}
|
||||
|
||||
private readonly HBoxContainer m_Actions = new();
|
||||
private readonly VBoxContainer m_Body = new();
|
||||
private readonly Label m_Message = new();
|
||||
private readonly Label m_Title = new();
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
uid://65iow3r0egvo
|
||||
20
src/ReactorMaintenance.Godot/Controls/PrimaryButton.cs
Normal file
20
src/ReactorMaintenance.Godot/Controls/PrimaryButton.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
using Godot;
|
||||
|
||||
namespace ReactorMaintenance.Godot.Controls;
|
||||
|
||||
public partial class PrimaryButton : Button
|
||||
{
|
||||
public override void _Ready()
|
||||
{
|
||||
FocusMode = FocusModeEnum.All;
|
||||
CustomMinimumSize = new(220, 44);
|
||||
SizeFlagsHorizontal = SizeFlags.ExpandFill;
|
||||
}
|
||||
|
||||
public void Configure(string text, string tooltip = "", bool disabled = false)
|
||||
{
|
||||
Text = text;
|
||||
TooltipText = tooltip;
|
||||
Disabled = disabled;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
uid://bxk3mw5bybqxr
|
||||
30
src/ReactorMaintenance.Godot/Controls/StateBadge.cs
Normal file
30
src/ReactorMaintenance.Godot/Controls/StateBadge.cs
Normal file
@@ -0,0 +1,30 @@
|
||||
using Godot;
|
||||
|
||||
namespace ReactorMaintenance.Godot.Controls;
|
||||
|
||||
public partial class StateBadge : Label
|
||||
{
|
||||
public override void _Ready()
|
||||
{
|
||||
HorizontalAlignment = HorizontalAlignment.Center;
|
||||
VerticalAlignment = VerticalAlignment.Center;
|
||||
CustomMinimumSize = new(96, 28);
|
||||
}
|
||||
|
||||
public void SetState(string state)
|
||||
{
|
||||
Text = state;
|
||||
AddThemeColorOverride("font_color", GetColor(state));
|
||||
}
|
||||
|
||||
private static Color GetColor(string state)
|
||||
{
|
||||
return state.ToLowerInvariant() switch {
|
||||
"stable" => new(0.72f, 0.86f, 0.76f),
|
||||
"caution" => new(1.0f, 0.76f, 0.24f),
|
||||
"critical" or "lost" => new(1.0f, 0.36f, 0.32f),
|
||||
"ready" or "won" => new(0.45f, 1.0f, 0.58f),
|
||||
_ => Colors.White
|
||||
};
|
||||
}
|
||||
}
|
||||
1
src/ReactorMaintenance.Godot/Controls/StateBadge.cs.uid
Normal file
1
src/ReactorMaintenance.Godot/Controls/StateBadge.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://y7qn5eixkr7j
|
||||
9
src/ReactorMaintenance.Godot/Data/CampaignLevel.cs
Normal file
9
src/ReactorMaintenance.Godot/Data/CampaignLevel.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
namespace ReactorMaintenance.Godot.Data;
|
||||
|
||||
public sealed record CampaignLevel
|
||||
{
|
||||
public string Id { get; init; } = string.Empty;
|
||||
public string Name { get; init; } = string.Empty;
|
||||
public string FlavorText { get; init; } = string.Empty;
|
||||
public string LevelPath { get; init; } = string.Empty;
|
||||
}
|
||||
1
src/ReactorMaintenance.Godot/Data/CampaignLevel.cs.uid
Normal file
1
src/ReactorMaintenance.Godot/Data/CampaignLevel.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://uis6i7yfkrty
|
||||
6
src/ReactorMaintenance.Godot/Data/CampaignManifest.cs
Normal file
6
src/ReactorMaintenance.Godot/Data/CampaignManifest.cs
Normal file
@@ -0,0 +1,6 @@
|
||||
namespace ReactorMaintenance.Godot.Data;
|
||||
|
||||
public sealed record CampaignManifest
|
||||
{
|
||||
public IReadOnlyList<CampaignLevel> Levels { get; init; } = Array.Empty<CampaignLevel>();
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
uid://bnyc3qlyksmua
|
||||
39
src/ReactorMaintenance.Godot/Data/CampaignRepository.cs
Normal file
39
src/ReactorMaintenance.Godot/Data/CampaignRepository.cs
Normal file
@@ -0,0 +1,39 @@
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using FileAccess = Godot.FileAccess;
|
||||
|
||||
namespace ReactorMaintenance.Godot.Data;
|
||||
|
||||
public static class CampaignRepository
|
||||
{
|
||||
public static CampaignManifest LoadDefault()
|
||||
{
|
||||
var json = FileAccess.GetFileAsString(c_DefaultManifestPath);
|
||||
if (string.IsNullOrWhiteSpace(json))
|
||||
return CreateFallback();
|
||||
|
||||
var manifest = JsonSerializer.Deserialize<CampaignManifest>(json, s_Options);
|
||||
return manifest is { Levels.Count: > 0 } ? manifest : CreateFallback();
|
||||
}
|
||||
|
||||
private static CampaignManifest CreateFallback()
|
||||
{
|
||||
return new() {
|
||||
Levels = [
|
||||
new() {
|
||||
Id = "fallback",
|
||||
Name = "Fallback Reactor",
|
||||
FlavorText = "A placeholder level loaded because the campaign manifest was unavailable.",
|
||||
LevelPath = "res://Data/Levels/fallback.json"
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
|
||||
private const string c_DefaultManifestPath = "res://Data/default_campaign_manifest.json";
|
||||
|
||||
private static readonly JsonSerializerOptions s_Options = new() {
|
||||
PropertyNameCaseInsensitive = true,
|
||||
Converters = { new JsonStringEnumConverter() }
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
uid://bufo8npdbreb1
|
||||
62
src/ReactorMaintenance.Godot/Data/FrontendSession.cs
Normal file
62
src/ReactorMaintenance.Godot/Data/FrontendSession.cs
Normal file
@@ -0,0 +1,62 @@
|
||||
namespace ReactorMaintenance.Godot.Data;
|
||||
|
||||
public sealed class FrontendSession
|
||||
{
|
||||
public FrontendSession(CampaignManifest campaign)
|
||||
{
|
||||
m_Campaign = campaign;
|
||||
}
|
||||
|
||||
public void StartNewCampaign()
|
||||
{
|
||||
IsRandomLevel = false;
|
||||
CampaignIndex = 0;
|
||||
HasContinue = true;
|
||||
}
|
||||
|
||||
public void ContinueCampaign()
|
||||
{
|
||||
IsRandomLevel = false;
|
||||
HasContinue = true;
|
||||
}
|
||||
|
||||
public void StartRandomLevel()
|
||||
{
|
||||
IsRandomLevel = true;
|
||||
}
|
||||
|
||||
public void MarkCurrentLevelLoaded()
|
||||
{
|
||||
if (!IsRandomLevel)
|
||||
HasContinue = true;
|
||||
}
|
||||
|
||||
public void AdvanceToNextLevel()
|
||||
{
|
||||
if (HasNextLevel)
|
||||
CampaignIndex++;
|
||||
}
|
||||
|
||||
public void CompleteCampaign()
|
||||
{
|
||||
IsRandomLevel = false;
|
||||
CampaignIndex = 0;
|
||||
HasContinue = false;
|
||||
}
|
||||
|
||||
public bool HasContinue { get; private set; }
|
||||
public bool IsRandomLevel { get; private set; }
|
||||
public int CampaignIndex { get; private set; }
|
||||
public CampaignLevel CurrentLevel => IsRandomLevel ? m_RandomLevel : m_Campaign.Levels[CampaignIndex];
|
||||
public int LevelNumber => IsRandomLevel ? 1 : CampaignIndex + 1;
|
||||
public int LevelCount => IsRandomLevel ? 1 : m_Campaign.Levels.Count;
|
||||
public bool HasNextLevel => !IsRandomLevel && CampaignIndex + 1 < m_Campaign.Levels.Count;
|
||||
private readonly CampaignManifest m_Campaign;
|
||||
|
||||
private readonly CampaignLevel m_RandomLevel = new() {
|
||||
Id = "random-maintenance",
|
||||
Name = "Random Maintenance Shift",
|
||||
FlavorText = "A generated shift will use authored JSON level data until generation is implemented.",
|
||||
LevelPath = "res://Data/Levels/random_placeholder.json"
|
||||
};
|
||||
}
|
||||
1
src/ReactorMaintenance.Godot/Data/FrontendSession.cs.uid
Normal file
1
src/ReactorMaintenance.Godot/Data/FrontendSession.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://bsbukw3qpo0by
|
||||
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"levels": [
|
||||
{
|
||||
"id": "coolant-restart",
|
||||
"name": "Coolant Restart",
|
||||
"flavorText": "The lower coolant loop is starving the reactor core. Restore enough service to keep the first startup window alive.",
|
||||
"levelPath": "res://Data/Levels/coolant_restart.json"
|
||||
},
|
||||
{
|
||||
"id": "fuel-bleed",
|
||||
"name": "Fuel Bleed",
|
||||
"flavorText": "A fuel manifold is venting through the maintenance deck. Isolate the leak before pressure cascades into the ignition zone.",
|
||||
"levelPath": "res://Data/Levels/fuel_bleed.json"
|
||||
},
|
||||
{
|
||||
"id": "black-start",
|
||||
"name": "Black Start",
|
||||
"flavorText": "The final reactor needs fuel, coolant, and electricity in balance before the station can carry load again.",
|
||||
"levelPath": "res://Data/Levels/black_start.json"
|
||||
}
|
||||
]
|
||||
}
|
||||
12
src/ReactorMaintenance.Godot/Scenes/CampaignIntro.tscn
Normal file
12
src/ReactorMaintenance.Godot/Scenes/CampaignIntro.tscn
Normal file
@@ -0,0 +1,12 @@
|
||||
[gd_scene load_steps=2 format=3]
|
||||
|
||||
[ext_resource type="Script" path="res://Screens/CampaignIntro.cs" id="1"]
|
||||
|
||||
[node name="CampaignIntro" type="Control"]
|
||||
layout_mode = 3
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
script = ExtResource("1")
|
||||
@@ -0,0 +1,6 @@
|
||||
[gd_scene load_steps=2 format=3]
|
||||
|
||||
[ext_resource type="Script" path="res://Controls/CellInspector.cs" id="1"]
|
||||
|
||||
[node name="CellInspector" type="PanelContainer"]
|
||||
script = ExtResource("1")
|
||||
@@ -0,0 +1,6 @@
|
||||
[gd_scene load_steps=2 format=3]
|
||||
|
||||
[ext_resource type="Script" path="res://Controls/ConfirmDialog.cs" id="1"]
|
||||
|
||||
[node name="ConfirmDialog" type="PanelContainer"]
|
||||
script = ExtResource("1")
|
||||
@@ -0,0 +1,6 @@
|
||||
[gd_scene load_steps=2 format=3]
|
||||
|
||||
[ext_resource type="Script" path="res://Controls/ForecastList.cs" id="1"]
|
||||
|
||||
[node name="ForecastList" type="PanelContainer"]
|
||||
script = ExtResource("1")
|
||||
@@ -0,0 +1,6 @@
|
||||
[gd_scene load_steps=2 format=3]
|
||||
|
||||
[ext_resource type="Script" path="res://Controls/InventoryStrip.cs" id="1"]
|
||||
|
||||
[node name="InventoryStrip" type="HBoxContainer"]
|
||||
script = ExtResource("1")
|
||||
@@ -0,0 +1,6 @@
|
||||
[gd_scene load_steps=2 format=3]
|
||||
|
||||
[ext_resource type="Script" path="res://Controls/LevelHeader.cs" id="1"]
|
||||
|
||||
[node name="LevelHeader" type="HBoxContainer"]
|
||||
script = ExtResource("1")
|
||||
@@ -0,0 +1,6 @@
|
||||
[gd_scene load_steps=2 format=3]
|
||||
|
||||
[ext_resource type="Script" path="res://Controls/OutcomeOverlay.cs" id="1"]
|
||||
|
||||
[node name="OutcomeOverlay" type="PanelContainer"]
|
||||
script = ExtResource("1")
|
||||
@@ -0,0 +1,6 @@
|
||||
[gd_scene load_steps=2 format=3]
|
||||
|
||||
[ext_resource type="Script" path="res://Controls/PrimaryButton.cs" id="1"]
|
||||
|
||||
[node name="PrimaryButton" type="Button"]
|
||||
script = ExtResource("1")
|
||||
@@ -0,0 +1,6 @@
|
||||
[gd_scene load_steps=2 format=3]
|
||||
|
||||
[ext_resource type="Script" path="res://Controls/StateBadge.cs" id="1"]
|
||||
|
||||
[node name="StateBadge" type="Label"]
|
||||
script = ExtResource("1")
|
||||
12
src/ReactorMaintenance.Godot/Scenes/GameOverScreen.tscn
Normal file
12
src/ReactorMaintenance.Godot/Scenes/GameOverScreen.tscn
Normal file
@@ -0,0 +1,12 @@
|
||||
[gd_scene load_steps=2 format=3]
|
||||
|
||||
[ext_resource type="Script" path="res://Screens/GameOverScreen.cs" id="1"]
|
||||
|
||||
[node name="GameOverScreen" type="Control"]
|
||||
layout_mode = 3
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
script = ExtResource("1")
|
||||
12
src/ReactorMaintenance.Godot/Scenes/GameWonScreen.tscn
Normal file
12
src/ReactorMaintenance.Godot/Scenes/GameWonScreen.tscn
Normal file
@@ -0,0 +1,12 @@
|
||||
[gd_scene load_steps=2 format=3]
|
||||
|
||||
[ext_resource type="Script" path="res://Screens/GameWonScreen.cs" id="1"]
|
||||
|
||||
[node name="GameWonScreen" type="Control"]
|
||||
layout_mode = 3
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
script = ExtResource("1")
|
||||
12
src/ReactorMaintenance.Godot/Scenes/GenerationScreen.tscn
Normal file
12
src/ReactorMaintenance.Godot/Scenes/GenerationScreen.tscn
Normal file
@@ -0,0 +1,12 @@
|
||||
[gd_scene load_steps=2 format=3]
|
||||
|
||||
[ext_resource type="Script" path="res://Screens/GenerationScreen.cs" id="1"]
|
||||
|
||||
[node name="GenerationScreen" type="Control"]
|
||||
layout_mode = 3
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
script = ExtResource("1")
|
||||
12
src/ReactorMaintenance.Godot/Scenes/LevelScreen.tscn
Normal file
12
src/ReactorMaintenance.Godot/Scenes/LevelScreen.tscn
Normal file
@@ -0,0 +1,12 @@
|
||||
[gd_scene load_steps=2 format=3]
|
||||
|
||||
[ext_resource type="Script" path="res://Screens/LevelScreen.cs" id="1"]
|
||||
|
||||
[node name="LevelScreen" type="Control"]
|
||||
layout_mode = 3
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
script = ExtResource("1")
|
||||
6
src/ReactorMaintenance.Godot/Scenes/LoseOverlay.tscn
Normal file
6
src/ReactorMaintenance.Godot/Scenes/LoseOverlay.tscn
Normal file
@@ -0,0 +1,6 @@
|
||||
[gd_scene load_steps=2 format=3]
|
||||
|
||||
[ext_resource type="Script" path="res://Screens/LoseOverlay.cs" id="1"]
|
||||
|
||||
[node name="LoseOverlay" type="PanelContainer"]
|
||||
script = ExtResource("1")
|
||||
12
src/ReactorMaintenance.Godot/Scenes/MainMenu.tscn
Normal file
12
src/ReactorMaintenance.Godot/Scenes/MainMenu.tscn
Normal file
@@ -0,0 +1,12 @@
|
||||
[gd_scene load_steps=2 format=3]
|
||||
|
||||
[ext_resource type="Script" path="res://Screens/MainMenu.cs" id="1"]
|
||||
|
||||
[node name="MainMenu" type="Control"]
|
||||
layout_mode = 3
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
script = ExtResource("1")
|
||||
12
src/ReactorMaintenance.Godot/Scenes/OptionsScreen.tscn
Normal file
12
src/ReactorMaintenance.Godot/Scenes/OptionsScreen.tscn
Normal file
@@ -0,0 +1,12 @@
|
||||
[gd_scene load_steps=2 format=3]
|
||||
|
||||
[ext_resource type="Script" path="res://Screens/OptionsScreen.cs" id="1"]
|
||||
|
||||
[node name="OptionsScreen" type="Control"]
|
||||
layout_mode = 3
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
script = ExtResource("1")
|
||||
12
src/ReactorMaintenance.Godot/Scenes/SplashScreen.tscn
Normal file
12
src/ReactorMaintenance.Godot/Scenes/SplashScreen.tscn
Normal file
@@ -0,0 +1,12 @@
|
||||
[gd_scene load_steps=2 format=3]
|
||||
|
||||
[ext_resource type="Script" path="res://Screens/SplashScreen.cs" id="1"]
|
||||
|
||||
[node name="SplashScreen" type="Control"]
|
||||
layout_mode = 3
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
script = ExtResource("1")
|
||||
12
src/ReactorMaintenance.Godot/Scenes/TutorialScreen.tscn
Normal file
12
src/ReactorMaintenance.Godot/Scenes/TutorialScreen.tscn
Normal file
@@ -0,0 +1,12 @@
|
||||
[gd_scene load_steps=2 format=3]
|
||||
|
||||
[ext_resource type="Script" path="res://Screens/TutorialScreen.cs" id="1"]
|
||||
|
||||
[node name="TutorialScreen" type="Control"]
|
||||
layout_mode = 3
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
script = ExtResource("1")
|
||||
6
src/ReactorMaintenance.Godot/Scenes/WinOverlay.tscn
Normal file
6
src/ReactorMaintenance.Godot/Scenes/WinOverlay.tscn
Normal file
@@ -0,0 +1,6 @@
|
||||
[gd_scene load_steps=2 format=3]
|
||||
|
||||
[ext_resource type="Script" path="res://Screens/WinOverlay.cs" id="1"]
|
||||
|
||||
[node name="WinOverlay" type="PanelContainer"]
|
||||
script = ExtResource("1")
|
||||
20
src/ReactorMaintenance.Godot/Screens/CampaignIntro.cs
Normal file
20
src/ReactorMaintenance.Godot/Screens/CampaignIntro.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
using Godot;
|
||||
using ReactorMaintenance.Godot.Data;
|
||||
|
||||
namespace ReactorMaintenance.Godot.Screens;
|
||||
|
||||
public partial class CampaignIntro : ScreenBase
|
||||
{
|
||||
public void Configure(AppController app, CampaignLevel level, int levelNumber, int levelCount)
|
||||
{
|
||||
var body = CreatePage(level.Name);
|
||||
body.Alignment = BoxContainer.AlignmentMode.Center;
|
||||
body.AddChild(CreateBodyText($"Campaign level {levelNumber} / {levelCount}"));
|
||||
body.AddChild(CreateBodyText(level.FlavorText));
|
||||
|
||||
var actions = new HBoxContainer { SizeFlagsHorizontal = SizeFlags.ShrinkCenter };
|
||||
body.AddChild(actions);
|
||||
actions.AddChild(CreateButton("Begin", app.LoadCurrentLevel));
|
||||
actions.AddChild(CreateButton("Back", app.ShowMainMenu));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
uid://cd0ffydc3pdc2
|
||||
19
src/ReactorMaintenance.Godot/Screens/GameOverScreen.cs
Normal file
19
src/ReactorMaintenance.Godot/Screens/GameOverScreen.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using Godot;
|
||||
using ReactorMaintenance.Godot.Data;
|
||||
|
||||
namespace ReactorMaintenance.Godot.Screens;
|
||||
|
||||
public partial class GameOverScreen : ScreenBase
|
||||
{
|
||||
public void Configure(AppController app, CampaignLevel level)
|
||||
{
|
||||
var body = CreatePage("Game Over");
|
||||
body.Alignment = BoxContainer.AlignmentMode.Center;
|
||||
body.AddChild(CreateBodyText($"Failed level: {level.Name}"));
|
||||
|
||||
var actions = new HBoxContainer { SizeFlagsHorizontal = SizeFlags.ShrinkCenter };
|
||||
body.AddChild(actions);
|
||||
actions.AddChild(CreateButton("Retry Current Level", app.RetryCurrentLevel));
|
||||
actions.AddChild(CreateButton("Main Menu", app.ShowMainMenu));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
uid://d1ncb4ysjstdd
|
||||
15
src/ReactorMaintenance.Godot/Screens/GameWonScreen.cs
Normal file
15
src/ReactorMaintenance.Godot/Screens/GameWonScreen.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
using Godot;
|
||||
|
||||
namespace ReactorMaintenance.Godot.Screens;
|
||||
|
||||
public partial class GameWonScreen : ScreenBase
|
||||
{
|
||||
public void Configure(AppController app, int completedLevels)
|
||||
{
|
||||
var body = CreatePage("Campaign Complete");
|
||||
body.Alignment = BoxContainer.AlignmentMode.Center;
|
||||
body.AddChild(CreateBodyText($"All {completedLevels} handcrafted reactor incidents are resolved."));
|
||||
body.AddChild(CreateBodyText("The maintenance crew has restored enough capacity to bring the station back online."));
|
||||
body.AddChild(CreateButton("Main Menu", app.ShowMainMenu));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
uid://cfijlvnlio424
|
||||
20
src/ReactorMaintenance.Godot/Screens/GenerationScreen.cs
Normal file
20
src/ReactorMaintenance.Godot/Screens/GenerationScreen.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
using Godot;
|
||||
using ReactorMaintenance.Godot.Data;
|
||||
|
||||
namespace ReactorMaintenance.Godot.Screens;
|
||||
|
||||
public partial class GenerationScreen : ScreenBase
|
||||
{
|
||||
public void Configure(AppController app, CampaignLevel level)
|
||||
{
|
||||
var body = CreatePage("Random Level");
|
||||
body.Alignment = BoxContainer.AlignmentMode.Center;
|
||||
body.AddChild(CreateBodyText(level.FlavorText));
|
||||
body.AddChild(CreateBodyText($"Future level JSON: {level.LevelPath}"));
|
||||
|
||||
var actions = new HBoxContainer { SizeFlagsHorizontal = SizeFlags.ShrinkCenter };
|
||||
body.AddChild(actions);
|
||||
actions.AddChild(CreateButton("Begin", app.LoadCurrentLevel));
|
||||
actions.AddChild(CreateButton("Back", app.ShowMainMenu));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
uid://cs63x3a7h8pad
|
||||
107
src/ReactorMaintenance.Godot/Screens/LevelScreen.cs
Normal file
107
src/ReactorMaintenance.Godot/Screens/LevelScreen.cs
Normal file
@@ -0,0 +1,107 @@
|
||||
using Godot;
|
||||
using ReactorMaintenance.Godot.Controls;
|
||||
using ReactorMaintenance.Godot.Data;
|
||||
|
||||
namespace ReactorMaintenance.Godot.Screens;
|
||||
|
||||
public partial class LevelScreen : ScreenBase
|
||||
{
|
||||
public void Configure(AppController app, CampaignLevel level, int levelNumber, int levelCount)
|
||||
{
|
||||
m_App = app;
|
||||
m_Level = level;
|
||||
|
||||
var body = CreatePage(string.Empty);
|
||||
var header = new LevelHeader();
|
||||
body.AddChild(header);
|
||||
header.SetLevel(level, levelNumber, levelCount, "Stable");
|
||||
|
||||
var flavor = CreateBodyText(level.FlavorText);
|
||||
flavor.HorizontalAlignment = HorizontalAlignment.Left;
|
||||
body.AddChild(flavor);
|
||||
|
||||
var split = new HSplitContainer { SizeFlagsVertical = SizeFlags.ExpandFill };
|
||||
body.AddChild(split);
|
||||
|
||||
split.AddChild(CreateGridPlaceholder());
|
||||
split.AddChild(CreateSidePanel(level));
|
||||
|
||||
body.AddChild(new InventoryStrip());
|
||||
body.AddChild(CreateActionBar());
|
||||
|
||||
m_OverlayLayer = new();
|
||||
AddChild(m_OverlayLayer);
|
||||
}
|
||||
|
||||
private static PanelContainer CreateGridPlaceholder()
|
||||
{
|
||||
var panel = new PanelContainer { CustomMinimumSize = new(560, 360), SizeFlagsHorizontal = SizeFlags.ExpandFill, SizeFlagsVertical = SizeFlags.ExpandFill };
|
||||
var label = new Label {
|
||||
Text = "Level Grid Placeholder\nRobot marker, terrain, props, hazards, and underground overlays will render here.",
|
||||
HorizontalAlignment = HorizontalAlignment.Center,
|
||||
VerticalAlignment = VerticalAlignment.Center,
|
||||
AutowrapMode = TextServer.AutowrapMode.WordSmart
|
||||
};
|
||||
panel.AddChild(label);
|
||||
return panel;
|
||||
}
|
||||
|
||||
private static VBoxContainer CreateSidePanel(CampaignLevel level)
|
||||
{
|
||||
var sidePanel = new VBoxContainer { CustomMinimumSize = new(300, 0) };
|
||||
sidePanel.AddChild(new Label { Text = "Inspector" });
|
||||
sidePanel.AddChild(new CellInspector());
|
||||
sidePanel.AddChild(new ForecastList());
|
||||
sidePanel.AddChild(new Label { Text = $"Level JSON: {level.LevelPath}", AutowrapMode = TextServer.AutowrapMode.WordSmart });
|
||||
return sidePanel;
|
||||
}
|
||||
|
||||
private HBoxContainer CreateActionBar()
|
||||
{
|
||||
var actions = new HBoxContainer();
|
||||
actions.AddChild(CreateButton("Move", () => { }, "Quick action placeholder"));
|
||||
actions.AddChild(CreateButton("Interact", () => { }, "Lengthy action placeholder"));
|
||||
actions.AddChild(CreateButton("Repair", () => { }, "Lengthy action placeholder"));
|
||||
actions.AddChild(CreateButton("Trigger Win", ShowWinOverlay));
|
||||
actions.AddChild(CreateButton("Trigger Lose", ShowLoseOverlay));
|
||||
actions.AddChild(CreateButton("Main Menu", () => m_App?.ShowMainMenu()));
|
||||
return actions;
|
||||
}
|
||||
|
||||
private void ShowLoseOverlay()
|
||||
{
|
||||
if (m_OutcomeVisible || m_App is null || m_Level is null || m_OverlayLayer is null)
|
||||
return;
|
||||
|
||||
m_OutcomeVisible = true;
|
||||
var overlay = new LoseOverlay();
|
||||
overlay.Configure(m_Level, m_App.RetryCurrentLevel, m_App.ShowGameOver, m_App.ShowMainMenu);
|
||||
AddCenteredOverlay(overlay);
|
||||
}
|
||||
|
||||
private void ShowWinOverlay()
|
||||
{
|
||||
if (m_OutcomeVisible || m_App is null || m_Level is null || m_OverlayLayer is null)
|
||||
return;
|
||||
|
||||
m_OutcomeVisible = true;
|
||||
var overlay = new WinOverlay();
|
||||
overlay.Configure(m_Level, m_App.CompleteCurrentLevel, m_App.ShowMainMenu);
|
||||
AddCenteredOverlay(overlay);
|
||||
}
|
||||
|
||||
private void AddCenteredOverlay(Control overlay)
|
||||
{
|
||||
var center = new CenterContainer {
|
||||
AnchorRight = 1,
|
||||
AnchorBottom = 1
|
||||
};
|
||||
center.AddChild(overlay);
|
||||
m_OverlayLayer?.AddChild(center);
|
||||
}
|
||||
|
||||
private AppController? m_App;
|
||||
private CampaignLevel? m_Level;
|
||||
private bool m_OutcomeVisible;
|
||||
private CanvasLayer? m_OverlayLayer;
|
||||
}
|
||||
1
src/ReactorMaintenance.Godot/Screens/LevelScreen.cs.uid
Normal file
1
src/ReactorMaintenance.Godot/Screens/LevelScreen.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://dix1dibqgxr3y
|
||||
19
src/ReactorMaintenance.Godot/Screens/LoseOverlay.cs
Normal file
19
src/ReactorMaintenance.Godot/Screens/LoseOverlay.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using ReactorMaintenance.Godot.Controls;
|
||||
using ReactorMaintenance.Godot.Data;
|
||||
|
||||
namespace ReactorMaintenance.Godot.Screens;
|
||||
|
||||
public partial class LoseOverlay : OutcomeOverlay
|
||||
{
|
||||
public void Configure(CampaignLevel level, Action retryLevel, Action openGameOver, Action mainMenu)
|
||||
{
|
||||
Configure(
|
||||
"Level Lost",
|
||||
$"{level.Name} has failed. Retry reloads the level from its starting snapshot.",
|
||||
[
|
||||
("Retry Level", retryLevel),
|
||||
("Game Over", openGameOver),
|
||||
("Main Menu", mainMenu)
|
||||
]);
|
||||
}
|
||||
}
|
||||
1
src/ReactorMaintenance.Godot/Screens/LoseOverlay.cs.uid
Normal file
1
src/ReactorMaintenance.Godot/Screens/LoseOverlay.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://bvonbqula7dxq
|
||||
26
src/ReactorMaintenance.Godot/Screens/MainMenu.cs
Normal file
26
src/ReactorMaintenance.Godot/Screens/MainMenu.cs
Normal file
@@ -0,0 +1,26 @@
|
||||
using Godot;
|
||||
|
||||
namespace ReactorMaintenance.Godot.Screens;
|
||||
|
||||
public partial class MainMenu : ScreenBase
|
||||
{
|
||||
public void Configure(AppController app, bool hasContinue)
|
||||
{
|
||||
var body = CreatePage("Reactor Maintenance");
|
||||
body.Alignment = BoxContainer.AlignmentMode.Center;
|
||||
|
||||
var commands = new VBoxContainer {
|
||||
CustomMinimumSize = new(320, 0),
|
||||
SizeFlagsHorizontal = SizeFlags.ShrinkCenter
|
||||
};
|
||||
body.AddChild(commands);
|
||||
|
||||
commands.AddChild(CreateButton("New Campaign", app.StartNewCampaign));
|
||||
commands.AddChild(CreateButton("Continue Campaign", app.ContinueCampaign, "No campaign progress exists yet.", !hasContinue));
|
||||
commands.AddChild(CreateButton("Play Random Level", app.StartRandomLevel));
|
||||
commands.AddChild(CreateButton("Options", app.ShowOptions));
|
||||
commands.AddChild(CreateButton("Tutorial", app.ShowTutorial));
|
||||
|
||||
body.AddChild(CreateBodyText("Godot frontend prototype"));
|
||||
}
|
||||
}
|
||||
1
src/ReactorMaintenance.Godot/Screens/MainMenu.cs.uid
Normal file
1
src/ReactorMaintenance.Godot/Screens/MainMenu.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://dj4he4y5anmdy
|
||||
26
src/ReactorMaintenance.Godot/Screens/OptionsScreen.cs
Normal file
26
src/ReactorMaintenance.Godot/Screens/OptionsScreen.cs
Normal file
@@ -0,0 +1,26 @@
|
||||
using Godot;
|
||||
|
||||
namespace ReactorMaintenance.Godot.Screens;
|
||||
|
||||
public partial class OptionsScreen : ScreenBase
|
||||
{
|
||||
public void Configure(AppController app)
|
||||
{
|
||||
var body = CreatePage("Options");
|
||||
body.Alignment = BoxContainer.AlignmentMode.Center;
|
||||
|
||||
body.AddChild(CreateSlider("Master Volume"));
|
||||
body.AddChild(CreateSlider("Music Volume"));
|
||||
body.AddChild(new CheckBox { Text = "Fullscreen" });
|
||||
body.AddChild(new OptionButton { Text = "UI Scale" });
|
||||
body.AddChild(CreateButton("Back", app.ShowMainMenu));
|
||||
}
|
||||
|
||||
private static HBoxContainer CreateSlider(string label)
|
||||
{
|
||||
var row = new HBoxContainer { CustomMinimumSize = new(360, 40), SizeFlagsHorizontal = SizeFlags.ShrinkCenter };
|
||||
row.AddChild(new Label { Text = label, CustomMinimumSize = new(140, 0) });
|
||||
row.AddChild(new HSlider { MinValue = 0, MaxValue = 100, Value = 75, SizeFlagsHorizontal = SizeFlags.ExpandFill });
|
||||
return row;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
uid://bkf0ctd7yk656
|
||||
58
src/ReactorMaintenance.Godot/Screens/ScreenBase.cs
Normal file
58
src/ReactorMaintenance.Godot/Screens/ScreenBase.cs
Normal file
@@ -0,0 +1,58 @@
|
||||
using Godot;
|
||||
using ReactorMaintenance.Godot.Controls;
|
||||
|
||||
namespace ReactorMaintenance.Godot.Screens;
|
||||
|
||||
public abstract partial class ScreenBase : Control
|
||||
{
|
||||
protected VBoxContainer CreatePage(string title)
|
||||
{
|
||||
foreach (var child in GetChildren())
|
||||
child.QueueFree();
|
||||
|
||||
SetAnchorsPreset(LayoutPreset.FullRect);
|
||||
|
||||
var margin = new MarginContainer {
|
||||
AnchorRight = 1,
|
||||
AnchorBottom = 1
|
||||
};
|
||||
margin.AddThemeConstantOverride("margin_left", 48);
|
||||
margin.AddThemeConstantOverride("margin_top", 36);
|
||||
margin.AddThemeConstantOverride("margin_right", 48);
|
||||
margin.AddThemeConstantOverride("margin_bottom", 36);
|
||||
AddChild(margin);
|
||||
|
||||
var body = new VBoxContainer {
|
||||
SizeFlagsHorizontal = SizeFlags.ExpandFill,
|
||||
SizeFlagsVertical = SizeFlags.ExpandFill
|
||||
};
|
||||
margin.AddChild(body);
|
||||
|
||||
var titleLabel = new Label {
|
||||
Text = title,
|
||||
HorizontalAlignment = HorizontalAlignment.Center
|
||||
};
|
||||
titleLabel.AddThemeFontSizeOverride("font_size", 32);
|
||||
body.AddChild(titleLabel);
|
||||
|
||||
return body;
|
||||
}
|
||||
|
||||
protected static PrimaryButton CreateButton(string text, Action pressed, string tooltip = "", bool disabled = false)
|
||||
{
|
||||
var button = new PrimaryButton();
|
||||
button.Configure(text, tooltip, disabled);
|
||||
button.Pressed += pressed;
|
||||
return button;
|
||||
}
|
||||
|
||||
protected static Label CreateBodyText(string text)
|
||||
{
|
||||
return new() {
|
||||
Text = text,
|
||||
AutowrapMode = TextServer.AutowrapMode.WordSmart,
|
||||
HorizontalAlignment = HorizontalAlignment.Center,
|
||||
SizeFlagsHorizontal = SizeFlags.ExpandFill
|
||||
};
|
||||
}
|
||||
}
|
||||
1
src/ReactorMaintenance.Godot/Screens/ScreenBase.cs.uid
Normal file
1
src/ReactorMaintenance.Godot/Screens/ScreenBase.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://dcwn6wqeikkpn
|
||||
33
src/ReactorMaintenance.Godot/Screens/SplashScreen.cs
Normal file
33
src/ReactorMaintenance.Godot/Screens/SplashScreen.cs
Normal file
@@ -0,0 +1,33 @@
|
||||
using Godot;
|
||||
|
||||
namespace ReactorMaintenance.Godot.Screens;
|
||||
|
||||
public partial class SplashScreen : ScreenBase
|
||||
{
|
||||
public event Action? Started;
|
||||
|
||||
public override void _Ready()
|
||||
{
|
||||
var body = CreatePage("Reactor Maintenance");
|
||||
body.Alignment = BoxContainer.AlignmentMode.Center;
|
||||
body.AddChild(CreateBodyText("Systems booting..."));
|
||||
GetTree().CreateTimer(1.2).Timeout += Start;
|
||||
}
|
||||
|
||||
public override void _UnhandledInput(InputEvent @event)
|
||||
{
|
||||
if (@event.IsPressed())
|
||||
Start();
|
||||
}
|
||||
|
||||
private void Start()
|
||||
{
|
||||
if (m_Transitioned)
|
||||
return;
|
||||
|
||||
m_Transitioned = true;
|
||||
Started?.Invoke();
|
||||
}
|
||||
|
||||
private bool m_Transitioned;
|
||||
}
|
||||
1
src/ReactorMaintenance.Godot/Screens/SplashScreen.cs.uid
Normal file
1
src/ReactorMaintenance.Godot/Screens/SplashScreen.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://yiggx6pgqntg
|
||||
18
src/ReactorMaintenance.Godot/Screens/TutorialScreen.cs
Normal file
18
src/ReactorMaintenance.Godot/Screens/TutorialScreen.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
using Godot;
|
||||
|
||||
namespace ReactorMaintenance.Godot.Screens;
|
||||
|
||||
public partial class TutorialScreen : ScreenBase
|
||||
{
|
||||
public void Configure(AppController app)
|
||||
{
|
||||
var body = CreatePage("Tutorial");
|
||||
body.Alignment = BoxContainer.AlignmentMode.Center;
|
||||
body.AddChild(CreateBodyText("Topics: action economy, hazards, forecasts, remedies, heat shields, and reactor activation."));
|
||||
|
||||
var actions = new HBoxContainer { SizeFlagsHorizontal = SizeFlags.ShrinkCenter };
|
||||
body.AddChild(actions);
|
||||
actions.AddChild(CreateButton("Start Tutorial Level", app.StartRandomLevel));
|
||||
actions.AddChild(CreateButton("Back", app.ShowMainMenu));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
uid://xfq61pdayub7
|
||||
18
src/ReactorMaintenance.Godot/Screens/WinOverlay.cs
Normal file
18
src/ReactorMaintenance.Godot/Screens/WinOverlay.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
using ReactorMaintenance.Godot.Controls;
|
||||
using ReactorMaintenance.Godot.Data;
|
||||
|
||||
namespace ReactorMaintenance.Godot.Screens;
|
||||
|
||||
public partial class WinOverlay : OutcomeOverlay
|
||||
{
|
||||
public void Configure(CampaignLevel level, Action nextLevel, Action mainMenu)
|
||||
{
|
||||
Configure(
|
||||
"Reactor Online",
|
||||
$"{level.Name} is stabilized. Continue loads the next campaign level or campaign completion screen.",
|
||||
[
|
||||
("Continue", nextLevel),
|
||||
("Main Menu", mainMenu)
|
||||
]);
|
||||
}
|
||||
}
|
||||
1
src/ReactorMaintenance.Godot/Screens/WinOverlay.cs.uid
Normal file
1
src/ReactorMaintenance.Godot/Screens/WinOverlay.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://cqiqwgr0usmki
|
||||
110
src/ReactorMaintenance.Godot/Scripts/AppController.cs
Normal file
110
src/ReactorMaintenance.Godot/Scripts/AppController.cs
Normal file
@@ -0,0 +1,110 @@
|
||||
using Godot;
|
||||
using ReactorMaintenance.Godot.Data;
|
||||
using ReactorMaintenance.Godot.Screens;
|
||||
|
||||
namespace ReactorMaintenance.Godot;
|
||||
|
||||
public partial class AppController : Control
|
||||
{
|
||||
public override void _Ready()
|
||||
{
|
||||
ShowSplash();
|
||||
}
|
||||
|
||||
public void ShowSplash()
|
||||
{
|
||||
ShowScreen<SplashScreen>("res://Scenes/SplashScreen.tscn", screen => screen.Started += ShowMainMenu);
|
||||
}
|
||||
|
||||
public void ShowMainMenu()
|
||||
{
|
||||
ShowScreen<MainMenu>("res://Scenes/MainMenu.tscn", screen => screen.Configure(this, m_Session.HasContinue));
|
||||
}
|
||||
|
||||
public void StartNewCampaign()
|
||||
{
|
||||
m_Session.StartNewCampaign();
|
||||
ShowCampaignIntro();
|
||||
}
|
||||
|
||||
public void ContinueCampaign()
|
||||
{
|
||||
m_Session.ContinueCampaign();
|
||||
LoadCurrentLevel();
|
||||
}
|
||||
|
||||
public void StartRandomLevel()
|
||||
{
|
||||
m_Session.StartRandomLevel();
|
||||
ShowScreen<GenerationScreen>("res://Scenes/GenerationScreen.tscn", screen => screen.Configure(this, m_Session.CurrentLevel));
|
||||
}
|
||||
|
||||
public void ShowCampaignIntro()
|
||||
{
|
||||
ShowScreen<CampaignIntro>("res://Scenes/CampaignIntro.tscn", screen => screen.Configure(this, m_Session.CurrentLevel, m_Session.LevelNumber, m_Session.LevelCount));
|
||||
}
|
||||
|
||||
public void LoadCurrentLevel()
|
||||
{
|
||||
m_Session.MarkCurrentLevelLoaded();
|
||||
ShowScreen<LevelScreen>("res://Scenes/LevelScreen.tscn", screen => screen.Configure(this, m_Session.CurrentLevel, m_Session.LevelNumber, m_Session.LevelCount));
|
||||
}
|
||||
|
||||
public void RetryCurrentLevel()
|
||||
{
|
||||
LoadCurrentLevel();
|
||||
}
|
||||
|
||||
public void CompleteCurrentLevel()
|
||||
{
|
||||
if (m_Session.IsRandomLevel)
|
||||
{
|
||||
StartRandomLevel();
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_Session.HasNextLevel)
|
||||
{
|
||||
m_Session.AdvanceToNextLevel();
|
||||
ShowCampaignIntro();
|
||||
return;
|
||||
}
|
||||
|
||||
m_Session.CompleteCampaign();
|
||||
ShowGameWon();
|
||||
}
|
||||
|
||||
public void ShowOptions()
|
||||
{
|
||||
ShowScreen<OptionsScreen>("res://Scenes/OptionsScreen.tscn", screen => screen.Configure(this));
|
||||
}
|
||||
|
||||
public void ShowTutorial()
|
||||
{
|
||||
ShowScreen<TutorialScreen>("res://Scenes/TutorialScreen.tscn", screen => screen.Configure(this));
|
||||
}
|
||||
|
||||
public void ShowGameOver()
|
||||
{
|
||||
ShowScreen<GameOverScreen>("res://Scenes/GameOverScreen.tscn", screen => screen.Configure(this, m_Session.CurrentLevel));
|
||||
}
|
||||
|
||||
private void ShowGameWon()
|
||||
{
|
||||
ShowScreen<GameWonScreen>("res://Scenes/GameWonScreen.tscn", screen => screen.Configure(this, m_Session.LevelCount));
|
||||
}
|
||||
|
||||
private void ShowScreen<TScreen>(string scenePath, Action<TScreen> configure) where TScreen : Control
|
||||
{
|
||||
m_CurrentScreen?.QueueFree();
|
||||
|
||||
var packedScene = ResourceLoader.Load<PackedScene>(scenePath);
|
||||
var screen = packedScene.Instantiate<TScreen>();
|
||||
m_CurrentScreen = screen;
|
||||
AddChild(screen);
|
||||
configure(screen);
|
||||
}
|
||||
|
||||
private readonly FrontendSession m_Session = new(CampaignRepository.LoadDefault());
|
||||
private Control? m_CurrentScreen;
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
uid://exf77g2sqb6d
|
||||
@@ -1,3 +1,12 @@
|
||||
[gd_scene format=3 uid="uid://bhhppnvto57ht"]
|
||||
[gd_scene load_steps=2 format=3 uid="uid://bhhppnvto57ht"]
|
||||
|
||||
[node name="Node2D" type="Node2D"]
|
||||
[ext_resource type="Script" path="res://Scripts/AppController.cs" id="1"]
|
||||
|
||||
[node name="Main" type="Control"]
|
||||
layout_mode = 3
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
script = ExtResource("1")
|
||||
|
||||
@@ -8,12 +8,10 @@
|
||||
|
||||
config_version=5
|
||||
|
||||
"config_version"=5
|
||||
|
||||
[application]
|
||||
|
||||
config/name="Reactor Maintenance"
|
||||
run/main_scene="uid://bhhppnvto57ht"
|
||||
run/main_scene="res://main.tscn"
|
||||
config/features=PackedStringArray("4.5", "C#", "Forward Plus")
|
||||
|
||||
[dotnet]
|
||||
|
||||
Reference in New Issue
Block a user