Merge branch 'shield-actions' into 'master'

Shield actions

The branch is basically complete, I just need to figure out the best way to have the whirlwind shield let the player know you can use it.

SRB2 shields:
* WHIRLWIND SHIELD - It's like King Dedede. You can't improve on perfection. (Might get some new sprites as tells for being able to use it, though.)
* ARMAGEDDON SHIELD - Create a bomb burst whenever you pick up another of the same shield FOR FREE!
* MAGNETIC SHIELD - Homing attack towards enemies only, no stopping when you hit 'em, no zooming off if you're not near enemies.
* ELEMENTAL SHIELD - Perform a piercing stomp that rips through enemies (that don't have spikes on their heads) and creates a fire burst when you land above water.
* FORCE SHIELD - Perfect stop in midair.

S3NK shields:
* FLAME SHIELD - Additive thok on the spin button.
* BUBBLE SHIELD - Bubble bounce to 1.5*jumpheight (also rips through enemies).
* THUNDER SHIELD - Double jump, but with no uncurl and a twang noise.

Supers don't have access to shield actives. Characters with thok can superfloat like usual.

New Lua hooks:
* "ShieldSpawn" in the form function(player), hooks into P_SpawnShieldOrb.
* "ShieldSpecial" in the form function(player), hooks into the shield activation code.

See merge request !31
This commit is contained in:
Monster Iestyn 2016-12-13 17:06:29 -05:00
commit 46afe9b3e0
21 changed files with 1742 additions and 426 deletions

View file

@ -152,7 +152,13 @@ typedef enum
PF_ANALOGMODE = 1<<26, // Analog mode?
// Can carry another player?
PF_CANCARRY = 1<<27
PF_CANCARRY = 1<<27,
// Used shield ability
PF_SHIELDABILITY = 1<<28,
// Force jump damage?
PF_FORCEJUMPDAMAGE = 1<<29
// free up to and including 1<<31
} pflags_t;
@ -179,23 +185,34 @@ typedef enum
typedef enum
{
SH_NONE = 0,
// Standard shields
SH_JUMP,
SH_ATTRACT,
SH_ELEMENTAL,
SH_BOMB,
// Stupid useless unimplimented Sonic 3 shields
SH_BUBBLEWRAP,
SH_THUNDERCOIN,
SH_FLAMEAURA,
// Pity shield: the world's most basic shield ever, given to players who suck at Match
SH_PITY,
// The fireflower is special, it combines with other shields.
SH_FIREFLOWER = 0x100,
// The force shield uses the lower 8 bits to count how many hits are left.
SH_FORCE = 0x200,
SH_STACK = SH_FIREFLOWER,
// Shield flags
SH_PROTECTFIRE = 0x400,
SH_PROTECTWATER = 0x800,
SH_PROTECTELECTRIC = 0x1000,
// Indivisible shields
SH_PITY = 1, // the world's most basic shield ever, given to players who suck at Match
SH_WHIRLWIND,
SH_ARMAGEDDON,
// normal shields that use flags
SH_ATTRACT = SH_PROTECTELECTRIC,
SH_ELEMENTAL = SH_PROTECTFIRE|SH_PROTECTWATER,
// Sonic 3 shields
SH_FLAMEAURA = SH_PROTECTFIRE,
SH_BUBBLEWRAP = SH_PROTECTWATER,
SH_THUNDERCOIN = SH_WHIRLWIND|SH_PROTECTELECTRIC,
// The force shield uses the lower 8 bits to count how many extra hits are left.
SH_FORCE = 0x100,
SH_FORCEHP = 0xFF, // to be used as a bitmask only
// Mostly for use with Mario mode.
SH_FIREFLOWER = 0x200,
SH_STACK = SH_FIREFLOWER, // second-layer shields
SH_NOSTACK = ~SH_STACK
} shieldtype_t; // pw_shield
@ -360,8 +377,8 @@ typedef struct player_s
UINT8 gotcontinue; // Got continue from this stage?
fixed_t speed; // Player's speed (distance formula of MOMX and MOMY values)
UINT8 jumping; // Jump counter
UINT8 secondjump;
UINT8 jumping; // Holding down jump button
UINT8 secondjump; // Jump counter
UINT8 fly1; // Tails flying
UINT8 scoreadd; // Used for multiple enemy attack bonus

View file

@ -1687,6 +1687,9 @@ static actionpointer_t actionpointers[] =
{{A_WaterShield}, "A_WATERSHIELD"},
{{A_ForceShield}, "A_FORCESHIELD"},
{{A_PityShield}, "A_PITYSHIELD"},
{{A_FlameShield}, "A_FLAMESHIELD"},
{{A_BubbleShield}, "A_BUBBLESHIELD"},
{{A_ThunderShield}, "A_THUNDERSHIELD"},
{{A_GravityBox}, "A_GRAVITYBOX"},
{{A_ScoreRise}, "A_SCORERISE"},
{{A_ParticleSpawn}, "A_PARTICLESPAWN"},
@ -4834,7 +4837,7 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
"S_SPIKEBALL7",
"S_SPIKEBALL8",
// Fire Shield's Spawn
// Elemental Shield's Spawn
"S_SPINFIRE1",
"S_SPINFIRE2",
"S_SPINFIRE3",
@ -4908,6 +4911,9 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
"S_RECYCLER_BOX",
"S_SCORE1K_BOX",
"S_SCORE10K_BOX",
"S_FLAMEAURA_BOX",
"S_BUBBLEWRAP_BOX",
"S_THUNDERCOIN_BOX",
// Gold Repeat Monitor States (one per box)
"S_PITY_GOLDBOX",
@ -4920,6 +4926,9 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
"S_INVULN_GOLDBOX",
"S_EGGMAN_GOLDBOX",
"S_GRAVITY_GOLDBOX",
"S_FLAMEAURA_GOLDBOX",
"S_BUBBLEWRAP_GOLDBOX",
"S_THUNDERCOIN_GOLDBOX",
// Team Ring Boxes (these are special)
"S_RING_REDBOX1",
@ -4981,6 +4990,15 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
"S_SCORE10K_ICON1",
"S_SCORE10K_ICON2",
"S_FLAMEAURA_ICON1",
"S_FLAMEAURA_ICON2",
"S_BUBBLEWRAP_ICON1",
"S_BUBBLEWRAP_ICON2",
"S_THUNDERCOIN_ICON1",
"S_THUNDERCOIN_ICON2",
"S_ROCKET",
"S_LASER",
@ -5350,6 +5368,7 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
"S_MAGN10",
"S_MAGN11",
"S_MAGN12",
"S_MAGN13",
"S_FORC1",
"S_FORC2",
@ -5373,6 +5392,8 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
"S_FORC19",
"S_FORC20",
"S_FORC21",
"S_ELEM1",
"S_ELEM2",
"S_ELEM3",
@ -5386,6 +5407,9 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
"S_ELEM11",
"S_ELEM12",
"S_ELEM13",
"S_ELEM14",
"S_ELEMF1",
"S_ELEMF2",
"S_ELEMF3",
@ -5394,6 +5418,8 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
"S_ELEMF6",
"S_ELEMF7",
"S_ELEMF8",
"S_ELEMF9",
"S_ELEMF10",
"S_PITY1",
"S_PITY2",
@ -5406,6 +5432,84 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
"S_PITY9",
"S_PITY10",
"S_FIRS1",
"S_FIRS2",
"S_FIRS3",
"S_FIRS4",
"S_FIRS5",
"S_FIRS6",
"S_FIRS7",
"S_FIRS8",
"S_FIRS9",
"S_FIRS10",
"S_FIRS11",
"S_FIRSB1",
"S_FIRSB2",
"S_FIRSB3",
"S_FIRSB4",
"S_FIRSB5",
"S_FIRSB6",
"S_FIRSB7",
"S_FIRSB8",
"S_FIRSB9",
"S_FIRSB10",
"S_BUBS1",
"S_BUBS2",
"S_BUBS3",
"S_BUBS4",
"S_BUBS5",
"S_BUBS6",
"S_BUBS7",
"S_BUBS8",
"S_BUBS9",
"S_BUBS10",
"S_BUBS11",
"S_BUBSB1",
"S_BUBSB2",
"S_BUBSB3",
"S_BUBSB4",
"S_BUBSB5",
"S_BUBSB6",
"S_ZAPS1",
"S_ZAPS2",
"S_ZAPS3",
"S_ZAPS4",
"S_ZAPS5",
"S_ZAPS6",
"S_ZAPS7",
"S_ZAPS8",
"S_ZAPS9",
"S_ZAPS10",
"S_ZAPS11",
"S_ZAPS12",
"S_ZAPS13", // blank frame
"S_ZAPS14",
"S_ZAPS15",
"S_ZAPS16",
"S_ZAPSB1", // blank frame
"S_ZAPSB2",
"S_ZAPSB3",
"S_ZAPSB4",
"S_ZAPSB5",
"S_ZAPSB6",
"S_ZAPSB7",
"S_ZAPSB8",
"S_ZAPSB9",
"S_ZAPSB10",
"S_ZAPSB11", // blank frame
// Thunder spark
"S_THUNDERCOIN_SPARK",
// Invincibility Sparkles
"S_IVSP",
@ -6178,6 +6282,9 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s
"MT_RECYCLER_BOX",
"MT_SCORE1K_BOX",
"MT_SCORE10K_BOX",
"MT_FLAMEAURA_BOX",
"MT_BUBBLEWRAP_BOX",
"MT_THUNDERCOIN_BOX",
// Monitor boxes -- repeating (big) boxes
"MT_PITY_GOLDBOX",
@ -6190,6 +6297,9 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s
"MT_INVULN_GOLDBOX",
"MT_EGGMAN_GOLDBOX",
"MT_GRAVITY_GOLDBOX",
"MT_FLAMEAURA_GOLDBOX",
"MT_BUBBLEWRAP_GOLDBOX",
"MT_THUNDERCOIN_GOLDBOX",
// Monitor boxes -- special
"MT_RING_REDBOX",
@ -6212,6 +6322,9 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s
"MT_RECYCLER_ICON",
"MT_SCORE1K_ICON",
"MT_SCORE10K_ICON",
"MT_FLAMEAURA_ICON",
"MT_BUBBLEWRAP_ICON",
"MT_THUNDERCOIN_ICON",
// Projectiles
"MT_ROCKET",
@ -6364,13 +6477,17 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s
"MT_EGGSTATUE2",
// Powerup Indicators
"MT_GREENORB", // Elemental shield mobj
"MT_YELLOWORB", // Attract shield mobj
"MT_BLUEORB", // Force shield mobj
"MT_BLACKORB", // Armageddon shield mobj
"MT_WHITEORB", // Whirlwind shield mobj
"MT_PITYORB", // Pity shield mobj
"MT_IVSP", // invincibility sparkles
"MT_ELEMENTAL_ORB", // Elemental shield mobj
"MT_ATTRACT_ORB", // Attract shield mobj
"MT_FORCE_ORB", // Force shield mobj
"MT_ARMAGEDDON_ORB", // Armageddon shield mobj
"MT_WHIRLWIND_ORB", // Whirlwind shield mobj
"MT_PITY_ORB", // Pity shield mobj
"MT_FLAMEAURA_ORB", // Flame shield mobj
"MT_BUBBLEWRAP_ORB", // Bubble shield mobj
"MT_THUNDERCOIN_ORB", // Thunder shield mobj
"MT_THUNDERCOIN_SPARK", // Thunder spark
"MT_IVSP", // Invincibility sparkles
"MT_SUPERSPARK", // Super Sonic Spark
// Freed Animals
@ -6559,35 +6676,36 @@ static const char *const MOBJFLAG_LIST[] = {
// \tMF2_(\S+).*// (.+) --> \t"\1", // \2
static const char *const MOBJFLAG2_LIST[] = {
"AXIS", // It's a NiGHTS axis! (For faster checking)
"TWOD", // Moves like it's in a 2D level
"DONTRESPAWN", // Don't respawn this object!
"DONTDRAW", // Don't generate a vissprite
"AUTOMATIC", // Thrown ring has automatic properties
"RAILRING", // Thrown ring has rail properties
"BOUNCERING", // Thrown ring has bounce properties
"EXPLOSION", // Thrown ring has explosive properties
"SCATTER", // Thrown ring has scatter properties
"BEYONDTHEGRAVE",// Source of this missile has died and has since respawned.
"SLIDEPUSH", // MF_PUSHABLE that pushes continuously.
"CLASSICPUSH", // Drops straight down when object has negative Z.
"STANDONME", // While not pushable, stand on me anyway.
"INFLOAT", // Floating to a height for a move, don't auto float to target's height.
"DEBRIS", // Splash ring from explosion ring
"NIGHTSPULL", // Attracted from a paraloop
"JUSTATTACKED", // can be pushed by other moving mobjs
"FIRING", // turret fire
"SUPERFIRE", // Firing something with Super Sonic-stopping properties. Or, if mobj has MF_MISSILE, this is the actual fire from it.
"SHADOW", // Fuzzy draw, makes targeting harder.
"STRONGBOX", // Flag used for "strong" random monitors.
"OBJECTFLIP", // Flag for objects that always have flipped gravity.
"SKULLFLY", // Special handling: skull in flight.
"FRET", // Flashing from a previous hit
"BOSSNOTRAP", // No Egg Trap after boss
"BOSSFLEE", // Boss is fleeing!
"BOSSDEAD", // Boss is dead! (Not necessarily fleeing, if a fleeing point doesn't exist.)
"AMBUSH", // Alternate behaviour typically set by MTF_AMBUSH
"LINKDRAW", // Draw vissprite of mobj immediately before/after tracer's vissprite (dependent on dispoffset and position)
"AXIS", // It's a NiGHTS axis! (For faster checking)
"TWOD", // Moves like it's in a 2D level
"DONTRESPAWN", // Don't respawn this object!
"DONTDRAW", // Don't generate a vissprite
"AUTOMATIC", // Thrown ring has automatic properties
"RAILRING", // Thrown ring has rail properties
"BOUNCERING", // Thrown ring has bounce properties
"EXPLOSION", // Thrown ring has explosive properties
"SCATTER", // Thrown ring has scatter properties
"BEYONDTHEGRAVE", // Source of this missile has died and has since respawned.
"SLIDEPUSH", // MF_PUSHABLE that pushes continuously.
"CLASSICPUSH", // Drops straight down when object has negative Z.
"STANDONME", // While not pushable, stand on me anyway.
"INFLOAT", // Floating to a height for a move, don't auto float to target's height.
"DEBRIS", // Splash ring from explosion ring
"NIGHTSPULL", // Attracted from a paraloop
"JUSTATTACKED", // can be pushed by other moving mobjs
"FIRING", // turret fire
"SUPERFIRE", // Firing something with Super Sonic-stopping properties. Or, if mobj has MF_MISSILE, this is the actual fire from it.
"SHADOW", // Fuzzy draw, makes targeting harder.
"STRONGBOX", // Flag used for "strong" random monitors.
"OBJECTFLIP", // Flag for objects that always have flipped gravity.
"SKULLFLY", // Special handling: skull in flight.
"FRET", // Flashing from a previous hit
"BOSSNOTRAP", // No Egg Trap after boss
"BOSSFLEE", // Boss is fleeing!
"BOSSDEAD", // Boss is dead! (Not necessarily fleeing, if a fleeing point doesn't exist.)
"AMBUSH", // Alternate behaviour typically set by MTF_AMBUSH
"LINKDRAW", // Draw vissprite of mobj immediately before/after tracer's vissprite (dependent on dispoffset and position)
"SHIELD", // Thinker calls P_AddShield/P_ShieldLook (must be partnered with MF_SCENERY to use)
NULL
};
@ -6669,6 +6787,9 @@ static const char *const PLAYERFLAG_LIST[] = {
/*** misc ***/
"FORCESTRAFE", // Translate turn inputs into strafe inputs
"ANALOGMODE", // Analog mode?
"CANCARRY", // Can carry?
"SHIELDABILITY", // Thokked with shield ability
"FORCEJUMPDAMAGE", // Force jump damage
NULL // stop loop here.
};
@ -7013,20 +7134,27 @@ struct {
{"PRECIP_STORM_NOSTRIKES",PRECIP_STORM_NOSTRIKES},
// Shields
// These ones use the lower 8 bits
{"SH_NONE",SH_NONE},
{"SH_JUMP",SH_JUMP},
// Shield flags
{"SH_PROTECTFIRE",SH_PROTECTFIRE},
{"SH_PROTECTWATER",SH_PROTECTWATER},
{"SH_PROTECTELECTRIC",SH_PROTECTELECTRIC},
// Indivisible shields
{"SH_PITY",SH_PITY},
{"SH_WHIRLWIND",SH_WHIRLWIND},
{"SH_ARMAGEDDON",SH_ARMAGEDDON},
// normal shields that use flags
{"SH_ATTRACT",SH_ATTRACT},
{"SH_ELEMENTAL",SH_ELEMENTAL},
{"SH_BOMB",SH_BOMB},
// Sonic 3 shields
{"SH_FLAMEAURA",SH_FLAMEAURA},
{"SH_BUBBLEWRAP",SH_BUBBLEWRAP},
{"SH_THUNDERCOIN",SH_THUNDERCOIN},
{"SH_FLAMEAURA",SH_FLAMEAURA},
{"SH_PITY",SH_PITY},
// These ones are special and use the upper bits
{"SH_FIREFLOWER",SH_FIREFLOWER}, // Lower bits are a normal shield stacked on top of the fire flower
{"SH_FORCE",SH_FORCE}, // Lower bits are how many hits left, 0 is the last hit
// Stack masks
// The force shield uses the lower 8 bits to count how many extra hits are left.
{"SH_FORCE",SH_FORCE},
{"SH_FORCEHP",SH_FORCEHP}, // to be used as a bitmask only
// Mostly for use with Mario mode.
{"SH_FIREFLOWER", SH_FIREFLOWER},
{"SH_STACK",SH_STACK},
{"SH_NOSTACK",SH_NOSTACK},

View file

@ -271,6 +271,9 @@ light_t *t_lspr[NUMSPRITES] =
&lspr[NOLIGHT], // SPR_TVRC
&lspr[NOLIGHT], // SPR_TV1K
&lspr[NOLIGHT], // SPR_TVTK
&lspr[NOLIGHT], // SPR_TVFL
&lspr[NOLIGHT], // SPR_TVBB
&lspr[NOLIGHT], // SPR_TVZP
// Projectiles
&lspr[NOLIGHT], // SPR_MISL
@ -359,6 +362,9 @@ light_t *t_lspr[NUMSPRITES] =
&lspr[NOLIGHT], // SPR_ELEM
&lspr[NOLIGHT], // SPR_FORC
&lspr[NOLIGHT], // SPR_PITY
&lspr[NOLIGHT], // SPR_FIRS
&lspr[NOLIGHT], // SPR_BUBS
&lspr[NOLIGHT], // SPR_ZAPS
&lspr[INVINCIBLE_L], // SPR_IVSP
&lspr[SUPERSPARK_L], // SPR_SSPK

View file

@ -159,6 +159,9 @@ char sprnames[NUMSPRITES + 1][5] =
"TVRC", // ReCycler
"TV1K", // 1,000 points (1 K)
"TVTK", // 10,000 points (Ten K)
"TVFL", // FLame shield
"TVBB", // BuBble shield
"TVZP", // Thunder shield (ZaP)
// Projectiles
"MISL",
@ -243,6 +246,9 @@ char sprnames[NUMSPRITES + 1][5] =
"ELEM", // Elemental Shield Orb and Fire
"FORC", // Force Shield Orb
"PITY", // Pity Shield Orb
"FIRS", // Flame Shield Orb
"BUBS", // Bubble Shield Orb
"ZAPS", // Thunder Shield Orb
"IVSP", // invincibility sparkles
"SSPK", // Super Sonic Spark
@ -1534,7 +1540,7 @@ state_t states[NUMSTATES] =
{SPR_SPIK, 6, 1, {A_RotateSpikeBall}, 0, 0, S_SPIKEBALL8}, // S_SPIKEBALL7
{SPR_SPIK, 7, 1, {A_RotateSpikeBall}, 0, 0, S_SPIKEBALL1}, // S_SPIKEBALL8
// Red Shield's Spawn
// Elemental Shield's Spawn
{SPR_SFLM, FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_SPINFIRE2}, // S_SPINFIRE1
{SPR_SFLM, FF_FULLBRIGHT|1, 2, {NULL}, 0, 0, S_SPINFIRE3}, // S_SPINFIRE2
{SPR_SFLM, FF_FULLBRIGHT|2, 2, {NULL}, 0, 0, S_SPINFIRE4}, // S_SPINFIRE3
@ -1608,6 +1614,9 @@ state_t states[NUMSTATES] =
{SPR_TVRC, 0, 2, {NULL}, 0, 0, S_BOX_FLICKER}, // S_RECYCLER_BOX
{SPR_TV1K, 0, 2, {NULL}, 0, 0, S_BOX_FLICKER}, // S_SCORE1K_BOX
{SPR_TVTK, 0, 2, {NULL}, 0, 0, S_BOX_FLICKER}, // S_SCORE10K_BOX
{SPR_TVFL, 0, 2, {NULL}, 0, 0, S_BOX_FLICKER}, // S_FLAMEAURA_BOX
{SPR_TVBB, 0, 2, {NULL}, 0, 0, S_BOX_FLICKER}, // S_BUBBLEWRAP_BOX
{SPR_TVZP, 0, 2, {NULL}, 0, 0, S_BOX_FLICKER}, // S_THUNDERCOIN_BOX
// Gold Repeat Monitor States (one per box)
{SPR_TVPI, 1, 2, {A_GoldMonitorSparkle}, 0, 0, S_GOLDBOX_FLICKER}, // S_PITY_GOLDBOX
@ -1620,6 +1629,9 @@ state_t states[NUMSTATES] =
{SPR_TVIV, 1, 2, {A_GoldMonitorSparkle}, 0, 0, S_GOLDBOX_FLICKER}, // S_INVULN_GOLDBOX
{SPR_TVEG, 1, 2, {A_GoldMonitorSparkle}, 0, 0, S_GOLDBOX_FLICKER}, // S_EGGMAN_GOLDBOX
{SPR_TVGV, 1, 2, {A_GoldMonitorSparkle}, 0, 0, S_GOLDBOX_FLICKER}, // S_GRAVITY_GOLDBOX
{SPR_TVFL, 1, 2, {A_GoldMonitorSparkle}, 0, 0, S_GOLDBOX_FLICKER}, // S_FLAMEAURA_GOLDBOX
{SPR_TVBB, 1, 2, {A_GoldMonitorSparkle}, 0, 0, S_GOLDBOX_FLICKER}, // S_BUBBLEWRAP_GOLDBOX
{SPR_TVZP, 1, 2, {A_GoldMonitorSparkle}, 0, 0, S_GOLDBOX_FLICKER}, // S_THUNDERCOIN_GOLDBOX
// Team Ring Boxes (these are special)
{SPR_TRRI, 0, 2, {NULL}, 0, 0, S_RING_REDBOX2}, // S_RING_REDBOX1
@ -1643,7 +1655,7 @@ state_t states[NUMSTATES] =
{SPR_TVAT, 2, 18, {A_RingShield},0, 0, S_NULL}, // S_ATTRACT_ICON2
{SPR_TVFO, FF_ANIMATE|2, 18, {NULL}, 3, 4, S_FORCE_ICON2}, // S_FORCE_ICON1
{SPR_TVFO, 2, 18, {A_ForceShield}, 0, 0, S_NULL}, // S_FORCE_ICON2
{SPR_TVFO, 2, 18, {A_ForceShield}, 1, 0, S_NULL}, // S_FORCE_ICON2
{SPR_TVAR, FF_ANIMATE|2, 18, {NULL}, 3, 4, S_ARMAGEDDON_ICON2}, // S_ARMAGEDDON_ICON1
{SPR_TVAR, 2, 18, {A_BombShield}, 0, 0, S_NULL}, // S_ARMAGEDDON_ICON2
@ -1681,6 +1693,15 @@ state_t states[NUMSTATES] =
{SPR_TVTK, FF_ANIMATE|2, 18, {NULL}, 3, 4, S_SCORE10K_ICON2}, // S_SCORE10K_ICON1
{SPR_TVTK, 2, 18, {A_AwardScore}, 0, 0, S_NULL}, // S_SCORE10K_ICON2
{SPR_TVFL, FF_ANIMATE|2, 18, {NULL}, 3, 4, S_FLAMEAURA_ICON2}, // S_FLAMEAURA_ICON1
{SPR_TVFL, 2, 18, {A_FlameShield}, 0, 0, S_NULL}, // S_FLAMEAURA_ICON2
{SPR_TVBB, FF_ANIMATE|2, 18, {NULL}, 3, 4, S_BUBBLEWRAP_ICON2}, // S_BUBBLEWRAP_ICON1
{SPR_TVBB, 2, 18, {A_BubbleShield}, 0, 0, S_NULL}, // S_BUBBLERWAP_ICON2
{SPR_TVZP, FF_ANIMATE|2, 18, {NULL}, 3, 4, S_THUNDERCOIN_ICON2}, // S_THUNDERCOIN_ICON1
{SPR_TVZP, 2, 18, {A_ThunderShield}, 0, 0, S_NULL}, // S_THUNDERCOIN_ICON2
// ---
{SPR_MISL, FF_FULLBRIGHT, 1, {A_SmokeTrailer}, MT_SMOKE, 0, S_ROCKET}, // S_ROCKET
@ -2061,6 +2082,8 @@ state_t states[NUMSTATES] =
{SPR_MAGN, FF_FULLBRIGHT|FF_TRANS40|10, 2, {NULL}, 0, 0, S_MAGN12}, // S_MAGN11
{SPR_MAGN, FF_FULLBRIGHT|FF_TRANS40|11, 2, {NULL}, 0, 0, S_MAGN1 }, // S_MAGN12
{SPR_MAGN, FF_FULLBRIGHT|FF_TRANS10|12, 2, {NULL}, 0, 0, S_MAGN1 }, // S_MAGN13
{SPR_FORC, FF_TRANS50 , 3, {NULL}, 0, 0, S_FORC2 }, // S_FORC1
{SPR_FORC, FF_TRANS50|1, 3, {NULL}, 0, 0, S_FORC3 }, // S_FORC2
{SPR_FORC, FF_TRANS50|2, 3, {NULL}, 0, 0, S_FORC4 }, // S_FORC3
@ -2083,6 +2106,8 @@ state_t states[NUMSTATES] =
{SPR_FORC, FF_TRANS50|18, 3, {NULL}, 0, 0, S_FORC20}, // S_FORC19
{SPR_FORC, FF_TRANS50|19, 3, {NULL}, 0, 0, S_FORC11}, // S_FORC20
{SPR_FORC, FF_TRANS50|20, -1, {NULL}, 0, 0, S_NULL}, // S_FORC21
{SPR_ELEM, FF_TRANS50 , 4, {NULL}, 0, 0, S_ELEM2 }, // S_ELEM1
{SPR_ELEM, FF_TRANS50| 1, 4, {NULL}, 0, 0, S_ELEM3 }, // S_ELEM2
{SPR_ELEM, FF_TRANS50| 2, 4, {NULL}, 0, 0, S_ELEM4 }, // S_ELEM3
@ -2096,14 +2121,20 @@ state_t states[NUMSTATES] =
{SPR_ELEM, FF_TRANS50|10, 4, {NULL}, 0, 0, S_ELEM12}, // S_ELEM11
{SPR_ELEM, FF_TRANS50|11, 4, {NULL}, 0, 0, S_ELEM1 }, // S_ELEM12
{SPR_ELEM, FF_FULLBRIGHT|12, 3, {NULL}, 0, 0, S_ELEMF2}, // S_ELEMF1
{SPR_ELEM, FF_FULLBRIGHT|13, 3, {NULL}, 0, 0, S_ELEMF3}, // S_ELEMF2
{SPR_ELEM, FF_FULLBRIGHT|14, 3, {NULL}, 0, 0, S_ELEMF4}, // S_ELEMF3
{SPR_ELEM, FF_FULLBRIGHT|15, 3, {NULL}, 0, 0, S_ELEMF5}, // S_ELEMF4
{SPR_ELEM, FF_FULLBRIGHT|16, 3, {NULL}, 0, 0, S_ELEMF6}, // S_ELEMF5
{SPR_ELEM, FF_FULLBRIGHT|17, 3, {NULL}, 0, 0, S_ELEMF7}, // S_ELEMF6
{SPR_ELEM, FF_FULLBRIGHT|18, 3, {NULL}, 0, 0, S_ELEMF8}, // S_ELEMF7
{SPR_ELEM, FF_FULLBRIGHT|19, 3, {NULL}, 0, 0, S_ELEMF1}, // S_ELEMF8
{SPR_NULL, 0, 1, {NULL}, 0, 0, S_ELEM14}, // S_ELEM13
{SPR_ELEM, FF_TRANS50|11, 1, {NULL}, 0, 0, S_ELEM1 }, // S_ELEM14
{SPR_ELEM, FF_FULLBRIGHT|12, 3, {NULL}, 0, 0, S_ELEMF2 }, // S_ELEMF1
{SPR_ELEM, FF_FULLBRIGHT|13, 3, {NULL}, 0, 0, S_ELEMF3 }, // S_ELEMF2
{SPR_ELEM, FF_FULLBRIGHT|14, 3, {NULL}, 0, 0, S_ELEMF4 }, // S_ELEMF3
{SPR_ELEM, FF_FULLBRIGHT|15, 3, {NULL}, 0, 0, S_ELEMF5 }, // S_ELEMF4
{SPR_ELEM, FF_FULLBRIGHT|16, 3, {NULL}, 0, 0, S_ELEMF6 }, // S_ELEMF5
{SPR_ELEM, FF_FULLBRIGHT|17, 3, {NULL}, 0, 0, S_ELEMF7 }, // S_ELEMF6
{SPR_ELEM, FF_FULLBRIGHT|18, 3, {NULL}, 0, 0, S_ELEMF8 }, // S_ELEMF7
{SPR_ELEM, FF_FULLBRIGHT|19, 3, {NULL}, 0, 0, S_ELEMF1 }, // S_ELEMF8
{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_TRANS20 , 1, {NULL}, 0, 0, S_PITY2 }, // S_PITY1
{SPR_PITY, FF_TRANS20|1, 1, {NULL}, 0, 0, S_PITY3 }, // S_PITY2
@ -2116,6 +2147,84 @@ state_t states[NUMSTATES] =
{SPR_PITY, FF_TRANS20 , 1, {NULL}, 0, 0, S_PITY10}, // S_PITY9
{SPR_PITY, FF_TRANS20|5, 1, {NULL}, 0, 0, S_PITY1 }, // S_PITY10
{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
{SPR_FIRS, FF_FULLBRIGHT|FF_TRANS40|2, 2, {NULL}, 0, 0, S_FIRS4}, // S_FIRS3
{SPR_FIRS, FF_FULLBRIGHT|FF_TRANS40|3, 2, {NULL}, 0, 0, S_FIRS5}, // S_FIRS4
{SPR_FIRS, FF_FULLBRIGHT|FF_TRANS40|4, 2, {NULL}, 0, 0, S_FIRS6}, // S_FIRS5
{SPR_FIRS, FF_FULLBRIGHT|FF_TRANS40|5, 2, {NULL}, 0, 0, S_FIRS7}, // S_FIRS6
{SPR_FIRS, FF_FULLBRIGHT|FF_TRANS40|6, 2, {NULL}, 0, 0, S_FIRS8}, // S_FIRS7
{SPR_FIRS, FF_FULLBRIGHT|FF_TRANS40|7, 2, {NULL}, 0, 0, S_FIRS9}, // S_FIRS8
{SPR_FIRS, FF_FULLBRIGHT|FF_TRANS40|8, 2, {NULL}, 0, 0, S_FIRS1}, // S_FIRS9
{SPR_FIRS, FF_FULLBRIGHT|FF_TRANS40|18, 1, {NULL}, 0, 0, S_FIRS11}, // S_FIRS10
{SPR_NULL, 0, 1, {NULL}, 0, 0, S_FIRS1 }, // S_FIRS11
{SPR_FIRS, FF_FULLBRIGHT|FF_TRANS40| 9, 2, {NULL}, 0, 0, S_FIRSB2}, // S_FIRSB1
{SPR_FIRS, FF_FULLBRIGHT|FF_TRANS40|10, 2, {NULL}, 0, 0, S_FIRSB3}, // S_FIRSB2
{SPR_FIRS, FF_FULLBRIGHT|FF_TRANS40|11, 2, {NULL}, 0, 0, S_FIRSB4}, // S_FIRSB3
{SPR_FIRS, FF_FULLBRIGHT|FF_TRANS40|12, 2, {NULL}, 0, 0, S_FIRSB5}, // S_FIRSB4
{SPR_FIRS, FF_FULLBRIGHT|FF_TRANS40|13, 2, {NULL}, 0, 0, S_FIRSB6}, // S_FIRSB5
{SPR_FIRS, FF_FULLBRIGHT|FF_TRANS40|14, 2, {NULL}, 0, 0, S_FIRSB7}, // S_FIRSB6
{SPR_FIRS, FF_FULLBRIGHT|FF_TRANS40|15, 2, {NULL}, 0, 0, S_FIRSB8}, // S_FIRSB7
{SPR_FIRS, FF_FULLBRIGHT|FF_TRANS40|16, 2, {NULL}, 0, 0, S_FIRSB9}, // S_FIRSB8
{SPR_FIRS, FF_FULLBRIGHT|FF_TRANS40|17, 2, {NULL}, 0, 0, S_FIRSB1}, // S_FIRSB9
{SPR_NULL, 0, 2, {NULL}, 0, 0, S_FIRSB1 }, // S_FIRSB10
{SPR_BUBS, FF_TRANS30 , 3, {NULL}, 0, 0, S_BUBS2}, // S_BUBS1
{SPR_BUBS, FF_TRANS30|1, 3, {NULL}, 0, 0, S_BUBS3}, // S_BUBS2
{SPR_BUBS, FF_TRANS30|2, 3, {NULL}, 0, 0, S_BUBS4}, // S_BUBS3
{SPR_BUBS, FF_TRANS30|3, 3, {NULL}, 0, 0, S_BUBS5}, // S_BUBS4
{SPR_BUBS, FF_TRANS30|4, 3, {NULL}, 0, 0, S_BUBS6}, // S_BUBS5
{SPR_BUBS, FF_TRANS30|5, 3, {NULL}, 0, 0, S_BUBS7}, // S_BUBS6
{SPR_BUBS, FF_TRANS30|6, 3, {NULL}, 0, 0, S_BUBS8}, // S_BUBS7
{SPR_BUBS, FF_TRANS30|7, 3, {NULL}, 0, 0, S_BUBS9}, // S_BUBS8
{SPR_BUBS, FF_TRANS30|8, 3, {NULL}, 0, 0, S_BUBS1}, // S_BUBS9
{SPR_NULL, 0, 3, {NULL}, 0, 0, S_BUBS1}, // S_BUBS10
{SPR_NULL, 0, 4*3, {NULL}, 0, 0, S_BUBS1}, // S_BUBS11
{SPR_BUBS, FF_TRANS30| 9, 3, {NULL}, 0, 0, S_BUBSB2}, // S_BUBSB1
{SPR_BUBS, FF_TRANS30|10, 3, {NULL}, 0, 0, S_BUBSB3}, // S_BUBSB2
{SPR_BUBS, FF_TRANS30|11, 3, {NULL}, 0, 0, S_BUBSB4}, // S_BUBSB3
{SPR_BUBS, FF_TRANS30|10, 3, {NULL}, 0, 0, S_BUBSB1}, // S_BUBSB4
{SPR_BUBS, FF_TRANS30|12, 3, {NULL}, 0, 0, S_BUBSB3}, // S_BUBSB5
{SPR_BUBS, FF_TRANS30|13, 3, {NULL}, 0, 0, S_BUBSB5}, // S_BUBSB6
{SPR_ZAPS, FF_FULLBRIGHT|FF_TRANS20 , 2, {NULL}, 0, 0, S_ZAPS2 }, // S_ZAPS1
{SPR_ZAPS, FF_FULLBRIGHT|FF_TRANS20| 1, 2, {NULL}, 0, 0, S_ZAPS3 }, // S_ZAPS2
{SPR_ZAPS, FF_FULLBRIGHT|FF_TRANS20| 2, 2, {NULL}, 0, 0, S_ZAPS4 }, // S_ZAPS3
{SPR_ZAPS, FF_FULLBRIGHT|FF_TRANS20| 3, 2, {NULL}, 0, 0, S_ZAPS5 }, // S_ZAPS4
{SPR_ZAPS, FF_FULLBRIGHT|FF_TRANS20| 4, 2, {NULL}, 0, 0, S_ZAPS6 }, // S_ZAPS5
{SPR_ZAPS, FF_FULLBRIGHT|FF_TRANS20| 5, 2, {NULL}, 0, 0, S_ZAPS7 }, // S_ZAPS6
{SPR_ZAPS, FF_FULLBRIGHT|FF_TRANS20| 6, 2, {NULL}, 0, 0, S_ZAPS8 }, // S_ZAPS7
{SPR_ZAPS, FF_FULLBRIGHT|FF_TRANS20| 7, 2, {NULL}, 0, 0, S_ZAPS9 }, // S_ZAPS8
{SPR_ZAPS, FF_FULLBRIGHT|FF_TRANS20| 8, 2, {NULL}, 0, 0, S_ZAPS10}, // S_ZAPS9
{SPR_ZAPS, FF_FULLBRIGHT|FF_TRANS20| 9, 2, {NULL}, 0, 0, S_ZAPS11}, // S_ZAPS10
{SPR_ZAPS, FF_FULLBRIGHT|FF_TRANS20|10, 2, {NULL}, 0, 0, S_ZAPS12}, // S_ZAPS11
{SPR_ZAPS, FF_FULLBRIGHT|FF_TRANS20|11, 2, {NULL}, 0, 0, S_ZAPS13}, // S_ZAPS12
{SPR_NULL, 0, 9*2, {NULL}, 0, 0, S_ZAPS14}, // S_ZAPS13
{SPR_ZAPS, FF_FULLBRIGHT|FF_TRANS20| 9, 2, {NULL}, 0, 0, S_ZAPS15}, // S_ZAPS14
{SPR_ZAPS, FF_FULLBRIGHT|FF_TRANS20|10, 2, {NULL}, 0, 0, S_ZAPS16}, // S_ZAPS15
{SPR_ZAPS, FF_FULLBRIGHT|FF_TRANS20|11, 2, {NULL}, 0, 0, S_ZAPS1 }, // S_ZAPS16
{SPR_NULL, 0, 12*2, {NULL}, 0, 0, S_ZAPSB2 }, // S_ZAPSB1
{SPR_ZAPS, FF_FULLBRIGHT|FF_TRANS20| 8, 2, {NULL}, 0, 0, S_ZAPSB3 }, // S_ZAPSB2
{SPR_ZAPS, FF_FULLBRIGHT|FF_TRANS20| 7, 2, {NULL}, 0, 0, S_ZAPSB4 }, // S_ZAPSB3
{SPR_ZAPS, FF_FULLBRIGHT|FF_TRANS20| 6, 2, {NULL}, 0, 0, S_ZAPSB5 }, // S_ZAPSB4
{SPR_ZAPS, FF_FULLBRIGHT|FF_TRANS20| 5, 2, {NULL}, 0, 0, S_ZAPSB6 }, // S_ZAPSB5
{SPR_ZAPS, FF_FULLBRIGHT|FF_TRANS20| 4, 2, {NULL}, 0, 0, S_ZAPSB7 }, // S_ZAPSB6
{SPR_ZAPS, FF_FULLBRIGHT|FF_TRANS20| 3, 2, {NULL}, 0, 0, S_ZAPSB8 }, // S_ZAPSB7
{SPR_ZAPS, FF_FULLBRIGHT|FF_TRANS20| 2, 2, {NULL}, 0, 0, S_ZAPSB9 }, // S_ZAPSB8
{SPR_ZAPS, FF_FULLBRIGHT|FF_TRANS20| 1, 2, {NULL}, 0, 0, S_ZAPSB10}, // S_ZAPSB9
{SPR_ZAPS, FF_FULLBRIGHT|FF_TRANS20 , 2, {NULL}, 0, 0, S_ZAPSB11}, // S_ZAPSB10
{SPR_NULL, 0, 15*2, {NULL}, 0, 0, S_ZAPSB2 }, // S_ZAPSB11
// Thunder spark
{SPR_SSPK, FF_ANIMATE, 18, {NULL}, 1, 2, S_NULL}, // S_THUNDERCOIN_SPARK
// Invincibility Sparkles
{SPR_IVSP, FF_ANIMATE, 32, {NULL}, 31, 1, S_NULL}, // S_IVSP
@ -6363,6 +6472,87 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
S_NULL // raisestate
},
{ // MT_FLAMEAURA_BOX
420, // doomednum
S_FLAMEAURA_BOX, // spawnstate
1, // spawnhealth
S_NULL, // seestate
sfx_None, // seesound
8, // reactiontime
sfx_None, // attacksound
S_FLAMEAURA_BOX, // painstate
0, // painchance
sfx_None, // painsound
S_NULL, // meleestate
S_NULL, // missilestate
S_BOX_POP1, // deathstate
S_NULL, // xdeathstate
sfx_pop, // deathsound
1, // speed
16*FRACUNIT, // radius
32*FRACUNIT, // height
0, // display offset
100, // mass
MT_FLAMEAURA_ICON, // damage
sfx_None, // activesound
MF_SOLID|MF_SHOOTABLE|MF_MONITOR, // flags
S_NULL // raisestate
},
{ // MT_BUBBLEWRAP_BOX
421, // doomednum
S_BUBBLEWRAP_BOX, // spawnstate
1, // spawnhealth
S_NULL, // seestate
sfx_None, // seesound
8, // reactiontime
sfx_None, // attacksound
S_BUBBLEWRAP_BOX, // painstate
0, // painchance
sfx_None, // painsound
S_NULL, // meleestate
S_NULL, // missilestate
S_BOX_POP1, // deathstate
S_NULL, // xdeathstate
sfx_pop, // deathsound
1, // speed
16*FRACUNIT, // radius
32*FRACUNIT, // height
0, // display offset
100, // mass
MT_BUBBLEWRAP_ICON, // damage
sfx_None, // activesound
MF_SOLID|MF_SHOOTABLE|MF_MONITOR, // flags
S_NULL // raisestate
},
{ // MT_THUNDERCOIN_BOX
422, // doomednum
S_THUNDERCOIN_BOX, // spawnstate
1, // spawnhealth
S_NULL, // seestate
sfx_None, // seesound
8, // reactiontime
sfx_None, // attacksound
S_THUNDERCOIN_BOX, // painstate
0, // painchance
sfx_None, // painsound
S_NULL, // meleestate
S_NULL, // missilestate
S_BOX_POP1, // deathstate
S_NULL, // xdeathstate
sfx_pop, // deathsound
1, // speed
16*FRACUNIT, // radius
32*FRACUNIT, // height
0, // display offset
100, // mass
MT_THUNDERCOIN_ICON, // damage
sfx_None, // activesound
MF_SOLID|MF_SHOOTABLE|MF_MONITOR, // flags
S_NULL // raisestate
},
{ // MT_PITY_GOLDBOX
431, // doomednum
S_PITY_GOLDBOX, // spawnstate
@ -6633,6 +6823,87 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
S_NULL // raisestate
},
{ // MT_FLAMEAURA_GOLDBOX
450, // doomednum
S_FLAMEAURA_GOLDBOX, // spawnstate
1, // spawnhealth
S_NULL, // seestate
sfx_None, // seesound
8, // reactiontime
sfx_monton, // attacksound
S_FLAMEAURA_GOLDBOX, // painstate
0, // painchance
sfx_None, // painsound
S_NULL, // meleestate
S_NULL, // missilestate
S_GOLDBOX_OFF1, // deathstate
S_NULL, // xdeathstate
sfx_pop, // deathsound
0, // speed
16*FRACUNIT, // radius
36*FRACUNIT, // height
0, // display offset
100, // mass
MT_FLAMEAURA_ICON, // damage
sfx_None, // activesound
MF_SOLID|MF_SHOOTABLE|MF_MONITOR|MF_GRENADEBOUNCE, // flags
S_NULL // raisestate
},
{ // MT_BUBBLEWRAP_GOLDBOX
451, // doomednum
S_BUBBLEWRAP_GOLDBOX, // spawnstate
1, // spawnhealth
S_NULL, // seestate
sfx_None, // seesound
8, // reactiontime
sfx_monton, // attacksound
S_BUBBLEWRAP_GOLDBOX, // painstate
0, // painchance
sfx_None, // painsound
S_NULL, // meleestate
S_NULL, // missilestate
S_GOLDBOX_OFF1, // deathstate
S_NULL, // xdeathstate
sfx_pop, // deathsound
0, // speed
16*FRACUNIT, // radius
36*FRACUNIT, // height
0, // display offset
100, // mass
MT_BUBBLEWRAP_ICON, // damage
sfx_None, // activesound
MF_SOLID|MF_SHOOTABLE|MF_MONITOR|MF_GRENADEBOUNCE, // flags
S_NULL // raisestate
},
{ // MT_THUNDERCOIN_GOLDBOX
452, // doomednum
S_THUNDERCOIN_GOLDBOX, // spawnstate
1, // spawnhealth
S_NULL, // seestate
sfx_None, // seesound
8, // reactiontime
sfx_monton, // attacksound
S_THUNDERCOIN_GOLDBOX, // painstate
0, // painchance
sfx_None, // painsound
S_NULL, // meleestate
S_NULL, // missilestate
S_GOLDBOX_OFF1, // deathstate
S_NULL, // xdeathstate
sfx_pop, // deathsound
0, // speed
16*FRACUNIT, // radius
36*FRACUNIT, // height
0, // display offset
100, // mass
MT_THUNDERCOIN_ICON, // damage
sfx_None, // activesound
MF_SOLID|MF_SHOOTABLE|MF_MONITOR|MF_GRENADEBOUNCE, // flags
S_NULL // raisestate
},
{ // MT_RING_REDBOX
414, // doomednum
S_RING_REDBOX1, // spawnstate
@ -6719,7 +6990,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
S_PITY_ICON1, // spawnstate
1, // spawnhealth
S_NULL, // seestate
sfx_shield, // seesound
sfx_s3k3a, // seesound
8, // reactiontime
sfx_None, // attacksound
S_NULL, // painstate
@ -6746,7 +7017,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
S_ATTRACT_ICON1, // spawnstate
1, // spawnhealth
S_NULL, // seestate
sfx_shield, // seesound
sfx_s3k41, // seesound
8, // reactiontime
sfx_None, // attacksound
S_NULL, // painstate
@ -6773,7 +7044,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
S_FORCE_ICON1, // spawnstate
1, // spawnhealth
S_NULL, // seestate
sfx_shield, // seesound
sfx_forcsg, // seesound
8, // reactiontime
sfx_None, // attacksound
S_NULL, // painstate
@ -6800,7 +7071,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
S_ARMAGEDDON_ICON1, // spawnstate
1, // spawnhealth
S_NULL, // seestate
sfx_shield, // seesound
sfx_armasg, // seesound
8, // reactiontime
sfx_None, // attacksound
S_NULL, // painstate
@ -6827,7 +7098,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
S_WHIRLWIND_ICON1, // spawnstate
1, // spawnhealth
S_NULL, // seestate
sfx_shield, // seesound
sfx_wirlsg, // seesound
8, // reactiontime
sfx_None, // attacksound
S_NULL, // painstate
@ -6854,7 +7125,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
S_ELEMENTAL_ICON1, // spawnstate
1, // spawnhealth
S_NULL, // seestate
sfx_shield, // seesound
sfx_elemsg, // seesound
8, // reactiontime
sfx_None, // attacksound
S_NULL, // painstate
@ -7119,6 +7390,87 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
S_NULL // raisestate
},
{ // MT_FLAMEAURA_ICON
-1, // doomednum
S_FLAMEAURA_ICON1, // spawnstate
1, // spawnhealth
S_NULL, // seestate
sfx_s3k3e, // seesound
8, // reactiontime
sfx_None, // attacksound
S_NULL, // painstate
0, // painchance
sfx_None, // painsound
S_NULL, // meleestate
S_NULL, // missilestate
S_NULL, // deathstate
S_NULL, // xdeathstate
sfx_None, // deathsound
2*FRACUNIT, // speed
8*FRACUNIT, // radius
14*FRACUNIT, // height
0, // display offset
100, // mass
62*FRACUNIT, // damage
sfx_None, // activesound
MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY|MF_NOGRAVITY|MF_BOXICON, // flags
S_NULL // raisestate
},
{ // MT_BUBBLEWRAP_ICON
-1, // doomednum
S_BUBBLEWRAP_ICON1, // spawnstate
1, // spawnhealth
S_NULL, // seestate
sfx_s3k3f, // seesound
8, // reactiontime
sfx_None, // attacksound
S_NULL, // painstate
0, // painchance
sfx_None, // painsound
S_NULL, // meleestate
S_NULL, // missilestate
S_NULL, // deathstate
S_NULL, // xdeathstate
sfx_None, // deathsound
2*FRACUNIT, // speed
8*FRACUNIT, // radius
14*FRACUNIT, // height
0, // display offset
100, // mass
62*FRACUNIT, // damage
sfx_None, // activesound
MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY|MF_NOGRAVITY|MF_BOXICON, // flags
S_NULL // raisestate
},
{ // MT_THUNDERCOIN_ICON
-1, // doomednum
S_THUNDERCOIN_ICON1, // spawnstate
1, // spawnhealth
S_NULL, // seestate
sfx_s3k41, // seesound
8, // reactiontime
sfx_None, // attacksound
S_NULL, // painstate
0, // painchance
sfx_None, // painsound
S_NULL, // meleestate
S_NULL, // missilestate
S_NULL, // deathstate
S_NULL, // xdeathstate
sfx_None, // deathsound
2*FRACUNIT, // speed
8*FRACUNIT, // radius
14*FRACUNIT, // height
0, // display offset
100, // mass
62*FRACUNIT, // damage
sfx_None, // activesound
MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY|MF_NOGRAVITY|MF_BOXICON, // flags
S_NULL // raisestate
},
{ // MT_ROCKET
-1, // doomednum
S_ROCKET, // spawnstate
@ -10362,7 +10714,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
S_NULL // raisestate
},
{ // MT_GREENORB
{ // MT_ELEMENTAL_ORB
-1, // doomednum
S_ELEM1, // spawnstate
1000, // spawnhealth
@ -10370,7 +10722,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
sfx_None, // seesound
0, // reactiontime
sfx_None, // attacksound
S_NULL, // painstate
S_ELEM13, // painstate
SKINCOLOR_NONE, // painchance
sfx_None, // painsound
S_NULL, // meleestate
@ -10381,15 +10733,15 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
SH_ELEMENTAL, // speed
64*FRACUNIT, // radius
64*FRACUNIT, // height
1, // display offset
2, // display offset
16, // mass
0, // damage
sfx_None, // activesound
MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOGRAVITY|MF_SCENERY, // flags
S_NULL // raisestate
S_ELEMF9 // raisestate
},
{ // MT_YELLOWORB
{ // MT_ATTRACT_ORB
-1, // doomednum
S_MAGN1, // spawnstate
1000, // spawnhealth
@ -10397,7 +10749,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
sfx_None, // seesound
8, // reactiontime
sfx_None, // attacksound
S_NULL, // painstate
S_MAGN13, // painstate
SKINCOLOR_NONE, // painchance
sfx_None, // painsound
S_NULL, // meleestate
@ -10408,7 +10760,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
SH_ATTRACT, // speed
64*FRACUNIT, // radius
64*FRACUNIT, // height
1, // display offset
2, // display offset
16, // mass
0, // damage
sfx_None, // activesound
@ -10416,7 +10768,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
S_NULL // raisestate
},
{ // MT_BLUEORB
{ // MT_FORCE_ORB
-1, // doomednum
S_FORC1, // spawnstate
1000, // spawnhealth
@ -10435,15 +10787,15 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
SH_FORCE, // speed
64*FRACUNIT, // radius
64*FRACUNIT, // height
1, // display offset
2, // display offset
16, // mass
0, // damage
sfx_None, // activesound
MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOGRAVITY|MF_SCENERY, // flags
S_NULL // raisestate
S_FORC21 // raisestate
},
{ // MT_BLACKORB
{ // MT_ARMAGEDDON_ORB
-1, // doomednum
S_ARMA1, // spawnstate
1000, // spawnhealth
@ -10459,10 +10811,10 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
S_NULL, // deathstate
S_NULL, // xdeathstate
sfx_None, // deathsound
SH_BOMB, // speed
SH_ARMAGEDDON, // speed
64*FRACUNIT, // radius
64*FRACUNIT, // height
1, // display offset
2, // display offset
16, // mass
0, // damage
sfx_None, // activesound
@ -10470,7 +10822,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
S_NULL // raisestate
},
{ // MT_WHITEORB
{ // MT_WHIRLWIND_ORB
-1, // doomednum
S_WIND1, // spawnstate
1000, // spawnhealth
@ -10486,10 +10838,10 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
S_NULL, // deathstate
S_NULL, // xdeathstate
sfx_None, // deathsound
SH_JUMP, // speed
SH_WHIRLWIND, // speed
64*FRACUNIT, // radius
64*FRACUNIT, // height
1, // display offset
2, // display offset
16, // mass
0, // damage
sfx_None, // activesound
@ -10497,7 +10849,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
S_NULL // raisestate
},
{ // MT_PITYORB
{ // MT_PITY_ORB
-1, // doomednum
S_PITY1, // spawnstate
1000, // spawnhealth
@ -10516,7 +10868,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
SH_PITY, // speed
64*FRACUNIT, // radius
64*FRACUNIT, // height
1, // display offset
2, // display offset
16, // mass
0, // damage
sfx_None, // activesound
@ -10524,6 +10876,114 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
S_NULL // raisestate
},
{ // MT_FLAMEAURA_ORB
-1, // doomednum
S_FIRSB1, // spawnstate
1000, // spawnhealth
S_FIRS1, // seestate
sfx_None, // seesound
8, // reactiontime
sfx_None, // attacksound
S_FIRSB10, // painstate
SKINCOLOR_NONE, // painchance
sfx_None, // painsound
S_NULL, // meleestate
S_NULL, // missilestate
S_NULL, // deathstate
S_NULL, // xdeathstate
sfx_None, // deathsound
SH_FLAMEAURA, // speed
64*FRACUNIT, // radius
64*FRACUNIT, // height
-2, // display offset
16, // mass
0, // damage
sfx_None, // activesound
MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOGRAVITY|MF_SCENERY, // flags
S_FIRS10 // raisestate
},
{ // MT_BUBBLEWRAP_ORB
-1, // doomednum
S_BUBSB1, // spawnstate
1000, // spawnhealth
S_BUBS1, // seestate
sfx_None, // seesound
8, // reactiontime
sfx_None, // attacksound
S_BUBSB5, // painstate
SKINCOLOR_NONE, // painchance
sfx_None, // painsound
S_NULL, // meleestate
S_NULL, // missilestate
S_NULL, // deathstate
S_NULL, // xdeathstate
sfx_None, // deathsound
SH_BUBBLEWRAP, // speed
64*FRACUNIT, // radius
64*FRACUNIT, // height
2, // display offset
16, // mass
0, // damage
sfx_None, // activesound
MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOGRAVITY|MF_SCENERY, // flags
S_BUBS10 // raisestate
},
{ // MT_THUNDERCOIN_ORB
-1, // doomednum
S_ZAPSB1, // spawnstate
1000, // spawnhealth
S_ZAPS1, // seestate
sfx_None, // seesound
8, // reactiontime
sfx_None, // attacksound
S_ZAPSB11, // painstate
SKINCOLOR_NONE, // painchance
sfx_None, // painsound
S_NULL, // meleestate
S_NULL, // missilestate
S_NULL, // deathstate
S_NULL, // xdeathstate
sfx_None, // deathsound
SH_THUNDERCOIN, // speed
64*FRACUNIT, // radius
64*FRACUNIT, // height
-2, // display offset
16, // mass
0, // damage
sfx_None, // activesound
MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOGRAVITY|MF_SCENERY, // flags
S_ZAPS14 // raisestate
},
{ // MT_THUNDERCOIN_SPARK
-1, // doomednum
S_THUNDERCOIN_SPARK, // spawnstate
1, // spawnhealth
S_NULL, // seestate
sfx_None, // seesound
8, // reactiontime
sfx_None, // attacksound
S_NULL, // painstate
0, // painchance
sfx_None, // painsound
S_NULL, // meleestate
S_NULL, // missilestate
S_NULL, // deathstate
S_NULL, // xdeathstate
sfx_None, // deathsound
0, // speed
4*FRACUNIT, // radius
4*FRACUNIT, // height
0, // display offset
100, // mass
0, // damage
sfx_None, // activesound
MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOGRAVITY|MF_SCENERY, // flags
S_NULL // raisestate
},
{ // MT_IVSP
-1, // doomednum
S_IVSP, // spawnstate
@ -10543,7 +11003,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
8, // speed
64*FRACUNIT, // radius
64*FRACUNIT, // height
2, // display offset
3, // display offset
16, // mass
0, // damage
sfx_None, // activesound
@ -12197,7 +12657,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
S_NULL, // missilestate
S_NULL, // deathstate
S_NULL, // xdeathstate
sfx_mario3, // deathsound
sfx_None, // deathsound
0, // speed
16*FRACUNIT, // radius
32*FRACUNIT, // height

View file

@ -56,6 +56,9 @@ void A_BombShield(); // Obtained Bomb Shield
void A_WaterShield(); // Obtained Water Shield
void A_ForceShield(); // Obtained Force Shield
void A_PityShield(); // Obtained Pity Shield. We're... sorry.
void A_FlameShield(); // Obtained Flame Shield
void A_BubbleShield(); // Obtained Bubble Shield
void A_ThunderShield(); // Obtained Thunder Shield
void A_GravityBox();
void A_ScoreRise(); // Rise the score logo
void A_ParticleSpawn();
@ -351,6 +354,9 @@ typedef enum sprite
SPR_TVRC, // ReCycler
SPR_TV1K, // 1,000 points (1 K)
SPR_TVTK, // 10,000 points (Ten K)
SPR_TVFL, // FLame shield
SPR_TVBB, // BuBble shield
SPR_TVZP, // Thunder shield (ZaP)
// Projectiles
SPR_MISL,
@ -435,6 +441,9 @@ typedef enum sprite
SPR_ELEM, // Elemental Shield Orb and Fire
SPR_FORC, // Force Shield Orb
SPR_PITY, // Pity Shield Orb
SPR_FIRS, // Flame Shield Orb
SPR_BUBS, // Bubble Shield Orb
SPR_ZAPS, // Thunder Shield Orb
SPR_IVSP, // invincibility sparkles
SPR_SSPK, // Super Sonic Spark
@ -1725,7 +1734,7 @@ typedef enum state
S_SPIKEBALL7,
S_SPIKEBALL8,
// Fire Shield's Spawn
// Elemental Shield's Spawn
S_SPINFIRE1,
S_SPINFIRE2,
S_SPINFIRE3,
@ -1799,6 +1808,9 @@ typedef enum state
S_RECYCLER_BOX,
S_SCORE1K_BOX,
S_SCORE10K_BOX,
S_FLAMEAURA_BOX,
S_BUBBLEWRAP_BOX,
S_THUNDERCOIN_BOX,
// Gold Repeat Monitor States (one per box)
S_PITY_GOLDBOX,
@ -1811,6 +1823,9 @@ typedef enum state
S_INVULN_GOLDBOX,
S_EGGMAN_GOLDBOX,
S_GRAVITY_GOLDBOX,
S_FLAMEAURA_GOLDBOX,
S_BUBBLEWRAP_GOLDBOX,
S_THUNDERCOIN_GOLDBOX,
// Team Ring Boxes (these are special)
S_RING_REDBOX1,
@ -1872,6 +1887,15 @@ typedef enum state
S_SCORE10K_ICON1,
S_SCORE10K_ICON2,
S_FLAMEAURA_ICON1,
S_FLAMEAURA_ICON2,
S_BUBBLEWRAP_ICON1,
S_BUBBLEWRAP_ICON2,
S_THUNDERCOIN_ICON1,
S_THUNDERCOIN_ICON2,
// ---
S_ROCKET,
@ -2243,6 +2267,7 @@ typedef enum state
S_MAGN10,
S_MAGN11,
S_MAGN12,
S_MAGN13,
S_FORC1,
S_FORC2,
@ -2266,6 +2291,8 @@ typedef enum state
S_FORC19,
S_FORC20,
S_FORC21,
S_ELEM1,
S_ELEM2,
S_ELEM3,
@ -2279,6 +2306,9 @@ typedef enum state
S_ELEM11,
S_ELEM12,
S_ELEM13,
S_ELEM14,
S_ELEMF1,
S_ELEMF2,
S_ELEMF3,
@ -2287,6 +2317,8 @@ typedef enum state
S_ELEMF6,
S_ELEMF7,
S_ELEMF8,
S_ELEMF9,
S_ELEMF10,
S_PITY1,
S_PITY2,
@ -2299,6 +2331,84 @@ typedef enum state
S_PITY9,
S_PITY10,
S_FIRS1,
S_FIRS2,
S_FIRS3,
S_FIRS4,
S_FIRS5,
S_FIRS6,
S_FIRS7,
S_FIRS8,
S_FIRS9,
S_FIRS10,
S_FIRS11,
S_FIRSB1,
S_FIRSB2,
S_FIRSB3,
S_FIRSB4,
S_FIRSB5,
S_FIRSB6,
S_FIRSB7,
S_FIRSB8,
S_FIRSB9,
S_FIRSB10,
S_BUBS1,
S_BUBS2,
S_BUBS3,
S_BUBS4,
S_BUBS5,
S_BUBS6,
S_BUBS7,
S_BUBS8,
S_BUBS9,
S_BUBS10,
S_BUBS11,
S_BUBSB1,
S_BUBSB2,
S_BUBSB3,
S_BUBSB4,
S_BUBSB5,
S_BUBSB6,
S_ZAPS1,
S_ZAPS2,
S_ZAPS3,
S_ZAPS4,
S_ZAPS5,
S_ZAPS6,
S_ZAPS7,
S_ZAPS8,
S_ZAPS9,
S_ZAPS10,
S_ZAPS11,
S_ZAPS12,
S_ZAPS13, // blank frame
S_ZAPS14,
S_ZAPS15,
S_ZAPS16,
S_ZAPSB1, // blank frame
S_ZAPSB2,
S_ZAPSB3,
S_ZAPSB4,
S_ZAPSB5,
S_ZAPSB6,
S_ZAPSB7,
S_ZAPSB8,
S_ZAPSB9,
S_ZAPSB10,
S_ZAPSB11, // blank frame
//Thunder spark
S_THUNDERCOIN_SPARK,
// Invincibility Sparkles
S_IVSP,
@ -3090,6 +3200,9 @@ typedef enum mobj_type
MT_RECYCLER_BOX,
MT_SCORE1K_BOX,
MT_SCORE10K_BOX,
MT_FLAMEAURA_BOX,
MT_BUBBLEWRAP_BOX,
MT_THUNDERCOIN_BOX,
// Monitor boxes -- repeating (big) boxes
MT_PITY_GOLDBOX,
@ -3102,6 +3215,9 @@ typedef enum mobj_type
MT_INVULN_GOLDBOX,
MT_EGGMAN_GOLDBOX,
MT_GRAVITY_GOLDBOX,
MT_FLAMEAURA_GOLDBOX,
MT_BUBBLEWRAP_GOLDBOX,
MT_THUNDERCOIN_GOLDBOX,
// Monitor boxes -- special
MT_RING_REDBOX,
@ -3124,6 +3240,9 @@ typedef enum mobj_type
MT_RECYCLER_ICON,
MT_SCORE1K_ICON,
MT_SCORE10K_ICON,
MT_FLAMEAURA_ICON,
MT_BUBBLEWRAP_ICON,
MT_THUNDERCOIN_ICON,
// Projectiles
MT_ROCKET,
@ -3276,13 +3395,17 @@ typedef enum mobj_type
MT_EGGSTATUE2,
// Powerup Indicators
MT_GREENORB, // Elemental shield mobj
MT_YELLOWORB, // Attract shield mobj
MT_BLUEORB, // Force shield mobj
MT_BLACKORB, // Armageddon shield mobj
MT_WHITEORB, // Whirlwind shield mobj
MT_PITYORB, // Pity shield mobj
MT_IVSP, // invincibility sparkles
MT_ELEMENTAL_ORB, // Elemental shield mobj
MT_ATTRACT_ORB, // Attract shield mobj
MT_FORCE_ORB, // Force shield mobj
MT_ARMAGEDDON_ORB, // Armageddon shield mobj
MT_WHIRLWIND_ORB, // Whirlwind shield mobj
MT_PITY_ORB, // Pity shield mobj
MT_FLAMEAURA_ORB, // Flame shield mobj
MT_BUBBLEWRAP_ORB, // Bubble shield mobj
MT_THUNDERCOIN_ORB, // Thunder shield mobj
MT_THUNDERCOIN_SPARK, // Thunder spark
MT_IVSP, // Invincibility sparkles
MT_SUPERSPARK, // Super Sonic Spark
// Freed Animals

View file

@ -801,6 +801,16 @@ static int lib_pDoJumpShield(lua_State *L)
return 0;
}
static int lib_pDoBubbleBounce(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
NOHUD
if (!player)
return LUA_ErrInvalid(L, "player_t");
P_DoBubbleBounce(player);
return 0;
}
static int lib_pBlackOw(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
@ -811,13 +821,14 @@ static int lib_pBlackOw(lua_State *L)
return 0;
}
static int lib_pElementalFireTrail(lua_State *L)
static int lib_pElementalFire(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
boolean cropcircle = lua_optboolean(L, 2);
NOHUD
if (!player)
return LUA_ErrInvalid(L, "player_t");
P_ElementalFireTrail(player);
P_ElementalFire(player, cropcircle);
return 0;
}
@ -872,10 +883,11 @@ static int lib_pReturnThrustY(lua_State *L)
static int lib_pLookForEnemies(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
boolean nonenemies = lua_opttrueboolean(L, 2);
NOHUD
if (!player)
return LUA_ErrInvalid(L, "player_t");
lua_pushboolean(L, P_LookForEnemies(player));
lua_pushboolean(L, P_LookForEnemies(player, nonenemies));
return 1;
}
@ -2092,8 +2104,9 @@ static luaL_Reg lib[] = {
{"P_GivePlayerLives",lib_pGivePlayerLives},
{"P_ResetScore",lib_pResetScore},
{"P_DoJumpShield",lib_pDoJumpShield},
{"P_DoBubbleBounce",lib_pDoBubbleBounce},
{"P_BlackOw",lib_pBlackOw},
{"P_ElementalFireTrail",lib_pElementalFireTrail},
{"P_ElementalFire",lib_pElementalFire},
{"P_DoPlayerExit",lib_pDoPlayerExit},
{"P_InstaThrust",lib_pInstaThrust},
{"P_ReturnThrustX",lib_pReturnThrustX},

View file

@ -43,6 +43,8 @@ enum hook {
hook_PlayerMsg,
hook_HurtMsg,
hook_PlayerSpawn,
hook_ShieldSpawn,
hook_ShieldSpecial,
hook_MAX // last hook
};
@ -77,5 +79,7 @@ boolean LUAh_LinedefExecute(line_t *line, mobj_t *mo, sector_t *sector); // Hook
boolean LUAh_PlayerMsg(int source, int target, int flags, char *msg); // Hook for chat messages
boolean LUAh_HurtMsg(player_t *player, mobj_t *inflictor, mobj_t *source, UINT8 damagetype); // Hook for hurt messages
#define LUAh_PlayerSpawn(player) LUAh_PlayerHook(player, hook_PlayerSpawn) // Hook for G_SpawnPlayer
#define LUAh_ShieldSpawn(player) LUAh_PlayerHook(player, hook_ShieldSpawn) // Hook for P_SpawnShieldOrb
#define LUAh_ShieldSpecial(player) LUAh_PlayerHook(player, hook_ShieldSpecial) // Hook for shield abilities
#endif

View file

@ -54,6 +54,8 @@ const char *const hookNames[hook_MAX+1] = {
"PlayerMsg",
"HurtMsg",
"PlayerSpawn",
"ShieldSpawn",
"ShieldSpecial",
NULL
};

View file

@ -104,6 +104,9 @@ void A_BombShield(mobj_t *actor);
void A_WaterShield(mobj_t *actor);
void A_ForceShield(mobj_t *actor);
void A_PityShield(mobj_t *actor);
void A_FlameShield(mobj_t *actor);
void A_BubbleShield(mobj_t *actor);
void A_ThunderShield(mobj_t *actor);
void A_GravityBox(mobj_t *actor);
void A_ScoreRise(mobj_t *actor);
void A_ParticleSpawn(mobj_t *actor);
@ -738,7 +741,7 @@ static boolean P_LookForShield(mobj_t *actor)
(actor->type == MT_BLUETEAMRING && player->ctfteam != 2))
continue;
if ((player->powers[pw_shield] & SH_NOSTACK) == SH_ATTRACT
if ((player->powers[pw_shield] & SH_PROTECTELECTRIC)
&& (P_AproxDistance(P_AproxDistance(actor->x-player->mo->x, actor->y-player->mo->y), actor->z-player->mo->z) < FixedMul(RING_DIST, player->mo->scale)))
{
P_SetTarget(&actor->tracer, player->mo);
@ -3059,11 +3062,7 @@ void A_JumpShield(mobj_t *actor)
player = actor->target->player;
if ((player->powers[pw_shield] & SH_NOSTACK) != SH_JUMP)
{
player->powers[pw_shield] = SH_JUMP|(player->powers[pw_shield] & SH_STACK);
P_SpawnShieldOrb(player);
}
P_SwitchShield(player, SH_WHIRLWIND);
S_StartSound(player->mo, actor->info->seesound);
}
@ -3091,11 +3090,7 @@ void A_RingShield(mobj_t *actor)
player = actor->target->player;
if ((player->powers[pw_shield] & SH_NOSTACK) != SH_ATTRACT)
{
player->powers[pw_shield] = SH_ATTRACT|(player->powers[pw_shield] & SH_STACK);
P_SpawnShieldOrb(player);
}
P_SwitchShield(player, SH_ATTRACT);
S_StartSound(player->mo, actor->info->seesound);
}
@ -3292,11 +3287,12 @@ void A_BombShield(mobj_t *actor)
player = actor->target->player;
if ((player->powers[pw_shield] & SH_NOSTACK) != SH_BOMB)
{
player->powers[pw_shield] = SH_BOMB|(player->powers[pw_shield] & SH_STACK);
P_SpawnShieldOrb(player);
}
// If you already have a bomb shield, use it!
if ((player->powers[pw_shield] & SH_NOSTACK) == SH_ARMAGEDDON)
P_BlackOw(player);
// Now we know for certain that we don't have a bomb shield, so add one. :3
P_SwitchShield(player, SH_ARMAGEDDON);
S_StartSound(player->mo, actor->info->seesound);
}
@ -3324,22 +3320,8 @@ void A_WaterShield(mobj_t *actor)
player = actor->target->player;
if ((player->powers[pw_shield] & SH_NOSTACK) != SH_ELEMENTAL)
{
player->powers[pw_shield] = SH_ELEMENTAL|(player->powers[pw_shield] & SH_STACK);
P_SpawnShieldOrb(player);
}
P_SwitchShield(player, SH_ELEMENTAL);
if (player->powers[pw_underwater] && player->powers[pw_underwater] <= 12*TICRATE + 1)
P_RestoreMusic(player);
player->powers[pw_underwater] = 0;
if (player->powers[pw_spacetime] > 1)
{
player->powers[pw_spacetime] = 0;
P_RestoreMusic(player);
}
S_StartSound(player->mo, actor->info->seesound);
}
@ -3347,12 +3329,13 @@ void A_WaterShield(mobj_t *actor)
//
// Description: Awards the player a force shield.
//
// var1 = unused
// var1 = Number of additional hitpoints to give
// var2 = unused
//
void A_ForceShield(mobj_t *actor)
{
player_t *player;
INT32 locvar1 = var1;
#ifdef HAVE_BLUA
if (LUA_CallAction("A_ForceShield", actor))
@ -3364,15 +3347,15 @@ void A_ForceShield(mobj_t *actor)
return;
}
if (locvar1 & ~SH_FORCEHP)
{
CONS_Debug(DBG_GAMELOGIC, "Invalid number of additional hitpoints.\n");
return;
}
player = actor->target->player;
if (!(player->powers[pw_shield] & SH_FORCE))
{
player->powers[pw_shield] = SH_FORCE|(player->powers[pw_shield] & SH_STACK)|0x01;
P_SpawnShieldOrb(player);
}
else
player->powers[pw_shield] = SH_FORCE|(player->powers[pw_shield] & SH_STACK)|0x01;
P_SwitchShield(player, SH_FORCE|locvar1);
S_StartSound(player->mo, actor->info->seesound);
}
@ -3404,12 +3387,92 @@ void A_PityShield(mobj_t *actor)
player = actor->target->player;
if ((player->powers[pw_shield] & SH_NOSTACK) != SH_PITY)
P_SwitchShield(player, SH_PITY);
S_StartSound(player->mo, actor->info->seesound);
}
// Function: A_FlameShield
//
// Description: Awards the player a flame shield.
//
// var1 = unused
// var2 = unused
//
void A_FlameShield(mobj_t *actor)
{
player_t *player;
#ifdef HAVE_BLUA
if (LUA_CallAction("A_FlameShield", actor))
return;
#endif
if (!actor->target || !actor->target->player)
{
player->powers[pw_shield] = SH_PITY+(player->powers[pw_shield] & SH_STACK);
P_SpawnShieldOrb(player);
CONS_Debug(DBG_GAMELOGIC, "Powerup has no target.\n");
return;
}
player = actor->target->player;
P_SwitchShield(player, SH_FLAMEAURA);
S_StartSound(player->mo, actor->info->seesound);
}
// Function: A_BubbleShield
//
// Description: Awards the player a bubble shield.
//
// var1 = unused
// var2 = unused
//
void A_BubbleShield(mobj_t *actor)
{
player_t *player;
#ifdef HAVE_BLUA
if (LUA_CallAction("A_BubbleShield", actor))
return;
#endif
if (!actor->target || !actor->target->player)
{
CONS_Debug(DBG_GAMELOGIC, "Powerup has no target.\n");
return;
}
player = actor->target->player;
P_SwitchShield(player, SH_BUBBLEWRAP);
S_StartSound(player->mo, actor->info->seesound);
}
// Function: A_ThunderShield
//
// Description: Awards the player a thunder shield.
//
// var1 = unused
// var2 = unused
//
void A_ThunderShield(mobj_t *actor)
{
player_t *player;
#ifdef HAVE_BLUA
if (LUA_CallAction("A_ThunderShield", actor))
return;
#endif
if (!actor->target || !actor->target->player)
{
CONS_Debug(DBG_GAMELOGIC, "Powerup has no target.\n");
return;
}
player = actor->target->player;
P_SwitchShield(player, SH_THUNDERCOIN);
S_StartSound(player->mo, actor->info->seesound);
}
@ -3436,9 +3499,10 @@ void A_GravityBox(mobj_t *actor)
}
player = actor->target->player;
player->powers[pw_gravityboots] = (UINT16)(actor->info->reactiontime + 1);
S_StartSound(player, actor->info->activesound);
player->powers[pw_gravityboots] = (UINT16)(actor->info->reactiontime + 1);
}
// Function: A_ScoreRise
@ -3704,7 +3768,7 @@ void A_AttractChase(mobj_t *actor)
// Turn flingrings back into regular rings if attracted.
if (actor->tracer && actor->tracer->player
&& (actor->tracer->player->powers[pw_shield] & SH_NOSTACK) != SH_ATTRACT && actor->info->reactiontime && actor->type != (mobjtype_t)actor->info->reactiontime)
&& !(actor->tracer->player->powers[pw_shield] & SH_PROTECTELECTRIC) && actor->info->reactiontime && actor->type != (mobjtype_t)actor->info->reactiontime)
{
mobj_t *newring;
newring = P_SpawnMobj(actor->x, actor->y, actor->z, actor->info->reactiontime);
@ -3909,7 +3973,7 @@ void A_ThrownRing(mobj_t *actor)
// A non-homing ring getting attracted by a
// magnetic player. If he gets too far away, make
// sure to stop the attraction!
if ((!actor->tracer->health) || (actor->tracer->player && (actor->tracer->player->powers[pw_shield] & SH_NOSTACK) == SH_ATTRACT
if ((!actor->tracer->health) || (actor->tracer->player && (actor->tracer->player->powers[pw_shield] & SH_PROTECTELECTRIC)
&& P_AproxDistance(P_AproxDistance(actor->tracer->x-actor->x,
actor->tracer->y-actor->y), actor->tracer->z-actor->z) > FixedMul(RING_DIST/4, actor->tracer->scale)))
{
@ -3917,7 +3981,7 @@ void A_ThrownRing(mobj_t *actor)
}
if (actor->tracer && (actor->tracer->health)
&& (actor->tracer->player->powers[pw_shield] & SH_NOSTACK) == SH_ATTRACT)// Already found someone to follow.
&& (actor->tracer->player->powers[pw_shield] & SH_PROTECTELECTRIC))// Already found someone to follow.
{
const INT32 temp = actor->threshold;
actor->threshold = 32000;
@ -3985,7 +4049,7 @@ void A_ThrownRing(mobj_t *actor)
if (!P_CheckSight(actor, player->mo))
continue; // out of sight
if ((player->powers[pw_shield] & SH_NOSTACK) == SH_ATTRACT
if ((player->powers[pw_shield] & SH_PROTECTELECTRIC)
&& dist < FixedMul(RING_DIST/4, player->mo->scale))
P_SetTarget(&actor->tracer, player->mo);
return;

View file

@ -1748,12 +1748,15 @@ static mobj_t *SearchMarioNode(msecnode_t *node)
case MT_GHOST:
case MT_OVERLAY:
case MT_EMERALDSPAWN:
case MT_GREENORB:
case MT_YELLOWORB:
case MT_BLUEORB:
case MT_BLACKORB:
case MT_WHITEORB:
case MT_PITYORB:
case MT_ELEMENTAL_ORB:
case MT_ATTRACT_ORB:
case MT_FORCE_ORB:
case MT_ARMAGEDDON_ORB:
case MT_WHIRLWIND_ORB:
case MT_PITY_ORB:
case MT_FLAMEAURA_ORB:
case MT_BUBBLEWRAP_ORB:
case MT_THUNDERCOIN_ORB:
case MT_IVSP:
case MT_SUPERSPARK:
case MT_RAIN:
@ -1782,8 +1785,8 @@ static mobj_t *SearchMarioNode(msecnode_t *node)
break;
}
// Ignore popped monitors, too.
if (node->m_thing->flags & MF_MONITOR
&& node->m_thing->threshold == 68)
if (node->m_thing->health == 0 // this only really applies for monitors
|| (!(node->m_thing->flags & MF_MONITOR) && (mobjinfo[node->m_thing->type].flags & MF_MONITOR))) // gold monitor support
continue;
// Okay, we found something valid.
if (!thing // take either the first thing
@ -3156,15 +3159,15 @@ INT32 EV_MarioBlock(sector_t *sec, sector_t *roversector, fixed_t topheight, mob
S_StartSound(puncher, sfx_mario9); // Puncher is "close enough"
}
if (itsamonitor)
if (itsamonitor && thing)
{
P_UnsetThingPosition(tmthing);
tmthing->x = oldx;
tmthing->y = oldy;
tmthing->z = oldz;
tmthing->momx = 1;
tmthing->momy = 1;
P_SetThingPosition(tmthing);
P_UnsetThingPosition(thing);
thing->x = oldx;
thing->y = oldy;
thing->z = oldz;
thing->momx = 1;
thing->momy = 1;
P_SetThingPosition(thing);
}
}
else

View file

@ -142,7 +142,10 @@ boolean P_CanPickupItem(player_t *player, boolean weapon)
if (player->bot && weapon)
return false;
if (player->powers[pw_flashing] > (flashingtics/4)*3 && player->powers[pw_flashing] <= flashingtics)
if (player->powers[pw_flashing] > (flashingtics/4)*3 && player->powers[pw_flashing] < UINT16_MAX)
return false;
if (player->mo && player->mo->health <= 0)
return false;
return true;
@ -296,6 +299,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
{
player_t *player;
INT32 i;
UINT8 elementalpierce;
if (objectplacing)
return;
@ -350,6 +354,11 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
return;
#endif
// 0 = none, 1 = elemental pierce, 2 = bubble bounce
elementalpierce = (((player->powers[pw_shield] & SH_NOSTACK) == SH_ELEMENTAL || (player->powers[pw_shield] & SH_NOSTACK) == SH_BUBBLEWRAP) && (player->pflags & PF_SHIELDABILITY)
? (((player->powers[pw_shield] & SH_NOSTACK) == SH_ELEMENTAL) ? 1 : 2)
: 0);
if (special->flags & MF_BOSS)
{
if (special->type == MT_BLACKEGGMAN)
@ -359,14 +368,20 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
}
if (((player->pflags & PF_NIGHTSMODE) && (player->pflags & PF_DRILLING))
|| ((player->pflags & PF_JUMPED) && !(player->charflags & SF_NOJUMPDAMAGE && !(player->charability == CA_TWINSPIN && player->panim == PA_ABILITY)))
|| ((player->pflags & PF_JUMPED) && (player->pflags & PF_FORCEJUMPDAMAGE || !(player->charflags & SF_NOJUMPSPIN) || (player->charability == CA_TWINSPIN && player->panim == PA_ABILITY)))
|| (player->pflags & (PF_SPINNING|PF_GLIDING))
|| (player->charability2 == CA2_MELEE && player->panim == PA_ABILITY2)
|| ((player->charflags & SF_STOMPDAMAGE) && (P_MobjFlip(toucher)*(toucher->z - (special->z + special->height/2)) > 0) && (P_MobjFlip(toucher)*toucher->momz < 0))
|| player->powers[pw_invulnerability] || player->powers[pw_super]) // Do you possess the ability to subdue the object?
|| player->powers[pw_invulnerability] || player->powers[pw_super]
|| elementalpierce) // Do you possess the ability to subdue the object?
{
if (P_MobjFlip(toucher)*toucher->momz < 0)
toucher->momz = -toucher->momz;
if ((P_MobjFlip(toucher)*toucher->momz < 0) && (elementalpierce != 1))
{
if (elementalpierce == 2)
P_DoBubbleBounce(player);
else
toucher->momz = -toucher->momz;
}
toucher->momx = -toucher->momx;
toucher->momy = -toucher->momy;
P_DamageMobj(special, toucher, toucher, 1, 0);
@ -392,7 +407,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
/////ENEMIES!!//////////////////////////////////////////
////////////////////////////////////////////////////////
if (special->type == MT_GSNAPPER && !(((player->pflags & PF_NIGHTSMODE) && (player->pflags & PF_DRILLING))
|| player->powers[pw_invulnerability] || player->powers[pw_super])
|| player->powers[pw_invulnerability] || player->powers[pw_super] || elementalpierce)
&& toucher->z < special->z + special->height && toucher->z + toucher->height > special->z)
{
// Can only hit snapper from above
@ -405,14 +420,19 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
P_DamageMobj(toucher, special, special, 1, 0);
}
else if (((player->pflags & PF_NIGHTSMODE) && (player->pflags & PF_DRILLING))
|| ((player->pflags & PF_JUMPED) && !(player->charflags & SF_NOJUMPDAMAGE && !(player->charability == CA_TWINSPIN && player->panim == PA_ABILITY)))
|| ((player->pflags & PF_JUMPED) && (player->pflags & PF_FORCEJUMPDAMAGE || !(player->charflags & SF_NOJUMPSPIN) || (player->charability == CA_TWINSPIN && player->panim == PA_ABILITY)))
|| (player->pflags & (PF_SPINNING|PF_GLIDING))
|| (player->charability2 == CA2_MELEE && player->panim == PA_ABILITY2)
|| ((player->charflags & SF_STOMPDAMAGE) && (P_MobjFlip(toucher)*(toucher->z - (special->z + special->height/2)) > 0) && (P_MobjFlip(toucher)*toucher->momz < 0))
|| player->powers[pw_invulnerability] || player->powers[pw_super]) // Do you possess the ability to subdue the object?
{
if (P_MobjFlip(toucher)*toucher->momz < 0)
toucher->momz = -toucher->momz;
if ((P_MobjFlip(toucher)*toucher->momz < 0) && (elementalpierce != 1))
{
if (elementalpierce == 2)
P_DoBubbleBounce(player);
else
toucher->momz = -toucher->momz;
}
P_DamageMobj(special, toucher, toucher, 1, 0);
}
@ -1195,9 +1215,17 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
case MT_FIREFLOWER:
if (player->bot)
return;
player->powers[pw_shield] |= SH_FIREFLOWER;
toucher->color = SKINCOLOR_WHITE;
G_GhostAddColor(GHC_FIREFLOWER);
S_StartSound(toucher, sfx_mario3);
player->powers[pw_shield] = (player->powers[pw_shield] & SH_NOSTACK)|SH_FIREFLOWER;
if (!(player->powers[pw_super] || (mariomode && player->powers[pw_invulnerability])))
{
player->mo->color = SKINCOLOR_WHITE;
G_GhostAddColor(GHC_FIREFLOWER);
}
break;
// *************** //
@ -1366,7 +1394,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
return;
}
else if (((player->pflags & PF_NIGHTSMODE) && (player->pflags & PF_DRILLING))
|| ((player->pflags & PF_JUMPED) && !(player->charflags & SF_NOJUMPDAMAGE))
|| ((player->pflags & PF_JUMPED) && (player->pflags & PF_FORCEJUMPDAMAGE || !(player->charflags & SF_NOJUMPSPIN) || (player->charability == CA_TWINSPIN && player->panim == PA_ABILITY)))
|| ((player->charflags & SF_STOMPDAMAGE) && (P_MobjFlip(toucher)*(toucher->z - (special->z + special->height/2)) > 0) && (P_MobjFlip(toucher)*toucher->momz < 0))
|| (player->pflags & (PF_SPINNING|PF_GLIDING))
|| player->powers[pw_invulnerability] || player->powers[pw_super]) // Do you possess the ability to subdue the object?
@ -1478,7 +1506,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
return;
case MT_EXTRALARGEBUBBLE:
if ((player->powers[pw_shield] & SH_NOSTACK) == SH_ELEMENTAL)
if (player->powers[pw_shield] & SH_PROTECTWATER)
return;
if (maptol & TOL_NIGHTS)
return;
@ -1604,8 +1632,10 @@ static void P_HitDeathMessages(player_t *player, mobj_t *inflictor, mobj_t *sour
else switch (inflictor->type)
{
case MT_PLAYER:
if (damagetype == DMG_NUKE) // SH_BOMB, armageddon shield
if (damagetype == DMG_NUKE) // SH_ARMAGEDDON, armageddon shield
str = M_GetText("%s%s's armageddon blast %s %s.\n");
else if ((inflictor->player->powers[pw_shield] & SH_NOSTACK) == SH_ELEMENTAL && (inflictor->player->pflags & PF_SHIELDABILITY))
str = M_GetText("%s%s's flame stomp %s %s.\n");
else if (inflictor->player->powers[pw_invulnerability])
str = M_GetText("%s%s's invincibility aura %s %s.\n");
else if (inflictor->player->powers[pw_super])
@ -2321,24 +2351,27 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget
break;
case MT_PLAYER:
target->fuse = TICRATE*3; // timer before mobj disappears from view (even if not an actual player)
target->momx = target->momy = target->momz = 0;
if (damagetype == DMG_DROWNED) // drowned
{
target->movedir = damagetype; // we're MOVING the Damage Into anotheR function... Okay, this is a bit of a hack.
if (target->player->charflags & SF_MACHINE)
S_StartSound(target, sfx_fizzle);
target->fuse = TICRATE*3; // timer before mobj disappears from view (even if not an actual player)
target->momx = target->momy = target->momz = 0;
if (damagetype == DMG_DROWNED) // drowned
{
target->movedir = damagetype; // we're MOVING the Damage Into anotheR function... Okay, this is a bit of a hack.
if (target->player->charflags & SF_MACHINE)
S_StartSound(target, sfx_fizzle);
else
S_StartSound(target, sfx_drown);
// Don't jump up when drowning
}
else
S_StartSound(target, sfx_drown);
// Don't jump up when drowning
}
else
{
P_SetObjectMomZ(target, 14*FRACUNIT, false);
if ((source && source->type == MT_SPIKE) || damagetype == DMG_SPIKE) // Spikes
S_StartSound(target, sfx_spkdth);
else
P_PlayDeathSound(target);
{
P_SetObjectMomZ(target, 14*FRACUNIT, false);
if ((source && source->type == MT_SPIKE) || damagetype == DMG_SPIKE) // Spikes
S_StartSound(target, sfx_spkdth);
else
P_PlayDeathSound(target);
}
}
break;
default:
@ -2786,22 +2819,21 @@ void P_RemoveShield(player_t *player)
{
if (player->powers[pw_shield] & SH_FORCE)
{ // Multi-hit
if ((player->powers[pw_shield] & 0xFF) == 0)
player->powers[pw_shield] &= ~SH_FORCE;
else
if (player->powers[pw_shield] & SH_FORCEHP)
player->powers[pw_shield]--;
else
player->powers[pw_shield] &= SH_STACK;
}
else if ((player->powers[pw_shield] & SH_NOSTACK) == SH_NONE)
{ // Second layer shields
player->powers[pw_shield] = SH_NONE;
// Reset fireflower
if (!player->powers[pw_super])
if (((player->powers[pw_shield] & SH_STACK) == SH_FIREFLOWER) && !(player->powers[pw_super] || (mariomode && player->powers[pw_invulnerability])))
{
player->mo->color = player->skincolor;
G_GhostAddColor(GHC_NORMAL);
}
player->powers[pw_shield] = SH_NONE;
}
else if ((player->powers[pw_shield] & SH_NOSTACK) == SH_BOMB) // Give them what's coming to them!
else if ((player->powers[pw_shield] & SH_NOSTACK) == SH_ARMAGEDDON) // Give them what's coming to them!
{
P_BlackOw(player); // BAM!
player->pflags |= PF_JUMPDOWN;
@ -3027,12 +3059,15 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
switch (damagetype)
{
case DMG_WATER:
if (player->powers[pw_shield] & SH_PROTECTWATER)
return false; // Invincible to water damage
break;
case DMG_FIRE:
if ((player->powers[pw_shield] & SH_NOSTACK) == SH_ELEMENTAL)
return false; // Invincible to water/fire damage
if (player->powers[pw_shield] & SH_PROTECTFIRE)
return false; // Invincible to fire damage
break;
case DMG_ELECTRIC:
if ((player->powers[pw_shield] & SH_NOSTACK) == SH_ATTRACT)
if (player->powers[pw_shield] & SH_PROTECTELECTRIC)
return false; // Invincible to electric damage
break;
default:
@ -3061,7 +3096,7 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
if (!force && inflictor && inflictor->flags & MF_FIRE)
{
if ((player->powers[pw_shield] & SH_NOSTACK) == SH_ELEMENTAL)
if (player->powers[pw_shield] & SH_PROTECTFIRE)
return false; // Invincible to fire objects
if (G_PlatformGametype() && inflictor && source && source->player)

View file

@ -59,9 +59,10 @@
#define AIMINGTOSLOPE(aiming) FINESINE((aiming>>ANGLETOFINESHIFT) & FINEMASK)
#define mariomode (maptol & TOL_MARIO)
#define twodlevel (maptol & TOL_2D)
#define mariomode (maptol & TOL_MARIO)
#define P_GetPlayerHeight(player) FixedMul(player->height, player->mo->scale)
#define P_GetPlayerSpinHeight(player) FixedMul(player->spinheight, player->mo->scale)
@ -143,6 +144,7 @@ boolean P_InQuicksand(mobj_t *mo);
void P_SetObjectMomZ(mobj_t *mo, fixed_t value, boolean relative);
void P_RestoreMusic(player_t *player);
void P_SpawnShieldOrb(player_t *player);
void P_SwitchShield(player_t *player, UINT16 shieldtype);
mobj_t *P_SpawnGhostMobj(mobj_t *mobj);
void P_GivePlayerRings(player_t *player, INT32 num_rings);
void P_GivePlayerLives(player_t *player, INT32 numlives);
@ -152,8 +154,9 @@ void P_ResetScore(player_t *player);
boolean P_AutoPause(void);
void P_DoJumpShield(player_t *player);
void P_DoBubbleBounce(player_t *player);
void P_BlackOw(player_t *player);
void P_ElementalFireTrail(player_t *player);
void P_ElementalFire(player_t *player, boolean cropcircle);
void P_DoPityCheck(player_t *player);
void P_PlayerThink(player_t *player);
@ -166,7 +169,7 @@ fixed_t P_ReturnThrustX(mobj_t *mo, angle_t angle, fixed_t move);
fixed_t P_ReturnThrustY(mobj_t *mo, angle_t angle, fixed_t move);
void P_InstaThrustEvenIn2D(mobj_t *mo, angle_t angle, fixed_t move);
boolean P_LookForEnemies(player_t *player);
boolean P_LookForEnemies(player_t *player, boolean nonenemies);
void P_NukeEnemies(mobj_t *inflictor, mobj_t *source, fixed_t radius);
void P_HomingAttack(mobj_t *source, mobj_t *enemy); /// \todo doesn't belong in p_user
boolean P_SuperReady(player_t *player);

View file

@ -203,7 +203,7 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object)
}
}
pflags = object->player->pflags & (PF_JUMPED|PF_SPINNING|PF_THOKKED); // I still need these.
pflags = object->player->pflags & (PF_JUMPED|PF_SPINNING|PF_THOKKED|PF_SHIELDABILITY); // I still need these.
jumping = object->player->jumping;
secondjump = object->player->secondjump;
P_ResetPlayer(object->player);
@ -969,10 +969,10 @@ static boolean PIT_CheckThing(mobj_t *thing)
{
if (G_RingSlingerGametype() && (!G_GametypeHasTeams() || tmthing->player->ctfteam != thing->player->ctfteam))
{
if ((tmthing->player->powers[pw_invulnerability] || tmthing->player->powers[pw_super])
if ((tmthing->player->powers[pw_invulnerability] || tmthing->player->powers[pw_super] || (((tmthing->player->powers[pw_shield] & SH_NOSTACK) == SH_ELEMENTAL) && (tmthing->player->pflags & PF_SHIELDABILITY)))
&& !thing->player->powers[pw_super])
P_DamageMobj(thing, tmthing, tmthing, 1, 0);
else if ((thing->player->powers[pw_invulnerability] || thing->player->powers[pw_super])
else if ((thing->player->powers[pw_invulnerability] || thing->player->powers[pw_super] || (((thing->player->powers[pw_shield] & SH_NOSTACK) == SH_ELEMENTAL) && (thing->player->pflags & PF_SHIELDABILITY)))
&& !tmthing->player->powers[pw_super])
P_DamageMobj(tmthing, thing, thing, 1, 0);
}
@ -1052,24 +1052,41 @@ static boolean PIT_CheckThing(mobj_t *thing)
else if (thing->z - FixedMul(FRACUNIT, thing->scale) <= tmthing->z + tmthing->height
&& thing->z + thing->height + FixedMul(FRACUNIT, thing->scale) >= tmthing->z)
{
// 0 = none, 1 = elemental pierce, 2 = bubble bounce
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 (thing->flags & MF_MONITOR
&& (tmthing->player->pflags & (PF_SPINNING|PF_GLIDING)
|| ((tmthing->player->pflags & PF_JUMPED)
&& !(tmthing->player->charflags & SF_NOJUMPDAMAGE
&& !(tmthing->player->charability == CA_TWINSPIN && tmthing->player->panim == PA_ABILITY)))
&& (tmthing->player->pflags & PF_FORCEJUMPDAMAGE
|| !(tmthing->player->charflags & SF_NOJUMPSPIN)
|| (tmthing->player->charability == CA_TWINSPIN && tmthing->player->panim == PA_ABILITY)))
|| (tmthing->player->charability2 == CA2_MELEE && tmthing->player->panim == PA_ABILITY2)
|| ((tmthing->player->charflags & SF_STOMPDAMAGE)
&& (P_MobjFlip(tmthing)*(tmthing->z - (thing->z + thing->height/2)) > 0) && (P_MobjFlip(tmthing)*tmthing->momz < 0))))
&& (P_MobjFlip(tmthing)*(tmthing->z - (thing->z + thing->height/2)) > 0) && (P_MobjFlip(tmthing)*tmthing->momz < 0))
|| elementalpierce))
{
player_t *player = tmthing->player;
SINT8 flipval = P_MobjFlip(thing); // Save this value in case monitor gets removed.
fixed_t *momz = &tmthing->momz; // tmthing gets changed by P_DamageMobj, so we need a new pointer?! X_x;;
fixed_t *z = &tmthing->z; // aau.
P_DamageMobj(thing, tmthing, tmthing, 1, 0); // break the monitor
// Going down? Then bounce back up.
if ((P_MobjWasRemoved(thing) // Monitor was removed
|| !thing->health) // or otherwise popped
&& (flipval*(*momz) < 0)) // monitor is on the floor and you're going down, or on the ceiling and you're going up
*momz = -*momz; // Therefore, you should be thrust in the opposite direction, vertically.
return false;
&& (flipval*(*momz) < 0) // monitor is on the floor and you're going down, or on the ceiling and you're going up
&& (elementalpierce != 1)) // you're not piercing through the monitor...
{
if (elementalpierce == 2)
P_DoBubbleBounce(player);
else
*momz = -*momz; // Therefore, you should be thrust in the opposite direction, vertically.
}
if (!(elementalpierce == 1 && thing->flags & MF_GRENADEBOUNCE)) // prevent gold monitor clipthrough.
return false;
else
*z -= *momz; // to ensure proper collision.
}
}
}
@ -1084,8 +1101,9 @@ static boolean PIT_CheckThing(mobj_t *thing)
else if (thing->flags & MF_MONITOR && tmthing->player
&& (tmthing->player->pflags & (PF_SPINNING|PF_GLIDING)
|| ((tmthing->player->pflags & PF_JUMPED)
&& !(tmthing->player->charflags & SF_NOJUMPDAMAGE
&& !(tmthing->player->charability == CA_TWINSPIN && tmthing->player->panim == PA_ABILITY)))
&& (tmthing->player->pflags & PF_FORCEJUMPDAMAGE
|| !(tmthing->player->charflags & SF_NOJUMPSPIN)
|| (tmthing->player->charability == CA_TWINSPIN && tmthing->player->panim == PA_ABILITY)))
|| (tmthing->player->charability2 == CA2_MELEE && tmthing->player->panim == PA_ABILITY2)
|| ((tmthing->player->charflags & SF_STOMPDAMAGE)
&& (P_MobjFlip(tmthing)*(tmthing->z - (thing->z + thing->height/2)) > 0) && (P_MobjFlip(tmthing)*tmthing->momz < 0)))
@ -1124,6 +1142,9 @@ static boolean PIT_CheckThing(mobj_t *thing)
if (tmthing->player && tmthing->z + tmthing->height > topz
&& tmthing->z + tmthing->height < tmthing->ceilingz)
{
if (thing->flags & MF_GRENADEBOUNCE && (thing->flags & MF_MONITOR || thing->flags2 & MF2_STANDONME)) // Gold monitor hack...
return false;
tmfloorz = tmceilingz = INT32_MIN; // block while in air
#ifdef ESLOPE
tmceilingslope = NULL;
@ -1167,6 +1188,9 @@ static boolean PIT_CheckThing(mobj_t *thing)
if (tmthing->player && tmthing->z < topz
&& tmthing->z > tmthing->floorz)
{
if (thing->flags & MF_GRENADEBOUNCE && (thing->flags & MF_MONITOR || thing->flags2 & MF2_STANDONME)) // Gold monitor hack...
return false;
tmfloorz = tmceilingz = INT32_MAX; // block while in air
#ifdef ESLOPE
tmfloorslope = NULL;

View file

@ -2636,6 +2636,23 @@ static boolean P_ZMovement(mobj_t *mo)
mo->flags |= MF_NOGRAVITY;
}
break;
case MT_SPINFIRE:
if (P_CheckDeathPitCollide(mo))
{
P_RemoveMobj(mo);
return false;
}
if (mo->momz
&& !(mo->flags & MF_NOGRAVITY)
&& ((!(mo->eflags & MFE_VERTICALFLIP) && mo->z <= mo->floorz)
|| ((mo->eflags & MFE_VERTICALFLIP) && mo->z+mo->height >= mo->ceilingz)))
{
mo->flags |= MF_NOGRAVITY;
mo->momx = 8; // this is a hack which is used to ensure it still behaves as a missile and can damage others
mo->momy = mo->momz = 0;
mo->z = ((mo->eflags & MFE_VERTICALFLIP) ? mo->ceilingz-mo->height : mo->floorz);
}
break;
case MT_GOOP:
if (P_CheckDeathPitCollide(mo))
{
@ -3121,6 +3138,8 @@ static void P_PlayerZMovement(mobj_t *mo)
if (P_MobjFlip(mo)*mo->momz < 0) // falling
{
boolean clipmomz = !(P_CheckDeathPitCollide(mo));
mo->pmomz = 0; // We're on a new floor, don't keep doing platform movement.
// Squat down. Decrease viewheight for a moment after hitting the ground (hard),
@ -3250,23 +3269,56 @@ static void P_PlayerZMovement(mobj_t *mo)
mo->player->pflags &= ~PF_SPINNING;
if (!(mo->player->pflags & PF_GLIDING))
mo->player->pflags &= ~PF_JUMPED;
mo->player->pflags &= ~(PF_JUMPED|PF_FORCEJUMPDAMAGE);
mo->player->pflags &= ~(PF_THOKKED|PF_CANCARRY/*|PF_GLIDING*/);
mo->player->jumping = 0;
mo->player->secondjump = 0;
mo->player->glidetime = 0;
mo->player->climbing = 0;
mo->player->powers[pw_tailsfly] = 0;
if (mo->player->pflags & PF_SHIELDABILITY)
{
mo->player->pflags &= ~PF_SHIELDABILITY;
if ((mo->player->powers[pw_shield] & SH_NOSTACK) == SH_ELEMENTAL) // Elemental shield's stomp attack.
{
if (mo->eflags & (MFE_UNDERWATER|MFE_TOUCHWATER)) // play a blunt sound
S_StartSound(mo, sfx_s3k4c);
else // create a fire pattern on the ground
{
S_StartSound(mo, sfx_s3k47);
P_ElementalFire(mo->player, true);
}
P_SetObjectMomZ(mo,
(mo->eflags & MFE_UNDERWATER)
? 6*FRACUNIT/5
: 5*FRACUNIT/2,
false);
P_SetPlayerMobjState(mo, S_PLAY_FALL);
mo->momx = mo->momy = 0;
clipmomz = false;
}
else if ((mo->player->powers[pw_shield] & SH_NOSTACK) == SH_BUBBLEWRAP) // Bubble shield's bounce attack.
{
P_DoBubbleBounce(mo->player);
clipmomz = false;
}
}
}
}
if (!(mo->player->pflags & PF_SPINNING))
mo->player->pflags &= ~PF_STARTDASH;
if (tmfloorthing && (tmfloorthing->flags & (MF_PUSHABLE|MF_MONITOR)
|| tmfloorthing->flags2 & MF2_STANDONME || tmfloorthing->type == MT_PLAYER))
mo->momz = tmfloorthing->momz;
else if (!tmfloorthing)
mo->momz = 0;
if (clipmomz)
{
if (tmfloorthing && (tmfloorthing->flags & (MF_PUSHABLE|MF_MONITOR)
|| tmfloorthing->flags2 & MF2_STANDONME || tmfloorthing->type == MT_PLAYER))
mo->momz = tmfloorthing->momz;
else if (!tmfloorthing)
mo->momz = 0;
}
}
else if (tmfloorthing && (tmfloorthing->flags & (MF_PUSHABLE|MF_MONITOR)
|| tmfloorthing->flags2 & MF2_STANDONME || tmfloorthing->type == MT_PLAYER))
@ -3538,6 +3590,7 @@ void P_MobjCheckWater(mobj_t *mobj)
ffloor_t *rover;
player_t *p = mobj->player; // Will just be null if not a player.
fixed_t height = (p ? P_GetPlayerHeight(p) : mobj->height); // for players, calculation height does not necessarily match actual height for gameplay reasons (spin, etc)
boolean wasgroundpounding = (p && (mobj->eflags & MFE_GOOWATER) && ((p->powers[pw_shield] & SH_NOSTACK) == SH_ELEMENTAL || (p->powers[pw_shield] & SH_NOSTACK) == SH_BUBBLEWRAP) && (p->pflags & PF_SHIELDABILITY));
// Default if no water exists.
mobj->watertop = mobj->waterbottom = mobj->z - 1000*FRACUNIT;
@ -3608,15 +3661,24 @@ void P_MobjCheckWater(mobj_t *mobj)
{
if (!((p->powers[pw_super]) || (p->powers[pw_invulnerability])))
{
if ((p->powers[pw_shield] & SH_NOSTACK) == SH_ATTRACT)
{ // Water removes attract shield.
boolean electric = !!(p->powers[pw_shield] & SH_PROTECTELECTRIC);
#define SH_OP (SH_PROTECTFIRE|SH_PROTECTWATER|SH_PROTECTELECTRIC)
if ((p->powers[pw_shield] & SH_OP) == SH_OP) // No.
P_KillMobj(mobj, NULL, NULL, DMG_INSTAKILL);
#undef SH_OP
else if (electric || ((p->powers[pw_shield] & SH_PROTECTFIRE) && !(p->powers[pw_shield] & SH_PROTECTWATER)))
{ // Water removes electric and non-water fire shields...
P_FlashPal(p,
electric
? PAL_WHITE
: PAL_NUKE,
1);
p->powers[pw_shield] = p->powers[pw_shield] & SH_STACK;
P_FlashPal(p, PAL_WHITE, 1);
}
}
// Drown timer setting
if ((p->powers[pw_shield] & SH_NOSTACK) == SH_ELEMENTAL // Has elemental
if ((p->powers[pw_shield] & SH_PROTECTWATER) // Has water protection
|| (p->exiting) // Or exiting
|| (maptol & TOL_NIGHTS) // Or in NiGHTS mode
|| (mariomode)) // Or in Mario mode...
@ -3629,6 +3691,12 @@ void P_MobjCheckWater(mobj_t *mobj)
// Then we'll set it!
p->powers[pw_underwater] = underwatertics + 1;
}
if (wasgroundpounding)
{
p->pflags &= ~PF_SHIELDABILITY;
mobj->momz >>= 1;
}
}
// The rest of this code only executes on a water state change.
@ -3646,7 +3714,7 @@ void P_MobjCheckWater(mobj_t *mobj)
|| ((mobj->eflags & MFE_VERTICALFLIP) && mobj->ceilingz-mobj->waterbottom <= height>>1))
return;
if ((mobj->eflags & MFE_GOOWATER || wasingoo)) { // Decide what happens to your momentum when you enter/leave goopy water.
if (!wasgroundpounding && (mobj->eflags & MFE_GOOWATER || wasingoo)) { // Decide what happens to your momentum when you enter/leave goopy water.
if (P_MobjFlip(mobj)*mobj->momz < 0) // You are entering the goo?
mobj->momz = FixedMul(mobj->momz, FixedDiv(2*FRACUNIT, 5*FRACUNIT)); // kill momentum significantly, to make the goo feel thick.
}
@ -6318,7 +6386,7 @@ static boolean P_ShieldLook(mobj_t *thing, shieldtype_t shield)
// TODO: Make an MT_SHIELDORB which changes color/states to always match the appropriate shield,
// instead of having completely seperate mobjtypes.
if (shield != SH_FORCE)
if (!(shield & SH_FORCE))
{ // Regular shields check for themselves only
if ((shieldtype_t)(thing->target->player->powers[pw_shield] & SH_NOSTACK) != shield)
{
@ -6332,9 +6400,9 @@ static boolean P_ShieldLook(mobj_t *thing, shieldtype_t shield)
return false;
}
if (shield == SH_FORCE && thing->movecount != (thing->target->player->powers[pw_shield] & 0xFF))
if (shield & SH_FORCE && thing->movecount != (thing->target->player->powers[pw_shield] & SH_FORCEHP))
{
thing->movecount = (thing->target->player->powers[pw_shield] & 0xFF);
thing->movecount = (thing->target->player->powers[pw_shield] & SH_FORCEHP);
if (thing->movecount < 1)
{
if (thing->info->painstate)
@ -6355,13 +6423,14 @@ static boolean P_ShieldLook(mobj_t *thing, shieldtype_t shield)
thing->eflags = (thing->eflags & ~MFE_VERTICALFLIP)|(thing->target->eflags & MFE_VERTICALFLIP);
P_SetScale(thing, FixedMul(thing->target->scale, thing->target->player->shieldscale));
thing->destscale = thing->scale;
P_UnsetThingPosition(thing);
thing->x = thing->target->x;
thing->y = thing->target->y;
if (thing->eflags & MFE_VERTICALFLIP)
thing->z = thing->target->z + thing->target->height - thing->height + FixedDiv(P_GetPlayerHeight(thing->target->player) - thing->target->height, 3*FRACUNIT) - FixedMul(2*FRACUNIT, thing->target->scale);
thing->z = thing->target->z + (thing->target->height - thing->height + FixedDiv(P_GetPlayerHeight(thing->target->player) - thing->target->height, 3*FRACUNIT)) - FixedMul(2*FRACUNIT, thing->target->scale);
else
thing->z = thing->target->z - FixedDiv(P_GetPlayerHeight(thing->target->player) - thing->target->height, 3*FRACUNIT) + FixedMul(2*FRACUNIT, thing->target->scale);
thing->z = thing->target->z - (FixedDiv(P_GetPlayerHeight(thing->target->player) - thing->target->height, 3*FRACUNIT)) + FixedMul(2*FRACUNIT, thing->target->scale);
P_SetThingPosition(thing);
P_CheckPosition(thing, thing->x, thing->y);
@ -6384,7 +6453,7 @@ void P_RunShields(void)
// run shields
for (i = 0; i < numshields; i++)
{
P_ShieldLook(shields[i], shields[i]->info->speed);
P_ShieldLook(shields[i], shields[i]->threshold);
P_SetTarget(&shields[i], NULL);
}
numshields = 0;
@ -6392,7 +6461,7 @@ void P_RunShields(void)
static boolean P_AddShield(mobj_t *thing)
{
shieldtype_t shield = thing->info->speed;
shieldtype_t shield = thing->threshold;
if (!thing->target || thing->target->health <= 0 || !thing->target->player
|| (thing->target->player->powers[pw_shield] & SH_NOSTACK) == SH_NONE || thing->target->player->powers[pw_super]
@ -6402,7 +6471,7 @@ static boolean P_AddShield(mobj_t *thing)
return false;
}
if (shield != SH_FORCE)
if (!(shield & SH_FORCE))
{ // Regular shields check for themselves only
if ((shieldtype_t)(thing->target->player->powers[pw_shield] & SH_NOSTACK) != shield)
{
@ -6440,6 +6509,13 @@ void P_RunOverlays(void)
if (!mo->target)
continue;
if (P_MobjWasRemoved(mo->target))
{
P_RemoveMobj(mo);
continue;
}
if (!splitscreen /*&& rendermode != render_soft*/)
{
angle_t viewingangle;
@ -6619,7 +6695,7 @@ void P_MobjThinker(mobj_t *mobj)
fixed_t oldheight = mobj->height;
UINT8 correctionType = 0; // Don't correct Z position, just gain height
if (mobj->z > mobj->floorz && mobj->z + mobj->height < mobj->ceilingz
if ((mobj->flags & MF_NOCLIPHEIGHT || (mobj->z > mobj->floorz && mobj->z + mobj->height < mobj->ceilingz))
&& mobj->type != MT_EGGMOBILE_FIRE)
correctionType = 1; // Correct Z position by centering
else if (mobj->eflags & MFE_VERTICALFLIP)
@ -6664,6 +6740,11 @@ void P_MobjThinker(mobj_t *mobj)
if (P_MobjWasRemoved(mobj))
return;
#endif
if (mobj->flags2 & MF2_SHIELD)
if (!P_AddShield(mobj))
return;
switch (mobj->type)
{
case MT_HOOP:
@ -6720,15 +6801,121 @@ void P_MobjThinker(mobj_t *mobj)
else
P_AddOverlay(mobj);
break;
case MT_BLACKORB:
case MT_WHITEORB:
case MT_GREENORB:
case MT_YELLOWORB:
case MT_BLUEORB:
case MT_PITYORB:
if (!P_AddShield(mobj))
case MT_PITY_ORB:
case MT_WHIRLWIND_ORB:
case MT_ARMAGEDDON_ORB:
if (!(mobj->flags2 & MF2_SHIELD))
return;
break;
case MT_ATTRACT_ORB:
if (!(mobj->flags2 & MF2_SHIELD))
return;
if (/*(mobj->target) -- the following is implicit by P_AddShield
&& (mobj->target->player)
&& */ (mobj->target->player->homing))
{
P_SetMobjState(mobj, mobj->info->painstate);
mobj->tics++;
}
break;
case MT_ELEMENTAL_ORB:
if (!(mobj->flags2 & MF2_SHIELD))
return;
if (mobj->tracer
/* && mobj->target -- the following is implicit by P_AddShield
&& mobj->target->player
&& (mobj->target->player->powers[pw_shield] & SH_NOSTACK) == SH_ELEMENTAL */
&& mobj->target->player->pflags & PF_SHIELDABILITY
&& ((statenum_t)(mobj->tracer->state-states) < mobj->info->raisestate
|| (mobj->tracer->state->nextstate < mobj->info->raisestate && mobj->tracer->tics == 1)))
{
P_SetMobjState(mobj, mobj->info->painstate);
mobj->tics++;
P_SetMobjState(mobj->tracer, mobj->info->raisestate);
mobj->tracer->tics++;
}
break;
case MT_FORCE_ORB:
if (!(mobj->flags2 & MF2_SHIELD))
return;
if (/*
&& mobj->target -- the following is implicit by P_AddShield
&& mobj->target->player
&& (mobj->target->player->powers[pw_shield] & SH_FORCE)
&& */ (mobj->target->player->pflags & PF_SHIELDABILITY))
{
mobj_t *whoosh = P_SpawnMobjFromMobj(mobj, 0, 0, 0, MT_GHOST); // done here so the offset is correct
P_SetMobjState(whoosh, mobj->info->raisestate);
whoosh->destscale = whoosh->scale<<1;
whoosh->scalespeed = FixedMul(whoosh->scalespeed, whoosh->scale);
whoosh->height = 38*whoosh->scale;
whoosh->fuse = 10;
whoosh->flags |= MF_NOCLIPHEIGHT;
whoosh->momz = mobj->target->momz; // Stay reasonably centered for a few frames
mobj->target->player->pflags &= ~PF_SHIELDABILITY; // prevent eternal whoosh
}
case MT_FLAMEAURA_ORB:
if (!(mobj->flags2 & MF2_SHIELD))
return;
mobj->angle = mobj->target->angle; // implicitly okay because of P_AddShield
if (mobj->tracer
/* && mobj->target -- the following is implicit by P_AddShield
&& mobj->target->player
&& (mobj->target->player->powers[pw_shield] & SH_NOSTACK) == SH_FLAMEAURA */
&& mobj->target->player->pflags & PF_SHIELDABILITY
&& ((statenum_t)(mobj->tracer->state-states) < mobj->info->raisestate
|| (mobj->tracer->state->nextstate < mobj->info->raisestate && mobj->tracer->tics == 1)))
{
P_SetMobjState(mobj, mobj->info->painstate);
mobj->tics++;
P_SetMobjState(mobj->tracer, mobj->info->raisestate);
mobj->tracer->tics++;
}
break;
case MT_BUBBLEWRAP_ORB:
if (!(mobj->flags2 & MF2_SHIELD))
return;
if (mobj->tracer
/* && mobj->target -- the following is implicit by P_AddShield
&& mobj->target->player
&& (mobj->target->player->powers[pw_shield] & SH_NOSTACK) == SH_BUBBLEWRAP */
)
{
if (mobj->target->player->pflags & PF_SHIELDABILITY
&& ((statenum_t)(mobj->state-states) < mobj->info->painstate
|| (mobj->state->nextstate < mobj->info->painstate && mobj->tics == 1)))
{
P_SetMobjState(mobj, mobj->info->painstate);
mobj->tics++;
P_SetMobjState(mobj->tracer, mobj->info->raisestate);
mobj->tracer->tics++;
}
else if (mobj->target->eflags & MFE_JUSTHITFLOOR
&& (statenum_t)(mobj->state-states) == mobj->info->painstate)
{
P_SetMobjState(mobj, mobj->info->painstate+1);
mobj->tics++;
P_SetMobjState(mobj->tracer, mobj->info->raisestate+1);
mobj->tracer->tics++;
}
}
break;
case MT_THUNDERCOIN_ORB:
if (!(mobj->flags2 & MF2_SHIELD))
return;
if (mobj->tracer
/* && mobj->target -- the following is implicit by P_AddShield
&& mobj->target->player
&& (mobj->target->player->powers[pw_shield] & SH_NOSTACK) == SH_THUNDERCOIN */
&& (mobj->target->player->pflags & PF_SHIELDABILITY))
{
P_SetMobjState(mobj, mobj->info->painstate);
mobj->tics++;
P_SetMobjState(mobj->tracer, mobj->info->raisestate);
mobj->tracer->tics++;
mobj->target->player->pflags &= ~PF_SHIELDABILITY; // prevent eternal spark
}
break;
case MT_WATERDROP:
P_SceneryCheckWater(mobj);
if ((mobj->z <= mobj->floorz || mobj->z <= mobj->watertop)
@ -7576,10 +7763,13 @@ void P_MobjThinker(mobj_t *mobj)
}
break;
case MT_SPINFIRE:
if (mobj->eflags & MFE_VERTICALFLIP)
mobj->z = mobj->ceilingz - mobj->height;
else
mobj->z = mobj->floorz;
if (mobj->flags & MF_NOGRAVITY)
{
if (mobj->eflags & MFE_VERTICALFLIP)
mobj->z = mobj->ceilingz - mobj->height;
else
mobj->z = mobj->floorz;
}
// THERE IS NO BREAK HERE ON PURPOSE
default:
// check mobj against possible water content, before movement code

View file

@ -193,6 +193,7 @@ typedef enum
MF2_BOSSDEAD = 1<<26, // Boss is dead! (Not necessarily fleeing, if a fleeing point doesn't exist.)
MF2_AMBUSH = 1<<27, // Alternate behaviour typically set by MTF_AMBUSH
MF2_LINKDRAW = 1<<28, // Draw vissprite of mobj immediately before/after tracer's vissprite (dependent on dispoffset and position)
MF2_SHIELD = 1<<29, // Thinker calls P_AddShield/P_ShieldLook (must be partnered with MF_SCENERY to use)
// free: to and including 1<<31
} mobjflag2_t;

View file

@ -3581,7 +3581,7 @@ void P_ProcessSpecialSector(player_t *player, sector_t *sector, sector_t *rovers
P_PlayerFlagBurst(player, false);
break;
case 12: // Space Countdown
if ((player->powers[pw_shield] & SH_NOSTACK) != SH_ELEMENTAL && !player->powers[pw_spacetime])
if (!(player->powers[pw_shield] & SH_PROTECTWATER) && !player->powers[pw_spacetime])
player->powers[pw_spacetime] = spacetimetics + 1;
break;
case 13: // Ramp Sector (Increase step-up/down)

View file

@ -650,7 +650,7 @@ void P_NightserizePlayer(player_t *player, INT32 nighttime)
if (!(player->pflags & PF_NIGHTSMODE))
player->mo->height = P_GetPlayerHeight(player); // Just to make sure jumping into the drone doesn't result in a squashed hitbox.
player->pflags &= ~(PF_USEDOWN|PF_JUMPDOWN|PF_ATTACKDOWN|PF_STARTDASH|PF_GLIDING|PF_JUMPED|PF_THOKKED|PF_SPINNING|PF_DRILLING);
player->pflags &= ~(PF_USEDOWN|PF_JUMPDOWN|PF_ATTACKDOWN|PF_STARTDASH|PF_GLIDING|PF_JUMPED|PF_THOKKED|PF_SHIELDABILITY|PF_SPINNING|PF_DRILLING);
player->homing = 0;
player->mo->fuse = 0;
player->speed = 0;
@ -790,59 +790,64 @@ boolean P_PlayerInPain(player_t *player)
//
void P_DoPlayerPain(player_t *player, mobj_t *source, mobj_t *inflictor)
{
angle_t ang;
fixed_t fallbackspeed;
if (player->mo->eflags & MFE_VERTICALFLIP)
player->mo->z--;
else
player->mo->z++;
if (player->mo->eflags & MFE_UNDERWATER)
P_SetObjectMomZ(player->mo, FixedDiv(10511*FRACUNIT,2600*FRACUNIT), false);
else
P_SetObjectMomZ(player->mo, FixedDiv(69*FRACUNIT,10*FRACUNIT), false);
if (inflictor)
{
ang = R_PointToAngle2(inflictor->x-inflictor->momx, inflictor->y - inflictor->momy, player->mo->x - player->mo->momx, player->mo->y - player->mo->momy);
// explosion and rail rings send you farther back, making it more difficult
// to recover
if ((inflictor->flags2 & MF2_SCATTER) && source)
{
fixed_t dist = P_AproxDistance(P_AproxDistance(source->x-player->mo->x, source->y-player->mo->y), source->z-player->mo->z);
dist = FixedMul(128*FRACUNIT, inflictor->scale) - dist/4;
if (dist < FixedMul(4*FRACUNIT, inflictor->scale))
dist = FixedMul(4*FRACUNIT, inflictor->scale);
fallbackspeed = dist;
}
else if (inflictor->flags2 & MF2_EXPLOSION)
{
if (inflictor->flags2 & MF2_RAILRING)
fallbackspeed = FixedMul(38*FRACUNIT, inflictor->scale); // 7x
else
fallbackspeed = FixedMul(30*FRACUNIT, inflictor->scale); // 5x
}
else if (inflictor->flags2 & MF2_RAILRING)
fallbackspeed = FixedMul(45*FRACUNIT, inflictor->scale); // 4x
else
fallbackspeed = FixedMul(4*FRACUNIT, inflictor->scale); // the usual amount of force
}
else
{
ang = R_PointToAngle2(player->mo->momx, player->mo->momy, 0, 0);
fallbackspeed = FixedMul(4*FRACUNIT, player->mo->scale);
}
P_InstaThrust(player->mo, ang, fallbackspeed);
if (player->powers[pw_carry] == CR_ROPEHANG)
P_SetTarget(&player->mo->tracer, NULL);
{
angle_t ang;
fixed_t fallbackspeed;
P_ResetPlayer(player);
P_SetPlayerMobjState(player->mo, player->mo->info->painstate);
if (player->mo->eflags & MFE_VERTICALFLIP)
player->mo->z--;
else
player->mo->z++;
if (player->mo->eflags & MFE_UNDERWATER)
P_SetObjectMomZ(player->mo, FixedDiv(10511*FRACUNIT,2600*FRACUNIT), false);
else
P_SetObjectMomZ(player->mo, FixedDiv(69*FRACUNIT,10*FRACUNIT), false);
if (inflictor)
{
ang = R_PointToAngle2(inflictor->x-inflictor->momx, inflictor->y - inflictor->momy, player->mo->x - player->mo->momx, player->mo->y - player->mo->momy);
// explosion and rail rings send you farther back, making it more difficult
// to recover
if ((inflictor->flags2 & MF2_SCATTER) && source)
{
fixed_t dist = P_AproxDistance(P_AproxDistance(source->x-player->mo->x, source->y-player->mo->y), source->z-player->mo->z);
dist = FixedMul(128*FRACUNIT, inflictor->scale) - dist/4;
if (dist < FixedMul(4*FRACUNIT, inflictor->scale))
dist = FixedMul(4*FRACUNIT, inflictor->scale);
fallbackspeed = dist;
}
else if (inflictor->flags2 & MF2_EXPLOSION)
{
if (inflictor->flags2 & MF2_RAILRING)
fallbackspeed = FixedMul(38*FRACUNIT, inflictor->scale); // 7x
else
fallbackspeed = FixedMul(30*FRACUNIT, inflictor->scale); // 5x
}
else if (inflictor->flags2 & MF2_RAILRING)
fallbackspeed = FixedMul(45*FRACUNIT, inflictor->scale); // 4x
else
fallbackspeed = FixedMul(4*FRACUNIT, inflictor->scale); // the usual amount of force
}
else
{
ang = R_PointToAngle2(player->mo->momx, player->mo->momy, 0, 0);
fallbackspeed = FixedMul(4*FRACUNIT, player->mo->scale);
}
P_InstaThrust(player->mo, ang, fallbackspeed);
}
// Point penalty for hitting a hazard during tag.
// Discourages players from intentionally hurting themselves to avoid being tagged.
if (gametype == GT_TAG && (!(player->pflags & PF_TAGGED) && !(player->pflags & PF_TAGIT)))
@ -853,8 +858,6 @@ void P_DoPlayerPain(player_t *player, mobj_t *source, mobj_t *inflictor)
player->score = 0;
}
P_ResetPlayer(player);
P_SetPlayerMobjState(player->mo, player->mo->info->painstate);
player->powers[pw_flashing] = flashingtics;
if (player->timeshit != UINT8_MAX)
@ -867,7 +870,7 @@ void P_DoPlayerPain(player_t *player, mobj_t *source, mobj_t *inflictor)
// Useful when you want to kill everything the player is doing.
void P_ResetPlayer(player_t *player)
{
player->pflags &= ~(PF_SPINNING|PF_STARTDASH|PF_JUMPED|PF_GLIDING|PF_THOKKED|PF_CANCARRY);
player->pflags &= ~(PF_SPINNING|PF_STARTDASH|PF_JUMPED|PF_FORCEJUMPDAMAGE|PF_GLIDING|PF_THOKKED|PF_CANCARRY|PF_SHIELDABILITY);
player->powers[pw_carry] = CR_NONE;
player->jumping = 0;
player->secondjump = 0;
@ -1348,24 +1351,38 @@ void P_SpawnShieldOrb(player_t *player)
I_Error("P_SpawnShieldOrb: player->mo is NULL!\n");
#endif
#ifdef HAVE_BLUA
if (LUAh_ShieldSpawn(player))
return;
#endif
if (player->powers[pw_shield] & SH_FORCE)
orbtype = MT_BLUEORB;
orbtype = MT_FORCE_ORB;
else switch (player->powers[pw_shield] & SH_NOSTACK)
{
case SH_JUMP:
orbtype = MT_WHITEORB;
case SH_WHIRLWIND:
orbtype = MT_WHIRLWIND_ORB;
break;
case SH_ATTRACT:
orbtype = MT_YELLOWORB;
orbtype = MT_ATTRACT_ORB;
break;
case SH_ELEMENTAL:
orbtype = MT_GREENORB;
orbtype = MT_ELEMENTAL_ORB;
break;
case SH_BOMB:
orbtype = MT_BLACKORB;
case SH_ARMAGEDDON:
orbtype = MT_ARMAGEDDON_ORB;
break;
case SH_PITY:
orbtype = MT_PITYORB;
orbtype = MT_PITY_ORB;
break;
case SH_FLAMEAURA:
orbtype = MT_FLAMEAURA_ORB;
break;
case SH_BUBBLEWRAP:
orbtype = MT_BUBBLEWRAP_ORB;
break;
case SH_THUNDERCOIN:
orbtype = MT_THUNDERCOIN_ORB;
break;
default:
return;
@ -1384,14 +1401,17 @@ 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;
shieldobj->threshold = (player->powers[pw_shield] & SH_FORCE) ? SH_FORCE : (player->powers[pw_shield] & SH_NOSTACK);
if (shieldobj->info->seestate)
{
ov = P_SpawnMobj(shieldobj->x, shieldobj->y, shieldobj->z, MT_OVERLAY);
P_SetTarget(&ov->target, shieldobj);
P_SetMobjState(ov, shieldobj->info->seestate);
P_SetTarget(&shieldobj->tracer, ov);
}
if (shieldobj->info->meleestate)
{
@ -1408,7 +1428,7 @@ void P_SpawnShieldOrb(player_t *player)
if (player->powers[pw_shield] & SH_FORCE)
{
//Copy and pasted from P_ShieldLook in p_mobj.c
shieldobj->movecount = (player->powers[pw_shield] & 0xFF);
shieldobj->movecount = (player->powers[pw_shield] & SH_FORCEHP);
if (shieldobj->movecount < 1)
{
if (shieldobj->info->painstate)
@ -1419,6 +1439,51 @@ void P_SpawnShieldOrb(player_t *player)
}
}
//
// P_SwitchShield
//
// Handles the possibility of switching between
// the non-stack layer of shields thoroughly,
// then adds the desired one.
//
void P_SwitchShield(player_t *player, UINT16 shieldtype)
{
boolean donthavealready = (shieldtype & SH_FORCE)
? (!(player->powers[pw_shield] & SH_FORCE) || (player->powers[pw_shield] & SH_FORCEHP) < (shieldtype & ~SH_FORCE))
: ((player->powers[pw_shield] & SH_NOSTACK) != shieldtype);
if (donthavealready)
{
boolean stopshieldability = (shieldtype & SH_FORCE)
? (!(player->powers[pw_shield] & SH_FORCE))
: true;
// Just in case.
if (stopshieldability && player->pflags & PF_SHIELDABILITY)
{
player->pflags &= ~(PF_SPINNING|PF_SHIELDABILITY); // They'll still have PF_THOKKED...
player->homing = 0;
}
player->powers[pw_shield] = shieldtype|(player->powers[pw_shield] & SH_STACK);
P_SpawnShieldOrb(player);
if (shieldtype & SH_PROTECTWATER)
{
if (player->powers[pw_underwater] && player->powers[pw_underwater] <= 12*TICRATE + 1)
P_RestoreMusic(player);
player->powers[pw_underwater] = 0;
if (player->powers[pw_spacetime] > 1)
{
player->powers[pw_spacetime] = 0;
P_RestoreMusic(player);
}
}
}
}
//
// P_SpawnGhostMobj
//
@ -2120,7 +2185,7 @@ static void P_CheckInvincibilityTimer(player_t *player)
{
if (mariomode)
{
if (player->powers[pw_shield] & SH_FIREFLOWER)
if ((player->powers[pw_shield] & SH_STACK) == SH_FIREFLOWER)
{
player->mo->color = SKINCOLOR_WHITE;
G_GhostAddColor(GHC_FIREFLOWER);
@ -2157,7 +2222,7 @@ static void P_DoBubbleBreath(player_t *player)
fixed_t z = player->mo->z;
mobj_t *bubble = NULL;
if (!(player->mo->eflags & MFE_UNDERWATER) || ((player->powers[pw_shield] & SH_NOSTACK) == SH_ELEMENTAL && !(player->pflags & PF_NIGHTSMODE)) || player->spectator)
if (!(player->mo->eflags & MFE_UNDERWATER) || ((player->powers[pw_shield] & SH_PROTECTWATER) && !(player->pflags & PF_NIGHTSMODE)) || player->spectator)
return;
if (player->charflags & SF_MACHINE)
@ -3143,7 +3208,7 @@ static void P_DoFiring(player_t *player, ticcmd_t *cmd)
if (cmd->buttons & BT_ATTACK || cmd->buttons & BT_FIRENORMAL)
{
if (!(player->pflags & PF_ATTACKDOWN) && player->powers[pw_shield] & SH_FIREFLOWER && !player->climbing)
if (!(player->pflags & PF_ATTACKDOWN) && (player->powers[pw_shield] & SH_STACK) == SH_FIREFLOWER && !player->climbing)
{
player->pflags |= PF_ATTACKDOWN;
P_SpawnPlayerMissile(player->mo, MT_FIREBALL, 0);
@ -3359,7 +3424,7 @@ static void P_DoSuperStuff(player_t *player)
P_SpawnShieldOrb(player);
// Restore color
if (player->powers[pw_shield] & SH_FIREFLOWER)
if ((player->powers[pw_shield] & SH_NOSTACK) == SH_FIREFLOWER)
{
player->mo->color = SKINCOLOR_WHITE;
G_GhostAddColor(GHC_FIREFLOWER);
@ -3406,7 +3471,7 @@ static void P_DoSuperStuff(player_t *player)
player->powers[pw_super] = 0;
// Restore color
if (player->powers[pw_shield] & SH_FIREFLOWER)
if ((player->powers[pw_shield] & SH_NOSTACK) == SH_FIREFLOWER)
{
player->mo->color = SKINCOLOR_WHITE;
G_GhostAddColor(GHC_FIREFLOWER);
@ -3859,18 +3924,59 @@ static void P_DoSpinAbility(player_t *player, ticcmd_t *cmd)
//
void P_DoJumpShield(player_t *player)
{
boolean electric = ((player->powers[pw_shield] & SH_PROTECTELECTRIC) == SH_PROTECTELECTRIC);
if (player->pflags & PF_THOKKED)
return;
player->pflags &= ~PF_JUMPED;
P_DoJump(player, false);
player->pflags &= ~PF_JUMPED;
player->secondjump = 0;
player->jumping = 0;
player->pflags |= PF_THOKKED;
player->secondjump = 0;
player->pflags |= PF_THOKKED|PF_SHIELDABILITY;
player->pflags &= ~PF_SPINNING;
P_SetPlayerMobjState(player->mo, S_PLAY_FALL);
S_StartSound(player->mo, sfx_wdjump);
if (electric)
{
mobj_t *spark;
INT32 i;
#define numangles 6
#define limitangle (360/numangles)
angle_t travelangle = player->mo->angle + P_RandomRange(-limitangle, limitangle)*ANG1;
for (i = 0; i < numangles; i++)
{
spark = P_SpawnMobjFromMobj(player->mo, 0, 0, 0, MT_THUNDERCOIN_SPARK);
P_InstaThrust(spark, travelangle + i*(ANGLE_MAX/numangles), FixedMul(4*FRACUNIT, spark->scale));
if (i % 2)
P_SetObjectMomZ(spark, -4*FRACUNIT, false);
}
#undef limitangle
#undef numangles
S_StartSound(player->mo, sfx_s3k45);
}
else
{
player->pflags &= ~PF_JUMPED;
P_SetPlayerMobjState(player->mo, S_PLAY_FALL);
S_StartSound(player->mo, sfx_wdjump);
}
}
//
// P_DoBubbleBounce
//
// Bubblewrap shield landing handling
//
void P_DoBubbleBounce(player_t *player)
{
player->pflags &= ~(PF_JUMPED|PF_SHIELDABILITY);
S_StartSound(player->mo, sfx_s3k44);
P_DoJump(player, false);
if (player->charflags & SF_NOJUMPSPIN)
P_SetPlayerMobjState(player->mo, S_PLAY_FALL);
player->pflags |= PF_THOKKED;
player->jumping = 0;
player->secondjump = UINT8_MAX;
player->mo->momz = FixedMul(player->mo->momz, 5*FRACUNIT/4);
}
//
@ -3941,6 +4047,10 @@ static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd)
{}
else if (onground || player->climbing || (player->mo->tracer && player->powers[pw_carry]))
{}
else if ((player->powers[pw_shield] & SH_NOSTACK) == SH_WHIRLWIND
&& !(player->pflags & PF_JUMPED)
&& !(player->pflags & PF_USEDOWN))
P_DoJumpShield(player);
else if (!(player->pflags & PF_SLIDING) && ((gametype != GT_CTF) || (!player->gotflag)))
{
#ifdef HAVE_BLUA
@ -4083,7 +4193,7 @@ static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd)
if (player->charability == CA_HOMINGTHOK && !player->homing)
{
if (P_LookForEnemies(player))
if (P_LookForEnemies(player, true))
{
if (player->mo->tracer)
player->homing = 3*TICRATE;
@ -4211,7 +4321,7 @@ static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd)
break;
}
}
else if ((player->powers[pw_shield] & SH_NOSTACK) == SH_JUMP && !player->powers[pw_super])
else if ((player->powers[pw_shield] & SH_NOSTACK) == SH_WHIRLWIND && !player->powers[pw_super])
P_DoJumpShield(player);
}
@ -6179,7 +6289,7 @@ void P_BlackOw(player_t *player)
player->powers[pw_shield] = player->powers[pw_shield] & SH_STACK;
}
void P_ElementalFireTrail(player_t *player)
void P_ElementalFire(player_t *player, boolean cropcircle)
{
fixed_t newx;
fixed_t newy;
@ -6197,40 +6307,65 @@ void P_ElementalFireTrail(player_t *player)
else
ground = player->mo->floorz;
travelangle = R_PointToAngle2(0, 0, player->rmomx, player->rmomy);
for (i = 0; i < 2; i++)
if (cropcircle)
{
newx = player->mo->x + P_ReturnThrustX(player->mo, travelangle + ((i&1) ? -1 : 1)*ANGLE_135, FixedMul(24*FRACUNIT, player->mo->scale));
newy = player->mo->y + P_ReturnThrustY(player->mo, travelangle + ((i&1) ? -1 : 1)*ANGLE_135, FixedMul(24*FRACUNIT, player->mo->scale));
#ifdef ESLOPE
if (player->mo->standingslope)
#define numangles 8
#define limitangle (180/numangles)
travelangle = player->mo->angle + P_RandomRange(-limitangle, limitangle)*ANG1;
for (i = 0; i < numangles; i++)
{
ground = P_GetZAt(player->mo->standingslope, newx, newy);
if (player->mo->eflags & MFE_VERTICALFLIP)
ground -= FixedMul(mobjinfo[MT_SPINFIRE].height, player->mo->scale);
flame = P_SpawnMobj(player->mo->x, player->mo->y, ground, MT_SPINFIRE);
flame->flags &= ~MF_NOGRAVITY;
P_SetTarget(&flame->target, player->mo);
flame->angle = travelangle + i*(ANGLE_MAX/numangles);
flame->fuse = TICRATE*7; // takes about an extra second to hit the ground
flame->destscale = player->mo->scale;
P_SetScale(flame, player->mo->scale);
flame->eflags = (flame->eflags & ~MFE_VERTICALFLIP)|(player->mo->eflags & MFE_VERTICALFLIP);
P_InstaThrust(flame, flame->angle, FixedMul(3*FRACUNIT, flame->scale));
P_SetObjectMomZ(flame, 3*FRACUNIT, false);
}
#endif
flame = P_SpawnMobj(newx, newy, ground, MT_SPINFIRE);
P_SetTarget(&flame->target, player->mo);
flame->angle = travelangle;
flame->fuse = TICRATE*6;
flame->destscale = player->mo->scale;
P_SetScale(flame, player->mo->scale);
flame->eflags = (flame->eflags & ~MFE_VERTICALFLIP)|(player->mo->eflags & MFE_VERTICALFLIP);
flame->momx = 8;
P_XYMovement(flame);
if (P_MobjWasRemoved(flame))
continue;
if (player->mo->eflags & MFE_VERTICALFLIP)
#undef limitangle
#undef numangles
}
else
{
travelangle = R_PointToAngle2(0, 0, player->rmomx, player->rmomy);
for (i = 0; i < 2; i++)
{
if (flame->z + flame->height < flame->ceilingz)
newx = player->mo->x + P_ReturnThrustX(player->mo, (travelangle + ((i&1) ? -1 : 1)*ANGLE_135), FixedMul(24*FRACUNIT, player->mo->scale));
newy = player->mo->y + P_ReturnThrustY(player->mo, (travelangle + ((i&1) ? -1 : 1)*ANGLE_135), FixedMul(24*FRACUNIT, player->mo->scale));
#ifdef ESLOPE
if (player->mo->standingslope)
{
ground = P_GetZAt(player->mo->standingslope, newx, newy);
if (player->mo->eflags & MFE_VERTICALFLIP)
ground -= FixedMul(mobjinfo[MT_SPINFIRE].height, player->mo->scale);
}
#endif
flame = P_SpawnMobj(newx, newy, ground, MT_SPINFIRE);
P_SetTarget(&flame->target, player->mo);
flame->angle = travelangle;
flame->fuse = TICRATE*6;
flame->destscale = player->mo->scale;
P_SetScale(flame, player->mo->scale);
flame->eflags = (flame->eflags & ~MFE_VERTICALFLIP)|(player->mo->eflags & MFE_VERTICALFLIP);
flame->momx = 8; // this is a hack which is used to ensure it still behaves as a missile and can damage others
P_XYMovement(flame);
if (P_MobjWasRemoved(flame))
continue;
if (player->mo->eflags & MFE_VERTICALFLIP)
{
if (flame->z + flame->height < flame->ceilingz)
P_RemoveMobj(flame);
}
else if (flame->z > flame->floorz)
P_RemoveMobj(flame);
}
else if (flame->z > flame->floorz)
P_RemoveMobj(flame);
}
}
@ -6524,7 +6659,7 @@ static void P_MovePlayer(player_t *player)
P_SetPlayerMobjState(player->mo, S_PLAY_WALK);
}
// If Springing (or nojumpspinning), but travelling DOWNWARD, change back! (nojumpspin also turns to fall once PF_THOKKED is added.)
// If Springing (or nojumpspinning), but travelling DOWNWARD, change back!
if ((player->panim == PA_SPRING && P_MobjFlip(player->mo)*player->mo->momz < 0)
|| ((((player->charflags & SF_NOJUMPSPIN) && (player->pflags & PF_JUMPED) && player->panim == PA_JUMP))
&& (P_MobjFlip(player->mo)*player->mo->momz < 0)))
@ -6780,7 +6915,7 @@ static void P_MovePlayer(player_t *player)
if ((player->powers[pw_shield] & SH_NOSTACK) == SH_ELEMENTAL
&& (player->pflags & PF_SPINNING) && player->speed > FixedMul(4<<FRACBITS, player->mo->scale) && onground && (leveltime & 1)
&& !(player->mo->eflags & (MFE_UNDERWATER|MFE_TOUCHWATER)))
P_ElementalFireTrail(player);
P_ElementalFire(player, false);
P_DoSpinAbility(player, cmd);
@ -6848,51 +6983,121 @@ static void P_MovePlayer(player_t *player)
localangle2 = player->mo->angle;
}
///////////////////////////
//BOMB SHIELD ACTIVATION,//
//HOMING, AND OTHER COOL //
//STUFF! //
///////////////////////////
//////////////////
//SHIELD ACTIVES//
//& SUPER FLOAT!//
//////////////////
if (cmd->buttons & BT_USE) // Spin button effects
if (player->pflags & PF_JUMPED && !player->exiting && player->mo->health)
{
if (player->pflags & PF_JUMPED) // If the player is jumping
if (cmd->buttons & BT_USE) // Spin button effects
{
if (!(player->pflags & PF_USEDOWN)) // If the player is not holding down BT_USE
if (player->powers[pw_super]) // Super can't use shield actives, only passives
{
// Jump shield activation
if (!P_PlayerInPain(player) // If the player is not in pain
&& !player->climbing // If the player is not climbing
&& !(player->pflags & (PF_GLIDING|PF_SLIDING|PF_THOKKED)) // If the player is not gliding or sliding and hasn't used their ability
&& !onground) // If the player isn't on the ground
if ((player->charability == CA_THOK) // Super Sonic float
&& (player->speed > 5*player->mo->scale) // FixedMul(5<<FRACBITS, player->mo->scale), but scale is FRACUNIT-based
&& (P_MobjFlip(player->mo)*player->mo->momz <= 0))
{
if ((player->powers[pw_shield] & SH_NOSTACK) == SH_JUMP && !player->powers[pw_super])
P_DoJumpShield(player);
}
// Bomb shield activation
if ((player->powers[pw_shield] & SH_NOSTACK) == SH_BOMB)
{
// Don't let Super Sonic or invincibility use it
if (!(player->powers[pw_super] || player->powers[pw_invulnerability]))
P_BlackOw(player);
if (player->panim == PA_PAIN || player->panim == PA_JUMP || player->panim == PA_FALL
|| (player->panim == PA_WALK && player->mo->state-states != S_PLAY_SUPER_FLOAT))
P_SetPlayerMobjState(player->mo, S_PLAY_SUPER_FLOAT);
player->mo->momz = 0;
player->pflags &= ~PF_SPINNING;
player->jumping = 0; // don't cut jump height after bouncing off something
}
}
// Super Sonic move
if (player->skin == 0 && player->powers[pw_super] && player->speed > FixedMul(5<<FRACBITS, player->mo->scale)
&& P_MobjFlip(player->mo)*player->mo->momz <= 0)
else
#ifdef HAVE_BLUA
if (!LUAh_ShieldSpecial(player))
#endif
{
if (player->panim == PA_ROLL || player->panim == PA_JUMP || player->mo->state-states == S_PLAY_PAIN || player->panim == PA_WALK)
P_SetPlayerMobjState(player->mo, S_PLAY_SUPER_FLOAT);
player->mo->momz = 0;
player->pflags &= ~PF_SPINNING;
player->jumping = 0; // don't cut jump height after bouncing off something
if (!(player->pflags & (PF_USEDOWN|PF_GLIDING|PF_SLIDING|PF_SHIELDABILITY)) // If the player is not holding down BT_USE, or having used an ability previously
&& (!(player->pflags & PF_THOKKED) || ((player->powers[pw_shield] & SH_NOSTACK) == SH_BUBBLEWRAP && player->secondjump == UINT8_MAX))) // thokked is optional if you're bubblewrapped
{
// Force shield activation
if ((player->powers[pw_shield] & ~(SH_FORCEHP|SH_STACK)) == SH_FORCE)
{
player->pflags |= PF_THOKKED|PF_SHIELDABILITY;
player->mo->momx = player->mo->momy = player->mo->momz = 0;
S_StartSound(player->mo, sfx_ngskid);
}
else
{
switch (player->powers[pw_shield] & SH_NOSTACK)
{
// Whirlwind/Thundercoin shield activation
case SH_WHIRLWIND:
case SH_THUNDERCOIN:
P_DoJumpShield(player);
break;
// Armageddon shield activation
case SH_ARMAGEDDON:
player->pflags |= PF_THOKKED|PF_SHIELDABILITY;
P_BlackOw(player);
break;
// Attract shield activation
case SH_ATTRACT:
player->pflags |= PF_THOKKED|PF_SHIELDABILITY;
player->homing = 2;
if (P_LookForEnemies(player, false) && player->mo->tracer)
{
player->pflags |= PF_FORCEJUMPDAMAGE;
P_SetPlayerMobjState(player->mo, S_PLAY_SPIN);
S_StartSound(player->mo, sfx_s3k40);
player->homing = 3*TICRATE;
}
else
S_StartSound(player->mo, sfx_s3ka6);
break;
// Elemental/Bubblewrap shield activation
case SH_ELEMENTAL:
case SH_BUBBLEWRAP:
player->pflags |= PF_FORCEJUMPDAMAGE|PF_THOKKED|PF_SHIELDABILITY;
P_SetPlayerMobjState(player->mo, S_PLAY_SPIN);
player->secondjump = 0;
player->mo->momx = player->mo->momy = 0;
P_SetObjectMomZ(player->mo, -24*FRACUNIT, false);
S_StartSound(player->mo,
((player->powers[pw_shield] & SH_NOSTACK) == SH_ELEMENTAL)
? sfx_s3k43
: sfx_s3k44);
break;
// Flame shield activation
case SH_FLAMEAURA:
player->pflags |= PF_THOKKED|PF_SHIELDABILITY;
P_Thrust(player->mo, player->mo->angle, FixedMul(30*FRACUNIT - FixedSqrt(FixedDiv(player->speed, player->mo->scale)), player->mo->scale));
S_StartSound(player->mo, sfx_s3k43);
default:
break;
}
}
}
}
}
}
// HOMING option.
if (player->charability == CA_HOMINGTHOK)
if ((player->powers[pw_shield] & SH_NOSTACK) == SH_ATTRACT // Sonic 3D Blast.
&& player->pflags & PF_SHIELDABILITY)
{
if (player->homing && player->mo->tracer)
{
P_HomingAttack(player->mo, player->mo->tracer);
if (player->mo->tracer->health <= 0 || (player->mo->tracer->flags2 & MF2_FRET))
{
P_SetObjectMomZ(player->mo, 6*FRACUNIT, false);
if (player->mo->eflags & MFE_UNDERWATER)
player->mo->momz = FixedMul(player->mo->momz, FRACUNIT/3);
player->homing = 0;
}
}
// If you're not jumping, then you obviously wouldn't be homing.
if (!(player->pflags & PF_JUMPED))
player->homing = 0;
}
else if (player->charability == CA_HOMINGTHOK) // Sonic Adventure.
{
// If you've got a target, chase after it!
if (player->homing && player->mo->tracer)
@ -7480,9 +7685,9 @@ void P_NukeEnemies(mobj_t *inflictor, mobj_t *source, fixed_t radius)
//
// P_LookForEnemies
// Looks for something you can hit - Used for homing attack
// Includes monitors and springs!
// If nonenemies is true, includes monitors and springs!
//
boolean P_LookForEnemies(player_t *player)
boolean P_LookForEnemies(player_t *player, boolean nonenemies)
{
mobj_t *mo;
thinker_t *think;
@ -7495,7 +7700,8 @@ boolean P_LookForEnemies(player_t *player)
continue; // not a mobj thinker
mo = (mobj_t *)think;
if (!(mo->flags & (MF_ENEMY|MF_BOSS|MF_MONITOR|MF_SPRING)))
if ((nonenemies && !(mo->flags & (MF_ENEMY|MF_BOSS|MF_MONITOR|MF_SPRING)))
|| (!nonenemies && !(mo->flags & (MF_ENEMY|MF_BOSS))))
continue; // not a valid enemy
if (mo->health <= 0) // dead
@ -7593,7 +7799,12 @@ void P_HomingAttack(mobj_t *source, mobj_t *enemy) // Home in on your target
ns = FixedMul(source->info->speed, source->scale);
}
else if (source->player)
ns = FixedDiv(FixedMul(source->player->actionspd, source->scale), 3*FRACUNIT/2);
{
if (source->player->charability == CA_HOMINGTHOK && !(source->player->pflags & PF_SHIELDABILITY))
ns = FixedDiv(FixedMul(source->player->actionspd, source->scale), 3*FRACUNIT/2);
else
ns = FixedMul(45*FRACUNIT, source->scale);
}
source->momx = FixedMul(FixedDiv(enemy->x - source->x, dist), ns);
source->momy = FixedMul(FixedDiv(enemy->y - source->y, dist), ns);
@ -8707,8 +8918,13 @@ void P_PlayerThink(player_t *player)
if (player->panim != PA_ABILITY)
P_SetPlayerMobjState(player->mo, S_PLAY_GLIDE);
}
else if ((player->pflags & PF_JUMPED) && !player->powers[pw_super] && player->panim != PA_JUMP && !(player->charflags & SF_NOJUMPSPIN))
P_SetPlayerMobjState(player->mo, S_PLAY_JUMP);
else if ((player->pflags & PF_JUMPED) && !player->powers[pw_super] && ((player->charflags & SF_NOJUMPSPIN && player->pflags & PF_FORCEJUMPDAMAGE && player->panim != PA_ROLL) || (!(player->charflags & SF_NOJUMPSPIN) && player->panim != PA_JUMP)))
{
if (!(player->charflags & SF_NOJUMPSPIN))
P_SetPlayerMobjState(player->mo, S_PLAY_JUMP);
else if (player->pflags & PF_FORCEJUMPDAMAGE)
P_SetPlayerMobjState(player->mo, S_PLAY_SPIN);
}
if (player->flashcount)
player->flashcount--;
@ -9027,7 +9243,7 @@ void P_PlayerThink(player_t *player)
if (player->powers[pw_tailsfly] && player->powers[pw_tailsfly] < UINT16_MAX && player->charability != CA_SWIM) // tails fly counter
player->powers[pw_tailsfly]--;
if (player->powers[pw_underwater] && (player->pflags & PF_GODMODE || (player->powers[pw_shield] & SH_NOSTACK) == SH_ELEMENTAL))
if (player->powers[pw_underwater] && (player->pflags & PF_GODMODE || (player->powers[pw_shield] & SH_PROTECTWATER)))
{
if (player->powers[pw_underwater] <= 12*TICRATE+1)
P_RestoreMusic(player); //incase they were about to drown
@ -9037,7 +9253,7 @@ void P_PlayerThink(player_t *player)
else if (player->powers[pw_underwater] && !(maptol & TOL_NIGHTS) && !((netgame || multiplayer) && player->spectator)) // underwater timer
player->powers[pw_underwater]--;
if (player->powers[pw_spacetime] && (player->pflags & PF_GODMODE || (player->powers[pw_shield] & SH_NOSTACK) == SH_ELEMENTAL))
if (player->powers[pw_spacetime] && (player->pflags & PF_GODMODE || (player->powers[pw_shield] & SH_PROTECTWATER)))
player->powers[pw_spacetime] = 0;
else if (player->powers[pw_spacetime] && !(maptol & TOL_NIGHTS) && !((netgame || multiplayer) && player->spectator)) // underwater timer
player->powers[pw_spacetime]--;
@ -9452,7 +9668,7 @@ void P_PlayerAfterThink(player_t *player)
player->mo->momy = (player->mo->tracer->y - player->mo->y)*2;
player->mo->momz = (player->mo->tracer->z - (player->mo->height-player->mo->tracer->height/2) - player->mo->z)*2;
P_TeleportMove(player->mo, player->mo->tracer->x, player->mo->tracer->y, player->mo->tracer->z - (player->mo->height-player->mo->tracer->height/2));
player->pflags |= PF_JUMPED;
player->pflags |= PF_JUMPED|PF_FORCEJUMPDAMAGE;
player->secondjump = 0;
player->pflags &= ~PF_THOKKED;

View file

@ -607,6 +607,13 @@ void S_StartSound(const void *origin, sfxenum_t sfx_id)
sfx_id = sfx_mario6;
break;
case sfx_shield:
case sfx_wirlsg:
case sfx_forcsg:
case sfx_elemsg:
case sfx_armasg:
case sfx_s3k3e:
case sfx_s3k3f:
case sfx_s3k41:
sfx_id = sfx_mario3;
break;
case sfx_itemup:

View file

@ -165,8 +165,12 @@ sfxinfo_t S_sfx[NUMSFX] =
{"rail1", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR},
{"rail2", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR},
{"rlaunc", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR},
{"shield", false, 60, 0, -1, NULL, 0, -1, -1, LUMPERROR},
{"shldls", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR},
{"shield", false, 60, 0, -1, NULL, 0, -1, -1, LUMPERROR}, // generic GET!
{"wirlsg", false, 60, 0, -1, NULL, 0, -1, -1, LUMPERROR}, // Whirlwind GET!
{"forcsg", false, 60, 0, -1, NULL, 0, -1, -1, LUMPERROR}, // Force GET!
{"elemsg", false, 60, 0, -1, NULL, 0, -1, -1, LUMPERROR}, // Elemental GET!
{"armasg", false, 60, 0, -1, NULL, 0, -1, -1, LUMPERROR}, // Armaggeddon GET!
{"shldls", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR}, // You LOSE!
{"spdpad", false, 127, 0, -1, NULL, 0, -1, -1, LUMPERROR},
{"spkdth", false, 127, 0, -1, NULL, 0, -1, -1, LUMPERROR},
{"spring", false, 112, 0, -1, NULL, 0, -1, -1, LUMPERROR},
@ -183,6 +187,7 @@ sfxinfo_t S_sfx[NUMSFX] =
{"wdjump", false, 60, 0, -1, NULL, 0, -1, -1, LUMPERROR},
{"mswarp", false, 60, 16, -1, NULL, 0, -1, -1, LUMPERROR},
{"mspogo", false, 60, 8, -1, NULL, 0, -1, -1, LUMPERROR},
{"boingf", false, 60, 0, -1, NULL, 0, -1, -1, LUMPERROR},
// Menu, interface
{"chchng", false, 120, 0, -1, NULL, 0, -1, -1, LUMPERROR},

View file

@ -229,6 +229,10 @@ typedef enum
sfx_rail2,
sfx_rlaunc,
sfx_shield,
sfx_wirlsg,
sfx_forcsg,
sfx_elemsg,
sfx_armasg,
sfx_shldls,
sfx_spdpad,
sfx_spkdth,
@ -246,6 +250,7 @@ typedef enum
sfx_wdjump,
sfx_mswarp,
sfx_mspogo,
sfx_boingf,
// Menu, interface
sfx_chchng,

View file

@ -99,6 +99,9 @@ static patch_t *ringshield;
static patch_t *watershield;
static patch_t *bombshield;
static patch_t *pityshield;
static patch_t *flameshield;
static patch_t *bubbleshield;
static patch_t *thundershield;
static patch_t *invincibility;
static patch_t *sneakers;
static patch_t *gravboots;
@ -294,6 +297,9 @@ void ST_LoadGraphics(void)
watershield = W_CachePatchName("TVELC0", PU_HUDGFX);
bombshield = W_CachePatchName("TVARC0", PU_HUDGFX);
pityshield = W_CachePatchName("TVPIC0", PU_HUDGFX);
flameshield = W_CachePatchName("TVFLC0", PU_HUDGFX);
bubbleshield = W_CachePatchName("TVBBC0", PU_HUDGFX);
thundershield = W_CachePatchName("TVZPC0", PU_HUDGFX);
invincibility = W_CachePatchName("TVIVC0", PU_HUDGFX);
sneakers = W_CachePatchName("TVSSC0", PU_HUDGFX);
gravboots = W_CachePatchName("TVGVC0", PU_HUDGFX);
@ -576,12 +582,13 @@ static void ST_drawDebugInfo(void)
V_DrawRightAlignedString(320, height - 80, V_MONOSPACE, va("AIR: %4d, %3d", stplyr->powers[pw_underwater], stplyr->powers[pw_spacetime]));
// Flags
V_DrawRightAlignedString(304-74, height - 72, V_MONOSPACE, "PF:");
V_DrawString(304-72, height - 72, (stplyr->jumping) ? V_GREENMAP : V_REDMAP, "JM");
V_DrawString(304-54, height - 72, (stplyr->pflags & PF_JUMPED) ? V_GREENMAP : V_REDMAP, "JD");
V_DrawString(304-36, height - 72, (stplyr->pflags & PF_SPINNING) ? V_GREENMAP : V_REDMAP, "SP");
V_DrawString(304-18, height - 72, (stplyr->pflags & PF_STARTDASH) ? V_GREENMAP : V_REDMAP, "ST");
V_DrawString(304, height - 72, (stplyr->pflags & PF_THOKKED) ? V_GREENMAP : V_REDMAP, "TH");
V_DrawRightAlignedString(304-92, height - 72, V_MONOSPACE, "PF:");
V_DrawString(304-90, height - 72, (stplyr->jumping) ? V_GREENMAP : V_REDMAP, "JM");
V_DrawString(304-72, height - 72, (stplyr->pflags & PF_JUMPED) ? V_GREENMAP : V_REDMAP, "JD");
V_DrawString(304-54, height - 72, (stplyr->pflags & PF_SPINNING) ? V_GREENMAP : V_REDMAP, "SP");
V_DrawString(304-36, height - 72, (stplyr->pflags & PF_STARTDASH) ? V_GREENMAP : V_REDMAP, "ST");
V_DrawString(304-18, height - 72, (stplyr->pflags & PF_THOKKED) ? V_GREENMAP : V_REDMAP, "TH");
V_DrawString(304, height - 72, (stplyr->pflags & PF_SHIELDABILITY) ? V_GREENMAP : V_REDMAP, "SH");
V_DrawRightAlignedString(320, height - 64, V_MONOSPACE, va("CEILZ: %6d", stplyr->mo->ceilingz>>FRACBITS));
V_DrawRightAlignedString(320, height - 56, V_MONOSPACE, va("FLOORZ: %6d", stplyr->mo->floorz>>FRACBITS));
@ -806,18 +813,21 @@ static void ST_drawFirstPersonHUD(void)
return;
// Graue 06-18-2004: no V_NOSCALESTART, no SCX, no SCY, snap to right
if (player->powers[pw_shield] & SH_FORCE)
if ((player->powers[pw_shield] & SH_NOSTACK & ~SH_FORCEHP) == SH_FORCE)
{
if ((player->powers[pw_shield] & 0xFF) > 0 || leveltime & 1)
if ((player->powers[pw_shield] & SH_FORCEHP) > 0 || leveltime & 1)
p = forceshield;
}
else switch (player->powers[pw_shield] & SH_NOSTACK)
{
case SH_JUMP: p = jumpshield; break;
case SH_ELEMENTAL: p = watershield; break;
case SH_BOMB: p = bombshield; break;
case SH_ATTRACT: p = ringshield; break;
case SH_PITY: p = pityshield; break;
case SH_WHIRLWIND: p = jumpshield; break;
case SH_ELEMENTAL: p = watershield; break;
case SH_ARMAGEDDON: p = bombshield; break;
case SH_ATTRACT: p = ringshield; break;
case SH_PITY: p = pityshield; break;
case SH_FLAMEAURA: p = flameshield; break;
case SH_BUBBLEWRAP: p = bubbleshield; break;
case SH_THUNDERCOIN: p = thundershield; break;
default: break;
}