saumwacht-godot/scripts/presentation/worker_figure.gd
Martin Stickelbroeck c2b447610c Baseline: Saumwacht 0.15.0 (Phase 20A) vor dem Umbau zu Champions of Luneraria
Unveränderter Ausgangsstand inklusive Masterprompt und Konzeptbildern
unter assets/. .godot/ und docs/screenshots/ bleiben laut .gitignore
unversioniert; letztere sind unter ../backups gesichert.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-27 20:00:36 +02:00

47 lines
1.6 KiB
GDScript

extends "res://scripts/presentation/skeletal_figure.gd"
## Funkenleser work loop: tool contact, gather, deposit into the reservoir, return.
const WORK_STEPS: Array = ["strike", "pickup", "deposit", "return"]
const WORK_GAP: float = 0.7
const STRIKE_CONTACT: float = 0.62
var _work_clock: float = 0.0
var _strike_contact_pending: bool = false
func cycle_length() -> float:
var total: float = WORK_GAP
for clip: String in WORK_STEPS:
total += clip_length(clip)
return total
func update_work(delta: float, phase: float = 0.0) -> void:
if player == null or not is_inside_tree():
return
var cycle: float = cycle_length()
var before: float = _work_clock + phase
_work_clock += maxf(delta, 0.0)
var after: float = _work_clock + phase
var contact: float = STRIKE_CONTACT * clip_length("strike")
# Count an actual crossing, including across the loop boundary. A time window
# can fire twice when consumed every frame, or fire after a phase-offset spawn.
if delta > 0.0 and floorf((after - contact) / cycle) > floorf((before - contact) / cycle):
_strike_contact_pending = true
var t: float = fposmod(after, cycle)
var cursor: float = 0.0
for clip: String in WORK_STEPS:
var length: float = clip_length(clip)
if t < cursor + length:
var local: float = t - cursor
_sample(clip, local, delta, .08)
return
cursor += length
_sample("idle", t - cursor, delta, .08)
func consume_strike_contact() -> bool:
if _strike_contact_pending:
_strike_contact_pending = false
return true
return false
func preview(clip: String, at: float) -> void:
_strike_contact_pending = false
super.preview(clip, at)