Skip to content

Commit f026ef3

Browse files
authored
Rework Areas into MapLevels class (#192)
Added customizable progression in levels Added ability for some stages to only appear in certain y heights
1 parent 55f968f commit f026ef3

File tree

10 files changed

+181
-106
lines changed

10 files changed

+181
-106
lines changed

Classes/MapAreas/MapArea.cs.uid

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
uid://dwi3hewlws25r

Classes/MapAreas/MapLevels.cs

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using FunkEngine;
4+
using Godot;
5+
6+
public class MapLevels
7+
{
8+
public struct MapConfig
9+
{
10+
public int Width { get; private set; }
11+
public int Height { get; private set; }
12+
public int Paths { get; private set; }
13+
14+
/// <summary>
15+
/// Rooms that exist at set levels, only one room can be set per y-level.
16+
/// </summary>
17+
public Dictionary<int, Stages> SetRooms { get; private set; } =
18+
new()
19+
{
20+
{ 0, Stages.Battle }, //The first, e.g. y = 0 room, should always be a battle.
21+
};
22+
23+
/// <summary>
24+
/// Adds a set room type to be generated guaranteed. Additional entries in the same y-level are ignored.
25+
/// This ignores minimum y-heights.
26+
/// </summary>
27+
/// <param name="height">The y-level of the rooms</param>
28+
/// <param name="roomType">The room type to be set.</param>
29+
public MapConfig AddSetRoom(int height, Stages roomType)
30+
{
31+
SetRooms.TryAdd(height, roomType);
32+
return this;
33+
}
34+
35+
public const int NumStages = 2;
36+
37+
public static readonly Stages[] StagsToRoll = new[] { Stages.Battle, Stages.Chest };
38+
39+
/// <summary>
40+
/// The odds for each stage to appear in a non-set room position.
41+
/// </summary>
42+
public float[] StageOdds = new float[2];
43+
44+
public MapConfig(int width, int height, int paths, float[] odds)
45+
{
46+
Width = width;
47+
Height = height;
48+
Paths = paths;
49+
for (int i = 0; i < NumStages; i++)
50+
{
51+
StageOdds[i] = odds[i];
52+
}
53+
}
54+
55+
/// <summary>
56+
/// Rooms that exist at set levels, only one room can be set per y-level.
57+
/// </summary>
58+
public Dictionary<Stages, int> MinHeights { get; private set; } = new();
59+
60+
/// <summary>
61+
/// Adds a minimum y-height for a room type. Can only have one set per room type
62+
/// </summary>
63+
/// <param name="height">The y-level of the room type</param>
64+
/// <param name="roomType">The room type to be set.</param>
65+
public MapConfig AddMinHeight(Stages roomType, int height)
66+
{
67+
MinHeights.TryAdd(roomType, height);
68+
return this;
69+
}
70+
}
71+
72+
private MapLevels(
73+
int id,
74+
MapConfig config,
75+
int[] battleSongs,
76+
int[] eliteSongs,
77+
int[] bossSongs,
78+
int nextLevelId = -1,
79+
string backgroundPath = "res://SharedAssets/BackGround_Full.png"
80+
)
81+
{
82+
Id = id;
83+
CurMapConfig = config;
84+
NormalBattles = battleSongs;
85+
EliteBattles = eliteSongs;
86+
BossBattles = bossSongs;
87+
NextLevel = nextLevelId;
88+
BackgroundPath = backgroundPath;
89+
}
90+
91+
public int Id { get; private set; }
92+
public string BackgroundPath { get; private set; }
93+
private MapConfig CurMapConfig;
94+
private int NextLevel;
95+
96+
//These tie into the Scribe SongDictionary
97+
public int[] NormalBattles { get; private set; }
98+
public int[] EliteBattles { get; private set; }
99+
public int[] BossBattles { get; private set; }
100+
101+
#region Preset Levels
102+
private static readonly MapConfig FirstMapConfig = new MapConfig(7, 6, 3, [10, 1])
103+
.AddSetRoom(3, Stages.Chest)
104+
.AddMinHeight(Stages.Chest, 2);
105+
106+
private static readonly MapConfig TutorialMapConfig = new MapConfig(1, 2, 1, [10, 0]);
107+
108+
private static readonly MapLevels[] PresetLevels = new[]
109+
{
110+
new MapLevels(0, TutorialMapConfig, [0], [], [3], 1),
111+
new MapLevels(1, FirstMapConfig, [1, 2, 3], [], [0], -1),
112+
};
113+
#endregion
114+
115+
public MapConfig GetCurrentConfig()
116+
{
117+
return CurMapConfig;
118+
}
119+
120+
public bool HasMoreMaps()
121+
{
122+
return NextLevel != -1;
123+
}
124+
125+
public MapLevels GetNextLevel()
126+
{
127+
return !HasMoreMaps() ? null : PresetLevels[NextLevel];
128+
}
129+
130+
public static MapLevels GetLevelFromId(int id)
131+
{
132+
return PresetLevels[id];
133+
}
134+
}

Classes/MapAreas/MapLevels.cs.uid

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
uid://dhcmdrux47fx5

Globals/FunkEngineNameSpace.cs

Lines changed: 16 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -245,20 +245,14 @@ public enum BattleEffectTrigger
245245

246246
public enum Stages
247247
{
248-
Title,
249-
Battle,
250-
Chest,
248+
Battle = 0,
249+
Chest = 1,
251250
Boss,
252251
Quit,
253252
Map,
254253
Load,
255254
Continue,
256-
}
257-
258-
public enum Area
259-
{
260-
Forest = 0,
261-
City = 1,
255+
Title,
262256
}
263257

264258
public enum Rarity
@@ -316,58 +310,10 @@ public void AddChild(int newIdx)
316310
}
317311
}
318312

319-
//TODO: Make odds for rooms based on y-level, e.g. elites only spawn on y > 3
320-
public struct MapConfig
321-
{
322-
public int Width { get; private set; }
323-
public int Height { get; private set; }
324-
public int Paths { get; private set; }
325-
326-
/// <summary>
327-
/// Rooms that exist at set levels, only one room can be set per y-level.
328-
/// </summary>
329-
public Dictionary<int, Stages> SetRooms { get; private set; } =
330-
new()
331-
{
332-
{ 0, Stages.Battle }, //The first, e.g. y = 0 room, should always be a battle.
333-
};
334-
335-
public const int NumStages = 2;
336-
337-
public static readonly Stages[] StagsToRoll = new[] { Stages.Battle, Stages.Chest };
338-
339-
/// <summary>
340-
/// The odds for each stage to appear in a non-set room position.
341-
/// </summary>
342-
public float[] StageOdds = new float[2];
343-
344-
public MapConfig(int width, int height, int paths, float[] odds)
345-
{
346-
Width = width;
347-
Height = height;
348-
Paths = paths;
349-
for (int i = 0; i < NumStages; i++)
350-
{
351-
StageOdds[i] = odds[i];
352-
}
353-
}
354-
355-
/// <summary>
356-
/// Adds a set room type to be generated guaranteed. Additional entries in the same y-level are ignored.
357-
/// </summary>
358-
/// <param name="height">The y-level of the rooms</param>
359-
/// <param name="roomType">The room type to be set.</param>
360-
public MapConfig AddSetRoom(int height, Stages roomType)
361-
{
362-
SetRooms.TryAdd(height, roomType);
363-
return this;
364-
}
365-
}
366-
367313
/**
368314
* <summary>Initializes the map with max <c>width</c>, max <c>height</c>, and with number of <c>paths</c>.</summary>
369315
*/
370-
public void InitMapGrid(MapConfig curConfig)
316+
public void InitMapGrid(MapLevels.MapConfig curConfig)
371317
{
372318
_curIdx = 0;
373319
_rooms = [];
@@ -387,7 +333,7 @@ public void InitMapGrid(MapConfig curConfig)
387333
}
388334

389335
/**Start at x, y, assume prev room exists. Picks new x pos within +/- 1, attaches recursively*/
390-
private void GeneratePath_r(int x, int y, MapConfig curConfig)
336+
private void GeneratePath_r(int x, int y, MapLevels.MapConfig curConfig)
391337
{
392338
int nextX = StageProducer.GlobalRng.RandiRange(
393339
Math.Max(x - 1, 0),
@@ -410,7 +356,7 @@ private void GeneratePath_r(int x, int y, MapConfig curConfig)
410356
}
411357
}
412358

413-
private Stages PickRoomType(int x, int y, MapConfig curConfig)
359+
private Stages PickRoomType(int x, int y, MapLevels.MapConfig curConfig)
414360
{
415361
//If the y has a set room return it.
416362
if (curConfig.SetRooms.TryGetValue(y, out Stages result))
@@ -419,8 +365,16 @@ private Stages PickRoomType(int x, int y, MapConfig curConfig)
419365
}
420366

421367
//Random roll for the room type.
422-
int idx = (int)StageProducer.GlobalRng.RandWeighted(curConfig.StageOdds);
423-
return MapConfig.StagsToRoll[idx];
368+
float[] validRooms = curConfig.StageOdds;
369+
foreach ((Stages stage, int height) in curConfig.MinHeights)
370+
{
371+
if (y < height)
372+
{
373+
validRooms[(int)stage] = 0;
374+
}
375+
}
376+
int idx = (int)StageProducer.GlobalRng.RandWeighted(validRooms);
377+
return MapLevels.MapConfig.StagsToRoll[idx];
424378
}
425379

426380
//Asserts that if there is a room at the same x, but y+1 they are connected

Globals/SaveSystem.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -411,7 +411,7 @@ public static void SaveGame()
411411
noteIds,
412412
relicIds,
413413
StageProducer.PlayerStats.CurrentHealth,
414-
(int)StageProducer.CurArea,
414+
StageProducer.CurLevel.Id,
415415
StageProducer.PlayerStats.Money
416416
);
417417
string json = JsonSerializer.Serialize(sv);

Globals/StageProducer.cs

Lines changed: 22 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System;
22
using System.Threading.Tasks;
33
using FunkEngine;
4+
using FunkEngine.Classes.MidiMaestro;
45
using Godot;
56

67
/**
@@ -13,28 +14,11 @@ public partial class StageProducer : Node
1314

1415
public static readonly RandomNumberGenerator GlobalRng = new();
1516

16-
private static readonly MapGrid.MapConfig FirstMapConfig = new MapGrid.MapConfig(
17-
7,
18-
6,
19-
3,
20-
[10, 1]
21-
).AddSetRoom(3, Stages.Chest);
22-
23-
private static readonly MapGrid.MapConfig TestMapConfig = new MapGrid.MapConfig(
24-
10,
25-
10,
26-
5,
27-
[10, 2]
28-
)
29-
.AddSetRoom(3, Stages.Chest)
30-
.AddSetRoom(6, Stages.Chest);
31-
32-
private static readonly MapGrid.MapConfig[] MapConfigs = new[] { FirstMapConfig };
17+
public static MapLevels CurLevel { get; private set; }
3318

3419
public static MapGrid Map { get; private set; } = new();
3520
private Stages _curStage = Stages.Title;
3621
public static int CurRoom { get; private set; }
37-
public static Area CurArea { get; private set; } = Area.Forest;
3822

3923
private Node _curScene;
4024
private Node _preloadStage;
@@ -70,14 +54,15 @@ private void InitFromCfg()
7054

7155
private void GenerateMapConsistent()
7256
{
73-
GlobalRng.State = GlobalRng.Seed << 5 / 2; //Fudge seed state, to get consistent maps across new/loaded games
74-
Map.InitMapGrid(MapConfigs[(int)CurArea]);
57+
//Fudge seed state, to get consistent maps across new/loaded games, might be bad practice
58+
GlobalRng.State = GlobalRng.Seed << 5 / 2;
59+
Map.InitMapGrid(CurLevel.GetCurrentConfig());
7560
}
7661

7762
private void StartNewGame()
7863
{
7964
GlobalRng.Randomize();
80-
CurArea = Area.Forest;
65+
CurLevel = MapLevels.GetLevelFromId(1);
8166
GenerateMapConsistent();
8267

8368
PlayerStats = new PlayerStats();
@@ -96,7 +81,7 @@ private bool LoadGame()
9681
return false;
9782
}
9883
GlobalRng.Seed = sv.RngSeed;
99-
CurArea = (Area)sv.Area;
84+
CurLevel = MapLevels.GetLevelFromId(sv.Area);
10085
GenerateMapConsistent();
10186
GlobalRng.State = sv.RngState;
10287
CurRoom = sv.LastRoomIdx;
@@ -196,7 +181,7 @@ public void TransitionStage(Stages nextStage, int nextRoomIdx = -1)
196181
GetTree().Quit();
197182
return;
198183
case Stages.Continue:
199-
ProgressAreas();
184+
ProgressLevels();
200185
GetTree().ChangeSceneToFile("res://Scenes/Maps/InBetween.tscn");
201186
break;
202187
default:
@@ -223,13 +208,18 @@ private BattleConfig MakeBattleConfig(Stages nextRoom, int nextRoomIdx)
223208
switch (nextRoom)
224209
{
225210
case Stages.Battle:
226-
int songIdx = stageRng.RandiRange(1, 3);
227-
result.CurSong = Scribe.SongDictionary[songIdx];
228-
result.EnemyScenePath = Scribe.SongDictionary[songIdx].EnemyScenePath;
211+
int songIdx = stageRng.RandiRange(0, CurLevel.NormalBattles.Length - 1);
212+
result.CurSong = Scribe.SongDictionary[CurLevel.NormalBattles[songIdx]];
213+
result.EnemyScenePath = Scribe
214+
.SongDictionary[CurLevel.NormalBattles[songIdx]]
215+
.EnemyScenePath;
229216
break;
230217
case Stages.Boss:
231-
result.EnemyScenePath = Scribe.SongDictionary[0].EnemyScenePath;
232-
result.CurSong = Scribe.SongDictionary[0];
218+
int bossIdx = stageRng.RandiRange(0, CurLevel.BossBattles.Length - 1);
219+
result.CurSong = Scribe.SongDictionary[CurLevel.BossBattles[bossIdx]];
220+
result.EnemyScenePath = Scribe
221+
.SongDictionary[CurLevel.BossBattles[bossIdx]]
222+
.EnemyScenePath;
233223
break;
234224
case Stages.Chest:
235225
break;
@@ -259,14 +249,14 @@ public override void _Input(InputEvent @event)
259249
/// There should always be a mapconfig for each area. It's preferable to crash later if there isn't even a placeholder config.
260250
/// </summary>
261251
/// <returns>True if there is another area.</returns>
262-
public static bool IsMoreAreas()
252+
public static bool IsMoreLevels()
263253
{
264-
return (int)CurArea + 1 < MapConfigs.Length;
254+
return CurLevel.HasMoreMaps();
265255
}
266256

267-
public void ProgressAreas()
257+
public void ProgressLevels()
268258
{
269-
CurArea += 1;
259+
CurLevel = CurLevel.GetNextLevel();
270260

271261
Map = new();
272262
GenerateMapConsistent();

Scenes/AreaBasedBackground.cs

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,6 @@ public partial class AreaBasedBackground : TextureRect
66
{
77
public override void _Ready()
88
{
9-
Texture = StageProducer.CurArea switch
10-
{
11-
Area.Forest => GD.Load<Texture2D>("res://SharedAssets/BackGround_Full.png"),
12-
Area.City => GD.Load<Texture2D>("res://icon.svg"),
13-
_ => null,
14-
};
9+
Texture = GD.Load<Texture2D>(StageProducer.CurLevel.BackgroundPath);
1510
}
1611
}

0 commit comments

Comments
 (0)