1use anyhow::Result;
8
9use super::prop_access;
10use crate::runtime::forms::codes::int_event_op;
11use crate::runtime::globals::{ScreenEffectState, ScreenFormState, ScreenQuakeState};
12use crate::runtime::{CommandContext, Value};
13
14const EFFECTLIST_RESIZE_OP: i32 = 1;
15const EFFECTLIST_GET_SIZE_OP: i32 = 2;
16
17const QUAKE_START_OP: i32 = 0;
18const QUAKE_START_WAIT_OP: i32 = 1;
19const QUAKE_START_WAIT_KEY_OP: i32 = 2;
20const QUAKE_START_NOWAIT_OP: i32 = 3;
21const QUAKE_START_ALL_OP: i32 = 4;
22const QUAKE_START_ALL_WAIT_OP: i32 = 5;
23const QUAKE_START_ALL_WAIT_KEY_OP: i32 = 6;
24const QUAKE_START_ALL_NOWAIT_OP: i32 = 7;
25const QUAKE_END_OP: i32 = 8;
26const QUAKE_CHECK_OP: i32 = 9;
27const QUAKE_WAIT_OP: i32 = 10;
28const QUAKE_WAIT_KEY_OP: i32 = 11;
29
30fn as_i64(v: &Value) -> Option<i64> {
31 match v {
32 Value::Int(n) => Some(*n),
33 Value::NamedArg { value, .. } => value.as_i64(),
34 _ => None,
35 }
36}
37
38fn default_for_ret_form(ret_form: i64) -> Value {
39 if prop_access::ret_form_is_string(ret_form) {
40 Value::Str(String::new())
41 } else {
42 Value::Int(0)
43 }
44}
45
46fn anim_skip_trace_enabled() -> bool {
47 std::env::var_os("SG_DEBUG").is_some()
48}
49
50fn screen_event_state(ev: &crate::runtime::int_event::IntEvent) -> String {
51 format!(
52 "value={} cur={} start={} end={} cur_time={} end_time={} delay={} loop_type={} speed={} real={} active={}",
53 ev.value, ev.cur_value, ev.start_value, ev.end_value, ev.cur_time, ev.end_time,
54 ev.delay_time, ev.loop_type, ev.speed_type, ev.real_flag, ev.check_event()
55 )
56}
57
58fn effect_prop_ref_mut<'a>(
59 ids: &crate::runtime::constants::RuntimeConstants,
60 effect: &'a mut ScreenEffectState,
61 op: i32,
62) -> Option<&'a mut i32> {
63 match op {
64 s if s == ids.effect_wipe_copy => Some(&mut effect.wipe_copy),
65 s if s == ids.effect_wipe_erase => Some(&mut effect.wipe_erase),
66 s if s == ids.effect_begin_order => Some(&mut effect.begin_order),
67 s if s == ids.effect_begin_layer => Some(&mut effect.begin_layer),
68 s if s == ids.effect_end_order => Some(&mut effect.end_order),
69 s if s == ids.effect_end_layer => Some(&mut effect.end_layer),
70 _ => None,
71 }
72}
73
74fn effect_prop_value(
75 ids: &crate::runtime::constants::RuntimeConstants,
76 effect: &ScreenEffectState,
77 op: i32,
78) -> Option<i64> {
79 match op {
80 s if s == ids.effect_wipe_copy => Some(effect.wipe_copy as i64),
81 s if s == ids.effect_wipe_erase => Some(effect.wipe_erase as i64),
82 s if s == ids.effect_begin_order => Some(effect.begin_order as i64),
83 s if s == ids.effect_begin_layer => Some(effect.begin_layer as i64),
84 s if s == ids.effect_end_order => Some(effect.end_order as i64),
85 s if s == ids.effect_end_layer => Some(effect.end_layer as i64),
86 _ => None,
87 }
88}
89
90fn effect_event_mut<'a>(
91 ids: &crate::runtime::constants::RuntimeConstants,
92 effect: &'a mut ScreenEffectState,
93 op: i32,
94) -> Option<&'a mut crate::runtime::int_event::IntEvent> {
95 match op {
96 s if s == ids.effect_x || s == ids.effect_x_eve => Some(&mut effect.x),
97 s if s == ids.effect_y || s == ids.effect_y_eve => Some(&mut effect.y),
98 s if s == ids.effect_z || s == ids.effect_z_eve => Some(&mut effect.z),
99 s if s == ids.effect_mono || s == ids.effect_mono_eve => Some(&mut effect.mono),
100 s if s == ids.effect_reverse || s == ids.effect_reverse_eve => Some(&mut effect.reverse),
101 s if s == ids.effect_bright || s == ids.effect_bright_eve => Some(&mut effect.bright),
102 s if s == ids.effect_dark || s == ids.effect_dark_eve => Some(&mut effect.dark),
103 s if s == ids.effect_color_r || s == ids.effect_color_r_eve => Some(&mut effect.color_r),
104 s if s == ids.effect_color_g || s == ids.effect_color_g_eve => Some(&mut effect.color_g),
105 s if s == ids.effect_color_b || s == ids.effect_color_b_eve => Some(&mut effect.color_b),
106 s if s == ids.effect_color_rate || s == ids.effect_color_rate_eve => {
107 Some(&mut effect.color_rate)
108 }
109 s if s == ids.effect_color_add_r || s == ids.effect_color_add_r_eve => {
110 Some(&mut effect.color_add_r)
111 }
112 s if s == ids.effect_color_add_g || s == ids.effect_color_add_g_eve => {
113 Some(&mut effect.color_add_g)
114 }
115 s if s == ids.effect_color_add_b || s == ids.effect_color_add_b_eve => {
116 Some(&mut effect.color_add_b)
117 }
118 _ => None,
119 }
120}
121
122fn run_int_event_command(
123 ctx: &mut CommandContext,
124 ev: &mut crate::runtime::int_event::IntEvent,
125 subop: i32,
126 params: &[Value],
127 ret_form: i64,
128) {
129 match subop {
130 int_event_op::SET | int_event_op::SET_REAL => {
131 let value = params.first().and_then(as_i64).unwrap_or(0) as i32;
132 let total_time = params.get(1).and_then(as_i64).unwrap_or(0) as i32;
133 let delay_time = params.get(2).and_then(as_i64).unwrap_or(0) as i32;
134 let speed_type = params.get(3).and_then(as_i64).unwrap_or(0) as i32;
135 let real_flag = if subop == int_event_op::SET_REAL {
136 1
137 } else {
138 0
139 };
140 ev.set_event(value, total_time, delay_time, speed_type, real_flag);
141 if anim_skip_trace_enabled() {
142 eprintln!(
143 "[SG_DEBUG][ANIM_SKIP_TRACE][SCREEN] INTEVENT.SET subop={} value={} total_time={} delay={} speed={} real={} state=[{}]",
144 subop, value, total_time, delay_time, speed_type, real_flag, screen_event_state(ev)
145 );
146 }
147 ctx.stack.push(default_for_ret_form(ret_form));
148 }
149 int_event_op::LOOP | int_event_op::LOOP_REAL => {
150 let start_value = params.first().and_then(as_i64).unwrap_or(0) as i32;
151 let end_value = params.get(1).and_then(as_i64).unwrap_or(0) as i32;
152 let loop_time = params.get(2).and_then(as_i64).unwrap_or(0) as i32;
153 let delay_time = params.get(3).and_then(as_i64).unwrap_or(0) as i32;
154 let speed_type = params.get(4).and_then(as_i64).unwrap_or(0) as i32;
155 let real_flag = if subop == int_event_op::LOOP_REAL {
156 1
157 } else {
158 0
159 };
160 ev.loop_event(
161 start_value,
162 end_value,
163 loop_time,
164 delay_time,
165 speed_type,
166 real_flag,
167 );
168 if anim_skip_trace_enabled() {
169 eprintln!(
170 "[SG_DEBUG][ANIM_SKIP_TRACE][SCREEN] INTEVENT.LOOP subop={} start={} end={} loop_time={} delay={} speed={} real={} state=[{}]",
171 subop, start_value, end_value, loop_time, delay_time, speed_type, real_flag, screen_event_state(ev)
172 );
173 }
174 ctx.stack.push(default_for_ret_form(ret_form));
175 }
176 int_event_op::TURN | int_event_op::TURN_REAL => {
177 let start_value = params.first().and_then(as_i64).unwrap_or(0) as i32;
178 let end_value = params.get(1).and_then(as_i64).unwrap_or(0) as i32;
179 let loop_time = params.get(2).and_then(as_i64).unwrap_or(0) as i32;
180 let delay_time = params.get(3).and_then(as_i64).unwrap_or(0) as i32;
181 let speed_type = params.get(4).and_then(as_i64).unwrap_or(0) as i32;
182 let real_flag = if subop == int_event_op::TURN_REAL {
183 1
184 } else {
185 0
186 };
187 ev.turn_event(
188 start_value,
189 end_value,
190 loop_time,
191 delay_time,
192 speed_type,
193 real_flag,
194 );
195 if anim_skip_trace_enabled() {
196 eprintln!(
197 "[SG_DEBUG][ANIM_SKIP_TRACE][SCREEN] INTEVENT.TURN subop={} start={} end={} loop_time={} delay={} speed={} real={} state=[{}]",
198 subop, start_value, end_value, loop_time, delay_time, speed_type, real_flag, screen_event_state(ev)
199 );
200 }
201 ctx.stack.push(default_for_ret_form(ret_form));
202 }
203 int_event_op::END => {
204 if anim_skip_trace_enabled() {
205 eprintln!(
206 "[SG_DEBUG][ANIM_SKIP_TRACE][SCREEN] INTEVENT.END before state=[{}]",
207 screen_event_state(ev)
208 );
209 }
210 ev.end_event();
211 if anim_skip_trace_enabled() {
212 eprintln!(
213 "[SG_DEBUG][ANIM_SKIP_TRACE][SCREEN] INTEVENT.END after state=[{}]",
214 screen_event_state(ev)
215 );
216 }
217 ctx.stack.push(default_for_ret_form(ret_form));
218 }
219 int_event_op::WAIT => {
220 if anim_skip_trace_enabled() {
221 eprintln!("[SG_DEBUG][ANIM_SKIP_TRACE][SCREEN] INTEVENT.WAIT requested NOTE=current implementation routes through generic form_id=0");
222 }
223 ctx.wait.wait_generic_int_event(0, None, false, false)
224 }
225 int_event_op::WAIT_KEY => {
226 if anim_skip_trace_enabled() {
227 eprintln!("[SG_DEBUG][ANIM_SKIP_TRACE][SCREEN] INTEVENT.WAIT_KEY requested NOTE=current implementation routes through generic form_id=0");
228 }
229 ctx.wait.wait_generic_int_event(0, None, true, true)
230 }
231 int_event_op::CHECK => ctx
232 .stack
233 .push(Value::Int(if ev.check_event() { 1 } else { 0 })),
234 _ => ctx.stack.push(default_for_ret_form(ret_form)),
235 }
236}
237
238fn screen_to_effect_prop(
239 ids: &crate::runtime::constants::RuntimeConstants,
240 selector: i32,
241) -> Option<i32> {
242 match selector {
243 s if ids.screen_x != 0 && s == ids.screen_x => Some(ids.effect_x),
244 s if ids.screen_y != 0 && s == ids.screen_y => Some(ids.effect_y),
245 s if ids.screen_z != 0 && s == ids.screen_z => Some(ids.effect_z),
246 s if ids.screen_mono != 0 && s == ids.screen_mono => Some(ids.effect_mono),
247 s if ids.screen_reverse != 0 && s == ids.screen_reverse => Some(ids.effect_reverse),
248 s if ids.screen_bright != 0 && s == ids.screen_bright => Some(ids.effect_bright),
249 s if ids.screen_dark != 0 && s == ids.screen_dark => Some(ids.effect_dark),
250 s if ids.screen_color_r != 0 && s == ids.screen_color_r => Some(ids.effect_color_r),
251 s if ids.screen_color_g != 0 && s == ids.screen_color_g => Some(ids.effect_color_g),
252 s if ids.screen_color_b != 0 && s == ids.screen_color_b => Some(ids.effect_color_b),
253 s if ids.screen_color_rate != 0 && s == ids.screen_color_rate => {
254 Some(ids.effect_color_rate)
255 }
256 s if ids.screen_color_add_r != 0 && s == ids.screen_color_add_r => {
257 Some(ids.effect_color_add_r)
258 }
259 s if ids.screen_color_add_g != 0 && s == ids.screen_color_add_g => {
260 Some(ids.effect_color_add_g)
261 }
262 s if ids.screen_color_add_b != 0 && s == ids.screen_color_add_b => {
263 Some(ids.effect_color_add_b)
264 }
265 _ => None,
266 }
267}
268
269fn screen_to_effect_event(
270 ids: &crate::runtime::constants::RuntimeConstants,
271 selector: i32,
272) -> Option<i32> {
273 match selector {
274 s if ids.screen_x_eve != 0 && s == ids.screen_x_eve => Some(ids.effect_x_eve),
275 s if ids.screen_y_eve != 0 && s == ids.screen_y_eve => Some(ids.effect_y_eve),
276 s if ids.screen_z_eve != 0 && s == ids.screen_z_eve => Some(ids.effect_z_eve),
277 s if ids.screen_mono_eve != 0 && s == ids.screen_mono_eve => Some(ids.effect_mono_eve),
278 s if ids.screen_reverse_eve != 0 && s == ids.screen_reverse_eve => {
279 Some(ids.effect_reverse_eve)
280 }
281 s if ids.screen_bright_eve != 0 && s == ids.screen_bright_eve => {
282 Some(ids.effect_bright_eve)
283 }
284 s if ids.screen_dark_eve != 0 && s == ids.screen_dark_eve => Some(ids.effect_dark_eve),
285 s if ids.screen_color_r_eve != 0 && s == ids.screen_color_r_eve => {
286 Some(ids.effect_color_r_eve)
287 }
288 s if ids.screen_color_g_eve != 0 && s == ids.screen_color_g_eve => {
289 Some(ids.effect_color_g_eve)
290 }
291 s if ids.screen_color_b_eve != 0 && s == ids.screen_color_b_eve => {
292 Some(ids.effect_color_b_eve)
293 }
294 s if ids.screen_color_rate_eve != 0 && s == ids.screen_color_rate_eve => {
295 Some(ids.effect_color_rate_eve)
296 }
297 s if ids.screen_color_add_r_eve != 0 && s == ids.screen_color_add_r_eve => {
298 Some(ids.effect_color_add_r_eve)
299 }
300 s if ids.screen_color_add_g_eve != 0 && s == ids.screen_color_add_g_eve => {
301 Some(ids.effect_color_add_g_eve)
302 }
303 s if ids.screen_color_add_b_eve != 0 && s == ids.screen_color_add_b_eve => {
304 Some(ids.effect_color_add_b_eve)
305 }
306 _ => None,
307 }
308}
309
310struct ScreenCall {
311 chain: Vec<i32>,
312 al_id: i32,
313 ret_form: i64,
314 rhs: Option<Value>,
315 script_args: Vec<Value>,
316}
317
318fn parse_screen_call(ctx: &CommandContext, args: &[Value]) -> Option<ScreenCall> {
319 let vm_call = ctx.vm_call.as_ref()?;
320 if vm_call.element.is_empty() {
321 return None;
322 }
323 let (al_id, ret_form) = prop_access::current_vm_meta(ctx);
324 let al_id = al_id.unwrap_or(-1) as i32;
325 let ret_form = ret_form.unwrap_or(0);
326 let rhs = if al_id == 1 {
327 args.first().cloned()
328 } else {
329 None
330 };
331 Some(ScreenCall {
332 chain: vm_call.element.clone(),
333 al_id,
334 ret_form,
335 rhs,
336 script_args: args.to_vec(),
337 })
338}
339
340fn last_list_arg(script_args: &[Value]) -> Option<&Vec<Value>> {
341 script_args.last().and_then(|v| match v.unwrap_named() {
342 Value::List(list) => Some(list),
343 _ => None,
344 })
345}
346
347fn quake_start_flags(op: i32) -> Option<(bool, bool, bool)> {
348 match op {
349 QUAKE_START_OP => Some((false, false, false)),
350 QUAKE_START_WAIT_OP => Some((false, true, false)),
351 QUAKE_START_WAIT_KEY_OP => Some((false, true, true)),
352 QUAKE_START_NOWAIT_OP => Some((false, false, false)),
353 QUAKE_START_ALL_OP => Some((true, false, false)),
354 QUAKE_START_ALL_WAIT_OP => Some((true, true, false)),
355 QUAKE_START_ALL_WAIT_KEY_OP => Some((true, true, true)),
356 QUAKE_START_ALL_NOWAIT_OP => Some((true, false, false)),
357 _ => None,
358 }
359}
360
361fn parse_quake_command(
362 item: &mut ScreenQuakeState,
363 op: i32,
364 script_args: &[Value],
365 ctx: &mut CommandContext,
366) -> bool {
367 if let Some((all_range, wait_flag, key_flag)) = quake_start_flags(op) {
368 let quake_type = script_args.first().and_then(as_i64).unwrap_or(0) as i32;
369 let time = script_args.get(1).and_then(as_i64).unwrap_or(1000);
370 let _cnt = script_args.get(2).and_then(as_i64).unwrap_or(0) as i32;
371 let _end_cnt = script_args.get(3).and_then(as_i64).unwrap_or(0) as i32;
372 item.begin_order = if all_range {
373 script_args
374 .get(4)
375 .and_then(as_i64)
376 .unwrap_or(i32::MIN as i64) as i32
377 } else {
378 script_args.get(4).and_then(as_i64).unwrap_or(0) as i32
379 };
380 item.end_order = if all_range {
381 script_args
382 .get(5)
383 .and_then(as_i64)
384 .unwrap_or(i32::MAX as i64) as i32
385 } else {
386 script_args.get(5).and_then(as_i64).unwrap_or(0) as i32
387 };
388
389 let opt = last_list_arg(script_args);
390 item.power = opt
391 .and_then(|list| list.first())
392 .and_then(as_i64)
393 .unwrap_or(0) as i32;
394 item.vec = opt
395 .and_then(|list| list.get(1))
396 .and_then(as_i64)
397 .unwrap_or(0) as i32;
398 item.center_x = opt
399 .and_then(|list| list.get(1))
400 .and_then(as_i64)
401 .unwrap_or(0) as i32;
402 item.center_y = opt
403 .and_then(|list| list.get(2))
404 .and_then(as_i64)
405 .unwrap_or(0) as i32;
406 item.start_kind(quake_type, time);
407 if wait_flag {
408 let rem = item.remaining_ms();
409 if key_flag {
410 ctx.wait.wait_ms_key(rem);
411 } else {
412 ctx.wait.wait_ms(rem);
413 }
414 }
415 ctx.stack.push(Value::Int(0));
416 return true;
417 }
418
419 match op {
420 QUAKE_END_OP => {
421 item.end_ms(script_args.first().and_then(as_i64).unwrap_or(0));
422 ctx.stack.push(Value::Int(0));
423 true
424 }
425 QUAKE_WAIT_OP => {
426 ctx.wait.wait_ms(item.remaining_ms());
427 ctx.stack.push(Value::Int(0));
428 true
429 }
430 QUAKE_WAIT_KEY_OP => {
431 ctx.wait.wait_ms_key(item.remaining_ms());
432 ctx.stack.push(Value::Int(0));
433 true
434 }
435 QUAKE_CHECK_OP => {
436 ctx.stack.push(Value::Int(item.check_value() as i64));
437 true
438 }
439 _ => false,
440 }
441}
442
443fn get_or_set_effect_scalar(
444 ctx: &mut CommandContext,
445 effect: &mut ScreenEffectState,
446 ids: &crate::runtime::constants::RuntimeConstants,
447 op: i32,
448 al_id: i32,
449 rhs: Option<&Value>,
450 ret_form: i64,
451) -> bool {
452 if let Some(ev) = effect_event_mut(ids, effect, op) {
453 match al_id {
454 0 => {
455 ctx.stack.push(Value::Int(ev.get_total_value() as i64));
456 true
457 }
458 1 => {
459 let value = rhs.and_then(as_i64).unwrap_or(0) as i32;
460 ev.set_value(value);
461 ev.frame();
462 ctx.stack.push(default_for_ret_form(ret_form));
463 true
464 }
465 _ => false,
466 }
467 } else if let Some(slot) = effect_prop_ref_mut(ids, effect, op) {
468 match al_id {
469 0 => {
470 ctx.stack.push(Value::Int(*slot as i64));
471 true
472 }
473 1 => {
474 *slot = rhs.and_then(as_i64).unwrap_or(0) as i32;
475 ctx.stack.push(default_for_ret_form(ret_form));
476 true
477 }
478 _ => false,
479 }
480 } else if let Some(value) = effect_prop_value(ids, effect, op) {
481 if al_id == 0 {
482 ctx.stack.push(Value::Int(value));
483 true
484 } else {
485 false
486 }
487 } else {
488 false
489 }
490}
491
492pub fn dispatch(ctx: &mut CommandContext, args: &[Value]) -> Result<bool> {
493 let Some(call) = parse_screen_call(ctx, args) else {
494 return Ok(false);
495 };
496 let chain = call.chain;
497 let form_id = chain[0] as u32;
498 let mut st = ctx
499 .globals
500 .screen_forms
501 .remove(&form_id)
502 .unwrap_or_default();
503 let result = (|| {
504 if chain.len() == 1 {
505 if call.ret_form != 0 {
506 ctx.stack.push(default_for_ret_form(call.ret_form));
507 }
508 return Ok(true);
509 }
510
511 let selector = chain[1];
512 let ids = ctx.ids.clone();
513
514 if selector == ids.screen_sel_effect {
515 if chain.len() == 3 {
516 match chain[2] {
517 EFFECTLIST_RESIZE_OP => {
518 st.ensure_effect_len(
519 args.first().and_then(as_i64).unwrap_or(0).max(0) as usize
520 );
521 ctx.stack.push(Value::Int(0));
522 return Ok(true);
523 }
524 EFFECTLIST_GET_SIZE_OP => {
525 ctx.stack.push(Value::Int(st.effect_list.len() as i64));
526 return Ok(true);
527 }
528 _ => return Ok(false),
529 }
530 }
531 if chain.len() < 4 || chain[2] != ids.elm_array {
532 return Ok(false);
533 }
534 let idx = chain[3].max(0) as usize;
535 st.ensure_effect_len(idx + 1);
536 let effect = &mut st.effect_list[idx];
537 if chain.len() == 4 {
538 if call.ret_form != 0 {
539 ctx.stack.push(default_for_ret_form(call.ret_form));
540 }
541 return Ok(true);
542 }
543 let op = chain[4];
544 if op == ids.effect_init && call.script_args.is_empty() && call.ret_form == 0 {
545 effect.reinit();
546 ctx.stack.push(Value::Int(0));
547 return Ok(true);
548 }
549 if chain.len() >= 6 {
550 if let Some(ev) = effect_event_mut(&ids, effect, op) {
551 run_int_event_command(ctx, ev, chain[5], &call.script_args, call.ret_form);
552 return Ok(true);
553 }
554 return Ok(false);
555 }
556 return Ok(get_or_set_effect_scalar(
557 ctx,
558 effect,
559 &ids,
560 op,
561 call.al_id,
562 call.rhs.as_ref(),
563 call.ret_form,
564 ));
565 }
566
567 if selector == ids.screen_sel_quake {
568 if chain.len() < 4 || chain[2] != ids.elm_array {
569 return Ok(false);
570 }
571 let idx = chain[3].max(0) as usize;
572 st.ensure_quake_len(idx + 1);
573 let quake = &mut st.quake_list[idx];
574 if chain.len() == 4 {
575 if call.ret_form != 0 {
576 ctx.stack.push(default_for_ret_form(call.ret_form));
577 }
578 return Ok(true);
579 }
580 return Ok(parse_quake_command(quake, chain[4], &call.script_args, ctx));
581 }
582
583 if selector == ids.screen_sel_shake {
584 if !call.script_args.is_empty() {
585 st.shake.set_ms(call.script_args[0].as_i64().unwrap_or(0));
586 ctx.stack.push(Value::Int(0));
587 return Ok(true);
588 }
589 return Ok(false);
590 }
591
592 if let Some(effect_op) = screen_to_effect_prop(&ids, selector) {
593 st.ensure_effect_len(1);
594 let effect = &mut st.effect_list[0];
595 return Ok(get_or_set_effect_scalar(
596 ctx,
597 effect,
598 &ids,
599 effect_op,
600 call.al_id,
601 call.rhs.as_ref(),
602 call.ret_form,
603 ));
604 }
605
606 if let Some(effect_event_op) = screen_to_effect_event(&ids, selector) {
607 if chain.len() != 3 {
608 return Ok(false);
609 }
610 st.ensure_effect_len(1);
611 let effect = &mut st.effect_list[0];
612 if let Some(ev) = effect_event_mut(&ids, effect, effect_event_op) {
613 run_int_event_command(ctx, ev, chain[2], &call.script_args, call.ret_form);
614 return Ok(true);
615 }
616 return Ok(false);
617 }
618
619 Ok(false)
620 })();
621 ctx.globals.screen_forms.insert(form_id, st);
622 result
623}