2023-09-15 18:27:48 -06:00

5373 lines
157 KiB
C++

#include <stdinc.hpp>
#include "clientscript_public.hpp"
#include <component/gsc.hpp>
#pragma warning(push)
#pragma warning(disable: 4244)
namespace codsrc
{
// Completed
void RemoveRefToValue(game::scriptInstance_t inst, game::VariableValue* value)
{
game::RemoveRefToValueInternal(inst, value->type, value->u);
}
// Completed
void Scr_CompileRemoveRefToString(game::scriptInstance_t inst, unsigned int stringVal)
{
assert(stringVal);
if (!game::gScrCompileGlob[inst].bConstRefCount) // gScrCompilePub[inst].developer_statement != 3
{
game::SL_RemoveRefToString(stringVal, inst);
}
}
// Completed
void EmitCanonicalString(game::scriptInstance_t inst, unsigned int stringVal)
{
assert(stringVal);
game::gScrCompileGlob[inst].codePos = game::TempMalloc(2);
if ( game::gScrCompilePub[inst].developer_statement == 2 )
{
assert(!game::gScrVarPub[inst].developer_script);
game::Scr_CompileRemoveRefToString(inst, stringVal);
}
/*
else if ( gScrCompilePub[inst].developer_statement == 3 )
{
*(_WORD *)gScrCompileGlob[inst].codePos = Scr_CompileCanonicalString(inst, stringValue);
if ( !*(_WORD *)gScrCompileGlob[inst].codePos )
CompileError(inst, 0, "unknown field");
}
*/
else
{
if ( game::gScrCompileGlob[inst].bConstRefCount )
{
game::SL_AddRefToString(inst, stringVal);
}
*(short *)game::gScrCompileGlob[inst].codePos = game::SL_TransferToCanonicalString(inst, stringVal);
}
}
// Completed
void CompileTransferRefToString(unsigned int stringValue, game::scriptInstance_t inst, unsigned int user)
{
assert(stringValue);
if ( game::gScrCompilePub[inst].developer_statement == 2 )
{
game::Scr_CompileRemoveRefToString(inst, stringValue);
}
else // if ( gScrCompilePub[inst].developer_statement != 3 )
{
if ( game::gScrCompileGlob[inst].bConstRefCount )
{
game::SL_AddRefToString(inst, stringValue);
}
game::SL_TransferRefToUser(stringValue, user, inst);
}
}
// Completed
void EmitOpcode(game::scriptInstance_t inst, game::OpcodeVM op, int offset, int callType)
{
int valueIndex;
int value_count;
unsigned int index;
unsigned int indexa;
/*
if ( gScrCompilePub[inst].developer_statement == 3 )
{
gScrCompileGlob[inst].codePos = TempMalloc(1);
*gScrCompileGlob[inst].codePos = op;
return;
}
*/
if ( game::gScrCompilePub[inst].value_count )
{
value_count = game::gScrCompilePub[inst].value_count;
game::gScrCompilePub[inst].value_count = 0;
for ( valueIndex = 0;
valueIndex < value_count;
++valueIndex )
{
game::EmitValue(inst, &game::gScrCompileGlob[inst].value_start[valueIndex]);
}
}
game::gScrCompilePub[inst].allowedBreakpoint = (!game::gScrCompileGlob[inst].cumulOffset || callType == 2 || callType == 3);
game::gScrCompileGlob[inst].cumulOffset += offset;
if ( game::gScrCompileGlob[inst].maxOffset < game::gScrCompileGlob[inst].cumulOffset )
{
game::gScrCompileGlob[inst].maxOffset = game::gScrCompileGlob[inst].cumulOffset;
}
if ( callType && game::gScrCompileGlob[inst].maxCallOffset < game::gScrCompileGlob[inst].cumulOffset )
{
game::gScrCompileGlob[inst].maxCallOffset = game::gScrCompileGlob[inst].cumulOffset;
}
game::gScrVarPub[inst].checksum *= 31;
game::gScrVarPub[inst].checksum += op;
if ( game::gScrCompilePub[inst].opcodePos )
{
game::gScrCompileGlob[inst].codePos = game::gScrCompilePub[inst].opcodePos;
switch ( op )
{
case game::OP_EvalArray:
if ( *game::gScrCompilePub[inst].opcodePos == game::OP_EvalLocalVariableCached )
{
game::RemoveOpcodePos(inst);
*game::gScrCompilePub[inst].opcodePos = game::OP_EvalLocalArrayCached;
return;
}
index = *(unsigned __int8 *)game::gScrCompilePub[inst].opcodePos - game::OP_EvalLocalVariableCached0;
if ( index > 5 )
{
goto LABEL_81;
}
game::RemoveOpcodePos(inst);
*game::gScrCompilePub[inst].opcodePos = game::OP_EvalLocalArrayCached;
game::EmitByte(inst, index);
return;
case game::OP_EvalArrayRef:
if ( *game::gScrCompilePub[inst].opcodePos == game::OP_EvalLocalVariableRefCached )
{
game::RemoveOpcodePos(inst);
*game::gScrCompilePub[inst].opcodePos = game::OP_EvalLocalArrayRefCached;
// game::EmitPreAssignmentPos(inst);
return;
}
if ( *game::gScrCompilePub[inst].opcodePos != game::OP_EvalLocalVariableRefCached0 )
{
goto LABEL_81;
}
game::RemoveOpcodePos(inst);
*game::gScrCompilePub[inst].opcodePos = game::OP_EvalLocalArrayRefCached0;
// game::EmitPreAssignmentPos(inst);
return;
case game::OP_EvalFieldVariable:
if ( *game::gScrCompilePub[inst].opcodePos == game::OP_GetSelfObject )
{
*game::gScrCompilePub[inst].opcodePos = game::OP_EvalSelfFieldVariable;
// game::EmitPreAssignmentPos(inst);
return;
}
if ( *game::gScrCompilePub[inst].opcodePos == game::OP_GetLevelObject )
{
*game::gScrCompilePub[inst].opcodePos = game::OP_EvalLevelFieldVariable;
// game::EmitPreAssignmentPos(inst);
return;
}
if ( *game::gScrCompilePub[inst].opcodePos != game::OP_GetAnimObject )
{
goto LABEL_81;
}
*game::gScrCompilePub[inst].opcodePos = game::OP_EvalAnimFieldVariable;
// game::EmitPreAssignmentPos(inst);
return;
case game::OP_EvalFieldVariableRef:
if ( *game::gScrCompilePub[inst].opcodePos == game::OP_GetSelfObject )
{
*game::gScrCompilePub[inst].opcodePos = game::OP_EvalSelfFieldVariableRef;
// game::EmitPreAssignmentPos(inst);
return;
}
if ( *game::gScrCompilePub[inst].opcodePos == game::OP_GetLevelObject )
{
*game::gScrCompilePub[inst].opcodePos = game::OP_EvalLevelFieldVariableRef;
// game::EmitPreAssignmentPos(inst);
return;
}
if ( *game::gScrCompilePub[inst].opcodePos != game::OP_GetAnimObject )
{
goto LABEL_81;
}
*game::gScrCompilePub[inst].opcodePos = game::OP_EvalAnimFieldVariableRef;
// game::EmitPreAssignmentPos(inst);
return;
case game::OP_SafeSetVariableFieldCached0:
if ( *game::gScrCompilePub[inst].opcodePos != game::OP_CreateLocalVariable )
{
goto LABEL_81;
}
*game::gScrCompilePub[inst].opcodePos = game::OP_SafeCreateVariableFieldCached;
return;
case game::OP_SetVariableField:
switch ( *game::gScrCompilePub[inst].opcodePos )
{
case game::OP_EvalLocalVariableRefCached:
game::RemoveOpcodePos(inst);
*game::gScrCompilePub[inst].opcodePos = game::OP_SetLocalVariableFieldCached;
// game::EmitPreAssignmentPos(inst);
return;
case game::OP_EvalLocalVariableRefCached0:
game::RemoveOpcodePos(inst);
*game::gScrCompilePub[inst].opcodePos = game::OP_SetLocalVariableFieldCached0;
// game::EmitPreAssignmentPos(inst);
return;
case game::OP_EvalSelfFieldVariableRef:
game::RemoveOpcodePos(inst);
*game::gScrCompilePub[inst].opcodePos = game::OP_SetSelfFieldVariableField;
// game::EmitPreAssignmentPos(inst);
return;
case game::OP_EvalLevelFieldVariableRef:
game::RemoveOpcodePos(inst);
*game::gScrCompilePub[inst].opcodePos = game::OP_SetLevelFieldVariableField;
// game::EmitPreAssignmentPos(inst);
return;
}
if ( *game::gScrCompilePub[inst].opcodePos != game::OP_EvalAnimFieldVariableRef )
{
goto LABEL_81;
}
game::RemoveOpcodePos(inst);
*game::gScrCompilePub[inst].opcodePos = game::OP_SetAnimFieldVariableField;
// game::EmitPreAssignmentPos(inst);
return;
case game::OP_ScriptFunctionCall:
if ( *game::gScrCompilePub[inst].opcodePos != game::OP_PreScriptCall )
{
goto LABEL_81;
}
*game::gScrCompilePub[inst].opcodePos = game::OP_ScriptFunctionCall2;
return;
case game::OP_ScriptMethodCall:
if ( *game::gScrCompilePub[inst].opcodePos != game::OP_GetSelf )
{
goto LABEL_81;
}
game::RemoveOpcodePos(inst);
*game::gScrCompilePub[inst].opcodePos = game::OP_ScriptFunctionCall;
assert(game::gScrCompileGlob[inst].prevOpcodePos);
if ( *game::gScrCompileGlob[inst].prevOpcodePos != game::OP_PreScriptCall )
{
return;
}
assert(game::gScrCompilePub[inst].opcodePos == game::TempMalloc(0) - 1);
game::TempMemorySetPos(game::gScrCompilePub[inst].opcodePos);
--game::gScrCompilePub[inst].opcodePos;
game::gScrCompileGlob[inst].prevOpcodePos = 0;
game::gScrCompileGlob[inst].codePos = game::gScrCompilePub[inst].opcodePos;
*game::gScrCompilePub[inst].opcodePos = game::OP_ScriptFunctionCall2;
return;
case game::OP_ScriptMethodThreadCall:
if ( *game::gScrCompilePub[inst].opcodePos != game::OP_GetSelf )
{
goto LABEL_81;
}
game::RemoveOpcodePos(inst);
*game::gScrCompilePub[inst].opcodePos = game::OP_ScriptThreadCall;
return;
case game::OP_CastFieldObject:
if ( *game::gScrCompilePub[inst].opcodePos == game::OP_EvalLocalVariableCached )
{
*game::gScrCompilePub[inst].opcodePos = game::OP_EvalLocalVariableObjectCached;
return;
}
indexa = *(unsigned __int8 *)game::gScrCompilePub[inst].opcodePos - game::OP_EvalLocalVariableCached0;
if ( indexa > 5 )
{
goto LABEL_81;
}
*game::gScrCompilePub[inst].opcodePos = game::OP_EvalLocalVariableObjectCached;
game::EmitByte(inst, indexa);
break;
case game::OP_JumpOnFalse:
if ( *game::gScrCompilePub[inst].opcodePos != game::OP_BoolNot )
{
goto LABEL_81;
}
game::RemoveOpcodePos(inst);
*game::gScrCompilePub[inst].opcodePos = game::OP_JumpOnTrue;
return;
default:
goto LABEL_81;
}
}
else
{
LABEL_81:
game::gScrCompileGlob[inst].prevOpcodePos = game::gScrCompilePub[inst].opcodePos;
game::gScrCompilePub[inst].opcodePos = game::TempMalloc(1);
game::gScrCompileGlob[inst].codePos = game::gScrCompilePub[inst].opcodePos;
*game::gScrCompilePub[inst].opcodePos = op;
}
}
// Completed
void EmitEnd(game::scriptInstance_t inst)
{
game::EmitOpcode(inst, game::OP_End, 0, 0);
// EmitPreAssignmentPos(inst);
}
// Completed
void EmitReturn(game::scriptInstance_t inst)
{
game::EmitOpcode(inst, game::OP_Return, -1, 0);
// game::EmitPreAssignmentPos(inst);
}
// Completed
void EmitCodepos(game::scriptInstance_t inst, int codepos)
{
game::gScrCompileGlob[inst].codePos = game::TempMalloc(4);
*(int *)game::gScrCompileGlob[inst].codePos = codepos;
}
// Completed
void EmitShort(game::scriptInstance_t inst, int value)
{
game::gScrCompileGlob[inst].codePos = game::TempMalloc(2);
*(short *)game::gScrCompileGlob[inst].codePos = value;
}
// Completed
void EmitByte(game::scriptInstance_t inst, int value)
{
game::gScrCompileGlob[inst].codePos = game::TempMalloc(1);
*(char *)game::gScrCompileGlob[inst].codePos = value;
}
// Completed
void EmitGetInteger(game::scriptInstance_t inst, int value, game::sval_u sourcePos)
{
if ( value < 0 )
{
if ( value > -256 )
{
game::EmitOpcode(inst, game::OP_GetNegByte, 1, 0);
game::AddOpcodePos(inst, sourcePos.stringValue, 1);
game::EmitByte(inst, -(char)value);
return;
}
if ( value > -65536 )
{
game::EmitOpcode(inst, game::OP_GetNegUnsignedShort, 1, 0);
game::AddOpcodePos(inst, sourcePos.stringValue, 1);
game::EmitShort(inst, -(__int16)value);
return;
}
}
else
{
if ( !value )
{
game::EmitOpcode(inst, game::OP_GetZero, 1, 0);
game::AddOpcodePos(inst, sourcePos.stringValue, 1);
return;
}
if ( value < 256 )
{
game::EmitOpcode(inst, game::OP_GetByte, 1, 0);
game::AddOpcodePos(inst, sourcePos.stringValue, 1);
game::EmitByte(inst, value);
return;
}
if ( value < 0x10000 )
{
game::EmitOpcode(inst, game::OP_GetUnsignedShort, 1, 0);
game::AddOpcodePos(inst, sourcePos.stringValue, 1);
game::EmitShort(inst, value);
return;
}
}
game::EmitOpcode(inst, game::OP_GetInteger, 1, 0);
game::AddOpcodePos(inst, sourcePos.stringValue, 1);
game::EmitCodepos(inst, value);
}
// Restored
void EmitFloat(game::scriptInstance_t inst, float value)
{
game::gScrCompileGlob[inst].codePos = game::TempMalloc(4);
*(float *)game::gScrCompileGlob[inst].codePos = value;
}
// Completed
void EmitGetFloat(game::scriptInstance_t inst, float value, game::sval_u sourcePos)
{
game::EmitOpcode(inst, game::OP_GetFloat, 1, 0);
game::AddOpcodePos(inst, sourcePos.stringValue, 1);
game::EmitFloat(inst, value);
}
// Completed
void EmitAnimTree(game::scriptInstance_t inst, game::sval_u sourcePos)
{
if ( game::gScrAnimPub[inst].animTreeIndex )
{
game::EmitGetInteger(inst, game::gScrAnimPub[inst].animTreeIndex, sourcePos);
}
else
{
game::CompileError(inst, sourcePos.stringValue, "#using_animtree was not specified");
}
}
// Restored
void EmitCanonicalStringConst(game::scriptInstance_t inst, unsigned int stringValue)
{
bool bConstRefCount;
bConstRefCount = game::gScrCompileGlob[inst].bConstRefCount;
game::gScrCompileGlob[inst].bConstRefCount = 1;
game::EmitCanonicalString(inst, stringValue);
game::gScrCompileGlob[inst].bConstRefCount = bConstRefCount;
}
// Completed
int Scr_FindLocalVarIndex(game::scriptInstance_t inst, unsigned int name, game::sval_u sourcePos, int create, game::scr_block_s* block)
{
int i;
/*assert(gScrCompilePub[inst].developer_statement != SCR_DEV_EVALUATE (3));*/
if ( block )
{
for ( i = 0;
;
++i )
{
if ( i >= block->localVarsCount )
{
if ( !create || game::gScrCompileGlob[inst].forceNotCreate )
{
game::CompileError(inst, sourcePos.stringValue, "uninitialised variable '%s'", game::SL_ConvertToString(name, inst));
return 0;
}
game::CompileError(inst, sourcePos.stringValue, "unreachable code");
return 0;
}
if ( i == block->localVarsCreateCount )
{
++block->localVarsCreateCount;
game::EmitOpcode(inst, game::OP_CreateLocalVariable, 0, 0);
game::EmitCanonicalStringConst(inst, block->localVars[i].name);
// game::AddOpcodePos(inst, block->localVars[i].sourcePos, 0);
}
if ( block->localVars[i].name == name )
{
break;
}
}
game::Scr_CompileRemoveRefToString(inst, name);
if ( ((unsigned __int8)(1 << (i & 7)) & block->localVarsInitBits[i >> 3]) == 0 )
{
if ( !create || game::gScrCompileGlob[inst].forceNotCreate )
{
if ( !create || game::gScrCompileGlob[inst].forceNotCreate )
{
game::CompileError(inst, sourcePos.stringValue, "uninitialised variable '%s'", game::SL_ConvertToString(name, inst));
return 0;
}
game::CompileError(inst, sourcePos.stringValue, "unreachable code");
return 0;
}
block->localVarsInitBits[i >> 3] |= 1 << (i & 7);
}
assert((block->localVarsCreateCount - 1) >= i);
return block->localVarsCreateCount - 1 - i;
}
game::CompileError(inst, sourcePos.stringValue, "unreachable code");
return 0;
}
// Completed
void EmitCreateLocalVars(game::scriptInstance_t inst, game::scr_block_s* block)
{
int i;
assert(block->localVarsPublicCount >= block->localVarsCreateCount);
if ( block->localVarsCreateCount != block->localVarsPublicCount )
{
for ( i = block->localVarsCreateCount;
i < block->localVarsPublicCount;
++i )
{
game::EmitOpcode(inst, game::OP_CreateLocalVariable, 0, 0);
game::EmitCanonicalStringConst(inst, block->localVars[i].name);
// game::AddOpcodePos(inst, block->localVars[i].sourcePos, 0);
}
block->localVarsCreateCount = block->localVarsPublicCount;
}
}
// Completed
void EmitRemoveLocalVars(game::scriptInstance_t inst, game::scr_block_s* outerBlock, game::scr_block_s* block)
{
int removeCount;
if ( !block->abortLevel )
{
assert(block->localVarsCreateCount >= block->localVarsPublicCount);
assert(block->localVarsPublicCount >= outerBlock->localVarsPublicCount);
removeCount = block->localVarsCreateCount - outerBlock->localVarsPublicCount;
assert(removeCount >= 0);
if ( removeCount )
{
game::EmitOpcode(inst, game::OP_RemoveLocalVariables, 0, 0);
game::EmitByte(inst, removeCount);
block->localVarsCreateCount = block->localVarsPublicCount;
}
}
}
// Completed
void EmitNOP2(game::scr_block_s* block, game::scriptInstance_t inst, int lastStatement, unsigned int endSourcePos)
{
int checksum;
checksum = game::gScrVarPub[inst].checksum;
if ( (char)lastStatement )
{
game::EmitEnd(inst);
game::AddOpcodePos(inst, endSourcePos, 1);
}
else
{
game::EmitRemoveLocalVars(inst, block, block);
}
game::gScrVarPub[inst].checksum = checksum + 1;
}
// Completed
void Scr_InitFromChildBlocks(game::scr_block_s** childBlocks, int childCount, game::scr_block_s* block)
{
game::scr_block_s *childBlock;
game::scr_block_s *childBlocka;
int childIndex;
int childIndexa;
int localVarsCreateCount;
unsigned int name;
int i;
if ( childCount )
{
localVarsCreateCount = (*childBlocks)->localVarsPublicCount;
for ( childIndex = 1;
childIndex < childCount;
++childIndex )
{
childBlock = childBlocks[childIndex];
if ( childBlock->localVarsPublicCount < localVarsCreateCount )
{
localVarsCreateCount = childBlock->localVarsPublicCount;
}
}
assert(block->localVarsCreateCount <= localVarsCreateCount);
assert(localVarsCreateCount <= block->localVarsCount);
block->localVarsCreateCount = localVarsCreateCount;
for ( i = 0;
i < localVarsCreateCount;
++i )
{
assert(i < block->localVarsCount);
if ( ((1 << (i & 7)) & (unsigned __int8)block->localVarsInitBits[i >> 3]) == 0 )
{
name = block->localVars[i].name;
for ( childIndexa = 0;
childIndexa < childCount;
++childIndexa )
{
childBlocka = childBlocks[childIndexa];
assert(localVarsCreateCount <= childBlocka->localVarsPublicCount);
assert(i < childBlocka->localVarsPublicCount);
assert(childBlocka->localVars[i].name == name);
if ( ((1 << (i & 7)) & (unsigned __int8)childBlocka->localVarsInitBits[i >> 3]) == 0 )
{
goto LABEL_14;
}
}
block->localVarsInitBits[i >> 3] |= 1 << (i & 7);
}
LABEL_14:
;
}
}
}
// Restored
int Scr_FindLocalVar(game::scr_block_s *block, int startIndex, unsigned int name)
{
while ( startIndex < block->localVarsCount )
{
if ( block->localVars[startIndex].name == name )
{
return startIndex;
}
++startIndex;
}
return -1;
}
// Completed
void Scr_AppendChildBlocks(game::scr_block_s* block, game::scr_block_s** childBlocks, int childCount)
{
unsigned int localVar;
int childIndex;
int childIndexa;
int i;
if ( childCount && !block->abortLevel )
{
for ( childIndex = 0;
childIndex < childCount;
++childIndex )
{
childBlocks[childIndex]->abortLevel = 0;
}
for ( i = 0;
i < (*childBlocks)->localVarsCount;
++i )
{
localVar = (*childBlocks)->localVars[i].name;
// v5 = (*childBlocks)->localVars[i].sourcePos;
if ( game::Scr_FindLocalVar(block, 0, localVar) < 0 )
{
for ( childIndexa = 1;
childIndexa < childCount;
++childIndexa )
{
if ( game::Scr_FindLocalVar(childBlocks[childIndexa], 0, localVar) < 0 )
{
goto LABEL_8;
}
}
block->localVars[block->localVarsCount].name = localVar;
// block->localVars[block->localVarsCount].sourcePos = v5;
++block->localVarsCount;
}
LABEL_8:
;
}
}
}
// Restored
void Scr_CheckLocalVarsCount(int localVarsCount)
{
if ( localVarsCount >= 64 )
{
game::Com_Error(game::ERR_DROP, "LOCAL_game::VAR_STACK_SIZE exceeded");
}
}
// Completed
void Scr_MergeChildBlocks(game::scr_block_s** childBlocks, int childCount, game::scr_block_s* block)
{
int j;
unsigned int localVar;
game::scr_block_s *childBlock;
int childIndex;
int i;
if ( childCount && !block->abortLevel )
{
for ( childIndex = 0;
childIndex < childCount;
++childIndex )
{
childBlock = childBlocks[childIndex];
assert(!childBlock->localVarsPublicCount);
childBlock->localVarsPublicCount = block->localVarsCount;
for ( i = 0;
i < block->localVarsCount;
++i )
{
localVar = block->localVars[i].name;
// v6 = block->localVars[i].sourcePos;
j = game::Scr_FindLocalVar(childBlock, i, localVar);
if ( j < 0 )
{
j = childBlock->localVarsCount;
game::Scr_CheckLocalVarsCount(j);
++childBlock->localVarsCount;
}
while ( j > i )
{
// v3 = *(_DWORD *)&childBlock->localVarsInitBits[8 * j + 4];
childBlock->localVars[j].name = childBlock->localVars[j - 1].name;
// childBlock->localVars[j].sourcePos = v3;
j--;
}
childBlock->localVars[i].name = localVar;
// childBlock->localVars[i].sourcePos = v6;
}
}
}
}
// Completed
void Scr_TransferBlock(game::scr_block_s* to, game::scr_block_s* from)
{
int j;
unsigned int localVar;
int i;
assert(to->localVarsPublicCount <= from->localVarsCount);
for ( i = 0;
i < to->localVarsPublicCount || i < from->localVarsCreateCount;
++i )
{
localVar = from->localVars[i].name;
// v5 = from->localVars[i].sourcePos;
j = game::Scr_FindLocalVar(to, i, localVar);
if ( j < 0 )
{
j = to->localVarsCount;
game::Scr_CheckLocalVarsCount(j);
++to->localVarsCount;
}
if (j >= to->localVarsPublicCount)
{
++to->localVarsPublicCount;
assert(to->localVarsPublicCount <= from->localVarsCount);
}
while ( j > i )
{
// v2 = *(_DWORD *)&to->localVarsInitBits[8 * j + 4];
to->localVars[j].name = to->localVars[j - 1].name;
// to->localVars[j].sourcePos = v2;
j--;
}
to->localVars[i].name = localVar;
// to->localVars[i].sourcePos = v5;
if ( ((1 << (i & 7)) & (unsigned __int8)from->localVarsInitBits[i >> 3]) != 0 )
{
to->localVarsInitBits[i >> 3] |= 1 << (i & 7);
}
}
assert(from->localVarsCreateCount <= to->localVarsPublicCount);
to->localVarsCreateCount = from->localVarsCreateCount;
to->abortLevel = 0;
}
// Completed
void EmitSafeSetVariableField(game::scr_block_s* block, game::scriptInstance_t inst, game::sval_u expr, game::sval_u sourcePos)
{
int index;
index = game::Scr_FindLocalVarIndex(inst, expr.stringValue, sourcePos, 1, block);
if (index == 0)
{
game::EmitOpcode(inst, game::OP_SafeSetVariableFieldCached0, 0, 0);
}
else
{
game::EmitOpcode(inst, game::OP_SafeSetVariableFieldCached, 0, 0);
}
// game::EmitPreAssignmentPos(inst);
if ( index )
{
game::EmitByte(inst, index);
}
game::AddOpcodePos(inst, sourcePos.stringValue, 0);
// game::EmitAssignmentPos(inst);
}
// Completed
void EmitSafeSetWaittillVariableField(game::scr_block_s* block, game::scriptInstance_t inst, game::sval_u expr, game::sval_u sourcePos)
{
char index;
index = Scr_FindLocalVarIndex(inst, expr.stringValue, sourcePos, 1, block);
game::EmitOpcode(inst, game::OP_SafeSetWaittillVariableFieldCached, 0, 0);
// game::EmitPreAssignmentPos(inst);
game::EmitByte(inst, index);
game::AddOpcodePos(inst, sourcePos.stringValue, 0);
// game::EmitAssignmentPos(inst);
}
// Completed
void EmitGetString(unsigned int value, game::scriptInstance_t inst, game::sval_u sourcePos)
{
game::EmitOpcode(inst, game::OP_GetString, 1, 0);
game::AddOpcodePos(inst, sourcePos.stringValue, 1);
game::EmitShort(inst, value);
game::CompileTransferRefToString(value, inst, 1u);
}
// Complete
void EmitGetIString(unsigned int value, game::scriptInstance_t inst, game::sval_u sourcePos)
{
game::EmitOpcode(inst, game::OP_GetIString, 1, 0);
game::AddOpcodePos(inst, sourcePos.stringValue, 1);
game::EmitShort(inst, value);
game::CompileTransferRefToString(value, inst, 1u);
}
// Decomp Status: Untested
// void __usercall EmitGetVector(const float *value@<eax>, game::scriptInstance_t inst, game::sval_u sourcePos)
void EmitGetVector(const float* value, game::scriptInstance_t inst, game::sval_u sourcePos)
{
int i;
game::EmitOpcode(inst, game::OP_GetVector, 1, 0);
game::AddOpcodePos(inst, sourcePos.stringValue, 1);
for ( i = 0;
i < 3;
++i )
{
game::EmitFloat(inst, value[i]);
}
game::RemoveRefToVector(value, inst);
}
// Restored
void EmitGetUndefined(game::scriptInstance_t inst, game::sval_u sourcePos)
{
game::EmitOpcode(inst, game::OP_GetUndefined, 1, 0);
game::AddOpcodePos(inst, sourcePos.stringValue, 1);
}
// Completed
void EmitValue(game::scriptInstance_t inst, game::VariableCompileValue* constValue)
{
switch (constValue->value.type)
{
case game::VAR_UNDEFINED:
game::EmitGetUndefined(inst, constValue->sourcePos);
break;
case game::VAR_STRING:
game::EmitGetString(constValue->value.u.intValue, inst, constValue->sourcePos);
break;
case game::VAR_ISTRING:
game::EmitGetIString(constValue->value.u.intValue, inst, constValue->sourcePos);
break;
case game::VAR_VECTOR:
game::EmitGetVector(constValue->value.u.vectorValue, inst, constValue->sourcePos);
break;
case game::VAR_FLOAT:
game::EmitGetFloat(inst, constValue->value.u.floatValue, constValue->sourcePos);
break;
case game::VAR_INTEGER:
game::EmitGetInteger(inst, constValue->value.u.intValue, constValue->sourcePos);
break;
default:
return;
}
}
// Completed
void Scr_PushValue(game::scriptInstance_t inst, game::VariableCompileValue* constValue)
{
if ( game::gScrCompilePub[inst].value_count < 32 )
{
game::gScrCompileGlob[inst].value_start[game::gScrCompilePub[inst].value_count++] = *constValue;
}
else
{
game::CompileError(inst, constValue->sourcePos.stringValue, "VALUE_STACK_SIZE exceeded");
}
}
// Completed
void EmitCastBool(game::scriptInstance_t inst, game::sval_u sourcePos)
{
game::EmitOpcode(inst, game::OP_CastBool, 0, 0);
game::AddOpcodePos(inst, sourcePos.stringValue, 0);
}
// Completed
void EmitBoolNot(game::scriptInstance_t inst, game::sval_u sourcePos)
{
game::EmitOpcode(inst, game::OP_BoolNot, 0, 0);
game::AddOpcodePos(inst, sourcePos.stringValue, 0);
}
// Completed
void EmitBoolComplement(game::scriptInstance_t inst, game::sval_u sourcePos)
{
game::EmitOpcode(inst, game::OP_BoolComplement, 0, 0);
game::AddOpcodePos(inst, sourcePos.stringValue, 0);
}
// Restored
void EmitPrimitiveExpression(game::scriptInstance_t inst, game::sval_u expr, game::scr_block_s *block)
{
game::VariableCompileValue constValue;
if ( game::EmitOrEvalPrimitiveExpression(inst, expr, &constValue, block) )
{
game::EmitValue(inst, &constValue);
}
}
// Completed
void EmitSize(game::scr_block_s* block, game::scriptInstance_t inst, game::sval_u expr, game::sval_u sourcePos)
{
game::EmitPrimitiveExpression(inst, expr, block);
game::EmitOpcode(inst, game::OP_size, 0, 0);
game::AddOpcodePos(inst, sourcePos.stringValue, 0);
}
// Completed
void EmitSelf(game::scriptInstance_t inst, game::sval_u sourcePos)
{
game::EmitOpcode(inst, game::OP_GetSelf, 1, 0);
game::AddOpcodePos(inst, sourcePos.stringValue, 1);
}
// Completed
void EmitLevel(game::scriptInstance_t inst, game::sval_u sourcePos)
{
game::EmitOpcode(inst, game::OP_GetLevel, 1, 0);
game::AddOpcodePos(inst, sourcePos.stringValue, 1);
}
// Completed
void EmitGame(game::scriptInstance_t inst, game::sval_u sourcePos)
{
game::EmitOpcode(inst, game::OP_GetGame, 1, 0);
game::AddOpcodePos(inst, sourcePos.stringValue, 1);
}
// Completed
void EmitAnim(game::scriptInstance_t inst, game::sval_u sourcePos)
{
game::EmitOpcode(inst, game::OP_GetAnim, 1, 0);
game::AddOpcodePos(inst, sourcePos.stringValue, 1);
}
// Completed
void EmitSelfObject(game::scriptInstance_t inst, game::sval_u sourcePos)
{
game::EmitOpcode(inst, game::OP_GetSelfObject, 0, 0);
// game::EmitPreAssignmentPos(inst);
game::AddOpcodePos(inst, sourcePos.stringValue, 1);
}
// Completed
void EmitLevelObject(game::scriptInstance_t inst, game::sval_u sourcePos)
{
game::EmitOpcode(inst, game::OP_GetLevelObject, 0, 0);
// game::EmitPreAssignmentPos(inst);
game::AddOpcodePos(inst, sourcePos.stringValue, 1);
}
// Completed
void EmitAnimObject(game::scriptInstance_t inst, game::sval_u sourcePos)
{
game::EmitOpcode(inst, game::OP_GetAnimObject, 0, 0);
// game::EmitPreAssignmentPos(inst);
game::AddOpcodePos(inst, sourcePos.stringValue, 1);
}
// Completed
void EmitLocalVariable(game::scr_block_s* block, game::scriptInstance_t inst, game::sval_u expr, game::sval_u sourcePos)
{
int index;
unsigned int opcode;
/*if (gScrCompilePub[inst].developer_statement == 3)
{
EmitOpcode(inst, game::OP_EvalLocalVariable, 1, 0);
EmitCanonicalString(inst, expr.stringValue);
return;
}*/
index = game::Scr_FindLocalVarIndex(inst, expr.stringValue, sourcePos, 0, block);
if ( index > 5 )
{
opcode = game::OP_EvalLocalVariableCached;
game::EmitOpcode(inst, game::OP_EvalLocalVariableCached, 1, 0);
}
else
{
opcode = index + game::OP_EvalLocalVariableCached0;
game::EmitOpcode(inst, (game::OpcodeVM)opcode, 1, 0);
}
if ( opcode == game::OP_EvalLocalVariableCached )
{
game::EmitByte(inst, index);
}
game::AddOpcodePos(inst, sourcePos.stringValue, 1);
}
// Completed
void EmitLocalVariableRef(game::scr_block_s* block, game::scriptInstance_t inst, game::sval_u expr, game::sval_u sourcePos)
{
int index;
/*if (gScrCompilePub[inst].developer_statement == 3)
{
EmitOpcode(inst, game::OP_EvalLocalVariableRef, 0, 0);
EmitCanonicalString(inst, expr.stringValue);
}*/
index = game::Scr_FindLocalVarIndex(inst, expr.stringValue, sourcePos, 1, block);
if (index == 0)
{
game::EmitOpcode(inst, game::OP_EvalLocalVariableRefCached0, 0, 0);
}
else
{
game::EmitOpcode(inst, game::OP_EvalLocalVariableRefCached, 0, 0);
}
// game::EmitPreAssignmentPos(inst);
if ( index )
{
game::EmitByte(inst, index);
}
game::AddOpcodePos(inst, sourcePos.stringValue, 1);
}
// Completed
void Scr_RegisterLocalVar(unsigned int name, [[maybe_unused]] game::sval_u sourcePos, game::scr_block_s* block)
{
int i;
if ( !block->abortLevel )
{
for ( i = 0;
i < block->localVarsCount;
++i )
{
if ( block->localVars[i].name == name )
{
return;
}
}
game::Scr_CheckLocalVarsCount(block->localVarsCount);
block->localVars[block->localVarsCount].name = name;
//block->localVars[block->localVarsCount].sourcePos = sourcePos.stringValue;
block->localVarsCount++;
}
}
// Completed
void EmitGameRef(game::scriptInstance_t inst, game::sval_u sourcePos)
{
game::EmitOpcode(inst, game::OP_GetGameRef, 0, 0);
// game::EmitPreAssignmentPos(inst);
game::AddOpcodePos(inst, sourcePos.stringValue, 1);
}
// Completed
void EmitClearArray(game::scriptInstance_t inst, game::sval_u sourcePos, game::sval_u indexSourcePos)
{
game::EmitOpcode(inst, game::OP_ClearArray, -1, 0);
game::AddOpcodePos(inst, indexSourcePos.stringValue, 0);
game::AddOpcodePos(inst, sourcePos.stringValue, 0);
// game::EmitAssignmentPos(inst);
}
// Completed
void EmitEmptyArray(game::scriptInstance_t inst, game::sval_u sourcePos)
{
game::EmitOpcode(inst, game::OP_EmptyArray, 1, 0);
game::AddOpcodePos(inst, sourcePos.stringValue, 1);
}
// Restored
void Scr_EmitAnimation(game::scriptInstance_t inst, char *pos, unsigned int animName, unsigned int sourcePos)
{
if ( game::gScrAnimPub[inst].animTreeNames )
{
game::Scr_EmitAnimationInternal(inst, pos, animName, game::gScrAnimPub[inst].animTreeNames);
}
else
{
game::CompileError(inst, sourcePos, "#using_animtree was not specified");
}
}
// Completed
void EmitAnimation(game::scriptInstance_t inst, game::sval_u anim, game::sval_u sourcePos)
{
game::EmitOpcode(inst, game::OP_GetAnimation, 1, 0);
game::AddOpcodePos(inst, sourcePos.stringValue, 1);
game::EmitCodepos(inst, 0xFFFFFFFF);
if ( game::gScrCompilePub[inst].developer_statement != 2 )
{
game::Scr_EmitAnimation(inst, game::gScrCompileGlob[inst].codePos, anim.stringValue, sourcePos.stringValue);
}
game::Scr_CompileRemoveRefToString(inst, anim.stringValue);
}
// Completed
void EmitFieldVariable(game::scr_block_s* block, game::scriptInstance_t inst, game::sval_u expr, game::sval_u field, game::sval_u sourcePos)
{
game::EmitPrimitiveExpressionFieldObject(inst, expr, sourcePos, block);
game::EmitOpcode(inst, game::OP_EvalFieldVariable, 1, 0);
game::AddOpcodePos(inst, sourcePos.stringValue, 0);
game::EmitCanonicalString(inst, field.stringValue);
}
// Completed
void EmitClearFieldVariable(game::scr_block_s* block, game::scriptInstance_t inst, game::sval_u expr, game::sval_u field, game::sval_u sourcePos, game::sval_u rhsSourcePos)
{
game::EmitPrimitiveExpressionFieldObject(inst, expr, sourcePos, block);
game::EmitOpcode(inst, game::OP_ClearFieldVariable, 0, 0);
game::AddOpcodePos(inst, rhsSourcePos.stringValue, 0);
game::EmitCanonicalString(inst, field.stringValue);
// game::EmitAssignmentPos(inst);
}
// Decomp Status: Untested
// void __usercall EmitObject(game::scriptInstance_t inst@<edi>, game::sval_u expr, game::sval_u sourcePos)
void EmitObject([[maybe_unused]] game::scriptInstance_t inst, [[maybe_unused]] game::sval_u expr, [[maybe_unused]] game::sval_u sourcePos)
{
/*int v3; // esi
unsigned int* v4; // ecx
char v5; // dl
unsigned int v6; // eax
VariableValueInternal_w v7; // eax
int v8; // eax
int v9; // eax
game::VariableCompileValue* v10; // esi
bool v11; // al
int v12; // eax
unsigned int* v13; // eax
char* v14; // eax
char* v15; // eax
scr_classStruct_t* v16; // eax
char* v17; // esi
int v18; // eax
game::VariableCompileValue* v19; // esi
bool v20; // al
int v21; // eax
unsigned int* v22; // eax
char* v23; // eax
char* v24; // eax
int codepos; // [esp+Ch] [ebp-Ch]
int codeposa; // [esp+Ch] [ebp-Ch]
int a2; // [esp+10h] [ebp-8h]
int a2a; // [esp+10h] [ebp-8h]
int v29; // [esp+14h] [ebp-4h]
if (game::gScrCompilePub[inst].script_loading)
{
game::CompileError(inst, sourcePos.stringValue, "$ can only be used in the script debugger");
}
v3 = 0;
if (expr.stringValue)
{
v4 = game::gScrMemTreePub[inst].mt_buffer->nodes[expr.stringValue].padding;
}
else
{
v4 = 0;
}
v5 = *(char*)v4;
if (*(char*)v4 == 0x74)
{
v6 = game::j__atol((const char*)v4 + 1);
a2 = v6;
if (v6)
{
if (v6 < 0x5FFE)
{
v7.status = (unsigned int)game::gScrVarGlob[inst].parentVariables[(unsigned __int16)v6 + 1].w.status;
if ((v7.status & 0x60) != 0)
{
v8 = v7.status & 0x1F;
if (v8 >= 13 && (v8 <= 16 || v8 == 21))
{
v9 = game::gScrCompilePub[inst].value_count;
if (v9)
{
game::gScrCompilePub[inst].value_count = 0;
if (v9 > 0)
{
v10 = game::gScrCompileGlob[inst].value_start;
codepos = v9;
do
{
game::EmitValue(inst, v10++);
--codepos;
} while (codepos);
}
}
v11 = game::gScrCompileGlob[inst].cumulOffset++ == 0;
game::gScrCompilePub[inst].allowedBreakpoint = v11;
v12 = game::gScrCompileGlob[inst].cumulOffset;
if (game::gScrCompileGlob[inst].maxOffset < v12)
{
game::gScrCompileGlob[inst].maxOffset = v12;
}
v13 = &game::gScrVarPub[inst].checksum;
*v13 *= 31;
*v13 += 130;
v14 = game::gScrCompilePub[inst].opcodePos;
if (v14)
{
game::gScrCompileGlob[inst].codePos = v14;
}
game::gScrCompileGlob[inst].prevOpcodePos = v14;
v15 = (char*)game::Hunk_UserAlloc((*game::g_user), 1, 1);
game::gScrCompilePub[inst].opcodePos = v15;
game::gScrCompileGlob[inst].codePos = v15;
*v15 = -126;
game::EmitShort(inst, a2);
return;
}
}
}
}
LABEL_22:
game::CompileError(inst, sourcePos.stringValue, "bad expression");
}
if (v5 == 97)
{
game::CompileError(inst, sourcePos.stringValue, "argument expressions not supported in statements");
}
v16 = game::gScrClassMap[inst]; // Scr_GetClassnumForCharId
while (v16->charId != v5)
{
++v3;
++v16;
if (v3 >= 4)
{
goto LABEL_30;
}
}
codeposa = v3;
if (v3 < 0)
{
LABEL_30:
game::CompileError(inst, sourcePos.stringValue, "bad expression");
}
v17 = (char*)v4 + 1;
v29 = game::j__atol((const char*)v4 + 1);
if (!v29 && *v17 != 48)
{
goto LABEL_22;
}
v18 = game::gScrCompilePub[inst].value_count;
if (v18)
{
game::gScrCompilePub[inst].value_count = 0;
if (v18 > 0)
{
v19 = game::gScrCompileGlob[inst].value_start;
a2a = v18;
do
{
game::EmitValue(inst, v19++);
--a2a;
} while (a2a);
}
}
v20 = game::gScrCompileGlob[inst].cumulOffset++ == 0;
game::gScrCompilePub[inst].allowedBreakpoint = v20;
v21 = game::gScrCompileGlob[inst].cumulOffset;
if (game::gScrCompileGlob[inst].maxOffset < v21)
{
game::gScrCompileGlob[inst].maxOffset = v21;
}
v22 = &game::gScrVarPub[inst].checksum;
*v22 *= 31;
*v22 += 129;
v23 = game::gScrCompilePub[inst].opcodePos;
if (v23)
{
game::gScrCompileGlob[inst].codePos = v23;
}
game::gScrCompileGlob[inst].prevOpcodePos = v23;
v24 = (char*)game::Hunk_UserAlloc((*game::g_user), 1, 1);
game::gScrCompilePub[inst].opcodePos = v24;
game::gScrCompileGlob[inst].codePos = v24;
*v24 = -127;
game::EmitCodepos(inst, codeposa);
game::EmitCodepos(inst, v29);*/
/*
game::VariableType v3; // [esp+0h] [ebp-18h]
const char *classnum; // [esp+4h] [ebp-14h]
char *s; // [esp+Ch] [ebp-Ch]
const char *entnum; // [esp+10h] [ebp-8h]
unsigned int idValue; // [esp+14h] [ebp-4h]
if ( gScrCompilePub[inst].script_loading )
{
CompileError(inst, sourcePos.stringValue, "$ can only be used in the script debugger");
return;
}
s = SL_ConvertToString(expr.stringValue, inst);
if ( *s == 't' )
{
idValue = atoi(s + 1);
if ( idValue )
{
if ( idValue < 0x7FFE && !IsObjectFree(inst, (unsigned __int16)idValue) )
{
v3 = GetObjectType(inst, (unsigned __int16)idValue);
if ( v3 >= game::VAR_THREAD && (v3 <= game::VAR_CHILD_THREAD || v3 == game::VAR_DEAD_THREAD) )
{
EmitOpcode(inst, 0x82u, 1, 0);
EmitShort(inst, idValue);
return;
}
}
}
LABEL_17:
CompileError(inst, sourcePos.stringValue, "bad expression");
return;
}
if ( *s == 97 )
{
CompileError(inst, sourcePos.stringValue, "argument expressions not supported in statements");
return;
}
classnum = (const char *)Scr_GetClassnumForCharId(inst, *s);
if ( (int)classnum < 0 )
goto LABEL_17;
entnum = (const char *)atoi(s + 1);
if ( !entnum && s[1] != 48 )
goto LABEL_17;
EmitOpcode(inst, 0x81u, 1, 0);
EmitCodepos(inst, classnum);
EmitCodepos(inst, entnum);
*/
}
// Completed
void EmitDecTop(game::scriptInstance_t inst)
{
game::EmitOpcode(inst, game::OP_DecTop, -1, 0);
}
// Completed
void EmitCastFieldObject(game::scriptInstance_t inst, game::sval_u sourcePos)
{
game::EmitOpcode(inst, game::OP_CastFieldObject, -1, 0);
// game::EmitPreAssignmentPos(inst);
game::AddOpcodePos(inst, sourcePos.stringValue, 0);
}
// Restored
void EmitEvalArray(game::scriptInstance_t inst, game::sval_u sourcePos, game::sval_u indexSourcePos)
{
game::EmitOpcode(inst, game::OP_EvalArray, -1, 0);
game::AddOpcodePos(inst, indexSourcePos.stringValue, 0);
game::AddOpcodePos(inst, sourcePos.stringValue, 1);
}
// Completed
void EmitArrayVariable(game::scr_block_s* block, game::scriptInstance_t inst, game::sval_u expr, game::sval_u index, game::sval_u sourcePos, game::sval_u indexSourcePos)
{
game::EmitExpression(inst, index, block);
game::EmitPrimitiveExpression(inst, expr, block);
game::EmitEvalArray(inst, sourcePos, indexSourcePos);
}
// Restored
void EmitEvalArrayRef(game::scriptInstance_t inst, game::sval_u sourcePos, game::sval_u indexSourcePos)
{
game::EmitOpcode(inst, game::OP_EvalArrayRef, -1, 0);
game::AddOpcodePos(inst, indexSourcePos.stringValue, 0);
game::AddOpcodePos(inst, sourcePos.stringValue, 1);
}
// Completed
void EmitArrayVariableRef(game::scr_block_s* block, game::scriptInstance_t inst, game::sval_u expr, game::sval_u index, game::sval_u sourcePos, game::sval_u indexSourcePos)
{
game::EmitExpression(inst, index, block);
game::EmitArrayPrimitiveExpressionRef(inst, expr, sourcePos, block);
game::EmitEvalArrayRef(inst, sourcePos, indexSourcePos);
}
// Completed
void EmitClearArrayVariable(game::scr_block_s* block, game::scriptInstance_t inst, game::sval_u expr, game::sval_u index, game::sval_u sourcePos, game::sval_u indexSourcePos)
{
game::EmitExpression(inst, index, block);
game::EmitArrayPrimitiveExpressionRef(inst, expr, sourcePos, block);
game::EmitClearArray(inst, sourcePos, indexSourcePos);
}
// Completed
void EmitVariableExpression(game::scriptInstance_t inst, game::sval_u expr, game::scr_block_s* block)
{
switch ( expr.node->type )
{
case game::ENUM_local_variable:
game::EmitLocalVariable(block, inst, expr.node[1], expr.node[2]);
break;
case game::ENUM_array_variable:
game::EmitArrayVariable(block, inst, expr.node[1], expr.node[2], expr.node[3], expr.node[4]);
break;
case game::ENUM_field_variable:
game::EmitFieldVariable(block, inst, expr.node[1], expr.node[2], expr.node[3]);
break;
case game::ENUM_self_field:
if ( game::gScrCompilePub[inst].script_loading )
{
game::CompileError(inst, expr.node[2].sourcePosValue, "self field can only be used in the script debugger");
}
else
{
game::CompileError(inst, expr.node[2].sourcePosValue, "self field in assignment expression not currently supported");
}
break;
case game::ENUM_object:
game::EmitObject(inst, expr.node[1], expr.node[2]);
break;
default:
return;
}
}
// Completed
int EmitExpressionList(game::scriptInstance_t inst, game::sval_u exprlist, game::scr_block_s* block)
{
game::sval_u *node;
int expr_count;
expr_count = 0;
for ( node = exprlist.node[0].node;
node;
node = node[1].node )
{
game::EmitExpression(inst, node->node[0], block);
++expr_count;
}
return expr_count;
}
// Completed
void AddExpressionListOpcodePos(game::scriptInstance_t inst, game::sval_u exprlist)
{
game::sval_u *node;
if (game::gScrVarPub[inst].developer)
{
for (node = exprlist.node[0].node;
node;
node = node[1].node)
{
game::AddOpcodePos(inst, node->node[1].sourcePosValue, 0);
}
}
}
// Completed
void AddFilePrecache(game::scriptInstance_t inst, unsigned int filename, unsigned int sourcePos, bool include, unsigned int* filePosId, unsigned int* fileCountId)
{
game::SL_AddRefToString(inst, filename);
game::Scr_CompileRemoveRefToString(inst, filename);
game::gScrCompileGlob[inst].precachescriptList->filename = filename;
game::gScrCompileGlob[inst].precachescriptList->sourcePos = sourcePos;
game::gScrCompileGlob[inst].precachescriptList->include = include;
++game::gScrCompileGlob[inst].precachescriptList;
if ( !include )
{
*filePosId = game::GetObject(inst, game::GetVariable(inst, game::gScrCompilePub[inst].scriptsPos, filename));
*fileCountId = game::GetObject(inst, game::GetVariable(inst, game::gScrCompilePub[inst].scriptsCount, filename));
}
}
// Completed
void EmitFunction(game::scriptInstance_t inst, game::sval_u func, game::sval_u sourcePos)
{
unsigned int threadCountId;
unsigned int valueId;
unsigned int fileCountId;
unsigned int filename;
unsigned int posId;
unsigned int threadName;
bool bExists;
int scope;
unsigned int countId;
unsigned int filePosId;
game::VariableValue count;
game::VariableValue value;
game::VariableValue pos;
/*if (gScrCompilePub[inst].developer_statement == 3)
{
CompileError(inst, sourcePos.stringValue, "cannot evaluate in the debugger");
return;
}*/
if ( game::gScrCompilePub[inst].developer_statement == 2 )
{
game::Scr_CompileRemoveRefToString(inst, func.node[1].stringValue);
if ( func.node[0].type != game::ENUM_far_function )
{
return;
}
game::Scr_CompileRemoveRefToString(inst, func.node[2].stringValue);
--game::gScrCompilePub[inst].far_function_count;
return;
}
if ( func.node[0].type == game::ENUM_local_function )
{
scope = 0;
fileCountId = game::gScrCompileGlob[inst].fileCountId;
threadName = func.node[1].stringValue;
game::CompileTransferRefToString(threadName, inst, 2u);
}
else
{
assert(func.node[0].type == game::ENUM_far_function);
scope = 1;
filename = game::Scr_CreateCanonicalFilename(inst, game::SL_ConvertToString(func.node[1].stringValue, inst));
game::Scr_CompileRemoveRefToString(inst, func.node[1].stringValue);
value = game::Scr_EvalVariable(inst, game::FindVariable(filename, game::gScrCompilePub[inst].loadedscripts, inst));
bExists = value.type != game::VAR_UNDEFINED;
game::AddFilePrecache(inst, filename, sourcePos.stringValue, 0, &filePosId, &fileCountId);
threadName = func.node[2].stringValue;
game::CompileTransferRefToString(threadName, inst, 2u);
if ( bExists )
{
posId = game::FindVariable(threadName, filePosId, inst);
if (!posId)
{
game::CompileError(inst, sourcePos.stringValue, "unknown function");
}
pos = game::Scr_EvalVariable(inst, posId);
assert((pos.type == game::VAR_CODEPOS || pos.type == game::VAR_DEVELOPER_CODEPOS));
assert(pos.u.codePosValue);
if ( pos.type == game::VAR_CODEPOS )
{
game::EmitCodepos(inst, pos.u.intValue);
return;
}
assert(pos.type == game::VAR_DEVELOPER_CODEPOS);
assert(game::gScrVarPub[inst].developer_script);
assert(game::gScrCompilePub[inst].developer_statement != 2); // SCR_DEV_IGNORE
if ( !game::gScrCompilePub[inst].developer_statement )
{
game::CompileError(inst, sourcePos.stringValue, "normal script cannot reference a function in a /# ... #/ comment");
}
game::EmitCodepos(inst, pos.u.intValue);
return;
}
}
game::EmitCodepos(inst, scope);
threadCountId = game::GetObject(inst, game::GetVariable(inst, fileCountId, threadName));
assert(threadCountId);
countId = game::GetVariable(inst, threadCountId, 0);
count = game::Scr_EvalVariable(inst, countId);
assert((count.type == game::VAR_UNDEFINED) || (count.type == game::VAR_INTEGER));
if (count.type == game::VAR_UNDEFINED)
{
count.type = game::VAR_INTEGER;
count.u.intValue = 0;
}
valueId = game::GetNewVariable(inst, count.u.intValue + 1, threadCountId);
value.u.intValue = (int)game::gScrCompileGlob[inst].codePos;
if ( game::gScrCompilePub[inst].developer_statement )
{
assert(game::gScrVarPub[inst].developer_script);
value.type = game::VAR_DEVELOPER_CODEPOS;
}
else
{
value.type = game::VAR_CODEPOS;
}
game::SetNewVariableValue(inst, valueId, &value);
++count.u.intValue;
game::SetVariableValue(inst, &count, countId);
game::AddOpcodePos(inst, sourcePos.stringValue, 0);
}
// Completed
void EmitGetFunction(game::scriptInstance_t inst, game::sval_u func, game::sval_u sourcePos)
{
game::EmitOpcode(inst, game::OP_GetFunction, 1, 0);
game::AddOpcodePos(inst, sourcePos.stringValue, 3);
game::EmitFunction(inst, func, sourcePos);
}
// Completed
int AddFunction(game::scriptInstance_t inst, int func)
{
int i;
for ( i = 0;
i < game::gScrCompilePub[inst].func_table_size;
++i )
{
if ( game::gScrCompilePub[inst].func_table[i] == func )
{
return i;
}
}
assert(i == game::gScrCompilePub[inst].func_table_size);
if ( game::gScrCompilePub[inst].func_table_size == 1024 )
{
game::Com_Error(game::ERR_DROP, "\x15SCR_FUNC_TABLE_SIZE exceeded");
}
game::gScrCompilePub[inst].func_table[game::gScrCompilePub[inst].func_table_size] = func;
// game::gScrVmDebugPub[inst].func_table[game::gScrCompilePub[inst].func_table_size].breakpointCount = 0;
game::gScrCompilePub[inst].func_table_size++;
return i;
}
// Completed
void EmitPostScriptFunction(game::scriptInstance_t inst, game::sval_u func, int param_count, int bMethod, game::sval_u nameSourcePos)
{
if ( bMethod )
{
game::EmitOpcode(inst, game::OP_ScriptMethodCall, -param_count - 1, 3);
}
else
{
game::EmitOpcode(inst, game::OP_ScriptFunctionCall, -param_count, 3);
}
game::AddOpcodePos(inst, nameSourcePos.stringValue, 3);
game::EmitFunction(inst, func, nameSourcePos);
}
// Completed
void EmitPostScriptFunctionPointer(game::scr_block_s* block, game::scriptInstance_t inst, game::sval_u expr, int param_count, int bMethod, game::sval_u nameSourcePos, game::sval_u sourcePos)
{
game::EmitExpression(inst, expr, block);
if ( bMethod )
{
game::EmitOpcode(inst, game::OP_ScriptMethodCallPointer, -param_count - 2, 3);
}
else
{
game::EmitOpcode(inst, game::OP_ScriptFunctionCallPointer, -param_count - 1, 3);
}
game::AddOpcodePos(inst, sourcePos.stringValue, 0);
game::AddOpcodePos(inst, nameSourcePos.stringValue, 1);
}
// Completed
void EmitPostScriptThread(game::scriptInstance_t inst, game::sval_u func, int param_count, int bMethod, game::sval_u sourcePos)
{
if ( bMethod )
{
game::EmitOpcode(inst, game::OP_ScriptMethodThreadCall, -param_count, 2);
}
else
{
game::EmitOpcode(inst, game::OP_ScriptThreadCall, 1 - param_count, 2);
}
game::AddOpcodePos(inst, sourcePos.stringValue, 3);
game::EmitFunction(inst, func, sourcePos);
game::EmitCodepos(inst, param_count);
}
// Completed
void EmitPostScriptThreadPointer(game::scr_block_s* block, game::scriptInstance_t inst, game::sval_u expr, int param_count, int bMethod, game::sval_u sourcePos)
{
game::EmitExpression(inst, expr, block);
if ( bMethod )
{
game::EmitOpcode(inst, game::OP_ScriptMethodThreadCallPointer, -param_count - 1, 2);
}
else
{
game::EmitOpcode(inst, game::OP_ScriptThreadCallPointer, -param_count, 2);
}
game::AddOpcodePos(inst, sourcePos.stringValue, 1);
game::EmitCodepos(inst, param_count);
}
// Completed
void EmitPostScriptFunctionCall(game::scriptInstance_t inst, int bMethod, int param_count, game::sval_u func_name, game::sval_u nameSourcePos, game::scr_block_s* block)
{
if (func_name.node[0].type == game::ENUM_function)
{
game::EmitPostScriptFunction(inst, func_name.node[1], param_count, bMethod, nameSourcePos);
}
else if (func_name.node[0].type == game::ENUM_function_pointer)
{
game::EmitPostScriptFunctionPointer(
block,
inst,
func_name.node[1],
param_count,
bMethod,
nameSourcePos,
func_name.node[2]);
}
}
// Completed
void EmitPostScriptThreadCall(game::scriptInstance_t inst, int isMethod, int param_count, game::sval_u func_name, game::sval_u sourcePos, game::sval_u nameSourcePos, game::scr_block_s* block)
{
if (func_name.node[0].type == game::ENUM_function)
{
game::EmitPostScriptThread(inst, func_name.node[1], param_count, isMethod, nameSourcePos);
}
else if (func_name.node[0].type == game::ENUM_function_pointer)
{
game::EmitPostScriptThreadPointer(
block,
inst,
func_name.node[1],
param_count,
isMethod,
func_name.node[2]);
}
game::AddOpcodePos(inst, sourcePos.stringValue, 0);
}
// Completed
void EmitPreFunctionCall(game::scriptInstance_t inst)
{
game::EmitOpcode(inst, game::OP_PreScriptCall, 1, 0);
}
// Completed
void EmitPostFunctionCall(game::scriptInstance_t inst, int bMethod, game::sval_u func_name, int param_count, game::scr_block_s* block)
{
if (func_name.node[0].type == game::ENUM_script_call)
{
game::EmitPostScriptFunctionCall(
inst,
bMethod,
param_count,
func_name.node[1],
func_name.node[2],
block);
}
else if (func_name.node[0].type == game::ENUM_script_thread_call)
{
game::EmitPostScriptThreadCall(
inst,
bMethod,
param_count,
func_name.node[1],
func_name.node[2],
func_name.node[3],
block);
}
}
// Completed
void Scr_BeginDevScript(game::scriptInstance_t inst, int* type, char** savedPos)
{
if ( game::gScrCompilePub[inst].developer_statement )
{
*type = 0;
}
else
{
if ( game::gScrVarPub[inst].developer_script )
{
game::gScrCompilePub[inst].developer_statement = 1;
}
else
{
*savedPos = game::TempMalloc(0);
game::gScrCompilePub[inst].developer_statement = 2;
}
*type = 1;
}
}
// Completed
void Scr_EndDevScript(game::scriptInstance_t inst, char** savedPos)
{
// if ( type != 1 && !Assert_MyHandler("C:\\projects_pc\\cod\\codsrc\\src\\clientscript\\cscr_compiler.cpp", 1833, 0, "%s", "type == BUILTIN_DEVELOPER_ONLY") )
game::gScrCompilePub[inst].developer_statement = 0;
if ( !game::gScrVarPub[inst].developer_script )
{
game::TempMemorySetPos(*savedPos);
}
}
// Completed
void EmitCallBuiltinOpcode(game::scriptInstance_t inst, int param_count, game::sval_u sourcePos)
{
unsigned int opcode;
if ( param_count > 5 )
{
opcode = game::OP_CallBuiltin;
game::EmitOpcode(inst, game::OP_CallBuiltin, 1 - param_count, 1);
}
else
{
opcode = param_count + game::OP_CallBuiltin0;
game::EmitOpcode(inst, (game::OpcodeVM)(param_count + game::OP_CallBuiltin0), 1 - param_count, 1);
}
game::AddOpcodePos(inst, sourcePos.stringValue, 9);
if ( opcode == game::OP_CallBuiltin )
{
game::EmitByte(inst, param_count);
}
}
// Completed
void EmitCallBuiltinMethodOpcode(game::scriptInstance_t inst, int param_count, game::sval_u sourcePos)
{
unsigned int opcode;
if ( param_count > 5 )
{
opcode = game::OP_CallBuiltinMethod;
game::EmitOpcode(inst, game::OP_CallBuiltinMethod, -param_count, 1);
}
else
{
opcode = param_count + game::OP_CallBuiltinMethod0;
game::EmitOpcode(inst, (game::OpcodeVM)(param_count + game::OP_CallBuiltinMethod0), -param_count, 1);
}
// game::EmitPreAssignmentPos(inst);
game::AddOpcodePos(inst, sourcePos.stringValue, 9);
if ( opcode == game::OP_CallBuiltinMethod )
{
game::EmitByte(inst, param_count);
}
}
// Restored
unsigned int Scr_GetBuiltin(game::scriptInstance_t inst, game::sval_u func_name)
{
game::sval_u func_namea;
game::sval_u func_nameb;
if ( func_name.node[0].type != game::ENUM_script_call )
{
return 0;
}
func_namea = func_name.node[1];
if ( func_namea.node[0].type != game::ENUM_function )
{
return 0;
}
func_nameb = func_namea.node[1];
if ( func_nameb.node[0].type != game::ENUM_local_function )
{
return 0;
}
if ( /*game::gScrCompilePub[inst].developer_statement == 3 ||*/ !game::FindVariable(func_nameb.node[1].stringValue, game::gScrCompileGlob[inst].filePosId, inst))
{
return func_nameb.node[1].stringValue;
}
return 0;
}
// Restored
int Scr_GetUncacheType(int type)
{
if ( type == game::VAR_CODEPOS )
{
return 0;
}
assert(type == game::VAR_DEVELOPER_CODEPOS);
return 1;
}
// Restored
int Scr_GetCacheType(int type)
{
if ( !type )
{
return game::VAR_CODEPOS;
}
assert(type == 1); // BUILTIN_DEVELOPER_ONLY
return game::VAR_DEVELOPER_CODEPOS;
}
// Restored
game::BuiltinFunction Scr_GetFunction(const char** pName, int* type)
{
game::BuiltinFunction answer;
answer = game::Sentient_GetFunction(pName);
if (answer)
{
return answer;
}
return game::BuiltIn_GetFunction(pName, type);
}
// Restored
game::BuiltinFunction GetFunction(game::scriptInstance_t inst, const char **pName, int *type)
{
if ( inst )
{
// pluto
if (game::plutonium::cscr_get_function_hook != nullptr)
{
return game::plutonium::cscr_get_function_hook(pName, type);
}
//
else
{
return game::CScr_GetFunction(pName, type);
}
}
// our addition
auto f = gsc::function::get(pName, type);
if (f != nullptr)
{
return f;
}
//
// pluto
if (game::plutonium::scr_get_function_hook != nullptr)
{
return game::plutonium::scr_get_function_hook(pName, type);
}
//
else
{
return game::Scr_GetFunction(pName, type);
}
}
// Completed
void EmitCall(game::scriptInstance_t inst, game::sval_u func_name, game::sval_u params, int bStatement, game::scr_block_s* block)
{
void (__cdecl *func)();
char *savedPos;
unsigned int funcId;
int param_count;
unsigned int name;
const char *pName;
int type;
game::sval_u sourcePos;
game::VariableValue value;
savedPos = 0;
name = game::Scr_GetBuiltin(inst, func_name);
if ( !name )
{
goto script_function;
}
pName = game::SL_ConvertToString(name, inst);
sourcePos = func_name.node[2];
/*if (gScrCompilePub[inst].developer_statement == 3)
{
type = 0;
func = game::GetFunction(inst, &pName, &type);
}
else*/
{
funcId = game::FindVariable(name, game::gScrCompilePub[inst].builtinFunc, inst);
if ( funcId )
{
value = game::Scr_EvalVariable(inst, funcId);
type = game::Scr_GetUncacheType(value.type);
func = (void (__cdecl *)())value.u.intValue;
}
else
{
type = 0;
func = game::GetFunction(inst, &pName, &type);
funcId = game::GetNewVariable(inst, name, game::gScrCompilePub[inst].builtinFunc);
value.type = (game::VariableType)game::Scr_GetCacheType(type);
value.u.intValue = (int)func;
game::SetVariableValue(inst, &value, funcId);
}
}
if ( func )
{
if ( type == 1 && (game::Scr_BeginDevScript(inst, &type, &savedPos), type == 1) && !bStatement )
{
game::CompileError(inst, sourcePos.stringValue, "return value of developer command can not be accessed if not in a /# ... #/ comment");
}
else
{
param_count = game::EmitExpressionList(inst, params, block);
if ( param_count < 256 )
{
game::Scr_CompileRemoveRefToString(inst, name);
game::EmitCallBuiltinOpcode(inst, param_count, sourcePos);
game::EmitShort(inst, game::AddFunction(inst, (int)func));
game::AddExpressionListOpcodePos(inst, params);
if ( bStatement )
{
game::EmitDecTop(inst);
}
if ( type == 1 )
{
game::Scr_EndDevScript(inst, &savedPos);
}
}
else
{
game::CompileError(inst, sourcePos.stringValue, "parameter count exceeds 256");
}
}
}
else
{
script_function:
/*if (gScrCompilePub[inst].developer_statement == 3)
{
CompileError(inst, *(_DWORD *)(func_name.stringValue + 8), "unknown builtin function");
}
else*/
{
if ( func_name.node[0].type == game::ENUM_script_call)
{
game::EmitPreFunctionCall(inst);
}
param_count = game::EmitExpressionList(inst, params, block);
game::EmitPostFunctionCall(inst, 0, func_name, param_count, block);
game::AddExpressionListOpcodePos(inst, params);
if ( bStatement )
{
game::EmitDecTop(inst);
}
}
}
}
// Restored
game::BuiltinMethod GetMethod(game::scriptInstance_t inst, const char **pName, int *type)
{
if ( inst )
{
// pluto
if (game::plutonium::cscr_get_method_hook != nullptr)
{
return game::plutonium::cscr_get_method_hook(pName, type);
}
//
else
{
return game::CScr_GetMethod(pName, type);
}
}
// our addition
auto f = gsc::method::get(pName, type);
if (f != nullptr)
{
return f;
}
//
// pluto
if (game::plutonium::scr_get_method_hook != nullptr)
{
return game::plutonium::scr_get_method_hook(pName, type);
}
//
else
{
return game::Scr_GetMethod(type, pName);
}
}
// Completed
void EmitMethod(game::scriptInstance_t inst, game::sval_u expr, game::sval_u func_name, game::sval_u params, game::sval_u methodSourcePos, int bStatement, game::scr_block_s* block)
{
char *savedPos;
unsigned int methId;
void (__cdecl *meth)(game::scr_entref_t);
int param_count;
unsigned int name;
const char *pName;
int type;
game::sval_u sourcePos;
game::VariableValue value;
savedPos = 0;
name = game::Scr_GetBuiltin(inst, func_name);
if ( !name )
{
goto script_method;
}
pName = game::SL_ConvertToString(name, inst);
sourcePos = func_name.node[2];
/*if (gScrCompilePub[inst].developer_statement == 3)
{
type = 0;
meth = GetMethod(inst, &pName, &type);
}
else*/
{
methId = game::FindVariable(name, game::gScrCompilePub[inst].builtinMeth, inst);
if ( methId )
{
value = game::Scr_EvalVariable(inst, methId);
type = game::Scr_GetUncacheType(value.type);
meth = (void (__cdecl *)(game::scr_entref_t))value.u.intValue;
}
else
{
type = 0;
meth = game::GetMethod(inst, &pName, &type); // waltuh
methId = game::GetNewVariable(inst, name, game::gScrCompilePub[inst].builtinMeth);
value.type = (game::VariableType)game::Scr_GetCacheType(type);
value.u.intValue = (int)meth;
game::SetVariableValue(inst, &value, methId);
}
}
if ( meth )
{
if ( type == 1 && (game::Scr_BeginDevScript(inst, &type, &savedPos), type == 1) && !bStatement )
{
game::CompileError(inst, sourcePos.stringValue, "return value of developer command can not be accessed if not in a /# ... #/ comment");
}
else
{
param_count = game::EmitExpressionList(inst, params, block);
game::EmitPrimitiveExpression(inst, expr, block);
if ( param_count < 256 )
{
game::Scr_CompileRemoveRefToString(inst, name);
game::EmitCallBuiltinMethodOpcode(inst, param_count, sourcePos);
game::EmitShort(inst, game::AddFunction(inst, (int)meth));
game::AddOpcodePos(inst, methodSourcePos.stringValue, 0);
game::AddExpressionListOpcodePos(inst, params);
if ( bStatement )
{
game::EmitDecTop(inst);
}
// game::EmitAssignmentPos(inst);
if ( type == 1 )
{
game::Scr_EndDevScript(inst, &savedPos);
}
}
else
{
game::CompileError(inst, sourcePos.stringValue, "parameter count exceeds 256");
}
}
}
else
{
script_method:
/*if (gScrCompilePub[inst].developer_statement == 3)
{
CompileError(inst, *(_DWORD *)(func_name.stringValue + 8), "unknown builtin method");
}
else*/
{
if ( func_name.node[0].type == game::ENUM_script_call)
{
game::EmitPreFunctionCall(inst);
}
param_count = game::EmitExpressionList(inst, params, block);
game::EmitPrimitiveExpression(inst, expr, block);
game::EmitPostFunctionCall(inst, 1, func_name, param_count, block);
game::AddOpcodePos(inst, methodSourcePos.stringValue, 0);
game::AddExpressionListOpcodePos(inst, params);
if ( bStatement )
{
game::EmitDecTop(inst);
}
}
}
}
// Completed
void LinkThread(game::scriptInstance_t inst, unsigned int threadCountId, game::VariableValue* pos, int allowFarCall)
{
unsigned int valueId;
unsigned int countId;
int type;
int i;
game::VariableValueInternal_u *value;
game::VariableValue count;
countId = game::FindVariable(0, threadCountId, inst);
if ( countId )
{
count = game::Scr_EvalVariable(inst, countId);
assert(count.type == game::VAR_INTEGER);
for ( i = 0;
i < count.u.intValue;
++i )
{
valueId = game::FindVariable(i + 1, threadCountId, inst);
assert(valueId);
value = game::GetVariableValueAddress(inst, valueId);
type = game::GetValueType(inst, valueId);
assert(type == game::VAR_CODEPOS || type == game::VAR_DEVELOPER_CODEPOS);
if ( pos->type == game::VAR_DEVELOPER_CODEPOS )
{
assert(game::gScrVarPub[inst].developer_script);
if ( type == game::VAR_CODEPOS )
{
game::CompileError2(value->u.codePosValue, inst, game::CompileError2_ADDR(), "normal script cannot reference a function in a /# ... #/ comment");
return;
}
}
if ( pos->type == game::VAR_UNDEFINED || !allowFarCall && *(int*)value->u.codePosValue == 1 )
{
game::CompileError2(value->u.codePosValue, inst, game::CompileError2_ADDR(), "unknown function");
return;
}
*(int*)value->u.codePosValue = pos->u.intValue;
game::RemoveVariable(i + 1, threadCountId, inst);
}
game::RemoveVariable(0, threadCountId, inst);
}
}
// Restored
unsigned int GetVariableName(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 entryValue->w.status >> 8;
}
// Completed
void LinkFile(game::scriptInstance_t inst, unsigned int filePosId, unsigned int fileCountId)
{
unsigned int threadCountId;
game::VariableValue pos;
unsigned int threadCountPtr;
unsigned int posId;
game::VariableValue emptyValue;
unsigned int nameId;
emptyValue.type = game::VAR_UNDEFINED;
emptyValue.u.intValue = 0;
for ( threadCountPtr = game::FindFirstSibling(inst, fileCountId);
threadCountPtr;
threadCountPtr = game::FindNextSibling(inst, threadCountPtr) )
{
threadCountId = game::FindObject(inst, threadCountPtr);
assert(threadCountId);
nameId = game::GetVariableName(inst, threadCountPtr);
posId = game::FindVariable(nameId, filePosId, inst);
if ( posId )
{
pos = game::Scr_EvalVariable(inst, posId);
assert(pos.type == game::VAR_CODEPOS || pos.type == game::VAR_DEVELOPER_CODEPOS);
assert(pos.u.codePosValue);
game::LinkThread(inst, threadCountId, &pos, 1);
}
else
{
game::LinkThread(inst, threadCountId, &emptyValue, 1);
}
}
game::ClearObject(fileCountId, inst);
}
// Completed
void CheckThreadPosition(game::scriptInstance_t inst, unsigned int posId, unsigned int name, unsigned int sourcePos)
{
game::VariableValue pos;
assert(!game::gScrVarPub[inst].evaluate);
pos = game::Scr_EvalVariable(inst, posId);
if ( pos.type != game::VAR_UNDEFINED )
{
// pluto
auto* developer = game::Dvar_FindVar("developer");
if ( pos.u.intValue && developer && developer->current.enabled )
//
{
game::CompileError(inst, sourcePos, "function '%s' already defined in '%s'", game::SL_ConvertToString(name, inst), game::gScrParserPub[inst].sourceBufferLookup[game::Scr_GetSourceBuffer(inst, pos.u.codePosValue)].buf);
}
else
{
game::CompileError(inst, sourcePos, "function '%s' already defined", game::SL_ConvertToString(name, inst));
}
}
}
// Completed
void EmitCallExpression(game::scriptInstance_t inst, game::scr_block_s* block, game::sval_u expr, int bStatement)
{
if (expr.node[0].type == game::ENUM_call)
{
game::EmitCall(inst, expr.node[1], expr.node[2], bStatement, block);
}
else if (expr.node[0].type == game::ENUM_method)
{
game::EmitMethod(
inst,
expr.node[1],
expr.node[2],
expr.node[3],
expr.node[4],
bStatement,
block);
}
}
// Completed
void EmitCallExpressionFieldObject(game::scr_block_s* block, game::scriptInstance_t inst, game::sval_u expr)
{
if (expr.node[0].type == game::ENUM_call)
{
game::EmitCall(inst, expr.node[1], expr.node[2], 0, block);
game::EmitCastFieldObject(inst, expr.node[3]);
}
else if (expr.node[0].type == game::ENUM_method)
{
game::EmitMethod(
inst,
expr.node[1],
expr.node[2],
expr.node[3],
expr.node[4],
0,
block);
game::EmitCastFieldObject(inst, expr.node[5]);
}
}
// Completed
void Scr_CreateVector(game::scriptInstance_t inst, game::VariableCompileValue* constValue, game::VariableValue* value)
{
int type;
int i;
float vec[3];
for ( i = 0;
i < 3;
++i )
{
type = constValue[i].value.type;
if ( type == game::VAR_FLOAT )
{
vec[2 - i] = constValue[i].value.u.floatValue;
}
else
{
if ( type != game::VAR_INTEGER )
{
game::CompileError(inst, constValue[i].sourcePos.stringValue, "type %s is not a float", game::var_typename[type]);
return;
}
vec[2 - i] = (float)constValue[i].value.u.intValue;
}
}
value->type = game::VAR_VECTOR;
value->u.vectorValue = game::Scr_AllocVector_(inst, vec);
}
// Restored
int GetExpressionCount(game::sval_u exprlist)
{
game::sval_u *node;
int expr_count;
expr_count = 0;
for ( node = exprlist.node->node;
node;
node = node[1].node )
{
++expr_count;
}
return expr_count;
}
// Completed
bool EvalPrimitiveExpressionList(game::scriptInstance_t inst, game::sval_u exprlist, game::sval_u sourcePos, game::VariableCompileValue* constValue)
{
game::sval_u* node;
game::VariableCompileValue constValue2[3];
int expr_count;
int i;
assert(constValue);
expr_count = game::GetExpressionCount(exprlist);
if ( expr_count == 1 )
{
return game::EvalExpression(constValue, inst, exprlist.node->node->node[0]);
}
if ( expr_count != 3 )
{
return 0;
}
i = 0;
for ( node = exprlist.node->node;
node;
node = node[1].node )
{
if ( !game::EvalExpression(&constValue2[i], inst, *node->node) )
{
return 0;
}
++i;
}
game::Scr_CreateVector(inst, constValue2, &constValue->value);
constValue->sourcePos = sourcePos;
return 1;
}
// Completed
bool EmitOrEvalPrimitiveExpressionList(game::scriptInstance_t inst, game::sval_u exprlist, game::sval_u sourcePos, game::VariableCompileValue* constValue, game::scr_block_s* block)
{
bool result;
game::sval_u *node;
game::VariableCompileValue constValue2;
int expr_count;
bool success;
assert(constValue);
expr_count = game::GetExpressionCount(exprlist);
if ( expr_count == 1 )
{
return game::EmitOrEvalExpression(inst, exprlist.node->node->node[0], constValue, block);
}
if ( expr_count == 3 )
{
success = 1;
for ( node = exprlist.node->node;
node;
node = node[1].node )
{
if ( success )
{
success = game::EmitOrEvalExpression(inst, *node->node, &constValue2, block);
if ( success )
{
game::Scr_PushValue(inst, &constValue2);
}
}
else
{
game::EmitExpression(inst, *node->node, block);
}
}
if ( success )
{
assert(game::gScrCompilePub[inst].value_count >= 3);
game::gScrCompilePub[inst].value_count -= 3;
game::Scr_CreateVector(inst, &game::gScrCompileGlob[inst].value_start[game::gScrCompilePub[inst].value_count], &constValue->value);
constValue->sourcePos = sourcePos;
result = 1;
}
else
{
game::EmitOpcode(inst, game::OP_vector, -2, 0);
game::AddOpcodePos(inst, sourcePos.stringValue, 1);
game::AddExpressionListOpcodePos(inst, exprlist);
result = 0;
}
}
else
{
game::CompileError(inst, sourcePos.stringValue, "expression list must have 1 or 3 parameters");
result = 0;
}
return result;
}
// Restored
game::sval_u * GetSingleParameter(game::sval_u exprlist)
{
if ( !exprlist.node->node )
{
return 0;
}
if ( exprlist.node->node[1].node )
{
return 0;
}
return exprlist.node->node;
}
// Restored
void EmitExpressionFieldObject(game::scriptInstance_t inst, game::sval_u expr, game::sval_u sourcePos, game::scr_block_s *block)
{
if ( expr.node[0].type == game::ENUM_primitive_expression)
{
game::EmitPrimitiveExpressionFieldObject(inst, expr.node[1], expr.node[2], block);
}
else
{
game::CompileError(inst, sourcePos.stringValue, "not an object");
}
}
// Completed
void EmitExpressionListFieldObject(game::scriptInstance_t inst, game::sval_u exprlist, game::sval_u sourcePos, game::scr_block_s* block)
{
game::sval_u *node;
node = game::GetSingleParameter(exprlist);
if ( node )
{
game::EmitExpressionFieldObject(inst, *node->node, node->node[1], block);
}
else
{
game::CompileError(inst, sourcePos.stringValue, "not an object");
}
}
// Restored
void EvalInteger(int value, game::sval_u sourcePos, game::VariableCompileValue *constValue)
{
assert(constValue);
constValue->value.type = game::VAR_INTEGER;
constValue->value.u.intValue = value;
constValue->sourcePos = sourcePos;
}
// Restored
void EvalFloat(float value, game::sval_u sourcePos, game::VariableCompileValue *constValue)
{
assert(constValue);
constValue->value.type = game::VAR_FLOAT;
constValue->value.u.floatValue = value;
constValue->sourcePos = sourcePos;
}
// Restored
void EvalString(unsigned int value, game::sval_u sourcePos, game::VariableCompileValue *constValue)
{
assert(constValue);
constValue->value.type = game::VAR_STRING;
constValue->value.u.stringValue = value;
constValue->sourcePos = sourcePos;
}
// Restored
void EvalIString(unsigned int value, game::sval_u sourcePos, game::VariableCompileValue *constValue)
{
assert(constValue);
constValue->value.type = game::VAR_ISTRING;
constValue->value.u.stringValue = value;
constValue->sourcePos = sourcePos;
}
// Restored
void EvalUndefined(game::sval_u sourcePos, game::VariableCompileValue *constValue)
{
assert(constValue);
constValue->value.type = game::VAR_UNDEFINED;
constValue->sourcePos = sourcePos;
}
// Completed
bool EvalPrimitiveExpression(game::scriptInstance_t inst, game::sval_u expr, game::VariableCompileValue* constValue)
{
bool result;
switch ( expr.node[0].type )
{
case game::ENUM_integer:
game::EvalInteger(expr.node[1].intValue, expr.node[2], constValue);
result = 1;
break;
case game::ENUM_float:
game::EvalFloat(expr.node[1].floatValue, expr.node[2], constValue);
result = 1;
break;
case game::ENUM_minus_integer:
game::EvalInteger(-expr.node[1].intValue, expr.node[2], constValue);
result = 1;
break;
case game::ENUM_minus_float:
game::EvalFloat(-expr.node[1].floatValue, expr.node[2], constValue);
result = 1;
break;
case game::ENUM_string:
game::EvalString(expr.node[1].stringValue, expr.node[2], constValue);
result = 1;
break;
case game::ENUM_istring:
game::EvalIString(expr.node[1].stringValue, expr.node[2], constValue);
result = 1;
break;
case game::ENUM_undefined:
game::EvalUndefined(expr.node[1], constValue);
result = 1;
break;
case game::ENUM_expression_list:
result = game::EvalPrimitiveExpressionList(inst, expr.node[1], expr.node[2], constValue);
break;
case game::ENUM_false:
game::EvalInteger(0, expr.node[1], constValue);
result = 1;
break;
case game::ENUM_true:
game::EvalInteger(1, expr.node[1], constValue);
result = 1;
break;
default:
result = 0;
break;
}
return result;
}
// Completed
bool EmitOrEvalPrimitiveExpression(game::scriptInstance_t inst, game::sval_u expr, game::VariableCompileValue* constValue, game::scr_block_s* block)
{
bool result;
switch (expr.node[0].type)
{
case game::ENUM_variable:
game::EmitVariableExpression(inst, expr.node[1], block);
result = 0;
break;
case game::ENUM_function:
game::EmitGetFunction(inst, expr.node[1], expr.node[2]);
result = 0;
break;
case game::ENUM_call_expression:
game::EmitCallExpression(inst, block, expr.node[1], 0);
result = 0;
break;
case game::ENUM_self:
game::EmitSelf(inst, expr.node[1]);
result = 0;
break;
case game::ENUM_level:
game::EmitLevel(inst, expr.node[1]);
result = 0;
break;
case game::ENUM_game:
game::EmitGame(inst, expr.node[1]);
result = 0;
break;
case game::ENUM_anim:
game::EmitAnim(inst, expr.node[1]);
result = 0;
break;
case game::ENUM_expression_list:
result = game::EmitOrEvalPrimitiveExpressionList(
inst,
expr.node[1],
expr.node[2],
constValue,
block);
break;
case game::ENUM_size_field:
game::EmitSize(block, inst, expr.node[1], expr.node[2]);
result = 0;
break;
case game::ENUM_empty_array:
game::EmitEmptyArray(inst, expr.node[1]);
result = 0;
break;
case game::ENUM_animation:
game::EmitAnimation(inst, expr.node[1], expr.node[2]);
result = 0;
break;
case game::ENUM_animtree:
game::EmitAnimTree(inst, expr.node[1]);
result = 0;
break;
case game::ENUM_breakon:
game::CompileError(inst, expr.node[3].sourcePosValue, "illegal function name");
default:
result = game::EvalPrimitiveExpression(inst, expr, constValue);
break;
}
return result;
}
// Completed
void EmitBoolOrExpression(game::scriptInstance_t inst, game::sval_u expr1, game::sval_u expr2, game::sval_u expr1sourcePos, game::sval_u expr2sourcePos, game::scr_block_s* block)
{
char *pos;
unsigned int offset;
const char *nextPos;
game::EmitExpression(inst, expr1, block);
game::EmitOpcode(inst, game::OP_JumpOnTrueExpr, -1, 0);
game::AddOpcodePos(inst, expr1sourcePos.stringValue, 0);
game::EmitShort(inst, 0);
pos = game::gScrCompileGlob[inst].codePos;
nextPos = game::TempMalloc(0);
game::EmitExpression(inst, expr2, block);
game::EmitCastBool(inst, expr2sourcePos);
offset = game::TempMalloc(0) - nextPos;
assert(offset < 65536);
*(short *)pos = (short)offset;
}
// Completed
void EmitBoolAndExpression(game::scriptInstance_t inst, game::sval_u expr1, game::sval_u expr2, game::sval_u expr1sourcePos, game::sval_u expr2sourcePos, game::scr_block_s* block)
{
char *pos;
unsigned int offset;
const char *nextPos;
game::EmitExpression(inst, expr1, block);
game::EmitOpcode(inst, game::OP_JumpOnFalseExpr, -1, 0);
game::AddOpcodePos(inst, expr1sourcePos.stringValue, 0);
game::EmitShort(inst, 0);
pos = game::gScrCompileGlob[inst].codePos;
nextPos = game::TempMalloc(0);
game::EmitExpression(inst, expr2, block);
game::EmitCastBool(inst, expr2sourcePos);
offset = game::TempMalloc(0) - nextPos;
assert(offset < 65536);
*(short *)pos = (short)offset;
}
// Copleted
bool EvalBinaryOperatorExpression(game::scriptInstance_t inst, game::sval_u expr1, game::sval_u expr2, game::sval_u opcode, game::sval_u sourcePos, game::VariableCompileValue* constValue)
{
bool result;
game::VariableCompileValue constValue2;
game::VariableCompileValue constValue1;
if ( !game::EvalExpression(&constValue1, inst, expr1) )
{
return 0;
}
if ( !game::EvalExpression(&constValue2, inst, expr2) )
{
return 0;
}
game::AddRefToValue(inst, constValue1.value.type, constValue1.value.u);
game::AddRefToValue(inst, constValue2.value.type, constValue2.value.u);
game::Scr_EvalBinaryOperator(inst, &constValue2.value, (game::OpcodeVM)opcode.intValue, &constValue1.value);
if ( game::gScrVarPub[inst].error_message )
{
game::CompileError(inst, sourcePos.stringValue, "%s", game::gScrVarPub[inst].error_message);
result = 0;
}
else
{
constValue->value.u.intValue = constValue1.value.u.intValue;
constValue->value.type = constValue1.value.type;
constValue->sourcePos = sourcePos;
result = 1;
}
return result;
}
// Restored
void Scr_PopValue(game::scriptInstance_t inst)
{
assert(game::gScrCompilePub[inst].value_count);
--game::gScrCompilePub[inst].value_count;
}
// Completed
bool EmitOrEvalBinaryOperatorExpression(game::scriptInstance_t inst, game::sval_u expr1, game::sval_u expr2, game::sval_u opcode, game::sval_u sourcePos, game::VariableCompileValue* constValue, game::scr_block_s* block)
{
bool result;
game::VariableCompileValue constValue2;
game::VariableCompileValue constValue1;
if ( !game::EmitOrEvalExpression(inst, expr1, &constValue1, block) )
{
game::EmitExpression(inst, expr2, block);
emitOpcode:
game::EmitOpcode(inst, (game::OpcodeVM)opcode.type, -1, 0);
game::AddOpcodePos(inst, sourcePos.stringValue, 0);
return 0;
}
game::Scr_PushValue(inst, &constValue1);
if ( !game::EmitOrEvalExpression(inst, expr2, &constValue2, block) )
{
goto emitOpcode;
}
game::Scr_PopValue(inst);
game::Scr_EvalBinaryOperator(inst, &constValue2.value, (game::OpcodeVM)opcode.intValue, &constValue1.value);
if ( game::gScrVarPub[inst].error_message )
{
game::CompileError(inst, sourcePos.stringValue, "%s", game::gScrVarPub[inst].error_message);
result = 0;
}
else
{
constValue->value.u.intValue = constValue1.value.u.intValue;
constValue->value.type = constValue1.value.type;
constValue->sourcePos = sourcePos;
result = 1;
}
return result;
}
// Restored
void EmitSetVariableField(game::scriptInstance_t inst, game::sval_u sourcePos)
{
game::EmitOpcode(inst, game::OP_SetVariableField, -1, 0);
game::AddOpcodePos(inst, sourcePos.stringValue, 0);
// game::EmitAssignmentPos(inst);
}
// Completed
void EmitBinaryEqualsOperatorExpression(game::scr_block_s* block, game::scriptInstance_t inst, game::sval_u lhs, game::sval_u rhs, game::sval_u opcode, game::sval_u sourcePos)
{
assert(!game::gScrCompileGlob[inst].bConstRefCount);
game::gScrCompileGlob[inst].bConstRefCount = 1;
game::EmitVariableExpression(inst, lhs, block);
assert(game::gScrCompileGlob[inst].bConstRefCount);
game::gScrCompileGlob[inst].bConstRefCount = 0;
game::EmitExpression(inst, rhs, block);
game::EmitOpcode(inst, (game::OpcodeVM)opcode.type, -1, 0);
game::AddOpcodePos(inst, sourcePos.stringValue, 0);
game::EmitVariableExpressionRef(inst, lhs, block);
game::EmitSetVariableField(inst, sourcePos);
}
// Completed
void Scr_CalcLocalVarsVariableExpressionRef(game::scr_block_s* block, game::sval_u expr)
{
if (expr.node[0].type == game::ENUM_local_variable)
{
game::Scr_RegisterLocalVar(expr.node[1].stringValue, expr.node[2], block);
}
else if (expr.node[0].type == game::ENUM_array_variable)
{
game::Scr_CalcLocalVarsArrayVariableRef(expr.node[1], block);
}
}
// Completed
bool EvalExpression(game::VariableCompileValue* constValue, game::scriptInstance_t inst, game::sval_u expr)
{
if (expr.node[0].type == game::ENUM_primitive_expression)
{
return game::EvalPrimitiveExpression(inst, expr.node[1], constValue);
}
if (expr.node[0].type == game::ENUM_binary)
{
return game::EvalBinaryOperatorExpression(
inst,
expr.node[1],
expr.node[2],
expr.node[3],
expr.node[4],
constValue);
}
return 0;
}
// Completed
bool EmitOrEvalExpression(game::scriptInstance_t inst, game::sval_u expr, game::VariableCompileValue* constValue, game::scr_block_s* block)
{
bool result;
switch ( expr.node[0].type )
{
case game::ENUM_duplicate_expression:
assert(!game::gScrCompileGlob[inst].bConstRefCount);
game::gScrCompileGlob[inst].bConstRefCount = 1;
result = game::EmitOrEvalExpression(inst, expr.node[1], constValue, block);
assert(game::gScrCompileGlob[inst].bConstRefCount);
game::gScrCompileGlob[inst].bConstRefCount = 0;
break;
case game::ENUM_primitive_expression:
result = EmitOrEvalPrimitiveExpression(inst, expr.node[1], constValue, block);
break;
case game::ENUM_bool_or:
game::EmitBoolOrExpression(inst, expr.node[1], expr.node[2], expr.node[3], expr.node[4], block);
result = 0;
break;
case game::ENUM_bool_and:
game::EmitBoolAndExpression(inst, expr.node[1], expr.node[2], expr.node[3], expr.node[4], block);
result = 0;
break;
case game::ENUM_binary:
result = game::EmitOrEvalBinaryOperatorExpression(inst, expr.node[1], expr.node[2], expr.node[3], expr.node[4], constValue, block);
break;
case game::ENUM_bool_not:
game::EmitExpression(inst, expr.node[1], block);
game::EmitBoolNot(inst, expr.node[2]);
result = 0;
break;
case game::ENUM_bool_complement:
game::EmitExpression(inst, expr.node[1], block);
game::EmitBoolComplement(inst, expr.node[2]);
result = 0;
break;
default:
result = 0;
break;
}
return result;
}
// Completed
void EmitExpression(game::scriptInstance_t inst, game::sval_u expr, game::scr_block_s* block)
{
game::VariableCompileValue constValue;
if (game::EmitOrEvalExpression(inst, expr, &constValue, block))
{
game::EmitValue(inst, &constValue);
}
}
// Restored
void EmitFieldVariableRef(game::scriptInstance_t inst, game::sval_u expr, game::sval_u field, game::sval_u sourcePos, game::scr_block_s *block)
{
game::EmitPrimitiveExpressionFieldObject(inst, expr, sourcePos, block);
game::EmitOpcode(inst, game::OP_EvalFieldVariableRef, 0, 0);
game::EmitCanonicalString(inst, field.stringValue);
}
// Completed
void EmitVariableExpressionRef(game::scriptInstance_t inst, game::sval_u expr, game::scr_block_s* block)
{
switch ( expr.node[0].type )
{
case game::ENUM_duplicate_variable:
assert(!game::gScrCompileGlob[inst].bConstRefCount);
game::gScrCompileGlob[inst].bConstRefCount = 1;
game::EmitVariableExpressionRef(inst, expr.node[1], block);
assert(game::gScrCompileGlob[inst].bConstRefCount);
game::gScrCompileGlob[inst].bConstRefCount = 0;
break;
case game::ENUM_local_variable:
game::EmitLocalVariableRef(block, inst, expr.node[1], expr.node[2]);
break;
case game::ENUM_array_variable:
game::EmitArrayVariableRef(block, inst, expr.node[1], expr.node[2], expr.node[3], expr.node[4]);
break;
case game::ENUM_field_variable:
game::EmitFieldVariableRef(inst, expr.node[1], expr.node[2], expr.node[3], block);
break;
case game::ENUM_self_field:
case game::ENUM_object:
if ( game::gScrCompilePub[inst].script_loading )
{
game::CompileError(inst, expr.node[2].sourcePosValue, "$ and self field can only be used in the script debugger");
}
else
{
game::CompileError(inst, expr.node[2].sourcePosValue, "not an lvalue");
}
break;
default:
return;
}
}
// Completed
void EmitArrayPrimitiveExpressionRef(game::scriptInstance_t inst, game::sval_u expr, game::sval_u sourcePos, game::scr_block_s* block)
{
if (expr.node[0].type == game::ENUM_variable)
{
game::EmitVariableExpressionRef(inst, expr.node[1], block);
}
else
{
if (expr.node[0].type != game::ENUM_game)
{
game::CompileError(inst, sourcePos.stringValue, "not an lvalue");
}
game::EmitGameRef(inst, expr.node[1]);
}
}
// Restored
void Scr_CalcLocalVarsArrayPrimitiveExpressionRef(game::sval_u expr, game::scr_block_s *block)
{
if ( expr.node[0].type == game::ENUM_variable )
{
game::Scr_CalcLocalVarsVariableExpressionRef(block, expr.node[1]);
}
}
// Completed
void Scr_CalcLocalVarsArrayVariableRef(game::sval_u expr, game::scr_block_s* block)
{
game::Scr_CalcLocalVarsArrayPrimitiveExpressionRef(expr, block);
}
// Completed
void EmitPrimitiveExpressionFieldObject(game::scriptInstance_t inst, game::sval_u expr, game::sval_u sourcePos, game::scr_block_s* block)
{
switch ( expr.node[0].type )
{
case game::ENUM_variable:
game::EmitVariableExpression(inst, expr.node[1], block);
game::EmitCastFieldObject(inst, expr.node[2]);
break;
case game::ENUM_call_expression:
game::EmitCallExpressionFieldObject(block, inst, expr.node[1]);
break;
case game::ENUM_self:
game::EmitSelfObject(inst, expr.node[1]);
break;
case game::ENUM_level:
game::EmitLevelObject(inst, expr.node[1]);
break;
case game::ENUM_anim:
game::EmitAnimObject(inst, expr.node[1]);
break;
case game::ENUM_expression_list:
game::EmitExpressionListFieldObject(inst, expr.node[1], sourcePos, block);
break;
default:
game::CompileError(inst, sourcePos.stringValue, "not an object");
break;
}
}
// Completed
void ConnectBreakStatements(game::scriptInstance_t inst)
{
game::BreakStatementInfo *breakStatement;
const char *codePos;
assert(!game::gScrCompilePub[inst].value_count);
codePos = game::TempMalloc(0);
for ( breakStatement = game::gScrCompileGlob[inst].currentBreakStatement;
breakStatement;
breakStatement = breakStatement->next )
{
*(int *)breakStatement->codePos = codePos - breakStatement->nextCodePos;
}
}
// Completed
void ConnectContinueStatements(game::scriptInstance_t inst)
{
game::ContinueStatementInfo *continueStatement;
const char *codePos;
codePos = game::TempMalloc(0);
for ( continueStatement = game::gScrCompileGlob[inst].currentContinueStatement;
continueStatement;
continueStatement = continueStatement->next )
{
*(int *)continueStatement->codePos = codePos - continueStatement->nextCodePos;
}
}
// Completed
bool EmitClearVariableExpression(game::scr_block_s* block, game::scriptInstance_t inst, game::sval_u expr, game::sval_u rhsSourcePos)
{
bool result;
const char* s;
switch (expr.node[0].type)
{
case game::ENUM_local_variable:
result = 0;
break;
case game::ENUM_array_variable:
game::EmitClearArrayVariable(
block,
inst,
expr.node[1],
expr.node[2],
expr.node[3],
expr.node[4]);
result = 1;
break;
case game::ENUM_field_variable:
game::EmitClearFieldVariable(
block,
inst,
expr.node[1],
expr.node[2],
expr.node[3],
rhsSourcePos);
result = 1;
break;
case game::ENUM_self_field:
case game::ENUM_object:
s = "not an lvalue";
if (game::gScrCompilePub[inst].script_loading)
{
s = "$ and self field can only be used in the script debugger";
}
game::CompileError(inst, expr.node[2].sourcePosValue, s);
default:
result = 1;
break;
}
return result;
}
// Restored
BOOL IsUndefinedPrimitiveExpression(game::sval_u expr)
{
return expr.node[0].type == game::ENUM_undefined;
}
// Restored
bool IsUndefinedExpression(game::sval_u expr)
{
if ( expr.node[0].type == game::ENUM_primitive_expression)
{
return game::IsUndefinedPrimitiveExpression(expr.node[1]);
}
return 0;
}
// Completed
void EmitAssignmentStatement(game::scriptInstance_t inst, game::sval_u lhs, game::sval_u rhs, game::sval_u sourcePos, game::sval_u rhsSourcePos, game::scr_block_s* block)
{
if ( !game::IsUndefinedExpression(rhs) || !game::EmitClearVariableExpression(block, inst, lhs, rhsSourcePos) )
{
game::EmitExpression(inst, rhs, block);
game::EmitVariableExpressionRef(inst, lhs, block);
game::EmitSetVariableField(inst, sourcePos);
}
}
// Completed
void EmitCallExpressionStatement(game::scriptInstance_t inst, game::scr_block_s* block, game::sval_u expr)
{
game::EmitCallExpression(inst, block, expr, 1);
}
// Completed
void EmitReturnStatement(game::scr_block_s* block, game::scriptInstance_t inst, game::sval_u expr, game::sval_u sourcePos)
{
if ( !block->abortLevel )
{
block->abortLevel = 3;
}
game::EmitExpression(inst, expr, block);
game::EmitReturn(inst);
game::AddOpcodePos(inst, sourcePos.stringValue, 0);
}
// Completed
void EmitWaitStatement(game::scr_block_s* block, game::scriptInstance_t inst, game::sval_u expr, game::sval_u sourcePos, game::sval_u waitSourcePos)
{
game::EmitExpression(inst, expr, block);
game::EmitOpcode(inst, game::OP_wait, -1, 0);
game::AddOpcodePos(inst, waitSourcePos.stringValue, 0);
game::AddOpcodePos(inst, waitSourcePos.stringValue, 0);
game::AddOpcodePos(inst, sourcePos.stringValue, 0);
}
// Completed
void EmitWaittillFrameEnd(game::scriptInstance_t inst, game::sval_u sourcePos)
{
game::EmitOpcode(inst, game::OP_waittillFrameEnd, 0, 0);
game::AddOpcodePos(inst, sourcePos.stringValue, 1);
game::AddOpcodePos(inst, sourcePos.stringValue, 0);
}
// Completed
void EmitIfStatement(game::scriptInstance_t inst, game::sval_u expr, game::sval_u stmt, game::sval_u sourcePos, int lastStatement, unsigned int endSourcePos, game::scr_block_s* block, game::sval_u* ifStatBlock)
{
char *pos;
unsigned int offset;
const char *nextPos;
game::EmitExpression(inst, expr, block);
game::EmitOpcode(inst, game::OP_JumpOnFalse, -1, 0);
game::AddOpcodePos(inst, sourcePos.stringValue, 0);
game::EmitShort(inst, 0);
pos = game::gScrCompileGlob[inst].codePos;
nextPos = game::TempMalloc(0);
game::Scr_TransferBlock(ifStatBlock->block, block);
game::EmitStatement(inst, stmt, lastStatement, endSourcePos, ifStatBlock->block);
assert(ifStatBlock->block->localVarsPublicCount == block->localVarsCreateCount);
game::EmitNOP2(ifStatBlock->block, inst, lastStatement, endSourcePos);
offset = game::TempMalloc(0) - nextPos;
assert(offset < 65536);
*(short *)pos = (short)offset;
}
// Restored
void Scr_CopyBlock(game::scr_block_s *from, game::scr_block_s **to)
{
if ( !*to )
{
*to = (game::scr_block_s*)game::Hunk_AllocateTempMemoryHigh(sizeof(game::scr_block_s));
}
memcpy(*to, from, sizeof(game::scr_block_s));
(*to)->localVarsPublicCount = 0;
}
// Completed
void Scr_CalcLocalVarsIfStatement(game::scriptInstance_t inst, game::sval_u stmt, game::scr_block_s* block, game::sval_u* ifStatBlock)
{
game::Scr_CopyBlock(block, (game::scr_block_s **)ifStatBlock);
game::Scr_CalcLocalVarsStatement(inst, stmt, ifStatBlock->block);
game::Scr_MergeChildBlocks((game::scr_block_s **)ifStatBlock, 1, block);
}
// Completed
void EmitIfElseStatement(game::scriptInstance_t inst, game::sval_u expr, game::sval_u stmt1, game::sval_u stmt2, game::sval_u sourcePos, game::sval_u elseSourcePos, int lastStatement, unsigned int endSourcePos, game::scr_block_s* block, game::sval_u* ifStatBlock, game::sval_u* elseStatBlock)
{
int checksum;
unsigned int offset;
const char *nextPos1;
char *pos1;
game::scr_block_s *childBlocks[2];
const char *nextPos2;
int childCount;
const char *pos2;
childCount = 0;
game::EmitExpression(inst, expr, block);
game::EmitOpcode(inst, game::OP_JumpOnFalse, -1, 0);
game::AddOpcodePos(inst, sourcePos.stringValue, 0);
game::EmitShort(inst, 0);
pos1 = game::gScrCompileGlob[inst].codePos;
nextPos1 = game::TempMalloc(0);
game::Scr_TransferBlock(ifStatBlock->block, block);
game::EmitStatement(inst, stmt1, lastStatement, endSourcePos, ifStatBlock->block);
game::EmitRemoveLocalVars(inst, ifStatBlock->block, ifStatBlock->block);
if ( !ifStatBlock->block->abortLevel )
{
childBlocks[childCount++] = ifStatBlock->block;
}
checksum = game::gScrVarPub[inst].checksum;
if ( (char)lastStatement )
{
game::EmitEnd(inst);
game::EmitCodepos(inst, 0);
game::AddOpcodePos(inst, endSourcePos, 1);
pos2 = 0;
nextPos2 = 0;
}
else
{
game::EmitOpcode(inst, game::OP_jump, 0, 0);
game::AddOpcodePos(inst, elseSourcePos.stringValue, 1);
game::EmitCodepos(inst, 0);
pos2 = game::gScrCompileGlob[inst].codePos;
nextPos2 = game::TempMalloc(0);
}
game::gScrVarPub[inst].checksum = checksum + 1;
offset = game::TempMalloc(0) - nextPos1;
assert(offset < 65536);
*(short *)pos1 = (short)offset;
game::Scr_TransferBlock(elseStatBlock->block, block);
game::EmitStatement(inst, stmt2, lastStatement, endSourcePos, elseStatBlock->block);
game::EmitNOP2(elseStatBlock->block, inst, lastStatement, endSourcePos);
if ( !elseStatBlock->block->abortLevel )
{
childBlocks[childCount++] = elseStatBlock->block;
}
if ( !(char)lastStatement )
{
*(int*)pos2 = game::TempMalloc(0) - nextPos2;
}
game::Scr_InitFromChildBlocks(childBlocks, childCount, block);
}
// Completed
void Scr_CalcLocalVarsIfElseStatement(game::scriptInstance_t inst, game::sval_u stmt1, game::sval_u stmt2, game::scr_block_s* block, game::sval_u* ifStatBlock, game::sval_u* elseStatBlock)
{
game::scr_block_s *childBlocks[2];
int childCount;
int abortLevel;
childCount = 0;
abortLevel = 3;
game::Scr_CopyBlock(block, (game::scr_block_s **)ifStatBlock);
game::Scr_CalcLocalVarsStatement(inst, stmt1, ifStatBlock->block);
if ( ifStatBlock->node->intValue <= 3 )
{
abortLevel = ifStatBlock->node->intValue;
if ( !abortLevel )
{
childBlocks[childCount++] = ifStatBlock->block;
}
}
game::Scr_CopyBlock(block, (game::scr_block_s **)elseStatBlock);
game::Scr_CalcLocalVarsStatement(inst, stmt2, elseStatBlock->block);
if ( elseStatBlock->node->intValue <= abortLevel )
{
abortLevel = elseStatBlock->node->intValue;
if ( !abortLevel )
{
childBlocks[childCount++] = elseStatBlock->block;
}
}
if ( !block->abortLevel )
{
block->abortLevel = abortLevel;
}
game::Scr_AppendChildBlocks(block, childBlocks, childCount);
game::Scr_MergeChildBlocks(childBlocks, childCount, block);
}
// Restored
void Scr_CheckMaxSwitchCases(int count)
{
if ( count >= 512 )
{
game::Com_Error(game::ERR_DROP, "MAX_SWITCH_CASES exceeded");
}
}
// Completed
void Scr_AddBreakBlock(game::scriptInstance_t inst, game::scr_block_s* block)
{
if ( !block->abortLevel && game::gScrCompileGlob[inst].breakChildBlocks && game::gScrCompilePub[inst].developer_statement != 2 )
{
game::Scr_CheckMaxSwitchCases(*game::gScrCompileGlob[inst].breakChildCount);
game::gScrCompileGlob[inst].breakChildBlocks[(*game::gScrCompileGlob[inst].breakChildCount)++] = block;
}
}
// Completed
void Scr_AddContinueBlock(game::scriptInstance_t inst, game::scr_block_s* block)
{
if ( !block->abortLevel && game::gScrCompileGlob[inst].continueChildBlocks && game::gScrCompilePub[inst].developer_statement != 2 )
{
game::Scr_CheckMaxSwitchCases(*game::gScrCompileGlob[inst].continueChildCount);
game::gScrCompileGlob[inst].continueChildBlocks[(*game::gScrCompileGlob[inst].continueChildCount)++] = block;
}
}
// Completed
void EmitWhileStatement(game::scriptInstance_t inst, game::sval_u expr, game::sval_u stmt, game::sval_u sourcePos, game::sval_u whileSourcePos, game::scr_block_s* block, game::sval_u* whileStatBlock)
{
game::ContinueStatementInfo *oldContinueStatement;
int breakChildCount;
int *oldBreakChildCount;
game::scr_block_s **breakChildBlocks;
game::BreakStatementInfo *oldBreakStatement;
bool constConditional;
unsigned int offset;
bool bOldCanBreak;
bool bOldCanContinue;
int *oldContinueChildCount;
game::VariableCompileValue constValue;
const char *pos1;
const char *nextPos2;
game::scr_block_s **oldBreakChildBlocks;
const char *pos2;
game::scr_block_s **oldContinueChildBlocks;
game::scr_block_s *oldBreakBlock;
bOldCanBreak = game::gScrCompileGlob[inst].bCanBreak;
oldBreakStatement = game::gScrCompileGlob[inst].currentBreakStatement;
game::gScrCompileGlob[inst].bCanBreak = 0;
bOldCanContinue = game::gScrCompileGlob[inst].bCanContinue;
oldContinueStatement = game::gScrCompileGlob[inst].currentContinueStatement;
game::gScrCompileGlob[inst].bCanContinue = 0;
game::Scr_TransferBlock(whileStatBlock->block, block);
game::EmitCreateLocalVars(inst, whileStatBlock->block);
assert(whileStatBlock->block->localVarsCreateCount <= block->localVarsCount);
block->localVarsCreateCount = whileStatBlock->block->localVarsCreateCount;
pos1 = game::TempMalloc(0);
constConditional = 0;
if ( game::EmitOrEvalExpression(inst, expr, &constValue, block) )
{
if ( constValue.value.type == game::VAR_INTEGER || constValue.value.type == game::VAR_FLOAT )
{
game::Scr_CastBool(inst, &constValue.value);
if ( !constValue.value.u.intValue )
{
game::CompileError(inst, sourcePos.stringValue, "conditional expression cannot be always false");
}
constConditional = 1;
}
else
{
game::EmitValue(inst, &constValue);
}
}
oldBreakChildBlocks = game::gScrCompileGlob[inst].breakChildBlocks;
oldBreakChildCount = game::gScrCompileGlob[inst].breakChildCount;
oldBreakBlock = game::gScrCompileGlob[inst].breakBlock;
oldContinueChildBlocks = game::gScrCompileGlob[inst].continueChildBlocks;
oldContinueChildCount = game::gScrCompileGlob[inst].continueChildCount;
breakChildCount = 0;
game::gScrCompileGlob[inst].continueChildBlocks = 0;
game::gScrCompileGlob[inst].breakBlock = whileStatBlock->block;
if ( constConditional )
{
pos2 = 0;
nextPos2 = 0;
breakChildBlocks = (game::scr_block_s **)game::Hunk_AllocateTempMemoryHigh(2048);
game::gScrCompileGlob[inst].breakChildCount = &breakChildCount;
}
else
{
game::EmitOpcode(inst, game::OP_JumpOnFalse, -1, 0);
game::AddOpcodePos(inst, sourcePos.stringValue, 0);
game::EmitShort(inst, 0);
pos2 = game::gScrCompileGlob[inst].codePos;
nextPos2 = game::TempMalloc(0);
breakChildBlocks = 0;
}
game::gScrCompileGlob[inst].breakChildBlocks = breakChildBlocks;
game::gScrCompileGlob[inst].bCanBreak = 1;
game::gScrCompileGlob[inst].currentBreakStatement = 0;
game::gScrCompileGlob[inst].bCanContinue = 1;
game::gScrCompileGlob[inst].currentContinueStatement = 0;
game::EmitStatement(inst, stmt, 0, 0, whileStatBlock->block);
if ( whileStatBlock->block->abortLevel != 3 ) // SCR_ABORT_RETURN
{
whileStatBlock->block->abortLevel = 0; // SCR_ABORT_NONE
}
game::gScrCompileGlob[inst].bCanBreak = 0;
game::gScrCompileGlob[inst].bCanContinue = 0;
game::ConnectContinueStatements(inst);
game::EmitOpcode(inst, game::OP_jumpback, 0, 0);
game::AddOpcodePos(inst, whileSourcePos.stringValue, 0);
if ( stmt.node->type == game::ENUM_statement_list )
{
game::AddOpcodePos(inst, stmt.node[3].sourcePosValue, 1); // SOURCE_TYPE_BREAKPOINT
}
game::EmitShort(inst, 0);
offset = game::TempMalloc(0) - pos1;
assert(offset < 65536);
*(short *)game::gScrCompileGlob[inst].codePos = offset;
if ( pos2 )
{
offset = game::TempMalloc(0) - nextPos2;
assert(offset < 65536);
*(short *)pos2 = offset;
}
game::ConnectBreakStatements(inst);
game::gScrCompileGlob[inst].bCanBreak = bOldCanBreak;
game::gScrCompileGlob[inst].currentBreakStatement = oldBreakStatement;
game::gScrCompileGlob[inst].bCanContinue = bOldCanContinue;
game::gScrCompileGlob[inst].currentContinueStatement = oldContinueStatement;
if ( constConditional )
{
game::Scr_InitFromChildBlocks(breakChildBlocks, breakChildCount, block);
}
game::gScrCompileGlob[inst].breakChildBlocks = oldBreakChildBlocks;
game::gScrCompileGlob[inst].breakChildCount = oldBreakChildCount;
game::gScrCompileGlob[inst].breakBlock = oldBreakBlock;
game::gScrCompileGlob[inst].continueChildBlocks = oldContinueChildBlocks;
game::gScrCompileGlob[inst].continueChildCount = oldContinueChildCount;
}
// Completed
void Scr_CalcLocalVarsWhileStatement(game::scriptInstance_t inst, game::sval_u expr, game::sval_u stmt, game::scr_block_s* block, game::sval_u* whileStatBlock)
{
int breakChildCount;
int *oldBreakChildCount;
game::scr_block_s **breakChildBlocks;
bool constConditional;
int continueChildCount;
int *oldContinueChildCount;
game::VariableCompileValue constValue;
int i;
game::scr_block_s **continueChildBlocks;
game::scr_block_s **oldBreakChildBlocks;
int abortLevel;
game::scr_block_s **oldContinueChildBlocks;
constConditional = 0;
if ( game::EvalExpression(&constValue, inst, expr) )
{
if ( constValue.value.type == game::VAR_INTEGER || constValue.value.type == game::VAR_FLOAT )
{
game::Scr_CastBool(inst, &constValue.value);
if ( constValue.value.u.intValue )
{
constConditional = 1;
}
}
game::RemoveRefToValueInternal(inst, constValue.value.type, constValue.value.u);
}
oldBreakChildBlocks = game::gScrCompileGlob[inst].breakChildBlocks;
oldBreakChildCount = game::gScrCompileGlob[inst].breakChildCount;
oldContinueChildBlocks = game::gScrCompileGlob[inst].continueChildBlocks;
oldContinueChildCount = game::gScrCompileGlob[inst].continueChildCount;
breakChildCount = 0;
continueChildCount = 0;
continueChildBlocks = (game::scr_block_s **)game::Hunk_AllocateTempMemoryHigh(2048);
game::gScrCompileGlob[inst].continueChildBlocks = continueChildBlocks;
game::gScrCompileGlob[inst].continueChildCount = &continueChildCount;
abortLevel = block->abortLevel;
if ( constConditional )
{
breakChildBlocks = (game::scr_block_s **)game::Hunk_AllocateTempMemoryHigh(2048);
game::gScrCompileGlob[inst].breakChildCount = &breakChildCount;
}
else
{
breakChildBlocks = 0;
}
game::gScrCompileGlob[inst].breakChildBlocks = breakChildBlocks;
game::Scr_CopyBlock(block, (game::scr_block_s **)whileStatBlock);
game::Scr_CalcLocalVarsStatement(inst, stmt, whileStatBlock->block);
game::Scr_AddContinueBlock(inst, whileStatBlock->block);
for ( i = 0;
i < continueChildCount;
++i )
{
game::Scr_AppendChildBlocks(block, &continueChildBlocks[i], 1);
}
if ( constConditional )
{
game::Scr_AppendChildBlocks(block, breakChildBlocks, breakChildCount);
}
game::Scr_MergeChildBlocks((game::scr_block_s **)whileStatBlock, 1, block);
game::gScrCompileGlob[inst].breakChildBlocks = oldBreakChildBlocks;
game::gScrCompileGlob[inst].breakChildCount = oldBreakChildCount;
game::gScrCompileGlob[inst].continueChildBlocks = oldContinueChildBlocks;
game::gScrCompileGlob[inst].continueChildCount = oldContinueChildCount;
}
// Completed
void EmitForStatement(game::scriptInstance_t inst, game::sval_u stmt1, game::sval_u expr, game::sval_u stmt2, game::sval_u stmt, game::sval_u sourcePos, game::sval_u forSourcePos, game::scr_block_s* block, game::sval_u* forStatBlock, game::sval_u* forStatPostBlock)
{
game::ContinueStatementInfo *oldContinueStatement;
int breakChildCount;
int *oldBreakChildCount;
game::scr_block_s **breakChildBlocks;
game::BreakStatementInfo *oldBreakStatement;
bool constConditional;
unsigned int offset;
bool bOldCanBreak;
bool bOldCanContinue;
int continueChildCount;
int *oldContinueChildCount;
game::VariableCompileValue constValue;
const char *pos1;
const char *nextPos2;
game::scr_block_s **continueChildBlocks;
game::scr_block_s **oldBreakChildBlocks;
const char *pos2;
game::scr_block_s **oldContinueChildBlocks;
game::scr_block_s *oldBreakBlock;
bOldCanBreak = game::gScrCompileGlob[inst].bCanBreak;
oldBreakStatement = game::gScrCompileGlob[inst].currentBreakStatement;
game::gScrCompileGlob[inst].bCanBreak = 0;
bOldCanContinue = game::gScrCompileGlob[inst].bCanContinue;
oldContinueStatement = game::gScrCompileGlob[inst].currentContinueStatement;
game::gScrCompileGlob[inst].bCanContinue = 0;
game::EmitStatement(inst, stmt1, 0, 0, block);
game::Scr_TransferBlock(forStatBlock->block, block);
game::EmitCreateLocalVars(inst, forStatBlock->block);
assert(forStatBlock->block->localVarsCreateCount <= block->localVarsCount);
block->localVarsCreateCount = forStatBlock->block->localVarsCreateCount;
game::Scr_TransferBlock(forStatPostBlock->block, block);
pos1 = game::TempMalloc(0);
if ( expr.node[0].type == game::ENUM_expression)
{
constConditional = 0;
if ( game::EmitOrEvalExpression(inst, expr.node[1], &constValue, block) )
{
if ( constValue.value.type == game::VAR_INTEGER || constValue.value.type == game::VAR_FLOAT )
{
game::Scr_CastBool(inst, &constValue.value);
if ( !constValue.value.u.intValue )
{
game::CompileError(inst, sourcePos.stringValue, "conditional expression cannot be always false");
}
constConditional = 1;
}
else
{
game::EmitValue(inst, &constValue);
}
}
}
else
{
constConditional = 1;
}
oldBreakChildBlocks = game::gScrCompileGlob[inst].breakChildBlocks;
oldBreakChildCount = game::gScrCompileGlob[inst].breakChildCount;
oldBreakBlock = game::gScrCompileGlob[inst].breakBlock;
oldContinueChildBlocks = game::gScrCompileGlob[inst].continueChildBlocks;
oldContinueChildCount = game::gScrCompileGlob[inst].continueChildCount;
breakChildCount = 0;
continueChildCount = 0;
continueChildBlocks = (game::scr_block_s **)game::Hunk_AllocateTempMemoryHigh(2048);
game::gScrCompileGlob[inst].continueChildBlocks = continueChildBlocks;
game::gScrCompileGlob[inst].continueChildCount = &continueChildCount;
game::gScrCompileGlob[inst].breakBlock = forStatBlock->block;
if ( constConditional )
{
pos2 = 0;
nextPos2 = 0;
breakChildBlocks = (game::scr_block_s **)game::Hunk_AllocateTempMemoryHigh(2048);
game::gScrCompileGlob[inst].breakChildCount = &breakChildCount;
}
else
{
game::EmitOpcode(inst, game::OP_JumpOnFalse, -1, 0);
game::AddOpcodePos(inst, sourcePos.stringValue, 0);
game::EmitShort(inst, 0);
pos2 = game::gScrCompileGlob[inst].codePos;
nextPos2 = game::TempMalloc(0);
breakChildBlocks = 0;
}
game::gScrCompileGlob[inst].breakChildBlocks = breakChildBlocks;
game::gScrCompileGlob[inst].bCanBreak = 1;
game::gScrCompileGlob[inst].currentBreakStatement = 0;
game::gScrCompileGlob[inst].bCanContinue = 1;
game::gScrCompileGlob[inst].currentContinueStatement = 0;
game::EmitStatement(inst, stmt, 0, 0, forStatBlock->block);
game::Scr_AddContinueBlock(inst, forStatBlock->block);
game::gScrCompileGlob[inst].bCanBreak = 0;
game::gScrCompileGlob[inst].bCanContinue = 0;
game::ConnectContinueStatements(inst);
game::Scr_InitFromChildBlocks(continueChildBlocks, continueChildCount, forStatPostBlock->block);
game::EmitStatement(inst, stmt2, 0, 0, forStatPostBlock->block);
game::EmitOpcode(inst, game::OP_jumpback, 0, 0);
game::AddOpcodePos(inst, forSourcePos.stringValue, 0);
if ( stmt.node[0].type == game::ENUM_statement_list)
{
game::AddOpcodePos(inst, stmt.node[3].sourcePosValue, 1);
}
game::EmitShort(inst, 0);
offset = game::TempMalloc(0) - pos1;
assert(offset < 65536);
*(short *)game::gScrCompileGlob[inst].codePos = offset;
if ( pos2 )
{
offset = game::TempMalloc(0) - nextPos2;
assert(offset < 65536);
*(short *)pos2 = offset;
}
game::ConnectBreakStatements(inst);
game::gScrCompileGlob[inst].bCanBreak = bOldCanBreak;
game::gScrCompileGlob[inst].currentBreakStatement = oldBreakStatement;
game::gScrCompileGlob[inst].bCanContinue = bOldCanContinue;
game::gScrCompileGlob[inst].currentContinueStatement = oldContinueStatement;
if ( constConditional )
{
game::Scr_InitFromChildBlocks(breakChildBlocks, breakChildCount, block);
}
game::gScrCompileGlob[inst].breakChildBlocks = oldBreakChildBlocks;
game::gScrCompileGlob[inst].breakChildCount = oldBreakChildCount;
game::gScrCompileGlob[inst].breakBlock = oldBreakBlock;
game::gScrCompileGlob[inst].continueChildBlocks = oldContinueChildBlocks;
game::gScrCompileGlob[inst].continueChildCount = oldContinueChildCount;
}
// Completed
void Scr_CalcLocalVarsForStatement(game::scriptInstance_t inst, game::sval_u stmt1, game::sval_u expr, game::sval_u stmt2, game::sval_u stmt, game::scr_block_s* block, game::sval_u* forStatBlock, game::sval_u* forStatPostBlock)
{
int breakChildCount;
int *oldBreakChildCount;
game::scr_block_s **breakChildBlocks;
bool constConditional;
int continueChildCount;
int *oldContinueChildCount;
game::VariableCompileValue constValue;
int i;
game::scr_block_s **continueChildBlocks;
game::scr_block_s **oldBreakChildBlocks;
int abortLevel;
game::scr_block_s **oldContinueChildBlocks;
game::Scr_CalcLocalVarsStatement(inst, stmt1, block);
if ( expr.node[0].type == game::ENUM_expression)
{
constConditional = 0;
if ( game::EvalExpression(&constValue, inst, expr.node[1]) )
{
if ( constValue.value.type == game::VAR_INTEGER || constValue.value.type == game::VAR_FLOAT )
{
game::Scr_CastBool(inst, &constValue.value);
if ( constValue.value.u.intValue )
{
constConditional = 1;
}
}
game::RemoveRefToValueInternal(inst, constValue.value.type, constValue.value.u);
}
}
else
{
constConditional = 1;
}
oldBreakChildBlocks = game::gScrCompileGlob[inst].breakChildBlocks;
oldBreakChildCount = game::gScrCompileGlob[inst].breakChildCount;
oldContinueChildBlocks = game::gScrCompileGlob[inst].continueChildBlocks;
oldContinueChildCount = game::gScrCompileGlob[inst].continueChildCount;
breakChildCount = 0;
continueChildCount = 0;
continueChildBlocks = (game::scr_block_s **)game::Hunk_AllocateTempMemoryHigh(2048);
game::gScrCompileGlob[inst].continueChildBlocks = continueChildBlocks;
game::gScrCompileGlob[inst].continueChildCount = &continueChildCount;
abortLevel = block->abortLevel;
if ( constConditional )
{
breakChildBlocks = (game::scr_block_s **)game::Hunk_AllocateTempMemoryHigh(2048);
game::gScrCompileGlob[inst].breakChildCount = &breakChildCount;
}
else
{
breakChildBlocks = 0;
}
game::gScrCompileGlob[inst].breakChildBlocks = breakChildBlocks;
game::Scr_CopyBlock(block, (game::scr_block_s **)forStatBlock);
game::Scr_CopyBlock(block, (game::scr_block_s **)forStatPostBlock);
game::Scr_CalcLocalVarsStatement(inst, stmt, forStatBlock->block);
game::Scr_AddContinueBlock(inst, forStatBlock->block);
for ( i = 0;
i < continueChildCount;
++i )
{
game::Scr_AppendChildBlocks(block, &continueChildBlocks[i], 1);
}
game::Scr_CalcLocalVarsStatement(inst, stmt2, forStatPostBlock->block);
game::Scr_AppendChildBlocks(block, (game::scr_block_s **)forStatPostBlock, 1);
game::Scr_MergeChildBlocks((game::scr_block_s **)forStatPostBlock, 1, block);
if ( constConditional )
{
game::Scr_AppendChildBlocks(block, breakChildBlocks, breakChildCount);
}
game::Scr_MergeChildBlocks((game::scr_block_s **)forStatBlock, 1, block);
game::gScrCompileGlob[inst].breakChildBlocks = oldBreakChildBlocks;
game::gScrCompileGlob[inst].breakChildCount = oldBreakChildCount;
game::gScrCompileGlob[inst].continueChildBlocks = oldContinueChildBlocks;
game::gScrCompileGlob[inst].continueChildCount = oldContinueChildCount;
}
// Completed
void EmitIncStatement(game::scr_block_s* block, game::scriptInstance_t inst, game::sval_u expr, game::sval_u sourcePos)
{
assert(!game::gScrCompileGlob[inst].forceNotCreate);
game::gScrCompileGlob[inst].forceNotCreate = 1;
game::EmitVariableExpressionRef(inst, expr, block);
assert(game::gScrCompileGlob[inst].forceNotCreate);
game::gScrCompileGlob[inst].forceNotCreate = 0;
game::EmitOpcode(inst, game::OP_inc, 1, 0);
game::AddOpcodePos(inst, sourcePos.stringValue, 0);
game::EmitSetVariableField(inst, sourcePos);
}
// Completed
void EmitDecStatement(game::scr_block_s* block, game::scriptInstance_t inst, game::sval_u expr, game::sval_u sourcePos)
{
assert(!game::gScrCompileGlob[inst].forceNotCreate);
game::gScrCompileGlob[inst].forceNotCreate = 1;
game::EmitVariableExpressionRef(inst, expr, block);
assert(game::gScrCompileGlob[inst].forceNotCreate);
game::gScrCompileGlob[inst].forceNotCreate = 0;
game::EmitOpcode(inst, game::OP_dec, 1, 0);
game::AddOpcodePos(inst, sourcePos.stringValue, 0);
game::EmitSetVariableField(inst, sourcePos);
}
// REstored
void Scr_CalcLocalVarsSafeSetVariableField(game::sval_u expr, game::sval_u sourcePos, game::scr_block_s *block)
{
game::Scr_RegisterLocalVar(expr.stringValue, sourcePos, block);
}
// Completed
void Scr_CalcLocalVarsFormalParameterListInternal(game::sval_u* node, game::scr_block_s* block)
{
while ( 1 )
{
node = node[1].node;
if ( !node )
{
break;
}
game::Scr_CalcLocalVarsSafeSetVariableField(*node->node, node[1], block);
}
}
// Restored
void EmitFormalWaittillParameterListRefInternal(game::scriptInstance_t inst, game::sval_u *node, game::scr_block_s *block)
{
while ( 1 )
{
node = node[1].node;
if ( !node )
{
break;
}
game::EmitSafeSetWaittillVariableField(block, inst, *node->node, node->node[1]);
}
}
// Completed
void EmitWaittillStatement(game::scriptInstance_t inst, game::sval_u obj, game::sval_u exprlist, game::sval_u sourcePos, game::sval_u waitSourcePos, game::scr_block_s* block)
{
game::sval_u *node;
node = exprlist.node->node[1].node;
assert(node);
game::EmitExpression(inst, *node->node, block);
game::EmitPrimitiveExpression(inst, obj, block);
game::EmitOpcode(inst, game::OP_waittill, -2, 0);
game::AddOpcodePos(inst, waitSourcePos.stringValue, 0);
game::AddOpcodePos(inst, waitSourcePos.stringValue, 0); // SOURCE_TYPE_NONE
game::AddOpcodePos(inst, sourcePos.stringValue, 0);
game::AddOpcodePos(inst, node->node[1].sourcePosValue, 0);
game::EmitFormalWaittillParameterListRefInternal(inst, node, block);
game::EmitOpcode(inst, game::OP_clearparams, 0, 0);
}
// Completed
void EmitWaittillmatchStatement(game::scriptInstance_t inst, game::sval_u obj, game::sval_u exprlist, game::sval_u sourcePos, game::sval_u waitSourcePos, game::scr_block_s* block)
{
game::sval_u *node;
game::sval_u *nodea;
int exprCount;
node = exprlist.node->node[1].node;
assert(node);
for ( exprCount = 0;
;
++exprCount )
{
node = node[1].node;
if ( !node )
{
break;
}
game::EmitExpression(inst, *node->node, block);
}
nodea = exprlist.node->node[1].node;
assert(nodea);
game::EmitExpression(inst, *nodea->node, block);
game::EmitPrimitiveExpression(inst, obj, block);
game::EmitOpcode(inst, game::OP_waittillmatch, -2 - exprCount, 0);
game::AddOpcodePos(inst, waitSourcePos.stringValue, 0);
game::AddOpcodePos(inst, waitSourcePos.stringValue, 0);
game::AddOpcodePos(inst, sourcePos.stringValue, 0);
game::AddOpcodePos(inst, nodea->node[1].sourcePosValue, 0);
while ( 1 )
{
nodea = nodea[1].node;
if ( !nodea )
{
break;
}
game::AddOpcodePos(inst, nodea->node[1].stringValue, 0);
}
assert(exprCount < 256);
game::EmitByte(inst, exprCount);
game::EmitOpcode(inst, game::OP_clearparams, 0, 0);
}
// Completed
void EmitNotifyStatement(game::scriptInstance_t inst, game::sval_u obj, game::sval_u exprlist, game::sval_u sourcePos, game::sval_u notifySourcePos, game::scr_block_s* block)
{
game::sval_u *node;
game::sval_u *start_node;
int expr_count;
game::EmitOpcode(inst, game::OP_voidCodepos, 1, 0);
game::AddOpcodePos(inst, sourcePos.stringValue, 1);
expr_count = 0;
start_node = 0;
for ( node = exprlist.node->node;
node;
node = node[1].node )
{
start_node = node;
game::EmitExpression(inst, *node->node, block);
++expr_count;
}
assert(start_node);
game::EmitPrimitiveExpression(inst, obj, block);
game::EmitOpcode(inst, game::OP_notify, -expr_count - 2, 0);
game::AddOpcodePos(inst, notifySourcePos.stringValue, 16);
game::AddOpcodePos(inst, start_node->node[1].stringValue, 0);
game::AddOpcodePos(inst, sourcePos.stringValue, 0);
}
// Completed
void EmitEndOnStatement(game::scr_block_s* block, game::scriptInstance_t inst, game::sval_u obj, game::sval_u expr, game::sval_u sourcePos, game::sval_u exprSourcePos)
{
game::EmitExpression(inst, expr, block);
game::EmitPrimitiveExpression(inst, obj, block);
game::EmitOpcode(inst, game::OP_endon, -2, 0);
game::AddOpcodePos(inst, exprSourcePos.stringValue, 0);
game::AddOpcodePos(inst, sourcePos.stringValue, 0);
}
// Completed
int CompareCaseInfo(const void* elem1, const void* elem2)
{
int result;
if (*(int*)elem1 <= *(int*)elem2)
{
result = *(int*)elem1 < *(int*)elem2;
}
else
{
result = -1;
}
return result;
}
// Completed
void EmitCaseStatement(game::scriptInstance_t inst, game::sval_u expr, game::sval_u sourcePos)
{
unsigned int name;
game::sval_u namea;
if ( expr.node[0].type == game::ENUM_integer)
{
if ( game::IsValidArrayIndex(inst, expr.node[1].idValue) )
{
name = game::GetInternalVariableIndex(inst, expr.node[1].idValue);
game::EmitCaseStatementInfo(inst, name, sourcePos);
}
else
{
game::CompileError(inst, sourcePos.stringValue, game::va("case index %d out of range", expr.node[1].intValue));
}
}
else if ( expr.node[0].type == game::ENUM_string )
{
namea = expr.node[1];
game::CompileTransferRefToString(namea.stringValue, inst, 1u);
game::EmitCaseStatementInfo(inst, namea.stringValue, sourcePos);
}
else
{
game::CompileError(inst, sourcePos.stringValue, "case expression must be an int or string");
}
}
// Restored
void EmitDefaultStatement(game::scriptInstance_t inst, game::sval_u sourcePos)
{
game::EmitCaseStatementInfo(inst, 0, sourcePos);
}
// Restored
char Scr_IsLastStatement(game::scriptInstance_t inst, game::sval_u *node)
{
if ( !node )
{
return 1;
}
if ( game::gScrVarPub[inst].developer_script )
{
return 0;
}
while ( node )
{
if ( node->node[0].type != game::ENUM_developer_statement_list )
{
return 0;
}
node = node[1].node;
}
return 1;
}
// Completed
void EmitSwitchStatementList(game::scriptInstance_t inst, game::sval_u val, int lastStatement, unsigned int endSourcePos, game::scr_block_s* block)
{
game::sval_u *node;
game::sval_u *nextNode;
int breakChildCount;
game::scr_block_s **breakChildBlocks;
int *oldBreakChildCount;
bool hasDefault;
game::scr_block_s **oldBreakChildBlocks;
game::scr_block_s *oldBreakBlock;
oldBreakChildBlocks = game::gScrCompileGlob[inst].breakChildBlocks;
oldBreakChildCount = game::gScrCompileGlob[inst].breakChildCount;
oldBreakBlock = game::gScrCompileGlob[inst].breakBlock;
breakChildCount = 0;
breakChildBlocks = (game::scr_block_s **)game::Hunk_AllocateTempMemoryHigh(2048);
game::gScrCompileGlob[inst].breakChildBlocks = breakChildBlocks;
game::gScrCompileGlob[inst].breakChildCount = &breakChildCount;
game::gScrCompileGlob[inst].breakBlock = 0;
hasDefault = 0;
for ( node = val.node->node[1].node;
node;
node = nextNode )
{
nextNode = node[1].node;
if ( node->node->type == game::ENUM_case || node->node->type == game::ENUM_default )
{
if ( game::gScrCompileGlob[inst].breakBlock )
{
assert(game::gScrCompileGlob[inst].bCanBreak);
game::gScrCompileGlob[inst].bCanBreak = 0;
game::EmitRemoveLocalVars(inst, game::gScrCompileGlob[inst].breakBlock, game::gScrCompileGlob[inst].breakBlock);
}
if ( node->node->type == game::ENUM_case )
{
game::gScrCompileGlob[inst].breakBlock = node->node[3].block;
game::EmitCaseStatement(inst, node->node[1], node->node[2]);
}
else
{
game::gScrCompileGlob[inst].breakBlock = node->node[2].block;
hasDefault = 1;
game::EmitDefaultStatement(inst, node->node[1]);
}
game::Scr_TransferBlock(game::gScrCompileGlob[inst].breakBlock, block);
assert(!game::gScrCompileGlob[inst].bCanBreak);
game::gScrCompileGlob[inst].bCanBreak = 1;
}
else
{
if ( !game::gScrCompileGlob[inst].breakBlock )
{
game::CompileError(inst, endSourcePos, "missing case statement");
return;
}
if ( lastStatement && game::Scr_IsLastStatement(inst, nextNode) )
{
game::EmitStatement(inst, *node, 1, endSourcePos, game::gScrCompileGlob[inst].breakBlock);
}
else
{
game::EmitStatement(inst, *node, 0, endSourcePos, game::gScrCompileGlob[inst].breakBlock);
}
if ( game::gScrCompileGlob[inst].breakBlock && game::gScrCompileGlob[inst].breakBlock->abortLevel )
{
game::gScrCompileGlob[inst].breakBlock = 0;
assert(game::gScrCompileGlob[inst].bCanBreak);
game::gScrCompileGlob[inst].bCanBreak = 0;
}
}
}
if ( game::gScrCompileGlob[inst].breakBlock )
{
assert(game::gScrCompileGlob[inst].bCanBreak);
game::gScrCompileGlob[inst].bCanBreak = 0;
game::EmitRemoveLocalVars(inst, game::gScrCompileGlob[inst].breakBlock, game::gScrCompileGlob[inst].breakBlock);
}
if ( hasDefault )
{
if ( game::gScrCompileGlob[inst].breakBlock )
{
game::Scr_AddBreakBlock(inst, game::gScrCompileGlob[inst].breakBlock);
}
game::Scr_InitFromChildBlocks(breakChildBlocks, breakChildCount, block);
}
game::gScrCompileGlob[inst].breakChildBlocks = oldBreakChildBlocks;
game::gScrCompileGlob[inst].breakChildCount = oldBreakChildCount;
game::gScrCompileGlob[inst].breakBlock = oldBreakBlock;
}
// Completed
void Scr_CalcLocalVarsSwitchStatement(game::scriptInstance_t inst, game::sval_u stmtlist, game::scr_block_s* block)
{
game::sval_u *node;
int breakChildCount;
game::scr_block_s **breakChildBlocks;
int *oldBreakChildCount;
bool hasDefault;
game::scr_block_s *currentBlock;
game::scr_block_s **childBlocks;
game::scr_block_s **oldBreakChildBlocks;
int childCount;
int abortLevel;
abortLevel = 3;
oldBreakChildBlocks = game::gScrCompileGlob[inst].breakChildBlocks;
oldBreakChildCount = game::gScrCompileGlob[inst].breakChildCount;
breakChildCount = 0;
breakChildBlocks = (game::scr_block_s **)game::Hunk_AllocateTempMemoryHigh(2048);
game::gScrCompileGlob[inst].breakChildBlocks = breakChildBlocks;
game::gScrCompileGlob[inst].breakChildCount = &breakChildCount;
childCount = 0;
currentBlock = 0;
hasDefault = 0;
childBlocks = (game::scr_block_s**)game::Hunk_AllocateTempMemoryHigh(2048);
for ( node = stmtlist.node->node[1].node;
node;
node = node[1].node )
{
if ( node->node[0].type == game::ENUM_case || node->node[0].type == game::ENUM_default)
{
currentBlock = 0;
game::Scr_CopyBlock(block, &currentBlock);
if ( node->node[0].type == game::ENUM_case )
{
node->node[3].block = currentBlock;
}
else
{
node->node[2].block = currentBlock;
hasDefault = 1;
}
}
else if ( currentBlock )
{
game::Scr_CalcLocalVarsStatement(inst, *node, currentBlock);
if ( currentBlock->abortLevel )
{
if ( currentBlock->abortLevel == 2 )
{
currentBlock->abortLevel = 0;
abortLevel = 0;
game::Scr_CheckMaxSwitchCases(childCount);
childBlocks[childCount++] = currentBlock;
}
else if ( currentBlock->abortLevel <= abortLevel )
{
abortLevel = currentBlock->abortLevel;
}
currentBlock = 0;
}
}
}
if ( hasDefault )
{
if ( currentBlock )
{
game::Scr_AddBreakBlock(inst, currentBlock);
game::Scr_CheckMaxSwitchCases(childCount);
childBlocks[childCount++] = currentBlock;
}
if ( !block->abortLevel )
{
block->abortLevel = abortLevel;
}
game::Scr_AppendChildBlocks(block, breakChildBlocks, breakChildCount);
game::Scr_MergeChildBlocks(childBlocks, childCount, block);
}
game::gScrCompileGlob[inst].breakChildBlocks = oldBreakChildBlocks;
game::gScrCompileGlob[inst].breakChildCount = oldBreakChildCount;
}
// Completed
void EmitSwitchStatement(game::scriptInstance_t inst, game::sval_u expr, game::sval_u stmtlist, game::sval_u sourcePos, int lastStatement, unsigned int endSourcePos, game::scr_block_s* block)
{
game::CaseStatementInfo *oldCaseStatement;
char *pos3;
game::BreakStatementInfo *oldBreakStatement;
bool bOldCanBreak;
char *nextPos1;
game::CaseStatementInfo *caseStatement;
game::CaseStatementInfo *caseStatementa;
char *pos1;
int num;
char *pos2;
oldCaseStatement = game::gScrCompileGlob[inst].currentCaseStatement;
bOldCanBreak = game::gScrCompileGlob[inst].bCanBreak;
oldBreakStatement = game::gScrCompileGlob[inst].currentBreakStatement;
game::gScrCompileGlob[inst].bCanBreak = 0;
game::EmitExpression(inst, expr, block);
game::EmitOpcode(inst, game::OP_switch, -1, 0);
game::EmitCodepos(inst, 0);
pos1 = game::gScrCompileGlob[inst].codePos;
nextPos1 = game::TempMalloc(0);
game::gScrCompileGlob[inst].currentCaseStatement = 0;
game::gScrCompileGlob[inst].currentBreakStatement = 0;
game::EmitSwitchStatementList(inst, stmtlist, lastStatement, endSourcePos, block);
game::EmitOpcode(inst, game::OP_endswitch, 0, 0);
game::AddOpcodePos(inst, sourcePos.stringValue, 0);
game::EmitShort(inst, 0);
pos2 = game::gScrCompileGlob[inst].codePos;
*(int *)pos1 = pos2 - nextPos1;
pos3 = game::TempMalloc(0);
num = 0;
caseStatement = game::gScrCompileGlob[inst].currentCaseStatement;
while ( caseStatement )
{
game::EmitCodepos(inst, caseStatement->name);
game::EmitCodepos(inst, (int)caseStatement->codePos);
caseStatement = caseStatement->next;
++num;
}
*(short *)pos2 = num;
qsort(pos3, num, 8u, game::CompareCaseInfo);
while ( num > 1 )
{
if ( *(int *)pos3 == *((int *)pos3 + 2) )
{
for ( caseStatementa = game::gScrCompileGlob[inst].currentCaseStatement;
caseStatementa;
caseStatementa = caseStatementa->next )
{
if ( caseStatementa->name == *(unsigned int *)pos3 )
{
game::CompileError(inst, caseStatementa->sourcePos, "duplicate case expression");
return;
}
}
}
--num;
pos3 += 8;
}
game::ConnectBreakStatements(inst);
game::gScrCompileGlob[inst].currentCaseStatement = oldCaseStatement;
game::gScrCompileGlob[inst].bCanBreak = bOldCanBreak;
game::gScrCompileGlob[inst].currentBreakStatement = oldBreakStatement;
}
// Completed
void EmitCaseStatementInfo(game::scriptInstance_t inst, unsigned int name, game::sval_u sourcePos)
{
game::CaseStatementInfo *newCaseStatement;
if ( game::gScrCompilePub[inst].developer_statement == 2 )
{
assert(!game::gScrVarPub[inst].developer_script);
}
else
{
newCaseStatement = (game::CaseStatementInfo *)game::Hunk_AllocateTempMemoryHigh(sizeof(game::CaseStatementInfo));
newCaseStatement->name = name;
newCaseStatement->codePos = game::TempMalloc(0);
newCaseStatement->sourcePos = sourcePos.stringValue;
newCaseStatement->next = game::gScrCompileGlob[inst].currentCaseStatement;
game::gScrCompileGlob[inst].currentCaseStatement = newCaseStatement;
}
}
// Completed
void EmitBreakStatement(game::scr_block_s* block, game::scriptInstance_t inst, game::sval_u sourcePos)
{
game::BreakStatementInfo *newBreakStatement;
if ( game::gScrCompileGlob[inst].bCanBreak && !block->abortLevel )
{
game::Scr_AddBreakBlock(inst, block);
assert(game::gScrCompileGlob[inst].breakBlock);
game::EmitRemoveLocalVars(inst, game::gScrCompileGlob[inst].breakBlock, block);
block->abortLevel = 2;
game::EmitOpcode(inst, game::OP_jump, 0, 0);
game::AddOpcodePos(inst, sourcePos.stringValue, 1);
game::EmitCodepos(inst, 0);
if ( game::gScrCompilePub[inst].developer_statement != 2 )
{
newBreakStatement = (game::BreakStatementInfo *)game::Hunk_AllocateTempMemoryHigh(sizeof(game::BreakStatementInfo));
newBreakStatement->codePos = game::gScrCompileGlob[inst].codePos;
newBreakStatement->nextCodePos = game::TempMalloc(0);
newBreakStatement->next = game::gScrCompileGlob[inst].currentBreakStatement;
game::gScrCompileGlob[inst].currentBreakStatement = newBreakStatement;
}
}
else
{
game::CompileError(inst, sourcePos.stringValue, "illegal break statement");
}
}
// Completed
void EmitContinueStatement(game::scr_block_s* block, game::scriptInstance_t inst, game::sval_u sourcePos)
{
game::ContinueStatementInfo *newContinueStatement;
if ( game::gScrCompileGlob[inst].bCanContinue && !block->abortLevel )
{
game::Scr_AddContinueBlock(inst, block);
game::EmitRemoveLocalVars(inst, block, block);
block->abortLevel = 1;
game::EmitOpcode(inst, game::OP_jump, 0, 0);
game::AddOpcodePos(inst, sourcePos.stringValue, 1);
game::EmitCodepos(inst, 0);
if ( game::gScrCompilePub[inst].developer_statement != 2 )
{
newContinueStatement = (game::ContinueStatementInfo *)game::Hunk_AllocateTempMemoryHigh(sizeof(game::ContinueStatementInfo));
newContinueStatement->codePos = game::gScrCompileGlob[inst].codePos;
newContinueStatement->nextCodePos = game::TempMalloc(0);
newContinueStatement->next = game::gScrCompileGlob[inst].currentContinueStatement;
game::gScrCompileGlob[inst].currentContinueStatement = newContinueStatement;
}
}
else
{
game::CompileError(inst, sourcePos.stringValue, "illegal continue statement");
}
}
// Completed
void EmitProfStatement(game::scriptInstance_t inst, game::sval_u profileName, [[maybe_unused]] game::sval_u sourcePos, game::OpcodeVM op)
{
if ( game::gScrVarPub[inst].developer_script )
{
game::Scr_CompileRemoveRefToString(inst, profileName.stringValue);
game::EmitOpcode(inst, op, 0, 0);
game::EmitByte(inst, 0);
}
else
{
game::Scr_CompileRemoveRefToString(inst, profileName.stringValue);
}
}
// Restored
void EmitProfBeginStatement(game::scriptInstance_t inst, game::sval_u profileName, game::sval_u sourcePos)
{
game::EmitProfStatement(inst, profileName, sourcePos, game::OP_prof_begin);
}
// Restored
void EmitProfEndStatement(game::scriptInstance_t inst, game::sval_u profileName, game::sval_u sourcePos)
{
game::EmitProfStatement(inst, profileName, sourcePos, game::OP_prof_end);
}
// Restored
void EmitEndStatement(game::scriptInstance_t inst, game::sval_u sourcePos, game::scr_block_s *block)
{
if ( !block->abortLevel )
{
block->abortLevel = 3;
}
game::EmitEnd(inst);
game::AddOpcodePos(inst, sourcePos.stringValue, 1);
}
// Completed
void EmitStatement(game::scriptInstance_t inst, game::sval_u val, int lastStatement, unsigned int endSourcePos, game::scr_block_s* block)
{
/*if (gScrCompilePub[inst].developer_statement == 3)
{
switch ( *(_BYTE *)val.stringValue )
{
case game::ENUM_assignment:
case game::ENUM_call_expression_statement:
case game::ENUM_inc:
case game::ENUM_dec:
case game::ENUM_binary_equals:
case game::ENUM_statement_list:
case game::ENUM_notify:
break;
default:
CompileError(inst, 0, "illegal statement in debugger");
break;
}
}*/
switch (val.node[0].type)
{
case game::ENUM_assignment:
game::EmitAssignmentStatement(
inst,
val.node[1],
val.node[2],
val.node[3],
val.node[4],
block);
break;
case game::ENUM_call_expression_statement:
game::EmitCallExpressionStatement(inst, block, val.node[1]);
break;
case game::ENUM_return:
game::EmitReturnStatement(block, inst, val.node[1], val.node[2]);
break;
case game::ENUM_return2:
game::EmitEndStatement(inst, val.node[1], block);
break;
case game::ENUM_wait:
game::EmitWaitStatement(
block,
inst,
val.node[1],
val.node[2],
val.node[3]);
break;
case game::ENUM_if:
game::EmitIfStatement(
inst,
val.node[1],
val.node[2],
val.node[3],
lastStatement,
endSourcePos,
block,
&val.node[4]);
break;
case game::ENUM_if_else:
game::EmitIfElseStatement(
inst,
val.node[1],
val.node[2],
val.node[3],
val.node[4],
val.node[5],
lastStatement,
endSourcePos,
block,
&val.node[6],
&val.node[7]);
break;
case game::ENUM_while:
game::EmitWhileStatement(
inst,
val.node[1],
val.node[2],
val.node[3],
val.node[4],
block,
&val.node[5]);
break;
case game::ENUM_for:
game::EmitForStatement(
inst,
val.node[1],
val.node[2],
val.node[3],
val.node[4],
val.node[5],
val.node[6],
block,
&val.node[7],
&val.node[8]);
break;
case game::ENUM_inc:
game::EmitIncStatement(block, inst, val.node[1], val.node[2]);
break;
case game::ENUM_dec:
game::EmitDecStatement(block, inst, val.node[1], val.node[2]);
break;
case game::ENUM_binary_equals:
game::EmitBinaryEqualsOperatorExpression(
block,
inst,
val.node[1],
val.node[2],
val.node[3],
val.node[4]);
break;
case game::ENUM_statement_list:
game::EmitStatementList(inst, val.node[1], lastStatement, endSourcePos, block);
break;
case game::ENUM_developer_statement_list:
game::EmitDeveloperStatementList(
inst,
val.node[1],
val.node[2],
block,
&val.node[3]);
break;
case game::ENUM_waittill:
game::EmitWaittillStatement(
inst,
val.node[1],
val.node[2],
val.node[3],
val.node[4],
block);
break;
case game::ENUM_waittillmatch:
game::EmitWaittillmatchStatement(
inst,
val.node[1],
val.node[2],
val.node[3],
val.node[4],
block);
break;
case game::ENUM_waittillFrameEnd:
game::EmitWaittillFrameEnd(inst, val.node[1]);
break;
case game::ENUM_notify:
game::EmitNotifyStatement(
inst,
val.node[1],
val.node[2],
val.node[3],
val.node[4],
block);
break;
case game::ENUM_endon:
game::EmitEndOnStatement(
block,
inst,
val.node[1],
val.node[2],
val.node[3],
val.node[4]);
break;
case game::ENUM_switch:
game::EmitSwitchStatement(
inst,
val.node[1],
val.node[2],
val.node[3],
lastStatement,
endSourcePos,
block);
break;
case game::ENUM_case:
game::CompileError(inst, val.node[2].sourcePosValue, "illegal case statement");
case game::ENUM_default:
game::CompileError(inst, val.node[1].sourcePosValue, "illegal default statement");
case game::ENUM_break:
game::EmitBreakStatement(block, inst, val.node[1]);
break;
case game::ENUM_continue:
game::EmitContinueStatement(block, inst, val.node[1]);
break;
/*case game::ENUM_breakpoint:
EmitBreakpointStatement(inst, *(game::sval_u *)(val.stringValue + 4));
break;*/
case game::ENUM_prof_begin:
game::EmitProfBeginStatement(inst, val.node[1], val.node[2]);
break;
case game::ENUM_prof_end:
game::EmitProfEndStatement(inst, val.node[1], val.node[2]);
break;
default:
return;
}
}
// Restored
void Scr_CalcLocalVarsIncStatement(game::sval_u expr, game::scr_block_s *block)
{
game::Scr_CalcLocalVarsVariableExpressionRef(block, expr);
}
// Restored
void Scr_CalcLocalVarsWaittillStatement(game::sval_u exprlist, game::scr_block_s *block)
{
game::sval_u *node;
node = exprlist.node->node[1].node;
assert(node);
game::Scr_CalcLocalVarsFormalParameterListInternal(node, block);
}
// Completed
void Scr_CalcLocalVarsStatement(game::scriptInstance_t inst, game::sval_u val, game::scr_block_s* block)
{
switch (val.node[0].type)
{
case game::ENUM_assignment:
game::Scr_CalcLocalVarsIncStatement(val.node[1], block);
break;
case game::ENUM_return:
case game::ENUM_return2:
if (!block->abortLevel)
{
block->abortLevel = 3;
}
break;
case game::ENUM_if:
game::Scr_CalcLocalVarsIfStatement(inst, val.node[2], block, &val.node[4]);
break;
case game::ENUM_if_else:
game::Scr_CalcLocalVarsIfElseStatement(
inst,
val.node[2],
val.node[3],
block,
&val.node[6],
&val.node[7]);
break;
case game::ENUM_while:
game::Scr_CalcLocalVarsWhileStatement(
inst,
val.node[1],
val.node[2],
block,
&val.node[5]);
break;
case game::ENUM_for:
game::Scr_CalcLocalVarsForStatement(
inst,
val.node[1],
val.node[2],
val.node[3],
val.node[4],
block,
&val.node[7],
&val.node[8]);
break;
case game::ENUM_inc:
case game::ENUM_dec:
case game::ENUM_binary_equals:
game::Scr_CalcLocalVarsIncStatement(val.node[1], block);
break;
case game::ENUM_statement_list:
game::Scr_CalcLocalVarsStatementList(block, inst, val.node[1]);
break;
case game::ENUM_developer_statement_list:
game::Scr_CalcLocalVarsDeveloperStatementList(
inst,
val.node[1],
block,
&val.node[3]);
break;
case game::ENUM_waittill:
game::Scr_CalcLocalVarsWaittillStatement(val.node[2], block);
break;
case game::ENUM_switch:
game::Scr_CalcLocalVarsSwitchStatement(inst, *(game::sval_u*)(val.stringValue + 8), block);
break;
case game::ENUM_break:
game::Scr_AddBreakBlock(inst, block);
if (!block->abortLevel)
{
block->abortLevel = 2;
}
break;
case game::ENUM_continue:
game::Scr_AddContinueBlock(inst, block);
if (!block->abortLevel)
{
block->abortLevel = 1;
}
break;
default:
return;
}
}
// Completed
void EmitStatementList(game::scriptInstance_t inst, game::sval_u val, int lastStatement, unsigned int endSourcePos, game::scr_block_s* block)
{
game::sval_u *node;
game::sval_u *nextNode;
for ( node = val.node->node[1].node;
node;
node = nextNode )
{
nextNode = node[1].node;
if ( (char)lastStatement && game::Scr_IsLastStatement(inst, nextNode) )
{
game::EmitStatement(inst, *node, 1, endSourcePos, block);
}
else
{
game::EmitStatement(inst, *node, 0, endSourcePos, block);
}
}
}
// Completed
void Scr_CalcLocalVarsStatementList(game::scr_block_s* block, game::scriptInstance_t inst, game::sval_u val)
{
game::sval_u *node;
for ( node = val.node->node[1].node;
node;
node = node[1].node )
{
game::Scr_CalcLocalVarsStatement(inst, *node, block);
}
}
// Completed
void Scr_CalcLocalVarsDeveloperStatementList(game::scriptInstance_t inst, game::sval_u val, game::scr_block_s* block, game::sval_u* devStatBlock)
{
game::Scr_CopyBlock(block, (game::scr_block_s **)devStatBlock);
game::Scr_CalcLocalVarsStatementList(devStatBlock->block, inst, val);
game::Scr_MergeChildBlocks((game::scr_block_s **)devStatBlock, 1, block);
}
// Completed
void EmitDeveloperStatementList(game::scriptInstance_t inst, game::sval_u val, game::sval_u sourcePos, game::scr_block_s* block, game::sval_u* devStatBlock)
{
char *savedPos;
unsigned int savedChecksum;
if ( game::gScrCompilePub[inst].developer_statement )
{
game::CompileError(inst, sourcePos.stringValue, "cannot recurse /#");
}
else
{
savedChecksum = game::gScrVarPub[inst].checksum;
game::Scr_TransferBlock(devStatBlock->block, block);
if ( game::gScrVarPub[inst].developer_script )
{
game::gScrCompilePub[inst].developer_statement = 1;
game::EmitStatementList(inst, val, 0, 0, devStatBlock->block);
game::EmitRemoveLocalVars(inst, devStatBlock->block, devStatBlock->block);
}
else
{
savedPos = game::TempMalloc(0);
game::gScrCompilePub[inst].developer_statement = 2;
game::EmitStatementList(inst, val, 0, 0, devStatBlock->block);
game::TempMemorySetPos(savedPos);
}
game::gScrCompilePub[inst].developer_statement = 0;
game::gScrVarPub[inst].checksum = savedChecksum;
}
}
// Restored
void EmitFormalParameterListInternal(game::scriptInstance_t inst, game::sval_u *node, game::scr_block_s *block)
{
while ( 1 )
{
node = node[1].node;
if ( !node )
{
break;
}
game::EmitSafeSetVariableField(block, inst, *node->node, node->node[1]);
}
}
// Completed
void EmitFormalParameterList(game::scriptInstance_t inst, game::sval_u exprlist, game::sval_u sourcePos, game::scr_block_s* block)
{
game::EmitFormalParameterListInternal(inst, exprlist.node->node, block);
game::EmitOpcode(inst, game::OP_checkclearparams, 0, 0);
game::AddOpcodePos(inst, sourcePos.stringValue, 0);
}
// Restored
unsigned int SpecifyThreadPosition(game::scriptInstance_t inst, unsigned int posId, unsigned int name, unsigned int sourcePos, int type)
{
game::VariableValue pos;
game::CheckThreadPosition(inst, posId, name, sourcePos);
pos.type = (game::VariableType)type;
pos.u.intValue = 0;
game::SetNewVariableValue(inst, posId, &pos);
return posId;
}
// Completed
void SpecifyThread(game::scriptInstance_t inst, game::sval_u val)
{
if ( val.node[0].type == game::ENUM_thread )
{
if ( !game::gScrCompileGlob[inst].in_developer_thread || game::gScrVarPub[inst].developer_script )
{
game::SpecifyThreadPosition(inst, game::GetVariable(inst, game::gScrCompileGlob[inst].filePosId, val.node[1].stringValue), val.node[1].stringValue, val.node[4].stringValue, game::gScrCompileGlob[inst].in_developer_thread ? game::VAR_DEVELOPER_CODEPOS : game::VAR_CODEPOS);
}
}
else if ( val.node[0].type == game::ENUM_begin_developer_thread )
{
if ( game::gScrCompileGlob[inst].in_developer_thread )
{
game::CompileError(inst, val.node[1].sourcePosValue, "cannot recurse /#");
}
else
{
game::gScrCompileGlob[inst].in_developer_thread = 1;
game::gScrCompileGlob[inst].developer_thread_sourcePos = val.node[1].sourcePosValue;
}
}
else if ( val.node[0].type == game::ENUM_end_developer_thread )
{
if ( game::gScrCompileGlob[inst].in_developer_thread )
{
game::gScrCompileGlob[inst].in_developer_thread = 0;
}
else
{
game::CompileError(inst, val.node[1].sourcePosValue, "#/ has no matching /#");
}
}
}
// Completed
void EmitThreadInternal(game::scriptInstance_t inst, game::sval_u val, game::sval_u sourcePos, game::sval_u endSourcePos, game::scr_block_s* block)
{
game::AddThreadStartOpcodePos(inst, sourcePos.stringValue);
game::gScrCompileGlob[inst].cumulOffset = 0;
game::gScrCompileGlob[inst].maxOffset = 0;
game::gScrCompileGlob[inst].maxCallOffset = 0;
// pluto
if (game::plutonium::store_func_codepos != nullptr)
{
game::plutonium::store_func_codepos(inst, val.node[1].stringValue);
}
//
game::CompileTransferRefToString(val.node[1].stringValue, inst, 2u);
game::EmitFormalParameterList(inst, val.node[2], sourcePos, block);
game::EmitStatementList(inst, val.node[3], 1, endSourcePos.stringValue, block);
game::EmitEnd(inst);
game::AddOpcodePos(inst, endSourcePos.stringValue, 1);
game::AddOpcodePos(inst, 0xFFFFFFFE, 0);
assert(!game::gScrCompileGlob[inst].cumulOffset);
if ( game::gScrCompileGlob[inst].maxOffset + 32 * game::gScrCompileGlob[inst].maxCallOffset >= 2048 )
{
game::CompileError(inst, sourcePos.stringValue, "function exceeds operand stack size");
}
}
// Restored
void Scr_CalcLocalVarsFormalParameterList(game::sval_u exprlist, game::scr_block_s *block)
{
game::Scr_CalcLocalVarsFormalParameterListInternal(exprlist.node->node, block);
}
// Completed
void Scr_CalcLocalVarsThread(game::sval_u* stmttblock, game::scriptInstance_t inst, game::sval_u exprlist, game::sval_u stmtlist)
{
game::gScrCompileGlob[inst].forceNotCreate = 0;
stmttblock->block = (game::scr_block_s*)game::Hunk_AllocateTempMemoryHigh(sizeof(game::scr_block_s));
stmttblock->block->abortLevel = 0;
stmttblock->block->localVarsCreateCount = 0;
stmttblock->block->localVarsCount = 0;
stmttblock->block->localVarsPublicCount = 0;
memset(stmttblock->block->localVarsInitBits, 0, sizeof(stmttblock->block->localVarsInitBits));
game::Scr_CalcLocalVarsFormalParameterList(exprlist, stmttblock->block);
game::Scr_CalcLocalVarsStatementList(stmttblock->block, inst, stmtlist);
}
// Completed
void InitThread(int type, game::scriptInstance_t inst)
{
game::gScrCompileGlob[inst].currentCaseStatement = 0;
game::gScrCompileGlob[inst].bCanBreak = 0;
game::gScrCompileGlob[inst].currentBreakStatement = 0;
game::gScrCompileGlob[inst].bCanContinue = 0;
game::gScrCompileGlob[inst].currentContinueStatement = 0;
game::gScrCompileGlob[inst].breakChildBlocks = 0;
game::gScrCompileGlob[inst].continueChildBlocks = 0;
if ( game::gScrCompileGlob[inst].firstThread[type] )
{
game::gScrCompileGlob[inst].firstThread[type] = 0;
game::EmitEnd(inst);
game::AddOpcodePos(inst, 0, 0);
game::AddOpcodePos(inst, 0xFFFFFFFE, 0);
}
}
// Restored
void SetThreadPosition(game::scriptInstance_t inst, unsigned int posId)
{
game::GetVariableValueAddress(inst, posId)->u.intValue = (unsigned int)game::TempMalloc(0);
}
// Completed
void EmitNormalThread(game::scriptInstance_t inst, game::sval_u val, game::sval_u* stmttblock)
{
unsigned int posId;
game::InitThread(0, inst);
posId = game::FindVariable(val.node[1].stringValue, game::gScrCompileGlob[inst].filePosId, inst);
game::SetThreadPosition(inst, posId);
game::EmitThreadInternal(inst, val, val.node[4], val.node[5], stmttblock->block);
}
// Completed
void EmitDeveloperThread(game::scriptInstance_t inst, game::sval_u val, game::sval_u* stmttblock)
{
unsigned int posId;
unsigned int savedChecksum;
char *begin_pos;
assert(game::gScrCompilePub[inst].developer_statement == 0); // SCR_DEV_NO
if ( game::gScrVarPub[inst].developer_script )
{
game::gScrCompilePub[inst].developer_statement = 1;
game::InitThread(1, inst);
posId = game::FindVariable(val.node[1].stringValue, game::gScrCompileGlob[inst].filePosId, inst);
game::SetThreadPosition(inst, posId);
game::EmitThreadInternal(inst, val, val.node[4], val.node[5], stmttblock->block);
}
else
{
begin_pos = game::TempMalloc(0);
savedChecksum = game::gScrVarPub[inst].checksum;
game::gScrCompilePub[inst].developer_statement = 2;
game::InitThread(1, inst);
game::EmitThreadInternal(inst, val, val.node[4], val.node[5], stmttblock->block);
game::TempMemorySetPos(begin_pos);
game::gScrVarPub[inst].checksum = savedChecksum;
}
game::gScrCompilePub[inst].developer_statement = 0;
}
// Completed
void EmitThread(game::scriptInstance_t inst, game::sval_u val)
{
switch (val.node[0].type)
{
case game::ENUM_thread:
game::Scr_CalcLocalVarsThread(&val.node[6], inst, val.node[2], val.node[3]);
if (game::gScrCompileGlob[inst].in_developer_thread)
{
game::EmitDeveloperThread(inst, val, &val.node[6]);
}
else
{
game::EmitNormalThread(inst, val, &val.node[6]);
}
break;
case game::ENUM_begin_developer_thread:
assert(!game::gScrCompileGlob[inst].in_developer_thread);
game::gScrCompileGlob[inst].in_developer_thread = 1;
break;
case game::ENUM_end_developer_thread:
assert(game::gScrCompileGlob[inst].in_developer_thread);
game::gScrCompileGlob[inst].in_developer_thread = 0;
break;
case game::ENUM_usingtree:
if (game::gScrCompileGlob[inst].in_developer_thread)
{
game::CompileError(inst, val.node[2].sourcePosValue, "cannot put #using_animtree inside /# ... #/ comment");
}
game::Scr_UsingTree(inst, game::SL_ConvertToString(val.node[1].stringValue, inst), val.node[3].sourcePosValue);
game::Scr_CompileRemoveRefToString(inst, val.node[1].stringValue);
break;
default:
return;
}
}
// Completed
void EmitThreadList(game::scriptInstance_t inst, game::sval_u val)
{
game::sval_u *node;
game::sval_u *nodea;
game::gScrCompileGlob[inst].in_developer_thread = 0;
for ( node = val.node->node[1].node;
node;
node = node[1].node )
{
game::SpecifyThread(inst, *node);
}
if ( game::gScrCompileGlob[inst].in_developer_thread )
{
game::CompileError(inst, game::gScrCompileGlob[inst].developer_thread_sourcePos, "/# has no matching #/");
}
game::gScrCompileGlob[inst].firstThread[0] = 1;
game::gScrCompileGlob[inst].firstThread[1] = 1;
assert(!game::gScrCompileGlob[inst].in_developer_thread);
for ( nodea = val.node->node[1].node;
nodea;
nodea = nodea[1].node )
{
game::EmitThread(inst, *nodea);
}
assert(!game::gScrCompileGlob[inst].in_developer_thread);
}
// Completed
void EmitInclude(game::scriptInstance_t inst, game::sval_u val)
{
unsigned int filename;
assert(val.node[0].type == game::ENUM_include);
filename = game::Scr_CreateCanonicalFilename(inst, game::SL_ConvertToString(val.node[1].stringValue, inst));
game::Scr_CompileRemoveRefToString(inst, val.node[1].stringValue);
game::AddFilePrecache(inst, filename, val.node[2].sourcePosValue, 1, 0, 0);
}
// Restored
void EmitIncludeList(game::scriptInstance_t inst, game::sval_u val)
{
game::sval_u *node;
for ( node = val.node->node[1].node;
node;
node = node[1].node )
{
game::EmitInclude(inst, *node);
}
}
// Completed
void ScriptCompile(game::scriptInstance_t inst, game::sval_u val, unsigned int filePosId, unsigned int fileCountId, unsigned int scriptId, game::PrecacheEntry* entries, int entriesCount)
{
int j;
game::VariableValue pos;
unsigned __int16 filename;
game::PrecacheEntry* precachescript;
int far_function_count;
game::PrecacheEntry* precachescript2;
unsigned int includeFilePosId;
unsigned int toPosId;
unsigned int posId;
game::VariableValue includePos;
unsigned __int16 name;
unsigned int includePosId;
game::PrecacheEntry* precachescriptList;
int i;
unsigned int toThreadCountId;
unsigned int duplicateFilePosId;
game::VariableValue value;
int entriesCounta;
game::gScrCompileGlob[inst].filePosId = filePosId;
game::gScrCompileGlob[inst].fileCountId = fileCountId;
game::gScrCompileGlob[inst].bConstRefCount = 0;
game::gScrAnimPub[inst].animTreeIndex = 0;
game::gScrCompilePub[inst].developer_statement = 0;
precachescriptList = game::gScrCompilePub[inst].far_function_count ? &entries[entriesCount] : 0;
entriesCounta = game::gScrCompilePub[inst].far_function_count + entriesCount;
if (entriesCounta > 0x400) // 0x700 on t5
{
game::Com_Error(game::ERR_DROP, "MAX_PRECACHE_ENTRIES exceeded.\nThis means that the script recursion is too deep.\nPlease see a coder."); // t5 meme message
}
game::gScrCompileGlob[inst].precachescriptList = precachescriptList;
game::EmitIncludeList(inst, *val.node);
game::EmitThreadList(inst, val.node[1]);
game::gScrCompilePub[inst].programLen = game::TempMalloc(0) - game::gScrVarPub[inst].programBuffer;
game::Scr_ShutdownAllocNode(inst);
game::Hunk_ClearTempMemoryHigh();
far_function_count = game::gScrCompileGlob[inst].precachescriptList - precachescriptList;
duplicateFilePosId = game::AllocObject(inst);
for (i = 0;
i < far_function_count;
++i)
{
precachescript = &precachescriptList[i];
filename = precachescript->filename;
includeFilePosId = game::Scr_LoadScriptInternal(inst, game::SL_ConvertToString(filename, inst), entries, entriesCounta);
if (!includeFilePosId)
{
game::CompileError(inst, precachescript->sourcePos, "Could not find script '%s'", game::SL_ConvertToString(filename, inst));
return;
}
game::SL_RemoveRefToString(filename, inst);
if (precachescript->include)
{
for (j = i + 1;
j < far_function_count;
++j)
{
precachescript2 = &precachescriptList[j];
if (!precachescript2->include)
{
break;
}
if (precachescript2->filename == filename)
{
game::CompileError(inst, precachescript2->sourcePos, "Duplicate #include");
return;
}
}
precachescript->include = 0;
pos.type = game::VAR_CODEPOS;
for (includePosId = game::FindFirstSibling(inst, includeFilePosId);
includePosId;
includePosId = game::FindNextSibling(inst, includePosId))
{
includePos = game::Scr_EvalVariable(inst, includePosId);
assert((includePos.type == game::VAR_CODEPOS) || (includePos.type == game::VAR_DEVELOPER_CODEPOS));
name = game::GetVariableName(inst, includePosId);
posId = game::FindVariable(name, filePosId, inst);
if (posId)
{
game::CheckThreadPosition(inst, posId, name, precachescript->sourcePos);
}
toPosId = game::GetVariable(inst, duplicateFilePosId, name);
game::CheckThreadPosition(inst, toPosId, name, precachescript->sourcePos);
pos.u.intValue = game::GetVariableValueAddress(inst, includePosId)->u.intValue;
game::SetNewVariableValue(inst, toPosId, &pos);
toThreadCountId = game::GetObject(inst, game::GetVariable(inst, fileCountId, name));
game::LinkThread(inst, toThreadCountId, &includePos, 0);
game::RemoveVariable(name, fileCountId, inst);
}
}
}
game::ClearObject(duplicateFilePosId, inst);
game::RemoveRefToEmptyObject(inst, duplicateFilePosId);
game::LinkFile(inst, filePosId, fileCountId);
value.type = game::VAR_INTEGER;
game::SetVariableValue(inst, &value, scriptId);
}
}
#pragma warning(pop)