Revamp map route stuff

This commit is contained in:
2026-06-11 20:53:16 -07:00
parent fc598ab48f
commit 403b136c5c
34 changed files with 731 additions and 559 deletions
@@ -13,6 +13,7 @@ public partial class GameState
public FloorExitScreen() public FloorExitScreen()
{ {
OnAttach(() => Get<IGameRepo>().Pause()); OnAttach(() => Get<IGameRepo>().Pause());
OnDetach(() => Get<IGameRepo>().Resume());
} }
public Transition On(in Input.LoadNextFloor input) public Transition On(in Input.LoadNextFloor input)
@@ -11,5 +11,7 @@ public interface IDungeonFloor : INode3D
public ImmutableList<IDungeonRoom> Rooms { get; } public ImmutableList<IDungeonRoom> Rooms { get; }
public IDungeonRoom GetPlayersCurrentRoom();
public bool FloorIsLoaded { get; set; } public bool FloorIsLoaded { get; set; }
} }
@@ -35,7 +35,7 @@ public partial class FleeBehavior : Node3D, IBehavior
public void StartFlee(NavigationAgent3D navigationAgent) public void StartFlee(NavigationAgent3D navigationAgent)
{ {
var currentRoom = _map.GetPlayersCurrentRoom(); var currentRoom = _map.CurrentFloor.GetPlayersCurrentRoom();
var rooms = _game.CurrentFloor.Rooms; var rooms = _game.CurrentFloor.Rooms;
var validRooms = new Godot.Collections.Array<MonsterRoom>(rooms.OfType<MonsterRoom>()); var validRooms = new Godot.Collections.Array<MonsterRoom>(rooms.OfType<MonsterRoom>());
var randomRoom = validRooms.PickRandom(); var randomRoom = validRooms.PickRandom();
+13 -33
View File
@@ -185,12 +185,10 @@ public partial class Game : Node3D, IGame
PauseContainer.AddChild((Map)_map); PauseContainer.AddChild((Map)_map);
} }
public async void OnResolved() public void OnResolved()
{ {
LoadExistingGame(); LoadExistingGame();
await InitializeGame();
GameState.Set(GameRepo); GameState.Set(GameRepo);
GameState.Set(_player); GameState.Set(_player);
GameState.Set(_map); GameState.Set(_map);
@@ -200,13 +198,11 @@ public partial class Game : Node3D, IGame
GameState.Start(); GameState.Start();
this.Provide(); this.Provide();
InitializeGame();
InGameUI.UseTeleportPrompt.TeleportToNextFloor += UseTeleportPrompt_TeleportToNextFloor; InGameUI.UseTeleportPrompt.TeleportToNextFloor += UseTeleportPrompt_TeleportToNextFloor;
InGameUI.UseTeleportPrompt.CloseTeleportPrompt += UseTeleportPrompt_CloseTeleportPrompt; InGameUI.UseTeleportPrompt.CloseTeleportPrompt += UseTeleportPrompt_CloseTeleportPrompt;
LoadNextLevel.GoToNextFloor += FloorClearMenu_GoToNextFloor;
LoadNextLevel.Exit += FloorClearMenu_Exit; LoadNextLevel.Exit += FloorClearMenu_Exit;
LoadNextLevel.TransitionCompleted += FloorClearMenu_TransitionCompleted;
OnLoadLevelRequest += LoadLevel;
GameRepo.CloseInventoryEvent += ExitInventoryAction; GameRepo.CloseInventoryEvent += ExitInventoryAction;
@@ -250,12 +246,11 @@ public partial class Game : Node3D, IGame
public void LoadExistingGame() => SaveFile.Load().ContinueWith((_) => CallDeferred(nameof(FinishedLoadingSaveFile))); public void LoadExistingGame() => SaveFile.Load().ContinueWith((_) => CallDeferred(nameof(FinishedLoadingSaveFile)));
public async Task InitializeGame() public void InitializeGame()
{ {
_player.ResetPlayerData(); _player.ResetPlayerData();
_map.InitializeMapData(); _map.LoadFloor(_map.FloorRoute.First());
_effectService = new EffectService(this, _player, _map); _effectService = new EffectService(this, _player, _map);
await _map.LoadFloor();
} }
public async Task Save() => await SaveFile.Save(); public async Task Save() => await SaveFile.Save();
@@ -424,7 +419,6 @@ public partial class Game : Node3D, IGame
}) })
.Handle((in GameState.Output.LoadNextFloor _) => .Handle((in GameState.Output.LoadNextFloor _) =>
{ {
EmitSignal(SignalName.OnLoadLevelRequest);
var breakableItems = _player.Inventory.Items.Where(x => x.ItemTag == ItemTag.BreaksOnFloorExit).ToList(); var breakableItems = _player.Inventory.Items.Where(x => x.ItemTag == ItemTag.BreaksOnFloorExit).ToList();
foreach (IEquipableItem breakableItem in breakableItems) foreach (IEquipableItem breakableItem in breakableItems)
{ {
@@ -433,11 +427,9 @@ public partial class Game : Node3D, IGame
_player.Inventory.Remove(breakableItem); _player.Inventory.Remove(breakableItem);
} }
Task.Run(() => Save()); Task.Run(() => Save());
LoadNextLevel.FadeOut();
}) })
.Handle((in GameState.Output.ReturnToOverworld _) => .Handle((in GameState.Output.ReturnToOverworld _) =>
{ {
LoadNextLevel.FadeOut();
Task.Run(() => Save()); Task.Run(() => Save());
InitializeGame(); InitializeGame();
}) })
@@ -464,13 +456,6 @@ public partial class Game : Node3D, IGame
InGameUI.InventoryMenu.SetProcessInput(false); InGameUI.InventoryMenu.SetProcessInput(false);
} }
private async void LoadLevel()
{
await _map.LoadFloor();
}
private void FloorClearMenu_GoToNextFloor() => GameState.Input(new GameState.Input.LoadNextFloor());
private void DropRestorative(Vector3 vector) private void DropRestorative(Vector3 vector)
{ {
var restorativeScene = GD.Load<PackedScene>("res://src/items/restorative/Restorative.tscn"); var restorativeScene = GD.Load<PackedScene>("res://src/items/restorative/Restorative.tscn");
@@ -506,11 +491,6 @@ public partial class Game : Node3D, IGame
private void PointUpFinished() => GameState.Input(new GameState.Input.UseTeleport()); private void PointUpFinished() => GameState.Input(new GameState.Input.UseTeleport());
private void FloorClearMenu_TransitionCompleted()
{
GameRepo.Resume();
}
private void IsPaused_Sync(bool isPaused) => GetTree().Paused = isPaused; private void IsPaused_Sync(bool isPaused) => GetTree().Paused = isPaused;
private void FinishedLoadingSaveFile() => EmitSignal(SignalName.SaveFileLoaded); private void FinishedLoadingSaveFile() => EmitSignal(SignalName.SaveFileLoaded);
@@ -924,13 +904,13 @@ public partial class Game : Node3D, IGame
private void OnFloorLoadFinished() private void OnFloorLoadFinished()
{ {
LoadNextLevel.Hide();
GameLoaded?.Invoke(); GameLoaded?.Invoke();
_map.FadeIn();
if (GameOverMenu.Visible) if (GameOverMenu.Visible)
GameOverMenu.FadeOut(); GameOverMenu.FadeOut();
GameRepo.Resume();
_player.Activate(); _player.Activate();
_map.ShowMap();
GameState.Input(new GameState.Input.LoadNextFloor());
Resume();
} }
private void RustStatusChanged(bool rustStatus) private void RustStatusChanged(bool rustStatus)
@@ -1001,9 +981,13 @@ public partial class Game : Node3D, IGame
UnlockGalleryItem.Invoke("TrueEnd"); UnlockGalleryItem.Invoke("TrueEnd");
} }
public void Pause() => GameRepo.Pause();
public void Resume() => GameRepo.Resume();
private void OnQuit() => GameExitRequested?.Invoke(); private void OnQuit() => GameExitRequested?.Invoke();
private void GameOverMenuAppeared() => _map.ClearFloor(); private void GameOverMenuAppeared() => _map.EndCurrentGame();
private void OnResume() => GameState.Input(new GameState.Input.PauseButtonPressed()); private void OnResume() => GameState.Input(new GameState.Input.PauseButtonPressed());
@@ -1011,11 +995,7 @@ public partial class Game : Node3D, IGame
{ {
InGameUI.UseTeleportPrompt.TeleportToNextFloor -= UseTeleportPrompt_TeleportToNextFloor; InGameUI.UseTeleportPrompt.TeleportToNextFloor -= UseTeleportPrompt_TeleportToNextFloor;
InGameUI.UseTeleportPrompt.CloseTeleportPrompt -= UseTeleportPrompt_CloseTeleportPrompt; InGameUI.UseTeleportPrompt.CloseTeleportPrompt -= UseTeleportPrompt_CloseTeleportPrompt;
LoadNextLevel.GoToNextFloor -= FloorClearMenu_GoToNextFloor;
LoadNextLevel.Exit -= FloorClearMenu_Exit; LoadNextLevel.Exit -= FloorClearMenu_Exit;
LoadNextLevel.TransitionCompleted -= FloorClearMenu_TransitionCompleted;
OnLoadLevelRequest -= LoadLevel;
GameRepo.CloseInventoryEvent -= ExitInventoryAction; GameRepo.CloseInventoryEvent -= ExitInventoryAction;
+4
View File
@@ -52,6 +52,10 @@ public interface IGame : IProvide<IGame>, IProvide<IGameRepo>, IProvide<IPlayer>
public Task OnReachTrueEnd(); public Task OnReachTrueEnd();
public void Pause();
public void Resume();
public ItemRescueMenu ItemRescueMenu { get; } public ItemRescueMenu ItemRescueMenu { get; }
public QuestData QuestData { get; } public QuestData QuestData { get; }
+6 -6
View File
@@ -22,7 +22,7 @@ public class EffectService
public void TeleportEnemiesToCurrentRoom(List<IEnemy> enemyList) public void TeleportEnemiesToCurrentRoom(List<IEnemy> enemyList)
{ {
var currentRoom = _map.GetPlayersCurrentRoom(); var currentRoom = _map.CurrentFloor.GetPlayersCurrentRoom();
if (currentRoom is MonsterRoom currentMonsterRoom) if (currentRoom is MonsterRoom currentMonsterRoom)
{ {
@@ -33,7 +33,7 @@ public class EffectService
public void KillHalfEnemiesInRoom() public void KillHalfEnemiesInRoom()
{ {
var currentRoom = _map.GetPlayersCurrentRoom(); var currentRoom = _map.CurrentFloor.GetPlayersCurrentRoom();
if (currentRoom is not MonsterRoom) if (currentRoom is not MonsterRoom)
return; return;
@@ -46,7 +46,7 @@ public class EffectService
public void TurnAllEnemiesInRoomIntoHealingItem() public void TurnAllEnemiesInRoomIntoHealingItem()
{ {
var currentRoom = _map.GetPlayersCurrentRoom(); var currentRoom = _map.CurrentFloor.GetPlayersCurrentRoom();
if (currentRoom is not MonsterRoom) if (currentRoom is not MonsterRoom)
return; return;
@@ -78,7 +78,7 @@ public class EffectService
public void HealAllEnemiesAndPlayerInRoomToFull() public void HealAllEnemiesAndPlayerInRoomToFull()
{ {
var currentRoom = _map.GetPlayersCurrentRoom(); var currentRoom = _map.CurrentFloor.GetPlayersCurrentRoom();
if (currentRoom is not MonsterRoom) if (currentRoom is not MonsterRoom)
return; return;
@@ -91,7 +91,7 @@ public class EffectService
public int AbsorbHPFromAllEnemiesInRoom() public int AbsorbHPFromAllEnemiesInRoom()
{ {
var currentRoom = _map.GetPlayersCurrentRoom(); var currentRoom = _map.CurrentFloor.GetPlayersCurrentRoom();
if (currentRoom is not MonsterRoom) if (currentRoom is not MonsterRoom)
return 0; return 0;
@@ -110,7 +110,7 @@ public class EffectService
public void DealElementalDamageToAllEnemiesInRoom(ElementType elementType) public void DealElementalDamageToAllEnemiesInRoom(ElementType elementType)
{ {
var currentRoom = _map.GetPlayersCurrentRoom(); var currentRoom = _map.CurrentFloor.GetPlayersCurrentRoom();
if (currentRoom is not MonsterRoom) if (currentRoom is not MonsterRoom)
return; return;
@@ -1,75 +0,0 @@
using Godot;
namespace Zennysoft.Game.Ma;
public partial class DungeonFloorNode : FloorNode
{
[ExportGroup("Floor Set")]
[Export]
public string FolderName { get; set; }
[Export]
public Godot.Collections.Array<float> FloorOdds { get; set; } = [];
[ExportGroup("Spawn Rates")]
[Export]
public float Sproingy { get; set; }
[Export]
public float Michael { get; set; }
[Export]
public float FilthEater { get; set; }
[Export]
public float Sara { get; set; }
[Export]
public float Ballos { get; set; }
[Export]
public float Chinthe { get; set; }
[Export]
public float GreenAmbassador { get; set; }
[Export]
public float RedAmbassador { get; set; }
[Export]
public float SteelAmbassador { get; set; }
[Export]
public float AgniDemon { get; set; }
[Export]
public float AqueosDemon { get; set; }
[Export]
public float Palan { get; set; }
[Export]
public float ShieldOfHeaven { get; set; }
[Export]
public float GoldSproingy { get; set; }
[ExportGroup("True Route Spawn Rates")]
[Export]
public float TrueSproingy { get; set; }
[Export]
public float TrueMichael { get; set; }
[Export]
public float TrueFilthEater { get; set; }
[Export]
public float TrueSara { get; set; }
[Export]
public float TrueBallos { get; set; }
[Export]
public float TrueChariot { get; set; }
[Export]
public float TrueChinthe { get; set; }
[Export]
public float TrueGreenAmbassador { get; set; }
[Export]
public float TrueRedAmbassador { get; set; }
[Export]
public float TrueSteelAmbassador { get; set; }
[Export]
public float TrueAgniDemon { get; set; }
[Export]
public float TrueAqueosDemon { get; set; }
[Export]
public float TruePalan { get; set; }
[Export]
public float TrueShieldOfHeaven { get; set; }
[Export]
public float TrueGoldSproingy { get; set; }
}
@@ -0,0 +1,13 @@
using Godot;
namespace Zennysoft.Game.Ma;
[GlobalClass]
public partial class EnemySpawnRate : Resource
{
[Export]
public EnemyType EnemyType { get; set; }
[Export]
public float SpawnRate { get; set; }
}
@@ -0,0 +1 @@
uid://bjal67ir4k11d
@@ -0,0 +1 @@
uid://0xsxfrp5akmf
@@ -1,11 +0,0 @@
using Godot;
namespace Zennysoft.Game.Ma;
[GlobalClass]
public partial class FloorResourceType : Resource
{
[Export] public string FloorDisplayName { get; set; }
[Export] public string FolderPath { get; set; }
}
@@ -0,0 +1,152 @@
using Godot;
using Godot.Collections;
using System;
using System.Linq;
namespace Zennysoft.Game.Ma;
public static class FloorScenePathConverter
{
public static string Convert(FloorScene sceneToConvert)
{
string filePath = @"res://src/map/dungeon/floors/";
switch (sceneToConvert.FloorType)
{
case FloorType.Overworld:
return filePath + @"Special Floors/Overworld.tscn";
case FloorType.Altar:
return filePath + @"Special Floors/00. Altar.tscn";
case FloorType.Floor01:
return PickRandomFromFolder(filePath + "Floor01/");
case FloorType.Floor02:
return PickRandomFromFolder(filePath + "Floor02/");
case FloorType.Floor03:
return PickRandomFromFolder(filePath + "Floor03/");
case FloorType.Floor04:
return PickRandomFromFolder(filePath + "Floor04/");
case FloorType.Floor05:
return PickRandomFromFolder(filePath + "Floor05/");
case FloorType.Floor06:
return PickRandomFromFolder(filePath + "Floor06/");
case FloorType.Floor07:
return PickRandomFromFolder(filePath + "Floor07/");
case FloorType.BossFloorA:
return filePath + "Special Floors/Floor 08 Boss Floor A.tscn";
case FloorType.Floor09:
return PickRandomFromFolder(filePath + "Floor09/");
case FloorType.Floor10:
return PickRandomFromFolder(filePath + "Floor10/");
case FloorType.Floor11:
return PickRandomFromFolder(filePath + "Floor11/");
case FloorType.Floor12:
return PickRandomFromFolder(filePath + "Floor12/");
case FloorType.Floor13:
return PickRandomFromFolder(filePath + "Floor13/");
case FloorType.Floor14:
return PickRandomFromFolder(filePath + "Floor14/");
case FloorType.Floor15:
return PickRandomFromFolder(filePath + "Floor15/");
case FloorType.BossFloorB:
return filePath + "Special Floors/Floor 16 Boss Floor B.tscn";
case FloorType.GoddessOfGuidance:
return filePath + "Special Floors/35. Goddess of Guidance's Room.tscn";
case FloorType.FinalFloor:
return filePath + "Special Floors/36. Final Floor.tscn";
case FloorType.Server:
return filePath + "Special Floors/Server.tscn";
case FloorType.Cellular:
return filePath + "Special Floors/Cellular.tscn";
case FloorType.Grassland:
return filePath + "Special Floors/Grassland.tscn";
case FloorType.Platform:
return filePath + "Special Floors/Platform.tscn";
case FloorType.River:
return filePath + "Special Floors/River.tscn";
case FloorType.BadEnd:
return filePath + "Special Floors/BAD END.tscn";
case FloorType.HeartOfAllThings:
break;
case FloorType.TrueGoddessOfGuidance:
return filePath + "Special Floors/40. Goddess of Guidance's Room - True Form.tscn";
default:
throw new NotImplementedException("Floor not added yet.");
}
return string.Empty;
}
public static string ConvertFromSpecificLayout(FloorScene sceneToConvert, string layoutSceneName)
{
string filePath = @"res://src/map/dungeon/floors/";
switch (sceneToConvert.FloorType)
{
case FloorType.Overworld:
return filePath + @"Special Floors/Overworld.tscn";
case FloorType.Altar:
return filePath + @"Special Floors/00. Altar.tscn";
case FloorType.Floor01:
return filePath + "Floor01/" + layoutSceneName;
case FloorType.Floor02:
return filePath + "Floor02/" + layoutSceneName;
case FloorType.Floor03:
return filePath + "Floor03/" + layoutSceneName;
case FloorType.Floor04:
return filePath + "Floor04/" + layoutSceneName;
case FloorType.Floor05:
return filePath + "Floor05/" + layoutSceneName;
case FloorType.Floor06:
return filePath + "Floor06/" + layoutSceneName;
case FloorType.Floor07:
return filePath + "Floor07/" + layoutSceneName;
case FloorType.BossFloorA:
return filePath + "Special Floors/Floor 08 Boss Floor A.tscn";
case FloorType.Floor09:
return filePath + "Floor09/" + layoutSceneName;
case FloorType.Floor10:
return filePath + "Floor10/" + layoutSceneName;
case FloorType.Floor11:
return filePath + "Floor11/" + layoutSceneName;
case FloorType.Floor12:
return filePath + "Floor12/" + layoutSceneName;
case FloorType.Floor13:
return filePath + "Floor13/" + layoutSceneName;
case FloorType.Floor14:
return filePath + "Floor14/" + layoutSceneName;
case FloorType.Floor15:
return filePath + "Floor15/" + layoutSceneName;
case FloorType.BossFloorB:
return filePath + "Special Floors/Floor 16 Boss Floor B.tscn";
case FloorType.GoddessOfGuidance:
return filePath + "Special Floors/35. Goddess of Guidance's Room.tscn";
case FloorType.FinalFloor:
return filePath + "Special Floors/36. Final Floor.tscn";
case FloorType.Server:
return filePath + "Special Floors/Server.tscn";
case FloorType.Cellular:
return filePath + "Special Floors/Cellular.tscn";
case FloorType.Grassland:
return filePath + "Special Floors/Grassland.tscn";
case FloorType.Platform:
return filePath + "Special Floors/Platform.tscn";
case FloorType.TrueGoddessOfGuidance:
return filePath + "Special Floors/40. Goddess of Guidance's Room - True Form.tscn";
case FloorType.River:
return filePath + "Special Floors/River.tscn";
case FloorType.BadEnd:
return filePath + "Special Floors/BAD END.tscn";
case FloorType.HeartOfAllThings:
break;
default:
throw new NotImplementedException("Floor not added yet.");
}
return string.Empty;
}
private static string PickRandomFromFolder(string folder)
{
Array<string> files = [.. DirAccess.GetFilesAt(folder).Where(x => x.EndsWith(".tscn"))];
return folder + files.PickRandom();
}
}
@@ -0,0 +1 @@
uid://bbabjp5tg27q2
+33
View File
@@ -0,0 +1,33 @@
namespace Zennysoft.Game.Ma;
public enum FloorType
{
Overworld,
Altar,
Floor01,
Floor02,
Floor03,
Floor04,
Floor05,
Floor06,
Floor07,
Floor09,
Floor10,
Floor11,
Floor12,
Floor13,
Floor14,
Floor15,
BossFloorA,
BossFloorB,
GoddessOfGuidance,
TrueGoddessOfGuidance,
Cellular,
Grassland,
Platform,
River,
Server,
FinalFloor,
BadEnd,
HeartOfAllThings
}
@@ -0,0 +1 @@
uid://bdyjlodn1pijf
+19 -20
View File
@@ -1,6 +1,7 @@
using Chickensoft.Collections; using Chickensoft.Collections;
using Chickensoft.GodotNodeInterfaces; using Chickensoft.GodotNodeInterfaces;
using Godot; using Godot;
using Godot.Collections;
using System; using System;
using System.Threading.Tasks; using System.Threading.Tasks;
@@ -8,31 +9,29 @@ namespace Zennysoft.Game.Ma;
public interface IMap : INode3D public interface IMap : INode3D
{ {
void ClearFloor();
Task LoadFloor();
Task LoadFloor(string sceneName);
IDungeonFloor CurrentFloor { get; } IDungeonFloor CurrentFloor { get; }
(Vector3 Rotation, Vector3 Position) GetPlayerSpawnPosition(); public AutoProp<FloorScene> CurrentSelectedFloor { get; }
IDungeonRoom GetPlayersCurrentRoom(); public Array<FloorScene> FloorRoute { get; }
void InitializeMapData();
public void FadeIn();
public void FadeOut();
public AutoProp<int> CurrentFloorNumber { get; }
AutoProp<string> CurrentFloorDisplayString { get; }
public string NextFloorDisplayString { get; }
public event Action<(Vector3 Rotation, Vector3 Position)> SpawnPointCreated; public event Action<(Vector3 Rotation, Vector3 Position)> SpawnPointCreated;
public event Action FloorLoaded; public event Action FloorLoaded;
public void ShowMap();
Task LoadFloor(FloorScene floorToLoad);
Task LoadFloorByPath(string filePath);
public void AddNormalRoute();
public void AddTrueRoute();
public void AddBadEndRoute();
public void ResetToBaseRoute();
public void EndCurrentGame();
} }
@@ -1,55 +0,0 @@
using Godot;
using System;
using System.Linq;
namespace Zennysoft.Game.Ma;
public static class LayoutToScenePathConverter
{
private static readonly string _folderPath = "res://src/map/dungeon/floors";
public static string Convert(FloorNode floorNode)
{
if (floorNode is DungeonFloorNode dungeonFloorNode)
return RandomDungeonFloor(dungeonFloorNode);
else if (floorNode is SpecialFloorNode specialFloorNode)
return SpawnSpecialFloor(specialFloorNode.FloorName);
throw new NotImplementedException();
}
private static string SpawnSpecialFloor(SpecialFloorType floorType)
{
var path = $"{_folderPath}/Special Floors/";
var files = DirAccess.GetFilesAt(path);
switch (floorType)
{
case SpecialFloorType.Overworld:
return path + files.Single(x => x.EndsWith("Overworld.tscn"));
case SpecialFloorType.Altar:
return path + files.Single(x => x.EndsWith("Altar.tscn"));
case SpecialFloorType.BossFloorA:
return path + files.Single(x => x.EndsWith("Boss Floor A.tscn"));
case SpecialFloorType.BossFloorB:
return path + files.Single(x => x.EndsWith("Boss Floor B.tscn"));
case SpecialFloorType.GoddessOfGuidanceFloor:
return path + files.Single(x => x.EndsWith("Goddess of Guidance's Room.tscn"));
case SpecialFloorType.TrueGoddessOfGuidanceFloor:
return path + files.Single(x => x.EndsWith("Goddess of Guidance's Room - True Form.tscn"));
case SpecialFloorType.FinalFloor:
return path + files.Single(x => x.EndsWith("Final Floor.tscn"));
default:
throw new NotImplementedException();
}
}
private static string RandomDungeonFloor(DungeonFloorNode floorNode)
{
var folderName = _folderPath + "/" + floorNode.FolderName;
var floorList = DirAccess.GetFilesAt(folderName).Where(x => x.EndsWith(".tscn"));
var rng = new RandomNumberGenerator();
rng.Randomize();
var index = (int)rng.RandWeighted([.. floorNode.FloorOdds]);
var result = floorList.ElementAt(index);
return folderName + "/" + result;
}
}
@@ -1 +0,0 @@
uid://d0yn4yu7264c8
+99 -77
View File
@@ -18,30 +18,34 @@ public partial class Map : Node3D, IMap
[Dependency] [Dependency]
public IGame Game => this.DependOn<IGame>(); public IGame Game => this.DependOn<IGame>();
[Node]
public Node MapOrder { get; set; } = default!;
[Node] [Node]
public AnimationPlayer AnimationPlayer { get; set; } = default!; public AnimationPlayer AnimationPlayer { get; set; } = default!;
public IDungeonFloor CurrentFloor { get; private set; } public IDungeonFloor CurrentFloor { get; private set; }
public AutoProp<int> CurrentFloorNumber { get; private set; } = new AutoProp<int>(0);
public AutoProp<string> CurrentFloorDisplayString { get; private set; } = new AutoProp<string>(string.Empty);
public string NextFloorDisplayString => MapOrder.GetChildren().OfType<FloorNode>().ElementAt(CurrentFloorNumber.Value + 1).DisplayedFloorNumber;
private readonly string _floorFilePath = @"res://src/map/dungeon/floors/";
public event Action<(Vector3 Rotation, Vector3 Position)> SpawnPointCreated; public event Action<(Vector3 Rotation, Vector3 Position)> SpawnPointCreated;
[Export] public Array<FloorScene> FloorRoute { get; private set; }
public Array<FloorResourceType> FloorOrder { get; set; } = [];
[Export] public Array<FloorScene> BaseRoute { get; set; }
[Export] public Array<FloorScene> NormalEndRoute { get; set; }
[Export] public Array<FloorScene> TrueEndRoute { get; set; }
[Export] public Array<FloorScene> BadEndRoute { get; set; }
public AutoProp<FloorScene> CurrentSelectedFloor { get; set; }
public event Action FloorLoaded; public event Action FloorLoaded;
private string _sceneName; private string _floorToLoad;
public override void _EnterTree()
{
FloorRoute = [.. BaseRoute];
CurrentSelectedFloor = new AutoProp<FloorScene>(FloorRoute.First());
}
public void OnResolved() public void OnResolved()
{ {
@@ -52,47 +56,93 @@ public partial class Map : Node3D, IMap
private async void AnimationPlayer_AnimationFinished(StringName animName) private async void AnimationPlayer_AnimationFinished(StringName animName)
{ {
if (animName == "fade_out") if (animName == "fade_out")
{ await ContinueLoadingFloor(_floorToLoad);
await LoadNewFloor();
FloorLoaded?.Invoke();
}
} }
private async Task LoadNewFloor() public void ShowMap() => FadeIn();
private void FadeIn() => AnimationPlayer.Play("fade_in");
private void FadeOut() => AnimationPlayer.Play("fade_out");
public void EndCurrentGame()
{
CleanupCurrentFloor();
ClearFloor();
FloorRoute = [.. BaseRoute];
}
public async Task LoadFloor(FloorScene floorToLoad)
{
Game.Pause();
// Clean up current floor
CleanupCurrentFloor();
// Start loading new floor
var filePath = FloorScenePathConverter.Convert(floorToLoad);
_floorToLoad = filePath;
FadeOut();
}
public async Task LoadFloorByPath(string filePath)
{
Game.Pause();
// Clean up current floor
CleanupCurrentFloor();
// Start loading new floor
_floorToLoad = filePath;
FadeOut();
}
public void AddNormalRoute()
{
FloorRoute.AddRange(NormalEndRoute);
}
public void AddTrueRoute()
{
FloorRoute.AddRange(TrueEndRoute);
}
public void AddBadEndRoute()
{
FloorRoute.AddRange(BadEndRoute);
}
public void ResetToBaseRoute()
{
FloorRoute = [.. BaseRoute];
CurrentSelectedFloor = new AutoProp<FloorScene>(FloorRoute.First());
}
private async Task ContinueLoadingFloor(string filePath)
{ {
SpawnPointCreated?.Invoke((Vector3.Forward, new Vector3(-999, -999, -999))); SpawnPointCreated?.Invoke((Vector3.Forward, new Vector3(-999, -999, -999)));
var newFloor = await LoadNewFloor(_sceneName); var newFloor = await LoadSceneFile(filePath);
// New floor created, remove old floor
ClearFloor(); ClearFloor();
// Setup new floor
AddChild(newFloor); AddChild(newFloor);
InitializeFloor(newFloor); CurrentFloor = newFloor as IDungeonFloor;
var floor = MapOrder.GetChildren().OfType<FloorNode>().ElementAt(CurrentFloorNumber.Value); CurrentFloor.InitializeDungeon();
if (CurrentFloor is DungeonFloor dungeonFloor && floor is DungeonFloorNode dungeonFloorNode) SpawnPointCreated?.Invoke(CurrentFloor.GetPlayerSpawnPoint());
dungeonFloor.SpawnEnemies(dungeonFloorNode); if (CurrentFloor is SpecialFloor)
CurrentFloorDisplayString.OnNext(floor.DisplayedFloorNumber); Game.ShowMinimap(false);
else
Game.ShowMinimap(true);
SpawnEnemies();
CurrentFloor.FloorIsLoaded = true;
FloorLoaded?.Invoke();
} }
public void FadeIn() => AnimationPlayer.Play("fade_in"); private void CleanupCurrentFloor()
public void FadeOut() => AnimationPlayer.Play("fade_out");
public void InitializeMapData()
{ {
CurrentFloorNumber.OnNext(-1); var dimmableAudio = GetTree().GetNodesInGroup("DimmableAudio").OfType<IDimmableAudioStreamPlayer>();
foreach (var node in dimmableAudio)
node.FadeOut();
} }
public IDungeonRoom GetPlayersCurrentRoom() private void ClearFloor()
{
var rooms = CurrentFloor.Rooms;
var playersRoom = rooms.SingleOrDefault(x => x.IsPlayerInRoom);
return playersRoom;
}
public (Vector3 Rotation, Vector3 Position) GetPlayerSpawnPosition()
{
var spawnPoint = CurrentFloor.GetPlayerSpawnPoint();
return (spawnPoint.Rotation, spawnPoint.Position);
}
public void ClearFloor()
{ {
try try
{ {
@@ -105,35 +155,7 @@ public partial class Map : Node3D, IMap
} }
} }
public async Task LoadFloor() private async Task<Node> LoadSceneFile(string sceneName)
{
var floor = MapOrder.GetChildren().OfType<FloorNode>().ElementAt(CurrentFloorNumber.Value + 1);
var sceneToLoad = LayoutToScenePathConverter.Convert(floor);
await LoadFloor(sceneToLoad);
}
public async Task LoadFloor(string sceneName)
{
CallDeferred(MethodName.FadeOut);
_sceneName = sceneName;
var dimmableAudio = GetTree().GetNodesInGroup("DimmableAudio").OfType<IDimmableAudioStreamPlayer>();
foreach (var node in dimmableAudio)
node.FadeOut();
}
private void InitializeFloor(Node newFloor)
{
CurrentFloor = (IDungeonFloor)newFloor;
SetupDungeonFloor();
CurrentFloor.FloorIsLoaded = true;
CurrentFloorNumber.OnNext(CurrentFloorNumber.Value + 1);
if (CurrentFloor is SpecialFloor)
Game.ShowMinimap(false);
else
Game.ShowMinimap(true);
}
private async Task<Node> LoadNewFloor(string sceneName)
{ {
var sceneLoader = new SceneLoader(); var sceneLoader = new SceneLoader();
AddChild(sceneLoader); AddChild(sceneLoader);
@@ -144,10 +166,10 @@ public partial class Map : Node3D, IMap
return result; return result;
} }
private void SetupDungeonFloor() private void SpawnEnemies()
{ {
CurrentFloor.InitializeDungeon(); var monsterRooms = CurrentFloor.Rooms.OfType<MonsterRoom>();
var transform = GetPlayerSpawnPosition(); foreach (var room in monsterRooms)
SpawnPointCreated?.Invoke(transform); room.SpawnEnemies(CurrentSelectedFloor.Value.EnemySpawnTable);
} }
} }
+199 -178
View File
@@ -1,15 +1,202 @@
[gd_scene load_steps=10 format=3 uid="uid://by67pn7fdsg1m"] [gd_scene load_steps=36 format=3 uid="uid://by67pn7fdsg1m"]
[ext_resource type="Script" uid="uid://14e8mu48ed4" path="res://src/map/Map.cs" id="1_bw70o"] [ext_resource type="Script" uid="uid://14e8mu48ed4" path="res://src/map/Map.cs" id="1_bw70o"]
[ext_resource type="Script" uid="uid://bvacb3ih0qt6u" path="res://src/map/FloorResourceType.cs" id="2_0qcd2"] [ext_resource type="Script" uid="uid://bnxutyeas2ymm" path="res://src/map/dungeon/floors/FloorScene.cs" id="2_0qcd2"]
[ext_resource type="Script" uid="uid://dbe3wf3ywtjqh" path="res://src/map/DungeonFloorNode.cs" id="2_00xd7"] [ext_resource type="Script" uid="uid://bjal67ir4k11d" path="res://src/map/EnemySpawnRate.cs" id="2_s7lwc"]
[ext_resource type="Script" uid="uid://dpj4qg0ip6yui" path="res://src/map/SpecialFloorNode.cs" id="3_v14r0"]
[sub_resource type="Resource" id="Resource_s7lwc"] [sub_resource type="Resource" id="Resource_s7lwc"]
script = ExtResource("2_0qcd2") script = ExtResource("2_0qcd2")
FloorDisplayName = "" FloorDisplayName = "Surface"
FolderPath = "" FloorType = 0
metadata/_custom_type_script = "uid://bvacb3ih0qt6u" EnemySpawnTable = Array[ExtResource("2_s7lwc")]([])
metadata/_custom_type_script = "uid://bnxutyeas2ymm"
[sub_resource type="Resource" id="Resource_1ny7u"]
script = ExtResource("2_0qcd2")
FloorDisplayName = "Altar"
FloorType = 1
EnemySpawnTable = Array[ExtResource("2_s7lwc")]([])
metadata/_custom_type_script = "uid://bnxutyeas2ymm"
[sub_resource type="Resource" id="Resource_v14r0"]
script = ExtResource("2_s7lwc")
EnemyType = 0
SpawnRate = 0.5
metadata/_custom_type_script = "uid://bjal67ir4k11d"
[sub_resource type="Resource" id="Resource_0qcd2"]
script = ExtResource("2_s7lwc")
EnemyType = 1
SpawnRate = 0.5
metadata/_custom_type_script = "uid://bjal67ir4k11d"
[sub_resource type="Resource" id="Resource_3olkd"]
script = ExtResource("2_0qcd2")
FloorDisplayName = "01"
FloorType = 2
EnemySpawnTable = Array[ExtResource("2_s7lwc")]([SubResource("Resource_v14r0"), SubResource("Resource_0qcd2")])
metadata/_custom_type_script = "uid://bnxutyeas2ymm"
[sub_resource type="Resource" id="Resource_55rmo"]
script = ExtResource("2_0qcd2")
FloorDisplayName = "02"
FloorType = 3
EnemySpawnTable = Array[ExtResource("2_s7lwc")]([])
metadata/_custom_type_script = "uid://bnxutyeas2ymm"
[sub_resource type="Resource" id="Resource_f6kwn"]
script = ExtResource("2_0qcd2")
FloorDisplayName = "03"
FloorType = 4
EnemySpawnTable = Array[ExtResource("2_s7lwc")]([])
metadata/_custom_type_script = "uid://bnxutyeas2ymm"
[sub_resource type="Resource" id="Resource_ne2vg"]
script = ExtResource("2_0qcd2")
FloorDisplayName = "04"
FloorType = 5
EnemySpawnTable = Array[ExtResource("2_s7lwc")]([])
metadata/_custom_type_script = "uid://bnxutyeas2ymm"
[sub_resource type="Resource" id="Resource_abpbr"]
script = ExtResource("2_0qcd2")
FloorDisplayName = "05"
FloorType = 6
EnemySpawnTable = Array[ExtResource("2_s7lwc")]([])
metadata/_custom_type_script = "uid://bnxutyeas2ymm"
[sub_resource type="Resource" id="Resource_caf7v"]
script = ExtResource("2_0qcd2")
FloorDisplayName = "06"
FloorType = 7
EnemySpawnTable = Array[ExtResource("2_s7lwc")]([])
metadata/_custom_type_script = "uid://bnxutyeas2ymm"
[sub_resource type="Resource" id="Resource_y74f3"]
script = ExtResource("2_0qcd2")
FloorDisplayName = "07"
FloorType = 8
EnemySpawnTable = Array[ExtResource("2_s7lwc")]([])
metadata/_custom_type_script = "uid://bnxutyeas2ymm"
[sub_resource type="Resource" id="Resource_dbqu2"]
script = ExtResource("2_0qcd2")
FloorDisplayName = "08"
FloorType = 16
EnemySpawnTable = Array[ExtResource("2_s7lwc")]([])
metadata/_custom_type_script = "uid://bnxutyeas2ymm"
[sub_resource type="Resource" id="Resource_xcm54"]
script = ExtResource("2_0qcd2")
FloorDisplayName = "09"
FloorType = 9
EnemySpawnTable = Array[ExtResource("2_s7lwc")]([])
metadata/_custom_type_script = "uid://bnxutyeas2ymm"
[sub_resource type="Resource" id="Resource_pvu0e"]
script = ExtResource("2_0qcd2")
FloorDisplayName = "10"
FloorType = 10
EnemySpawnTable = Array[ExtResource("2_s7lwc")]([])
metadata/_custom_type_script = "uid://bnxutyeas2ymm"
[sub_resource type="Resource" id="Resource_1de7e"]
script = ExtResource("2_0qcd2")
FloorDisplayName = "11"
FloorType = 11
EnemySpawnTable = Array[ExtResource("2_s7lwc")]([])
metadata/_custom_type_script = "uid://bnxutyeas2ymm"
[sub_resource type="Resource" id="Resource_5suoo"]
script = ExtResource("2_0qcd2")
FloorDisplayName = "12"
FloorType = 12
EnemySpawnTable = Array[ExtResource("2_s7lwc")]([])
metadata/_custom_type_script = "uid://bnxutyeas2ymm"
[sub_resource type="Resource" id="Resource_t2vkt"]
script = ExtResource("2_0qcd2")
FloorDisplayName = "13"
FloorType = 13
EnemySpawnTable = Array[ExtResource("2_s7lwc")]([])
metadata/_custom_type_script = "uid://bnxutyeas2ymm"
[sub_resource type="Resource" id="Resource_hi63v"]
script = ExtResource("2_0qcd2")
FloorDisplayName = "14"
FloorType = 14
EnemySpawnTable = Array[ExtResource("2_s7lwc")]([])
metadata/_custom_type_script = "uid://bnxutyeas2ymm"
[sub_resource type="Resource" id="Resource_httk4"]
script = ExtResource("2_0qcd2")
FloorDisplayName = "15"
FloorType = 15
EnemySpawnTable = Array[ExtResource("2_s7lwc")]([])
metadata/_custom_type_script = "uid://bnxutyeas2ymm"
[sub_resource type="Resource" id="Resource_ro62w"]
script = ExtResource("2_0qcd2")
FloorDisplayName = "16"
FloorType = 18
EnemySpawnTable = Array[ExtResource("2_s7lwc")]([])
metadata/_custom_type_script = "uid://bnxutyeas2ymm"
[sub_resource type="Resource" id="Resource_q7oan"]
script = ExtResource("2_0qcd2")
FloorDisplayName = "18"
FloorType = 25
EnemySpawnTable = Array[ExtResource("2_s7lwc")]([])
metadata/_custom_type_script = "uid://bnxutyeas2ymm"
[sub_resource type="Resource" id="Resource_3vg2e"]
script = ExtResource("2_0qcd2")
FloorDisplayName = "192"
FloorType = 24
EnemySpawnTable = Array[ExtResource("2_s7lwc")]([])
metadata/_custom_type_script = "uid://bnxutyeas2ymm"
[sub_resource type="Resource" id="Resource_tx34j"]
script = ExtResource("2_0qcd2")
FloorDisplayName = "7776"
FloorType = 20
EnemySpawnTable = Array[ExtResource("2_s7lwc")]([])
metadata/_custom_type_script = "uid://bnxutyeas2ymm"
[sub_resource type="Resource" id="Resource_8npfy"]
script = ExtResource("2_0qcd2")
FloorDisplayName = "11,664"
FloorType = 23
EnemySpawnTable = Array[ExtResource("2_s7lwc")]([])
metadata/_custom_type_script = "uid://bnxutyeas2ymm"
[sub_resource type="Resource" id="Resource_pids3"]
script = ExtResource("2_0qcd2")
FloorDisplayName = "117,000,000,000"
FloorType = 21
EnemySpawnTable = Array[ExtResource("2_s7lwc")]([])
metadata/_custom_type_script = "uid://bnxutyeas2ymm"
[sub_resource type="Resource" id="Resource_u3fsa"]
script = ExtResource("2_0qcd2")
FloorDisplayName = "5.63 × 10^7"
FloorType = 22
EnemySpawnTable = Array[ExtResource("2_s7lwc")]([])
metadata/_custom_type_script = "uid://bnxutyeas2ymm"
[sub_resource type="Resource" id="Resource_io2ww"]
script = ExtResource("2_0qcd2")
FloorDisplayName = "∞"
FloorType = 19
EnemySpawnTable = Array[ExtResource("2_s7lwc")]([])
metadata/_custom_type_script = "uid://bnxutyeas2ymm"
[sub_resource type="Resource" id="Resource_rb6u5"]
script = ExtResource("2_0qcd2")
FloorDisplayName = "-1"
FloorType = 26
EnemySpawnTable = Array[ExtResource("2_s7lwc")]([])
metadata/_custom_type_script = "uid://bnxutyeas2ymm"
[sub_resource type="Animation" id="Animation_00xd7"] [sub_resource type="Animation" id="Animation_00xd7"]
length = 0.001 length = 0.001
@@ -64,8 +251,12 @@ _data = {
} }
[node name="Map" type="Node3D"] [node name="Map" type="Node3D"]
process_mode = 3
script = ExtResource("1_bw70o") script = ExtResource("1_bw70o")
FloorOrder = Array[ExtResource("2_0qcd2")]([SubResource("Resource_s7lwc")]) BaseRoute = Array[ExtResource("2_0qcd2")]([SubResource("Resource_s7lwc"), SubResource("Resource_1ny7u"), SubResource("Resource_3olkd"), SubResource("Resource_55rmo"), SubResource("Resource_f6kwn"), SubResource("Resource_ne2vg"), SubResource("Resource_abpbr"), SubResource("Resource_caf7v"), SubResource("Resource_y74f3"), SubResource("Resource_dbqu2"), SubResource("Resource_xcm54"), SubResource("Resource_pvu0e"), SubResource("Resource_1de7e"), SubResource("Resource_5suoo"), SubResource("Resource_t2vkt"), SubResource("Resource_hi63v"), SubResource("Resource_httk4"), SubResource("Resource_ro62w")])
NormalEndRoute = Array[ExtResource("2_0qcd2")]([SubResource("Resource_q7oan")])
TrueEndRoute = Array[ExtResource("2_0qcd2")]([SubResource("Resource_3vg2e"), SubResource("Resource_tx34j"), SubResource("Resource_8npfy"), SubResource("Resource_pids3"), SubResource("Resource_u3fsa"), SubResource("Resource_io2ww")])
BadEndRoute = Array[Object]([SubResource("Resource_rb6u5")])
[node name="AnimationPlayer" type="AnimationPlayer" parent="."] [node name="AnimationPlayer" type="AnimationPlayer" parent="."]
unique_name_in_owner = true unique_name_in_owner = true
@@ -73,176 +264,6 @@ libraries = {
&"": SubResource("AnimationLibrary_00xd7") &"": SubResource("AnimationLibrary_00xd7")
} }
[node name="MapOrder" type="Node" parent="."]
unique_name_in_owner = true
[node name="Overworld" type="Node" parent="MapOrder"]
script = ExtResource("3_v14r0")
DisplayedFloorNumber = "Surface"
[node name="Altar" type="Node" parent="MapOrder"]
script = ExtResource("3_v14r0")
FloorName = 1
DisplayedFloorNumber = "Altar"
[node name="Floor01" type="Node" parent="MapOrder"]
script = ExtResource("2_00xd7")
FolderName = "Floor01"
FloorOdds = Array[float]([0.33, 0.33, 0.33])
Sproingy = 0.5
Michael = 0.5
DisplayedFloorNumber = "01"
[node name="Floor02" type="Node" parent="MapOrder"]
script = ExtResource("2_00xd7")
FolderName = "Floor02"
FloorOdds = Array[float]([0.33, 0.33, 0.33])
Sproingy = 0.5
Michael = 0.5
FilthEater = 0.1
GoldSproingy = 0.05
TrueRedAmbassador = 0.3
DisplayedFloorNumber = "02"
[node name="Floor03" type="Node" parent="MapOrder"]
script = ExtResource("2_00xd7")
FolderName = "Floor03"
FloorOdds = Array[float]([0.33, 0.33, 0.33])
Sproingy = 0.25
Michael = 0.5
FilthEater = 0.3
Sara = 0.1
GoldSproingy = 0.05
TrueRedAmbassador = 0.3
DisplayedFloorNumber = "03"
[node name="Floor04" type="Node" parent="MapOrder"]
script = ExtResource("2_00xd7")
FolderName = "Floor04"
FloorOdds = Array[float]([0.33, 0.33, 0.33])
FilthEater = 0.5
Sara = 0.3
AgniDemon = 0.3
GoldSproingy = 0.05
DisplayedFloorNumber = "04"
[node name="Floor05" type="Node" parent="MapOrder"]
script = ExtResource("2_00xd7")
FolderName = "Floor05"
FloorOdds = Array[float]([0.5, 0.5])
FilthEater = 0.25
Sara = 0.5
Ballos = 0.4
RedAmbassador = 0.3
AgniDemon = 0.5
GoldSproingy = 0.05
DisplayedFloorNumber = "05"
[node name="Floor06" type="Node" parent="MapOrder"]
script = ExtResource("2_00xd7")
FolderName = "Floor06"
FloorOdds = Array[float]([0.2, 0.8, 0.5, 0.1])
Sara = 0.5
Ballos = 0.5
RedAmbassador = 0.3
AgniDemon = 0.5
GoldSproingy = 0.05
DisplayedFloorNumber = "06"
[node name="Floor07" type="Node" parent="MapOrder"]
script = ExtResource("2_00xd7")
FolderName = "Floor07"
FloorOdds = Array[float]([0.33, 0.33, 0.33])
Sara = 0.1
Ballos = 0.5
RedAmbassador = 0.3
AgniDemon = 0.4
GoldSproingy = 0.05
DisplayedFloorNumber = "07"
[node name="Boss Floor 1" type="Node" parent="MapOrder"]
script = ExtResource("3_v14r0")
FloorName = 2
DisplayedFloorNumber = "08"
[node name="Floor09" type="Node" parent="MapOrder"]
script = ExtResource("2_00xd7")
FolderName = "Floor09"
FloorOdds = Array[float]([0.5, 0.5])
Chinthe = 0.5
GreenAmbassador = 0.1
DisplayedFloorNumber = "09"
[node name="Floor10" type="Node" parent="MapOrder"]
script = ExtResource("2_00xd7")
FolderName = "Floor10"
FloorOdds = Array[float]([0.5, 0.5])
Chinthe = 0.5
GreenAmbassador = 0.5
ShieldOfHeaven = 0.1
DisplayedFloorNumber = "10"
[node name="Floor11" type="Node" parent="MapOrder"]
script = ExtResource("2_00xd7")
FolderName = "Floor11"
FloorOdds = Array[float]([0.5, 0.5])
Chinthe = 0.5
GreenAmbassador = 0.5
ShieldOfHeaven = 0.5
DisplayedFloorNumber = "11"
[node name="Floor12" type="Node" parent="MapOrder"]
script = ExtResource("2_00xd7")
FolderName = "Floor12"
FloorOdds = Array[float]([0.5, 0.5])
GreenAmbassador = 0.5
SteelAmbassador = 0.05
ShieldOfHeaven = 0.5
DisplayedFloorNumber = "12"
[node name="Floor13" type="Node" parent="MapOrder"]
script = ExtResource("2_00xd7")
FolderName = "Floor13"
FloorOdds = Array[float]([0.5, 0.5])
Sproingy = 1.0
GreenAmbassador = 0.25
SteelAmbassador = 0.05
Palan = 0.3
ShieldOfHeaven = 0.5
DisplayedFloorNumber = "13"
[node name="Floor14" type="Node" parent="MapOrder"]
script = ExtResource("2_00xd7")
FolderName = "Floor14"
FloorOdds = Array[float]([0.5, 0.5])
SteelAmbassador = 0.05
Palan = 0.5
ShieldOfHeaven = 0.5
GoldSproingy = 0.05
DisplayedFloorNumber = "14"
[node name="Floor15" type="Node" parent="MapOrder"]
script = ExtResource("2_00xd7")
FolderName = "Floor15"
FloorOdds = Array[float]([1.0])
Sproingy = 1.0
DisplayedFloorNumber = "15"
[node name="Boss Floor 2" type="Node" parent="MapOrder"]
script = ExtResource("3_v14r0")
FloorName = 3
DisplayedFloorNumber = "16"
[node name="Goddess of Guidance Floor" type="Node" parent="MapOrder"]
script = ExtResource("3_v14r0")
FloorName = 4
DisplayedFloorNumber = "17"
[node name="Final Floor" type="Node" parent="MapOrder"]
script = ExtResource("3_v14r0")
FloorName = 6
DisplayedFloorNumber = "18"
[node name="ColorRect" type="ColorRect" parent="."] [node name="ColorRect" type="ColorRect" parent="."]
anchors_preset = 15 anchors_preset = 15
anchor_right = 1.0 anchor_right = 1.0
@@ -1,9 +0,0 @@
using Godot;
namespace Zennysoft.Game.Ma;
[GlobalClass]
public partial class SpecialFloorObject : FloorResourceType
{
//[Export] public SpecialFloorType specialFloorType { get; set; }
}
@@ -30,30 +30,6 @@ public partial class DungeonFloor : Node3D, IDungeonFloor
} }
public void SpawnEnemies(DungeonFloorNode floorNode)
{
var enemyOdds = new Godot.Collections.Dictionary<EnemyType, float>
{
{ EnemyType.Sproingy, floorNode.Sproingy },
{ EnemyType.Michael, floorNode.Michael },
{ EnemyType.FilthEater, floorNode.FilthEater },
{ EnemyType.Sara, floorNode.Sara },
{ EnemyType.Ballos, floorNode.Ballos },
{ EnemyType.Chinthe, floorNode.Chinthe },
{ EnemyType.AmbassadorGreen, floorNode.GreenAmbassador },
{ EnemyType.AmbassadorRed, floorNode.RedAmbassador },
{ EnemyType.AmbassadorSteel, floorNode.SteelAmbassador },
{ EnemyType.AgniDemon, floorNode.AgniDemon },
{ EnemyType.AqueousDemon, floorNode.AqueosDemon },
{ EnemyType.Palan, floorNode.Palan },
{ EnemyType.ShieldOfHeaven, floorNode.ShieldOfHeaven },
{ EnemyType.GoldSproingy, floorNode.GoldSproingy },
};
var monsterRooms = Rooms.OfType<MonsterRoom>();
foreach (var room in monsterRooms)
room.SpawnEnemies(enemyOdds);
}
public (Vector3 Rotation, Vector3 Position) GetPlayerSpawnPoint() { return (_playerSpawnPoint.Rotation, new Vector3(_playerSpawnPoint.GlobalPosition.X, 0, _playerSpawnPoint.GlobalPosition.Z)); } public (Vector3 Rotation, Vector3 Position) GetPlayerSpawnPoint() { return (_playerSpawnPoint.Rotation, new Vector3(_playerSpawnPoint.GlobalPosition.X, 0, _playerSpawnPoint.GlobalPosition.Z)); }
@@ -80,4 +56,10 @@ public partial class DungeonFloor : Node3D, IDungeonFloor
return FindAllDungeonRooms([.. nodesToSearch.SelectMany(x => x.GetChildren())], roomsFound); return FindAllDungeonRooms([.. nodesToSearch.SelectMany(x => x.GetChildren())], roomsFound);
} }
public IDungeonRoom GetPlayersCurrentRoom()
{
var playersRoom = Rooms.SingleOrDefault(x => x.IsPlayerInRoom);
return playersRoom;
}
} }
@@ -1,6 +1,7 @@
using Chickensoft.AutoInject; using Chickensoft.AutoInject;
using Chickensoft.Introspection; using Chickensoft.Introspection;
using Godot; using Godot;
using Godot.Collections;
using System.Linq; using System.Linq;
namespace Zennysoft.Game.Ma; namespace Zennysoft.Game.Ma;
@@ -21,9 +22,9 @@ public partial class MonsterRoom : DungeonRoom
SpawnItems(); SpawnItems();
} }
public void SpawnEnemies(Godot.Collections.Dictionary<EnemyType, float> enemyInfo) public void SpawnEnemies(Array<EnemySpawnRate> spawnTable)
{ {
if (enemyInfo == null || !enemyInfo.Any(x => x.Value > 0)) if (spawnTable.Count == 0)
return; return;
var rng = new RandomNumberGenerator(); var rng = new RandomNumberGenerator();
@@ -37,9 +38,9 @@ public partial class MonsterRoom : DungeonRoom
break; break;
numberOfEnemiesToSpawn--; numberOfEnemiesToSpawn--;
var index = rng.RandWeighted([.. enemyInfo.Values]); var index = rng.RandWeighted([.. spawnTable.Select(x => x.SpawnRate)]);
var selectedEnemy = enemyInfo.ElementAt((int)index); var selectedEnemy = spawnTable.ElementAt((int)index);
var instantiatedEnemy = EnemyTypeToEnemyConverter.Convert(selectedEnemy.Key); var instantiatedEnemy = EnemyTypeToEnemyConverter.Convert(selectedEnemy.EnemyType);
AddChild(instantiatedEnemy); AddChild(instantiatedEnemy);
instantiatedEnemy.GlobalPosition = new Vector3(spawnPoint.GlobalPosition.X, 0f, spawnPoint.GlobalPosition.Z); instantiatedEnemy.GlobalPosition = new Vector3(spawnPoint.GlobalPosition.X, 0f, spawnPoint.GlobalPosition.Z);
ResetPhysicsInterpolation(); ResetPhysicsInterpolation();
@@ -21,4 +21,6 @@ public partial class SpecialFloor : Node3D, IDungeonFloor
public bool FloorIsLoaded { get; set; } public bool FloorIsLoaded { get; set; }
public virtual (Vector3 Rotation, Vector3 Position) GetPlayerSpawnPoint() => (PlayerSpawnPoint.Rotation, new Vector3(PlayerSpawnPoint.Position.X, 0, PlayerSpawnPoint.Position.Z)); public virtual (Vector3 Rotation, Vector3 Position) GetPlayerSpawnPoint() => (PlayerSpawnPoint.Rotation, new Vector3(PlayerSpawnPoint.Position.X, 0, PlayerSpawnPoint.Position.Z));
public IDungeonRoom GetPlayersCurrentRoom() => null;
} }
@@ -0,0 +1,14 @@
using Godot;
using Godot.Collections;
namespace Zennysoft.Game.Ma;
[GlobalClass]
public partial class FloorScene : Resource
{
[Export] public string FloorDisplayName { get; set; }
[Export] public FloorType FloorType { get; set; }
[Export] public Array<EnemySpawnRate> EnemySpawnTable { get; set; } = [];
}
@@ -0,0 +1 @@
uid://bnxutyeas2ymm
+28
View File
@@ -63,6 +63,17 @@ layout_mode = 2
focus_neighbor_bottom = NodePath("../SpawnEnemyDropDown") focus_neighbor_bottom = NodePath("../SpawnEnemyDropDown")
theme_override_styles/normal = SubResource("StyleBoxFlat_1ctjd") theme_override_styles/normal = SubResource("StyleBoxFlat_1ctjd")
[node name="Layout Select" type="Label" parent="MarginContainer/VBoxContainer/HBoxContainer/VFlowContainer"]
layout_mode = 2
text = "Layout Select:"
label_settings = ExtResource("2_a7f7f")
[node name="LayoutSelectDropDown" type="OptionButton" parent="MarginContainer/VBoxContainer/HBoxContainer/VFlowContainer"]
unique_name_in_owner = true
layout_mode = 2
focus_neighbor_bottom = NodePath("../SpawnEnemyDropDown")
theme_override_styles/normal = SubResource("StyleBoxFlat_1ctjd")
[node name="Label" type="Label" parent="MarginContainer/VBoxContainer/HBoxContainer/VFlowContainer"] [node name="Label" type="Label" parent="MarginContainer/VBoxContainer/HBoxContainer/VFlowContainer"]
layout_mode = 2 layout_mode = 2
text = "Spawn Item:" text = "Spawn Item:"
@@ -167,3 +178,20 @@ text = "Rust"
unique_name_in_owner = true unique_name_in_owner = true
layout_mode = 2 layout_mode = 2
text = "Show Debug Info Overlay" text = "Show Debug Info Overlay"
[node name="HBoxContainer" type="HBoxContainer" parent="MarginContainer/VBoxContainer/HBoxContainer"]
layout_mode = 2
[node name="VBoxContainer" type="VBoxContainer" parent="MarginContainer/VBoxContainer/HBoxContainer/HBoxContainer"]
layout_mode = 2
theme_override_constants/separation = 15
[node name="RouteSelect" type="Label" parent="MarginContainer/VBoxContainer/HBoxContainer/HBoxContainer/VBoxContainer"]
layout_mode = 2
text = "Route Select:"
label_settings = ExtResource("2_a7f7f")
[node name="RouteSelectDropDown" type="OptionButton" parent="MarginContainer/VBoxContainer/HBoxContainer/HBoxContainer/VBoxContainer"]
unique_name_in_owner = true
layout_mode = 2
theme_override_styles/normal = SubResource("StyleBoxFlat_1ctjd")
+4 -4
View File
@@ -21,7 +21,7 @@ public partial class Minimap : Control
public void OnResolved() public void OnResolved()
{ {
_map.CurrentFloorDisplayString.Sync += CurrentFloorNumber_Sync; _map.CurrentSelectedFloor.Sync += CurrentFloorNumber_Sync;
_ready = true; _ready = true;
} }
@@ -31,13 +31,13 @@ public partial class Minimap : Control
MinimapCamera.Position = new Vector3(_player.GlobalPosition.X, MinimapCamera.Position.Y, _player.GlobalPosition.Z); MinimapCamera.Position = new Vector3(_player.GlobalPosition.X, MinimapCamera.Position.Y, _player.GlobalPosition.Z);
} }
private void CurrentFloorNumber_Sync(string obj) private void CurrentFloorNumber_Sync(FloorScene obj)
{ {
LayerNumberText.Text = obj; LayerNumberText.Text = obj.FloorDisplayName;
} }
public void OnExitTree() public void OnExitTree()
{ {
_map.CurrentFloorDisplayString.Sync -= CurrentFloorNumber_Sync; _map.CurrentSelectedFloor.Sync -= CurrentFloorNumber_Sync;
} }
} }
+2 -1
View File
@@ -42,6 +42,7 @@ orientation = 1
[node name="Minimap" type="Control"] [node name="Minimap" type="Control"]
process_mode = 3 process_mode = 3
visible = false
light_mask = 2 light_mask = 2
visibility_layer = 2 visibility_layer = 2
layout_mode = 3 layout_mode = 3
@@ -71,7 +72,7 @@ layout_mode = 2
transparent_bg = true transparent_bg = true
handle_input_locally = false handle_input_locally = false
size = Vector2i(400, 350) size = Vector2i(400, 350)
render_target_update_mode = 4 render_target_update_mode = 0
[node name="MinimapCamera" type="Camera3D" parent="CenterContainer/SubViewportContainer/SubViewport"] [node name="MinimapCamera" type="Camera3D" parent="CenterContainer/SubViewportContainer/SubViewport"]
unique_name_in_owner = true unique_name_in_owner = true
@@ -5,8 +5,6 @@ namespace Zennysoft.Game.Ma;
public interface IFloorClearMenu : IControl public interface IFloorClearMenu : IControl
{ {
public event Action GoToNextFloor;
public event Action Exit; public event Action Exit;
public event Action TransitionCompleted; public event Action TransitionCompleted;
@@ -33,8 +33,6 @@ public partial class LoadNextLevel : Control, IFloorClearMenu
public void FadeOut() => AnimationPlayer.Play("fade_out"); public void FadeOut() => AnimationPlayer.Play("fade_out");
public event Action GoToNextFloor;
public event Action Exit; public event Action Exit;
public event Action TransitionCompleted; public event Action TransitionCompleted;
@@ -49,9 +47,10 @@ public partial class LoadNextLevel : Control, IFloorClearMenu
AnimationPlayer.AnimationStarted += AnimationPlayer_AnimationStarted; AnimationPlayer.AnimationStarted += AnimationPlayer_AnimationStarted;
ContinueButton.Pressed += ContinueButton_Pressed; ContinueButton.Pressed += ContinueButton_Pressed;
ExitButton.Pressed += ExitButton_Pressed; ExitButton.Pressed += ExitButton_Pressed;
_map.CurrentSelectedFloor.Changed += CurrentSelectedFloor_Changed;
} }
private void CurrentFloorNumber_Sync(int _) => FloorNumber.Text = _map.NextFloorDisplayString; private void CurrentSelectedFloor_Changed(FloorScene obj) => FloorNumber.Text = obj.FloorDisplayName;
private void EquipmentComponent_EquipmentChanged(IEquipableItem obj) private void EquipmentComponent_EquipmentChanged(IEquipableItem obj)
{ {
@@ -81,22 +80,24 @@ public partial class LoadNextLevel : Control, IFloorClearMenu
ContinueButton.FocusMode = FocusModeEnum.None; ContinueButton.FocusMode = FocusModeEnum.None;
ExitButton.FocusMode = FocusModeEnum.None; ExitButton.FocusMode = FocusModeEnum.None;
SfxDatabase.Instance.Play(SoundEffect.SelectUI); SfxDatabase.Instance.Play(SoundEffect.SelectUI);
GoToNextFloor?.Invoke(); FadeOut();
} }
private void AnimationPlayer_AnimationStarted(StringName animName) private async void AnimationPlayer_AnimationStarted(StringName animName)
{ {
if (animName == "fade_in") if (animName == "fade_in")
{ {
_fadingIn = true; _fadingIn = true;
ContinueButton.FocusMode = FocusModeEnum.None; ContinueButton.FocusMode = FocusModeEnum.None;
ExitButton.FocusMode = FocusModeEnum.None; ExitButton.FocusMode = FocusModeEnum.None;
_map.CurrentSelectedFloor.OnNext(_map.FloorRoute[_map.FloorRoute.IndexOf(_map.CurrentSelectedFloor.Value) + 1]);
} }
if (animName == "fade_out") if (animName == "fade_out")
{ {
DisableUISync(); DisableUISync();
_fadingIn = false; _fadingIn = false;
ContinueButton.CallDeferred(MethodName.ReleaseFocus); ContinueButton.CallDeferred(MethodName.ReleaseFocus);
await _map.LoadFloor(_map.CurrentSelectedFloor.Value);
} }
} }
@@ -130,7 +131,7 @@ public partial class LoadNextLevel : Control, IFloorClearMenu
_player.DefenseComponent.CurrentDefense.Sync += Defense_Sync; _player.DefenseComponent.CurrentDefense.Sync += Defense_Sync;
_player.DefenseComponent.MaximumDefense.Sync += Defense_Sync; _player.DefenseComponent.MaximumDefense.Sync += Defense_Sync;
_player.EquipmentComponent.EquipmentChanged += EquipmentComponent_EquipmentChanged; _player.EquipmentComponent.EquipmentChanged += EquipmentComponent_EquipmentChanged;
_map.CurrentFloorNumber.Sync += CurrentFloorNumber_Sync; _map.CurrentSelectedFloor.Changed += CurrentSelectedFloor_Changed;
} }
private void DisableUISync() private void DisableUISync()
@@ -147,6 +148,6 @@ public partial class LoadNextLevel : Control, IFloorClearMenu
_player.DefenseComponent.CurrentDefense.Sync -= Defense_Sync; _player.DefenseComponent.CurrentDefense.Sync -= Defense_Sync;
_player.DefenseComponent.MaximumDefense.Sync -= Defense_Sync; _player.DefenseComponent.MaximumDefense.Sync -= Defense_Sync;
_player.EquipmentComponent.EquipmentChanged -= EquipmentComponent_EquipmentChanged; _player.EquipmentComponent.EquipmentChanged -= EquipmentComponent_EquipmentChanged;
_map.CurrentFloorNumber.Sync -= CurrentFloorNumber_Sync; _map.CurrentSelectedFloor.Changed -= CurrentSelectedFloor_Changed;
} }
} }
@@ -77,10 +77,22 @@ tracks/0/path = NodePath(".:modulate")
tracks/0/interp = 1 tracks/0/interp = 1
tracks/0/loop_wrap = true tracks/0/loop_wrap = true
tracks/0/keys = { tracks/0/keys = {
"times": PackedFloat32Array(0, 0.999, 1),
"transitions": PackedFloat32Array(1, 1, 1),
"update": 0,
"values": [Color(1, 1, 1, 1), Color(0, 0, 0, 1), Color(0, 0, 0, 1)]
}
tracks/1/type = "value"
tracks/1/imported = false
tracks/1/enabled = true
tracks/1/path = NodePath(".:visible")
tracks/1/interp = 1
tracks/1/loop_wrap = true
tracks/1/keys = {
"times": PackedFloat32Array(0, 1), "times": PackedFloat32Array(0, 1),
"transitions": PackedFloat32Array(1, 1), "transitions": PackedFloat32Array(1, 1),
"update": 0, "update": 1,
"values": [Color(1, 1, 1, 1), Color(0, 0, 0, 1)] "values": [true, false]
} }
[sub_resource type="AnimationLibrary" id="AnimationLibrary_7x216"] [sub_resource type="AnimationLibrary" id="AnimationLibrary_7x216"]
@@ -1,6 +1,9 @@
using Chickensoft.AutoInject; using Chickensoft.AutoInject;
using Chickensoft.Collections;
using Chickensoft.Introspection; using Chickensoft.Introspection;
using Chickensoft.LogicBlocks;
using Godot; using Godot;
using Godot.Collections;
using System.Collections.Immutable; using System.Collections.Immutable;
using System.Linq; using System.Linq;
using Zennysoft.Ma; using Zennysoft.Ma;
@@ -20,6 +23,9 @@ public partial class PauseDebugMenu : Control, IDebugMenu
[Dependency] private IPlayer _player => this.DependOn<IPlayer>(); [Dependency] private IPlayer _player => this.DependOn<IPlayer>();
[Node] public OptionButton FloorSelectDropDown { get; set; } = default!; [Node] public OptionButton FloorSelectDropDown { get; set; } = default!;
[Node] public OptionButton LayoutSelectDropDown { get; set; } = default!;
[Node] public OptionButton RouteSelectDropDown { get; set; } = default!;
[Node] public OptionButton SpawnItemDropDown { get; set; } = default; [Node] public OptionButton SpawnItemDropDown { get; set; } = default;
@@ -74,22 +80,30 @@ public partial class PauseDebugMenu : Control, IDebugMenu
foreach (var item in _spawnableItems) foreach (var item in _spawnableItems)
SpawnItemDropDown.AddItem(item.ItemName); SpawnItemDropDown.AddItem(item.ItemName);
var folders = DirAccess.GetDirectoriesAt(_floorFilePath);
foreach (var folder in folders)
{
var files = DirAccess.GetFilesAt(_floorFilePath + folder).Where(x => x.EndsWith(".tscn"));
foreach (var file in files)
FloorSelectDropDown.AddItem(folder + "/" + file);
}
SigilDropDown.Select(0); SigilDropDown.Select(0);
var dungeonFolders = DirAccess.GetDirectoriesAt(_floorFilePath).Except(["Special Floors"]);
foreach (var dungeonFolder in dungeonFolders)
{
var layouts = DirAccess.GetFilesAt(_floorFilePath + dungeonFolder).Where(x => x.EndsWith(".tscn"));
foreach (var layout in layouts)
LayoutSelectDropDown.AddItem(dungeonFolder + "/" + layout);
}
FloorSelectDropDown.AllowReselect = true; FloorSelectDropDown.AllowReselect = true;
LayoutSelectDropDown.AllowReselect = true;
SpawnItemDropDown.AllowReselect = true; SpawnItemDropDown.AllowReselect = true;
SpawnEnemyDropDown.AllowReselect = true; SpawnEnemyDropDown.AllowReselect = true;
RouteSelectDropDown.AddItem("Base");
RouteSelectDropDown.AddItem("Normal");
RouteSelectDropDown.AddItem("True");
RouteSelectDropDown.AddItem("Bad");
RouteSelectDropDown.Select(0);
RouteSelectDropDown.ItemSelected += RouteSelectDropDown_ItemSelected;
FloorSelectDropDown.ItemSelected += FloorSelectDropDown_ItemSelected; FloorSelectDropDown.ItemSelected += FloorSelectDropDown_ItemSelected;
LayoutSelectDropDown.ItemSelected += LayoutSelectDropDown_ItemSelected;
SpawnItemDropDown.ItemSelected += SpawnItemDropDown_ItemSelected; SpawnItemDropDown.ItemSelected += SpawnItemDropDown_ItemSelected;
SpawnEnemyDropDown.ItemSelected += SpawnEnemyDropDown_ItemSelected; SpawnEnemyDropDown.ItemSelected += SpawnEnemyDropDown_ItemSelected;
@@ -98,6 +112,42 @@ public partial class PauseDebugMenu : Control, IDebugMenu
DebugInfoCheckbox.Pressed += DebugInfoCheckbox_Pressed; DebugInfoCheckbox.Pressed += DebugInfoCheckbox_Pressed;
} }
private void RouteSelectDropDown_ItemSelected(long index)
{
_map.ResetToBaseRoute();
var selectedItem = RouteSelectDropDown.GetItemText((int)index);
if (selectedItem == "Normal")
_map.AddNormalRoute();
else if (selectedItem == "True")
_map.AddTrueRoute();
else if (selectedItem == "Bad")
_map.AddBadEndRoute();
SetFloorDropdownItems();
LayoutSelectDropDown.Select(0);
FloorSelectDropDown_ItemSelected(0);
}
private void SetFloorDropdownItems()
{
FloorSelectDropDown.Clear();
foreach (var item in _map.FloorRoute)
FloorSelectDropDown.AddItem(item.FloorType.ToString());
}
private async void LayoutSelectDropDown_ItemSelected(long index)
{
var selection = LayoutSelectDropDown.GetItemText((int)index);
_map.CurrentSelectedFloor.OnNext(_map.FloorRoute.Single(x => selection.Contains(x.FloorDisplayName)));
await _map.LoadFloorByPath(_floorFilePath + selection);
}
public void OnResolved()
{
SetFloorDropdownItems();
}
private void SigilDropDown_ItemSelected(long index) private void SigilDropDown_ItemSelected(long index)
{ {
var sigilName = SigilDropDown.GetItemText((int)index); var sigilName = SigilDropDown.GetItemText((int)index);
@@ -128,10 +178,12 @@ public partial class PauseDebugMenu : Control, IDebugMenu
private void RustButton_Pressed() => _player.StatusEffectComponent.Rust.OnNext(true); private void RustButton_Pressed() => _player.StatusEffectComponent.Rust.OnNext(true);
private void FloorSelectDropDown_ItemSelected(long index) private async void FloorSelectDropDown_ItemSelected(long index)
{ {
var sceneName = FloorSelectDropDown.GetItemText((int)index); var selection = FloorSelectDropDown.GetItemText((int)index);
_map.LoadFloor(_floorFilePath + "/" + sceneName); var selectedFloor = _map.FloorRoute[(int)index];
_map.CurrentSelectedFloor.OnNext(selectedFloor);
await _map.LoadFloor(selectedFloor);
} }
private void SpawnEnemyDropDown_ItemSelected(long index) private void SpawnEnemyDropDown_ItemSelected(long index)
@@ -152,6 +204,7 @@ public partial class PauseDebugMenu : Control, IDebugMenu
private async void LoadNextFloorButton_Pressed() private async void LoadNextFloorButton_Pressed()
{ {
await _map.LoadFloor(); _map.CurrentSelectedFloor.OnNext(_map.FloorRoute[_map.FloorRoute.IndexOf(_map.CurrentSelectedFloor.Value) + 1]);
await _map.LoadFloor(_map.CurrentSelectedFloor.Value);
} }
} }
@@ -1,5 +1,4 @@
using Godot; using Godot;
using System;
using System.Linq; using System.Linq;
namespace Zennysoft.Game.Ma; namespace Zennysoft.Game.Ma;