mirror of
https://github.com/G2-Games/lbee-utils.git
synced 2025-04-19 15:22:53 -05:00
More work reverse engineering scripts
This commit is contained in:
parent
866f353353
commit
43b65cf173
2 changed files with 121 additions and 158 deletions
|
@ -5,7 +5,9 @@ edition = "2021"
|
||||||
authors.workspace = true
|
authors.workspace = true
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
int-enum = "1.1.2"
|
byteorder = "1.5"
|
||||||
|
num-derive = "0.4"
|
||||||
|
num-traits = "0.2"
|
||||||
|
|
||||||
[lints]
|
[lints]
|
||||||
workspace = true
|
workspace = true
|
||||||
|
|
|
@ -1,8 +1,57 @@
|
||||||
use std::{fs::File, io::Read};
|
use std::{fs::File, io::{Read, Seek}, process::exit};
|
||||||
|
use byteorder::{ReadBytesExt, LE};
|
||||||
|
use num_derive::{FromPrimitive, ToPrimitive};
|
||||||
|
use num_traits::{FromPrimitive, ToPrimitive};
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let mut script = File::open("LOOPERS_scenario_01").unwrap();
|
||||||
|
|
||||||
|
while let Ok(byte) = script.read_u8() {
|
||||||
|
if let Some(opcode) = Opcode::from_u8(byte) {
|
||||||
|
println!(
|
||||||
|
"{:X?}: {:#04X?} ({:?})",
|
||||||
|
script.stream_position().unwrap() - 1,
|
||||||
|
opcode.to_u8().unwrap(),
|
||||||
|
opcode
|
||||||
|
);
|
||||||
|
if opcode == Opcode::TASK {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
match opcode {
|
||||||
|
Opcode::MESSAGE => {
|
||||||
|
let variables = script.read_u8().unwrap();
|
||||||
|
match variables {
|
||||||
|
1 => continue,
|
||||||
|
4 => {
|
||||||
|
dbg!(script.read_u32::<LE>().unwrap());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
let message = Message {
|
||||||
|
variables,
|
||||||
|
unknown1: Some(script.read_u16::<LE>().unwrap()),
|
||||||
|
unknown2: Some(script.read_u16::<LE>().unwrap()),
|
||||||
|
index: Some(script.read_u16::<LE>().unwrap()),
|
||||||
|
messages: Some((0..3).map(|_| ScriptString::read(&mut script)).collect()),
|
||||||
|
};
|
||||||
|
message.messages.unwrap().iter().for_each(|m| println!("{}", m.to_string()));
|
||||||
|
println!("-----");
|
||||||
|
},
|
||||||
|
Opcode::JUMP => {
|
||||||
|
dbg!(script.read_u32::<LE>().unwrap());
|
||||||
|
println!("------");
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[allow(non_camel_case_types)]
|
#[allow(non_camel_case_types)]
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
|
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
|
#[derive(FromPrimitive, ToPrimitive)]
|
||||||
enum Opcode {
|
enum Opcode {
|
||||||
EQU,
|
EQU,
|
||||||
EQUN,
|
EQUN,
|
||||||
|
@ -143,165 +192,77 @@ enum Opcode {
|
||||||
UNKNOWN
|
UNKNOWN
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<u8> for Opcode {
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
type Error = ();
|
struct Message {
|
||||||
|
variables: u8,
|
||||||
|
unknown1: Option<u16>,
|
||||||
|
unknown2: Option<u16>,
|
||||||
|
index: Option<u16>,
|
||||||
|
|
||||||
fn try_from(value: u8) -> Result<Self, Self::Error> {
|
messages: Option<Vec<ScriptString>>,
|
||||||
let val = match value {
|
}
|
||||||
0 => Opcode::EQU,
|
|
||||||
1 => Opcode::EQUN,
|
impl Default for Message {
|
||||||
2 => Opcode::EQUV,
|
fn default() -> Self {
|
||||||
3 => Opcode::ADD,
|
Self {
|
||||||
4 => Opcode::SUB,
|
variables: 1,
|
||||||
5 => Opcode::MUL,
|
unknown1: None,
|
||||||
6 => Opcode::DIV,
|
unknown2: None,
|
||||||
7 => Opcode::MOD,
|
index: None,
|
||||||
8 => Opcode::AND,
|
messages: None
|
||||||
9 => Opcode::OR,
|
}
|
||||||
10 => Opcode::RANDOM,
|
}
|
||||||
11 => Opcode::VARSTR,
|
}
|
||||||
12 => Opcode::VARSTR_ADD,
|
|
||||||
13 => Opcode::SET,
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
14 => Opcode::FLAGCLR,
|
struct ScriptString {
|
||||||
15 => Opcode::GOTO,
|
length: i16,
|
||||||
16 => Opcode::ONGOTO,
|
format: StringFormat,
|
||||||
17 => Opcode::GOSUB,
|
buffer: Vec<u8>,
|
||||||
18 => Opcode::IFY,
|
}
|
||||||
19 => Opcode::IFN,
|
|
||||||
20 => Opcode::RETURN,
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
21 => Opcode::JUMP,
|
enum StringFormat {
|
||||||
22 => Opcode::FARCALL,
|
UTF8,
|
||||||
23 => Opcode::FARRETURN,
|
UTF16,
|
||||||
24 => Opcode::JUMPPOINT,
|
ShiftJIS,
|
||||||
25 => Opcode::END,
|
ASCII,
|
||||||
26 => Opcode::STARTUP_BEGIN,
|
}
|
||||||
27 => Opcode::STARTUP_END,
|
|
||||||
28 => Opcode::TASKSCRVAR,
|
impl ScriptString {
|
||||||
29 => Opcode::VARSTR_SET,
|
fn read<R: Read + ReadBytesExt>(input: &mut R) -> Self {
|
||||||
30 => Opcode::VARSTR_ALLOC,
|
let length = input.read_i16::<LE>().unwrap();
|
||||||
31 => Opcode::ARFLAGSET,
|
let (mut buffer, format) = if length < 0 {
|
||||||
32 => Opcode::COLORBG_SET,
|
// If the length is negative, then the length is the exact length in
|
||||||
33 => Opcode::SPLINE_SET,
|
// bytes??
|
||||||
34 => Opcode::SHAKELIST_SET,
|
(vec![0u8; length.abs() as usize + 1], StringFormat::UTF8)
|
||||||
35 => Opcode::SCISSOR_TRIANGLELIST_SET,
|
} else {
|
||||||
36 => Opcode::MESSAGE,
|
// Otherwise double the length
|
||||||
37 => Opcode::MESSAGE_CLEAR,
|
(vec![0u8; (length as usize + 1) * 2], StringFormat::UTF16)
|
||||||
38 => Opcode::MESSAGE_WAIT,
|
|
||||||
39 => Opcode::MESSAGE_AR_SET,
|
|
||||||
40 => Opcode::SELECT,
|
|
||||||
41 => Opcode::CLOSE_WINDOW,
|
|
||||||
42 => Opcode::FADE_WINDOW,
|
|
||||||
43 => Opcode::LOG_BEGIN,
|
|
||||||
44 => Opcode::LOG_PAUSE,
|
|
||||||
45 => Opcode::LOG_END,
|
|
||||||
46 => Opcode::VOICE,
|
|
||||||
47 => Opcode::VOICE_STOP,
|
|
||||||
48 => Opcode::WAIT_COUNT,
|
|
||||||
49 => Opcode::WAIT_TIME,
|
|
||||||
50 => Opcode::WAIT_TEXTFEED,
|
|
||||||
51 => Opcode::FFSTOP,
|
|
||||||
52 => Opcode::INIT,
|
|
||||||
53 => Opcode::STOP,
|
|
||||||
54 => Opcode::IMAGELOAD,
|
|
||||||
55 => Opcode::IMAGEUPDATE,
|
|
||||||
56 => Opcode::ARC,
|
|
||||||
57 => Opcode::MOVE,
|
|
||||||
58 => Opcode::MOVE_SKIP,
|
|
||||||
59 => Opcode::ROT,
|
|
||||||
60 => Opcode::PEND,
|
|
||||||
61 => Opcode::FADE,
|
|
||||||
62 => Opcode::SCALE,
|
|
||||||
63 => Opcode::SHAKE,
|
|
||||||
64 => Opcode::SHAKELIST,
|
|
||||||
65 => Opcode::BASE,
|
|
||||||
66 => Opcode::MCMOVE,
|
|
||||||
67 => Opcode::MCARC,
|
|
||||||
68 => Opcode::MCROT,
|
|
||||||
69 => Opcode::MCSHAKE,
|
|
||||||
70 => Opcode::MCFADE,
|
|
||||||
71 => Opcode::WAIT,
|
|
||||||
72 => Opcode::WAIT_BSKIP,
|
|
||||||
73 => Opcode::DRAW,
|
|
||||||
74 => Opcode::WIPE,
|
|
||||||
75 => Opcode::FRAMEON,
|
|
||||||
76 => Opcode::FRAMEOFF,
|
|
||||||
77 => Opcode::FW,
|
|
||||||
78 => Opcode::SCISSOR,
|
|
||||||
79 => Opcode::DELAY,
|
|
||||||
80 => Opcode::RASTER,
|
|
||||||
81 => Opcode::TONE,
|
|
||||||
82 => Opcode::SCALECOSSIN,
|
|
||||||
83 => Opcode::BMODE,
|
|
||||||
84 => Opcode::SIZE,
|
|
||||||
85 => Opcode::SPLINE,
|
|
||||||
86 => Opcode::DISP,
|
|
||||||
87 => Opcode::MASK,
|
|
||||||
88 => Opcode::FACE,
|
|
||||||
89 => Opcode::SEPIA,
|
|
||||||
90 => Opcode::SEPIA_COLOR,
|
|
||||||
91 => Opcode::CUSTOMMOVE,
|
|
||||||
92 => Opcode::SWAP,
|
|
||||||
93 => Opcode::ADDCOLOR,
|
|
||||||
94 => Opcode::SUBCOLOR,
|
|
||||||
95 => Opcode::SATURATION,
|
|
||||||
96 => Opcode::CONTRAST,
|
|
||||||
97 => Opcode::PRIORITY,
|
|
||||||
98 => Opcode::UVWH,
|
|
||||||
99 => Opcode::EVSCROLL,
|
|
||||||
100 => Opcode::COLORLEVEL,
|
|
||||||
101 => Opcode::NEGA,
|
|
||||||
102 => Opcode::TONECURVE,
|
|
||||||
103 => Opcode::SKIP_SCOPE_BEGIN,
|
|
||||||
104 => Opcode::SKIP_SCOPE_END,
|
|
||||||
105 => Opcode::QUAKE,
|
|
||||||
106 => Opcode::BGM,
|
|
||||||
107 => Opcode::BGM_WAIT_START,
|
|
||||||
108 => Opcode::BGM_WAIT_FADE,
|
|
||||||
109 => Opcode::BGM_PUSH,
|
|
||||||
110 => Opcode::BGM_POP,
|
|
||||||
111 => Opcode::SE,
|
|
||||||
112 => Opcode::SE_STOP,
|
|
||||||
113 => Opcode::SE_WAIT,
|
|
||||||
114 => Opcode::SE_WAIT_COUNT,
|
|
||||||
115 => Opcode::SE_WAIT_FADE,
|
|
||||||
116 => Opcode::VOLUME,
|
|
||||||
117 => Opcode::MOVIE,
|
|
||||||
118 => Opcode::SETCGFLAG,
|
|
||||||
119 => Opcode::EX,
|
|
||||||
120 => Opcode::TROPHY,
|
|
||||||
121 => Opcode::SETBGMFLAG,
|
|
||||||
122 => Opcode::TASK,
|
|
||||||
123 => Opcode::PRINTF,
|
|
||||||
124 => Opcode::DIALOG,
|
|
||||||
125 => Opcode::VIB_PLAY,
|
|
||||||
126 => Opcode::VIB_FILE,
|
|
||||||
127 => Opcode::VIB_STOP,
|
|
||||||
128 => Opcode::CHAR_VOLUME,
|
|
||||||
129 => Opcode::SCENE_REPLAY_END,
|
|
||||||
130 => Opcode::SAVE_THUMBNAIL,
|
|
||||||
131 => Opcode::MANPU,
|
|
||||||
132 => Opcode::SCENARIO,
|
|
||||||
133 => Opcode::SCRIPTLINE,
|
|
||||||
134 => Opcode::COUNTER_SET,
|
|
||||||
135 => Opcode::COUNTER_WAIT,
|
|
||||||
_ => return Err(()),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(val)
|
input.read_exact(&mut buffer).unwrap();
|
||||||
|
|
||||||
|
Self {
|
||||||
|
length,
|
||||||
|
format,
|
||||||
|
buffer,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
impl ToString for ScriptString {
|
||||||
let script = File::open("LOOPERS_scenario_01").unwrap();
|
fn to_string(&self) -> String {
|
||||||
|
match self.format {
|
||||||
for byte in script.bytes().enumerate() {
|
StringFormat::UTF8 => String::from_utf8_lossy(&self.buffer).to_string(),
|
||||||
match Opcode::try_from(byte.1.unwrap()) {
|
StringFormat::UTF16 => {
|
||||||
Ok(v) => {
|
String::from_utf16_lossy(
|
||||||
if v == Opcode::MESSAGE {
|
&self.buffer
|
||||||
println!("{:0X?}: {:?}", byte.0, v)
|
.chunks(2)
|
||||||
}
|
.map(|c| u16::from_le_bytes(c.try_into().unwrap())).collect::<Vec<u16>>()).to_owned()
|
||||||
},
|
},
|
||||||
Err(e) => (),
|
StringFormat::ASCII => String::from_utf8_lossy(&self.buffer).to_string(),
|
||||||
|
_ => unimplemented!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue