Updated Release Archive. Fixed Mage-killer prereqs. Removed old LETO & ConvoCC related files. Added organized spell scroll store. Fixed Gloura spellbook. Various TLK fixes. Reorganized Repo. Removed invalid user folders. Added DocGen back in.
406 lines
14 KiB
Plaintext
406 lines
14 KiB
Plaintext
//:://////////////////////////////////////////////
|
|
//:: Thread include
|
|
//:: inc_threads
|
|
//:://////////////////////////////////////////////
|
|
/** @file
|
|
A simple set of functions for creating,
|
|
controlling and destroying threads that
|
|
repeatedly run a given script.
|
|
A thread is implemented as a pseudo-hb that
|
|
executes a given script on each of it's
|
|
beats.
|
|
|
|
Threads may be in one of 3 states:
|
|
THREAD_STATE_DEAD:
|
|
Equivalent to the thread not existing at
|
|
all.
|
|
|
|
THREAD_STATE_RUNNING:
|
|
The thread is alive, and will execute it's
|
|
script on each of the underlying pseudo-hb's
|
|
beats.
|
|
|
|
THREAD_STATE_SLEEPING:
|
|
The thread is alive, but will not execute
|
|
it's script on the pseudo-hb's beats.
|
|
|
|
|
|
The thread's script will be ExecuteScripted on
|
|
the object that the thread is running on. This
|
|
is the same object that also stores the
|
|
thread's state (all of 3 local variables).
|
|
|
|
|
|
@author Ornedan
|
|
@date Created - 14.03.2005
|
|
*/
|
|
//:://////////////////////////////////////////////
|
|
//:://////////////////////////////////////////////
|
|
|
|
|
|
//////////////////////////////////////////////////
|
|
/* Constant declarations */
|
|
//////////////////////////////////////////////////
|
|
|
|
// Thread state constants
|
|
|
|
/// Thread state - Dead or non-existent
|
|
const int THREAD_STATE_DEAD = 0;
|
|
/// Thread state - Running at the moment
|
|
const int THREAD_STATE_RUNNING = 1;
|
|
/// Thread state - Sleeping
|
|
const int THREAD_STATE_SLEEPING = 2;
|
|
|
|
|
|
// Internal constants. Nothing to see here. <.< >.>
|
|
|
|
const string PREFIX = "prc_thread_";
|
|
const string SUFFIX_SCRIPT = "_script";
|
|
const string SUFFIX_INTERVAL = "_interval";
|
|
const string SUFFIX_ITERATION = "_iteration";
|
|
const string CUR_THREAD = "current_thread";
|
|
|
|
|
|
//////////////////////////////////////////////////
|
|
/* Function prototypes */
|
|
//////////////////////////////////////////////////
|
|
|
|
/**
|
|
* Creates a new thread.
|
|
*
|
|
* @param sName Name of thread to create. Must be non-empty
|
|
* @param sScript Name of script to run. Must be non-empty
|
|
* @param fExecutionInterval Amount of time that passes between executions of sScript.
|
|
* Only values > 0.0 allowed
|
|
* @param oToRunOn Object that stores the thread state values, and that
|
|
* sScript will be ExecuteScripted on.
|
|
* If this is OBJECT_INVALID, the module will be used to hold
|
|
* the thread
|
|
*
|
|
* @return TRUE if the thread creation was successfull. Possible reasons of failure:
|
|
* - One or more parameters were invalid
|
|
* - A thread by the given name was already running on oToRunOn
|
|
*/
|
|
int SpawnNewThread(string sName, string sScript, float fExecutionInterval = 6.0f, object oToRunOn = OBJECT_INVALID);
|
|
|
|
/**
|
|
* Inspects the state of the given thread.
|
|
*
|
|
* @param sName Name of thread to inspect. Must be non-empty
|
|
* @param oRunningOn Object that the thread is running on. If this
|
|
* is OBJECT_INVALID, the module will be used.
|
|
*
|
|
* @return One of the THREAD_STATE_* constants. Inspecting a non-
|
|
* existent thread, or thread that was running on an object that
|
|
* was destroyed will return THREAD_STATE_DEAD
|
|
*/
|
|
int GetThreadState(string sName, object oRunningOn = OBJECT_INVALID);
|
|
|
|
/**
|
|
* Gets the name of the script the given thread is running.
|
|
*
|
|
* @param sName Name of thread to inspect. Must be non-empty
|
|
* @param oRunningOn Object that the thread is running on. If this
|
|
* is OBJECT_INVALID, the module will be used.
|
|
*
|
|
* @return The name of the the given thread executes on success, ""
|
|
* on failure (querying with invalid parameters, or on a dead thread)
|
|
*/
|
|
string GetThreadScript(string sName, object oRunningOn = OBJECT_INVALID);
|
|
|
|
/** Gets the execution interval for the given thread
|
|
*
|
|
* @param sName Name of thread to inspect. Must be non-empty
|
|
* @param oRunningOn Object that the thread is running on. If this
|
|
* is OBJECT_INVALID, the module will be used.
|
|
*
|
|
* @return The time between the given thread executing it's script.
|
|
* On failure, 0.0f is returned.
|
|
*/
|
|
float GetThreadExecutionInterval(string sName, object oRunningOn = OBJECT_INVALID);
|
|
|
|
/**
|
|
* Gets the name of the thread whose script is currently being executed.
|
|
*
|
|
* @return The name of the thread being executed at the time of the call,
|
|
* or "" if no thread is being executed when this is called.
|
|
*/
|
|
string GetCurrentThread();
|
|
|
|
/**
|
|
* Gets the object currently running thread is executing on
|
|
*
|
|
* @return The object the currently executing thread is being executed on
|
|
* or OBJECT_INVALID if no thread is being executed when this is called.
|
|
*/
|
|
object GetCurrentThreadObject();
|
|
|
|
/**
|
|
* Stops further execution of the given thread and removes it's data
|
|
* from the object it was running on.
|
|
*
|
|
* @param sName Name of thread to terminate. Must be non-empty
|
|
* @param oRunningOn Object that the thread is running on. If this
|
|
* is OBJECT_INVALID, the module will be used.
|
|
*/
|
|
void TerminateThread(string sName, object oRunningOn = OBJECT_INVALID);
|
|
|
|
/**
|
|
* Stops further execution of the thread currently being executed.
|
|
* A convenience wrapper for TerminateThread to be called from a
|
|
* threadscript.
|
|
*/
|
|
void TerminateCurrentThread();
|
|
|
|
/**
|
|
* Sets the stae of the given thread to sleeping.
|
|
*
|
|
* @param sName Name of thread to set sleeping. Must be non-empty
|
|
* @param oRunningOn Object that the thread is running on. If this
|
|
* is OBJECT_INVALID, the module will be used.
|
|
*
|
|
* @return Whether the operation was successfull. Failure indicates
|
|
* that the thread was dead.
|
|
*/
|
|
int SleepThread(string sName, object oRunningOn = OBJECT_INVALID);
|
|
|
|
/**
|
|
* Awakens the given thread.
|
|
*
|
|
* @param sName Name of thread to set back running. Must be non-empty
|
|
* @param oRunningOn Object that the thread is running on. If this
|
|
* is OBJECT_INVALID, the module will be used.
|
|
*
|
|
* @return Whether the operation was successfull. Failure indicates
|
|
* that the thread was dead.
|
|
*/
|
|
int AwakenThread(string sName, object oRunningOn = OBJECT_INVALID);
|
|
|
|
/**
|
|
* Changes the execution interval of the given thread.
|
|
*
|
|
* @param sName Name of thread to set back running. Must be non-empty
|
|
* @param oRunningOn Object that the thread is running on. If this
|
|
* is OBJECT_INVALID, the module will be used.
|
|
* @param fNewInterval The amount of time between executions of the
|
|
* threadscript that will used from next execution
|
|
* onwards.
|
|
*
|
|
* @return Returns whether the operation was successfull. Failure indicates
|
|
* that the thread was dead.
|
|
*/
|
|
int ChangeExecutionInterval(string sName, float fNewInterval, object oRunningOn = OBJECT_INVALID);
|
|
|
|
/*
|
|
* Internal function. This is the pseudo-hb function that calls itself.
|
|
*
|
|
* @param sName name of the thread to run. Used to build local variable names
|
|
* @param oRunningOn object that stores the variables, and the one that will
|
|
* be passed to ExecuteScript
|
|
*/
|
|
void RunThread(string sName, object oRunningOn, int iIteration);
|
|
|
|
|
|
//////////////////////////////////////////////////
|
|
/* Function defintions */
|
|
//////////////////////////////////////////////////
|
|
|
|
|
|
int SpawnNewThread(string sName, string sScript, float fExecutionInterval = 6.0f, object oToRunOn = OBJECT_INVALID){
|
|
if(oToRunOn == OBJECT_INVALID)
|
|
oToRunOn = GetModule();
|
|
|
|
// Check paramaeters for correctness
|
|
if(sName == "" ||
|
|
sScript == "" ||
|
|
fExecutionInterval <= 0.0f ||
|
|
!GetIsObjectValid(oToRunOn))
|
|
return FALSE;
|
|
|
|
// Make sure there is no thread by this name already running
|
|
// if(GetLocalInt(oToRunOn, PREFIX + sName))
|
|
// return FALSE;
|
|
// use iterations in place of the above to make it more reliable in case of a PC thread timing out while not logged in
|
|
int iIteration = GetLocalInt(oToRunOn, PREFIX + sName + SUFFIX_ITERATION);
|
|
|
|
// Set the thread variables
|
|
SetLocalInt(oToRunOn, PREFIX + sName, THREAD_STATE_RUNNING);
|
|
SetLocalString(oToRunOn, PREFIX + sName + SUFFIX_SCRIPT, sScript);
|
|
SetLocalFloat(oToRunOn, PREFIX + sName + SUFFIX_INTERVAL, fExecutionInterval);
|
|
|
|
// Start thread execution
|
|
DelayCommand(fExecutionInterval, RunThread(sName, oToRunOn, iIteration));
|
|
|
|
// All done successfully
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
int GetThreadState(string sName, object oRunningOn = OBJECT_INVALID){
|
|
if(oRunningOn == OBJECT_INVALID)
|
|
oRunningOn = GetModule();
|
|
|
|
// Check paramaeters for correctness
|
|
if(sName == "" ||
|
|
!GetIsObjectValid(oRunningOn))
|
|
return FALSE;
|
|
|
|
// Return the local determining if the thread exists
|
|
return GetLocalInt(oRunningOn, PREFIX + sName);
|
|
}
|
|
|
|
|
|
string GetThreadScript(string sName, object oRunningOn = OBJECT_INVALID){
|
|
if(oRunningOn == OBJECT_INVALID)
|
|
oRunningOn = GetModule();
|
|
|
|
// Check paramaeters for correctness
|
|
if(sName == "" ||
|
|
!GetIsObjectValid(oRunningOn))
|
|
return "";
|
|
|
|
return GetLocalString(oRunningOn, PREFIX + sName + SUFFIX_SCRIPT);
|
|
}
|
|
|
|
|
|
float GetThreadExecutionInterval(string sName, object oRunningOn = OBJECT_INVALID){
|
|
if(oRunningOn == OBJECT_INVALID)
|
|
oRunningOn = GetModule();
|
|
|
|
// Check paramaeters for correctness
|
|
if(sName == "" ||
|
|
!GetIsObjectValid(oRunningOn))
|
|
return 0.0f;
|
|
|
|
return GetLocalFloat(oRunningOn, PREFIX + sName + SUFFIX_INTERVAL);
|
|
}
|
|
|
|
|
|
string GetCurrentThread(){
|
|
return GetLocalString(GetModule(), PREFIX + CUR_THREAD);
|
|
}
|
|
|
|
|
|
object GetCurrentThreadObject(){
|
|
return GetIsObjectValid(GetLocalObject(GetModule(), PREFIX + CUR_THREAD)) ?
|
|
GetLocalObject(GetModule(), PREFIX + CUR_THREAD) :
|
|
OBJECT_INVALID;
|
|
}
|
|
|
|
|
|
void TerminateThread(string sName, object oRunningOn = OBJECT_INVALID){
|
|
if(oRunningOn == OBJECT_INVALID)
|
|
oRunningOn = GetModule();
|
|
|
|
// Check paramaeters for correctness. Just an optimization here, since
|
|
// if either of these were not valid, nothing would happen.
|
|
if(sName == "" ||
|
|
!GetIsObjectValid(oRunningOn))
|
|
return;
|
|
|
|
// Remove the thread variables
|
|
DeleteLocalInt(oRunningOn, PREFIX + sName);
|
|
DeleteLocalString(oRunningOn, PREFIX + sName + SUFFIX_SCRIPT);
|
|
DeleteLocalFloat(oRunningOn, PREFIX + sName + SUFFIX_INTERVAL);
|
|
|
|
// Increase the iteration so that any lingering runthread fail to fire if the thread is restarted
|
|
int iExpectedIteration = GetLocalInt(oRunningOn, PREFIX + sName + SUFFIX_ITERATION);
|
|
iExpectedIteration++;
|
|
SetLocalInt(oRunningOn, PREFIX + sName + SUFFIX_ITERATION, iExpectedIteration);
|
|
}
|
|
|
|
|
|
void TerminateCurrentThread(){
|
|
TerminateThread(GetLocalString(GetModule(), PREFIX + CUR_THREAD),
|
|
GetLocalObject(GetModule(), PREFIX + CUR_THREAD)
|
|
);
|
|
}
|
|
|
|
|
|
int SleepThread(string sName, object oRunningOn = OBJECT_INVALID){
|
|
if(oRunningOn == OBJECT_INVALID)
|
|
oRunningOn = GetModule();
|
|
|
|
// Check paramaeters for correctness
|
|
if(sName == "" ||
|
|
!GetIsObjectValid(oRunningOn))
|
|
return FALSE;
|
|
|
|
// Change thread state
|
|
SetLocalInt(oRunningOn, PREFIX + sName, THREAD_STATE_SLEEPING);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
int AwakenThread(string sName, object oRunningOn = OBJECT_INVALID){
|
|
if(oRunningOn == OBJECT_INVALID)
|
|
oRunningOn = GetModule();
|
|
|
|
// Check paramaeters for correctness
|
|
if(sName == "" ||
|
|
!GetIsObjectValid(oRunningOn))
|
|
return FALSE;
|
|
|
|
// Change thread state
|
|
SetLocalInt(oRunningOn, PREFIX + sName, THREAD_STATE_RUNNING);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
int ChangeExecutionInterval(string sName, float fNewInterval, object oRunningOn = OBJECT_INVALID){
|
|
if(oRunningOn == OBJECT_INVALID)
|
|
oRunningOn = GetModule();
|
|
|
|
// Check paramaeters for correctness
|
|
if(!GetThreadState(sName, oRunningOn) ||
|
|
fNewInterval <= 0.0f)
|
|
return FALSE;
|
|
|
|
|
|
SetLocalFloat(oRunningOn, PREFIX + sName + SUFFIX_INTERVAL, fNewInterval);
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
void RunThread(string sName, object oRunningOn, int iIteration){
|
|
// Abort if we're on the wrong iteration, this allows us to
|
|
// be liberal about spawning threads in case they've timed
|
|
// out while a PC was logged out
|
|
int iExpectedIteration = GetLocalInt(oRunningOn, PREFIX + sName + SUFFIX_ITERATION);
|
|
if(iIteration != iExpectedIteration)
|
|
return;
|
|
iExpectedIteration++;
|
|
SetLocalInt(oRunningOn, PREFIX + sName + SUFFIX_ITERATION, iExpectedIteration);
|
|
|
|
// Abort if the object we're running on has ceased to exist
|
|
// or if the thread has been terminated
|
|
int nThreadState = GetThreadState(sName, oRunningOn);
|
|
if(nThreadState == THREAD_STATE_DEAD)
|
|
return;
|
|
|
|
// Mark this thread as running
|
|
SetLocalString(GetModule(), PREFIX + CUR_THREAD, sName);
|
|
SetLocalObject(GetModule(), PREFIX + CUR_THREAD, oRunningOn);
|
|
|
|
// Execute the threadscript if the thread is running atm
|
|
if(nThreadState == THREAD_STATE_RUNNING){
|
|
string sScript = GetLocalString(oRunningOn, PREFIX + sName + SUFFIX_SCRIPT);
|
|
ExecuteScript(sScript, oRunningOn);
|
|
}
|
|
|
|
// Schedule next execution, unless we've been terminated
|
|
if(GetThreadState(sName, oRunningOn) != THREAD_STATE_DEAD){
|
|
DelayCommand(GetLocalFloat(oRunningOn, PREFIX + sName + SUFFIX_INTERVAL), RunThread(sName, oRunningOn, iExpectedIteration));
|
|
}
|
|
|
|
// Clean up the module variables
|
|
DeleteLocalString(GetModule(), PREFIX + CUR_THREAD);
|
|
DeleteLocalObject(GetModule(), PREFIX + CUR_THREAD);
|
|
}
|
|
|
|
|
|
// Test main
|
|
//void main(){}
|