Files
przygody-pana-cegly/Autoloads/GameManager.cs

252 lines
6.5 KiB
C#

using Godot;
using Godot.Collections;
using Mr.BrickAdventures.scripts.components;
using Mr.BrickAdventures.scripts.Resources;
using Mr.BrickAdventures.scripts.State;
namespace Mr.BrickAdventures.Autoloads;
/// <summary>
/// Game orchestrator - handles scene management and game flow.
/// State is delegated to GameStateStore for better separation of concerns.
/// </summary>
public partial class GameManager : Node
{
[Export] public Array<PackedScene> LevelScenes { get; set; } = [];
public PlayerController Player
{
get => GetPlayer();
private set => _player = value;
}
private PlayerController _player;
private SpeedRunManager SpeedRunManager => SpeedRunManager.Instance;
private GameStateStore Store => GameStateStore.Instance;
public static GameManager Instance { get; private set; }
public override void _Ready()
{
Instance = this;
EventBus.Instance.PlayerSpawned += OnPlayerSpawned;
}
public override void _ExitTree()
{
if (Instance == this) Instance = null;
if (EventBus.Instance != null)
EventBus.Instance.PlayerSpawned -= OnPlayerSpawned;
}
private void OnPlayerSpawned(PlayerController player)
{
_player = player;
player.TreeExiting += () => { if (_player == player) _player = null; };
}
#region Coin Operations
/// <summary>
/// Adds coins permanently to the player's saved total (Store.Player.Coins).
/// Use this for out-of-gameplay grants (e.g. console commands, rewards).
/// During active gameplay, coins collected in a level go through
/// <see cref="GameStateStore.AddSessionCoins"/> and are only committed on level completion.
/// </summary>
public void AddCoins(int amount)
{
if (Store != null)
{
Store.Player.Coins += amount;
EventBus.EmitCoinsChanged(Store.GetTotalCoins());
}
}
public void SetCoins(int amount)
{
if (Store != null)
{
Store.Player.Coins = Mathf.Max(0, amount);
EventBus.EmitCoinsChanged(Store.GetTotalCoins());
}
}
public int GetCoins() => Store?.GetTotalCoins() ?? 0;
public void RemoveCoins(int amount) => Store?.RemoveCoins(amount);
#endregion
#region Lives Operations
public void AddLives(int amount) => Store?.AddLives(amount);
public void RemoveLives(int amount) => Store?.RemoveLife();
public void SetLives(int amount)
{
if (Store != null)
{
Store.Player.Lives = amount;
EventBus.EmitLivesChanged(amount);
}
}
public int GetLives() => Store?.Player.Lives ?? 0;
#endregion
#region Skill Operations
public bool IsSkillUnlocked(SkillData skill) => Store?.IsSkillUnlocked(skill) ?? false;
public void UnlockSkill(SkillData skill)
{
if (Store != null && !Store.IsSkillUnlocked(skill))
{
Store.Player.UnlockedSkills.Add(skill);
}
}
public void RemoveSkill(string skillName)
{
if (Store == null) return;
var skills = Store.Player.UnlockedSkills;
for (int i = 0; i < skills.Count; i++)
{
if (skills[i].Name == skillName)
{
skills.RemoveAt(i);
break;
}
}
}
public void UnlockSkills(Array<SkillData> skills)
{
foreach (var s in skills)
UnlockSkill(s);
}
public Array<SkillData> GetUnlockedSkills()
{
if (Store == null) return new Array<SkillData>();
var skills = Store.GetAllUnlockedSkills();
var result = new Array<SkillData>();
foreach (var s in skills) result.Add(s);
return result;
}
#endregion
#region Level Operations
public void UnlockLevel(int levelIndex) => Store?.UnlockLevel(levelIndex);
public void MarkLevelComplete(int levelIndex) => Store?.MarkLevelComplete(levelIndex);
public void TryToGoToNextLevel()
{
if (Store == null) return;
var next = Store.Session.CurrentLevel + 1;
if (next < LevelScenes.Count && Store.IsLevelUnlocked(next))
{
Store.Session.CurrentLevel = next;
GetTree().ChangeSceneToPacked(LevelScenes[next]);
EventBus.EmitLevelStarted(next, GetTree().CurrentScene);
}
}
#endregion
#region State Reset
public void ResetPlayerState() => Store?.ResetAll();
public void ResetCurrentSessionState() => Store?.ResetSession();
#endregion
#region Game Flow
public void RestartGame()
{
Store?.ResetAll();
GetTree().ChangeSceneToPacked(LevelScenes[0]);
SaveSystem.Instance.SaveGame();
}
public void QuitGame() => GetTree().Quit();
public void PauseGame()
{
Engine.TimeScale = 0;
EventBus.EmitGamePaused();
}
public void ResumeGame()
{
Engine.TimeScale = 1;
EventBus.EmitGameResumed();
}
public void StartNewGame()
{
Store?.ResetAll();
SpeedRunManager?.StartTimer();
GetTree().ChangeSceneToPacked(LevelScenes[0]);
SaveSystem.Instance.SaveGame();
EventBus.EmitGameStarted();
}
public void ContinueGame()
{
var save = SaveSystem.Instance;
if (!save.LoadGame())
{
GD.PrintErr("Failed to load game. Starting a new game instead.");
StartNewGame();
return;
}
var idx = Store?.Session.CurrentLevel ?? 0;
if (idx < LevelScenes.Count)
{
GetTree().ChangeSceneToPacked(LevelScenes[idx]);
EventBus.EmitGameContinued();
}
else
{
GD.PrintErr("No levels unlocked to continue.");
}
}
public void OnLevelComplete()
{
if (Store == null) return;
var levelIndex = Store.Session.CurrentLevel;
Store.MarkLevelComplete(levelIndex);
Store.CommitSessionCoins();
Store.CommitSessionSkills();
var completionTime = SpeedRunManager?.GetCurrentLevelTime() ?? 0.0;
EventBus.EmitLevelCompleted(levelIndex, GetTree().CurrentScene, completionTime);
Store.ResetSession();
TryToGoToNextLevel();
SaveSystem.Instance.SaveGame();
}
#endregion
#region Player Lookup
public PlayerController GetPlayer()
{
if (_player != null && IsInstanceValid(_player)) return _player;
_player = null;
return null;
}
#endregion
}