Added random seed and ability to enter a seed. Also added a simple/small tutorial screen and unified the UI with UIStyle.cs

This commit is contained in:
2026-05-09 22:09:15 +02:00
parent 7e70471227
commit fc21c7c8d3
12 changed files with 493 additions and 22 deletions
+82 -12
View File
@@ -19,6 +19,7 @@
[ext_resource type="Texture2D" uid="uid://dt84awx33mulb" path="res://Assets/Images/ResearchSymbol.png" id="13_alh3a"] [ext_resource type="Texture2D" uid="uid://dt84awx33mulb" path="res://Assets/Images/ResearchSymbol.png" id="13_alh3a"]
[ext_resource type="Texture2D" uid="uid://bmcpkt6mae2qi" path="res://Assets/Images/AlarmSign.png" id="13_x3xnh"] [ext_resource type="Texture2D" uid="uid://bmcpkt6mae2qi" path="res://Assets/Images/AlarmSign.png" id="13_x3xnh"]
[ext_resource type="Texture2D" uid="uid://uunnuou4g86w" path="res://Assets/Images/Resources/MushroomSymbol.png" id="14_food"] [ext_resource type="Texture2D" uid="uid://uunnuou4g86w" path="res://Assets/Images/Resources/MushroomSymbol.png" id="14_food"]
[ext_resource type="Script" path="res://Scripts/UI/Tutorial/TutorialBubble.cs" id="15_tutorial"]
[sub_resource type="CompressedTexture2D" id="CompressedTexture2D_u44n3"] [sub_resource type="CompressedTexture2D" id="CompressedTexture2D_u44n3"]
@@ -111,6 +112,7 @@ grow_vertical = 2
[node name="HeaderContainer" type="PanelContainer" parent="CanvasLayer/UIHandler/MainUI" unique_id=1744492333] [node name="HeaderContainer" type="PanelContainer" parent="CanvasLayer/UIHandler/MainUI" unique_id=1744492333]
layout_mode = 2 layout_mode = 2
custom_minimum_size = Vector2(0, 48)
theme_override_styles/panel = SubResource("StyleBoxFlat_b2bpf") theme_override_styles/panel = SubResource("StyleBoxFlat_b2bpf")
[node name="VBoxContainer" type="HBoxContainer" parent="CanvasLayer/UIHandler/MainUI/HeaderContainer" unique_id=536619770] [node name="VBoxContainer" type="HBoxContainer" parent="CanvasLayer/UIHandler/MainUI/HeaderContainer" unique_id=536619770]
@@ -179,7 +181,7 @@ vertical_alignment = 1
[node name="CurrentLayer" type="RichTextLabel" parent="CanvasLayer/UIHandler/MainUI/HeaderContainer/VBoxContainer" unique_id=1435047910] [node name="CurrentLayer" type="RichTextLabel" parent="CanvasLayer/UIHandler/MainUI/HeaderContainer/VBoxContainer" unique_id=1435047910]
layout_mode = 2 layout_mode = 2
text = "Current layer: XXX" text = "Layer: 1/10"
fit_content = true fit_content = true
autowrap_mode = 0 autowrap_mode = 0
horizontal_alignment = 1 horizontal_alignment = 1
@@ -187,7 +189,7 @@ vertical_alignment = 1
[node name="DeepestLayer" type="RichTextLabel" parent="CanvasLayer/UIHandler/MainUI/HeaderContainer/VBoxContainer" unique_id=600512938] [node name="DeepestLayer" type="RichTextLabel" parent="CanvasLayer/UIHandler/MainUI/HeaderContainer/VBoxContainer" unique_id=600512938]
layout_mode = 2 layout_mode = 2
text = "Deepest layer: XXX" text = "Gate depth: 0"
fit_content = true fit_content = true
autowrap_mode = 0 autowrap_mode = 0
horizontal_alignment = 1 horizontal_alignment = 1
@@ -195,7 +197,8 @@ vertical_alignment = 1
[node name="UnlockLayer" type="Button" parent="CanvasLayer/UIHandler/MainUI/HeaderContainer/VBoxContainer" unique_id=1538511285] [node name="UnlockLayer" type="Button" parent="CanvasLayer/UIHandler/MainUI/HeaderContainer/VBoxContainer" unique_id=1538511285]
layout_mode = 2 layout_mode = 2
text = "Unlock layer" tooltip_text = "Open the next gate when all requirements are available"
text = "Open Gate"
[node name="Content" type="Control" parent="CanvasLayer/UIHandler/MainUI" unique_id=45665557] [node name="Content" type="Control" parent="CanvasLayer/UIHandler/MainUI" unique_id=45665557]
layout_mode = 2 layout_mode = 2
@@ -226,7 +229,7 @@ theme_override_constants/separation = 20
[node name="Title" type="RichTextLabel" parent="CanvasLayer/UIHandler/MainUI/Content/CodingWindow/VBoxContainer" unique_id=90213926] [node name="Title" type="RichTextLabel" parent="CanvasLayer/UIHandler/MainUI/Content/CodingWindow/VBoxContainer" unique_id=90213926]
layout_mode = 2 layout_mode = 2
bbcode_enabled = true bbcode_enabled = true
text = "[font_size=32]Script editor[/font_size]" text = "[font_size=32]Robot Script[/font_size]"
fit_content = true fit_content = true
autowrap_mode = 0 autowrap_mode = 0
horizontal_alignment = 1 horizontal_alignment = 1
@@ -238,7 +241,7 @@ theme_override_constants/separation = 20
[node name="RichTextLabel" type="RichTextLabel" parent="CanvasLayer/UIHandler/MainUI/Content/CodingWindow/VBoxContainer/Renaming" unique_id=1964282829] [node name="RichTextLabel" type="RichTextLabel" parent="CanvasLayer/UIHandler/MainUI/Content/CodingWindow/VBoxContainer/Renaming" unique_id=1964282829]
layout_mode = 2 layout_mode = 2
size_flags_horizontal = 3 size_flags_horizontal = 3
text = "Rename your robot:" text = "Robot name"
fit_content = true fit_content = true
autowrap_mode = 0 autowrap_mode = 0
horizontal_alignment = 1 horizontal_alignment = 1
@@ -253,7 +256,7 @@ max_length = 24
[node name="Button" type="Button" parent="CanvasLayer/UIHandler/MainUI/Content/CodingWindow/VBoxContainer/Renaming" unique_id=279251707] [node name="Button" type="Button" parent="CanvasLayer/UIHandler/MainUI/Content/CodingWindow/VBoxContainer/Renaming" unique_id=279251707]
layout_mode = 2 layout_mode = 2
size_flags_horizontal = 3 size_flags_horizontal = 3
text = "Submit" text = "Apply"
[node name="Scripting" type="HBoxContainer" parent="CanvasLayer/UIHandler/MainUI/Content/CodingWindow/VBoxContainer" unique_id=1934932205] [node name="Scripting" type="HBoxContainer" parent="CanvasLayer/UIHandler/MainUI/Content/CodingWindow/VBoxContainer" unique_id=1934932205]
layout_mode = 2 layout_mode = 2
@@ -348,7 +351,7 @@ layout_mode = 2
[node name="Title" type="RichTextLabel" parent="CanvasLayer/UIHandler/MainUI/Content/RobotList/VBoxContainer" unique_id=1891991275] [node name="Title" type="RichTextLabel" parent="CanvasLayer/UIHandler/MainUI/Content/RobotList/VBoxContainer" unique_id=1891991275]
layout_mode = 2 layout_mode = 2
bbcode_enabled = true bbcode_enabled = true
text = "[font_size=32]Robotlist[/font_size]" text = "[font_size=32]Robots[/font_size]"
fit_content = true fit_content = true
autowrap_mode = 0 autowrap_mode = 0
horizontal_alignment = 1 horizontal_alignment = 1
@@ -409,15 +412,16 @@ anchor_left = 0.5
anchor_top = 0.5 anchor_top = 0.5
anchor_right = 0.5 anchor_right = 0.5
anchor_bottom = 0.5 anchor_bottom = 0.5
offset_left = -20.0 offset_left = -120.0
offset_top = -20.0 offset_top = -125.0
offset_right = 20.0 offset_right = 120.0
offset_bottom = 20.0 offset_bottom = 125.0
grow_horizontal = 2 grow_horizontal = 2
grow_vertical = 2 grow_vertical = 2
[node name="VBoxContainer" type="VBoxContainer" parent="CanvasLayer/UIHandler/MainUI/Content/Menu" unique_id=1924672355] [node name="VBoxContainer" type="VBoxContainer" parent="CanvasLayer/UIHandler/MainUI/Content/Menu" unique_id=1924672355]
layout_mode = 2 layout_mode = 2
theme_override_constants/separation = 10
[node name="Button" type="Button" parent="CanvasLayer/UIHandler/MainUI/Content/Menu/VBoxContainer" unique_id=1938871792] [node name="Button" type="Button" parent="CanvasLayer/UIHandler/MainUI/Content/Menu/VBoxContainer" unique_id=1938871792]
layout_mode = 2 layout_mode = 2
@@ -470,7 +474,7 @@ horizontal_alignment = 1
[node name="RichTextLabel" type="RichTextLabel" parent="CanvasLayer/UIHandler/MainUI/Content/Inventory/VBoxContainer" unique_id=1572448693] [node name="RichTextLabel" type="RichTextLabel" parent="CanvasLayer/UIHandler/MainUI/Content/Inventory/VBoxContainer" unique_id=1572448693]
layout_mode = 2 layout_mode = 2
text = "Available Space:" text = "Storage"
fit_content = true fit_content = true
autowrap_mode = 0 autowrap_mode = 0
horizontal_alignment = 1 horizontal_alignment = 1
@@ -551,6 +555,7 @@ text = "Continue"
[node name="FooterContainer" type="PanelContainer" parent="CanvasLayer/UIHandler/MainUI" unique_id=1495029884] [node name="FooterContainer" type="PanelContainer" parent="CanvasLayer/UIHandler/MainUI" unique_id=1495029884]
layout_mode = 2 layout_mode = 2
custom_minimum_size = Vector2(0, 48)
[node name="HBoxContainer" type="HBoxContainer" parent="CanvasLayer/UIHandler/MainUI/FooterContainer" unique_id=1782436702] [node name="HBoxContainer" type="HBoxContainer" parent="CanvasLayer/UIHandler/MainUI/FooterContainer" unique_id=1782436702]
layout_mode = 2 layout_mode = 2
@@ -597,6 +602,71 @@ layout_mode = 2
tooltip_text = "Menu (ESC)" tooltip_text = "Menu (ESC)"
texture_normal = ExtResource("12_3so38") texture_normal = ExtResource("12_3so38")
[node name="TutorialBubble" type="PanelContainer" parent="CanvasLayer/UIHandler" node_paths=PackedStringArray("speakerLabel", "contentLabel", "progressLabel", "nextButton", "skipButton")]
layout_mode = 1
anchors_preset = 2
anchor_top = 1.0
anchor_bottom = 1.0
offset_left = 24.0
offset_top = -236.0
offset_right = 544.0
offset_bottom = -72.0
grow_vertical = 0
script = ExtResource("15_tutorial")
speakerLabel = NodePath("MarginContainer/VBoxContainer/Header/Speaker")
contentLabel = NodePath("MarginContainer/VBoxContainer/Content")
progressLabel = NodePath("MarginContainer/VBoxContainer/Footer/Progress")
nextButton = NodePath("MarginContainer/VBoxContainer/Footer/Next")
skipButton = NodePath("MarginContainer/VBoxContainer/Footer/Skip")
[node name="MarginContainer" type="MarginContainer" parent="CanvasLayer/UIHandler/TutorialBubble"]
layout_mode = 2
theme_override_constants/margin_left = 14
theme_override_constants/margin_top = 12
theme_override_constants/margin_right = 14
theme_override_constants/margin_bottom = 12
[node name="VBoxContainer" type="VBoxContainer" parent="CanvasLayer/UIHandler/TutorialBubble/MarginContainer"]
layout_mode = 2
theme_override_constants/separation = 8
[node name="Header" type="HBoxContainer" parent="CanvasLayer/UIHandler/TutorialBubble/MarginContainer/VBoxContainer"]
layout_mode = 2
[node name="Speaker" type="RichTextLabel" parent="CanvasLayer/UIHandler/TutorialBubble/MarginContainer/VBoxContainer/Header"]
layout_mode = 2
size_flags_horizontal = 3
bbcode_enabled = true
text = "[font_size=22]B.O.B.[/font_size]"
fit_content = true
autowrap_mode = 0
[node name="Content" type="RichTextLabel" parent="CanvasLayer/UIHandler/TutorialBubble/MarginContainer/VBoxContainer"]
layout_mode = 2
size_flags_vertical = 3
text = "Tutorial"
fit_content = true
autowrap_mode = 2
[node name="Footer" type="HBoxContainer" parent="CanvasLayer/UIHandler/TutorialBubble/MarginContainer/VBoxContainer"]
layout_mode = 2
theme_override_constants/separation = 10
[node name="Progress" type="RichTextLabel" parent="CanvasLayer/UIHandler/TutorialBubble/MarginContainer/VBoxContainer/Footer"]
layout_mode = 2
size_flags_horizontal = 3
text = "1/1"
fit_content = true
autowrap_mode = 0
[node name="Skip" type="Button" parent="CanvasLayer/UIHandler/TutorialBubble/MarginContainer/VBoxContainer/Footer"]
layout_mode = 2
text = "Skip"
[node name="Next" type="Button" parent="CanvasLayer/UIHandler/TutorialBubble/MarginContainer/VBoxContainer/Footer"]
layout_mode = 2
text = "Next"
[connection signal="pressed" from="CanvasLayer/UIHandler/MainUI/HeaderContainer/VBoxContainer/UnlockLayer" to="CanvasLayer/UIHandler" method="UnlockLayer"] [connection signal="pressed" from="CanvasLayer/UIHandler/MainUI/HeaderContainer/VBoxContainer/UnlockLayer" to="CanvasLayer/UIHandler" method="UnlockLayer"]
[connection signal="pressed" from="CanvasLayer/UIHandler/MainUI/Content/CodingWindow/VBoxContainer/Renaming/Button" to="CanvasLayer/UIHandler/MainUI/Content/CodingWindow" method="SaveRobotName"] [connection signal="pressed" from="CanvasLayer/UIHandler/MainUI/Content/CodingWindow/VBoxContainer/Renaming/Button" to="CanvasLayer/UIHandler/MainUI/Content/CodingWindow" method="SaveRobotName"]
[connection signal="button_up" from="CanvasLayer/UIHandler/MainUI/Content/CodingWindow/VBoxContainer/Scripting/EditorWindow/Buttons/Clear" to="CanvasLayer/UIHandler/MainUI/Content/CodingWindow" method="ClearWindow"] [connection signal="button_up" from="CanvasLayer/UIHandler/MainUI/Content/CodingWindow/VBoxContainer/Scripting/EditorWindow/Buttons/Clear" to="CanvasLayer/UIHandler/MainUI/Content/CodingWindow" method="ClearWindow"]
+5 -1
View File
@@ -108,7 +108,7 @@ theme_override_constants/separation = 40
[node name="RichTextLabel" type="RichTextLabel" parent="CenterContainer/VBoxContainer" unique_id=195514567] [node name="RichTextLabel" type="RichTextLabel" parent="CenterContainer/VBoxContainer" unique_id=195514567]
layout_mode = 2 layout_mode = 2
bbcode_enabled = true bbcode_enabled = true
text = "[font_size=50]RuinAdventurer[/font_size]" text = "[font_size=50]Ruin Adventurer[/font_size]"
fit_content = true fit_content = true
scroll_active = false scroll_active = false
autowrap_mode = 0 autowrap_mode = 0
@@ -119,24 +119,28 @@ layout_mode = 2
[node name="btnPlay" type="Button" parent="CenterContainer/VBoxContainer" unique_id=452402808] [node name="btnPlay" type="Button" parent="CenterContainer/VBoxContainer" unique_id=452402808]
layout_mode = 2 layout_mode = 2
custom_minimum_size = Vector2(220, 42)
theme_override_styles/normal = SubResource("StyleBoxFlat_bnhvo") theme_override_styles/normal = SubResource("StyleBoxFlat_bnhvo")
theme_override_styles/hover = SubResource("StyleBoxFlat_tt5f1") theme_override_styles/hover = SubResource("StyleBoxFlat_tt5f1")
text = "Start Game" text = "Start Game"
[node name="btnLoad" type="Button" parent="CenterContainer/VBoxContainer"] [node name="btnLoad" type="Button" parent="CenterContainer/VBoxContainer"]
layout_mode = 2 layout_mode = 2
custom_minimum_size = Vector2(220, 42)
theme_override_styles/normal = SubResource("StyleBoxFlat_bnhvo") theme_override_styles/normal = SubResource("StyleBoxFlat_bnhvo")
theme_override_styles/hover = SubResource("StyleBoxFlat_tt5f1") theme_override_styles/hover = SubResource("StyleBoxFlat_tt5f1")
text = "Load Game" text = "Load Game"
[node name="btnOptions" type="Button" parent="CenterContainer/VBoxContainer" unique_id=891656915] [node name="btnOptions" type="Button" parent="CenterContainer/VBoxContainer" unique_id=891656915]
layout_mode = 2 layout_mode = 2
custom_minimum_size = Vector2(220, 42)
theme_override_styles/normal = SubResource("StyleBoxFlat_bnhvo") theme_override_styles/normal = SubResource("StyleBoxFlat_bnhvo")
theme_override_styles/hover = SubResource("StyleBoxFlat_tt5f1") theme_override_styles/hover = SubResource("StyleBoxFlat_tt5f1")
text = "Options" text = "Options"
[node name="btnExit" type="Button" parent="CenterContainer/VBoxContainer" unique_id=2025231658] [node name="btnExit" type="Button" parent="CenterContainer/VBoxContainer" unique_id=2025231658]
layout_mode = 2 layout_mode = 2
custom_minimum_size = Vector2(220, 42)
theme_override_styles/normal = SubResource("StyleBoxFlat_bnhvo") theme_override_styles/normal = SubResource("StyleBoxFlat_bnhvo")
theme_override_styles/hover = SubResource("StyleBoxFlat_tt5f1") theme_override_styles/hover = SubResource("StyleBoxFlat_tt5f1")
text = "Exit Game" text = "Exit Game"
+75
View File
@@ -0,0 +1,75 @@
[gd_scene format=3]
[ext_resource type="Script" path="res://Scripts/UI/Menus/WorldSetup.cs" id="1_world_setup"]
[node name="WorldSetup" type="Control" node_paths=PackedStringArray("seedInput", "seedPreview")]
layout_mode = 3
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
script = ExtResource("1_world_setup")
seedInput = NodePath("CenterContainer/PanelContainer/VBoxContainer/SeedInput")
seedPreview = NodePath("CenterContainer/PanelContainer/VBoxContainer/SeedPreview")
[node name="CenterContainer" type="CenterContainer" parent="."]
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
[node name="PanelContainer" type="PanelContainer" parent="CenterContainer"]
layout_mode = 2
custom_minimum_size = Vector2(440, 260)
[node name="VBoxContainer" type="VBoxContainer" parent="CenterContainer/PanelContainer"]
layout_mode = 2
theme_override_constants/separation = 14
[node name="Title" type="RichTextLabel" parent="CenterContainer/PanelContainer/VBoxContainer"]
layout_mode = 2
bbcode_enabled = true
text = "[font_size=34]World Setup[/font_size]"
fit_content = true
autowrap_mode = 0
horizontal_alignment = 1
[node name="Description" type="RichTextLabel" parent="CenterContainer/PanelContainer/VBoxContainer"]
layout_mode = 2
text = "Choose a seed for the ruin layout. Leave it empty for a random expedition."
fit_content = true
autowrap_mode = 2
horizontal_alignment = 1
[node name="SeedInput" type="LineEdit" parent="CenterContainer/PanelContainer/VBoxContainer"]
layout_mode = 2
placeholder_text = "Seed..."
max_length = 32
[node name="SeedPreview" type="RichTextLabel" parent="CenterContainer/PanelContainer/VBoxContainer"]
layout_mode = 2
text = "No seed entered. B.O.B. will pick one from the ruins."
fit_content = true
autowrap_mode = 2
horizontal_alignment = 1
[node name="Buttons" type="HBoxContainer" parent="CenterContainer/PanelContainer/VBoxContainer"]
layout_mode = 2
theme_override_constants/separation = 12
[node name="Back" type="Button" parent="CenterContainer/PanelContainer/VBoxContainer/Buttons"]
layout_mode = 2
size_flags_horizontal = 3
text = "Back"
[node name="Start" type="Button" parent="CenterContainer/PanelContainer/VBoxContainer/Buttons"]
layout_mode = 2
size_flags_horizontal = 3
text = "Enter Ruins"
[connection signal="text_changed" from="CenterContainer/PanelContainer/VBoxContainer/SeedInput" to="." method="OnSeedChanged"]
[connection signal="pressed" from="CenterContainer/PanelContainer/VBoxContainer/Buttons/Back" to="." method="OnBackPressed"]
[connection signal="pressed" from="CenterContainer/PanelContainer/VBoxContainer/Buttons/Start" to="." method="OnStartPressed"]
+2 -2
View File
@@ -4,7 +4,7 @@ using Godot;
public partial class GameData public partial class GameData
{ {
public static bool debugMode = true; public static bool debugMode = false;
public static Random rand = new Random(seed); public static Random rand = new Random(seed);
public static Layer[] map; public static Layer[] map;
@@ -24,6 +24,7 @@ public partial class GameData
public static RobotStats robotStats = new RobotStats(); public static RobotStats robotStats = new RobotStats();
public static Dictionary<int, List<Ingredient>> gateUnlocks; public static Dictionary<int, List<Ingredient>> gateUnlocks;
public static bool loadSaveOnStart = false; public static bool loadSaveOnStart = false;
public static bool showTutorial = true;
public static Color primaryColor = new Color("#276ac2"); public static Color primaryColor = new Color("#276ac2");
public static Color lightColor = new Color("#7efff5"); public static Color lightColor = new Color("#7efff5");
@@ -36,7 +37,6 @@ public partial class GameData
public static void ResetRunState() public static void ResetRunState()
{ {
seed = 12345;
ruinSize = 10; ruinSize = 10;
layerSize = 20; layerSize = 20;
rand = new Random(seed); rand = new Random(seed);
+12 -6
View File
@@ -29,6 +29,7 @@ public partial class UIHandler : Control
private bool receivedRobotJumpSignal = false; private bool receivedRobotJumpSignal = false;
public override void _Ready() public override void _Ready()
{ {
UIStyle.Apply(this);
robotList.OnRobotJumpTo += OnRobotJumpTo; robotList.OnRobotJumpTo += OnRobotJumpTo;
} }
@@ -177,6 +178,10 @@ public partial class UIHandler : Control
waterLabel.Text = $"Water: {GameData.survival.thirst:0}/{GameData.survival.maxThirst:0}"; waterLabel.Text = $"Water: {GameData.survival.thirst:0}/{GameData.survival.maxThirst:0}";
hungerLabel.Text = $"Food: {GameData.survival.hunger:0}/{GameData.survival.maxHunger:0}"; hungerLabel.Text = $"Food: {GameData.survival.hunger:0}/{GameData.survival.maxHunger:0}";
survivalStatus.Text = GameData.survival.currentStatus; survivalStatus.Text = GameData.survival.currentStatus;
survivalStatus.Modulate = GameData.survival.currentStatus.Contains("critical")
? UIStyle.GetWarningColor()
: Colors.White;
if (GameData.survival.isDead) if (GameData.survival.isDead)
{ {
ShowGameOver(); ShowGameOver();
@@ -185,13 +190,14 @@ public partial class UIHandler : Control
private void DisplayWorldStats() private void DisplayWorldStats()
{ {
currentLayer.Text = $"Current layer: {GameData.currentLayer}/{GameData.ruinSize}"; currentLayer.Text = $"Layer: {GameData.currentLayer + 1}/{GameData.ruinSize}";
deepestLayer.Text = $"Deepest layer: {GameData.lowestLayer}"; deepestLayer.Text = $"Gate depth: {GameData.lowestLayer}";
if(GameData.lowestLayer == GameData.ruinSize){ if (GameData.lowestLayer == GameData.ruinSize)
{
unlockLayer.Visible = false; unlockLayer.Visible = false;
return; return;
} }
unlockLayer.TooltipText = "Needed items: \r" + GameData.map[GameData.lowestLayer].DisplayGateIngredients(); unlockLayer.TooltipText = "Gate requirements:\r" + GameData.map[GameData.lowestLayer].DisplayGateIngredients();
unlockLayer.Disabled = !GameData.inventory.CanCraft(GameData.map[GameData.lowestLayer].gateIngredients, 1); unlockLayer.Disabled = !GameData.inventory.CanCraft(GameData.map[GameData.lowestLayer].gateIngredients, 1);
} }
@@ -213,8 +219,8 @@ public partial class UIHandler : Control
public void ShowGameOver() public void ShowGameOver()
{ {
if(gameOver.Visible) return; if (gameOver.Visible) return;
gameOver.GetNode<RichTextLabel>("./VBoxContainer/Content").Text = $"[font_size=32]You died! \r Reason: {GameData.survival.deathReason} \r Better luck next time \r"; gameOver.GetNode<RichTextLabel>("./VBoxContainer/Content").Text = $"[font_size=32]You died!\rReason: {GameData.survival.deathReason}\rBetter luck next time.\r";
gameOver.Show(); gameOver.Show();
} }
+157
View File
@@ -0,0 +1,157 @@
using Godot;
public static class UIStyle
{
private static readonly Color Background = new Color("#101317");
private static readonly Color Surface = new Color("#171d22");
private static readonly Color SurfaceStrong = new Color("#202a31");
private static readonly Color SurfaceSoft = new Color("#25343d");
private static readonly Color Accent = new Color("#6ec6b8");
private static readonly Color AccentStrong = new Color("#9be7d8");
private static readonly Color Warning = new Color("#d69b5a");
private static readonly Color Text = new Color("#e8f0ed");
private static readonly Color MutedText = new Color("#aab8b4");
public static void Apply(Control root)
{
if (root == null) return;
ApplyToControl(root);
foreach (Node child in root.GetChildren())
{
Control control = child as Control;
if (control != null)
{
Apply(control);
}
}
}
private static void ApplyToControl(Control control)
{
PanelContainer panel = control as PanelContainer;
if (panel != null)
{
StylePanel(panel);
}
Button button = control as Button;
if (button != null)
{
StyleButton(button);
}
LineEdit lineEdit = control as LineEdit;
if (lineEdit != null)
{
StyleLineEdit(lineEdit);
}
OptionButton optionButton = control as OptionButton;
if (optionButton != null)
{
StyleButton(optionButton);
}
RichTextLabel label = control as RichTextLabel;
if (label != null)
{
StyleLabel(label);
}
TextureButton textureButton = control as TextureButton;
if (textureButton != null)
{
StyleTextureButton(textureButton);
}
TextureRect textureRect = control as TextureRect;
if (textureRect != null)
{
textureRect.CustomMinimumSize = new Vector2(26, 26);
}
}
private static void StylePanel(PanelContainer panel)
{
Color color = Surface;
if (panel.Name.ToString().Contains("Header") || panel.Name.ToString().Contains("Footer"))
{
color = Background;
}
if (panel.Name.ToString().Contains("GameOver") || panel.Name.ToString().Contains("Menu"))
{
color = SurfaceStrong;
}
StyleBoxFlat style = CreateBox(color, Accent, 1, 8);
panel.AddThemeStyleboxOverride("panel", style);
}
private static void StyleButton(Button button)
{
button.CustomMinimumSize = new Vector2(112, 34);
button.AddThemeStyleboxOverride("normal", CreateBox(SurfaceSoft, Accent, 1, 6));
button.AddThemeStyleboxOverride("hover", CreateBox(new Color("#314750"), AccentStrong, 1, 6));
button.AddThemeStyleboxOverride("pressed", CreateBox(new Color("#1a2b30"), AccentStrong, 1, 6));
button.AddThemeStyleboxOverride("focus", CreateBox(new Color(0, 0, 0, 0), AccentStrong, 1, 6));
button.AddThemeColorOverride("font_color", Text);
button.AddThemeColorOverride("font_hover_color", AccentStrong);
button.AddThemeColorOverride("font_pressed_color", AccentStrong);
button.AddThemeColorOverride("font_disabled_color", MutedText);
}
private static void StyleLineEdit(LineEdit lineEdit)
{
lineEdit.CustomMinimumSize = new Vector2(120, 34);
lineEdit.AddThemeStyleboxOverride("normal", CreateBox(new Color("#11191d"), Accent, 1, 6));
lineEdit.AddThemeStyleboxOverride("focus", CreateBox(new Color("#142126"), AccentStrong, 1, 6));
lineEdit.AddThemeColorOverride("font_color", Text);
lineEdit.AddThemeColorOverride("font_placeholder_color", MutedText);
}
private static void StyleLabel(RichTextLabel label)
{
label.AddThemeColorOverride("default_color", Text);
label.AddThemeColorOverride("font_shadow_color", new Color("#00000080"));
}
private static void StyleTextureButton(TextureButton textureButton)
{
textureButton.CustomMinimumSize = new Vector2(38, 38);
textureButton.Modulate = Text;
textureButton.SelfModulate = Text;
textureButton.StretchMode = TextureButton.StretchModeEnum.KeepAspectCentered;
}
private static StyleBoxFlat CreateBox(Color color, Color borderColor, int borderWidth, int radius)
{
StyleBoxFlat style = new StyleBoxFlat
{
BgColor = color,
BorderColor = borderColor,
BorderWidthTop = borderWidth,
BorderWidthBottom = borderWidth,
BorderWidthLeft = borderWidth,
BorderWidthRight = borderWidth,
CornerRadiusTopLeft = radius,
CornerRadiusTopRight = radius,
CornerRadiusBottomLeft = radius,
CornerRadiusBottomRight = radius,
ContentMarginLeft = 8,
ContentMarginRight = 8,
ContentMarginTop = 6,
ContentMarginBottom = 6
};
return style;
}
public static Color GetWarningColor()
{
return Warning;
}
}
+1
View File
@@ -0,0 +1 @@
uid://dkygddm6k0hjw
+7 -1
View File
@@ -2,10 +2,15 @@ using Godot;
public partial class MainMenu : Control public partial class MainMenu : Control
{ {
public override void _Ready()
{
UIStyle.Apply(this);
}
public void OnPlayPressed() public void OnPlayPressed()
{ {
GameData.loadSaveOnStart = false; GameData.loadSaveOnStart = false;
GetTree().ChangeSceneToFile("res://Scenes/Game.tscn"); GetTree().ChangeSceneToFile("res://Scenes/WorldSetup.tscn");
} }
public void OnLoadPressed() public void OnLoadPressed()
@@ -13,6 +18,7 @@ public partial class MainMenu : Control
if (!SaveGameManager.SaveExists()) return; if (!SaveGameManager.SaveExists()) return;
GameData.loadSaveOnStart = true; GameData.loadSaveOnStart = true;
GameData.showTutorial = false;
GetTree().ChangeSceneToFile("res://Scenes/Game.tscn"); GetTree().ChangeSceneToFile("res://Scenes/Game.tscn");
} }
+72
View File
@@ -0,0 +1,72 @@
using Godot;
using System;
public partial class WorldSetup : Control
{
[Export] LineEdit seedInput;
[Export] RichTextLabel seedPreview;
public override void _Ready()
{
UIStyle.Apply(this);
UpdateSeedPreview();
}
public void OnSeedChanged(string text)
{
UpdateSeedPreview();
}
public void OnStartPressed()
{
GameData.seed = GetSelectedSeed();
GameData.loadSaveOnStart = false;
GameData.showTutorial = true;
GetTree().ChangeSceneToFile("res://Scenes/Game.tscn");
}
public void OnBackPressed()
{
GetTree().ChangeSceneToFile("res://Scenes/MainMenu.tscn");
}
private int GetSelectedSeed()
{
string text = seedInput.Text.Trim();
if (text.Length <= 0)
{
return new Random().Next(1, int.MaxValue);
}
int numericSeed;
if (int.TryParse(text, out numericSeed))
{
return numericSeed;
}
return CreateTextSeed(text);
}
private int CreateTextSeed(string text)
{
int hash = 17;
foreach (char character in text)
{
hash = hash * 31 + character;
}
return Math.Abs(hash);
}
private void UpdateSeedPreview()
{
string text = seedInput.Text.Trim();
if (text.Length <= 0)
{
seedPreview.Text = "No seed entered. B.O.B. will pick one from the ruins.";
return;
}
seedPreview.Text = "Selected seed: " + GetSelectedSeed();
}
}
+1
View File
@@ -0,0 +1 @@
uid://3xjyrxtq3rww
+78
View File
@@ -0,0 +1,78 @@
using Godot;
using System.Collections.Generic;
public partial class TutorialBubble : PanelContainer
{
[Export] RichTextLabel speakerLabel;
[Export] RichTextLabel contentLabel;
[Export] RichTextLabel progressLabel;
[Export] Button nextButton;
[Export] Button skipButton;
private List<string> messages = new List<string>();
private int currentIndex = 0;
public override void _Ready()
{
UIStyle.Apply(this);
CreateMessages();
nextButton.Pressed += ShowNext;
skipButton.Pressed += SkipTutorial;
if (!GameData.showTutorial)
{
Hide();
return;
}
ShowMessage(0);
}
private void CreateMessages()
{
messages = new List<string>
{
"Welcome to the ruin. I am B.O.B.",
"B.O.B. means Building Operation Buddy. I will keep the lamps on while you teach the robots what to do.",
"The last remaining unit in this ruin saved you from your fall and brought you here. If you want to leave, you have to explore the ruin",
"You do not walk through the ruin yourself. Your robots explore, harvest, craft and carry progress for you.",
"The top bar shows survival pressure: energy, water and food. If those run out, the expedition ends.",
"Open the robot panel (Default: [R]) to inspect your robots. A robot can overheat, lose maintenance and slow down if ignored.",
"Use the script editor (Clicking 'Jump to' from the robot panel) to give robots commands. Start simple: move, explore, harvest, then craft.",
"Research unlocks better tools, buildings, robot upgrades and deeper progression. The graph is your technology map (Default: [T]).",
"The inventory (Default: [I]) stores everything your robots collect. Gates and research both consume items from it.",
"Each gate blocks the next layer. When you have the required items, use Open Gate in the top bar.",
"The map (Default: [M]) shows what your robots have discovered. Exploration matters because resources are hidden in the ruin.",
"That is enough briefing. Build a loop, keep the robots alive, and open the lower gates. B.O.B. believes in organized chaos."
};
}
private void ShowNext()
{
currentIndex++;
if (currentIndex >= messages.Count)
{
SkipTutorial();
return;
}
ShowMessage(currentIndex);
}
private void SkipTutorial()
{
GameData.showTutorial = false;
Hide();
}
private void ShowMessage(int index)
{
currentIndex = index;
speakerLabel.Text = "B.O.B.";
contentLabel.Text = messages[index];
progressLabel.Text = $"{index + 1}/{messages.Count}";
nextButton.Text = index == messages.Count - 1 ? "Done" : "Next";
Show();
}
}
@@ -0,0 +1 @@
uid://d0opysuqksr6l