- Added support for loading named ACS scripts. You can't run them directly at the moment, but

you can still use them for automatically executed script types (like open and enter).
- Change the DACSThinker::RunningScripts array into a TMap so that it can catalog the new range
  of ACS scripts (up to 32767).


SVN r3359 (trunk)
This commit is contained in:
Randy Heit 2012-02-15 02:18:30 +00:00
parent ebd115e7ca
commit 9ffb4c40ac
2 changed files with 109 additions and 28 deletions

View file

@ -1544,6 +1544,27 @@ void FBehavior::LoadScriptsDirectory ()
} }
} }
} }
// Load script names (if any)
scripts.b = FindChunk(MAKE_ID('S','N','A','M'));
if (scripts.dw != NULL)
{
for (i = 0; i < NumScripts; ++i)
{
// ACC stores script names as an index into the SNAM chunk, with the first index as
// -1 and counting down from there. We convert this from an index into SNAM into
// a negative index into the global name table.
if (Scripts[i].Number < 0)
{
const char *str = (const char *)(scripts.b + 8 + scripts.dw[3 + (-Scripts[i].Number - 1)]);
FName name(str);
Scripts[i].Number = -name;
}
}
// We need to resort scripts, because the new numbers for named scripts likely
// do not match the order they were originally in.
qsort (Scripts, NumScripts, sizeof(ScriptPtr), SortScripts);
}
} }
int STACK_ARGS FBehavior::SortScripts (const void *a, const void *b) int STACK_ARGS FBehavior::SortScripts (const void *a, const void *b)
@ -1621,8 +1642,8 @@ bool FBehavior::IsGood ()
const ScriptPtr *FBehavior::FindScript (int script) const const ScriptPtr *FBehavior::FindScript (int script) const
{ {
const ScriptPtr *ptr = BinarySearch<ScriptPtr, WORD> const ScriptPtr *ptr = BinarySearch<ScriptPtr, int>
((ScriptPtr *)Scripts, NumScripts, &ScriptPtr::Number, (WORD)script); ((ScriptPtr *)Scripts, NumScripts, &ScriptPtr::Number, script);
// If the preceding script has the same number, return it instead. // If the preceding script has the same number, return it instead.
// See the note by the script sorting above for why. // See the note by the script sorting above for why.
@ -1859,6 +1880,50 @@ void FBehavior::StaticStopMyScripts (AActor *actor)
} }
} }
//==========================================================================
//
// SerializeScriptNumber
//
// Serializes a script number. If it's negative, it's really a name, so
// that will get serialized after it.
//
//==========================================================================
static void SerializeScriptNumber(FArchive &arc, int &scriptnum, bool was2byte)
{
if (SaveVersion < 3359)
{
if (was2byte)
{
WORD oldver;
arc << oldver;
scriptnum = oldver;
}
else
{
arc << scriptnum;
}
}
else
{
arc << scriptnum;
// If the script number is negative, then it's really a name.
// So read/store the name after it.
if (scriptnum < 0)
{
if (arc.IsStoring())
{
arc.WriteName(FName(ENamedName(-scriptnum)).GetChars());
}
else
{
const char *nam = arc.ReadName();
scriptnum = -FName(nam);
}
}
}
}
//---- The ACS Interpreter ----// //---- The ACS Interpreter ----//
IMPLEMENT_POINTY_CLASS (DACSThinker) IMPLEMENT_POINTY_CLASS (DACSThinker)
@ -1880,8 +1945,7 @@ DACSThinker::DACSThinker ()
ActiveThinker = this; ActiveThinker = this;
Scripts = NULL; Scripts = NULL;
LastScript = NULL; LastScript = NULL;
for (int i = 0; i < 1000; i++) RunningScripts.Clear();
RunningScripts[i] = NULL;
} }
} }
@ -1893,27 +1957,34 @@ DACSThinker::~DACSThinker ()
void DACSThinker::Serialize (FArchive &arc) void DACSThinker::Serialize (FArchive &arc)
{ {
int scriptnum;
Super::Serialize (arc); Super::Serialize (arc);
arc << Scripts << LastScript; arc << Scripts << LastScript;
if (arc.IsStoring ()) if (arc.IsStoring ())
{ {
WORD i; ScriptMap::Iterator it(RunningScripts);
for (i = 0; i < 1000; i++) ScriptMap::Pair *pair;
while (it.NextPair(pair))
{ {
if (RunningScripts[i]) assert(pair->Value != NULL);
arc << RunningScripts[i] << i; arc << pair->Value;
scriptnum = pair->Key;
SerializeScriptNumber(arc, scriptnum, true);
} }
DLevelScript *nilptr = NULL; DLevelScript *nilptr = NULL;
arc << nilptr; arc << nilptr;
} }
else else // Loading
{ {
WORD scriptnum;
DLevelScript *script = NULL; DLevelScript *script = NULL;
RunningScripts.Clear();
arc << script; arc << script;
while (script) while (script)
{ {
arc << scriptnum; SerializeScriptNumber(arc, scriptnum, true);
RunningScripts[scriptnum] = script; RunningScripts[scriptnum] = script;
arc << script; arc << script;
} }
@ -1975,8 +2046,9 @@ void DLevelScript::Serialize (FArchive &arc)
DWORD i; DWORD i;
Super::Serialize (arc); Super::Serialize (arc);
arc << next << prev arc << next << prev;
<< script;
SerializeScriptNumber(arc, script, false);
arc << state arc << state
<< statedata << statedata
@ -3713,13 +3785,13 @@ int DLevelScript::RunScript ()
case SCRIPT_ScriptWaitPre: case SCRIPT_ScriptWaitPre:
// Wait for a script to start running, then enter state scriptwait // Wait for a script to start running, then enter state scriptwait
if (controller->RunningScripts[statedata]) if (controller->RunningScripts.CheckKey(statedata) != NULL)
state = SCRIPT_ScriptWait; state = SCRIPT_ScriptWait;
break; break;
case SCRIPT_ScriptWait: case SCRIPT_ScriptWait:
// Wait for a script to stop running, then enter state running // Wait for a script to stop running, then enter state running
if (controller->RunningScripts[statedata]) if (controller->RunningScripts.CheckKey(statedata) != NULL)
return resultValue; return resultValue;
state = SCRIPT_Running; state = SCRIPT_Running;
@ -5016,7 +5088,7 @@ int DLevelScript::RunScript ()
case PCD_SCRIPTWAIT: case PCD_SCRIPTWAIT:
statedata = STACK(1); statedata = STACK(1);
if (controller->RunningScripts[statedata]) if (controller->RunningScripts.CheckKey(statedata) != NULL)
state = SCRIPT_ScriptWait; state = SCRIPT_ScriptWait;
else else
state = SCRIPT_ScriptWaitPre; state = SCRIPT_ScriptWaitPre;
@ -6960,8 +7032,12 @@ int DLevelScript::RunScript ()
if (state == SCRIPT_PleaseRemove) if (state == SCRIPT_PleaseRemove)
{ {
Unlink (); Unlink ();
if (controller->RunningScripts[script] == this) DLevelScript **running;
controller->RunningScripts[script] = NULL; if ((running = controller->RunningScripts.CheckKey(script)) != NULL &&
*running == this)
{
controller->RunningScripts.Remove(script);
}
} }
else else
{ {
@ -6977,13 +7053,14 @@ static DLevelScript *P_GetScriptGoing (AActor *who, line_t *where, int num, cons
bool backSide, int arg0, int arg1, int arg2, int always) bool backSide, int arg0, int arg1, int arg2, int always)
{ {
DACSThinker *controller = DACSThinker::ActiveThinker; DACSThinker *controller = DACSThinker::ActiveThinker;
DLevelScript **running;
if (controller && !always && controller->RunningScripts[num]) if (controller && !always && (running = controller->RunningScripts.CheckKey(num)) != NULL)
{ {
if (controller->RunningScripts[num]->GetState () == DLevelScript::SCRIPT_Suspended) if ((*running)->GetState() == DLevelScript::SCRIPT_Suspended)
{ {
controller->RunningScripts[num]->SetState (DLevelScript::SCRIPT_Running); (*running)->SetState(DLevelScript::SCRIPT_Running);
return controller->RunningScripts[num]; return *running;
} }
return NULL; return NULL;
} }
@ -7044,9 +7121,12 @@ DLevelScript::DLevelScript (AActor *who, line_t *where, int num, const ScriptPtr
static void SetScriptState (int script, DLevelScript::EScriptState state) static void SetScriptState (int script, DLevelScript::EScriptState state)
{ {
DACSThinker *controller = DACSThinker::ActiveThinker; DACSThinker *controller = DACSThinker::ActiveThinker;
DLevelScript **running;
if (controller != NULL && controller->RunningScripts[script]) if (controller != NULL && (running = controller->RunningScripts.CheckKey(script)) != NULL)
controller->RunningScripts[script]->SetState (state); {
(*running)->SetState (state);
}
} }
void P_DoDeferedScripts () void P_DoDeferedScripts ()

View file

@ -76,18 +76,18 @@ void P_ClearACSVars(bool);
// The in-memory version // The in-memory version
struct ScriptPtr struct ScriptPtr
{ {
WORD Number; int Number;
DWORD Address;
BYTE Type; BYTE Type;
BYTE ArgCount; BYTE ArgCount;
WORD VarCount; WORD VarCount;
WORD Flags; WORD Flags;
DWORD Address;
}; };
// The present ZDoom version // The present ZDoom version
struct ScriptPtr3 struct ScriptPtr3
{ {
WORD Number; SWORD Number;
BYTE Type; BYTE Type;
BYTE ArgCount; BYTE ArgCount;
DWORD Address; DWORD Address;
@ -747,7 +747,8 @@ public:
void Serialize (FArchive &arc); void Serialize (FArchive &arc);
void Tick (); void Tick ();
DLevelScript *RunningScripts[1000]; // Array of all synchronous scripts typedef TMap<int, DLevelScript *> ScriptMap;
ScriptMap RunningScripts; // Array of all synchronous scripts
static TObjPtr<DACSThinker> ActiveThinker; static TObjPtr<DACSThinker> ActiveThinker;
void DumpScriptStatus(); void DumpScriptStatus();