This repository has been archived on 2022-01-09. You can view files and clone it, but cannot push or open issues/pull-requests.
liblast/Game/Assets/Weapons/Weapon.gd

228 lines
8.6 KiB
GDScript

extends Node3D
#Hand Camera Head Player
@onready var main = get_tree().root.get_node("Main")
@onready var hud = main.get_node("HUD")
@onready var score_rank = hud.get_node("ScoreRank")
@onready var player = get_parent().get_parent().get_parent().get_parent()
@onready var camera = get_parent().get_parent()
@onready var ejector = find_node("Ejector")
@onready var muzzle = find_node("Muzzle")
@onready var animation_player = find_node("AnimationPlayer")
@export var animation_speed : float
var casing = preload("res://Assets/Weapons/Handgun/Casing.tscn")
var flash = preload("res://Assets/Effects/MuzzleFlash.tscn")
var tracer = preload("res://Assets/Effects/BulletTracer.tscn")
var impact_bullet = preload("res://Assets/Effects/ImpactSparks.tscn")
var impact_explosion = preload("res://Assets/Effects/ImpactExplosion.tscn")
var flyby_sound = preload("res://Assets/Audio/BulletFlyBySoundPlayer.tscn")
enum WeaponType {HITSCAN, PROJECTILE, MELEE}
@export var weapon_type : WeaponType
@export var projectile_or_tracer_scene : PackedScene
@export var weapon_damage : int
# accuracy
var spread_min = 1
var spread_max = 64
var spread_lerp = 0.01
var spread_boost = 16
var spread = spread_min
# Declare member variables here. Examples:
# var a = 2
# var b = "text"
#enum Trigger {TRIGGER_PRIMARY, TRIGGER_SECONDARY}
@rpc(any_peer, call_local, reliable) func shoot(spread_offset:=Vector3.ZERO):
$"SFX/Shoot A".play()
$"SFX/Shoot B".play()
$"SFX/Shoot C".play()
var flash_effect = flash.instantiate()
get_parent().add_child(flash_effect)
flash_effect.global_transform = muzzle.global_transform
animation_player.play("Shoot", 0, animation_speed)
var space_state = get_world_3d().direct_space_state
var from = camera.get_global_transform().origin
var aim = - camera.get_global_transform().basis[2]
var to = from + (aim * 1000) + spread_offset
var physics_ray_query_parameters_3d = PhysicsRayQueryParameters3D.new()
physics_ray_query_parameters_3d.from = from
physics_ray_query_parameters_3d.to = to
physics_ray_query_parameters_3d.exclude = [player]
var ray = space_state.intersect_ray(physics_ray_query_parameters_3d)
if weapon_type == WeaponType.HITSCAN:
var tracer_instance = projectile_or_tracer_scene.instantiate()
get_tree().root.add_child(tracer_instance)
tracer_instance.global_transform = muzzle.global_transform.looking_at(to)
var casing_instance = casing.instantiate()
get_tree().root.add_child(casing_instance)
casing_instance.global_transform = ejector.global_transform#approximating delta
casing_instance.linear_velocity = ejector.global_transform.basis[1] * randf_range(3.2, 4.5) + (player.motion_velocity / 2)
casing_instance.angular_velocity.y += randf_range(-10, 10)
casing_instance.angular_velocity.x += randf_range(-10, 10)
if ray:
if is_multiplayer_authority(): # only do this on the attacker's local instance of the game
give_damage(ray['collider'], ray['position'], ray['normal'], 20, self.global_transform.origin, Globals.DamageType.BULLET, 1.0)
### bullet flyby sounds
if ray: # if we hit something - use that to evaluate the flyby sound
to = ray['position']
var flyby_camera = get_tree().get_root().get_camera_3d()
if flyby_camera == camera: # don't spawn flyby sound for the shooter
return
var x := Vector3.ZERO
var A = from
var B = to
var C = flyby_camera.global_transform.origin
var d0 = (B - A).dot(A - C)
var d1 = (B - A).dot(B - C)
if d0 < 0 and d1 < 0:
print("Firing away from the camera")
elif d0 > 0 and d1 > 0:
print("Bullet hit before passing by")
else:
var X = d0/(d0-d1)
var flyby = flyby_sound.instantiate()
get_tree().root.add_child(flyby)
flyby.global_transform.origin = A + X * (B - A)
#print("===")
#print(X)
#print("===")
#flyby.global_transform.origin = A + x * (B - A)
# TODO - spawn
elif weapon_type == WeaponType.PROJECTILE:
var projectile_instance = projectile_or_tracer_scene.instantiate()
projectile_instance.global_transform = muzzle.global_transform.looking_at(to)
projectile_instance.source_position = player.global_transform.origin
projectile_instance.player = player
projectile_instance.damage = weapon_damage
#projectile_instance.get_node("RayCast3D").add_exception(player)
#projectile_instance.rotate_x(PI/2)
get_tree().root.add_child(projectile_instance)
return # skip the rest - it's deprecated code
####################### DEPRACATED ↓↓↓↓↓↓↓↓
#
# var impact_vfx
#
# if ray: # did we hit anything?
# if ray['collider'].has_method(&'receive_damage') && is_multiplayer_authority():
# ray['collider'].rpc(&'damage', 20, get_multiplayer_authority(), global_transform.origin) # apply damage
#
# return
#
# if ray['collider'].has_method(&'damage'):
# if is_multiplayer_authority(): #get_tree().multiplayer.get_multiplayer_unique_id() == 1: # make sure this can only run on the server
# #print("SHOT HIT ", ray['collider'])
# ray['collider'].rpc(&'damage', 20) # apply damage
# if main.player_list.get(ray['collider'].get_multiplayer_authority()).health <= 0: # if he ded
# ray['collider'].rpc(&'die', self.get_multiplayer_authority())
#
# main.player_list.players[player.get_multiplayer_authority()].score += 1 # give the killer a point
# main.rpc(&'player_list_update', main.player_list.get(player.get_multiplayer_authority()).serialize(), player.get_multiplayer_authority())
# hud.get_node("Crosshair").kill()
# main.check_game_win_condition()
#
# # check for firstblood
# if main.player_list.players[player.get_multiplayer_authority()].score == 1:
# var firstblood = true
# for i in main.player_list.players.keys():
# if i != player.get_multiplayer_authority() and main.player_list.players[i].score > 0:
# firstblood = false
# if firstblood:
# main.get_node("Announcer").speak(main.get_node("Announcer").firstblood)
#
# # check for revenge (payback) - don't play if this is a duel, it'd be silly
# if main.player_list.players.size() > 2 and ray['collider'].get_multiplayer_authority() == player.revenge_pid:
# main.get_node("Announcer").speak(main.get_node("Announcer").payback)
# player.revenge_pid = -1 # reset revenge
# else:
# hud.get_node("Crosshair").hit()
# ray['collider'].rpc(&'moan')
#
# # boardcast the new health value to all peers
# main.rpc(&'player_list_update', main.player_list.get(ray['collider'].get_multiplayer_authority()).serialize(), ray['collider'].get_multiplayer_authority())
# main.update_hud()
#
## impact_vfx = impact_player.instantiate()
# else:
## impact_vfx = impact_wall.instantiate()
# pass
#
## if impact_vfx != null:
## impact_vfx.global_transform = impact_vfx.global_transform.looking_at(ray['normal'])
## impact_vfx.global_transform.origin = ray['position']
## get_tree().root.add_child(impact_vfx)
##
# #print(ray)
####################### DEPRACATED ↑↑↑↑↑↑↑↑
func give_damage(target: Node, hit_position: Vector3, hit_normal: Vector3, damage: int, source_position: Vector3, type: Globals.DamageType, push: float):
if target.has_method(&'take_damage'): # we've hit a player or something else - the ywill handle everything like effects etc.
target.rpc(&'take_damage', get_multiplayer_authority(), hit_position, hit_normal, damage, source_position, type, push)
else:
# TODO take data from the material of the target and spawn an appropriate hit effect
var impact_vfx : Node = impact_bullet.instantiate()
get_tree().root.add_child(impact_vfx)
impact_vfx.global_transform.origin = hit_position
#print(impact_vfx.global_transform)
var result = impact_vfx.look_at(hit_position + hit_normal)
if not result: # if the look_at failed (as it will on floors and ceilings) try another approach:
impact_vfx.look_at(hit_position + hit_normal, Vector3.LEFT)
impact_vfx.rotate(hit_normal, randf_range(0, PI * 2))
#print(impact_vfx.global_transform)
func trigger(index: int, active: bool) -> void:
#print("Weapon " + str(name) + ", Trigger " + str(index) + ", active: " + str(active))
if index == 0 and active and animation_player.is_playing() == false:
spread = min(spread + spread_boost, spread_max)
var spread_offset = Vector3.ZERO
spread_offset.x = randf_range(-1,1)
spread_offset.y = randf_range(-1,1)
spread_offset.z = randf_range(-1,1)
spread_offset = spread_offset.normalized() * randf_range(spread_min, spread)
rpc(&'shoot', spread_offset)
# Called when the node enters the scene tree for the first time.
func _ready():
# align the sound source with the head to produce balanced stereo
pass #$SFX/Shoot.global_transform = camera.global_transform