//========================================================================== // // 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(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<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(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((thing->x - bombspot->x) * thrust); thing->vely = origmomy + static_cast((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(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 ); }