diff --git a/src/d_player.h b/src/d_player.h index 724c137d3..1c57e6167 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -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 diff --git a/src/dehacked.c b/src/dehacked.c index 04b2e9ce5..f45b05b04 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -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}, diff --git a/src/hardware/hw_light.c b/src/hardware/hw_light.c index 9e5d92e0b..0bf3275c9 100644 --- a/src/hardware/hw_light.c +++ b/src/hardware/hw_light.c @@ -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 diff --git a/src/info.c b/src/info.c index a2d2bcaac..ad4aec136 100644 --- a/src/info.c +++ b/src/info.c @@ -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 diff --git a/src/info.h b/src/info.h index d3f4ad55a..932180ebf 100644 --- a/src/info.h +++ b/src/info.h @@ -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 diff --git a/src/lua_baselib.c b/src/lua_baselib.c index 6e0457ce8..0d59ff256 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -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}, diff --git a/src/lua_hook.h b/src/lua_hook.h index 97d447d2e..fd3130271 100644 --- a/src/lua_hook.h +++ b/src/lua_hook.h @@ -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 diff --git a/src/lua_hooklib.c b/src/lua_hooklib.c index e95b75eda..a1a34803c 100644 --- a/src/lua_hooklib.c +++ b/src/lua_hooklib.c @@ -54,6 +54,8 @@ const char *const hookNames[hook_MAX+1] = { "PlayerMsg", "HurtMsg", "PlayerSpawn", + "ShieldSpawn", + "ShieldSpecial", NULL }; diff --git a/src/p_enemy.c b/src/p_enemy.c index cca4ac560..76a86d8b9 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -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; diff --git a/src/p_floor.c b/src/p_floor.c index 8f51698cc..96d854a10 100644 --- a/src/p_floor.c +++ b/src/p_floor.c @@ -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 diff --git a/src/p_inter.c b/src/p_inter.c index 6ad04f477..974ae1b8f 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -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) diff --git a/src/p_local.h b/src/p_local.h index 8c49e4f18..df9b20a54 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -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); diff --git a/src/p_map.c b/src/p_map.c index 6ac48a7c8..7afd266fd 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -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; diff --git a/src/p_mobj.c b/src/p_mobj.c index 63b3c10e8..260593b66 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -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 diff --git a/src/p_mobj.h b/src/p_mobj.h index a8ec27f1a..f6ebd3cad 100644 --- a/src/p_mobj.h +++ b/src/p_mobj.h @@ -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; diff --git a/src/p_spec.c b/src/p_spec.c index 6e0ac7486..06e871c7e 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -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) diff --git a/src/p_user.c b/src/p_user.c index febbefac0..df9fbb2c1 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -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<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<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<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; diff --git a/src/s_sound.c b/src/s_sound.c index 47a955561..971961897 100644 --- a/src/s_sound.c +++ b/src/s_sound.c @@ -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: diff --git a/src/sounds.c b/src/sounds.c index 75ee1358c..b551b73b5 100644 --- a/src/sounds.c +++ b/src/sounds.c @@ -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}, diff --git a/src/sounds.h b/src/sounds.h index 532c61da6..42fa4c308 100644 --- a/src/sounds.h +++ b/src/sounds.h @@ -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, diff --git a/src/st_stuff.c b/src/st_stuff.c index 9a7f64986..658c2c6d6 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -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; }