push ze latest and greatest

This commit is contained in:
2025-12-30 16:22:06 +01:00
parent def119e21d
commit 1725c615ce
9 changed files with 1698 additions and 24 deletions

View File

@@ -113,8 +113,11 @@ func _addPlayer(id: int):
if min_distance > best_distance: if min_distance > best_distance:
best_distance = min_distance best_distance = min_distance
best_spawn = pos best_spawn = pos
# CRITICAL: Set position BEFORE adding child so MultiplayerSynchronizer syncs the correct value
player.position = best_spawn player.position = best_spawn
print("Setting player ", id, " spawn position to: ", best_spawn)
$SpawnRoot.add_child(player) $SpawnRoot.add_child(player)
if id == multiplayer.get_unique_id(): if id == multiplayer.get_unique_id():
player.initStats(MultiplayerManager.character_data) # iniitate with own stats, cuz this is us... player.initStats(MultiplayerManager.character_data) # iniitate with own stats, cuz this is us...

View File

@@ -781,30 +781,29 @@ horizontal_alignment = 1
[node name="Node2DPlayerNames" type="Node2D" parent="HUD" unique_id=176021972] [node name="Node2DPlayerNames" type="Node2D" parent="HUD" unique_id=176021972]
[node name="PlayerSpawnPoints" type="Node2D" parent="." unique_id=1413557024] [node name="PlayerSpawnPoints" type="Node2D" parent="." unique_id=1413557024]
position = Vector2(0, 1)
[node name="SpawnPointA" type="Sprite2D" parent="PlayerSpawnPoints" unique_id=475389955] [node name="SpawnPointA" type="Sprite2D" parent="PlayerSpawnPoints" unique_id=475389955]
visible = false visible = false
z_index = 6 z_index = 6
position = Vector2(-24, 7) position = Vector2(-24, 8)
texture = ExtResource("7_272bh") texture = ExtResource("7_272bh")
[node name="SpawnPointA2" type="Sprite2D" parent="PlayerSpawnPoints" unique_id=1602800528] [node name="SpawnPointA2" type="Sprite2D" parent="PlayerSpawnPoints" unique_id=1602800528]
visible = false visible = false
z_index = 6 z_index = 6
position = Vector2(-24, 151) position = Vector2(-24, 152)
texture = ExtResource("7_272bh") texture = ExtResource("7_272bh")
[node name="SpawnPointA3" type="Sprite2D" parent="PlayerSpawnPoints" unique_id=2121277940] [node name="SpawnPointA3" type="Sprite2D" parent="PlayerSpawnPoints" unique_id=2121277940]
visible = false visible = false
z_index = 6 z_index = 6
position = Vector2(200, 151) position = Vector2(200, 152)
texture = ExtResource("7_272bh") texture = ExtResource("7_272bh")
[node name="SpawnPointA4" type="Sprite2D" parent="PlayerSpawnPoints" unique_id=718892012] [node name="SpawnPointA4" type="Sprite2D" parent="PlayerSpawnPoints" unique_id=718892012]
visible = false visible = false
z_index = 6 z_index = 6
position = Vector2(216, 7) position = Vector2(216, 8)
texture = ExtResource("7_272bh") texture = ExtResource("7_272bh")
[node name="TimerUntilNextRound" type="Timer" parent="." unique_id=807927406] [node name="TimerUntilNextRound" type="Timer" parent="." unique_id=807927406]

View File

@@ -59,7 +59,7 @@ var accelerationZ = -330.0 # Gravity
locked_grab_direction = Vector2.ZERO # Clear locked direction when releasing locked_grab_direction = Vector2.ZERO # Clear locked direction when releasing
var is_player = true var is_player = true
@export var direction_vector = Vector2(0, 0) var direction_vector = Vector2(0, 0) # NOT exported - each player handles their own input locally
const ANIMATIONS = { const ANIMATIONS = {
"IDLE": { "IDLE": {
@@ -577,21 +577,18 @@ func _apply_movement_from_input(_delta: float) -> void:
locked_grab_direction = Vector2.ZERO locked_grab_direction = Vector2.ZERO
is_grabbing = false is_grabbing = false
var pot = a.get_parent() var pot = a.get_parent()
if multiplayer.is_server():
# Server can interact directly
held_entity = pot held_entity = pot
held_entity_path = str(pot.get_path()) held_entity_path = str(pot.get_path())
pot.lift(self) pot.lift(self)
current_animation = "LIFT" current_animation = "LIFT"
else:
if multiplayer.is_server(): # Client uses RPC to request from server
# Server can interact directly # DON'T set animation or held_entity here - server will sync it
held_entity = pot MultiplayerManager.request_lift_pot.rpc_id(1, pot.get_path(), multiplayer.get_unique_id())
#held_entity_path = str(pot.get_path())
#pot.lift(self)
#current_animation = "LIFT"
else:
# Client uses RPC to request from server
MultiplayerManager.request_lift_pot.rpc_id(1, pot.get_path(), multiplayer.get_unique_id())
break # only allow 1 at a time :) break # only allow 1 at a time :)
pass pass
pass pass
@@ -602,7 +599,9 @@ func _apply_movement_from_input(_delta: float) -> void:
is_grabbing = false is_grabbing = false
if held_entity == null: if held_entity == null:
is_lifting = false is_lifting = false
elif held_entity != null and is_lifting == false: # CRITICAL: Only run auto-throw/put-down logic for the authority (the player controlling this character)
# Otherwise, when held_entity_path syncs, ALL clients will run this and set animations
elif held_entity != null and is_lifting == false and get_multiplayer_authority() == multiplayer.get_unique_id():
if velocity.x != 0 or velocity.y != 0: if velocity.x != 0 or velocity.y != 0:
if multiplayer.is_server(): if multiplayer.is_server():
held_entity.throw(last_direction) held_entity.throw(last_direction)
@@ -1071,6 +1070,12 @@ func set_grabbed_entity_path_rpc(entity_path: String):
# This ensures locked_grab_direction is set correctly via the setter # This ensures locked_grab_direction is set correctly via the setter
grabbed_entity_path = entity_path grabbed_entity_path = entity_path
@rpc("authority", "reliable")
func sync_spawn_position(spawn_pos: Vector2):
# Server tells this client where to spawn
position = spawn_pos
print("Client ", multiplayer.get_unique_id(), " received spawn position: ", spawn_pos)
@rpc("call_local") @rpc("call_local")
func lift(): func lift():

View File

@@ -73,18 +73,15 @@ properties/9/replication_mode = 2
properties/10/path = NodePath(".:collision_layer") properties/10/path = NodePath(".:collision_layer")
properties/10/spawn = true properties/10/spawn = true
properties/10/replication_mode = 2 properties/10/replication_mode = 2
properties/11/path = NodePath(".:direction_vector") properties/11/path = NodePath(".:held_entity_path")
properties/11/spawn = true properties/11/spawn = true
properties/11/replication_mode = 2 properties/11/replication_mode = 2
properties/12/path = NodePath(".:held_entity_path") properties/12/path = NodePath(".:grabbed_entity_path")
properties/12/spawn = true properties/12/spawn = true
properties/12/replication_mode = 2 properties/12/replication_mode = 2
properties/13/path = NodePath(".:grabbed_entity_path") properties/13/path = NodePath(".:current_direction")
properties/13/spawn = true properties/13/spawn = true
properties/13/replication_mode = 2 properties/13/replication_mode = 2
properties/14/path = NodePath(".:current_direction")
properties/14/spawn = true
properties/14/replication_mode = 2
[sub_resource type="Gradient" id="Gradient_hsjxb"] [sub_resource type="Gradient" id="Gradient_hsjxb"]
offsets = PackedFloat32Array(0.847255, 0.861575) offsets = PackedFloat32Array(0.847255, 0.861575)

251
src/src/main.gd Normal file
View File

@@ -0,0 +1,251 @@
extends Node2D
@export var DEBUG_MULTIPLAYER: bool = true
var player_scene = preload("res://scripts/entities/player/player.tscn")
var pot_scene = preload("res://scripts/entities/world/pot.tscn")
var has_started = false
var round_started = false
var start_round = false
var round_finished = false
func _ready() -> void:
MultiplayerManager.addPlayerSignal.connect(_addPlayer)
MultiplayerManager.delPlayerSignal.connect(_delPlayer)
MultiplayerManager.finished_hosting.connect(_finishedHosting)
MultiplayerManager.countdownFinished.connect(_finishedCountdown)
#if id == 1:
#var pot:CharacterBody2D = pot_scene.instantiate()
#pot.position = Vector2(90,80)
#$SpawnRoot.add_child(pot)
if DEBUG_MULTIPLAYER:
# Add a random delay to ensure instances start at different times
var random_delay = randf_range(0.1, 0.5)
await get_tree().create_timer(random_delay).timeout
call_deferred("_setup_debug_multiplayer")
pass
func _finishedCountdown():
round_started = true
# reset all players hp, kills and deaths
$TimerRound.start($TimerRound.wait_time)
# sync to other players!
if multiplayer.is_server():
_syncTimerToPlayer.rpc($TimerRound.time_left)
pass
func time_to_minutes_secs(time: float):
var mins = int(floor(int(time) / 60.0))
time -= mins * 60
var secs = int(time)
#var mili = int((time - int(time)) * 100)
var extraSecZero = "0" if secs < 10 else ""
var extraMinZero = "0" if mins < 10 else ""
return extraMinZero + str(mins) + ":" + extraSecZero + str(secs)
func _process(_delta: float) -> void:
if round_finished == false and round_started == false and start_round == false and multiplayer != null and multiplayer.is_server():
# make sure atleast 2 players are connected
var _players = 0
for pl: CharacterBody2D in $SpawnRoot.get_children():
if "is_player" in pl:
_players += 1
#if _players == 2:
#start_round_func.rpc()
if round_started:
$HUD/MarginContainerUpperRight/HBoxContainer/VBoxContainer/LabelTimeValue.text = time_to_minutes_secs($TimerRound.time_left)
pass
@rpc("call_local", "reliable")
func start_round_func():
if start_round == true:
return
start_round = true
MultiplayerManager.start_round()
pass
func _finishedHosting():
has_started = true
pass
func _addPlayer(id: int):
print("add player:", id)
#if id == 1:
#var pot:CharacterBody2D = pot_scene.instantiate()
#pot.position = Vector2(90,80)
#$SpawnRoot.add_child(pot, true)
var player: CharacterBody2D = player_scene.instantiate()
player.name = str(id)
#find empty 16x16 tile to spawn player
'
if get_parent().get_parent() != null and get_parent().get_parent().has_node("TileMapLayerLower"):
var tile_map = get_parent().get_parent().get_node("TileMapLayerLower")
if tile_map != null:
var player_cell = tile_map.local_to_map(self.global_position)
var cell_tile_data = tile_map.get_cell_tile_data(player_cell)
if cell_tile_data != null:
var terrainData = cell_tile_data.get_custom_data("terrain")
if terrainData != null and terrainData == 8: # 8 = stairs
terrainMultiplier = 0.5
pass
pass'
# Only server calculates spawn positions - clients receive position via sync
if multiplayer.is_server():
var best_spawn = Vector2(0, 0)
var best_distance = -1
for spawnP: Node2D in $PlayerSpawnPoints.get_children():
var pos = spawnP.position
var min_distance = INF
# find spawn position which is furthest from all players...
for pl: CharacterBody2D in $SpawnRoot.get_children():
if "is_player" in pl:
var dist = pl.position.distance_to(pos)
min_distance = min(min_distance, dist) # Keep the smallest distance
pass
# Choose the spawn with the largest minimum distance
if min_distance > best_distance:
best_distance = min_distance
best_spawn = pos
player.position = best_spawn
print("Server: Spawning player ", id, " at position: ", best_spawn)
# else: clients will receive position via MultiplayerSynchronizer after add_child
$SpawnRoot.add_child(player)
if id == multiplayer.get_unique_id():
player.initStats(MultiplayerManager.character_data) # iniitate with own stats, cuz this is us...
if multiplayer.is_server():
if !$TimerRound.is_stopped():
_syncTimerToPlayer.rpc_id(id, $TimerRound.time_left)
pass
@rpc("reliable")
func _syncTimerToPlayer(iTimeLeft: float):
round_started = true
$TimerRound.start(iTimeLeft)
pass
func _delPlayer(id: int):
if !$SpawnRoot.has_node(str(id)):
return
$SpawnRoot.get_node(str(id)).queue_free()
pass
func _on_timer_timeout() -> void:
if has_started:
var countPots = 0
for child in $SpawnRoot.get_children():
if "object_name" in child:
countPots += 1
pass
if countPots < 8:
var pot = pot_scene.instantiate()
pot.is_spawning = true
pot.positionZ = 90
pot.position = Vector2(64 + 16 * randi_range(0, 5), 64 + 16 * randi_range(0, 5))
# Set server as authority for pot synchronization
pot.set_multiplayer_authority(1)
Console.print("Pot spawned with authority: ", pot.get_multiplayer_authority())
$SpawnRoot.add_child(pot, true)
$TimerSpawnPots.wait_time = randf_range(0.2, 1.4)
$TimerSpawnPots.start() # restart timer...
pass # Replace with function body.
func _on_timer_round_timeout() -> void:
round_started = false
$TimerUntilNextRound.start($TimerUntilNextRound.wait_time)
if multiplayer.is_server():
MultiplayerManager.round_finished.rpc()
pass # Replace with function body.
func _on_timer_until_next_round_timeout() -> void:
if multiplayer.is_server():
for pl2: CharacterBody2D in $SpawnRoot.get_children():
if "is_player" in pl2:
var best_spawn = Vector2(0, 0)
var best_distance = -1
for spawnP: Node2D in $PlayerSpawnPoints.get_children():
var pos = spawnP.position
var min_distance = INF
# find spawn position which is furthest from all players...
for pl: CharacterBody2D in $SpawnRoot.get_children():
if "is_player" in pl and pl != pl2:
var dist = pl.position.distance_to(pos)
min_distance = min(min_distance, dist) # Keep the smallest distance
pass
# Choose the spawn with the largest minimum distance
if min_distance > best_distance:
best_distance = min_distance
best_spawn = pos
pl2.position = best_spawn # reset player positions...
start_round = false
MultiplayerManager.new_round_started()
if multiplayer.is_server():
start_round_func.rpc()
pass # Replace with function body.
func _setup_debug_multiplayer():
# Get the character select scene to access the selected character
var character_select = get_tree().get_first_node_in_group("character_select")
if not character_select:
# Try to find it in the scene tree
character_select = get_tree().current_scene.get_node_or_null("CanvasLayer/CharacterSelect")
if character_select and character_select.has_method("get_current_character_stats"):
# Set the character data from the character select
MultiplayerManager.character_data = character_select.get_current_character_stats()
else:
# Fallback: create a default character
MultiplayerManager.character_data = CharacterStats.new()
MultiplayerManager.character_data.character_name = "DebugPlayer"
$MainMenu._showHostButton()
# Determine if this instance should host or join
# Check for command line arguments first
var should_host = false
var args = OS.get_cmdline_args()
# Check if --host or --join argument was passed
if "--host" in args:
should_host = true
print("DEBUG: Host mode specified via command line argument")
elif "--join" in args:
should_host = false
print("DEBUG: Join mode specified via command line argument")
else:
# Fallback: use process ID for deterministic behavior
var process_id = OS.get_process_id()
should_host = process_id % 2 == 1
print("DEBUG: No command line args, using process ID: ", process_id, " Should host: ", should_host)
if should_host:
print("DEBUG: Starting as HOST")
$MainMenu._on_button_host_pressed()
else:
print("DEBUG: Starting as CLIENT")
$MainMenu._on_button_join_pressed()
func _exit_tree():
# Clean up the debug lock file when exiting
if DEBUG_MULTIPLAYER:
var lock_file_path = "user://debug_host.lock"
if FileAccess.file_exists(lock_file_path):
DirAccess.remove_absolute(lock_file_path)
print("DEBUG: Cleaned up host lock file")

1
src/src/main.gd.uid Normal file
View File

@@ -0,0 +1 @@
uid://dwumfuf4tcif1

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1 @@
uid://b5dp4ifyxo38q

View File

@@ -0,0 +1,336 @@
[gd_scene format=3 uid="uid://dgtfy455abe1t"]
[ext_resource type="Script" uid="uid://cvvy2s6620mcw" path="res://scripts/entities/player/player.gd" id="1_sgemx"]
[ext_resource type="Texture2D" uid="uid://bkninujaqqvb1" path="res://assets/gfx/Puny-Characters/Layer 0 - Skins/Human1_1.png" id="3_0818e"]
[ext_resource type="Shader" uid="uid://cfd38qf1ojmft" path="res://assets/shaders/cloth.gdshader" id="4_6nxnb"]
[ext_resource type="Script" uid="uid://yid4hjp68enj" path="res://scripts/entities/player/camera_2d.gd" id="4_n1hb6"]
[ext_resource type="Texture2D" uid="uid://dx1fovugabbwc" path="res://assets/gfx/Puny-Characters/Layer 1 - Shoes/IronBoots.png" id="5_2bw0v"]
[ext_resource type="Texture2D" uid="uid://bbqk2lcs772q3" path="res://assets/gfx/Puny-Characters/Layer 2 - Clothes/Armour Body/BronzeArmour.png" id="5_7drg4"]
[ext_resource type="Texture2D" uid="uid://bkiexfnpcaxwa" path="res://assets/gfx/Puny-Characters/Layer 4 - Hairstyle/Facial Hairstyles/Mustache1White.png" id="7_2bw0v"]
[ext_resource type="Texture2D" uid="uid://0lmhxwt7k3e4" path="res://assets/gfx/Puny-Characters/Layer 5 - Eyes/Eye Color/EyecolorLightLime.png" id="8_68eso"]
[ext_resource type="Texture2D" uid="uid://ccu5cpyo7jpdr" path="res://assets/gfx/Puny-Characters/Layer 4 - Hairstyle/Hairstyles/MHairstyle8White.png" id="8_pyh4g"]
[ext_resource type="Texture2D" uid="uid://b4vh2v0x58v2f" path="res://assets/gfx/Puny-Characters/Layer 5 - Eyes/Eyelashes/MEyelash1.png" id="9_cvm1n"]
[ext_resource type="Texture2D" uid="uid://jxo0e2x145rs" path="res://assets/gfx/Puny-Characters/Layer 7 - Add-ons/Elf Add-ons/ElfEars3.png" id="10_o8aek"]
[ext_resource type="Texture2D" uid="uid://cu5fkio3ajr5i" path="res://assets/gfx/Puny-Characters/Layer 6 - Headgears/French/MusketeerHatPurple.png" id="11_idlgo"]
[ext_resource type="Texture2D" uid="uid://bloqx3mibftjn" path="res://assets/gfx/Puny-Characters/WeaponOverlayer.png" id="12_0818e"]
[ext_resource type="AudioStream" uid="uid://cbio6f0ssxvd6" path="res://assets/audio/sfx/walk/stone/walk_stone_1.wav.mp3" id="14_0818e"]
[ext_resource type="AudioStream" uid="uid://dq1va2882v23v" path="res://assets/audio/sfx/walk/stone/walk_stone_2.wav.mp3" id="15_2bw0v"]
[ext_resource type="AudioStream" uid="uid://dsuf4oa710gi8" path="res://assets/audio/sfx/walk/stone/walk_stone_3.wav.mp3" id="16_pyh4g"]
[ext_resource type="AudioStream" uid="uid://fvhvmxtcq018" path="res://assets/audio/sfx/walk/stone/walk_stone_4.wav.mp3" id="17_jfw4q"]
[ext_resource type="AudioStream" uid="uid://cw74evef8fm0t" path="res://assets/audio/sfx/walk/stone/walk_stone_5.wav.mp3" id="18_fj670"]
[ext_resource type="AudioStream" uid="uid://c43fyqtos11fd" path="res://assets/audio/sfx/walk/stone/walk_stone_6.wav.mp3" id="19_0j5vc"]
[ext_resource type="FontFile" uid="uid://bajcvmidrnc33" path="res://assets/fonts/standard_font.png" id="21_pyh4g"]
[ext_resource type="AudioStream" uid="uid://b4ng0o2en2hkm" path="res://assets/audio/sfx/player/fall_out/player_fall_infinitely-02.wav.mp3" id="22_jfw4q"]
[ext_resource type="AudioStream" uid="uid://bi546r2d771yg" path="res://assets/audio/sfx/player/take_damage/player_damaged_01.wav.mp3" id="23_7puce"]
[ext_resource type="AudioStream" uid="uid://b8trgc0pbomud" path="res://assets/audio/sfx/player/take_damage/player_damaged_02.wav.mp3" id="24_3n1we"]
[ext_resource type="AudioStream" uid="uid://dsnvagvhs152x" path="res://assets/audio/sfx/player/take_damage/player_damaged_03.wav.mp3" id="25_h8vet"]
[ext_resource type="AudioStream" uid="uid://ce51n4tvvflro" path="res://assets/audio/sfx/player/take_damage/player_damaged_04.wav.mp3" id="26_1rlbx"]
[ext_resource type="AudioStream" uid="uid://caclaiagfnr2o" path="res://assets/audio/sfx/player/take_damage/player_damaged_05.wav.mp3" id="27_1sdav"]
[ext_resource type="AudioStream" uid="uid://dighi525ty7sl" path="res://assets/audio/sfx/player/take_damage/player_damaged_06.wav.mp3" id="28_x7koh"]
[ext_resource type="AudioStream" uid="uid://bdhmel5vyixng" path="res://assets/audio/sfx/player/take_damage/player_damaged_07.wav.mp3" id="29_jl8uc"]
[sub_resource type="Gradient" id="Gradient_n1hb6"]
offsets = PackedFloat32Array(0.742243, 0.75179)
colors = PackedColorArray(1, 1, 1, 1, 1, 1, 1, 0)
[sub_resource type="GradientTexture2D" id="GradientTexture2D_n1hb6"]
gradient = SubResource("Gradient_n1hb6")
fill = 1
fill_from = Vector2(0.508547, 0.487179)
fill_to = Vector2(0.961538, 0.034188)
[sub_resource type="SceneReplicationConfig" id="SceneReplicationConfig_fgrik"]
properties/0/path = NodePath(".:position")
properties/0/spawn = true
properties/0/replication_mode = 1
properties/1/path = NodePath(".:is_attacking")
properties/1/spawn = true
properties/1/replication_mode = 2
properties/2/path = NodePath(".:is_using")
properties/2/spawn = true
properties/2/replication_mode = 2
properties/3/path = NodePath(".:current_animation")
properties/3/spawn = true
properties/3/replication_mode = 2
properties/4/path = NodePath(".:last_direction")
properties/4/spawn = true
properties/4/replication_mode = 2
properties/5/path = NodePath(".:held_entity_path")
properties/5/spawn = true
properties/5/replication_mode = 2
properties/6/path = NodePath(".:grabbed_entity_path")
properties/6/spawn = true
properties/6/replication_mode = 2
properties/7/path = NodePath(".:current_direction")
properties/7/spawn = true
properties/7/replication_mode = 2
[sub_resource type="Gradient" id="Gradient_hsjxb"]
offsets = PackedFloat32Array(0.847255, 0.861575)
colors = PackedColorArray(0, 0, 0, 0.611765, 0, 0, 0, 0)
[sub_resource type="GradientTexture2D" id="GradientTexture2D_0818e"]
gradient = SubResource("Gradient_hsjxb")
width = 14
height = 6
fill = 1
fill_from = Vector2(0.504274, 0.478632)
fill_to = Vector2(0.897436, 0.0769231)
[sub_resource type="ShaderMaterial" id="ShaderMaterial_2bw0v"]
shader = ExtResource("4_6nxnb")
shader_parameter/original_0 = Color(0, 0, 0, 1)
shader_parameter/original_1 = Color(0, 0, 0, 1)
shader_parameter/original_2 = Color(0, 0, 0, 1)
shader_parameter/original_3 = Color(0, 0, 0, 1)
shader_parameter/original_4 = Color(0, 0, 0, 1)
shader_parameter/original_5 = Color(0, 0, 0, 1)
shader_parameter/original_6 = Color(0, 0, 0, 1)
shader_parameter/replace_0 = Color(0, 0, 0, 1)
shader_parameter/replace_1 = Color(0, 0, 0, 1)
shader_parameter/replace_2 = Color(0, 0, 0, 1)
shader_parameter/replace_3 = Color(0, 0, 0, 1)
shader_parameter/replace_4 = Color(0, 0, 0, 1)
shader_parameter/replace_5 = Color(0, 0, 0, 1)
shader_parameter/replace_6 = Color(0, 0, 0, 1)
shader_parameter/tint = Color(1, 1, 1, 1)
[sub_resource type="ShaderMaterial" id="ShaderMaterial_8ugno"]
shader = ExtResource("4_6nxnb")
shader_parameter/original_0 = Color(0, 0, 0, 1)
shader_parameter/original_1 = Color(0, 0, 0, 1)
shader_parameter/original_2 = Color(0, 0, 0, 1)
shader_parameter/original_3 = Color(0, 0, 0, 1)
shader_parameter/original_4 = Color(0, 0, 0, 1)
shader_parameter/original_5 = Color(0, 0, 0, 1)
shader_parameter/original_6 = Color(0, 0, 0, 1)
shader_parameter/replace_0 = Color(0, 0, 0, 1)
shader_parameter/replace_1 = Color(0, 0, 0, 1)
shader_parameter/replace_2 = Color(0, 0, 0, 1)
shader_parameter/replace_3 = Color(0, 0, 0, 1)
shader_parameter/replace_4 = Color(0, 0, 0, 1)
shader_parameter/replace_5 = Color(0, 0, 0, 1)
shader_parameter/replace_6 = Color(0, 0, 0, 1)
shader_parameter/tint = Color(1, 1, 1, 1)
[sub_resource type="RectangleShape2D" id="RectangleShape2D_sgemx"]
size = Vector2(8, 6)
[sub_resource type="AudioStreamRandomizer" id="AudioStreamRandomizer_40ewq"]
streams_count = 6
stream_0/stream = ExtResource("14_0818e")
stream_1/stream = ExtResource("15_2bw0v")
stream_2/stream = ExtResource("16_pyh4g")
stream_3/stream = ExtResource("17_jfw4q")
stream_4/stream = ExtResource("18_fj670")
stream_5/stream = ExtResource("19_0j5vc")
[sub_resource type="RectangleShape2D" id="RectangleShape2D_0818e"]
size = Vector2(10, 8)
[sub_resource type="Gradient" id="Gradient_2bw0v"]
offsets = PackedFloat32Array(0)
colors = PackedColorArray(0, 0, 0, 1)
[sub_resource type="GradientTexture1D" id="GradientTexture1D_pyh4g"]
gradient = SubResource("Gradient_2bw0v")
width = 16
[sub_resource type="Gradient" id="Gradient_jfw4q"]
offsets = PackedFloat32Array(1)
colors = PackedColorArray(1, 0.231947, 0.351847, 1)
[sub_resource type="GradientTexture1D" id="GradientTexture1D_fj670"]
gradient = SubResource("Gradient_jfw4q")
width = 16
[sub_resource type="AudioStreamRandomizer" id="AudioStreamRandomizer_hnhes"]
streams_count = 7
stream_0/stream = ExtResource("23_7puce")
stream_1/stream = ExtResource("24_3n1we")
stream_2/stream = ExtResource("25_h8vet")
stream_3/stream = ExtResource("26_1rlbx")
stream_4/stream = ExtResource("27_1sdav")
stream_5/stream = ExtResource("28_x7koh")
stream_6/stream = ExtResource("29_jl8uc")
[node name="Player" type="CharacterBody2D" unique_id=642482055]
collision_layer = 512
collision_mask = 704
script = ExtResource("1_sgemx")
[node name="PlayerLight" type="PointLight2D" parent="." unique_id=98233177]
z_index = 10
position = Vector2(-1, -6)
blend_mode = 2
range_layer_max = 2
texture = SubResource("GradientTexture2D_n1hb6")
[node name="PlayerSynchronizer" type="MultiplayerSynchronizer" parent="." unique_id=1561958126]
replication_config = SubResource("SceneReplicationConfig_fgrik")
[node name="Sprite2DShadow" type="Sprite2D" parent="." unique_id=1430953243]
position = Vector2(0, 2)
texture = SubResource("GradientTexture2D_0818e")
[node name="Sprite2DBody" type="Sprite2D" parent="." unique_id=36949699]
material = SubResource("ShaderMaterial_2bw0v")
position = Vector2(0, -5)
texture = ExtResource("3_0818e")
hframes = 35
vframes = 8
[node name="Sprite2DBoots" type="Sprite2D" parent="." unique_id=1502518208]
material = SubResource("ShaderMaterial_8ugno")
position = Vector2(0, -5)
texture = ExtResource("5_2bw0v")
hframes = 35
vframes = 8
[node name="Sprite2DArmour" type="Sprite2D" parent="." unique_id=1239356181]
material = SubResource("ShaderMaterial_8ugno")
position = Vector2(0, -5)
texture = ExtResource("5_7drg4")
hframes = 35
vframes = 8
[node name="Sprite2DFacialHair" type="Sprite2D" parent="." unique_id=973907314]
material = SubResource("ShaderMaterial_8ugno")
position = Vector2(0, -5)
texture = ExtResource("7_2bw0v")
hframes = 35
vframes = 8
[node name="Sprite2DHair" type="Sprite2D" parent="." unique_id=1924405266]
material = SubResource("ShaderMaterial_8ugno")
position = Vector2(0, -5)
texture = ExtResource("8_pyh4g")
hframes = 35
vframes = 8
[node name="Sprite2DEyes" type="Sprite2D" parent="." unique_id=1443066557]
material = SubResource("ShaderMaterial_8ugno")
position = Vector2(0, -5)
texture = ExtResource("8_68eso")
hframes = 35
vframes = 8
[node name="Sprite2DEyeLashes" type="Sprite2D" parent="." unique_id=691771626]
material = SubResource("ShaderMaterial_8ugno")
position = Vector2(0, -5)
texture = ExtResource("9_cvm1n")
hframes = 35
vframes = 8
[node name="Sprite2DAddons" type="Sprite2D" parent="." unique_id=647154359]
material = SubResource("ShaderMaterial_8ugno")
position = Vector2(0, -5)
texture = ExtResource("10_o8aek")
hframes = 35
vframes = 8
[node name="Sprite2DHeadgear" type="Sprite2D" parent="." unique_id=831310279]
material = SubResource("ShaderMaterial_8ugno")
position = Vector2(0, -5)
texture = ExtResource("11_idlgo")
hframes = 35
vframes = 8
[node name="Sprite2DWeapon" type="Sprite2D" parent="." unique_id=2021209530]
material = SubResource("ShaderMaterial_8ugno")
position = Vector2(0, -5)
texture = ExtResource("12_0818e")
hframes = 35
vframes = 8
[node name="CollisionShape2D" type="CollisionShape2D" parent="." unique_id=131165090]
position = Vector2(0, -1)
shape = SubResource("RectangleShape2D_sgemx")
[node name="Camera2D" type="Camera2D" parent="." unique_id=643763897]
zoom = Vector2(3, 3)
position_smoothing_enabled = true
script = ExtResource("4_n1hb6")
[node name="Timer" type="Timer" parent="Camera2D" unique_id=880082893]
[node name="SfxWalk" type="AudioStreamPlayer2D" parent="." unique_id=568890407]
stream = SubResource("AudioStreamRandomizer_40ewq")
volume_db = -12.0
attenuation = 8.28211
bus = &"Sfx"
[node name="TimerWalk" type="Timer" parent="SfxWalk" unique_id=1285633304]
wait_time = 0.3
one_shot = true
[node name="Area2DPickup" type="Area2D" parent="." unique_id=1858677050]
collision_layer = 0
collision_mask = 1536
[node name="CollisionShape2D" type="CollisionShape2D" parent="Area2DPickup" unique_id=1519370124]
position = Vector2(0, -1)
shape = SubResource("RectangleShape2D_0818e")
debug_color = Color(0.7, 0.495943, 0.135446, 0.42)
[node name="LabelPlayerName" type="Label" parent="." unique_id=900440685]
z_index = 18
z_as_relative = false
offset_left = -29.82
offset_top = -26.39
offset_right = 30.18
offset_bottom = -20.39
size_flags_horizontal = 3
size_flags_vertical = 6
theme_override_constants/outline_size = 6
theme_override_fonts/font = ExtResource("21_pyh4g")
theme_override_font_sizes/font_size = 6
text = "Playername"
horizontal_alignment = 1
[node name="LabelCurrentAnimation" type="Label" parent="." unique_id=2024783119]
visible = false
z_index = 18
z_as_relative = false
offset_left = -29.82
offset_top = -33.945
offset_right = 30.18
offset_bottom = -27.945
size_flags_horizontal = 3
size_flags_vertical = 6
theme_override_constants/outline_size = 6
theme_override_fonts/font = ExtResource("21_pyh4g")
theme_override_font_sizes/font_size = 6
text = "CurAnim"
horizontal_alignment = 1
[node name="CanvasLayer" type="CanvasLayer" parent="." unique_id=1694102436]
follow_viewport_enabled = true
[node name="TextureProgressBarHealth" type="TextureProgressBar" parent="." unique_id=1783325028]
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
offset_left = -8.0
offset_top = -16.0
offset_right = 8.0
offset_bottom = -15.0
grow_horizontal = 2
grow_vertical = 2
value = 100.0
texture_under = SubResource("GradientTexture1D_pyh4g")
texture_progress = SubResource("GradientTexture1D_fj670")
[node name="SfxDie" type="AudioStreamPlayer2D" parent="." unique_id=1749167232]
stream = ExtResource("22_jfw4q")
bus = &"Sfx"
[node name="SfxTakeDamage" type="AudioStreamPlayer2D" parent="." unique_id=956824742]
stream = SubResource("AudioStreamRandomizer_hnhes")
bus = &"Sfx"
[node name="TimerGrab" type="Timer" parent="." unique_id=129649929]
wait_time = 0.2
one_shot = true
[connection signal="timeout" from="Camera2D/Timer" to="Camera2D" method="_on_timer_timeout"]