Major Player refactor
This commit is contained in:
@@ -1,43 +1,44 @@
|
||||
using Godot;
|
||||
using System;
|
||||
|
||||
namespace GameJamDungeon;
|
||||
|
||||
public partial class CharacterBody3d : CharacterBody3D
|
||||
{
|
||||
public const float Speed = 5.0f;
|
||||
public const float JumpVelocity = 4.5f;
|
||||
public const float Speed = 5.0f;
|
||||
public const float JumpVelocity = 4.5f;
|
||||
|
||||
public override void _PhysicsProcess(double delta)
|
||||
{
|
||||
Vector3 velocity = Velocity;
|
||||
public override void _PhysicsProcess(double delta)
|
||||
{
|
||||
Vector3 velocity = Velocity;
|
||||
|
||||
// Add the gravity.
|
||||
if (!IsOnFloor())
|
||||
{
|
||||
velocity += GetGravity() * (float)delta;
|
||||
}
|
||||
// Add the gravity.
|
||||
if (!IsOnFloor())
|
||||
{
|
||||
velocity += GetGravity() * (float)delta;
|
||||
}
|
||||
|
||||
// Handle Jump.
|
||||
if (Input.IsActionJustPressed("ui_accept") && IsOnFloor())
|
||||
{
|
||||
velocity.Y = JumpVelocity;
|
||||
}
|
||||
// Handle Jump.
|
||||
if (Input.IsActionJustPressed("ui_accept") && IsOnFloor())
|
||||
{
|
||||
velocity.Y = JumpVelocity;
|
||||
}
|
||||
|
||||
// Get the input direction and handle the movement/deceleration.
|
||||
// As good practice, you should replace UI actions with custom gameplay actions.
|
||||
Vector2 inputDir = Input.GetVector("ui_left", "ui_right", "ui_up", "ui_down");
|
||||
Vector3 direction = (Transform.Basis * new Vector3(inputDir.X, 0, inputDir.Y)).Normalized();
|
||||
if (direction != Vector3.Zero)
|
||||
{
|
||||
velocity.X = direction.X * Speed;
|
||||
velocity.Z = direction.Z * Speed;
|
||||
}
|
||||
else
|
||||
{
|
||||
velocity.X = Mathf.MoveToward(Velocity.X, 0, Speed);
|
||||
velocity.Z = Mathf.MoveToward(Velocity.Z, 0, Speed);
|
||||
}
|
||||
// Get the input direction and handle the movement/deceleration.
|
||||
// As good practice, you should replace UI actions with custom gameplay actions.
|
||||
Vector2 inputDir = Input.GetVector("ui_left", "ui_right", "ui_up", "ui_down");
|
||||
Vector3 direction = (Transform.Basis * new Vector3(inputDir.X, 0, inputDir.Y)).Normalized();
|
||||
if (direction != Vector3.Zero)
|
||||
{
|
||||
velocity.X = direction.X * Speed;
|
||||
velocity.Z = direction.Z * Speed;
|
||||
}
|
||||
else
|
||||
{
|
||||
velocity.X = Mathf.MoveToward(Velocity.X, 0, Speed);
|
||||
velocity.Z = Mathf.MoveToward(Velocity.Z, 0, Speed);
|
||||
}
|
||||
|
||||
Velocity = velocity;
|
||||
MoveAndSlide();
|
||||
}
|
||||
Velocity = velocity;
|
||||
MoveAndSlide();
|
||||
}
|
||||
}
|
||||
|
||||
125
src/app/App.cs
125
src/app/App.cs
@@ -3,78 +3,77 @@ using Chickensoft.GodotNodeInterfaces;
|
||||
using Chickensoft.Introspection;
|
||||
using Godot;
|
||||
|
||||
namespace GameJamDungeon
|
||||
namespace GameJamDungeon;
|
||||
|
||||
public interface IApp : ICanvasLayer, IProvide<IAppRepo>;
|
||||
|
||||
[Meta(typeof(IAutoNode))]
|
||||
public partial class App : CanvasLayer, IApp
|
||||
{
|
||||
public interface IApp : ICanvasLayer, IProvide<IAppRepo>;
|
||||
public override void _Notification(int what) => this.Notify(what);
|
||||
|
||||
[Meta(typeof(IAutoNode))]
|
||||
public partial class App : CanvasLayer, IApp
|
||||
public const string GAME_SCENE_PATH = "res://src/game/Game.tscn";
|
||||
|
||||
public IGame Game { get; set; } = default!;
|
||||
|
||||
public IInstantiator Instantiator { get; set; } = default!;
|
||||
|
||||
IAppRepo IProvide<IAppRepo>.Value() => AppRepo;
|
||||
|
||||
public IAppRepo AppRepo { get; set; } = default!;
|
||||
public IAppLogic AppLogic { get; set; } = default!;
|
||||
public AppLogic.IBinding AppBinding { get; set; } = default!;
|
||||
|
||||
[Node] public IMenu Menu { get; set; } = default!;
|
||||
|
||||
[Node] public ISubViewport GameWindow { get; set; } = default!;
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
public override void _Notification(int what) => this.Notify(what);
|
||||
Instantiator = new Instantiator(GetTree());
|
||||
AppRepo = new AppRepo();
|
||||
AppLogic = new AppLogic();
|
||||
AppLogic.Set(AppRepo);
|
||||
Menu.NewGame += OnNewGame;
|
||||
Menu.Quit += OnQuit;
|
||||
Input.MouseMode = Input.MouseModeEnum.Visible;
|
||||
this.Provide();
|
||||
}
|
||||
|
||||
public const string GAME_SCENE_PATH = "res://src/game/Game.tscn";
|
||||
public void OnReady()
|
||||
{
|
||||
AppBinding = AppLogic.Bind();
|
||||
|
||||
public IGame Game { get; set; } = default!;
|
||||
|
||||
public IInstantiator Instantiator { get; set; } = default!;
|
||||
|
||||
IAppRepo IProvide<IAppRepo>.Value() => AppRepo;
|
||||
|
||||
public IAppRepo AppRepo { get; set; } = default!;
|
||||
public IAppLogic AppLogic { get; set; } = default!;
|
||||
public AppLogic.IBinding AppBinding { get; set; } = default!;
|
||||
|
||||
[Node] public IMenu Menu { get; set; } = default!;
|
||||
|
||||
[Node] public ISubViewport GameWindow { get; set; } = default!;
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
Instantiator = new Instantiator(GetTree());
|
||||
AppRepo = new AppRepo();
|
||||
AppLogic = new AppLogic();
|
||||
AppLogic.Set(AppRepo);
|
||||
Menu.NewGame += OnNewGame;
|
||||
Menu.Quit += OnQuit;
|
||||
Input.MouseMode = Input.MouseModeEnum.Visible;
|
||||
this.Provide();
|
||||
}
|
||||
|
||||
public void OnReady()
|
||||
{
|
||||
AppBinding = AppLogic.Bind();
|
||||
|
||||
AppBinding
|
||||
.Handle((in AppLogic.Output.ShowLoadingScreen _) =>
|
||||
{
|
||||
Menu.Hide();
|
||||
})
|
||||
.Handle((in AppLogic.Output.SetupGameScene _) =>
|
||||
{
|
||||
Menu.Hide();
|
||||
Instantiator.SceneTree.Paused = true;
|
||||
Game = Instantiator.LoadAndInstantiate<Game>(GAME_SCENE_PATH);
|
||||
GameWindow.AddChildEx(Game);
|
||||
})
|
||||
.Handle((in AppLogic.Output.ShowGame _) =>
|
||||
{
|
||||
Instantiator.SceneTree.Paused = false;
|
||||
Game.Show();
|
||||
});
|
||||
AppBinding
|
||||
.Handle((in AppLogic.Output.ShowLoadingScreen _) =>
|
||||
{
|
||||
Menu.Hide();
|
||||
})
|
||||
.Handle((in AppLogic.Output.SetupGameScene _) =>
|
||||
{
|
||||
Menu.Hide();
|
||||
Instantiator.SceneTree.Paused = true;
|
||||
Game = Instantiator.LoadAndInstantiate<Game>(GAME_SCENE_PATH);
|
||||
GameWindow.AddChildEx(Game);
|
||||
})
|
||||
.Handle((in AppLogic.Output.ShowGame _) =>
|
||||
{
|
||||
Instantiator.SceneTree.Paused = false;
|
||||
Game.Show();
|
||||
});
|
||||
|
||||
|
||||
AppLogic.Start();
|
||||
}
|
||||
AppLogic.Start();
|
||||
}
|
||||
|
||||
public void OnNewGame() => AppLogic.Input(new AppLogic.Input.NewGame());
|
||||
public void OnNewGame() => AppLogic.Input(new AppLogic.Input.NewGame());
|
||||
|
||||
public void OnQuit() => AppLogic.Input(new AppLogic.Input.QuitGame());
|
||||
public void OnQuit() => AppLogic.Input(new AppLogic.Input.QuitGame());
|
||||
|
||||
public void OnExitTree()
|
||||
{
|
||||
AppLogic.Stop();
|
||||
AppBinding.Dispose();
|
||||
AppRepo.Dispose();
|
||||
}
|
||||
public void OnExitTree()
|
||||
{
|
||||
AppLogic.Stop();
|
||||
AppBinding.Dispose();
|
||||
AppRepo.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,77 +1,76 @@
|
||||
using System;
|
||||
|
||||
namespace GameJamDungeon
|
||||
namespace GameJamDungeon;
|
||||
|
||||
public interface IAppRepo : IDisposable
|
||||
{
|
||||
public interface IAppRepo : IDisposable
|
||||
event Action? GameEntered;
|
||||
|
||||
event Action? GameExited;
|
||||
|
||||
event Action? SplashScreenSkipped;
|
||||
|
||||
event Action? MainMenuEntered;
|
||||
|
||||
event Action? ShowLoadingScreen;
|
||||
|
||||
void SkipSplashScreen();
|
||||
|
||||
void OnMainMenuEntered();
|
||||
|
||||
void OnEnterGame();
|
||||
|
||||
void OnExitGame();
|
||||
|
||||
void OnGameOver();
|
||||
|
||||
void OnShowLoadingScreen();
|
||||
|
||||
}
|
||||
|
||||
public class AppRepo : IAppRepo
|
||||
{
|
||||
public event Action? SplashScreenSkipped;
|
||||
public event Action? MainMenuEntered;
|
||||
public event Action? GameEntered;
|
||||
public event Action? GameExited;
|
||||
public event Action? ShowLoadingScreen;
|
||||
|
||||
private bool _disposedValue;
|
||||
|
||||
public void SkipSplashScreen() => SplashScreenSkipped?.Invoke();
|
||||
|
||||
public void OnMainMenuEntered() => MainMenuEntered?.Invoke();
|
||||
|
||||
public void OnEnterGame() => GameEntered?.Invoke();
|
||||
|
||||
public void OnExitGame() => GameExited?.Invoke();
|
||||
|
||||
public void OnGameOver() => GameExited?.Invoke();
|
||||
|
||||
public void OnShowLoadingScreen() => ShowLoadingScreen?.Invoke();
|
||||
|
||||
protected void Dispose(bool disposing)
|
||||
{
|
||||
event Action? GameEntered;
|
||||
|
||||
event Action? GameExited;
|
||||
|
||||
event Action? SplashScreenSkipped;
|
||||
|
||||
event Action? MainMenuEntered;
|
||||
|
||||
event Action? ShowLoadingScreen;
|
||||
|
||||
void SkipSplashScreen();
|
||||
|
||||
void OnMainMenuEntered();
|
||||
|
||||
void OnEnterGame();
|
||||
|
||||
void OnExitGame();
|
||||
|
||||
void OnGameOver();
|
||||
|
||||
void OnShowLoadingScreen();
|
||||
if (!_disposedValue)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
// Dispose managed objects.
|
||||
SplashScreenSkipped = null;
|
||||
MainMenuEntered = null;
|
||||
GameEntered = null;
|
||||
GameExited = null;
|
||||
ShowLoadingScreen = null;
|
||||
}
|
||||
|
||||
_disposedValue = true;
|
||||
}
|
||||
}
|
||||
|
||||
public class AppRepo : IAppRepo
|
||||
public void Dispose()
|
||||
{
|
||||
public event Action? SplashScreenSkipped;
|
||||
public event Action? MainMenuEntered;
|
||||
public event Action? GameEntered;
|
||||
public event Action? GameExited;
|
||||
public event Action? ShowLoadingScreen;
|
||||
|
||||
private bool _disposedValue;
|
||||
|
||||
public void SkipSplashScreen() => SplashScreenSkipped?.Invoke();
|
||||
|
||||
public void OnMainMenuEntered() => MainMenuEntered?.Invoke();
|
||||
|
||||
public void OnEnterGame() => GameEntered?.Invoke();
|
||||
|
||||
public void OnExitGame() => GameExited?.Invoke();
|
||||
|
||||
public void OnGameOver() => GameExited?.Invoke();
|
||||
|
||||
public void OnShowLoadingScreen() => ShowLoadingScreen?.Invoke();
|
||||
|
||||
protected void Dispose(bool disposing)
|
||||
{
|
||||
if (!_disposedValue)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
// Dispose managed objects.
|
||||
SplashScreenSkipped = null;
|
||||
MainMenuEntered = null;
|
||||
GameEntered = null;
|
||||
GameExited = null;
|
||||
ShowLoadingScreen = null;
|
||||
}
|
||||
|
||||
_disposedValue = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(disposing: true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
Dispose(disposing: true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,20 +1,19 @@
|
||||
namespace GameJamDungeon
|
||||
namespace GameJamDungeon;
|
||||
|
||||
public partial class AppLogic
|
||||
{
|
||||
public partial class AppLogic
|
||||
public static class Input
|
||||
{
|
||||
public static class Input
|
||||
{
|
||||
public readonly record struct NewGame;
|
||||
public readonly record struct NewGame;
|
||||
|
||||
public readonly record struct LoadGameFinished;
|
||||
public readonly record struct LoadGameFinished;
|
||||
|
||||
public readonly record struct FadeOutFinished;
|
||||
public readonly record struct FadeOutFinished;
|
||||
|
||||
public readonly record struct QuitGame;
|
||||
public readonly record struct QuitGame;
|
||||
|
||||
public readonly record struct GameOver;
|
||||
public readonly record struct GameOver;
|
||||
|
||||
public readonly record struct ShowLoadingScreen;
|
||||
}
|
||||
public readonly record struct ShowLoadingScreen;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,32 +1,31 @@
|
||||
namespace GameJamDungeon
|
||||
namespace GameJamDungeon;
|
||||
|
||||
public partial class AppLogic
|
||||
{
|
||||
public partial class AppLogic
|
||||
public static class Output
|
||||
{
|
||||
public static class Output
|
||||
{
|
||||
public readonly record struct FadeToBlack;
|
||||
public readonly record struct FadeToBlack;
|
||||
|
||||
public readonly record struct ShowSplashScreen;
|
||||
public readonly record struct ShowSplashScreen;
|
||||
|
||||
public readonly record struct HideSplashScreen;
|
||||
public readonly record struct HideSplashScreen;
|
||||
|
||||
public readonly record struct RemoveExistingGame;
|
||||
public readonly record struct RemoveExistingGame;
|
||||
|
||||
public readonly record struct PlayGame;
|
||||
public readonly record struct PlayGame;
|
||||
|
||||
public readonly record struct ShowGame;
|
||||
public readonly record struct ShowGame;
|
||||
|
||||
public readonly record struct HideGame;
|
||||
public readonly record struct HideGame;
|
||||
|
||||
public readonly record struct SetupGameScene;
|
||||
public readonly record struct SetupGameScene;
|
||||
|
||||
public readonly record struct ShowLoadingScreen;
|
||||
public readonly record struct ShowLoadingScreen;
|
||||
|
||||
public readonly record struct ShowMainMenu;
|
||||
public readonly record struct ShowMainMenu;
|
||||
|
||||
public readonly record struct ExitGame;
|
||||
public readonly record struct ExitGame;
|
||||
|
||||
public readonly record struct GameOver;
|
||||
}
|
||||
public readonly record struct GameOver;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
using Chickensoft.Introspection;
|
||||
using Chickensoft.LogicBlocks;
|
||||
|
||||
namespace GameJamDungeon
|
||||
namespace GameJamDungeon;
|
||||
|
||||
public partial class AppLogic
|
||||
{
|
||||
public partial class AppLogic
|
||||
{
|
||||
[Meta]
|
||||
public abstract partial record State : StateLogic<State>;
|
||||
}
|
||||
[Meta]
|
||||
public abstract partial record State : StateLogic<State>;
|
||||
}
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
using Chickensoft.Introspection;
|
||||
using Chickensoft.LogicBlocks;
|
||||
|
||||
namespace GameJamDungeon
|
||||
{
|
||||
public interface IAppLogic : ILogicBlock<AppLogic.State>;
|
||||
namespace GameJamDungeon;
|
||||
|
||||
[Meta]
|
||||
[LogicBlock(typeof(State), Diagram = true)]
|
||||
public partial class AppLogic : LogicBlock<AppLogic.State>, IAppLogic
|
||||
{
|
||||
public override Transition GetInitialState() => To<State.SetupGameScene>();
|
||||
}
|
||||
public interface IAppLogic : ILogicBlock<AppLogic.State>;
|
||||
|
||||
[Meta]
|
||||
[LogicBlock(typeof(State), Diagram = true)]
|
||||
public partial class AppLogic : LogicBlock<AppLogic.State>, IAppLogic
|
||||
{
|
||||
public override Transition GetInitialState() => To<State.SetupGameScene>();
|
||||
}
|
||||
|
||||
@@ -1,29 +1,28 @@
|
||||
using Chickensoft.Introspection;
|
||||
using Chickensoft.LogicBlocks;
|
||||
|
||||
namespace GameJamDungeon
|
||||
{
|
||||
public partial class AppLogic
|
||||
{
|
||||
public partial record State
|
||||
{
|
||||
[Meta]
|
||||
public partial record SetupGameScene : State, IGet<Input.LoadGameFinished>
|
||||
{
|
||||
public SetupGameScene()
|
||||
{
|
||||
this.OnEnter(() =>
|
||||
{
|
||||
Output(new Output.SetupGameScene());
|
||||
Output(new Output.ShowGame());
|
||||
Input(new Input.LoadGameFinished());
|
||||
});
|
||||
}
|
||||
namespace GameJamDungeon;
|
||||
|
||||
public Transition On(in Input.LoadGameFinished input)
|
||||
public partial class AppLogic
|
||||
{
|
||||
public partial record State
|
||||
{
|
||||
[Meta]
|
||||
public partial record SetupGameScene : State, IGet<Input.LoadGameFinished>
|
||||
{
|
||||
public SetupGameScene()
|
||||
{
|
||||
this.OnEnter(() =>
|
||||
{
|
||||
return To<InGame>();
|
||||
}
|
||||
Output(new Output.SetupGameScene());
|
||||
Output(new Output.ShowGame());
|
||||
Input(new Input.LoadGameFinished());
|
||||
});
|
||||
}
|
||||
|
||||
public Transition On(in Input.LoadGameFinished input)
|
||||
{
|
||||
return To<InGame>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,37 +1,36 @@
|
||||
using Chickensoft.Introspection;
|
||||
using Chickensoft.LogicBlocks;
|
||||
|
||||
namespace GameJamDungeon
|
||||
namespace GameJamDungeon;
|
||||
|
||||
public partial class AppLogic
|
||||
{
|
||||
public partial class AppLogic
|
||||
public partial record State
|
||||
{
|
||||
public partial record State
|
||||
[Meta]
|
||||
public partial record InGame : State, IGet<Input.GameOver>
|
||||
{
|
||||
[Meta]
|
||||
public partial record InGame : State, IGet<Input.GameOver>
|
||||
public InGame()
|
||||
{
|
||||
public InGame()
|
||||
|
||||
this.OnEnter(() =>
|
||||
{
|
||||
Get<IAppRepo>().OnEnterGame();
|
||||
Output(new Output.ShowGame());
|
||||
});
|
||||
this.OnExit(() => Output(new Output.HideGame()));
|
||||
|
||||
this.OnEnter(() =>
|
||||
{
|
||||
Get<IAppRepo>().OnEnterGame();
|
||||
Output(new Output.ShowGame());
|
||||
});
|
||||
this.OnExit(() => Output(new Output.HideGame()));
|
||||
|
||||
OnAttach(() => Get<IAppRepo>().GameExited += OnGameExited);
|
||||
OnDetach(() => Get<IAppRepo>().GameExited -= OnGameExited);
|
||||
}
|
||||
|
||||
public Transition On(in Input.GameOver input)
|
||||
{
|
||||
Output(new Output.RemoveExistingGame());
|
||||
return To<MainMenu>();
|
||||
}
|
||||
|
||||
public void OnGameExited() => Input(new Input.GameOver());
|
||||
OnAttach(() => Get<IAppRepo>().GameExited += OnGameExited);
|
||||
OnDetach(() => Get<IAppRepo>().GameExited -= OnGameExited);
|
||||
}
|
||||
|
||||
public Transition On(in Input.GameOver input)
|
||||
{
|
||||
Output(new Output.RemoveExistingGame());
|
||||
return To<MainMenu>();
|
||||
}
|
||||
|
||||
public void OnGameExited() => Input(new Input.GameOver());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,34 +1,33 @@
|
||||
using Chickensoft.Introspection;
|
||||
using Chickensoft.LogicBlocks;
|
||||
|
||||
namespace GameJamDungeon
|
||||
{
|
||||
public partial class AppLogic
|
||||
{
|
||||
public partial record State
|
||||
{
|
||||
[Meta]
|
||||
public partial record MainMenu : State, IGet<Input.NewGame>, IGet<Input.QuitGame>
|
||||
{
|
||||
public MainMenu()
|
||||
{
|
||||
this.OnEnter(() =>
|
||||
{
|
||||
Get<IAppRepo>().OnMainMenuEntered();
|
||||
Output(new Output.ShowMainMenu());
|
||||
});
|
||||
}
|
||||
public Transition On(in Input.NewGame input)
|
||||
{
|
||||
Output(new Output.SetupGameScene());
|
||||
return To<LoadingScreen>();
|
||||
}
|
||||
namespace GameJamDungeon;
|
||||
|
||||
public Transition On(in Input.QuitGame input)
|
||||
public partial class AppLogic
|
||||
{
|
||||
public partial record State
|
||||
{
|
||||
[Meta]
|
||||
public partial record MainMenu : State, IGet<Input.NewGame>, IGet<Input.QuitGame>
|
||||
{
|
||||
public MainMenu()
|
||||
{
|
||||
this.OnEnter(() =>
|
||||
{
|
||||
Output(new Output.ExitGame());
|
||||
return ToSelf();
|
||||
}
|
||||
Get<IAppRepo>().OnMainMenuEntered();
|
||||
Output(new Output.ShowMainMenu());
|
||||
});
|
||||
}
|
||||
public Transition On(in Input.NewGame input)
|
||||
{
|
||||
Output(new Output.SetupGameScene());
|
||||
return To<LoadingScreen>();
|
||||
}
|
||||
|
||||
public Transition On(in Input.QuitGame input)
|
||||
{
|
||||
Output(new Output.ExitGame());
|
||||
return ToSelf();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,34 +1,33 @@
|
||||
namespace GameJamDungeon
|
||||
namespace GameJamDungeon;
|
||||
|
||||
public partial class InGameAudioLogic
|
||||
{
|
||||
public partial class InGameAudioLogic
|
||||
public static class Output
|
||||
{
|
||||
public static class Output
|
||||
{
|
||||
#region BGM
|
||||
public readonly record struct PlayOverworldMusic;
|
||||
#region BGM
|
||||
public readonly record struct PlayOverworldMusic;
|
||||
|
||||
public readonly record struct PlayDungeonThemeAMusic;
|
||||
#endregion
|
||||
public readonly record struct PlayDungeonThemeAMusic;
|
||||
#endregion
|
||||
|
||||
#region SFX
|
||||
public readonly record struct PlayPlayerAttackSound;
|
||||
#region SFX
|
||||
public readonly record struct PlayPlayerAttackSound;
|
||||
|
||||
public readonly record struct PlayMenuScrollSound;
|
||||
public readonly record struct PlayMenuScrollSound;
|
||||
|
||||
public readonly record struct PlayEquipSound;
|
||||
public readonly record struct PlayEquipSound;
|
||||
|
||||
public readonly record struct PlayInventorySortedSound;
|
||||
public readonly record struct PlayInventorySortedSound;
|
||||
|
||||
public readonly record struct PlayMenuBackSound;
|
||||
public readonly record struct PlayMenuBackSound;
|
||||
|
||||
public readonly record struct PlayHealingItemSound;
|
||||
public readonly record struct PlayHealingItemSound;
|
||||
|
||||
public readonly record struct PlayTeleportSound;
|
||||
#endregion
|
||||
public readonly record struct PlayTeleportSound;
|
||||
#endregion
|
||||
|
||||
public readonly record struct PlayGameMusic;
|
||||
public readonly record struct PlayGameMusic;
|
||||
|
||||
public readonly record struct StopGameMusic;
|
||||
}
|
||||
public readonly record struct StopGameMusic;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
using Chickensoft.Introspection;
|
||||
using Chickensoft.LogicBlocks;
|
||||
using System;
|
||||
|
||||
namespace GameJamDungeon;
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using Chickensoft.Introspection;
|
||||
using Chickensoft.LogicBlocks;
|
||||
|
||||
namespace GameJamDungeon;
|
||||
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
using Chickensoft.Introspection;
|
||||
using Chickensoft.LogicBlocks;
|
||||
using System;
|
||||
|
||||
namespace GameJamDungeon;
|
||||
|
||||
|
||||
260
src/boss/Boss.cs
260
src/boss/Boss.cs
@@ -4,151 +4,149 @@ using Chickensoft.GodotNodeInterfaces;
|
||||
using Chickensoft.Introspection;
|
||||
using Godot;
|
||||
|
||||
namespace GameJamDungeon
|
||||
namespace GameJamDungeon;
|
||||
|
||||
public interface IBoss : ICharacterBody3D
|
||||
{
|
||||
public interface IBoss : ICharacterBody3D
|
||||
public AnimationTree AnimationTree { get; }
|
||||
|
||||
public AnimationPlayer HitAnimation { get; }
|
||||
|
||||
public Timer AttackTimer { get; }
|
||||
|
||||
public void Activate();
|
||||
|
||||
public AutoProp<double> CurrentHP { get; }
|
||||
}
|
||||
|
||||
[Meta(typeof(IAutoNode))]
|
||||
public partial class Boss : CharacterBody3D, IBoss, IProvide<IBossLogic>
|
||||
{
|
||||
public override void _Notification(int what) => this.Notify(what);
|
||||
|
||||
public IBossLogic BossLogic { get; set; } = default!;
|
||||
|
||||
[Export] public EnemyStatResource BossResource { get; set; } = default!;
|
||||
|
||||
IBossLogic IProvide<IBossLogic>.Value() => BossLogic;
|
||||
|
||||
public BossLogic.IBinding BossBinding { get; set; } = default!;
|
||||
|
||||
[Dependency] public IGameRepo GameRepo => this.DependOn<IGameRepo>();
|
||||
|
||||
[Dependency] public IGameEventDepot GameEventDepot => this.DependOn<IGameEventDepot>();
|
||||
|
||||
[Dependency] public IGame Game => this.DependOn<IGame>();
|
||||
|
||||
[Dependency] public IPlayer Player => this.DependOn<IPlayer>();
|
||||
|
||||
[Node] public AnimationTree AnimationTree { get; set; } = default!;
|
||||
|
||||
[Node] public Timer AttackTimer { get; set; } = default!;
|
||||
|
||||
[Node] public AnimationPlayer HitAnimation { get; set; } = default!;
|
||||
|
||||
[Node] public Area3D Hitbox { get; set; } = default!;
|
||||
|
||||
[Node] public Area3D AttackBox { get; set; } = default!;
|
||||
|
||||
[Node] public Area3D SecondaryAttackBox { get; set; } = default!;
|
||||
|
||||
public AutoProp<double> CurrentHP { get; set; }
|
||||
|
||||
public void Setup()
|
||||
{
|
||||
public AnimationTree AnimationTree { get; }
|
||||
BossLogic = new BossLogic();
|
||||
BossLogic.Set(this as IBoss);
|
||||
BossLogic.Set(GameRepo);
|
||||
|
||||
public AnimationPlayer HitAnimation { get; }
|
||||
|
||||
public Timer AttackTimer { get; }
|
||||
|
||||
public void Activate();
|
||||
|
||||
public AutoProp<double> CurrentHP { get; }
|
||||
SetPhysicsProcess(false);
|
||||
Hide();
|
||||
}
|
||||
|
||||
[Meta(typeof(IAutoNode))]
|
||||
public partial class Boss : CharacterBody3D, IBoss, IProvide<IBossLogic>
|
||||
public void OnResolved()
|
||||
{
|
||||
public override void _Notification(int what) => this.Notify(what);
|
||||
|
||||
public IBossLogic BossLogic { get; set; } = default!;
|
||||
|
||||
[Export] public EnemyStatResource BossResource { get; set; } = default!;
|
||||
|
||||
IBossLogic IProvide<IBossLogic>.Value() => BossLogic;
|
||||
|
||||
public BossLogic.IBinding BossBinding { get; set; } = default!;
|
||||
|
||||
[Dependency] public IGameRepo GameRepo => this.DependOn<IGameRepo>();
|
||||
|
||||
[Dependency] public IGameEventDepot GameEventDepot => this.DependOn<IGameEventDepot>();
|
||||
|
||||
[Dependency] public IGame Game => this.DependOn<IGame>();
|
||||
|
||||
[Node] public AnimationTree AnimationTree { get; set; } = default!;
|
||||
|
||||
[Node] public Timer AttackTimer { get; set; } = default!;
|
||||
|
||||
[Node] public AnimationPlayer HitAnimation { get; set; } = default!;
|
||||
|
||||
[Node] public Area3D Hitbox { get; set; } = default!;
|
||||
|
||||
[Node] public Area3D AttackBox { get; set; } = default!;
|
||||
|
||||
[Node] public Area3D SecondaryAttackBox { get; set; } = default!;
|
||||
|
||||
public AutoProp<double> CurrentHP { get; set; }
|
||||
|
||||
public void Setup()
|
||||
BossBinding = BossLogic.Bind();
|
||||
BossBinding
|
||||
.Handle((in BossLogic.Output.Defeated output) =>
|
||||
{
|
||||
BossLogic = new BossLogic();
|
||||
BossLogic.Set(this as IBoss);
|
||||
BossLogic.Set(GameRepo);
|
||||
HitAnimation.Play("Defeated");
|
||||
});
|
||||
this.Provide();
|
||||
BossLogic.Start();
|
||||
CurrentHP = new AutoProp<double>(BossResource.MaximumHP);
|
||||
CurrentHP.Sync += OnHPChanged;
|
||||
AttackTimer.Timeout += AttackTimer_Timeout;
|
||||
Hitbox.AreaEntered += Hitbox_AreaEntered;
|
||||
HitAnimation.AnimationFinished += HitAnimation_AnimationFinished;
|
||||
AttackBox.AreaEntered += AttackBox_AreaEntered;
|
||||
SecondaryAttackBox.AreaEntered += SecondaryAttackBox_AreaEntered;
|
||||
}
|
||||
|
||||
SetPhysicsProcess(false);
|
||||
Hide();
|
||||
}
|
||||
private void AttackBox_AreaEntered(Area3D area)
|
||||
{
|
||||
//var bossHitDamage = DamageCalculator.CalculateEnemyAttackDamage(GameRepo.PlayerData.CurrentDefense.Value + GameRepo.PlayerData.BonusDefense,
|
||||
// BossResource,
|
||||
// GameRepo.PlayerData.Inventory.EquippedArmor.Value.ArmorStats,
|
||||
// false);
|
||||
//GameRepo.PlayerData.SetCurrentHP(GameRepo.PlayerData.CurrentHP.Value - Mathf.RoundToInt(bossHitDamage));
|
||||
}
|
||||
|
||||
public void OnResolved()
|
||||
private void SecondaryAttackBox_AreaEntered(Area3D area)
|
||||
{
|
||||
//var bossHitDamage = DamageCalculator.CalculateEnemyAttackDamage(GameRepo.PlayerData.CurrentDefense.Value + GameRepo.PlayerData.BonusDefense,
|
||||
// BossResource,
|
||||
// GameRepo.PlayerData.Inventory.EquippedArmor.Value.ArmorStats,
|
||||
// false);
|
||||
//var nerfDamage = bossHitDamage *= 0.25f;
|
||||
//GameRepo.PlayerData.SetCurrentHP(GameRepo.PlayerData.CurrentHP.Value - Mathf.RoundToInt(nerfDamage));
|
||||
Player.Knockback(115f);
|
||||
}
|
||||
|
||||
private void HitAnimation_AnimationFinished(StringName animName)
|
||||
{
|
||||
if (animName == "Defeated")
|
||||
QueueFree();
|
||||
}
|
||||
|
||||
private void Hitbox_AreaEntered(Area3D area)
|
||||
{
|
||||
if (area is IHitbox)
|
||||
{
|
||||
BossBinding = BossLogic.Bind();
|
||||
BossBinding
|
||||
.Handle((in BossLogic.Output.Defeated output) =>
|
||||
{
|
||||
HitAnimation.Play("Defeated");
|
||||
});
|
||||
this.Provide();
|
||||
BossLogic.Start();
|
||||
CurrentHP = new AutoProp<double>(BossResource.MaximumHP);
|
||||
CurrentHP.Sync += OnHPChanged;
|
||||
AttackTimer.Timeout += AttackTimer_Timeout;
|
||||
Hitbox.AreaEntered += Hitbox_AreaEntered;
|
||||
HitAnimation.AnimationFinished += HitAnimation_AnimationFinished;
|
||||
AttackBox.AreaEntered += AttackBox_AreaEntered;
|
||||
SecondaryAttackBox.AreaEntered += SecondaryAttackBox_AreaEntered;
|
||||
var isCriticalHit = false;
|
||||
var rng = new RandomNumberGenerator();
|
||||
rng.Randomize();
|
||||
var roll = rng.Randf();
|
||||
if (roll <= Player.Inventory.EquippedWeapon.Value.Luck)
|
||||
isCriticalHit = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void AttackBox_AreaEntered(Area3D area)
|
||||
{
|
||||
//var bossHitDamage = DamageCalculator.CalculateEnemyAttackDamage(GameRepo.PlayerData.CurrentDefense.Value + GameRepo.PlayerData.BonusDefense,
|
||||
// BossResource,
|
||||
// GameRepo.PlayerData.Inventory.EquippedArmor.Value.ArmorStats,
|
||||
// false);
|
||||
//GameRepo.PlayerData.SetCurrentHP(GameRepo.PlayerData.CurrentHP.Value - Mathf.RoundToInt(bossHitDamage));
|
||||
}
|
||||
public void Activate()
|
||||
{
|
||||
BossLogic.Input(new BossLogic.Input.Activate());
|
||||
}
|
||||
|
||||
private void SecondaryAttackBox_AreaEntered(Area3D area)
|
||||
{
|
||||
//var bossHitDamage = DamageCalculator.CalculateEnemyAttackDamage(GameRepo.PlayerData.CurrentDefense.Value + GameRepo.PlayerData.BonusDefense,
|
||||
// BossResource,
|
||||
// GameRepo.PlayerData.Inventory.EquippedArmor.Value.ArmorStats,
|
||||
// false);
|
||||
//var nerfDamage = bossHitDamage *= 0.25f;
|
||||
//GameRepo.PlayerData.SetCurrentHP(GameRepo.PlayerData.CurrentHP.Value - Mathf.RoundToInt(nerfDamage));
|
||||
Game.Player.ApplyCentralImpulseToPlayer(GlobalBasis.Z.Normalized());
|
||||
}
|
||||
private void AttackTimer_Timeout()
|
||||
{
|
||||
var random = new RandomNumberGenerator();
|
||||
random.Randomize();
|
||||
var selection = random.RandWeighted([0.2f, 0.8f]);
|
||||
if (selection == 0)
|
||||
BossLogic.Input(new BossLogic.Input.SecondaryAttack());
|
||||
else
|
||||
BossLogic.Input(new BossLogic.Input.PrimaryAttack());
|
||||
}
|
||||
|
||||
private void HitAnimation_AnimationFinished(StringName animName)
|
||||
{
|
||||
if (animName == "Defeated")
|
||||
QueueFree();
|
||||
}
|
||||
public void OnPhysicsProcess(double delta)
|
||||
{
|
||||
BossLogic.Input(new BossLogic.Input.PhysicsTick(delta));
|
||||
MoveAndSlide();
|
||||
}
|
||||
|
||||
private void Hitbox_AreaEntered(Area3D area)
|
||||
{
|
||||
if (area is IHitbox)
|
||||
{
|
||||
var isCriticalHit = false;
|
||||
var rng = new RandomNumberGenerator();
|
||||
rng.Randomize();
|
||||
var roll = rng.Randf();
|
||||
if (roll <= GameRepo.PlayerData.Inventory.EquippedWeapon.Value.WeaponStats.Luck)
|
||||
isCriticalHit = true;
|
||||
//var damage = DamageCalculator.CalculateWeaponAttackDamage(GameRepo.PlayerData.CurrentAttack.Value + GameRepo.PlayerData.BonusAttack, BossResource, GameRepo.PlayerData.Inventory.EquippedWeapon.Value.WeaponStats, isCriticalHit);
|
||||
//GD.Print($"Enemy Hit for {damage} damage.");
|
||||
//BossLogic.Input(new BossLogic.Input.HitByPlayer(damage));
|
||||
}
|
||||
}
|
||||
|
||||
public void Activate()
|
||||
{
|
||||
BossLogic.Input(new BossLogic.Input.Activate());
|
||||
}
|
||||
|
||||
private void AttackTimer_Timeout()
|
||||
{
|
||||
var random = new RandomNumberGenerator();
|
||||
random.Randomize();
|
||||
var selection = random.RandWeighted([0.2f, 0.8f]);
|
||||
if (selection == 0)
|
||||
BossLogic.Input(new BossLogic.Input.SecondaryAttack());
|
||||
else
|
||||
BossLogic.Input(new BossLogic.Input.PrimaryAttack());
|
||||
}
|
||||
|
||||
public void OnPhysicsProcess(double delta)
|
||||
{
|
||||
BossLogic.Input(new BossLogic.Input.PhysicsTick(delta));
|
||||
MoveAndSlide();
|
||||
}
|
||||
|
||||
private void OnHPChanged(double newHP)
|
||||
{
|
||||
if (newHP <= 0)
|
||||
BossLogic.Input(new BossLogic.Input.BossDefeated());
|
||||
}
|
||||
private void OnHPChanged(double newHP)
|
||||
{
|
||||
if (newHP <= 0)
|
||||
BossLogic.Input(new BossLogic.Input.BossDefeated());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,20 +1,19 @@
|
||||
namespace GameJamDungeon
|
||||
namespace GameJamDungeon;
|
||||
|
||||
public partial class BossLogic
|
||||
{
|
||||
public partial class BossLogic
|
||||
public static class Input
|
||||
{
|
||||
public static class Input
|
||||
{
|
||||
public readonly record struct Activate();
|
||||
public readonly record struct Activate();
|
||||
|
||||
public readonly record struct PhysicsTick(double Delta);
|
||||
public readonly record struct PhysicsTick(double Delta);
|
||||
|
||||
public readonly record struct PrimaryAttack();
|
||||
public readonly record struct PrimaryAttack();
|
||||
|
||||
public readonly record struct SecondaryAttack();
|
||||
public readonly record struct SecondaryAttack();
|
||||
|
||||
public readonly record struct HitByPlayer(double Damage);
|
||||
public readonly record struct HitByPlayer(double Damage);
|
||||
|
||||
public readonly record struct BossDefeated();
|
||||
}
|
||||
public readonly record struct BossDefeated();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
namespace GameJamDungeon
|
||||
{
|
||||
public partial class BossLogic
|
||||
{
|
||||
public static class Output
|
||||
{
|
||||
public readonly record struct HitByPlayer(double CurrentHP);
|
||||
namespace GameJamDungeon;
|
||||
|
||||
public readonly record struct Defeated();
|
||||
}
|
||||
public partial class BossLogic
|
||||
{
|
||||
public static class Output
|
||||
{
|
||||
public readonly record struct HitByPlayer(double CurrentHP);
|
||||
|
||||
public readonly record struct Defeated();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,16 +1,15 @@
|
||||
using Chickensoft.Introspection;
|
||||
using Chickensoft.LogicBlocks;
|
||||
|
||||
namespace GameJamDungeon
|
||||
namespace GameJamDungeon;
|
||||
|
||||
public partial class BossLogic
|
||||
{
|
||||
public partial class BossLogic
|
||||
[Meta]
|
||||
public abstract partial record State : StateLogic<State>
|
||||
{
|
||||
[Meta]
|
||||
public abstract partial record State : StateLogic<State>
|
||||
protected State()
|
||||
{
|
||||
protected State()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
using Chickensoft.Introspection;
|
||||
using Chickensoft.LogicBlocks;
|
||||
|
||||
namespace GameJamDungeon
|
||||
{
|
||||
public interface IBossLogic : ILogicBlock<BossLogic.State>;
|
||||
namespace GameJamDungeon;
|
||||
|
||||
[Meta, Id("boss_logic")]
|
||||
[LogicBlock(typeof(State), Diagram = true)]
|
||||
public partial class BossLogic : LogicBlock<BossLogic.State>, IBossLogic
|
||||
{
|
||||
public override Transition GetInitialState() => To<State.Idle>();
|
||||
}
|
||||
public interface IBossLogic : ILogicBlock<BossLogic.State>;
|
||||
|
||||
[Meta, Id("boss_logic")]
|
||||
[LogicBlock(typeof(State), Diagram = true)]
|
||||
public partial class BossLogic : LogicBlock<BossLogic.State>, IBossLogic
|
||||
{
|
||||
public override Transition GetInitialState() => To<State.Idle>();
|
||||
}
|
||||
|
||||
@@ -1,32 +1,31 @@
|
||||
using Chickensoft.Introspection;
|
||||
using Godot;
|
||||
|
||||
namespace GameJamDungeon
|
||||
namespace GameJamDungeon;
|
||||
|
||||
public partial class BossLogic
|
||||
{
|
||||
public partial class BossLogic
|
||||
public partial record State
|
||||
{
|
||||
public partial record State
|
||||
[Meta, Id("boss_logic_state_alive")]
|
||||
public abstract partial record Alive : State, IGet<Input.HitByPlayer>, IGet<Input.BossDefeated>
|
||||
{
|
||||
[Meta, Id("boss_logic_state_alive")]
|
||||
public abstract partial record Alive : State, IGet<Input.HitByPlayer>, IGet<Input.BossDefeated>
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public Transition On(in Input.HitByPlayer input)
|
||||
{
|
||||
var enemy = Get<IBoss>();
|
||||
enemy.HitAnimation.Play("Hit");
|
||||
enemy.CurrentHP.OnNext(enemy.CurrentHP.Value - input.Damage);
|
||||
GD.Print("Current HP: " + enemy.CurrentHP.Value);
|
||||
Output(new Output.HitByPlayer());
|
||||
return ToSelf();
|
||||
}
|
||||
public Transition On(in Input.HitByPlayer input)
|
||||
{
|
||||
var enemy = Get<IBoss>();
|
||||
enemy.HitAnimation.Play("Hit");
|
||||
enemy.CurrentHP.OnNext(enemy.CurrentHP.Value - input.Damage);
|
||||
GD.Print("Current HP: " + enemy.CurrentHP.Value);
|
||||
Output(new Output.HitByPlayer());
|
||||
return ToSelf();
|
||||
}
|
||||
|
||||
public Transition On(in Input.BossDefeated input)
|
||||
{
|
||||
Output(new Output.Defeated());
|
||||
return To<Defeated>();
|
||||
}
|
||||
public Transition On(in Input.BossDefeated input)
|
||||
{
|
||||
Output(new Output.Defeated());
|
||||
return To<Defeated>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,34 +1,33 @@
|
||||
using Chickensoft.Introspection;
|
||||
using Godot;
|
||||
|
||||
namespace GameJamDungeon
|
||||
namespace GameJamDungeon;
|
||||
|
||||
public partial class BossLogic
|
||||
{
|
||||
public partial class BossLogic
|
||||
public partial record State
|
||||
{
|
||||
public partial record State
|
||||
[Meta, Id("boss_logic_state_approach_player")]
|
||||
public partial record ApproachPlayer : Alive, IGet<Input.PhysicsTick>
|
||||
{
|
||||
[Meta, Id("boss_logic_state_approach_player")]
|
||||
public partial record ApproachPlayer : Alive, IGet<Input.PhysicsTick>
|
||||
public Transition On(in Input.PhysicsTick input)
|
||||
{
|
||||
public Transition On(in Input.PhysicsTick input)
|
||||
{
|
||||
var gameRepo = Get<IGameRepo>();
|
||||
var boss = Get<IBoss>();
|
||||
var delta = (float)input.Delta;
|
||||
var boss = Get<IBoss>();
|
||||
var player = Get<IPlayer>();
|
||||
var delta = (float)input.Delta;
|
||||
|
||||
var playerPosition = new Vector3(gameRepo.PlayerGlobalPosition.Value.X, boss.GlobalPosition.Y, gameRepo.PlayerGlobalPosition.Value.Z);
|
||||
var playerPosition = new Vector3(player.CurrentPosition.X, boss.GlobalPosition.Y, player.CurrentPosition.Z);
|
||||
|
||||
if (boss.GlobalPosition.DistanceTo(gameRepo.PlayerGlobalPosition.Value) <= 5.0f)
|
||||
return To<EngagePlayer>();
|
||||
if (boss.GlobalPosition.DistanceTo(player.CurrentPosition) <= 5.0f)
|
||||
return To<EngagePlayer>();
|
||||
|
||||
var moveToward = boss.GlobalPosition.MoveToward(playerPosition, (float)delta * 3f);
|
||||
boss.GlobalPosition = moveToward;
|
||||
var moveToward = boss.GlobalPosition.MoveToward(playerPosition, (float)delta * 3f);
|
||||
boss.GlobalPosition = moveToward;
|
||||
|
||||
var targetDirection = boss.GlobalPosition - gameRepo.PlayerGlobalPosition.Value;
|
||||
boss.GlobalRotation = new Vector3(boss.GlobalRotation.X, Mathf.LerpAngle(boss.GlobalRotation.Y, Mathf.Atan2(-targetDirection.X, -targetDirection.Z), delta * 3f), boss.GlobalRotation.Z);
|
||||
boss.AnimationTree.Get("parameters/playback").As<AnimationNodeStateMachinePlayback>().Travel("Walk");
|
||||
return ToSelf();
|
||||
}
|
||||
var targetDirection = boss.GlobalPosition - player.CurrentPosition;
|
||||
boss.GlobalRotation = new Vector3(boss.GlobalRotation.X, Mathf.LerpAngle(boss.GlobalRotation.Y, Mathf.Atan2(-targetDirection.X, -targetDirection.Z), delta * 3f), boss.GlobalRotation.Z);
|
||||
boss.AnimationTree.Get("parameters/playback").As<AnimationNodeStateMachinePlayback>().Travel("Walk");
|
||||
return ToSelf();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
using Chickensoft.Introspection;
|
||||
|
||||
namespace GameJamDungeon
|
||||
namespace GameJamDungeon;
|
||||
|
||||
public partial class BossLogic
|
||||
{
|
||||
public partial class BossLogic
|
||||
public partial record State
|
||||
{
|
||||
public partial record State
|
||||
[Meta, Id("boss_logic_state_defeated")]
|
||||
public partial record Defeated : State
|
||||
{
|
||||
[Meta, Id("boss_logic_state_defeated")]
|
||||
public partial record Defeated : State
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,47 +1,46 @@
|
||||
using Chickensoft.Introspection;
|
||||
using Godot;
|
||||
|
||||
namespace GameJamDungeon
|
||||
namespace GameJamDungeon;
|
||||
|
||||
public partial class BossLogic
|
||||
{
|
||||
public partial class BossLogic
|
||||
public partial record State
|
||||
{
|
||||
public partial record State
|
||||
[Meta, Id("boss_logic_state_engage_player")]
|
||||
public partial record EngagePlayer : Alive, IGet<Input.PhysicsTick>, IGet<Input.PrimaryAttack>, IGet<Input.SecondaryAttack>
|
||||
{
|
||||
[Meta, Id("boss_logic_state_engage_player")]
|
||||
public partial record EngagePlayer : Alive, IGet<Input.PhysicsTick>, IGet<Input.PrimaryAttack>, IGet<Input.SecondaryAttack>
|
||||
public EngagePlayer()
|
||||
{
|
||||
public EngagePlayer()
|
||||
{
|
||||
OnAttach(() => Get<IBoss>().AnimationTree.Get("parameters/playback").As<AnimationNodeStateMachinePlayback>().Travel("Idle"));
|
||||
}
|
||||
OnAttach(() => Get<IBoss>().AnimationTree.Get("parameters/playback").As<AnimationNodeStateMachinePlayback>().Travel("Idle"));
|
||||
}
|
||||
|
||||
public Transition On(in Input.PhysicsTick input)
|
||||
{
|
||||
var gameRepo = Get<IGameRepo>();
|
||||
var boss = Get<IBoss>();
|
||||
var delta = (float)input.Delta;
|
||||
var playerPosition = new Vector3(gameRepo.PlayerGlobalPosition.Value.X, boss.GlobalPosition.Y, gameRepo.PlayerGlobalPosition.Value.Z);
|
||||
var targetDirection = boss.GlobalPosition - gameRepo.PlayerGlobalPosition.Value;
|
||||
boss.GlobalRotation = new Vector3(boss.GlobalRotation.X, Mathf.LerpAngle(boss.GlobalRotation.Y, Mathf.Atan2(-targetDirection.X, -targetDirection.Z), delta * 3f), boss.GlobalRotation.Z);
|
||||
if (boss.GlobalPosition.DistanceTo(gameRepo.PlayerGlobalPosition.Value) > 5.0f)
|
||||
return To<ApproachPlayer>();
|
||||
public Transition On(in Input.PhysicsTick input)
|
||||
{
|
||||
var boss = Get<IBoss>();
|
||||
var player = Get<IPlayer>();
|
||||
var delta = (float)input.Delta;
|
||||
var playerPosition = new Vector3(player.CurrentPosition.X, boss.GlobalPosition.Y, player.CurrentPosition.Z);
|
||||
var targetDirection = boss.GlobalPosition - player.CurrentPosition;
|
||||
boss.GlobalRotation = new Vector3(boss.GlobalRotation.X, Mathf.LerpAngle(boss.GlobalRotation.Y, Mathf.Atan2(-targetDirection.X, -targetDirection.Z), delta * 3f), boss.GlobalRotation.Z);
|
||||
if (boss.GlobalPosition.DistanceTo(player.CurrentPosition) > 5.0f)
|
||||
return To<ApproachPlayer>();
|
||||
|
||||
return ToSelf();
|
||||
}
|
||||
return ToSelf();
|
||||
}
|
||||
|
||||
public Transition On(in Input.PrimaryAttack input)
|
||||
{
|
||||
var boss = Get<IBoss>();
|
||||
boss.AnimationTree.Get("parameters/playback").As<AnimationNodeStateMachinePlayback>().Travel("PrimaryAttack");
|
||||
return ToSelf();
|
||||
}
|
||||
public Transition On(in Input.PrimaryAttack input)
|
||||
{
|
||||
var boss = Get<IBoss>();
|
||||
boss.AnimationTree.Get("parameters/playback").As<AnimationNodeStateMachinePlayback>().Travel("PrimaryAttack");
|
||||
return ToSelf();
|
||||
}
|
||||
|
||||
public Transition On(in Input.SecondaryAttack input)
|
||||
{
|
||||
var boss = Get<IBoss>();
|
||||
boss.AnimationTree.Get("parameters/playback").As<AnimationNodeStateMachinePlayback>().Travel("SecondaryAttack");
|
||||
return ToSelf();
|
||||
}
|
||||
public Transition On(in Input.SecondaryAttack input)
|
||||
{
|
||||
var boss = Get<IBoss>();
|
||||
boss.AnimationTree.Get("parameters/playback").As<AnimationNodeStateMachinePlayback>().Travel("SecondaryAttack");
|
||||
return ToSelf();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,29 +1,28 @@
|
||||
using Chickensoft.Introspection;
|
||||
|
||||
namespace GameJamDungeon
|
||||
namespace GameJamDungeon;
|
||||
|
||||
public partial class BossLogic
|
||||
{
|
||||
public partial class BossLogic
|
||||
public partial record State
|
||||
{
|
||||
public partial record State
|
||||
[Meta, Id("boss_logic_state_idle")]
|
||||
public partial record Idle : Alive, IGet<Input.Activate>
|
||||
{
|
||||
[Meta, Id("boss_logic_state_idle")]
|
||||
public partial record Idle : Alive, IGet<Input.Activate>
|
||||
public Idle()
|
||||
{
|
||||
public Idle()
|
||||
OnDetach(() =>
|
||||
{
|
||||
OnDetach(() =>
|
||||
{
|
||||
var boss = Get<IBoss>();
|
||||
boss.SetPhysicsProcess(true);
|
||||
boss.Show();
|
||||
boss.AttackTimer.Start();
|
||||
}
|
||||
);
|
||||
}
|
||||
public Transition On(in Input.Activate input)
|
||||
{
|
||||
return To<ApproachPlayer>();
|
||||
var boss = Get<IBoss>();
|
||||
boss.SetPhysicsProcess(true);
|
||||
boss.Show();
|
||||
boss.AttackTimer.Start();
|
||||
}
|
||||
);
|
||||
}
|
||||
public Transition On(in Input.Activate input)
|
||||
{
|
||||
return To<ApproachPlayer>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
using Chickensoft.AutoInject;
|
||||
using Chickensoft.Introspection;
|
||||
using GameJamDungeon;
|
||||
using Godot;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
|
||||
namespace GameJamDungeon;
|
||||
|
||||
[Meta(typeof(IAutoNode))]
|
||||
public partial class DataViewer : Control
|
||||
{
|
||||
|
||||
@@ -2,6 +2,8 @@ using Chickensoft.AutoInject;
|
||||
using Chickensoft.Introspection;
|
||||
using Godot;
|
||||
|
||||
namespace GameJamDungeon;
|
||||
|
||||
[Meta(typeof(IAutoNode))]
|
||||
public partial class DataViewerRepository : Node
|
||||
{
|
||||
|
||||
@@ -23,6 +23,8 @@ public partial class Enemy : RigidBody3D, IEnemy, IProvide<IEnemyLogic>
|
||||
[Dependency] IGameRepo GameRepo => this.DependOn<IGameRepo>();
|
||||
|
||||
[Dependency] IGameEventDepot GameEventDepot => this.DependOn<IGameEventDepot>();
|
||||
|
||||
[Dependency] IPlayer Player => this.DependOn<IPlayer>();
|
||||
#endregion
|
||||
|
||||
#region Exports
|
||||
@@ -56,15 +58,13 @@ public partial class Enemy : RigidBody3D, IEnemy, IProvide<IEnemyLogic>
|
||||
_enemyLogic = new EnemyLogic();
|
||||
_enemyLogic.Set(_enemyStatResource);
|
||||
_enemyLogic.Set(this as IEnemy);
|
||||
_enemyLogic.Set(GameRepo);
|
||||
_enemyLogic.Set(Player);
|
||||
}
|
||||
|
||||
public void TakeDamage(double damage, ElementType elementType, bool isCriticalHit = false, bool ignoreDefense = false, bool ignoreElementalResistance = false)
|
||||
{
|
||||
if (_currentHP.Value > 0)
|
||||
{
|
||||
ApplyKnockback();
|
||||
|
||||
if (!ignoreElementalResistance)
|
||||
damage = CalculateElementalResistance(damage, elementType);
|
||||
if (!ignoreDefense)
|
||||
@@ -93,11 +93,17 @@ public partial class Enemy : RigidBody3D, IEnemy, IProvide<IEnemyLogic>
|
||||
var lookAtPosition = new Vector3(lookAtDir.X, GlobalPosition.Y, lookAtDir.Z);
|
||||
if (GlobalPosition.DistanceTo(target) > 1.0f && !velocity.IsEqualApprox(Vector3.Zero) && !Position.IsEqualApprox(lookAtPosition))
|
||||
LookAt(lookAtPosition + new Vector3(0.001f, 0.001f, 0.001f), Vector3.Up);
|
||||
EnemyModelView.RotateModel(GlobalTransform.Basis, -GameRepo.PlayerGlobalTransform.Value.Basis.Z);
|
||||
EnemyModelView.RotateModel(GlobalTransform.Basis, -Player.CurrentBasis.Z);
|
||||
_knockbackStrength = _knockbackStrength * 0.9f;
|
||||
MoveAndCollide(velocity + (_knockbackDirection * _knockbackStrength));
|
||||
}
|
||||
|
||||
public void Knockback(float impulse, Vector3 direction)
|
||||
{
|
||||
_knockbackDirection = direction;
|
||||
_knockbackStrength = 0.3f;
|
||||
}
|
||||
|
||||
public void Die()
|
||||
{
|
||||
_enemyLogic.Input(new EnemyLogic.Input.EnemyDefeated());
|
||||
@@ -157,7 +163,7 @@ public partial class Enemy : RigidBody3D, IEnemy, IProvide<IEnemyLogic>
|
||||
|
||||
private void OnAttackTimeout()
|
||||
{
|
||||
if (GlobalPosition.DistanceTo(GameRepo.PlayerGlobalPosition.Value) > 2.5f)
|
||||
if (GlobalPosition.DistanceTo(Player.CurrentPosition) > 2.5f)
|
||||
return;
|
||||
|
||||
var rng = new RandomNumberGenerator();
|
||||
@@ -173,13 +179,13 @@ public partial class Enemy : RigidBody3D, IEnemy, IProvide<IEnemyLogic>
|
||||
var overlappingBodies = LineOfSight.GetOverlappingBodies();
|
||||
foreach (var overlap in overlappingBodies)
|
||||
{
|
||||
if (Raycast.GlobalPosition != GameRepo.PlayerGlobalPosition.Value)
|
||||
Raycast.LookAt(GameRepo.PlayerGlobalPosition.Value, Vector3.Up);
|
||||
if (Raycast.GlobalPosition != Player.CurrentPosition)
|
||||
Raycast.LookAt(Player.CurrentPosition, Vector3.Up);
|
||||
Raycast.ForceRaycastUpdate();
|
||||
if (Raycast.IsColliding())
|
||||
{
|
||||
var collider = Raycast.GetCollider();
|
||||
if (collider is IPlayer player)
|
||||
if (collider is IPlayer)
|
||||
{
|
||||
Raycast.DebugShapeCustomColor = Color.FromString("Purple", Colors.Purple);
|
||||
_enemyLogic.Input(new EnemyLogic.Input.Alerted());
|
||||
@@ -188,15 +194,6 @@ public partial class Enemy : RigidBody3D, IEnemy, IProvide<IEnemyLogic>
|
||||
}
|
||||
}
|
||||
|
||||
private void ApplyKnockback()
|
||||
{
|
||||
if (GameRepo.PlayerData.Inventory.EquippedWeapon.Value.WeaponStats.WeaponTags.Contains(WeaponTag.Knockback))
|
||||
{
|
||||
_knockbackDirection = -GameRepo.PlayerGlobalTransform.Value.Basis.Z.Normalized();
|
||||
_knockbackStrength = 0.3f;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnHPChanged(double newHP)
|
||||
{
|
||||
if (newHP <= 0)
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
using Godot;
|
||||
|
||||
namespace GameJamDungeon;
|
||||
|
||||
public partial class EnemyDatabase : Node
|
||||
{
|
||||
[Export]
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
using Godot;
|
||||
|
||||
namespace GameJamDungeon
|
||||
{
|
||||
[GlobalClass]
|
||||
public partial class EnemyLoreInfo : Resource
|
||||
{
|
||||
[Export]
|
||||
public string Name { get; set; }
|
||||
namespace GameJamDungeon;
|
||||
|
||||
[Export]
|
||||
public string Description { get; set; }
|
||||
}
|
||||
[GlobalClass]
|
||||
public partial class EnemyLoreInfo : Resource
|
||||
{
|
||||
[Export]
|
||||
public string Name { get; set; }
|
||||
|
||||
[Export]
|
||||
public string Description { get; set; }
|
||||
}
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
using Chickensoft.AutoInject;
|
||||
using Chickensoft.GodotNodeInterfaces;
|
||||
using Chickensoft.Introspection;
|
||||
using GameJamDungeon;
|
||||
using Godot;
|
||||
|
||||
namespace GameJamDungeon;
|
||||
|
||||
public interface IEnemyModelView : INode3D
|
||||
{
|
||||
public void PlayPrimaryAttackAnimation();
|
||||
|
||||
@@ -1,50 +1,49 @@
|
||||
using Godot;
|
||||
|
||||
namespace GameJamDungeon
|
||||
namespace GameJamDungeon;
|
||||
|
||||
[GlobalClass]
|
||||
public partial class EnemyStatResource : Resource
|
||||
{
|
||||
[GlobalClass]
|
||||
public partial class EnemyStatResource : Resource
|
||||
{
|
||||
[Export]
|
||||
public double CurrentHP { get; set; }
|
||||
[Export]
|
||||
public double CurrentHP { get; set; }
|
||||
|
||||
[Export]
|
||||
public double MaximumHP { get; set; }
|
||||
[Export]
|
||||
public double MaximumHP { get; set; }
|
||||
|
||||
[Export]
|
||||
public int CurrentAttack { get; set; }
|
||||
[Export]
|
||||
public int CurrentAttack { get; set; }
|
||||
|
||||
[Export]
|
||||
public int CurrentDefense { get; set; }
|
||||
[Export]
|
||||
public int CurrentDefense { get; set; }
|
||||
|
||||
[Export]
|
||||
public int MaxAttack { get; set; }
|
||||
[Export]
|
||||
public int MaxAttack { get; set; }
|
||||
|
||||
[Export]
|
||||
public int MaxDefense { get; set; }
|
||||
[Export]
|
||||
public int MaxDefense { get; set; }
|
||||
|
||||
[Export]
|
||||
public int ExpFromDefeat { get; set; }
|
||||
[Export]
|
||||
public int ExpFromDefeat { get; set; }
|
||||
|
||||
[Export]
|
||||
public double Luck { get; set; } = 0.05f;
|
||||
[Export]
|
||||
public double Luck { get; set; } = 0.05f;
|
||||
|
||||
[Export]
|
||||
public double TelluricResistance { get; set; }
|
||||
[Export]
|
||||
public double TelluricResistance { get; set; }
|
||||
|
||||
[Export]
|
||||
public double AeolicResistance { get; set; }
|
||||
[Export]
|
||||
public double AeolicResistance { get; set; }
|
||||
|
||||
[Export]
|
||||
public double HydricResistance { get; set; }
|
||||
[Export]
|
||||
public double HydricResistance { get; set; }
|
||||
|
||||
[Export]
|
||||
public double IgneousResistance { get; set; }
|
||||
[Export]
|
||||
public double IgneousResistance { get; set; }
|
||||
|
||||
[Export]
|
||||
public double FerrumResistance { get; set; }
|
||||
[Export]
|
||||
public double FerrumResistance { get; set; }
|
||||
|
||||
[Export]
|
||||
public float DropsSoulGemChance { get; set; } = 0.75f;
|
||||
}
|
||||
[Export]
|
||||
public float DropsSoulGemChance { get; set; } = 0.75f;
|
||||
}
|
||||
|
||||
@@ -2,15 +2,15 @@
|
||||
|
||||
namespace GameJamDungeon;
|
||||
|
||||
public interface IEnemy
|
||||
public interface IEnemy : IKillable
|
||||
{
|
||||
public void TakeAction();
|
||||
|
||||
public void TakeDamage(double damage, ElementType elementType, bool isCriticalHit = false, bool ignoreDefense = false, bool ignoreElementalResistance = false);
|
||||
public void TakeDamage(double damage, ElementType elementType = ElementType.None, bool isCriticalHit = false, bool ignoreDefense = false, bool ignoreElementalResistance = false);
|
||||
|
||||
public void Knockback(float impulse, Vector3 direction);
|
||||
|
||||
public void MoveToLocation(Vector3 target, float delta);
|
||||
|
||||
public void Die();
|
||||
|
||||
public double CurrentHP { get; }
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
using Godot;
|
||||
|
||||
namespace GameJamDungeon;
|
||||
|
||||
public partial class HorseHead : Node3D
|
||||
{
|
||||
}
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
using Chickensoft.AutoInject;
|
||||
using Chickensoft.Introspection;
|
||||
using GameJamDungeon;
|
||||
using Godot;
|
||||
|
||||
namespace GameJamDungeon;
|
||||
|
||||
[Meta(typeof(IAutoNode))]
|
||||
public partial class OxFace : Node3D
|
||||
{
|
||||
@@ -12,6 +13,8 @@ public partial class OxFace : Node3D
|
||||
|
||||
[Dependency] public IGameRepo GameRepo => this.DependOn<IGameRepo>();
|
||||
|
||||
[Dependency] public IPlayer Player => this.DependOn<IPlayer>();
|
||||
|
||||
[Node] public Timer AttackTimer { get; set; } = default!;
|
||||
|
||||
private bool isInRange = false;
|
||||
@@ -36,10 +39,10 @@ public partial class OxFace : Node3D
|
||||
|
||||
public override void _PhysicsProcess(double delta)
|
||||
{
|
||||
var playerPosition = new Vector3(GameRepo.PlayerGlobalPosition.Value.X, GlobalPosition.Y, GameRepo.PlayerGlobalPosition.Value.Z);
|
||||
var targetDirection = GlobalPosition - GameRepo.PlayerGlobalPosition.Value;
|
||||
var playerPosition = new Vector3(Player.CurrentPosition.X, GlobalPosition.Y, Player.CurrentPosition.Z);
|
||||
var targetDirection = GlobalPosition - Player.CurrentPosition;
|
||||
GlobalRotation = new Vector3(GlobalRotation.X, Mathf.LerpAngle(GlobalRotation.Y, Mathf.Atan2(-targetDirection.X, -targetDirection.Z), (float)delta * 3f), GlobalRotation.Z);
|
||||
if (GlobalPosition.DistanceTo(GameRepo.PlayerGlobalPosition.Value) > 5.0f)
|
||||
if (GlobalPosition.DistanceTo(Player.CurrentPosition) > 5.0f)
|
||||
{
|
||||
isInRange = false;
|
||||
var moveToward = GlobalPosition.MoveToward(playerPosition, (float)delta * 3f);
|
||||
|
||||
@@ -8,9 +8,9 @@
|
||||
script = ExtResource("2_8vcnq")
|
||||
CurrentHP = 50.0
|
||||
MaximumHP = 50.0
|
||||
CurrentAttack = 8
|
||||
CurrentAttack = 20
|
||||
CurrentDefense = 5
|
||||
MaxAttack = 8
|
||||
MaxAttack = 20
|
||||
MaxDefense = 5
|
||||
ExpFromDefeat = 15
|
||||
Luck = 0.05
|
||||
|
||||
@@ -1,23 +1,22 @@
|
||||
|
||||
using Godot;
|
||||
|
||||
namespace GameJamDungeon
|
||||
namespace GameJamDungeon;
|
||||
|
||||
public partial class EnemyLogic
|
||||
{
|
||||
public partial class EnemyLogic
|
||||
public static class Input
|
||||
{
|
||||
public static class Input
|
||||
{
|
||||
public readonly record struct Alerted();
|
||||
public readonly record struct Alerted();
|
||||
|
||||
public readonly record struct LostPlayer();
|
||||
public readonly record struct LostPlayer();
|
||||
|
||||
public readonly record struct PhysicsTick(double Delta);
|
||||
public readonly record struct PhysicsTick(double Delta);
|
||||
|
||||
public readonly record struct EnemyDefeated();
|
||||
public readonly record struct EnemyDefeated();
|
||||
|
||||
public readonly record struct PatrolToRandomSpot(Vector3 PatrolTarget);
|
||||
public readonly record struct PatrolToRandomSpot(Vector3 PatrolTarget);
|
||||
|
||||
public readonly record struct AttackTimer;
|
||||
}
|
||||
public readonly record struct AttackTimer;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,18 +1,17 @@
|
||||
using Godot;
|
||||
|
||||
namespace GameJamDungeon
|
||||
namespace GameJamDungeon;
|
||||
|
||||
public partial class EnemyLogic
|
||||
{
|
||||
public partial class EnemyLogic
|
||||
public static class Output
|
||||
{
|
||||
public static class Output
|
||||
{
|
||||
public readonly record struct MoveTowardsPlayer(Vector3 TargetPosition);
|
||||
public readonly record struct MoveTowardsPlayer(Vector3 TargetPosition);
|
||||
|
||||
public readonly record struct MovementComputed(Vector3 LinearVelocity);
|
||||
public readonly record struct MovementComputed(Vector3 LinearVelocity);
|
||||
|
||||
public readonly record struct TakeAction();
|
||||
public readonly record struct TakeAction();
|
||||
|
||||
public readonly record struct Defeated();
|
||||
}
|
||||
public readonly record struct Defeated();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
namespace GameJamDungeon
|
||||
namespace GameJamDungeon;
|
||||
|
||||
public partial class EnemyLogic
|
||||
{
|
||||
public partial class EnemyLogic
|
||||
{
|
||||
public record Settings(float MaximumHP);
|
||||
}
|
||||
public record Settings(float MaximumHP);
|
||||
}
|
||||
|
||||
@@ -1,16 +1,15 @@
|
||||
using Chickensoft.Introspection;
|
||||
using Chickensoft.LogicBlocks;
|
||||
|
||||
namespace GameJamDungeon
|
||||
namespace GameJamDungeon;
|
||||
|
||||
public partial class EnemyLogic
|
||||
{
|
||||
public partial class EnemyLogic
|
||||
[Meta]
|
||||
public abstract partial record State : StateLogic<State>
|
||||
{
|
||||
[Meta]
|
||||
public abstract partial record State : StateLogic<State>
|
||||
protected State()
|
||||
{
|
||||
protected State()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
using Chickensoft.Introspection;
|
||||
using Chickensoft.LogicBlocks;
|
||||
|
||||
namespace GameJamDungeon
|
||||
{
|
||||
public interface IEnemyLogic : ILogicBlock<EnemyLogic.State>;
|
||||
namespace GameJamDungeon;
|
||||
|
||||
[Meta, Id("enemy_logic")]
|
||||
[LogicBlock(typeof(State), Diagram = true)]
|
||||
public partial class EnemyLogic : LogicBlock<EnemyLogic.State>, IEnemyLogic
|
||||
{
|
||||
public override Transition GetInitialState() => To<State.Idle>();
|
||||
}
|
||||
public interface IEnemyLogic : ILogicBlock<EnemyLogic.State>;
|
||||
|
||||
[Meta, Id("enemy_logic")]
|
||||
[LogicBlock(typeof(State), Diagram = true)]
|
||||
public partial class EnemyLogic : LogicBlock<EnemyLogic.State>, IEnemyLogic
|
||||
{
|
||||
public override Transition GetInitialState() => To<State.Idle>();
|
||||
}
|
||||
|
||||
@@ -1,26 +1,24 @@
|
||||
using Chickensoft.Introspection;
|
||||
using Godot;
|
||||
|
||||
namespace GameJamDungeon
|
||||
namespace GameJamDungeon;
|
||||
|
||||
public partial class EnemyLogic
|
||||
{
|
||||
public partial class EnemyLogic
|
||||
public partial record State
|
||||
{
|
||||
public partial record State
|
||||
[Meta, Id("enemy_logic_state_alive")]
|
||||
public abstract partial record Alive : State, IGet<Input.AttackTimer>, IGet<Input.EnemyDefeated>
|
||||
{
|
||||
[Meta, Id("enemy_logic_state_alive")]
|
||||
public abstract partial record Alive : State, IGet<Input.AttackTimer>, IGet<Input.EnemyDefeated>
|
||||
public Transition On(in Input.AttackTimer input)
|
||||
{
|
||||
public Transition On(in Input.AttackTimer input)
|
||||
{
|
||||
Output(new Output.TakeAction());
|
||||
return ToSelf();
|
||||
}
|
||||
Output(new Output.TakeAction());
|
||||
return ToSelf();
|
||||
}
|
||||
|
||||
public Transition On(in Input.EnemyDefeated input)
|
||||
{
|
||||
Output(new Output.Defeated());
|
||||
return To<Defeated>();
|
||||
}
|
||||
public Transition On(in Input.EnemyDefeated input)
|
||||
{
|
||||
Output(new Output.Defeated());
|
||||
return To<Defeated>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,29 +1,27 @@
|
||||
using Chickensoft.Introspection;
|
||||
using Godot;
|
||||
|
||||
namespace GameJamDungeon
|
||||
namespace GameJamDungeon;
|
||||
|
||||
public partial class EnemyLogic
|
||||
{
|
||||
public partial class EnemyLogic
|
||||
public partial record State
|
||||
{
|
||||
public partial record State
|
||||
[Meta, Id("enemy_logic_state_followplayer")]
|
||||
public partial record FollowPlayer : Alive, IGet<Input.PhysicsTick>, IGet<Input.LostPlayer>
|
||||
{
|
||||
[Meta, Id("enemy_logic_state_followplayer")]
|
||||
public partial record FollowPlayer : Alive, IGet<Input.PhysicsTick>, IGet<Input.LostPlayer>
|
||||
public Transition On(in Input.PhysicsTick input)
|
||||
{
|
||||
public Transition On(in Input.PhysicsTick input)
|
||||
{
|
||||
var delta = input.Delta;
|
||||
var enemy = Get<IEnemy>();
|
||||
var gameRepo = Get<IGameRepo>();
|
||||
var target = gameRepo.PlayerGlobalPosition.Value;
|
||||
enemy.MoveToLocation(target, (float)delta);
|
||||
return ToSelf();
|
||||
}
|
||||
var delta = input.Delta;
|
||||
var enemy = Get<IEnemy>();
|
||||
var player = Get<IPlayer>();
|
||||
var target = player.CurrentPosition;
|
||||
enemy.MoveToLocation(target, (float)delta);
|
||||
return ToSelf();
|
||||
}
|
||||
|
||||
public Transition On(in Input.LostPlayer input)
|
||||
{
|
||||
return To<Idle>();
|
||||
}
|
||||
public Transition On(in Input.LostPlayer input)
|
||||
{
|
||||
return To<Idle>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
using DialogueManagerRuntime;
|
||||
using Godot;
|
||||
|
||||
namespace GameJamDungeon;
|
||||
|
||||
public partial class DialogueController : Node
|
||||
{
|
||||
public static PackedScene DialogueBalloon { get; set; }
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
namespace GameJamDungeon
|
||||
namespace GameJamDungeon;
|
||||
|
||||
public enum ElementType
|
||||
{
|
||||
public enum ElementType
|
||||
{
|
||||
None,
|
||||
Aeolic,
|
||||
Telluric,
|
||||
Hydric,
|
||||
Igneous,
|
||||
Ferrum
|
||||
}
|
||||
None,
|
||||
Aeolic,
|
||||
Telluric,
|
||||
Hydric,
|
||||
Igneous,
|
||||
Ferrum
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ namespace GameJamDungeon;
|
||||
|
||||
using Chickensoft.AutoInject;
|
||||
using Chickensoft.Introspection;
|
||||
using GameJamDungeon.src.item_rescue;
|
||||
using Godot;
|
||||
using System;
|
||||
|
||||
@@ -16,6 +15,8 @@ public partial class Game : Node3D, IGame
|
||||
|
||||
IGame IProvide<IGame>.Value() => this;
|
||||
|
||||
IPlayer IProvide<IPlayer>.Value() => Player;
|
||||
|
||||
IGameEventDepot IProvide<IGameEventDepot>.Value() => GameEventDepot;
|
||||
|
||||
public IInstantiator Instantiator { get; set; } = default!;
|
||||
@@ -61,6 +62,7 @@ public partial class Game : Node3D, IGame
|
||||
GameLogic.Set(GameRepo);
|
||||
GameLogic.Set(AppRepo);
|
||||
GameLogic.Set(GameEventDepot);
|
||||
GameLogic.Set(Player);
|
||||
Instantiator = new Instantiator(GetTree());
|
||||
RescuedItems = new RescuedItemDatabase();
|
||||
}
|
||||
@@ -117,29 +119,27 @@ public partial class Game : Node3D, IGame
|
||||
InGameUI.UseTeleportPrompt.TeleportToNextFloor += UseTeleportPrompt_TeleportToNextFloor;
|
||||
InGameUI.UseTeleportPrompt.CloseTeleportPrompt += UseTeleportPrompt_CloseTeleportPrompt;
|
||||
|
||||
GameRepo.PlayerData.Inventory.InventoryAtCapacity += PlayerInventory_InventoryAtCapacity;
|
||||
GameRepo.PlayerData.Inventory.PickedUpItem += Inventory_PickedUpItem;
|
||||
GameRepo.PlayerData.Inventory.RaiseStatRequest += Inventory_RaiseStatRequest;
|
||||
Player.Inventory.InventoryAtCapacity += PlayerInventory_InventoryAtCapacity;
|
||||
Player.Inventory.PickedUpItem += Inventory_PickedUpItem;
|
||||
Player.Inventory.RaiseStatRequest += Inventory_RaiseStatRequest;
|
||||
FloorClearMenu.GoToNextFloor += FloorClearMenu_GoToNextFloor;
|
||||
FloorClearMenu.SaveAndExit += FloorClearMenu_SaveAndExit;
|
||||
FloorClearMenu.TransitionCompleted += FloorClearMenu_TransitionCompleted;
|
||||
|
||||
Player.InventoryButtonPressed += Player_InventoryButtonPressed;
|
||||
Player.MinimapButtonHeld += Player_MinimapButtonHeld;
|
||||
Player.PauseButtonPressed += Player_PauseButtonPressed;
|
||||
|
||||
GameRepo.PlayerData.CurrentHP.Sync += CurrentHP_Sync;
|
||||
|
||||
GameEventDepot.EnemyDefeated += OnEnemyDefeated;
|
||||
GameEventDepot.RestorativePickedUp += GameEventDepot_RestorativePickedUp;
|
||||
|
||||
DoubleEXPTimer.Timeout += DoubleEXPTimer_Timeout;
|
||||
}
|
||||
|
||||
private void CurrentHP_Sync(int currentHP)
|
||||
public void ToggleInventory()
|
||||
{
|
||||
if (currentHP <= 0)
|
||||
GameLogic.Input(new GameLogic.Input.GameOver());
|
||||
GameLogic.Input(new GameLogic.Input.OpenInventory());
|
||||
}
|
||||
|
||||
public void ToggleMinimap()
|
||||
{
|
||||
GameLogic.Input(new GameLogic.Input.MiniMapButtonPressed());
|
||||
}
|
||||
|
||||
private void Inventory_PickedUpItem(string pickedUpItemName)
|
||||
@@ -160,14 +160,14 @@ public partial class Game : Node3D, IGame
|
||||
{
|
||||
var thrownScene = GD.Load<PackedScene>("res://src/items/thrown/ThrownItem.tscn");
|
||||
var thrown = thrownScene.Instantiate<ThrownItem>();
|
||||
thrown.ThrownItemStats = item.Info;
|
||||
thrown.ItemThatIsThrown = item;
|
||||
AddChild(thrown);
|
||||
thrown.Throw();
|
||||
}
|
||||
|
||||
private void OnEnemyDefeated(Vector3 vector, EnemyStatResource resource)
|
||||
{
|
||||
GameRepo.PlayerData.SetCurrentExp(GameRepo.PlayerData.CurrentExp.Value + (resource.ExpFromDefeat * GameRepo.EXPRate));
|
||||
Player.GainExp(resource.ExpFromDefeat * GameRepo.EXPRate);
|
||||
DropRestorative(vector);
|
||||
}
|
||||
|
||||
@@ -205,21 +205,11 @@ public partial class Game : Node3D, IGame
|
||||
GameLogic.Input(new GameLogic.Input.MiniMapButtonReleased());
|
||||
}
|
||||
|
||||
private void Player_MinimapButtonHeld()
|
||||
{
|
||||
GameLogic.Input(new GameLogic.Input.MiniMapButtonPressed());
|
||||
}
|
||||
|
||||
private void Player_InventoryButtonPressed()
|
||||
{
|
||||
GameLogic.Input(new GameLogic.Input.OpenInventory());
|
||||
}
|
||||
|
||||
private void FloorClearMenu_TransitionCompleted()
|
||||
{
|
||||
GameRepo.Resume();
|
||||
if (GameRepo.PlayerData.Inventory.EquippedWeapon.Value.WeaponStats.WeaponTags.Contains(WeaponTag.BreaksOnChange))
|
||||
GameRepo.PlayerData.Inventory.Unequip(GameRepo.PlayerData.Inventory.EquippedWeapon.Value);
|
||||
if (Player.Inventory.EquippedWeapon.Value.WeaponTags.Contains(WeaponTag.BreaksOnChange))
|
||||
Player.Inventory.Unequip(Player.Inventory.EquippedWeapon.Value);
|
||||
}
|
||||
|
||||
private void FloorClearMenu_GoToNextFloor()
|
||||
@@ -235,7 +225,7 @@ public partial class Game : Node3D, IGame
|
||||
}
|
||||
|
||||
private void GameEventDepot_RestorativePickedUp(Restorative obj)
|
||||
=> GameRepo.PlayerData.SetCurrentVT(GameRepo.PlayerData.CurrentVT.Value + obj.VTRestoreAmount);
|
||||
=> Player.Stats.SetCurrentVT(Player.Stats.CurrentVT.Value + obj.VTRestoreAmount);
|
||||
|
||||
private void Inventory_RaiseStatRequest(InventoryItemStats itemStats)
|
||||
{
|
||||
@@ -251,34 +241,34 @@ public partial class Game : Node3D, IGame
|
||||
|
||||
public void RaiseHP(int amountToRaise)
|
||||
{
|
||||
if (GameRepo.PlayerData.CurrentHP.Value == GameRepo.PlayerData.MaximumHP.Value)
|
||||
if (Player.Stats.CurrentHP.Value == Player.Stats.MaximumHP.Value)
|
||||
{
|
||||
GameRepo.PlayerData.SetMaximumHP(GameRepo.PlayerData.MaximumHP.Value + amountToRaise);
|
||||
GameRepo.PlayerData.SetCurrentHP(GameRepo.PlayerData.MaximumHP.Value);
|
||||
Player.Stats.SetMaximumHP(Player.Stats.MaximumHP.Value + amountToRaise);
|
||||
Player.Stats.SetCurrentHP(Player.Stats.MaximumHP.Value);
|
||||
EmitSignal(SignalName.StatRaisedAlert, $"{amountToRaise}MAXHP Up.");
|
||||
}
|
||||
}
|
||||
|
||||
public void HealHP(int amountToRestore)
|
||||
{
|
||||
GameRepo.PlayerData.SetCurrentHP(GameRepo.PlayerData.CurrentHP.Value + amountToRestore);
|
||||
Player.Stats.SetCurrentHP(Player.Stats.CurrentHP.Value + amountToRestore);
|
||||
var raiseString = amountToRestore == 1000 ? "MAX" : $"{amountToRestore}";
|
||||
EmitSignal(SignalName.StatRaisedAlert, $"{raiseString}HP Restored.");
|
||||
}
|
||||
|
||||
public void RaiseVT(int amountToRaise)
|
||||
{
|
||||
if (GameRepo.PlayerData.CurrentVT.Value == GameRepo.PlayerData.MaximumVT.Value)
|
||||
if (Player.Stats.CurrentVT.Value == Player.Stats.MaximumVT.Value)
|
||||
{
|
||||
GameRepo.PlayerData.SetMaximumVT(GameRepo.PlayerData.MaximumVT.Value + amountToRaise);
|
||||
GameRepo.PlayerData.SetCurrentVT(GameRepo.PlayerData.MaximumVT.Value);
|
||||
Player.Stats.SetMaximumVT(Player.Stats.MaximumVT.Value + amountToRaise);
|
||||
Player.Stats.SetCurrentVT(Player.Stats.MaximumVT.Value);
|
||||
EmitSignal(SignalName.StatRaisedAlert, $"{amountToRaise}MAXVT Up.");
|
||||
}
|
||||
}
|
||||
|
||||
public void HealVT(int amountToRestore)
|
||||
{
|
||||
GameRepo.PlayerData.SetCurrentVT(GameRepo.PlayerData.CurrentVT.Value + amountToRestore);
|
||||
Player.Stats.SetCurrentVT(Player.Stats.CurrentVT.Value + amountToRestore);
|
||||
var raiseString = amountToRestore == 1000 ? "MAX" : $"{amountToRestore}";
|
||||
EmitSignal(SignalName.StatRaisedAlert, $"{raiseString}VT Restored.");
|
||||
}
|
||||
@@ -309,7 +299,7 @@ public partial class Game : Node3D, IGame
|
||||
{
|
||||
var transform = Map.GetPlayerSpawnPosition();
|
||||
GameRepo.SetPlayerGlobalTransform(transform);
|
||||
GameRepo.SetPlayerGlobalPosition(new Vector3(transform.Origin.X, -2, transform.Origin.Z));
|
||||
Player.TeleportPlayer(new Vector3(transform.Origin.X, -1.75f, transform.Origin.Z));
|
||||
GameLogic.Input(new GameLogic.Input.HideFloorClearMenu());
|
||||
}
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ process_mode = 1
|
||||
[node name="Player" parent="SubViewportContainer/SubViewport/PauseContainer" instance=ExtResource("3_kk6ly")]
|
||||
unique_name_in_owner = true
|
||||
process_mode = 1
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -2.74459, 1.22144)
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.283374, 1.22144)
|
||||
|
||||
[node name="Map" parent="SubViewportContainer/SubViewport/PauseContainer" instance=ExtResource("3_d8awv")]
|
||||
unique_name_in_owner = true
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
using Chickensoft.Introspection;
|
||||
using Chickensoft.Serialization;
|
||||
|
||||
namespace GameJamDungeon
|
||||
namespace GameJamDungeon;
|
||||
|
||||
[Meta, Id("game_data")]
|
||||
public partial record GameData
|
||||
{
|
||||
[Meta, Id("game_data")]
|
||||
public partial record GameData
|
||||
{
|
||||
[Save("player_data")]
|
||||
public required PlayerData PlayerData { get; init; }
|
||||
}
|
||||
[Save("player_data")]
|
||||
public required PlayerStats PlayerData { get; init; }
|
||||
}
|
||||
|
||||
@@ -1,114 +1,113 @@
|
||||
using Godot;
|
||||
using System;
|
||||
|
||||
namespace GameJamDungeon
|
||||
namespace GameJamDungeon;
|
||||
|
||||
public interface IGameEventDepot : IDisposable
|
||||
{
|
||||
public interface IGameEventDepot : IDisposable
|
||||
event Action? OverworldEntered;
|
||||
public void OnOverworldEntered();
|
||||
|
||||
event Action? DungeonAThemeAreaEntered;
|
||||
public void OnDungeonAThemeAreaEntered();
|
||||
|
||||
event Action? DungeonBThemeAreaEntered;
|
||||
public void OnDungeonBThemeAreaEntered();
|
||||
|
||||
event Action? DungeonCThemeAreaEntered;
|
||||
public void OnDungeonCThemeAreaEntered();
|
||||
|
||||
event Action? TeleportEntered;
|
||||
public void OnTeleportEntered();
|
||||
|
||||
event Action? MenuScrolled;
|
||||
public void OnMenuScrolled();
|
||||
|
||||
event Action? MenuBackedOut;
|
||||
public void OnMenuBackedOut();
|
||||
|
||||
event Action<Weapon>? EquippedWeapon;
|
||||
public void OnEquippedWeapon(Weapon equippedWeapon);
|
||||
|
||||
event Action? UnequippedWeapon;
|
||||
public void OnUnequippedWeapon();
|
||||
|
||||
event Action<Armor>? EquippedArmor;
|
||||
public void OnEquippedArmor(Armor equippedArmor);
|
||||
|
||||
event Action? UnequippedArmor;
|
||||
public void OnUnequippedArmor();
|
||||
|
||||
event Action<Accessory>? EquippedAccessory;
|
||||
public void OnEquippedAccessory(Accessory equippedAccessory);
|
||||
|
||||
event Action? UnequippedAccessory;
|
||||
public void OnUnequippedAccessory();
|
||||
|
||||
event Action? InventorySorted;
|
||||
public void OnInventorySorted();
|
||||
|
||||
event Action<ConsumableItemStats>? HealingItemConsumed;
|
||||
public void OnHealingItemConsumed(ConsumableItemStats item);
|
||||
|
||||
event Action<Vector3, EnemyStatResource>? EnemyDefeated;
|
||||
public void OnEnemyDefeated(Vector3 position, EnemyStatResource enemyStatResource);
|
||||
|
||||
event Action<Restorative>? RestorativePickedUp;
|
||||
public void OnRestorativePickedUp(Restorative restorative);
|
||||
}
|
||||
|
||||
public class GameEventDepot : IGameEventDepot
|
||||
{
|
||||
|
||||
public event Action? OverworldEntered;
|
||||
public event Action? DungeonAThemeAreaEntered;
|
||||
public event Action? DungeonBThemeAreaEntered;
|
||||
public event Action? DungeonCThemeAreaEntered;
|
||||
|
||||
public event Action? TeleportEntered;
|
||||
|
||||
public event Action? MenuScrolled;
|
||||
public event Action? MenuBackedOut;
|
||||
public event Action<Weapon>? EquippedWeapon;
|
||||
public event Action? UnequippedWeapon;
|
||||
public event Action<Armor>? EquippedArmor;
|
||||
public event Action? UnequippedArmor;
|
||||
public event Action<Accessory>? EquippedAccessory;
|
||||
public event Action? UnequippedAccessory;
|
||||
public event Action? InventorySorted;
|
||||
public event Action<ConsumableItemStats>? HealingItemConsumed;
|
||||
public event Action<Restorative>? RestorativePickedUp;
|
||||
|
||||
public event Action<Vector3, EnemyStatResource>? EnemyDefeated;
|
||||
|
||||
public void OnOverworldEntered() => OverworldEntered?.Invoke();
|
||||
public void OnDungeonAThemeAreaEntered() => DungeonAThemeAreaEntered?.Invoke();
|
||||
public void OnDungeonBThemeAreaEntered() => DungeonBThemeAreaEntered?.Invoke();
|
||||
public void OnDungeonCThemeAreaEntered() => DungeonCThemeAreaEntered?.Invoke();
|
||||
|
||||
public void OnTeleportEntered() => TeleportEntered?.Invoke();
|
||||
|
||||
public void OnMenuScrolled() => MenuScrolled?.Invoke();
|
||||
public void OnMenuBackedOut() => MenuBackedOut?.Invoke();
|
||||
|
||||
public void OnEquippedWeapon(Weapon equippedWeapon) => EquippedWeapon?.Invoke(equippedWeapon);
|
||||
public void OnUnequippedWeapon() => UnequippedWeapon?.Invoke();
|
||||
|
||||
public void OnEquippedArmor(Armor equippedArmor) => EquippedArmor?.Invoke(equippedArmor);
|
||||
public void OnUnequippedArmor() => UnequippedArmor?.Invoke();
|
||||
|
||||
public void OnEquippedAccessory(Accessory equippedAccessory) => EquippedAccessory?.Invoke(equippedAccessory);
|
||||
public void OnUnequippedAccessory() => UnequippedAccessory?.Invoke();
|
||||
|
||||
public void OnInventorySorted() => InventorySorted?.Invoke();
|
||||
public void OnHealingItemConsumed(ConsumableItemStats item) => HealingItemConsumed?.Invoke(item);
|
||||
public void OnRestorativePickedUp(Restorative restorative) => RestorativePickedUp?.Invoke(restorative);
|
||||
|
||||
public void OnEnemyDefeated(Vector3 position, EnemyStatResource enemyStatResource) => EnemyDefeated?.Invoke(position, enemyStatResource);
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
event Action? OverworldEntered;
|
||||
public void OnOverworldEntered();
|
||||
|
||||
event Action? DungeonAThemeAreaEntered;
|
||||
public void OnDungeonAThemeAreaEntered();
|
||||
|
||||
event Action? DungeonBThemeAreaEntered;
|
||||
public void OnDungeonBThemeAreaEntered();
|
||||
|
||||
event Action? DungeonCThemeAreaEntered;
|
||||
public void OnDungeonCThemeAreaEntered();
|
||||
|
||||
event Action? TeleportEntered;
|
||||
public void OnTeleportEntered();
|
||||
|
||||
event Action? MenuScrolled;
|
||||
public void OnMenuScrolled();
|
||||
|
||||
event Action? MenuBackedOut;
|
||||
public void OnMenuBackedOut();
|
||||
|
||||
event Action<Weapon>? EquippedWeapon;
|
||||
public void OnEquippedWeapon(Weapon equippedWeapon);
|
||||
|
||||
event Action? UnequippedWeapon;
|
||||
public void OnUnequippedWeapon();
|
||||
|
||||
event Action<Armor>? EquippedArmor;
|
||||
public void OnEquippedArmor(Armor equippedArmor);
|
||||
|
||||
event Action? UnequippedArmor;
|
||||
public void OnUnequippedArmor();
|
||||
|
||||
event Action<Accessory>? EquippedAccessory;
|
||||
public void OnEquippedAccessory(Accessory equippedAccessory);
|
||||
|
||||
event Action? UnequippedAccessory;
|
||||
public void OnUnequippedAccessory();
|
||||
|
||||
event Action? InventorySorted;
|
||||
public void OnInventorySorted();
|
||||
|
||||
event Action<ConsumableItemStats>? HealingItemConsumed;
|
||||
public void OnHealingItemConsumed(ConsumableItemStats item);
|
||||
|
||||
event Action<Vector3, EnemyStatResource>? EnemyDefeated;
|
||||
public void OnEnemyDefeated(Vector3 position, EnemyStatResource enemyStatResource);
|
||||
|
||||
event Action<Restorative>? RestorativePickedUp;
|
||||
public void OnRestorativePickedUp(Restorative restorative);
|
||||
}
|
||||
|
||||
public class GameEventDepot : IGameEventDepot
|
||||
{
|
||||
|
||||
public event Action? OverworldEntered;
|
||||
public event Action? DungeonAThemeAreaEntered;
|
||||
public event Action? DungeonBThemeAreaEntered;
|
||||
public event Action? DungeonCThemeAreaEntered;
|
||||
|
||||
public event Action? TeleportEntered;
|
||||
|
||||
public event Action? MenuScrolled;
|
||||
public event Action? MenuBackedOut;
|
||||
public event Action<Weapon>? EquippedWeapon;
|
||||
public event Action? UnequippedWeapon;
|
||||
public event Action<Armor>? EquippedArmor;
|
||||
public event Action? UnequippedArmor;
|
||||
public event Action<Accessory>? EquippedAccessory;
|
||||
public event Action? UnequippedAccessory;
|
||||
public event Action? InventorySorted;
|
||||
public event Action<ConsumableItemStats>? HealingItemConsumed;
|
||||
public event Action<Restorative>? RestorativePickedUp;
|
||||
|
||||
public event Action<Vector3, EnemyStatResource>? EnemyDefeated;
|
||||
|
||||
public void OnOverworldEntered() => OverworldEntered?.Invoke();
|
||||
public void OnDungeonAThemeAreaEntered() => DungeonAThemeAreaEntered?.Invoke();
|
||||
public void OnDungeonBThemeAreaEntered() => DungeonBThemeAreaEntered?.Invoke();
|
||||
public void OnDungeonCThemeAreaEntered() => DungeonCThemeAreaEntered?.Invoke();
|
||||
|
||||
public void OnTeleportEntered() => TeleportEntered?.Invoke();
|
||||
|
||||
public void OnMenuScrolled() => MenuScrolled?.Invoke();
|
||||
public void OnMenuBackedOut() => MenuBackedOut?.Invoke();
|
||||
|
||||
public void OnEquippedWeapon(Weapon equippedWeapon) => EquippedWeapon?.Invoke(equippedWeapon);
|
||||
public void OnUnequippedWeapon() => UnequippedWeapon?.Invoke();
|
||||
|
||||
public void OnEquippedArmor(Armor equippedArmor) => EquippedArmor?.Invoke(equippedArmor);
|
||||
public void OnUnequippedArmor() => UnequippedArmor?.Invoke();
|
||||
|
||||
public void OnEquippedAccessory(Accessory equippedAccessory) => EquippedAccessory?.Invoke(equippedAccessory);
|
||||
public void OnUnequippedAccessory() => UnequippedAccessory?.Invoke();
|
||||
|
||||
public void OnInventorySorted() => InventorySorted?.Invoke();
|
||||
public void OnHealingItemConsumed(ConsumableItemStats item) => HealingItemConsumed?.Invoke(item);
|
||||
public void OnRestorativePickedUp(Restorative restorative) => RestorativePickedUp?.Invoke(restorative);
|
||||
|
||||
public void OnEnemyDefeated(Vector3 position, EnemyStatResource enemyStatResource) => EnemyDefeated?.Invoke(position, enemyStatResource);
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,41 +1,40 @@
|
||||
namespace GameJamDungeon
|
||||
namespace GameJamDungeon;
|
||||
|
||||
public partial class GameLogic
|
||||
{
|
||||
public partial class GameLogic
|
||||
public static class Input
|
||||
{
|
||||
public static class Input
|
||||
{
|
||||
public readonly record struct StartGame;
|
||||
public readonly record struct StartGame;
|
||||
|
||||
public readonly record struct Initialize;
|
||||
public readonly record struct Initialize;
|
||||
|
||||
public readonly record struct GoToOverworld;
|
||||
public readonly record struct GoToOverworld;
|
||||
|
||||
public readonly record struct SaveGame;
|
||||
public readonly record struct SaveGame;
|
||||
|
||||
public readonly record struct OpenInventory;
|
||||
public readonly record struct OpenInventory;
|
||||
|
||||
public readonly record struct CloseInventory;
|
||||
public readonly record struct CloseInventory;
|
||||
|
||||
public readonly record struct MiniMapButtonPressed;
|
||||
public readonly record struct MiniMapButtonPressed;
|
||||
|
||||
public readonly record struct MiniMapButtonReleased;
|
||||
public readonly record struct MiniMapButtonReleased;
|
||||
|
||||
public readonly record struct FloorExitReached;
|
||||
public readonly record struct HideFloorClearMenu;
|
||||
public readonly record struct FloorExitReached;
|
||||
public readonly record struct HideFloorClearMenu;
|
||||
|
||||
public readonly record struct GameOver;
|
||||
public readonly record struct GameOver;
|
||||
|
||||
public readonly record struct GoToNextFloor;
|
||||
public readonly record struct GoToNextFloor;
|
||||
|
||||
public readonly record struct PauseGame;
|
||||
public readonly record struct PauseGame;
|
||||
|
||||
public readonly record struct UnpauseGame;
|
||||
public readonly record struct UnpauseGame;
|
||||
|
||||
public readonly record struct PauseMenuTransitioned;
|
||||
public readonly record struct PauseMenuTransitioned;
|
||||
|
||||
public readonly record struct AskForTeleport;
|
||||
public readonly record struct AskForTeleport;
|
||||
|
||||
public readonly record struct HideAskForTeleport;
|
||||
}
|
||||
public readonly record struct HideAskForTeleport;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,44 +1,41 @@
|
||||
using System.Collections.Generic;
|
||||
namespace GameJamDungeon;
|
||||
|
||||
namespace GameJamDungeon
|
||||
public partial class GameLogic
|
||||
{
|
||||
public partial class GameLogic
|
||||
public static class Output
|
||||
{
|
||||
public static class Output
|
||||
{
|
||||
public readonly record struct StartGame;
|
||||
public readonly record struct StartGame;
|
||||
|
||||
public readonly record struct ShowPauseMenu;
|
||||
public readonly record struct ShowPauseMenu;
|
||||
|
||||
public readonly record struct HidePauseMenu;
|
||||
public readonly record struct HidePauseMenu;
|
||||
|
||||
public readonly record struct ExitPauseMenu;
|
||||
public readonly record struct ExitPauseMenu;
|
||||
|
||||
public readonly record struct OpenInventory();
|
||||
public readonly record struct OpenInventory();
|
||||
|
||||
public readonly record struct HideInventory;
|
||||
public readonly record struct HideInventory;
|
||||
|
||||
public readonly record struct SetPauseMode(bool IsPaused);
|
||||
public readonly record struct SetPauseMode(bool IsPaused);
|
||||
|
||||
public readonly record struct ShowMiniMap;
|
||||
public readonly record struct ShowMiniMap;
|
||||
|
||||
public readonly record struct HideMiniMap;
|
||||
public readonly record struct HideMiniMap;
|
||||
|
||||
public readonly record struct ShowLostScreen;
|
||||
public readonly record struct ShowLostScreen;
|
||||
|
||||
public readonly record struct ExitLostScreen;
|
||||
public readonly record struct ExitLostScreen;
|
||||
|
||||
public readonly record struct LoadNextFloor;
|
||||
public readonly record struct LoadNextFloor;
|
||||
|
||||
public readonly record struct ShowFloorClearMenu;
|
||||
public readonly record struct ShowFloorClearMenu;
|
||||
|
||||
public readonly record struct ExitFloorClearMenu;
|
||||
public readonly record struct ExitFloorClearMenu;
|
||||
|
||||
public readonly record struct ShowAskForTeleport;
|
||||
public readonly record struct ShowAskForTeleport;
|
||||
|
||||
public readonly record struct HideAskForTeleport;
|
||||
public readonly record struct HideAskForTeleport;
|
||||
|
||||
public readonly record struct GoToOverworld;
|
||||
}
|
||||
public readonly record struct GoToOverworld;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,28 +1,27 @@
|
||||
using Chickensoft.Introspection;
|
||||
using Chickensoft.LogicBlocks;
|
||||
|
||||
namespace GameJamDungeon
|
||||
{
|
||||
public partial class GameLogic
|
||||
{
|
||||
[Meta]
|
||||
public abstract partial record State : StateLogic<State>
|
||||
{
|
||||
protected State()
|
||||
{
|
||||
OnAttach(() =>
|
||||
{
|
||||
var gameRepo = Get<IGameRepo>();
|
||||
gameRepo.IsPaused.Sync += OnIsPaused;
|
||||
});
|
||||
OnDetach(() =>
|
||||
{
|
||||
var gameRepo = Get<IGameRepo>();
|
||||
gameRepo.IsPaused.Sync -= OnIsPaused;
|
||||
});
|
||||
}
|
||||
namespace GameJamDungeon;
|
||||
|
||||
public void OnIsPaused(bool isPaused) => Output(new Output.SetPauseMode(isPaused));
|
||||
public partial class GameLogic
|
||||
{
|
||||
[Meta]
|
||||
public abstract partial record State : StateLogic<State>
|
||||
{
|
||||
protected State()
|
||||
{
|
||||
OnAttach(() =>
|
||||
{
|
||||
var gameRepo = Get<IGameRepo>();
|
||||
gameRepo.IsPaused.Sync += OnIsPaused;
|
||||
});
|
||||
OnDetach(() =>
|
||||
{
|
||||
var gameRepo = Get<IGameRepo>();
|
||||
gameRepo.IsPaused.Sync -= OnIsPaused;
|
||||
});
|
||||
}
|
||||
|
||||
public void OnIsPaused(bool isPaused) => Output(new Output.SetPauseMode(isPaused));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
using Chickensoft.Introspection;
|
||||
using Chickensoft.LogicBlocks;
|
||||
|
||||
namespace GameJamDungeon
|
||||
{
|
||||
public interface IGameLogic : ILogicBlock<GameLogic.State>;
|
||||
namespace GameJamDungeon;
|
||||
|
||||
[Meta]
|
||||
[LogicBlock(typeof(State), Diagram = true)]
|
||||
public partial class GameLogic : LogicBlock<GameLogic.State>, IGameLogic
|
||||
{
|
||||
public override Transition GetInitialState() => To<State.GameStarted>();
|
||||
}
|
||||
public interface IGameLogic : ILogicBlock<GameLogic.State>;
|
||||
|
||||
[Meta]
|
||||
[LogicBlock(typeof(State), Diagram = true)]
|
||||
public partial class GameLogic : LogicBlock<GameLogic.State>, IGameLogic
|
||||
{
|
||||
public override Transition GetInitialState() => To<State.GameStarted>();
|
||||
}
|
||||
|
||||
@@ -12,16 +12,6 @@ public interface IGameRepo : IDisposable
|
||||
|
||||
IAutoProp<bool> IsPaused { get; }
|
||||
|
||||
IAutoProp<Vector3> PlayerGlobalPosition { get; }
|
||||
|
||||
IAutoProp<Transform3D> PlayerGlobalTransform { get; }
|
||||
|
||||
PlayerData PlayerData { get; }
|
||||
|
||||
public void SetPlayerData(PlayerData playerData);
|
||||
|
||||
void SetPlayerGlobalPosition(Vector3 playerGlobalPosition);
|
||||
|
||||
void SetPlayerGlobalTransform(Transform3D playerGlobalTransform);
|
||||
|
||||
public int MaxItemSize { get; }
|
||||
@@ -35,18 +25,12 @@ public class GameRepo : IGameRepo
|
||||
{
|
||||
public event Action? Ended;
|
||||
|
||||
public IAutoProp<Vector3> PlayerGlobalPosition => _playerGlobalPosition;
|
||||
private readonly AutoProp<Vector3> _playerGlobalPosition;
|
||||
|
||||
public IAutoProp<Transform3D> PlayerGlobalTransform => _playerGlobalTransform;
|
||||
private readonly AutoProp<Transform3D> _playerGlobalTransform;
|
||||
|
||||
public IAutoProp<bool> IsPaused => _isPaused;
|
||||
private readonly AutoProp<bool> _isPaused;
|
||||
|
||||
public PlayerData PlayerData => _playerData;
|
||||
private PlayerData _playerData;
|
||||
|
||||
public int MaxItemSize => 20;
|
||||
|
||||
public int EXPRate { get; set; } = 1;
|
||||
@@ -58,7 +42,6 @@ public class GameRepo : IGameRepo
|
||||
public GameRepo()
|
||||
{
|
||||
_isPaused = new AutoProp<bool>(false);
|
||||
_playerGlobalPosition = new AutoProp<Vector3>(Vector3.Zero);
|
||||
_playerGlobalTransform = new AutoProp<Transform3D>(Transform3D.Identity);
|
||||
}
|
||||
|
||||
@@ -74,12 +57,8 @@ public class GameRepo : IGameRepo
|
||||
GD.Print("Resume");
|
||||
}
|
||||
|
||||
public void SetPlayerGlobalPosition(Vector3 playerGlobalPosition) => _playerGlobalPosition.OnNext(playerGlobalPosition);
|
||||
|
||||
public void SetPlayerGlobalTransform(Transform3D playerGlobalTransform) => _playerGlobalTransform.OnNext(playerGlobalTransform);
|
||||
|
||||
public void SetPlayerData(PlayerData playerData) => _playerData = playerData;
|
||||
|
||||
public void OnGameEnded()
|
||||
{
|
||||
Pause();
|
||||
@@ -92,8 +71,6 @@ public class GameRepo : IGameRepo
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
_playerGlobalPosition.OnCompleted();
|
||||
_playerGlobalPosition.Dispose();
|
||||
_isPaused.OnCompleted();
|
||||
_isPaused.Dispose();
|
||||
}
|
||||
|
||||
@@ -3,10 +3,9 @@ namespace GameJamDungeon;
|
||||
|
||||
using Chickensoft.AutoInject;
|
||||
using Chickensoft.GodotNodeInterfaces;
|
||||
using GameJamDungeon.src.item_rescue;
|
||||
using System;
|
||||
|
||||
public interface IGame : IProvide<IGameRepo>, IProvide<IGameEventDepot>, IProvide<IGame>, INode3D
|
||||
public interface IGame : IProvide<IGameRepo>, IProvide<IGameEventDepot>, IProvide<IGame>, IProvide<IPlayer>, INode3D
|
||||
{
|
||||
event Game.StatRaisedAlertEventHandler StatRaisedAlert;
|
||||
|
||||
@@ -25,4 +24,8 @@ public interface IGame : IProvide<IGameRepo>, IProvide<IGameEventDepot>, IProvid
|
||||
public void RaiseVT(int amountToRaise);
|
||||
|
||||
public void DoubleEXP(TimeSpan lengthOfEffect);
|
||||
|
||||
public void ToggleInventory();
|
||||
|
||||
public void ToggleMinimap();
|
||||
}
|
||||
|
||||
@@ -1,27 +1,25 @@
|
||||
using Chickensoft.Introspection;
|
||||
using Chickensoft.LogicBlocks;
|
||||
|
||||
namespace GameJamDungeon
|
||||
namespace GameJamDungeon;
|
||||
|
||||
public partial class GameLogic
|
||||
{
|
||||
public partial class GameLogic
|
||||
public partial record State
|
||||
{
|
||||
public partial record State
|
||||
[Meta]
|
||||
public partial record AskForTeleport : Playing, IGet<Input.FloorExitReached>, IGet<Input.HideAskForTeleport>
|
||||
{
|
||||
[Meta]
|
||||
public partial record AskForTeleport : Playing, IGet<Input.FloorExitReached>, IGet<Input.HideAskForTeleport>
|
||||
public AskForTeleport()
|
||||
{
|
||||
public AskForTeleport()
|
||||
{
|
||||
this.OnAttach(() => { Get<IGameRepo>().Pause(); Output(new Output.ShowAskForTeleport()); });
|
||||
this.OnDetach(() => { Output(new Output.HideAskForTeleport()); });
|
||||
}
|
||||
this.OnAttach(() => { Get<IGameRepo>().Pause(); Output(new Output.ShowAskForTeleport()); });
|
||||
this.OnDetach(() => { Output(new Output.HideAskForTeleport()); });
|
||||
}
|
||||
|
||||
public Transition On(in Input.FloorExitReached input) => To<FloorClearedDecisionState>();
|
||||
public Transition On(in Input.FloorExitReached input) => To<FloorClearedDecisionState>();
|
||||
|
||||
public Transition On(in Input.HideAskForTeleport input)
|
||||
{
|
||||
return To<Playing>();
|
||||
}
|
||||
public Transition On(in Input.HideAskForTeleport input)
|
||||
{
|
||||
return To<Playing>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,31 +1,29 @@
|
||||
using Chickensoft.Introspection;
|
||||
using Chickensoft.LogicBlocks;
|
||||
|
||||
namespace GameJamDungeon
|
||||
namespace GameJamDungeon;
|
||||
|
||||
public partial class GameLogic
|
||||
{
|
||||
public partial class GameLogic
|
||||
public partial record State
|
||||
{
|
||||
public partial record State
|
||||
[Meta]
|
||||
public partial record FloorClearedDecisionState : Playing, IGet<Input.GoToNextFloor>, IGet<Input.HideFloorClearMenu>
|
||||
{
|
||||
[Meta]
|
||||
public partial record FloorClearedDecisionState : Playing, IGet<Input.GoToNextFloor>, IGet<Input.HideFloorClearMenu>
|
||||
public FloorClearedDecisionState()
|
||||
{
|
||||
public FloorClearedDecisionState()
|
||||
{
|
||||
this.OnAttach(() => { Get<IGameRepo>().Pause(); Output(new Output.ShowFloorClearMenu()); });
|
||||
this.OnDetach(() => { Output(new Output.ExitFloorClearMenu()); });
|
||||
}
|
||||
this.OnAttach(() => { Get<IGameRepo>().Pause(); Output(new Output.ShowFloorClearMenu()); });
|
||||
this.OnDetach(() => { Output(new Output.ExitFloorClearMenu()); });
|
||||
}
|
||||
|
||||
public Transition On(in Input.GoToNextFloor input)
|
||||
{
|
||||
Output(new Output.LoadNextFloor());
|
||||
return ToSelf();
|
||||
}
|
||||
public Transition On(in Input.GoToNextFloor input)
|
||||
{
|
||||
Output(new Output.LoadNextFloor());
|
||||
return ToSelf();
|
||||
}
|
||||
|
||||
public Transition On(in Input.HideFloorClearMenu input)
|
||||
{
|
||||
return To<Playing>();
|
||||
}
|
||||
public Transition On(in Input.HideFloorClearMenu input)
|
||||
{
|
||||
return To<Playing>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,26 +1,25 @@
|
||||
using Chickensoft.Introspection;
|
||||
using Chickensoft.LogicBlocks;
|
||||
|
||||
namespace GameJamDungeon
|
||||
{
|
||||
public partial class GameLogic
|
||||
{
|
||||
public partial record State
|
||||
{
|
||||
[Meta]
|
||||
public partial record GameStarted : State, IGet<Input.Initialize>
|
||||
{
|
||||
public GameStarted()
|
||||
{
|
||||
this.OnEnter(() => { Get<IGameRepo>().Pause(); });
|
||||
this.OnExit(() => { Get<IGameRepo>().Resume(); });
|
||||
}
|
||||
namespace GameJamDungeon;
|
||||
|
||||
public Transition On(in Input.Initialize input)
|
||||
{
|
||||
Output(new Output.StartGame());
|
||||
return To<Playing>();
|
||||
}
|
||||
public partial class GameLogic
|
||||
{
|
||||
public partial record State
|
||||
{
|
||||
[Meta]
|
||||
public partial record GameStarted : State, IGet<Input.Initialize>
|
||||
{
|
||||
public GameStarted()
|
||||
{
|
||||
this.OnEnter(() => { Get<IGameRepo>().Pause(); });
|
||||
this.OnExit(() => { Get<IGameRepo>().Resume(); });
|
||||
}
|
||||
|
||||
public Transition On(in Input.Initialize input)
|
||||
{
|
||||
Output(new Output.StartGame());
|
||||
return To<Playing>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,25 +1,24 @@
|
||||
using Chickensoft.Introspection;
|
||||
using Chickensoft.LogicBlocks;
|
||||
|
||||
namespace GameJamDungeon
|
||||
{
|
||||
public partial class GameLogic
|
||||
{
|
||||
public partial record State
|
||||
{
|
||||
[Meta]
|
||||
public partial record InventoryOpened : Playing, IGet<Input.CloseInventory>
|
||||
{
|
||||
public InventoryOpened()
|
||||
{
|
||||
this.OnEnter(() => { Get<IGameRepo>().Pause(); Output(new Output.OpenInventory()); });
|
||||
this.OnExit(() => { Get<IGameRepo>().Resume(); Output(new Output.HideInventory()); });
|
||||
}
|
||||
namespace GameJamDungeon;
|
||||
|
||||
public Transition On(in Input.CloseInventory input)
|
||||
{
|
||||
return To<Playing>();
|
||||
}
|
||||
public partial class GameLogic
|
||||
{
|
||||
public partial record State
|
||||
{
|
||||
[Meta]
|
||||
public partial record InventoryOpened : Playing, IGet<Input.CloseInventory>
|
||||
{
|
||||
public InventoryOpened()
|
||||
{
|
||||
this.OnEnter(() => { Get<IGameRepo>().Pause(); Output(new Output.OpenInventory()); });
|
||||
this.OnExit(() => { Get<IGameRepo>().Resume(); Output(new Output.HideInventory()); });
|
||||
}
|
||||
|
||||
public Transition On(in Input.CloseInventory input)
|
||||
{
|
||||
return To<Playing>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,23 +1,22 @@
|
||||
using Chickensoft.Introspection;
|
||||
using Chickensoft.LogicBlocks;
|
||||
|
||||
namespace GameJamDungeon
|
||||
{
|
||||
public partial class GameLogic
|
||||
{
|
||||
public partial record State
|
||||
{
|
||||
[Meta]
|
||||
public partial record MinimapOpen : Playing, IGet<Input.MiniMapButtonReleased>
|
||||
{
|
||||
public MinimapOpen()
|
||||
{
|
||||
this.OnEnter(() => { Get<IGameRepo>().Pause(); Output(new Output.ShowMiniMap()); });
|
||||
this.OnExit(() => { Get<IGameRepo>().Resume(); Output(new Output.HideMiniMap()); });
|
||||
}
|
||||
namespace GameJamDungeon;
|
||||
|
||||
public Transition On(in Input.MiniMapButtonReleased input) => To<Playing>();
|
||||
public partial class GameLogic
|
||||
{
|
||||
public partial record State
|
||||
{
|
||||
[Meta]
|
||||
public partial record MinimapOpen : Playing, IGet<Input.MiniMapButtonReleased>
|
||||
{
|
||||
public MinimapOpen()
|
||||
{
|
||||
this.OnEnter(() => { Get<IGameRepo>().Pause(); Output(new Output.ShowMiniMap()); });
|
||||
this.OnExit(() => { Get<IGameRepo>().Resume(); Output(new Output.HideMiniMap()); });
|
||||
}
|
||||
|
||||
public Transition On(in Input.MiniMapButtonReleased input) => To<Playing>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,27 +1,26 @@
|
||||
using Chickensoft.Introspection;
|
||||
using Chickensoft.LogicBlocks;
|
||||
|
||||
namespace GameJamDungeon
|
||||
{
|
||||
public partial class GameLogic
|
||||
{
|
||||
public partial record State
|
||||
{
|
||||
[Meta]
|
||||
public partial record Paused : Playing, IGet<Input.UnpauseGame>
|
||||
{
|
||||
public Paused()
|
||||
{
|
||||
this.OnEnter(() =>
|
||||
{
|
||||
Get<IGameRepo>().Pause();
|
||||
Output(new Output.ShowPauseMenu());
|
||||
});
|
||||
this.OnExit(() => Output(new Output.ExitPauseMenu()));
|
||||
}
|
||||
namespace GameJamDungeon;
|
||||
|
||||
public virtual Transition On(in Input.UnpauseGame input) => To<Resuming>();
|
||||
public partial class GameLogic
|
||||
{
|
||||
public partial record State
|
||||
{
|
||||
[Meta]
|
||||
public partial record Paused : Playing, IGet<Input.UnpauseGame>
|
||||
{
|
||||
public Paused()
|
||||
{
|
||||
this.OnEnter(() =>
|
||||
{
|
||||
Get<IGameRepo>().Pause();
|
||||
Output(new Output.ShowPauseMenu());
|
||||
});
|
||||
this.OnExit(() => Output(new Output.ExitPauseMenu()));
|
||||
}
|
||||
|
||||
public virtual Transition On(in Input.UnpauseGame input) => To<Resuming>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,42 +1,40 @@
|
||||
using Chickensoft.Introspection;
|
||||
using Chickensoft.LogicBlocks;
|
||||
|
||||
namespace GameJamDungeon
|
||||
namespace GameJamDungeon;
|
||||
|
||||
public partial class GameLogic
|
||||
{
|
||||
public partial class GameLogic
|
||||
public partial record State
|
||||
{
|
||||
public partial record State
|
||||
[Meta]
|
||||
public partial record Playing : State,
|
||||
IGet<Input.OpenInventory>,
|
||||
IGet<Input.MiniMapButtonPressed>,
|
||||
IGet<Input.GameOver>,
|
||||
IGet<Input.AskForTeleport>,
|
||||
IGet<Input.PauseGame>,
|
||||
IGet<Input.GoToOverworld>
|
||||
{
|
||||
[Meta]
|
||||
public partial record Playing : State,
|
||||
IGet<Input.OpenInventory>,
|
||||
IGet<Input.MiniMapButtonPressed>,
|
||||
IGet<Input.GameOver>,
|
||||
IGet<Input.AskForTeleport>,
|
||||
IGet<Input.PauseGame>,
|
||||
IGet<Input.GoToOverworld>
|
||||
public Playing()
|
||||
{
|
||||
public Playing()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public void OnEnded() => Input(new Input.GameOver());
|
||||
public void OnEnded() => Input(new Input.GameOver());
|
||||
|
||||
public Transition On(in Input.OpenInventory input) => To<InventoryOpened>();
|
||||
public Transition On(in Input.OpenInventory input) => To<InventoryOpened>();
|
||||
|
||||
public Transition On(in Input.MiniMapButtonPressed input) => To<MinimapOpen>();
|
||||
public Transition On(in Input.MiniMapButtonPressed input) => To<MinimapOpen>();
|
||||
|
||||
public Transition On(in Input.GameOver input) => To<Quit>();
|
||||
public Transition On(in Input.GameOver input) => To<Quit>();
|
||||
|
||||
public Transition On(in Input.AskForTeleport input) => To<AskForTeleport>();
|
||||
public Transition On(in Input.AskForTeleport input) => To<AskForTeleport>();
|
||||
|
||||
public Transition On(in Input.PauseGame input) => To<Paused>();
|
||||
public Transition On(in Input.PauseGame input) => To<Paused>();
|
||||
|
||||
public Transition On(in Input.GoToOverworld input)
|
||||
{
|
||||
Output(new Output.GoToOverworld());
|
||||
return ToSelf();
|
||||
}
|
||||
public Transition On(in Input.GoToOverworld input)
|
||||
{
|
||||
Output(new Output.GoToOverworld());
|
||||
return ToSelf();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,19 +1,18 @@
|
||||
using Chickensoft.Introspection;
|
||||
using Chickensoft.LogicBlocks;
|
||||
|
||||
namespace GameJamDungeon
|
||||
namespace GameJamDungeon;
|
||||
|
||||
public partial class GameLogic
|
||||
{
|
||||
public partial class GameLogic
|
||||
public partial record State
|
||||
{
|
||||
public partial record State
|
||||
[Meta]
|
||||
public partial record Quit : State
|
||||
{
|
||||
[Meta]
|
||||
public partial record Quit : State
|
||||
public Quit()
|
||||
{
|
||||
public Quit()
|
||||
{
|
||||
this.OnEnter(() => Output(new Output.ShowLostScreen()));
|
||||
}
|
||||
this.OnEnter(() => Output(new Output.ShowLostScreen()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using Chickensoft.GodotNodeInterfaces;
|
||||
using Godot;
|
||||
|
||||
namespace GameJamDungeon;
|
||||
public interface IHitbox : IArea3D
|
||||
{
|
||||
}
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
using Chickensoft.AutoInject;
|
||||
using Chickensoft.GodotNodeInterfaces;
|
||||
using Chickensoft.Introspection;
|
||||
using GameJamDungeon;
|
||||
using Godot;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace GameJamDungeon;
|
||||
|
||||
public interface IInventoryMenu : IControl
|
||||
{
|
||||
public Task RedrawInventory();
|
||||
@@ -18,14 +19,13 @@ public partial class InventoryMenu : Control, IInventoryMenu
|
||||
{
|
||||
public override void _Notification(int what) => this.Notify(what);
|
||||
|
||||
[Dependency]
|
||||
public IGameRepo GameRepo => this.DependOn<IGameRepo>();
|
||||
[Dependency] public IGameRepo GameRepo => this.DependOn<IGameRepo>();
|
||||
|
||||
[Dependency]
|
||||
public IGame Game => this.DependOn<IGame>();
|
||||
[Dependency] public IGame Game => this.DependOn<IGame>();
|
||||
|
||||
[Dependency]
|
||||
public IGameEventDepot GameEventDepot => this.DependOn<IGameEventDepot>();
|
||||
[Dependency] public IPlayer Player => this.DependOn<IPlayer>();
|
||||
|
||||
[Dependency] public IGameEventDepot GameEventDepot => this.DependOn<IGameEventDepot>();
|
||||
|
||||
[Signal]
|
||||
public delegate void ClosedMenuEventHandler();
|
||||
@@ -78,20 +78,20 @@ public partial class InventoryMenu : Control, IInventoryMenu
|
||||
|
||||
public void OnResolved()
|
||||
{
|
||||
GameRepo.PlayerData.CurrentHP.Sync += CurrentHP_Sync;
|
||||
GameRepo.PlayerData.MaximumHP.Sync += MaximumHP_Sync;
|
||||
GameRepo.PlayerData.CurrentVT.Sync += CurrentVT_Sync;
|
||||
GameRepo.PlayerData.MaximumVT.Sync += MaximumVT_Sync;
|
||||
GameRepo.PlayerData.CurrentAttack.Sync += CurrentAttack_Sync;
|
||||
GameRepo.PlayerData.MaxAttack.Sync += MaxAttack_Sync;
|
||||
GameRepo.PlayerData.CurrentDefense.Sync += CurrentDefense_Sync;
|
||||
GameRepo.PlayerData.MaxDefense.Sync += MaxDefense_Sync;
|
||||
GameRepo.PlayerData.CurrentExp.Sync += CurrentExp_Sync;
|
||||
GameRepo.PlayerData.ExpToNextLevel.Sync += ExpToNextLevel_Sync;
|
||||
GameRepo.PlayerData.CurrentLevel.Sync += CurrentLevel_Sync;
|
||||
GameRepo.PlayerData.Inventory.EquippedWeapon.Sync += EquippedWeapon_Sync;
|
||||
GameRepo.PlayerData.Inventory.EquippedArmor.Sync += EquippedArmor_Sync;
|
||||
GameRepo.PlayerData.Inventory.EquippedAccessory.Sync += EquippedAccessory_Sync;
|
||||
Player.Stats.CurrentHP.Sync += CurrentHP_Sync;
|
||||
Player.Stats.MaximumHP.Sync += MaximumHP_Sync;
|
||||
Player.Stats.CurrentVT.Sync += CurrentVT_Sync;
|
||||
Player.Stats.MaximumVT.Sync += MaximumVT_Sync;
|
||||
Player.Stats.CurrentAttack.Sync += CurrentAttack_Sync;
|
||||
Player.Stats.MaxAttack.Sync += MaxAttack_Sync;
|
||||
Player.Stats.CurrentDefense.Sync += CurrentDefense_Sync;
|
||||
Player.Stats.MaxDefense.Sync += MaxDefense_Sync;
|
||||
Player.Stats.CurrentExp.Sync += CurrentExp_Sync;
|
||||
Player.Stats.ExpToNextLevel.Sync += ExpToNextLevel_Sync;
|
||||
Player.Stats.CurrentLevel.Sync += CurrentLevel_Sync;
|
||||
Player.Inventory.EquippedWeapon.Sync += EquippedWeapon_Sync;
|
||||
Player.Inventory.EquippedArmor.Sync += EquippedArmor_Sync;
|
||||
Player.Inventory.EquippedAccessory.Sync += EquippedAccessory_Sync;
|
||||
|
||||
Game.StatRaisedAlert += Game_StatRaisedAlert;
|
||||
SetProcessInput(false);
|
||||
@@ -110,44 +110,44 @@ public partial class InventoryMenu : Control, IInventoryMenu
|
||||
|
||||
private void EquippedAccessory_Sync(Accessory obj)
|
||||
{
|
||||
ATKBonusLabel.Text = $"{GameRepo.PlayerData.BonusAttack:+0;-#;\\.\\.\\.}";
|
||||
DEFBonusLabel.Text = $"{GameRepo.PlayerData.BonusDefense:+0;-#;\\.\\.\\.}";
|
||||
ATKBonusLabel.Text = $"{Player.Stats.BonusAttack.Value:+0;-#;\\.\\.\\.}";
|
||||
DEFBonusLabel.Text = $"{Player.Stats.BonusDefense.Value:+0;-#;\\.\\.\\.}";
|
||||
}
|
||||
|
||||
private void EquippedArmor_Sync(Armor obj)
|
||||
{
|
||||
ATKBonusLabel.Text = $"{GameRepo.PlayerData.BonusAttack:+0;-#;\\.\\.\\.}";
|
||||
DEFBonusLabel.Text = $"{GameRepo.PlayerData.BonusDefense:+0;-#;\\.\\.\\.}";
|
||||
ATKBonusLabel.Text = $"{Player.Stats.BonusAttack.Value:+0;-#;\\.\\.\\.}";
|
||||
DEFBonusLabel.Text = $"{Player.Stats.BonusDefense.Value:+0;-#;\\.\\.\\.}";
|
||||
}
|
||||
|
||||
private void EquippedWeapon_Sync(Weapon obj)
|
||||
{
|
||||
ATKBonusLabel.Text = $"{GameRepo.PlayerData.BonusAttack:+0;-#;\\.\\.\\.}";
|
||||
DEFBonusLabel.Text = $"{GameRepo.PlayerData.BonusDefense:+0;-#;\\.\\.\\.}";
|
||||
ATKBonusLabel.Text = $"{Player.Stats.BonusAttack.Value:+0;-#;\\.\\.\\.}";
|
||||
DEFBonusLabel.Text = $"{Player.Stats.BonusDefense.Value:+0;-#;\\.\\.\\.}";
|
||||
}
|
||||
|
||||
private void CurrentLevel_Sync(int obj) => CurrentLevelLabel.Text = $"Level {obj:D2}";
|
||||
|
||||
private void ExpToNextLevel_Sync(int obj) => EXPValue.Text = $"{GameRepo.PlayerData.CurrentExp.Value}/{obj}";
|
||||
private void ExpToNextLevel_Sync(int obj) => EXPValue.Text = $"{Player.Stats.CurrentExp.Value}/{obj}";
|
||||
|
||||
// TODO: Change font style when EXP Bonus effect is active
|
||||
private void CurrentExp_Sync(int obj) => EXPValue.Text = $"{obj}/{GameRepo.PlayerData.ExpToNextLevel.Value}";
|
||||
private void CurrentExp_Sync(int obj) => EXPValue.Text = $"{obj}/{Player.Stats.ExpToNextLevel.Value}";
|
||||
|
||||
private void MaxDefense_Sync(int obj) => DEFValue.Text = $"{GameRepo.PlayerData.CurrentDefense.Value}/{obj}";
|
||||
private void MaxDefense_Sync(int obj) => DEFValue.Text = $"{Player.Stats.CurrentDefense.Value}/{obj}";
|
||||
|
||||
private void CurrentDefense_Sync(int obj) => DEFValue.Text = $"{obj}/{GameRepo.PlayerData.MaxDefense.Value}";
|
||||
private void CurrentDefense_Sync(int obj) => DEFValue.Text = $"{obj}/{Player.Stats.MaxDefense.Value}";
|
||||
|
||||
private void MaxAttack_Sync(int obj) => ATKValue.Text = $"{GameRepo.PlayerData.CurrentAttack.Value}/{obj}";
|
||||
private void MaxAttack_Sync(int obj) => ATKValue.Text = $"{Player.Stats.CurrentAttack.Value}/{obj}";
|
||||
|
||||
private void CurrentAttack_Sync(int obj) => ATKValue.Text = $"{obj}/{GameRepo.PlayerData.MaxAttack.Value}";
|
||||
private void CurrentAttack_Sync(int obj) => ATKValue.Text = $"{obj}/{Player.Stats.MaxAttack.Value}";
|
||||
|
||||
private void MaximumVT_Sync(int obj) => VTValue.Text = $"{GameRepo.PlayerData.CurrentVT.Value}/{obj}";
|
||||
private void MaximumVT_Sync(int obj) => VTValue.Text = $"{Player.Stats.CurrentVT.Value}/{obj}";
|
||||
|
||||
private void CurrentVT_Sync(int obj) => VTValue.Text = $"{obj}/{GameRepo.PlayerData.MaximumVT.Value}";
|
||||
private void CurrentVT_Sync(int obj) => VTValue.Text = $"{obj}/{Player.Stats.MaximumVT.Value}";
|
||||
|
||||
private void MaximumHP_Sync(int obj) => HPValue.Text = $"{GameRepo.PlayerData.CurrentHP.Value}/{obj}";
|
||||
private void MaximumHP_Sync(int obj) => HPValue.Text = $"{Player.Stats.CurrentHP.Value}/{obj}";
|
||||
|
||||
private void CurrentHP_Sync(int obj) => HPValue.Text = $"{obj}/{GameRepo.PlayerData.MaximumHP.Value}";
|
||||
private void CurrentHP_Sync(int obj) => HPValue.Text = $"{obj}/{Player.Stats.MaximumHP.Value}";
|
||||
|
||||
public async Task RedrawInventory()
|
||||
{
|
||||
@@ -161,7 +161,7 @@ public partial class InventoryMenu : Control, IInventoryMenu
|
||||
#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
|
||||
public override void _Input(InputEvent @event)
|
||||
{
|
||||
var inventory = GameRepo.PlayerData.Inventory;
|
||||
var inventory = Player.Inventory;
|
||||
|
||||
if (@event.IsActionPressed(GameInputs.UiCancel))
|
||||
{
|
||||
@@ -249,8 +249,8 @@ public partial class InventoryMenu : Control, IInventoryMenu
|
||||
if (ItemSlots.Any())
|
||||
{
|
||||
var item = ItemSlots.ElementAt(_currentIndex).Item;
|
||||
ItemDescriptionTitle.Text = $"{item.Info.Name}";
|
||||
ItemEffectLabel.Text = $"{item.Info.Description}";
|
||||
ItemDescriptionTitle.Text = $"{item.ItemName}";
|
||||
ItemEffectLabel.Text = $"{item.Description}";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -267,7 +267,7 @@ public partial class InventoryMenu : Control, IInventoryMenu
|
||||
|
||||
if (currentItem is IEquipableItem equipable)
|
||||
{
|
||||
var isEquipped = GameRepo.PlayerData.Inventory.IsEquipped(equipable);
|
||||
var isEquipped = Player.Inventory.IsEquipped(equipable);
|
||||
UseButton.Text = isEquipped ? "Unequip" : "Equip";
|
||||
ThrowButton.Disabled = isEquipped ? true : false;
|
||||
ThrowButton.FocusMode = isEquipped ? FocusModeEnum.None : FocusModeEnum.All;
|
||||
@@ -311,7 +311,7 @@ public partial class InventoryMenu : Control, IInventoryMenu
|
||||
|
||||
private async void PopulateInventory()
|
||||
{
|
||||
var inventory = GameRepo.PlayerData.Inventory;
|
||||
var inventory = Player.Inventory;
|
||||
var numberOfItemsToDisplay = _currentPageNumber == InventoryPageNumber.FirstPage ? Mathf.Min(inventory.Items.Count, _itemsPerPage) : Mathf.Min(inventory.Items.Count - _itemsPerPage, _itemsPerPage);
|
||||
var indexToStart = _currentPageNumber == InventoryPageNumber.FirstPage ? 0 : _itemsPerPage;
|
||||
|
||||
@@ -338,14 +338,14 @@ public partial class InventoryMenu : Control, IInventoryMenu
|
||||
itemSlot.Item = item;
|
||||
ItemsPage.AddChildEx(itemSlot);
|
||||
|
||||
if (itemSlot.Item is IEquipableItem equipable && GameRepo.PlayerData.Inventory.IsEquipped(equipable))
|
||||
if (itemSlot.Item is IEquipableItem equipable && Player.Inventory.IsEquipped(equipable))
|
||||
itemSlot.SetEquippedItemStyle();
|
||||
}
|
||||
|
||||
if (ItemSlots.Any())
|
||||
{
|
||||
ItemSlots.ElementAt(_currentIndex).SetSelectedItemStyle();
|
||||
if (ItemSlots.ElementAt(_currentIndex).Item is IEquipableItem equipable && GameRepo.PlayerData.Inventory.IsEquipped(equipable))
|
||||
if (ItemSlots.ElementAt(_currentIndex).Item is IEquipableItem equipable && Player.Inventory.IsEquipped(equipable))
|
||||
ItemSlots.ElementAt(_currentIndex).SetEquippedSelectedItemStyle();
|
||||
}
|
||||
}
|
||||
@@ -354,7 +354,7 @@ public partial class InventoryMenu : Control, IInventoryMenu
|
||||
{
|
||||
await ToSignal(GetTree().CreateTimer(0.1f), "timeout");
|
||||
itemSlot.SetItemStyle();
|
||||
if (itemSlot.Item is IEquipableItem equipable && GameRepo.PlayerData.Inventory.IsEquipped(equipable))
|
||||
if (itemSlot.Item is IEquipableItem equipable && Player.Inventory.IsEquipped(equipable))
|
||||
itemSlot.SetEquippedItemStyle();
|
||||
}
|
||||
|
||||
@@ -362,8 +362,8 @@ public partial class InventoryMenu : Control, IInventoryMenu
|
||||
{
|
||||
await ToSignal(GetTree().CreateTimer(0.1f), "timeout");
|
||||
itemSlot.SetSelectedItemStyle();
|
||||
ItemDescriptionTitle.Text = $"{itemSlot.Item.Info.Name}";
|
||||
ItemEffectLabel.Text = $"{itemSlot.Item.Info.Description}";
|
||||
ItemDescriptionTitle.Text = $"{itemSlot.Item.ItemName}";
|
||||
ItemEffectLabel.Text = $"{itemSlot.Item.Description}";
|
||||
}
|
||||
|
||||
private async Task EquipOrUnequipItem()
|
||||
@@ -371,16 +371,16 @@ public partial class InventoryMenu : Control, IInventoryMenu
|
||||
var itemSlot = ItemSlots[_currentIndex];
|
||||
if (itemSlot.Item is IEquipableItem equipableItem)
|
||||
{
|
||||
if (GameRepo.PlayerData.Inventory.IsEquipped(equipableItem))
|
||||
if (Player.Inventory.IsEquipped(equipableItem))
|
||||
{
|
||||
ItemEffectLabel.Text = $"{itemSlot.Item.GetType()} unequipped.";
|
||||
GameRepo.PlayerData.Inventory.Unequip(equipableItem);
|
||||
Player.Inventory.Unequip(equipableItem);
|
||||
itemSlot.SetSelectedItemStyle();
|
||||
}
|
||||
else
|
||||
{
|
||||
ItemEffectLabel.Text = $"{itemSlot.Item.GetType()} equipped.";
|
||||
GameRepo.PlayerData.Inventory.Equip(equipableItem);
|
||||
Player.Inventory.Equip(equipableItem);
|
||||
itemSlot.SetEquippedSelectedItemStyle();
|
||||
}
|
||||
|
||||
@@ -404,7 +404,7 @@ public partial class InventoryMenu : Control, IInventoryMenu
|
||||
|
||||
private async void DestroyItem(IUsableItem usableItem)
|
||||
{
|
||||
GameRepo.PlayerData.Inventory.Remove(usableItem);
|
||||
Player.Inventory.Remove(usableItem);
|
||||
if (_currentIndex >= ItemSlots.Length - 1)
|
||||
_currentIndex--;
|
||||
if (_currentIndex <= 0)
|
||||
@@ -416,7 +416,7 @@ public partial class InventoryMenu : Control, IInventoryMenu
|
||||
var currentItem = ItemSlots[_currentIndex].Item;
|
||||
|
||||
Game.ThrowItem(currentItem);
|
||||
GameRepo.PlayerData.Inventory.Remove(currentItem);
|
||||
Player.Inventory.Remove(currentItem);
|
||||
|
||||
if (_currentIndex >= ItemSlots.Length - 1)
|
||||
_currentIndex--;
|
||||
@@ -430,7 +430,7 @@ public partial class InventoryMenu : Control, IInventoryMenu
|
||||
{
|
||||
var currentItem = ItemSlots[_currentIndex].Item;
|
||||
Game.DropItem(currentItem);
|
||||
GameRepo.PlayerData.Inventory.Remove(currentItem);
|
||||
Player.Inventory.Remove(currentItem);
|
||||
|
||||
if (_currentIndex >= ItemSlots.Length - 1)
|
||||
_currentIndex--;
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
using GameJamDungeon;
|
||||
using Godot;
|
||||
|
||||
namespace GameJamDungeon;
|
||||
|
||||
public partial class ItemLabel : Label
|
||||
{
|
||||
public ItemLabel()
|
||||
@@ -8,8 +10,6 @@ public partial class ItemLabel : Label
|
||||
LabelSettings = UnequippedItemFont;
|
||||
}
|
||||
|
||||
public IInventoryItem InventoryItem { get; set; } = default!;
|
||||
|
||||
private static LabelSettings UnequippedItemFont => GD.Load<LabelSettings>("res://src/ui/label_settings/MainTextRegular.tres");
|
||||
private static LabelSettings EquippedItemFont => GD.Load<LabelSettings>("res://src/ui/label_settings/MainTextFontEquipped.tres");
|
||||
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
using Chickensoft.AutoInject;
|
||||
using Chickensoft.GodotNodeInterfaces;
|
||||
using Chickensoft.Introspection;
|
||||
using GameJamDungeon;
|
||||
using Godot;
|
||||
|
||||
namespace GameJamDungeon;
|
||||
|
||||
public interface IItemSlot : IHBoxContainer
|
||||
{
|
||||
public IInventoryItem Item { get; set; }
|
||||
@@ -22,8 +23,9 @@ public partial class ItemSlot : HBoxContainer, IItemSlot
|
||||
{
|
||||
public override void _Notification(int what) => this.Notify(what);
|
||||
|
||||
[Dependency]
|
||||
public IGameRepo GameRepo => this.DependOn<IGameRepo>();
|
||||
[Dependency] public IGameRepo GameRepo => this.DependOn<IGameRepo>();
|
||||
|
||||
[Dependency] public IPlayer Player => this.DependOn<IPlayer>();
|
||||
|
||||
//[Node] public Label EquipBonus { get; set; } = default!;
|
||||
|
||||
@@ -39,12 +41,12 @@ public partial class ItemSlot : HBoxContainer, IItemSlot
|
||||
|
||||
public void OnReady()
|
||||
{
|
||||
ItemName.Text = Item.Info.Name;
|
||||
ItemName.Text = Item.ItemName;
|
||||
//EquipBonus.Text = "...";
|
||||
ItemTexture.Texture = Item.Info.Texture;
|
||||
GameRepo.PlayerData.Inventory.EquippedWeapon.Sync += EquippedWeapon_Sync;
|
||||
GameRepo.PlayerData.Inventory.EquippedArmor.Sync += EquippedArmor_Sync;
|
||||
GameRepo.PlayerData.Inventory.EquippedAccessory.Sync += EquippedAccessory_Sync;
|
||||
ItemTexture.Texture = Item.GetTexture();
|
||||
Player.Inventory.EquippedWeapon.Sync += EquippedWeapon_Sync;
|
||||
Player.Inventory.EquippedArmor.Sync += EquippedArmor_Sync;
|
||||
Player.Inventory.EquippedAccessory.Sync += EquippedAccessory_Sync;
|
||||
}
|
||||
|
||||
private void EquippedWeapon_Sync(Weapon obj)
|
||||
@@ -90,7 +92,7 @@ public partial class ItemSlot : HBoxContainer, IItemSlot
|
||||
}
|
||||
public void SetSelectedItemStyle()
|
||||
{
|
||||
if (Item is IEquipableItem equipableItem && GameRepo.PlayerData.Inventory.IsEquipped(equipableItem))
|
||||
if (Item is IEquipableItem equipableItem && Player.Inventory.IsEquipped(equipableItem))
|
||||
{
|
||||
ItemName.LabelSettings = SelectedEquippedItemFont;
|
||||
//EquipBonus.LabelSettings = EquippedItemFont;
|
||||
|
||||
@@ -3,6 +3,8 @@ using Chickensoft.Introspection;
|
||||
using GameJamDungeon;
|
||||
using Godot;
|
||||
|
||||
namespace GameJamDungeon;
|
||||
|
||||
[Meta(typeof(IAutoNode))]
|
||||
public partial class ItemRescue : Area3D
|
||||
{
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace GameJamDungeon.src.item_rescue
|
||||
{
|
||||
public class RescuedItemDatabase
|
||||
{
|
||||
public List<IInventoryItem> Items;
|
||||
namespace GameJamDungeon;
|
||||
|
||||
public RescuedItemDatabase()
|
||||
{
|
||||
Items = new List<IInventoryItem>();
|
||||
}
|
||||
public class RescuedItemDatabase
|
||||
{
|
||||
public List<IInventoryItem> Items;
|
||||
|
||||
public RescuedItemDatabase()
|
||||
{
|
||||
Items = new List<IInventoryItem>();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,8 @@ using Godot;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace GameJamDungeon;
|
||||
|
||||
[Meta(typeof(IAutoNode))]
|
||||
public partial class RescuedItems : Node3D
|
||||
{
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
namespace GameJamDungeon
|
||||
{
|
||||
public interface IEquipableItem : IInventoryItem
|
||||
{
|
||||
public void Equip();
|
||||
namespace GameJamDungeon;
|
||||
|
||||
public void Unequip();
|
||||
}
|
||||
public interface IEquipableItem : IInventoryItem
|
||||
{
|
||||
public void Equip();
|
||||
|
||||
public void Unequip();
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
using Chickensoft.GodotNodeInterfaces;
|
||||
using Godot;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
@@ -34,6 +33,8 @@ public interface IInventory : INode
|
||||
event Inventory.PickedUpItemEventHandler PickedUpItem;
|
||||
|
||||
event Inventory.AccessoryUnequippedEventHandler AccessoryUnequipped;
|
||||
|
||||
event Inventory.RaiseStatRequestEventHandler RaiseStatRequest;
|
||||
}
|
||||
|
||||
public partial class Inventory : Node, IInventory
|
||||
@@ -44,7 +45,7 @@ public partial class Inventory : Node, IInventory
|
||||
[Signal]
|
||||
public delegate void InventoryAtCapacityEventHandler(string rejectedItemName);
|
||||
[Signal]
|
||||
public delegate void AccessoryUnequippedEventHandler(AccessoryStats unequippedAccessory);
|
||||
public delegate void AccessoryUnequippedEventHandler(Accessory unequippedAccessory);
|
||||
[Signal]
|
||||
public delegate void RaiseStatRequestEventHandler(ConsumableItemStats consumableItemStats);
|
||||
[Signal]
|
||||
@@ -70,12 +71,12 @@ public partial class Inventory : Node, IInventory
|
||||
{
|
||||
if (Items.Count >= _maxInventorySize)
|
||||
{
|
||||
EmitSignal(SignalName.InventoryAtCapacity, inventoryItem.Info.Name);
|
||||
EmitSignal(SignalName.InventoryAtCapacity, inventoryItem.ItemName);
|
||||
return false;
|
||||
}
|
||||
|
||||
Items.Add(inventoryItem);
|
||||
EmitSignal(SignalName.PickedUpItem, inventoryItem.Info.Name);
|
||||
EmitSignal(SignalName.PickedUpItem, inventoryItem.ItemName);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -98,14 +99,14 @@ public partial class Inventory : Node, IInventory
|
||||
if (equipable is Weapon weapon)
|
||||
{
|
||||
_equippedWeapon.OnNext(new Weapon());
|
||||
if (weapon.WeaponStats.WeaponTags.Contains(WeaponTag.BreaksOnChange))
|
||||
if (weapon.WeaponTags.Contains(WeaponTag.BreaksOnChange))
|
||||
Items.Remove(weapon);
|
||||
}
|
||||
else if (equipable is Armor armor)
|
||||
_equippedArmor.OnNext(new Armor());
|
||||
else if (equipable is Accessory accessory)
|
||||
{
|
||||
EmitSignal(SignalName.AccessoryUnequipped, _equippedAccessory.Value.AccessoryStats);
|
||||
EmitSignal(SignalName.AccessoryUnequipped, _equippedAccessory.Value);
|
||||
_equippedAccessory.OnNext(new Accessory());
|
||||
}
|
||||
else
|
||||
@@ -146,10 +147,10 @@ public partial class Inventory : Node, IInventory
|
||||
{
|
||||
public int Compare(Weapon x, Weapon y)
|
||||
{
|
||||
if (x.WeaponStats.Damage == y.WeaponStats.Damage)
|
||||
return x.WeaponStats.Name.CompareTo(y.WeaponStats.Name);
|
||||
if (x.Damage == y.Damage)
|
||||
return x.ItemName.CompareTo(y.ItemName);
|
||||
|
||||
return x.WeaponStats.Damage < y.WeaponStats.Damage ? 1 : -1;
|
||||
return x.Damage < y.Damage ? 1 : -1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -157,10 +158,10 @@ public partial class Inventory : Node, IInventory
|
||||
{
|
||||
public int Compare(Armor x, Armor y)
|
||||
{
|
||||
if (x.ArmorStats.Defense == y.ArmorStats.Defense)
|
||||
return x.ArmorStats.Name.CompareTo(y.ArmorStats.Name);
|
||||
if (x.Defense == y.Defense)
|
||||
return x.ItemName.CompareTo(y.ItemName);
|
||||
|
||||
return x.ArmorStats.Defense < y.ArmorStats.Defense ? 1 : -1;
|
||||
return x.Defense < y.Defense ? 1 : -1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -168,7 +169,7 @@ public partial class Inventory : Node, IInventory
|
||||
{
|
||||
public int Compare(Accessory x, Accessory y)
|
||||
{
|
||||
return x.AccessoryStats.Name.CompareTo(y.AccessoryStats.Name);
|
||||
return x.ItemName.CompareTo(y.ItemName);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -176,14 +177,14 @@ public partial class Inventory : Node, IInventory
|
||||
{
|
||||
public int Compare(ConsumableItem x, ConsumableItem y)
|
||||
{
|
||||
return x.ConsumableItemInfo.Name.CompareTo(y.ConsumableItemInfo.Name);
|
||||
return x.ItemName.CompareTo(y.ItemName);
|
||||
}
|
||||
}
|
||||
public class ThrowableComparer : IComparer<ThrowableItem>
|
||||
{
|
||||
public int Compare(ThrowableItem x, ThrowableItem y)
|
||||
{
|
||||
return x.ThrowableItemInfo.Name.CompareTo(y.ThrowableItemInfo.Name);
|
||||
return x.ItemName.CompareTo(y.ItemName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,17 +1,29 @@
|
||||
using Chickensoft.GodotNodeInterfaces;
|
||||
using Godot;
|
||||
using System;
|
||||
|
||||
namespace GameJamDungeon
|
||||
namespace GameJamDungeon;
|
||||
|
||||
public interface IInventoryItem : INode3D
|
||||
{
|
||||
public interface IInventoryItem : INode3D
|
||||
{
|
||||
public Guid ID { get; }
|
||||
public Guid ID { get; }
|
||||
|
||||
public InventoryItemStats Info { get; }
|
||||
}
|
||||
string ItemName { get; }
|
||||
|
||||
public interface IUsableItem : IInventoryItem
|
||||
{
|
||||
public void Use();
|
||||
}
|
||||
string Description { get; }
|
||||
|
||||
float SpawnRate { get; }
|
||||
|
||||
double ThrowDamage { get; }
|
||||
|
||||
float ThrowSpeed { get; }
|
||||
|
||||
Texture2D GetTexture();
|
||||
|
||||
public void SetItemStats(InventoryItemStats inventoryItemStats);
|
||||
}
|
||||
|
||||
public interface IUsableItem : IInventoryItem
|
||||
{
|
||||
public void Use();
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using Godot;
|
||||
|
||||
namespace GameJamDungeon;
|
||||
public partial class InventoryItemStats : Resource
|
||||
{
|
||||
[Export]
|
||||
|
||||
@@ -1,75 +1,74 @@
|
||||
using Godot;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace GameJamDungeon
|
||||
namespace GameJamDungeon;
|
||||
|
||||
public partial class ItemDatabase : Node
|
||||
{
|
||||
public partial class ItemDatabase : Node
|
||||
[Export]
|
||||
public PackedScene WeaponScene { get; set; }
|
||||
|
||||
[Export]
|
||||
public PackedScene ArmorScene { get; set; }
|
||||
|
||||
[Export]
|
||||
public PackedScene AccessoryScene { get; set; }
|
||||
|
||||
[Export]
|
||||
public PackedScene ThrowableItemScene { get; set; }
|
||||
|
||||
[Export]
|
||||
public PackedScene ConsumableItemScene { get; set; }
|
||||
|
||||
public IInventoryItem[] Initialize()
|
||||
{
|
||||
[Export]
|
||||
public PackedScene WeaponScene { get; set; }
|
||||
var database = new List<IInventoryItem>();
|
||||
var armorResources = DirAccess.GetFilesAt("res://src/items/armor/resources/");
|
||||
var weaponResources = DirAccess.GetFilesAt("res://src/items/weapons/resources/");
|
||||
var accessoryResources = DirAccess.GetFilesAt("res://src/items/accessory/resources/");
|
||||
var throwableResources = DirAccess.GetFilesAt("res://src/items/throwable/resources/");
|
||||
var consumableResources = DirAccess.GetFilesAt("res://src/items/consumable/resources/");
|
||||
|
||||
[Export]
|
||||
public PackedScene ArmorScene { get; set; }
|
||||
|
||||
[Export]
|
||||
public PackedScene AccessoryScene { get; set; }
|
||||
|
||||
[Export]
|
||||
public PackedScene ThrowableItemScene { get; set; }
|
||||
|
||||
[Export]
|
||||
public PackedScene ConsumableItemScene { get; set; }
|
||||
|
||||
public IInventoryItem[] Initialize()
|
||||
foreach (var armor in armorResources)
|
||||
{
|
||||
var database = new List<IInventoryItem>();
|
||||
var armorResources = DirAccess.GetFilesAt("res://src/items/armor/resources/");
|
||||
var weaponResources = DirAccess.GetFilesAt("res://src/items/weapons/resources/");
|
||||
var accessoryResources = DirAccess.GetFilesAt("res://src/items/accessory/resources/");
|
||||
var throwableResources = DirAccess.GetFilesAt("res://src/items/throwable/resources/");
|
||||
var consumableResources = DirAccess.GetFilesAt("res://src/items/consumable/resources/");
|
||||
|
||||
foreach (var armor in armorResources)
|
||||
{
|
||||
var armorInfo = GD.Load<ArmorStats>($"res://src/items/armor/resources/{armor}");
|
||||
var armorScene = ArmorScene.Instantiate<Armor>();
|
||||
armorScene.ArmorStats = armorInfo;
|
||||
database.Add(armorScene);
|
||||
}
|
||||
|
||||
foreach (var weapon in weaponResources)
|
||||
{
|
||||
var weaponInfo = GD.Load<WeaponStats>($"res://src/items/weapons/resources/{weapon}");
|
||||
var weaponScene = WeaponScene.Instantiate<Weapon>();
|
||||
weaponScene.WeaponStats = weaponInfo;
|
||||
database.Add(weaponScene);
|
||||
}
|
||||
|
||||
foreach (var accessory in accessoryResources)
|
||||
{
|
||||
var accessoryInfo = GD.Load<AccessoryStats>($"res://src/items/accessory/resources/{accessory}");
|
||||
var accessoryScene = AccessoryScene.Instantiate<Accessory>();
|
||||
accessoryScene.AccessoryStats = accessoryInfo;
|
||||
database.Add(accessoryScene);
|
||||
}
|
||||
|
||||
foreach (var throwable in throwableResources)
|
||||
{
|
||||
var throwableItemInfo = GD.Load<ThrowableItemStats>($"res://src/items/throwable/resources/{throwable}");
|
||||
var throwableItemScene = ThrowableItemScene.Instantiate<ThrowableItem>();
|
||||
throwableItemScene.ThrowableItemInfo = throwableItemInfo;
|
||||
database.Add(throwableItemScene);
|
||||
}
|
||||
|
||||
foreach (var consumable in consumableResources)
|
||||
{
|
||||
var consumableItemInfo = GD.Load<ConsumableItemStats>($"res://src/items/consumable/resources/{consumable}");
|
||||
var consumableItemScene = ConsumableItemScene.Instantiate<ConsumableItem>();
|
||||
consumableItemScene.ConsumableItemInfo = consumableItemInfo;
|
||||
database.Add(consumableItemScene);
|
||||
}
|
||||
|
||||
return database.ToArray();
|
||||
var armorInfo = GD.Load<ArmorStats>($"res://src/items/armor/resources/{armor}");
|
||||
var armorScene = ArmorScene.Instantiate<Armor>();
|
||||
armorScene.SetItemStats(armorInfo);
|
||||
database.Add(armorScene);
|
||||
}
|
||||
|
||||
foreach (var weapon in weaponResources)
|
||||
{
|
||||
var weaponInfo = GD.Load<WeaponStats>($"res://src/items/weapons/resources/{weapon}");
|
||||
var weaponScene = WeaponScene.Instantiate<Weapon>();
|
||||
weaponScene.SetItemStats(weaponInfo);
|
||||
database.Add(weaponScene);
|
||||
}
|
||||
|
||||
foreach (var accessory in accessoryResources)
|
||||
{
|
||||
var accessoryInfo = GD.Load<AccessoryStats>($"res://src/items/accessory/resources/{accessory}");
|
||||
var accessoryScene = AccessoryScene.Instantiate<Accessory>();
|
||||
accessoryScene.SetItemStats(accessoryInfo);
|
||||
database.Add(accessoryScene);
|
||||
}
|
||||
|
||||
foreach (var throwable in throwableResources)
|
||||
{
|
||||
var throwableItemInfo = GD.Load<ThrowableItemStats>($"res://src/items/throwable/resources/{throwable}");
|
||||
var throwableItemScene = ThrowableItemScene.Instantiate<ThrowableItem>();
|
||||
throwableItemScene.SetItemStats(throwableItemInfo);
|
||||
database.Add(throwableItemScene);
|
||||
}
|
||||
|
||||
foreach (var consumable in consumableResources)
|
||||
{
|
||||
var consumableItemInfo = GD.Load<ConsumableItemStats>($"res://src/items/consumable/resources/{consumable}");
|
||||
var consumableItemScene = ConsumableItemScene.Instantiate<ConsumableItem>();
|
||||
consumableItemScene.SetItemStats(consumableItemInfo);
|
||||
database.Add(consumableItemScene);
|
||||
}
|
||||
|
||||
return database.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
using Chickensoft.AutoInject;
|
||||
using Chickensoft.Introspection;
|
||||
using GameJamDungeon;
|
||||
using Godot;
|
||||
using System;
|
||||
using System.Collections.Immutable;
|
||||
|
||||
namespace GameJamDungeon;
|
||||
|
||||
[Meta(typeof(IAutoNode))]
|
||||
public partial class Accessory : Node3D, IEquipableItem
|
||||
@@ -13,21 +15,45 @@ public partial class Accessory : Node3D, IEquipableItem
|
||||
|
||||
[Dependency] public IGameEventDepot GameEventDepot => this.DependOn<IGameEventDepot>();
|
||||
|
||||
public InventoryItemStats Info => AccessoryStats;
|
||||
[Dependency] public IPlayer Player => this.DependOn<IPlayer>();
|
||||
|
||||
[Export]
|
||||
public AccessoryStats AccessoryStats { get; set; } = new AccessoryStats();
|
||||
[Export] private AccessoryStats _accessoryStats { get; set; } = new AccessoryStats();
|
||||
|
||||
[Node] public Sprite3D Sprite { get; set; } = default!;
|
||||
[Node] private Sprite3D Sprite { get; set; } = new Sprite3D();
|
||||
|
||||
[Node] public Area3D Pickup { get; set; } = default!;
|
||||
|
||||
public Guid ID => Guid.NewGuid();
|
||||
|
||||
public string ItemName => _accessoryStats.Name;
|
||||
|
||||
public string Description => _accessoryStats.Description;
|
||||
|
||||
public float SpawnRate => _accessoryStats.SpawnRate;
|
||||
|
||||
public Texture2D GetTexture() => _accessoryStats.Texture;
|
||||
|
||||
public double ThrowDamage => _accessoryStats.ThrowDamage;
|
||||
|
||||
public float ThrowSpeed => _accessoryStats.ThrowSpeed;
|
||||
|
||||
public int MaxHPUp => _accessoryStats.MaxHPUp;
|
||||
|
||||
public int MaxVTUp => _accessoryStats.MaxVTUp;
|
||||
|
||||
public double LuckUp => _accessoryStats.LuckUp;
|
||||
|
||||
public ImmutableList<AccessoryTag> AccessoryTags => [.. _accessoryStats.AccessoryTags];
|
||||
|
||||
public void OnReady()
|
||||
{
|
||||
Sprite.Texture = AccessoryStats.Texture;
|
||||
Pickup.BodyEntered += OnEntered;
|
||||
Sprite.Texture = _accessoryStats.Texture;
|
||||
}
|
||||
|
||||
public void SetItemStats(InventoryItemStats inventoryItemStats)
|
||||
{
|
||||
_accessoryStats = (AccessoryStats)inventoryItemStats;
|
||||
}
|
||||
|
||||
public void Equip()
|
||||
@@ -42,12 +68,12 @@ public partial class Accessory : Node3D, IEquipableItem
|
||||
|
||||
public void Throw()
|
||||
{
|
||||
GameRepo.PlayerData.Inventory.Remove(this);
|
||||
Player.Inventory.Remove(this);
|
||||
}
|
||||
|
||||
public void OnEntered(Node3D body)
|
||||
{
|
||||
var isAdded = GameRepo.PlayerData.Inventory.TryAdd(this);
|
||||
var isAdded = Player.Inventory.TryAdd(this);
|
||||
if (isAdded)
|
||||
QueueFree();
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using Godot;
|
||||
using System;
|
||||
|
||||
namespace GameJamDungeon;
|
||||
|
||||
@@ -13,7 +12,7 @@ public partial class AccessoryStats : InventoryItemStats
|
||||
public int DEFUp { get; set; } = 0;
|
||||
|
||||
[Export]
|
||||
public double LUCKUp { get; set; } = 0;
|
||||
public double LuckUp { get; set; } = 0;
|
||||
|
||||
[Export]
|
||||
public int MaxHPUp { get; set; } = 0;
|
||||
|
||||
@@ -1,33 +1,50 @@
|
||||
using Chickensoft.AutoInject;
|
||||
using Chickensoft.Introspection;
|
||||
using GameJamDungeon;
|
||||
using Godot;
|
||||
using System;
|
||||
|
||||
namespace GameJamDungeon;
|
||||
|
||||
[Meta(typeof(IAutoNode))]
|
||||
public partial class Armor : Node3D, IEquipableItem
|
||||
{
|
||||
public override void _Notification(int what) => this.Notify(what);
|
||||
|
||||
[Dependency] public IGameRepo GameRepo => this.DependOn<IGameRepo>();
|
||||
|
||||
[Dependency] public IGameEventDepot GameEventDepot => this.DependOn<IGameEventDepot>();
|
||||
|
||||
public InventoryItemStats Info => ArmorStats;
|
||||
[Dependency] public IPlayer Player => this.DependOn<IPlayer>();
|
||||
|
||||
[Export]
|
||||
public ArmorStats ArmorStats { get; set; } = new ArmorStats();
|
||||
[Export] private ArmorStats _armorStats { get; set; } = new ArmorStats();
|
||||
|
||||
[Node] public Sprite3D Sprite { get; set; } = default!;
|
||||
[Node] private Sprite3D Sprite { get; set; } = new Sprite3D();
|
||||
|
||||
[Node] public Area3D Pickup { get; set; } = default!;
|
||||
[Node] private Area3D Pickup { get; set; } = default!;
|
||||
|
||||
public Guid ID => Guid.NewGuid();
|
||||
|
||||
public string ItemName => _armorStats.Name;
|
||||
|
||||
public string Description => _armorStats.Description;
|
||||
|
||||
public float SpawnRate => _armorStats.SpawnRate;
|
||||
|
||||
public Texture2D GetTexture() => _armorStats.Texture;
|
||||
|
||||
public double ThrowDamage => _armorStats.ThrowDamage;
|
||||
|
||||
public float ThrowSpeed => _armorStats.ThrowSpeed;
|
||||
|
||||
public int Defense => _armorStats.Defense;
|
||||
|
||||
public void OnReady()
|
||||
{
|
||||
Sprite.Texture = ArmorStats.Texture;
|
||||
Pickup.BodyEntered += OnEntered;
|
||||
Sprite.Texture = _armorStats.Texture;
|
||||
}
|
||||
|
||||
public void SetItemStats(InventoryItemStats inventoryItemStats)
|
||||
{
|
||||
_armorStats = (ArmorStats)inventoryItemStats;
|
||||
}
|
||||
|
||||
public void Equip()
|
||||
@@ -42,17 +59,17 @@ public partial class Armor : Node3D, IEquipableItem
|
||||
|
||||
public void Throw()
|
||||
{
|
||||
GameRepo.PlayerData.Inventory.Remove(this);
|
||||
Player.Inventory.Remove(this);
|
||||
}
|
||||
|
||||
public void Drop()
|
||||
{
|
||||
GameRepo.PlayerData.Inventory.Remove(this);
|
||||
Player.Inventory.Remove(this);
|
||||
}
|
||||
|
||||
public void OnEntered(Node3D body)
|
||||
{
|
||||
var isAdded = GameRepo.PlayerData.Inventory.TryAdd(this);
|
||||
var isAdded = Player.Inventory.TryAdd(this);
|
||||
if (isAdded)
|
||||
QueueFree();
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[gd_scene load_steps=3 format=3 uid="uid://dorr7v1tkeiy0"]
|
||||
|
||||
[ext_resource type="Script" path="res://src/items/armor/Armor.cs" id="1_cmjpq"]
|
||||
[ext_resource type="Script" uid="uid://bxvre2y2caa3h" path="res://src/items/armor/Armor.cs" id="1_cmjpq"]
|
||||
|
||||
[sub_resource type="BoxShape3D" id="BoxShape3D_qdeu2"]
|
||||
size = Vector3(0.778381, 0.929947, 0.731567)
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
using Chickensoft.AutoInject;
|
||||
using Chickensoft.Introspection;
|
||||
using GameJamDungeon;
|
||||
using Godot;
|
||||
using System;
|
||||
|
||||
namespace GameJamDungeon;
|
||||
|
||||
[Meta(typeof(IAutoNode))]
|
||||
public partial class ConsumableItem : Node3D, IUsableItem
|
||||
{
|
||||
@@ -13,42 +14,57 @@ public partial class ConsumableItem : Node3D, IUsableItem
|
||||
public delegate void RaiseStatRequestEventHandler(ConsumableItemStats consumableItemStats);
|
||||
|
||||
[Dependency] public IGame Game => this.DependOn<IGame>();
|
||||
[Dependency] public IGameRepo GameRepo => this.DependOn<IGameRepo>();
|
||||
[Dependency] public IGameEventDepot GameEventDepot => this.DependOn<IGameEventDepot>();
|
||||
|
||||
public InventoryItemStats Info => ConsumableItemInfo;
|
||||
[Dependency] public IPlayer Player => this.DependOn<IPlayer>();
|
||||
|
||||
[Export]
|
||||
public ConsumableItemStats ConsumableItemInfo { get; set; }
|
||||
private ConsumableItemStats _consumableItemStats { get; set; }
|
||||
|
||||
[Node] public Sprite3D Sprite { get; set; } = default!;
|
||||
[Node] private Sprite3D Sprite { get; set; } = new Sprite3D();
|
||||
|
||||
[Node] public Area3D Pickup { get; set; } = default!;
|
||||
[Node] private Area3D Pickup { get; set; } = default!;
|
||||
|
||||
public Guid ID => Guid.NewGuid();
|
||||
|
||||
public string ItemName => _consumableItemStats.Name;
|
||||
|
||||
public string Description => _consumableItemStats.Description;
|
||||
|
||||
public float SpawnRate => _consumableItemStats.SpawnRate;
|
||||
|
||||
public Texture2D GetTexture() => _consumableItemStats.Texture;
|
||||
|
||||
public double ThrowDamage => _consumableItemStats.ThrowDamage;
|
||||
|
||||
public float ThrowSpeed => _consumableItemStats.ThrowSpeed;
|
||||
|
||||
public void Use()
|
||||
{
|
||||
if (ConsumableItemInfo.RaiseHPAmount > 0)
|
||||
Game.RaiseHP(ConsumableItemInfo.RaiseHPAmount);
|
||||
if (ConsumableItemInfo.RaiseVTAmount > 0)
|
||||
Game.RaiseVT(ConsumableItemInfo.RaiseVTAmount);
|
||||
if (_consumableItemStats.RaiseHPAmount > 0)
|
||||
Game.RaiseHP(_consumableItemStats.RaiseHPAmount);
|
||||
if (_consumableItemStats.RaiseVTAmount > 0)
|
||||
Game.RaiseVT(_consumableItemStats.RaiseVTAmount);
|
||||
|
||||
if (ConsumableItemInfo.HealHPAmount > 0 && GameRepo.PlayerData.CurrentHP.Value != GameRepo.PlayerData.MaximumHP.Value)
|
||||
Game.HealHP(ConsumableItemInfo.HealHPAmount);
|
||||
if (ConsumableItemInfo.HealVTAmount > 0 && GameRepo.PlayerData.CurrentVT.Value != GameRepo.PlayerData.MaximumVT.Value)
|
||||
Game.HealVT(ConsumableItemInfo.HealVTAmount);
|
||||
if (_consumableItemStats.HealHPAmount > 0 && Player.Stats.CurrentHP.Value != Player.Stats.MaximumHP.Value)
|
||||
Game.HealHP(_consumableItemStats.HealHPAmount);
|
||||
if (_consumableItemStats.HealVTAmount > 0 && Player.Stats.CurrentVT.Value != Player.Stats.MaximumVT.Value)
|
||||
Game.HealVT(_consumableItemStats.HealVTAmount);
|
||||
}
|
||||
|
||||
public void SetItemStats(InventoryItemStats inventoryItemStats)
|
||||
{
|
||||
_consumableItemStats = (ConsumableItemStats)inventoryItemStats;
|
||||
}
|
||||
|
||||
public void OnReady()
|
||||
{
|
||||
Sprite.Texture = ConsumableItemInfo.Texture;
|
||||
Pickup.BodyEntered += OnEntered;
|
||||
Sprite.Texture = _consumableItemStats.Texture;
|
||||
}
|
||||
|
||||
public void OnEntered(Node3D body)
|
||||
{
|
||||
var isAdded = GameRepo.PlayerData.Inventory.TryAdd(this);
|
||||
var isAdded = Player.Inventory.TryAdd(this);
|
||||
if (isAdded)
|
||||
QueueFree();
|
||||
}
|
||||
|
||||
@@ -3,86 +3,87 @@ using Chickensoft.GodotNodeInterfaces;
|
||||
using Chickensoft.Introspection;
|
||||
using Godot;
|
||||
|
||||
namespace GameJamDungeon
|
||||
namespace GameJamDungeon;
|
||||
|
||||
public interface IDroppedItem : IRigidBody3D
|
||||
{
|
||||
public interface IDroppedItem : IRigidBody3D
|
||||
void RescueItem();
|
||||
}
|
||||
|
||||
[Meta(typeof(IAutoNode))]
|
||||
public partial class DroppedItem : RigidBody3D, IDroppedItem
|
||||
{
|
||||
public override void _Notification(int what) => this.Notify(what);
|
||||
|
||||
[Dependency] public IGameRepo GameRepo => this.DependOn<IGameRepo>();
|
||||
|
||||
[Dependency] public IGame Game => this.DependOn<IGame>();
|
||||
|
||||
[Dependency] public IPlayer Player => this.DependOn<IPlayer>();
|
||||
|
||||
[Node] private Sprite2D Sprite { get; set; } = default!;
|
||||
|
||||
public IInventoryItem Item { get; set; }
|
||||
|
||||
public void OnResolved()
|
||||
{
|
||||
void RescueItem();
|
||||
ContactMonitor = true;
|
||||
BodyEntered += DroppedItem_BodyEntered;
|
||||
Sprite.Texture = Item.GetTexture();
|
||||
}
|
||||
|
||||
[Meta(typeof(IAutoNode))]
|
||||
public partial class DroppedItem : RigidBody3D, IDroppedItem
|
||||
public async void Drop()
|
||||
{
|
||||
public override void _Notification(int what) => this.Notify(what);
|
||||
AddCollisionExceptionWith((Node)Game.Player);
|
||||
GlobalPosition = Player.CurrentPosition + Vector3.Up;
|
||||
ApplyCentralImpulse(-Player.CurrentBasis.Z.Normalized() * 5.0f);
|
||||
await ToSignal(GetTree().CreateTimer(1.5), "timeout");
|
||||
RemoveCollisionExceptionWith((Node)Game.Player);
|
||||
}
|
||||
|
||||
[Dependency] public IGameRepo GameRepo => this.DependOn<IGameRepo>();
|
||||
public void RescueItem()
|
||||
{
|
||||
ContactMonitor = false;
|
||||
PlayRescueAnimation();
|
||||
Game.RescuedItems.Items.Add(Item);
|
||||
}
|
||||
|
||||
[Dependency] public IGame Game => this.DependOn<IGame>();
|
||||
private void PlayRescueAnimation()
|
||||
{
|
||||
LoadShader("res://src/vfx/shaders/PixelMelt.gdshader");
|
||||
var tweener = GetTree().CreateTween();
|
||||
SetShaderValue(true);
|
||||
tweener.TweenMethod(Callable.From((float x) => SetShaderValue(x)), 0.0f, 0.3f, 2f);
|
||||
tweener.TweenCallback(Callable.From(QueueFree));
|
||||
}
|
||||
|
||||
[Node] public Sprite2D Sprite { get; set; } = default!;
|
||||
private void LoadShader(string shaderPath)
|
||||
{
|
||||
var shader = GD.Load<Shader>(shaderPath);
|
||||
Sprite.Material = new ShaderMaterial();
|
||||
var shaderMaterial = (ShaderMaterial)Sprite.Material;
|
||||
shaderMaterial.Shader = shader;
|
||||
}
|
||||
|
||||
public IInventoryItem Item { get; set; }
|
||||
private void SetShaderValue(float shaderValue)
|
||||
{
|
||||
var shaderMaterial = (ShaderMaterial)Sprite.Material;
|
||||
shaderMaterial.SetShaderParameter("progress", shaderValue);
|
||||
}
|
||||
|
||||
public void OnResolved()
|
||||
private void SetShaderValue(bool shaderValue)
|
||||
{
|
||||
var shaderMaterial = (ShaderMaterial)Sprite.Material;
|
||||
shaderMaterial.SetShaderParameter("reverse", shaderValue);
|
||||
}
|
||||
|
||||
private void DroppedItem_BodyEntered(Node body)
|
||||
{
|
||||
if (body is IPlayer player)
|
||||
{
|
||||
ContactMonitor = true;
|
||||
BodyEntered += DroppedItem_BodyEntered;
|
||||
Sprite.Texture = Item.Info.Texture;
|
||||
}
|
||||
|
||||
public async void Drop()
|
||||
{
|
||||
AddCollisionExceptionWith((Node)Game.Player);
|
||||
GlobalPosition = Game.Player.GlobalPosition + Vector3.Up;
|
||||
ApplyCentralImpulse(-Game.Player.GlobalBasis.Z.Normalized() * 5.0f);
|
||||
await ToSignal(GetTree().CreateTimer(1.5), "timeout");
|
||||
RemoveCollisionExceptionWith((Node)Game.Player);
|
||||
}
|
||||
|
||||
public void RescueItem()
|
||||
{
|
||||
ContactMonitor = false;
|
||||
PlayRescueAnimation();
|
||||
Game.RescuedItems.Items.Add(Item);
|
||||
}
|
||||
|
||||
private void PlayRescueAnimation()
|
||||
{
|
||||
LoadShader("res://src/vfx/shaders/PixelMelt.gdshader");
|
||||
var tweener = GetTree().CreateTween();
|
||||
SetShaderValue(true);
|
||||
tweener.TweenMethod(Callable.From((float x) => SetShaderValue(x)), 0.0f, 0.3f, 2f);
|
||||
tweener.TweenCallback(Callable.From(QueueFree));
|
||||
}
|
||||
|
||||
private void LoadShader(string shaderPath)
|
||||
{
|
||||
var shader = GD.Load<Shader>(shaderPath);
|
||||
Sprite.Material = new ShaderMaterial();
|
||||
var shaderMaterial = (ShaderMaterial)Sprite.Material;
|
||||
shaderMaterial.Shader = shader;
|
||||
}
|
||||
|
||||
private void SetShaderValue(float shaderValue)
|
||||
{
|
||||
var shaderMaterial = (ShaderMaterial)Sprite.Material;
|
||||
shaderMaterial.SetShaderParameter("progress", shaderValue);
|
||||
}
|
||||
|
||||
private void SetShaderValue(bool shaderValue)
|
||||
{
|
||||
var shaderMaterial = (ShaderMaterial)Sprite.Material;
|
||||
shaderMaterial.SetShaderParameter("reverse", shaderValue);
|
||||
}
|
||||
|
||||
private void DroppedItem_BodyEntered(Node body)
|
||||
{
|
||||
if (body is IPlayer player)
|
||||
{
|
||||
var isAdded = GameRepo.PlayerData.Inventory.TryAdd(Item);
|
||||
if (isAdded)
|
||||
QueueFree();
|
||||
}
|
||||
var isAdded = Player.Inventory.TryAdd(Item);
|
||||
if (isAdded)
|
||||
QueueFree();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
using Chickensoft.AutoInject;
|
||||
using Chickensoft.Introspection;
|
||||
using GameJamDungeon;
|
||||
using Godot;
|
||||
|
||||
namespace GameJamDungeon;
|
||||
|
||||
[Meta(typeof(IAutoNode))]
|
||||
public partial class Restorative : Node3D
|
||||
{
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
using Chickensoft.AutoInject;
|
||||
using Chickensoft.Introspection;
|
||||
using GameJamDungeon;
|
||||
using Godot;
|
||||
using System;
|
||||
using System.Collections.Immutable;
|
||||
|
||||
namespace GameJamDungeon;
|
||||
|
||||
[Meta(typeof(IAutoNode))]
|
||||
public partial class ThrowableItem : Node3D, IUsableItem
|
||||
@@ -11,56 +13,75 @@ public partial class ThrowableItem : Node3D, IUsableItem
|
||||
|
||||
[Dependency] public IGame Game => this.DependOn<IGame>();
|
||||
|
||||
[Dependency] public IGameRepo GameRepo => this.DependOn<IGameRepo>();
|
||||
|
||||
public InventoryItemStats Info => ThrowableItemInfo;
|
||||
|
||||
public int Count { get; }
|
||||
[Dependency] public IPlayer Player => this.DependOn<IPlayer>();
|
||||
|
||||
public Guid ID => Guid.NewGuid();
|
||||
|
||||
public string ItemName => _throwableItemStats.Name;
|
||||
|
||||
public string Description => _throwableItemStats.Description;
|
||||
|
||||
public float SpawnRate => _throwableItemStats.SpawnRate;
|
||||
|
||||
public Texture2D GetTexture() => _throwableItemStats.Texture;
|
||||
|
||||
public double ThrowDamage => _throwableItemStats.ThrowDamage;
|
||||
|
||||
public float ThrowSpeed => _throwableItemStats.ThrowSpeed;
|
||||
|
||||
public ElementType ElementType => _throwableItemStats.ElementType;
|
||||
|
||||
public ImmutableList<ThrowableItemTag> ThrowableItemTags => [.. _throwableItemStats.ThrowableItemTags];
|
||||
|
||||
public int Count { get; }
|
||||
|
||||
public void SetItemStats(InventoryItemStats inventoryItemStats)
|
||||
{
|
||||
_throwableItemStats = (ThrowableItemStats)inventoryItemStats;
|
||||
}
|
||||
|
||||
public void OnEntered(Node3D body)
|
||||
{
|
||||
var isAdded = Player.Inventory.TryAdd(this);
|
||||
if (isAdded)
|
||||
QueueFree();
|
||||
}
|
||||
|
||||
[Export]
|
||||
public ThrowableItemStats ThrowableItemInfo { get; set; }
|
||||
private ThrowableItemStats _throwableItemStats { get; set; }
|
||||
|
||||
[Node] public Sprite3D Sprite { get; set; } = default!;
|
||||
[Node] private Sprite3D Sprite { get; set; } = new Sprite3D();
|
||||
|
||||
[Node] public Area3D Pickup { get; set; } = default!;
|
||||
[Node] private Area3D Pickup { get; set; } = default!;
|
||||
|
||||
public void OnResolved()
|
||||
{
|
||||
Sprite.Texture = ThrowableItemInfo.Texture;
|
||||
Pickup.BodyEntered += OnEntered;
|
||||
Sprite.Texture = _throwableItemStats.Texture;
|
||||
}
|
||||
|
||||
public void Use()
|
||||
{
|
||||
if (ThrowableItemInfo.HealHPAmount > 0)
|
||||
Game.HealHP(ThrowableItemInfo.HealHPAmount);
|
||||
if (ThrowableItemInfo.HealVTAmount > 0)
|
||||
Game.HealVT(ThrowableItemInfo.HealVTAmount);
|
||||
if (_throwableItemStats.HealHPAmount > 0)
|
||||
Game.HealHP(_throwableItemStats.HealHPAmount);
|
||||
if (_throwableItemStats.HealVTAmount > 0)
|
||||
Game.HealVT(_throwableItemStats.HealVTAmount);
|
||||
|
||||
if (ThrowableItemInfo.UsableItemTags.Contains(UsableItemTag.DoubleEXP))
|
||||
if (_throwableItemStats.UsableItemTags.Contains(UsableItemTag.DoubleEXP))
|
||||
Game.DoubleEXP(TimeSpan.FromSeconds(30));
|
||||
|
||||
if (ThrowableItemInfo.ThrowableItemTags.Contains(ThrowableItemTag.CanChangeAffinity))
|
||||
if (_throwableItemStats.ThrowableItemTags.Contains(ThrowableItemTag.CanChangeAffinity))
|
||||
ChangeAffinity();
|
||||
}
|
||||
|
||||
private void ChangeAffinity()
|
||||
{
|
||||
var maximumElements = Enum.GetNames(typeof(ElementType)).Length;
|
||||
ThrowableItemInfo.ElementType = ThrowableItemInfo.ElementType + 1 % maximumElements;
|
||||
_throwableItemStats.ElementType = _throwableItemStats.ElementType + 1 % maximumElements;
|
||||
|
||||
// TODO: Make this an inventory animation to cycle through elements.
|
||||
ThrowableItemInfo.Description =
|
||||
$"Inflicts {ThrowableItemInfo.ElementType} damage when thrown." +
|
||||
_throwableItemStats.Description =
|
||||
$"Inflicts {_throwableItemStats.ElementType} damage when thrown." +
|
||||
$"{System.Environment.NewLine}Use item to change Affinity.";
|
||||
}
|
||||
|
||||
public void OnEntered(Node3D body)
|
||||
{
|
||||
var isAdded = GameRepo.PlayerData.Inventory.TryAdd(this);
|
||||
if (isAdded)
|
||||
QueueFree();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System.ComponentModel;
|
||||
namespace GameJamDungeon;
|
||||
|
||||
public enum ThrowableItemTag
|
||||
{
|
||||
|
||||
@@ -1,53 +1,52 @@
|
||||
using Chickensoft.AutoInject;
|
||||
using Chickensoft.Introspection;
|
||||
using GameJamDungeon;
|
||||
using Godot;
|
||||
|
||||
namespace GameJamDungeon;
|
||||
|
||||
[Meta(typeof(IAutoNode))]
|
||||
public partial class ThrownItem : RigidBody3D
|
||||
{
|
||||
public override void _Notification(int what) => this.Notify(what);
|
||||
|
||||
[Dependency] public IGame Game => this.DependOn<IGame>();
|
||||
[Dependency] public IPlayer Player => this.DependOn<IPlayer>();
|
||||
|
||||
public InventoryItemStats ThrownItemStats;
|
||||
public IInventoryItem ItemThatIsThrown;
|
||||
|
||||
[Node] public Sprite3D Sprite { get; set; } = default!;
|
||||
|
||||
public void OnResolved()
|
||||
{
|
||||
BodyEntered += ThrownItem_BodyEntered;
|
||||
GlobalPosition = Game.Player.GlobalPosition + new Vector3(0, 0, 0);
|
||||
Sprite.Texture = ThrownItemStats.Texture;
|
||||
AddCollisionExceptionWith((Node)Game.Player);
|
||||
GlobalPosition = Player.CurrentPosition;
|
||||
Sprite.Texture = ItemThatIsThrown.GetTexture();
|
||||
AddCollisionExceptionWith((Node)Player);
|
||||
}
|
||||
|
||||
private void ThrownItem_BodyEntered(Node body)
|
||||
{
|
||||
if (body is IEnemy enemy)
|
||||
{
|
||||
CalculateEffect(enemy);
|
||||
}
|
||||
QueueFree();
|
||||
}
|
||||
|
||||
public void Throw()
|
||||
{
|
||||
ApplyCentralImpulse(-Game.Player.GlobalBasis.Z.Normalized() * ThrownItemStats.ThrowSpeed);
|
||||
ApplyCentralImpulse(-Player.CurrentBasis.Z.Normalized() * ItemThatIsThrown.ThrowSpeed);
|
||||
}
|
||||
|
||||
private void CalculateEffect(IEnemy enemy)
|
||||
{
|
||||
if (ThrownItemStats is ThrowableItemStats throwableItemStats)
|
||||
if (ItemThatIsThrown is ThrowableItem throwableItem)
|
||||
{
|
||||
if (throwableItemStats.ThrowableItemTags.Contains(ThrowableItemTag.LowerTargetTo1HP))
|
||||
enemy.TakeDamage(enemy.CurrentHP - 1, ElementType.None, false, true, true);
|
||||
if (throwableItem.ThrowableItemTags.Contains(ThrowableItemTag.LowerTargetTo1HP))
|
||||
enemy.TakeDamage(enemy.CurrentHP - 1, ignoreDefense: true, ignoreElementalResistance: true);
|
||||
else
|
||||
enemy.TakeDamage(throwableItemStats.ThrowDamage, throwableItemStats.ElementType);
|
||||
enemy.TakeDamage(throwableItem.ThrowDamage, throwableItem.ElementType);
|
||||
}
|
||||
else
|
||||
{
|
||||
enemy.TakeDamage(ThrownItemStats.ThrowDamage, ElementType.None);
|
||||
enemy.TakeDamage(ItemThatIsThrown.ThrowDamage);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,34 +1,65 @@
|
||||
using Chickensoft.AutoInject;
|
||||
using Chickensoft.Introspection;
|
||||
using GameJamDungeon;
|
||||
using Godot;
|
||||
using System;
|
||||
using System.Collections.Immutable;
|
||||
|
||||
namespace GameJamDungeon;
|
||||
|
||||
[Meta(typeof(IAutoNode))]
|
||||
public partial class Weapon : Node3D, IInventoryItem, IEquipableItem
|
||||
{
|
||||
public override void _Notification(int what) => this.Notify(what);
|
||||
|
||||
[Dependency] public IGameRepo GameRepo => this.DependOn<IGameRepo>();
|
||||
|
||||
public InventoryItemStats Info => WeaponStats;
|
||||
[Dependency] public IPlayer Player => this.DependOn<IPlayer>();
|
||||
|
||||
[Signal]
|
||||
public delegate void EquippedItemEventHandler(Weapon equippedWeapon);
|
||||
|
||||
[Export]
|
||||
public WeaponStats WeaponStats { get; set; } = new WeaponStats();
|
||||
private WeaponStats _weaponStats { get; set; } = new WeaponStats();
|
||||
|
||||
[Node] public Sprite3D Sprite { get; set; } = default!;
|
||||
[Node] public Sprite3D Sprite { get; set; } = new Sprite3D();
|
||||
|
||||
[Node] public Area3D Pickup { get; set; } = default!;
|
||||
|
||||
public Texture2D GetTexture() => _weaponStats.Texture;
|
||||
|
||||
public Guid ID => Guid.NewGuid();
|
||||
|
||||
public string ItemName => _weaponStats.Name;
|
||||
|
||||
public string Description => _weaponStats.Description;
|
||||
|
||||
public float SpawnRate => _weaponStats.SpawnRate;
|
||||
|
||||
public int Damage => _weaponStats.Damage;
|
||||
|
||||
public double ThrowDamage => _weaponStats.ThrowDamage;
|
||||
|
||||
public float ThrowSpeed => _weaponStats.ThrowSpeed;
|
||||
|
||||
public double Luck => _weaponStats.Luck;
|
||||
|
||||
public double AttackSpeed => _weaponStats.AttackSpeed;
|
||||
|
||||
public ImmutableList<WeaponTag> WeaponTags => [.. _weaponStats.WeaponTags];
|
||||
|
||||
public ElementType WeaponElement => _weaponStats.WeaponElement;
|
||||
|
||||
public double ElementalDamageBonus => _weaponStats.ElementalDamageBonus;
|
||||
|
||||
public void OnReady()
|
||||
{
|
||||
Sprite.Texture = WeaponStats.Texture;
|
||||
Pickup.BodyEntered += OnEntered;
|
||||
Sprite.Texture = _weaponStats.Texture;
|
||||
}
|
||||
|
||||
public void SetItemStats(InventoryItemStats inventoryItemStats)
|
||||
{
|
||||
_weaponStats = (WeaponStats)inventoryItemStats;
|
||||
var texture = ResourceLoader.Load(inventoryItemStats.Texture.ResourcePath) as Texture2D;
|
||||
Sprite.Texture = texture;
|
||||
}
|
||||
|
||||
public void Equip()
|
||||
@@ -43,17 +74,17 @@ public partial class Weapon : Node3D, IInventoryItem, IEquipableItem
|
||||
|
||||
public void Throw()
|
||||
{
|
||||
GameRepo.PlayerData.Inventory.Remove(this);
|
||||
Player.Inventory.Remove(this);
|
||||
}
|
||||
|
||||
public void Drop()
|
||||
{
|
||||
GameRepo.PlayerData.Inventory.Remove(this);
|
||||
Player.Inventory.Remove(this);
|
||||
}
|
||||
|
||||
public void OnEntered(Node3D body)
|
||||
{
|
||||
var isAdded = GameRepo.PlayerData.Inventory.TryAdd(this);
|
||||
var isAdded = Player.Inventory.TryAdd(this);
|
||||
if (isAdded)
|
||||
QueueFree();
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using GameJamDungeon;
|
||||
using Godot;
|
||||
|
||||
namespace GameJamDungeon;
|
||||
|
||||
[GlobalClass]
|
||||
public partial class WeaponStats : InventoryItemStats
|
||||
{
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
using Godot;
|
||||
using System;
|
||||
|
||||
public partial class Rigid : RigidBody3D
|
||||
{
|
||||
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
[gd_scene load_steps=9 format=3 uid="uid://by67pn7fdsg1m"]
|
||||
|
||||
[ext_resource type="Script" path="res://src/map/Map.cs" id="1_bw70o"]
|
||||
[ext_resource type="Script" uid="uid://14e8mu48ed4" path="res://src/map/Map.cs" id="1_bw70o"]
|
||||
[ext_resource type="PackedScene" uid="uid://dl6h1djc27ddl" path="res://src/map/overworld/Floor0.tscn" id="2_0m8h8"]
|
||||
[ext_resource type="PackedScene" uid="uid://bc1sp6xwe0j65" path="res://src/map/dungeon/floors/Floor01.tscn" id="2_merfv"]
|
||||
[ext_resource type="Script" path="res://src/map/dungeon/code/Floor0.cs" id="3_n0f1p"]
|
||||
[ext_resource type="Script" uid="uid://c1nhqlem1ew3m" path="res://src/map/dungeon/code/Floor0.cs" id="3_n0f1p"]
|
||||
[ext_resource type="PackedScene" uid="uid://g28xmp6cn16h" path="res://src/map/dungeon/floors/Floor11.tscn" id="3_niasb"]
|
||||
[ext_resource type="PackedScene" uid="uid://dmiqwmivkjgmq" path="res://src/map/dungeon/floors/Floor02.tscn" id="4_8y0oy"]
|
||||
[ext_resource type="PackedScene" uid="uid://bjqgl5u05ia04" path="res://src/map/dungeon/Teleport.tscn" id="5_jiohg"]
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
using Chickensoft.AutoInject;
|
||||
using Chickensoft.Introspection;
|
||||
using GameJamDungeon;
|
||||
using Godot;
|
||||
|
||||
namespace GameJamDungeon;
|
||||
|
||||
[Meta(typeof(IAutoNode))]
|
||||
public partial class BossFloor : Node3D, IDungeonFloor
|
||||
{
|
||||
|
||||
@@ -3,67 +3,66 @@ using Chickensoft.Introspection;
|
||||
using Godot;
|
||||
using System.Linq;
|
||||
|
||||
namespace GameJamDungeon
|
||||
namespace GameJamDungeon;
|
||||
|
||||
[Meta(typeof(IAutoNode))]
|
||||
public partial class BossRoom : Node3D, IDungeonRoom
|
||||
{
|
||||
[Meta(typeof(IAutoNode))]
|
||||
public partial class BossRoom : Node3D, IDungeonRoom
|
||||
public override void _Notification(int what) => this.Notify(what);
|
||||
|
||||
[Dependency] public IGameRepo GameRepo => this.DependOn<IGameRepo>();
|
||||
|
||||
[Node] public Marker3D PlayerSpawn { get; set; } = default!;
|
||||
|
||||
[Node] public Marker3D TeleportSpawn { get; set; } = default!;
|
||||
|
||||
[Node] public Marker3D ItemSpawnPoint { get; set; } = default!;
|
||||
|
||||
[Node] public ItemDatabase ItemDatabase { get; set; } = default!;
|
||||
|
||||
[Node] public Node3D HorseHeadStatue { get; set; } = default!;
|
||||
|
||||
[Node] public Node3D OxFaceStatue { get; set; } = default!;
|
||||
|
||||
[Node] public Boss OxFace { get; set; } = default!;
|
||||
|
||||
[Node] public Boss HorseFace { get; set; } = default!;
|
||||
|
||||
[Node] public Area3D ActivateTrap { get; set; } = default!;
|
||||
|
||||
[Node] public StaticBody3D GateCollision { get; set; } = default!;
|
||||
|
||||
public void Setup()
|
||||
{
|
||||
public override void _Notification(int what) => this.Notify(what);
|
||||
SpawnItems();
|
||||
ActivateTrap.BodyEntered += StartBossFight;
|
||||
OxFace.CurrentHP.Sync += BossHPUpdate;
|
||||
HorseFace.CurrentHP.Sync += BossHPUpdate;
|
||||
}
|
||||
|
||||
[Dependency] public IGameRepo GameRepo => this.DependOn<IGameRepo>();
|
||||
private void BossHPUpdate(double obj)
|
||||
{
|
||||
if (OxFace.CurrentHP.Value <= 0 && HorseFace.CurrentHP.Value <= 0)
|
||||
GateCollision.CallDeferred(MethodName.QueueFree);
|
||||
}
|
||||
|
||||
[Node] public Marker3D PlayerSpawn { get; set; } = default!;
|
||||
private void SpawnItems()
|
||||
{
|
||||
var database = ItemDatabase.Initialize().OfType<ConsumableItem>().ToArray();
|
||||
var rng = new RandomNumberGenerator();
|
||||
rng.Randomize();
|
||||
var weights = database.Select(x => x.SpawnRate).ToArray();
|
||||
var selectedItem = database[rng.RandWeighted(weights)];
|
||||
var duplicated = selectedItem.Duplicate((int)DuplicateFlags.UseInstantiation) as Node3D;
|
||||
duplicated.Position = ItemSpawnPoint.Position;
|
||||
AddChild(duplicated);
|
||||
}
|
||||
|
||||
[Node] public Marker3D TeleportSpawn { get; set; } = default!;
|
||||
|
||||
[Node] public Marker3D ItemSpawnPoint { get; set; } = default!;
|
||||
|
||||
[Node] public ItemDatabase ItemDatabase { get; set; } = default!;
|
||||
|
||||
[Node] public Node3D HorseHeadStatue { get; set; } = default!;
|
||||
|
||||
[Node] public Node3D OxFaceStatue { get; set; } = default!;
|
||||
|
||||
[Node] public Boss OxFace { get; set; } = default!;
|
||||
|
||||
[Node] public Boss HorseFace { get; set; } = default!;
|
||||
|
||||
[Node] public Area3D ActivateTrap { get; set; } = default!;
|
||||
|
||||
[Node] public StaticBody3D GateCollision { get; set; } = default!;
|
||||
|
||||
public void Setup()
|
||||
{
|
||||
SpawnItems();
|
||||
ActivateTrap.BodyEntered += StartBossFight;
|
||||
OxFace.CurrentHP.Sync += BossHPUpdate;
|
||||
HorseFace.CurrentHP.Sync += BossHPUpdate;
|
||||
}
|
||||
|
||||
private void BossHPUpdate(double obj)
|
||||
{
|
||||
if (OxFace.CurrentHP.Value <= 0 && HorseFace.CurrentHP.Value <= 0)
|
||||
GateCollision.CallDeferred(MethodName.QueueFree);
|
||||
}
|
||||
|
||||
private void SpawnItems()
|
||||
{
|
||||
var database = ItemDatabase.Initialize().OfType<ConsumableItem>().ToArray();
|
||||
var rng = new RandomNumberGenerator();
|
||||
rng.Randomize();
|
||||
var weights = database.Select(x => x.Info.SpawnRate).ToArray();
|
||||
var selectedItem = database[rng.RandWeighted(weights)];
|
||||
var duplicated = selectedItem.Duplicate((int)DuplicateFlags.UseInstantiation) as Node3D;
|
||||
duplicated.Position = ItemSpawnPoint.Position;
|
||||
AddChild(duplicated);
|
||||
}
|
||||
|
||||
private void StartBossFight(Node3D body)
|
||||
{
|
||||
OxFaceStatue.Hide();
|
||||
HorseHeadStatue.Hide();
|
||||
OxFace.Activate();
|
||||
HorseFace.Activate();
|
||||
}
|
||||
private void StartBossFight(Node3D body)
|
||||
{
|
||||
OxFaceStatue.Hide();
|
||||
HorseHeadStatue.Hide();
|
||||
OxFace.Activate();
|
||||
HorseFace.Activate();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,90 +1,83 @@
|
||||
using Chickensoft.AutoInject;
|
||||
using Chickensoft.GodotNodeInterfaces;
|
||||
using Chickensoft.Introspection;
|
||||
using Godot;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
public interface IDungeonFloor : INode3D
|
||||
namespace GameJamDungeon
|
||||
{
|
||||
void InitializeDungeon();
|
||||
|
||||
public Transform3D GetPlayerSpawnPoint();
|
||||
|
||||
public Vector3 GetTeleportSpawnPoint();
|
||||
}
|
||||
|
||||
[Meta(typeof(IAutoNode))]
|
||||
public partial class DungeonFloor : Node3D, IDungeonFloor
|
||||
{
|
||||
public override void _Notification(int what) => this.Notify(what);
|
||||
|
||||
[Node] public GodotObject DungeonGenerator { get; set; } = default!;
|
||||
|
||||
[Node] public NavigationRegion3D NavigationRegion3D { get; set; } = default!;
|
||||
|
||||
private Transform3D _playerSpawnPoint;
|
||||
|
||||
private Vector3 _teleportSpawnPoint;
|
||||
|
||||
internal List<IDungeonRoom> Rooms { get; private set; }
|
||||
|
||||
public void InitializeDungeon()
|
||||
[Meta(typeof(IAutoNode))]
|
||||
public partial class DungeonFloor : Node3D, IDungeonFloor
|
||||
{
|
||||
Rooms = new List<IDungeonRoom>();
|
||||
DungeonGenerator.Call("generate");
|
||||
NavigationRegion3D.BakeNavigationMesh();
|
||||
Rooms = FindAllDungeonRooms([.. GetChildren()], Rooms);
|
||||
_playerSpawnPoint = RandomizePlayerSpawnPoint();
|
||||
_teleportSpawnPoint = RandomizeTeleportSpawnPointAwayFromPosition(_playerSpawnPoint.Origin);
|
||||
}
|
||||
public override void _Notification(int what) => this.Notify(what);
|
||||
|
||||
public Transform3D GetPlayerSpawnPoint() => _playerSpawnPoint;
|
||||
[Node] public GodotObject DungeonGenerator { get; set; } = default!;
|
||||
|
||||
public Vector3 GetTeleportSpawnPoint() => _teleportSpawnPoint;
|
||||
[Node] public NavigationRegion3D NavigationRegion3D { get; set; } = default!;
|
||||
|
||||
private Transform3D RandomizePlayerSpawnPoint()
|
||||
{
|
||||
var rng = new RandomNumberGenerator();
|
||||
rng.Randomize();
|
||||
var rngDistribution = new List<float>();
|
||||
var randomSpawnLocations = Rooms
|
||||
.Select(x => x.PlayerSpawn);
|
||||
var godotCollection = new Godot.Collections.Array<Marker3D>(randomSpawnLocations);
|
||||
var result = godotCollection.PickRandom();
|
||||
return result.GlobalTransform;
|
||||
}
|
||||
private Transform3D _playerSpawnPoint;
|
||||
|
||||
private Vector3 RandomizeTeleportSpawnPointAwayFromPosition(Vector3 target)
|
||||
{
|
||||
var rng = new RandomNumberGenerator();
|
||||
rng.Randomize();
|
||||
var rngDistribution = new List<float>();
|
||||
var roomsSortedByDistance = Rooms
|
||||
.Select(x => x.TeleportSpawn.GlobalPosition)
|
||||
.OrderByDescending(x => x.DistanceTo(target))
|
||||
.ToArray();
|
||||
var rngIndex = 1.0;
|
||||
var rngSteps = rngIndex / roomsSortedByDistance.Count();
|
||||
foreach (var room in roomsSortedByDistance)
|
||||
private Vector3 _teleportSpawnPoint;
|
||||
|
||||
internal List<IDungeonRoom> Rooms { get; private set; }
|
||||
|
||||
public void InitializeDungeon()
|
||||
{
|
||||
rngIndex -= rngSteps;
|
||||
rngDistribution.Add((float)rngIndex);
|
||||
Rooms = new List<IDungeonRoom>();
|
||||
DungeonGenerator.Call("generate");
|
||||
NavigationRegion3D.BakeNavigationMesh();
|
||||
Rooms = FindAllDungeonRooms([.. GetChildren()], Rooms);
|
||||
_playerSpawnPoint = RandomizePlayerSpawnPoint();
|
||||
_teleportSpawnPoint = RandomizeTeleportSpawnPointAwayFromPosition(_playerSpawnPoint.Origin);
|
||||
}
|
||||
|
||||
var result = roomsSortedByDistance[rng.RandWeighted([.. rngDistribution])];
|
||||
return result;
|
||||
}
|
||||
public Transform3D GetPlayerSpawnPoint() => _playerSpawnPoint;
|
||||
|
||||
private List<IDungeonRoom> FindAllDungeonRooms(List<Node> nodesToSearch, List<IDungeonRoom> roomsFound)
|
||||
{
|
||||
if (nodesToSearch.Count == 0)
|
||||
return roomsFound;
|
||||
public Vector3 GetTeleportSpawnPoint() => _teleportSpawnPoint;
|
||||
|
||||
foreach (var node in nodesToSearch)
|
||||
if (node is IDungeonRoom dungeonRoom)
|
||||
roomsFound.Add(dungeonRoom);
|
||||
private Transform3D RandomizePlayerSpawnPoint()
|
||||
{
|
||||
var rng = new RandomNumberGenerator();
|
||||
rng.Randomize();
|
||||
var rngDistribution = new List<float>();
|
||||
var randomSpawnLocations = Rooms
|
||||
.Select(x => x.PlayerSpawn);
|
||||
var godotCollection = new Godot.Collections.Array<Marker3D>(randomSpawnLocations);
|
||||
var result = godotCollection.PickRandom();
|
||||
return result.GlobalTransform;
|
||||
}
|
||||
|
||||
return FindAllDungeonRooms(nodesToSearch.SelectMany(x => x.GetChildren()).ToList(), roomsFound);
|
||||
private Vector3 RandomizeTeleportSpawnPointAwayFromPosition(Vector3 target)
|
||||
{
|
||||
var rng = new RandomNumberGenerator();
|
||||
rng.Randomize();
|
||||
var rngDistribution = new List<float>();
|
||||
var roomsSortedByDistance = Rooms
|
||||
.Select(x => x.TeleportSpawn.GlobalPosition)
|
||||
.OrderByDescending(x => x.DistanceTo(target))
|
||||
.ToArray();
|
||||
var rngIndex = 1.0;
|
||||
var rngSteps = rngIndex / roomsSortedByDistance.Length;
|
||||
foreach (var room in roomsSortedByDistance)
|
||||
{
|
||||
rngIndex -= rngSteps;
|
||||
rngDistribution.Add((float)rngIndex);
|
||||
}
|
||||
|
||||
var result = roomsSortedByDistance[rng.RandWeighted([.. rngDistribution])];
|
||||
return result;
|
||||
}
|
||||
|
||||
private static List<IDungeonRoom> FindAllDungeonRooms(List<Node> nodesToSearch, List<IDungeonRoom> roomsFound)
|
||||
{
|
||||
if (nodesToSearch.Count == 0)
|
||||
return roomsFound;
|
||||
|
||||
foreach (var node in nodesToSearch)
|
||||
if (node is IDungeonRoom dungeonRoom)
|
||||
roomsFound.Add(dungeonRoom);
|
||||
|
||||
return FindAllDungeonRooms(nodesToSearch.SelectMany(x => x.GetChildren()).ToList(), roomsFound);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ using GameJamDungeon;
|
||||
using Godot;
|
||||
using System.Linq;
|
||||
|
||||
namespace GameJamDungeon;
|
||||
public interface IDungeonRoom : INode3D
|
||||
{
|
||||
public Marker3D PlayerSpawn { get; set; }
|
||||
@@ -50,7 +51,7 @@ public partial class DungeonRoom : Node3D, IDungeonRoom
|
||||
break;
|
||||
numberOfItemsToSpawn--;
|
||||
|
||||
var weights = database.Select(x => x.Info.SpawnRate).ToArray();
|
||||
var weights = database.Select(x => x.SpawnRate).ToArray();
|
||||
var selectedItem = database[rng.RandWeighted(weights)];
|
||||
var duplicated = selectedItem.Duplicate((int)DuplicateFlags.UseInstantiation) as Node3D;
|
||||
duplicated.Position = new Vector3(spawnPoint.Position.X, -1.75f, spawnPoint.Position.Z);
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using Chickensoft.Introspection;
|
||||
using Godot;
|
||||
|
||||
namespace GameJamDungeon;
|
||||
[Meta(typeof(IAutoNode))]
|
||||
public partial class Floor0 : Node3D, IDungeonFloor
|
||||
{
|
||||
|
||||
12
src/map/dungeon/code/IDungeonFloor.cs
Normal file
12
src/map/dungeon/code/IDungeonFloor.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
using Chickensoft.GodotNodeInterfaces;
|
||||
using Godot;
|
||||
|
||||
namespace GameJamDungeon;
|
||||
public interface IDungeonFloor : INode3D
|
||||
{
|
||||
void InitializeDungeon();
|
||||
|
||||
public Transform3D GetPlayerSpawnPoint();
|
||||
|
||||
public Vector3 GetTeleportSpawnPoint();
|
||||
}
|
||||
@@ -2,6 +2,7 @@ using Chickensoft.AutoInject;
|
||||
using Chickensoft.Introspection;
|
||||
using Godot;
|
||||
|
||||
namespace GameJamDungeon;
|
||||
[Meta(typeof(IAutoNode))]
|
||||
public partial class MinimapManager : Area3D
|
||||
{
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
using Chickensoft.AutoInject;
|
||||
using Chickensoft.Introspection;
|
||||
using GameJamDungeon;
|
||||
using Godot;
|
||||
|
||||
namespace GameJamDungeon;
|
||||
[Meta(typeof(IAutoNode))]
|
||||
public partial class Overworld : Node3D, IDungeonFloor
|
||||
{
|
||||
|
||||
@@ -705,7 +705,7 @@ skeleton = NodePath("")
|
||||
|
||||
[node name="PlayerSpawn" type="Marker3D" parent="Antechamber"]
|
||||
unique_name_in_owner = true
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -8.61757, -2.04983, 0.580412)
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -8.61757, -1.89174, 0.580412)
|
||||
|
||||
[node name="ItemSpawnPoints" type="Node3D" parent="Antechamber"]
|
||||
unique_name_in_owner = true
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
[gd_scene load_steps=8 format=3 uid="uid://dl6h1djc27ddl"]
|
||||
[gd_scene load_steps=7 format=3 uid="uid://dl6h1djc27ddl"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://cuhfkyh3d7noa" path="res://src/map/dungeon/code/Overworld.cs" id="1_2ce63"]
|
||||
[ext_resource type="PackedScene" uid="uid://duis2vhf5ojy3" path="res://src/item_rescue/ItemRescue.tscn" id="2_4ixnb"]
|
||||
[ext_resource type="PackedScene" uid="uid://tc5kdfoggrng" path="res://src/item_rescue/RescuedItems.tscn" id="3_tbcl3"]
|
||||
[ext_resource type="PackedScene" uid="uid://1fl6s352e2ej" path="res://src/items/throwable/ThrowableItem.tscn" id="4_wibf0"]
|
||||
|
||||
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_pb22g"]
|
||||
|
||||
@@ -57,7 +56,4 @@ collision_mask = 3
|
||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="Spawn Rescued Items/Area3D"]
|
||||
shape = SubResource("SphereShape3D_tbcl3")
|
||||
|
||||
[node name="ThrowableItem" parent="." instance=ExtResource("4_wibf0")]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -0.5, 0)
|
||||
|
||||
[connection signal="body_entered" from="Spawn Rescued Items/Area3D" to="Rescued Items" method="OnSpawnItemsEntered"]
|
||||
|
||||
@@ -4,6 +4,8 @@ using Chickensoft.Introspection;
|
||||
using GameJamDungeon;
|
||||
using Godot;
|
||||
|
||||
namespace GameJamDungeon;
|
||||
|
||||
public interface IMenu : IControl
|
||||
{
|
||||
event Menu.NewGameEventHandler NewGame;
|
||||
|
||||
@@ -3,28 +3,27 @@ using Chickensoft.GodotNodeInterfaces;
|
||||
using Chickensoft.Introspection;
|
||||
using Godot;
|
||||
|
||||
namespace GameJamDungeon
|
||||
namespace GameJamDungeon;
|
||||
|
||||
public interface ISplash : IControl;
|
||||
|
||||
[Meta(typeof(IAutoNode))]
|
||||
public partial class Splash : Control, ISplash
|
||||
{
|
||||
public interface ISplash : IControl;
|
||||
public override void _Notification(int what) => this.Notify(what);
|
||||
|
||||
[Meta(typeof(IAutoNode))]
|
||||
public partial class Splash : Control, ISplash
|
||||
{
|
||||
public override void _Notification(int what) => this.Notify(what);
|
||||
[Dependency]
|
||||
public IAppRepo AppRepo => this.DependOn<IAppRepo>();
|
||||
|
||||
[Dependency]
|
||||
public IAppRepo AppRepo => this.DependOn<IAppRepo>();
|
||||
[Node]
|
||||
public IAnimationPlayer AnimationPlayer { get; set; } = default!;
|
||||
|
||||
[Node]
|
||||
public IAnimationPlayer AnimationPlayer { get; set; } = default!;
|
||||
public void OnReady() =>
|
||||
AnimationPlayer.AnimationFinished += OnAnimationFinished;
|
||||
|
||||
public void OnReady() =>
|
||||
AnimationPlayer.AnimationFinished += OnAnimationFinished;
|
||||
public void OnExitTree()
|
||||
=> AnimationPlayer.AnimationFinished -= OnAnimationFinished;
|
||||
|
||||
public void OnExitTree()
|
||||
=> AnimationPlayer.AnimationFinished -= OnAnimationFinished;
|
||||
|
||||
public void OnAnimationFinished(StringName name)
|
||||
=> AppRepo.SkipSplashScreen();
|
||||
}
|
||||
public void OnAnimationFinished(StringName name)
|
||||
=> AppRepo.SkipSplashScreen();
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user