Skip to main content

siglus_scene_vm/runtime/forms/
bgm.rs

1use anyhow::{bail, Result};
2
3use crate::runtime::{CommandContext, Value};
4
5use super::codes::bgm_op;
6
7fn store_or_push_bgm_prop(ctx: &mut CommandContext, op: i32, args: &[Value]) {
8    let form_key = if ctx.ids.form_global_bgm != 0 {
9        ctx.ids.form_global_bgm
10    } else {
11        super::codes::FORM_GLOBAL_BGM
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
62fn named_str<'a>(args: &'a [Value], id: i32) -> Option<&'a str> {
63    args.iter().find_map(|v| match v {
64        Value::NamedArg { id: nid, value } if *nid == id => value.as_str(),
65        _ => None,
66    })
67}
68
69fn named_int(args: &[Value], id: i32) -> Option<i64> {
70    args.iter().find_map(|v| match v {
71        Value::NamedArg { id: nid, value } if *nid == id => value.as_i64(),
72        _ => None,
73    })
74}
75
76pub fn dispatch(ctx: &mut CommandContext, args: &[Value]) -> Result<bool> {
77    let ret_form = crate::runtime::forms::prop_access::current_vm_meta(ctx).1;
78    let Some(op) = crate::runtime::forms::prop_access::current_op_from_ctx_or_args(ctx, args)
79    else {
80        bail!("BGM form expects an element opcode");
81    };
82    let args = crate::runtime::forms::prop_access::params_without_op(ctx, args);
83
84    let play_name = || named_str(args, 0).or_else(|| arg_str(args, 0));
85
86    match op {
87        bgm_op::PLAY
88        | bgm_op::PLAY_WAIT
89        | bgm_op::READY
90        | bgm_op::PLAY_ONESHOT
91        | bgm_op::READY_ONESHOT => {
92            let name = match play_name() {
93                Some(s) => s,
94                None => {
95                    store_or_push_bgm_prop(ctx, op, args);
96                    return Ok(true);
97                }
98            };
99
100            let mut loop_flag = true;
101            let mut wait_flag = false;
102            let mut fade_in_time = 0i64;
103            let mut fade_out_time = 0i64;
104            let mut start_pos_sample = -1i64;
105            let mut ready_only = false;
106
107            match op {
108                bgm_op::PLAY => {
109                    fade_in_time = arg_int(args, 1).unwrap_or(0);
110                    fade_out_time = arg_int(args, 2).unwrap_or(0);
111                }
112                bgm_op::PLAY_ONESHOT => {
113                    loop_flag = false;
114                    fade_in_time = arg_int(args, 1).unwrap_or(0);
115                    fade_out_time = arg_int(args, 2).unwrap_or(0);
116                }
117                bgm_op::PLAY_WAIT => {
118                    loop_flag = false;
119                    wait_flag = true;
120                    fade_in_time = arg_int(args, 1).unwrap_or(0);
121                    fade_out_time = arg_int(args, 2).unwrap_or(0);
122                }
123                bgm_op::READY => {
124                    ready_only = true;
125                    fade_out_time = arg_int(args, 1).unwrap_or(100);
126                }
127                bgm_op::READY_ONESHOT => {
128                    loop_flag = false;
129                    ready_only = true;
130                    fade_in_time = arg_int(args, 1).unwrap_or(0);
131                    fade_out_time = arg_int(args, 2).unwrap_or(0);
132                }
133                _ => {}
134            }
135
136            if let Some(v) = named_int(args, 1) {
137                loop_flag = v != 0;
138            }
139            if let Some(v) = named_int(args, 2) {
140                wait_flag = v != 0;
141            }
142            if let Some(v) = named_int(args, 3) {
143                start_pos_sample = v;
144            }
145            if let Some(v) = named_int(args, 4) {
146                fade_in_time = v;
147            }
148            if let Some(v) = named_int(args, 5) {
149                fade_out_time = v;
150            }
151
152            if wait_flag {
153                loop_flag = false;
154            }
155
156            let (bgm, audio) = (&mut ctx.bgm, &mut ctx.audio);
157            bgm.play_name_script(
158                audio,
159                name,
160                loop_flag,
161                fade_in_time,
162                fade_out_time,
163                start_pos_sample,
164                ready_only,
165                0,
166            )?;
167            if let Some(cur) = ctx.bgm.current_name().map(|s| s.to_string()) {
168                let _ = super::bgm_table::mark_listened_by_name(ctx, &cur, true);
169            }
170            if wait_flag {
171                ctx.wait
172                    .wait_audio(crate::runtime::wait::AudioWait::Bgm, false);
173            }
174            Ok(true)
175        }
176        bgm_op::STOP => {
177            let fade_time = arg_int(args, 0).unwrap_or(100);
178            ctx.bgm.stop_fade(fade_time)?;
179            Ok(true)
180        }
181        bgm_op::PAUSE => {
182            let fade_time = arg_int(args, 0).unwrap_or(100);
183            let (bgm, audio) = (&mut ctx.bgm, &mut ctx.audio);
184            bgm.pause_fade(audio, fade_time)?;
185            Ok(true)
186        }
187        bgm_op::RESUME | bgm_op::RESUME_WAIT => {
188            let fade_time = arg_int(args, 0).unwrap_or(0);
189            let delay_time = if op == bgm_op::RESUME {
190                named_int(args, 0).unwrap_or(0)
191            } else {
192                0
193            };
194            let (bgm, audio) = (&mut ctx.bgm, &mut ctx.audio);
195            bgm.resume_script(audio, fade_time, delay_time)?;
196            if op == bgm_op::RESUME_WAIT {
197                ctx.wait
198                    .wait_audio(crate::runtime::wait::AudioWait::Bgm, false);
199            }
200            Ok(true)
201        }
202        bgm_op::WAIT | bgm_op::WAIT_KEY => {
203            ctx.wait.wait_audio_with_return(
204                crate::runtime::wait::AudioWait::Bgm,
205                op == bgm_op::WAIT_KEY,
206                ret_form.unwrap_or(0) != 0,
207            );
208            Ok(true)
209        }
210        bgm_op::WAIT_FADE | bgm_op::WAIT_FADE_KEY => {
211            ctx.wait.wait_audio_with_return(
212                crate::runtime::wait::AudioWait::BgmFade,
213                op == bgm_op::WAIT_FADE_KEY,
214                ret_form.unwrap_or(0) != 0,
215            );
216            Ok(true)
217        }
218        bgm_op::SET_VOLUME => {
219            let vol_raw = match arg_int(args, 0) {
220                Some(v) => v.clamp(0, 255) as u8,
221                None => {
222                    store_or_push_bgm_prop(ctx, op, args);
223                    return Ok(true);
224                }
225            };
226            let fade_time = arg_int(args, 0).unwrap_or(0);
227            let (bgm, audio) = (&mut ctx.bgm, &mut ctx.audio);
228            bgm.set_volume_raw_fade(audio, vol_raw, fade_time)?;
229            Ok(true)
230        }
231        bgm_op::SET_VOLUME_MAX => {
232            let fade_time = arg_int(args, 0).unwrap_or(0);
233            let (bgm, audio) = (&mut ctx.bgm, &mut ctx.audio);
234            bgm.set_volume_raw_fade(audio, 255, fade_time)?;
235            Ok(true)
236        }
237        bgm_op::SET_VOLUME_MIN => {
238            let fade_time = arg_int(args, 0).unwrap_or(0);
239            let (bgm, audio) = (&mut ctx.bgm, &mut ctx.audio);
240            bgm.set_volume_raw_fade(audio, 0, fade_time)?;
241            Ok(true)
242        }
243        bgm_op::GET_VOLUME => {
244            ctx.push(Value::Int(ctx.bgm.volume_raw() as i64));
245            Ok(true)
246        }
247        bgm_op::GET_REGIST_NAME => {
248            ctx.push(Value::Str(ctx.bgm.current_name().unwrap_or("").to_string()));
249            Ok(true)
250        }
251        bgm_op::CHECK => {
252            ctx.push(Value::Int(ctx.bgm.check_state() as i64));
253            Ok(true)
254        }
255        bgm_op::GET_PLAY_POS => {
256            ctx.push(Value::Int(ctx.bgm.play_pos_samples() as i64));
257            Ok(true)
258        }
259        _ => {
260            store_or_push_bgm_prop(ctx, op, args);
261            Ok(true)
262        }
263    }
264}