November Merge
This commit is contained in:
@@ -7,7 +7,7 @@ public partial class AppLogic
|
||||
public partial record State
|
||||
{
|
||||
[Meta]
|
||||
public partial record MainMenu : State, IGet<Input.NewGame>, IGet<Input.LoadGame>, IGet<Input.EnemyViewerOpened>
|
||||
public partial record MainMenu : State, IGet<Input.NewGame>, IGet<Input.EnemyViewerOpened>, IGet<Input.QuitGame>
|
||||
{
|
||||
public MainMenu()
|
||||
{
|
||||
@@ -16,7 +16,11 @@ public partial class AppLogic
|
||||
public Transition On(in Input.NewGame input) => To<GameStarted>();
|
||||
|
||||
public Transition On(in Input.EnemyViewerOpened input) => To<EnemyViewer>();
|
||||
public Transition On(in Input.LoadGame input) => To<LoadingSaveFile>();
|
||||
public Transition On(in Input.QuitGame input)
|
||||
{
|
||||
Output(new Output.ExitGame());
|
||||
return ToSelf();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Chickensoft.Collections;
|
||||
using Godot;
|
||||
using Zennysoft.Ma.Adapter.Entity;
|
||||
|
||||
namespace Zennysoft.Ma.Adapter;
|
||||
@@ -28,4 +29,5 @@ public interface IEquipmentComponent : IEntityComponent
|
||||
|
||||
public ElementalResistanceSet ElementalResistance { get; }
|
||||
|
||||
public event Action<EquipableItem> EquipmentChanged;
|
||||
}
|
||||
|
||||
@@ -21,5 +21,5 @@ public interface IHealthComponent : IEntityComponent
|
||||
|
||||
public void SetMaximumHealth(int health);
|
||||
|
||||
public void RaiseMaximumHP(int raiseAmount);
|
||||
public void RaiseMaximumHP(int raiseAmount, bool restoreHP = false);
|
||||
}
|
||||
@@ -16,5 +16,7 @@ public interface IVTComponent : IEntityComponent
|
||||
|
||||
public void SetVT(int vt);
|
||||
|
||||
public void RaiseMaximumVT(int raiseAmount);
|
||||
public void RaiseMaximumVT(int raiseAmount, bool restoreVT = true);
|
||||
|
||||
public void SetMaximumVT(int vt);
|
||||
}
|
||||
|
||||
@@ -15,4 +15,5 @@ public interface IInventory
|
||||
public void Sort(EquipableItem currentWeapon, EquipableItem currentArmor, EquipableItem currentAccessory);
|
||||
|
||||
public event Action<string> BroadcastMessage;
|
||||
public event Action InventoryChanged;
|
||||
}
|
||||
|
||||
287
Zennysoft.Game.Ma/addons/input_helper/InputHelper.cs
Normal file
287
Zennysoft.Game.Ma/addons/input_helper/InputHelper.cs
Normal file
@@ -0,0 +1,287 @@
|
||||
using Godot;
|
||||
using Godot.Collections;
|
||||
|
||||
namespace NathanHoad
|
||||
{
|
||||
public static class InputHelper
|
||||
{
|
||||
public delegate void DeviceChangedEventHandler(string device, int deviceIndex);
|
||||
public delegate void KeyboardInputChangedEventHandler(string action, InputEvent input);
|
||||
public delegate void JoypadInputChangedEventHandler(string action, InputEvent input);
|
||||
public delegate void JoypadChangedEventHandler(int deviceIndex, bool isConnected);
|
||||
|
||||
public static DeviceChangedEventHandler? DeviceChanged;
|
||||
public static KeyboardInputChangedEventHandler? KeyboardInputChanged;
|
||||
public static JoypadInputChangedEventHandler? JoypadInputChanged;
|
||||
public static JoypadChangedEventHandler? JoypadChanged;
|
||||
|
||||
|
||||
public const string DEVICE_KEYBOARD = "keyboard";
|
||||
public const string DEVICE_XBOX_CONTROLLER = "xbox";
|
||||
public const string DEVICE_SWITCH_CONTROLLER = "switch";
|
||||
public const string DEVICE_PLAYSTATION_CONTROLLER = "playstation";
|
||||
public const string DEVICE_STEAMDECK_CONTROLLER = "steamdeck";
|
||||
public const string DEVICE_GENERIC = "generic";
|
||||
|
||||
public const string SUB_DEVICE_XBOX_ONE_CONTROLLER = "xbox_one";
|
||||
public const string SUB_DEVICE_XBOX_SERIES_CONTROLLER = "xbox_series";
|
||||
public const string SUB_DEVICE_PLAYSTATION3_CONTROLLER = "playstation3";
|
||||
public const string SUB_DEVICE_PLAYSTATION4_CONTROLLER = "playstation4";
|
||||
public const string SUB_DEVICE_PLAYSTATION5_CONTROLLER = "playstation5";
|
||||
public const string SUB_DEVICE_SWITCH_JOYCON_LEFT_CONTROLLER = "switch_left_joycon";
|
||||
public const string SUB_DEVICE_SWITCH_JOYCON_RIGHT_CONTROLLER = "switch_right_joycon";
|
||||
|
||||
|
||||
private static Node instance;
|
||||
public static Node Instance
|
||||
{
|
||||
get
|
||||
{
|
||||
if (instance == null)
|
||||
{
|
||||
instance = (Node)Engine.GetSingleton("InputHelper");
|
||||
instance.Connect("device_changed", Callable.From((string device, int deviceIndex) => DeviceChanged?.Invoke(device, deviceIndex)));
|
||||
instance.Connect("keyboard_input_changed", Callable.From((string action, InputEvent input) => KeyboardInputChanged?.Invoke(action, input)));
|
||||
instance.Connect("joypad_input_changed", Callable.From((string action, InputEvent input) => JoypadInputChanged?.Invoke(action, input)));
|
||||
instance.Connect("joypad_changed", Callable.From((int deviceIndex, bool isConnected) => JoypadChanged?.Invoke(deviceIndex, isConnected)));
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static string Device
|
||||
{
|
||||
get => (string)Instance.Get("device");
|
||||
}
|
||||
|
||||
|
||||
public static int DeviceIndex
|
||||
{
|
||||
get => (int)Instance.Get("device_index");
|
||||
}
|
||||
|
||||
|
||||
public static string LastKnownJoypadDevice
|
||||
{
|
||||
get => (string)Instance.Get("last_known_joypad_device");
|
||||
}
|
||||
|
||||
|
||||
public static string LastKnownJoypadIndex
|
||||
{
|
||||
get => (string)Instance.Get("last_known_joypad_index");
|
||||
}
|
||||
|
||||
|
||||
public static float Deadzone
|
||||
{
|
||||
get => (float)Instance.Get("deadzone");
|
||||
set => Instance.Set("deadzone", value);
|
||||
}
|
||||
|
||||
|
||||
public static int MouseMotionThreshold
|
||||
{
|
||||
get => (int)Instance.Get("mouse_motion_threshold");
|
||||
set => Instance.Set("mouse_motion_threshold", value);
|
||||
}
|
||||
|
||||
|
||||
public static string GetSimplifiedDeviceName(string rawName)
|
||||
{
|
||||
return (string)Instance.Call("get_simplified_device_name", rawName);
|
||||
}
|
||||
|
||||
|
||||
public static string GetDeviceFromEvent(InputEvent @event)
|
||||
{
|
||||
return (string)Instance.Call("get_device_from_event", @event);
|
||||
}
|
||||
|
||||
|
||||
public static int GetDeviceIndexFromEvent(InputEvent @event)
|
||||
{
|
||||
return (int)Instance.Call("get_device_index_from_event", @event);
|
||||
}
|
||||
|
||||
|
||||
public static bool HasJoypad()
|
||||
{
|
||||
return (bool)Instance.Call("has_joypad");
|
||||
}
|
||||
|
||||
|
||||
public static string GuessDeviceName()
|
||||
{
|
||||
return (string)Instance.Call("guess_device_name");
|
||||
}
|
||||
|
||||
|
||||
public static void ResetAllActions()
|
||||
{
|
||||
Instance.Call("reset_all_actions");
|
||||
}
|
||||
|
||||
|
||||
public static void SetKeyboardOrJoypadInputForAction(string action, InputEvent input, bool swapIfTaken = true)
|
||||
{
|
||||
Instance.Call("set_keyboard_or_joypad_input_for_action", action, input, swapIfTaken);
|
||||
}
|
||||
|
||||
|
||||
public static InputEvent GetKeyboardOrJoypadInputForAction(string action, InputEvent input, bool swapIfTaken = true)
|
||||
{
|
||||
return (InputEvent)Instance.Call("get_keyboard_or_joypad_input_for_action", action, input, swapIfTaken);
|
||||
}
|
||||
|
||||
|
||||
public static Array<InputEvent> GetKeyboardOrJoypadInputsForAction(string action)
|
||||
{
|
||||
return (Array<InputEvent>)Instance.Call("get_keyboard_or_joypad_inputs_for_action", action);
|
||||
}
|
||||
|
||||
|
||||
public static string GetLabelForInput(InputEvent input)
|
||||
{
|
||||
return (string)Instance.Call("get_label_for_input", input);
|
||||
}
|
||||
|
||||
|
||||
public static string SerializeInputsForAction(string action)
|
||||
{
|
||||
return (string)Instance.Call("serialize_inputs_for_action", action);
|
||||
}
|
||||
|
||||
|
||||
public static string SerializeInputsForActions(Array<string> actions = null)
|
||||
{
|
||||
if (actions == null)
|
||||
{
|
||||
actions = new Array<string>();
|
||||
}
|
||||
return (string)Instance.Call("serialize_inputs_for_actions", actions);
|
||||
}
|
||||
|
||||
|
||||
public static void DeserializeInputsForAction(string action, string serializedInputs)
|
||||
{
|
||||
Instance.Call("desserialize_inputs_for_action", action, serializedInputs);
|
||||
}
|
||||
|
||||
public static void DeserializeInputsForActions(string serializedInputs)
|
||||
{
|
||||
Instance.Call("deserialize_inputs_for_actions", serializedInputs);
|
||||
}
|
||||
|
||||
|
||||
#region Keyboard/Mouse
|
||||
|
||||
public static Array<InputEvent> GetKeyboardInputsForAction(string action)
|
||||
{
|
||||
return (Array<InputEvent>)Instance.Call("get_keyboard_inputs_for_action", action);
|
||||
}
|
||||
|
||||
|
||||
public static InputEvent GetKeyboardInputForAction(string action)
|
||||
{
|
||||
return (InputEvent)Instance.Call("get_keyboard_input_for_action", action);
|
||||
}
|
||||
|
||||
|
||||
public static void SetKeyboardInputForAction(string action, InputEvent input, bool swapIfTaken = true)
|
||||
{
|
||||
Instance.Call("set_keyboard_input_for_action", action, input, swapIfTaken);
|
||||
}
|
||||
|
||||
|
||||
public static void ReplaceKeyboardInputForAction(string action, InputEvent currentInput, InputEvent input, bool swapIfTaken = true)
|
||||
{
|
||||
Instance.Call("replace_keyboard_input_for_action", action, currentInput, input, swapIfTaken);
|
||||
}
|
||||
|
||||
|
||||
public static void ReplaceKeyboardInputAtIndex(string action, int index, InputEvent input, bool swapIfTaken = true)
|
||||
{
|
||||
Instance.Call("replace_keyboard_input_at_index", action, index, input, swapIfTaken);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Joypad
|
||||
|
||||
public static Array<InputEvent> GetJoypadInputsForAction(string action)
|
||||
{
|
||||
return (Array<InputEvent>)Instance.Call("get_joypad_inputs_for_action", action);
|
||||
}
|
||||
|
||||
|
||||
public static InputEvent GetJoypadInputForAction(string action)
|
||||
{
|
||||
return (InputEvent)Instance.Call("get_joypad_input_for_action", action);
|
||||
}
|
||||
|
||||
|
||||
public static void SetJoypadInputForAction(string action, InputEvent input, bool swapIfTaken = true)
|
||||
{
|
||||
Instance.Call("set_joypad_input_for_action", action, input, swapIfTaken);
|
||||
}
|
||||
|
||||
|
||||
public static void ReplaceJoypadInputForAction(string action, InputEvent currentInput, InputEvent input, bool swapIfTaken = true)
|
||||
{
|
||||
Instance.Call("replace_joypad_input_for_action", action, currentInput, input, swapIfTaken);
|
||||
}
|
||||
|
||||
|
||||
public static void ReplaceJoypadInputAtIndex(string action, int index, InputEvent input, bool swapIfTaken = true)
|
||||
{
|
||||
Instance.Call("replace_joypad_input_at_index", action, index, input, swapIfTaken);
|
||||
}
|
||||
|
||||
|
||||
public static void RumbleSmall(int targetDevice = 0)
|
||||
{
|
||||
Instance.Call("rumble_small", targetDevice);
|
||||
}
|
||||
|
||||
|
||||
public static void RumbleMedium(int targetDevice = 0)
|
||||
{
|
||||
Instance.Call("rumble_medium", targetDevice);
|
||||
}
|
||||
|
||||
|
||||
public static void RumbleLarge(int targetDevice = 0)
|
||||
{
|
||||
Instance.Call("rumble_large", targetDevice);
|
||||
}
|
||||
|
||||
|
||||
public static void StartRumbleSmall(int targetDevice = 0)
|
||||
{
|
||||
Instance.Call("start_rumble_small", targetDevice);
|
||||
}
|
||||
|
||||
|
||||
public static void StartRumbleMedium(int targetDevice = 0)
|
||||
{
|
||||
Instance.Call("start_rumble_medium", targetDevice);
|
||||
}
|
||||
|
||||
|
||||
public static void StartRumbleLarge(int targetDevice = 0)
|
||||
{
|
||||
Instance.Call("start_rumble_large", targetDevice);
|
||||
}
|
||||
|
||||
|
||||
public static void StopRumble(int targetDevice = 0)
|
||||
{
|
||||
Instance.Call("stop_rumble", targetDevice);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
1
Zennysoft.Game.Ma/addons/input_helper/InputHelper.cs.uid
Normal file
1
Zennysoft.Game.Ma/addons/input_helper/InputHelper.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://cfs4dgwrfvb11
|
||||
21
Zennysoft.Game.Ma/addons/input_helper/LICENSE
Normal file
21
Zennysoft.Game.Ma/addons/input_helper/LICENSE
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2022-present Nathan Hoad
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
230
Zennysoft.Game.Ma/addons/input_helper/assets/update.svg
Normal file
230
Zennysoft.Game.Ma/addons/input_helper/assets/update.svg
Normal file
@@ -0,0 +1,230 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
width="300"
|
||||
height="80"
|
||||
viewBox="0 0 79.374999 21.166667"
|
||||
version="1.1"
|
||||
id="svg291"
|
||||
inkscape:version="1.2 (dc2aedaf03, 2022-05-15)"
|
||||
sodipodi:docname="update.svg"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<sodipodi:namedview
|
||||
id="namedview293"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:document-units="px"
|
||||
showgrid="false"
|
||||
width="1920px"
|
||||
units="px"
|
||||
borderlayer="true"
|
||||
inkscape:showpageshadow="false"
|
||||
inkscape:zoom="4"
|
||||
inkscape:cx="121.625"
|
||||
inkscape:cy="43.25"
|
||||
inkscape:window-width="2560"
|
||||
inkscape:window-height="1377"
|
||||
inkscape:window-x="2552"
|
||||
inkscape:window-y="-8"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="layer1"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
showguides="true">
|
||||
<sodipodi:guide
|
||||
position="-15.575132,19.553027"
|
||||
orientation="0,-1"
|
||||
id="guide2089"
|
||||
inkscape:locked="false" />
|
||||
</sodipodi:namedview>
|
||||
<defs
|
||||
id="defs288" />
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1">
|
||||
<g
|
||||
id="g2335"
|
||||
transform="matrix(0.93072355,0,0,0.92874157,17.062816,18.409989)"
|
||||
style="stroke-width:0.85374062;stroke-dasharray:none;stroke:none">
|
||||
<path
|
||||
id="rect2095"
|
||||
style="fill:#349684;fill-opacity:1;stroke:#152f2c;stroke-width:0.56916041;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-dashoffset:0.3;stroke-opacity:1;paint-order:normal"
|
||||
d="m 24.364404,-16.012976 a 1.7811118,1.7811118 0 0 0 -1.568379,0.938961 1.7811118,1.7811118 0 0 0 -1.557528,-0.918291 1.7811118,1.7811118 0 0 0 -1.383895,0.660942 c -1.816891,-1.243302 -4.115395,-0.49791 -5.162476,1.678967 l -2.844787,5.914368 c -1.050638,2.1842718 -0.431729,4.957652 1.388029,6.2187419 1.819758,1.26108987 4.130958,0.5177068 5.181596,-1.666565 l 1.240234,-2.5786539 h 6.335531 l 1.240234,2.5786539 c 1.050638,2.1842718 3.361322,2.92765487 5.181079,1.666565 1.819758,-1.2610899 2.439184,-4.0344701 1.388546,-6.2187419 L 30.9578,-13.652397 c -1.050637,-2.184271 -3.361838,-2.927654 -5.181596,-1.666565 -1.97e-4,1.37e-4 -3.19e-4,3.8e-4 -5.16e-4,5.17e-4 a 1.7811118,1.7811118 0 0 0 -1.411284,-0.694531 z" />
|
||||
<rect
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.85374062;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-dashoffset:0.3;stroke-opacity:1;paint-order:markers stroke fill"
|
||||
id="rect2101"
|
||||
width="1.403165"
|
||||
height="4.2796535"
|
||||
x="17.394386"
|
||||
y="-13.427068"
|
||||
ry="0.75541198"
|
||||
rx="0.75380331" />
|
||||
<rect
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.85374062;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-dashoffset:0.3;stroke-opacity:1;paint-order:markers stroke fill"
|
||||
id="rect2103"
|
||||
width="1.403165"
|
||||
height="4.2796535"
|
||||
x="-11.988823"
|
||||
y="-20.235798"
|
||||
ry="0.75380331"
|
||||
rx="0.75541198"
|
||||
transform="rotate(90)" />
|
||||
<ellipse
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.85374062;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-dashoffset:0.3;stroke-opacity:1;paint-order:markers stroke fill"
|
||||
id="ellipse2105"
|
||||
cx="28.192503"
|
||||
cy="2.7587082"
|
||||
rx="0.82257289"
|
||||
ry="0.79261416"
|
||||
transform="rotate(-30)" />
|
||||
<ellipse
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.85374062;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-dashoffset:0.3;stroke-opacity:1;paint-order:markers stroke fill"
|
||||
id="ellipse2107"
|
||||
cx="28.216581"
|
||||
cy="4.7943339"
|
||||
rx="0.82257289"
|
||||
ry="0.79261416"
|
||||
transform="rotate(-30)" />
|
||||
<ellipse
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.85374062;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-dashoffset:0.3;stroke-opacity:1;paint-order:markers stroke fill"
|
||||
id="ellipse2109"
|
||||
cx="30.279696"
|
||||
cy="2.6987464"
|
||||
rx="0.82257289"
|
||||
ry="0.79261416"
|
||||
transform="rotate(-30)" />
|
||||
<ellipse
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.85374062;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-dashoffset:0.3;stroke-opacity:1;paint-order:markers stroke fill"
|
||||
id="ellipse2111"
|
||||
cx="30.320311"
|
||||
cy="4.767447"
|
||||
rx="0.82257289"
|
||||
ry="0.79261416"
|
||||
transform="rotate(-30)" />
|
||||
<rect
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.85374062;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-dashoffset:0.3;stroke-opacity:1;paint-order:markers stroke fill"
|
||||
id="rect2117"
|
||||
width="1.109892"
|
||||
height="2.1669323"
|
||||
x="22.090807"
|
||||
y="-10.531444"
|
||||
ry="0.52878839"
|
||||
rx="0.52766228" />
|
||||
</g>
|
||||
<path
|
||||
id="rect1625"
|
||||
style="fill:#50fa7b;fill-opacity:1;stroke:#0f451d;stroke-width:0.593381;stroke-dasharray:none;stroke-opacity:1;paint-order:normal"
|
||||
d="m 50.52517,5.3570989 c -0.643062,0 -1.160653,0.5900216 -1.160653,1.3229166 v 1.0764201 h -1.07642 c -0.732895,0 -1.322916,0.5175908 -1.322916,1.1606533 0,0.643061 0.590021,1.1611691 1.322916,1.1611691 h 1.07642 v 1.076421 c 0,0.732895 0.517591,1.322917 1.160653,1.322917 0.643062,0 1.160653,-0.590022 1.160653,-1.322917 v -1.076421 h 1.076937 c 0.732895,0 1.322916,-0.5181081 1.322916,-1.1611691 0,-0.6430625 -0.590021,-1.1606533 -1.322916,-1.1606533 H 51.685823 V 6.6800155 c 0,-0.732895 -0.517591,-1.3229166 -1.160653,-1.3229166 z" />
|
||||
<path
|
||||
id="path2678"
|
||||
style="fill:#50fa7b;fill-opacity:1;stroke:#0f451d;stroke-width:0.593381;stroke-dasharray:none;stroke-opacity:1;paint-order:normal"
|
||||
d="m 57.791691,5.357099 c -0.643062,0 -1.160653,0.5900216 -1.160653,1.3229166 v 1.0764201 h -1.07642 c -0.732895,0 -1.322916,0.5175908 -1.322916,1.1606522 0,0.643062 0.590021,1.1611701 1.322916,1.1611701 h 1.07642 v 1.076421 c 0,0.732895 0.517591,1.322917 1.160653,1.322917 0.643062,0 1.160653,-0.590022 1.160653,-1.322917 v -1.076421 h 1.076937 c 0.732895,0 1.322916,-0.5181081 1.322916,-1.1611701 0,-0.6430614 -0.590021,-1.1606522 -1.322916,-1.1606522 H 58.952344 V 6.6800156 c 0,-0.732895 -0.517591,-1.3229166 -1.160653,-1.3229166 z" />
|
||||
<rect
|
||||
style="fill:#000000;fill-opacity:1;stroke-width:0.72829;stroke-linecap:round;stroke-linejoin:round;stroke-dashoffset:0.3;paint-order:markers stroke fill"
|
||||
id="rect413"
|
||||
width="10.200269"
|
||||
height="8.7847834"
|
||||
x="-21.316095"
|
||||
y="3.0372066" />
|
||||
<rect
|
||||
style="fill:#000000;fill-opacity:1;stroke-width:0.622475;stroke-linecap:round;stroke-linejoin:round;stroke-dashoffset:0.3;paint-order:markers stroke fill"
|
||||
id="rect415"
|
||||
width="7.9928446"
|
||||
height="15.312933"
|
||||
x="-20.546837"
|
||||
y="12.977094"
|
||||
ry="4.375123"
|
||||
transform="matrix(0.82192626,0.56959391,-0.43346431,0.90117073,0,0)"
|
||||
rx="4.375123" />
|
||||
<rect
|
||||
style="fill:#000000;fill-opacity:1;stroke-width:0.622475;stroke-linecap:round;stroke-linejoin:round;stroke-dashoffset:0.3;paint-order:markers stroke fill"
|
||||
id="rect471"
|
||||
width="7.9928446"
|
||||
height="15.312933"
|
||||
x="9.1578636"
|
||||
y="-5.7980561"
|
||||
ry="4.375123"
|
||||
transform="matrix(-0.82192626,0.56959391,0.43346431,0.90117073,0,0)"
|
||||
rx="4.375123" />
|
||||
<rect
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1.32292;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-dashoffset:0.3;stroke-opacity:1;paint-order:markers stroke fill"
|
||||
id="rect1137"
|
||||
width="1.403165"
|
||||
height="4.2796535"
|
||||
x="-22.240166"
|
||||
y="3.9990206"
|
||||
ry="0.70158249"
|
||||
rx="0.70158249" />
|
||||
<rect
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1.32292;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-dashoffset:0.3;stroke-opacity:1;paint-order:markers stroke fill"
|
||||
id="rect1295"
|
||||
width="1.403165"
|
||||
height="4.2796535"
|
||||
x="5.4372649"
|
||||
y="19.398754"
|
||||
ry="0.70158249"
|
||||
rx="0.70158249"
|
||||
transform="rotate(90)" />
|
||||
<ellipse
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1.32292;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-dashoffset:0.3;stroke-opacity:1;paint-order:markers stroke fill"
|
||||
id="ellipse1297"
|
||||
cx="-13.849753"
|
||||
cy="-1.3102485"
|
||||
rx="0.82257289"
|
||||
ry="0.79261416"
|
||||
transform="rotate(-30)" />
|
||||
<ellipse
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1.32292;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-dashoffset:0.3;stroke-opacity:1;paint-order:markers stroke fill"
|
||||
id="ellipse1299"
|
||||
cx="-13.825675"
|
||||
cy="0.72537726"
|
||||
rx="0.82257289"
|
||||
ry="0.79261416"
|
||||
transform="rotate(-30)" />
|
||||
<ellipse
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1.32292;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-dashoffset:0.3;stroke-opacity:1;paint-order:markers stroke fill"
|
||||
id="ellipse1301"
|
||||
cx="-11.762562"
|
||||
cy="-1.3702103"
|
||||
rx="0.82257289"
|
||||
ry="0.79261416"
|
||||
transform="rotate(-30)" />
|
||||
<ellipse
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1.32292;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-dashoffset:0.3;stroke-opacity:1;paint-order:markers stroke fill"
|
||||
id="ellipse1303"
|
||||
cx="-11.721946"
|
||||
cy="0.69849032"
|
||||
rx="0.82257289"
|
||||
ry="0.79261416"
|
||||
transform="rotate(-30)" />
|
||||
<circle
|
||||
style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.32292;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-dashoffset:0.3;stroke-opacity:1;paint-order:markers stroke fill"
|
||||
id="path2085"
|
||||
cx="-17.863199"
|
||||
cy="3.3752983"
|
||||
r="1.7811118" />
|
||||
<circle
|
||||
style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.32292;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-dashoffset:0.3;stroke-opacity:1;paint-order:markers stroke fill"
|
||||
id="circle2087"
|
||||
cx="-14.737003"
|
||||
cy="3.3542202"
|
||||
r="1.7811118" />
|
||||
<rect
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1.32292;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-dashoffset:0.3;stroke-opacity:1;paint-order:markers stroke fill"
|
||||
id="rect2091"
|
||||
width="0.98221546"
|
||||
height="1.917659"
|
||||
x="-16.946886"
|
||||
y="7.1795278"
|
||||
ry="0.49110773"
|
||||
rx="0.49110773" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 11 KiB |
@@ -0,0 +1,37 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://ddixs2ish5bi6"
|
||||
path="res://.godot/imported/update.svg-3137f1f7d53c08c0ae65aabe138d898b.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://addons/input_helper/assets/update.svg"
|
||||
dest_files=["res://.godot/imported/update.svg-3137f1f7d53c08c0ae65aabe138d898b.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/hdr_compression=1
|
||||
compress/normal_map=0
|
||||
compress/channel_pack=0
|
||||
mipmaps/generate=false
|
||||
mipmaps/limit=-1
|
||||
roughness/mode=0
|
||||
roughness/src_normal=""
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/normal_map_invert_y=false
|
||||
process/hdr_as_srgb=false
|
||||
process/hdr_clamp_exposure=false
|
||||
process/size_limit=0
|
||||
detect_3d/compress_to=1
|
||||
svg/scale=1.0
|
||||
editor/scale_with_editor_scale=false
|
||||
editor/convert_colors_with_editor_theme=false
|
||||
@@ -0,0 +1,83 @@
|
||||
@tool
|
||||
|
||||
extends Control
|
||||
|
||||
|
||||
signal failed()
|
||||
signal updated(updated_to_version: String)
|
||||
|
||||
|
||||
const TEMP_FILE_NAME = "user://temp.zip"
|
||||
|
||||
|
||||
@onready var logo: TextureRect = %Logo
|
||||
@onready var label: Label = $VBox/Label
|
||||
@onready var http_request: HTTPRequest = $HTTPRequest
|
||||
@onready var download_button: Button = %DownloadButton
|
||||
|
||||
var next_version: String = "":
|
||||
set(next_next_version):
|
||||
next_version = next_next_version
|
||||
label.text = "Version %s is available for download!" % next_version
|
||||
get:
|
||||
return next_version
|
||||
|
||||
|
||||
func save_zip(bytes: PackedByteArray) -> void:
|
||||
var file: FileAccess = FileAccess.open(TEMP_FILE_NAME, FileAccess.WRITE)
|
||||
file.store_buffer(bytes)
|
||||
file.flush()
|
||||
|
||||
|
||||
### Signals
|
||||
|
||||
|
||||
func _on_download_button_pressed() -> void:
|
||||
# Safeguard the actual input helper repo from accidentally updating itself
|
||||
if FileAccess.file_exists("res://examples/device_tester.gd"):
|
||||
prints("You can't update the input helper from within itself.")
|
||||
failed.emit()
|
||||
return
|
||||
|
||||
http_request.request("https://github.com/nathanhoad/godot_input_helper/archive/refs/tags/v%s.zip" % next_version)
|
||||
download_button.disabled = true
|
||||
download_button.text = "Downloading..."
|
||||
|
||||
|
||||
func _on_http_request_request_completed(result: int, response_code: int, headers: PackedStringArray, body: PackedByteArray) -> void:
|
||||
if result != HTTPRequest.RESULT_SUCCESS:
|
||||
failed.emit()
|
||||
return
|
||||
|
||||
# Save the downloaded zip
|
||||
save_zip(body)
|
||||
|
||||
OS.move_to_trash(ProjectSettings.globalize_path("res://addons/input_helper"))
|
||||
|
||||
var zip_reader: ZIPReader = ZIPReader.new()
|
||||
zip_reader.open(TEMP_FILE_NAME)
|
||||
var files: PackedStringArray = zip_reader.get_files()
|
||||
|
||||
var base_path = files[1]
|
||||
# Remove archive folder
|
||||
files.remove_at(0)
|
||||
# Remove assets folder
|
||||
files.remove_at(0)
|
||||
|
||||
for path in files:
|
||||
var new_file_path: String = path.replace(base_path, "")
|
||||
if path.ends_with("/"):
|
||||
DirAccess.make_dir_recursive_absolute("res://addons/%s" % new_file_path)
|
||||
else:
|
||||
var file: FileAccess = FileAccess.open("res://addons/%s" % new_file_path, FileAccess.WRITE)
|
||||
file.store_buffer(zip_reader.read_file(path))
|
||||
|
||||
zip_reader.close()
|
||||
|
||||
DirAccess.remove_absolute(TEMP_FILE_NAME)
|
||||
|
||||
updated.emit(next_version)
|
||||
|
||||
|
||||
func _on_notes_button_pressed() -> void:
|
||||
OS.shell_open("https://github.com/nathanhoad/godot_input_helper/releases/tag/v%s" % next_version)
|
||||
@@ -0,0 +1 @@
|
||||
uid://dcff0mowkn6km
|
||||
@@ -0,0 +1,60 @@
|
||||
[gd_scene load_steps=3 format=3 uid="uid://b7mst0qu7vjk1"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://dcff0mowkn6km" path="res://addons/input_helper/components/download_update_panel.gd" id="1_4tm1k"]
|
||||
[ext_resource type="Texture2D" uid="uid://ddixs2ish5bi6" path="res://addons/input_helper/assets/update.svg" id="2_j7shv"]
|
||||
|
||||
[node name="DownloadUpdatePanel" type="Control"]
|
||||
layout_mode = 3
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
script = ExtResource("1_4tm1k")
|
||||
|
||||
[node name="HTTPRequest" type="HTTPRequest" parent="."]
|
||||
|
||||
[node name="VBox" type="VBoxContainer" parent="."]
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
offset_left = -1.0
|
||||
offset_top = 9.0
|
||||
offset_right = -1.0
|
||||
offset_bottom = 9.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
theme_override_constants/separation = 10
|
||||
|
||||
[node name="Logo" type="TextureRect" parent="VBox"]
|
||||
unique_name_in_owner = true
|
||||
clip_contents = true
|
||||
custom_minimum_size = Vector2(300, 80)
|
||||
layout_mode = 2
|
||||
texture = ExtResource("2_j7shv")
|
||||
stretch_mode = 5
|
||||
|
||||
[node name="Label" type="Label" parent="VBox"]
|
||||
layout_mode = 2
|
||||
text = "v1.2.3 is available for download."
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="Center" type="CenterContainer" parent="VBox"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="DownloadButton" type="Button" parent="VBox/Center"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
text = "Download and install update"
|
||||
|
||||
[node name="Center2" type="CenterContainer" parent="VBox"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="NotesButton" type="LinkButton" parent="VBox/Center2"]
|
||||
layout_mode = 2
|
||||
text = "Read release notes..."
|
||||
|
||||
[connection signal="request_completed" from="HTTPRequest" to="." method="_on_http_request_request_completed"]
|
||||
[connection signal="pressed" from="VBox/Center/DownloadButton" to="." method="_on_download_button_pressed"]
|
||||
[connection signal="pressed" from="VBox/Center2/NotesButton" to="." method="_on_notes_button_pressed"]
|
||||
601
Zennysoft.Game.Ma/addons/input_helper/input_helper.gd
Normal file
601
Zennysoft.Game.Ma/addons/input_helper/input_helper.gd
Normal file
@@ -0,0 +1,601 @@
|
||||
extends Node
|
||||
|
||||
|
||||
signal device_changed(device: String, device_index: int)
|
||||
signal keyboard_input_changed(action: String, input: InputEvent)
|
||||
signal joypad_input_changed(action: String, input: InputEvent)
|
||||
signal joypad_changed(device_index: int, is_connected: bool)
|
||||
|
||||
|
||||
const DEVICE_KEYBOARD = "keyboard"
|
||||
const DEVICE_XBOX_CONTROLLER = "xbox"
|
||||
const DEVICE_SWITCH_CONTROLLER = "switch"
|
||||
const DEVICE_PLAYSTATION_CONTROLLER = "playstation"
|
||||
const DEVICE_STEAMDECK_CONTROLLER = "steamdeck"
|
||||
const DEVICE_GENERIC = "generic"
|
||||
|
||||
const SUB_DEVICE_XBOX_ONE_CONTROLLER = "xbox_one"
|
||||
const SUB_DEVICE_XBOX_SERIES_CONTROLLER = "xbox_series"
|
||||
|
||||
const SUB_DEVICE_PLAYSTATION3_CONTROLLER = "playstation3"
|
||||
const SUB_DEVICE_PLAYSTATION4_CONTROLLER = "playstation4"
|
||||
const SUB_DEVICE_PLAYSTATION5_CONTROLLER = "playstation5"
|
||||
|
||||
const SUB_DEVICE_SWITCH_JOYCON_LEFT_CONTROLLER = "switch_left_joycon"
|
||||
const SUB_DEVICE_SWITCH_JOYCON_RIGHT_CONTROLLER = "switch_right_joycon"
|
||||
|
||||
const XBOX_BUTTON_LABELS = ["A", "B", "X", "Y", "Back", "Guide", "Start", "Left Stick", "Right Stick", "LB", "RB", "Up", "Down", "Left", "Right", "Share", "Paddle 1", "Paddle 2", "Paddle 3", "Paddle 4"]
|
||||
const XBOX_ONE_BUTTON_LABELS = ["A", "B", "X", "Y", "View", "Guide", "Menu", "Left Stick", "Right Stick", "LB", "RB", "Up", "Down", "Left", "Right", "Share", "Paddle 1", "Paddle 2", "Paddle 3", "Paddle 4"]
|
||||
const XBOX_SERIES_BUTTON_LABELS = ["A", "B", "X", "Y", "View", "Guide", "Menu", "Left Stick", "Right Stick", "LB", "RB", "Up", "Down", "Left", "Right", "Share", "Paddle 1", "Paddle 2", "Paddle 3", "Paddle 4"]
|
||||
const STEAMDECK_BUTTON_LABELS = ["A", "B", "X", "Y", "View", "?", "Options", "Left Stick", "Right Stick", "L1", "R1", "Up", "Down", "Left", "Right", "", "", "", "", ""]
|
||||
# Note: share and home buttons are not recognized
|
||||
const SWITCH_BUTTON_LABELS = ["B", "A", "Y", "X", "Minus", "", "Plus", "Left Stick", "Right Stick", "LS", "RS", "Up", "Down", "Left", "Right", "Capture"]
|
||||
# Mapping for left and right joypad connected together (extended gamepad)
|
||||
# Left Stick is Axis 0 and 1
|
||||
# Right Stick is Axis 2 and 3
|
||||
# ZL and ZR are Axis 4 and 5
|
||||
const SWITCH_EXTENDED_GAMEPAD_BUTTON_LABELS = ["B", "A", "Y", "X", "Minus", "", "Plus", "Left Stick", "Right Stick", "L", "R", "Up", "Down", "Left", "Right", "Capture"]
|
||||
const PLAYSTATION_3_4_BUTTON_LABELS = ["Cross", "Circle", "Square", "Triangle", "Share", "PS", "Options", "L3", "R3", "L1", "R1", "Up", "Down", "Left", "Right", "Microphone", "", "", "", "", "Touchpad"]
|
||||
# Note: Microphone does not work on PC / touchpad is not recognized
|
||||
const PLAYSTATION_5_BUTTON_LABELS = ["Cross", "Circle", "Square", "Triangle", "Create", "PS", "Options", "L3", "R3", "L1", "R1", "Up", "Down", "Left", "Right", "Microphone", "", "", "", "", "Touchpad"]
|
||||
|
||||
const SERIAL_VERSION = 1
|
||||
|
||||
## The deadzone to ignore for joypad motion
|
||||
var deadzone: float = 0.5
|
||||
## The mouse distance to ignore before movement is assumed
|
||||
var mouse_motion_threshold: int = 100
|
||||
## The last known joypad device name (or "" if no joypad detected)
|
||||
var last_known_joypad_device: String = get_simplified_device_name(Input.get_joy_name(0))
|
||||
## The last known joypad index
|
||||
var last_known_joypad_index: int = 0 if Input.get_connected_joypads().size() > 0 else -1
|
||||
|
||||
## Used internally
|
||||
var device_last_changed_at: int = 0
|
||||
var _last_known_granular_joypad_device: String = get_simplified_device_name(Input.get_joy_name(0), true)
|
||||
|
||||
@onready var device: String = guess_device_name()
|
||||
@onready var device_index: int = 0 if has_joypad() else -1
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
process_mode = Node.PROCESS_MODE_ALWAYS
|
||||
|
||||
if not Engine.has_singleton("InputHelper"):
|
||||
Engine.register_singleton("InputHelper", self)
|
||||
|
||||
Input.joy_connection_changed.connect(func(device_index, is_connected): joypad_changed.emit(device_index, is_connected))
|
||||
|
||||
|
||||
func _input(event: InputEvent) -> void:
|
||||
var next_device: String = device
|
||||
var next_device_index: int = device_index
|
||||
|
||||
# Did we just press a key on the keyboard or move the mouse?
|
||||
if event is InputEventKey \
|
||||
or event is InputEventMouseButton \
|
||||
or (event is InputEventMouseMotion and (event as InputEventMouseMotion).relative.length_squared() > mouse_motion_threshold):
|
||||
next_device = DEVICE_KEYBOARD
|
||||
next_device_index = -1
|
||||
|
||||
# Did we just use a joypad?
|
||||
elif event is InputEventJoypadButton \
|
||||
or (event is InputEventJoypadMotion and abs(event.axis_value) > deadzone):
|
||||
next_device = get_simplified_device_name(get_joy_name(event.device))
|
||||
last_known_joypad_device = next_device
|
||||
next_device_index = event.device
|
||||
last_known_joypad_index = next_device_index
|
||||
|
||||
_last_known_granular_joypad_device = get_simplified_device_name(get_joy_name(event.device), true)
|
||||
|
||||
# Debounce changes for 1 second because some joypads register twice in Windows for some reason
|
||||
var not_changed_in_last_second = Engine.get_frames_drawn() - device_last_changed_at > Engine.get_frames_per_second()
|
||||
if (next_device != device or next_device_index != device_index) and not_changed_in_last_second:
|
||||
device_last_changed_at = Engine.get_frames_drawn()
|
||||
|
||||
device = next_device
|
||||
device_index = next_device_index
|
||||
device_changed.emit(device, device_index)
|
||||
|
||||
|
||||
## Get the name of a joypad
|
||||
func get_joy_name(at_device_index: int) -> String:
|
||||
var joy_name: String = Input.get_joy_name(at_device_index)
|
||||
if joy_name == "" and Input.get_joy_info(at_device_index).size() > 0 and "xinput" in Input.get_joy_info(at_device_index).keys()[0]:
|
||||
joy_name = "XInput"
|
||||
return joy_name
|
||||
|
||||
|
||||
## Get the device name for an event
|
||||
func get_device_from_event(event: InputEvent) -> String:
|
||||
if event is InputEventKey or event is InputEventMouseButton or event is InputEventMouseMotion:
|
||||
return DEVICE_KEYBOARD
|
||||
elif event is InputEventJoypadButton or event is InputEventJoypadMotion:
|
||||
return get_simplified_device_name(get_joy_name(event.device))
|
||||
else:
|
||||
return DEVICE_GENERIC
|
||||
|
||||
|
||||
## Get the device name for an event
|
||||
func get_device_index_from_event(event: InputEvent) -> int:
|
||||
if event is InputEventJoypadButton or event is InputEventJoypadMotion:
|
||||
return event.device
|
||||
else:
|
||||
return -1
|
||||
|
||||
|
||||
## Convert a Godot device identifier to a simplified string
|
||||
func get_simplified_device_name(raw_name: String, force_granular_identifier: bool = false) -> String:
|
||||
var use_granular_identifier: bool = force_granular_identifier or InputHelperSettings.get_setting(InputHelperSettings.USE_GRANULAR_DEVICE_IDENTIFIERS, false)
|
||||
|
||||
var keywords: Dictionary = {
|
||||
SUB_DEVICE_XBOX_ONE_CONTROLLER: ["Xbox One Controller"],
|
||||
SUB_DEVICE_XBOX_SERIES_CONTROLLER: ["Xbox Series Controller", "Xbox Wireless Controller"],
|
||||
DEVICE_XBOX_CONTROLLER: ["XInput", "XBox"],
|
||||
SUB_DEVICE_PLAYSTATION3_CONTROLLER: ["PS3"],
|
||||
SUB_DEVICE_PLAYSTATION4_CONTROLLER:["Nacon Revolution Unlimited Pro Controller", "PS4", "DUALSHOCK 4"],
|
||||
SUB_DEVICE_PLAYSTATION5_CONTROLLER:["Sony DualSense", "PS5", "DualSense Wireless Controller"],
|
||||
DEVICE_STEAMDECK_CONTROLLER: ["Steam"],
|
||||
DEVICE_SWITCH_CONTROLLER: ["Switch", "Joy-Con (L/R)", "PowerA Core Controller"],
|
||||
SUB_DEVICE_SWITCH_JOYCON_LEFT_CONTROLLER: ["Joy-Con (L)"],
|
||||
SUB_DEVICE_SWITCH_JOYCON_RIGHT_CONTROLLER: ["joy-Con (R)"],
|
||||
} if use_granular_identifier else {
|
||||
DEVICE_XBOX_CONTROLLER: ["XBox", "XInput"],
|
||||
DEVICE_PLAYSTATION_CONTROLLER: ["Sony", "PS3", "PS5", "PS4", "DUALSHOCK 4", "DualSense", "Nacon Revolution Unlimited Pro Controller"],
|
||||
DEVICE_STEAMDECK_CONTROLLER: ["Steam"],
|
||||
DEVICE_SWITCH_CONTROLLER: ["Switch", "Joy-Con", "PowerA Core Controller"],
|
||||
}
|
||||
|
||||
for device_key in keywords:
|
||||
for keyword in keywords[device_key]:
|
||||
if keyword.to_lower() in raw_name.to_lower():
|
||||
return device_key
|
||||
|
||||
return DEVICE_GENERIC
|
||||
|
||||
|
||||
## Check if there is a connected joypad
|
||||
func has_joypad() -> bool:
|
||||
return Input.get_connected_joypads().size() > 0
|
||||
|
||||
|
||||
## Guess the initial input device
|
||||
func guess_device_name() -> String:
|
||||
if has_joypad():
|
||||
return get_simplified_device_name(get_joy_name(0))
|
||||
else:
|
||||
return DEVICE_KEYBOARD
|
||||
|
||||
|
||||
#region Mapping
|
||||
|
||||
|
||||
func reset_all_actions() -> void:
|
||||
InputMap.load_from_project_settings()
|
||||
for action in InputMap.get_actions():
|
||||
var input: InputEvent = get_joypad_input_for_action(action)
|
||||
if input != null:
|
||||
joypad_input_changed.emit(action, input)
|
||||
|
||||
input = get_keyboard_input_for_action(action)
|
||||
if input != null:
|
||||
keyboard_input_changed.emit(action, input)
|
||||
|
||||
|
||||
## Set the key or button for an action
|
||||
func set_keyboard_or_joypad_input_for_action(action: String, event: InputEvent, swap_if_taken: bool = true) -> void:
|
||||
if event is InputEventKey or event is InputEventMouse:
|
||||
set_keyboard_input_for_action(action, event, swap_if_taken)
|
||||
elif event is InputEventJoypadButton:
|
||||
set_joypad_input_for_action(action, event, swap_if_taken)
|
||||
|
||||
|
||||
## Get the key or button for a given action depending on the current device
|
||||
func get_keyboard_or_joypad_input_for_action(action: String) -> InputEvent:
|
||||
if device == DEVICE_KEYBOARD:
|
||||
return get_keyboard_input_for_action(action)
|
||||
else:
|
||||
return get_joypad_input_for_action(action)
|
||||
|
||||
|
||||
## Get the key or button for a given action depending on the current device
|
||||
func get_keyboard_or_joypad_inputs_for_action(action: String) -> Array[InputEvent]:
|
||||
if device == DEVICE_KEYBOARD:
|
||||
return get_keyboard_inputs_for_action(action)
|
||||
else:
|
||||
return get_joypad_inputs_for_action(action)
|
||||
|
||||
|
||||
## Get a text label for a given input
|
||||
func get_label_for_input(input: InputEvent) -> String:
|
||||
if input == null: return ""
|
||||
|
||||
if input is InputEventKey:
|
||||
if input.physical_keycode > 0 :
|
||||
var keycode: Key = DisplayServer.keyboard_get_keycode_from_physical(input.physical_keycode) if DisplayServer.keyboard_get_current_layout() > -1 else input.physical_keycode
|
||||
return OS.get_keycode_string(keycode)
|
||||
elif input.keycode > 0:
|
||||
return OS.get_keycode_string(input.keycode)
|
||||
else:
|
||||
return input.as_text()
|
||||
|
||||
elif input is InputEventMouseButton:
|
||||
match input.button_index:
|
||||
MOUSE_BUTTON_LEFT:
|
||||
return "Mouse Left Button"
|
||||
MOUSE_BUTTON_MIDDLE:
|
||||
return "Mouse Middle Button"
|
||||
MOUSE_BUTTON_RIGHT:
|
||||
return "Mouse Right Button"
|
||||
return "Mouse Button %d" % input.button_index
|
||||
|
||||
elif input is InputEventJoypadButton:
|
||||
var labels = []
|
||||
match _last_known_granular_joypad_device:
|
||||
DEVICE_XBOX_CONTROLLER, DEVICE_GENERIC:
|
||||
labels = XBOX_BUTTON_LABELS
|
||||
SUB_DEVICE_XBOX_ONE_CONTROLLER:
|
||||
labels = XBOX_ONE_BUTTON_LABELS
|
||||
SUB_DEVICE_XBOX_SERIES_CONTROLLER:
|
||||
labels = XBOX_SERIES_BUTTON_LABELS
|
||||
SUB_DEVICE_SWITCH_JOYCON_LEFT_CONTROLLER, SUB_DEVICE_SWITCH_JOYCON_RIGHT_CONTROLLER:
|
||||
labels = SWITCH_BUTTON_LABELS
|
||||
DEVICE_SWITCH_CONTROLLER:
|
||||
labels = SWITCH_EXTENDED_GAMEPAD_BUTTON_LABELS
|
||||
SUB_DEVICE_PLAYSTATION3_CONTROLLER, SUB_DEVICE_PLAYSTATION4_CONTROLLER:
|
||||
labels = PLAYSTATION_3_4_BUTTON_LABELS
|
||||
DEVICE_PLAYSTATION_CONTROLLER, SUB_DEVICE_PLAYSTATION5_CONTROLLER:
|
||||
labels = PLAYSTATION_5_BUTTON_LABELS
|
||||
DEVICE_STEAMDECK_CONTROLLER:
|
||||
labels = STEAMDECK_BUTTON_LABELS
|
||||
if input.button_index < labels.size():
|
||||
return "%s Button" % labels[input.button_index]
|
||||
else:
|
||||
return "Button %d" % input.button_index
|
||||
|
||||
elif input is InputEventJoypadMotion:
|
||||
var motion: InputEventJoypadMotion = input as InputEventJoypadMotion
|
||||
match motion.axis:
|
||||
JOY_AXIS_LEFT_X:
|
||||
return "Left Stick %s" % ("Left" if motion.axis_value < 0 else "Right")
|
||||
JOY_AXIS_LEFT_Y:
|
||||
return "Left Stick %s" % ("Up" if motion.axis_value < 0 else "Down")
|
||||
JOY_AXIS_RIGHT_X:
|
||||
return "Right Stick %s" % ("Left" if motion.axis_value < 0 else "Right")
|
||||
JOY_AXIS_RIGHT_Y:
|
||||
return "Right Stick %s" % ("Up" if motion.axis_value < 0 else "Down")
|
||||
JOY_AXIS_TRIGGER_LEFT:
|
||||
return "Left Trigger"
|
||||
JOY_AXIS_TRIGGER_RIGHT:
|
||||
return "Right Trigger"
|
||||
|
||||
return input.as_text()
|
||||
|
||||
|
||||
## Serialize a single action's inputs.
|
||||
func serialize_inputs_for_action(action: StringName) -> String:
|
||||
var action_inputs: PackedStringArray = []
|
||||
var inputs: Array[InputEvent] = InputMap.action_get_events(action)
|
||||
for input in inputs:
|
||||
if input is InputEventKey:
|
||||
var s: String = get_label_for_input(input)
|
||||
var modifiers: Array[String] = []
|
||||
if input.alt_pressed:
|
||||
modifiers.append("alt")
|
||||
if input.shift_pressed:
|
||||
modifiers.append("shift")
|
||||
if input.ctrl_pressed:
|
||||
modifiers.append("ctrl")
|
||||
if input.meta_pressed:
|
||||
modifiers.append("meta")
|
||||
if not modifiers.is_empty():
|
||||
s += "|" + ",".join(modifiers)
|
||||
action_inputs.append("key:%s" % s)
|
||||
elif input is InputEventMouseButton:
|
||||
action_inputs.append("mouse:%d" % input.button_index)
|
||||
elif input is InputEventJoypadButton:
|
||||
action_inputs.append("joypad:%d" % input.button_index)
|
||||
elif input is InputEventJoypadMotion:
|
||||
action_inputs.append("joypad:%d|%f" % [input.axis, input.axis_value])
|
||||
|
||||
return ";".join(action_inputs)
|
||||
|
||||
|
||||
## Serialize a list of action inputs to string. If actions is empty then it will serialize
|
||||
## all actions.
|
||||
func serialize_inputs_for_actions(actions: PackedStringArray = []) -> String:
|
||||
if actions == null or actions.is_empty():
|
||||
actions = InputMap.get_actions()
|
||||
|
||||
var map: Dictionary = {}
|
||||
for action in actions:
|
||||
map[action] = serialize_inputs_for_action(action)
|
||||
|
||||
return JSON.stringify({
|
||||
version = SERIAL_VERSION,
|
||||
map = map
|
||||
})
|
||||
|
||||
|
||||
## Deserialize a single action's inputs.
|
||||
func deserialize_inputs_for_action(action: String, string: String) -> void:
|
||||
InputMap.action_erase_events(action)
|
||||
var action_inputs: PackedStringArray = string.split(";")
|
||||
for action_input in action_inputs:
|
||||
var bits: PackedStringArray = action_input.split(":")
|
||||
|
||||
# Ignore any empty actions
|
||||
if bits.size() < 2: continue
|
||||
|
||||
var input_type: String = bits[0]
|
||||
var input_details: String = bits[1]
|
||||
|
||||
match input_type:
|
||||
"key":
|
||||
var keyboard_input = InputEventKey.new()
|
||||
if "|" in input_details:
|
||||
var detail_bits = input_details.split("|")
|
||||
keyboard_input.keycode = OS.find_keycode_from_string(detail_bits[0])
|
||||
detail_bits = detail_bits[1].split(",")
|
||||
if detail_bits.has("alt"):
|
||||
keyboard_input.alt_pressed = true
|
||||
if detail_bits.has("shift"):
|
||||
keyboard_input.shift_pressed = true
|
||||
if detail_bits.has("ctrl"):
|
||||
keyboard_input.ctrl_pressed = true
|
||||
if detail_bits.has("meta"):
|
||||
keyboard_input.meta_pressed = true
|
||||
else:
|
||||
keyboard_input.keycode = OS.find_keycode_from_string(input_details)
|
||||
InputMap.action_add_event(action, keyboard_input)
|
||||
keyboard_input_changed.emit(action, keyboard_input)
|
||||
|
||||
"mouse":
|
||||
var mouse_input = InputEventMouseButton.new()
|
||||
mouse_input.button_index = int(input_details)
|
||||
InputMap.action_add_event(action, mouse_input)
|
||||
keyboard_input_changed.emit(action, mouse_input)
|
||||
|
||||
"joypad":
|
||||
if "|" in str(input_details):
|
||||
var joypad_motion_input = InputEventJoypadMotion.new()
|
||||
var joypad_bits = input_details.split("|")
|
||||
joypad_motion_input.axis = int(joypad_bits[0])
|
||||
joypad_motion_input.axis_value = float(joypad_bits[1])
|
||||
InputMap.action_add_event(action, joypad_motion_input)
|
||||
joypad_input_changed.emit(action, joypad_motion_input)
|
||||
else:
|
||||
var joypad_input = InputEventJoypadButton.new()
|
||||
joypad_input.button_index = int(input_details)
|
||||
InputMap.action_add_event(action, joypad_input)
|
||||
joypad_input_changed.emit(action, joypad_input)
|
||||
|
||||
|
||||
## Deserialise a list of actions' inputs.
|
||||
func deserialize_inputs_for_actions(string: String) -> void:
|
||||
var data: Dictionary = JSON.parse_string(string)
|
||||
|
||||
# Use legacy deserialization
|
||||
if not data.has("version"):
|
||||
_deprecated_deserialize_inputs_for_actions(string)
|
||||
return
|
||||
|
||||
# Version 1
|
||||
for action in data.map.keys():
|
||||
deserialize_inputs_for_action(action, data.map[action])
|
||||
|
||||
|
||||
# Load inputs from a serialized string. [deprecated]
|
||||
func _deprecated_deserialize_inputs_for_actions(string: String) -> void:
|
||||
var map: Dictionary = JSON.parse_string(string)
|
||||
for action in map.keys():
|
||||
InputMap.action_erase_events(action)
|
||||
|
||||
for key in map[action]["keyboard"]:
|
||||
var keyboard_input = InputEventKey.new()
|
||||
if "|" in key:
|
||||
var bits = key.split("|")
|
||||
keyboard_input.keycode = OS.find_keycode_from_string(bits[0])
|
||||
bits = bits[1].split(",")
|
||||
if bits.has("alt"):
|
||||
keyboard_input.alt_pressed = true
|
||||
if bits.has("shift"):
|
||||
keyboard_input.shift_pressed = true
|
||||
if bits.has("ctrl"):
|
||||
keyboard_input.ctrl_pressed = true
|
||||
if bits.has("meta"):
|
||||
keyboard_input.meta_pressed = true
|
||||
else:
|
||||
keyboard_input.keycode = OS.find_keycode_from_string(key)
|
||||
InputMap.action_add_event(action, keyboard_input)
|
||||
|
||||
for button_index in map[action]["mouse"]:
|
||||
var mouse_input = InputEventMouseButton.new()
|
||||
mouse_input.button_index = int(button_index)
|
||||
InputMap.action_add_event(action, mouse_input)
|
||||
|
||||
for button_index_or_motion in map[action]["joypad"]:
|
||||
if "|" in str(button_index_or_motion):
|
||||
var joypad_motion_input = InputEventJoypadMotion.new()
|
||||
var bits = button_index_or_motion.split("|")
|
||||
joypad_motion_input.axis = int(bits[0])
|
||||
joypad_motion_input.axis_value = float(bits[1])
|
||||
InputMap.action_add_event(action, joypad_motion_input)
|
||||
else:
|
||||
var joypad_input = InputEventJoypadButton.new()
|
||||
joypad_input.button_index = int(button_index_or_motion)
|
||||
InputMap.action_add_event(action, joypad_input)
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
#region Keyboard/mouse input
|
||||
|
||||
|
||||
## Get all of the keys/mouse buttons used for an action.
|
||||
func get_keyboard_inputs_for_action(action: String) -> Array[InputEvent]:
|
||||
return InputMap.action_get_events(action).filter(func(event):
|
||||
return event is InputEventKey or event is InputEventMouseButton
|
||||
)
|
||||
|
||||
|
||||
## Get the first key for an action
|
||||
func get_keyboard_input_for_action(action: String) -> InputEvent:
|
||||
var inputs: Array[InputEvent] = get_keyboard_inputs_for_action(action)
|
||||
return null if inputs.is_empty() else inputs[0]
|
||||
|
||||
|
||||
## Set the key used for an action
|
||||
func set_keyboard_input_for_action(action: String, input: InputEvent, swap_if_taken: bool = true) -> Error:
|
||||
return _update_keyboard_input_for_action(action, input, swap_if_taken, null)
|
||||
|
||||
|
||||
## Replace a specific key with another key
|
||||
func replace_keyboard_input_for_action(action: String, current_input: InputEvent, input: InputEvent, swap_if_taken: bool = true) -> Error:
|
||||
return _update_keyboard_input_for_action(action, input, swap_if_taken, current_input)
|
||||
|
||||
|
||||
## Replace a specific key, given its index
|
||||
func replace_keyboard_input_at_index(action: String, index: int, input: InputEvent, swap_if_taken: bool = true) -> Error:
|
||||
var inputs: Array[InputEvent] = get_keyboard_inputs_for_action(action)
|
||||
var replacing_input = InputEventKey.new() if (inputs.is_empty() or inputs.size() <= index) else inputs[index]
|
||||
return _update_keyboard_input_for_action(action, input, swap_if_taken, replacing_input)
|
||||
|
||||
|
||||
func _update_keyboard_input_for_action(action: String, input: InputEvent, swap_if_taken: bool, replacing_input: InputEvent = null) -> Error:
|
||||
if not (input is InputEventKey or input is InputEventMouseButton): return ERR_INVALID_DATA
|
||||
|
||||
var is_valid_keyboard_event = func(event):
|
||||
return event is InputEventKey or event is InputEventMouseButton
|
||||
|
||||
return _update_input_for_action(action, input, swap_if_taken, replacing_input, is_valid_keyboard_event, keyboard_input_changed)
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
#region Joypad input
|
||||
|
||||
|
||||
## Get all buttons used for an action
|
||||
func get_joypad_inputs_for_action(action: String) -> Array[InputEvent]:
|
||||
return InputMap.action_get_events(action).filter(func(event):
|
||||
return event is InputEventJoypadButton or event is InputEventJoypadMotion
|
||||
)
|
||||
|
||||
|
||||
## Get the first button for an action
|
||||
func get_joypad_input_for_action(action: String) -> InputEvent:
|
||||
var buttons: Array[InputEvent] = get_joypad_inputs_for_action(action)
|
||||
return null if buttons.is_empty() else buttons[0]
|
||||
|
||||
|
||||
## Set the button for an action
|
||||
func set_joypad_input_for_action(action: String, input: InputEvent, swap_if_taken: bool = true) -> Error:
|
||||
return _update_joypad_input_for_action(action, input, swap_if_taken, null)
|
||||
|
||||
|
||||
## Replace a specific button for an action
|
||||
func replace_joypad_input_for_action(action: String, current_input: InputEvent, input: InputEventJoypadButton, swap_if_taken: bool = true) -> Error:
|
||||
return _update_joypad_input_for_action(action, input, swap_if_taken, current_input)
|
||||
|
||||
|
||||
## Replace a button, given its index
|
||||
func replace_joypad_input_at_index(action: String, index: int, input: InputEvent, swap_if_taken: bool = true) -> Error:
|
||||
var inputs: Array[InputEvent] = get_joypad_inputs_for_action(action)
|
||||
var replacing_input
|
||||
if inputs.is_empty() or inputs.size() <= index:
|
||||
replacing_input = InputEventJoypadButton.new()
|
||||
replacing_input.button_index = JOY_BUTTON_INVALID
|
||||
else:
|
||||
replacing_input = inputs[index]
|
||||
return _update_joypad_input_for_action(action, input, swap_if_taken, replacing_input)
|
||||
|
||||
|
||||
## Set the action used for a button
|
||||
func _update_joypad_input_for_action(action: String, input: InputEvent, swap_if_taken: bool = true, replacing_input: InputEvent = null) -> Error:
|
||||
var is_valid_keyboard_event = func(event):
|
||||
return event is InputEventJoypadButton or event is InputEventJoypadMotion
|
||||
|
||||
return _update_input_for_action(action, input, swap_if_taken, replacing_input, is_valid_keyboard_event, joypad_input_changed)
|
||||
|
||||
|
||||
func _update_input_for_action(action: String, input: InputEvent, swap_if_taken: bool, replacing_input: InputEvent, check_is_valid: Callable, did_change_signal: Signal) -> Error:
|
||||
# Find any action that is already mapped to this input
|
||||
var clashing_action = ""
|
||||
var clashing_event
|
||||
if swap_if_taken:
|
||||
for other_action in InputMap.get_actions():
|
||||
if other_action == action: continue
|
||||
|
||||
for event in InputMap.action_get_events(other_action):
|
||||
if event.is_match(input):
|
||||
clashing_action = other_action
|
||||
clashing_event = event
|
||||
|
||||
# Find the key based event for the target action
|
||||
var action_events: Array[InputEvent] = InputMap.action_get_events(action)
|
||||
var is_replacing: bool = false
|
||||
for i in range(0, action_events.size()):
|
||||
var event: InputEvent = action_events[i]
|
||||
if check_is_valid.call(event):
|
||||
if replacing_input != null and not event.is_match(replacing_input):
|
||||
continue
|
||||
|
||||
# Remap the other event if there is a clashing one
|
||||
if clashing_action:
|
||||
_update_input_for_action(clashing_action, event, false, clashing_event, check_is_valid, did_change_signal)
|
||||
|
||||
# Replace the event
|
||||
action_events[i] = input
|
||||
is_replacing = true
|
||||
break
|
||||
|
||||
# If we were trying to replace something but didn't find it then just add it to the end
|
||||
if not is_replacing:
|
||||
action_events.append(input)
|
||||
|
||||
# Apply the changes
|
||||
InputMap.action_erase_events(action)
|
||||
for event in action_events:
|
||||
if event != null:
|
||||
InputMap.action_add_event(action, event)
|
||||
|
||||
did_change_signal.emit(action, input)
|
||||
|
||||
return OK
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
#region Rumbling
|
||||
|
||||
|
||||
func rumble_small(target_device: int = 0) -> void:
|
||||
Input.start_joy_vibration(target_device, 0.4, 0, 0.1)
|
||||
|
||||
|
||||
func rumble_medium(target_device: int = 0) -> void:
|
||||
Input.start_joy_vibration(target_device, 0, 0.7, 0.1)
|
||||
|
||||
|
||||
func rumble_large(target_device: int = 0) -> void:
|
||||
Input.start_joy_vibration(target_device, 0, 1, 0.1)
|
||||
|
||||
|
||||
func start_rumble_small(target_device: int = 0) -> void:
|
||||
Input.start_joy_vibration(target_device, 0.4, 0, 0)
|
||||
|
||||
|
||||
func start_rumble_medium(target_device: int = 0) -> void:
|
||||
Input.start_joy_vibration(target_device, 0, 0.7, 0)
|
||||
|
||||
|
||||
func start_rumble_large(target_device: int = 0) -> void:
|
||||
Input.start_joy_vibration(target_device, 0, 1, 0)
|
||||
|
||||
|
||||
func stop_rumble(target_device: int = 0) -> void:
|
||||
Input.stop_joy_vibration(target_device)
|
||||
|
||||
|
||||
#endregion
|
||||
@@ -0,0 +1 @@
|
||||
uid://cholww48njaeh
|
||||
7
Zennysoft.Game.Ma/addons/input_helper/plugin.cfg
Normal file
7
Zennysoft.Game.Ma/addons/input_helper/plugin.cfg
Normal file
@@ -0,0 +1,7 @@
|
||||
[plugin]
|
||||
|
||||
name="Input Helper"
|
||||
description="Detect which input device the player is using and manage input actions"
|
||||
author="Nathan Hoad"
|
||||
version="4.7.0"
|
||||
script="plugin.gd"
|
||||
112
Zennysoft.Game.Ma/addons/input_helper/plugin.gd
Normal file
112
Zennysoft.Game.Ma/addons/input_helper/plugin.gd
Normal file
@@ -0,0 +1,112 @@
|
||||
@tool
|
||||
extends EditorPlugin
|
||||
|
||||
|
||||
const REMOTE_RELEASES_URL = "https://api.github.com/repos/nathanhoad/godot_input_helper/releases"
|
||||
const LOCAL_CONFIG_PATH = "res://addons/input_helper/plugin.cfg"
|
||||
|
||||
const DownloadDialogScene = preload("res://addons/input_helper/views/download_dialog.tscn")
|
||||
|
||||
|
||||
var http_request: HTTPRequest = HTTPRequest.new()
|
||||
var next_version: String = ""
|
||||
|
||||
|
||||
func _enter_tree():
|
||||
add_autoload_singleton("InputHelper", "res://addons/input_helper/input_helper.gd")
|
||||
|
||||
# Configure settings
|
||||
InputHelperSettings.prepare()
|
||||
|
||||
# Check for updates on GitHub
|
||||
get_editor_interface().get_base_control().add_child(http_request)
|
||||
http_request.request_completed.connect(_on_http_request_request_completed)
|
||||
http_request.request(REMOTE_RELEASES_URL)
|
||||
|
||||
|
||||
func _exit_tree():
|
||||
remove_autoload_singleton("InputHelper")
|
||||
|
||||
if next_version != "":
|
||||
remove_tool_menu_item("Update Input Helper to v%s" % next_version)
|
||||
|
||||
|
||||
# Get the current version
|
||||
func get_version() -> String:
|
||||
var config: ConfigFile = ConfigFile.new()
|
||||
config.load(LOCAL_CONFIG_PATH)
|
||||
return config.get_value("plugin", "version")
|
||||
|
||||
|
||||
# Convert a version number to an actually comparable number
|
||||
func version_to_number(version: String) -> int:
|
||||
var bits = version.split(".")
|
||||
return bits[0].to_int() * 1000000 + bits[1].to_int() * 1000 + bits[2].to_int()
|
||||
|
||||
|
||||
### Signals
|
||||
|
||||
|
||||
func _on_http_request_request_completed(result: int, response_code: int, headers: PackedStringArray, body: PackedByteArray) -> void:
|
||||
http_request.queue_free()
|
||||
|
||||
if result != HTTPRequest.RESULT_SUCCESS: return
|
||||
|
||||
var current_version: String = get_version()
|
||||
|
||||
# Work out the next version from the releases information on GitHub
|
||||
var response = JSON.parse_string(body.get_string_from_utf8())
|
||||
if typeof(response) != TYPE_ARRAY: return
|
||||
|
||||
# GitHub releases are in order of creation, not order of version
|
||||
var versions = (response as Array).filter(func(release):
|
||||
var version: String = release.tag_name.substr(1)
|
||||
return version_to_number(version) > version_to_number(current_version)
|
||||
)
|
||||
if versions.size() > 0:
|
||||
next_version = versions[0].tag_name.substr(1)
|
||||
add_tool_menu_item("Update Input Helper to v%s" % next_version, _update_input_helper)
|
||||
|
||||
|
||||
func _update_input_helper() -> void:
|
||||
var download_dialog := DownloadDialogScene.instantiate()
|
||||
download_dialog.next_version = next_version
|
||||
|
||||
var scale: float = get_editor_interface().get_editor_scale()
|
||||
download_dialog.min_size = Vector2(300, 250) * scale
|
||||
|
||||
download_dialog.update_finished.connect(_on_download_dialog_update_finished)
|
||||
download_dialog.update_failed.connect(_on_download_dialog_update_failed)
|
||||
|
||||
get_editor_interface().get_base_control().add_child(download_dialog)
|
||||
download_dialog.show()
|
||||
|
||||
|
||||
func _on_download_dialog_update_finished() -> void:
|
||||
remove_tool_menu_item("Update Input Helper to v%s" % next_version)
|
||||
|
||||
get_editor_interface().get_resource_filesystem().scan()
|
||||
|
||||
print_rich("\n[b]Updated Input Helper to v%s[/b]\n" % next_version)
|
||||
|
||||
var finished_dialog: AcceptDialog = AcceptDialog.new()
|
||||
finished_dialog.dialog_text = "Your Input Helper is now up to date."
|
||||
|
||||
var restart_addon = func():
|
||||
finished_dialog.queue_free()
|
||||
get_editor_interface().call_deferred("set_plugin_enabled", "input_helper", true)
|
||||
get_editor_interface().set_plugin_enabled("input_helper", false)
|
||||
|
||||
finished_dialog.canceled.connect(restart_addon)
|
||||
finished_dialog.confirmed.connect(restart_addon)
|
||||
get_editor_interface().get_base_control().add_child(finished_dialog)
|
||||
finished_dialog.popup_centered()
|
||||
|
||||
|
||||
func _on_download_dialog_update_failed() -> void:
|
||||
var failed_dialog: AcceptDialog = AcceptDialog.new()
|
||||
failed_dialog.dialog_text = "There was a problem downloading the update."
|
||||
failed_dialog.canceled.connect(func(): failed_dialog.queue_free())
|
||||
failed_dialog.confirmed.connect(func(): failed_dialog.queue_free())
|
||||
get_editor_interface().get_base_control().add_child(failed_dialog)
|
||||
failed_dialog.popup_centered()
|
||||
1
Zennysoft.Game.Ma/addons/input_helper/plugin.gd.uid
Normal file
1
Zennysoft.Game.Ma/addons/input_helper/plugin.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://cul6evy00vr55
|
||||
42
Zennysoft.Game.Ma/addons/input_helper/settings.gd
Normal file
42
Zennysoft.Game.Ma/addons/input_helper/settings.gd
Normal file
@@ -0,0 +1,42 @@
|
||||
class_name InputHelperSettings extends Node
|
||||
|
||||
const USE_GRANULAR_DEVICE_IDENTIFIERS = "devices/use_granular_device_identifiers"
|
||||
|
||||
const SETTINGS_CONFIGURATION = {
|
||||
USE_GRANULAR_DEVICE_IDENTIFIERS: {
|
||||
value = false,
|
||||
type = TYPE_BOOL,
|
||||
is_advanced = true
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
static func prepare() -> void:
|
||||
for key: String in SETTINGS_CONFIGURATION:
|
||||
var setting_config: Dictionary = SETTINGS_CONFIGURATION[key]
|
||||
var setting_name: String = "input_helper/%s" % key
|
||||
if not ProjectSettings.has_setting(setting_name):
|
||||
ProjectSettings.set_setting(setting_name, setting_config.value)
|
||||
ProjectSettings.set_initial_value(setting_name, setting_config.value)
|
||||
ProjectSettings.add_property_info({
|
||||
"name" = setting_name,
|
||||
"type" = setting_config.type,
|
||||
"hint" = setting_config.get("hint", PROPERTY_HINT_NONE),
|
||||
"hint_string" = setting_config.get("hint_string", "")
|
||||
})
|
||||
ProjectSettings.set_as_basic(setting_name, not setting_config.has("is_advanced"))
|
||||
ProjectSettings.set_as_internal(setting_name, setting_config.has("is_hidden"))
|
||||
|
||||
|
||||
static func set_setting(key: String, value) -> void:
|
||||
if get_setting(key, value) != value:
|
||||
ProjectSettings.set_setting("input_helper/%s" % key, value)
|
||||
ProjectSettings.set_initial_value("input_helper/%s" % key, SETTINGS_CONFIGURATION[key].value)
|
||||
ProjectSettings.save()
|
||||
|
||||
|
||||
static func get_setting(key: String, default):
|
||||
if ProjectSettings.has_setting("input_helper/%s" % key):
|
||||
return ProjectSettings.get_setting("input_helper/%s" % key)
|
||||
else:
|
||||
return default
|
||||
1
Zennysoft.Game.Ma/addons/input_helper/settings.gd.uid
Normal file
1
Zennysoft.Game.Ma/addons/input_helper/settings.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://yqplm6a6focp
|
||||
@@ -0,0 +1,30 @@
|
||||
@tool
|
||||
|
||||
extends AcceptDialog
|
||||
|
||||
|
||||
signal update_finished()
|
||||
signal update_failed()
|
||||
|
||||
|
||||
@onready var download_update_panel := $DownloadUpdatePanel
|
||||
|
||||
|
||||
var next_version: String
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
download_update_panel.next_version = next_version
|
||||
|
||||
|
||||
### Signals
|
||||
|
||||
|
||||
func _on_download_update_panel_updated(updated_to_version) -> void:
|
||||
update_finished.emit()
|
||||
queue_free()
|
||||
|
||||
|
||||
func _on_download_update_panel_failed() -> void:
|
||||
update_failed.emit()
|
||||
queue_free()
|
||||
@@ -0,0 +1 @@
|
||||
uid://1t3qhgrro2es
|
||||
@@ -0,0 +1,14 @@
|
||||
[gd_scene load_steps=3 format=3 uid="uid://bownbkcmm43gn"]
|
||||
|
||||
[ext_resource type="PackedScene" uid="uid://b7mst0qu7vjk1" path="res://addons/input_helper/components/download_update_panel.tscn" id="1_37q37"]
|
||||
[ext_resource type="Script" uid="uid://1t3qhgrro2es" path="res://addons/input_helper/views/download_dialog.gd" id="1_ltktf"]
|
||||
|
||||
[node name="DownloadDialog" type="AcceptDialog"]
|
||||
initial_position = 2
|
||||
ok_button_text = "Close"
|
||||
script = ExtResource("1_ltktf")
|
||||
|
||||
[node name="DownloadUpdatePanel" parent="." instance=ExtResource("1_37q37")]
|
||||
|
||||
[connection signal="failed" from="DownloadUpdatePanel" to="." method="_on_download_update_panel_failed"]
|
||||
[connection signal="updated" from="DownloadUpdatePanel" to="." method="_on_download_update_panel_updated"]
|
||||
@@ -23,6 +23,7 @@ DialogueManager="*res://addons/dialogue_manager/dialogue_manager.gd"
|
||||
DialogueController="*res://src/game/DialogueController.cs"
|
||||
AudioManager="*res://src/audio/AudioManager.cs"
|
||||
BgmPlayer="*res://src/audio/BGMPlayer.cs"
|
||||
InputHelper="*res://addons/input_helper/input_helper.gd"
|
||||
|
||||
[dialogue_manager]
|
||||
|
||||
@@ -43,7 +44,7 @@ project/assembly_name="Ma"
|
||||
|
||||
[editor_plugins]
|
||||
|
||||
enabled=PackedStringArray("res://addons/dialogue_manager/plugin.cfg", "res://addons/dungeon_floor_layout/plugin.cfg", "res://addons/special_floor_layout_node/plugin.cfg")
|
||||
enabled=PackedStringArray("res://addons/dialogue_manager/plugin.cfg", "res://addons/input_helper/plugin.cfg")
|
||||
|
||||
[file_customization]
|
||||
|
||||
@@ -72,9 +73,7 @@ texture={
|
||||
ui_accept={
|
||||
"deadzone": 0.5,
|
||||
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":32,"physical_keycode":0,"key_label":0,"unicode":32,"location":0,"echo":false,"script":null)
|
||||
, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"button_index":0,"pressure":0.0,"pressed":false,"script":null)
|
||||
, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"button_index":3,"pressure":0.0,"pressed":false,"script":null)
|
||||
, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":69,"key_label":0,"unicode":101,"location":0,"echo":false,"script":null)
|
||||
, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"button_index":0,"pressure":0.0,"pressed":true,"script":null)
|
||||
]
|
||||
}
|
||||
ui_select={
|
||||
@@ -83,34 +82,40 @@ ui_select={
|
||||
}
|
||||
ui_cancel={
|
||||
"deadzone": 0.5,
|
||||
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":4194305,"physical_keycode":0,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
|
||||
, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194309,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
|
||||
, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"button_index":1,"pressure":0.0,"pressed":false,"script":null)
|
||||
"events": [Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"button_index":1,"pressure":0.0,"pressed":true,"script":null)
|
||||
, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":70,"key_label":0,"unicode":102,"location":0,"echo":false,"script":null)
|
||||
]
|
||||
}
|
||||
ui_focus_next={
|
||||
"deadzone": 0.5,
|
||||
"events": []
|
||||
}
|
||||
ui_focus_prev={
|
||||
"deadzone": 0.5,
|
||||
"events": []
|
||||
}
|
||||
ui_left={
|
||||
"deadzone": 0.5,
|
||||
"events": [Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":13,"pressure":0.0,"pressed":false,"script":null)
|
||||
, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":65,"key_label":0,"unicode":97,"location":0,"echo":false,"script":null)
|
||||
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":4194319,"physical_keycode":0,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
|
||||
, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":13,"pressure":0.0,"pressed":false,"script":null)
|
||||
]
|
||||
}
|
||||
ui_right={
|
||||
"deadzone": 0.5,
|
||||
"events": [Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":14,"pressure":0.0,"pressed":false,"script":null)
|
||||
, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":68,"key_label":0,"unicode":100,"location":0,"echo":false,"script":null)
|
||||
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":4194321,"physical_keycode":0,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
|
||||
, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":14,"pressure":0.0,"pressed":false,"script":null)
|
||||
]
|
||||
}
|
||||
ui_up={
|
||||
"deadzone": 0.5,
|
||||
"events": [Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":11,"pressure":0.0,"pressed":false,"script":null)
|
||||
, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":87,"key_label":0,"unicode":119,"location":0,"echo":false,"script":null)
|
||||
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":4194320,"physical_keycode":0,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
|
||||
, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":11,"pressure":0.0,"pressed":false,"script":null)
|
||||
]
|
||||
}
|
||||
ui_down={
|
||||
"deadzone": 0.5,
|
||||
"events": [Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":12,"pressure":0.0,"pressed":false,"script":null)
|
||||
, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":83,"key_label":0,"unicode":115,"location":0,"echo":false,"script":null)
|
||||
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":4194322,"physical_keycode":0,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
|
||||
, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":12,"pressure":0.0,"pressed":false,"script":null)
|
||||
]
|
||||
}
|
||||
MoveUp={
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
using Chickensoft.Collections;
|
||||
using Godot;
|
||||
using System;
|
||||
using Zennysoft.Ma.Adapter;
|
||||
using Zennysoft.Ma.Adapter.Entity;
|
||||
|
||||
@@ -17,6 +19,8 @@ public class EquipmentComponent : IEquipmentComponent
|
||||
|
||||
public AutoProp<EquipableItem> _equippedAccessory;
|
||||
|
||||
public event Action<EquipableItem> EquipmentChanged;
|
||||
|
||||
public int BonusAttack => _equippedWeapon.Value.BonusAttack + _equippedArmor.Value.BonusAttack + _equippedAccessory.Value.BonusAttack;
|
||||
|
||||
public int BonusDefense => _equippedWeapon.Value.BonusDefense + _equippedArmor.Value.BonusDefense + _equippedAccessory.Value.BonusDefense;
|
||||
@@ -51,6 +55,7 @@ public class EquipmentComponent : IEquipmentComponent
|
||||
_equippedArmor.OnNext(armor);
|
||||
if (equipable is Accessory accessory)
|
||||
_equippedAccessory.OnNext(accessory);
|
||||
EquipmentChanged?.Invoke(equipable);
|
||||
}
|
||||
|
||||
public void Unequip(EquipableItem equipable)
|
||||
@@ -61,6 +66,7 @@ public class EquipmentComponent : IEquipmentComponent
|
||||
_equippedArmor.OnNext(new Armor());
|
||||
if (equipable is Accessory accessory)
|
||||
_equippedAccessory.OnNext(new Accessory());
|
||||
EquipmentChanged?.Invoke(equipable);
|
||||
}
|
||||
|
||||
public bool IsItemEquipped(InventoryItem item)
|
||||
|
||||
@@ -60,11 +60,15 @@ public class HealthComponent : IHealthComponent
|
||||
public void SetMaximumHealth(int health)
|
||||
{
|
||||
_maximumHP.OnNext(health);
|
||||
|
||||
if (_currentHP.Value > _maximumHP.Value)
|
||||
_currentHP.OnNext(_maximumHP.Value);
|
||||
}
|
||||
|
||||
public void RaiseMaximumHP(int raiseAmount)
|
||||
public void RaiseMaximumHP(int raiseAmount, bool restoreHP = true)
|
||||
{
|
||||
_maximumHP.OnNext(raiseAmount);
|
||||
Heal(raiseAmount);
|
||||
_maximumHP.OnNext(_maximumHP.Value + raiseAmount);
|
||||
if (restoreHP)
|
||||
Heal(raiseAmount);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,9 +49,18 @@ public class VTComponent : IVTComponent
|
||||
_currentVT.OnNext(cappedAmount);
|
||||
}
|
||||
|
||||
public void RaiseMaximumVT(int raiseAmount)
|
||||
public void RaiseMaximumVT(int raiseAmount, bool restoreVT = true)
|
||||
{
|
||||
_maximumVT.OnNext(raiseAmount);
|
||||
Restore(raiseAmount);
|
||||
_maximumVT.OnNext(_maximumVT.Value + raiseAmount);
|
||||
if (restoreVT)
|
||||
Restore(raiseAmount);
|
||||
}
|
||||
|
||||
public void SetMaximumVT(int vt)
|
||||
{
|
||||
_maximumVT.OnNext(vt);
|
||||
|
||||
if (_currentVT.Value > _maximumVT.Value)
|
||||
_currentVT.OnNext(_maximumVT.Value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,9 +4,13 @@ using Chickensoft.GodotNodeInterfaces;
|
||||
using Chickensoft.Introspection;
|
||||
using Godot;
|
||||
using Godot.Collections;
|
||||
using NathanHoad;
|
||||
using SimpleInjector.Lifestyles;
|
||||
using System.IO.Abstractions;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Zennysoft.Game.Abstractions;
|
||||
using Zennysoft.Game.Implementation;
|
||||
using Zennysoft.Ma.Adapter;
|
||||
|
||||
namespace Zennysoft.Game.Ma;
|
||||
@@ -26,6 +30,8 @@ public partial class App : Node, IApp
|
||||
|
||||
[Node] private LoadingScreen LoadingScreen { get; set; } = default!;
|
||||
|
||||
[Node] private OptionsMenu OptionsMenu { get; set; }
|
||||
|
||||
public IInstantiator Instantiator { get; set; } = default!;
|
||||
|
||||
IAppRepo IProvide<IAppRepo>.Value() => AppRepo;
|
||||
@@ -35,25 +41,50 @@ public partial class App : Node, IApp
|
||||
public AppLogic.IBinding AppBinding { get; set; } = default!;
|
||||
|
||||
private Array _progress;
|
||||
private SimpleInjector.Container _container;
|
||||
|
||||
private AutoProp<string> _loadedScene = new(string.Empty);
|
||||
private bool _loadingGame = false;
|
||||
private bool _loadingEnemyViewer = false;
|
||||
private string _optionsSavePath = string.Empty;
|
||||
private string _controllerSavePath = string.Empty;
|
||||
private ISaveFileManager _saveFileManager;
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
var container = new SimpleInjector.Container();
|
||||
container.Options.DefaultScopedLifestyle = new AsyncScopedLifestyle();
|
||||
container.RegisterSingleton<IAppRepo, AppRepo>();
|
||||
container.RegisterSingleton<IAppLogic, AppLogic>();
|
||||
_container = new SimpleInjector.Container();
|
||||
_container.Options.DefaultScopedLifestyle = new AsyncScopedLifestyle();
|
||||
_container.RegisterSingleton<IAppRepo, AppRepo>();
|
||||
_container.RegisterSingleton<IAppLogic, AppLogic>();
|
||||
_container.RegisterSingleton<IFileSystem, FileSystem>();
|
||||
_container.RegisterSingleton<ISaveFileManager, SaveFileManager>();
|
||||
|
||||
_saveFileManager = _container.GetInstance<ISaveFileManager>();
|
||||
_optionsSavePath = $"{OS.GetUserDataDir()}/options.json";
|
||||
_controllerSavePath = $"{OS.GetUserDataDir()}/controls.json";
|
||||
|
||||
Task.Run(() => _saveFileManager.ReadFromFile<OptionsData>(_optionsSavePath).ContinueWith((data) =>
|
||||
{
|
||||
if (data.IsCompletedSuccessfully)
|
||||
OptionsMenu.CallDeferred("Load", data.Result);
|
||||
}));
|
||||
|
||||
Task.Run(() => _saveFileManager.ReadFromFile<string>(_controllerSavePath).ContinueWith((data) =>
|
||||
{
|
||||
if (data.IsCompletedSuccessfully)
|
||||
OptionsMenu.Controller.CallDeferred(nameof(OptionsMenu.Controller.LoadControllerInput), data.Result);
|
||||
}));
|
||||
|
||||
MainMenu.StartGame += OnStartGame;
|
||||
MainMenu.EnemyViewer += OnEnemyViewer;
|
||||
MainMenu.Options += OnOptions;
|
||||
MainMenu.Quit += OnQuit;
|
||||
_loadedScene.Changed += OnGameLoaded;
|
||||
|
||||
AppRepo = container.GetInstance<IAppRepo>();
|
||||
AppLogic = container.GetInstance<IAppLogic>();
|
||||
OptionsMenu.OptionsMenuExited += OptionsMenu_OptionsMenuExited;
|
||||
|
||||
AppRepo = _container.GetInstance<IAppRepo>();
|
||||
AppLogic = _container.GetInstance<IAppLogic>();
|
||||
|
||||
AppLogic.Set(AppRepo);
|
||||
AppLogic.Set(new AppLogic.Data());
|
||||
@@ -63,6 +94,16 @@ public partial class App : Node, IApp
|
||||
this.Provide();
|
||||
}
|
||||
|
||||
private async void OptionsMenu_OptionsMenuExited()
|
||||
{
|
||||
var saveFileManager = _container.GetInstance<ISaveFileManager>();
|
||||
await saveFileManager.WriteToFile(OptionsMenu.OptionsData, _optionsSavePath);
|
||||
var controllerOutput = InputHelper.SerializeInputsForActions();
|
||||
await saveFileManager.WriteToFile(controllerOutput, _controllerSavePath);
|
||||
OptionsMenu.Hide();
|
||||
MainMenu.OptionsButton.GrabFocus();
|
||||
}
|
||||
|
||||
private void OnGameLoaded(string sceneName)
|
||||
{
|
||||
LoadingScreen.Hide();
|
||||
@@ -86,6 +127,7 @@ public partial class App : Node, IApp
|
||||
{
|
||||
ResourceLoader.LoadThreadedRequest(GAME_SCENE_PATH);
|
||||
_loadingGame = true;
|
||||
MainMenu.ReleaseFocus();
|
||||
MainMenu.Hide();
|
||||
})
|
||||
.Handle((in AppLogic.Output.ShowMainMenu _) =>
|
||||
@@ -109,7 +151,6 @@ public partial class App : Node, IApp
|
||||
});
|
||||
|
||||
AppLogic.Start();
|
||||
MainMenu.Show();
|
||||
}
|
||||
|
||||
public override void _Process(double delta)
|
||||
@@ -135,7 +176,11 @@ public partial class App : Node, IApp
|
||||
|
||||
private void OnEnemyViewer() => AppLogic.Input(new AppLogic.Input.EnemyViewerOpened());
|
||||
|
||||
private void OnLoadGame() => AppLogic.Input(new AppLogic.Input.LoadGame());
|
||||
private async void OnOptions()
|
||||
{
|
||||
OptionsMenu.Show();
|
||||
OptionsMenu.MasterVolumeSlider.GrabFocus();
|
||||
}
|
||||
|
||||
public void OnQuit() => AppLogic.Input(new AppLogic.Input.QuitGame());
|
||||
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
[gd_scene load_steps=4 format=3 uid="uid://cagfc5ridmteu"]
|
||||
[gd_scene load_steps=5 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/MainMenu.tscn" id="2_1uiag"]
|
||||
[ext_resource type="PackedScene" uid="uid://drkl3btdy6uxj" path="res://src/options/OptionsMenu.tscn" id="2_v0mgf"]
|
||||
[ext_resource type="PackedScene" uid="uid://cpjlj7kxdhv16" path="res://src/menu/LoadingScreen.tscn" id="3_3st5l"]
|
||||
|
||||
[node name="App" type="Node"]
|
||||
@@ -11,6 +12,9 @@ script = ExtResource("1_rt73h")
|
||||
[node name="LoadingScreen" parent="." instance=ExtResource("3_3st5l")]
|
||||
unique_name_in_owner = true
|
||||
|
||||
[node name="MainMenu" parent="." instance=ExtResource("2_1uiag")]
|
||||
[node name="OptionsMenu" parent="." instance=ExtResource("2_v0mgf")]
|
||||
unique_name_in_owner = true
|
||||
visible = false
|
||||
|
||||
[node name="MainMenu" parent="." instance=ExtResource("2_1uiag")]
|
||||
unique_name_in_owner = true
|
||||
|
||||
@@ -3,12 +3,12 @@
|
||||
importer="wav"
|
||||
type="AudioStreamWAV"
|
||||
uid="uid://ddii3pi8x75xc"
|
||||
path="res://.godot/imported/amb_beach.wav-e64adf8f733e6a108ae15edd5f0499ab.sample"
|
||||
path="res://.godot/imported/amb_beach.wav-046e4f838e50e43a1aba1a754b92aad6.sample"
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://src/audio/amb/amb_beach.wav"
|
||||
dest_files=["res://.godot/imported/amb_beach.wav-e64adf8f733e6a108ae15edd5f0499ab.sample"]
|
||||
source_file="res://src/audio/AMB/amb_beach.wav"
|
||||
dest_files=["res://.godot/imported/amb_beach.wav-046e4f838e50e43a1aba1a754b92aad6.sample"]
|
||||
|
||||
[params]
|
||||
|
||||
|
||||
@@ -3,12 +3,12 @@
|
||||
importer="wav"
|
||||
type="AudioStreamWAV"
|
||||
uid="uid://ym4ur8a2qxhp"
|
||||
path="res://.godot/imported/amb_perlin.wav-dea63667b2a56d37d48ba209f56f8900.sample"
|
||||
path="res://.godot/imported/amb_perlin.wav-ba6da0d5591f392e4aca7d2f85c4dfc2.sample"
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://src/audio/amb/amb_perlin.wav"
|
||||
dest_files=["res://.godot/imported/amb_perlin.wav-dea63667b2a56d37d48ba209f56f8900.sample"]
|
||||
source_file="res://src/audio/AMB/amb_perlin.wav"
|
||||
dest_files=["res://.godot/imported/amb_perlin.wav-ba6da0d5591f392e4aca7d2f85c4dfc2.sample"]
|
||||
|
||||
[params]
|
||||
|
||||
|
||||
@@ -3,12 +3,12 @@
|
||||
importer="wav"
|
||||
type="AudioStreamWAV"
|
||||
uid="uid://b7wxddjx3qw5o"
|
||||
path="res://.godot/imported/amb_white_noise.wav-c98b45aa94120bc0c660bf2d6af1c696.sample"
|
||||
path="res://.godot/imported/amb_white_noise.wav-d316dd05afe429f6bcdda594285ad718.sample"
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://src/audio/amb/amb_white_noise.wav"
|
||||
dest_files=["res://.godot/imported/amb_white_noise.wav-c98b45aa94120bc0c660bf2d6af1c696.sample"]
|
||||
source_file="res://src/audio/AMB/amb_white_noise.wav"
|
||||
dest_files=["res://.godot/imported/amb_white_noise.wav-d316dd05afe429f6bcdda594285ad718.sample"]
|
||||
|
||||
[params]
|
||||
|
||||
|
||||
@@ -3,12 +3,12 @@
|
||||
importer="wav"
|
||||
type="AudioStreamWAV"
|
||||
uid="uid://bmiitw4fcs68e"
|
||||
path="res://.godot/imported/amb_wind_loop_altar.wav-b9d60e3c3c10ec00833903539a7f3796.sample"
|
||||
path="res://.godot/imported/amb_wind_loop_altar.wav-e766e3db29faa01ad6dbaa8cb18d7de6.sample"
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://src/audio/amb/amb_wind_loop_altar.wav"
|
||||
dest_files=["res://.godot/imported/amb_wind_loop_altar.wav-b9d60e3c3c10ec00833903539a7f3796.sample"]
|
||||
source_file="res://src/audio/AMB/amb_wind_loop_altar.wav"
|
||||
dest_files=["res://.godot/imported/amb_wind_loop_altar.wav-e766e3db29faa01ad6dbaa8cb18d7de6.sample"]
|
||||
|
||||
[params]
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ public partial class AudioManager : Node
|
||||
var soundEffects = Enum.GetValues(typeof(SoundEffect));
|
||||
foreach (var effect in soundEffects)
|
||||
_sfxDictionary.Add((SoundEffect)effect, GD.Load<AudioStream>(sfxPath + effect + ".ogg"));
|
||||
_audioPlayer.Bus = "SFX";
|
||||
}
|
||||
|
||||
public void Play(SoundEffect soundEffect)
|
||||
|
||||
@@ -1 +1 @@
|
||||
uid://dnh47mgvakhvh
|
||||
uid://ry5iewox61vs
|
||||
|
||||
@@ -1 +1 @@
|
||||
uid://btpqk2uvk834y
|
||||
uid://t0j1h13hgo0t
|
||||
|
||||
@@ -267,7 +267,7 @@ public partial class Game : Node3D, IGame
|
||||
})
|
||||
.Handle((in GameState.Output.OpenInventoryMenu _) =>
|
||||
{
|
||||
InGameUI.InventoryMenu.RefreshInventoryScreen();
|
||||
//InGameUI.InventoryMenu.RefreshInventoryScreen();
|
||||
InGameUI.InventoryMenu.Show();
|
||||
InGameUI.InventoryMenu.SetProcessInput(true);
|
||||
})
|
||||
@@ -460,7 +460,7 @@ public partial class Game : Node3D, IGame
|
||||
if (item is IStackable stackableItem && stackableItem.Count > 1)
|
||||
stackableItem.SetCount(stackableItem.Count - 1);
|
||||
else
|
||||
GameRepo.RemoveItemFromInventory(item);
|
||||
_player.Inventory.Remove(item);
|
||||
}
|
||||
|
||||
private void MovePlayer(Transform3D spawnPoint) => _player.TeleportPlayer(spawnPoint);
|
||||
|
||||
@@ -19,6 +19,7 @@ public partial class Inventory : Node, IInventory
|
||||
private const int _maxInventorySize = 20;
|
||||
|
||||
public event Action<string> BroadcastMessage;
|
||||
public event Action InventoryChanged;
|
||||
|
||||
public Inventory()
|
||||
{
|
||||
@@ -32,10 +33,7 @@ public partial class Inventory : Node, IInventory
|
||||
{
|
||||
var isAdded = TryAdd(item);
|
||||
if (isAdded)
|
||||
{
|
||||
BroadcastMessage?.Invoke($"{item.ItemName} picked up.");
|
||||
item.QueueFree();
|
||||
}
|
||||
else
|
||||
BroadcastMessage?.Invoke($"Could not pick up {item.ItemName}.");
|
||||
|
||||
@@ -48,6 +46,7 @@ public partial class Inventory : Node, IInventory
|
||||
return false;
|
||||
|
||||
Items.Add(inventoryItem);
|
||||
InventoryChanged?.Invoke();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -57,11 +56,15 @@ public partial class Inventory : Node, IInventory
|
||||
return false;
|
||||
|
||||
Items.Insert(index, inventoryItem);
|
||||
InventoryChanged?.Invoke();
|
||||
return true;
|
||||
}
|
||||
|
||||
public void Remove(InventoryItem inventoryItem) => Items.Remove(inventoryItem);
|
||||
|
||||
public void Remove(InventoryItem inventoryItem)
|
||||
{
|
||||
Items.Remove(inventoryItem);
|
||||
InventoryChanged?.Invoke();
|
||||
}
|
||||
|
||||
public void Sort(EquipableItem currentWeapon, EquipableItem currentArmor, EquipableItem currentAccessory)
|
||||
{
|
||||
|
||||
@@ -9,9 +9,11 @@ namespace Zennysoft.Game.Ma;
|
||||
public abstract partial class InventoryItemStats : Resource
|
||||
{
|
||||
[Export]
|
||||
[Save("equipment_name")]
|
||||
public string Name { get; set; }
|
||||
|
||||
[Export(PropertyHint.MultilineText)]
|
||||
[Save("equipment_description")]
|
||||
public string Description { get; set; }
|
||||
|
||||
[Export(PropertyHint.Range, "0, 1, 0.01")]
|
||||
@@ -30,33 +32,43 @@ public abstract partial class InventoryItemStats : Resource
|
||||
public double BonusLuck { get; set; } = 0.05;
|
||||
|
||||
[Export]
|
||||
[Save("equipment_bonus_hp")]
|
||||
public int BonusHP { get; set; } = 0;
|
||||
|
||||
[Export]
|
||||
[Save("equipment_bonus_vt")]
|
||||
public int BonusVT { get; set; } = 0;
|
||||
|
||||
[Export]
|
||||
[Save("equipment_aeolic_resist")]
|
||||
public int AeolicResistance { get; set; } = 0;
|
||||
|
||||
[Export]
|
||||
[Save("equipment_telluric_resist")]
|
||||
public int TelluricResistance { get; set; } = 0;
|
||||
|
||||
[Export]
|
||||
[Save("equipment_hydric_resist")]
|
||||
public int HydricResistance { get; set; } = 0;
|
||||
|
||||
[Export]
|
||||
[Save("equipment_igneous_resist")]
|
||||
public int IgneousResistance { get; set; } = 0;
|
||||
|
||||
[Export]
|
||||
[Save("equipment_ferrum_resist")]
|
||||
public int FerrumResistance { get; set; } = 0;
|
||||
|
||||
[Export(PropertyHint.Range, "0, 25, 0.1")]
|
||||
[Save("equipment_throw_speed")]
|
||||
public float ThrowSpeed { get; set; } = 12.0f;
|
||||
|
||||
[Export(PropertyHint.Range, "0, 999, 1")]
|
||||
public int IncreaseMaxHPAmount { get; set; }
|
||||
|
||||
[Export(PropertyHint.Range, "0, 999, 1")]
|
||||
public int IncreaseMaxVTAmount { get; set; }
|
||||
|
||||
[Export(PropertyHint.Range, "0, 999, 1")]
|
||||
[Save("equipment_throw_damage")]
|
||||
public int ThrowDamage { get; set; } = 5;
|
||||
|
||||
[Export]
|
||||
[Save("equipment_item_tag")]
|
||||
public ItemTag ItemTag { get; set; } = ItemTag.None;
|
||||
|
||||
[Export]
|
||||
|
||||
@@ -62,7 +62,6 @@ public class ItemDatabase
|
||||
weaponScene.Stats = weaponInfo;
|
||||
if (!database.Contains(weaponScene))
|
||||
database.Add(weaponScene);
|
||||
database.Add(weaponScene);
|
||||
}
|
||||
|
||||
foreach (var accessory in accessoryResources)
|
||||
@@ -72,7 +71,6 @@ public class ItemDatabase
|
||||
accessoryScene.Stats = accessoryInfo;
|
||||
if (!database.Contains(accessoryScene))
|
||||
database.Add(accessoryScene);
|
||||
database.Add(accessoryScene);
|
||||
}
|
||||
|
||||
foreach (var throwable in throwableResources)
|
||||
@@ -82,7 +80,6 @@ public class ItemDatabase
|
||||
throwableItemScene.Stats = throwableItemInfo;
|
||||
if (!database.Contains(throwableItemScene))
|
||||
database.Add(throwableItemScene);
|
||||
database.Add(throwableItemScene);
|
||||
}
|
||||
|
||||
foreach (var consumable in consumableResources)
|
||||
@@ -92,7 +89,6 @@ public class ItemDatabase
|
||||
consumableItemScene.Stats = consumableItemInfo;
|
||||
if (!database.Contains(consumableItemScene))
|
||||
database.Add(consumableItemScene);
|
||||
database.Add(consumableItemScene);
|
||||
}
|
||||
|
||||
foreach (var effectItem in effectResources)
|
||||
@@ -102,7 +98,6 @@ public class ItemDatabase
|
||||
effectItemScene.Stats = effectItemInfo;
|
||||
if (!database.Contains(effectItemScene))
|
||||
database.Add(effectItemScene);
|
||||
database.Add(effectItemScene);
|
||||
}
|
||||
|
||||
Items = [.. database];
|
||||
|
||||
@@ -28,6 +28,14 @@ public partial class Accessory : EquipableItem
|
||||
|
||||
public override float ThrowSpeed => Stats.ThrowSpeed;
|
||||
|
||||
public override int BonusAttack => Stats.BonusAttack;
|
||||
|
||||
public override int BonusDefense => Stats.BonusDefense;
|
||||
|
||||
public override int BonusHP => Stats.BonusHP;
|
||||
|
||||
public override int BonusVT => Stats.BonusVT;
|
||||
|
||||
public override ElementalResistanceSet ElementalResistance => new ElementalResistanceSet(Stats.AeolicResistance, Stats.HydricResistance, Stats.IgneousResistance, Stats.FerrumResistance, Stats.TelluricResistance);
|
||||
|
||||
[Save("accessory_tag")]
|
||||
|
||||
@@ -5,18 +5,21 @@
|
||||
|
||||
[resource]
|
||||
script = ExtResource("1_xqaot")
|
||||
ATKUp = 0
|
||||
DEFUp = 0
|
||||
LuckUp = 0.1
|
||||
MaxHPUp = 0
|
||||
MaxVTUp = 0
|
||||
AccessoryTag = 0
|
||||
Name = "Mask of the Goddess of Avarice"
|
||||
Description = "Raises Luck"
|
||||
Texture = ExtResource("1_q42cv")
|
||||
SpawnRate = 0.1
|
||||
BonusAttack = 0
|
||||
BonusDefense = 0
|
||||
BonusLuck = 0.3
|
||||
AeolicResistance = 0
|
||||
TelluricResistance = 0
|
||||
HydricResistance = 0
|
||||
IgneousResistance = 0
|
||||
FerrumResistance = 0
|
||||
ThrowSpeed = 12.0
|
||||
HealHPAmount = 0
|
||||
HealVTAmount = 0
|
||||
IncreaseMaxHPAmount = 0
|
||||
IncreaseMaxVTAmount = 0
|
||||
ThrowDamage = 5
|
||||
ItemTag = 0
|
||||
Texture = ExtResource("1_q42cv")
|
||||
|
||||
@@ -1,17 +1,25 @@
|
||||
[gd_resource type="Resource" script_class="AccessoryStats" load_steps=3 format=3 uid="uid://d4bcem2nup7ef"]
|
||||
|
||||
[ext_resource type="Texture2D" uid="uid://db7i7iy5gagae" path="res://src/items/accessory/textures/MASK 02.PNG" id="1_0p1ot"]
|
||||
[ext_resource type="Script" path="res://src/items/accessory/AccessoryStats.cs" id="1_vef66"]
|
||||
[ext_resource type="Script" uid="uid://b8arlmivk68b" path="res://src/items/accessory/AccessoryStats.cs" id="1_vef66"]
|
||||
|
||||
[resource]
|
||||
script = ExtResource("1_vef66")
|
||||
ATKUp = 3
|
||||
DEFUp = 0
|
||||
LUCKUp = 0.0
|
||||
MaxHPUp = 0
|
||||
MaxVTUp = 0
|
||||
AccessoryTags = [0]
|
||||
AccessoryTag = 0
|
||||
Name = "Mask of the Goddess of Destruction"
|
||||
Description = "Raises ATK."
|
||||
Texture = ExtResource("1_0p1ot")
|
||||
SpawnRate = 0.1
|
||||
BonusAttack = 3
|
||||
BonusDefense = 0
|
||||
BonusLuck = 0.05
|
||||
AeolicResistance = 0
|
||||
TelluricResistance = 0
|
||||
HydricResistance = 0
|
||||
IgneousResistance = 0
|
||||
FerrumResistance = 0
|
||||
ThrowSpeed = 12.0
|
||||
IncreaseMaxHPAmount = 0
|
||||
IncreaseMaxVTAmount = 0
|
||||
ThrowDamage = 5
|
||||
ItemTag = 0
|
||||
Texture = ExtResource("1_0p1ot")
|
||||
|
||||
@@ -1,17 +1,25 @@
|
||||
[gd_resource type="Resource" script_class="AccessoryStats" load_steps=3 format=3 uid="uid://bejy3lpudgawg"]
|
||||
|
||||
[ext_resource type="Texture2D" uid="uid://db7i7iy5gagae" path="res://src/items/accessory/textures/MASK 02.PNG" id="1_0k42r"]
|
||||
[ext_resource type="Script" path="res://src/items/accessory/AccessoryStats.cs" id="1_cgxkh"]
|
||||
[ext_resource type="Script" uid="uid://b8arlmivk68b" path="res://src/items/accessory/AccessoryStats.cs" id="1_cgxkh"]
|
||||
|
||||
[resource]
|
||||
script = ExtResource("1_cgxkh")
|
||||
ATKUp = 1
|
||||
DEFUp = 1
|
||||
LUCKUp = 0.0
|
||||
MaxHPUp = 30
|
||||
MaxVTUp = 30
|
||||
AccessoryTags = []
|
||||
AccessoryTag = 0
|
||||
Name = "Mask of the Goddess of Guilt"
|
||||
Description = "Raises MAX HP, MAX VT, ATK, DEF"
|
||||
Texture = ExtResource("1_0k42r")
|
||||
SpawnRate = 0.1
|
||||
BonusAttack = 2
|
||||
BonusDefense = 2
|
||||
BonusLuck = 0.05
|
||||
BonusHP = 25
|
||||
BonusVT = 25
|
||||
AeolicResistance = 0
|
||||
TelluricResistance = 0
|
||||
HydricResistance = 0
|
||||
IgneousResistance = 0
|
||||
FerrumResistance = 0
|
||||
ThrowSpeed = 12.0
|
||||
ThrowDamage = 5
|
||||
ItemTag = 0
|
||||
Texture = ExtResource("1_0k42r")
|
||||
|
||||
@@ -1,17 +1,25 @@
|
||||
[gd_resource type="Resource" script_class="AccessoryStats" load_steps=3 format=3 uid="uid://ddwyaxxqvk52h"]
|
||||
|
||||
[ext_resource type="Texture2D" uid="uid://db7i7iy5gagae" path="res://src/items/accessory/textures/MASK 02.PNG" id="1_1uw37"]
|
||||
[ext_resource type="Script" path="res://src/items/accessory/AccessoryStats.cs" id="1_kuyyj"]
|
||||
[ext_resource type="Script" uid="uid://b8arlmivk68b" path="res://src/items/accessory/AccessoryStats.cs" id="1_kuyyj"]
|
||||
|
||||
[resource]
|
||||
script = ExtResource("1_kuyyj")
|
||||
ATKUp = 0
|
||||
DEFUp = 3
|
||||
LUCKUp = 0.0
|
||||
MaxHPUp = 0
|
||||
MaxVTUp = 0
|
||||
AccessoryTags = []
|
||||
AccessoryTag = 0
|
||||
Name = "Mask of the Goddess of Obstinance"
|
||||
Description = "Raises DEF."
|
||||
Texture = ExtResource("1_1uw37")
|
||||
SpawnRate = 0.1
|
||||
BonusAttack = 0
|
||||
BonusDefense = 3
|
||||
BonusLuck = 0.05
|
||||
AeolicResistance = 0
|
||||
TelluricResistance = 0
|
||||
HydricResistance = 0
|
||||
IgneousResistance = 0
|
||||
FerrumResistance = 0
|
||||
ThrowSpeed = 12.0
|
||||
IncreaseMaxHPAmount = 0
|
||||
IncreaseMaxVTAmount = 0
|
||||
ThrowDamage = 5
|
||||
ItemTag = 0
|
||||
Texture = ExtResource("1_1uw37")
|
||||
|
||||
@@ -1,17 +1,25 @@
|
||||
[gd_resource type="Resource" script_class="AccessoryStats" load_steps=3 format=3 uid="uid://d02kuxaus43mk"]
|
||||
|
||||
[ext_resource type="Script" path="res://src/items/accessory/AccessoryStats.cs" id="1_3iw2y"]
|
||||
[ext_resource type="Script" uid="uid://b8arlmivk68b" path="res://src/items/accessory/AccessoryStats.cs" id="1_3iw2y"]
|
||||
[ext_resource type="Texture2D" uid="uid://db7i7iy5gagae" path="res://src/items/accessory/textures/MASK 02.PNG" id="1_vc77e"]
|
||||
|
||||
[resource]
|
||||
script = ExtResource("1_3iw2y")
|
||||
ATKUp = 0
|
||||
DEFUp = 0
|
||||
LUCKUp = 0.0
|
||||
MaxHPUp = 0
|
||||
MaxVTUp = 50
|
||||
AccessoryTags = []
|
||||
AccessoryTag = 0
|
||||
Name = "Mask of the Goddess of Suffering"
|
||||
Description = "Raises MAX VT"
|
||||
Texture = ExtResource("1_vc77e")
|
||||
SpawnRate = 0.1
|
||||
BonusAttack = 0
|
||||
BonusDefense = 0
|
||||
BonusLuck = 0.05
|
||||
BonusHP = 0
|
||||
BonusVT = 50
|
||||
AeolicResistance = 0
|
||||
TelluricResistance = 0
|
||||
HydricResistance = 0
|
||||
IgneousResistance = 0
|
||||
FerrumResistance = 0
|
||||
ThrowSpeed = 12.0
|
||||
ThrowDamage = 5
|
||||
ItemTag = 0
|
||||
Texture = ExtResource("1_vc77e")
|
||||
|
||||
@@ -1,17 +1,25 @@
|
||||
[gd_resource type="Resource" script_class="AccessoryStats" load_steps=3 format=3 uid="uid://b0bxwp55mcyyp"]
|
||||
|
||||
[ext_resource type="Script" path="res://src/items/accessory/AccessoryStats.cs" id="1_0u4rq"]
|
||||
[ext_resource type="Script" uid="uid://b8arlmivk68b" path="res://src/items/accessory/AccessoryStats.cs" id="1_0u4rq"]
|
||||
[ext_resource type="Texture2D" uid="uid://db7i7iy5gagae" path="res://src/items/accessory/textures/MASK 02.PNG" id="1_ggv41"]
|
||||
|
||||
[resource]
|
||||
script = ExtResource("1_0u4rq")
|
||||
ATKUp = 0
|
||||
DEFUp = 0
|
||||
LUCKUp = 0.0
|
||||
MaxHPUp = 50
|
||||
MaxVTUp = 0
|
||||
AccessoryTags = []
|
||||
AccessoryTag = 0
|
||||
Name = "Mask of the Goddess of Zeal"
|
||||
Description = "Raises MAX HP"
|
||||
Texture = ExtResource("1_ggv41")
|
||||
SpawnRate = 0.1
|
||||
BonusAttack = 0
|
||||
BonusDefense = 0
|
||||
BonusLuck = 0.05
|
||||
BonusHP = 50
|
||||
BonusVT = 0
|
||||
AeolicResistance = 0
|
||||
TelluricResistance = 0
|
||||
HydricResistance = 0
|
||||
IgneousResistance = 0
|
||||
FerrumResistance = 0
|
||||
ThrowSpeed = 12.0
|
||||
ThrowDamage = 5
|
||||
ItemTag = 0
|
||||
Texture = ExtResource("1_ggv41")
|
||||
|
||||
@@ -5,9 +5,6 @@
|
||||
|
||||
[resource]
|
||||
script = ExtResource("1_si4wu")
|
||||
Name = "Acceptance"
|
||||
Description = "+9 DEF"
|
||||
Defense = 9
|
||||
_telluricResistance = 0.0
|
||||
_aeolicResistance = 0.0
|
||||
_hydricResistance = 0.0
|
||||
@@ -16,9 +13,17 @@ _ferrumResistance = 0.0
|
||||
Name = "Acceptance"
|
||||
Description = "+9 DEF"
|
||||
SpawnRate = 0.01
|
||||
BonusAttack = 0
|
||||
BonusDefense = 9
|
||||
BonusLuck = 0.05
|
||||
AeolicResistance = 0
|
||||
TelluricResistance = 0
|
||||
HydricResistance = 0
|
||||
IgneousResistance = 0
|
||||
FerrumResistance = 0
|
||||
ThrowSpeed = 12.0
|
||||
HealHPAmount = 0
|
||||
HealVTAmount = 0
|
||||
IncreaseMaxHPAmount = 0
|
||||
IncreaseMaxVTAmount = 0
|
||||
ThrowDamage = 5
|
||||
ItemTag = 0
|
||||
Texture = ExtResource("1_p85jd")
|
||||
|
||||
@@ -5,18 +5,25 @@
|
||||
|
||||
[resource]
|
||||
script = ExtResource("1_6r2bl")
|
||||
Defense = 1
|
||||
TelluricResistance = 0.0
|
||||
AeolicResistance = 0.0
|
||||
HydricResistance = 0.0
|
||||
IgneousResistance = 0.0
|
||||
FerrumResistance = 0.0
|
||||
_telluricResistance = 0.0
|
||||
_aeolicResistance = 0.0
|
||||
_hydricResistance = 0.0
|
||||
_igneousResistance = 0.0
|
||||
_ferrumResistance = 0.0
|
||||
Name = "Atoner's Adornments"
|
||||
Description = "+1 DEF"
|
||||
Texture = ExtResource("1_588l8")
|
||||
SpawnRate = 0.25
|
||||
BonusAttack = 0
|
||||
BonusDefense = 1
|
||||
BonusLuck = 0.05
|
||||
AeolicResistance = 0
|
||||
TelluricResistance = 0
|
||||
HydricResistance = 0
|
||||
IgneousResistance = 0
|
||||
FerrumResistance = 0
|
||||
ThrowSpeed = 12.0
|
||||
HealHPAmount = 0
|
||||
HealVTAmount = 0
|
||||
IncreaseMaxHPAmount = 0
|
||||
IncreaseMaxVTAmount = 0
|
||||
ThrowDamage = 5
|
||||
ItemTag = 0
|
||||
Texture = ExtResource("1_588l8")
|
||||
|
||||
@@ -1,17 +1,29 @@
|
||||
[gd_resource type="Resource" script_class="ArmorStats" load_steps=3 format=3 uid="uid://dnu241lh47oqd"]
|
||||
|
||||
[ext_resource type="Script" path="res://src/items/armor/ArmorStats.cs" id="1_0qtvf"]
|
||||
[ext_resource type="Script" uid="uid://dqtp6ewvttoyu" path="res://src/items/armor/ArmorStats.cs" id="1_0qtvf"]
|
||||
[ext_resource type="Texture2D" uid="uid://vvhbibkslh57" path="res://src/items/armor/textures/CEREMONIAL.PNG" id="1_s4gpg"]
|
||||
|
||||
[resource]
|
||||
script = ExtResource("1_0qtvf")
|
||||
Defense = 2
|
||||
TelluricResistance = 0.0
|
||||
AeolicResistance = 0.0
|
||||
HydricResistance = 0.0
|
||||
IgneousResistance = 0.0
|
||||
FerrumResistance = 0.0
|
||||
_telluricResistance = 0.0
|
||||
_aeolicResistance = 0.0
|
||||
_hydricResistance = 0.0
|
||||
_igneousResistance = 0.0
|
||||
_ferrumResistance = 0.0
|
||||
Name = "Ceremonial Vestments"
|
||||
Description = "+2 DEF"
|
||||
Texture = ExtResource("1_s4gpg")
|
||||
SpawnRate = 0.2
|
||||
BonusAttack = 0
|
||||
BonusDefense = 2
|
||||
BonusLuck = 0.05
|
||||
AeolicResistance = 0
|
||||
TelluricResistance = 0
|
||||
HydricResistance = 0
|
||||
IgneousResistance = 0
|
||||
FerrumResistance = 0
|
||||
ThrowSpeed = 12.0
|
||||
IncreaseMaxHPAmount = 0
|
||||
IncreaseMaxVTAmount = 0
|
||||
ThrowDamage = 5
|
||||
ItemTag = 0
|
||||
Texture = ExtResource("1_s4gpg")
|
||||
|
||||
@@ -1,17 +1,29 @@
|
||||
[gd_resource type="Resource" script_class="ArmorStats" load_steps=3 format=3 uid="uid://4s7wjsb7eb6e"]
|
||||
|
||||
[ext_resource type="Texture2D" uid="uid://381ddynsa3gc" path="res://src/items/armor/textures/DEVIC.PNG" id="1_5ik54"]
|
||||
[ext_resource type="Script" path="res://src/items/armor/ArmorStats.cs" id="1_w3lql"]
|
||||
[ext_resource type="Script" uid="uid://dqtp6ewvttoyu" path="res://src/items/armor/ArmorStats.cs" id="1_w3lql"]
|
||||
|
||||
[resource]
|
||||
script = ExtResource("1_w3lql")
|
||||
Defense = 7
|
||||
TelluricResistance = 0.0
|
||||
AeolicResistance = 0.0
|
||||
HydricResistance = 0.0
|
||||
IgneousResistance = 0.0
|
||||
FerrumResistance = 0.0
|
||||
_telluricResistance = 0.0
|
||||
_aeolicResistance = 0.0
|
||||
_hydricResistance = 0.0
|
||||
_igneousResistance = 0.0
|
||||
_ferrumResistance = 0.0
|
||||
Name = "Devic Layers"
|
||||
Description = "+7 DEF"
|
||||
Texture = ExtResource("1_5ik54")
|
||||
SpawnRate = 0.05
|
||||
BonusAttack = 0
|
||||
BonusDefense = 7
|
||||
BonusLuck = 0.05
|
||||
AeolicResistance = 0
|
||||
TelluricResistance = 0
|
||||
HydricResistance = 0
|
||||
IgneousResistance = 0
|
||||
FerrumResistance = 0
|
||||
ThrowSpeed = 12.0
|
||||
IncreaseMaxHPAmount = 0
|
||||
IncreaseMaxVTAmount = 0
|
||||
ThrowDamage = 5
|
||||
ItemTag = 0
|
||||
Texture = ExtResource("1_5ik54")
|
||||
|
||||
@@ -1,17 +1,29 @@
|
||||
[gd_resource type="Resource" script_class="ArmorStats" load_steps=3 format=3 uid="uid://dc0qjer88chme"]
|
||||
|
||||
[ext_resource type="Script" path="res://src/items/armor/ArmorStats.cs" id="1_3mc7x"]
|
||||
[ext_resource type="Script" uid="uid://dqtp6ewvttoyu" path="res://src/items/armor/ArmorStats.cs" id="1_3mc7x"]
|
||||
[ext_resource type="Texture2D" uid="uid://c57kuugsc2lti" path="res://src/items/armor/textures/GODDESS.PNG" id="1_5vleh"]
|
||||
|
||||
[resource]
|
||||
script = ExtResource("1_3mc7x")
|
||||
Defense = 8
|
||||
TelluricResistance = 0.0
|
||||
AeolicResistance = 0.0
|
||||
HydricResistance = 0.0
|
||||
IgneousResistance = 0.0
|
||||
FerrumResistance = 0.0
|
||||
_telluricResistance = 0.0
|
||||
_aeolicResistance = 0.0
|
||||
_hydricResistance = 0.0
|
||||
_igneousResistance = 0.0
|
||||
_ferrumResistance = 0.0
|
||||
Name = "Goddess' Robe"
|
||||
Description = "+8 DEF"
|
||||
Texture = ExtResource("1_5vleh")
|
||||
SpawnRate = 0.03
|
||||
BonusAttack = 0
|
||||
BonusDefense = 8
|
||||
BonusLuck = 0.05
|
||||
AeolicResistance = 0
|
||||
TelluricResistance = 0
|
||||
HydricResistance = 0
|
||||
IgneousResistance = 0
|
||||
FerrumResistance = 0
|
||||
ThrowSpeed = 12.0
|
||||
IncreaseMaxHPAmount = 0
|
||||
IncreaseMaxVTAmount = 0
|
||||
ThrowDamage = 5
|
||||
ItemTag = 0
|
||||
Texture = ExtResource("1_5vleh")
|
||||
|
||||
@@ -1,17 +1,29 @@
|
||||
[gd_resource type="Resource" script_class="ArmorStats" load_steps=3 format=3 uid="uid://ceqnyutl7y7t4"]
|
||||
|
||||
[ext_resource type="Script" path="res://src/items/armor/ArmorStats.cs" id="1_iqj2w"]
|
||||
[ext_resource type="Script" uid="uid://dqtp6ewvttoyu" path="res://src/items/armor/ArmorStats.cs" id="1_iqj2w"]
|
||||
[ext_resource type="Texture2D" uid="uid://cj5m8qkpqrcx4" path="res://src/items/armor/textures/IRON.PNG" id="1_jyoar"]
|
||||
|
||||
[resource]
|
||||
script = ExtResource("1_iqj2w")
|
||||
Defense = 4
|
||||
TelluricResistance = 0.0
|
||||
AeolicResistance = 0.0
|
||||
HydricResistance = 0.0
|
||||
IgneousResistance = 0.0
|
||||
FerrumResistance = 0.0
|
||||
_telluricResistance = 0.0
|
||||
_aeolicResistance = 0.0
|
||||
_hydricResistance = 0.0
|
||||
_igneousResistance = 0.0
|
||||
_ferrumResistance = 0.0
|
||||
Name = "Iron Cage"
|
||||
Description = "+4 DEF"
|
||||
Texture = ExtResource("1_jyoar")
|
||||
SpawnRate = 0.15
|
||||
BonusAttack = 0
|
||||
BonusDefense = 4
|
||||
BonusLuck = 0.05
|
||||
AeolicResistance = 0
|
||||
TelluricResistance = 0
|
||||
HydricResistance = 0
|
||||
IgneousResistance = 0
|
||||
FerrumResistance = 0
|
||||
ThrowSpeed = 12.0
|
||||
IncreaseMaxHPAmount = 0
|
||||
IncreaseMaxVTAmount = 0
|
||||
ThrowDamage = 5
|
||||
ItemTag = 0
|
||||
Texture = ExtResource("1_jyoar")
|
||||
|
||||
@@ -1,17 +1,29 @@
|
||||
[gd_resource type="Resource" script_class="ArmorStats" load_steps=3 format=3 uid="uid://chhxktntl4k8r"]
|
||||
|
||||
[ext_resource type="Script" path="res://src/items/armor/ArmorStats.cs" id="1_frqfh"]
|
||||
[ext_resource type="Script" uid="uid://dqtp6ewvttoyu" path="res://src/items/armor/ArmorStats.cs" id="1_frqfh"]
|
||||
[ext_resource type="Texture2D" uid="uid://2qvbtq2obsac" path="res://src/items/armor/textures/LOGISTIAN.PNG" id="1_kh3n2"]
|
||||
|
||||
[resource]
|
||||
script = ExtResource("1_frqfh")
|
||||
Defense = 5
|
||||
TelluricResistance = 0.0
|
||||
AeolicResistance = 0.0
|
||||
HydricResistance = 0.0
|
||||
IgneousResistance = 0.0
|
||||
FerrumResistance = 0.0
|
||||
_telluricResistance = 0.0
|
||||
_aeolicResistance = 0.0
|
||||
_hydricResistance = 0.0
|
||||
_igneousResistance = 0.0
|
||||
_ferrumResistance = 0.0
|
||||
Name = "Logistician's Garb"
|
||||
Description = "+5 DEF"
|
||||
Texture = ExtResource("1_kh3n2")
|
||||
SpawnRate = 0.08
|
||||
BonusAttack = 0
|
||||
BonusDefense = 5
|
||||
BonusLuck = 0.05
|
||||
AeolicResistance = 0
|
||||
TelluricResistance = 0
|
||||
HydricResistance = 0
|
||||
IgneousResistance = 0
|
||||
FerrumResistance = 0
|
||||
ThrowSpeed = 12.0
|
||||
IncreaseMaxHPAmount = 0
|
||||
IncreaseMaxVTAmount = 0
|
||||
ThrowDamage = 5
|
||||
ItemTag = 0
|
||||
Texture = ExtResource("1_kh3n2")
|
||||
|
||||
@@ -1,17 +1,29 @@
|
||||
[gd_resource type="Resource" script_class="ArmorStats" load_steps=3 format=3 uid="uid://d3l8aa87tevgt"]
|
||||
|
||||
[ext_resource type="Script" path="res://src/items/armor/ArmorStats.cs" id="1_dh6tr"]
|
||||
[ext_resource type="Script" uid="uid://dqtp6ewvttoyu" path="res://src/items/armor/ArmorStats.cs" id="1_dh6tr"]
|
||||
[ext_resource type="Texture2D" uid="uid://ddtscpfj6nf6i" path="res://src/items/armor/textures/STOIC.PNG" id="1_xpphu"]
|
||||
|
||||
[resource]
|
||||
script = ExtResource("1_dh6tr")
|
||||
Defense = 6
|
||||
TelluricResistance = 0.0
|
||||
AeolicResistance = 0.0
|
||||
HydricResistance = 0.0
|
||||
IgneousResistance = 0.0
|
||||
FerrumResistance = 0.0
|
||||
_telluricResistance = 0.0
|
||||
_aeolicResistance = 0.0
|
||||
_hydricResistance = 0.0
|
||||
_igneousResistance = 0.0
|
||||
_ferrumResistance = 0.0
|
||||
Name = "Stoic"
|
||||
Description = "+6 DEF"
|
||||
Texture = ExtResource("1_xpphu")
|
||||
SpawnRate = 0.05
|
||||
BonusAttack = 0
|
||||
BonusDefense = 6
|
||||
BonusLuck = 0.05
|
||||
AeolicResistance = 0
|
||||
TelluricResistance = 0
|
||||
HydricResistance = 0
|
||||
IgneousResistance = 0
|
||||
FerrumResistance = 0
|
||||
ThrowSpeed = 12.0
|
||||
IncreaseMaxHPAmount = 0
|
||||
IncreaseMaxVTAmount = 0
|
||||
ThrowDamage = 5
|
||||
ItemTag = 0
|
||||
Texture = ExtResource("1_xpphu")
|
||||
|
||||
@@ -1,17 +1,29 @@
|
||||
[gd_resource type="Resource" script_class="ArmorStats" load_steps=3 format=3 uid="uid://dq4c6an78qa4q"]
|
||||
|
||||
[ext_resource type="Script" path="res://src/items/armor/ArmorStats.cs" id="1_bkpin"]
|
||||
[ext_resource type="Script" uid="uid://dqtp6ewvttoyu" path="res://src/items/armor/ArmorStats.cs" id="1_bkpin"]
|
||||
[ext_resource type="Texture2D" uid="uid://dghvd33w32q63" path="res://src/items/armor/textures/WOODEN.PNG" id="1_vs6ua"]
|
||||
|
||||
[resource]
|
||||
script = ExtResource("1_bkpin")
|
||||
Defense = 3
|
||||
TelluricResistance = 0.0
|
||||
AeolicResistance = 0.0
|
||||
HydricResistance = 0.0
|
||||
IgneousResistance = 0.0
|
||||
FerrumResistance = 0.0
|
||||
_telluricResistance = 0.0
|
||||
_aeolicResistance = 0.0
|
||||
_hydricResistance = 0.0
|
||||
_igneousResistance = 0.0
|
||||
_ferrumResistance = 0.0
|
||||
Name = "Wooden Armament"
|
||||
Description = "+3 DEF"
|
||||
Texture = ExtResource("1_vs6ua")
|
||||
SpawnRate = 0.3
|
||||
BonusAttack = 0
|
||||
BonusDefense = 3
|
||||
BonusLuck = 0.05
|
||||
AeolicResistance = 0
|
||||
TelluricResistance = 0
|
||||
HydricResistance = 0
|
||||
IgneousResistance = 0
|
||||
FerrumResistance = 0
|
||||
ThrowSpeed = 12.0
|
||||
IncreaseMaxHPAmount = 0
|
||||
IncreaseMaxVTAmount = 0
|
||||
ThrowDamage = 5
|
||||
ItemTag = 0
|
||||
Texture = ExtResource("1_vs6ua")
|
||||
|
||||
@@ -1,16 +1,29 @@
|
||||
[gd_resource type="Resource" script_class="ConsumableItemStats" load_steps=3 format=3 uid="uid://d0cxrf0nldona"]
|
||||
|
||||
[ext_resource type="Texture2D" uid="uid://ttmu3vttq8yo" path="res://src/items/consumable/textures/amrit shard.PNG" id="1_f1n30"]
|
||||
[ext_resource type="Script" path="res://src/items/consumable/ConsumableItemStats.cs" id="2_riwik"]
|
||||
[ext_resource type="Script" uid="uid://cymeea1n4f04i" path="res://src/items/consumable/ConsumableItemStats.cs" id="2_riwik"]
|
||||
|
||||
[resource]
|
||||
script = ExtResource("2_riwik")
|
||||
HealHPAmount = 60
|
||||
RaiseHPAmount = 16
|
||||
HealVTAmount = 0
|
||||
RaiseVTAmount = 0
|
||||
PermanentRaiseHPAmount = 16
|
||||
PermanentRaiseVTAmount = 0
|
||||
Name = "Amrit Shard"
|
||||
Description = "A droplet of the heavenly elixir, frozen in time.
|
||||
Restores 60 HP. If HP full, raises MAX HP by 16."
|
||||
Texture = ExtResource("1_f1n30")
|
||||
SpawnRate = 0.05
|
||||
BonusAttack = 0
|
||||
BonusDefense = 0
|
||||
BonusLuck = 0.05
|
||||
BonusHP = 0
|
||||
BonusVT = 0
|
||||
AeolicResistance = 0
|
||||
TelluricResistance = 0
|
||||
HydricResistance = 0
|
||||
IgneousResistance = 0
|
||||
FerrumResistance = 0
|
||||
ThrowSpeed = 12.0
|
||||
ThrowDamage = 5
|
||||
ItemTag = 0
|
||||
Texture = ExtResource("1_f1n30")
|
||||
|
||||
@@ -1,15 +1,28 @@
|
||||
[gd_resource type="Resource" script_class="ConsumableItemStats" load_steps=3 format=3 uid="uid://dns281deffo6q"]
|
||||
|
||||
[ext_resource type="Texture2D" uid="uid://bg47n2tmintm0" path="res://src/items/consumable/textures/past self remnant.PNG" id="1_rc8t1"]
|
||||
[ext_resource type="Script" path="res://src/items/consumable/ConsumableItemStats.cs" id="2_e61q8"]
|
||||
[ext_resource type="Script" uid="uid://cymeea1n4f04i" path="res://src/items/consumable/ConsumableItemStats.cs" id="2_e61q8"]
|
||||
|
||||
[resource]
|
||||
script = ExtResource("2_e61q8")
|
||||
HealHPAmount = 1000
|
||||
RaiseHPAmount = 25
|
||||
HealHPAmount = 999
|
||||
HealVTAmount = 0
|
||||
RaiseVTAmount = 0
|
||||
PermanentRaiseHPAmount = 25
|
||||
PermanentRaiseVTAmount = 0
|
||||
Name = "Past Self's Fragment"
|
||||
Description = "Restores all HP. If HP full, raises MAX HP by 25."
|
||||
Texture = ExtResource("1_rc8t1")
|
||||
SpawnRate = 0.05
|
||||
BonusAttack = 0
|
||||
BonusDefense = 0
|
||||
BonusLuck = 0.05
|
||||
BonusHP = 0
|
||||
BonusVT = 0
|
||||
AeolicResistance = 0
|
||||
TelluricResistance = 0
|
||||
HydricResistance = 0
|
||||
IgneousResistance = 0
|
||||
FerrumResistance = 0
|
||||
ThrowSpeed = 12.0
|
||||
ThrowDamage = 5
|
||||
ItemTag = 0
|
||||
Texture = ExtResource("1_rc8t1")
|
||||
|
||||
@@ -1,15 +1,28 @@
|
||||
[gd_resource type="Resource" script_class="ConsumableItemStats" load_steps=3 format=3 uid="uid://bnec53frgyue8"]
|
||||
|
||||
[ext_resource type="Texture2D" uid="uid://cj0x1u7rknrvy" path="res://src/items/consumable/textures/past self spirit.PNG" id="1_jx43p"]
|
||||
[ext_resource type="Script" path="res://src/items/consumable/ConsumableItemStats.cs" id="2_wmtl1"]
|
||||
[ext_resource type="Script" uid="uid://cymeea1n4f04i" path="res://src/items/consumable/ConsumableItemStats.cs" id="2_wmtl1"]
|
||||
|
||||
[resource]
|
||||
script = ExtResource("2_wmtl1")
|
||||
HealHPAmount = 0
|
||||
RaiseHPAmount = 0
|
||||
HealVTAmount = 1000
|
||||
RaiseVTAmount = 20
|
||||
PermanentRaiseHPAmount = 0
|
||||
PermanentRaiseVTAmount = 20
|
||||
Name = "Past Self's Spirit"
|
||||
Description = "Restores all VT. If VT full, raises MAX VT by 20."
|
||||
Texture = ExtResource("1_jx43p")
|
||||
SpawnRate = 0.05
|
||||
BonusAttack = 0
|
||||
BonusDefense = 0
|
||||
BonusLuck = 0.05
|
||||
BonusHP = 0
|
||||
BonusVT = 0
|
||||
AeolicResistance = 0
|
||||
TelluricResistance = 0
|
||||
HydricResistance = 0
|
||||
IgneousResistance = 0
|
||||
FerrumResistance = 0
|
||||
ThrowSpeed = 12.0
|
||||
ThrowDamage = 5
|
||||
ItemTag = 0
|
||||
Texture = ExtResource("1_jx43p")
|
||||
|
||||
@@ -1,16 +1,29 @@
|
||||
[gd_resource type="Resource" script_class="ConsumableItemStats" load_steps=3 format=3 uid="uid://75fpkwfp0t0k"]
|
||||
|
||||
[ext_resource type="Script" path="res://src/items/consumable/ConsumableItemStats.cs" id="1_f8ogj"]
|
||||
[ext_resource type="Script" uid="uid://cymeea1n4f04i" path="res://src/items/consumable/ConsumableItemStats.cs" id="1_f8ogj"]
|
||||
[ext_resource type="Texture2D" uid="uid://dbl5v5i1s3m2u" path="res://src/items/consumable/textures/stelo fragment.PNG" id="1_ic5xm"]
|
||||
|
||||
[resource]
|
||||
script = ExtResource("1_f8ogj")
|
||||
HealHPAmount = 0
|
||||
RaiseHPAmount = 0
|
||||
HealVTAmount = 30
|
||||
RaiseVTAmount = 10
|
||||
PermanentRaiseHPAmount = 0
|
||||
PermanentRaiseVTAmount = 10
|
||||
Name = "Stelo Fragment"
|
||||
Description = "A small gathered piece of the former heavens.
|
||||
Restores 30 VT. If VT full, raises MAX VT by 10."
|
||||
Texture = ExtResource("1_ic5xm")
|
||||
SpawnRate = 0.5
|
||||
BonusAttack = 0
|
||||
BonusDefense = 0
|
||||
BonusLuck = 0.05
|
||||
BonusHP = 0
|
||||
BonusVT = 0
|
||||
AeolicResistance = 0
|
||||
TelluricResistance = 0
|
||||
HydricResistance = 0
|
||||
IgneousResistance = 0
|
||||
FerrumResistance = 0
|
||||
ThrowSpeed = 12.0
|
||||
ThrowDamage = 5
|
||||
ItemTag = 0
|
||||
Texture = ExtResource("1_ic5xm")
|
||||
|
||||
@@ -1,16 +1,29 @@
|
||||
[gd_resource type="Resource" script_class="ConsumableItemStats" load_steps=3 format=3 uid="uid://ypw2yg10430p"]
|
||||
|
||||
[ext_resource type="Texture2D" uid="uid://bqyjjdgub6iem" path="res://src/items/consumable/textures/suna fragment.PNG" id="1_ldd10"]
|
||||
[ext_resource type="Script" path="res://src/items/consumable/ConsumableItemStats.cs" id="2_41hue"]
|
||||
[ext_resource type="Script" uid="uid://cymeea1n4f04i" path="res://src/items/consumable/ConsumableItemStats.cs" id="2_41hue"]
|
||||
|
||||
[resource]
|
||||
script = ExtResource("2_41hue")
|
||||
HealHPAmount = 0
|
||||
RaiseHPAmount = 0
|
||||
HealVTAmount = 60
|
||||
RaiseVTAmount = 20
|
||||
PermanentRaiseHPAmount = 0
|
||||
PermanentRaiseVTAmount = 20
|
||||
Name = "Suna Fragment"
|
||||
Description = "A large gathered piece of the former heavens.
|
||||
Restores 60 VT. If VT full, raises MAX VT by 20."
|
||||
Texture = ExtResource("1_ldd10")
|
||||
SpawnRate = 0.1
|
||||
BonusAttack = 0
|
||||
BonusDefense = 0
|
||||
BonusLuck = 0.05
|
||||
BonusHP = 0
|
||||
BonusVT = 0
|
||||
AeolicResistance = 0
|
||||
TelluricResistance = 0
|
||||
HydricResistance = 0
|
||||
IgneousResistance = 0
|
||||
FerrumResistance = 0
|
||||
ThrowSpeed = 12.0
|
||||
ThrowDamage = 5
|
||||
ItemTag = 0
|
||||
Texture = ExtResource("1_ldd10")
|
||||
|
||||
@@ -1,16 +1,29 @@
|
||||
[gd_resource type="Resource" script_class="ConsumableItemStats" load_steps=3 format=3 uid="uid://lu0ddu3538p6"]
|
||||
|
||||
[ext_resource type="Texture2D" uid="uid://dw06kkltgk3sv" path="res://src/items/consumable/textures/ydunic fragment.PNG" id="1_4llax"]
|
||||
[ext_resource type="Script" path="res://src/items/consumable/ConsumableItemStats.cs" id="2_q4pyq"]
|
||||
[ext_resource type="Script" uid="uid://cymeea1n4f04i" path="res://src/items/consumable/ConsumableItemStats.cs" id="2_q4pyq"]
|
||||
|
||||
[resource]
|
||||
script = ExtResource("2_q4pyq")
|
||||
HealHPAmount = 30
|
||||
RaiseHPAmount = 8
|
||||
HealVTAmount = 0
|
||||
RaiseVTAmount = 0
|
||||
HealVTAmount = 8
|
||||
PermanentRaiseHPAmount = 0
|
||||
PermanentRaiseVTAmount = 0
|
||||
Name = "Ydunic Shard"
|
||||
Description = "A fragment of the divine fruit, frozen in time.
|
||||
Restores 30 HP. If HP full, raises MAX HP by 8."
|
||||
Texture = ExtResource("1_4llax")
|
||||
SpawnRate = 0.1
|
||||
BonusAttack = 0
|
||||
BonusDefense = 0
|
||||
BonusLuck = 0.05
|
||||
BonusHP = 0
|
||||
BonusVT = 0
|
||||
AeolicResistance = 0
|
||||
TelluricResistance = 0
|
||||
HydricResistance = 0
|
||||
IgneousResistance = 0
|
||||
FerrumResistance = 0
|
||||
ThrowSpeed = 12.0
|
||||
ThrowDamage = 5
|
||||
ItemTag = 0
|
||||
Texture = ExtResource("1_4llax")
|
||||
|
||||
@@ -5,9 +5,8 @@
|
||||
|
||||
[resource]
|
||||
script = ExtResource("1_ewck5")
|
||||
Name = "Geomantic Dice"
|
||||
Description = "Inflicts base damage when thrown.
|
||||
Use item to change Affinity."
|
||||
HealHPAmount = 10
|
||||
HealVTAmount = 5
|
||||
ThrowableItemTag = 3
|
||||
ElementType = 0
|
||||
UsableItemTag = 0
|
||||
@@ -17,9 +16,17 @@ Name = "Geomantic Dice"
|
||||
Description = "Inflicts base damage when thrown.
|
||||
Use item to change Affinity."
|
||||
SpawnRate = 1.0
|
||||
BonusAttack = 0
|
||||
BonusDefense = 0
|
||||
BonusLuck = 0.05
|
||||
BonusHP = 0
|
||||
BonusVT = 0
|
||||
AeolicResistance = 0
|
||||
TelluricResistance = 0
|
||||
HydricResistance = 0
|
||||
IgneousResistance = 0
|
||||
FerrumResistance = 0
|
||||
ThrowSpeed = 20.0
|
||||
HealHPAmount = 0
|
||||
HealVTAmount = 0
|
||||
ThrowDamage = 20
|
||||
ItemTag = 0
|
||||
Texture = ExtResource("1_jhits")
|
||||
|
||||
@@ -5,9 +5,9 @@
|
||||
|
||||
[resource]
|
||||
script = ExtResource("2_m680r")
|
||||
Name = "Gospel of Dimension"
|
||||
Description = "Teleports target to a random location."
|
||||
ThrowableItemTag = 0
|
||||
HealHPAmount = 0
|
||||
HealVTAmount = 0
|
||||
ThrowableItemTag = 4
|
||||
ElementType = 0
|
||||
UsableItemTag = 0
|
||||
MinimumCount = 1
|
||||
@@ -15,9 +15,17 @@ MaximumCount = 8
|
||||
Name = "Gospel of Dimension"
|
||||
Description = "Teleports target to a random location."
|
||||
SpawnRate = 0.1
|
||||
BonusAttack = 0
|
||||
BonusDefense = 0
|
||||
BonusLuck = 0.05
|
||||
AeolicResistance = 0
|
||||
TelluricResistance = 0
|
||||
HydricResistance = 0
|
||||
IgneousResistance = 0
|
||||
FerrumResistance = 0
|
||||
ThrowSpeed = 20.0
|
||||
HealHPAmount = 0
|
||||
HealVTAmount = 0
|
||||
IncreaseMaxHPAmount = 0
|
||||
IncreaseMaxVTAmount = 0
|
||||
ThrowDamage = 20
|
||||
ItemTag = 0
|
||||
Texture = ExtResource("1_xt2mp")
|
||||
|
||||
@@ -5,17 +5,27 @@
|
||||
|
||||
[resource]
|
||||
script = ExtResource("1_s3pq7")
|
||||
Name = "Spell Sign: Knowledge"
|
||||
Description = "Doubles experience points earned. Effect is temporary."
|
||||
HealHPAmount = 8
|
||||
HealVTAmount = 3
|
||||
ThrowableItemTag = 1
|
||||
ElementType = 0
|
||||
UsableItemTag = 0
|
||||
MinimumCount = 1
|
||||
MaximumCount = 8
|
||||
Name = "Spell Sign: Knowledge"
|
||||
Description = "Doubles experience points earned. Effect is temporary."
|
||||
SpawnRate = 0.1
|
||||
BonusAttack = 0
|
||||
BonusDefense = 0
|
||||
BonusLuck = 0.05
|
||||
BonusHP = 0
|
||||
BonusVT = 0
|
||||
AeolicResistance = 0
|
||||
TelluricResistance = 0
|
||||
HydricResistance = 0
|
||||
IgneousResistance = 0
|
||||
FerrumResistance = 0
|
||||
ThrowSpeed = 12.0
|
||||
HealHPAmount = 0
|
||||
HealVTAmount = 0
|
||||
ThrowDamage = 5
|
||||
ItemTag = 0
|
||||
Texture = ExtResource("1_3605p")
|
||||
|
||||
@@ -80,7 +80,7 @@ unique_name_in_owner = true
|
||||
script = ExtResource("2_00xd7")
|
||||
FolderName = "SetAFloors"
|
||||
FloorOdds = Array[float]([0.0, 1.0])
|
||||
GoldSproingy = 1.0
|
||||
Sproingy = 1.0
|
||||
|
||||
[node name="Overworld" type="Node" parent="MapOrder"]
|
||||
script = ExtResource("3_v14r0")
|
||||
|
||||
@@ -26,6 +26,8 @@ public partial class MainMenu : Control, IMainMenu
|
||||
|
||||
[Node] public IButton GalleryButton { get; set; } = default!;
|
||||
|
||||
[Node] public IButton OptionsButton { get; set; } = default!;
|
||||
|
||||
[Node] public IButton QuitButton { get; set; } = default!;
|
||||
|
||||
[Signal]
|
||||
@@ -35,6 +37,8 @@ public partial class MainMenu : Control, IMainMenu
|
||||
[Signal]
|
||||
public delegate void GalleryEventHandler();
|
||||
[Signal]
|
||||
public delegate void OptionsEventHandler();
|
||||
[Signal]
|
||||
public delegate void QuitEventHandler();
|
||||
|
||||
public void OnReady()
|
||||
@@ -42,6 +46,7 @@ public partial class MainMenu : Control, IMainMenu
|
||||
StartGameButton.Pressed += OnStartGamePressed;
|
||||
EnemyViewerButton.Pressed += EnemyViewerButton_Pressed;
|
||||
GalleryButton.Pressed += GalleryButton_Pressed;
|
||||
OptionsButton.Pressed += OptionsButton_Pressed;
|
||||
QuitButton.Pressed += OnQuitPressed;
|
||||
StartGameButton.GrabFocus();
|
||||
}
|
||||
@@ -57,6 +62,7 @@ public partial class MainMenu : Control, IMainMenu
|
||||
StartGameButton.Pressed -= OnStartGamePressed;
|
||||
EnemyViewerButton.Pressed -= EnemyViewerButton_Pressed;
|
||||
GalleryButton.Pressed -= GalleryButton_Pressed;
|
||||
OptionsButton.Pressed -= OptionsButton_Pressed;
|
||||
QuitButton.Pressed -= OnQuitPressed;
|
||||
}
|
||||
|
||||
@@ -66,5 +72,7 @@ public partial class MainMenu : Control, IMainMenu
|
||||
|
||||
private void EnemyViewerButton_Pressed() => EmitSignal(SignalName.EnemyViewer);
|
||||
|
||||
private void OptionsButton_Pressed() => EmitSignal(SignalName.Options);
|
||||
|
||||
public void OnQuitPressed() => EmitSignal(SignalName.Quit);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
[gd_scene load_steps=2 format=3 uid="uid://rfvnddfqufho"]
|
||||
[gd_scene load_steps=3 format=3 uid="uid://rfvnddfqufho"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://14b7o2c6cgry" path="res://src/menu/MainMenu.cs" id="1_y6722"]
|
||||
[ext_resource type="Shortcut" uid="uid://dumkrjur22k2a" path="res://src/ui/ButtonShortcut.tres" id="2_7fwjx"]
|
||||
|
||||
[node name="MainMenu" type="Control"]
|
||||
layout_mode = 3
|
||||
@@ -27,7 +28,6 @@ anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
mouse_filter = 0
|
||||
theme_override_constants/margin_left = 100
|
||||
theme_override_constants/margin_top = 100
|
||||
theme_override_constants/margin_right = 100
|
||||
@@ -37,33 +37,56 @@ theme_override_constants/margin_bottom = 100
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 0
|
||||
size_flags_vertical = 0
|
||||
mouse_filter = 0
|
||||
|
||||
[node name="StartGameButton" type="Button" parent="MarginContainer/VBoxContainer"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
focus_neighbor_bottom = NodePath("../EnemyViewerButton")
|
||||
focus_next = NodePath("../EnemyViewerButton")
|
||||
theme_override_colors/font_focus_color = Color(0.976471, 0.827451, 0, 1)
|
||||
shortcut = ExtResource("2_7fwjx")
|
||||
text = "Start Game"
|
||||
|
||||
[node name="EnemyViewerButton" type="Button" parent="MarginContainer/VBoxContainer"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
focus_neighbor_bottom = NodePath("../GalleryButton")
|
||||
focus_next = NodePath("../GalleryButton")
|
||||
focus_previous = NodePath("../StartGameButton")
|
||||
theme_override_colors/font_focus_color = Color(0.976471, 0.827451, 0, 1)
|
||||
shortcut = ExtResource("2_7fwjx")
|
||||
text = "Enemy Viewer"
|
||||
|
||||
[node name="GalleryButton" type="Button" parent="MarginContainer/VBoxContainer"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
focus_neighbor_top = NodePath("../EnemyViewerButton")
|
||||
focus_neighbor_bottom = NodePath("../QuitButton")
|
||||
focus_neighbor_bottom = NodePath("../OptionsButton")
|
||||
focus_next = NodePath("../OptionsButton")
|
||||
focus_previous = NodePath("../EnemyViewerButton")
|
||||
theme_override_colors/font_focus_color = Color(0.976471, 0.827451, 0, 1)
|
||||
shortcut = ExtResource("2_7fwjx")
|
||||
text = "Gallery"
|
||||
|
||||
[node name="OptionsButton" type="Button" parent="MarginContainer/VBoxContainer"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
focus_neighbor_top = NodePath("../GalleryButton")
|
||||
focus_neighbor_bottom = NodePath("../QuitButton")
|
||||
focus_next = NodePath("../QuitButton")
|
||||
focus_previous = NodePath("../GalleryButton")
|
||||
theme_override_colors/font_focus_color = Color(0.976471, 0.827451, 0, 1)
|
||||
shortcut = ExtResource("2_7fwjx")
|
||||
text = "Options"
|
||||
|
||||
[node name="QuitButton" type="Button" parent="MarginContainer/VBoxContainer"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
focus_neighbor_top = NodePath("../GalleryButton")
|
||||
focus_neighbor_top = NodePath("../OptionsButton")
|
||||
focus_neighbor_bottom = NodePath(".")
|
||||
focus_next = NodePath(".")
|
||||
focus_previous = NodePath("../OptionsButton")
|
||||
theme_override_colors/font_focus_color = Color(0.976471, 0.827451, 0, 1)
|
||||
shortcut = ExtResource("2_7fwjx")
|
||||
text = "Quit
|
||||
"
|
||||
|
||||
19
Zennysoft.Game.Ma/src/options/InputMapButton.cs
Normal file
19
Zennysoft.Game.Ma/src/options/InputMapButton.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using Godot;
|
||||
|
||||
namespace Zennysoft.Game.Ma;
|
||||
|
||||
public abstract partial class InputMapButton : Button
|
||||
{
|
||||
[Signal] public delegate void RemapEventHandler(InputMapButton buttonBeingRemapped);
|
||||
|
||||
public string Action { get; set; }
|
||||
|
||||
public InputEvent InputEvent { get; set; }
|
||||
|
||||
public InputMapButton()
|
||||
{
|
||||
Pressed += RemapButton_Pressed;
|
||||
}
|
||||
|
||||
private void RemapButton_Pressed() => EmitSignal(SignalName.Remap, this);
|
||||
}
|
||||
1
Zennysoft.Game.Ma/src/options/InputMapButton.cs.uid
Normal file
1
Zennysoft.Game.Ma/src/options/InputMapButton.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://bhfrdlnv7xyf6
|
||||
191
Zennysoft.Game.Ma/src/options/InputMapper.cs
Normal file
191
Zennysoft.Game.Ma/src/options/InputMapper.cs
Normal file
@@ -0,0 +1,191 @@
|
||||
using Chickensoft.AutoInject;
|
||||
using Chickensoft.Introspection;
|
||||
using Godot;
|
||||
using NathanHoad;
|
||||
using SimpleInjector.Lifestyles;
|
||||
using System.Collections.Generic;
|
||||
using System.IO.Abstractions;
|
||||
using System.Linq;
|
||||
using Zennysoft.Game.Abstractions;
|
||||
using Zennysoft.Game.Implementation;
|
||||
|
||||
namespace Zennysoft.Game.Ma;
|
||||
|
||||
[Meta(typeof(IAutoNode))]
|
||||
public partial class InputMapper : PanelContainer
|
||||
{
|
||||
public override void _Notification(int what) => this.Notify(what);
|
||||
|
||||
[Node] public VBoxContainer ActionList { get; set; }
|
||||
|
||||
[Node] public KeyboardRemapButton MoveForwardKeyboard { get; set; }
|
||||
[Node] public JoypadRemapButton MoveForwardController { get; set; }
|
||||
[Node] public KeyboardRemapButton MoveLeftKeyboard { get; set; }
|
||||
[Node] public JoypadRemapButton MoveLeftController { get; set; }
|
||||
[Node] public KeyboardRemapButton MoveRightKeyboard { get; set; }
|
||||
[Node] public JoypadRemapButton MoveRightController { get; set; }
|
||||
[Node] public KeyboardRemapButton MoveBackwardKeyboard { get; set; }
|
||||
[Node] public JoypadRemapButton MoveBackwardController { get; set; }
|
||||
[Node] public KeyboardRemapButton StrafeLeftKeyboard { get; set; }
|
||||
[Node] public JoypadRemapButton StrafeLeftController { get; set; }
|
||||
[Node] public KeyboardRemapButton StrafeRightKeyboard { get; set; }
|
||||
[Node] public JoypadRemapButton StrafeRightController { get; set; }
|
||||
[Node] public KeyboardRemapButton AttackKeyboard { get; set; }
|
||||
[Node] public JoypadRemapButton AttackController { get; set; }
|
||||
[Node] public KeyboardRemapButton InteractKeyboard { get; set; }
|
||||
[Node] public JoypadRemapButton InteractController { get; set; }
|
||||
[Node] public KeyboardRemapButton InventoryKeyboard { get; set; }
|
||||
[Node] public JoypadRemapButton InventoryController { get; set; }
|
||||
[Node] public KeyboardRemapButton SortKeyboard { get; set; }
|
||||
[Node] public JoypadRemapButton SortController { get; set; }
|
||||
|
||||
private Button _remappingButton = null;
|
||||
private InputEvent _remappingAction = null;
|
||||
|
||||
private List<JoypadRemapButton> _actionJoyMap = [];
|
||||
private List<KeyboardRemapButton> _actionKeyMap = [];
|
||||
|
||||
private SimpleInjector.Container _container;
|
||||
private ISaveFileManager _saveFileManager;
|
||||
|
||||
[Signal] public delegate void SaveControllerInputEventHandler();
|
||||
|
||||
public void OnReady()
|
||||
{
|
||||
_container = new SimpleInjector.Container();
|
||||
_container.Options.DefaultScopedLifestyle = new AsyncScopedLifestyle();
|
||||
_container.RegisterSingleton<IFileSystem, FileSystem>();
|
||||
_container.RegisterSingleton<ISaveFileManager, SaveFileManager>();
|
||||
_saveFileManager = _container.GetInstance<ISaveFileManager>();
|
||||
|
||||
MoveForwardController.Action = GameInputs.MoveUp;
|
||||
MoveForwardKeyboard.Action = GameInputs.MoveUp;
|
||||
MoveLeftController.Action = GameInputs.MoveLeft;
|
||||
MoveLeftKeyboard.Action = GameInputs.MoveLeft;
|
||||
MoveRightController.Action = GameInputs.MoveRight;
|
||||
MoveRightKeyboard.Action = GameInputs.MoveRight;
|
||||
MoveBackwardController.Action = GameInputs.MoveDown;
|
||||
MoveBackwardKeyboard.Action = GameInputs.MoveDown;
|
||||
StrafeLeftController.Action = GameInputs.StrafeLeft;
|
||||
StrafeLeftKeyboard.Action = GameInputs.StrafeLeft;
|
||||
StrafeRightController.Action = GameInputs.StrafeRight;
|
||||
StrafeRightKeyboard.Action = GameInputs.StrafeRight;
|
||||
AttackController.Action = GameInputs.Attack;
|
||||
AttackKeyboard.Action = GameInputs.Attack;
|
||||
InteractController.Action = GameInputs.Interact;
|
||||
InteractKeyboard.Action = GameInputs.Interact;
|
||||
InventoryController.Action = GameInputs.Inventory;
|
||||
InventoryKeyboard.Action = GameInputs.Inventory;
|
||||
SortController.Action = GameInputs.InventorySort;
|
||||
SortKeyboard.Action = GameInputs.InventorySort;
|
||||
|
||||
_actionJoyMap.Add(MoveForwardController);
|
||||
_actionJoyMap.Add(MoveLeftController);
|
||||
_actionJoyMap.Add(MoveRightController);
|
||||
_actionJoyMap.Add(MoveBackwardController);
|
||||
_actionJoyMap.Add(StrafeLeftController);
|
||||
_actionJoyMap.Add(StrafeRightController);
|
||||
_actionJoyMap.Add(AttackController);
|
||||
_actionJoyMap.Add(InteractController);
|
||||
_actionJoyMap.Add(InventoryController);
|
||||
_actionJoyMap.Add(SortController);
|
||||
|
||||
_actionKeyMap.Add(MoveForwardKeyboard);
|
||||
_actionKeyMap.Add(MoveLeftKeyboard);
|
||||
_actionKeyMap.Add(MoveRightKeyboard);
|
||||
_actionKeyMap.Add(MoveBackwardKeyboard);
|
||||
_actionKeyMap.Add(StrafeLeftKeyboard);
|
||||
_actionKeyMap.Add(StrafeRightKeyboard);
|
||||
_actionKeyMap.Add(AttackKeyboard);
|
||||
_actionKeyMap.Add(InteractKeyboard);
|
||||
_actionKeyMap.Add(InventoryKeyboard);
|
||||
_actionKeyMap.Add(SortKeyboard);
|
||||
|
||||
MoveForwardKeyboard.Remap += OnRemap;
|
||||
MoveForwardController.Remap += OnRemap;
|
||||
MoveLeftKeyboard.Remap += OnRemap;
|
||||
MoveLeftController.Remap += OnRemap;
|
||||
MoveRightKeyboard.Remap += OnRemap;
|
||||
MoveRightController.Remap += OnRemap;
|
||||
MoveBackwardKeyboard.Remap += OnRemap;
|
||||
MoveBackwardController.Remap += OnRemap;
|
||||
StrafeLeftKeyboard.Remap += OnRemap;
|
||||
StrafeLeftController.Remap += OnRemap;
|
||||
StrafeRightKeyboard.Remap += OnRemap;
|
||||
StrafeRightController.Remap += OnRemap;
|
||||
AttackKeyboard.Remap += OnRemap;
|
||||
AttackController.Remap += OnRemap;
|
||||
InteractKeyboard.Remap += OnRemap;
|
||||
InteractController.Remap += OnRemap;
|
||||
InventoryKeyboard.Remap += OnRemap;
|
||||
InventoryController.Remap += OnRemap;
|
||||
SortKeyboard.Remap += OnRemap;
|
||||
SortController.Remap += OnRemap;
|
||||
|
||||
InputHelper.JoypadInputChanged += (string action, InputEvent input) =>
|
||||
{
|
||||
var buttonChanged = _actionJoyMap.SingleOrDefault(x => x.Action == action);
|
||||
if (buttonChanged != null)
|
||||
{
|
||||
buttonChanged.SetProcessInput(false);
|
||||
buttonChanged.Text = InputHelper.GetLabelForInput(input);
|
||||
}
|
||||
var allButtons = _actionKeyMap.Concat<InputMapButton>(_actionJoyMap);
|
||||
foreach (var button in allButtons)
|
||||
button.Disabled = false;
|
||||
};
|
||||
|
||||
InputHelper.KeyboardInputChanged += (string action, InputEvent input) =>
|
||||
{
|
||||
var buttonChanged = _actionKeyMap.SingleOrDefault(x => x.Action == action);
|
||||
if (buttonChanged != null)
|
||||
{
|
||||
buttonChanged.SetProcessInput(false);
|
||||
buttonChanged.Text = InputHelper.GetLabelForInput(input);
|
||||
}
|
||||
var allButtons = _actionKeyMap.Concat<InputMapButton>(_actionJoyMap);
|
||||
foreach (var button in allButtons)
|
||||
button.Disabled = false;
|
||||
};
|
||||
}
|
||||
|
||||
public void LoadControllerInput(string jsonData)
|
||||
{
|
||||
InputHelper.DeserializeInputsForActions(jsonData);
|
||||
InitializeButtonText();
|
||||
}
|
||||
|
||||
public void InitializeButtonText()
|
||||
{
|
||||
MoveForwardKeyboard.Text = InputHelper.GetLabelForInput(InputHelper.GetKeyboardInputForAction(GameInputs.MoveUp));
|
||||
MoveForwardController.Text = InputHelper.GetLabelForInput(InputHelper.GetJoypadInputForAction(GameInputs.MoveUp));
|
||||
MoveLeftKeyboard.Text = InputHelper.GetLabelForInput(InputHelper.GetKeyboardInputForAction(GameInputs.MoveLeft));
|
||||
MoveLeftController.Text = InputHelper.GetLabelForInput(InputHelper.GetJoypadInputForAction(GameInputs.MoveLeft));
|
||||
MoveRightKeyboard.Text = InputHelper.GetLabelForInput(InputHelper.GetKeyboardInputForAction(GameInputs.MoveRight));
|
||||
MoveRightController.Text = InputHelper.GetLabelForInput(InputHelper.GetJoypadInputForAction(GameInputs.MoveRight));
|
||||
MoveBackwardKeyboard.Text = InputHelper.GetLabelForInput(InputHelper.GetKeyboardInputForAction(GameInputs.MoveDown));
|
||||
MoveBackwardController.Text = InputHelper.GetLabelForInput(InputHelper.GetJoypadInputForAction(GameInputs.MoveDown));
|
||||
StrafeLeftKeyboard.Text = InputHelper.GetLabelForInput(InputHelper.GetKeyboardInputForAction(GameInputs.StrafeLeft));
|
||||
StrafeLeftController.Text = InputHelper.GetLabelForInput(InputHelper.GetJoypadInputForAction(GameInputs.StrafeLeft));
|
||||
StrafeRightKeyboard.Text = InputHelper.GetLabelForInput(InputHelper.GetKeyboardInputForAction(GameInputs.StrafeRight));
|
||||
StrafeRightController.Text = InputHelper.GetLabelForInput(InputHelper.GetJoypadInputForAction(GameInputs.StrafeRight));
|
||||
AttackKeyboard.Text = InputHelper.GetLabelForInput(InputHelper.GetKeyboardInputForAction(GameInputs.Attack));
|
||||
AttackController.Text = InputHelper.GetLabelForInput(InputHelper.GetJoypadInputForAction(GameInputs.Attack));
|
||||
InteractKeyboard.Text = InputHelper.GetLabelForInput(InputHelper.GetKeyboardInputForAction(GameInputs.Interact));
|
||||
InteractController.Text = InputHelper.GetLabelForInput(InputHelper.GetJoypadInputForAction(GameInputs.Interact));
|
||||
InventoryKeyboard.Text = InputHelper.GetLabelForInput(InputHelper.GetKeyboardInputForAction(GameInputs.Inventory));
|
||||
InventoryController.Text = InputHelper.GetLabelForInput(InputHelper.GetJoypadInputForAction(GameInputs.Inventory));
|
||||
SortKeyboard.Text = InputHelper.GetLabelForInput(InputHelper.GetKeyboardInputForAction(GameInputs.InventorySort));
|
||||
SortController.Text = InputHelper.GetLabelForInput(InputHelper.GetJoypadInputForAction(GameInputs.InventorySort));
|
||||
}
|
||||
|
||||
private void OnRemap(InputMapButton inputButton)
|
||||
{
|
||||
inputButton.Text = "...";
|
||||
inputButton.SetProcessInput(true);
|
||||
var allButtons = _actionKeyMap.Concat<InputMapButton>(_actionJoyMap);
|
||||
foreach (var button in allButtons)
|
||||
button.Disabled = true;
|
||||
ReleaseFocus();
|
||||
}
|
||||
}
|
||||
1
Zennysoft.Game.Ma/src/options/InputMapper.cs.uid
Normal file
1
Zennysoft.Game.Ma/src/options/InputMapper.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://c6lw5yp8p0wb5
|
||||
361
Zennysoft.Game.Ma/src/options/InputMapper.tscn
Normal file
361
Zennysoft.Game.Ma/src/options/InputMapper.tscn
Normal file
@@ -0,0 +1,361 @@
|
||||
[gd_scene load_steps=4 format=3 uid="uid://dk5esf6mm6kte"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://c6lw5yp8p0wb5" path="res://src/options/InputMapper.cs" id="1_rwvs3"]
|
||||
[ext_resource type="Script" uid="uid://b70br20xue678" path="res://src/options/KeyboardRemapButton.cs" id="2_fmxfy"]
|
||||
[ext_resource type="Script" uid="uid://bo7vk56h1lr07" path="res://src/options/JoypadRemapButton.cs" id="3_yis0i"]
|
||||
|
||||
[node name="InputMapper" type="PanelContainer"]
|
||||
anchors_preset = 8
|
||||
anchor_left = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -451.0
|
||||
offset_top = -451.0
|
||||
offset_right = 449.0
|
||||
offset_bottom = 449.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
script = ExtResource("1_rwvs3")
|
||||
|
||||
[node name="MarginContainer" type="MarginContainer" parent="."]
|
||||
layout_mode = 2
|
||||
mouse_filter = 0
|
||||
theme_override_constants/margin_left = 25
|
||||
theme_override_constants/margin_top = 25
|
||||
theme_override_constants/margin_right = 25
|
||||
theme_override_constants/margin_bottom = 25
|
||||
|
||||
[node name="VBoxContainer" type="VBoxContainer" parent="MarginContainer"]
|
||||
layout_mode = 2
|
||||
theme_override_constants/separation = 3
|
||||
|
||||
[node name="ScrollContainer" type="ScrollContainer" parent="MarginContainer/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
size_flags_vertical = 3
|
||||
|
||||
[node name="ActionList" type="VBoxContainer" parent="MarginContainer/VBoxContainer/ScrollContainer"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 3
|
||||
theme_override_constants/separation = 10
|
||||
|
||||
[node name="Header" type="HBoxContainer" parent="MarginContainer/VBoxContainer/ScrollContainer/ActionList"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Label" type="Label" parent="MarginContainer/VBoxContainer/ScrollContainer/ActionList/Header"]
|
||||
custom_minimum_size = Vector2(200, 0)
|
||||
layout_mode = 2
|
||||
text = "Actions"
|
||||
horizontal_alignment = 2
|
||||
|
||||
[node name="Control" type="Control" parent="MarginContainer/VBoxContainer/ScrollContainer/ActionList/Header"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
|
||||
[node name="Label2" type="Label" parent="MarginContainer/VBoxContainer/ScrollContainer/ActionList/Header"]
|
||||
custom_minimum_size = Vector2(200, 0)
|
||||
layout_mode = 2
|
||||
text = "Keyboard"
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="Control2" type="Control" parent="MarginContainer/VBoxContainer/ScrollContainer/ActionList/Header"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
|
||||
[node name="Label3" type="Label" parent="MarginContainer/VBoxContainer/ScrollContainer/ActionList/Header"]
|
||||
custom_minimum_size = Vector2(200, 0)
|
||||
layout_mode = 2
|
||||
text = "Controller"
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="Move Forward" type="HBoxContainer" parent="MarginContainer/VBoxContainer/ScrollContainer/ActionList"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Label" type="Label" parent="MarginContainer/VBoxContainer/ScrollContainer/ActionList/Move Forward"]
|
||||
custom_minimum_size = Vector2(200, 0)
|
||||
layout_mode = 2
|
||||
text = "Move Forward"
|
||||
horizontal_alignment = 2
|
||||
|
||||
[node name="Control" type="Control" parent="MarginContainer/VBoxContainer/ScrollContainer/ActionList/Move Forward"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
|
||||
[node name="MoveForwardKeyboard" type="Button" parent="MarginContainer/VBoxContainer/ScrollContainer/ActionList/Move Forward"]
|
||||
unique_name_in_owner = true
|
||||
custom_minimum_size = Vector2(200, 35)
|
||||
layout_mode = 2
|
||||
script = ExtResource("2_fmxfy")
|
||||
|
||||
[node name="Control2" type="Control" parent="MarginContainer/VBoxContainer/ScrollContainer/ActionList/Move Forward"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
|
||||
[node name="MoveForwardController" type="Button" parent="MarginContainer/VBoxContainer/ScrollContainer/ActionList/Move Forward"]
|
||||
unique_name_in_owner = true
|
||||
custom_minimum_size = Vector2(200, 0)
|
||||
layout_mode = 2
|
||||
script = ExtResource("3_yis0i")
|
||||
|
||||
[node name="Move Left" type="HBoxContainer" parent="MarginContainer/VBoxContainer/ScrollContainer/ActionList"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Label" type="Label" parent="MarginContainer/VBoxContainer/ScrollContainer/ActionList/Move Left"]
|
||||
custom_minimum_size = Vector2(200, 0)
|
||||
layout_mode = 2
|
||||
text = "Move Left"
|
||||
horizontal_alignment = 2
|
||||
|
||||
[node name="Control" type="Control" parent="MarginContainer/VBoxContainer/ScrollContainer/ActionList/Move Left"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
|
||||
[node name="MoveLeftKeyboard" type="Button" parent="MarginContainer/VBoxContainer/ScrollContainer/ActionList/Move Left"]
|
||||
unique_name_in_owner = true
|
||||
custom_minimum_size = Vector2(200, 35)
|
||||
layout_mode = 2
|
||||
script = ExtResource("2_fmxfy")
|
||||
|
||||
[node name="Control2" type="Control" parent="MarginContainer/VBoxContainer/ScrollContainer/ActionList/Move Left"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
|
||||
[node name="MoveLeftController" type="Button" parent="MarginContainer/VBoxContainer/ScrollContainer/ActionList/Move Left"]
|
||||
unique_name_in_owner = true
|
||||
custom_minimum_size = Vector2(200, 0)
|
||||
layout_mode = 2
|
||||
script = ExtResource("3_yis0i")
|
||||
|
||||
[node name="Move Right" type="HBoxContainer" parent="MarginContainer/VBoxContainer/ScrollContainer/ActionList"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Label" type="Label" parent="MarginContainer/VBoxContainer/ScrollContainer/ActionList/Move Right"]
|
||||
custom_minimum_size = Vector2(200, 0)
|
||||
layout_mode = 2
|
||||
text = "Move Right"
|
||||
horizontal_alignment = 2
|
||||
|
||||
[node name="Control" type="Control" parent="MarginContainer/VBoxContainer/ScrollContainer/ActionList/Move Right"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
|
||||
[node name="MoveRightKeyboard" type="Button" parent="MarginContainer/VBoxContainer/ScrollContainer/ActionList/Move Right"]
|
||||
unique_name_in_owner = true
|
||||
custom_minimum_size = Vector2(200, 35)
|
||||
layout_mode = 2
|
||||
script = ExtResource("2_fmxfy")
|
||||
|
||||
[node name="Control2" type="Control" parent="MarginContainer/VBoxContainer/ScrollContainer/ActionList/Move Right"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
|
||||
[node name="MoveRightController" type="Button" parent="MarginContainer/VBoxContainer/ScrollContainer/ActionList/Move Right"]
|
||||
unique_name_in_owner = true
|
||||
custom_minimum_size = Vector2(200, 0)
|
||||
layout_mode = 2
|
||||
script = ExtResource("3_yis0i")
|
||||
|
||||
[node name="Move Backward" type="HBoxContainer" parent="MarginContainer/VBoxContainer/ScrollContainer/ActionList"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Label" type="Label" parent="MarginContainer/VBoxContainer/ScrollContainer/ActionList/Move Backward"]
|
||||
custom_minimum_size = Vector2(200, 0)
|
||||
layout_mode = 2
|
||||
text = "Move Backward"
|
||||
horizontal_alignment = 2
|
||||
|
||||
[node name="Control" type="Control" parent="MarginContainer/VBoxContainer/ScrollContainer/ActionList/Move Backward"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
|
||||
[node name="MoveBackwardKeyboard" type="Button" parent="MarginContainer/VBoxContainer/ScrollContainer/ActionList/Move Backward"]
|
||||
unique_name_in_owner = true
|
||||
custom_minimum_size = Vector2(200, 0)
|
||||
layout_mode = 2
|
||||
script = ExtResource("2_fmxfy")
|
||||
|
||||
[node name="Control2" type="Control" parent="MarginContainer/VBoxContainer/ScrollContainer/ActionList/Move Backward"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
|
||||
[node name="MoveBackwardController" type="Button" parent="MarginContainer/VBoxContainer/ScrollContainer/ActionList/Move Backward"]
|
||||
unique_name_in_owner = true
|
||||
custom_minimum_size = Vector2(200, 0)
|
||||
layout_mode = 2
|
||||
script = ExtResource("3_yis0i")
|
||||
|
||||
[node name="Strafe Left" type="HBoxContainer" parent="MarginContainer/VBoxContainer/ScrollContainer/ActionList"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Label" type="Label" parent="MarginContainer/VBoxContainer/ScrollContainer/ActionList/Strafe Left"]
|
||||
custom_minimum_size = Vector2(200, 0)
|
||||
layout_mode = 2
|
||||
text = "Strafe Left"
|
||||
horizontal_alignment = 2
|
||||
|
||||
[node name="Control" type="Control" parent="MarginContainer/VBoxContainer/ScrollContainer/ActionList/Strafe Left"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
|
||||
[node name="StrafeLeftKeyboard" type="Button" parent="MarginContainer/VBoxContainer/ScrollContainer/ActionList/Strafe Left"]
|
||||
unique_name_in_owner = true
|
||||
custom_minimum_size = Vector2(200, 0)
|
||||
layout_mode = 2
|
||||
script = ExtResource("2_fmxfy")
|
||||
|
||||
[node name="Control2" type="Control" parent="MarginContainer/VBoxContainer/ScrollContainer/ActionList/Strafe Left"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
|
||||
[node name="StrafeLeftController" type="Button" parent="MarginContainer/VBoxContainer/ScrollContainer/ActionList/Strafe Left"]
|
||||
unique_name_in_owner = true
|
||||
custom_minimum_size = Vector2(200, 0)
|
||||
layout_mode = 2
|
||||
script = ExtResource("3_yis0i")
|
||||
|
||||
[node name="Strafe Right" type="HBoxContainer" parent="MarginContainer/VBoxContainer/ScrollContainer/ActionList"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Label" type="Label" parent="MarginContainer/VBoxContainer/ScrollContainer/ActionList/Strafe Right"]
|
||||
custom_minimum_size = Vector2(200, 0)
|
||||
layout_mode = 2
|
||||
text = "Strafe Right"
|
||||
horizontal_alignment = 2
|
||||
|
||||
[node name="Control" type="Control" parent="MarginContainer/VBoxContainer/ScrollContainer/ActionList/Strafe Right"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
|
||||
[node name="StrafeRightKeyboard" type="Button" parent="MarginContainer/VBoxContainer/ScrollContainer/ActionList/Strafe Right"]
|
||||
unique_name_in_owner = true
|
||||
custom_minimum_size = Vector2(200, 0)
|
||||
layout_mode = 2
|
||||
script = ExtResource("2_fmxfy")
|
||||
|
||||
[node name="Control2" type="Control" parent="MarginContainer/VBoxContainer/ScrollContainer/ActionList/Strafe Right"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
|
||||
[node name="StrafeRightController" type="Button" parent="MarginContainer/VBoxContainer/ScrollContainer/ActionList/Strafe Right"]
|
||||
unique_name_in_owner = true
|
||||
custom_minimum_size = Vector2(200, 0)
|
||||
layout_mode = 2
|
||||
script = ExtResource("3_yis0i")
|
||||
|
||||
[node name="Attack" type="HBoxContainer" parent="MarginContainer/VBoxContainer/ScrollContainer/ActionList"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Label" type="Label" parent="MarginContainer/VBoxContainer/ScrollContainer/ActionList/Attack"]
|
||||
custom_minimum_size = Vector2(200, 0)
|
||||
layout_mode = 2
|
||||
text = "Attack"
|
||||
horizontal_alignment = 2
|
||||
|
||||
[node name="Control" type="Control" parent="MarginContainer/VBoxContainer/ScrollContainer/ActionList/Attack"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
|
||||
[node name="AttackKeyboard" type="Button" parent="MarginContainer/VBoxContainer/ScrollContainer/ActionList/Attack"]
|
||||
unique_name_in_owner = true
|
||||
custom_minimum_size = Vector2(200, 35)
|
||||
layout_mode = 2
|
||||
script = ExtResource("2_fmxfy")
|
||||
|
||||
[node name="Control2" type="Control" parent="MarginContainer/VBoxContainer/ScrollContainer/ActionList/Attack"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
|
||||
[node name="AttackController" type="Button" parent="MarginContainer/VBoxContainer/ScrollContainer/ActionList/Attack"]
|
||||
unique_name_in_owner = true
|
||||
custom_minimum_size = Vector2(200, 0)
|
||||
layout_mode = 2
|
||||
script = ExtResource("3_yis0i")
|
||||
|
||||
[node name="Interact" type="HBoxContainer" parent="MarginContainer/VBoxContainer/ScrollContainer/ActionList"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Label" type="Label" parent="MarginContainer/VBoxContainer/ScrollContainer/ActionList/Interact"]
|
||||
custom_minimum_size = Vector2(200, 0)
|
||||
layout_mode = 2
|
||||
text = "Interact"
|
||||
horizontal_alignment = 2
|
||||
|
||||
[node name="Control" type="Control" parent="MarginContainer/VBoxContainer/ScrollContainer/ActionList/Interact"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
|
||||
[node name="InteractKeyboard" type="Button" parent="MarginContainer/VBoxContainer/ScrollContainer/ActionList/Interact"]
|
||||
unique_name_in_owner = true
|
||||
custom_minimum_size = Vector2(200, 35)
|
||||
layout_mode = 2
|
||||
script = ExtResource("2_fmxfy")
|
||||
|
||||
[node name="Control2" type="Control" parent="MarginContainer/VBoxContainer/ScrollContainer/ActionList/Interact"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
|
||||
[node name="InteractController" type="Button" parent="MarginContainer/VBoxContainer/ScrollContainer/ActionList/Interact"]
|
||||
unique_name_in_owner = true
|
||||
custom_minimum_size = Vector2(200, 0)
|
||||
layout_mode = 2
|
||||
script = ExtResource("3_yis0i")
|
||||
|
||||
[node name="Open Inventory" type="HBoxContainer" parent="MarginContainer/VBoxContainer/ScrollContainer/ActionList"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Label" type="Label" parent="MarginContainer/VBoxContainer/ScrollContainer/ActionList/Open Inventory"]
|
||||
custom_minimum_size = Vector2(200, 0)
|
||||
layout_mode = 2
|
||||
text = "Open Inventory"
|
||||
horizontal_alignment = 2
|
||||
|
||||
[node name="Control" type="Control" parent="MarginContainer/VBoxContainer/ScrollContainer/ActionList/Open Inventory"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
|
||||
[node name="InventoryKeyboard" type="Button" parent="MarginContainer/VBoxContainer/ScrollContainer/ActionList/Open Inventory"]
|
||||
unique_name_in_owner = true
|
||||
custom_minimum_size = Vector2(200, 35)
|
||||
layout_mode = 2
|
||||
script = ExtResource("2_fmxfy")
|
||||
|
||||
[node name="Control2" type="Control" parent="MarginContainer/VBoxContainer/ScrollContainer/ActionList/Open Inventory"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
|
||||
[node name="InventoryController" type="Button" parent="MarginContainer/VBoxContainer/ScrollContainer/ActionList/Open Inventory"]
|
||||
unique_name_in_owner = true
|
||||
custom_minimum_size = Vector2(200, 0)
|
||||
layout_mode = 2
|
||||
script = ExtResource("3_yis0i")
|
||||
|
||||
[node name="Sort Inventory" type="HBoxContainer" parent="MarginContainer/VBoxContainer/ScrollContainer/ActionList"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Label" type="Label" parent="MarginContainer/VBoxContainer/ScrollContainer/ActionList/Sort Inventory"]
|
||||
custom_minimum_size = Vector2(200, 0)
|
||||
layout_mode = 2
|
||||
text = "Sort Inventory"
|
||||
horizontal_alignment = 2
|
||||
|
||||
[node name="Control" type="Control" parent="MarginContainer/VBoxContainer/ScrollContainer/ActionList/Sort Inventory"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
|
||||
[node name="SortKeyboard" type="Button" parent="MarginContainer/VBoxContainer/ScrollContainer/ActionList/Sort Inventory"]
|
||||
unique_name_in_owner = true
|
||||
custom_minimum_size = Vector2(200, 35)
|
||||
layout_mode = 2
|
||||
script = ExtResource("2_fmxfy")
|
||||
|
||||
[node name="Control2" type="Control" parent="MarginContainer/VBoxContainer/ScrollContainer/ActionList/Sort Inventory"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
|
||||
[node name="SortController" type="Button" parent="MarginContainer/VBoxContainer/ScrollContainer/ActionList/Sort Inventory"]
|
||||
unique_name_in_owner = true
|
||||
custom_minimum_size = Vector2(200, 0)
|
||||
layout_mode = 2
|
||||
script = ExtResource("3_yis0i")
|
||||
1
Zennysoft.Game.Ma/src/options/InputToString.cs.uid
Normal file
1
Zennysoft.Game.Ma/src/options/InputToString.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://bwd066xv65pbi
|
||||
41
Zennysoft.Game.Ma/src/options/JoypadRemapButton.cs
Normal file
41
Zennysoft.Game.Ma/src/options/JoypadRemapButton.cs
Normal file
@@ -0,0 +1,41 @@
|
||||
using Godot;
|
||||
using NathanHoad;
|
||||
|
||||
namespace Zennysoft.Game.Ma;
|
||||
|
||||
public partial class JoypadRemapButton : InputMapButton
|
||||
{
|
||||
public override void _Ready()
|
||||
{
|
||||
SetProcessInput(false);
|
||||
}
|
||||
|
||||
public override void _Input(InputEvent @event)
|
||||
{
|
||||
if (@event.IsActionType() && InputHelper.GetDeviceFromEvent(@event) != "keyboard")
|
||||
{
|
||||
if (InputHelper.GetJoypadInputForAction(GameInputs.Pause).IsMatch(@event))
|
||||
{
|
||||
InputHelper.SetJoypadInputForAction(Action, InputEvent);
|
||||
}
|
||||
else
|
||||
{
|
||||
InputHelper.ReplaceJoypadInputForAction(Action, InputEvent, @event, true);
|
||||
if (Action == GameInputs.MoveUp)
|
||||
InputHelper.ReplaceJoypadInputForAction(GameInputs.UiUp, InputEvent, @event, true);
|
||||
else if (Action == GameInputs.MoveLeft)
|
||||
InputHelper.ReplaceJoypadInputForAction(GameInputs.UiLeft, InputEvent, @event, true);
|
||||
else if (Action == GameInputs.MoveRight)
|
||||
InputHelper.ReplaceJoypadInputForAction(GameInputs.UiRight, InputEvent, @event, true);
|
||||
else if (Action == GameInputs.MoveDown)
|
||||
InputHelper.ReplaceJoypadInputForAction(GameInputs.UiDown, InputEvent, @event, true);
|
||||
else if (Action == GameInputs.Attack)
|
||||
InputHelper.ReplaceJoypadInputForAction(GameInputs.UiAccept, InputEvent, @event, true);
|
||||
else if (Action == GameInputs.Interact)
|
||||
InputHelper.ReplaceJoypadInputForAction(GameInputs.UiCancel, InputEvent, @event, true);
|
||||
InputEvent = @event;
|
||||
}
|
||||
}
|
||||
AcceptEvent();
|
||||
}
|
||||
}
|
||||
1
Zennysoft.Game.Ma/src/options/JoypadRemapButton.cs.uid
Normal file
1
Zennysoft.Game.Ma/src/options/JoypadRemapButton.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://bo7vk56h1lr07
|
||||
42
Zennysoft.Game.Ma/src/options/KeyboardRemapButton.cs
Normal file
42
Zennysoft.Game.Ma/src/options/KeyboardRemapButton.cs
Normal file
@@ -0,0 +1,42 @@
|
||||
using Godot;
|
||||
using NathanHoad;
|
||||
|
||||
namespace Zennysoft.Game.Ma;
|
||||
|
||||
public partial class KeyboardRemapButton : InputMapButton
|
||||
{
|
||||
public override void _Ready()
|
||||
{
|
||||
SetProcessInput(false);
|
||||
}
|
||||
|
||||
public override void _Input(InputEvent @event)
|
||||
{
|
||||
AcceptEvent();
|
||||
if (@event.IsActionType() && InputHelper.GetDeviceFromEvent(@event) == "keyboard")
|
||||
{
|
||||
if (InputHelper.GetKeyboardInputForAction(GameInputs.Pause).IsMatch(@event))
|
||||
{
|
||||
InputHelper.SetKeyboardInputForAction(Action, InputEvent);
|
||||
}
|
||||
else
|
||||
{
|
||||
InputHelper.ReplaceKeyboardInputForAction(Action, InputEvent, @event, true);
|
||||
if (Action == GameInputs.MoveUp)
|
||||
InputHelper.ReplaceKeyboardInputForAction(GameInputs.UiUp, InputEvent, @event, true);
|
||||
else if (Action == GameInputs.MoveLeft)
|
||||
InputHelper.ReplaceKeyboardInputForAction(GameInputs.UiLeft, InputEvent, @event, true);
|
||||
else if (Action == GameInputs.MoveRight)
|
||||
InputHelper.ReplaceKeyboardInputForAction(GameInputs.UiRight, InputEvent, @event, true);
|
||||
else if (Action == GameInputs.MoveDown)
|
||||
InputHelper.ReplaceKeyboardInputForAction(GameInputs.UiDown, InputEvent, @event, true);
|
||||
else if (Action == GameInputs.Attack)
|
||||
InputHelper.ReplaceKeyboardInputForAction(GameInputs.UiAccept, InputEvent, @event, true);
|
||||
else if (Action == GameInputs.Interact)
|
||||
InputHelper.ReplaceKeyboardInputForAction(GameInputs.UiCancel, InputEvent, @event, true);
|
||||
InputEvent = @event;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
1
Zennysoft.Game.Ma/src/options/KeyboardRemapButton.cs.uid
Normal file
1
Zennysoft.Game.Ma/src/options/KeyboardRemapButton.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://b70br20xue678
|
||||
21
Zennysoft.Game.Ma/src/options/OptionsData.cs
Normal file
21
Zennysoft.Game.Ma/src/options/OptionsData.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
using Chickensoft.Introspection;
|
||||
using Chickensoft.Serialization;
|
||||
using Godot;
|
||||
|
||||
namespace Zennysoft.Game.Ma;
|
||||
|
||||
[Meta, Id("options_data")]
|
||||
public partial class OptionsData : Node
|
||||
{
|
||||
[Save("MasterVolume")]
|
||||
public required double MasterVolumeLevel { get; set; }
|
||||
|
||||
[Save("MusicVolume")]
|
||||
public required double MusicVolumeLevel { get; set; }
|
||||
|
||||
[Save("SFXVolume")]
|
||||
public required double SFXVolumeLevel { get; set; }
|
||||
|
||||
[Save("ScreenResolution")]
|
||||
public required int ScreenResolution { get; set; }
|
||||
}
|
||||
1
Zennysoft.Game.Ma/src/options/OptionsData.cs.uid
Normal file
1
Zennysoft.Game.Ma/src/options/OptionsData.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://jrl2hyudv6jn
|
||||
159
Zennysoft.Game.Ma/src/options/OptionsMenu.cs
Normal file
159
Zennysoft.Game.Ma/src/options/OptionsMenu.cs
Normal file
@@ -0,0 +1,159 @@
|
||||
using Chickensoft.AutoInject;
|
||||
using Chickensoft.Introspection;
|
||||
using Godot;
|
||||
using NathanHoad;
|
||||
using System.Linq;
|
||||
|
||||
namespace Zennysoft.Game.Ma;
|
||||
|
||||
[Meta(typeof(IAutoNode))]
|
||||
public partial class OptionsMenu : Control
|
||||
{
|
||||
public override void _Notification(int what) => this.Notify(what);
|
||||
|
||||
[Node] public OptionButton ResolutionOptions { get; set; }
|
||||
|
||||
[Node] public HSlider MasterVolumeSlider { get; set; }
|
||||
[Node] public HSlider MusicVolumeSlider { get; set; }
|
||||
[Node] public HSlider SFXVolumeSlider { get; set; }
|
||||
|
||||
[Node] public InputMapper Controller { get; set; }
|
||||
[Node] public TabContainer TabContainer { get; set; }
|
||||
[Node] public Label PressToGoBackLabel { get; set; }
|
||||
|
||||
[Node] public CanvasLayer CanvasLayer { get; set; }
|
||||
|
||||
public OptionsData OptionsData;
|
||||
|
||||
private int _masterBusIndex;
|
||||
private int _musicBusIndex;
|
||||
private int _sfxBusIndex;
|
||||
|
||||
private readonly DisplayServer.WindowMode[] _windowModes = [DisplayServer.WindowMode.Windowed, DisplayServer.WindowMode.Maximized, DisplayServer.WindowMode.Fullscreen, DisplayServer.WindowMode.ExclusiveFullscreen];
|
||||
|
||||
[Signal] public delegate void OptionsMenuExitedEventHandler();
|
||||
|
||||
public void OnReady()
|
||||
{
|
||||
ResolutionOptions.AddItem("Windowed");
|
||||
ResolutionOptions.AddItem("Maximized");
|
||||
ResolutionOptions.AddItem("Fullscreen");
|
||||
ResolutionOptions.AddItem("Exclusive Fullscreen");
|
||||
ResolutionOptions.Select(0);
|
||||
|
||||
OptionsData = new OptionsData()
|
||||
{
|
||||
MasterVolumeLevel = MasterVolumeSlider.Value,
|
||||
MusicVolumeLevel = MusicVolumeSlider.Value,
|
||||
SFXVolumeLevel = SFXVolumeSlider.Value,
|
||||
ScreenResolution = ResolutionOptions.GetSelectedId()
|
||||
};
|
||||
MasterVolumeSlider.ValueChanged += MasterVolumeSlider_Changed;
|
||||
MusicVolumeSlider.ValueChanged += MusicVolumeSlider_Changed;
|
||||
SFXVolumeSlider.ValueChanged += SFXVolumeSlider_Changed;
|
||||
|
||||
ResolutionOptions.ItemSelected += ResolutionOptions_ItemSelected;
|
||||
|
||||
TabContainer.TabChanged += TabContainer_TabChanged;
|
||||
|
||||
_masterBusIndex = AudioServer.GetBusIndex("Master");
|
||||
_musicBusIndex = AudioServer.GetBusIndex("MUSIC");
|
||||
_sfxBusIndex = AudioServer.GetBusIndex("SFX");
|
||||
|
||||
VisibilityChanged += OptionsMenu_VisibilityChanged;
|
||||
|
||||
InputHelper.JoypadInputChanged += (string action, InputEvent input) =>
|
||||
{
|
||||
if (GameInputs.Interact == action)
|
||||
{
|
||||
var interactInputs = InputHelper.GetLabelForInput(InputHelper.GetJoypadInputForAction(GameInputs.Interact));
|
||||
PressToGoBackLabel.Text = $"Press {interactInputs} to save and exit.";
|
||||
}
|
||||
};
|
||||
|
||||
InputHelper.KeyboardInputChanged += (string action, InputEvent input) =>
|
||||
{
|
||||
if (GameInputs.Interact == action)
|
||||
{
|
||||
var interactInputs = InputHelper.GetLabelForInput(InputHelper.GetKeyboardInputForAction(GameInputs.Interact));
|
||||
PressToGoBackLabel.Text = $"Press {interactInputs} to save and exit.";
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private void TabContainer_TabChanged(long tab)
|
||||
{
|
||||
if (tab == 0)
|
||||
MasterVolumeSlider.GrabFocus();
|
||||
if (tab == 1)
|
||||
Controller.MoveForwardKeyboard.GrabFocus();
|
||||
}
|
||||
|
||||
private void OptionsMenu_VisibilityChanged()
|
||||
{
|
||||
CanvasLayer.Visible = !CanvasLayer.Visible;
|
||||
}
|
||||
|
||||
public override void _Input(InputEvent @event)
|
||||
{
|
||||
if (!Visible)
|
||||
return;
|
||||
|
||||
var interactInputs = InputHelper.GetKeyboardOrJoypadInputsForAction(GameInputs.Interact);
|
||||
if (interactInputs.Any(x => x.IsMatch(@event)))
|
||||
{
|
||||
AcceptEvent();
|
||||
SaveAndExitMenu();
|
||||
}
|
||||
|
||||
var leftTab = InputHelper.GetKeyboardOrJoypadInputsForAction(GameInputs.StrafeLeft);
|
||||
if (leftTab.Any(x => x.IsMatch(@event)))
|
||||
{
|
||||
AcceptEvent();
|
||||
TabContainer.CurrentTab = Mathf.Max(0, TabContainer.CurrentTab - 1);
|
||||
}
|
||||
|
||||
var rightTab = InputHelper.GetKeyboardOrJoypadInputsForAction(GameInputs.StrafeRight);
|
||||
if (rightTab.Any(x => x.IsMatch(@event)))
|
||||
{
|
||||
AcceptEvent();
|
||||
TabContainer.CurrentTab = Mathf.Min(TabContainer.GetTabCount() - 1, TabContainer.CurrentTab + 1);
|
||||
}
|
||||
}
|
||||
|
||||
private void ResolutionOptions_ItemSelected(long index)
|
||||
{
|
||||
var resolutionIndex = ResolutionOptions.GetSelectedId();
|
||||
OptionsData.ScreenResolution = resolutionIndex;
|
||||
DisplayServer.WindowSetMode(_windowModes[resolutionIndex]);
|
||||
}
|
||||
|
||||
public void Load(OptionsData optionsData)
|
||||
{
|
||||
MasterVolumeSlider.Value = optionsData.MasterVolumeLevel;
|
||||
MusicVolumeSlider.Value = optionsData.MusicVolumeLevel;
|
||||
SFXVolumeSlider.Value = optionsData.SFXVolumeLevel;
|
||||
ResolutionOptions.Select(optionsData.ScreenResolution);
|
||||
DisplayServer.WindowSetMode(_windowModes[optionsData.ScreenResolution]);
|
||||
}
|
||||
|
||||
private void SaveAndExitMenu() => EmitSignal(SignalName.OptionsMenuExited);
|
||||
|
||||
private void MasterVolumeSlider_Changed(double valueChanged)
|
||||
{
|
||||
OptionsData.MasterVolumeLevel = valueChanged;
|
||||
AudioServer.SetBusVolumeDb(_masterBusIndex, Mathf.LinearToDb((float)valueChanged));
|
||||
}
|
||||
|
||||
private void MusicVolumeSlider_Changed(double valueChanged)
|
||||
{
|
||||
OptionsData.MusicVolumeLevel = valueChanged;
|
||||
AudioServer.SetBusVolumeDb(_musicBusIndex, Mathf.LinearToDb((float)valueChanged));
|
||||
}
|
||||
|
||||
private void SFXVolumeSlider_Changed(double valueChanged)
|
||||
{
|
||||
OptionsData.SFXVolumeLevel = valueChanged;
|
||||
AudioServer.SetBusVolumeDb(_sfxBusIndex, Mathf.LinearToDb((float)valueChanged));
|
||||
}
|
||||
}
|
||||
1
Zennysoft.Game.Ma/src/options/OptionsMenu.cs.uid
Normal file
1
Zennysoft.Game.Ma/src/options/OptionsMenu.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://cjxmdvhixcj6e
|
||||
149
Zennysoft.Game.Ma/src/options/OptionsMenu.tscn
Normal file
149
Zennysoft.Game.Ma/src/options/OptionsMenu.tscn
Normal file
@@ -0,0 +1,149 @@
|
||||
[gd_scene load_steps=7 format=3 uid="uid://drkl3btdy6uxj"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://cjxmdvhixcj6e" path="res://src/options/OptionsMenu.cs" id="1_jli36"]
|
||||
[ext_resource type="Shortcut" uid="uid://dumkrjur22k2a" path="res://src/ui/ButtonShortcut.tres" id="2_1egkf"]
|
||||
[ext_resource type="PackedScene" uid="uid://dk5esf6mm6kte" path="res://src/options/InputMapper.tscn" id="2_utd4g"]
|
||||
|
||||
[sub_resource type="StyleBoxLine" id="StyleBoxLine_jli36"]
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_utd4g"]
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_1egkf"]
|
||||
bg_color = Color(2.5028e-06, 0.712708, 0.445629, 1)
|
||||
|
||||
[node name="OptionsMenu" type="Control"]
|
||||
layout_mode = 3
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
script = ExtResource("1_jli36")
|
||||
|
||||
[node name="CanvasLayer" type="CanvasLayer" parent="."]
|
||||
unique_name_in_owner = true
|
||||
visible = false
|
||||
|
||||
[node name="CenterContainer" type="AspectRatioContainer" parent="CanvasLayer"]
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
mouse_filter = 0
|
||||
|
||||
[node name="VBoxContainer" type="VBoxContainer" parent="CanvasLayer/CenterContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="TabContainer" type="TabContainer" parent="CanvasLayer/CenterContainer/VBoxContainer"]
|
||||
unique_name_in_owner = true
|
||||
custom_minimum_size = Vector2(1280, 960)
|
||||
layout_mode = 2
|
||||
current_tab = 0
|
||||
|
||||
[node name="Audio" type="MarginContainer" parent="CanvasLayer/CenterContainer/VBoxContainer/TabContainer"]
|
||||
layout_mode = 2
|
||||
theme_override_constants/margin_left = 100
|
||||
theme_override_constants/margin_top = 100
|
||||
theme_override_constants/margin_right = 100
|
||||
theme_override_constants/margin_bottom = 100
|
||||
metadata/_tab_index = 0
|
||||
|
||||
[node name="VBoxContainer" type="VBoxContainer" parent="CanvasLayer/CenterContainer/VBoxContainer/TabContainer/Audio"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 0
|
||||
mouse_filter = 0
|
||||
|
||||
[node name="MasterVolume" type="HBoxContainer" parent="CanvasLayer/CenterContainer/VBoxContainer/TabContainer/Audio/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="VolumeLabel" type="Label" parent="CanvasLayer/CenterContainer/VBoxContainer/TabContainer/Audio/VBoxContainer/MasterVolume"]
|
||||
custom_minimum_size = Vector2(125, 0)
|
||||
layout_mode = 2
|
||||
text = "Master Volume"
|
||||
horizontal_alignment = 2
|
||||
|
||||
[node name="MasterVolumeSlider" type="HSlider" parent="CanvasLayer/CenterContainer/VBoxContainer/TabContainer/Audio/VBoxContainer/MasterVolume"]
|
||||
unique_name_in_owner = true
|
||||
custom_minimum_size = Vector2(300, 0)
|
||||
layout_mode = 2
|
||||
size_flags_vertical = 1
|
||||
theme_override_styles/slider = SubResource("StyleBoxLine_jli36")
|
||||
theme_override_styles/grabber_area = SubResource("StyleBoxFlat_utd4g")
|
||||
theme_override_styles/grabber_area_highlight = SubResource("StyleBoxFlat_1egkf")
|
||||
max_value = 1.0
|
||||
step = 0.001
|
||||
value = 1.0
|
||||
|
||||
[node name="MusicVolume" type="HBoxContainer" parent="CanvasLayer/CenterContainer/VBoxContainer/TabContainer/Audio/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="VolumeLabel" type="Label" parent="CanvasLayer/CenterContainer/VBoxContainer/TabContainer/Audio/VBoxContainer/MusicVolume"]
|
||||
custom_minimum_size = Vector2(125, 0)
|
||||
layout_mode = 2
|
||||
text = "Music Volume"
|
||||
horizontal_alignment = 2
|
||||
|
||||
[node name="MusicVolumeSlider" type="HSlider" parent="CanvasLayer/CenterContainer/VBoxContainer/TabContainer/Audio/VBoxContainer/MusicVolume"]
|
||||
unique_name_in_owner = true
|
||||
custom_minimum_size = Vector2(300, 0)
|
||||
layout_mode = 2
|
||||
size_flags_vertical = 1
|
||||
theme_override_styles/slider = SubResource("StyleBoxLine_jli36")
|
||||
theme_override_styles/grabber_area = SubResource("StyleBoxFlat_utd4g")
|
||||
theme_override_styles/grabber_area_highlight = SubResource("StyleBoxFlat_1egkf")
|
||||
max_value = 1.0
|
||||
step = 0.001
|
||||
value = 1.0
|
||||
|
||||
[node name="SFXVolume" type="HBoxContainer" parent="CanvasLayer/CenterContainer/VBoxContainer/TabContainer/Audio/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="VolumeLabel" type="Label" parent="CanvasLayer/CenterContainer/VBoxContainer/TabContainer/Audio/VBoxContainer/SFXVolume"]
|
||||
custom_minimum_size = Vector2(125, 0)
|
||||
layout_mode = 2
|
||||
text = "SFX Volume"
|
||||
horizontal_alignment = 2
|
||||
|
||||
[node name="SFXVolumeSlider" type="HSlider" parent="CanvasLayer/CenterContainer/VBoxContainer/TabContainer/Audio/VBoxContainer/SFXVolume"]
|
||||
unique_name_in_owner = true
|
||||
custom_minimum_size = Vector2(300, 0)
|
||||
layout_mode = 2
|
||||
size_flags_vertical = 1
|
||||
theme_override_styles/slider = SubResource("StyleBoxLine_jli36")
|
||||
theme_override_styles/grabber_area = SubResource("StyleBoxFlat_utd4g")
|
||||
theme_override_styles/grabber_area_highlight = SubResource("StyleBoxFlat_1egkf")
|
||||
max_value = 1.0
|
||||
step = 0.001
|
||||
value = 1.0
|
||||
|
||||
[node name="Resolution" type="HBoxContainer" parent="CanvasLayer/CenterContainer/VBoxContainer/TabContainer/Audio/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="ResolutionLabel" type="Label" parent="CanvasLayer/CenterContainer/VBoxContainer/TabContainer/Audio/VBoxContainer/Resolution"]
|
||||
custom_minimum_size = Vector2(125, 0)
|
||||
layout_mode = 2
|
||||
text = "Resolution: "
|
||||
horizontal_alignment = 2
|
||||
|
||||
[node name="ResolutionOptions" type="OptionButton" parent="CanvasLayer/CenterContainer/VBoxContainer/TabContainer/Audio/VBoxContainer/Resolution"]
|
||||
unique_name_in_owner = true
|
||||
custom_minimum_size = Vector2(200, 0)
|
||||
layout_mode = 2
|
||||
shortcut = ExtResource("2_1egkf")
|
||||
flat = true
|
||||
|
||||
[node name="HBoxContainer" type="HBoxContainer" parent="CanvasLayer/CenterContainer/VBoxContainer/TabContainer/Audio/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
size_flags_vertical = 10
|
||||
|
||||
[node name="Controller" parent="CanvasLayer/CenterContainer/VBoxContainer/TabContainer" instance=ExtResource("2_utd4g")]
|
||||
unique_name_in_owner = true
|
||||
visible = false
|
||||
layout_mode = 2
|
||||
metadata/_tab_index = 1
|
||||
|
||||
[node name="PressToGoBackLabel" type="Label" parent="CanvasLayer/CenterContainer/VBoxContainer"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
text = "Press "
|
||||
@@ -99,173 +99,179 @@ public partial class Player : CharacterBody3D, IPlayer, IProvide<IPlayer>
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
var container = new SimpleInjector.Container();
|
||||
container.Register<IPlayerLogic, PlayerLogic>(Lifestyle.Singleton);
|
||||
var container = new SimpleInjector.Container();
|
||||
container.Register<IPlayerLogic, PlayerLogic>(Lifestyle.Singleton);
|
||||
|
||||
PlayerLogic = container.GetInstance<IPlayerLogic>();
|
||||
PlayerLogic.Set(this as IPlayer);
|
||||
PlayerLogic.Set(Settings);
|
||||
PlayerLogic = container.GetInstance<IPlayerLogic>();
|
||||
PlayerLogic.Set(this as IPlayer);
|
||||
PlayerLogic.Set(Settings);
|
||||
|
||||
Inventory = new Inventory();
|
||||
HealthComponent = new HealthComponent(InitialHP);
|
||||
VTComponent = new VTComponent(InitialVT);
|
||||
AttackComponent = new AttackComponent(InitialAttack);
|
||||
DefenseComponent = new DefenseComponent(InitialDefense);
|
||||
ExperiencePointsComponent = new ExperiencePointsComponent();
|
||||
LuckComponent = new LuckComponent(InitialLuck);
|
||||
EquipmentComponent = new EquipmentComponent();
|
||||
Inventory = new Inventory();
|
||||
HealthComponent = new HealthComponent(InitialHP);
|
||||
VTComponent = new VTComponent(InitialVT);
|
||||
AttackComponent = new AttackComponent(InitialAttack);
|
||||
DefenseComponent = new DefenseComponent(InitialDefense);
|
||||
ExperiencePointsComponent = new ExperiencePointsComponent();
|
||||
LuckComponent = new LuckComponent(InitialLuck);
|
||||
EquipmentComponent = new EquipmentComponent();
|
||||
|
||||
_itemReroller = new ItemReroller(ItemDatabase.Instance);
|
||||
_itemReroller = new ItemReroller(ItemDatabase.Instance);
|
||||
|
||||
Settings = new PlayerLogic.Settings() { RotationSpeed = RotationSpeed, MoveSpeed = MoveSpeed, Acceleration = Acceleration };
|
||||
Settings = new PlayerLogic.Settings() { RotationSpeed = RotationSpeed, MoveSpeed = MoveSpeed, Acceleration = Acceleration };
|
||||
|
||||
PlayerBinding = PlayerLogic.Bind();
|
||||
PlayerBinding = PlayerLogic.Bind();
|
||||
|
||||
PlayerBinding
|
||||
.Handle((in PlayerLogic.Output.ThrowItem output) =>
|
||||
{
|
||||
})
|
||||
.Handle((in PlayerLogic.Output.Move output) =>
|
||||
{
|
||||
Move(output.delta);
|
||||
});
|
||||
PlayerBinding
|
||||
.Handle((in PlayerLogic.Output.ThrowItem output) =>
|
||||
{
|
||||
})
|
||||
.Handle((in PlayerLogic.Output.Move output) =>
|
||||
{
|
||||
Move(output.delta);
|
||||
});
|
||||
|
||||
PlayerLogic.Start();
|
||||
this.Provide();
|
||||
PlayerLogic.Start();
|
||||
this.Provide();
|
||||
}
|
||||
|
||||
public void ResetPlayerData()
|
||||
{
|
||||
foreach (var item in Inventory.Items)
|
||||
Inventory.Remove(item);
|
||||
foreach (var item in Inventory.Items)
|
||||
Inventory.Remove(item);
|
||||
|
||||
HealthComponent.Reset();
|
||||
VTComponent.Reset();
|
||||
AttackComponent.Reset();
|
||||
DefenseComponent.Reset();
|
||||
ExperiencePointsComponent.Reset();
|
||||
LuckComponent.Reset();
|
||||
EquipmentComponent.Reset();
|
||||
HealthComponent.Reset();
|
||||
VTComponent.Reset();
|
||||
AttackComponent.Reset();
|
||||
DefenseComponent.Reset();
|
||||
ExperiencePointsComponent.Reset();
|
||||
LuckComponent.Reset();
|
||||
EquipmentComponent.Reset();
|
||||
|
||||
HealthTimer.Timeout += OnHealthTimerTimeout;
|
||||
HealthTimer.Timeout += OnHealthTimerTimeout;
|
||||
}
|
||||
|
||||
#region Initialization
|
||||
public void OnReady()
|
||||
{
|
||||
Hitbox.AreaEntered += Hitbox_AreaEntered;
|
||||
CollisionDetector.AreaEntered += CollisionDetector_AreaEntered;
|
||||
SwordSlashAnimation.Position = GetViewport().GetVisibleRect().Size / 2;
|
||||
HealthComponent.HealthReachedZero += Die;
|
||||
HealthTimer.WaitTime = _healthTimerWaitTime;
|
||||
SetProcessInput(false);
|
||||
SetPhysicsProcess(false);
|
||||
Hitbox.AreaEntered += Hitbox_AreaEntered;
|
||||
CollisionDetector.AreaEntered += CollisionDetector_AreaEntered;
|
||||
SwordSlashAnimation.Position = GetViewport().GetVisibleRect().Size / 2;
|
||||
HealthComponent.HealthReachedZero += Die;
|
||||
HealthTimer.WaitTime = _healthTimerWaitTime;
|
||||
SetProcessInput(false);
|
||||
SetPhysicsProcess(false);
|
||||
}
|
||||
#endregion
|
||||
|
||||
public void Activate()
|
||||
{
|
||||
SetProcessInput(true);
|
||||
SetPhysicsProcess(true);
|
||||
SetHealthTimerStatus(HealthTimerIsActive);
|
||||
SetProcessInput(true);
|
||||
SetPhysicsProcess(true);
|
||||
SetHealthTimerStatus(HealthTimerIsActive);
|
||||
}
|
||||
|
||||
public void Deactivate()
|
||||
{
|
||||
SetProcessInput(false);
|
||||
SetPhysicsProcess(false);
|
||||
SetHealthTimerStatus(false);
|
||||
SetProcessInput(false);
|
||||
SetPhysicsProcess(false);
|
||||
SetHealthTimerStatus(false);
|
||||
}
|
||||
|
||||
private void SetHealthTimerStatus(bool isActive)
|
||||
{
|
||||
if (isActive)
|
||||
HealthTimer.Start();
|
||||
else
|
||||
HealthTimer.Stop();
|
||||
if (isActive)
|
||||
HealthTimer.Start();
|
||||
else
|
||||
HealthTimer.Stop();
|
||||
}
|
||||
|
||||
public void TeleportPlayer(Transform3D newTransform)
|
||||
{
|
||||
Transform = newTransform;
|
||||
Transform = newTransform;
|
||||
}
|
||||
|
||||
public void TakeDamage(AttackData damage)
|
||||
{
|
||||
var damageReceived = DamageCalculator.CalculateDamage(damage, DefenseComponent.CurrentDefense.Value + EquipmentComponent.BonusDefense, EquipmentComponent.ElementalResistance);
|
||||
HealthComponent.Damage(damageReceived);
|
||||
var damageReceived = DamageCalculator.CalculateDamage(damage, DefenseComponent.CurrentDefense.Value + EquipmentComponent.BonusDefense, EquipmentComponent.ElementalResistance);
|
||||
HealthComponent.Damage(damageReceived);
|
||||
}
|
||||
|
||||
public void Knockback(float impulse)
|
||||
{
|
||||
_knockbackStrength = impulse;
|
||||
_knockbackDirection = GlobalBasis.Z.Normalized();
|
||||
_knockbackStrength = impulse;
|
||||
_knockbackDirection = GlobalBasis.Z.Normalized();
|
||||
}
|
||||
|
||||
public void LevelUp()
|
||||
{
|
||||
var rng = new RandomNumberGenerator();
|
||||
rng.Randomize();
|
||||
var hpIncrease = rng.RandiRange(3, 6);
|
||||
HealthComponent.RaiseMaximumHP(hpIncrease);
|
||||
ExperiencePointsComponent.LevelUp();
|
||||
var rng = new RandomNumberGenerator();
|
||||
rng.Randomize();
|
||||
var hpIncrease = rng.RandiRange(3, 6);
|
||||
HealthComponent.RaiseMaximumHP(hpIncrease);
|
||||
ExperiencePointsComponent.LevelUp();
|
||||
}
|
||||
|
||||
public void Die()
|
||||
{
|
||||
HealthTimer.WaitTime = _healthTimerWaitTime;
|
||||
HealthTimer.Timeout -= OnHealthTimerTimeout;
|
||||
SwordSlashAnimation.Stop();
|
||||
SetProcessInput(false);
|
||||
SetPhysicsProcess(false);
|
||||
PlayerDied?.Invoke();
|
||||
HealthTimer.WaitTime = _healthTimerWaitTime;
|
||||
HealthTimer.Timeout -= OnHealthTimerTimeout;
|
||||
SwordSlashAnimation.Stop();
|
||||
SetProcessInput(false);
|
||||
SetPhysicsProcess(false);
|
||||
PlayerDied?.Invoke();
|
||||
}
|
||||
|
||||
public override void _Input(InputEvent @event)
|
||||
{
|
||||
if (@event.IsActionPressed(GameInputs.Attack))
|
||||
Attack();
|
||||
if (@event.IsActionPressed(GameInputs.Sprint))
|
||||
Settings.MoveSpeed *= 2;
|
||||
if (@event.IsActionReleased(GameInputs.Sprint))
|
||||
Settings.MoveSpeed /= 2;
|
||||
if (@event.IsActionPressed(GameInputs.Attack))
|
||||
Attack();
|
||||
if (@event.IsActionPressed(GameInputs.Sprint))
|
||||
Settings.MoveSpeed *= 2;
|
||||
if (@event.IsActionReleased(GameInputs.Sprint))
|
||||
Settings.MoveSpeed /= 2;
|
||||
}
|
||||
|
||||
public void OnPhysicsProcess(double delta)
|
||||
{
|
||||
PlayerLogic.Input(new PlayerLogic.Input.PhysicsTick(delta));
|
||||
PlayerLogic.Input(new PlayerLogic.Input.Moved(GlobalPosition, GlobalTransform));
|
||||
PlayerLogic.Input(new PlayerLogic.Input.PhysicsTick(delta));
|
||||
PlayerLogic.Input(new PlayerLogic.Input.Moved(GlobalPosition, GlobalTransform));
|
||||
}
|
||||
|
||||
public void Equip(EquipableItem equipable)
|
||||
{
|
||||
if (equipable.ItemTag == ItemTag.MysteryItem)
|
||||
{
|
||||
var rerolledItem = _itemReroller.RerollItem(equipable, Inventory);
|
||||
Equip(rerolledItem);
|
||||
return;
|
||||
}
|
||||
if (equipable.ItemTag == ItemTag.MysteryItem)
|
||||
{
|
||||
var rerolledItem = _itemReroller.RerollItem(equipable, Inventory);
|
||||
Equip(rerolledItem);
|
||||
return;
|
||||
}
|
||||
|
||||
EquipmentComponent.Equip(equipable);
|
||||
HealthComponent.RaiseMaximumHP(equipable.BonusHP, false);
|
||||
VTComponent.RaiseMaximumVT(equipable.BonusVT, false);
|
||||
|
||||
EquipmentComponent.Equip(equipable);
|
||||
}
|
||||
|
||||
public void Unequip(EquipableItem equipable)
|
||||
{
|
||||
EquipmentComponent.Unequip(equipable);
|
||||
HealthComponent.SetMaximumHealth(HealthComponent.MaximumHP.Value - equipable.BonusHP);
|
||||
VTComponent.SetMaximumVT(VTComponent.MaximumVT.Value - equipable.BonusVT);
|
||||
|
||||
EquipmentComponent.Unequip(equipable);
|
||||
}
|
||||
|
||||
private static Vector3 GlobalInputVector
|
||||
{
|
||||
get
|
||||
{
|
||||
var rawInput = Input.GetVector(GameInputs.MoveLeft, GameInputs.MoveRight, GameInputs.MoveUp, GameInputs.MoveDown);
|
||||
var input = new Vector3
|
||||
{
|
||||
X = rawInput.X,
|
||||
Z = rawInput.Y
|
||||
};
|
||||
return input with { Y = 0f };
|
||||
}
|
||||
get
|
||||
{
|
||||
var rawInput = Input.GetVector(GameInputs.MoveLeft, GameInputs.MoveRight, GameInputs.MoveUp, GameInputs.MoveDown);
|
||||
var input = new Vector3
|
||||
{
|
||||
X = rawInput.X,
|
||||
Z = rawInput.Y
|
||||
};
|
||||
return input with { Y = 0f };
|
||||
}
|
||||
}
|
||||
|
||||
private static float LeftStrafeInputVector => Input.GetActionStrength(GameInputs.StrafeLeft);
|
||||
@@ -274,140 +280,140 @@ public partial class Player : CharacterBody3D, IPlayer, IProvide<IPlayer>
|
||||
|
||||
private void Attack()
|
||||
{
|
||||
if (PlayerIsHittingGeometry())
|
||||
{
|
||||
AnimationPlayer.Play("hit_wall");
|
||||
}
|
||||
else
|
||||
{
|
||||
PlayAttackAnimation();
|
||||
}
|
||||
if (PlayerIsHittingGeometry())
|
||||
{
|
||||
AnimationPlayer.Play("hit_wall");
|
||||
}
|
||||
else
|
||||
{
|
||||
PlayAttackAnimation();
|
||||
}
|
||||
}
|
||||
|
||||
private void ThrowItem()
|
||||
{
|
||||
var itemScene = GD.Load<PackedScene>("res://src/items/throwable/ThrowableItem.tscn");
|
||||
var throwItem = itemScene.Instantiate<ThrowableItem>();
|
||||
GetTree().Root.AddChildEx(throwItem);
|
||||
throwItem.GlobalPosition = CurrentPosition + new Vector3(0, 3.5f, 0);
|
||||
throwItem.GlobalRotation = GlobalRotation;
|
||||
var itemScene = GD.Load<PackedScene>("res://src/items/throwable/ThrowableItem.tscn");
|
||||
var throwItem = itemScene.Instantiate<ThrowableItem>();
|
||||
GetTree().Root.AddChildEx(throwItem);
|
||||
throwItem.GlobalPosition = CurrentPosition + new Vector3(0, 3.5f, 0);
|
||||
throwItem.GlobalRotation = GlobalRotation;
|
||||
}
|
||||
|
||||
private void PlayAttackAnimation()
|
||||
{
|
||||
var attackSpeed = ((Weapon)EquipmentComponent.EquippedWeapon.Value).AttackSpeed;
|
||||
AnimationPlayer.SetSpeedScale((float)attackSpeed);
|
||||
AnimationPlayer.Play("attack");
|
||||
var attackSpeed = ((Weapon)EquipmentComponent.EquippedWeapon.Value).AttackSpeed;
|
||||
AnimationPlayer.SetSpeedScale((float)attackSpeed);
|
||||
AnimationPlayer.Play("attack");
|
||||
}
|
||||
|
||||
private void OnExitTree()
|
||||
{
|
||||
PlayerLogic.Stop();
|
||||
PlayerBinding.Dispose();
|
||||
Hitbox.AreaEntered -= Hitbox_AreaEntered;
|
||||
CollisionDetector.AreaEntered -= CollisionDetector_AreaEntered;
|
||||
HealthComponent.HealthReachedZero -= Die;
|
||||
HealthTimer.Timeout -= OnHealthTimerTimeout;
|
||||
PlayerLogic.Stop();
|
||||
PlayerBinding.Dispose();
|
||||
Hitbox.AreaEntered -= Hitbox_AreaEntered;
|
||||
CollisionDetector.AreaEntered -= CollisionDetector_AreaEntered;
|
||||
HealthComponent.HealthReachedZero -= Die;
|
||||
HealthTimer.Timeout -= OnHealthTimerTimeout;
|
||||
}
|
||||
|
||||
private void Move(float delta)
|
||||
{
|
||||
var rawInput = GlobalInputVector;
|
||||
var strafeLeftInput = LeftStrafeInputVector;
|
||||
var strafeRightInput = RightStrafeInputVector;
|
||||
var rawInput = GlobalInputVector;
|
||||
var strafeLeftInput = LeftStrafeInputVector;
|
||||
var strafeRightInput = RightStrafeInputVector;
|
||||
|
||||
var transform = Transform;
|
||||
transform.Basis = new Basis(Vector3.Up, Settings.RotationSpeed * -rawInput.X * delta) * transform.Basis;
|
||||
var moveDirection = new Vector3(strafeRightInput - strafeLeftInput, 0, rawInput.Z).Normalized();
|
||||
var velocity = Basis * moveDirection * Settings.MoveSpeed * Settings.Acceleration;
|
||||
_knockbackStrength *= 0.9f;
|
||||
Transform = Transform with { Basis = transform.Basis };
|
||||
Velocity = velocity + (_knockbackDirection * _knockbackStrength);
|
||||
MoveAndSlide();
|
||||
var transform = Transform;
|
||||
transform.Basis = new Basis(Vector3.Up, Settings.RotationSpeed * -rawInput.X * delta) * transform.Basis;
|
||||
var moveDirection = new Vector3(strafeRightInput - strafeLeftInput, 0, rawInput.Z).Normalized();
|
||||
var velocity = Basis * moveDirection * Settings.MoveSpeed * Settings.Acceleration;
|
||||
_knockbackStrength *= 0.9f;
|
||||
Transform = Transform with { Basis = transform.Basis };
|
||||
Velocity = velocity + (_knockbackDirection * _knockbackStrength);
|
||||
MoveAndSlide();
|
||||
}
|
||||
|
||||
private void OnPlayerPositionUpdated(Vector3 globalPosition) => GlobalPosition = globalPosition;
|
||||
|
||||
private void OnHealthTimerTimeout()
|
||||
{
|
||||
if (VTComponent.CurrentVT.Value > 0)
|
||||
{
|
||||
if (((Accessory)EquipmentComponent.EquippedAccessory.Value).AccessoryTag == AccessoryTag.HalfVTConsumption)
|
||||
reduceOnTick = !reduceOnTick;
|
||||
if (VTComponent.CurrentVT.Value > 0)
|
||||
{
|
||||
if (((Accessory)EquipmentComponent.EquippedAccessory.Value).AccessoryTag == AccessoryTag.HalfVTConsumption)
|
||||
reduceOnTick = !reduceOnTick;
|
||||
|
||||
HealthComponent.Heal(1);
|
||||
HealthComponent.Heal(1);
|
||||
|
||||
if (reduceOnTick)
|
||||
VTComponent.Reduce(1);
|
||||
}
|
||||
else
|
||||
HealthComponent.Damage(1);
|
||||
if (reduceOnTick)
|
||||
VTComponent.Reduce(1);
|
||||
}
|
||||
else
|
||||
HealthComponent.Damage(1);
|
||||
}
|
||||
|
||||
private void Hitbox_AreaEntered(Area3D area)
|
||||
{
|
||||
var target = area.GetOwner();
|
||||
if (target is IEnemy enemy)
|
||||
HitEnemy(enemy);
|
||||
var target = area.GetOwner();
|
||||
if (target is IEnemy enemy)
|
||||
HitEnemy(enemy);
|
||||
}
|
||||
|
||||
private void HitEnemy(IEnemy enemy)
|
||||
{
|
||||
var ignoreElementalResistance = (EquipmentComponent.EquippedWeapon.Value as Weapon).WeaponTag == WeaponTag.IgnoreAffinity;
|
||||
var ignoreDefense = (EquipmentComponent.EquippedWeapon.Value as Weapon).WeaponTag == WeaponTag.IgnoreDefense;
|
||||
var isCriticalHit = BattleExtensions.IsCriticalHit(LuckComponent.Luck.Value + EquipmentComponent.BonusLuck);
|
||||
var totalDamage = AttackComponent.CurrentAttack.Value + EquipmentComponent.BonusAttack;
|
||||
var element = (EquipmentComponent.EquippedWeapon.Value as Weapon).WeaponElement;
|
||||
var ignoreElementalResistance = (EquipmentComponent.EquippedWeapon.Value as Weapon).WeaponTag == WeaponTag.IgnoreAffinity;
|
||||
var ignoreDefense = (EquipmentComponent.EquippedWeapon.Value as Weapon).WeaponTag == WeaponTag.IgnoreDefense;
|
||||
var isCriticalHit = BattleExtensions.IsCriticalHit(LuckComponent.Luck.Value + EquipmentComponent.BonusLuck);
|
||||
var totalDamage = AttackComponent.CurrentAttack.Value + EquipmentComponent.BonusAttack;
|
||||
var element = (EquipmentComponent.EquippedWeapon.Value as Weapon).WeaponElement;
|
||||
|
||||
if (isCriticalHit)
|
||||
totalDamage += (int)(totalDamage * 0.5f);
|
||||
if (isCriticalHit)
|
||||
totalDamage += (int)(totalDamage * 0.5f);
|
||||
|
||||
var baseAttack = new AttackData(totalDamage, element, ignoreDefense, ignoreElementalResistance);
|
||||
var damageDealt = DamageCalculator.CalculateDamage(baseAttack, enemy.DefenseComponent.CurrentDefense.Value, ElementalResistanceSet.None);
|
||||
enemy.HealthComponent.Damage(damageDealt);
|
||||
var baseAttack = new AttackData(totalDamage, element, ignoreDefense, ignoreElementalResistance);
|
||||
var damageDealt = DamageCalculator.CalculateDamage(baseAttack, enemy.DefenseComponent.CurrentDefense.Value, ElementalResistanceSet.None);
|
||||
enemy.HealthComponent.Damage(damageDealt);
|
||||
|
||||
if (((Weapon)EquipmentComponent.EquippedWeapon.Value).WeaponTag == WeaponTag.Knockback && enemy is IKnockbackable knockbackable)
|
||||
knockbackable.Knockback(0.3f, -CurrentBasis.Z.Normalized());
|
||||
if (((Weapon)EquipmentComponent.EquippedWeapon.Value).WeaponTag == WeaponTag.SelfDamage)
|
||||
HealthComponent.Damage(5);
|
||||
if (((Weapon)EquipmentComponent.EquippedWeapon.Value).WeaponTag == WeaponTag.Knockback && enemy is IKnockbackable knockbackable)
|
||||
knockbackable.Knockback(0.3f, -CurrentBasis.Z.Normalized());
|
||||
if (((Weapon)EquipmentComponent.EquippedWeapon.Value).WeaponTag == WeaponTag.SelfDamage)
|
||||
HealthComponent.Damage(5);
|
||||
}
|
||||
|
||||
private void CollisionDetector_AreaEntered(Area3D area)
|
||||
{
|
||||
if (area.GetParent() is InventoryItem inventoryItem)
|
||||
{
|
||||
var isAdded = Inventory.PickUpItem(inventoryItem);
|
||||
if (isAdded)
|
||||
inventoryItem.QueueFree();
|
||||
}
|
||||
if (area.GetParent() is DroppedItem droppedItem)
|
||||
{
|
||||
var isAdded = Inventory.PickUpItem(droppedItem.Item);
|
||||
if (isAdded)
|
||||
droppedItem.QueueFree();
|
||||
}
|
||||
if (area.GetParent() is ThrownItem thrownItem)
|
||||
{
|
||||
var isAdded = Inventory.PickUpItem(thrownItem.ItemThatIsThrown);
|
||||
if (isAdded)
|
||||
thrownItem.QueueFree();
|
||||
}
|
||||
if (area.GetParent() is Restorative restorative)
|
||||
{
|
||||
//_gameRepo.OnRestorativePickedUp(restorative);
|
||||
restorative.QueueFree();
|
||||
}
|
||||
if (area.GetParent() is InventoryItem inventoryItem)
|
||||
{
|
||||
var isAdded = Inventory.PickUpItem(inventoryItem);
|
||||
if (isAdded)
|
||||
inventoryItem.QueueFree();
|
||||
}
|
||||
if (area.GetParent() is DroppedItem droppedItem)
|
||||
{
|
||||
var isAdded = Inventory.PickUpItem(droppedItem.Item);
|
||||
if (isAdded)
|
||||
droppedItem.QueueFree();
|
||||
}
|
||||
if (area.GetParent() is ThrownItem thrownItem)
|
||||
{
|
||||
var isAdded = Inventory.PickUpItem(thrownItem.ItemThatIsThrown);
|
||||
if (isAdded)
|
||||
thrownItem.QueueFree();
|
||||
}
|
||||
if (area.GetParent() is Restorative restorative)
|
||||
{
|
||||
//_gameRepo.OnRestorativePickedUp(restorative);
|
||||
restorative.QueueFree();
|
||||
}
|
||||
}
|
||||
|
||||
private bool PlayerIsHittingGeometry()
|
||||
{
|
||||
var collisions = WallCheck.GetCollidingBodies();
|
||||
return collisions.Count > 0;
|
||||
var collisions = WallCheck.GetCollidingBodies();
|
||||
return collisions.Count > 0;
|
||||
}
|
||||
|
||||
private void WallCheck_BodyEntered(Node body)
|
||||
{
|
||||
GD.Print("Hit wall");
|
||||
AnimationPlayer.Stop();
|
||||
GD.Print("Hit wall");
|
||||
AnimationPlayer.Stop();
|
||||
}
|
||||
}
|
||||
|
||||
3
Zennysoft.Game.Ma/src/ui/ButtonShortcut.tres
Normal file
3
Zennysoft.Game.Ma/src/ui/ButtonShortcut.tres
Normal file
@@ -0,0 +1,3 @@
|
||||
[gd_resource type="Shortcut" format=3 uid="uid://dumkrjur22k2a"]
|
||||
|
||||
[resource]
|
||||
@@ -5,8 +5,8 @@ using Godot.Collections;
|
||||
namespace Zennysoft.Game.Ma;
|
||||
public partial class DialogueBalloon : CanvasLayer
|
||||
{
|
||||
[Export] public string NextAction = "ui_accept";
|
||||
[Export] public string SkipAction = "ui_cancel";
|
||||
[Export] public string NextAction = GameInputs.Interact;
|
||||
[Export] public string SkipAction = GameInputs.Attack;
|
||||
|
||||
|
||||
Control balloon;
|
||||
|
||||
@@ -44,9 +44,9 @@ public partial class InGameUI : Control, IInGameUI
|
||||
|
||||
InGameUILogicBinding
|
||||
.Handle((in InGameUILogic.Output.AnnounceMessageOnMainScreen output) => { InventoryMessageUI.DisplayMessage(output.Message); })
|
||||
.Handle((in InGameUILogic.Output.AnnounceMessageInInventory output) => { InventoryMenu.DisplayMessage(output.Message); })
|
||||
.Handle((in InGameUILogic.Output.RemoveItemFromInventory output) => { InventoryMenu.RemoveItem(output.Item); })
|
||||
.Handle((in InGameUILogic.Output.ShowInventory _) => { InventoryMenu.RefreshInventoryScreen(); InventoryMenu.Show(); InventoryMenu.SetProcessInput(true); })
|
||||
.Handle((in InGameUILogic.Output.AnnounceMessageInInventory output) => { })
|
||||
.Handle((in InGameUILogic.Output.RemoveItemFromInventory output) => { })
|
||||
.Handle((in InGameUILogic.Output.ShowInventory _) => { InventoryMenu.Show(); InventoryMenu.SetProcessInput(true); })
|
||||
.Handle((in InGameUILogic.Output.HideInventory _) => { CloseInventory(); });
|
||||
|
||||
InGameUILogic.Start();
|
||||
@@ -60,7 +60,7 @@ public partial class InGameUI : Control, IInGameUI
|
||||
|
||||
public override void _UnhandledInput(InputEvent @event)
|
||||
{
|
||||
if (@event.IsActionPressed(GameInputs.Inventory))
|
||||
if (@event.IsActionPressed(GameInputs.Inventory) && !InventoryMenu.Visible)
|
||||
{
|
||||
GD.Print("Inventory button pressed");
|
||||
InGameUILogic.Input(new InGameUILogic.Input.ShowInventory());
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
using Chickensoft.GodotNodeInterfaces;
|
||||
|
||||
namespace Zennysoft.Game.Ma;
|
||||
|
||||
public interface IInventoryMenu : IControl
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
uid://nhhwcce8ma3a
|
||||
@@ -1,18 +1,19 @@
|
||||
using Chickensoft.Collections;
|
||||
using Chickensoft.GodotNodeInterfaces;
|
||||
using Zennysoft.Game.Implementation;
|
||||
using System;
|
||||
using Zennysoft.Ma.Adapter;
|
||||
|
||||
namespace Zennysoft.Game.Ma;
|
||||
|
||||
public interface IItemSlot : IHBoxContainer
|
||||
public interface IItemSlot : IButton
|
||||
{
|
||||
public InventoryItem Item { get; set; }
|
||||
public AutoProp<InventoryItem> Item { get; }
|
||||
|
||||
public bool IsSelected { get; set; }
|
||||
|
||||
public void SetItemStyle();
|
||||
|
||||
public void SetSelectedItemStyle();
|
||||
|
||||
public void SetEquippedItemStyle();
|
||||
|
||||
public void SetEquippedSelectedItemStyle();
|
||||
public event Action<InventoryItem> ItemPressed;
|
||||
public event Action<IItemSlot> ItemEnterFocus;
|
||||
public event Action<IItemSlot> ItemExitFocus;
|
||||
}
|
||||
|
||||
@@ -1,32 +1,52 @@
|
||||
using Chickensoft.AutoInject;
|
||||
using Chickensoft.GodotNodeInterfaces;
|
||||
using Chickensoft.Introspection;
|
||||
using Godot;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Zennysoft.Ma.Adapter;
|
||||
|
||||
namespace Zennysoft.Game.Ma;
|
||||
|
||||
public interface IInventoryMenu : IControl
|
||||
{
|
||||
public Task RefreshInventoryScreen();
|
||||
|
||||
public Task DisplayMessage(string message);
|
||||
|
||||
public void RemoveItem(InventoryItem item);
|
||||
}
|
||||
|
||||
[Meta(typeof(IAutoNode))]
|
||||
public partial class InventoryMenu : Control, IInventoryMenu
|
||||
{
|
||||
public override void _Notification(int what) => this.Notify(what);
|
||||
|
||||
[Node] public VBoxContainer ItemsPage { get; set; }
|
||||
|
||||
[Node] public Label ATKValue { get; set; }
|
||||
[Node] public Label ATKBonusLabel { get; set; }
|
||||
[Node] public Label DEFValue { get; set; }
|
||||
[Node] public Label DEFBonusLabel { get; set; }
|
||||
|
||||
[Node] public Button UseButton { get; set; }
|
||||
[Node] public Button ThrowButton { get; set; }
|
||||
[Node] public Button DropButton { get; set; }
|
||||
|
||||
[Node] public Label ItemDescriptionTitle { get; set; }
|
||||
[Node] public Label UseItemPrompt { get; set; }
|
||||
[Node] public Label ItemEffectLabel { get; set; }
|
||||
|
||||
[Node] public Label BackArrow { get; set; } = default!;
|
||||
[Node] public Label ForwardArrow { get; set; } = default!;
|
||||
|
||||
[Node] public ItemSlot ItemSlot1 { get; set; }
|
||||
[Node] public ItemSlot ItemSlot2 { get; set; }
|
||||
[Node] public ItemSlot ItemSlot3 { get; set; }
|
||||
[Node] public ItemSlot ItemSlot4 { get; set; }
|
||||
[Node] public ItemSlot ItemSlot5 { get; set; }
|
||||
[Node] public ItemSlot ItemSlot6 { get; set; }
|
||||
[Node] public ItemSlot ItemSlot7 { get; set; }
|
||||
[Node] public ItemSlot ItemSlot8 { get; set; }
|
||||
[Node] public ItemSlot ItemSlot9 { get; set; }
|
||||
[Node] public ItemSlot ItemSlot10 { get; set; }
|
||||
|
||||
[Dependency] private IPlayer _player => this.DependOn<IPlayer>();
|
||||
[Dependency] private IGame _game => this.DependOn<IGame>();
|
||||
[Dependency] private IGameRepo _gameRepo => this.DependOn<IGameRepo>();
|
||||
|
||||
[Dependency] public IGame Game => this.DependOn<IGame>();
|
||||
|
||||
[Dependency] public IPlayer Player => this.DependOn<IPlayer>();
|
||||
private List<IItemSlot> ItemSlots;
|
||||
|
||||
private InventoryPageNumber _currentPageNumber = InventoryPageNumber.FirstPage;
|
||||
|
||||
@@ -34,203 +54,208 @@ public partial class InventoryMenu : Control, IInventoryMenu
|
||||
|
||||
private const int _itemsPerPage = 10;
|
||||
|
||||
private int _currentIndex = 0;
|
||||
private IItemSlot _currentlySelectedItem = null;
|
||||
|
||||
private IItemSlot[] ItemSlots => [.. ItemsPage.GetChildren().OfType<IItemSlot>()];
|
||||
|
||||
#region Control Nodes
|
||||
[Node] public Label ATKValue { get; set; } = default!;
|
||||
[Node] public Label ATKBonusLabel { get; set; } = default!;
|
||||
[Node] public Label DEFValue { get; set; } = default!;
|
||||
[Node] public Label DEFBonusLabel { get; set; } = default!;
|
||||
[Node] public Label ItemDescriptionTitle { get; set; } = default!;
|
||||
[Node] public Label ItemEffectLabel { get; set; } = default!;
|
||||
|
||||
// Item Menu
|
||||
[Node] public Label BackArrow { get; set; } = default!;
|
||||
[Node] public Label ForwardArrow { get; set; } = default!;
|
||||
[Node] public Control ItemsPage { get; set; } = default!;
|
||||
|
||||
// User Prompt Menu
|
||||
[Node] public Label UseItemPrompt { get; set; } = default!;
|
||||
[Node] public Button UseButton { get; set; } = default!;
|
||||
[Node] public Button ThrowButton { get; set; } = default!;
|
||||
[Node] public Button DropButton { get; set; } = default!;
|
||||
|
||||
[Node] public AnimationPlayer AnimationPlayer { get; set; } = default!;
|
||||
#endregion
|
||||
|
||||
public InventoryMenu()
|
||||
public override void _EnterTree()
|
||||
{
|
||||
SetProcessInput(false);
|
||||
SetProcess(false);
|
||||
}
|
||||
|
||||
public void OnResolved()
|
||||
{
|
||||
ItemSlots = [ItemSlot1, ItemSlot2, ItemSlot3, ItemSlot4, ItemSlot5, ItemSlot6, ItemSlot7, ItemSlot8, ItemSlot9, ItemSlot10];
|
||||
_currentlySelectedItem = ItemSlot1;
|
||||
foreach (var item in ItemSlots)
|
||||
{
|
||||
item.ItemPressed += Item_Pressed;
|
||||
item.ItemEnterFocus += Item_FocusEntered;
|
||||
item.ItemExitFocus += Item_ItemExitFocus;
|
||||
}
|
||||
|
||||
_player.AttackComponent.CurrentAttack.Sync += Attack_Sync;
|
||||
_player.AttackComponent.MaximumAttack.Sync += Attack_Sync;
|
||||
_player.DefenseComponent.CurrentDefense.Sync += Defense_Sync;
|
||||
_player.DefenseComponent.MaximumDefense.Sync += Defense_Sync;
|
||||
_player.EquipmentComponent.EquipmentChanged += EquipmentComponent_EquipmentChanged;
|
||||
_player.Inventory.InventoryChanged += Inventory_InventoryChanged;
|
||||
|
||||
UseButton.Pressed += UseButtonPressed;
|
||||
ThrowButton.Pressed += ThrowButtonPressed;
|
||||
DropButton.Pressed += DropButtonPressed;
|
||||
Player.AttackComponent.CurrentAttack.Sync += AttackSync;
|
||||
Player.AttackComponent.MaximumAttack.Sync += AttackSync;
|
||||
Player.EquipmentComponent.EquippedWeapon.Sync += BonusSync;
|
||||
Player.EquipmentComponent.EquippedArmor.Sync += BonusSync;
|
||||
Player.EquipmentComponent.EquippedAccessory.Sync += BonusSync;
|
||||
Player.DefenseComponent.CurrentDefense.Sync += DefenseSync;
|
||||
Player.DefenseComponent.MaximumDefense.Sync += DefenseSync;
|
||||
|
||||
VisibilityChanged += InventoryMenu2_VisibilityChanged;
|
||||
}
|
||||
|
||||
public void OnExitTree()
|
||||
{
|
||||
Player.AttackComponent.CurrentAttack.Sync -= AttackSync;
|
||||
Player.AttackComponent.MaximumAttack.Sync -= AttackSync;
|
||||
Player.EquipmentComponent.EquippedWeapon.Sync -= BonusSync;
|
||||
Player.EquipmentComponent.EquippedArmor.Sync -= BonusSync;
|
||||
Player.EquipmentComponent.EquippedAccessory.Sync -= BonusSync;
|
||||
Player.DefenseComponent.CurrentDefense.Sync -= DefenseSync;
|
||||
Player.DefenseComponent.MaximumDefense.Sync -= DefenseSync;
|
||||
}
|
||||
|
||||
public async Task DisplayMessage(string message)
|
||||
{
|
||||
SetProcessInput(false);
|
||||
await HideUserActionPrompt();
|
||||
await ShowInventoryInfo();
|
||||
ItemEffectLabel.Text = message;
|
||||
await ToSignal(GetTree().CreateTimer(1f), "timeout");
|
||||
await RefreshInventoryScreen();
|
||||
SetProcessInput(true);
|
||||
}
|
||||
|
||||
private void AttackSync(int obj) => ATKValue.Text = $"{Player.AttackComponent.CurrentAttack.Value}/{Player.AttackComponent.MaximumAttack.Value}";
|
||||
|
||||
private void BonusSync(EquipableItem equip)
|
||||
{
|
||||
ATKBonusLabel.Text = $"{Player.EquipmentComponent.BonusAttack:+0;-#;\\.\\.\\.}";
|
||||
DEFBonusLabel.Text = $"{Player.EquipmentComponent.BonusDefense:+0;-#;\\.\\.\\.}";
|
||||
}
|
||||
|
||||
private void DefenseSync(int obj) => DEFValue.Text = $"{Player.DefenseComponent.CurrentDefense.Value}/{Player.DefenseComponent.MaximumDefense.Value}";
|
||||
|
||||
public async Task RefreshInventoryScreen()
|
||||
{
|
||||
await ClearItems();
|
||||
PopulateInventory();
|
||||
PopulatePlayerInfo();
|
||||
await HideUserActionPrompt();
|
||||
await ShowInventoryInfo();
|
||||
}
|
||||
|
||||
#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)
|
||||
{
|
||||
if (@event.IsActionPressed(GameInputs.UiCancel))
|
||||
{
|
||||
if (UseButton.HasFocus() || DropButton.HasFocus() || ThrowButton.HasFocus())
|
||||
{
|
||||
HideUserActionPrompt();
|
||||
ShowInventoryInfo();
|
||||
Autoload.AudioManager.Play(SoundEffect.Cancel);
|
||||
}
|
||||
else
|
||||
{
|
||||
Autoload.AudioManager.Play(SoundEffect.Cancel);
|
||||
_gameRepo.CloseInventory();
|
||||
}
|
||||
}
|
||||
|
||||
if (ItemSlots.Length == 0 || UseButton.HasFocus() || DropButton.HasFocus() || ThrowButton.HasFocus())
|
||||
if (!Visible)
|
||||
return;
|
||||
|
||||
if (@event.IsActionPressed(GameInputs.UiRight) && _currentPageNumber == InventoryPageNumber.FirstPage)
|
||||
if (Input.IsActionJustPressed(GameInputs.Inventory) && !(UseButton.HasFocus() || DropButton.HasFocus() || ThrowButton.HasFocus()))
|
||||
{
|
||||
var inventory = Player.Inventory;
|
||||
if (inventory.Items.Count > _itemsPerPage)
|
||||
ChangeInventoryPage(InventoryPageNumber.SecondPage);
|
||||
AcceptEvent();
|
||||
_gameRepo.CloseInventory();
|
||||
}
|
||||
if (Input.IsActionJustPressed(GameInputs.UiCancel) && (UseButton.HasFocus() || DropButton.HasFocus() || ThrowButton.HasFocus()))
|
||||
{
|
||||
AcceptEvent();
|
||||
HideUserActionPrompt();
|
||||
}
|
||||
else if (Input.IsActionJustPressed(GameInputs.UiCancel))
|
||||
{
|
||||
AcceptEvent();
|
||||
_gameRepo.CloseInventory();
|
||||
}
|
||||
if (_currentPageNumber == InventoryPageNumber.FirstPage && _player.Inventory.Items.Count > 10 && Input.IsActionJustPressed(GameInputs.MoveRight))
|
||||
{
|
||||
_currentPageNumber = InventoryPageNumber.SecondPage;
|
||||
Inventory_InventoryChanged();
|
||||
_currentlySelectedItem = ItemSlot1;
|
||||
ItemSlot1.GrabFocus();
|
||||
}
|
||||
else if (_currentPageNumber == InventoryPageNumber.SecondPage && Input.IsActionJustPressed(GameInputs.MoveLeft))
|
||||
{
|
||||
_currentPageNumber = InventoryPageNumber.FirstPage;
|
||||
Inventory_InventoryChanged();
|
||||
_currentlySelectedItem = ItemSlot1;
|
||||
ItemSlot1.GrabFocus();
|
||||
}
|
||||
|
||||
if (@event.IsActionPressed(GameInputs.UiLeft) && _currentPageNumber == InventoryPageNumber.SecondPage)
|
||||
ChangeInventoryPage(InventoryPageNumber.FirstPage);
|
||||
|
||||
if (@event.IsActionPressed(GameInputs.UiDown))
|
||||
if (Input.IsActionJustPressed(GameInputs.InventorySort))
|
||||
{
|
||||
var oldIndex = _currentIndex;
|
||||
var newIndex = new[] { _currentIndex + 1, _itemsPerPage - 1, ItemSlots.Length - 1 }.Min();
|
||||
if (oldIndex == newIndex)
|
||||
return;
|
||||
|
||||
SetToUnselectedStyle(ItemSlots.ElementAt(oldIndex));
|
||||
SetToSelectedStyle(ItemSlots.ElementAt(newIndex));
|
||||
Autoload.AudioManager.Play(SoundEffect.MoveThroughOptions);
|
||||
_currentIndex = newIndex;
|
||||
}
|
||||
|
||||
if (@event.IsActionPressed(GameInputs.UiUp))
|
||||
{
|
||||
var oldIndex = _currentIndex;
|
||||
var newIndex = new[] { _currentIndex - 1, 0 }.Max();
|
||||
|
||||
if (oldIndex == newIndex)
|
||||
return;
|
||||
|
||||
SetToUnselectedStyle(ItemSlots.ElementAt(oldIndex));
|
||||
SetToSelectedStyle(ItemSlots.ElementAt(newIndex));
|
||||
Autoload.AudioManager.Play(SoundEffect.MoveThroughOptions);
|
||||
_currentIndex = newIndex;
|
||||
}
|
||||
|
||||
if (@event.IsActionPressed(GameInputs.UiAccept))
|
||||
{
|
||||
DisplayUserActionPrompt();
|
||||
Autoload.AudioManager.Play(SoundEffect.Select);
|
||||
}
|
||||
|
||||
if (@event.IsActionPressed(GameInputs.InventorySort))
|
||||
{
|
||||
var inventory = Player.Inventory;
|
||||
inventory.Sort(Player.EquipmentComponent.EquippedWeapon.Value, Player.EquipmentComponent.EquippedArmor.Value, Player.EquipmentComponent.EquippedAccessory.Value);
|
||||
if (_currentIndex > inventory.Items.Count - 1)
|
||||
_currentIndex = inventory.Items.Count - 1;
|
||||
RefreshInventoryScreen();
|
||||
_player.Inventory.Sort(_player.EquipmentComponent.EquippedWeapon.Value, _player.EquipmentComponent.EquippedArmor.Value, _player.EquipmentComponent.EquippedAccessory.Value);
|
||||
Inventory_InventoryChanged();
|
||||
foreach (var slot in ItemSlots)
|
||||
slot.SetItemStyle();
|
||||
Item_ItemExitFocus(_currentlySelectedItem);
|
||||
_currentlySelectedItem = ItemSlot1;
|
||||
_currentlySelectedItem.GrabFocus();
|
||||
}
|
||||
}
|
||||
#pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
|
||||
|
||||
public async void RemoveItem(InventoryItem item)
|
||||
private void InventoryMenu2_VisibilityChanged()
|
||||
{
|
||||
Player.Inventory.Remove(item);
|
||||
if (_currentIndex >= ItemSlots.Length - 1)
|
||||
_currentIndex--;
|
||||
if (_currentIndex <= 0)
|
||||
_currentIndex = 0;
|
||||
_currentlySelectedItem.GrabFocus();
|
||||
}
|
||||
|
||||
private void PopulateItems()
|
||||
private void Item_ItemExitFocus(IItemSlot itemSlot)
|
||||
{
|
||||
PopulateInventory();
|
||||
PopulatePlayerInfo();
|
||||
}
|
||||
|
||||
private async Task ClearItems()
|
||||
{
|
||||
foreach (var item in ItemSlots)
|
||||
ItemsPage.RemoveChildEx(item);
|
||||
|
||||
ItemDescriptionTitle.Text = string.Empty;
|
||||
ItemEffectLabel.Text = string.Empty;
|
||||
itemSlot.IsSelected = false;
|
||||
itemSlot.SetItemStyle();
|
||||
}
|
||||
|
||||
private void PopulatePlayerInfo()
|
||||
private void Item_FocusEntered(IItemSlot itemSlot)
|
||||
{
|
||||
if (ItemSlots.Length != 0)
|
||||
if (itemSlot.Item.Value == null)
|
||||
return;
|
||||
|
||||
ItemDescriptionTitle.Text = $"{itemSlot.Item.Value.ItemName}";
|
||||
ItemEffectLabel.Text = $"{itemSlot.Item.Value.Description}";
|
||||
_currentlySelectedItem = itemSlot;
|
||||
itemSlot.IsSelected = true;
|
||||
itemSlot.SetItemStyle();
|
||||
}
|
||||
|
||||
private void Item_Pressed(InventoryItem item) => DisplayUserActionPrompt(item);
|
||||
|
||||
private async void Inventory_InventoryChanged()
|
||||
{
|
||||
foreach (var slot in ItemSlots)
|
||||
{
|
||||
var item = ItemSlots.ElementAt(_currentIndex).Item;
|
||||
ItemDescriptionTitle.Text = $"{item.ItemName}";
|
||||
ItemEffectLabel.Text = $"{item.Description}";
|
||||
slot.Visible = false;
|
||||
slot.SetItemStyle();
|
||||
}
|
||||
|
||||
if (_currentPageNumber == InventoryPageNumber.SecondPage && _player.Inventory.Items.Count <= 10)
|
||||
{
|
||||
_currentPageNumber = InventoryPageNumber.FirstPage;
|
||||
var elementToSelect = _player.Inventory.Items.IndexOf(_player.Inventory.Items.Last());
|
||||
_currentlySelectedItem = ItemSlots.ElementAt(elementToSelect);
|
||||
_currentlySelectedItem.GrabFocus();
|
||||
}
|
||||
|
||||
var itemsToDisplay = new List<InventoryItem>();
|
||||
if (_currentPageNumber == InventoryPageNumber.FirstPage)
|
||||
itemsToDisplay = [.. _player.Inventory.Items.Take(_itemsPerPage)];
|
||||
else
|
||||
itemsToDisplay = [.. _player.Inventory.Items.TakeLast(_player.Inventory.Items.Count - _itemsPerPage)];
|
||||
|
||||
for (var i = 0; i < itemsToDisplay.Count; i++)
|
||||
{
|
||||
ItemSlots[i].Item.OnNext(itemsToDisplay[i]);
|
||||
ItemSlots[i].Visible = true;
|
||||
}
|
||||
|
||||
SetPageIndicators();
|
||||
|
||||
if (!_player.Inventory.Items.Contains(_currentlySelectedItem.Item.Value))
|
||||
{
|
||||
_currentlySelectedItem.Item.OnNext(null);
|
||||
var elementToSelect = Mathf.Max(0, ItemSlots.IndexOf(_currentlySelectedItem) - 1);
|
||||
_currentlySelectedItem = ItemSlots.ElementAt(elementToSelect);
|
||||
_currentlySelectedItem.GrabFocus();
|
||||
}
|
||||
}
|
||||
|
||||
private void DisplayUserActionPrompt()
|
||||
private void SetPageIndicators()
|
||||
{
|
||||
if (_player.Inventory.Items.Count > 10 && _currentPageNumber == InventoryPageNumber.FirstPage)
|
||||
{
|
||||
ForwardArrow.Text = "►";
|
||||
BackArrow.Text = "";
|
||||
}
|
||||
else if (_player.Inventory.Items.Count > 10 && _currentPageNumber == InventoryPageNumber.SecondPage)
|
||||
{
|
||||
ForwardArrow.Text = "";
|
||||
BackArrow.Text = "◄";
|
||||
}
|
||||
}
|
||||
|
||||
private void Attack_Sync(int obj) => ATKValue.Text = $"{_player.AttackComponent.CurrentAttack.Value}/{_player.AttackComponent.MaximumAttack.Value}";
|
||||
private void Defense_Sync(int obj) => DEFValue.Text = $"{_player.DefenseComponent.CurrentDefense.Value}/{_player.DefenseComponent.MaximumDefense.Value}";
|
||||
|
||||
private void EquipmentComponent_EquipmentChanged(EquipableItem equipableItem)
|
||||
{
|
||||
ATKBonusLabel.Text = $"{_player.EquipmentComponent.BonusAttack:+0;-#;\\.\\.\\.}";
|
||||
DEFBonusLabel.Text = $"{_player.EquipmentComponent.BonusDefense:+0;-#;\\.\\.\\.}";
|
||||
}
|
||||
|
||||
private async void UseButtonPressed()
|
||||
{
|
||||
UseButton.Disabled = true;
|
||||
if (_currentlySelectedItem.Item.Value is EquipableItem equipable)
|
||||
await EquipOrUnequipItem(equipable);
|
||||
else
|
||||
await _game.UseItem(_currentlySelectedItem.Item.Value);
|
||||
UseButton.Disabled = false;
|
||||
|
||||
|
||||
HideUserActionPrompt();
|
||||
await ShowInventoryInfo();
|
||||
await ToSignal(GetTree().CreateTimer(1f), "timeout");
|
||||
}
|
||||
|
||||
private async void ThrowButtonPressed()
|
||||
{
|
||||
_game.ThrowItem(_currentlySelectedItem.Item.Value);
|
||||
_player.Inventory.Remove(_currentlySelectedItem.Item.Value);
|
||||
HideUserActionPrompt();
|
||||
await ShowInventoryInfo();
|
||||
_gameRepo.CloseInventory();
|
||||
}
|
||||
|
||||
private async void DropButtonPressed()
|
||||
{
|
||||
_game.DropItem(_currentlySelectedItem.Item.Value);
|
||||
_player.Inventory.Remove(_currentlySelectedItem.Item.Value);
|
||||
HideUserActionPrompt();
|
||||
await ShowInventoryInfo();
|
||||
_gameRepo.CloseInventory();
|
||||
}
|
||||
|
||||
private void DisplayUserActionPrompt(InventoryItem item)
|
||||
{
|
||||
ItemDescriptionTitle.Hide();
|
||||
ItemEffectLabel.Hide();
|
||||
@@ -239,11 +264,9 @@ public partial class InventoryMenu : Control, IInventoryMenu
|
||||
ThrowButton.Show();
|
||||
DropButton.Show();
|
||||
|
||||
var currentItem = ItemSlots.ElementAt(_currentIndex).Item;
|
||||
|
||||
if (currentItem is EquipableItem equipable)
|
||||
if (item is EquipableItem equipable)
|
||||
{
|
||||
var isItemEquipped = Player.EquipmentComponent.IsItemEquipped(equipable);
|
||||
var isItemEquipped = _player.EquipmentComponent.IsItemEquipped(equipable);
|
||||
UseButton.Text = isItemEquipped ? "Unequip" : "Equip";
|
||||
ThrowButton.Disabled = isItemEquipped;
|
||||
ThrowButton.FocusMode = isItemEquipped ? FocusModeEnum.None : FocusModeEnum.All;
|
||||
@@ -258,7 +281,7 @@ public partial class InventoryMenu : Control, IInventoryMenu
|
||||
UseButton.CallDeferred(MethodName.GrabFocus);
|
||||
}
|
||||
|
||||
private async Task HideUserActionPrompt()
|
||||
private void HideUserActionPrompt()
|
||||
{
|
||||
UseItemPrompt.Hide();
|
||||
UseButton.Hide();
|
||||
@@ -267,6 +290,23 @@ public partial class InventoryMenu : Control, IInventoryMenu
|
||||
UseButton.ReleaseFocus();
|
||||
ThrowButton.ReleaseFocus();
|
||||
DropButton.ReleaseFocus();
|
||||
_currentlySelectedItem.GrabFocus();
|
||||
}
|
||||
|
||||
private async Task EquipOrUnequipItem(EquipableItem equipable)
|
||||
{
|
||||
if (_player.EquipmentComponent.IsItemEquipped(equipable))
|
||||
{
|
||||
ItemEffectLabel.Text = $"{equipable.GetType().Name} unequipped.";
|
||||
_player.Unequip(equipable);
|
||||
}
|
||||
else
|
||||
{
|
||||
var itemSlot = _currentlySelectedItem;
|
||||
ItemEffectLabel.Text = $"{equipable.GetType().Name} equipped.";
|
||||
_player.Equip(equipable);
|
||||
_currentlySelectedItem = itemSlot;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task ShowInventoryInfo()
|
||||
@@ -275,149 +315,6 @@ public partial class InventoryMenu : Control, IInventoryMenu
|
||||
ItemEffectLabel.Show();
|
||||
}
|
||||
|
||||
private async Task ChangeInventoryPage(InventoryPageNumber pageToChangeTo)
|
||||
{
|
||||
await ClearItems();
|
||||
await ToSignal(GetTree().CreateTimer(0.1f), "timeout");
|
||||
_currentIndex = 0;
|
||||
_currentPageNumber = pageToChangeTo;
|
||||
await RefreshInventoryScreen();
|
||||
Autoload.AudioManager.Play(SoundEffect.MoveThroughOptions);
|
||||
}
|
||||
|
||||
private async void PopulateInventory()
|
||||
{
|
||||
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;
|
||||
|
||||
ForwardArrow.Text = "";
|
||||
BackArrow.Text = "";
|
||||
|
||||
if (_currentPageNumber == InventoryPageNumber.FirstPage && inventory.Items.Count > _itemsPerPage)
|
||||
{
|
||||
ForwardArrow.Text = "►";
|
||||
BackArrow.Text = "";
|
||||
}
|
||||
if (_currentPageNumber == InventoryPageNumber.SecondPage)
|
||||
{
|
||||
ForwardArrow.Text = "";
|
||||
BackArrow.Text = "◄";
|
||||
}
|
||||
|
||||
|
||||
for (var i = 0; i < numberOfItemsToDisplay; i++)
|
||||
{
|
||||
var item = inventory.Items.ElementAt(i + indexToStart);
|
||||
var itemScene = GD.Load<PackedScene>(ITEM_SLOT_SCENE);
|
||||
var itemSlot = itemScene.Instantiate<IItemSlot>();
|
||||
itemSlot.Item = item;
|
||||
ItemsPage.AddChildEx(itemSlot);
|
||||
|
||||
if (Player.EquipmentComponent.IsItemEquipped(itemSlot.Item))
|
||||
itemSlot.SetEquippedItemStyle();
|
||||
}
|
||||
|
||||
if (ItemSlots.Length != 0)
|
||||
{
|
||||
ItemSlots.ElementAt(_currentIndex).SetSelectedItemStyle();
|
||||
if (Player.EquipmentComponent.IsItemEquipped(ItemSlots.ElementAt(_currentIndex).Item))
|
||||
ItemSlots.ElementAt(_currentIndex).SetEquippedSelectedItemStyle();
|
||||
}
|
||||
}
|
||||
|
||||
private async Task SetToUnselectedStyle(IItemSlot itemSlot)
|
||||
{
|
||||
await ToSignal(GetTree().CreateTimer(0.1f), "timeout");
|
||||
itemSlot.SetItemStyle();
|
||||
if (Player.EquipmentComponent.IsItemEquipped(itemSlot.Item))
|
||||
itemSlot.SetEquippedItemStyle();
|
||||
}
|
||||
|
||||
private async Task SetToSelectedStyle(IItemSlot itemSlot)
|
||||
{
|
||||
await ToSignal(GetTree().CreateTimer(0.1f), "timeout");
|
||||
itemSlot.SetSelectedItemStyle();
|
||||
ItemDescriptionTitle.Text = $"{itemSlot.Item.ItemName}";
|
||||
ItemEffectLabel.Text = $"{itemSlot.Item.Description}";
|
||||
}
|
||||
|
||||
private async Task EquipOrUnequipItem()
|
||||
{
|
||||
var itemSlot = ItemSlots[_currentIndex];
|
||||
if (itemSlot.Item is not EquipableItem)
|
||||
return;
|
||||
var equippableItem = (EquipableItem)itemSlot.Item;
|
||||
if (Player.EquipmentComponent.IsItemEquipped(equippableItem))
|
||||
{
|
||||
ItemEffectLabel.Text = $"{equippableItem.GetType().Name} unequipped.";
|
||||
Player.EquipmentComponent.Unequip(equippableItem);
|
||||
itemSlot.SetSelectedItemStyle();
|
||||
if (itemSlot.Item.ItemTag == ItemTag.BreaksOnChange)
|
||||
Player.Inventory.Remove(equippableItem);
|
||||
}
|
||||
else
|
||||
{
|
||||
ItemEffectLabel.Text = $"{equippableItem.GetType().Name} equipped.";
|
||||
Player.Equip(equippableItem);
|
||||
itemSlot.SetEquippedSelectedItemStyle();
|
||||
}
|
||||
|
||||
RefreshUIAfterUserSelection();
|
||||
}
|
||||
|
||||
private async void UseButtonPressed()
|
||||
{
|
||||
UseButton.Disabled = true;
|
||||
var currentItem = ItemSlots[_currentIndex].Item;
|
||||
if (currentItem is EquipableItem)
|
||||
await EquipOrUnequipItem();
|
||||
else
|
||||
await Game.UseItem(currentItem);
|
||||
|
||||
RefreshUIAfterUserSelection();
|
||||
UseButton.Disabled = false;
|
||||
}
|
||||
|
||||
private async void ThrowButtonPressed()
|
||||
{
|
||||
var currentItem = ItemSlots[_currentIndex].Item;
|
||||
|
||||
Game.ThrowItem(currentItem);
|
||||
Player.Inventory.Remove(currentItem);
|
||||
|
||||
if (_currentIndex >= ItemSlots.Length - 1)
|
||||
_currentIndex--;
|
||||
if (_currentIndex <= 0)
|
||||
_currentIndex = 0;
|
||||
|
||||
_gameRepo.CloseInventory();
|
||||
}
|
||||
|
||||
private async void DropButtonPressed()
|
||||
{
|
||||
var currentItem = ItemSlots[_currentIndex].Item;
|
||||
Game.DropItem(currentItem);
|
||||
Player.Inventory.Remove(currentItem);
|
||||
|
||||
if (_currentIndex >= ItemSlots.Length - 1)
|
||||
_currentIndex--;
|
||||
if (_currentIndex <= 0)
|
||||
_currentIndex = 0;
|
||||
|
||||
_gameRepo.CloseInventory();
|
||||
}
|
||||
|
||||
private async void RefreshUIAfterUserSelection()
|
||||
{
|
||||
SetProcessInput(false);
|
||||
await HideUserActionPrompt();
|
||||
await ShowInventoryInfo();
|
||||
await RefreshInventoryScreen();
|
||||
await ToSignal(GetTree().CreateTimer(1f), "timeout");
|
||||
SetProcessInput(true);
|
||||
}
|
||||
|
||||
private enum InventoryPageNumber
|
||||
{
|
||||
FirstPage,
|
||||
|
||||
@@ -1 +1 @@
|
||||
uid://cmtet15hi5oiy
|
||||
uid://bi1xopts68paw
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
[gd_scene load_steps=29 format=3 uid="uid://dlj8qdg1c5048"]
|
||||
[gd_scene load_steps=27 format=3 uid="uid://dlj8qdg1c5048"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://cmtet15hi5oiy" path="res://src/ui/inventory_menu/InventoryMenu.cs" id="1_l64wl"]
|
||||
[ext_resource type="Script" uid="uid://bi1xopts68paw" path="res://src/ui/inventory_menu/InventoryMenu.cs" id="1_b6rkr"]
|
||||
[ext_resource type="Shader" uid="uid://cnphwvmr05hp1" path="res://src/ui/inventory_menu/InventoryMenu.gdshader" id="2_0fvsh"]
|
||||
[ext_resource type="FontFile" uid="uid://cm8j5vcdop5x0" path="res://src/ui/fonts/Mrs-Eaves-OT-Roman_31443.ttf" id="3_lm4o1"]
|
||||
[ext_resource type="PackedScene" uid="uid://c005nd0m2eim" path="res://src/ui/inventory_menu/ItemSlot.tscn" id="4_aiji3"]
|
||||
[ext_resource type="FontFile" uid="uid://cb41qqmxqurj8" path="res://src/ui/fonts/FT88-Bold.ttf" id="4_rg5yb"]
|
||||
[ext_resource type="FontFile" uid="uid://dit3vylt7hmmx" path="res://src/ui/fonts/FT88-Regular.ttf" id="5_2qnnx"]
|
||||
[ext_resource type="LabelSettings" uid="uid://ca1q6yu8blwxf" path="res://src/ui/label_settings/InventoryMainTextBold.tres" id="6_tmdno"]
|
||||
@@ -71,67 +72,6 @@ font_color = Color(0.737255, 0.705882, 0.690196, 1)
|
||||
|
||||
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_ct6ql"]
|
||||
|
||||
[sub_resource type="Animation" id="Animation_dg155"]
|
||||
length = 0.001
|
||||
tracks/0/type = "value"
|
||||
tracks/0/imported = false
|
||||
tracks/0/enabled = true
|
||||
tracks/0/path = NodePath("InventoryInfo/HBoxContainer/PlayerInfo/HBoxContainer/VBoxContainer/ItemEffectLabel:visible")
|
||||
tracks/0/interp = 1
|
||||
tracks/0/loop_wrap = true
|
||||
tracks/0/keys = {
|
||||
"times": PackedFloat32Array(0),
|
||||
"transitions": PackedFloat32Array(1),
|
||||
"update": 1,
|
||||
"values": [true]
|
||||
}
|
||||
tracks/1/type = "value"
|
||||
tracks/1/imported = false
|
||||
tracks/1/enabled = true
|
||||
tracks/1/path = NodePath("InventoryInfo/HBoxContainer/PlayerInfo/HBoxContainer/VBoxContainer/ItemEffectLabel:text")
|
||||
tracks/1/interp = 1
|
||||
tracks/1/loop_wrap = true
|
||||
tracks/1/keys = {
|
||||
"times": PackedFloat32Array(0),
|
||||
"transitions": PackedFloat32Array(1),
|
||||
"update": 1,
|
||||
"values": [""]
|
||||
}
|
||||
|
||||
[sub_resource type="Animation" id="Animation_7by7u"]
|
||||
resource_name = "status_up"
|
||||
length = 2.5
|
||||
tracks/0/type = "value"
|
||||
tracks/0/imported = false
|
||||
tracks/0/enabled = true
|
||||
tracks/0/path = NodePath("InventoryInfo/HBoxContainer/PlayerInfo/HBoxContainer/VBoxContainer/ItemEffectLabel:visible")
|
||||
tracks/0/interp = 1
|
||||
tracks/0/loop_wrap = true
|
||||
tracks/0/keys = {
|
||||
"times": PackedFloat32Array(0, 2.5),
|
||||
"transitions": PackedFloat32Array(1, 1),
|
||||
"update": 1,
|
||||
"values": [true, false]
|
||||
}
|
||||
tracks/1/type = "value"
|
||||
tracks/1/imported = false
|
||||
tracks/1/enabled = true
|
||||
tracks/1/path = NodePath("InventoryInfo/HBoxContainer/PlayerInfo/HBoxContainer/VBoxContainer/ItemEffectLabel:text")
|
||||
tracks/1/interp = 1
|
||||
tracks/1/loop_wrap = true
|
||||
tracks/1/keys = {
|
||||
"times": PackedFloat32Array(2.5),
|
||||
"transitions": PackedFloat32Array(1),
|
||||
"update": 1,
|
||||
"values": [""]
|
||||
}
|
||||
|
||||
[sub_resource type="AnimationLibrary" id="AnimationLibrary_eivo2"]
|
||||
_data = {
|
||||
&"RESET": SubResource("Animation_dg155"),
|
||||
&"status_up": SubResource("Animation_7by7u")
|
||||
}
|
||||
|
||||
[node name="InventoryMenu" type="Control"]
|
||||
custom_minimum_size = Vector2(1440, 1080)
|
||||
layout_mode = 3
|
||||
@@ -140,7 +80,8 @@ offset_right = 1440.0
|
||||
offset_bottom = 1080.0
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 3
|
||||
script = ExtResource("1_l64wl")
|
||||
mouse_filter = 2
|
||||
script = ExtResource("1_b6rkr")
|
||||
|
||||
[node name="BG" type="TextureRect" parent="."]
|
||||
material = SubResource("ShaderMaterial_i55tv")
|
||||
@@ -150,6 +91,7 @@ anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
mouse_filter = 2
|
||||
texture = SubResource("PlaceholderTexture2D_3ynpe")
|
||||
expand_mode = 2
|
||||
|
||||
@@ -205,7 +147,6 @@ horizontal_alignment = 2
|
||||
[node name="ItemsPage" type="VBoxContainer" parent="InventoryInfo/HBoxContainer/ItemInfo"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
size_flags_vertical = 0
|
||||
theme_override_constants/separation = 15
|
||||
alignment = 1
|
||||
|
||||
@@ -213,8 +154,59 @@ alignment = 1
|
||||
custom_minimum_size = Vector2(0, 14)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="ItemSlot1" parent="InventoryInfo/HBoxContainer/ItemInfo/ItemsPage" instance=ExtResource("4_aiji3")]
|
||||
unique_name_in_owner = true
|
||||
visible = false
|
||||
layout_mode = 2
|
||||
|
||||
[node name="ItemSlot2" parent="InventoryInfo/HBoxContainer/ItemInfo/ItemsPage" instance=ExtResource("4_aiji3")]
|
||||
unique_name_in_owner = true
|
||||
visible = false
|
||||
layout_mode = 2
|
||||
|
||||
[node name="ItemSlot3" parent="InventoryInfo/HBoxContainer/ItemInfo/ItemsPage" instance=ExtResource("4_aiji3")]
|
||||
unique_name_in_owner = true
|
||||
visible = false
|
||||
layout_mode = 2
|
||||
|
||||
[node name="ItemSlot4" parent="InventoryInfo/HBoxContainer/ItemInfo/ItemsPage" instance=ExtResource("4_aiji3")]
|
||||
unique_name_in_owner = true
|
||||
visible = false
|
||||
layout_mode = 2
|
||||
|
||||
[node name="ItemSlot5" parent="InventoryInfo/HBoxContainer/ItemInfo/ItemsPage" instance=ExtResource("4_aiji3")]
|
||||
unique_name_in_owner = true
|
||||
visible = false
|
||||
layout_mode = 2
|
||||
|
||||
[node name="ItemSlot6" parent="InventoryInfo/HBoxContainer/ItemInfo/ItemsPage" instance=ExtResource("4_aiji3")]
|
||||
unique_name_in_owner = true
|
||||
visible = false
|
||||
layout_mode = 2
|
||||
|
||||
[node name="ItemSlot7" parent="InventoryInfo/HBoxContainer/ItemInfo/ItemsPage" instance=ExtResource("4_aiji3")]
|
||||
unique_name_in_owner = true
|
||||
visible = false
|
||||
layout_mode = 2
|
||||
|
||||
[node name="ItemSlot8" parent="InventoryInfo/HBoxContainer/ItemInfo/ItemsPage" instance=ExtResource("4_aiji3")]
|
||||
unique_name_in_owner = true
|
||||
visible = false
|
||||
layout_mode = 2
|
||||
|
||||
[node name="ItemSlot9" parent="InventoryInfo/HBoxContainer/ItemInfo/ItemsPage" instance=ExtResource("4_aiji3")]
|
||||
unique_name_in_owner = true
|
||||
visible = false
|
||||
layout_mode = 2
|
||||
|
||||
[node name="ItemSlot10" parent="InventoryInfo/HBoxContainer/ItemInfo/ItemsPage" instance=ExtResource("4_aiji3")]
|
||||
unique_name_in_owner = true
|
||||
visible = false
|
||||
layout_mode = 2
|
||||
|
||||
[node name="PlayerInfo" type="VBoxContainer" parent="InventoryInfo/HBoxContainer"]
|
||||
layout_mode = 2
|
||||
mouse_filter = 2
|
||||
theme_override_constants/separation = 20
|
||||
|
||||
[node name="VTBox" type="HBoxContainer" parent="InventoryInfo/HBoxContainer/PlayerInfo"]
|
||||
@@ -431,9 +423,3 @@ theme_override_styles/normal = SubResource("StyleBoxEmpty_ct6ql")
|
||||
button_mask = 0
|
||||
text = "Drop"
|
||||
alignment = 0
|
||||
|
||||
[node name="AnimationPlayer" type="AnimationPlayer" parent="."]
|
||||
unique_name_in_owner = true
|
||||
libraries = {
|
||||
&"": SubResource("AnimationLibrary_eivo2")
|
||||
}
|
||||
|
||||
@@ -1,18 +1,19 @@
|
||||
using Chickensoft.AutoInject;
|
||||
using Chickensoft.Collections;
|
||||
using Chickensoft.Introspection;
|
||||
using Godot;
|
||||
using System;
|
||||
using Zennysoft.Game.Abstractions;
|
||||
using Zennysoft.Game.Implementation;
|
||||
using Zennysoft.Ma.Adapter;
|
||||
|
||||
namespace Zennysoft.Game.Ma;
|
||||
|
||||
[Meta(typeof(IAutoNode))]
|
||||
public partial class ItemSlot : HBoxContainer, IItemSlot
|
||||
public partial class ItemSlot : Button, IItemSlot
|
||||
{
|
||||
public override void _Notification(int what) => this.Notify(what);
|
||||
|
||||
[Dependency] public IPlayer Player => this.DependOn<IPlayer>();
|
||||
[Dependency] private IPlayer _player => this.DependOn<IPlayer>();
|
||||
|
||||
[Node] public TextureRect ItemTexture { get; set; } = default!;
|
||||
|
||||
@@ -20,6 +21,8 @@ public partial class ItemSlot : HBoxContainer, IItemSlot
|
||||
|
||||
[Node] public Label ItemCount { get; set; } = default!;
|
||||
|
||||
public AutoProp<InventoryItem> Item { get; } = new AutoProp<InventoryItem>(default);
|
||||
|
||||
private static LabelSettings ItemFont => GD.Load<LabelSettings>("res://src/ui/label_settings/MainTextBold.tres");
|
||||
|
||||
private static LabelSettings SelectedItemFont => GD.Load<LabelSettings>("res://src/ui/label_settings/MainTextFontItalicized.tres");
|
||||
@@ -28,53 +31,89 @@ public partial class ItemSlot : HBoxContainer, IItemSlot
|
||||
|
||||
private static LabelSettings SelectedEquippedItemFont => GD.Load<LabelSettings>("res://src/ui/label_settings/MainTextFontSelectedEquipped.tres");
|
||||
|
||||
public void OnReady()
|
||||
{
|
||||
ItemName.Text = Item.ItemName;
|
||||
ItemTexture.Texture = Item.GetTexture();
|
||||
Player.EquipmentComponent.EquippedWeapon.Sync += EquipableItem_Sync;
|
||||
Player.EquipmentComponent.EquippedArmor.Sync += EquipableItem_Sync;
|
||||
Player.EquipmentComponent.EquippedAccessory.Sync += EquipableItem_Sync;
|
||||
public event Action<InventoryItem> ItemPressed;
|
||||
public event Action<IItemSlot> ItemEnterFocus;
|
||||
public event Action<IItemSlot> ItemExitFocus;
|
||||
|
||||
if (Item is IStackable stackableItem)
|
||||
{
|
||||
ItemCount.Text = $"{stackableItem.Count:D2}";
|
||||
ItemCount.Visible = true;
|
||||
}
|
||||
}
|
||||
public bool IsSelected { get; set; } = false;
|
||||
|
||||
private void EquipableItem_Sync(EquipableItem obj)
|
||||
public void OnResolved()
|
||||
{
|
||||
if (Item is EquipableItem equipableItem && equipableItem == obj)
|
||||
{
|
||||
SetEquippedSelectedItemStyle();
|
||||
}
|
||||
if (Item is EquipableItem unequippedItem && unequippedItem != obj)
|
||||
{
|
||||
SetItemStyle();
|
||||
}
|
||||
Item.Changed += Item_Changed;
|
||||
_player.EquipmentComponent.EquippedWeapon.Sync += EquipableItem_Sync;
|
||||
_player.EquipmentComponent.EquippedArmor.Sync += EquipableItem_Sync;
|
||||
_player.EquipmentComponent.EquippedAccessory.Sync += EquipableItem_Sync;
|
||||
|
||||
FocusEntered += ItemSlot_FocusEntered;
|
||||
FocusExited += ItemSlot_FocusExited;
|
||||
|
||||
Pressed += ItemSlot_Pressed;
|
||||
}
|
||||
|
||||
public void SetItemStyle()
|
||||
{
|
||||
ItemName.LabelSettings = ItemFont;
|
||||
if (_player.EquipmentComponent.IsItemEquipped(Item.Value) && IsSelected)
|
||||
SetEquippedSelectedItemStyle();
|
||||
else if (_player.EquipmentComponent.IsItemEquipped(Item.Value))
|
||||
SetEquippedItemStyle();
|
||||
else if (IsSelected)
|
||||
SetSelectedItemStyle();
|
||||
else
|
||||
SetToUnselectedStyle();
|
||||
}
|
||||
public void SetSelectedItemStyle()
|
||||
|
||||
public void SetToUnselectedStyle()
|
||||
{
|
||||
if (Player.EquipmentComponent.IsItemEquipped(Item))
|
||||
SetItemFont();
|
||||
if (_player.EquipmentComponent.IsItemEquipped(Item.Value))
|
||||
SetEquippedItemStyle();
|
||||
}
|
||||
|
||||
private void EquipableItem_Sync(EquipableItem item) => SetItemStyle();
|
||||
|
||||
private void ItemSlot_Pressed()
|
||||
{
|
||||
if (Item.Value == null)
|
||||
return;
|
||||
|
||||
ItemPressed?.Invoke(Item.Value);
|
||||
}
|
||||
|
||||
private void ItemSlot_FocusExited() => ItemExitFocus?.Invoke(this);
|
||||
|
||||
private void ItemSlot_FocusEntered() => ItemEnterFocus?.Invoke(this);
|
||||
|
||||
private void Item_Changed(InventoryItem obj)
|
||||
{
|
||||
if (obj == null)
|
||||
return;
|
||||
|
||||
ItemName.Text = obj.ItemName;
|
||||
ItemTexture.Texture = obj.GetTexture();
|
||||
if (obj is IStackable stackableItem)
|
||||
{
|
||||
ItemCount.Text = $"{stackableItem.Count:D2}";
|
||||
ItemCount.Visible = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
ItemCount.Text = string.Empty;
|
||||
ItemCount.Visible = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void SetToSelectedStyle() => SetSelectedItemStyle();
|
||||
|
||||
private void SetSelectedItemStyle()
|
||||
{
|
||||
if (_player.EquipmentComponent.IsItemEquipped(Item.Value))
|
||||
ItemName.LabelSettings = SelectedEquippedItemFont;
|
||||
else
|
||||
ItemName.LabelSettings = SelectedItemFont;
|
||||
}
|
||||
public void SetEquippedItemStyle()
|
||||
{
|
||||
ItemName.LabelSettings = EquippedItemFont;
|
||||
}
|
||||
private void SetItemFont() => ItemName.LabelSettings = ItemFont;
|
||||
|
||||
public void SetEquippedSelectedItemStyle()
|
||||
{
|
||||
ItemName.LabelSettings = SelectedEquippedItemFont;
|
||||
}
|
||||
private void SetEquippedItemStyle() => ItemName.LabelSettings = EquippedItemFont;
|
||||
|
||||
public InventoryItem Item { get; set; } = default!;
|
||||
private void SetEquippedSelectedItemStyle() => ItemName.LabelSettings = SelectedEquippedItemFont;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
[gd_scene load_steps=7 format=3 uid="uid://c005nd0m2eim"]
|
||||
[gd_scene load_steps=8 format=3 uid="uid://c005nd0m2eim"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://cglxk7v8hpesn" path="res://src/ui/inventory_menu/ItemSlot.cs" id="1_yttxt"]
|
||||
[ext_resource type="Texture2D" uid="uid://0r1dws4ajhdx" path="res://src/items/accessory/textures/MASK 01.PNG" id="2_7kdbd"]
|
||||
@@ -6,42 +6,65 @@
|
||||
[ext_resource type="FontFile" uid="uid://bohbd123672ea" path="res://src/ui/fonts/FT88-Italic.ttf" id="4_vcxwm"]
|
||||
[ext_resource type="LabelSettings" uid="uid://bl5xpqyq8vjtv" path="res://src/ui/inventory_menu/InventoryLabelSettings.tres" id="5_a7hko"]
|
||||
|
||||
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_lt1pw"]
|
||||
|
||||
[sub_resource type="LabelSettings" id="LabelSettings_lgjx0"]
|
||||
font = ExtResource("4_vcxwm")
|
||||
font_size = 30
|
||||
font_color = Color(0, 0.682353, 0.937255, 1)
|
||||
|
||||
[node name="ItemSlot" type="HBoxContainer"]
|
||||
[node name="ItemSlot" type="Button"]
|
||||
custom_minimum_size = Vector2(100, 60)
|
||||
offset_right = 1748.0
|
||||
offset_bottom = 85.0
|
||||
anchors_preset = -1
|
||||
anchor_right = 0.885
|
||||
anchor_bottom = 0.093
|
||||
offset_right = 0.799927
|
||||
offset_bottom = -0.440002
|
||||
theme_override_styles/focus = SubResource("StyleBoxEmpty_lt1pw")
|
||||
theme_override_styles/disabled_mirrored = SubResource("StyleBoxEmpty_lt1pw")
|
||||
theme_override_styles/disabled = SubResource("StyleBoxEmpty_lt1pw")
|
||||
theme_override_styles/hover_pressed_mirrored = SubResource("StyleBoxEmpty_lt1pw")
|
||||
theme_override_styles/hover_pressed = SubResource("StyleBoxEmpty_lt1pw")
|
||||
theme_override_styles/hover_mirrored = SubResource("StyleBoxEmpty_lt1pw")
|
||||
theme_override_styles/hover = SubResource("StyleBoxEmpty_lt1pw")
|
||||
theme_override_styles/pressed_mirrored = SubResource("StyleBoxEmpty_lt1pw")
|
||||
theme_override_styles/pressed = SubResource("StyleBoxEmpty_lt1pw")
|
||||
theme_override_styles/normal_mirrored = SubResource("StyleBoxEmpty_lt1pw")
|
||||
theme_override_styles/normal = SubResource("StyleBoxEmpty_lt1pw")
|
||||
flat = true
|
||||
alignment = 0
|
||||
script = ExtResource("1_yttxt")
|
||||
|
||||
[node name="ReferenceRect" type="ReferenceRect" parent="."]
|
||||
[node name="HBox" type="HBoxContainer" parent="."]
|
||||
custom_minimum_size = Vector2(100, 60)
|
||||
layout_mode = 0
|
||||
offset_right = 1700.0
|
||||
offset_bottom = 100.0
|
||||
|
||||
[node name="ReferenceRect" type="ReferenceRect" parent="HBox"]
|
||||
custom_minimum_size = Vector2(100, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="ItemTexture" type="TextureRect" parent="."]
|
||||
[node name="ItemTexture" type="TextureRect" parent="HBox"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
texture = ExtResource("2_7kdbd")
|
||||
expand_mode = 2
|
||||
|
||||
[node name="ReferenceRect2" type="ReferenceRect" parent="."]
|
||||
[node name="ReferenceRect2" type="ReferenceRect" parent="HBox"]
|
||||
custom_minimum_size = Vector2(40, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="ItemName" type="Label" parent="."]
|
||||
[node name="ItemName" type="Label" parent="HBox"]
|
||||
unique_name_in_owner = true
|
||||
custom_minimum_size = Vector2(550, 50)
|
||||
layout_mode = 2
|
||||
text = "Mask of the Goddess of Destruction"
|
||||
label_settings = SubResource("LabelSettings_lgjx0")
|
||||
vertical_alignment = 1
|
||||
autowrap_mode = 2
|
||||
script = ExtResource("3_xlgl0")
|
||||
|
||||
[node name="ItemCount" type="Label" parent="."]
|
||||
[node name="ItemCount" type="Label" parent="HBox"]
|
||||
unique_name_in_owner = true
|
||||
visible = false
|
||||
layout_mode = 2
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
using Chickensoft.AutoInject;
|
||||
using Chickensoft.Introspection;
|
||||
using Godot;
|
||||
using System;
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
using Zennysoft.Game.Implementation;
|
||||
using Zennysoft.Ma.Adapter;
|
||||
|
||||
namespace Zennysoft.Game.Ma;
|
||||
|
||||
Reference in New Issue
Block a user