feat: add plasma gun weapon implementation and new pause menu system with loadout management

This commit is contained in:
DottsGit
2026-06-04 17:06:50 -04:00
parent 67bd5b4302
commit 1ccc66a601
37 changed files with 1070 additions and 0 deletions
+126
View File
@@ -0,0 +1,126 @@
extends Node3D
class_name BaseProjectileWeapon
@export var weapon_name: String = "Base Projectile"
@export var fire_rate: float = 0.1
@export var max_ammo: int = 30
@export var reload_time: float = 1.5
@export var base_damage: float = 10.0
@export var min_damage: float = 5.0
@export var falloff_start: float = 10.0
@export var max_range: float = 200.0
@export var automatic: bool = true
@export var spread_angle: float = 0.01
@export var projectile_speed: float = 50.0
@export var projectile_gravity: float = 0.0
var current_ammo: int = 30
var reloading: bool = false
var reload_timer: float = 0.0
var fire_cooldown: float = 0.0
var is_firing: bool = false
var player: CharacterBody3D
var camera: Camera3D
var muzzle_flash: OmniLight3D
var fire_sound: AudioStreamPlayer3D
var reload_sound: AudioStreamPlayer3D
var model_root: Node3D
func _ready() -> void:
current_ammo = max_ammo
set_process_input(true)
set_process(true)
model_root = Node3D.new()
add_child(model_root)
_build_model()
func _build_model() -> void:
pass
func _process(delta: float) -> void:
if fire_cooldown > 0.0:
fire_cooldown -= delta
if reloading:
reload_timer -= delta
var spin_speed = (PI * 2.0) / reload_time
model_root.rotation.x += spin_speed * delta
if reload_timer <= 0.0:
current_ammo = max_ammo
reloading = false
model_root.rotation.x = 0.0
print(weapon_name, " Reloaded!")
elif automatic and is_firing and fire_cooldown <= 0.0 and current_ammo > 0:
_fire()
func _input(event: InputEvent) -> void:
if Input.get_mouse_mode() != Input.MOUSE_MODE_CAPTURED:
return
if event.is_action_pressed("fire"):
is_firing = true
if not automatic and fire_cooldown <= 0.0 and current_ammo > 0 and not reloading:
_fire()
elif current_ammo == 0 and not reloading:
_start_reload()
elif event.is_action_released("fire"):
is_firing = false
if event.is_action_pressed("reload"):
if current_ammo < max_ammo and not reloading:
_start_reload()
func _start_reload() -> void:
reloading = true
reload_timer = reload_time
is_firing = false
if reload_sound:
reload_sound.play()
func _fire() -> void:
if current_ammo <= 0 or reloading:
return
current_ammo -= 1
fire_cooldown = fire_rate
_shoot_projectile()
_play_muzzle_flash()
if fire_sound:
fire_sound.pitch_scale = 1.0 + randf_range(-0.05, 0.05)
fire_sound.play()
if current_ammo == 0:
_start_reload()
func _play_muzzle_flash() -> void:
if muzzle_flash:
muzzle_flash.light_energy = 8.0
var tween = create_tween()
tween.tween_property(muzzle_flash, "light_energy", 0.0, 0.05)
func _shoot_projectile() -> void:
if not camera: return
var origin = camera.global_position
var forward = -camera.global_transform.basis.z.normalized()
var right = camera.global_transform.basis.x.normalized()
var up = camera.global_transform.basis.y.normalized()
# Calculate spread
var r = sqrt(randf()) * spread_angle
var theta = randf() * PI * 2.0
var offset_dir = (right * cos(theta) + up * sin(theta)) * r
var fire_dir = (forward + offset_dir).normalized()
_spawn_custom_projectile(origin, fire_dir)
func _spawn_custom_projectile(origin: Vector3, fire_dir: Vector3) -> void:
# Overridden by specific weapons to instance their unique visual projectile
pass