Files
Papay-Shooter/weapons/mortar.gd
T
Nicholas ButzkeandClaude Fable 5 6c8b0ddd28 feat: cel-shaded look & feel overhaul — real audio, comic UI, themed VFX
Audio (all CC0 — Kenney packs + OpenGameArt, see assets/sounds/SOURCES.md):
- Replace every procedural synth WAV with forged sounds (ffmpeg pitch/layer
  mixes): distinct fire sounds per weapon with 2-3 variations, explosions,
  footsteps x5, land/jump/dash/vault, knife swing, hit/kill confirms,
  bullet impacts, reload, flight loops, UI hover/click/confirm/error,
  match jingles, menu music
- AudioManager.stream_for(): AudioStreamRandomizer per sound id — every
  weapon now gets variation + pitch randomization on each shot
- Explosions and bullet impacts play positional audio; landing has its own
  sound instead of a pitched footstep; ambient wind bed on every map

Visuals:
- ExplosionVFX: shared cel-shaded burst (white-hot stepped core, ink
  shockwave ring, star spikes, flat smoke puffs) replaces the orange
  sphere in both local and remote-replay paths
- Comic star muzzle flashes on all weapons; unified cel tracer bolts with
  ink outlines across hitscan/shotgun/remote paths
- Impact decals: hard-stepped ink-splat gradients instead of soft airbrush
- Toon shading on first-person view models + arms, third-person weapons,
  and the procedural humanoid fallback (no hull outlines on FBX weapons —
  their hard normals tear the inverted hull)
- Fix: giant soft "blob" highlight on floors — toon rim/specular disabled
  on level-geometry materials (pre-existing artifact since the cel commit)
- Fix: own third-person weapon rendered into the first-person camera
  (shadows-only now covers first_person_mode)

UI:
- UITheme: comic theme on the root window — Bangers display font (OFL),
  paper panels with thick ink borders + hard drop shadows, papaya accent,
  themed buttons/inputs/popups; hover/click sounds on all menu buttons
- Main menu: tilted comic wordmark, sunset toon diorama, looping menu music
- Match HUD: themed scoreboard/killfeed/kill counter

Viewports:
- 4x MSAA project-wide + viewmodel/diorama viewports (crisp ink lines)
- Viewmodel camera near plane 0.01; third-person camera FOV syncs settings
- debug/visual_capture.gd: dev tool to screenshot menu + level for review

Verified: 11/11 movement tests, spawn smoke test 0 failures, before/after
screenshot comparison of menu and level.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-07-17 18:15:42 -04:00

89 lines
2.9 KiB
GDScript

extends BaseProjectileWeapon
class_name Mortar
func _init() -> void:
weapon_name = "Mortar"
fire_rate = 1.5 # Slow
max_ammo = 1
reload_time = 3.0 # Extremely long
base_damage = 230.0 # Huge damage
min_damage = 50.0
falloff_start = 0.0
max_range = 500.0
automatic = false
spread_angle = 0.0
projectile_speed = 25.0 # Very slow
projectile_gravity = 15.0 # Heavy drop
func _build_model() -> void:
position = Vector3(0.5, -0.4, -0.8)
var model_scene = load("res://assets/weapons/mortar/source/scene.gltf")
if model_scene:
var model = model_scene.instantiate()
model_root.add_child(model)
model.scale = Vector3(0.0025, 0.0025, 0.0025)
model.rotation_degrees.y = -90
model.position.y -= 0.2
# Aggressively strip any rogue nodes from the GLTF that could ruin the scene
for node in model.find_children("*", "", true, false):
if node is Light3D or node is Camera3D or node is WorldEnvironment or node is ReflectionProbe:
if node is Node3D: node.visible = false
node.queue_free()
# Audio
fire_sound = AudioStreamPlayer3D.new()
fire_sound.bus = "SFX"
fire_sound.stream = AudioManager.stream_for("mortar_fire", "res://assets/sounds/mortar_fire.wav")
model_root.add_child(fire_sound)
reload_sound = AudioStreamPlayer3D.new()
reload_sound.bus = "SFX"
reload_sound.stream = AudioManager.stream_for("shotgun_reload", "res://assets/sounds/shotgun_reload.wav")
model_root.add_child(reload_sound)
func _spawn_custom_projectile(origin: Vector3, fire_dir: Vector3) -> void:
var proj = load("res://weapons/bouncing_projectile.gd").new()
# Mesh
var mesh_instance = MeshInstance3D.new()
var p_mesh = SphereMesh.new()
p_mesh.radius = 0.1
p_mesh.height = 0.2
var mat = StandardMaterial3D.new()
mat.albedo_color = Color(0.1, 0.1, 0.1) # Black bomb
p_mesh.material = mat
mesh_instance.mesh = p_mesh
proj.add_child(mesh_instance)
# Logic
proj.position = origin + fire_dir * 0.2
proj.logical_source = origin
proj.velocity = fire_dir * projectile_speed
if player:
proj.velocity += fire_dir * max(0.0, player.velocity.dot(fire_dir))
proj.damage = base_damage
proj.min_damage = min_damage
proj.falloff_start = falloff_start
proj.max_range = max_range
proj.drop_gravity = projectile_gravity
proj.owner_player = player
# Mortar Bouncing logic
proj.fuse_time = -1.0 # Don't start ticking until it bounces
proj.bounce_fuse_delay = 3.0 # Explodes 3 seconds after first bounce
proj.impact_detonate_time = 1.0 # If flying > 1s, explode on impact instead
proj.bounciness = 0.4 # Heavy, loses momentum on bounce
# Explosive stats
proj.explosion_radius = 10.0 # Very large AoE
proj.explosion_knockback = 60.0 # Massive knockback
proj.falloff_curve = 2.0 # Steep dropoff: "Should be an instant kill in closest 50%"
# (0-50% = dist<6. 6/12 = 0.5. 1.0 - 0.5^2 = 0.75 multiplier. 200 * 0.75 = 150 damage -> 1 shot kill)
proj.can_self_damage = true # Can self damage
proj.explosion_pitch = 0.4 # Deepest explosion
get_tree().current_scene.add_child(proj)