From 469e8f9630b12e3fde72cd8222008514bb0de12f Mon Sep 17 00:00:00 2001 From: ineed bots Date: Thu, 31 Aug 2023 18:56:00 -0600 Subject: [PATCH] The decomp is compiling! --- .../clientscript/clientscript_public.hpp | 8 + src/codsrc/clientscript/cscr_memorytree.cpp | 525 ++ src/codsrc/clientscript/cscr_memorytree.hpp | 21 + src/codsrc/clientscript/cscr_parser.cpp | 917 +++ src/codsrc/clientscript/cscr_parser.hpp | 31 + src/codsrc/clientscript/cscr_parsetree.cpp | 191 + src/codsrc/clientscript/cscr_parsetree.hpp | 19 + src/codsrc/clientscript/cscr_readwrite.cpp | 117 + src/codsrc/clientscript/cscr_readwrite.hpp | 8 + src/codsrc/clientscript/cscr_stringlist.cpp | 821 +++ src/codsrc/clientscript/cscr_stringlist.hpp | 42 + src/codsrc/clientscript/cscr_tempmemory.cpp | 23 + src/codsrc/clientscript/cscr_tempmemory.hpp | 8 + src/codsrc/clientscript/cscr_variable.cpp | 4254 +++++++++++++ src/codsrc/clientscript/cscr_variable.hpp | 141 + src/codsrc/clientscript/cscr_vm.cpp | 5636 +++++++++++++++++ src/codsrc/clientscript/cscr_vm.hpp | 119 + .../decomp/clientscript/re_cscr_main.cpp | 1 - .../clientscript/re_cscr_memorytree.cpp | 2 +- .../decomp/clientscript/re_cscr_parser.cpp | 2 +- .../decomp/clientscript/re_cscr_parsetree.cpp | 3 +- .../decomp/clientscript/re_cscr_readwrite.cpp | 2 +- .../clientscript/re_cscr_stringlist.cpp | 3 +- .../decomp/clientscript/re_cscr_variable.cpp | 30 +- .../decomp/clientscript/re_cscr_vm.cpp | 3 +- src/game/clientscript/clientscript_public.hpp | 41 +- .../clientscript/clientscript_public_w.cpp | 59 +- src/game/clientscript/cscr_memorytree.hpp | 1 - src/game/clientscript/cscr_memorytree_w.cpp | 10 +- src/game/clientscript/cscr_parser_w.cpp | 6 +- src/game/clientscript/cscr_parsetree_w.cpp | 4 +- src/game/clientscript/cscr_readwrite_w.cpp | 4 +- src/game/clientscript/cscr_stringlist.hpp | 1 - src/game/clientscript/cscr_stringlist_w.cpp | 28 +- src/game/clientscript/cscr_tempmemory_w.cpp | 8 +- src/game/clientscript/cscr_variable_w.cpp | 84 +- src/game/clientscript/cscr_vm_w.cpp | 104 +- src/game/game.cpp | 177 + src/game/symbols.hpp | 62 +- src/game/xasset.hpp | 1 + src/stdinc.hpp | 5 +- 41 files changed, 13313 insertions(+), 209 deletions(-) create mode 100644 src/codsrc/clientscript/cscr_memorytree.cpp create mode 100644 src/codsrc/clientscript/cscr_memorytree.hpp create mode 100644 src/codsrc/clientscript/cscr_parser.cpp create mode 100644 src/codsrc/clientscript/cscr_parser.hpp create mode 100644 src/codsrc/clientscript/cscr_parsetree.cpp create mode 100644 src/codsrc/clientscript/cscr_parsetree.hpp create mode 100644 src/codsrc/clientscript/cscr_readwrite.cpp create mode 100644 src/codsrc/clientscript/cscr_readwrite.hpp create mode 100644 src/codsrc/clientscript/cscr_stringlist.cpp create mode 100644 src/codsrc/clientscript/cscr_stringlist.hpp create mode 100644 src/codsrc/clientscript/cscr_tempmemory.cpp create mode 100644 src/codsrc/clientscript/cscr_tempmemory.hpp create mode 100644 src/codsrc/clientscript/cscr_variable.cpp create mode 100644 src/codsrc/clientscript/cscr_variable.hpp create mode 100644 src/codsrc/clientscript/cscr_vm.cpp create mode 100644 src/codsrc/clientscript/cscr_vm.hpp diff --git a/src/codsrc/clientscript/clientscript_public.hpp b/src/codsrc/clientscript/clientscript_public.hpp index bb23257..e5eb8c1 100644 --- a/src/codsrc/clientscript/clientscript_public.hpp +++ b/src/codsrc/clientscript/clientscript_public.hpp @@ -1,3 +1,11 @@ #pragma once #include "cscr_main.hpp" +#include "cscr_memorytree.hpp" +#include "cscr_parser.hpp" +#include "cscr_parsetree.hpp" +#include "cscr_readwrite.hpp" +#include "cscr_stringlist.hpp" +#include "cscr_tempmemory.hpp" +#include "cscr_variable.hpp" +#include "cscr_vm.hpp" diff --git a/src/codsrc/clientscript/cscr_memorytree.cpp b/src/codsrc/clientscript/cscr_memorytree.cpp new file mode 100644 index 0000000..1f14e0a --- /dev/null +++ b/src/codsrc/clientscript/cscr_memorytree.cpp @@ -0,0 +1,525 @@ +#include +#include "clientscript_public.hpp" + +namespace codsrc +{ + // Restored + game::RefVector* GetRefVector(game::scriptInstance_t inst, unsigned int id) + { + assert(id); + + assert((id * MT_NODE_SIZE) < MT_SIZE); + + return (game::RefVector*)&game::gScrMemTreePub[inst].mt_buffer->nodes[id]; + } + + // Decomp Status: Tested, Completed + int MT_GetSubTreeSize(game::scriptInstance_t inst, int nodeNum) + { + int treeSize; + + if (nodeNum) + { + treeSize = game::MT_GetSubTreeSize(inst, game::gScrMemTreeGlob[inst].nodes[nodeNum].next); + return treeSize + game::MT_GetSubTreeSize(inst, game::gScrMemTreeGlob[inst].nodes[nodeNum].prev) + 1; + } + else + { + return 0; + } + } + + // Decomp Status: Tested, Completed + void MT_DumpTree(game::scriptInstance_t inst) + { + int size; + + //assert(game::gScrMemTreeGlob[inst].totalAlloc == totalAlloc); + //assert(game::gScrMemTreeGlob[inst].totalAllocBuckets == totalAllocBuckets); + + game::Com_Printf(game::CON_CHANNEL_PARSERSCRIPT, "********************************\n"); + for (int i = 0; i <= MT_NODE_BITS; ++i) + { + size = game::MT_GetSubTreeSize(inst, game::gScrMemTreeGlob[inst].head[i]); + game::Com_Printf(game::CON_CHANNEL_PARSERSCRIPT, "%d subtree has %d * %d = %d free buckets\n", i, size, 1 << i, size << i); + } + game::Com_Printf(game::CON_CHANNEL_PARSERSCRIPT, "********************************\n"); + game::Com_Printf(game::CON_CHANNEL_PARSERSCRIPT, "********************************\n"); + game::Com_Printf(game::CON_CHANNEL_PARSERSCRIPT, "********************************\n"); + + //assert(totalBuckets == (1 << MEMORY_NODE_BITS) - 1); + } + + // Decomp Status: Tested, Completed + void MT_InitBits(game::scriptInstance_t inst) + { + char bits; + int temp; + int i; + + for (i = 0; i < MT_NUM_BUCKETS; ++i) + { + bits = 0; + + for (temp = i; temp; temp >>= 1) + { + if (temp & 1) + { + ++bits; + } + } + + game::gScrMemTreeGlob[inst].numBits[i] = bits; + + for (bits = 8; i & ((1 << bits) - 1); --bits); + + game::gScrMemTreeGlob[inst].leftBits[i] = bits; + bits = 0; + + for (temp = i; temp; temp >>= 1) + { + ++bits; + } + + game::gScrMemTreeGlob[inst].logBits[i] = bits; + } + } + + // Decomp Status: Tested, Completed + int MT_GetScore(game::scriptInstance_t inst, int num) + { + char bits; + + union MTnum_t + { + int i; + uint8_t b[4]; + }; + + assert(num); + + assert(MT_NODE_COUNT - num); + + MTnum_t mtnum; + + mtnum.i = MT_NODE_COUNT - num; + + bits = game::gScrMemTreeGlob[inst].leftBits[mtnum.b[0]]; + + if (!mtnum.b[0]) + { + bits += game::gScrMemTreeGlob[inst].leftBits[mtnum.b[1]]; + } + + return mtnum.i - (game::gScrMemTreeGlob[inst].numBits[mtnum.b[1]] + game::gScrMemTreeGlob[inst].numBits[mtnum.b[0]]) + (1 << bits); + } + + // Decomp Status: Tested, Completed + void MT_AddMemoryNode(game::scriptInstance_t inst, int newNode, int size) + { + int node; + int nodeNum; + int newScore; + uint16_t* parentNode; + int level; + int score; + + assert(size >= 0 && size <= MT_NODE_BITS); + + parentNode = &game::gScrMemTreeGlob[inst].head[size]; + node = game::gScrMemTreeGlob[inst].head[size]; + if (game::gScrMemTreeGlob[inst].head[size]) + { + newScore = game::MT_GetScore(inst, newNode); + nodeNum = 0; + level = MT_NODE_COUNT; + do + { + assert(newNode != node); + + score = game::MT_GetScore(inst, node); + + assert(score != newScore); + + if (score < newScore) + { + while (1) + { + *parentNode = (short)newNode; + game::gScrMemTreeGlob[inst].nodes[newNode] = game::gScrMemTreeGlob[inst].nodes[node]; + if (!node) + { + break; + } + level >>= 1; + + assert(node != nodeNum); + + if (node >= nodeNum) + { + parentNode = &game::gScrMemTreeGlob[inst].nodes[newNode].next; + nodeNum += level; + } + else + { + parentNode = &game::gScrMemTreeGlob[inst].nodes[newNode].prev; + nodeNum -= level; + } + + newNode = node; + node = *parentNode; + } + return; + } + level >>= 1; + + assert(newNode != nodeNum); + + if (newNode >= nodeNum) + { + parentNode = &game::gScrMemTreeGlob[inst].nodes[node].next; + nodeNum += level; + } + else + { + parentNode = &game::gScrMemTreeGlob[inst].nodes[node].prev; + nodeNum -= level; + } + + node = *parentNode; + } while (node); + } + + *parentNode = (short)newNode; + + game::gScrMemTreeGlob[inst].nodes[newNode].prev = 0; + game::gScrMemTreeGlob[inst].nodes[newNode].next = 0; + } + + // Decomp Status: Tested, Completed + char MT_RemoveMemoryNode(game::scriptInstance_t inst, int oldNode, int size) + { + game::MemoryNode tempNodeValue; + int node; + game::MemoryNode oldNodeValue; + int nodeNum; + uint16_t* parentNode; + int prevScore; + int nextScore; + int level; + + assert(size >= 0 && size <= MT_NODE_BITS); + + nodeNum = 0; + level = MT_NODE_COUNT; + parentNode = &game::gScrMemTreeGlob[inst].head[size]; + + for (node = *parentNode; node; node = *parentNode) + { + if (oldNode == node) + { + oldNodeValue = game::gScrMemTreeGlob[inst].nodes[oldNode]; + + while (1) + { + if (oldNodeValue.prev) + { + if (oldNodeValue.next) + { + prevScore = game::MT_GetScore(inst, oldNodeValue.prev); + nextScore = game::MT_GetScore(inst, oldNodeValue.next); + + assert(prevScore != nextScore); + + if (prevScore >= nextScore) + { + oldNode = oldNodeValue.prev; + *parentNode = oldNodeValue.prev; + parentNode = &game::gScrMemTreeGlob[inst].nodes[oldNodeValue.prev].prev; + } + else + { + oldNode = oldNodeValue.next; + *parentNode = oldNodeValue.next; + parentNode = &game::gScrMemTreeGlob[inst].nodes[oldNodeValue.next].next; + } + } + else + { + oldNode = oldNodeValue.prev; + *parentNode = oldNodeValue.prev; + parentNode = &game::gScrMemTreeGlob[inst].nodes[oldNodeValue.prev].prev; + } + } + else + { + oldNode = oldNodeValue.next; + *parentNode = oldNodeValue.next; + + if (!oldNodeValue.next) + { + return true; + } + + parentNode = &game::gScrMemTreeGlob[inst].nodes[oldNodeValue.next].next; + } + + assert(oldNode); + + tempNodeValue = oldNodeValue; + oldNodeValue = game::gScrMemTreeGlob[inst].nodes[oldNode]; + game::gScrMemTreeGlob[inst].nodes[oldNode] = tempNodeValue; + } + } + + if (oldNode == nodeNum) + { + return false; + } + + level >>= 1; + + if (oldNode >= nodeNum) + { + parentNode = &game::gScrMemTreeGlob[inst].nodes[node].next; + nodeNum += level; + } + else + { + parentNode = &game::gScrMemTreeGlob[inst].nodes[node].prev; + nodeNum -= level; + } + } + + return false; + } + + // Decomp Status: Tested, Completed + void MT_RemoveHeadMemoryNode(game::scriptInstance_t inst, int size) + { + game::MemoryNode tempNodeValue; + int oldNode; + game::MemoryNode oldNodeValue; + uint16_t* parentNode; + int prevScore; + int nextScore; + + assert(size >= 0 && size <= MT_NODE_BITS); + + parentNode = &game::gScrMemTreeGlob[inst].head[size]; + oldNodeValue = game::gScrMemTreeGlob[inst].nodes[*parentNode]; + + while (1) + { + if (!oldNodeValue.prev) + { + oldNode = oldNodeValue.next; + *parentNode = oldNodeValue.next; + if (!oldNode) + { + break; + } + parentNode = &game::gScrMemTreeGlob[inst].nodes[oldNode].next; + } + else + { + if (oldNodeValue.next) + { + prevScore = game::MT_GetScore(inst, oldNodeValue.prev); + nextScore = game::MT_GetScore(inst, oldNodeValue.next); + + assert(prevScore != nextScore); + + if (prevScore >= nextScore) + { + oldNode = oldNodeValue.prev; + *parentNode = (short)oldNode; + parentNode = &game::gScrMemTreeGlob[inst].nodes[oldNode].prev; + } + else + { + oldNode = oldNodeValue.next; + *parentNode = (short)oldNode; + parentNode = &game::gScrMemTreeGlob[inst].nodes[oldNode].next; + } + } + else + { + oldNode = oldNodeValue.prev; + *parentNode = (short)oldNode; + parentNode = &game::gScrMemTreeGlob[inst].nodes[oldNode].prev; + } + } + assert(oldNode != 0); + + tempNodeValue = oldNodeValue; + oldNodeValue = game::gScrMemTreeGlob[inst].nodes[oldNode]; + game::gScrMemTreeGlob[inst].nodes[oldNode] = tempNodeValue; + } + } + + // Decomp Status: Tested, Completed + void MT_Init(game::scriptInstance_t inst) + { + game::Sys_EnterCriticalSection(game::CRITSECT_MEMORY_TREE); + + game::scrMemTreeGlob_t* memTreeBuffer = &game::gScrMemTreeGlob[inst]; + game::gScrMemTreePub[inst].mt_buffer = memTreeBuffer; + + game::MT_InitBits(inst); + + for (int i = 0; i <= MT_NODE_BITS; ++i) + { + memTreeBuffer->head[i] = 0; + } + + memTreeBuffer->nodes[0].next = 0; + memTreeBuffer->nodes[0].prev = 0; + + for (int i = 0; i < MT_NODE_BITS; ++i) + { + game::MT_AddMemoryNode(inst, 1 << i, i); + } + + game::Sys_LeaveCriticalSection(game::CRITSECT_MEMORY_TREE); + } + + // Decomp Status: Tested, Completed + void MT_Error(game::scriptInstance_t inst, const char* funcName, int numBytes) + { + game::MT_DumpTree(inst); + game::Com_Printf(game::CON_CHANNEL_PARSERSCRIPT, "%s: failed memory allocation of %d bytes for script usage\n", funcName, numBytes); + game::Scr_DumpScriptThreads(inst); + game::gScrVmPub[inst].terminal_error = 1; + game::Scr_Error("failed memory allocation for script usage", inst, 0); + } + + // Decomp Status: Tested, Completed + int MT_GetSize(int numBytes, game::scriptInstance_t inst) + { + int numBuckets; + int result; + + assert(numBytes > 0); + + if (numBytes >= MT_NODE_COUNT) + { + game::MT_Error(inst, "MT_GetSize: max allocation exceeded", numBytes); + result = 0; + } + else + { + numBuckets = (numBytes + MT_NODE_SIZE - 1) / MT_NODE_SIZE - 1; + if (numBuckets > MT_NUM_BUCKETS - 1) + { + result = game::gScrMemTreeGlob[inst].logBits[numBuckets >> 8] + 8; + } + else + { + result = game::gScrMemTreeGlob[inst].logBits[numBuckets]; + } + } + return result; + } + + // Decomp Status: Tested, Completed + unsigned __int16 MT_AllocIndex(game::scriptInstance_t inst, int numBytes) + { + int nodeNum; + int size = game::MT_GetSize(numBytes, inst); + int newSize; + + assert(size >= 0 && size <= MT_NODE_BITS); + + game::Sys_EnterCriticalSection(game::CRITSECT_MEMORY_TREE); + + for (newSize = size; ; ++newSize) + { + if (newSize > MT_NODE_BITS) + { + game::Sys_LeaveCriticalSection(game::CRITSECT_MEMORY_TREE); + game::MT_Error(inst, "MT_AllocIndex", numBytes); + return 0; + } + nodeNum = game::gScrMemTreeGlob[inst].head[newSize]; + if (game::gScrMemTreeGlob[inst].head[newSize]) + { + break; + } + } + + game::MT_RemoveHeadMemoryNode(inst, newSize); + + while (newSize != size) + { + --newSize; + game::MT_AddMemoryNode(inst, nodeNum + (1 << newSize), newSize); + } + + //assert(type); + + //assert(!game::gScrMemTreeDebugGlob[inst].mt_usage[nodeNum]); + + //assert(!game::gScrMemTreeDebugGlob[inst].mt_usage_size[nodeNum]); + + game::Sys_LeaveCriticalSection(game::CRITSECT_MEMORY_TREE); + return (short)nodeNum; + } + + // Decomp Status: Tested, Completed + void MT_FreeIndex(int numBytes, game::scriptInstance_t inst, int nodeNum) + { + int size = game::MT_GetSize(numBytes, inst); + + assert(size >= 0 && size <= MT_NODE_BITS); + + assert(nodeNum > 0 && nodeNum < MT_NODE_COUNT); + + game::Sys_EnterCriticalSection(game::CRITSECT_MEMORY_TREE); + + //assert(game::gScrMemTreeDebugGlob[inst].mt_usage[nodeNum]); + + //assert(game::gScrMemTreeDebugGlob[inst].mt_usage_size[nodeNum] == size); + + for (int i = 1 << size; size != MT_NODE_BITS; i = 1 << ++size) + { + assert(size <= MT_NODE_BITS); + + assert(nodeNum == (nodeNum & ~((1 << size) - 1))); + + if (!game::MT_RemoveMemoryNode(inst, nodeNum ^ i, size)) + { + break; + } + nodeNum &= ~i; + } + game::MT_AddMemoryNode(inst, nodeNum, size); + + game::Sys_LeaveCriticalSection(game::CRITSECT_MEMORY_TREE); + } + + // Decomp Status: Tested, Completed + char* MT_Alloc(int numBytes, game::scriptInstance_t inst) + { + return (char*)(game::gScrMemTreeGlob[inst].nodes + game::MT_AllocIndex(inst, numBytes)); + } + + // Decomp Status: Tested, Completed + void MT_Free(void* p, int numBytes, game::scriptInstance_t inst) + { + assert((game::MemoryNode*)p - game::gScrMemTreeGlob[inst].nodes >= 0 && (game::MemoryNode*)p - game::gScrMemTreeGlob[inst].nodes < MT_NODE_COUNT); + + game::MT_FreeIndex(numBytes, inst, (game::MemoryNode*)p - game::gScrMemTreeGlob[inst].nodes); + } + + // Restored inlined function + char* MT_GetRefByIndex(game::scriptInstance_t inst, int index) + { + if (index > MT_NODE_COUNT) + { + game::MT_Error(inst, "MT_GetRefByIndex: out of bounds index", index); + return NULL; + } + return (char*)&game::gScrMemTreeGlob[inst].nodes[index]; + } +} \ No newline at end of file diff --git a/src/codsrc/clientscript/cscr_memorytree.hpp b/src/codsrc/clientscript/cscr_memorytree.hpp new file mode 100644 index 0000000..8e36784 --- /dev/null +++ b/src/codsrc/clientscript/cscr_memorytree.hpp @@ -0,0 +1,21 @@ +#pragma once + +namespace codsrc +{ + game::RefVector* GetRefVector(game::scriptInstance_t inst, unsigned int id); + int MT_GetSubTreeSize(game::scriptInstance_t inst, int nodeNum); + void MT_DumpTree(game::scriptInstance_t inst); + void MT_InitBits(game::scriptInstance_t inst); + int MT_GetScore(game::scriptInstance_t inst, int num); + void MT_AddMemoryNode(game::scriptInstance_t inst, int newNode, int size); + char MT_RemoveMemoryNode(game::scriptInstance_t inst, int oldNode, int size); + void MT_RemoveHeadMemoryNode(game::scriptInstance_t inst, int size); + void MT_Init(game::scriptInstance_t inst); + void MT_Error(game::scriptInstance_t inst, const char* funcName, int numBytes); + int MT_GetSize(int numBytes, game::scriptInstance_t inst); + unsigned __int16 MT_AllocIndex(game::scriptInstance_t inst, int numBytes); + void MT_FreeIndex(int numBytes, game::scriptInstance_t inst, int nodeNum); + char* MT_Alloc(int numBytes, game::scriptInstance_t inst); + void MT_Free(void* p, int numBytes, game::scriptInstance_t inst); + const char* MT_NodeInfoString(game::scriptInstance_t inst, unsigned int nodeNum); +} diff --git a/src/codsrc/clientscript/cscr_parser.cpp b/src/codsrc/clientscript/cscr_parser.cpp new file mode 100644 index 0000000..3357608 --- /dev/null +++ b/src/codsrc/clientscript/cscr_parser.cpp @@ -0,0 +1,917 @@ +#include +#include "clientscript_public.hpp" + +namespace codsrc +{ + // Decomp Status: Tested, Completed + void Scr_InitOpcodeLookup(game::scriptInstance_t inst) + { + unsigned int opcodeLookupMaxLen; + game::OpcodeLookup* opcodeLookup; + unsigned int sourcePosLookupMaxLen; + game::HunkUser* debugHunkUser; + unsigned int sourceBufferLookupMaxLen; + + assert(!game::gScrParserGlob[inst].opcodeLookup); + + assert(!game::gScrParserGlob[inst].sourcePosLookup); + + assert(!game::gScrParserPub[inst].sourceBufferLookup); + + if (game::gScrVarPub[inst].developer) + { + debugHunkUser = (game::HunkUser*)game::g_DebugHunkUser.get(); + opcodeLookupMaxLen = inst != game::SCRIPTINSTANCE_CLIENT ? 0x40000 : 0x4000; + game::gScrParserGlob[inst].opcodeLookupMaxLen = opcodeLookupMaxLen; + game::gScrParserGlob[inst].delayedSourceIndex = -1; + game::gScrParserGlob[inst].opcodeLookupLen = 0; + opcodeLookup = (game::OpcodeLookup*)game::Hunk_UserAlloc(debugHunkUser, 24 * opcodeLookupMaxLen, 4); + game::gScrParserGlob[inst].opcodeLookup = opcodeLookup; + + memset(opcodeLookup, 0, sizeof(game::OpcodeLookup) * game::gScrParserGlob[inst].opcodeLookupMaxLen); + + sourcePosLookupMaxLen = inst != game::SCRIPTINSTANCE_CLIENT ? 0x60000 : 0x10; + game::gScrParserGlob[inst].sourcePosLookupMaxLen = sourcePosLookupMaxLen; + game::gScrParserGlob[inst].sourcePosLookupLen = 0; + game::gScrParserGlob[inst].sourcePosLookup = (game::SourceLookup*)game::Hunk_UserAlloc(debugHunkUser, 8 * sourcePosLookupMaxLen, 4); + sourceBufferLookupMaxLen = inst != game::SCRIPTINSTANCE_CLIENT ? 0x100 : 0x10; + game::gScrParserGlob[inst].sourceBufferLookupMaxLen = sourceBufferLookupMaxLen; + game::gScrParserGlob[inst].currentCodePos = 0; + game::gScrParserGlob[inst].currentSourcePosCount = 0; + game::gScrParserPub[inst].sourceBufferLookupLen = 0; + game::gScrParserPub[inst].sourceBufferLookup = (game::SourceBufferInfo*)game::Hunk_UserAlloc(debugHunkUser, 24 * sourceBufferLookupMaxLen, 4); + } + } + + // Decomp Status: Tested, Completed + void Scr_ShutdownOpcodeLookup(game::scriptInstance_t inst) + { + if (game::gScrParserGlob[inst].opcodeLookup) + { + game::gScrParserGlob[inst].opcodeLookup = 0; + } + if (game::gScrParserGlob[inst].sourcePosLookup) + { + game::gScrParserGlob[inst].sourcePosLookup = 0; + } + if (game::gScrParserPub[inst].sourceBufferLookup != 0) + { + game::gScrParserPub[inst].sourceBufferLookup = 0; + } + if (game::gScrParserGlob[inst].saveSourceBufferLookup) + { + game::gScrParserGlob[inst].saveSourceBufferLookup = 0; + } + } + + // Decomp Status: Completed + void AddOpcodePos(game::scriptInstance_t inst, unsigned int sourcePos, int type) + { + game::OpcodeLookup* newOpcodeLookup; + game::SourceLookup* newSourcePosLookup; + char* compilerOpcodePos; + game::OpcodeLookup* opcodeLookup; + int posIndex; + game::SourceLookup* sourcePosLookup; + int delayedSourceIndex; + int allocSize; + + if (game::gScrVarPub[inst].developer) + { + if (game::gScrCompilePub[inst].developer_statement != 2) + { + if (!game::gScrCompilePub[inst].allowedBreakpoint) + { + type &= ~1u; + } + + assert(game::gScrParserGlob[inst].opcodeLookup); + + assert(game::gScrParserGlob[inst].opcodeLookupMaxLen); + + assert(game::gScrParserGlob[inst].sourcePosLookup); + + assert(game::gScrCompilePub[inst].opcodePos); + + if (game::gScrParserGlob[inst].opcodeLookupLen >= game::gScrParserGlob[inst].opcodeLookupMaxLen) + { + allocSize = (sizeof(game::OpcodeLookup) * 2) * game::gScrParserGlob[inst].opcodeLookupMaxLen; + game::gScrParserGlob[inst].opcodeLookupMaxLen *= 2; + + assert(game::gScrParserGlob[inst].opcodeLookupLen < game::gScrParserGlob[inst].opcodeLookupMaxLen); + + newOpcodeLookup = (game::OpcodeLookup*)game::Hunk_UserAlloc((game::HunkUser*)game::g_DebugHunkUser.get(), allocSize, 4); + memcpy(newOpcodeLookup, game::gScrParserGlob[inst].opcodeLookup, sizeof(game::OpcodeLookup) * game::gScrParserGlob[inst].opcodeLookupLen); + game::gScrParserGlob[inst].opcodeLookup = newOpcodeLookup; + } + + if (game::gScrParserGlob[inst].sourcePosLookupLen >= game::gScrParserGlob[inst].sourcePosLookupMaxLen) + { + allocSize = (sizeof(game::SourceLookup) * 2) * game::gScrParserGlob[inst].sourcePosLookupMaxLen; + game::gScrParserGlob[inst].sourcePosLookupMaxLen *= 2; + + assert(game::gScrParserGlob[inst].sourcePosLookupLen < game::gScrParserGlob[inst].sourcePosLookupMaxLen); + + newSourcePosLookup = (game::SourceLookup*)game::Hunk_UserAlloc((game::HunkUser*)game::g_DebugHunkUser.get(), allocSize, 4); + memcpy(newSourcePosLookup, game::gScrParserGlob[inst].sourcePosLookup, sizeof(game::SourceLookup) * game::gScrParserGlob[inst].sourcePosLookupLen); + game::gScrParserGlob[inst].sourcePosLookup = newSourcePosLookup; + } + + compilerOpcodePos = game::gScrCompilePub[inst].opcodePos; + if ((char*)game::gScrParserGlob[inst].currentCodePos == compilerOpcodePos) + { + //assert(game::gScrParserGlob[inst].currentSourcePosCount); + + opcodeLookup = &game::gScrParserGlob[inst].opcodeLookup[--game::gScrParserGlob[inst].opcodeLookupLen]; + + //assert(opcodeLookup->sourcePosIndex + game::gScrParserGlob[inst].currentSourcePosCount == game::gScrParserGlob[inst].sourcePosLookupLen); + + //assert(opcodeLookup->codePos == (char*)game::gScrParserGlob[inst].currentCodePos); + } + else + { + game::gScrParserGlob[inst].currentCodePos = (const unsigned char*)compilerOpcodePos; + opcodeLookup = &game::gScrParserGlob[inst].opcodeLookup[game::gScrParserGlob[inst].opcodeLookupLen]; + game::gScrParserGlob[inst].currentSourcePosCount = 0; + opcodeLookup->sourcePosIndex = game::gScrParserGlob[inst].sourcePosLookupLen; + opcodeLookup->codePos = (const char*)game::gScrParserGlob[inst].currentCodePos; + } + + posIndex = game::gScrParserGlob[inst].currentSourcePosCount + opcodeLookup->sourcePosIndex; + sourcePosLookup = &game::gScrParserGlob[inst].sourcePosLookup[posIndex]; + sourcePosLookup->sourcePos = sourcePos; + if (sourcePos == -1) + { + assert(game::gScrParserGlob[inst].delayedSourceIndex == -1); + + assert(type & game::SOURCE_TYPE_BREAKPOINT); + + game::gScrParserGlob[inst].delayedSourceIndex = posIndex; + } + else if (sourcePos == -2) + { + game::gScrParserGlob[inst].threadStartSourceIndex = posIndex; + } + else + { + delayedSourceIndex = game::gScrParserGlob[inst].delayedSourceIndex; + if (delayedSourceIndex >= 0 && (type & 1) != 0) + { + game::gScrParserGlob[inst].sourcePosLookup[delayedSourceIndex].sourcePos = sourcePos; + game::gScrParserGlob[inst].delayedSourceIndex = -1; + } + } + + sourcePosLookup->type |= type; + opcodeLookup->sourcePosCount = ++game::gScrParserGlob[inst].currentSourcePosCount; + ++game::gScrParserGlob[inst].opcodeLookupLen; + ++game::gScrParserGlob[inst].sourcePosLookupLen; + } + else + { + assert(!game::gScrVarPub[inst].developer_script); + } + } + } + + // Decomp Status: Tested, Completed + void RemoveOpcodePos(game::scriptInstance_t inst) + { + game::OpcodeLookup* opcodeLookup; + + if (game::gScrVarPub[inst].developer) + { + if (game::gScrCompilePub[inst].developer_statement == 2) + { + assert(!game::gScrVarPub[inst].developer_script); + } + else + { + assert(game::gScrParserGlob[inst].opcodeLookup); + + assert(game::gScrParserGlob[inst].opcodeLookupMaxLen); + + assert(game::gScrParserGlob[inst].sourcePosLookup); + + assert(game::gScrCompilePub[inst].opcodePos); + + assert(game::gScrParserGlob[inst].sourcePosLookupLen); + + --game::gScrParserGlob[inst].sourcePosLookupLen; + + assert(game::gScrParserGlob[inst].opcodeLookupLen); + + --game::gScrParserGlob[inst].opcodeLookupLen; + + assert(game::gScrParserGlob[inst].currentSourcePosCount); + + --game::gScrParserGlob[inst].currentSourcePosCount; + opcodeLookup = &game::gScrParserGlob[inst].opcodeLookup[game::gScrParserGlob[inst].opcodeLookupLen]; + + assert((char*)game::gScrParserGlob[inst].currentCodePos == game::gScrCompilePub[inst].opcodePos); + + assert(opcodeLookup->sourcePosIndex + game::gScrParserGlob[inst].currentSourcePosCount == game::gScrParserGlob[inst].sourcePosLookupLen); + + assert(opcodeLookup->codePos == (char*)game::gScrParserGlob[inst].currentCodePos); + + if (game::gScrParserGlob[inst].currentSourcePosCount == 1) + { + game::gScrParserGlob[inst].currentCodePos = 0; + } + + game::gScrParserGlob[inst].opcodeLookup[game::gScrParserGlob[inst].opcodeLookupLen].sourcePosCount = game::gScrParserGlob[inst].currentSourcePosCount; + } + + } + } + + // Decomp Status: Tested, Completed + void AddThreadStartOpcodePos(game::scriptInstance_t inst, unsigned int sourcePos) + { + game::SourceLookup* sourcePosLookup; + + if (game::gScrVarPub[inst].developer) + { + if (game::gScrCompilePub[inst].developer_statement == 2) + { + assert(!game::gScrVarPub[inst].developer_script); + } + else + { + assert(game::gScrParserGlob[inst].threadStartSourceIndex >= 0); + + sourcePosLookup = &game::gScrParserGlob[inst].sourcePosLookup[game::gScrParserGlob[inst].threadStartSourceIndex]; + sourcePosLookup->sourcePos = sourcePos; + + assert(!sourcePosLookup->type); + + sourcePosLookup->type = 4; + game::gScrParserGlob[inst].threadStartSourceIndex = -1; + } + } + } + + // Decomp Status: Completed + unsigned int Scr_GetSourceBuffer(game::scriptInstance_t inst, const char* codePos) + { + unsigned int bufferIndex; + + assert(game::Scr_IsInOpcodeMemory(inst, codePos)); + + assert(game::gScrParserPub[inst].sourceBufferLookupLen > 0); + + for ( bufferIndex = game::gScrParserPub[inst].sourceBufferLookupLen - 1; + bufferIndex && (!game::gScrParserPub[inst].sourceBufferLookup[bufferIndex].codePos || game::gScrParserPub[inst].sourceBufferLookup[bufferIndex].codePos > codePos); + --bufferIndex ) + { + ; + } + + return bufferIndex; + } + + // Decomp Status: Tested, Completed + unsigned int Scr_GetLineNumInternal(const char** startLine, const char* buf, const char* sourcePos, int* col) + { + unsigned int lineNum; + + assert(buf); + + lineNum = 0; + for (*startLine = buf; sourcePos; --sourcePos) + { + if (!*buf) + { + *startLine = buf + 1; + ++lineNum; + } + ++buf; + } + *col = buf - *startLine; + return lineNum; + } + + // Decomp Status: Tested, Completed + game::SourceBufferInfo* Scr_GetNewSourceBuffer(game::scriptInstance_t inst) + { + unsigned int* sourceBufferLookupMaxLen; + int allocSize; + game::SourceBufferInfo* newSourceBufferInfo; + + assert(game::gScrParserPub[inst].sourceBufferLookup); + + assert(game::gScrParserGlob[inst].sourceBufferLookupMaxLen); + + if (game::gScrParserPub[inst].sourceBufferLookupLen < game::gScrParserGlob[inst].sourceBufferLookupMaxLen) + { + return &game::gScrParserPub[inst].sourceBufferLookup[game::gScrParserPub[inst].sourceBufferLookupLen++]; + } + + //assert(gScrParserPub[inst].sourceBufferLookupLen >= gScrParserGlob[inst].sourceBufferLookupMaxLen); + + sourceBufferLookupMaxLen = &game::gScrParserGlob[inst].sourceBufferLookupMaxLen; + allocSize = 2 * *sourceBufferLookupMaxLen; + *sourceBufferLookupMaxLen = allocSize; + newSourceBufferInfo = (game::SourceBufferInfo*)game::Hunk_UserAlloc((game::HunkUser*)game::g_DebugHunkUser.get(), sizeof(game::OpcodeLookup) * allocSize, 4); + memcpy(newSourceBufferInfo, game::gScrParserPub[inst].sourceBufferLookup, sizeof(game::OpcodeLookup) * game::gScrParserPub[inst].sourceBufferLookupLen); + game::gScrParserPub[inst].sourceBufferLookup = newSourceBufferInfo; + return &game::gScrParserPub[inst].sourceBufferLookup[game::gScrParserPub[inst].sourceBufferLookupLen++]; + } + + // Decomp Status: Tested, Completed + void Scr_AddSourceBufferInternal(const char* filename, game::scriptInstance_t inst, const char* codepos, char* buffer, int len, int archive) + { + game::SourceBufferInfo* newBuffer; + const char* source; + char* buf; + char c; + int i; + char* tmp; + size_t size; + char* dest; + + if (game::gScrParserPub[inst].sourceBufferLookup) + { + size = strlen(filename); + dest = (char*)game::Hunk_UserAlloc((struct game::HunkUser*)game::g_DebugHunkUser.get(), size + len + 3, 4); + memcpy(dest, filename, size + 1); + if (buffer) + { + source = &dest[size + 1]; + } + else + { + source = 0; + } + buf = buffer; + tmp = (char*)source; + if (len >= 0) + { + for (i = 0; i <= len; ++i) + { + c = *buf++; + if (c == '\n' || c == '\r' && *buf != '\n') + *tmp = 0; + else + *tmp = c; + ++tmp; + } + } + newBuffer = game::Scr_GetNewSourceBuffer(inst); + newBuffer->codePos = codepos; + newBuffer->buf = dest; + newBuffer->sourceBuf = source; + newBuffer->len = len; + newBuffer->sortedIndex = -1; + newBuffer->archive = archive; + if (source) + { + game::gScrParserPub[inst].sourceBuf = source; + } + } + else + { + game::gScrParserPub[inst].sourceBuf = 0; + } + } + + // Decomp Status: Tested, Completed + char* Scr_ReadFile_FastFile(game::scriptInstance_t inst, [[maybe_unused]] int unused, char* filename, const char* codepos, int archive) + { + char* buffer; + game::RawFile* scriptFile; + + scriptFile = game::DB_FindXAssetHeader(game::ASSET_TYPE_RAWFILE, filename, 1, -1).rawfile; + if ((*game::useFastFile)->current.enabled && scriptFile != 0) + { + game::Scr_AddSourceBufferInternal(filename, inst, codepos, scriptFile->buffer, strlen(scriptFile->buffer), archive); + buffer = scriptFile->buffer; + } + else + { + game::Scr_AddSourceBufferInternal(filename, inst, codepos, 0, -1, archive); + buffer = 0; + } + return buffer; + } + + // Decomp Status: Tested, Completed + char* Scr_ReadFile_LoadObj(game::scriptInstance_t inst, [[maybe_unused]] int unused_arg1, const char* filename, const char* codepos, int archive) + { + int fileLen; + int fh; + char* buffer; + + fileLen = game::FS_FOpenFileRead(filename, &fh); + if (fh) + { + game::fsh[fh].fileSize = fileLen; + game::fsh[fh].streamed = 0; + } + + game::fsh[fh].handleSync = 0; + if (fileLen >= 0) + { + if (!(*game::fs_game)->current.string) + { + game::Scr_SetLoadedImpureScript(true); + } + buffer = (char*)game::Hunk_AllocateTempMemoryHigh(fileLen + 1); + game::FS_Read(buffer, fileLen, fh); + buffer[fileLen] = 0; + game::FS_FCloseFile(fh); + game::Scr_AddSourceBufferInternal(filename, inst, codepos, buffer, fileLen, archive); + } + else + { + game::Scr_AddSourceBufferInternal(filename, inst, codepos, 0, -1, archive); + buffer = 0; + } + + return buffer; + } + + // Decomp Status: Tested, Completed + char* Scr_ReadFile(const char* codepos, char* filename, game::scriptInstance_t inst, int unused) + { + char* buffer; + int fh; + + if (*(*game::fs_game)->current.string || (*game::com_developer)->current.enabled) + { + *game::statmon_related_bool = 1; + if (game::FS_FOpenFileByMode(filename, &fh, game::FS_READ) < 0) + { + buffer = game::Scr_ReadFile_FastFile(inst, unused, filename, codepos, 1); + } + else + { + game::FS_FCloseFile(fh); + buffer = game::Scr_ReadFile_LoadObj(inst, unused, filename, codepos, 1); + } + } + else + { + if (!(*game::useFastFile)->current.enabled) + { + buffer = game::Scr_ReadFile_LoadObj(inst, unused, filename, codepos, 1); + } + else + { + buffer = game::Scr_ReadFile_FastFile(inst, unused, filename, codepos, 1); + } + + } + return buffer; + } + + // Decomp Status: Completed + char* Scr_AddSourceBuffer(game::scriptInstance_t inst, int unused_arg1, char* filename, const char* codepos) + { + unsigned int saveSourceBufferLookupLen; + int len; + game::SaveSourceBufferInfo* saveSourceBuffer; + char* dest; + char* sourceBuf; + char* source; + int len2; + char c; + + if (!game::gScrParserGlob[inst].saveSourceBufferLookup) + { + return game::Scr_ReadFile(codepos, filename, inst, unused_arg1); + } + + assert(game::gScrParserGlob[inst].saveSourceBufferLookupLen > 0); + + saveSourceBufferLookupLen = --game::gScrParserGlob[inst].saveSourceBufferLookupLen; + len = game::gScrParserGlob[inst].saveSourceBufferLookup[saveSourceBufferLookupLen].len; + saveSourceBuffer = &game::gScrParserGlob[inst].saveSourceBufferLookup[saveSourceBufferLookupLen]; + + assert(len >= -1); + + if (len >= 0) + { + sourceBuf = (char*)game::Hunk_AllocateTempMemoryHigh(len + 1); + source = (char*)saveSourceBuffer->sourceBuf; + dest = sourceBuf; + if (len > 0) + { + len2 = len; + do + { + c = *source++; + if (!c) + { + c = '\n'; + } + *dest++ = c; + --len2; + } while (len2); + } + *dest = 0; + } + else + { + dest = 0; + } + + game::Scr_AddSourceBufferInternal(filename, inst, codepos, dest, len, 1); + return dest; + } + + // Decomp Status: Completed + void Scr_CopyFormattedLine(const char* rawLine, char* line) + { + char cleanChar; + int len; + int i; + + len = strlen(rawLine); + if ( len >= 1024 ) + { + len = 1023; + } + + for ( i = 0; + i < len; + ++i ) + { + if ( rawLine[i] == '\t' ) + { + cleanChar = ' '; + } + else + { + cleanChar = rawLine[i]; + } + + line[i] = cleanChar; + } + + if ( line[len - 1] == '\r' ) + { + line[len - 1] = 0; + } + + line[len] = 0; + } + + // Decomp Status: Completed + unsigned int Scr_GetLineInfo(int* col, const char* buf, unsigned int sourcePos, char* line) + { + const char *startLine; + unsigned int lineNum; + + if ( buf ) + { + lineNum = game::Scr_GetLineNumInternal(&startLine, buf, (const char*)sourcePos, col); + } + else + { + lineNum = 0; + startLine = ""; + *col = 0; + } + + game::Scr_CopyFormattedLine(startLine, line); + return lineNum; + } + + // Decomp Status: Completed + void Scr_PrintSourcePos(unsigned int sourcePos, const char* buf, game::con_channel_e channel, game::scriptInstance_t inst, const char* file) + { + const char *fileVaLine; + const char *lineStr; + const char *savegameStr; + unsigned int lineNum; + char line[1024]; + int i; + int col; + + assert(file); + + lineNum = game::Scr_GetLineInfo(&col, buf, sourcePos, line); + + if ( game::gScrParserGlob[inst].saveSourceBufferLookup ) + { + savegameStr = " (savegame)"; + } + else + { + savegameStr = ""; + } + + fileVaLine = game::va("(file '%s'%s, line %d)\n", file, savegameStr, lineNum + 1); + game::Com_PrintMessage(channel, fileVaLine, 0); + + lineStr = game::va("%s\n", line); + game::Com_PrintMessage(channel, lineStr, 0); + + for ( i = 0; + i < col; + ++i ) + { + game::Com_PrintMessage(channel, " ", 0); + } + + game::Com_PrintMessage(channel, "*\n", 0); + } + + // Decomp Status: Completed + game::OpcodeLookup* Scr_GetPrevSourcePosOpcodeLookup(game::scriptInstance_t inst, const char* codePos) + { + unsigned int low; + unsigned int middle; + unsigned int high; + + assert(game::Scr_IsInOpcodeMemory(inst, codePos)); + + assert(game::gScrParserGlob[inst].opcodeLookup); + + low = 0; + high = game::gScrParserGlob[inst].opcodeLookupLen - 1; + while ( low <= high ) + { + middle = (high + low) >> 1; + if ( codePos < game::gScrParserGlob[inst].opcodeLookup[middle].codePos ) + { + high = middle - 1; + } + else + { + low = middle + 1; + if ( middle + 1 == game::gScrParserGlob[inst].opcodeLookupLen || codePos < game::gScrParserGlob[inst].opcodeLookup[low].codePos ) + { + return &game::gScrParserGlob[inst].opcodeLookup[middle]; + } + } + } + + assert(false); + + return 0; + } + + // Restored + unsigned int Scr_GetPrevSourcePos(game::scriptInstance_t inst, const char *codePos, unsigned int index) + { + return game::gScrParserGlob[inst].sourcePosLookup[index + game::Scr_GetPrevSourcePosOpcodeLookup(inst, codePos)->sourcePosIndex].sourcePos; + } + + // Decomp Status: Completed + void Scr_GetTextSourcePos(char* line, const char* codePos, game::scriptInstance_t inst) + { + unsigned int prevsourcePos; + unsigned int bufferIndex; + int col; + + if ( game::gScrVarPub[inst].developer + && codePos + && codePos != game::g_EndPos.get() + && game::gScrVarPub[inst].programBuffer + && game::Scr_IsInOpcodeMemory(inst, codePos) ) + { + bufferIndex = game::Scr_GetSourceBuffer(inst, codePos - 1); + prevsourcePos = game::Scr_GetPrevSourcePos(inst, codePos - 1, 0); + game::Scr_GetLineInfo(&col, game::gScrParserPub[inst].sourceBufferLookup[bufferIndex].sourceBuf, prevsourcePos, line); + } + else + { + *line = 0; + } + } + + // Decomp Status: Completed + void Scr_PrintPrevCodePos(const char* codepos, game::scriptInstance_t scriptInstance, game::con_channel_e channel, unsigned int index) + { + unsigned int bufferIndex; // esi + unsigned int prevSourcepos; // eax + + if (!codepos) + { + game::Com_PrintMessage(channel, "\n", 0); + return; + } + + if (codepos == game::g_EndPos.get()) + { + game::Com_PrintMessage(channel, "\n", 0); + } + else + { + if (game::gScrVarPub[scriptInstance].developer) + { + if (game::gScrVarPub[scriptInstance].programBuffer && game::Scr_IsInOpcodeMemory(scriptInstance, codepos)) + { + bufferIndex = game::Scr_GetSourceBuffer(scriptInstance, codepos - 1); + prevSourcepos = game::Scr_GetPrevSourcePos(scriptInstance, codepos - 1, index); + + game::Scr_PrintSourcePos( + prevSourcepos, + game::gScrParserPub[scriptInstance].sourceBufferLookup[bufferIndex].sourceBuf, + channel, + scriptInstance, + game::gScrParserPub[scriptInstance].sourceBufferLookup[bufferIndex].buf); + return; + } + } + else + { + if (game::Scr_IsInOpcodeMemory(scriptInstance, codepos - 1)) + { + game::Com_PrintMessage(channel, game::va("@ %d\n", codepos - game::gScrVarPub[scriptInstance].programBuffer), 0); + return; + } + } + + game::Com_PrintMessage(channel, game::va("%s\n\n", codepos), 0); + } + } + + // Restored + void Scr_ShutdownAllocNode(game::scriptInstance_t inst) + { + if (game::g_allocNodeUser[inst]) + { + game::Hunk_UserDestroy(game::g_allocNodeUser[inst]); + game::g_allocNodeUser[inst] = 0; + } + } + + // Decomp Status: Completed + void CompileError(game::scriptInstance_t inst, unsigned int codePos, const char* msg, ...) + { + const char* instStr; + int col; + int lineNumber; + char text[1024]; + char line[1024]; + va_list va; + + va_start(va, msg); + vsnprintf(text, 0x400u, msg, va); + va_end(va); + + instStr = "Server"; + if (inst) + { + instStr = "Client"; + } + + if (game::gScrVarPub[inst].evaluate) + { + if (!game::gScrVarPub[inst].error_message) + { + game::gScrVarPub[inst].error_message = (char*)game::va("%s", text); + } + } + else + { + game::Scr_ShutdownAllocNode(inst); + + game::Com_PrintError(game::CON_CHANNEL_PARSERSCRIPT, "\n"); + game::Com_PrintError(game::CON_CHANNEL_PARSERSCRIPT, "******* %s script compile error *******\n", instStr); + + if (game::gScrVarPub[inst].developer && game::gScrParserPub[inst].sourceBuf) + { + game::Com_PrintError(game::CON_CHANNEL_PARSERSCRIPT, "%s: ", text); + game::Scr_PrintSourcePos( + codePos, + game::gScrParserPub[inst].sourceBuf, + game::CON_CHANNEL_PARSERSCRIPT, + inst, + game::gScrParserPub[inst].scriptfilename); + lineNumber = game::Scr_GetLineInfo(&col, game::gScrParserPub[inst].sourceBuf, codePos, line); + } + else + { + game::Com_PrintError(game::CON_CHANNEL_PARSERSCRIPT, "%s\n", text); + line[0] = 0; + lineNumber = 0; + } + game::Com_Printf(game::CON_CHANNEL_PARSERSCRIPT, "************************************\n"); + game::Com_Error(game::ERR_SCRIPT_DROP, "\x15" "%s script compile error\n%s\n%s\n(see console for details)\n", instStr, text, line); + } + } + + // Decomp Status: Completed + void CompileError2(const char* codePos, game::scriptInstance_t inst, const char* msg, ...) + { + const char* instStr; + char text[1024]; + char line[1024]; + va_list va; + + va_start(va, msg); + + assert(!game::gScrVarPub[inst].evaluate); + + assert(game::Scr_IsInOpcodeMemory(inst, codePos)); + + vsnprintf(text, 0x400u, msg, va); + va_end(va); + + instStr = "Server"; + if (inst) + { + instStr = "Client"; + } + + game::Com_PrintError(game::CON_CHANNEL_PARSERSCRIPT, "\n"); + game::Com_PrintError(game::CON_CHANNEL_PARSERSCRIPT, "******* %s script compile error *******\n", instStr); + game::Com_PrintError(game::CON_CHANNEL_PARSERSCRIPT, "%s: ", text); + game::Scr_PrintPrevCodePos(codePos, inst, game::CON_CHANNEL_PARSERSCRIPT, 0); + game::Com_Printf(game::CON_CHANNEL_PARSERSCRIPT, "************************************\n"); + game::Scr_GetTextSourcePos(line, codePos, inst); + game::Com_Error(game::ERR_SCRIPT_DROP, "\x15" "%s script compile error\n%s\n%s\n(see console for details)\n", instStr, text, line); + } + + // Decomp Status: Completed + void RuntimeErrorInternal(const char* msg, game::scriptInstance_t inst, game::con_channel_e channel, const char* codepos, int index) + { + int functionCount; + int i; + + assert(game::Scr_IsInOpcodeMemory(inst, codepos)); + + game::Com_PrintError(channel, "\n******* script runtime error *******\n%s: ", msg); + game::Scr_PrintPrevCodePos(codepos, inst, channel, index); + functionCount = game::gScrVmPub[inst].function_count; + if (functionCount) + { + for (i = game::gScrVmPub[inst].function_count - 1; + i >= 1; + --i) + { + game::Com_PrintError(channel, "called from:\n"); + game::Scr_PrintPrevCodePos(game::gScrVmPub[inst].function_frame_start[i].fs.pos, inst, game::CON_CHANNEL_DONT_FILTER, game::gScrVmPub[inst].function_frame_start[i].fs.localId == 0); + } + + game::Com_PrintError(channel, "started from:\n"); + game::Scr_PrintPrevCodePos(game::gScrVmPub[inst].function_frame_start[0].fs.pos, inst, game::CON_CHANNEL_DONT_FILTER, 1u); + } + game::Com_PrintError(channel, "************************************\n"); + } + + // Decomp Status: Completed + void RuntimeError(game::scriptInstance_t inst, const char* codePos, int index, const char* msg, const char* dialogMessage) + { + bool abort_or_terminal; + const char* errNewline; + const char* errNewline2; + + if (!game::gScrVarPub[inst].developer) + { + assert(game::Scr_IsInOpcodeMemory(inst, codePos)); + + if (!game::gScrVmPub[inst].terminal_error) + { + return; + } + } + + if (game::gScrVmPub[inst].debugCode) + { + game::Com_Printf(game::CON_CHANNEL_PARSERSCRIPT, "%s\n", msg); + + if (!game::gScrVmPub[inst].terminal_error) + { + return; + } + } + else + { + abort_or_terminal = game::gScrVmPub[inst].abort_on_error || game::gScrVmPub[inst].terminal_error; + game::RuntimeErrorInternal( + msg, + inst, + abort_or_terminal ? game::CON_CHANNEL_PARSERSCRIPT : game::CON_CHANNEL_LOGFILEONLY, + codePos, + index); + + if (!abort_or_terminal) + { + return; + } + } + + errNewline = dialogMessage; + if (dialogMessage) + { + errNewline2 = "\n"; + } + else + { + errNewline = ""; + errNewline2 = ""; + } + + game::Com_Error( + game::gScrVmPub[inst].terminal_error ? game::ERR_FATAL : game::ERR_SCRIPT, + "\x15" "script runtime error\n(see console for details)\n%s%s%s", + msg, + errNewline2, + errNewline); + } +} \ No newline at end of file diff --git a/src/codsrc/clientscript/cscr_parser.hpp b/src/codsrc/clientscript/cscr_parser.hpp new file mode 100644 index 0000000..384bd9b --- /dev/null +++ b/src/codsrc/clientscript/cscr_parser.hpp @@ -0,0 +1,31 @@ +#pragma once + +namespace codsrc +{ + void Scr_InitOpcodeLookup(game::scriptInstance_t a1); + void Scr_ShutdownOpcodeLookup(game::scriptInstance_t a1); + void AddOpcodePos(game::scriptInstance_t a1, unsigned int sourcePos, int type); + void RemoveOpcodePos(game::scriptInstance_t result); + void AddThreadStartOpcodePos(game::scriptInstance_t result, unsigned int sourcePos); + unsigned int Scr_GetSourceBuffer(game::scriptInstance_t a1, const char* codePos); + unsigned int Scr_GetLineNumInternal(const char** startLine, const char* buf, const char* sourcePos, int* col); + game::SourceBufferInfo* Scr_GetNewSourceBuffer(game::scriptInstance_t a1); + void Scr_AddSourceBufferInternal(const char* filename, game::scriptInstance_t inst, const char* codepos, char* buffer, int len, int archive); + char* Scr_ReadFile_FastFile(game::scriptInstance_t inst, int unused, char* filename, const char* codepos, int archive); + char* Scr_ReadFile_LoadObj(game::scriptInstance_t inst, int unused_arg1, const char* filename, const char* codepos, int archive); + char* Scr_ReadFile(const char* codepos, char* filename, game::scriptInstance_t inst, int unused); + char* Scr_AddSourceBuffer(game::scriptInstance_t inst, int unused_arg1, char* filename, const char* codepos); + void Scr_CopyFormattedLine(const char* rawLine, char* line); + unsigned int Scr_GetLineInfo(int* col, const char* buf, unsigned int sourcePos, char* line); + void Scr_PrintSourcePos(unsigned int sourcePos, const char* buf, game::con_channel_e channel, game::scriptInstance_t a4, const char* file); + game::OpcodeLookup * Scr_GetPrevSourcePosOpcodeLookup(game::scriptInstance_t a1, const char* codePos); + void Scr_GetTextSourcePos(char* line, const char* codePos, game::scriptInstance_t a3); + void Scr_PrintPrevCodePos(const char* codepos, game::scriptInstance_t scriptInstance, game::con_channel_e channel, unsigned int index); + void CompileError(game::scriptInstance_t a1, unsigned int codePos, const char* msg, ...); + void CompileError2(const char* codePos, game::scriptInstance_t a2, const char* msg, ...); + void RuntimeErrorInternal(const char* msg, game::scriptInstance_t inst, game::con_channel_e channel, const char* codepos, int index); + void RuntimeError(game::scriptInstance_t inst, const char* pos, int error_index, const char* err, const char* err2); + + unsigned int Scr_GetPrevSourcePos(game::scriptInstance_t inst, const char* codePos, unsigned int index); + void Scr_ShutdownAllocNode(game::scriptInstance_t inst); +} diff --git a/src/codsrc/clientscript/cscr_parsetree.cpp b/src/codsrc/clientscript/cscr_parsetree.cpp new file mode 100644 index 0000000..82d2e71 --- /dev/null +++ b/src/codsrc/clientscript/cscr_parsetree.cpp @@ -0,0 +1,191 @@ +#include +#include "clientscript_public.hpp" + +namespace codsrc +{ + // Decomp Status: Tested, Completed + void Scr_InitAllocNode(game::scriptInstance_t inst) + { + game::HunkUser* nodeUser; + + assert(!game::g_allocNodeUser[inst]); + + nodeUser = game::Hunk_UserCreate(0x10000, "Scr_InitAllocNode", false, true, false, 7); + game::g_allocNodeUser[inst] = nodeUser; + } + + // Restored function + game::sval_u* Scr_AllocNode(game::scriptInstance_t inst, int size) + { + assert(game::g_allocNodeUser[inst]); + + return (game::sval_u*)game::Hunk_UserAlloc(game::g_allocNodeUser[inst], 4 * size, 4); + } + + // Decomp Status: Tested, Completed + game::sval_u node0() + { + game::sval_u result; + + result.node = game::Scr_AllocNode(*game::gInst, 1); + result.node[0].intValue = game::ENUM_NOP; + return result; + } + + // Decomp Status: Tested, Completed + game::sval_u node1(game::scr_enum_t type, game::sval_u val1) + { + game::sval_u result; + + result.node = game::Scr_AllocNode(*game::gInst, 2); + result.node[0].intValue = type; + result.node[1].node = val1.node; + return result; + } + + // Decomp Status: Tested, Completed + game::sval_u node2(game::scr_enum_t type, game::sval_u val1, game::sval_u val2) + { + game::sval_u result; + + result.node = game::Scr_AllocNode(*game::gInst, 3); + result.node[0].intValue = type; + result.node[1].node = val1.node; + result.node[2].node = val2.node; + return result; + } + + // Decomp Status: Tested, Completed + game::sval_u node3(game::scr_enum_t type, game::sval_u val1, game::sval_u val2, game::sval_u val3) + { + game::sval_u result; + + result.node = game::Scr_AllocNode(*game::gInst,4); + result.node[0].intValue = type; + result.node[1].node = val1.node; + result.node[2].node = val2.node; + result.node[3].node = val3.node; + return result; + } + + // Decomp Status: Tested, Completed + game::sval_u node4(game::scr_enum_t type, game::sval_u val1, game::sval_u val2, game::sval_u val3, game::sval_u val4) + { + game::sval_u result; + + result.node = game::Scr_AllocNode(*game::gInst, 5); + result.node[0].intValue = type; + result.node[1].node = val1.node; + result.node[2].node = val2.node; + result.node[3].node = val3.node; + result.node[4].node = val4.node; + return result; + } + + // Decomp Status: Tested, Completed + game::sval_u node5(game::scr_enum_t type, game::sval_u val1, game::sval_u val2, game::sval_u val3, game::sval_u val4, game::sval_u val5) + { + game::sval_u result; + + result.node = game::Scr_AllocNode(*game::gInst, 6); + result.node[0].intValue = type; + result.node[1].node = val1.node; + result.node[2].node = val2.node; + result.node[3].node = val3.node; + result.node[4].node = val4.node; + result.node[5].node = val5.node; + return result; + } + + // Decomp Status: Tested, Completed + game::sval_u node6(game::sval_u val1, game::sval_u val2, game::sval_u val3, game::sval_u val4, game::sval_u val5, game::sval_u val6) + { + game::sval_u result; + + result.node = game::Scr_AllocNode(*game::gInst, 7); + result.node[0].intValue = game::ENUM_thread; + result.node[1].node = val1.node; + result.node[2].node = val2.node; + result.node[3].node = val3.node; + result.node[4].node = val4.node; + result.node[5].node = val5.node; + result.node[6].node = val6.node; + return result; + } + + // Decomp Status: Tested, Completed + game::sval_u node7(game::sval_u val1, game::sval_u val2, game::sval_u val3, game::sval_u val4, game::sval_u val5, game::sval_u val6, game::sval_u val7) + { + game::sval_u result; + + result.node = game::Scr_AllocNode(*game::gInst, 8); + result.node[0].intValue = game::ENUM_if_else; + result.node[1].node = val1.node; + result.node[2].node = val2.node; + result.node[3].node = val3.node; + result.node[4].node = val4.node; + result.node[5].node = val5.node; + result.node[6].node = val6.node; + result.node[7].node = val7.node; + return result; + } + + // Decomp Status: Tested, Completed + game::sval_u node8(game::sval_u val1, game::sval_u val2, game::sval_u val3, game::sval_u val4, game::sval_u val5, game::sval_u val6, game::sval_u val7, game::sval_u val8) + { + game::sval_u result; + + result.node = game::Scr_AllocNode(*game::gInst, 9); + result.node[0].intValue = game::ENUM_for; + result.node[1].node = val1.node; + result.node[2].node = val2.node; + result.node[3].node = val3.node; + result.node[4].node = val4.node; + result.node[5].node = val5.node; + result.node[6].node = val6.node; + result.node[7].node = val7.node; + result.node[8].node = val8.node; + return result; + } + + // Decomp Status: Tested, Completed + game::sval_u linked_list_end(game::sval_u val1) + { + game::sval_u* node; + game::sval_u result; + + node = game::Scr_AllocNode(*game::gInst, 2); + node[0].node = val1.node; + node[1].stringValue = 0; + result.node = game::Scr_AllocNode(*game::gInst, 2); + result.node[0].node = node; + result.node[1].node = node; + return result; + } + + // Decomp Status: Tested, Completed + game::sval_u prepend_node(game::sval_u val1, game::sval_u val2) + { + game::sval_u* node; + + node = game::Scr_AllocNode(*game::gInst, 2); + node[0] = val1; + node[1] = *val2.node; + val2.node->node = node; + return val2; + } + + // Decomp Status: Tested, Completed + game::sval_u append_node(game::sval_u val1, game::sval_u val2) + { + game::sval_u* node; + + node = game::Scr_AllocNode(*game::gInst, 2); + node[0] = val2; + node[1].stringValue = 0; + val1.node[1].node[1].stringValue = (unsigned int)node; + val1.node[1].node = node; + return val1; + } + +} diff --git a/src/codsrc/clientscript/cscr_parsetree.hpp b/src/codsrc/clientscript/cscr_parsetree.hpp new file mode 100644 index 0000000..22c3aca --- /dev/null +++ b/src/codsrc/clientscript/cscr_parsetree.hpp @@ -0,0 +1,19 @@ +#pragma once + +namespace codsrc +{ + void Scr_InitAllocNode(game::scriptInstance_t inst); + game::sval_u* Scr_AllocNode(game::scriptInstance_t inst, int size); + game::sval_u node0(); + game::sval_u node1(game::scr_enum_t type, game::sval_u val1); + game::sval_u node2(game::scr_enum_t type, game::sval_u val1, game::sval_u val2); + game::sval_u node3(game::scr_enum_t type, game::sval_u val1, game::sval_u val2, game::sval_u val3); + game::sval_u node4(game::scr_enum_t type, game::sval_u val1, game::sval_u val2, game::sval_u val3, game::sval_u val4); + game::sval_u node5(game::scr_enum_t type, game::sval_u val1, game::sval_u val2, game::sval_u val3, game::sval_u val4, game::sval_u val5); + game::sval_u node6(game::sval_u val1, game::sval_u val2, game::sval_u val3, game::sval_u val4, game::sval_u val5, game::sval_u val6); + game::sval_u node7(game::sval_u val1, game::sval_u val2, game::sval_u val3, game::sval_u val4, game::sval_u val5, game::sval_u val6, game::sval_u val7); + game::sval_u node8(game::sval_u val1, game::sval_u val2, game::sval_u val3, game::sval_u val4, game::sval_u val5, game::sval_u val6, game::sval_u val7, game::sval_u val8); + game::sval_u linked_list_end(game::sval_u val1); + game::sval_u prepend_node(game::sval_u val1, game::sval_u val2); + game::sval_u append_node(game::sval_u val1, game::sval_u val2); +} diff --git a/src/codsrc/clientscript/cscr_readwrite.cpp b/src/codsrc/clientscript/cscr_readwrite.cpp new file mode 100644 index 0000000..f302517 --- /dev/null +++ b/src/codsrc/clientscript/cscr_readwrite.cpp @@ -0,0 +1,117 @@ +#include +#include "clientscript_public.hpp" + +namespace codsrc +{ + // Restored + unsigned int FindVariableIndexInternal(game::scriptInstance_t inst, unsigned int parentId, unsigned int name) + { + 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)); + + return game::FindVariableIndexInternal2(inst, name, (parentId + name) % 0xFFFD + 1); + } + + // Decomp Status: Tested, Completed + unsigned int FindVariableIndexInternal2(game::scriptInstance_t inst, unsigned int name, unsigned int index) + { + unsigned int newIndex; + game::VariableValueInternal* newEntryValue; + game::VariableValueInternal* entryValue; + game::Variable* entry; + + entry = &game::gScrVarGlob[inst].childVariables[index].hash; + + entryValue = &game::gScrVarGlob[inst].childVariables[entry->id]; + + assert((name & VAR_NAME_LOW_MASK) == 0); + + assert(index < VARIABLELIST_CHILD_SIZE); + + assert(entry->id < VARIABLELIST_CHILD_SIZE); + + if ((entryValue->w.status & VAR_STAT_MASK) != VAR_STAT_HEAD) + { + return 0; + } + + assert((entryValue->w.status & VAR_STAT_MASK) != VAR_STAT_FREE); + + assert(!IsObject(entryValue)); + + if (entryValue->w.status >> VAR_NAME_BIT_SHIFT == name) + { + return index; + } + + newIndex = entryValue->v.next; + + for (entryValue = &game::gScrVarGlob[inst].childVariables[newIndex]; + entryValue != &game::gScrVarGlob[inst].childVariables[index]; + entryValue = &game::gScrVarGlob[inst].childVariables[newIndex]) + { + newEntryValue = &game::gScrVarGlob[inst].childVariables[entryValue->hash.id]; + + assert((newEntryValue->w.status & VAR_STAT_MASK) == VAR_STAT_MOVABLE); + + assert((newEntryValue->w.status & VAR_STAT_MASK) != VAR_STAT_FREE); + + assert(!IsObject(newEntryValue)); + + if (newEntryValue->w.status >> VAR_NAME_BIT_SHIFT == name) + { + return newIndex; + } + + newIndex = newEntryValue->v.next; + } + + return 0; + } + + // Decomp Status: Tested, Completed + unsigned int FindLastSibling(unsigned int parentId, game::scriptInstance_t inst) + { + game::VariableValueInternal* parentValue; + unsigned int nextParentVarIndex; + unsigned int id; + unsigned int childVarName; + unsigned int index; + + 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.status & VAR_STAT_MASK) == VAR_STAT_EXTERNAL)); + + nextParentVarIndex = parentValue->v.next + 1; + + id = game::gScrVarGlob[inst].parentVariables[nextParentVarIndex].hash.u.prev; + + if (!id) + { + return 0; + } + + childVarName = game::gScrVarGlob[inst].childVariables[id].w.status >> VAR_NAME_BIT_SHIFT; + + index = game::FindVariableIndexInternal(inst, parentId, childVarName); + + assert(index); + + return index; + } +} \ No newline at end of file diff --git a/src/codsrc/clientscript/cscr_readwrite.hpp b/src/codsrc/clientscript/cscr_readwrite.hpp new file mode 100644 index 0000000..df1ea51 --- /dev/null +++ b/src/codsrc/clientscript/cscr_readwrite.hpp @@ -0,0 +1,8 @@ +#pragma once + +namespace codsrc +{ + unsigned int FindVariableIndexInternal2(game::scriptInstance_t inst, unsigned int name, unsigned int index); + unsigned int FindLastSibling(unsigned int parentId, game::scriptInstance_t inst); + unsigned int FindVariableIndexInternal(game::scriptInstance_t inst, unsigned int parentId, unsigned int name); +} diff --git a/src/codsrc/clientscript/cscr_stringlist.cpp b/src/codsrc/clientscript/cscr_stringlist.cpp new file mode 100644 index 0000000..9c5bb5c --- /dev/null +++ b/src/codsrc/clientscript/cscr_stringlist.cpp @@ -0,0 +1,821 @@ +#include +#include "clientscript_public.hpp" + +namespace codsrc +{ + // Restored + game::RefString* GetRefString(game::scriptInstance_t inst, unsigned int id) + { + assert(id); + + assert((id * MT_NODE_SIZE) < MT_SIZE); + + return (game::RefString*)&game::gScrMemTreePub[inst].mt_buffer->nodes[id]; + } + + // Restored + game::RefString * GetRefString_0([[maybe_unused]] game::scriptInstance_t inst, const char *str) + { + assert(str >= (char*)game::gScrMemTreePub[inst].mt_buffer && str < (char*)(game::gScrMemTreePub[inst].mt_buffer + MT_SIZE)); + + return (game::RefString *)(str - 4); + } + + // Restored + int SL_ConvertFromRefString(game::scriptInstance_t inst, game::RefString *refString) + { + return ((char *)refString - (char *)game::gScrMemTreePub[inst].mt_buffer) / MT_NODE_SIZE; + } + + // Restored + int SL_ConvertFromString(game::scriptInstance_t inst, const char *str) + { + game::RefString *v2; + + assert(str); + + v2 = game::GetRefString_0(inst, str); + return game::SL_ConvertFromRefString(inst, v2); + } + + // Restored + const char* SL_ConvertToStringSafe(unsigned int id, game::scriptInstance_t inst) + { + if (!id) + { + return "(NULL)"; + } + + return game::GetRefString(inst, id)->str; + } + + // Decomp Status: Completed + char* SL_ConvertToString(unsigned int id, game::scriptInstance_t inst) + { + //assert((!id || !game::gScrStringDebugGlob[inst] || game::gScrStringDebugGlob[inst]->refCount[id])); + + if (!id) + { + return nullptr; + } + + return game::GetRefString(inst, id)->str; + } + + // Restored + int SL_GetRefStringLen(game::RefString* refString) + { + int len; + + for ( len = refString->u.s.byteLen - 1; + refString->str[len]; + len += 256 ) + { + ; + } + + return len; + } + + // Decomp Status: Completed + int SL_GetStringLen(unsigned int stringValue, game::scriptInstance_t inst) + { + game::RefString *refString; + + assert(stringValue); + + refString = game::GetRefString(inst, stringValue); + + return game::SL_GetRefStringLen(refString); + } + + // Decomp Status: Completed + unsigned int GetHashCode(unsigned int len, const char* str) + { + unsigned int i; + + if (len >= 0x100) + { + return (len >> 2) % 0x61A7 + 1; + } + for (i = 0; len; --len) + { + i = 31 * i + *str++; + } + return i % 0x61A7 + 1; + } + + // Decomp Status: Completed + void SL_Init(game::scriptInstance_t inst) + { + unsigned int hash; + game::HashEntry *entry; + unsigned int prev; + + assert(!game::gScrStringGlob[inst].inited); + + game::MT_Init(inst); + game::Sys_EnterCriticalSection(game::CRITSECT_SCRIPT_STRING); + + game::gScrStringGlob[inst].hashTable[0].status_next = 0; + + prev = 0; + for (hash = 1; + hash < HASH_MAX_HASHES; + ++hash) + { + assert(!(hash & HASH_STAT_MASK)); + + entry = &game::gScrStringGlob[inst].hashTable[hash]; + entry->status_next = 0; + game::gScrStringGlob[inst].hashTable[prev].status_next |= hash; + entry->u.prev = prev; + prev = hash; + } + + assert(!(game::gScrStringGlob[inst].hashTable[prev].status_next)); + + game::gScrStringGlob[inst].hashTable[0].u.prev = prev; + game::gScrStringGlob[inst].inited = 1; + game::Sys_LeaveCriticalSection(game::CRITSECT_SCRIPT_STRING); + } + + // Decomp Status: Completed + unsigned int SL_FindStringOfSize(game::scriptInstance_t inst, const char* str, unsigned int len) + { + unsigned int stringValue; + game::HashEntry *entry; + int hash; + unsigned int newIndex; + game::RefString *refStr; + game::RefString *refStra; + unsigned int prev; + game::HashEntry *newEntry; + + assert(str); + + hash = game::GetHashCode(len, str); + game::Sys_EnterCriticalSection(game::CRITSECT_SCRIPT_STRING); + entry = &game::gScrStringGlob[inst].hashTable[hash]; + + if ( (entry->status_next & HASH_STAT_MASK) != HASH_STAT_HEAD ) + { + game::Sys_LeaveCriticalSection(game::CRITSECT_SCRIPT_STRING); + return 0; + } + + refStr = game::GetRefString(inst, entry->u.prev); + if ( (unsigned char)refStr->u.s.byteLen != (unsigned char)len || memcmp(refStr->str, str, len) ) + { + prev = hash; + newIndex = (unsigned short)entry->status_next; + + for ( newEntry = &game::gScrStringGlob[inst].hashTable[newIndex]; + newEntry != entry; + newEntry = &game::gScrStringGlob[inst].hashTable[newIndex] ) + { + assert((newEntry->status_next & HASH_STAT_MASK) == HASH_STAT_MOVABLE); + + refStra = game::GetRefString(inst, newEntry->u.prev); + + if ( (unsigned char)refStra->u.s.byteLen == (unsigned char)len && !memcmp(refStra->str, str, len) ) + { + game::gScrStringGlob[inst].hashTable[prev].status_next = (unsigned short)newEntry->status_next | game::gScrStringGlob[inst].hashTable[prev].status_next & HASH_STAT_MASK; + newEntry->status_next = (unsigned short)entry->status_next | newEntry->status_next & HASH_STAT_MASK; + entry->status_next = newIndex | entry->status_next & HASH_STAT_MASK; + stringValue = newEntry->u.prev; + newEntry->u.prev = entry->u.prev; + entry->u.prev = stringValue; + + assert((newEntry->status_next & HASH_STAT_MASK) != HASH_STAT_FREE); + + assert((entry->status_next & HASH_STAT_MASK) != HASH_STAT_FREE); + + assert(refStra->str == game::SL_ConvertToString(stringValue, inst)); + + game::Sys_LeaveCriticalSection(game::CRITSECT_SCRIPT_STRING); + return stringValue; + } + + prev = newIndex; + newIndex = (unsigned short)newEntry->status_next; + } + + game::Sys_LeaveCriticalSection(game::CRITSECT_SCRIPT_STRING); + return 0; + } + + assert((entry->status_next & HASH_STAT_MASK) != HASH_STAT_FREE); + + stringValue = entry->u.prev; + + assert(refStr->str == game::SL_ConvertToString(stringValue, inst)); + + game::Sys_LeaveCriticalSection(game::CRITSECT_SCRIPT_STRING); + return stringValue; + } + + // Decomp Status: Completed + unsigned int SL_FindString(const char* str, game::scriptInstance_t inst) + { + return game::SL_FindStringOfSize(inst, str, strlen(str) + 1); + } + + // Decomp Status: Completed + unsigned int SL_FindLowercaseString(const char* str, game::scriptInstance_t inst) + { + char stra[8196]; + unsigned int len; + int i; + + len = strlen(str) + 1; + + if ( (int)len > 0x2000 ) + return 0; + + for ( i = 0; + i < (int)len; + ++i ) + { + stra[i] = (char)tolower(str[i]); + } + + return game::SL_FindStringOfSize(inst, stra, len); + } + + // Decomp Status: Completed + void SL_AddUserInternal(unsigned int user, game::RefString* refStr) + { + unsigned __int32 data; + + if ( ((unsigned __int8)user & (unsigned __int8)refStr->u.s.user) == 0 ) + { + do + data = refStr->u.data; + while ( InterlockedCompareExchange((volatile unsigned int*)&refStr->u.data, data | (user << 16), data) != data); + + InterlockedExchangeAdd((volatile unsigned int*)&refStr->u.data, 1u); + } + } + + // Restored + void SL_AddUser(unsigned int stringValue, unsigned int user, game::scriptInstance_t inst) + { + game::RefString *refStr; + + refStr = game::GetRefString(inst, stringValue); + game::SL_AddUserInternal(user, refStr); + } + + // Decomp Status: Untested unknown how to test, completed + void Mark_ScriptStringCustom(unsigned int var) + { + game::SL_AddUser(var, 4u, game::SCRIPTINSTANCE_SERVER); + } + + // Decomp Status: Completed + unsigned int SL_GetStringOfSize(game::scriptInstance_t inst, const char* str, unsigned int user, unsigned int len) + { + unsigned int stringValue; + game::HashEntry* entry; + unsigned int newNext; + unsigned int newNexta; + int hash; + unsigned int newIndex; + unsigned int newIndexa; + unsigned int newIndexb; + game::RefString *refStr; + game::RefString *refStra; + game::RefString *refStrb; + unsigned int nexta; + unsigned int next; + unsigned int prev; + unsigned int prevb; + unsigned int preva; + game::HashEntry *newEntry; + game::HashEntry *newEntrya; + game::HashEntry *newEntryb; + + assert(str); + + hash = game::GetHashCode(len, str); + game::Sys_EnterCriticalSection(game::CRITSECT_SCRIPT_STRING); + entry = &game::gScrStringGlob[inst].hashTable[hash]; + + if ( (entry->status_next & HASH_STAT_MASK) == HASH_STAT_HEAD ) + { + refStr = game::GetRefString(inst, entry->u.prev); + + if ( (unsigned char)refStr->u.s.byteLen == (unsigned char)len && !memcmp(refStr->str, str, len) ) + { + game::SL_AddUserInternal(user, refStr); + + assert((entry->status_next & HASH_STAT_MASK) != HASH_STAT_FREE); + + stringValue = entry->u.prev; + + assert(refStr->str == game::SL_ConvertToString(stringValue, inst)); + + game::Sys_LeaveCriticalSection(game::CRITSECT_SCRIPT_STRING); + return stringValue; + } + + prev = hash; + newIndex = (unsigned short)entry->status_next; + for ( newEntry = &game::gScrStringGlob[inst].hashTable[newIndex]; + newEntry != entry; + newEntry = &game::gScrStringGlob[inst].hashTable[newIndex] ) + { + assert((newEntry->status_next & HASH_STAT_MASK) == HASH_STAT_MOVABLE); + + refStra = game::GetRefString(inst, newEntry->u.prev); + + if ( (unsigned char)refStra->u.s.byteLen == (unsigned char)len && !memcmp(refStra->str, str, len) ) + { + game::gScrStringGlob[inst].hashTable[prev].status_next = (unsigned short)newEntry->status_next | game::gScrStringGlob[inst].hashTable[prev].status_next & HASH_STAT_MASK; + newEntry->status_next = (unsigned short)entry->status_next | newEntry->status_next & HASH_STAT_MASK; + entry->status_next = newIndex | entry->status_next & HASH_STAT_MASK; + stringValue = newEntry->u.prev; + newEntry->u.prev = entry->u.prev; + entry->u.prev = stringValue; + game::SL_AddUserInternal(user, refStra); + + assert((newEntry->status_next & HASH_STAT_MASK) != HASH_STAT_FREE); + + assert((entry->status_next & HASH_STAT_MASK) != HASH_STAT_FREE); + + assert(refStra->str == game::SL_ConvertToString(stringValue, inst)); + + game::Sys_LeaveCriticalSection(game::CRITSECT_SCRIPT_STRING); + return stringValue; + } + + prev = newIndex; + newIndex = (unsigned short)newEntry->status_next; + } + + newIndexa = game::gScrStringGlob[inst].hashTable->status_next; + if ( !newIndexa ) + { + game::Scr_DumpScriptThreads(inst); + game::Com_Error(game::ERR_DROP, "\x15" "exceeded maximum number of script strings\n"); + } + + stringValue = game::MT_AllocIndex(inst, len + 4); + newEntrya = &game::gScrStringGlob[inst].hashTable[newIndexa]; + + assert((newEntrya->status_next & HASH_STAT_MASK) == HASH_STAT_FREE); + + newNext = (unsigned short)newEntrya->status_next; + game::gScrStringGlob[inst].hashTable->status_next = newNext; + game::gScrStringGlob[inst].hashTable[newNext].u.prev = 0; + newEntrya->status_next = (unsigned short)entry->status_next | HASH_STAT_MOVABLE; + entry->status_next = (unsigned short)newIndexa | entry->status_next & HASH_STAT_MASK; + newEntrya->u.prev = entry->u.prev; + } + else + { + if ( (entry->status_next & HASH_STAT_MASK) != HASH_STAT_FREE ) + { + assert((entry->status_next & HASH_STAT_MASK) == HASH_STAT_MOVABLE); + + next = (unsigned short)entry->status_next; + for ( preva = next; + (unsigned short)game::gScrStringGlob[inst].hashTable[preva].status_next != hash; + preva = (unsigned short)game::gScrStringGlob[inst].hashTable[preva].status_next ) + { + ; + } + + assert(preva); + + newIndexb = game::gScrStringGlob[inst].hashTable->status_next; + if ( !newIndexb ) + { + game::Scr_DumpScriptThreads(inst); + game::Com_Error(game::ERR_DROP, "\x15" "exceeded maximum number of script strings\n"); + } + + stringValue = game::MT_AllocIndex(inst, len + 4); + newEntryb = &game::gScrStringGlob[inst].hashTable[newIndexb]; + + assert((newEntryb->status_next & HASH_STAT_MASK) == HASH_STAT_FREE); + + newNexta = (unsigned short)newEntryb->status_next; + game::gScrStringGlob[inst].hashTable->status_next = newNexta; + game::gScrStringGlob[inst].hashTable[newNexta].u.prev = 0; + game::gScrStringGlob[inst].hashTable[preva].status_next = newIndexb | game::gScrStringGlob[inst].hashTable[preva].status_next & HASH_STAT_MASK; + newEntryb->status_next = next | HASH_STAT_MOVABLE; + newEntryb->u.prev = entry->u.prev; + } + else + { + stringValue = game::MT_AllocIndex(inst, len + 4); + prevb = entry->u.prev; + nexta = (unsigned short)entry->status_next; + game::gScrStringGlob[inst].hashTable[prevb].status_next = nexta | game::gScrStringGlob[inst].hashTable[prevb].status_next & HASH_STAT_MASK; + game::gScrStringGlob[inst].hashTable[nexta].u.prev = prevb; + } + + assert((hash & HASH_STAT_MASK) == 0); + + entry->status_next = hash | HASH_STAT_HEAD; + } + + assert(stringValue); + + entry->u.prev = stringValue; + + refStrb = game::GetRefString(inst, stringValue); + memcpy(refStrb->str, str, len); + + refStrb->u.s.user = user; + assert(refStrb->u.s.user == user); + refStrb->u.s.refCount = 1; + refStrb->u.s.byteLen = len; + + assert((entry->status_next & HASH_STAT_MASK) != HASH_STAT_FREE); + assert(refStrb->str == game::SL_ConvertToString(stringValue, inst)); + + game::Sys_LeaveCriticalSection(game::CRITSECT_SCRIPT_STRING); + return stringValue; + } + + // Decomp Status: Untested unknown how to test, Completed + unsigned int SL_GetString_(const char* str, game::scriptInstance_t inst, unsigned int user) + { + return game::SL_GetStringOfSize(inst, str, user, strlen(str) + 1); + } + + // Decomp Status: Completed + unsigned int SL_GetString__0(const char* str, unsigned int user, game::scriptInstance_t inst) + { + return game::SL_GetStringOfSize(inst, str, user, strlen(str) + 1); + } + + // Decomp Status: Completed + unsigned int SL_GetLowercaseStringOfLen(game::scriptInstance_t inst, const char* str, unsigned int user, unsigned int len) + { + char stra[SL_MAX_STRING_LEN]; + unsigned int i; + + if (len > SL_MAX_STRING_LEN) + { + game::Com_Error(game::ERR_DROP, "max string length exceeded: \"%s\"", str); + } + + for ( i = 0; + i < len; + ++i ) + { + stra[i] = (char)tolower(str[i]); + } + + return game::SL_GetStringOfSize(inst, stra, user, len); + } + + // Decomp Status: Completed + unsigned int SL_GetLowercaseString(const char* str) + { + return game::SL_GetLowercaseStringOfLen(game::SCRIPTINSTANCE_SERVER, str, 0, strlen(str) + 1); + } + + // Decomp Status: Completed + unsigned int SL_ConvertToLowercase(game::scriptInstance_t inst, unsigned int stringVal, unsigned int user) + { + char *strCopy; + char str[SL_MAX_STRING_LEN]; + unsigned int answer; + unsigned int len; + unsigned int i; + + len = game::SL_GetStringLen(stringVal, inst) + 1; + if ( len > SL_MAX_STRING_LEN) + { + return stringVal; + } + + strCopy = game::SL_ConvertToString(stringVal, inst); + + for ( i = 0; + i < len; + ++i ) + { + str[i] = (char)tolower(strCopy[i]); + } + + answer = game::SL_GetStringOfSize(inst, str, user, len); + game::SL_RemoveRefToString(stringVal, inst); + return answer; + } + + // Decomp Status: Completed + void SL_TransferRefToUser(unsigned int stringValue, unsigned int user, game::scriptInstance_t inst) + { + unsigned int data; + game::RefString *refStr; + + refStr = game::GetRefString(inst, stringValue); + if ( ((unsigned char)user & (unsigned char)refStr->u.s.user) != 0 ) + { + InterlockedExchangeAdd((volatile unsigned int*)&refStr->u.data, 0xFFFFFFFF); + } + else + { + do + data = refStr->u.data; + while ( InterlockedCompareExchange((volatile unsigned int*)&refStr->u.data, data | (user << 16), data) != data ); + } + } + + // Decomp Status: Completed + void SL_FreeString(game::scriptInstance_t inst, unsigned int stringValue, game::RefString* refStr, unsigned int len) + { + game::HashEntry *entry; + unsigned int newIndex; + unsigned int newNext; + int index; + unsigned int prev; + game::HashEntry *newEntry; + + index = game::GetHashCode(len, refStr->str); + game::Sys_EnterCriticalSection(game::CRITSECT_SCRIPT_STRING); + + if ( !(unsigned short)refStr->u.s.refCount ) + { + entry = &game::gScrStringGlob[inst].hashTable[index]; + game::MT_FreeIndex(len + 4, inst, stringValue); + + assert(((entry->status_next & HASH_STAT_MASK) == HASH_STAT_HEAD)); + + newIndex = (unsigned short)entry->status_next; + newEntry = &game::gScrStringGlob[inst].hashTable[newIndex]; + if ( entry->u.prev == stringValue ) + { + if ( newEntry == entry ) + { + newEntry = entry; + newIndex = index; + } + else + { + entry->status_next = (unsigned short)newEntry->status_next | HASH_STAT_HEAD; + entry->u.prev = newEntry->u.prev; + game::gScrStringGlob[inst].nextFreeEntry = entry; + } + } + else + { + prev = index; + while ( 1 ) + { + assert(newEntry != entry); + + assert((newEntry->status_next & HASH_STAT_MASK) == HASH_STAT_MOVABLE); + + if ( newEntry->u.prev == stringValue ) + { + break; + } + + prev = newIndex; + newIndex = (unsigned short)newEntry->status_next; + newEntry = &game::gScrStringGlob[inst].hashTable[newIndex]; + } + + game::gScrStringGlob[inst].hashTable[prev].status_next = (unsigned short)newEntry->status_next | game::gScrStringGlob[inst].hashTable[prev].status_next & HASH_STAT_MASK; + } + + assert((newEntry->status_next & HASH_STAT_MASK) != HASH_STAT_FREE); + + newNext = game::gScrStringGlob[inst].hashTable->status_next; + + assert((newNext & HASH_STAT_MASK) == HASH_STAT_FREE); + + newEntry->status_next = newNext; + newEntry->u.prev = 0; + game::gScrStringGlob[inst].hashTable[newNext].u.prev = newIndex; + game::gScrStringGlob[inst].hashTable->status_next = newIndex; + } + + game::Sys_LeaveCriticalSection(game::CRITSECT_SCRIPT_STRING); + } + + // Restored + void SL_RemoveRefToStringOfSize(game::scriptInstance_t inst, unsigned int stringValue, unsigned int len) + { + game::RefString *refStr; + + refStr = game::GetRefString(inst, stringValue); + if ( !(unsigned __int16)InterlockedDecrement((volatile unsigned int*)&refStr->u.data)) + { + game::SL_FreeString(inst, stringValue, refStr, len); + } + } + + // Decomp Status: Tested, Completed + void SL_RemoveRefToString(unsigned int stringVal, game::scriptInstance_t inst) + { + game::RefString *refStr; + int len; + + refStr = game::GetRefString(inst, stringVal); + len = game::SL_GetRefStringLen(refStr) + 1; + game::SL_RemoveRefToStringOfSize(inst, stringVal, len); + } + + // Restored + void SL_AddRefToString(game::scriptInstance_t inst, unsigned int stringValue) + { + game::RefString* refStr = game::GetRefString(inst, stringValue); + InterlockedExchangeAdd((volatile unsigned int*)&refStr->u.data, 1u); + } + + // Decomp Status: Tested, Completed + void Scr_SetString(game::scriptInstance_t inst, unsigned int from, unsigned __int16* to) + { + if (from) + { + game::SL_AddRefToString(inst, from); + } + + if (*to) + { + game::SL_RemoveRefToString(*to, inst); + } + + *to = (unsigned short)from; + } + + // Decomp Status: Tested, Completed + void Scr_SetStringFromCharString(const char* from, unsigned __int16* to) + { + if (*to) + { + game::SL_RemoveRefToString(*to, game::SCRIPTINSTANCE_SERVER); + } + + *to = (unsigned short)game::SL_GetString_(from, game::SCRIPTINSTANCE_SERVER, 0); + } + + // Decomp Status: Tested, Completed + unsigned int GScr_AllocString(const char* str, game::scriptInstance_t inst) + { + return game::SL_GetString_(str, inst, 1); + } + + // Decomp Status: Tested, Completed + unsigned int SL_GetStringForFloat(float floatVal, game::scriptInstance_t inst) + { + char Buffer[128]; + + sprintf_s(Buffer, "%g", floatVal); + return game::SL_GetString_(Buffer, inst, 0); + } + + // Decomp Status: Tested, Completed + unsigned int SL_GetStringForInt(int intVal, game::scriptInstance_t inst) + { + char Buffer[128]; + + sprintf_s(Buffer, "%i", intVal); + return game::SL_GetString_(Buffer, inst, 0); + } + + // Decomp Status: Tested, Completed + unsigned int SL_GetStringForVector(float* vector, game::scriptInstance_t inst) + { + char Buffer[128]; + + sprintf_s(Buffer, "(%g, %g, %g)", vector[0], vector[1], vector[2]); + return game::SL_GetString_(Buffer, inst, 0); + } + + // Decomp Status: Tested, Completed + void SL_ShutdownSystem(game::scriptInstance_t inst, unsigned int user) + { + unsigned int hash; + game::HashEntry *entry; + game::RefString *refStr; + + assert(user); + + game::Sys_EnterCriticalSection(game::CRITSECT_SCRIPT_STRING); + + for ( hash = 1; + hash < HASH_MAX_HASHES; + ++hash ) + { + do + { + entry = &game::gScrStringGlob[inst].hashTable[hash]; + if ( (entry->status_next & HASH_STAT_MASK) == HASH_STAT_FREE ) + { + break; + } + + refStr = game::GetRefString(inst, entry->u.prev); + if ( ((unsigned char)user & (unsigned char)refStr->u.s.user) == 0 ) + { + break; + } + + refStr->u.s.user &= ~user; + game::gScrStringGlob[inst].nextFreeEntry = 0; + game::SL_RemoveRefToString(entry->u.prev, inst); + } + while ( game::gScrStringGlob[inst].nextFreeEntry ); + } + + game::Sys_LeaveCriticalSection(game::CRITSECT_SCRIPT_STRING); + } + + // Decomp Status: Tested, Completed, Optimized args + void SL_TransferSystem() + { + unsigned int hash; + game::HashEntry *entry; + game::RefString* refStr; + + // args + int from = 4; + int to = 8; + game::scriptInstance_t inst = game::SCRIPTINSTANCE_SERVER; + + assert(from); + assert(to); + + game::Sys_EnterCriticalSection(game::CRITSECT_SCRIPT_STRING); + + for (hash = 1; hash < HASH_MAX_HASHES; hash++) + { + entry = &game::gScrStringGlob[inst].hashTable[hash]; + + if ((entry->status_next & HASH_STAT_MASK) != HASH_STAT_FREE) + { + refStr = game::GetRefString(inst, entry->u.prev); + + if ( ((unsigned __int8)from & (unsigned __int8)refStr->u.s.user) != 0 ) + { + refStr->u.s.user &= ~from; + refStr->u.s.user |= to; + } + } + } + + game::Sys_LeaveCriticalSection(game::CRITSECT_SCRIPT_STRING); + } + + // Decomp Status: Tested, Completed + void SL_CreateCanonicalFilename(const char* filename, char* newFilename) + { + int count; + unsigned int c; + + count = 1024; + do + { + do + { + do + { + c = *filename++; + } while (c == '\\'); + } while (c == '/'); + if (c >= ' ') + { + while (1) + { + *newFilename++ = (char)tolower(c); + if (!--count) + { + game::Com_Error(game::ERR_DROP, "\x15" "Filename '%s' exceeds maximum length of %d", filename, 0); + } + if (c == '/') + { + break; + } + c = *filename++; + if (c == '\\') + { + c = '/'; + } + else if (c < ' ') + { + break; + } + } + } + } while (c); + *newFilename = 0; + } + + // Decomp Status: Tested, Completed + unsigned int Scr_CreateCanonicalFilename(game::scriptInstance_t inst, const char* filename) + { + char newFileName[1024]; + + game::SL_CreateCanonicalFilename(filename, newFileName); + return game::SL_GetString_(newFileName, inst, 0); + } +} \ No newline at end of file diff --git a/src/codsrc/clientscript/cscr_stringlist.hpp b/src/codsrc/clientscript/cscr_stringlist.hpp new file mode 100644 index 0000000..426fd26 --- /dev/null +++ b/src/codsrc/clientscript/cscr_stringlist.hpp @@ -0,0 +1,42 @@ +#pragma once + +namespace codsrc +{ + char* SL_ConvertToString(unsigned int id, game::scriptInstance_t inst); + int SL_GetStringLen(unsigned int a1, game::scriptInstance_t a2); + unsigned int GetHashCode(unsigned int a1, const char* a2); + void SL_Init(game::scriptInstance_t a1); + unsigned int SL_FindStringOfSize(game::scriptInstance_t inst, const char* str, unsigned int len); + unsigned int SL_FindString(const char* a1, game::scriptInstance_t a2); + unsigned int SL_FindLowercaseString(const char* str, game::scriptInstance_t inst); + void SL_AddUserInternal(unsigned int user, game::RefString* refStr); + void Mark_ScriptStringCustom(unsigned int a1); + unsigned int SL_GetStringOfSize(game::scriptInstance_t inst, const char* string, unsigned int user, unsigned int len); + unsigned int SL_GetString_(const char* a1, game::scriptInstance_t a2, unsigned int user); + unsigned int SL_GetString__0(const char* a1, unsigned int user, game::scriptInstance_t a3); + unsigned int SL_GetLowercaseStringOfLen(game::scriptInstance_t a1, const char* ArgList, unsigned int user, unsigned int len); + unsigned int SL_GetLowercaseString(const char* a2); + unsigned int SL_ConvertToLowercase(game::scriptInstance_t inst, unsigned int stringVal, unsigned int user); + void SL_TransferRefToUser(unsigned int stringValue, unsigned int user, game::scriptInstance_t inst); + void SL_FreeString(game::scriptInstance_t inst, unsigned int stringValue, game::RefString* refStr, unsigned int len); + void SL_RemoveRefToString(unsigned int stringVal, game::scriptInstance_t inst); + void SL_AddRefToString(game::scriptInstance_t inst, unsigned int stringValue); + void Scr_SetString(game::scriptInstance_t inst, unsigned int from, unsigned __int16* to); + void Scr_SetStringFromCharString(const char* from, unsigned __int16* to); + unsigned int GScr_AllocString(const char* a1, game::scriptInstance_t inst); + unsigned int SL_GetStringForFloat(float floatVal, game::scriptInstance_t inst); + unsigned int SL_GetStringForInt(int intVal, game::scriptInstance_t inst); + unsigned int SL_GetStringForVector(float* vector, game::scriptInstance_t inst); + void SL_ShutdownSystem(game::scriptInstance_t inst, unsigned int user); + void SL_TransferSystem(); + void SL_CreateCanonicalFilename(const char* filename, char* newFilename); + unsigned int Scr_CreateCanonicalFilename(game::scriptInstance_t inst, const char* filename); + game::RefString* GetRefString(game::scriptInstance_t inst, unsigned int id); + void SL_RemoveRefToStringOfSize(game::scriptInstance_t inst, unsigned int stringValue, unsigned int len); + int SL_GetRefStringLen(game::RefString* refString); + void SL_AddUser(unsigned int stringValue, unsigned int user, game::scriptInstance_t inst); + int SL_ConvertFromString(game::scriptInstance_t inst, const char* str); + int SL_ConvertFromRefString(game::scriptInstance_t inst, game::RefString* refString); + game::RefString* GetRefString_0(game::scriptInstance_t inst, const char* str); + const char* SL_DebugConvertToString(unsigned int stringValue, game::scriptInstance_t inst); +} diff --git a/src/codsrc/clientscript/cscr_tempmemory.cpp b/src/codsrc/clientscript/cscr_tempmemory.cpp new file mode 100644 index 0000000..789ecbf --- /dev/null +++ b/src/codsrc/clientscript/cscr_tempmemory.cpp @@ -0,0 +1,23 @@ +#include +#include "clientscript_public.hpp" + +namespace codsrc +{ + // Restored + char* TempMalloc(int len) + { + return (char *)game::Hunk_UserAlloc(*game::g_user, len, 1); + } + + // Restored + void TempMemoryReset(game::HunkUser* user) + { + *game::g_user = user; + } + + // Restored + void TempMemorySetPos(char* pos) + { + (*game::g_user)->pos = (int)pos; + } +} \ No newline at end of file diff --git a/src/codsrc/clientscript/cscr_tempmemory.hpp b/src/codsrc/clientscript/cscr_tempmemory.hpp new file mode 100644 index 0000000..e221113 --- /dev/null +++ b/src/codsrc/clientscript/cscr_tempmemory.hpp @@ -0,0 +1,8 @@ +#pragma once + +namespace codsrc +{ + char* TempMalloc(int len); + void TempMemoryReset(game::HunkUser* user); + void TempMemorySetPos(char* pos); +} diff --git a/src/codsrc/clientscript/cscr_variable.cpp b/src/codsrc/clientscript/cscr_variable.cpp new file mode 100644 index 0000000..ea1ae1e --- /dev/null +++ b/src/codsrc/clientscript/cscr_variable.cpp @@ -0,0 +1,4254 @@ +#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) diff --git a/src/codsrc/clientscript/cscr_variable.hpp b/src/codsrc/clientscript/cscr_variable.hpp new file mode 100644 index 0000000..24859b9 --- /dev/null +++ b/src/codsrc/clientscript/cscr_variable.hpp @@ -0,0 +1,141 @@ +#pragma once + +namespace codsrc +{ + int ThreadInfoCompare(const void* a1, const void* a2); + void Scr_DumpScriptThreads(game::scriptInstance_t scriptInstance); + void Scr_InitVariableRange(unsigned int a1, unsigned int a2, game::scriptInstance_t inst); + void Scr_InitClassMap(game::scriptInstance_t inst); + unsigned int GetNewVariableIndexInternal3(game::scriptInstance_t inst, unsigned int parentId, unsigned int name, unsigned int index); + unsigned int GetNewVariableIndexInternal2(unsigned int name, game::scriptInstance_t inst, unsigned int parentId, unsigned int index); + unsigned int GetNewVariableIndexReverseInternal2(unsigned int name, game::scriptInstance_t inst, unsigned int parentId, unsigned int index); + void MakeVariableExternal(game::VariableValueInternal* parentValue, game::scriptInstance_t inst, unsigned int index); + void FreeChildValue(unsigned int id, game::scriptInstance_t inst, unsigned int parentId); + void ClearObjectInternal(game::scriptInstance_t inst, unsigned int parentId); + void ClearObject(unsigned int a1, game::scriptInstance_t inst); + void Scr_StopThread(game::scriptInstance_t inst, unsigned int a2); + unsigned int GetSafeParentLocalId(game::scriptInstance_t inst, unsigned int a2); + unsigned int GetStartLocalId(unsigned int result, game::scriptInstance_t inst); + void Scr_KillThread(game::scriptInstance_t inst, unsigned int parentId_1); + unsigned __int16 AllocVariable(game::scriptInstance_t inst); + void FreeVariable(unsigned int a1, game::scriptInstance_t inst); + unsigned int AllocValue(game::scriptInstance_t inst); + unsigned int AllocEntity(game::classNum_e classnum, game::scriptInstance_t inst, int entnum, int clientnum); + unsigned int Scr_AllocArray(game::scriptInstance_t a1); + unsigned int AllocChildThread(game::scriptInstance_t inst, unsigned int a2, unsigned int a3); + void FreeValue(unsigned int id, game::scriptInstance_t inst); + void RemoveRefToObject(unsigned int id, game::scriptInstance_t inst); + float* Scr_AllocVector(game::scriptInstance_t a1); + void RemoveRefToVector(const float* vectorValue, game::scriptInstance_t inst); + void AddRefToValue(game::scriptInstance_t inst, game::VariableType type, game::VariableUnion u); + void RemoveRefToValueInternal(game::scriptInstance_t inst, game::VariableType type, game::VariableUnion a3); + unsigned int FindArrayVariable(unsigned int id, unsigned int intvalue, game::scriptInstance_t inst); + unsigned int FindVariable(unsigned int name, unsigned int a2, game::scriptInstance_t inst); + unsigned int GetArrayVariableIndex(unsigned int unsignedValue, game::scriptInstance_t inst, unsigned int parentId); + unsigned int Scr_GetVariableFieldIndex(game::scriptInstance_t inst, unsigned int name, unsigned int parentId); + game::VariableValue Scr_FindVariableField(game::scriptInstance_t inst, unsigned int parentId, unsigned int name); + void ClearVariableField(game::scriptInstance_t inst, unsigned int id, unsigned int name, game::VariableValue* value); + unsigned int GetVariable(game::scriptInstance_t inst, unsigned int parentId, unsigned int name); + unsigned int GetNewVariable(game::scriptInstance_t inst, unsigned int a2, unsigned int a3); + unsigned int GetObjectVariable(unsigned int a1, game::scriptInstance_t inst, unsigned int parentId); + unsigned int GetNewObjectVariable(game::scriptInstance_t inst, unsigned int name, unsigned int parentId); + void RemoveVariable(unsigned int name, unsigned int parentId, game::scriptInstance_t inst); + void RemoveNextVariable(game::scriptInstance_t inst, unsigned int parentId); + void SafeRemoveVariable(unsigned int unsignedValue, unsigned int parentId, game::scriptInstance_t inst); + void CopyArray(game::scriptInstance_t inst, unsigned int parentId, unsigned int newParentId); + void SetVariableValue(game::scriptInstance_t inst, game::VariableValue* a2, unsigned int a3); + void SetVariableEntityFieldValue(game::scriptInstance_t inst, unsigned int parentId, unsigned int name, game::VariableValue* a4); + game::VariableValue Scr_EvalVariable(game::scriptInstance_t inst, unsigned int a2); + unsigned int Scr_EvalVariableObject(game::scriptInstance_t inst, unsigned int a2); + game::VariableValue Scr_EvalVariableEntityField(unsigned int entId, game::scriptInstance_t inst, unsigned int name); + game::VariableValue Scr_EvalVariableField(game::scriptInstance_t inst, unsigned int id); + void Scr_EvalSizeValue(game::scriptInstance_t inst, game::VariableValue* value); + unsigned int GetObject(game::scriptInstance_t inst, unsigned int a2); + unsigned int GetArray(game::scriptInstance_t inst, unsigned int a2); + void Scr_EvalBoolComplement(game::scriptInstance_t inst, game::VariableValue* a2); + void Scr_CastBool(game::scriptInstance_t inst, game::VariableValue* a2); + char Scr_CastString(game::scriptInstance_t inst, game::VariableValue* a2); + void Scr_CastDebugString(game::scriptInstance_t inst, game::VariableValue* a2); + void Scr_ClearVector(game::scriptInstance_t inst, game::VariableValue* a2); + void Scr_CastVector(game::scriptInstance_t inst, game::VariableValue* a2); + game::VariableUnion Scr_EvalFieldObject(game::VariableValue* a1, game::scriptInstance_t inst, unsigned int a3); + void Scr_UnmatchingTypesError(game::scriptInstance_t inst, game::VariableValue* a2, game::VariableValue* value); + void Scr_CastWeakerPair(game::VariableValue* a1, game::VariableValue* a2, game::scriptInstance_t inst); + void Scr_CastWeakerStringPair(game::VariableValue* a1, game::VariableValue* a2, game::scriptInstance_t inst); + void Scr_EvalOr(game::VariableValue* result, game::VariableValue* a2, game::scriptInstance_t inst); + void Scr_EvalExOr(game::VariableValue* result, game::VariableValue* a2, game::scriptInstance_t inst); + void Scr_EvalAnd(game::VariableValue* result, game::VariableValue* a2, game::scriptInstance_t inst); + void Scr_EvalEquality(game::VariableValue* a1, game::scriptInstance_t inst, game::VariableValue* a4); + void Scr_EvalLess(game::VariableValue* a1, game::VariableValue* a2, game::scriptInstance_t inst); + void Scr_EvalGreaterEqual(game::scriptInstance_t inst, game::VariableValue* a2, game::VariableValue* a3); + void Scr_EvalGreater(game::VariableValue* a1, game::VariableValue* a2, game::scriptInstance_t inst); + void Scr_EvalLessEqual(game::scriptInstance_t inst, game::VariableValue* a2, game::VariableValue* a3); + void Scr_EvalShiftLeft(game::VariableValue* result, game::VariableValue* a2, game::scriptInstance_t inst); + void Scr_EvalShiftRight(game::VariableValue* result, game::VariableValue* a2, game::scriptInstance_t inst); + void Scr_EvalPlus(game::scriptInstance_t inst, game::VariableValue* a1, game::VariableValue* a2); + void Scr_EvalMinus(game::VariableValue* a1, game::scriptInstance_t inst, game::VariableValue* a3); + void Scr_EvalMultiply(game::VariableValue* a1, game::scriptInstance_t inst, game::VariableValue* a3); + void Scr_EvalDivide(game::VariableValue* a1, game::scriptInstance_t inst, game::VariableValue* a3); + void Scr_EvalMod(game::scriptInstance_t inst, game::VariableValue* a2, game::VariableValue* a3); + void Scr_EvalBinaryOperator(game::scriptInstance_t inst, game::VariableValue* a2, game::OpcodeVM a4, game::VariableValue* a5); + void Scr_FreeEntityNum(game::scriptInstance_t inst, game::classNum_e classnum, unsigned int entnum); + void Scr_FreeEntityList(game::scriptInstance_t inst); + void Scr_FreeObjects(game::scriptInstance_t inst); + void Scr_SetClassMap(game::scriptInstance_t inst, game::classNum_e classnum); + void Scr_RemoveClassMap(game::classNum_e classnum, game::scriptInstance_t inst); + void Scr_AddClassField(game::scriptInstance_t inst, game::classNum_e classnum, const char* name, unsigned int offset); + game::VariableUnion Scr_GetOffset(const char* name, game::scriptInstance_t inst, game::classNum_e classNum); + unsigned int FindEntityId(unsigned int entClass, int entNum, game::scriptInstance_t inst); + unsigned int Scr_GetEntityId(int entNum, game::scriptInstance_t inst, game::classNum_e classnum, int clientnum); + unsigned int Scr_FindArrayIndex(game::scriptInstance_t inst, game::VariableValue* a2, unsigned int a3); + void Scr_EvalArray(game::scriptInstance_t inst, game::VariableValue* eax0, game::VariableValue* a3); + unsigned int Scr_EvalArrayRef(game::scriptInstance_t inst, unsigned int eax0); + void ClearArray(unsigned int parentId, game::scriptInstance_t inst, game::VariableValue* value); + void SetEmptyArray(game::scriptInstance_t inst, unsigned int parentId); + void Scr_AddArrayKeys(unsigned int array, game::scriptInstance_t inst); + game::scr_entref_t* Scr_GetEntityIdRef(game::scr_entref_t* result, game::scriptInstance_t inst, unsigned int a3); + void CopyEntity(unsigned int parentId, unsigned int newParentId); + float Scr_GetEndonUsage(unsigned int a1, game::scriptInstance_t inst); + float Scr_GetEntryUsageInternal(game::scriptInstance_t inst, unsigned int type, game::VariableUnion u); + float Scr_GetEntryUsage(game::scriptInstance_t inst, game::VariableValueInternal* entryValue); + float Scr_GetObjectUsage(game::scriptInstance_t inst, unsigned int parentId); + float Scr_GetThreadUsage(game::VariableStackBuffer* inst, game::scriptInstance_t a2, float* endonUsage); + unsigned int Scr_FindField(game::scriptInstance_t inst, const char* name, int* type); + char* Scr_GetSourceFile_LoadObj(const char* a1); + char* Scr_GetSourceFile_FastFile(const char* a3); + void Scr_AddFieldsForFile(game::scriptInstance_t inst, const char* filename); + void Scr_AddFields_LoadObj(game::scriptInstance_t inst, const char* path, const char* extension); + void Scr_AddFields_FastFile(game::scriptInstance_t inst, const char* path, const char* extension); + int Scr_MakeValuePrimitive(game::scriptInstance_t inst, unsigned int parentId); + void Scr_FreeGameVariable(game::scriptInstance_t inst, int bComplete); + bool Scr_SLHasLowercaseString(unsigned int a1, const char* a2); + + unsigned int FindObject(game::scriptInstance_t inst, unsigned int id); + unsigned int FindFirstSibling(game::scriptInstance_t inst, unsigned int id); + unsigned int FindNextSibling(game::scriptInstance_t inst, unsigned int id); + game::VariableValue Scr_GetArrayIndexValue(game::scriptInstance_t inst, unsigned int name); + void AddRefToObject(game::scriptInstance_t inst, unsigned int id); + void RemoveRefToEmptyObject(game::scriptInstance_t inst, unsigned int id); + void Scr_ClearThread(game::scriptInstance_t inst, unsigned int parentId); + unsigned int FindObjectVariable(game::scriptInstance_t inst, unsigned int parentId, unsigned int id); + void RemoveObjectVariable(game::scriptInstance_t inst, unsigned int parentId, unsigned int id); + game::VariableValueInternal_u* GetVariableValueAddress(game::scriptInstance_t inst, unsigned int id); + void Scr_KillEndonThread(game::scriptInstance_t inst, unsigned int threadId); + BOOL IsValidArrayIndex(game::scriptInstance_t inst, unsigned int unsignedValue); + void RemoveArrayVariable(game::scriptInstance_t inst, unsigned int parentId, unsigned int unsignedValue); + void SafeRemoveArrayVariable(game::scriptInstance_t inst, unsigned int parentId, unsigned int unsignedValue); + void AddRefToVector(game::scriptInstance_t inst, const float* vecVal); + unsigned int FindArrayVariableIndex(game::scriptInstance_t inst, unsigned int parentId, unsigned int unsignedValue); + unsigned int GetVariableIndexInternal(game::scriptInstance_t inst, unsigned int parentId, unsigned int name); + unsigned int GetNewVariableIndexInternal(game::scriptInstance_t inst, unsigned int parentId, unsigned int name); + unsigned int AllocObject(game::scriptInstance_t inst); + game::VariableType GetValueType(game::scriptInstance_t inst, unsigned int id); + game::VariableType GetObjectType(game::scriptInstance_t inst, unsigned int id); + float* Scr_AllocVector_(game::scriptInstance_t inst, const float* v); + void Scr_EvalInequality(game::scriptInstance_t inst, game::VariableValue* value1, game::VariableValue* value2); + unsigned int Scr_EvalArrayRefInternal(game::scriptInstance_t inst, game::VariableValue* varValue, game::VariableValueInternal* parentValue); + unsigned int GetNewArrayVariableIndex(game::scriptInstance_t inst, unsigned int parentId, unsigned int unsignedValue); + unsigned int GetNewArrayVariable(game::scriptInstance_t inst, unsigned int parentId, unsigned int unsignedValue); + unsigned int GetArrayVariable(game::scriptInstance_t inst, unsigned int parentId, unsigned int unsignedValue); + unsigned int AllocThread(game::scriptInstance_t inst, unsigned int self); +} diff --git a/src/codsrc/clientscript/cscr_vm.cpp b/src/codsrc/clientscript/cscr_vm.cpp new file mode 100644 index 0000000..c2f5e92 --- /dev/null +++ b/src/codsrc/clientscript/cscr_vm.cpp @@ -0,0 +1,5636 @@ +#include +#include "clientscript_public.hpp" + +#pragma warning(push) +#pragma warning(disable: 4244) +#pragma warning(disable: 4146) + +namespace codsrc +{ + // Restored + void Scr_ClearErrorMessage(game::scriptInstance_t inst) + { + game::gScrVarPub[inst].error_message = 0; + game::gScrVmGlob[inst].dialog_error_message = 0; + game::gScrVarPub[inst].error_index = 0; + } + + // Completed + void Scr_VM_Init(game::scriptInstance_t inst) + { + game::gScrVmPub[inst].maxstack = &game::gScrVmPub[inst].stack[2047]; + game::gScrVmPub[inst].top = game::gScrVmPub[inst].stack; + game::gScrVmPub[inst].function_count = 0; + game::gScrVmPub[inst].function_frame = game::gScrVmPub[inst].function_frame_start; + game::gScrVmPub[inst].localVars = game::gScrVmGlob[inst].localVarsStack - 1; + game::gScrVarPub[inst].evaluate = 0; + game::gScrVmPub[inst].debugCode = 0; + game::Scr_ClearErrorMessage(inst); + game::gScrVmPub[inst].terminal_error = 0; + game::gScrVmPub[inst].outparamcount = 0; + game::gScrVmPub[inst].inparamcount = 0; + game::gScrVarPub[inst].tempVariable = game::AllocValue(inst); + game::gScrVarPub[inst].timeArrayId = 0; + game::gScrVarPub[inst].pauseArrayId = 0; + game::gScrVarPub[inst].levelId = 0; + game::gScrVarPub[inst].gameId = 0; + game::gScrVarPub[inst].animId = 0; + game::gScrVarPub[inst].freeEntList = 0; + game::gScrVmPub[inst].stack[0].type = game::VAR_CODEPOS; + game::gScrVmGlob[inst].loading = 0; + + if ( inst == game::SCRIPTINSTANCE_SERVER ) + { + *game::sv_clientside = game::Dvar_RegisterBool( + 0, + "sv_clientside", + game::DVAR_FLAG_NONE, + "Used to toggle systems in script on and off on the server."); + } + } + + // Completed + void Scr_Init(game::scriptInstance_t inst) + { + assert(!game::gScrVarPub[inst].bInited); + + game::Scr_InitClassMap(inst); + game::Scr_VM_Init(inst); + game::gScrCompilePub[inst].script_loading = 0; + game::gScrAnimPub[inst].animtree_loading = 0; + game::gScrCompilePub[inst].scriptsPos = 0; + game::gScrCompilePub[inst].scriptsCount = 0; + game::gScrCompilePub[inst].loadedscripts = 0; + game::gScrAnimPub[inst].animtrees = 0; + game::gScrCompilePub[inst].builtinMeth = 0; + game::gScrCompilePub[inst].builtinFunc = 0; + game::gScrVarPub[inst].bInited = 1; + } + + // Resotred + void VM_Shutdown(game::scriptInstance_t inst) + { + if ( game::gScrVarPub[inst].tempVariable ) + { + game::FreeValue(game::gScrVarPub[inst].tempVariable, inst); + game::gScrVarPub[inst].tempVariable = 0; + } + } + + // Restored + void Scr_ShutdownVariables(game::scriptInstance_t inst) + { + if ( game::gScrVarPub[inst].gameId ) + { + game::FreeValue(game::gScrVarPub[inst].gameId, inst); + game::gScrVarPub[inst].gameId = 0; + } + } + + // Completed + void Scr_Shutdown(game::scriptInstance_t inst) + { + if ( game::gScrVarPub[inst].bInited ) + { + game::gScrVarPub[inst].bInited = 0; + game::VM_Shutdown(inst); + game::Scr_ShutdownVariables(inst); + } + } + + jmp_buf g_script_error[2][33]; + + // Completed + void Scr_ErrorInternal(game::scriptInstance_t inst) + { + assert(game::gScrVarPub[inst].error_message); + + if ( !game::gScrVarPub[inst].evaluate && !game::gScrCompilePub[inst].script_loading ) + { + if ( game::gScrVmPub[inst].function_count || game::gScrVmPub[inst].debugCode ) + { + game::Com_PrintMessage(game::CON_CHANNEL_LOGFILEONLY, "throwing script exception: ", 0); + game::Com_PrintMessage(game::CON_CHANNEL_LOGFILEONLY, game::gScrVarPub[inst].error_message, 0); + game::Com_PrintMessage(game::CON_CHANNEL_LOGFILEONLY, "\n", 0); + + assert(game::g_script_error_level[inst] < 33); + + //game::longjmp((int*)game::g_script_error.get() + 0x10 * (0x21 * inst + game::g_script_error_level[inst]), -1); + longjmp(g_script_error[inst][game::g_script_error_level[inst]], -1); + } + + game::Sys_Error("%s", game::gScrVarPub[inst].error_message); + } + if ( game::gScrVmPub[inst].terminal_error ) + { + game::Sys_Error("%s", game::gScrVarPub[inst].error_message); + } + } + + // Completed + void Scr_ClearOutParams(game::scriptInstance_t inst) + { + while ( game::gScrVmPub[inst].outparamcount ) + { + game::RemoveRefToValueInternal(inst, game::gScrVmPub[inst].top->type, game::gScrVmPub[inst].top->u); + --game::gScrVmPub[inst].top; + --game::gScrVmPub[inst].outparamcount; + } + } + + // Restored + void ClearVariableValue(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(!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; + + assert((entryValue->w.type & VAR_MASK) == game::VAR_UNDEFINED); + } + + // Completed + unsigned int GetDummyObject(game::scriptInstance_t inst) + { + game::ClearVariableValue(inst, game::gScrVarPub[inst].tempVariable); + return game::GetObject(inst, game::gScrVarPub[inst].tempVariable); + } + + // Completed + unsigned int GetDummyFieldValue(game::scriptInstance_t inst) + { + game::ClearVariableValue(inst, game::gScrVarPub[inst].tempVariable); + return game::gScrVarPub[inst].tempVariable; + } + + // Restored + BOOL IsFieldObject(game::scriptInstance_t inst, unsigned int id) + { + game::VariableValueInternal *entryValue; + + assert(id); + + entryValue = &game::gScrVarGlob[inst].parentVariables[id + 1]; + + assert((entryValue->w.status & VAR_STAT_MASK) != VAR_STAT_FREE); + assert(IsObject(entryValue)); + + return (game::VariableType)(entryValue->w.status & VAR_MASK) < game::VAR_ARRAY; + } + + // Restored + void RemoveVariableValue(game::scriptInstance_t inst, unsigned int parentId, unsigned int index) + { + unsigned int id; + + assert(index); + id = game::gScrVarGlob[inst].childVariables[index].hash.id; + + assert(id); + + game::MakeVariableExternal(&game::gScrVarGlob[inst].parentVariables[parentId + 1], inst, index); + game::FreeChildValue(id, inst, parentId); + } + + // Restored + unsigned int GetNewVariableIndexReverseInternal(game::scriptInstance_t inst, unsigned int parentId, unsigned int name) + { + assert(!game::FindVariableIndexInternal(inst, parentId, name)); + + return game::GetNewVariableIndexReverseInternal2(name, inst, parentId, (parentId + name) % 0xFFFD + 1); + } + + // Restored + unsigned int GetNewObjectVariableReverse(game::scriptInstance_t inst, unsigned int parentId, unsigned int id) + { + assert((game::gScrVarGlob[inst].parentVariables[parentId + 1].w.status & VAR_MASK) == game::VAR_ARRAY); + + return game::gScrVarGlob[inst].childVariables[game::GetNewVariableIndexReverseInternal(inst, parentId, id + 0x10000)].hash.id; + } + + // Restored + unsigned int Scr_GetLocalVar(game::scriptInstance_t inst, int pos) + { + return game::gScrVmPub[inst].localVars[-pos]; + } + + // Restored + void Scr_EvalBoolNot(game::scriptInstance_t inst, game::VariableValue *value) + { + game::Scr_CastBool(inst, value); + + if ( value->type == game::VAR_INTEGER ) + { + value->u.intValue = value->u.intValue == 0; + } + } + + // Restored + unsigned int GetInternalVariableIndex([[maybe_unused]] game::scriptInstance_t inst, unsigned int unsignedValue) + { + assert(game::IsValidArrayIndex(inst, unsignedValue)); + return (unsignedValue + 0x800000) & 0xFFFFFF; + } + + // Restored + const char * Scr_ReadCodePos([[maybe_unused]] game::scriptInstance_t inst, const char **pos) + { + int ans; + + ans = *(int *)*pos; + *pos += 4; + return (const char *)ans; + } + + // Restored + unsigned int Scr_ReadUnsignedInt([[maybe_unused]] game::scriptInstance_t inst, const char **pos) + { + unsigned int ans; + + ans = *(unsigned int *)*pos; + *pos += 4; + return ans; + } + + // Restored + unsigned short Scr_ReadUnsignedShort([[maybe_unused]] game::scriptInstance_t inst, const char **pos) + { + unsigned short ans; + + ans = *(unsigned short *)*pos; + *pos += 2; + return ans; + } + + // Restored + unsigned char Scr_ReadUnsignedByte([[maybe_unused]] game::scriptInstance_t inst, const char **pos) + { + unsigned char ans; + + ans = *(unsigned char *)*pos; + *pos += 1; + return ans; + } + + // Restored + float Scr_ReadFloat([[maybe_unused]] game::scriptInstance_t inst, const char **pos) + { + float ans; + + ans = *(float *)*pos; + *pos += 4; + return ans; + } + + // Restored + const float* Scr_ReadVector([[maybe_unused]] game::scriptInstance_t inst, const char **pos) + { + float* ans; + + ans = (float *)*pos; + *pos += 12; + return ans; + } + + // Restored + const char* Scr_ReadData([[maybe_unused]] game::scriptInstance_t inst, const char** pos, unsigned int count) + { + const char* result; + + result = *pos; + *pos += count; + return result; + } + + // Restored + namespace VM + { + bool OP_End(game::scriptInstance_t inst) + { + game::function_stack_t localFs = game::gFs[inst]; + unsigned int parentLocalId = game::GetSafeParentLocalId(inst, localFs.localId); + + game::Scr_KillThread(inst, localFs.localId); + game::gScrVmPub[inst].localVars -= localFs.localVarCount; + + assert(localFs.top->type != game::VAR_PRECODEPOS); + + while (localFs.top->type != game::VAR_CODEPOS) + { + game::RemoveRefToValueInternal(inst, localFs.top->type, localFs.top->u); + --localFs.top; + assert(localFs.top->type != game::VAR_PRECODEPOS); + } + --game::gScrVmPub[inst].function_count; + --game::gScrVmPub[inst].function_frame; + + if (!parentLocalId) + { + assert(localFs.top == localFs.startTop); + + localFs.startTop[1].type = game::VAR_UNDEFINED; + + if (game::gThreadCount[inst]) + { + --game::gThreadCount[inst]; + game::RemoveRefToObject(localFs.localId, inst); + localFs = game::gScrVmPub[inst].function_frame->fs; + localFs.top->type = (game::VariableType)game::gScrVmPub[inst].function_frame->topType; + ++localFs.top; + game::gFs[inst] = localFs; + return true; + } + + assert(game::g_script_error_level[inst] >= 0); + + --game::g_script_error_level[inst]; + game::gFs[inst] = localFs; + return false; + } + + assert(localFs.top->type == game::VAR_CODEPOS); + localFs.top->type = game::VAR_UNDEFINED; + assert(localFs.top != localFs.startTop); + + game::RemoveRefToObject(localFs.localId, inst); + localFs.pos = game::gScrVmPub[inst].function_frame->fs.pos; + + assert(localFs.pos); + + localFs.localVarCount = game::gScrVmPub[inst].function_frame->fs.localVarCount; + localFs.localId = parentLocalId; + + game::gFs[inst] = localFs; + return true; + } + + bool OP_Return(game::scriptInstance_t inst) + { + game::VariableValue tempValue; + game::function_stack_t localFs = game::gFs[inst]; + unsigned int parentLocalId = game::GetSafeParentLocalId(inst, localFs.localId); + + game::Scr_KillThread(inst, localFs.localId); + game::gScrVmPub[inst].localVars -= localFs.localVarCount; + tempValue.u.intValue = localFs.top->u.intValue; + tempValue.type = localFs.top->type; + --localFs.top; + assert(localFs.top->type != game::VAR_PRECODEPOS); + + while ( localFs.top->type != game::VAR_CODEPOS ) + { + game::RemoveRefToValueInternal(inst, localFs.top->type, localFs.top->u); + --localFs.top; + assert(localFs.top->type != game::VAR_PRECODEPOS); + } + + --game::gScrVmPub[inst].function_count; + --game::gScrVmPub[inst].function_frame; + if ( parentLocalId ) + { + assert(localFs.top->type == game::VAR_CODEPOS); + *localFs.top = tempValue; + assert(localFs.top != localFs.startTop); + game::RemoveRefToObject(localFs.localId, inst); + + localFs.pos = game::gScrVmPub[inst].function_frame->fs.pos; + assert(localFs.pos); + localFs.localVarCount = game::gScrVmPub[inst].function_frame->fs.localVarCount; + localFs.localId = parentLocalId; + + game::gFs[inst] = localFs; + return true; + } + + assert(localFs.top == localFs.startTop); + localFs.top[1] = tempValue; + + if ( game::gThreadCount[inst] ) + { + --game::gThreadCount[inst]; + game::RemoveRefToObject(localFs.localId, inst); + localFs = game::gScrVmPub[inst].function_frame->fs; + localFs.top->type = (game::VariableType)game::gScrVmPub[inst].function_frame->topType; + ++localFs.top; + + game::gFs[inst] = localFs; + return true; + } + + assert(game::g_script_error_level[inst] >= 0); + + --game::g_script_error_level[inst]; + game::gFs[inst] = localFs; + return false; + } + + void OP_GetUndefined(game::scriptInstance_t inst) + { + assert(game::gFs[inst].top >= game::gScrVmPub[inst].stack); + assert(&game::gFs[inst].top[1] <= game::gScrVmPub[inst].maxstack); + + ++game::gFs[inst].top; + game::gFs[inst].top->type = game::VAR_UNDEFINED; + } + + void OP_GetZero(game::scriptInstance_t inst) + { + assert(game::gFs[inst].top >= game::gScrVmPub[inst].stack); + assert(&game::gFs[inst].top[1] <= game::gScrVmPub[inst].maxstack); + + ++game::gFs[inst].top; + game::gFs[inst].top->type = game::VAR_INTEGER; + game::gFs[inst].top->u.intValue = 0; + } + + void OP_GetByte(game::scriptInstance_t inst) + { + assert(game::gFs[inst].top >= game::gScrVmPub[inst].stack); + assert(&game::gFs[inst].top[1] <= game::gScrVmPub[inst].maxstack); + + ++game::gFs[inst].top; + game::gFs[inst].top->type = game::VAR_INTEGER; + game::gFs[inst].top->u.intValue = game::Scr_ReadUnsignedByte(inst, &game::gFs[inst].pos); + } + + void OP_GetNegByte(game::scriptInstance_t inst) + { + assert(game::gFs[inst].top >= game::gScrVmPub[inst].stack); + assert(&game::gFs[inst].top[1] <= game::gScrVmPub[inst].maxstack); + + ++game::gFs[inst].top; + game::gFs[inst].top->type = game::VAR_INTEGER; + game::gFs[inst].top->u.intValue = -game::Scr_ReadUnsignedByte(inst, &game::gFs[inst].pos); + } + + void OP_GetUnsignedShort(game::scriptInstance_t inst) + { + assert(game::gFs[inst].top >= game::gScrVmPub[inst].stack); + assert(&game::gFs[inst].top[1] <= game::gScrVmPub[inst].maxstack); + + ++game::gFs[inst].top; + game::gFs[inst].top->type = game::VAR_INTEGER; + game::gFs[inst].top->u.intValue = game::Scr_ReadUnsignedShort(inst, &game::gFs[inst].pos); + } + + void OP_GetNegUnsignedShort(game::scriptInstance_t inst) + { + assert(game::gFs[inst].top >= game::gScrVmPub[inst].stack); + assert(&game::gFs[inst].top[1] <= game::gScrVmPub[inst].maxstack); + + ++game::gFs[inst].top; + game::gFs[inst].top->type = game::VAR_INTEGER; + game::gFs[inst].top->u.intValue = -game::Scr_ReadUnsignedShort(inst, &game::gFs[inst].pos); + } + + void OP_GetInteger(game::scriptInstance_t inst) + { + assert(game::gFs[inst].top >= game::gScrVmPub[inst].stack); + assert(&game::gFs[inst].top[1] <= game::gScrVmPub[inst].maxstack); + + ++game::gFs[inst].top; + game::gFs[inst].top->type = game::VAR_INTEGER; + game::gFs[inst].top->u.intValue = game::Scr_ReadUnsignedInt(inst, &game::gFs[inst].pos); + } + + void OP_GetFloat(game::scriptInstance_t inst) + { + assert(game::gFs[inst].top >= game::gScrVmPub[inst].stack); + assert(&game::gFs[inst].top[1] <= game::gScrVmPub[inst].maxstack); + + ++game::gFs[inst].top; + game::gFs[inst].top->type = game::VAR_FLOAT; + game::gFs[inst].top->u.floatValue = game::Scr_ReadFloat(inst, &game::gFs[inst].pos); + } + + void OP_GetString(game::scriptInstance_t inst) + { + assert(game::gFs[inst].top >= game::gScrVmPub[inst].stack); + assert(&game::gFs[inst].top[1] <= game::gScrVmPub[inst].maxstack); + + ++game::gFs[inst].top; + game::gFs[inst].top->type = game::VAR_STRING; + game::gFs[inst].top->u.stringValue = game::Scr_ReadUnsignedShort(inst, &game::gFs[inst].pos); + game::SL_CheckExists(inst, game::gFs[inst].top->u.stringValue); + game::SL_AddRefToString(inst, game::gFs[inst].top->u.stringValue); + } + + void OP_GetIString(game::scriptInstance_t inst) + { + assert(game::gFs[inst].top >= game::gScrVmPub[inst].stack); + assert(&game::gFs[inst].top[1] <= game::gScrVmPub[inst].maxstack); + + ++game::gFs[inst].top; + game::gFs[inst].top->type = game::VAR_ISTRING; + game::gFs[inst].top->u.stringValue = game::Scr_ReadUnsignedShort(inst, &game::gFs[inst].pos); + game::SL_CheckExists(inst, game::gFs[inst].top->u.stringValue); + game::SL_AddRefToString(inst, game::gFs[inst].top->u.stringValue); + } + + void OP_GetVector(game::scriptInstance_t inst) + { + assert(game::gFs[inst].top >= game::gScrVmPub[inst].stack); + assert(&game::gFs[inst].top[1] <= game::gScrVmPub[inst].maxstack); + + ++game::gFs[inst].top; + game::gFs[inst].top->type = game::VAR_VECTOR; + game::gFs[inst].top->u.vectorValue = game::Scr_ReadVector(inst, &game::gFs[inst].pos); + } + + void OP_GetLevelObject(game::scriptInstance_t inst, unsigned int* objectId) + { + assert(game::gScrVarPub[inst].levelId); + + *objectId = game::gScrVarPub[inst].levelId; + } + + void OP_GetAnimObject(game::scriptInstance_t inst, unsigned int* objectId) + { + assert(game::gScrVarPub[inst].animId); + + *objectId = game::gScrVarPub[inst].animId; + } + + void OP_GetSelf(game::scriptInstance_t inst) + { + assert(game::gFs[inst].top >= game::gScrVmPub[inst].stack); + assert(&game::gFs[inst].top[1] <= game::gScrVmPub[inst].maxstack); + + ++game::gFs[inst].top; + game::gFs[inst].top->type = game::VAR_POINTER; + game::gFs[inst].top->u.pointerValue = game::Scr_GetSelf(inst, game::gFs[inst].localId); + game::AddRefToObject(inst, game::gFs[inst].top->u.pointerValue); + } + + void OP_GetLevel(game::scriptInstance_t inst) + { + assert(game::gFs[inst].top >= game::gScrVmPub[inst].stack); + assert(&game::gFs[inst].top[1] <= game::gScrVmPub[inst].maxstack); + + ++game::gFs[inst].top; + game::gFs[inst].top->type = game::VAR_POINTER; + game::gFs[inst].top->u.pointerValue = game::gScrVarPub[inst].levelId; + game::AddRefToObject(inst, game::gScrVarPub[inst].levelId); + } + + void OP_GetGame(game::scriptInstance_t inst) + { + assert(game::gFs[inst].top >= game::gScrVmPub[inst].stack); + assert(&game::gFs[inst].top[1] <= game::gScrVmPub[inst].maxstack); + + ++game::gFs[inst].top; + *game::gFs[inst].top = game::Scr_EvalVariable(inst, game::gScrVarPub[inst].gameId); + } + + void OP_GetAnim(game::scriptInstance_t inst) + { + assert(game::gFs[inst].top >= game::gScrVmPub[inst].stack); + assert(&game::gFs[inst].top[1] <= game::gScrVmPub[inst].maxstack); + + ++game::gFs[inst].top; + game::gFs[inst].top->type = game::VAR_POINTER; + game::gFs[inst].top->u.pointerValue = game::gScrVarPub[inst].animId; + game::AddRefToObject(inst, game::gScrVarPub[inst].animId); + } + + void OP_GetAnimation(game::scriptInstance_t inst) + { + assert(game::gFs[inst].top >= game::gScrVmPub[inst].stack); + assert(&game::gFs[inst].top[1] <= game::gScrVmPub[inst].maxstack); + + ++game::gFs[inst].top; + game::gFs[inst].top->type = game::VAR_ANIMATION; + game::gFs[inst].top->u.codePosValue = game::Scr_ReadCodePos(inst, &game::gFs[inst].pos); + } + + void OP_GetGameRef(game::scriptInstance_t inst, unsigned int* fieldValueIndex, unsigned int* fieldValueId) + { + *fieldValueIndex = 0; + *fieldValueId = game::gScrVarPub[inst].gameId; + } + + void OP_GetFunction(game::scriptInstance_t inst) + { + assert(game::gFs[inst].top >= game::gScrVmPub[inst].stack); + assert(&game::gFs[inst].top[1] <= game::gScrVmPub[inst].maxstack); + + ++game::gFs[inst].top; + game::gFs[inst].top->type = game::VAR_FUNCTION; + game::gFs[inst].top->u.codePosValue = game::Scr_ReadCodePos(inst, &game::gFs[inst].pos); + } + + void OP_CreateLocalVariable(game::scriptInstance_t inst) + { + ++game::gFs[inst].localVarCount; + ++game::gScrVmPub[inst].localVars; + + unsigned short pos = game::Scr_ReadUnsignedShort(inst, &game::gFs[inst].pos); + *game::gScrVmPub[inst].localVars = game::GetNewVariable(inst, pos, game::gFs[inst].localId); + } + + void OP_RemoveLocalVariables(game::scriptInstance_t inst) + { + unsigned char removeCount = game::Scr_ReadUnsignedByte(inst, &game::gFs[inst].pos); + game::gFs[inst].localVarCount -= removeCount; + game::gScrVmPub[inst].localVars -= removeCount; + + while ( removeCount ) + { + game::RemoveNextVariable(inst, game::gFs[inst].localId); + --removeCount; + } + } + + void OP_EvalLocalVariableCached(game::scriptInstance_t inst, int num) + { + assert(game::gFs[inst].top >= game::gScrVmPub[inst].stack); + assert(&game::gFs[inst].top[1] <= game::gScrVmPub[inst].maxstack); + + if (num < 0) + { + num = game::Scr_ReadUnsignedByte(inst, &game::gFs[inst].pos); + } + + ++game::gFs[inst].top; + *game::gFs[inst].top = game::Scr_EvalVariable(inst, game::gScrVmPub[inst].localVars[-num]); + } + + void OP_EvalArray(game::scriptInstance_t inst) + { + game::Scr_EvalArray(inst, game::gFs[inst].top - 1, game::gFs[inst].top); + --game::gFs[inst].top; + } + + void OP_EvalLocalArrayCached(game::scriptInstance_t inst) + { + assert(game::gFs[inst].top >= game::gScrVmPub[inst].stack); + assert(&game::gFs[inst].top[1] <= game::gScrVmPub[inst].maxstack); + + ++game::gFs[inst].top; + *game::gFs[inst].top = game::Scr_EvalVariable(inst, game::gScrVmPub[inst].localVars[-game::Scr_ReadUnsignedByte(inst, &game::gFs[inst].pos)]); + + OP_EvalArray(inst); + } + + void OP_EvalArrayRef(game::scriptInstance_t inst, unsigned int* fieldValueId, unsigned int* fieldValueIndex, unsigned int* objectId) + { + game::function_stack_t localFs = game::gFs[inst]; + + *objectId = game::Scr_EvalArrayRef(inst, *fieldValueId); + if ( localFs.top->type == game::VAR_INTEGER ) + { + if ( !game::IsValidArrayIndex(inst, localFs.top->u.stringValue) ) + { + game::gFs[inst] = localFs; + game::Scr_Error(game::va("array index %d out of range", localFs.top->u.intValue), inst, false); + } + + *fieldValueIndex = game::GetArrayVariableIndex(localFs.top->u.stringValue, inst, *objectId); + } + else if ( localFs.top->type == game::VAR_STRING ) + { + *fieldValueIndex = game::GetVariableIndexInternal(inst, *objectId, localFs.top->u.stringValue); + game::SL_RemoveRefToString(localFs.top->u.stringValue, inst); + } + else + { + game::gFs[inst] = localFs; + game::Scr_Error(game::va("%s is not an array index", game::var_typename[localFs.top->type]), inst, false); + } + + game::gFs[inst] = localFs; + --game::gFs[inst].top; + + *fieldValueId = game::gScrVarGlob[inst].childVariables[*fieldValueIndex].hash.id; + assert(fieldValueId); + } + + void OP_EvalLocalArrayRefCached(game::scriptInstance_t inst, int num, unsigned int* fieldValueId, unsigned int* fieldValueIndex, unsigned int* objectId) + { + if (num < 0) + { + num = game::Scr_ReadUnsignedByte(inst, &game::gFs[inst].pos); + } + + *fieldValueId = game::gScrVmPub[inst].localVars[-num]; + + OP_EvalArrayRef(inst, fieldValueId, fieldValueIndex, objectId); + } + + void OP_ClearArray(game::scriptInstance_t inst, unsigned int *fieldValueId) + { + game::ClearArray(*fieldValueId, inst, game::gFs[inst].top); + --game::gFs[inst].top; + } + + void OP_EmptyArray(game::scriptInstance_t inst) + { + ++game::gFs[inst].top; + game::gFs[inst].top->type = game::VAR_POINTER; + game::gFs[inst].top->u.pointerValue = game::Scr_AllocArray(inst); + } + + void OP_GetSelfObject(game::scriptInstance_t inst, unsigned int *objectId) + { + game::function_stack_t localFs = game::gFs[inst]; + game::VariableType type; + + *objectId = game::Scr_GetSelf(inst, localFs.localId); + + if (!game::IsFieldObject(inst, *objectId)) + { + type = game::GetObjectType(inst, *objectId); + game::gFs[inst] = localFs; + game::Scr_Error(game::va("%s is not an object", game::var_typename[type]), inst, false); + } + + game::gFs[inst] = localFs; + } + + void OP_EvalLevelAnimFieldVariable(game::scriptInstance_t inst, bool isLevel, unsigned int *objectId) + { + assert(game::gFs[inst].top >= game::gScrVmPub[inst].stack); + assert(&game::gFs[inst].top[1] <= game::gScrVmPub[inst].maxstack); + + game::function_stack_t localFs = game::gFs[inst]; + + if (isLevel) + { + *objectId = game::gScrVarPub[inst].levelId; + } + else + { + *objectId = game::gScrVarPub[inst].animId; + } + + ++localFs.top; + *localFs.top = game::Scr_EvalVariable(inst, game::FindVariable(game::Scr_ReadUnsignedShort(inst, &localFs.pos), *objectId, inst)); + + game::gFs[inst] = localFs; + } + + void OP_EvalFieldVariable(game::scriptInstance_t inst, unsigned int* objectId) + { + assert(game::gFs[inst].top >= game::gScrVmPub[inst].stack); + assert(&game::gFs[inst].top[1] <= game::gScrVmPub[inst].maxstack); + + game::gFs[inst].top[1] = game::Scr_FindVariableField(inst, *objectId, game::Scr_ReadUnsignedShort(inst, &game::gFs[inst].pos)); + ++game::gFs[inst].top; + } + + void OP_EvalSelfFieldVariable(game::scriptInstance_t inst, unsigned int *objectId) + { + game::function_stack_t localFs = game::gFs[inst]; + game::VariableType type; + + *objectId = game::Scr_GetSelf(inst, localFs.localId); + if (!game::IsFieldObject(inst, *objectId)) + { + assert(game::gFs[inst].top >= game::gScrVmPub[inst].stack); + assert(&game::gFs[inst].top[1] <= game::gScrVmPub[inst].maxstack); + + ++localFs.top; + game::Scr_ReadUnsignedShort(inst, &localFs.pos); + + type = game::GetObjectType(inst, *objectId); + game::gFs[inst] = localFs; + game::Scr_Error(game::va("%s is not an object", game::var_typename[type]), inst, false); + } + + game::gFs[inst] = localFs; + OP_EvalFieldVariable(inst, objectId); + } + + void OP_EvalFieldVariableRef(game::scriptInstance_t inst, unsigned int *objectId, unsigned int *fieldValueIndex, unsigned int *fieldValueId) + { + *fieldValueIndex = game::Scr_GetVariableFieldIndex(inst, game::Scr_ReadUnsignedShort(inst, &game::gFs[inst].pos), *objectId); + *fieldValueId = game::gScrVarGlob[inst].childVariables[*fieldValueIndex].hash.id; + } + + void OP_EvalLevelFieldVariableRef(game::scriptInstance_t inst, unsigned int *objectId, unsigned int *fieldValueIndex, unsigned int *fieldValueId) + { + *objectId = game::gScrVarPub[inst].levelId; + OP_EvalFieldVariableRef(inst, objectId, fieldValueIndex, fieldValueId); + } + + void OP_EvalAnimFieldVariableRef(game::scriptInstance_t inst, unsigned int *objectId, unsigned int *fieldValueIndex, unsigned int *fieldValueId) + { + *objectId = game::gScrVarPub[inst].animId; + OP_EvalFieldVariableRef(inst, objectId, fieldValueIndex, fieldValueId); + } + + void OP_EvalSelfFieldVariableRef(game::scriptInstance_t inst, unsigned int *objectId, unsigned int *fieldValueIndex, unsigned int *fieldValueId) + { + assert(*objectId); + + *objectId = game::Scr_GetSelf(inst, game::gFs[inst].localId); + OP_EvalFieldVariableRef(inst, objectId, fieldValueIndex, fieldValueId); + } + + void OP_ClearFieldVariable(game::scriptInstance_t inst, unsigned int *objectId) + { + assert(*objectId); + + game::ClearVariableField(inst, *objectId, game::Scr_ReadUnsignedShort(inst, &game::gFs[inst].pos), game::gFs[inst].top); + } + + void OP_SafeSetVariableFieldCached(game::scriptInstance_t inst, int num) + { + assert(game::gFs[inst].top->type != game::VAR_CODEPOS); + + if (num < 0) + { + num = game::Scr_ReadUnsignedByte(inst, &game::gFs[inst].pos); + } + + if (game::gFs[inst].top->type != game::VAR_PRECODEPOS) + { + game::SetVariableValue(inst, game::gFs[inst].top, game::gScrVmPub[inst].localVars[-num]); + --game::gFs[inst].top; + } + } + + void OP_SafeCreateVariableFieldCached(game::scriptInstance_t inst) + { + ++game::gScrVmPub[inst].localVars; + ++game::gFs[inst].localVarCount; + + *game::gScrVmPub[inst].localVars = game::GetNewVariable(inst, game::Scr_ReadUnsignedShort(inst, &game::gFs[inst].pos), game::gFs[inst].localId); + + OP_SafeSetVariableFieldCached(inst, 0); + } + + void OP_SafeSetWaittillVariableFieldCached(game::scriptInstance_t inst) + { + assert(game::gFs[inst].top->type != game::VAR_PRECODEPOS); + + unsigned char num = game::Scr_ReadUnsignedByte(inst, &game::gFs[inst].pos); + + if (game::gFs[inst].top->type != game::VAR_CODEPOS) + { + game::SetVariableValue(inst, game::gFs[inst].top, game::gScrVmPub[inst].localVars[-num]); + --game::gFs[inst].top; + } + else + { + game::ClearVariableValue(inst, game::gScrVmPub[inst].localVars[-num]); + } + } + + void OP_clearparams(game::scriptInstance_t inst) + { + assert(game::gFs[inst].top->type != game::VAR_PRECODEPOS); + + while ( game::gFs[inst].top->type != game::VAR_CODEPOS ) + { + game::RemoveRefToValueInternal(inst, game::gFs[inst].top->type, game::gFs[inst].top->u); + --game::gFs[inst].top; + + assert(game::gFs[inst].top->type != game::VAR_PRECODEPOS); + } + } + + void OP_checkclearparams(game::scriptInstance_t inst) + { + assert(game::gFs[inst].top->type != game::VAR_CODEPOS); + if ( game::gFs[inst].top->type == game::VAR_PRECODEPOS ) + { + /*if (gScrVarPub[inst].numScriptValues > 0x3F37E || gScrVarPub[inst].numScriptObjects > 0x737E) + { + gFs[inst] = localFs; + if ( gScrVmPub[inst].showError ) + { + Scr_DumpScriptThreads(inst); + Scr_DumpScriptVariablesDefault(inst); + Scr_Error(inst, "exceeded maximum number of script variables", 0); + } + Sys_Error("exceeded maximum number of script variables"); + }*/ + game::gFs[inst].top->type = game::VAR_CODEPOS; + } + else + { + game::Scr_Error("function called with too many parameters", inst, false); + } + } + + void OP_EvalLocalVariableRefCached(game::scriptInstance_t inst, int num, unsigned int* fieldValueIndex, unsigned int* fieldValueId) + { + if (num < 0) + { + num = game::Scr_ReadUnsignedByte(inst, &game::gFs[inst].pos); + } + + *fieldValueIndex = 0; + *fieldValueId = game::gScrVmPub[inst].localVars[-num]; + } + + void OP_SetLevelFieldVariableField(game::scriptInstance_t inst) + { + game::SetVariableValue(inst, game::gFs[inst].top, game::GetVariable(inst, game::gScrVarPub[inst].levelId, game::Scr_ReadUnsignedShort(inst, &game::gFs[inst].pos))); + --game::gFs[inst].top; + } + + void OP_SetAnimFieldVariableField(game::scriptInstance_t inst) + { + game::SetVariableValue(inst, game::gFs[inst].top, game::GetVariable(inst, game::gScrVarPub[inst].animId, game::Scr_ReadUnsignedShort(inst, &game::gFs[inst].pos))); + + game::gFs[inst].top--; + } + + void OP_SetVariableField(game::scriptInstance_t inst, unsigned int* objectId, unsigned int* fieldValueIndex, unsigned int* fieldValueId) + { + if ( *fieldValueIndex ) + { + assert(*fieldValueId); + + if ( game::gFs[inst].top->type) + { + game::SetVariableValue(inst, game::gFs[inst].top, *fieldValueId); + } + else + { + game::RemoveVariableValue(inst, *objectId, *fieldValueIndex); + } + } + else + { + game::SetVariableFieldValue(inst, *fieldValueId, game::gFs[inst].top); + } + + game::gFs[inst].top--; + } + + void OP_SetSelfFieldVariableField(game::scriptInstance_t inst, unsigned int* objectId, unsigned int* fieldValueIndex, unsigned int* fieldValueId) + { + unsigned short fieldName = game::Scr_ReadUnsignedShort(inst, &game::gFs[inst].pos); + *objectId = game::Scr_GetSelf(inst, game::gFs[inst].localId); + *fieldValueIndex = game::Scr_GetVariableFieldIndex(inst, fieldName, *objectId); + *fieldValueId = game::gScrVarGlob[inst].childVariables[*fieldValueIndex].hash.id; + + OP_SetVariableField(inst, objectId, fieldValueIndex, fieldValueId); + } + + void OP_SetLocalVariableFieldCached(game::scriptInstance_t inst, int num) + { + if (num < 0) + { + num = game::Scr_ReadUnsignedByte(inst, &game::gFs[inst].pos); + } + + game::SetVariableValue(inst, game::gFs[inst].top, game::gScrVmPub[inst].localVars[-num]); + game::gFs[inst].top--; + } + + void post_builtin(game::scriptInstance_t inst) + { + unsigned int paramcount; + + game::gFs[inst].top = game::gScrVmPub[inst].top; + game::gFs[inst].pos = game::gScrVmPub[inst].function_frame->fs.pos; + + if ( game::gScrVmPub[inst].outparamcount ) + { + paramcount = game::gScrVmPub[inst].outparamcount; + game::gScrVmPub[inst].outparamcount = 0; + game::gScrVmPub[inst].top -= paramcount; + + do + { + game::RemoveRefToValueInternal(inst, game::gFs[inst].top->type, game::gFs[inst].top->u); + --game::gFs[inst].top; + --paramcount; + } + while ( paramcount ); + } + + if ( game::gScrVmPub[inst].inparamcount ) + { + assert(game::gScrVmPub[inst].inparamcount == 1); + + game::gScrVmPub[inst].inparamcount = 0; + assert(game::gFs[inst].top == game::gScrVmPub[inst].top); + } + else + { + assert(game::gFs[inst].top == game::gScrVmPub[inst].top); + + game::gFs[inst].top[1].type = game::VAR_UNDEFINED; + ++game::gFs[inst].top; + } + } + + void OP_CallBuiltin(game::scriptInstance_t inst, int num) + { + if (num < 0) + { + num = game::Scr_ReadUnsignedByte(inst, &game::gFs[inst].pos); + } + + assert(!game::gScrVmPub[inst].outparamcount); + + assert(!game::gScrVmPub[inst].inparamcount); + + game::gScrVmPub[inst].outparamcount = num; + + //const char* debugpos = game::gFs[inst].pos; + unsigned short builtinIndex = game::Scr_ReadUnsignedShort(inst, &game::gFs[inst].pos); + game::gScrVmPub[inst].function_frame->fs.pos = game::gFs[inst].pos; + + /* + if ( gScrVmDebugPub[inst].func_table[builtinIndex].breakpointCount ) + { + outparamcount = gScrVmPub[inst].outparamcount; + Scr_HitBuiltinBreakpoint(inst, localFs.top, debugpos, localFs.localId, gOpcode[inst], builtinIndex, outparamcount); + gScrVmPub[inst].outparamcount = outparamcount; + }*/ + + assert(builtinIndex >= 0); + assert(builtinIndex < 1024); + + game::gScrVmPub[inst].top = game::gFs[inst].top; + ((void (*)(void))game::gScrCompilePub[inst].func_table[builtinIndex])(); + + post_builtin(inst); + } + + void OP_CallBuiltinMethod(game::scriptInstance_t inst, int num, unsigned int *objectId) + { + game::VariableType type; + game::scr_entref_t entref; + + if (num < 0) + { + num = game::Scr_ReadUnsignedByte(inst, &game::gFs[inst].pos); + } + + assert(!game::gScrVmPub[inst].outparamcount); + + assert(!game::gScrVmPub[inst].inparamcount); + + game::gScrVmPub[inst].outparamcount = num; + + //const char* debugpos = game::gFs[inst].pos; + game::gScrVmPub[inst].top = game::gFs[inst].top - 1; + unsigned short builtinIndex = game::Scr_ReadUnsignedShort(inst, &game::gFs[inst].pos); + + if (game::gFs[inst].top->type != game::VAR_POINTER) + { + type = game::gFs[inst].top->type; + game::RemoveRefToValueInternal(inst, game::gFs[inst].top->type, game::gFs[inst].top->u); + game::gScrVarPub[inst].error_index = -1; + game::Scr_Error(game::va("%s is not an entity", game::var_typename[type]), inst, false); + } + + *objectId = game::gFs[inst].top->u.pointerValue; + + if (game::GetObjectType(inst, *objectId) != game::VAR_ENTITY) + { + type = game::GetObjectType(inst, *objectId); + game::RemoveRefToObject(*objectId, inst); + game::gScrVarPub[inst].error_index = -1; + game::Scr_Error(game::va("%s is not an entity", game::var_typename[type]), inst, false); + } + + entref = *game::Scr_GetEntityIdRef(&entref, inst, *objectId); + + game::RemoveRefToObject(*objectId, inst); + game::gScrVmPub[inst].function_frame->fs.pos = game::gFs[inst].pos; + /* + if ( gScrVmGlob[inst].recordPlace ) + Scr_GetFileAndLine(inst, localFs.pos, &gScrVmGlob[inst].lastFileName, &gScrVmGlob[inst].lastLine); + if ( gScrVmDebugPub[inst].func_table[builtinIndex].breakpointCount ) + { + if ( gScrVmPub[inst].top != localFs.top - 1 && !Assert_MyHandler("C:\\projects_pc\\cod\\codsrc\\src\\clientscript\\cscr_vm.cpp", 1611, 0, "%s", "gScrVmPub[inst].top == localFs.top - 1") ) + __debugbreak(); + v104 = gScrVmPub[inst].outparamcount; + Scr_HitBuiltinBreakpoint(inst, localFs.top, debugpos, localFs.localId, gOpcode[inst], builtinIndex, v104 + 1); + gScrVmPub[inst].outparamcount = v104; + gScrVmPub[inst].top = localFs.top - 1; + }*/ + + assert(builtinIndex >= 0); + assert(builtinIndex < 1024); + + ((void (__cdecl *)(game::scr_entref_t))game::gScrCompilePub[inst].func_table[builtinIndex])(entref); + + post_builtin(inst); + } + + bool OP_wait(game::scriptInstance_t inst) + { + game::function_stack_t localFs = game::gFs[inst]; + int waitTime; + game::VariableValue stackValue; + unsigned int id; + unsigned int stackId; + + assert(game::Scr_IsInOpcodeMemory(inst, localFs.pos)); + + if ( localFs.top->type == game::VAR_FLOAT ) + { + if (localFs.top->u.floatValue < 0.0f) + { + game::gFs[inst] = localFs; + game::Scr_Error("negative wait is not allowed", inst, false); + } + + waitTime = (int)(((inst != game::SCRIPTINSTANCE_SERVER ? 60 : 20) * localFs.top->u.floatValue) + 9.313225746154785e-10); + if ( !waitTime ) + { + waitTime = localFs.top->u.floatValue != 0.0; + } + } + else if ( localFs.top->type == game::VAR_INTEGER ) + { + waitTime = localFs.top->u.intValue * (inst != game::SCRIPTINSTANCE_SERVER ? 60 : 20); + } + else + { + game::gScrVarPub[inst].error_index = 2; + game::gFs[inst] = localFs; + waitTime = 0; + game::Scr_Error(game::va("type %s is not a float", game::var_typename[localFs.top->type]), inst, false); + } + + if ((unsigned int)waitTime >= 0xFFFFFF) + { + game::gScrVarPub[inst].error_index = 2; + if (waitTime >= 0) + { + game::gFs[inst] = localFs; + game::Scr_Error("wait is too long", inst, false); + } + + game::gFs[inst] = localFs; + game::Scr_Error("negative wait is not allowed", inst, false); + } + + if ( waitTime ) + { + game::Scr_ResetTimeout(inst); + } + + waitTime = (waitTime + game::gScrVarPub[inst].time) & 0xFFFFFF; + --localFs.top; + stackValue.type = game::VAR_STACK; + + game::gFs[inst] = localFs; + stackValue.u.stackValue = game::VM_ArchiveStack(inst); + localFs = game::gFs[inst]; + + id = game::GetArray(inst, game::GetVariable(inst, game::gScrVarPub[inst].timeArrayId, waitTime)); + + stackId = game::GetNewObjectVariable(inst, localFs.localId, id); + game::SetNewVariableValue(inst, stackId, &stackValue); + game::Scr_SetThreadWaitTime(inst, localFs.localId, waitTime); + + localFs.startTop[1].type = game::VAR_UNDEFINED; + if ( game::gThreadCount[inst] ) + { + --game::gThreadCount[inst]; + game::RemoveRefToObject(localFs.localId, inst); + localFs = game::gScrVmPub[inst].function_frame->fs; + localFs.top->type = (game::VariableType)game::gScrVmPub[inst].function_frame->topType; + ++localFs.top; + + game::gFs[inst] = localFs; + return true; + } + + assert(game::g_script_error_level[inst] >= 0); + --game::g_script_error_level[inst]; + game::gFs[inst] = localFs; + return false; + } + + bool OP_waittillFrameEnd(game::scriptInstance_t inst) + { + game::function_stack_t localFs = game::gFs[inst]; + game::VariableValue stackValue; + unsigned int id; + unsigned int stackId; + + assert(game::Scr_IsInOpcodeMemory(inst, localFs.pos)); + assert((game::gScrVarPub[inst].time & VAR_NAME_LOW_MASK) == 0); + + stackValue.type = game::VAR_STACK; + + game::gFs[inst] = localFs; + stackValue.u.stackValue = game::VM_ArchiveStack(inst); + localFs = game::gFs[inst]; + + id = game::GetArray(inst, game::GetVariable(inst, game::gScrVarPub[inst].timeArrayId, game::gScrVarPub[inst].time)); + + stackId = game::GetNewObjectVariableReverse(inst, id, localFs.localId); + + game::SetNewVariableValue(inst, stackId, &stackValue); + game::Scr_SetThreadWaitTime(inst, localFs.localId, game::gScrVarPub[inst].time); + + localFs.startTop[1].type = game::VAR_UNDEFINED; + if ( game::gThreadCount[inst] ) + { + --game::gThreadCount[inst]; + game::RemoveRefToObject(localFs.localId, inst); + localFs = game::gScrVmPub[inst].function_frame->fs; + localFs.top->type = (game::VariableType)game::gScrVmPub[inst].function_frame->topType; + ++localFs.top; + + game::gFs[inst] = localFs; + return true; + } + + assert(game::g_script_error_level[inst] >= 0); + --game::g_script_error_level[inst]; + + game::gFs[inst] = localFs; + return false; + } + + void OP_PreScriptCall(game::scriptInstance_t inst, bool) + { + assert(game::gFs[inst].top >= game::gScrVmPub[inst].stack); + assert(&game::gFs[inst].top[1] <= game::gScrVmPub[inst].maxstack); + + game::gFs[inst].top[1].type = game::VAR_PRECODEPOS; + ++game::gFs[inst].top; + } + + void function_call(game::scriptInstance_t inst) + { + game::gScrVmPub[inst].function_frame->fs.localVarCount = game::gFs[inst].localVarCount; + game::gFs[inst].localVarCount = 0; + ++game::gScrVmPub[inst].function_count; + ++game::gScrVmPub[inst].function_frame; + game::gScrVmPub[inst].function_frame->fs.localId = game::gFs[inst].localId; + + assert(game::gFs[inst].pos); + + // replace func + } + + void OP_ScriptFunctionCall(game::scriptInstance_t inst) + { + unsigned int selfId; + + if ( game::gScrVmPub[inst].function_count >= 31 ) + { + game::Scr_Error("script stack overflow (too many embedded function calls)", inst, false); + } + + selfId = game::Scr_GetSelf(inst, game::gFs[inst].localId); + game::AddRefToObject(inst, selfId); + + game::gFs[inst].localId = game::AllocChildThread(inst, game::gFs[inst].localId, selfId); + game::gScrVmPub[inst].function_frame->fs.pos = game::gFs[inst].pos; + game::gFs[inst].pos = game::Scr_ReadCodePos(inst, &game::gScrVmPub[inst].function_frame->fs.pos); + + function_call(inst); + } + + void OP_ScriptFunctionCall2(game::scriptInstance_t inst) + { + assert(game::gFs[inst].top >= game::gScrVmPub[inst].stack); + assert(&game::gFs[inst].top[1] <= game::gScrVmPub[inst].maxstack); + + game::gFs[inst].top[1].type = game::VAR_PRECODEPOS; + ++game::gFs[inst].top; + + OP_ScriptFunctionCall(inst); + } + + void OP_ScriptFunctionCallPointer(game::scriptInstance_t inst) + { + unsigned int selfId; + + if (game::gFs[inst].top->type != game::VAR_FUNCTION) + { + game::Scr_Error(game::va("%s is not a function pointer", game::var_typename[game::gFs[inst].top->type]), inst, false); + } + + if (game::gScrVmPub[inst].function_count >= 31) + { + game::gScrVarPub[inst].error_index = 1; + game::Scr_Error("script stack overflow (too many embedded function calls)", inst, false); + } + + selfId = game::Scr_GetSelf(inst, game::gFs[inst].localId); + + game::AddRefToObject(inst, selfId); + game::gFs[inst].localId = game::AllocChildThread(inst, game::gFs[inst].localId, selfId); + game::gScrVmPub[inst].function_frame->fs.pos = game::gFs[inst].pos; + game::gFs[inst].pos = game::gFs[inst].top->u.codePosValue; + --game::gFs[inst].top; + + function_call(inst); + } + + void OP_ScriptMethodCall(game::scriptInstance_t inst) + { + game::VariableType type; + + if (game::gFs[inst].top->type != game::VAR_POINTER) + { + type = game::gFs[inst].top->type; + game::gScrVarPub[inst].error_index = 1; + game::Scr_Error(game::va("%s is not an object", game::var_typename[type]), inst, false); + } + + if (game::gScrVmPub[inst].function_count >= 31) + { + game::Scr_Error("script stack overflow (too many embedded function calls)", inst, false); + } + + game::gFs[inst].localId = game::AllocChildThread(inst, game::gFs[inst].localId, game::gFs[inst].top->u.pointerValue); + --game::gFs[inst].top; + game::gScrVmPub[inst].function_frame->fs.pos = game::gFs[inst].pos; + game::gFs[inst].pos = game::Scr_ReadCodePos(inst, &game::gScrVmPub[inst].function_frame->fs.pos); + + function_call(inst); + } + + void OP_ScriptMethodCallPointer(game::scriptInstance_t inst) + { + const char* tempCodePos; + game::VariableType type; + + if (game::gFs[inst].top->type != game::VAR_FUNCTION) + { + game::RemoveRefToValue(inst, game::gFs[inst].top--); + game::Scr_Error(game::va("%s is not a function pointer", game::var_typename[game::gFs[inst].top[1].type]), inst, false); + } + + tempCodePos = game::gFs[inst].top->u.codePosValue; + --game::gFs[inst].top; + + if (game::gFs[inst].top->type != game::VAR_POINTER) + { + type = game::gFs[inst].top->type; + game::gScrVarPub[inst].error_index = 2; + game::Scr_Error(game::va("%s is not an object", game::var_typename[type]), inst, false); + } + + if (game::gScrVmPub[inst].function_count >= 31) + { + game::gScrVarPub[inst].error_index = 1; + game::Scr_Error("script stack overflow (too many embedded function calls)", inst, false); + } + + game::gFs[inst].localId = game::AllocChildThread(inst, game::gFs[inst].localId, game::gFs[inst].top->u.pointerValue); + --game::gFs[inst].top; + game::gScrVmPub[inst].function_frame->fs.pos = game::gFs[inst].pos; + game::gFs[inst].pos = tempCodePos; + + function_call(inst); + } + + void thread_call(game::scriptInstance_t inst) + { + game::gScrVmPub[inst].function_frame->fs.top = game::gFs[inst].startTop; + game::gScrVmPub[inst].function_frame->topType = game::gFs[inst].startTop->type; + game::gFs[inst].startTop->type = game::VAR_PRECODEPOS; + + ++game::gThreadCount[inst]; + + function_call(inst); + } + + void OP_ScriptThreadCall(game::scriptInstance_t inst) + { + unsigned int selfId; + int num; + + if ( game::gScrVmPub[inst].function_count >= 31 ) + { + game::gScrVarPub[inst].error_index = 1; + game::Scr_Error("script stack overflow (too many embedded function calls)", inst, false); + } + + selfId = game::Scr_GetSelf(inst, game::gFs[inst].localId); + game::AddRefToObject(inst, selfId); + game::gFs[inst].localId = game::AllocThread(inst, selfId); + game::gScrVmPub[inst].function_frame->fs.pos = game::gFs[inst].pos; + game::gScrVmPub[inst].function_frame->fs.startTop = game::gFs[inst].startTop; + game::gFs[inst].pos = game::Scr_ReadCodePos(inst, &game::gScrVmPub[inst].function_frame->fs.pos); + + num = game::Scr_ReadUnsignedInt(inst, &game::gScrVmPub[inst].function_frame->fs.pos); + game::gFs[inst].startTop = &game::gFs[inst].top[-num]; + + thread_call(inst); + } + + void OP_ScriptThreadCallPointer(game::scriptInstance_t inst) + { + unsigned int selfId; + const char* tempCodePos; + int num; + + if (game::gFs[inst].top->type != game::VAR_FUNCTION) + { + game::Scr_Error(game::va("%s is not a function pointer", game::var_typename[game::gFs[inst].top->type]), inst, false); + } + + if (game::gScrVmPub[inst].function_count >= 31) + { + game::gScrVarPub[inst].error_index = 1; + game::Scr_Error("script stack overflow (too many embedded function calls)", inst, false); + } + + tempCodePos = game::gFs[inst].top->u.codePosValue; + --game::gFs[inst].top; + selfId = game::Scr_GetSelf(inst, game::gFs[inst].localId); + + game::AddRefToObject(inst, selfId); + game::gFs[inst].localId = game::AllocThread(inst, selfId); + game::gScrVmPub[inst].function_frame->fs.pos = game::gFs[inst].pos; + game::gScrVmPub[inst].function_frame->fs.startTop = game::gFs[inst].startTop; + game::gFs[inst].pos = tempCodePos; + + num = game::Scr_ReadUnsignedInt(inst, &game::gScrVmPub[inst].function_frame->fs.pos); + game::gFs[inst].startTop = &game::gFs[inst].top[-num]; + + thread_call(inst); + } + + void OP_ScriptMethodThreadCall(game::scriptInstance_t inst) + { + game::VariableType type; + int num; + + if (game::gFs[inst].top->type != game::VAR_POINTER) + { + type = game::gFs[inst].top->type; + game::gScrVarPub[inst].error_index = 2; + game::Scr_Error(game::va("%s is not an object", game::var_typename[type]), inst, false); + } + + if (game::gScrVmPub[inst].function_count >= 31) + { + game::gScrVarPub[inst].error_index = 1; + game::Scr_Error("script stack overflow (too many embedded function calls)", inst, false); + } + + game::gFs[inst].localId = game::AllocThread(inst, game::gFs[inst].top->u.pointerValue); + --game::gFs[inst].top; + game::gScrVmPub[inst].function_frame->fs.pos = game::gFs[inst].pos; + game::gScrVmPub[inst].function_frame->fs.startTop = game::gFs[inst].startTop; + game::gFs[inst].pos = game::Scr_ReadCodePos(inst, &game::gScrVmPub[inst].function_frame->fs.pos); + + num = game::Scr_ReadUnsignedInt(inst, &game::gScrVmPub[inst].function_frame->fs.pos); + game::gFs[inst].startTop = &game::gFs[inst].top[-num]; + + thread_call(inst); + } + + void OP_ScriptMethodThreadCallPointer(game::scriptInstance_t inst) + { + const char* tempCodePos; + game::VariableType type; + int num; + + if (game::gFs[inst].top->type != game::VAR_FUNCTION) + { + game::RemoveRefToValue(inst, game::gFs[inst].top--); + game::Scr_Error(game::va("%s is not a function pointer", game::var_typename[game::gFs[inst].top[1].type]), inst, false); + } + + tempCodePos = game::gFs[inst].top->u.codePosValue; + --game::gFs[inst].top; + + if (game::gFs[inst].top->type != game::VAR_POINTER) + { + type = game::gFs[inst].top->type; + game::gScrVarPub[inst].error_index = 2; + game::Scr_Error(game::va("%s is not an object", game::var_typename[type]), inst, false); + } + + if (game::gScrVmPub[inst].function_count >= 31) + { + game::gScrVarPub[inst].error_index = 1; + game::Scr_Error("script stack overflow (too many embedded function calls)", inst, false); + } + + game::gFs[inst].localId = game::AllocThread(inst, game::gFs[inst].top->u.pointerValue); + --game::gFs[inst].top; + game::gScrVmPub[inst].function_frame->fs.pos = game::gFs[inst].pos; + game::gScrVmPub[inst].function_frame->fs.startTop = game::gFs[inst].startTop; + game::gFs[inst].pos = tempCodePos; + + num = game::Scr_ReadUnsignedInt(inst, &game::gScrVmPub[inst].function_frame->fs.pos); + game::gFs[inst].startTop = &game::gFs[inst].top[-num]; + + thread_call(inst); + } + + void OP_DecTop(game::scriptInstance_t inst) + { + game::RemoveRefToValue(inst, game::gFs[inst].top); + game::gFs[inst].top--; + } + + void OP_CastFieldObject(game::scriptInstance_t inst, unsigned int* objectId) + { + *objectId = game::Scr_EvalFieldObject(game::gFs[inst].top, inst, game::gScrVarPub[inst].tempVariable).pointerValue; + game::gFs[inst].top--; + } + + void OP_EvalLocalVariableObjectCached(game::scriptInstance_t inst, unsigned int* objectId) + { + *objectId = game::Scr_EvalVariableObject(inst, game::Scr_GetLocalVar(inst, *game::gFs[inst].pos)); + // error recovery handler will inc the pos + game::Scr_ReadUnsignedByte(inst, &game::gFs[inst].pos); + } + + void OP_CastBool(game::scriptInstance_t inst) + { + game::Scr_CastBool(inst, game::gFs[inst].top); + } + + void OP_BoolNot(game::scriptInstance_t inst) + { + game::Scr_EvalBoolNot(inst, game::gFs[inst].top); + } + + void OP_BoolComplement(game::scriptInstance_t inst) + { + game::Scr_EvalBoolComplement(inst, game::gFs[inst].top); + } + + void OP_JumpOnFalse(game::scriptInstance_t inst) + { + unsigned short jumpOffset; + + game::Scr_CastBool(inst, game::gFs[inst].top); + + assert(game::gFs[inst].top->type == game::VAR_INTEGER); + + jumpOffset = game::Scr_ReadUnsignedShort(inst, &game::gFs[inst].pos); + + if ( !game::gFs[inst].top->u.intValue ) + { + game::gFs[inst].pos += jumpOffset; + } + + game::gFs[inst].top--; + } + + void OP_JumpOnTrue(game::scriptInstance_t inst) + { + unsigned short jumpOffset; + + game::Scr_CastBool(inst, game::gFs[inst].top); + + assert(game::gFs[inst].top->type == game::VAR_INTEGER); + + jumpOffset = game::Scr_ReadUnsignedShort(inst, &game::gFs[inst].pos); + + if ( game::gFs[inst].top->u.intValue ) + { + game::gFs[inst].pos += jumpOffset; + } + + game::gFs[inst].top--; + } + + void OP_JumpOnFalseExpr(game::scriptInstance_t inst) + { + unsigned short jumpOffset; + + game::Scr_CastBool(inst, game::gFs[inst].top); + assert(game::gFs[inst].top->type == game::VAR_INTEGER); + + jumpOffset = game::Scr_ReadUnsignedShort(inst, &game::gFs[inst].pos); + + if ( !game::gFs[inst].top->u.intValue ) + { + game::gFs[inst].pos += jumpOffset; + return; + } + + --game::gFs[inst].top; + } + + void OP_JumpOnTrueExpr(game::scriptInstance_t inst) + { + unsigned short jumpOffset; + + game::Scr_CastBool(inst, game::gFs[inst].top); + assert(game::gFs[inst].top->type == game::VAR_INTEGER); + + jumpOffset = game::Scr_ReadUnsignedShort(inst, &game::gFs[inst].pos); + + if ( game::gFs[inst].top->u.intValue ) + { + game::gFs[inst].pos += jumpOffset; + return; + } + + --game::gFs[inst].top; + } + + void OP_jump(game::scriptInstance_t inst) + { + int jumpOffset; + jumpOffset = game::Scr_ReadUnsignedInt(inst, &game::gFs[inst].pos); + game::gFs[inst].pos += jumpOffset; + } + + bool OP_jumpback(game::scriptInstance_t inst) + { + unsigned int parentLocalId; + unsigned short jumpOffset; + + /*if (gScrVarPub[inst].numScriptValues > 0x3F37E || gScrVarPub[inst].numScriptObjects > 0x737E) + { + if ( gScrVmPub[inst].showError ) + { + Scr_DumpScriptThreads(inst); + Scr_DumpScriptVariablesDefault(inst); + gFs[inst] = localFs; + Scr_Error(inst, "exceeded maximum number of script variables", 0); + } + Sys_Error("exceeded maximum number of script variables"); + }*/ + + if ((game::Sys_Milliseconds() - game::gScrVmGlob[inst].starttime) >= 2500) + { + /*if (!logScriptTimes && !Assert_MyHandler("C:\\projects_pc\\cod\\codsrc\\src\\clientscript\\cscr_vm.cpp", 2013, 0, "%s", "logScriptTimes")) + __debugbreak(); + if (logScriptTimes->current.enabled) + { + v28 = Sys_Milliseconds(); + Com_Printf(game::CON_CHANNEL_PARSERSCRIPT, "EXCEED TIME: %d\n", v28); + }*/ + + if (!game::gScrVmGlob[inst].loading) + { + /*if (always_false()) + { + Com_PrintWarning(game::CON_CHANNEL_PARSERSCRIPT, "script runtime warning: potential infinite loop in script.\n"); + Scr_PrintPrevCodePos(inst, 24, localFs.pos, 0); + jumpOffset = Scr_ReadUnsignedShort(&localFs.pos); + localFs.pos -= jumpOffset; + Scr_ResetTimeout(inst); + } + VM_PrintJumpHistory(inst); + if (gScrVmPub[inst].showError) + { + if (gScrVmPub[inst].debugCode && !Assert_MyHandler("C:\\projects_pc\\cod\\codsrc\\src\\clientscript\\cscr_vm.cpp", 2046, 0, "%s", "!gScrVmPub[inst].debugCode")) + __debugbreak(); + Scr_DumpScriptThreads(inst); + Scr_DumpScriptVariablesDefault(inst); + gFs[inst] = localFs; + Scr_Error(inst, "potential infinite loop in script", 0); + }*/ + + if (!game::gScrVmPub[inst].abort_on_error) + { + // t5 added this extra string + const char* side = inst == game::SCRIPTINSTANCE_CLIENT ? "client" : "server"; + + game::Com_PrintError(game::CON_CHANNEL_PARSERSCRIPT, "%s script runtime error: potential infinite loop in script - killing thread.\n", side); + + game::Scr_PrintPrevCodePos(game::gFs[inst].pos, inst, game::CON_CHANNEL_PARSERSCRIPT, 0); + game::Scr_ResetTimeout(inst); + + while (1) + { + parentLocalId = game::GetSafeParentLocalId(inst, game::gFs[inst].localId); + game::Scr_KillThread(inst, game::gFs[inst].localId); + + game::gScrVmPub[inst].localVars -= game::gFs[inst].localVarCount; + assert(game::gFs[inst].top->type != game::VAR_PRECODEPOS); + + while (game::gFs[inst].top->type != game::VAR_CODEPOS) + { + game::RemoveRefToValue(inst, game::gFs[inst].top--); + assert(game::gFs[inst].top->type != game::VAR_PRECODEPOS); + } + + --game::gScrVmPub[inst].function_count; + --game::gScrVmPub[inst].function_frame; + if (!parentLocalId) + { + break; + } + + assert(game::gFs[inst].top != game::gFs[inst].startTop); + + game::RemoveRefToObject(game::gFs[inst].localId, inst); + + assert(game::gFs[inst].top->type == game::VAR_CODEPOS); + + game::gFs[inst].pos = game::gScrVmPub[inst].function_frame->fs.pos; + assert(game::gFs[inst].pos); + + game::gFs[inst].localVarCount = game::gScrVmPub[inst].function_frame->fs.localVarCount; + game::gFs[inst].localId = parentLocalId; + --game::gFs[inst].top; + } + + assert(game::gFs[inst].top == game::gFs[inst].startTop); + + game::gFs[inst].startTop[1].type = game::VAR_UNDEFINED; + if ( game::gThreadCount[inst] ) + { + --game::gThreadCount[inst]; + game::RemoveRefToObject(game::gFs[inst].localId, inst); + game::gFs[inst] = game::gScrVmPub[inst].function_frame->fs; + game::gFs[inst].top->type = (game::VariableType)game::gScrVmPub[inst].function_frame->topType; + ++game::gFs[inst].top; + return true; + } + + assert(game::g_script_error_level[inst] >= 0); + --game::g_script_error_level[inst]; + return false; + } + + // t5 is different here + // game::Scr_DumpScriptThreads(inst); + game::gScrVmPub[inst].terminal_error = 1; + game::Scr_ResetTimeout(inst); // fix the bug + game::Scr_Error("potential infinite loop in script", inst, false); + } + else + { + //if ( gScrVmPub[inst].abort_on_error ) + // gScrVmPub[inst].showError = 1; + game::Com_PrintWarning(game::CON_CHANNEL_PARSERSCRIPT, "script runtime warning: potential infinite loop in script.\n"); + game::Scr_PrintPrevCodePos(game::gFs[inst].pos, inst, game::CON_CHANNEL_PARSERSCRIPT, 0); + jumpOffset = game::Scr_ReadUnsignedShort(inst, &game::gFs[inst].pos); + game::gFs[inst].pos -= jumpOffset; + game::Scr_ResetTimeout(inst); + } + } + else + { + // gScrVmDebugPub[inst].jumpbackHistory[gScrVmDebugPub[inst].jumpbackHistoryIndex] = localFs.pos; + // gScrVmDebugPub[inst].jumpbackHistoryIndex = (gScrVmDebugPub[inst].jumpbackHistoryIndex + 1) % 0x80u; + jumpOffset = game::Scr_ReadUnsignedShort(inst, &game::gFs[inst].pos); + game::gFs[inst].pos -= jumpOffset; + } + + return true; + } + + void OP_inc(game::scriptInstance_t inst, unsigned int *fieldValueId) + { + assert(game::gFs[inst].top >= game::gScrVmPub[inst].stack); + assert(&game::gFs[inst].top[1] <= game::gScrVmPub[inst].maxstack); + + ++game::gFs[inst].top; + *game::gFs[inst].top = game::Scr_EvalVariableField(inst, *fieldValueId); + + if ( game::gFs[inst].top->type != game::VAR_INTEGER ) + { + game::Scr_Error(game::va("++ must be applied to an int (applied to %s)", game::var_typename[game::gFs[inst].top->type]), inst, false); + } + + ++game::gFs[inst].top->u.intValue; + assert(*game::gFs[inst].pos == game::OpcodeVM::OP_SetVariableField); + } + + void OP_dec(game::scriptInstance_t inst, unsigned int *fieldValueId) + { + assert(game::gFs[inst].top >= game::gScrVmPub[inst].stack); + assert(&game::gFs[inst].top[1] <= game::gScrVmPub[inst].maxstack); + + ++game::gFs[inst].top; + *game::gFs[inst].top = game::Scr_EvalVariableField(inst, *fieldValueId); + + if ( game::gFs[inst].top->type != game::VAR_INTEGER ) + { + game::Scr_Error(game::va("-- must be applied to an int (applied to %s)", game::var_typename[game::gFs[inst].top->type]), inst, false); + } + + --game::gFs[inst].top->u.intValue; + assert(*game::gFs[inst].pos == game::OpcodeVM::OP_SetVariableField); + } + + void OP_bit_or(game::scriptInstance_t inst) + { + game::Scr_EvalOr(game::gFs[inst].top - 1, game::gFs[inst].top, inst); + --game::gFs[inst].top; + } + + void OP_bit_ex_or(game::scriptInstance_t inst) + { + game::Scr_EvalExOr(game::gFs[inst].top - 1, game::gFs[inst].top, inst); + --game::gFs[inst].top; + } + + void OP_bit_and(game::scriptInstance_t inst) + { + game::Scr_EvalAnd(game::gFs[inst].top - 1, game::gFs[inst].top, inst); + --game::gFs[inst].top; + } + + void OP_equality(game::scriptInstance_t inst) + { + game::Scr_EvalEquality(game::gFs[inst].top - 1, inst, game::gFs[inst].top); + --game::gFs[inst].top; + } + + void OP_inequality(game::scriptInstance_t inst) + { + game::Scr_EvalInequality(inst, game::gFs[inst].top - 1, game::gFs[inst].top); + --game::gFs[inst].top; + } + + void OP_less(game::scriptInstance_t inst) + { + game::Scr_EvalLess(game::gFs[inst].top, game::gFs[inst].top - 1, inst); + --game::gFs[inst].top; + } + + void OP_greater(game::scriptInstance_t inst) + { + game::Scr_EvalGreater(game::gFs[inst].top, game::gFs[inst].top - 1, inst); + --game::gFs[inst].top; + } + + void OP_less_equal(game::scriptInstance_t inst) + { + game::Scr_EvalLessEqual(inst, game::gFs[inst].top - 1, game::gFs[inst].top); + --game::gFs[inst].top; + } + + void OP_greater_equal(game::scriptInstance_t inst) + { + game::Scr_EvalGreaterEqual(inst, game::gFs[inst].top - 1, game::gFs[inst].top); + --game::gFs[inst].top; + } + + void OP_shift_left(game::scriptInstance_t inst) + { + game::Scr_EvalShiftLeft(game::gFs[inst].top - 1, game::gFs[inst].top, inst); + --game::gFs[inst].top; + } + + void OP_shift_right(game::scriptInstance_t inst) + { + game::Scr_EvalShiftRight(game::gFs[inst].top - 1, game::gFs[inst].top, inst); + --game::gFs[inst].top; + } + + void OP_plus(game::scriptInstance_t inst) + { + game::Scr_EvalPlus(inst, game::gFs[inst].top - 1, game::gFs[inst].top); + --game::gFs[inst].top; + } + + void OP_minus(game::scriptInstance_t inst) + { + game::Scr_EvalMinus(game::gFs[inst].top, inst, game::gFs[inst].top - 1); + --game::gFs[inst].top; + } + + void OP_multiply(game::scriptInstance_t inst) + { + game::Scr_EvalMultiply(game::gFs[inst].top, inst, game::gFs[inst].top - 1); + --game::gFs[inst].top; + } + + void OP_divide(game::scriptInstance_t inst) + { + game::Scr_EvalDivide(game::gFs[inst].top, inst, game::gFs[inst].top - 1); + --game::gFs[inst].top; + } + + void OP_mod(game::scriptInstance_t inst) + { + game::Scr_EvalMod(inst, game::gFs[inst].top - 1, game::gFs[inst].top); + --game::gFs[inst].top; + } + + void OP_size(game::scriptInstance_t inst) + { + game::Scr_EvalSizeValue(inst, game::gFs[inst].top); + } + + bool OP_waittill(game::scriptInstance_t inst) + { + game::function_stack_t localFs = game::gFs[inst]; + game::VariableType type; + game::VariableValue tempValue; + unsigned int stringValue; + game::VariableValue stackValue; + unsigned int id; + unsigned int stackId; + + assert(game::Scr_IsInOpcodeMemory(inst, localFs.pos)); + + if (localFs.top->type != game::VAR_POINTER) + { + type = localFs.top->type; + game::gScrVarPub[inst].error_index = 2; + game::gFs[inst] = localFs; + game::Scr_Error(game::va("%s is not an object", game::var_typename[type]), inst, false); + } + + if (!game::IsFieldObject(inst, localFs.top->u.stringValue)) + { + type = game::GetObjectType(inst, localFs.top->u.stringValue); + game::gScrVarPub[inst].error_index = 2; + game::gFs[inst] = localFs; + game::Scr_Error(game::va("%s is not an object", game::var_typename[type]), inst, false); + } + + tempValue.u.intValue = localFs.top->u.intValue; + --localFs.top; + if ( localFs.top->type != game::VAR_STRING ) + { + ++localFs.top; + game::gScrVarPub[inst].error_index = 3; + game::gFs[inst] = localFs; + game::Scr_Error("first parameter of waittill must evaluate to a string", inst, false); + } + + stringValue = localFs.top->u.stringValue; + --localFs.top; + + assert(game::GetObjectType(inst, tempValue.u.stringValue) != game::VAR_THREAD); + assert(game::GetObjectType(inst, tempValue.u.stringValue) != game::VAR_NOTIFY_THREAD); + assert(game::GetObjectType(inst, tempValue.u.stringValue) != game::VAR_TIME_THREAD); + assert(game::GetObjectType(inst, tempValue.u.stringValue) != game::VAR_CHILD_THREAD); + assert(game::GetObjectType(inst, tempValue.u.stringValue) != game::VAR_DEAD_THREAD); + + stackValue.type = game::VAR_STACK; + + game::gFs[inst] = localFs; + stackValue.u.stackValue = game::VM_ArchiveStack(inst); + localFs = game::gFs[inst]; + + id = game::GetArray(inst, game::GetVariable(inst, game::GetArray(inst, game::GetVariable(inst, tempValue.u.stringValue, OBJECT_STACK)), stringValue)); + + stackId = game::GetNewObjectVariable(inst, localFs.localId, id); + + game::SetNewVariableValue(inst, stackId, &stackValue); + tempValue.type = game::VAR_POINTER; + + game::SetNewVariableValue(inst, game::GetNewObjectVariable(inst, localFs.localId, game::GetArray(inst, game::GetObjectVariable(game::Scr_GetSelf(inst, localFs.localId), inst, game::gScrVarPub[inst].pauseArrayId))), &tempValue); + + game::Scr_SetThreadNotifyName(inst, localFs.localId, stringValue); + + localFs.startTop[1].type = game::VAR_UNDEFINED; + if ( game::gThreadCount[inst] ) + { + --game::gThreadCount[inst]; + game::RemoveRefToObject(localFs.localId, inst); + localFs = game::gScrVmPub[inst].function_frame->fs; + localFs.top->type = (game::VariableType)game::gScrVmPub[inst].function_frame->topType; + ++localFs.top; + + game::gFs[inst] = localFs; + return true; + } + + assert(game::g_script_error_level[inst] >= 0); + + --game::g_script_error_level[inst]; + game::gFs[inst] = localFs; + return false; + } + + void OP_notify(game::scriptInstance_t inst) + { + game::function_stack_t localFs = game::gFs[inst]; + game::VariableType type; + unsigned int id; + unsigned int stringValue; + + if ( localFs.top->type != game::VAR_POINTER ) + { + type = localFs.top->type; + game::gScrVarPub[inst].error_index = 2; + game::gFs[inst] = localFs; + game::Scr_Error(game::va("%s is not an object", game::var_typename[type]), inst, false); + } + + id = localFs.top->u.stringValue; + if ( !game::IsFieldObject(inst, id) ) + { + type = game::GetObjectType(inst, localFs.top->u.stringValue); + game::gScrVarPub[inst].error_index = 2; + game::gFs[inst] = localFs; + game::Scr_Error(game::va("%s is not an object", game::var_typename[type]), inst, false); + } + + --localFs.top; + if ( localFs.top->type != game::VAR_STRING ) + { + ++localFs.top; + game::gScrVarPub[inst].error_index = 1; + game::gFs[inst] = localFs; + game::Scr_Error("first parameter of notify must evaluate to a string", inst, false); + } + + stringValue = localFs.top->u.stringValue; + --localFs.top; + + // if ( gScrVmDebugPub[inst].checkBreakon ) + // Scr_CheckBreakonNotify(inst, id, stringValue, localFs.top, localFs.pos, localFs.localId); + + game::gScrVmPub[inst].function_frame->fs.pos = localFs.pos; + game::VM_Notify(inst, id, stringValue, localFs.top); + localFs.pos = game::gScrVmPub[inst].function_frame->fs.pos; + + game::RemoveRefToObject(id, inst); + game::SL_RemoveRefToString(stringValue, inst); + + assert(localFs.top->type != game::VAR_CODEPOS); + + while ( localFs.top->type != game::VAR_PRECODEPOS ) + { + game::RemoveRefToValue(inst, localFs.top--); + assert(localFs.top->type != game::VAR_CODEPOS); + } + + --localFs.top; + game::gFs[inst] = localFs; + } + + void OP_endon(game::scriptInstance_t inst) + { + game::function_stack_t localFs = game::gFs[inst]; + game::VariableType type; + game::VariableValue tempValue; + unsigned int stringValue; + unsigned int threadId; + + if ( localFs.top->type != game::VAR_POINTER ) + { + type = localFs.top->type; + game::gScrVarPub[inst].error_index = 1; + game::gFs[inst] = localFs; + game::Scr_Error(game::va("%s is not an object", game::var_typename[type]), inst, false); + } + + if ( !game::IsFieldObject(inst, localFs.top->u.stringValue) ) + { + type = game::GetObjectType(inst, localFs.top->u.stringValue); + game::gScrVarPub[inst].error_index = 1; + game::gFs[inst] = localFs; + game::Scr_Error(game::va("%s is not an object", game::var_typename[type]), inst, false); + } + + if ( localFs.top[-1].type != game::VAR_STRING ) + { + game::gFs[inst] = localFs; + game::Scr_Error("first parameter of endon must evaluate to a string", inst, false); + } + stringValue = localFs.top[-1].u.stringValue; + game::AddRefToObject(inst, localFs.localId); + threadId = game::AllocThread(inst, localFs.localId); + + assert(game::GetObjectType(inst, localFs.top->u.stringValue) != game::VAR_THREAD); + assert(game::GetObjectType(inst, localFs.top->u.stringValue) != game::VAR_NOTIFY_THREAD); + assert(game::GetObjectType(inst, localFs.top->u.stringValue) != game::VAR_TIME_THREAD); + assert(game::GetObjectType(inst, localFs.top->u.stringValue) != game::VAR_CHILD_THREAD); + assert(game::GetObjectType(inst, localFs.top->u.stringValue) != game::VAR_DEAD_THREAD); + + game::GetObjectVariable(threadId, inst, game::GetArray(inst, game::GetVariable(inst, game::GetArray(inst, game::GetVariable(inst, localFs.top->u.stringValue, OBJECT_STACK)), stringValue))); + game::RemoveRefToObject(threadId, inst); + + tempValue.type = game::VAR_POINTER; + tempValue.u.intValue = localFs.top->u.intValue; + + game::SetNewVariableValue(inst, game::GetNewObjectVariable(inst, threadId, game::GetArray(inst, game::GetObjectVariable(localFs.localId, inst, game::gScrVarPub[inst].pauseArrayId))), &tempValue); + game::Scr_SetThreadNotifyName(inst, threadId, stringValue); + + localFs.top -= 2; + game::gFs[inst] = localFs; + } + + void OP_switch(game::scriptInstance_t inst) + { + game::function_stack_t localFs = game::gFs[inst]; + int jumpOffset; + unsigned int caseValue; + unsigned int currentCaseValue; + const char* currentCodePos; + + jumpOffset = game::Scr_ReadUnsignedInt(inst, &localFs.pos); + localFs.pos += jumpOffset; + + game::gCaseCount[inst] = game::Scr_ReadUnsignedShort(inst, &localFs.pos); + + if ( localFs.top->type == game::VAR_STRING ) + { + caseValue = localFs.top->u.stringValue; + game::SL_RemoveRefToString(localFs.top->u.stringValue, inst); + } + else + { + if ( localFs.top->type != game::VAR_INTEGER ) + { + game::gFs[inst] = localFs; + game::Scr_Error(game::va("cannot switch on %s", game::var_typename[localFs.top->type]), inst, false); + } + + if ( !game::IsValidArrayIndex(inst, localFs.top->u.stringValue) ) + { + game::gFs[inst] = localFs; + game::Scr_Error(game::va("switch index %d out of range", localFs.top->u.intValue), inst, false); + } + + caseValue = game::GetInternalVariableIndex(inst, localFs.top->u.stringValue); + } + if (!game::gCaseCount[inst]) + { + localFs.top--; + game::gFs[inst] = localFs; + return; + } + + assert(caseValue); + + do + { + currentCaseValue = game::Scr_ReadUnsignedInt(inst, &localFs.pos); + currentCodePos = game::Scr_ReadCodePos(inst, &localFs.pos); + if ( currentCaseValue == caseValue ) + { + localFs.pos = currentCodePos; + assert(currentCodePos); + + localFs.top--; + game::gFs[inst] = localFs; + return; + } + + --game::gCaseCount[inst]; + } + while ( game::gCaseCount[inst] ); + + if ( !currentCaseValue ) + { + localFs.pos = currentCodePos; + assert(currentCodePos); + } + + localFs.top--; + game::gFs[inst] = localFs; + } + + void OP_endswitch(game::scriptInstance_t inst) + { + game::gCaseCount[inst] = game::Scr_ReadUnsignedShort(inst, &game::gFs[inst].pos); + game::Scr_ReadData(inst, &game::gFs[inst].pos, 2 * game::gCaseCount[inst]); + } + + void OP_vector(game::scriptInstance_t inst) + { + game::gFs[inst].top -= 2; + game::Scr_CastVector(inst, game::gFs[inst].top); + } + + void OP_NOP([[maybe_unused]] game::scriptInstance_t inst) + { + } + + void OP_abort(game::scriptInstance_t inst) + { + assert(game::g_script_error_level[inst] >= 0); + --game::g_script_error_level[inst]; + } + + void OP_object([[maybe_unused]] game::scriptInstance_t inst) + { + /*if (localFs.top < gScrVmPub[inst].stack && !Assert_MyHandler("C:\\projects_pc\\cod\\codsrc\\src\\clientscript\\cscr_vm.cpp", 2397, 0, "%s", "localFs.top >= gScrVmPub[inst].stack")) + __debugbreak(); + if ( localFs.top > gScrVmPub[inst].maxstack && !Assert_MyHandler("C:\\projects_pc\\cod\\codsrc\\src\\clientscript\\cscr_vm.cpp", 2398, 0, "%s", "localFs.top <= gScrVmPub[inst].maxstack") ) + __debugbreak(); + classnum = R_ReadPrimDrawSurfInt((GfxReadCmdBuf *)&localFs); + entnum = R_ReadPrimDrawSurfInt((GfxReadCmdBuf *)&localFs); + v38.intValue = FindEntityId(inst, entnum, classnum, 0); + localFs.top[1].u = v38; + if ( !localFs.top[1].u.intValue ) + { + localFs.top[1].type = game::VAR_UNDEFINED; + ++localFs.top; + gFs[inst] = localFs; + Scr_Error(inst, "unknown object", 0); + } + ++localFs.top; + goto object; + + ++game::gFs[inst].top; + v278 = game::gFs[inst].pos; + v279 = *(__int32 *)v278; + v280 = v278 + 4; // Scr_ReadUnsignedInt + game::gFs[inst].pos = v278 + 4; // Scr_ReadUnsignedInt + v281 = *((__int32 *)v278 + 1); + game::gFs[inst].pos = v280 + 4; + game::gFs[inst].top->u.intValue = game::FindEntityId(v279, v281, inst); + v282 = game::gFs[inst].top; + if ( !v282->u.intValue ) + { + v282->type = game::VAR_UNDEFINED; + game::Scr_Error("unknown object", inst, 0); + } + goto object;*/ + } + + void OP_thread_object([[maybe_unused]] game::scriptInstance_t inst) + { + /*if (localFs.top < gScrVmPub[inst].stack && !Assert_MyHandler("C:\\projects_pc\\cod\\codsrc\\src\\clientscript\\cscr_vm.cpp", 2422, 0, "%s", "localFs.top >= gScrVmPub[inst].stack")) + __debugbreak(); + if ( &localFs.top[1] > gScrVmPub[inst].maxstack && !Assert_MyHandler("C:\\projects_pc\\cod\\codsrc\\src\\clientscript\\cscr_vm.cpp", 2423, 0, "%s", "localFs.top+1 <= gScrVmPub[inst].maxstack") ) + __debugbreak(); + v39 = Scr_ReadUnsignedShort(&localFs.pos); + localFs.top[1].u.intValue = v39; + ++localFs.top; + object: + localFs.top->type = VAR_BEGIN_REF; + AddRefToObject(inst, localFs.top->u.stringValue); + + ++game::gFs[inst].top; + v283 = game::gFs[inst].pos; + v284 = *(__int16 *)v283; + game::gFs[inst].pos = v283 + 2; // Scr_ReadUnsignedShort + game::gFs[inst].top->u.intValue = v284; + object: + game::gFs[inst].top->type = VAR_BEGIN_REF; + v30.intValue = game::gFs[inst].top->u.intValue; + inc_ref_count_continue: + ++game::gScrVarGlob[inst].parentVariables[v30.intValue + 1].u.next;*/ + } + + void OP_EvalLocalVariable([[maybe_unused]] game::scriptInstance_t inst) + { + /*if (localFs.top < gScrVmPub[inst].stack && !Assert_MyHandler("C:\\projects_pc\\cod\\codsrc\\src\\clientscript\\cscr_vm.cpp", 2429, 0, "%s", "localFs.top >= gScrVmPub[inst].stack")) + __debugbreak(); + if ( &localFs.top[1] > gScrVmPub[inst].maxstack && !Assert_MyHandler("C:\\projects_pc\\cod\\codsrc\\src\\clientscript\\cscr_vm.cpp", 2430, 0, "%s", "localFs.top+1 <= gScrVmPub[inst].maxstack") ) + __debugbreak(); + v40 = Scr_ReadUnsignedShort(&localFs.pos); + v63 = FindVariable(inst, localFs.localId, v40); + v90 = Scr_EvalVariable(inst, v63); + localFs.top[1] = v90; + ++localFs.top; + + ++game::gFs[inst].top; + v285 = game::gFs[inst].pos; + v286 = *(__int16 *)v285; + game::gFs[inst].pos = v285 + 2; // Scr_ReadUnsignedShort + v287 = &game::gScrVarGlob[inst].childVariables[game::gScrVarGlob[inst].childVariables[game::FindVariableIndexInternal2( + inst, + v286, + (v286 + game::gFs[inst].localId) % 0xFFFD + + 1)].hash.id];// FindVariable FindVariableIndexInternal + v310.intValue = (int)v287->u.u.intValue; + v311 = v287->w.status & 0x1F; + game::AddRefToValue(inst, (game::VariableType)v311, v310);// Scr_EvalVariable + v288 = game::gFs[inst].top; + v288->u = v310; + v288->type = (game::VariableType)v311;*/ + } + + void OP_EvalLocalVariableRef([[maybe_unused]] game::scriptInstance_t inst) + { + /*fieldValueIndex = 0; + v41 = Scr_ReadUnsignedShort(&localFs.pos); + fieldValueId = FindVariable(inst, localFs.localId, v41); + if ( !fieldValueId ) + { + gFs[inst] = localFs; + Scr_Error(inst, "cannot create a new local variable in the debugger", 0); + } + + v289 = game::gFs[inst].pos; + v290 = *(__int16 *)v289; + game::gFs[inst].pos = v289 + 2; // Scr_ReadUnsignedShort + fieldValueIndex = 0; + v291 = game::FindVariableIndexInternal2(inst, v290, (v290 + game::gFs[inst].localId) % 0xFFFD + 1);// FindVariableIndexInternal + fieldValueId = game::gScrVarGlob[inst].childVariables[v291].hash.id;// FindVariable + if ( game::gScrVarGlob[inst].childVariables[v291].hash.id ) + { + continue; + } + game::Scr_Error("cannot create a new local variable in the debugger", inst, 0); + goto OP_prof_begin;*/ + } + + void OP_prof_begin(game::scriptInstance_t inst) + { + game::Scr_ReadUnsignedByte(inst, &game::gFs[inst].pos); + } + + void OP_prof_end(game::scriptInstance_t inst) + { + game::Scr_ReadUnsignedByte(inst, &game::gFs[inst].pos); + } + } + + // Completed + unsigned int VM_ExecuteInternal(game::scriptInstance_t inst) + { + unsigned int objectId; + unsigned int fieldValueId; + unsigned int fieldValueIndex; + + ++game::g_script_error_level[inst]; + while (true) + { + assert(game::g_script_error_level[inst] >= 0); + assert(game::g_script_error_level[inst] < 33); + assert(inst == 0 || inst == 1); + if (!setjmp(g_script_error[inst][game::g_script_error_level[inst]])) + { + break; + } + + switch ( game::gOpcode[inst] ) + { + case game::OP_EvalLocalArrayRefCached0: + case game::OP_EvalLocalArrayRefCached: + case game::OP_EvalArrayRef: + case game::OP_ClearArray: + case game::OP_EvalLocalVariableRef: + assert(game::gScrVarPub[inst].error_index >= -1); + + if ( game::gScrVarPub[inst].error_index < 0 ) + { + game::gScrVarPub[inst].error_index = 1; + } + + break; + + case game::OP_EvalSelfFieldVariable: + case game::OP_EvalFieldVariable: + case game::OP_ClearFieldVariable: + case game::OP_SetVariableField: + case game::OP_SetSelfFieldVariableField: + case game::OP_inc: + case game::OP_dec: + game::gScrVarPub[inst].error_index = 0; + break; + + case game::OP_CallBuiltin0: + case game::OP_CallBuiltin1: + case game::OP_CallBuiltin2: + case game::OP_CallBuiltin3: + case game::OP_CallBuiltin4: + case game::OP_CallBuiltin5: + case game::OP_CallBuiltin: + assert(game::gScrVarPub[inst].error_index >= 0); + + if ( game::gScrVarPub[inst].error_index > 0 ) + { + game::gScrVarPub[inst].error_index = game::gScrVmPub[inst].outparamcount + 1 - game::gScrVarPub[inst].error_index; + } + + break; + + case game::OP_CallBuiltinMethod0: + case game::OP_CallBuiltinMethod1: + case game::OP_CallBuiltinMethod2: + case game::OP_CallBuiltinMethod3: + case game::OP_CallBuiltinMethod4: + case game::OP_CallBuiltinMethod5: + case game::OP_CallBuiltinMethod: + assert(game::gScrVarPub[inst].error_index >= -1); + + if ( game::gScrVarPub[inst].error_index <= 0 ) + { + if ( game::gScrVarPub[inst].error_index < 0 ) + { + game::gScrVarPub[inst].error_index = 1; + } + } + else + { + game::gScrVarPub[inst].error_index = game::gScrVmPub[inst].outparamcount + 2 - game::gScrVarPub[inst].error_index; + } + + break; + + default: + break; + } + + game::RuntimeError( + inst, + game::gFs[inst].pos, + game::gScrVarPub[inst].error_index, + game::gScrVarPub[inst].error_message, + game::gScrVmGlob[inst].dialog_error_message); + + game::Scr_ClearErrorMessage(inst); + + switch ( game::gOpcode[inst] ) + { + case game::OP_EvalLocalArrayCached: + case game::OP_EvalArray: + game::RemoveRefToValue(inst, game::gFs[inst].top--); + game::RemoveRefToValue(inst, game::gFs[inst].top); + game::gFs[inst].top->type = game::VAR_UNDEFINED; + break; + + case game::OP_EvalLocalArrayRefCached0: + case game::OP_EvalLocalArrayRefCached: + case game::OP_EvalArrayRef: + case game::OP_EvalLocalVariableRef: + fieldValueIndex = 0; + fieldValueId = game::GetDummyFieldValue(inst); + game::RemoveRefToValue(inst, game::gFs[inst].top); + --game::gFs[inst].top; + break; + + case game::OP_ClearArray: + case game::OP_wait: + game::RemoveRefToValue(inst, game::gFs[inst].top); + --game::gFs[inst].top; + break; + + case game::OP_GetSelfObject: + objectId = game::GetDummyObject(inst); + break; + + case game::OP_EvalSelfFieldVariable: + case game::OP_EvalFieldVariable: + game::gFs[inst].top->type = game::VAR_UNDEFINED; + break; + + case game::OP_EvalSelfFieldVariableRef: + case game::OP_EvalFieldVariableRef: + fieldValueIndex = 0; + fieldValueId = game::GetDummyFieldValue(inst); + break; + + case game::OP_ClearFieldVariable: + if ( game::gScrVmPub[inst].outparamcount ) + { + assert(game::gScrVmPub[inst].outparamcount == 1); + assert(game::gScrVmPub[inst].top->type == game::VAR_UNDEFINED); + game::gScrVmPub[inst].outparamcount = 0; + } + + if ( game::gScrVmPub[inst].outparamcount ) + { + game::gScrVmPub[inst].outparamcount = 0; + } + + break; + + case game::OP_checkclearparams: + assert(game::gFs[inst].top->type != game::VAR_CODEPOS); + + while ( game::gFs[inst].top->type != game::VAR_PRECODEPOS ) + { + game::RemoveRefToValue(inst, game::gFs[inst].top--); + assert(game::gFs[inst].top->type != game::VAR_CODEPOS); + } + + game::gFs[inst].top->type = game::VAR_CODEPOS; + break; + + case game::OP_SetVariableField: + if ( game::gScrVmPub[inst].outparamcount ) + { + assert(game::gScrVmPub[inst].outparamcount == 1); + assert(game::gScrVmPub[inst].top == game::gFs[inst].top); + game::RemoveRefToValue(inst, game::gFs[inst].top); + game::gScrVmPub[inst].outparamcount = 0; + } + + --game::gFs[inst].top; + break; + + case game::OP_SetSelfFieldVariableField: + game::RemoveRefToValue(inst, game::gFs[inst].top); + game::gScrVmPub[inst].outparamcount = 0; + --game::gFs[inst].top; + break; + + case game::OP_CallBuiltin0: + case game::OP_CallBuiltin1: + case game::OP_CallBuiltin2: + case game::OP_CallBuiltin3: + case game::OP_CallBuiltin4: + case game::OP_CallBuiltin5: + case game::OP_CallBuiltin: + case game::OP_CallBuiltinMethod0: + case game::OP_CallBuiltinMethod1: + case game::OP_CallBuiltinMethod2: + case game::OP_CallBuiltinMethod3: + case game::OP_CallBuiltinMethod4: + case game::OP_CallBuiltinMethod5: + case game::OP_CallBuiltinMethod: + game::Scr_ClearOutParams(inst); + game::gFs[inst].top = game::gScrVmPub[inst].top + 1; + game::gFs[inst].top->type = game::VAR_UNDEFINED; + break; + + case game::OP_ScriptFunctionCall2: + case game::OP_ScriptFunctionCall: + case game::OP_ScriptMethodCall: + game::Scr_ReadCodePos(inst, &game::gFs[inst].pos); + [[fallthrough]]; + + case game::OP_ScriptFunctionCallPointer: + case game::OP_ScriptMethodCallPointer: + assert(game::gFs[inst].top->type != game::VAR_CODEPOS); + + while ( game::gFs[inst].top->type != game::VAR_PRECODEPOS ) + { + game::RemoveRefToValue(inst, game::gFs[inst].top); + --game::gFs[inst].top; + assert(game::gFs[inst].top->type != game::VAR_CODEPOS); + } + + game::gFs[inst].top->type = game::VAR_UNDEFINED; + break; + + case game::OP_ScriptThreadCall: + case game::OP_ScriptMethodThreadCall: + game::Scr_ReadCodePos(inst, &game::gFs[inst].pos); + [[fallthrough]]; + + case game::OP_ScriptThreadCallPointer: + case game::OP_ScriptMethodThreadCallPointer: + { + for (unsigned int paramcount = game::Scr_ReadUnsignedInt(inst, &game::gFs[inst].pos); + paramcount; + --paramcount) + { + game::RemoveRefToValue(inst, game::gFs[inst].top--); + } + ++game::gFs[inst].top; + game::gFs[inst].top->type = game::VAR_UNDEFINED; + break; + } + + case game::OP_CastFieldObject: + objectId = game::GetDummyObject(inst); + --game::gFs[inst].top; + break; + + case game::OP_EvalLocalVariableObjectCached: + game::Scr_ReadUnsignedByte(inst, &game::gFs[inst].pos); + objectId = game::GetDummyObject(inst); + break; + + case game::OP_JumpOnFalse: + case game::OP_JumpOnTrue: + case game::OP_JumpOnFalseExpr: + case game::OP_JumpOnTrueExpr: + game::Scr_ReadUnsignedShort(inst, &game::gFs[inst].pos); + --game::gFs[inst].top; + break; + + case game::OP_jumpback: + { + unsigned short jumpOffset = game::Scr_ReadUnsignedShort(inst, &game::gFs[inst].pos); + game::gFs[inst].pos -= jumpOffset; + break; + } + + case game::OP_bit_or: + case game::OP_bit_ex_or: + case game::OP_bit_and: + case game::OP_equality: + case game::OP_inequality: + case game::OP_less: + case game::OP_greater: + case game::OP_less_equal: + case game::OP_greater_equal: + case game::OP_shift_left: + case game::OP_shift_right: + case game::OP_plus: + case game::OP_minus: + case game::OP_multiply: + case game::OP_divide: + case game::OP_mod: + --game::gFs[inst].top; + break; + + case game::OP_waittillmatch: + game::Scr_ReadUnsignedByte(inst, &game::gFs[inst].pos); + [[fallthrough]]; + + case game::OP_waittill: + case game::OP_endon: + game::RemoveRefToValue(inst, game::gFs[inst].top); + --game::gFs[inst].top; + game::RemoveRefToValue(inst, game::gFs[inst].top); + --game::gFs[inst].top; + break; + + case game::OP_notify: + assert(game::gFs[inst].top->type != game::VAR_CODEPOS); + + while ( game::gFs[inst].top->type != game::VAR_PRECODEPOS ) + { + game::RemoveRefToValue(inst, game::gFs[inst].top--); + assert(game::gFs[inst].top->type != game::VAR_CODEPOS); + } + + game::RemoveRefToValue(inst, game::gFs[inst].top); + --game::gFs[inst].top; + break; + + case game::OP_switch: + { + if (game::gCaseCount[inst]) + { + int currentCaseValue; + const char* currentCodePos; + + do + { + currentCaseValue = game::Scr_ReadUnsignedInt(inst, &game::gFs[inst].pos); + currentCodePos = game::Scr_ReadCodePos(inst, &game::gFs[inst].pos); + --game::gCaseCount[inst]; + } while (game::gCaseCount[inst]); + + if (!currentCaseValue) + { + game::gFs[inst].pos = currentCodePos; + assert(currentCodePos); + } + } + + game::RemoveRefToValue(inst, game::gFs[inst].top); + --game::gFs[inst].top; + break; + } + + default: + break; + } + + continue; + } + + while ( true ) + { + game::gOpcode[inst] = (game::OpcodeVM)game::Scr_ReadUnsignedByte(inst, &game::gFs[inst].pos); + interrupt_return: + switch ( game::gOpcode[inst] ) + { + case game::OP_End: + if (VM::OP_End(inst)) + { + continue; + } + + return game::gFs[inst].localId; + + case game::OP_Return: + if (VM::OP_Return(inst)) + { + continue; + } + + return game::gFs[inst].localId; + + case game::OP_GetUndefined: + VM::OP_GetUndefined(inst); + continue; + + case game::OP_GetZero: + VM::OP_GetZero(inst); + continue; + + case game::OP_GetByte: + VM::OP_GetByte(inst); + continue; + + case game::OP_GetNegByte: + VM::OP_GetNegByte(inst); + continue; + + case game::OP_GetUnsignedShort: + VM::OP_GetUnsignedShort(inst); + continue; + + case game::OP_GetNegUnsignedShort: + VM::OP_GetNegUnsignedShort(inst); + continue; + + case game::OP_GetInteger: + VM::OP_GetInteger(inst); + continue; + + case game::OP_GetFloat: + VM::OP_GetFloat(inst); + continue; + + case game::OP_GetString: + VM::OP_GetString(inst); + continue; + + case game::OP_GetIString: + VM::OP_GetIString(inst); + continue; + + case game::OP_GetVector: + VM::OP_GetVector(inst); + continue; + + case game::OP_GetLevelObject: + VM::OP_GetLevelObject(inst, &objectId); + continue; + + case game::OP_GetAnimObject: + VM::OP_GetAnimObject(inst, &objectId); + continue; + + case game::OP_GetSelf: + VM::OP_GetSelf(inst); + continue; + + case game::OP_GetLevel: + VM::OP_GetLevel(inst); + continue; + + case game::OP_GetGame: + VM::OP_GetGame(inst); + continue; + + case game::OP_GetAnim: + VM::OP_GetAnim(inst); + continue; + + case game::OP_GetAnimation: + VM::OP_GetAnimation(inst); + continue; + + case game::OP_GetGameRef: + VM::OP_GetGameRef(inst, &fieldValueIndex, &fieldValueId); + continue; + + case game::OP_GetFunction: + VM::OP_GetFunction(inst); + continue; + + case game::OP_CreateLocalVariable: + VM::OP_CreateLocalVariable(inst); + continue; + + case game::OP_RemoveLocalVariables: + VM::OP_RemoveLocalVariables(inst); + continue; + + case game::OP_EvalLocalVariableCached0: + VM::OP_EvalLocalVariableCached(inst, 0); + continue; + + case game::OP_EvalLocalVariableCached1: + VM::OP_EvalLocalVariableCached(inst, 1); + continue; + + case game::OP_EvalLocalVariableCached2: + VM::OP_EvalLocalVariableCached(inst, 2); + continue; + + case game::OP_EvalLocalVariableCached3: + VM::OP_EvalLocalVariableCached(inst, 3); + continue; + + case game::OP_EvalLocalVariableCached4: + VM::OP_EvalLocalVariableCached(inst, 4); + continue; + + case game::OP_EvalLocalVariableCached5: + VM::OP_EvalLocalVariableCached(inst, 5); + continue; + + case game::OP_EvalLocalVariableCached: + VM::OP_EvalLocalVariableCached(inst, -1); + continue; + + case game::OP_EvalLocalArrayCached: + VM::OP_EvalLocalArrayCached(inst); + continue; + + case game::OP_EvalArray: + VM::OP_EvalArray(inst); + continue; + + case game::OP_EvalLocalArrayRefCached0: + VM::OP_EvalLocalArrayRefCached(inst, 0, &fieldValueId, &fieldValueIndex, &objectId); + continue; + + case game::OP_EvalLocalArrayRefCached: + VM::OP_EvalLocalArrayRefCached(inst, -1, &fieldValueId, &fieldValueIndex, &objectId); + continue; + + case game::OP_EvalArrayRef: + VM::OP_EvalArrayRef(inst, &fieldValueId, &fieldValueIndex, &objectId); + continue; + + case game::OP_ClearArray: + VM::OP_ClearArray(inst, &fieldValueId); + continue; + + case game::OP_EmptyArray: + VM::OP_EmptyArray(inst); + continue; + + case game::OP_GetSelfObject: + VM::OP_GetSelfObject(inst, &objectId); + continue; + + case game::OP_EvalLevelFieldVariable: + VM::OP_EvalLevelAnimFieldVariable(inst, true, &objectId); + continue; + + case game::OP_EvalAnimFieldVariable: + VM::OP_EvalLevelAnimFieldVariable(inst, false, &objectId); + continue; + + case game::OP_EvalSelfFieldVariable: + VM::OP_EvalSelfFieldVariable(inst, &objectId); + continue; + + case game::OP_EvalFieldVariable: + VM::OP_EvalFieldVariable(inst, &objectId); + continue; + + case game::OP_EvalLevelFieldVariableRef: + VM::OP_EvalLevelFieldVariableRef(inst, &objectId, &fieldValueIndex, &fieldValueId); + continue; + + case game::OP_EvalAnimFieldVariableRef: + VM::OP_EvalAnimFieldVariableRef(inst, &objectId, &fieldValueIndex, &fieldValueId); + continue; + + case game::OP_EvalSelfFieldVariableRef: + VM::OP_EvalSelfFieldVariableRef(inst, &objectId, &fieldValueIndex, &fieldValueId); + continue; + + case game::OP_EvalFieldVariableRef: + VM::OP_EvalFieldVariableRef(inst, &objectId, &fieldValueIndex, &fieldValueId); + continue; + + case game::OP_ClearFieldVariable: + VM::OP_ClearFieldVariable(inst, &objectId); + continue; + + case game::OP_SafeCreateVariableFieldCached: + VM::OP_SafeCreateVariableFieldCached(inst); + continue; + + case game::OP_SafeSetVariableFieldCached0: + VM::OP_SafeSetVariableFieldCached(inst, 0); + continue; + + case game::OP_SafeSetVariableFieldCached: + VM::OP_SafeSetVariableFieldCached(inst, -1); + continue; + + case game::OP_SafeSetWaittillVariableFieldCached: + VM::OP_SafeSetWaittillVariableFieldCached(inst); + continue; + + case game::OP_clearparams: + VM::OP_clearparams(inst); + continue; + + case game::OP_checkclearparams: + VM::OP_checkclearparams(inst); + continue; + + case game::OP_EvalLocalVariableRefCached0: + VM::OP_EvalLocalVariableRefCached(inst, 0, &fieldValueIndex, &fieldValueId); + continue; + + case game::OP_EvalLocalVariableRefCached: + VM::OP_EvalLocalVariableRefCached(inst, -1, &fieldValueIndex, &fieldValueId); + continue; + + case game::OP_SetLevelFieldVariableField: + VM::OP_SetLevelFieldVariableField(inst); + continue; + + case game::OP_SetVariableField: + VM::OP_SetVariableField(inst, &objectId, &fieldValueIndex, &fieldValueId); + continue; + + case game::OP_SetAnimFieldVariableField: + VM::OP_SetAnimFieldVariableField(inst); + continue; + + case game::OP_SetSelfFieldVariableField: + VM::OP_SetSelfFieldVariableField(inst, &objectId, &fieldValueIndex, &fieldValueId); + continue; + + case game::OP_SetLocalVariableFieldCached0: + VM::OP_SetLocalVariableFieldCached(inst, 0); + continue; + + case game::OP_SetLocalVariableFieldCached: + VM::OP_SetLocalVariableFieldCached(inst, -1); + continue; + + case game::OP_CallBuiltin0: + VM::OP_CallBuiltin(inst, 0); + continue; + + case game::OP_CallBuiltin1: + VM::OP_CallBuiltin(inst, 1); + continue; + case game::OP_CallBuiltin2: + + VM::OP_CallBuiltin(inst, 2); + continue; + + case game::OP_CallBuiltin3: + VM::OP_CallBuiltin(inst, 3); + continue; + + case game::OP_CallBuiltin4: + VM::OP_CallBuiltin(inst, 4); + continue; + + case game::OP_CallBuiltin5: + VM::OP_CallBuiltin(inst, 5); + continue; + + case game::OP_CallBuiltin: + VM::OP_CallBuiltin(inst, -1); + continue; + + case game::OP_CallBuiltinMethod0: + VM::OP_CallBuiltinMethod(inst, 0, &objectId); + continue; + + case game::OP_CallBuiltinMethod1: + VM::OP_CallBuiltinMethod(inst, 1, &objectId); + continue; + + case game::OP_CallBuiltinMethod2: + VM::OP_CallBuiltinMethod(inst, 2, &objectId); + continue; + + case game::OP_CallBuiltinMethod3: + VM::OP_CallBuiltinMethod(inst, 3, &objectId); + continue; + + case game::OP_CallBuiltinMethod4: + VM::OP_CallBuiltinMethod(inst, 4, &objectId); + continue; + + case game::OP_CallBuiltinMethod5: + VM::OP_CallBuiltinMethod(inst, 5, &objectId); + continue; + + case game::OP_CallBuiltinMethod: + VM::OP_CallBuiltinMethod(inst, -1, &objectId); + continue; + + case game::OP_wait: + if (VM::OP_wait(inst)) + { + continue; + } + + return game::gFs[inst].localId; + + case game::OP_waittillFrameEnd: + if (VM::OP_waittillFrameEnd(inst)) + { + continue; + } + + return game::gFs[inst].localId; + + case game::OP_PreScriptCall: + VM::OP_PreScriptCall(inst, true); + continue; + + case game::OP_voidCodepos: + VM::OP_PreScriptCall(inst, false); + continue; + + case game::OP_ScriptFunctionCall2: + VM::OP_ScriptFunctionCall2(inst); + continue; + + case game::OP_ScriptFunctionCall: + VM::OP_ScriptFunctionCall(inst); + continue; + + case game::OP_ScriptFunctionCallPointer: + VM::OP_ScriptFunctionCallPointer(inst); + continue; + + case game::OP_ScriptMethodCall: + VM::OP_ScriptMethodCall(inst); + continue; + + case game::OP_ScriptMethodCallPointer: + VM::OP_ScriptMethodCallPointer(inst); + continue; + + case game::OP_ScriptThreadCall: + VM::OP_ScriptThreadCall(inst); + continue; + + case game::OP_ScriptThreadCallPointer: + VM::OP_ScriptThreadCallPointer(inst); + continue; + + case game::OP_ScriptMethodThreadCall: + VM::OP_ScriptMethodThreadCall(inst); + continue; + + case game::OP_ScriptMethodThreadCallPointer: + VM::OP_ScriptMethodThreadCallPointer(inst); + continue; + + case game::OP_DecTop: + VM::OP_DecTop(inst); + continue; + + case game::OP_CastFieldObject: + VM::OP_CastFieldObject(inst, &objectId); + continue; + + case game::OP_EvalLocalVariableObjectCached: + VM::OP_EvalLocalVariableObjectCached(inst, &objectId); + continue; + + case game::OP_CastBool: + VM::OP_CastBool(inst); + continue; + + case game::OP_BoolNot: + VM::OP_BoolNot(inst); + continue; + + case game::OP_BoolComplement: + VM::OP_BoolComplement(inst); + continue; + + case game::OP_JumpOnFalse: + VM::OP_JumpOnFalse(inst); + continue; + + case game::OP_JumpOnTrue: + VM::OP_JumpOnTrue(inst); + continue; + + case game::OP_JumpOnFalseExpr: + VM::OP_JumpOnFalseExpr(inst); + continue; + + case game::OP_JumpOnTrueExpr: + VM::OP_JumpOnTrueExpr(inst); + continue; + + case game::OP_jump: + VM::OP_jump(inst); + continue; + + case game::OP_jumpback: + if (VM::OP_jumpback(inst)) + { + continue; + } + + return game::gFs[inst].localId; + + case game::OP_inc: + VM::OP_inc(inst, &fieldValueId); + continue; + + case game::OP_dec: + VM::OP_dec(inst, &fieldValueId); + continue; + + case game::OP_bit_or: + VM::OP_bit_or(inst); + continue; + + case game::OP_bit_ex_or: + VM::OP_bit_ex_or(inst); + continue; + + case game::OP_bit_and: + VM::OP_bit_and(inst); + continue; + + case game::OP_equality: + VM::OP_equality(inst); + continue; + + case game::OP_inequality: + VM::OP_inequality(inst); + continue; + + case game::OP_less: + VM::OP_less(inst); + continue; + + case game::OP_greater: + VM::OP_greater(inst); + continue; + + case game::OP_less_equal: + VM::OP_less_equal(inst); + continue; + + case game::OP_greater_equal: + VM::OP_greater_equal(inst); + continue; + + case game::OP_shift_left: + VM::OP_shift_left(inst); + continue; + + case game::OP_shift_right: + VM::OP_shift_right(inst); + continue; + + case game::OP_plus: + VM::OP_plus(inst); + continue; + + case game::OP_minus: + VM::OP_minus(inst); + continue; + + case game::OP_multiply: + VM::OP_multiply(inst); + continue; + + case game::OP_divide: + VM::OP_divide(inst); + continue; + + case game::OP_mod: + VM::OP_mod(inst); + continue; + + case game::OP_size: + VM::OP_size(inst); + continue; + + case game::OP_waittillmatch: + case game::OP_waittill: + if (VM::OP_waittill(inst)) + { + continue; + } + + return game::gFs[inst].localId; + + case game::OP_notify: + VM::OP_notify(inst); + continue; + + case game::OP_endon: + VM::OP_endon(inst); + continue; + + case game::OP_switch: + VM::OP_switch(inst); + continue; + + case game::OP_endswitch: + VM::OP_endswitch(inst); + continue; + + case game::OP_vector: + VM::OP_vector(inst); + continue; + + case game::OP_NOP: + VM::OP_NOP(inst); + continue; + + case game::OP_abort: + VM::OP_abort(inst); + return 0; + + case game::OP_object: + VM::OP_object(inst); + continue; + + case game::OP_thread_object: + VM::OP_thread_object(inst); + continue; + + case game::OP_EvalLocalVariable: + VM::OP_EvalLocalVariable(inst); + continue; + + case game::OP_EvalLocalVariableRef: + VM::OP_EvalLocalVariableRef(inst); + continue; + + case game::OP_prof_begin: + VM::OP_prof_begin(inst); + continue; + + case game::OP_prof_end: + VM::OP_prof_end(inst); + continue; + + case game::OP_breakpoint: + if ( !game::gScrVarPub[inst].developer ) + { + continue; + } + //game::gOpcode[inst] = Scr_HitBreakpoint(inst, localFs.top, localFs.pos, localFs.localId, 0); + goto interrupt_return; + + case game::OP_assignmentBreakpoint: + //game::gOpcode[inst] = Scr_HitAssignmentBreakpoint(inst, localFs.top, localFs.pos, localFs.localId, 0); + goto interrupt_return; + + case game::OP_manualAndAssignmentBreakpoint: + //game::gOpcode[inst] = Scr_HitAssignmentBreakpoint(inst, localFs.top, localFs.pos, localFs.localId, 1); + goto interrupt_return; + + default: + game::gScrVmPub[inst].terminal_error = 1; + game::RuntimeError(inst, game::gFs[inst].pos, 0, game::va("CODE ERROR: unknown opcode %d", game::gOpcode[inst]), nullptr); + continue; + } + } + } + + // Restored + void Scr_RemoveThreadNotifyName(game::scriptInstance_t inst, unsigned int startLocalId) + { + unsigned __int16 stringValue; + game::VariableValueInternal *entryValue; + + entryValue = &game::gScrVarGlob[inst].parentVariables[startLocalId + 1]; + + assert((entryValue->w.status & VAR_STAT_MASK) != VAR_STAT_FREE); + + assert((entryValue->w.type & VAR_MASK) == game::VAR_NOTIFY_THREAD); + + stringValue = game::Scr_GetThreadNotifyName(inst, startLocalId); + + assert(stringValue); + + game::SL_RemoveRefToString(stringValue, inst); + entryValue->w.status &= ~VAR_MASK; + entryValue->w.status |= game::VAR_THREAD; + } + + // Restored + unsigned int Scr_GetThreadNotifyName(game::scriptInstance_t inst, unsigned int startLocalId) + { + assert((game::gScrVarGlob[inst].parentVariables[startLocalId + 1].w.type & VAR_STAT_MASK) == VAR_STAT_EXTERNAL); + + assert((game::gScrVarGlob[inst].parentVariables[startLocalId + 1].w.type & VAR_MASK) == game::VAR_NOTIFY_THREAD); + + assert((game::gScrVarGlob[inst].parentVariables[startLocalId + 1].w.notifyName >> VAR_NAME_BIT_SHIFT) < VARIABLELIST_CHILD_SIZE); + + return game::gScrVarGlob[inst].parentVariables[startLocalId + 1].w.status >> VAR_NAME_BIT_SHIFT; + } + + // Restored + unsigned int GetArraySize(game::scriptInstance_t inst, unsigned int id) + { + game::VariableValueInternal *entryValue; + + assert(id); + + entryValue = &game::gScrVarGlob[inst].parentVariables[id + 1]; + + assert((entryValue->w.type & VAR_MASK) == game::VAR_ARRAY); + + return entryValue->u.o.u.entnum; + } + + // Completed + void VM_CancelNotifyInternal(game::scriptInstance_t inst, unsigned int notifyNameListId, unsigned int notifyListOwnerId, unsigned int startLocalId, unsigned int notifyListId, unsigned int stringValue) + { + assert(stringValue == game::Scr_GetThreadNotifyName(inst, startLocalId)); + + assert(notifyListId == game::FindObject(inst, game::FindVariable(OBJECT_NOTIFY_LIST, notifyListOwnerId, inst))); + + assert(notifyNameListId == game::FindObject(inst, game::FindVariable(stringValue, notifyListId, inst))); + + game::Scr_RemoveThreadNotifyName(inst, startLocalId); + game::RemoveObjectVariable(inst, notifyNameListId, startLocalId); + + if ( !game::GetArraySize(inst, notifyNameListId) ) + { + game::RemoveVariable(stringValue, notifyListId, inst); + if ( !game::GetArraySize(inst, notifyListId) ) + { + game::RemoveVariable(OBJECT_STACK, notifyListOwnerId, inst); + } + } + } + + // Completed + void VM_CancelNotify(game::scriptInstance_t inst, unsigned int notifyListOwnerId, unsigned int startLocalId) + { + unsigned int stringValue; + unsigned int notifyListId; + unsigned int notifyNameListId; + + notifyListId = game::FindObject(inst, game::FindVariable(OBJECT_STACK, notifyListOwnerId, inst)); + stringValue = game::Scr_GetThreadNotifyName(inst, startLocalId); + + assert(stringValue); + + notifyNameListId = game::FindObject(inst, game::FindVariable(stringValue, notifyListId, inst)); + game::VM_CancelNotifyInternal(inst, notifyNameListId, notifyListOwnerId, startLocalId, notifyListId, stringValue); + } + + // Restored + unsigned int GetParentLocalId(game::scriptInstance_t inst, unsigned int threadId) + { + 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_CHILD_THREAD); + + return game::gScrVarGlob[inst].parentVariables[threadId + 1].w.status >> VAR_NAME_BIT_SHIFT; + } + + // Completed + game::VariableStackBuffer *VM_ArchiveStack(game::scriptInstance_t inst) + { + game::VariableStackBuffer *stackValue; + game::VariableValue *top; + char *buf; + char *bufa; + unsigned int localId; + int size; + int bufLen; + game::function_stack_t* stack; + + stack = &game::gFs[inst]; + + top = stack->top; + size = top - stack->startTop; + + assert(size == (unsigned short)size); + + bufLen = 5 * size + 11; // t5 is 13? + + assert(bufLen == (unsigned short)bufLen); + + stackValue = (game::VariableStackBuffer *)game::MT_Alloc(bufLen, inst); + localId = stack->localId; + stackValue->localId = localId; + stackValue->size = size; + stackValue->bufLen = bufLen; + stackValue->pos = (char*)stack->pos; + stackValue->time = game::gScrVarPub[inst].time; + game::gScrVmPub[inst].localVars -= stack->localVarCount; + buf = &stackValue->buf[5 * size]; + while ( size ) + { + bufa = buf - 4; + if ( top->type == game::VAR_CODEPOS ) + { + --game::gScrVmPub[inst].function_count; + --game::gScrVmPub[inst].function_frame; + *(int *)bufa = (int)game::gScrVmPub[inst].function_frame->fs.pos; + game::gScrVmPub[inst].localVars -= game::gScrVmPub[inst].function_frame->fs.localVarCount; + localId = game::GetParentLocalId(inst, localId); + } + else + { + *(int *)bufa = top->u.intValue; + } + buf = bufa - 1; + + assert(top->type >= 0 && top->type < (1 << 8)); + + *buf = top->type; + --top; + --size; + } + --game::gScrVmPub[inst].function_count; + --game::gScrVmPub[inst].function_frame; + game::AddRefToObject(inst, localId); + stack->localId = localId; + return stackValue; + } + + // Completed + int Scr_AddLocalVars(game::scriptInstance_t inst, unsigned int localId) + { + int localVarCount; + unsigned int fieldIndex; + + localVarCount = 0; + for ( fieldIndex = game::FindLastSibling(localId, inst); + fieldIndex; + fieldIndex = game::gScrVarGlob[inst].childVariables[fieldIndex].hash.u.prev ) + { + *++game::gScrVmPub[inst].localVars = game::gScrVarGlob[inst].childVariables[fieldIndex].hash.id; + ++localVarCount; + } + return localVarCount; + } + + // Restored + void Scr_ClearWaitTime(game::scriptInstance_t inst, unsigned int startLocalId) + { + game::VariableValueInternal *entryValue; + + entryValue = &game::gScrVarGlob[inst].parentVariables[startLocalId + 1]; + + assert(((entryValue->w.status & VAR_STAT_MASK) == VAR_STAT_EXTERNAL)); + + assert((entryValue->w.type & VAR_MASK) == game::VAR_TIME_THREAD); + + entryValue->w.status &= ~VAR_MASK; + entryValue->w.status |= game::VAR_THREAD; + } + + // Completed + void VM_UnarchiveStack(game::scriptInstance_t inst, unsigned int startLocalId, game::VariableStackBuffer *stackValue) + { + game::VariableValue *top; + char *buf; + const char **bufa; + unsigned int localId; + int function_count; + int size; + + assert(!game::gScrVmPub[inst].function_count); + + assert(stackValue->pos); + + assert(game::gFs[inst].startTop == &game::gScrVmPub[inst].stack[0]); + + game::gScrVmPub[inst].function_frame->fs.pos = stackValue->pos; + ++game::gScrVmPub[inst].function_count; + ++game::gScrVmPub[inst].function_frame; + size = stackValue->size; + buf = stackValue->buf; + top = game::gScrVmPub[inst].stack; + + while ( size ) + { + --size; + top[1].type = (game::VariableType)*buf; + ++top; + bufa = (const char **)(buf + 1); + + if ( top->type == game::VAR_CODEPOS ) + { + assert(game::gScrVmPub[inst].function_count < MAX_VM_STACK_DEPTH); + + game::gScrVmPub[inst].function_frame->fs.pos = *bufa; + ++game::gScrVmPub[inst].function_count; + ++game::gScrVmPub[inst].function_frame; + } + else + { + top->u.intValue = (int)*bufa; + } + + buf = (char *)(bufa + 1); + } + + game::gFs[inst].pos = stackValue->pos; + game::gFs[inst].top = top; + localId = stackValue->localId; + game::gFs[inst].localId = localId; + game::Scr_ClearWaitTime(inst, startLocalId); + + assert(game::gScrVmPub[inst].function_count < MAX_VM_STACK_DEPTH); + + function_count = game::gScrVmPub[inst].function_count; + + while ( 1 ) + { + game::gScrVmPub[inst].function_frame_start[function_count--].fs.localId = localId; + if ( !function_count ) + { + break; + } + localId = game::GetParentLocalId(inst, localId); + } + + while ( ++function_count != game::gScrVmPub[inst].function_count ) + { + game::gScrVmPub[inst].function_frame_start[function_count].fs.localVarCount = game::Scr_AddLocalVars(inst, game::gScrVmPub[inst].function_frame_start[function_count].fs.localId); + } + + game::gFs[inst].localVarCount = game::Scr_AddLocalVars(inst, game::gFs[inst].localId); + if ( (unsigned __int8)stackValue->time != (unsigned __int8)(game::gScrVarPub[inst].time & 0xFF) ) + { + game::Scr_ResetTimeout(inst); + } + + game::MT_Free((void *)stackValue, stackValue->bufLen, inst); + + assert(game::gScrVmPub[inst].stack[0].type == game::VAR_CODEPOS); + } + + // Restored + void Scr_SetThreadWaitTime(game::scriptInstance_t inst, unsigned int startLocalId, unsigned int waitTime) + { + game::VariableValueInternal *entryValue; + + entryValue = &game::gScrVarGlob[inst].parentVariables[startLocalId + 1]; + + assert(((entryValue->w.status & VAR_STAT_MASK) == VAR_STAT_EXTERNAL)); + + assert(((entryValue->w.type & VAR_MASK) == game::VAR_THREAD) || !game::Scr_GetThreadNotifyName(inst, startLocalId)); + + entryValue->w.status &= ~VAR_MASK; + entryValue->w.status = (unsigned __int8)entryValue->w.status; + entryValue->w.status |= game::VAR_TIME_THREAD; + game::gScrVarGlob[inst].parentVariables[startLocalId + 1].w.status |= waitTime << 8; + } + + // Completed + void VM_TerminateStack(game::scriptInstance_t inst, unsigned int endLocalId, unsigned int startLocalId, game::VariableStackBuffer *stackValue) + { + unsigned int stackId; + unsigned int localId; + const char* buf; + const char *bufa; + int size; + int sizea; + unsigned int parentLocalId; + game::VariableUnion u; + game::VariableValue tempValue; + + assert(startLocalId); + + size = stackValue->size; + localId = stackValue->localId; + buf = &stackValue->buf[5 * size]; + + while ( size ) + { + bufa = buf - 4; + u.intValue = *(int*)bufa; + buf = bufa - 1; + --size; + + if ( *buf == game::VAR_CODEPOS ) + { + parentLocalId = game::GetParentLocalId(inst, localId); + game::Scr_KillThread(inst, localId); + game::RemoveRefToObject(localId, inst); + + if ( localId == endLocalId ) + { + assert(startLocalId != localId); + + sizea = size + 1; + *(char*)buf = 0; + + assert(stackValue->size >= size); + + game::Scr_SetThreadWaitTime(inst, startLocalId, game::gScrVarPub[inst].time); + + assert(u.codePosValue); + + stackValue->pos = (char*)u.codePosValue; + stackValue->localId = parentLocalId; + stackValue->size = sizea; + tempValue.type = game::VAR_STACK; + tempValue.u.stackValue = stackValue; + stackId = game::GetNewObjectVariable(inst, startLocalId, game::GetArray(inst, game::GetVariable(inst, game::gScrVarPub[inst].timeArrayId, game::gScrVarPub[inst].time))); + game::SetNewVariableValue(inst, stackId, &tempValue); + return; + } + + localId = parentLocalId; + } + else + { + game::RemoveRefToValueInternal(inst, (game::VariableType)*(unsigned __int8 *)buf, u); + } + } + + assert(localId == endLocalId); + + assert(startLocalId == localId); + + game::Scr_KillThread(inst, localId); + game::RemoveRefToObject(localId, inst); + game::MT_Free(stackValue, stackValue->bufLen, inst); + } + + // Restored + void Scr_SetThreadNotifyName(game::scriptInstance_t inst, unsigned int startLocalId, unsigned int stringValue) + { + game::VariableValueInternal *entryValue; + + entryValue = &game::gScrVarGlob[inst].parentVariables[startLocalId + 1]; + + assert((entryValue->w.status & VAR_STAT_MASK) != VAR_STAT_FREE); + + assert(((entryValue->w.type & VAR_MASK) == game::VAR_THREAD)); + + entryValue->w.status &= ~VAR_MASK; + entryValue->w.status = (unsigned __int8)entryValue->w.status; + entryValue->w.status |= game::VAR_NOTIFY_THREAD; + entryValue->w.status |= stringValue << 8; + } + + // Completed + void VM_TrimStack(game::scriptInstance_t inst, unsigned int startLocalId, game::VariableStackBuffer *stackValue, int fromEndon) + { + unsigned int localId; + const char *buf; + const char *bufa; + int size; + unsigned int parentLocalId; + game::VariableUnion u; + game::VariableValue tempValue; + + assert(startLocalId); + + size = stackValue->size; + localId = stackValue->localId; + buf = &stackValue->buf[5 * size]; + + while ( size ) + { + bufa = buf - 4; + u.intValue = *(int *)bufa; + buf = bufa - 1; + --size; + if ( *buf == game::VAR_CODEPOS ) + { + if ( game::FindObjectVariable(inst, game::gScrVarPub[inst].pauseArrayId, localId) ) + { + assert(startLocalId != localId); + + stackValue->localId = localId; + stackValue->size = size + 1; + game::Scr_StopThread(inst, localId); + if ( fromEndon ) + { + return; + } + + game::Scr_SetThreadNotifyName(inst, startLocalId, 0); + stackValue->pos = 0; + tempValue.type = game::VAR_STACK; + tempValue.u.stackValue = stackValue; + game::SetNewVariableValue(inst, game::GetNewVariable(inst, OBJECT_STACK, startLocalId), &tempValue); + return; + } + + parentLocalId = game::GetParentLocalId(inst, localId); + game::Scr_KillThread(inst, localId); + game::RemoveRefToObject(localId, inst); + localId = parentLocalId; + } + else + { + game::RemoveRefToValueInternal(inst, (game::VariableType)*(unsigned __int8 *)buf, u); + } + } + + assert(startLocalId == localId); + + if ( fromEndon ) + { + game::RemoveVariable(OBJECT_STACK, startLocalId, inst); + } + + game::Scr_KillThread(inst, startLocalId); + game::RemoveRefToObject(startLocalId, inst); + game::MT_Free(stackValue, stackValue->bufLen, inst); + } + + // Restored + void Scr_DebugTerminateThread(game::scriptInstance_t inst, int topThread) + { + // if ( topThread != game::gScrVmPub[inst].function_count ) + { + game::gScrVmPub[inst].function_frame_start[topThread].fs.pos = game::g_EndPos.get(); + } + } + + // Completed + void Scr_TerminateRunningThread(game::scriptInstance_t inst, unsigned int localId) + { + int function_count; + int topThread; + unsigned int threadId; + + assert(game::gScrVmPub[inst].function_count); + + function_count = game::gScrVmPub[inst].function_count; + topThread = function_count; + + while ( 1 ) + { + assert(function_count); + + threadId = game::gScrVmPub[inst].function_frame_start[function_count].fs.localId; + if ( threadId == localId ) + { + break; + } + + --function_count; + if ( !game::GetSafeParentLocalId(inst, threadId) ) + { + topThread = function_count; + } + } + + while ( topThread >= function_count ) + { + if ( game::gScrVarPub[inst].developer ) + { + game::Scr_DebugTerminateThread(inst, topThread); + } + else + { + game::gScrVmPub[inst].function_frame_start[topThread].fs.pos = game::g_EndPos.get(); + } + --topThread; + } + } + + // Restored + unsigned int Scr_GetThreadWaitTime(game::scriptInstance_t inst, unsigned int startLocalId) + { + assert((game::gScrVarGlob[inst].parentVariables[startLocalId + 1].w.status & VAR_STAT_MASK) == VAR_STAT_EXTERNAL); + + assert((game::gScrVarGlob[inst].parentVariables[startLocalId + 1].w.type & VAR_MASK) == game::VAR_TIME_THREAD); + + return game::gScrVarGlob[inst].parentVariables[startLocalId + 1].w.status >> 8; + } + + const char* Scr_GetStackThreadPos([[maybe_unused]] game::scriptInstance_t inst, [[maybe_unused]] unsigned int endLocalId, [[maybe_unused]] game::VariableStackBuffer* stackValue, [[maybe_unused]] bool killThread) + { + assert(game::gScrVarPub[inst].developer); + + return 0; + } + + // Completed + void Scr_TerminateWaitThread(game::scriptInstance_t inst, unsigned int localId, unsigned int startLocalId) + { + game::VariableStackBuffer *stackValue; + unsigned int stackId; + unsigned int time; + unsigned int id; + + time = game::Scr_GetThreadWaitTime(inst, startLocalId); + game::Scr_ClearWaitTime(inst, startLocalId); + id = game::FindObject(inst, game::FindVariable(time, game::gScrVarPub[inst].timeArrayId, inst)); + stackId = game::FindObjectVariable(inst, id, startLocalId); + + assert(stackId); + + assert(game::GetValueType(inst, stackId) == game::VAR_STACK); + + stackValue = game::GetVariableValueAddress(inst, stackId)->u.stackValue; + if ( game::gScrVarPub[inst].developer ) + { + game::Scr_GetStackThreadPos(inst, localId, stackValue, 1); + } + + game::RemoveObjectVariable(inst, id, startLocalId); + if ( !game::GetArraySize(inst, id) && time != game::gScrVarPub[inst].time ) + { + game::RemoveVariable(time, game::gScrVarPub[inst].timeArrayId, inst); + } + + game::VM_TerminateStack(inst, localId, startLocalId, stackValue); + } + + // Restored + unsigned int Scr_GetSelf(game::scriptInstance_t inst, unsigned int threadId) + { + assert((game::gScrVarGlob[inst].parentVariables[threadId + 1].w.status & VAR_STAT_MASK) != VAR_STAT_FREE); + + 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)); + + return game::gScrVarGlob[inst].parentVariables[threadId + 1].u.o.u.self; + } + + // Completed + void Scr_CancelWaittill(game::scriptInstance_t inst, unsigned int startLocalId) + { + unsigned int selfNameId; + unsigned int selfId; + + selfId = game::Scr_GetSelf(inst, startLocalId); + selfNameId = game::FindObject(inst, game::FindObjectVariable(inst, game::gScrVarPub[inst].pauseArrayId, selfId)); + game::VM_CancelNotify(inst, game::GetVariableValueAddress(inst, game::FindObjectVariable(inst, selfNameId, startLocalId))->u.pointerValue, startLocalId); + game::RemoveObjectVariable(inst, selfNameId, startLocalId); + if ( !game::GetArraySize(inst, selfNameId) ) + { + game::RemoveObjectVariable(inst, game::gScrVarPub[inst].pauseArrayId, selfId); + } + } + + // Completed + void Scr_TerminateWaittillThread(game::scriptInstance_t inst, unsigned int localId, unsigned int startLocalId) + { + game::VariableStackBuffer *stackValue; + unsigned int stringValue; + unsigned int stackId; + unsigned int stackIda; + unsigned int selfNameId; + unsigned int notifyListId; + unsigned int notifyNameListId; + unsigned int notifyListOwnerId; + unsigned int selfId; + + stringValue = game::Scr_GetThreadNotifyName(inst, startLocalId); + if ( stringValue ) + { + selfId = game::Scr_GetSelf(inst, startLocalId); + selfNameId = game::FindObject(inst, game::FindObjectVariable(inst, game::gScrVarPub[inst].pauseArrayId, selfId)); + notifyListOwnerId = game::GetVariableValueAddress(inst, game::FindObjectVariable(inst, selfNameId, startLocalId))->u.intValue; + notifyListId = game::FindObject(inst, game::FindVariable(OBJECT_STACK, notifyListOwnerId, inst)); + notifyNameListId = game::FindObject(inst, game::FindVariable(stringValue, notifyListId, inst)); + stackId = game::FindObjectVariable(inst, notifyNameListId, startLocalId); + + assert(stackId); + + assert(game::GetValueType(inst, stackId) == game::VAR_STACK); + + stackValue = game::GetVariableValueAddress(inst, stackId)->u.stackValue; + + if ( game::gScrVarPub[inst].developer ) + { + game::Scr_GetStackThreadPos(inst, localId, stackValue, 1); + } + + game::VM_CancelNotifyInternal(inst, notifyNameListId, notifyListOwnerId, startLocalId, notifyListId, stringValue); + game::RemoveObjectVariable(inst, selfNameId, startLocalId); + + if ( !game::GetArraySize(inst, selfNameId) ) + { + game::RemoveObjectVariable(inst, game::gScrVarPub[inst].pauseArrayId, selfId); + } + } + else + { + stackIda = game::FindVariable(OBJECT_STACK, startLocalId, inst); + + assert(stackIda); + + assert(game::GetValueType(inst, stackIda) == game::VAR_STACK); + + stackValue = game::GetVariableValueAddress(inst, stackIda)->u.stackValue; + if ( game::gScrVarPub[inst].developer ) + { + game::Scr_GetStackThreadPos(inst, localId, stackValue, 1); + } + game::RemoveVariable(OBJECT_STACK, startLocalId, inst); + } + + game::VM_TerminateStack(inst, localId, startLocalId, stackValue); + } + + // Completed + void Scr_TerminateThread(unsigned int localId, game::scriptInstance_t inst) + { + unsigned int startLocalId; + + startLocalId = game::GetStartLocalId(localId, inst); + switch ( game::GetObjectType(inst, startLocalId) ) + { + case game::VAR_THREAD: + game::Scr_TerminateRunningThread(inst, localId); + break; + case game::VAR_NOTIFY_THREAD: + game::Scr_TerminateWaittillThread(inst, localId, startLocalId); + break; + case game::VAR_TIME_THREAD: + game::Scr_TerminateWaitThread(inst, localId, startLocalId); + break; + default: + //assertMsg("unreachable"); + assert(false); + break; + } + } + + // Restored + unsigned int GetVariableKeyObject(game::scriptInstance_t inst, unsigned int id) + { + game::VariableValueInternal* entryValue; + + entryValue = &game::gScrVarGlob[inst].childVariables[id]; + + assert((entryValue->w.status & VAR_STAT_MASK) != VAR_STAT_FREE); + + assert(!IsObject(entryValue)); + + return (game::gScrVarGlob[inst].childVariables[id].w.status >> 8) - 0x10000; + } + + // Restored + int MT_Realloc(game::scriptInstance_t inst, int oldNumBytes, int newNumbytes) + { + int size; + + size = game::MT_GetSize(oldNumBytes, inst); + return size >= game::MT_GetSize(newNumbytes, inst); + } + + // Completed + void VM_Notify(game::scriptInstance_t inst, int notifyListOwnerId, unsigned int stringValue, game::VariableValue *top) + { + game::VariableStackBuffer *stackValue; + unsigned int notifyListIndex; + game::VariableValue tempValue2; + game::VariableValue tempValue3; + unsigned int stackId; + unsigned int startLocalId; + game::VariableStackBuffer *newStackValue; + game::VariableValue tempValue5; + game::VariableValue *currentValue; + char *buf; + unsigned int selfNameId; + int size; + int len; + unsigned int notifyListId; + unsigned int notifyNameListId; + int newSize; + int bufLen; + bool bNoStack; + game::VariableUnion *tempValue; + unsigned int selfId; + unsigned int notifyListEntry; + + notifyListId = game::FindVariable(OBJECT_STACK, notifyListOwnerId, inst); + if ( notifyListId ) + { + notifyListId = game::FindObject(inst, notifyListId); + + assert(notifyListId); + + notifyNameListId = game::FindVariable(stringValue, notifyListId, inst); + if ( notifyNameListId ) + { + notifyNameListId = game::FindObject(inst, notifyNameListId); + + assert(notifyNameListId); + + game::AddRefToObject(inst, notifyNameListId); + + assert(!game::gScrVarPub[inst].evaluate); + + game::gScrVarPub[inst].evaluate = 1; + notifyListEntry = notifyNameListId; + + while ( 1 ) + { + notifyListIndex = game::FindLastSibling(notifyListEntry, inst); + next: + if ( !notifyListIndex ) + { + break; + } + + notifyListEntry = game::gScrVarGlob[inst].childVariables[notifyListIndex].hash.id; + + assert(notifyListEntry); + + startLocalId = game::GetVariableKeyObject(inst, notifyListEntry); + selfId = game::Scr_GetSelf(inst, startLocalId); + selfNameId = game::FindObject(inst, game::FindObjectVariable(inst, game::gScrVarPub[inst].pauseArrayId, selfId)); + + if ( game::GetValueType(inst, notifyListEntry) ) + { + assert(game::GetValueType(inst, notifyListEntry) == game::VAR_STACK); + + tempValue = &game::GetVariableValueAddress(inst, notifyListEntry)->u; + stackValue = tempValue->stackValue; + if ( *((char *)stackValue->pos - 1) == game::OP_waittillmatch ) + { + size = *stackValue->pos; + + assert(size >= 0); + + assert(size <= stackValue->size); + + buf = &stackValue->buf[5 * (stackValue->size - size)]; + for ( currentValue = top; + size; + --currentValue ) + { + assert(currentValue->type != game::VAR_CODEPOS); + + if ( currentValue->type == game::VAR_PRECODEPOS ) + { + notifyListIndex = game::gScrVarGlob[inst].childVariables[notifyListIndex].hash.u.prev; + goto next; + } + + --size; + tempValue3.type = (game::VariableType)(unsigned char)*buf; + + assert(tempValue3.type != game::VAR_CODEPOS); + + if ( tempValue3.type == game::VAR_PRECODEPOS ) + { + break; + } + + tempValue3.u.intValue = *(int*)++buf; + buf += 4; + game::AddRefToValue(inst, tempValue3.type, tempValue3.u); + tempValue2.u.intValue = currentValue->u.intValue; + tempValue2.type = currentValue->type; + game::AddRefToValue(inst, currentValue->type, tempValue2.u); + game::Scr_EvalEquality(&tempValue3, inst, &tempValue2); + + if ( game::gScrVarPub[inst].error_message ) + { + game::RuntimeError(inst, stackValue->pos, *stackValue->pos - size + 3, game::gScrVarPub[inst].error_message, game::gScrVmGlob[inst].dialog_error_message); + game::Scr_ClearErrorMessage(inst); + notifyListIndex = game::gScrVarGlob[inst].childVariables[notifyListIndex].hash.u.prev; + goto next; + } + + assert(tempValue3.type == game::VAR_INTEGER); + + if ( !tempValue3.u.intValue ) + { + notifyListIndex = game::gScrVarGlob[inst].childVariables[notifyListIndex].hash.u.prev; + goto next; + } + } + ++stackValue->pos; + bNoStack = 1; + } + else + { + assert(top->type != game::VAR_CODEPOS); + + bNoStack = top->type == game::VAR_PRECODEPOS; + } + + tempValue5.type = game::VAR_STACK; + tempValue5.u.stackValue = stackValue; + stackId = game::GetNewObjectVariable(inst, startLocalId, game::GetArray(inst, game::GetVariable(inst, game::gScrVarPub[inst].timeArrayId, game::gScrVarPub[inst].time))); + game::SetNewVariableValue(inst, stackId, &tempValue5); + tempValue = &game::GetVariableValueAddress(inst, stackId)->u; + + game::VM_CancelNotifyInternal(inst, notifyNameListId, notifyListOwnerId, startLocalId, notifyListId, stringValue); + + game::RemoveObjectVariable(inst, selfNameId, startLocalId); + if ( !game::GetArraySize(inst, selfNameId) ) + { + game::RemoveObjectVariable(inst, game::gScrVarPub[inst].pauseArrayId, selfId); + } + + game::Scr_SetThreadWaitTime(inst, startLocalId, game::gScrVarPub[inst].time); + if ( bNoStack ) + { + notifyListEntry = notifyNameListId; + } + else + { + assert((top->type != game::VAR_PRECODEPOS)); + + assert((top->type != game::VAR_CODEPOS)); + + size = stackValue->size; + newSize = size; + currentValue = top; + do + { + ++newSize; + --currentValue; + + assert((currentValue->type != game::VAR_CODEPOS)); + } + while ( currentValue->type != game::VAR_PRECODEPOS ); + + assert(newSize >= 0 && newSize < VARIABLELIST_CHILD_SIZE); + + len = 5 * size; + bufLen = 5 * newSize + 11; + + if ( !game::MT_Realloc(inst, stackValue->bufLen, bufLen) ) + { + newStackValue = (game::VariableStackBuffer *)game::MT_Alloc(bufLen, inst); + newStackValue->bufLen = bufLen; + newStackValue->pos = stackValue->pos; + newStackValue->localId = stackValue->localId; + memcpy(newStackValue->buf, stackValue->buf, len); + game::MT_Free(stackValue, stackValue->bufLen, inst); + stackValue = newStackValue; + tempValue->stackValue = newStackValue; + } + + stackValue->size = newSize; + buf = &stackValue->buf[len]; + newSize -= size; + + assert(newSize); + + do + { + ++currentValue; + game::AddRefToValue(inst, currentValue->type, currentValue->u); + + assert((unsigned)currentValue->type < game::VAR_COUNT); + + *buf++ = currentValue->type; + *(int *)buf = currentValue->u.intValue; + buf += 4; + --newSize; + } + while ( newSize ); + + assert(buf - (const char*)stackValue == bufLen); + + notifyListEntry = notifyNameListId; + } + } + else + { + game::VM_CancelNotifyInternal(inst, notifyNameListId, notifyListOwnerId, startLocalId, notifyListId, stringValue); + game::Scr_KillEndonThread(inst, startLocalId); + game::RemoveObjectVariable(inst, selfNameId, startLocalId); + + if ( !game::GetArraySize(inst, selfNameId) ) + { + game::RemoveObjectVariable(inst, game::gScrVarPub[inst].pauseArrayId, selfId); + } + + game::Scr_TerminateThread(selfId, inst); + notifyListEntry = notifyNameListId; + } + } + game::RemoveRefToObject(notifyNameListId, inst); + + assert(game::gScrVarPub[inst].evaluate); + + game::gScrVarPub[inst].evaluate = 0; + } + } + } + + //Restored function + void SL_CheckExists([[maybe_unused]] game::scriptInstance_t inst, [[maybe_unused]] unsigned int stringValue) + { + + } + + // Completed + void Scr_NotifyNum_Internal(game::scriptInstance_t inst, int entnum, unsigned int classnum, unsigned int stringValue, unsigned int paramcount) + { + game::VariableValue *startTop; + int type; + unsigned int id; + unsigned int paramcounta; + + game::SL_CheckExists(inst, stringValue); + + assert(game::gScrVarPub[inst].timeArrayId); + + assert(paramcount <= game::gScrVmPub[inst].inparamcount); + + game::Scr_ClearOutParams(inst); + startTop = &game::gScrVmPub[inst].top[-paramcount]; + paramcounta = game::gScrVmPub[inst].inparamcount - paramcount; + id = game::FindEntityId(classnum, entnum, inst); + + if ( id ) + { + type = startTop->type; + startTop->type = game::VAR_PRECODEPOS; + game::gScrVmPub[inst].inparamcount = 0; + game::VM_Notify(inst, id, stringValue, game::gScrVmPub[inst].top); + startTop->type = (game::VariableType)type; + } + + while ( game::gScrVmPub[inst].top != startTop ) + { + game::RemoveRefToValueInternal(inst, game::gScrVmPub[inst].top->type, game::gScrVmPub[inst].top->u); + --game::gScrVmPub[inst].top; + } + + game::gScrVmPub[inst].inparamcount = paramcounta; + + assert(!game::gScrVmPub[inst].outparamcount); + + game::SL_CheckExists(inst, stringValue); + } + + // Completed + void Scr_CancelNotifyList(unsigned int notifyListOwnerId, game::scriptInstance_t inst) + { + game::VariableStackBuffer* stackValuea; + game::VariableStackBuffer *stackValue; + game::VariableValueInternal_u* valueAddress; + unsigned int stackId; + unsigned int stackIda; + unsigned int startLocalId; + unsigned int selfStartLocalId; + unsigned int notifyListId; + unsigned int notifyListIda; + unsigned int notifyNameListId; + unsigned int notifyNameListIda; + unsigned int selfLocalId; + + while ( 1 ) + { + notifyListId = game::FindVariable(OBJECT_STACK, notifyListOwnerId, inst); + if ( !notifyListId ) + { + break; + } + + notifyListIda = game::FindObject(inst, notifyListId); + + assert(notifyListIda); + + notifyNameListId = game::FindFirstSibling(inst, notifyListIda); + if ( !notifyNameListId ) + { + break; + } + + notifyNameListIda = game::FindObject(inst, notifyNameListId); + + assert(notifyNameListIda); + + stackId = game::FindFirstSibling(inst, notifyNameListIda); + if ( !stackId ) + { + break; + } + + startLocalId = game::GetVariableKeyObject(inst, stackId); + + assert(startLocalId); + + if ( game::GetValueType(inst, stackId) == game::VAR_STACK ) + { + stackValuea = game::GetVariableValueAddress(inst, stackId)->u.stackValue; + game::Scr_CancelWaittill(inst, startLocalId); + game::VM_TrimStack(inst, startLocalId, stackValuea, 0); + } + else + { + game::AddRefToObject(inst, startLocalId); + game::Scr_CancelWaittill(inst, startLocalId); + selfLocalId = game::Scr_GetSelf(inst, startLocalId); + selfStartLocalId = game::GetStartLocalId(selfLocalId, inst); + stackIda = game::FindVariable(OBJECT_STACK, selfStartLocalId, inst); + + if ( stackIda ) + { + assert(!game::Scr_GetThreadNotifyName(inst, selfStartLocalId)); + + assert(game::GetValueType(inst, stackIda) == game::VAR_STACK); + + valueAddress = game::GetVariableValueAddress(inst, stackIda); + + stackValue = valueAddress->u.stackValue; + + assert(!stackValue->pos); + + game::VM_TrimStack(inst, selfStartLocalId, stackValue, 1); + } + + game::Scr_KillEndonThread(inst, startLocalId); + game::RemoveRefToEmptyObject(inst, startLocalId); + } + } + } + + // Decomp Status: Tested, Completed + void VM_TerminateTime(game::scriptInstance_t inst, unsigned int timeId) + { + game::VariableStackBuffer* stackValue; + unsigned int stackId; + unsigned int startLocalId; + + assert(timeId); + + assert(!game::gScrVmPub[inst].function_count); + + game::AddRefToObject(inst, timeId); + + while (1) + { + stackId = game::FindFirstSibling(inst, timeId); + + if (!stackId) + { + break; + } + + startLocalId = game::GetVariableKeyObject(inst, stackId); + + assert(startLocalId); + + assert(game::GetValueType(inst, stackId) == game::VAR_STACK); + + stackValue = game::GetVariableValueAddress(inst, stackId)->u.stackValue; + game::RemoveObjectVariable(inst, timeId, startLocalId); + game::Scr_ClearWaitTime(inst, startLocalId); + game::VM_TerminateStack(inst, startLocalId, startLocalId, stackValue); + } + + game::RemoveRefToObject(timeId, inst); + } + + // Decomp Status: Tested, Completed + void VM_Resume(game::scriptInstance_t inst, unsigned int timeId) + { + int stackId; + unsigned int startLocalId; + int id; + game::VariableStackBuffer *stackValue; + + assert(game::gScrVmPub[inst].top == game::gScrVmPub[inst].stack); + + game::Scr_ResetTimeout(inst); + game::AddRefToObject(inst, timeId); + game::gFs[inst].startTop = game::gScrVmPub[inst].stack; + game::gThreadCount[inst] = 0; + + while ( true ) + { + assert(!game::gScrVarPub[inst].error_index); + + assert(!game::gScrVmPub[inst].outparamcount); + + assert(!game::gScrVmPub[inst].inparamcount); + + assert(!game::gScrVmPub[inst].function_count); + + assert(game::gScrVmPub[inst].localVars == game::gScrVmGlob[inst].localVarsStack - 1); + + assert(game::gFs[inst].startTop == &game::gScrVmPub[inst].stack[0]); + + assert(!game::gThreadCount[inst]); + + stackId = game::FindFirstSibling(inst, timeId); + + if (!stackId) + { + break; + } + + startLocalId = game::GetVariableKeyObject(inst, stackId); + + assert(startLocalId); + + assert(game::GetValueType(inst, stackId) == game::VAR_STACK); + + stackValue = game::GetVariableValueAddress(inst, stackId)->u.stackValue; + game::RemoveObjectVariable(inst, timeId, startLocalId); + game::VM_UnarchiveStack(inst, startLocalId, stackValue); + id = game::VM_ExecuteInternal(inst); + game::RemoveRefToObject(id, inst); + game::RemoveRefToValue(inst, &game::gScrVmPub[inst].stack[1]); + } + + game::RemoveRefToObject(timeId, inst); + game::ClearVariableValue(inst, game::gScrVarPub[inst].tempVariable); + game::gScrVmPub[inst].top = game::gScrVmPub[inst].stack; + } + + // Decomp Status: Tested, Completed + unsigned int VM_Execute(game::scriptInstance_t inst, unsigned int localId, const char *pos, unsigned int paramcount) + { + game::VariableValue *startTop; + game::VariableType type; + int thread_count_backup; + game::function_stack_t fs_backup[game::SCRIPT_INSTANCE_MAX]; + unsigned int paramcounta; + + assert(paramcount <= game::gScrVmPub[inst].inparamcount); + + game::Scr_ClearOutParams(inst); + startTop = &game::gScrVmPub[inst].top[-paramcount]; + paramcounta = game::gScrVmPub[inst].inparamcount - paramcount; + startTop = &game::gScrVmPub[inst].top[-paramcount]; + if (game::gScrVmPub[inst].function_count >= MAX_VM_STACK_DEPTH) + { + game::Scr_KillThread(inst, localId); + game::gScrVmPub[inst].inparamcount = paramcounta + 1; + + assert(!game::gScrVmPub[inst].outparamcount); + + while (paramcounta) + { + game::RemoveRefToValue(inst, game::gScrVmPub[inst].top); + --game::gScrVmPub[inst].top; + --paramcounta; + } + + ++game::gScrVmPub[inst].top; + game::gScrVmPub[inst].top->type = game::VAR_UNDEFINED; + game::RuntimeError(inst, pos, 0, "script stack overflow (too many embedded function calls)", 0); + } + else + { + fs_backup[inst] = game::gFs[inst]; + fs_backup[inst].startTop = game::gFs[inst].startTop; + thread_count_backup = game::gThreadCount[inst]; + game::gFs[inst].localId = localId; + game::gFs[inst].startTop = startTop; + + if (game::gScrVmPub[inst].function_count) + { + ++game::gScrVmPub[inst].function_count; + ++game::gScrVmPub[inst].function_frame; + game::gScrVmPub[inst].function_frame->fs.localId = 0; + } + + game::gScrVmPub[inst].function_frame->fs.pos = pos; + ++game::gScrVmPub[inst].function_count; + ++game::gScrVmPub[inst].function_frame; + game::gScrVmPub[inst].function_frame->fs.localId = localId; + type = startTop->type; + startTop->type = game::VAR_PRECODEPOS; + game::gScrVmPub[inst].inparamcount = 0; + game::gFs[inst].top = game::gScrVmPub[inst].top; + game::gFs[inst].pos = pos; + game::gFs[inst].localVarCount = 0; + game::gThreadCount[inst] = 0; + localId = game::VM_ExecuteInternal(inst); + game::gFs[inst] = fs_backup[inst]; + game::gFs[inst].startTop = fs_backup[inst].startTop; + game::gThreadCount[inst] = thread_count_backup; + startTop->type = type; + game::gScrVmPub[inst].top = startTop + 1; + game::gScrVmPub[inst].inparamcount = paramcounta + 1; + + assert(!game::gScrVmPub[inst].outparamcount); + + game::ClearVariableValue(inst, game::gScrVarPub[inst].tempVariable); + + if ( game::gScrVmPub[inst].function_count ) + { + --game::gScrVmPub[inst].function_count; + --game::gScrVmPub[inst].function_frame; + return localId; + } + } + return localId; + } + + // Decomp Status: Tested, Completed + unsigned short Scr_ExecThread(game::scriptInstance_t inst, unsigned int handle, unsigned int paramCount) + { + unsigned int objId; + unsigned short threadId; + const char* pos; + + pos = &game::gScrVarPub[inst].programBuffer[handle]; + + if ( !game::gScrVmPub[inst].function_count ) + { + assert(game::gScrVmPub[inst].localVars == game::gScrVmGlob[inst].localVarsStack - 1); + + game::Scr_ResetTimeout(inst); + } + + assert(game::gScrVarPub[inst].timeArrayId); + + assert(handle); + + game::Scr_IsInOpcodeMemory(inst, pos); + game::AddRefToObject(inst, game::gScrVarPub[inst].levelId); + objId = game::AllocThread(inst, game::gScrVarPub[inst].levelId); + threadId = game::VM_Execute(inst, objId, pos, paramCount); + + game::RemoveRefToValue(inst, game::gScrVmPub[inst].top); + game::gScrVmPub[inst].top->type = game::VAR_UNDEFINED; + + --game::gScrVmPub[inst].top; + --game::gScrVmPub[inst].inparamcount; + + if (!game::gScrVmPub[inst].function_count) + { + assert(game::gScrVmPub[inst].localVars == game::gScrVmGlob[inst].localVarsStack - 1); + } + + return threadId; + } + + // Decomp Status: Tested, Completed + unsigned short Scr_ExecEntThreadNum(game::scriptInstance_t inst, int entNum, unsigned int handle, int numParams, unsigned int clientNum) + { + unsigned int threadId; + unsigned short thread; + unsigned int objId; + const char* pos; + game::classNum_e classnum = game::CLASS_NUM_ENTITY; + + pos = &game::gScrVarPub[inst].programBuffer[handle]; + + if ( !game::gScrVmPub[inst].function_count ) + { + assert(game::gScrVmPub[inst].localVars == game::gScrVmGlob[inst].localVarsStack - 1); + + game::Scr_ResetTimeout(inst); + } + + assert(game::gScrVarPub[inst].timeArrayId); + + assert(handle); + + assert(game::Scr_IsInOpcodeMemory(inst, pos)); + + objId = game::Scr_GetEntityId(entNum, inst, classnum, clientNum); + game::AddRefToObject(inst, objId); + threadId = game::AllocThread(inst, objId); + thread = game::VM_Execute(inst, threadId, &game::gScrVarPub[inst].programBuffer[handle], numParams); + game::RemoveRefToValue(inst, game::gScrVmPub[inst].top); + game::gScrVmPub[inst].top->type = game::VAR_UNDEFINED; + --game::gScrVmPub[inst].top; + --game::gScrVmPub[inst].inparamcount; + + if (!game::gScrVmPub[inst].function_count) + { + assert(game::gScrVmPub[inst].localVars == game::gScrVmGlob[inst].localVarsStack - 1); + } + + return thread; + } + + // Decomp Status: Tested, Completed + void Scr_AddExecThread(game::scriptInstance_t inst, unsigned int handle) + { + unsigned int threadId; + unsigned int thread; + unsigned int paramcount = 0; + + if ( !game::gScrVmPub[inst].function_count ) + { + assert(game::gScrVmPub[inst].localVars == game::gScrVmGlob[inst].localVarsStack - 1); + + game::Scr_ResetTimeout(inst); + } + + assert(game::gScrVarPub[inst].timeArrayId); + + assert(game::Scr_IsInOpcodeMemory(inst, &game::gScrVarPub[inst].programBuffer[handle])); + + game::AddRefToObject(inst, game::gScrVarPub[inst].levelId); + threadId = game::AllocThread(inst, game::gScrVarPub[inst].levelId); + thread = game::VM_Execute(inst, threadId, &game::gScrVarPub[inst].programBuffer[handle], paramcount); + game::RemoveRefToObject(thread, inst); + ++game::gScrVmPub[inst].outparamcount; + --game::gScrVmPub[inst].inparamcount; + + if (!game::gScrVmPub[inst].function_count) + { + assert(game::gScrVmPub[inst].localVars == game::gScrVmGlob[inst].localVarsStack - 1); + } + } + + // Decomp Status: Tested, Completed + void VM_SetTime(game::scriptInstance_t inst) + { + int id; + + assert((game::gScrVarPub[inst].time & VAR_NAME_LOW_MASK) == 0); + + if (game::gScrVarPub[inst].timeArrayId) + { + id = game::FindVariable(game::gScrVarPub[inst].time, game::gScrVarPub[inst].timeArrayId, inst); + if ( id ) + { + game::VM_Resume(inst, game::FindObject(inst, id)); + game::SafeRemoveVariable(game::gScrVarPub[inst].time, game::gScrVarPub[inst].timeArrayId, inst); + } + } + } + + // Decomp Status: Tested, Completed + void Scr_InitSystem(game::scriptInstance_t inst) + { + assert(!game::gScrVarPub[inst].timeArrayId); + + //assert(!game::gScrVarPub[inst].ext_threadcount); + + //assert(!game::gScrVarPub[inst].varUsagePos); + + game::gScrVarPub[inst].timeArrayId = game::AllocObject(inst); + + assert(!game::gScrVarPub[inst].pauseArrayId); + + game::gScrVarPub[inst].pauseArrayId = game::Scr_AllocArray(inst); + + assert(!game::gScrVarPub[inst].levelId); + + game::gScrVarPub[inst].levelId = game::AllocObject(inst); + + game::gScrVarPub[inst].time = 0; + + assert(!game::gScrVarPub[inst].animId); + + game::gScrVarPub[inst].animId = game::AllocObject(inst); + + assert(!game::gScrVarPub[inst].freeEntList); + + game::g_script_error_level[inst] = -1; + } + + //Restored function + bool Scr_IsStackClear(game::scriptInstance_t inst) + { + return game::gScrVmPub[inst].top == game::gScrVmPub[inst].stack; + } + + // Decomp Status: Tested, Completed + void Scr_ShutdownSystem(game::scriptInstance_t inst, int bComplete) + { + int functionCount; + int id; + unsigned int ida; + unsigned int idb; + unsigned int parentId; + + game::Scr_FreeEntityList(inst); + if ( game::gScrVarPub[inst].timeArrayId ) + { + game::Scr_FreeGameVariable(inst, bComplete); + functionCount = game::gScrVmPub[inst].function_count; + game::gScrVmPub[inst].function_count = 0; + + for (id = game::FindFirstSibling(inst, game::gScrVarPub[inst].timeArrayId); id; id = game::FindNextSibling(inst, id)) + { + game::VM_TerminateTime(inst, game::FindObject(inst, id)); + } + + while (true) + { + ida = game::FindFirstSibling(inst, game::gScrVarPub[inst].pauseArrayId); + if (!ida) + { + break; + } + + idb = game::FindFirstSibling(inst, game::FindObject(inst, ida)); + + assert(idb); + + parentId = game::GetVariableValueAddress(inst, idb)->u.stringValue; + game::AddRefToObject(inst, parentId); + game::Scr_CancelNotifyList(parentId, inst); + game::RemoveRefToObject(parentId, inst); + } + + assert(game::gScrVarPub[inst].levelId); + + game::ClearObject(game::gScrVarPub[inst].levelId, inst); + game::RemoveRefToEmptyObject(inst, game::gScrVarPub[inst].levelId); + game::gScrVarPub[inst].levelId = 0; + + assert(game::gScrVarPub[inst].animId); + + game::ClearObject(game::gScrVarPub[inst].animId, inst); + game::RemoveRefToEmptyObject(inst, game::gScrVarPub[inst].animId); + game::gScrVarPub[inst].animId = 0; + + assert(game::gScrVarPub[inst].timeArrayId); + + game::ClearObject(game::gScrVarPub[inst].timeArrayId, inst); + game::RemoveRefToEmptyObject(inst, game::gScrVarPub[inst].timeArrayId); + game::gScrVarPub[inst].timeArrayId = 0; + + assert(game::gScrVarPub[inst].pauseArrayId); + + assert(!game::GetArraySize(inst, game::gScrVarPub[inst].pauseArrayId)); + + game::ClearObject(game::gScrVarPub[inst].pauseArrayId, inst); + game::RemoveRefToEmptyObject(inst, game::gScrVarPub[inst].pauseArrayId); + game::gScrVarPub[inst].pauseArrayId = 0; + + assert(!game::gScrVarPub[inst].freeEntList); + + game::Scr_FreeObjects(inst); + + if ( functionCount ) + { + game::gScrVarPub[inst].bInited = 0; + game::Scr_Init(inst); + } + else + { + //assert(!game::gScrVarPub[inst].ext_threadcount); + + assert(game::Scr_IsStackClear(inst)); + } + } + } + + // Decomp Status: Tested, Completed + bool Scr_IsSystemActive() + { + game::scriptInstance_t inst = game::SCRIPTINSTANCE_SERVER; + + return game::gScrVarPub[inst].timeArrayId && !game::gScrVarPub[inst].error_message; + } + + // Decomp Status: Tested, Completed + int Scr_GetInt(game::scriptInstance_t inst, unsigned int index) + { + game::VariableValue *value; + const char *errorMsg; + + if ( index < game::gScrVmPub[inst].outparamcount ) + { + value = &game::gScrVmPub[inst].top[-index]; + if ( value->type == game::VAR_INTEGER ) + { + return value->u.intValue; + } + + game::gScrVarPub[inst].error_index = index + 1; + errorMsg = game::va("type %s is not an int", game::var_typename[value->type]); + game::Scr_Error(errorMsg, inst, false); + } + + errorMsg = game::va("parameter %d does not exist", index + 1); + game::Scr_Error(errorMsg, inst, false); + return 0; + } + + // Decomp Status: Tested, Completed + game::scr_anim_s Scr_GetAnim(unsigned int index, game::XAnimTree_s *animTreeInputForValidation) + { + game::VariableValue *value; + game::scr_anim_s result; + game::XAnim_s *animTreeAnimPtr; + game::XAnim_s *animPtr; + const char *debugMsg; + const char *errorMsg; + game::scriptInstance_t inst = game::SCRIPTINSTANCE_SERVER; + game::animUserInstance_t user = game::ANIM_USER_SERVER; + + result.u.linkPointer = nullptr; + + if ( index >= game::gScrVmPub[inst].outparamcount ) + { + errorMsg = game::va("parameter %d does not exist", index + 1); + game::Scr_Error(errorMsg, inst, false); + return result; + } + + value = &game::gScrVmPub[inst].top[-index]; + if (value->type != game::VAR_ANIMATION ) + { + game::gScrVarPub[inst].error_message = (char*)game::va("type %s is not an anim", game::var_typename[value->type]); + game::RemoveRefToValueInternal(inst, value->type, value->u); + value->type = game::VAR_UNDEFINED; + game::gScrVarPub[inst].error_index = index + 1; + game::Scr_ErrorInternal(inst); + return result; + } + + result.u.linkPointer = (const char*)value->u.intValue; + if ( !animTreeInputForValidation ) + { + return result; + } + + animTreeAnimPtr = animTreeInputForValidation->anims; + animPtr = game::gScrAnimPub[inst].xanim_lookup[user][(unsigned int)result.u.linkPointer >> 16].anims; + if ( animPtr == animTreeAnimPtr ) + { + return result; + } + + debugMsg = game::XAnimGetAnimDebugName(value->u.intValue, animPtr); + game::gScrVarPub[inst].error_message = (char*)game::va("anim '%s' in animtree '%s' does not belong to the entity's animtree '%s'", debugMsg, animTreeAnimPtr->debugName, animTreeAnimPtr->debugName); + game::RemoveRefToValueInternal(game::SCRIPTINSTANCE_SERVER, value->type, value->u); + value->type = game::VAR_UNDEFINED; + game::gScrVarPub[inst].error_index = index + 1; + game::Scr_ErrorInternal(game::SCRIPTINSTANCE_SERVER); + return result; + } + + // Decomp Status: Untested, Completed + game::scr_animtree_t Scr_GetAnimTree() + { + const char* errorMsg; + unsigned int i; + game::VariableValue* value; + unsigned int index = 0; + game::scr_animtree_t result; + + game::animUserInstance_t user = game::ANIM_USER_SERVER; + game::scriptInstance_t inst = game::SCRIPTINSTANCE_SERVER; + + result.anims = nullptr; + + if (index < game::gScrVmPub[inst].outparamcount) + { + value = &game::gScrVmPub[inst].top[-index]; + if (value->type == game::VAR_INTEGER) + { + i = value->u.intValue; + if (value->u.intValue <= (int)game::gScrAnimPub[inst].xanim_num[user] && game::gScrAnimPub[inst].xanim_lookup[user][i].anims) + { + result.anims = game::gScrAnimPub[inst].xanim_lookup[user][i].anims; + return result; + } + + game::gScrVarPub[inst].error_message = (char*)"bad anim tree"; + } + else + { + game::gScrVarPub[inst].error_message = (char*)game::va("type %s is not an animtree", game::var_typename[value->type]); + } + + game::RemoveRefToValue(inst, value); + value->u.intValue = 0; + game::gScrVarPub[inst].error_index = index + 1; + game::Scr_ErrorInternal(inst); + } + + errorMsg = game::va("parameter %d does not exist", index + 1); + game::Scr_Error(errorMsg, inst, false); + return result; + } + + // Decomp Status: Tested, Completed + float Scr_GetFloat(game::scriptInstance_t inst, unsigned int index) + { + game::VariableValue *value; + game::VariableType type; + const char *errorMsg; + + if ( index < game::gScrVmPub[inst].outparamcount ) + { + value = &game::gScrVmPub[inst].top[-index]; + type = value->type; + if ( type == game::VAR_FLOAT ) + { + return value->u.floatValue; + } + + if ( type == game::VAR_INTEGER ) + { + return (float)value->u.intValue; + } + + game::gScrVarPub[inst].error_index = index + 1; + errorMsg = game::va("type %s is not a float", game::var_typename[value->type]); + game::Scr_Error(errorMsg, inst, false); + } + + errorMsg = game::va("parameter %d does not exist", index + 1); + game::Scr_Error(errorMsg, inst, false); + return 0.0f; + } + + // Decomp Status: Tested, Completed + unsigned int Scr_GetConstString(game::scriptInstance_t inst, unsigned int index) + { + game::VariableValue *value; + const char *errorMsg; + + if ( index < game::gScrVmPub[inst].outparamcount ) + { + value = &game::gScrVmPub[inst].top[-index]; + if ( game::Scr_CastString(inst, value) ) + { + assert(value->type == game::VAR_STRING); + + return value->u.stringValue; + } + + game::gScrVarPub[inst].error_index = index + 1; + game::Scr_ErrorInternal(inst); + } + + errorMsg = game::va("parameter %d does not exist", index + 1); + game::Scr_Error(errorMsg, inst, false); + return 0; + } + + // Decomp Status: Tested, Completed + unsigned int Scr_GetConstLowercaseString(game::scriptInstance_t inst, unsigned int index) + { + const char* errorMsg; + char* originalStr; + char retStr[SL_MAX_STRING_LEN]; + int i; + game::VariableValue* value; + unsigned int stringValue; + + if (index >= game::gScrVmPub[inst].outparamcount) + { + errorMsg = game::va("parameter %d does not exist", index + 1); + game::Scr_Error(errorMsg, inst, false); + return 0; + } + + value = &game::gScrVmPub[inst].top[-index]; + if (!game::Scr_CastString(inst, value)) + { + game::gScrVarPub[inst].error_index = index + 1; + game::Scr_ErrorInternal(inst); + return 0; + } + + assert(value->type == game::VAR_STRING); + + stringValue = value->u.stringValue; + originalStr = game::SL_ConvertToString(stringValue, inst); + for (i = 0; ; ++i) + { + retStr[i] = tolower(originalStr[i]); + if (!originalStr[i]) + { + break; + } + } + + assert(value->type == game::VAR_STRING); + + value->u.stringValue = game::SL_GetString_(retStr, inst, 0); + game::SL_RemoveRefToString(stringValue, inst); + //SL_CheckExists(inst, value->u.intValue); + return value->u.stringValue; + } + + // Decomp Status: Untested, Completed + const char *Scr_GetString(unsigned int index, game::scriptInstance_t inst) + { + unsigned int stringValue; + + stringValue = game::Scr_GetConstString(inst, index); + return game::SL_ConvertToString(stringValue, inst); + } + + // Decomp Status: Untested, Completed + unsigned int Scr_GetConstStringIncludeNull(game::scriptInstance_t inst) + { + unsigned int result = 0; + unsigned int index = 0; + + if ( index >= game::gScrVmPub[inst].outparamcount || game::gScrVmPub[inst].top[-index].type) + { + result = game::Scr_GetConstString(inst, index); + } + + return result; + } + + // Decomp Status: Tested, Completed + char *Scr_GetDebugString(game::scriptInstance_t inst, unsigned int index) + { + game::VariableValue *value; + char *result; + const char *errorMsg; + + if ( index >= game::gScrVmPub[inst].outparamcount ) + { + errorMsg = game::va("parameter %d does not exist", index + 1); + game::Scr_Error(errorMsg, inst, false); + result = 0; + } + else + { + value = &game::gScrVmPub[inst].top[-index]; + game::Scr_CastDebugString(inst, value); + + assert(value->type == game::VAR_STRING); + + result = game::SL_ConvertToString(value->u.stringValue, inst); + } + + return result; + } + + // Decomp Status: Tested, Completed + unsigned int Scr_GetConstIString(unsigned int index) + { + const char* errorMsg; + game::VariableValue* value; + game::scriptInstance_t inst = game::SCRIPTINSTANCE_SERVER; + + if (index < game::gScrVmPub[inst].outparamcount) + { + value = &game::gScrVmPub[inst].top[-index]; + if (value->type == game::VAR_ISTRING) + { + return value->u.stringValue; + } + + game::gScrVarPub[inst].error_index = index + 1; + errorMsg = game::va("type %s is not a localized string", game::var_typename[value->type]); + game::Scr_Error(errorMsg, inst, false); + } + + errorMsg = game::va("parameter %d does not exist", index + 1); + game::Scr_Error(errorMsg, inst, false); + return 0; + } + + // Decomp Status: Tested, Completed + void Scr_GetVector(game::scriptInstance_t inst, float * vectorValue, unsigned int index) + { + const char* errorMsg; + const float* varValue; + game::VariableValue* value; + + if (index < game::gScrVmPub[inst].outparamcount) + { + value = &game::gScrVmPub[inst].top[-index]; + if (value->type == game::VAR_VECTOR) + { + varValue = value->u.vectorValue; + vectorValue[0] = varValue[0]; + vectorValue[1] = varValue[1]; + vectorValue[2] = varValue[2]; + return; + } + + game::gScrVarPub[inst].error_index = index + 1; + errorMsg = game::va("type %s is not a vector", game::var_typename[value->type]); + game::Scr_Error(errorMsg, inst, false); + } + + errorMsg = game::va("parameter %d does not exist", index + 1); + game::Scr_Error(errorMsg, inst, false); + } + + // Decomp Status: Untested, Completed + unsigned int Scr_GetFunc() + { + const char *errorMsg; + game::scriptInstance_t inst = game::SCRIPTINSTANCE_SERVER; + unsigned int index = 0; + + if ( game::gScrVmPub[inst].outparamcount ) + { + if ( game::gScrVmPub[inst].top[-index].type == game::VAR_FUNCTION) + { + assert(game::Scr_IsInOpcodeMemory(inst, game::gScrVmPub[inst].top[-index].u.codePosValue)); + + return game::gScrVmPub[inst].top[-index].u.intValue - (unsigned int)game::gScrVarPub[inst].programBuffer; + } + + game::gScrVarPub[inst].error_index = index + 1; + errorMsg = game::va("type %s is not a function", game::var_typename[game::gScrVmPub[inst].top[-index].type]); + game::Scr_Error(errorMsg, inst, false); + } + + errorMsg = game::va("parameter %d does not exist", index + 1); + game::Scr_Error(errorMsg, inst, false); + return 0; + } + + // Decomp Status: Tested, Completed + game::scr_entref_t *Scr_GetEntityRef(game::scriptInstance_t inst, game::scr_entref_t *retstr, unsigned int index) + { + const char* errorMsg; + game::scr_entref_t entRef; + game::VariableValue* value; + unsigned int id; + + if (index < game::gScrVmPub[inst].outparamcount) + { + value = &game::gScrVmPub[inst].top[-index]; + if (value->type == game::VAR_POINTER) + { + id = value->u.intValue; + if (game::GetObjectType(inst, id) == game::VAR_ENTITY) + { + *retstr = *game::Scr_GetEntityIdRef(&entRef, inst, id);; + return retstr; + } + + game::gScrVarPub[inst].error_index = index + 1; + errorMsg = game::va("type %s is not an entity", game::var_typename[game::GetObjectType(inst, id)]); + game::Scr_Error(errorMsg, inst, false); + } + + game::gScrVarPub[inst].error_index = index + 1; + errorMsg = game::va("type %s is not an entity", game::var_typename[value->type]); + game::Scr_Error(errorMsg, inst, false); + } + + errorMsg = game::va("parameter %d does not exist", index + 1); + game::Scr_Error(errorMsg, inst, false); + return retstr; + } + + // Decomp Status: Tested, Completed + game::VariableUnion Scr_GetObject(game::scriptInstance_t inst) + { + const char *errorMsg; + unsigned int index = 0; + + if (index < game::gScrVmPub[inst].outparamcount ) + { + if (game::gScrVmPub[inst].top[-index].type == game::VAR_POINTER) + { + return game::gScrVmPub[inst].top[-index].u; + } + + game::gScrVarPub[inst].error_index = index + 1; + errorMsg = game::va("type %s is not an object", game::var_typename[game::gScrVmPub[inst].top[-index].type]); + game::Scr_Error(errorMsg, inst, false); + } + + errorMsg = game::va("parameter %d does not exist", index + 1); + game::Scr_Error(errorMsg, inst, false); + return game::gScrVmPub[inst].top[-index].u; // won't reach it ok + } + + // Decomp Status: Tested, Completed + game::VariableType Scr_GetType(game::scriptInstance_t inst, unsigned int index) + { + const char *errorMsg; + + if ( index < game::gScrVmPub[inst].outparamcount ) + { + return game::gScrVmPub[inst].top[-index].type; + } + + errorMsg = game::va("parameter %d does not exist", index + 1); + game::Scr_Error(errorMsg, inst, false); + return (game::VariableType)0; + } + + // Decomp Status: Tested, Completed + const char *Scr_GetTypeName(game::scriptInstance_t inst) + { + const char *errorMsg; + unsigned int index = 0; + + if (index < game::gScrVmPub[inst].outparamcount ) + { + return game::var_typename[game::gScrVmPub[inst].top[-index].type]; + } + + errorMsg = game::va("parameter %d does not exist", index + 1); + game::Scr_Error(errorMsg, inst, false); + return 0; + } + + // Decomp Status: Tested, Completed + game::VariableType Scr_GetPointerType(game::scriptInstance_t inst, unsigned int index) + { + const char *errorMsg; + + if ( index < game::gScrVmPub[inst].outparamcount ) + { + if (game::gScrVmPub[inst].top[-index].type == game::VAR_POINTER ) + { + return (game::VariableType)(game::gScrVarGlob[inst].parentVariables[game::gScrVmPub[inst].top[-index].u.intValue + 1].w.status & VAR_MASK); + } + + errorMsg = game::va("type %s is not an object", game::var_typename[game::gScrVmPub[inst].top[-index].type]); + game::Scr_Error(errorMsg, inst, false); + } + + errorMsg = game::va("parameter %d does not exist", index + 1); + game::Scr_Error(errorMsg, inst, false); + return (game::VariableType)0; + } + + // Decomp Status: Tested, Completed + void Scr_AddInt(game::scriptInstance_t inst, int value) + { + game::IncInParam(inst); + game::gScrVmPub[inst].top->type = game::VAR_INTEGER; + game::gScrVmPub[inst].top->u.intValue = value; + } + + // Decomp Status: Tested, Completed + void Scr_AddFloat(game::scriptInstance_t inst, float value) + { + game::IncInParam(inst); + game::gScrVmPub[inst].top->type = game::VAR_FLOAT; + game::gScrVmPub[inst].top->u.floatValue = value; + } + + // Decomp Status: Tested, Completed + void Scr_AddAnim(game::scr_anim_s value) + { + game::scriptInstance_t inst = game::SCRIPTINSTANCE_SERVER; + + game::IncInParam(inst); + game::gScrVmPub[inst].top->type = game::VAR_ANIMATION; + game::gScrVmPub[inst].top->u.intValue = (int)value.u.linkPointer; + } + + // Decomp Status: Tested, Completed + void Scr_AddUndefined(game::scriptInstance_t inst) + { + game::IncInParam(inst); + game::gScrVmPub[inst].top->type = game::VAR_UNDEFINED; + } + + // Decomp Status: Tested, Completed + void Scr_AddObject(game::scriptInstance_t inst, unsigned int entid) + { + assert(entid); + + assert(game::GetObjectType(inst, entid) != game::VAR_THREAD); + + assert(game::GetObjectType(inst, entid) != game::VAR_NOTIFY_THREAD); + + assert(game::GetObjectType(inst, entid) != game::VAR_TIME_THREAD); + + assert(game::GetObjectType(inst, entid) != game::VAR_CHILD_THREAD); + + assert(game::GetObjectType(inst, entid) != game::VAR_DEAD_THREAD); + + game::IncInParam(inst); + game::gScrVmPub[inst].top->type = game::VAR_POINTER; + game::gScrVmPub[inst].top->u.intValue = entid; + game::AddRefToObject(inst, entid); + } + + // Decomp Status: Tested, Completed + void Scr_AddString(game::scriptInstance_t inst, const char *string) + { + assert(string); + + game::IncInParam(inst); + game::gScrVmPub[inst].top->type = game::VAR_STRING; + game::gScrVmPub[inst].top->u.stringValue = game::SL_GetString_(string, inst, 0); + } + + // Decomp Status: Tested, Completed + void Scr_AddIString(const char *string) + { + game::scriptInstance_t inst = game::SCRIPTINSTANCE_SERVER; + + assert(string); + + game::IncInParam(inst); + game::gScrVmPub[inst].top->type = game::VAR_ISTRING; + game::gScrVmPub[inst].top->u.stringValue = game::SL_GetString_(string, inst, 0); + } + + // Decomp Status: Tested, Completed + void Scr_AddConstString(game::scriptInstance_t inst, unsigned int id) + { + assert(id); + + game::IncInParam(inst); + game::gScrVmPub[inst].top->type = game::VAR_STRING; + game::gScrVmPub[inst].top->u.intValue = id; + game::SL_AddRefToString(inst, id); + } + + // Decomp Status: Tested, Completed + void Scr_AddVector(game::scriptInstance_t inst, float *value) + { + game::IncInParam(inst); + game::gScrVmPub[inst].top->type = game::VAR_VECTOR; + game::gScrVmPub[inst].top->u.vectorValue = game::Scr_AllocVector_(inst, value); + } + + // Restored Function + void IncInParam(game::scriptInstance_t inst) + { + assert(((game::gScrVmPub[inst].top >= game::gScrVmGlob[inst].eval_stack - 1) && (game::gScrVmPub[inst].top <= game::gScrVmGlob[inst].eval_stack)) || + ((game::gScrVmPub[inst].top >= game::gScrVmPub[inst].stack) && (game::gScrVmPub[inst].top <= game::gScrVmPub[inst].maxstack))); + + game::Scr_ClearOutParams(inst); + + if (game::gScrVmPub[inst].top == game::gScrVmPub[inst].maxstack) + { + game::Sys_Error("Internal script stack overflow"); + } + + ++game::gScrVmPub[inst].top; + ++game::gScrVmPub[inst].inparamcount; + + assert(((game::gScrVmPub[inst].top >= game::gScrVmGlob[inst].eval_stack) && (game::gScrVmPub[inst].top <= game::gScrVmGlob[inst].eval_stack + 1)) || + ((game::gScrVmPub[inst].top >= game::gScrVmPub[inst].stack) && (game::gScrVmPub[inst].top <= game::gScrVmPub[inst].maxstack))); + } + + // Decomp Status: Tested, Completed + void Scr_MakeArray(game::scriptInstance_t inst) + { + game::IncInParam(inst); + game::gScrVmPub[inst].top->type = game::VAR_POINTER; + game::gScrVmPub[inst].top->u.intValue = game::Scr_AllocArray(inst); + } + + // Decomp Status: Tested, Completed + void Scr_AddArray(game::scriptInstance_t inst) + { + unsigned int arraySize; + unsigned int id; + + assert(game::gScrVmPub[inst].inparamcount); + + --game::gScrVmPub[inst].top; + --game::gScrVmPub[inst].inparamcount; + + assert(game::gScrVmPub[inst].top->type == game::VAR_POINTER); + + arraySize = game::GetArraySize(inst, game::gScrVmPub[inst].top->u.stringValue); + id = game::GetNewArrayVariable(inst, game::gScrVmPub[inst].top->u.stringValue, arraySize); + game::SetNewVariableValue(inst, id, game::gScrVmPub[inst].top + 1); + } + + // Restored function + void SetNewVariableValue(game::scriptInstance_t inst, unsigned int id, game::VariableValue* value) + { + game::VariableValueInternal* entryValue; + + assert(value->type < game::VAR_THREAD); + + entryValue = &game::gScrVarGlob[inst].childVariables[id]; + + assert((entryValue->w.status & VAR_STAT_MASK) != VAR_STAT_FREE); + + assert(!IsObject(entryValue)); + + assert(value->type >= game::VAR_UNDEFINED && value->type < game::VAR_COUNT); + + assert((entryValue->w.type & VAR_MASK) == game::VAR_UNDEFINED); + + assert((value->type != game::VAR_POINTER) || ((entryValue->w.type & VAR_MASK) < game::FIRST_DEAD_OBJECT)); + + entryValue->w.status |= value->type; + entryValue->u.u.intValue = value->u.intValue; + } + + // Decomp Status: Tested, Completed + void Scr_AddArrayStringIndexed(unsigned int stringValue, game::scriptInstance_t inst) + { + unsigned int id; + + assert(game::gScrVmPub[inst].inparamcount); + + --game::gScrVmPub[inst].top; + --game::gScrVmPub[inst].inparamcount; + + assert(game::gScrVmPub[inst].top->type == game::VAR_POINTER); + + id = game::GetNewVariable(inst, stringValue, game::gScrVmPub[inst].top->u.stringValue); + game::SetNewVariableValue(inst, id, game::gScrVmPub[inst].top + 1); + } + + //Restored function + void Scr_SetErrorMessage(game::scriptInstance_t inst, const char* error) + { + if (!game::gScrVarPub[inst].error_message) + { + game::I_strncpyz(game::error_message_buff.get(), error, 1023u); + game::error_message_buff[1023] = '\0'; + game::gScrVarPub[inst].error_message = game::error_message_buff.get(); + } + } + + // Decomp Status: Tested, Completed + void Scr_Error(const char* error, game::scriptInstance_t inst, int is_terminal) + { + game::Scr_SetErrorMessage(inst, error); + + game::gScrVmPub[inst].terminal_error = is_terminal; + game::Scr_ErrorInternal(inst); + } + + // Decomp Status: Tested, Completed + void Scr_TerminalError(game::scriptInstance_t inst, const char* error) + { + game::Scr_DumpScriptThreads(inst); + game::gScrVmPub[inst].terminal_error = 1; + game::Scr_Error(error, inst, false); + } + + // Decomp Status: Tested, Completed + void Scr_ParamError(unsigned int index, game::scriptInstance_t inst, const char* error) + { + assert(index < game::gScrVmPub[inst].outparamcount); + + game::gScrVarPub[inst].error_index = index + 1; + game::Scr_Error(error, inst, false); + } + + // Decomp Status: Tested, Completed + void Scr_ObjectError(game::scriptInstance_t inst, const char* error) + { + game::gScrVarPub[inst].error_index = -1; + game::Scr_Error(error, inst, false); + } + + //Restored function + int CScr_SetObjectField(game::classNum_e classnum, int entnum, int clientNum, int offset) + { + if (classnum > game::CLASS_NUM_ENTITY) + { + //assertMsg("bad classnum"); + assert(false); + return 1; + } + else + { + return game::CScr_SetEntityField(offset, entnum, clientNum); + } + } + + // Decomp Status: Tested, Completed + bool SetEntityFieldValue(game::scriptInstance_t inst, int offset, int entnum, game::classNum_e classnum, int clientNum, game::VariableValue *value) + { + int bSet = false; + + assert((value - game::gScrVmPub[inst].stack > 0)); + + assert((value - game::gScrVmPub[inst].maxstack <= 0)); + + assert(!game::gScrVmPub[inst].inparamcount); + + assert(!game::gScrVmPub[inst].outparamcount); + + game::gScrVmPub[inst].top = value; + game::gScrVmPub[inst].outparamcount = 1; + + if ( inst == game::SCRIPTINSTANCE_CLIENT ) + { + bSet = game::CScr_SetObjectField(classnum, entnum, clientNum, offset); + } + else + { + bSet = game::Scr_SetObjectField(offset, entnum, classnum, inst); + } + + if ( !bSet ) + { + assert(!game::gScrVmPub[inst].inparamcount); + + assert(game::gScrVmPub[inst].outparamcount == 1); + + game::gScrVmPub[inst].outparamcount = 0; + return 0; + } + + assert(!game::gScrVmPub[inst].inparamcount); + + if ( !game::gScrVmPub[inst].outparamcount ) + { + return 1; + } + + assert(game::gScrVmPub[inst].outparamcount == 1); + + game::RemoveRefToValue(inst, game::gScrVmPub[inst].top); + --game::gScrVmPub[inst].top; + game::gScrVmPub[inst].outparamcount = 0; + return 1; + } + + //Restored function + void CScr_GetObjectField(game::classNum_e classnum, int entnum, int clientNum, int offset) + { + if (classnum > game::CLASS_NUM_ENTITY) + { + //assertMsg("bad classnum"); + assert(false); + } + else + { + game::CScr_GetEntityField(offset, entnum, clientNum); + } + } + + // Decomp Status: Tested, Completed + game::VariableValue GetEntityFieldValue(int offset, int entnum, game::scriptInstance_t inst, game::classNum_e classnum, int clientNum) + { + game::VariableValue result; + + assert(!game::gScrVmPub[inst].inparamcount); + + assert(!game::gScrVmPub[inst].outparamcount); + + game::gScrVmPub[inst].top = game::gScrVmGlob[inst].eval_stack - 1; + game::gScrVmGlob[inst].eval_stack[0].type = game::VAR_UNDEFINED; + + if (inst == game::SCRIPTINSTANCE_CLIENT) + { + game::CScr_GetObjectField(classnum, entnum, clientNum, offset); + } + else + { + game::Scr_GetObjectField(offset, inst, classnum, entnum); + } + + assert(!game::gScrVmPub[inst].inparamcount || game::gScrVmPub[inst].inparamcount == 1); + + assert(!game::gScrVmPub[inst].outparamcount); + + assert(game::gScrVmPub[inst].top - game::gScrVmPub[inst].inparamcount == game::gScrVmGlob[inst].eval_stack - 1); + + result.u.intValue = game::gScrVmGlob[inst].eval_stack[0].u.intValue; + result.type = game::gScrVmGlob[inst].eval_stack[0].type; + game::gScrVmPub[inst].inparamcount = 0; + return result; + } + + //Restored function + void SetVariableFieldValue(game::scriptInstance_t inst, unsigned int id, game::VariableValue* value) + { + if (id) + { + game::SetVariableValue(inst, value, id); + } + else + { + game::SetVariableEntityFieldValue(inst, game::gScrVarPub[inst].entId, game::gScrVarPub[inst].entFieldName, value); + } + } + + // Decomp Status: Tested, Completed + void Scr_SetStructField(unsigned int structId, unsigned int index, game::scriptInstance_t inst) + { + unsigned int fieldValueId; + + assert(!game::gScrVmPub[inst].outparamcount); + + assert(game::gScrVmPub[inst].inparamcount == 1); + + fieldValueId = game::gScrVarGlob[inst].childVariables[game::Scr_GetVariableFieldIndex(inst, index, structId)].hash.id; + + assert(game::gScrVmPub[inst].inparamcount == 1); + + game::gScrVmPub[inst].inparamcount = 0; + game::SetVariableFieldValue(inst, fieldValueId, game::gScrVmPub[inst].top); + + assert(!game::gScrVmPub[inst].inparamcount); + + assert(!game::gScrVmPub[inst].outparamcount); + + --game::gScrVmPub[inst].top; + } + + // Decomp Status: Tested, Completed + void Scr_IncTime(game::scriptInstance_t inst) + { + game::Scr_RunCurrentThreads(inst); + game::Scr_FreeEntityList(inst); + + assert((game::gScrVarPub[inst].time & VAR_NAME_LOW_MASK) == 0); + + ++game::gScrVarPub[inst].time; + game::gScrVarPub[inst].time &= ~VAR_NAME_LOW_MASK; + } + + // Decomp Status: Tested, Completed + void Scr_RunCurrentThreads(game::scriptInstance_t inst) + { + int preTime; + + preTime = timeGetTime(); + + assert(!game::gScrVmPub[inst].function_count); + + assert(!game::gScrVarPub[inst].error_message); + + assert(!game::gScrVarPub[inst].error_index); + + assert(!game::gScrVmPub[inst].outparamcount); + + assert(!game::gScrVmPub[inst].inparamcount); + + assert(game::gScrVmPub[inst].top == game::gScrVmPub[inst].stack); + + game::VM_SetTime(inst); + game::gScrExecuteTime[inst] += timeGetTime() - preTime; + } + + // Decomp Status: Tested, Completed + void Scr_ResetTimeout(game::scriptInstance_t inst) + { + game::gScrVmGlob[inst].starttime = game::Sys_Milliseconds(); + } + + game::VariableStackBuffer* GetRefVariableStackBuffer(game::scriptInstance_t inst, int id) + { + assert(id); + + assert((id * MT_NODE_SIZE) < MT_SIZE); + + return (game::VariableStackBuffer*)&game::gScrMemTreePub[inst].mt_buffer->nodes[id]; + } + + void Scr_NotifyNum(int entnum, game::classNum_e classnum, unsigned int stringValue, unsigned int paramcount) + { + game::Scr_NotifyNum_Internal(game::SCRIPTINSTANCE_SERVER, entnum, classnum, stringValue, paramcount); + } +} +#pragma warning(pop) diff --git a/src/codsrc/clientscript/cscr_vm.hpp b/src/codsrc/clientscript/cscr_vm.hpp new file mode 100644 index 0000000..2eb2323 --- /dev/null +++ b/src/codsrc/clientscript/cscr_vm.hpp @@ -0,0 +1,119 @@ +#pragma once + +namespace codsrc +{ + void Scr_VM_Init(game::scriptInstance_t inst); + void Scr_Init(game::scriptInstance_t inst); + void Scr_Shutdown(game::scriptInstance_t inst); + void Scr_ErrorInternal(game::scriptInstance_t inst); + void Scr_ClearOutParams(game::scriptInstance_t inst); + unsigned int GetDummyObject(game::scriptInstance_t inst); + unsigned int GetDummyFieldValue(game::scriptInstance_t inst); + unsigned int VM_ExecuteInternal(game::scriptInstance_t inst); + void VM_CancelNotifyInternal(game::scriptInstance_t inst, unsigned int notifyListOwnerId, unsigned int startLocalId, unsigned int notifyListId, unsigned int notifyNameListId, unsigned int stringValue); + void VM_CancelNotify(game::scriptInstance_t inst, unsigned int a2, unsigned int a3); + game::VariableStackBuffer* VM_ArchiveStack(game::scriptInstance_t inst); + int Scr_AddLocalVars(game::scriptInstance_t inst, unsigned int a2); + void VM_UnarchiveStack(game::scriptInstance_t inst, unsigned int startLocalId, game::VariableStackBuffer* stackValue); + void VM_TerminateStack(game::scriptInstance_t inst, unsigned int a2, unsigned int a3, game::VariableStackBuffer* name); + void VM_TrimStack(game::scriptInstance_t inst, unsigned int parentId, game::VariableStackBuffer* a3, int fromEndon); + void Scr_TerminateRunningThread(game::scriptInstance_t inst, unsigned int a2); + void Scr_TerminateWaitThread(game::scriptInstance_t inst, unsigned int a2, unsigned int a3); + void Scr_CancelWaittill(game::scriptInstance_t inst, unsigned int startLocalId); + void Scr_TerminateWaittillThread(game::scriptInstance_t inst, unsigned int a2, unsigned int a3); + void Scr_TerminateThread(unsigned int a2, game::scriptInstance_t inst); + void VM_Notify(game::scriptInstance_t inst, int notifyListOwnerId, unsigned int stringValue, game::VariableValue* top); + void Scr_NotifyNum_Internal(game::scriptInstance_t inst, int entNum, unsigned int entClass, unsigned int notifStr, unsigned int numParams); + void Scr_CancelNotifyList(unsigned int notifyListOwnerId, game::scriptInstance_t inst); + void VM_TerminateTime(game::scriptInstance_t inst, unsigned int parentId); + void VM_Resume(game::scriptInstance_t inst, unsigned int timeId); + unsigned int VM_Execute(game::scriptInstance_t inst, unsigned int localId, const char* pos, unsigned int paramcount); + unsigned short Scr_ExecThread(game::scriptInstance_t inst, unsigned int handle, unsigned int paramCount); + unsigned short Scr_ExecEntThreadNum(game::scriptInstance_t inst, int entNum, unsigned int handle, int numParams, unsigned int entClass); + void Scr_AddExecThread(game::scriptInstance_t inst, unsigned int handle); + void VM_SetTime(game::scriptInstance_t inst); + void Scr_InitSystem(game::scriptInstance_t inst); + void Scr_ShutdownSystem(game::scriptInstance_t inst, int bComplete); + bool Scr_IsSystemActive(); + int Scr_GetInt(game::scriptInstance_t inst, unsigned int index); + game::scr_anim_s Scr_GetAnim(unsigned int index, game::XAnimTree_s* anims); + game::scr_animtree_t Scr_GetAnimTree(); + float Scr_GetFloat(game::scriptInstance_t inst, unsigned int index); + unsigned int Scr_GetConstString(game::scriptInstance_t inst, unsigned int index); + unsigned int Scr_GetConstLowercaseString(game::scriptInstance_t inst, unsigned int index); + const char* Scr_GetString(unsigned int index, game::scriptInstance_t inst); + unsigned int Scr_GetConstStringIncludeNull(game::scriptInstance_t inst); + char* Scr_GetDebugString(game::scriptInstance_t inst, unsigned int index); + unsigned int Scr_GetConstIString(unsigned int index); + void Scr_GetVector(game::scriptInstance_t inst, float* vectorValue, unsigned int index); + unsigned int Scr_GetFunc(); + game::scr_entref_t* Scr_GetEntityRef(game::scriptInstance_t inst, game::scr_entref_t* retstr, unsigned int index); + game::VariableUnion Scr_GetObject(game::scriptInstance_t inst); + game::VariableType Scr_GetType(game::scriptInstance_t inst, unsigned int index); + const char* Scr_GetTypeName(game::scriptInstance_t inst); + game::VariableType Scr_GetPointerType(game::scriptInstance_t inst, unsigned int index); + void Scr_AddInt(game::scriptInstance_t inst, int value); + void Scr_AddFloat(game::scriptInstance_t inst, float value); + void Scr_AddAnim(game::scr_anim_s value); + void Scr_AddUndefined(game::scriptInstance_t inst); + void Scr_AddObject(game::scriptInstance_t inst, unsigned int entid); + void Scr_AddString(game::scriptInstance_t inst, const char* string); + void Scr_AddIString(const char* string); + void Scr_AddConstString(game::scriptInstance_t inst, unsigned int id); + void Scr_AddVector(game::scriptInstance_t inst, float* value); + void Scr_MakeArray(game::scriptInstance_t inst); + void Scr_AddArray(game::scriptInstance_t inst); + void Scr_AddArrayStringIndexed(unsigned int id, game::scriptInstance_t inst); + void Scr_Error(const char* error, game::scriptInstance_t inst, int is_terminal); + void Scr_TerminalError(game::scriptInstance_t inst, const char* error); + void Scr_ParamError(unsigned int index, game::scriptInstance_t inst, const char* error); + void Scr_ObjectError(game::scriptInstance_t inst, const char* error); + bool SetEntityFieldValue(game::scriptInstance_t inst, int offset, int entnum, game::classNum_e classnum, int clientNum, game::VariableValue* value); + game::VariableValue GetEntityFieldValue(int offset, int entnum, game::scriptInstance_t inst, game::classNum_e classnum, int clientNum); + void Scr_SetStructField(unsigned int structId, unsigned int index, game::scriptInstance_t inst); + void Scr_IncTime(game::scriptInstance_t inst); + void Scr_RunCurrentThreads(game::scriptInstance_t inst); + void Scr_ResetTimeout(game::scriptInstance_t inst); + + void SetVariableFieldValue(game::scriptInstance_t inst, unsigned int id, game::VariableValue* value); + void SetNewVariableValue(game::scriptInstance_t inst, unsigned int id, game::VariableValue* value); + void Scr_ClearErrorMessage(game::scriptInstance_t inst); + void VM_Shutdown(game::scriptInstance_t inst); + void Scr_ShutdownVariables(game::scriptInstance_t inst); + void ClearVariableValue(game::scriptInstance_t inst, unsigned int id); + unsigned int Scr_GetThreadNotifyName(game::scriptInstance_t inst, unsigned int startLocalId); + void Scr_RemoveThreadNotifyName(game::scriptInstance_t inst, unsigned int startLocalId); + unsigned int GetArraySize(game::scriptInstance_t inst, unsigned int id); + void IncInParam(game::scriptInstance_t inst); + unsigned int GetParentLocalId(game::scriptInstance_t inst, unsigned int threadId); + void Scr_ClearWaitTime(game::scriptInstance_t inst, unsigned int startLocalId); + void Scr_SetThreadWaitTime(game::scriptInstance_t inst, unsigned int startLocalId, unsigned int waitTime); + void Scr_SetThreadNotifyName(game::scriptInstance_t inst, unsigned int startLocalId, unsigned int stringValue); + void Scr_DebugTerminateThread(game::scriptInstance_t inst, int topThread); + unsigned int Scr_GetThreadWaitTime(game::scriptInstance_t inst, unsigned int startLocalId); + const char* Scr_GetStackThreadPos(game::scriptInstance_t inst, unsigned int endLocalId, game::VariableStackBuffer* stackValue, bool killThread); + unsigned int Scr_GetSelf(game::scriptInstance_t inst, unsigned int threadId); + unsigned int GetVariableKeyObject(game::scriptInstance_t inst, unsigned int id); + int MT_Realloc(game::scriptInstance_t inst, int oldNumBytes, int newNumbytes); + void CScr_GetObjectField(game::classNum_e classnum, int entnum, int clientNum, int offset); + int CScr_SetObjectField(game::classNum_e classnum, int entnum, int clientNum, int offset); + void Scr_SetErrorMessage(game::scriptInstance_t inst, const char* error); + bool Scr_IsStackClear(game::scriptInstance_t inst); + void SL_CheckExists(game::scriptInstance_t inst, unsigned int stringValue); + const char* Scr_ReadCodePos(game::scriptInstance_t inst, const char** pos); + unsigned int Scr_ReadUnsignedInt(game::scriptInstance_t inst, const char** pos); + unsigned short Scr_ReadUnsignedShort(game::scriptInstance_t inst, const char** pos); + unsigned char Scr_ReadUnsignedByte(game::scriptInstance_t inst, const char** pos); + float Scr_ReadFloat(game::scriptInstance_t inst, const char** pos); + const float* Scr_ReadVector(game::scriptInstance_t inst, const char** pos); + BOOL IsFieldObject(game::scriptInstance_t inst, unsigned int id); + void RemoveVariableValue(game::scriptInstance_t inst, unsigned int parentId, unsigned int index); + game::VariableStackBuffer* GetRefVariableStackBuffer(game::scriptInstance_t inst, int id); + unsigned int GetNewObjectVariableReverse(game::scriptInstance_t inst, unsigned int parentId, unsigned int id); + unsigned int GetNewVariableIndexReverseInternal(game::scriptInstance_t inst, unsigned int parentId, unsigned int name); + unsigned int Scr_GetLocalVar(game::scriptInstance_t inst, int pos); + void Scr_EvalBoolNot(game::scriptInstance_t inst, game::VariableValue* value); + unsigned int GetInternalVariableIndex(game::scriptInstance_t inst, unsigned int unsignedValue); + const char* Scr_ReadData(game::scriptInstance_t inst, const char** pos, unsigned int count); + void Scr_NotifyNum(int entnum, game::classNum_e classnum, unsigned int stringValue, unsigned int paramcount); +} diff --git a/src/component/decomp/clientscript/re_cscr_main.cpp b/src/component/decomp/clientscript/re_cscr_main.cpp index cff8836..18bfbbd 100644 --- a/src/component/decomp/clientscript/re_cscr_main.cpp +++ b/src/component/decomp/clientscript/re_cscr_main.cpp @@ -5,7 +5,6 @@ #define RE_CSCR_MAIN_USE_WRAPPERS - namespace re_cscr_main { utils::hook::detour Scr_IsIdentifier_hook; diff --git a/src/component/decomp/clientscript/re_cscr_memorytree.cpp b/src/component/decomp/clientscript/re_cscr_memorytree.cpp index b3ca261..6d99e4f 100644 --- a/src/component/decomp/clientscript/re_cscr_memorytree.cpp +++ b/src/component/decomp/clientscript/re_cscr_memorytree.cpp @@ -1,7 +1,7 @@ #include #include "loader/component_loader.hpp" #include "utils/hook.hpp" -//#include "codsrc/clientscript/cscr_memorytree.hpp" +#include "codsrc/clientscript/cscr_memorytree.hpp" #define RE_CSCR_MEMORYTREE_USE_WRAPPERS diff --git a/src/component/decomp/clientscript/re_cscr_parser.cpp b/src/component/decomp/clientscript/re_cscr_parser.cpp index ab277f2..8a35e19 100644 --- a/src/component/decomp/clientscript/re_cscr_parser.cpp +++ b/src/component/decomp/clientscript/re_cscr_parser.cpp @@ -1,7 +1,7 @@ #include #include "loader/component_loader.hpp" #include "utils/hook.hpp" -//#include "codsrc/clientscript/cscr_parser.hpp" +#include "codsrc/clientscript/cscr_parser.hpp" #define RE_CSCR_PARSER_USE_WRAPPERS diff --git a/src/component/decomp/clientscript/re_cscr_parsetree.cpp b/src/component/decomp/clientscript/re_cscr_parsetree.cpp index 118dc5d..b776ce4 100644 --- a/src/component/decomp/clientscript/re_cscr_parsetree.cpp +++ b/src/component/decomp/clientscript/re_cscr_parsetree.cpp @@ -1,11 +1,10 @@ #include #include "loader/component_loader.hpp" #include "utils/hook.hpp" -//#include "codsrc/clientscript/cscr_parsetree.hpp" +#include "codsrc/clientscript/cscr_parsetree.hpp" #define RE_CSCR_PARSETREE_USE_WRAPPERS - namespace re_cscr_parsetree { utils::hook::detour Scr_InitAllocNode_hook; diff --git a/src/component/decomp/clientscript/re_cscr_readwrite.cpp b/src/component/decomp/clientscript/re_cscr_readwrite.cpp index 3d8b6bb..b8defb8 100644 --- a/src/component/decomp/clientscript/re_cscr_readwrite.cpp +++ b/src/component/decomp/clientscript/re_cscr_readwrite.cpp @@ -1,7 +1,7 @@ #include #include "loader/component_loader.hpp" #include "utils/hook.hpp" -//#include "codsrc/clientscript/cscr_readwrite.hpp" +#include "codsrc/clientscript/cscr_readwrite.hpp" #define RE_CSCR_READWRITE_USE_WRAPPERS diff --git a/src/component/decomp/clientscript/re_cscr_stringlist.cpp b/src/component/decomp/clientscript/re_cscr_stringlist.cpp index a88604f..fc67398 100644 --- a/src/component/decomp/clientscript/re_cscr_stringlist.cpp +++ b/src/component/decomp/clientscript/re_cscr_stringlist.cpp @@ -1,11 +1,10 @@ #include #include "loader/component_loader.hpp" #include "utils/hook.hpp" -//#include "codsrc/clientscript/cscr_stringlist.hpp" +#include "codsrc/clientscript/cscr_stringlist.hpp" #define RE_CSCR_STRINGLIST_USE_WRAPPERS - namespace re_cscr_stringlist { utils::hook::detour SL_ConvertToString_hook; diff --git a/src/component/decomp/clientscript/re_cscr_variable.cpp b/src/component/decomp/clientscript/re_cscr_variable.cpp index 84d03da..28425ff 100644 --- a/src/component/decomp/clientscript/re_cscr_variable.cpp +++ b/src/component/decomp/clientscript/re_cscr_variable.cpp @@ -1,11 +1,10 @@ #include #include "loader/component_loader.hpp" #include "utils/hook.hpp" -//#include "codsrc/clientscript/cscr_variable.hpp" +#include "codsrc/clientscript/cscr_variable.hpp" #define RE_CSCR_VARIABLE_USE_WRAPPERS - namespace re_cscr_variable { utils::hook::detour ThreadInfoCompare_hook; @@ -563,7 +562,7 @@ namespace re_cscr_variable } } - unsigned int AllocEntity_call(int classnum, game::scriptInstance_t inst, [[maybe_unused]] void* caller_addr, int entnum, unsigned int clientnum) + unsigned int AllocEntity_call(game::classNum_e classnum, game::scriptInstance_t inst, [[maybe_unused]] void* caller_addr, int entnum, unsigned int clientnum) { #ifdef RE_CSCR_VARIABLE_USE_WRAPPERS return game::AllocEntity(classnum, inst, entnum, clientnum, AllocEntity_original); @@ -1774,7 +1773,7 @@ namespace re_cscr_variable } } - void Scr_FreeEntityNum_call(game::scriptInstance_t inst, unsigned int classnum, [[maybe_unused]] void* caller_addr, unsigned int entnum) + void Scr_FreeEntityNum_call(game::scriptInstance_t inst, game::classNum_e classnum, [[maybe_unused]] void* caller_addr, unsigned int entnum) { #ifdef RE_CSCR_VARIABLE_USE_WRAPPERS game::Scr_FreeEntityNum(inst, classnum, entnum, Scr_FreeEntityNum_original); @@ -1814,7 +1813,7 @@ namespace re_cscr_variable #endif } - void Scr_SetClassMap_call(game::scriptInstance_t a1, [[maybe_unused]] void* caller_addr, unsigned int a2) + void Scr_SetClassMap_call(game::scriptInstance_t a1, [[maybe_unused]] void* caller_addr, game::classNum_e a2) { #ifdef RE_CSCR_VARIABLE_USE_WRAPPERS game::Scr_SetClassMap(a1, a2, Scr_SetClassMap_original); @@ -1835,7 +1834,7 @@ namespace re_cscr_variable } } - void Scr_RemoveClassMap_call(unsigned int result, game::scriptInstance_t a2, [[maybe_unused]] void* caller_addr) + void Scr_RemoveClassMap_call(game::classNum_e result, game::scriptInstance_t a2, [[maybe_unused]] void* caller_addr) { #ifdef RE_CSCR_VARIABLE_USE_WRAPPERS game::Scr_RemoveClassMap(result, a2, Scr_RemoveClassMap_original); @@ -1857,7 +1856,7 @@ namespace re_cscr_variable } } - void Scr_AddClassField_call(game::scriptInstance_t inst, unsigned int a2, [[maybe_unused]] void* caller_addr, const char * name, unsigned int a4) + void Scr_AddClassField_call(game::scriptInstance_t inst, game::classNum_e a2, [[maybe_unused]] void* caller_addr, const char * name, unsigned int a4) { #ifdef RE_CSCR_VARIABLE_USE_WRAPPERS game::Scr_AddClassField(inst, a2, name, a4, Scr_AddClassField_original); @@ -2310,41 +2309,34 @@ namespace re_cscr_variable AllocValue_hook.create(game::AllocValue_ADDR(), AllocValue_stub); AllocEntity_hook.create(game::AllocEntity_ADDR(), AllocEntity_stub); Scr_AllocArray_hook.create(game::Scr_AllocArray_ADDR(), Scr_AllocArray_stub); - AllocChildThread_hook.create(game::AllocChildThread_ADDR(), AllocChildThread_stub); FreeValue_hook.create(game::FreeValue_ADDR(), FreeValue_stub); RemoveRefToObject_hook.create(game::RemoveRefToObject_ADDR(), RemoveRefToObject_stub); Scr_AllocVector_hook.create(game::Scr_AllocVector_ADDR(), Scr_AllocVector_stub); RemoveRefToVector_hook.create(game::RemoveRefToVector_ADDR(), RemoveRefToVector_stub); - AddRefToValue_hook.create(game::AddRefToValue_ADDR(), AddRefToValue_stub); RemoveRefToValueInternal_hook.create(game::RemoveRefToValueInternal.get(), RemoveRefToValueInternal_stub); FindArrayVariable_hook.create(game::FindArrayVariable_ADDR(), FindArrayVariable_stub); FindVariable_hook.create(game::FindVariable_ADDR(), FindVariable_stub); - GetArrayVariableIndex_hook.create(game::GetArrayVariableIndex_ADDR(), GetArrayVariableIndex_stub); Scr_GetVariableFieldIndex_hook.create(game::Scr_GetVariableFieldIndex_ADDR(), Scr_GetVariableFieldIndex_stub); Scr_FindVariableField_hook.create(game::Scr_FindVariableField_ADDR(), Scr_FindVariableField_stub); ClearVariableField_hook.create(game::ClearVariableField_ADDR(), ClearVariableField_stub); GetVariable_hook.create(game::GetVariable_ADDR(), GetVariable_stub); - GetNewVariable_hook.create(game::GetNewVariable_ADDR(), GetNewVariable_stub); GetObjectVariable_hook.create(game::GetObjectVariable_ADDR(), GetObjectVariable_stub); GetNewObjectVariable_hook.create(game::GetNewObjectVariable_ADDR(), GetNewObjectVariable_stub); RemoveVariable_hook.create(game::RemoveVariable_ADDR(), RemoveVariable_stub); RemoveNextVariable_hook.create(game::RemoveNextVariable_ADDR(), RemoveNextVariable_stub); SafeRemoveVariable_hook.create(game::SafeRemoveVariable_ADDR(), SafeRemoveVariable_stub); - CopyArray_hook.create(game::CopyArray.get(), CopyArray_stub); SetVariableValue_hook.create(game::SetVariableValue_ADDR(), SetVariableValue_stub); SetVariableEntityFieldValue_hook.create(game::SetVariableEntityFieldValue.get(), SetVariableEntityFieldValue_stub); Scr_EvalVariable_hook.create(game::Scr_EvalVariable_ADDR(), Scr_EvalVariable_stub); - Scr_EvalVariableObject_hook.create(game::Scr_EvalVariableObject_ADDR(), Scr_EvalVariableObject_stub); Scr_EvalVariableEntityField_hook.create(game::Scr_EvalVariableEntityField_ADDR(), Scr_EvalVariableEntityField_stub); Scr_EvalVariableField_hook.create(game::Scr_EvalVariableField_ADDR(), Scr_EvalVariableField_stub); Scr_EvalSizeValue_hook.create(game::Scr_EvalSizeValue_ADDR(), Scr_EvalSizeValue_stub); - GetObject_hook.create(game::GetObject_ADDR(), GetObject_stub); GetArray_hook.create(game::GetArray_ADDR(), GetArray_stub); Scr_EvalBoolComplement_hook.create(game::Scr_EvalBoolComplement_ADDR(), Scr_EvalBoolComplement_stub); @@ -2353,7 +2345,6 @@ namespace re_cscr_variable Scr_CastDebugString_hook.create(game::Scr_CastDebugString_ADDR(), Scr_CastDebugString_stub); Scr_ClearVector_hook.create(game::Scr_ClearVector.get(), Scr_ClearVector_stub); Scr_CastVector_hook.create(game::Scr_CastVector_ADDR(), Scr_CastVector_stub); - Scr_EvalFieldObject_hook.create(game::Scr_EvalFieldObject_ADDR(), Scr_EvalFieldObject_stub); Scr_UnmatchingTypesError_hook.create(game::Scr_UnmatchingTypesError_ADDR(), Scr_UnmatchingTypesError_stub); Scr_CastWeakerPair_hook.create(game::Scr_CastWeakerPair_ADDR(), Scr_CastWeakerPair_stub); @@ -2371,18 +2362,13 @@ namespace re_cscr_variable Scr_EvalPlus_hook.create(game::Scr_EvalPlus_ADDR(), Scr_EvalPlus_stub); Scr_EvalMinus_hook.create(game::Scr_EvalMinus_ADDR(), Scr_EvalMinus_stub); Scr_EvalMultiply_hook.create(game::Scr_EvalMultiply_ADDR(), Scr_EvalMultiply_stub); - Scr_EvalDivide_hook.create(game::Scr_EvalDivide_ADDR(), Scr_EvalDivide_stub); Scr_EvalMod_hook.create(game::Scr_EvalMod_ADDR(), Scr_EvalMod_stub); - Scr_EvalBinaryOperator_hook.create(game::Scr_EvalBinaryOperator_ADDR(), Scr_EvalBinaryOperator_stub); - Scr_FreeEntityNum_hook.create(game::Scr_FreeEntityNum_ADDR(), Scr_FreeEntityNum_stub); - Scr_FreeEntityList_hook.create(game::Scr_FreeEntityList.get(), Scr_FreeEntityList_stub); Scr_FreeObjects_hook.create(game::Scr_FreeObjects.get(), Scr_FreeObjects_stub); Scr_SetClassMap_hook.create(game::Scr_SetClassMap_ADDR(), Scr_SetClassMap_stub); - Scr_RemoveClassMap_hook.create(game::Scr_RemoveClassMap_ADDR(), Scr_RemoveClassMap_stub); Scr_AddClassField_hook.create(game::Scr_AddClassField_ADDR(), Scr_AddClassField_stub); Scr_GetOffset_hook.create(game::Scr_GetOffset_ADDR(), Scr_GetOffset_stub); @@ -2390,19 +2376,15 @@ namespace re_cscr_variable Scr_GetEntityId_hook.create(game::Scr_GetEntityId_ADDR(), Scr_GetEntityId_stub); Scr_FindArrayIndex_hook.create(game::Scr_FindArrayIndex_ADDR(), Scr_FindArrayIndex_stub); Scr_EvalArray_hook.create(game::Scr_EvalArray_ADDR(), Scr_EvalArray_stub); - Scr_EvalArrayRef_hook.create(game::Scr_EvalArrayRef_ADDR(), Scr_EvalArrayRef_stub); ClearArray_hook.create(game::ClearArray_ADDR(), ClearArray_stub); - SetEmptyArray_hook.create(game::SetEmptyArray_ADDR(), SetEmptyArray_stub); Scr_AddArrayKeys_hook.create(game::Scr_AddArrayKeys.get(), Scr_AddArrayKeys_stub); Scr_GetEntityIdRef_hook.create(game::Scr_GetEntityIdRef_ADDR(), Scr_GetEntityIdRef_stub); CopyEntity_hook.create(game::CopyEntity_ADDR(), CopyEntity_stub); - Scr_GetEndonUsage_hook.create(game::Scr_GetEndonUsage_ADDR(), Scr_GetEndonUsage_stub); Scr_GetObjectUsage_hook.create(game::Scr_GetObjectUsage.get(), Scr_GetObjectUsage_stub); Scr_GetThreadUsage_hook.create(game::Scr_GetThreadUsage_ADDR(), Scr_GetThreadUsage_stub); - Scr_FindField_hook.create(game::Scr_FindField_ADDR(), Scr_FindField_stub); Scr_GetSourceFile_LoadObj_hook.create(game::Scr_GetSourceFile_LoadObj.get(), Scr_GetSourceFile_LoadObj_stub); Scr_GetSourceFile_FastFile_hook.create(game::Scr_GetSourceFile_FastFile.get(), Scr_GetSourceFile_FastFile_stub); diff --git a/src/component/decomp/clientscript/re_cscr_vm.cpp b/src/component/decomp/clientscript/re_cscr_vm.cpp index d6e78f9..66382ec 100644 --- a/src/component/decomp/clientscript/re_cscr_vm.cpp +++ b/src/component/decomp/clientscript/re_cscr_vm.cpp @@ -1,7 +1,7 @@ #include #include "loader/component_loader.hpp" #include "utils/hook.hpp" -//#include "codsrc/clientscript/cscr_vm.hpp" +#include "codsrc/clientscript/cscr_vm.hpp" #define RE_CSCR_VM_USE_WRAPPERS @@ -1552,7 +1552,6 @@ namespace re_cscr_vm VM_Notify_hook.create(game::VM_Notify_ADDR(), VM_Notify_stub); Scr_NotifyNum_Internal_hook.create(game::Scr_NotifyNum_Internal_ADDR(), Scr_NotifyNum_Internal_stub); Scr_CancelNotifyList_hook.create(game::Scr_CancelNotifyList_ADDR(), Scr_CancelNotifyList_stub); - VM_TerminateTime_hook.create(game::VM_TerminateTime_ADDR(), VM_TerminateTime_stub); VM_Resume_hook.create(game::VM_Resume_ADDR(), VM_Resume_stub); VM_Execute_hook.create(game::VM_Execute.get(), VM_Execute_stub); diff --git a/src/game/clientscript/clientscript_public.hpp b/src/game/clientscript/clientscript_public.hpp index 15e449f..648b552 100644 --- a/src/game/clientscript/clientscript_public.hpp +++ b/src/game/clientscript/clientscript_public.hpp @@ -20,11 +20,11 @@ #define VARIABLELIST_CHILD_BEGIN 0x6000 #define IsObject(__parentValue__) \ - ((__parentValue__->w.status & VAR_MASK) >= VAR_THREAD) \ + ((__parentValue__->w.status & VAR_MASK) >= game::VAR_THREAD) \ #define MT_NODE_BITS 16 -#define MT_NODE_SIZE sizeof(MemoryNode) -#define MT_SIZE sizeof(scrMemTreeGlob_t::nodes) +#define MT_NODE_SIZE sizeof(game::MemoryNode) +#define MT_SIZE sizeof(game::scrMemTreeGlob_t::nodes) #define MT_NODE_COUNT (1 << MT_NODE_BITS) #define MT_NUM_BUCKETS 256 @@ -36,6 +36,8 @@ #define SL_MAX_STRING_LEN 0x2000 #define SL_MAX_STRING_INDEX 0x10000 +#define MAX_VM_STACK_DEPTH 30 + #ifdef __cplusplus namespace game { @@ -51,6 +53,7 @@ namespace game struct sentient_s; struct gclient_s; struct game_hudelem_s; + struct dvar_s; #pragma region "enums" @@ -70,6 +73,13 @@ namespace game SCRIPT_INSTANCE_MAX = 0x2, }; + enum animUserInstance_t + { + ANIM_USER_CLIENT = 0x0, + ANIM_USER_SERVER = 0x1, + ANIM_USER_COUNT = 0x2 + }; + enum OpcodeVM : __int32 { OP_End = 0x0, @@ -335,6 +345,16 @@ namespace game FIRST_OBJECT = 0x14, };*/ + enum ObjectTypes + { + FIRST_OBJECT = 0xD, + FIRST_CLEARABLE_OBJECT = 0x11, + LAST_NONENTITY_OBJECT = 0x11, + FIRST_ENTITY_OBJECT = 0x13, + FIRST_NONFIELD_OBJECT = 0x14, + FIRST_DEAD_OBJECT = 0x15, + }; + enum VariableType { VAR_UNDEFINED = 0x0, @@ -2231,6 +2251,8 @@ namespace game WEAK symbol gScrClassMap{ 0x0, 0x8CF568 }; WEAK symbol scr_const{ 0x0, 0x1F33B90 }; WEAK symbol loadedImpureScript{ 0x0, 0x22C1352 }; + WEAK symbol sv_clientside{ 0x0, 0x3882B6C }; + WEAK symbol error_message_buff{ 0x0, 0x3BE1E30 }; WEAK symbol g_parse_user{ 0x0, 0x234F72E }; WEAK symbol gInst{ 0x0, 0x3BE624C }; @@ -2272,7 +2294,7 @@ namespace game #pragma endregion #pragma region "functions" - WEAK symbolHunk_UserDestroy{ 0x0, 0x5E4940 }; + WEAK symbolRemoveRefToValue{ 0x0, 0x67EB70 }; inline void* ScriptParse_ADDR() { return CALL_ADDR(0x0, 0x69D710); } void ScriptParse(scriptInstance_t inst, sval_u* parseData, void* call_addr = ScriptParse_ADDR()); @@ -2280,8 +2302,15 @@ namespace game void ScriptCompile(scriptInstance_t inst, sval_u val, unsigned int filePosId, unsigned int fileCountId, unsigned int scriptId, PrecacheEntry * entries, int entriesCount, void* call_addr = ScriptCompile_ADDR()); inline void* Scr_LoadAnimTreeAtIndex_ADDR() { return CALL_ADDR(0x0, 0x67E7D0); } void Scr_LoadAnimTreeAtIndex(scriptInstance_t inst, int user, unsigned int index, void* (__cdecl* Alloc)(int), int modCheckSum, void* call_addr = Scr_LoadAnimTreeAtIndex_ADDR()); - inline void* Hunk_UserCreate_ADDR() { return CALL_ADDR(0x0, 0x5E46E0); } - HunkUser* Hunk_UserCreate(signed int maxSize, const char* name, int fixed, int tempMem, int debugMem, int type, void* call_addr = Hunk_UserCreate_ADDR()); + + inline void* CScr_SetEntityField_ADDR() { return CALL_ADDR(0x0, 0x671470); } + int CScr_SetEntityField(int ofs, int entnum, unsigned int clientnum, void* call_addr = CScr_SetEntityField_ADDR()); + inline void* Scr_SetObjectField_ADDR() { return CALL_ADDR(0x0, 0x5469C0); } + int Scr_SetObjectField(int ofs, int entnum, classNum_e classnum, scriptInstance_t inst, void* call_addr = Scr_SetObjectField_ADDR()); + inline void* CScr_GetEntityField_ADDR() { return CALL_ADDR(0x0, 0x671410); } + void CScr_GetEntityField(int ofs, int entnum, unsigned int clientnum, void* call_addr = CScr_GetEntityField_ADDR()); + inline void* Scr_GetObjectField_ADDR() { return CALL_ADDR(0x0, 0x546D30); } + void Scr_GetObjectField(int ofs, int inst, classNum_e classnum, int entnum, void* call_addr = Scr_GetObjectField_ADDR()); #pragma endregion } diff --git a/src/game/clientscript/clientscript_public_w.cpp b/src/game/clientscript/clientscript_public_w.cpp index 73215b6..27e228e 100644 --- a/src/game/clientscript/clientscript_public_w.cpp +++ b/src/game/clientscript/clientscript_public_w.cpp @@ -46,24 +46,63 @@ namespace game } } - // HunkUser* __usercall Hunk_UserCreate@(signed int maxSize@, char* name, char fixed, char tempMem, char debugMem, int type); - HunkUser* Hunk_UserCreate(signed int maxSize, const char* name, int fixed, int tempMem, int debugMem, int typ, void* call_addr) + int CScr_SetEntityField/*@*/(int ofs/*@*/, int entnum/*@*/, unsigned int clientnum, void* call_addr) { - HunkUser* answer; + int answer; __asm { - push typ; - push debugMem; - push tempMem; - push fixed; - push name; - mov edi, maxSize; + push clientnum; + mov edx, ofs; + mov ecx, entnum; call call_addr; - add esp, 0x14; mov answer, eax; + add esp, 0x4; } return answer; } + + int Scr_SetObjectField/*@*/(int ofs/*@*/, int entnum/*@*/, classNum_e classnum, scriptInstance_t inst, void* call_addr) + { + int answer; + + __asm + { + push inst; + push classnum; + mov eax, ofs; + mov edx, entnum; + call call_addr; + mov answer, eax; + add esp, 0x8; + } + + return answer; + } + + void CScr_GetEntityField(int ofs/*@*/, int entnum/*@*/, unsigned int clientnum, void* call_addr) + { + __asm + { + push clientnum; + mov edx, ofs; + mov ecx, entnum; + call call_addr; + add esp, 0x4; + } + } + + void Scr_GetObjectField(int ofs/*@*/, int inst/*@*/, classNum_e classnum, int entnum, void* call_addr) + { + __asm + { + push entnum; + push classnum; + mov eax, ofs; + mov edx, inst; + call call_addr; + add esp, 0x8; + } + } } \ No newline at end of file diff --git a/src/game/clientscript/cscr_memorytree.hpp b/src/game/clientscript/cscr_memorytree.hpp index 23e6b5b..7692d01 100644 --- a/src/game/clientscript/cscr_memorytree.hpp +++ b/src/game/clientscript/cscr_memorytree.hpp @@ -27,5 +27,4 @@ namespace game char* MT_Alloc(int numBytes, scriptInstance_t inst, void* call_addr = MT_Alloc_ADDR()); RefVector* GetRefVector(scriptInstance_t inst, unsigned int id); - const char* MT_NodeInfoString(scriptInstance_t inst, unsigned int nodeNum); } \ No newline at end of file diff --git a/src/game/clientscript/cscr_memorytree_w.cpp b/src/game/clientscript/cscr_memorytree_w.cpp index d4a7c73..167d751 100644 --- a/src/game/clientscript/cscr_memorytree_w.cpp +++ b/src/game/clientscript/cscr_memorytree_w.cpp @@ -1,4 +1,5 @@ #include +#include "codsrc/clientscript/cscr_memorytree.hpp" namespace game { @@ -116,13 +117,6 @@ namespace game RefVector* GetRefVector(scriptInstance_t inst, unsigned int id) { - //return cscr_memorytree::GetRefVector(inst, id); - return nullptr; - } - - const char* MT_NodeInfoString(scriptInstance_t inst, unsigned int nodeNum) - { - //return cscr_memorytree::MT_NodeInfoString(inst, nodeNum); - return nullptr; + return codsrc::GetRefVector(inst, id); } } \ No newline at end of file diff --git a/src/game/clientscript/cscr_parser_w.cpp b/src/game/clientscript/cscr_parser_w.cpp index b739255..d246b4d 100644 --- a/src/game/clientscript/cscr_parser_w.cpp +++ b/src/game/clientscript/cscr_parser_w.cpp @@ -1,4 +1,5 @@ #include +#include "codsrc/clientscript/cscr_parser.hpp" namespace game { @@ -305,12 +306,11 @@ namespace game unsigned int Scr_GetPrevSourcePos(scriptInstance_t inst, const char* codePos, unsigned int index) { - //return cscr_parser::Scr_GetPrevSourcePos(inst, codePos, index); - return 0; + return codsrc::Scr_GetPrevSourcePos(inst, codePos, index); } void Scr_ShutdownAllocNode(scriptInstance_t inst) { - //cscr_parser::Scr_ShutdownAllocNode(inst); + codsrc::Scr_ShutdownAllocNode(inst); } } \ No newline at end of file diff --git a/src/game/clientscript/cscr_parsetree_w.cpp b/src/game/clientscript/cscr_parsetree_w.cpp index 57102ee..657baad 100644 --- a/src/game/clientscript/cscr_parsetree_w.cpp +++ b/src/game/clientscript/cscr_parsetree_w.cpp @@ -1,10 +1,10 @@ #include +#include "codsrc/clientscript/cscr_parsetree.hpp" namespace game { sval_u* Scr_AllocNode(scriptInstance_t inst, int size) { - //return cscr_parsetree::Scr_AllocNode(inst, size); - return nullptr; + return codsrc::Scr_AllocNode(inst, size); } } \ No newline at end of file diff --git a/src/game/clientscript/cscr_readwrite_w.cpp b/src/game/clientscript/cscr_readwrite_w.cpp index 5f8611a..9341900 100644 --- a/src/game/clientscript/cscr_readwrite_w.cpp +++ b/src/game/clientscript/cscr_readwrite_w.cpp @@ -1,4 +1,5 @@ #include +#include "codsrc/clientscript/cscr_readwrite.hpp" namespace game { @@ -38,7 +39,6 @@ namespace game unsigned int FindVariableIndexInternal(scriptInstance_t inst, unsigned int parentId, unsigned int name) { - //return cscr_readwrite::FindVariableIndexInternal(inst, parentId, name); - return 0; + return codsrc::FindVariableIndexInternal(inst, parentId, name); } } \ No newline at end of file diff --git a/src/game/clientscript/cscr_stringlist.hpp b/src/game/clientscript/cscr_stringlist.hpp index 8da4e67..701ba65 100644 --- a/src/game/clientscript/cscr_stringlist.hpp +++ b/src/game/clientscript/cscr_stringlist.hpp @@ -61,5 +61,4 @@ namespace game int SL_ConvertFromString(scriptInstance_t inst, const char* str); int SL_ConvertFromRefString(scriptInstance_t inst, RefString* refString); RefString* GetRefString_0(scriptInstance_t inst, const char* str); - const char* SL_DebugConvertToString(unsigned int stringValue, scriptInstance_t inst); } \ No newline at end of file diff --git a/src/game/clientscript/cscr_stringlist_w.cpp b/src/game/clientscript/cscr_stringlist_w.cpp index 9358456..71730fa 100644 --- a/src/game/clientscript/cscr_stringlist_w.cpp +++ b/src/game/clientscript/cscr_stringlist_w.cpp @@ -1,4 +1,5 @@ #include +#include "codsrc/clientscript/cscr_stringlist.hpp" namespace game { @@ -324,52 +325,41 @@ namespace game RefString* GetRefString(scriptInstance_t inst, unsigned int id) { - //return cscr_stringlist::GetRefString(inst, id); - return nullptr; + return codsrc::GetRefString(inst, id); } void SL_AddRefToString(scriptInstance_t inst, unsigned int stringValue) { - //cscr_stringlist::SL_AddRefToString(inst, stringValue); + codsrc::SL_AddRefToString(inst, stringValue); } void SL_RemoveRefToStringOfSize(scriptInstance_t inst, unsigned int stringValue, unsigned int len) { - //cscr_stringlist::SL_RemoveRefToStringOfSize(inst, stringValue, len); + codsrc::SL_RemoveRefToStringOfSize(inst, stringValue, len); } int SL_GetRefStringLen(RefString* refString) { - //return cscr_stringlist::SL_GetRefStringLen(refString); - return 0; + return codsrc::SL_GetRefStringLen(refString); } void SL_AddUser(unsigned int stringValue, unsigned int user, scriptInstance_t inst) { - //cscr_stringlist::SL_AddUser(stringValue, user, inst); + codsrc::SL_AddUser(stringValue, user, inst); } int SL_ConvertFromString(scriptInstance_t inst, const char* str) { - //return cscr_stringlist::SL_ConvertFromString(inst, str); - return 0; + return codsrc::SL_ConvertFromString(inst, str); } int SL_ConvertFromRefString(scriptInstance_t inst, RefString* refString) { - //return cscr_stringlist::SL_ConvertFromRefString(inst, refString); - return 0; + return codsrc::SL_ConvertFromRefString(inst, refString); } RefString* GetRefString_0(scriptInstance_t inst, const char* str) { - //return cscr_stringlist::GetRefString_0(inst, str); - return nullptr; - } - - const char* SL_DebugConvertToString(unsigned int stringValue, scriptInstance_t inst) - { - //return cscr_stringlist::SL_DebugConvertToString(stringValue, inst); - return nullptr; + return codsrc::GetRefString_0(inst, str); } } \ No newline at end of file diff --git a/src/game/clientscript/cscr_tempmemory_w.cpp b/src/game/clientscript/cscr_tempmemory_w.cpp index 3eb12a8..9a517de 100644 --- a/src/game/clientscript/cscr_tempmemory_w.cpp +++ b/src/game/clientscript/cscr_tempmemory_w.cpp @@ -1,20 +1,20 @@ #include +#include "codsrc/clientscript/cscr_tempmemory.hpp" namespace game { void TempMemorySetPos(char* pos) { - //cscr_tempmemory::TempMemorySetPos(pos); + codsrc::TempMemorySetPos(pos); } void TempMemoryReset(HunkUser* user) { - //cscr_tempmemory::TempMemoryReset(user); + codsrc::TempMemoryReset(user); } char* TempMalloc(int len) { - //return cscr_tempmemory::TempMalloc(len); - return nullptr; + return codsrc::TempMalloc(len); } } \ No newline at end of file diff --git a/src/game/clientscript/cscr_variable_w.cpp b/src/game/clientscript/cscr_variable_w.cpp index 6f8e5c6..a65e883 100644 --- a/src/game/clientscript/cscr_variable_w.cpp +++ b/src/game/clientscript/cscr_variable_w.cpp @@ -1,4 +1,5 @@ #include +#include "codsrc/clientscript/cscr_variable.hpp" namespace game { @@ -1286,174 +1287,151 @@ namespace game unsigned int FindObject(scriptInstance_t inst, unsigned int id) { - //return cscr_variable::FindObject(inst, id); - return 0; + return codsrc::FindObject(inst, id); } float Scr_GetEntryUsageInternal(scriptInstance_t inst, unsigned int type, VariableUnion u) { - //return cscr_variable::Scr_GetEntryUsageInternal(inst, type, u); - return 0; + return codsrc::Scr_GetEntryUsageInternal(inst, type, u); } float Scr_GetEntryUsage(scriptInstance_t inst, VariableValueInternal* entryValue) { - //return cscr_variable::Scr_GetEntryUsage(inst, entryValue); - return 0; + return codsrc::Scr_GetEntryUsage(inst, entryValue); } unsigned int FindFirstSibling(scriptInstance_t inst, unsigned int id) { - //return cscr_variable::FindFirstSibling(inst, id); - return 0; + return codsrc::FindFirstSibling(inst, id); } unsigned int FindNextSibling(scriptInstance_t inst, unsigned int id) { - //return cscr_variable::FindNextSibling(inst, id); - return 0; + return codsrc::FindNextSibling(inst, id); } VariableValue Scr_GetArrayIndexValue(scriptInstance_t inst, unsigned int name) { - //return cscr_variable::Scr_GetArrayIndexValue(inst, name); - VariableValue l; - l.type = VAR_UNDEFINED; - return l; + return codsrc::Scr_GetArrayIndexValue(inst, name); } void AddRefToObject(scriptInstance_t inst, unsigned int id) { - //cscr_variable::AddRefToObject(inst, id); + codsrc::AddRefToObject(inst, id); } void RemoveRefToEmptyObject(scriptInstance_t inst, unsigned int id) { - //cscr_variable::RemoveRefToEmptyObject(inst, id); + codsrc::RemoveRefToEmptyObject(inst, id); } void Scr_ClearThread(scriptInstance_t inst, unsigned int parentId) { - //cscr_variable::Scr_ClearThread(inst, parentId); + codsrc::Scr_ClearThread(inst, parentId); } unsigned int FindObjectVariable(scriptInstance_t inst, unsigned int parentId, unsigned int id) { - //return cscr_variable::FindObjectVariable(inst, parentId, id); - return 0; + return codsrc::FindObjectVariable(inst, parentId, id); } void RemoveObjectVariable(scriptInstance_t inst, unsigned int parentId, unsigned int id) { - //cscr_variable::RemoveObjectVariable(inst, parentId, id); + codsrc::RemoveObjectVariable(inst, parentId, id); } VariableValueInternal_u* GetVariableValueAddress(scriptInstance_t inst, unsigned int id) { - //return cscr_variable::GetVariableValueAddress(inst, id); - return nullptr; + return codsrc::GetVariableValueAddress(inst, id); } void Scr_KillEndonThread(scriptInstance_t inst, unsigned int threadId) { - //cscr_variable::Scr_KillEndonThread(inst, threadId); + codsrc::Scr_KillEndonThread(inst, threadId); } BOOL IsValidArrayIndex(scriptInstance_t inst, unsigned int unsignedValue) { - //return cscr_variable::IsValidArrayIndex(inst, unsignedValue); - return 0; + return codsrc::IsValidArrayIndex(inst, unsignedValue); } void RemoveArrayVariable(scriptInstance_t inst, unsigned int parentId, unsigned int unsignedValue) { - //cscr_variable::RemoveArrayVariable(inst, parentId, unsignedValue); + codsrc::RemoveArrayVariable(inst, parentId, unsignedValue); } void SafeRemoveArrayVariable(scriptInstance_t inst, unsigned int parentId, unsigned int unsignedValue) { - //cscr_variable::SafeRemoveArrayVariable(inst, parentId, unsignedValue); + codsrc::SafeRemoveArrayVariable(inst, parentId, unsignedValue); } void AddRefToVector(scriptInstance_t inst, const float* floatVal) { - //cscr_variable::AddRefToVector(inst, floatVal); + codsrc::AddRefToVector(inst, floatVal); } unsigned int FindArrayVariableIndex(scriptInstance_t inst, unsigned int parentId, unsigned int unsignedValue) { - //return cscr_variable::FindArrayVariableIndex(inst, parentId, unsignedValue); - return 0; + return codsrc::FindArrayVariableIndex(inst, parentId, unsignedValue); } unsigned int GetVariableIndexInternal(scriptInstance_t inst, unsigned int parentId, unsigned int name) { - //return cscr_variable::GetVariableIndexInternal(inst, parentId, name); - return 0; + return codsrc::GetVariableIndexInternal(inst, parentId, name); } unsigned int GetNewVariableIndexInternal(scriptInstance_t inst, unsigned int parentId, unsigned int name) { - //return cscr_variable::GetNewVariableIndexInternal(inst, parentId, name); - return 0; + return codsrc::GetNewVariableIndexInternal(inst, parentId, name); } unsigned int AllocObject(scriptInstance_t inst) { - //return cscr_variable::AllocObject(inst); - return 0; + return codsrc::AllocObject(inst); } VariableType GetValueType(scriptInstance_t inst, unsigned int id) { - //return cscr_variable::GetValueType(inst, id); - return (VariableType)0; + return codsrc::GetValueType(inst, id); } VariableType GetObjectType(scriptInstance_t inst, unsigned int id) { - //return cscr_variable::GetObjectType(inst, id); - return (VariableType)0; + return codsrc::GetObjectType(inst, id); } float* Scr_AllocVector_(scriptInstance_t inst, const float* v) { - //return cscr_variable::Scr_AllocVector_(inst, v); - return 0; + return codsrc::Scr_AllocVector_(inst, v); } void Scr_EvalInequality(scriptInstance_t inst, VariableValue* value1, VariableValue* value2) { - //cscr_variable::Scr_EvalInequality(inst, value1, value2); + codsrc::Scr_EvalInequality(inst, value1, value2); } unsigned int Scr_EvalArrayRefInternal(scriptInstance_t inst, VariableValue* varValue, VariableValueInternal* parentValue) { - //return cscr_variable::Scr_EvalArrayRefInternal(inst, varValue, parentValue); - return 0; + return codsrc::Scr_EvalArrayRefInternal(inst, varValue, parentValue); } unsigned int GetNewArrayVariableIndex(scriptInstance_t inst, unsigned int parentId, unsigned int unsignedValue) { - //return cscr_variable::GetNewArrayVariableIndex(inst, parentId, unsignedValue); - return 0; + return codsrc::GetNewArrayVariableIndex(inst, parentId, unsignedValue); } unsigned int GetNewArrayVariable(scriptInstance_t inst, unsigned int parentId, unsigned int unsignedValue) { - //return cscr_variable::GetNewArrayVariable(inst, parentId, unsignedValue); - return 0; + return codsrc::GetNewArrayVariable(inst, parentId, unsignedValue); } unsigned int GetArrayVariable(scriptInstance_t inst, unsigned int parentId, unsigned int unsignedValue) { - //return cscr_variable::GetArrayVariable(inst, parentId, unsignedValue); - return 0; + return codsrc::GetArrayVariable(inst, parentId, unsignedValue); } unsigned int AllocThread(scriptInstance_t inst, unsigned int self) { - //return cscr_variable::AllocThread(inst, self); - return 0; + return codsrc::AllocThread(inst, self); } } diff --git a/src/game/clientscript/cscr_vm_w.cpp b/src/game/clientscript/cscr_vm_w.cpp index 455d6f6..b3874f2 100644 --- a/src/game/clientscript/cscr_vm_w.cpp +++ b/src/game/clientscript/cscr_vm_w.cpp @@ -1,4 +1,5 @@ #include +#include "codsrc/clientscript/cscr_vm.hpp" namespace game { @@ -783,224 +784,201 @@ namespace game void SetVariableFieldValue(scriptInstance_t inst, unsigned int id, VariableValue* value) { - //cscr_vm::SetVariableFieldValue(inst, id, value); + codsrc::SetVariableFieldValue(inst, id, value); } void SetNewVariableValue(scriptInstance_t inst, unsigned int id, VariableValue* value) { - //cscr_vm::SetNewVariableValue(inst, id, value); + codsrc::SetNewVariableValue(inst, id, value); } void Scr_ClearErrorMessage(scriptInstance_t inst) { - //cscr_vm::Scr_ClearErrorMessage(inst); + codsrc::Scr_ClearErrorMessage(inst); } void VM_Shutdown(scriptInstance_t inst) { - //cscr_vm::VM_Shutdown(inst); + codsrc::VM_Shutdown(inst); } void Scr_ShutdownVariables(scriptInstance_t inst) { - //cscr_vm::Scr_ShutdownVariables(inst); + codsrc::Scr_ShutdownVariables(inst); } void ClearVariableValue(scriptInstance_t inst, unsigned int id) { - //cscr_vm::ClearVariableValue(inst, id); + codsrc::ClearVariableValue(inst, id); } unsigned int Scr_GetThreadNotifyName(scriptInstance_t inst, unsigned int startLocalId) { - //return cscr_vm::Scr_GetThreadNotifyName(inst, startLocalId); - return 0; + return codsrc::Scr_GetThreadNotifyName(inst, startLocalId); } void Scr_RemoveThreadNotifyName(scriptInstance_t inst, unsigned int startLocalId) { - //cscr_vm::Scr_RemoveThreadNotifyName(inst, startLocalId); + codsrc::Scr_RemoveThreadNotifyName(inst, startLocalId); } unsigned int GetArraySize(scriptInstance_t inst, unsigned int id) { - //return cscr_vm::GetArraySize(inst, id); - return 0; + return codsrc::GetArraySize(inst, id); } void IncInParam(scriptInstance_t inst) { - //cscr_vm::IncInParam(inst); + codsrc::IncInParam(inst); } unsigned int GetParentLocalId(scriptInstance_t inst, unsigned int threadId) { - //return cscr_vm::GetParentLocalId(inst, threadId); - return 0; + return codsrc::GetParentLocalId(inst, threadId); } void Scr_ClearWaitTime(scriptInstance_t inst, unsigned int startLocalId) { - //cscr_vm::Scr_ClearWaitTime(inst, startLocalId); + codsrc::Scr_ClearWaitTime(inst, startLocalId); } void Scr_SetThreadWaitTime(scriptInstance_t inst, unsigned int startLocalId, unsigned int waitTime) { - //cscr_vm::Scr_SetThreadWaitTime(inst, startLocalId, waitTime); + codsrc::Scr_SetThreadWaitTime(inst, startLocalId, waitTime); } void Scr_SetThreadNotifyName(scriptInstance_t inst, unsigned int startLocalId, unsigned int stringValue) { - //cscr_vm::Scr_SetThreadNotifyName(inst, startLocalId, stringValue); + codsrc::Scr_SetThreadNotifyName(inst, startLocalId, stringValue); } void Scr_DebugTerminateThread(scriptInstance_t inst, int topThread) { - //cscr_vm::Scr_DebugTerminateThread(inst, topThread); + codsrc::Scr_DebugTerminateThread(inst, topThread); } unsigned int Scr_GetThreadWaitTime(scriptInstance_t inst, unsigned int startLocalId) { - //return cscr_vm::Scr_GetThreadWaitTime(inst, startLocalId); - return 0; + return codsrc::Scr_GetThreadWaitTime(inst, startLocalId); } const char* Scr_GetStackThreadPos(scriptInstance_t inst, unsigned int endLocalId, VariableStackBuffer* stackValue, bool killThread) { - //return cscr_vm::Scr_GetStackThreadPos(inst, endLocalId, stackValue, killThread); - return 0; + return codsrc::Scr_GetStackThreadPos(inst, endLocalId, stackValue, killThread); } unsigned int Scr_GetSelf(scriptInstance_t inst, unsigned int threadId) { - //return cscr_vm::Scr_GetSelf(inst, threadId); - return 0; + return codsrc::Scr_GetSelf(inst, threadId); } unsigned int GetVariableKeyObject(scriptInstance_t inst, unsigned int id) { - //return cscr_vm::GetVariableKeyObject(inst, id); - return 0; + return codsrc::GetVariableKeyObject(inst, id); } int MT_Realloc(scriptInstance_t inst, int oldNumBytes, int newNumbytes) { - //return cscr_vm::MT_Realloc(inst, oldNumBytes, newNumbytes); - return 0; + return codsrc::MT_Realloc(inst, oldNumBytes, newNumbytes); } void CScr_GetObjectField(classNum_e classnum, int entnum, int clientNum, int offset) { - //cscr_vm::CScr_GetObjectField(classnum, entnum, clientNum, offset); + codsrc::CScr_GetObjectField(classnum, entnum, clientNum, offset); } int CScr_SetObjectField(classNum_e classnum, int entnum, int clientNum, int offset) { - //return cscr_vm::CScr_SetObjectField(classnum, entnum, clientNum, offset); - return 0; + return codsrc::CScr_SetObjectField(classnum, entnum, clientNum, offset); } void Scr_SetErrorMessage(scriptInstance_t inst, const char* error) { - //cscr_vm::Scr_SetErrorMessage(inst, error); + codsrc::Scr_SetErrorMessage(inst, error); } bool Scr_IsStackClear(scriptInstance_t inst) { - //return cscr_vm::Scr_IsStackClear(inst); - return 0; + return codsrc::Scr_IsStackClear(inst); } void SL_CheckExists(scriptInstance_t inst, unsigned int stringValue) { - //cscr_vm::SL_CheckExists(inst, stringValue); + codsrc::SL_CheckExists(inst, stringValue); } const char* Scr_ReadCodePos(scriptInstance_t inst, const char** pos) { - //return cscr_vm::Scr_ReadCodePos(inst, pos); - return 0; + return codsrc::Scr_ReadCodePos(inst, pos); } unsigned int Scr_ReadUnsignedInt(scriptInstance_t inst, const char** pos) { - //return cscr_vm::Scr_ReadUnsignedInt(inst, pos); - return 0; + return codsrc::Scr_ReadUnsignedInt(inst, pos); } unsigned short Scr_ReadUnsignedShort(scriptInstance_t inst, const char** pos) { - //return cscr_vm::Scr_ReadUnsignedShort(inst, pos); - return 0; + return codsrc::Scr_ReadUnsignedShort(inst, pos); } unsigned char Scr_ReadUnsignedByte(scriptInstance_t inst, const char** pos) { - //return cscr_vm::Scr_ReadUnsignedByte(inst, pos); - return 0; + return codsrc::Scr_ReadUnsignedByte(inst, pos); } float Scr_ReadFloat(scriptInstance_t inst, const char** pos) { - //return cscr_vm::Scr_ReadFloat(inst, pos); - return 0; + return codsrc::Scr_ReadFloat(inst, pos); } const float* Scr_ReadVector(scriptInstance_t inst, const char** pos) { - //return cscr_vm::Scr_ReadVector(inst, pos); - return 0; + return codsrc::Scr_ReadVector(inst, pos); } BOOL IsFieldObject(scriptInstance_t inst, unsigned int id) { - //return cscr_vm::IsFieldObject(inst, id); - return 0; + return codsrc::IsFieldObject(inst, id); } void RemoveVariableValue(scriptInstance_t inst, unsigned int parentId, unsigned int index) { - //cscr_vm::RemoveVariableValue(inst, parentId, index); + codsrc::RemoveVariableValue(inst, parentId, index); } VariableStackBuffer* GetRefVariableStackBuffer(scriptInstance_t inst, int id) { - //return cscr_vm::GetRefVariableStackBuffer(inst, id); - return 0; + return codsrc::GetRefVariableStackBuffer(inst, id); } unsigned int GetNewVariableIndexReverseInternal(scriptInstance_t inst, unsigned int parentId, unsigned int name) { - //return cscr_vm::GetNewVariableIndexReverseInternal(inst, parentId, name); - return 0; + return codsrc::GetNewVariableIndexReverseInternal(inst, parentId, name); } unsigned int GetNewObjectVariableReverse(scriptInstance_t inst, unsigned int parentId, unsigned int id) { - //return cscr_vm::GetNewObjectVariableReverse(inst, parentId, id); - return 0; + return codsrc::GetNewObjectVariableReverse(inst, parentId, id); } unsigned int Scr_GetLocalVar(scriptInstance_t inst, int pos) { - //return cscr_vm::Scr_GetLocalVar(inst, pos); - return 0; + return codsrc::Scr_GetLocalVar(inst, pos); } void Scr_EvalBoolNot(scriptInstance_t inst, VariableValue* value) { - //cscr_vm::Scr_EvalBoolNot(inst, value); + codsrc::Scr_EvalBoolNot(inst, value); } unsigned int GetInternalVariableIndex(scriptInstance_t inst, unsigned int unsignedValue) { - //return cscr_vm::GetInternalVariableIndex(inst, unsignedValue); - return 0; + return codsrc::GetInternalVariableIndex(inst, unsignedValue); } const char* Scr_ReadData(scriptInstance_t inst, const char** pos, unsigned int count) { - //return cscr_vm::Scr_ReadData(inst, pos, count); - return 0; + return codsrc::Scr_ReadData(inst, pos, count); } } \ No newline at end of file diff --git a/src/game/game.cpp b/src/game/game.cpp index a9b73b6..f936880 100644 --- a/src/game/game.cpp +++ b/src/game/game.cpp @@ -23,6 +23,183 @@ namespace game } } + // HunkUser* __usercall Hunk_UserCreate@(signed int maxSize@, char* name, char fixed, char tempMem, char debugMem, int type); + HunkUser* Hunk_UserCreate(signed int maxSize, const char* name, int fixed, int tempMem, int debugMem, int typ, void* call_addr) + { + HunkUser* answer; + + __asm + { + push typ; + push debugMem; + push tempMem; + push fixed; + push name; + mov edi, maxSize; + call call_addr; + add esp, 0x14; + mov answer, eax; + } + + return answer; + } + + // unsigned int __usercall Hunk_AllocateTempMemoryHigh@(int a1@) + unsigned int Hunk_AllocateTempMemoryHigh(int size_, void* call_addr) + { + unsigned int answer; + + __asm + { + mov eax, size_; + call call_addr; + mov answer, eax; + } + + return answer; + } + + // void __usercall FS_FCloseFile(int h@) + void FS_FCloseFile(int h, void* call_addr) + { + __asm + { + mov eax, h; + call call_addr; + } + } + + // void *__usercall Z_TryVirtualAlloc@(signed int a1@) + void* Z_TryVirtualAlloc(signed int size_, void* call_addr) + { + void* answer; + + __asm + { + mov edi, size_; + call call_addr; + mov answer, eax; + } + + return answer; + } + + // int __usercall I_stricmp@(int a1@, CHAR *a2@, const char *a3) + int I_stricmp(int len, const char* s0, const char* s1, void* call_addr) + { + int answer; + + __asm + { + push s1; + mov eax, len; + mov edx, s0; + call call_addr; + mov answer, eax; + add esp, 0x4; + } + + return answer; + } + + //parseInfo_t* __usercall Com_Parse@(const char** a1@) + parseInfo_t* Com_Parse(const char** buffer, void* call_addr) + { + parseInfo_t* answer; + + __asm + { + mov esi, buffer; + call call_addr; + mov answer, eax; + } + + return answer; + } + + //int __usercall I_strncmp@(char *str1@, char *str2@, int len) + int I_strncmp(const char* str1, const char* str2, int len, void* call_addr) + { + int answer; + + __asm + { + push len; + mov ecx, str2; + mov edx, str1; + call call_addr; + mov answer, eax; + } + + return answer; + } + + // const char **__usercall FS_ListFilteredFiles@(searchpath_s *searchPath@, const char *path@, const char *extension, const char *filter, FsListBehavior_e behavior, int *numFiles) + const char** FS_ListFilteredFiles(searchpath_s* searchPath, const char* path, const char* extension, const char* filter, FsListBehavior_e behavior, int* numFiles, void* call_addr) + { + const char** answer; + + __asm + { + push numFiles; + push behavior; + push filter; + push extension; + mov eax, searchPath; + mov edx, path; + call call_addr; + mov answer, eax; + add esp, 0x10; + } + + return answer; + } + + dvar_s * Dvar_RegisterBool/*@*/(unsigned __int8 val/*@*/, const char * name/*@*/, int flags, const char * desc, void* call_addr) + { + dvar_s * answer; + + __asm + { + push desc; + push flags; + mov al, val; + mov edi, name; + call call_addr; + mov answer, eax; + add esp, 0x8; + } + + return answer; + } + + const char * XAnimGetAnimDebugName/*@*/(unsigned int animIndex/*@*/, XAnim_s * anims/*@*/, void* call_addr) + { + const char * answer; + + __asm + { + mov ecx, animIndex; + mov edx, anims; + call call_addr; + mov answer, eax; + } + + return answer; + } + + // restored + void Sys_EnterCriticalSection(CriticalSection critSect) + { + EnterCriticalSection(&s_criticalSection[critSect]); + } + + // restored + void Sys_LeaveCriticalSection(CriticalSection critSect) + { + LeaveCriticalSection(&s_criticalSection[critSect]); + } + namespace plutonium { } diff --git a/src/game/symbols.hpp b/src/game/symbols.hpp index df57a7d..b912a90 100644 --- a/src/game/symbols.hpp +++ b/src/game/symbols.hpp @@ -4,9 +4,69 @@ namespace game { // Functions WEAK symbol Com_Printf{ 0x0, 0x59A2C0 }; + WEAK symbolCom_PrintMessage{ 0x0, 0x59A170 }; + WEAK symbolCom_PrintWarning{ 0x0, 0x59A440 }; + WEAK symbolCom_PrintError{ 0x0, 0x59A380 }; + WEAK symbolCom_Error{ 0x0, 0x59AC50 }; + WEAK symbolSys_Error{ 0x0, 0x5FE8C0 }; + + WEAK symbolHunk_UserDestroy{ 0x0, 0x5E4940 }; + WEAK symbol Hunk_UserAlloc{ 0x0, 0x5E47B0 }; + WEAK symbol Hunk_ClearTempMemoryHigh{ 0x0, 0x5E4300 }; + + WEAK symbolFS_FOpenFileRead{ 0x0, 0x5DBD20 }; + WEAK symbolFS_Read{ 0x0, 0x5DBDF0 }; + WEAK symbolFS_FOpenFileByMode{ 0x0, 0x5DB630 }; + + WEAK symbolva{ 0x0, 0x5F6D80 }; + + WEAK symbolCom_BeginParseSession{ 0x0, 0x5F5830 }; + WEAK symbol Com_EndParseSession{ 0x0, 0x5F5910 }; + WEAK symbol Sys_Milliseconds{ 0x0, 0x603D40 }; + + WEAK symbolI_strncpyz{ 0x0, 0x7AA9C0 }; + + inline void* I_strncmp_ADDR() { return CALL_ADDR(0x0, 0x5F6A40); } + int I_strncmp(const char* str1, const char* str2, int len, void* call_addr = I_strncmp_ADDR()); + + inline void* Hunk_UserCreate_ADDR() { return CALL_ADDR(0x0, 0x5E46E0); } + HunkUser* Hunk_UserCreate(signed int maxSize, const char* name, int fixed, int tempMem, int debugMem, int type, void* call_addr = Hunk_UserCreate_ADDR()); + inline void* Hunk_AllocateTempMemoryHigh_ADDR() { return CALL_ADDR(0x0, 0x5E4220); } + unsigned int Hunk_AllocateTempMemoryHigh(int size_, void* call_addr = Hunk_AllocateTempMemoryHigh_ADDR()); + + inline void* FS_FCloseFile_ADDR() { return CALL_ADDR(0x0, 0x5DB060); } + void FS_FCloseFile(int h, void* call_addr = FS_FCloseFile_ADDR()); + inline void* FS_ListFilteredFiles_ADDR() { return CALL_ADDR(0x0, 0x5DC720); } + const char** FS_ListFilteredFiles(searchpath_s* searchPath, const char* path, const char* extension, const char* filter, FsListBehavior_e behavior, int* numFiles, void* call_addr = FS_ListFilteredFiles_ADDR()); + + inline void* Z_TryVirtualAlloc_ADDR() { return CALL_ADDR(0x0, 0x5E39D0); } + void* Z_TryVirtualAlloc(signed int size_, void* call_addr = Z_TryVirtualAlloc_ADDR()); + inline void* I_stricmp_ADDR() { return CALL_ADDR(0x0, 0x5F69E0); } + int I_stricmp(int len, const char* s0, const char* s1, void* call_addr = I_stricmp_ADDR()); + + inline void* Com_Parse_ADDR() { return CALL_ADDR(0x0, 0x5F61B0); } + parseInfo_t* Com_Parse(const char** buffer, void* call_addr = Com_Parse_ADDR()); + + inline void* Dvar_RegisterBool_ADDR() { return CALL_ADDR(0x0, 0x5EEE20); } + dvar_s * Dvar_RegisterBool(unsigned __int8 val, const char * name, int flags, const char * desc, void* call_addr = Dvar_RegisterBool_ADDR()); + + inline void* XAnimGetAnimDebugName_ADDR() { return CALL_ADDR(0x0, 0x60F850); } + const char * XAnimGetAnimDebugName(unsigned int animIndex, XAnim_s * anims, void* call_addr = XAnimGetAnimDebugName_ADDR()); + + void Sys_EnterCriticalSection(CriticalSection critSect); + void Sys_LeaveCriticalSection(CriticalSection critSect); // Variables - WEAK symbol tempServerCommandBuf{ 0x0, 0x2FCDC00 }; + WEAK symbol s_criticalSection{ 0x0, 0x2298D08 }; + WEAK symbol g_DebugHunkUser{ 0x0, 0x212B2EC }; + WEAK symbol useFastFile{ 0x0, 0x1F552FC }; + WEAK symbol fsh{ 0x0, 0x2126E20 }; + WEAK symbol fs_game{ 0x0, 0x2122B00 }; + WEAK symbol com_developer{ 0x0, 0x1F55288 }; + WEAK symbol statmon_related_bool{ 0x0, 0x2122B04 }; + WEAK symbol g_allocNodeUser{ 0x0, 0x3882B20 }; + WEAK symbol g_user{ 0x0, 0x3882B48 }; + WEAK symbol fs_searchpaths{ 0x0, 0x46E5044 }; namespace plutonium { diff --git a/src/game/xasset.hpp b/src/game/xasset.hpp index 6852073..490b09a 100644 --- a/src/game/xasset.hpp +++ b/src/game/xasset.hpp @@ -5418,5 +5418,6 @@ namespace game ASSERT_STRUCT_OFFSET(XZone, blocks, 0xC); #ifdef __cplusplus + WEAK symbolDB_FindXAssetHeader{ 0x0, 0x48DA30 }; } #endif diff --git a/src/stdinc.hpp b/src/stdinc.hpp index ec291d4..3d0e9e3 100644 --- a/src/stdinc.hpp +++ b/src/stdinc.hpp @@ -9,10 +9,9 @@ #pragma warning(disable: 4324) #pragma warning(disable: 4459) +#pragma warning(disable: 4611) #pragma warning(error: 4409) -#pragma warning(disable: 4100) // remove when decomp is imported - #define DLL_EXPORT extern "C" __declspec(dllexport) #define WIN32_LEAN_AND_MEAN #include @@ -36,6 +35,7 @@ #include #include #include +#include #ifdef max #undef max @@ -58,6 +58,7 @@ #pragma comment(lib, "urlmon.lib" ) #pragma comment(lib, "iphlpapi.lib") #pragma comment(lib, "Crypt32.lib") +#pragma comment(lib, "Winmm.lib") #include "utils/hexrays_defs.h"