Skip to main content

siglus_scene_vm/runtime/forms/
frame_action.rs

1use 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}