* Add new damagetype flag (DMG_CANHURTSELF) that allows a player to hurt themselves indirectly.

* Add damagetype to P_RadiusAttack (optinteger in lua, A_Explode var1).
* Removed the prevention of MF_BOSS objects from getting P_RadiusAttacked. This was a holdover from DooM (I checked) - a way to prevent the Cyberdemon from gibbing itself when firing point blank into a wall, and also a way to make it and the Spider Mastermind harder.
* Enemies are solid to other enemies movement-wise now.
* (Fun little aside - if you remove MF_SOLID from a monitor, it now behaves like they did in Sonic Adventure (poppable by colliding with, not just attacking).
* Fixed Metal Sonic battle conflict in MF_PAIN/mass not picked up earlier.
* Miscellaneous tiny code tweaks.
This commit is contained in:
toasterbabe 2018-05-08 23:26:36 +01:00
parent d0575f7fb0
commit 8a61d87961
8 changed files with 59 additions and 60 deletions

View File

@ -7400,6 +7400,7 @@ struct {
{"DMG_CRUSHED",DMG_CRUSHED},
{"DMG_SPECTATOR",DMG_SPECTATOR},
//// Masks
{"DMG_CANHURTSELF",DMG_CANHURTSELF},
{"DMG_DEATHMASK",DMG_DEATHMASK},
// Gametypes, for use with global var "gametype"

View File

@ -5422,7 +5422,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
16*FRACUNIT, // radius
48*FRACUNIT, // height
0, // display offset
sfx_s3k5a, // mass
0, // mass
3, // damage
sfx_mswarp, // activesound
MF_NOGRAVITY|MF_BOSS|MF_SLIDEME, // flags

View File

@ -1356,11 +1356,12 @@ static int lib_pRadiusAttack(lua_State *L)
mobj_t *spot = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
mobj_t *source = *((mobj_t **)luaL_checkudata(L, 2, META_MOBJ));
fixed_t damagedist = luaL_checkfixed(L, 3);
UINT8 damagetype = luaL_optinteger(L, 4, 0);
NOHUD
INLEVEL
if (!spot || !source)
return LUA_ErrInvalid(L, "mobj_t");
P_RadiusAttack(spot, source, damagedist);
P_RadiusAttack(spot, source, damagedist, damagetype);
return 0;
}

View File

@ -2824,16 +2824,17 @@ void A_GoldMonitorSparkle(mobj_t *actor)
//
// Description: Explodes an object, doing damage to any objects nearby. The target is used as the cause of the explosion. Damage value is used as explosion range.
//
// var1 = unused
// var1 = damagetype
// var2 = unused
//
void A_Explode(mobj_t *actor)
{
INT32 locvar1 = var1;
#ifdef HAVE_BLUA
if (LUA_CallAction("A_Explode", actor))
return;
#endif
P_RadiusAttack(actor, actor->target, actor->info->damage);
P_RadiusAttack(actor, actor->target, actor->info->damage, locvar1);
}
// Function: A_BossDeath
@ -9580,7 +9581,7 @@ void A_VileAttack(mobj_t *actor)
actor->target->x - P_ReturnThrustX(fire, actor->angle, FixedMul(24*FRACUNIT, fire->scale)),
actor->target->y - P_ReturnThrustY(fire, actor->angle, FixedMul(24*FRACUNIT, fire->scale)),
fire->z);
P_RadiusAttack(fire, actor, 70*FRACUNIT);
P_RadiusAttack(fire, actor, 70*FRACUNIT, 0);
}
else
{
@ -9625,7 +9626,7 @@ void A_VileAttack(mobj_t *actor)
actor->target->x - P_ReturnThrustX(fire, actor->angle, FixedMul(24*FRACUNIT, fire->scale)),
actor->target->y - P_ReturnThrustY(fire, actor->angle, FixedMul(24*FRACUNIT, fire->scale)),
fire->z);
P_RadiusAttack(fire, actor, 70*FRACUNIT);
P_RadiusAttack(fire, actor, 70*FRACUNIT, 0);
}
}
@ -10709,7 +10710,7 @@ void A_MineExplode(mobj_t *actor)
quake.intensity = 8*FRACUNIT;
quake.time = TICRATE/3;
P_RadiusAttack(actor, actor->tracer, 192*FRACUNIT);
P_RadiusAttack(actor, actor->tracer, 192*FRACUNIT, DMG_CANHURTSELF);
P_MobjCheckWater(actor);
{

View File

@ -2670,7 +2670,7 @@ static inline void P_NiGHTSDamage(mobj_t *target, mobj_t *source)
}
}
static inline boolean P_TagDamage(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 damage)
static inline boolean P_TagDamage(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 damage, UINT8 damagetype)
{
player_t *player = target->player;
(void)damage; //unused parm
@ -2680,7 +2680,7 @@ static inline boolean P_TagDamage(mobj_t *target, mobj_t *inflictor, mobj_t *sou
return false;
// Ignore IT players shooting each other, unless friendlyfire is on.
if ((player->pflags & PF_TAGIT && !(cv_friendlyfire.value &&
if ((player->pflags & PF_TAGIT && !((cv_friendlyfire.value || (damagetype & DMG_CANHURTSELF)) &&
source && source->player && source->player->pflags & PF_TAGIT)))
return false;
@ -2690,7 +2690,7 @@ static inline boolean P_TagDamage(mobj_t *target, mobj_t *inflictor, mobj_t *sou
// Don't allow players on the same team to hurt one another,
// unless cv_friendlyfire is on.
if (!cv_friendlyfire.value && (player->pflags & PF_TAGIT) == (source->player->pflags & PF_TAGIT))
if (!(cv_friendlyfire.value || (damagetype & DMG_CANHURTSELF)) && (player->pflags & PF_TAGIT) == (source->player->pflags & PF_TAGIT))
{
if (!(inflictor->flags & MF_FIRE))
P_GivePlayerRings(player, 1);
@ -2745,21 +2745,26 @@ static inline boolean P_TagDamage(mobj_t *target, mobj_t *inflictor, mobj_t *sou
return true;
}
static inline boolean P_PlayerHitsPlayer(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 damage)
static inline boolean P_PlayerHitsPlayer(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 damage, UINT8 damagetype)
{
player_t *player = target->player;
// You can't kill yourself, idiot...
if (source == target)
return false;
if (!(damagetype & DMG_CANHURTSELF))
{
// You can't kill yourself, idiot...
if (source == target)
return false;
// In COOP/RACE/CHAOS, you can't hurt other players unless cv_friendlyfire is on
if (!cv_friendlyfire.value && (G_PlatformGametype()))
return false;
// In COOP/RACE, you can't hurt other players unless cv_friendlyfire is on
if (!cv_friendlyfire.value && (G_PlatformGametype()))
return false;
}
// Tag handling
if (G_TagGametype())
return P_TagDamage(target, inflictor, source, damage);
return P_TagDamage(target, inflictor, source, damage, damagetype);
else if (damagetype & DMG_CANHURTSELF)
return true;
else if (G_GametypeHasTeams()) // CTF + Team Match
{
// Don't allow players on the same team to hurt one another,
@ -3177,7 +3182,7 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
// Player hits another player
if (!force && source && source->player)
{
if (!P_PlayerHitsPlayer(target, inflictor, source, damage))
if (!P_PlayerHitsPlayer(target, inflictor, source, damage, damagetype))
return false;
}

View File

@ -363,7 +363,7 @@ void P_DelPrecipSeclist(mprecipsecnode_t *node);
void P_CreateSecNodeList(mobj_t *thing, fixed_t x, fixed_t y);
void P_Initsecnode(void);
void P_RadiusAttack(mobj_t *spot, mobj_t *source, fixed_t damagedist);
void P_RadiusAttack(mobj_t *spot, mobj_t *source, fixed_t damagedist, UINT8 damagetype);
fixed_t P_FloorzAtPos(fixed_t x, fixed_t y, fixed_t z, fixed_t height);
boolean PIT_PushableMoved(mobj_t *thing);
@ -413,6 +413,8 @@ typedef struct BasicFF_s
#define DMG_DEATHPIT 0x80+3
#define DMG_CRUSHED 0x80+4
#define DMG_SPECTATOR 0x80+5
// Masks
#define DMG_CANHURTSELF 0x40 // Flag - can hurt self/team indirectly, such as through mines
#define DMG_DEATHMASK DMG_INSTAKILL // if bit 7 is set, this is a death type instead of a damage type
void P_ForceFeed(const player_t *player, INT32 attack, INT32 fade, tic_t duration, INT32 period);

View File

@ -674,14 +674,14 @@ static boolean PIT_CheckThing(mobj_t *thing)
return true;
}
if (thing->flags & MF_PAIN)
if (thing->flags & MF_PAIN && tmthing->player)
{ // Player touches painful thing sitting on the floor
// see if it went over / under
if (thing->z > tmthing->z + tmthing->height)
return true; // overhead
if (thing->z + thing->height < tmthing->z)
return true; // underneath
if (tmthing->player && tmthing->flags & MF_SHOOTABLE && thing->health > 0)
if (tmthing->flags & MF_SHOOTABLE && thing->health > 0)
{
UINT8 damagetype = thing->info->mass;
if (!damagetype && thing->flags & MF_FIRE) // BURN!
@ -691,14 +691,14 @@ static boolean PIT_CheckThing(mobj_t *thing)
}
return true;
}
else if (tmthing->flags & MF_PAIN)
else if (tmthing->flags & MF_PAIN && thing->player)
{ // Painful thing splats player in the face
// see if it went over / under
if (tmthing->z > thing->z + thing->height)
return true; // overhead
if (tmthing->z + tmthing->height < thing->z)
return true; // underneath
if (thing->player && thing->flags & MF_SHOOTABLE && tmthing->health > 0)
if (thing->flags & MF_SHOOTABLE && tmthing->health > 0)
{
UINT8 damagetype = tmthing->info->mass;
if (!damagetype && tmthing->flags & MF_FIRE) // BURN!
@ -751,6 +751,7 @@ static boolean PIT_CheckThing(mobj_t *thing)
else if (tmz > thzh - sprarea && tmz < thzh) // Don't damage people springing up / down
return true;
}
// missiles can hit other things
if (tmthing->flags & MF_MISSILE || tmthing->type == MT_SHELL)
{
@ -805,30 +806,11 @@ static boolean PIT_CheckThing(mobj_t *thing)
if (thing->type == MT_EGGSHIELD)
{
fixed_t touchx, touchy;
angle_t angle;
angle_t angle = (R_PointToAngle2(thing->x, thing->y, tmthing->x - tmthing->momx, tmthing->y - tmthing->momy) - thing->angle) - ANGLE_90;
if (P_AproxDistance(tmthing->x-thing->x, tmthing->y-thing->y) >
P_AproxDistance((tmthing->x-tmthing->momx)-thing->x, (tmthing->y-tmthing->momy)-thing->y))
{
touchx = tmthing->x + tmthing->momx;
touchy = tmthing->y + tmthing->momy;
}
else
{
touchx = tmthing->x;
touchy = tmthing->y;
}
angle = R_PointToAngle2(thing->x, thing->y, touchx, touchy) - thing->angle;
if (!(angle > ANGLE_90 && angle < ANGLE_270)) // hit front of shield, didn't destroy it
return false;
else // hit shield from behind, shield is destroyed!
{
if (angle < ANGLE_180) // hit shield from behind, shield is destroyed!
P_KillMobj(thing, tmthing, tmthing, 0);
return false;
}
return false;
}
// damage / explode
@ -1086,6 +1068,14 @@ static boolean PIT_CheckThing(mobj_t *thing)
}
}
// thanks to sal for solidenemies dot lua
if (thing->flags & (MF_ENEMY|MF_BOSS) && tmthing->flags & (MF_ENEMY|MF_BOSS))
{
if ((thing->z + thing->height >= tmthing->z)
&& (tmthing->z + tmthing->height >= thing->z))
return false;
}
// Damage other players when invincible
if (tmthing->player && thing->player
// Make sure they aren't able to damage you ANYWHERE along the Z axis, you have to be TOUCHING the person.
@ -1150,7 +1140,7 @@ static boolean PIT_CheckThing(mobj_t *thing)
{
// Objects kill you if it falls from above.
if (thing != tmthing->target)
P_DamageMobj(thing, tmthing, tmthing->target, 1, DMG_INSTAKILL);
P_DamageMobj(thing, tmthing, tmthing->target, 1, DMG_CRUSHED);
tmthing->momz = -tmthing->momz/2; // Bounce, just for fun!
// The tmthing->target allows the pusher of the object
@ -1185,7 +1175,8 @@ static boolean PIT_CheckThing(mobj_t *thing)
UINT8 elementalpierce = (((tmthing->player->powers[pw_shield] & SH_NOSTACK) == SH_ELEMENTAL || (tmthing->player->powers[pw_shield] & SH_NOSTACK) == SH_BUBBLEWRAP) && (tmthing->player->pflags & PF_SHIELDABILITY)
? (((tmthing->player->powers[pw_shield] & SH_NOSTACK) == SH_ELEMENTAL) ? 1 : 2)
: 0);
if (tmthing->player->pflags & (PF_SPINNING|PF_GLIDING)
if (!(thing->flags & MF_SOLID)
|| tmthing->player->pflags & (PF_SPINNING|PF_GLIDING)
|| ((tmthing->player->pflags & PF_JUMPED)
&& (!(tmthing->player->pflags & PF_NOJUMPDAMAGE)
|| (tmthing->player->charability == CA_TWINSPIN && tmthing->player->panim == PA_ABILITY)))
@ -1194,8 +1185,8 @@ static boolean PIT_CheckThing(mobj_t *thing)
&& (P_MobjFlip(tmthing)*(tmthing->z - (thing->z + thing->height/2)) > 0) && (P_MobjFlip(tmthing)*tmthing->momz < 0))
|| elementalpierce)
{
if (thing->z - FixedMul(FRACUNIT, thing->scale) <= tmthing->z + tmthing->height
&& thing->z + thing->height + FixedMul(FRACUNIT, thing->scale) >= tmthing->z)
if (thing->z - thing->scale <= tmthing->z + tmthing->height
&& thing->z + thing->height + thing->scale >= tmthing->z)
{
player_t *player = tmthing->player;
SINT8 flipval = P_MobjFlip(thing); // Save this value in case monitor gets removed.
@ -3527,6 +3518,7 @@ bounceback:
static fixed_t bombdamage;
static mobj_t *bombsource;
static mobj_t *bombspot;
static UINT8 bombdamagetype;
//
// PIT_RadiusAttack
@ -3537,17 +3529,13 @@ static boolean PIT_RadiusAttack(mobj_t *thing)
{
fixed_t dx, dy, dz, dist;
if (thing == bombspot // ignore the bomb itself (Deton fix)
|| (bombsource && thing->type == bombsource->type)) // ignore the type of guys who dropped the bomb (Jetty-Syn Bomber or Skim can bomb eachother, but not themselves.)
if (thing == bombspot) // ignore the bomb itself (Deton fix)
return true;
if (!(thing->flags & MF_SHOOTABLE))
if ((thing->flags & (MF_MONITOR|MF_SHOOTABLE)) != MF_SHOOTABLE)
return true;
if (thing->flags & MF_BOSS)
return true;
if (thing->flags & MF_MONITOR)
if (bombsource && thing->type == bombsource->type && !(bombdamagetype & DMG_CANHURTSELF)) // ignore the type of guys who dropped the bomb (Jetty-Syn Bomber or Skim can bomb eachother, but not themselves.)
return true;
dx = abs(thing->x - bombspot->x);
@ -3571,7 +3559,7 @@ static boolean PIT_RadiusAttack(mobj_t *thing)
if (P_CheckSight(thing, bombspot))
{ // must be in direct path
P_DamageMobj(thing, bombspot, bombsource, 1, 0); // Tails 01-11-2001
P_DamageMobj(thing, bombspot, bombsource, 1, bombdamagetype); // Tails 01-11-2001
}
return true;
@ -3581,7 +3569,7 @@ static boolean PIT_RadiusAttack(mobj_t *thing)
// P_RadiusAttack
// Source is the creature that caused the explosion at spot.
//
void P_RadiusAttack(mobj_t *spot, mobj_t *source, fixed_t damagedist)
void P_RadiusAttack(mobj_t *spot, mobj_t *source, fixed_t damagedist, UINT8 damagetype)
{
INT32 x, y;
INT32 xl, xh, yl, yh;
@ -3598,6 +3586,7 @@ void P_RadiusAttack(mobj_t *spot, mobj_t *source, fixed_t damagedist)
bombspot = spot;
bombsource = source;
bombdamage = FixedMul(damagedist, spot->scale);
bombdamagetype = damagetype;
for (y = yl; y <= yh; y++)
for (x = xl; x <= xh; x++)

View File

@ -877,7 +877,7 @@ void P_ExplodeMissile(mobj_t *mo)
if (mo->type == MT_DETON)
{
P_RadiusAttack(mo, mo, 96*FRACUNIT);
P_RadiusAttack(mo, mo, 96*FRACUNIT, 0);
explodemo = P_SpawnMobj(mo->x, mo->y, mo->z, MT_EXPLODE);
P_SetScale(explodemo, mo->scale);