Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Classes/MapAreas/MapArea.cs.uid
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
uid://dwi3hewlws25r
134 changes: 134 additions & 0 deletions Classes/MapAreas/MapLevels.cs
Original file line number Diff line number Diff line change
@@ -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; }

/// <summary>
/// Rooms that exist at set levels, only one room can be set per y-level.
/// </summary>
public Dictionary<int, Stages> SetRooms { get; private set; } =
new()
{
{ 0, Stages.Battle }, //The first, e.g. y = 0 room, should always be a battle.
};

/// <summary>
/// Adds a set room type to be generated guaranteed. Additional entries in the same y-level are ignored.
/// This ignores minimum y-heights.
/// </summary>
/// <param name="height">The y-level of the rooms</param>
/// <param name="roomType">The room type to be set.</param>
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 };

/// <summary>
/// The odds for each stage to appear in a non-set room position.
/// </summary>
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];
}
}

/// <summary>
/// Rooms that exist at set levels, only one room can be set per y-level.
/// </summary>
public Dictionary<Stages, int> MinHeights { get; private set; } = new();

/// <summary>
/// Adds a minimum y-height for a room type. Can only have one set per room type
/// </summary>
/// <param name="height">The y-level of the room type</param>
/// <param name="roomType">The room type to be set.</param>
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];
}
}
1 change: 1 addition & 0 deletions Classes/MapAreas/MapLevels.cs.uid
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
uid://dhcmdrux47fx5
78 changes: 16 additions & 62 deletions Globals/FunkEngineNameSpace.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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; }

/// <summary>
/// Rooms that exist at set levels, only one room can be set per y-level.
/// </summary>
public Dictionary<int, Stages> 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 };

/// <summary>
/// The odds for each stage to appear in a non-set room position.
/// </summary>
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];
}
}

/// <summary>
/// Adds a set room type to be generated guaranteed. Additional entries in the same y-level are ignored.
/// </summary>
/// <param name="height">The y-level of the rooms</param>
/// <param name="roomType">The room type to be set.</param>
public MapConfig AddSetRoom(int height, Stages roomType)
{
SetRooms.TryAdd(height, roomType);
return this;
}
}

/**
* <summary>Initializes the map with max <c>width</c>, max <c>height</c>, and with number of <c>paths</c>.</summary>
*/
public void InitMapGrid(MapConfig curConfig)
public void InitMapGrid(MapLevels.MapConfig curConfig)
{
_curIdx = 0;
_rooms = [];
Expand All @@ -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),
Expand All @@ -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))
Expand All @@ -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
Expand Down
2 changes: 1 addition & 1 deletion Globals/SaveSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
54 changes: 22 additions & 32 deletions Globals/StageProducer.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.Threading.Tasks;
using FunkEngine;
using FunkEngine.Classes.MidiMaestro;
using Godot;

/**
Expand All @@ -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;
Expand Down Expand Up @@ -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();
Expand All @@ -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;
Expand Down Expand Up @@ -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:
Expand All @@ -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;
Expand Down Expand Up @@ -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.
/// </summary>
/// <returns>True if there is another area.</returns>
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();
Expand Down
7 changes: 1 addition & 6 deletions Scenes/AreaBasedBackground.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,6 @@ public partial class AreaBasedBackground : TextureRect
{
public override void _Ready()
{
Texture = StageProducer.CurArea switch
{
Area.Forest => GD.Load<Texture2D>("res://SharedAssets/BackGround_Full.png"),
Area.City => GD.Load<Texture2D>("res://icon.svg"),
_ => null,
};
Texture = GD.Load<Texture2D>(StageProducer.CurLevel.BackgroundPath);
}
}
Loading