diff --git a/HEADS b/HEADS index 949397a5..43c9889f 100644 --- a/HEADS +++ b/HEADS @@ -1 +1 @@ -{"engine": {"3.2": "ed27b7e6b973eb6be6fdac4439e99a1907b9cb58", "master": "8c73e813134001e575b6f59e3b0100471c007410"}, "world_generator": {"master": "97f10512f8832394389e1109154b8af34a2ef2c6"}, "entity_spell_system": {"master": "677f138a462b248d45b679a66d0b4cd3ed886ef8"}, "ui_extensions": {"master": "6fe4f69fea8d71043b08d959b8085404c9c4fe47"}, "voxelman": {"master": "af0c4d6586fa4dd7364280df6c4a0a768d9436da"}, "texture_packer": {"master": "b29b499adf570aa7f85af69ef080ff0d5e04afae"}, "fastnoise": {"master": "d0e3f1c759332cf0d9a5d7e0e71d0b0278310651"}, "mesh_data_resource": {"master": "4ee946963a16bbfdb4dbb5df52134d22aa168041"}, "procedural_animations": {"master": "9ae56c17230ba9c6160777650b2b89eecdc8df9e"}, "ess_data": {"master": "3bd637fdd3304b64a18287a49a6b7387acf2f5de"}, "fast_quadratic_mesh_simplifier": {"master": "f6d3d65cc6ce4dddfc68054164feec1f612ecd1f"}, "props": {"master": "b2bcb5ea6469b19298cd849c1232ddb5ad26f71c"}} \ No newline at end of file +{"engine": {"3.2": "ed27b7e6b973eb6be6fdac4439e99a1907b9cb58", "master": "8c73e813134001e575b6f59e3b0100471c007410"}, "world_generator": {"master": "97f10512f8832394389e1109154b8af34a2ef2c6"}, "entity_spell_system": {"master": "677f138a462b248d45b679a66d0b4cd3ed886ef8"}, "ui_extensions": {"master": "6fe4f69fea8d71043b08d959b8085404c9c4fe47"}, "voxelman": {"master": "233dde39defd6608913da5434d8ef2cbff3bfd42"}, "texture_packer": {"master": "b29b499adf570aa7f85af69ef080ff0d5e04afae"}, "fastnoise": {"master": "d0e3f1c759332cf0d9a5d7e0e71d0b0278310651"}, "mesh_data_resource": {"master": "4ee946963a16bbfdb4dbb5df52134d22aa168041"}, "procedural_animations": {"master": "9ae56c17230ba9c6160777650b2b89eecdc8df9e"}, "ess_data": {"master": "3bd637fdd3304b64a18287a49a6b7387acf2f5de"}, "fast_quadratic_mesh_simplifier": {"master": "f6d3d65cc6ce4dddfc68054164feec1f612ecd1f"}, "props": {"master": "b2bcb5ea6469b19298cd849c1232ddb5ad26f71c"}} \ No newline at end of file diff --git a/game/player/Body.gd b/game/player/Body.gd index 2ce81784..0a6878ba 100644 --- a/game/player/Body.gd +++ b/game/player/Body.gd @@ -23,6 +23,11 @@ extends KinematicBody + + +export(float) var max_visible_distance : float = 120 setget set_max_visible_distance +var max_visible_distance_squared : float = max_visible_distance * max_visible_distance + export(float) var MOUSE_SENSITIVITY : float = 0.05 export(String) var world_path : String = "../.." export(NodePath) var model_path : NodePath = "Rotation_Helper/Model" @@ -36,7 +41,8 @@ const JUMP_SPEED : float = 3.8 const MAX_SLOPE_ANGLE : float = 40.0 const MOUSE_TARGET_MAX_OFFSET : int = 10 -var _on : bool = false +var _on : bool = true +var _controlled : bool = false var y_rot : float = 0.0 @@ -51,6 +57,7 @@ var mouse_right_down : bool = false var touchpad_dir : Vector2 = Vector2() var mouse_down_delta : Vector2 = Vector2() var queued_camera_rotaions : Vector2 = Vector2() +var target_movement_direction : Vector2 = Vector2() var key_left : bool = false var key_right : bool = false @@ -72,6 +79,10 @@ var animation_run : bool = false var moving : bool = false var casting_anim : bool = false +var sleep : bool = false +var dead : bool = false +var death_timer : float = 0 + var last_mouse_over : Entity = null var world : VoxelWorld = null @@ -81,8 +92,8 @@ var model_rotation_node : Spatial var character_skeleton : CharacterSkeleton3D func _ready() -> void: - camera = $CameraPivot/Camera as Camera - camera_pivot = $CameraPivot as Spatial + camera = get_node_or_null("CameraPivot/Camera") as Camera + camera_pivot = get_node_or_null("CameraPivot") as Spatial model_rotation_node = get_node(model_path) character_skeleton = get_node(character_skeleton_path) @@ -91,16 +102,53 @@ func _ready() -> void: entity.connect("ccast_failed", self, "_con_cast_failed") entity.connect("ccast_finished", self, "_con_cast_finished") entity.connect("cspell_cast_success", self, "_con_spell_cast_success") + entity.connect("sdied", self, "on_sdied") + animation_tree = character_skeleton.get_animation_tree() if animation_tree != null: anim_node_state_machine = animation_tree["parameters/playback"] - + + animation_tree["parameters/run-loop/blend_position"] = Vector2(0, -1) + + func _enter_tree(): world = get_node(world_path) as VoxelWorld + set_process(true) set_physics_process(true) get_parent().connect("isc_controlled_changed", self, "on_c_controlled_changed") + +func _process(delta : float) -> void: + if entity.ai_state == EntityEnums.AI_STATE_OFF: + return + + var camera : Camera = get_tree().get_root().get_camera() as Camera + + if camera == null: + return + + var cam_pos : Vector3 = camera.global_transform.xform(Vector3()) + var dstv : Vector3 = cam_pos - translation + dstv.y = 0 + var dst : float = dstv.length_squared() + + if dst > max_visible_distance_squared: + if visible: + hide() + return + else: +# var lod_level : int = int(dst / max_visible_distance_squared * 3.0) + + if dst < 400: #20^2 + entity.get_character_skeleton().set_lod_level(0) + elif dst > 400 and dst < 900: #20^2, 30^2 + entity.get_character_skeleton().set_lod_level(1) + else: + entity.get_character_skeleton().set_lod_level(2) + + if not visible: + show() func _physics_process(delta : float) -> void: @@ -109,9 +157,22 @@ func _physics_process(delta : float) -> void: if world.initial_generation: return - - process_input(delta) - process_movement(delta) + + if entity.sentity_data == null: + return + + if dead: + return + + if entity.ai_state == EntityEnums.AI_STATE_OFF: + process_input(delta) + process_movement_player(delta) + else: + if world != null: + if not world.is_position_walkable(transform.origin): + return + + process_movement_mob(delta) func process_input(delta: float) -> void: var key_dir : Vector2 = Vector2() @@ -161,7 +222,7 @@ func process_input(delta: float) -> void: rotate_delta(camera_pivot.get_y_rot()) camera_pivot.set_y_rot(0.0) -func process_movement(delta : float) -> void: +func process_movement_player(delta : float) -> void: var state : int = entity.getc_state() if state & EntityEnums.ENTITY_STATE_TYPE_FLAG_ROOT != 0 or state & EntityEnums.ENTITY_STATE_TYPE_FLAG_STUN != 0: @@ -209,6 +270,89 @@ func process_movement(delta : float) -> void: rpc_id(1, "sset_position", translation, rotation) else: sset_position(translation, rotation) + + +func process_movement_mob(delta : float) -> void: + if entity.starget != null: + look_at(entity.starget.get_body().translation, Vector3(0, 1, 0)) + + var state : int = entity.getc_state() + + if state & EntityEnums.ENTITY_STATE_TYPE_FLAG_ROOT != 0 or state & EntityEnums.ENTITY_STATE_TYPE_FLAG_STUN != 0: + moving = false + return + + if target_movement_direction.length_squared() > 0.1: + if anim_node_state_machine != null and not animation_run: + anim_node_state_machine.travel("run-loop") + animation_run = true + + target_movement_direction = target_movement_direction.normalized() + moving = true + else: + if anim_node_state_machine != null and animation_run: + anim_node_state_machine.travel("idle-loop") + animation_run = false + + moving = false + + if target_movement_direction.x > 0.1 or target_movement_direction.y > 0.1 or target_movement_direction.x < -0.1 or target_movement_direction.y < -0.1: + y_rot = Vector2(0, 1).angle_to(target_movement_direction) + + var forward : Vector3 = Vector3(0, 0, 1).rotated(Vector3(0, 1, 0), deg2rad(y_rot)) + var right : Vector3 = forward.cross(Vector3(0, 1, 0)) * -target_movement_direction.x + forward *= target_movement_direction.y #only potentially make it zero after getting the right vector + + dir = forward + dir += right + + if dir.length_squared() > 0.1: + dir = dir.normalized() + + moving = true + else: + dir = Vector3() + moving = false + + if not moving and sleep: + return + + if moving and sleep: + sleep = false + + vel.y += delta * GRAVITY + + var hvel : Vector3 = vel + hvel.y = 0 + + var target : Vector3 = dir + target *= entity.get_speed().ccurrent + + var accel + if dir.dot(hvel) > 0: + accel = ACCEL + else: + accel = DEACCEL + + hvel = hvel.linear_interpolate(target, accel * delta) as Vector3 + vel.x = hvel.x + vel.z = hvel.z + + var facing : Vector3 = vel + facing.y = 0 + + vel = move_and_slide(vel, Vector3(0,1,0), false, 4, deg2rad(MAX_SLOPE_ANGLE)) + sset_position(translation, rotation) + + if vel.length_squared() < 0.12: + sleep = true + + if translation.y < -50.0: + print("killed mob with fall damage") + var sdi : SpellDamageInfo = SpellDamageInfo.new() + sdi.damage_source_type = SpellDamageInfo.DAMAGE_SOURCE_UNKNOWN + sdi.damage = 999999999 + entity.stake_damage(sdi) func _input(event: InputEvent) -> void: @@ -319,6 +463,7 @@ func rotate_delta(x_delta : float) -> void: rotation_degrees = Vector3(0.0, y_rot, 0.0) + func target(position : Vector2): var from = camera.project_ray_origin(position) var to = from + camera.project_ray_normal(position) * ray_length @@ -379,21 +524,16 @@ func queue_camera_rotation(rot : Vector2) -> void: queued_camera_rotaions += rot remote func sset_position(position : Vector3, rotation : Vector3) -> void: - if get_network_master() != 1: - print(str(get_network_master()) + "psset") - if multiplayer.network_peer and multiplayer.is_network_server(): entity.vrpc("cset_position", position, rotation) - cset_position(position, rotation) + + if _controlled: + cset_position(position, rotation) remote func cset_position(position : Vector3, rotation : Vector3) -> void: - if get_network_master() != 1: - print(str(get_network_master()) + " pcset") translation = position rotation = rotation - -#func _setup(): -# setup_actionbars() + func _con_cast_started(info): if anim_node_state_machine != null and not casting_anim: @@ -428,7 +568,29 @@ func _con_spell_cast_success(info): func on_c_controlled_changed(val): #create camera and pivot if true - _on = val + _controlled = val - set_physics_process(val) +# set_physics_process(val) + set_process_input(val) + set_process_unhandled_input(val) +func on_sdied(entity): + if dead: + return + + dead = true + + anim_node_state_machine.travel("dead") + + set_physics_process(false) + +remote func set_position(position : Vector3, rotation : Vector3) -> void: + if get_tree().is_network_server(): + rpc("set_position", position, rotation) + + +func set_max_visible_distance(var value : float) -> void: + max_visible_distance_squared = value * value + + max_visible_distance = value + diff --git a/game/player/Mob.gd b/game/player/Mob.gd index da47822b..a6cff4b3 100644 --- a/game/player/Mob.gd +++ b/game/player/Mob.gd @@ -23,53 +23,15 @@ extends Entity # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. -#export (String) var map_path : String -export(float) var max_visible_distance : float = 120 setget set_max_visible_distance -var max_visible_distance_squared : float = max_visible_distance * max_visible_distance - -const ray_length = 1000 -const ACCEL : float = 100.0 -const DEACCEL : float = 100.0 -const GRAVITY : float = -24.8 -const JUMP_SPEED : float = 3.8 -const MAX_SLOPE_ANGLE : float = 40.0 - -var _on : bool = true - -var y_rot : float = 0.0 - -var vel : Vector3 = Vector3() -var dir : Vector3 = Vector3() -var target_movement_direction : Vector2 = Vector2() - -var animation_tree : AnimationTree -var anim_node_state_machine : AnimationNodeStateMachinePlayback = null -var animation_run : bool = false - -var moving : bool = false -var sleep : bool = false var dead : bool = false var death_timer : float = 0 -var _world : VoxelWorld = null - func _ready() -> void: - animation_tree = get_character_skeleton().get_animation_tree() - - if animation_tree != null: - anim_node_state_machine = animation_tree["parameters/playback"] - - animation_tree["parameters/run-loop/blend_position"] = Vector2(0, -1) - ai_state = EntityEnums.AI_STATE_PATROL func _enter_tree(): - _world = get_node("..") as VoxelWorld - set_process(true) - set_physics_process(true) - func _process(delta : float) -> void: if dead: death_timer += delta @@ -78,142 +40,6 @@ func _process(delta : float) -> void: queue_free() return - - - var camera : Camera = get_tree().get_root().get_camera() as Camera - - if camera == null: - return - - var cam_pos : Vector3 = camera.global_transform.xform(Vector3()) - var dstv : Vector3 = cam_pos - get_body().translation - dstv.y = 0 - var dst : float = dstv.length_squared() - - if dst > max_visible_distance_squared: - if get_body().visible: - get_body().hide() - return - else: -# var lod_level : int = int(dst / max_visible_distance_squared * 3.0) - - if dst < 400: #20^2 - get_character_skeleton().set_lod_level(0) - elif dst > 400 and dst < 900: #20^2, 30^2 - get_character_skeleton().set_lod_level(1) - else: - get_character_skeleton().set_lod_level(2) - - if not get_body().visible: - get_body().show() - -func _physics_process(delta : float) -> void: - if not _on: - return - - if sentity_data == null: - return - - if dead: - return - - if _world != null: - if not _world.is_position_walkable(get_body().transform.origin): - return - - process_movement(delta) - -func process_movement(delta : float) -> void: - if starget != null: - get_body().look_at(starget.get_body().translation, Vector3(0, 1, 0)) - - var state : int = getc_state() - - if state & EntityEnums.ENTITY_STATE_TYPE_FLAG_ROOT != 0 or state & EntityEnums.ENTITY_STATE_TYPE_FLAG_STUN != 0: - moving = false - return - - if target_movement_direction.length_squared() > 0.1: - if anim_node_state_machine != null and not animation_run: - anim_node_state_machine.travel("run-loop") - animation_run = true - - target_movement_direction = target_movement_direction.normalized() - moving = true - else: - if anim_node_state_machine != null and animation_run: - anim_node_state_machine.travel("idle-loop") - animation_run = false - - moving = false - - if target_movement_direction.x > 0.1 or target_movement_direction.y > 0.1 or target_movement_direction.x < -0.1 or target_movement_direction.y < -0.1: - y_rot = Vector2(0, 1).angle_to(target_movement_direction) - - var forward : Vector3 = Vector3(0, 0, 1).rotated(Vector3(0, 1, 0), deg2rad(y_rot)) - var right : Vector3 = forward.cross(Vector3(0, 1, 0)) * -target_movement_direction.x - forward *= target_movement_direction.y #only potentially make it zero after getting the right vector - - dir = forward - dir += right - - if dir.length_squared() > 0.1: - dir = dir.normalized() - - moving = true - else: - dir = Vector3() - moving = false - - if not moving and sleep: - return - - if moving and sleep: - sleep = false - - vel.y += delta * GRAVITY - - var hvel : Vector3 = vel - hvel.y = 0 - - var target : Vector3 = dir - target *= get_speed().ccurrent - - var accel - if dir.dot(hvel) > 0: - accel = ACCEL - else: - accel = DEACCEL - - hvel = hvel.linear_interpolate(target, accel * delta) as Vector3 - vel.x = hvel.x - vel.z = hvel.z - - var facing : Vector3 = vel - facing.y = 0 - - vel = get_body().move_and_slide(vel, Vector3(0,1,0), false, 4, deg2rad(MAX_SLOPE_ANGLE)) - sset_position(get_body().translation, get_body().rotation) - - if vel.length_squared() < 0.12: - sleep = true - - if get_body().translation.y < -50.0: - print("killed mob with fall damage") - var sdi : SpellDamageInfo = SpellDamageInfo.new() - sdi.damage_source_type = SpellDamageInfo.DAMAGE_SOURCE_UNKNOWN - sdi.damage = 999999999 - stake_damage(sdi) - -func rotate_delta(x_delta : float) -> void: - y_rot += x_delta - - if y_rot > 360: - y_rot = 0 - if y_rot < 0: - y_rot = 360 - - get_body().rotation_degrees = Vector3(0.0, y_rot, 0.0) func sstart_attack(entity : Entity) -> void: ai_state = EntityEnums.AI_STATE_ATTACK @@ -259,15 +85,10 @@ func _son_death(): sentity_interaction_type = EntityEnums.ENITIY_INTERACTION_TYPE_LOOT ai_state = EntityEnums.AI_STATE_OFF + - anim_node_state_machine.travel("dead") - -# set_process(false) - set_physics_process(false) - -remote func set_position(position : Vector3, rotation : Vector3) -> void: - if get_tree().is_network_server(): - rpc("set_position", position, rotation) +func set_position(position : Vector3, rotation : Vector3) -> void: + get_body().set_position(position, rotation) func _son_damage_dealt(data): if ai_state != EntityEnums.AI_STATE_ATTACK and data.dealer != self: @@ -279,19 +100,7 @@ func _con_damage_dealt(info : SpellDamageInfo) -> void: func _con_heal_dealt(info : SpellHealInfo) -> void: WorldNumbers.heal(get_body().translation, 1.6, info.heal, info.crit) - -func _moved() -> void: - if sis_casting(): - sfail_cast() -func set_max_visible_distance(var value : float) -> void: - max_visible_distance_squared = value * value - - max_visible_distance = value - -#func _setup(): -# sentity_name = sentity_data.text_name - func _son_xp_gained(value : int) -> void: if not ESS.get_resource_db().get_xp_data().can_character_level_up(gets_character_level()): return @@ -347,12 +156,3 @@ func refresh_spells(value: int): break -func sset_position(position : Vector3, rotation : Vector3) -> void: - if multiplayer.network_peer and multiplayer.is_network_server(): -# cset_position(position, rotation) - vrpc("cset_position", position, rotation) - -remote func cset_position(position : Vector3, rotation : Vector3) -> void: - get_body().translation = position - get_body().rotation = rotation - diff --git a/game/player/Mob.tscn b/game/player/Mob.tscn index a1094a3c..15fe749a 100644 --- a/game/player/Mob.tscn +++ b/game/player/Mob.tscn @@ -1,8 +1,9 @@ -[gd_scene load_steps=6 format=2] +[gd_scene load_steps=7 format=2] [ext_resource path="res://data/models/armature_model_orig_v2.tscn" type="PackedScene" id=1] [ext_resource path="res://player/Mob.gd" type="Script" id=2] [ext_resource path="res://ui/nameplates/NamePlate.tscn" type="PackedScene" id=3] +[ext_resource path="res://player/Body.gd" type="Script" id=4] [sub_resource type="CapsuleShape" id=1] radius = 0.266582 @@ -17,12 +18,12 @@ extents = Vector3( 0.216228, 0.0681041, 0.183397 ) body_path = NodePath("Body") character_skeleton_path = NodePath("Body/Rotation_Helper/Model/character") script = ExtResource( 2 ) -max_visible_distance = 100.0 [node name="NamePlate" parent="." instance=ExtResource( 3 )] max_distance = 50.0 [node name="Body" type="KinematicBody" parent="."] +script = ExtResource( 4 ) [node name="Body_CollisionShape" type="CollisionShape" parent="Body"] transform = Transform( 1, 0, 0, 0, -1.62921e-07, -1, 0, 1, -1.62921e-07, 0, 0.73, 0 ) @@ -38,3 +39,5 @@ transform = Transform( -1, 0, -3.25841e-07, 0, 1, 0, 3.25841e-07, 0, -1, 0, 0, 0 [node name="Model" type="Spatial" parent="Body/Rotation_Helper"] [node name="character" parent="Body/Rotation_Helper/Model" instance=ExtResource( 1 )] +refresh_in_editor = false +use_lod = true diff --git a/game/player/NetworkedPlayer.gd b/game/player/NetworkedPlayer.gd index c23f982c..b7b455a4 100644 --- a/game/player/NetworkedPlayer.gd +++ b/game/player/NetworkedPlayer.gd @@ -24,46 +24,3 @@ class_name NetworkedPlayerGD # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. -const ray_length = 1000 -const ACCEL : float = 100.0 -const DEACCEL : float = 100.0 -const GRAVITY : float = -24.8 -const JUMP_SPEED : float = 3.8 -const MAX_SLOPE_ANGLE : float = 40.0 -const MOUSE_TARGET_MAX_OFFSET : int = 10 - -var y_rot : float = 0.0 - -var animation_tree : AnimationTree -var anim_node_state_machine : AnimationNodeStateMachinePlayback = null - -func _ready() -> void: - animation_tree = get_character_skeleton().get_animation_tree() - - if animation_tree != null: - anim_node_state_machine = animation_tree["parameters/playback"] - - -func rotate_delta(x_delta : float) -> void: - y_rot += x_delta - - if y_rot > 360: - y_rot = 0 - if y_rot < 0: - y_rot = 360 - - get_body().rotation_degrees = Vector3(0.0, y_rot, 0.0) - -remote func sset_position(position : Vector3, rotation : Vector3) -> void: - if multiplayer.network_peer and multiplayer.is_network_server(): - cset_position(position, rotation) - vrpc("cset_position", position, rotation) - -remote func cset_position(position : Vector3, rotation : Vector3) -> void: - get_body().translation = position - get_body().rotation = rotation - -func _moved() -> void: - if sis_casting(): - sfail_cast() - diff --git a/game/player/NetworkedPlayer.tscn b/game/player/NetworkedPlayer.tscn index 8926dfbc..7326561d 100644 --- a/game/player/NetworkedPlayer.tscn +++ b/game/player/NetworkedPlayer.tscn @@ -1,8 +1,9 @@ -[gd_scene load_steps=6 format=2] +[gd_scene load_steps=7 format=2] [ext_resource path="res://player/NetworkedPlayer.gd" type="Script" id=1] [ext_resource path="res://data/models/armature_model_orig_v2.tscn" type="PackedScene" id=2] [ext_resource path="res://ui/nameplates/NamePlate.tscn" type="PackedScene" id=3] +[ext_resource path="res://player/Body.gd" type="Script" id=4] [sub_resource type="CapsuleShape" id=1] radius = 0.266582 @@ -17,6 +18,7 @@ character_skeleton_path = NodePath("Body/Rotation_Helper/Model/character") script = ExtResource( 1 ) [node name="Body" type="KinematicBody" parent="."] +script = ExtResource( 4 ) [node name="Body_CollisionShape" type="CollisionShape" parent="Body"] transform = Transform( 1, 0, 0, 0, -1.62921e-07, -1, 0, 1, -1.62921e-07, 0, 0.8, 0 ) diff --git a/game/scripts/ai/EntityAIGD.gd b/game/scripts/ai/EntityAIGD.gd index 96b6882b..3befd4bd 100644 --- a/game/scripts/ai/EntityAIGD.gd +++ b/game/scripts/ai/EntityAIGD.gd @@ -76,7 +76,7 @@ func attack(delta): if target == null: owner.ai_state = EntityEnums.AI_STATE_REGENERATE - owner.target_movement_direction = Vector2() + owner.get_body().target_movement_direction = Vector2() return var cast : bool = false @@ -116,16 +116,16 @@ func attack(delta): break if owner.sis_casting(): - owner.target_movement_direction = Vector2() + owner.get_body().target_movement_direction = Vector2() return - owner.target_movement_direction = Vector2() + owner.get_body().target_movement_direction = Vector2() var dir : Vector3 = target.get_body().translation - owner.get_body().translation var l = dir.length() if l > 2.5: - owner.target_movement_direction = Vector2(dir.x, dir.z) + owner.get_body().target_movement_direction = Vector2(dir.x, dir.z) func sort_spells_by_rank(a, b): if a == null or b == null: diff --git a/game/ui/loot_window/LootWindow.gd b/game/ui/loot_window/LootWindow.gd index af4217c2..e73d98d5 100644 --- a/game/ui/loot_window/LootWindow.gd +++ b/game/ui/loot_window/LootWindow.gd @@ -62,8 +62,9 @@ func on_visibility_changed(): if visible: refresh() else: - target_bag.disconnect("item_removed", self, "on_item_removed") - target_bag = null + if target_bag != null: + target_bag.disconnect("item_removed", self, "on_item_removed") + target_bag = null func on_item_removed(bag: Bag, item: ItemInstance, slot_id: int) -> void: refresh()