mirror of
https://github.com/ZDoom/gzdoom.git
synced 2024-11-11 07:12:02 +00:00
- added an ACS ScriptCall function. So far only superficially tested.
This commit is contained in:
parent
217bcb847d
commit
f563a296c2
1 changed files with 140 additions and 24 deletions
164
src/p_acs.cpp
164
src/p_acs.cpp
|
@ -180,7 +180,7 @@ inline int PitchToACS(DAngle ang)
|
||||||
|
|
||||||
struct CallReturn
|
struct CallReturn
|
||||||
{
|
{
|
||||||
CallReturn(int pc, ScriptFunction *func, FBehavior *module, SDWORD *locals, ACSLocalArrays *arrays, bool discard, unsigned int runaway)
|
CallReturn(int pc, ScriptFunction *func, FBehavior *module, int32_t *locals, ACSLocalArrays *arrays, bool discard, unsigned int runaway)
|
||||||
: ReturnFunction(func),
|
: ReturnFunction(func),
|
||||||
ReturnModule(module),
|
ReturnModule(module),
|
||||||
ReturnLocals(locals),
|
ReturnLocals(locals),
|
||||||
|
@ -192,7 +192,7 @@ struct CallReturn
|
||||||
|
|
||||||
ScriptFunction *ReturnFunction;
|
ScriptFunction *ReturnFunction;
|
||||||
FBehavior *ReturnModule;
|
FBehavior *ReturnModule;
|
||||||
SDWORD *ReturnLocals;
|
int32_t *ReturnLocals;
|
||||||
ACSLocalArrays *ReturnArrays;
|
ACSLocalArrays *ReturnArrays;
|
||||||
int ReturnAddress;
|
int ReturnAddress;
|
||||||
int bDiscardResult;
|
int bDiscardResult;
|
||||||
|
@ -206,7 +206,7 @@ static DLevelScript *P_GetScriptGoing (AActor *who, line_t *where, int num, cons
|
||||||
struct FBehavior::ArrayInfo
|
struct FBehavior::ArrayInfo
|
||||||
{
|
{
|
||||||
DWORD ArraySize;
|
DWORD ArraySize;
|
||||||
SDWORD *Elements;
|
int32_t *Elements;
|
||||||
};
|
};
|
||||||
|
|
||||||
TArray<FBehavior *> FBehavior::StaticModules;
|
TArray<FBehavior *> FBehavior::StaticModules;
|
||||||
|
@ -243,11 +243,11 @@ inline int uallong(const int &foo)
|
||||||
//============================================================================
|
//============================================================================
|
||||||
|
|
||||||
// ACS variables with world scope
|
// ACS variables with world scope
|
||||||
SDWORD ACS_WorldVars[NUM_WORLDVARS];
|
int32_t ACS_WorldVars[NUM_WORLDVARS];
|
||||||
FWorldGlobalArray ACS_WorldArrays[NUM_WORLDVARS];
|
FWorldGlobalArray ACS_WorldArrays[NUM_WORLDVARS];
|
||||||
|
|
||||||
// ACS variables with global scope
|
// ACS variables with global scope
|
||||||
SDWORD ACS_GlobalVars[NUM_GLOBALVARS];
|
int32_t ACS_GlobalVars[NUM_GLOBALVARS];
|
||||||
FWorldGlobalArray ACS_GlobalArrays[NUM_GLOBALVARS];
|
FWorldGlobalArray ACS_GlobalArrays[NUM_GLOBALVARS];
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
|
@ -261,7 +261,7 @@ FWorldGlobalArray ACS_GlobalArrays[NUM_GLOBALVARS];
|
||||||
|
|
||||||
struct FACSStack
|
struct FACSStack
|
||||||
{
|
{
|
||||||
SDWORD buffer[STACK_SIZE];
|
int32_t buffer[STACK_SIZE];
|
||||||
int sp;
|
int sp;
|
||||||
FACSStack *next;
|
FACSStack *next;
|
||||||
FACSStack *prev;
|
FACSStack *prev;
|
||||||
|
@ -979,7 +979,7 @@ void P_ClearACSVars(bool alsoglobal)
|
||||||
//
|
//
|
||||||
//============================================================================
|
//============================================================================
|
||||||
|
|
||||||
static void WriteVars (FSerializer &file, SDWORD *vars, size_t count, const char *key)
|
static void WriteVars (FSerializer &file, int32_t *vars, size_t count, const char *key)
|
||||||
{
|
{
|
||||||
size_t i, j;
|
size_t i, j;
|
||||||
|
|
||||||
|
@ -1007,7 +1007,7 @@ static void WriteVars (FSerializer &file, SDWORD *vars, size_t count, const char
|
||||||
//
|
//
|
||||||
//============================================================================
|
//============================================================================
|
||||||
|
|
||||||
static void ReadVars (FSerializer &arc, SDWORD *vars, size_t count, const char *key)
|
static void ReadVars (FSerializer &arc, int32_t *vars, size_t count, const char *key)
|
||||||
{
|
{
|
||||||
memset(&vars[0], 0, count * 4);
|
memset(&vars[0], 0, count * 4);
|
||||||
arc.Array(key, vars, (int)count);
|
arc.Array(key, vars, (int)count);
|
||||||
|
@ -1684,10 +1684,10 @@ void FBehavior::SerializeVars (FSerializer &arc)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void FBehavior::SerializeVarSet (FSerializer &arc, SDWORD *vars, int max)
|
void FBehavior::SerializeVarSet (FSerializer &arc, int32_t *vars, int max)
|
||||||
{
|
{
|
||||||
SDWORD count;
|
int32_t count;
|
||||||
SDWORD first, last;
|
int32_t first, last;
|
||||||
|
|
||||||
if (arc.BeginObject(nullptr))
|
if (arc.BeginObject(nullptr))
|
||||||
{
|
{
|
||||||
|
@ -1997,7 +1997,7 @@ bool FBehavior::Init(int lumpnum, FileReader * fr, int len)
|
||||||
{
|
{
|
||||||
MapVarStore[LittleLong(chunk[2+i*2])] = i;
|
MapVarStore[LittleLong(chunk[2+i*2])] = i;
|
||||||
ArrayStore[i].ArraySize = LittleLong(chunk[3+i*2]);
|
ArrayStore[i].ArraySize = LittleLong(chunk[3+i*2]);
|
||||||
ArrayStore[i].Elements = new SDWORD[ArrayStore[i].ArraySize];
|
ArrayStore[i].Elements = new int32_t[ArrayStore[i].ArraySize];
|
||||||
memset(ArrayStore[i].Elements, 0, ArrayStore[i].ArraySize*sizeof(DWORD));
|
memset(ArrayStore[i].Elements, 0, ArrayStore[i].ArraySize*sizeof(DWORD));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2013,7 +2013,7 @@ bool FBehavior::Init(int lumpnum, FileReader * fr, int len)
|
||||||
// optimizer. Might be some undefined behavior in this code,
|
// optimizer. Might be some undefined behavior in this code,
|
||||||
// but I don't know what it is.
|
// but I don't know what it is.
|
||||||
unsigned int initsize = MIN<unsigned int> (ArrayStore[arraynum].ArraySize, (LittleLong(chunk[1])-4)/4);
|
unsigned int initsize = MIN<unsigned int> (ArrayStore[arraynum].ArraySize, (LittleLong(chunk[1])-4)/4);
|
||||||
SDWORD *elems = ArrayStore[arraynum].Elements;
|
int32_t *elems = ArrayStore[arraynum].Elements;
|
||||||
for (unsigned int j = 0; j < initsize; ++j)
|
for (unsigned int j = 0; j < initsize; ++j)
|
||||||
{
|
{
|
||||||
elems[j] = LittleLong(chunk[3+j]);
|
elems[j] = LittleLong(chunk[3+j]);
|
||||||
|
@ -2062,7 +2062,7 @@ bool FBehavior::Init(int lumpnum, FileReader * fr, int len)
|
||||||
int arraynum = MapVarStore[LittleLong(chunk[i+2])];
|
int arraynum = MapVarStore[LittleLong(chunk[i+2])];
|
||||||
if ((unsigned)arraynum < (unsigned)NumArrays)
|
if ((unsigned)arraynum < (unsigned)NumArrays)
|
||||||
{
|
{
|
||||||
SDWORD *elems = ArrayStore[arraynum].Elements;
|
int32_t *elems = ArrayStore[arraynum].Elements;
|
||||||
for (int j = ArrayStore[arraynum].ArraySize; j > 0; --j, ++elems)
|
for (int j = ArrayStore[arraynum].ArraySize; j > 0; --j, ++elems)
|
||||||
{
|
{
|
||||||
// *elems |= LibraryID;
|
// *elems |= LibraryID;
|
||||||
|
@ -2088,7 +2088,7 @@ bool FBehavior::Init(int lumpnum, FileReader * fr, int len)
|
||||||
chunkData += 4;
|
chunkData += 4;
|
||||||
if ((unsigned)arraynum < (unsigned)NumArrays)
|
if ((unsigned)arraynum < (unsigned)NumArrays)
|
||||||
{
|
{
|
||||||
SDWORD *elems = ArrayStore[arraynum].Elements;
|
int32_t *elems = ArrayStore[arraynum].Elements;
|
||||||
// Ending zeros may be left out.
|
// Ending zeros may be left out.
|
||||||
for (int j = MIN(LittleLong(chunk[1])-5, ArrayStore[arraynum].ArraySize); j > 0; --j, ++elems, ++chunkData)
|
for (int j = MIN(LittleLong(chunk[1])-5, ArrayStore[arraynum].ArraySize); j > 0; --j, ++elems, ++chunkData)
|
||||||
{
|
{
|
||||||
|
@ -4371,6 +4371,7 @@ enum EACSFunctions
|
||||||
ACSF_Floor,
|
ACSF_Floor,
|
||||||
ACSF_Round,
|
ACSF_Round,
|
||||||
ACSF_Ceil,
|
ACSF_Ceil,
|
||||||
|
ACSF_ScriptCall,
|
||||||
|
|
||||||
|
|
||||||
// OpenGL stuff
|
// OpenGL stuff
|
||||||
|
@ -4753,9 +4754,121 @@ static int SwapActorTeleFog(AActor *activator, int tid)
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int ScriptCall(unsigned argc, int32_t *args)
|
||||||
|
{
|
||||||
|
int retval = 0;
|
||||||
|
if (argc >= 2)
|
||||||
|
{
|
||||||
|
auto clsname = FBehavior::StaticLookupString(args[0]);
|
||||||
|
auto funcname = FBehavior::StaticLookupString(args[1]);
|
||||||
|
|
||||||
|
auto cls = PClass::FindClass(clsname);
|
||||||
|
if (!cls)
|
||||||
|
{
|
||||||
|
I_Error("ACS call to unknown class in script function %s.%s", cls, funcname);
|
||||||
|
}
|
||||||
|
auto funcsym = dyn_cast<PFunction>(cls->Symbols.FindSymbol(funcname, true));
|
||||||
|
if (funcsym == nullptr)
|
||||||
|
{
|
||||||
|
I_Error("ACS call to unknown script function %s.%s", cls, funcname);
|
||||||
|
}
|
||||||
|
auto func = funcsym->Variants[0].Implementation;
|
||||||
|
if (func->ImplicitArgs > 0)
|
||||||
|
{
|
||||||
|
I_Error("ACS call to non-static script function %s.%s", cls, funcname);
|
||||||
|
}
|
||||||
|
TArray<VMValue> params;
|
||||||
|
for (unsigned i = 2; i < argc; i++)
|
||||||
|
{
|
||||||
|
if (func->Proto->ArgumentTypes.Size() < i - 1)
|
||||||
|
{
|
||||||
|
I_Error("Too many parameters in call to %s.%s", cls, funcname);
|
||||||
|
}
|
||||||
|
auto argtype = func->Proto->ArgumentTypes[i - 2];
|
||||||
|
// The only types allowed are int, bool, double, Name, Sound, Color and String
|
||||||
|
if (argtype == TypeSInt32 || argtype == TypeColor)
|
||||||
|
{
|
||||||
|
params.Push(args[i]);
|
||||||
|
}
|
||||||
|
else if (argtype == TypeBool)
|
||||||
|
{
|
||||||
|
params.Push(!!args[i]);
|
||||||
|
}
|
||||||
|
else if (argtype == TypeFloat64)
|
||||||
|
{
|
||||||
|
params.Push(ACSToDouble(args[i]));
|
||||||
|
}
|
||||||
|
else if (argtype == TypeName)
|
||||||
|
{
|
||||||
|
params.Push(FName(FBehavior::StaticLookupString(args[i])).GetIndex());
|
||||||
|
}
|
||||||
|
else if (argtype == TypeString)
|
||||||
|
{
|
||||||
|
params.Push(FBehavior::StaticLookupString(args[i]));
|
||||||
|
}
|
||||||
|
else if (argtype == TypeSound)
|
||||||
|
{
|
||||||
|
params.Push(int(FSoundID(FBehavior::StaticLookupString(args[i]))));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
I_Error("Invalid type %s in call to %s.%s", argtype->DescriptiveName(), cls, funcname);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (func->Proto->ArgumentTypes.Size() > params.Size())
|
||||||
|
{
|
||||||
|
// Check if we got enough parameters. That means we either cover the full argument list of the function or the next argument is optional.
|
||||||
|
if (!(funcsym->Variants[0].ArgFlags[params.Size()] & VARF_Optional))
|
||||||
|
{
|
||||||
|
I_Error("Insufficient parameters in call to %s.%s", cls, funcname);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// The return value can be the same types as the parameter types, plus void
|
||||||
|
if (func->Proto->ReturnTypes.Size() == 0)
|
||||||
|
{
|
||||||
|
GlobalVMStack.Call(func, ¶ms[0], params.Size(), nullptr, 0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto rettype = func->Proto->ReturnTypes[0];
|
||||||
|
if (rettype == TypeSInt32 || rettype == TypeBool || rettype == TypeColor || rettype == TypeName || rettype == TypeSound)
|
||||||
|
{
|
||||||
|
VMReturn ret(&retval);
|
||||||
|
GlobalVMStack.Call(func, ¶ms[0], params.Size(), &ret, 1);
|
||||||
|
if (rettype == TypeName)
|
||||||
|
{
|
||||||
|
retval = GlobalACSStrings.AddString(FName(ENamedName(retval)));
|
||||||
|
}
|
||||||
|
else if (rettype == TypeSound)
|
||||||
|
{
|
||||||
|
retval = GlobalACSStrings.AddString(FSoundID(retval));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (rettype == TypeFloat64)
|
||||||
|
{
|
||||||
|
double d;
|
||||||
|
VMReturn ret(&d);
|
||||||
|
GlobalVMStack.Call(func, ¶ms[0], params.Size(), &ret, 1);
|
||||||
|
retval = DoubleToACS(d);
|
||||||
|
}
|
||||||
|
else if (rettype == TypeString)
|
||||||
|
{
|
||||||
|
FString d;
|
||||||
|
VMReturn ret(&d);
|
||||||
|
GlobalVMStack.Call(func, ¶ms[0], params.Size(), &ret, 1);
|
||||||
|
retval = GlobalACSStrings.AddString(d);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// All other return values can not be handled so ignore them.
|
||||||
|
GlobalVMStack.Call(func, ¶ms[0], params.Size(), nullptr, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
int DLevelScript::CallFunction(int argCount, int funcIndex, SDWORD *args)
|
int DLevelScript::CallFunction(int argCount, int funcIndex, int32_t *args)
|
||||||
{
|
{
|
||||||
AActor *actor;
|
AActor *actor;
|
||||||
switch(funcIndex)
|
switch(funcIndex)
|
||||||
|
@ -6103,6 +6216,9 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound)
|
||||||
case ACSF_Round:
|
case ACSF_Round:
|
||||||
return (args[0] + 32768) & ~0xffff;
|
return (args[0] + 32768) & ~0xffff;
|
||||||
|
|
||||||
|
case ACSF_ScriptCall:
|
||||||
|
return ScriptCall(argCount, args);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -6192,7 +6308,7 @@ static void SetMarineSprite(AActor *marine, PClassActor *source)
|
||||||
int DLevelScript::RunScript ()
|
int DLevelScript::RunScript ()
|
||||||
{
|
{
|
||||||
DACSThinker *controller = DACSThinker::ActiveThinker;
|
DACSThinker *controller = DACSThinker::ActiveThinker;
|
||||||
SDWORD *locals = &Localvars[0];
|
int32_t *locals = &Localvars[0];
|
||||||
ACSLocalArrays noarrays;
|
ACSLocalArrays noarrays;
|
||||||
ACSLocalArrays *localarrays = &noarrays;
|
ACSLocalArrays *localarrays = &noarrays;
|
||||||
ScriptFunction *activeFunction = NULL;
|
ScriptFunction *activeFunction = NULL;
|
||||||
|
@ -6266,7 +6382,7 @@ int DLevelScript::RunScript ()
|
||||||
}
|
}
|
||||||
|
|
||||||
FACSStack stackobj;
|
FACSStack stackobj;
|
||||||
SDWORD *Stack = stackobj.buffer;
|
int32_t *Stack = stackobj.buffer;
|
||||||
int &sp = stackobj.sp;
|
int &sp = stackobj.sp;
|
||||||
|
|
||||||
int *pc = this->pc;
|
int *pc = this->pc;
|
||||||
|
@ -6560,7 +6676,7 @@ int DLevelScript::RunScript ()
|
||||||
int i;
|
int i;
|
||||||
ScriptFunction *func;
|
ScriptFunction *func;
|
||||||
FBehavior *module;
|
FBehavior *module;
|
||||||
SDWORD *mylocals;
|
int32_t *mylocals;
|
||||||
|
|
||||||
if(pcd == PCD_CALLSTACK)
|
if(pcd == PCD_CALLSTACK)
|
||||||
{
|
{
|
||||||
|
@ -6615,7 +6731,7 @@ int DLevelScript::RunScript ()
|
||||||
int value;
|
int value;
|
||||||
union
|
union
|
||||||
{
|
{
|
||||||
SDWORD *retsp;
|
int32_t *retsp;
|
||||||
CallReturn *ret;
|
CallReturn *ret;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -7770,7 +7886,7 @@ scriptwait:
|
||||||
while (min <= max)
|
while (min <= max)
|
||||||
{
|
{
|
||||||
int mid = (min + max) / 2;
|
int mid = (min + max) / 2;
|
||||||
SDWORD caseval = LittleLong(pc[mid*2]);
|
int32_t caseval = LittleLong(pc[mid*2]);
|
||||||
if (caseval == STACK(1))
|
if (caseval == STACK(1))
|
||||||
{
|
{
|
||||||
pc = activeBehavior->Ofs2PC (LittleLong(pc[mid*2+1]));
|
pc = activeBehavior->Ofs2PC (LittleLong(pc[mid*2+1]));
|
||||||
|
@ -9185,7 +9301,7 @@ scriptwait:
|
||||||
const char *str = FBehavior::StaticLookupString(STACK(1));
|
const char *str = FBehavior::StaticLookupString(STACK(1));
|
||||||
if (str != NULL)
|
if (str != NULL)
|
||||||
{
|
{
|
||||||
STACK(1) = SDWORD(strlen(str));
|
STACK(1) = int32_t(strlen(str));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9355,7 +9471,7 @@ scriptwait:
|
||||||
switch (STACK(1))
|
switch (STACK(1))
|
||||||
{
|
{
|
||||||
case PLAYERINFO_TEAM: STACK(2) = userinfo->GetTeam(); break;
|
case PLAYERINFO_TEAM: STACK(2) = userinfo->GetTeam(); break;
|
||||||
case PLAYERINFO_AIMDIST: STACK(2) = (SDWORD)(userinfo->GetAimDist() * (0x40000000/90.)); break; // Yes, this has been returning a BAM since its creation.
|
case PLAYERINFO_AIMDIST: STACK(2) = (int32_t)(userinfo->GetAimDist() * (0x40000000/90.)); break; // Yes, this has been returning a BAM since its creation.
|
||||||
case PLAYERINFO_COLOR: STACK(2) = userinfo->GetColor(); break;
|
case PLAYERINFO_COLOR: STACK(2) = userinfo->GetColor(); break;
|
||||||
case PLAYERINFO_GENDER: STACK(2) = userinfo->GetGender(); break;
|
case PLAYERINFO_GENDER: STACK(2) = userinfo->GetGender(); break;
|
||||||
case PLAYERINFO_NEVERSWITCH: STACK(2) = userinfo->GetNeverSwitch(); break;
|
case PLAYERINFO_NEVERSWITCH: STACK(2) = userinfo->GetNeverSwitch(); break;
|
||||||
|
@ -9762,7 +9878,7 @@ DLevelScript::DLevelScript (AActor *who, line_t *where, int num, const ScriptPtr
|
||||||
script = num;
|
script = num;
|
||||||
assert(code->VarCount >= code->ArgCount);
|
assert(code->VarCount >= code->ArgCount);
|
||||||
Localvars.Resize(code->VarCount);
|
Localvars.Resize(code->VarCount);
|
||||||
memset(&Localvars[0], 0, code->VarCount * sizeof(SDWORD));
|
memset(&Localvars[0], 0, code->VarCount * sizeof(int32_t));
|
||||||
for (int i = 0; i < MIN<int>(argcount, code->ArgCount); ++i)
|
for (int i = 0; i < MIN<int>(argcount, code->ArgCount); ++i)
|
||||||
{
|
{
|
||||||
Localvars[i] = args[i];
|
Localvars[i] = args[i];
|
||||||
|
|
Loading…
Reference in a new issue