Skip to content

Commit

Permalink
Merge pull request #61 from snipercup/magazine-reloading
Browse files Browse the repository at this point in the history
Magazine reloading
  • Loading branch information
snipercup authored Mar 5, 2024
2 parents fc787fa + f04ebc7 commit 19f405b
Show file tree
Hide file tree
Showing 17 changed files with 430 additions and 215 deletions.
2 changes: 1 addition & 1 deletion Defaults/Mobs/mob_corpse.tscn
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
[ext_resource type="Script" path="res://Scripts/container.gd" id="1_4celg"]
[ext_resource type="Script" path="res://addons/gloot/core/inventory_stacked.gd" id="2_3htey"]
[ext_resource type="Texture2D" uid="uid://cy56wx4qynp3m" path="res://Textures/enemy.png" id="2_pvjek"]
[ext_resource type="Resource" uid="uid://cr7u5aveonr7t" path="res://ItemProtosets.tres" id="4_ehn4b"]
[ext_resource type="Resource" uid="uid://b1tngttyk4w2s" path="res://ItemProtosets.tres" id="4_ehn4b"]

[sub_resource type="SphereShape3D" id="SphereShape3D_0pnwx"]
radius = 0.2
Expand Down
9 changes: 5 additions & 4 deletions ItemProtosets.tres
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ json_data = "[
},
{
\"Magazine\": {
\"current_ammo\": \"19\",
\"max_ammo\": \"20\",
\"used_ammo\": \"9mm\"
},
Expand All @@ -71,10 +72,10 @@ json_data = "[
},
{
\"Ranged\": {
\"firing_speed\": \"0.25\",
\"firing_speed\": \"0.4\",
\"range\": \"1000\",
\"recoil\": \"20\",
\"reload_speed\": \"2.5\",
\"recoil\": \"10\",
\"reload_speed\": \"1.5\",
\"spread\": \"5\",
\"sway\": \"5\",
\"used_ammo\": \"9mm\",
Expand All @@ -96,7 +97,7 @@ json_data = "[
},
{
\"Ranged\": {
\"firing_speed\": \"0.1\",
\"firing_speed\": \"0.2\",
\"range\": \"1000\",
\"recoil\": \"15\",
\"reload_speed\": \"2.5\",
Expand Down
1 change: 1 addition & 0 deletions Mods/Core/Items/Items.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
},
{
"Magazine": {
"current_ammo": "19",
"max_ammo": "20",
"used_ammo": "9mm"
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

[ext_resource type="Script" path="res://Scripts/ItemMagazineEditor.gd" id="1_cgvqr"]

[node name="ItemMagazineEditor" type="Control" node_paths=PackedStringArray("UsedAmmoTextEdit", "MaxAmmoNumberBox")]
[node name="ItemMagazineEditor" type="Control" node_paths=PackedStringArray("UsedAmmoTextEdit", "MaxAmmoNumberBox", "CurrentAmmoNumberBox")]
layout_mode = 3
anchors_preset = 15
anchor_right = 1.0
Expand All @@ -12,6 +12,7 @@ grow_vertical = 2
script = ExtResource("1_cgvqr")
UsedAmmoTextEdit = NodePath("Magazine/UsedAmmoTextEdit")
MaxAmmoNumberBox = NodePath("Magazine/MaxAmmoNumber")
CurrentAmmoNumberBox = NodePath("Magazine/CurrentAmmoNumber")

[node name="Magazine" type="GridContainer" parent="."]
layout_mode = 0
Expand All @@ -37,3 +38,12 @@ text = "Max ammo"
layout_mode = 2
tooltip_text = "The width of this item in the inventory. A larger number means it will take up more horizontal inventory slots"
value = 20.0

[node name="CurrentAmmoLabel" type="Label" parent="Magazine"]
layout_mode = 2
text = "Current ammo"

[node name="CurrentAmmoNumber" type="SpinBox" parent="Magazine"]
layout_mode = 2
tooltip_text = "The amount of ammunition this magazine has when it is spawned. You can use this to create magazines that have been somewhat spent."
value = 20.0
23 changes: 16 additions & 7 deletions Scenes/InventoryWindow.tscn
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
[ext_resource type="Script" path="res://Scripts/InventoryWindow.gd" id="1_7kqbx"]
[ext_resource type="PackedScene" uid="uid://crck2fhgayxhn" path="res://Scenes/InventoryContainerListItem.tscn" id="2_xfgb3"]
[ext_resource type="Script" path="res://addons/gloot/core/inventory_stacked.gd" id="3_l8xgt"]
[ext_resource type="Resource" uid="uid://3jcimsp05x5c" path="res://ItemProtosets.tres" id="3_sqsc0"]
[ext_resource type="Resource" uid="uid://b1tngttyk4w2s" path="res://ItemProtosets.tres" id="3_sqsc0"]
[ext_resource type="Script" path="res://addons/gloot/core/inventory_item.gd" id="5_qidb6"]
[ext_resource type="FontFile" uid="uid://chm7lbcdeyo0h" path="res://Roboto-Bold.ttf" id="6_xpf2l"]
[ext_resource type="PackedScene" uid="uid://y2iul2r3nysx" path="res://Scenes/UI/CtrlInventoryStackedCustom.tscn" id="8_f75fl"]
Expand Down Expand Up @@ -74,6 +74,16 @@ script = ExtResource("5_qidb6")
protoset = ExtResource("3_sqsc0")
prototype_id = "pistol_9mm"

[node name="_Node_98558" type="Node" parent="InventoryStacked"]
script = ExtResource("5_qidb6")
protoset = ExtResource("3_sqsc0")
prototype_id = "pistol_magazine"

[node name="_Node_98565" type="Node" parent="InventoryStacked"]
script = ExtResource("5_qidb6")
protoset = ExtResource("3_sqsc0")
prototype_id = "pistol_magazine"

[node name="InventoryStackedProx" type="Node" parent="."]
script = ExtResource("3_l8xgt")
capacity = 1000.0
Expand Down Expand Up @@ -137,10 +147,11 @@ layout_mode = 2
[node name="LeftHandEquipment" type="HBoxContainer" parent="HBoxContainer/EquipmentSlotList"]
layout_mode = 2

[node name="LeftHandEquipmentSlot" parent="HBoxContainer/EquipmentSlotList/LeftHandEquipment" node_paths=PackedStringArray("myInventory") instance=ExtResource("9_tpx1u")]
[node name="LeftHandEquipmentSlot" parent="HBoxContainer/EquipmentSlotList/LeftHandEquipment" node_paths=PackedStringArray("myInventory", "otherHandSlot") instance=ExtResource("9_tpx1u")]
custom_minimum_size = Vector2(32, 32)
layout_mode = 2
myInventory = NodePath("../../../../InventoryStacked")
otherHandSlot = NodePath("../../RightHandEquipment/RightHandEquipmentSlot")

[node name="Label" type="Label" parent="HBoxContainer/EquipmentSlotList/LeftHandEquipment"]
layout_mode = 2
Expand All @@ -149,10 +160,12 @@ text = "Left hand"
[node name="RightHandEquipment" type="HBoxContainer" parent="HBoxContainer/EquipmentSlotList"]
layout_mode = 2

[node name="RightHandEquipmentSlot" parent="HBoxContainer/EquipmentSlotList/RightHandEquipment" node_paths=PackedStringArray("myInventory") instance=ExtResource("9_tpx1u")]
[node name="RightHandEquipmentSlot" parent="HBoxContainer/EquipmentSlotList/RightHandEquipment" node_paths=PackedStringArray("myInventory", "otherHandSlot") instance=ExtResource("9_tpx1u")]
custom_minimum_size = Vector2(32, 32)
layout_mode = 2
myInventory = NodePath("../../../../InventoryStacked")
otherHandSlot = NodePath("../../LeftHandEquipment/LeftHandEquipmentSlot")
is_left_slot = false

[node name="Label" type="Label" parent="HBoxContainer/EquipmentSlotList/RightHandEquipment"]
layout_mode = 2
Expand Down Expand Up @@ -216,7 +229,3 @@ autowrap_mode = 3
[connection signal="button_up" from="HBoxContainer/HBoxContainer/TransferLeftButton" to="." method="_on_transfer_left_button_button_up"]
[connection signal="equip_left" from="HBoxContainer/VBoxContainer2/CtrlInventoryStackedCustom" to="." method="_on_ctrl_inventory_stacked_custom_equip_left"]
[connection signal="equip_right" from="HBoxContainer/VBoxContainer2/CtrlInventoryStackedCustom" to="." method="_on_ctrl_inventory_stacked_custom_equip_right"]
[connection signal="item_equipped" from="HBoxContainer/EquipmentSlotList/LeftHandEquipment/LeftHandEquipmentSlot" to="." method="_on_left_hand_equipment_slot_item_equipped"]
[connection signal="item_unequipped" from="HBoxContainer/EquipmentSlotList/LeftHandEquipment/LeftHandEquipmentSlot" to="." method="_on_left_hand_equipment_slot_cleared"]
[connection signal="item_equipped" from="HBoxContainer/EquipmentSlotList/RightHandEquipment/RightHandEquipmentSlot" to="." method="_on_right_hand_equipment_slot_item_equipped"]
[connection signal="item_unequipped" from="HBoxContainer/EquipmentSlotList/RightHandEquipment/RightHandEquipmentSlot" to="." method="_on_right_hand_equipment_slot_cleared"]
4 changes: 2 additions & 2 deletions Scripts/CtrlInventoryStackedCustom.gd
Original file line number Diff line number Diff line change
Expand Up @@ -505,13 +505,13 @@ func _deselect_and_clear_current_inventory():
# Reset other variables if needed
last_selected_item = null


# All rows are desleected
func _deselect_all_items():
for row_name in inventory_rows.keys():
if inventory_rows.has(row_name):
_toggle_row_selection(row_name, false)


# When the user clicks on one of the cells in the grid
func _on_grid_cell_gui_input(event, gridCell: Control):
if event is InputEventMouseButton:
if event.pressed: # Check if the mouse button was pressed down
Expand Down
158 changes: 141 additions & 17 deletions Scripts/EquipmentSlot.gd
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,24 @@ extends Control
@export var myInventory: InventoryStacked
@export var backgroundColor: ColorRect
@export var myIcon: TextureRect
# A timer that will prevent the user from reloading while a reload is happening now
@export var otherHandSlot: Control
@export var is_left_slot: bool = true

var myInventoryItem: InventoryItem = null
var myMagazine: InventoryItem = null
# The node that will actually operate the item
var equippedItem: Sprite3D = null
var default_reload_speed: float = 1.0

# Signals
signal item_equipped(item)
signal item_unequipped
signal item_was_equipped(equippedItem: InventoryItem, equipmentSlot: Control)
signal item_was_cleared(equippedItem: InventoryItem, equipmentSlot: Control)

# Called when the node enters the scene tree for the first time.
func _ready():
pass # Replace with function body.
item_was_equipped.connect(Helper.signal_broker.on_item_equipped)
item_was_cleared.connect(Helper.signal_broker.on_item_slot_cleared)


# Handle GUI input events
Expand All @@ -37,35 +45,46 @@ func _gui_input(event):
unequip()



# Equip an item
func equip(item: InventoryItem) -> void:
# First unequip any currently equipped item
if myInventoryItem:
unequip()

if item:
var is_two_handed: bool = item.get_property("two_handed", false)
var other_slot_item: InventoryItem = otherHandSlot.get_item()
# Check if the other slot has a two-handed item equipped
if other_slot_item and other_slot_item.get_property("two_handed", false):
print_debug("Cannot equip item. The other slot has a two-handed weapon equipped.")
return

myInventoryItem = item
update_icon()
# Remove the item from its original inventory
# Not applicable if a game is loaded and we re-equip an item that was alread equipped
var itemInventory = item.get_inventory()
if itemInventory and itemInventory.has_item(item):
item.get_inventory().remove_item(item)
emit_signal("item_equipped", myInventoryItem)


# If the item is two-handed, clear the other hand slot before equipping
if is_two_handed:
otherHandSlot.unequip()
item_was_equipped.emit(item, self)


# Unequip the current item
func unequip() -> void:
if myInventoryItem:
item_was_cleared.emit(myInventoryItem, self)
myInventoryItem.clear_property("equipped_laft")
myInventory.add_item(myInventoryItem)
myInventoryItem = null
if myMagazine:
myInventory.add_item(myMagazine)
myMagazine = null
update_icon()
emit_signal("item_unequipped")

func get_item() -> InventoryItem:
return myInventoryItem


# Update the icon of the equipped item
func update_icon() -> void:
Expand All @@ -76,15 +95,120 @@ func update_icon() -> void:
myIcon.texture = null
myIcon.visible = false

# Serialize the equipped item

# Serialize the equipped item and the magazine into one dictionary
func serialize() -> Dictionary:
var data: Dictionary = {}
if myInventoryItem:
return myInventoryItem.serialize()
return {}
data["item"] = myInventoryItem.serialize() # Serialize equipped item
if myMagazine:
data["magazine"] = myMagazine.serialize() # Serialize magazine
return data


# Deserialize and equip an item
# Deserialize and equip an item and a magazine from the provided data
func deserialize(data: Dictionary) -> void:
if data.size() > 0:
# Deserialize and equip an item
if data.has("item"):
var itemData: Dictionary = data["item"]
var item = InventoryItem.new()
item.deserialize(data)
equip(item)
item.deserialize(itemData)
equip(item) # Equip the deserialized item

if data.has("magazine"):
var magazineData: Dictionary = data["magazine"]
var magazine = InventoryItem.new()
magazine.deserialize(magazineData)
myMagazine = magazine # Directly assign the deserialized magazine
equippedItem.on_magazine_inserted()


# The reload has completed. We now need to remove the current magazine and put in a new one
func reload_weapon(item: InventoryItem, specific_magazine: InventoryItem = null):
if myInventoryItem and not myInventoryItem.get_property("Ranged") == null and item == myInventoryItem:
var oldMagazine = myMagazine
remove_magazine()
insert_magazine(specific_magazine, oldMagazine)
equippedItem.is_reloading = false


# This will start the reload action. General will keep track of the progress
# We pass reload_weapon as a function that will be executed when the action is done
func start_reload(item: InventoryItem, reload_time: float, specific_magazine: InventoryItem = null):
var reload_callable = Callable(self, "reload_weapon").bind(item, specific_magazine)
equippedItem.is_reloading = true
General.start_action(reload_time, reload_callable)


func insert_magazine(specific_magazine: InventoryItem = null, oldMagazine: InventoryItem = null):
if not myInventoryItem or myInventoryItem.get_property("Ranged") == null:
return # Ensure the item is a ranged weapon

var magazine = specific_magazine if specific_magazine else find_compatible_magazine(oldMagazine)
if magazine:
myMagazine = magazine
myInventory.remove_item(magazine) # Remove the magazine from the inventory
equippedItem.on_magazine_inserted()


func remove_magazine():
if not myInventoryItem or not myInventoryItem.get_property("Ranged") or not myMagazine:
return # Ensure the item is a ranged weapon

myInventory.add_item(myMagazine)
equippedItem.on_magazine_removed()
myMagazine = null


func get_magazine() -> InventoryItem:
return myMagazine


func get_item() -> InventoryItem:
return myInventoryItem


# This function will loop over the items in the inventory
# It will select items that have the "magazine" property
# It will return the first result if a magazine is found
# It will return null of no magazine is found
func find_compatible_magazine(oldMagazine: InventoryItem) -> InventoryItem:
var bestMagazine: InventoryItem = null
var bestAmmo: int = 0 # Variable to track the maximum ammo found

var inventoryItems: Array = myInventory.get_items() # Retrieve all items in the inventory
for item in inventoryItems:
if item.get_property("Magazine") and item != oldMagazine:
var magazine = item.get_property("Magazine")
if magazine and magazine.has("current_ammo"):
var currentAmmo: int = int(magazine["current_ammo"])
if currentAmmo > bestAmmo:
bestAmmo = currentAmmo
bestMagazine = item

return bestMagazine # Return the magazine with the most current ammo



# This function should return true if the dragged data can be dropped here
func _can_drop_data(_newpos, data) -> bool:
return data is Array[InventoryItem]


# This function handles the data being dropped
func _drop_data(newpos, data):
if _can_drop_data(newpos, data):
if data is Array and data.size() > 0 and data[0] is InventoryItem:
var first_item = data[0]
# Check if the dropped item is a magazine
if first_item.get_property("Magazine"):
_handle_magazine_drop(first_item)
else:
# Equip the item if it's not a magazine
equip(first_item)


# When the user has dropped a magaziene from the inventory
func _handle_magazine_drop(magazine: InventoryItem):
if myInventoryItem and myInventoryItem.get_property("Ranged"):
start_reload(myInventoryItem, equippedItem.reload_speed, magazine)
Loading

0 comments on commit 19f405b

Please sign in to comment.