Files
GameJamDungeon/Zennysoft.Game.Ma/src/map/Map.cs
T

190 lines
4.7 KiB
C#

using Chickensoft.AutoInject;
using Chickensoft.Collections;
using Chickensoft.Introspection;
using Godot;
using Godot.Collections;
using System;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using Zennysoft.Game.Abstractions;
namespace Zennysoft.Game.Ma;
[Meta(typeof(IAutoNode))]
public partial class Map : Node3D, IMap
{
public override void _Notification(int what) => this.Notify(what);
[Dependency]
public IGame Game => this.DependOn<IGame>();
[Node]
public AnimationPlayer AnimationPlayer { get; set; } = default!;
public IDungeonFloor CurrentFloor { get; private set; }
public event Action<(Vector3 Rotation, Vector3 Position)> SpawnPointCreated;
public Array<FloorScene> FloorRoute { get; private 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;
private string _floorToLoad;
private Stopwatch _elapsedTime;
public override void _EnterTree()
{
FloorRoute = [.. BaseRoute];
CurrentSelectedFloor = new AutoProp<FloorScene>(FloorRoute.First());
}
public void OnResolved()
{
AnimationPlayer.AnimationFinished += AnimationPlayer_AnimationFinished;
this.Provide();
}
private async void AnimationPlayer_AnimationFinished(StringName animName)
{
if (animName == "fade_out")
await ContinueLoadingFloor(_floorToLoad);
}
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)
{
_elapsedTime = new Stopwatch();
_elapsedTime.Start();
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)));
var newFloor = await LoadSceneFile(filePath);
// New floor created, remove old floor
ClearFloor();
// Setup new floor
AddChild(newFloor);
CurrentFloor = newFloor as IDungeonFloor;
CurrentFloor.InitializeDungeon();
SpawnPointCreated?.Invoke(CurrentFloor.GetPlayerSpawnPoint());
if (CurrentFloor is SpecialFloor)
Game.ShowMinimap(false);
else
Game.ShowMinimap(true);
SpawnEnemies();
SpawnItems();
CurrentFloor.FloorIsLoaded = true;
FloorLoaded?.Invoke();
_elapsedTime.Stop();
GD.Print($"Floor loaded in {_elapsedTime.ElapsedMilliseconds}ms.");
}
private void CleanupCurrentFloor()
{
var dimmableAudio = GetTree().GetNodesInGroup("DimmableAudio").OfType<IDimmableAudioStreamPlayer>();
foreach (var node in dimmableAudio)
node.FadeOut();
}
private void ClearFloor()
{
try
{
if (CurrentFloor != null && !CurrentFloor.IsQueuedForDeletion())
CurrentFloor?.CallDeferred(MethodName.QueueFree, []);
}
catch (ObjectDisposedException ex)
{
}
}
private async Task<Node> LoadSceneFile(string sceneName)
{
var sceneLoader = new SceneLoader();
AddChild(sceneLoader);
sceneLoader.LoadSceneRequest(sceneName);
await ToSignal(sceneLoader, SceneLoader.SignalName.SceneLoaded);
var result = sceneLoader.LoadedScene;
sceneLoader.QueueFree();
return result;
}
private void SpawnEnemies()
{
var monsterRooms = CurrentFloor.Rooms.OfType<MonsterRoom>();
foreach (var room in monsterRooms)
room.SpawnEnemies(CurrentSelectedFloor.Value.EnemySpawnTable);
}
private void SpawnItems()
{
var monsterRooms = CurrentFloor.Rooms.OfType<MonsterRoom>();
foreach (var room in monsterRooms)
room.SpawnItems(CurrentSelectedFloor.Value.FloorType);
}
}