Move files and folders to new repo format to enable multi-project format
This commit is contained in:
25
Zennysoft.Game.Ma/src/Main.cs
Normal file
25
Zennysoft.Game.Ma/src/Main.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
namespace Zennysoft.Game.Ma;
|
||||
|
||||
using Godot;
|
||||
|
||||
#if DEBUG
|
||||
using System.Reflection;
|
||||
#endif
|
||||
|
||||
// This entry-point file is responsible for determining if we should run tests.
|
||||
//
|
||||
// If you want to edit your game's main entry-point, please see Game.tscn and
|
||||
// Game.cs instead.
|
||||
|
||||
public partial class Main : Node
|
||||
{
|
||||
|
||||
public override void _Ready()
|
||||
{
|
||||
// If we don't need to run tests, we can just switch to the game scene.
|
||||
CallDeferred("RunScene");
|
||||
}
|
||||
|
||||
private void RunScene()
|
||||
=> GetTree().ChangeSceneToFile("res://src/app/App.tscn");
|
||||
}
|
||||
1
Zennysoft.Game.Ma/src/Main.cs.uid
Normal file
1
Zennysoft.Game.Ma/src/Main.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://cck757iieiyj5
|
||||
7
Zennysoft.Game.Ma/src/Main.tscn
Normal file
7
Zennysoft.Game.Ma/src/Main.tscn
Normal file
@@ -0,0 +1,7 @@
|
||||
[gd_scene load_steps=2 format=3 uid="uid://d1gjaijijd5ot"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://cck757iieiyj5" path="res://src/Main.cs" id="1_prpoe"]
|
||||
|
||||
[node name="Node" type="Node"]
|
||||
process_mode = 3
|
||||
script = ExtResource("1_prpoe")
|
||||
154
Zennysoft.Game.Ma/src/app/App.cs
Normal file
154
Zennysoft.Game.Ma/src/app/App.cs
Normal file
@@ -0,0 +1,154 @@
|
||||
using Chickensoft.AutoInject;
|
||||
using Chickensoft.GodotNodeInterfaces;
|
||||
using Chickensoft.Introspection;
|
||||
using Godot;
|
||||
using static Zennysoft.Game.Ma.AppLogic.Input;
|
||||
|
||||
namespace Zennysoft.Game.Ma;
|
||||
|
||||
public interface IApp : ICanvasLayer, IProvide<IAppRepo>;
|
||||
|
||||
[Meta(typeof(IAutoNode))]
|
||||
public partial class App : CanvasLayer, IApp
|
||||
{
|
||||
public override void _Notification(int what) => this.Notify(what);
|
||||
|
||||
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 Menu Menu { get; set; } = default!;
|
||||
|
||||
[Node] public ISubViewport GameWindow { get; set; } = default!;
|
||||
|
||||
[Node] public ISplash Splash { get; set; } = default!;
|
||||
[Node] public IColorRect BlankScreen { get; set; } = default!;
|
||||
[Node] public IAnimationPlayer AnimationPlayer { get; set; } = default!;
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
Instantiator = new Instantiator(GetTree());
|
||||
AppRepo = new AppRepo();
|
||||
AppLogic = new AppLogic();
|
||||
AppLogic.Set(AppRepo);
|
||||
AppLogic.Set(new AppLogic.Data());
|
||||
|
||||
Menu.NewGame += OnNewGame;
|
||||
Menu.LoadGame += OnLoadGame;
|
||||
Menu.Quit += OnQuit;
|
||||
|
||||
AnimationPlayer.AnimationFinished += OnAnimationFinished;
|
||||
|
||||
Input.MouseMode = Input.MouseModeEnum.Visible;
|
||||
this.Provide();
|
||||
}
|
||||
|
||||
public void OnReady()
|
||||
{
|
||||
AppBinding = AppLogic.Bind();
|
||||
|
||||
AppBinding
|
||||
.Handle((in AppLogic.Output.ShowSplashScreen _) =>
|
||||
{
|
||||
HideMenus();
|
||||
BlankScreen.Hide();
|
||||
Splash.Show();
|
||||
})
|
||||
.Handle((in AppLogic.Output.HideSplashScreen _) =>
|
||||
{
|
||||
BlankScreen.Show();
|
||||
FadeToBlack();
|
||||
})
|
||||
.Handle((in AppLogic.Output.SetupGameScene _) =>
|
||||
{
|
||||
Game = Instantiator.LoadAndInstantiate<Game>(GAME_SCENE_PATH);
|
||||
GameWindow.AddChildEx(Game);
|
||||
Instantiator.SceneTree.Paused = false;
|
||||
})
|
||||
.Handle((in AppLogic.Output.ShowMainMenu _) =>
|
||||
{
|
||||
// Load everything while we're showing a black screen, then fade in.
|
||||
HideMenus();
|
||||
Menu.Show();
|
||||
|
||||
FadeInFromBlack();
|
||||
Menu.NewGameButton.GrabFocus();
|
||||
})
|
||||
.Handle((in AppLogic.Output.FadeToBlack _) => FadeToBlack())
|
||||
.Handle((in AppLogic.Output.HideGame _) => FadeToBlack())
|
||||
.Handle((in AppLogic.Output.ShowGame _) =>
|
||||
{
|
||||
HideMenus();
|
||||
FadeInFromBlack();
|
||||
})
|
||||
.Handle((in AppLogic.Output.StartLoadingSaveFile _) =>
|
||||
{
|
||||
Game.SaveFileLoaded += OnSaveFileLoaded;
|
||||
Game.LoadExistingGame();
|
||||
})
|
||||
.Handle((in AppLogic.Output.ExitGame _) =>
|
||||
{
|
||||
GetTree().Quit();
|
||||
});
|
||||
|
||||
|
||||
AppLogic.Start();
|
||||
}
|
||||
|
||||
public void OnNewGame() => AppLogic.Input(new NewGame());
|
||||
|
||||
private void OnLoadGame() => AppLogic.Input(new LoadGame());
|
||||
|
||||
public void OnQuit() => AppLogic.Input(new QuitGame());
|
||||
|
||||
public void OnSaveFileLoaded()
|
||||
{
|
||||
Game.SaveFileLoaded -= OnSaveFileLoaded;
|
||||
AppLogic.Input(new SaveFileLoaded());
|
||||
}
|
||||
|
||||
public void FadeInFromBlack()
|
||||
{
|
||||
BlankScreen.Show();
|
||||
AnimationPlayer.Play("fade_in");
|
||||
}
|
||||
|
||||
public void FadeToBlack()
|
||||
{
|
||||
BlankScreen.Show();
|
||||
AnimationPlayer.Play("fade_out");
|
||||
}
|
||||
|
||||
public void HideMenus()
|
||||
{
|
||||
Splash.Hide();
|
||||
Menu.Hide();
|
||||
}
|
||||
|
||||
public void OnAnimationFinished(StringName animation)
|
||||
{
|
||||
if (animation == "fade_in")
|
||||
{
|
||||
AppLogic.Input(new FadeInFinished());
|
||||
BlankScreen.Hide();
|
||||
return;
|
||||
}
|
||||
|
||||
AppLogic.Input(new FadeOutFinished());
|
||||
}
|
||||
|
||||
public void OnExitTree()
|
||||
{
|
||||
AppLogic.Stop();
|
||||
AppBinding.Dispose();
|
||||
AppRepo.Dispose();
|
||||
}
|
||||
}
|
||||
1
Zennysoft.Game.Ma/src/app/App.cs.uid
Normal file
1
Zennysoft.Game.Ma/src/app/App.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://d1f8blk5ucqvq
|
||||
140
Zennysoft.Game.Ma/src/app/App.gdshader
Normal file
140
Zennysoft.Game.Ma/src/app/App.gdshader
Normal file
@@ -0,0 +1,140 @@
|
||||
shader_type canvas_item;
|
||||
|
||||
// Handles the resolution changes, color depth, and dithering
|
||||
group_uniforms resolution_and_colors;
|
||||
uniform bool change_color_depth = false;
|
||||
uniform int target_color_depth : hint_range(1, 8) = 5;
|
||||
uniform bool dithering = false;
|
||||
uniform bool scale_resolution = false;
|
||||
uniform int target_resolution_scale = 3;
|
||||
|
||||
// Handles the LUTish recoloring
|
||||
group_uniforms gradient_recoloring;
|
||||
uniform bool enable_recolor = false;
|
||||
uniform sampler2D to_gradient: hint_default_black;
|
||||
|
||||
int dithering_pattern(ivec2 fragcoord) {
|
||||
const int pattern[] = {
|
||||
-4, +0, -3, +1,
|
||||
+2, -2, +3, -1,
|
||||
-3, +1, -4, +0,
|
||||
+3, -1, +2, -2
|
||||
};
|
||||
|
||||
int x = fragcoord.x % 4;
|
||||
int y = fragcoord.y % 4;
|
||||
|
||||
return pattern[y * 4 + x];
|
||||
}
|
||||
|
||||
vec3 rgb2hsv(vec3 rgb) { //Converts RGB values to HSV
|
||||
float r = rgb.r;
|
||||
float g = rgb.g;
|
||||
float b = rgb.b;
|
||||
|
||||
float cmax = max(r,max(g,b));
|
||||
float cmin = min(r,min(g,b));
|
||||
float delta = cmax - cmin;
|
||||
|
||||
float h = 0.f; //hue
|
||||
|
||||
if (delta > 0.f){
|
||||
if (cmax == r){
|
||||
h = (g-b)/delta;
|
||||
h = mod(h,6.f);
|
||||
} else if (cmax == g){
|
||||
h = ((b - r) / delta) + 2.f;
|
||||
} else {
|
||||
h = ((r-g)/delta) + 4.f;
|
||||
}
|
||||
h = h * 60.f;
|
||||
}
|
||||
|
||||
float s = 0.f; //saturation
|
||||
if (cmax > 0.f){
|
||||
s = delta / cmax;
|
||||
}
|
||||
|
||||
return vec3(h,s,cmax); // Keep original alpha value
|
||||
|
||||
}
|
||||
|
||||
vec3 hsv2rgb(vec3 hsv) { //Converts HSV values to RGB
|
||||
float h = hsv.r;
|
||||
float s = hsv.g;
|
||||
float v = hsv.b;
|
||||
float c = v * s;
|
||||
//X = C × (1 - |(H / 60°) mod 2 - 1|)
|
||||
float x = h / 60.f;
|
||||
x = mod(x,2.f);
|
||||
x = abs(x - 1.f);
|
||||
x = c * (1.f - x);
|
||||
|
||||
float m = v - c;
|
||||
|
||||
vec3 rgb = vec3(0.f,0.f,0.f);
|
||||
|
||||
if (h < 60.f) {
|
||||
rgb = vec3(c,x,0.f);
|
||||
} else if (h < 120.f){
|
||||
rgb = vec3(x,c,0.f);
|
||||
} else if (h < 180.f){
|
||||
rgb = vec3(0.f,c,x);
|
||||
} else if (h < 240.f){
|
||||
rgb = vec3(0.f,x,c);
|
||||
} else if (h < 300.f){
|
||||
rgb = vec3(x,0.f,c);
|
||||
} else if (h < 360.f){
|
||||
rgb = vec3(c,0.f,x);
|
||||
}
|
||||
rgb[0] = rgb[0] + m;
|
||||
rgb[1] = rgb[1] + m;
|
||||
rgb[2] = rgb[2] + m;
|
||||
|
||||
return rgb;
|
||||
}
|
||||
|
||||
void fragment() {
|
||||
ivec2 uv;
|
||||
vec3 color;
|
||||
|
||||
if(scale_resolution){
|
||||
uv = ivec2(FRAGCOORD.xy / float(target_resolution_scale));
|
||||
color = texelFetch(TEXTURE, uv * target_resolution_scale, 0).rgb;
|
||||
} else {
|
||||
uv = ivec2(FRAGCOORD.xy);
|
||||
color = texelFetch(TEXTURE, uv, 0).rgb;
|
||||
}
|
||||
|
||||
if(enable_recolor){
|
||||
vec3 hsv = rgb2hsv(color);
|
||||
float color_pos = (hsv.x / 360.0);
|
||||
vec3 new_color = texture(to_gradient, vec2((color_pos), 0.5)).rgb;
|
||||
vec3 new_hsv = rgb2hsv(new_color);
|
||||
hsv.x = new_hsv.x;
|
||||
vec3 final_rgb = hsv2rgb(hsv);
|
||||
|
||||
color.rgb = final_rgb;
|
||||
}
|
||||
|
||||
|
||||
// Convert from [0.0, 1.0] range to [0, 255] range
|
||||
ivec3 c = ivec3(round(color * 255.0));
|
||||
|
||||
// Apply the dithering pattern
|
||||
if (dithering) {
|
||||
c += ivec3(dithering_pattern(uv));
|
||||
}
|
||||
|
||||
vec3 final_color;
|
||||
if(change_color_depth){
|
||||
// Truncate from 8 bits to color_depth bits
|
||||
c >>= (8 - target_color_depth);
|
||||
final_color = vec3(c) / float(1 << target_color_depth);
|
||||
} else {
|
||||
final_color = vec3(c) / float(1 << 8);
|
||||
}
|
||||
|
||||
// Convert back to [0.0, 1.0] range
|
||||
COLOR.rgb = final_color;
|
||||
}
|
||||
1
Zennysoft.Game.Ma/src/app/App.gdshader.uid
Normal file
1
Zennysoft.Game.Ma/src/app/App.gdshader.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://dmjxo4k2rx1an
|
||||
111
Zennysoft.Game.Ma/src/app/App.tscn
Normal file
111
Zennysoft.Game.Ma/src/app/App.tscn
Normal file
@@ -0,0 +1,111 @@
|
||||
[gd_scene load_steps=8 format=3 uid="uid://cagfc5ridmteu"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://d1f8blk5ucqvq" path="res://src/app/App.cs" id="1_rt73h"]
|
||||
[ext_resource type="PackedScene" uid="uid://rfvnddfqufho" path="res://src/menu/Menu.tscn" id="2_kvwo1"]
|
||||
[ext_resource type="PackedScene" uid="uid://bd0p761qakisw" path="res://src/menu/splash/Splash.tscn" id="3_3st5l"]
|
||||
|
||||
[sub_resource type="Animation" id="Animation_3st5l"]
|
||||
length = 0.001
|
||||
tracks/0/type = "value"
|
||||
tracks/0/imported = false
|
||||
tracks/0/enabled = true
|
||||
tracks/0/path = NodePath("BlankScreenControl/BlankScreen:color")
|
||||
tracks/0/interp = 1
|
||||
tracks/0/loop_wrap = true
|
||||
tracks/0/keys = {
|
||||
"times": PackedFloat32Array(0),
|
||||
"transitions": PackedFloat32Array(1),
|
||||
"update": 0,
|
||||
"values": [Color(0, 0, 0, 1)]
|
||||
}
|
||||
|
||||
[sub_resource type="Animation" id="Animation_1uiag"]
|
||||
resource_name = "fade_in"
|
||||
length = 0.1
|
||||
tracks/0/type = "value"
|
||||
tracks/0/imported = false
|
||||
tracks/0/enabled = true
|
||||
tracks/0/path = NodePath("BlankScreenControl/BlankScreen:color")
|
||||
tracks/0/interp = 1
|
||||
tracks/0/loop_wrap = true
|
||||
tracks/0/keys = {
|
||||
"times": PackedFloat32Array(0, 0.1),
|
||||
"transitions": PackedFloat32Array(1, 1),
|
||||
"update": 0,
|
||||
"values": [Color(0, 0, 0, 1), Color(0, 0, 0, 0)]
|
||||
}
|
||||
|
||||
[sub_resource type="Animation" id="Animation_v0mgf"]
|
||||
resource_name = "fade_out"
|
||||
length = 0.1
|
||||
tracks/0/type = "value"
|
||||
tracks/0/imported = false
|
||||
tracks/0/enabled = true
|
||||
tracks/0/path = NodePath("BlankScreenControl/BlankScreen:color")
|
||||
tracks/0/interp = 1
|
||||
tracks/0/loop_wrap = true
|
||||
tracks/0/keys = {
|
||||
"times": PackedFloat32Array(0, 0.1),
|
||||
"transitions": PackedFloat32Array(1, 1),
|
||||
"update": 0,
|
||||
"values": [Color(0, 0, 0, 0), Color(0, 0, 0, 1)]
|
||||
}
|
||||
|
||||
[sub_resource type="AnimationLibrary" id="AnimationLibrary_3st5l"]
|
||||
_data = {
|
||||
&"RESET": SubResource("Animation_3st5l"),
|
||||
&"fade_in": SubResource("Animation_1uiag"),
|
||||
&"fade_out": SubResource("Animation_v0mgf")
|
||||
}
|
||||
|
||||
[node name="App" type="CanvasLayer"]
|
||||
process_mode = 3
|
||||
script = ExtResource("1_rt73h")
|
||||
|
||||
[node name="SubViewportContainer" type="SubViewportContainer" parent="."]
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
stretch = true
|
||||
|
||||
[node name="GameWindow" type="SubViewport" parent="SubViewportContainer"]
|
||||
unique_name_in_owner = true
|
||||
transparent_bg = true
|
||||
handle_input_locally = false
|
||||
audio_listener_enable_2d = true
|
||||
audio_listener_enable_3d = true
|
||||
size = Vector2i(1280, 960)
|
||||
render_target_update_mode = 4
|
||||
|
||||
[node name="Menu" parent="." instance=ExtResource("2_kvwo1")]
|
||||
unique_name_in_owner = true
|
||||
visible = false
|
||||
|
||||
[node name="Splash" parent="." instance=ExtResource("3_3st5l")]
|
||||
unique_name_in_owner = true
|
||||
|
||||
[node name="BlankScreenControl" type="Control" parent="."]
|
||||
layout_mode = 3
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
|
||||
[node name="BlankScreen" type="ColorRect" parent="BlankScreenControl"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
color = Color(0, 0, 0, 1)
|
||||
|
||||
[node name="AnimationPlayer" type="AnimationPlayer" parent="."]
|
||||
unique_name_in_owner = true
|
||||
libraries = {
|
||||
&"": SubResource("AnimationLibrary_3st5l")
|
||||
}
|
||||
67
Zennysoft.Game.Ma/src/app/domain/AppRepo.cs
Normal file
67
Zennysoft.Game.Ma/src/app/domain/AppRepo.cs
Normal file
@@ -0,0 +1,67 @@
|
||||
using System;
|
||||
|
||||
namespace Zennysoft.Game.Ma;
|
||||
|
||||
public interface IAppRepo : IDisposable
|
||||
{
|
||||
event Action? GameEntered;
|
||||
|
||||
event Action? GameExited;
|
||||
|
||||
event Action? SplashScreenSkipped;
|
||||
|
||||
event Action? MainMenuEntered;
|
||||
|
||||
void SkipSplashScreen();
|
||||
|
||||
void OnMainMenuEntered();
|
||||
|
||||
void OnEnterGame();
|
||||
|
||||
void OnExitGame();
|
||||
|
||||
void OnGameOver();
|
||||
}
|
||||
|
||||
public class AppRepo : IAppRepo
|
||||
{
|
||||
public event Action? SplashScreenSkipped;
|
||||
public event Action? MainMenuEntered;
|
||||
public event Action? GameEntered;
|
||||
public event Action? GameExited;
|
||||
|
||||
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();
|
||||
|
||||
protected void Dispose(bool disposing)
|
||||
{
|
||||
if (!_disposedValue)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
// Dispose managed objects.
|
||||
SplashScreenSkipped = null;
|
||||
MainMenuEntered = null;
|
||||
GameEntered = null;
|
||||
GameExited = null;
|
||||
}
|
||||
|
||||
_disposedValue = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(disposing: true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
||||
1
Zennysoft.Game.Ma/src/app/domain/AppRepo.cs.uid
Normal file
1
Zennysoft.Game.Ma/src/app/domain/AppRepo.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://dyd1r1pl5beku
|
||||
8
Zennysoft.Game.Ma/src/app/state/AppLogic.Data.cs
Normal file
8
Zennysoft.Game.Ma/src/app/state/AppLogic.Data.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
namespace Zennysoft.Game.Ma;
|
||||
public partial class AppLogic
|
||||
{
|
||||
public record Data
|
||||
{
|
||||
public bool ShouldLoadExistingGame { get; set; }
|
||||
}
|
||||
}
|
||||
1
Zennysoft.Game.Ma/src/app/state/AppLogic.Data.cs.uid
Normal file
1
Zennysoft.Game.Ma/src/app/state/AppLogic.Data.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://cbqvl36d7foae
|
||||
24
Zennysoft.Game.Ma/src/app/state/AppLogic.Input.cs
Normal file
24
Zennysoft.Game.Ma/src/app/state/AppLogic.Input.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
namespace Zennysoft.Game.Ma;
|
||||
|
||||
public partial class AppLogic
|
||||
{
|
||||
public static class Input
|
||||
{
|
||||
public readonly record struct NewGame;
|
||||
|
||||
public readonly record struct LoadGame;
|
||||
|
||||
public readonly record struct LoadGameFinished;
|
||||
|
||||
public readonly record struct FadeInFinished;
|
||||
public readonly record struct FadeOutFinished;
|
||||
|
||||
public readonly record struct QuitGame;
|
||||
|
||||
public readonly record struct GameOver;
|
||||
|
||||
public readonly record struct ShowLoadingScreen;
|
||||
|
||||
public readonly record struct SaveFileLoaded;
|
||||
}
|
||||
}
|
||||
1
Zennysoft.Game.Ma/src/app/state/AppLogic.Input.cs.uid
Normal file
1
Zennysoft.Game.Ma/src/app/state/AppLogic.Input.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://b2hwfi78870pf
|
||||
33
Zennysoft.Game.Ma/src/app/state/AppLogic.Output.cs
Normal file
33
Zennysoft.Game.Ma/src/app/state/AppLogic.Output.cs
Normal file
@@ -0,0 +1,33 @@
|
||||
namespace Zennysoft.Game.Ma;
|
||||
|
||||
public partial class AppLogic
|
||||
{
|
||||
public static class Output
|
||||
{
|
||||
public readonly record struct FadeToBlack;
|
||||
|
||||
public readonly record struct ShowSplashScreen;
|
||||
|
||||
public readonly record struct HideSplashScreen;
|
||||
|
||||
public readonly record struct RemoveExistingGame;
|
||||
|
||||
public readonly record struct PlayGame;
|
||||
|
||||
public readonly record struct ShowGame;
|
||||
|
||||
public readonly record struct HideGame;
|
||||
|
||||
public readonly record struct SetupGameScene;
|
||||
|
||||
public readonly record struct ShowLoadingScreen;
|
||||
|
||||
public readonly record struct ShowMainMenu;
|
||||
|
||||
public readonly record struct ExitGame;
|
||||
|
||||
public readonly record struct GameOver;
|
||||
|
||||
public readonly record struct StartLoadingSaveFile;
|
||||
}
|
||||
}
|
||||
1
Zennysoft.Game.Ma/src/app/state/AppLogic.Output.cs.uid
Normal file
1
Zennysoft.Game.Ma/src/app/state/AppLogic.Output.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://dfygx4qdyomdw
|
||||
10
Zennysoft.Game.Ma/src/app/state/AppLogic.State.cs
Normal file
10
Zennysoft.Game.Ma/src/app/state/AppLogic.State.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
using Chickensoft.Introspection;
|
||||
using Chickensoft.LogicBlocks;
|
||||
|
||||
namespace Zennysoft.Game.Ma;
|
||||
|
||||
public partial class AppLogic
|
||||
{
|
||||
[Meta]
|
||||
public abstract partial record State : StateLogic<State>;
|
||||
}
|
||||
1
Zennysoft.Game.Ma/src/app/state/AppLogic.State.cs.uid
Normal file
1
Zennysoft.Game.Ma/src/app/state/AppLogic.State.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://dqc8wddrx0txd
|
||||
13
Zennysoft.Game.Ma/src/app/state/AppLogic.cs
Normal file
13
Zennysoft.Game.Ma/src/app/state/AppLogic.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
using Chickensoft.Introspection;
|
||||
using Chickensoft.LogicBlocks;
|
||||
|
||||
namespace Zennysoft.Game.Ma;
|
||||
|
||||
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.SplashScreen>();
|
||||
}
|
||||
1
Zennysoft.Game.Ma/src/app/state/AppLogic.cs.uid
Normal file
1
Zennysoft.Game.Ma/src/app/state/AppLogic.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://e51dlkiwpksy
|
||||
30
Zennysoft.Game.Ma/src/app/state/AppLogic.g.puml
Normal file
30
Zennysoft.Game.Ma/src/app/state/AppLogic.g.puml
Normal file
@@ -0,0 +1,30 @@
|
||||
@startuml AppLogic
|
||||
state "AppLogic State" as Zennysoft_Game_Ma_AppLogic_State {
|
||||
state "InGame" as Zennysoft_Game_Ma_AppLogic_State_InGame
|
||||
state "LeavingMenu" as Zennysoft_Game_Ma_AppLogic_State_LeavingMenu
|
||||
state "LoadingSaveFile" as Zennysoft_Game_Ma_AppLogic_State_LoadingSaveFile
|
||||
state "MainMenu" as Zennysoft_Game_Ma_AppLogic_State_MainMenu
|
||||
state "SplashScreen" as Zennysoft_Game_Ma_AppLogic_State_SplashScreen
|
||||
}
|
||||
|
||||
Zennysoft_Game_Ma_AppLogic_State_InGame --> Zennysoft_Game_Ma_AppLogic_State_MainMenu : GameOver
|
||||
Zennysoft_Game_Ma_AppLogic_State_LeavingMenu --> Zennysoft_Game_Ma_AppLogic_State_InGame : FadeOutFinished
|
||||
Zennysoft_Game_Ma_AppLogic_State_LeavingMenu --> Zennysoft_Game_Ma_AppLogic_State_LoadingSaveFile : FadeOutFinished
|
||||
Zennysoft_Game_Ma_AppLogic_State_LoadingSaveFile --> Zennysoft_Game_Ma_AppLogic_State_InGame : SaveFileLoaded
|
||||
Zennysoft_Game_Ma_AppLogic_State_MainMenu --> Zennysoft_Game_Ma_AppLogic_State_LeavingMenu : LoadGame
|
||||
Zennysoft_Game_Ma_AppLogic_State_MainMenu --> Zennysoft_Game_Ma_AppLogic_State_LeavingMenu : NewGame
|
||||
Zennysoft_Game_Ma_AppLogic_State_MainMenu --> Zennysoft_Game_Ma_AppLogic_State_MainMenu : QuitGame
|
||||
Zennysoft_Game_Ma_AppLogic_State_SplashScreen --> Zennysoft_Game_Ma_AppLogic_State_MainMenu : FadeOutFinished
|
||||
|
||||
Zennysoft_Game_Ma_AppLogic_State_InGame : OnEnter → ShowGame
|
||||
Zennysoft_Game_Ma_AppLogic_State_InGame : OnExit → HideGame
|
||||
Zennysoft_Game_Ma_AppLogic_State_InGame : OnGameOver → RemoveExistingGame
|
||||
Zennysoft_Game_Ma_AppLogic_State_LeavingMenu : OnEnter → FadeToBlack
|
||||
Zennysoft_Game_Ma_AppLogic_State_LoadingSaveFile : OnEnter → StartLoadingSaveFile
|
||||
Zennysoft_Game_Ma_AppLogic_State_MainMenu : OnEnter → SetupGameScene, ShowMainMenu
|
||||
Zennysoft_Game_Ma_AppLogic_State_MainMenu : OnQuitGame → ExitGame
|
||||
Zennysoft_Game_Ma_AppLogic_State_SplashScreen : OnEnter → ShowSplashScreen
|
||||
Zennysoft_Game_Ma_AppLogic_State_SplashScreen : OnSplashScreenSkipped() → HideSplashScreen
|
||||
|
||||
[*] --> Zennysoft_Game_Ma_AppLogic_State_SplashScreen
|
||||
@enduml
|
||||
@@ -0,0 +1,36 @@
|
||||
using Chickensoft.Introspection;
|
||||
using Chickensoft.LogicBlocks;
|
||||
|
||||
namespace Zennysoft.Game.Ma;
|
||||
|
||||
public partial class AppLogic
|
||||
{
|
||||
public partial record State
|
||||
{
|
||||
[Meta]
|
||||
public partial record InGame : State, IGet<Input.GameOver>
|
||||
{
|
||||
public InGame()
|
||||
{
|
||||
|
||||
this.OnEnter(() =>
|
||||
{
|
||||
Output(new Output.ShowGame());
|
||||
Get<IAppRepo>().OnEnterGame();
|
||||
});
|
||||
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.QuitGame());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
uid://ckb88dvtckagu
|
||||
@@ -0,0 +1,24 @@
|
||||
namespace Zennysoft.Game.Ma;
|
||||
|
||||
using Chickensoft.Introspection;
|
||||
using Chickensoft.LogicBlocks;
|
||||
|
||||
public partial class AppLogic
|
||||
{
|
||||
public partial record State
|
||||
{
|
||||
[Meta]
|
||||
public partial record LeavingMenu : State, IGet<Input.FadeOutFinished>
|
||||
{
|
||||
public LeavingMenu()
|
||||
{
|
||||
this.OnEnter(() => Output(new Output.FadeToBlack()));
|
||||
}
|
||||
|
||||
public Transition On(in Input.FadeOutFinished input) =>
|
||||
Get<Data>().ShouldLoadExistingGame
|
||||
? To<LoadingSaveFile>()
|
||||
: To<InGame>();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
uid://du7y6o0h004sm
|
||||
@@ -0,0 +1,21 @@
|
||||
namespace Zennysoft.Game.Ma;
|
||||
|
||||
using Chickensoft.Introspection;
|
||||
using Chickensoft.LogicBlocks;
|
||||
|
||||
public partial class AppLogic
|
||||
{
|
||||
public partial record State
|
||||
{
|
||||
[Meta]
|
||||
public partial record LoadingSaveFile : State, IGet<Input.SaveFileLoaded>
|
||||
{
|
||||
public LoadingSaveFile()
|
||||
{
|
||||
this.OnEnter(() => Output(new Output.StartLoadingSaveFile()));
|
||||
}
|
||||
|
||||
public Transition On(in Input.SaveFileLoaded input) => To<InGame>();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
uid://b5j2df20jd05i
|
||||
@@ -0,0 +1,42 @@
|
||||
using Chickensoft.Introspection;
|
||||
using Chickensoft.LogicBlocks;
|
||||
|
||||
namespace Zennysoft.Game.Ma;
|
||||
|
||||
public partial class AppLogic
|
||||
{
|
||||
public partial record State
|
||||
{
|
||||
[Meta]
|
||||
public partial record MainMenu : State, IGet<Input.NewGame>, IGet<Input.LoadGame>, IGet<Input.QuitGame>
|
||||
{
|
||||
public MainMenu()
|
||||
{
|
||||
this.OnEnter(() =>
|
||||
{
|
||||
Get<Data>().ShouldLoadExistingGame = false;
|
||||
Output(new Output.SetupGameScene());
|
||||
Get<IAppRepo>().OnMainMenuEntered();
|
||||
Output(new Output.ShowMainMenu());
|
||||
});
|
||||
}
|
||||
|
||||
public Transition On(in Input.NewGame input)
|
||||
{
|
||||
return To<LeavingMenu>();
|
||||
}
|
||||
|
||||
public Transition On(in Input.LoadGame input)
|
||||
{
|
||||
Get<Data>().ShouldLoadExistingGame = true;
|
||||
return To<LeavingMenu>();
|
||||
}
|
||||
|
||||
public Transition On(in Input.QuitGame input)
|
||||
{
|
||||
Output(new Output.ExitGame());
|
||||
return ToSelf();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
uid://b5ehfb8l8u2fy
|
||||
@@ -0,0 +1 @@
|
||||
uid://ddceu88ak7e41
|
||||
@@ -0,0 +1,32 @@
|
||||
namespace Zennysoft.Game.Ma;
|
||||
|
||||
using Chickensoft.Introspection;
|
||||
using Chickensoft.LogicBlocks;
|
||||
|
||||
public partial class AppLogic
|
||||
{
|
||||
public partial record State
|
||||
{
|
||||
[Meta]
|
||||
public partial record SplashScreen : State, IGet<Input.FadeOutFinished>
|
||||
{
|
||||
public SplashScreen()
|
||||
{
|
||||
this.OnEnter(() => Output(new Output.ShowSplashScreen()));
|
||||
|
||||
OnAttach(
|
||||
() => Get<IAppRepo>().SplashScreenSkipped += OnSplashScreenSkipped
|
||||
);
|
||||
|
||||
OnDetach(
|
||||
() => Get<IAppRepo>().SplashScreenSkipped -= OnSplashScreenSkipped
|
||||
);
|
||||
}
|
||||
|
||||
public Transition On(in Input.FadeOutFinished input) => To<MainMenu>();
|
||||
|
||||
public void OnSplashScreenSkipped() =>
|
||||
Output(new Output.HideSplashScreen());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
uid://dxbrwt7jduxu8
|
||||
1
Zennysoft.Game.Ma/src/app/state/states/InGame.cs.uid
Normal file
1
Zennysoft.Game.Ma/src/app/state/states/InGame.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://xix7akau8f8g
|
||||
@@ -0,0 +1 @@
|
||||
uid://cm2spwox38qgx
|
||||
1
Zennysoft.Game.Ma/src/app/state/states/MainMenu.cs.uid
Normal file
1
Zennysoft.Game.Ma/src/app/state/states/MainMenu.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://bjhw05eivyte3
|
||||
58
Zennysoft.Game.Ma/src/audio/DimmableAudioStreamPlayer.cs
Normal file
58
Zennysoft.Game.Ma/src/audio/DimmableAudioStreamPlayer.cs
Normal file
@@ -0,0 +1,58 @@
|
||||
namespace Zennysoft.Game.Ma;
|
||||
|
||||
using Chickensoft.GodotNodeInterfaces;
|
||||
using Godot;
|
||||
|
||||
public interface IDimmableAudioStreamPlayer : IAudioStreamPlayer
|
||||
{
|
||||
/// <summary>Fade this dimmable audio stream track in.</summary>
|
||||
public void FadeIn();
|
||||
/// <summary>Fade this dimmable audio stream track out.</summary>
|
||||
public void FadeOut();
|
||||
}
|
||||
|
||||
public partial class DimmableAudioStreamPlayer :
|
||||
AudioStreamPlayer, IDimmableAudioStreamPlayer
|
||||
{
|
||||
#region Constants
|
||||
// -60 to -80 is considered inaudible for decibels.
|
||||
public const float VOLUME_DB_INAUDIBLE = -80f;
|
||||
public const double FADE_DURATION = 3d; // seconds
|
||||
#endregion Constants
|
||||
|
||||
public ITween? FadeTween { get; set; }
|
||||
|
||||
public float InitialVolumeDb;
|
||||
|
||||
public override void _Ready()
|
||||
{
|
||||
InitialVolumeDb = VolumeDb;
|
||||
VolumeDb = VOLUME_DB_INAUDIBLE;
|
||||
}
|
||||
|
||||
public void FadeIn()
|
||||
{
|
||||
SetupFade(InitialVolumeDb, Tween.EaseType.Out);
|
||||
Play();
|
||||
}
|
||||
|
||||
public void FadeOut()
|
||||
{
|
||||
SetupFade(VOLUME_DB_INAUDIBLE, Tween.EaseType.In);
|
||||
FadeTween!.TweenCallback(Callable.From(Stop));
|
||||
}
|
||||
|
||||
public void SetupFade(float volumeDb, Tween.EaseType ease)
|
||||
{
|
||||
FadeTween?.Kill();
|
||||
|
||||
FadeTween = GodotInterfaces.Adapt<ITween>(CreateTween());
|
||||
|
||||
FadeTween.TweenProperty(
|
||||
this,
|
||||
"volume_db",
|
||||
volumeDb,
|
||||
FADE_DURATION
|
||||
).SetTrans(Tween.TransitionType.Circ).SetEase(ease);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
uid://br4e8xfwd73if
|
||||
130
Zennysoft.Game.Ma/src/audio/InGameAudio.cs
Normal file
130
Zennysoft.Game.Ma/src/audio/InGameAudio.cs
Normal file
@@ -0,0 +1,130 @@
|
||||
using Chickensoft.AutoInject;
|
||||
using Chickensoft.GodotNodeInterfaces;
|
||||
using Chickensoft.Introspection;
|
||||
using Godot;
|
||||
|
||||
namespace Zennysoft.Game.Ma;
|
||||
|
||||
[Meta(typeof(IAutoNode))]
|
||||
public partial class InGameAudio : Node
|
||||
{
|
||||
public override void _Notification(int what) => this.Notify(what);
|
||||
|
||||
[Dependency] public IAppRepo AppRepo => this.DependOn<IAppRepo>();
|
||||
|
||||
[Dependency] public IGameEventDepot GameEventDepot => this.DependOn<IGameEventDepot>();
|
||||
|
||||
[Dependency] public IPlayer Player => this.DependOn<IPlayer>();
|
||||
|
||||
#region BGM Nodes
|
||||
[Node] public IDimmableAudioStreamPlayer MenuBgm { get; set; } = default!;
|
||||
|
||||
[Node] public IDimmableAudioStreamPlayer OverworldBgm { get; set; } = default!;
|
||||
|
||||
[Node] public IDimmableAudioStreamPlayer DungeonThemeABgm { get; set; } = default!;
|
||||
|
||||
[Node] public IDimmableAudioStreamPlayer DungeonThemeBBgm { get; set; } = default!;
|
||||
|
||||
[Node] public IDimmableAudioStreamPlayer DungeonThemeCBgm { get; set; } = default!;
|
||||
#endregion
|
||||
|
||||
#region SFX Nodes
|
||||
[Node] public IAudioStreamPlayer PlayerAttackSFX { get; set; } = default!;
|
||||
|
||||
[Node] public IAudioStreamPlayer MenuScrollSFX { get; set; } = default!;
|
||||
|
||||
[Node] public IAudioStreamPlayer EquipSFX { get; set; } = default!;
|
||||
|
||||
[Node] public IAudioStreamPlayer MenuBackSFX { get; set; } = default!;
|
||||
|
||||
[Node] public IAudioStreamPlayer InventorySortedSFX { get; set; } = default!;
|
||||
|
||||
[Node] public IAudioStreamPlayer HealingItemSFX { get; set; } = default!;
|
||||
|
||||
[Node] public IAudioStreamPlayer TeleportSFX { get; set; } = default!;
|
||||
#endregion
|
||||
|
||||
public IInGameAudioLogic InGameAudioLogic { get; set; } = default!;
|
||||
public InGameAudioLogic.IBinding InGameAudioBinding { get; set; } = default!;
|
||||
|
||||
public void Setup()
|
||||
{
|
||||
InGameAudioLogic = new InGameAudioLogic();
|
||||
}
|
||||
|
||||
public void OnResolved()
|
||||
{
|
||||
InGameAudioLogic.Set(AppRepo);
|
||||
InGameAudioLogic.Set(GameEventDepot);
|
||||
InGameAudioLogic.Set(Player);
|
||||
|
||||
InGameAudioBinding = InGameAudioLogic.Bind();
|
||||
|
||||
InGameAudioBinding
|
||||
.Handle((in InGameAudioLogic.Output.PlayOverworldMusic _) => StartOverworldMusic())
|
||||
.Handle((in InGameAudioLogic.Output.PlayDungeonThemeAMusic _) => StartDungeonThemeA())
|
||||
.Handle((in InGameAudioLogic.Output.PlayMenuScrollSound _) => PlayMenuScrollSound())
|
||||
.Handle((in InGameAudioLogic.Output.PlayEquipSound _) => PlayEquipSound())
|
||||
.Handle((in InGameAudioLogic.Output.PlayMenuBackSound _) => PlayMenuBackSound())
|
||||
.Handle((in InGameAudioLogic.Output.PlayInventorySortedSound _) => PlayInventorySortedSound())
|
||||
.Handle((in InGameAudioLogic.Output.PlayHealingItemSound _) => PlayHealingItemSound())
|
||||
.Handle((in InGameAudioLogic.Output.PlayTeleportSound _) => PlayTeleportSound());
|
||||
|
||||
InGameAudioLogic.Start();
|
||||
}
|
||||
|
||||
public void OnExitTree()
|
||||
{
|
||||
InGameAudioLogic.Stop();
|
||||
InGameAudioBinding.Dispose();
|
||||
}
|
||||
|
||||
private void StartOverworldMusic()
|
||||
{
|
||||
OverworldBgm.Stop();
|
||||
OverworldBgm.FadeIn();
|
||||
}
|
||||
|
||||
private void StartDungeonThemeA()
|
||||
{
|
||||
OverworldBgm.FadeOut();
|
||||
DungeonThemeABgm.Stop();
|
||||
DungeonThemeABgm.FadeIn();
|
||||
}
|
||||
|
||||
private void PlayMenuScrollSound()
|
||||
{
|
||||
MenuScrollSFX.Stop();
|
||||
MenuScrollSFX.Play();
|
||||
}
|
||||
|
||||
private void PlayEquipSound()
|
||||
{
|
||||
EquipSFX.Stop();
|
||||
EquipSFX.Play();
|
||||
}
|
||||
|
||||
private void PlayMenuBackSound()
|
||||
{
|
||||
MenuBackSFX.Stop();
|
||||
MenuBackSFX.Play();
|
||||
}
|
||||
|
||||
private void PlayInventorySortedSound()
|
||||
{
|
||||
InventorySortedSFX.Stop();
|
||||
InventorySortedSFX.Play();
|
||||
}
|
||||
|
||||
private void PlayHealingItemSound()
|
||||
{
|
||||
HealingItemSFX.Stop();
|
||||
HealingItemSFX.Play();
|
||||
}
|
||||
|
||||
private void PlayTeleportSound()
|
||||
{
|
||||
TeleportSFX.Stop();
|
||||
TeleportSFX.Play();
|
||||
}
|
||||
}
|
||||
1
Zennysoft.Game.Ma/src/audio/InGameAudio.cs.uid
Normal file
1
Zennysoft.Game.Ma/src/audio/InGameAudio.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://2mnouyn1jcqs
|
||||
93
Zennysoft.Game.Ma/src/audio/InGameAudio.tscn
Normal file
93
Zennysoft.Game.Ma/src/audio/InGameAudio.tscn
Normal file
@@ -0,0 +1,93 @@
|
||||
[gd_scene load_steps=13 format=3 uid="uid://b16ejcwanod72"]
|
||||
|
||||
[ext_resource type="Script" path="res://src/audio/InGameAudio.cs" id="1_gpmcr"]
|
||||
[ext_resource type="AudioStream" uid="uid://dfu0fksb6slhx" path="res://src/audio/music/droney.mp3" id="2_8hfyr"]
|
||||
[ext_resource type="Script" path="res://src/audio/DimmableAudioStreamPlayer.cs" id="2_857rw"]
|
||||
[ext_resource type="AudioStream" uid="uid://d2jrktp06xsba" path="res://src/audio/music/crossing-the-gate.mp3" id="3_wbmd6"]
|
||||
[ext_resource type="AudioStream" uid="uid://dn2e2hqujlia1" path="res://src/audio/music/tar-winds.mp3" id="4_surnl"]
|
||||
[ext_resource type="AudioStream" uid="uid://t3g04u722f2k" path="res://src/audio/music/useless immune system-1.mp3" id="6_agr3r"]
|
||||
[ext_resource type="AudioStream" uid="uid://dor0in0x2fg48" path="res://src/audio/sfx/TempFFVII/menu-move.ogg" id="7_777nl"]
|
||||
[ext_resource type="AudioStream" uid="uid://r1tryiit38i8" path="res://src/audio/sfx/TempFFVII/menu-back.ogg" id="8_1xcgo"]
|
||||
[ext_resource type="AudioStream" uid="uid://bjj61s8q2gwb8" path="res://src/audio/sfx/TempFFVII/junction.ogg" id="8_kwybb"]
|
||||
[ext_resource type="AudioStream" uid="uid://myx4s8lmarc2" path="res://src/audio/sfx/TempFFVII/something-earned.ogg" id="10_3lcw5"]
|
||||
[ext_resource type="AudioStream" uid="uid://dci08kmwsu6k1" path="res://src/audio/sfx/TempFFVII/teleport.ogg" id="11_offhc"]
|
||||
[ext_resource type="AudioStream" uid="uid://d3sn7c614uj2n" path="res://src/audio/sfx/TempFFVII/sort.ogg" id="12_wprjr"]
|
||||
|
||||
[node name="InGameAudio" type="Node"]
|
||||
process_mode = 3
|
||||
script = ExtResource("1_gpmcr")
|
||||
|
||||
[node name="MenuBgm" type="AudioStreamPlayer" parent="."]
|
||||
unique_name_in_owner = true
|
||||
stream = ExtResource("2_8hfyr")
|
||||
parameters/looping = true
|
||||
script = ExtResource("2_857rw")
|
||||
|
||||
[node name="OverworldBgm" type="AudioStreamPlayer" parent="."]
|
||||
unique_name_in_owner = true
|
||||
stream = ExtResource("3_wbmd6")
|
||||
volume_db = -15.0
|
||||
parameters/looping = true
|
||||
script = ExtResource("2_857rw")
|
||||
|
||||
[node name="DungeonThemeABgm" type="AudioStreamPlayer" parent="."]
|
||||
unique_name_in_owner = true
|
||||
stream = ExtResource("4_surnl")
|
||||
volume_db = -15.0
|
||||
parameters/looping = true
|
||||
script = ExtResource("2_857rw")
|
||||
|
||||
[node name="DungeonThemeBBgm" type="AudioStreamPlayer" parent="."]
|
||||
unique_name_in_owner = true
|
||||
stream = ExtResource("6_agr3r")
|
||||
volume_db = -15.0
|
||||
parameters/looping = true
|
||||
script = ExtResource("2_857rw")
|
||||
|
||||
[node name="DungeonThemeCBgm" type="AudioStreamPlayer" parent="."]
|
||||
unique_name_in_owner = true
|
||||
volume_db = -15.0
|
||||
script = ExtResource("2_857rw")
|
||||
|
||||
[node name="Title_Bgm" type="AudioStreamPlayer" parent="."]
|
||||
unique_name_in_owner = true
|
||||
volume_db = -15.0
|
||||
script = ExtResource("2_857rw")
|
||||
|
||||
[node name="PlayerAttackSFX" type="AudioStreamPlayer" parent="."]
|
||||
unique_name_in_owner = true
|
||||
|
||||
[node name="MenuScrollSFX" type="AudioStreamPlayer" parent="."]
|
||||
unique_name_in_owner = true
|
||||
stream = ExtResource("7_777nl")
|
||||
volume_db = -10.0
|
||||
|
||||
[node name="MenuBackSFX" type="AudioStreamPlayer" parent="."]
|
||||
unique_name_in_owner = true
|
||||
stream = ExtResource("8_1xcgo")
|
||||
volume_db = -10.0
|
||||
|
||||
[node name="EquipSFX" type="AudioStreamPlayer" parent="."]
|
||||
unique_name_in_owner = true
|
||||
stream = ExtResource("8_kwybb")
|
||||
volume_db = -10.0
|
||||
|
||||
[node name="HealSFX" type="AudioStreamPlayer" parent="."]
|
||||
unique_name_in_owner = true
|
||||
stream = ExtResource("10_3lcw5")
|
||||
volume_db = -10.0
|
||||
|
||||
[node name="TeleportSFX" type="AudioStreamPlayer" parent="."]
|
||||
unique_name_in_owner = true
|
||||
stream = ExtResource("11_offhc")
|
||||
volume_db = -18.0
|
||||
|
||||
[node name="InventorySortedSFX" type="AudioStreamPlayer" parent="."]
|
||||
unique_name_in_owner = true
|
||||
stream = ExtResource("12_wprjr")
|
||||
volume_db = -15.0
|
||||
|
||||
[node name="HealingItemSFX" type="AudioStreamPlayer" parent="."]
|
||||
unique_name_in_owner = true
|
||||
stream = ExtResource("10_3lcw5")
|
||||
volume_db = -15.0
|
||||
BIN
Zennysoft.Game.Ma/src/audio/music/crossing-the-gate.mp3
Normal file
BIN
Zennysoft.Game.Ma/src/audio/music/crossing-the-gate.mp3
Normal file
Binary file not shown.
@@ -0,0 +1,19 @@
|
||||
[remap]
|
||||
|
||||
importer="mp3"
|
||||
type="AudioStreamMP3"
|
||||
uid="uid://d2jrktp06xsba"
|
||||
path="res://.godot/imported/crossing-the-gate.mp3-f062dfcb3f59739ce7e55970f8091d25.mp3str"
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://src/audio/music/crossing-the-gate.mp3"
|
||||
dest_files=["res://.godot/imported/crossing-the-gate.mp3-f062dfcb3f59739ce7e55970f8091d25.mp3str"]
|
||||
|
||||
[params]
|
||||
|
||||
loop=false
|
||||
loop_offset=0
|
||||
bpm=0
|
||||
beat_count=0
|
||||
bar_beats=4
|
||||
BIN
Zennysoft.Game.Ma/src/audio/music/droney.mp3
Normal file
BIN
Zennysoft.Game.Ma/src/audio/music/droney.mp3
Normal file
Binary file not shown.
19
Zennysoft.Game.Ma/src/audio/music/droney.mp3.import
Normal file
19
Zennysoft.Game.Ma/src/audio/music/droney.mp3.import
Normal file
@@ -0,0 +1,19 @@
|
||||
[remap]
|
||||
|
||||
importer="mp3"
|
||||
type="AudioStreamMP3"
|
||||
uid="uid://dfu0fksb6slhx"
|
||||
path="res://.godot/imported/droney.mp3-a35fe85a5df08f09cd4cf965e60dc611.mp3str"
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://src/audio/music/droney.mp3"
|
||||
dest_files=["res://.godot/imported/droney.mp3-a35fe85a5df08f09cd4cf965e60dc611.mp3str"]
|
||||
|
||||
[params]
|
||||
|
||||
loop=false
|
||||
loop_offset=0
|
||||
bpm=0
|
||||
beat_count=0
|
||||
bar_beats=4
|
||||
BIN
Zennysoft.Game.Ma/src/audio/music/tar-winds.mp3
Normal file
BIN
Zennysoft.Game.Ma/src/audio/music/tar-winds.mp3
Normal file
Binary file not shown.
19
Zennysoft.Game.Ma/src/audio/music/tar-winds.mp3.import
Normal file
19
Zennysoft.Game.Ma/src/audio/music/tar-winds.mp3.import
Normal file
@@ -0,0 +1,19 @@
|
||||
[remap]
|
||||
|
||||
importer="mp3"
|
||||
type="AudioStreamMP3"
|
||||
uid="uid://dn2e2hqujlia1"
|
||||
path="res://.godot/imported/tar-winds.mp3-7ac6ab80e2c96dfbcd5e5c27c1154ff2.mp3str"
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://src/audio/music/tar-winds.mp3"
|
||||
dest_files=["res://.godot/imported/tar-winds.mp3-7ac6ab80e2c96dfbcd5e5c27c1154ff2.mp3str"]
|
||||
|
||||
[params]
|
||||
|
||||
loop=false
|
||||
loop_offset=0
|
||||
bpm=0
|
||||
beat_count=0
|
||||
bar_beats=4
|
||||
BIN
Zennysoft.Game.Ma/src/audio/music/useless immune system-1.mp3
Normal file
BIN
Zennysoft.Game.Ma/src/audio/music/useless immune system-1.mp3
Normal file
Binary file not shown.
@@ -0,0 +1,19 @@
|
||||
[remap]
|
||||
|
||||
importer="mp3"
|
||||
type="AudioStreamMP3"
|
||||
uid="uid://t3g04u722f2k"
|
||||
path="res://.godot/imported/useless immune system-1.mp3-e40a7d02f05bda566c0eac2b33f080a0.mp3str"
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://src/audio/music/useless immune system-1.mp3"
|
||||
dest_files=["res://.godot/imported/useless immune system-1.mp3-e40a7d02f05bda566c0eac2b33f080a0.mp3str"]
|
||||
|
||||
[params]
|
||||
|
||||
loop=false
|
||||
loop_offset=0
|
||||
bpm=0
|
||||
beat_count=0
|
||||
bar_beats=4
|
||||
BIN
Zennysoft.Game.Ma/src/audio/music/useless immune system.wav
Normal file
BIN
Zennysoft.Game.Ma/src/audio/music/useless immune system.wav
Normal file
Binary file not shown.
@@ -0,0 +1,24 @@
|
||||
[remap]
|
||||
|
||||
importer="wav"
|
||||
type="AudioStreamWAV"
|
||||
uid="uid://6002a12ecfo5"
|
||||
path="res://.godot/imported/useless immune system.wav-90ff2c5c12784f54b1b15c7a7e4603b8.sample"
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://src/audio/music/useless immune system.wav"
|
||||
dest_files=["res://.godot/imported/useless immune system.wav-90ff2c5c12784f54b1b15c7a7e4603b8.sample"]
|
||||
|
||||
[params]
|
||||
|
||||
force/8_bit=false
|
||||
force/mono=false
|
||||
force/max_rate=false
|
||||
force/max_rate_hz=44100
|
||||
edit/trim=false
|
||||
edit/normalize=false
|
||||
edit/loop_mode=0
|
||||
edit/loop_begin=0
|
||||
edit/loop_end=-1
|
||||
compress/mode=0
|
||||
23
Zennysoft.Game.Ma/src/audio/sfx/TempFFVII/Equip.wav.import
Normal file
23
Zennysoft.Game.Ma/src/audio/sfx/TempFFVII/Equip.wav.import
Normal file
@@ -0,0 +1,23 @@
|
||||
[remap]
|
||||
|
||||
importer="wav"
|
||||
type="AudioStreamWAV"
|
||||
uid="uid://t28qhjuibv3f"
|
||||
valid=false
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://src/audio/sfx/TempFFVII/Equip.wav"
|
||||
|
||||
[params]
|
||||
|
||||
force/8_bit=false
|
||||
force/mono=false
|
||||
force/max_rate=false
|
||||
force/max_rate_hz=44100
|
||||
edit/trim=false
|
||||
edit/normalize=false
|
||||
edit/loop_mode=0
|
||||
edit/loop_begin=0
|
||||
edit/loop_end=-1
|
||||
compress/mode=0
|
||||
BIN
Zennysoft.Game.Ma/src/audio/sfx/TempFFVII/junction.ogg
Normal file
BIN
Zennysoft.Game.Ma/src/audio/sfx/TempFFVII/junction.ogg
Normal file
Binary file not shown.
@@ -0,0 +1,19 @@
|
||||
[remap]
|
||||
|
||||
importer="oggvorbisstr"
|
||||
type="AudioStreamOggVorbis"
|
||||
uid="uid://bjj61s8q2gwb8"
|
||||
path="res://.godot/imported/junction.ogg-f4350086a08e048d3008edcdc25abf96.oggvorbisstr"
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://src/audio/sfx/TempFFVII/junction.ogg"
|
||||
dest_files=["res://.godot/imported/junction.ogg-f4350086a08e048d3008edcdc25abf96.oggvorbisstr"]
|
||||
|
||||
[params]
|
||||
|
||||
loop=false
|
||||
loop_offset=0
|
||||
bpm=0
|
||||
beat_count=0
|
||||
bar_beats=4
|
||||
BIN
Zennysoft.Game.Ma/src/audio/sfx/TempFFVII/menu-back.ogg
Normal file
BIN
Zennysoft.Game.Ma/src/audio/sfx/TempFFVII/menu-back.ogg
Normal file
Binary file not shown.
@@ -0,0 +1,19 @@
|
||||
[remap]
|
||||
|
||||
importer="oggvorbisstr"
|
||||
type="AudioStreamOggVorbis"
|
||||
uid="uid://r1tryiit38i8"
|
||||
path="res://.godot/imported/menu-back.ogg-3ec385c1a9cfaaa1be4ba85197708f0c.oggvorbisstr"
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://src/audio/sfx/TempFFVII/menu-back.ogg"
|
||||
dest_files=["res://.godot/imported/menu-back.ogg-3ec385c1a9cfaaa1be4ba85197708f0c.oggvorbisstr"]
|
||||
|
||||
[params]
|
||||
|
||||
loop=false
|
||||
loop_offset=0
|
||||
bpm=0
|
||||
beat_count=0
|
||||
bar_beats=4
|
||||
BIN
Zennysoft.Game.Ma/src/audio/sfx/TempFFVII/menu-move.ogg
Normal file
BIN
Zennysoft.Game.Ma/src/audio/sfx/TempFFVII/menu-move.ogg
Normal file
Binary file not shown.
@@ -0,0 +1,19 @@
|
||||
[remap]
|
||||
|
||||
importer="oggvorbisstr"
|
||||
type="AudioStreamOggVorbis"
|
||||
uid="uid://dor0in0x2fg48"
|
||||
path="res://.godot/imported/menu-move.ogg-d71b0989e00dd1d4488a72c7dde3d41d.oggvorbisstr"
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://src/audio/sfx/TempFFVII/menu-move.ogg"
|
||||
dest_files=["res://.godot/imported/menu-move.ogg-d71b0989e00dd1d4488a72c7dde3d41d.oggvorbisstr"]
|
||||
|
||||
[params]
|
||||
|
||||
loop=false
|
||||
loop_offset=0
|
||||
bpm=0
|
||||
beat_count=0
|
||||
bar_beats=4
|
||||
BIN
Zennysoft.Game.Ma/src/audio/sfx/TempFFVII/menu.wav
Normal file
BIN
Zennysoft.Game.Ma/src/audio/sfx/TempFFVII/menu.wav
Normal file
Binary file not shown.
24
Zennysoft.Game.Ma/src/audio/sfx/TempFFVII/menu.wav.import
Normal file
24
Zennysoft.Game.Ma/src/audio/sfx/TempFFVII/menu.wav.import
Normal file
@@ -0,0 +1,24 @@
|
||||
[remap]
|
||||
|
||||
importer="wav"
|
||||
type="AudioStreamWAV"
|
||||
uid="uid://tce7m18vkgao"
|
||||
path="res://.godot/imported/menu.wav-3931712b8a8483f269018c4a880368b2.sample"
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://src/audio/sfx/TempFFVII/menu.wav"
|
||||
dest_files=["res://.godot/imported/menu.wav-3931712b8a8483f269018c4a880368b2.sample"]
|
||||
|
||||
[params]
|
||||
|
||||
force/8_bit=false
|
||||
force/mono=false
|
||||
force/max_rate=false
|
||||
force/max_rate_hz=44100
|
||||
edit/trim=false
|
||||
edit/normalize=false
|
||||
edit/loop_mode=0
|
||||
edit/loop_begin=0
|
||||
edit/loop_end=-1
|
||||
compress/mode=0
|
||||
BIN
Zennysoft.Game.Ma/src/audio/sfx/TempFFVII/something-earned.ogg
Normal file
BIN
Zennysoft.Game.Ma/src/audio/sfx/TempFFVII/something-earned.ogg
Normal file
Binary file not shown.
@@ -0,0 +1,19 @@
|
||||
[remap]
|
||||
|
||||
importer="oggvorbisstr"
|
||||
type="AudioStreamOggVorbis"
|
||||
uid="uid://myx4s8lmarc2"
|
||||
path="res://.godot/imported/something-earned.ogg-150627e4deb45db30e8dd2f98ddcc5a8.oggvorbisstr"
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://src/audio/sfx/TempFFVII/something-earned.ogg"
|
||||
dest_files=["res://.godot/imported/something-earned.ogg-150627e4deb45db30e8dd2f98ddcc5a8.oggvorbisstr"]
|
||||
|
||||
[params]
|
||||
|
||||
loop=false
|
||||
loop_offset=0
|
||||
bpm=0
|
||||
beat_count=0
|
||||
bar_beats=4
|
||||
BIN
Zennysoft.Game.Ma/src/audio/sfx/TempFFVII/sort.ogg
Normal file
BIN
Zennysoft.Game.Ma/src/audio/sfx/TempFFVII/sort.ogg
Normal file
Binary file not shown.
19
Zennysoft.Game.Ma/src/audio/sfx/TempFFVII/sort.ogg.import
Normal file
19
Zennysoft.Game.Ma/src/audio/sfx/TempFFVII/sort.ogg.import
Normal file
@@ -0,0 +1,19 @@
|
||||
[remap]
|
||||
|
||||
importer="oggvorbisstr"
|
||||
type="AudioStreamOggVorbis"
|
||||
uid="uid://d3sn7c614uj2n"
|
||||
path="res://.godot/imported/sort.ogg-cb2a2c4769c8e6574221a3c313e75bcf.oggvorbisstr"
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://src/audio/sfx/TempFFVII/sort.ogg"
|
||||
dest_files=["res://.godot/imported/sort.ogg-cb2a2c4769c8e6574221a3c313e75bcf.oggvorbisstr"]
|
||||
|
||||
[params]
|
||||
|
||||
loop=false
|
||||
loop_offset=0
|
||||
bpm=0
|
||||
beat_count=0
|
||||
bar_beats=4
|
||||
BIN
Zennysoft.Game.Ma/src/audio/sfx/TempFFVII/teleport.ogg
Normal file
BIN
Zennysoft.Game.Ma/src/audio/sfx/TempFFVII/teleport.ogg
Normal file
Binary file not shown.
@@ -0,0 +1,19 @@
|
||||
[remap]
|
||||
|
||||
importer="oggvorbisstr"
|
||||
type="AudioStreamOggVorbis"
|
||||
uid="uid://dci08kmwsu6k1"
|
||||
path="res://.godot/imported/teleport.ogg-9024f7b675b201a391dee183da020b1d.oggvorbisstr"
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://src/audio/sfx/TempFFVII/teleport.ogg"
|
||||
dest_files=["res://.godot/imported/teleport.ogg-9024f7b675b201a391dee183da020b1d.oggvorbisstr"]
|
||||
|
||||
[params]
|
||||
|
||||
loop=false
|
||||
loop_offset=0
|
||||
bpm=0
|
||||
beat_count=0
|
||||
bar_beats=4
|
||||
33
Zennysoft.Game.Ma/src/audio/state/InGameAudioLogic.Output.cs
Normal file
33
Zennysoft.Game.Ma/src/audio/state/InGameAudioLogic.Output.cs
Normal file
@@ -0,0 +1,33 @@
|
||||
namespace Zennysoft.Game.Ma;
|
||||
|
||||
public partial class InGameAudioLogic
|
||||
{
|
||||
public static class Output
|
||||
{
|
||||
#region BGM
|
||||
public readonly record struct PlayOverworldMusic;
|
||||
|
||||
public readonly record struct PlayDungeonThemeAMusic;
|
||||
#endregion
|
||||
|
||||
#region SFX
|
||||
public readonly record struct PlayPlayerAttackSound;
|
||||
|
||||
public readonly record struct PlayMenuScrollSound;
|
||||
|
||||
public readonly record struct PlayEquipSound;
|
||||
|
||||
public readonly record struct PlayInventorySortedSound;
|
||||
|
||||
public readonly record struct PlayMenuBackSound;
|
||||
|
||||
public readonly record struct PlayHealingItemSound;
|
||||
|
||||
public readonly record struct PlayTeleportSound;
|
||||
#endregion
|
||||
|
||||
public readonly record struct PlayGameMusic;
|
||||
|
||||
public readonly record struct StopGameMusic;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
uid://bfnbplmd35454
|
||||
12
Zennysoft.Game.Ma/src/audio/state/InGameAudioLogic.State.cs
Normal file
12
Zennysoft.Game.Ma/src/audio/state/InGameAudioLogic.State.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
using Chickensoft.Introspection;
|
||||
using Chickensoft.LogicBlocks;
|
||||
|
||||
namespace Zennysoft.Game.Ma;
|
||||
|
||||
public partial class InGameAudioLogic
|
||||
{
|
||||
[Meta]
|
||||
public partial record State : StateLogic<State>
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
uid://c8cfpu81338hk
|
||||
13
Zennysoft.Game.Ma/src/audio/state/InGameAudioLogic.cs
Normal file
13
Zennysoft.Game.Ma/src/audio/state/InGameAudioLogic.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
using Chickensoft.Introspection;
|
||||
using Chickensoft.LogicBlocks;
|
||||
|
||||
namespace Zennysoft.Game.Ma;
|
||||
public interface IInGameAudioLogic : ILogicBlock<InGameAudioLogic.State>;
|
||||
|
||||
[Meta]
|
||||
[LogicBlock(typeof(State))]
|
||||
public partial class InGameAudioLogic :
|
||||
LogicBlock<InGameAudioLogic.State>, IInGameAudioLogic
|
||||
{
|
||||
public override Transition GetInitialState() => To<Enabled>();
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
uid://on5thilbaogw
|
||||
@@ -0,0 +1,11 @@
|
||||
using Chickensoft.Introspection;
|
||||
|
||||
namespace Zennysoft.Game.Ma;
|
||||
|
||||
public partial class InGameAudioLogic
|
||||
{
|
||||
[Meta]
|
||||
public partial record Disabled : State
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
uid://c02hwxip7xksf
|
||||
@@ -0,0 +1,63 @@
|
||||
using Chickensoft.Introspection;
|
||||
|
||||
namespace Zennysoft.Game.Ma;
|
||||
|
||||
public partial class InGameAudioLogic
|
||||
{
|
||||
[Meta]
|
||||
public partial record Enabled : State
|
||||
{
|
||||
public Enabled()
|
||||
{
|
||||
OnAttach(() =>
|
||||
{
|
||||
var player = Get<IPlayer>();
|
||||
OnOverworldEntered();
|
||||
var gameEventDepot = Get<IGameEventDepot>();
|
||||
gameEventDepot.OverworldEntered += OnOverworldEntered;
|
||||
gameEventDepot.DungeonAThemeAreaEntered += OnDungeonAThemeEntered;
|
||||
gameEventDepot.MenuScrolled += OnMenuScrolled;
|
||||
gameEventDepot.MenuBackedOut += OnMenuBackedOut;
|
||||
player.EquippedWeapon.Changed += OnEquippedItem;
|
||||
player.EquippedArmor.Changed += OnEquippedItem;
|
||||
player.EquippedAccessory.Changed += OnEquippedItem;
|
||||
gameEventDepot.InventorySorted += OnInventorySorted;
|
||||
gameEventDepot.HealingItemConsumed += OnHealingItemConsumed;
|
||||
gameEventDepot.RestorativePickedUp += OnRestorativePickedUp;
|
||||
gameEventDepot.TeleportEntered += OnTeleportEntered;
|
||||
});
|
||||
OnDetach(() =>
|
||||
{
|
||||
var gameEventDepot = Get<IGameEventDepot>();
|
||||
var player = Get<IPlayer>();
|
||||
gameEventDepot.OverworldEntered -= OnOverworldEntered;
|
||||
gameEventDepot.DungeonAThemeAreaEntered -= OnDungeonAThemeEntered;
|
||||
gameEventDepot.MenuScrolled -= OnMenuScrolled;
|
||||
gameEventDepot.MenuBackedOut -= OnMenuBackedOut;
|
||||
player.EquippedWeapon.Changed -= OnEquippedItem;
|
||||
player.EquippedArmor.Changed -= OnEquippedItem;
|
||||
player.EquippedAccessory.Changed -= OnEquippedItem;
|
||||
gameEventDepot.InventorySorted -= OnInventorySorted;
|
||||
gameEventDepot.TeleportEntered -= OnTeleportEntered;
|
||||
});
|
||||
}
|
||||
|
||||
private void OnRestorativePickedUp(Restorative restorative) => Output(new Output.PlayHealingItemSound());
|
||||
|
||||
private void OnMenuBackedOut() => Output(new Output.PlayMenuBackSound());
|
||||
|
||||
private void OnHealingItemConsumed(ConsumableItemStats stats) => Output(new Output.PlayHealingItemSound());
|
||||
|
||||
private void OnInventorySorted() => Output(new Output.PlayInventorySortedSound());
|
||||
|
||||
private void OnEquippedItem(EquipableItem equipableItem) => Output(new Output.PlayEquipSound());
|
||||
|
||||
private void OnOverworldEntered() => Output(new Output.PlayOverworldMusic());
|
||||
|
||||
private void OnDungeonAThemeEntered() => Output(new Output.PlayDungeonThemeAMusic());
|
||||
|
||||
private void OnMenuScrolled() => Output(new Output.PlayMenuScrollSound());
|
||||
|
||||
private void OnTeleportEntered() => Output(new Output.PlayTeleportSound());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
uid://ddvs2b5hjchag
|
||||
162
Zennysoft.Game.Ma/src/boss/Boss.cs
Normal file
162
Zennysoft.Game.Ma/src/boss/Boss.cs
Normal file
@@ -0,0 +1,162 @@
|
||||
using Chickensoft.AutoInject;
|
||||
using Chickensoft.Collections;
|
||||
using Chickensoft.GodotNodeInterfaces;
|
||||
using Chickensoft.Introspection;
|
||||
using Godot;
|
||||
|
||||
namespace Zennysoft.Game.Ma;
|
||||
|
||||
public interface IBoss : ICharacterBody3D
|
||||
{
|
||||
public void Activate();
|
||||
|
||||
public void TakeDamage(double damage, ElementType elementType = ElementType.None, bool isCriticalHit = false, bool ignoreDefense = false, bool ignoreElementalResistance = false);
|
||||
|
||||
public void MoveToLocation(Vector3 target, float delta);
|
||||
|
||||
public void StartAttackTimer();
|
||||
|
||||
public void StopAttackTimer();
|
||||
|
||||
public double CurrentHP { get; }
|
||||
|
||||
public AutoProp<bool> IsDefeated { get; }
|
||||
}
|
||||
|
||||
[Meta(typeof(IAutoNode))]
|
||||
public partial class Boss : CharacterBody3D, IBoss, IProvide<IBossLogic>
|
||||
{
|
||||
public override void _Notification(int what) => this.Notify(what);
|
||||
|
||||
public double CurrentHP => _currentHP.Value;
|
||||
|
||||
public AutoProp<bool> IsDefeated { get; set; }
|
||||
|
||||
private AutoProp<double> _currentHP { get; set; }
|
||||
|
||||
#region Autoinject
|
||||
protected IBossLogic _bossLogic { get; set; } = default!;
|
||||
|
||||
IBossLogic IProvide<IBossLogic>.Value() => _bossLogic;
|
||||
|
||||
public BossLogic.IBinding BossBinding { get; set; } = default!;
|
||||
#endregion
|
||||
|
||||
#region Export
|
||||
[Export] private EnemyStatResource _bossStatResource { get; set; } = default!;
|
||||
#endregion
|
||||
|
||||
#region Dependencies
|
||||
[Dependency] private IPlayer _player => this.DependOn<IPlayer>();
|
||||
#endregion
|
||||
|
||||
#region Nodes
|
||||
[Node] private AnimationTree _animationTree { get; set; } = default!;
|
||||
|
||||
[Node] private Timer _attackTimer { get; set; } = default!;
|
||||
|
||||
[Node] private AnimationPlayer _hitAnimation { get; set; } = default!;
|
||||
|
||||
[Node] private Area3D _hitbox { get; set; } = default!;
|
||||
|
||||
[Node] private Area3D _attackBox { get; set; } = default!;
|
||||
|
||||
[Node] private Area3D _secondaryAttackBox { get; set; } = default!;
|
||||
#endregion
|
||||
|
||||
public void Setup()
|
||||
{
|
||||
_bossLogic = new BossLogic();
|
||||
_bossLogic.Set(this as IBoss);
|
||||
_bossLogic.Set(_player);
|
||||
|
||||
SetPhysicsProcess(false);
|
||||
Hide();
|
||||
}
|
||||
|
||||
public void OnResolved()
|
||||
{
|
||||
BossBinding = _bossLogic.Bind();
|
||||
BossBinding
|
||||
.Handle((in BossLogic.Output.Defeated output) =>
|
||||
{
|
||||
_hitAnimation.Play("Defeated");
|
||||
});
|
||||
this.Provide();
|
||||
_bossLogic.Start();
|
||||
_currentHP = new AutoProp<double>(_bossStatResource.MaximumHP);
|
||||
_currentHP.Sync += OnHPChanged;
|
||||
_attackTimer.Timeout += AttackTimer_Timeout;
|
||||
}
|
||||
|
||||
public void Activate()
|
||||
{
|
||||
_bossLogic.Input(new BossLogic.Input.Activate());
|
||||
}
|
||||
|
||||
public void TakeDamage(double damage, ElementType elementType, bool isCriticalHit = false, bool ignoreDefense = false, bool ignoreElementalResistance = false)
|
||||
{
|
||||
if (_currentHP.Value > 0)
|
||||
{
|
||||
if (!ignoreElementalResistance)
|
||||
damage = CalculateElementalResistance(damage, elementType);
|
||||
if (!ignoreDefense)
|
||||
damage = CalculateDefenseResistance(damage);
|
||||
if (isCriticalHit)
|
||||
damage *= 2;
|
||||
GD.Print($"Enemy Hit for {damage} damage.");
|
||||
_currentHP.OnNext(_currentHP.Value - damage);
|
||||
GD.Print("Current HP: " + _currentHP.Value);
|
||||
|
||||
if (_currentHP.Value <= 0)
|
||||
return;
|
||||
|
||||
//EnemyModelView.PlayHitAnimation();
|
||||
}
|
||||
}
|
||||
|
||||
public void MoveToLocation(Vector3 target, float delta) => throw new System.NotImplementedException();
|
||||
|
||||
public void StartAttackTimer() => _attackTimer.Start();
|
||||
|
||||
public void StopAttackTimer() => _attackTimer.Stop();
|
||||
|
||||
private void AttackTimer_Timeout() => _bossLogic.Input(new BossLogic.Input.AttackTimer());
|
||||
|
||||
public virtual void TakeAction()
|
||||
{
|
||||
}
|
||||
|
||||
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 double CalculateElementalResistance(double incomingDamage, ElementType incomingElementType)
|
||||
{
|
||||
if (incomingElementType == ElementType.Aeolic)
|
||||
return Mathf.Max(incomingDamage - (incomingDamage * _bossStatResource.AeolicResistance), 0.0);
|
||||
if (incomingElementType == ElementType.Hydric)
|
||||
return Mathf.Max(incomingDamage - (incomingDamage * _bossStatResource.HydricResistance), 0.0);
|
||||
if (incomingElementType == ElementType.Igneous)
|
||||
return Mathf.Max(incomingDamage - (incomingDamage * _bossStatResource.IgneousResistance), 0.0);
|
||||
if (incomingElementType == ElementType.Ferrum)
|
||||
return Mathf.Max(incomingDamage - (incomingDamage * _bossStatResource.FerrumResistance), 0.0);
|
||||
if (incomingElementType == ElementType.Telluric)
|
||||
return Mathf.Max(incomingDamage - (incomingDamage * _bossStatResource.TelluricResistance), 0.0);
|
||||
|
||||
return Mathf.Max(incomingDamage, 0.0);
|
||||
}
|
||||
|
||||
private double CalculateDefenseResistance(double incomingDamage)
|
||||
{
|
||||
return Mathf.Max(incomingDamage - _bossStatResource.CurrentDefense, 0.0);
|
||||
}
|
||||
}
|
||||
1
Zennysoft.Game.Ma/src/boss/Boss.cs.uid
Normal file
1
Zennysoft.Game.Ma/src/boss/Boss.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://dwpswg0xufxa7
|
||||
19
Zennysoft.Game.Ma/src/boss/state/BossLogic.Input.cs
Normal file
19
Zennysoft.Game.Ma/src/boss/state/BossLogic.Input.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
namespace Zennysoft.Game.Ma;
|
||||
|
||||
public partial class BossLogic
|
||||
{
|
||||
public static class Input
|
||||
{
|
||||
public readonly record struct Activate;
|
||||
|
||||
public readonly record struct PhysicsTick(double Delta);
|
||||
|
||||
public readonly record struct StopMoving;
|
||||
|
||||
public readonly record struct AttackTimer;
|
||||
|
||||
public readonly record struct StartAttacking;
|
||||
|
||||
public readonly record struct BossDefeated;
|
||||
}
|
||||
}
|
||||
1
Zennysoft.Game.Ma/src/boss/state/BossLogic.Input.cs.uid
Normal file
1
Zennysoft.Game.Ma/src/boss/state/BossLogic.Input.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://cc1wadksmbq6h
|
||||
17
Zennysoft.Game.Ma/src/boss/state/BossLogic.Output.cs
Normal file
17
Zennysoft.Game.Ma/src/boss/state/BossLogic.Output.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
using Godot;
|
||||
|
||||
namespace Zennysoft.Game.Ma;
|
||||
|
||||
public partial class BossLogic
|
||||
{
|
||||
public static class Output
|
||||
{
|
||||
public readonly record struct MoveTowardsPlayer(Vector3 TargetPosition);
|
||||
|
||||
public readonly record struct MovementComputed(Vector3 LinearVelocity);
|
||||
|
||||
public readonly record struct TakeAction;
|
||||
|
||||
public readonly record struct Defeated;
|
||||
}
|
||||
}
|
||||
1
Zennysoft.Game.Ma/src/boss/state/BossLogic.Output.cs.uid
Normal file
1
Zennysoft.Game.Ma/src/boss/state/BossLogic.Output.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://c7r8l4w4nwd8x
|
||||
15
Zennysoft.Game.Ma/src/boss/state/BossLogic.State.cs
Normal file
15
Zennysoft.Game.Ma/src/boss/state/BossLogic.State.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
using Chickensoft.Introspection;
|
||||
using Chickensoft.LogicBlocks;
|
||||
|
||||
namespace Zennysoft.Game.Ma;
|
||||
|
||||
public partial class BossLogic
|
||||
{
|
||||
[Meta]
|
||||
public abstract partial record State : StateLogic<State>
|
||||
{
|
||||
protected State()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
1
Zennysoft.Game.Ma/src/boss/state/BossLogic.State.cs.uid
Normal file
1
Zennysoft.Game.Ma/src/boss/state/BossLogic.State.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://ds1hjuenunrht
|
||||
13
Zennysoft.Game.Ma/src/boss/state/BossLogic.cs
Normal file
13
Zennysoft.Game.Ma/src/boss/state/BossLogic.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
using Chickensoft.Introspection;
|
||||
using Chickensoft.LogicBlocks;
|
||||
|
||||
namespace Zennysoft.Game.Ma;
|
||||
|
||||
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.Unactivated>();
|
||||
}
|
||||
1
Zennysoft.Game.Ma/src/boss/state/BossLogic.cs.uid
Normal file
1
Zennysoft.Game.Ma/src/boss/state/BossLogic.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://dnpj001c3iabh
|
||||
29
Zennysoft.Game.Ma/src/boss/state/BossLogic.g.puml
Normal file
29
Zennysoft.Game.Ma/src/boss/state/BossLogic.g.puml
Normal file
@@ -0,0 +1,29 @@
|
||||
@startuml BossLogic
|
||||
state "BossLogic State" as GameJamDungeon_BossLogic_State {
|
||||
state "Defeated" as GameJamDungeon_BossLogic_State_Defeated
|
||||
state "Alive" as GameJamDungeon_BossLogic_State_Alive {
|
||||
state "Idle" as GameJamDungeon_BossLogic_State_Idle
|
||||
state "EngagePlayer" as GameJamDungeon_BossLogic_State_EngagePlayer
|
||||
state "ApproachPlayer" as GameJamDungeon_BossLogic_State_ApproachPlayer
|
||||
state "Activated" as GameJamDungeon_BossLogic_State_Activated {
|
||||
state "Attacking" as GameJamDungeon_BossLogic_State_Attacking
|
||||
state "FollowPlayer" as GameJamDungeon_BossLogic_State_FollowPlayer
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GameJamDungeon_BossLogic_State_Alive --> GameJamDungeon_BossLogic_State_Defeated : BossDefeated
|
||||
GameJamDungeon_BossLogic_State_ApproachPlayer --> GameJamDungeon_BossLogic_State_ApproachPlayer : PhysicsTick
|
||||
GameJamDungeon_BossLogic_State_ApproachPlayer --> GameJamDungeon_BossLogic_State_EngagePlayer : PhysicsTick
|
||||
GameJamDungeon_BossLogic_State_EngagePlayer --> GameJamDungeon_BossLogic_State_ApproachPlayer : PhysicsTick
|
||||
GameJamDungeon_BossLogic_State_EngagePlayer --> GameJamDungeon_BossLogic_State_EngagePlayer : PhysicsTick
|
||||
GameJamDungeon_BossLogic_State_EngagePlayer --> GameJamDungeon_BossLogic_State_EngagePlayer : PrimaryAttack
|
||||
GameJamDungeon_BossLogic_State_EngagePlayer --> GameJamDungeon_BossLogic_State_EngagePlayer : SecondaryAttack
|
||||
GameJamDungeon_BossLogic_State_FollowPlayer --> GameJamDungeon_BossLogic_State_FollowPlayer : PhysicsTick
|
||||
GameJamDungeon_BossLogic_State_Idle --> GameJamDungeon_BossLogic_State_ApproachPlayer : Activate
|
||||
|
||||
GameJamDungeon_BossLogic_State : On() → Defeated
|
||||
GameJamDungeon_BossLogic_State_Alive : OnBossDefeated → Defeated
|
||||
|
||||
[*] --> GameJamDungeon_BossLogic_State_Idle
|
||||
@enduml
|
||||
@@ -0,0 +1,14 @@
|
||||
using Chickensoft.Introspection;
|
||||
|
||||
namespace Zennysoft.Game.Ma;
|
||||
|
||||
public partial class BossLogic
|
||||
{
|
||||
public partial record State
|
||||
{
|
||||
[Meta, Id("boss_logic_state_activated")]
|
||||
public partial record Activated : Alive
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
uid://dk60nmw42pm82
|
||||
@@ -0,0 +1,37 @@
|
||||
using Chickensoft.Introspection;
|
||||
using Godot;
|
||||
|
||||
namespace Zennysoft.Game.Ma;
|
||||
|
||||
public partial class BossLogic
|
||||
{
|
||||
public partial record State
|
||||
{
|
||||
[Meta, Id("boss_logic_state_alive")]
|
||||
public abstract partial record Alive : State, IGet<Input.BossDefeated>, IGet<Input.AttackTimer>, IGet<Input.StopMoving>, IGet<Input.StartAttacking>
|
||||
{
|
||||
}
|
||||
|
||||
public Transition On(in Input.AttackTimer input)
|
||||
{
|
||||
Output(new Output.TakeAction());
|
||||
return To<Attacking>();
|
||||
}
|
||||
|
||||
public Transition On(in Input.BossDefeated input)
|
||||
{
|
||||
Output(new Output.Defeated());
|
||||
return To<Defeated>();
|
||||
}
|
||||
|
||||
public Transition On(in Input.StopMoving input)
|
||||
{
|
||||
return To<Idle>();
|
||||
}
|
||||
|
||||
public Transition On(in Input.StartAttacking input)
|
||||
{
|
||||
return To<Attacking>();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
uid://bbwhocehdcsbt
|
||||
@@ -0,0 +1,33 @@
|
||||
using Chickensoft.Introspection;
|
||||
using Godot;
|
||||
|
||||
namespace Zennysoft.Game.Ma;
|
||||
|
||||
public partial class BossLogic
|
||||
{
|
||||
public partial record State
|
||||
{
|
||||
[Meta, Id("boss_logic_state_approach_player")]
|
||||
public partial record ApproachPlayer : Alive, IGet<Input.PhysicsTick>
|
||||
{
|
||||
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);
|
||||
|
||||
if (boss.GlobalPosition.DistanceTo(player.CurrentPosition) <= 5.0f)
|
||||
return To<EngagePlayer>();
|
||||
|
||||
var moveToward = boss.GlobalPosition.MoveToward(playerPosition, (float)delta * 3f);
|
||||
boss.GlobalPosition = moveToward;
|
||||
|
||||
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);
|
||||
return ToSelf();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
uid://crhdnddatd7ap
|
||||
@@ -0,0 +1,19 @@
|
||||
using Chickensoft.Introspection;
|
||||
|
||||
namespace Zennysoft.Game.Ma;
|
||||
|
||||
public partial class BossLogic
|
||||
{
|
||||
public partial record State
|
||||
{
|
||||
[Meta, Id("boss_logic_state_attacking")]
|
||||
public partial record Attacking : Activated, IGet<Input.StopMoving>
|
||||
{
|
||||
public Attacking()
|
||||
{
|
||||
OnAttach(() => Get<IEnemy>().StartAttackTimer());
|
||||
OnDetach(() => Get<IEnemy>().StopAttackTimer());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
uid://crsw8t5nr4ots
|
||||
@@ -0,0 +1,14 @@
|
||||
using Chickensoft.Introspection;
|
||||
|
||||
namespace Zennysoft.Game.Ma;
|
||||
|
||||
public partial class BossLogic
|
||||
{
|
||||
public partial record State
|
||||
{
|
||||
[Meta, Id("boss_logic_state_defeated")]
|
||||
public partial record Defeated : State
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
uid://beymhvkyuay4h
|
||||
@@ -0,0 +1,31 @@
|
||||
using Chickensoft.Introspection;
|
||||
using Godot;
|
||||
|
||||
namespace Zennysoft.Game.Ma;
|
||||
|
||||
public partial class BossLogic
|
||||
{
|
||||
public partial record State
|
||||
{
|
||||
[Meta, Id("boss_logic_state_engage_player")]
|
||||
public partial record EngagePlayer : Alive, IGet<Input.PhysicsTick>
|
||||
{
|
||||
public EngagePlayer()
|
||||
{
|
||||
}
|
||||
|
||||
public Transition On(in Input.PhysicsTick input)
|
||||
{
|
||||
var boss = Get<IBoss>();
|
||||
var player = Get<IPlayer>();
|
||||
var delta = (float)input.Delta;
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
uid://bvwwpwvlou5gg
|
||||
@@ -0,0 +1,22 @@
|
||||
using Chickensoft.Introspection;
|
||||
|
||||
namespace Zennysoft.Game.Ma;
|
||||
|
||||
public partial class BossLogic
|
||||
{
|
||||
public partial record State
|
||||
{
|
||||
[Meta, Id("boss_logic_state_followplayer")]
|
||||
public partial record FollowPlayer : Activated, IGet<Input.PhysicsTick>
|
||||
{
|
||||
public Transition On(in Input.PhysicsTick input)
|
||||
{
|
||||
var enemy = Get<IEnemy>();
|
||||
var player = Get<IPlayer>();
|
||||
var target = player.CurrentPosition;
|
||||
enemy.SetTarget(target);
|
||||
return ToSelf();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
uid://0uou7c2gl6jr
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user