siglus_scene_vm/runtime/forms/
mov.rs1use anyhow::{bail, Result};
2
3use crate::runtime::{CommandContext, ProcKind, Value};
4
5use super::codes::mov_op;
6
7fn store_or_push_mov_prop(ctx: &mut CommandContext, op: i32, args: &[Value]) {
8 let form_key = if ctx.ids.form_global_mov != 0 {
9 ctx.ids.form_global_mov
10 } else {
11 super::codes::FORM_GLOBAL_MOV
12 };
13 let prop = op;
14 if let Some(v) = args.get(0).cloned() {
15 match v {
16 Value::Str(s) => {
17 ctx.globals
18 .str_props
19 .entry(form_key)
20 .or_default()
21 .insert(prop, s);
22 }
23 Value::Int(n) => {
24 ctx.globals
25 .int_props
26 .entry(form_key)
27 .or_default()
28 .insert(prop, n);
29 }
30 _ => {}
31 }
32 ctx.push(Value::Int(0));
33 return;
34 }
35 if let Some(s) = ctx
36 .globals
37 .str_props
38 .get(&form_key)
39 .and_then(|m| m.get(&prop))
40 .cloned()
41 {
42 ctx.push(Value::Str(s));
43 return;
44 }
45 let v = ctx
46 .globals
47 .int_props
48 .get(&form_key)
49 .and_then(|m| m.get(&prop).copied())
50 .unwrap_or(0);
51 ctx.push(Value::Int(v));
52}
53
54fn arg_str<'a>(args: &'a [Value], idx: usize) -> Option<&'a str> {
55 args.get(idx).and_then(|v| v.as_str())
56}
57
58fn arg_int(args: &[Value], idx: usize) -> Option<i64> {
59 args.get(idx).and_then(|v| v.as_i64())
60}
61
62pub fn dispatch(ctx: &mut CommandContext, args: &[Value]) -> Result<bool> {
63 let Some(op) = crate::runtime::forms::prop_access::current_op_from_ctx_or_args(ctx, args)
64 else {
65 bail!("MOV form expects an element opcode");
66 };
67 let args = crate::runtime::forms::prop_access::params_without_op(ctx, args);
68
69 match op {
70 mov_op::PLAY | mov_op::PLAY_WAIT | mov_op::PLAY_WAIT_KEY => {
71 let name = match arg_str(args, 0) {
72 Some(s) => s,
73 None => {
74 store_or_push_mov_prop(ctx, op, args);
75 return Ok(true);
76 }
77 };
78 let x = arg_int(args, 1).unwrap_or(0) as i32;
79 let y = arg_int(args, 2).unwrap_or(0) as i32;
80 let raw_w = arg_int(args, 3).unwrap_or(ctx.screen_w as i64);
81 let raw_h = arg_int(args, 4).unwrap_or(ctx.screen_h as i64);
82 let w = if raw_w <= 0 {
83 ctx.screen_w.max(1)
84 } else {
85 raw_w as u32
86 };
87 let h = if raw_h <= 0 {
88 ctx.screen_h.max(1)
89 } else {
90 raw_h as u32
91 };
92
93 let wait = op == mov_op::PLAY_WAIT || op == mov_op::PLAY_WAIT_KEY;
94 let key_skip = op == mov_op::PLAY_WAIT_KEY;
95 if let Some(id) = ctx.globals.mov.audio_id.take() {
96 ctx.movie.stop_audio(id);
97 }
98 ctx.movie.stop();
99 let info = ctx.movie.play(name, wait, key_skip)?;
100 ctx.globals
106 .mov
107 .start(name.to_string(), x, y, w, h, None, key_skip);
108 if std::env::var_os("SG_DEBUG").is_some()
109 || std::env::var_os("SG_MOVIE_TRACE").is_some()
110 {
111 eprintln!(
112 "[SG_DEBUG][MOV] PLAY file={} pos=({}, {}) size={}x{} wait={} key_skip={} total_ms={:?} path={}",
113 name, x, y, w, h, wait, key_skip, info.duration_ms(), info.path.display()
114 );
115 }
116 if wait {
117 let ret_form = crate::runtime::forms::prop_access::current_vm_meta(ctx)
118 .1
119 .unwrap_or(0);
120 let return_value_flag = ret_form != super::codes::FM_VOID as i64;
121 ctx.wait.wait_global_movie(key_skip, return_value_flag);
122 ctx.request_wait_proc_boundary(ProcKind::MovieWait);
123 }
124 Ok(true)
125 }
126 mov_op::STOP => {
127 if let Some(id) = ctx.globals.mov.audio_id.take() {
128 ctx.movie.stop_audio(id);
129 }
130 ctx.globals.mov.stop();
131 ctx.movie.stop();
132 Ok(true)
133 }
134 _ => {
135 store_or_push_mov_prop(ctx, op, args);
136 Ok(true)
137 }
138 }
139}