mirror of
https://git.do.srb2.org/STJr/SRB2.git
synced 2025-01-31 05:30:48 +00:00
PITY IN PINK!
* Smoothen Pity Shield animation to go with sphere's updates to Nev3r's sprites. * Added LHRT object, designed to be summoned with CA2_MELEE. * Gives a pink Pity Shield (SH_PINK) on same-team player contact. * Deals damage to non-player enemies. * Harmlessly fades into nothing when touching an enemy player, players with SH_PINK already, and players capable of applying SH_PINK to others (through non-Lua methods). * Basically, you-know-who is the Healer of the party whenever they're around. Fun consequences for the Co-op and CTF metas.
This commit is contained in:
parent
6a58ae34d1
commit
2e6898f29e
10 changed files with 170 additions and 18 deletions
|
@ -196,6 +196,7 @@ typedef enum
|
|||
SH_PITY = 1, // the world's most basic shield ever, given to players who suck at Match
|
||||
SH_WHIRLWIND,
|
||||
SH_ARMAGEDDON,
|
||||
SH_PINK, // PITY IN PINK!
|
||||
|
||||
// Normal shields that use flags
|
||||
SH_ATTRACT = SH_PITY|SH_PROTECTELECTRIC,
|
||||
|
|
|
@ -6027,6 +6027,12 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
|
|||
"S_PITY4",
|
||||
"S_PITY5",
|
||||
"S_PITY6",
|
||||
"S_PITY7",
|
||||
"S_PITY8",
|
||||
"S_PITY9",
|
||||
"S_PITY10",
|
||||
"S_PITY11",
|
||||
"S_PITY12",
|
||||
|
||||
"S_FIRS1",
|
||||
"S_FIRS2",
|
||||
|
@ -6519,6 +6525,7 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
|
|||
"S_GOTFLAG",
|
||||
|
||||
"S_CORK",
|
||||
"S_LHRT",
|
||||
|
||||
// Red Ring
|
||||
"S_RRNG1",
|
||||
|
@ -7579,6 +7586,7 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s
|
|||
"MT_MACHINEAMBIENCE",
|
||||
|
||||
"MT_CORK",
|
||||
"MT_LHRT",
|
||||
|
||||
// Ring Weapons
|
||||
"MT_REDRING",
|
||||
|
@ -8342,6 +8350,7 @@ struct {
|
|||
{"SH_PITY",SH_PITY},
|
||||
{"SH_WHIRLWIND",SH_WHIRLWIND},
|
||||
{"SH_ARMAGEDDON",SH_ARMAGEDDON},
|
||||
{"SH_PINK",SH_PINK},
|
||||
// normal shields that use flags
|
||||
{"SH_ATTRACT",SH_ATTRACT},
|
||||
{"SH_ELEMENTAL",SH_ELEMENTAL},
|
||||
|
|
|
@ -469,6 +469,7 @@ light_t *t_lspr[NUMSPRITES] =
|
|||
&lspr[NOLIGHT], // SPR_GFLG
|
||||
|
||||
&lspr[NOLIGHT], // SPR_CORK
|
||||
&lspr[NOLIGHT], // SPR_LHRT
|
||||
|
||||
// Ring Weapons
|
||||
&lspr[RINGLIGHT_L], // SPR_RRNG
|
||||
|
|
49
src/info.c
49
src/info.c
|
@ -364,6 +364,7 @@ char sprnames[NUMSPRITES + 1][5] =
|
|||
"GFLG", // Got Flag sign
|
||||
|
||||
"CORK",
|
||||
"LHRT",
|
||||
|
||||
// Ring Weapons
|
||||
"RRNG", // Red Ring
|
||||
|
@ -2664,12 +2665,18 @@ state_t states[NUMSTATES] =
|
|||
{SPR_ELEM, FF_FULLBRIGHT|20, 1, {NULL}, 0, 0, S_ELEMF10}, // S_ELEMF9
|
||||
{SPR_NULL, 0, 1, {NULL}, 0, 0, S_ELEMF1 }, // S_ELEMF10
|
||||
|
||||
{SPR_PITY, FF_TRANS30 , 2, {NULL}, 0, 0, S_PITY2}, // S_PITY1
|
||||
{SPR_PITY, FF_TRANS30|1, 2, {NULL}, 0, 0, S_PITY3}, // S_PITY2
|
||||
{SPR_PITY, FF_TRANS30|2, 2, {NULL}, 0, 0, S_PITY4}, // S_PITY3
|
||||
{SPR_PITY, FF_TRANS20|3, 2, {NULL}, 0, 0, S_PITY5}, // S_PITY4
|
||||
{SPR_PITY, FF_TRANS30|4, 2, {NULL}, 0, 0, S_PITY6}, // S_PITY5
|
||||
{SPR_PITY, FF_TRANS20|5, 2, {NULL}, 0, 0, S_PITY1}, // S_PITY6
|
||||
{SPR_PITY, FF_TRANS30 , 2, {NULL}, 0, 0, S_PITY2}, // S_PITY1
|
||||
{SPR_PITY, FF_TRANS30| 1, 2, {NULL}, 0, 0, S_PITY3}, // S_PITY2
|
||||
{SPR_PITY, FF_TRANS30| 2, 2, {NULL}, 0, 0, S_PITY4}, // S_PITY3
|
||||
{SPR_PITY, FF_TRANS30| 3, 2, {NULL}, 0, 0, S_PITY5}, // S_PITY4
|
||||
{SPR_PITY, FF_TRANS30| 4, 2, {NULL}, 0, 0, S_PITY6}, // S_PITY5
|
||||
{SPR_PITY, FF_TRANS30| 5, 2, {NULL}, 0, 0, S_PITY7}, // S_PITY6
|
||||
{SPR_PITY, FF_TRANS30| 6, 2, {NULL}, 0, 0, S_PITY8}, // S_PITY7
|
||||
{SPR_PITY, FF_TRANS30| 7, 2, {NULL}, 0, 0, S_PITY9}, // S_PITY8
|
||||
{SPR_PITY, FF_TRANS30| 8, 2, {NULL}, 0, 0, S_PITY10}, // S_PITY9
|
||||
{SPR_PITY, FF_TRANS30| 9, 2, {NULL}, 0, 0, S_PITY11}, // S_PITY10
|
||||
{SPR_PITY, FF_TRANS30|10, 2, {NULL}, 0, 0, S_PITY12}, // S_PITY11
|
||||
{SPR_PITY, FF_TRANS30|11, 2, {NULL}, 0, 0, S_PITY1}, // S_PITY12
|
||||
|
||||
{SPR_FIRS, FF_FULLBRIGHT|FF_TRANS40 , 2, {NULL}, 0, 0, S_FIRS2}, // S_FIRS1
|
||||
{SPR_FIRS, FF_FULLBRIGHT|FF_TRANS40|1, 2, {NULL}, 0, 0, S_FIRS3}, // S_FIRS2
|
||||
|
@ -3165,7 +3172,8 @@ state_t states[NUMSTATES] =
|
|||
// CTF Sign
|
||||
{SPR_GFLG, FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_NULL}, // S_GOTFLAG
|
||||
|
||||
{SPR_CORK, 0, -1, {NULL}, 0, 0, S_NULL}, // S_CORK
|
||||
{SPR_CORK, 0, -1, {NULL}, 0, 0, S_NULL}, // S_CORK
|
||||
{SPR_LHRT, FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL}, // S_LHRT
|
||||
|
||||
// Red Rings (thrown)
|
||||
{SPR_RRNG, FF_FULLBRIGHT, 1, {A_ThrownRing}, 0, 0, S_RRNG2}, // S_RRNG1
|
||||
|
@ -16099,6 +16107,33 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
|
|||
S_NULL // raisestate
|
||||
},
|
||||
|
||||
{ // MT_LHRT
|
||||
-1, // doomednum
|
||||
S_LHRT, // spawnstate
|
||||
1000, // spawnhealth
|
||||
S_NULL, // seestate
|
||||
sfx_None, // seesound
|
||||
0, // reactiontime
|
||||
sfx_None, // attacksound
|
||||
S_NULL, // painstate
|
||||
0, // painchance
|
||||
sfx_None, // painsound
|
||||
S_NULL, // meleestate
|
||||
S_NULL, // missilestate
|
||||
S_SPRK1, // deathstate
|
||||
S_SPRK1, // xdeathstate
|
||||
sfx_None, // deathsound
|
||||
60*FRACUNIT, // speed
|
||||
16*FRACUNIT, // radius
|
||||
16*FRACUNIT, // height
|
||||
0, // display offset
|
||||
0, // mass
|
||||
1, // damage
|
||||
sfx_None, // activesound
|
||||
MF_NOBLOCKMAP|MF_MISSILE, // flags
|
||||
S_NULL // raisestate
|
||||
},
|
||||
|
||||
{ // MT_REDRING
|
||||
-1, // doomednum
|
||||
S_RRNG1, // spawnstate
|
||||
|
|
|
@ -595,6 +595,7 @@ typedef enum sprite
|
|||
SPR_GFLG, // Got Flag sign
|
||||
|
||||
SPR_CORK,
|
||||
SPR_LHRT,
|
||||
|
||||
// Ring Weapons
|
||||
SPR_RRNG, // Red Ring
|
||||
|
@ -2771,6 +2772,12 @@ typedef enum state
|
|||
S_PITY4,
|
||||
S_PITY5,
|
||||
S_PITY6,
|
||||
S_PITY7,
|
||||
S_PITY8,
|
||||
S_PITY9,
|
||||
S_PITY10,
|
||||
S_PITY11,
|
||||
S_PITY12,
|
||||
|
||||
S_FIRS1,
|
||||
S_FIRS2,
|
||||
|
@ -3263,6 +3270,7 @@ typedef enum state
|
|||
S_GOTFLAG,
|
||||
|
||||
S_CORK,
|
||||
S_LHRT,
|
||||
|
||||
// Red Ring
|
||||
S_RRNG1,
|
||||
|
@ -4343,6 +4351,7 @@ typedef enum mobj_type
|
|||
MT_MACHINEAMBIENCE,
|
||||
|
||||
MT_CORK,
|
||||
MT_LHRT,
|
||||
|
||||
// Ring Weapons
|
||||
MT_REDRING,
|
||||
|
|
|
@ -2813,26 +2813,47 @@ static inline boolean P_TagDamage(mobj_t *target, mobj_t *inflictor, mobj_t *sou
|
|||
if (player->powers[pw_flashing] || player->powers[pw_invulnerability])
|
||||
return false;
|
||||
|
||||
// Ignore IT players shooting each other, unless friendlyfire is on.
|
||||
if ((player->pflags & PF_TAGIT && !((cv_friendlyfire.value || (damagetype & DMG_CANHURTSELF)) &&
|
||||
source && source->player && source->player->pflags & PF_TAGIT)))
|
||||
return false;
|
||||
|
||||
// Don't allow any damage before the round starts.
|
||||
if (leveltime <= hidetime * TICRATE)
|
||||
return false;
|
||||
|
||||
// Ignore IT players shooting each other, unless friendlyfire is on.
|
||||
if ((player->pflags & PF_TAGIT && !((cv_friendlyfire.value || (damagetype & DMG_CANHURTSELF)) &&
|
||||
source && source->player && source->player->pflags & PF_TAGIT)))
|
||||
{
|
||||
if (inflictor->type == MT_LHRT && !(player->powers[pw_shield] & SH_NOSTACK))
|
||||
{
|
||||
if (player->spinitem != MT_LHRT && player->revitem != MT_LHRT && player->thokitem != MT_LHRT) // Healers do not get to heal other healers.
|
||||
{
|
||||
P_SwitchShield(player, SH_PINK);
|
||||
S_StartSound(target, mobjinfo[MT_PITY_ICON].seesound);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Don't allow players on the same team to hurt one another,
|
||||
// unless cv_friendlyfire is on.
|
||||
if (!(cv_friendlyfire.value || (damagetype & DMG_CANHURTSELF)) && (player->pflags & PF_TAGIT) == (source->player->pflags & PF_TAGIT))
|
||||
{
|
||||
if (!(inflictor->flags & MF_FIRE))
|
||||
if (inflictor->type == MT_LHRT && !(player->powers[pw_shield] & SH_NOSTACK))
|
||||
{
|
||||
if (player->spinitem != MT_LHRT && player->revitem != MT_LHRT && player->thokitem != MT_LHRT) // Healers do not get to heal other healers.
|
||||
{
|
||||
P_SwitchShield(player, SH_PINK);
|
||||
S_StartSound(target, mobjinfo[MT_PITY_ICON].seesound);
|
||||
}
|
||||
}
|
||||
else if (!(inflictor->flags & MF_FIRE))
|
||||
P_GivePlayerRings(player, 1);
|
||||
if (inflictor->flags2 & MF2_BOUNCERING)
|
||||
inflictor->fuse = 0; // bounce ring disappears at -1 not 0
|
||||
return false;
|
||||
}
|
||||
|
||||
if (inflictor->type == MT_LHRT)
|
||||
return false;
|
||||
|
||||
// The tag occurs so long as you aren't shooting another tagger with friendlyfire on.
|
||||
if (source->player->pflags & PF_TAGIT && !(player->pflags & PF_TAGIT))
|
||||
{
|
||||
|
@ -2899,7 +2920,17 @@ static inline boolean P_PlayerHitsPlayer(mobj_t *target, mobj_t *inflictor, mobj
|
|||
|
||||
// In COOP/RACE, you can't hurt other players unless cv_friendlyfire is on
|
||||
if (!cv_friendlyfire.value && (G_PlatformGametype()))
|
||||
{
|
||||
if (inflictor->type == MT_LHRT && !(player->powers[pw_shield] & SH_NOSTACK))
|
||||
{
|
||||
if (player->spinitem != MT_LHRT && player->revitem != MT_LHRT && player->thokitem != MT_LHRT) // Healers do not get to heal other healers.
|
||||
{
|
||||
P_SwitchShield(player, SH_PINK);
|
||||
S_StartSound(target, mobjinfo[MT_PITY_ICON].seesound);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Tag handling
|
||||
|
@ -2913,7 +2944,15 @@ static inline boolean P_PlayerHitsPlayer(mobj_t *target, mobj_t *inflictor, mobj
|
|||
// unless cv_friendlyfire is on.
|
||||
if (!cv_friendlyfire.value && target->player->ctfteam == source->player->ctfteam)
|
||||
{
|
||||
if (!(inflictor->flags & MF_FIRE))
|
||||
if (inflictor->type == MT_LHRT && !(player->powers[pw_shield] & SH_NOSTACK))
|
||||
{
|
||||
if (player->spinitem != MT_LHRT && player->revitem != MT_LHRT && player->thokitem != MT_LHRT) // Healers do not get to heal other healers.
|
||||
{
|
||||
P_SwitchShield(player, SH_PINK);
|
||||
S_StartSound(target, mobjinfo[MT_PITY_ICON].seesound);
|
||||
}
|
||||
}
|
||||
else if (!(inflictor->flags & MF_FIRE))
|
||||
P_GivePlayerRings(target->player, 1);
|
||||
if (inflictor->flags2 & MF2_BOUNCERING)
|
||||
inflictor->fuse = 0; // bounce ring disappears at -1 not 0
|
||||
|
@ -2922,6 +2961,9 @@ static inline boolean P_PlayerHitsPlayer(mobj_t *target, mobj_t *inflictor, mobj
|
|||
}
|
||||
}
|
||||
|
||||
if (inflictor->type == MT_LHRT)
|
||||
return false;
|
||||
|
||||
// Add pity.
|
||||
if (!player->powers[pw_flashing] && !player->powers[pw_invulnerability] && !player->powers[pw_super]
|
||||
&& source->player->score > player->score)
|
||||
|
|
|
@ -1076,7 +1076,7 @@ static boolean PIT_CheckThing(mobj_t *thing)
|
|||
tmthing->y = thing->y;
|
||||
P_SetThingPosition(tmthing);
|
||||
}
|
||||
else if (!(tmthing->type == MT_SHELL && thing->player)) // player collision handled in touchspecial
|
||||
else if (!(tmthing->type == MT_SHELL && thing->player)) // player collision handled in touchspecial for shell
|
||||
{
|
||||
UINT8 damagetype = tmthing->info->mass;
|
||||
if (!damagetype && tmthing->flags & MF_FIRE) // BURN!
|
||||
|
|
|
@ -7861,6 +7861,10 @@ void P_MobjThinker(mobj_t *mobj)
|
|||
}
|
||||
}
|
||||
break;
|
||||
case MT_LHRT:
|
||||
mobj->momx = FixedMul(mobj->momx, (48*FRACUNIT)/50);
|
||||
mobj->momy = FixedMul(mobj->momy, (48*FRACUNIT)/50);
|
||||
break;
|
||||
case MT_EGGCAPSULE:
|
||||
if (!mobj->reactiontime)
|
||||
{
|
||||
|
@ -8547,6 +8551,9 @@ for (i = ((mobj->flags2 & MF2_STRONGBOX) ? strongboxamt : weakboxamt); i; --i) s
|
|||
case MT_CYBRAKDEMON_NAPALM_BOMB_LARGE:
|
||||
P_SetMobjState(mobj, mobj->info->deathstate);
|
||||
break;
|
||||
case MT_LHRT:
|
||||
P_KillMobj(mobj, NULL, NULL, 0);
|
||||
break;
|
||||
case MT_BLUEFLAG:
|
||||
case MT_REDFLAG:
|
||||
if (mobj->spawnpoint)
|
||||
|
|
51
src/p_user.c
51
src/p_user.c
|
@ -1609,6 +1609,7 @@ void P_SpawnShieldOrb(player_t *player)
|
|||
orbtype = MT_ARMAGEDDON_ORB;
|
||||
break;
|
||||
case SH_PITY:
|
||||
case SH_PINK: // PITY IN PINK
|
||||
orbtype = MT_PITY_ORB;
|
||||
break;
|
||||
case SH_FLAMEAURA:
|
||||
|
@ -1639,7 +1640,13 @@ void P_SpawnShieldOrb(player_t *player)
|
|||
shieldobj = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, orbtype);
|
||||
shieldobj->flags2 |= MF2_SHIELD;
|
||||
P_SetTarget(&shieldobj->target, player->mo);
|
||||
shieldobj->color = (UINT8)shieldobj->info->painchance;
|
||||
if ((player->powers[pw_shield] & SH_NOSTACK) == SH_PINK)
|
||||
{
|
||||
shieldobj->color = SKINCOLOR_PINK;
|
||||
shieldobj->colorized = true;
|
||||
}
|
||||
else
|
||||
shieldobj->color = (UINT8)shieldobj->info->painchance;
|
||||
shieldobj->threshold = (player->powers[pw_shield] & SH_FORCE) ? SH_FORCE : (player->powers[pw_shield] & SH_NOSTACK);
|
||||
|
||||
if (shieldobj->info->seestate)
|
||||
|
@ -1787,6 +1794,9 @@ void P_SpawnThokMobj(player_t *player)
|
|||
if (player->spectator)
|
||||
return;
|
||||
|
||||
if (!type)
|
||||
return;
|
||||
|
||||
if (type == MT_GHOST)
|
||||
mobj = P_SpawnGhostMobj(player->mo); // virtually does everything here for us
|
||||
else
|
||||
|
@ -1847,6 +1857,9 @@ void P_SpawnSpinMobj(player_t *player, mobjtype_t type)
|
|||
if (player->spectator)
|
||||
return;
|
||||
|
||||
if (!type)
|
||||
return;
|
||||
|
||||
if (type == MT_GHOST)
|
||||
mobj = P_SpawnGhostMobj(player->mo); // virtually does everything here for us
|
||||
else
|
||||
|
@ -2002,10 +2015,42 @@ boolean P_PlayerHitFloor(player_t *player)
|
|||
}
|
||||
else if (player->charability2 == CA2_MELEE && (player->panim == PA_ABILITY2 && player->mo->state-states != S_PLAY_MELEE_LANDING))
|
||||
{
|
||||
mobjtype_t type = player->spinitem;
|
||||
P_SetPlayerMobjState(player->mo, S_PLAY_MELEE_LANDING);
|
||||
player->mo->tics = (player->mo->movefactor == FRACUNIT) ? TICRATE/2 : (FixedDiv(35<<(FRACBITS-1), FixedSqrt(player->mo->movefactor)))>>FRACBITS;
|
||||
S_StartSound(player->mo, sfx_s3k8b);
|
||||
player->pflags |= PF_FULLSTASIS;
|
||||
|
||||
// hearticles
|
||||
if (type)
|
||||
{
|
||||
UINT8 i = 0;
|
||||
angle_t throwang = -(2*ANG30);
|
||||
fixed_t xo = P_ReturnThrustX(player->mo, player->drawangle, 16*player->mo->scale);
|
||||
fixed_t yo = P_ReturnThrustY(player->mo, player->drawangle, 16*player->mo->scale);
|
||||
fixed_t zo = 6*player->mo->scale;
|
||||
fixed_t mu = FixedMul(player->maxdash, player->mo->scale);
|
||||
fixed_t mu2 = FixedHypot(player->mo->momx, player->mo->momy);
|
||||
mobj_t *missile;
|
||||
if (mu2 < mu)
|
||||
mu2 = mu;
|
||||
while (i < 5)
|
||||
{
|
||||
missile = P_SpawnMobjFromMobj(player->mo, xo, yo, zo, type);
|
||||
P_SetTarget(&missile->target, player->mo);
|
||||
missile->angle = throwang + player->drawangle;
|
||||
P_Thrust(missile, player->drawangle + ANGLE_90,
|
||||
P_ReturnThrustY(missile, throwang, mu)); // side to side component
|
||||
P_Thrust(missile, player->drawangle, mu2); // forward component
|
||||
P_SetObjectMomZ(missile, (4 + ((i&1)<<1))*FRACUNIT, true);
|
||||
missile->fuse = TICRATE/2;
|
||||
|
||||
i++;
|
||||
throwang += ANG30;
|
||||
}
|
||||
if (mobjinfo[type].seesound)
|
||||
S_StartSound(missile, missile->info->seesound);
|
||||
}
|
||||
}
|
||||
else if (player->pflags & PF_JUMPED || !(player->pflags & PF_SPINNING)
|
||||
|| player->powers[pw_tailsfly] || player->mo->state-states == S_PLAY_FLY_TIRED)
|
||||
|
@ -9806,12 +9851,12 @@ void P_DoPityCheck(player_t *player)
|
|||
// Apply pity shield if available.
|
||||
if ((player->pity >= 3 || player->pity < 0) && player->powers[pw_shield] == SH_NONE)
|
||||
{
|
||||
P_SwitchShield(player, SH_PITY);
|
||||
|
||||
if (player->pity > 0)
|
||||
S_StartSound(player->mo, mobjinfo[MT_PITY_ICON].seesound);
|
||||
|
||||
player->pity = 0;
|
||||
player->powers[pw_shield] = SH_PITY;
|
||||
P_SpawnShieldOrb(player);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2704,6 +2704,9 @@ void SetPlayerSkinByNum(INT32 playernum, INT32 skinnum)
|
|||
player->revitem = skin->revitem < 0 ? (mobjtype_t)mobjinfo[MT_PLAYER].raisestate : (UINT32)skin->revitem;
|
||||
player->followitem = skin->followitem;
|
||||
|
||||
if (((player->powers[pw_shield] & SH_NOSTACK) == SH_PINK) && (player->spinitem == MT_LHRT)) // Healers can't keep their buff.
|
||||
player->powers[pw_shield] &= SH_STACK;
|
||||
|
||||
player->actionspd = skin->actionspd;
|
||||
player->mindash = skin->mindash;
|
||||
player->maxdash = skin->maxdash;
|
||||
|
|
Loading…
Reference in a new issue