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(slots: Dictionary[StringName,WeaponSubStateMachine]) signal ammo_updated(ammo: int, remaining_ammo: int) func _ready() -> void: 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) 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 slots_updated.emit(slots) if current_state == null: current_state = state ammo_updated.emit(current_state.ammo,current_state.remaining_ammo) state.enter.call_deferred() func process_spawned_weapon(weapon_node: Node): var weapon = weapon_node as WeaponSubStateMachine slots[weapon.slot] = weapon slots_updated.emit(slots) if current_state == null: current_state = weapon ammo_updated.emit(current_state.ammo,current_state.remaining_ammo) 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" @rpc("authority","call_remote","reliable") func switch(to: StringName, exit: bool = true): if slots.has(to) == false or slots[to] == null or slots[to] == current_state or (multiplayer.get_remote_sender_id() != 1 and is_multiplayer_authority() == false): return if current_state != null and exit: current_state.exit() if current_state.can_be_previous: last_slot = slots.find_key(current_state) else: last_slot = "" current_state = slots[to] current_state.enter() ammo_updated.emit(current_state.ammo,current_state.remaining_ammo) switched_to.emit(current_state) if is_multiplayer_authority(): switch.rpc(to,exit) 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) == "knife": return var dropped_weapon: DroppableWeapon = Registry.weapons[weapon.registry_entry].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) 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 slots_updated.emit(slots) weapon.queue_free() return_to_previous(false) func drop_slot(slot: StringName): if slots.has(slot) == false or slots[slot] == null: return drop(slots[slot]) 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: child.queue_free() func on_ammo_updated() -> void: if current_state != null: ammo_updated.emit(current_state.ammo,current_state.remaining_ammo) func disable() -> void: disabled = true func _process(delta: float) -> void: if current_state == null or disabled: return current_state.update(delta) func _physics_process(delta: float) -> void: if current_state == null or disabled: return current_state.physics_update(delta) func use_begin() -> void: current_state.use_begin.rpc() func use_end() -> void: current_state.use_end.rpc() func alternate_state() -> void: current_state.alternate_state() func switch_mode() -> void: current_state.switch_mode()