Skip to main content

siglus_scene_vm/runtime/commands/
bg.rs

1use anyhow::Result;
2
3use crate::runtime::commands::util::strip_vm_meta;
4use crate::runtime::{Command, CommandContext, Value};
5
6fn arg_as_str(args: &[Value], idx: usize) -> Option<&str> {
7    match args.get(idx) {
8        Some(Value::Str(s)) => Some(s.as_str()),
9        _ => None,
10    }
11}
12
13fn last_i64(args: &[Value]) -> Option<i64> {
14    args.iter().rev().find_map(|v| match v {
15        Value::Int(i) => Some(*i),
16        _ => None,
17    })
18}
19
20fn collect_i64(args: &[Value]) -> Vec<i64> {
21    args.iter()
22        .filter_map(|v| match v {
23            Value::Int(i) => Some(*i),
24            _ => None,
25        })
26        .collect()
27}
28
29pub fn handle(ctx: &mut CommandContext, cmd: &Command) -> Result<bool> {
30    let name = cmd.name.to_ascii_uppercase();
31
32    if name == "BG" {
33        let args = strip_vm_meta(&cmd.args);
34        let bg_name = match arg_as_str(args, 0) {
35            Some(s) => s,
36            None => return Ok(false),
37        };
38        let frame_idx = args
39            .get(1)
40            .and_then(|v| v.as_i64())
41            .and_then(|x| usize::try_from(x).ok())
42            .unwrap_or(0);
43        let (gfx, images, layers) = (&mut ctx.gfx, &mut ctx.images, &mut ctx.layers);
44        gfx.object_create(images, layers, 0, 0, bg_name, 1, 0, 0, frame_idx as i64)?;
45        return Ok(true);
46    }
47
48    if matches!(name.as_str(), "BG_CLEAR" | "BG_OFF" | "BGCLEAR") {
49        // Clear both the gfx object and the dedicated bg sprite.
50        {
51            let (gfx, images, layers) = (&mut ctx.gfx, &mut ctx.images, &mut ctx.layers);
52            let _ = gfx.object_clear(images, layers, 0, 0);
53        }
54        ctx.layers.clear_bg();
55        return Ok(true);
56    }
57
58    if matches!(name.as_str(), "BG_ALPHA" | "BGALPHA" | "BG_A") {
59        let args = strip_vm_meta(&cmd.args);
60        let alpha_i = match last_i64(args) {
61            Some(v) => v,
62            None => return Ok(false),
63        };
64        let alpha = alpha_i.clamp(0, 255);
65        let (gfx, images, layers) = (&mut ctx.gfx, &mut ctx.images, &mut ctx.layers);
66        gfx.object_set_alpha(images, layers, 0, 0, alpha)?;
67        return Ok(true);
68    }
69
70    if matches!(name.as_str(), "BG_X" | "BGX") {
71        let args = strip_vm_meta(&cmd.args);
72        if let Some(x) = last_i64(args) {
73            let (gfx, images, layers) = (&mut ctx.gfx, &mut ctx.images, &mut ctx.layers);
74            gfx.object_set_x(images, layers, 0, 0, x)?;
75            return Ok(true);
76        }
77        return Ok(false);
78    }
79
80    if matches!(name.as_str(), "BG_Y" | "BGY") {
81        let args = strip_vm_meta(&cmd.args);
82        if let Some(y) = last_i64(args) {
83            let (gfx, images, layers) = (&mut ctx.gfx, &mut ctx.images, &mut ctx.layers);
84            gfx.object_set_y(images, layers, 0, 0, y)?;
85            return Ok(true);
86        }
87        return Ok(false);
88    }
89
90    if matches!(name.as_str(), "BG_POS" | "BGPOS" | "BG_MOVE" | "BGMOVE") {
91        // Heuristic: use the last two integer args as (x, y), and if a third
92        // integer exists before them, treat it as a duration in ms.
93        let args = strip_vm_meta(&cmd.args);
94        let ints = collect_i64(args);
95        if ints.len() >= 2 {
96            let x = ints[ints.len() - 2];
97            let y = ints[ints.len() - 1];
98            let (gfx, images, layers) = (&mut ctx.gfx, &mut ctx.images, &mut ctx.layers);
99            gfx.object_set_pos(images, layers, 0, 0, x, y)?;
100            if ints.len() >= 3 {
101                let dur = ints[ints.len() - 3];
102                if dur > 0 {
103                    ctx.wait.wait_ms(dur as u64);
104                }
105            }
106            return Ok(true);
107        }
108        return Ok(false);
109    }
110
111    if matches!(
112        name.as_str(),
113        "BG_PAT" | "BGPAT" | "BG_FRAME" | "BGFRAME" | "BG_NO" | "BGNO"
114    ) {
115        let args = strip_vm_meta(&cmd.args);
116        if let Some(p) = last_i64(args) {
117            let (gfx, images, layers) = (&mut ctx.gfx, &mut ctx.images, &mut ctx.layers);
118            gfx.object_set_patno(images, layers, 0, 0, p)?;
119            return Ok(true);
120        }
121        return Ok(false);
122    }
123
124    if matches!(name.as_str(), "BG_FADE" | "BGFADE") {
125        // Heuristic: last int = duration (ms), previous int = alpha.
126        let args = strip_vm_meta(&cmd.args);
127        let ints = collect_i64(args);
128        if ints.len() >= 2 {
129            let alpha = ints[ints.len() - 2].clamp(0, 255);
130            let dur = ints[ints.len() - 1];
131            let (gfx, images, layers) = (&mut ctx.gfx, &mut ctx.images, &mut ctx.layers);
132            gfx.object_set_alpha(images, layers, 0, 0, alpha)?;
133            if dur > 0 {
134                ctx.wait.wait_ms(dur as u64);
135            }
136            return Ok(true);
137        }
138        return Ok(false);
139    }
140
141    // If the script uses additional BG_* commands we haven't wired yet,
142    // keep the VM progressing while preserving a trace for later alignment.
143    if name.starts_with("BG") {
144        return Ok(true);
145    }
146
147    Ok(false)
148}