feat: real per-weapon reload/recoil choreography + knife slash, fully matte hair
Weapons no longer reload by spinning the gun 360 (that was the upside-down
flip; nothing detached). New ViewmodelAnim module drives per-style manual-of-
arms sequences on the existing model_root + named arm pivots, with a temporary
magazine/shell/rocket/cell prop that visibly leaves and returns to the gun:
- mag (M4/AK/MP7/DMR): roll gun to present the well, hand rips the mag
down and away, fresh mag up, seat, charge. Gun stays UPRIGHT.
- boltmag (AWP): mag swap + a distinct bolt-cycle rock.
- break (double barrel): hinge open, flick both shells out, drop fresh
shells in, snap shut.
- tube (rocket launcher): tip the tube in, shove a rocket home, shoulder.
- cell (plasma/nail gun): glowing energy cell swapped on the side.
Per-shot viewmodel recoil kick (ViewmodelAnim.apply_kick) scaled by each
weapon's recoil_amplitude, so an AWP slams and an MP7 chatters — replaces the
old flat model behaviour. Weapons expose reload_style; base classes call
play_reload / stop (on unequip) / apply_kick.
Knife: the old barely-visible flick is now a real diagonal slash that
alternates backhand/forehand, whips the blade through screen centre, and
fires the third-person melee arm-swing action (synced to other players).
Hair/materials: specular fully to 0 (even a 2% stepped glint swept as shine
across Taila's hair when the camera moved); rim trimmed to a whisper. Fully
matte cloth/hair now.
Verify: debug/fp_weapon_capture.gd screenshots each weapon's reload phases,
the knife slash, and the fire kick.
Co-Authored-By: Claude Fable 5 <[email protected]>
This commit is contained in:
co-authored by
Claude Fable 5
parent
d46530bd8c
commit
df0bf18e0f
+32
-20
@@ -72,33 +72,45 @@ func do_quick_melee(prev_slot: int) -> void:
|
||||
get_parent()._equip_slot(auto_switch_slot)
|
||||
auto_switch_slot = -1
|
||||
|
||||
var _swing_alt: bool = false # alternate slash direction each attack
|
||||
|
||||
func _swing() -> void:
|
||||
is_swinging = true
|
||||
fire_cooldown = fire_rate
|
||||
|
||||
_swing_alt = not _swing_alt
|
||||
|
||||
if fire_sound:
|
||||
fire_sound.play()
|
||||
|
||||
# Tween for swipe animation
|
||||
|
||||
# A real slash: windup opposite, then a fast diagonal arc THROUGH screen
|
||||
# centre with the blade leading, alternating backhand/forehand.
|
||||
var s := 1.0 if _swing_alt else -1.0
|
||||
var tween = create_tween()
|
||||
|
||||
# Windup: Move to the right, point the blade left and tilt it
|
||||
tween.tween_property(self, "position", Vector3(0.6, -0.2, -0.630), 0.1)
|
||||
tween.parallel().tween_property(self, "rotation", Vector3(deg_to_rad(10), deg_to_rad(80), deg_to_rad(-40)), 0.1)
|
||||
|
||||
# Swipe: Move across the screen to the left quickly
|
||||
tween.tween_property(self, "position", Vector3(-0.6, -0.3, -0.788), 0.1)
|
||||
tween.parallel().tween_property(self, "rotation", Vector3(deg_to_rad(10), deg_to_rad(110), deg_to_rad(-60)), 0.1)
|
||||
|
||||
# Return to idle
|
||||
tween.tween_property(self, "position", default_pos, 0.2)
|
||||
tween.parallel().tween_property(self, "rotation", Vector3.ZERO, 0.2)
|
||||
|
||||
# Damage occurs partway through the swing
|
||||
get_tree().create_timer(0.15).timeout.connect(_do_damage)
|
||||
|
||||
# Windup: cock back and up on the swing-origin side, blade rolled outward.
|
||||
tween.tween_property(self, "position",
|
||||
Vector3(0.55 * s, 0.05, -0.55), 0.08).set_ease(Tween.EASE_OUT)
|
||||
tween.parallel().tween_property(self, "rotation", Vector3(
|
||||
deg_to_rad(35), deg_to_rad(70 * s), deg_to_rad(-70 * s)), 0.08)
|
||||
# Slash: whip across to the other side, low — a full diagonal cut.
|
||||
tween.tween_property(self, "position",
|
||||
Vector3(-0.55 * s, -0.42, -0.80), 0.09).set_ease(Tween.EASE_IN)
|
||||
tween.parallel().tween_property(self, "rotation", Vector3(
|
||||
deg_to_rad(-25), deg_to_rad(120 * s), deg_to_rad(-100 * s)), 0.09)
|
||||
# Follow-through drift before recovering to guard.
|
||||
tween.tween_property(self, "position",
|
||||
Vector3(-0.62 * s, -0.5, -0.72), 0.06)
|
||||
tween.tween_property(self, "position", default_pos, 0.18).set_ease(Tween.EASE_OUT)
|
||||
tween.parallel().tween_property(self, "rotation", Vector3.ZERO, 0.18)
|
||||
|
||||
# Third-person: the model swings an arm (synced to other players too).
|
||||
if player and player.has_method("_trigger_action"):
|
||||
player._trigger_action("melee")
|
||||
|
||||
# Damage lands mid-slash.
|
||||
get_tree().create_timer(0.12).timeout.connect(_do_damage)
|
||||
|
||||
# Finish swing
|
||||
get_tree().create_timer(0.4).timeout.connect(_finish_swing)
|
||||
get_tree().create_timer(0.41).timeout.connect(_finish_swing)
|
||||
|
||||
func _do_damage() -> void:
|
||||
if not camera: return
|
||||
|
||||
Reference in New Issue
Block a user