Chelimbalo/scripts/weapon_system/weapon_system.gd
2025-11-29 23:46:16 +05:00

202 lines
5.6 KiB
GDScript

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 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:
$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 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 _input(event: InputEvent) -> void:
if is_multiplayer_authority() == false or disabled or Session.round_state == Session.ROUND_STATES.BUY: 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()