cirnogodot/Scripts/Components/FSM/3DPlayer/Dead.cs

141 lines
No EOL
4.3 KiB
C#

using Cirno.Scripts.Components.Actors;
using Cirno.Scripts.Components.Actors._3D;
using Cirno.Scripts.Controllers;
using Godot;
namespace Cirno.Scripts.Components.FSM._3DPlayer;
public partial class Dead : BaseState<PlayerState, CharacterBody3D>
{
public override PlayerState StateId => PlayerState.Dead;
private ActorResourceProvider _motivationProvider;
private InputProvider _inputProvider;
private ActorResourceProvider _healthProvider;
private PlayerAnimationProvider3D _animationProvider;
private bool _isGameOver;
public override void Init(IStateMachine<PlayerState, CharacterBody3D> machine)
{
base.Init(machine);
// try to obtain common providers via modules/storage
if (machine is IsoPlayerStateMachine sm)
{
var storage = sm.Storage;
// store references if present on storage
_motivationProvider = storage.Root.GetNodeOrNull<ActorResourceProvider>("MotivationProvider");
_healthProvider = storage.Root.GetNodeOrNull<ActorResourceProvider>("HealthProvider");
}
// fallback to searching on the actor
_motivationProvider ??= StateMachine.GetModule<ActorResourceProvider>();
_healthProvider ??= StateMachine.GetModule<ActorResourceProvider>();
_animationProvider ??= StateMachine.GetModule<PlayerAnimationProvider3D>();
// The input provider was not initialized after the FSM refactor which caused
// a NullReferenceException in ProcessState when accessing it. Try to obtain
// it from the state machine modules as well. If it's still null, ProcessState
// will early-return to avoid throwing.
_inputProvider ??= StateMachine.GetModule<InputProvider>();
}
public override void EnterState()
{
base.EnterState();
//MainObject.Hide();
// Play death animation if provider is available
_animationProvider?.PlayDeathAnimation();
// If we don't have a motivation provider, assume game over and log the problem.
if (_motivationProvider is null)
{
GD.PrintErr("[Dead] MotivationProvider not found - defaulting to Game Over");
Hud.Instance.ShowGameOver();
_isGameOver = true;
return;
}
if (_motivationProvider.CurrentResource < 100f)
{
// If motivation is not enough show game over scene
Hud.Instance.ShowGameOver();
_isGameOver = true;
}
else
{
// Else show respawn notification
Hud.Instance.ShowTerminated();
_isGameOver = false;
}
}
public override void ExitState()
{
base.ExitState();
Hud.Instance.HideTerminated();
}
public override void ProcessState(double delta)
{
base.ProcessState(delta);
// If input provider is missing, bail out to avoid NullReferenceException.
if (_inputProvider is null)
{
// Log once to help debugging, but avoid spamming the console every frame.
GD.PrintErr("[Dead] InputProvider not available - input ignored in Dead state.");
return;
}
if (_inputProvider.GetShootJustPressed())
{
if (_isGameOver)
{
// Restart Level
GlobalState.Instance.RestartLevel();
}
else
{
Respawn();
}
}
}
public void Respawn()
{
MainObject.GlobalPosition = GameController.Instance.LastCheckPointPosition;
if (_healthProvider is null)
{
GD.PrintErr("[Dead] HealthProvider not found - cannot refill health on respawn");
}
else
{
_healthProvider.FillResource();
}
PoolingManager.Instance.ClearBullets();
if (_motivationProvider is null)
{
GD.PrintErr("[Dead] MotivationProvider not found - skipping motivation deduction");
}
else
{
_motivationProvider.CurrentResource -= 100f;
if (_motivationProvider.CurrentResource <= 1f)
{
_motivationProvider.CurrentResource = 1f;
}
}
ChangeState(PlayerState.Active);
}
}