mirror of
https://github.com/libretro/scummvm.git
synced 2025-01-22 10:17:22 +00:00
8ad28e3a7e
message functions with our own. We still need to go through them and assign sensible debug levels to them. svn-id: r10422
713 lines
20 KiB
C++
713 lines
20 KiB
C++
/* Copyright (C) 1994-2003 Revolution Software Ltd
|
|
*
|
|
* 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$
|
|
*/
|
|
|
|
#include "stdafx.h"
|
|
|
|
#include "console.h"
|
|
#include "driver/driver96.h"
|
|
#include "interpreter.h"
|
|
|
|
// This file serves two purposes. It is compiled as part of the test functions
|
|
// of Linc, and also as part of the game
|
|
|
|
// I assume Linc was the name of some sort of development tool. Anyway, I've
|
|
// removed the pieces of code that were labelled as INSIDE_LINC, because we
|
|
// don't have it, and probably wouldn't have much use for it if we did.
|
|
|
|
// The machine code table
|
|
|
|
int32 FN_test_function(int32 *params);
|
|
int32 FN_test_flags(int32 *params);
|
|
int32 FN_register_start_point(int32 *params);
|
|
int32 FN_init_background(int32 *params);
|
|
int32 FN_set_session(int32 *params);
|
|
int32 FN_back_sprite(int32 *params);
|
|
int32 FN_sort_sprite(int32 *params);
|
|
int32 FN_fore_sprite(int32 *params);
|
|
int32 FN_register_mouse(int32 *params);
|
|
int32 FN_anim(int32 *);
|
|
int32 FN_random(int32 *);
|
|
int32 FN_preload(int32 *);
|
|
int32 FN_add_subject(int32 *);
|
|
int32 FN_interact(int32 *);
|
|
int32 FN_choose(int32 *);
|
|
int32 FN_walk(int32 *);
|
|
int32 FN_walk_to_anim(int32 *); // walk to start position of anim
|
|
int32 FN_turn(int32 *); // turn to (dir)
|
|
int32 FN_stand_at(int32 *); // stand at (x,y,dir)
|
|
int32 FN_stand(int32 *); // stand facing (dir)
|
|
int32 FN_stand_after_anim(int32 *); // stand at end position of anim
|
|
int32 FN_pause(int32 *);
|
|
int32 FN_mega_table_anim(int32 *);
|
|
int32 FN_add_menu_object(int32 *);
|
|
int32 FN_start_conversation(int32 *);
|
|
int32 FN_end_conversation(int32 *);
|
|
int32 FN_set_frame(int32 *);
|
|
int32 FN_random_pause(int32 *);
|
|
int32 FN_register_frame(int32 *);
|
|
int32 FN_no_sprite(int32 *);
|
|
int32 FN_send_sync(int32 *);
|
|
int32 FN_update_player_stats(int32 *);
|
|
int32 FN_pass_graph(int32 *);
|
|
int32 FN_init_floor_mouse(int32 *);
|
|
int32 FN_pass_mega(int32 *);
|
|
int32 FN_face_xy(int32 *);
|
|
int32 FN_end_session(int32 *);
|
|
int32 FN_no_human(int32 *);
|
|
int32 FN_add_human(int32 *);
|
|
int32 FN_we_wait(int32 *);
|
|
int32 FN_they_do_we_wait(int32 *);
|
|
int32 FN_they_do(int32 *);
|
|
int32 FN_walk_to_talk_to_mega(int32 *);
|
|
int32 FN_fade_down(int32 *);
|
|
int32 FN_i_speak(int32 *);
|
|
int32 FN_total_restart(int32 *);
|
|
int32 FN_set_walkgrid(int32 *);
|
|
int32 FN_speech_process(int32 *);
|
|
int32 FN_set_scaling(int32 *);
|
|
int32 FN_start_event(int32 *);
|
|
int32 FN_check_event_waiting(int32 *);
|
|
int32 FN_request_speech(int32 *);
|
|
int32 FN_gosub(int32 *);
|
|
int32 FN_timed_wait(int32 *);
|
|
int32 FN_play_fx(int32 *);
|
|
int32 FN_stop_fx(int32 *);
|
|
int32 FN_play_music(int32 *);
|
|
int32 FN_stop_music(int32 *);
|
|
int32 FN_set_value(int32 *);
|
|
int32 FN_new_script(int32 *);
|
|
int32 FN_get_sync(int32 *);
|
|
int32 FN_wait_sync(int32 *);
|
|
int32 FN_register_walkgrid(int32 *);
|
|
int32 FN_reverse_mega_table_anim(int32 *);
|
|
int32 FN_reverse_anim(int32 *);
|
|
int32 FN_add_to_kill_list(int32 *);
|
|
int32 FN_set_standby_coords(int32 *);
|
|
int32 FN_back_par0_sprite(int32 *params);
|
|
int32 FN_back_par1_sprite(int32 *params);
|
|
int32 FN_fore_par0_sprite(int32 *params);
|
|
int32 FN_fore_par1_sprite(int32 *params);
|
|
int32 FN_set_player_action_event(int32 *params);
|
|
int32 FN_set_scroll_coordinate(int32 *params);
|
|
int32 FN_stand_at_anim(int32 *params);
|
|
int32 FN_set_scroll_left_mouse(int32 *params);
|
|
int32 FN_set_scroll_right_mouse(int32 *params);
|
|
int32 FN_colour(int32 *params);
|
|
int32 FN_flash(int32 *params);
|
|
int32 FN_prefetch(int32 *params);
|
|
int32 FN_get_player_savedata(int32 *params);
|
|
int32 FN_pass_player_savedata(int32 *params);
|
|
int32 FN_send_event(int32 *params);
|
|
int32 FN_add_walkgrid(int32 *params);
|
|
int32 FN_remove_walkgrid(int32 *params);
|
|
int32 FN_check_for_event(int32 *params);
|
|
int32 FN_pause_for_event(int32 *params);
|
|
int32 FN_clear_event(int32 *params);
|
|
int32 FN_face_mega(int32 *params);
|
|
int32 FN_play_sequence(int32 *params);
|
|
int32 FN_shaded_sprite(int32 *params);
|
|
int32 FN_unshaded_sprite(int32 *params);
|
|
int32 FN_fade_up(int32 *params);
|
|
int32 FN_display_msg(int32 *params);
|
|
int32 FN_set_object_held(int32 *params);
|
|
int32 FN_add_sequence_text(int32 *params);
|
|
int32 FN_reset_globals(int32 *params);
|
|
int32 FN_set_palette(int32 *params);
|
|
int32 FN_register_pointer_text(int32 *params);
|
|
int32 FN_fetch_wait(int32 *params);
|
|
int32 FN_release(int32 *params);
|
|
int32 FN_sound_fetch(int32 *params);
|
|
int32 FN_prepare_music(int32 *params);
|
|
int32 FN_smacker_lead_in(int32 *params);
|
|
int32 FN_smacker_lead_out(int32 *params);
|
|
int32 FN_stop_all_fx(int32 *params);
|
|
int32 FN_check_player_activity(int32 *params);
|
|
int32 FN_reset_player_activity_delay(int32 *params);
|
|
int32 FN_check_music_playing(int32 *params);
|
|
int32 FN_play_credits(int32 *params);
|
|
int32 FN_set_scroll_speed_normal(int32 *params);
|
|
int32 FN_set_scroll_speed_slow(int32 *params);
|
|
int32 FN_remove_chooser(int32 *params);
|
|
int32 FN_set_fx_vol_and_pan(int32 *params);
|
|
int32 FN_set_fx_vol(int32 *params);
|
|
int32 FN_restore_game(int32 *params);
|
|
int32 FN_refresh_inventory(int32 *params);
|
|
int32 FN_change_shadows(int32 *params);
|
|
|
|
#define MAX_FN_NUMBER 117
|
|
|
|
extern int32 (*McodeTable[]) (int32 *);
|
|
|
|
// Point to the global variable data
|
|
int32 *globalInterpreterVariables2 = NULL;
|
|
|
|
int g_debugFlag = 0; // Set this to turn debugging on
|
|
|
|
int32 (*McodeTable[MAX_FN_NUMBER + 1]) (int32 *) = {
|
|
FN_test_function,
|
|
FN_test_flags,
|
|
FN_register_start_point,
|
|
FN_init_background,
|
|
FN_set_session,
|
|
FN_back_sprite,
|
|
FN_sort_sprite,
|
|
FN_fore_sprite,
|
|
FN_register_mouse,
|
|
FN_anim,
|
|
FN_random,
|
|
FN_preload,
|
|
FN_add_subject,
|
|
FN_interact,
|
|
FN_choose,
|
|
FN_walk,
|
|
FN_walk_to_anim,
|
|
FN_turn,
|
|
FN_stand_at,
|
|
FN_stand,
|
|
FN_stand_after_anim,
|
|
FN_pause,
|
|
FN_mega_table_anim,
|
|
FN_add_menu_object,
|
|
FN_start_conversation,
|
|
FN_end_conversation,
|
|
FN_set_frame,
|
|
FN_random_pause,
|
|
FN_register_frame,
|
|
FN_no_sprite,
|
|
FN_send_sync,
|
|
FN_update_player_stats,
|
|
FN_pass_graph,
|
|
FN_init_floor_mouse,
|
|
FN_pass_mega,
|
|
FN_face_xy,
|
|
FN_end_session,
|
|
FN_no_human,
|
|
FN_add_human,
|
|
FN_we_wait,
|
|
FN_they_do_we_wait,
|
|
FN_they_do,
|
|
FN_walk_to_talk_to_mega,
|
|
FN_fade_down,
|
|
FN_i_speak,
|
|
FN_total_restart,
|
|
FN_set_walkgrid,
|
|
FN_speech_process,
|
|
FN_set_scaling,
|
|
FN_start_event,
|
|
FN_check_event_waiting,
|
|
FN_request_speech,
|
|
FN_gosub,
|
|
FN_timed_wait,
|
|
FN_play_fx,
|
|
FN_stop_fx,
|
|
FN_play_music,
|
|
FN_stop_music,
|
|
FN_set_value,
|
|
FN_new_script,
|
|
FN_get_sync,
|
|
FN_wait_sync,
|
|
FN_register_walkgrid,
|
|
FN_reverse_mega_table_anim,
|
|
FN_reverse_anim,
|
|
FN_add_to_kill_list,
|
|
FN_set_standby_coords,
|
|
FN_back_par0_sprite,
|
|
FN_back_par1_sprite,
|
|
FN_fore_par0_sprite,
|
|
FN_fore_par1_sprite,
|
|
FN_set_player_action_event,
|
|
FN_set_scroll_coordinate,
|
|
FN_stand_at_anim,
|
|
FN_set_scroll_left_mouse,
|
|
FN_set_scroll_right_mouse,
|
|
FN_colour,
|
|
FN_flash,
|
|
FN_prefetch,
|
|
FN_get_player_savedata,
|
|
FN_pass_player_savedata,
|
|
FN_send_event,
|
|
FN_add_walkgrid,
|
|
FN_remove_walkgrid,
|
|
FN_check_for_event,
|
|
FN_pause_for_event,
|
|
FN_clear_event,
|
|
FN_face_mega,
|
|
FN_play_sequence,
|
|
FN_shaded_sprite,
|
|
FN_unshaded_sprite,
|
|
FN_fade_up,
|
|
FN_display_msg,
|
|
FN_set_object_held,
|
|
FN_add_sequence_text,
|
|
FN_reset_globals,
|
|
FN_set_palette,
|
|
FN_register_pointer_text,
|
|
FN_fetch_wait,
|
|
FN_release,
|
|
FN_prepare_music,
|
|
FN_sound_fetch,
|
|
FN_prepare_music,
|
|
FN_smacker_lead_in,
|
|
FN_smacker_lead_out,
|
|
FN_stop_all_fx,
|
|
FN_check_player_activity,
|
|
FN_reset_player_activity_delay,
|
|
FN_check_music_playing,
|
|
FN_play_credits,
|
|
FN_set_scroll_speed_normal,
|
|
FN_set_scroll_speed_slow,
|
|
FN_remove_chooser,
|
|
FN_set_fx_vol_and_pan,
|
|
FN_set_fx_vol,
|
|
FN_restore_game,
|
|
FN_refresh_inventory,
|
|
FN_change_shadows,
|
|
};
|
|
|
|
#define CHECKSTACKPOINTER2 assert(stackPointer2 >= 0 && stackPointer2 < STACK_SIZE);
|
|
#define PUSHONSTACK(x) { stack2[stackPointer2] = (x); stackPointer2++; CHECKSTACKPOINTER2 }
|
|
#define POPOFFSTACK(x) { x = stack2[stackPointer2 - 1]; stackPointer2--; CHECKSTACKPOINTER2 }
|
|
#define DOOPERATION(x) { stack2[stackPointer2 - 2] = (x); stackPointer2--; CHECKSTACKPOINTER2 }
|
|
|
|
void SetGlobalInterpreterVariables(int32 *vars) {
|
|
globalInterpreterVariables2 = vars;
|
|
}
|
|
|
|
int RunScript(char *scriptData, char *objectData, uint32 *offset) {
|
|
#define STACK_SIZE 10
|
|
|
|
_standardHeader *header = (_standardHeader *) scriptData;
|
|
scriptData += sizeof(_standardHeader) + sizeof(_object_hub);
|
|
|
|
// The script data format:
|
|
// int32_TYPE 1 Size of variable space in bytes
|
|
// ... The variable space
|
|
// int32_TYPE 1 numberOfScripts
|
|
// int32_TYPE numberOfScripts The offsets for each script
|
|
|
|
// Initialise some stuff
|
|
|
|
int ip = 0; // Code pointer
|
|
int curCommand,parameter, value; // Command and parameter variables
|
|
int32 stack2[STACK_SIZE]; // The current stack
|
|
int32 stackPointer2 = 0; // Position within stack
|
|
int parameterReturnedFromMcodeFunction = 0; // Allow scripts to return things
|
|
int savedStartOfMcode = 0; // For saving start of mcode commands
|
|
|
|
int count;
|
|
int retVal;
|
|
int caseCount, foundCase;
|
|
int scriptNumber, foundScript;
|
|
const char *tempScrPtr;
|
|
|
|
// Get the start of variables and start of code
|
|
debug(5, "Enter interpreter data %x, object %x, offset %d", scriptData, objectData, *offset);
|
|
|
|
// FIXME: 'scriptData' and 'variables' used to be const. However,
|
|
// this code writes into 'variables' so it can not be const.
|
|
|
|
char *variables = scriptData + sizeof(int);
|
|
const char *code = scriptData + (int32) READ_LE_UINT32(scriptData) + sizeof(int);
|
|
uint32 noScripts = (int32) READ_LE_UINT32(code);
|
|
|
|
if (*offset < noScripts) {
|
|
ip = READ_LE_UINT32((const int *) code + *offset + 1);
|
|
debug(5, "Start script %d with offset %d",*offset,ip);
|
|
} else {
|
|
ip = *offset;
|
|
debug(5, "Start script with offset %d",ip);
|
|
}
|
|
|
|
code += noScripts * sizeof(int) + sizeof(int);
|
|
|
|
#ifdef DONTPROCESSSCRIPTCHECKSUM
|
|
code += sizeof(int) * 3;
|
|
#else
|
|
// Code should nop be pointing at an identifier and a checksum
|
|
const int *checksumBlock = (const int *) code;
|
|
code += sizeof(int) * 3;
|
|
|
|
if (READ_LE_UINT32(checksumBlock) != 12345678) {
|
|
Con_fatal_error("Invalid script in object %s", header->name);
|
|
return 0;
|
|
}
|
|
|
|
int codeLen = READ_LE_UINT32(checksumBlock + 1);
|
|
int checksum = 0;
|
|
|
|
for (count = 0; count < codeLen; count++)
|
|
checksum += (unsigned char) code[count];
|
|
|
|
if (checksum != (int32) READ_LE_UINT32(checksumBlock + 2)) {
|
|
Con_fatal_error("Checksum error in object %s", header->name);
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
int runningScript = 1;
|
|
|
|
while (runningScript) {
|
|
curCommand = code[ip++];
|
|
|
|
switch (curCommand) {
|
|
case CP_END_SCRIPT:
|
|
// End the script
|
|
debug(5, "End script",0);
|
|
runningScript = 0;
|
|
break;
|
|
case CP_PUSH_LOCAL_VAR32:
|
|
// Push the contents of a local variable
|
|
Read16ip(parameter);
|
|
debug(5, "Push local var %d (%d)", parameter, *(int32 *) (variables + parameter));
|
|
PUSHONSTACK(*(int32 *) (variables + parameter));
|
|
break;
|
|
case CP_PUSH_GLOBAL_VAR32:
|
|
// Push a global variable
|
|
Read16ip(parameter);
|
|
debug(5, "Push global var %d (%d)", parameter, globalInterpreterVariables2[parameter]);
|
|
assert(globalInterpreterVariables2);
|
|
PUSHONSTACK(globalInterpreterVariables2[parameter]);
|
|
break;
|
|
case CP_POP_LOCAL_VAR32:
|
|
// Pop a value into a local word variable
|
|
Read16ip(parameter);
|
|
POPOFFSTACK(value);
|
|
debug(5, "Pop %d into var %d", value, parameter);
|
|
*((int32 *) (variables + parameter)) = value;
|
|
break;
|
|
case CP_CALL_MCODE:
|
|
// Call an mcode routine
|
|
Read16ip(parameter);
|
|
assert(parameter <= MAX_FN_NUMBER);
|
|
// amount to adjust stack by (no of parameters)
|
|
Read8ip(value);
|
|
debug(5, "Call mcode %d with stack = %x", parameter, stack2 + stackPointer2 - value);
|
|
retVal = McodeTable[parameter](stack2 + stackPointer2 - value);
|
|
stackPointer2 -= value;
|
|
CHECKSTACKPOINTER2
|
|
|
|
switch (retVal & 7) {
|
|
case IR_STOP:
|
|
// Quit out for a cycle
|
|
*offset = ip;
|
|
return 0;
|
|
case IR_CONT:
|
|
// Continue as normal
|
|
break;
|
|
case IR_TERMINATE:
|
|
// Return without updating the
|
|
// offset
|
|
return 2;
|
|
case IR_REPEAT:
|
|
// Return setting offset to
|
|
// start of this function call
|
|
*offset = savedStartOfMcode;
|
|
return 0;
|
|
case IR_GOSUB:
|
|
// that's really neat
|
|
*offset = ip;
|
|
return 2;
|
|
default:
|
|
assert(false);
|
|
}
|
|
parameterReturnedFromMcodeFunction = retVal >> 3;
|
|
break;
|
|
case CP_PUSH_LOCAL_ADDR:
|
|
// push the address of a local variable
|
|
Read16ip(parameter);
|
|
debug(5, "Push address of local variable %d (%x)", parameter, (int32) (variables + parameter));
|
|
PUSHONSTACK((int32) (variables + parameter));
|
|
break;
|
|
case CP_PUSH_INT32:
|
|
// Push a long word value on to the stack
|
|
Read32ip(parameter);
|
|
debug(5, "Push int32 %d (%x)", parameter, parameter);
|
|
PUSHONSTACK(parameter);
|
|
break;
|
|
case CP_SKIPONFALSE:
|
|
// Skip if the value on the stack is false
|
|
Read32ipLeaveip(parameter);
|
|
POPOFFSTACK(value);
|
|
debug(5, "Skip %d if %d is false", parameter, value);
|
|
if (value)
|
|
ip += sizeof(int32);
|
|
else
|
|
ip += parameter;
|
|
break;
|
|
case CP_SKIPALWAYS:
|
|
// skip a block
|
|
Read32ipLeaveip(parameter);
|
|
debug(5, "Skip %d", parameter);
|
|
ip += parameter;
|
|
break;
|
|
case CP_SWITCH:
|
|
// 9 switch
|
|
POPOFFSTACK(value);
|
|
Read32ip(caseCount);
|
|
|
|
// Search the cases
|
|
foundCase = 0;
|
|
for (count = 0; count < caseCount && !foundCase; count++) {
|
|
if (value == (int32) READ_LE_UINT32(code + ip)) {
|
|
// We have found the case, so lets
|
|
// jump to it
|
|
foundCase = 1;
|
|
ip += READ_LE_UINT32(code + ip + sizeof(int32));
|
|
} else
|
|
ip += sizeof(int32) * 2;
|
|
}
|
|
|
|
// If we found no matching case then use the
|
|
// default
|
|
|
|
if (!foundCase)
|
|
ip += READ_LE_UINT32(code + ip);
|
|
|
|
break;
|
|
case CP_ADDNPOP_LOCAL_VAR32:
|
|
Read16ip(parameter);
|
|
POPOFFSTACK(value);
|
|
*((int32 *) (variables + parameter)) += value;
|
|
debug(5, "+= %d into var %d->%d", value, parameter, *(int32 *) (variables + parameter));
|
|
break;
|
|
case CP_SUBNPOP_LOCAL_VAR32:
|
|
Read16ip(parameter);
|
|
POPOFFSTACK(value);
|
|
*((int32 *) (variables + parameter)) -= value;
|
|
debug(5, "-= %d into var %d->%d", value, parameter, *(int32 *) (variables + parameter));
|
|
break;
|
|
case CP_SKIPONTRUE:
|
|
// Skip if the value on the stack is TRUE
|
|
Read32ipLeaveip(parameter);
|
|
POPOFFSTACK(value);
|
|
debug(5, "Skip %d if %d is false", parameter, value);
|
|
if (!value)
|
|
ip += sizeof(int32);
|
|
else
|
|
ip += parameter;
|
|
break;
|
|
case CP_POP_GLOBAL_VAR32:
|
|
// Pop a global variable
|
|
Read16ip(parameter);
|
|
POPOFFSTACK(value);
|
|
debug(5, "Pop %d into global var %d", value, parameter);
|
|
|
|
#ifdef TRACEGLOBALVARIABLESET
|
|
TRACEGLOBALVARIABLESET(parameter, value);
|
|
#endif
|
|
|
|
globalInterpreterVariables2[parameter] = value;
|
|
break;
|
|
case CP_ADDNPOP_GLOBAL_VAR32:
|
|
// Add and pop a global variable
|
|
Read16ip(parameter);
|
|
// parameter = *((int16_TYPE *) (code + ip));
|
|
// ip += 2;
|
|
POPOFFSTACK(value);
|
|
globalInterpreterVariables2[parameter] += value;
|
|
debug(5, "+= %d into global var %d->%d", value, parameter, *(int32 *) (variables + parameter));
|
|
break;
|
|
case CP_SUBNPOP_GLOBAL_VAR32:
|
|
// Sub and pop a global variable
|
|
Read16ip(parameter);
|
|
POPOFFSTACK(value);
|
|
globalInterpreterVariables2[parameter] -= value;
|
|
debug(5, "-= %d into global var %d->%d", value, parameter, *(int32 *) (variables + parameter));
|
|
break;
|
|
case CP_DEBUGON:
|
|
// Turn debugging on
|
|
g_debugFlag = 1;
|
|
break;
|
|
case CP_DEBUGOFF:
|
|
// Turn debugging on
|
|
g_debugFlag = 0;
|
|
break;
|
|
case CP_QUIT:
|
|
// Quit out for a cycle
|
|
*offset = ip;
|
|
return 0;
|
|
case CP_TERMINATE:
|
|
// Quit out immediately without affecting the offset
|
|
// pointer
|
|
return 3;
|
|
|
|
// Operators
|
|
|
|
case OP_ISEQUAL:
|
|
// '=='
|
|
debug(5, "%d == %d -> %d",
|
|
stack2[stackPointer2 - 2],
|
|
stack2[stackPointer2 - 1],
|
|
stack2[stackPointer2 - 2] == stack2[stackPointer2 - 1]);
|
|
DOOPERATION (stack2[stackPointer2 - 2] == stack2[stackPointer2 - 1]);
|
|
break;
|
|
case OP_PLUS:
|
|
// '+'
|
|
debug(5, "%d + %d -> %d",
|
|
stack2[stackPointer2 - 2],
|
|
stack2[stackPointer2 - 1],
|
|
stack2[stackPointer2 - 2] + stack2[stackPointer2 - 1]);
|
|
DOOPERATION(stack2[stackPointer2 - 2] + stack2[stackPointer2 - 1]);
|
|
break;
|
|
case OP_MINUS:
|
|
// '-'
|
|
debug(5, "%d - %d -> %d",
|
|
stack2[stackPointer2 - 2],
|
|
stack2[stackPointer2 - 1],
|
|
stack2[stackPointer2 - 2] - stack2[stackPointer2 - 1]);
|
|
DOOPERATION(stack2[stackPointer2 - 2] - stack2[stackPointer2 - 1]);
|
|
break;
|
|
case OP_TIMES:
|
|
// '*'
|
|
debug(5, "%d * %d -> %d",
|
|
stack2[stackPointer2 - 2],
|
|
stack2[stackPointer2 - 1],
|
|
stack2[stackPointer2 - 2] * stack2[stackPointer2 - 1]);
|
|
DOOPERATION(stack2[stackPointer2 - 2] * stack2[stackPointer2 - 1]);
|
|
break;
|
|
case OP_DIVIDE:
|
|
// '/'
|
|
debug(5, "%d / %d -> %d",
|
|
stack2[stackPointer2 - 2],
|
|
stack2[stackPointer2 - 1],
|
|
stack2[stackPointer2 - 2] / stack2[stackPointer2 - 1]);
|
|
DOOPERATION(stack2[stackPointer2 - 2] / stack2[stackPointer2 - 1]);
|
|
break;
|
|
case OP_NOTEQUAL:
|
|
// '!='
|
|
debug(5, "%d != %d -> %d",
|
|
stack2[stackPointer2 - 2],
|
|
stack2[stackPointer2 - 1],
|
|
stack2[stackPointer2 - 2] != stack2[stackPointer2 - 1]);
|
|
DOOPERATION(stack2[stackPointer2 - 2] != stack2[stackPointer2 - 1]);
|
|
break;
|
|
case OP_ANDAND:
|
|
// '&&'
|
|
debug(5, "%d != %d -> %d",
|
|
stack2[stackPointer2 - 2],
|
|
stack2[stackPointer2 - 1],
|
|
stack2[stackPointer2 - 2] && stack2[stackPointer2 - 1]);
|
|
DOOPERATION(stack2[stackPointer2 - 2] && stack2[stackPointer2 - 1]);
|
|
break;
|
|
case OP_GTTHAN:
|
|
// '>'
|
|
debug(5, "%d > %d -> %d",
|
|
stack2[stackPointer2 - 2],
|
|
stack2[stackPointer2 - 1],
|
|
stack2[stackPointer2 - 2] > stack2[stackPointer2 - 1]);
|
|
DOOPERATION(stack2[stackPointer2 - 2] > stack2[stackPointer2 - 1]);
|
|
break;
|
|
case OP_LSTHAN:
|
|
// '<'
|
|
debug(5, "%d < %d -> %d",
|
|
stack2[stackPointer2 - 2],
|
|
stack2[stackPointer2 - 1],
|
|
stack2[stackPointer2 - 2] < stack2[stackPointer2 - 1]);
|
|
DOOPERATION(stack2[stackPointer2 - 2] < stack2[stackPointer2 - 1]);
|
|
break;
|
|
case CP_JUMP_ON_RETURNED:
|
|
// Jump to a part of the script depending on
|
|
// the return value from an mcode routine
|
|
|
|
// Get the maximum value
|
|
Read8ip(parameter);
|
|
ip += READ_LE_UINT32(code + ip + parameterReturnedFromMcodeFunction * 4);
|
|
break;
|
|
case CP_TEMP_TEXT_PROCESS:
|
|
// Process a text line
|
|
// This was apparently used in Linc
|
|
Read32ip(parameter);
|
|
debug(5, "Process text id %d", parameter);
|
|
break;
|
|
case CP_SAVE_MCODE_START:
|
|
// Save the start position on an mcode instruction in
|
|
// case we need to restart it again
|
|
savedStartOfMcode = ip - 1;
|
|
break;
|
|
case CP_RESTART_SCRIPT:
|
|
// Start the script again
|
|
// Do a ip search to find the script we are running
|
|
|
|
tempScrPtr = scriptData + READ_LE_UINT32(scriptData) + sizeof(int);
|
|
scriptNumber = 0;
|
|
foundScript = 0;
|
|
|
|
for (count = 1; count < (int) noScripts && !foundScript; count++) {
|
|
if (ip < ((const int *) tempScrPtr)[count + 1]) {
|
|
scriptNumber = count - 1;
|
|
foundScript = 1;
|
|
}
|
|
}
|
|
|
|
if (!foundScript)
|
|
scriptNumber = count - 1;
|
|
|
|
// So we know what script we are running, lets restart
|
|
// it
|
|
|
|
ip = ((const int *) tempScrPtr)[scriptNumber + 1];
|
|
break;
|
|
case CP_PUSH_STRING:
|
|
// Push the address of a string on to the stack
|
|
// Get the string size
|
|
Read8ip(parameter);
|
|
|
|
// ip points to the string
|
|
PUSHONSTACK((int) (code + ip));
|
|
ip += (parameter + 1);
|
|
break;
|
|
case CP_PUSH_DEREFERENCED_STRUCTURE:
|
|
// Push the address of a dereferenced structure
|
|
Read32ip(parameter);
|
|
debug(5, "Push address of far variable (%x)", (int32) (variables + parameter));
|
|
PUSHONSTACK((int) (objectData + sizeof(int) + sizeof(_standardHeader) + sizeof(_object_hub) + parameter));
|
|
break;
|
|
case OP_GTTHANE:
|
|
// '>='
|
|
debug(5, "%d > %d -> %d",
|
|
stack2[stackPointer2 - 2],
|
|
stack2[stackPointer2 - 1],
|
|
stack2[stackPointer2 - 2] >= stack2[stackPointer2 - 1]);
|
|
DOOPERATION(stack2[stackPointer2 - 2] >= stack2[stackPointer2 - 1]);
|
|
break;
|
|
case OP_LSTHANE:
|
|
// '<='
|
|
debug(5, "%d < %d -> %d",
|
|
stack2[stackPointer2 - 2],
|
|
stack2[stackPointer2 - 1],
|
|
stack2[stackPointer2 - 2] <= stack2[stackPointer2 - 1]);
|
|
DOOPERATION(stack2[stackPointer2 - 2] <= stack2[stackPointer2 - 1]);
|
|
break;
|
|
case OP_OROR:
|
|
// '||'
|
|
debug(5, "%d || %d -> %d",
|
|
stack2[stackPointer2 - 2],
|
|
stack2[stackPointer2 - 1],
|
|
stack2[stackPointer2 - 2] || stack2[stackPointer2 - 1]);
|
|
DOOPERATION (stack2[stackPointer2 - 2] || stack2[stackPointer2 - 1]);
|
|
break;
|
|
default:
|
|
Con_fatal_error("Interpreter error: Invalid token %d", curCommand);
|
|
return 3;
|
|
}
|
|
}
|
|
|
|
return 1;
|
|
}
|