(Mostly) show status update when using an item. Need to fix up the equipping code here
This commit is contained in:
@@ -8,6 +8,7 @@ using Godot;
|
||||
|
||||
public interface IGame : IProvide<IGameRepo>, IProvide<IGame>, INode3D
|
||||
{
|
||||
event Game.StatRaisedAlertEventHandler StatRaisedAlert;
|
||||
}
|
||||
|
||||
[Meta(typeof(IAutoNode))]
|
||||
@@ -27,6 +28,9 @@ public partial class Game : Node3D, IGame
|
||||
|
||||
public GameLogic.IBinding GameBinding { get; set; } = default!;
|
||||
|
||||
[Signal]
|
||||
public delegate void StatRaisedAlertEventHandler(string statRaisedAlert);
|
||||
|
||||
[Dependency] public IAppRepo AppRepo => this.DependOn<IAppRepo>();
|
||||
|
||||
#region Nodes
|
||||
@@ -121,6 +125,30 @@ public partial class Game : Node3D, IGame
|
||||
Map.DungeonFinishedGenerating += Map_DungeonFinishedGenerating;
|
||||
InGameUI.InventoryMenu.ClosedMenu += InventoryMenu_CloseInventory;
|
||||
GameRepo.PlayerData.Inventory.InventoryAtCapacity += PlayerInventory_InventoryAtCapacity;
|
||||
GameRepo.PlayerData.Inventory.RaiseStatRequest += Inventory_RaiseStatRequest;
|
||||
}
|
||||
|
||||
private void Inventory_RaiseStatRequest(ConsumableItemStats consumableItemStats)
|
||||
{
|
||||
if (consumableItemStats.RaiseHPAmount > 0 && GameRepo.PlayerData.CurrentHP.Value.Equals(GameRepo.PlayerData.MaximumHP.Value))
|
||||
RaiseHP(consumableItemStats.RaiseHPAmount);
|
||||
else if (consumableItemStats.HealHPAmount > 0)
|
||||
HealHP(consumableItemStats.HealHPAmount);
|
||||
|
||||
if (consumableItemStats.RaiseVTAmount > 0 && GameRepo.PlayerData.CurrentVT.Value.Equals(GameRepo.PlayerData.MaximumVT.Value))
|
||||
RaiseVT(consumableItemStats.RaiseVTAmount);
|
||||
else if (consumableItemStats.HealVTAmount > 0)
|
||||
HealVT(consumableItemStats.HealVTAmount);
|
||||
}
|
||||
|
||||
private void RaiseHP(int amountToRaise)
|
||||
{
|
||||
if (GameRepo.PlayerData.CurrentHP == GameRepo.PlayerData.MaximumHP)
|
||||
{
|
||||
GameRepo.PlayerData.SetMaximumHP(GameRepo.PlayerData.MaximumHP.Value + amountToRaise);
|
||||
GameRepo.PlayerData.SetCurrentHP(GameRepo.PlayerData.MaximumHP.Value);
|
||||
EmitSignal(SignalName.StatRaisedAlert, $"{amountToRaise} Maximum HP Up.");
|
||||
}
|
||||
}
|
||||
|
||||
public void ToggleInventory()
|
||||
@@ -161,5 +189,27 @@ public partial class Game : Node3D, IGame
|
||||
GetTree().Paused = isPaused;
|
||||
}
|
||||
|
||||
private void HealHP(int amountToRaise)
|
||||
{
|
||||
GameRepo.PlayerData.SetCurrentHP(GameRepo.PlayerData.CurrentHP.Value + amountToRaise);
|
||||
EmitSignal(SignalName.StatRaisedAlert, $"{amountToRaise}HP Up.");
|
||||
}
|
||||
|
||||
private void RaiseVT(int amountToRaise)
|
||||
{
|
||||
if (GameRepo.PlayerData.CurrentVT == GameRepo.PlayerData.MaximumVT)
|
||||
{
|
||||
GameRepo.PlayerData.SetMaximumVT(GameRepo.PlayerData.MaximumVT.Value + amountToRaise);
|
||||
GameRepo.PlayerData.SetCurrentVT(GameRepo.PlayerData.MaximumVT.Value);
|
||||
EmitSignal(SignalName.StatRaisedAlert, $"{amountToRaise} Maximum VT Up.");
|
||||
}
|
||||
}
|
||||
|
||||
private void HealVT(int amountToRaise)
|
||||
{
|
||||
GameRepo.PlayerData.SetCurrentVT(GameRepo.PlayerData.CurrentVT.Value + amountToRaise);
|
||||
EmitSignal(SignalName.StatRaisedAlert, $"{amountToRaise}VT Up.");
|
||||
}
|
||||
|
||||
public void OnStart() => GameLogic.Input(new GameLogic.Input.StartGame());
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ using Chickensoft.Introspection;
|
||||
using GameJamDungeon;
|
||||
using Godot;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
public interface IInventoryMenu : IControl
|
||||
@@ -21,6 +22,9 @@ public partial class InventoryMenu : Control, IInventoryMenu
|
||||
[Dependency]
|
||||
public IGameRepo GameRepo => this.DependOn<IGameRepo>();
|
||||
|
||||
[Dependency]
|
||||
public IGame Game => this.DependOn<IGame>();
|
||||
|
||||
[Signal]
|
||||
public delegate void ClosedMenuEventHandler();
|
||||
|
||||
@@ -59,6 +63,8 @@ public partial class InventoryMenu : Control, IInventoryMenu
|
||||
[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 void OnReady()
|
||||
@@ -84,6 +90,29 @@ public partial class InventoryMenu : Control, IInventoryMenu
|
||||
GameRepo.PlayerData.Inventory.EquippedWeapon.Sync += EquippedWeapon_Sync;
|
||||
GameRepo.PlayerData.Inventory.EquippedArmor.Sync += EquippedArmor_Sync;
|
||||
GameRepo.PlayerData.Inventory.EquippedAccessory.Sync += EquippedAccessory_Sync;
|
||||
|
||||
Game.StatRaisedAlert += Game_StatRaisedAlert;
|
||||
|
||||
AnimationPlayer.AnimationFinished += AnimationPlayer_AnimationFinished;
|
||||
}
|
||||
|
||||
private async void AnimationPlayer_AnimationFinished(StringName animName)
|
||||
{
|
||||
if (animName == "status_up")
|
||||
{
|
||||
if (_currentIndex >= ItemSlots.Length - 1)
|
||||
_currentIndex--;
|
||||
if (_currentIndex <= 0)
|
||||
_currentIndex = 0;
|
||||
await RedrawInventory();
|
||||
await ShowInventoryInfo();
|
||||
}
|
||||
}
|
||||
|
||||
private async void Game_StatRaisedAlert(string statRaisedAlert)
|
||||
{
|
||||
ItemEffectLabel.Text = statRaisedAlert;
|
||||
AnimationPlayer.Play("status_up");
|
||||
}
|
||||
|
||||
private void EquippedAccessory_Sync(Accessory obj)
|
||||
@@ -129,7 +158,6 @@ public partial class InventoryMenu : Control, IInventoryMenu
|
||||
|
||||
public async Task RedrawInventory()
|
||||
{
|
||||
await HideUserActionPrompt();
|
||||
await ClearItems();
|
||||
PopulateInventory();
|
||||
PopulatePlayerInfo();
|
||||
@@ -182,8 +210,6 @@ public partial class InventoryMenu : Control, IInventoryMenu
|
||||
{
|
||||
foreach (var item in ItemSlots)
|
||||
ItemsPage.RemoveChildEx(item);
|
||||
|
||||
await HideUserActionPrompt();
|
||||
}
|
||||
|
||||
private void PopulatePlayerInfo()
|
||||
@@ -228,14 +254,18 @@ public partial class InventoryMenu : Control, IInventoryMenu
|
||||
|
||||
private async Task HideUserActionPrompt()
|
||||
{
|
||||
ItemDescriptionTitle.Show();
|
||||
ItemEffectLabel.Show();
|
||||
UseItemPrompt.Hide();
|
||||
UseButton.Hide();
|
||||
ThrowButton.Hide();
|
||||
DropButton.Hide();
|
||||
}
|
||||
|
||||
private async Task ShowInventoryInfo()
|
||||
{
|
||||
ItemDescriptionTitle.Show();
|
||||
ItemEffectLabel.Show();
|
||||
}
|
||||
|
||||
private async Task ChangeInventoryPage(InventoryPageNumber pageToChangeTo)
|
||||
{
|
||||
await ClearItems();
|
||||
@@ -311,12 +341,14 @@ public partial class InventoryMenu : Control, IInventoryMenu
|
||||
if (GameRepo.PlayerData.Inventory.IsEquipped(equipableItem))
|
||||
{
|
||||
GameRepo.PlayerData.Inventory.Unequip(equipableItem);
|
||||
AnimationPlayer.Play("status_up");
|
||||
itemSlot.SetSelectedItemStyle();
|
||||
}
|
||||
else
|
||||
{
|
||||
GameRepo.PlayerData.Inventory.Equip(equipableItem);
|
||||
itemSlot.SetEquippedSelectedItemStyle();
|
||||
AnimationPlayer.Play("status_up");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -328,17 +360,10 @@ public partial class InventoryMenu : Control, IInventoryMenu
|
||||
await EquipOrUnequipItem();
|
||||
else if (currentItem is ConsumableItem consumable)
|
||||
{
|
||||
consumable.Use();
|
||||
if (_currentIndex >= ItemSlots.Length - 1)
|
||||
_currentIndex--;
|
||||
if (_currentIndex <= 0)
|
||||
_currentIndex = 0;
|
||||
EmitSignal(SignalName.ClosedMenu);
|
||||
GameRepo.PlayerData.Inventory.Use(consumable);
|
||||
}
|
||||
|
||||
// TODO: Replace with animation player (for visual effects/sound effects?)
|
||||
await ToSignal(GetTree().CreateTimer(0.25f), "timeout");
|
||||
await RedrawInventory();
|
||||
await HideUserActionPrompt();
|
||||
}
|
||||
|
||||
private async void ThrowButtonPressed()
|
||||
@@ -350,7 +375,7 @@ public partial class InventoryMenu : Control, IInventoryMenu
|
||||
if (_currentIndex <= 0)
|
||||
_currentIndex = 0;
|
||||
EmitSignal(SignalName.ClosedMenu);
|
||||
currentItem.Throw();
|
||||
GameRepo.PlayerData.Inventory.Throw(currentItem);
|
||||
}
|
||||
|
||||
private async void DropButtonPressed()
|
||||
@@ -363,7 +388,7 @@ public partial class InventoryMenu : Control, IInventoryMenu
|
||||
_currentIndex = 0;
|
||||
|
||||
EmitSignal(SignalName.ClosedMenu);
|
||||
currentItem.Drop();
|
||||
GameRepo.PlayerData.Inventory.Drop(currentItem);
|
||||
}
|
||||
|
||||
private enum InventoryPageNumber
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
[gd_scene load_steps=32 format=3 uid="uid://dlj8qdg1c5048"]
|
||||
[gd_scene load_steps=35 format=3 uid="uid://dlj8qdg1c5048"]
|
||||
|
||||
[ext_resource type="Script" path="res://src/inventory_menu/InventoryMenu.cs" id="1_l64wl"]
|
||||
[ext_resource type="Shader" path="res://src/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="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://c4wbba5mo7qcp" path="res://src/ui/label_settings/MainTextFontItalicized.tres" id="6_q3oua"]
|
||||
[ext_resource type="LabelSettings" uid="uid://ca1q6yu8blwxf" path="res://src/ui/label_settings/InventoryMainTextBold.tres" id="6_tmdno"]
|
||||
[ext_resource type="LabelSettings" uid="uid://cuuo43x72xcsc" path="res://src/ui/label_settings/MainTextBold.tres" id="7_vyrxm"]
|
||||
[ext_resource type="Theme" uid="uid://daxuhpmyxwxck" path="res://src/inventory_menu/InventoryDialogueSelectionStyle.tres" id="8_khyvo"]
|
||||
|
||||
[sub_resource type="ShaderMaterial" id="ShaderMaterial_i55tv"]
|
||||
@@ -101,6 +101,67 @@ font = ExtResource("3_lm4o1")
|
||||
font_size = 80
|
||||
font_color = Color(0.737255, 0.705882, 0.690196, 1)
|
||||
|
||||
[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="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="AnimationLibrary" id="AnimationLibrary_eivo2"]
|
||||
_data = {
|
||||
"RESET": SubResource("Animation_dg155"),
|
||||
"status_up": SubResource("Animation_7by7u")
|
||||
}
|
||||
|
||||
[node name="InventoryMenu" type="Control"]
|
||||
layout_mode = 3
|
||||
anchors_preset = 15
|
||||
@@ -349,12 +410,11 @@ unique_name_in_owner = true
|
||||
custom_minimum_size = Vector2(800, 100)
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 0
|
||||
label_settings = ExtResource("6_q3oua")
|
||||
label_settings = ExtResource("7_vyrxm")
|
||||
autowrap_mode = 2
|
||||
|
||||
[node name="UseItemPrompt" type="Label" parent="InventoryInfo/HBoxContainer/PlayerInfo/HBoxContainer/VBoxContainer"]
|
||||
unique_name_in_owner = true
|
||||
visible = false
|
||||
custom_minimum_size = Vector2(800, 100)
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 0
|
||||
@@ -485,3 +545,9 @@ alignment = 1
|
||||
[node name="ReferenceRect3" type="ReferenceRect" parent="InventoryInfo/HBoxContainer/ItemInfo/ItemsPage"]
|
||||
custom_minimum_size = Vector2(0, 14)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="AnimationPlayer" type="AnimationPlayer" parent="."]
|
||||
unique_name_in_owner = true
|
||||
libraries = {
|
||||
"": SubResource("AnimationLibrary_eivo2")
|
||||
}
|
||||
|
||||
@@ -25,9 +25,17 @@ public interface IInventory : INode
|
||||
|
||||
public bool IsEquipped(IEquipable equipable);
|
||||
|
||||
public void Use(IInventoryItem inventoryItem);
|
||||
|
||||
public void Throw(IInventoryItem inventoryItem);
|
||||
|
||||
public void Drop(IInventoryItem inventoryItem);
|
||||
|
||||
event Inventory.InventoryAtCapacityEventHandler InventoryAtCapacity;
|
||||
|
||||
event Inventory.AccessoryUnequippedEventHandler AccessoryUnequipped;
|
||||
|
||||
event Inventory.RaiseStatRequestEventHandler RaiseStatRequest;
|
||||
}
|
||||
|
||||
public partial class Inventory : Node, IInventory
|
||||
@@ -39,6 +47,8 @@ public partial class Inventory : Node, IInventory
|
||||
public delegate void InventoryAtCapacityEventHandler(string rejectedItemName);
|
||||
[Signal]
|
||||
public delegate void AccessoryUnequippedEventHandler(AccessoryStats unequippedAccessory);
|
||||
[Signal]
|
||||
public delegate void RaiseStatRequestEventHandler(ConsumableItemStats consumableItemStats);
|
||||
|
||||
public Inventory()
|
||||
{
|
||||
@@ -108,4 +118,23 @@ public partial class Inventory : Node, IInventory
|
||||
else
|
||||
throw new NotImplementedException("Item type is not supported.");
|
||||
}
|
||||
|
||||
public void Use(IInventoryItem item)
|
||||
{
|
||||
if (item is ConsumableItem consumableItem)
|
||||
{
|
||||
EmitSignal(SignalName.RaiseStatRequest, consumableItem.ConsumableItemInfo);
|
||||
Remove(consumableItem);
|
||||
}
|
||||
}
|
||||
|
||||
public void Throw(IInventoryItem item)
|
||||
{
|
||||
Remove(item);
|
||||
}
|
||||
|
||||
public void Drop(IInventoryItem item)
|
||||
{
|
||||
Remove(item);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,9 +9,5 @@ namespace GameJamDungeon
|
||||
public IGameRepo GameRepo { get; }
|
||||
|
||||
public InventoryItemStats Info { get; }
|
||||
|
||||
public void Throw();
|
||||
|
||||
public void Drop();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ using Chickensoft.Introspection;
|
||||
using GameJamDungeon;
|
||||
using Godot;
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
[Meta(typeof(IAutoNode))]
|
||||
public partial class ConsumableItem : Node3D, IInventoryItem
|
||||
@@ -29,58 +28,6 @@ public partial class ConsumableItem : Node3D, IInventoryItem
|
||||
Pickup.BodyEntered += OnEntered;
|
||||
}
|
||||
|
||||
public void Use()
|
||||
{
|
||||
if (ConsumableItemInfo.RaiseHPAmount != 0)
|
||||
RaiseHP();
|
||||
if (ConsumableItemInfo.RaiseVTAmount != 0)
|
||||
RaiseVT();
|
||||
if (ConsumableItemInfo.HealHPAmount != 0)
|
||||
HealHP();
|
||||
if (ConsumableItemInfo.HealVTAmount != 0)
|
||||
HealVT();
|
||||
|
||||
GameRepo.PlayerData.Inventory.Remove(this);
|
||||
}
|
||||
|
||||
private void RaiseHP()
|
||||
{
|
||||
if (GameRepo.PlayerData.CurrentHP == GameRepo.PlayerData.MaximumHP)
|
||||
{
|
||||
GameRepo.PlayerData.SetMaximumHP(GameRepo.PlayerData.MaximumHP.Value + ConsumableItemInfo.RaiseHPAmount);
|
||||
GameRepo.PlayerData.SetCurrentHP(GameRepo.PlayerData.MaximumHP.Value);
|
||||
}
|
||||
}
|
||||
|
||||
private void HealHP()
|
||||
{
|
||||
GameRepo.PlayerData.SetCurrentHP(GameRepo.PlayerData.CurrentHP.Value + ConsumableItemInfo.HealHPAmount);
|
||||
}
|
||||
|
||||
private void RaiseVT()
|
||||
{
|
||||
if (GameRepo.PlayerData.CurrentVT == GameRepo.PlayerData.MaximumVT)
|
||||
{
|
||||
GameRepo.PlayerData.SetMaximumVT(GameRepo.PlayerData.MaximumVT.Value + ConsumableItemInfo.RaiseVTAmount);
|
||||
GameRepo.PlayerData.SetCurrentVT(GameRepo.PlayerData.MaximumVT.Value);
|
||||
}
|
||||
}
|
||||
|
||||
private void HealVT()
|
||||
{
|
||||
GameRepo.PlayerData.SetCurrentVT(GameRepo.PlayerData.CurrentVT.Value + ConsumableItemInfo.HealVTAmount);
|
||||
}
|
||||
|
||||
public void Throw()
|
||||
{
|
||||
GameRepo.PlayerData.Inventory.Remove(this);
|
||||
}
|
||||
|
||||
public void Drop()
|
||||
{
|
||||
GameRepo.PlayerData.Inventory.Remove(this);
|
||||
}
|
||||
|
||||
public void OnEntered(Node3D body)
|
||||
{
|
||||
var isAdded = GameRepo.PlayerData.Inventory.TryAdd(this);
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
[gd_resource type="LabelSettings" load_steps=2 format=3 uid="uid://bqdq5r46uduvd"]
|
||||
|
||||
[ext_resource type="FontFile" uid="uid://dit3vylt7hmmx" path="res://src/ui/fonts/FT88-Regular.ttf" id="1_gld51"]
|
||||
|
||||
[resource]
|
||||
font = ExtResource("1_gld51")
|
||||
font_size = 24
|
||||
font_color = Color(0.737255, 0.705882, 0.690196, 1)
|
||||
@@ -5,3 +5,4 @@
|
||||
[resource]
|
||||
font = ExtResource("1_ofouc")
|
||||
font_size = 36
|
||||
font_color = Color(1, 0.94902, 0, 1)
|
||||
|
||||
@@ -32,7 +32,7 @@ public partial class PlayerInfoUI : Control, IPlayerInfoUI
|
||||
|
||||
public void OnResolved()
|
||||
{
|
||||
_labelSettings = GD.Load<LabelSettings>("res://src/ui/label_settings/MainTextRegular.tres");
|
||||
_labelSettings = GD.Load<LabelSettings>("res://src/ui/label_settings/InventoryFullAlertLabelSetting.tres");
|
||||
GameRepo.PlayerData.CurrentHP.Sync += CurrentHP_Sync;
|
||||
GameRepo.PlayerData.MaximumHP.Sync += MaximumHP_Sync;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user