siglus_scene_vm/runtime/forms/
int_event.rs1use anyhow::{bail, Result};
2
3use crate::runtime::forms::codes::{int_event_list_op, int_event_op};
4use crate::runtime::int_event::IntEvent;
5use crate::runtime::{CommandContext, Value};
6
7use super::prop_access;
8
9fn default_for_ret_form(ret_form: i64) -> Value {
10 if prop_access::ret_form_is_string(ret_form) {
11 Value::Str(String::new())
12 } else {
13 Value::Int(0)
14 }
15}
16
17fn parse_chain<'a>(
18 ctx: &'a CommandContext,
19 form_id: u32,
20 args: &'a [Value],
21) -> Option<(usize, &'a [i32])> {
22 prop_access::parse_element_chain_ctx(ctx, form_id, args)
23}
24
25fn collect_params<'a>(chain_pos: usize, args: &'a [Value]) -> &'a [Value] {
26 prop_access::script_args(args, chain_pos)
27}
28
29enum PostAction {
30 Push(Value),
31 Wait {
32 index: Option<usize>,
33 key_skip: bool,
34 },
35}
36
37fn apply_named_init(ev: &mut IntEvent, args: &[Value], chain_pos: usize) {
38 let start = (chain_pos + 3).min(args.len());
39 for arg in &args[start..] {
40 if let Value::NamedArg { id: 0, value } = arg {
41 if let Some(v) = value.as_i64() {
42 *ev = IntEvent::new(v as i32);
43 }
44 }
45 }
46}
47
48fn run_event_op(
49 ev: &mut IntEvent,
50 op: i32,
51 params: &[Value],
52 ret_form: Option<i64>,
53 args: &[Value],
54 chain_pos: usize,
55 index: Option<usize>,
56) -> Result<PostAction> {
57 let post = match op {
58 int_event_op::SET | int_event_op::SET_REAL => {
59 apply_named_init(ev, args, chain_pos);
60 let value = params.first().and_then(|v| v.as_i64()).unwrap_or(0) as i32;
61 let total_time = params.get(1).and_then(|v| v.as_i64()).unwrap_or(0) as i32;
62 let delay_time = params.get(2).and_then(|v| v.as_i64()).unwrap_or(0) as i32;
63 let speed_type = params.get(3).and_then(|v| v.as_i64()).unwrap_or(0) as i32;
64 let real_flag = if op == int_event_op::SET_REAL { 1 } else { 0 };
65 ev.set_event(value, total_time, delay_time, speed_type, real_flag);
66 PostAction::Push(default_for_ret_form(ret_form.unwrap_or(0)))
67 }
68 int_event_op::LOOP | int_event_op::LOOP_REAL => {
69 let start_value = params.first().and_then(|v| v.as_i64()).unwrap_or(0) as i32;
70 let end_value = params.get(1).and_then(|v| v.as_i64()).unwrap_or(0) as i32;
71 let loop_time = params.get(2).and_then(|v| v.as_i64()).unwrap_or(0) as i32;
72 let delay_time = params.get(3).and_then(|v| v.as_i64()).unwrap_or(0) as i32;
73 let speed_type = params.get(4).and_then(|v| v.as_i64()).unwrap_or(0) as i32;
74 let real_flag = if op == int_event_op::LOOP_REAL { 1 } else { 0 };
75 ev.loop_event(
76 start_value,
77 end_value,
78 loop_time,
79 delay_time,
80 speed_type,
81 real_flag,
82 );
83 PostAction::Push(default_for_ret_form(ret_form.unwrap_or(0)))
84 }
85 int_event_op::TURN | int_event_op::TURN_REAL => {
86 let start_value = params.first().and_then(|v| v.as_i64()).unwrap_or(0) as i32;
87 let end_value = params.get(1).and_then(|v| v.as_i64()).unwrap_or(0) as i32;
88 let loop_time = params.get(2).and_then(|v| v.as_i64()).unwrap_or(0) as i32;
89 let delay_time = params.get(3).and_then(|v| v.as_i64()).unwrap_or(0) as i32;
90 let speed_type = params.get(4).and_then(|v| v.as_i64()).unwrap_or(0) as i32;
91 let real_flag = if op == int_event_op::TURN_REAL { 1 } else { 0 };
92 ev.turn_event(
93 start_value,
94 end_value,
95 loop_time,
96 delay_time,
97 speed_type,
98 real_flag,
99 );
100 PostAction::Push(default_for_ret_form(ret_form.unwrap_or(0)))
101 }
102 int_event_op::END => {
103 ev.end_event();
104 PostAction::Push(default_for_ret_form(ret_form.unwrap_or(0)))
105 }
106 int_event_op::WAIT => PostAction::Wait {
107 index,
108 key_skip: false,
109 },
110 int_event_op::WAIT_KEY => PostAction::Wait {
111 index,
112 key_skip: true,
113 },
114 int_event_op::CHECK => PostAction::Push(Value::Int(if ev.check_event() { 1 } else { 0 })),
115 _ => bail!("unsupported INTEVENT op {}", op),
116 };
117 Ok(post)
118}
119
120pub fn dispatch(ctx: &mut CommandContext, form_id: u32, args: &[Value]) -> Result<bool> {
121 let Some((chain_pos, chain)) = parse_chain(ctx, form_id, args) else {
122 return Ok(false);
123 };
124
125 let params = collect_params(chain_pos, args);
126 let (_al_id, ret_form, rhs) =
127 super::prop_access::infer_assign_and_ret_ctx(ctx, chain_pos, args);
128
129 let post = if form_id as i32 == crate::runtime::forms::codes::FM_INTEVENTLIST {
130 if chain.len() >= 4
131 && (chain[1] == ctx.ids.elm_array
132 || chain[1] == crate::runtime::forms::codes::ELM_ARRAY)
133 {
134 let idx = chain[2].max(0) as usize;
135 let op = chain[3];
136 let list = ctx
137 .globals
138 .int_event_lists
139 .entry(form_id)
140 .or_insert_with(Vec::new);
141 if list.len() <= idx {
142 list.resize_with(idx + 1, || IntEvent::new(0));
143 }
144 let ev = &mut list[idx];
145 run_event_op(ev, op, params, ret_form, args, chain_pos, Some(idx))?
146 } else if chain.len() >= 2 && chain[1] == int_event_list_op::RESIZE {
147 let n = params.first().and_then(|v| v.as_i64()).unwrap_or(0).max(0) as usize;
148 let list = ctx
149 .globals
150 .int_event_lists
151 .entry(form_id)
152 .or_insert_with(Vec::new);
153 list.resize_with(n, || IntEvent::new(0));
154 PostAction::Push(default_for_ret_form(ret_form.unwrap_or(0)))
155 } else {
156 bail!("unsupported INTEVENTLIST op chain {:?}", chain)
157 }
158 } else {
159 let op = chain.get(1).copied().unwrap_or(0);
160 let ev = ctx
161 .globals
162 .int_event_roots
163 .entry(form_id)
164 .or_insert_with(|| IntEvent::new(0));
165 if let Some(Value::Int(v)) = rhs {
166 *ev = IntEvent::new(v as i32);
167 PostAction::Push(default_for_ret_form(ret_form.unwrap_or(0)))
168 } else {
169 run_event_op(ev, op, params, ret_form, args, chain_pos, None)?
170 }
171 };
172
173 match post {
174 PostAction::Push(v) => ctx.push(v),
175 PostAction::Wait { index, key_skip } => ctx
176 .wait
177 .wait_generic_int_event(form_id, index, key_skip, key_skip),
178 }
179 Ok(true)
180}