Started to rework script threads. Partially moved to thread flags.

Scene skipping now works, but scripts aren't chained yet.

svn-id: r15688
This commit is contained in:
Eugene Sandulenko 2004-10-27 02:27:54 +00:00
parent dc796c9399
commit b4df9bb2c1
8 changed files with 158 additions and 57 deletions

View File

@ -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;

View File

@ -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

View File

@ -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];

View File

@ -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");

View File

@ -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
};
struct R_SCRIPT_THREAD {
int executing;
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
};
int sleep_time;
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 flags;
int waitType;
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

View File

@ -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;
long time;
time_param = thread->pop();
time = _vm->_sdata->readWordU(time_param);
thread->sleep_time = time * 10;
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;
}

View File

@ -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);
}
}

View File

@ -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()