aboutsummaryrefslogtreecommitdiff
path: root/saga/sthread.cpp
diff options
context:
space:
mode:
authorEugene Sandulenko2004-04-12 21:40:49 +0000
committerEugene Sandulenko2004-04-12 21:40:49 +0000
commitf3d340fb0ce72b9db59b8c701153bc82b595f75e (patch)
treebf250cf3a1e6aee35c7f40d766994b0c2c188e5c /saga/sthread.cpp
parent0a0a0c7b0609d8774cef849e7511e7b21d12c5db (diff)
downloadscummvm-rg350-f3d340fb0ce72b9db59b8c701153bc82b595f75e.tar.gz
scummvm-rg350-f3d340fb0ce72b9db59b8c701153bc82b595f75e.tar.bz2
scummvm-rg350-f3d340fb0ce72b9db59b8c701153bc82b595f75e.zip
WIP for SAGA engine.
o text formatting is not consistent with rules, just indent utility is too dumb for that o it does not use OSystem, i.e. it runs on direct SDL calls o it may not even compile on your box o if you enable it, expect zillions of warnings o no sound Now it runs ITE intro as reinherit did svn-id: r13564
Diffstat (limited to 'saga/sthread.cpp')
-rw-r--r--saga/sthread.cpp1120
1 files changed, 1120 insertions, 0 deletions
diff --git a/saga/sthread.cpp b/saga/sthread.cpp
new file mode 100644
index 0000000000..04407a1eec
--- /dev/null
+++ b/saga/sthread.cpp
@@ -0,0 +1,1120 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2004 The ScummVM project
+ *
+ * The ReInherit Engine is (C)2000-2003 by Daniel Balsom.
+ *
+ * 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$
+ *
+ */
+/*
+
+ Description:
+
+ Scripting module thread management component
+
+ Notes:
+*/
+
+#include "reinherit.h"
+
+#include "yslib.h"
+
+#include <limits.h>
+
+/*
+ * Uses the following modules:
+\*--------------------------------------------------------------------------*/
+#include "actor_mod.h"
+#include "console_mod.h"
+#include "text_mod.h"
+
+/*
+ * Begin module component
+\*--------------------------------------------------------------------------*/
+#include "script.h"
+#include "script_mod.h"
+
+#include "sdata.h"
+#include "sstack.h"
+#include "sthread.h"
+#include "sfuncs.h"
+
+namespace Saga {
+
+R_SCRIPT_THREAD *STHREAD_Create(void)
+{
+ YS_DL_NODE *new_node;
+ R_SCRIPT_THREAD *new_thread;
+
+ int result;
+
+ if (!ScriptModule.initialized) {
+
+ return NULL;
+ }
+
+ new_thread = (R_SCRIPT_THREAD *)calloc(1, sizeof *new_thread);
+ if (new_thread == NULL) {
+ return NULL;
+ }
+
+ result = SSTACK_Create(&(new_thread->stack),
+ R_DEF_THREAD_STACKSIZE, STACK_GROW);
+
+ if (result != STACK_SUCCESS) {
+ return NULL;
+ }
+
+ new_node = ys_dll_add_head(ScriptModule.thread_list,
+ new_thread, sizeof *new_thread);
+
+ free(new_thread);
+
+ return (R_SCRIPT_THREAD *)ys_dll_get_data(new_node);
+
+}
+
+int STHREAD_Destroy(R_SCRIPT_THREAD * thread)
+{
+ if (thread == NULL) {
+ return R_FAILURE;
+ }
+
+ SSTACK_Destroy(thread->stack);
+
+ return R_SUCCESS;
+}
+
+int STHREAD_ExecThreads(int msec)
+{
+ YS_DL_NODE *walk_p;
+ R_SCRIPT_THREAD *thread;
+
+ if (!ScriptModule.initialized) {
+
+ return R_FAILURE;
+ }
+
+ for (walk_p = ys_dll_head(ScriptModule.thread_list);
+ walk_p != NULL; walk_p = ys_dll_next(walk_p)) {
+
+ thread = (R_SCRIPT_THREAD *)ys_dll_get_data(walk_p);
+
+ if (thread->executing) {
+
+ STHREAD_Run(thread, STHREAD_DEF_INSTR_COUNT, msec);
+ }
+ }
+
+ return R_SUCCESS;
+}
+
+int STHREAD_SetEntrypoint(R_SCRIPT_THREAD * thread, int ep_num)
+{
+
+ R_SCRIPT_BYTECODE *bytecode;
+ int max_entrypoint;
+
+ assert(ScriptModule.initialized);
+
+ bytecode = ScriptModule.current_script->bytecode;
+ max_entrypoint = bytecode->n_entrypoints;
+
+ if ((ep_num < 0) || (ep_num >= max_entrypoint)) {
+ return R_FAILURE;
+ }
+
+ thread->ep_num = ep_num;
+ thread->ep_offset = bytecode->entrypoints[ep_num].offset;
+
+ return R_SUCCESS;
+}
+
+int STHREAD_Execute(R_SCRIPT_THREAD * thread, int ep_num)
+{
+
+ assert(ScriptModule.initialized);
+
+ if ((ScriptModule.current_script == NULL) ||
+ (!ScriptModule.current_script->loaded)) {
+
+ return R_FAILURE;
+ }
+
+ STHREAD_SetEntrypoint(thread, ep_num);
+
+ thread->i_offset = thread->ep_offset;
+ thread->executing = 1;
+
+ return R_SUCCESS;
+}
+
+unsigned char *GetReadPtr(R_SCRIPT_THREAD * thread)
+{
+
+ return ScriptModule.current_script->bytecode->bytecode_p +
+ thread->i_offset;
+}
+
+unsigned long GetReadOffset(const uchar * read_p)
+{
+
+ return (unsigned long)(read_p - (unsigned char *)
+ ScriptModule.current_script->bytecode->bytecode_p);
+}
+
+int STHREAD_HoldSem(R_SEMAPHORE * sem)
+{
+ if (sem == NULL) {
+ return R_FAILURE;
+ }
+
+ sem->hold_count++;
+
+ return R_SUCCESS;
+}
+
+int STHREAD_ReleaseSem(R_SEMAPHORE * sem)
+{
+ if (sem == NULL) {
+ return R_FAILURE;
+ }
+
+ sem->hold_count--;
+ if (sem->hold_count < 0) {
+ sem->hold_count = 0;
+ }
+
+ return R_SUCCESS;
+}
+
+int STHREAD_DebugStep(void)
+{
+
+ if (ScriptModule.dbg_singlestep) {
+ ScriptModule.dbg_dostep = 1;
+ }
+
+ return R_SUCCESS;
+}
+
+int STHREAD_Run(R_SCRIPT_THREAD * thread, int instr_limit, int msec)
+{
+
+ int instr_count;
+
+ const uchar *read_p;
+ ulong saved_offset;
+
+ SDataWord_T param1;
+ SDataWord_T param2;
+
+ long iparam1;
+ long iparam2;
+ long iresult;
+
+ SDataWord_T data;
+
+ int debug_print = 0;
+ int n_buf;
+ int bitstate;
+
+ int result;
+ int in_char;
+ int i;
+
+ int unhandled = 0;
+
+ /* Handle debug single-stepping */
+ if ((thread == ScriptModule.dbg_thread) && ScriptModule.dbg_singlestep) {
+
+ if (ScriptModule.dbg_dostep) {
+
+ debug_print = 1;
+
+ thread->sleep_time = 0;
+ instr_limit = 1;
+ ScriptModule.dbg_dostep = 0;
+ } else {
+
+ return R_SUCCESS;
+ }
+ }
+
+ for (instr_count = 0; instr_count < instr_limit; instr_count++) {
+
+ if ((!thread->executing) || (thread->sem.hold_count)) {
+ break;
+ }
+
+ thread->sleep_time -= msec;
+ if (thread->sleep_time < 0) {
+ thread->sleep_time = 0;
+ }
+
+ if (thread->sleep_time) {
+ break;
+ }
+
+ saved_offset = thread->i_offset;
+#if 0
+ R_printf(R_STDOUT, "Executing thread offset: %lu",
+ thread->i_offset);
+#endif
+ read_p = GetReadPtr(thread);
+
+ in_char = ys_read_u8(read_p, &read_p);
+
+ switch (in_char) {
+
+ /* Align (ALGN) */
+ case 0x01:
+ break;
+
+ /*-------------------------------------------------------------*\
+ * STACK INSTRUCTIONS
+ \*-------------------------------------------------------------*/
+
+ /* Push nothing (PSHN) */
+ case 0x02:
+
+ SSTACK_PushNull(thread->stack);
+
+ break;
+
+ /* Pop nothing (POPN) */
+ case 0x03:
+
+ SSTACK_Pop(thread->stack, NULL);
+
+ break;
+
+ /* Push false (PSHF) */
+ case 0x04:
+
+ SSTACK_Push(thread->stack, 0);
+
+ break;
+
+ /* Push true (PSHT) */
+ case 0x05:
+
+ SSTACK_Push(thread->stack, 1);
+
+ break;
+
+ /* Push word (PUSH) */
+ case 0x06:
+
+ param1 = (SDataWord_T) ys_read_u16_le(read_p, &read_p);
+ SSTACK_Push(thread->stack, param1);
+
+ break;
+
+ /* Push word (PSHD) (dialogue string index) */
+ case 0x08:
+
+ param1 = (SDataWord_T) ys_read_u16_le(read_p, &read_p);
+ SSTACK_Push(thread->stack, param1);
+
+ break;
+
+ /*-------------------------------------------------------------*\
+ * DATA INSTRUCTIONS
+ \*-------------------------------------------------------------*/
+
+ /* Test flag (TSTF) */
+ case 0x0B:
+
+ n_buf = *read_p++;
+ param1 = (SDataWord_T) ys_read_u16_le(read_p, &read_p);
+
+ SDATA_GetBit(n_buf, param1, &bitstate);
+ SSTACK_Push(thread->stack, bitstate);
+
+ break;
+
+ /* Get word (GETW) */
+ case 0x0C:
+
+ n_buf = *read_p++;
+ param1 = ys_read_u16_le(read_p, &read_p);
+
+ SDATA_GetWord(n_buf, param1, &data);
+ SSTACK_Push(thread->stack, data);
+
+ break;
+
+ /* Modify flag (MODF) */
+ case 0x0F:
+
+ n_buf = *read_p++;
+ param1 = (SDataWord_T) ys_read_u16_le(read_p, &read_p);
+
+ bitstate = SDATA_ReadWordU(param1);
+
+ SSTACK_Top(thread->stack, &data);
+
+ if (bitstate) {
+ SDATA_SetBit(n_buf, data, 1);
+ } else {
+ SDATA_SetBit(n_buf, data, 0);
+ }
+
+ break;
+
+ /* Put word (PUTW) */
+ case 0x10:
+
+ n_buf = *read_p++;
+ param1 = (SDataWord_T) ys_read_u16_le(read_p, &read_p);
+
+ SSTACK_Top(thread->stack, &data);
+ SDATA_PutWord(n_buf, param1, data);
+
+ break;
+
+ /* Modify flag and pop (MDFP) */
+ case 0x13:
+
+ n_buf = *read_p++;
+ param1 = (SDataWord_T) ys_read_u16_le(read_p, &read_p);
+
+ SSTACK_Pop(thread->stack, &param1);
+
+ bitstate = SDATA_ReadWordU(param1);
+
+ if (bitstate) {
+ SDATA_SetBit(n_buf, param1, 1);
+ } else {
+ SDATA_SetBit(n_buf, param1, 0);
+ }
+
+ break;
+
+ /* Put word and pop (PTWP) */
+ case 0x14:
+
+ n_buf = *read_p++;
+ param1 = (SDataWord_T) ys_read_u16_le(read_p, &read_p);
+
+ SSTACK_Top(thread->stack, &data);
+ SDATA_PutWord(n_buf, param1, data);
+
+ break;
+
+ /*-------------------------------------------------------------*\
+ * CONTROL INSTRUCTIONS
+ \*-------------------------------------------------------------*/
+
+ /* (GOSB): Call subscript ? */
+ case 0x17:
+ {
+
+ int temp;
+ int temp2;
+
+ temp = *read_p++;
+ temp2 = *read_p++;
+
+ param1 =
+ (SDataWord_T) ys_read_u16_le(read_p,
+ &read_p);
+ data = GetReadOffset(read_p);
+
+ /*SSTACK_Push( thread->stack, (SDataWord_T)temp ); */
+ SSTACK_Push(thread->stack, data);
+
+ thread->i_offset = (unsigned long)param1;
+ }
+ break;
+
+ /* (CALL): Call function */
+ case 0x19:
+ case 0x18:
+ {
+ int n_args;
+ uint func_num;
+ int result;
+
+ SFunc_T sfunc;
+
+ n_args = ys_read_u8(read_p, &read_p);
+ func_num = ys_read_u16_le(read_p, &read_p);
+
+ if (func_num >= R_SFUNC_NUM) {
+
+ CON_Print(S_ERROR_PREFIX
+ "Invalid script function number: (%X)\n",
+ func_num);
+
+ thread->executing = 0;
+ break;
+ }
+
+ sfunc = SFuncList[func_num].sfunc_fp;
+
+ if (sfunc == NULL) {
+
+ CON_Print(S_WARN_PREFIX
+ "%X: Undefined script function number: (%X)\n",
+ thread->i_offset, func_num);
+
+ CON_Print(S_WARN_PREFIX
+ "Removing %d operand(s) from stack.\n",
+ n_args);
+
+ for (i = 0; i < n_args; i++) {
+
+ SSTACK_Pop(thread->stack,
+ NULL);
+ }
+ } else {
+
+ result = sfunc(thread);
+
+ if (result != R_SUCCESS) {
+ CON_Print(S_WARN_PREFIX
+ "%X: Script function %d failed.\n",
+ thread->i_offset,
+ func_num);
+ }
+ }
+
+ }
+ break;
+
+ /* (ENTR) Enter the dragon */
+ case 0x1A:
+
+ param1 = ys_read_u16_le(read_p, &read_p);
+
+ break;
+
+ /* (?) Unknown */
+ case 0x1B:
+
+ unhandled = 1;
+ break;
+
+ /* (EXIT) End subscript */
+ case 0x1C:
+
+ result = SSTACK_Pop(thread->stack, &data);
+
+ if (result != STACK_SUCCESS) {
+
+ CON_Print("Script execution complete.");
+ thread->executing = 0;
+ } else {
+
+ thread->i_offset = data;
+ }
+ break;
+
+ /*-------------------------------------------------------------*\
+ * BRANCH INSTRUCTIONS
+ \*-------------------------------------------------------------*/
+
+ /* (JMP): Unconditional jump */
+ case 0x1D:
+
+ param1 = ys_read_u16_le(read_p, &read_p);
+ thread->i_offset = (unsigned long)param1;
+
+ break;
+
+ /* (JNZP): Jump if nonzero + POP */
+ case 0x1E:
+
+ param1 = ys_read_u16_le(read_p, &read_p);
+
+ SSTACK_Pop(thread->stack, &data);
+ if (data) {
+ thread->i_offset = (unsigned long)param1;
+ }
+
+ break;
+
+ /* (JZP): Jump if zero + POP */
+ case 0x1F:
+
+ param1 = ys_read_u16_le(read_p, &read_p);
+
+ SSTACK_Pop(thread->stack, &data);
+ if (!data) {
+ thread->i_offset = (unsigned long)param1;
+ }
+
+ break;
+
+ /* (JNZ): Jump if nonzero */
+ case 0x20:
+
+ param1 = ys_read_u16_le(read_p, &read_p);
+
+ SSTACK_Top(thread->stack, &data);
+ if (data) {
+ thread->i_offset = (unsigned long)param1;
+ }
+
+ break;
+
+ /* (JZ): Jump if zero */
+ case 0x21:
+
+ param1 = ys_read_u16_le(read_p, &read_p);
+
+ SSTACK_Top(thread->stack, &data);
+ if (!data) {
+ thread->i_offset = (unsigned long)param1;
+ }
+
+ break;
+
+ /* (JMPR): Relative jump */
+ case 0x57:
+
+ /* ignored? */
+ ys_read_u16_le(read_p, &read_p);
+ ys_read_u16_le(read_p, &read_p);
+
+ iparam1 = (long)*read_p++;
+
+ thread->i_offset += iparam1;
+ break;
+
+ /* (SWCH): Switch */
+ case 0x22:
+ {
+
+ int n_switch;
+ unsigned int switch_num;
+ unsigned int switch_jmp;
+ unsigned int default_jmp;
+ int case_found = 0;
+
+ SSTACK_Pop(thread->stack, &data);
+
+ n_switch = ys_read_u16_le(read_p, &read_p);
+
+ for (i = 0; i < n_switch; i++) {
+
+ switch_num =
+ ys_read_u16_le(read_p, &read_p);
+ switch_jmp =
+ ys_read_u16_le(read_p, &read_p);
+
+ /* Found the specified case */
+ if (data == (SDataWord_T) switch_num) {
+
+ thread->i_offset = switch_jmp;
+ case_found = 1;
+ break;
+ }
+ }
+
+ /* Jump to default case */
+ if (!case_found) {
+
+ default_jmp =
+ ys_read_u16_le(read_p, &read_p);
+ thread->i_offset = default_jmp;
+ }
+
+ }
+ break;
+
+ /* (RJMP): Random branch */
+ case 0x24:
+ {
+ int n_branch;
+ unsigned int branch_wt;
+ unsigned int branch_jmp;
+
+ int rand_sel = 0;
+ int branch_found = 0;
+
+ /* Ignored? */
+ ys_read_u16_le(read_p, &read_p);
+
+ n_branch = ys_read_u16_le(read_p, &read_p);
+
+ for (i = 0; i < n_branch; i++) {
+
+ branch_wt =
+ ys_read_u16_le(read_p, &read_p);
+ branch_jmp =
+ ys_read_u16_le(read_p, &read_p);
+
+ if (rand_sel == i) {
+
+ thread->i_offset = branch_jmp;
+ branch_found = 1;
+ break;
+ }
+ }
+
+ if (!branch_found) {
+ CON_Print(S_ERROR_PREFIX
+ "%X: Random jump target out of "
+ "bounds.", thread->i_offset);
+ }
+
+ }
+ break;
+
+ /*-------------------------------------------------------------*\
+ * MISC. INSTRUCTIONS
+ \*-------------------------------------------------------------*/
+
+ /* (NEG) Negate stack by 2's complement */
+ case 0x25:
+
+ SSTACK_Pop(thread->stack, &data);
+ data = ~data;
+ data++;
+ SSTACK_Push(thread->stack, data);
+
+ break;
+
+ /* (TSTZ) Test for zero */
+ case 0x26:
+
+ SSTACK_Pop(thread->stack, &data);
+ data = data ? 0 : 1;
+ SSTACK_Push(thread->stack, data);
+
+ break;
+
+ /* (NOT) Binary not */
+ case 0x27:
+
+ SSTACK_Pop(thread->stack, &data);
+ data = ~data;
+ SSTACK_Push(thread->stack, data);
+
+ break;
+
+ /* (?) */
+ case 0x28:
+ unhandled = 1;
+ printf("??? ");
+ read_p++;
+ ys_read_u16_le(read_p, &read_p);
+ break;
+
+ /* (?) */
+ case 0x29:
+ unhandled = 1;
+ printf("??? ");
+ read_p++;
+ ys_read_u16_le(read_p, &read_p);
+ break;
+
+ /* (?) */
+ case 0x2A:
+ unhandled = 1;
+ printf("??? ");
+ read_p++;
+ ys_read_u16_le(read_p, &read_p);
+ break;
+
+ /* (?) */
+ case 0x2B:
+ unhandled = 1;
+ printf("??? ");
+ read_p++;
+ ys_read_u16_le(read_p, &read_p);
+ break;
+
+ /*-------------------------------------------------------------*\
+ * ARITHMETIC INSTRUCTIONS
+ \*-------------------------------------------------------------*/
+
+ /* (ADD): Addition */
+ case 0x2C:
+
+ SSTACK_Pop(thread->stack, &param2);
+ SSTACK_Pop(thread->stack, &param1);
+ iparam2 = (long)param2;
+ iparam1 = (long)param1;
+
+ iresult = iparam1 + iparam2;
+
+ SSTACK_Push(thread->stack, (SDataWord_T) iresult);
+ break;
+
+ /* (SUB): Subtraction */
+ case 0x2D:
+
+ SSTACK_Pop(thread->stack, &param2);
+ SSTACK_Pop(thread->stack, &param1);
+ iparam2 = (long)param2;
+ iparam1 = (long)param1;
+
+ iresult = iparam1 - iparam2;
+
+ SSTACK_Push(thread->stack, (SDataWord_T) iresult);
+ break;
+
+ /* (MULT): Integer multiplication */
+ case 0x2E:
+
+ SSTACK_Pop(thread->stack, &param2);
+ SSTACK_Pop(thread->stack, &param1);
+ iparam2 = (long)param2;
+ iparam1 = (long)param1;
+
+ iresult = iparam1 * iparam2;
+
+ SSTACK_Push(thread->stack, (SDataWord_T) iresult);
+ break;
+
+ /* (DIB): Integer division */
+ case 0x2F:
+
+ SSTACK_Pop(thread->stack, &param2);
+ SSTACK_Pop(thread->stack, &param1);
+ iparam2 = (long)param2;
+ iparam1 = (long)param1;
+
+ iresult = iparam1 / iparam2;
+
+ SSTACK_Push(thread->stack, (SDataWord_T) iresult);
+ break;
+
+ /* (MOD) Modulus */
+ case 0x30:
+
+ SSTACK_Pop(thread->stack, &param2);
+ SSTACK_Pop(thread->stack, &param1);
+ iparam2 = (long)param2;
+ iparam1 = (long)param1;
+
+ iresult = iparam1 % iparam2;
+
+ SSTACK_Push(thread->stack, (SDataWord_T) iresult);
+ break;
+
+ /* (EQU) Test equality */
+ case 0x33:
+
+ SSTACK_Pop(thread->stack, &param2);
+ SSTACK_Pop(thread->stack, &param1);
+ iparam2 = (long)param2;
+ iparam1 = (long)param1;
+
+ data = (iparam1 == iparam2) ? 1 : 0;
+
+ SSTACK_Push(thread->stack, data);
+ break;
+
+ /* (NEQU) Test inequality */
+ case 0x34:
+
+ SSTACK_Pop(thread->stack, &param2);
+ SSTACK_Pop(thread->stack, &param1);
+ iparam2 = (long)param2;
+ iparam1 = (long)param1;
+
+ data = (iparam1 != iparam2) ? 1 : 0;
+
+ SSTACK_Push(thread->stack, data);
+ break;
+
+ /* (GRT) Test Greater-than */
+ case 0x35:
+
+ SSTACK_Pop(thread->stack, &param2);
+ SSTACK_Pop(thread->stack, &param1);
+ iparam2 = (long)param2;
+ iparam1 = (long)param1;
+
+ data = (iparam1 > iparam2) ? 1 : 0;
+
+ SSTACK_Push(thread->stack, data);
+ break;
+
+ /* (LST) Test Less-than */
+ case 0x36:
+
+ SSTACK_Pop(thread->stack, &param2);
+ SSTACK_Pop(thread->stack, &param1);
+ iparam2 = (long)param2;
+ iparam1 = (long)param1;
+
+ data = (iparam1 < iparam2) ? 1 : 0;
+
+ SSTACK_Push(thread->stack, data);
+ break;
+
+ /* (GRTE) Test Greater-than or Equal to */
+ case 0x37:
+
+ SSTACK_Pop(thread->stack, &param2);
+ SSTACK_Pop(thread->stack, &param1);
+ iparam2 = (long)param2;
+ iparam1 = (long)param1;
+
+ data = (iparam1 >= iparam2) ? 1 : 0;
+
+ SSTACK_Push(thread->stack, data);
+ break;
+
+ /* (LSTE) Test Less-than or Equal to */
+ case 0x38:
+
+ SSTACK_Pop(thread->stack, &param2);
+ SSTACK_Pop(thread->stack, &param1);
+ iparam2 = (long)param2;
+ iparam1 = (long)param1;
+
+ data = (iparam1 <= iparam2) ? 1 : 0;
+
+ SSTACK_Push(thread->stack, data);
+ break;
+
+ /* (SHR): Arithmetic binary shift right */
+ case 0x3F:
+
+ SSTACK_Pop(thread->stack, &param2);
+ SSTACK_Pop(thread->stack, &param1);
+
+ iparam2 = (long)param2;
+
+ /* Preserve most significant bit */
+ data =
+ (0x01 << ((sizeof param1 * CHAR_BIT) -
+ 1)) & param1;
+
+ for (i = 0; i < (int)iparam2; i++) {
+ param1 >>= 1;
+ param1 |= data;
+ }
+
+ SSTACK_Push(thread->stack, param1);
+ break;
+
+ /*-------------------------------------------------------------*\
+ * BITWISE INSTRUCTIONS
+ \*-------------------------------------------------------------*/
+
+ /* (SHL) Binary shift left */
+ case 0x40:
+
+ SSTACK_Pop(thread->stack, &param2);
+ SSTACK_Pop(thread->stack, &param1);
+
+ param1 <<= param2;
+
+ SSTACK_Push(thread->stack, param1);
+ break;
+
+ /* (AND) Binary AND */
+ case 0x41:
+
+ SSTACK_Pop(thread->stack, &param2);
+ SSTACK_Pop(thread->stack, &param1);
+
+ param1 &= param2;
+
+ SSTACK_Push(thread->stack, param1);
+ break;
+
+ /* (OR) Binary OR */
+ case 0x42:
+
+ SSTACK_Pop(thread->stack, &param2);
+ SSTACK_Pop(thread->stack, &param1);
+
+ param1 |= param2;
+
+ SSTACK_Push(thread->stack, param1);
+ break;
+
+ /* (XOR) Binary XOR */
+ case 0x43:
+
+ SSTACK_Pop(thread->stack, &param2);
+ SSTACK_Pop(thread->stack, &param1);
+
+ param1 ^= param2;
+
+ SSTACK_Push(thread->stack, param1);
+ break;
+
+ /*-------------------------------------------------------------*\
+ * BOOLEAN LOGIC INSTRUCTIONS
+ \*-------------------------------------------------------------*/
+
+ /* (LAND): Logical AND */
+ case 0x44:
+
+ SSTACK_Pop(thread->stack, &param2);
+ SSTACK_Pop(thread->stack, &param1);
+
+ data = (param1 && param2) ? 1 : 0;
+
+ SSTACK_Push(thread->stack, data);
+ break;
+
+ /* (LOR): Logical OR */
+ case 0x45:
+
+ SSTACK_Pop(thread->stack, &param2);
+ SSTACK_Pop(thread->stack, &param1);
+
+ data = (param1 || param2) ? 1 : 0;
+
+ SSTACK_Push(thread->stack, data);
+ break;
+
+ /* (LXOR): Logical XOR */
+ case 0x46:
+
+ SSTACK_Pop(thread->stack, &param2);
+ SSTACK_Pop(thread->stack, &param1);
+
+ data = ((param1) ? !(param2) : !!(param2));
+
+ SSTACK_Push(thread->stack, data);
+ break;
+
+ /*-------------------------------------------------------------*\
+ * GAME INSTRUCTIONS
+ \*-------------------------------------------------------------*/
+
+ /* (DLGP): Play Character Dialogue */
+ case 0x53:
+ {
+ int n_voices;
+ int a_index;
+ int voice_rn;
+
+ n_voices = *read_p++;
+ param1 =
+ (SDataWord_T) ys_read_u16_le(read_p,
+ &read_p);
+
+ /* ignored ? */
+ *read_p++;
+ ys_read_u16_le(read_p, &read_p);
+
+ a_index = ACTOR_GetActorIndex(param1);
+
+ if (a_index < 0) {
+ CON_Print(S_WARN_PREFIX
+ "%X: DLGP Actor id not found.",
+ thread->i_offset);
+ }
+
+ for (i = 0; i < n_voices; i++) {
+
+ SSTACK_Pop(thread->stack, &data);
+
+ if (a_index < 0)
+ continue;
+
+ if (!ScriptModule.voice_lut_present) {
+ voice_rn = -1;
+ } else {
+ voice_rn =
+ ScriptModule.
+ current_script->voice->
+ voices[data];
+ }
+
+ ACTOR_Speak(a_index,
+ ScriptModule.current_script->diag->
+ str[data], voice_rn, &thread->sem);
+
+ }
+
+ }
+ break;
+
+ /* (DLGS): Initialize dialogue interface */
+ case 0x54:
+ break;
+
+ /* (DLGX): Run dialogue interface */
+ case 0x55:
+ break;
+
+ /* (DLGO): Add a dialogue option to interface */
+ case 0x56:
+ {
+ int param1;
+ int param2;
+ int param3;
+
+ printf("DLGO | ");
+ param1 = *read_p++;
+ param2 = *read_p++;
+
+ printf("%02X %02X ", param1, param2);
+
+ if (param2 > 0) {
+ param3 =
+ ys_read_u16_le(read_p, &read_p);
+
+ printf("%04X", param3);
+ }
+ }
+ break;
+
+ /*-------------------------------------------------------------*\
+ * End instruction list
+ \*-------------------------------------------------------------*/
+
+ default:
+
+ CON_Print(S_ERROR_PREFIX
+ "%X: Invalid opcode encountered: " "(%X).\n",
+ thread->i_offset, in_char);
+ thread->executing = 0;
+
+ break;
+
+ } /* end switch( in_char ) */
+
+ /* Set instruction offset only if a previous instruction didn't
+ * branch */
+ if (saved_offset == thread->i_offset) {
+
+ thread->i_offset = GetReadOffset(read_p);
+ }
+
+ if (unhandled) {
+
+ CON_Print(S_ERROR_PREFIX "%X: Unhandled opcode.\n",
+ thread->i_offset);
+ thread->executing = 0;
+ }
+
+ if (thread->executing && debug_print) {
+ SDEBUG_PrintInstr(thread);
+ }
+
+ }
+
+ return R_SUCCESS;
+}
+
+} // End of namespace Saga
+