mirror of
https://github.com/JezuzLizard/T4SP-Server-Plugin.git
synced 2025-04-20 21:45:43 +00:00
4255 lines
129 KiB
C++
4255 lines
129 KiB
C++
#include <stdinc.hpp>
|
|
#include "clientscript_public.hpp"
|
|
|
|
#pragma warning(push)
|
|
#pragma warning(disable: 4244)
|
|
|
|
namespace codsrc
|
|
{
|
|
// Decomp Status: Completed
|
|
int ThreadInfoCompare(const void* a1, const void* a2)
|
|
{
|
|
const char* pos1;
|
|
int i;
|
|
const char* pos2;
|
|
game::ThreadDebugInfo* info1, * info2;
|
|
info1 = (game::ThreadDebugInfo*)a1;
|
|
info2 = (game::ThreadDebugInfo*)a2;
|
|
|
|
for (i = 0; ; ++i)
|
|
{
|
|
if (i >= info1->posSize || i >= info2->posSize)
|
|
{
|
|
return info1->posSize - info2->posSize;
|
|
}
|
|
pos1 = info1->pos[i];
|
|
pos2 = info2->pos[i];
|
|
if (pos1 != pos2)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
return pos1 - pos2;
|
|
}
|
|
|
|
// Restored
|
|
unsigned int FindFirstSibling(game::scriptInstance_t inst, unsigned int id)
|
|
{
|
|
game::VariableValueInternal* entryValue;
|
|
|
|
entryValue = &game::gScrVarGlob[inst].parentVariables[id + 1];
|
|
|
|
assert((entryValue->w.status & VAR_STAT_MASK) != VAR_STAT_FREE);
|
|
|
|
assert(IsObject(entryValue));
|
|
|
|
return entryValue->nextSibling;
|
|
}
|
|
|
|
// Restored
|
|
unsigned int FindNextSibling(game::scriptInstance_t inst, unsigned int id)
|
|
{
|
|
unsigned int nextSibling;
|
|
game::VariableValueInternal* list;
|
|
unsigned int childId;
|
|
game::VariableValueInternal* entryValue;
|
|
game::VariableValueInternal* childValue;
|
|
|
|
list = game::gScrVarGlob[inst].childVariables;
|
|
entryValue = &list[id];
|
|
|
|
assert((entryValue->w.status & VAR_STAT_MASK) != VAR_STAT_FREE);
|
|
|
|
assert(!IsObject(entryValue));
|
|
|
|
nextSibling = entryValue->nextSibling;
|
|
|
|
if (!nextSibling)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
childId = list[nextSibling].hash.id;
|
|
|
|
assert((entryValue->w.status & VAR_STAT_MASK) != VAR_STAT_FREE);
|
|
|
|
childValue = &list[childId];
|
|
|
|
assert(!IsObject(childValue));
|
|
|
|
return childId;
|
|
}
|
|
|
|
// Decomp Status: Completed
|
|
void Scr_DumpScriptThreads(game::scriptInstance_t inst)
|
|
{
|
|
float objectUsage;
|
|
int j;
|
|
int ja;
|
|
unsigned int classnum;
|
|
const char* pos;
|
|
int info[32];
|
|
int infoIndex;
|
|
float infoArrayVarUsage;
|
|
float infoArrayEndonUsage;
|
|
const char* buf;
|
|
int size;
|
|
game::VariableValueInternal* entryValue;
|
|
game::ThreadDebugInfo* pInfo;
|
|
int num;
|
|
char type;
|
|
game::VariableUnion u;
|
|
int i;
|
|
game::VariableStackBuffer* stackBuf;
|
|
unsigned int entId;
|
|
game::ThreadDebugInfo* infoArray;
|
|
int count;
|
|
float endonUsage;
|
|
unsigned int id;
|
|
float varUsage;
|
|
|
|
num = 0;
|
|
for (id = 1;
|
|
id < VARIABLELIST_CHILD_SIZE - 1;
|
|
++id)
|
|
{
|
|
entryValue = &game::gScrVarGlob[inst].childVariables[id];
|
|
if ((entryValue->w.status & VAR_STAT_MASK) != VAR_STAT_FREE && (entryValue->w.status & VAR_MASK) == game::VAR_STACK)
|
|
{
|
|
++num;
|
|
}
|
|
}
|
|
|
|
if (num)
|
|
{
|
|
infoArray = (game::ThreadDebugInfo*)game::Z_TryVirtualAlloc(sizeof(game::ThreadDebugInfo) * num);
|
|
if (infoArray)
|
|
{
|
|
num = 0;
|
|
for (id = 1;
|
|
id < VARIABLELIST_CHILD_SIZE - 1;
|
|
++id)
|
|
{
|
|
entryValue = &game::gScrVarGlob[inst].childVariables[id];
|
|
if ((entryValue->w.status & VAR_STAT_MASK) != VAR_STAT_FREE && (entryValue->w.status & VAR_MASK) == game::VAR_STACK)
|
|
{
|
|
pInfo = &infoArray[num++];
|
|
infoIndex = 0;
|
|
stackBuf = entryValue->u.u.stackValue;
|
|
size = stackBuf->size;
|
|
pos = stackBuf->pos;
|
|
buf = stackBuf->buf;
|
|
|
|
while (size)
|
|
{
|
|
--size;
|
|
type = *buf++;
|
|
u.intValue = *(int*)buf;
|
|
buf += 4;
|
|
if (type == game::VAR_CODEPOS)
|
|
{
|
|
info[infoIndex++] = u.intValue;
|
|
}
|
|
}
|
|
|
|
info[infoIndex++] = (int)pos;
|
|
pInfo->varUsage = game::Scr_GetThreadUsage(stackBuf, inst, &pInfo->endonUsage);
|
|
pInfo->posSize = infoIndex--;
|
|
|
|
for (j = 0;
|
|
j < pInfo->posSize;
|
|
++j)
|
|
{
|
|
pInfo->pos[j] = (const char*)info[infoIndex - j];
|
|
}
|
|
}
|
|
}
|
|
|
|
qsort(infoArray, num, sizeof(game::ThreadDebugInfo), game::ThreadInfoCompare);
|
|
game::Com_Printf(game::CON_CHANNEL_PARSERSCRIPT, "********************************\n");
|
|
varUsage = 0.0f;
|
|
endonUsage = 0.0f;
|
|
i = 0;
|
|
|
|
while (i < num)
|
|
{
|
|
pInfo = &infoArray[i];
|
|
count = 0;
|
|
infoArrayVarUsage = 0.0f;
|
|
infoArrayEndonUsage = 0.0f;
|
|
|
|
do
|
|
{
|
|
++count;
|
|
infoArrayVarUsage = infoArrayVarUsage + infoArray[i].varUsage;
|
|
infoArrayEndonUsage = infoArrayEndonUsage + infoArray[i++].endonUsage;
|
|
} while (i < num && !game::ThreadInfoCompare(pInfo, &infoArray[i]));
|
|
|
|
varUsage = varUsage + infoArrayVarUsage;
|
|
endonUsage = endonUsage + infoArrayEndonUsage;
|
|
game::Com_Printf(game::CON_CHANNEL_PARSERSCRIPT, "count: %d, var usage: %d, endon usage: %d\n", count, (int)infoArrayVarUsage, (int)infoArrayEndonUsage);
|
|
game::Scr_PrintPrevCodePos(pInfo->pos[0], inst, game::CON_CHANNEL_PARSERSCRIPT, 0);
|
|
|
|
for (ja = 1;
|
|
ja < pInfo->posSize;
|
|
++ja)
|
|
{
|
|
game::Com_Printf(game::CON_CHANNEL_PARSERSCRIPT, "called from:\n");
|
|
game::Scr_PrintPrevCodePos(pInfo->pos[ja], inst, game::CON_CHANNEL_PARSERSCRIPT, 0);
|
|
}
|
|
}
|
|
|
|
VirtualFree(infoArray, 0, 0x8000u); // Z_VirtualFree Z_VirtualFreeInternal
|
|
game::Com_Printf(game::CON_CHANNEL_PARSERSCRIPT, "********************************\n");
|
|
game::Com_Printf(game::CON_CHANNEL_PARSERSCRIPT, "var usage: %d, endon usage: %d\n", (int)varUsage, (int)endonUsage);
|
|
game::Com_Printf(game::CON_CHANNEL_PARSERSCRIPT, "\n");
|
|
|
|
for (classnum = 0;
|
|
classnum < game::CLASS_NUM_COUNT;
|
|
++classnum)
|
|
{
|
|
if (game::gScrClassMap[inst][classnum].entArrayId)
|
|
{
|
|
infoArrayVarUsage = 0.0f;
|
|
count = 0;
|
|
for (entId = game::FindFirstSibling(inst, game::gScrClassMap[inst][classnum].entArrayId);
|
|
entId;
|
|
entId = game::FindNextSibling(inst, entId))
|
|
{
|
|
++count;
|
|
if ((game::gScrVarGlob[inst].childVariables[entId].w.status & VAR_MASK) == game::VAR_POINTER)
|
|
{
|
|
objectUsage = game::Scr_GetObjectUsage(inst, game::gScrVarGlob[inst].childVariables[entId].u.u.intValue);
|
|
infoArrayVarUsage = objectUsage + infoArrayVarUsage;
|
|
}
|
|
}
|
|
|
|
game::Com_Printf(game::CON_CHANNEL_PARSERSCRIPT, "ent type '%s'... count: %d, var usage: %d\n", game::gScrClassMap[inst][classnum].name, count, (int)infoArrayVarUsage);
|
|
}
|
|
}
|
|
|
|
game::Com_Printf(game::CON_CHANNEL_PARSERSCRIPT, "********************************\n");
|
|
}
|
|
else
|
|
{
|
|
game::Com_Printf(game::CON_CHANNEL_PARSERSCRIPT, "Cannot dump script threads: out of memory\n");
|
|
}
|
|
}
|
|
}
|
|
|
|
// Decomp Status: Completed
|
|
void Scr_InitVariableRange(unsigned int begin, unsigned int end, game::scriptInstance_t inst)
|
|
{
|
|
unsigned int index;
|
|
game::VariableValueInternal* value;
|
|
game::VariableValueInternal* valuea;
|
|
|
|
for (index = begin + 1;
|
|
index < end;
|
|
++index)
|
|
{
|
|
value = &game::gScrVarGlob[inst].parentVariables[index];
|
|
value->w.status = 0;
|
|
|
|
assert(!(value->w.type & VAR_MASK));
|
|
|
|
value->hash.id = index - begin;
|
|
value->v.next = index - begin;
|
|
value->u.next = index - begin + 1;
|
|
value->hash.u.prev = index - begin - 1;
|
|
}
|
|
|
|
valuea = &game::gScrVarGlob[inst].parentVariables[begin];
|
|
valuea->w.status = 0;
|
|
|
|
assert(!(valuea->w.type & VAR_MASK));
|
|
|
|
valuea->w.status = valuea->w.status;
|
|
valuea->hash.id = 0;
|
|
valuea->v.next = 0;
|
|
valuea->u.next = 1;
|
|
game::gScrVarGlob[inst].parentVariables[begin + 1].hash.u.prev = 0;
|
|
valuea->hash.u.prev = end - begin - 1;
|
|
game::gScrVarGlob[inst].parentVariables[end - 1].u.next = 0;
|
|
}
|
|
|
|
// Decomp Status: Completed
|
|
void Scr_InitClassMap(game::scriptInstance_t inst)
|
|
{
|
|
game::gScrClassMap[inst][game::CLASS_NUM_ENTITY].entArrayId = 0;
|
|
game::gScrClassMap[inst][game::CLASS_NUM_ENTITY].id = 0;
|
|
game::gScrClassMap[inst][game::CLASS_NUM_HUDELEM].entArrayId = 0;
|
|
game::gScrClassMap[inst][game::CLASS_NUM_HUDELEM].id = 0;
|
|
game::gScrClassMap[inst][game::CLASS_NUM_PATHNODE].entArrayId = 0;
|
|
game::gScrClassMap[inst][game::CLASS_NUM_PATHNODE].id = 0;
|
|
game::gScrClassMap[inst][game::CLASS_NUM_VEHICLENODE].entArrayId = 0;
|
|
game::gScrClassMap[inst][game::CLASS_NUM_VEHICLENODE].id = 0;
|
|
}
|
|
|
|
// Restored
|
|
game::VariableValue Scr_GetArrayIndexValue([[maybe_unused]] game::scriptInstance_t inst, unsigned int name)
|
|
{
|
|
game::VariableValue value;
|
|
|
|
assert(name);
|
|
|
|
if (name >= SL_MAX_STRING_INDEX)
|
|
{
|
|
if (name >= OBJECT_STACK)
|
|
{
|
|
value.type = game::VAR_INTEGER;
|
|
value.u.intValue = name - 0x800000;
|
|
}
|
|
else
|
|
{
|
|
value.type = game::VAR_POINTER;
|
|
value.u.intValue = name - SL_MAX_STRING_INDEX;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
value.type = game::VAR_STRING;
|
|
value.u.intValue = (unsigned short)name;
|
|
}
|
|
|
|
return value;
|
|
}
|
|
|
|
// Decomp Status: Completed
|
|
unsigned int GetNewVariableIndexInternal3(game::scriptInstance_t inst, unsigned int parentId, unsigned int name, unsigned int index)
|
|
{
|
|
game::VariableValueInternal* parentValue;
|
|
game::VariableValueInternal* entry;
|
|
unsigned int newIndex;
|
|
unsigned int newIndexb;
|
|
unsigned int newIndexa;
|
|
unsigned int prevId;
|
|
unsigned int nextSiblingIndex;
|
|
unsigned int prevSiblingIndex;
|
|
unsigned int next;
|
|
unsigned int nexta;
|
|
unsigned int nextb;
|
|
unsigned int nextc;
|
|
unsigned int nextd;
|
|
game::VariableValueInternal* entryValue;
|
|
unsigned int prev;
|
|
unsigned int preva;
|
|
unsigned int prevb;
|
|
game::VariableValueInternal* newEntryValue;
|
|
int type;
|
|
game::VariableValueInternal* newEntrya;
|
|
game::VariableValueInternal* newEntry;
|
|
game::VariableValue value;
|
|
unsigned int id;
|
|
|
|
assert((name & VAR_NAME_LOW_MASK) == 0);
|
|
|
|
entry = &game::gScrVarGlob[inst].childVariables[index];
|
|
entryValue = &game::gScrVarGlob[inst].childVariables[entry->hash.id];
|
|
type = entryValue->w.status & VAR_STAT_MASK;
|
|
if (type)
|
|
{
|
|
if (type == VAR_STAT_HEAD)
|
|
{
|
|
if ((entry->w.status & VAR_STAT_MASK) != VAR_STAT_FREE)
|
|
{
|
|
index = game::gScrVarGlob[inst].childVariables[0].u.next;
|
|
if (!index)
|
|
{
|
|
game::Scr_TerminalError(inst, "exceeded maximum number of script variables");
|
|
}
|
|
|
|
entry = &game::gScrVarGlob[inst].childVariables[index];
|
|
newEntryValue = &game::gScrVarGlob[inst].childVariables[entry->hash.id];
|
|
|
|
assert((newEntryValue->w.status & VAR_STAT_MASK) == VAR_STAT_FREE);
|
|
|
|
nextb = newEntryValue->u.next;
|
|
game::gScrVarGlob[inst].childVariables[0].u.next = nextb;
|
|
game::gScrVarGlob[inst].childVariables[nextb].hash.u.prev = 0;
|
|
newEntryValue->w.status = VAR_STAT_MOVABLE;
|
|
newEntryValue->v.next = entryValue->v.next;
|
|
entryValue->v.next = index;
|
|
}
|
|
else
|
|
{
|
|
newIndexb = entry->v.next;
|
|
newEntrya = &game::gScrVarGlob[inst].childVariables[newIndexb];
|
|
newEntryValue = &game::gScrVarGlob[inst].childVariables[index];
|
|
preva = newEntrya->hash.u.prev;
|
|
nexta = entry->u.next;
|
|
game::gScrVarGlob[inst].childVariables[game::gScrVarGlob[inst].childVariables[preva].hash.id].u.next = nexta;
|
|
game::gScrVarGlob[inst].childVariables[nexta].hash.u.prev = preva;
|
|
newEntrya->hash.id = entry->hash.id;
|
|
entry->hash.id = index;
|
|
newEntrya->hash.u.prev = entry->hash.u.prev;
|
|
game::gScrVarGlob[inst].childVariables[game::gScrVarGlob[inst].childVariables[newEntrya->hash.u.prev].hash.id].nextSibling = newIndexb;
|
|
game::gScrVarGlob[inst].childVariables[entryValue->nextSibling].hash.u.prev = newIndexb;
|
|
entryValue->w.status = entryValue->w.status & ~VAR_STAT_HEAD | VAR_STAT_MOVABLE;
|
|
entry->w.status = VAR_STAT_HEAD;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
assert(type == VAR_STAT_MOVABLE || type == VAR_STAT_EXTERNAL);
|
|
|
|
if ((entry->w.status & VAR_STAT_MASK) != VAR_STAT_FREE)
|
|
{
|
|
newIndexa = game::gScrVarGlob[inst].childVariables[0].u.next;
|
|
if (!newIndexa)
|
|
{
|
|
game::Scr_TerminalError(inst, "exceeded maximum number of script variables");
|
|
}
|
|
|
|
newEntry = &game::gScrVarGlob[inst].childVariables[newIndexa];
|
|
newEntryValue = &game::gScrVarGlob[inst].childVariables[newEntry->hash.id];
|
|
|
|
assert((newEntryValue->w.status & VAR_STAT_MASK) == VAR_STAT_FREE);
|
|
|
|
nextd = newEntryValue->u.next;
|
|
game::gScrVarGlob[inst].childVariables[0].u.next = nextd;
|
|
game::gScrVarGlob[inst].childVariables[nextd].hash.u.prev = 0;
|
|
}
|
|
else
|
|
{
|
|
assert(entry != entryValue);
|
|
|
|
newIndexa = entry->v.next;
|
|
newEntry = &game::gScrVarGlob[inst].childVariables[newIndexa];
|
|
newEntryValue = entry;
|
|
prevb = newEntry->hash.u.prev;
|
|
nextc = entry->u.next;
|
|
game::gScrVarGlob[inst].childVariables[game::gScrVarGlob[inst].childVariables[prevb].hash.id].u.next = nextc;
|
|
game::gScrVarGlob[inst].childVariables[nextc].hash.u.prev = prevb;
|
|
}
|
|
|
|
prevSiblingIndex = entry->hash.u.prev;
|
|
if (prevSiblingIndex)
|
|
{
|
|
game::gScrVarGlob[inst].childVariables[game::gScrVarGlob[inst].childVariables[prevSiblingIndex].hash.id].nextSibling = newIndexa;
|
|
}
|
|
|
|
nextSiblingIndex = entryValue->nextSibling;
|
|
if (nextSiblingIndex)
|
|
{
|
|
game::gScrVarGlob[inst].childVariables[nextSiblingIndex].hash.u.prev = newIndexa;
|
|
}
|
|
|
|
if (type == VAR_STAT_MOVABLE)
|
|
{
|
|
prevId = game::gScrVarGlob[inst].childVariables[entryValue->v.next].hash.id;
|
|
|
|
assert((game::gScrVarGlob[inst].childVariables[prevId].w.status & VAR_STAT_MASK) == VAR_STAT_MOVABLE ||
|
|
(game::gScrVarGlob[inst].childVariables[prevId].w.status & VAR_STAT_MASK) == VAR_STAT_HEAD);
|
|
|
|
while (game::gScrVarGlob[inst].childVariables[prevId].v.next != index)
|
|
{
|
|
prevId = game::gScrVarGlob[inst].childVariables[game::gScrVarGlob[inst].childVariables[prevId].v.next].hash.id;
|
|
|
|
assert((game::gScrVarGlob[inst].childVariables[prevId].w.status & VAR_STAT_MASK) == VAR_STAT_MOVABLE ||
|
|
(game::gScrVarGlob[inst].childVariables[prevId].w.status & VAR_STAT_MASK) == VAR_STAT_HEAD);
|
|
}
|
|
|
|
game::gScrVarGlob[inst].childVariables[prevId].v.next = newIndexa;
|
|
}
|
|
else
|
|
{
|
|
assert(type == VAR_STAT_EXTERNAL);
|
|
|
|
entryValue->v.next = newIndexa;
|
|
}
|
|
|
|
newEntry->hash.u.prev = entry->hash.u.prev;
|
|
id = newEntry->hash.id;
|
|
newEntry->hash.id = entry->hash.id;
|
|
entry->hash.id = id;
|
|
newEntryValue->w.status = VAR_STAT_HEAD;
|
|
newEntryValue->v.next = index;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
newIndex = entry->v.next;
|
|
next = entryValue->u.next;
|
|
if (newIndex == entry->hash.id || (entry->w.status & VAR_STAT_MASK) != VAR_STAT_FREE)
|
|
{
|
|
newEntryValue = &game::gScrVarGlob[inst].childVariables[entry->hash.id];
|
|
}
|
|
else
|
|
{
|
|
game::gScrVarGlob[inst].childVariables[newIndex].hash.id = entry->hash.id;
|
|
entry->hash.id = index;
|
|
entryValue->v.next = newIndex;
|
|
entryValue->u.next = entry->u.next;
|
|
newEntryValue = entry;
|
|
}
|
|
|
|
prev = entry->hash.u.prev;
|
|
|
|
if (game::gScrVarGlob[inst].childVariables[prev].hash.id)
|
|
{
|
|
if ((game::gScrVarGlob[inst].childVariables[game::gScrVarGlob[inst].childVariables[prev].hash.id].w.status & VAR_STAT_MASK) != VAR_STAT_FREE)
|
|
{
|
|
//v4 = va(
|
|
// "%d, %d, %d",
|
|
// prev,
|
|
// gScrVarGlob[inst].variableList[prev + 0x8000].hash.id,
|
|
// gScrVarGlob[inst].variableList[gScrVarGlob[inst].variableList[prev + 0x8000].hash.id + 0x8000].w.status & 0x60);
|
|
|
|
assert(!game::gScrVarGlob[inst].childVariables[prev].hash.id ||
|
|
(game::gScrVarGlob[inst].childVariables[game::gScrVarGlob[inst].childVariables[prev].hash.id].w.status & VAR_STAT_MASK) == VAR_STAT_FREE);
|
|
}
|
|
}
|
|
if (game::gScrVarGlob[inst].childVariables[next].hash.id)
|
|
{
|
|
if ((game::gScrVarGlob[inst].childVariables[game::gScrVarGlob[inst].childVariables[next].hash.id].w.status & VAR_STAT_MASK) != VAR_STAT_FREE)
|
|
{
|
|
//v5 = va(
|
|
// "%d, %d, %d",
|
|
// next,
|
|
// gScrVarGlob[inst].variableList[next + 0x8000].hash.id,
|
|
// gScrVarGlob[inst].variableList[gScrVarGlob[inst].variableList[next + 0x8000].hash.id + 0x8000].w.status & 0x60);
|
|
|
|
assert(!game::gScrVarGlob[inst].childVariables[next].hash.id ||
|
|
(game::gScrVarGlob[inst].childVariables[game::gScrVarGlob[inst].childVariables[next].hash.id].w.status & VAR_STAT_MASK) == VAR_STAT_FREE);
|
|
}
|
|
}
|
|
|
|
game::gScrVarGlob[inst].childVariables[game::gScrVarGlob[inst].childVariables[prev].hash.id].u.next = next;
|
|
game::gScrVarGlob[inst].childVariables[next].hash.u.prev = prev;
|
|
newEntryValue->w.status = VAR_STAT_HEAD;
|
|
newEntryValue->v.next = index;
|
|
}
|
|
|
|
assert(entry == &game::gScrVarGlob[inst].childVariables[index]);
|
|
|
|
assert(newEntryValue == &game::gScrVarGlob[inst].childVariables[entry->hash.id]);
|
|
|
|
assert((newEntryValue->w.type & VAR_MASK) == game::VAR_UNDEFINED);
|
|
|
|
newEntryValue->w.status = (name << VAR_NAME_BIT_SHIFT) | (unsigned char)newEntryValue->w.status;
|
|
|
|
assert((entry->hash.id > 0) && (entry->hash.id < VARIABLELIST_CHILD_SIZE));
|
|
|
|
parentValue = &game::gScrVarGlob[inst].parentVariables[parentId + 1];
|
|
|
|
assert((parentValue->w.status & VAR_STAT_MASK) == VAR_STAT_EXTERNAL);
|
|
|
|
assert((parentValue->w.status & VAR_STAT_MASK) != VAR_STAT_FREE);
|
|
|
|
assert(IsObject(parentValue));
|
|
|
|
if ((parentValue->w.status & VAR_MASK) != game::VAR_ARRAY)
|
|
{
|
|
return index;
|
|
}
|
|
|
|
++parentValue->u.o.u.size;
|
|
value = game::Scr_GetArrayIndexValue(inst, name);
|
|
game::AddRefToValue(inst, value.type, value.u);
|
|
return index;
|
|
}
|
|
|
|
// Decomp Status: Completed
|
|
unsigned int GetNewVariableIndexInternal2(unsigned int name, game::scriptInstance_t inst, unsigned int parentId, unsigned int index)
|
|
{
|
|
unsigned int siblingId;
|
|
game::VariableValueInternal* parentValue;
|
|
game::VariableValueInternal* entry;
|
|
game::VariableValueInternal* siblingValue;
|
|
unsigned int siblingIndex;
|
|
unsigned int id;
|
|
unsigned int indexa;
|
|
|
|
indexa = game::GetNewVariableIndexInternal3(inst, parentId, name, index);
|
|
parentValue = &game::gScrVarGlob[inst].parentVariables[parentId + 1];
|
|
|
|
assert(((parentValue->w.status & VAR_STAT_MASK) == VAR_STAT_EXTERNAL));
|
|
|
|
entry = &game::gScrVarGlob[inst].childVariables[indexa];
|
|
id = entry->hash.id;
|
|
siblingId = parentValue->nextSibling;
|
|
|
|
if (siblingId)
|
|
{
|
|
siblingValue = &game::gScrVarGlob[inst].childVariables[siblingId];
|
|
|
|
assert((siblingValue->w.status & VAR_STAT_MASK) != VAR_STAT_FREE);
|
|
|
|
assert(!IsObject(siblingValue));
|
|
|
|
siblingIndex = game::FindVariableIndexInternal(inst, parentId, siblingValue->w.status >> VAR_NAME_BIT_SHIFT);
|
|
|
|
assert(siblingIndex);
|
|
|
|
game::gScrVarGlob[inst].childVariables[siblingIndex].hash.u.prev = indexa;
|
|
}
|
|
else
|
|
{
|
|
siblingIndex = 0;
|
|
game::gScrVarGlob[inst].parentVariables[parentValue->v.next + 1].hash.u.prev = id;
|
|
}
|
|
|
|
parentValue->nextSibling = id;
|
|
entry->hash.u.prev = 0;
|
|
game::gScrVarGlob[inst].childVariables[id].nextSibling = siblingIndex;
|
|
return indexa;
|
|
}
|
|
|
|
// Decomp Status: Completed
|
|
unsigned int GetNewVariableIndexReverseInternal2(unsigned int name, game::scriptInstance_t inst, unsigned int parentId, unsigned int index)
|
|
{
|
|
game::VariableValueInternal* parentValue;
|
|
unsigned int siblingId;
|
|
game::VariableValueInternal* entry;
|
|
unsigned int siblingIndex;
|
|
game::VariableValueInternal* siblingValue;
|
|
game::VariableValueInternal* parent;
|
|
unsigned int id;
|
|
unsigned int indexa;
|
|
|
|
indexa = game::GetNewVariableIndexInternal3(inst, parentId, name, index);
|
|
parentValue = &game::gScrVarGlob[inst].parentVariables[parentId + 1];
|
|
|
|
assert(((parentValue->w.status & VAR_STAT_MASK) == VAR_STAT_EXTERNAL));
|
|
|
|
parent = &game::gScrVarGlob[inst].parentVariables[parentValue->v.next + 1];
|
|
entry = &game::gScrVarGlob[inst].childVariables[indexa];
|
|
id = entry->hash.id;
|
|
siblingId = parent->hash.u.prev;
|
|
|
|
if (siblingId)
|
|
{
|
|
siblingValue = &game::gScrVarGlob[inst].childVariables[siblingId];
|
|
|
|
assert((siblingValue->w.status & VAR_STAT_MASK) != VAR_STAT_FREE);
|
|
|
|
assert(!IsObject(siblingValue));
|
|
|
|
siblingValue->nextSibling = indexa;
|
|
siblingIndex = game::FindVariableIndexInternal(inst, parentId, siblingValue->w.status >> VAR_NAME_BIT_SHIFT);
|
|
|
|
assert(siblingIndex);
|
|
}
|
|
else
|
|
{
|
|
siblingIndex = 0;
|
|
parentValue->nextSibling = id;
|
|
}
|
|
|
|
parent->hash.u.prev = id;
|
|
entry->hash.u.prev = siblingIndex;
|
|
game::gScrVarGlob[inst].childVariables[id].nextSibling = 0;
|
|
return indexa;
|
|
}
|
|
|
|
// Decomp Status: Completed
|
|
void MakeVariableExternal(game::VariableValueInternal* parentValue, game::scriptInstance_t inst, unsigned int index)
|
|
{
|
|
game::VariableValueInternal* entry;
|
|
unsigned int oldPrevSiblingIndex;
|
|
unsigned int nextSiblingIndex;
|
|
unsigned int prevSiblingIndex;
|
|
unsigned int oldIndex;
|
|
game::VariableValueInternal* entryValue;
|
|
game::Variable tempEntry;
|
|
game::VariableValueInternal* oldEntry;
|
|
game::VariableValueInternal* oldEntrya;
|
|
game::Variable* prev;
|
|
unsigned int oldNextSiblingIndex;
|
|
game::VariableValue value;
|
|
game::VariableValueInternal* oldEntryValue;
|
|
game::VariableValueInternal* oldEntryValuea;
|
|
|
|
entry = &game::gScrVarGlob[inst].childVariables[index];
|
|
entryValue = &game::gScrVarGlob[inst].childVariables[entry->hash.id];
|
|
|
|
assert((entryValue->w.status & VAR_STAT_MASK) == VAR_STAT_MOVABLE || (entryValue->w.status & VAR_STAT_MASK) == VAR_STAT_HEAD);
|
|
|
|
assert((entryValue->w.status & VAR_STAT_MASK) != VAR_STAT_FREE);
|
|
|
|
assert(!IsObject(entryValue));
|
|
|
|
if ((parentValue->w.status & VAR_MASK) == game::VAR_ARRAY)
|
|
{
|
|
--parentValue->u.o.u.size;
|
|
|
|
assert((entryValue->w.status & VAR_STAT_MASK) != VAR_STAT_FREE);
|
|
|
|
assert(!IsObject(entryValue));
|
|
|
|
value = game::Scr_GetArrayIndexValue(inst, entryValue->w.status >> VAR_NAME_BIT_SHIFT);
|
|
game::RemoveRefToValueInternal(inst, value.type, value.u);
|
|
}
|
|
|
|
if ((entryValue->w.status & VAR_STAT_MASK) == VAR_STAT_HEAD)
|
|
{
|
|
oldIndex = entryValue->v.next;
|
|
oldEntry = &game::gScrVarGlob[inst].childVariables[oldIndex];
|
|
oldEntryValue = &game::gScrVarGlob[inst].childVariables[oldEntry->hash.id];
|
|
|
|
if (oldEntry != entry)
|
|
{
|
|
assert((oldEntryValue->w.status & VAR_STAT_MASK) == VAR_STAT_MOVABLE);
|
|
|
|
oldEntryValue->w.status = oldEntryValue->w.status & ~VAR_STAT_MOVABLE | VAR_STAT_HEAD;
|
|
prevSiblingIndex = entry->hash.u.prev;
|
|
nextSiblingIndex = entryValue->nextSibling;
|
|
oldPrevSiblingIndex = oldEntry->hash.u.prev;
|
|
oldNextSiblingIndex = oldEntryValue->nextSibling;
|
|
|
|
if (oldNextSiblingIndex)
|
|
{
|
|
game::gScrVarGlob[inst].childVariables[oldNextSiblingIndex].hash.u.prev = index;
|
|
}
|
|
|
|
if (oldPrevSiblingIndex)
|
|
{
|
|
game::gScrVarGlob[inst].childVariables[game::gScrVarGlob[inst].childVariables[oldPrevSiblingIndex].hash.id].nextSibling = index;
|
|
}
|
|
|
|
if (nextSiblingIndex)
|
|
{
|
|
game::gScrVarGlob[inst].childVariables[nextSiblingIndex].hash.u.prev = oldIndex;
|
|
}
|
|
|
|
if (prevSiblingIndex)
|
|
{
|
|
game::gScrVarGlob[inst].childVariables[game::gScrVarGlob[inst].childVariables[prevSiblingIndex].hash.id].nextSibling = oldIndex;
|
|
}
|
|
|
|
tempEntry = entry->hash;
|
|
entry->hash = oldEntry->hash;
|
|
oldEntry->hash = tempEntry;
|
|
entryValue->w.status |= VAR_STAT_EXTERNAL;
|
|
entryValue->v.next = oldIndex;
|
|
}
|
|
else
|
|
{
|
|
entryValue->w.status |= VAR_STAT_EXTERNAL;
|
|
entryValue->v.next = index;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
oldEntrya = entry;
|
|
oldEntryValuea = entryValue;
|
|
|
|
do
|
|
{
|
|
assert((oldEntryValuea->w.status & VAR_STAT_MASK) == VAR_STAT_MOVABLE || (oldEntryValuea->w.status & VAR_STAT_MASK) == VAR_STAT_HEAD);
|
|
|
|
prev = &oldEntrya->hash;
|
|
oldEntrya = &game::gScrVarGlob[inst].childVariables[oldEntryValuea->v.next];
|
|
oldEntryValuea = &game::gScrVarGlob[inst].childVariables[oldEntrya->hash.id];
|
|
} while (oldEntrya != entry);
|
|
|
|
game::gScrVarGlob[inst].childVariables[prev->id].v.next = entryValue->v.next;
|
|
|
|
assert(entryValue == &game::gScrVarGlob[inst].childVariables[entry->hash.id]);
|
|
|
|
entryValue->w.status |= VAR_STAT_EXTERNAL;
|
|
entryValue->v.next = index;
|
|
}
|
|
}
|
|
|
|
// Decomp Status: Completed
|
|
void FreeChildValue(unsigned int id, game::scriptInstance_t inst, unsigned int parentId)
|
|
{
|
|
game::VariableValueInternal* entry;
|
|
unsigned int nextSiblingIndex;
|
|
unsigned int prevSiblingIndex;
|
|
unsigned int parentIndex;
|
|
game::VariableValueInternal* entryValue;
|
|
unsigned int index;
|
|
|
|
entryValue = &game::gScrVarGlob[inst].childVariables[id];
|
|
|
|
assert(((entryValue->w.status & VAR_STAT_MASK) == VAR_STAT_EXTERNAL));
|
|
|
|
assert((entryValue->w.status & VAR_STAT_MASK) != VAR_STAT_FREE);
|
|
|
|
assert(!IsObject(entryValue));
|
|
|
|
assert(game::gScrVarGlob[inst].childVariables[entryValue->v.index].hash.id == id);
|
|
|
|
game::RemoveRefToValueInternal(inst, (game::VariableType)(entryValue->w.status & VAR_MASK), entryValue->u.u);
|
|
|
|
assert(id > 0 && id < VARIABLELIST_CHILD_SIZE);
|
|
|
|
assert(((entryValue->w.status & VAR_STAT_MASK) == VAR_STAT_EXTERNAL));
|
|
|
|
index = entryValue->v.next;
|
|
entry = &game::gScrVarGlob[inst].childVariables[index];
|
|
|
|
assert(entry->hash.id == id);
|
|
|
|
nextSiblingIndex = entryValue->nextSibling;
|
|
prevSiblingIndex = entry->hash.u.prev;
|
|
|
|
if (prevSiblingIndex)
|
|
{
|
|
game::gScrVarGlob[inst].childVariables[game::gScrVarGlob[inst].childVariables[prevSiblingIndex].hash.id].nextSibling = nextSiblingIndex;
|
|
}
|
|
else
|
|
{
|
|
assert(!game::gScrVarGlob[inst].childVariables[0].hash.id);
|
|
|
|
game::gScrVarGlob[inst].parentVariables[parentId + 1].nextSibling = game::gScrVarGlob[inst].childVariables[nextSiblingIndex].hash.id;
|
|
}
|
|
|
|
if (nextSiblingIndex)
|
|
{
|
|
game::gScrVarGlob[inst].childVariables[nextSiblingIndex].hash.u.prev = prevSiblingIndex;
|
|
}
|
|
else
|
|
{
|
|
assert(!game::gScrVarGlob[inst].childVariables[0].hash.id);
|
|
|
|
parentIndex = game::gScrVarGlob[inst].parentVariables[parentId + 1].v.next;
|
|
game::gScrVarGlob[inst].parentVariables[parentIndex + 1].hash.u.prev = game::gScrVarGlob[inst].childVariables[prevSiblingIndex].hash.id;
|
|
}
|
|
|
|
entryValue->w.status = 0;
|
|
entryValue->u.next = game::gScrVarGlob[inst].childVariables[0].u.next;
|
|
entry->hash.u.prev = 0;
|
|
game::gScrVarGlob[inst].childVariables[game::gScrVarGlob[inst].childVariables[0].u.next].hash.u.prev = index;
|
|
game::gScrVarGlob[inst].childVariables[0].u.next = index;
|
|
}
|
|
|
|
// Decomp Status: Completed
|
|
void ClearObjectInternal(game::scriptInstance_t inst, unsigned int parentId)
|
|
{
|
|
unsigned int nextId;
|
|
unsigned int nextSibling;
|
|
unsigned int nextSiblinga;
|
|
game::VariableValueInternal* parentValue;
|
|
game::VariableValueInternal* entryValue;
|
|
unsigned int id;
|
|
unsigned int ida;
|
|
|
|
parentValue = &game::gScrVarGlob[inst].parentVariables[parentId + 1];
|
|
|
|
assert((parentValue->w.status & VAR_STAT_MASK) != VAR_STAT_FREE);
|
|
|
|
assert(IsObject(parentValue));
|
|
|
|
if (parentValue->nextSibling)
|
|
{
|
|
entryValue = &game::gScrVarGlob[inst].childVariables[parentValue->nextSibling];
|
|
|
|
assert((entryValue->w.status & VAR_STAT_MASK) != VAR_STAT_FREE);
|
|
|
|
assert(!IsObject(entryValue));
|
|
|
|
nextSibling = game::FindVariableIndexInternal(inst, parentId, entryValue->w.status >> VAR_NAME_BIT_SHIFT);
|
|
|
|
assert(nextSibling);
|
|
|
|
do
|
|
{
|
|
id = game::gScrVarGlob[inst].childVariables[nextSibling].hash.id;
|
|
game::MakeVariableExternal(parentValue, inst, nextSibling);
|
|
nextSibling = game::gScrVarGlob[inst].childVariables[id].nextSibling;
|
|
} while (nextSibling);
|
|
|
|
nextId = parentValue->nextSibling;
|
|
do
|
|
{
|
|
ida = nextId;
|
|
nextSiblinga = game::gScrVarGlob[inst].childVariables[nextId].nextSibling;
|
|
nextId = game::gScrVarGlob[inst].childVariables[nextSiblinga].hash.id;
|
|
game::FreeChildValue(ida, inst, parentId);
|
|
} while (nextSiblinga);
|
|
}
|
|
}
|
|
|
|
// Restored
|
|
void AddRefToObject(game::scriptInstance_t inst, unsigned int id)
|
|
{
|
|
game::VariableValueInternal* entryValue;
|
|
|
|
assert(id >= 1 && id < VARIABLELIST_CHILD_BEGIN);
|
|
|
|
assert((game::gScrVarGlob[inst].parentVariables[id + 1].w.status & VAR_STAT_MASK) != VAR_STAT_FREE);
|
|
|
|
entryValue = &game::gScrVarGlob[inst].parentVariables[id + 1];
|
|
|
|
assert((entryValue->w.status & VAR_STAT_MASK) != VAR_STAT_FREE);
|
|
|
|
assert(IsObject(entryValue));
|
|
|
|
++entryValue->u.o.refCount;
|
|
|
|
assert(entryValue->u.o.refCount);
|
|
}
|
|
|
|
// Restored
|
|
void RemoveRefToEmptyObject(game::scriptInstance_t inst, unsigned int id)
|
|
{
|
|
game::VariableValueInternal* entryValue;
|
|
|
|
entryValue = &game::gScrVarGlob[inst].parentVariables[id + 1];
|
|
|
|
assert(((entryValue->w.status & VAR_STAT_MASK) == VAR_STAT_EXTERNAL));
|
|
|
|
assert((entryValue->w.status & VAR_STAT_MASK) != VAR_STAT_FREE);
|
|
|
|
assert(IsObject(entryValue));
|
|
|
|
assert(!entryValue->nextSibling);
|
|
|
|
if (entryValue->u.o.refCount)
|
|
{
|
|
assert(id >= 1 && id < VARIABLELIST_CHILD_BEGIN);
|
|
|
|
--entryValue->u.o.refCount;
|
|
}
|
|
else
|
|
{
|
|
game::FreeVariable(id, inst);
|
|
}
|
|
}
|
|
|
|
// Decomp Status: Completed
|
|
void ClearObject(unsigned int parentId, game::scriptInstance_t inst)
|
|
{
|
|
assert((game::gScrVarGlob[inst].parentVariables[parentId + 1].w.status & VAR_STAT_MASK) != VAR_STAT_FREE);
|
|
|
|
game::AddRefToObject(inst, parentId);
|
|
game::ClearObjectInternal(inst, parentId);
|
|
game::RemoveRefToEmptyObject(inst, parentId);
|
|
}
|
|
|
|
// Restored
|
|
void Scr_ClearThread(game::scriptInstance_t inst, unsigned int parentId)
|
|
{
|
|
game::VariableValueInternal* parentValue;
|
|
|
|
assert(parentId);
|
|
|
|
parentValue = &game::gScrVarGlob[inst].parentVariables[parentId + 1];
|
|
|
|
assert((parentValue->w.status & VAR_STAT_MASK) != VAR_STAT_FREE);
|
|
|
|
assert(((parentValue->w.type & VAR_MASK) >= game::VAR_THREAD) && ((parentValue->w.type & VAR_MASK) <= game::VAR_CHILD_THREAD));
|
|
|
|
assert(!game::FindVariable(OBJECT_STACK, parentId, inst));
|
|
|
|
if (parentValue->nextSibling)
|
|
{
|
|
game::ClearObjectInternal(inst, parentId);
|
|
}
|
|
|
|
game::RemoveRefToObject(parentValue->u.o.u.nextEntId, inst);
|
|
}
|
|
|
|
// Decomp Status: Completed
|
|
void Scr_StopThread(game::scriptInstance_t inst, unsigned int threadId)
|
|
{
|
|
assert(threadId);
|
|
|
|
game::Scr_ClearThread(inst, threadId);
|
|
game::gScrVarGlob[inst].parentVariables[threadId + 1].u.o.u.nextEntId = game::gScrVarPub[inst].levelId;
|
|
game::AddRefToObject(inst, game::gScrVarPub[inst].levelId);
|
|
}
|
|
|
|
// Decomp Status: Completed
|
|
unsigned int GetSafeParentLocalId(game::scriptInstance_t inst, unsigned int threadId)
|
|
{
|
|
unsigned int id;
|
|
|
|
id = 0;
|
|
|
|
if ((game::gScrVarGlob[inst].parentVariables[threadId + 1].w.status & VAR_STAT_MASK) == VAR_STAT_FREE)
|
|
{
|
|
return id;
|
|
}
|
|
|
|
assert((game::gScrVarGlob[inst].parentVariables[threadId + 1].w.status & VAR_STAT_MASK) == VAR_STAT_EXTERNAL);
|
|
|
|
assert((game::gScrVarGlob[inst].parentVariables[threadId + 1].w.type & VAR_MASK) >= game::VAR_THREAD &&
|
|
(game::gScrVarGlob[inst].parentVariables[threadId + 1].w.type & VAR_MASK) <= game::VAR_CHILD_THREAD);
|
|
|
|
if ((game::gScrVarGlob[inst].parentVariables[threadId + 1].w.status & VAR_MASK) == game::VAR_CHILD_THREAD)
|
|
{
|
|
id = game::gScrVarGlob[inst].parentVariables[threadId + 1].w.parentLocalId >> VAR_PARENTID_BIT_SHIFT;
|
|
}
|
|
|
|
return id;
|
|
}
|
|
|
|
// Decomp Status: Completed
|
|
unsigned int GetStartLocalId(unsigned int threadId, game::scriptInstance_t inst)
|
|
{
|
|
assert((game::gScrVarGlob[inst].parentVariables[threadId + 1].w.status & VAR_STAT_MASK) == VAR_STAT_EXTERNAL);
|
|
|
|
assert((game::gScrVarGlob[inst].parentVariables[threadId + 1].w.type & VAR_MASK) >= game::VAR_THREAD &&
|
|
(game::gScrVarGlob[inst].parentVariables[threadId + 1].w.type & VAR_MASK) <= game::VAR_CHILD_THREAD);
|
|
|
|
while ((game::gScrVarGlob[inst].parentVariables[threadId + 1].w.status & VAR_MASK) == game::VAR_CHILD_THREAD)
|
|
{
|
|
threadId = game::gScrVarGlob[inst].parentVariables[threadId + 1].w.parentLocalId >> VAR_PARENTID_BIT_SHIFT;
|
|
}
|
|
|
|
assert((game::gScrVarGlob[inst].parentVariables[threadId + 1].w.status & VAR_STAT_MASK) == VAR_STAT_EXTERNAL);
|
|
|
|
assert((game::gScrVarGlob[inst].parentVariables[threadId + 1].w.type & VAR_MASK) >= game::VAR_THREAD &&
|
|
(game::gScrVarGlob[inst].parentVariables[threadId + 1].w.type & VAR_MASK) <= game::VAR_TIME_THREAD);
|
|
|
|
return threadId;
|
|
}
|
|
|
|
// Restored
|
|
unsigned int FindObjectVariable(game::scriptInstance_t inst, unsigned int parentId, unsigned int id)
|
|
{
|
|
return game::gScrVarGlob[inst].childVariables[game::FindVariableIndexInternal(inst, parentId, id + SL_MAX_STRING_INDEX)].hash.id;
|
|
}
|
|
|
|
// Restored
|
|
void RemoveObjectVariable(game::scriptInstance_t inst, unsigned int parentId, unsigned int id)
|
|
{
|
|
assert((game::gScrVarGlob[inst].parentVariables[parentId + 1].w.type & VAR_MASK) == game::VAR_ARRAY);
|
|
|
|
game::RemoveVariable(id + SL_MAX_STRING_INDEX, parentId, inst);
|
|
}
|
|
|
|
// Restored
|
|
game::VariableValueInternal_u* GetVariableValueAddress(game::scriptInstance_t inst, unsigned int id)
|
|
{
|
|
game::VariableValueInternal* entryValue;
|
|
|
|
assert(id);
|
|
|
|
entryValue = &game::gScrVarGlob[inst].childVariables[id];
|
|
|
|
assert((entryValue->w.status & VAR_STAT_MASK) != VAR_STAT_FREE);
|
|
|
|
assert((entryValue->w.type & VAR_MASK) != game::VAR_UNDEFINED);
|
|
|
|
assert((entryValue->w.status & VAR_STAT_MASK) != VAR_STAT_FREE);
|
|
|
|
assert(!IsObject(entryValue));
|
|
|
|
return &entryValue->u;
|
|
}
|
|
|
|
// Restored
|
|
void Scr_KillEndonThread(game::scriptInstance_t inst, unsigned int threadId)
|
|
{
|
|
game::VariableValueInternal* parentValue;
|
|
|
|
parentValue = &game::gScrVarGlob[inst].parentVariables[threadId + 1];
|
|
|
|
assert((parentValue->w.status & VAR_STAT_MASK) == VAR_STAT_EXTERNAL);
|
|
|
|
assert((parentValue->w.type & VAR_MASK) == game::VAR_THREAD);
|
|
|
|
assert(!parentValue->nextSibling);
|
|
|
|
game::RemoveRefToObject(parentValue->u.o.u.nextEntId, inst);
|
|
|
|
assert(!game::FindObjectVariable(inst, game::gScrVarPub[inst].pauseArrayId, threadId));
|
|
|
|
parentValue->w.status &= ~0xAu;
|
|
parentValue->w.status |= game::VAR_DEAD_THREAD;
|
|
}
|
|
|
|
// Decomp Status: Completed
|
|
void Scr_KillThread(game::scriptInstance_t inst, unsigned int parentId)
|
|
{
|
|
game::VariableValueInternal* parentValue;
|
|
unsigned int selfNameId;
|
|
unsigned int name;
|
|
unsigned int id;
|
|
unsigned int notifyListEntry;
|
|
game::VariableValueInternal_u* address;
|
|
unsigned int objectVariableId;
|
|
|
|
assert(parentId);
|
|
|
|
parentValue = &game::gScrVarGlob[inst].parentVariables[parentId + 1];
|
|
|
|
assert((parentValue->w.status & VAR_STAT_MASK) == VAR_STAT_EXTERNAL);
|
|
|
|
assert(((parentValue->w.type & VAR_MASK) >= game::VAR_THREAD) && ((parentValue->w.type & VAR_MASK) <= game::VAR_CHILD_THREAD));
|
|
|
|
game::Scr_ClearThread(inst, parentId);
|
|
id = game::FindObjectVariable(inst, game::gScrVarPub[inst].pauseArrayId, parentId);
|
|
|
|
if (id)
|
|
{
|
|
for (selfNameId = game::FindObject(inst, id);
|
|
;
|
|
game::RemoveObjectVariable(inst, selfNameId, name - SL_MAX_STRING_INDEX))
|
|
{
|
|
notifyListEntry = game::FindFirstSibling(inst, selfNameId);
|
|
if (!notifyListEntry)
|
|
{
|
|
break;
|
|
}
|
|
|
|
assert((game::gScrVarGlob[inst].childVariables[notifyListEntry].w.type & VAR_MASK) == game::VAR_POINTER);
|
|
|
|
name = game::gScrVarGlob[inst].childVariables[notifyListEntry].w.status >> VAR_NAME_BIT_SHIFT;
|
|
|
|
assert((name - SL_MAX_STRING_INDEX) < SL_MAX_STRING_INDEX);
|
|
|
|
objectVariableId = game::FindObjectVariable(inst, selfNameId, name - SL_MAX_STRING_INDEX);
|
|
address = game::GetVariableValueAddress(inst, objectVariableId);
|
|
game::VM_CancelNotify(inst, address->u.stringValue, name - SL_MAX_STRING_INDEX);
|
|
game::Scr_KillEndonThread(inst, name - SL_MAX_STRING_INDEX);
|
|
}
|
|
|
|
assert(!game::GetArraySize(inst, selfNameId));
|
|
|
|
game::RemoveObjectVariable(inst, game::gScrVarPub[inst].pauseArrayId, parentId);
|
|
}
|
|
|
|
parentValue->w.status &= ~VAR_MASK;
|
|
parentValue->w.status |= game::VAR_DEAD_THREAD;
|
|
}
|
|
|
|
// Decomp Status: Completed
|
|
unsigned __int16 AllocVariable(game::scriptInstance_t inst)
|
|
{
|
|
game::VariableValueInternal* entry;
|
|
unsigned int newIndex;
|
|
unsigned int next;
|
|
unsigned int index;
|
|
game::VariableValueInternal* entryValue;
|
|
|
|
index = game::gScrVarGlob[inst].parentVariables[1].u.next;
|
|
if (!index)
|
|
{
|
|
game::Scr_TerminalError(inst, "exceeded maximum number of script variables");
|
|
}
|
|
|
|
entry = &game::gScrVarGlob[inst].parentVariables[index + 1];
|
|
entryValue = &game::gScrVarGlob[inst].parentVariables[entry->hash.id + 1];
|
|
|
|
assert((entryValue->w.status & VAR_STAT_MASK) == VAR_STAT_FREE);
|
|
|
|
next = entryValue->u.next;
|
|
|
|
if (entry != entryValue && (entry->w.status & VAR_STAT_MASK) == VAR_STAT_FREE)
|
|
{
|
|
newIndex = entry->v.next;
|
|
|
|
assert(newIndex != index);
|
|
|
|
game::gScrVarGlob[inst].parentVariables[newIndex + 1].hash.id = entry->hash.id;
|
|
entry->hash.id = index;
|
|
entryValue->v.next = newIndex;
|
|
entryValue->u.next = entry->u.next;
|
|
entryValue = entry;
|
|
}
|
|
|
|
game::gScrVarGlob[inst].parentVariables[1].u.next = next;
|
|
game::gScrVarGlob[inst].parentVariables[next + 1].hash.u.prev = 0;
|
|
entryValue->v.next = index;
|
|
entryValue->nextSibling = 0;
|
|
entry->hash.u.prev = 0;
|
|
|
|
assert(entry->hash.id > 0 && entry->hash.id < VARIABLELIST_CHILD_BEGIN);
|
|
|
|
return entry->hash.id;
|
|
}
|
|
|
|
// Decomp Status: Completed
|
|
void FreeVariable(unsigned int id, game::scriptInstance_t inst)
|
|
{
|
|
game::VariableValueInternal* entry;
|
|
game::VariableValueInternal* entryValue;
|
|
unsigned int index;
|
|
|
|
assert(id > 0 && id < VARIABLELIST_CHILD_BEGIN);
|
|
|
|
entryValue = &game::gScrVarGlob[inst].parentVariables[id + 1];
|
|
|
|
assert(((entryValue->w.status & VAR_STAT_MASK) == VAR_STAT_EXTERNAL));
|
|
|
|
index = entryValue->v.next;
|
|
entry = &game::gScrVarGlob[inst].parentVariables[index + 1];
|
|
|
|
assert(entry->hash.id == id);
|
|
|
|
assert(!entry->hash.u.prev);
|
|
|
|
assert(!entryValue->nextSibling);
|
|
|
|
entryValue->w.status = 0;
|
|
entryValue->u.next = game::gScrVarGlob[inst].parentVariables[1].u.next;
|
|
entry->hash.u.prev = 0;
|
|
game::gScrVarGlob[inst].parentVariables[game::gScrVarGlob[inst].parentVariables[1].u.next + 1].hash.u.prev = index;
|
|
game::gScrVarGlob[inst].parentVariables[1].u.next = index;
|
|
}
|
|
|
|
// Decomp Status: Tested, Needs cleaning
|
|
// unsigned int __usercall AllocValue@<eax>(game::scriptInstance_t inst@<eax>)
|
|
unsigned int AllocValue(game::scriptInstance_t inst)
|
|
{
|
|
game::VariableValueInternal* entry;
|
|
unsigned int newIndex;
|
|
unsigned int next;
|
|
game::VariableValueInternal* entryValue;
|
|
unsigned int index;
|
|
|
|
index = game::gScrVarGlob[inst].childVariables[0].u.next;
|
|
if (!index)
|
|
{
|
|
game::Scr_TerminalError(inst, "exceeded maximum number of script variables");
|
|
}
|
|
|
|
entry = &game::gScrVarGlob[inst].childVariables[index];
|
|
entryValue = &game::gScrVarGlob[inst].childVariables[entry->hash.id];
|
|
|
|
assert((entryValue->w.status & VAR_STAT_MASK) == VAR_STAT_FREE);
|
|
|
|
next = entryValue->u.next;
|
|
if (entry != entryValue && (entry->w.status & VAR_STAT_MASK) == VAR_STAT_FREE)
|
|
{
|
|
newIndex = entry->v.next;
|
|
|
|
assert(newIndex != index);
|
|
|
|
game::gScrVarGlob[inst].childVariables[newIndex].hash.id = entry->hash.id;
|
|
entry->hash.id = index;
|
|
entryValue->v.next = newIndex;
|
|
entryValue->u.next = entry->u.next;
|
|
entryValue = entry;
|
|
}
|
|
|
|
game::gScrVarGlob[inst].childVariables[0].u.next = next;
|
|
game::gScrVarGlob[inst].childVariables[next].hash.u.prev = 0;
|
|
entryValue->v.next = index;
|
|
entryValue->nextSibling = 0;
|
|
entry->hash.u.prev = 0;
|
|
entryValue->w.status = VAR_STAT_EXTERNAL;
|
|
|
|
assert((entryValue->w.type & VAR_MASK) == game::VAR_UNDEFINED);
|
|
|
|
return entry->hash.id;
|
|
}
|
|
|
|
// Decomp Status: Completed
|
|
unsigned int AllocEntity(game::classNum_e classnum, game::scriptInstance_t inst, int entnum, int clientnum)
|
|
{
|
|
game::VariableValueInternal* entryValue;
|
|
unsigned int id;
|
|
|
|
id = game::AllocVariable(inst);
|
|
entryValue = &game::gScrVarGlob[inst].parentVariables[id + 1];
|
|
entryValue->w.status = VAR_STAT_EXTERNAL;
|
|
|
|
assert((entryValue->w.type & VAR_MASK) == game::VAR_UNDEFINED);
|
|
|
|
entryValue->w.status |= game::VAR_ENTITY;
|
|
|
|
assert(!(entryValue->w.status & VAR_NAME_HIGH_MASK));
|
|
|
|
entryValue->w.status |= classnum << VAR_NAME_BIT_SHIFT;
|
|
entryValue->u.o.refCount = 0;
|
|
entryValue->u.o.u.entnum = (unsigned short)entnum;
|
|
entryValue->u.o.u.entnum |= (unsigned char)clientnum << VAR_CLIENT_MASK;
|
|
return id;
|
|
}
|
|
|
|
// Decomp Status: Completed
|
|
unsigned int Scr_AllocArray(game::scriptInstance_t inst)
|
|
{
|
|
game::VariableValueInternal* entryValue;
|
|
unsigned int id;
|
|
|
|
id = game::AllocVariable(inst);
|
|
entryValue = &game::gScrVarGlob[inst].parentVariables[id + 1];
|
|
entryValue->w.status = VAR_STAT_EXTERNAL;
|
|
|
|
assert((entryValue->w.type & VAR_MASK) == game::VAR_UNDEFINED);
|
|
|
|
entryValue->w.status |= game::VAR_ARRAY;
|
|
entryValue->u.o.refCount = 0;
|
|
entryValue->u.o.u.size = 0;
|
|
return id;
|
|
}
|
|
|
|
unsigned int AllocThread(game::scriptInstance_t inst, unsigned int self)
|
|
{
|
|
game::VariableValueInternal* entryValue;
|
|
unsigned int id;
|
|
|
|
id = game::AllocVariable(inst);
|
|
entryValue = &game::gScrVarGlob[inst].parentVariables[id + 1];
|
|
entryValue->w.status = VAR_STAT_EXTERNAL;
|
|
|
|
assert((entryValue->w.type & VAR_MASK) == game::VAR_UNDEFINED);
|
|
|
|
entryValue->w.status |= game::VAR_THREAD;
|
|
entryValue->u.o.refCount = 0;
|
|
entryValue->u.o.u.self = self;
|
|
return id;
|
|
}
|
|
|
|
// Decomp Status: Completed
|
|
unsigned int AllocChildThread(game::scriptInstance_t inst, unsigned int parentLocalId, unsigned int self)
|
|
{
|
|
game::VariableValueInternal* entryValue;
|
|
unsigned int id;
|
|
|
|
id = game::AllocVariable(inst);
|
|
entryValue = &game::gScrVarGlob[inst].parentVariables[id + 1];
|
|
entryValue->w.status = VAR_STAT_EXTERNAL;
|
|
|
|
assert((entryValue->w.type & VAR_MASK) == game::VAR_UNDEFINED);
|
|
|
|
entryValue->w.type |= game::VAR_CHILD_THREAD;
|
|
|
|
assert(!(entryValue->w.status & VAR_NAME_HIGH_MASK));
|
|
|
|
entryValue->w.parentLocalId |= parentLocalId << VAR_NAME_BIT_SHIFT;
|
|
entryValue->u.o.refCount = 0;
|
|
entryValue->u.o.u.self = self;
|
|
return id;
|
|
}
|
|
|
|
// Decomp Status: Completed
|
|
void FreeValue(unsigned int id, game::scriptInstance_t inst)
|
|
{
|
|
game::VariableValueInternal* entry;
|
|
game::VariableValueInternal* entryValue;
|
|
unsigned int index;
|
|
|
|
entryValue = &game::gScrVarGlob[inst].childVariables[id];
|
|
|
|
assert(((entryValue->w.status & VAR_STAT_MASK) == VAR_STAT_EXTERNAL));
|
|
|
|
assert((entryValue->w.status & VAR_STAT_MASK) != VAR_STAT_FREE);
|
|
|
|
assert(!IsObject(entryValue));
|
|
|
|
assert(game::gScrVarGlob[inst].childVariables[entryValue->v.next].hash.id == id);
|
|
|
|
game::RemoveRefToValueInternal(inst, (game::VariableType)(entryValue->w.status & VAR_MASK), entryValue->u.u);
|
|
|
|
assert(id > 0 && id < VARIABLELIST_CHILD_SIZE);
|
|
|
|
assert(((entryValue->w.status & VAR_STAT_MASK) == VAR_STAT_EXTERNAL));
|
|
|
|
index = entryValue->v.next;
|
|
entry = &game::gScrVarGlob[inst].childVariables[index];
|
|
|
|
assert(entry->hash.id == id);
|
|
|
|
assert(!entry->hash.u.prev);
|
|
|
|
assert(!entryValue->nextSibling);
|
|
|
|
entryValue->w.status = 0;
|
|
entryValue->u.next = game::gScrVarGlob[inst].childVariables[0].u.next;
|
|
entry->hash.u.prev = 0;
|
|
game::gScrVarGlob[inst].childVariables[game::gScrVarGlob[inst].childVariables[0].u.next].hash.u.prev = index;
|
|
game::gScrVarGlob[inst].childVariables[0].u.next = index;
|
|
}
|
|
|
|
// Restored
|
|
void RemoveArrayVariable(game::scriptInstance_t inst, unsigned int parentId, unsigned int unsignedValue)
|
|
{
|
|
assert(game::IsValidArrayIndex(inst, unsignedValue));
|
|
|
|
game::RemoveVariable((unsignedValue + 0x800000) & 0xFFFFFF, parentId, inst);
|
|
}
|
|
|
|
// Restored inlined function
|
|
unsigned int FindObject(game::scriptInstance_t inst, unsigned int id)
|
|
{
|
|
game::VariableValueInternal* entryValue;
|
|
|
|
assert(id);
|
|
|
|
entryValue = &game::gScrVarGlob[inst].childVariables[id];
|
|
|
|
assert((entryValue->w.status & VAR_STAT_MASK) != VAR_STAT_FREE);
|
|
|
|
assert((entryValue->w.type & VAR_MASK) == game::VAR_POINTER);
|
|
|
|
return entryValue->u.u.pointerValue;
|
|
}
|
|
|
|
// Decomp Status: Completed
|
|
void RemoveRefToObject(unsigned int id, game::scriptInstance_t inst)
|
|
{
|
|
int unsignedValue;
|
|
game::classNum_e classnum;
|
|
unsigned int entArrayId;
|
|
game::VariableValueInternal* entryValue;
|
|
|
|
assert(id >= 1 && id < VARIABLELIST_CHILD_BEGIN);
|
|
|
|
entryValue = &game::gScrVarGlob[inst].parentVariables[id + 1];
|
|
|
|
assert(((entryValue->w.status & VAR_STAT_MASK) == VAR_STAT_EXTERNAL));
|
|
|
|
assert((entryValue->w.status & VAR_STAT_MASK) != VAR_STAT_FREE);
|
|
|
|
assert(IsObject(entryValue));
|
|
|
|
if (entryValue->u.o.refCount)
|
|
{
|
|
if (!--entryValue->u.o.refCount && (entryValue->w.status & VAR_MASK) == game::VAR_ENTITY && !entryValue->nextSibling)
|
|
{
|
|
entryValue->w.status &= ~VAR_MASK;
|
|
entryValue->w.status |= game::VAR_DEAD_ENTITY;
|
|
classnum = (game::classNum_e)(entryValue->w.status >> VAR_NAME_BIT_SHIFT);
|
|
|
|
assert(classnum < game::CLASS_NUM_COUNT);
|
|
|
|
entArrayId = game::gScrClassMap[inst][classnum].entArrayId;
|
|
|
|
assert(entArrayId);
|
|
|
|
unsignedValue = entryValue->u.o.u.entnum & 0x3FFF;
|
|
if (inst == game::SCRIPTINSTANCE_CLIENT && (entryValue->u.o.u.entnum & 0xC000) != 0)
|
|
{
|
|
unsignedValue += entryValue->u.o.u.entnum >> 14 << 11;
|
|
}
|
|
|
|
game::RemoveArrayVariable(inst, entArrayId, unsignedValue);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (entryValue->nextSibling)
|
|
{
|
|
game::ClearObject(id, inst);
|
|
}
|
|
|
|
game::FreeVariable(id, inst);
|
|
}
|
|
}
|
|
|
|
// Decomp Status: Completed
|
|
float* Scr_AllocVector(game::scriptInstance_t inst)
|
|
{
|
|
game::RefVector* result;
|
|
|
|
result = (game::RefVector*)game::MT_Alloc(sizeof(game::RefVector), inst);
|
|
result->u.head = 0;
|
|
return &result->vec[0];
|
|
}
|
|
|
|
// Decomp Status: Completed
|
|
void RemoveRefToVector(const float* vectorValue, game::scriptInstance_t inst)
|
|
{
|
|
game::RefVector* ref = (game::RefVector*)((char*)vectorValue - 4);
|
|
|
|
if (!ref->u.s.length)
|
|
{
|
|
if (ref->u.s.refCount)
|
|
{
|
|
ref->u.s.refCount--;
|
|
}
|
|
else
|
|
{
|
|
game::MT_Free(ref, sizeof(game::RefVector), inst);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Restored
|
|
void AddRefToVector([[maybe_unused]] game::scriptInstance_t inst, const float* floatVal)
|
|
{
|
|
game::RefVector* rf = (game::RefVector*)(floatVal - 1);
|
|
|
|
if (!rf->u.s.length)
|
|
{
|
|
++rf->u.s.refCount;
|
|
|
|
assert(rf->u.s.refCount);
|
|
}
|
|
}
|
|
|
|
// Completed
|
|
void AddRefToValue(game::scriptInstance_t inst, game::VariableType type, game::VariableUnion u)
|
|
{
|
|
if (type > game::VAR_ISTRING)
|
|
{
|
|
//assert(type == game::VAR_VECTOR);
|
|
|
|
if (type == game::VAR_VECTOR)
|
|
{
|
|
game::AddRefToVector(inst, u.vectorValue);
|
|
}
|
|
}
|
|
else if (type >= game::VAR_STRING)
|
|
{
|
|
game::SL_AddRefToString(inst, u.stringValue);
|
|
}
|
|
else if (type == game::VAR_POINTER)
|
|
{
|
|
game::AddRefToObject(inst, u.pointerValue);
|
|
}
|
|
}
|
|
|
|
// Completed
|
|
void RemoveRefToValueInternal(game::scriptInstance_t inst, game::VariableType type, game::VariableUnion u)
|
|
{
|
|
if (type > game::VAR_ISTRING)
|
|
{
|
|
//assert(type == game::VAR_VECTOR);
|
|
|
|
if (type == game::VAR_VECTOR)
|
|
{
|
|
game::RemoveRefToVector(u.vectorValue, inst);
|
|
}
|
|
}
|
|
else if (type >= game::VAR_STRING)
|
|
{
|
|
game::SL_RemoveRefToString(u.stringValue, inst);
|
|
}
|
|
else if (type == game::VAR_POINTER)
|
|
{
|
|
game::RemoveRefToObject(u.pointerValue, inst);
|
|
}
|
|
}
|
|
|
|
// restored
|
|
unsigned int FindArrayVariableIndex(game::scriptInstance_t inst, unsigned int parentId, unsigned int unsignedValue)
|
|
{
|
|
assert(game::IsValidArrayIndex(inst, unsignedValue));
|
|
|
|
return game::FindVariableIndexInternal(inst, parentId, (unsignedValue + 0x800000) & 0xFFFFFF); // - ??
|
|
}
|
|
|
|
// Completed
|
|
unsigned int FindArrayVariable(unsigned int parentId, unsigned int intValue, game::scriptInstance_t inst)
|
|
{
|
|
return game::gScrVarGlob[inst].childVariables[game::FindArrayVariableIndex(inst, parentId, intValue)].hash.id;
|
|
}
|
|
|
|
// Completed
|
|
unsigned int FindVariable(unsigned int name, unsigned int parentId, game::scriptInstance_t inst)
|
|
{
|
|
return game::gScrVarGlob[inst].childVariables[game::FindVariableIndexInternal(inst, parentId, name)].hash.id;
|
|
}
|
|
|
|
// Restored
|
|
unsigned int GetVariableIndexInternal(game::scriptInstance_t inst, unsigned int parentId, unsigned int name)
|
|
{
|
|
unsigned int newIndex;
|
|
game::VariableValueInternal* parentValue;
|
|
|
|
assert(parentId);
|
|
|
|
parentValue = &game::gScrVarGlob[inst].parentVariables[parentId + 1];
|
|
|
|
assert((parentValue->w.status & VAR_STAT_MASK) == VAR_STAT_EXTERNAL);
|
|
|
|
assert((parentValue->w.status & VAR_STAT_MASK) != VAR_STAT_FREE);
|
|
|
|
assert(IsObject(parentValue));
|
|
|
|
newIndex = game::FindVariableIndexInternal2(inst, name, (parentId + name) % 0xFFFD + 1);
|
|
if (newIndex)
|
|
{
|
|
return newIndex;
|
|
}
|
|
|
|
return game::GetNewVariableIndexInternal2(name, inst, parentId, (parentId + name) % 0xFFFD + 1);
|
|
}
|
|
|
|
// Completed
|
|
unsigned int GetArrayVariableIndex(unsigned int unsignedValue, game::scriptInstance_t inst, unsigned int parentId)
|
|
{
|
|
assert(game::IsValidArrayIndex(inst, unsignedValue));
|
|
|
|
return game::GetVariableIndexInternal(inst, parentId, (unsignedValue + 0x800000) & 0xFFFFFF);
|
|
}
|
|
|
|
// Completed
|
|
unsigned int Scr_GetVariableFieldIndex(game::scriptInstance_t inst, unsigned int name, unsigned int parentId)
|
|
{
|
|
unsigned int index;
|
|
game::VariableType type;
|
|
game::VariableValueInternal* parentValue;
|
|
|
|
assert(parentId);
|
|
|
|
parentValue = &game::gScrVarGlob[inst].parentVariables[parentId + 1];
|
|
|
|
assert((parentValue->w.status & VAR_STAT_MASK) != VAR_STAT_FREE);
|
|
|
|
assert(IsObject(parentValue));
|
|
|
|
type = (game::VariableType)(parentValue->w.status & VAR_MASK);
|
|
|
|
if (type <= game::VAR_OBJECT)
|
|
{
|
|
return game::GetVariableIndexInternal(inst, parentId, name);
|
|
}
|
|
|
|
if (type != game::VAR_ENTITY)
|
|
{
|
|
game::Scr_Error(game::va("cannot set field of %s", game::var_typename[type]), inst, 0);
|
|
}
|
|
|
|
index = game::FindVariableIndexInternal(inst, parentId, name);
|
|
if (index)
|
|
{
|
|
return index;
|
|
}
|
|
|
|
game::gScrVarPub[inst].entId = parentId;
|
|
game::gScrVarPub[inst].entFieldName = name;
|
|
return 0;
|
|
}
|
|
|
|
// Completed
|
|
game::VariableValue Scr_FindVariableField(game::scriptInstance_t inst, unsigned int parentId, unsigned int name)
|
|
{
|
|
game::VariableValue result;
|
|
unsigned int id;
|
|
game::VariableValueInternal* parentValue;
|
|
|
|
assert(parentId);
|
|
|
|
parentValue = &game::gScrVarGlob[inst].parentVariables[parentId + 1];
|
|
|
|
assert((parentValue->w.status & VAR_STAT_MASK) != VAR_STAT_FREE);
|
|
|
|
assert(IsObject(parentValue));
|
|
|
|
assert(((parentValue->w.type & VAR_MASK) >= game::FIRST_OBJECT && (parentValue->w.type & VAR_MASK) < game::FIRST_NONFIELD_OBJECT) ||
|
|
((parentValue->w.type & VAR_MASK) >= game::FIRST_DEAD_OBJECT));
|
|
|
|
id = game::FindVariable(name, parentId, inst);
|
|
|
|
if (id)
|
|
{
|
|
return game::Scr_EvalVariable(inst, id);
|
|
}
|
|
|
|
if ((game::gScrVarGlob[inst].parentVariables[parentId + 1].w.status & VAR_MASK) == game::VAR_ENTITY)
|
|
{
|
|
return game::Scr_EvalVariableEntityField(parentId, inst, name);
|
|
}
|
|
|
|
result.u.intValue = 0;
|
|
result.type = game::VAR_UNDEFINED;
|
|
return result;
|
|
}
|
|
|
|
// Completed
|
|
void ClearVariableField(game::scriptInstance_t inst, unsigned int parentId, unsigned int name, game::VariableValue* value)
|
|
{
|
|
game::classNum_e classnum;
|
|
game::VariableValueInternal* parentValue;
|
|
game::VariableValueInternal* parentValue1;
|
|
unsigned int fieldId;
|
|
game::VariableValue* valuea;
|
|
|
|
parentValue1 = &game::gScrVarGlob[inst].parentVariables[parentId + 1];
|
|
|
|
assert((parentValue1->w.status & VAR_STAT_MASK) != VAR_STAT_FREE);
|
|
|
|
assert(IsObject(parentValue1));
|
|
|
|
assert(((parentValue1->w.type & VAR_MASK) >= game::FIRST_OBJECT && (parentValue1->w.type & VAR_MASK) < game::FIRST_NONFIELD_OBJECT) ||
|
|
((parentValue1->w.type & VAR_MASK) >= game::FIRST_DEAD_OBJECT));
|
|
|
|
if (game::FindVariableIndexInternal(inst, parentId, name))
|
|
{
|
|
game::RemoveVariable(name, parentId, inst);
|
|
}
|
|
else
|
|
{
|
|
parentValue = &game::gScrVarGlob[inst].parentVariables[parentId + 1];
|
|
if ((parentValue->w.status & VAR_MASK) == game::VAR_ENTITY)
|
|
{
|
|
classnum = (game::classNum_e)(parentValue->w.status >> VAR_NAME_BIT_SHIFT);
|
|
fieldId = game::FindArrayVariable(game::gScrClassMap[inst][classnum].id, name, inst);
|
|
if (fieldId)
|
|
{
|
|
valuea = value + 1;
|
|
valuea->type = game::VAR_UNDEFINED;
|
|
game::SetEntityFieldValue(inst, game::gScrVarGlob[inst].childVariables[fieldId].u.u.intValue, parentValue->u.o.u.entnum & VAR_ENT_MASK, classnum, parentValue->u.o.u.entnum >> VAR_CLIENT_MASK, valuea);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Completed
|
|
unsigned int GetVariable(game::scriptInstance_t inst, unsigned int parentId, unsigned int unsignedValue)
|
|
{
|
|
return game::gScrVarGlob[inst].childVariables[game::GetVariableIndexInternal(inst, parentId, unsignedValue)].hash.id;
|
|
}
|
|
|
|
// Restored
|
|
unsigned int GetNewVariableIndexInternal(game::scriptInstance_t inst, unsigned int parentId, unsigned int name)
|
|
{
|
|
assert(!game::FindVariableIndexInternal(inst, parentId, name));
|
|
|
|
return game::GetNewVariableIndexInternal2(name, inst, parentId, (parentId + name) % 0xFFFD + 1);
|
|
}
|
|
|
|
// Completed
|
|
unsigned int GetNewVariable(game::scriptInstance_t inst, unsigned int unsignedValue, unsigned int parentId)
|
|
{
|
|
return game::gScrVarGlob[inst].childVariables[game::GetNewVariableIndexInternal(inst, parentId, unsignedValue)].hash.id;
|
|
}
|
|
|
|
// Completed
|
|
unsigned int GetObjectVariable(unsigned int id, game::scriptInstance_t inst, unsigned int parentId)
|
|
{
|
|
assert((game::gScrVarGlob[inst].parentVariables[parentId + 1].w.type & VAR_MASK) == game::VAR_ARRAY);
|
|
|
|
return game::gScrVarGlob[inst].childVariables[game::GetVariableIndexInternal(inst, parentId, id + 0x10000)].hash.id;
|
|
}
|
|
|
|
// Completed
|
|
unsigned int GetNewObjectVariable(game::scriptInstance_t inst, unsigned int id, unsigned int parentId)
|
|
{
|
|
assert((game::gScrVarGlob[inst].parentVariables[parentId + 1].w.type & VAR_MASK) == game::VAR_ARRAY);
|
|
|
|
return game::gScrVarGlob[inst].childVariables[game::GetNewVariableIndexInternal(inst, parentId, id + 0x10000)].hash.id;
|
|
}
|
|
|
|
// Completed
|
|
void RemoveVariable(unsigned int unsignedValue, unsigned int parentId, game::scriptInstance_t inst)
|
|
{
|
|
unsigned int index;
|
|
unsigned int id;
|
|
|
|
index = game::FindVariableIndexInternal(inst, parentId, unsignedValue);
|
|
|
|
assert(index);
|
|
|
|
id = game::gScrVarGlob[inst].childVariables[index].hash.id;
|
|
game::MakeVariableExternal(&game::gScrVarGlob[inst].parentVariables[parentId + 1], inst, index);
|
|
game::FreeChildValue(id, inst, parentId);
|
|
}
|
|
|
|
// Completed
|
|
void RemoveNextVariable(game::scriptInstance_t inst, unsigned int parentId)
|
|
{
|
|
unsigned int index;
|
|
unsigned int id;
|
|
|
|
assert((game::gScrVarGlob[inst].parentVariables[parentId + 1].w.status & VAR_STAT_MASK) != VAR_STAT_FREE);
|
|
|
|
id = game::gScrVarGlob[inst].parentVariables[parentId + 1].nextSibling;
|
|
|
|
assert(id);
|
|
|
|
index = game::FindVariableIndexInternal(inst, parentId, game::gScrVarGlob[inst].childVariables[id].w.status >> VAR_NAME_BIT_SHIFT);
|
|
|
|
assert(index);
|
|
|
|
assert(id == game::gScrVarGlob[inst].childVariables[index].hash.id);
|
|
|
|
game::MakeVariableExternal(&game::gScrVarGlob[inst].parentVariables[parentId + 1], inst, index);
|
|
game::FreeChildValue(id, inst, parentId);
|
|
}
|
|
|
|
// Completed
|
|
void SafeRemoveVariable(unsigned int unsignedValue, unsigned int parentId, game::scriptInstance_t inst)
|
|
{
|
|
unsigned int index;
|
|
unsigned int id;
|
|
game::VariableValueInternal* entryValue;
|
|
|
|
index = game::FindVariableIndexInternal(inst, parentId, unsignedValue);
|
|
if (index)
|
|
{
|
|
id = (unsigned int)game::gScrVarGlob[inst].childVariables[index].hash.id;
|
|
|
|
entryValue = &game::gScrVarGlob[inst].childVariables[id];
|
|
|
|
assert((entryValue->w.status & VAR_STAT_MASK) != VAR_STAT_FREE);
|
|
|
|
assert(!IsObject(entryValue));
|
|
|
|
game::MakeVariableExternal(&game::gScrVarGlob[inst].parentVariables[parentId + 1], inst, index);
|
|
game::FreeChildValue(id, inst, parentId);
|
|
}
|
|
}
|
|
|
|
// Completed
|
|
void CopyArray(game::scriptInstance_t inst, unsigned int parentId, unsigned int newParentId)
|
|
{
|
|
unsigned int nextSibling;
|
|
game::VariableValueInternal* parentValue;
|
|
game::VariableValueInternal* entryValue;
|
|
game::VariableType type;
|
|
game::VariableValueInternal* newEntryValue;
|
|
unsigned int id;
|
|
|
|
parentValue = &game::gScrVarGlob[inst].parentVariables[parentId + 1];
|
|
|
|
assert((parentValue->w.status & VAR_STAT_MASK) != VAR_STAT_FREE);
|
|
|
|
assert(IsObject(parentValue));
|
|
|
|
assert((parentValue->w.type & VAR_MASK) == game::VAR_ARRAY);
|
|
|
|
id = game::gScrVarGlob[inst].parentVariables[parentId + 1].nextSibling;
|
|
if (id)
|
|
{
|
|
while (true)
|
|
{
|
|
entryValue = &game::gScrVarGlob[inst].childVariables[id];
|
|
|
|
assert((entryValue->w.status & VAR_STAT_MASK) != VAR_STAT_FREE);
|
|
|
|
assert(!IsObject(entryValue));
|
|
|
|
type = (game::VariableType)(entryValue->w.status & VAR_MASK);
|
|
newEntryValue = &game::gScrVarGlob[inst].childVariables[game::gScrVarGlob[inst].childVariables[game::GetVariableIndexInternal(inst, newParentId, entryValue->w.status >> VAR_NAME_BIT_SHIFT)].hash.id];
|
|
|
|
assert((newEntryValue->w.type & VAR_MASK) == game::VAR_UNDEFINED);
|
|
|
|
newEntryValue->w.status |= type;
|
|
|
|
if (type == game::VAR_POINTER)
|
|
{
|
|
if ((game::gScrVarGlob[inst].parentVariables[entryValue->u.u.intValue + 1].w.status & VAR_MASK) == game::VAR_ARRAY)
|
|
{
|
|
newEntryValue->u.u.pointerValue = game::Scr_AllocArray(inst);
|
|
game::CopyArray(inst, entryValue->u.u.pointerValue, newEntryValue->u.u.pointerValue);
|
|
}
|
|
else
|
|
{
|
|
newEntryValue->u.u.pointerValue = entryValue->u.u.pointerValue;
|
|
game::AddRefToObject(inst, entryValue->u.u.pointerValue);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
assert(type != game::VAR_STACK);
|
|
|
|
auto tmp = entryValue->u.o.u;
|
|
newEntryValue->u.u.stackValue = entryValue->u.u.stackValue;
|
|
newEntryValue->u.o.u = tmp;
|
|
game::AddRefToValue(inst, type, entryValue->u.u);
|
|
}
|
|
|
|
nextSibling = game::gScrVarGlob[inst].childVariables[id].nextSibling;
|
|
if (!nextSibling)
|
|
{
|
|
break;
|
|
}
|
|
|
|
id = game::gScrVarGlob[inst].childVariables[nextSibling].hash.id;
|
|
|
|
assert(id);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Completed
|
|
void SetVariableValue(game::scriptInstance_t inst, game::VariableValue* value, unsigned int id)
|
|
{
|
|
game::VariableValueInternal* entryValue;
|
|
|
|
assert(id);
|
|
|
|
assert(value->type < game::VAR_THREAD);
|
|
|
|
assert(value->type >= game::VAR_UNDEFINED && value->type < game::VAR_COUNT);
|
|
|
|
assert(value->type != game::VAR_STACK);
|
|
|
|
entryValue = &game::gScrVarGlob[inst].childVariables[id];
|
|
|
|
assert((entryValue->w.status & VAR_STAT_MASK) != VAR_STAT_FREE);
|
|
|
|
assert(!IsObject(entryValue));
|
|
|
|
assert((entryValue->w.type & VAR_MASK) != game::VAR_STACK);
|
|
|
|
game::RemoveRefToValueInternal(inst, (game::VariableType)(entryValue->w.status & VAR_MASK), entryValue->u.u);
|
|
entryValue->w.status &= ~VAR_MASK;
|
|
entryValue->w.status |= value->type;
|
|
entryValue->u.u.intValue = value->u.intValue;
|
|
}
|
|
|
|
// Completed
|
|
void SetVariableEntityFieldValue(game::scriptInstance_t inst, unsigned int entId, unsigned int fieldName, game::VariableValue* value)
|
|
{
|
|
game::VariableValueInternal* entValue;
|
|
game::VariableValueInternal* entryValue;
|
|
unsigned int fieldId;
|
|
|
|
assert(value->type < game::VAR_THREAD);
|
|
|
|
assert(value->type != game::VAR_STACK);
|
|
|
|
entValue = &game::gScrVarGlob[inst].parentVariables[entId + 1];
|
|
|
|
assert((entValue->w.type & VAR_MASK) == game::VAR_ENTITY);
|
|
|
|
assert((entValue->w.classnum >> VAR_NAME_BIT_SHIFT) < game::CLASS_NUM_COUNT);
|
|
|
|
fieldId = game::FindArrayVariable(game::gScrClassMap[inst][entValue->w.status >> VAR_NAME_BIT_SHIFT].id, fieldName, inst);
|
|
if (!fieldId || !game::SetEntityFieldValue(inst, game::gScrVarGlob[inst].childVariables[fieldId].u.u.intValue, entValue->u.o.u.entnum & VAR_ENT_MASK, (game::classNum_e)(entValue->w.status >> VAR_NAME_BIT_SHIFT), entValue->u.o.u.entnum >> VAR_CLIENT_MASK, value))
|
|
{
|
|
entryValue = &game::gScrVarGlob[inst].childVariables[game::GetNewVariable(inst, fieldName, entId)];
|
|
|
|
assert((entryValue->w.type & VAR_MASK) == game::VAR_UNDEFINED);
|
|
|
|
entryValue->w.status |= value->type;
|
|
entryValue->u.u.intValue = value->u.intValue;
|
|
}
|
|
}
|
|
|
|
// Completed
|
|
game::VariableValue Scr_EvalVariable(game::scriptInstance_t inst, unsigned int id)
|
|
{
|
|
game::VariableValueInternal* entryValue;
|
|
game::VariableValue value;
|
|
|
|
entryValue = &game::gScrVarGlob[inst].childVariables[id];
|
|
|
|
assert(((entryValue->w.status & VAR_STAT_MASK) != VAR_STAT_FREE) || !id);
|
|
|
|
value.type = (game::VariableType)(entryValue->w.status & VAR_MASK);
|
|
|
|
assert(value.type < game::VAR_THREAD);
|
|
|
|
value.u.intValue = entryValue->u.u.intValue;
|
|
game::AddRefToValue(inst, value.type, value.u);
|
|
return value;
|
|
}
|
|
|
|
// Completed
|
|
unsigned int Scr_EvalVariableObject(game::scriptInstance_t inst, unsigned int id)
|
|
{
|
|
game::VariableValueInternal* entryValue;
|
|
game::VariableType type;
|
|
|
|
entryValue = &game::gScrVarGlob[inst].childVariables[id];
|
|
|
|
assert(((entryValue->w.status & VAR_STAT_MASK) != VAR_STAT_FREE) || !id);
|
|
|
|
type = (game::VariableType)(entryValue->w.status & VAR_MASK);
|
|
if (type == game::VAR_POINTER && (type = (game::VariableType)(game::gScrVarGlob[inst].parentVariables[entryValue->u.u.stringValue + 1].w.status & VAR_MASK), (int)type < (int)game::FIRST_NONFIELD_OBJECT))
|
|
{
|
|
assert((int)type >= (int)game::FIRST_OBJECT);
|
|
|
|
return entryValue->u.u.stringValue;
|
|
}
|
|
else
|
|
{
|
|
game::Scr_Error(game::va("%s is not a field object", game::var_typename[type]), inst, false);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
// Completed
|
|
game::VariableValue Scr_EvalVariableEntityField(unsigned int entId, game::scriptInstance_t inst, unsigned int fieldName)
|
|
{
|
|
game::VariableValue result;
|
|
game::VariableValueInternal* entValue;
|
|
unsigned int fieldId;
|
|
|
|
entValue = &game::gScrVarGlob[inst].parentVariables[entId + 1];
|
|
|
|
assert((entValue->w.type & VAR_MASK) == game::VAR_ENTITY);
|
|
|
|
assert((entValue->w.classnum >> VAR_NAME_BIT_SHIFT) < game::CLASS_NUM_COUNT);
|
|
|
|
fieldId = game::FindArrayVariable(game::gScrClassMap[inst][entValue->w.status >> 8].id, fieldName, inst);
|
|
|
|
if (!fieldId)
|
|
{
|
|
result.u.intValue = 0;
|
|
result.type = game::VAR_UNDEFINED;
|
|
return result;
|
|
}
|
|
|
|
result = game::GetEntityFieldValue(game::gScrVarGlob[inst].childVariables[fieldId].u.u.intValue, entValue->u.o.u.entnum & VAR_ENT_MASK, inst, entValue->w.status >> VAR_NAME_BIT_SHIFT, entValue->u.o.u.entnum >> VAR_CLIENT_MASK);
|
|
|
|
if (result.type == game::VAR_POINTER)
|
|
{
|
|
// t5 doesnt do this
|
|
auto parentId = result.u.intValue;
|
|
auto newParentId = result.u.intValue;
|
|
auto parentValue = &game::gScrVarGlob[inst].parentVariables[result.u.intValue + 1];
|
|
|
|
if ((parentValue->w.status & VAR_MASK) == game::VAR_ARRAY)
|
|
{
|
|
if (parentValue->u.next)
|
|
{
|
|
game::RemoveRefToObject(result.u.stringValue, inst);
|
|
newParentId = game::Scr_AllocArray(inst);
|
|
game::CopyArray(inst, parentId, newParentId);
|
|
}
|
|
|
|
result.u.intValue = newParentId;
|
|
result.type = game::VAR_POINTER;
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
// Completed
|
|
game::VariableValue Scr_EvalVariableField(game::scriptInstance_t inst, unsigned int id)
|
|
{
|
|
if (id)
|
|
{
|
|
return game::Scr_EvalVariable(inst, id);
|
|
}
|
|
|
|
return game::Scr_EvalVariableEntityField(game::gScrVarPub[inst].entId, inst, game::gScrVarPub[inst].entFieldName);
|
|
}
|
|
|
|
// Completed
|
|
void Scr_EvalSizeValue(game::scriptInstance_t inst, game::VariableValue* value)
|
|
{
|
|
game::VariableValueInternal* entryValue;
|
|
const char* error_message;
|
|
unsigned int id;
|
|
|
|
if (value->type == game::VAR_POINTER)
|
|
{
|
|
id = value->u.intValue;
|
|
entryValue = &game::gScrVarGlob[inst].parentVariables[id + 1];
|
|
value->type = game::VAR_INTEGER;
|
|
|
|
if ((entryValue->w.status & VAR_MASK) == game::VAR_ARRAY)
|
|
{
|
|
value->u.intValue = entryValue->u.o.u.size;
|
|
}
|
|
else
|
|
{
|
|
value->u.intValue = 1;
|
|
}
|
|
|
|
game::RemoveRefToObject(id, inst);
|
|
}
|
|
else if (value->type == game::VAR_STRING)
|
|
{
|
|
value->type = game::VAR_INTEGER;
|
|
id = value->u.stringValue;
|
|
value->u.intValue = strlen(game::SL_ConvertToString(id, inst));
|
|
game::SL_RemoveRefToString(id, inst);
|
|
}
|
|
else
|
|
{
|
|
assert(value->type != game::VAR_STACK);
|
|
|
|
error_message = game::va("size cannot be applied to %s", game::var_typename[value->type]);
|
|
game::RemoveRefToValueInternal(inst, value->type, value->u);
|
|
value->type = game::VAR_UNDEFINED;
|
|
game::Scr_Error(error_message, inst, 0);
|
|
}
|
|
}
|
|
|
|
// Restored
|
|
unsigned int AllocObject(game::scriptInstance_t inst)
|
|
{
|
|
game::VariableValueInternal* entryValue;
|
|
unsigned int id;
|
|
|
|
id = game::AllocVariable(inst);
|
|
entryValue = &game::gScrVarGlob[inst].parentVariables[id + 1];
|
|
entryValue->w.status = VAR_STAT_EXTERNAL;
|
|
|
|
assert((entryValue->w.type & VAR_MASK) == game::VAR_UNDEFINED);
|
|
|
|
entryValue->w.status |= game::VAR_OBJECT;
|
|
entryValue->u.o.refCount = 0;
|
|
return id;
|
|
}
|
|
|
|
// Completed
|
|
unsigned int GetObject(game::scriptInstance_t inst, unsigned int id)
|
|
{
|
|
game::VariableValueInternal* entryValue;
|
|
|
|
assert(id);
|
|
|
|
entryValue = &game::gScrVarGlob[inst].childVariables[id];
|
|
|
|
assert((entryValue->w.status & VAR_STAT_MASK) != VAR_STAT_FREE);
|
|
|
|
assert((entryValue->w.type & VAR_MASK) == game::VAR_UNDEFINED || (entryValue->w.type & VAR_MASK) == game::VAR_POINTER);
|
|
|
|
if ((entryValue->w.status & VAR_MASK) == game::VAR_UNDEFINED)
|
|
{
|
|
entryValue->w.status |= game::VAR_POINTER;
|
|
entryValue->u.u.pointerValue = game::AllocObject(inst);
|
|
}
|
|
|
|
assert((entryValue->w.type & VAR_MASK) == game::VAR_POINTER);
|
|
|
|
return entryValue->u.u.pointerValue;
|
|
}
|
|
|
|
// Completed
|
|
unsigned int GetArray(game::scriptInstance_t inst, unsigned int id)
|
|
{
|
|
game::VariableValueInternal* entryValue;
|
|
|
|
assert(id);
|
|
|
|
entryValue = &game::gScrVarGlob[inst].childVariables[id];
|
|
|
|
assert((entryValue->w.status & VAR_STAT_MASK) != VAR_STAT_FREE);
|
|
|
|
assert((entryValue->w.type & VAR_MASK) == game::VAR_UNDEFINED || (entryValue->w.type & VAR_MASK) == game::VAR_POINTER);
|
|
|
|
if ((entryValue->w.status & VAR_MASK) == game::VAR_UNDEFINED)
|
|
{
|
|
entryValue->w.status |= game::VAR_POINTER;
|
|
entryValue->u.u.pointerValue = game::Scr_AllocArray(inst);
|
|
}
|
|
|
|
assert((entryValue->w.type & VAR_MASK) == game::VAR_POINTER);
|
|
|
|
return entryValue->u.u.pointerValue;
|
|
}
|
|
|
|
// Completed
|
|
void Scr_EvalBoolComplement(game::scriptInstance_t inst, game::VariableValue* value)
|
|
{
|
|
game::VariableType type;
|
|
|
|
if (value->type == game::VAR_INTEGER)
|
|
{
|
|
value->u.intValue = ~value->u.intValue;
|
|
}
|
|
else
|
|
{
|
|
type = value->type;
|
|
game::RemoveRefToValueInternal(inst, type, value->u);
|
|
value->type = game::VAR_UNDEFINED;
|
|
game::Scr_Error(game::va("~ cannot be applied to \"%s\"", game::var_typename[type]), inst, 0);
|
|
}
|
|
}
|
|
|
|
// Completed
|
|
void Scr_CastBool(game::scriptInstance_t inst, game::VariableValue* value)
|
|
{
|
|
game::VariableType type;
|
|
|
|
if (value->type == game::VAR_INTEGER)
|
|
{
|
|
value->u.intValue = value->u.intValue != 0;
|
|
}
|
|
else if (value->type == game::VAR_FLOAT)
|
|
{
|
|
value->type = game::VAR_INTEGER;
|
|
value->u.intValue = value->u.floatValue != 0.0;
|
|
}
|
|
else
|
|
{
|
|
type = value->type;
|
|
game::RemoveRefToValueInternal(inst, type, value->u);
|
|
value->type = game::VAR_UNDEFINED;
|
|
game::Scr_Error(game::va("cannot cast %s to bool", game::var_typename[type]), inst, 0);
|
|
}
|
|
}
|
|
|
|
// Completed
|
|
char Scr_CastString(game::scriptInstance_t inst, game::VariableValue* value)
|
|
{
|
|
const float* constTempVector;
|
|
|
|
switch (value->type)
|
|
{
|
|
case game::VAR_STRING:
|
|
return 1;
|
|
case game::VAR_INTEGER:
|
|
value->type = game::VAR_STRING;
|
|
value->u.stringValue = game::SL_GetStringForInt(value->u.intValue, inst);
|
|
return 1;
|
|
case game::VAR_FLOAT:
|
|
value->type = game::VAR_STRING;
|
|
value->u.stringValue = game::SL_GetStringForFloat(value->u.floatValue, inst);
|
|
return 1;
|
|
case game::VAR_VECTOR:
|
|
value->type = game::VAR_STRING;
|
|
constTempVector = value->u.vectorValue;
|
|
value->u.stringValue = game::SL_GetStringForVector((float*)value->u.vectorValue, inst);
|
|
game::RemoveRefToVector(constTempVector, inst);
|
|
return 1;
|
|
default:
|
|
game::gScrVarPub[inst].error_message = (char*)game::va("cannot cast %s to string", game::var_typename[value->type]);
|
|
game::RemoveRefToValueInternal(inst, value->type, value->u);
|
|
value->type = game::VAR_UNDEFINED;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
// Restored
|
|
game::VariableType GetValueType(game::scriptInstance_t inst, unsigned int id)
|
|
{
|
|
assert((game::gScrVarGlob[inst].childVariables[id].w.status & VAR_STAT_MASK) != VAR_STAT_FREE);
|
|
|
|
return (game::VariableType)(game::gScrVarGlob[inst].childVariables[id].w.status & VAR_MASK);
|
|
}
|
|
|
|
// Restored
|
|
game::VariableType GetObjectType(game::scriptInstance_t inst, unsigned int id)
|
|
{
|
|
assert((game::gScrVarGlob[inst].parentVariables[id + 1].w.status & VAR_STAT_MASK) != VAR_STAT_FREE);
|
|
|
|
return (game::VariableType)(game::gScrVarGlob[inst].parentVariables[id + 1].w.status & VAR_MASK);
|
|
}
|
|
|
|
// Almost completed
|
|
void Scr_CastDebugString(game::scriptInstance_t inst, game::VariableValue* value)
|
|
{
|
|
unsigned int stringValue;
|
|
const char* s;
|
|
const char* sa;
|
|
|
|
switch (value->type)
|
|
{
|
|
case game::VAR_POINTER:
|
|
sa = game::var_typename[game::GetObjectType(inst, value->u.intValue)];
|
|
stringValue = game::SL_GetString_(sa, inst, 0);
|
|
break;
|
|
case game::VAR_STRING:
|
|
case game::VAR_VECTOR:
|
|
case game::VAR_FLOAT:
|
|
case game::VAR_INTEGER:
|
|
game::Scr_CastString(inst, value);
|
|
return;
|
|
case game::VAR_ISTRING:
|
|
value->type = game::VAR_STRING;
|
|
return;
|
|
case game::VAR_ANIMATION:
|
|
//s = game::XAnimGetAnimDebugName(game::Scr_GetAnims(HIWORD(value->u.intValue), game::SCRIPTINSTANCE_SERVER), value->u.intValue);
|
|
s = ""; // TODO
|
|
stringValue = game::SL_GetString_(s, inst, 0);
|
|
break;
|
|
default:
|
|
stringValue = game::SL_GetString_(game::var_typename[value->type], inst, 0);
|
|
break;
|
|
}
|
|
|
|
game::RemoveRefToValueInternal(inst, value->type, value->u);
|
|
value->type = game::VAR_STRING;
|
|
value->u.intValue = stringValue;
|
|
}
|
|
|
|
// Completed
|
|
void Scr_ClearVector(game::scriptInstance_t inst, game::VariableValue* value)
|
|
{
|
|
int i;
|
|
|
|
for (i = 2;
|
|
i >= 0;
|
|
--i)
|
|
{
|
|
game::RemoveRefToValueInternal(inst, value[i].type, value[i].u);
|
|
}
|
|
value->type = game::VAR_UNDEFINED;
|
|
}
|
|
|
|
// Restored
|
|
float* Scr_AllocVector_(game::scriptInstance_t inst, const float* v)
|
|
{
|
|
float* vectorValue;
|
|
|
|
vectorValue = game::Scr_AllocVector(inst);
|
|
vectorValue[0] = v[0];
|
|
vectorValue[1] = v[1];
|
|
vectorValue[2] = v[2];
|
|
return vectorValue;
|
|
}
|
|
|
|
// Completed
|
|
void Scr_CastVector(game::scriptInstance_t inst, game::VariableValue* value)
|
|
{
|
|
int type;
|
|
int i;
|
|
float vec[3];
|
|
|
|
for (i = 2;
|
|
i >= 0;
|
|
--i)
|
|
{
|
|
type = value[i].type;
|
|
if (type == game::VAR_FLOAT)
|
|
{
|
|
vec[2 - i] = value[i].u.floatValue;
|
|
}
|
|
else
|
|
{
|
|
if (type != game::VAR_INTEGER)
|
|
{
|
|
game::gScrVarPub[inst].error_index = i + 1;
|
|
game::Scr_ClearVector(inst, value);
|
|
game::Scr_Error(game::va("type %s is not a float", game::var_typename[type]), inst, 0);
|
|
return;
|
|
}
|
|
vec[2 - i] = value[i].u.intValue;
|
|
}
|
|
}
|
|
|
|
value->type = game::VAR_VECTOR;
|
|
value->u.vectorValue = game::Scr_AllocVector_(inst, vec);
|
|
}
|
|
|
|
// Completed
|
|
game::VariableUnion Scr_EvalFieldObject(game::VariableValue* value, game::scriptInstance_t inst, unsigned int tempVariable)
|
|
{
|
|
game::VariableUnion result;
|
|
unsigned int type;
|
|
game::VariableValue tempValue;
|
|
|
|
type = value->type;
|
|
|
|
if (type == game::VAR_POINTER && (type = game::gScrVarGlob[inst].parentVariables[value->u.intValue + 1].w.status & VAR_MASK, type < game::FIRST_NONFIELD_OBJECT))
|
|
{
|
|
assert(type >= game::FIRST_OBJECT);
|
|
|
|
tempValue.type = game::VAR_POINTER;
|
|
tempValue.u.intValue = value->u.intValue;
|
|
game::SetVariableValue(inst, &tempValue, tempVariable);
|
|
result.intValue = tempValue.u.intValue;
|
|
}
|
|
else
|
|
{
|
|
game::RemoveRefToValueInternal(inst, value->type, value->u);
|
|
game::Scr_Error(game::va("%s is not a field object", game::var_typename[type]), inst, 0);
|
|
result.intValue = 0;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
// Completed
|
|
void Scr_UnmatchingTypesError(game::scriptInstance_t inst, game::VariableValue* value2, game::VariableValue* value1)
|
|
{
|
|
int type1;
|
|
int type2;
|
|
char* error_message;
|
|
|
|
if (game::gScrVarPub[inst].error_message)
|
|
{
|
|
error_message = 0;
|
|
}
|
|
else
|
|
{
|
|
type1 = value1->type;
|
|
type2 = value2->type;
|
|
game::Scr_CastDebugString(inst, value1);
|
|
game::Scr_CastDebugString(inst, value2);
|
|
|
|
assert(value1->type == game::VAR_STRING);
|
|
|
|
assert(value2->type == game::VAR_STRING);
|
|
|
|
error_message = (char*)game::va("pair '%s' and '%s' has unmatching types '%s' and '%s'", game::SL_ConvertToString(value1->u.intValue, inst), game::SL_ConvertToString(value2->u.intValue, inst), game::var_typename[type1], game::var_typename[type2]);
|
|
}
|
|
|
|
game::RemoveRefToValueInternal(inst, value1->type, value1->u);
|
|
value1->type = game::VAR_UNDEFINED;
|
|
game::RemoveRefToValueInternal(inst, value2->type, value2->u);
|
|
value2->type = game::VAR_UNDEFINED;
|
|
game::Scr_Error(error_message, inst, 0);
|
|
}
|
|
|
|
// Completed
|
|
void Scr_CastWeakerPair(game::VariableValue* value2, game::VariableValue* value1, game::scriptInstance_t inst)
|
|
{
|
|
game::VariableType type1;
|
|
float* tempVector;
|
|
float* tempVectora;
|
|
float* tempVectorb;
|
|
game::VariableType type2;
|
|
float* tempVectorc;
|
|
|
|
type1 = value1->type;
|
|
type2 = value2->type;
|
|
|
|
if (type1 != type2)
|
|
{
|
|
if (type1 == game::VAR_FLOAT && type2 == game::VAR_INTEGER)
|
|
{
|
|
value2->type = game::VAR_FLOAT;
|
|
value2->u.floatValue = value2->u.intValue;
|
|
return;
|
|
}
|
|
|
|
if (type1 == game::VAR_INTEGER && type2 == game::VAR_FLOAT)
|
|
{
|
|
value1->type = game::VAR_FLOAT;
|
|
value1->u.floatValue = value1->u.intValue;
|
|
return;
|
|
}
|
|
|
|
if (type1 == game::VAR_VECTOR)
|
|
{
|
|
if (type2 == game::VAR_FLOAT)
|
|
{
|
|
tempVector = game::Scr_AllocVector(inst);
|
|
tempVector[0] = value2->u.floatValue;
|
|
tempVector[1] = value2->u.floatValue;
|
|
tempVector[2] = value2->u.floatValue;
|
|
value2->u.vectorValue = tempVector;
|
|
value2->type = game::VAR_VECTOR;
|
|
return;
|
|
}
|
|
|
|
if (type2 == game::VAR_INTEGER)
|
|
{
|
|
tempVectorc = game::Scr_AllocVector(inst);
|
|
tempVectorc[0] = value2->u.intValue;
|
|
tempVectorc[1] = value2->u.intValue;
|
|
tempVectorc[2] = value2->u.intValue;
|
|
value2->u.vectorValue = tempVectorc;
|
|
value2->type = game::VAR_VECTOR;
|
|
return;
|
|
}
|
|
}
|
|
if (type2 != game::VAR_VECTOR)
|
|
{
|
|
game::Scr_UnmatchingTypesError(inst, value2, value1);
|
|
return;
|
|
}
|
|
|
|
if (type1 == game::VAR_FLOAT)
|
|
{
|
|
tempVectora = game::Scr_AllocVector(inst);
|
|
tempVectora[0] = value1->u.floatValue;
|
|
tempVectora[1] = value1->u.floatValue;
|
|
tempVectora[2] = value1->u.floatValue;
|
|
value1->u.vectorValue = tempVectora;
|
|
value1->type = game::VAR_VECTOR;
|
|
return;
|
|
}
|
|
|
|
if (type1 == game::VAR_INTEGER)
|
|
{
|
|
tempVectorb = game::Scr_AllocVector(inst);
|
|
tempVectorb[0] = value1->u.intValue;
|
|
tempVectorb[1] = value1->u.intValue;
|
|
tempVectorb[2] = value1->u.intValue;
|
|
value1->u.vectorValue = tempVectorb;
|
|
value1->type = game::VAR_VECTOR;
|
|
}
|
|
else
|
|
{
|
|
game::Scr_UnmatchingTypesError(inst, value2, value1);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// Completed
|
|
void Scr_CastWeakerStringPair(game::VariableValue* value2, game::VariableValue* value1, game::scriptInstance_t inst)
|
|
{
|
|
game::VariableType type1;
|
|
game::VariableType type2;
|
|
const float* constTempVector;
|
|
const float* constTempVectora;
|
|
|
|
type1 = value1->type;
|
|
type2 = value2->type;
|
|
|
|
if (type1 != type2)
|
|
{
|
|
if (type1 < type2)
|
|
{
|
|
if (type1 == game::VAR_STRING)
|
|
{
|
|
switch (type2)
|
|
{
|
|
case game::VAR_VECTOR:
|
|
value2->type = game::VAR_STRING;
|
|
constTempVector = value2->u.vectorValue;
|
|
value2->u.stringValue = game::SL_GetStringForVector((float*)value2->u.vectorValue, inst);
|
|
game::RemoveRefToVector(constTempVector, inst);
|
|
return;
|
|
case game::VAR_FLOAT:
|
|
value2->type = game::VAR_STRING;
|
|
value2->u.intValue = game::SL_GetStringForFloat(value2->u.floatValue, inst);
|
|
return;
|
|
case game::VAR_INTEGER:
|
|
value2->type = game::VAR_STRING;
|
|
value2->u.intValue = game::SL_GetStringForInt(value2->u.intValue, inst);
|
|
return;
|
|
}
|
|
}
|
|
else if (type1 != game::VAR_FLOAT)
|
|
{
|
|
game::Scr_UnmatchingTypesError(inst, value2, value1);
|
|
return;
|
|
}
|
|
|
|
if (type2 == game::VAR_INTEGER)
|
|
{
|
|
value2->type = game::VAR_FLOAT;
|
|
value2->u.floatValue = value2->u.intValue;
|
|
return;
|
|
}
|
|
|
|
game::Scr_UnmatchingTypesError(inst, value2, value1);
|
|
return;
|
|
}
|
|
|
|
if (type2 == game::VAR_STRING)
|
|
{
|
|
switch (type1)
|
|
{
|
|
case game::VAR_VECTOR:
|
|
value1->type = game::VAR_STRING;
|
|
constTempVectora = value1->u.vectorValue;
|
|
value1->u.stringValue = game::SL_GetStringForVector((float*)value1->u.vectorValue, inst);
|
|
game::RemoveRefToVector(constTempVectora, inst);
|
|
return;
|
|
case game::VAR_FLOAT:
|
|
value1->type = game::VAR_STRING;
|
|
value1->u.intValue = game::SL_GetStringForFloat(value1->u.floatValue, inst);
|
|
return;
|
|
case game::VAR_INTEGER:
|
|
value1->type = game::VAR_STRING;
|
|
value1->u.intValue = game::SL_GetStringForInt(value1->u.intValue, inst);
|
|
return;
|
|
}
|
|
}
|
|
else if (type2 != game::VAR_FLOAT)
|
|
{
|
|
game::Scr_UnmatchingTypesError(inst, value2, value1);
|
|
return;
|
|
}
|
|
|
|
if (type1 == game::VAR_INTEGER)
|
|
{
|
|
value1->type = game::VAR_FLOAT;
|
|
value1->u.floatValue = value1->u.intValue;
|
|
return;
|
|
}
|
|
|
|
game::Scr_UnmatchingTypesError(inst, value2, value1);
|
|
return;
|
|
}
|
|
}
|
|
|
|
// Completed
|
|
void Scr_EvalOr(game::VariableValue* value1, game::VariableValue* value2, game::scriptInstance_t inst)
|
|
{
|
|
if (value1->type == game::VAR_INTEGER && value2->type == game::VAR_INTEGER)
|
|
{
|
|
value1->u.intValue |= value2->u.intValue;
|
|
}
|
|
else
|
|
{
|
|
game::Scr_UnmatchingTypesError(inst, value2, value1);
|
|
}
|
|
}
|
|
|
|
// Completed
|
|
void Scr_EvalExOr(game::VariableValue* value1, game::VariableValue* value2, game::scriptInstance_t inst)
|
|
{
|
|
if (value1->type == game::VAR_INTEGER && value2->type == game::VAR_INTEGER)
|
|
{
|
|
value1->u.intValue ^= value2->u.intValue;
|
|
}
|
|
else
|
|
{
|
|
game::Scr_UnmatchingTypesError(inst, value2, value1);
|
|
}
|
|
}
|
|
|
|
// Completed
|
|
void Scr_EvalAnd(game::VariableValue* value1, game::VariableValue* value2, game::scriptInstance_t inst)
|
|
{
|
|
if (value1->type == game::VAR_INTEGER && value2->type == game::VAR_INTEGER)
|
|
{
|
|
value1->u.intValue &= value2->u.intValue;
|
|
}
|
|
else
|
|
{
|
|
game::Scr_UnmatchingTypesError(inst, value2, value1);
|
|
}
|
|
}
|
|
|
|
// Completed
|
|
void Scr_EvalEquality(game::VariableValue* value1, game::scriptInstance_t inst, game::VariableValue* value2)
|
|
{
|
|
int tempInt;
|
|
int tempInta;
|
|
|
|
game::Scr_CastWeakerPair(value2, value1, inst);
|
|
|
|
assert(value1->type == value2->type);
|
|
|
|
switch (value1->type)
|
|
{
|
|
case game::VAR_UNDEFINED:
|
|
value1->type = game::VAR_INTEGER;
|
|
value1->u.intValue = 1; // undefined evals to true??
|
|
break;
|
|
case game::VAR_POINTER:
|
|
if (((game::gScrVarGlob[inst].childVariables[value1->u.intValue].w.status & VAR_MASK) == game::VAR_ARRAY || (game::gScrVarGlob[inst].childVariables[value2->u.intValue].w.status & VAR_MASK) == game::VAR_ARRAY) && !game::gScrVarPub[inst].evaluate)
|
|
{
|
|
game::Scr_UnmatchingTypesError(inst, value2, value1);
|
|
break;
|
|
}
|
|
value1->type = game::VAR_INTEGER;
|
|
tempInta = value1->u.pointerValue == value2->u.pointerValue;
|
|
game::RemoveRefToObject(value1->u.intValue, inst);
|
|
game::RemoveRefToObject(value2->u.intValue, inst);
|
|
value1->u.intValue = tempInta;
|
|
break;
|
|
case game::VAR_STRING:
|
|
case game::VAR_ISTRING:
|
|
value1->type = game::VAR_INTEGER;
|
|
tempInt = value1->u.stringValue == value2->u.stringValue;
|
|
game::SL_RemoveRefToString(value1->u.intValue, inst);
|
|
game::SL_RemoveRefToString(value2->u.intValue, inst);
|
|
value1->u.intValue = tempInt;
|
|
break;
|
|
case game::VAR_VECTOR:
|
|
{
|
|
value1->type = game::VAR_INTEGER;
|
|
auto isEqual = *value1->u.vectorValue == *value2->u.vectorValue && *(value1->u.vectorValue + 1) == *(value2->u.vectorValue + 1) && *(value1->u.vectorValue + 2) == *(value2->u.vectorValue + 2);
|
|
game::RemoveRefToVector(value1->u.vectorValue, inst);
|
|
game::RemoveRefToVector(value2->u.vectorValue, inst);
|
|
value1->u.intValue = isEqual;
|
|
break;
|
|
}
|
|
case game::VAR_FLOAT:
|
|
value1->type = game::VAR_INTEGER;
|
|
value1->u.intValue = (fabs(value2->u.floatValue - value1->u.floatValue) < 0.000001f);
|
|
break;
|
|
case game::VAR_INTEGER:
|
|
value1->u.intValue = value1->u.intValue == value2->u.intValue;
|
|
break;
|
|
case game::VAR_FUNCTION:
|
|
value1->type = game::VAR_INTEGER;
|
|
value1->u.intValue = value1->u.codePosValue == value2->u.codePosValue;
|
|
break;
|
|
case game::VAR_ANIMATION:
|
|
value1->type = game::VAR_INTEGER;
|
|
value1->u.intValue = value1->u.intValue == value2->u.intValue;
|
|
break;
|
|
default:
|
|
game::Scr_UnmatchingTypesError(inst, value2, value1);
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Completed
|
|
void Scr_EvalLess(game::VariableValue* value2, game::VariableValue* value1, game::scriptInstance_t inst)
|
|
{
|
|
game::Scr_CastWeakerPair(value2, value1, inst);
|
|
|
|
assert(value1->type == value2->type);
|
|
|
|
if (value1->type == game::VAR_FLOAT)
|
|
{
|
|
value1->type = game::VAR_INTEGER;
|
|
value1->u.intValue = value2->u.floatValue > value1->u.floatValue;
|
|
}
|
|
else if (value1->type == game::VAR_INTEGER)
|
|
{
|
|
value1->u.intValue = value1->u.intValue < value2->u.intValue;
|
|
}
|
|
else
|
|
{
|
|
game::Scr_UnmatchingTypesError(inst, value2, value1);
|
|
}
|
|
}
|
|
|
|
// Completed
|
|
void Scr_EvalGreaterEqual(game::scriptInstance_t inst, game::VariableValue* value1, game::VariableValue* value2)
|
|
{
|
|
game::Scr_EvalLess(value2, value1, inst);
|
|
|
|
assert((value1->type == game::VAR_INTEGER) || (value1->type == game::VAR_UNDEFINED));
|
|
|
|
value1->u.intValue = value1->u.intValue == 0;
|
|
}
|
|
|
|
// Completed
|
|
void Scr_EvalGreater(game::VariableValue* value2, game::VariableValue* value1, game::scriptInstance_t inst)
|
|
{
|
|
game::Scr_CastWeakerPair(value2, value1, inst);
|
|
|
|
assert(value1->type == value2->type);
|
|
|
|
if (value1->type == game::VAR_FLOAT)
|
|
{
|
|
value1->type = game::VAR_INTEGER;
|
|
value1->u.intValue = value1->u.floatValue > value2->u.floatValue;
|
|
}
|
|
else if (value1->type == game::VAR_INTEGER)
|
|
{
|
|
value1->u.intValue = value1->u.intValue > value2->u.intValue;
|
|
}
|
|
else
|
|
{
|
|
game::Scr_UnmatchingTypesError(inst, value2, value1);
|
|
}
|
|
}
|
|
|
|
// Completed
|
|
void Scr_EvalLessEqual(game::scriptInstance_t inst, game::VariableValue* value1, game::VariableValue* value2)
|
|
{
|
|
game::Scr_EvalGreater(value2, value1, inst);
|
|
|
|
assert((value1->type == game::VAR_INTEGER) || (value1->type == game::VAR_UNDEFINED));
|
|
|
|
value1->u.intValue = value1->u.intValue == 0;
|
|
}
|
|
|
|
// Completed
|
|
void Scr_EvalShiftLeft(game::VariableValue* value1, game::VariableValue* value2, game::scriptInstance_t inst)
|
|
{
|
|
if (value1->type == game::VAR_INTEGER && value2->type == game::VAR_INTEGER)
|
|
{
|
|
value1->u.intValue <<= value2->u.intValue;
|
|
}
|
|
else
|
|
{
|
|
game::Scr_UnmatchingTypesError(inst, value2, value1);
|
|
}
|
|
}
|
|
|
|
// Completed
|
|
void Scr_EvalShiftRight(game::VariableValue* value1, game::VariableValue* value2, game::scriptInstance_t inst)
|
|
{
|
|
if (value1->type == game::VAR_INTEGER && value2->type == game::VAR_INTEGER)
|
|
{
|
|
value1->u.intValue >>= value2->u.intValue;
|
|
}
|
|
else
|
|
{
|
|
game::Scr_UnmatchingTypesError(inst, value2, value1);
|
|
}
|
|
}
|
|
|
|
// Completed
|
|
void Scr_EvalPlus(game::scriptInstance_t inst, game::VariableValue* value1, game::VariableValue* value2)
|
|
{
|
|
unsigned int stringValue;
|
|
unsigned int str1Len;
|
|
char* str1;
|
|
char* str2;
|
|
char str[8192];
|
|
unsigned int len;
|
|
|
|
game::Scr_CastWeakerStringPair(value2, value1, inst);
|
|
|
|
assert(value1->type == value2->type);
|
|
|
|
switch (value1->type)
|
|
{
|
|
case game::VAR_STRING:
|
|
str1 = game::SL_ConvertToString(value1->u.intValue, inst);
|
|
str2 = game::SL_ConvertToString(value2->u.intValue, inst);
|
|
str1Len = game::SL_GetStringLen(value1->u.intValue, inst);
|
|
len = str1Len + game::SL_GetStringLen(value2->u.intValue, inst) + 1;
|
|
if (len <= 0x2000)
|
|
{
|
|
strncpy(str, str1, str1Len);
|
|
str[str1Len] = '\0';
|
|
strncat(str, str2, len);
|
|
str[len - 1] = '\0';
|
|
|
|
stringValue = game::SL_GetStringOfSize(inst, str, 0, len);
|
|
game::SL_RemoveRefToString(value1->u.intValue, inst);
|
|
game::SL_RemoveRefToString(value2->u.intValue, inst);
|
|
value1->u.stringValue = stringValue;
|
|
}
|
|
else
|
|
{
|
|
game::SL_RemoveRefToString(value1->u.intValue, inst);
|
|
game::SL_RemoveRefToString(value2->u.intValue, inst);
|
|
value1->type = game::VAR_UNDEFINED;
|
|
value2->type = game::VAR_UNDEFINED;
|
|
game::Scr_Error(game::va("cannot concat \"%s\" and \"%s\" - max string length exceeded", str1, str2), inst, 0);
|
|
}
|
|
break;
|
|
case game::VAR_VECTOR:
|
|
{
|
|
auto vectorValue = game::Scr_AllocVector(inst);
|
|
vectorValue[0] = *value1->u.vectorValue + *value2->u.vectorValue;
|
|
vectorValue[1] = *(value1->u.vectorValue + 1) + *(value2->u.vectorValue + 1);
|
|
vectorValue[2] = *(value1->u.vectorValue + 2) + *(value2->u.vectorValue + 2);
|
|
game::RemoveRefToVector(value1->u.vectorValue, inst);
|
|
game::RemoveRefToVector(value2->u.vectorValue, inst);
|
|
value1->u.vectorValue = vectorValue;
|
|
break;
|
|
}
|
|
case game::VAR_FLOAT:
|
|
value1->u.floatValue = value1->u.floatValue + value2->u.floatValue;
|
|
break;
|
|
case game::VAR_INTEGER:
|
|
value1->u.intValue += value2->u.intValue;
|
|
break;
|
|
default:
|
|
game::Scr_UnmatchingTypesError(inst, value2, value1);
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Completed
|
|
void Scr_EvalMinus(game::VariableValue* value2, game::scriptInstance_t inst, game::VariableValue* value1)
|
|
{
|
|
float* tempVector;
|
|
|
|
game::Scr_CastWeakerPair(value2, value1, inst);
|
|
|
|
assert(value1->type == value2->type);
|
|
|
|
switch (value1->type)
|
|
{
|
|
case game::VAR_VECTOR:
|
|
tempVector = game::Scr_AllocVector(inst);
|
|
tempVector[0] = *value1->u.vectorValue - *value2->u.vectorValue;
|
|
tempVector[1] = *(value1->u.vectorValue + 1) - *(value2->u.vectorValue + 1);
|
|
tempVector[2] = *(value1->u.vectorValue + 2) - *(value2->u.vectorValue + 2);
|
|
game::RemoveRefToVector(value1->u.vectorValue, inst);
|
|
game::RemoveRefToVector(value2->u.vectorValue, inst);
|
|
value1->u.vectorValue = tempVector;
|
|
break;
|
|
case game::VAR_FLOAT:
|
|
value1->u.floatValue = value1->u.floatValue - value2->u.floatValue;
|
|
break;
|
|
case game::VAR_INTEGER:
|
|
value1->u.intValue -= value2->u.intValue;
|
|
break;
|
|
default:
|
|
game::Scr_UnmatchingTypesError(inst, value2, value1);
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Completed
|
|
void Scr_EvalMultiply(game::VariableValue* value2, game::scriptInstance_t inst, game::VariableValue* value1)
|
|
{
|
|
float* tempVector;
|
|
|
|
game::Scr_CastWeakerPair(value2, value1, inst);
|
|
|
|
assert(value1->type == value2->type);
|
|
|
|
switch (value1->type)
|
|
{
|
|
case game::VAR_VECTOR:
|
|
tempVector = game::Scr_AllocVector(inst);
|
|
tempVector[0] = *value1->u.vectorValue * *value2->u.vectorValue;
|
|
tempVector[1] = *(value1->u.vectorValue + 1) * *(value2->u.vectorValue + 1);
|
|
tempVector[2] = *(value1->u.vectorValue + 2) * *(value2->u.vectorValue + 2);
|
|
game::RemoveRefToVector(value2->u.vectorValue, inst);
|
|
game::RemoveRefToVector(value1->u.vectorValue, inst);
|
|
value1->u.vectorValue = tempVector;
|
|
break;
|
|
case game::VAR_FLOAT:
|
|
value1->u.floatValue = value1->u.floatValue * value2->u.floatValue;
|
|
break;
|
|
case game::VAR_INTEGER:
|
|
value1->u.intValue *= value2->u.intValue;
|
|
break;
|
|
default:
|
|
game::Scr_UnmatchingTypesError(inst, value2, value1);
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Completed
|
|
void Scr_EvalDivide(game::VariableValue* value2, game::scriptInstance_t inst, game::VariableValue* value1)
|
|
{
|
|
float* tempVector;
|
|
|
|
game::Scr_CastWeakerPair(value2, value1, inst);
|
|
|
|
assert(value1->type == value2->type);
|
|
|
|
switch (value1->type)
|
|
{
|
|
case game::VAR_VECTOR:
|
|
tempVector = game::Scr_AllocVector(inst);
|
|
|
|
if (*value2->u.vectorValue == 0.0f || *(value2->u.vectorValue + 1) == 0.0f || *(value2->u.vectorValue + 2) == 0.0f)
|
|
{
|
|
tempVector[0] = 0.0f;
|
|
tempVector[1] = 0.0f;
|
|
tempVector[2] = 0.0f;
|
|
game::RemoveRefToVector(value1->u.vectorValue, inst);
|
|
game::RemoveRefToVector(value2->u.vectorValue, inst);
|
|
value1->u.vectorValue = tempVector;
|
|
game::Scr_Error("divide by 0", inst, 0);
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
tempVector[0] = *value1->u.vectorValue / *value2->u.vectorValue;
|
|
tempVector[1] = *(value1->u.vectorValue + 1) / *(value2->u.vectorValue + 1);
|
|
tempVector[2] = *(value1->u.vectorValue + 2) / *(value2->u.vectorValue + 2);
|
|
game::RemoveRefToVector(value1->u.vectorValue, inst);
|
|
game::RemoveRefToVector(value2->u.vectorValue, inst);
|
|
value1->u.vectorValue = tempVector;
|
|
}
|
|
break;
|
|
case game::VAR_FLOAT:
|
|
if (value2->u.floatValue == 0.0)
|
|
{
|
|
value1->u.floatValue = 0.0f;
|
|
game::Scr_Error("divide by 0", inst, 0);
|
|
return;
|
|
}
|
|
|
|
value1->u.floatValue = value1->u.floatValue / value2->u.floatValue;
|
|
break;
|
|
case game::VAR_INTEGER:
|
|
value1->type = game::VAR_FLOAT;
|
|
if (value2->u.intValue)
|
|
{
|
|
value1->u.floatValue = (float)(value1->u.intValue) / value2->u.intValue;
|
|
return;
|
|
}
|
|
|
|
game::Scr_Error("divide by 0", inst, 0);
|
|
return;
|
|
default:
|
|
game::Scr_UnmatchingTypesError(inst, value2, value1);
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Completed
|
|
void Scr_EvalMod(game::scriptInstance_t inst, game::VariableValue* value1, game::VariableValue* value2)
|
|
{
|
|
if (value1->type == game::VAR_INTEGER && value2->type == game::VAR_INTEGER)
|
|
{
|
|
if (value2->u.intValue)
|
|
{
|
|
value1->u.intValue %= value2->u.intValue;
|
|
}
|
|
else
|
|
{
|
|
value1->u.intValue = 0;
|
|
game::Scr_Error("divide by 0", inst, 0);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
game::Scr_UnmatchingTypesError(inst, value2, value1);
|
|
}
|
|
}
|
|
|
|
// Restored
|
|
void Scr_EvalInequality(game::scriptInstance_t inst, game::VariableValue* value1, game::VariableValue* value2)
|
|
{
|
|
game::Scr_EvalEquality(value1, inst, value2);
|
|
|
|
assert((value1->type == game::VAR_INTEGER) || (value1->type == game::VAR_UNDEFINED));
|
|
|
|
value1->u.intValue = value1->u.intValue == 0;
|
|
}
|
|
|
|
// Completed
|
|
void Scr_EvalBinaryOperator(game::scriptInstance_t inst, game::VariableValue* value2, game::OpcodeVM op, game::VariableValue* value1)
|
|
{
|
|
switch (op)
|
|
{
|
|
case game::OP_bit_or:
|
|
game::Scr_EvalOr(value1, value2, inst);
|
|
break;
|
|
case game::OP_bit_ex_or:
|
|
game::Scr_EvalExOr(value1, value2, inst);
|
|
break;
|
|
case game::OP_bit_and:
|
|
game::Scr_EvalAnd(value1, value2, inst);
|
|
break;
|
|
case game::OP_equality:
|
|
game::Scr_EvalEquality(value1, inst, value2);
|
|
break;
|
|
case game::OP_inequality:
|
|
game::Scr_EvalInequality(inst, value1, value2);
|
|
break;
|
|
case game::OP_less:
|
|
game::Scr_EvalLess(value2, value1, inst);
|
|
break;
|
|
case game::OP_greater:
|
|
game::Scr_EvalGreater(value2, value1, inst);
|
|
break;
|
|
case game::OP_less_equal:
|
|
game::Scr_EvalLessEqual(inst, value1, value2);
|
|
break;
|
|
case game::OP_greater_equal:
|
|
game::Scr_EvalGreaterEqual(inst, value1, value2);
|
|
break;
|
|
case game::OP_shift_left:
|
|
game::Scr_EvalShiftLeft(value1, value2, inst);
|
|
break;
|
|
case game::OP_shift_right:
|
|
game::Scr_EvalShiftRight(value1, value2, inst);
|
|
break;
|
|
case game::OP_plus:
|
|
game::Scr_EvalPlus(inst, value1, value2);
|
|
break;
|
|
case game::OP_minus:
|
|
game::Scr_EvalMinus(value2, inst, value1);
|
|
break;
|
|
case game::OP_multiply:
|
|
game::Scr_EvalMultiply(value2, inst, value1);
|
|
break;
|
|
case game::OP_divide:
|
|
game::Scr_EvalDivide(value2, inst, value1);
|
|
break;
|
|
case game::OP_mod:
|
|
game::Scr_EvalMod(inst, value1, value2);
|
|
break;
|
|
default:
|
|
return;
|
|
}
|
|
}
|
|
|
|
// Completed
|
|
void Scr_FreeEntityNum(game::scriptInstance_t inst, game::classNum_e classnum, unsigned int entnum)
|
|
{
|
|
unsigned int entArrayId;
|
|
unsigned int entnumId;
|
|
game::VariableValueInternal* entryValue;
|
|
unsigned int entId;
|
|
|
|
if (game::gScrVarPub[inst].bInited)
|
|
{
|
|
entArrayId = game::gScrClassMap[inst][classnum].entArrayId;
|
|
|
|
assert(entArrayId);
|
|
|
|
entnumId = game::FindArrayVariable(entArrayId, entnum, inst);
|
|
if (entnumId)
|
|
{
|
|
entId = game::FindObject(inst, entnumId);
|
|
|
|
assert(entId);
|
|
|
|
entryValue = &game::gScrVarGlob[inst].parentVariables[entId + 1];
|
|
|
|
assert((entryValue->w.type & VAR_MASK) == game::VAR_ENTITY);
|
|
|
|
assert((game::classNum_e)(entryValue->w.classnum >> VAR_NAME_BIT_SHIFT) == classnum);
|
|
|
|
entryValue->w.status &= ~VAR_MASK;
|
|
entryValue->w.status |= game::VAR_DEAD_ENTITY;
|
|
game::AddRefToObject(inst, entId);
|
|
entryValue->u.o.u.nextEntId = game::gScrVarPub[inst].freeEntList;
|
|
game::gScrVarPub[inst].freeEntList = entId;
|
|
game::RemoveArrayVariable(inst, entArrayId, entnum);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Completed
|
|
void Scr_FreeEntityList(game::scriptInstance_t inst)
|
|
{
|
|
game::VariableValueInternal* entryValue;
|
|
unsigned int entId;
|
|
|
|
while (game::gScrVarPub[inst].freeEntList)
|
|
{
|
|
entId = game::gScrVarPub[inst].freeEntList;
|
|
entryValue = &game::gScrVarGlob[inst].parentVariables[entId + 1];
|
|
game::gScrVarPub[inst].freeEntList = entryValue->u.o.u.nextEntId;
|
|
entryValue->u.o.u.nextEntId = 0;
|
|
game::Scr_CancelNotifyList(entId, inst);
|
|
|
|
if (entryValue->nextSibling)
|
|
{
|
|
game::ClearObjectInternal(inst, entId);
|
|
}
|
|
|
|
game::RemoveRefToObject(entId, inst);
|
|
}
|
|
}
|
|
|
|
// Completed
|
|
void Scr_FreeObjects(game::scriptInstance_t inst)
|
|
{
|
|
game::VariableValueInternal* entryValue;
|
|
unsigned int id;
|
|
|
|
for (id = 1;
|
|
id < (VARIABLELIST_CHILD_BEGIN - 2);
|
|
++id)
|
|
{
|
|
entryValue = &game::gScrVarGlob[inst].parentVariables[id + 1];
|
|
if ((entryValue->w.status & VAR_STAT_MASK) != VAR_STAT_FREE && ((entryValue->w.status & VAR_MASK) == game::VAR_OBJECT || (entryValue->w.status & VAR_MASK) == game::VAR_DEAD_ENTITY))
|
|
{
|
|
game::Scr_CancelNotifyList(id, inst);
|
|
game::ClearObject(id, inst);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Completed
|
|
void Scr_SetClassMap(game::scriptInstance_t inst, game::classNum_e classnum)
|
|
{
|
|
assert(!game::gScrClassMap[inst][classnum].entArrayId);
|
|
|
|
assert(!game::gScrClassMap[inst][classnum].id);
|
|
|
|
game::gScrClassMap[inst][classnum].entArrayId = game::Scr_AllocArray(inst);
|
|
game::gScrClassMap[inst][classnum].id = game::Scr_AllocArray(inst);
|
|
}
|
|
|
|
// Completed
|
|
void Scr_RemoveClassMap(game::classNum_e classnum, game::scriptInstance_t inst)
|
|
{
|
|
if (game::gScrVarPub[inst].bInited)
|
|
{
|
|
if (game::gScrClassMap[inst][classnum].entArrayId)
|
|
{
|
|
game::RemoveRefToObject(game::gScrClassMap[inst][classnum].entArrayId, inst);
|
|
game::gScrClassMap[inst][classnum].entArrayId = 0;
|
|
}
|
|
if (game::gScrClassMap[inst][classnum].id)
|
|
{
|
|
game::RemoveRefToObject(game::gScrClassMap[inst][classnum].id, inst);
|
|
game::gScrClassMap[inst][classnum].id = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Restored
|
|
unsigned int GetNewArrayVariableIndex(game::scriptInstance_t inst, unsigned int parentId, unsigned int unsignedValue)
|
|
{
|
|
assert(game::IsValidArrayIndex(inst, unsignedValue));
|
|
|
|
return game::GetNewVariableIndexInternal(inst, parentId, (unsignedValue + 0x800000) & 0xFFFFFF);
|
|
}
|
|
|
|
// Restored
|
|
unsigned int GetNewArrayVariable(game::scriptInstance_t inst, unsigned int parentId, unsigned int unsignedValue)
|
|
{
|
|
return game::gScrVarGlob[inst].childVariables[game::GetNewArrayVariableIndex(inst, parentId, unsignedValue)].hash.id;
|
|
}
|
|
|
|
// Completed
|
|
void Scr_AddClassField(game::scriptInstance_t inst, game::classNum_e classnum, const char* name, unsigned int offset)
|
|
{
|
|
unsigned int str;
|
|
unsigned int stra;
|
|
unsigned int classId;
|
|
game::VariableValueInternal* entryValue;
|
|
game::VariableValueInternal* entryValuea;
|
|
unsigned int fieldId;
|
|
const char* namePos;
|
|
|
|
assert(offset < VARIABLELIST_CHILD_SIZE);
|
|
|
|
for (namePos = name; *namePos; ++namePos)
|
|
{
|
|
assert((*namePos < 'A' || *namePos > 'Z'));
|
|
}
|
|
|
|
classId = game::gScrClassMap[inst][classnum].id;
|
|
str = game::SL_GetCanonicalString(name, inst);
|
|
|
|
assert(!game::FindArrayVariable(classId, str, inst));
|
|
|
|
entryValue = &game::gScrVarGlob[inst].childVariables[game::GetNewArrayVariable(inst, classId, str)];
|
|
entryValue->w.status &= ~VAR_MASK;
|
|
entryValue->w.status |= game::VAR_INTEGER;
|
|
entryValue->u.u.intValue = offset;
|
|
stra = game::SL_GetString_(name, inst, 0);
|
|
|
|
assert(!game::FindVariable(stra, classId, inst));
|
|
|
|
fieldId = game::GetNewVariable(inst, stra, classId);
|
|
game::SL_RemoveRefToString(stra, inst);
|
|
entryValuea = &game::gScrVarGlob[inst].childVariables[fieldId];
|
|
entryValuea->w.status &= ~VAR_MASK;
|
|
entryValuea->w.status |= game::VAR_INTEGER;
|
|
entryValuea->u.u.intValue = offset;
|
|
}
|
|
|
|
// Decomp Status: Untested
|
|
// game::VariableUnion __usercall Scr_GetOffset@<eax>(const char *name@<eax>, game::scriptInstance_t inst@<edi>, game::classNum_e classNum)
|
|
game::VariableUnion Scr_GetOffset(const char* name, game::scriptInstance_t inst, game::classNum_e classnum)
|
|
{
|
|
game::VariableUnion result;
|
|
unsigned int classId;
|
|
unsigned int fieldId;
|
|
|
|
classId = game::gScrClassMap[inst][classnum].id;
|
|
fieldId = game::FindVariable(game::SL_ConvertFromString(inst, name), classId, inst);
|
|
|
|
if (fieldId)
|
|
{
|
|
result.intValue = game::gScrVarGlob[inst].childVariables[fieldId].u.u.intValue;
|
|
}
|
|
else
|
|
{
|
|
result.intValue = -1;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
// Decomp Status: Untested
|
|
// unsigned int __usercall FindEntityId@<eax>(unsigned int entClass@<eax>, int entNum@<ecx>, game::scriptInstance_t inst@<edi>)
|
|
unsigned int FindEntityId(unsigned int classnum, int entNum, game::scriptInstance_t inst)
|
|
{
|
|
unsigned int entArrayId;
|
|
game::VariableValueInternal* entryValue;
|
|
unsigned int id;
|
|
unsigned int clientNum = 0;
|
|
|
|
if (clientNum && inst == game::SCRIPTINSTANCE_CLIENT)
|
|
{
|
|
entNum += 1536 * clientNum;
|
|
}
|
|
|
|
assert(entNum < VARIABLELIST_CHILD_SIZE);
|
|
|
|
entArrayId = game::gScrClassMap[inst][classnum].entArrayId;
|
|
|
|
assert(entArrayId);
|
|
|
|
id = game::FindArrayVariable(entArrayId, entNum, inst);
|
|
if (!id)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
entryValue = &game::gScrVarGlob[inst].childVariables[id];
|
|
|
|
assert((entryValue->w.status & VAR_STAT_MASK) != VAR_STAT_FREE);
|
|
|
|
assert((entryValue->w.type & VAR_MASK) == game::VAR_POINTER);
|
|
|
|
assert(entryValue->u.u.pointerValue);
|
|
|
|
return entryValue->u.u.pointerValue;
|
|
}
|
|
|
|
//Restored function
|
|
unsigned int GetArrayVariable(game::scriptInstance_t inst, unsigned int parentId, unsigned int unsignedValue)
|
|
{
|
|
return game::gScrVarGlob[inst].childVariables[game::GetArrayVariableIndex(unsignedValue, inst, parentId)].hash.id;
|
|
}
|
|
|
|
// Decomp Status: Tested, Completed
|
|
// this is the first function i made a usercall detour for -INeedGames
|
|
// unsigned int __usercall Scr_GetEntityId@<eax>(int entNum@<eax>, game::scriptInstance_t inst, game::classNum_e classnum, int clientnum)
|
|
unsigned int Scr_GetEntityId(int entNum, game::scriptInstance_t inst, game::classNum_e classnum, int clientnum)
|
|
{
|
|
unsigned int result;
|
|
unsigned int entArrayId;
|
|
unsigned __int16 actualEntNum;
|
|
game::VariableValueInternal* entryValue;
|
|
unsigned int entId;
|
|
unsigned int id;
|
|
|
|
actualEntNum = entNum;
|
|
if (clientnum && inst == game::SCRIPTINSTANCE_CLIENT)
|
|
{
|
|
entNum += 1536 * clientnum;
|
|
}
|
|
|
|
assert(entNum < VARIABLELIST_CHILD_SIZE);
|
|
|
|
entArrayId = game::gScrClassMap[inst][classnum].entArrayId;
|
|
|
|
assert(entArrayId);
|
|
|
|
id = game::GetArrayVariable(inst, entArrayId, entNum);
|
|
|
|
assert(id);
|
|
|
|
entryValue = &game::gScrVarGlob[inst].childVariables[id];
|
|
|
|
assert((entryValue->w.status & VAR_STAT_MASK) != VAR_STAT_FREE);
|
|
|
|
if ((entryValue->w.status & VAR_MASK) != game::VAR_UNDEFINED)
|
|
{
|
|
assert((entryValue->w.type & VAR_MASK) == game::VAR_POINTER);
|
|
|
|
result = entryValue->u.u.intValue;
|
|
}
|
|
else
|
|
{
|
|
entId = game::AllocEntity(classnum, inst, actualEntNum, clientnum);
|
|
|
|
assert((entryValue->w.type & VAR_MASK) == game::VAR_UNDEFINED);
|
|
|
|
entryValue->w.status |= game::VAR_POINTER;
|
|
entryValue->u.u.intValue = entId;
|
|
result = entId;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
// Decomp Status: Untested
|
|
// unsigned int __usercall Scr_FindArrayIndex@<eax>(game::scriptInstance_t a1@<eax>, game::VariableValue *a2@<ecx>, unsigned int a3)
|
|
unsigned int Scr_FindArrayIndex(game::scriptInstance_t inst, game::VariableValue* index, unsigned int parentId)
|
|
{
|
|
unsigned int result;
|
|
const char* errorMsg;
|
|
unsigned int id;
|
|
|
|
if (index->type == game::VAR_INTEGER)
|
|
{
|
|
if (game::IsValidArrayIndex(inst, index->u.intValue))
|
|
{
|
|
result = game::FindArrayVariable(parentId, index->u.intValue, inst);
|
|
}
|
|
else
|
|
{
|
|
errorMsg = game::va("array index %d out of range", index->u.intValue);
|
|
game::Scr_Error(errorMsg, inst, false);
|
|
game::AddRefToObject(inst, parentId);
|
|
result = 0;
|
|
}
|
|
}
|
|
else if (index->type == game::VAR_STRING)
|
|
{
|
|
id = game::FindVariable(index->u.intValue, parentId, inst);
|
|
game::SL_RemoveRefToString(index->u.intValue, inst);
|
|
result = id;
|
|
}
|
|
else
|
|
{
|
|
errorMsg = game::va("%s is not an array index", game::var_typename[index->type]);
|
|
game::Scr_Error(errorMsg, inst, false);
|
|
game::AddRefToObject(inst, parentId);
|
|
result = 0;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
// Decomp Status: Tested, Completed
|
|
// void __usercall Scr_EvalArray(game::scriptInstance_t a2@<ecx>, game::VariableValue *eax0@<eax>, game::VariableValue *a3)
|
|
void Scr_EvalArray(game::scriptInstance_t inst, game::VariableValue* index, game::VariableValue* value)
|
|
{
|
|
const char* errorMsg;
|
|
game::VariableType arrayType;
|
|
char c[4];
|
|
const char* s;
|
|
game::VariableValueInternal* entryValue;
|
|
|
|
assert(value != index);
|
|
|
|
arrayType = value->type;
|
|
switch (arrayType)
|
|
{
|
|
case game::VAR_POINTER:
|
|
entryValue = &game::gScrVarGlob[inst].parentVariables[value->u.intValue + 1];
|
|
|
|
assert((entryValue->w.status & VAR_STAT_MASK) != VAR_STAT_FREE);
|
|
|
|
assert(IsObject(entryValue));
|
|
|
|
if ((entryValue->w.status & VAR_MASK) == game::VAR_ARRAY)
|
|
{
|
|
*index = game::Scr_EvalVariable(inst, game::Scr_FindArrayIndex(inst, index, value->u.intValue));
|
|
game::RemoveRefToObject(value->u.intValue, inst);
|
|
}
|
|
else
|
|
{
|
|
game::gScrVarPub[inst].error_index = 1;
|
|
errorMsg = game::va("%s is not an array", game::var_typename[entryValue->w.status & VAR_MASK]);
|
|
game::Scr_Error(errorMsg, inst, false);
|
|
}
|
|
break;
|
|
case game::VAR_STRING:
|
|
if (index->type == game::VAR_INTEGER)
|
|
{
|
|
s = game::SL_ConvertToString(value->u.intValue, inst);
|
|
if (index->u.intValue < 0 || (index->u.intValue >= (int)strlen(s)))
|
|
{
|
|
errorMsg = game::va("string index %d out of range", index->u.intValue);
|
|
game::Scr_Error(errorMsg, inst, false);
|
|
}
|
|
else
|
|
{
|
|
index->type = game::VAR_STRING;
|
|
c[0] = s[index->u.intValue];
|
|
c[1] = 0;
|
|
index->u.intValue = game::SL_GetStringOfSize(inst, c, 0, 2u);
|
|
game::SL_RemoveRefToString(value->u.intValue, inst);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
errorMsg = game::va("%s is not a string index", game::var_typename[index->type]);
|
|
game::Scr_Error(errorMsg, inst, false);
|
|
}
|
|
break;
|
|
case game::VAR_VECTOR:
|
|
if (index->type == game::VAR_INTEGER)
|
|
{
|
|
if (index->u.intValue >= 3u)
|
|
{
|
|
errorMsg = game::va("vector index %d out of range", index->u.intValue);
|
|
game::Scr_Error(errorMsg, inst, false);
|
|
}
|
|
else
|
|
{
|
|
index->type = game::VAR_FLOAT;
|
|
index->u.floatValue = *(float*)(value->u.intValue + 4 * index->u.intValue);
|
|
game::RemoveRefToVector(value->u.vectorValue, inst);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
errorMsg = game::va("%s is not a vector index", game::var_typename[index->type]);
|
|
game::Scr_Error(errorMsg, inst, false);
|
|
}
|
|
break;
|
|
default:
|
|
|
|
assert(value->type != game::VAR_STACK);
|
|
|
|
game::gScrVarPub[inst].error_index = 1;
|
|
errorMsg = game::va("%s is not an array, string, or vector", game::var_typename[value->type]);
|
|
game::Scr_Error(errorMsg, inst, false);
|
|
break;
|
|
}
|
|
}
|
|
|
|
//Custom function added to remove goto
|
|
unsigned int Scr_EvalArrayRefInternal(game::scriptInstance_t inst, game::VariableValue* varValue, game::VariableValueInternal* parentValue)
|
|
{
|
|
game::VariableValueInternal* entryValue;
|
|
unsigned int result;
|
|
unsigned int id;
|
|
|
|
if (varValue->type == game::VAR_POINTER)
|
|
{
|
|
entryValue = &game::gScrVarGlob[inst].parentVariables[varValue->u.intValue + 1];
|
|
|
|
assert((entryValue->w.status & VAR_STAT_MASK) != VAR_STAT_FREE);
|
|
|
|
assert(IsObject(entryValue));
|
|
|
|
if ((entryValue->w.status & VAR_MASK) == game::VAR_ARRAY)
|
|
{
|
|
if (entryValue->u.o.refCount)
|
|
{
|
|
id = varValue->u.intValue;
|
|
game::RemoveRefToObject(varValue->u.stringValue, inst);
|
|
varValue->u.intValue = game::Scr_AllocArray(inst);
|
|
game::CopyArray(inst, id, varValue->u.stringValue);
|
|
parentValue->u.u.intValue = varValue->u.intValue;
|
|
}
|
|
result = varValue->u.intValue;
|
|
}
|
|
else
|
|
{
|
|
game::gScrVarPub[inst].error_index = 1;
|
|
game::Scr_Error(game::va("%s is not an array", game::var_typename[entryValue->w.status & VAR_MASK]), inst, 0);
|
|
result = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
assert(varValue->type != game::VAR_STACK);
|
|
|
|
game::gScrVarPub[inst].error_index = 1;
|
|
if (varValue->type == game::VAR_STRING)
|
|
{
|
|
game::Scr_Error("string characters cannot be individually changed", inst, 0);
|
|
result = 0;
|
|
}
|
|
else
|
|
{
|
|
if (varValue->type == game::VAR_VECTOR)
|
|
{
|
|
game::Scr_Error("vector components cannot be individually changed", inst, 0);
|
|
}
|
|
else
|
|
{
|
|
game::Scr_Error(game::va("%s is not an array", game::var_typename[varValue->type]), inst, 0);
|
|
}
|
|
result = 0;
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
// Decomp Status: Tested, Completed
|
|
unsigned int Scr_EvalArrayRef(game::scriptInstance_t inst, unsigned int parentId)
|
|
{
|
|
game::VariableValueInternal* parentValue;
|
|
game::VariableValueInternal* entValue;
|
|
game::VariableValue varValue;
|
|
unsigned int fieldId;
|
|
|
|
if (parentId)
|
|
{
|
|
parentValue = &game::gScrVarGlob[inst].childVariables[parentId];
|
|
varValue.type = (game::VariableType)(parentValue->w.status & VAR_MASK);
|
|
if (varValue.type != game::VAR_UNDEFINED)
|
|
{
|
|
varValue.u.intValue = parentValue->u.u.intValue;
|
|
return game::Scr_EvalArrayRefInternal(inst, &varValue, parentValue);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
entValue = &game::gScrVarGlob[inst].parentVariables[game::gScrVarPub[inst].entId + 1];
|
|
|
|
assert((entValue->w.type & VAR_MASK) == game::VAR_ENTITY);
|
|
|
|
assert((entValue->w.classnum >> VAR_NAME_BIT_SHIFT) < game::CLASS_NUM_COUNT);
|
|
|
|
fieldId = game::FindArrayVariable(game::gScrClassMap[inst][entValue->w.status >> VAR_NAME_BIT_SHIFT].id, game::gScrVarPub[inst].entFieldName, inst);
|
|
if (fieldId)
|
|
{
|
|
varValue = game::GetEntityFieldValue(game::gScrVarGlob[inst].childVariables[fieldId].u.u.intValue, entValue->u.o.u.entnum & VAR_ENT_MASK, inst, entValue->w.status >> VAR_NAME_BIT_SHIFT, entValue->u.o.u.entnum >> VAR_CLIENT_MASK);
|
|
if (varValue.type)
|
|
{
|
|
if (varValue.type == game::VAR_POINTER && !game::gScrVarGlob[inst].parentVariables[varValue.u.intValue + 1].u.o.refCount)
|
|
{
|
|
game::RemoveRefToValueInternal(inst, game::VAR_POINTER, varValue.u);
|
|
game::gScrVarPub[inst].error_index = 1;
|
|
game::Scr_Error("read-only array cannot be changed", inst, 0);
|
|
return 0;
|
|
}
|
|
game::RemoveRefToValueInternal(inst, varValue.type, varValue.u);
|
|
|
|
assert((varValue.type != game::VAR_POINTER) || !game::gScrVarGlob[inst].parentVariables[varValue.u.intValue + 1].u.o.refCount);
|
|
|
|
parentValue = 0;
|
|
return game::Scr_EvalArrayRefInternal(inst, &varValue, parentValue);
|
|
}
|
|
}
|
|
parentValue = &game::gScrVarGlob[inst].childVariables[game::GetNewVariable(inst, game::gScrVarPub[inst].entFieldName, game::gScrVarPub[inst].entId)];
|
|
}
|
|
|
|
assert((parentValue->w.type & VAR_MASK) == game::VAR_UNDEFINED);
|
|
|
|
parentValue->w.status |= game::VAR_POINTER;
|
|
parentValue->u.u.intValue = game::Scr_AllocArray(inst);
|
|
return parentValue->u.u.intValue;
|
|
}
|
|
|
|
//Restored function
|
|
BOOL IsValidArrayIndex([[maybe_unused]] game::scriptInstance_t inst, unsigned int unsignedValue)
|
|
{
|
|
return (unsignedValue + 0x7EA002) <= 0xFEA001;
|
|
}
|
|
|
|
//Restored function
|
|
void SafeRemoveArrayVariable(game::scriptInstance_t inst, unsigned int parentId, unsigned int unsignedValue)
|
|
{
|
|
assert(game::IsValidArrayIndex(inst, unsignedValue));
|
|
|
|
game::SafeRemoveVariable((unsignedValue + 0x800000) & 0xFFFFFF, parentId, inst);
|
|
}
|
|
|
|
// Decomp Status:Tested, Completed
|
|
void ClearArray(unsigned int parentId, game::scriptInstance_t inst, game::VariableValue* value)
|
|
{
|
|
game::VariableValueInternal* entValue;
|
|
int fieldId;
|
|
game::VariableValue entFieldValue;
|
|
game::VariableType type;
|
|
game::VariableUnion indexValue;
|
|
game::VariableValueInternal* parentValue;
|
|
const char* errorMsg;
|
|
game::VariableValueInternal* entryValue;
|
|
unsigned int varValue;
|
|
game::VariableType indexType;
|
|
|
|
if (parentId)
|
|
{
|
|
parentValue = &game::gScrVarGlob[inst].childVariables[parentId];
|
|
|
|
assert((parentValue->w.status & VAR_STAT_MASK) != VAR_STAT_FREE);
|
|
|
|
indexValue.intValue = parentValue->u.u.intValue;
|
|
type = (game::VariableType)(parentValue->w.status & VAR_MASK);
|
|
entFieldValue.type = type;
|
|
entFieldValue.u = indexValue;
|
|
}
|
|
else
|
|
{
|
|
entValue = &game::gScrVarGlob[inst].parentVariables[game::gScrVarPub[inst].entId + 1];
|
|
|
|
assert((entValue->w.type & VAR_MASK) == game::VAR_ENTITY);
|
|
|
|
assert((entValue->w.classnum >> VAR_NAME_BIT_SHIFT) < game::CLASS_NUM_COUNT);
|
|
|
|
fieldId = game::FindArrayVariable(game::gScrClassMap[inst][entValue->w.status >> VAR_PARENTID_BIT_SHIFT].id, game::gScrVarPub[inst].entFieldName, inst);
|
|
entFieldValue = game::GetEntityFieldValue(
|
|
game::gScrVarGlob[inst].childVariables[fieldId].u.u.intValue,
|
|
entValue->u.o.u.entnum & VAR_ENT_MASK,
|
|
inst,
|
|
entValue->w.status >> VAR_PARENTID_BIT_SHIFT,
|
|
entValue->u.o.u.entnum >> VAR_CLIENT_MASK);
|
|
if (!fieldId || (entFieldValue.type == game::VAR_UNDEFINED))
|
|
{
|
|
game::gScrVarPub[inst].error_index = 1;
|
|
errorMsg = game::va("%s is not an array", game::var_typename[game::VAR_UNDEFINED]);
|
|
game::Scr_Error(errorMsg, inst, false);
|
|
return;
|
|
}
|
|
if (entFieldValue.type == game::VAR_POINTER && !game::gScrVarGlob[inst].parentVariables[entFieldValue.u.intValue + 1].u.o.refCount)
|
|
{
|
|
game::RemoveRefToValue(inst, &entFieldValue);
|
|
game::gScrVarPub[inst].error_index = 1;
|
|
game::Scr_Error("read-only array cannot be changed", inst, false);
|
|
return;
|
|
}
|
|
game::RemoveRefToValueInternal(inst, entFieldValue.type, entFieldValue.u);
|
|
|
|
assert((entFieldValue.type != game::VAR_POINTER) || !game::gScrVarGlob[inst].parentVariables[entFieldValue.u.intValue + 1].u.o.refCount);
|
|
|
|
type = entFieldValue.type;
|
|
indexValue.intValue = entFieldValue.u.intValue;
|
|
parentValue = 0;
|
|
}
|
|
if (type != game::VAR_POINTER)
|
|
{
|
|
assert(type != game::VAR_STACK);
|
|
|
|
game::gScrVarPub[inst].error_index = 1;
|
|
errorMsg = game::va("%s is not an array", game::var_typename[entFieldValue.type]);
|
|
game::Scr_Error(errorMsg, inst, false);
|
|
return;
|
|
}
|
|
entryValue = &game::gScrVarGlob[inst].parentVariables[indexValue.intValue + 1];
|
|
|
|
assert((entryValue->w.status & VAR_STAT_MASK) != VAR_STAT_FREE);
|
|
|
|
assert(IsObject(entryValue));
|
|
|
|
type = (game::VariableType)(entryValue->w.status & VAR_MASK);
|
|
if (type == game::VAR_ARRAY)
|
|
{
|
|
if (entryValue->u.o.refCount)
|
|
{
|
|
game::RemoveRefToObject(indexValue.stringValue, inst);
|
|
varValue = game::Scr_AllocArray(inst);
|
|
entFieldValue.u.intValue = varValue;
|
|
game::CopyArray(inst, indexValue.intValue, varValue);
|
|
|
|
assert(parentValue);
|
|
|
|
parentValue->u.u.intValue = varValue;
|
|
indexValue.intValue = varValue;
|
|
}
|
|
indexType = value->type;
|
|
if (indexType == game::VAR_INTEGER)
|
|
{
|
|
if (!game::IsValidArrayIndex(inst, value->u.intValue))
|
|
{
|
|
errorMsg = game::va("array index %d out of range", value->u.intValue);
|
|
game::Scr_Error(errorMsg, inst, false);
|
|
}
|
|
else
|
|
{
|
|
game::SafeRemoveArrayVariable(inst, indexValue.stringValue, value->u.intValue);
|
|
}
|
|
}
|
|
else if (indexType == game::VAR_STRING)
|
|
{
|
|
game::SL_RemoveRefToString(value->u.intValue, inst);
|
|
game::SafeRemoveVariable(value->u.intValue, entFieldValue.u.stringValue, inst);
|
|
}
|
|
else
|
|
{
|
|
errorMsg = game::va("%s is not an array index", game::var_typename[indexType]);
|
|
game::Scr_Error(errorMsg, inst, false);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
game::gScrVarPub[inst].error_index = 1;
|
|
errorMsg = game::va("%s is not an array", game::var_typename[type]);
|
|
game::Scr_Error(errorMsg, inst, false);
|
|
}
|
|
}
|
|
|
|
// Decomp Status: Tested, Completed
|
|
void SetEmptyArray(game::scriptInstance_t inst, unsigned int parentId)
|
|
{
|
|
game::VariableValue tempValue;
|
|
|
|
tempValue.type = game::VAR_POINTER;
|
|
tempValue.u.intValue = game::Scr_AllocArray(inst);
|
|
game::SetVariableValue(inst, &tempValue, parentId);
|
|
}
|
|
|
|
// Decomp Status: Tested, Completed
|
|
// this is what started JezuzLizard to want to decomp the VM
|
|
void Scr_AddArrayKeys(unsigned int parentId, game::scriptInstance_t inst)
|
|
{
|
|
game::VariableValue indexValue;
|
|
game::VariableValueInternal* entryValue;
|
|
unsigned int id;
|
|
|
|
assert(parentId);
|
|
|
|
assert(game::GetObjectType(inst, parentId) == game::VAR_ARRAY);
|
|
|
|
game::Scr_MakeArray(inst);
|
|
for (id = game::FindFirstSibling(inst, parentId); id; id = game::FindNextSibling(inst, id))
|
|
{
|
|
entryValue = &game::gScrVarGlob[inst].childVariables[id];
|
|
|
|
assert((entryValue->w.status & VAR_STAT_MASK) != VAR_STAT_FREE && (entryValue->w.status & VAR_STAT_MASK) != VAR_STAT_EXTERNAL);
|
|
|
|
assert((entryValue->w.status & VAR_STAT_MASK) != VAR_STAT_FREE);
|
|
|
|
assert(!IsObject(entryValue));
|
|
|
|
indexValue = game::Scr_GetArrayIndexValue(inst, entryValue->w.status >> 8);
|
|
if (indexValue.type == game::VAR_STRING)
|
|
{
|
|
game::Scr_AddConstString(inst, indexValue.u.stringValue);
|
|
}
|
|
else if (indexValue.type == game::VAR_INTEGER)
|
|
{
|
|
game::Scr_AddInt(inst, indexValue.u.intValue);
|
|
}
|
|
else
|
|
{
|
|
assert(false);
|
|
//assertMsg("bad case");
|
|
}
|
|
game::Scr_AddArray(inst);
|
|
}
|
|
}
|
|
|
|
// Decomp Status: Tested, Completed
|
|
game::scr_entref_t* Scr_GetEntityIdRef(game::scr_entref_t* retstr, game::scriptInstance_t inst, unsigned int entId)
|
|
{
|
|
game::VariableValueInternal* entValue;
|
|
game::ObjectInfo_u entref;
|
|
|
|
entValue = &game::gScrVarGlob[inst].parentVariables[entId + 1];
|
|
|
|
assert((entValue->w.type & VAR_MASK) == game::VAR_ENTITY);
|
|
|
|
assert((entValue->w.name >> VAR_NAME_BIT_SHIFT) < game::CLASS_NUM_COUNT);
|
|
|
|
entref = entValue->u.o.u;
|
|
retstr->entnum = entref.entnum & VAR_ENT_MASK;
|
|
retstr->classnum = entValue->w.status >> VAR_NAME_BIT_SHIFT;
|
|
retstr->client = entref.entnum >> VAR_CLIENT_MASK;
|
|
return retstr;
|
|
}
|
|
|
|
// Decomp Status: Tested, Completed
|
|
void CopyEntity(unsigned int parentId, unsigned int newParentId)
|
|
{
|
|
unsigned int name;
|
|
game::VariableValueInternal* parentValue;
|
|
game::VariableValueInternal* newParentValue;
|
|
game::VariableValueInternal* entryValue;
|
|
game::VariableValueInternal* newEntryValue;
|
|
game::VariableType type;
|
|
unsigned int id;
|
|
game::scriptInstance_t inst = game::SCRIPTINSTANCE_SERVER;
|
|
|
|
assert(parentId);
|
|
|
|
assert(newParentId);
|
|
|
|
parentValue = &game::gScrVarGlob[inst].parentVariables[parentId + 1];
|
|
|
|
assert((parentValue->w.status & VAR_STAT_MASK) == VAR_STAT_EXTERNAL);
|
|
|
|
assert((parentValue->w.status & VAR_STAT_MASK) != VAR_STAT_FREE);
|
|
|
|
assert(IsObject(parentValue));
|
|
|
|
assert((parentValue->w.type & VAR_MASK) == game::VAR_ENTITY);
|
|
|
|
assert((game::gScrVarGlob[inst].parentVariables[newParentId + 1].w.status & VAR_STAT_MASK) == VAR_STAT_EXTERNAL);
|
|
|
|
newParentValue = &game::gScrVarGlob[inst].parentVariables[newParentId + 1];
|
|
|
|
assert((newParentValue->w.status & VAR_STAT_MASK) != VAR_STAT_FREE);
|
|
|
|
assert(IsObject(newParentValue));
|
|
|
|
assert((newParentValue->w.status & VAR_MASK) == game::VAR_ENTITY);
|
|
|
|
for (id = game::FindFirstSibling(inst, parentId); id; id = game::FindNextSibling(inst, id))
|
|
{
|
|
entryValue = &game::gScrVarGlob[inst].childVariables[id];
|
|
|
|
assert((entryValue->w.status & VAR_STAT_MASK) != VAR_STAT_FREE && (entryValue->w.status & VAR_STAT_MASK) != VAR_STAT_EXTERNAL);
|
|
|
|
assert((entryValue->w.status & VAR_STAT_MASK) != VAR_STAT_FREE);
|
|
|
|
assert(!IsObject(entryValue));
|
|
|
|
name = entryValue->w.status >> VAR_NAME_BIT_SHIFT;
|
|
|
|
//assert(name != OBJECT_STACK);
|
|
|
|
if (name != OBJECT_STACK)
|
|
{
|
|
assert(!game::FindVariableIndexInternal(inst, newParentId, name));
|
|
|
|
newEntryValue = &game::gScrVarGlob[inst].childVariables[game::GetVariable(inst, newParentId, name)];
|
|
|
|
assert((newEntryValue->w.status & VAR_STAT_MASK) != VAR_STAT_FREE && (newEntryValue->w.status & VAR_STAT_MASK) != VAR_STAT_EXTERNAL);
|
|
|
|
assert((newEntryValue->w.status & VAR_MASK) == game::VAR_UNDEFINED);
|
|
|
|
type = (game::VariableType)(entryValue->w.status & VAR_MASK);
|
|
|
|
assert((newEntryValue->w.status & VAR_MASK) == game::VAR_UNDEFINED);
|
|
|
|
newEntryValue->w.status |= type;
|
|
|
|
assert((newEntryValue->w.name >> VAR_NAME_BIT_SHIFT) == name);
|
|
|
|
newEntryValue->u.u.intValue = entryValue->u.u.intValue;
|
|
game::AddRefToValue(inst, type, newEntryValue->u.u);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Decomp Status: Tested, Completed
|
|
float Scr_GetEndonUsage(unsigned int parentId, game::scriptInstance_t inst)
|
|
{
|
|
game::VariableValueInternal* parentValue;
|
|
unsigned int id;
|
|
|
|
parentValue = &game::gScrVarGlob[inst].parentVariables[parentId + 1];
|
|
|
|
assert((parentValue->w.status & VAR_STAT_MASK) != VAR_STAT_FREE);
|
|
|
|
assert(IsObject(parentValue));
|
|
|
|
id = game::FindObjectVariable(inst, game::gScrVarPub[inst].pauseArrayId, parentId);
|
|
if (!id)
|
|
{
|
|
return 0.0f;
|
|
}
|
|
|
|
return game::Scr_GetObjectUsage(inst, game::FindObject(inst, id));
|
|
}
|
|
|
|
//Restored inlined function
|
|
float Scr_GetEntryUsageInternal(game::scriptInstance_t inst, unsigned int type, game::VariableUnion u)
|
|
{
|
|
float result;
|
|
game::VariableValueInternal* parentValue;
|
|
|
|
if (type != game::VAR_POINTER)
|
|
{
|
|
return 0.0f;
|
|
}
|
|
|
|
parentValue = &game::gScrVarGlob[inst].parentVariables[u.intValue + 1];
|
|
|
|
assert((parentValue->w.status & VAR_STAT_MASK) != VAR_STAT_FREE);
|
|
|
|
assert(IsObject(parentValue));
|
|
|
|
if ((parentValue->w.status & VAR_MASK) == game::VAR_ARRAY)
|
|
{
|
|
result = game::Scr_GetObjectUsage(inst, u.stringValue) / ((float)parentValue->u.o.refCount + 1.0);
|
|
}
|
|
else
|
|
{
|
|
result = 0.0f;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
//Restored inlined function
|
|
float Scr_GetEntryUsage(game::scriptInstance_t inst, game::VariableValueInternal* entryValue)
|
|
{
|
|
return game::Scr_GetEntryUsageInternal(inst, entryValue->w.status & 0x1F, entryValue->u.u) + 1.0;
|
|
}
|
|
|
|
// Decomp Status: Tested, Completed
|
|
float Scr_GetObjectUsage(game::scriptInstance_t inst, unsigned int parentId)
|
|
{
|
|
game::VariableValueInternal* parentValue;
|
|
float usage;
|
|
unsigned int id;
|
|
|
|
parentValue = &game::gScrVarGlob[inst].parentVariables[parentId + 1];
|
|
|
|
assert((parentValue->w.status & VAR_STAT_MASK) != VAR_STAT_FREE);
|
|
|
|
assert(IsObject(parentValue));
|
|
|
|
usage = 1.0;
|
|
for (id = game::FindFirstSibling(inst, parentId); id; id = game::FindNextSibling(inst, id))
|
|
usage = game::Scr_GetEntryUsage(inst, &game::gScrVarGlob[inst].childVariables[id]) + usage;
|
|
return usage;
|
|
}
|
|
|
|
// Decomp Status: Tested, Completed
|
|
float Scr_GetThreadUsage(game::VariableStackBuffer* stackBuf, game::scriptInstance_t inst, float* endonUsage)
|
|
{
|
|
int size;
|
|
char* buf_1;
|
|
unsigned int parentId;
|
|
char* bufa;
|
|
char buf;
|
|
game::VariableValueInternal* parentValue;
|
|
float threadUsageCount;
|
|
unsigned int parentId2;
|
|
|
|
size = stackBuf->size;
|
|
buf_1 = &stackBuf->buf[4 * size + size];
|
|
threadUsageCount = game::Scr_GetObjectUsage(inst, stackBuf->localId);
|
|
*endonUsage = game::Scr_GetEndonUsage(stackBuf->localId, inst);
|
|
parentId2 = stackBuf->localId;
|
|
while (size)
|
|
{
|
|
parentId = *((int*)buf_1 - 1);
|
|
bufa = buf_1 - 4;
|
|
buf = *(bufa - 1);
|
|
buf_1 = bufa - 1;
|
|
--size;
|
|
parentValue = &game::gScrVarGlob[inst].parentVariables[parentId + 1];
|
|
if (buf == game::VAR_CODEPOS)
|
|
{
|
|
parentId2 = game::gScrVarGlob[inst].parentVariables[parentId2 + 1].w.status >> VAR_NAME_BIT_SHIFT;
|
|
threadUsageCount = game::Scr_GetObjectUsage(inst, parentId2) + threadUsageCount;
|
|
*endonUsage = game::Scr_GetEndonUsage(parentId2, inst) + *endonUsage;
|
|
}
|
|
else if (buf == game::VAR_POINTER && (parentValue->w.status & VAR_MASK) == game::VAR_ARRAY)
|
|
{
|
|
threadUsageCount = game::Scr_GetObjectUsage(inst, parentId) / (parentValue->u.o.refCount + 1.0f) + threadUsageCount;
|
|
}
|
|
else
|
|
{
|
|
threadUsageCount = threadUsageCount + 0.0f;
|
|
}
|
|
}
|
|
return threadUsageCount;
|
|
}
|
|
|
|
// Decomp Status: Tested, Completed
|
|
unsigned int Scr_FindField(game::scriptInstance_t inst, const char* name, int* type)
|
|
{
|
|
const char* pos;
|
|
const char* posa;
|
|
int len;
|
|
unsigned int index;
|
|
|
|
assert(game::gScrVarPub[inst].fieldBuffer);
|
|
|
|
for (pos = game::gScrVarPub[inst].fieldBuffer; *pos; pos += len + 3)
|
|
{
|
|
len = strlen(pos) + 1;
|
|
if (!game::I_stricmp(0x7FFFFFFF, (char*)name, pos))
|
|
{
|
|
posa = &pos[len];
|
|
index = *(unsigned short*)posa;
|
|
*type = posa[2];
|
|
return index;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
// Decomp Status: Untested, Completed
|
|
char* Scr_GetSourceFile_LoadObj(const char* filename)
|
|
{
|
|
int len;
|
|
int h;
|
|
char* sourceBuffer;
|
|
|
|
len = game::FS_FOpenFileRead(filename, &h); // FS_FOpenFileByMode
|
|
if (h)
|
|
{
|
|
game::fsh[h].fileSize = len;
|
|
game::fsh[h].streamed = 0;
|
|
}
|
|
game::fsh[h].handleSync = 0;
|
|
if (len < 0)
|
|
{
|
|
game::Com_Error(game::ERR_DROP, game::va("\x15" "cannot find '%s'", filename));
|
|
return (char*)0;
|
|
}
|
|
sourceBuffer = (char*)game::Hunk_AllocateTempMemoryHigh(len + 1);
|
|
game::FS_Read(sourceBuffer, len, h);
|
|
sourceBuffer[len] = 0;
|
|
game::FS_FCloseFile(h);
|
|
return sourceBuffer;
|
|
}
|
|
|
|
// Decomp Status: Tested, Completed
|
|
char* Scr_GetSourceFile_FastFile(const char* filename)
|
|
{
|
|
game::RawFile* file; // esi
|
|
|
|
file = game::DB_FindXAssetHeader(game::ASSET_TYPE_RAWFILE, filename, 1, -1).rawfile;
|
|
if (file)
|
|
{
|
|
return file->buffer;
|
|
}
|
|
game::Com_Error(game::ERR_DROP, game::va("\x15" "cannot find '%s'", filename));
|
|
return nullptr;
|
|
}
|
|
|
|
// Decomp Status: Tested, Completed
|
|
void Scr_AddFieldsForFile(game::scriptInstance_t inst, const char* filename)
|
|
{
|
|
char* i;
|
|
game::parseInfo_t* parseInfo;
|
|
unsigned int tokenLen;
|
|
int j;
|
|
char character;
|
|
__int16 slStrOfToken;
|
|
char* token;
|
|
char* targetPos;
|
|
const char* data_p;
|
|
int type;
|
|
int tempType;
|
|
|
|
if (!(*game::useFastFile)->current.enabled)
|
|
{
|
|
data_p = game::Scr_GetSourceFile_LoadObj(filename);
|
|
}
|
|
else
|
|
{
|
|
data_p = game::Scr_GetSourceFile_FastFile((char*)filename);
|
|
}
|
|
game::Com_BeginParseSession("Scr_AddFields");
|
|
for (i = (char*)game::Hunk_UserAlloc(*game::g_user, 0, 1); ; *i = 0)
|
|
{
|
|
parseInfo = game::Com_Parse(&data_p);
|
|
if (!data_p)
|
|
{
|
|
break;
|
|
}
|
|
if (!strcmp(parseInfo->token, "float"))
|
|
{
|
|
type = 5;
|
|
}
|
|
else if (!strcmp(parseInfo->token, "int"))
|
|
{
|
|
type = 6;
|
|
}
|
|
else if (!strcmp(parseInfo->token, "string"))
|
|
{
|
|
type = 2;
|
|
}
|
|
else
|
|
{
|
|
if (strcmp(parseInfo->token, "vector"))
|
|
{
|
|
game::Com_Error(game::ERR_DROP, game::va("\x15" "unknown type '%s' in '%s'", parseInfo->token, filename));
|
|
return;
|
|
}
|
|
type = 4;
|
|
}
|
|
parseInfo = game::Com_Parse(&data_p);
|
|
if (!data_p)
|
|
{
|
|
game::Com_Error(game::ERR_DROP, game::va("\x15" "missing field name in '%s'", filename));
|
|
return;
|
|
}
|
|
tokenLen = strlen(parseInfo->token);
|
|
for (j = tokenLen; j >= 0; parseInfo->token[j + 1] = character)
|
|
{
|
|
character = tolower(parseInfo->token[j--]);
|
|
}
|
|
slStrOfToken = game::SL_GetCanonicalString(parseInfo->token, inst);
|
|
if (game::Scr_FindField(inst, parseInfo->token, &tempType))
|
|
{
|
|
game::Com_Error(game::ERR_DROP, "\x15" "duplicate key '%s' in '%s'", parseInfo->token, filename);
|
|
return;
|
|
}
|
|
|
|
//assert(i == (game::TempMalloc(0) - 1));
|
|
|
|
game::TempMemorySetPos(i);
|
|
token = (char*)game::Hunk_UserAlloc(*game::g_user, tokenLen + 1 + 4, 1);
|
|
strcpy(token, parseInfo->token);
|
|
targetPos = &token[tokenLen + 1];
|
|
*(short*)targetPos = slStrOfToken;
|
|
targetPos += 2;
|
|
*targetPos = type;
|
|
i = targetPos + 1;
|
|
}
|
|
game::Com_EndParseSession();
|
|
game::Hunk_ClearTempMemoryHigh();
|
|
}
|
|
|
|
// Decomp Status: Untested, Completed
|
|
void Scr_AddFields_LoadObj(game::scriptInstance_t inst, const char* path, const char* extension)
|
|
{
|
|
const char** files;
|
|
char* v4;
|
|
int numFiles;
|
|
const char** v19;
|
|
char filename[64];
|
|
int i;
|
|
|
|
files = game::FS_ListFilteredFiles((*game::fs_searchpaths), path, extension, 0, game::FS_LIST_PURE_ONLY, &numFiles);
|
|
v19 = files;
|
|
v4 = (char*)game::Hunk_UserAlloc(*game::g_user, 0, 1); // TempMallocAlignStrict
|
|
game::gScrVarPub[inst].fieldBuffer = v4;
|
|
for (i = 0; i < numFiles; ++i)
|
|
{
|
|
if ((inst == game::SCRIPTINSTANCE_CLIENT || strlen(files[i]) <= 6 || game::I_strncmp(files[i], "client", 6))
|
|
&& (inst == game::SCRIPTINSTANCE_SERVER || strlen(files[i]) > 6 && !game::I_strncmp(files[i], "client", 6)))
|
|
{
|
|
sprintf_s(filename, "%s/%s", path, files[i]);
|
|
|
|
assert(strlen(filename) < 0x40);
|
|
|
|
game::Scr_AddFieldsForFile(inst, filename);
|
|
}
|
|
}
|
|
if (files)
|
|
{
|
|
game::Hunk_UserDestroy((game::HunkUser*)*(files - 1)); // FS_FreeFileList
|
|
}
|
|
*(char*)game::Hunk_UserAlloc(*game::g_user, 1, 1) = 0;
|
|
}
|
|
|
|
// Decomp Status: Tested, Completed
|
|
void Scr_AddFields_FastFile(game::scriptInstance_t inst, const char* path, const char* extension)
|
|
{
|
|
char* fieldBuffer;
|
|
const char* radiantKeysName;
|
|
char Buffer[64];
|
|
|
|
fieldBuffer = (char*)game::Hunk_UserAlloc(*game::g_user, 0, 1);
|
|
game::gScrVarPub[inst].fieldBuffer = fieldBuffer;
|
|
*fieldBuffer = 0;
|
|
radiantKeysName = "keys";
|
|
if (inst)
|
|
{
|
|
radiantKeysName = "clientkeys";
|
|
}
|
|
sprintf_s(Buffer, "%s/%s.%s", path, radiantKeysName, extension);
|
|
game::Scr_AddFieldsForFile(inst, Buffer);
|
|
*(char*)game::Hunk_UserAlloc(*game::g_user, 1, 1) = 0;
|
|
}
|
|
|
|
// Decomp Status: Tested, Completed
|
|
int Scr_MakeValuePrimitive(game::scriptInstance_t inst, unsigned int parentId)
|
|
{
|
|
int id;
|
|
game::VariableValueInternal* entryValue;
|
|
unsigned int varType;
|
|
unsigned int varName;
|
|
game::VariableValueInternal* parentValue;
|
|
|
|
parentValue = &game::gScrVarGlob[inst].parentVariables[parentId + 1];
|
|
|
|
assert((parentValue->w.status & VAR_STAT_MASK) == VAR_STAT_EXTERNAL);
|
|
|
|
assert((parentValue->w.status & VAR_STAT_MASK) != VAR_STAT_FREE);
|
|
|
|
assert(IsObject(parentValue));
|
|
|
|
assert((parentValue->w.type & VAR_MASK) != game::VAR_THREAD);
|
|
|
|
assert((parentValue->w.type & VAR_MASK) != game::VAR_NOTIFY_THREAD);
|
|
|
|
assert((parentValue->w.type & VAR_MASK) != game::VAR_TIME_THREAD);
|
|
|
|
assert((parentValue->w.type & VAR_MASK) != game::VAR_CHILD_THREAD);
|
|
|
|
if ((parentValue->w.status & VAR_MASK) != game::VAR_ARRAY)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
id = game::FindFirstSibling(inst, parentId);
|
|
while (id)
|
|
{
|
|
entryValue = &game::gScrVarGlob[inst].childVariables[id];
|
|
|
|
assert((entryValue->w.status & VAR_STAT_MASK) != VAR_STAT_FREE && (entryValue->w.status & VAR_STAT_MASK) != VAR_STAT_EXTERNAL);
|
|
|
|
assert((entryValue->w.status & VAR_STAT_MASK) != VAR_STAT_FREE);
|
|
|
|
assert(!IsObject(entryValue));
|
|
|
|
varType = entryValue->w.status & VAR_MASK;
|
|
varName = entryValue->w.status >> VAR_NAME_BIT_SHIFT;
|
|
|
|
if (varType == game::VAR_POINTER)
|
|
{
|
|
if (!game::Scr_MakeValuePrimitive(inst, entryValue->u.u.intValue))
|
|
{
|
|
game::RemoveVariable(varName, parentId, inst);
|
|
id = game::gScrVarGlob[inst].parentVariables[parentId + 1].nextSibling;
|
|
continue;
|
|
}
|
|
}
|
|
else if (varType > game::VAR_INTEGER && varType <= game::VAR_ANIMATION)
|
|
{
|
|
game::RemoveVariable(varName, parentId, inst);
|
|
id = game::gScrVarGlob[inst].parentVariables[parentId + 1].nextSibling;
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
assert(varType < game::VAR_UNDEFINED || varType > game::VAR_ANIMATION);
|
|
}
|
|
|
|
id = game::FindNextSibling(inst, id);
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
// Decomp Status: Tested, Completed
|
|
void Scr_FreeGameVariable(game::scriptInstance_t inst, int bComplete)
|
|
{
|
|
unsigned int* gameId;
|
|
game::VariableValueInternal* entryValue;
|
|
|
|
assert(game::gScrVarPub[inst].gameId);
|
|
|
|
if (bComplete)
|
|
{
|
|
gameId = &game::gScrVarPub[inst].gameId;
|
|
game::FreeValue(*gameId, inst);
|
|
*gameId = 0;
|
|
}
|
|
else
|
|
{
|
|
entryValue = &game::gScrVarGlob[inst].childVariables[game::gScrVarPub[inst].gameId];
|
|
|
|
assert((entryValue->w.type & VAR_MASK) == game::VAR_POINTER);
|
|
|
|
game::Scr_MakeValuePrimitive(inst, game::gScrVarGlob[inst].childVariables[game::gScrVarPub[inst].gameId].u.u.intValue);
|
|
}
|
|
}
|
|
|
|
// Decomp Status: Tested, Completed
|
|
bool Scr_SLHasLowercaseString(unsigned int parentId, const char* str)
|
|
{
|
|
unsigned int slStr;
|
|
game::VariableValueInternal* childVar;
|
|
unsigned int childVarIndex;
|
|
game::scriptInstance_t inst = game::SCRIPTINSTANCE_SERVER;
|
|
|
|
slStr = game::SL_GetLowercaseStringOfLen(inst, str, 0, strlen(str) + 1);
|
|
childVarIndex = game::FindVariableIndexInternal(inst, parentId, slStr);
|
|
if (game::gScrVarGlob[inst].childVariables[childVarIndex].hash.id)
|
|
{
|
|
game::SL_RemoveRefToString(slStr, inst);
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
childVarIndex = game::GetVariable(inst, parentId, slStr);
|
|
game::SL_RemoveRefToString(slStr, inst);
|
|
childVar = &game::gScrVarGlob[inst].childVariables[childVarIndex];
|
|
game::RemoveRefToValueInternal(inst, (game::VariableType)(childVar->w.status & VAR_MASK), childVar->u.u); // RemoveRefToValue
|
|
childVar->w.status = childVar->w.status & 0xFFFFFFE6 | 6;
|
|
childVar->u.u.intValue = 0;
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
#pragma warning(pop)
|