extends Node class_name WeaponSystem @export var animation_player: AnimationPlayer @export var camera: PlayerCamera @export var player: Player var current_state: WeaponSubStateMachine var last_slot: StringName 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: $WeaponSpawner.spawn_function = pick_up_weapon 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 @rpc("call_local","reliable") func add(state: WeaponSubStateMachine, slot: StringName,ignore_parent: bool = false) -> void: if can_add(slot) == false: return if ignore_parent == false: if state.get_parent() == null: add_child(state, true) if state.get_parent() != self: state.get_parent().remove_child(state) add_child(state,true) state.ready.emit() slots[slot] = state state.system = self state.animation_player = animation_player state.player_camera = camera state.player = player state.request_return.connect(return_to_previous) state.ammo_depleted.connect(check_for_empty) state.ammo_updated.connect(on_ammo_updated) 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 switch(to: StringName, exit: bool = true): if slots.has(to) == false or slots[to] == null or slots[to] == current_state or 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) update_remotes.rpc(to,exit) func return_to_previous(exit: bool = true): if last_slot != "": switch(last_slot, exit) else: switch("knife", exit) @rpc("authority","call_remote","reliable") func update_remotes(to: StringName,exit: bool): if current_state != null and exit: current_state.exit() current_state = slots[to] current_state.enter() switched_to.emit(current_state) func drop(): if slots.find_key(current_state) == "knife": return var drop_data: Dictionary = {} drop_data.scene = current_state.droppable drop_data.ammo = current_state.ammo drop_data.remaining_ammo = current_state.remaining_ammo drop_data.slot = current_state.slot drop_data.position = camera.global_position drop_data.impulse = -camera.global_basis.z * 10 + player.velocity Session.spawn(drop_data) $"../PickupRange".start_temp_ignore() slots[slots.find_key(current_state)] = null slots_updated.emit(slots) current_state.queue_free() return_to_previous(false) # Spawn function # Data should be a dictionary with these keys: # ammo # remaining_ammo # scene_file_path func pick_up_weapon(data: Variant) -> Node: if data.has("scene_file_path") == false: return Node.new() if data.has_all(["ammo","remaining_ammo"]): var scene: WeaponSubStateMachine = load(data["scene_file_path"]).instantiate() scene.ammo = data["ammo"] scene.remaining_ammo = data["remaining_ammo"] scene.slot = data["slot"] scene.set_multiplayer_authority(get_multiplayer_authority()) add(scene,scene.slot,true) return scene else: var scene: WeaponSubStateMachine = load(data["scene_file_path"]).instantiate() scene.set_multiplayer_authority(get_multiplayer_authority()) add(scene,scene.slot,true) return scene 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: ammo_updated.emit(current_state.ammo,current_state.remaining_ammo) func _process(delta: float) -> void: if current_state == null: return current_state.update(delta) func _physics_process(delta: float) -> void: if current_state == null: return current_state.physics_update(delta) func _input(event: InputEvent) -> void: if is_multiplayer_authority() == false: return if current_state != null: current_state.state_input(event) if event.is_action_pressed("plr_ult"): switch("ultimate") elif event.is_action_pressed("plr_bomb"): switch("bomb") elif event.is_action_pressed("plr_primary"): switch("primary") elif event.is_action_pressed("plr_active_first"): switch("ability_first") elif event.is_action_pressed("plr_active_second"): switch("ability_second") elif event.is_action_pressed("plr_active_third"): switch("ability_third") elif event.is_action_pressed("plr_secondary"): switch("secondary") elif event.is_action_pressed("plr_knife"): switch("knife") if event.is_action_pressed("plr_fire"): current_state.use_begin.rpc() if event.is_action_released("plr_fire"): current_state.use_end.rpc() if event.is_action_pressed("plr_scope"): current_state.alternate_state() if event.is_action_pressed("plr_firemode"): current_state.switch_mode() if event.is_action_pressed("plr_drop"): drop()