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