Attached Files | P_RadiusAttack.txt [^] (8,654 bytes) 2015-04-29 18:30 [Show Content] [Hide Content]//==========================================================================
//
// P_RadiusAttack
// Source is the creature that caused the explosion at spot.
//
//==========================================================================
void P_RadiusAttack (AActor *bombspot, AActor *bombsource, int bombdamage, int bombdistance, FName bombmod,
bool DamageSource, bool bombdodamage, int fulldamagedistance)
{
if (bombdistance <= 0)
return;
fulldamagedistance = clamp<int>(fulldamagedistance, 0, bombdistance-1);
float bombdistancefloat = 1.f / (float)(bombdistance - fulldamagedistance);
float bombdamagefloat = (float)bombdamage;
FVector3 bombvec(FIXED2FLOAT(bombspot->x), FIXED2FLOAT(bombspot->y), FIXED2FLOAT(bombspot->z));
FBlockThingsIterator it(FBoundingBox(bombspot->x, bombspot->y, bombdistance<<FRACBITS));
AActor *thing;
while ((thing = it.Next()))
{
// Vulnerable actors can be damaged by radius attacks even if not shootable
// Used to emulate MBF's vulnerability of non-missile bouncers to explosions.
if (!((thing->flags & MF_SHOOTABLE) || (thing->flags6 & MF6_VULNERABLE)))
continue;
// Boss spider and cyborg and Heretic's ep >= 2 bosses
// take no damage from concussion.
if (thing->flags3 & MF3_NORADIUSDMG && !(bombspot->flags4 & MF4_FORCERADIUSDMG))
continue;
if (!DamageSource && thing == bombsource)
{ // don't damage the source of the explosion
continue;
}
// a much needed option: monsters that fire explosive projectiles cannot
// be hurt by projectiles fired by a monster of the same type.
// Controlled by the DONTHARMCLASS and DONTHARMSPECIES flags.
if ((bombsource && !thing->player) // code common to both checks
&& ( // Class check first
((bombsource->flags4 & MF4_DONTHARMCLASS) && (thing->GetClass() == bombsource->GetClass()))
|| // Nigh-identical species check second
((bombsource->flags6 & MF6_DONTHARMSPECIES) && (thing->GetSpecies() == bombsource->GetSpecies()))
)
) continue;
// Barrels always use the original code, since this makes
// them far too "active." BossBrains also use the old code
// because some user levels require they have a height of 16,
// which can make them near impossible to hit with the new code.
if (!bombdodamage || ( !((bombspot->flags5 | thing->flags5) & MF5_OLDRADIUSDMG)
&& !( zacompatflags & ZACOMPATF_OLDRADIUSDMG ) ) )
{
// [RH] New code. The bounding box only covers the
// height of the thing and not the height of the map.
float points;
float len;
fixed_t dx, dy;
float boxradius;
dx = abs (thing->x - bombspot->x);
dy = abs (thing->y - bombspot->y);
boxradius = float (thing->radius);
// The damage pattern is square, not circular.
len = float (dx > dy ? dx : dy);
if (bombspot->z < thing->z || bombspot->z >= thing->z + thing->height)
{
float dz;
if (bombspot->z > thing->z)
{
dz = float (bombspot->z - thing->z - thing->height);
}
else
{
dz = float (thing->z - bombspot->z);
}
if (len <= boxradius)
{
len = dz;
}
else
{
len -= boxradius;
len = sqrtf (len*len + dz*dz);
}
}
else
{
len -= boxradius;
if (len < 0.f)
len = 0.f;
}
len /= FRACUNIT;
len = clamp<float>(len - (float)fulldamagedistance, 0, len);
points = bombdamagefloat * (1.f - len * bombdistancefloat);
if (thing == bombsource)
{
points = points * splashfactor;
}
points *= thing->GetClass()->Meta.GetMetaFixed(AMETA_RDFactor, FRACUNIT)/(float)FRACUNIT;
if (points > 0.f && P_CheckSight (thing, bombspot, SF_IGNOREVISIBILITY|SF_IGNOREWATERBOUNDARY))
{ // OK to damage; target is in direct path
float velz;
float thrust;
// [BB] We need to store these values for ZACOMPATF_OLD_EXPLOSION_THRUST.
const fixed_t origmomx = thing->velx;
const fixed_t origmomy = thing->vely;
int damage = (int)points;
// [BC] Damage is server side.
if (( NETWORK_GetState( ) != NETSTATE_CLIENT ) && ( CLIENTDEMO_IsPlaying( ) == false ))
{
if (bombdodamage) P_DamageMobj (thing, bombspot, bombsource, damage, bombmod);
else if (thing->player == NULL)
{
thing->flags2 |= MF2_BLASTED;
// [BB] If we're the server, tell clients to update the flags of the object.
if ( NETWORK_GetState( ) == NETSTATE_SERVER )
SERVERCOMMANDS_SetThingFlags( thing, FLAGSET_FLAGS2 );
}
}
// [BC] If this explosion damaged a player, and the explosion originated from a
// player, mark the source player as striking a player, to potentially reward an
// accuracy medal.
if (( bombsource ) &&
( bombsource->player ) &&
( thing != bombsource ) &&
( thing->player ) &&
( thing->IsTeammate( bombsource ) == false ))
{
bombsource->player->bStruckPlayer = true;
}
if (!(thing->flags & MF_ICECORPSE))
{
if (bombdodamage && !(bombspot->flags3 & MF3_BLOODLESSIMPACT)) P_TraceBleed (damage, thing, bombspot);
if (!bombdodamage || !(bombspot->flags2 & MF2_NODMGTHRUST))
{
if (bombsource == NULL || !(bombsource->flags2 & MF2_NODMGTHRUST))
{
thrust = points * 0.5f / (float)thing->Mass;
if (bombsource == thing)
{
thrust *= selfthrustscale;
}
velz = (float)(thing->z + (thing->height>>1) - bombspot->z) * thrust;
if (bombsource != thing)
{
velz *= 0.5f;
}
else
{
velz *= 0.8f;
}
// [BB] Potentially use the horizontal thrust of old ZDoom versions.
if ( zacompatflags & ZACOMPATF_OLD_EXPLOSION_THRUST )
{
thing->velx = origmomx + static_cast<fixed_t>((thing->x - bombspot->x) * thrust);
thing->vely = origmomy + static_cast<fixed_t>((thing->y - bombspot->y) * thrust);
}
else
{
angle_t ang = R_PointToAngle2 (bombspot->x, bombspot->y, thing->x, thing->y) >> ANGLETOFINESHIFT;
thing->velx += fixed_t (finecosine[ang] * thrust);
thing->vely += fixed_t (finesine[ang] * thrust);
}
// [BB] If ZADF_NO_ROCKET_JUMPING is on, don't give players any z-momentum if the attack was made by a player.
if ( ( (zadmflags & ZADF_NO_ROCKET_JUMPING) == false ) ||
( bombsource == NULL ) || ( bombsource->player == NULL ) || ( thing->player == NULL ) )
{
if (bombdodamage)
thing->velz += (fixed_t)velz; // this really doesn't work well
}
}
// [BC] If we're the server, update the thing's momentum.
// [BB] Use SERVER_UpdateThingMomentum to prevent sync problems.
if ( NETWORK_GetState( ) == NETSTATE_SERVER )
SERVER_UpdateThingMomentum( thing, true );
}
}
}
}
else
{
// [RH] Old code just for barrels
fixed_t dx, dy, dist;
dx = abs (thing->x - bombspot->x);
dy = abs (thing->y - bombspot->y);
dist = dx>dy ? dx : dy;
dist = (dist - thing->radius) >> FRACBITS;
if (dist < 0)
dist = 0;
if (dist >= bombdistance)
continue; // out of range
if (P_CheckSight (thing, bombspot, SF_IGNOREVISIBILITY|SF_IGNOREWATERBOUNDARY))
{ // OK to damage; target is in direct path
dist = clamp<int>(dist - fulldamagedistance, 0, dist);
int damage = Scale (bombdamage, bombdistance-dist, bombdistance);
damage = (int)((float)damage * splashfactor);
damage = Scale(damage, thing->GetClass()->Meta.GetMetaFixed(AMETA_RDFactor, FRACUNIT), FRACUNIT);
if (damage > 0)
{
// Damage is server side.
if (( NETWORK_GetState( ) != NETSTATE_CLIENT ) && ( CLIENTDEMO_IsPlaying( ) == false ))
P_DamageMobj (thing, bombspot, bombsource, damage, bombmod);
P_TraceBleed (damage, thing, bombspot);
}
// Ch0wW: --DAMN SON, WHY HAVE YOU FORGOTTEN THIS?--
// [BC] If this explosion damaged a player, and the explosion originated from a
// player, mark the source player as striking a player, to potentially reward an
// accuracy medal.
if (( bombsource ) &&
( bombsource->player ) &&
( thing != bombsource ) &&
( thing->player ) &&
( thing->IsTeammate( bombsource ) == false ))
{
bombsource->player->bStruckPlayer = true;
}
}
}
}
// [BB] If the bombsource is a player and hit another player with his attack, potentially give him a medal.
PLAYER_CheckStruckPlayer( bombsource );
}
|