From b4f05ee89bab28a12dc5377a6702c5a059e068e3 Mon Sep 17 00:00:00 2001 From: MajorCooke Date: Wed, 22 Jul 2015 16:46:14 -0500 Subject: [PATCH 1/2] - 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. --- src/thingdef/thingdef_codeptr.cpp | 221 +++++++++++++++-------------- wadsrc/static/actors/actor.txt | 2 +- wadsrc/static/actors/constants.txt | 6 + 3 files changed, 121 insertions(+), 108 deletions(-) diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index 54bbe68d3..d124a507d 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -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 -// 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. // //========================================================================== @@ -4972,21 +4985,30 @@ enum RadiusGiveFlags RGF_CUBE = 1 << 9, RGF_NOSIGHT = 1 << 10, 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) { - ACTION_PARAM_START(7); + ACTION_PARAM_START(6); ACTION_PARAM_CLASS(item, 0); ACTION_PARAM_FIXED(distance, 1); ACTION_PARAM_INT(flags, 2); 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 - if (item == NULL || (flags & RGF_MASK) == 0 || distance <= 0) + if (item == NULL || (flags & RGF_MASK) == 0 || !flags || distance <= 0) { return; } + if (amount == 0) { amount = 1; @@ -4997,108 +5019,107 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RadiusGive) AActor *thing; while ((thing = it.Next())) { - // Don't give to inventory items - if (thing->flags & MF_SPECIAL) + //[MC] Check for a filter, species, and the related exfilter/expecies/either flag(s). + bool filterpass = DoCheckClass(thing, filter, !!(flags & RGF_EXFILTER)), + speciespass = DoCheckSpecies(thing, species, !!(flags & RGF_EXSPECIES)); + + if ((flags & RGF_EITHER) ? (!(filterpass || speciespass)) : (!(filterpass && speciespass))) { - continue; - } - // 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)) - { + if (thing != self) //Don't let filter and species obstruct RGF_GIVESELF. 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) - { // 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) - { + if (thing == self) + { + if (!(flags & RGF_GIVESELF)) continue; - } } - else - { // check if inside a sphere - TVector3 tpos(thing->x, thing->y, thing->z + thing->height/2); - TVector3 spos(self->x, self->y, self->z + self->height/2); - if ((tpos - spos).LengthSquared() > distsquared) - { + + //Check for target, master, and tracer flagging. + bool targetPass = true; + bool masterPass = true; + 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; + } + + //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)) - { // 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(Spawn (item, 0, 0, 0, NO_REPLACE)); - if (gift->IsKindOf(RUNTIME_CLASS(AHealth))) - { - gift->Amount *= amount; + bool itemPass = !!((flags & RGF_ITEMS) && thing->flags & MF_SPECIAL); + bool missilePass = !!((flags & RGF_MISSILES) && thing->flags & MF_MISSILE); + + if (selfPass || monsterPass || corpsePass || killedPass || itemPass || objectPass || missilePass || playerPass || voodooPass) + { + 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 - { - gift->Amount = amount; + { // check if inside a sphere + TVector3 tpos(thing->x, thing->y, thing->z + thing->height / 2); + TVector3 spos(self->x, self->y, self->z + self->height / 2); + if ((tpos - spos).LengthSquared() > distsquared) + { + continue; + } } - gift->flags |= MF_DROPPED; - gift->ClearCounters(); - if (!gift->CallTryPickup (thing)) - { - gift->Destroy (); + + if ((flags & RGF_NOSIGHT) || P_CheckSight(thing, self, SF_IGNOREVISIBILITY | SF_IGNOREWATERBOUNDARY)) + { // 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(Spawn(item, 0, 0, 0, NO_REPLACE)); + 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; } -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 diff --git a/wadsrc/static/actors/actor.txt b/wadsrc/static/actors/actor.txt index b7fea4189..6885ad2d6 100644 --- a/wadsrc/static/actors/actor.txt +++ b/wadsrc/static/actors/actor.txt @@ -257,7 +257,7 @@ ACTOR Actor native //: Thinker action native A_JumpIfInTargetInventory(class itemtype, int amount, state label, int forward_ptr = AAPTR_DEFAULT); action native A_GiveToTarget(class itemtype, int amount = 0, int forward_ptr = AAPTR_DEFAULT); action native A_TakeFromTarget(class itemtype, int amount = 0, int flags = 0, int forward_ptr = AAPTR_DEFAULT); - action native A_RadiusGive(class itemtype, int distance, int flags, int amount = 0); + action native A_RadiusGive(class itemtype, int distance, int flags, int amount = 0, class filter = "None", name species = "None"); 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_CustomComboAttack(class missiletype, float spawnheight, int damage, sound meleesound = "", name damagetype = "none", bool bleed = true); diff --git a/wadsrc/static/actors/constants.txt b/wadsrc/static/actors/constants.txt index 6612dd9f8..7aa23716f 100644 --- a/wadsrc/static/actors/constants.txt +++ b/wadsrc/static/actors/constants.txt @@ -224,6 +224,12 @@ enum RGF_CUBE = 1 << 9, RGF_NOSIGHT = 1 << 10, 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 From 41b4df71c26bb9e0287519042685de15cc863bc3 Mon Sep 17 00:00:00 2001 From: MajorCooke Date: Wed, 22 Jul 2015 17:12:42 -0500 Subject: [PATCH 2/2] Use IsKindOf instead of MF_SPECIAL to check for an inventory item. --- src/thingdef/thingdef_codeptr.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index d124a507d..570557be8 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -5079,7 +5079,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RadiusGive) } } - bool itemPass = !!((flags & RGF_ITEMS) && thing->flags & MF_SPECIAL); + bool itemPass = !!((flags & RGF_ITEMS) && thing->IsKindOf(RUNTIME_CLASS(AInventory))); bool missilePass = !!((flags & RGF_MISSILES) && thing->flags & MF_MISSILE); if (selfPass || monsterPass || corpsePass || killedPass || itemPass || objectPass || missilePass || playerPass || voodooPass)