mirror of
https://github.com/ZDoom/gzdoom.git
synced 2024-11-26 22:11:43 +00:00
Merge branch 'RadiusGiveExp2'
This commit is contained in:
commit
5317a92d11
1 changed files with 137 additions and 114 deletions
|
@ -4975,6 +4975,133 @@ enum RadiusGiveFlags
|
||||||
RGF_EITHER = 1 << 17,
|
RGF_EITHER = 1 << 17,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static bool DoRadiusGive(AActor *self, AActor *thing, const PClass *item, int amount, fixed_t distance, int flags, const PClass *filter, FName species, fixed_t mindist)
|
||||||
|
{
|
||||||
|
// [MC] We only want to make an exception for missiles here. Nothing else.
|
||||||
|
bool missilePass = !!((flags & RGF_MISSILES) && thing->isMissile());
|
||||||
|
if (thing == self)
|
||||||
|
{
|
||||||
|
if (!(flags & RGF_GIVESELF))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else if (thing->isMissile())
|
||||||
|
{
|
||||||
|
if (!missilePass)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//[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)))
|
||||||
|
{
|
||||||
|
if (thing != self) //Don't let filter and species obstruct RGF_GIVESELF.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//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)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//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->player == NULL) && (!(thing->flags3 & MF3_ISMONSTER))
|
||||||
|
&& ((thing->flags & MF_SHOOTABLE) || (thing->flags6 & MF6_VULNERABLE)));
|
||||||
|
bool playerPass = !!((flags & RGF_PLAYERS) && (thing->player != NULL) && (thing->player->mo == thing));
|
||||||
|
bool voodooPass = !!((flags & RGF_VOODOO) && (thing->player != NULL) && (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!
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool itemPass = !!((flags & RGF_ITEMS) && thing->IsKindOf(RUNTIME_CLASS(AInventory)));
|
||||||
|
|
||||||
|
if (selfPass || monsterPass || corpsePass || killedPass || itemPass || objectPass || missilePass || playerPass || voodooPass)
|
||||||
|
{
|
||||||
|
|
||||||
|
fixedvec3 diff = self->Vec3To(thing);
|
||||||
|
diff.z += (thing->height - self->height) / 2;
|
||||||
|
if (flags & RGF_CUBE)
|
||||||
|
{ // check if inside a cube
|
||||||
|
double dx = fabs((double)(diff.x));
|
||||||
|
double dy = fabs((double)(diff.y));
|
||||||
|
double dz = fabs((double)(diff.z));
|
||||||
|
double dist = (double)distance;
|
||||||
|
double min = (double)mindist;
|
||||||
|
if ((dx > dist || dy > dist || dz > dist) || (min && (dx < min && dy < min && dz < min)))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{ // check if inside a sphere
|
||||||
|
double distsquared = double(distance) * double(distance);
|
||||||
|
double minsquared = double(mindist) * double(mindist);
|
||||||
|
double lengthsquared = TVector3<double>(diff.x, diff.y, diff.z).LengthSquared();
|
||||||
|
if (lengthsquared > distsquared || (minsquared && (lengthsquared < minsquared)))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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<AInventory *>(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();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RadiusGive)
|
DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RadiusGive)
|
||||||
{
|
{
|
||||||
ACTION_PARAM_START(7);
|
ACTION_PARAM_START(7);
|
||||||
|
@ -4997,126 +5124,22 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RadiusGive)
|
||||||
{
|
{
|
||||||
amount = 1;
|
amount = 1;
|
||||||
}
|
}
|
||||||
FBlockThingsIterator it(FBoundingBox(self->X(), self->Y(), distance));
|
|
||||||
|
|
||||||
AActor *thing;
|
AActor *thing;
|
||||||
bool given = false;
|
bool given = false;
|
||||||
while ((thing = it.Next()))
|
if (flags & RGF_MISSILES)
|
||||||
{
|
{
|
||||||
//[MC] Check for a filter, species, and the related exfilter/expecies/either flag(s).
|
TThinkerIterator<AActor> it;
|
||||||
bool filterpass = DoCheckClass(thing, filter, !!(flags & RGF_EXFILTER)),
|
while ((thing = it.Next()))
|
||||||
speciespass = DoCheckSpecies(thing, species, !!(flags & RGF_EXSPECIES));
|
|
||||||
|
|
||||||
if ((flags & RGF_EITHER) ? (!(filterpass || speciespass)) : (!(filterpass && speciespass)))
|
|
||||||
{
|
{
|
||||||
if (thing != self) //Don't let filter and species obstruct RGF_GIVESELF.
|
if (DoRadiusGive(self, thing, item, amount, distance, flags, filter, species, mindist)) given = true;
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (thing == self)
|
else
|
||||||
|
{
|
||||||
|
FBlockThingsIterator it(FBoundingBox(self->X(), self->Y(), distance));
|
||||||
|
while ((thing = it.Next()))
|
||||||
{
|
{
|
||||||
if (!(flags & RGF_GIVESELF))
|
if (DoRadiusGive(self, thing, item, amount, distance, flags, filter, species, mindist)) given = true;
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
//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->player == NULL) && (!(thing->flags3 & MF3_ISMONSTER))
|
|
||||||
&& ((thing->flags & MF_SHOOTABLE) || (thing->flags6 & MF6_VULNERABLE)));
|
|
||||||
bool playerPass = !!((flags & RGF_PLAYERS) && (thing->player != NULL) && (thing->player->mo == thing));
|
|
||||||
bool voodooPass = !!((flags & RGF_VOODOO) && (thing->player != NULL) && (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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
|
|
||||||
fixedvec3 diff = self->Vec3To(thing);
|
|
||||||
diff.z += (thing->height - self->height) / 2;
|
|
||||||
if (flags & RGF_CUBE)
|
|
||||||
{ // check if inside a cube
|
|
||||||
double dx = fabs((double)(diff.x));
|
|
||||||
double dy = fabs((double)(diff.y));
|
|
||||||
double dz = fabs((double)(diff.z));
|
|
||||||
double dist = (double)distance;
|
|
||||||
double min = (double)mindist;
|
|
||||||
if ((dx > dist || dy > dist || dz > dist) || (min && (dx < min && dy < min && dz < min)))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{ // check if inside a sphere
|
|
||||||
double distsquared = double(distance) * double(distance);
|
|
||||||
double minsquared = double(mindist) * double(mindist);
|
|
||||||
double lengthsquared = TVector3<double>(diff.x, diff.y, diff.z).LengthSquared();
|
|
||||||
if (lengthsquared > distsquared || (minsquared && (lengthsquared < minsquared)))
|
|
||||||
{
|
|
||||||
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<AInventory *>(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();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
given = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ACTION_SET_RESULT(given);
|
ACTION_SET_RESULT(given);
|
||||||
|
|
Loading…
Reference in a new issue