fixed so there isn't too many spam messages

This commit is contained in:
2026-01-20 02:48:14 +01:00
parent e44eeb6dea
commit 22cb66877c
12 changed files with 983 additions and 159 deletions

View File

@@ -23,6 +23,7 @@ stream_0/stream = ExtResource("7_pg2b6")
stream_1/stream = ExtResource("7_kgbum")
[node name="Door" type="StaticBody2D" unique_id=371155975]
y_sort_enabled = true
collision_layer = 64
script = ExtResource("1_uvdjg")

View File

@@ -8,6 +8,7 @@ default_font = ExtResource("2_dmg_font")
default_font_size = 12
[node name="FloatingText" type="Node2D" unique_id=1350559946]
z_index = 3
script = ExtResource("1")
[node name="ItemSprite" type="Sprite2D" parent="." unique_id=1657362510]
@@ -15,6 +16,7 @@ visible = false
offset = Vector2(0, -8)
[node name="Label" type="Label" parent="." unique_id=1387220833]
z_index = 3
offset_right = 64.0
offset_bottom = 24.0
theme = SubResource("Theme_floating_text")

View File

@@ -386,7 +386,7 @@ ignore_texture_size = true
stretch_mode = 5
script = ExtResource("8_cu5yl")
touchscreen_only = true
input_action = "attack"
input_action = "inventory"
metadata/_custom_type_script = "uid://bh5a3ydiu51eo"
[connection signal="analogic_changed" from="MobileInput/VirtualJoystick" to="MobileInput" method="_on_virtual_joystick_analogic_changed"]

View File

@@ -309,7 +309,7 @@ collision_mask = 16384
shape = SubResource("CircleShape2D_pf23h")
[node name="Shadow" type="Sprite2D" parent="." unique_id=937683521]
position = Vector2(0, 8)
position = Vector2(0, 7)
texture = SubResource("GradientTexture2D_jej6c")
script = ExtResource("3")

View File

@@ -579,54 +579,64 @@ func forceUpdate():
emit_signal("character_changed", self)
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:
return
var old_item = null
var item_index = self.inventory.find(iItem)
match iItem.equipment_type:
Item.EquipmentType.MAINHAND:
if equipment["mainhand"] != null:
self.inventory.push_back(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
old_item = equipment["mainhand"]
equipment["mainhand"] = iItem
pass
pass
Item.EquipmentType.OFFHAND:
if equipment["offhand"] != null:
self.inventory.push_back(equipment["offhand"])
old_item = equipment["offhand"]
equipment["offhand"] = iItem
pass
pass
Item.EquipmentType.HEADGEAR:
if equipment["headgear"] != null:
self.inventory.push_back(equipment["headgear"])
old_item = equipment["headgear"]
equipment["headgear"] = iItem
pass
pass
Item.EquipmentType.ARMOUR:
if equipment["armour"] != null:
self.inventory.push_back(equipment["armour"])
old_item = equipment["armour"]
equipment["armour"] = iItem
pass
pass
Item.EquipmentType.BOOTS:
if equipment["boots"] != null:
self.inventory.push_back(equipment["boots"])
old_item = equipment["boots"]
equipment["boots"] = iItem
pass
pass
Item.EquipmentType.ACCESSORY:
if equipment["accessory"] != null:
self.inventory.push_back(equipment["accessory"])
old_item = equipment["accessory"]
equipment["accessory"] = iItem
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)
pass

View File

@@ -661,8 +661,8 @@ func _spawn_loot():
loot_rng.seed = loot_seed
var random_angle = loot_rng.randf() * PI * 2
var random_force = loot_rng.randf_range(50.0, 100.0)
var random_velocity_z = loot_rng.randf_range(80.0, 120.0)
var random_force = loot_rng.randf_range(25.0, 50.0) # Reduced to half speed
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)
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
# Regenerate velocity with correct seed
var real_random_angle = loot_rng.randf() * PI * 2
var real_random_force = loot_rng.randf_range(50.0, 100.0)
var real_random_velocity_z = loot_rng.randf_range(80.0, 120.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(40.0, 60.0) # Reduced to half speed
initial_velocity = Vector2(cos(real_random_angle), sin(real_random_angle)) * real_random_force
random_velocity_z = real_random_velocity_z
# Update loot with correct velocity

File diff suppressed because it is too large Load Diff

View File

@@ -233,6 +233,7 @@ func _create_equipment_slots():
button.size_flags_horizontal = 0
button.size_flags_vertical = 0
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)
if local_player and local_player.character_stats:
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_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():
# This function is kept for compatibility but now uses _update_selection_rectangle()
_update_selection_rectangle()
@@ -488,6 +502,7 @@ func _update_ui():
button.flat = false # Use styleboxes
button.focus_mode = Control.FOCUS_ALL # Allow button to receive focus
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)
# Note: focus_entered will trigger when we call grab_focus(), but _on_inventory_item_pressed
# 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)
# 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_rectangle()
_update_info_panel()
_set_selection()
# Reset update flag
is_updating_ui = false
func _set_selection():
# NOW check for items AFTER UI is updated
# 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
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"
inventory_selection_row = 0
inventory_selection_col = 0
# Ensure selection is set correctly
# Ensure selection is set correctly (preserves existing selection if valid)
_update_selection_from_navigation()
# 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
await _update_selection_rectangle() # Await to ensure focus is set
_update_info_panel()
@@ -859,6 +904,40 @@ func _on_inventory_item_pressed(item: Item):
_update_selection_highlight()
_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):
# Always update stats when character changes (even if inventory is closed)
# Equipment changes affect max HP/MP which should be reflected everywhere
@@ -984,25 +1063,90 @@ func _handle_f_key():
Item.EquipmentType.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)
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
if sfx_armour:
sfx_armour.play()
# If this was the last item, set selection state BEFORE _update_ui()
# so that _update_selection_from_navigation() works correctly
if was_last_item and target_slot_name != "":
# Update UI first
_update_ui()
# 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:
selected_type = "equipment"
selected_slot = target_slot_name
equipment_selection_index = equipment_slots_list.find(target_slot_name)
selected_item = char_stats.equipment[target_slot_name]
_update_ui()
_update_selection_from_navigation()
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()
@@ -1017,6 +1161,10 @@ func _use_consumable_item(item: Item):
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
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.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)
func _handle_e_key():

View File

@@ -27,8 +27,8 @@ static func spawn_item_loot(item: Item, position: Vector2, entities_node: Node,
loot_rng.seed = loot_seed
var random_angle = loot_rng.randf() * PI * 2
var random_force = loot_rng.randf_range(50.0, 100.0)
var random_velocity_z = loot_rng.randf_range(80.0, 120.0)
var random_force = loot_rng.randf_range(25.0, 50.0) # Reduced to half speed
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
# Find safe spawn position if game_world is provided

View File

@@ -641,14 +641,27 @@ func _create_peer_connection(peer_id: int) -> WebRTCPeerConnection:
# Add TURN server as separate entry with credentials
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 is_web = OS.get_name() == "Web"
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")
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")
if is_web:
# Add TCP transport for browsers (can help with restrictive firewalls)
turn_urls.append(TURN_SERVER + "?transport=tcp")
# Create TURN server configuration

View File

@@ -820,14 +820,27 @@ func create_peer_connection() -> WebRTCPeerConnection:
# Add TURN server as separate entry with credentials
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 is_web = OS.get_name() == "Web"
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")
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")
if is_web:
# Add TCP transport for browsers (can help with restrictive firewalls)
turn_urls.append(TURN_SERVER + "?transport=tcp")
# Create TURN server configuration

View File

@@ -3415,8 +3415,13 @@ func take_damage(amount: float, attacker_position: Vector2):
actual_damage = amount
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 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()
# 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)
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 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()
# Play damage animation