extends Node3D const WEAPON_SCENE = preload("res://entities/Weapon.scn") @onready var player_root = get_node("../../..") @onready var raycast = get_node("../Camera3D/AimCast") as RayCast3D #@onready var crosshair = $Crosshair var ALL_WEAPONS = [] var weapons = [] var current_weapon_index = 0 var current_weapon = null var mouse_mov : Vector3 var sway_lerp = 5 @onready var game = get_node("/root/Game") as Game func _ready(): Init_Config(game.weapon_config) if not player_root.is_local_authority(): for w_name in game.init_config.get_value("PLAYER", "starting_weapons"): GiveWeapon(w_name) func set_weapons(): for w_name in game.init_config.get_value("PLAYER", "starting_weapons"): rpc("GiveWeapon",w_name) @rpc(call_local, any_peer) func GiveWeapon(weapon_name): for i in ALL_WEAPONS.size(): if(ALL_WEAPONS[i].name != weapon_name): continue if(weapons.has(i)): return weapons.append(i) if(current_weapon == null): rpc("ChangeWeapon", ((posmod(current_weapon_index, weapons.size())))) return @rpc(call_local, any_peer) func TakeWeapon(weapon_name): for i in ALL_WEAPONS.size(): if(ALL_WEAPONS[i].name != weapon_name): continue weapons.erase(i) if(current_weapon == ALL_WEAPONS[i]): rpc("ChangeWeapon", ((posmod(current_weapon_index, weapons.size())))) func _input(event): if not player_root.is_local_authority(): return if event is InputEventMouseMotion: mouse_mov.y = clampf(-event.relative.x, -0.1, 0.1) mouse_mov.x = clampf(event.relative.y, -0.1, 0.1) if event is InputEventKey and event.is_pressed(): if event.keycode == KEY_T: rpc("GiveWeapon","CHAINSAW") func _unhandled_input(_event): if not player_root.is_local_authority(): return if(weapons.size() == 0): return if weapons.size() > 1 && Input.is_action_just_released("wheel_up"): rpc("ChangeWeapon", (posmod((current_weapon_index + 1),weapons.size()))) if weapons.size() > 1 && Input.is_action_just_released("wheel_down"): rpc("ChangeWeapon", (posmod((current_weapon_index - 1),weapons.size()))) if Input.is_action_just_pressed("reload"): current_weapon.Reload() @rpc(call_local, any_peer) func ChangeWeapon(i): if(current_weapon): current_weapon.hide() if(weapons.size() == 0): current_weapon = null return current_weapon_index = i var w_index = weapons[current_weapon_index] current_weapon = ALL_WEAPONS[w_index] current_weapon.show() current_weapon.init() raycast.target_position.z = -current_weapon.RAY_LEN var time = 0 func _process(delta): if not player_root.is_local_authority(): return if(current_weapon == null): return if Input.is_action_pressed("shoot") && current_weapon.Shoot(): if(current_weapon.HITSCAN): HitScan() else: Projectile() if Input.is_action_just_released("shoot"): current_weapon.Release() #SWAY if mouse_mov != null && mouse_mov.length() > 0: current_weapon.MODEL.rotation = current_weapon.MODEL.rotation.lerp(mouse_mov, sway_lerp * delta) mouse_mov = Vector3.ZERO else: current_weapon.MODEL.rotation = current_weapon.MODEL.rotation.lerp(Vector3.ZERO, sway_lerp * delta) #BOB if player_root.velocity.length() > 0: time += delta var bobOscillate = sin(time * 4 * (2 * PI)) * 0.01 position.y = bobOscillate bobOscillate = sin(time * 4 * (PI) + PI/4) * 0.015 position.x = bobOscillate @rpc(call_local, any_peer) func HitScan(): if(raycast.is_colliding()): var target = raycast.get_collider() print_debug("Hit target ", target.name, " with ", current_weapon.name, " ",current_weapon_index, ". Dealt damage ", current_weapon.DAMAGE) if(raycast.get_collision_mask_value(10)): if(target is Hitable): target.Hit(current_weapon.DAMAGE) func Projectile(): pass func Init_Config(config): for weapon in config.get_sections(): var root = WEAPON_SCENE.instantiate() root.name = weapon var model_path = config.get_value(weapon, "MODEL") as String var weapon_model if(model_path.ends_with(".glb") or model_path.ends_with(".gltf")): weapon_model = Runtimeloader.load_gltf(model_path, root) as Node3D elif(model_path.ends_with(".tscn") or model_path.ends_with(".scn")): weapon_model = Runtimeloader.loadScene(model_path, root) else: printerr("Invalid file extension for "+ model_path) continue root.position = config.get_value(weapon, "HAND_POS") root.rotation = config.get_value(weapon, "HAND_ROT") root.hide() add_child(root) #Set Weapon Data root.MELEE = config.get_value(weapon, "MELEE") root.MAX_CLIP = config.get_value(weapon, "MAX_CLIP") root.clip = root.MAX_CLIP root.DAMAGE = config.get_value(weapon, "DAMAGE") root.RPM = config.get_value(weapon, "RPM") root.FIREMODE = config.get_value(weapon, "FIREMODE") root.HITSCAN = config.get_value(weapon, "HITSCAN") if(not root.HITSCAN): print("Projectile stats") else: root.RAY_LEN = config.get_value(weapon, "RAY_LEN") #Set Anim Data root.MODEL = weapon_model root.DRAW_POS = config.get_value(weapon, "DRAW_POS") root.DRAW_ROT = config.get_value(weapon, "DRAW_ROT") root.MOMENTUM = config.get_value(weapon, "MOMENTUM") root.ANGULAR_MOMENTUM = config.get_value(weapon, "ANGULAR_MOMENTUM") root.RECOIL_COOLDOWN = config.get_value(weapon, "RECOIL_COOLDOWN") root.RELOAD_MOMENTUM = config.get_value(weapon, "RELOAD_MOMENTUM") root.RELOAD_ANGULAR_MOMENTUM = config.get_value(weapon, "RELOAD_ANGULAR_MOMENTUM") root.RELOAD_TIME = config.get_value(weapon, "RELOAD_TIME") ALL_WEAPONS.append(root)