Check all ACS functions for minimum number of arguments.

Also fixes SpawnForced not respecting the minimum declared in zspecial.acs. (https://forum.zdoom.org/viewtopic.php?t=77027)
This commit is contained in:
Marisa Heit 2023-01-15 22:58:38 -06:00 committed by Christoph Oelckers
parent dd7cb8649f
commit 258f4b6786

View file

@ -748,7 +748,7 @@ protected:
int DoSpawnSpot(int type, int spot, int tid, int angle, bool forced);
int DoSpawnSpotFacing(int type, int spot, int tid, bool forced);
int DoClassifyActor(int tid);
int CallFunction(int argCount, int funcIndex, int32_t *args);
int CallFunction(int argCount, int funcIndex, int32_t *args, int &needCount);
void DoFadeTo(int r, int g, int b, int a, int time);
void DoFadeRange(int r1, int g1, int b1, int a1, int r2, int g2, int b2, int a2, int time);
@ -5323,46 +5323,60 @@ int DLevelScript::SwapActorTeleFog(AActor *activator, int tid)
return retval;
}
int DLevelScript::CallFunction(int argCount, int funcIndex, int32_t *args)
// Macro for CallFunction. Checks passed number of arguments with minimum required. Sets needCount and returns if not enough.
#define MIN_ARG_COUNT(minCount) do { if (argCount < minCount) { needCount = minCount; return 0; } } while(0)
int DLevelScript::CallFunction(int argCount, int funcIndex, int32_t *args, int &needCount)
{
AActor *actor;
switch(funcIndex)
{
case ACSF_GetLineUDMFInt:
MIN_ARG_COUNT(2);
return GetUDMFInt(Level, UDMF_Line, LineFromID(args[0]), Level->Behaviors.LookupString(args[1]));
case ACSF_GetLineUDMFFixed:
MIN_ARG_COUNT(2);
return DoubleToACS(GetUDMFFloat(Level, UDMF_Line, LineFromID(args[0]), Level->Behaviors.LookupString(args[1])));
case ACSF_GetThingUDMFInt:
case ACSF_GetThingUDMFFixed:
MIN_ARG_COUNT(2);
return 0; // Not implemented yet
case ACSF_GetSectorUDMFInt:
MIN_ARG_COUNT(2);
return GetUDMFInt(Level, UDMF_Sector, Level->FindFirstSectorFromTag(args[0]), Level->Behaviors.LookupString(args[1]));
case ACSF_GetSectorUDMFFixed:
MIN_ARG_COUNT(2);
return DoubleToACS(GetUDMFFloat(Level, UDMF_Sector, Level->FindFirstSectorFromTag(args[0]), Level->Behaviors.LookupString(args[1])));
case ACSF_GetSideUDMFInt:
MIN_ARG_COUNT(3);
return GetUDMFInt(Level, UDMF_Side, SideFromID(args[0], args[1]), Level->Behaviors.LookupString(args[2]));
case ACSF_GetSideUDMFFixed:
MIN_ARG_COUNT(3);
return DoubleToACS(GetUDMFFloat(Level, UDMF_Side, SideFromID(args[0], args[1]), Level->Behaviors.LookupString(args[2])));
case ACSF_GetActorVelX:
MIN_ARG_COUNT(1);
actor = Level->SingleActorFromTID(args[0], activator);
return actor != NULL? DoubleToACS(actor->Vel.X) : 0;
case ACSF_GetActorVelY:
MIN_ARG_COUNT(1);
actor = Level->SingleActorFromTID(args[0], activator);
return actor != NULL? DoubleToACS(actor->Vel.Y) : 0;
case ACSF_GetActorVelZ:
MIN_ARG_COUNT(1);
actor = Level->SingleActorFromTID(args[0], activator);
return actor != NULL? DoubleToACS(actor->Vel.Z) : 0;
case ACSF_SetPointer:
MIN_ARG_COUNT(2);
if (activator)
{
AActor *ptr = Level->SingleActorFromTID(args[1], activator);
@ -5377,6 +5391,7 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, int32_t *args)
return 0;
case ACSF_SetActivator:
MIN_ARG_COUNT(1);
if (argCount > 1 && args[1] != AAPTR_DEFAULT) // condition (x != AAPTR_DEFAULT) is essentially condition (x).
{
activator = COPY_AAPTREX(Level, Level->SingleActorFromTID(args[0], activator), args[1]);
@ -5388,6 +5403,7 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, int32_t *args)
return activator != NULL;
case ACSF_SetActivatorToTarget:
MIN_ARG_COUNT(1);
// [KS] I revised this a little bit
actor = Level->SingleActorFromTID(args[0], activator);
if (actor != NULL)
@ -5411,6 +5427,7 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, int32_t *args)
return 0;
case ACSF_GetActorViewHeight:
MIN_ARG_COUNT(1);
actor = Level->SingleActorFromTID(args[0], activator);
if (actor != NULL)
{
@ -5426,6 +5443,7 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, int32_t *args)
else return 0;
case ACSF_GetChar:
MIN_ARG_COUNT(2);
{
const char *p = Level->Behaviors.LookupString(args[0]);
if (p != NULL && args[1] >= 0 && args[1] < int(strlen(p)))
@ -5439,6 +5457,7 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, int32_t *args)
}
case ACSF_GetAirSupply:
MIN_ARG_COUNT(1);
{
if (args[0] < 0 || args[0] >= MAXPLAYERS || !Level->PlayerInGame(args[0]))
{
@ -5451,6 +5470,7 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, int32_t *args)
}
case ACSF_SetAirSupply:
MIN_ARG_COUNT(2);
{
if (args[0] < 0 || args[0] >= MAXPLAYERS || !Level->PlayerInGame(args[0]))
{
@ -5464,6 +5484,7 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, int32_t *args)
}
case ACSF_SetSkyScrollSpeed:
MIN_ARG_COUNT(2);
{
if (args[0] == 1) Level->skyspeed1 = ACSToFloat(args[1]);
else if (args[0] == 2) Level->skyspeed2 = ACSToFloat(args[1]);
@ -5471,6 +5492,7 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, int32_t *args)
}
case ACSF_GetArmorType:
MIN_ARG_COUNT(2);
{
if (args[1] < 0 || args[1] >= MAXPLAYERS || !Level->PlayerInGame(args[1]))
{
@ -5486,6 +5508,7 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, int32_t *args)
}
case ACSF_GetArmorInfo:
MIN_ARG_COUNT(1);
{
if (activator == NULL || activator->player == NULL) return 0;
@ -5521,15 +5544,19 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, int32_t *args)
}
case ACSF_SpawnSpotForced:
MIN_ARG_COUNT(4);
return DoSpawnSpot(args[0], args[1], args[2], args[3], true);
case ACSF_SpawnSpotFacingForced:
MIN_ARG_COUNT(3);
return DoSpawnSpotFacing(args[0], args[1], args[2], true);
case ACSF_CheckActorProperty:
MIN_ARG_COUNT(3);
return (CheckActorProperty(args[0], args[1], args[2]));
case ACSF_SetActorVelocity:
MIN_ARG_COUNT(6);
{
DVector3 vel(ACSToDouble(args[1]), ACSToDouble(args[2]), ACSToDouble(args[3]));
if (args[0] == 0)
@ -5549,6 +5576,7 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, int32_t *args)
}
case ACSF_SetUserVariable:
MIN_ARG_COUNT(3);
{
int cnt = 0;
FName varname(Level->Behaviors.LookupString(args[1]), true);
@ -5577,6 +5605,7 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, int32_t *args)
}
case ACSF_GetUserVariable:
MIN_ARG_COUNT(2);
{
FName varname(Level->Behaviors.LookupString(args[1]), true);
if (varname != NAME_None)
@ -5588,6 +5617,7 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, int32_t *args)
}
case ACSF_SetUserArray:
MIN_ARG_COUNT(4);
{
int cnt = 0;
FName varname(Level->Behaviors.LookupString(args[1]), true);
@ -5616,6 +5646,7 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, int32_t *args)
}
case ACSF_GetUserArray:
MIN_ARG_COUNT(3);
{
FName varname(Level->Behaviors.LookupString(args[1]), true);
if (varname != NAME_None)
@ -5627,22 +5658,26 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, int32_t *args)
}
case ACSF_Radius_Quake2:
MIN_ARG_COUNT(6);
P_StartQuake(Level, activator, args[0], (double)args[1], args[2], args[3], args[4], S_FindSound(Level->Behaviors.LookupString(args[5])));
break;
case ACSF_CheckActorClass:
MIN_ARG_COUNT(2);
{
AActor *a = Level->SingleActorFromTID(args[0], activator);
return a == NULL ? false : a->GetClass()->TypeName == FName(Level->Behaviors.LookupString(args[1]));
}
case ACSF_GetActorClass:
MIN_ARG_COUNT(1);
{
AActor *a = Level->SingleActorFromTID(args[0], activator);
return GlobalACSStrings.AddString(a == NULL ? "None" : a->GetClass()->TypeName.GetChars());
}
case ACSF_SoundSequenceOnActor:
MIN_ARG_COUNT(2);
{
const char *seqname = Level->Behaviors.LookupString(args[1]);
if (seqname != NULL)
@ -5669,6 +5704,7 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, int32_t *args)
break;
case ACSF_SoundSequenceOnSector:
MIN_ARG_COUNT(3);
{
const char *seqname = Level->Behaviors.LookupString(args[1]);
int space = args[2] < CHAN_FLOOR || args[2] > CHAN_INTERIOR ? CHAN_FULLHEIGHT : args[2];
@ -5685,6 +5721,7 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, int32_t *args)
break;
case ACSF_SoundSequenceOnPolyobj:
MIN_ARG_COUNT(2);
{
const char *seqname = Level->Behaviors.LookupString(args[1]);
if (seqname != NULL)
@ -5699,6 +5736,7 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, int32_t *args)
break;
case ACSF_GetPolyobjX:
MIN_ARG_COUNT(1);
{
FPolyObj *poly = Level->GetPolyobj(args[0]);
if (poly != NULL)
@ -5709,6 +5747,7 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, int32_t *args)
return FIXED_MAX;
case ACSF_GetPolyobjY:
MIN_ARG_COUNT(1);
{
FPolyObj *poly = Level->GetPolyobj(args[0]);
if (poly != NULL)
@ -5719,6 +5758,7 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, int32_t *args)
return FIXED_MAX;
case ACSF_CheckSight:
MIN_ARG_COUNT(3);
{
AActor *source;
AActor *dest;
@ -5764,7 +5804,8 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, int32_t *args)
}
case ACSF_SpawnForced:
return DoSpawn(args[0], args[1], args[2], args[3], args[4], args[5], true);
MIN_ARG_COUNT(4);
return DoSpawn(args[0], args[1], args[2], args[3], argCount > 4 ? args[4] : 0, argCount > 5 ? args[5] : 0, true);
case ACSF_ACS_NamedExecute:
case ACSF_ACS_NamedSuspend:
@ -5773,6 +5814,7 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, int32_t *args)
case ACSF_ACS_NamedLockedExecuteDoor:
case ACSF_ACS_NamedExecuteWithResult:
case ACSF_ACS_NamedExecuteAlways:
MIN_ARG_COUNT(1);
{
int scriptnum = -FName(Level->Behaviors.LookupString(args[0])).GetIndex();
int arg1 = argCount > 1 ? args[1] : 0;
@ -5789,15 +5831,19 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, int32_t *args)
return Level->FindUniqueTID(argCount > 0 ? args[0] : 0, (argCount > 1 && args[1] >= 0) ? args[1] : 0);
case ACSF_IsTIDUsed:
MIN_ARG_COUNT(1);
return Level->IsTIDUsed(args[0]);
case ACSF_Sqrt:
MIN_ARG_COUNT(1);
return xs_FloorToInt(g_sqrt(double(args[0])));
case ACSF_FixedSqrt:
MIN_ARG_COUNT(1);
return DoubleToACS(g_sqrt(ACSToDouble(args[0])));
case ACSF_VectorLength:
MIN_ARG_COUNT(2);
return DoubleToACS(DVector2(ACSToDouble(args[0]), ACSToDouble(args[1])).Length());
case ACSF_SetHUDClipRect:
@ -5814,56 +5860,36 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, int32_t *args)
break;
case ACSF_GetCVarString:
if (argCount == 1)
{
return DoGetCVar(GetCVar(activator && activator->player ? int(activator->player - players) : -1, Level->Behaviors.LookupString(args[0])), true);
}
break;
MIN_ARG_COUNT(1);
return DoGetCVar(GetCVar(activator && activator->player ? int(activator->player - players) : -1, Level->Behaviors.LookupString(args[0])), true);
case ACSF_SetCVar:
if (argCount == 2)
{
return SetCVar(activator, Level->Behaviors.LookupString(args[0]), args[1], false);
}
break;
MIN_ARG_COUNT(2);
return SetCVar(activator, Level->Behaviors.LookupString(args[0]), args[1], false);
case ACSF_SetCVarString:
if (argCount == 2)
{
return SetCVar(activator, Level->Behaviors.LookupString(args[0]), args[1], true);
}
break;
MIN_ARG_COUNT(2);
return SetCVar(activator, Level->Behaviors.LookupString(args[0]), args[1], true);
case ACSF_GetUserCVar:
if (argCount == 2)
{
return DoGetCVar(G_GetUserCVar(args[0], Level->Behaviors.LookupString(args[1])), false);
}
break;
MIN_ARG_COUNT(2);
return DoGetCVar(G_GetUserCVar(args[0], Level->Behaviors.LookupString(args[1])), false);
case ACSF_GetUserCVarString:
if (argCount == 2)
{
return DoGetCVar(G_GetUserCVar(args[0], Level->Behaviors.LookupString(args[1])), true);
}
break;
MIN_ARG_COUNT(2);
return DoGetCVar(G_GetUserCVar(args[0], Level->Behaviors.LookupString(args[1])), true);
case ACSF_SetUserCVar:
if (argCount == 3)
{
return SetUserCVar(args[0], Level->Behaviors.LookupString(args[1]), args[2], false);
}
break;
MIN_ARG_COUNT(3);
return SetUserCVar(args[0], Level->Behaviors.LookupString(args[1]), args[2], false);
case ACSF_SetUserCVarString:
if (argCount == 3)
{
return SetUserCVar(args[0], Level->Behaviors.LookupString(args[1]), args[2], true);
}
break;
MIN_ARG_COUNT(3);
return SetUserCVar(args[0], Level->Behaviors.LookupString(args[1]), args[2], true);
//[RC] A bullet firing function for ACS. Thanks to DavidPH.
case ACSF_LineAttack:
MIN_ARG_COUNT(4);
{
DAngle angle = ACSToAngle(args[1]);
DAngle pitch = ACSToAngle(args[2]);
@ -5906,6 +5932,7 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, int32_t *args)
case ACSF_PlaySound:
case ACSF_PlayActorSound:
// PlaySound(tid, "SoundName", channel, volume, looping, attenuation, local)
MIN_ARG_COUNT(2);
{
FSoundID sid = NO_SOUND;
@ -5952,6 +5979,7 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound)
break;
case ACSF_StopSound:
MIN_ARG_COUNT(1);
{
int chan = argCount > 1 ? args[1] : CHAN_BODY;
@ -5974,6 +6002,7 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound)
case ACSF_SoundVolume:
// SoundVolume(int tid, int channel, fixed volume)
MIN_ARG_COUNT(3);
{
int chan = args[1];
double volume = ACSToDouble(args[2]);
@ -5997,7 +6026,7 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound)
case ACSF_strcmp:
case ACSF_stricmp:
if (argCount >= 2)
MIN_ARG_COUNT(2);
{
const char *a, *b;
// If the string indicies are the same, then they are the same string.
@ -6026,7 +6055,7 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound)
case ACSF_StrLeft:
case ACSF_StrRight:
if (argCount >= 2)
MIN_ARG_COUNT(2);
{
const char *oldstr = Level->Behaviors.LookupString(args[0]);
if (oldstr == NULL || *oldstr == '\0')
@ -6046,7 +6075,7 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound)
break;
case ACSF_StrMid:
if (argCount >= 3)
MIN_ARG_COUNT(3);
{
const char *oldstr = Level->Behaviors.LookupString(args[0]);
if (oldstr == NULL || *oldstr == '\0')
@ -6083,6 +6112,7 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound)
case ACSF_SpawnDecal:
// int SpawnDecal(int tid, str decalname, int flags, fixed angle, int|fixed zoffset, int|fixed distance)
// Returns number of decals spawned (not including spreading)
MIN_ARG_COUNT(2);
{
int count = 0;
const FDecalTemplate *tpl = DecalLibrary.GetDecalByName(Level->Behaviors.LookupString(args[1]));
@ -6117,9 +6147,11 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound)
case ACSF_CheckFont:
// bool CheckFont(str fontname)
MIN_ARG_COUNT(1);
return V_GetFont(Level->Behaviors.LookupString(args[0])) != NULL;
case ACSF_DropItem:
MIN_ARG_COUNT(2);
{
const char *type = Level->Behaviors.LookupString(args[1]);
int amount = argCount >= 3? args[2] : -1;
@ -6153,6 +6185,7 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound)
}
case ACSF_DropInventory:
MIN_ARG_COUNT(2);
{
const char *type = Level->Behaviors.LookupString(args[1]);
AActor *inv;
@ -6189,6 +6222,7 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound)
}
case ACSF_CheckFlag:
MIN_ARG_COUNT(2);
{
AActor *actor = Level->SingleActorFromTID(args[0], activator);
if (actor != NULL)
@ -6199,6 +6233,7 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound)
}
case ACSF_QuakeEx:
MIN_ARG_COUNT(8);
{
return P_StartQuakeXYZ(Level, activator, args[0], args[1], args[2], args[3], args[4], args[5], args[6], S_FindSound(Level->Behaviors.LookupString(args[7])),
argCount > 8 ? args[8] : 0,
@ -6212,11 +6247,11 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound)
}
case ACSF_SetLineActivation:
if (argCount >= 2)
MIN_ARG_COUNT(2);
{
int line;
auto itr = Level->GetLineIdIterator(args[0]);
int repeat = argCount > 2? args[2] : -1;
int repeat = argCount > 2 ? args[2] : -1;
while ((line = itr.Next()) >= 0)
{
Level->lines[line].activation = args[1];
@ -6227,7 +6262,7 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound)
break;
case ACSF_GetLineActivation:
if (argCount > 0)
MIN_ARG_COUNT(1);
{
int line = Level->FindFirstLineFromID(args[0]);
return line >= 0 ? Level->lines[line].activation : 0;
@ -6235,7 +6270,7 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound)
break;
case ACSF_GetActorPowerupTics:
if (argCount >= 2)
MIN_ARG_COUNT(2);
{
PClassActor *powerupclass = PClass::FindActor(Level->Behaviors.LookupString(args[1]));
if (powerupclass == NULL || !powerupclass->IsDescendantOf(NAME_Powerup))
@ -6256,32 +6291,26 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound)
break;
case ACSF_ChangeActorAngle:
if (argCount >= 2)
{
SetActorAngle(activator, args[0], args[1], argCount > 2 ? !!args[2] : false);
}
MIN_ARG_COUNT(2);
SetActorAngle(activator, args[0], args[1], argCount > 2 ? !!args[2] : false);
break;
case ACSF_ChangeActorPitch:
if (argCount >= 2)
{
SetActorPitch(activator, args[0], args[1], argCount > 2 ? !!args[2] : false);
}
MIN_ARG_COUNT(2);
SetActorPitch(activator, args[0], args[1], argCount > 2 ? !!args[2] : false);
break;
case ACSF_SetActorTeleFog:
if (argCount >= 3)
{
SetActorTeleFog(activator, args[0], Level->Behaviors.LookupString(args[1]), Level->Behaviors.LookupString(args[2]));
}
MIN_ARG_COUNT(3);
SetActorTeleFog(activator, args[0], Level->Behaviors.LookupString(args[1]), Level->Behaviors.LookupString(args[2]));
break;
case ACSF_SwapActorTeleFog:
if (argCount >= 1)
{
return SwapActorTeleFog(activator, args[0]);
}
break;
MIN_ARG_COUNT(1);
return SwapActorTeleFog(activator, args[0]);
case ACSF_PickActor:
if (argCount >= 5)
MIN_ARG_COUNT(5);
{
actor = Level->SingleActorFromTID(args[0], activator);
if (actor == NULL)
@ -6326,6 +6355,7 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound)
break;
case ACSF_IsPointerEqual:
MIN_ARG_COUNT(2);
{
int tid1 = 0, tid2 = 0;
switch (argCount)
@ -6342,7 +6372,8 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound)
break;
case ACSF_CanRaiseActor:
if (argCount >= 1) {
MIN_ARG_COUNT(1);
{
if (args[0] == 0) {
actor = Level->SingleActorFromTID(args[0], activator);
if (actor != NULL) {
@ -6354,7 +6385,7 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound)
bool canraiseall = true;
while ((actor = iterator.Next()))
{
canraiseall = P_Thing_CanRaise(actor) & canraiseall;
canraiseall &= P_Thing_CanRaise(actor);
}
return canraiseall;
@ -6363,22 +6394,23 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound)
// [Nash] Actor roll functions. Let's roll!
case ACSF_SetActorRoll:
MIN_ARG_COUNT(2);
SetActorRoll(activator, args[0], args[1], false);
return 0;
break;
case ACSF_ChangeActorRoll:
if (argCount >= 2)
{
SetActorRoll(activator, args[0], args[1], argCount > 2 ? !!args[2] : false);
}
MIN_ARG_COUNT(2);
SetActorRoll(activator, args[0], args[1], argCount > 2 ? !!args[2] : false);
break;
case ACSF_GetActorRoll:
MIN_ARG_COUNT(1);
actor = Level->SingleActorFromTID(args[0], activator);
return actor != NULL? AngleToACS(actor->Angles.Roll) : 0;
// [ZK] A_Warp in ACS
case ACSF_Warp:
MIN_ARG_COUNT(6);
{
if (nullptr == activator)
{
@ -6430,6 +6462,7 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound)
return true;
}
case ACSF_GetMaxInventory:
MIN_ARG_COUNT(2);
actor = Level->SingleActorFromTID(args[0], activator);
if (actor != NULL)
{
@ -6438,7 +6471,7 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound)
break;
case ACSF_SetSectorDamage:
if (argCount >= 2)
MIN_ARG_COUNT(2);
{
auto it = Level->GetSectorTagIterator(args[0]);
int s;
@ -6455,7 +6488,7 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound)
break;
case ACSF_SetSectorTerrain:
if (argCount >= 3)
MIN_ARG_COUNT(3);
{
if (args[1] == sector_t::floor || args[1] == sector_t::ceiling)
{
@ -6471,6 +6504,7 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound)
break;
case ACSF_SpawnParticle:
MIN_ARG_COUNT(1);
{
PalEntry color = args[0];
bool fullbright = argCount > 1 ? !!args[1] : false;
@ -6503,10 +6537,12 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound)
break;
case ACSF_SetMusicVolume:
MIN_ARG_COUNT(1);
Level->SetMusicVolume(ACSToFloat(args[0]));
break;
case ACSF_CheckProximity:
MIN_ARG_COUNT(3);
{
// [zombie] ACS version of A_CheckProximity
actor = Level->SingleActorFromTID(args[0], activator);
@ -6519,6 +6555,7 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound)
}
case ACSF_CheckActorState:
MIN_ARG_COUNT(2);
{
actor = Level->SingleActorFromTID(args[0], activator);
const char *statename = Level->Behaviors.LookupString(args[1]);
@ -6531,12 +6568,14 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound)
}
case ACSF_CheckClass:
MIN_ARG_COUNT(1);
{
const char *clsname = Level->Behaviors.LookupString(args[0]);
return !!PClass::FindActor(clsname);
}
case ACSF_DamageActor: // [arookas] wrapper around P_DamageMobj
MIN_ARG_COUNT(6);
{
// (target, ptr_select1, inflictor, ptr_select2, amount, damagetype)
AActor* target = COPY_AAPTREX(Level, Level->SingleActorFromTID(args[0], activator), args[1]);
@ -6546,6 +6585,7 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound)
}
case ACSF_SetActorFlag:
MIN_ARG_COUNT(3);
{
int tid = args[0];
FString flagname = Level->Behaviors.LookupString(args[1]);
@ -6574,6 +6614,7 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound)
}
case ACSF_SetTranslation:
MIN_ARG_COUNT(2);
{
int tid = args[0];
const char *trname = Level->Behaviors.LookupString(args[1]);
@ -6595,6 +6636,7 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound)
// OpenGL exclusive functions
case ACSF_SetSectorGlow:
MIN_ARG_COUNT(6);
{
int which = !!args[1];
PalEntry color(args[2], args[3], args[4]);
@ -6612,6 +6654,7 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound)
}
case ACSF_SetFogDensity:
MIN_ARG_COUNT(2);
{
auto it = Level->GetSectorTagIterator(args[0]);
int s;
@ -6624,6 +6667,7 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound)
}
case ACSF_GetActorFloorTexture:
MIN_ARG_COUNT(1);
{
auto a = Level->SingleActorFromTID(args[0], activator);
if (a != nullptr)
@ -6638,6 +6682,7 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound)
}
case ACSF_GetActorFloorTerrain:
MIN_ARG_COUNT(1);
{
auto a = Level->SingleActorFromTID(args[0], activator);
if (a != nullptr)
@ -6652,25 +6697,32 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound)
}
case ACSF_StrArg:
MIN_ARG_COUNT(1);
return -FName(Level->Behaviors.LookupString(args[0])).GetIndex();
case ACSF_Floor:
MIN_ARG_COUNT(1);
return args[0] & ~0xffff;
case ACSF_Ceil:
MIN_ARG_COUNT(1);
return (args[0] & ~0xffff) + 0x10000;
case ACSF_Round:
MIN_ARG_COUNT(1);
return (args[0] + 32768) & ~0xffff;
case ACSF_ScriptCall:
MIN_ARG_COUNT(1);
return ScriptCall(activator, argCount, args);
case ACSF_StartSlideshow:
MIN_ARG_COUNT(1);
G_StartSlideshow(Level, FName(Level->Behaviors.LookupString(args[0])));
break;
case ACSF_GetSectorHealth:
MIN_ARG_COUNT(2);
{
int part = args[1];
auto it = Level->GetSectorTagIterator(args[0]);
@ -6698,6 +6750,7 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound)
}
case ACSF_GetLineHealth:
MIN_ARG_COUNT(1);
{
auto it = Level->GetLineIdIterator(args[0]);
int l = it.Next();
@ -6715,6 +6768,7 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound)
case ACSF_GetLineX:
case ACSF_GetLineY:
MIN_ARG_COUNT(3);
{
auto it = Level->GetLineIdIterator(args[0]);
int lineno = it.Next();
@ -6730,22 +6784,20 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound)
}
case ACSF_SetSubtitleNumber:
if (argCount >= 2)
MIN_ARG_COUNT(2);
// only players allowed as activator
if (activator != nullptr && activator->player != nullptr)
{
// only players allowed as activator
if (activator != nullptr && activator->player != nullptr)
int logNum = args[0];
FSoundID sid = NO_SOUND;
const char* lookup = Level->Behaviors.LookupString(args[1]);
if (lookup != nullptr)
{
int logNum = args[0];
FSoundID sid = NO_SOUND;
const char* lookup = Level->Behaviors.LookupString(args[1]);
if (lookup != nullptr)
{
sid = S_FindSound(lookup);
}
activator->player->SetSubtitle(logNum, sid);
sid = S_FindSound(lookup);
}
activator->player->SetSubtitle(logNum, sid);
}
break;
@ -6754,6 +6806,7 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound)
}
return 0;
}
#undef MIN_ARG_COUNT
enum
{
@ -7167,7 +7220,12 @@ int DLevelScript::RunScript()
int argCount = NEXTBYTE;
int funcIndex = NEXTSHORT;
int retval = CallFunction(argCount, funcIndex, &STACK(argCount));
int retval, minCount = 0;
retval = CallFunction(argCount, funcIndex, &STACK(argCount), minCount);
if (minCount != 0)
{
Printf("Called ACS function index %d with too few args: %d (need %d)\n", funcIndex, argCount, minCount);
}
sp -= argCount-1;
STACK(1) = retval;
}