mirror of
https://github.com/ZDoom/gzdoom-gles.git
synced 2024-11-28 15:02:39 +00:00
- Significant A_RadiusGive update.
- Added filter and species parameter. - Added new flags: RGF_INCLUSIVE, RGF_ITEMS, RGF_KILLED, RGF_EXFILTER, RGF_EXSPECIES, and RGF_EITHER. - RGF_ITEMS: Items can receive inventory. - RGF_KILLED: Actors who are truly dead might not be corpses, and vice versa. - RGF_EXFILTER: Blacklists the specified actor filter. All but the filtered actor can receive the item. - RGF_EXSPECIES: Blacklists the specified species. All but the filtered species can receive the item. - RGF_EITHER: The actor can receive the item if it satisfies either the filter or the species. Only useful when both are used. - RGF_INCLUSIVE: An actor marked as more than one pointer to the calling actor can ignore the exclusion pointers, but only if at least one is missing. I.e. an actor who is a target and tracer of the calling actor can still receive the item, if the calling actor doesn't pass RGF_NOTARGET and NOTRACER at the same time. RGF_INCLUSIVE only works with the pointer filtering flags. By default, if not specified, the actor will not be loopholed the item if they are under any one of the three filters. - Fixed discrepancies and dependencies upon several flags and actor conditions which caused the function to fail.
This commit is contained in:
parent
7be6041f57
commit
b4f05ee89b
3 changed files with 121 additions and 108 deletions
|
@ -4948,12 +4948,25 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, ACS_NamedTerminate)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static bool DoCheckSpecies(AActor *mo, FName filterSpecies, bool exclude)
|
||||||
|
{
|
||||||
|
FName actorSpecies = mo->GetSpecies();
|
||||||
|
if (filterSpecies == NAME_None) return true;
|
||||||
|
return exclude ? (actorSpecies != filterSpecies) : (actorSpecies == filterSpecies);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool DoCheckClass(AActor *mo, const PClass *filterClass, bool exclude)
|
||||||
|
{
|
||||||
|
const PClass *actorClass = mo->GetClass();
|
||||||
|
if (filterClass == NULL) return true;
|
||||||
|
return exclude ? (actorClass != filterClass) : (actorClass == filterClass);
|
||||||
|
}
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
//
|
//
|
||||||
// A_RadiusGive
|
// A_RadiusGive(item, distance, flags, amount, filter, species)
|
||||||
//
|
//
|
||||||
// Uses code roughly similar to A_Explode (but without all the compatibility
|
// Uses code roughly similar to A_Explode (but without all the compatibility
|
||||||
// baggage and damage computation code to give an item to all eligible mobjs
|
// baggage and damage computation code) to give an item to all eligible mobjs
|
||||||
// in range.
|
// in range.
|
||||||
//
|
//
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
@ -4972,21 +4985,30 @@ enum RadiusGiveFlags
|
||||||
RGF_CUBE = 1 << 9,
|
RGF_CUBE = 1 << 9,
|
||||||
RGF_NOSIGHT = 1 << 10,
|
RGF_NOSIGHT = 1 << 10,
|
||||||
RGF_MISSILES = 1 << 11,
|
RGF_MISSILES = 1 << 11,
|
||||||
|
RGF_INCLUSIVE = 1 << 12,
|
||||||
|
RGF_ITEMS = 1 << 13,
|
||||||
|
RGF_KILLED = 1 << 14,
|
||||||
|
RGF_EXFILTER = 1 << 15,
|
||||||
|
RGF_EXSPECIES = 1 << 16,
|
||||||
|
RGF_EITHER = 1 << 17,
|
||||||
};
|
};
|
||||||
|
|
||||||
DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RadiusGive)
|
DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RadiusGive)
|
||||||
{
|
{
|
||||||
ACTION_PARAM_START(7);
|
ACTION_PARAM_START(6);
|
||||||
ACTION_PARAM_CLASS(item, 0);
|
ACTION_PARAM_CLASS(item, 0);
|
||||||
ACTION_PARAM_FIXED(distance, 1);
|
ACTION_PARAM_FIXED(distance, 1);
|
||||||
ACTION_PARAM_INT(flags, 2);
|
ACTION_PARAM_INT(flags, 2);
|
||||||
ACTION_PARAM_INT(amount, 3);
|
ACTION_PARAM_INT(amount, 3);
|
||||||
|
ACTION_PARAM_CLASS(filter, 4);
|
||||||
|
ACTION_PARAM_NAME(species, 5);
|
||||||
|
|
||||||
// We need a valid item, valid targets, and a valid range
|
// We need a valid item, valid targets, and a valid range
|
||||||
if (item == NULL || (flags & RGF_MASK) == 0 || distance <= 0)
|
if (item == NULL || (flags & RGF_MASK) == 0 || !flags || distance <= 0)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (amount == 0)
|
if (amount == 0)
|
||||||
{
|
{
|
||||||
amount = 1;
|
amount = 1;
|
||||||
|
@ -4997,108 +5019,107 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RadiusGive)
|
||||||
AActor *thing;
|
AActor *thing;
|
||||||
while ((thing = it.Next()))
|
while ((thing = it.Next()))
|
||||||
{
|
{
|
||||||
// Don't give to inventory items
|
//[MC] Check for a filter, species, and the related exfilter/expecies/either flag(s).
|
||||||
if (thing->flags & MF_SPECIAL)
|
bool filterpass = DoCheckClass(thing, filter, !!(flags & RGF_EXFILTER)),
|
||||||
|
speciespass = DoCheckSpecies(thing, species, !!(flags & RGF_EXSPECIES));
|
||||||
|
|
||||||
|
if ((flags & RGF_EITHER) ? (!(filterpass || speciespass)) : (!(filterpass && speciespass)))
|
||||||
{
|
{
|
||||||
continue;
|
if (thing != self) //Don't let filter and species obstruct RGF_GIVESELF.
|
||||||
}
|
|
||||||
// Avoid giving to self unless requested
|
|
||||||
if (thing == self && !(flags & RGF_GIVESELF))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
// Avoiding special pointers if requested
|
|
||||||
if (((thing == self->target) && (flags & RGF_NOTARGET)) ||
|
|
||||||
((thing == self->tracer) && (flags & RGF_NOTRACER)) ||
|
|
||||||
((thing == self->master) && (flags & RGF_NOMASTER)))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
// Don't give to dead thing unless requested
|
|
||||||
if (thing->flags & MF_CORPSE)
|
|
||||||
{
|
|
||||||
if (!(flags & RGF_CORPSES))
|
|
||||||
{
|
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (thing->health <= 0 || thing->flags6 & MF6_KILLED)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
// Players, monsters, and other shootable objects
|
|
||||||
if (thing->player)
|
|
||||||
{
|
|
||||||
if ((thing->player->mo == thing) && !(flags & RGF_PLAYERS))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if ((thing->player->mo != thing) && !(flags & RGF_VOODOO))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (thing->flags3 & MF3_ISMONSTER)
|
|
||||||
{
|
|
||||||
if (!(flags & RGF_MONSTERS))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (thing->flags & MF_SHOOTABLE || thing->flags6 & MF6_VULNERABLE)
|
|
||||||
{
|
|
||||||
if (!(flags & RGF_OBJECTS))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (thing->flags & MF_MISSILE)
|
|
||||||
{
|
|
||||||
if (!(flags & RGF_MISSILES))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (flags & RGF_CUBE)
|
if (thing == self)
|
||||||
{ // check if inside a cube
|
{
|
||||||
if (fabs((double)thing->x - self->x) > (double)distance ||
|
if (!(flags & RGF_GIVESELF))
|
||||||
fabs((double)thing->y - self->y) > (double)distance ||
|
|
||||||
fabs((double)(thing->z + thing->height/2) - (self->z + self->height/2)) > (double)distance)
|
|
||||||
{
|
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{ // check if inside a sphere
|
//Check for target, master, and tracer flagging.
|
||||||
TVector3<double> tpos(thing->x, thing->y, thing->z + thing->height/2);
|
bool targetPass = true;
|
||||||
TVector3<double> spos(self->x, self->y, self->z + self->height/2);
|
bool masterPass = true;
|
||||||
if ((tpos - spos).LengthSquared() > distsquared)
|
bool tracerPass = true;
|
||||||
{
|
bool ptrPass = false;
|
||||||
|
if ((thing != self) && (flags & (RGF_NOTARGET | RGF_NOMASTER | RGF_NOTRACER)))
|
||||||
|
{
|
||||||
|
if ((thing == self->target) && (flags & RGF_NOTARGET))
|
||||||
|
targetPass = false;
|
||||||
|
if ((thing == self->master) && (flags & RGF_NOMASTER))
|
||||||
|
masterPass = false;
|
||||||
|
if ((thing == self->tracer) && (flags & RGF_NOTRACER))
|
||||||
|
tracerPass = false;
|
||||||
|
|
||||||
|
ptrPass = (flags & RGF_INCLUSIVE) ? (targetPass || masterPass || tracerPass) : (targetPass && masterPass && tracerPass);
|
||||||
|
|
||||||
|
//We should not care about what the actor is here. It's safe to abort this actor.
|
||||||
|
if (!ptrPass)
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Next, actor flag checking.
|
||||||
|
bool selfPass = !!((flags & RGF_GIVESELF) && thing == self);
|
||||||
|
bool corpsePass = !!((flags & RGF_CORPSES) && thing->flags & MF_CORPSE);
|
||||||
|
bool killedPass = !!((flags & RGF_KILLED) && thing->flags6 & MF6_KILLED);
|
||||||
|
bool monsterPass = !!((flags & RGF_MONSTERS) && thing->flags3 & MF3_ISMONSTER);
|
||||||
|
bool objectPass = !!((flags & RGF_OBJECTS) && ((thing->flags & MF_SHOOTABLE) || (thing->flags6 & MF6_VULNERABLE)));
|
||||||
|
bool playerPass = !!((flags & RGF_PLAYERS) && thing->player->mo == thing);
|
||||||
|
bool voodooPass = !!((flags & RGF_VOODOO) && thing->player->mo != thing);
|
||||||
|
//Self calls priority over the rest of this.
|
||||||
|
if (!selfPass)
|
||||||
|
{
|
||||||
|
//If it's specifically a monster/object/player/voodoo... Can be either or...
|
||||||
|
if (monsterPass || objectPass || playerPass || voodooPass)
|
||||||
|
{
|
||||||
|
//...and is dead, without desire to give to the dead...
|
||||||
|
if (((thing->health <= 0) && !(corpsePass || killedPass)))
|
||||||
|
{
|
||||||
|
//Skip!
|
||||||
|
continue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((flags & RGF_NOSIGHT) || P_CheckSight (thing, self, SF_IGNOREVISIBILITY|SF_IGNOREWATERBOUNDARY))
|
bool itemPass = !!((flags & RGF_ITEMS) && thing->flags & MF_SPECIAL);
|
||||||
{ // OK to give; target is in direct path, or the monster doesn't care about it being in line of sight.
|
bool missilePass = !!((flags & RGF_MISSILES) && thing->flags & MF_MISSILE);
|
||||||
AInventory *gift = static_cast<AInventory *>(Spawn (item, 0, 0, 0, NO_REPLACE));
|
|
||||||
if (gift->IsKindOf(RUNTIME_CLASS(AHealth)))
|
if (selfPass || monsterPass || corpsePass || killedPass || itemPass || objectPass || missilePass || playerPass || voodooPass)
|
||||||
{
|
{
|
||||||
gift->Amount *= amount;
|
if (flags & RGF_CUBE)
|
||||||
|
{ // check if inside a cube
|
||||||
|
if (fabs((double)thing->x - self->x) > (double)distance ||
|
||||||
|
fabs((double)thing->y - self->y) > (double)distance ||
|
||||||
|
fabs((double)(thing->z + thing->height / 2) - (self->z + self->height / 2)) > (double)distance)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{ // check if inside a sphere
|
||||||
gift->Amount = amount;
|
TVector3<double> tpos(thing->x, thing->y, thing->z + thing->height / 2);
|
||||||
|
TVector3<double> spos(self->x, self->y, self->z + self->height / 2);
|
||||||
|
if ((tpos - spos).LengthSquared() > distsquared)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
gift->flags |= MF_DROPPED;
|
|
||||||
gift->ClearCounters();
|
if ((flags & RGF_NOSIGHT) || P_CheckSight(thing, self, SF_IGNOREVISIBILITY | SF_IGNOREWATERBOUNDARY))
|
||||||
if (!gift->CallTryPickup (thing))
|
{ // OK to give; target is in direct path, or the monster doesn't care about it being in line of sight.
|
||||||
{
|
AInventory *gift = static_cast<AInventory *>(Spawn(item, 0, 0, 0, NO_REPLACE));
|
||||||
gift->Destroy ();
|
if (gift->IsKindOf(RUNTIME_CLASS(AHealth)))
|
||||||
|
{
|
||||||
|
gift->Amount *= amount;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
gift->Amount = amount;
|
||||||
|
}
|
||||||
|
gift->flags |= MF_DROPPED;
|
||||||
|
gift->ClearCounters();
|
||||||
|
if (!gift->CallTryPickup(thing))
|
||||||
|
{
|
||||||
|
gift->Destroy();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5184,20 +5205,6 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetSpeed)
|
||||||
ref->Speed = speed;
|
ref->Speed = speed;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool DoCheckSpecies(AActor *mo, FName filterSpecies, bool exclude)
|
|
||||||
{
|
|
||||||
FName actorSpecies = mo->GetSpecies();
|
|
||||||
if (filterSpecies == NAME_None) return true;
|
|
||||||
return exclude ? (actorSpecies != filterSpecies) : (actorSpecies == filterSpecies);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool DoCheckClass(AActor *mo, const PClass *filterClass, bool exclude)
|
|
||||||
{
|
|
||||||
const PClass *actorClass = mo->GetClass();
|
|
||||||
if (filterClass == NULL) return true;
|
|
||||||
return exclude ? (actorClass != filterClass) : (actorClass == filterClass);
|
|
||||||
}
|
|
||||||
|
|
||||||
//===========================================================================
|
//===========================================================================
|
||||||
//
|
//
|
||||||
// Common A_Damage handler
|
// Common A_Damage handler
|
||||||
|
|
|
@ -257,7 +257,7 @@ ACTOR Actor native //: Thinker
|
||||||
action native A_JumpIfInTargetInventory(class<Inventory> itemtype, int amount, state label, int forward_ptr = AAPTR_DEFAULT);
|
action native A_JumpIfInTargetInventory(class<Inventory> itemtype, int amount, state label, int forward_ptr = AAPTR_DEFAULT);
|
||||||
action native A_GiveToTarget(class<Inventory> itemtype, int amount = 0, int forward_ptr = AAPTR_DEFAULT);
|
action native A_GiveToTarget(class<Inventory> itemtype, int amount = 0, int forward_ptr = AAPTR_DEFAULT);
|
||||||
action native A_TakeFromTarget(class<Inventory> itemtype, int amount = 0, int flags = 0, int forward_ptr = AAPTR_DEFAULT);
|
action native A_TakeFromTarget(class<Inventory> itemtype, int amount = 0, int flags = 0, int forward_ptr = AAPTR_DEFAULT);
|
||||||
action native A_RadiusGive(class<Inventory> itemtype, int distance, int flags, int amount = 0);
|
action native A_RadiusGive(class<Inventory> itemtype, int distance, int flags, int amount = 0, class<Actor> filter = "None", name species = "None");
|
||||||
action native A_CountdownArg(int argnum, state targstate = "");
|
action native A_CountdownArg(int argnum, state targstate = "");
|
||||||
action native A_CustomMeleeAttack(int damage = 0, sound meleesound = "", sound misssound = "", name damagetype = "none", bool bleed = true);
|
action native A_CustomMeleeAttack(int damage = 0, 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_CustomComboAttack(class<Actor> missiletype, float spawnheight, int damage, sound meleesound = "", name damagetype = "none", bool bleed = true);
|
||||||
|
|
|
@ -224,6 +224,12 @@ enum
|
||||||
RGF_CUBE = 1 << 9,
|
RGF_CUBE = 1 << 9,
|
||||||
RGF_NOSIGHT = 1 << 10,
|
RGF_NOSIGHT = 1 << 10,
|
||||||
RGF_MISSILES = 1 << 11,
|
RGF_MISSILES = 1 << 11,
|
||||||
|
RGF_INCLUSIVE = 1 << 12,
|
||||||
|
RGF_ITEMS = 1 << 13,
|
||||||
|
RGF_KILLED = 1 << 14,
|
||||||
|
RGF_EXFILTER = 1 << 15,
|
||||||
|
RGF_EXSPECIES = 1 << 16,
|
||||||
|
RGF_EITHER = 1 << 17,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Activation flags
|
// Activation flags
|
||||||
|
|
Loading…
Reference in a new issue