diff --git a/Characters/Player.tscn b/Characters/Player.tscn index 6eef8bd..d9fc4ea 100644 --- a/Characters/Player.tscn +++ b/Characters/Player.tscn @@ -36,9 +36,9 @@ [ext_resource type="Script" path="res://addons/phantom_camera/scripts/phantom_camera/phantom_camera_2d.gd" id="27_mndpv"] [ext_resource type="Script" path="res://addons/phantom_camera/scripts/resources/tween_resource.gd" id="28_6gq8l"] [ext_resource type="Script" path="res://Items/PlayerInventory.cs" id="30_y2wmw"] -[ext_resource type="PackedScene" uid="uid://cgg0sfm2qeiwn" path="res://Items/Weapons/Bow.tscn" id="31_mofvy"] -[ext_resource type="PackedScene" uid="uid://dvqap2uhcah63" path="res://Items/Weapons/Sword.tscn" id="31_ql4as"] -[ext_resource type="PackedScene" uid="uid://5y1acxl4j4n7" path="res://Items/Weapons/Pugio.tscn" id="32_6ffmm"] +[ext_resource type="Resource" uid="uid://cl7jvdu2lnv2d" path="res://Items/Weapons/Sword.tres" id="33_3qyfl"] +[ext_resource type="Resource" uid="uid://cjsh0dcgbfn77" path="res://Items/Weapons/Bow.tres" id="34_70ron"] +[ext_resource type="Resource" uid="uid://iqe6rgnb3jur" path="res://Items/Weapons/Pugio.tres" id="35_4pap1"] [sub_resource type="ShaderMaterial" id="ShaderMaterial_h78y7"] shader = ExtResource("2_ngsgt") @@ -836,35 +836,14 @@ horizontal_alignment = 1 [node name="Inventory" type="Node2D" parent="." node_paths=PackedStringArray("Hotbar")] y_sort_enabled = true script = ExtResource("30_y2wmw") -Hotbar = [NodePath("Sword"), NodePath("Bow"), NodePath("Pugio")] +Hotbar = [null, null, null] +Items = Array[Object]([ExtResource("33_3qyfl"), ExtResource("34_70ron"), ExtResource("35_4pap1")]) InventoryMap = { "equip_1": 0, "equip_2": 1, "equip_3": 2 } -[node name="Bow" parent="Inventory" node_paths=PackedStringArray("StateMachine") instance=ExtResource("31_mofvy")] -visible = false -StateMachine = NodePath("StateMachine") - -[node name="Sword" parent="Inventory" node_paths=PackedStringArray("Hitbox", "AnimationPlayer", "ParryParticles", "StateMachine", "Anchor", "HandAnchor") instance=ExtResource("31_ql4as")] -visible = false -Hitbox = NodePath("Hitbox") -AnimationPlayer = NodePath("AnimationPlayer") -ParryParticles = NodePath("Anchor/Node2D/Sprite2D/ParryParticles") -StateMachine = NodePath("State") -Anchor = NodePath("Anchor") -HandAnchor = NodePath("Anchor/Node2D/Sprite2D/Hand") - -[node name="Pugio" parent="Inventory" node_paths=PackedStringArray("Hitbox", "AnimationPlayer", "ParryParticles", "StateMachine", "Anchor", "HandAnchor") instance=ExtResource("32_6ffmm")] -visible = false -Hitbox = NodePath("Hitbox") -AnimationPlayer = NodePath("AnimationPlayer") -ParryParticles = NodePath("Anchor/Node2D/Sprite2D/ParryParticles") -StateMachine = NodePath("State") -Anchor = NodePath("Anchor") -HandAnchor = NodePath("Anchor/Node2D/Sprite2D/Hand") - [node name="Hurtbox" parent="." node_paths=PackedStringArray("InvincibilityTimer") instance=ExtResource("9_avyu4")] visible = false InvincibilityTimer = NodePath("Timer") diff --git a/Events/EventBus.cs b/Events/EventBus.cs index e158812..e16d0b4 100644 --- a/Events/EventBus.cs +++ b/Events/EventBus.cs @@ -36,6 +36,9 @@ public partial class EventBus : Node [Signal] public delegate void PlayerStunEventHandler(); + [Signal] + public delegate void PlayerOpenInventoryEventHandler(Items.Inventory inventory); + [Signal] public delegate void RegisteredBossEventHandler(Characters.Boss boss); diff --git a/Items/Inventory.cs b/Items/Inventory.cs index 548618a..8c5f876 100644 --- a/Items/Inventory.cs +++ b/Items/Inventory.cs @@ -69,6 +69,7 @@ public partial class Inventory : Node2D, IItemCollection // instantiating a new array will prevent characters from // sharing inventories Hotbar = new(); + Hotbar.Resize(HotbarCapacity); } if (Items is null) @@ -154,6 +155,35 @@ public partial class Inventory : Node2D, IItemCollection return item; } + public Item SetHotbarIndexToItem(int index, ItemMetadata metadata) + { + var oldItem = Hotbar[index]; + Item newItem = null; + + if (IsInstanceValid(oldItem)) + { + oldItem?.QueueFree(); + } + + if (metadata is not null) + { + newItem = metadata.Instance.Instantiate(); + AddChild(newItem); + Hotbar[index] = newItem; + } + + if (SelectedIndex == index) + { + // equip item if the hotbar index we are setting is selected + EquipIndex(index); + } + + var bus = Events.EventBus.Instance; + bus.EmitSignal(Events.EventBus.SignalName.PlayerInventoryUpdate, this); + + return newItem; + } + public Item AddItem(Item item) { if (Hotbar.Count >= HotbarCapacity) diff --git a/State/Character/PlayerState.cs b/State/Character/PlayerState.cs index e9493ae..d6b9a0a 100644 --- a/State/Character/PlayerState.cs +++ b/State/Character/PlayerState.cs @@ -23,17 +23,14 @@ public abstract partial class PlayerState : CharacterState { if (@event.IsActionPressed("equip_1")) { - //inventory.SelectedItem = inventory.GetItemByMap("equip_1"); inventory.SelectedIndex = 0; } else if (@event.IsActionPressed("equip_2")) { - //inventory.SelectedItem = inventory.GetItemByMap("equip_2"); inventory.SelectedIndex = 1; } else if (@event.IsActionPressed("equip_3")) { - //inventory.SelectedItem = inventory.GetItemByMap("equip_3"); inventory.SelectedIndex = 2; } else if (@event.IsActionPressed("next_item")) @@ -58,6 +55,13 @@ public abstract partial class PlayerState : CharacterState return MaxLevelState; } } + + if (@event.IsActionPressed("inventory")) + { + var bus = Events.EventBus.Instance; + bus.EmitSignal(Events.EventBus.SignalName.PlayerOpenInventory, + player.Inventory); + } } return base.UnhandledInput(@event); diff --git a/UI/Base.tscn b/UI/Base.tscn index bbc7b12..d2a80fd 100644 --- a/UI/Base.tscn +++ b/UI/Base.tscn @@ -1,4 +1,4 @@ -[gd_scene load_steps=14 format=3 uid="uid://c271rdjhd1gfo"] +[gd_scene load_steps=15 format=3 uid="uid://c271rdjhd1gfo"] [ext_resource type="Script" path="res://UI/UIController.cs" id="2_b4b6l"] [ext_resource type="PackedScene" uid="uid://bxo553hblp6nf" path="res://UI/HealthBar.tscn" id="3_j1j6h"] @@ -9,6 +9,7 @@ [ext_resource type="PackedScene" uid="uid://d3q1yu3n7cqfj" path="res://UI/SceneTransition.tscn" id="6_j0nhv"] [ext_resource type="PackedScene" uid="uid://cyggkyqosjk36" path="res://UI/Inventory/ShopMenu.tscn" id="8_ep3ae"] [ext_resource type="PackedScene" uid="uid://2afbrf8asy2a" path="res://UI/PostProcessing/Vignette.tscn" id="9_p1ubd"] +[ext_resource type="PackedScene" uid="uid://bg51duwdtyl8w" path="res://UI/Inventory/InventoryMenu.tscn" id="10_5m8qa"] [ext_resource type="PackedScene" uid="uid://b1wsryv4bn0cn" path="res://UI/PostProcessing/StunEffect.tscn" id="10_646ma"] [ext_resource type="Shader" path="res://Shaders/Grayscale.gdshader" id="11_w4gn1"] [ext_resource type="Texture2D" uid="uid://bw052v8ikfget" path="res://icon.svg" id="12_tyv35"] @@ -22,11 +23,17 @@ process_mode = 3 [node name="PostProcessing" type="CanvasLayer" parent="."] -[node name="Vignette" parent="PostProcessing" instance=ExtResource("9_p1ubd")] +[node name="CanvasLayer" type="CanvasLayer" parent="PostProcessing"] -[node name="StunEffect" parent="PostProcessing" instance=ExtResource("10_646ma")] +[node name="Vignette" parent="PostProcessing/CanvasLayer" instance=ExtResource("9_p1ubd")] -[node name="Sprite2D" type="TextureRect" parent="PostProcessing"] +[node name="CanvasLayer2" type="CanvasLayer" parent="PostProcessing"] + +[node name="StunEffect" parent="PostProcessing/CanvasLayer2" instance=ExtResource("10_646ma")] + +[node name="CanvasLayer3" type="CanvasLayer" parent="PostProcessing"] + +[node name="Sprite2D" type="TextureRect" parent="PostProcessing/CanvasLayer3"] visible = false material = SubResource("ShaderMaterial_kbd61") anchors_preset = 3 @@ -53,6 +60,7 @@ stretch_shrink = 3 disable_3d = true transparent_bg = true handle_input_locally = false +snap_2d_transforms_to_pixel = true size = Vector2i(640, 360) render_target_update_mode = 4 @@ -126,6 +134,12 @@ visible = false layout_mode = 2 _inventoryGrid = NodePath("PanelContainer/VBoxContainer/ScrollContainer/InventoryGrid") +[node name="InventoryMenu" parent="SubViewportContainer/UIViewport/MainUILayer/Main/BoxContainer" node_paths=PackedStringArray("_inventoryGrid") instance=ExtResource("10_5m8qa")] +unique_name_in_owner = true +visible = false +layout_mode = 2 +_inventoryGrid = NodePath("PanelContainer/VBoxContainer/ScrollContainer/InventoryGrid") + [node name="Bottom" type="HBoxContainer" parent="SubViewportContainer/UIViewport/MainUILayer/Main"] layout_mode = 1 anchors_preset = 12 diff --git a/UI/Inventory/BaseMenu.cs b/UI/Inventory/BaseMenu.cs new file mode 100644 index 0000000..4516063 --- /dev/null +++ b/UI/Inventory/BaseMenu.cs @@ -0,0 +1,74 @@ +using Godot; + +namespace SupaLidlGame.UI.Inventory; + +public abstract partial class BaseMenu : Control, IModal +{ + [Export] + protected InventoryGrid _inventoryGrid; + + protected Button _focusButtonOnSelect { get; set; } + + protected InventorySlot _selected; + + public abstract void ShowModal(); + + public abstract void HideModal(); + + public bool IsPlayingAnimation => GetNode("%AnimationPlayer").IsPlaying(); + + public async void Close() + { + var animPlayer = GetNode("%AnimationPlayer"); + animPlayer.Play("close"); + await ToSignal(animPlayer, AnimationPlayer.SignalName.AnimationFinished); + HideModal(); + } + + public override void _Ready() + { + var onSlotFocused = (InventorySlot slot) => + { + if (slot.Item is not null) + { + SetTooltipItem(slot); + } + }; + + var onSlotUnfocused = (InventorySlot slot) => + { + SetTooltipItem(_selected); + }; + + var onSlotSelected = (InventorySlot slot) => + { + _selected = slot; + SetTooltipItem(slot); + //GetNode("%ActionButton").GrabFocus(); + _focusButtonOnSelect.GrabFocus(); + }; + + _inventoryGrid.Connect(InventoryGrid.SignalName.SlotFocused, + Callable.From(onSlotFocused)); + _inventoryGrid.Connect(InventoryGrid.SignalName.SlotUnfocused, + Callable.From(onSlotUnfocused)); + _inventoryGrid.Connect(InventoryGrid.SignalName.SlotSelected, + Callable.From(onSlotSelected)); + } + + protected virtual void SetTooltipItem(InventorySlot slot) + { + GetNode("%ItemTooltip").Item = slot?.Item; + } + + public abstract void OnButtonPress(Button button); + + public override void _UnhandledInput(InputEvent @event) + { + if (@event.IsActionPressed("ui_cancel")) + { + AcceptEvent(); + Close(); + } + } +} diff --git a/UI/Inventory/BaseMenu.tscn b/UI/Inventory/BaseMenu.tscn new file mode 100644 index 0000000..47d3ac7 --- /dev/null +++ b/UI/Inventory/BaseMenu.tscn @@ -0,0 +1,206 @@ +[gd_scene load_steps=13 format=3 uid="uid://7blvai53i2a0"] + +[ext_resource type="Shader" path="res://Shaders/WipeXY.gdshader" id="2_y0ues"] +[ext_resource type="StyleBox" path="res://UI/Themes/Panel.tres" id="3_6elnp"] +[ext_resource type="FontFile" uid="uid://cgwa8bjiyv534" path="res://Assets/Fonts/alagard.ttf" id="4_68gcu"] +[ext_resource type="PackedScene" uid="uid://chmokkxsy5vas" path="res://UI/Inventory/InventoryGrid.tscn" id="5_u7ajr"] +[ext_resource type="PackedScene" uid="uid://baawkwo8aiwbu" path="res://UI/Inventory/ShopSlot.tscn" id="6_onxvb"] +[ext_resource type="PackedScene" uid="uid://bsheehtfcdwhh" path="res://UI/Inventory/ItemTooltip.tscn" id="7_nphc3"] + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_gm1xk"] +bg_color = Color(0, 0, 0, 0.784314) +border_width_left = 16 +border_width_top = 16 +border_width_right = 16 +border_width_bottom = 16 +border_color = Color(0.145098, 0.145098, 0.145098, 0) +border_blend = true +corner_radius_top_left = 16 +corner_radius_top_right = 16 +corner_radius_bottom_right = 16 +corner_radius_bottom_left = 16 + +[sub_resource type="ShaderMaterial" id="ShaderMaterial_2hdh3"] +shader = ExtResource("2_y0ues") +shader_parameter/x_amount = 1.0 +shader_parameter/y_amount = 0.5 + +[sub_resource type="Animation" id="Animation_yj24f"] +length = 0.001 +tracks/0/type = "value" +tracks/0/imported = false +tracks/0/enabled = true +tracks/0/path = NodePath(".:modulate") +tracks/0/interp = 1 +tracks/0/loop_wrap = true +tracks/0/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Color(1, 1, 1, 1)] +} +tracks/1/type = "value" +tracks/1/imported = false +tracks/1/enabled = true +tracks/1/path = NodePath("PanelContainer:material:shader_parameter/y_amount") +tracks/1/interp = 1 +tracks/1/loop_wrap = true +tracks/1/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [0.5] +} +tracks/2/type = "value" +tracks/2/imported = false +tracks/2/enabled = true +tracks/2/path = NodePath("PanelContainer:material:shader_parameter/x_amount") +tracks/2/interp = 1 +tracks/2/loop_wrap = true +tracks/2/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [1.0] +} + +[sub_resource type="Animation" id="Animation_tm2as"] +resource_name = "close" +length = 0.5 +step = 0.05 +tracks/0/type = "value" +tracks/0/imported = false +tracks/0/enabled = true +tracks/0/path = NodePath(".:modulate") +tracks/0/interp = 1 +tracks/0/loop_wrap = true +tracks/0/keys = { +"times": PackedFloat32Array(0, 0.4), +"transitions": PackedFloat32Array(1, 1), +"update": 0, +"values": [Color(1, 1, 1, 1), Color(1, 1, 1, 0)] +} +tracks/1/type = "value" +tracks/1/imported = false +tracks/1/enabled = true +tracks/1/path = NodePath("PanelContainer:material:shader_parameter/y_amount") +tracks/1/interp = 1 +tracks/1/loop_wrap = true +tracks/1/keys = { +"times": PackedFloat32Array(0, 0.1), +"transitions": PackedFloat32Array(1, 1), +"update": 0, +"values": [0.5, 1.0] +} +tracks/2/type = "value" +tracks/2/imported = false +tracks/2/enabled = true +tracks/2/path = NodePath("PanelContainer:material:shader_parameter/x_amount") +tracks/2/interp = 1 +tracks/2/loop_wrap = true +tracks/2/keys = { +"times": PackedFloat32Array(0.05, 0.15), +"transitions": PackedFloat32Array(1, 1), +"update": 0, +"values": [1.0, 0.5] +} + +[sub_resource type="Animation" id="Animation_fgj27"] +resource_name = "open" +length = 0.5 +tracks/0/type = "value" +tracks/0/imported = false +tracks/0/enabled = true +tracks/0/path = NodePath(".:modulate") +tracks/0/interp = 1 +tracks/0/loop_wrap = true +tracks/0/keys = { +"times": PackedFloat32Array(0, 0.3), +"transitions": PackedFloat32Array(1, 1), +"update": 0, +"values": [Color(1, 1, 1, 0), Color(1, 1, 1, 1)] +} +tracks/1/type = "value" +tracks/1/imported = false +tracks/1/enabled = true +tracks/1/path = NodePath("PanelContainer:material:shader_parameter/y_amount") +tracks/1/interp = 1 +tracks/1/loop_wrap = true +tracks/1/keys = { +"times": PackedFloat32Array(0, 0.5), +"transitions": PackedFloat32Array(1, 1), +"update": 0, +"values": [1.0, 0.5] +} +tracks/2/type = "value" +tracks/2/imported = false +tracks/2/enabled = true +tracks/2/path = NodePath("PanelContainer:material:shader_parameter/x_amount") +tracks/2/interp = 1 +tracks/2/loop_wrap = true +tracks/2/keys = { +"times": PackedFloat32Array(0, 0.3), +"transitions": PackedFloat32Array(1, 1), +"update": 0, +"values": [0.5, 1.0] +} + +[sub_resource type="AnimationLibrary" id="AnimationLibrary_0glcp"] +_data = { +"RESET": SubResource("Animation_yj24f"), +"close": SubResource("Animation_tm2as"), +"open": SubResource("Animation_fgj27") +} + +[node name="Panel" type="PanelContainer"] +anchors_preset = 6 +anchor_left = 1.0 +anchor_top = 0.5 +anchor_right = 1.0 +anchor_bottom = 0.5 +offset_left = -236.0 +offset_top = -175.5 +offset_bottom = 175.5 +grow_horizontal = 0 +grow_vertical = 2 +theme_override_styles/panel = SubResource("StyleBoxFlat_gm1xk") + +[node name="PanelContainer" type="PanelContainer" parent="."] +material = SubResource("ShaderMaterial_2hdh3") +layout_mode = 2 +theme_override_styles/panel = ExtResource("3_6elnp") + +[node name="VBoxContainer" type="VBoxContainer" parent="PanelContainer"] +layout_mode = 2 + +[node name="HBoxContainer" type="HBoxContainer" parent="PanelContainer/VBoxContainer"] +layout_mode = 2 + +[node name="Label" type="Label" parent="PanelContainer/VBoxContainer/HBoxContainer"] +layout_mode = 2 +theme_override_fonts/font = ExtResource("4_68gcu") +text = "Snus Dealer" + +[node name="ScrollContainer" type="ScrollContainer" parent="PanelContainer/VBoxContainer"] +layout_mode = 2 +size_flags_vertical = 3 +follow_focus = true +horizontal_scroll_mode = 0 + +[node name="InventoryGrid" parent="PanelContainer/VBoxContainer/ScrollContainer" instance=ExtResource("5_u7ajr")] +layout_mode = 2 +size_flags_vertical = 3 +_slotScene = ExtResource("6_onxvb") + +[node name="ItemTooltip" parent="PanelContainer/VBoxContainer" instance=ExtResource("7_nphc3")] +unique_name_in_owner = true +layout_mode = 2 + +[node name="HBoxContainer2" type="HBoxContainer" parent="PanelContainer/VBoxContainer"] +layout_mode = 2 + +[node name="AnimationPlayer" type="AnimationPlayer" parent="."] +unique_name_in_owner = true +libraries = { +"": SubResource("AnimationLibrary_0glcp") +} diff --git a/UI/Inventory/Hotbar.tscn b/UI/Inventory/Hotbar.tscn index 2ef8600..f97f418 100644 --- a/UI/Inventory/Hotbar.tscn +++ b/UI/Inventory/Hotbar.tscn @@ -1,10 +1,8 @@ -[gd_scene load_steps=4 format=3 uid="uid://sfs8dpfitpdu"] +[gd_scene load_steps=3 format=3 uid="uid://sfs8dpfitpdu"] [ext_resource type="Script" path="res://UI/Inventory/Hotbar.cs" id="1_2sak2"] [ext_resource type="PackedScene" uid="uid://dmvu2hjyrwc1y" path="res://UI/Inventory/HotbarSlot.tscn" id="2_3axfe"] -[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_6jbma"] - [node name="Hotbar" type="GridContainer" node_paths=PackedStringArray("_slots")] anchors_preset = 1 anchor_left = 1.0 @@ -19,12 +17,9 @@ _slots = [NodePath("InventorySlot"), NodePath("InventorySlot2"), NodePath("Inven [node name="InventorySlot" parent="." instance=ExtResource("2_3axfe")] layout_mode = 2 -theme_override_styles/panel = SubResource("StyleBoxEmpty_6jbma") [node name="InventorySlot2" parent="." instance=ExtResource("2_3axfe")] layout_mode = 2 -theme_override_styles/panel = SubResource("StyleBoxEmpty_6jbma") [node name="InventorySlot3" parent="." instance=ExtResource("2_3axfe")] layout_mode = 2 -theme_override_styles/panel = SubResource("StyleBoxEmpty_6jbma") diff --git a/UI/Inventory/InventoryGrid.cs b/UI/Inventory/InventoryGrid.cs index 124b536..fc33d54 100644 --- a/UI/Inventory/InventoryGrid.cs +++ b/UI/Inventory/InventoryGrid.cs @@ -6,14 +6,14 @@ namespace SupaLidlGame.UI.Inventory; public partial class InventoryGrid : GridContainer { - private SupaLidlGame.Items.IItemCollection _source; + private Items.IItemCollection _source; [Export] private PackedScene _slotScene; public ButtonGroup ButtonGroup { get; private set; } - public SupaLidlGame.Items.IItemCollection Source + public Items.IItemCollection Source { get => _source; set diff --git a/UI/Inventory/InventoryMenu.cs b/UI/Inventory/InventoryMenu.cs new file mode 100644 index 0000000..1a27612 --- /dev/null +++ b/UI/Inventory/InventoryMenu.cs @@ -0,0 +1,81 @@ +using Godot; +using System.Collections.Generic; + +namespace SupaLidlGame.UI.Inventory; + +public partial class InventoryMenu : BaseMenu, IModal +{ + private Items.Inventory _source; + + public Items.Inventory Source + { + get => _source; + set + { + _source = value; + _inventoryGrid.Source = value; + } + } + + public override void ShowModal() + { + Show(); + var animPlayer = GetNode("%AnimationPlayer"); + animPlayer.Play("open"); + } + + public override void HideModal() + { + Hide(); + _source = null; + } + + public override void _Ready() + { + base._Ready(); + + _focusButtonOnSelect = GetNode