diff --git a/resources/levels/forest/forest_1.tres b/resources/levels/forest/forest_1.tres index b32ddd8..00c828c 100644 --- a/resources/levels/forest/forest_1.tres +++ b/resources/levels/forest/forest_1.tres @@ -1,9 +1,11 @@ -[gd_resource type="Resource" script_class="LevelResource" load_steps=2 format=3 uid="uid://dsq0y2iw7tfmk"] +[gd_resource type="Resource" script_class="LevelResource" load_steps=3 format=3 uid="uid://dsq0y2iw7tfmk"] -[ext_resource type="Script" uid="uid://c2h0pqhxiqswe" path="res://scripts/Resources/LevelResource.cs" id="1_8mmd7"] +[ext_resource type="Script" uid="uid://c2h0pqhxiqswe" path="res://scripts/Resources/LevelResource.cs" id="1_script"] +[ext_resource type="PackedScene" uid="uid://cq4glvuewsno5" path="res://scenes/level_forest_1.tscn" id="2_scene"] [resource] -script = ExtResource("1_8mmd7") -LevelName = "LEVEL_5_NAME" -ScenePath = "res://scenes/level_forest_5.tscn" +script = ExtResource("1_script") +Id = "forest_1" +LevelName = "LEVEL_FOREST_1_NAME" +Scene = ExtResource("2_scene") metadata/_custom_type_script = "uid://cp68km8bykymb" diff --git a/resources/levels/level_catalogue.tres b/resources/levels/level_catalogue.tres new file mode 100644 index 0000000..5f4b344 --- /dev/null +++ b/resources/levels/level_catalogue.tres @@ -0,0 +1,13 @@ +[gd_resource type="Resource" script_class="LevelCatalogue" load_steps=8 format=3] + +[ext_resource type="Script" path="res://scripts/Resources/LevelCatalogue.cs" id="1_script"] +[ext_resource type="Resource" path="res://resources/levels/tutorial_1.tres" id="2_tutorial_1"] +[ext_resource type="Resource" uid="uid://cqtalsov2bkpo" path="res://resources/levels/village/village_1.tres" id="3_village_1"] +[ext_resource type="Resource" uid="uid://dlwkbjw1l33uq" path="res://resources/levels/village/village_2.tres" id="4_village_2"] +[ext_resource type="Resource" uid="uid://b63u5qfp8p7pv" path="res://resources/levels/village/village_3.tres" id="5_village_3"] +[ext_resource type="Resource" uid="uid://cxfei28yu3buh" path="res://resources/levels/village/village_4.tres" id="6_village_4"] +[ext_resource type="Resource" uid="uid://qld841xv5ui0" path="res://resources/levels/village/village_5.tres" id="7_village_5"] + +[resource] +script = ExtResource("1_script") +Levels = Array[Resource]([ExtResource("2_tutorial_1"), ExtResource("3_village_1"), ExtResource("4_village_2"), ExtResource("5_village_3"), ExtResource("6_village_4"), ExtResource("7_village_5")]) diff --git a/resources/levels/tutorial_1.tres b/resources/levels/tutorial_1.tres new file mode 100644 index 0000000..c5d90b6 --- /dev/null +++ b/resources/levels/tutorial_1.tres @@ -0,0 +1,11 @@ +[gd_resource type="Resource" script_class="LevelResource" load_steps=3 format=3] + +[ext_resource type="Script" uid="uid://c2h0pqhxiqswe" path="res://scripts/Resources/LevelResource.cs" id="1_script"] +[ext_resource type="PackedScene" uid="uid://dwr3avefuwnpy" path="res://scenes/level_tutorial_1.tscn" id="2_scene"] + +[resource] +script = ExtResource("1_script") +Id = "tutorial_1" +LevelName = "LEVEL_TUTORIAL_1_NAME" +Scene = ExtResource("2_scene") +metadata/_custom_type_script = "uid://cp68km8bykymb" diff --git a/resources/levels/village/village_1.tres b/resources/levels/village/village_1.tres index 2833437..0aaf363 100644 --- a/resources/levels/village/village_1.tres +++ b/resources/levels/village/village_1.tres @@ -1,10 +1,11 @@ -[gd_resource type="Resource" script_class="LevelResource" load_steps=2 format=3 uid="uid://cqtalsov2bkpo"] +[gd_resource type="Resource" script_class="LevelResource" load_steps=3 format=3 uid="uid://cqtalsov2bkpo"] -[ext_resource type="Script" uid="uid://c2h0pqhxiqswe" path="res://scripts/Resources/LevelResource.cs" id="1_72j7f"] +[ext_resource type="Script" uid="uid://c2h0pqhxiqswe" path="res://scripts/Resources/LevelResource.cs" id="1_script"] +[ext_resource type="PackedScene" uid="uid://bol7g83v2accs" path="res://scenes/level_village_1.tscn" id="2_scene"] [resource] -resource_local_to_scene = true -script = ExtResource("1_72j7f") +script = ExtResource("1_script") +Id = "village_1" LevelName = "LEVEL_1_NAME" -ScenePath = "res://scenes/level_village_1.tscn" +Scene = ExtResource("2_scene") metadata/_custom_type_script = "uid://cp68km8bykymb" diff --git a/resources/levels/village/village_2.tres b/resources/levels/village/village_2.tres index 6ded9e6..9eaf32d 100644 --- a/resources/levels/village/village_2.tres +++ b/resources/levels/village/village_2.tres @@ -1,9 +1,11 @@ -[gd_resource type="Resource" script_class="LevelResource" load_steps=2 format=3 uid="uid://dlwkbjw1l33uq"] +[gd_resource type="Resource" script_class="LevelResource" load_steps=3 format=3 uid="uid://dlwkbjw1l33uq"] -[ext_resource type="Script" uid="uid://c2h0pqhxiqswe" path="res://scripts/Resources/LevelResource.cs" id="1_msres"] +[ext_resource type="Script" uid="uid://c2h0pqhxiqswe" path="res://scripts/Resources/LevelResource.cs" id="1_script"] +[ext_resource type="PackedScene" uid="uid://chqb11pfoqmeb" path="res://scenes/level_village_2.tscn" id="2_scene"] [resource] -script = ExtResource("1_msres") +script = ExtResource("1_script") +Id = "village_2" LevelName = "LEVEL_2_NAME" -ScenePath = "res://scenes/level_village_2.tscn" +Scene = ExtResource("2_scene") metadata/_custom_type_script = "uid://cp68km8bykymb" diff --git a/resources/levels/village/village_3.tres b/resources/levels/village/village_3.tres index 0d3176e..bc1e157 100644 --- a/resources/levels/village/village_3.tres +++ b/resources/levels/village/village_3.tres @@ -1,9 +1,11 @@ -[gd_resource type="Resource" script_class="LevelResource" load_steps=2 format=3 uid="uid://b63u5qfp8p7pv"] +[gd_resource type="Resource" script_class="LevelResource" load_steps=3 format=3 uid="uid://b63u5qfp8p7pv"] -[ext_resource type="Script" uid="uid://c2h0pqhxiqswe" path="res://scripts/Resources/LevelResource.cs" id="1_6vcr8"] +[ext_resource type="Script" uid="uid://c2h0pqhxiqswe" path="res://scripts/Resources/LevelResource.cs" id="1_script"] +[ext_resource type="PackedScene" uid="uid://h60obxmju6mo" path="res://scenes/level_village_3.tscn" id="2_scene"] [resource] -script = ExtResource("1_6vcr8") +script = ExtResource("1_script") +Id = "village_3" LevelName = "LEVEL_3_NAME" -ScenePath = "res://scenes/level_village_3.tscn" +Scene = ExtResource("2_scene") metadata/_custom_type_script = "uid://cp68km8bykymb" diff --git a/resources/levels/village/village_4.tres b/resources/levels/village/village_4.tres index 6ed1da3..2cd00e4 100644 --- a/resources/levels/village/village_4.tres +++ b/resources/levels/village/village_4.tres @@ -1,9 +1,11 @@ -[gd_resource type="Resource" script_class="LevelResource" load_steps=2 format=3 uid="uid://cxfei28yu3buh"] +[gd_resource type="Resource" script_class="LevelResource" load_steps=3 format=3 uid="uid://cxfei28yu3buh"] -[ext_resource type="Script" uid="uid://c2h0pqhxiqswe" path="res://scripts/Resources/LevelResource.cs" id="1_h4twv"] +[ext_resource type="Script" uid="uid://c2h0pqhxiqswe" path="res://scripts/Resources/LevelResource.cs" id="1_script"] +[ext_resource type="PackedScene" uid="uid://bhad760x3vvco" path="res://scenes/level_village_4.tscn" id="2_scene"] [resource] -script = ExtResource("1_h4twv") +script = ExtResource("1_script") +Id = "village_4" LevelName = "LEVEL_4_NAME" -ScenePath = "res://scenes/level_village_4.tscn" +Scene = ExtResource("2_scene") metadata/_custom_type_script = "uid://cp68km8bykymb" diff --git a/resources/levels/village/village_5.tres b/resources/levels/village/village_5.tres index 3c81c48..11d73cb 100644 --- a/resources/levels/village/village_5.tres +++ b/resources/levels/village/village_5.tres @@ -1,8 +1,11 @@ -[gd_resource type="Resource" script_class="LevelResource" load_steps=2 format=3 uid="uid://qld841xv5ui0"] +[gd_resource type="Resource" script_class="LevelResource" load_steps=3 format=3 uid="uid://qld841xv5ui0"] -[ext_resource type="Script" uid="uid://c2h0pqhxiqswe" path="res://scripts/Resources/LevelResource.cs" id="1_chped"] +[ext_resource type="Script" uid="uid://c2h0pqhxiqswe" path="res://scripts/Resources/LevelResource.cs" id="1_script"] +[ext_resource type="PackedScene" uid="uid://bbwef3n2gjkt8" path="res://scenes/level_village_5.tscn" id="2_scene"] [resource] -script = ExtResource("1_chped") +script = ExtResource("1_script") +Id = "village_5" LevelName = "LEVEL_5_NAME" -ScenePath = "res://scenes/level_village_5.tscn" +Scene = ExtResource("2_scene") +metadata/_custom_type_script = "uid://cp68km8bykymb" diff --git a/resources/levels/village/village_6.tres b/resources/levels/village/village_6.tres new file mode 100644 index 0000000..b6e2d68 --- /dev/null +++ b/resources/levels/village/village_6.tres @@ -0,0 +1,11 @@ +[gd_resource type="Resource" script_class="LevelResource" load_steps=3 format=3] + +[ext_resource type="Script" uid="uid://c2h0pqhxiqswe" path="res://scripts/Resources/LevelResource.cs" id="1_script"] +[ext_resource type="PackedScene" uid="uid://dqekccjkwev4y" path="res://scenes/level_village_6.tscn" id="2_scene"] + +[resource] +script = ExtResource("1_script") +Id = "village_6" +LevelName = "LEVEL_6_NAME" +Scene = ExtResource("2_scene") +metadata/_custom_type_script = "uid://cp68km8bykymb" diff --git a/scenes/level_tutorial_1.tscn b/scenes/level_tutorial_1.tscn index 00a8a36..1f5a312 100644 --- a/scenes/level_tutorial_1.tscn +++ b/scenes/level_tutorial_1.tscn @@ -20,7 +20,6 @@ [sub_resource type="Resource" id="Resource_asu0i"] script = ExtResource("3_ph1yb") LevelName = "Tutorial 1" -ScenePath = "res://scenes/level_tutorial_1.tscn" metadata/_custom_type_script = "uid://c2h0pqhxiqswe" [sub_resource type="Resource" id="Resource_0nwt7"] diff --git a/scenes/level_village_1.tscn b/scenes/level_village_1.tscn index de5e2d1..20b49f3 100644 --- a/scenes/level_village_1.tscn +++ b/scenes/level_village_1.tscn @@ -54,7 +54,6 @@ color_ramp = SubResource("GradientTexture1D_f1fvy") resource_local_to_scene = true script = ExtResource("4_84xgs") LevelName = "LEVEL_1_NAME" -ScenePath = "res://scenes/level_village_1.tscn" metadata/_custom_type_script = "uid://cp68km8bykymb" [sub_resource type="Resource" id="Resource_0nwt7"] diff --git a/scripts/Resources/LevelCatalogue.cs b/scripts/Resources/LevelCatalogue.cs new file mode 100644 index 0000000..dee1023 --- /dev/null +++ b/scripts/Resources/LevelCatalogue.cs @@ -0,0 +1,54 @@ +using System.Collections.Generic; +using System.Linq; +using Godot; +using Godot.Collections; +using Mr.BrickAdventures.Progression; + +namespace Mr.BrickAdventures.scripts.Resources; + +/// +/// The authored list of Levels in campaign order, and the bridge from a back to +/// the Godot scene that implements it. +/// +/// +/// Not a domain port. Nothing in the progression domain resolves a Level to a scene — the domain only +/// needs the ordering, which it takes as a . Scene lookup is wanted solely by +/// the composition root, which is engine-side anyway. +/// +[GlobalClass] +public partial class LevelCatalogue : Resource +{ + /// + /// Levels in campaign order. A Level absent from this list is not reachable, even if its + /// exists. + /// + [Export] + public Array Levels { get; set; } = []; + + /// + /// The ordering the domain works from. Throws if the authored data is inconsistent — a blank or + /// duplicated id cannot produce a , so a mistake here fails at boot rather + /// than corrupting a save later. + /// + public Campaign ToCampaign() + { + var ids = new List(); + + for (var i = 0; i < Levels.Count; i++) + { + var level = Levels[i]; + if (level == null) + throw new System.InvalidOperationException( + $"LevelCatalogue has an empty slot at index {i}."); + + ids.Add(LevelId.Of(level.Id)); + } + + return Campaign.Of(ids); + } + + public LevelResource Find(LevelId id) => + Levels.FirstOrDefault(level => level != null && level.Id == id.Value); + + public PackedScene SceneFor(LevelId id) => Find(id)?.Scene; +} diff --git a/scripts/Resources/LevelResource.cs b/scripts/Resources/LevelResource.cs index 7db4219..51b003d 100644 --- a/scripts/Resources/LevelResource.cs +++ b/scripts/Resources/LevelResource.cs @@ -2,12 +2,33 @@ using Godot; namespace Mr.BrickAdventures.scripts.Resources; +/// +/// One authored Level: its stable id, its display name key, and the scene to load. +/// +/// +/// +/// is what Playthroughs and Best Times reference, so it must never change once a +/// build has shipped — unlike position in a list, which is what the old +/// GameManager.LevelScenes array used and which every save depended on. +/// +/// +/// The scene is a rather than a path string. The previous +/// ScenePath field was never read by anything and had rotted: forest_1.tres pointed at +/// res://scenes/level_forest_5.tscn, which does not exist. An exported reference is tracked by +/// the editor and cannot drift. +/// +/// [GlobalClass] public partial class LevelResource : Resource { - [Export] + /// Stable identity. Referenced by saves — do not change after shipping. + [Export] + public string Id { get; set; } = string.Empty; + + /// Translation key for the player-facing name. Labels auto-translate it. + [Export] public string LevelName { get; set; } = string.Empty; - [Export] - public string ScenePath { get; set; } = string.Empty; -} \ No newline at end of file + [Export] + public PackedScene Scene { get; set; } +} diff --git a/translations.csv b/translations.csv index a1ede99..9e64864 100644 --- a/translations.csv +++ b/translations.csv @@ -61,3 +61,6 @@ MAGNETIC_DESCRIPTION,Attract coins,Przyciąga monety w pobliżu LEVEL_1_TOOLTIP_1,Some blocks might collapse,Niektóre bloki mogą się zapaść. LEVEL_1_TOOLTIP_2,Jump to the other side!,Przeskocz na drugą stronę! LEVEL_1_TOOLTIP_3,"To rescue your child, you need to find the lever.",Uratuj dziecko poprzez aktywację dźwigni. +LEVEL_TUTORIAL_1_NAME,TUTORIAL,SAMOUCZEK +LEVEL_6_NAME,VILLAGE – 6,WIOSKA – 6 +LEVEL_FOREST_1_NAME,FOREST – 1,LAS – 1