/* ScummVM - Graphic Adventure Engine * * ScummVM is the legal property of its developers, whose names * are too numerous to list here. Please refer to the COPYRIGHT * file distributed with this source distribution. * * 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 3 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, see . * * * Based on the original sources * Faery Tale II -- The Halls of the Dead * (c) 1993-1996 The Wyrmkeep Entertainment Co. */ #ifndef SAGA2_SCRIPT_H #define SAGA2_SCRIPT_H #include "saga2/objects.h" #include "saga2/calendar.h" namespace Saga2 { typedef int16 ThreadID; // Various result codes returned from runScript enum scriptResult { // Code returned when attempt to run a non-existent script kScriptResultNoScript = 0, // Code returned when script was aborted before completion kScriptResultAborted, // Code returned when script finished kScriptResultFinished, // Script spun off as async thread; no answer available. kScriptResultAsync }; // Variables specific to a thread struct scriptCallFrame { // ID of object who's method is being called (which can be the same // as one of the other objects below). ObjectID invokedObject = Nothing; ActiveItemID invokedTAI; // ID of the objects in the interaction. ObjectID enactor = Nothing, // actor who caused interaction directObject = Nothing, // the object being acted on indirectObject = Nothing; // the object being used // with the other one ActiveItemID directTAI, // the tile activity instance // being used indirectTAI; // the tile activity instance // upon which the object is being // used int16 responseType = -1; // used with knowledge package int16 methodNum = -1; // which method being invoked // Misc fields used in passing parameters to scripts. int16 idNum = 0; // a misc. id number int16 value = 0; // a misc. parameter value TilePoint coords; // a misc. tilepoint int16 returnVal = 0; // return value of script }; // Standard return codes from scripts in the "returnVal" field enum { // Code returned by script when script decides requested // action is not possible, and the calling C-code should // take action to inform user kActionResultFailure = 0, // Code returned by script when script completes the action // successfully and C-code should not complete the action kActionResultSuccess, // Code returned by script when requested action should complete // the action kActionResultNotDone }; // Method used to refer to a SAGA object struct SegmentRef { uint16 segment; // segment / resource number uint16 offset; // offset within segment }; // Segment numbers of "builtin" SAGA data structures, // such as actors and TAGS enum builtinTypes { kBuiltinTypeObject = -1, kBuiltinTypeTAG = -2, kBuiltinAbstract = -3, kBuiltinTypeMission = -4 }; /* ===================================================================== * SAGA management functions * ===================================================================== */ // Load the SAGA data segment from the resource file void initSAGADataSeg(); void saveSAGADataSeg(Common::OutSaveFile *outS); void loadSAGADataSeg(Common::InSaveFile *in); // Dispose of the SAGA data segment -- do nothing inline void cleanupSAGADataSeg() {} /* ===================================================================== * Thread management functions * ===================================================================== */ class Thread; // Initialize the SAGA thread list void initSAGAThreads(); void saveSAGAThreads(Common::OutSaveFile *outS); void loadSAGAThreads(Common::InSaveFile *in, int32 chunkSize); // Dispose of the active SAGA threads void cleanupSAGAThreads(); // Dispose of an active SAGA thread void deleteThread(Thread *p); void newThread(Thread *p, ThreadID id); void newThread(Thread *p); // Return the ID of the specified SAGA thread ThreadID getThreadID(Thread *thread); // Return a pointer to a SAGA thread, given a thread ID Thread *getThreadAddress(ThreadID id); /* ===================================================================== * Class Thread: An execution context of a script * ===================================================================== */ // A script task is called a thread scriptResult runMethod( uint16 scriptClassID, // which script class int16 bType, // builtin type uint16 index, // object index uint16 methodNum, // method number to call scriptCallFrame &args); class Thread { friend char *STRING(int strNum); friend scriptResult runScript(uint16 exportEntryNum, scriptCallFrame &args); friend void wakeUpThread(ThreadID, int16); public: SegmentRef _programCounter; // current PC location uint8 *_stackPtr; // current stack location byte *_codeSeg; // base of current data segment // *_stringBase; // base of string resource uint8 *_stackBase; // base of module stack enum threadFlags { kTFWaiting = (1 << 0), // thread waiting for event kTFFinished = (1 << 1), // thread finished normally kTFAborted = (1 << 2), // thread is aborted kTFExtended = (1 << 3), // this is an extended sequence kTFExpectResult = (1 << 4), // script is expecting result on stack kTFSynchronous = (1 << 5), // when this bit is set this thread will // run until it is finished or this bit // is cleared kTFAsleep = (kTFWaiting | kTFFinished | kTFAborted) }; int16 _stackSize, // allocated size of stack _flags, // execution flags _framePtr, // pointer to call frame _returnVal; // return value from ccalls bool _valid; // Various signals that a script can wait upon enum WaitTypes { kWaitNone = 0, // waiting for nothing kWaitDelay, // waiting for a timer kWaitFrameDelay, // waiting for frame count kWaitOther, // waiting for to be awoken kWaitTagSemaphore // waiting for a tag semaphore // kWaitSpeech, // waiting for speech to finish // kWaitDialogEnd, // waiting for my dialog to finish // kWaitDialogBegin, // waiting for other dialog to finish // kWaitWalk, // waiting to finish walking // kWaitRequest, // a request is up }; WaitTypes _waitType; // what we're waiting for union { Alarm _waitAlarm; // for time-delay FrameAlarm _waitFrameAlarm; // for frame count delay ActiveItem *_waitParam; // for other waiting }; scriptCallFrame _threadArgs; // arguments from C to thread // For 'cfunc' member functions, the address of the object who's // member function is being invoked. void *_thisObject; uint16 _argCount; // number of args to cfunc // Constructor Thread(uint16 segNum, uint16 segOff, scriptCallFrame &args); // Constructor -- reconstruct from archive buffer Thread(void **buf); Thread(Common::SeekableReadStream *stream, ThreadID id); // Destructor ~Thread(); // Return the number of bytes need to archive this thread in an // arhive buffer int32 archiveSize(); // Create an archive of this thread in an archive buffer void *archive(void *buf); void write(Common::MemoryWriteStreamDynamic *out); // Dispatch all asynchronous threads static void dispatch(); // Intepret a single thread scriptResult run(); // Tells thread to wait for an event void waitForEvent(WaitTypes wt, ActiveItem *param) { _flags |= kTFWaiting; _waitType = wt; _waitParam = param; } // Convert to extended script, and back to synchonous script void setExtended(); void clearExtended(); bool interpret(); private: uint8 *strAddress(int strNum); }; const int maxTimeSlice = 16, // max instructions per call kStackSize = 512; // thread stack size /* ============================================================================ * C-Function dispatch table * ============================================================================ */ typedef int16 C_Call(int16 *); struct CallTable { C_Call **table; uint16 numEntries; uint16 classID; }; extern CallTable globalCFuncs, actorCFuncs, tagCFuncs, missionCFuncs; //extern C_Call *ccall_table[]; //extern int16 ccall_count; /* ===================================================================== * Externals * ===================================================================== */ extern Thread *thisThread; // task queue // Thread control //void killThread( Thread *th ); /* void wakeUpActorThread(WaitTypes wakeupType, void *obj); void wakeUpThreads(WaitTypes wakeupType); void wakeUpThreadsDelayed(WaitTypes wakeupType, int newdelay); void abortObjectThreads(Thread *keep, uint16 id); bool abortAllThreads(void); */ // Run a script function scriptResult runScript(uint16 exportEntryNum, scriptCallFrame &args); // Run a script class method. scriptResult runObjectMethod( ObjectID id, uint16 methodNum, scriptCallFrame &args); scriptResult runTagMethod( uint16 tagNum, uint16 methodNum, scriptCallFrame &args); struct ResImportTable { int16 deadActorProto, reserved[2]; int16 EXP_spellEffect_CreateFireWisp, EXP_spellEffect_CreateWindWisp, EXP_spellEffect_CreateWraith, EXP_spellEffect_TeleportToShrine, EXP_spellEffect_Rejoin, EXP_spellEffect_Timequake, EXP_spellEffect_CreateFood; }; extern ResImportTable *resImports; } // end of namespace Saga2 #endif