fixed so there isn't too many spam messages
This commit is contained in:
@@ -23,6 +23,7 @@ stream_0/stream = ExtResource("7_pg2b6")
|
|||||||
stream_1/stream = ExtResource("7_kgbum")
|
stream_1/stream = ExtResource("7_kgbum")
|
||||||
|
|
||||||
[node name="Door" type="StaticBody2D" unique_id=371155975]
|
[node name="Door" type="StaticBody2D" unique_id=371155975]
|
||||||
|
y_sort_enabled = true
|
||||||
collision_layer = 64
|
collision_layer = 64
|
||||||
script = ExtResource("1_uvdjg")
|
script = ExtResource("1_uvdjg")
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ default_font = ExtResource("2_dmg_font")
|
|||||||
default_font_size = 12
|
default_font_size = 12
|
||||||
|
|
||||||
[node name="FloatingText" type="Node2D" unique_id=1350559946]
|
[node name="FloatingText" type="Node2D" unique_id=1350559946]
|
||||||
|
z_index = 3
|
||||||
script = ExtResource("1")
|
script = ExtResource("1")
|
||||||
|
|
||||||
[node name="ItemSprite" type="Sprite2D" parent="." unique_id=1657362510]
|
[node name="ItemSprite" type="Sprite2D" parent="." unique_id=1657362510]
|
||||||
@@ -15,6 +16,7 @@ visible = false
|
|||||||
offset = Vector2(0, -8)
|
offset = Vector2(0, -8)
|
||||||
|
|
||||||
[node name="Label" type="Label" parent="." unique_id=1387220833]
|
[node name="Label" type="Label" parent="." unique_id=1387220833]
|
||||||
|
z_index = 3
|
||||||
offset_right = 64.0
|
offset_right = 64.0
|
||||||
offset_bottom = 24.0
|
offset_bottom = 24.0
|
||||||
theme = SubResource("Theme_floating_text")
|
theme = SubResource("Theme_floating_text")
|
||||||
|
|||||||
@@ -386,7 +386,7 @@ ignore_texture_size = true
|
|||||||
stretch_mode = 5
|
stretch_mode = 5
|
||||||
script = ExtResource("8_cu5yl")
|
script = ExtResource("8_cu5yl")
|
||||||
touchscreen_only = true
|
touchscreen_only = true
|
||||||
input_action = "attack"
|
input_action = "inventory"
|
||||||
metadata/_custom_type_script = "uid://bh5a3ydiu51eo"
|
metadata/_custom_type_script = "uid://bh5a3ydiu51eo"
|
||||||
|
|
||||||
[connection signal="analogic_changed" from="MobileInput/VirtualJoystick" to="MobileInput" method="_on_virtual_joystick_analogic_changed"]
|
[connection signal="analogic_changed" from="MobileInput/VirtualJoystick" to="MobileInput" method="_on_virtual_joystick_analogic_changed"]
|
||||||
|
|||||||
@@ -309,7 +309,7 @@ collision_mask = 16384
|
|||||||
shape = SubResource("CircleShape2D_pf23h")
|
shape = SubResource("CircleShape2D_pf23h")
|
||||||
|
|
||||||
[node name="Shadow" type="Sprite2D" parent="." unique_id=937683521]
|
[node name="Shadow" type="Sprite2D" parent="." unique_id=937683521]
|
||||||
position = Vector2(0, 8)
|
position = Vector2(0, 7)
|
||||||
texture = SubResource("GradientTexture2D_jej6c")
|
texture = SubResource("GradientTexture2D_jej6c")
|
||||||
script = ExtResource("3")
|
script = ExtResource("3")
|
||||||
|
|
||||||
|
|||||||
@@ -579,54 +579,64 @@ func forceUpdate():
|
|||||||
emit_signal("character_changed", self)
|
emit_signal("character_changed", self)
|
||||||
pass
|
pass
|
||||||
|
|
||||||
func equip_item(iItem:Item):
|
func equip_item(iItem:Item, insert_index: int = -1):
|
||||||
|
# insert_index: if >= 0, place old item at this index instead of at the end
|
||||||
if iItem.equipment_type == Item.EquipmentType.NONE:
|
if iItem.equipment_type == Item.EquipmentType.NONE:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
var old_item = null
|
||||||
|
var item_index = self.inventory.find(iItem)
|
||||||
|
|
||||||
match iItem.equipment_type:
|
match iItem.equipment_type:
|
||||||
Item.EquipmentType.MAINHAND:
|
Item.EquipmentType.MAINHAND:
|
||||||
if equipment["mainhand"] != null:
|
if equipment["mainhand"] != null:
|
||||||
self.inventory.push_back(equipment["mainhand"])
|
old_item = equipment["mainhand"]
|
||||||
# If we equip different weapon than bow and we have ammunition in offhand, remove, the offhand.
|
|
||||||
# If we equip two handed weapon, remove offhand...
|
|
||||||
#if equipment["offhand"] != null:
|
|
||||||
#(equipment["offhand"] as Item).equipment_type == Item.WeaponType.AMMUNITION
|
|
||||||
#if iItem.WeaponType.BOW
|
|
||||||
|
|
||||||
equipment["mainhand"] = iItem
|
equipment["mainhand"] = iItem
|
||||||
pass
|
pass
|
||||||
pass
|
pass
|
||||||
Item.EquipmentType.OFFHAND:
|
Item.EquipmentType.OFFHAND:
|
||||||
if equipment["offhand"] != null:
|
if equipment["offhand"] != null:
|
||||||
self.inventory.push_back(equipment["offhand"])
|
old_item = equipment["offhand"]
|
||||||
equipment["offhand"] = iItem
|
equipment["offhand"] = iItem
|
||||||
pass
|
pass
|
||||||
pass
|
pass
|
||||||
Item.EquipmentType.HEADGEAR:
|
Item.EquipmentType.HEADGEAR:
|
||||||
if equipment["headgear"] != null:
|
if equipment["headgear"] != null:
|
||||||
self.inventory.push_back(equipment["headgear"])
|
old_item = equipment["headgear"]
|
||||||
equipment["headgear"] = iItem
|
equipment["headgear"] = iItem
|
||||||
pass
|
pass
|
||||||
pass
|
pass
|
||||||
|
|
||||||
Item.EquipmentType.ARMOUR:
|
Item.EquipmentType.ARMOUR:
|
||||||
if equipment["armour"] != null:
|
if equipment["armour"] != null:
|
||||||
self.inventory.push_back(equipment["armour"])
|
old_item = equipment["armour"]
|
||||||
equipment["armour"] = iItem
|
equipment["armour"] = iItem
|
||||||
pass
|
pass
|
||||||
pass
|
pass
|
||||||
Item.EquipmentType.BOOTS:
|
Item.EquipmentType.BOOTS:
|
||||||
if equipment["boots"] != null:
|
if equipment["boots"] != null:
|
||||||
self.inventory.push_back(equipment["boots"])
|
old_item = equipment["boots"]
|
||||||
equipment["boots"] = iItem
|
equipment["boots"] = iItem
|
||||||
pass
|
pass
|
||||||
pass
|
pass
|
||||||
Item.EquipmentType.ACCESSORY:
|
Item.EquipmentType.ACCESSORY:
|
||||||
if equipment["accessory"] != null:
|
if equipment["accessory"] != null:
|
||||||
self.inventory.push_back(equipment["accessory"])
|
old_item = equipment["accessory"]
|
||||||
equipment["accessory"] = iItem
|
equipment["accessory"] = iItem
|
||||||
pass
|
pass
|
||||||
pass
|
pass
|
||||||
self.inventory.remove_at(self.inventory.find(iItem))
|
|
||||||
|
# Remove the item being equipped from inventory first
|
||||||
|
if item_index >= 0:
|
||||||
|
self.inventory.remove_at(item_index)
|
||||||
|
|
||||||
|
# Add old item back to inventory at the specified position (or end if -1)
|
||||||
|
if old_item != null:
|
||||||
|
if insert_index >= 0 and insert_index <= self.inventory.size():
|
||||||
|
self.inventory.insert(insert_index, old_item)
|
||||||
|
else:
|
||||||
|
self.inventory.push_back(old_item)
|
||||||
|
|
||||||
emit_signal("character_changed", self)
|
emit_signal("character_changed", self)
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|||||||
@@ -661,8 +661,8 @@ func _spawn_loot():
|
|||||||
loot_rng.seed = loot_seed
|
loot_rng.seed = loot_seed
|
||||||
|
|
||||||
var random_angle = loot_rng.randf() * PI * 2
|
var random_angle = loot_rng.randf() * PI * 2
|
||||||
var random_force = loot_rng.randf_range(50.0, 100.0)
|
var random_force = loot_rng.randf_range(25.0, 50.0) # Reduced to half speed
|
||||||
var random_velocity_z = loot_rng.randf_range(80.0, 120.0)
|
var random_velocity_z = loot_rng.randf_range(40.0, 60.0) # Reduced to half speed
|
||||||
|
|
||||||
# Generate initial velocity (same on all clients via RPC)
|
# Generate initial velocity (same on all clients via RPC)
|
||||||
var initial_velocity = Vector2(cos(random_angle), sin(random_angle)) * random_force
|
var initial_velocity = Vector2(cos(random_angle), sin(random_angle)) * random_force
|
||||||
@@ -738,8 +738,8 @@ func _spawn_loot():
|
|||||||
loot_rng.seed = real_loot_seed
|
loot_rng.seed = real_loot_seed
|
||||||
# Regenerate velocity with correct seed
|
# Regenerate velocity with correct seed
|
||||||
var real_random_angle = loot_rng.randf() * PI * 2
|
var real_random_angle = loot_rng.randf() * PI * 2
|
||||||
var real_random_force = loot_rng.randf_range(50.0, 100.0)
|
var real_random_force = loot_rng.randf_range(25.0, 50.0) # Reduced to half speed
|
||||||
var real_random_velocity_z = loot_rng.randf_range(80.0, 120.0)
|
var real_random_velocity_z = loot_rng.randf_range(40.0, 60.0) # Reduced to half speed
|
||||||
initial_velocity = Vector2(cos(real_random_angle), sin(real_random_angle)) * real_random_force
|
initial_velocity = Vector2(cos(real_random_angle), sin(real_random_angle)) * real_random_force
|
||||||
random_velocity_z = real_random_velocity_z
|
random_velocity_z = real_random_velocity_z
|
||||||
# Update loot with correct velocity
|
# Update loot with correct velocity
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -233,6 +233,7 @@ func _create_equipment_slots():
|
|||||||
button.size_flags_horizontal = 0
|
button.size_flags_horizontal = 0
|
||||||
button.size_flags_vertical = 0
|
button.size_flags_vertical = 0
|
||||||
button.connect("pressed", _on_equipment_slot_pressed.bind(slot_name))
|
button.connect("pressed", _on_equipment_slot_pressed.bind(slot_name))
|
||||||
|
button.connect("gui_input", _on_equipment_slot_gui_input.bind(slot_name))
|
||||||
# Connect focus_entered like inspiration system (for keyboard navigation)
|
# Connect focus_entered like inspiration system (for keyboard navigation)
|
||||||
if local_player and local_player.character_stats:
|
if local_player and local_player.character_stats:
|
||||||
var equipped_item = local_player.character_stats.equipment[slot_name]
|
var equipped_item = local_player.character_stats.equipment[slot_name]
|
||||||
@@ -288,6 +289,19 @@ func _on_equipment_slot_pressed(slot_name: String):
|
|||||||
_update_selection_highlight()
|
_update_selection_highlight()
|
||||||
_update_selection_rectangle()
|
_update_selection_rectangle()
|
||||||
|
|
||||||
|
func _on_equipment_slot_gui_input(event: InputEvent, slot_name: String):
|
||||||
|
# Handle double-click to unequip
|
||||||
|
if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_LEFT:
|
||||||
|
if event.double_click and event.pressed:
|
||||||
|
# Double-click detected - unequip the item
|
||||||
|
selected_slot = slot_name
|
||||||
|
selected_item = local_player.character_stats.equipment[slot_name] if local_player and local_player.character_stats else null
|
||||||
|
selected_type = "equipment" if selected_item else ""
|
||||||
|
|
||||||
|
if selected_type == "equipment" and selected_slot != "":
|
||||||
|
# Use the same logic as F key to unequip
|
||||||
|
_handle_f_key()
|
||||||
|
|
||||||
func _update_selection_highlight():
|
func _update_selection_highlight():
|
||||||
# This function is kept for compatibility but now uses _update_selection_rectangle()
|
# This function is kept for compatibility but now uses _update_selection_rectangle()
|
||||||
_update_selection_rectangle()
|
_update_selection_rectangle()
|
||||||
@@ -488,6 +502,7 @@ func _update_ui():
|
|||||||
button.flat = false # Use styleboxes
|
button.flat = false # Use styleboxes
|
||||||
button.focus_mode = Control.FOCUS_ALL # Allow button to receive focus
|
button.focus_mode = Control.FOCUS_ALL # Allow button to receive focus
|
||||||
button.connect("pressed", _on_inventory_item_pressed.bind(item))
|
button.connect("pressed", _on_inventory_item_pressed.bind(item))
|
||||||
|
button.connect("gui_input", _on_inventory_item_gui_input.bind(item))
|
||||||
# Connect focus_entered like inspiration system (for keyboard navigation)
|
# Connect focus_entered like inspiration system (for keyboard navigation)
|
||||||
# Note: focus_entered will trigger when we call grab_focus(), but _on_inventory_item_pressed
|
# Note: focus_entered will trigger when we call grab_focus(), but _on_inventory_item_pressed
|
||||||
# just updates selection state, so it should be safe
|
# just updates selection state, so it should be safe
|
||||||
@@ -540,28 +555,58 @@ func _update_ui():
|
|||||||
inventory_selection_col = max(0, row.get_child_count() - 1)
|
inventory_selection_col = max(0, row.get_child_count() - 1)
|
||||||
|
|
||||||
# Update selection only if selected_type is already set (don't auto-update during initialization)
|
# Update selection only if selected_type is already set (don't auto-update during initialization)
|
||||||
if selected_type != "":
|
# Don't call _set_selection() here if we already have a valid selection - it will reset to 0,0
|
||||||
|
# Only call it if selection is empty or invalid
|
||||||
|
var should_reset_selection = false
|
||||||
|
if selected_type == "":
|
||||||
|
should_reset_selection = true
|
||||||
|
elif selected_type == "item":
|
||||||
|
# Check if current selection is still valid
|
||||||
|
if inventory_selection_row < 0 or inventory_selection_row >= inventory_rows_list.size():
|
||||||
|
should_reset_selection = true
|
||||||
|
elif inventory_selection_row >= 0 and inventory_selection_row < inventory_rows_list.size():
|
||||||
|
var row = inventory_rows_list[inventory_selection_row]
|
||||||
|
if inventory_selection_col < 0 or inventory_selection_col >= row.get_child_count():
|
||||||
|
should_reset_selection = true
|
||||||
|
|
||||||
|
if should_reset_selection:
|
||||||
|
_set_selection()
|
||||||
|
elif selected_type != "":
|
||||||
|
# Selection is valid, just update it
|
||||||
_update_selection_from_navigation()
|
_update_selection_from_navigation()
|
||||||
_update_selection_rectangle()
|
_update_selection_rectangle()
|
||||||
_update_info_panel()
|
_update_info_panel()
|
||||||
|
|
||||||
_set_selection()
|
|
||||||
|
|
||||||
# Reset update flag
|
# Reset update flag
|
||||||
is_updating_ui = false
|
is_updating_ui = false
|
||||||
|
|
||||||
func _set_selection():
|
func _set_selection():
|
||||||
# NOW check for items AFTER UI is updated
|
# NOW check for items AFTER UI is updated
|
||||||
# Initialize selection - prefer inventory, but if empty, check equipment
|
# Initialize selection - prefer inventory, but if empty, check equipment
|
||||||
|
# Only set initial selection if not already set, or if current selection is invalid
|
||||||
|
var needs_initial_selection = false
|
||||||
|
if selected_type == "":
|
||||||
|
needs_initial_selection = true
|
||||||
|
elif selected_type == "item":
|
||||||
|
# Check if current selection is still valid
|
||||||
|
if inventory_selection_row >= inventory_rows_list.size() or inventory_selection_row < 0:
|
||||||
|
needs_initial_selection = true
|
||||||
|
elif inventory_selection_row >= 0 and inventory_selection_row < inventory_rows_list.size():
|
||||||
|
var row = inventory_rows_list[inventory_selection_row]
|
||||||
|
if inventory_selection_col >= row.get_child_count() or inventory_selection_col < 0:
|
||||||
|
needs_initial_selection = true
|
||||||
|
|
||||||
# Check if we have inventory items
|
# Check if we have inventory items
|
||||||
if inventory_rows_list.size() > 0 and inventory_items_list.size() > 0:
|
if inventory_rows_list.size() > 0 and inventory_items_list.size() > 0:
|
||||||
|
if needs_initial_selection:
|
||||||
|
# Only reset to 0 if we need initial selection
|
||||||
selected_type = "item"
|
selected_type = "item"
|
||||||
inventory_selection_row = 0
|
inventory_selection_row = 0
|
||||||
inventory_selection_col = 0
|
inventory_selection_col = 0
|
||||||
# Ensure selection is set correctly
|
# Ensure selection is set correctly (preserves existing selection if valid)
|
||||||
_update_selection_from_navigation()
|
_update_selection_from_navigation()
|
||||||
# Debug: Print selection state
|
# Debug: Print selection state
|
||||||
print("InventoryUI: Initial selection - type: ", selected_type, " row: ", inventory_selection_row, " col: ", inventory_selection_col, " item: ", selected_item)
|
print("InventoryUI: Selection - type: ", selected_type, " row: ", inventory_selection_row, " col: ", inventory_selection_col, " item: ", selected_item)
|
||||||
# Now set focus - buttons should be ready
|
# Now set focus - buttons should be ready
|
||||||
await _update_selection_rectangle() # Await to ensure focus is set
|
await _update_selection_rectangle() # Await to ensure focus is set
|
||||||
_update_info_panel()
|
_update_info_panel()
|
||||||
@@ -859,6 +904,40 @@ func _on_inventory_item_pressed(item: Item):
|
|||||||
_update_selection_highlight()
|
_update_selection_highlight()
|
||||||
_update_selection_rectangle()
|
_update_selection_rectangle()
|
||||||
|
|
||||||
|
func _on_inventory_item_gui_input(event: InputEvent, item: Item):
|
||||||
|
# Handle double-click to equip/consume and right-click to drop
|
||||||
|
if event is InputEventMouseButton:
|
||||||
|
if event.button_index == MOUSE_BUTTON_LEFT and event.double_click and event.pressed:
|
||||||
|
# Double-click detected - equip or consume the item
|
||||||
|
selected_item = item
|
||||||
|
selected_slot = ""
|
||||||
|
selected_type = "item"
|
||||||
|
|
||||||
|
# Update navigation position first
|
||||||
|
var item_index = inventory_items_list.find(item)
|
||||||
|
if item_index >= 0:
|
||||||
|
var items_per_row: int = 8
|
||||||
|
inventory_selection_row = floor(item_index / float(items_per_row))
|
||||||
|
inventory_selection_col = item_index % items_per_row
|
||||||
|
|
||||||
|
# Use the same logic as F key to equip/consume
|
||||||
|
_handle_f_key()
|
||||||
|
elif event.button_index == MOUSE_BUTTON_RIGHT and event.pressed:
|
||||||
|
# Right-click detected - drop the item
|
||||||
|
selected_item = item
|
||||||
|
selected_slot = ""
|
||||||
|
selected_type = "item"
|
||||||
|
|
||||||
|
# Update navigation position first
|
||||||
|
var item_index = inventory_items_list.find(item)
|
||||||
|
if item_index >= 0:
|
||||||
|
var items_per_row: int = 8
|
||||||
|
inventory_selection_row = floor(item_index / float(items_per_row))
|
||||||
|
inventory_selection_col = item_index % items_per_row
|
||||||
|
|
||||||
|
# Use the same logic as E key to drop
|
||||||
|
_handle_e_key()
|
||||||
|
|
||||||
func _on_character_changed(_char: CharacterStats):
|
func _on_character_changed(_char: CharacterStats):
|
||||||
# Always update stats when character changes (even if inventory is closed)
|
# Always update stats when character changes (even if inventory is closed)
|
||||||
# Equipment changes affect max HP/MP which should be reflected everywhere
|
# Equipment changes affect max HP/MP which should be reflected everywhere
|
||||||
@@ -984,25 +1063,90 @@ func _handle_f_key():
|
|||||||
Item.EquipmentType.ACCESSORY:
|
Item.EquipmentType.ACCESSORY:
|
||||||
target_slot_name = "accessory"
|
target_slot_name = "accessory"
|
||||||
|
|
||||||
|
# Remember current item position before equipping
|
||||||
|
var items_per_row = 8
|
||||||
|
var current_item_index = inventory_selection_row * items_per_row + inventory_selection_col
|
||||||
|
|
||||||
|
# Check if target slot has an item (will be placed back in inventory)
|
||||||
|
var slot_has_item = char_stats.equipment[target_slot_name] != null
|
||||||
|
|
||||||
# Check if this is the last item in inventory (before equipping)
|
# Check if this is the last item in inventory (before equipping)
|
||||||
var was_last_item = char_stats.inventory.size() == 1
|
var was_last_item = char_stats.inventory.size() == 1
|
||||||
|
|
||||||
char_stats.equip_item(selected_item)
|
# Equip the item, placing old item at the same position if slot had an item
|
||||||
|
var insert_index = current_item_index if slot_has_item else -1
|
||||||
|
char_stats.equip_item(selected_item, insert_index)
|
||||||
|
|
||||||
# Play armour sound when equipping
|
# Play armour sound when equipping
|
||||||
if sfx_armour:
|
if sfx_armour:
|
||||||
sfx_armour.play()
|
sfx_armour.play()
|
||||||
|
|
||||||
# If this was the last item, set selection state BEFORE _update_ui()
|
# Update UI first
|
||||||
# so that _update_selection_from_navigation() works correctly
|
_update_ui()
|
||||||
if was_last_item and target_slot_name != "":
|
|
||||||
|
# If slot had an item, keep selection at the same position (old item is now there)
|
||||||
|
if slot_has_item and current_item_index < char_stats.inventory.size():
|
||||||
|
# Keep selection at the same position
|
||||||
|
selected_type = "item"
|
||||||
|
selected_slot = ""
|
||||||
|
# Recalculate row/col from index (may have changed if rows shifted)
|
||||||
|
inventory_selection_row = floor(current_item_index / float(items_per_row))
|
||||||
|
inventory_selection_col = current_item_index % items_per_row
|
||||||
|
# Ensure row/col are within bounds
|
||||||
|
if inventory_selection_row >= inventory_rows_list.size():
|
||||||
|
inventory_selection_row = max(0, inventory_rows_list.size() - 1)
|
||||||
|
if inventory_selection_row >= 0 and inventory_selection_row < inventory_rows_list.size():
|
||||||
|
var row = inventory_rows_list[inventory_selection_row]
|
||||||
|
if inventory_selection_col >= row.get_child_count():
|
||||||
|
inventory_selection_col = max(0, row.get_child_count() - 1)
|
||||||
|
_update_selection_from_navigation()
|
||||||
|
elif was_last_item and target_slot_name != "":
|
||||||
|
# Last item was equipped, move selection to equipment slot
|
||||||
if target_slot_name in equipment_slots_list:
|
if target_slot_name in equipment_slots_list:
|
||||||
selected_type = "equipment"
|
selected_type = "equipment"
|
||||||
selected_slot = target_slot_name
|
selected_slot = target_slot_name
|
||||||
equipment_selection_index = equipment_slots_list.find(target_slot_name)
|
equipment_selection_index = equipment_slots_list.find(target_slot_name)
|
||||||
selected_item = char_stats.equipment[target_slot_name]
|
selected_item = char_stats.equipment[target_slot_name]
|
||||||
|
_update_selection_from_navigation()
|
||||||
_update_ui()
|
else:
|
||||||
|
# Item was removed, try to keep selection at same position if possible
|
||||||
|
if current_item_index < char_stats.inventory.size():
|
||||||
|
# Item at next position moved up, keep selection there
|
||||||
|
selected_type = "item"
|
||||||
|
selected_slot = ""
|
||||||
|
inventory_selection_row = floor(current_item_index / float(items_per_row))
|
||||||
|
inventory_selection_col = current_item_index % items_per_row
|
||||||
|
if inventory_selection_row >= inventory_rows_list.size():
|
||||||
|
inventory_selection_row = max(0, inventory_rows_list.size() - 1)
|
||||||
|
if inventory_selection_row >= 0 and inventory_selection_row < inventory_rows_list.size():
|
||||||
|
var row = inventory_rows_list[inventory_selection_row]
|
||||||
|
if inventory_selection_col >= row.get_child_count():
|
||||||
|
inventory_selection_col = max(0, row.get_child_count() - 1)
|
||||||
|
_update_selection_from_navigation()
|
||||||
|
elif current_item_index > 0:
|
||||||
|
# Move to previous position (current_item_index - 1) if current is out of bounds
|
||||||
|
var previous_index = current_item_index - 1
|
||||||
|
inventory_selection_row = floor(previous_index / float(items_per_row))
|
||||||
|
inventory_selection_col = previous_index % items_per_row
|
||||||
|
if inventory_selection_row >= 0 and inventory_selection_row < inventory_rows_list.size():
|
||||||
|
var row = inventory_rows_list[inventory_selection_row]
|
||||||
|
if inventory_selection_col >= row.get_child_count():
|
||||||
|
inventory_selection_col = max(0, row.get_child_count() - 1)
|
||||||
|
selected_type = "item"
|
||||||
|
selected_slot = ""
|
||||||
|
_update_selection_from_navigation()
|
||||||
|
else:
|
||||||
|
# Previous position is also out of bounds, move to equipment if available
|
||||||
|
selected_type = ""
|
||||||
|
selected_slot = ""
|
||||||
|
selected_item = null
|
||||||
|
_update_selection_from_navigation()
|
||||||
|
else:
|
||||||
|
# No items left, move to equipment if available
|
||||||
|
selected_type = ""
|
||||||
|
selected_slot = ""
|
||||||
|
selected_item = null
|
||||||
|
_update_selection_from_navigation()
|
||||||
|
|
||||||
# Update selection rectangle and info panel
|
# Update selection rectangle and info panel
|
||||||
_update_selection_rectangle()
|
_update_selection_rectangle()
|
||||||
@@ -1017,6 +1161,10 @@ func _use_consumable_item(item: Item):
|
|||||||
|
|
||||||
var char_stats = local_player.character_stats
|
var char_stats = local_player.character_stats
|
||||||
|
|
||||||
|
# Remember current item position before consuming
|
||||||
|
var items_per_row = 8
|
||||||
|
var current_item_index = inventory_selection_row * items_per_row + inventory_selection_col
|
||||||
|
|
||||||
# Determine if it's a potion or food based on item name
|
# Determine if it's a potion or food based on item name
|
||||||
var is_potion = "potion" in item.item_name.to_lower()
|
var is_potion = "potion" in item.item_name.to_lower()
|
||||||
|
|
||||||
@@ -1042,6 +1190,43 @@ func _use_consumable_item(item: Item):
|
|||||||
char_stats.inventory.remove_at(index)
|
char_stats.inventory.remove_at(index)
|
||||||
char_stats.character_changed.emit(char_stats)
|
char_stats.character_changed.emit(char_stats)
|
||||||
|
|
||||||
|
# Update UI first
|
||||||
|
_update_ui()
|
||||||
|
|
||||||
|
# Try to keep selection at the same position if possible
|
||||||
|
if current_item_index < char_stats.inventory.size():
|
||||||
|
# Item at next position moved up, keep selection there
|
||||||
|
selected_type = "item"
|
||||||
|
selected_slot = ""
|
||||||
|
inventory_selection_row = floor(current_item_index / float(items_per_row))
|
||||||
|
inventory_selection_col = current_item_index % items_per_row
|
||||||
|
if inventory_selection_row >= inventory_rows_list.size():
|
||||||
|
inventory_selection_row = max(0, inventory_rows_list.size() - 1)
|
||||||
|
if inventory_selection_row >= 0 and inventory_selection_row < inventory_rows_list.size():
|
||||||
|
var row = inventory_rows_list[inventory_selection_row]
|
||||||
|
if inventory_selection_col >= row.get_child_count():
|
||||||
|
inventory_selection_col = max(0, row.get_child_count() - 1)
|
||||||
|
_update_selection_from_navigation()
|
||||||
|
_update_selection_rectangle()
|
||||||
|
elif current_item_index > 0:
|
||||||
|
# Move to previous position if current is out of bounds
|
||||||
|
current_item_index = char_stats.inventory.size() - 1
|
||||||
|
inventory_selection_row = floor(current_item_index / float(items_per_row))
|
||||||
|
inventory_selection_col = current_item_index % items_per_row
|
||||||
|
if inventory_selection_row >= 0 and inventory_selection_row < inventory_rows_list.size():
|
||||||
|
var row = inventory_rows_list[inventory_selection_row]
|
||||||
|
if inventory_selection_col >= row.get_child_count():
|
||||||
|
inventory_selection_col = max(0, row.get_child_count() - 1)
|
||||||
|
_update_selection_from_navigation()
|
||||||
|
_update_selection_rectangle()
|
||||||
|
else:
|
||||||
|
# No items left, clear selection
|
||||||
|
selected_type = ""
|
||||||
|
selected_slot = ""
|
||||||
|
selected_item = null
|
||||||
|
_update_selection_from_navigation()
|
||||||
|
_update_selection_rectangle()
|
||||||
|
|
||||||
print(local_player.name, " used item: ", item.item_name)
|
print(local_player.name, " used item: ", item.item_name)
|
||||||
|
|
||||||
func _handle_e_key():
|
func _handle_e_key():
|
||||||
|
|||||||
@@ -27,8 +27,8 @@ static func spawn_item_loot(item: Item, position: Vector2, entities_node: Node,
|
|||||||
loot_rng.seed = loot_seed
|
loot_rng.seed = loot_seed
|
||||||
|
|
||||||
var random_angle = loot_rng.randf() * PI * 2
|
var random_angle = loot_rng.randf() * PI * 2
|
||||||
var random_force = loot_rng.randf_range(50.0, 100.0)
|
var random_force = loot_rng.randf_range(25.0, 50.0) # Reduced to half speed
|
||||||
var random_velocity_z = loot_rng.randf_range(80.0, 120.0)
|
var random_velocity_z = loot_rng.randf_range(40.0, 60.0) # Reduced to half speed
|
||||||
var initial_velocity = Vector2(cos(random_angle), sin(random_angle)) * random_force
|
var initial_velocity = Vector2(cos(random_angle), sin(random_angle)) * random_force
|
||||||
|
|
||||||
# Find safe spawn position if game_world is provided
|
# Find safe spawn position if game_world is provided
|
||||||
|
|||||||
@@ -641,14 +641,27 @@ func _create_peer_connection(peer_id: int) -> WebRTCPeerConnection:
|
|||||||
|
|
||||||
# Add TURN server as separate entry with credentials
|
# Add TURN server as separate entry with credentials
|
||||||
if not TURN_SERVER.is_empty():
|
if not TURN_SERVER.is_empty():
|
||||||
# For TURN, create URLs array with both UDP and TCP transports
|
# For TURN, create URLs array with appropriate transports
|
||||||
|
# Note: libjuice (native builds) only supports UDP transport
|
||||||
|
# WebAssembly (browser) supports both UDP and TCP/TLS
|
||||||
var turn_urls = []
|
var turn_urls = []
|
||||||
|
var is_web = OS.get_name() == "Web"
|
||||||
|
|
||||||
if TURN_SERVER.begins_with("turns:"):
|
if TURN_SERVER.begins_with("turns:"):
|
||||||
# TURNS over TLS: primarily TCP
|
# TURNS over TLS: TCP transport (browser only, libjuice doesn't support it)
|
||||||
|
if is_web:
|
||||||
turn_urls.append(TURN_SERVER + "?transport=tcp")
|
turn_urls.append(TURN_SERVER + "?transport=tcp")
|
||||||
else:
|
else:
|
||||||
# Standard TURN: try both UDP and TCP
|
# Native builds: skip TLS (libjuice limitation), use UDP fallback if available
|
||||||
|
log_print("MatchboxClient: Skipping TLS transport for native build (libjuice limitation)")
|
||||||
|
# Convert turns: to turn: and use UDP transport for native builds
|
||||||
|
var udp_turn_server = TURN_SERVER.replace("turns:", "turn:")
|
||||||
|
turn_urls.append(udp_turn_server + "?transport=udp")
|
||||||
|
else:
|
||||||
|
# Standard TURN: UDP works everywhere, TCP only on browser
|
||||||
turn_urls.append(TURN_SERVER + "?transport=udp")
|
turn_urls.append(TURN_SERVER + "?transport=udp")
|
||||||
|
if is_web:
|
||||||
|
# Add TCP transport for browsers (can help with restrictive firewalls)
|
||||||
turn_urls.append(TURN_SERVER + "?transport=tcp")
|
turn_urls.append(TURN_SERVER + "?transport=tcp")
|
||||||
|
|
||||||
# Create TURN server configuration
|
# Create TURN server configuration
|
||||||
|
|||||||
@@ -820,14 +820,27 @@ func create_peer_connection() -> WebRTCPeerConnection:
|
|||||||
|
|
||||||
# Add TURN server as separate entry with credentials
|
# Add TURN server as separate entry with credentials
|
||||||
if not TURN_SERVER.is_empty():
|
if not TURN_SERVER.is_empty():
|
||||||
# For TURN, create URLs array with both UDP and TCP transports
|
# For TURN, create URLs array with appropriate transports
|
||||||
|
# Note: libjuice (native builds) only supports UDP transport
|
||||||
|
# WebAssembly (browser) supports both UDP and TCP/TLS
|
||||||
var turn_urls = []
|
var turn_urls = []
|
||||||
|
var is_web = OS.get_name() == "Web"
|
||||||
|
|
||||||
if TURN_SERVER.begins_with("turns:"):
|
if TURN_SERVER.begins_with("turns:"):
|
||||||
# TURNS over TLS: primarily TCP
|
# TURNS over TLS: TCP transport (browser only, libjuice doesn't support it)
|
||||||
|
if is_web:
|
||||||
turn_urls.append(TURN_SERVER + "?transport=tcp")
|
turn_urls.append(TURN_SERVER + "?transport=tcp")
|
||||||
else:
|
else:
|
||||||
# Standard TURN: try both UDP and TCP
|
# Native builds: skip TLS (libjuice limitation), use UDP fallback if available
|
||||||
|
print("NetworkManager: Skipping TLS transport for native build (libjuice limitation)")
|
||||||
|
# Convert turns: to turn: and use UDP transport for native builds
|
||||||
|
var udp_turn_server = TURN_SERVER.replace("turns:", "turn:")
|
||||||
|
turn_urls.append(udp_turn_server + "?transport=udp")
|
||||||
|
else:
|
||||||
|
# Standard TURN: UDP works everywhere, TCP only on browser
|
||||||
turn_urls.append(TURN_SERVER + "?transport=udp")
|
turn_urls.append(TURN_SERVER + "?transport=udp")
|
||||||
|
if is_web:
|
||||||
|
# Add TCP transport for browsers (can help with restrictive firewalls)
|
||||||
turn_urls.append(TURN_SERVER + "?transport=tcp")
|
turn_urls.append(TURN_SERVER + "?transport=tcp")
|
||||||
|
|
||||||
# Create TURN server configuration
|
# Create TURN server configuration
|
||||||
|
|||||||
@@ -3415,8 +3415,13 @@ func take_damage(amount: float, attacker_position: Vector2):
|
|||||||
actual_damage = amount
|
actual_damage = amount
|
||||||
print(name, " took ", amount, " damage! Health: ", current_health)
|
print(name, " took ", amount, " damage! Health: ", current_health)
|
||||||
|
|
||||||
# Play damage sound effect
|
# Play damage sound effect (rate limited to prevent spam when tab becomes active)
|
||||||
|
var game_world = get_tree().get_first_node_in_group("game_world")
|
||||||
if sfx_take_damage:
|
if sfx_take_damage:
|
||||||
|
if game_world and game_world.has_method("can_play_sound"):
|
||||||
|
if game_world.can_play_sound("player_damage_" + str(get_instance_id())):
|
||||||
|
sfx_take_damage.play()
|
||||||
|
else:
|
||||||
sfx_take_damage.play()
|
sfx_take_damage.play()
|
||||||
|
|
||||||
# Play damage animation
|
# Play damage animation
|
||||||
@@ -3991,8 +3996,13 @@ func _sync_damage(_amount: float, attacker_position: Vector2, is_crit: bool = fa
|
|||||||
_show_damage_number(0.0, attacker_position, false, false, true)
|
_show_damage_number(0.0, attacker_position, false, false, true)
|
||||||
return
|
return
|
||||||
|
|
||||||
# Play damage sound and effects
|
# Play damage sound and effects (rate limited to prevent spam when tab becomes active)
|
||||||
|
var game_world = get_tree().get_first_node_in_group("game_world")
|
||||||
if sfx_take_damage:
|
if sfx_take_damage:
|
||||||
|
if game_world and game_world.has_method("can_play_sound"):
|
||||||
|
if game_world.can_play_sound("player_damage_sync_" + str(get_instance_id())):
|
||||||
|
sfx_take_damage.play()
|
||||||
|
else:
|
||||||
sfx_take_damage.play()
|
sfx_take_damage.play()
|
||||||
|
|
||||||
# Play damage animation
|
# Play damage animation
|
||||||
|
|||||||
Reference in New Issue
Block a user