190 lines
4.7 KiB
C#
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);
|
|
}
|
|
} |