#include #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@(game::scriptInstance_t inst@) 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@(const char *name@, game::scriptInstance_t inst@, 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@(unsigned int entClass@, int entNum@, game::scriptInstance_t inst@) 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@(int entNum@, 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@(game::scriptInstance_t a1@, game::VariableValue *a2@, 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@, game::VariableValue *eax0@, 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)