Tune marker animation: 2000ms Hold queue delay

Empirically tested delay thresholds (100/500/1000/2000/3900ms).
Delays under ~2s cause the engine's blend logic to accelerate the
Stand grow-in animation. 2000ms is the shortest delay that preserves
full-speed Stand across all 5 marker colors.

Also confirmed all 5 Raid_UI_FX M2 models have identical animation
sequence entries (Stand→Hold→loop chain via nextAnimation fields),
but the engine doesn't honor the chain — explicit PlayBoneAnimation
queue is still required.
This commit is contained in:
MarcelineVQ
2026-03-02 08:58:43 -08:00
parent e474b61c37
commit 7e28c81db0
+14 -9
View File
@@ -73,7 +73,7 @@ var marker_positions: [NUM_MARKERS]?Vec3 = .{null} ** NUM_MARKERS;
var marker_created_tick: [NUM_MARKERS]u32 = .{0} ** NUM_MARKERS;
var hold_queued: [NUM_MARKERS]bool = .{false} ** NUM_MARKERS;
const STAND_DURATION_MS: u32 = 3900;
// Entities playing their Decay animation before destruction.
// Cleaned up every frame by tickAnimations (via OnWorldUpdate hook).
@@ -242,7 +242,7 @@ fn playAnimation(entity: *anyopaque, anim_id: u32, queue: bool) void {
@bitCast(@as(i32, -1)), // seqIndex: random
0, // animData: NULL
speed_bits, // speed: 1.0
1, // blendMode: blend
1, // blendMode: smooth blend
@intFromBool(queue),
};
@@ -322,14 +322,12 @@ fn placeMarker(index: usize, pos: Vec3) bool {
return false;
};
// Stand (grow-in) is queued by the engine in CM2Model_CreateForModelObject.
// Hold is deferred to the per-frame callback (tickAnimations) once
// the model is fully initialised (model+0x10 != 0), so it doesn't clobber
// Stand in the command queue.
marker_entities[index] = obj;
marker_positions[index] = pos;
hold_queued[index] = false;
marker_created_tick[index] = GetTickCount();
hold_queued[index] = false;
con.fmt("[markers] marker {d} placed at {d:.1}, {d:.1}, {d:.1}\n", .{ index + 1, pos.x, pos.y, pos.z });
return true;
}
@@ -439,8 +437,15 @@ pub fn luaClearWorldMarker(L: u32) callconv(.c) u32 {
return 0;
}
// Delay before queuing Hold after Stand starts. Too short (<1s) causes the
// engine's blend logic to accelerate Stand; too long and there's a visible gap.
// 2000ms was empirically determined as the shortest delay that preserves
// Stand's full-speed grow-in animation across all 5 marker colors.
const HOLD_QUEUE_DELAY_MS: u32 = 2000;
/// Per-frame animation tick (driven by OnWorldUpdate hook).
/// Queues Hold once after Stand finishes, then cleans up despawning entities.
/// Queues Hold once after Stand has been playing long enough, then cleans up
/// despawning entities.
fn tickAnimations() void {
const now = GetTickCount();
@@ -449,7 +454,7 @@ fn tickAnimations() void {
for (0..NUM_MARKERS) |i| {
if (hold_queued[i]) continue;
const entity = marker_entities[i] orelse continue;
if (now -% marker_created_tick[i] < STAND_DURATION_MS) continue;
if (now -% marker_created_tick[i] < HOLD_QUEUE_DELAY_MS) continue;
playAnimation(entity, ANIM_HOLD, true);
hold_queued[i] = true;