Skip to main content

siglus_scene_vm/runtime/forms/
cgtable.rs

1use anyhow::Result;
2
3use crate::runtime::forms::prop_access;
4use crate::runtime::{CommandContext, Value};
5
6fn ensure_cg_flags_size(ctx: &mut CommandContext, size: usize) {
7    if let Some(cnt) = ctx.tables.cgtable_flag_cnt {
8        let want = size.max(cnt);
9        if ctx.tables.cg_flags.len() < want {
10            ctx.tables.cg_flags.resize(want, 0);
11        }
12    } else if ctx.tables.cg_flags.len() < size {
13        ctx.tables.cg_flags.resize(size, 0);
14    }
15}
16
17fn get_cg_flag(ctx: &CommandContext, flag_no: i32) -> i64 {
18    if flag_no < 0 {
19        return 0;
20    }
21    ctx.tables
22        .cg_flags
23        .get(flag_no as usize)
24        .copied()
25        .unwrap_or(0) as i64
26}
27
28fn set_cg_flag(ctx: &mut CommandContext, flag_no: i32, value: i64) {
29    if flag_no < 0 {
30        return;
31    }
32    let idx = flag_no as usize;
33    ensure_cg_flags_size(ctx, idx + 1);
34    ctx.tables.cg_flags[idx] = if value != 0 { 1 } else { 0 };
35}
36
37fn cgtable_look_cnt(ctx: &CommandContext) -> i64 {
38    let Some(table) = ctx.tables.cgtable.as_ref() else {
39        return 0;
40    };
41    table
42        .entries
43        .iter()
44        .filter(|e| e.flag_no >= 0 && get_cg_flag(ctx, e.flag_no) != 0)
45        .count() as i64
46}
47
48pub(crate) fn mark_look_by_name(ctx: &mut CommandContext, name: &str) {
49    if ctx.globals.cg_table_off {
50        return;
51    }
52    let flag_no = ctx
53        .tables
54        .cgtable
55        .as_ref()
56        .and_then(|t| t.get_sub_from_name(name))
57        .map(|e| e.flag_no);
58    if let Some(flag_no) = flag_no {
59        set_cg_flag(ctx, flag_no, 1);
60    }
61}
62
63pub fn dispatch(ctx: &mut CommandContext, form_id: u32, args: &[Value]) -> Result<bool> {
64    let parsed = prop_access::parse_element_chain_ctx(ctx, form_id, args);
65    let (chain_pos, chain) = match parsed {
66        Some((pos, ch)) if ch.len() >= 2 => (Some(pos), Some(ch)),
67        _ => (None, None),
68    };
69
70    if let Some(chain) = chain {
71        let op = chain[1];
72
73        if op == ctx.ids.cgtable_flag {
74            let rest = &chain[2..];
75            if rest.len() >= 2 && rest[0] == ctx.ids.elm_array {
76                let idx_i32 = rest[1];
77                if idx_i32 < 0 {
78                    ctx.push(Value::Int(0));
79                    return Ok(true);
80                }
81
82                let idx = idx_i32 as usize;
83                ensure_cg_flags_size(ctx, idx + 1);
84
85                let (al_id, _ret_form, rhs_value) =
86                    crate::runtime::forms::prop_access::infer_assign_and_ret_ctx(
87                        ctx,
88                        chain_pos.unwrap_or(args.len()),
89                        args,
90                    );
91                let rhs = rhs_value.as_ref().and_then(Value::as_i64);
92
93                if al_id == Some(1) {
94                    let v = rhs.unwrap_or(0);
95                    ctx.tables.cg_flags[idx] = if v != 0 { 1 } else { 0 };
96                    ctx.push(Value::Int(0));
97                } else {
98                    ctx.push(Value::Int(ctx.tables.cg_flags[idx] as i64));
99                }
100                return Ok(true);
101            }
102
103            ctx.push(Value::Int(0));
104            return Ok(true);
105        }
106
107        let params = if let Some(pos) = chain_pos {
108            crate::runtime::forms::prop_access::script_args(args, pos)
109        } else {
110            &[]
111        };
112        let p_int = |i: usize| -> i64 { params.get(i).and_then(|v| v.as_i64()).unwrap_or(0) };
113        let p_str = |i: usize| -> &str { params.get(i).and_then(|v| v.as_str()).unwrap_or("") };
114
115        if ctx.ids.cgtable_set_disable != 0 && op == ctx.ids.cgtable_set_disable {
116            ctx.globals.cg_table_off = true;
117            ctx.push(Value::Int(0));
118            return Ok(true);
119        }
120        if ctx.ids.cgtable_set_enable != 0 && op == ctx.ids.cgtable_set_enable {
121            ctx.globals.cg_table_off = false;
122            ctx.push(Value::Int(0));
123            return Ok(true);
124        }
125        if ctx.ids.cgtable_set_all_flag != 0 && op == ctx.ids.cgtable_set_all_flag {
126            let v = p_int(0);
127            let flag_nos: Vec<i32> = ctx
128                .tables
129                .cgtable
130                .as_ref()
131                .map(|t| t.entries.iter().map(|e| e.flag_no).collect())
132                .unwrap_or_default();
133            for flag_no in flag_nos {
134                set_cg_flag(ctx, flag_no, v);
135            }
136            ctx.push(Value::Int(0));
137            return Ok(true);
138        }
139
140        if ctx.ids.cgtable_get_cg_cnt != 0 && op == ctx.ids.cgtable_get_cg_cnt {
141            let cnt = ctx
142                .tables
143                .cgtable
144                .as_ref()
145                .map(|t| t.get_cg_cnt())
146                .unwrap_or(0);
147            ctx.push(Value::Int(cnt as i64));
148            return Ok(true);
149        }
150
151        if ctx.ids.cgtable_get_look_cnt != 0 && op == ctx.ids.cgtable_get_look_cnt {
152            ctx.push(Value::Int(cgtable_look_cnt(ctx)));
153            return Ok(true);
154        }
155
156        if ctx.ids.cgtable_get_look_percent != 0 && op == ctx.ids.cgtable_get_look_percent {
157            let total = ctx
158                .tables
159                .cgtable
160                .as_ref()
161                .map(|t| t.get_cg_cnt())
162                .unwrap_or(0) as i64;
163            let looked = cgtable_look_cnt(ctx);
164            let percent = if total <= 0 || looked <= 0 {
165                0
166            } else {
167                let raw = looked * 100 / total;
168                if raw <= 0 {
169                    1
170                } else {
171                    raw
172                }
173            };
174            ctx.push(Value::Int(percent));
175            return Ok(true);
176        }
177
178        if ctx.ids.cgtable_get_flag_no_by_name != 0 && op == ctx.ids.cgtable_get_flag_no_by_name {
179            let name = p_str(0);
180            let res = ctx
181                .tables
182                .cgtable
183                .as_ref()
184                .and_then(|t| t.get_sub_from_name(name))
185                .map(|e| e.flag_no as i64)
186                .unwrap_or(-1);
187            ctx.push(Value::Int(res));
188            return Ok(true);
189        }
190
191        if ctx.ids.cgtable_get_look_by_name != 0 && op == ctx.ids.cgtable_get_look_by_name {
192            let name = p_str(0);
193            let res = if let Some(e) = ctx
194                .tables
195                .cgtable
196                .as_ref()
197                .and_then(|t| t.get_sub_from_name(name))
198            {
199                get_cg_flag(ctx, e.flag_no)
200            } else {
201                -1
202            };
203            ctx.push(Value::Int(res));
204            return Ok(true);
205        }
206
207        if ctx.ids.cgtable_set_look_by_name != 0 && op == ctx.ids.cgtable_set_look_by_name {
208            let name = p_str(0);
209            let v = p_int(1);
210            let flag_no = ctx
211                .tables
212                .cgtable
213                .as_ref()
214                .and_then(|t| t.get_sub_from_name(name))
215                .map(|e| e.flag_no);
216            if let Some(flag_no) = flag_no {
217                set_cg_flag(ctx, flag_no, v);
218            }
219            ctx.push(Value::Int(0));
220            return Ok(true);
221        }
222
223        if ctx.ids.cgtable_get_name_by_flag_no != 0 && op == ctx.ids.cgtable_get_name_by_flag_no {
224            let flag_no = p_int(0) as i32;
225            let name = ctx
226                .tables
227                .cgtable
228                .as_ref()
229                .and_then(|t| t.get_sub_from_flag_no(flag_no))
230                .map(|e| e.name.as_str())
231                .unwrap_or("");
232            ctx.push(Value::Str(name.to_string()));
233            return Ok(true);
234        }
235
236        prop_access::store_or_push_prop(ctx, form_id, op, chain_pos.unwrap(), args);
237        return Ok(true);
238    }
239
240    Ok(false)
241}