extends Node class_name WeaponSystem @export var animation_player: AnimationPlayer @export var camera: PlayerCamera @export var player: Player @export var player_input: PlayerInput var current_state: WeaponSubStateMachine var last_slot: StringName var disabled: bool var slots: Dictionary[StringName,WeaponSubStateMachine] = { "primary": null, "secondary": null, "knife": null, "bomb": null, "ability_first": null, "ability_second": null, "ability_third": null, "ultimate": null } signal switched_to(state: WeaponSubStateMachine) signal slots_updated(current_slot: StringName,slots: Dictionary[StringName,StringName]) signal ammo_updated(ammo: int, remaining_ammo: int) func _ready() -> void: if not multiplayer.is_server(): return player_input.drop.connect(drop_current) player_input.fire_begin.connect(use_begin) player_input.fire_end.connect(use_end) player_input.switch_weapon.connect(switch) player_input.alternate_state.connect(alternate_state) player_input.switch_firemode.connect(switch_mode) await get_tree().process_frame await get_tree().process_frame notify_slots_updated() on_ammo_updated() func get_speed_modifier() -> float: if current_state == null: return 1 return current_state.speed_modifier func can_add(slot: StringName) -> bool: return slots.has(slot) and slots[slot] == null func add(state: WeaponSubStateMachine, slot: StringName) -> void: if not multiplayer.is_server(): return if can_add(slot) == false: return add_child(state, true) slots[slot] = state notify_slots_updated() if current_state == null: current_state = state ammo_updated.emit(current_state.ammo,current_state.remaining_ammo) #Replace with way to ensure all players loaded await get_tree().process_frame await get_tree().process_frame state._enter() func get_empty_ability_slot() -> StringName: if slots["ability_first"] == null: return "ability_first" elif slots["ability_second"] == null: return "ability_second" elif slots["ability_third"] == null: return "ability_third" return "ability_first" func can_add_ability(ability: StringName, slot: StringName) -> bool: for ability_slot in ["ability_first","ability_second","ability_third"]: if slots[ability_slot] != null and slots[ability_slot].weapon_gid == ability: return false return can_add(slot) func switch(to: StringName, exit: bool = true): if slots.has(to) == false or slots[to] == null or slots[to] == current_state or not is_multiplayer_authority(): return if current_state != null: if exit: current_state._exit() if current_state.can_be_previous: var found = slots.find_key(current_state) last_slot = found if found else "" current_state = slots[to] current_state._enter() ammo_updated.emit(current_state.ammo,current_state.remaining_ammo) switched_to.emit(current_state) notify_slots_updated() func return_to_previous(exit: bool = true): if last_slot != "": switch(last_slot, exit) else: switch("knife", exit) func drop_current(): drop(current_state) func drop(weapon: WeaponSubStateMachine) -> void: if not is_multiplayer_authority(): return if slots.find_key(weapon) in ["knife","ability_first","ability_second","ability_third"]: return var dropped_weapon: DroppableWeapon = Registry.weapons[weapon.weapon_gid].dropped_scene.instantiate() dropped_weapon.weapon.ammo = weapon.ammo dropped_weapon.weapon.remaining_ammo = weapon.remaining_ammo dropped_weapon.weapon.slot = weapon.slot Session.dynamic_objects_parent.add_child(dropped_weapon,true) dropped_weapon.global_position = camera.global_position dropped_weapon.apply_central_impulse(-camera.global_basis.z * 10 + player.velocity) $"../PickupRange".start_temp_ignore() slots[slots.find_key(weapon)] = null notify_slots_updated() return_to_previous(false) weapon.queue_free() func drop_slot(slot: StringName): if slots.has(slot) == false or slots[slot] == null: return drop(slots[slot]) func drop_death(): if slots["primary"] != null: drop_slot("primary") elif slots["secondary"] != null: drop_slot("secondary") drop_slot("bomb") func check_for_empty() -> void: if is_multiplayer_authority() == false: return for child in get_children(): if child is WeaponSubStateMachine and child.ammo == 0 and child.remaining_ammo == 0 and child.destroy_when_empty: if child == current_state: return_to_previous(false) child.queue_free() notify_slots_updated() func on_ammo_updated() -> void: if is_multiplayer_authority() == false: return if current_state != null: ammo_updated.emit(current_state.ammo,current_state.remaining_ammo) remote_ammo_update.rpc(current_state.ammo,current_state.remaining_ammo) @rpc func remote_ammo_update(ammo: int, remaining_ammo: int): ammo_updated.emit(ammo,remaining_ammo) func notify_slots_updated(): if not is_multiplayer_authority(): return var display_slots: Dictionary[StringName,StringName] = {} for key in slots.keys(): if slots[key] == null: display_slots[key] = "" else: display_slots[key] = slots[key].weapon_gid var current_slot: StringName = "" var found = slots.find_key(current_state) if found: current_slot = found remote_update_slots.rpc(current_slot,display_slots) slots_updated.emit(current_slot,display_slots) @rpc func remote_update_slots(current_slot: StringName, update_slots: Dictionary[StringName,StringName]): slots_updated.emit(current_slot, update_slots) func disable() -> void: disabled = true func _process(delta: float) -> void: if not multiplayer.is_server(): return if current_state == null or disabled: return current_state.update(delta) func _physics_process(delta: float) -> void: if not multiplayer.is_server(): return if current_state == null or disabled: return current_state.physics_update(delta) func use_begin() -> void: if not multiplayer.is_server() or Session.round_state == Session.ROUND_STATES.BUY or disabled: return if current_state != null: current_state.use_begin() func use_end() -> void: if not multiplayer.is_server() or Session.round_state == Session.ROUND_STATES.BUY or disabled: return if current_state != null: current_state.use_end() func alternate_state() -> void: if not multiplayer.is_server() or Session.round_state == Session.ROUND_STATES.BUY or disabled: return if current_state != null: current_state.alternate_state() func switch_mode() -> void: if not multiplayer.is_server() or Session.round_state == Session.ROUND_STATES.BUY or disabled: return if current_state != null: current_state.switch_mode()