aboutsummaryrefslogtreecommitdiff
path: root/saga
diff options
context:
space:
mode:
authorEugene Sandulenko2004-10-27 02:27:54 +0000
committerEugene Sandulenko2004-10-27 02:27:54 +0000
commitb4df9bb2c1ba4970e4f519da477a75a55ad8b93b (patch)
tree10a22a3427e3c0c3fdace2da9a0386a1743a35b0 /saga
parentdc796c939998e74b0e97c894b14da6bc6e2f35e3 (diff)
downloadscummvm-rg350-b4df9bb2c1ba4970e4f519da477a75a55ad8b93b.tar.gz
scummvm-rg350-b4df9bb2c1ba4970e4f519da477a75a55ad8b93b.tar.bz2
scummvm-rg350-b4df9bb2c1ba4970e4f519da477a75a55ad8b93b.zip
Started to rework script threads. Partially moved to thread flags.
Scene skipping now works, but scripts aren't chained yet. svn-id: r15688
Diffstat (limited to 'saga')
-rw-r--r--saga/input.cpp5
-rw-r--r--saga/interface.cpp10
-rw-r--r--saga/interface.h10
-rw-r--r--saga/script.cpp2
-rw-r--r--saga/script.h37
-rw-r--r--saga/sfuncs.cpp40
-rw-r--r--saga/sthread.cpp103
-rw-r--r--saga/xref.txt8
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()