363 lines
13 KiB
GDScript
363 lines
13 KiB
GDScript
extends Node3D
|
|
class_name weapon
|
|
|
|
@export var weapon_info : weapon_resource
|
|
@export var anim_player : AnimationPlayer
|
|
@export var anim_rot_body : Node3D
|
|
@export var barrel_ray : RayCast3D
|
|
@export var casing_ejector : RayCast3D
|
|
@export var mag_ejector : RayCast3D
|
|
@export var audio_fire : AudioStreamPlayer3D
|
|
@export var audio_empty : AudioStreamPlayer3D
|
|
@export var audio_reload : AudioStreamPlayer3D
|
|
@export_group("Barrel Smoke")
|
|
@export var fire_smoke : GPUParticles3D
|
|
@export var smoke_timer : Timer
|
|
@export_group("Revolver")
|
|
@export var casing_array : Array[MeshInstance3D]
|
|
@export var bullet_array : Array[MeshInstance3D]
|
|
@export var chamber : Node
|
|
@export_group("Melee")
|
|
@export var melee_collision_shape : Node
|
|
@export_group("Tracker Gun")
|
|
@export var looking_mesh : Node
|
|
|
|
@onready var player = get_tree().current_scene.player
|
|
|
|
#calculate spawn angular and linear velocity
|
|
var spawn_av_lv = []
|
|
|
|
# Revolver vars
|
|
var revolver_chamber_rot_amt = 0
|
|
var casings_chamber_last
|
|
|
|
# Tracker vars
|
|
var tracker
|
|
var check_track
|
|
const TRACKER_ASSIGNED_COLOR: Color = Color(0, 0.853, 0, 1)
|
|
const TRACKER_NULL_COLOR :Color = Color(0.743, 0.359, 0, 1)
|
|
|
|
var remaining_ammo
|
|
var start_position
|
|
var start_rotation
|
|
var cycle_count_start
|
|
var cycle_count
|
|
|
|
# Called when the node enters the scene tree for the first time.
|
|
func _ready():
|
|
|
|
if melee_collision_shape != null:
|
|
melee_collision_shape.disabled = true
|
|
|
|
if weapon_info.weapon_type != 1:
|
|
casings_chamber_last = weapon_info.max_ammo
|
|
|
|
match weapon_info.fire_mode:
|
|
0:
|
|
cycle_count_start = 1
|
|
1:
|
|
cycle_count_start = 1
|
|
2:
|
|
cycle_count_start = 3
|
|
|
|
cycle_count = cycle_count_start
|
|
|
|
ready_revolver_casings()
|
|
|
|
# Called every frame. 'delta' is the elapsed time since the previous frame.
|
|
func _process(_delta):
|
|
if chamber != null:
|
|
var rot_amount = revolver_chamber_rot_amt * _delta * 10
|
|
chamber.rotate_object_local(Vector3(0,-1,0),deg_to_rad(rot_amount))
|
|
revolver_chamber_rot_amt -= rot_amount
|
|
|
|
if Input.is_action_just_released("shoot"):
|
|
cycle_count = cycle_count_start
|
|
|
|
if weapon_info.weapon_type == 2:
|
|
if tracker != null:
|
|
weapon_info.tracker_asset.tracker_indicator_material.emission = TRACKER_ASSIGNED_COLOR
|
|
if looking_mesh != null:
|
|
looking_mesh.look_at(tracker.global_position)
|
|
else:
|
|
weapon_info.tracker_asset.tracker_indicator_material.emission = TRACKER_NULL_COLOR
|
|
looking_mesh.rotation = lerp(rotation, Vector3(0,0,0), _delta * 4)
|
|
if check_track:
|
|
tracker_checker(_delta)
|
|
|
|
func reload_finished():
|
|
match weapon_info.reload_type:
|
|
0: #MAGAZINE
|
|
#calculate ammo to add from reserve --- discards ammo in previous mag
|
|
var ammo_added = clamp(weapon_info.max_ammo,1,GameGlobals.ammo_reserve[str(weapon_info.bullet.ammo_type)])
|
|
#add to gun and remove from reserve
|
|
GameGlobals.gun_ammo[weapon_info.gun_name] += ammo_added
|
|
GameGlobals.ammo_reserve[str(weapon_info.bullet.ammo_type)] -= ammo_added
|
|
1: #REVOLVER
|
|
#calculate ammo to add from reserve --- only pulls from what it is missing
|
|
var ammo_needed = weapon_info.max_ammo - GameGlobals.gun_ammo[weapon_info.gun_name]
|
|
var ammo_added = clamp(ammo_needed,1,GameGlobals.ammo_reserve[str(weapon_info.bullet.ammo_type)])
|
|
#add to gun and remove from reserve
|
|
GameGlobals.gun_ammo[weapon_info.gun_name] += ammo_added
|
|
GameGlobals.ammo_reserve[str(weapon_info.bullet.ammo_type)] -= ammo_added
|
|
#make the added-back casings visible
|
|
var index = 0
|
|
while index <= (ammo_added - 1):
|
|
if index < bullet_array.size():
|
|
bullet_array[index].visible = true
|
|
if index < casing_array.size():
|
|
casing_array[index].visible = true
|
|
index += 1
|
|
|
|
|
|
func shoot():
|
|
if weapon_info.weapon_type == 0:
|
|
if GameGlobals.gun_ammo[weapon_info.gun_name] > 0 and cycle_count > 0:
|
|
if !anim_player.is_playing():
|
|
GameGlobals.gun_ammo[weapon_info.gun_name] -= 1
|
|
if weapon_info.fire_mode != 0:
|
|
cycle_count -= 1
|
|
#audio and anims
|
|
anim_player.play("shoot")
|
|
|
|
elif !anim_player.is_playing() and cycle_count != 0:
|
|
anim_player.play("empty")
|
|
audio_empty.play()
|
|
|
|
elif weapon_info.weapon_type == 1:
|
|
if !anim_player.is_playing():
|
|
#audio and anims
|
|
anim_player.play("shoot")
|
|
vibration()
|
|
player.recoil.add_recoil(Vector3(0,weapon_info.recoil_amount.y,weapon_info.recoil_amount.z),10,10)
|
|
player.recoil.add_gun_recoil(weapon_info.recoil_amount.x)
|
|
|
|
elif weapon_info.weapon_type == 2:
|
|
if !anim_player.is_playing():
|
|
if tracker == null and Input.is_action_just_pressed("shoot"):
|
|
check_track = true
|
|
weapon_info.tracker_check_mesh.visible = true
|
|
weapon_info.tracker_check_mesh.anim_player.play("check")
|
|
if tracker != null and !check_track:
|
|
anim_player.play("shoot")
|
|
|
|
func reload():
|
|
SignalBus.emit_signal("player_reloading")
|
|
match weapon_info.weapon_type:
|
|
0:
|
|
match weapon_info.reload_type:
|
|
0:
|
|
if GameGlobals.gun_ammo[weapon_info.gun_name] < weapon_info.max_ammo and anim_player.get_current_animation() != "reload" and GameGlobals.ammo_reserve[str(weapon_info.bullet.ammo_type)] > 0:
|
|
anim_player.play("reload")
|
|
audio_reload.play()
|
|
if anim_player.is_playing() and anim_player.current_animation == "reload":
|
|
if GameGlobals.gun_ammo[weapon_info.gun_name] == 0:
|
|
GameGlobals.gun_ammo[weapon_info.gun_name] = 0
|
|
else:
|
|
GameGlobals.gun_ammo[weapon_info.gun_name] = 1
|
|
1:
|
|
if GameGlobals.gun_ammo[weapon_info.gun_name] < weapon_info.max_ammo and anim_player.get_current_animation() != "reload" and GameGlobals.ammo_reserve[str(weapon_info.bullet.ammo_type)] > 0:
|
|
anim_player.play("reload")
|
|
audio_reload.play()
|
|
|
|
func spawn_mag():
|
|
var instance_mag = weapon_info.mag.instantiate()
|
|
var anim_velocity = solve_anim_av_lv()
|
|
|
|
instance_mag.position = mag_ejector.global_position
|
|
instance_mag.transform.basis = mag_ejector.global_transform.basis
|
|
instance_mag.linear_velocity += global_transform.basis * (anim_velocity["lv"] * 5) + player.velocity
|
|
instance_mag.angular_velocity += global_transform.basis * anim_velocity["av"]
|
|
|
|
get_tree().get_root().add_child(instance_mag)
|
|
|
|
func spawn_casing():
|
|
if weapon_info.casing != null and casing_ejector != null:
|
|
# Casing transform
|
|
var instance_casing = weapon_info.casing.instantiate()
|
|
|
|
var casing_random_velocity = random_rotation(true)
|
|
|
|
instance_casing.position = casing_ejector.global_position
|
|
instance_casing.transform.basis = casing_ejector.transform.basis
|
|
instance_casing.linear_velocity += global_transform.basis * casing_random_velocity["lv"] + player.velocity
|
|
instance_casing.angular_velocity += global_transform.basis * casing_random_velocity["av"]
|
|
get_tree().get_root().add_child(instance_casing)
|
|
|
|
func ready_revolver_casings():
|
|
if casing_array != []:
|
|
#hide all casings
|
|
for i in casing_array:
|
|
i.visible = false
|
|
#add back ones in gun
|
|
for i in range(GameGlobals.gun_ammo[weapon_info.gun_name]):
|
|
casing_array[i].visible = true
|
|
|
|
func spawn_revolver_casings():
|
|
if casing_array.size() > 0:
|
|
var ammo_needed = weapon_info.max_ammo - GameGlobals.gun_ammo[weapon_info.gun_name]
|
|
var index = 0
|
|
while index <= ammo_needed - 1:
|
|
if index < bullet_array.size():
|
|
bullet_array[index].visible = false
|
|
if index < casing_array.size():
|
|
casing_array[index].visible = false
|
|
|
|
var instance_casing = weapon_info.casing.instantiate()
|
|
var random_velocity = random_rotation(true)
|
|
var anim_velocity = solve_anim_av_lv()
|
|
instance_casing.position = casing_array[index].global_position
|
|
instance_casing.transform.basis = casing_array[index].global_transform.basis
|
|
instance_casing.rotation.x += deg_to_rad(90) # casings were initially rotated with the assumption that they would spawn horizontally, realigning for revolvers
|
|
instance_casing.linear_velocity += transform.basis * (player.velocity + anim_velocity["lv"] + Vector3(0,random_velocity["lv"].y,0))
|
|
instance_casing.angular_velocity += transform.basis * anim_velocity["av"]
|
|
get_tree().get_root().add_child(instance_casing)
|
|
|
|
index += 1
|
|
|
|
func fire_tracker():
|
|
var instance_tracker = weapon_info.tracker_asset.instantiate()
|
|
get_tree().current_scene.add_child(instance_tracker)
|
|
if player.bullet_ray.is_colliding():
|
|
var spawn_loc = player.bullet_ray.get_collision_point()
|
|
var spawn_parent = player.bullet_ray.get_collider()
|
|
if spawn_parent != null:
|
|
spawn_parent.add_child(instance_tracker)
|
|
instance_tracker.global_transform.origin = spawn_loc
|
|
instance_tracker.anim_player.play("mark")
|
|
tracker = instance_tracker
|
|
|
|
func tracker_checker(_delta):
|
|
if player.bullet_ray.is_colliding():
|
|
var tracker_check_mesh = weapon_info.tracker_asset.instantiate()
|
|
var spawn_loc = player.bullet_ray.get_collision_point()
|
|
var distance_to_point = self.global_position.distance_to(spawn_loc)
|
|
var scale_adjusted = distance_to_point/5
|
|
tracker_check_mesh.global_transform.origin = spawn_loc
|
|
tracker_check_mesh.global_rotation = Vector3(0,0,0)
|
|
tracker_check_mesh.scale = Vector3(scale_adjusted,scale_adjusted,scale_adjusted)
|
|
if check_track == true and Input.is_action_just_released("shoot"):
|
|
fire_tracker()
|
|
check_track = false
|
|
|
|
func shotgun_pellet_spawn():
|
|
SignalBus.emit_signal("shot_fired",weapon_info.crosshair_jump_amount)
|
|
audio_fire.play()
|
|
spawn_casing()
|
|
var pellets_remaining = weapon_info.pellets_per_shot
|
|
|
|
while pellets_remaining > 0:
|
|
var lv_x = randf_range(-weapon_info.shotgun_spread.x,weapon_info.shotgun_spread.x)
|
|
var lv_y = randf_range(-weapon_info.shotgun_spread.y,weapon_info.shotgun_spread.y)
|
|
# instance bullet
|
|
var instance_bullet = projectile_initialize()
|
|
instance_bullet.linear_velocity += instance_bullet.transform.basis * Vector3(lv_x, lv_y, -weapon_info.bullet_speed) + player.velocity
|
|
get_tree().get_root().add_child(instance_bullet)
|
|
pellets_remaining -= 1
|
|
|
|
vibration()
|
|
if fire_smoke != null:
|
|
fire_smoke.restart()
|
|
fire_smoke.emitting = true
|
|
smoke_timer.start()
|
|
player.recoil.add_recoil(Vector3(0,weapon_info.recoil_amount.y,weapon_info.recoil_amount.z),10,10)
|
|
player.recoil.add_gun_recoil(weapon_info.recoil_amount.x)
|
|
player.velocity += player.bullet_ray.global_basis * Vector3(0,0, weapon_info.kick_amount)
|
|
|
|
func spawn_muzzle_smoke():
|
|
var instance_smoke = weapon_info.muzzle_smoke.instantiate()
|
|
instance_smoke.global_transform.basis = barrel_ray.global_transform.basis
|
|
|
|
add_child(instance_smoke)
|
|
|
|
func projectile_initialize():
|
|
var instance_bullet = weapon_info.bullet.asset.instantiate()
|
|
instance_bullet.position = player.bullet_ray.global_position
|
|
#shoot bullet from real gun if gun is folded up
|
|
if !player.gun_ray.is_colliding():
|
|
instance_bullet.transform.basis = player.bullet_ray.global_transform.basis
|
|
else:
|
|
instance_bullet.transform.basis = barrel_ray.global_transform.basis
|
|
instance_bullet.bullet_damage = weapon_info.bullet_damage
|
|
instance_bullet.blast_power = weapon_info.blast_power
|
|
instance_bullet.bullet_force_mod = weapon_info.bullet_force_mod
|
|
if weapon_info.bullet.bullet_hole != null:
|
|
instance_bullet.instance_bullethole = weapon_info.bullet.bullet_hole.instantiate()
|
|
instance_bullet.player_position = player.global_position
|
|
instance_bullet.linear_velocity += instance_bullet.transform.basis * Vector3(0, 0, -weapon_info.bullet_speed) + player.velocity
|
|
return instance_bullet
|
|
|
|
func bullet_fire():
|
|
SignalBus.emit_signal("shot_fired",weapon_info.crosshair_jump_amount)
|
|
audio_fire.play()
|
|
var bullet_spawn = projectile_initialize()
|
|
get_tree().current_scene.add_child(bullet_spawn)
|
|
|
|
spawn_casing()
|
|
vibration()
|
|
|
|
if chamber != null:
|
|
revolver_chamber_rot_amt += weapon_info.chamber_rot_amount
|
|
if weapon_info.smoke_enabled:
|
|
spawn_muzzle_smoke()
|
|
|
|
player.recoil.add_recoil(Vector3(0,weapon_info.recoil_amount.y,weapon_info.recoil_amount.z),10,10)
|
|
player.recoil.add_gun_recoil(weapon_info.recoil_amount.x)
|
|
|
|
|
|
func random_rotation(random_rotation):
|
|
if random_rotation:
|
|
var lv_x = randf_range(5.0,7.0)
|
|
var lv_y = randf_range(0.0,3.0)
|
|
var lv_z = randf_range(0.0,2.0)
|
|
var av_x = randf_range(-50.0,50.0)
|
|
var av_y = randf_range(-50.0,50.0)
|
|
var av_z = randf_range(-50.0,50.0)
|
|
return {"av" : Vector3(av_x,av_y,av_z),"lv" : Vector3(lv_x,lv_y,lv_z)}
|
|
else:
|
|
return {"av" : Vector3.ZERO,"lv" : Vector3.ZERO}
|
|
|
|
func mark_anim_rot():
|
|
if anim_rot_body != null:
|
|
if spawn_av_lv.size() < 2:
|
|
var time = anim_player.current_animation_position
|
|
var rot = anim_rot_body.rotation
|
|
var pos = anim_rot_body.position
|
|
spawn_av_lv.append({"time" : time,"rot" : rot,"pos" : pos})
|
|
|
|
func solve_anim_av_lv():
|
|
if spawn_av_lv.size() >= 2:
|
|
var start = spawn_av_lv[0]
|
|
var end = spawn_av_lv[1]
|
|
|
|
var calculated_av = (end["rot"] - start["rot"]) / (end["time"] - start["time"])
|
|
var calculated_lv = (end["pos"] - start["pos"]) / (end["time"] - start["time"])
|
|
|
|
return {"av" : calculated_av,"lv" : calculated_lv}
|
|
else:
|
|
return {"av" : Vector3.ZERO,"lv" : Vector3.ZERO}
|
|
|
|
func can_fire():
|
|
if anim_player.is_playing() and anim_player.current_animation == "reload":
|
|
return false
|
|
elif weapon_info.weapon_type == 0 and GameGlobals.gun_ammo[weapon_info.gun_name] <= 0:
|
|
return false
|
|
else:
|
|
return true
|
|
|
|
func hitscan_fire():
|
|
# Fire hitscan
|
|
pass
|
|
|
|
func swapped_out():
|
|
queue_free()
|
|
|
|
func melee_collider_enable():
|
|
melee_collision_shape.disabled = false
|
|
|
|
func melee_collider_disable():
|
|
melee_collision_shape.disabled = true
|
|
|
|
func vibration():
|
|
Input.start_joy_vibration(0,weapon_info.vibration_weak_magnitude,weapon_info.vibration_strong_magnitude,weapon_info.vibration_duration)
|