Badly encrypted. Bytecode. Text inline. Bytecode implementation here is hacky.
There are two versions of the ripper for this engine. I used one on katahane and the other on sukinara. Both are given here.
Katahane:
1 #include <stdint.h>
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include <string>
6
7 uint8_t key[1024] = {
8 0x00,0x00,0x00,0x00,0x96,0x30,0x07,0x77,0x2c,0x61,0x0e,0xee,0xba,0x51,0x09,0x99,
9 0x19,0xc4,0x6d,0x07,0x8f,0xf4,0x6a,0x70,0x35,0xa5,0x63,0xe9,0xa3,0x95,0x64,0x9e,
10 0x32,0x88,0xdb,0x0e,0xa4,0xb8,0xdc,0x79,0x1e,0xe9,0xd5,0xe0,0x88,0xd9,0xd2,0x97,
11 0x2b,0x4c,0xb6,0x09,0xbd,0x7c,0xb1,0x7e,0x07,0x2d,0xb8,0xe7,0x91,0x1d,0xbf,0x90,
12 0x64,0x10,0xb7,0x1d,0xf2,0x20,0xb0,0x6a,0x48,0x71,0xb9,0xf3,0xde,0x41,0xbe,0x84,
13 0x7d,0xd4,0xda,0x1a,0xeb,0xe4,0xdd,0x6d,0x51,0xb5,0xd4,0xf4,0xc7,0x85,0xd3,0x83,
14 0x56,0x98,0x6c,0x13,0xc0,0xa8,0x6b,0x64,0x7a,0xf9,0x62,0xfd,0xec,0xc9,0x65,0x8a,
15 0x4f,0x5c,0x01,0x14,0xd9,0x6c,0x06,0x63,0x63,0x3d,0x0f,0xfa,0xf5,0x0d,0x08,0x8d,
16 0xc8,0x20,0x6e,0x3b,0x5e,0x10,0x69,0x4c,0xe4,0x41,0x60,0xd5,0x72,0x71,0x67,0xa2,
17 0xd1,0xe4,0x03,0x3c,0x47,0xd4,0x04,0x4b,0xfd,0x85,0x0d,0xd2,0x6b,0xb5,0x0a,0xa5,
18 0xfa,0xa8,0xb5,0x35,0x6c,0x98,0xb2,0x42,0xd6,0xc9,0xbb,0xdb,0x40,0xf9,0xbc,0xac,
19 0xe3,0x6c,0xd8,0x32,0x75,0x5c,0xdf,0x45,0xcf,0x0d,0xd6,0xdc,0x59,0x3d,0xd1,0xab,
20 0xac,0x30,0xd9,0x26,0x3a,0x00,0xde,0x51,0x80,0x51,0xd7,0xc8,0x16,0x61,0xd0,0xbf,
21 0xb5,0xf4,0xb4,0x21,0x23,0xc4,0xb3,0x56,0x99,0x95,0xba,0xcf,0x0f,0xa5,0xbd,0xb8,
22 0x9e,0xb8,0x02,0x28,0x08,0x88,0x05,0x5f,0xb2,0xd9,0x0c,0xc6,0x24,0xe9,0x0b,0xb1,
23 0x87,0x7c,0x6f,0x2f,0x11,0x4c,0x68,0x58,0xab,0x1d,0x61,0xc1,0x3d,0x2d,0x66,0xb6,
24 0x90,0x41,0xdc,0x76,0x06,0x71,0xdb,0x01,0xbc,0x20,0xd2,0x98,0x2a,0x10,0xd5,0xef,
25 0x89,0x85,0xb1,0x71,0x1f,0xb5,0xb6,0x06,0xa5,0xe4,0xbf,0x9f,0x33,0xd4,0xb8,0xe8,
26 0xa2,0xc9,0x07,0x78,0x34,0xf9,0x00,0x0f,0x8e,0xa8,0x09,0x96,0x18,0x98,0x0e,0xe1,
27 0xbb,0x0d,0x6a,0x7f,0x2d,0x3d,0x6d,0x08,0x97,0x6c,0x64,0x91,0x01,0x5c,0x63,0xe6,
28 0xf4,0x51,0x6b,0x6b,0x62,0x61,0x6c,0x1c,0xd8,0x30,0x65,0x85,0x4e,0x00,0x62,0xf2,
29 0xed,0x95,0x06,0x6c,0x7b,0xa5,0x01,0x1b,0xc1,0xf4,0x08,0x82,0x57,0xc4,0x0f,0xf5,
30 0xc6,0xd9,0xb0,0x65,0x50,0xe9,0xb7,0x12,0xea,0xb8,0xbe,0x8b,0x7c,0x88,0xb9,0xfc,
31 0xdf,0x1d,0xdd,0x62,0x49,0x2d,0xda,0x15,0xf3,0x7c,0xd3,0x8c,0x65,0x4c,0xd4,0xfb,
32 0x58,0x61,0xb2,0x4d,0xce,0x51,0xb5,0x3a,0x74,0x00,0xbc,0xa3,0xe2,0x30,0xbb,0xd4,
33 0x41,0xa5,0xdf,0x4a,0xd7,0x95,0xd8,0x3d,0x6d,0xc4,0xd1,0xa4,0xfb,0xf4,0xd6,0xd3,
34 0x6a,0xe9,0x69,0x43,0xfc,0xd9,0x6e,0x34,0x46,0x88,0x67,0xad,0xd0,0xb8,0x60,0xda,
35 0x73,0x2d,0x04,0x44,0xe5,0x1d,0x03,0x33,0x5f,0x4c,0x0a,0xaa,0xc9,0x7c,0x0d,0xdd,
36 0x3c,0x71,0x05,0x50,0xaa,0x41,0x02,0x27,0x10,0x10,0x0b,0xbe,0x86,0x20,0x0c,0xc9,
37 0x25,0xb5,0x68,0x57,0xb3,0x85,0x6f,0x20,0x09,0xd4,0x66,0xb9,0x9f,0xe4,0x61,0xce,
38 0x0e,0xf9,0xde,0x5e,0x98,0xc9,0xd9,0x29,0x22,0x98,0xd0,0xb0,0xb4,0xa8,0xd7,0xc7,
39 0x17,0x3d,0xb3,0x59,0x81,0x0d,0xb4,0x2e,0x3b,0x5c,0xbd,0xb7,0xad,0x6c,0xba,0xc0,
40 0x20,0x83,0xb8,0xed,0xb6,0xb3,0xbf,0x9a,0x0c,0xe2,0xb6,0x03,0x9a,0xd2,0xb1,0x74,
41 0x39,0x47,0xd5,0xea,0xaf,0x77,0xd2,0x9d,0x15,0x26,0xdb,0x04,0x83,0x16,0xdc,0x73,
42 0x12,0x0b,0x63,0xe3,0x84,0x3b,0x64,0x94,0x3e,0x6a,0x6d,0x0d,0xa8,0x5a,0x6a,0x7a,
43 0x0b,0xcf,0x0e,0xe4,0x9d,0xff,0x09,0x93,0x27,0xae,0x00,0x0a,0xb1,0x9e,0x07,0x7d,
44 0x44,0x93,0x0f,0xf0,0xd2,0xa3,0x08,0x87,0x68,0xf2,0x01,0x1e,0xfe,0xc2,0x06,0x69,
45 0x5d,0x57,0x62,0xf7,0xcb,0x67,0x65,0x80,0x71,0x36,0x6c,0x19,0xe7,0x06,0x6b,0x6e,
46 0x76,0x1b,0xd4,0xfe,0xe0,0x2b,0xd3,0x89,0x5a,0x7a,0xda,0x10,0xcc,0x4a,0xdd,0x67,
47 0x6f,0xdf,0xb9,0xf9,0xf9,0xef,0xbe,0x8e,0x43,0xbe,0xb7,0x17,0xd5,0x8e,0xb0,0x60,
48 0xe8,0xa3,0xd6,0xd6,0x7e,0x93,0xd1,0xa1,0xc4,0xc2,0xd8,0x38,0x52,0xf2,0xdf,0x4f,
49 0xf1,0x67,0xbb,0xd1,0x67,0x57,0xbc,0xa6,0xdd,0x06,0xb5,0x3f,0x4b,0x36,0xb2,0x48,
50 0xda,0x2b,0x0d,0xd8,0x4c,0x1b,0x0a,0xaf,0xf6,0x4a,0x03,0x36,0x60,0x7a,0x04,0x41,
51 0xc3,0xef,0x60,0xdf,0x55,0xdf,0x67,0xa8,0xef,0x8e,0x6e,0x31,0x79,0xbe,0x69,0x46,
52 0x8c,0xb3,0x61,0xcb,0x1a,0x83,0x66,0xbc,0xa0,0xd2,0x6f,0x25,0x36,0xe2,0x68,0x52,
53 0x95,0x77,0x0c,0xcc,0x03,0x47,0x0b,0xbb,0xb9,0x16,0x02,0x22,0x2f,0x26,0x05,0x55,
54 0xbe,0x3b,0xba,0xc5,0x28,0x0b,0xbd,0xb2,0x92,0x5a,0xb4,0x2b,0x04,0x6a,0xb3,0x5c,
55 0xa7,0xff,0xd7,0xc2,0x31,0xcf,0xd0,0xb5,0x8b,0x9e,0xd9,0x2c,0x1d,0xae,0xde,0x5b,
56 0xb0,0xc2,0x64,0x9b,0x26,0xf2,0x63,0xec,0x9c,0xa3,0x6a,0x75,0x0a,0x93,0x6d,0x02,
57 0xa9,0x06,0x09,0x9c,0x3f,0x36,0x0e,0xeb,0x85,0x67,0x07,0x72,0x13,0x57,0x00,0x05,
58 0x82,0x4a,0xbf,0x95,0x14,0x7a,0xb8,0xe2,0xae,0x2b,0xb1,0x7b,0x38,0x1b,0xb6,0x0c,
59 0x9b,0x8e,0xd2,0x92,0x0d,0xbe,0xd5,0xe5,0xb7,0xef,0xdc,0x7c,0x21,0xdf,0xdb,0x0b,
60 0xd4,0xd2,0xd3,0x86,0x42,0xe2,0xd4,0xf1,0xf8,0xb3,0xdd,0x68,0x6e,0x83,0xda,0x1f,
61 0xcd,0x16,0xbe,0x81,0x5b,0x26,0xb9,0xf6,0xe1,0x77,0xb0,0x6f,0x77,0x47,0xb7,0x18,
62 0xe6,0x5a,0x08,0x88,0x70,0x6a,0x0f,0xff,0xca,0x3b,0x06,0x66,0x5c,0x0b,0x01,0x11,
63 0xff,0x9e,0x65,0x8f,0x69,0xae,0x62,0xf8,0xd3,0xff,0x6b,0x61,0x45,0xcf,0x6c,0x16,
64 0x78,0xe2,0x0a,0xa0,0xee,0xd2,0x0d,0xd7,0x54,0x83,0x04,0x4e,0xc2,0xb3,0x03,0x39,
65 0x61,0x26,0x67,0xa7,0xf7,0x16,0x60,0xd0,0x4d,0x47,0x69,0x49,0xdb,0x77,0x6e,0x3e,
66 0x4a,0x6a,0xd1,0xae,0xdc,0x5a,0xd6,0xd9,0x66,0x0b,0xdf,0x40,0xf0,0x3b,0xd8,0x37,
67 0x53,0xae,0xbc,0xa9,0xc5,0x9e,0xbb,0xde,0x7f,0xcf,0xb2,0x47,0xe9,0xff,0xb5,0x30,
68 0x1c,0xf2,0xbd,0xbd,0x8a,0xc2,0xba,0xca,0x30,0x93,0xb3,0x53,0xa6,0xa3,0xb4,0x24,
69 0x05,0x36,0xd0,0xba,0x93,0x06,0xd7,0xcd,0x29,0x57,0xde,0x54,0xbf,0x67,0xd9,0x23,
70 0x2e,0x7a,0x66,0xb3,0xb8,0x4a,0x61,0xc4,0x02,0x1b,0x68,0x5d,0x94,0x2b,0x6f,0x2a,
71 0x37,0xbe,0x0b,0xb4,0xa1,0x8e,0x0c,0xc3,0x1b,0xdf,0x05,0x5a,0x8d,0xef,0x02,0x2d};
72
73 void fread_or_die(void * a, size_t b, size_t c, FILE * d)
74 {
75 size_t got = fread(a, b, c, d);
76 if(feof(d)) {puts("feof"); exit(0);}
77 if(ferror(d)) {puts("ferror"); exit(0);}
78 if(got != c) {exit(0);}
79 }
80
81 bool is_jis_surrogate(uint8_t c)
82 {
83 if(c >= 0x80 and c <= 0xA0) return true;
84 if(c >= 0xE0) return true;
85 return false;
86 }
87
88 int main(int argc, char ** argv)
89 {
90 //16 header
91 //4 ?
92 //4 ?
93 //4 num?
94 //8[num?] ?
95 //4 scriptsize
96 //1 script[scriptsize]
97 if(argc < 2) return puts("usage: unmjo file.mjo"), 0;
98 auto f = fopen(argv[1], "rb");
99
100 char magic[16];
101 fread(magic, 1, 16, f);
102 if(strncmp(magic, "MajiroObjX1.000", 16) != 0) return puts("unsupported file"), puts(argv[1]), 0;
103
104 uint32_t crap[2];
105 fread(crap, 4, 2, f);
106
107 uint32_t numoffsets;
108 fread(&numoffsets, 4, 1, f);
109
110 for(uint32_t i = 0; i < numoffsets; i++)
111 {
112 uint32_t offsetdata[2];
113 fread(offsetdata, 4, 2, f);
114 }
115
116 uint32_t length;
117 fread(&length, 4, 1, f);
118
119 unsigned char * data = (unsigned char *)malloc(length);
120 fread(data, 1, length, f);
121
122 uint32_t i = 0;
123 while(i < length)
124 {
125 data[i] ^= key[i%1024];
126 i++;
127 }
128
129 auto f2 = fopen((std::string(argv[1])+".script.txt").data(), "wb");
130 //auto f2 = fopen((std::string(argv[1])+".dec").data(), "wb");
131
132 i = 0;
133 auto fake_fread = [data, &i, length](void * write, int size, int num)
134 {
135 if(i >= length) exit(0);
136 unsigned char * real_write = (unsigned char *)write;
137 for(int j = 0; j < size*num; j++)
138 {
139 real_write[j] = data[i];
140 i++;
141 }
142 };
143 auto fake_fgetc = [data, &i, length]()
144 {
145 if(i >= length) exit(0);
146 return data[i++];
147 };
148
149 int furigana_length = 0;
150 std::string internal_text("");
151
152 int debug = 0;
153
154 while(!ferror(f) and !feof(f))
155 {
156 uint16_t n;
157 fake_fread(&n, 2, 1);
158 if(debug) fprintf(f2, ">%04X:", n);
159
160 // 083A XXXX: line in original code?
161 // 0840 XXXX: content text of length XXXX
162 // 0801 XXXX: internal text of length XXXX (also used for furigana)
163 // 0841: after content text, always occurs, but sometimes before it too, no idea what it does
164 // 0810: followed by two shorts, seem to dictate what to do with the significance of whatever's on the stack:
165 // - FDF0 812A F0 FD 2A 81 speech file
166 // - FD01 3198 01 FD 98 31 furigana
167 // - EE67 0836 67 EE 36 08 triggers (allows?) a wait for input (also affects auto mode's wait timer)
168 // further followed by three shorts, the first two are blank in the file but modified at runtime.
169 // if, at runtime, you change the 0810 "command" but not the rewritten shorts, it will continue to act like the old command.
170 // example:
171 // F0 FD 2A 81 -> 25 D6 FE 07
172 // 01 FD 98 31 -> B6 1C FF 07
173 // 67 EE 36 08 -> D5 0C FF 07
174 // the last of the three shorts seems to be 0 or 1, sometimes 2. stack usage?
175 // similar to 0810: 080F, 0835
176
177 // 0842: text control?
178 // 0842 0002 XXXX (?), where
179 // 006E : new line. waits for input. fucks up the backlog if you use it multiple times in a row
180 // 0070 : wait for input, even twice if you use it multiple times in a row
181 // 0077 : new page, move to upper left
182 // normally 0070 and 0077 are run in that order together
183 // but if you replace the 0070 with 0077 it doesn't seem to change anything.
184 //
185 if(n == 0x0810 or n == 0x080F)
186 {
187 uint16_t a[5];
188 fake_fread(a, 2, 5);
189 if(debug) fprintf(f2, "%04X %04X %04X %04X %04X\n", a[0], a[1], a[2], a[3], a[4]);
190 if(a[0] == 0xEE67 and a[1] == 0x0836)
191 fputc('\n', f2);
192 else if(a[0] == 0xFD01 and a[1] == 0x3198)
193 {
194 // 8171〈
195 // 8172〉
196 // 8173《
197 // 8174》
198 // 8171234
199 fputs("\x81\x73", f2);
200 bool last_char_first_surrogate = false;
201 int chars_printed = 0;
202 for(char c : internal_text)
203 {
204 //if(c == '\\' and !is_jis_surrogate(last_c))
205 //{
206 // fputc('\\', f2);
207 // fputc('\\', f2);
208 //}
209 //else
210 if(is_jis_surrogate(c) and !last_char_first_surrogate)
211 {
212 fputc(c, f2);
213 last_char_first_surrogate = true;
214 }
215 else
216 {
217 if(last_char_first_surrogate or (c != '\n' and c != '\r'))
218 fputc(c, f2);
219 else if(c == '\n') fprintf(f2, "\\n");
220 else if(c == '\r') fprintf(f2, "\\r");
221 last_char_first_surrogate = false;
222 chars_printed++;
223 }
224 }
225 fputs("\x81\x74", f2);
226 furigana_length = chars_printed;
227 internal_text.assign("");
228 }
229 if(debug) fprintf(f2, "\n");
230 }
231 else if(n == 0x0842)
232 {
233 uint16_t a[2];
234 fake_fread(a, 2, 2);
235 if(debug) fprintf(f2, "%04X %04X\n", a[0], a[1]);
236 //if(a[1] == 0x0077 or a[1] == 0x006E)
237 // fputc('\n', f2);
238 if(a[1] == 0x0077 or a[1] == 0x0070 and !debug) // double newline for new page
239 fputc('\n', f2);
240 }
241 else if(n == 0x0840 or n == 0x0801)
242 {
243 if(n == 0x0801)
244 internal_text.assign("");
245 uint16_t len;
246 fake_fread(&len, 2, 1);
247 bool last_char_first_surrogate = 0;
248 if(furigana_length != 0)
249 fputs("\x81\x71", f2);
250 int chars_printed = 0;
251 for(int i = 0; i < len; i++)
252 {
253 uint8_t c = fake_fgetc();
254 if(c == 0)
255 { }
256 else
257 {
258 if(n == 0x0801)
259 internal_text += c;
260 if(n != 0x0801 or debug)
261 {
262 if(last_char_first_surrogate or (c != '\n' and c != '\r'))
263 fputc(c, f2);
264 else if(c == '\n') fprintf(f2, "\\n");
265 else if(c == '\r') fprintf(f2, "\\r");
266 }
267 }
268 if(is_jis_surrogate(c) and !last_char_first_surrogate)
269 {
270 last_char_first_surrogate = true;
271 }
272 else
273 {
274 last_char_first_surrogate = false;
275 chars_printed++;
276 }
277 if(furigana_length != 0 and chars_printed*3 > furigana_length and !last_char_first_surrogate) // This is a hack since I don't know how/if the engine keeps track of hiragana width in fullwidth characters. Gives the right results on sr001.mjo.
278 {
279 fputs("\x81\x72", f2);
280 furigana_length = 0;
281 }
282 }
283 if(debug) fputs("\n", f2);
284 furigana_length = 0;
285 }
286 // ensure program counter is consistent
287 else if(n == 0x083A)
288 {
289 uint16_t a[1];
290 fake_fread(a, 2, 1);
291 if(debug) fprintf(f2, "%04X\n", a[0]);
292 }
293 else if(n == 0x0841 or n == 0x082F or n == 0x082B)
294 {
295 if(debug) fprintf(f2, "\n");
296 }
297 else if(n == 0x0836)
298 {
299 uint8_t a[3];
300 fake_fread(a, 1, 3);
301 if(debug) fprintf(f2, "%04X %04X %04X\n", a[0], a[1], a[2]);
302 }
303 else if(n == 0x0802 or n == 0x01B0 or n == 0x01D0)
304 {
305 uint16_t a[4];
306 fake_fread(a, 2, 4);
307 if(debug) fprintf(f2, "%04X %04X %04X %04X\n", a[0], a[1], a[2], a[4]);
308 }
309 else if(n == 0x0829)
310 {
311 uint16_t a[1];
312 fake_fread(a, 2, 1);
313 if(debug) fprintf(f2, "%04X\n", a[0]);
314 }
315 else if(n == 0x0800 or n == 0x082C or n == 0x0830 or n == 0x0831)
316 {
317 uint16_t a[2];
318 fake_fread(a, 2, 2);
319 if(debug) fprintf(f2, "%04X %04X\n", a[0], a[1]);
320 }
321 else if(n == 0x0835)
322 {
323 uint16_t a[3];
324 fake_fread(a, 2, 3);
325 if(debug) fprintf(f2, "%04X %04X %04X\n", a[0], a[1], a[2]);
326 }
327 else if(n == 0x0148 or n == 0x0158)
328 {
329 uint16_t a[3];
330 fake_fread(a, 2, 3);
331 if(debug) fprintf(f2, "%04X %04X %04X\n", a[0], a[1], a[2]);
332 }
333 }
334 }
Suki nara suki tte itte
1 #include <stdint.h>
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include <string>
6 #include <vector>
7
8 uint8_t key[1024] = {
9 0x00,0x00,0x00,0x00,0x96,0x30,0x07,0x77,0x2c,0x61,0x0e,0xee,0xba,0x51,0x09,0x99,
10 0x19,0xc4,0x6d,0x07,0x8f,0xf4,0x6a,0x70,0x35,0xa5,0x63,0xe9,0xa3,0x95,0x64,0x9e,
11 0x32,0x88,0xdb,0x0e,0xa4,0xb8,0xdc,0x79,0x1e,0xe9,0xd5,0xe0,0x88,0xd9,0xd2,0x97,
12 0x2b,0x4c,0xb6,0x09,0xbd,0x7c,0xb1,0x7e,0x07,0x2d,0xb8,0xe7,0x91,0x1d,0xbf,0x90,
13 0x64,0x10,0xb7,0x1d,0xf2,0x20,0xb0,0x6a,0x48,0x71,0xb9,0xf3,0xde,0x41,0xbe,0x84,
14 0x7d,0xd4,0xda,0x1a,0xeb,0xe4,0xdd,0x6d,0x51,0xb5,0xd4,0xf4,0xc7,0x85,0xd3,0x83,
15 0x56,0x98,0x6c,0x13,0xc0,0xa8,0x6b,0x64,0x7a,0xf9,0x62,0xfd,0xec,0xc9,0x65,0x8a,
16 0x4f,0x5c,0x01,0x14,0xd9,0x6c,0x06,0x63,0x63,0x3d,0x0f,0xfa,0xf5,0x0d,0x08,0x8d,
17 0xc8,0x20,0x6e,0x3b,0x5e,0x10,0x69,0x4c,0xe4,0x41,0x60,0xd5,0x72,0x71,0x67,0xa2,
18 0xd1,0xe4,0x03,0x3c,0x47,0xd4,0x04,0x4b,0xfd,0x85,0x0d,0xd2,0x6b,0xb5,0x0a,0xa5,
19 0xfa,0xa8,0xb5,0x35,0x6c,0x98,0xb2,0x42,0xd6,0xc9,0xbb,0xdb,0x40,0xf9,0xbc,0xac,
20 0xe3,0x6c,0xd8,0x32,0x75,0x5c,0xdf,0x45,0xcf,0x0d,0xd6,0xdc,0x59,0x3d,0xd1,0xab,
21 0xac,0x30,0xd9,0x26,0x3a,0x00,0xde,0x51,0x80,0x51,0xd7,0xc8,0x16,0x61,0xd0,0xbf,
22 0xb5,0xf4,0xb4,0x21,0x23,0xc4,0xb3,0x56,0x99,0x95,0xba,0xcf,0x0f,0xa5,0xbd,0xb8,
23 0x9e,0xb8,0x02,0x28,0x08,0x88,0x05,0x5f,0xb2,0xd9,0x0c,0xc6,0x24,0xe9,0x0b,0xb1,
24 0x87,0x7c,0x6f,0x2f,0x11,0x4c,0x68,0x58,0xab,0x1d,0x61,0xc1,0x3d,0x2d,0x66,0xb6,
25 0x90,0x41,0xdc,0x76,0x06,0x71,0xdb,0x01,0xbc,0x20,0xd2,0x98,0x2a,0x10,0xd5,0xef,
26 0x89,0x85,0xb1,0x71,0x1f,0xb5,0xb6,0x06,0xa5,0xe4,0xbf,0x9f,0x33,0xd4,0xb8,0xe8,
27 0xa2,0xc9,0x07,0x78,0x34,0xf9,0x00,0x0f,0x8e,0xa8,0x09,0x96,0x18,0x98,0x0e,0xe1,
28 0xbb,0x0d,0x6a,0x7f,0x2d,0x3d,0x6d,0x08,0x97,0x6c,0x64,0x91,0x01,0x5c,0x63,0xe6,
29 0xf4,0x51,0x6b,0x6b,0x62,0x61,0x6c,0x1c,0xd8,0x30,0x65,0x85,0x4e,0x00,0x62,0xf2,
30 0xed,0x95,0x06,0x6c,0x7b,0xa5,0x01,0x1b,0xc1,0xf4,0x08,0x82,0x57,0xc4,0x0f,0xf5,
31 0xc6,0xd9,0xb0,0x65,0x50,0xe9,0xb7,0x12,0xea,0xb8,0xbe,0x8b,0x7c,0x88,0xb9,0xfc,
32 0xdf,0x1d,0xdd,0x62,0x49,0x2d,0xda,0x15,0xf3,0x7c,0xd3,0x8c,0x65,0x4c,0xd4,0xfb,
33 0x58,0x61,0xb2,0x4d,0xce,0x51,0xb5,0x3a,0x74,0x00,0xbc,0xa3,0xe2,0x30,0xbb,0xd4,
34 0x41,0xa5,0xdf,0x4a,0xd7,0x95,0xd8,0x3d,0x6d,0xc4,0xd1,0xa4,0xfb,0xf4,0xd6,0xd3,
35 0x6a,0xe9,0x69,0x43,0xfc,0xd9,0x6e,0x34,0x46,0x88,0x67,0xad,0xd0,0xb8,0x60,0xda,
36 0x73,0x2d,0x04,0x44,0xe5,0x1d,0x03,0x33,0x5f,0x4c,0x0a,0xaa,0xc9,0x7c,0x0d,0xdd,
37 0x3c,0x71,0x05,0x50,0xaa,0x41,0x02,0x27,0x10,0x10,0x0b,0xbe,0x86,0x20,0x0c,0xc9,
38 0x25,0xb5,0x68,0x57,0xb3,0x85,0x6f,0x20,0x09,0xd4,0x66,0xb9,0x9f,0xe4,0x61,0xce,
39 0x0e,0xf9,0xde,0x5e,0x98,0xc9,0xd9,0x29,0x22,0x98,0xd0,0xb0,0xb4,0xa8,0xd7,0xc7,
40 0x17,0x3d,0xb3,0x59,0x81,0x0d,0xb4,0x2e,0x3b,0x5c,0xbd,0xb7,0xad,0x6c,0xba,0xc0,
41 0x20,0x83,0xb8,0xed,0xb6,0xb3,0xbf,0x9a,0x0c,0xe2,0xb6,0x03,0x9a,0xd2,0xb1,0x74,
42 0x39,0x47,0xd5,0xea,0xaf,0x77,0xd2,0x9d,0x15,0x26,0xdb,0x04,0x83,0x16,0xdc,0x73,
43 0x12,0x0b,0x63,0xe3,0x84,0x3b,0x64,0x94,0x3e,0x6a,0x6d,0x0d,0xa8,0x5a,0x6a,0x7a,
44 0x0b,0xcf,0x0e,0xe4,0x9d,0xff,0x09,0x93,0x27,0xae,0x00,0x0a,0xb1,0x9e,0x07,0x7d,
45 0x44,0x93,0x0f,0xf0,0xd2,0xa3,0x08,0x87,0x68,0xf2,0x01,0x1e,0xfe,0xc2,0x06,0x69,
46 0x5d,0x57,0x62,0xf7,0xcb,0x67,0x65,0x80,0x71,0x36,0x6c,0x19,0xe7,0x06,0x6b,0x6e,
47 0x76,0x1b,0xd4,0xfe,0xe0,0x2b,0xd3,0x89,0x5a,0x7a,0xda,0x10,0xcc,0x4a,0xdd,0x67,
48 0x6f,0xdf,0xb9,0xf9,0xf9,0xef,0xbe,0x8e,0x43,0xbe,0xb7,0x17,0xd5,0x8e,0xb0,0x60,
49 0xe8,0xa3,0xd6,0xd6,0x7e,0x93,0xd1,0xa1,0xc4,0xc2,0xd8,0x38,0x52,0xf2,0xdf,0x4f,
50 0xf1,0x67,0xbb,0xd1,0x67,0x57,0xbc,0xa6,0xdd,0x06,0xb5,0x3f,0x4b,0x36,0xb2,0x48,
51 0xda,0x2b,0x0d,0xd8,0x4c,0x1b,0x0a,0xaf,0xf6,0x4a,0x03,0x36,0x60,0x7a,0x04,0x41,
52 0xc3,0xef,0x60,0xdf,0x55,0xdf,0x67,0xa8,0xef,0x8e,0x6e,0x31,0x79,0xbe,0x69,0x46,
53 0x8c,0xb3,0x61,0xcb,0x1a,0x83,0x66,0xbc,0xa0,0xd2,0x6f,0x25,0x36,0xe2,0x68,0x52,
54 0x95,0x77,0x0c,0xcc,0x03,0x47,0x0b,0xbb,0xb9,0x16,0x02,0x22,0x2f,0x26,0x05,0x55,
55 0xbe,0x3b,0xba,0xc5,0x28,0x0b,0xbd,0xb2,0x92,0x5a,0xb4,0x2b,0x04,0x6a,0xb3,0x5c,
56 0xa7,0xff,0xd7,0xc2,0x31,0xcf,0xd0,0xb5,0x8b,0x9e,0xd9,0x2c,0x1d,0xae,0xde,0x5b,
57 0xb0,0xc2,0x64,0x9b,0x26,0xf2,0x63,0xec,0x9c,0xa3,0x6a,0x75,0x0a,0x93,0x6d,0x02,
58 0xa9,0x06,0x09,0x9c,0x3f,0x36,0x0e,0xeb,0x85,0x67,0x07,0x72,0x13,0x57,0x00,0x05,
59 0x82,0x4a,0xbf,0x95,0x14,0x7a,0xb8,0xe2,0xae,0x2b,0xb1,0x7b,0x38,0x1b,0xb6,0x0c,
60 0x9b,0x8e,0xd2,0x92,0x0d,0xbe,0xd5,0xe5,0xb7,0xef,0xdc,0x7c,0x21,0xdf,0xdb,0x0b,
61 0xd4,0xd2,0xd3,0x86,0x42,0xe2,0xd4,0xf1,0xf8,0xb3,0xdd,0x68,0x6e,0x83,0xda,0x1f,
62 0xcd,0x16,0xbe,0x81,0x5b,0x26,0xb9,0xf6,0xe1,0x77,0xb0,0x6f,0x77,0x47,0xb7,0x18,
63 0xe6,0x5a,0x08,0x88,0x70,0x6a,0x0f,0xff,0xca,0x3b,0x06,0x66,0x5c,0x0b,0x01,0x11,
64 0xff,0x9e,0x65,0x8f,0x69,0xae,0x62,0xf8,0xd3,0xff,0x6b,0x61,0x45,0xcf,0x6c,0x16,
65 0x78,0xe2,0x0a,0xa0,0xee,0xd2,0x0d,0xd7,0x54,0x83,0x04,0x4e,0xc2,0xb3,0x03,0x39,
66 0x61,0x26,0x67,0xa7,0xf7,0x16,0x60,0xd0,0x4d,0x47,0x69,0x49,0xdb,0x77,0x6e,0x3e,
67 0x4a,0x6a,0xd1,0xae,0xdc,0x5a,0xd6,0xd9,0x66,0x0b,0xdf,0x40,0xf0,0x3b,0xd8,0x37,
68 0x53,0xae,0xbc,0xa9,0xc5,0x9e,0xbb,0xde,0x7f,0xcf,0xb2,0x47,0xe9,0xff,0xb5,0x30,
69 0x1c,0xf2,0xbd,0xbd,0x8a,0xc2,0xba,0xca,0x30,0x93,0xb3,0x53,0xa6,0xa3,0xb4,0x24,
70 0x05,0x36,0xd0,0xba,0x93,0x06,0xd7,0xcd,0x29,0x57,0xde,0x54,0xbf,0x67,0xd9,0x23,
71 0x2e,0x7a,0x66,0xb3,0xb8,0x4a,0x61,0xc4,0x02,0x1b,0x68,0x5d,0x94,0x2b,0x6f,0x2a,
72 0x37,0xbe,0x0b,0xb4,0xa1,0x8e,0x0c,0xc3,0x1b,0xdf,0x05,0x5a,0x8d,0xef,0x02,0x2d};
73
74 void fread_or_die(void * a, size_t b, size_t c, FILE * d)
75 {
76 size_t got = fread(a, b, c, d);
77 if(feof(d)) {puts("feof"); exit(0);}
78 if(ferror(d)) {puts("ferror"); exit(0);}
79 if(got != c) {exit(0);}
80 }
81
82 bool is_jis_surrogate(uint8_t c)
83 {
84 if(c >= 0x80 and c <= 0xA0) return true;
85 if(c >= 0xE0) return true;
86 return false;
87 }
88
89 int main(int argc, char ** argv)
90 {
91 //16 header
92 //4 ?
93 //4 ?
94 //4 num?
95 //8[num?] ?
96 //4 scriptsize
97 //1 script[scriptsize]
98 if(argc < 2) return puts("usage: unmjo file.mjo"), 0;
99 auto f = fopen(argv[1], "rb");
100
101 char magic[16];
102 fread(magic, 1, 16, f);
103 if(strncmp(magic, "MajiroObjX1.000", 16) != 0) return puts("unsupported file"), puts(argv[1]), 0;
104
105 uint32_t crap[2];
106 fread(crap, 4, 2, f);
107
108 uint32_t numoffsets;
109 fread(&numoffsets, 4, 1, f);
110
111 for(uint32_t i = 0; i < numoffsets; i++)
112 {
113 uint32_t offsetdata[2];
114 fread(offsetdata, 4, 2, f);
115 }
116
117 uint32_t length;
118 fread(&length, 4, 1, f);
119
120 unsigned char * data = (unsigned char *)malloc(length);
121 fread(data, 1, length, f);
122
123 uint32_t i = 0;
124 while(i < length)
125 {
126 data[i] ^= key[i%1024];
127 i++;
128 }
129
130 auto f3 = fopen((std::string(argv[1])+".dec").data(), "wb");
131
132 for(uint32_t i = 0; i < length; i++)
133 {
134 fputc(data[i], f3);
135 }
136
137 auto f2 = fopen((std::string(argv[1])+".script.txt").data(), "wb");
138 //auto f2 = fopen((std::string(argv[1])+".dec").data(), "wb");
139
140 i = 0;
141 auto fake_fread = [data, &i, length](void * write, int size, int num)
142 {
143 if(i+size*num > length) exit(0);
144 unsigned char * real_write = (unsigned char *)write;
145 for(int j = 0; j < size*num; j++)
146 {
147 real_write[j] = data[i];
148 i++;
149 }
150 };
151 auto fake_fgetc = [data, &i, length]()
152 {
153 if(i >= length) exit(0);
154 return data[i++];
155 };
156
157 int furigana_length = 0;
158 std::vector<std::string> internal_text;
159
160 int debug = 0;
161
162 while(1)
163 {
164 uint16_t n;
165 fake_fread(&n, 2, 1);
166 if(debug) fprintf(f2, "\n>%04X:%04X\n", i-2, n);
167
168 // 083A XXXX: line in original code?
169 // 0840 XXXX: content text of length XXXX
170 // 0801 XXXX: internal text of length XXXX (also used for furigana)
171 // 0841: after content text, always occurs, but sometimes before it too, no idea what it does
172 // 0810: followed by two shorts, seem to dictate what to do with the significance of whatever's on the stack:
173 // - FDF0 812A F0 FD 2A 81 speech file
174 // - FD01 3198 01 FD 98 31 furigana
175 // - EE67 0836 67 EE 36 08 triggers (allows?) a wait for input (also affects auto mode's wait timer)
176 // further followed by three shorts, the first two are blank in the file but modified at runtime.
177 // if, at runtime, you change the 0810 "command" but not the rewritten shorts, it will continue to act like the old command.
178 // example:
179 // F0 FD 2A 81 -> 25 D6 FE 07
180 // 01 FD 98 31 -> B6 1C FF 07
181 // 67 EE 36 08 -> D5 0C FF 07
182 // the last of the three shorts seems to be 0 or 1, sometimes 2. stack usage?
183 // similar to 0810: 080F, 0835
184
185 // 0842: text control?
186 // 0842 0002 XXXX (?), where
187 // 006E : new line. waits for input. fucks up the backlog if you use it multiple times in a row
188 // 0070 : wait for input, even twice if you use it multiple times in a row
189 // 0077 : new page, move to upper left
190 // normally 0070 and 0077 are run in that order together
191 // but if you replace the 0070 with 0077 it doesn't seem to change anything.
192 //
193 if(n == 0x0810 or n == 0x080F)
194 {
195 uint16_t a[5];
196 fake_fread(a, 2, 5);
197 if(debug) fprintf(f2, "%04X %04X %04X %04X %04X\n", a[0], a[1], a[2], a[3], a[4]);
198 if(a[0] == 0xEE67 and a[1] == 0x0836)
199 fputc('\n', f2);
200 else if(a[0] == 0xFD01 and a[1] == 0x3198)
201 {
202 // 8171〈
203 // 8172〉
204 // 8173《
205 // 8174》
206 // 8171234
207 bool last_char_first_surrogate = false;
208 int chars_printed = 0;
209
210 for(int i = 0; i < 2; i++)
211 {
212 if(i == 0)
213 fputs("\x81\x71", f2);
214 else
215 fputs("\x81\x73", f2);
216 for(char c : internal_text[internal_text.size()-1-i])
217 {
218 //if(c == '\\' and !is_jis_surrogate(last_c))
219 //{
220 // fputc('\\', f2);
221 // fputc('\\', f2);
222 //}
223 //else
224 if(is_jis_surrogate(c) and !last_char_first_surrogate)
225 {
226 fputc(c, f2);
227 last_char_first_surrogate = true;
228 }
229 else
230 {
231 if(last_char_first_surrogate or (c != '\n' and c != '\r'))
232 fputc(c, f2);
233 else if(c == '\n') fprintf(f2, "\\n");
234 else if(c == '\r') fprintf(f2, "\\r");
235 last_char_first_surrogate = false;
236 chars_printed++;
237 }
238 }
239 if(i == 0)
240 fputs("\x81\x72", f2);
241 else
242 fputs("\x81\x74", f2);
243 }
244 internal_text.clear();
245 }
246 if(debug) fprintf(f2, "\n");
247 }
248 else if(n == 0x0842)
249 {
250 uint16_t a[2];
251 fake_fread(a, 2, 2);
252 if(debug) fprintf(f2, "%04X %04X\n", a[0], a[1]);
253 //if(a[1] == 0x0077 or a[1] == 0x006E)
254 // fputc('\n', f2);
255 if(a[1] == 0x0077 or a[1] == 0x0070 and !debug) // double newline for new page
256 fputc('\n', f2);
257 }
258 else if(n == 0x0840 or n == 0x0801)
259 {
260 std::string temp;
261 uint16_t len;
262 fake_fread(&len, 2, 1);
263 bool last_char_first_surrogate = 0;
264 int chars_printed = 0;
265 for(int i = 0; i < len; i++)
266 {
267 uint8_t c = fake_fgetc();
268 if(c == 0)
269 { }
270 else
271 {
272 if(n == 0x0801)
273 temp += c;
274 if(n != 0x0801 or debug)
275 {
276 if(last_char_first_surrogate or (c != '\n' and c != '\r'))
277 fputc(c, f2);
278 else if(c == '\n') fprintf(f2, "\\n");
279 else if(c == '\r') fprintf(f2, "\\r");
280 }
281 }
282 if(is_jis_surrogate(c) and !last_char_first_surrogate)
283 {
284 last_char_first_surrogate = true;
285 }
286 else
287 {
288 last_char_first_surrogate = false;
289 chars_printed++;
290 }
291 }
292 if(n == 0x0801)
293 internal_text.push_back(temp);
294 if(debug) fputs("\n", f2);
295 }
296 // ensure program counter is consistent
297 else if(n == 0x0800 or n == 0x0803)
298 {
299 uint16_t a[2];
300 fake_fread(a, 2, 2);
301 }
302 else if(n == 0x083A)
303 {
304 uint16_t a[1];
305 fake_fread(a, 2, 1);
306 }
307 else if(n == 0x0829 or n == 0x0836)
308 {
309 uint16_t a[1];
310 fake_fread(a, 2, 1);
311 while(a[0]-- > 0)
312 {
313 uint8_t t;
314 fake_fread(&t, 1, 1);
315 }
316 }
317 else if(n == 0x0835 or n == 0x0834)
318 {
319 uint16_t a[3];
320 fake_fread(a, 2, 3);
321 }
322 else if(n == 0x01B0 or n == 0x0802)
323 {
324 uint16_t a[4];
325 fake_fread(a, 2, 4);
326 }
327 else if(n == 0x0841 or n == 0x083F or n == 0x082F or n == 0x082B or n == 0x0844)
328 {
329 //uint16_t a[1];
330 //fake_fread(a, 2, 1);
331 //if(debug) fprintf(f2, "%04X\n", a[0]);
332 }
333 else if(n == 0x082E or n == 0x082C or n == 0x0830 or n == 0x0831 or n == 0x0847 or n == 0x083B or n == 0x0832 or n == 0x083D)
334 {
335 uint16_t a[2];
336 fake_fread(a, 2, 2);
337 }
338 else if(n == 0x01B2)
339 {
340 uint16_t a[4];
341 fake_fread(a, 2, 4);
342 }
343 else if(n == 0x0130 or n == 0x0188 or n == 0x0100
344 or n == 0x0108 or n == 0x0120 or n == 0x0118
345 or n == 0x0158 or n == 0x0138 or n == 0x0104
346 or n == 0x0140 or n == 0x0190 or n == 0x011A
347 or n == 0x015A or n == 0x0170 or n == 0x0148
348 or n == 0x013A) // ???
349 {
350 //uint16_t a[1];
351 //fake_fread(a, 2, 1);
352 //if(debug) fprintf(f2, "%04X\n", a[0]);
353 }
354 else
355 {
356 puts(argv[1]);
357 printf("Unknown opcode 0x%X at 0x%X\n", n, i-2);
358 return 0;
359 }
360 }
361 }