- Changed the action function declaration parser so that optional parameters

can be given a default value. The 'optional' keyword is no longer needed
  and was removed, as well as 'evalnot'.


SVN r1164 (trunk)
This commit is contained in:
Christoph Oelckers 2008-08-12 20:19:47 +00:00
parent 1957659b1b
commit 65a19e4be7
18 changed files with 1093 additions and 1096 deletions

View file

@ -1,4 +1,7 @@
August 12, 2008 (Changes by Graf Zahl)
- Changed the action function declaration parser so that optional parameters
can be given a default value. The 'optional' keyword is no longer needed
and was removed, as well as 'evalnot'.
- Restructured the action function interface to remove the dependence on
the global CallingState variable.
- Changed handling of AUTOPAGE texture so that it is properly inserted into

View file

@ -81,6 +81,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_BrainSpit)
DSpotState *state = DSpotState::GetSpotState();
AActor *targ;
AActor *spit;
bool isdefault = false;
// shoot a cube at current target
targ = state->GetNextInList(PClass::FindClass("BossTarget"), G_SkillProperty(SKILLP_EasyBossBrain));
@ -89,8 +90,15 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_BrainSpit)
{
const PClass *spawntype = NULL;
int index = CheckIndex (1);
if (index >= 0) spawntype = PClass::FindClass ((ENamedName)StateParameters[index]);
if (spawntype == NULL) spawntype = PClass::FindClass("SpawnShot");
if (index < 0) return;
spawntype = PClass::FindClass ((ENamedName)StateParameters[index]);
if (spawntype == NULL)
{
spawntype = PClass::FindClass("SpawnShot");
isdefault = true;
}
// spawn brain missile
spit = P_SpawnMissile (self, targ, spawntype);
@ -117,7 +125,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_BrainSpit)
spit->reactiontime += level.maptime;
}
if (index >= 0)
if (!isdefault)
{
S_Sound(self, CHAN_WEAPON, self->AttackSound, 1, ATTN_NONE);
}
@ -240,10 +248,12 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SpawnFly)
int index = CheckIndex (1);
// First spawn teleport fire.
if (index >= 0)
if (index < 0) return;
spawntype = PClass::FindClass ((ENamedName)StateParameters[index]);
if (spawntype != NULL)
{
spawntype = PClass::FindClass ((ENamedName)StateParameters[index]);
if (spawntype != NULL) sound = GetDefaultByType(spawntype)->SeeSound;
sound = GetDefaultByType(spawntype)->SeeSound;
}
else
{

View file

@ -120,18 +120,12 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Saw)
}
int index = CheckIndex (4);
if (index >= 0)
{
fullsound = FSoundID(StateParameters[index]);
hitsound = FSoundID(StateParameters[index+1]);
damage = EvalExpressionI (StateParameters[index+2], self);
pufftype = PClass::FindClass ((ENamedName)StateParameters[index+3]);
}
else
{
fullsound = "weapons/sawfull";
hitsound = "weapons/sawhit";
}
if (index < 0) return;
fullsound = FSoundID(StateParameters[index]);
hitsound = FSoundID(StateParameters[index+1]);
damage = EvalExpressionI (StateParameters[index+2], self);
pufftype = PClass::FindClass ((ENamedName)StateParameters[index+3]);
if (pufftype == NULL) pufftype = PClass::FindClass(NAME_BulletPuff);
if (damage == 0) damage = 2;
@ -500,20 +494,17 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_BFGSpray)
AActor *linetarget;
int index = CheckIndex (3);
if (index >= 0)
{
spraytype = PClass::FindClass ((ENamedName)StateParameters[index]);
numrays = EvalExpressionI (StateParameters[index+1], self);
if (numrays <= 0)
numrays = 40;
damagecnt = EvalExpressionI (StateParameters[index+2], self);
if (damagecnt <= 0)
damagecnt = 15;
}
if (index < 0) return;
spraytype = PClass::FindClass ((ENamedName)StateParameters[index]);
if (spraytype == NULL)
{
spraytype = PClass::FindClass("BFGExtra");
}
numrays = EvalExpressionI (StateParameters[index+1], self);
if (numrays <= 0)
numrays = 40;
damagecnt = EvalExpressionI (StateParameters[index+2], self);
if (damagecnt <= 0)
damagecnt = 15;
// [RH] Don't crash if no target
if (!self->target)

View file

@ -46,14 +46,14 @@ void A_SkullAttack(AActor *self, fixed_t speed)
DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SkullAttack)
{
int n;
int n = 0;
int index = CheckIndex (1);
if (index >= 0)
{
n = FLOAT2FIXED(EvalExpressionF (StateParameters[index], self));
if (n == 0) n = SKULLSPEED;
}
else n = SKULLSPEED;
if (n == 0) n = SKULLSPEED;
A_SkullAttack(self, n);
}

View file

@ -2234,13 +2234,16 @@ enum ChaseFlags
DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Chase)
{
int index=CheckIndex(3);
if (index>=0)
if (index < 0) return;
if (StateParameters[index] != INT_MIN)
{
FState *melee = P_GetState(self, CallingState, StateParameters[index]);
FState *missile = P_GetState(self, CallingState, StateParameters[index+1]);
int flags = EvalExpressionI (StateParameters[index+2], self);
if (flags & CHF_RESURRECT && P_CheckForResurrection(self, false)) return;
FState *melee = P_GetState(self, CallingState, StateParameters[index]);
FState *missile = P_GetState(self, CallingState, StateParameters[index+1]);
A_DoChase(self, !!(flags&CHF_FASTCHASE), melee, missile, !(flags&CHF_NOPLAYACTIVE),
!!(flags&CHF_NIGHTMAREFAST), !!(flags&CHF_DONTMOVE));
@ -2271,7 +2274,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_ExtChase)
A_DoChase(self, false,
EvalExpressionI (StateParameters[index], self) ? self->MeleeState:NULL,
EvalExpressionI (StateParameters[index+1], self) ? self->MissileState:NULL,
EvalExpressionN (StateParameters[index+2], self),
!!EvalExpressionI (StateParameters[index+2], self),
!!EvalExpressionI (StateParameters[index+3], self), false);
}

View file

@ -910,8 +910,6 @@ FString FScanner::TokenName (int token, const char *string)
"'global'",
"'self'",
"'stop'",
"'eval'",
"'evalnot'",
"'pickup'",
"'breakable'",
"'projectile'",

File diff suppressed because it is too large Load diff

View file

@ -138,8 +138,6 @@ std2:
'stop' { RET(TK_Stop); }
/* Needed for decorate action functions */
'eval' { RET(TK_Eval); }
'evalnot' { RET(TK_EvalNot); }
'action' { RET(TK_Action); }
/* other DECORATE top level keywords */

View file

@ -146,6 +146,144 @@ void ParseEnum (FScanner &sc, PSymbolTable *symt, PClass *cls)
sc.MustGetToken(';');
}
//==========================================================================
//
// ParseParameter
//
// Parses aparameter - either a default in a function declaration
// or an argument in a function call.
//
//==========================================================================
int ParseParameter(FScanner &sc, PClass *cls, char type, bool constant)
{
int v;
switch(type)
{
case 'S':
case 's': // Sound name
sc.MustGetString();
return S_FindSound(sc.String);
case 'M':
case 'm': // Actor name
case 'T':
case 't': // String
sc.SetEscape(true);
sc.MustGetString();
sc.SetEscape(false);
return (int)(sc.String[0] ? FName(sc.String) : NAME_None);
case 'C':
case 'c': // Color
sc.MustGetString ();
if (sc.Compare("none"))
{
return -1;
}
else if (sc.Compare(""))
{
return 0;
}
else
{
int c = V_GetColor (NULL, sc.String);
// 0 needs to be the default so we have to mark the color.
return MAKEARGB(1, RPART(c), GPART(c), BPART(c));
}
case 'L':
case 'l':
{
if (JumpParameters.Size()==0) JumpParameters.Push(NAME_None);
v = -(int)JumpParameters.Size();
// This forces quotation marks around the state name.
sc.MustGetToken(TK_StringConst);
if (sc.String[0] == 0 || sc.Compare("None"))
{
return 0;
}
if (sc.Compare("*"))
{
if (constant) return INT_MIN;
else sc.ScriptError("Invalid state name '*'");
}
FString statestring = sc.String; // ParseStateString(sc);
const PClass *stype=NULL;
int scope = statestring.IndexOf("::");
if (scope >= 0)
{
FName scopename = FName(statestring, scope, false);
if (scopename == NAME_Super)
{
// Super refers to the direct superclass
scopename = cls->ParentClass->TypeName;
}
JumpParameters.Push(scopename);
statestring = statestring.Right(statestring.Len()-scope-2);
stype = PClass::FindClass (scopename);
if (stype == NULL)
{
sc.ScriptError ("%s is an unknown class.", scopename.GetChars());
}
if (!stype->IsDescendantOf (RUNTIME_CLASS(AActor)))
{
sc.ScriptError ("%s is not an actor class, so it has no states.", stype->TypeName.GetChars());
}
if (!stype->IsAncestorOf (cls))
{
sc.ScriptError ("%s is not derived from %s so cannot access its states.",
cls->TypeName.GetChars(), stype->TypeName.GetChars());
}
}
else
{
// No class name is stored. This allows 'virtual' jumps to
// labels in subclasses.
// It also means that the validity of the given state cannot
// be checked here.
JumpParameters.Push(NAME_None);
}
TArray<FName> names;
MakeStateNameList(statestring, &names);
if (stype != NULL)
{
if (!stype->ActorInfo->FindState(names.Size(), &names[0]))
{
sc.ScriptError("Jump to unknown state '%s' in class '%s'",
statestring.GetChars(), stype->TypeName.GetChars());
}
}
JumpParameters.Push((ENamedName)names.Size());
for(unsigned i=0;i<names.Size();i++)
{
JumpParameters.Push(names[i]);
}
// No offsets here. The point of jumping to labels is to avoid such things!
return v;
}
case 'X':
case 'x':
v = ParseExpression (sc, false, cls);
if (constant && !IsExpressionConst(v))
{
sc.ScriptError("Default parameter must be constant.");
}
return v;
default:
assert(false);
return -1;
}
}
//==========================================================================
//
// ActorActionDef
@ -158,12 +296,16 @@ void ParseEnum (FScanner &sc, PSymbolTable *symt, PClass *cls)
static void ParseActionDef (FScanner &sc, PClass *cls)
{
#define OPTIONAL 1
#define EVALNOT 4
enum
{
OPTIONAL = 1
};
AFuncDesc *afd;
FName funcname;
FString args;
TArray<int> DefaultParams;
bool hasdefaults = false;
if (sc.LumpNum == -1 || Wads.GetLumpFile(sc.LumpNum) > 0)
{
@ -189,15 +331,7 @@ static void ParseActionDef (FScanner &sc, PClass *cls)
// Retrieve flags before type name
for (;;)
{
if (sc.CheckToken(TK_Optional))
{
flags |= OPTIONAL;
}
else if (sc.CheckToken(TK_EvalNot))
{
flags |= EVALNOT;
}
else if (sc.CheckToken(TK_Coerce) || sc.CheckToken(TK_Native))
if (sc.CheckToken(TK_Coerce) || sc.CheckToken(TK_Native))
{
}
else
@ -212,7 +346,7 @@ static void ParseActionDef (FScanner &sc, PClass *cls)
case TK_Bool:
case TK_Int:
case TK_Float:
type = (flags & EVALNOT)? 'y' : 'x';
type = 'x';
break;
case TK_Sound: type = 's'; break;
@ -244,13 +378,24 @@ static void ParseActionDef (FScanner &sc, PClass *cls)
{
sc.UnGet();
}
int def;
if (sc.CheckToken('='))
{
hasdefaults = true;
flags|=OPTIONAL;
def = ParseParameter(sc, cls, type, true);
}
else
{
def = 0;
}
DefaultParams.Push(def);
if (!(flags & OPTIONAL) && type != '+')
{
type -= 'a' - 'A';
}
#undef OPTIONAL
#undef EVAL
#undef EVALNOT
args += type;
sc.MustGetAnyToken();
if (sc.TokenType != ',' && sc.TokenType != ')')
@ -265,7 +410,15 @@ static void ParseActionDef (FScanner &sc, PClass *cls)
sym->SymbolType = SYM_ActionFunction;
sym->Arguments = args;
sym->Function = afd->Function;
sym->defaultparameterindex = -1;
if (hasdefaults)
{
sym->defaultparameterindex = StateParameters.Size();
for(int i = 0; i < DefaultParams.Size(); i++) StateParameters.Push(DefaultParams[i]);
}
else
{
sym->defaultparameterindex = -1;
}
if (cls->Symbols.AddSymbol (sym) == NULL)
{
delete sym;

View file

@ -117,13 +117,14 @@ void FinishActor(FScanner &sc, FActorInfo *info, Baggage &bag);
void ParseConstant (FScanner &sc, PSymbolTable *symt, PClass *cls);
void ParseEnum (FScanner &sc, PSymbolTable *symt, PClass *cls);
int ParseParameter(FScanner &sc, PClass *cls, char type, bool constant);
int ParseExpression (FScanner &sc, bool _not, PClass *cls);
bool IsExpressionConst(int id);
int EvalExpressionI (int id, AActor *self, const PClass *cls=NULL);
float EvalExpressionF (int id, AActor *self, const PClass *cls=NULL);
bool EvalExpressionN (int id, AActor *self, const PClass *cls=NULL);
enum
@ -197,8 +198,6 @@ enum EDefinitionType
int var = EvalExpressionI(StateParameters[ap_index_++], self);
#define ACTION_PARAM_BOOL(var) \
bool var = !!EvalExpressionI(StateParameters[ap_index_++], self);
#define ACTION_PARAM_NOT_BOOL(var) \
bool var = EvalExpressionN(StateParameters[ap_index_++], self);
#define ACTION_PARAM_FIXED(var) \
fixed_t var = fixed_t(EvalExpressionF(StateParameters[ap_index_++], self)*65536.f);
#define ACTION_PARAM_FLOAT(var) \

View file

@ -386,7 +386,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_BulletAttack)
FState *P_GetState(AActor *self, FState *CallingState, int offset)
{
if (offset == 0)
if (offset == 0 || offset == INT_MIN)
{
return NULL; // 0 means 'no state'
}
@ -584,22 +584,24 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Explode)
bool alert;
int index=CheckIndex(4);
if (index>=0)
{
damage = EvalExpressionI (StateParameters[index], self);
distance = EvalExpressionI (StateParameters[index+1], self);
hurtSource = EvalExpressionN (StateParameters[index+2], self);
if (damage == 0) damage = 128;
if (distance == 0) distance = damage;
alert = !!EvalExpressionI (StateParameters[index+3], self);
}
else
if (index < 0) return;
damage = EvalExpressionI (StateParameters[index], self);
distance = EvalExpressionI (StateParameters[index+1], self);
hurtSource = !!EvalExpressionI (StateParameters[index+2], self);
alert = !!EvalExpressionI (StateParameters[index+3], self);
if (damage < 0) // get parameters from metadata
{
damage = self->GetClass()->Meta.GetMetaInt (ACMETA_ExplosionDamage, 128);
distance = self->GetClass()->Meta.GetMetaInt (ACMETA_ExplosionRadius, damage);
hurtSource = !self->GetClass()->Meta.GetMetaInt (ACMETA_DontHurtShooter);
alert = false;
}
else
{
if (distance <= 0) distance = damage;
}
P_RadiusAttack (self, self->target, damage, distance, self->DamageType, hurtSource);
if (self->z <= self->floorz + (distance<<FRACBITS))
@ -626,14 +628,14 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RadiusThrust)
bool affectSource = true;
int index=CheckIndex(3);
if (index>=0)
{
force = EvalExpressionI (StateParameters[index], self);
distance = EvalExpressionI (StateParameters[index+1], self);
affectSource = EvalExpressionN (StateParameters[index+2], self);
}
if (force == 0) force = 128;
if (distance == 0) distance = force;
if (index < 0) return;
force = EvalExpressionI (StateParameters[index], self);
distance = EvalExpressionI (StateParameters[index+1], self);
affectSource = !!EvalExpressionI (StateParameters[index+2], self);
if (force <= 0) force = 128;
if (distance <= 0) distance = force;
P_RadiusAttack (self, self->target, force, distance, self->DamageType, affectSource, false);
if (self->z <= self->floorz + (distance<<FRACBITS))
@ -865,7 +867,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomMeleeAttack)
int MeleeSound = StateParameters[index+1];
int MissSound = StateParameters[index+2];
ENamedName DamageType = (ENamedName)StateParameters[index+3];
bool bleed = EvalExpressionN (StateParameters[index+4], self);
bool bleed = !!EvalExpressionI (StateParameters[index+4], self);
if (DamageType==NAME_None) DamageType = NAME_Melee; // Melee is the default type
@ -900,7 +902,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomComboAttack)
int damage = EvalExpressionI (StateParameters[index+2], self);
int MeleeSound = StateParameters[index+3];
ENamedName DamageType = (ENamedName)StateParameters[index+4];
bool bleed = EvalExpressionN (StateParameters[index+5], self);
bool bleed = !!EvalExpressionI (StateParameters[index+5], self);
if (!self->target)
@ -975,7 +977,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FireBullets)
int NumberOfBullets=EvalExpressionI (StateParameters[index+2], self);
int DamagePerBullet=EvalExpressionI (StateParameters[index+3], self);
ENamedName PuffTypeName=(ENamedName)StateParameters[index+4];
bool UseAmmo=EvalExpressionN (StateParameters[index+5], self);
bool UseAmmo=!!EvalExpressionI (StateParameters[index+5], self);
fixed_t Range=fixed_t(EvalExpressionF (StateParameters[index+6], self) * FRACUNIT);
const PClass * PuffType;
@ -1035,7 +1037,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FireCustomMissile)
ENamedName MissileName=(ENamedName)StateParameters[index];
angle_t Angle=angle_t(EvalExpressionF (StateParameters[index+1], self) * ANGLE_1);
bool UseAmmo=EvalExpressionN (StateParameters[index+2], self);
bool UseAmmo=!!EvalExpressionI (StateParameters[index+2], self);
int SpawnOfs_XY=EvalExpressionI (StateParameters[index+3], self);
fixed_t SpawnHeight=fixed_t(EvalExpressionF (StateParameters[index+4], self) * FRACUNIT);
INTBOOL AimAtAngle=EvalExpressionI (StateParameters[index+5], self);
@ -1095,7 +1097,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomPunch)
int Damage=EvalExpressionI (StateParameters[index], self);
bool norandom=!!EvalExpressionI (StateParameters[index+1], self);
bool UseAmmo=EvalExpressionN (StateParameters[index+2], self);
bool UseAmmo=!!EvalExpressionI (StateParameters[index+2], self);
ENamedName PuffTypeName=(ENamedName)StateParameters[index+3];
fixed_t Range=fixed_t(EvalExpressionF (StateParameters[index+4], self) * FRACUNIT);
@ -1152,7 +1154,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RailAttack)
int Damage=EvalExpressionI (StateParameters[index], self);
int Spawnofs_XY=EvalExpressionI (StateParameters[index+1], self);
bool UseAmmo=EvalExpressionN (StateParameters[index+2], self);
bool UseAmmo=!!EvalExpressionI (StateParameters[index+2], self);
int Color1=StateParameters[index+3];
int Color2=StateParameters[index+4];
bool Silent=!!EvalExpressionI (StateParameters[index+5], self);
@ -1426,7 +1428,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SpawnItem)
const PClass * missile= PClass::FindClass((ENamedName)StateParameters[index]);
fixed_t distance = fixed_t(EvalExpressionF (StateParameters[index+1], self) * FRACUNIT);
fixed_t zheight = fixed_t(EvalExpressionF (StateParameters[index+2], self) * FRACUNIT);
bool useammo = EvalExpressionN (StateParameters[index+3], self);
bool useammo = !!EvalExpressionI (StateParameters[index+3], self);
INTBOOL transfer_translation = EvalExpressionI (StateParameters[index+4], self);
if (!missile)
@ -1554,7 +1556,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_ThrowGrenade)
fixed_t zheight = fixed_t(EvalExpressionF (StateParameters[index+1], self) * FRACUNIT);
fixed_t xymom = fixed_t(EvalExpressionF (StateParameters[index+2], self) * FRACUNIT);
fixed_t zmom = fixed_t(EvalExpressionF (StateParameters[index+3], self) * FRACUNIT);
bool useammo = EvalExpressionN (StateParameters[index+4], self);
bool useammo = !!EvalExpressionI (StateParameters[index+4], self);
if (self->player && CallingState != self->state && (pStateCall==NULL || CallingState != pStateCall->State))
{
@ -2046,7 +2048,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Respawn)
self->renderflags &= ~RF_INVISIBLE;
int index=CheckIndex(1);
if (index<0 || EvalExpressionN (StateParameters[index], self))
if (index<0 || EvalExpressionI (StateParameters[index], self))
{
Spawn<ATeleportFog> (x, y, self->z + TELEFOGHEIGHT, ALLOW_REPLACE);
}
@ -2125,6 +2127,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_ClearTarget)
DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfTargetInLOS)
{
int index = CheckIndex(3);
if (index < 0) return;
angle_t an;
angle_t fov = angle_t(EvalExpressionF (StateParameters[index+1], self) * ANGLE_1);
INTBOOL projtarg = EvalExpressionI (StateParameters[index+2], self);

View file

@ -404,15 +404,6 @@ int ParseExpression (FScanner &sc, bool _not, PClass *cls)
ExpData *data = ParseExpressionM (sc, cls);
if (_not)
{
ExpData *tmp = data;
data = new ExpData;
data->Type = EX_Not;
data->Children[0] = tmp;
data->EvalConst (cls);
}
for (unsigned int i = 0; i < StateExpressions.Size (); i++)
{
if (StateExpressions[i]->Compare (data))
@ -666,6 +657,24 @@ static ExpData *ParseExpressionA (FScanner &sc, const PClass *cls)
sc.MustGetToken(')');
return data;
}
else if (sc.CheckToken(TK_True))
{
ExpData *data = new ExpData;
data->Type = EX_Const;
data->Value.Type = VAL_Int;
data->Value.Int = 1;
return data;
}
else if (sc.CheckToken(TK_False))
{
ExpData *data = new ExpData;
data->Type = EX_Const;
data->Value.Type = VAL_Int;
data->Value.Int = 0;
return data;
}
else if (sc.CheckToken(TK_IntConst))
{
ExpData *data = new ExpData;
@ -895,6 +904,13 @@ static ExpData *ParseExpressionA (FScanner &sc, const PClass *cls)
// [GRB] Evaluates previously stored expression
//
bool IsExpressionConst(int id)
{
if (StateExpressions.Size() <= (unsigned int)id) return false;
return StateExpressions[id]->Type == EX_Const;
}
int EvalExpressionI (int id, AActor *self, const PClass *cls)
{
if (StateExpressions.Size() <= (unsigned int)id) return 0;
@ -916,11 +932,6 @@ int EvalExpressionI (int id, AActor *self, const PClass *cls)
}
}
bool EvalExpressionN(int id, AActor *self, const PClass *cls)
{
return !EvalExpressionI(id, self, cls);
}
float EvalExpressionF (int id, AActor *self, const PClass *cls)
{
if (StateExpressions.Size() <= (unsigned int)id) return 0.f;

View file

@ -459,6 +459,7 @@ static void HandleDeprecatedFlags(AActor *defaults, bool set, int index)
DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_ChangeFlag)
{
int index=CheckIndex(2);
if (index < 0) return;
const char * flagname = FName((ENamedName)StateParameters[index]).GetChars();
int expression = EvalExpressionI (StateParameters[index+1], self);

View file

@ -690,151 +690,40 @@ do_stop:
int paramstart = paramindex;
bool varargs = params[numparams - 1] == '+';
if (varargs)
{
StateParameters[paramindex++] = 0;
}
else if (afd->defaultparameterindex > -1)
{
memcpy(&StateParameters[paramindex], &StateParameters[afd->defaultparameterindex],
afd->Arguments.Len() * sizeof (StateParameters[0]));
}
while (*params)
{
switch(*params)
if ((*params == 'l' || *params == 'L') && sc.CheckNumber())
{
case 'S':
case 's': // Sound name
sc.MustGetString();
v = S_FindSound(sc.String);
break;
case 'M':
case 'm': // Actor name
case 'T':
case 't': // String
sc.SetEscape(true);
sc.MustGetString();
sc.SetEscape(false);
v = (int)(sc.String[0] ? FName(sc.String) : NAME_None);
break;
case 'L':
case 'l': // Jump label
if (sc.CheckNumber())
// Special case: State label as an offset
if (sc.Number > 0 && strlen(statestring)>0)
{
if (sc.Number > 0 && strlen(statestring)>0)
{
sc.ScriptError("You cannot use state jumps commands with a jump offset on multistate definitions\n");
}
v=sc.Number;
if (v<0)
{
sc.ScriptError("Negative jump offsets are not allowed");
}
{
int minreq=count+v;
if (minreq>minrequiredstate) minrequiredstate=minreq;
}
}
else
{
if (JumpParameters.Size()==0) JumpParameters.Push(NAME_None);
v = -(int)JumpParameters.Size();
// This forces quotation marks around the state name.
sc.MustGetToken(TK_StringConst);
if (sc.String[0] == 0 || sc.Compare("None"))
{
v = 0; // an empty string means 'no state'.
break;
}
FString statestring = sc.String; // ParseStateString(sc);
const PClass *stype=NULL;
int scope = statestring.IndexOf("::");
if (scope >= 0)
{
FName scopename = FName(statestring, scope, false);
if (scopename == NAME_Super)
{
// Super refers to the direct superclass
scopename = actor->Class->ParentClass->TypeName;
}
JumpParameters.Push(scopename);
statestring = statestring.Right(statestring.Len()-scope-2);
stype = PClass::FindClass (scopename);
if (stype == NULL)
{
sc.ScriptError ("%s is an unknown class.", scopename.GetChars());
}
if (!stype->IsDescendantOf (RUNTIME_CLASS(AActor)))
{
sc.ScriptError ("%s is not an actor class, so it has no states.", stype->TypeName.GetChars());
}
if (!stype->IsAncestorOf (actor->Class))
{
sc.ScriptError ("%s is not derived from %s so cannot access its states.",
actor->Class->TypeName.GetChars(), stype->TypeName.GetChars());
}
}
else
{
// No class name is stored. This allows 'virtual' jumps to
// labels in subclasses.
// It also means that the validity of the given state cannot
// be checked here.
JumpParameters.Push(NAME_None);
}
TArray<FName> names;
MakeStateNameList(statestring, &names);
if (stype != NULL)
{
if (!stype->ActorInfo->FindState(names.Size(), &names[0]))
{
sc.ScriptError("Jump to unknown state '%s' in class '%s'",
statestring.GetChars(), stype->TypeName.GetChars());
}
}
JumpParameters.Push((ENamedName)names.Size());
for(unsigned i=0;i<names.Size();i++)
{
JumpParameters.Push(names[i]);
}
// No offsets here. The point of jumping to labels is to avoid such things!
sc.ScriptError("You cannot use state jumps commands with a jump offset on multistate definitions\n");
}
break;
case 'C':
case 'c': // Color
sc.MustGetString ();
if (sc.Compare("none"))
v=sc.Number;
if (v<0)
{
v = -1;
sc.ScriptError("Negative jump offsets are not allowed");
}
else
{
int c = V_GetColor (NULL, sc.String);
// 0 needs to be the default so we have to mark the color.
v = MAKEARGB(1, RPART(c), GPART(c), BPART(c));
}
break;
case 'X':
case 'x':
v = ParseExpression (sc, false, bag.Info->Class);
break;
case 'Y':
case 'y':
v = ParseExpression (sc, true, bag.Info->Class);
break;
default:
assert(false);
v = -1;
break;
int minreq=count+v;
if (minreq>minrequiredstate) minrequiredstate=minreq;
}
else
{
// Use the generic parameter parser for everything else
v = ParseParameter(sc, bag.Info->Class, *params, false);
}
StateParameters[paramindex++] = v;
params++;

View file

@ -19,12 +19,12 @@ ACTOR Actor native //: Thinker
Gravity 1
action native A_MonsterRail();
action native A_BFGSpray(optional class<Actor> spraytype, optional int numrays, optional int damagecount);
action native A_BFGSpray(class<Actor> spraytype = "BFGSpray", int numrays = 40, int damagecount = 15);
action native A_Pain();
action native A_NoBlocking();
action native A_XScream();
action native A_Look();
action native A_Chase(optional state melee, optional state missile, optional int flags);
action native A_Chase(state melee = "*", state missile = "none", int flags = 0);
action native A_FaceTarget();
action native A_PosAttack();
action native A_Scream();
@ -42,9 +42,9 @@ ACTOR Actor native //: Thinker
action native A_SkelFist();
action native A_SkelMissile();
action native A_FatRaise();
action native A_FatAttack1(optional class<Actor> spawntype);
action native A_FatAttack2(optional class<Actor> spawntype);
action native A_FatAttack3(optional class<Actor> spawntype);
action native A_FatAttack1(class<Actor> spawntype = "FatShot");
action native A_FatAttack2(class<Actor> spawntype = "FatShot");
action native A_FatAttack3(class<Actor> spawntype = "FatShot");
action native A_BossDeath();
action native A_CPosAttack();
action native A_CPosRefire();
@ -52,28 +52,28 @@ ACTOR Actor native //: Thinker
action native A_SargAttack();
action native A_HeadAttack();
action native A_BruisAttack();
action native A_SkullAttack(optional float speed);
action native A_SkullAttack(float speed = 20);
action native A_Metal();
action native A_SpidRefire();
action native A_BabyMetal();
action native A_BspiAttack();
action native A_Hoof();
action native A_CyberAttack();
action native A_PainAttack(optional class<Actor> spawntype);
action native A_DualPainAttack(optional class<Actor> spawntype);
action native A_PainDie(optional class<Actor> spawntype);
action native A_PainAttack(class<Actor> spawntype = "LostSoul");
action native A_DualPainAttack(class<Actor> spawntype = "LostSoul");
action native A_PainDie(class<Actor> spawntype = "LostSoul");
action native A_KeenDie();
action native A_BrainPain();
action native A_BrainScream();
action native A_BrainDie();
action native A_BrainAwake();
action native A_BrainSpit(optional class<Actor> spawntype);
action native A_BrainSpit(class<Actor> spawntype = "none"); // needs special treatment for default
action native A_SpawnSound();
action native A_SpawnFly(optional class<Actor> spawntype);
action native A_SpawnFly(class<Actor> spawntype = "none"); // needs special treatment for default
action native A_BrainExplode();
action native A_Die(optional name damagetype);
action native A_Die(name damagetype = "none");
action native A_Detonate();
action native A_Mushroom(optional class<Actor> spawntype, optional int numspawns);
action native A_Mushroom(class<Actor> spawntype = "FatShot", int numspawns = 0);
action native A_SetFloorClip();
action native A_UnSetFloorClip();
@ -112,7 +112,7 @@ ACTOR Actor native //: Thinker
action native A_BishopMissileWeave();
action native A_CStaffMissileSlither();
action native A_PlayerScream();
action native A_SkullPop(optional class<Actor> skulltype);
action native A_SkullPop(class<Actor> skulltype = "BloodySkull");
action native A_CheckPlayerDone();
action native A_Wander();
@ -141,29 +141,29 @@ ACTOR Actor native //: Thinker
action native A_FLoopActiveSound();
action native A_LoopActiveSound();
action native A_StopSound();
action native A_PlaySoundEx(sound whattoplay, coerce name slot, optional bool looping, optional int attenuation);
action native A_PlaySoundEx(sound whattoplay, coerce name slot, bool looping = false, int attenuation = 0);
action native A_StopSoundEx(coerce name slot);
action native A_SeekerMissile(int threshold, int turnmax);
action native A_Jump(int chance, state label, ...);
action native A_CustomMissile(class<Actor> missiletype, float spawnheight, int spawnofs_xy, optional float angle, optional int flags, optional float pitch);
action native A_CustomBulletAttack(float spread_xy, float spread_z, int numbullets, int damageperbullet, optional class<Actor> pufftype, optional float range, optional bool aimfacing);
action native A_CustomRailgun(int damage, optional int spawnofs_xy, optional color color1, optional color color2, optional bool silent, optional bool aim, optional float maxdiff, optional class<Actor> pufftype);
action native A_CustomMissile(class<Actor> missiletype, float spawnheight = 32, int spawnofs_xy = 0, float angle = 0, int flags = 0, float pitch = 0);
action native A_CustomBulletAttack(float spread_xy, float spread_z, int numbullets, int damageperbullet, class<Actor> pufftype = "BulletPuff", float range = 0, bool aimfacing = false);
action native A_CustomRailgun(int damage, int spawnofs_xy = 0, color color1 = "", color color2 = "", bool silent = false, bool aim = false, float maxdiff = 0, class<Actor> pufftype = "BulletPuff");
action native A_JumpIfHealthLower(int health, state label);
action native A_JumpIfCloser(float distance, state label);
action native A_JumpIfInventory(class<Inventory> itemtype, int itemamount, state label);
action native A_GiveInventory(class<Inventory> itemtype, optional int amount);
action native A_TakeInventory(class<Inventory> itemtype, optional int amount);
action native A_SpawnItem(class<Actor> itemtype, optional float distance, optional float zheight, optional evalnot bool useammo, optional bool transfer_translation);
action native A_SpawnItemEx(class<Actor> itemtype, optional float xofs, optional float yofs, optional float zofs, optional float xmom, optional float ymom, optional float zmom, optional float angle, optional int flags, optional int chance);
action native A_Print(string whattoprint, optional float time, optional string fontname);
action native A_SetTranslucent(float alpha, optional int style);
action native A_FadeIn(optional float reduce);
action native A_FadeOut(optional float reduce);
action native A_SpawnDebris(class<Actor> spawntype, optional bool transfer_translation, optional float mult_h, optional float mult_v);
action native A_GiveInventory(class<Inventory> itemtype, int amount = 0);
action native A_TakeInventory(class<Inventory> itemtype, int amount = 0);
action native A_SpawnItem(class<Actor> itemtype, float distance = 0, float zheight = 0, bool useammo = true, bool transfer_translation = false);
action native A_SpawnItemEx(class<Actor> itemtype, float xofs = 0, float yofs = 0, float zofs = 0, float xmom = 0, float ymom = 0, float zmom = 0, float angle = 0, int flags = 0, int failchance = 0);
action native A_Print(string whattoprint, float time = 0, string fontname = "");
action native A_SetTranslucent(float alpha, int style = 0);
action native A_FadeIn(float reduce = 0.1);
action native A_FadeOut(float reduce = 0.1);
action native A_SpawnDebris(class<Actor> spawntype, bool transfer_translation = false, float mult_h = 1, float mult_v = 1);
action native A_CheckSight(state label);
action native A_ExtChase(bool usemelee, bool usemissile, optional evalnot bool playactive, optional bool nightmarefast);
action native A_ExtChase(bool usemelee, bool usemissile, bool playactive = true, bool nightmarefast = false);
action native A_DropInventory(class<Inventory> itemtype);
action native A_SetBlend(color color1, float alpha, int tics, optional color color2);
action native A_SetBlend(color color1, float alpha, int tics, color color2 = "");
action native A_ChangeFlag(string flagname, bool value);
action native A_JumpIf(bool expression, state label);
action native A_KillMaster();
@ -171,28 +171,28 @@ ACTOR Actor native //: Thinker
action native A_CheckFloor(state label);
action native A_PlayerSkinCheck(state label);
action native A_BasicAttack(int meleedamage, sound meleesound, class<actor> missiletype, float missileheight);
action native A_ThrowGrenade(class<Actor> itemtype, optional float zheight, optional float xymom, optional float zmom, optional evalnot bool useammo);
action native A_ThrowGrenade(class<Actor> itemtype, float zheight = 0, float xymom = 0, float zmom = 0, bool useammo = true);
action native A_Recoil(float xymom);
action native A_JumpIfInTargetInventory(class<Inventory> itemtype, int amount, state label);
action native A_GiveToTarget(class<Inventory> itemtype, optional int amount);
action native A_TakeFromTarget(class<Inventory> itemtype, optional int amount);
action native A_GiveToTarget(class<Inventory> itemtype, int amount = 0);
action native A_TakeFromTarget(class<Inventory> itemtype, int amount = 0);
action native A_CountdownArg(int argnum);
action native A_CustomMeleeAttack(int damage, optional sound meleesound, optional sound misssound, optional name damagetype, optional evalnot bool bleed);
action native A_CustomComboAttack(class<Actor> missiletype, float spawnheight, int damage, optional sound meleesound, optional name damagetype, optional evalnot bool bleed);
action native A_CustomMeleeAttack(int damage, sound meleesound = "", sound misssound = "", name damagetype = "none", bool bleed = true);
action native A_CustomComboAttack(class<Actor> missiletype, float spawnheight, int damage, sound meleesound = "", name damagetype = "none", bool bleed = true);
action native A_Burst(class<Actor> chunktype);
action native A_RadiusThrust(optional int force, optional int distance, optional evalnot bool affectsource);
action native A_Explode(optional int damage, optional int distance, optional evalnot bool hurtsource, optional bool alert);
action native A_RadiusThrust(int force = 128, int distance = -1, bool affectsource = true);
action native A_Explode(int damage = -1, int distance = -1, bool hurtsource = true, bool alert = false);
action native A_Stop();
action native A_Respawn(optional evalnot bool fog);
action native A_Respawn(bool fog = true);
action native A_BarrelDestroy();
action native A_QueueCorpse();
action native A_DeQueueCorpse();
action native A_LookEx(optional int flags, optional float minseedist, optional float maxseedist, optional float maxheardist, optional float fov, optional state label);
action native A_LookEx(int flags = 0, float minseedist = 0, float maxseedist = 0, float maxheardist = 0, float fov = 0, state label = "");
action native A_ClearTarget();
action native A_JumpIfTargetInLOS (state label, optional float fov, optional bool projectiletarget);
action native A_DamageMaster(int amount, optional name damagetype);
action native A_DamageChildren(int amount, optional name damagetype);
action native A_JumpIfTargetInLOS (state label, float fov = 0, bool projectiletarget = false);
action native A_DamageMaster(int amount, name damagetype = "none");
action native A_DamageChildren(int amount, name damagetype = "none");
action native A_SelectWeapon(class<Weapon> whichweapon);
action native A_Punch();
action native A_Feathers();

View file

@ -30,7 +30,7 @@ ACTOR CustomBridge 9991 native
Height 2
RenderStyle None
action native A_BridgeInit(optional class<Actor> balltype);
action native A_BridgeInit(class<Actor> balltype = "BridgeBall");
states
{

View file

@ -6,10 +6,10 @@ ACTOR Inventory native
Inventory.PickupSound "misc/i_pkup"
action native A_JumpIfNoAmmo(state label);
action native A_CustomPunch(int damage, optional bool norandom, optional evalnot bool useammo, optional class<Actor> pufftype, optional float range);
action native A_FireBullets(float spread_xy, float spread_z, int numbullets, int damageperbullet, optional class<Actor> pufftype, optional evalnot bool useammo, optional float range);
action native A_FireCustomMissile(class<Actor> missiletype, optional float angle, optional evalnot bool useammo, optional int spawnofs_xy, optional float spawnheight, optional bool aimatangle);
action native A_RailAttack(int damage, optional int spawnofs_xy, optional evalnot int useammo, optional color color1, optional color color2, optional bool silent, optional float maxdiff, optional class<Actor> pufftype);
action native A_CustomPunch(int damage, bool norandom = false, bool useammo = true, class<Actor> pufftype = "BulletPuff", float range = 0);
action native A_FireBullets(float spread_xy, float spread_z, int numbullets, int damageperbullet, class<Actor> pufftype = "BulletPuff", bool useammo = true, float range = 0);
action native A_FireCustomMissile(class<Actor> missiletype, float angle = 0, bool useammo = true, int spawnofs_xy = 0, float spawnheight = 0, bool aimatangle = false);
action native A_RailAttack(int damage, int spawnofs_xy = 0, int useammo = true, color color1 = "", color color2 = "", bool silent = false, float maxdiff = 0, class<Actor> pufftype = "BulletPuff");
action native A_Light(int extralight);
action native A_Light0();
action native A_Light1();
@ -37,7 +37,7 @@ ACTOR Inventory native
action native A_ClearReFire();
action native A_CheckReload();
action native A_GunFlash();
action native A_Saw(optional coerce sound fullsound, optional coerce sound hitsound, optional int damage, optional class<Actor> pufftype);
action native A_Saw(sound fullsound = "misc/sawfull", sound hitsound = "misc/sawhit", int damage = 2, class<Actor> pufftype = "BulletPuff");
action native A_CheckForReload(int counter, state label);
action native A_ResetReloadCounter();
action native A_RestoreSpecialPosition();

View file

@ -1,5 +1,5 @@
ACTOR SpecialSpot native
{
action native A_SpawnSingleItem(class<Actor> type, optional int fail_sp, optional int fail_co, optional int fail_dm);
action native A_SpawnSingleItem(class<Actor> type, int fail_sp = 0, int fail_co = 0, int fail_dm = 0);
}