Files
scummex/descumm6.cpp

2400 lines
43 KiB
C++

/* DeScumm - Scumm Script Disassembler (version 6-8 scripts)
* Copyright (C) 2001 Ludvig Strigeus
* Copyright (C) 2002, 2003 The ScummVM Team
*
* 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: /Users/sev/projects/sc/s/scummvm/scummex/descumm6.cpp,v 1.1 2003/09/19 19:57:07 yoshizf Exp $
*
*/
#include "file.h"
#include "wxwindows.h"
#include "descumm.h"
enum {
seInt = 1,
seVar = 2,
seArray = 3,
seBinary = 4,
seUnary = 5,
seComplex = 6,
seStackList = 7,
seDup = 8,
seNeg = 9
};
enum {
isZero,
isEqual,
isNotEqual,
isGreater,
isLess,
isLessEqual,
isGreaterEqual,
operAdd,
operSub,
operMul,
operDiv,
operLand,
operLor,
operBand,
operBor,
operMod
};
static const char *oper_list[] = {
"0==",
"==",
"!=",
">",
"<",
"<=",
">=",
"+",
"-",
"*",
"/",
"&&",
"||",
"&",
"|",
"%"
};
StackEnt *stack[128];
int num_stack;
bool HumongousFlag = false;
const char *var_names6[] = {
/* 0 */
NULL,
"g_ego",
"g_camera_cur_pos",
"g_have_msg",
/* 4 */
"g_room",
"g_override",
NULL,
NULL,
/* 8 */
"g_num_actor",
NULL,
"g_drive_number",
"g_timer_1",
/* 12 */
"g_timer_2",
"g_timer_3",
NULL,
NULL,
/* 16 */
NULL,
"g_camera_min",
"g_camera_max",
"g_timer_next",
/* 20 */
"g_virtual_mouse_x",
"g_virtual_mouse_y",
"g_room_resource",
"g_last_sound",
/* 24 */
"g_cutsceneexit_key",
"g_talk_actor",
"g_camera_fast",
"g_scroll_script",
/* 28 */
"g_entry_script",
"g_entry_script_2",
"g_exit_script",
"g_exit_script_2",
/* 32 */
"g_verb_script",
"g_sentence_script",
"g_hook_script",
"g_begin_cutscene_script",
/* 36 */
"g_end_cutscene_script",
"g_char_inc",
"g_walkto_obj",
"g_debug_mode",
/* 40 */
"g_heap_space",
"g_scr_width",
"g_restart_key",
"g_pause_key",
/* 44 */
"g_mouse_x",
"g_mouse_y",
"g_timer",
"g_timer_4",
/* 48 */
NULL,
"g_video_mode",
"g_save_load_key",
"g_fixed_disk",
/* 52 */
"g_cursor_state",
"g_user_put",
"g_scr_height",
NULL,
/* 56 */
"g_sound_thing",
"g_talkstop_key",
NULL,
NULL,
/* 60 */
NULL,
NULL,
NULL,
NULL,
/* 64 */
"g_sound_param",
"g_sound_param_2",
"g_sound_param_3",
"g_mouse_present",
/* 68 */
"g_performance_1",
"g_performance_2",
NULL,
"g_save_load_thing",
/* 72 */
"g_new_room",
NULL,
NULL,
NULL,
/* 76 */
"g_ems_space"
};
const char *var_names7[] = {
/* 0 */
NULL,
"VAR_MOUSE_X",
"VAR_MOUSE_Y",
"VAR_VIRT_MOUSE_X",
/* 4 */
"VAR_VIRT_MOUSE_Y",
"VAR_V6_SCREEN_WIDTH",
"VAR_V6_SCREEN_HEIGHT",
"VAR_CAMERA_POS_X",
/* 8 */
"VAR_CAMERA_POS_Y",
"VAR_OVERRIDE",
"VAR_ROOM",
"VAR_ROOM_RESOURCE",
/* 12 */
"VAR_TALK_ACTOR",
"VAR_HAVE_MSG",
"VAR_TIMER",
"VAR_TMR_4",
/* 16 */
NULL,
NULL,
NULL,
NULL,
/* 20 */
NULL,
NULL,
"VAR_LEFTBTN_DOWN",
"VAR_RIGHTBTN_DOWN",
/* 24 */
"VAR_LEFTBTN_HOLD",
"VAR_RIGHTBTN_HOLD",
"VAR_PERFORMANCE_1",
"VAR_PERFORMANCE_2",
/* 28 */
NULL,
NULL,
NULL,
NULL,
/* 32 */
"VAR_V6_EMSSPACE",
NULL,
"VAR_V6_RANDOM_NR",
"VAR_NEW_ROOM",
/* 36 */
"VAR_WALKTO_OBJ",
NULL,
"VAR_CAMERA_DEST_X",
"VAR_CAMERA_DEST_>",
/* 40 */
"VAR_CAMERA_FOLLOWED_ACTOR",
NULL,
NULL,
NULL,
/* 44 */
NULL,
NULL,
NULL,
NULL,
/* 48 */
NULL,
NULL,
"VAR_SCROLL_SCRIPT",
"VAR_ENTRY_SCRIPT",
/* 52 */
"VAR_ENTRY_SCRIPT2",
"VAR_EXIT_SCRIPT",
"VAR_EXIT_SCRIPT2",
"VAR_VERB_SCRIPT",
/* 56 */
"VAR_SENTENCE_SCRIPT",
"VAR_HOOK_SCRIPT",
"VAR_CUTSCENE_START_SCRIPT",
"VAR_CUTSCENE_END_SCRIPT",
/* 60 */
"VAR_UNK_SCRIPT",
"VAR_UNK_SCRIPT2",
"VAR_CUTSCENEEXIT_KEY",
"VAR_RESTART_KEY", // ???
/* 64 */
"VAR_PAUSE_KEY",
"VAR_SAVELOADDIALOG_KEY", // ???
NULL,
"VAR_TALKSTOP_KEY", // ???
/* 68 */
NULL,
NULL,
NULL,
NULL,
/* 72 */
NULL,
NULL,
NULL,
NULL,
/* 76 */
NULL,
NULL,
NULL,
NULL,
/* 80 */
NULL,
NULL,
NULL,
NULL,
/* 84 */
NULL,
NULL,
NULL,
NULL,
/* 88 */
NULL,
NULL,
NULL,
NULL,
/* 92 */
NULL,
NULL,
NULL,
NULL,
/* 96 */
NULL,
"VAR_TIMER_NEXT",
"VAR_TMR_1",
"VAR_TMR_2",
/* 100 */
"VAR_TMR_3",
"VAR_CAMERA_MIN_X",
"VAR_CAMERA_MAX_X",
"VAR_CAMERA_MIN_Y",
/* 104 */
"VAR_CAMERA_MAX_Y",
"VAR_CAMERA_THRESHOLD_X",
"VAR_CAMERA_THRESHOLD_Y",
"VAR_CAMERA_SPEED_X",
/* 108 */
"VAR_CAMERA_SPEED_Y",
"VAR_CAMERA_ACCEL_X",
"VAR_CAMERA_ACCEL_Y",
"VAR_EGO",
/* 112 */
"VAR_CURSORSTATE",
"VAR_USERPUT",
"VAR_DEFAULT_TALK_DELAY",
"VAR_CHARINC",
/* 116 */
"VAR_DEBUGMODE",
NULL,
NULL,
"VAR_CHARSET_MASK",
/* 120 */
NULL,
NULL,
NULL,
"VAR_VIDEONAME",
/* 124 */
NULL,
NULL,
NULL,
NULL,
/* 128 */
NULL,
NULL,
"VAR_STRING2DRAW",
"VAR_CUSTOMSCALETABLE",
};
const char *var_names8[] = {
/* 0 */
NULL,
"room_width?",
"room_height?",
"VAR_MOUSE_X",
/* 4 */
"VAR_MOUSE_Y",
"VAR_VIRT_MOUSE_X",
"VAR_VIRT_MOUSE_Y",
"VAR_CURSORSTATE",
/* 8 */
"VAR_USERPUT",
"VAR_CAMERA_POS_X",
"VAR_CAMERA_POS_Y",
"VAR_CAMERA_DEST_X",
/* 12 */
"VAR_CAMERA_DEST_Y",
"VAR_CAMERA_FOLLOWED_ACTOR",
"VAR_TALK_ACTOR",
"VAR_HAVE_MSG",
/* 16 */
"VAR_MOUSE_BUTTONS",
NULL,
"VAR_MOUSE_HOLD",
NULL,
/* 20 */
NULL,
NULL,
NULL,
NULL,
/* 24 */
"VAR_TIMEDATE_YEAR",
"VAR_TIMEDATE_MONTH",
"VAR_TIMEDATE_DAY",
"VAR_TIMEDATE_HOUR",
/* 28 */
"VAR_TIMEDATE_MINUTE",
"VAR_TIMEDATE_SECOND",
"VAR_OVERRIDE",
"VAR_ROOM",
/* 32 */
NULL,
NULL,
NULL,
NULL,
/* 36 */
NULL,
NULL,
NULL,
"voice_text_mode",
/* 40 */
"VAR_GAME_LOADED",
"VAR_LANGUAGE",
"VAR_CURRENTDISK",
NULL,
/* 44 */
NULL,
NULL,
NULL,
NULL,
/* 48 */
NULL,
NULL,
NULL,
"VAR_ENTRY_SCRIPT",
/* 52 */
"VAR_ENTRY_SCRIPT2",
"VAR_EXIT_SCRIPT",
"VAR_EXIT_SCRIPT2",
"VAR_VERB_SCRIPT",
/* 56 */
"VAR_SENTENCE_SCRIPT",
"VAR_HOOK_SCRIPT",
"VAR_CUTSCENE_START_SCRIPT",
"VAR_CUTSCENE_END_SCRIPT",
/* 60 */
NULL,
NULL,
"VAR_CUTSCENEEXIT_KEY",
"VAR_RESTART_KEY",
/* 64 */
"VAR_PAUSE_KEY",
"VAR_SAVELOADDIALOG_KEY",
NULL,
"VAR_TALKSTOP_KEY",
/* 68 */
NULL,
NULL,
NULL,
NULL,
/* 72 */
NULL,
NULL,
NULL,
NULL,
/* 76 */
NULL,
NULL,
NULL,
NULL,
/* 80 */
NULL,
NULL,
NULL,
NULL,
/* 84 */
NULL,
NULL,
NULL,
NULL,
/* 88 */
NULL,
NULL,
NULL,
NULL,
/* 92 */
NULL,
NULL,
NULL,
NULL,
/* 96 */
NULL,
NULL,
NULL,
NULL,
/* 100 */
NULL,
NULL,
NULL,
NULL,
/* 104 */
NULL,
NULL,
NULL,
NULL,
/* 108 */
NULL,
NULL,
NULL,
NULL,
/* 112 */
"VAR_TIMER_NEXT",
"VAR_TMR_1",
"VAR_TMR_2",
"VAR_TMR_3",
/* 116 */
NULL,
NULL,
NULL,
NULL,
/* 120 */
NULL,
NULL,
NULL,
NULL,
/* 124 */
NULL,
NULL,
"VAR_EGO",
NULL,
/* 128 */
NULL,
"text_delay?",
"VAR_DEBUGMODE",
NULL,
/* 132 */
"VAR_KEYPRESS",
NULL,
NULL,
NULL,
};
const char *DeScumm::getVarName(uint var)
{
if (scriptVersion == 8) {
if (var >= sizeof(var_names8) / sizeof(var_names8[0]))
return NULL;
return var_names8[var];
} else if (scriptVersion == 7) {
if (var >= sizeof(var_names7) / sizeof(var_names7[0]))
return NULL;
return var_names7[var];
} else {
if (var >= sizeof(var_names6) / sizeof(var_names6[0]))
return NULL;
return var_names6[var];
}
}
void DeScumm::push(StackEnt * se)
{
assert(se);
stack[num_stack++] = se;
}
void DeScumm::invalidop(const char *cmd, int op)
{
if (cmd)
printf("ERROR: Unknown opcode %s:0x%x (stack count %d)\n", cmd, op, num_stack);
else
printf("ERROR: Unknown opcode 0x%x (stack count %d)\n", op, num_stack);
exit(1);
}
byte *DeScumm::skipVerbHeader_V8(byte *p)
{
uint32 *ptr;
uint32 code;
int hdrlen;
ptr = (uint32 *)p;
while (TO_LE_32(*ptr++) != 0) {
ptr++;
}
hdrlen = (byte *)ptr - p;
ptr = (uint32 *)p;
while ((code = TO_LE_32(*ptr++)) != 0) {
printf(" %2d - %.4X\n", code, TO_LE_32(*ptr++) - hdrlen);
}
return (byte *)ptr;
}
int DeScumm::skipVerbHeader_V67(byte *p)
{
byte code;
int offset = 8;
int minOffset = 255;
p += offset;
printf("Events:\n");
while ((code = *p++) != 0) {
offset = TO_LE_16(*(uint16 *)p);
p += 2;
printf(" %2X - %.4X\n", code, offset);
if (minOffset > offset)
minOffset = offset;
}
return minOffset;
}
StackEnt *DeScumm::se_new(int type)
{
StackEnt *se = (StackEnt *) malloc(sizeof(StackEnt));
se->type = type;
return se;
}
void DeScumm::se_free(StackEnt * se)
{
free(se);
}
StackEnt *DeScumm::se_neg(StackEnt * se)
{
StackEnt *s = se_new(seNeg);
s->left = se;
return s;
}
StackEnt *DeScumm::se_int(int i)
{
StackEnt *se = se_new(seInt);
se->data = i;
return se;
}
StackEnt *DeScumm::se_var(int i)
{
StackEnt *se = se_new(seVar);
se->data = i;
return se;
}
StackEnt *DeScumm::se_array(int i, StackEnt * dim2, StackEnt * dim1)
{
StackEnt *se = se_new(seArray);
se->left = dim2;
se->right = dim1;
se->data = i;
return se;
}
StackEnt *DeScumm::se_oper(StackEnt * a, int op)
{
StackEnt *se = se_new(seUnary);
se->data = op;
se->left = a;
return se;
}
StackEnt *DeScumm::se_oper(StackEnt * a, int op, StackEnt * b)
{
StackEnt *se = se_new(seBinary);
se->data = op;
se->left = a;
se->right = b;
return se;
}
StackEnt *DeScumm::se_complex(const char *s)
{
StackEnt *se = se_new(seComplex);
se->str = strdup(s);
return se;
}
char *DeScumm::se_astext(StackEnt * se, char *where, bool wantparens)
{
int i;
int var;
const char *s;
switch (se->type) {
case seInt:
where += sprintf(where, "%ld", se->data);
break;
case seVar:
if (scriptVersion == 8) {
if (!(se->data & 0xF0000000)) {
var = se->data & 0xFFFFFFF;
if ((s = getVarName(var)) != NULL)
where = strecpy(where, s);
else
where += sprintf(where, "var%ld", se->data & 0xFFFFFFF);
} else if (se->data & 0x80000000) {
where += sprintf(where, "bitvar%ld", se->data & 0x7FFFFFFF);
} else if (se->data & 0x40000000) {
where += sprintf(where, "localvar%ld", se->data & 0xFFFFFFF);
} else {
where += sprintf(where, "?var?%ld", se->data);
}
} else {
if (!(se->data & 0xF000)) {
var = se->data & 0xFFF;
if ((s = getVarName(var)) != NULL)
where = strecpy(where, s);
else
where += sprintf(where, "var%ld", se->data & 0xFFF);
} else if (se->data & 0x8000) {
where += sprintf(where, "bitvar%ld", se->data & 0x7FFF);
} else if (se->data & 0x4000) {
where += sprintf(where, "localvar%ld", se->data & 0xFFF);
} else {
where += sprintf(where, "?var?%ld", se->data);
}
}
break;
case seArray:
if (se->left) {
where += sprintf(where, "array-%ld[", se->data);
where = se_astext(se->left, where);
where = strecpy(where, "][");
where = se_astext(se->right, where);
where = strecpy(where, "]");
} else {
where += sprintf(where, "array-%ld[", se->data);
where = se_astext(se->right, where);
where = strecpy(where, "]");
}
break;
case seUnary:
where += sprintf(where, "%s ", oper_list[se->data]);
where = se_astext(se->left, where);
break;
case seBinary:
if (wantparens)
*where++ = '(';
where = se_astext(se->left, where);
where += sprintf(where, " %s ", oper_list[se->data]);
where = se_astext(se->right, where);
if (wantparens)
*where++ = ')';
*where = 0;
break;
case seComplex:
where = strecpy(where, se->str);
break;
case seStackList:
*where++ = '[';
for (i = se->data; --i >= 0;) {
where = se_astext(se->list[i], where);
if (i)
*where++ = ',';
}
*where++ = ']';
*where = 0;
break;
case seDup:
where += sprintf(where, "dup[%ld]", se->data);
break;
case seNeg:
*where++ = '!';
where = se_astext(se->left, where);
break;
}
return where;
}
StackEnt *DeScumm::pop()
{
if (num_stack == 0) {
printf("ERROR: No items on stack to pop!\n");
if (!haltOnError)
return se_complex("**** INVALID DATA ****");
exit(1);
}
return stack[--num_stack];
}
void DeScumm::kill(StackEnt * se)
{
if (se->type != seDup) {
char *e = strecpy(output, "pop(");
e = se_astext(se, e);
strcpy(e, ")");
se_free(se);
} else {
push(se);
}
}
void DeScumm::doAssign(StackEnt * dst, StackEnt * src)
{
if (src->type == seDup && dst->type == seDup) {
dst->data = src->data;
return;
}
char *e = se_astext(dst, output);
e = strecpy(e, " = ");
se_astext(src, e);
}
void DeScumm::doAdd(StackEnt * se, int val)
{
char *e = se_astext(se, output);
sprintf(e, " += %d", val);
}
StackEnt *DeScumm::dup(StackEnt * se)
{
static int dupindex = 0;
if (se->type == seInt)
return se;
StackEnt *dse = se_new(seDup);
dse->data = ++dupindex;
doAssign(dse, se);
return dse;
}
void DeScumm::writeArray(int i, StackEnt * dim2, StackEnt * dim1, StackEnt * value)
{
StackEnt *array = se_array(i, dim2, dim1);
doAssign(array, value);
se_free(array);
}
void DeScumm::writeVar(int i, StackEnt * value)
{
StackEnt *se = se_var(i);
doAssign(se, value);
se_free(se);
}
void DeScumm::addArray(int i, StackEnt * dim1, int val)
{
StackEnt *array = se_array(i, NULL, dim1);
doAdd(array, val);
se_free(array);
}
void DeScumm::addVar(int i, int val)
{
StackEnt *se = se_var(i);
doAdd(se, val);
se_free(se);
}
StackEnt *DeScumm::se_get_string()
{
byte cmd;
char buf[1024];
char *e = buf;
bool in = false;
int i;
while ((cmd = get_byte()) != 0) {
if (cmd == 0xFF || cmd == 0xFE) {
if (in) {
*e++ = '"';
in = false;
}
i = get_byte();
switch (i) {
case 1:
e += sprintf(e, ":newline:");
break;
case 2:
e += sprintf(e, ":keeptext:");
break;
case 3:
e += sprintf(e, ":wait:");
break;
case 4: // addIntToStack
case 5: // addVerbToStack
case 6: // addNameToStack
case 7: // addStringToStack
{
StackEnt foo;
foo.type = seVar;
foo.data = get_word();
e += sprintf(e, ":");
e = se_astext(&foo, e);
e += sprintf(e, ":");
}
break;
case 9:
e += sprintf(e, ":startanim=%d:", get_word());
break;
case 10:
e += sprintf(e, ":sound:");
cur_pos += 14;
break;
case 14:
e += sprintf(e, ":setfont=%d:", get_word());
break;
case 12:
e += sprintf(e, ":setcolor=%d:", get_word());
break;
case 13:
e += sprintf(e, ":unk2=%d:", get_word());
break;
default:
e += sprintf(e, ":unk%d=%d:", i, get_word());
}
} else {
if (!in) {
*e++ = '"';
in = true;
}
*e++ = cmd;
}
}
if (in)
*e++ = '"';
*e = 0;
return se_complex(buf);
}
StackEnt *DeScumm::se_get_list()
{
StackEnt *se = se_new(seStackList);
StackEnt *senum = pop();
int num, i;
if (senum->type != seInt) {
printf("ERROR: stackList with variable number of arguments, cannot disassemble\n");
exit(1);
}
se->data = num = senum->data;
se->list = (StackEnt **) calloc(num, sizeof(StackEnt *));
for(i = 0; i < num; i++) {
se->list[i] = pop();
}
return se;
}
void DeScumm::ext(const char *fmt)
{
bool wantresult;
byte cmd, extcmd;
const char *extstr = NULL;
const char *prep = NULL;
StackEnt *args[10];
int numArgs = 0;
char *e = (char *)output;
/* return the result? */
wantresult = false;
if (*fmt == 'r') {
wantresult = true;
fmt++;
}
while ((cmd = *fmt++) != '|') {
if (cmd == 'x' && !extstr) {
/* Sub-op: next byte specifies which one */
extstr = fmt;
while (*fmt++)
;
e += sprintf(e, "%s.", extstr);
/* extended thing */
extcmd = get_byte();
/* locate our extended item */
while ((cmd = *fmt++) != extcmd) {
/* scan until we find , or \0 */
while ((cmd = *fmt++) != ',') {
if (cmd == 0) {
invalidop(extstr, extcmd);
}
}
}
/* found a command, continue at the beginning */
continue;
}
if (cmd == 'y' && !extstr) {
/* Sub-op: parameters are in a list, first element of the list specified the command */
StackEnt *se;
extstr = fmt;
while (*fmt++)
;
e += sprintf(e, "%s.", extstr);
args[numArgs++] = se_get_list();
/* extended thing */
se = args[numArgs - 1];
se->data--;
extcmd = (byte) se->list[se->data]->data;
/* locate our extended item */
while ((cmd = *fmt++) != extcmd) {
/* scan until we find , or \0 */
while ((cmd = *fmt++) != ',') {
if (cmd == 0) {
se->data++;
fmt = "Unknown";
goto output_command;
}
}
}
/* found a command, continue at the beginning */
continue;
}
if (cmd == 'p') {
args[numArgs++] = pop();
} else if (cmd == 'z') { // = popRoomAndObj()
args[numArgs++] = pop();
if (scriptVersion < 7)
args[numArgs++] = pop();
} else if (cmd == 's') {
args[numArgs++] = se_get_string();
} else if (cmd == 'w') {
args[numArgs++] = se_int(get_word());
} else if (cmd == 'l') {
args[numArgs++] = se_get_list();
} else if (cmd == 'j') {
args[numArgs++] = se_int(get_word());
} else {
printf("error in argument string '%s', character '%c' unknown\n", fmt, cmd);
}
}
output_command:
/* create a string from the arguments */
if (prep)
e = strecpy(e, prep);
while (*fmt != 0 && *fmt != ',')
*e++ = *fmt++;
*e++ = '(';
while (--numArgs >= 0) {
e = se_astext(args[numArgs], e);
if (numArgs)
*e++ = ',';
}
*e++ = ')';
*e = 0;
if (wantresult) {
push(se_complex((char *)output));
output[0] = 0;
return;
}
}
void DeScumm::jump()
{
int offset = get_signed_word();
int cur = get_curoffs();
int to = cur + offset;
if (offset == 1) {
// Sometimes, jumps with offset 1 occur. I used to suppress those.
// But it turns out that's not quite correct in some cases. With this
// code, it can sometimes happens that you get an empty 'else' branch;
// but in many other cases, an otherwis hidden instruction is revealed,
// or an instruction is placed into an else branch instead of being
// (incorrectly) placed inside the body of the 'if' itself.
sprintf(output, "/* jump %x; */", to);
} else if (!dontOutputElse && maybeAddElse(cur, to)) {
pendingElse = true;
pendingElseTo = to;
pendingElseOffs = cur - 1;
pendingElseOpcode = g_jump_opcode;
pendingElseIndent = num_block_stack;
} else {
if (num_block_stack && !dontOutputWhile) {
BlockStack *p = &block_stack[num_block_stack - 1];
if (p->isWhile && cur == p->to)
return; // A 'while' ends here.
}
sprintf(output, "jump %x", to);
}
}
void DeScumm::jumpif(StackEnt * se, bool negate)
{
int offset = get_signed_word();
int cur = get_curoffs();
int to = cur + offset;
char *e = output;
if (!dontOutputElseif && pendingElse) {
if (maybeAddElseIf(cur, pendingElseTo, to)) {
pendingElse = false;
haveElse = true;
e = strecpy(e, "} else if (");
if (negate)
se = se_neg(se);
e = se_astext(se, e, false);
sprintf(e, alwaysShowOffs ? ") /*%.4X*/ {" : ") {", to);
return;
}
}
if (!dontOutputIfs && maybeAddIf(cur, to)) {
if (!dontOutputWhile && block_stack[num_block_stack - 1].isWhile) {
e = strecpy(e, "while (");
} else
e = strecpy(e, "if (");
if (negate)
se = se_neg(se);
e = se_astext(se, e, false);
sprintf(e, alwaysShowOffs ? ") /*%.4X*/ {" : ") {", to);
return;
}
e = strecpy(e, negate ? "if (" : "unless (");
e = se_astext(se, e);
sprintf(e, ") jump %x", to);
}
#define PRINT_V8(name) \
do { \
ext("x" name "\0" \
"\xC8|baseop," \
"\xC9|end," \
"\xCApp|XY," \
"\xCBp|color," \
"\xCC|center," \
"\xCDp|charset," \
"\xCE|left," \
"\xCF|overhead," \
"\xD0|mumble," \
"\xD1s|msg," \
"\xD2|wrap" \
); \
} while(0)
void DeScumm::next_line_V8()
{
byte code = get_byte();
StackEnt *se_a, *se_b;
switch (code) {
case 0x1:
push(se_int(get_word()));
break;
case 0x2:
push(se_var(get_word()));
break;
case 0x3:
push(se_array(get_word(), NULL, pop()));
break;
case 0x4:
se_a = pop();
push(se_array(get_word(), pop(), se_a));
break;
case 0x5:
se_a = dup(pop());
push(se_a);
push(se_a);
break;
case 0x6:
kill(pop());
break;
case 0x7:
push(se_oper(pop(), isZero));
break;
case 0x8:
case 0x9:
case 0xA:
case 0xB:
case 0xC:
case 0xD:
case 0xE:
case 0xF:
case 0x10:
case 0x11:
case 0x12:
case 0x13:
case 0x14:
case 0x15:
case 0x16:
se_a = pop();
se_b = pop();
push(se_oper(se_b, (code - 0x8) + isEqual, se_a));
break;
case 0x64:
jumpif(pop(), true);
break;
case 0x65:
jumpif(pop(), false);
break;
case 0x66:
jump();
break;
case 0x67:
ext("|breakHere");
break;
case 0x68:
ext("p|breakHereVar");
break;
case 0x69:
ext("x" "wait\0"
"\x1Epj|waitForActor,"
"\x1F|waitForMessage,"
"\x20|waitForCamera,"
"\x21|waitForSentence,"
"\x22pj|waitUntilActorDrawn,"
"\x23pj|waitUntilActorTurned,"
);
break;
case 0x6A:
ext("p|delay");
break;
case 0x6B:
ext("p|delaySeconds");
break;
case 0x6C:
ext("p|delayMinutes");
break;
case 0x6D:
writeVar(get_word(), pop());
break;
case 0x6E:
addVar(get_word(), +1);
break;
case 0x6F:
addVar(get_word(), -1);
break;
case 0x70:
// FIXME - is this correct?!? Also, make the display nicer...
ext("x" "dim\0"
"\x0Apw|dim-scummvar,"
"\x0Bpw|dim-string,"
"\xCAw|undim"
);
break;
case 0x71:
se_a = pop();
writeArray(get_word(), NULL, pop(), se_a);
break;
case 0x74:
// FIXME - is this correct?!? Also, make the display nicer...
ext("x" "dim2\0"
"\x0Appw|dim2-scummvar,"
"\x0Bppw|dim2-string,"
"\xCAw|undim2"
);
break;
case 0x75:
se_a = pop();
se_b = pop();
writeArray(get_word(), pop(), se_b, se_a);
break;
case 0x76:
switch (get_byte()) {
case 0x14:{
int array = get_word();
writeArray(array, NULL, pop(), se_get_string());
}
break;
case 0x15:
se_a = pop();
se_b = se_get_list();
writeArray(get_word(), NULL, se_a, se_b);
break;
case 0x16:
se_a = pop();
se_b = se_get_list();
writeArray(get_word(), pop(), se_a, se_b);
break;
}
break;
case 0x79:
ext("lpp|startScriptEx");
break;
case 0x7A:
ext("lp|startScript");
break;
case 0x7B:
ext("|stopObjectCode");
break;
case 0x7C:
ext("p|stopScript");
break;
case 0x7D:
ext("lpp|jumpToScript");
break;
case 0x7E:
ext("p|return");
break;
case 0x7F:
ext("lppp|startObjectEx");
break;
case 0x81:
ext("l|beginCutscene");
break;
case 0x82:
ext("|endCutscene");
break;
case 0x83:
ext("p|freezeUnfreeze");
break;
case 0x84:
ext("|beginOverride");
break;
case 0x85:
ext("|endOverride");
break;
case 0x86:
ext("|stopSentence");
break;
case 0x89:
ext("lp|setClassOf?");
break;
case 0x8A:
ext("pp|setState");
break;
case 0x8B:
ext("pp|setOwner");
break;
case 0x8C:
ext("pp|panCameraTo");
break;
case 0x8D:
ext("p|actorFollowCamera");
break;
case 0x8E:
ext("pp|setCameraAt");
break;
case 0x8F:
ext("ps|printActor");
break;
case 0x90:
PRINT_V8("printEgo");
break;
case 0x91:
ext("ps|talkActor");
break;
case 0x92:
ext("s|talkEgo");
break;
case 0x93:
PRINT_V8("printLine");
break;
case 0x94:
PRINT_V8("printCursor");
break;
case 0x95:
PRINT_V8("printDebug");
break;
case 0x96:
PRINT_V8("printSystem");
break;
case 0x97:
PRINT_V8("blastText");
break;
case 0x9C:
ext("x" "cursorCommand\0"
"\xDC|cursorOn,"
"\xDD|cursorOff,"
"\xDE|userPutOn,"
"\xDF|userPutOff,"
"\xE0|softCursorOn,"
"\xE1|softCursorOff,"
"\xE2|softUserputOn,"
"\xE3|softUserputOff,"
"\xE4pp|setCursorImg,"
"\xE5pp|setCursorHotspot,"
"\xE6p|makeCursorColorTransparent,"
"\xE7p|initCharset,"
"\xE8l|charsetColors,"
"\xE9pp|setCursorPosition");
break;
case 0x9D:
ext("p|loadRoom");
break;
case 0x9E:
ext("ppz|loadRoomWithEgo");
break;
case 0x9F:
ext("ppp|walkActorToObj");
break;
case 0xA0:
ext("ppp|walkActorTo");
break;
case 0xA1:
ext("pppp|putActorInRoom");
break;
case 0xA2:
ext("zp|putActorAtObject");
break;
case 0xA3:
ext("pp|faceActor");
break;
case 0xA4:
ext("pp|animateActor");
break;
case 0xA5:
ext("ppp|doSentence");
break;
case 0xA6:
ext("z|pickupObject");
break;
case 0xA7:
ext("pl|setBoxFlags");
break;
case 0xA8:
ext("|createBoxMatrix");
break;
case 0xAA:
ext("x" "resourceRoutines\0"
"\x3Cp|loadCharset,"
"\x3Dp|loadCostume,"
"\x3Ep|loadObject,"
"\x3Fp|loadRoom,"
"\x40p|loadScript,"
"\x41p|loadSound,"
"\x42p|lockCostume,"
"\x43p|lockRoom,"
"\x44p|lockScript,"
"\x45p|lockSound,"
"\x46p|unlockCostume,"
"\x47p|unlockRoom,"
"\x48p|unlockScript,"
"\x49p|unlockSound,"
"\x4Ap|nukeCostume,"
"\x4Bp|nukeRoom,"
"\x4Cp|nukeScript,"
"\x4Dp|nukeSound"
);
break;
case 0xAB:
// FIXME - not sure how much stuff each subopcode pops
ext("x" "roomOps\0"
"\x52|setRoomPalette,"
"\x55|setRoomIntensity,"
"\x57p|fade,"
"\x58ppppp|setRoomRBGIntensity,"
"\x59|transformRoom,"
"\x5A|colorCycleDelay,"
"\x5B|copyPalette,"
"\x5C|newPalette,"
"\x5D|saveGame,"
"\x5E|LoadGame,"
"\x5F|setRoomSaturation"
);
break;
case 0xAC:
// Note: these are guesses and may partially be wrong
ext("x" "actorOps\0"
"\x64p|setActorCostume,"
"\x65pp|setActorWalkSpeed,"
"\x67|setActorDefAnim,"
"\x68p|setActorInitFrame,"
"\x69pp|setActorTalkFrame,"
"\x6Ap|setActorWalkFrame,"
"\x6Bp|setActorStandFrame,"
"\x6C|setActorAnimSpeed,"
"\x6D|setActorDefault," // = initActorLittle ?
"\x6Ep|setActorElevation,"
"\x6Fpp|setActorPalette,"
"\x70p|setActorTalkColor,"
"\x71s|setActorName,"
"\x72p|setActorWidth,"
"\x73p|setActorScale,"
"\x74|setActorNeverZClip,"
"\x75p|setActorAlwayZClip?,"
"\x76|setActorIgnoreBoxes,"
"\x77|setActorFollowBoxes,"
"\x78p|actorSpecialDraw,"
"\x79pp|setActorTalkPos,"
"\x7Ap|setCurActor,"
"\x7Bpp|setActorAnimVar,"
"\x7C|setActorIgnoreTurnsOn,"
"\x7D|setActorIgnoreTurnsOff,"
"\x7E|newActor,"
"\x7Fp|setActorLayer,"
"\x80|setActorStanding,"
"\x81p|setActorDirection,"
"\x82p|actorTurnToDirection,"
"\x83p|setActorWalkScript,"
"\x84p|setTalkScript,"
"\x85|freezeActor,"
"\x86|unfreezeActor,"
"\x87p|setActorVolume,"
"\x88p|setActorFrequency,"
"\x89p|setActorPan"
);
break;
case 0xAD:
ext("x" "cameraOps\0"
"\x32|freezeCamera,"
"\x33|unfreezeCamera"
);
break;
case 0xAE:
ext("x" "verbOps\0"
"\x96p|verbInit,"
"\x97|verbNew,"
"\x98|verbDelete,"
"\x99s|verbLoadString,"
"\x9App|verbSetXY,"
"\x9B|verbOn,"
"\x9C|verbOff,"
"\x9Dp|verbSetColor,"
"\x9Ep|verbSetHiColor,"
"\xA0p|verbSetDimColor,"
"\xA1|verbSetDim,"
"\xA2p|verbSetKey,"
"\xA3p|verbLoadImg,"
"\xA4p|verbSetToString,"
"\xA5|verbSetCenter,"
"\xA6p|verbSetCharset,"
"\xA7p|verbSetLineSpacing"
);
break;
case 0xAF:
ext("p|startSound");
break;
case 0xB1:
ext("p|stopSound");
break;
case 0xB2:
ext("l|soundKludge");
break;
case 0xB3:
ext("x" "system\0"
"\x28|restart,"
"\x29|quit");
break;
case 0xB4:
ext("x" "saveRestoreVerbs\0"
"\xB4ppp|saveVerbs,"
"\xB5ppp|restoreVerbs,"
"\xB6ppp|deleteVerbs");
break;
case 0xB5:
ext("ps|setObjectName");
break;
case 0xB6:
ext("|getDateTime");
break;
case 0xB7:
ext("ppppp|drawBox");
break;
case 0xB9:
ext("s|startVideo");
break;
case 0xBA:
ext("y" "kernelSetFunctions\0"
"\xB|lockObject,"
"\xC|unlockObject,"
"\xD|remapCostume,"
"\xE|remapCostumeInsert,"
"\xF|setVideoFrameRate,"
"\x14|setBoxScale,"
"\x15|setScaleSlot,"
"\x16|setBannerColors,"
"\x17|setActorChoreLimbFrame,"
"\x18|clearTextQueue,"
"\x19|saveGameWrite,"
"\x1A|saveGameRead,"
"\x1B|saveGameReadName,"
"\x1C|saveGameStampScreenshot,"
"\x1D|setKeyScript,"
"\x1E|killAllScriptsButMe,"
"\x1F|stopAllVideo,"
"\x20|writeRegistryValue,"
"\x21|paletteSetIntensity,"
"\x22|queryQuit,"
"\x6C|buildPaletteShadow,"
"\x6D|setPaletteShadow,"
"\x76|blastShadowObject,"
"\x77|superBlastObject"
);
break;
case 0xC8:
ext("rlp|startScriptQuick");
break;
case 0xC9:
ext("lppp|startObjectQuick");
break;
case 0xCA:
ext("rlp|pickOneOf");
break;
case 0xCB:
ext("rplp|pickOneOfDefault");
break;
case 0xCD:
ext("rlp|isAnyOf");
break;
case 0xCE:
ext("rp|getRandomNumber");
break;
case 0xCF:
ext("rpp|getRandomNumberRange");
break;
case 0xD0:
ext("rlp|ifClassOfIs");
break;
case 0xD1:
ext("rp|getState");
break;
case 0xD2:
ext("rp|getOwner");
break;
case 0xD3:
ext("rp|isScriptRunning");
break;
case 0xD5:
ext("rp|isSoundRunning");
break;
case 0xD6:
ext("rp|abs");
break;
case 0xD8:
ext("ry" "kernelGetFunctions\0"
"\x73|getWalkBoxAt,"
"\x74|isPointInBox,"
"\xCE|getRGBSlot,"
"\xD3|getKeyState,"
"\xD7|getBox,"
"\xD8|findBlastObject,"
"\xD9|actorHit,"
"\xDA|lipSyncWidth,"
"\xDB|lipSyncHeight,"
"\xDC|actorTalkAnimation,"
"\xDD|getMasterSFXVol,"
"\xDE|getMasterVoiceVol,"
"\xDF|getMasterMusicVol,"
"\xE0|readRegistryValue"
);
break;
case 0xD9:
ext("rpp|isActorInBox");
break;
case 0xDA:
ext("rpp|getVerbEntrypoint");
break;
case 0xDB:
ext("rpp|getActorFromXY");
break;
case 0xDC:
ext("rpp|findObject");
break;
case 0xDD:
ext("rpp|getVerbFromXY");
break;
case 0xDF:
ext("rpp|findInventory");
break;
case 0xE0:
ext("rp|getInventoryCount");
break;
case 0xE1:
ext("rpp|getAnimateVariable");
break;
case 0xE2:
ext("rp|getActorRoom");
break;
case 0xE3:
ext("rp|getActorWalkBox");
break;
case 0xE4:
ext("rp|getActorMoving");
break;
case 0xE5:
ext("rp|getActorCostume");
break;
case 0xE6:
ext("rp|getActorScaleX");
break;
case 0xE7:
ext("rp|getActorLayer");
break;
case 0xE8:
ext("rp|getActorElevation");
break;
case 0xE9:
ext("rp|getActorWidth");
break;
case 0xEA:
ext("rp|getObjectDir");
break;
case 0xEB:
ext("rp|getObjectX");
break;
case 0xEC:
ext("rp|getObjectY");
break;
case 0xED:
ext("rp|getActorChore");
break;
case 0xEE:
ext("rpp|getDistObjObj");
break;
case 0xEF:
ext("rpppp|getDistPtPt");
break;
case 0xF0:
ext("rp|getObjectImageX");
break;
case 0xF1:
ext("rp|getObjectImageY");
break;
case 0xF2:
ext("rp|getObjectImageWidth");
break;
case 0xF3:
ext("rp|getObjectImageHeight");
break;
case 0xF4:
ext("rp|getVerbX");
break;
case 0xF5:
ext("rp|getVerbY");
break;
case 0xF6:
ext("rps|stringWidth");
break;
case 0xF7:
ext("rp|getActorZPlane");
break;
default:
invalidop(NULL, code);
break;
}
}
#define PRINT_V67(name) \
do { \
ext("x" name "\0" \
"\x41pp|XY," \
"\x42p|color," \
"\x43p|right," \
"\x45|center," \
"\x47|left," \
"\x48|overhead," \
"\x4A|mumble," \
"\x4Bs|msg," \
"\xFE|begin," \
"\xFF|end" \
); \
} while(0)
void DeScumm::next_line_V67()
{
byte code = get_byte();
StackEnt *se_a, *se_b;
switch (code) {
case 0x0:
push(se_int(get_byte()));
break;
case 0x1:
push(se_int(get_word()));
break;
case 0x2:
push(se_var(get_byte()));
break;
case 0x3:
push(se_var(get_word()));
break;
case 0x6:
push(se_array(get_byte(), NULL, pop()));
break;
case 0x7:
push(se_array(get_word(), NULL, pop()));
break;
case 0xA:
se_a = pop();
push(se_array(get_byte(), pop(), se_a));
break;
case 0xB:
se_a = pop();
push(se_array(get_word(), pop(), se_a));
break;
case 0xC:
se_a = dup(pop());
push(se_a);
push(se_a);
break;
case 0xD:
push(se_oper(pop(), isZero));
break;
case 0xE:
case 0xF:
case 0x10:
case 0x11:
case 0x12:
case 0x13:
case 0x14:
case 0x15:
case 0x16:
case 0x17:
case 0x18:
case 0x19:
se_a = pop();
se_b = pop();
push(se_oper(se_b, (code - 0xE) + isEqual, se_a));
break;
case 0x1A:
case 0xA7:
kill(pop());
break;
case 0x42:
writeVar(get_byte(), pop());
break;
case 0x43:
writeVar(get_word(), pop());
break;
case 0x46:
writeArray(get_byte(), NULL, pop(), pop());
break;
case 0x47:
writeArray(get_word(), NULL, pop(), pop());
break;
case 0x4A:
writeArray(get_byte(), pop(), pop(), pop());
break;
case 0x4B:
writeArray(get_word(), pop(), pop(), pop());
break;
case 0x4E:
addVar(get_byte(), 1);
break;
case 0x4F:
addVar(get_word(), 1);
break;
case 0x52:
addArray(get_byte(), pop(), 1);
break;
case 0x53:
addArray(get_word(), pop(), 1);
break;
case 0x56:
addVar(get_byte(), -1);
break;
case 0x57:
addVar(get_word(), -1);
break;
case 0x5A:
addArray(get_byte(), pop(), -1);
break;
case 0x5B:
addArray(get_word(), pop(), -1);
break;
case 0x5C:
jumpif(pop(), true);
break;
case 0x5D:
jumpif(pop(), false);
break;
case 0x5E:
ext("lpp|startScriptEx");
break;
case 0x5F:
ext("lp|startScript");
break;
case 0x60:
ext("lppp|startObject");
break;
case 0x61:
ext("pp|setObjectState");
break;
case 0x62:
ext("ppp|setObjectXY");
break;
/* *** */
case 0x65:
ext("|stopObjectCodeA");
break;
case 0x66:
ext("|stopObjectCodeB");
break;
case 0x67:
ext("|endCutscene");
break;
case 0x68:
ext("l|beginCutscene");
break;
case 0x69:
ext("|stopMusic");
break;
case 0x6A:
ext("p|freezeUnfreeze");
break;
case 0x6B:
ext("x" "cursorCommand\0"
"\x90|cursorOn,"
"\x91|cursorOff,"
"\x92|userPutOn,"
"\x93|userPutOff,"
"\x94|softCursorOn,"
"\x95|softCursorOff,"
"\x96|softUserputOn,"
"\x97|softUserputOff,"
"\x99z|setCursorImg,"
"\x9App|setCursorHotspot,"
"\x9Cp|initCharset,"
"\x9Dl|charsetColors,"
"\xD6p|makeCursorColorTransparent");
break;
case 0x6C:
ext("|break");
break;
case 0x6D:
ext("rlp|ifClassOfIs");
break;
case 0x6E:
ext("lp|setClass");
break;
case 0x6F:
ext("rp|getState");
break;
case 0x70:
ext("pp|setState");
break;
case 0x71:
ext("pp|setOwner");
break;
case 0x72:
ext("rp|getOwner");
break;
case 0x73:
jump();
break;
case 0x74:
if (HumongousFlag) {
ext("pp|startSound");
break;
}
ext("p|startSound");
break;
case 0x75:
ext("p|stopSound");
break;
case 0x76:
ext("p|startMusic");
break;
case 0x77:
ext("p|stopObjectScript");
break;
case 0x78:
if (scriptVersion < 7)
ext("p|panCameraTo");
else
ext("pp|panCameraTo");
break;
case 0x79:
ext("p|actorFollowCamera");
break;
case 0x7A:
if (scriptVersion < 7)
ext("p|setCameraAt");
else
ext("pp|setCameraAt");
break;
case 0x7B:
ext("p|loadRoom");
break;
case 0x7C:
ext("p|stopScript");
break;
case 0x7D:
ext("ppp|walkActorToObj");
break;
case 0x7E:
ext("ppp|walkActorTo");
break;
case 0x7F:
ext("pppp|putActorInRoom");
break;
case 0x80:
ext("zp|putActorAtObject");
break;
case 0x81:
ext("pp|faceActor");
break;
case 0x82:
ext("pp|animateActor");
break;
case 0x83:
ext("pppp|doSentence");
break;
case 0x84:
ext("z|pickupObject");
break;
case 0x85:
ext("ppz|loadRoomWithEgo");
break;
case 0x87:
ext("rp|getRandomNumber");
break;
case 0x88:
ext("rpp|getRandomNumberRange");
break;
case 0x8A:
ext("rp|getActorMoving");
break;
case 0x8B:
ext("rp|isScriptRunning");
break;
case 0x8C:
ext("rp|getActorRoom");
break;
case 0x8D:
ext("rp|getObjectX");
break;
case 0x8E:
ext("rp|getObjectY");
break;
case 0x8F:
ext("rp|getObjectDir");
break;
case 0x90:
ext("rp|getActorWalkBox");
break;
case 0x91:
ext("rp|getActorCostume");
break;
case 0x92:
ext("rpp|findInventory");
break;
case 0x93:
ext("rp|getInventoryCount");
break;
case 0x94:
ext("rpp|getVerbFromXY");
break;
case 0x95:
ext("|beginOverride");
break;
case 0x96:
ext("|endOverride");
break;
case 0x97:
ext("ps|setObjectName");
break;
case 0x98:
ext("rp|isSoundRunning");
break;
case 0x99:
ext("pl|setBoxFlags");
break;
case 0x9A:
ext("|createBoxMatrix");
break;
case 0x9B:
ext("x" "resourceRoutines\0"
"\x64p|loadScript,"
"\x65p|loadSound,"
"\x66p|loadCostume,"
"\x67p|loadRoom,"
"\x68p|nukeScript,"
"\x69p|nukeSound,"
"\x6Ap|nukeCostume,"
"\x6Bp|nukeRoom,"
"\x6Cp|lockScript,"
"\x6Dp|lockSound,"
"\x6Ep|lockCostume,"
"\x6Fp|lockRoom,"
"\x70p|unlockScript,"
"\x71p|unlockSound,"
"\x72p|unlockCostume,"
"\x73p|unlockRoom,"
"\x75p|loadCharset,"
"\x76p|nukeCharset,"
"\x77z|loadFlObject");
break;
case 0x9C:
ext("x" "roomOps\0"
"\xACpp|roomScroll,"
"\xAEpp|setScreen,"
"\xAFpppp|setPalColor,"
"\xB0|shakeOn,"
"\xB1|shakeOff,"
"\xB3ppp|darkenPalette,"
"\xB4pp|saveLoadThing,"
"\xB5p|screenEffect,"
"\xB6ppppp|darkenPalette,"
"\xB7ppppp|setupShadowPalette,"
"\xBApppp|palManipulate,"
"\xBBpp|colorCycleDelay,"
"\xD5p|setPalette");
break;
case 0x9D:
ext("x" "actorSet\0"
"\xC5p|setCurActor,"
"\x4Cp|setActorCostume,"
"\x4Dpp|setActorWalkSpeed,"
"\x4El|setActorSound,"
"\x4Fp|setActorWalkFrame,"
"\x50pp|setActorTalkFrame,"
"\x51p|setActorStandFrame,"
"\x52ppp|actorSet:82:??,"
"\x53|initActor,"
"\x54p|setActorElevation,"
"\x55|setActorDefAnim,"
"\x56pp|setActorPalette,"
"\x57p|setActorTalkColor,"
"\x58s|setActorName,"
"\x59p|setActorInitFrame,"
"\x5Bp|setActorWidth,"
"\x5Cp|setActorScale,"
"\x5D|setActorNeverZClip,"
"\x5Ep|setActorAlwayZClip?,"
"\xE1p|setActorAlwayZClip?,"
"\x5F|setActorIgnoreBoxes,"
"\x60|setActorFollowBoxes,"
"\x61|setActorAnimSpeed,"
"\x62|setActorShadowMode,"
"\x63pp|setActorTalkPos,"
"\xC6p|setActorAnimVar,"
"\xD7|setActorIgnoreTurnsOn,"
"\xD8|setActorIgnoreTurnsOff,"
"\xD9|initActorLittle,"
"\xE3p|setActorLayer,"
"\xE4p|setActorWalkScript,"
"\xE5|setActorStanding,"
"\xE6p|setActorDirection,"
"\xE7p|actorTurnToDirection,"
"\xE9|freezeActor,"
"\xEA|unfreezeActor,"
"\xEBp|setTalkScript");
break;
case 0x9E:
ext("x" "verbOps\0"
"\xC4p|setCurVerb,"
"\x7Cp|verbLoadImg,"
"\x7Ds|verbLoadString,"
"\x7Ep|verbSetColor,"
"\x7Fp|verbSetHiColor,"
"\x80pp|verbSetXY,"
"\x81|verbSetCurmode1," // = verbOn ?
"\x82|verbSetCurmode0," // = verbOff ?
"\x83|verbKill,"
"\x84|verbInit,"
"\x85p|verbSetDimColor,"
"\x86|verbSetCurmode2," // = verbDim ?
"\x87p|verbSetKey,"
"\x88|verbSetCenter,"
"\x89p|verbSetToString,"
"\x8Bpp|verbSetToObject,"
"\x8Cp|verbSetBkColor,"
"\xFF|verbRedraw");
break;
case 0x9F:
ext("rpp|getActorFromXY");
break;
case 0xA0:
ext("rpp|findObject");
break;
case 0xA1:
ext("lp|pseudoRoom");
break;
case 0xA2:
ext("rp|getActorElevation");
break;
case 0xA3:
ext("rpp|getVerbEntrypoint");
break;
case 0xA4:
ext("x" "arrayOps\0" "\xCDwps|arrayOps205," "\xD0wpl|arrayOps208," "\xD4wplp|arrayOps212");
break;
case 0xA5:
ext("x" "saveRestoreVerbs\0"
"\x8Dppp|saveVerbs,"
"\x8Eppp|restoreVerbs,"
"\x8Fppp|deleteVerbs");
break;
case 0xA6:
ext("ppppp|drawBox");
break;
case 0xA8:
ext("rp|getActorWidth");
break;
case 0xA9:
ext("x" "wait\0"
"\xA8pj|waitForActor,"
"\xA9|waitForMessage,"
"\xAA|waitForCamera,"
"\xAB|waitForSentence,"
"\xE2pj|waitUntilActorDrawn,"
"\xE8pj|waitUntilActorTurned,"
);
break;
case 0xAA:
ext("rp|getActorScaleX");
break;
case 0xAB:
ext("rp|getActorAnimCounter1");
break;
case 0xAC:
ext("l|soundKludge");
break;
case 0xAD:
ext("rlp|isAnyOf");
break;
case 0xAE:
ext("x" "quitPauseRestart\0" "\x9E|pauseGame," "\xA0|shutDown");
break;
case 0xAF:
ext("rp|isActorInBox");
break;
case 0xB0:
ext("p|delay");
break;
case 0xB1:
ext("p|delaySeconds");
break;
case 0xB2:
ext("p|delayMinutes");
break;
case 0xB3:
ext("|stopSentence");
break;
case 0xB4:
PRINT_V67("printLine");
break;
case 0xB5:
PRINT_V67("printCursor");
break;
case 0xB6:
PRINT_V67("printDebug");
break;
case 0xB7:
PRINT_V67("printSystem");
break;
case 0xB8:
// This is *almost* identical to the other print opcodes, only the 'begine' subop differs
ext("x" "printActor\0"
"\x41pp|XY,"
"\x42p|color,"
"\x43p|right,"
"\x45|center,"
"\x47|left," "\x48|overhead," "\x4A|new3," "\x4Bs|msg," "\xFEp|begin," "\xFF|end");
break;
case 0xB9:
PRINT_V67("printEgo");
break;
case 0xBA:
ext("ps|talkActor");
break;
case 0xBB:
ext("s|talkEgo");
break;
case 0xBC:
ext("x" "dim\0"
"\xC7pw|dimType5,"
"\xC8pw|dimType1,"
"\xC9pw|dimType2,"
"\xCApw|dimType3,"
"\xCBpw|dimType4,"
"\xCCw|nukeArray");
break;
case 0xBE:
ext("lpp|startObjectQuick");
break;
case 0xBF:
ext("lp|startScriptQuick");
break;
case 0xC0:
ext("x" "dim2\0"
"\xC7ppw|dim2Type5,"
"\xC8ppw|dim2Type1,"
"\xC9ppw|dim2Type2,"
"\xCAppw|dim2Type3,"
"\xCBppw|dim2Type4");
break;
case 0xC4:
ext("rp|abs");
break;
case 0xC5:
ext("rpp|getDistObjObj");
break;
case 0xC6:
ext("rppp|getDistObjPt");
break;
case 0xC7:
ext("rpppp|getDistPtPt");
break;
case 0xC8:
// TODO - add more subopcodes
ext("ry" "kernelGetFunctions\0"
"\x73|getWalkBoxAt,"
"\x74|isPointInBox,"
"\xCE|getRGBSlot"
);
break;
case 0xC9:
// TODO - add more subopcodes
ext("y" "kernelSetFunctions\0"
"\x4|grabCursor,"
"\x5|fadeOut,"
"\x6|startVideo,"
"\xC|setCursorImg,"
"\xD|remapCostume,"
"\xE|remapCostumeInsert,"
"\xF|setVideoFrameRate,"
"\x6C|buildPaletteShadow,"
"\x6D|setPaletteShadow,"
"\x76|blastShadowObject,"
"\x77|superBlastObject"
);
break;
case 0xCA:
ext("p|breakXTimes");
break;
case 0xCB:
ext("rlp|pickOneOf");
break;
case 0xCC:
ext("rplp|pickOneOfDefault");
break;
case 0xCD:
ext("pppp|stampObject");
break;
case 0xD0:
ext("|getDateTime");
break;
case 0xD1:
ext("|stopTalking");
break;
case 0xD2:
ext("rpp|getAnimateVariable");
break;
case 0xD4:
ext("wpp|shuffle");
break;
case 0xD5:
ext("lpp|jumpToScript");
break;
case 0xD6:
se_a = pop();
se_b = pop();
push(se_oper(se_b, operBand, se_a));
break;
case 0xD7:
se_a = pop();
se_b = pop();
push(se_oper(se_b, operBor, se_a));
break;
case 0xD8:
ext("rp|isRoomScriptRunning");
break;
case 0xD9:
ext("p|closeFile");
break;
case 0xDA:
ext("rsp|openFile");
break;
case 0xDB:
ext("rpp|readFile");
break;
case 0xDD:
ext("rp|findAllObjects");
break;
case 0xE0:
ext("x" "p|unknownEO\0"
"\xDEp|unknownE0-DE,"
"\xDC|unknownE0-DC");
break;
case 0xE1:
ext("rp|unknownE1");
break;
case 0xE2:
ext("p|localizeArray");
break;
case 0xDE:
ext("s|deleteFile");
break;
case 0xEC:
ext("rp|getActorLayer");
break;
case 0xED:
ext("rp|getObjectNewDir");
break;
case 0xF3:
ext("rsp|readINI");
break;
case 0xFA:
get_byte();
ext("s|unknownFA");
break;
default:
invalidop(NULL, code);
break;
}
}