diff options
-rw-r--r-- | saga/input.cpp | 5 | ||||
-rw-r--r-- | saga/interface.cpp | 10 | ||||
-rw-r--r-- | saga/interface.h | 10 | ||||
-rw-r--r-- | saga/script.cpp | 2 | ||||
-rw-r--r-- | saga/script.h | 37 | ||||
-rw-r--r-- | saga/sfuncs.cpp | 40 | ||||
-rw-r--r-- | saga/sthread.cpp | 103 | ||||
-rw-r--r-- | saga/xref.txt | 8 |
8 files changed, 158 insertions, 57 deletions
diff --git a/saga/input.cpp b/saga/input.cpp index 941b63c41f..4bab4b5a54 100644 --- a/saga/input.cpp +++ b/saga/input.cpp @@ -104,7 +104,10 @@ int SagaEngine::processInput() { break; case 27: // Esc // Skip to next scene skip target - _vm->_scene->skipScene(); + if (!_vm->_interface->getMode() == kPanelNone) // FIXME: hack + _vm->_script->SThreadAbortAll(); + else + _vm->_scene->skipScene(); break; default: break; diff --git a/saga/interface.cpp b/saga/interface.cpp index 56def3b38e..6d76ce36e1 100644 --- a/saga/interface.cpp +++ b/saga/interface.cpp @@ -218,7 +218,7 @@ Interface::Interface(SagaEngine *vm) : _vm(vm), _initialized(false) { _activeVerb = I_VERB_WALKTO; _active = 0; - _panelMode = PANEL_COMMAND; + _panelMode = kPanelNone; *_statusText = 0; _initialized = true; @@ -241,7 +241,7 @@ int Interface::deactivate() { return R_SUCCESS; } -int Interface::setMode(R_PANEL_MODES mode) { +int Interface::setMode(int mode) { // TODO: Is this where we should hide/show the mouse cursor? _panelMode = mode; @@ -311,7 +311,7 @@ int Interface::draw() { _vm->_gfx->drawRect(back_buf, &rect, _iDesc.status_bgcol); // Draw command panel background - if (_panelMode == PANEL_COMMAND) { + if (_panelMode == kPanelCommand) { xbase = _cPanel.x; ybase = _cPanel.y; @@ -337,7 +337,7 @@ int Interface::draw() { _vm->_sprite->draw(back_buf, _defPortraits, _leftPortrait, lportrait_x, lportrait_y); - if (_panelMode == PANEL_DIALOGUE && _iDesc.rportrait_x >= 0) { + if (_panelMode == kPanelDialogue && _iDesc.rportrait_x >= 0) { rportrait_x = xbase + _iDesc.rportrait_x; rportrait_y = ybase + _iDesc.rportrait_y; @@ -366,7 +366,7 @@ int Interface::update(const Point& imousePt, int update_flag) { // Get game display info GAME_GetDisplayInfo(&g_di); - if (_panelMode == PANEL_COMMAND) { + if (_panelMode == kPanelCommand) { // Update playfield space ( only if cursor is inside ) if (imouse_y < g_di.scene_h) { // Mouse is in playfield space diff --git a/saga/interface.h b/saga/interface.h index 4b87bfbdd6..003f2c123d 100644 --- a/saga/interface.h +++ b/saga/interface.h @@ -77,8 +77,9 @@ enum INTERFACE_UPDATE_FLAGS { #define IHNM_RPORTRAIT_Y -1 enum R_PANEL_MODES { - PANEL_COMMAND, - PANEL_DIALOGUE + kPanelNone, + kPanelCommand, + kPanelDialogue }; enum R_BUTTON_FLAGS { @@ -164,7 +165,8 @@ class Interface { int registerLang(); int activate(); int deactivate(); - int setMode(R_PANEL_MODES mode); + int setMode(int mode); + int getMode(void) { return _panelMode; } int setStatusText(const char *new_txt); int loadScenePortraits(int res); int setLeftPortrait(int portrait); @@ -188,7 +190,7 @@ class Interface { int _active; R_RSCFILE_CONTEXT *_interfaceContext; R_INTERFACE_DESC _iDesc; - R_PANEL_MODES _panelMode; + int _panelMode; R_INTERFACE_PANEL _cPanel; R_INTERFACE_PANEL _dPanel; char _statusText[R_STATUS_TEXT_LEN]; diff --git a/saga/script.cpp b/saga/script.cpp index 1f6731bd48..ca2d7805f0 100644 --- a/saga/script.cpp +++ b/saga/script.cpp @@ -64,6 +64,8 @@ Script::Script() { _scriptLUTEntryLen = 0; _currentScript = 0; _threadList = 0; + _abortEnabled = true; + _skipSpeeches = false; memset(_dataBuf, 0, sizeof(_dataBuf)); debug(0, "Initializing scripting subsystem"); diff --git a/saga/script.h b/saga/script.h index 5bbde08f4d..04af017413 100644 --- a/saga/script.h +++ b/saga/script.h @@ -62,7 +62,7 @@ enum R_SCRIPT_VERBS { S_VERB_GIVE }; -#define STHREAD_DEF_INSTR_COUNT 8 +#define STHREAD_TIMESLICE 8 struct R_SEMAPHORE { int hold_count; @@ -75,15 +75,35 @@ enum { kVarActor }; +enum { + kTFlagNone = 0, + kTFlagWaiting = 1, // wait for even denoted in waitType + kTFlagFinished = 2, + kTFlagAborted = 4, + kTFlagAsleep = 7 // Combination of all flags which can halt a thread +}; + +enum { + kTWaitNone = 0, // waiting for nothing + kTWaitDelay, // waiting for a timer + kTWaitSpeech, // waiting for speech to finish + kTWaitDialogEnd, // waiting for my dialog to finish + kTWaitDialogBegin, // waiting for other dialog to finish + kTWaitWalk, // waiting to finish walking + kTWaitRequest, // a request is up + kTWaitPause +}; + struct R_SCRIPT_THREAD { - int executing; + int flags; + int waitType; - int sleep_time; + uint sleepTime; int ep_num; // Entrypoint number unsigned long ep_offset; // Entrypoint offset unsigned long i_offset; // Instruction offset - R_SEMAPHORE sem; + R_SEMAPHORE sem; // FIXME: no equivalent. should be replaced with flags // The scripts are allowed to access the stack like any other memory // area. It's therefore probably quite important that our stacks work @@ -195,6 +215,9 @@ protected: R_SCRIPT_DATABUF *_dataBuf[R_SCRIPT_DATABUF_NUM]; YS_DL_LIST *_threadList; + bool _skipSpeeches; + bool _abortEnabled; + public: int _dbg_singlestep; int _dbg_dostep; @@ -204,19 +227,20 @@ public: public: R_SCRIPT_THREAD *SThreadCreate(); int SThreadExecute(R_SCRIPT_THREAD *thread, int ep_num); - int SThreadExecThreads(int msec); + int SThreadExecThreads(uint msec); int SThreadHoldSem(R_SEMAPHORE *sem); int SThreadReleaseSem(R_SEMAPHORE *sem); int SThreadDebugStep(); void SThreadCompleteThread(void); int SThreadDestroy(R_SCRIPT_THREAD *thread); + void SThreadAbortAll(void); private: void setFramePtr(R_SCRIPT_THREAD *thread, int newPtr); unsigned char *SThreadGetReadPtr(R_SCRIPT_THREAD *thread); unsigned long SThreadGetReadOffset(const byte *read_p); size_t SThreadGetReadLen(R_SCRIPT_THREAD *thread); - int SThreadRun(R_SCRIPT_THREAD *thread, int instr_limit, int msec); + int SThreadRun(R_SCRIPT_THREAD *thread, int instr_limit); int SThreadSetEntrypoint(R_SCRIPT_THREAD *thread, int ep_num); private: @@ -276,6 +300,7 @@ private: int SF_playMusic(R_SCRIPTFUNC_PARAMS); int SF_enableEscape(R_SCRIPTFUNC_PARAMS); int SF_playSound(R_SCRIPTFUNC_PARAMS); + int SF_gotoScene(R_SCRIPTFUNC_PARAMS); }; } // End of namespace Saga diff --git a/saga/sfuncs.cpp b/saga/sfuncs.cpp index bb8f462c0f..fa04a6f5fa 100644 --- a/saga/sfuncs.cpp +++ b/saga/sfuncs.cpp @@ -59,7 +59,7 @@ void Script::setupScriptFuncList(void) { {13, 0, NULL}, {14, 2, OPCODE(SF_faceTowards)}, {15, 2, OPCODE(SF_setFollower)}, - {16, 0, NULL}, + {16, 2, OPCODE(SF_gotoScene)}, {17, 0, NULL}, {18, 0, NULL}, {19, 0, NULL}, @@ -127,14 +127,17 @@ void Script::setupScriptFuncList(void) { // Script function #1 (0x01) blocking // Suspends thread execution for the specified time period -// Param1: time to suspend ( units? ) int Script::SF_sleep(R_SCRIPTFUNC_PARAMS) { SDataWord_T time_param; - int time; - - time_param = thread->pop(); - time = _vm->_sdata->readWordU(time_param); - thread->sleep_time = time * 10; + long time; + + if (!_skipSpeeches) { + time_param = thread->pop(); + time = _vm->_sdata->readWordU(time_param); + time = time * 10; // 72.8 ticks per second + thread->flags |= kTFlagWaiting; // put thread to sleep + thread->waitType = kTWaitDelay; + } return R_SUCCESS; } @@ -171,7 +174,7 @@ int Script::SF_setStatusText(R_SCRIPTFUNC_PARAMS) { // Script function #5 (0x05) int Script::SF_commandMode(R_SCRIPTFUNC_PARAMS) { - return _vm->_interface->setMode(PANEL_COMMAND); + return _vm->_interface->setMode(kPanelCommand); } // Script function #6 (0x06) blocking @@ -276,7 +279,7 @@ int Script::SF_freezeInterface(R_SCRIPTFUNC_PARAMS) { // Script function #12 (0x0C) // Disables mouse input, etc. int Script::SF_dialogMode(R_SCRIPTFUNC_PARAMS) { - return _vm->_interface->setMode(PANEL_DIALOGUE); + return _vm->_interface->setMode(kPanelDialogue); } // Script function #14 (0x0E) @@ -293,6 +296,13 @@ int Script::SF_setFollower(R_SCRIPTFUNC_PARAMS) { return R_SUCCESS; } +// Script function #16 (0x10) +int Script::SF_gotoScene(R_SCRIPTFUNC_PARAMS) { + thread->pop(); + thread->pop(); + return R_SUCCESS; +} + // Script function #23 (0x17) int Script::SF_setBgdAnimSpeed(R_SCRIPTFUNC_PARAMS) { thread->pop(); @@ -641,9 +651,7 @@ int Script::SF_placeActor(R_SCRIPTFUNC_PARAMS) { // game cinematic. Pushes a zero or positive value if the game // has not been interrupted. int Script::SF_checkUserInterrupt(R_SCRIPTFUNC_PARAMS) { - thread->retVal = 0; - - // INCOMPLETE + thread->retVal = (_skipSpeeches == true); return R_SUCCESS; } @@ -734,7 +742,13 @@ int Script::SF_playMusic(R_SCRIPTFUNC_PARAMS) { // Script function #69 int Script::SF_enableEscape(R_SCRIPTFUNC_PARAMS) { - thread->pop(); + if (thread->pop()) + _abortEnabled = true; + else { + _skipSpeeches = false; + _abortEnabled = false; + } + return R_SUCCESS; } diff --git a/saga/sthread.cpp b/saga/sthread.cpp index b80d58817e..f8f6edb747 100644 --- a/saga/sthread.cpp +++ b/saga/sthread.cpp @@ -62,6 +62,9 @@ R_SCRIPT_THREAD *Script::SThreadCreate() { new_thread->stackPtr = ARRAYSIZE(new_thread->stackBuf) - 1; setFramePtr(new_thread, new_thread->stackPtr); + new_thread->flags = kTFlagWaiting; + new_thread->waitType = kTWaitPause; + dataBuffer(4)->len = ARRAYSIZE(new_thread->threadVars); dataBuffer(4)->data = new_thread->threadVars; @@ -69,26 +72,66 @@ R_SCRIPT_THREAD *Script::SThreadCreate() { } int Script::SThreadDestroy(R_SCRIPT_THREAD *thread) { + YS_DL_NODE *walk_p; + R_SCRIPT_THREAD *th; + if (thread == NULL) { return R_FAILURE; } + for (walk_p = ys_dll_head(threadList()); walk_p != NULL; walk_p = ys_dll_next(walk_p)) { + th = (R_SCRIPT_THREAD *)ys_dll_get_data(walk_p); + if (thread == th) { + ys_dll_delete(walk_p); + break; + } + } + return R_SUCCESS; } -int Script::SThreadExecThreads(int msec) { - YS_DL_NODE *walk_p; +int Script::SThreadExecThreads(uint msec) { + YS_DL_NODE *walk_p, *next_p; R_SCRIPT_THREAD *thread; if (!isInitialized()) { return R_FAILURE; } - for (walk_p = ys_dll_head(threadList()); walk_p != NULL; walk_p = ys_dll_next(walk_p)) { + walk_p = ys_dll_head(threadList()); + + while (walk_p != NULL) { + next_p = ys_dll_next(walk_p); + thread = (R_SCRIPT_THREAD *)ys_dll_get_data(walk_p); - if (thread->executing) { - SThreadRun(thread, STHREAD_DEF_INSTR_COUNT, msec); + + if (thread->flags & (kTFlagFinished | kTFlagAborted)) { + //if (thread->flags & kTFlagFinished) // FIXME. Missing function + + SThreadDestroy(thread); + walk_p = next_p; + continue; } + + if (thread->flags & kTFlagWaiting) { + switch(thread->waitType) { + case kTWaitDelay: + if (thread->sleepTime < msec) { + thread->sleepTime = 0; + } else { + thread->sleepTime -= msec; + } + + if (thread->sleepTime == 0) + thread->flags &= ~kTFlagWaiting; + break; + } + } + + if (!(thread->flags & kTFlagWaiting)) + SThreadRun(thread, STHREAD_TIMESLICE); + + walk_p = next_p; } return R_SUCCESS; @@ -128,11 +171,21 @@ int Script::SThreadExecute(R_SCRIPT_THREAD *thread, int ep_num) { SThreadSetEntrypoint(thread, ep_num); thread->i_offset = thread->ep_offset; - thread->executing = 1; + thread->flags = kTFlagNone; return R_SUCCESS; } +void Script::SThreadAbortAll(void) { + // TODO: stop current speech + + if (_abortEnabled) + _skipSpeeches = true; + + for (int i = 0; i < 10; i++) + _vm->_script->SThreadExecThreads(0); +} + unsigned char *Script::SThreadGetReadPtr(R_SCRIPT_THREAD *thread) { return currentScript()->bytecode->bytecode_p + thread->i_offset; } @@ -177,7 +230,7 @@ int Script::SThreadDebugStep() { return R_SUCCESS; } -int Script::SThreadRun(R_SCRIPT_THREAD *thread, int instr_limit, int msec) { +int Script::SThreadRun(R_SCRIPT_THREAD *thread, int instr_limit) { int instr_count; uint32 saved_offset; SDataWord_T param1; @@ -199,7 +252,7 @@ int Script::SThreadRun(R_SCRIPT_THREAD *thread, int instr_limit, int msec) { if ((thread == _dbg_thread) && _dbg_singlestep) { if (_dbg_dostep) { debug_print = 1; - thread->sleep_time = 0; + thread->sleepTime = 0; instr_limit = 1; _dbg_dostep = 0; } else { @@ -215,18 +268,8 @@ int Script::SThreadRun(R_SCRIPT_THREAD *thread, int instr_limit, int msec) { scriptS.seek(thread->i_offset); 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; - } + if (thread->sem.hold_count) + break; saved_offset = thread->i_offset; in_char = scriptS.readByte(); @@ -341,7 +384,7 @@ int Script::SThreadRun(R_SCRIPT_THREAD *thread, int instr_limit, int msec) { func_num = scriptS.readUint16LE(); if (func_num >= R_SFUNC_NUM) { _vm->_console->print(S_ERROR_PREFIX "Invalid script function number: (%X)\n", func_num); - thread->executing = 0; + thread->flags |= kTFlagAborted; break; } @@ -359,8 +402,16 @@ int Script::SThreadRun(R_SCRIPT_THREAD *thread, int instr_limit, int msec) { _vm->_console->print(S_WARN_PREFIX "%X: Script function %d failed.\n", thread->i_offset, func_num); } - if (in_char == 0x18) + if (func_num == 16) { // SF_gotoScene + instr_count = instr_limit; // break the loop + break; + } + + if (in_char == 0x18) // CALL function thread->push(thread->retVal); + + if (thread->flags & kTFlagAsleep) + instr_count = instr_limit; // break out of loop! } } break; @@ -378,7 +429,7 @@ int Script::SThreadRun(R_SCRIPT_THREAD *thread, int instr_limit, int msec) { setFramePtr(thread, thread->pop()); if (thread->stackSize() == 0) { _vm->_console->print("Script execution complete."); - thread->executing = 0; + thread->flags |= kTFlagFinished; } else { thread->i_offset = thread->pop(); /* int n_args = */ thread->pop(); @@ -765,7 +816,7 @@ int Script::SThreadRun(R_SCRIPT_THREAD *thread, int instr_limit, int msec) { default: _vm->_console->print(S_ERROR_PREFIX "%X: Invalid opcode encountered: " "(%X).\n", thread->i_offset, in_char); - thread->executing = 0; + thread->flags |= kTFlagAborted; break; } @@ -777,9 +828,9 @@ int Script::SThreadRun(R_SCRIPT_THREAD *thread, int instr_limit, int msec) { } if (unhandled) { _vm->_console->print(S_ERROR_PREFIX "%X: Unhandled opcode.\n", thread->i_offset); - thread->executing = 0; + thread->flags |= kTFlagAborted; } - if (thread->executing && debug_print) { + if ((thread->flags == kTFlagNone) && debug_print) { SDebugPrintInstr(thread); } } diff --git a/saga/xref.txt b/saga/xref.txt index ad1415287b..c31c033af8 100644 --- a/saga/xref.txt +++ b/saga/xref.txt @@ -59,8 +59,8 @@ Scene.c Interp.c ======== - dispatchThreads() STHREAD_ExecThreads() - runThread() STHREAD_completeThread() + dispatchThreads() SThreadExecThreads() + runThread() SThreadCompleteThread() moduleList _scriptLUT ModuleEntry->codeID _scriptLUT->script_rn ModuleEntry->strID _scriptLUT->diag_list_rn @@ -69,3 +69,7 @@ Interp.c threadBase.theObject threadVars[kVarObject] threadBase.withObject threadVars[kVarWithObject] threadBase.theActor threadVars[kVarActor] + +Actor.c +======= + abortAllSpeeches() SThreadAbortAll() |