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