siglus_scene_vm/runtime/forms/
bgm.rs1use 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}