1use crate::platform_time::{Duration, Instant};
10
11use crate::audio::{BgmEngine, KoeEngine, PcmEngine, SeEngine};
12
13use super::Value;
14use super::constants::RuntimeConstants;
15use super::globals::{GlobalState, ObjectState, StageFormState};
16use super::int_event::IntEvent;
17
18fn anim_skip_trace_enabled() -> bool {
19 env_is_set!("SG_DEBUG")
20}
21
22fn anim_skip_trace(msg: impl AsRef<str>) {
23 if anim_skip_trace_enabled() {
24 eprintln!("[SG_DEBUG][ANIM_SKIP_TRACE][WAIT] {}", msg.as_ref());
25 }
26}
27
28fn int_event_state(ev: &IntEvent) -> String {
29 format!(
30 "def={} value={} cur={} start={} end={} cur_time={} end_time={} delay={} loop_type={} speed={} real={} active={}",
31 ev.def_value,
32 ev.value,
33 ev.cur_value,
34 ev.start_value,
35 ev.end_value,
36 ev.cur_time,
37 ev.end_time,
38 ev.delay_time,
39 ev.loop_type,
40 ev.speed_type,
41 ev.real_flag,
42 ev.check_event(),
43 )
44}
45
46fn object_event_op_name(ids: &RuntimeConstants, op: i32) -> &'static str {
47 if ids.obj_patno_eve != 0 && op == ids.obj_patno_eve {
48 return "PATNO_EVE";
49 }
50 if ids.obj_x_eve != 0 && op == ids.obj_x_eve {
51 return "X_EVE";
52 }
53 if ids.obj_y_eve != 0 && op == ids.obj_y_eve {
54 return "Y_EVE";
55 }
56 if ids.obj_z_eve != 0 && op == ids.obj_z_eve {
57 return "Z_EVE";
58 }
59 if ids.obj_center_x_eve != 0 && op == ids.obj_center_x_eve {
60 return "CENTER_X_EVE";
61 }
62 if ids.obj_center_y_eve != 0 && op == ids.obj_center_y_eve {
63 return "CENTER_Y_EVE";
64 }
65 if ids.obj_center_z_eve != 0 && op == ids.obj_center_z_eve {
66 return "CENTER_Z_EVE";
67 }
68 if ids.obj_center_rep_x_eve != 0 && op == ids.obj_center_rep_x_eve {
69 return "CENTER_REP_X_EVE";
70 }
71 if ids.obj_center_rep_y_eve != 0 && op == ids.obj_center_rep_y_eve {
72 return "CENTER_REP_Y_EVE";
73 }
74 if ids.obj_center_rep_z_eve != 0 && op == ids.obj_center_rep_z_eve {
75 return "CENTER_REP_Z_EVE";
76 }
77 if ids.obj_scale_x_eve != 0 && op == ids.obj_scale_x_eve {
78 return "SCALE_X_EVE";
79 }
80 if ids.obj_scale_y_eve != 0 && op == ids.obj_scale_y_eve {
81 return "SCALE_Y_EVE";
82 }
83 if ids.obj_scale_z_eve != 0 && op == ids.obj_scale_z_eve {
84 return "SCALE_Z_EVE";
85 }
86 if ids.obj_rotate_x_eve != 0 && op == ids.obj_rotate_x_eve {
87 return "ROTATE_X_EVE";
88 }
89 if ids.obj_rotate_y_eve != 0 && op == ids.obj_rotate_y_eve {
90 return "ROTATE_Y_EVE";
91 }
92 if ids.obj_rotate_z_eve != 0 && op == ids.obj_rotate_z_eve {
93 return "ROTATE_Z_EVE";
94 }
95 if ids.obj_clip_left_eve != 0 && op == ids.obj_clip_left_eve {
96 return "CLIP_LEFT_EVE";
97 }
98 if ids.obj_clip_top_eve != 0 && op == ids.obj_clip_top_eve {
99 return "CLIP_TOP_EVE";
100 }
101 if ids.obj_clip_right_eve != 0 && op == ids.obj_clip_right_eve {
102 return "CLIP_RIGHT_EVE";
103 }
104 if ids.obj_clip_bottom_eve != 0 && op == ids.obj_clip_bottom_eve {
105 return "CLIP_BOTTOM_EVE";
106 }
107 if ids.obj_src_clip_left_eve != 0 && op == ids.obj_src_clip_left_eve {
108 return "SRC_CLIP_LEFT_EVE";
109 }
110 if ids.obj_src_clip_top_eve != 0 && op == ids.obj_src_clip_top_eve {
111 return "SRC_CLIP_TOP_EVE";
112 }
113 if ids.obj_src_clip_right_eve != 0 && op == ids.obj_src_clip_right_eve {
114 return "SRC_CLIP_RIGHT_EVE";
115 }
116 if ids.obj_src_clip_bottom_eve != 0 && op == ids.obj_src_clip_bottom_eve {
117 return "SRC_CLIP_BOTTOM_EVE";
118 }
119 if ids.obj_tr_eve != 0 && op == ids.obj_tr_eve {
120 return "TR_EVE";
121 }
122 if ids.obj_mono_eve != 0 && op == ids.obj_mono_eve {
123 return "MONO_EVE";
124 }
125 if ids.obj_reverse_eve != 0 && op == ids.obj_reverse_eve {
126 return "REVERSE_EVE";
127 }
128 if ids.obj_bright_eve != 0 && op == ids.obj_bright_eve {
129 return "BRIGHT_EVE";
130 }
131 if ids.obj_dark_eve != 0 && op == ids.obj_dark_eve {
132 return "DARK_EVE";
133 }
134 if ids.obj_color_r_eve != 0 && op == ids.obj_color_r_eve {
135 return "COLOR_R_EVE";
136 }
137 if ids.obj_color_g_eve != 0 && op == ids.obj_color_g_eve {
138 return "COLOR_G_EVE";
139 }
140 if ids.obj_color_b_eve != 0 && op == ids.obj_color_b_eve {
141 return "COLOR_B_EVE";
142 }
143 if ids.obj_color_rate_eve != 0 && op == ids.obj_color_rate_eve {
144 return "COLOR_RATE_EVE";
145 }
146 if ids.obj_color_add_r_eve != 0 && op == ids.obj_color_add_r_eve {
147 return "COLOR_ADD_R_EVE";
148 }
149 if ids.obj_color_add_g_eve != 0 && op == ids.obj_color_add_g_eve {
150 return "COLOR_ADD_G_EVE";
151 }
152 if ids.obj_color_add_b_eve != 0 && op == ids.obj_color_add_b_eve {
153 return "COLOR_ADD_B_EVE";
154 }
155 if ids.obj_x_rep_eve != 0 && op == ids.obj_x_rep_eve {
156 return "X_REP_EVE";
157 }
158 if ids.obj_y_rep_eve != 0 && op == ids.obj_y_rep_eve {
159 return "Y_REP_EVE";
160 }
161 if ids.obj_z_rep_eve != 0 && op == ids.obj_z_rep_eve {
162 return "Z_REP_EVE";
163 }
164 if ids.obj_tr_rep_eve != 0 && op == ids.obj_tr_rep_eve {
165 return "TR_REP_EVE";
166 }
167 "UNKNOWN_EVE"
168}
169
170#[derive(Debug, Clone, Copy)]
171pub enum AudioWait {
172 Bgm,
173 BgmFade,
174 KoeAny,
175 SeAny,
176 PcmAny,
177 PcmSlot(u8),
178 PcmSlotFade(u8),
179}
180
181#[derive(Debug, Clone)]
182pub enum EventWait {
183 ObjectAll {
184 stage_form_id: u32,
185 stage_idx: i64,
186 runtime_slot: usize,
187 },
188 ObjectOne {
189 stage_form_id: u32,
190 stage_idx: i64,
191 runtime_slot: usize,
192 op: i32,
193 },
194 ObjectList {
195 stage_form_id: u32,
196 stage_idx: i64,
197 runtime_slot: usize,
198 list_op: i32,
199 list_idx: usize,
200 },
201 GenericIntEvent {
202 form_id: u32,
203 index: Option<usize>,
204 },
205 ScreenEffect {
206 form_id: u32,
207 index: usize,
208 op: i32,
209 },
210 StageEffect {
211 stage_form_id: u32,
212 stage_idx: i64,
213 index: usize,
214 op: i32,
215 },
216 Mask {
217 form_id: u32,
218 index: usize,
219 op: i32,
220 },
221 FogX,
222 CounterThreshold {
223 form_id: u32,
224 index: usize,
225 target: i64,
226 },
227 PcmEvent {
228 form_id: u32,
229 index: usize,
230 },
231}
232
233#[derive(Debug, Clone, Copy)]
234pub struct MovieWait {
235 pub stage_form_id: u32,
236 pub stage_idx: i64,
237 pub runtime_slot: usize,
238 pub return_value_flag: bool,
239}
240
241#[derive(Debug, Clone, Copy)]
242pub struct EmoteWait {
243 pub stage_form_id: u32,
244 pub stage_idx: i64,
245 pub runtime_slot: usize,
246 pub return_value_flag: bool,
247}
248
249#[derive(Debug, Clone, Copy)]
250pub enum QuakeWait {
251 Screen {
252 form_id: u32,
253 index: usize,
254 },
255 Stage {
256 stage_form_id: u32,
257 stage_idx: i64,
258 index: usize,
259 },
260}
261
262fn quake_wait_active(globals: &GlobalState, wait: QuakeWait) -> bool {
263 match wait {
264 QuakeWait::Screen { form_id, index } => globals
265 .screen_forms
266 .get(&form_id)
267 .and_then(|screen| screen.quake_list.get(index))
268 .map(|quake| quake.is_active())
269 .unwrap_or(false),
270 QuakeWait::Stage {
271 stage_form_id,
272 stage_idx,
273 index,
274 } => globals
275 .stage_forms
276 .get(&stage_form_id)
277 .and_then(|stage| stage.quake_lists.get(&stage_idx))
278 .and_then(|quakes| quakes.get(index))
279 .map(|quake| quake.is_active())
280 .unwrap_or(false),
281 }
282}
283
284fn stop_waited_quake(globals: &mut GlobalState, wait: QuakeWait) {
285 let quake = match wait {
286 QuakeWait::Screen { form_id, index } => globals
287 .screen_forms
288 .get_mut(&form_id)
289 .and_then(|screen| screen.quake_list.get_mut(index)),
290 QuakeWait::Stage {
291 stage_form_id,
292 stage_idx,
293 index,
294 } => globals
295 .stage_forms
296 .get_mut(&stage_form_id)
297 .and_then(|stage| stage.quake_lists.get_mut(&stage_idx))
298 .and_then(|quakes| quakes.get_mut(index)),
299 };
300 if let Some(quake) = quake {
301 quake.reinit();
302 }
303}
304
305fn object_runtime_slot(idx: usize, obj: &ObjectState) -> usize {
306 obj.runtime_slot_or(idx)
307}
308
309fn find_object_by_runtime_slot(
310 objects: &[ObjectState],
311 runtime_slot: usize,
312) -> Option<&ObjectState> {
313 for (idx, obj) in objects.iter().enumerate() {
314 if object_runtime_slot(idx, obj) == runtime_slot {
315 return Some(obj);
316 }
317 if let Some(found) = find_object_by_runtime_slot(&obj.runtime.child_objects, runtime_slot) {
318 return Some(found);
319 }
320 }
321 None
322}
323
324fn find_object_by_runtime_slot_mut(
325 mut objects: &mut [ObjectState],
326 runtime_slot: usize,
327) -> Option<&mut ObjectState> {
328 let mut idx = 0usize;
329 while let Some((obj, tail)) = objects.split_first_mut() {
330 if object_runtime_slot(idx, obj) == runtime_slot {
331 return Some(obj);
332 }
333 if let Some(found) =
334 find_object_by_runtime_slot_mut(&mut obj.runtime.child_objects, runtime_slot)
335 {
336 return Some(found);
337 }
338 objects = tail;
339 idx += 1;
340 }
341 None
342}
343
344fn object_event_list_for_wait<'a>(
345 obj: &'a ObjectState,
346 ids: &RuntimeConstants,
347 op: i32,
348) -> Option<&'a Vec<IntEvent>> {
349 obj.int_event_list_by_op(ids, op)
350 .or_else(|| obj.rep_int_event_list_by_rep_op(ids, op))
351}
352
353fn object_event_list_for_wait_mut<'a>(
354 obj: &'a mut ObjectState,
355 ids: &RuntimeConstants,
356 op: i32,
357) -> Option<&'a mut Vec<IntEvent>> {
358 if ids.obj_x_rep_eve != 0 && op == ids.obj_x_rep_eve {
359 Some(&mut obj.runtime.prop_event_lists.x_rep)
360 } else if ids.obj_y_rep_eve != 0 && op == ids.obj_y_rep_eve {
361 Some(&mut obj.runtime.prop_event_lists.y_rep)
362 } else if ids.obj_z_rep_eve != 0 && op == ids.obj_z_rep_eve {
363 Some(&mut obj.runtime.prop_event_lists.z_rep)
364 } else if ids.obj_tr_rep_eve != 0 && op == ids.obj_tr_rep_eve {
365 Some(&mut obj.runtime.prop_event_lists.tr_rep)
366 } else if ids.obj_x_rep != 0 && op == ids.obj_x_rep {
367 Some(&mut obj.runtime.prop_event_lists.x_rep)
368 } else if ids.obj_y_rep != 0 && op == ids.obj_y_rep {
369 Some(&mut obj.runtime.prop_event_lists.y_rep)
370 } else if ids.obj_z_rep != 0 && op == ids.obj_z_rep {
371 Some(&mut obj.runtime.prop_event_lists.z_rep)
372 } else if ids.obj_tr_rep != 0 && op == ids.obj_tr_rep {
373 Some(&mut obj.runtime.prop_event_lists.tr_rep)
374 } else {
375 None
376 }
377}
378
379fn object_active_in_stage_state_by_runtime_slot(
380 st: &StageFormState,
381 stage_idx: i64,
382 runtime_slot: usize,
383) -> Option<&ObjectState> {
384 if let Some(obj) = st
385 .object_lists
386 .get(&stage_idx)
387 .and_then(|list| find_object_by_runtime_slot(list, runtime_slot))
388 {
389 return Some(obj);
390 }
391
392 if let Some(items) = st.btnselitem_lists.get(&stage_idx) {
393 for item in items {
394 if let Some(obj) = find_object_by_runtime_slot(&item.object_list, runtime_slot) {
395 return Some(obj);
396 }
397 }
398 }
399
400 if let Some(mwnds) = st.mwnd_lists.get(&stage_idx) {
401 for mwnd in mwnds {
402 if let Some(obj) = find_object_by_runtime_slot(&mwnd.button_list, runtime_slot) {
403 return Some(obj);
404 }
405 if let Some(obj) = find_object_by_runtime_slot(&mwnd.face_list, runtime_slot) {
406 return Some(obj);
407 }
408 if let Some(obj) = find_object_by_runtime_slot(&mwnd.object_list, runtime_slot) {
409 return Some(obj);
410 }
411 }
412 }
413
414 None
415}
416
417fn object_active_by_runtime_slot(
418 globals: &GlobalState,
419 stage_form_id: u32,
420 stage_idx: i64,
421 runtime_slot: usize,
422) -> Option<&ObjectState> {
423 globals
424 .stage_forms
425 .get(&stage_form_id)
426 .and_then(|st| object_active_in_stage_state_by_runtime_slot(st, stage_idx, runtime_slot))
427}
428
429fn find_object_by_runtime_slot_mut_ptr(
430 objects: &mut [ObjectState],
431 runtime_slot: usize,
432) -> Option<*mut ObjectState> {
433 find_object_by_runtime_slot_mut(objects, runtime_slot).map(|obj| obj as *mut ObjectState)
434}
435
436fn object_active_by_runtime_slot_mut(
437 globals: &mut GlobalState,
438 stage_form_id: u32,
439 stage_idx: i64,
440 runtime_slot: usize,
441) -> Option<&mut ObjectState> {
442 let st = globals.stage_forms.get_mut(&stage_form_id)?;
443
444 if let Some(ptr) = st
445 .object_lists
446 .get_mut(&stage_idx)
447 .and_then(|list| find_object_by_runtime_slot_mut_ptr(list, runtime_slot))
448 {
449 return unsafe { Some(&mut *ptr) };
450 }
451
452 if let Some(items) = st.btnselitem_lists.get_mut(&stage_idx) {
453 for item in items {
454 if let Some(ptr) =
455 find_object_by_runtime_slot_mut_ptr(&mut item.object_list, runtime_slot)
456 {
457 return unsafe { Some(&mut *ptr) };
458 }
459 }
460 }
461
462 if let Some(mwnds) = st.mwnd_lists.get_mut(&stage_idx) {
463 for mwnd in mwnds {
464 if let Some(ptr) =
465 find_object_by_runtime_slot_mut_ptr(&mut mwnd.button_list, runtime_slot)
466 {
467 return unsafe { Some(&mut *ptr) };
468 }
469 if let Some(ptr) =
470 find_object_by_runtime_slot_mut_ptr(&mut mwnd.face_list, runtime_slot)
471 {
472 return unsafe { Some(&mut *ptr) };
473 }
474 if let Some(ptr) =
475 find_object_by_runtime_slot_mut_ptr(&mut mwnd.object_list, runtime_slot)
476 {
477 return unsafe { Some(&mut *ptr) };
478 }
479 }
480 }
481
482 None
483}
484
485fn finish_wait_skipped_event(ev: &mut IntEvent) {
486 let before = if anim_skip_trace_enabled() {
487 Some(int_event_state(ev))
488 } else {
489 None
490 };
491 ev.end_event();
492 ev.frame();
493 if let Some(before) = before {
494 anim_skip_trace(format!(
495 "finish_event before=[{}] after=[{}]",
496 before,
497 int_event_state(ev)
498 ));
499 }
500}
501
502fn event_prop_pairs(ids: &RuntimeConstants) -> [(i32, i32); 36] {
503 [
504 (ids.obj_patno_eve, ids.obj_patno),
505 (ids.obj_x_eve, ids.obj_x),
506 (ids.obj_y_eve, ids.obj_y),
507 (ids.obj_z_eve, ids.obj_z),
508 (ids.obj_center_x_eve, ids.obj_center_x),
509 (ids.obj_center_y_eve, ids.obj_center_y),
510 (ids.obj_center_z_eve, ids.obj_center_z),
511 (ids.obj_center_rep_x_eve, ids.obj_center_rep_x),
512 (ids.obj_center_rep_y_eve, ids.obj_center_rep_y),
513 (ids.obj_center_rep_z_eve, ids.obj_center_rep_z),
514 (ids.obj_scale_x_eve, ids.obj_scale_x),
515 (ids.obj_scale_y_eve, ids.obj_scale_y),
516 (ids.obj_scale_z_eve, ids.obj_scale_z),
517 (ids.obj_rotate_x_eve, ids.obj_rotate_x),
518 (ids.obj_rotate_y_eve, ids.obj_rotate_y),
519 (ids.obj_rotate_z_eve, ids.obj_rotate_z),
520 (ids.obj_clip_left_eve, ids.obj_clip_left),
521 (ids.obj_clip_top_eve, ids.obj_clip_top),
522 (ids.obj_clip_right_eve, ids.obj_clip_right),
523 (ids.obj_clip_bottom_eve, ids.obj_clip_bottom),
524 (ids.obj_src_clip_left_eve, ids.obj_src_clip_left),
525 (ids.obj_src_clip_top_eve, ids.obj_src_clip_top),
526 (ids.obj_src_clip_right_eve, ids.obj_src_clip_right),
527 (ids.obj_src_clip_bottom_eve, ids.obj_src_clip_bottom),
528 (ids.obj_tr_eve, ids.obj_tr),
529 (ids.obj_mono_eve, ids.obj_mono),
530 (ids.obj_reverse_eve, ids.obj_reverse),
531 (ids.obj_bright_eve, ids.obj_bright),
532 (ids.obj_dark_eve, ids.obj_dark),
533 (ids.obj_color_r_eve, ids.obj_color_r),
534 (ids.obj_color_g_eve, ids.obj_color_g),
535 (ids.obj_color_b_eve, ids.obj_color_b),
536 (ids.obj_color_rate_eve, ids.obj_color_rate),
537 (ids.obj_color_add_r_eve, ids.obj_color_add_r),
538 (ids.obj_color_add_g_eve, ids.obj_color_add_g),
539 (ids.obj_color_add_b_eve, ids.obj_color_add_b),
540 ]
541}
542
543fn object_prop_op_for_event_op(ids: &RuntimeConstants, event_op: i32) -> Option<i32> {
544 event_prop_pairs(ids)
545 .into_iter()
546 .find_map(|(ev_op, prop_op)| (ev_op != 0 && event_op == ev_op).then_some(prop_op))
547}
548
549fn finish_wait_skipped_object_event_by_op(
550 obj: &mut ObjectState,
551 ids: &RuntimeConstants,
552 event_op: i32,
553) {
554 let file = obj.file_name.as_deref().unwrap_or("-").to_string();
555 let runtime_slot = obj.runtime_slot_or(usize::MAX);
556 let event_name = object_event_op_name(ids, event_op);
557 let Some(value) = obj.int_event_by_op_mut(ids, event_op).map(|ev| {
558 anim_skip_trace(format!(
559 "finish_object_event begin slot={} file={} op={}({}) state=[{}]",
560 runtime_slot,
561 file,
562 event_op,
563 event_name,
564 int_event_state(ev)
565 ));
566 finish_wait_skipped_event(ev);
567 anim_skip_trace(format!(
568 "finish_object_event event_done slot={} file={} op={}({}) state=[{}]",
569 runtime_slot,
570 file,
571 event_op,
572 event_name,
573 int_event_state(ev)
574 ));
575 ev.get_total_value() as i64
576 }) else {
577 anim_skip_trace(format!(
578 "finish_object_event missing slot={} file={} op={}({})",
579 runtime_slot, file, event_op, event_name
580 ));
581 return;
582 };
583 if let Some(prop_op) = object_prop_op_for_event_op(ids, event_op) {
584 obj.set_int_prop(ids, prop_op, value);
585 anim_skip_trace(format!(
586 "finish_object_event prop_write slot={} file={} event_op={}({}) prop_op={} value={} obj_tr={} obj_alpha={} obj_pos=({}, {})",
587 runtime_slot,
588 file,
589 event_op,
590 event_name,
591 prop_op,
592 value,
593 obj.get_int_prop(ids, ids.obj_tr),
594 obj.base.alpha,
595 obj.get_int_prop(ids, ids.obj_x),
596 obj.get_int_prop(ids, ids.obj_y),
597 ));
598 } else {
599 anim_skip_trace(format!(
600 "finish_object_event no_prop_map slot={} file={} event_op={}({}) value={}",
601 runtime_slot, file, event_op, event_name, value
602 ));
603 }
604}
605
606fn finish_wait_skipped_object_events(obj: &mut ObjectState, ids: &RuntimeConstants) {
607 let file = obj.file_name.as_deref().unwrap_or("-").to_string();
608 let runtime_slot = obj.runtime_slot_or(usize::MAX);
609 anim_skip_trace(format!(
610 "finish_object_all begin slot={} file={} any_active={} tr={} alpha={} pos=({}, {})",
611 runtime_slot,
612 file,
613 obj.any_event_active(),
614 obj.get_int_prop(ids, ids.obj_tr),
615 obj.base.alpha,
616 obj.get_int_prop(ids, ids.obj_x),
617 obj.get_int_prop(ids, ids.obj_y),
618 ));
619 let mut final_values = Vec::new();
620 for (event_op, prop_op) in event_prop_pairs(ids) {
621 if event_op == 0 || prop_op == 0 {
622 continue;
623 }
624 if let Some(ev) = obj.int_event_by_op_mut(ids, event_op) {
625 if ev.check_event() {
626 anim_skip_trace(format!(
627 "finish_object_all active slot={} file={} op={}({}) state=[{}]",
628 runtime_slot,
629 file,
630 event_op,
631 object_event_op_name(ids, event_op),
632 int_event_state(ev)
633 ));
634 }
635 finish_wait_skipped_event(ev);
636 final_values.push((event_op, prop_op, ev.get_total_value() as i64));
637 }
638 }
639 obj.runtime.prop_event_lists.end_all();
640 obj.runtime.prop_event_lists.frame();
641 for (event_op, prop_op, value) in final_values {
642 obj.set_int_prop(ids, prop_op, value);
643 anim_skip_trace(format!(
644 "finish_object_all prop_write slot={} file={} event_op={}({}) prop_op={} value={}",
645 runtime_slot,
646 file,
647 event_op,
648 object_event_op_name(ids, event_op),
649 prop_op,
650 value
651 ));
652 }
653 anim_skip_trace(format!(
654 "finish_object_all end slot={} file={} any_active={} tr={} alpha={} pos=({}, {})",
655 runtime_slot,
656 file,
657 obj.any_event_active(),
658 obj.get_int_prop(ids, ids.obj_tr),
659 obj.base.alpha,
660 obj.get_int_prop(ids, ids.obj_x),
661 obj.get_int_prop(ids, ids.obj_y),
662 ));
663}
664
665fn finish_event_wait_by_key(w: &EventWait, globals: &mut GlobalState, ids: &RuntimeConstants) {
666 match w {
667 EventWait::ObjectAll {
668 stage_form_id,
669 stage_idx,
670 runtime_slot,
671 } => {
672 if let Some(obj) = object_active_by_runtime_slot_mut(
673 globals,
674 *stage_form_id,
675 *stage_idx,
676 *runtime_slot,
677 ) {
678 finish_wait_skipped_object_events(obj, ids);
679 }
680 }
681 EventWait::ObjectOne {
682 stage_form_id,
683 stage_idx,
684 runtime_slot,
685 op,
686 } => {
687 if let Some(obj) = object_active_by_runtime_slot_mut(
688 globals,
689 *stage_form_id,
690 *stage_idx,
691 *runtime_slot,
692 ) {
693 finish_wait_skipped_object_event_by_op(obj, ids, *op);
694 }
695 }
696 EventWait::ObjectList {
697 stage_form_id,
698 stage_idx,
699 runtime_slot,
700 list_op,
701 list_idx,
702 } => {
703 if let Some(obj) = object_active_by_runtime_slot_mut(
704 globals,
705 *stage_form_id,
706 *stage_idx,
707 *runtime_slot,
708 ) {
709 let file = obj.file_name.as_deref().unwrap_or("-").to_string();
710 if let Some(ev) = object_event_list_for_wait_mut(obj, ids, *list_op)
711 .and_then(|v| v.get_mut(*list_idx))
712 {
713 anim_skip_trace(format!(
714 "finish_object_list_event begin stage_form={} stage={} slot={} file={} list_op={}({}) list_idx={} state=[{}]",
715 stage_form_id,
716 stage_idx,
717 runtime_slot,
718 file,
719 list_op,
720 object_event_op_name(ids, *list_op),
721 list_idx,
722 int_event_state(ev)
723 ));
724 finish_wait_skipped_event(ev);
725 anim_skip_trace(format!(
726 "finish_object_list_event end stage_form={} stage={} slot={} file={} list_op={}({}) list_idx={} state=[{}]",
727 stage_form_id,
728 stage_idx,
729 runtime_slot,
730 file,
731 list_op,
732 object_event_op_name(ids, *list_op),
733 list_idx,
734 int_event_state(ev)
735 ));
736 } else {
737 anim_skip_trace(format!(
738 "finish_object_list_event missing stage_form={} stage={} slot={} file={} list_op={}({}) list_idx={}",
739 stage_form_id,
740 stage_idx,
741 runtime_slot,
742 file,
743 list_op,
744 object_event_op_name(ids, *list_op),
745 list_idx
746 ));
747 }
748 }
749 }
750 EventWait::GenericIntEvent { form_id, index } => match index {
751 Some(i) => {
752 if let Some(ev) = globals
753 .int_event_lists
754 .get_mut(form_id)
755 .and_then(|v| v.get_mut(*i))
756 {
757 anim_skip_trace(format!(
758 "finish_generic_int_event begin form_id={} index={} state=[{}]",
759 form_id,
760 i,
761 int_event_state(ev)
762 ));
763 finish_wait_skipped_event(ev);
764 anim_skip_trace(format!(
765 "finish_generic_int_event end form_id={} index={} state=[{}]",
766 form_id,
767 i,
768 int_event_state(ev)
769 ));
770 }
771 }
772 None => {
773 if let Some(ev) = globals.int_event_roots.get_mut(form_id) {
774 anim_skip_trace(format!(
775 "finish_generic_int_event begin form_id={} index=None state=[{}]",
776 form_id,
777 int_event_state(ev)
778 ));
779 finish_wait_skipped_event(ev);
780 anim_skip_trace(format!(
781 "finish_generic_int_event end form_id={} index=None state=[{}]",
782 form_id,
783 int_event_state(ev)
784 ));
785 }
786 }
787 },
788 EventWait::ScreenEffect { form_id, index, op } => {
789 if let Some(ev) = globals
790 .screen_forms
791 .get_mut(form_id)
792 .and_then(|screen| screen.effect_list.get_mut(*index))
793 .and_then(|effect| effect.int_event_by_op_mut(ids, *op))
794 {
795 finish_wait_skipped_event(ev);
796 }
797 }
798 EventWait::StageEffect {
799 stage_form_id,
800 stage_idx,
801 index,
802 op,
803 } => {
804 if let Some(ev) = globals
805 .stage_forms
806 .get_mut(stage_form_id)
807 .and_then(|stage| stage.effect_lists.get_mut(stage_idx))
808 .and_then(|effects| effects.get_mut(*index))
809 .and_then(|effect| effect.int_event_by_op_mut(ids, *op))
810 {
811 finish_wait_skipped_event(ev);
812 }
813 }
814 EventWait::Mask { form_id, index, op } => {
815 if let Some(mask) = globals
816 .mask_lists
817 .get_mut(form_id)
818 .and_then(|list| list.masks.get_mut(*index))
819 {
820 let ev = if *op == super::constants::elm_value::MASK_X_EVE {
821 Some(&mut mask.x_event)
822 } else if *op == super::constants::elm_value::MASK_Y_EVE {
823 Some(&mut mask.y_event)
824 } else {
825 None
826 };
827 if let Some(ev) = ev {
828 finish_wait_skipped_event(ev);
829 }
830 }
831 }
832 EventWait::FogX => {
833 finish_wait_skipped_event(&mut globals.fog_global.x_event);
834 globals.fog_global.scroll_x = globals.fog_global.x_event.get_total_value() as f32;
835 }
836 EventWait::CounterThreshold { .. } => {}
837 EventWait::PcmEvent { .. } => {}
840 }
841}
842
843#[derive(Debug, Default, Clone)]
844pub struct VmWait {
845 pub until: Option<Instant>,
846 pub until_frame: Option<u64>,
847 mwnd_animation_wait: bool,
849 pub waiting_for_key: bool,
850 selbtn: bool,
855 group_selection: Option<(u32, i64, usize)>,
858 generic_key_wait: bool,
860 generic_key_wait_skip_disabled: bool,
861 pub message_reveal: bool,
865 message_key_after_reveal: bool,
868 message_key_wait: bool,
869 skip_time_on_key: bool,
871
872 pub audio: Option<AudioWait>,
873 audio_key_skip: bool,
878 audio_return_value: bool,
879
880 pub event: Option<EventWait>,
881 event_key_skip: bool,
882 event_return_value: bool,
883
884 pub movie: Option<MovieWait>,
885 movie_key_skip: bool,
886
887 emote: Option<EmoteWait>,
888 emote_key_skip: bool,
889
890 global_movie: bool,
891 global_movie_key_skip: bool,
892 global_movie_return_value: bool,
893
894 movie_skip_info: Option<MovieWait>,
895
896 pub quake: Option<QuakeWait>,
897 quake_key_skip: bool,
898 pub pending_value: Option<Value>,
899
900 pub system_modal: bool,
902
903 pub wipe: bool,
904 wipe_key_skip: bool,
905 wipe_return_value: bool,
906
907 block_generation: u64,
908}
909
910impl VmWait {
911 pub fn block_generation(&self) -> u64 {
912 self.block_generation
913 }
914
915 pub fn needs_runtime_poll(&self) -> bool {
916 self.message_reveal
917 || self.message_key_wait
918 || self.generic_key_wait
919 || self.selbtn
920 || self.until.is_some()
921 || self.until_frame.is_some()
922 || self.audio.is_some()
923 || self.event.is_some()
924 || self.movie.is_some()
925 || self.emote.is_some()
926 || self.quake.is_some()
927 || self.global_movie
928 || self.wipe
929 }
930
931 pub fn needs_continuous_frame(&self) -> bool {
936 self.message_reveal
937 || self.until.is_some()
938 || self.until_frame.is_some()
939 || self.audio.is_some()
940 || self.event.is_some()
941 || self.movie.is_some()
942 || self.emote.is_some()
943 || self.quake.is_some()
944 || self.global_movie
945 || self.wipe
946 }
947
948 fn mark_block_request(&mut self) {
949 self.block_generation = self.block_generation.wrapping_add(1);
950 }
951
952 pub fn poll(
953 &mut self,
954 stack: &mut Vec<Value>,
955 bgm: &mut BgmEngine,
956 koe: &mut KoeEngine,
957 se: &mut SeEngine,
958 pcm: &mut PcmEngine,
959 globals: &mut GlobalState,
960 ids: &RuntimeConstants,
961 skipping: bool,
962 ) -> bool {
963 let blocked = self.is_blocked(bgm, koe, se, pcm, globals, ids, skipping);
964 if !blocked && let Some(v) = self.pending_value.take() {
965 stack.push(v);
966 }
967 blocked
968 }
969
970 pub fn is_blocked(
971 &mut self,
972 bgm: &mut BgmEngine,
973 koe: &mut KoeEngine,
974 se: &mut SeEngine,
975 pcm: &mut PcmEngine,
976 globals: &mut GlobalState,
977 ids: &RuntimeConstants,
978 skipping: bool,
979 ) -> bool {
980 if self.selbtn {
984 let processing = match globals.selbtn.sync_type {
985 0 => globals.selbtn.processing_flag_0,
986 1 => globals.selbtn.processing_flag_1,
987 2 => globals.selbtn.processing_flag_2,
988 _ => false,
989 };
990 if !processing {
991 self.selbtn = false;
992 }
993 }
994
995 if let Some(t) = self.until
997 && Instant::now() >= t
998 {
999 let key_skippable_timewait = self.skip_time_on_key;
1000 self.until = None;
1001 self.skip_time_on_key = false;
1002 self.mwnd_animation_wait = false;
1003 if key_skippable_timewait {
1004 anim_skip_trace("timewait_key naturally finished pending=0");
1005 self.pending_value = Some(Value::Int(0));
1006 }
1007 }
1008
1009 if skipping && self.until.is_some() {
1013 let return_value = self.skip_time_on_key;
1014 self.until = None;
1015 self.skip_time_on_key = false;
1016 self.mwnd_animation_wait = false;
1017 if return_value {
1018 self.pending_value = Some(Value::Int(0));
1019 }
1020 }
1021
1022 if let Some(frame) = self.until_frame
1023 && globals.render_frame >= frame
1024 {
1025 self.until_frame = None;
1026 }
1027
1028 if skipping && self.generic_key_wait && !self.generic_key_wait_skip_disabled {
1031 self.generic_key_wait = false;
1032 self.generic_key_wait_skip_disabled = false;
1033 self.waiting_for_key = false;
1034 }
1035
1036 if let Some(w) = self.audio {
1038 let done = match w {
1039 AudioWait::Bgm => !bgm.is_playing(),
1040 AudioWait::BgmFade => !bgm.is_fade_out_doing(),
1041 AudioWait::KoeAny => !koe.is_playing_any(),
1042 AudioWait::SeAny => !se.is_playing_any(),
1043 AudioWait::PcmAny => !pcm.is_playing_any(),
1044 AudioWait::PcmSlot(s) => !pcm.is_playing_slot(s as usize),
1045 AudioWait::PcmSlotFade(s) => !pcm.is_fading_slot(s as usize),
1046 };
1047 if done {
1048 self.audio = None;
1049 self.audio_key_skip = false;
1050 if self.audio_return_value {
1051 self.pending_value = Some(Value::Int(0));
1052 }
1053 self.audio_return_value = false;
1054 }
1055 }
1056
1057 if skipping && self.audio.is_some() {
1061 self.audio = None;
1062 self.audio_key_skip = false;
1063 if self.audio_return_value {
1064 self.pending_value = Some(Value::Int(0));
1065 }
1066 self.audio_return_value = false;
1067 }
1068
1069 let event_done = if let Some(w) = self.event.as_ref() {
1071 match w {
1072 EventWait::ObjectAll {
1073 stage_form_id,
1074 stage_idx,
1075 runtime_slot,
1076 } => object_active_by_runtime_slot(
1077 globals,
1078 *stage_form_id,
1079 *stage_idx,
1080 *runtime_slot,
1081 )
1082 .map(|obj| !obj.any_event_active())
1083 .unwrap_or(true),
1084 EventWait::ObjectOne {
1085 stage_form_id,
1086 stage_idx,
1087 runtime_slot,
1088 op,
1089 } => object_active_by_runtime_slot(
1090 globals,
1091 *stage_form_id,
1092 *stage_idx,
1093 *runtime_slot,
1094 )
1095 .map(|obj| {
1096 !obj.int_event_by_op(ids, *op)
1097 .map(|e| e.check_event())
1098 .unwrap_or(false)
1099 })
1100 .unwrap_or(true),
1101 EventWait::ObjectList {
1102 stage_form_id,
1103 stage_idx,
1104 runtime_slot,
1105 list_op,
1106 list_idx,
1107 } => object_active_by_runtime_slot(
1108 globals,
1109 *stage_form_id,
1110 *stage_idx,
1111 *runtime_slot,
1112 )
1113 .map(|obj| {
1114 let active = object_event_list_for_wait(obj, ids, *list_op)
1115 .and_then(|v| v.get(*list_idx))
1116 .map(|e| e.check_event())
1117 .unwrap_or(false);
1118 !active
1119 })
1120 .unwrap_or(true),
1121 EventWait::GenericIntEvent { form_id, index } => match index {
1122 Some(i) => globals
1123 .int_event_lists
1124 .get(form_id)
1125 .and_then(|v| v.get(*i))
1126 .map(|e| !e.check_event())
1127 .unwrap_or(true),
1128 None => globals
1129 .int_event_roots
1130 .get(form_id)
1131 .map(|e| !e.check_event())
1132 .unwrap_or(true),
1133 },
1134 EventWait::ScreenEffect { form_id, index, op } => globals
1135 .screen_forms
1136 .get(form_id)
1137 .and_then(|screen| screen.effect_list.get(*index))
1138 .and_then(|effect| effect.int_event_by_op(ids, *op))
1139 .map(|event| !event.check_event())
1140 .unwrap_or(true),
1141 EventWait::StageEffect {
1142 stage_form_id,
1143 stage_idx,
1144 index,
1145 op,
1146 } => globals
1147 .stage_forms
1148 .get(stage_form_id)
1149 .and_then(|stage| stage.effect_lists.get(stage_idx))
1150 .and_then(|effects| effects.get(*index))
1151 .and_then(|effect| effect.int_event_by_op(ids, *op))
1152 .map(|event| !event.check_event())
1153 .unwrap_or(true),
1154 EventWait::Mask { form_id, index, op } => globals
1155 .mask_lists
1156 .get(form_id)
1157 .and_then(|list| list.masks.get(*index))
1158 .and_then(|mask| {
1159 if *op == super::constants::elm_value::MASK_X_EVE {
1160 Some(&mask.x_event)
1161 } else if *op == super::constants::elm_value::MASK_Y_EVE {
1162 Some(&mask.y_event)
1163 } else {
1164 None
1165 }
1166 })
1167 .map(|event| !event.check_event())
1168 .unwrap_or(true),
1169 EventWait::FogX => !globals.fog_global.x_event.check_event(),
1170 EventWait::CounterThreshold {
1171 form_id,
1172 index,
1173 target,
1174 } => globals
1175 .counter_lists
1176 .get(form_id)
1177 .and_then(|v| v.get(*index))
1178 .map(|c| c.get_count() - *target >= 0)
1179 .unwrap_or(true),
1180 EventWait::PcmEvent { form_id, index } => globals
1181 .pcm_event_lists
1182 .get(form_id)
1183 .and_then(|v| v.get(*index))
1184 .map(|event| !event.is_active())
1185 .unwrap_or(true),
1186 }
1187 } else {
1188 false
1189 };
1190 if event_done {
1191 let was_event_key_skip = self.event_key_skip;
1192 anim_skip_trace(format!(
1193 "event_wait naturally finished event={:?} key_skip={} return_value={}",
1194 self.event.as_ref(),
1195 was_event_key_skip,
1196 self.event_return_value
1197 ));
1198 self.event = None;
1199 self.event_key_skip = false;
1200 if was_event_key_skip {
1201 self.waiting_for_key = false;
1202 }
1203 if self.event_return_value {
1204 self.pending_value = Some(Value::Int(0));
1205 }
1206 self.event_return_value = false;
1207 }
1208
1209 if skipping && matches!(self.event, Some(EventWait::CounterThreshold { .. })) {
1213 self.event = None;
1214 self.event_key_skip = false;
1215 if self.event_return_value {
1216 self.pending_value = Some(Value::Int(0));
1217 }
1218 self.event_return_value = false;
1219 self.waiting_for_key = false;
1220 }
1221
1222 if self
1223 .quake
1224 .map(|wait| !quake_wait_active(globals, wait))
1225 .unwrap_or(false)
1226 {
1227 self.quake = None;
1228 self.quake_key_skip = false;
1229 self.waiting_for_key = false;
1230 }
1231 if skipping && let Some(wait) = self.quake.take() {
1232 stop_waited_quake(globals, wait);
1233 self.quake_key_skip = false;
1234 self.waiting_for_key = false;
1235 }
1236
1237 if self.global_movie && !globals.mov.playing {
1239 if self.global_movie_return_value {
1240 self.pending_value = Some(Value::Int(0));
1241 }
1242 self.global_movie = false;
1243 self.global_movie_key_skip = false;
1244 self.global_movie_return_value = false;
1245 }
1246
1247 if let Some(w) = self.movie {
1249 let done = object_active_by_runtime_slot(
1250 globals,
1251 w.stage_form_id,
1252 w.stage_idx,
1253 w.runtime_slot,
1254 )
1255 .map(|obj| !obj.movie.check_movie())
1256 .unwrap_or(true);
1257
1258 if done {
1259 if w.return_value_flag {
1260 self.pending_value = Some(Value::Int(0));
1261 }
1262 self.movie = None;
1263 self.movie_key_skip = false;
1264 }
1265 }
1266
1267 if let Some(w) = self.emote {
1269 let done = object_active_by_runtime_slot(
1270 globals,
1271 w.stage_form_id,
1272 w.stage_idx,
1273 w.runtime_slot,
1274 )
1275 .map(|obj| !obj.emote.is_animating())
1276 .unwrap_or(true);
1277
1278 if done {
1279 let was_key_skip = self.emote_key_skip;
1280 if w.return_value_flag {
1281 self.pending_value = Some(Value::Int(0));
1282 }
1283 self.emote = None;
1284 self.emote_key_skip = false;
1285 if was_key_skip {
1286 self.waiting_for_key = false;
1287 }
1288 }
1289 }
1290
1291 if self.wipe && globals.wipe_done() {
1293 self.wipe = false;
1294 if self.wipe_return_value {
1295 self.pending_value = Some(Value::Int(0));
1296 }
1297 self.wipe_return_value = false;
1298 if self.wipe_key_skip {
1299 self.wipe_key_skip = false;
1300 if self.waiting_for_key {
1301 self.waiting_for_key = false;
1302 }
1303 }
1304 }
1305
1306 if let Some((form_id, stage_idx, group_idx)) = self.group_selection {
1307 let waiting = globals
1308 .stage_forms
1309 .get(&form_id)
1310 .and_then(|st| st.group_lists.get(&stage_idx))
1311 .and_then(|groups| groups.get(group_idx))
1312 .map(|group| group.wait_flag && group.started)
1313 .unwrap_or(false);
1314 if !waiting {
1315 self.group_selection = None;
1316 }
1317 }
1318
1319 self.selbtn
1320 || self.group_selection.is_some()
1321 || self.waiting_for_key
1322 || self.message_reveal
1323 || self.until.is_some()
1324 || self.until_frame.is_some()
1325 || self.audio.is_some()
1326 || self.event.is_some()
1327 || self.movie.is_some()
1328 || self.emote.is_some()
1329 || self.quake.is_some()
1330 || self.global_movie
1331 || self.system_modal
1332 || self.wipe
1333 }
1334
1335 pub fn wait_system_modal(&mut self) {
1336 self.mark_block_request();
1337 self.system_modal = true;
1338 }
1339
1340 pub fn finish_system_modal(&mut self, value: Value) {
1341 if self.system_modal {
1342 self.system_modal = false;
1343 self.pending_value = Some(value);
1344 }
1345 }
1346
1347 pub fn finish_system_modal_void(&mut self) {
1348 if self.system_modal {
1349 self.system_modal = false;
1350 self.pending_value = None;
1351 }
1352 }
1353
1354 pub fn system_modal_active(&self) -> bool {
1355 self.system_modal
1356 }
1357
1358 pub fn wait_ms(&mut self, ms: u64) {
1359 if ms == 0 {
1360 return;
1361 }
1362 self.mark_block_request();
1363 self.until = Some(Instant::now() + Duration::from_millis(ms));
1364 self.skip_time_on_key = false;
1365 self.mwnd_animation_wait = false;
1366 }
1367
1368 pub fn wait_mwnd_animation(&mut self, ms: u64) {
1369 if ms == 0 {
1370 return;
1371 }
1372 self.mark_block_request();
1373 self.until = Some(Instant::now() + Duration::from_millis(ms));
1374 self.skip_time_on_key = false;
1375 self.mwnd_animation_wait = true;
1376 }
1377
1378 pub fn mwnd_animation_waiting(&self) -> bool {
1379 self.mwnd_animation_wait && self.until.is_some()
1380 }
1381
1382 pub fn wait_next_frame(&mut self, current_frame: u64) {
1383 self.mark_block_request();
1384 self.until_frame = Some(current_frame.saturating_add(1));
1385 self.skip_time_on_key = false;
1386 }
1387
1388 pub fn wait_ms_key(&mut self, ms: u64) {
1390 if ms == 0 {
1391 anim_skip_trace("wait_ms_key ignored ms=0");
1392 return;
1393 }
1394 self.mark_block_request();
1395 self.until = Some(Instant::now() + Duration::from_millis(ms));
1396 self.skip_time_on_key = true;
1397 self.mwnd_animation_wait = false;
1398 anim_skip_trace(format!(
1399 "wait_ms_key start ms={} block_generation={}",
1400 ms, self.block_generation
1401 ));
1402 }
1403
1404 pub fn wait_selbtn(&mut self) {
1405 self.mark_block_request();
1406 self.selbtn = true;
1407 }
1408
1409 pub fn set_selbtn_result(&mut self, result: i64) {
1410 self.pending_value = Some(Value::Int(result));
1415 }
1416
1417 pub fn wait_key(&mut self) {
1418 self.mark_block_request();
1419 self.waiting_for_key = true;
1420 }
1421
1422 pub fn wait_group_selection(&mut self, form_id: u32, stage_idx: i64, group_idx: usize) {
1423 self.mark_block_request();
1424 self.group_selection = Some((form_id, stage_idx, group_idx));
1425 }
1426
1427 pub(crate) fn button_selection_waiting(&self) -> bool {
1428 self.selbtn || self.group_selection.is_some()
1429 }
1430
1431 pub fn wait_input_key(&mut self, skip_disabled: bool) {
1432 self.mark_block_request();
1433 self.waiting_for_key = true;
1434 self.generic_key_wait = true;
1435 self.generic_key_wait_skip_disabled = skip_disabled;
1436 }
1437
1438 pub fn waiting_for_key(&self) -> bool {
1439 self.waiting_for_key
1440 }
1441
1442 pub fn wait_message_reveal(&mut self) {
1443 self.mark_block_request();
1444 self.message_reveal = true;
1445 self.message_key_after_reveal = false;
1446 }
1447
1448 pub fn wait_message_reveal_then_key(&mut self) {
1449 self.mark_block_request();
1450 self.message_reveal = true;
1451 self.message_key_after_reveal = true;
1452 self.message_key_wait = false;
1453 }
1454
1455 pub fn message_reveal_waiting(&self) -> bool {
1456 self.message_reveal
1457 }
1458
1459 pub fn finish_message_reveal(&mut self) -> bool {
1462 self.message_reveal = false;
1463 if self.message_key_after_reveal {
1464 self.message_key_after_reveal = false;
1465 self.message_key_wait = true;
1466 self.waiting_for_key = true;
1467 true
1468 } else {
1469 false
1470 }
1471 }
1472
1473 pub fn message_key_waiting(&self) -> bool {
1474 self.message_key_wait
1475 }
1476
1477 pub fn finish_message_key_wait(&mut self) {
1478 self.message_key_wait = false;
1479 self.waiting_for_key = false;
1480 }
1481
1482 pub fn wait_quake(&mut self, wait: QuakeWait, key_skip: bool) {
1483 self.mark_block_request();
1484 self.quake = Some(wait);
1485 self.quake_key_skip = key_skip;
1486 if key_skip {
1487 self.waiting_for_key = true;
1488 }
1489 }
1490
1491 pub fn wait_audio(&mut self, w: AudioWait, key: bool) {
1492 self.wait_audio_with_return(w, key, false);
1493 }
1494
1495 pub fn wait_audio_with_return(&mut self, w: AudioWait, key: bool, return_value_flag: bool) {
1496 self.mark_block_request();
1497 self.audio = Some(w);
1498 self.audio_key_skip = key;
1499 self.audio_return_value = return_value_flag;
1500 }
1501
1502 pub fn wait_object_all_events(
1503 &mut self,
1504 stage_form_id: u32,
1505 stage_idx: i64,
1506 runtime_slot: usize,
1507 key_skip: bool,
1508 ) {
1509 self.mark_block_request();
1510 self.event = Some(EventWait::ObjectAll {
1511 stage_form_id,
1512 stage_idx,
1513 runtime_slot,
1514 });
1515 anim_skip_trace(format!(
1516 "wait_object_all_events start stage_form={} stage={} slot={} key_skip={} block_generation={}",
1517 stage_form_id, stage_idx, runtime_slot, key_skip, self.block_generation
1518 ));
1519 self.event_key_skip = key_skip;
1520 self.event_return_value = false;
1521 if key_skip {
1522 self.waiting_for_key = true;
1523 }
1524 }
1525
1526 pub fn wait_object_event(
1527 &mut self,
1528 stage_form_id: u32,
1529 stage_idx: i64,
1530 runtime_slot: usize,
1531 op: i32,
1532 key_skip: bool,
1533 return_value_flag: bool,
1534 ) {
1535 self.mark_block_request();
1536 self.event = Some(EventWait::ObjectOne {
1537 stage_form_id,
1538 stage_idx,
1539 runtime_slot,
1540 op,
1541 });
1542 anim_skip_trace(format!(
1543 "wait_object_event start stage_form={} stage={} slot={} op={} key_skip={} return_value={} block_generation={}",
1544 stage_form_id,
1545 stage_idx,
1546 runtime_slot,
1547 op,
1548 key_skip,
1549 return_value_flag,
1550 self.block_generation
1551 ));
1552 self.event_key_skip = key_skip;
1553 self.event_return_value = return_value_flag;
1554 if key_skip {
1555 self.waiting_for_key = true;
1556 }
1557 }
1558
1559 pub fn wait_object_event_list(
1560 &mut self,
1561 stage_form_id: u32,
1562 stage_idx: i64,
1563 runtime_slot: usize,
1564 list_op: i32,
1565 list_idx: usize,
1566 key_skip: bool,
1567 return_value_flag: bool,
1568 ) {
1569 self.mark_block_request();
1570 self.event = Some(EventWait::ObjectList {
1571 stage_form_id,
1572 stage_idx,
1573 runtime_slot,
1574 list_op,
1575 list_idx,
1576 });
1577 anim_skip_trace(format!(
1578 "wait_object_event_list start stage_form={} stage={} slot={} list_op={} list_idx={} key_skip={} return_value={} block_generation={}",
1579 stage_form_id,
1580 stage_idx,
1581 runtime_slot,
1582 list_op,
1583 list_idx,
1584 key_skip,
1585 return_value_flag,
1586 self.block_generation
1587 ));
1588 self.event_key_skip = key_skip;
1589 self.event_return_value = return_value_flag;
1590 if key_skip {
1591 self.waiting_for_key = true;
1592 }
1593 }
1594
1595 pub fn wait_global_movie(&mut self, key_skip: bool, return_value_flag: bool) {
1596 self.mark_block_request();
1597 self.global_movie = true;
1598 self.global_movie_key_skip = key_skip;
1599 self.global_movie_return_value = return_value_flag;
1600 }
1601
1602 pub fn wait_object_movie(
1603 &mut self,
1604 stage_form_id: u32,
1605 stage_idx: i64,
1606 runtime_slot: usize,
1607 key_skip: bool,
1608 return_value_flag: bool,
1609 ) {
1610 self.mark_block_request();
1611 self.movie = Some(MovieWait {
1612 stage_form_id,
1613 stage_idx,
1614 runtime_slot,
1615 return_value_flag,
1616 });
1617 self.movie_key_skip = key_skip;
1618 }
1619
1620 pub fn wait_object_emote(
1621 &mut self,
1622 stage_form_id: u32,
1623 stage_idx: i64,
1624 runtime_slot: usize,
1625 key_skip: bool,
1626 return_value_flag: bool,
1627 ) {
1628 self.mark_block_request();
1629 self.emote = Some(EmoteWait {
1630 stage_form_id,
1631 stage_idx,
1632 runtime_slot,
1633 return_value_flag,
1634 });
1635 self.emote_key_skip = key_skip;
1636 if key_skip {
1637 self.waiting_for_key = true;
1638 }
1639 }
1640
1641 pub fn wait_generic_int_event(
1642 &mut self,
1643 form_id: u32,
1644 index: Option<usize>,
1645 key_skip: bool,
1646 return_value_flag: bool,
1647 ) {
1648 self.mark_block_request();
1649 self.event = Some(EventWait::GenericIntEvent { form_id, index });
1650 anim_skip_trace(format!(
1651 "wait_generic_int_event start form_id={} index={:?} key_skip={} return_value={} block_generation={}",
1652 form_id, index, key_skip, return_value_flag, self.block_generation
1653 ));
1654 self.event_key_skip = key_skip;
1655 self.event_return_value = return_value_flag;
1656 if key_skip {
1657 self.waiting_for_key = true;
1658 }
1659 }
1660
1661 pub fn wait_pcm_event(
1662 &mut self,
1663 form_id: u32,
1664 index: usize,
1665 key_skip: bool,
1666 return_value_flag: bool,
1667 ) {
1668 self.mark_block_request();
1669 self.event = Some(EventWait::PcmEvent { form_id, index });
1670 self.event_key_skip = key_skip;
1671 self.event_return_value = return_value_flag;
1672 if key_skip {
1673 self.waiting_for_key = true;
1674 }
1675 }
1676
1677 pub fn wait_screen_effect(
1678 &mut self,
1679 form_id: u32,
1680 index: usize,
1681 op: i32,
1682 key_skip: bool,
1683 return_value_flag: bool,
1684 ) {
1685 self.mark_block_request();
1686 self.event = Some(EventWait::ScreenEffect { form_id, index, op });
1687 self.event_key_skip = key_skip;
1688 self.event_return_value = return_value_flag;
1689 if key_skip {
1690 self.waiting_for_key = true;
1691 }
1692 }
1693
1694 pub fn wait_stage_effect(
1695 &mut self,
1696 stage_form_id: u32,
1697 stage_idx: i64,
1698 index: usize,
1699 op: i32,
1700 key_skip: bool,
1701 return_value_flag: bool,
1702 ) {
1703 self.mark_block_request();
1704 self.event = Some(EventWait::StageEffect {
1705 stage_form_id,
1706 stage_idx,
1707 index,
1708 op,
1709 });
1710 self.event_key_skip = key_skip;
1711 self.event_return_value = return_value_flag;
1712 if key_skip {
1713 self.waiting_for_key = true;
1714 }
1715 }
1716
1717 pub fn wait_mask_event(
1718 &mut self,
1719 form_id: u32,
1720 index: usize,
1721 op: i32,
1722 key_skip: bool,
1723 return_value_flag: bool,
1724 ) {
1725 self.mark_block_request();
1726 self.event = Some(EventWait::Mask { form_id, index, op });
1727 self.event_key_skip = key_skip;
1728 self.event_return_value = return_value_flag;
1729 if key_skip {
1730 self.waiting_for_key = true;
1731 }
1732 }
1733
1734 pub fn wait_fog_x_event(&mut self, key_skip: bool, return_value_flag: bool) {
1735 self.mark_block_request();
1736 self.event = Some(EventWait::FogX);
1737 self.event_key_skip = key_skip;
1738 self.event_return_value = return_value_flag;
1739 if key_skip {
1740 self.waiting_for_key = true;
1741 }
1742 }
1743
1744 pub fn wait_counter(
1745 &mut self,
1746 form_id: u32,
1747 index: usize,
1748 target: i64,
1749 key_skip: bool,
1750 return_value_flag: bool,
1751 ) {
1752 self.mark_block_request();
1753 self.event = Some(EventWait::CounterThreshold {
1754 form_id,
1755 index,
1756 target,
1757 });
1758 self.event_key_skip = key_skip;
1759 self.event_return_value = return_value_flag;
1760 if key_skip {
1761 self.waiting_for_key = true;
1762 }
1763 }
1764
1765 pub fn wait_wipe(&mut self, key_skip: bool) {
1766 self.wait_wipe_with_return(key_skip, false);
1767 }
1768
1769 pub fn wait_wipe_with_return(&mut self, key_skip: bool, return_value_flag: bool) {
1770 self.mark_block_request();
1771 self.wipe = true;
1772 self.wipe_key_skip = key_skip;
1773 self.wipe_return_value = return_value_flag;
1774 }
1779
1780 pub fn notify_key(&mut self, _globals: &mut GlobalState, _ids: &RuntimeConstants) -> bool {
1784 let wipe_skipped = self.wipe && self.wipe_key_skip;
1785 self.waiting_for_key = false;
1786 self.generic_key_wait = false;
1787 self.generic_key_wait_skip_disabled = false;
1788 if wipe_skipped {
1794 self.wipe = false;
1795 self.wipe_key_skip = false;
1796 if self.wipe_return_value {
1797 self.pending_value = Some(Value::Int(1));
1798 }
1799 self.wipe_return_value = false;
1800 }
1801
1802 wipe_skipped
1803 }
1804
1805 pub fn notify_movie_down_up(
1812 &mut self,
1813 globals: &mut GlobalState,
1814 ids: &RuntimeConstants,
1815 result: i64,
1816 ) -> bool {
1817 let mut skipped = false;
1818 if result == 1 && self.audio_key_skip {
1822 if self.audio.take().is_some() {
1823 if self.audio_return_value {
1824 self.pending_value = Some(Value::Int(1));
1825 }
1826 skipped = true;
1827 }
1828 self.audio_key_skip = false;
1829 self.audio_return_value = false;
1830 }
1831 if self.skip_time_on_key && matches!(result, 1 | -1) {
1832 anim_skip_trace(format!(
1833 "notify_movie_down_up skipped TIMEWAIT_KEY pending={}",
1834 result
1835 ));
1836 self.until = None;
1837 self.skip_time_on_key = false;
1838 self.pending_value = Some(Value::Int(result));
1839 skipped = true;
1840 }
1841 if result == 1 && self.quake_key_skip {
1842 if let Some(wait) = self.quake.take() {
1843 stop_waited_quake(globals, wait);
1844 skipped = true;
1845 }
1846 self.quake_key_skip = false;
1847 }
1848 if result == 1 && self.event_key_skip {
1849 if let Some(w) = self.event.take() {
1850 anim_skip_trace(format!(
1851 "notify_movie_down_up skip event result={} event={:?} return_value={}",
1852 result, w, self.event_return_value
1853 ));
1854 finish_event_wait_by_key(&w, globals, ids);
1855 if self.event_return_value {
1856 self.pending_value = Some(Value::Int(1));
1857 }
1858 skipped = true;
1859 } else {
1860 anim_skip_trace(format!(
1861 "notify_movie_down_up event_key_skip without event result={}",
1862 result
1863 ));
1864 }
1865 self.event_key_skip = false;
1866 self.event_return_value = false;
1867 }
1868 if self.global_movie && self.global_movie_key_skip {
1869 globals.mov.playing = false;
1873 if self.global_movie_return_value {
1874 self.pending_value = Some(Value::Int(result));
1875 }
1876 self.global_movie = false;
1877 self.global_movie_key_skip = false;
1878 self.global_movie_return_value = false;
1879 skipped = true;
1880 }
1881 if self.movie_key_skip && result == 1 {
1884 if let Some(w) = self.movie.take() {
1885 if w.return_value_flag {
1886 self.pending_value = Some(Value::Int(1));
1887 }
1888 self.movie_skip_info = Some(w);
1889 skipped = true;
1890 }
1891 self.movie_key_skip = false;
1892 }
1893
1894 if self.emote_key_skip && result == 1 {
1897 if let Some(w) = self.emote.take() {
1898 if let Some(obj) = object_active_by_runtime_slot_mut(
1899 globals,
1900 w.stage_form_id,
1901 w.stage_idx,
1902 w.runtime_slot,
1903 ) && let Some(runtime) = obj.emote.runtime.as_mut()
1904 && let Err(err) = runtime.pass()
1905 {
1906 log::error!("EMOTE_WAIT_PLAYING_KEY Pass failed: {err:#}");
1907 }
1908 if w.return_value_flag {
1909 self.pending_value = Some(Value::Int(1));
1910 }
1911 skipped = true;
1912 }
1913 self.emote_key_skip = false;
1914 }
1915 if skipped {
1916 self.waiting_for_key = false;
1917 }
1918 skipped
1919 }
1920
1921 pub fn take_movie_skip(&mut self) -> Option<MovieWait> {
1923 self.movie_skip_info.take()
1924 }
1925
1926 pub fn clear(&mut self) {
1927 self.selbtn = false;
1928 self.group_selection = None;
1929 self.until = None;
1930 self.mwnd_animation_wait = false;
1931 self.waiting_for_key = false;
1932 self.generic_key_wait = false;
1933 self.generic_key_wait_skip_disabled = false;
1934 self.message_reveal = false;
1935 self.message_key_after_reveal = false;
1936 self.message_key_wait = false;
1937 self.skip_time_on_key = false;
1938 self.audio = None;
1939 self.audio_key_skip = false;
1940 self.audio_return_value = false;
1941 self.event = None;
1942 self.event_key_skip = false;
1943 self.event_return_value = false;
1944 self.movie = None;
1945 self.movie_key_skip = false;
1946 self.global_movie = false;
1947 self.global_movie_key_skip = false;
1948 self.global_movie_return_value = false;
1949 self.movie_skip_info = None;
1950 self.quake = None;
1951 self.quake_key_skip = false;
1952 self.pending_value = None;
1953 self.system_modal = false;
1954 self.wipe = false;
1955 self.wipe_key_skip = false;
1956 self.wipe_return_value = false;
1957 }
1958}
1959
1960#[cfg(test)]
1961mod audio_wait_parity_tests {
1962 use super::*;
1963 use std::path::PathBuf;
1964
1965 fn engines() -> (BgmEngine, KoeEngine, SeEngine, PcmEngine) {
1966 let root = PathBuf::from(".");
1967 (
1968 BgmEngine::new(root.clone()),
1969 KoeEngine::new(root.clone()),
1970 SeEngine::new(root.clone()),
1971 PcmEngine::new(root),
1972 )
1973 }
1974
1975 #[test]
1976 fn audio_wait_key_ignores_generic_input_and_cancel_but_decide_returns_one() {
1977 let mut wait = VmWait::default();
1978 let mut globals = GlobalState::default();
1979 let ids = RuntimeConstants::default();
1980
1981 wait.wait_audio_with_return(AudioWait::KoeAny, true, true);
1982 assert!(wait.audio.is_some());
1983 assert!(wait.audio_key_skip);
1984 assert!(!wait.waiting_for_key);
1985
1986 assert!(!wait.notify_key(&mut globals, &ids));
1988 assert!(wait.audio.is_some());
1989 assert!(wait.pending_value.is_none());
1990
1991 assert!(!wait.notify_movie_down_up(&mut globals, &ids, -1));
1993 assert!(wait.audio.is_some());
1994 assert!(wait.pending_value.is_none());
1995
1996 assert!(wait.notify_movie_down_up(&mut globals, &ids, 1));
1997 assert!(wait.audio.is_none());
1998 assert!(!wait.audio_key_skip);
1999 assert_eq!(wait.pending_value.take().and_then(|v| v.as_i64()), Some(1));
2000 }
2001
2002 #[test]
2003 fn audio_wait_natural_finish_returns_zero_without_leaving_generic_key_wait() {
2004 let mut wait = VmWait::default();
2005 let (mut bgm, mut koe, mut se, mut pcm) = engines();
2006 let mut globals = GlobalState::default();
2007 let ids = RuntimeConstants::default();
2008
2009 wait.wait_audio_with_return(AudioWait::KoeAny, true, true);
2010 assert!(!wait.is_blocked(
2011 &mut bgm,
2012 &mut koe,
2013 &mut se,
2014 &mut pcm,
2015 &mut globals,
2016 &ids,
2017 false,
2018 ));
2019 assert!(wait.audio.is_none());
2020 assert!(!wait.audio_key_skip);
2021 assert!(!wait.waiting_for_key);
2022 assert_eq!(wait.pending_value.take().and_then(|v| v.as_i64()), Some(0));
2023 }
2024
2025 #[test]
2026 fn message_wait_preserves_cpp_proc_stack_order() {
2027 let mut wait = VmWait::default();
2028
2029 wait.wait_message_reveal_then_key();
2030 assert!(wait.needs_continuous_frame());
2031 assert!(wait.message_reveal_waiting());
2032 assert!(!wait.message_key_waiting());
2033 assert!(!wait.waiting_for_key());
2034
2035 assert!(wait.finish_message_reveal());
2036 assert!(wait.needs_runtime_poll());
2037 assert!(!wait.needs_continuous_frame());
2038 assert!(!wait.message_reveal_waiting());
2039 assert!(wait.message_key_waiting());
2040 assert!(wait.waiting_for_key());
2041
2042 wait.finish_message_key_wait();
2043 assert!(!wait.message_key_waiting());
2044 assert!(!wait.waiting_for_key());
2045 }
2046
2047 #[test]
2048 fn selbtn_wait_ignores_generic_key_release_and_preserves_second_choice() {
2049 let mut wait = VmWait::default();
2050 let (mut bgm, mut koe, mut se, mut pcm) = engines();
2051 let mut globals = GlobalState::default();
2052 let ids = RuntimeConstants::default();
2053 let mut stack = Vec::new();
2054
2055 globals.selbtn.sync_type = 0;
2056 globals.selbtn.processing_flag_0 = true;
2057 wait.wait_selbtn();
2058 wait.set_selbtn_result(1);
2059
2060 assert!(!wait.notify_key(&mut globals, &ids));
2063 assert!(wait.poll(
2064 &mut stack,
2065 &mut bgm,
2066 &mut koe,
2067 &mut se,
2068 &mut pcm,
2069 &mut globals,
2070 &ids,
2071 false,
2072 ));
2073 assert!(stack.is_empty());
2074
2075 globals.selbtn.processing_flag_0 = false;
2076 assert!(!wait.poll(
2077 &mut stack,
2078 &mut bgm,
2079 &mut koe,
2080 &mut se,
2081 &mut pcm,
2082 &mut globals,
2083 &ids,
2084 false,
2085 ));
2086 assert_eq!(stack.pop().and_then(|v| v.as_i64()), Some(1));
2087 }
2088
2089 #[test]
2090 fn selbtn_sync_type_two_releases_at_decision() {
2091 let mut wait = VmWait::default();
2092 let (mut bgm, mut koe, mut se, mut pcm) = engines();
2093 let mut globals = GlobalState::default();
2094 let ids = RuntimeConstants::default();
2095 let mut stack = Vec::new();
2096
2097 globals.selbtn.sync_type = 2;
2098 globals.selbtn.processing_flag_2 = true;
2099 wait.wait_selbtn();
2100 assert!(wait.poll(
2101 &mut stack,
2102 &mut bgm,
2103 &mut koe,
2104 &mut se,
2105 &mut pcm,
2106 &mut globals,
2107 &ids,
2108 false,
2109 ));
2110
2111 wait.set_selbtn_result(1);
2112 globals.selbtn.processing_flag_2 = false;
2113 assert!(!wait.poll(
2114 &mut stack,
2115 &mut bgm,
2116 &mut koe,
2117 &mut se,
2118 &mut pcm,
2119 &mut globals,
2120 &ids,
2121 false,
2122 ));
2123 assert_eq!(stack.pop().and_then(|v| v.as_i64()), Some(1));
2124 }
2125
2126 #[test]
2127 fn pure_key_wait_does_not_request_idle_frames() {
2128 let mut wait = VmWait::default();
2129
2130 wait.wait_input_key(false);
2131
2132 assert!(wait.needs_runtime_poll());
2133 assert!(!wait.needs_continuous_frame());
2134 }
2135
2136 #[test]
2137 fn keylist_wait_obeys_skip_but_wait_force_does_not() {
2138 let (mut bgm, mut koe, mut se, mut pcm) = engines();
2139 let mut globals = GlobalState::default();
2140 let ids = RuntimeConstants::default();
2141
2142 let mut wait = VmWait::default();
2143 wait.wait_input_key(false);
2144 assert!(!wait.is_blocked(
2145 &mut bgm,
2146 &mut koe,
2147 &mut se,
2148 &mut pcm,
2149 &mut globals,
2150 &ids,
2151 true,
2152 ));
2153
2154 let mut forced = VmWait::default();
2155 forced.wait_input_key(true);
2156 assert!(forced.is_blocked(
2157 &mut bgm,
2158 &mut koe,
2159 &mut se,
2160 &mut pcm,
2161 &mut globals,
2162 &ids,
2163 true,
2164 ));
2165 }
2166
2167 #[test]
2168 fn skipping_releases_audio_wait_with_zero_without_stopping_player_state() {
2169 let mut wait = VmWait::default();
2170 let (mut bgm, mut koe, mut se, mut pcm) = engines();
2171 let mut globals = GlobalState::default();
2172 let ids = RuntimeConstants::default();
2173
2174 wait.wait_audio_with_return(AudioWait::KoeAny, true, true);
2175 assert!(!wait.is_blocked(
2176 &mut bgm,
2177 &mut koe,
2178 &mut se,
2179 &mut pcm,
2180 &mut globals,
2181 &ids,
2182 true,
2183 ));
2184 assert!(wait.audio.is_none());
2185 assert!(!wait.audio_key_skip);
2186 assert_eq!(wait.pending_value.take().and_then(|v| v.as_i64()), Some(0));
2187 }
2188}