scummvm/simon/debug.cpp

775 lines
14 KiB
C++
Raw Normal View History

/* ScummVM - Scumm Interpreter
* Copyright (C) 2001/2002 The ScummVM project
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* $Header$
*
*/
// Simon debug functions
#include "stdafx.h"
2002-08-21 16:07:07 +00:00
#include "simon/simon.h"
#include "simon/intern.h"
#include "simon/vga.h"
#if defined (WIN32) && !defined(_WIN32_WCE)
#include <sys/stat.h>
#endif
#ifdef SIMONDEBUG
#define SIMON2
#define SIMON2WIN
2002-07-07 19:06:48 +00:00
static const char *const opcode_name_table[256] = {
/* 0 */
"|INV_COND",
"IJ|PTRA_PARENT_IS",
"IJ|PTRA_PARENT_ISNOT",
NULL,
/* 4 */
NULL,
"IJ|PARENT_IS_1",
"IJ|PARENT_ISNOT_1",
"IIJ|PARENT_IS",
/* 8 */
NULL,
NULL,
NULL,
"VJ|IS_ZERO",
/* 12 */
"VJ|ISNOT_ZERO",
"VWJ|IS_EQ",
"VWJ|IS_NEQ",
"VWJ|IS_LE",
/* 16 */
"VWJ|IS_GE",
"VVJ|IS_EQF",
"VVJ|IS_NEQF",
"VVJ|IS_LEF",
/* 20 */
"VVJ|IS_GEF",
NULL,
NULL,
"WJ|UNK23",
/* 24 */
NULL,
"IJ|HAS_CHILD_1",
"IJ|HAS_CHILD_2",
"IWJ|ITEM_UNK3_IS",
/* 28 */
"IBJ|CHILD_HAS_FLAG",
NULL,
NULL,
"I|SET_NO_PARENT",
/* 32 */
NULL,
"II|SET_PARENT",
NULL,
NULL,
/* 36 */
"VV|MOVE",
NULL,
NULL,
NULL,
/* 40 */
NULL,
"V|ZERO",
"VW|SET",
"VW|ADD",
/* 44 */
"VW|SUB",
"VV|ADDF",
"VV|SUBF",
"VW|MUL",
/* 48 */
"VW|DIV",
"VV|MULF",
"VV|DIVF",
"VW|MOD",
/* 52 */
"VV|MODF",
"VW|RANDOM",
NULL,
"I|SET_A_PARENT",
/* 56 */
"IB|SET_CHILD2_BIT",
"IB|CLEAR_CHILD2_BIT",
"II|MAKE_SIBLING",
"I|INC_UNK3",
/* 60 */
"I|DEC_UNK3",
"IW|SET_UNK3",
"V|SHOW_INT",
"T|SHOW_STRING_NL",
/* 64 */
"T|SHOW_STRING",
"WWWWWB|ADD_HITAREA",
"BT|SET_ITEM_NAME",
#if defined SIMON1WIN || defined SIMON2
"BTw|SET_ITEM_DESC",
#endif
#ifdef SIMON1DOS
"BT|SET_ITEM_DESC",
#endif
/* 68 */
"x|HALT",
"x|RET1",
"V|SHOW_STRING_AR3",
"W|START_SUB",
/* 72 */
NULL,
NULL,
NULL,
NULL,
/* 76 */
"WW|ADD_TIMEOUT",
"J|IS_M1_EMPTY",
"J|IS_M3_EMPTY",
"ITJ|CHILD_FR2_IS",
/* 80 */
"IIJ|IS_ITEM_EQ",
NULL,
"B|UNK82",
"|RETM10",
/* 84 */
NULL,
NULL,
NULL,
"W|UNK87",
/* 88 */
"|OR_SCRIPT_WORD_10",
"|AND_SCRIPT_WORD_10",
"IB|SET_M_TO_PARENT",
"IB|SET_M_TO_SIBLING",
/* 92 */
"IB|SET_M_TO_CHILD",
NULL,
NULL,
NULL,
/* 96 */
"WB|UNK96",
"W|LOAD_VGA",
#ifdef SIMON2
"WWBWWW|START_VGA",
#else
"WBWWW|START_VGA",
#endif
#ifdef SIMON2
"WW|KILL_THREAD",
#else
"W|KILL_THREAD",
#endif
/* 100 */
"|VGA_RESET",
"BWWWWWW|UNK101",
"B|UNK102",
"|UNK103",
/* 104 */
"B|UNK104",
NULL,
NULL,
"WWWWWIW|ADD_ITEM_HITAREA",
/* 108 */
"W|DEL_HITAREA",
"W|CLEAR_HITAREA_0x40",
"W|SET_HITAREA_0x40",
"WWW|SET_HITAREA_XY",
/* 112 */
NULL,
NULL,
"IB|UNK114",
"IBJ|HAS_FLAG",
/* 116 */
"IB|SET_FLAG",
"IB|CLEAR_FLAG",
NULL,
"W|WAIT_VGA",
/* 120 */
"W|UNK120",
"BI|SET_VGA_ITEM",
NULL,
NULL,
/* 124 */
NULL,
"IJ|IS_SIBLING_WITH_A",
"IBB|UNK126",
"WW|UNK127",
/* 128 */
"W|GET_DUMMY_WORD",
"W|GET_WORD_COND_TRUE",
"Bww|UNK131",
2002-07-07 19:06:48 +00:00
NULL, /* opcode 131 doesn't exist */
/* 132 */
"|SAVE_GAME",
"|LOAD_GAME",
"|DUMMYPROC_134",
"|QUIT_IF_USER_PRESSES_Y",
/* 136 */
"IV|GET_ITEM_UNK3",
"B|UNK137",
"|VGA_POINTER_OP_4",
"II|SET_PARENT_SPECIAL",
/* 140 */
"|DEL_TE_AND_ADD_ONE",
"BI|SET_M1_OR_M3",
"WJ|IS_HITAREA_0x40_CLEAR",
"I|START_ITEM_SUB",
/* 144 */
NULL,
NULL,
NULL,
NULL,
/* 148 */
NULL,
NULL,
NULL,
"BI|SET_ARRAY6_TO",
/* 152 */
"BB|SET_M1_M3_TO_ARRAY6",
"B|SET_BIT",
"B|CLEAR_BIT",
"BJ|IS_BIT_CLEAR",
/* 156 */
"BJ|IS_BIT_SET",
"IBB|GET_ITEM_PROP",
"IBW|SET_ITEM_PROP",
NULL,
/* 160 */
"B|UNK160",
"BWBW|SETUP_TEXT",
#if defined SIMON1WIN || defined SIMON2
"BBTW|PRINT_STR",
#endif
#ifdef SIMON1DOS
"BBT|PRINT_STR",
#endif
"W|SOUND_1",
/* 164 */
"|UNK164",
"IWWJ|ITEM_UNK1_UNK2_IS",
"B|SET_BIT2",
"B|CLEAR_BIT2",
/* 168 */
"BJ|IS_BIT2_CLEAR",
"BJ|IS_BIT2_SET",
NULL,
NULL,
/* 172 */
NULL,
NULL,
NULL,
"|VGA_POINTER_OP_1",
/* 176 */
"|VGA_POINTER_OP_2",
"BBI|UNK177",
"WWBB|PATHFIND",
"BBB|UNK179",
/* 180 */
"|FORCE_UNLOCK",
"|FORCE_LOCK",
"|READ_VGARES_328",
"|READ_VGARES_23",
/* 184 */
"W|CLEAR_VGAPOINTER_ENTRY",
"W|DUMMY_185",
"|VGA_POINTER_OP_3",
"|FADE_TO_BLACK",
#ifdef SIMON2
/* 188 */
"BSJ|STRING2_IS",
"|UNK189",
"B|UNK190",
#endif
};
2002-07-07 19:06:48 +00:00
byte *SimonState::dumpOpcode(byte *p)
{
byte opcode;
const char *s, *st;
opcode = *p++;
if (opcode == 255)
return NULL;
st = s = opcode_name_table[opcode];
if (s == NULL) {
error("INVALID OPCODE %d\n", opcode);
return NULL;
}
2002-07-07 19:06:48 +00:00
while (*st != '|')
st++;
fprintf(_dump_file, "%s ", st + 1);
2002-07-07 19:06:48 +00:00
for (;;) {
switch (*s++) {
case 'x':
2002-07-07 19:06:48 +00:00
fprintf(_dump_file, "\n");
return NULL;
case '|':
2002-07-07 19:06:48 +00:00
fprintf(_dump_file, "\n");
return p;
2002-07-07 19:06:48 +00:00
case 'B':{
byte b = *p++;
if (b == 255)
fprintf(_dump_file, "[%d] ", *p++);
else
fprintf(_dump_file, "%d ", b);
break;
}
case 'V':{
byte b = *p++;
if (b == 255)
fprintf(_dump_file, "[[%d]] ", *p++);
else
fprintf(_dump_file, "[%d] ", b);
break;
}
2002-07-07 19:06:48 +00:00
case 'W':{
int n = (int16)((p[0] << 8) | p[1]);
p += 2;
if (n >= 30000 && n < 30512)
fprintf(_dump_file, "[%d] ", n - 30000);
else
fprintf(_dump_file, "%d ", n);
break;
}
case 'w':{
int n = (int16)((p[0] << 8) | p[1]);
p += 2;
fprintf(_dump_file, "%d ", n);
break;
}
2002-07-07 19:06:48 +00:00
case 'I':{
int n = (int16)((p[0] << 8) | p[1]);;
p += 2;
if (n == -1)
fprintf(_dump_file, "ITEM_M1 ");
else if (n == -3)
fprintf(_dump_file, "ITEM_M3 ");
else if (n == -5)
fprintf(_dump_file, "ITEM_1 ");
else if (n == -7)
fprintf(_dump_file, "ITEM_0 ");
else if (n == -9)
fprintf(_dump_file, "ITEM_A_PARENT ");
else
fprintf(_dump_file, "<%d> ", n);
break;
}
case 'J':{
fprintf(_dump_file, "-> ");
}
break;
2002-07-07 19:06:48 +00:00
case 'T':{
uint n = ((p[0] << 8) | p[1]);
p += 2;
if (n != 0xFFFF)
fprintf(_dump_file, "\"%s\"(%d) ", getStringPtrByID(n), n);
else
fprintf(_dump_file, "NULL_STRING ");
}
break;
}
}
}
2002-07-07 19:06:48 +00:00
void SimonState::dumpSubroutineLine(SubroutineLine *sl, Subroutine *sub)
{
byte *p;
2002-07-07 19:06:48 +00:00
printf("; ****\n");
2002-07-07 19:06:48 +00:00
p = (byte *)sl + SUBROUTINE_LINE_SMALL_SIZE;
if (sub->id == 0) {
2002-07-07 19:06:48 +00:00
fprintf(_dump_file, "; cond_a=%d, cond_b=%d, cond_c=%d\n", sl->cond_a, sl->cond_b, sl->cond_c);
p = (byte *)sl + SUBROUTINE_LINE_BIG_SIZE;
}
2002-07-07 19:06:48 +00:00
for (;;) {
p = dumpOpcode(p);
2002-07-07 19:06:48 +00:00
if (p == NULL)
break;
}
}
2002-07-07 19:06:48 +00:00
void SimonState::dumpSubroutine(Subroutine *sub)
{
SubroutineLine *sl;
2002-07-07 19:06:48 +00:00
fprintf(_dump_file,
"\n******************************************\n;Subroutine, ID=%d:\nSUB_%d:\n", sub->id,
sub->id);
sl = (SubroutineLine *)((byte *)sub + sub->first);
for (; (byte *)sl != (byte *)sub; sl = (SubroutineLine *)((byte *)sub + sl->next)) {
dumpSubroutineLine(sl, sub);
}
2002-07-07 19:06:48 +00:00
fprintf(_dump_file, "\nEND ******************************************\n");
fflush(_dump_file);
}
2002-07-07 19:06:48 +00:00
void SimonState::dumpSubroutines()
{
Subroutine *sub = _subroutine_list;
2002-07-07 19:06:48 +00:00
for (; sub; sub = sub->next) {
dumpSubroutine(sub);
}
}
2002-07-07 19:06:48 +00:00
const char *const video_opcode_name_table[] = {
/* 0 */
"x|RET",
"ddd|DUMMY",
"d|CALL",
"ddddd|NEW_THREAD",
/* 4 */
"ddd|DUMMY_2",
"vd|SKIP_IF_NEQ",
"d|SKIP_IFN_SIB_WITH_A",
"d|SKIP_IF_SIB_WITH_A",
/* 8 */
"dd|SKIP_IF_PARENT_IS",
"dd|SKIP_IF_UNK3_IS",
#ifdef SIMON2
"ddddb|DRAW",
#else
"ddddd|DRAW",
#endif
"|CLEAR_PATHFIND_ARRAY",
/* 12 */
#ifdef SIMON2
"b|DELAY",
#else
"d|DELAY",
#endif
"d|OFFSET_X",
"d|OFFSET_Y",
"d|IDENT_WAKEUP",
/* 16 */
"d|IDENT_SLEEP",
"dq|SET_PATHFIND_ITEM",
"i|JUMP_REL",
"|CHAIN_TO",
/* 20 */
"dd|SET_CODE_WORD",
"i|JUMP_IF_CODE_WORD",
"dd|SET_PAL",
"d|SET_PRI",
/* 24 */
"diid|SET_IMG_XY",
"x|HALT_THREAD",
"ddddd|SET_WINDOW",
"|RESET",
/* 28 */
"dddd|DUMMY_3",
"|STOP_ALL_SOUNDS",
"d|SET_BASE_DELAY",
"d|SET_PALETTE_MODE",
/* 32 */
"vv|COPY_VAR",
"|FORCE_UNLOCK",
"|FORCE_LOCK",
"dd|DUMMY_4",
/* 36 */
"dd|SAVELOAD_THING",
"v|OFFSET_Y_F",
"v|SKIP_IF_VAR_ZERO",
"vd|SET_VAR",
/* 40 */
"vd|ADD_VAR",
"vd|SUB_VAR",
"vd|SLEEP_UNTIL_SET",
"d|SKIP_IF_BIT_CLEAR",
/* 44 */
2002-07-07 19:06:48 +00:00
"d|SKIP_IF_BIT_SET",
"v|SET_X_F",
"v|SET_Y_F",
"vv|ADD_VAR_F",
/* 48 */
"|VC_48",
"d|SET_BIT",
"d|CLEAR_BIT",
"d|CLEAR_HITAREA_BIT_0x40",
/* 52 */
"d|VC_52",
"dd|DUMMY_5",
"ddd|DUMMY_6",
"ddd|OFFSET_HIT_AREA",
/* 56 */
#ifdef SIMON2
"i|SLEEP_EX",
#else
"|DUMMY_7",
#endif
"|DUMMY_8",
"|DUMMY_9",
#ifdef SIMON2
"ddd|KILL_MULTI_THREAD",
#else
"|SKIP_IF_SOUND??",
#endif
/* 60 */
#ifdef SIMON2
"dd|KILL_THREAD",
#else
"d|KILL_THREAD",
#endif
"ddd|INIT_SPRITE",
"|PALETTE_THING",
"|PALETTE_THING_2",
#ifdef SIMON2
/* 64 */
"|UNK64",
"|UNK65",
"|UNK66",
"|UNK67",
/* 68 */
"|UNK68",
"dd|UNK69",
"dd|UNK70",
"|UNK71",
/* 72 */
"dd|UNK72",
"bb|UNK73",
"bb|UNK74",
#endif
};
2002-07-07 19:06:48 +00:00
void SimonState::dump_video_script(byte *src, bool one_opcode_only)
{
uint opcode;
const char *str, *strn;
do {
if (!(_game & GAME_SIMON2)) {
opcode = READ_BE_UINT16_UNALIGNED(src);
2002-07-07 19:06:48 +00:00
src += 2;
} else {
opcode = *src++;
}
if (opcode >= gss->NUM_VIDEO_OP_CODES) {
error("Invalid opcode %x\n", opcode);
return;
}
strn = str = video_opcode_name_table[opcode];
2002-07-07 19:06:48 +00:00
while (*strn != '|')
strn++;
fprintf(_dump_file, "%.2d: %s ", opcode, strn + 1);
for (; *str != '|'; str++) {
switch (*str) {
case 'x':
fprintf(_dump_file, "\n");
return;
case 'b':
fprintf(_dump_file, "%d ", *src++);
break;
case 'd':
fprintf(_dump_file, "%d ", READ_BE_UINT16_UNALIGNED(src));
src += 2;
break;
case 'v':
fprintf(_dump_file, "[%d] ", READ_BE_UINT16_UNALIGNED(src));
src += 2;
break;
case 'i':
fprintf(_dump_file, "%d ", (int16)READ_BE_UINT16_UNALIGNED(src));
src += 2;
break;
case 'q':
while (READ_BE_UINT16_UNALIGNED(src) != 999) {
2002-07-07 19:06:48 +00:00
fprintf(_dump_file, "(%d,%d) ", READ_BE_UINT16_UNALIGNED(src),
READ_BE_UINT16_UNALIGNED(src + 2));
src += 4;
}
src++;
break;
default:
error("Invalid fmt string '%c' in decompile VGA", *str);
}
}
2002-07-07 19:06:48 +00:00
fprintf(_dump_file, "\n");
} while (!one_opcode_only);
}
2002-07-07 19:06:48 +00:00
void SimonState::dump_vga_file(byte *vga)
{
{
byte *pp;
byte *p;
int count;
pp = vga;
2002-07-07 19:06:48 +00:00
p = pp + READ_BE_UINT16_UNALIGNED(&((VgaFile1Header *) pp)->hdr2_start);
count = READ_BE_UINT16_UNALIGNED(&((VgaFile1Header2 *) p)->id_count);
p = pp + READ_BE_UINT16_UNALIGNED(&((VgaFile1Header2 *) p)->id_table);
while (--count >= 0) {
2002-07-07 19:06:48 +00:00
int id = READ_BE_UINT16_UNALIGNED(&((VgaFile1Struct0x6 *) p)->id);
2002-07-07 19:06:48 +00:00
dump_vga_script_always(vga +
READ_BE_UINT16_UNALIGNED(&((VgaFile1Struct0x6 *) p)->script_offs),
id / 100, id);
p += sizeof(VgaFile1Struct0x6);
}
}
{
byte *bb, *b;
int c;
bb = vga;
2002-07-07 19:06:48 +00:00
b = bb + READ_BE_UINT16_UNALIGNED(&((VgaFile1Header *) bb)->hdr2_start);
c = READ_BE_UINT16_UNALIGNED(&((VgaFile1Header2 *) b)->unk1);
b = bb + READ_BE_UINT16_UNALIGNED(&((VgaFile1Header2 *) b)->unk2_offs);
while (--c >= 0) {
2002-07-07 19:06:48 +00:00
int id = READ_BE_UINT16_UNALIGNED(&((VgaFile1Struct0x8 *) b)->id);
2002-07-07 19:06:48 +00:00
dump_vga_script_always(vga +
READ_BE_UINT16_UNALIGNED(&((VgaFile1Struct0x8 *) b)->script_offs),
id / 100, id);
b += sizeof(VgaFile1Struct0x8);
}
}
}
const byte bmp_hdr[] = {
2002-07-07 19:06:48 +00:00
0x42, 0x4D,
0x9E, 0x14, 0x00, 0x00, /* offset 2, file size */
0x00, 0x00, 0x00, 0x00,
0x36, 0x04, 0x00, 0x00,
0x28, 0x00, 0x00, 0x00,
0x3C, 0x00, 0x00, 0x00, /* image width */
0x46, 0x00, 0x00, 0x00, /* image height */
0x01, 0x00, 0x08, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x01, 0x00, 0x00,
0x00, 0x01, 0x00, 0x00,
};
2002-07-07 19:06:48 +00:00
void dump_bmp(const char *filename, int w, int h, const byte *bytes, const uint32 *palette)
{
FILE *out = fopen(filename, "wb");
byte my_hdr[sizeof(bmp_hdr)];
int i;
if (out == NULL) {
printf("DUMP ERROR\n");
return;
}
memcpy(my_hdr, bmp_hdr, sizeof(bmp_hdr));
2002-07-07 19:06:48 +00:00
*(uint32 *)(my_hdr + 2) = w * h + 1024 + sizeof(bmp_hdr);
*(uint32 *)(my_hdr + 18) = w;
*(uint32 *)(my_hdr + 22) = h;
fwrite(my_hdr, 1, sizeof(my_hdr), out);
2002-07-07 19:06:48 +00:00
for (i = 0; i != 256; i++, palette++) {
byte color[4];
color[0] = (byte)(*palette >> 16);
color[1] = (byte)(*palette >> 8);
color[2] = (byte)(*palette);
color[3] = 0;
fwrite(color, 1, 4, out);
}
while (--h >= 0) {
2002-07-07 19:06:48 +00:00
fwrite(bytes + h * ((w + 3) & ~3), ((w + 3) & ~3), 1, out);
}
fclose(out);
}
2002-07-07 19:06:48 +00:00
void dump_bitmap(const char *filename, byte *offs, int w, int h, int flags, const byte *palette,
byte base)
{
/* allocate */
2002-07-07 19:06:48 +00:00
byte *b = (byte *)malloc(w * h);
int i, j;
VC10_state state;
state.depack_cont = -0x80;
state.depack_src = offs;
state.dh = h;
state.y_skip = 0;
2002-07-07 19:06:48 +00:00
for (i = 0; i != w; i += 2) {
byte *c = vc_10_depack_column(&state);
2002-07-07 19:06:48 +00:00
for (j = 0; j != h; j++) {
byte pix = c[j];
2002-07-07 19:06:48 +00:00
b[j * w + i] = (pix >> 4) | base;
b[j * w + i + 1] = (pix & 0xF) | base;
}
}
2002-07-07 19:06:48 +00:00
dump_bmp(filename, w, h, b, (uint32 *)palette);
free(b);
}
2002-07-07 19:06:48 +00:00
void SimonState::dump_single_bitmap(int file, int image, byte *offs, int w, int h, byte base)
{
/* Only supported for win32 atm. mkdir doesn't work otherwise. */
#if defined (WIN32) && !defined(_WIN32_WCE)
char buf[255], buf2[255];
struct stat statbuf;
sprintf(buf, "bmp_%d\\%d.bmp", file, image);
if (stat(buf, &statbuf) == 0)
return;
sprintf(buf2, "bmp_%d", file);
mkdir(buf2);
dump_bitmap(buf, offs, w, h, 0, _palette, base);
#endif
}
2002-07-07 19:06:48 +00:00
void SimonState::dump_vga_script_always(byte *ptr, uint res, uint sprite_id)
{
fprintf(_dump_file, "; address=%x, vgafile=%d vgasprite=%d\n",
ptr - _vga_buffer_pointers[res].vgaFile1, res, sprite_id);
dump_video_script(ptr, false);
2002-07-07 19:06:48 +00:00
fprintf(_dump_file, "; end\n");
}
2002-07-07 19:06:48 +00:00
void SimonState::dump_vga_script(byte *ptr, uint res, uint sprite_id)
{
dump_vga_script_always(ptr, res, sprite_id);
}
#endif