Rework game over logic and game initialization

This commit is contained in:
2025-10-27 15:04:01 -07:00
parent 720696aed0
commit 7e6dca1c29
46 changed files with 653 additions and 610 deletions

View File

@@ -60,38 +60,29 @@ public partial class Game : Node3D, IGame
public RescuedItemDatabase RescuedItems { get; set; } = default!;
public ItemDatabase ItemDatabase { get; private set; }
public QuestData QuestData { get; private set; }
private EffectService _effectService;
private ItemReroller _itemReroller;
private IInstantiator _instantiator;
private Player _player;
private Map _map;
private IPlayer _player;
private IMap _map;
public Game()
{
QuestData = new QuestData();
}
public void Setup()
{
_container = new SimpleInjector.Container();
Module.Bootstrap(_container);
_instantiator = new Instantiator(GetTree());
_player = _instantiator.LoadAndInstantiate<Player>("res://src/player/Player.tscn");
PauseContainer.AddChild(_player);
_map = _instantiator.LoadAndInstantiate<Map>("res://src/map/Map.tscn");
PauseContainer.AddChild(_map);
GameRepo = _container.GetInstance<IGameRepo>();
GameState = _container.GetInstance<IGameState>();
GameState.Set(GameRepo);
GameState.Set(_player);
GameState.Set(_map);
GameState.Set(InGameUI);
QuestData = new QuestData();
RescuedItems = new RescuedItemDatabase();
ItemDatabase = ItemDatabase.Instance;
_itemReroller = new ItemReroller(ItemDatabase);
GameChunk = new SaveChunk<GameData>(
(chunk) =>
@@ -111,15 +102,12 @@ public partial class Game : Node3D, IGame
},
onLoad:
(chunk, data) =>
{
RescuedItems = data.RescuedItems;
QuestData = data.QuestData;
}
{
RescuedItems = data.RescuedItems;
QuestData = data.QuestData;
}
);
}
public void OnResolved()
{
var saveFileManager = _container.GetInstance<IMaSaveFileManager>();
SaveFile = new SaveFile<GameData>(
root: GameChunk,
@@ -139,14 +127,129 @@ public partial class Game : Node3D, IGame
return null;
}
);
}
public void Setup()
{
_instantiator = new Instantiator(GetTree());
_player = _instantiator.LoadAndInstantiate<Player>("res://src/player/Player.tscn");
_map = _instantiator.LoadAndInstantiate<Map>("res://src/map/Map.tscn");
PauseContainer.AddChild((Player)_player);
PauseContainer.AddChild((Map)_map);
}
public async void OnResolved()
{
await InitializeGame();
GameState.Set(GameRepo);
GameState.Set(_player);
GameState.Set(_map);
GameState.Set(InGameUI);
GameRepo.Resume();
InGameUI.Show();
HandleGameLogic();
GameState.Start();
this.Provide();
InGameUI.UseTeleportPrompt.TeleportToNextFloor += UseTeleportPrompt_TeleportToNextFloor;
InGameUI.UseTeleportPrompt.CloseTeleportPrompt += UseTeleportPrompt_CloseTeleportPrompt;
FloorClearMenu.GoToNextFloor += FloorClearMenu_GoToNextFloor;
FloorClearMenu.Exit += FloorClearMenu_Exit;
FloorClearMenu.TransitionCompleted += FloorClearMenu_TransitionCompleted;
GameRepo.RestorativePickedUp += GameEventDepot_RestorativePickedUp;
_player.PlayerDied += GameOver;
DeathMenu.NewGame += OnNewGame;
DeathMenu.QuitGame += OnQuit;
GameRepo.IsPaused.Sync += IsPaused_Sync;
InGameUI.PlayerInfoUI.Activate();
_map.SpawnPointCreated += MovePlayer;
}
public void LoadExistingGame() => SaveFile.Load().ContinueWith((_) => CallDeferred(nameof(FinishedLoadingSaveFile)));
public async Task InitializeGame()
{
_player.ResetPlayerData();
_map.InitializeMapData();
_effectService = new EffectService(this, _player, _map);
_player.Activate();
await _map.LoadFloor();
}
public async Task Save() => await SaveFile.Save();
public void FloorExitReached() => GameState.Input(new GameState.Input.FloorExitEntered());
public async Task UseItem(InventoryItem item)
{
if (item.ItemTag == ItemTag.MysteryItem)
item = _itemReroller.RerollItem(item, _player.Inventory);
switch (item)
{
case ConsumableItem consumableItem:
EnactConsumableItemEffects(consumableItem);
break;
case EffectItem effectItem:
EnactEffectItemEffects(effectItem);
break;
case ThrowableItem throwableItem:
EnactThrowableItemEffects(throwableItem);
break;
}
await ToSignal(GetTree().CreateTimer(0.3f), "timeout");
RemoveItemOrSubtractFromItemCount(item);
}
public void DropItem(InventoryItem item)
{
var droppedScene = GD.Load<PackedScene>("res://src/items/dropped/DroppedItem.tscn");
var dropped = droppedScene.Instantiate<DroppedItem>();
dropped.Item = item;
AddChild(dropped);
dropped.Drop();
}
public void ThrowItem(InventoryItem item)
{
var thrownScene = GD.Load<PackedScene>("res://src/items/thrown/ThrownItem.tscn");
var thrown = thrownScene.Instantiate<ThrownItem>();
thrown.ItemThatIsThrown = item;
AddChild(thrown);
thrown.Position += new Vector3(0, 1.5f, 0);
thrown.Throw(_effectService);
}
public IDungeonFloor CurrentFloor => _map.CurrentFloor;
public void GameOver()
{
_player.Deactivate();
GameState.Input(new GameState.Input.GameOver());
}
public override void _Input(InputEvent @event)
{
if (@event.IsActionPressed(GameInputs.Debug))
GameState.Input(new GameState.Input.DebugButtonPressed());
}
private void HandleGameLogic()
{
GameBinding = GameState.Bind();
GameBinding
.Handle((in GameState.Output.InitializeGame _) =>
{
})
.Handle((in GameState.Output.LoadGameFromFile _) =>
{
LoadExistingGame();
InitializeGame();
})
.Handle((in GameState.Output.OpenPauseScreen _) =>
{
@@ -227,146 +330,17 @@ public partial class Game : Node3D, IGame
GameRepo.Pause();
DeathMenu.FadeIn();
});
GameState.Start();
this.Provide();
InGameUI.UseTeleportPrompt.TeleportToNextFloor += UseTeleportPrompt_TeleportToNextFloor;
InGameUI.UseTeleportPrompt.CloseTeleportPrompt += UseTeleportPrompt_CloseTeleportPrompt;
FloorClearMenu.GoToNextFloor += FloorClearMenu_GoToNextFloor;
FloorClearMenu.SaveAndExit += FloorClearMenu_SaveAndExit;
FloorClearMenu.TransitionCompleted += FloorClearMenu_TransitionCompleted;
GameRepo.RestorativePickedUp += GameEventDepot_RestorativePickedUp;
DeathMenu.NewGame += OnContinueGame;
DeathMenu.QuitGame += OnQuit;
GameRepo.IsPaused.Sync += IsPaused_Sync;
_effectService = new EffectService(this, _player, _map);
}
#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
public void OnReady()
{
InitializeGame();
SaveFile.Load();
_map.LoadFloor();
GameRepo.Resume();
InGameUI.Show();
InGameUI.PlayerInfoUI.Activate();
_player.Activate();
}
#pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
private void FloorClearMenu_SaveAndExit()
private void FloorClearMenu_Exit()
{
_player.Deactivate();
GameState.Input(new GameState.Input.ReturnToMainMenu());
_map.ClearMap();
InGameUI.Hide();
}
private void FloorClearMenu_GoToNextFloor() => GameState.Input(new GameState.Input.LoadNextFloor());
public void LoadExistingGame() => SaveFile.Load().ContinueWith((_) => CallDeferred(nameof(FinishedLoadingSaveFile)));
public void InitializeGame()
{
_map.InitializeMapData();
}
public async Task Save() => await SaveFile.Save();
public void FloorExitReached()
{
GameState.Input(new GameState.Input.FloorExitEntered());
}
public async Task UseItem(InventoryItem item)
{
if (item.ItemTag == ItemTag.MysteryItem)
item = RerollItem(item);
switch (item)
{
case ConsumableItem consumableItem:
EnactConsumableItemEffects(consumableItem);
break;
case EffectItem effectItem:
EnactEffectItemEffects(effectItem);
break;
case ThrowableItem throwableItem:
EnactThrowableItemEffects(throwableItem);
break;
}
await ToSignal(GetTree().CreateTimer(0.3f), "timeout");
RemoveItemOrSubtractFromItemCount(item);
}
public void DropItem(InventoryItem item)
{
var droppedScene = GD.Load<PackedScene>("res://src/items/dropped/DroppedItem.tscn");
var dropped = droppedScene.Instantiate<DroppedItem>();
dropped.Item = item;
AddChild(dropped);
dropped.Drop();
}
public void ThrowItem(InventoryItem item)
{
var thrownScene = GD.Load<PackedScene>("res://src/items/thrown/ThrownItem.tscn");
var thrown = thrownScene.Instantiate<ThrownItem>();
thrown.ItemThatIsThrown = item;
AddChild(thrown);
thrown.Position += new Vector3(0, 1.5f, 0);
thrown.Throw(_effectService);
}
public IDungeonFloor CurrentFloor => _map.CurrentFloor;
public InventoryItem RerollItem(InventoryItem itemToReroll, bool insertIntoInventory = true)
{
var itemDb = new ItemDatabase();
var currentIndex = _player.Inventory.Items.IndexOf(itemToReroll);
if (insertIntoInventory)
_player.Inventory.Remove(itemToReroll);
InventoryItem rolledItem = null;
if (itemToReroll is Weapon weapon)
rolledItem = itemDb.PickItem(weapon);
if (itemToReroll is Armor armor)
rolledItem = itemDb.PickItem(armor);
if (itemToReroll is Accessory accessory)
rolledItem = itemDb.PickItem(accessory);
if (itemToReroll is ThrowableItem throwableItem)
rolledItem = itemDb.PickItem(throwableItem);
if (itemToReroll is EffectItem effectItem)
rolledItem = itemDb.PickItem(effectItem);
if (itemToReroll is ConsumableItem consumableItem)
rolledItem = itemDb.PickItem(consumableItem);
if (insertIntoInventory)
_player.Inventory.TryInsert(rolledItem, currentIndex);
return rolledItem;
}
public void GameOver()
{
GameState.Input(new GameState.Input.GameOver());
}
public override void _Input(InputEvent @event)
{
if (@event.IsActionPressed(GameInputs.Debug))
GameState.Input(new GameState.Input.DebugButtonPressed());
}
private void DropRestorative(Vector3 vector)
{
var restorativeScene = GD.Load<PackedScene>("res://src/items/restorative/Restorative.tscn");
@@ -490,36 +464,28 @@ public partial class Game : Node3D, IGame
GameRepo.RemoveItemFromInventory(item);
}
private void MovePlayer(Transform3D spawnPoint) => _player.TeleportPlayer(spawnPoint);
private void OnNewGame()
{
SaveFile.Load();
GameState.Input(new GameState.Input.NewGame());
GameRepo.Resume();
}
private void OnContinueGame()
{
GameState.Input(new GameState.Input.ContinueGame());
}
private void OnLoadGame()
{
GameState.Input(new GameState.Input.LoadGame());
}
private void OnQuit()
{
}
private void OnQuit() => GetTree().Root.QueueFree();
public void OnExitTree()
{
InGameUI.UseTeleportPrompt.TeleportToNextFloor -= UseTeleportPrompt_TeleportToNextFloor;
InGameUI.UseTeleportPrompt.CloseTeleportPrompt -= UseTeleportPrompt_CloseTeleportPrompt;
FloorClearMenu.GoToNextFloor -= FloorClearMenu_GoToNextFloor;
FloorClearMenu.SaveAndExit -= FloorClearMenu_SaveAndExit;
FloorClearMenu.Exit -= FloorClearMenu_Exit;
FloorClearMenu.TransitionCompleted -= FloorClearMenu_TransitionCompleted;
GameRepo.RestorativePickedUp -= GameEventDepot_RestorativePickedUp;
DeathMenu.NewGame -= OnContinueGame;
DeathMenu.NewGame -= OnNewGame;
DeathMenu.QuitGame -= OnQuit;
GameRepo.IsPaused.Sync -= IsPaused_Sync;