2003-07-28 01:44:38 +00:00
/* 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 $
*/
2003-11-16 14:18:29 +00:00
# include "common/stdafx.h"
# include "sword2/sword2.h"
2003-10-28 19:51:30 +00:00
# include "sword2/interpreter.h"
2003-07-28 01:44:38 +00:00
2003-10-04 00:52:27 +00:00
namespace Sword2 {
2003-09-20 12:43:52 +00:00
// This file serves two purposes. It is compiled as part of the test functions
// of Linc, and also as part of the game
2003-07-28 01:44:38 +00:00
2003-09-20 12:43:52 +00:00
// I assume Linc was the name of some sort of development tool. Anyway, I've
2003-09-20 12:51:55 +00:00
// 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.
2003-07-28 01:44:38 +00:00
2003-09-20 12:43:52 +00:00
// The machine code table
2003-07-28 01:44:38 +00:00
# define MAX_FN_NUMBER 117
2003-10-18 08:11:50 +00:00
# define OPCODE(x, y) { x, &Logic::y, #y }
void Logic : : setupOpcodes ( void ) {
static const OpcodeEntry opcodes [ MAX_FN_NUMBER + 1 ] = {
/* 00 */
OPCODE ( 1 , fnTestFunction ) ,
OPCODE ( 1 , fnTestFlags ) ,
OPCODE ( 2 , fnRegisterStartPoint ) ,
OPCODE ( 2 , fnInitBackground ) ,
/* 04 */
OPCODE ( 1 , fnSetSession ) ,
OPCODE ( 1 , fnBackSprite ) ,
OPCODE ( 1 , fnSortSprite ) ,
OPCODE ( 1 , fnForeSprite ) ,
/* 08 */
OPCODE ( 1 , fnRegisterMouse ) ,
OPCODE ( 3 , fnAnim ) ,
OPCODE ( 2 , fnRandom ) ,
OPCODE ( 1 , fnPreLoad ) ,
/* 0C */
OPCODE ( 2 , fnAddSubject ) ,
OPCODE ( 1 , fnInteract ) ,
OPCODE ( 0 , fnChoose ) ,
OPCODE ( 7 , fnWalk ) ,
/* 10 */
OPCODE ( 5 , fnWalkToAnim ) ,
OPCODE ( 6 , fnTurn ) ,
OPCODE ( 5 , fnStandAt ) ,
OPCODE ( 3 , fnStand ) ,
/* 14 */
OPCODE ( 3 , fnStandAfterAnim ) ,
OPCODE ( 2 , fnPause ) ,
OPCODE ( 4 , fnMegaTableAnim ) ,
OPCODE ( 1 , fnAddMenuObject ) ,
/* 18 */
OPCODE ( 0 , fnStartConversation ) ,
OPCODE ( 0 , fnEndConversation ) ,
OPCODE ( 3 , fnSetFrame ) ,
OPCODE ( 3 , fnRandomPause ) ,
/* 1C */
OPCODE ( 3 , fnRegisterFrame ) ,
OPCODE ( 1 , fnNoSprite ) ,
OPCODE ( 2 , fnSendSync ) ,
OPCODE ( 1 , fnUpdatePlayerStats ) ,
/* 20 */
OPCODE ( 1 , fnPassGraph ) ,
OPCODE ( 1 , fnInitFloorMouse ) ,
OPCODE ( 1 , fnPassMega ) ,
OPCODE ( 6 , fnFaceXY ) ,
/* 24 */
OPCODE ( 1 , fnEndSession ) ,
OPCODE ( 0 , fnNoHuman ) ,
OPCODE ( 0 , fnAddHuman ) ,
OPCODE ( 1 , fnWeWait ) ,
/* 28 */
OPCODE ( 8 , fnTheyDoWeWait ) ,
OPCODE ( 7 , fnTheyDo ) ,
OPCODE ( 6 , fnWalkToTalkToMega ) ,
OPCODE ( 0 , fnFadeDown ) ,
/* 2C */
OPCODE ( 0 , fnISpeak ) ,
OPCODE ( 0 , fnTotalRestart ) ,
OPCODE ( 0 , fnSetWalkGrid ) ,
OPCODE ( 5 , fnSpeechProcess ) ,
/* 30 */
OPCODE ( 3 , fnSetScaling ) ,
OPCODE ( 0 , fnStartEvent ) ,
OPCODE ( 0 , fnCheckEventWaiting ) ,
OPCODE ( 1 , fnRequestSpeech ) ,
/* 34 */
OPCODE ( 1 , fnGosub ) ,
OPCODE ( 3 , fnTimedWait ) ,
OPCODE ( 5 , fnPlayFx ) ,
OPCODE ( 1 , fnStopFx ) ,
/* 38 */
OPCODE ( 2 , fnPlayMusic ) ,
OPCODE ( 0 , fnStopMusic ) ,
OPCODE ( 2 , fnSetValue ) ,
OPCODE ( 1 , fnNewScript ) ,
/* 3C */
OPCODE ( 0 , fnGetSync ) ,
OPCODE ( 0 , fnWaitSync ) ,
OPCODE ( 0 , fnRegisterWalkGrid ) ,
OPCODE ( 4 , fnReverseMegaTableAnim ) ,
/* 40 */
OPCODE ( 3 , fnReverseAnim ) ,
OPCODE ( 0 , fnAddToKillList ) ,
OPCODE ( 3 , fnSetStandbyCoords ) ,
OPCODE ( 1 , fnBackPar0Sprite ) ,
/* 44 */
OPCODE ( 1 , fnBackPar1Sprite ) ,
OPCODE ( 1 , fnForePar0Sprite ) ,
OPCODE ( 1 , fnForePar1Sprite ) ,
OPCODE ( 1 , fnSetPlayerActionEvent ) ,
/* 48 */
OPCODE ( 2 , fnSetScrollCoordinate ) ,
OPCODE ( 3 , fnStandAtAnim ) ,
OPCODE ( 1 , fnSetScrollLeftMouse ) ,
OPCODE ( 1 , fnSetScrollRightMouse ) ,
/* 4C */
OPCODE ( 1 , fnColour ) ,
OPCODE ( 1 , fnFlash ) ,
OPCODE ( 1 , fnPreFetch ) ,
OPCODE ( 3 , fnGetPlayerSaveData ) ,
/* 50 */
OPCODE ( 3 , fnPassPlayerSaveData ) ,
OPCODE ( 2 , fnSendEvent ) ,
OPCODE ( 1 , fnAddWalkGrid ) ,
OPCODE ( 1 , fnRemoveWalkGrid ) ,
/* 54 */
OPCODE ( 0 , fnCheckForEvent ) ,
OPCODE ( 2 , fnPauseForEvent ) ,
OPCODE ( 0 , fnClearEvent ) ,
OPCODE ( 5 , fnFaceMega ) ,
/* 58 */
OPCODE ( 2 , fnPlaySequence ) ,
OPCODE ( 1 , fnShadedSprite ) ,
OPCODE ( 1 , fnUnshadedSprite ) ,
OPCODE ( 0 , fnFadeUp ) ,
/* 60 */
OPCODE ( 1 , fnDisplayMsg ) ,
OPCODE ( 0 , fnSetObjectHeld ) ,
OPCODE ( 3 , fnAddSequenceText ) ,
OPCODE ( 0 , fnResetGlobals ) ,
/* 64 */
OPCODE ( 1 , fnSetPalette ) ,
OPCODE ( 1 , fnRegisterPointerText ) ,
OPCODE ( 1 , fnFetchWait ) ,
OPCODE ( 1 , fnRelease ) ,
/* 68 */
OPCODE ( 1 , fnPrepareMusic ) ,
OPCODE ( 1 , fnSoundFetch ) ,
OPCODE ( 1 , fnPrepareMusic ) , // Again, apparently
OPCODE ( 1 , fnSmackerLeadIn ) ,
/* 6C */
OPCODE ( 1 , fnSmackerLeadOut ) ,
OPCODE ( 0 , fnStopAllFx ) ,
OPCODE ( 1 , fnCheckPlayerActivity ) ,
OPCODE ( 0 , fnResetPlayerActivityDelay ) ,
/* 70 */
OPCODE ( 0 , fnCheckMusicPlaying ) ,
OPCODE ( 0 , fnPlayCredits ) ,
OPCODE ( 0 , fnSetScrollSpeedNormal ) ,
OPCODE ( 0 , fnSetScrollSpeedSlow ) ,
/* 74 */
OPCODE ( 0 , fnRemoveChooser ) ,
OPCODE ( 3 , fnSetFxVolAndPan ) ,
OPCODE ( 3 , fnSetFxVol ) ,
OPCODE ( 0 , fnRestoreGame ) ,
/* 78 */
OPCODE ( 0 , fnRefreshInventory ) ,
OPCODE ( 0 , fnChangeShadows )
} ;
_opcodes = opcodes ;
2003-07-28 01:44:38 +00:00
} ;
2003-10-18 08:11:50 +00:00
int32 Logic : : executeOpcode ( int i , int32 * params ) {
OpcodeProc op = _opcodes [ i ] . proc ;
return ( this - > * op ) ( params ) ;
}
2003-11-10 07:52:15 +00:00
// FIXME: Is the handling of script local variables really alignment-safe?
2003-10-19 18:01:05 +00:00
2003-09-27 11:02:58 +00:00
# define CHECKSTACKPOINTER2 assert(stackPointer2 >= 0 && stackPointer2 < STACK_SIZE);
2003-09-20 12:43:52 +00:00
# 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 }
2003-07-28 01:44:38 +00:00
2003-10-21 08:54:50 +00:00
void Logic : : setGlobalInterpreterVariables ( int32 * vars ) {
2003-10-22 06:51:57 +00:00
_globals = vars ;
2003-07-28 01:44:38 +00:00
}
2003-10-21 08:54:50 +00:00
int Logic : : runScript ( char * scriptData , char * objectData , uint32 * offset ) {
2003-07-28 01:44:38 +00:00
# define STACK_SIZE 10
2003-09-20 12:43:52 +00:00
_standardHeader * header = ( _standardHeader * ) scriptData ;
2003-07-28 01:44:38 +00:00
scriptData + = sizeof ( _standardHeader ) + sizeof ( _object_hub ) ;
// The script data format:
2003-09-20 12:43:52 +00:00
// int32_TYPE 1 Size of variable space in bytes
// ... The variable space
// int32_TYPE 1 numberOfScripts
// int32_TYPE numberOfScripts The offsets for each script
2003-07-28 01:44:38 +00:00
// Initialise some stuff
2003-09-20 12:43:52 +00:00
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 ;
2003-07-28 01:44:38 +00:00
// Get the start of variables and start of code
2003-09-27 11:02:58 +00:00
debug ( 5 , " Enter interpreter data %x, object %x, offset %d " , scriptData , objectData , * offset ) ;
2003-07-28 02:39:40 +00:00
2003-07-28 11:54:26 +00:00
// FIXME: 'scriptData' and 'variables' used to be const. However,
// this code writes into 'variables' so it can not be const.
2003-09-20 12:43:52 +00:00
2003-10-19 18:01:05 +00:00
char * variables = scriptData + sizeof ( int32 ) ;
const char * code = scriptData + ( int32 ) READ_LE_UINT32 ( scriptData ) + sizeof ( int32 ) ;
2003-09-20 12:43:52 +00:00
uint32 noScripts = ( int32 ) READ_LE_UINT32 ( code ) ;
if ( * offset < noScripts ) {
ip = READ_LE_UINT32 ( ( const int * ) code + * offset + 1 ) ;
2003-10-18 08:11:50 +00:00
debug ( 5 , " Start script %d with offset %d " , * offset , ip ) ;
2003-09-20 12:43:52 +00:00
} else {
ip = * offset ;
2003-10-18 08:11:50 +00:00
debug ( 5 , " Start script with offset %d " , ip ) ;
2003-07-28 01:44:38 +00:00
}
2003-10-19 18:01:05 +00:00
code + = noScripts * sizeof ( int32 ) + sizeof ( int32 ) ;
2003-07-28 01:44:38 +00:00
# ifdef DONTPROCESSSCRIPTCHECKSUM
2003-10-19 18:01:05 +00:00
code + = sizeof ( int32 ) * 3 ;
2003-07-28 01:44:38 +00:00
# else
2003-09-20 12:43:52 +00:00
// Code should nop be pointing at an identifier and a checksum
const int * checksumBlock = ( const int * ) code ;
2003-10-19 18:01:05 +00:00
code + = sizeof ( int32 ) * 3 ;
2003-07-28 01:44:38 +00:00
2003-09-20 12:43:52 +00:00
if ( READ_LE_UINT32 ( checksumBlock ) ! = 12345678 ) {
2003-10-26 15:42:49 +00:00
error ( " Invalid script in object %s " , header - > name ) ;
2003-09-20 12:43:52 +00:00
return 0 ;
2003-07-28 01:44:38 +00:00
}
2003-09-20 12:43:52 +00:00
int codeLen = READ_LE_UINT32 ( checksumBlock + 1 ) ;
2003-07-28 01:44:38 +00:00
int checksum = 0 ;
2003-09-20 12:43:52 +00:00
for ( count = 0 ; count < codeLen ; count + + )
checksum + = ( unsigned char ) code [ count ] ;
2003-07-28 01:44:38 +00:00
2003-09-20 12:43:52 +00:00
if ( checksum ! = ( int32 ) READ_LE_UINT32 ( checksumBlock + 2 ) ) {
2003-10-26 15:42:49 +00:00
error ( " Checksum error in object %s " , header - > name ) ;
2003-09-20 12:43:52 +00:00
return 0 ;
}
# endif
2003-07-28 01:44:38 +00:00
int runningScript = 1 ;
2003-09-20 12:43:52 +00:00
while ( runningScript ) {
curCommand = code [ ip + + ] ;
2003-09-21 16:11:26 +00:00
switch ( curCommand ) {
case CP_END_SCRIPT :
// End the script
2003-09-27 11:02:58 +00:00
debug ( 5 , " End script " , 0 ) ;
2003-09-21 16:11:26 +00:00
runningScript = 0 ;
break ;
case CP_PUSH_LOCAL_VAR32 :
// Push the contents of a local variable
Read16ip ( parameter ) ;
2003-09-27 11:02:58 +00:00
debug ( 5 , " Push local var %d (%d) " , parameter , * ( int32 * ) ( variables + parameter ) ) ;
2003-09-21 16:11:26 +00:00
PUSHONSTACK ( * ( int32 * ) ( variables + parameter ) ) ;
break ;
case CP_PUSH_GLOBAL_VAR32 :
// Push a global variable
Read16ip ( parameter ) ;
2003-10-22 06:51:57 +00:00
assert ( _globals ) ;
debug ( 5 , " Push global var %d (%d) " , parameter , _globals [ parameter ] ) ;
PUSHONSTACK ( _globals [ parameter ] ) ;
2003-09-21 16:11:26 +00:00
break ;
case CP_POP_LOCAL_VAR32 :
// Pop a value into a local word variable
Read16ip ( parameter ) ;
POPOFFSTACK ( value ) ;
2003-10-23 07:08:09 +00:00
debug ( 5 , " Pop %d into local var %d " , value , parameter ) ;
2003-09-21 16:11:26 +00:00
* ( ( int32 * ) ( variables + parameter ) ) = value ;
break ;
case CP_CALL_MCODE :
// Call an mcode routine
Read16ip ( parameter ) ;
2003-09-27 11:02:58 +00:00
assert ( parameter < = MAX_FN_NUMBER ) ;
2003-09-21 16:11:26 +00:00
// amount to adjust stack by (no of parameters)
Read8ip ( value ) ;
2003-09-27 11:02:58 +00:00
debug ( 5 , " Call mcode %d with stack = %x " , parameter , stack2 + stackPointer2 - value ) ;
2003-10-18 08:11:50 +00:00
2003-10-21 08:54:50 +00:00
retVal = executeOpcode ( parameter , stack2 + stackPointer2 - value ) ;
2003-10-18 08:11:50 +00:00
2003-09-21 16:11:26 +00:00
stackPointer2 - = value ;
CHECKSTACKPOINTER2
switch ( retVal & 7 ) {
case IR_STOP :
2003-07-28 01:44:38 +00:00
// Quit out for a cycle
* offset = ip ;
2003-09-20 12:43:52 +00:00
return 0 ;
2003-09-21 16:11:26 +00:00
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 :
2003-09-27 11:02:58 +00:00
assert ( false ) ;
2003-09-21 16:11:26 +00:00
}
parameterReturnedFromMcodeFunction = retVal > > 3 ;
break ;
case CP_PUSH_LOCAL_ADDR :
// push the address of a local variable
Read16ip ( parameter ) ;
2003-11-16 14:18:29 +00:00
debug ( 5 , " Push address of local variable %d (%x) " , parameter , _vm - > _memory - > ptrToInt ( ( const uint8 * ) ( variables + parameter ) ) ) ;
PUSHONSTACK ( _vm - > _memory - > ptrToInt ( ( uint8 * ) ( variables + parameter ) ) ) ;
2003-09-21 16:11:26 +00:00
break ;
case CP_PUSH_INT32 :
// Push a long word value on to the stack
Read32ip ( parameter ) ;
2003-09-27 11:02:58 +00:00
debug ( 5 , " Push int32 %d (%x) " , parameter , parameter ) ;
2003-09-21 16:11:26 +00:00
PUSHONSTACK ( parameter ) ;
break ;
case CP_SKIPONFALSE :
// Skip if the value on the stack is false
Read32ipLeaveip ( parameter ) ;
POPOFFSTACK ( value ) ;
2003-09-27 11:02:58 +00:00
debug ( 5 , " Skip %d if %d is false " , parameter , value ) ;
2003-09-21 16:11:26 +00:00
if ( value )
ip + = sizeof ( int32 ) ;
else
ip + = parameter ;
break ;
case CP_SKIPALWAYS :
// skip a block
Read32ipLeaveip ( parameter ) ;
2003-09-27 11:02:58 +00:00
debug ( 5 , " Skip %d " , parameter ) ;
2003-09-21 16:11:26 +00:00
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 ;
2003-10-19 18:01:05 +00:00
debug ( 5 , " += %d into local var %d->%d " , value , parameter , * ( int32 * ) ( variables + parameter ) ) ;
2003-09-21 16:11:26 +00:00
break ;
case CP_SUBNPOP_LOCAL_VAR32 :
Read16ip ( parameter ) ;
POPOFFSTACK ( value ) ;
* ( ( int32 * ) ( variables + parameter ) ) - = value ;
2003-10-19 18:01:05 +00:00
debug ( 5 , " -= %d into local var %d->%d " , value , parameter , * ( int32 * ) ( variables + parameter ) ) ;
2003-09-21 16:11:26 +00:00
break ;
case CP_SKIPONTRUE :
// Skip if the value on the stack is TRUE
Read32ipLeaveip ( parameter ) ;
POPOFFSTACK ( value ) ;
2003-09-27 11:02:58 +00:00
debug ( 5 , " Skip %d if %d is false " , parameter , value ) ;
2003-09-21 16:11:26 +00:00
if ( ! value )
ip + = sizeof ( int32 ) ;
else
ip + = parameter ;
break ;
case CP_POP_GLOBAL_VAR32 :
// Pop a global variable
Read16ip ( parameter ) ;
POPOFFSTACK ( value ) ;
2003-09-27 11:02:58 +00:00
debug ( 5 , " Pop %d into global var %d " , value , parameter ) ;
2003-07-28 01:44:38 +00:00
2003-09-21 16:11:26 +00:00
# ifdef TRACEGLOBALVARIABLESET
TRACEGLOBALVARIABLESET ( parameter , value ) ;
# endif
2003-09-20 12:43:52 +00:00
2003-10-22 06:51:57 +00:00
_globals [ parameter ] = value ;
2003-09-21 16:11:26 +00:00
break ;
case CP_ADDNPOP_GLOBAL_VAR32 :
// Add and pop a global variable
Read16ip ( parameter ) ;
POPOFFSTACK ( value ) ;
2003-10-22 06:51:57 +00:00
_globals [ parameter ] + = value ;
2003-10-23 07:08:09 +00:00
debug ( 5 , " += %d into global var %d->%d " , value , parameter , _globals [ parameter ] ) ;
2003-09-21 16:11:26 +00:00
break ;
case CP_SUBNPOP_GLOBAL_VAR32 :
// Sub and pop a global variable
Read16ip ( parameter ) ;
POPOFFSTACK ( value ) ;
2003-10-22 06:51:57 +00:00
_globals [ parameter ] - = value ;
2003-10-23 07:08:09 +00:00
debug ( 5 , " -= %d into global var %d->%d " , value , parameter , _globals [ parameter ] ) ;
2003-09-21 16:11:26 +00:00
break ;
case CP_DEBUGON :
// Turn debugging on
2003-10-22 06:51:57 +00:00
_debugFlag = true ;
2003-09-21 16:11:26 +00:00
break ;
case CP_DEBUGOFF :
// Turn debugging on
2003-10-22 06:51:57 +00:00
_debugFlag = false ;
2003-09-21 16:11:26 +00:00
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 :
// '=='
2003-09-27 11:02:58 +00:00
debug ( 5 , " %d == %d -> %d " ,
2003-09-21 16:11:26 +00:00
stack2 [ stackPointer2 - 2 ] ,
stack2 [ stackPointer2 - 1 ] ,
stack2 [ stackPointer2 - 2 ] = = stack2 [ stackPointer2 - 1 ] ) ;
2003-10-23 07:08:09 +00:00
DOOPERATION ( stack2 [ stackPointer2 - 2 ] = = stack2 [ stackPointer2 - 1 ] ) ;
2003-09-21 16:11:26 +00:00
break ;
case OP_PLUS :
// '+'
2003-09-27 11:02:58 +00:00
debug ( 5 , " %d + %d -> %d " ,
2003-09-21 16:11:26 +00:00
stack2 [ stackPointer2 - 2 ] ,
stack2 [ stackPointer2 - 1 ] ,
stack2 [ stackPointer2 - 2 ] + stack2 [ stackPointer2 - 1 ] ) ;
DOOPERATION ( stack2 [ stackPointer2 - 2 ] + stack2 [ stackPointer2 - 1 ] ) ;
break ;
case OP_MINUS :
// '-'
2003-09-27 11:02:58 +00:00
debug ( 5 , " %d - %d -> %d " ,
2003-09-21 16:11:26 +00:00
stack2 [ stackPointer2 - 2 ] ,
stack2 [ stackPointer2 - 1 ] ,
stack2 [ stackPointer2 - 2 ] - stack2 [ stackPointer2 - 1 ] ) ;
DOOPERATION ( stack2 [ stackPointer2 - 2 ] - stack2 [ stackPointer2 - 1 ] ) ;
break ;
case OP_TIMES :
// '*'
2003-09-27 11:02:58 +00:00
debug ( 5 , " %d * %d -> %d " ,
2003-09-21 16:11:26 +00:00
stack2 [ stackPointer2 - 2 ] ,
stack2 [ stackPointer2 - 1 ] ,
stack2 [ stackPointer2 - 2 ] * stack2 [ stackPointer2 - 1 ] ) ;
DOOPERATION ( stack2 [ stackPointer2 - 2 ] * stack2 [ stackPointer2 - 1 ] ) ;
break ;
case OP_DIVIDE :
// '/'
2003-09-27 11:02:58 +00:00
debug ( 5 , " %d / %d -> %d " ,
2003-09-21 16:11:26 +00:00
stack2 [ stackPointer2 - 2 ] ,
stack2 [ stackPointer2 - 1 ] ,
stack2 [ stackPointer2 - 2 ] / stack2 [ stackPointer2 - 1 ] ) ;
DOOPERATION ( stack2 [ stackPointer2 - 2 ] / stack2 [ stackPointer2 - 1 ] ) ;
break ;
case OP_NOTEQUAL :
// '!='
2003-09-27 11:02:58 +00:00
debug ( 5 , " %d != %d -> %d " ,
2003-09-21 16:11:26 +00:00
stack2 [ stackPointer2 - 2 ] ,
stack2 [ stackPointer2 - 1 ] ,
stack2 [ stackPointer2 - 2 ] ! = stack2 [ stackPointer2 - 1 ] ) ;
DOOPERATION ( stack2 [ stackPointer2 - 2 ] ! = stack2 [ stackPointer2 - 1 ] ) ;
break ;
case OP_ANDAND :
// '&&'
2003-09-27 11:02:58 +00:00
debug ( 5 , " %d != %d -> %d " ,
2003-09-21 16:11:26 +00:00
stack2 [ stackPointer2 - 2 ] ,
stack2 [ stackPointer2 - 1 ] ,
stack2 [ stackPointer2 - 2 ] & & stack2 [ stackPointer2 - 1 ] ) ;
DOOPERATION ( stack2 [ stackPointer2 - 2 ] & & stack2 [ stackPointer2 - 1 ] ) ;
break ;
case OP_GTTHAN :
// '>'
2003-09-27 11:02:58 +00:00
debug ( 5 , " %d > %d -> %d " ,
2003-09-21 16:11:26 +00:00
stack2 [ stackPointer2 - 2 ] ,
stack2 [ stackPointer2 - 1 ] ,
stack2 [ stackPointer2 - 2 ] > stack2 [ stackPointer2 - 1 ] ) ;
DOOPERATION ( stack2 [ stackPointer2 - 2 ] > stack2 [ stackPointer2 - 1 ] ) ;
break ;
case OP_LSTHAN :
// '<'
2003-09-27 11:02:58 +00:00
debug ( 5 , " %d < %d -> %d " ,
2003-09-21 16:11:26 +00:00
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 ) ;
2003-09-27 11:02:58 +00:00
debug ( 5 , " Process text id %d " , parameter ) ;
2003-09-21 16:11:26 +00:00
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
2003-10-19 18:01:05 +00:00
tempScrPtr = scriptData + READ_LE_UINT32 ( scriptData ) + sizeof ( int32 ) ;
2003-09-21 16:11:26 +00:00
scriptNumber = 0 ;
foundScript = 0 ;
for ( count = 1 ; count < ( int ) noScripts & & ! foundScript ; count + + ) {
if ( ip < ( ( const int * ) tempScrPtr ) [ count + 1 ] ) {
2003-09-20 12:43:52 +00:00
scriptNumber = count - 1 ;
2003-09-21 16:11:26 +00:00
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
2003-11-16 14:18:29 +00:00
PUSHONSTACK ( _vm - > _memory - > ptrToInt ( ( const uint8 * ) ( code + ip ) ) ) ;
2003-09-21 16:11:26 +00:00
ip + = ( parameter + 1 ) ;
break ;
case CP_PUSH_DEREFERENCED_STRUCTURE :
// Push the address of a dereferenced structure
Read32ip ( parameter ) ;
2003-11-16 14:18:29 +00:00
debug ( 5 , " Push address of far variable (%x) " , _vm - > _memory - > ptrToInt ( ( const uint8 * ) ( objectData + sizeof ( int32 ) + sizeof ( _standardHeader ) + sizeof ( _object_hub ) + parameter ) ) ) ;
PUSHONSTACK ( _vm - > _memory - > ptrToInt ( ( const uint8 * ) ( objectData + sizeof ( int32 ) + sizeof ( _standardHeader ) + sizeof ( _object_hub ) + parameter ) ) ) ;
2003-09-21 16:11:26 +00:00
break ;
case OP_GTTHANE :
// '>='
2003-09-27 11:02:58 +00:00
debug ( 5 , " %d > %d -> %d " ,
2003-09-21 16:11:26 +00:00
stack2 [ stackPointer2 - 2 ] ,
stack2 [ stackPointer2 - 1 ] ,
stack2 [ stackPointer2 - 2 ] > = stack2 [ stackPointer2 - 1 ] ) ;
DOOPERATION ( stack2 [ stackPointer2 - 2 ] > = stack2 [ stackPointer2 - 1 ] ) ;
break ;
case OP_LSTHANE :
// '<='
2003-09-27 11:02:58 +00:00
debug ( 5 , " %d < %d -> %d " ,
2003-09-21 16:11:26 +00:00
stack2 [ stackPointer2 - 2 ] ,
stack2 [ stackPointer2 - 1 ] ,
stack2 [ stackPointer2 - 2 ] < = stack2 [ stackPointer2 - 1 ] ) ;
DOOPERATION ( stack2 [ stackPointer2 - 2 ] < = stack2 [ stackPointer2 - 1 ] ) ;
break ;
case OP_OROR :
// '||'
2003-09-27 11:02:58 +00:00
debug ( 5 , " %d || %d -> %d " ,
2003-09-21 16:11:26 +00:00
stack2 [ stackPointer2 - 2 ] ,
stack2 [ stackPointer2 - 1 ] ,
stack2 [ stackPointer2 - 2 ] | | stack2 [ stackPointer2 - 1 ] ) ;
DOOPERATION ( stack2 [ stackPointer2 - 2 ] | | stack2 [ stackPointer2 - 1 ] ) ;
break ;
default :
2003-10-26 15:42:49 +00:00
error ( " Interpreter error: Invalid token %d " , curCommand ) ;
2003-09-21 16:11:26 +00:00
return 3 ;
2003-07-28 01:44:38 +00:00
}
}
2003-09-20 12:43:52 +00:00
return 1 ;
2003-07-28 01:44:38 +00:00
}
2003-10-04 00:52:27 +00:00
} // End of namespace Sword2