siglus_scene_vm/runtime/forms/
frame_action.rs1use anyhow::Result;
2
3use crate::runtime::forms::prop_access;
4use crate::runtime::globals::{ObjectFrameActionState, PendingFrameActionFinish};
5use crate::runtime::{CommandContext, Value};
6
7fn as_i64(v: &Value) -> Option<i64> {
8 match v {
9 Value::Int(n) => Some(*n),
10 Value::NamedArg { value, .. } => as_i64(value),
11 _ => None,
12 }
13}
14
15fn push_ok(ctx: &mut CommandContext, ret_form: Option<i64>) {
16 let v = if matches!(ret_form, Some(rf) if rf == prop_access::FM_STR) {
17 Value::Str(String::new())
18 } else {
19 Value::Int(0)
20 };
21 ctx.push(v);
22}
23
24fn queue_finish(
25 ctx: &mut CommandContext,
26 fa: &ObjectFrameActionState,
27 frame_action_chain: Vec<i32>,
28) {
29 if fa.cmd_name.is_empty() {
30 return;
31 }
32 ctx.globals
33 .pending_frame_action_finishes
34 .push(PendingFrameActionFinish {
35 frame_action_chain,
36 object_chain: None,
37 scn_name: fa.scn_name.clone(),
38 cmd_name: fa.cmd_name.clone(),
39 end_time: fa.end_time,
40 args: fa.args.clone(),
41 });
42}
43
44fn apply_set_from_parts(
45 fa: &mut ObjectFrameActionState,
46 scene_name: &str,
47 end_time: i64,
48 cmd_name: String,
49 args: Vec<Value>,
50 real_time_flag: bool,
51) {
52 fa.end_time = end_time;
53 fa.cmd_name = cmd_name;
54 fa.scn_name = scene_name.to_string();
55 fa.real_time_flag = real_time_flag;
56 fa.end_flag = false;
57 fa.counter.reset();
58 if real_time_flag {
59 fa.counter.start_real();
60 } else {
61 fa.counter.start();
62 }
63 fa.args = args;
64}
65
66pub fn dispatch(ctx: &mut CommandContext, form_id: u32, args: &[Value]) -> Result<bool> {
67 let Some((chain_pos, chain_ref)) = prop_access::parse_current_element_chain(ctx, args) else {
68 return Ok(false);
69 };
70 let chain: Vec<i32> = chain_ref.to_vec();
71 let tail: Vec<i32> = chain[1..].to_vec();
72 let script_args: Vec<Value> = prop_access::script_args(args, chain_pos).to_vec();
73 let scene_name = ctx.current_scene_name.clone().unwrap_or_default();
74 let (al_id, ret_form) = prop_access::current_vm_meta(ctx);
75 let rhs = if al_id == Some(1) {
76 script_args.first().cloned()
77 } else {
78 None
79 };
80
81 if tail.is_empty() {
82 push_ok(ctx, ret_form);
83 return Ok(true);
84 }
85
86 match tail[0] {
87 crate::runtime::constants::elm_value::FRAMEACTION_COUNTER => {
88 let counter_tail = &tail[1..];
89 if counter_tail.is_empty() {
90 let set_v = rhs.as_ref().and_then(as_i64).or_else(|| {
91 if al_id == Some(1) && script_args.len() == 1 {
92 script_args.first().and_then(as_i64)
93 } else {
94 None
95 }
96 });
97 if let Some(v) = set_v {
98 {
99 let fa = ctx.globals.frame_actions.entry(form_id).or_default();
100 fa.counter.set_count(v);
101 }
102 push_ok(ctx, ret_form);
103 } else {
104 let count = {
105 let fa = ctx.globals.frame_actions.entry(form_id).or_default();
106 fa.counter.get_count()
107 };
108 ctx.push(Value::Int(count));
109 }
110 return Ok(true);
111 }
112
113 match counter_tail[0] {
114 crate::runtime::constants::COUNTER_SET => {
115 let value = script_args.get(0).and_then(as_i64).unwrap_or(0);
116 {
117 let fa = ctx.globals.frame_actions.entry(form_id).or_default();
118 fa.counter.set_count(value);
119 }
120 push_ok(ctx, ret_form);
121 }
122 crate::runtime::constants::COUNTER_GET => {
123 let count = {
124 let fa = ctx.globals.frame_actions.entry(form_id).or_default();
125 fa.counter.get_count()
126 };
127 ctx.push(Value::Int(count));
128 }
129 crate::runtime::constants::COUNTER_RESET => {
130 {
131 let fa = ctx.globals.frame_actions.entry(form_id).or_default();
132 fa.counter.reset();
133 }
134 push_ok(ctx, ret_form);
135 }
136 crate::runtime::constants::COUNTER_START => {
137 {
138 let fa = ctx.globals.frame_actions.entry(form_id).or_default();
139 fa.counter.start();
140 }
141 push_ok(ctx, ret_form);
142 }
143 crate::runtime::constants::COUNTER_START_REAL => {
144 {
145 let fa = ctx.globals.frame_actions.entry(form_id).or_default();
146 fa.counter.start_real();
147 }
148 push_ok(ctx, ret_form);
149 }
150 crate::runtime::constants::COUNTER_START_FRAME => {
151 let from = script_args.get(0).and_then(as_i64).unwrap_or(0);
152 let to = script_args.get(1).and_then(as_i64).unwrap_or(0);
153 let frame_time = script_args.get(2).and_then(as_i64).unwrap_or(0);
154 {
155 let fa = ctx.globals.frame_actions.entry(form_id).or_default();
156 fa.counter.start_frame(from, to, frame_time);
157 }
158 push_ok(ctx, ret_form);
159 }
160 crate::runtime::constants::COUNTER_START_FRAME_REAL => {
161 let from = script_args.get(0).and_then(as_i64).unwrap_or(0);
162 let to = script_args.get(1).and_then(as_i64).unwrap_or(0);
163 let frame_time = script_args.get(2).and_then(as_i64).unwrap_or(0);
164 {
165 let fa = ctx.globals.frame_actions.entry(form_id).or_default();
166 fa.counter.start_frame_real(from, to, frame_time);
167 }
168 push_ok(ctx, ret_form);
169 }
170 crate::runtime::constants::COUNTER_START_FRAME_LOOP => {
171 let from = script_args.get(0).and_then(as_i64).unwrap_or(0);
172 let to = script_args.get(1).and_then(as_i64).unwrap_or(0);
173 let frame_time = script_args.get(2).and_then(as_i64).unwrap_or(0);
174 {
175 let fa = ctx.globals.frame_actions.entry(form_id).or_default();
176 fa.counter.start_frame_loop(from, to, frame_time);
177 }
178 push_ok(ctx, ret_form);
179 }
180 crate::runtime::constants::COUNTER_START_FRAME_LOOP_REAL => {
181 let from = script_args.get(0).and_then(as_i64).unwrap_or(0);
182 let to = script_args.get(1).and_then(as_i64).unwrap_or(0);
183 let frame_time = script_args.get(2).and_then(as_i64).unwrap_or(0);
184 {
185 let fa = ctx.globals.frame_actions.entry(form_id).or_default();
186 fa.counter.start_frame_loop_real(from, to, frame_time);
187 }
188 push_ok(ctx, ret_form);
189 }
190 crate::runtime::constants::COUNTER_STOP => {
191 {
192 let fa = ctx.globals.frame_actions.entry(form_id).or_default();
193 fa.counter.stop();
194 }
195 push_ok(ctx, ret_form);
196 }
197 crate::runtime::constants::COUNTER_RESUME => {
198 {
199 let fa = ctx.globals.frame_actions.entry(form_id).or_default();
200 fa.counter.resume();
201 }
202 push_ok(ctx, ret_form);
203 }
204 crate::runtime::constants::COUNTER_CHECK_VALUE => {
205 let target = script_args.get(0).and_then(as_i64).unwrap_or(0);
206 let count = {
207 let fa = ctx.globals.frame_actions.entry(form_id).or_default();
208 fa.counter.get_count()
209 };
210 ctx.push(Value::Int(if count - target >= 0 { 1 } else { 0 }));
211 }
212 crate::runtime::constants::COUNTER_CHECK_ACTIVE => {
213 let active = {
214 let fa = ctx.globals.frame_actions.entry(form_id).or_default();
215 fa.counter.is_running()
216 };
217 ctx.push(Value::Int(if active { 1 } else { 0 }));
218 }
219 crate::runtime::constants::COUNTER_WAIT
220 | crate::runtime::constants::COUNTER_WAIT_KEY => return Ok(false),
221 _ => return Ok(false),
222 }
223 Ok(true)
224 }
225 crate::runtime::constants::elm_value::FRAMEACTION_START => {
226 let end_time = script_args.first().and_then(as_i64).unwrap_or(0);
227 let cmd_name = script_args
228 .get(1)
229 .and_then(|v| v.as_str())
230 .unwrap_or("")
231 .to_string();
232 let fa_args = script_args.iter().skip(2).cloned().collect();
233 {
234 let fa_snapshot = ctx
235 .globals
236 .frame_actions
237 .entry(form_id)
238 .or_default()
239 .clone();
240 queue_finish(ctx, &fa_snapshot, chain.clone());
241 let fa = ctx.globals.frame_actions.entry(form_id).or_default();
242 apply_set_from_parts(fa, &scene_name, end_time, cmd_name, fa_args, false);
243 }
244 push_ok(ctx, ret_form);
245 Ok(true)
246 }
247 crate::runtime::constants::elm_value::FRAMEACTION_END => {
248 let fa_snapshot = ctx
249 .globals
250 .frame_actions
251 .entry(form_id)
252 .or_default()
253 .clone();
254 queue_finish(ctx, &fa_snapshot, chain.clone());
255 let fa = ctx.globals.frame_actions.entry(form_id).or_default();
256 *fa = ObjectFrameActionState::default();
257 push_ok(ctx, ret_form);
258 Ok(true)
259 }
260 crate::runtime::constants::elm_value::FRAMEACTION_START_REAL => {
261 let end_time = script_args.first().and_then(as_i64).unwrap_or(0);
262 let cmd_name = script_args
263 .get(1)
264 .and_then(|v| v.as_str())
265 .unwrap_or("")
266 .to_string();
267 let fa_args = script_args.iter().skip(2).cloned().collect();
268 {
269 let fa_snapshot = ctx
270 .globals
271 .frame_actions
272 .entry(form_id)
273 .or_default()
274 .clone();
275 queue_finish(ctx, &fa_snapshot, chain.clone());
276 let fa = ctx.globals.frame_actions.entry(form_id).or_default();
277 apply_set_from_parts(fa, &scene_name, end_time, cmd_name, fa_args, true);
278 }
279 push_ok(ctx, ret_form);
280 Ok(true)
281 }
282 crate::runtime::constants::elm_value::FRAMEACTION_IS_END_ACTION => {
283 let end_flag = ctx
284 .globals
285 .frame_actions
286 .entry(form_id)
287 .or_default()
288 .end_flag;
289 ctx.push(Value::Int(if end_flag { 1 } else { 0 }));
290 Ok(true)
291 }
292 _ => Ok(false),
293 }
294}