1use crate::{
2 script::{
3 cursor::{read_i16, read_i32, read_string, read_u16, read_u8, read_var},
4 ins::{GenericArg, GenericIns, Ins, ItemSize, Operand},
5 },
6 utils::subslice_offset,
7};
8use arrayvec::ArrayVec;
9use std::{cell::Cell, fmt::Write};
10
11pub fn disasm_to_string(code: &[u8]) -> String {
12 let mut output = String::new();
13 let decoder = Decoder::new(code);
14 while let Some((pos, ins)) = decoder.next() {
15 writeln!(output, "0x{:04x} {}", pos, ins).unwrap();
16 }
17 for pos in decoder.pos()..decoder.code.len() {
19 writeln!(output, "0x{:04x} .db 0x{:02x}", pos, decoder.code[pos]).unwrap();
20 }
21 output
22}
23
24pub struct Decoder<'a> {
25 code: &'a [u8],
26 pub pos: Cell<usize>,
27}
28
29impl<'a> Decoder<'a> {
30 pub fn new(code: &'a [u8]) -> Self {
31 Self {
32 code,
33 pos: Cell::new(0),
34 }
35 }
36
37 pub fn next(&self) -> Option<(usize, Ins<'a>)> {
38 let pos = self.pos.get();
39 let code = &self.code[pos..];
40 let mut cur = code;
41 let ins = decode_ins(&mut cur)?;
42 self.pos.set(pos + subslice_offset(code, cur));
43 Some((pos, ins))
44 }
45
46 pub fn pos(&self) -> usize {
47 self.pos.get()
48 }
49
50 pub fn set_pos(&self, value: usize) {
51 self.pos.set(value);
52 }
53}
54
55macro_rules! ins {
57 (
63 @parse,
64 bytecode = {},
65 name = $name:tt,
66 ops = $ops:tt,
67 args = $args:tt,
68 retval = $retval:tt,
69 rest = {[$($byte:expr),+] $(, $($rest:tt)*)?},
70 ) => {
71 ins!(
72 @parse,
73 bytecode = {bytearray![$($byte),+]},
74 name = $name,
75 ops = $ops,
76 args = $args,
77 retval = $retval,
78 rest = {$($($rest)*)?},
79 )
80 };
81 (
83 @parse,
84 bytecode = $bytecode:tt,
85 name = {},
86 ops = $ops:tt,
87 args = $args:tt,
88 retval = $retval:tt,
89 rest = {name = $name:expr $(, $($rest:tt)*)?},
90 ) => {
91 ins!(
92 @parse,
93 bytecode = $bytecode,
94 name = {Some($name)},
95 ops = $ops,
96 args = $args,
97 retval = $retval,
98 rest = {$($($rest)*)?},
99 )
100 };
101 (
103 @parse,
104 bytecode = $bytecode:tt,
105 name = $name:tt,
106 ops = {},
107 args = $args:tt,
108 retval = $retval:tt,
109 rest = {ops = [$($ops:tt)*] $(, $($rest:tt)*)?},
110 ) => {
111 ins!(
112 @parse,
113 bytecode = $bytecode,
114 name = $name,
115 ops = {ins!(@ops, begin = {$($ops)*})},
116 args = $args,
117 retval = $retval,
118 rest = {$($($rest)*)?},
119 )
120 };
121 (
123 @parse,
124 bytecode = $bytecode:tt,
125 name = $name:tt,
126 ops = $ops:tt,
127 args = {},
128 retval = $retval:tt,
129 rest = {args = [$($args:tt)*] $(, $($rest:tt)*)?},
130 ) => {
131 ins!(
132 @parse,
133 bytecode = $bytecode,
134 name = $name,
135 ops = $ops,
136 args = {ins!(@args, begin = {$($args)*})},
137 retval = $retval,
138 rest = {$($($rest)*)?},
139 )
140 };
141 (
143 @parse,
144 bytecode = $bytecode:tt,
145 name = $name:tt,
146 ops = $ops:tt,
147 args = $args:tt,
148 retval = {},
149 rest = {retval $(, $($rest:tt)*)?},
150 ) => {
151 ins!(
152 @parse,
153 bytecode = $bytecode,
154 name = $name,
155 ops = $ops,
156 args = $args,
157 retval = {true},
158 rest = {$($($rest)*)?},
159 )
160 };
161 (
163 @parse,
164 bytecode = $bytecode:tt,
165 name = $name:tt,
166 ops = $ops:tt,
167 args = $args:tt,
168 retval = $retval:tt,
169 rest = {},
170 ) => {
171 ins!(
172 @set_defaults,
173 bytecode = $bytecode,
174 name = $name,
175 ops = $ops,
176 args = $args,
177 retval = $retval,
178 )
179 };
180
181 (
187 @set_defaults,
188 bytecode = $bytecode:tt,
189 name = {},
190 ops = $ops:tt,
191 args = $args:tt,
192 retval = $retval:tt,
193 ) => {
194 ins!(
195 @set_defaults,
196 bytecode = $bytecode,
197 name = {None},
198 ops = $ops,
199 args = $args,
200 retval = $retval,
201 )
202 };
203 (
205 @set_defaults,
206 bytecode = $bytecode:tt,
207 name = $name:tt,
208 ops = {},
209 args = $args:tt,
210 retval = $retval:tt,
211 ) => {
212 ins!(
213 @set_defaults,
214 bytecode = $bytecode,
215 name = $name,
216 ops = {arrayvec![]},
217 args = $args,
218 retval = $retval,
219 )
220 };
221 (
223 @set_defaults,
224 bytecode = $bytecode:tt,
225 name = $name:tt,
226 ops = $ops:tt,
227 args = {},
228 retval = $retval:tt,
229 ) => {
230 ins!(
231 @set_defaults,
232 bytecode = $bytecode,
233 name = $name,
234 ops = $ops,
235 args = {&[]},
236 retval = $retval,
237 )
238 };
239 (
241 @set_defaults,
242 bytecode = $bytecode:tt,
243 name = $name:tt,
244 ops = $ops:tt,
245 args = $args:tt,
246 retval = {},
247 ) => {
248 ins!(
249 @set_defaults,
250 bytecode = $bytecode,
251 name = $name,
252 ops = $ops,
253 args = $args,
254 retval = {false},
255 )
256 };
257 (
259 @set_defaults,
260 bytecode = {$($bytecode:tt)*},
261 name = {$($name:tt)*},
262 ops = {$($ops:tt)*},
263 args = {$($args:tt)*},
264 retval = {$retval:tt},
265 ) => {
266 Some(Ins::Generic({$($bytecode)*}, {$($ops)*}, &GenericIns {
267 name: {$($name)*},
268 args: {$($args)*},
269 returns_value: $retval,
270 }))
271 };
272
273 (
279 @ops,
280 begin = {$($in:tt)*}
281 ) => {
282 ins!(
283 @ops,
284 in = {$($in)*},
285 out = {,},
286 )
287 };
288 (
290 @ops,
291 in = {$type:ident: $value:expr $(, $($tail:tt)*)?},
292 out = {$($out:tt)*},
293 ) => {
294 ins!(
295 @ops,
296 in = {$($($tail)*)?},
297 out = {$($out)* ins!(@op_kind $type)($value),},
298 )
299 };
300 (@op_kind u8) => {
301 Operand::Byte
302 };
303 (@op_kind i16) => {
304 Operand::I16
305 };
306 (@op_kind var) => {
307 Operand::Var
308 };
309 (@op_kind string) => {
310 Operand::String
311 };
312 (
314 @ops,
315 in = {},
316 out = {, $($out:tt)*},
317 ) => {
318 arrayvec![$($out)*]
319 };
320
321 (
327 @args,
328 begin = {$($in:tt)*}
329 ) => {
330 ins!(
331 @args,
332 in = {$($in)*},
333 out = {,},
334 )
335 };
336 (
338 @args,
339 in = {$arg:ident $(, $($rest:tt)*)?},
340 out = {$($out:tt)*},
341 ) => {
342 ins!(
343 @args,
344 in = {$($($rest)*)?},
345 out = {$($out)* ins!(@one_arg $arg),},
346 )
347 };
348 (@one_arg int) => {
349 GenericArg::Int
350 };
351 (@one_arg string) => {
352 GenericArg::String
353 };
354 (@one_arg list) => {
355 GenericArg::List
356 };
357 (@one_arg script) => {
358 GenericArg::IntScript
359 };
360 (
362 @args,
363 in = {},
364 out = {, $($out:tt)*},
365 ) => {
366 &[$($out)*]
367 };
368
369 (@ $($rest:tt)*) => {
375 compile_error!("macro has failed")
376 };
377
378 ($($rest:tt)*) => {
380 ins!(
381 @parse,
382 bytecode = {},
383 name = {},
384 ops = {},
385 args = {},
386 retval = {},
387 rest = {$($rest)*},
388 )
389 };
390}
391
392#[allow(clippy::too_many_lines)]
393fn decode_ins<'a>(code: &mut &'a [u8]) -> Option<Ins<'a>> {
394 let opcode = read_u8(code)?;
395 #[allow(clippy::match_same_arms)]
396 match opcode {
397 0x00 => op_00_push_byte(code),
398 0x01 => op_01_push_i16(code),
399 0x02 => op_02_push_i32(code),
400 0x03 => op_03_push_var(code),
401 0x04 => op_04_push_str(code),
402 0x07 => op_07_get_array_item(code),
403 0x0a => Some(Ins::StackDupN(read_u16(code)?)),
404 0x0b => op_0b_get_array_item_2d(code),
405 0x0c => Some(Ins::StackDup),
406 0x0d => Some(Ins::Not),
407 0x0e => Some(Ins::Equal),
408 0x0f => Some(Ins::NotEqual),
409 0x10 => Some(Ins::Greater),
410 0x11 => Some(Ins::Less),
411 0x12 => Some(Ins::LessOrEqual),
412 0x13 => Some(Ins::GreaterOrEqual),
413 0x14 => Some(Ins::Add),
414 0x15 => Some(Ins::Sub),
415 0x16 => Some(Ins::Mul),
416 0x17 => Some(Ins::Div),
417 0x18 => Some(Ins::LogicalAnd),
418 0x19 => Some(Ins::LogicalOr),
419 0x1a => Some(Ins::PopDiscard),
420 0x1b => Some(Ins::In),
421 0x1c => op_1c_image(code),
422 0x1d => ins!([0x1d], name = "min", args = [int, int], retval),
423 0x1e => ins!([0x1e], name = "max", args = [int, int], retval),
424 0x1f => ins!([0x1f], name = "sin", args = [int], retval),
425 0x20 => ins!([0x20], name = "cos", args = [int], retval),
426 0x21 => ins!([0x21], args = [int], retval),
427 0x22 => ins!([0x22], name = "atan2", args = [int, int], retval),
428 0x23 => ins!([0x22], name = "atan4", args = [int, int, int, int], retval),
429 0x24 => op_24(code),
430 0x25 => op_25_sprite_retval(code),
431 0x26 => op_26_sprite(code),
432 0x27 => op_27_sprite_group_retval(code),
433 0x28 => op_28_sprite_group(code),
434 0x29 => op_29_image_retval(code),
435 0x2a => {
436 ins!(
437 [0x2a],
438 name = "actor-get-property",
439 args = [int, int, int],
440 retval,
441 )
442 }
443 0x2b => op_2b_begin_script(code),
444 0x2c => op_2c_become_script(code),
445 0x30 => ins!([0x30], name = "mod", args = [int, int], retval),
446 0x31 => ins!([0x31], name = "shl", args = [int, int], retval),
447 0x32 => ins!([0x32], name = "shr", args = [int, int], retval),
448 0x34 => {
449 ins!(
450 [0x34],
451 name = "find-all-objects-of-class",
452 args = [int, list],
453 retval,
454 )
455 }
456 0x36 => ins!([0x36], name = "iif", args = [int, int, int], retval),
457 0x37 => op_37_dim_array(code),
458 0x38 => op_38_redim_array(code),
459 0x3a => op_3a_array_sort(code),
460 0x43 => op_43_set(code),
461 0x46 => ins!([0x46], name = "file-get-size", args = [string], retval),
462 0x47 => op_47_set_array_item(code),
463 0x48 => ins!([0x48], name = "atoi", args = [int], retval),
464 0x4b => op_4b_set_array_item_2d(code),
465 0x4d => op_4d_read_ini(code),
466 0x4e => op_4e_write_ini(code),
467 0x4f => op_4f_inc(code),
468 0x50 => ins!([0x50]),
469 0x53 => ins!([0x53], name = "inc-array-item", ops = [var: read_var(code)?], args = [int]),
470 0x57 => op_57_dec(code),
471 0x58 => op_58(code),
472 0x5a => {
473 ins!(
474 [0x5a],
475 name = "sound-samples-remaining",
476 args = [int],
477 retval,
478 )
479 }
480 0x5b => ins!([0x5b], name = "dec-array-item", ops = [var: read_var(code)?], args = [int]),
481 0x5c => op_5c_jump_if(code),
482 0x5d => op_5d_jump_unless(code),
483 0x5e => op_5e_run_script(code),
484 0x60 => op_60_start_script(code),
485 0x61 => op_61_draw_object(code),
486 0x62 => ins!([0x62], name = "draw-x62", args = [int]),
487 0x63 => op_63_array_sizes(code),
488 0x64 => ins!([0x64], name = "get-free-arrays", retval),
489 0x65 => ins!([0x65], name = "finish-script"),
490 0x66 => ins!([0x66], name = "free-script"),
491 0x69 => op_69_window(code),
492 0x6a => ins!([0x6a], args = [int]),
493 0x6b => op_6b_cursor(code),
494 0x6c => ins!([0x6c], name = "stop-script"),
495 0x6d => ins!([0x6d], name = "get-class", args = [int, list], retval),
496 0x6e => ins!([0x6e], name = "put-class", args = [int, list]),
497 0x6f => ins!([0x6f], name = "object-get-state", args = [int], retval),
498 0x70 => ins!([0x70], name = "object-put-state", args = [int, int]),
499 0x73 => op_73_jump(code),
500 0x74 => op_74_sound(code),
501 0x75 => ins!([0x75], name = "stop-sound", args = [int]),
502 0x7b => ins!([0x7b], name = "go-to-room", args = [int]),
503 0x7c => ins!([0x7c], name = "free-running-script", args = [script]),
504 0x7f => ins!([0x7f], name = "put-actor", args = [int, int, int, int]),
505 0x82 => ins!([0x82], name = "actor-do-anim", args = [int, int]),
506 0x87 => ins!([0x87], name = "random", args = [int], retval),
507 0x88 => ins!([0x88], name = "random2", args = [int, int], retval),
508 0x8b => ins!([0x8b], name = "is-script-running", args = [script], retval),
509 0x8c => ins!([0x8c], name = "get-room", args = [int], retval),
510 0x8d => ins!([0x8d], name = "get-x", args = [int], retval),
511 0x8e => ins!([0x8e], name = "get-y", args = [int], retval),
512 0x91 => ins!([0x91], name = "actor-get-costume", args = [int], retval),
513 0x94 => op_94(code),
514 0x95 => op_95_cutscene_start(code),
515 0x96 => ins!([0x96], name = "cutscene-end"),
516 0x98 => ins!([0x98], name = "is-sound-playing", args = [int], retval),
517 0x9b => op_9b(code),
518 0x9c => op_9c(code),
519 0x9d => op_9d_actor(code),
520 0x9e => op_9e_palette(code),
521 0x9f => ins!([0x9f], args = [int, int], retval),
522 0xa0 => ins!([0xa0], args = [int, int], retval),
523 0xa2 => ins!([0xa2], args = [int], retval),
524 0xa3 => ins!([0xa3], args = [int, int], retval),
525 0xa4 => op_a4_array(code),
526 0xa6 => ins!([0xa6], args = [int, int, int, int, int]),
527 0xa7 => ins!([0xa7], name = "pop-discard", args = [int]),
528 0xa9 => op_a9(code),
529 0xaa => ins!([0xaa], name = "actor-get-xaa", args = [int], retval),
530 0xad => Some(Ins::In), 0xae => op_ae(code),
532 0xb0 => ins!([0xb0], name = "sleep-frames", args = [int]),
533 0xb1 => ins!([0xb1], name = "sleep-seconds", args = [int]),
534 0xb3 => ins!([0xb3], name = "stop-script-34"),
535 0xb5 => op_b5(code),
536 0xb6 => op_b6(code),
537 0xb7 => op_b7(code),
538 0xb8 => op_b8(code),
539 0xb9 => op_b9(code),
540 0xba => ins!([0xba], ops = [string: read_string(code)?], args = [int]),
541 0xbb => ins!([0xbb], ops = [string: read_string(code)?]),
542 0xbc => op_bc_array(code),
543 0xbd => ins!([0xbd], name = "return", args = [int]),
544 0xbf => ins!([0xbf], name = "call-script", args = [script, list], retval),
545 0xc0 => op_c0_dim_array(code),
546 0xc1 => ins!([0xc1], name = "pop-discard-2", args = [int, string]),
547 0xc4 => ins!([0xc4], name = "abs", args = [int], retval),
548 0xc8 => ins!([0xc8], name = "kludge-retval", args = [list], retval),
549 0xc9 => ins!([0xc9], name = "kludge", args = [list]),
550 0xca => ins!([0xca], name = "sleep", args = [int]),
551 0xcb => ins!([0xcb], name = "pick", args = [int, list], retval),
552 0xcf => ins!([0xcf], name = "input-dialog", args = [string], retval),
553 0xd0 => ins!([0xd0], name = "now"),
554 0xd1 => ins!([0xd1]),
555 0xd2 => ins!([0xd2], name = "actor-get-var", args = [int, int], retval),
556 0xd4 => {
557 ins!([0xd4], name = "shuffle-array", ops = [var: read_var(code)?], args = [int, int])
558 }
559 0xd5 => op_d5_exec_script(code),
560 0xd6 => Some(Ins::BitwiseAnd),
561 0xd7 => Some(Ins::BitwiseOr),
562 0xd9 => ins!([0xd9], name = "file-close", args = [int]),
563 0xda => ins!([0xda], name = "file-open", args = [string, int], retval),
564 0xdb => op_db_file_read(code),
565 0xdc => op_dc_file_write(code),
566 0xde => ins!([0xde], name = "file-delete", args = [string]),
567 0xe0 => op_e0(code),
568 0xe2 => ins!([0xe2], args = [int]),
569 0xe3 => ins!([0xe3], ops = [var: read_var(code)?], args = [list], retval),
570 0xe9 => ins!([0xe9], name = "file-seek", args = [int, int, int]),
571 0xea => {
572 ins!(
573 [0xea],
574 name = "redim",
575 ops = [u8: read_u8(code)?, var: read_var(code)?],
576 args = [int, int],
577 )
578 }
579 0xeb => ins!([0xeb], name = "file-get-pos", args = [int], retval),
580 0xec => ins!([0xec], name = "strcpy", args = [int], retval),
581 0xed => ins!([0xed], args = [int, int, int], retval),
582 0xee => ins!([0xee], name = "strlen", args = [int], retval),
583 0xef => ins!([0xef], name = "substr", args = [int, int, int], retval),
584 0xf1 => ins!([0xf1], name = "strcmp", args = [int, int], retval),
585 0xf2 => op_f2_percent_loaded(code),
586 0xf3 => op_f3_read_ini(code),
587 0xf4 => op_f4_write_ini(code),
588 0xf5 => ins!([0xf5], args = [int, int, int], retval),
589 0xf6 => {
590 ins!(
591 [0xf6],
592 name = "array-find",
593 args = [int, int, int, int],
594 retval,
595 )
596 }
597 0xf8 => op_f8_get_size(code),
598 0xf9 => ins!([0xf9], name = "create-directory", args = [string]),
599 0xfa => op_fa_window_title(code),
600 0xfb => op_fb(code),
601 0xfc => ins!([0xfc], args = [int, int], retval),
602 _ => None,
603 }
604}
605
606fn op_00_push_byte<'a>(code: &mut &'a [u8]) -> Option<Ins<'a>> {
607 Some(Ins::Push(Operand::Byte(read_u8(code)?)))
608}
609
610fn op_01_push_i16<'a>(code: &mut &'a [u8]) -> Option<Ins<'a>> {
611 Some(Ins::Push(Operand::I16(read_i16(code)?)))
612}
613
614fn op_02_push_i32<'a>(code: &mut &'a [u8]) -> Option<Ins<'a>> {
615 Some(Ins::Push(Operand::I32(read_i32(code)?)))
616}
617
618fn op_03_push_var<'a>(code: &mut &'a [u8]) -> Option<Ins<'a>> {
619 Some(Ins::Push(Operand::Var(read_var(code)?)))
620}
621
622fn op_04_push_str<'a>(code: &mut &'a [u8]) -> Option<Ins<'a>> {
623 Some(Ins::Push(Operand::String(read_string(code)?)))
624}
625
626fn op_07_get_array_item<'a>(code: &mut &'a [u8]) -> Option<Ins<'a>> {
627 Some(Ins::GetArrayItem(read_var(code)?))
628}
629
630fn op_0b_get_array_item_2d<'a>(code: &mut &'a [u8]) -> Option<Ins<'a>> {
631 Some(Ins::GetArrayItem2D(read_var(code)?))
632}
633
634fn op_1c_image<'a>(code: &mut &'a [u8]) -> Option<Ins<'a>> {
635 match read_u8(code)? {
636 0x20 => ins!([0x1c, 0x20], name = "image-x20", args = [int]),
637 0x21 => ins!([0x1c, 0x21], name = "image-x21", args = [int]),
638 0x30 => ins!([0x1c, 0x30], name = "image-x30"),
639 0x31 => ins!([0x1c, 0x31], name = "image-path", args = [string]),
640 0x33 => {
641 ins!(
642 [0x1c, 0x33],
643 name = "image-x33",
644 args = [int, int, int, int, int],
645 )
646 }
647 0x34 => ins!([0x1c, 0x34], name = "image-x34", args = [int]),
648 0x36 => ins!([0x1c, 0x36], name = "image-x36", args = [int]),
649 0x38 => {
650 ins!(
651 [0x1c, 0x38],
652 name = "image-x38",
653 args = [int, int, int, int, int],
654 )
655 }
656 0x39 => ins!([0x1c, 0x39], name = "image-select", args = [int]),
657 0x41 => ins!([0x1c, 0x41], name = "image-pos", args = [int, int]),
658 0x56 => ins!([0x1c, 0x56], name = "image-palette", args = [int]),
659 0x62 => ins!([0x1c, 0x62], name = "image-x62", args = [int]),
660 0x85 => {
661 ins!(
662 [0x1c, 0x85],
663 name = "image-x85",
664 args = [int, int, int, int, int],
665 )
666 }
667 0x89 => ins!([0x1c, 0x89], name = "image-render-into", args = [int]),
668 0x9a => ins!([0x1c, 0x9a], name = "image-x9a", args = [int, int]),
669 0xd9 => ins!([0x1c, 0xd9], name = "image-op-create"),
670 0xf6 => ins!([0x1c, 0xf6], name = "image-xf6", args = [int]),
671 0xff => ins!([0x1c, 0xff], name = "image-xff"),
672 _ => None,
673 }
674}
675
676fn op_24<'a>(code: &mut &'a [u8]) -> Option<Ins<'a>> {
677 match read_u8(code)? {
678 0x1c => {
679 ins!(
680 [0x24, 0x1c],
681 name = "distance-2d",
682 args = [int, int, int, int],
683 retval,
684 )
685 }
686 0x1d => {
687 ins!(
688 [0x24, 0x1d],
689 name = "distance-3d",
690 args = [int, int, int, int, int, int],
691 retval,
692 )
693 }
694 _ => None,
695 }
696}
697
698fn op_25_sprite_retval<'a>(code: &mut &'a [u8]) -> Option<Ins<'a>> {
699 match read_u8(code)? {
700 0x1e => {
701 ins!(
702 [0x25, 0x1e],
703 name = "sprite-get-hotspot-x",
704 args = [int],
705 retval,
706 )
707 }
708 0x1f => {
709 ins!(
710 [0x25, 0x1f],
711 name = "sprite-get-hotspot-y",
712 args = [int],
713 retval,
714 )
715 }
716 0x24 => ins!([0x25, 0x24], name = "sprite-get-x24", args = [int], retval),
717 0x25 => {
718 ins!(
719 [0x25, 0x25],
720 name = "sprite-get-group",
721 args = [int],
722 retval,
723 )
724 }
725 0x26 => {
726 ins!(
727 [0x25, 0x26],
728 name = "sprite-get-translated-hotspot-x",
729 args = [int],
730 retval,
731 )
732 }
733 0x27 => {
734 ins!(
735 [0x25, 0x27],
736 name = "sprite-get-translated-hotspot-y",
737 args = [int],
738 retval,
739 )
740 }
741 0x2b => ins!([0x25, 0x2b], name = "sprite-get-x2b", args = [int], retval),
742 0x2d => {
743 ins!(
744 [0x25, 0x2d],
745 name = "sprite-get-x2d",
746 args = [int, int, int, int, list],
747 retval,
748 )
749 }
750 0x34 => ins!([0x25, 0x34], name = "sprite-get-wiz", args = [int], retval),
751 0x3f => {
752 ins!(
753 [0x25, 0x3f],
754 name = "sprite-get-image",
755 args = [int],
756 retval,
757 )
758 }
759 0x56 => ins!([0x25, 0x56], name = "sprite-get-x56", args = [int], retval),
760 0x7c => ins!([0x25, 0x7c], name = "sprite-get-x7c", args = [int], retval),
761 0x7d => {
762 ins!(
763 [0x25, 0x7d],
764 name = "sprite-has-class",
765 args = [int, list],
766 retval,
767 )
768 }
769 0xc6 => {
770 ins!(
771 [0x25, 0xc6],
772 name = "sprite-get-xc6",
773 args = [int, int],
774 retval,
775 )
776 }
777 _ => None,
778 }
779}
780
781fn op_26_sprite<'a>(code: &mut &'a [u8]) -> Option<Ins<'a>> {
782 match read_u8(code)? {
783 0x25 => ins!([0x26, 0x25], name = "sprite-x25", args = [int]),
784 0x2a => ins!([0x26, 0x2a], name = "sprite-x2a", args = [int, int]),
785 0x2b => ins!([0x26, 0x2b], name = "sprite-x2b", args = [int]),
786 0x2c => {
787 ins!(
788 [0x26, 0x2c],
789 name = "sprite-move-hotspot",
790 args = [int, int],
791 )
792 }
793 0x34 => ins!([0x26, 0x34], name = "sprite-x34", args = [int]),
794 0x39 => ins!([0x26, 0x39], name = "sprite-set-range", args = [int, int]),
795 0x3f => ins!([0x26, 0x3f], name = "sprite-set-image", args = [int]),
796 0x41 => ins!([0x26, 0x41], name = "sprite-set-hotspot", args = [int, int]),
797 0x4d => ins!([0x26, 0x4d], name = "sprite-x4d", args = [int, int]),
798 0x52 => ins!([0x26, 0x52], name = "sprite-x52", args = [int]),
799 0x56 => ins!([0x26, 0x56], name = "sprite-palette", args = [int]),
800 0x61 => ins!([0x26, 0x61], name = "sprite-x61", args = [int]),
801 0x62 => ins!([0x26, 0x62], name = "sprite-x62", args = [int]),
802 0x7c => ins!([0x26, 0x7c], name = "sprite-x7c", args = [int]),
803 0x7d => ins!([0x26, 0x7d], name = "sprite-x7d", args = [list]),
804 0x8c => ins!([0x26, 0x8c], name = "sprite-x8c", args = [int]),
805 0x9e => ins!([0x26, 0x9e], name = "sprite-x9e"),
806 0xc6 => ins!([0x26, 0xc6], name = "sprite-xc6", args = [int, int]),
807 0xd9 => ins!([0x26, 0xd9], name = "sprite-clear"),
808 _ => None,
809 }
810}
811
812fn op_27_sprite_group_retval<'a>(code: &mut &'a [u8]) -> Option<Ins<'a>> {
813 match read_u8(code)? {
814 0x08 => {
815 ins!(
816 [0x27, 0x08],
817 name = "sprite-group-get-x08",
818 args = [int],
819 retval,
820 )
821 }
822 0x1e => {
823 ins!(
824 [0x27, 0x1e],
825 name = "sprite-group-get-x",
826 args = [int],
827 retval,
828 )
829 }
830 0x1f => {
831 ins!(
832 [0x27, 0x1f],
833 name = "sprite-group-get-y",
834 args = [int],
835 retval,
836 )
837 }
838 _ => None,
839 }
840}
841
842fn op_28_sprite_group<'a>(code: &mut &'a [u8]) -> Option<Ins<'a>> {
843 match read_u8(code)? {
844 0x2c => ins!([0x28, 0x2c], name = "sprite-group-x2c", args = [int, int]),
845 0x39 => ins!([0x28, 0x39], name = "sprite-group-select", args = [int]),
846 0x41 => ins!([0x28, 0x41], name = "sprite-group-x41", args = [int, int]),
847 0x43 => {
848 ins!(
849 [0x28, 0x43],
850 name = "sprite-group-x43",
851 args = [int, int, int, int],
852 )
853 }
854 0xd9 => ins!([0x28, 0xd9], name = "sprite-group-clear"),
855 _ => None,
856 }
857}
858
859fn op_29_image_retval<'a>(code: &mut &'a [u8]) -> Option<Ins<'a>> {
860 match read_u8(code)? {
861 0x1e => {
862 ins!(
863 [0x29, 0x1e],
864 name = "image-get-hotspot-x",
865 args = [int, int],
866 retval,
867 )
868 }
869 0x1f => {
870 ins!(
871 [0x29, 0x1f],
872 name = "image-get-hotspot-y",
873 args = [int, int],
874 retval,
875 )
876 }
877 0x20 => {
878 ins!(
879 [0x29, 0x20],
880 name = "image-get-width",
881 args = [int, int],
882 retval,
883 )
884 }
885 0x21 => {
886 ins!(
887 [0x29, 0x21],
888 name = "image-get-height",
889 args = [int, int],
890 retval,
891 )
892 }
893 0x24 => ins!([0x29, 0x24], name = "image-get-x24", args = [int], retval),
894 0x42 => {
895 ins!(
896 [0x29, 0x42],
897 name = "image-get-x42",
898 args = [int, int, int, int],
899 retval,
900 )
901 }
902 _ => None,
903 }
904}
905
906fn op_2b_begin_script<'a>(code: &mut &'a [u8]) -> Option<Ins<'a>> {
907 match read_u8(code)? {
908 0x01 => {
909 ins!(
910 [0x2b, 0x01],
911 name = "begin-script",
912 args = [script, int, list],
913 )
914 }
915 _ => None,
916 }
917}
918
919fn op_2c_become_script<'a>(code: &mut &'a [u8]) -> Option<Ins<'a>> {
920 match read_u8(code)? {
921 0x01 => {
922 ins!(
923 [0x2c, 0x01],
924 name = "become-script",
925 args = [script, int, list],
926 )
927 }
928 _ => None,
929 }
930}
931
932fn op_37_dim_array<'a>(code: &mut &'a [u8]) -> Option<Ins<'a>> {
933 let item_size = to_item_size(read_u8(code)?)?;
934 let var = read_var(code)?;
935 Some(Ins::DimArray2D(item_size, var))
936}
937
938fn op_38_redim_array<'a>(code: &mut &'a [u8]) -> Option<Ins<'a>> {
939 let item_size = to_item_size(read_u8(code)?)?;
940 let var = read_var(code)?;
941 Some(Ins::RedimArray2D(item_size, var))
942}
943
944fn to_item_size(n: u8) -> Option<ItemSize> {
945 match n {
946 2 => Some(ItemSize::Bit),
947 4 => Some(ItemSize::Byte),
948 5 => Some(ItemSize::I16),
949 6 => Some(ItemSize::I32),
950 7 => Some(ItemSize::Char),
951 _ => None,
952 }
953}
954
955fn op_3a_array_sort<'a>(code: &mut &'a [u8]) -> Option<Ins<'a>> {
956 match read_u8(code)? {
957 0x81 => {
958 ins!(
959 [0x3a, 0x81],
960 name = "array-sort",
961 ops = [var: read_var(code)?],
962 args = [int, int, int, int, int],
963 )
964 }
965 _ => None,
966 }
967}
968
969fn op_43_set<'a>(code: &mut &'a [u8]) -> Option<Ins<'a>> {
970 Some(Ins::Set(read_var(code)?))
971}
972
973fn op_47_set_array_item<'a>(code: &mut &'a [u8]) -> Option<Ins<'a>> {
974 Some(Ins::SetArrayItem(read_var(code)?))
975}
976
977fn op_4b_set_array_item_2d<'a>(code: &mut &'a [u8]) -> Option<Ins<'a>> {
978 Some(Ins::SetArrayItem2D(read_var(code)?))
979}
980
981fn op_4d_read_ini<'a>(code: &mut &'a [u8]) -> Option<Ins<'a>> {
982 match read_u8(code)? {
983 0x06 => {
984 ins!(
985 [0x4d, 0x06],
986 name = "read-ini-int",
987 args = [string, string, string],
988 retval,
989 )
990 }
991 0x07 => {
992 ins!(
993 [0x4d, 0x07],
994 name = "read-ini-string",
995 args = [string, string, string],
996 retval,
997 )
998 }
999 _ => None,
1000 }
1001}
1002
1003fn op_4e_write_ini<'a>(code: &mut &'a [u8]) -> Option<Ins<'a>> {
1004 match read_u8(code)? {
1005 0x06 => {
1006 ins!(
1007 [0x4e, 0x06],
1008 name = "write-ini-int",
1009 args = [string, string, string, int],
1010 )
1011 }
1012 0x07 => {
1013 ins!(
1014 [0x4e, 0x07],
1015 name = "write-ini-string",
1016 args = [string, string, string, string],
1017 )
1018 }
1019 _ => None,
1020 }
1021}
1022
1023fn op_4f_inc<'a>(code: &mut &'a [u8]) -> Option<Ins<'a>> {
1024 Some(Ins::Inc(read_var(code)?))
1025}
1026
1027fn op_57_dec<'a>(code: &mut &'a [u8]) -> Option<Ins<'a>> {
1028 Some(Ins::Dec(read_var(code)?))
1029}
1030
1031fn op_58<'a>(code: &mut &'a [u8]) -> Option<Ins<'a>> {
1032 match read_u8(code)? {
1033 0x0a => ins!([0x58, 0x0a], name = "timer-x0a", args = [int], retval),
1034 _ => None,
1035 }
1036}
1037
1038fn op_5c_jump_if<'a>(code: &mut &'a [u8]) -> Option<Ins<'a>> {
1039 Some(Ins::JumpIf(read_i16(code)?))
1040}
1041
1042fn op_5d_jump_unless<'a>(code: &mut &'a [u8]) -> Option<Ins<'a>> {
1043 Some(Ins::JumpUnless(read_i16(code)?))
1044}
1045
1046fn op_5e_run_script<'a>(code: &mut &'a [u8]) -> Option<Ins<'a>> {
1047 match read_u8(code)? {
1048 0x01 => ins!([0x5e, 0x01], name = "run-script", args = [script, list]),
1049 0xc3 => ins!([0x5e, 0xc3], name = "run-script-xc3", args = [script, list]),
1050 _ => None,
1051 }
1052}
1053
1054fn op_60_start_script<'a>(code: &mut &'a [u8]) -> Option<Ins<'a>> {
1055 match read_u8(code)? {
1056 0x01 => {
1057 ins!(
1058 [0x60, 0x01],
1059 name = "start-script",
1060 args = [script, int, list],
1061 )
1062 }
1063 0xc3 => {
1064 ins!(
1065 [0x60, 0xc3],
1066 name = "start-script-xc3",
1067 args = [script, int, list],
1068 )
1069 }
1070 _ => None,
1071 }
1072}
1073
1074fn op_61_draw_object<'a>(code: &mut &'a [u8]) -> Option<Ins<'a>> {
1075 match read_u8(code)? {
1076 0x3f => ins!([0x61, 0x3f], name = "draw-object-x3f", args = [int, int]),
1077 _ => None,
1078 }
1079}
1080
1081fn op_63_array_sizes<'a>(code: &mut &'a [u8]) -> Option<Ins<'a>> {
1082 match read_u8(code)? {
1083 0x01 => ins!([0x63, 0x01], name = "array-width", ops = [var: read_var(code)?], retval),
1084 0x03 => ins!([0x63, 0x03], name = "array-width", ops = [var: read_var(code)?], retval),
1085 0x02 => ins!([0x63, 0x02], name = "array-height", ops = [var: read_var(code)?], retval),
1086 _ => None,
1087 }
1088}
1089
1090fn op_69_window<'a>(code: &mut &'a [u8]) -> Option<Ins<'a>> {
1091 match read_u8(code)? {
1092 0x39 => ins!([0x69, 0x39], name = "window-select", args = [int]),
1093 0x3a => ins!([0x69, 0x3a], name = "window-x3a", args = [int]),
1094 0x3f => ins!([0x69, 0x3f], name = "window-set-image", args = [int]),
1095 0xd9 => ins!([0x69, 0xd9], name = "window-destroy"),
1096 0xf3 => ins!([0x69, 0xf3], name = "window-set-text", args = [string]),
1097 0xff => ins!([0x69, 0xff], name = "window-xff"),
1098 _ => None,
1099 }
1100}
1101
1102fn op_6b_cursor<'a>(code: &mut &'a [u8]) -> Option<Ins<'a>> {
1103 match read_u8(code)? {
1104 0x13 => ins!([0x6b, 0x13], name = "cursor-set-image-bw", args = [int]),
1105 0x14 => ins!([0x6b, 0x14], name = "cursor-set-image-color", args = [int]),
1106 0x90 => ins!([0x6b, 0x90], name = "cursor-show"),
1107 0x91 => ins!([0x6b, 0x91], name = "cursor-hide"),
1108 0x92 => ins!([0x6b, 0x92], name = "cursor-input-enable"),
1109 0x93 => ins!([0x6b, 0x93], name = "cursor-input-disable"),
1110 0x94 => ins!([0x6b, 0x94], name = "cursor-visible-increment"),
1111 0x95 => ins!([0x6b, 0x95], name = "cursor-visible-decrement"),
1112 0x9c => ins!([0x6b, 0x9c], name = "cursor-charset", args = [int]),
1113 _ => None,
1114 }
1115}
1116
1117fn op_73_jump<'a>(code: &mut &'a [u8]) -> Option<Ins<'a>> {
1118 Some(Ins::Jump(read_i16(code)?))
1119}
1120
1121fn op_74_sound<'a>(code: &mut &'a [u8]) -> Option<Ins<'a>> {
1122 match read_u8(code)? {
1123 0x09 => ins!([0x74, 0x09], name = "sound-x09"),
1124 0xe6 => ins!([0x74, 0xe6], name = "sound-channel", args = [int]),
1125 0xe7 => ins!([0x74, 0xe7], name = "sound-offset", args = [int]),
1126 0xe8 => ins!([0x74, 0xe8], name = "sound-select", args = [int]),
1127 0xf5 => ins!([0x74, 0xf5], name = "sound-xf5"),
1128 0xff => ins!([0x74, 0xff], name = "sound-play"),
1129 _ => None,
1130 }
1131}
1132
1133fn op_94<'a>(code: &mut &'a [u8]) -> Option<Ins<'a>> {
1134 match read_u8(code)? {
1135 0x42 => {
1136 ins!(
1137 [0x94, 0x42],
1138 name = "palette-x42",
1139 args = [int, int],
1140 retval,
1141 )
1142 }
1143 0xd9 => {
1144 ins!(
1145 [0x94, 0xd9],
1146 name = "palette-xd9",
1147 args = [int, int, int],
1148 retval,
1149 )
1150 }
1151 _ => None,
1152 }
1153}
1154
1155fn op_95_cutscene_start<'a>(code: &mut &'a [u8]) -> Option<Ins<'a>> {
1156 ins!([0x95], name = "cutscene-start", ops = [u8: read_u8(code)?, i16: read_i16(code)?])
1157}
1158
1159fn op_9b<'a>(code: &mut &'a [u8]) -> Option<Ins<'a>> {
1160 match read_u8(code)? {
1161 0x64 => ins!([0x9b, 0x64], name = "load-script", args = [script]),
1162 0x65 => ins!([0x9b, 0x65], name = "load-sound", args = [int]),
1163 0x66 => ins!([0x9b, 0x66], name = "load-costume", args = [int]),
1164 0x69 => ins!([0x9b, 0x69], name = "free-sound", args = [int]),
1165 0x6a => ins!([0x9b, 0x6a], name = "free-costume", args = [int]),
1166 0x6c => ins!([0x9b, 0x6c], name = "lock-script", args = [script]),
1167 0x6e => ins!([0x9b, 0x6e], name = "lock-costume", args = [int]),
1168 0x72 => ins!([0x9b, 0x72], name = "unlock-costume", args = [int]),
1169 0x75 => ins!([0x9b, 0x75], name = "load-charset", args = [int]),
1170 0x79 => ins!([0x9b, 0x79], name = "queue-sound", args = [int]),
1171 0x7a => ins!([0x9b, 0x7a], name = "queue-costume", args = [int]),
1172 0x7b => ins!([0x9b, 0x7b], name = "queue-room", args = [int]),
1173 0x9f => ins!([0x9b, 0x9f], name = "unlock-image", args = [int]),
1174 0xc0 => ins!([0x9b, 0xc0], name = "free-image", args = [int]),
1175 0xc9 => ins!([0x9b, 0xc9], name = "load-image", args = [int]),
1176 0xca => ins!([0x9b, 0xca], name = "lock-image", args = [int]),
1177 0xcb => ins!([0x9b, 0xcb], name = "queue-image", args = [int]),
1178 _ => None,
1179 }
1180}
1181
1182fn op_9c<'a>(code: &mut &'a [u8]) -> Option<Ins<'a>> {
1183 match read_u8(code)? {
1184 0xb5 => ins!([0x9c, 0xb5], args = [int]),
1185 0xd5 => ins!([0x9c, 0xd5], args = [int]),
1186 0xdd => ins!([0x9c, 0xdd], name = "save-load-game", args = [int, string]),
1187 _ => None,
1188 }
1189}
1190
1191fn op_9d_actor<'a>(code: &mut &'a [u8]) -> Option<Ins<'a>> {
1192 match read_u8(code)? {
1193 0x15 => ins!([0x9d, 0x15], name = "actor-set-conditons", args = [list]),
1194 0x2b => ins!([0x9d, 0x2b], name = "actor-x2b", args = [int]),
1195 0x40 => {
1196 ins!(
1197 [0x9d, 0x40],
1198 name = "actor-default-clip-rect",
1199 args = [int, int, int, int],
1200 )
1201 }
1202 0x41 => ins!([0x9d, 0x41], name = "actor-move", args = [int, int]),
1203 0x43 => {
1204 ins!(
1205 [0x9d, 0x43],
1206 name = "actor-clip-rect",
1207 args = [int, int, int, int],
1208 )
1209 }
1210 0x4c => ins!([0x9d, 0x4c], name = "actor-set-costume", args = [int]),
1211 0x4e => ins!([0x9d, 0x4e], name = "actor-set-sounds", args = [list]),
1212 0x50 => ins!([0x9d, 0x50], name = "actor-x50", args = [int, int]),
1213 0x54 => ins!([0x9d, 0x54], name = "actor-x54", args = [int]),
1214 0x56 => ins!([0x9d, 0x56], name = "actor-x56", args = [int, int]),
1215 0x57 => ins!([0x9d, 0x57], name = "actor-x57", args = [int]),
1216 0x5c => ins!([0x9d, 0x5c], name = "actor-set-scale", args = [int]),
1217 0x5d => ins!([0x9d, 0x5d], name = "actor-x5d"),
1218 0x5e => ins!([0x9d, 0x5e], name = "actor-x5e", args = [int]),
1219 0x5f => ins!([0x9d, 0x5f], name = "actor-x5f"),
1220 0x61 => ins!([0x9d, 0x61], name = "actor-x61", args = [int]),
1221 0x62 => ins!([0x9d, 0x62], name = "actor-x62", args = [int]),
1222 0x63 => ins!([0x9d, 0x63], name = "actor-x63", args = [int, int]),
1223 0xc5 => ins!([0x9d, 0xc5], name = "actor-select", args = [int]),
1224 0xc6 => ins!([0x9d, 0xc6], name = "actor-set-var", args = [int, int]),
1225 0xd9 => ins!([0x9d, 0xd9], name = "actor-xd9"),
1226 0xda => ins!([0x9d, 0xda], name = "actor-xda"),
1227 _ => None,
1228 }
1229}
1230
1231fn op_9e_palette<'a>(code: &mut &'a [u8]) -> Option<Ins<'a>> {
1232 match read_u8(code)? {
1233 0x39 => ins!([0x9e, 0x39], name = "palette-select", args = [int]),
1234 0x3f => ins!([0x9e, 0x3f], name = "palette-load", args = [int, int]),
1235 0x42 => {
1236 ins!(
1237 [0x9e, 0x42],
1238 name = "palette-set-rgb",
1239 args = [int, int, int, int, int],
1240 )
1241 }
1242 0x46 => {
1243 ins!(
1244 [0x9e, 0x46],
1245 name = "palette-set-16bit",
1246 args = [int, int, int],
1247 )
1248 }
1249 0x56 => ins!([0x9e, 0x56], name = "palette-copy", args = [int]),
1250 0xd9 => ins!([0x9e, 0xd9], name = "palette-reset"),
1251 0xff => ins!([0x9e, 0xff], name = "palette-unselect"),
1252 _ => None,
1253 }
1254}
1255
1256fn op_a4_array<'a>(code: &mut &'a [u8]) -> Option<Ins<'a>> {
1257 match read_u8(code)? {
1258 0x07 => Some(Ins::AssignString(read_var(code)?)),
1259 0x7e => {
1260 ins!(
1261 [0xa4, 0x7e],
1262 name = "array-fill-list",
1263 ops = [var: read_var(code)?],
1264 args = [int, int, int, int, list],
1265 )
1266 }
1267 0x7f => {
1268 ins!(
1269 [0xa4, 0x7f],
1270 name = "array-copy-range",
1271 ops = [var: read_var(code)?, var: read_var(code)?],
1272 args = [int, int, int, int, int, int, int, int],
1273 )
1274 }
1275 0x80 => {
1276 ins!(
1277 [0xa4, 0x80],
1278 name = "array-fill-values",
1279 ops = [var: read_var(code)?],
1280 args = [int, int, int, int, int, int],
1281 )
1282 }
1283 0xc2 => Some(Ins::Sprintf(read_var(code)?)),
1284 0xd0 => {
1285 ins!(
1286 [0xa4, 0xd0],
1287 name = "array-set",
1288 ops = [var: read_var(code)?],
1289 args = [list, int],
1290 )
1291 }
1292 0xd4 => {
1293 ins!(
1294 [0xa4, 0xd4],
1295 name = "array-set-row",
1296 ops = [var: read_var(code)?],
1297 args = [int, list],
1298 )
1299 }
1300 _ => None,
1301 }
1302}
1303
1304fn op_a9<'a>(code: &mut &'a [u8]) -> Option<Ins<'a>> {
1305 match read_u8(code)? {
1306 0xa9 => ins!([0xa9, 0xa9]),
1307 _ => None,
1308 }
1309}
1310
1311fn op_ae<'a>(code: &mut &'a [u8]) -> Option<Ins<'a>> {
1312 match read_u8(code)? {
1313 0x1a => ins!([0xae, 0x1a], name = "paint"),
1314 0xa0 => ins!([0xae, 0xa0], name = "quit-without-prompt"),
1315 0xf4 => ins!([0xae, 0xf4], name = "prompt-quit"),
1316 _ => None,
1317 }
1318}
1319
1320fn op_b5<'a>(code: &mut &'a [u8]) -> Option<Ins<'a>> {
1321 op_b4_thru_b9(0xb5, false, code)
1322}
1323
1324fn op_b6<'a>(code: &mut &'a [u8]) -> Option<Ins<'a>> {
1325 op_b4_thru_b9(0xb6, false, code)
1326}
1327
1328fn op_b7<'a>(code: &mut &'a [u8]) -> Option<Ins<'a>> {
1329 op_b4_thru_b9(0xb7, false, code)
1330}
1331
1332fn op_b8<'a>(code: &mut &'a [u8]) -> Option<Ins<'a>> {
1333 op_b4_thru_b9(0xb8, true, code)
1334}
1335
1336fn op_b9<'a>(code: &mut &'a [u8]) -> Option<Ins<'a>> {
1337 op_b4_thru_b9(0xb9, true, code)
1338}
1339
1340fn op_b4_thru_b9<'a>(opcode: u8, flag: bool, code: &mut &'a [u8]) -> Option<Ins<'a>> {
1341 let sub = read_u8(code)?;
1342 let stack_hack = opcode == 0xb9;
1343 if stack_hack && sub != 0xfe {
1344 return None;
1345 }
1346 match sub {
1347 0x41 => ins!([opcode, 0x41], args = [int, int]),
1348 0x45 => ins!([opcode, 0x45]),
1349 0x4b => ins!([opcode, 0x4b], ops = [string: read_string(code)?]),
1350 0xc2 => ins!([opcode, 0xc2], ops = [string: read_string(code)?], args = [int, list]),
1351 0xe1 => ins!([opcode, 0xe1], args = [int]),
1352 0xf9 => ins!([opcode, 0xf9], args = [list]),
1353 0xfe => {
1354 Some(Ins::Generic(
1355 bytearray![opcode, 0xfe],
1356 ArrayVec::new(),
1357 if flag && !stack_hack {
1358 &GenericIns {
1359 name: None,
1360 args: &[GenericArg::Int],
1361 returns_value: false,
1362 }
1363 } else {
1364 &GenericIns {
1365 name: None,
1366 args: &[],
1367 returns_value: false,
1368 }
1369 },
1370 ))
1371 }
1372 0xff => ins!([opcode, 0xff]),
1373 _ => None,
1374 }
1375}
1376
1377fn op_bc_array<'a>(code: &mut &'a [u8]) -> Option<Ins<'a>> {
1378 let n = read_u8(code)?;
1379 if let Some(item_size) = to_item_size(n) {
1380 return Some(Ins::DimArray1DSimple(item_size, read_var(code)?));
1381 }
1382 match n {
1383 0xcc => ins!([0xbc, 0xcc], name = "free-array", ops = [var: read_var(code)?]),
1384 _ => None,
1385 }
1386}
1387
1388fn op_c0_dim_array<'a>(code: &mut &'a [u8]) -> Option<Ins<'a>> {
1389 let item_size = to_item_size(read_u8(code)?)?;
1390 let var = read_var(code)?;
1391 Some(Ins::DimArray2DSimple(item_size, var))
1392}
1393
1394fn op_d5_exec_script<'a>(code: &mut &'a [u8]) -> Option<Ins<'a>> {
1395 match read_u8(code)? {
1396 0x01 => {
1397 ins!([0xd5, 0x01], name = "exec-script", args = [script, list])
1398 }
1399 0xc3 => {
1400 ins!(
1401 [0xd5, 0xc3],
1402 name = "exec-script-xc3",
1403 args = [script, list],
1404 )
1405 }
1406 _ => None,
1407 }
1408}
1409
1410fn op_db_file_read<'a>(code: &mut &'a [u8]) -> Option<Ins<'a>> {
1411 match read_u8(code)? {
1412 0x05 => ins!([0xdb, 0x05], name = "file-read-i16", args = [int], retval),
1413 0x08 => {
1414 ins!(
1415 [0xdb, 0x08],
1416 name = "file-read-array",
1417 ops = [u8: read_u8(code)?],
1418 args = [int, int],
1419 retval,
1420 )
1421 }
1422 _ => None,
1423 }
1424}
1425
1426fn op_dc_file_write<'a>(code: &mut &'a [u8]) -> Option<Ins<'a>> {
1427 match read_u8(code)? {
1428 0x05 => ins!([0xdc, 0x05], name = "file-write-i16", args = [int, int]),
1429 0x08 => {
1430 ins!(
1431 [0xdc, 0x08],
1432 name = "file-write-array",
1433 ops = [u8: read_u8(code)?],
1434 args = [int, int],
1435 )
1436 }
1437 _ => None,
1438 }
1439}
1440
1441fn op_e0<'a>(code: &mut &'a [u8]) -> Option<Ins<'a>> {
1442 match read_u8(code)? {
1443 0x42 => ins!([0xe0, 0x42], args = [int, int, int, int, int, int]),
1444 _ => None,
1445 }
1446}
1447
1448fn op_f2_percent_loaded<'a>(code: &mut &'a [u8]) -> Option<Ins<'a>> {
1449 match read_u8(code)? {
1450 0xe3 => {
1451 ins!(
1452 [0xf2, 0xe3],
1453 name = "percent-loaded-costume",
1454 args = [int],
1455 retval,
1456 )
1457 }
1458 _ => None,
1459 }
1460}
1461
1462fn op_f3_read_ini<'a>(code: &mut &'a [u8]) -> Option<Ins<'a>> {
1463 match read_u8(code)? {
1464 0x06 => ins!([0xf3, 0x06], name = "read-ini-int", args = [string], retval),
1465 0x07 => {
1466 ins!(
1467 [0xf3, 0x07],
1468 name = "read-ini-string",
1469 args = [string],
1470 retval,
1471 )
1472 }
1473 _ => None,
1474 }
1475}
1476
1477fn op_f4_write_ini<'a>(code: &mut &'a [u8]) -> Option<Ins<'a>> {
1478 match read_u8(code)? {
1479 0x06 => ins!([0xf4, 0x06], name = "write-ini-int", args = [string, int]),
1480 0x07 => {
1481 ins!(
1482 [0xf4, 0x07],
1483 name = "write-ini-string",
1484 args = [string, string],
1485 )
1486 }
1487 _ => None,
1488 }
1489}
1490
1491fn op_f8_get_size<'a>(code: &mut &'a [u8]) -> Option<Ins<'a>> {
1492 match read_u8(code)? {
1493 0x0d => ins!([0xf8, 0x0d], name = "get-sound-size", args = [int], retval),
1494 _ => None,
1495 }
1496}
1497
1498fn op_fa_window_title<'a>(code: &mut &'a [u8]) -> Option<Ins<'a>> {
1499 match read_u8(code)? {
1500 0xf3 => ins!([0xfa, 0xf3], name = "set-window-title", args = [string]),
1501 _ => None,
1502 }
1503}
1504
1505fn op_fb<'a>(code: &mut &'a [u8]) -> Option<Ins<'a>> {
1506 match read_u8(code)? {
1507 0xf7 => ins!([0xfb, 0xf7], name = "polygon-xf7", args = [int, int]),
1508 0xf8 => {
1509 ins!(
1510 [0xfb, 0xf8],
1511 name = "polygon-quadrilateral",
1512 args = [int, int, int, int, int, int, int, int, int],
1513 )
1514 }
1515 _ => None,
1516 }
1517}