Mercurial > otakunoraifu
comparison scn2k/scn2kdump.cc @ 0:223b71206888
Initial import
author | thib |
---|---|
date | Fri, 01 Aug 2008 16:32:45 +0000 |
parents | |
children | 3a6aaeab7b4e |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:223b71206888 |
---|---|
1 /* | |
2 * | |
3 * Copyright (C) 2002- Kazunori Ueno(JAGARL) <jagarl@creator.club.ne.jp> | |
4 * | |
5 * This program is free software; you can redistribute it and/or modify | |
6 * it under the terms of the GNU General Public License as published by | |
7 * the Free Software Foundation; either version 2 of the License, or | |
8 * (at your option) any later version. | |
9 * | |
10 * This program is distributed in the hope that it will be useful, | |
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 * GNU General Public License for more details. | |
14 * | |
15 * You should have received a copy of the GNU General Public License | |
16 * along with this program; if not, write to the Free Software | |
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
18 * | |
19 */ | |
20 | |
21 #include<stdlib.h> | |
22 #include<stdarg.h> | |
23 #include<stdio.h> | |
24 #include<string.h> | |
25 #include<string> | |
26 #include<vector> | |
27 #include<map> | |
28 | |
29 using namespace std; | |
30 | |
31 #include"system/file.h" | |
32 #include"system/file_impl.h" | |
33 | |
34 /* 注意点: @@@ で表記 */ | |
35 | |
36 struct VarInfo { | |
37 #define TYPE_VARSTR 18 | |
38 #define TYPE_VARMAX 7 | |
39 #define TYPE_STR 58 | |
40 #define TYPE_VAL 68 | |
41 #define TYPE_SYS 0xc8 | |
42 int type; | |
43 int number; | |
44 int value; | |
45 VarInfo() { type = TYPE_VAL; value = 0;} | |
46 VarInfo(int n) { type = TYPE_VAL; value = n;} | |
47 VarInfo(const VarInfo& i) { type = i.type; number = i.number; value = i.value;} | |
48 }; | |
49 class Flags { | |
50 /* flag: | |
51 ** type 0-5 : ローカル整数、各2000個 | |
52 ** type 6, 25 : グローバル整数、2000個 | |
53 ** type 12 : グローバル文字列、2000個 (今は無視しても良いが) | |
54 ** type 18 : ローカル文字列、2000個 | |
55 ** type 25: システム変数(マウス座標など?) 1000 個? | |
56 ** type 26-32, 51 : 1-bit access to 0-6, 25 | |
57 ** type 52-58, 77 : 2-bit access to 0-6, 25 | |
58 ** type 78-84, 103 : 4-bit access to 0-6, 25 | |
59 ** type 104-110, 129 : 8-bit access to 0-6, 25 | |
60 */ | |
61 typedef unsigned int uint; | |
62 int sys; | |
63 int var[8][2000]; | |
64 string str[2000]; | |
65 public: | |
66 int operator () () const; | |
67 int operator () (VarInfo info) const; | |
68 void Str(unsigned int number, char* buf, int sz) const; | |
69 | |
70 bool IsInt(int type) const; | |
71 int MaxIndex(int type) const; | |
72 | |
73 void Set(VarInfo info, int value); | |
74 int Get(int type, int number) const; | |
75 void SetSys(int value); | |
76 void SetStr(unsigned int number, string val); | |
77 }; | |
78 | |
79 bool Flags::IsInt(int type) const { | |
80 int v = type % 26; | |
81 return v >= 0 && v < 7 || v == 25; | |
82 } | |
83 | |
84 int Flags::MaxIndex(int type) const { | |
85 switch (type / 26) { | |
86 case 1: | |
87 return 63999; | |
88 case 2: | |
89 return 31999; | |
90 case 3: | |
91 return 15999; | |
92 case 4: | |
93 return 7999; | |
94 default: | |
95 return 1999; | |
96 } | |
97 } | |
98 | |
99 int Flags::operator()() const { | |
100 return rand() % 10000; | |
101 } | |
102 int Flags::operator() (VarInfo info) const { | |
103 return Get(info.type, info.number); | |
104 } | |
105 int Flags::Get(int type, int number) const { | |
106 int index = type % 26; | |
107 type /= 26; | |
108 if (index == 25) index = 7; | |
109 if (index > 7 || uint(type) > 4) return 0; | |
110 if (type == 0) { | |
111 // A[]..G[], Z[] を直に読む | |
112 if (uint(number) >= 2000) return 0; | |
113 return var[index][number]; | |
114 } else { | |
115 // Ab[]..G4b[], Z8b[] などを読む | |
116 int factor = 1 << (type - 1); | |
117 int eltsize = 32 / factor; | |
118 if (uint(number) >= (64000 / factor)) return 0; | |
119 return (var[index][number / eltsize] >> ((number % eltsize) * factor)) & ((1 << factor) - 1); | |
120 } | |
121 } | |
122 | |
123 void Flags::Set(VarInfo info, int value) { | |
124 int type = info.type / 26; | |
125 int index = info.type % 26; | |
126 if (index == 25) index = 7; | |
127 if (type == 0) { | |
128 // A[]..G[], Z[] を直に書く | |
129 if (uint(info.number) >= 2000) return; | |
130 var[index][info.number] = value; | |
131 } else { | |
132 // Ab[]..G4b[], Z8b[] などを書く | |
133 int factor = 1 << (type - 1); | |
134 int eltsize = 32 / factor; | |
135 int eltmask = (1 << factor) - 1; | |
136 int shift = (info.number % eltsize) * factor; | |
137 if (uint(info.number) >= (64000 / factor)) return; | |
138 var[index][info.number / eltsize] = | |
139 (var[index][info.number / eltsize] & ~(eltmask << shift)) | |
140 | (value & eltmask) << shift; | |
141 } | |
142 } | |
143 | |
144 void Flags::SetSys(int value) { | |
145 sys = value; | |
146 } | |
147 void Flags::SetStr(unsigned int number, string val) { | |
148 if (number >= 2000) return; | |
149 str[number] = val; | |
150 } | |
151 void Flags::Str(unsigned int number, char* buf, int sz) const { | |
152 if (number >= 2000) {if(sz>0) buf[0] = 0; return;} | |
153 const string& s = str[number]; | |
154 int len = s.length(); | |
155 if (sz-1 > len) sz = len; | |
156 s.copy(buf, sz, 0); | |
157 buf[sz] = 0; | |
158 return; | |
159 } | |
160 | |
161 /* commands */ | |
162 enum Cmdtype { CMD_FLAGS, CMD_JMP, CMD_TEXT, CMD_OTHER}; | |
163 class Cmd { | |
164 Cmdtype cmd_type; | |
165 int cmd1, cmd2, cmd3, cmd4; | |
166 int argc; | |
167 bool errorflag; | |
168 char cmdstr[1024]; | |
169 const Flags& flags; | |
170 vector<VarInfo> args; | |
171 | |
172 int GetArgs(const char*& d); | |
173 int GetArgsSpecial(int normal_args,const char*& d); | |
174 void GetSelection(const char*& d); | |
175 int GetSwitch(const char*& d); | |
176 int GetSimpleSwitch(const char*& d); | |
177 int GetExpression(const char*& d, struct VarInfo* info = 0); | |
178 int GetExpressionCond(const char*& d); | |
179 int GetLeftToken(const char*& d, struct VarInfo& info); | |
180 static int GetString(const char*& d); | |
181 int StrVar(int number); | |
182 static char strtype[256]; | |
183 static int StrType(const char* d) { return strtype[*(unsigned const char*)d];} | |
184 int AddStr(char* s) { | |
185 // 1-0a-0064 はこういうものが必要らしい | |
186 int start = strend; | |
187 while (*s) strheap[strend++] = *s++; | |
188 strheap[strend++] = 0; | |
189 return start; | |
190 } | |
191 #define STRHEAP_SIZE 10000 | |
192 static char strheap[STRHEAP_SIZE]; | |
193 static int strend; | |
194 void SetError(void) { errorflag = true;} | |
195 static void ResetString(void) { | |
196 strend = 0; | |
197 } | |
198 static map<int, struct CmdDescrItem*> cmd_descr; | |
199 const char* CmdDescr(int cmd1, int cmd2, int cmd3, int cmd4); | |
200 public: | |
201 void GetCmd(Flags& f, const char*& d); | |
202 bool IsError() { return errorflag;} | |
203 bool ClearError() { errorflag = false;} | |
204 Cmd(const Flags& f) : flags(f) { argc = 0; errorflag = false; cmdstr[0] = 0;} | |
205 | |
206 }; | |
207 | |
208 bool debug_flag = false; | |
209 void dprintf(const char* fmt, ...) { | |
210 if (debug_flag) { | |
211 va_list ap; va_start(ap, fmt); | |
212 vprintf(fmt, ap); | |
213 va_end(ap); | |
214 } | |
215 } | |
216 | |
217 | |
218 #define SCN_DUMP | |
219 | |
220 int system_version = 0; | |
221 bool ruby_flag = false; | |
222 bool ret_flag = false; | |
223 bool text_flag = false; | |
224 bool selection_flag = false; | |
225 char Cmd::strheap[STRHEAP_SIZE]; | |
226 int Cmd::strend = 0; | |
227 | |
228 /* 数値 num := 0x24 0xff <int num> */ | |
229 /* 変数 var := 0x24 <uchar type> 0x5b <exp> 0x5d */ | |
230 /* 項 token := num | var | 0x28 <exp> 0x29 | <plus|minus> token */ | |
231 | |
232 int Cmd::GetLeftToken(const char*& d, VarInfo& info) { | |
233 bool var_flag = true; | |
234 int minus_flag = 0; | |
235 int value = 0; | |
236 if (d[0] == 0x5c && (d[1] == 1 || d[1] == 0) ) { | |
237 if (d[1] == 1) {dprintf("minus-"); minus_flag ^= 1;} | |
238 else dprintf("plus-"); | |
239 d += 2; | |
240 var_flag = false; | |
241 } | |
242 if (d[0] == 0x24 && ((unsigned const char*)d)[1] == 0xff) { | |
243 // if ( (d[0] == 0x30 || d[0] == 0x31) && d[1] == 0x24 && ((unsigned const char*)d)[2] == 0xff) /* @@@ not supported; selection 内で、0x30|0x31 が付随することがある */ | |
244 // numerical atom | |
245 d += 6; | |
246 value = read_little_endian_int(d-4); | |
247 dprintf("%d",value); | |
248 var_flag = false; | |
249 } else if (d[0] == 0x24 && *(unsigned char*)(d+1) == 0xc8) { | |
250 dprintf("V<sys>"); | |
251 d += 2; | |
252 info.type = TYPE_SYS; info.number = 0; | |
253 value = info.value = flags(); | |
254 } else if (d[0] == 0x24 && d[2] == 0x5b) { | |
255 // 0x24,<type>,0x5b,<expr>,0x5d-terminated term | |
256 info.type = *(unsigned char*)(d+1); | |
257 d += 3; | |
258 dprintf("V<%d>[",info.type); | |
259 info.number = GetExpression(d); | |
260 dprintf("]"); | |
261 if (*d == 0x5d) d++; | |
262 else SetError(); | |
263 if (info.type == TYPE_VARSTR) { | |
264 value = 0; | |
265 info.value = StrVar(info.number); | |
266 } else { | |
267 value = info.value = flags(info); | |
268 } | |
269 dprintf("(=%d)",value); | |
270 } else SetError(); | |
271 | |
272 if (minus_flag) value = -value; | |
273 if (!var_flag) { | |
274 info.type = TYPE_VAL; | |
275 info.value = value; | |
276 } | |
277 return value; | |
278 } | |
279 | |
280 static char* op_str[70] = { | |
281 // 0 1 2 3 4 5 6 7 8 9 | |
282 "+", "-", "*", "/", "%", "&", "|", "^", "<<", ">>", // +00 | |
283 "err.","err.","err.","err.","err.","err.","err.","err.","err.","err.", // +10 | |
284 "+=", "-=", "*=", "/=", "%=", "&=", "|=", "^=", "<<=", ">>=", // +20 | |
285 "=", "err.","err.","err.","err.","err.","err.","err.","err.","err.", // +30 | |
286 "==", "!=", "<=", "<", ">=", ">", "err.","err.","err.","err.", // +40 | |
287 "err.","err.","err.","err.","err.","err.","err.","err.","err.","err.", // +50 | |
288 "&&", "||", "err.","err.","err.","err.","err.","err.","err.","err.", // +60 | |
289 }; | |
290 | |
291 static int op_pri_tbl[12] = { | |
292 // + - * / % & | ^ << >> | |
293 1, 1, 0, 0, 0, 3, 5, 4, 2, 2, 10, 10}; | |
294 | |
295 inline int op_pri(int op) { | |
296 if (op > 11) return 10; | |
297 return op_pri_tbl[op]; | |
298 } | |
299 inline int op_pri_cond(int op) { | |
300 if (op <= 11) return op_pri_tbl[op]; | |
301 else if (op < 50) return 7; | |
302 else if (op == 60) return 8; | |
303 else if (op == 61) return 9; | |
304 else return 10; | |
305 } | |
306 | |
307 | |
308 inline int eval(int v1, int op, int v2) { | |
309 switch(op) { | |
310 case 0: return v1+v2; | |
311 case 1: return v1-v2; | |
312 case 2: return v1*v2; | |
313 case 3: return v2!=0 ? v1/v2 : v1; | |
314 case 4: return v2!=0 ? v1%v2 : v1; | |
315 case 5: return v1&v2; | |
316 case 6: return v1|v2; | |
317 case 7: return v1^v2; | |
318 case 8: return v1<<v2; | |
319 case 9: return v1>>v2; | |
320 case 40: return v1 == v2; | |
321 case 41: return v1 != v2; | |
322 case 42: return v1 <= v2; | |
323 case 43: return v1 < v2; | |
324 case 44: return v1 >= v2; | |
325 case 45: return v1 > v2; | |
326 case 60: return v1 && v2; | |
327 case 61: return v1 || v2; | |
328 } | |
329 return v2; | |
330 } | |
331 | |
332 /* 演算子 op := 0x5c <uchar op> */ | |
333 /* 数式 exp: [op] <token> [op <token> [...]] */ | |
334 int Cmd::GetExpression(const char*& d, VarInfo* info_ptr) { | |
335 #define STACK_DEPTH 1024 | |
336 #define OP_LB 11 | |
337 char op_stack[STACK_DEPTH]; | |
338 int val_stack[STACK_DEPTH]; | |
339 int stack_count = 0; | |
340 | |
341 // 第一項の読み込み | |
342 while(*d == 0x28) { | |
343 d++; | |
344 dprintf("("); | |
345 op_stack[stack_count++] = OP_LB; | |
346 } | |
347 VarInfo info; | |
348 int value = GetLeftToken(d, info); | |
349 | |
350 while(*d == 0x29 && stack_count > 0 && op_stack[stack_count-1] == OP_LB) { | |
351 d++; | |
352 dprintf(")"); | |
353 stack_count--; | |
354 } | |
355 | |
356 if (*d != 0x5c && stack_count == 0) { | |
357 if (info_ptr) *info_ptr = info; | |
358 return value; // 単純なleft-termはここで終了。有効なinfo_ptrを帰す(可能性がある) | |
359 } | |
360 | |
361 while(*d == 0x5c) { | |
362 int op_type = *(unsigned char*)(d+1); | |
363 d += 2; | |
364 if (op_type < 70) dprintf("%s",op_str[op_type]); | |
365 else dprintf("err."); | |
366 if (op_type >= 10) SetError(); | |
367 int cur_pri = op_pri(op_type); | |
368 while(stack_count != 0 && op_pri(op_stack[stack_count-1]) <= cur_pri) { | |
369 // 優先順位の高い、先行する演算を行う | |
370 value = eval(val_stack[stack_count-1], op_stack[stack_count-1], value); | |
371 stack_count--; | |
372 } | |
373 val_stack[stack_count] = value; | |
374 op_stack[stack_count++] = op_type; | |
375 while(*d == 0x28) { | |
376 d++; | |
377 dprintf("("); | |
378 op_stack[stack_count++] = OP_LB; | |
379 } | |
380 if (stack_count >= STACK_DEPTH) SetError(); | |
381 value = GetLeftToken(d, info); | |
382 | |
383 while (*d != 0x5c && stack_count > 0) { | |
384 // 未実行の演算を終わらせる | |
385 if (op_stack[stack_count-1] != OP_LB) { | |
386 value = eval(val_stack[stack_count-1], op_stack[stack_count-1], value); | |
387 stack_count--; | |
388 } else if (*d == 0x29) { /* op_stack == OP_LB */ | |
389 // bracket 終端があれば、閉じておく | |
390 d++; | |
391 dprintf(")"); | |
392 stack_count--; | |
393 } else break; // error | |
394 } | |
395 } | |
396 if (stack_count) SetError(); // unbalanced bracket | |
397 dprintf("(=%d)",value); | |
398 if (info_ptr) { | |
399 info_ptr->type = TYPE_VAL; | |
400 info_ptr->value = value; | |
401 } | |
402 return value; | |
403 } | |
404 | |
405 // 条件分岐専用に、条件演算と算術演算の混合を検知できる専用ルーチン(本来はGetExpressionで差し支えない) | |
406 int Cmd::GetExpressionCond(const char*& d) { | |
407 char op_stack[STACK_DEPTH]; | |
408 int val_stack[STACK_DEPTH]; | |
409 int valattr_stack[STACK_DEPTH]; | |
410 #define ATTR_VAL 0 | |
411 #define ATTR_FLAG 1 | |
412 int stack_count = 0; | |
413 | |
414 // 第一項の読み込み | |
415 while(*d == 0x28) { | |
416 d++; | |
417 dprintf("("); | |
418 op_stack[stack_count++] = OP_LB; | |
419 } | |
420 VarInfo info; | |
421 int value = GetLeftToken(d, info); | |
422 bool valattr = ATTR_VAL; | |
423 | |
424 while(*d == 0x5c) { | |
425 int op_type = *(unsigned char*)(d+1); | |
426 d += 2; | |
427 if (op_type < 70) dprintf("%s",op_str[op_type]); | |
428 else dprintf("err."); | |
429 int cur_pri = op_pri_cond(op_type); | |
430 while(stack_count != 0 && op_pri_cond(op_stack[stack_count-1]) <= cur_pri) { | |
431 // 優先順位の高い、先行する演算を行う | |
432 if (op_stack[stack_count-1] >= 60) { | |
433 if (valattr_stack[stack_count-1] != ATTR_FLAG || valattr != ATTR_FLAG) SetError(); | |
434 } else { | |
435 if (valattr_stack[stack_count-1] != ATTR_VAL || valattr != ATTR_VAL) SetError(); | |
436 } | |
437 value = eval(val_stack[stack_count-1], op_stack[stack_count-1], value); | |
438 if (op_stack[stack_count-1] >= 40) valattr = ATTR_FLAG; | |
439 stack_count--; | |
440 } | |
441 val_stack[stack_count] = value; | |
442 valattr_stack[stack_count] = valattr; | |
443 op_stack[stack_count++] = op_type; | |
444 while(*d == 0x28) { | |
445 d++; | |
446 dprintf("("); | |
447 op_stack[stack_count++] = OP_LB; | |
448 } | |
449 if (stack_count >= STACK_DEPTH) SetError(); | |
450 value = GetLeftToken(d, info); | |
451 valattr = ATTR_VAL; | |
452 | |
453 while (*d != 0x5c && stack_count > 0) { | |
454 // 未実行の演算を終わらせる | |
455 if (op_stack[stack_count-1] != OP_LB) { | |
456 if (op_stack[stack_count-1] >= 60) { | |
457 if (valattr_stack[stack_count-1] != ATTR_FLAG || valattr != ATTR_FLAG) SetError(); | |
458 } else { | |
459 if (valattr_stack[stack_count-1] != ATTR_VAL || valattr != ATTR_VAL) SetError(); | |
460 } | |
461 value = eval(val_stack[stack_count-1], op_stack[stack_count-1], value); | |
462 if (op_stack[stack_count-1] >= 40) valattr = ATTR_FLAG; | |
463 stack_count--; | |
464 // bracket 終端があれば、閉じておく | |
465 } else if (*d == 0x29) { /* op_stack == OP_LB */ | |
466 d++; | |
467 dprintf(")"); | |
468 stack_count--; | |
469 } else break; // error | |
470 } | |
471 } | |
472 if (stack_count) SetError(); // unbalanced bracket | |
473 if (value) dprintf("(=true)"); | |
474 else dprintf("(=false)"); | |
475 return value; | |
476 } | |
477 | |
478 | |
479 /* | |
480 str = | |
481 arg = | |
482 args = 0x28 <exp> [[0x2c] <exp> [[0x2c] <exp> [...] ]] | |
483 */ | |
484 | |
485 int Cmd::GetArgs(const char*& d) { | |
486 if (*d != 0x28) return 0; /* 引数なし */ | |
487 d++; | |
488 dprintf("args:"); | |
489 VarInfo var; | |
490 int i; for (i=0; i<100 ; i++) { | |
491 /* number, variable, string の種別なく値を得る */ | |
492 if (*d == 0x61) { // よくわからない(智代アフター) | |
493 dprintf("@%d",d[1]); | |
494 d += 2; | |
495 if (*d == 0x28) { | |
496 dprintf("{"); | |
497 GetArgs(d); // (A,B,C)節が含まれることがある | |
498 dprintf("}"); | |
499 } else { | |
500 dprintf("{}"); | |
501 } | |
502 } else if (d[0] == 0x0a || d[0] == 0x40) { // よくわからない (Little Busters!) | |
503 int var; | |
504 if (system_version == 0) { var = read_little_endian_int(d+1); d += 5;} | |
505 else { var = read_little_endian_short(d+1); d += 3;} | |
506 dprintf("line %d; ",var); | |
507 } else if (*d == 0x24 || (*d == 0x5c && (d[1] == 1 || d[1] == 0)) || *d == 0x28) { | |
508 GetExpression(d, &var); | |
509 args.push_back(var); | |
510 } else if (StrType(d)) { | |
511 var.type = TYPE_STR; | |
512 var.value = GetString(d); | |
513 args.push_back(var); | |
514 } else SetError(); | |
515 if (*d == 0x29) break; | |
516 if (*d == 0x2c) {d++;} // 次の arg が演算子で始まる、などがなければ存在しない | |
517 dprintf(","); | |
518 } | |
519 if (*d == 0x29) d++; | |
520 else SetError(); | |
521 return i; | |
522 } | |
523 | |
524 int Cmd::GetArgsSpecial(int normal_args,const char*& d) { | |
525 if (*d != 0x28) return 0; /* 引数なし */ | |
526 d++; | |
527 dprintf("args:"); | |
528 int i; for (i=0; i<normal_args; i++) { | |
529 /* number, variable, string の種別なく値を得る */ | |
530 if (*d == 0x24 || (*d == 0x5c && (d[1] == 1 || d[1] == 0)) || *d == 0x28) { | |
531 GetExpression(d); | |
532 } else if (StrType(d)) { | |
533 GetString(d); | |
534 } else SetError(); | |
535 if (*d == 0x29) break; | |
536 if (*d == 0x2c) {d++;} // 次の arg が演算子で始まる、などがなければ存在しない | |
537 dprintf(","); | |
538 } | |
539 for (i=0; i<argc ; i++) { | |
540 if (*d == 0x28) { | |
541 /* | |
542 ** cmd 01-22:0c1c, 01-22:0835 | |
543 ** Princess Bride のカードが落ちるアニメの場面 | |
544 ** なお、_PBCARDANM* の画像はこのコマンドでのみ使われているので、特殊処理として無視することも可能 | |
545 ** | |
546 ** cmd 01-04:0276, 026c, 0270 | |
547 ** 複数の enum が args の数だけ続く処理。特殊処理として分離する | |
548 */ | |
549 dprintf("enum.<"); | |
550 /* (...) は列挙型 or 構造体の可能性がある */ | |
551 const char* d_orig = d; | |
552 int pt = args.size(); args.push_back(VarInfo(0)); | |
553 int count = GetArgs(d); | |
554 args[pt] = VarInfo(count); | |
555 dprintf(">"); | |
556 } else if (*d == 0x61 && (d[1] >= 0x00 && d[1] <= 0x04) && d[2] == 0x28 ) { | |
557 /* 使われるコマンドは 01-21:004b, 01-28:0064 のいずれか(R,C,PB,LO) | |
558 ** それらのコマンドは | |
559 ** arg1: 画像ファイル名 | |
560 ** arg2 : Sel 番号 | |
561 ** らしく、arg3 以降が 0x61 <00-04> (a,b,c,...) となる(ダンプ上は enum と表記される) | |
562 ** () 内の引数はさまざまで、a のみ(画像ファイル名)、 | |
563 ** a,b b=SEL? | |
564 ** a,b,c (b,c)=座標? | |
565 ** a,(b,c,d,e,f,g) b-g = src / dest? | |
566 ** らしい | |
567 */ | |
568 dprintf("kasane. #%d <",d[1]); | |
569 d += 2; | |
570 int pt = args.size(); args.push_back(VarInfo(0)); | |
571 int count = GetArgs(d); | |
572 args[pt] = VarInfo(count); | |
573 dprintf(">"); | |
574 } else if (*d == 0x24 || (*d == 0x5c && (d[1] == 1 || d[1] == 0))) { | |
575 /* cmd 01-15:0028 ; 始めに 0x24 節があり、続いて 0x28 節になる */ | |
576 VarInfo var; | |
577 GetExpression(d, &var); | |
578 args.push_back(var); | |
579 i--; // この引数はargc の数には入らない | |
580 } else SetError(); | |
581 if (d[0] == 0x0a || d[0] == 0x40) { | |
582 /* cmd 01-15:0028 ; 0x28 節の後に毎回 0x0a 節が来る */ | |
583 int var; | |
584 if (system_version == 0) { var = read_little_endian_int(d+1); d += 5;} | |
585 else { var = read_little_endian_short(d+1); d += 3;} | |
586 dprintf("line %d; ",var); | |
587 } | |
588 if (*d == 0x29) break; | |
589 if (*d == 0x2c) {d++;} // 次の arg が演算子で始まる、などがなければ存在しない | |
590 dprintf(","); | |
591 } | |
592 if (*d == 0x29) d++; | |
593 else SetError(); | |
594 return 0; | |
595 } | |
596 | |
597 /* switch | |
598 <exp> | |
599 0x7b | |
600 <exp> <int> | |
601 ... | |
602 0x7d | |
603 */ | |
604 | |
605 int Cmd::GetSwitch(const char*& d) { | |
606 if (*d != 0x28) {SetError(); return -1;} | |
607 d++; | |
608 dprintf("switch. "); | |
609 int var = GetExpression(d); | |
610 if (*d != 0x29) {SetError(); return -1;} | |
611 d++; | |
612 dprintf("->\n"); | |
613 if (*d == 0x7b) { | |
614 d++; | |
615 } else SetError(); | |
616 | |
617 int default_jmp = -1; int jmpto = -1; | |
618 int i; for (i=0; i<argc; i++) { | |
619 dprintf("\t"); | |
620 if (*d++ != 0x28) {SetError(); return -1;} | |
621 int item = -1; // default | |
622 if (*d != 0x29) { | |
623 int item = GetExpression(d); | |
624 if (*d++ != 0x29) {SetError(); return -1;} | |
625 int jmp = read_little_endian_int(d); | |
626 if (var == item) { | |
627 dprintf("(selected)"); | |
628 jmpto = jmp; | |
629 } | |
630 dprintf(" -> %d\n", jmp); | |
631 } else { | |
632 d++; | |
633 default_jmp = read_little_endian_int(d); | |
634 } | |
635 d += 4; | |
636 } | |
637 if (default_jmp != -1) { | |
638 dprintf("default -> %d\n",default_jmp); | |
639 if (jmpto == -1) jmpto = default_jmp; | |
640 } | |
641 if (*d == 0x7d) { | |
642 d++; | |
643 } else SetError(); | |
644 return jmpto; | |
645 } | |
646 /* simple switch | |
647 <exp> | |
648 0x7b | |
649 <int> | |
650 ... | |
651 0x7d | |
652 */ | |
653 int Cmd::GetSimpleSwitch(const char*& d) { | |
654 if (*d != 0x28) {SetError(); return -1;} | |
655 d++; | |
656 dprintf("simple switch. "); | |
657 int var = GetExpression(d); | |
658 if (*d != 0x29) {SetError(); return -1;} | |
659 d++; | |
660 dprintf(" ->\n"); | |
661 int jumpto = -1; | |
662 if (*d == 0x7b) { | |
663 d++; | |
664 } else SetError(); | |
665 int i; for (i=0; i<argc; i++) { | |
666 int j = read_little_endian_int(d); | |
667 d += 4; | |
668 dprintf("\t%d -> %d\n", i+1, j); | |
669 if (var == i+1) jumpto = j; | |
670 } | |
671 if (*d == 0x7d) { | |
672 d++; | |
673 } else SetError(); | |
674 return jumpto; | |
675 } | |
676 | |
677 /* | |
678 selection | |
679 ? <exp> | |
680 0x7b | |
681 <0x0a|0x40> <ushort | uint> | |
682 */ | |
683 void Cmd::GetSelection(const char*& d) { | |
684 dprintf("selection. "); | |
685 if (*d == 0x28) { | |
686 d++; | |
687 GetExpression(d); | |
688 if (*d != 0x29) { SetError(); return;} | |
689 d++; | |
690 } | |
691 if (*d == 0x7b) { | |
692 d++; | |
693 dprintf("{\n\t"); | |
694 } else SetError(); | |
695 int arg_count = 0; | |
696 while(*d != 0x7d) { | |
697 if (d[0] == 0x0a || d[0] == 0x40) { | |
698 int var; | |
699 if (system_version == 0) { var = read_little_endian_int(d+1); d += 5;} | |
700 else { var = read_little_endian_short(d+1); d += 3;} | |
701 dprintf("line %d; ",var); | |
702 } else if (d[0] == 0x2c) { | |
703 dprintf(":comma:"); | |
704 } else if (d[0] == 0x28) { | |
705 dprintf(":cond:"); | |
706 d++; | |
707 while(d[0] != 0x29) { | |
708 GetExpressionCond(d); // PRINT- 節でないばあい、条件表示。次は文字節、またはPRINT節のはず | |
709 if (IsError()) break; | |
710 if (*d == 0x32) { d++; dprintf("##");} // 0x32 なら、現在の条件節を表示しない | |
711 if (*d == 0x31) { d++; dprintf("**");} // 0x31 なら、現在の条件節を表示する(Little Busters! : 処理が正しいかは分からない) | |
712 dprintf(":"); | |
713 } | |
714 d++; | |
715 } else if (StrType(d)) { | |
716 GetString(d); | |
717 arg_count++; | |
718 dprintf("\n\t"); | |
719 } else if (*d == 0x23 && strncmp(d,"###PRINT",8) == 0) { | |
720 d += 8; | |
721 if (d[0] != 0x28) SetError(); | |
722 else { // 文字変数の内容の表示 | |
723 d++; | |
724 dprintf("Print."); | |
725 VarInfo info; | |
726 GetLeftToken(d, info); | |
727 if (d[0] != 0x29 || info.type == -1) SetError(); | |
728 d++; | |
729 dprintf(";"); | |
730 } | |
731 } else { SetError(); break;} | |
732 } | |
733 d++; | |
734 /* @@@ */ | |
735 /* 一致しない場合があるのでコメントアウト */ | |
736 // if (arg_count != argc) SetError(); | |
737 dprintf("\n}\n"); | |
738 return; | |
739 } | |
740 | |
741 char* op_str3[11] = { "+=", "-=", "*=", "/=", "%=", "&=", "|=", "^=", "<<=", ">>=", "="}; | |
742 void Cmd::GetCmd(Flags& flags_orig, const char*& d ) { | |
743 ResetString(); | |
744 | |
745 cmdstr[0] = 0; | |
746 debug_flag = true; | |
747 if (*d == 0x23) { /* コマンド */ | |
748 cmd_type = CMD_OTHER; | |
749 cmd1 = *(unsigned const char*)(d+1); | |
750 cmd2 = *(unsigned const char*)(d+2); | |
751 cmd3 = read_little_endian_short(d+3); | |
752 argc = read_little_endian_short(d+5); | |
753 cmd4 = *(unsigned const char*)(d+7); | |
754 d += 8; | |
755 /* verbose */ | |
756 // dprintf(" 0x23 - cmd %02x-%02x:%04x:%02x[%2d] \n",cmd1,cmd2,cmd3,cmd4,argc); | |
757 sprintf(cmdstr, "%02x-%02x:%04x:%02x : %s",cmd1,cmd2,cmd3,cmd4,CmdDescr(cmd1,cmd2,cmd3,cmd4)); | |
758 /* 引数を得る */ | |
759 /* 特殊引数のもの */ | |
760 int is_special = 0; | |
761 if (cmd1 == 0) { | |
762 if (cmd2 == 1) { | |
763 int jump_arg = -1; | |
764 if (cmd3 == 0 || cmd3 == 5) { | |
765 /* gosub / goto */ | |
766 jump_arg =read_little_endian_int(d); | |
767 d += 4; | |
768 dprintf("\tjmp -> %d\n", jump_arg); | |
769 is_special = 1; | |
770 } else if (cmd3 == 1 || cmd3 == 2) { | |
771 /* conditional jump (if / unless) */ | |
772 if (*d++ != 0x28) { SetError(); return;} | |
773 dprintf("\t"); | |
774 int cond = GetExpressionCond(d); | |
775 if (IsError()) return; | |
776 if (*d++ != 0x29) { SetError(); return; } | |
777 int jumpto = read_little_endian_int(d); | |
778 d += 4; | |
779 dprintf("-> %d\n", jumpto); | |
780 if (cond) jump_arg = jumpto; | |
781 is_special = 1; | |
782 } else if (cmd3 == 4) { | |
783 /* switch to */ | |
784 jump_arg = GetSwitch(d); | |
785 is_special = 1; | |
786 } else if (cmd3 == 16) { | |
787 dprintf("local call with paramters;\n"); | |
788 GetArgs(d); | |
789 int jumpto = read_little_endian_int(d); | |
790 d += 4; | |
791 dprintf("\tjmp -> %d\n",jumpto); | |
792 is_special = 1; | |
793 } else if (cmd3 == 8 || cmd3 == 3) { | |
794 /* switch to */ | |
795 jump_arg = GetSimpleSwitch(d); | |
796 dprintf("\tjmp -> %d\n",jump_arg); | |
797 is_special = 1; | |
798 } | |
799 cmd_type = CMD_OTHER; | |
800 args.push_back(VarInfo(jump_arg)); | |
801 } else if (cmd2 == 2 && (cmd3 == 0 || cmd3 == 1 || cmd3 == 2 || cmd3 == 3 || cmd3 == 0x0d) ) { | |
802 /* selection */ | |
803 GetSelection(d); | |
804 is_special = 1; | |
805 } | |
806 } | |
807 /* 一般引数のもの */ | |
808 if (!is_special) { | |
809 dprintf(" 0x23 - cmd %02x-%02x:%04x:%02x[%2d] : %s\n",cmd1,cmd2,cmd3,cmd4,argc,CmdDescr(cmd1,cmd2,cmd3,cmd4)); | |
810 dprintf("\t"); | |
811 if (cmd1 == 1 && cmd2 == 0x22 && (cmd3 == 0xc1c || cmd3 == 0x835)) GetArgsSpecial(3, d); | |
812 else if (cmd1 == 1 && cmd2 == 0x0b && cmd3 == 0x65) GetArgsSpecial(0, d); | |
813 else if (cmd1 == 1 && cmd2 == 0x15 && cmd3 == 0x28) GetArgsSpecial(0, d); | |
814 else if (cmd1 == 1 && cmd2 == 4 && (cmd3 == 0x26c || cmd3 == 0x26d || cmd3 == 0x270 || cmd3 == 0x276)) GetArgsSpecial(0, d); | |
815 else if (cmd1 == 1 && (cmd2 == 0x21 && cmd3 == 0x4b) || (cmd2 == 0x28 && cmd3 == 0x64)) GetArgsSpecial(2,d); | |
816 else GetArgs(d); | |
817 dprintf("\n"); | |
818 | |
819 } | |
820 if (cmd2 == 3 && cmd3 == 0x78 && cmd4 == 0) ruby_flag = true; | |
821 if (cmd2 == 3 && cmd3 == 0x11) ret_flag = true; | |
822 } else if (*d == 0x24) { /* 代入演算 */ | |
823 if (d[1] == 0x12 || d[2] != 0x5b) SetError(); | |
824 dprintf("expr: "); | |
825 sprintf(cmdstr, "expr"); | |
826 | |
827 VarInfo info; | |
828 int value = GetLeftToken(d, info); | |
829 if (d[0] != 0x5c) SetError(); | |
830 int type = d[1]; | |
831 if (type < 20 || type > 30) SetError(); | |
832 else dprintf("%s",op_str[type]); | |
833 d += 2; | |
834 int value2 = GetExpression(d); | |
835 // 代入情報を埋め込む | |
836 if (type != 30) value2 = eval(value, type-20, value2); | |
837 cmd_type = CMD_FLAGS; | |
838 args.push_back(info); | |
839 args.push_back(value2); | |
840 dprintf("\n"); | |
841 } else if (StrType(d)) { /* 文字出力 */ | |
842 VarInfo info; | |
843 info.type = TYPE_STR; | |
844 info.value = GetString(d); | |
845 args.push_back(info); | |
846 cmd_type = CMD_TEXT; | |
847 text_flag = true; | |
848 dprintf("\n"); | |
849 } else if (*d == 0x0a || *d == 0x40 || *d == 0x21) { /* デバッグ用データと既読フラグ */ | |
850 cmd_type = CMD_OTHER; | |
851 if (*d == 0x0a) { | |
852 dprintf("line "); | |
853 d++; | |
854 int l; | |
855 if (system_version == 0) { | |
856 l = read_little_endian_int(d); | |
857 d += 4; | |
858 } else { | |
859 l = read_little_endian_short(d); | |
860 d += 2; | |
861 } | |
862 dprintf("%d\n", l); | |
863 } else { /* 0x40, 0x21 */ | |
864 // 既読マーカーらしい。エントリーポイントとセーブポイントも使われる。 | |
865 // RealLive 1.2.5から、0x40はセーブポイント、0x21はエントリーポイント。 | |
866 // 1.2.5以前、どちらも0x40が使われる。 | |
867 int kidoku_index; | |
868 d++; | |
869 if (system_version == 0) { | |
870 kidoku_index = read_little_endian_int(d); | |
871 d += 4; | |
872 } else { | |
873 kidoku_index = read_little_endian_short(d); | |
874 d += 2; | |
875 } | |
876 dprintf("kidoku marker %d\n", kidoku_index); | |
877 // text_readflagは、このkidoku_indexを使ったら良いかな。 | |
878 } | |
879 } else if (*d == 0x2c) { /* ??? */ | |
880 dprintf("commd;0x2c\n"); // conditional jump の行き先によくあるらしい(常に、かはわからない) | |
881 d++; | |
882 } else { | |
883 SetError(); | |
884 } | |
885 return; | |
886 } | |
887 | |
888 char Cmd::strtype[256] = { | |
889 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, /* +00 */ | |
890 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, /* +10 */ | |
891 0,0,3,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, /* +20 */ | |
892 1,1,1,1, 1,1,1,1, 1,1,0,0, 0,0,0,1, /* +30 */ | |
893 0,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1, /* +40 */ | |
894 1,1,1,1, 1,1,1,1, 1,1,1,0, 0,0,0,1, /* +50 */ | |
895 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, /* +60 */ | |
896 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, /* +70 */ | |
897 2,2,2,2, 2,2,2,2, 2,2,2,2, 2,2,2,2, /* +80 */ | |
898 2,2,2,2, 2,2,2,2, 2,2,2,2, 2,2,2,2, /* +90 */ | |
899 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, /* +A0 */ | |
900 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, /* +B0 */ | |
901 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, /* +C0 */ | |
902 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, /* +D0 */ | |
903 2,2,2,2, 2,2,2,2, 2,2,2,2, 2,2,2,2, /* +E0 */ | |
904 2,2,2,2, 2,2,2,2, 2,2,2,2, 2,2,0,0 /* +F0 */ | |
905 }; | |
906 | |
907 int Cmd::GetString(const char*& d) { | |
908 int retnum = -1; | |
909 while(1) { | |
910 if (*d == '\\') { | |
911 d++; | |
912 strheap[strend++] = *d++; | |
913 } else if (*d == '"') { | |
914 d++; | |
915 if (retnum == -1) retnum = strend; | |
916 while(*d != '"') strheap[strend++] = *d++; | |
917 d++; | |
918 } else if (StrType(d)) { | |
919 if (retnum == -1) retnum = strend; | |
920 int stype; | |
921 while( (stype = StrType(d)) ) { | |
922 if (stype == 3) break; // 文中に '"' が現れた場合 | |
923 strheap[strend++] = *d++; | |
924 if (stype == 2) strheap[strend++] = *d++; | |
925 } | |
926 } else break; | |
927 } | |
928 if (retnum != -1) strheap[strend++] = 0; | |
929 dprintf("\"%s\"", strheap + retnum); | |
930 if (strend >= STRHEAP_SIZE) { | |
931 dprintf("Error: string heap overflow\n"); | |
932 } | |
933 return retnum; | |
934 } | |
935 | |
936 int Cmd::StrVar(int var_num) { | |
937 int retnum = strend; | |
938 flags.Str(var_num, strheap+strend, STRHEAP_SIZE-strend); | |
939 strend += strlen(strheap+strend)+1; | |
940 return retnum; | |
941 } | |
942 | |
943 void usage(void) { | |
944 fprintf(stderr,"usage : scn2kdump [inputfile] [outputfile]\n"); | |
945 fprintf(stderr," inputfile: seen.txt(default)\n"); | |
946 fprintf(stderr," outputfile: seen.txt_out(default)\n"); | |
947 exit(-1); | |
948 } | |
949 int main(int argc, char** argv) { | |
950 /* determine file names */ | |
951 bool verbose = false; | |
952 char* inname = "seen.txt"; | |
953 char* outname = 0; | |
954 if (argc > 2 && strcmp(argv[1],"-v") == 0) { | |
955 int i; for (i=1; i<argc; i++) argv[i] = argv[i+1]; | |
956 argc--; | |
957 verbose = true; | |
958 } | |
959 switch(argc) { | |
960 case 1: break; | |
961 case 2: inname = argv[1]; break; | |
962 case 3: inname = argv[1]; outname = argv[2]; break; | |
963 default: usage(); | |
964 } | |
965 /* open output file */ | |
966 FILE* outstream = stdout; | |
967 /* create archive instance */ | |
968 SCN2kFILE archive(inname); | |
969 archive.Init(); | |
970 if (archive.Deal() == 0) { | |
971 fprintf(stderr,"Cannot open / Invalid archive file %s\n",inname); | |
972 usage(); | |
973 } | |
974 /* dump files */ | |
975 archive.InitList(); | |
976 char* fname; | |
977 fprintf(stderr,"Dump start\n"); | |
978 while( (fname = archive.ListItem()) != 0) { | |
979 ARCINFO* info = archive.Find(fname,""); | |
980 if (info == 0) continue; | |
981 char* data = info->CopyRead(); | |
982 char* d = data; | |
983 char* dend = d + info->Size(); | |
984 /* version 確認 */ | |
985 if (read_little_endian_int(d) == 0x1cc) { | |
986 system_version = 0; | |
987 } else if (read_little_endian_int(d) == 0x1d0) { | |
988 system_version = 1; | |
989 } else { | |
990 continue; | |
991 } | |
992 if (read_little_endian_int(d+4) == 0x1adb2) ; // little busters! | |
993 else if (read_little_endian_int(d+4) != 0x2712) continue; | |
994 int header_size; | |
995 if (system_version == 0) { | |
996 header_size = 0x1cc + read_little_endian_int(d+0x20) * 4; | |
997 } else { | |
998 header_size = read_little_endian_int(d+0x20); | |
999 } | |
1000 d += header_size; | |
1001 | |
1002 const char* dcur = d; | |
1003 const char* dstart = d; | |
1004 fprintf(stderr,"Dumping %s\n",fname); | |
1005 fprintf(stdout,"Dumping %s\n",fname); | |
1006 { int i; for (i=0; i<100; i++) { | |
1007 int n = read_little_endian_int(data + 0x34 + i*4); | |
1008 if (n != 6) fprintf(stdout,"subroutine table %2d: %6d\n",i,n); | |
1009 }} | |
1010 Flags flags; | |
1011 /* 最初から最後までコマンド取得 -> 出力を繰り返す */ | |
1012 while(dcur<dend) { | |
1013 const char* dprev = dcur; | |
1014 Cmd cmd(flags); cmd.ClearError(); | |
1015 | |
1016 /* end? */ | |
1017 if (*dcur == -1) { | |
1018 /* 0xff x 32byte + 0x00 : end sign */ | |
1019 int i; for (i=0; i<0x20; i++) | |
1020 if (dcur[i] != -1) break; | |
1021 if (i == 0x20 && dcur[i] == 0) break; | |
1022 } | |
1023 dprintf("%d : ",dcur-dstart); | |
1024 cmd.GetCmd(flags, dcur); | |
1025 if (cmd.IsError()) { | |
1026 fprintf(outstream, "Error at %6d\n",dprev-dstart); | |
1027 while(dcur < dend) { | |
1028 if (*dcur == 0x29 && dcur[1] == 0x0a) {dcur++;break;} | |
1029 if (*dcur == 0 && dcur[1] == 0x0a) {dcur++;break;} | |
1030 if (*dcur == 0 && dcur[1] == 0x23) {dcur++;break;} | |
1031 dcur++; | |
1032 } | |
1033 dprev -= 2*16; | |
1034 int ilen = (dcur-dprev+15)/16; | |
1035 int i; for (i=0; i<ilen; i++) { | |
1036 fprintf(outstream, "%6d: ",dprev-dstart); | |
1037 int j; for (j=0; j<16; j++) { | |
1038 if (dprev >= dend) break; | |
1039 if (dprev < data) continue; | |
1040 fprintf(outstream, "%02x ",*(unsigned char*)(dprev)); | |
1041 dprev++; | |
1042 } | |
1043 fprintf(outstream, "\n"); | |
1044 } | |
1045 } | |
1046 } | |
1047 delete info; | |
1048 } | |
1049 return 0; | |
1050 } | |
1051 | |
1052 /* | |
1053 SetStr | |
1054 0x23 - cmd 01-0a:0000:00[ 2] | |
1055 args:V<18>[17],"PB47" | |
1056 CatStr | |
1057 0x23 - cmd 01-0a:0002:00[ 2] | |
1058 args:V<18>[17],V<18>[20] | |
1059 | |
1060 WaitClick | |
1061 0x23 - cmd 00-03:0011:00[ 0] | |
1062 | |
1063 ChangeFaceGraphics | |
1064 0x23 - cmd 00-03:03e8:00[ 1] | |
1065 args:V<18>[17] | |
1066 DeleteFaceGraphics | |
1067 0x23 - cmd 00-03:03e9:01[ 0] | |
1068 KoePlay | |
1069 0x23 - cmd 01-17:0000:01[ 2] | |
1070 args:100000026,5 | |
1071 DrawGraphics(前景画あり) | |
1072 0x23 - cmd 01-21:004b:00[ 1] | |
1073 args:V<18>[1],10,kasane. #1 <args:V<18>[17],11> | |
1074 | |
1075 DrawGraphics(背景のみ) | |
1076 0x23 - cmd 01-21:0049:00[ 2] | |
1077 args:V<18>[1],10 | |
1078 | |
1079 Ruby | |
1080 0x23 - cmd 00-03:0078:01[ 0] | |
1081 "理由" | |
1082 0x23 - cmd 00-03:0078:00[ 1] | |
1083 "わけ" | |
1084 SetTitle | |
1085 0x23 - cmd 01-04:0000:00[ 1] | |
1086 args:"Long Long Time Ago..." | |
1087 WaitTime | |
1088 0x23 - cmd 01-14:0069:00[ 1] | |
1089 args:3000 | |
1090 ChangeBGM 数値引数はフェードアウト、インの時間と推測 | |
1091 0x23 - cmd 01-14:0000:02[ 3] | |
1092 args:"BGM18",700,700 | |
1093 */ | |
1094 | |
1095 struct CmdDescrItem { | |
1096 CmdDescrItem* next; | |
1097 int cmd4; | |
1098 int cmd1; | |
1099 int cmd2; | |
1100 int cmd3; | |
1101 const char* cmd_descr; | |
1102 }; | |
1103 CmdDescrItem cmd_descr_orig[] = { | |
1104 // scn2k_impl.cc; Scn2k::SysExec() | |
1105 {0,0,0x00,0x01,0x0a, "local return"}, | |
1106 {0,0,0x00,0x01,0x0b, "global jump"}, | |
1107 {0,0,0x00,0x01,0x0c, "global call"}, | |
1108 {0,0,0x00,0x01,0x0d, "global return"}, | |
1109 {0,0,0x00,0x01,0x12, "global call"}, | |
1110 {0,0,0x00,0x01,0x13, "global return(?)"}, | |
1111 {0,0,0x00,0x04,0x0d, "Menu_return"}, | |
1112 {0,0,0x01,0x04,0x00, "SetWindowCaption"}, | |
1113 {0,0,0x01,0x04,0x82, "ClearMousePress"}, | |
1114 {0,0,0x01,0x04,0x83, "GetMouse(2)"}, | |
1115 {0,0,0x01,0x04,0x85, "GetMouse"}, | |
1116 {0,0,0x01,0x04,0x4b0,"QuitGame"}, | |
1117 {0,0,0x01,0x04,0x58d,"PrevSaveNumber"}, | |
1118 {0,0,0x01,0x04,0x585,"SavedDate"}, | |
1119 {0,0,0x01,0x04,0xc23,"Save"}, | |
1120 {0,0,0x01,0x04,0xc25,"Load"}, | |
1121 {0,0,0x01,0x04,0x4b1,"GoMenu"}, | |
1122 {0,0,0x01,0x04,0x4b3,"GoMenu_Badend"}, | |
1123 {0,0,0x01,0x04,0xcc, "ShowMouseCursor"}, | |
1124 {0,0,0x01,0x04,0xcd, "HideMouseCursor"}, | |
1125 {0,0,0x01,0x04,0xcf, "SetCursorType"}, | |
1126 // scn2k_cmd.cc; Cmd::GetCmd() | |
1127 {0,0,0x00,0x01,0, "local jump"}, | |
1128 {0,0,0x00,0x01,1, "local jump-if"}, | |
1129 {0,0,0x00,0x01,2, "local jump-unless"}, | |
1130 {0,0,0x00,0x01,3, "local jump-switch??"}, | |
1131 {0,0,0x00,0x01,4, "local switch"}, | |
1132 {0,0,0x00,0x01,5, "local call"}, | |
1133 {0,0,0x00,0x01,8, "local switch(simple form)"}, | |
1134 {0,0,0x01,0x0b,0, "set multiple variables"}, | |
1135 {0,0,0x01,0x0b,1, "set variables in a range"}, | |
1136 {0,0,0x01,0x0b,4, "clear variables in a range"}, | |
1137 {0,0,0x01,0x0b,0x64, "get summation of variables in a range"}, | |
1138 // scn2k_cmd.cc; Flags::Exec() | |
1139 {0,0,0x01,0x0a,0, "SetStr"}, | |
1140 {0,0,0x01,0x0a,1, "ClearStr"}, | |
1141 {0,0,0x01,0x0a,2, "AppendStr"}, | |
1142 {0,0,0x01,0x0a,3, "StrLen"}, | |
1143 {0,0,0x01,0x0a,4, "StrCmp"}, | |
1144 {0,0,0x01,0x0a,5, "SubStrL"}, | |
1145 {0,0,0x01,0x0a,6, "SubStrR"}, | |
1146 {0,0,0x01,0x0a,7, "StrLenWideChar"}, | |
1147 {0,0,0x01,0x0a,8, "TrimStr"}, | |
1148 {0,0,0x01,0x0a,0x0f, "IntToStr"}, | |
1149 {0,0,0x01,0x0a,0x11, "IntToStr_Fill"}, | |
1150 {0,0,0x01,0x0a,0x64, "ShowStr"}, | |
1151 // scn2k_text.cc; TextImpl::Exec() | |
1152 {0,0,0x01,0x21,0x49, "SetFaceGraphic"}, | |
1153 {0,0,0x01,0x21,0x4b, "SetFaceGraphic"}, | |
1154 {0,0,0x01,0x21,0x4c, "SetFaceGraphic"}, | |
1155 {0,0,0x00,0x03,0x97, "CloseTextWindow"}, | |
1156 {0,0,0x00,0x03,0x11, "WaitText"}, | |
1157 {0,0,0x00,0x03,0x03, "TextReturn"}, | |
1158 {0,0,0x00,0x03,0xc9, "TextReturn"}, | |
1159 {0,0,0x00,0x03,0x3e8,"SetFaceGraphic"}, | |
1160 {0,0,0x00,0x03,0x3e9,"SetFaceGraphic"}, | |
1161 {0,0,0x00,0x03,0x78, "TextRuby"}, | |
1162 {0,0,0x00,0x03,0x66, "SetTextWindowType"}, | |
1163 {0,0,0x00,0x03,0x67, "OpenTextWindow"}, | |
1164 {0,0,0x00,0x03,0x98, "ClearTextWindow"}, | |
1165 {0,0,0x00,0x03,0x68, "ShowText"}, | |
1166 {0,0,0x00,0x02,0x01, "Select"}, | |
1167 {0,0,0x00,0x02,0x03, "Select"}, | |
1168 {0,0,0x00,0x04,0x44c,"TextSkipStart"}, | |
1169 {0,0,0x00,0x04,0x3e8,"CloseTextWindow"}, | |
1170 {0,0,0x01,0x04,0x64, "WaitTime"}, | |
1171 {0,0,0x01,0x04,0x6f, "WaitTime"}, | |
1172 {0,0,0x01,0x04,0x79, "WaitTime"}, | |
1173 {0,0,0x01,0x04,0x65, "WaitTime w/ Cancel"}, | |
1174 {0,0,0x01,0x04,0x70, "WaitTime w/ Cancel"}, | |
1175 {0,0,0x01,0x04,0x1fe,"GetTimer"}, | |
1176 {0,0,0x01,0x04,0x201,"ResetTimer (unsupported; see rldev)"}, | |
1177 {0,0,0x01,0x04,0x202,"ResetTimerAll (unsupported; see rldev)"}, | |
1178 {0,0,0x01,0x04,0x72, "GetTimer"}, | |
1179 {0,0,0x01,0x04,0x7c, "GetTimer(2)"}, | |
1180 {0,0,0x01,0x04,0x6e, "ClearTimer"}, | |
1181 {0,0,0x01,0x04,0x78, "ClearTimer(2)"}, | |
1182 {0,0,0x01,0x04,0x26c,"ClearTimer(multi)"}, | |
1183 {0,0,0x01,0x04,0x270,"ClearTimer(multi)"}, | |
1184 {0,0,0x01,0x04,0x276,"GetTimer(multi)"}, | |
1185 {0,0,0x01,0x04,0x1f4,"SetTimer"}, | |
1186 {0,0,0x01,0x04,0x3e8,"rand(x,y)"}, | |
1187 {0,0,0x01,0x04,0x3ec,"min(x,y)"}, | |
1188 {0,0,0x01,0x04,0x3ef,"min(x,y)"}, | |
1189 {0,0,0x01,0x04,0x320,"range conversion(V,?,ResultMin,ValMin,ValMax,ResultMax,?)"}, | |
1190 {0,0,0x01,0x04,0x3f1,"in_range(x,y,a)"}, | |
1191 {0,0,0x01,0x04,0x16c,"SetCursorType?"}, | |
1192 {0,0,0x01,0x04,0xbc1,"LoadFromMenu"}, | |
1193 {0,0,0x01,0x04,0x8d4,"SetTextWindowColor"}, | |
1194 {0,0,0x01,0x04,0x8d5,"SetTextWindowColor"}, | |
1195 {0,0,0x01,0x04,0x8d6,"SetTextWindowColor"}, | |
1196 {0,0,0x01,0x04,0x8d7,"SetTextWindowColor"}, | |
1197 {0,0,0x01,0x04,0x8d8,"SetTextWindowColor"}, | |
1198 {0,0,0x01,0x04,0x8db,"SetTextWindowColor"}, | |
1199 {0,0,0x01,0x04,0x93f,"SetTextWindowColor"}, | |
1200 {0,0,0x01,0x04,0xa39,"SetTextWindowColor"}, | |
1201 {0,0,0x01,0x04,0xa28,"Get #INIT_MESSAGE_SPEED (original) from gameexe.ini"}, | |
1202 {0,0,0x01,0x04,0xa29,"Get #INIT_MESSAGE_SPEED (original) from gameexe.ini"}, | |
1203 {0,0,0x01,0x04,0xa2c,"Get #MESSAGE_KEY_WAIT_USE (original) from gameexe.ini"}, | |
1204 {0,0,0x01,0x04,0xa2d,"Get #INIT_MESSAGE_SPEED (original) from gameexe.ini"}, | |
1205 {0,0,0x01,0x04,0xa2e,"Get #MESSAGE_KEY_WAIT_TIME (original) from gameexe.ini"}, | |
1206 {0,0,0x01,0x04,0x913,"Get #INIT_MESSAGE_SPEED"}, | |
1207 {0,0,0x01,0x04,0x914,"Get #INIT_MESSAGE_SPEED_MOD"}, | |
1208 {0,0,0x01,0x04,0x92e,"Get #MESSAGE_KEY_WAIT_USE"}, | |
1209 {0,0,0x01,0x04,0x92f,"Get #INIT_MESSAGE_SPEED_MOD"}, | |
1210 {0,0,0x01,0x04,0x930,"Get #MESSAGE_KEY_WAIT_TIME"}, | |
1211 {0,0,0x01,0x04,0x8af,"Set #INIT_MESSAGE_SPEED"}, | |
1212 {0,0,0x01,0x04,0x8b0,"Set #INIT_MESSAGE_SPEED_MOD"}, | |
1213 {0,0,0x01,0x04,0x8ca,"Set #MESSAGE_KEY_WAIT_USE"}, | |
1214 {0,0,0x01,0x04,0x8cb,"Set #INIT_MESSAGE_SPEED_MOD"}, | |
1215 {0,0,0x01,0x04,0x8cc,"Set #MESSAGE_KEY_WAIT_USE"}, | |
1216 {0,0,0x01,0x04,0x51f,"Set Name Text"}, | |
1217 {0,0,0x01,0x04,0x51e,"Get Name Text"}, | |
1218 {0,0,0x01,0x04,0x514,"Get Name Text"}, | |
1219 // scn2k_grp.cc; GrpImpl::Exec() | |
1220 // music commands | |
1221 {0,0,0x01,0x14,0, "PlayBGM"}, | |
1222 {0,0,0x01,0x14,2, "PlayBGM"}, | |
1223 {0,0,0x01,0x14,0x05, "StopBGM"}, | |
1224 {0,0,0x01,0x14,0x69, "FadeBGM"}, | |
1225 {0,0,0x01,0x15,0, "PlaySE"}, | |
1226 {0,0,0x01,0x15,2, "PlaySE"}, | |
1227 {0,0,0x01,0x17,0, "PlayKoe"}, | |
1228 {0,0,0x01,0x1a,1, "PlayMovie"}, | |
1229 {0,0,0x01,0x1a,0x14, "PlayMovie"}, | |
1230 // graphic commands | |
1231 {0,0,0x01,0x1e,0, "GraphicStackClear"}, | |
1232 {0,0,0x01,0x1f,0, "GraphicStackClear"}, | |
1233 {0,0,0x01,0x21,0x46, "LoadSurface"}, | |
1234 {0,0,0x01,0x21,0x49, "LoadBackSurface"}, | |
1235 {0,0,0x01,0x21,0x4b, "LoadForeSurface"}, | |
1236 {0,0,0x01,0x21,0x4c, "LoadSurface"}, | |
1237 {0,0,0x01,0x21,0x64, "CopySurface"}, | |
1238 {0,0,0x01,0x21,0x4b1,"ClearSurface"}, | |
1239 {0,0,0x01,0x21,0x44c,"AlphaCopy"}, | |
1240 {0,0,0x01,0x21,0x640,"SaturateCopy"}, | |
1241 {0,0,0x01,0x21,0x196,"??? grp"}, | |
1242 {0,0,0x01,0x22,0xc30,"ScrollEffect (Princess Bride)"}, | |
1243 {0,0,0x01,0x22,0xc1c,"FallEffect (Princess Bride)"}, | |
1244 {0,0,0x01,0x22,0x835,"FallEffect (Princess Bride)"}, | |
1245 // grphic object commands | |
1246 {0,0,0x01,0x04,0xd2, "??? grp"}, | |
1247 {0,0,0x01,0x04,0xd3, "??? grp"}, | |
1248 {0,0,0x01,0x04,0xd7, "??? grp"}, | |
1249 {0,0,0x01,0x04,0xd8, "??? grp"}, | |
1250 {0,0,0x01,0x04,0x5e0,"GetShownGrpFlag"}, | |
1251 {0,0,0x01,0x3d,0x0a, "ClearGrpObj"}, | |
1252 {0,0,0x01,0x3d,0x0b, "ClearGrpObj"}, | |
1253 {0,0,0x01,0x3e,0x0a, "ClearGrpObj"}, | |
1254 {0,0,0x01,0x3e,0x0a, "ClearGrpObj"}, | |
1255 {0,0,0x01,0x3c,0x01, "??? grp (CLANNAD)"}, | |
1256 {0,0,0x01,0x47,0x3e8,"SetGrpObj_Fname"}, | |
1257 {0,0,0x01,0x47,0x3eb,"SetGrpObj_GANname"}, | |
1258 {0,0,0x01,0x47,0x4b0,"SetGrpObj_Text"}, | |
1259 {0,0,0x01,0x48,0x3e8,"SetGrpObj_ForeGrp?"}, | |
1260 {0,0,0x01,0x49,0, "StopAnimation"}, | |
1261 {0,0,0x01,0x49,3, "QueryExecAnimation"}, | |
1262 {0,0,0x01,0x49,0x7d3,"SetGrpObj_GAN?"}, | |
1263 {0,0,0x01,0x49,0xbb9,"StartAnimation"}, | |
1264 {0,0,0x01,0x49,0xbbb,"StartAnimation"}, | |
1265 {0,0,0x01,0x49,0xbbd,"StartAnimation"}, | |
1266 {0,0,0x01,0x51,0x3e8,"SetGrpObj_xy"}, | |
1267 {0,0,0x01,0x51,0x3e9,"SetGrpObj_x"}, | |
1268 {0,0,0x01,0x51,0x3ea,"SetGrpObj_y"}, | |
1269 {0,0,0x01,0x51,0x3eb,"SetGrpObj_alpha"}, | |
1270 {0,0,0x01,0x51,0x3ec,"SetGrpObj_visible"}, | |
1271 {0,0,0x01,0x51,0x3ee,"SetGrpObj_xy?"}, | |
1272 {0,0,0x01,0x51,0x3fd,"SetGrpObj_centering?"}, | |
1273 {0,0,0x01,0x51,0x401,"SetGrpObj_textsize"}, | |
1274 {0,0,0x01,0x51,0x40a,"SetGrpObj_clipregion"}, | |
1275 {0,0,0x01,0x51,0x40f,"SetGrpObj_surfacenum"}, | |
1276 {0,0,0x01,0x51,0x416,"SetGrpObj_expand"}, | |
1277 {0,0,0x01,0x51,0x419,"SetGrpObj_rotate"}, | |
1278 {0,0,0x01,0x52,0x3e8,"SetGrpObj_xy(2)"}, | |
1279 {0,0,0x01,0x52,0x3ea,"SetGrpObj_y(2)"}, | |
1280 {0,0,0x01,0x52,0x3eb,"SetGrpObj_alpha(2)"}, | |
1281 {0,0,0x01,0x52,0x3ec,"SetGrpObj_visible(2)"}, | |
1282 {0,0,0x01,0x52,0x3ee,"SetGrpObj_xy?(2)"}, | |
1283 {0,0,0x01,0x52,0x3fd,"SetGrpObj_centering?(2)"}, | |
1284 {0,0,0x01,0x52,0x401,"SetGrpObj_textsize(2)"}, | |
1285 {0,0,0x01,0x52,0x408,"SetGrpObj_order (not supported)"}, | |
1286 {0,0,0x01,0x52,0x40a,"SetGrpObj_clipregion(2)"}, | |
1287 {0,0,0x01,0x52,0x40f,"SetGrpObj_surfacenum(2)"}, | |
1288 {0,0,0x01,0x52,0x416,"SetGrpObj_expand(2)"}, | |
1289 {0,0,0x01,0x52,0x419,"SetGrpObj_rotate(2)"}, | |
1290 {0,0,0x01,0x54,0x3e8,"GetGrpObj_xy"}, | |
1291 {0,0,0x01,0x54,0x44c,"GetGrpObj_wh"}, | |
1292 | |
1293 {0,0,0x02,0x3d,0x0a, "ClearGrpObj(2)"}, | |
1294 {0,0,0x02,0x3d,0x0b, "ClearGrpObj(2)"}, | |
1295 {0,0,0x02,0x3e,0x0a, "ClearGrpObj(2)"}, | |
1296 {0,0,0x02,0x3e,0x0a, "ClearGrpObj(2)"}, | |
1297 {0,0,0x02,0x3c,0x01, "??? grp (CLANNAD)(2)"}, | |
1298 {0,0,0x02,0x47,0x3e8,"SetGrpObj_Fname(2)"}, | |
1299 {0,0,0x02,0x47,0x3eb,"SetGrpObj_GANname(2)"}, | |
1300 {0,0,0x02,0x47,0x4b0,"SetGrpObj_Text(2)"}, | |
1301 {0,0,0x02,0x48,0x3e8,"SetGrpObj_ForeGrp?(2)"}, | |
1302 {0,0,0x02,0x49,0, "StopAnimation(2)"}, | |
1303 {0,0,0x02,0x49,3, "QueryExecAnimation(2)"}, | |
1304 {0,0,0x02,0x49,0x7d3,"SetGrpObj_GAN?(2)"}, | |
1305 {0,0,0x02,0x49,0xbb9,"StartAnimation(2)"}, | |
1306 {0,0,0x02,0x49,0xbbb,"StartAnimation(2)"}, | |
1307 {0,0,0x02,0x49,0xbbd,"StartAnimation(2)"}, | |
1308 {0,0,0x02,0x51,0x3e8,"SetGrpObj_xy(2)"}, | |
1309 {0,0,0x02,0x51,0x3ea,"SetGrpObj_y(2)"}, | |
1310 {0,0,0x02,0x51,0x3eb,"SetGrpObj_alpha(2)"}, | |
1311 {0,0,0x02,0x51,0x3ec,"SetGrpObj_visible(2)"}, | |
1312 {0,0,0x02,0x51,0x3ee,"SetGrpObj_xy?(2)"}, | |
1313 {0,0,0x02,0x51,0x3fd,"SetGrpObj_centering?(2)"}, | |
1314 {0,0,0x02,0x51,0x401,"SetGrpObj_textsize(2)"}, | |
1315 {0,0,0x02,0x51,0x40a,"SetGrpObj_clipregion(2)"}, | |
1316 {0,0,0x02,0x51,0x40f,"SetGrpObj_surfacenum(2)"}, | |
1317 {0,0,0x02,0x51,0x416,"SetGrpObj_expand(2)"}, | |
1318 {0,0,0x02,0x51,0x419,"SetGrpObj_rotate(2)"}, | |
1319 {0,0,0x02,0x52,0x3e8,"SetGrpObj_xy(2)(2)"}, | |
1320 {0,0,0x02,0x52,0x3ea,"SetGrpObj_y(2)(2)"}, | |
1321 {0,0,0x02,0x52,0x3eb,"SetGrpObj_alpha(2)(2)"}, | |
1322 {0,0,0x02,0x52,0x3ec,"SetGrpObj_visible(2)(2)"}, | |
1323 {0,0,0x02,0x52,0x3ee,"SetGrpObj_xy?(2)(2)"}, | |
1324 {0,0,0x02,0x52,0x3fd,"SetGrpObj_centering?(2)(2)"}, | |
1325 {0,0,0x02,0x52,0x401,"SetGrpObj_textsize(2)(2)"}, | |
1326 {0,0,0x02,0x52,0x40a,"SetGrpObj_clipregion(2)(2)"}, | |
1327 {0,0,0x02,0x52,0x40f,"SetGrpObj_surfacenum(2)(2)"}, | |
1328 {0,0,0x02,0x52,0x416,"SetGrpObj_expand(2)(2)"}, | |
1329 {0,0,0x02,0x52,0x419,"SetGrpObj_rotate(2)(2)"}, | |
1330 {0,0,0x02,0x54,0x3e8,"GetGrpObj_xy(2)"}, | |
1331 {0,0,0x02,0x54,0x44c,"GetGrpObj_wh(2)"}, | |
1332 {0,0,0,0,0,0} | |
1333 }; | |
1334 map<int, CmdDescrItem*> Cmd::cmd_descr; | |
1335 const char* Cmd::CmdDescr(int cmd1, int cmd2, int cmd3, int cmd4) { | |
1336 if (cmd_descr.empty()) { | |
1337 int i; | |
1338 for (i=0; cmd_descr_orig[i].cmd_descr != 0; i++) { | |
1339 CmdDescrItem& cur = cmd_descr_orig[i]; | |
1340 int item_num = cur.cmd1*1000000+cur.cmd2*10000+cur.cmd3; | |
1341 map<int,CmdDescrItem*>::iterator it = cmd_descr.find(item_num); | |
1342 if (it == cmd_descr.end()) cmd_descr[item_num] = &cur; | |
1343 else { | |
1344 cur.next = it->second; | |
1345 it->second = &cur; | |
1346 } | |
1347 } | |
1348 } | |
1349 int item_num = cmd1*1000000+cmd2*10000+cmd3; | |
1350 map<int,CmdDescrItem*>::iterator it = cmd_descr.find(item_num); | |
1351 if (it == cmd_descr.end()) return "No descr (unsupported)"; | |
1352 CmdDescrItem* cur = it->second; | |
1353 do { | |
1354 if (cur->cmd1 == cmd1 && cur->cmd2 == cmd2 && cur->cmd3 == cmd3) { | |
1355 return cur->cmd_descr; | |
1356 } | |
1357 cur = cur->next; | |
1358 } while(cur != 0); | |
1359 return "No descr (unsupported)"; | |
1360 } |