Refactoring game logic
This commit is contained in:
@@ -6,5 +6,11 @@ public interface ISaveFileManager<T>
|
||||
{
|
||||
public Task WriteToFile(T gameData);
|
||||
|
||||
public Task<T> ReadFromFile();
|
||||
public Task WriteToFile(T gameData, string filePath);
|
||||
|
||||
public Task WriteToFile(T gameData, string filePath, JsonSerializerOptions jsonOptions);
|
||||
|
||||
public Task<T?> ReadFromFile();
|
||||
|
||||
public Task<T?> ReadFromFile(string filePath);
|
||||
}
|
||||
|
||||
@@ -12,9 +12,9 @@ public partial class GameLogic
|
||||
|
||||
public readonly record struct ExitPauseMenu;
|
||||
|
||||
public readonly record struct OpenInventory();
|
||||
public readonly record struct OpenInventory;
|
||||
|
||||
public readonly record struct HideInventory;
|
||||
public readonly record struct CloseInventory;
|
||||
|
||||
public readonly record struct SetPauseMode(bool IsPaused);
|
||||
|
||||
@@ -41,5 +41,9 @@ public partial class GameLogic
|
||||
public readonly record struct GoToOverworld;
|
||||
|
||||
public readonly record struct SaveGame;
|
||||
|
||||
public readonly record struct AnnounceMessage(string Message);
|
||||
|
||||
public readonly record struct DoubleExpTimeStart(int lengthOfTimeInSeconds);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,14 +14,30 @@ public partial class GameLogic
|
||||
{
|
||||
var gameRepo = Get<IGameRepo>();
|
||||
gameRepo.IsPaused.Sync += OnIsPaused;
|
||||
gameRepo.OpenInventory += OnOpenInventory;
|
||||
gameRepo.CloseInventory += OnCloseInventory;
|
||||
gameRepo.AnnounceMessage += OnAnnounceMessage;
|
||||
gameRepo.DoubleExpTimeStart += OnDoubleExpTimeStart;
|
||||
});
|
||||
OnDetach(() =>
|
||||
{
|
||||
var gameRepo = Get<IGameRepo>();
|
||||
gameRepo.IsPaused.Sync -= OnIsPaused;
|
||||
gameRepo.OpenInventory -= OnOpenInventory;
|
||||
gameRepo.CloseInventory -= OnCloseInventory;
|
||||
gameRepo.AnnounceMessage -= OnAnnounceMessage;
|
||||
gameRepo.DoubleExpTimeStart -= OnDoubleExpTimeStart;
|
||||
});
|
||||
}
|
||||
|
||||
private void OnOpenInventory() => Output(new Output.OpenInventory());
|
||||
|
||||
private void OnCloseInventory() => Output(new Output.CloseInventory());
|
||||
|
||||
private void OnAnnounceMessage(string message) => Output(new Output.AnnounceMessage(message));
|
||||
|
||||
private void OnDoubleExpTimeStart(int lengthOfTimeInSeconds) => Output(new Output.DoubleExpTimeStart(lengthOfTimeInSeconds));
|
||||
|
||||
public void OnIsPaused(bool isPaused) => Output(new Output.SetPauseMode(isPaused));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,27 +5,51 @@ namespace Zennysoft.Game.Ma.Implementation;
|
||||
|
||||
public interface IGameRepo : IDisposable
|
||||
{
|
||||
event Action? Ended;
|
||||
|
||||
event Action? OpenInventory;
|
||||
|
||||
event Action? CloseInventory;
|
||||
|
||||
event Action<string>? AnnounceMessage;
|
||||
|
||||
event Action<int>? DoubleExpTimeStart;
|
||||
|
||||
event Action? DoubleExpTimeEnd;
|
||||
|
||||
void Pause();
|
||||
|
||||
void Resume();
|
||||
|
||||
IAutoProp<bool> IsPaused { get; }
|
||||
|
||||
public void StartDoubleEXP(TimeSpan lengthOfEffect);
|
||||
|
||||
public void EndDoubleExp();
|
||||
|
||||
public double ExpRate { get; }
|
||||
}
|
||||
|
||||
public class GameRepo : IGameRepo
|
||||
{
|
||||
public event Action? Ended;
|
||||
public event Action? OpenInventory;
|
||||
public event Action? CloseInventory;
|
||||
public event Action<string>? AnnounceMessage;
|
||||
public event Action<int>? DoubleExpTimeStart;
|
||||
public event Action? DoubleExpTimeEnd;
|
||||
|
||||
public IAutoProp<bool> IsPaused => _isPaused;
|
||||
private readonly AutoProp<bool> _isPaused;
|
||||
|
||||
public int MaxItemSize => 20;
|
||||
public double ExpRate { get; private set; }
|
||||
|
||||
private bool _disposedValue;
|
||||
|
||||
public GameRepo()
|
||||
{
|
||||
_isPaused = new AutoProp<bool>(true);
|
||||
ExpRate = 1;
|
||||
}
|
||||
|
||||
public void Pause()
|
||||
@@ -40,6 +64,20 @@ public class GameRepo : IGameRepo
|
||||
GD.Print("Resume");
|
||||
}
|
||||
|
||||
public void StartDoubleEXP(TimeSpan lengthOfEffect)
|
||||
{
|
||||
CloseInventory?.Invoke();
|
||||
AnnounceMessage?.Invoke("Experience points temporarily doubled.");
|
||||
DoubleExpTimeStart?.Invoke(lengthOfEffect.Seconds);
|
||||
ExpRate = 2;
|
||||
}
|
||||
|
||||
public void EndDoubleExp()
|
||||
{
|
||||
AnnounceMessage?.Invoke("Experience points effect wore off.");
|
||||
ExpRate = 1;
|
||||
}
|
||||
|
||||
public void OnGameEnded()
|
||||
{
|
||||
Pause();
|
||||
|
||||
@@ -13,7 +13,7 @@ public partial class GameLogic
|
||||
public InventoryOpened()
|
||||
{
|
||||
this.OnEnter(() => { Get<IGameRepo>().Pause(); Output(new Output.OpenInventory()); });
|
||||
this.OnExit(() => { Get<IGameRepo>().Resume(); Output(new Output.HideInventory()); });
|
||||
this.OnExit(() => { Get<IGameRepo>().Resume(); Output(new Output.CloseInventory()); });
|
||||
}
|
||||
|
||||
public Transition On(in Input.CloseInventory input)
|
||||
|
||||
8
Zennysoft.Game.Ma.Implementation/GlobalSuppressions.cs
Normal file
8
Zennysoft.Game.Ma.Implementation/GlobalSuppressions.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
// This file is used by Code Analysis to maintain SuppressMessage
|
||||
// attributes that are applied to this project.
|
||||
// Project-level suppressions either have no target or are given
|
||||
// a specific target and scoped to a namespace, type, member, etc.
|
||||
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
[assembly: SuppressMessage("Style", "IDE0130:Namespace does not match folder structure", Justification = "<Pending>", Scope = "namespace", Target = "~N:Zennysoft.Game.Ma.Implementation")]
|
||||
@@ -3,6 +3,7 @@
|
||||
public enum ThrowableItemTag
|
||||
{
|
||||
None,
|
||||
DoubleExp,
|
||||
LowerTargetTo1HP,
|
||||
CanChangeAffinity,
|
||||
TeleportToRandomLocation,
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
public enum UsableItemTag
|
||||
{
|
||||
None,
|
||||
DoubleEXP,
|
||||
IdentifyAllItemsCostHP,
|
||||
BriefImmunity,
|
||||
SwapHPAndVT,
|
||||
|
||||
@@ -12,15 +12,14 @@ namespace Zennysoft.Game.Ma.Implementation;
|
||||
public class SaveFileManager<T> : ISaveFileManager<T>
|
||||
{
|
||||
private readonly IFileSystem _fileSystem;
|
||||
public const string SAVE_FILE_NAME = "game.json";
|
||||
public JsonSerializerOptions JsonOptions { get; set; } = default!;
|
||||
|
||||
public string SaveFilePath { get; set; } = default!;
|
||||
private JsonSerializerOptions _jsonOptions;
|
||||
private string _defaultSaveLocation;
|
||||
public const string DEFAULT_SAVE_FILE_NAME = "game.json";
|
||||
|
||||
public SaveFileManager(IFileSystem fileSystem)
|
||||
{
|
||||
_fileSystem = fileSystem;
|
||||
SaveFilePath = _fileSystem.Path.Join(OS.GetUserDataDir(), SAVE_FILE_NAME);
|
||||
_defaultSaveLocation = _fileSystem.Path.Join(OS.GetUserDataDir(), DEFAULT_SAVE_FILE_NAME);
|
||||
|
||||
var resolver = new SerializableTypeResolver();
|
||||
GodotSerialization.Setup();
|
||||
@@ -28,7 +27,7 @@ public class SaveFileManager<T> : ISaveFileManager<T>
|
||||
|
||||
var upgradeDependencies = new Blackboard();
|
||||
|
||||
JsonOptions = new JsonSerializerOptions
|
||||
_jsonOptions = new JsonSerializerOptions
|
||||
{
|
||||
Converters = {
|
||||
new SerializableTypeConverter(upgradeDependencies)
|
||||
@@ -39,18 +38,36 @@ public class SaveFileManager<T> : ISaveFileManager<T>
|
||||
}
|
||||
|
||||
|
||||
public async Task<T> ReadFromFile()
|
||||
public Task<T?> ReadFromFile()
|
||||
{
|
||||
if (!_fileSystem.File.Exists(SaveFilePath))
|
||||
if (!_fileSystem.File.Exists(_defaultSaveLocation))
|
||||
throw new FileNotFoundException();
|
||||
return ReadFromFile(_defaultSaveLocation);
|
||||
}
|
||||
|
||||
public async Task<T?> ReadFromFile(string filePath)
|
||||
{
|
||||
if (!_fileSystem.File.Exists(filePath))
|
||||
throw new FileNotFoundException();
|
||||
|
||||
var json = await _fileSystem.File.ReadAllTextAsync(SaveFilePath);
|
||||
return JsonSerializer.Deserialize<T>(json, JsonOptions);
|
||||
var json = await _fileSystem.File.ReadAllTextAsync(filePath);
|
||||
|
||||
return JsonSerializer.Deserialize<T?>(json, _jsonOptions);
|
||||
}
|
||||
|
||||
public async Task WriteToFile(T gameData)
|
||||
public Task WriteToFile(T gameData)
|
||||
{
|
||||
var json = JsonSerializer.Serialize(gameData, JsonOptions);
|
||||
await _fileSystem.File.WriteAllTextAsync(SaveFilePath, json);
|
||||
return WriteToFile(gameData, _defaultSaveLocation, _jsonOptions);
|
||||
}
|
||||
|
||||
public Task WriteToFile(T gameData, string filePath)
|
||||
{
|
||||
return WriteToFile(gameData, filePath, _jsonOptions);
|
||||
}
|
||||
|
||||
public async Task WriteToFile(T gameData, string filePath, JsonSerializerOptions jsonOptions)
|
||||
{
|
||||
var json = JsonSerializer.Serialize(gameData, jsonOptions);
|
||||
await _fileSystem.File.WriteAllTextAsync(filePath, json);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,8 +80,6 @@ public partial class Game : Node3D, IGame
|
||||
|
||||
private EffectService _effectService;
|
||||
|
||||
private double _expRate = 1;
|
||||
|
||||
public void Setup()
|
||||
{
|
||||
_container = new SimpleInjector.Container();
|
||||
@@ -194,13 +192,15 @@ public partial class Game : Node3D, IGame
|
||||
.Handle((in GameLogic.Output.ShowFloorClearMenu _) => { FloorClearMenu.Show(); FloorClearMenu.FadeIn(); })
|
||||
.Handle((in GameLogic.Output.ExitFloorClearMenu _) => { FloorClearMenu.FadeOut(); })
|
||||
.Handle((in GameLogic.Output.OpenInventory _) => { InGameUI.ShowInventoryScreen(); InGameUI.InventoryMenu.SetProcessInput(true); })
|
||||
.Handle((in GameLogic.Output.HideInventory _) => { InGameUI.HideInventoryScreen(); InGameUI.InventoryMenu.SetProcessInput(false); })
|
||||
.Handle((in GameLogic.Output.CloseInventory _) => { InGameUI.HideInventoryScreen(); InGameUI.InventoryMenu.SetProcessInput(false); })
|
||||
.Handle((in GameLogic.Output.ShowMiniMap _) => { InGameUI.ShowMiniMap(); })
|
||||
.Handle((in GameLogic.Output.HideMiniMap _) => { InGameUI.HideMiniMap(); })
|
||||
.Handle((in GameLogic.Output.ShowAskForTeleport _) => { GameRepo.Pause(); InGameUI.UseTeleportPrompt.FadeIn(); InGameUI.SetProcessInput(true); })
|
||||
.Handle((in GameLogic.Output.HideAskForTeleport _) => { GameRepo.Resume(); InGameUI.UseTeleportPrompt.FadeOut(); InGameUI.SetProcessInput(false); })
|
||||
.Handle((in GameLogic.Output.ShowLostScreen _) => { DeathMenu.Show(); DeathMenu.FadeIn(); })
|
||||
.Handle((in GameLogic.Output.ExitLostScreen _) => { DeathMenu.FadeOut(); })
|
||||
.Handle((in GameLogic.Output.AnnounceMessage output) => { AnnounceMessageOnMainScreen(output.Message); })
|
||||
.Handle((in GameLogic.Output.DoubleExpTimeStart output) => { DoubleEXPTimer.WaitTime = output.lengthOfTimeInSeconds; DoubleEXPTimer.Start(); })
|
||||
.Handle((in GameLogic.Output.SaveGame _) =>
|
||||
{
|
||||
SaveFile.Save();
|
||||
@@ -284,9 +284,6 @@ public partial class Game : Node3D, IGame
|
||||
{
|
||||
switch (effectItem.UsableItemTag)
|
||||
{
|
||||
case UsableItemTag.DoubleEXP:
|
||||
DoubleEXP(TimeSpan.FromSeconds(30));
|
||||
break;
|
||||
case UsableItemTag.TeleportAllEnemiesToRoom:
|
||||
_effectService.TeleportEnemiesToCurrentRoom();
|
||||
break;
|
||||
@@ -324,6 +321,9 @@ public partial class Game : Node3D, IGame
|
||||
}
|
||||
if (item is ThrowableItem throwableItem)
|
||||
{
|
||||
if (throwableItem.ThrowableItemTag == ThrowableItemTag.DoubleExp)
|
||||
GameRepo.StartDoubleEXP(TimeSpan.FromSeconds(30));
|
||||
|
||||
if (throwableItem.HealHPAmount > 0)
|
||||
Player.HealHP(throwableItem.HealHPAmount);
|
||||
if (throwableItem.HealVTAmount > 0)
|
||||
@@ -373,7 +373,7 @@ public partial class Game : Node3D, IGame
|
||||
|
||||
public void EnemyDefeated(Vector3 defeatedLocation, EnemyStatResource resource)
|
||||
{
|
||||
Player.GainExp(resource.ExpFromDefeat * _expRate);
|
||||
Player.GainExp(resource.ExpFromDefeat * GameRepo.ExpRate);
|
||||
}
|
||||
|
||||
private void DropRestorative(Vector3 vector)
|
||||
@@ -441,19 +441,9 @@ public partial class Game : Node3D, IGame
|
||||
GetTree().Paused = isPaused;
|
||||
}
|
||||
|
||||
public async void DoubleEXP(TimeSpan lengthOfEffect)
|
||||
{
|
||||
ToggleInventory();
|
||||
AnnounceMessageOnMainScreen("Experience points temporarily doubled.");
|
||||
DoubleEXPTimer.Start(lengthOfEffect.Seconds);
|
||||
_expRate = 2;
|
||||
}
|
||||
|
||||
private void DoubleEXPTimer_Timeout()
|
||||
{
|
||||
DoubleEXPTimer.Stop();
|
||||
_expRate = 1;
|
||||
AnnounceMessageOnMainScreen("Experience points effect wore off.");
|
||||
GameRepo.EndDoubleExp();
|
||||
}
|
||||
|
||||
private void InventoryMenu_CloseInventory() => GameLogic.Input(new GameLogic.Input.CloseInventory());
|
||||
|
||||
@@ -26,8 +26,6 @@ public interface IGame : IProvide<IGameRepo>, IProvide<IGameEventDepot>, IProvid
|
||||
|
||||
public void ThrowItem(InventoryItem item);
|
||||
|
||||
public void DoubleEXP(TimeSpan lengthOfEffect);
|
||||
|
||||
public void ToggleInventory();
|
||||
|
||||
public void ToggleMinimap();
|
||||
|
||||
@@ -5,8 +5,9 @@
|
||||
|
||||
[resource]
|
||||
script = ExtResource("1_s3pq7")
|
||||
ThrowableItemTags = Array[int]([])
|
||||
UsableItemTags = Array[int]([0])
|
||||
ThrowableItemTag = 1
|
||||
ElementType = 0
|
||||
UsableItemTag = 0
|
||||
Name = "Spell Sign: Knowledge"
|
||||
Description = "Doubles experience points earned. Effect is temporary."
|
||||
Texture = ExtResource("1_3605p")
|
||||
@@ -15,3 +16,4 @@ ThrowSpeed = 12.0
|
||||
HealHPAmount = 0
|
||||
HealVTAmount = 0
|
||||
ThrowDamage = 5
|
||||
ItemTag = 0
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
[gd_scene load_steps=61 format=4 uid="uid://dl6h1djc27ddl"]
|
||||
[gd_scene load_steps=63 format=4 uid="uid://dl6h1djc27ddl"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://c1nhqlem1ew3m" path="res://src/map/dungeon/code/Floor0.cs" id="1_db2o3"]
|
||||
[ext_resource type="Texture2D" uid="uid://b27ksiyfefb33" path="res://src/map/dungeon/models/Set A/02. Altar/02_ALTAR_FLOOR_ZER0_VER_outside_desert.png" id="2_xh2ej"]
|
||||
@@ -15,6 +15,8 @@
|
||||
[ext_resource type="Texture2D" uid="uid://dyufabjcwlago" path="res://src/map/dungeon/models/Set A/02. Altar/02_ALTAR_FLOOR_ZER0_VER_HAND_CYCLE_MOTIF.png" id="13_1i307"]
|
||||
[ext_resource type="Texture2D" uid="uid://4k6vtn4oip5f" path="res://src/map/dungeon/models/Set A/02. Altar/02_ALTAR_FLOOR_ZER0_VER_TILE4.png" id="14_qqc7i"]
|
||||
[ext_resource type="Texture2D" uid="uid://cururtxtgylxf" path="res://src/map/dungeon/models/Set A/02. Altar/02_ALTAR_FLOOR_ZER0_VER_COLUMN.jpg" id="15_ojbcg"]
|
||||
[ext_resource type="PackedScene" uid="uid://1fl6s352e2ej" path="res://src/items/throwable/ThrowableItem.tscn" id="16_db2o3"]
|
||||
[ext_resource type="Resource" uid="uid://qqg0gdcb8fwg" path="res://src/items/throwable/resources/SpellSignKnowledge.tres" id="17_ntxe5"]
|
||||
|
||||
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_3ubi4"]
|
||||
shading_mode = 0
|
||||
@@ -896,3 +898,7 @@ shape = SubResource("BoxShape3D_db2o3")
|
||||
|
||||
[node name="Camera3D" type="Camera3D" parent="."]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -9.00384, 1.80761, 11.3571)
|
||||
|
||||
[node name="ThrowableItem" parent="." instance=ExtResource("16_db2o3")]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -3.78811, -3.32789, 0)
|
||||
_throwableItemStats = ExtResource("17_ntxe5")
|
||||
|
||||
Reference in New Issue
Block a user