From 10581414e41a799d5e6309d4468d433882d21d51 Mon Sep 17 00:00:00 2001 From: LifeHckr Date: Thu, 1 May 2025 19:57:45 -0700 Subject: [PATCH] Rework Areas into MapLevels class Added customizable progression in levels Added ability for some stages to only appear in certain y heights --- Classes/MapAreas/MapArea.cs.uid | 1 + Classes/MapAreas/MapLevels.cs | 134 +++++++++++++++++++++++++ Classes/MapAreas/MapLevels.cs.uid | 1 + Globals/FunkEngineNameSpace.cs | 78 +++----------- Globals/SaveSystem.cs | 2 +- Globals/StageProducer.cs | 54 ++++------ Scenes/AreaBasedBackground.cs | 7 +- Scenes/Maps/InBetween.tscn | 2 +- Scenes/Maps/Scripts/Cartographer.cs | 2 +- Scenes/UI/TitleScreen/TitleScreen.tscn | 6 +- 10 files changed, 181 insertions(+), 106 deletions(-) create mode 100644 Classes/MapAreas/MapArea.cs.uid create mode 100644 Classes/MapAreas/MapLevels.cs create mode 100644 Classes/MapAreas/MapLevels.cs.uid diff --git a/Classes/MapAreas/MapArea.cs.uid b/Classes/MapAreas/MapArea.cs.uid new file mode 100644 index 00000000..cc07f4c9 --- /dev/null +++ b/Classes/MapAreas/MapArea.cs.uid @@ -0,0 +1 @@ +uid://dwi3hewlws25r diff --git a/Classes/MapAreas/MapLevels.cs b/Classes/MapAreas/MapLevels.cs new file mode 100644 index 00000000..6287ada7 --- /dev/null +++ b/Classes/MapAreas/MapLevels.cs @@ -0,0 +1,134 @@ +using System; +using System.Collections.Generic; +using FunkEngine; +using Godot; + +public class MapLevels +{ + public struct MapConfig + { + public int Width { get; private set; } + public int Height { get; private set; } + public int Paths { get; private set; } + + /// + /// Rooms that exist at set levels, only one room can be set per y-level. + /// + public Dictionary SetRooms { get; private set; } = + new() + { + { 0, Stages.Battle }, //The first, e.g. y = 0 room, should always be a battle. + }; + + /// + /// Adds a set room type to be generated guaranteed. Additional entries in the same y-level are ignored. + /// This ignores minimum y-heights. + /// + /// The y-level of the rooms + /// The room type to be set. + public MapConfig AddSetRoom(int height, Stages roomType) + { + SetRooms.TryAdd(height, roomType); + return this; + } + + public const int NumStages = 2; + + public static readonly Stages[] StagsToRoll = new[] { Stages.Battle, Stages.Chest }; + + /// + /// The odds for each stage to appear in a non-set room position. + /// + public float[] StageOdds = new float[2]; + + public MapConfig(int width, int height, int paths, float[] odds) + { + Width = width; + Height = height; + Paths = paths; + for (int i = 0; i < NumStages; i++) + { + StageOdds[i] = odds[i]; + } + } + + /// + /// Rooms that exist at set levels, only one room can be set per y-level. + /// + public Dictionary MinHeights { get; private set; } = new(); + + /// + /// Adds a minimum y-height for a room type. Can only have one set per room type + /// + /// The y-level of the room type + /// The room type to be set. + public MapConfig AddMinHeight(Stages roomType, int height) + { + MinHeights.TryAdd(roomType, height); + return this; + } + } + + private MapLevels( + int id, + MapConfig config, + int[] battleSongs, + int[] eliteSongs, + int[] bossSongs, + int nextLevelId = -1, + string backgroundPath = "res://SharedAssets/BackGround_Full.png" + ) + { + Id = id; + CurMapConfig = config; + NormalBattles = battleSongs; + EliteBattles = eliteSongs; + BossBattles = bossSongs; + NextLevel = nextLevelId; + BackgroundPath = backgroundPath; + } + + public int Id { get; private set; } + public string BackgroundPath { get; private set; } + private MapConfig CurMapConfig; + private int NextLevel; + + //These tie into the Scribe SongDictionary + public int[] NormalBattles { get; private set; } + public int[] EliteBattles { get; private set; } + public int[] BossBattles { get; private set; } + + #region Preset Levels + private static readonly MapConfig FirstMapConfig = new MapConfig(7, 6, 3, [10, 1]) + .AddSetRoom(3, Stages.Chest) + .AddMinHeight(Stages.Chest, 2); + + private static readonly MapConfig TutorialMapConfig = new MapConfig(1, 2, 1, [10, 0]); + + private static readonly MapLevels[] PresetLevels = new[] + { + new MapLevels(0, TutorialMapConfig, [0], [], [3], 1), + new MapLevels(1, FirstMapConfig, [1, 2, 3], [], [0], -1), + }; + #endregion + + public MapConfig GetCurrentConfig() + { + return CurMapConfig; + } + + public bool HasMoreMaps() + { + return NextLevel != -1; + } + + public MapLevels GetNextLevel() + { + return !HasMoreMaps() ? null : PresetLevels[NextLevel]; + } + + public static MapLevels GetLevelFromId(int id) + { + return PresetLevels[id]; + } +} diff --git a/Classes/MapAreas/MapLevels.cs.uid b/Classes/MapAreas/MapLevels.cs.uid new file mode 100644 index 00000000..7e949af2 --- /dev/null +++ b/Classes/MapAreas/MapLevels.cs.uid @@ -0,0 +1 @@ +uid://dhcmdrux47fx5 diff --git a/Globals/FunkEngineNameSpace.cs b/Globals/FunkEngineNameSpace.cs index c73800f6..8bf7d56f 100644 --- a/Globals/FunkEngineNameSpace.cs +++ b/Globals/FunkEngineNameSpace.cs @@ -245,20 +245,14 @@ public enum BattleEffectTrigger public enum Stages { - Title, - Battle, - Chest, + Battle = 0, + Chest = 1, Boss, Quit, Map, Load, Continue, -} - -public enum Area -{ - Forest = 0, - City = 1, + Title, } public enum Rarity @@ -316,58 +310,10 @@ public void AddChild(int newIdx) } } - //TODO: Make odds for rooms based on y-level, e.g. elites only spawn on y > 3 - public struct MapConfig - { - public int Width { get; private set; } - public int Height { get; private set; } - public int Paths { get; private set; } - - /// - /// Rooms that exist at set levels, only one room can be set per y-level. - /// - public Dictionary SetRooms { get; private set; } = - new() - { - { 0, Stages.Battle }, //The first, e.g. y = 0 room, should always be a battle. - }; - - public const int NumStages = 2; - - public static readonly Stages[] StagsToRoll = new[] { Stages.Battle, Stages.Chest }; - - /// - /// The odds for each stage to appear in a non-set room position. - /// - public float[] StageOdds = new float[2]; - - public MapConfig(int width, int height, int paths, float[] odds) - { - Width = width; - Height = height; - Paths = paths; - for (int i = 0; i < NumStages; i++) - { - StageOdds[i] = odds[i]; - } - } - - /// - /// Adds a set room type to be generated guaranteed. Additional entries in the same y-level are ignored. - /// - /// The y-level of the rooms - /// The room type to be set. - public MapConfig AddSetRoom(int height, Stages roomType) - { - SetRooms.TryAdd(height, roomType); - return this; - } - } - /** * Initializes the map with max width, max height, and with number of paths. */ - public void InitMapGrid(MapConfig curConfig) + public void InitMapGrid(MapLevels.MapConfig curConfig) { _curIdx = 0; _rooms = []; @@ -387,7 +333,7 @@ public void InitMapGrid(MapConfig curConfig) } /**Start at x, y, assume prev room exists. Picks new x pos within +/- 1, attaches recursively*/ - private void GeneratePath_r(int x, int y, MapConfig curConfig) + private void GeneratePath_r(int x, int y, MapLevels.MapConfig curConfig) { int nextX = StageProducer.GlobalRng.RandiRange( Math.Max(x - 1, 0), @@ -410,7 +356,7 @@ private void GeneratePath_r(int x, int y, MapConfig curConfig) } } - private Stages PickRoomType(int x, int y, MapConfig curConfig) + private Stages PickRoomType(int x, int y, MapLevels.MapConfig curConfig) { //If the y has a set room return it. if (curConfig.SetRooms.TryGetValue(y, out Stages result)) @@ -419,8 +365,16 @@ private Stages PickRoomType(int x, int y, MapConfig curConfig) } //Random roll for the room type. - int idx = (int)StageProducer.GlobalRng.RandWeighted(curConfig.StageOdds); - return MapConfig.StagsToRoll[idx]; + float[] validRooms = curConfig.StageOdds; + foreach ((Stages stage, int height) in curConfig.MinHeights) + { + if (y < height) + { + validRooms[(int)stage] = 0; + } + } + int idx = (int)StageProducer.GlobalRng.RandWeighted(validRooms); + return MapLevels.MapConfig.StagsToRoll[idx]; } //Asserts that if there is a room at the same x, but y+1 they are connected diff --git a/Globals/SaveSystem.cs b/Globals/SaveSystem.cs index 86cb317f..d78f27df 100644 --- a/Globals/SaveSystem.cs +++ b/Globals/SaveSystem.cs @@ -411,7 +411,7 @@ public static void SaveGame() noteIds, relicIds, StageProducer.PlayerStats.CurrentHealth, - (int)StageProducer.CurArea, + StageProducer.CurLevel.Id, StageProducer.PlayerStats.Money ); string json = JsonSerializer.Serialize(sv); diff --git a/Globals/StageProducer.cs b/Globals/StageProducer.cs index 382404ff..9379c1c5 100644 --- a/Globals/StageProducer.cs +++ b/Globals/StageProducer.cs @@ -1,6 +1,7 @@ using System; using System.Threading.Tasks; using FunkEngine; +using FunkEngine.Classes.MidiMaestro; using Godot; /** @@ -13,28 +14,11 @@ public partial class StageProducer : Node public static readonly RandomNumberGenerator GlobalRng = new(); - private static readonly MapGrid.MapConfig FirstMapConfig = new MapGrid.MapConfig( - 7, - 6, - 3, - [10, 1] - ).AddSetRoom(3, Stages.Chest); - - private static readonly MapGrid.MapConfig TestMapConfig = new MapGrid.MapConfig( - 10, - 10, - 5, - [10, 2] - ) - .AddSetRoom(3, Stages.Chest) - .AddSetRoom(6, Stages.Chest); - - private static readonly MapGrid.MapConfig[] MapConfigs = new[] { FirstMapConfig }; + public static MapLevels CurLevel { get; private set; } public static MapGrid Map { get; private set; } = new(); private Stages _curStage = Stages.Title; public static int CurRoom { get; private set; } - public static Area CurArea { get; private set; } = Area.Forest; private Node _curScene; private Node _preloadStage; @@ -70,14 +54,15 @@ private void InitFromCfg() private void GenerateMapConsistent() { - GlobalRng.State = GlobalRng.Seed << 5 / 2; //Fudge seed state, to get consistent maps across new/loaded games - Map.InitMapGrid(MapConfigs[(int)CurArea]); + //Fudge seed state, to get consistent maps across new/loaded games, might be bad practice + GlobalRng.State = GlobalRng.Seed << 5 / 2; + Map.InitMapGrid(CurLevel.GetCurrentConfig()); } private void StartNewGame() { GlobalRng.Randomize(); - CurArea = Area.Forest; + CurLevel = MapLevels.GetLevelFromId(1); GenerateMapConsistent(); PlayerStats = new PlayerStats(); @@ -96,7 +81,7 @@ private bool LoadGame() return false; } GlobalRng.Seed = sv.RngSeed; - CurArea = (Area)sv.Area; + CurLevel = MapLevels.GetLevelFromId(sv.Area); GenerateMapConsistent(); GlobalRng.State = sv.RngState; CurRoom = sv.LastRoomIdx; @@ -196,7 +181,7 @@ public void TransitionStage(Stages nextStage, int nextRoomIdx = -1) GetTree().Quit(); return; case Stages.Continue: - ProgressAreas(); + ProgressLevels(); GetTree().ChangeSceneToFile("res://Scenes/Maps/InBetween.tscn"); break; default: @@ -223,13 +208,18 @@ private BattleConfig MakeBattleConfig(Stages nextRoom, int nextRoomIdx) switch (nextRoom) { case Stages.Battle: - int songIdx = stageRng.RandiRange(1, 3); - result.CurSong = Scribe.SongDictionary[songIdx]; - result.EnemyScenePath = Scribe.SongDictionary[songIdx].EnemyScenePath; + int songIdx = stageRng.RandiRange(0, CurLevel.NormalBattles.Length - 1); + result.CurSong = Scribe.SongDictionary[CurLevel.NormalBattles[songIdx]]; + result.EnemyScenePath = Scribe + .SongDictionary[CurLevel.NormalBattles[songIdx]] + .EnemyScenePath; break; case Stages.Boss: - result.EnemyScenePath = Scribe.SongDictionary[0].EnemyScenePath; - result.CurSong = Scribe.SongDictionary[0]; + int bossIdx = stageRng.RandiRange(0, CurLevel.BossBattles.Length - 1); + result.CurSong = Scribe.SongDictionary[CurLevel.BossBattles[bossIdx]]; + result.EnemyScenePath = Scribe + .SongDictionary[CurLevel.BossBattles[bossIdx]] + .EnemyScenePath; break; case Stages.Chest: break; @@ -259,14 +249,14 @@ public override void _Input(InputEvent @event) /// There should always be a mapconfig for each area. It's preferable to crash later if there isn't even a placeholder config. /// /// True if there is another area. - public static bool IsMoreAreas() + public static bool IsMoreLevels() { - return (int)CurArea + 1 < MapConfigs.Length; + return CurLevel.HasMoreMaps(); } - public void ProgressAreas() + public void ProgressLevels() { - CurArea += 1; + CurLevel = CurLevel.GetNextLevel(); Map = new(); GenerateMapConsistent(); diff --git a/Scenes/AreaBasedBackground.cs b/Scenes/AreaBasedBackground.cs index 8a5275a2..3ae8150a 100644 --- a/Scenes/AreaBasedBackground.cs +++ b/Scenes/AreaBasedBackground.cs @@ -6,11 +6,6 @@ public partial class AreaBasedBackground : TextureRect { public override void _Ready() { - Texture = StageProducer.CurArea switch - { - Area.Forest => GD.Load("res://SharedAssets/BackGround_Full.png"), - Area.City => GD.Load("res://icon.svg"), - _ => null, - }; + Texture = GD.Load(StageProducer.CurLevel.BackgroundPath); } } diff --git a/Scenes/Maps/InBetween.tscn b/Scenes/Maps/InBetween.tscn index d425f862..10f2cf20 100644 --- a/Scenes/Maps/InBetween.tscn +++ b/Scenes/Maps/InBetween.tscn @@ -20,5 +20,5 @@ offset_bottom = 284.0 theme = ExtResource("2_dapxv") text = "INBETWEEN_CONTINUE" script = ExtResource("3_35xdc") -ScenePath = 5 +ScenePath = 6 _startFocused = true diff --git a/Scenes/Maps/Scripts/Cartographer.cs b/Scenes/Maps/Scripts/Cartographer.cs index ebd07533..94573f16 100644 --- a/Scenes/Maps/Scripts/Cartographer.cs +++ b/Scenes/Maps/Scripts/Cartographer.cs @@ -150,7 +150,7 @@ private void EnterStage(int roomIdx, Button button) private void WinArea() { - if (StageProducer.IsMoreAreas()) + if (StageProducer.IsMoreLevels()) { GetTree().Paused = false; //What the living fuck? Can't do this during ready? diff --git a/Scenes/UI/TitleScreen/TitleScreen.tscn b/Scenes/UI/TitleScreen/TitleScreen.tscn index 1bd9f8c2..d16c8ea4 100644 --- a/Scenes/UI/TitleScreen/TitleScreen.tscn +++ b/Scenes/UI/TitleScreen/TitleScreen.tscn @@ -183,7 +183,7 @@ theme = ExtResource("13_v0au1") theme_override_font_sizes/font_size = 24 text = "TITLE_START" script = ExtResource("2_7f3m6") -ScenePath = 5 +ScenePath = 4 _startFocused = true [node name="MarginContainer3" type="MarginContainer" parent="VBoxContainer/HBoxContainer"] @@ -206,7 +206,7 @@ theme = ExtResource("13_v0au1") theme_override_font_sizes/font_size = 24 text = "TITLE_CONTINUE" script = ExtResource("2_7f3m6") -ScenePath = 6 +ScenePath = 5 [node name="MarginContainer2" type="MarginContainer" parent="VBoxContainer/HBoxContainer"] layout_mode = 2 @@ -227,7 +227,7 @@ theme = ExtResource("13_v0au1") theme_override_font_sizes/font_size = 24 text = "TITLE_QUIT" script = ExtResource("2_7f3m6") -ScenePath = 4 +ScenePath = 3 [node name="OptionsMargin" type="MarginContainer" parent="VBoxContainer"] layout_mode = 2