diff --git a/src/d_clisrv.c b/src/d_clisrv.c index f1cacc833..1e01c8779 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -2540,7 +2540,7 @@ void CL_ClearPlayer(INT32 playernum) } #define PlayerPointerRemove(field) \ - if (field) \ + if (P_MobjWasRemoved(field) == false) \ { \ P_RemoveMobj(field); \ P_SetTarget(&field, NULL); \ @@ -2550,7 +2550,8 @@ void CL_ClearPlayer(INT32 playernum) PlayerPointerRemove(players[playernum].mo); PlayerPointerRemove(players[playernum].followmobj); PlayerPointerRemove(players[playernum].stumbleIndicator); - PlayerPointerRemove(players[playernum].sliptideZipIndicator); + PlayerPointerRemove(players[playernum].wavedashIndicator); + PlayerPointerRemove(players[playernum].trickIndicator); #undef PlayerPointerRemove diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 63a6f37a9..10ff36129 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -2429,13 +2429,16 @@ static void Command_Map_f(void) // Let's just guess so we don't have to specify the gametype EVERY time... newgametype = G_GuessGametypeByTOL(mapheaderinfo[newmapnum-1]->typeoflevel); - if (newgametype == -1) + if (!option_force && newgametype == -1) { CONS_Alert(CONS_WARNING, M_GetText("%s (%s) doesn't support any known gametype!\n"), realmapname, G_BuildMapName(newmapnum)); Z_Free(realmapname); Z_Free(mapname); return; } + + if (newgametype == -1) + newgametype = GT_RACE; // sensible default } } diff --git a/src/d_player.h b/src/d_player.h index 9cb40db98..d9d46979d 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -267,6 +267,16 @@ typedef enum TRIPWIRE_BLASTER, } tripwirepass_t; +typedef enum +{ + TRICKSTATE_NONE = 0, + TRICKSTATE_READY, + TRICKSTATE_FORWARD, + TRICKSTATE_RIGHT, + TRICKSTATE_LEFT, + TRICKSTATE_BACK, +} trickstate_t; + typedef enum { // Unsynced, HUD or clientsided effects @@ -644,6 +654,7 @@ struct player_t respawnvars_t respawn; // Respawn info mobj_t *ringShooter; // DEZ respawner object tic_t airtime; // Used to track just air time, but has evolved over time into a general "karted" timer. Rename this variable? + tic_t lastairtime; UINT8 startboost; // (0 to 125) - Boost you get from start of race UINT8 dropdashboost; // Boost you get when holding A while respawning @@ -757,7 +768,7 @@ struct player_t UINT8 confirmVictim; // Player ID that you dealt damage to UINT8 confirmVictimDelay; // Delay before playing the sound - UINT8 trickpanel; // Trick panel state + UINT8 trickpanel; // Trick panel state - see trickstate_t UINT8 tricktime; // Increases while you're tricking. You can't input any trick until it's reached a certain threshold fixed_t trickboostpower; // Save the rough speed multiplier. Used for upwards tricks. UINT8 trickboostdecay; // used to know how long you've waited @@ -902,14 +913,19 @@ struct player_t UINT8 tripwireReboundDelay; // When failing Tripwire, brieftly lock out speed-based tripwire pass (anti-cheese) - UINT16 sliptideZip; // How long is our chained sliptide? Grant a proportional boost when it's over. - UINT8 sliptideZipDelay; // How long since the last sliptide? Only boost once you've been straightened out for a bit. - UINT16 sliptideZipBoost; // The actual boost granted from sliptideZip. + UINT16 wavedash; // How long is our chained sliptide? Grant a proportional boost when it's over. + UINT8 wavedashdelay; // How long since the last sliptide? Only boost once you've been straightened out for a bit. + UINT16 wavedashboost; // The actual boost granted from wavedash. + + UINT16 trickcharge; // Landed normally from a trick panel? Get the benefits package! + + UINT16 infinitether; // Generic infinitether time, used for infinitether leniency. UINT8 lastsafelap; mobj_t *stumbleIndicator; - mobj_t *sliptideZipIndicator; + mobj_t *wavedashIndicator; + mobj_t *trickIndicator; mobj_t *whip; mobj_t *hand; mobj_t *flickyAttacker; @@ -927,6 +943,7 @@ struct player_t INT16 incontrol; // -1 to -175 when spinning out or tumbling, 1 to 175 when not. Use to check for combo hits or emergency inputs. boolean markedfordeath; + boolean dotrickfx; UINT8 ringboxdelay; // Delay until Ring Box auto-activates UINT8 ringboxaward; // Where did we stop? diff --git a/src/deh_tables.c b/src/deh_tables.c index daaa3ec59..7175b7a35 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -3314,7 +3314,7 @@ const char *const STATE_LIST[] = { // array length left dynamic for sanity testi "S_MAGICIANBOXTOP", "S_MAGICIANBOXBOTTOM", - "S_SLIPTIDEZIP", + "S_WAVEDASH", "S_INSTAWHIP", "S_INSTAWHIP_RECHARGE1", @@ -3325,6 +3325,13 @@ const char *const STATE_LIST[] = { // array length left dynamic for sanity testi "S_BLOCKRING", "S_BLOCKBODY", + "S_CHARGEAURA", + "S_CHARGEFALL", + "S_CHARGEFLICKER", + "S_CHARGESPARK", + "S_CHARGERELEASE", + "S_CHARGEEXTRA", + "S_SERVANTHAND", "S_HORNCODE", @@ -3892,6 +3899,16 @@ const char *const STATE_LIST[] = { // array length left dynamic for sanity testi "S_SMOOTHLANDING", + "S_TRICKINDICATOR_OVERLAY", + "S_TRICKINDICATOR_UNDERLAY", + "S_TRICKINDICATOR_OVERLAY_ARROW", + "S_TRICKINDICATOR_UNDERLAY_ARROW", + "S_TRICKINDICATOR_UNDERLAY_ARROW2", + + "S_SIDETRICK", + "S_BACKTRICK", + "S_FORWARDTRICK", + // DEZ Ring Shooter "S_TIREGRABBER", "S_RINGSHOOTER_SIDE", @@ -5538,7 +5555,7 @@ const char *const MOBJTYPE_LIST[] = { // array length left dynamic for sanity t "MT_MONITOR_SHARD", "MT_MAGICIANBOX", - "MT_SLIPTIDEZIP", + "MT_WAVEDASH", "MT_INSTAWHIP", "MT_INSTAWHIP_RECHARGE", @@ -5546,6 +5563,13 @@ const char *const MOBJTYPE_LIST[] = { // array length left dynamic for sanity t "MT_BLOCKRING", "MT_BLOCKBODY", + "MT_CHARGEAURA", + "MT_CHARGEFALL", + "MT_CHARGEFLICKER", + "MT_CHARGESPARK", + "MT_CHARGERELEASE", + "MT_CHARGEEXTRA", + "MT_SERVANTHAND", "MT_HORNCODE", @@ -5649,6 +5673,9 @@ const char *const MOBJTYPE_LIST[] = { // array length left dynamic for sanity t "MT_TRIPWIREBOOST", "MT_SMOOTHLANDING", + "MT_TRICKINDICATOR", + "MT_SIDETRICK", + "MT_FORWARDTRICK", "MT_TIREGRABBER", "MT_RINGSHOOTER", diff --git a/src/g_game.c b/src/g_game.c index fe2c2762a..c66923d2a 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -2234,7 +2234,7 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps) K_RemoveFollower(&players[player]); #define PlayerPointerRemove(field) \ - if (field) \ + if (P_MobjWasRemoved(field) == false) \ { \ P_RemoveMobj(field); \ P_SetTarget(&field, NULL); \ @@ -2243,7 +2243,8 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps) // These are mostly subservient to the player, and may not clean themselves up. PlayerPointerRemove(players[player].followmobj); PlayerPointerRemove(players[player].stumbleIndicator); - PlayerPointerRemove(players[player].sliptideZipIndicator); + PlayerPointerRemove(players[player].wavedashIndicator); + PlayerPointerRemove(players[player].trickIndicator); #undef PlayerPointerRemove diff --git a/src/info.c b/src/info.c index f82551b92..546cd2b68 100644 --- a/src/info.c +++ b/src/info.c @@ -558,7 +558,8 @@ char sprnames[NUMSPRITES + 1][5] = "IMDB", // Item Monitor Small Shard (Debris) "MTWK", // Item Monitor Glass Twinkle - "SLPT", // Sliptide zip indicator + "SLPT", // Wavedash indicator + "TRBS", // Trickdash indicator "IWHP", // Instawhip "WPRE", // Instawhip Recharge @@ -566,6 +567,12 @@ char sprnames[NUMSPRITES + 1][5] = "GRNG", // Guard ring "GBDY", // Guard body + "TRC1", // Charge aura + "TRC2", // Charge fall + "TRC3", // Charge flicker/sparks + "TRC4", // Charge release + "TRC5", // Charge extra + "DHND", // Servant Hand "HORN", // Horncode @@ -631,6 +638,15 @@ char sprnames[NUMSPRITES + 1][5] = "TWBT", // Tripwire BLASTER "SMLD", // Smooth landing + // Trick Effects + "TRK1", + "TRK2", + "TRK3", + "TRK4", + "TRK5", + "TRK6", + "TRK7", + "TIRG", // Tire grabbers "RSHT", // DEZ Ring Shooter @@ -4118,7 +4134,7 @@ state_t states[NUMSTATES] = {SPR_MGBT, FF_FLOORSPRITE|0, -1, {NULL}, 0, 0, S_NULL}, // S_MAGICIANBOX_TOP {SPR_MGBB, FF_FLOORSPRITE|0, -1, {NULL}, 0, 0, S_NULL}, // S_MAGICIANBOX_BOTTOM - {SPR_SLPT, FF_PAPERSPRITE|0, -1, {NULL}, 0, 0, S_NULL}, // S_SLIPTIDEZIP + {SPR_SLPT, FF_PAPERSPRITE|0, -1, {NULL}, 0, 0, S_NULL}, // S_WAVEDASH {SPR_IWHP, FF_FLOORSPRITE|FF_ANIMATE|0, -1, {NULL}, 6, 2, S_NULL}, // S_INSTAWHIP {SPR_NULL, 0, 1, {NULL}, 0, 0, S_INSTAWHIP_RECHARGE2}, // S_INSTAWHIP_RECHARGE1 @@ -4129,6 +4145,13 @@ state_t states[NUMSTATES] = {SPR_GRNG, FF_FULLBRIGHT|FF_PAPERSPRITE|0, -1, {NULL}, 0, 0, S_NULL}, // S_BLOCKRING {SPR_GBDY, FF_FULLBRIGHT|FF_ANIMATE|0, -1, {NULL}, 4, 2, S_NULL}, // S_BLOCKBODY + {SPR_TRC1, FF_FULLBRIGHT|FF_ANIMATE|0, -1, {NULL}, 4, 2, S_NULL}, // S_CHARGEAURA + {SPR_TRC2, FF_FULLBRIGHT|FF_ANIMATE|0, 20, {NULL}, 19, 1, S_NULL}, // S_CHARGEFALL + {SPR_TRC3, FF_FULLBRIGHT|FF_ADD|0, 2, {NULL}, 0, 0, S_NULL}, // S_CHARGEFLICKER + {SPR_TRC3, FF_FULLBRIGHT|FF_ADD|1, 2, {NULL}, 0, 0, S_NULL}, // S_CHARGESPARK + {SPR_TRC4, FF_FULLBRIGHT|FF_ADD|FF_ANIMATE|0, -1, {NULL}, 4, 1, S_NULL}, // S_CHARGERELEASE + {SPR_TRC5, FF_FULLBRIGHT|FF_ADD|FF_ANIMATE|0, -1, {NULL}, 4, 1, S_NULL}, // S_CHARGEEXTRA + {SPR_DHND, 0, -1, {NULL}, 0, 0, S_NULL}, // S_SERVANTHAND {SPR_HORN, 0, -1, {NULL}, 0, 0, S_NULL}, // S_HORNCODE @@ -4662,6 +4685,16 @@ state_t states[NUMSTATES] = {SPR_SMLD, FF_FULLBRIGHT|FF_ADD|FF_ANIMATE, -1, {NULL}, 7, 2, S_NULL}, // S_SMOOTHLANDING + {SPR_TRK1, FF_FULLBRIGHT|FF_ANIMATE|FF_PAPERSPRITE|FF_ADD, -1, {NULL}, 3, 3, S_NULL}, // S_TRICKINDICATOR_OVERLAY, + {SPR_TRK2, FF_FULLBRIGHT|FF_ANIMATE|FF_PAPERSPRITE, -1, {NULL}, 3, 3, S_NULL}, // S_TRICKINDICATOR_UNDERLAY, + {SPR_TRK3, FF_FULLBRIGHT|FF_ANIMATE|FF_PAPERSPRITE|FF_ADD, 13, {NULL}, 12, 1, S_INVISIBLE}, // S_TRICKINDICATOR_OVERLAY_ARROW, + {SPR_NULL, 0, 1, {NULL}, 12, 1, S_TRICKINDICATOR_UNDERLAY_ARROW2}, // S_TRICKINDICATOR_UNDERLAY_ARROW, + {SPR_TRK4, FF_FULLBRIGHT|FF_ANIMATE|FF_PAPERSPRITE, 13, {NULL}, 12, 1, S_INVISIBLE}, // S_TRICKINDICATOR_UNDERLAY_ARROW2, + + {SPR_TRK5, FF_FULLBRIGHT|FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL}, // S_SIDETRICK, + {SPR_TRK6, FF_FULLBRIGHT|FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL}, // S_BACKTRICK, + {SPR_TRK7, FF_FULLBRIGHT|FF_PAPERSPRITE|FF_ANIMATE, -1, {NULL}, 6, 1, S_NULL}, // S_FORWARDTRICK, + {SPR_TIRG, FF_ANIMATE, -1, {NULL}, 1, 1, S_NULL}, // S_TIREGRABBER {SPR_RSHT, FF_PAPERSPRITE|0, -1, {NULL}, 0, 0, S_NULL}, // S_RINGSHOOTER_SIDE {SPR_RSHT, FF_SEMIBRIGHT|FF_PAPERSPRITE|2, -1, {NULL}, 0, 0, S_NULL}, // S_RINGSHOOTER_NIPPLES @@ -23061,9 +23094,9 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL // raisestate }, - { // MT_SLIPTIDEZIP + { // MT_WAVEDASH -1, // doomednum - S_SLIPTIDEZIP, // spawnstate + S_WAVEDASH, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound @@ -23223,6 +23256,168 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL // raisestate }, + { // MT_CHARGEAURA + -1, // doomednum + S_CHARGEAURA, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 0, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 67*FRACUNIT, // radius + 67*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOGRAVITY|MF_NOCLIPHEIGHT, // flags + S_NULL // raisestate + }, + + { // MT_CHARGEFALL + -1, // doomednum + S_CHARGEFALL, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 0, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 67*FRACUNIT, // radius + 67*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOGRAVITY|MF_NOCLIPHEIGHT, // flags + S_NULL // raisestate + }, + + { // MT_CHARGEFLICKER + -1, // doomednum + S_CHARGEFLICKER, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 0, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 67*FRACUNIT, // radius + 67*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_SCENERY, // flags + S_NULL // raisestate + }, + + { // MT_CHARGESPARK + -1, // doomednum + S_CHARGESPARK, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 0, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 67*FRACUNIT, // radius + 67*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_SCENERY, // flags + S_NULL // raisestate + }, + + { // MT_CHARGERELEASE + -1, // doomednum + S_CHARGERELEASE, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 0, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 67*FRACUNIT, // radius + 67*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOGRAVITY|MF_NOCLIPHEIGHT, // flags + S_NULL // raisestate + }, + + { // MT_CHARGEEXTRA + -1, // doomednum + S_CHARGEEXTRA, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 0, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 67*FRACUNIT, // radius + 67*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOGRAVITY|MF_NOCLIPHEIGHT, // flags + S_NULL // raisestate + }, + { // MT_SERVANTHAND -1, // doomednum S_SERVANTHAND, // spawnstate @@ -25329,6 +25524,87 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL // raisestate }, + { // MT_TRICKINDICATOR + -1, // doomednum + S_INVISIBLE, // spawnstate + 1000, // 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 + 128*FRACUNIT, // radius + 128*FRACUNIT, // height + -1, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_NOCLIPTHING|MF_DONTENCOREMAP, // flags + S_NULL // raisestate + }, + + { // MT_SIDETRICK + -1, // doomednum + S_SIDETRICK, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 0, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 36*FRACUNIT, // radius + 40*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOGRAVITY|MF_NOCLIP|MF_NOCLIPTHING|MF_NOCLIPHEIGHT|MF_DONTENCOREMAP, // flags + S_NULL // raisestate + }, + + { // MT_FORWARDTRICK + -1, // doomednum + S_FORWARDTRICK, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 0, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 60*FRACUNIT, // radius + 86*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOGRAVITY|MF_NOCLIP|MF_NOCLIPTHING|MF_NOCLIPHEIGHT|MF_DONTENCOREMAP, // flags + S_NULL // raisestate + }, + { // MT_TIREGRABBER -1, // doomednum S_TIREGRABBER, // spawnstate diff --git a/src/info.h b/src/info.h index b57082a5f..3d83aebed 100644 --- a/src/info.h +++ b/src/info.h @@ -1115,7 +1115,8 @@ typedef enum sprite SPR_IMDB, // Item Monitor Small Shard (Debris) SPR_MTWK, // Item Monitor Glass Twinkle - SPR_SLPT, // Sliptide zip indicator + SPR_SLPT, // Wavedash indicator + SPR_TRBS, // Trickdash indicator SPR_IWHP, // Instawhip SPR_WPRE, // Instawhip Recharge @@ -1123,6 +1124,12 @@ typedef enum sprite SPR_GRNG, // Guard ring SPR_GBDY, // Guard body + SPR_TRC1, // Charge aura + SPR_TRC2, // Charge fall + SPR_TRC3, // Charge flicker/sparks + SPR_TRC4, // Charge release + SPR_TRC5, // Charge extra + SPR_DHND, // Servant Hand SPR_HORN, // Horncode @@ -1188,6 +1195,15 @@ typedef enum sprite SPR_TWBT, // Tripwire BLASTER SPR_SMLD, // Smooth landing + // Trick Effects + SPR_TRK1, + SPR_TRK2, + SPR_TRK3, + SPR_TRK4, + SPR_TRK5, + SPR_TRK6, + SPR_TRK7, + SPR_TIRG, // Tire grabbers SPR_RSHT, // DEZ Ring Shooter @@ -4529,7 +4545,7 @@ typedef enum state S_MAGICIANBOX_TOP, S_MAGICIANBOX_BOTTOM, - S_SLIPTIDEZIP, + S_WAVEDASH, S_INSTAWHIP, S_INSTAWHIP_RECHARGE1, @@ -4540,6 +4556,13 @@ typedef enum state S_BLOCKRING, S_BLOCKBODY, + S_CHARGEAURA, + S_CHARGEFALL, + S_CHARGEFLICKER, + S_CHARGESPARK, + S_CHARGERELEASE, + S_CHARGEEXTRA, + S_SERVANTHAND, S_HORNCODE, @@ -5106,6 +5129,16 @@ typedef enum state S_SMOOTHLANDING, + S_TRICKINDICATOR_OVERLAY, + S_TRICKINDICATOR_UNDERLAY, + S_TRICKINDICATOR_OVERLAY_ARROW, + S_TRICKINDICATOR_UNDERLAY_ARROW, + S_TRICKINDICATOR_UNDERLAY_ARROW2, + + S_SIDETRICK, + S_BACKTRICK, + S_FORWARDTRICK, + // DEZ Ring Shooter S_TIREGRABBER, S_RINGSHOOTER_SIDE, @@ -6791,7 +6824,7 @@ typedef enum mobj_type MT_MONITOR_PART, MT_MONITOR_SHARD, MT_MAGICIANBOX, - MT_SLIPTIDEZIP, + MT_WAVEDASH, MT_INSTAWHIP, MT_INSTAWHIP_RECHARGE, @@ -6799,6 +6832,13 @@ typedef enum mobj_type MT_BLOCKRING, MT_BLOCKBODY, + MT_CHARGEAURA, + MT_CHARGEFALL, + MT_CHARGEFLICKER, + MT_CHARGESPARK, + MT_CHARGERELEASE, + MT_CHARGEEXTRA, + MT_SERVANTHAND, MT_HORNCODE, @@ -6902,6 +6942,9 @@ typedef enum mobj_type MT_TRIPWIREBOOST, MT_SMOOTHLANDING, + MT_TRICKINDICATOR, + MT_SIDETRICK, + MT_FORWARDTRICK, MT_TIREGRABBER, MT_RINGSHOOTER, diff --git a/src/k_bot.cpp b/src/k_bot.cpp index 2d796758e..8c1894fba 100644 --- a/src/k_bot.cpp +++ b/src/k_bot.cpp @@ -1109,7 +1109,7 @@ static void K_BotTrick(player_t *player, ticcmd_t *cmd, const botcontroller_t *b return; } - if (player->trickpanel == 1) + if (player->trickpanel == TRICKSTATE_READY) { switch (botController->trick) { @@ -1521,7 +1521,7 @@ static void K_BuildBotTiccmdNormal(player_t *player, ticcmd_t *cmd) // Actual gameplay behaviors below this block! const botcontroller_t *botController = K_GetBotController(player->mo); - if (player->trickpanel != 0) + if (player->trickpanel != TRICKSTATE_NONE) { K_BotTrick(player, cmd, botController); diff --git a/src/k_director.cpp b/src/k_director.cpp index f04d2dfca..118786d63 100644 --- a/src/k_director.cpp +++ b/src/k_director.cpp @@ -221,7 +221,7 @@ private: bool can_change() const { - if (viewplayer()->trickpanel > 0) + if (viewplayer()->trickpanel != TRICKSTATE_NONE) { return false; } diff --git a/src/k_kart.c b/src/k_kart.c index cc6137a2b..021e71158 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -1263,6 +1263,12 @@ static boolean K_HasInfiniteTether(player_t *player) if (player->eggmanexplode > 0) return true; + if (player->trickcharge) + return true; + + if (player->infinitether) + return true; + return false; } @@ -1881,7 +1887,7 @@ static void K_SpawnGenericSpeedLines(player_t *player, boolean top) fast->colorized = true; fast->renderflags |= RF_ADD; } - else if (player->sliptideZipBoost) + else if (player->wavedashboost) { fast->color = SKINCOLOR_WHITE; fast->colorized = true; @@ -3231,9 +3237,9 @@ static void K_GetKartBoostPower(player_t *player) ); } - if (player->sliptideZipBoost) + if (player->wavedashboost) { - // NB: This is intentionally under the 25% threshold required to initiate a sliptide + // NB: This is intentionally under the 25% handleboost threshold required to initiate a sliptide ADDBOOST(8*FRACUNIT/10, 4*FRACUNIT, 2*SLIPTIDEHANDLING/5); // + 80% top speed, + 400% acceleration, +20% handling } @@ -3302,6 +3308,13 @@ static void K_GetKartBoostPower(player_t *player) ADDBOOST(6*FRACUNIT/20, FRACUNIT, 0); // + 30% top speed, + 100% acceleration, +0% handling } + if (player->trickcharge) + { + // NB: This is an acceleration-only boost. + // If this is applied earlier in the chain, it will diminish real speed boosts. + ADDBOOST(0, FRACUNIT, 2*SLIPTIDEHANDLING/10); // 0% speed 100% accel 20% handle + } + if (player->draftpower > 0) // Drafting { // 30% - 44%, each point of speed adds 1.75% @@ -4063,7 +4076,7 @@ void K_InitStumbleIndicator(player_t *player) return; } - if (player->stumbleIndicator != NULL && P_MobjWasRemoved(player->stumbleIndicator) == false) + if (P_MobjWasRemoved(player->stumbleIndicator) == false) { P_RemoveMobj(player->stumbleIndicator); } @@ -4074,7 +4087,7 @@ void K_InitStumbleIndicator(player_t *player) P_SetTarget(&new->target, player->mo); } -void K_InitSliptideZipIndicator(player_t *player) +void K_InitWavedashIndicator(player_t *player) { mobj_t *new = NULL; @@ -4088,17 +4101,61 @@ void K_InitSliptideZipIndicator(player_t *player) return; } - if (player->stumbleIndicator != NULL && P_MobjWasRemoved(player->sliptideZipIndicator) == false) + if (P_MobjWasRemoved(player->wavedashIndicator) == false) { - P_RemoveMobj(player->sliptideZipIndicator); + P_RemoveMobj(player->wavedashIndicator); } - new = P_SpawnMobjFromMobj(player->mo, 0, 0, 0, MT_SLIPTIDEZIP); + new = P_SpawnMobjFromMobj(player->mo, 0, 0, 0, MT_WAVEDASH); - P_SetTarget(&player->sliptideZipIndicator, new); + P_SetTarget(&player->wavedashIndicator, new); P_SetTarget(&new->target, player->mo); } +void K_InitTrickIndicator(player_t *player) +{ + mobj_t *new = NULL; + + if (player == NULL) + { + return; + } + + if (player->mo == NULL || P_MobjWasRemoved(player->mo) == true) + { + return; + } + + if (P_MobjWasRemoved(player->trickIndicator) == false) + { + if (P_MobjWasRemoved(player->trickIndicator->tracer) == false) + { + P_RemoveMobj(player->trickIndicator->tracer); + } + + P_RemoveMobj(player->trickIndicator); + } + + UINT32 invis = (RF_DONTDRAW & ~K_GetPlayerDontDrawFlag(player)); + + new = P_SpawnMobjFromMobj(player->mo, 0, 0, 0, MT_TRICKINDICATOR); + + P_SetMobjState(new, S_INVISIBLE); + P_SetTarget(&player->trickIndicator, new); + P_SetTarget(&new->target, player->mo); + new->renderflags |= invis; + + mobj_t *secondlayer = P_SpawnMobjFromMobj(new, 0, 0, 0, MT_OVERLAY); + + P_SetMobjState(secondlayer, S_INVISIBLE); + P_SetTarget(&new->tracer, secondlayer); + P_SetTarget(&secondlayer->target, new); + secondlayer->renderflags |= invis; + + secondlayer->dispoffset = 1; + secondlayer->flags |= MF_DONTENCOREMAP; +} + void K_UpdateStumbleIndicator(player_t *player) { const angle_t fudge = ANG15; @@ -4206,11 +4263,11 @@ void K_UpdateStumbleIndicator(player_t *player) #define MIN_WAVEDASH_CHARGE ((7*TICRATE/16)*9) -static boolean K_IsLosingSliptideZip(player_t *player) +static boolean K_IsLosingWavedash(player_t *player) { if (player->mo == NULL || P_MobjWasRemoved(player->mo) == true) return true; - if (!K_Sliptiding(player) && player->sliptideZip < MIN_WAVEDASH_CHARGE) + if (!K_Sliptiding(player) && player->wavedash < MIN_WAVEDASH_CHARGE) return true; if (!K_Sliptiding(player) && player->drift == 0 && P_IsObjectOnGround(player->mo) && player->sneakertimer == 0 @@ -4219,7 +4276,7 @@ static boolean K_IsLosingSliptideZip(player_t *player) return false; } -void K_UpdateSliptideZipIndicator(player_t *player) +void K_UpdateWavedashIndicator(player_t *player) { mobj_t *mobj = NULL; @@ -4233,13 +4290,13 @@ void K_UpdateSliptideZipIndicator(player_t *player) return; } - if (player->sliptideZipIndicator == NULL || P_MobjWasRemoved(player->sliptideZipIndicator) == true) + if (player->wavedashIndicator == NULL || P_MobjWasRemoved(player->wavedashIndicator) == true) { - K_InitSliptideZipIndicator(player); + K_InitWavedashIndicator(player); return; } - mobj = player->sliptideZipIndicator; + mobj = player->wavedashIndicator; angle_t momentumAngle = K_MomentumAngle(player->mo); P_MoveOrigin(mobj, player->mo->x - FixedMul(40*mapobjectscale, FINECOSINE(momentumAngle >> ANGLETOFINESHIFT)), @@ -4249,7 +4306,7 @@ void K_UpdateSliptideZipIndicator(player_t *player) P_SetScale(mobj, 3 * player->mo->scale / 2); // No stored boost (or negligible enough that it might be a mistake) - if (player->sliptideZip <= HIDEWAVEDASHCHARGE) + if (player->wavedash <= HIDEWAVEDASHCHARGE) { mobj->renderflags |= RF_DONTDRAW; mobj->frame = 7; @@ -4258,8 +4315,8 @@ void K_UpdateSliptideZipIndicator(player_t *player) mobj->renderflags &= ~RF_DONTDRAW; - UINT32 chargeFrame = 7 - min(7, player->sliptideZip / 100); - UINT32 decayFrame = min(7, player->sliptideZipDelay / 2); + UINT32 chargeFrame = 7 - min(7, player->wavedash / 100); + UINT32 decayFrame = min(7, player->wavedashdelay / 2); if (max(chargeFrame, decayFrame) > mobj->frame) mobj->frame++; else if (max(chargeFrame, decayFrame) < mobj->frame) @@ -4268,7 +4325,7 @@ void K_UpdateSliptideZipIndicator(player_t *player) mobj->renderflags &= ~RF_TRANSMASK; mobj->renderflags |= RF_PAPERSPRITE; - if (K_IsLosingSliptideZip(player)) + if (K_IsLosingWavedash(player)) { // Decay timer's ticking mobj->rollangle += 3*ANG30/4; @@ -4282,6 +4339,69 @@ void K_UpdateSliptideZipIndicator(player_t *player) } } +static mobj_t *K_TrickCatholocismBlast(mobj_t *trickIndicator, fixed_t destscale, angle_t rollangle) +{ + // It's my last minute visual effect and I get to choose the ridiculous function name - toast 061123 + + mobj_t *catholocismBlast = P_SpawnGhostMobj(trickIndicator); // HOLY? + catholocismBlast->height = 1; + catholocismBlast->destscale = destscale; + catholocismBlast->fuse = 12; + catholocismBlast->rollangle = rollangle; + catholocismBlast->dispoffset = -1; + + return catholocismBlast; +} + +void K_UpdateTrickIndicator(player_t *player) +{ + mobj_t *mobj = NULL; + + if (player == NULL) + { + return; + } + + if (player->mo == NULL || P_MobjWasRemoved(player->mo) == true) + { + return; + } + + if (player->trickIndicator == NULL + || P_MobjWasRemoved(player->trickIndicator) == true + || player->trickIndicator->tracer == NULL + || P_MobjWasRemoved(player->trickIndicator->tracer) == true) + { + K_InitTrickIndicator(player); + return; + } + + mobj = player->trickIndicator; + + statenum_t test = (mobj->state-states); + + if (test >= S_TRICKINDICATOR_UNDERLAY_ARROW) + return; + + const fixed_t onidistance = 150*mapobjectscale; + + P_MoveOrigin( + mobj, + player->mo->x + P_ReturnThrustX(player->mo, player->mo->angle, onidistance), + player->mo->y + P_ReturnThrustY(player->mo, player->mo->angle, onidistance), + player->mo->z + (player->mo->height / 2)); + mobj->angle = player->mo->angle + ANGLE_90; + + if (player->trickpanel == TRICKSTATE_NONE + && test != S_INVISIBLE) + { + K_TrickCatholocismBlast(mobj, 1, ANGLE_22h); + + P_SetMobjState(mobj, S_INVISIBLE); + P_SetMobjState(mobj->tracer, S_INVISIBLE); + } +} + static boolean K_LastTumbleBounceCondition(player_t *player) { return (player->tumbleBounces > TUMBLEBOUNCES && player->tumbleHeight < 60); @@ -5100,6 +5220,16 @@ void K_SpawnDriftElectricSparks(player_t *player, int color, boolean shockwave) fixed_t sparkspeed = mobjinfo[MT_DRIFTELECTRICSPARK].speed; fixed_t sparkradius = 2 * shockscale * mobjinfo[MT_DRIFTELECTRICSPARK].radius; + if (player->trickcharge && !shockwave) + { + mobj_t *release = P_SpawnMobjFromMobj(mo, 0, 0, 0, MT_CHARGERELEASE); + P_SetTarget(&release->target, mo); + release->tics = 40; + release->scale /= 5; + release->destscale *= 2; + release->scalespeed = release->scale/2; + } + for (hdir = -1; hdir <= 1; hdir += 2) { for (vdir = -1; vdir <= 1; vdir += 2) @@ -5107,12 +5237,16 @@ void K_SpawnDriftElectricSparks(player_t *player, int color, boolean shockwave) fixed_t hspeed = FixedMul(hdir * sparkspeed, mo->scale); // P_InstaThrust treats speed as absolute fixed_t vspeed = vdir * sparkspeed; // P_SetObjectMomZ scales speed with object scale angle_t sparkangle = mo->angle + ANGLE_45; + mobj_t *spark; for (i = 0; i < 4; i++) { fixed_t xoff = P_ReturnThrustX(mo, sparkangle, sparkradius); fixed_t yoff = P_ReturnThrustY(mo, sparkangle, sparkradius); - mobj_t *spark = P_SpawnMobjFromMobj(mo, x + xoff, y + yoff, z, MT_DRIFTELECTRICSPARK); + if (player->trickcharge && !shockwave) + spark = P_SpawnMobjFromMobj(mo, x + xoff, y + yoff, z, MT_CHARGEEXTRA); + else + spark = P_SpawnMobjFromMobj(mo, x + xoff, y + yoff, z, MT_DRIFTELECTRICSPARK); spark->angle = sparkangle; spark->color = color; @@ -5125,7 +5259,14 @@ void K_SpawnDriftElectricSparks(player_t *player, int color, boolean shockwave) P_SetScale(spark, shockscale * spark->scale); if (shockwave) + { spark->frame |= FF_ADD; + } + else if (player->trickcharge) + { + spark->tics = 20; + } + sparkangle += ANGLE_90; K_ReduceVFX(spark, player); @@ -6229,6 +6370,7 @@ static void K_DoShrink(player_t *user) void K_DoPogoSpring(mobj_t *mo, fixed_t vertispeed, UINT8 sound) { fixed_t thrust = 0; + boolean dontapplymomz = false; if (mo->player && mo->player->spectator) return; @@ -6243,23 +6385,73 @@ void K_DoPogoSpring(mobj_t *mo, fixed_t vertispeed, UINT8 sound) if (vertispeed == 0) { - thrust = P_AproxDistance(mo->momx, mo->momy) * P_MobjFlip(mo); - thrust = FixedMul(thrust, FINESINE(ANGLE_22h >> ANGLETOFINESHIFT)); + vertispeed = P_AproxDistance(mo->momx, mo->momy); + vertispeed = FixedMul(vertispeed, FINESINE(ANGLE_22h >> ANGLETOFINESHIFT)); } - else + else if (vertispeed < 0) { - thrust = vertispeed * P_MobjFlip(mo); + dontapplymomz = 0; + vertispeed = -vertispeed; } + thrust = vertispeed * P_MobjFlip(mo); + if (mo->player) { - if (mo->player->sneakertimer) + if (!P_PlayerInPain(mo->player)) { - thrust = FixedMul(thrust, 5*FRACUNIT/4); + mo->player->trickpanel = TRICKSTATE_READY; + mo->player->pflags |= PF_TRICKDELAY; + + if (P_MobjWasRemoved(mo->player->trickIndicator) == false) + { + mobj_t *trickIndicator = mo->player->trickIndicator; + + P_SetScale(trickIndicator, + trickIndicator->destscale + = trickIndicator->old_scale + = trickIndicator->old_scale2 + = mo->scale/4); + trickIndicator->rollangle = 0; + + static const skincolornum_t trick_colors[] = { + SKINCOLOR_WHITE, // trickPanel == 1 -- was SKINCOLOR_GREY + SKINCOLOR_TAN, + SKINCOLOR_YELLOW, // trickPanel == 2 + SKINCOLOR_TANGERINE, + SKINCOLOR_KETCHUP, // trickPanel == 3 + SKINCOLOR_MOONSET, + SKINCOLOR_ULTRAMARINE, // trickPanel == 4 + }; + static const UINT8 numColors = sizeof(trick_colors) / sizeof(skincolornum_t); + + const fixed_t step = 8*FRACUNIT; + fixed_t trickcol = ((vertispeed - (step/2)) / step) - 1; + if (trickcol < 0) + trickcol = 0; + trickIndicator->color = trick_colors[min(trickcol, numColors - 1)]; + + P_SetMobjState(trickIndicator, S_TRICKINDICATOR_UNDERLAY); + + if (P_MobjWasRemoved(trickIndicator->tracer) == false) + { + P_SetScale(trickIndicator->tracer, + trickIndicator->tracer->destscale + = trickIndicator->tracer->old_scale + = trickIndicator->tracer->old_scale2 + = trickIndicator->destscale); + trickIndicator->tracer->rollangle = 0; + + trickIndicator->tracer->color = mo->player->trickIndicator->color; + + P_SetMobjState(trickIndicator->tracer, S_TRICKINDICATOR_OVERLAY); + } + } } - else if (mo->player->invincibilitytimer) + + if (mo->player->sneakertimer || mo->player->invincibilitytimer) { - thrust = FixedMul(thrust, 9*FRACUNIT/8); + thrust = FixedMul(thrust, (3*FRACUNIT)/2); } mo->player->tricktime = 0; // Reset post-hitlag timer @@ -6270,11 +6462,14 @@ void K_DoPogoSpring(mobj_t *mo, fixed_t vertispeed, UINT8 sound) mo->player->fastfall = 0; } - mo->momz = FixedMul(thrust, mapobjectscale); - - if (mo->eflags & MFE_UNDERWATER) + if (dontapplymomz == false) { - mo->momz = FixedDiv(mo->momz, FixedSqrt(3*FRACUNIT)); + mo->momz = FixedMul(thrust, mapobjectscale); + + if (mo->eflags & MFE_UNDERWATER) + { + mo->momz = FixedDiv(mo->momz, FixedSqrt(3*FRACUNIT)); + } } P_ResetPitchRoll(mo); @@ -7946,7 +8141,7 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) if (player->sneakertimer || player->ringboost || player->driftboost || player->startboost || player->eggmanexplode || player->trickboost - || player->gateBoost || player->sliptideZipBoost) + || player->gateBoost || player->wavedashboost) { #if 0 if (player->invincibilitytimer) @@ -8232,9 +8427,21 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) if (player->dropdashboost) player->dropdashboost--; - if (player->sliptideZipBoost > 0 && onground == true) + if (player->wavedashboost > 0 && onground == true) { - player->sliptideZipBoost--; + player->wavedashboost--; + } + + if (player->trickcharge > 0 && onground == true) + { + player->trickcharge--; + if (player->drift) + player->trickcharge = max(player->trickcharge, 1); + } + + if (player->infinitether > 0) + { + player->infinitether--; } if (player->spindashboost) @@ -8349,6 +8556,31 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) player->instaWhipCooldown--; } + if (player->dotrickfx && !player->mo->hitlag) + { + int i; + S_StartSoundAtVolume(player->mo, sfx_trick1, 255/2); + + if (!player->trickcharge) + { + for(i = 0;i < 5;i++) + { + mobj_t *aura = P_SpawnMobjFromMobj(player->mo, 0, 0, player->mo->height/2, MT_CHARGEAURA); + aura->angle = player->mo->angle + i*ANG15; + P_SetTarget(&aura->target, player->mo); + if (i == 0) + aura->extravalue2 = 1; + else + aura->renderflags |= RF_TRANS50; + aura->cvmem = leveltime; + } + } + + player->trickcharge = 8*TICRATE; + + player->dotrickfx = false; + } + // Don't screw up chain ring pickup/usage with instawhip charge. // If the button stays held, delay charge a bit. if (player->instaWhipChargeLockout) @@ -8510,11 +8742,11 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) K_FlameDashLeftoverSmoke(player->mo); } - if (P_IsObjectOnGround(player->mo) && player->trickpanel != 0) + if (P_IsObjectOnGround(player->mo) && player->trickpanel != TRICKSTATE_NONE) { if (P_MobjFlip(player->mo) * player->mo->momz <= 0) { - player->trickpanel = 0; + player->trickpanel = TRICKSTATE_NONE; } } @@ -8700,8 +8932,8 @@ void K_KartPlayerAfterThink(player_t *player) K_KartResetPlayerColor(player); K_UpdateStumbleIndicator(player); - - K_UpdateSliptideZipIndicator(player); + K_UpdateWavedashIndicator(player); + K_UpdateTrickIndicator(player); // Move held objects (Bananas, Orbinaut, etc) K_MoveHeldObjects(player); @@ -9425,9 +9657,9 @@ INT16 K_GetKartTurnValue(player_t *player, INT16 turnvalue) return 0; } - if (player->trickpanel != 0 && player->trickpanel < 4) + if (player->trickpanel == TRICKSTATE_READY || player->trickpanel == TRICKSTATE_FORWARD) { - // No turning during trick panel unless you did the upwards trick (4) + // Forward trick or rising from trickpanel return 0; } @@ -9523,6 +9755,12 @@ INT16 K_GetKartTurnValue(player_t *player, INT16 turnvalue) // Weight has a small effect on turning turnfixed = FixedMul(turnfixed, weightadjust); + // Side trick + if (player->trickpanel == TRICKSTATE_LEFT || player->trickpanel == TRICKSTATE_RIGHT) + { + turnfixed /= 2; + } + return (turnfixed / FRACUNIT); } @@ -9628,6 +9866,8 @@ static void K_KartDrift(player_t *player, boolean onground) const UINT16 buttons = K_GetKartButtons(player); + boolean dokicker = false; + // Drifting is actually straffing + automatic turning. // Holding the Jump button will enable drifting. // (This comment is extremely funny) @@ -9690,6 +9930,7 @@ static void K_KartDrift(player_t *player, boolean onground) K_SpawnDriftBoostExplosion(player, 3); K_SpawnDriftElectricSparks(player, K_DriftSparkColor(player, player->driftcharge), false); + dokicker = true; } else if (player->driftcharge >= dsfour) { @@ -9704,6 +9945,17 @@ static void K_KartDrift(player_t *player, boolean onground) K_SpawnDriftBoostExplosion(player, 4); K_SpawnDriftElectricSparks(player, K_DriftSparkColor(player, player->driftcharge), false); + dokicker = true; + } + + if (player->trickcharge && dokicker) + { + player->driftboost += 20; + player->wavedashboost += 10; + P_Thrust(player->mo, pushdir, player->speed / 2); + S_StartSound(player->mo, sfx_gshba); + player->trickcharge = 0; + player->infinitether = TICRATE*2; } } @@ -9755,8 +10007,9 @@ static void K_KartDrift(player_t *player, boolean onground) player->drift = player->driftcharge = player->aizdriftstrat = 0; player->pflags &= ~(PF_BRAKEDRIFT|PF_GETSPARKS); // And take away wavedash properties: advanced cornering demands advanced finesse - player->sliptideZip = 0; - player->sliptideZipBoost = 0; + player->wavedash = 0; + player->wavedashboost = 0; + player->trickcharge = 0; } else if ((player->pflags & PF_DRIFTINPUT) && player->drift != 0) { @@ -9822,6 +10075,9 @@ static void K_KartDrift(player_t *player, boolean onground) driftadditive = 0; } + if (player->trickcharge && driftadditive) + driftadditive += 16; + // This spawns the drift sparks if ((player->driftcharge + driftadditive >= dsone) || (player->driftcharge < 0)) @@ -9858,11 +10114,11 @@ static void K_KartDrift(player_t *player, boolean onground) || (!player->aizdriftstrat) || (player->steering > 0) != (player->aizdriftstrat > 0)) { - if (!player->drift && player->steering && player->aizdriftstrat && player->sliptideZip // If we were sliptiding last tic, + if (!player->drift && player->steering && player->aizdriftstrat && player->wavedash // If we were sliptiding last tic, && (player->steering > 0) == (player->aizdriftstrat > 0) // we're steering in the right direction, && player->speed >= K_GetKartSpeed(player, false, true)) // and we're above the threshold to spawn dust... { - keepsliptide = true; // Then keep your current sliptide, but note the behavior change for sliptidezip handling. + keepsliptide = true; // Then keep your current sliptide, but note the behavior change for wavedash handling. } else { @@ -9890,9 +10146,9 @@ static void K_KartDrift(player_t *player, boolean onground) // This makes wavedash charge noticeably slower on even modest delay, despite the magnitude of the turn seeming the same. // So we only require 90% of a turn to get full charge strength. - player->sliptideZip += addCharge; + player->wavedash += addCharge; - if (player->sliptideZip >= MIN_WAVEDASH_CHARGE && (player->sliptideZip - addCharge) < MIN_WAVEDASH_CHARGE) + if (player->wavedash >= MIN_WAVEDASH_CHARGE && (player->wavedash - addCharge) < MIN_WAVEDASH_CHARGE) S_StartSound(player->mo, sfx_waved5); } @@ -9918,16 +10174,16 @@ static void K_KartDrift(player_t *player, boolean onground) if (!K_Sliptiding(player) || keepsliptide) { - if (!keepsliptide && K_IsLosingSliptideZip(player) && player->sliptideZip > 0) + if (!keepsliptide && K_IsLosingWavedash(player) && player->wavedash > 0) { - if (player->sliptideZip > HIDEWAVEDASHCHARGE && !S_SoundPlaying(player->mo, sfx_waved2)) + if (player->wavedash > HIDEWAVEDASHCHARGE && !S_SoundPlaying(player->mo, sfx_waved2)) S_StartSoundAtVolume(player->mo, sfx_waved2, 255); // Losing combo time, going to boost S_StopSoundByID(player->mo, sfx_waved1); S_StopSoundByID(player->mo, sfx_waved4); - player->sliptideZipDelay++; - if (player->sliptideZipDelay > TICRATE/2) + player->wavedashdelay++; + if (player->wavedashdelay > TICRATE/2) { - if (player->sliptideZip >= MIN_WAVEDASH_CHARGE) + if (player->wavedash >= MIN_WAVEDASH_CHARGE) { fixed_t maxZipPower = 2*FRACUNIT; fixed_t minZipPower = 1*FRACUNIT; @@ -9942,30 +10198,26 @@ static void K_KartDrift(player_t *player, boolean onground) fixed_t yourPowerReduction = FixedDiv(yourPenalty * FRACUNIT, penaltySpread * FRACUNIT); fixed_t yourPower = maxZipPower - FixedMul(yourPowerReduction, powerSpread); - int yourBoost = FixedInt(FixedMul(yourPower, player->sliptideZip/10 * FRACUNIT)); + int yourBoost = FixedInt(FixedMul(yourPower, player->wavedash/10 * FRACUNIT)); - /* - CONS_Printf("SZ %d MZ %d mZ %d pwS %d mP %d MP %d peS %d yPe %d yPR %d yPw %d yB %d\n", - player->sliptideZip, maxZipPower, minZipPower, powerSpread, minPenalty, maxPenalty, penaltySpread, yourPenalty, yourPowerReduction, yourPower, yourBoost); - */ + player->wavedashboost += yourBoost; - player->sliptideZipBoost += yourBoost; + S_StartSoundAtVolume(player->mo, sfx_waved3, 255); // Boost K_SpawnDriftBoostExplosion(player, 0); - S_StartSoundAtVolume(player->mo, sfx_waved3, 255); // Boost } S_StopSoundByID(player->mo, sfx_waved1); S_StopSoundByID(player->mo, sfx_waved2); S_StopSoundByID(player->mo, sfx_waved4); - player->sliptideZip = 0; - player->sliptideZipDelay = 0; + player->wavedash = 0; + player->wavedashdelay = 0; } } else { S_StopSoundByID(player->mo, sfx_waved1); S_StopSoundByID(player->mo, sfx_waved2); - if (player->sliptideZip > 0 && !S_SoundPlaying(player->mo, sfx_waved4)) + if (player->wavedash > 0 && !S_SoundPlaying(player->mo, sfx_waved4)) S_StartSoundAtVolume(player->mo, sfx_waved4, 255); // Passive woosh } @@ -9979,10 +10231,10 @@ static void K_KartDrift(player_t *player, boolean onground) } else { - player->sliptideZipDelay = 0; + player->wavedashdelay = 0; S_StopSoundByID(player->mo, sfx_waved2); S_StopSoundByID(player->mo, sfx_waved4); - if (player->sliptideZip > HIDEWAVEDASHCHARGE && !S_SoundPlaying(player->mo, sfx_waved1)) + if (player->wavedash > HIDEWAVEDASHCHARGE && !S_SoundPlaying(player->mo, sfx_waved1)) S_StartSoundAtVolume(player->mo, sfx_waved1, 255); // Charging } @@ -10541,7 +10793,7 @@ static void K_KartSpindashWind(mobj_t *parent) P_SetTarget(&wind->target, parent); - if (parent->player && parent->player->sliptideZipBoost) + if (parent->player && parent->player->wavedashboost) P_SetScale(wind, wind->scale * 2); if (parent->momx || parent->momy) @@ -10605,7 +10857,7 @@ static void K_KartSpindash(player_t *player) K_KartSpindashWind(player->mo); } - if ((player->sliptideZipBoost > 0) && (spawnWind == true)) + if ((player->wavedashboost > 0) && (spawnWind == true)) { K_KartSpindashWind(player->mo); } @@ -10771,9 +11023,10 @@ boolean K_FastFallBounce(player_t *player) player->pflags |= PF_UPDATEMYRESPAWN; + player->fastfall = 0; + player->mo->momz = bounce * P_MobjFlip(player->mo); - player->fastfall = 0; return true; } @@ -10973,7 +11226,7 @@ static void K_trickPanelTimingVisual(player_t *player, fixed_t momz) flame->sprite = SPR_TRCK; flame->frame = i|FF_FULLBRIGHT; - if (player->trickpanel <= 1 && !player->tumbleBounces) + if (player->trickpanel <= TRICKSTATE_READY && !player->tumbleBounces) { flame->tics = 2; flame->momx = player->mo->momx; @@ -10984,7 +11237,7 @@ static void K_trickPanelTimingVisual(player_t *player, fixed_t momz) { flame->tics = TICRATE; - if (player->trickpanel > 1) // we tricked + if (player->trickpanel > TRICKSTATE_READY) // we tricked { // Send the thing outwards via ghetto maths which involves redoing the whole 3d sphere again, witht the "vertical" angle shifted by 90 degrees. // There's probably a simplier way to do this the way I want to but this works. @@ -11729,7 +11982,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground) if (player->throwdir == -1) { P_InstaThrust(player->mo, player->mo->angle, player->speed + (80 * mapobjectscale)); - player->sliptideZipBoost += TICRATE; // Just for keeping speed briefly vs. tripwire etc. + player->wavedashboost += TICRATE; // Just for keeping speed briefly vs. tripwire etc. // If this doesn't turn out to be reliable, I'll change it to directly set leniency or something. } K_PlayAttackTaunt(player->mo); @@ -11859,7 +12112,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground) } break; case KITEM_POGOSPRING: - if (ATTACK_IS_DOWN && !HOLDING_ITEM && onground && NO_HYUDORO && player->trickpanel == 0) + if (ATTACK_IS_DOWN && !HOLDING_ITEM && onground && NO_HYUDORO && player->trickpanel == TRICKSTATE_NONE) { K_PlayBoostTaunt(player->mo); //K_DoPogoSpring(player->mo, 32<mo->renderflags &= ~RF_BLENDMASK; } - if (player->trickpanel == 1) + if (player->trickpanel == TRICKSTATE_READY) { const angle_t lr = ANGLE_45; fixed_t momz = FixedDiv(player->mo->momz, mapobjectscale); // bring momz back to scale... @@ -11979,7 +12232,21 @@ void K_MoveKartPlayer(player_t *player, boolean onground) fixed_t basespeed = FixedMul(invertscale, K_GetKartSpeed(player, false, false)); // at WORSE, keep your normal speed when tricking. fixed_t speed = FixedMul(invertscale, FixedMul(speedmult, P_AproxDistance(player->mo->momx, player->mo->momy))); - K_trickPanelTimingVisual(player, momz); + if (P_MobjWasRemoved(player->trickIndicator) == false) + { + const fixed_t indicatormult = 3*(mapobjectscale/5); + player->trickIndicator->destscale = FixedMul(speedmult + FRACUNIT, indicatormult); + + fixed_t trans = ((player->trickIndicator->scale * 9)/indicatormult) - 9; + if (trans < 10) // it's fine if it stays barely visible imo + { + UINT32 renderflags = player->trickIndicator->renderflags & ~RF_TRANSMASK; + if (trans > 0) + renderflags |= (trans << RF_TRANSSHIFT); + + player->trickIndicator->renderflags = renderflags; + } + } // streaks: if (momz*P_MobjFlip(player->mo) > 0) // only spawn those while you're going upwards relative to your current gravity @@ -12024,8 +12291,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground) player->tumbleBounces = 1; player->pflags &= ~PF_TUMBLESOUND; player->tumbleHeight = 30; // Base tumble bounce height - player->trickpanel = 0; - K_trickPanelTimingVisual(player, momz); // fail trick visual + player->trickpanel = TRICKSTATE_NONE; P_SetPlayerMobjState(player->mo, S_KART_SPINOUT); if (player->itemflags & (IF_ITEMOUT|IF_EGGMANOUT)) { @@ -12036,36 +12302,83 @@ void K_MoveKartPlayer(player_t *player, boolean onground) else if (!(player->pflags & PF_TRICKDELAY)) // don't allow tricking at the same frame you tumble obv { + // For tornado trick effects + angle_t tornadotrickspeed = ANG30; + const angle_t angledelta = FixedAngle(36*FRACUNIT); + angle_t baseangle = player->mo->angle + angledelta/2; + INT16 aimingcompare = abs(cmd->throwdir) - abs(cmd->turning); // Uses cmd->turning over steering intentionally. #define TRICKTHRESHOLD (KART_FULLTURN/4) if (aimingcompare < -TRICKTHRESHOLD) // side trick { + S_StartSoundAtVolume(player->mo, sfx_trick0, 255/2); + player->dotrickfx = true; + + // Calculate speed boost decay: + // Base speed boost duration is 35 tics. + // At most, lose 3/4th of your boost. + player->trickboostdecay = min(TICRATE*3/4, abs(momz/FRACUNIT)); + if (cmd->turning > 0) { P_InstaThrust(player->mo, player->mo->angle + lr, max(basespeed, speed*5/2)); - player->trickpanel = 2; + player->trickpanel = TRICKSTATE_RIGHT; + + if (P_MobjWasRemoved(player->trickIndicator) == false) + { + player->trickIndicator->rollangle = ANGLE_270; + } + + player->drawangle -= ANGLE_45; + P_SetPlayerMobjState(player->mo, S_KART_FAST_LOOK_L); } else { P_InstaThrust(player->mo, player->mo->angle - lr, max(basespeed, speed*5/2)); - player->trickpanel = 3; + player->trickpanel = TRICKSTATE_LEFT; + + if (P_MobjWasRemoved(player->trickIndicator) == false) + { + player->trickIndicator->rollangle = ANGLE_90; + } + + tornadotrickspeed = InvAngle(tornadotrickspeed); + + player->drawangle += ANGLE_45; + P_SetPlayerMobjState(player->mo, S_KART_FAST_LOOK_R); } } else if (aimingcompare > TRICKTHRESHOLD) // forward/back trick { - if (cmd->throwdir > 0) // back trick + S_StartSoundAtVolume(player->mo, sfx_trick0, 255/2); + player->dotrickfx = true; + + // Calculate speed boost decay: + // Base speed boost duration is 35 tics. + // At most, lose 3/4th of your boost. + player->trickboostdecay = min(TICRATE*3/4, abs(momz/FRACUNIT)); + + if (cmd->throwdir > 0) // forward trick { + if (player->mo->momz * P_MobjFlip(player->mo) > 0) { player->mo->momz = 0; } P_InstaThrust(player->mo, player->mo->angle, max(basespeed, speed*3)); - player->trickpanel = 2; + player->trickpanel = TRICKSTATE_FORWARD; + + if (P_MobjWasRemoved(player->trickIndicator) == false) + { + player->trickIndicator->rollangle = 0; + } + + P_SetPlayerMobjState(player->mo, S_KART_FAST); } - else if (cmd->throwdir < 0) + else if (cmd->throwdir < 0) // back trick { player->mo->momx /= 3; player->mo->momy /= 3; @@ -12075,41 +12388,154 @@ void K_MoveKartPlayer(player_t *player, boolean onground) player->mo->momz = 0; // relative = false; } - // Calculate speed boost decay: - // Base speed boost duration is 35 tics. - // At most, lose 3/4th of your boost. - player->trickboostdecay = min(TICRATE*3/4, abs(momz/FRACUNIT)); - //CONS_Printf("decay: %d\n", player->trickboostdecay); - player->mo->momz += P_MobjFlip(player->mo)*48*mapobjectscale; - player->trickpanel = 4; + player->trickpanel = TRICKSTATE_BACK; + + if (P_MobjWasRemoved(player->trickIndicator) == false) + { + player->trickIndicator->rollangle = ANGLE_180; + } + + //tornadotrickspeed = InvAngle(tornadotrickspeed); + + //player->drawangle += ANGLE_45; + P_SetPlayerMobjState(player->mo, S_KART_FAST); } } #undef TRICKTHRESHOLD // Finalise everything. - if (player->trickpanel != 1) // just changed from 1? + if (player->trickpanel != TRICKSTATE_READY) // just changed from 1? { player->mo->hitlag = TRICKLAG; player->mo->eflags &= ~MFE_DAMAGEHITLAG; - K_trickPanelTimingVisual(player, momz); - if (abs(momz) < FRACUNIT*99) // Let's use that as baseline for PERFECT trick. { player->karthud[khud_trickcool] = TICRATE; } + + INT32 j; + skincolornum_t trickcolor = SKINCOLOR_NONE; + + if (P_MobjWasRemoved(player->trickIndicator) == false) + trickcolor = player->trickIndicator->color; + + if (player->trickpanel == TRICKSTATE_FORWARD) + { + for (j = 0; j < 2; j++) + { + mobj_t *fwush = P_SpawnMobjFromMobj(player->mo, 0, 0, 0, MT_FORWARDTRICK); + + P_SetTarget(&fwush->target, player->mo); + fwush->hitlag = TRICKLAG; + fwush->color = trickcolor; + fwush->renderflags |= RF_DONTDRAW; + fwush->flags2 |= MF2_AMBUSH; // don't interp on first think + fwush->threshold = 0; + + fwush->movedir = player->mo->angle; + if (j == 0) + { + fwush->angle = fwush->old_angle = fwush->movedir + ANGLE_135; + fwush->movefactor = 1; + } + else + { + fwush->angle = fwush->old_angle = fwush->movedir - ANGLE_135; + fwush->movefactor = -1; + } + } + } + else for (j = 0; j < 8; j++, baseangle += angledelta) + { + mobj_t *swipe = P_SpawnMobjFromMobj(player->mo, 0, 0, 0, MT_SIDETRICK); + + if (player->trickpanel == TRICKSTATE_BACK) + P_SetMobjState(swipe, S_BACKTRICK); + + P_SetTarget(&swipe->target, player->mo); + swipe->hitlag = TRICKLAG; + swipe->color = trickcolor; + swipe->angle = baseangle + ANGLE_90; + swipe->renderflags |= RF_DONTDRAW; + swipe->flags2 |= MF2_AMBUSH; // don't interp on first think + swipe->movedir = tornadotrickspeed; + swipe->frame |= (j % 4); + swipe->threshold = 0; + + // This is so they make a 10-sided shape with one-sprite gap + if (j != 3) + continue; + + baseangle += angledelta; + } + + if (P_MobjWasRemoved(player->trickIndicator) == false) + { + K_TrickCatholocismBlast(player->trickIndicator, player->trickIndicator->scale*10, 0); + + player->trickIndicator->renderflags &= ~RF_TRANSMASK; + + P_InstaScale(player->trickIndicator, 3*mapobjectscale/2); + player->trickIndicator->old_scale = player->trickIndicator->scale; + + P_SetMobjState(player->trickIndicator, S_TRICKINDICATOR_UNDERLAY_ARROW); + if (P_MobjWasRemoved(player->trickIndicator->tracer) == false) + { + P_InstaScale(player->trickIndicator->tracer, player->trickIndicator->scale); + player->trickIndicator->tracer->old_scale = player->trickIndicator->tracer->scale; + + P_SetMobjState(player->trickIndicator->tracer, S_TRICKINDICATOR_OVERLAY_ARROW); + } + } } } - } - else if (player->trickpanel == 4 && P_IsObjectOnGround(player->mo)) // Upwards trick landed! - { - //CONS_Printf("apply boost\n"); - S_StartSound(player->mo, sfx_s23c); - K_SpawnDashDustRelease(player); - player->trickboost = TICRATE - player->trickboostdecay; - player->trickpanel = player->trickboostdecay = 0; + K_trickPanelTimingVisual(player, momz); + } + else if ((player->trickpanel != TRICKSTATE_NONE) && P_IsObjectOnGround(player->mo)) // Landed from trick + { + K_SpawnDashDustRelease(player); + + if (player->fastfall) + { + if (player->curshield != KSHIELD_BUBBLE) // Allow bubblebounce (it's cute) but don't give standard trick rewards + { + P_InstaThrust(player->mo, player->mo->angle, 2*abs(player->fastfall)/3 + 15*FRACUNIT); + player->mo->hitlag = 3; + S_StartSound(player->mo, sfx_gshba); + player->fastfall = 0; // intentionally skip bounce + player->trickcharge = 0; + + UINT8 i; + for (i = 0; i < 4; i++) + { + mobj_t *arc = P_SpawnMobjFromMobj(player->mo, 0, 0, 0, MT_CHARGEFALL); + P_SetTarget(&arc->target, player->mo); + arc->extravalue1 = i; + } + } + } + else + { + S_StartSound(player->mo, sfx_s23c); + + UINT8 award = TICRATE - player->trickboostdecay; + + player->trickboost = award; + K_AwardPlayerRings(player, + (TICRATE-player->trickboostdecay) * player->lastairtime/3 / TICRATE, // Scale ring award by same amount as trickboost + true); + + if (player->trickpanel == TRICKSTATE_FORWARD) + player->trickboostpower /= 18; + else if (player->trickpanel != TRICKSTATE_BACK) + player->trickboostpower /= 9; + } + + player->trickpanel = TRICKSTATE_NONE; + player->trickboostdecay = 0; } // Wait until we let go off the control stick to remove the delay diff --git a/src/k_kart.h b/src/k_kart.h index 7b3d6d62c..44b7283dc 100644 --- a/src/k_kart.h +++ b/src/k_kart.h @@ -119,9 +119,11 @@ angle_t K_StumbleSlope(angle_t angle, angle_t pitch, angle_t roll); void K_StumblePlayer(player_t *player); boolean K_CheckStumble(player_t *player, angle_t oldPitch, angle_t oldRoll, boolean fromAir); void K_InitStumbleIndicator(player_t *player); -void K_InitSliptideZipIndicator(player_t *player); +void K_InitWavedashIndicator(player_t *player); +void K_InitTrickIndicator(player_t *player); void K_UpdateStumbleIndicator(player_t *player); -void K_UpdateSliptideZipIndicator(player_t *player); +void K_UpdateWavedashIndicator(player_t *player); +void K_UpdateTrickIndicator(player_t *player); INT32 K_ExplodePlayer(player_t *player, mobj_t *inflictor, mobj_t *source); void K_DebtStingPlayer(player_t *player, mobj_t *source); void K_GiveBumpersToPlayer(player_t *player, player_t *victim, UINT8 amount); diff --git a/src/k_objects.h b/src/k_objects.h index bad973f62..72029bb65 100644 --- a/src/k_objects.h +++ b/src/k_objects.h @@ -126,6 +126,11 @@ void Obj_BlockRingThink(mobj_t *ring); void Obj_BlockBodyThink(mobj_t *body); void Obj_GuardBreakThink(mobj_t *fx); +void Obj_ChargeAuraThink(mobj_t *aura); +void Obj_ChargeFallThink(mobj_t *charge); +void Obj_ChargeReleaseThink(mobj_t *release); +void Obj_ChargeExtraThink(mobj_t *extra); + /* Ring Shooter */ boolean Obj_RingShooterThinker(mobj_t *mo); boolean Obj_PlayerRingShooterFreeze(player_t *const player); diff --git a/src/k_respawn.c b/src/k_respawn.c index 144156fc6..f9c03e499 100644 --- a/src/k_respawn.c +++ b/src/k_respawn.c @@ -156,7 +156,9 @@ void K_DoIngameRespawn(player_t *player) player->ringboost = 0; player->driftboost = player->strongdriftboost = 0; player->gateBoost = 0; - player->sliptideZip = player->sliptideZipBoost = player->sliptideZipDelay = 0; + player->trickcharge = 0; + player->infinitether = 0; + player->wavedash = player->wavedashboost = player->wavedashdelay = 0; K_TumbleInterrupt(player); P_ResetPlayer(player); diff --git a/src/k_terrain.c b/src/k_terrain.c index 36edb5261..d2d9a3f8a 100644 --- a/src/k_terrain.c +++ b/src/k_terrain.c @@ -485,8 +485,6 @@ void K_ProcessTerrainEffect(mobj_t *mo) fixed_t speed = FixedHypot(mo->momx, mo->momy); fixed_t upwards = 16 * terrain->trickPanel; - player->trickpanel = 1; - player->pflags |= PF_TRICKDELAY; K_DoPogoSpring(mo, upwards, 1); // Reduce speed @@ -551,7 +549,7 @@ void K_ProcessTerrainEffect(mobj_t *mo) P_InstaThrust(player->mo, thrustAngle, max(thrustSpeed, 2*playerSpeed)); player->dashpadcooldown = TICRATE/3; - player->trickpanel = 0; + player->trickpanel = TRICKSTATE_NONE; player->floorboost = 2; S_StartSound(player->mo, sfx_cdfm62); diff --git a/src/lua_playerlib.c b/src/lua_playerlib.c index 0f6b7a485..2d39cc7c9 100644 --- a/src/lua_playerlib.c +++ b/src/lua_playerlib.c @@ -233,6 +233,8 @@ static int player_get(lua_State *L) lua_pushinteger(L, plr->lastpickuptype); else if (fastcmp(field,"airtime")) lua_pushinteger(L, plr->airtime); + else if (fastcmp(field,"lastairtime")) + lua_pushinteger(L, plr->lastairtime); else if (fastcmp(field,"flashing")) lua_pushinteger(L, plr->flashing); else if (fastcmp(field,"spinouttimer")) @@ -255,6 +257,8 @@ static int player_get(lua_State *L) lua_pushboolean(L, plr->flipDI); else if (fastcmp(field,"markedfordeath")) lua_pushboolean(L, plr->markedfordeath); + else if (fastcmp(field,"dotrickfx")) + lua_pushboolean(L, plr->dotrickfx); else if (fastcmp(field,"ringboxdelay")) lua_pushinteger(L, plr->ringboxdelay); else if (fastcmp(field,"ringboxaward")) @@ -325,12 +329,16 @@ static int player_get(lua_State *L) lua_pushinteger(L, plr->tripwireLeniency); else if (fastcmp(field,"tripwireReboundDelay")) lua_pushinteger(L, plr->tripwireReboundDelay); - else if (fastcmp(field,"sliptideZip")) - lua_pushinteger(L, plr->sliptideZip); - else if (fastcmp(field,"sliptideZipDelay")) - lua_pushinteger(L, plr->sliptideZipDelay); - else if (fastcmp(field,"sliptideZipBoost")) - lua_pushinteger(L, plr->sliptideZipBoost); + else if (fastcmp(field,"wavedash")) + lua_pushinteger(L, plr->wavedash); + else if (fastcmp(field,"wavedashdelay")) + lua_pushinteger(L, plr->wavedashdelay); + else if (fastcmp(field,"wavedashboost")) + lua_pushinteger(L, plr->wavedashboost); + else if (fastcmp(field,"trickcharge")) + lua_pushinteger(L, plr->trickcharge); + else if (fastcmp(field,"infinitether")) + lua_pushinteger(L, plr->infinitether); else if (fastcmp(field,"lastsafelap")) lua_pushinteger(L, plr->lastsafelap); else if (fastcmp(field,"instaWhipCharge")) @@ -721,6 +729,8 @@ static int player_set(lua_State *L) plr->airtime = luaL_checkinteger(L, 3); else if (fastcmp(field,"airtime")) plr->airtime = luaL_checkinteger(L, 3); + else if (fastcmp(field,"lastairtime")) + plr->lastairtime = luaL_checkinteger(L, 3); else if (fastcmp(field,"flashing")) plr->flashing = luaL_checkinteger(L, 3); else if (fastcmp(field,"spinouttimer")) @@ -743,6 +753,8 @@ static int player_set(lua_State *L) plr->flipDI = luaL_checkboolean(L, 3); else if (fastcmp(field,"markedfordeath")) plr->markedfordeath = luaL_checkboolean(L, 3); + else if (fastcmp(field,"dotrickfx")) + plr->dotrickfx = luaL_checkboolean(L, 3); else if (fastcmp(field,"ringboxdelay")) plr->ringboxdelay = luaL_checkinteger(L, 3); else if (fastcmp(field,"ringboxaward")) @@ -813,12 +825,16 @@ static int player_set(lua_State *L) plr->tripwireLeniency = luaL_checkinteger(L, 3); else if (fastcmp(field,"tripwireReboundDelay")) plr->tripwireReboundDelay = luaL_checkinteger(L, 3); - else if (fastcmp(field,"sliptideZip")) - plr->sliptideZip = luaL_checkinteger(L, 3); - else if (fastcmp(field,"sliptideZipDelay")) - plr->sliptideZipDelay = luaL_checkinteger(L, 3); - else if (fastcmp(field,"sliptideZipBoost")) - plr->sliptideZipBoost = luaL_checkinteger(L, 3); + else if (fastcmp(field,"wavedash")) + plr->wavedash = luaL_checkinteger(L, 3); + else if (fastcmp(field,"wavedashdelay")) + plr->wavedashdelay = luaL_checkinteger(L, 3); + else if (fastcmp(field,"wavedashboost")) + plr->wavedashboost = luaL_checkinteger(L, 3); + else if (fastcmp(field,"trickcharge")) + plr->trickcharge = luaL_checkinteger(L, 3); + else if (fastcmp(field,"infinitether")) + plr->infinitether = luaL_checkinteger(L, 3); else if (fastcmp(field,"lastsafelap")) plr->lastsafelap = luaL_checkinteger(L, 3); else if (fastcmp(field,"instaWhipCharge")) diff --git a/src/objects/CMakeLists.txt b/src/objects/CMakeLists.txt index 1e035d52d..8abbd34ee 100644 --- a/src/objects/CMakeLists.txt +++ b/src/objects/CMakeLists.txt @@ -39,6 +39,7 @@ target_sources(SRB2SDL2 PRIVATE wpzothers.c shadow.cpp ball-switch.cpp + charge.c ) add_subdirectory(versus) diff --git a/src/objects/charge.c b/src/objects/charge.c new file mode 100644 index 000000000..7623b6ece --- /dev/null +++ b/src/objects/charge.c @@ -0,0 +1,147 @@ +#include "../doomdef.h" +#include "../info.h" +#include "../k_objects.h" +#include "../p_local.h" +#include "../k_kart.h" +#include "../k_powerup.h" +#include "../m_random.h" + +#define CHARGEAURA_BURSTTIME (9) +#define CHARGEAURA_SPARKRADIUS (40) + +// xval1: destruction timer +// xval2: master (spawns other visuals) +// cvmem: spawn time (used to offset flash) +void Obj_ChargeAuraThink (mobj_t *aura) +{ + if (P_MobjWasRemoved(aura->target) || !aura->target->player || (aura->extravalue1 >= CHARGEAURA_BURSTTIME)) + { + P_RemoveMobj(aura); + } + else + { + mobj_t *mo = aura->target; + player_t *player = mo->player; + + // Follow player + aura->flags &= ~(MF_NOCLIPTHING); + P_MoveOrigin(aura, mo->x, mo->y, mo->z + mo->height/2); + aura->flags |= MF_NOCLIPTHING; + aura->color = mo->color; + + aura->renderflags &= ~RF_DONTDRAW; + + fixed_t baseScale = 12*mo->scale/10; + + if (aura->extravalue1 || !player->trickcharge) + { + aura->extravalue1++; + baseScale += (mo->scale / 3) * aura->extravalue1; + aura->renderflags &= ~RF_TRANSMASK; + aura->renderflags |= (aura->extravalue1)<extravalue1 % 2) + aura->renderflags |= RF_DONTDRAW; + } + + P_SetScale(aura, baseScale); + + // Twirl + aura->angle = aura->angle - ANG1*(player->trickcharge/TICRATE + 4); + // Visuals + aura->renderflags |= RF_PAPERSPRITE|RF_ADD; + + // fuck + boolean forceinvisible = !!!((leveltime - aura->cvmem) % 4); + if (aura->extravalue1 || !(player->driftcharge > K_GetKartDriftSparkValueForStage(player, 3))) + forceinvisible = false; + + if (forceinvisible) + aura->renderflags |= RF_DONTDRAW; + + if (aura->extravalue2) + { + if (player->driftcharge) + { + mobj_t *spark = P_SpawnMobjFromMobj(aura, + FRACUNIT*P_RandomRange(PR_DECORATION, -1*CHARGEAURA_SPARKRADIUS, CHARGEAURA_SPARKRADIUS), + FRACUNIT*P_RandomRange(PR_DECORATION, -1*CHARGEAURA_SPARKRADIUS, CHARGEAURA_SPARKRADIUS), + FRACUNIT*P_RandomRange(PR_DECORATION, -1*CHARGEAURA_SPARKRADIUS, CHARGEAURA_SPARKRADIUS), + MT_CHARGESPARK); + spark->frame = P_RandomRange(PR_DECORATION, 1, 5); + spark->renderflags |= RF_FULLBRIGHT|RF_ADD; + P_SetTarget(&spark->target, aura); + P_SetScale(spark, 15*aura->scale/10); + } + + if (forceinvisible) + { + mobj_t *flicker = P_SpawnMobjFromMobj(aura, 0, 0, 0, MT_CHARGEFLICKER); + P_SetTarget(&flicker->target, aura); + P_SetScale(flicker, aura->scale); + } + } + } +} + +void Obj_ChargeFallThink (mobj_t *charge) +{ + if (P_MobjWasRemoved(charge->target) || !charge->target->player) + { + P_RemoveMobj(charge); + } + else + { + mobj_t *mo = charge->target; + + // Follow player + charge->flags &= ~(MF_NOCLIPTHING); + P_MoveOrigin(charge, mo->x, mo->y, mo->z); + charge->flags |= MF_NOCLIPTHING; + charge->color = mo->color; + charge->angle = mo->angle + ANGLE_45 + (ANGLE_90 * charge->extravalue1); + + if (!P_IsObjectOnGround(mo)) + charge->renderflags |= RF_DONTDRAW; + else + charge->renderflags &= ~RF_DONTDRAW; + + fixed_t baseScale = 12*mo->scale/10; + P_SetScale(charge, baseScale); + + charge->renderflags &= ~RF_TRANSMASK; + if (charge->tics < 10) + charge->renderflags |= (9 - charge->tics)<renderflags |= RF_PAPERSPRITE|RF_ADD; + } +} + +// xval1: lifetime (used to offset from tracked player) +void Obj_ChargeReleaseThink (mobj_t *release) +{ + release->renderflags &= ~RF_TRANSMASK; + if (release->tics < 36) + release->renderflags |= (9 - release->tics/4)<rollangle += ANG15/2; + + if (P_MobjWasRemoved(release->target) || !release->target->player) + return; + + release->extravalue1++; + + fixed_t off = 8 * release->extravalue1 * release->target->scale; + angle_t ang = K_MomentumAngle(release->target) + ANGLE_180; + fixed_t xoff = FixedMul(off, FINECOSINE(ang >> ANGLETOFINESHIFT)); + fixed_t yoff = FixedMul(off, FINESINE(ang >> ANGLETOFINESHIFT)); + + P_MoveOrigin(release, release->target->x + xoff, release->target->y + yoff, release->target->z + release->target->height/2); +} + +void Obj_ChargeExtraThink (mobj_t *extra) +{ + extra->renderflags &= ~RF_TRANSMASK; + if (extra->tics < 18) + extra->renderflags |= (9 - extra->tics/2)<rollangle += ANG30; +} \ No newline at end of file diff --git a/src/objects/dash-rings.c b/src/objects/dash-rings.c index d40e341bb..ba9fed39e 100644 --- a/src/objects/dash-rings.c +++ b/src/objects/dash-rings.c @@ -66,7 +66,7 @@ void Obj_RainbowDashRingSpawn(mobj_t *mobj) void Obj_DashRingSetup(mobj_t *mobj, mapthing_t *mthing) { - static const UINT8 numColors = sizeof(rainbow_colors) / sizeof(skincolornum_t); + static const UINT8 numColors = sizeof(ring_colors) / sizeof(skincolornum_t); const UINT8 additionalThrust = mthing->thing_args[1]; statenum_t ringState, overlayState; @@ -199,8 +199,6 @@ static void RegularDashRingLaunch(player_t *player, mobj_t *ring) static void RainbowDashRingLaunch(player_t *player, mobj_t *ring) { player->mo->eflags &= ~MFE_SPRUNG; - player->trickpanel = 1; - player->pflags |= PF_TRICKDELAY; K_DoPogoSpring(player->mo, 0, 0); DashRingLaunch(player, ring); } diff --git a/src/p_inter.c b/src/p_inter.c index 69d0c2a17..88da20f74 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -1693,7 +1693,7 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget target->player->roundscore = 0; } - target->player->trickpanel = 0; + target->player->trickpanel = TRICKSTATE_NONE; ACS_RunPlayerDeathScript(target->player); } @@ -2612,10 +2612,18 @@ static boolean P_KillPlayer(player_t *player, mobj_t *inflictor, mobj_t *source, P_SetPlayerMobjState(player->mo, player->mo->info->deathstate); - if (player->sliptideZipIndicator && !P_MobjWasRemoved(player->sliptideZipIndicator)) - P_RemoveMobj(player->sliptideZipIndicator); - if (player->stumbleIndicator && !P_MobjWasRemoved(player->stumbleIndicator)) - P_RemoveMobj(player->stumbleIndicator); +#define PlayerPointerRemove(field) \ + if (P_MobjWasRemoved(field) == false) \ + { \ + P_RemoveMobj(field); \ + P_SetTarget(&field, NULL); \ + } + + PlayerPointerRemove(player->stumbleIndicator); + PlayerPointerRemove(player->wavedashIndicator); + PlayerPointerRemove(player->trickIndicator); + +#undef PlayerPointerRemove if (type == DMG_TIMEOVER) { diff --git a/src/p_map.c b/src/p_map.c index 9888c23c3..69ff25357 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -427,12 +427,8 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object) { if (spring->reactiontime == 0) { - object->player->tricktime = 0; // Reset post-hitlag timer - // Setup the boost for potential upwards trick, at worse, make it your regular max speed. (boost = curr speed*1.25) - object->player->trickboostpower = max(FixedDiv(object->player->speed, K_GetKartSpeed(object->player, false, false)) - FRACUNIT, 0)*125/100; - //CONS_Printf("Got boost: %d%\n", mo->player->trickboostpower*100 / FRACUNIT); - object->player->trickpanel = 1; - object->player->pflags |= PF_TRICKDELAY; + object->eflags &= ~MFE_SPRUNG; // needed to permit the following + K_DoPogoSpring(object, -vertispeed, 0); // negative so momz isn't modified } else { @@ -512,12 +508,6 @@ static void P_DoFanAndGasJet(mobj_t *spring, mobj_t *object) if (spring->thing_args[1]) { - if (object->player) - { - object->player->trickpanel = 1; - object->player->pflags |= PF_TRICKDELAY; - } - K_DoPogoSpring(object, 32<player->trickpanel >= 2) + if (mo->player->trickpanel > TRICKSTATE_READY) { gravityadd = (5*gravityadd)/2; } @@ -8395,10 +8395,9 @@ static boolean P_MobjRegularThink(mobj_t *mobj) return true; } - mobj->extravalue1 += 1; - mobj->angle += ANG1*mobj->extravalue1; - P_SetScale(mobj, mobj->target->scale); + mobj->extravalue1 += 1; + P_InstaScale(mobj, mobj->target->scale); destx = mobj->target->x; desty = mobj->target->y; @@ -8407,6 +8406,12 @@ static boolean P_MobjRegularThink(mobj_t *mobj) { destx += FixedMul(mobj->radius*2, FINECOSINE((mobj->angle+ANGLE_90) >> ANGLETOFINESHIFT)); desty += FixedMul(mobj->radius*2, FINESINE((mobj->angle+ANGLE_90) >> ANGLETOFINESHIFT)); + + mobj->eflags = (mobj->eflags & ~MFE_VERTICALFLIP)|(mobj->target->eflags & MFE_VERTICALFLIP); + mobj->flags2 = (mobj->flags2 & ~MF2_OBJECTFLIP)|(mobj->target->flags2 & MF2_OBJECTFLIP); + + if (mobj->eflags & MFE_VERTICALFLIP) + zoff += mobj->target->height - mobj->height; } else if (mobj->state == &states[S_MAGICIANBOX_TOP]) // top { @@ -8416,6 +8421,150 @@ static boolean P_MobjRegularThink(mobj_t *mobj) // Necessary to "ride" on Garden Top zoff += mobj->target->sprzoff; + if (mobj->flags2 & MF2_AMBUSH) + { + P_SetOrigin(mobj, destx, desty, mobj->target->z + zoff); + mobj->old_angle = mobj->angle; + mobj->flags2 &= ~MF2_AMBUSH; + } + else + { + P_MoveOrigin(mobj, destx, desty, mobj->target->z + zoff); + } + break; + } + case MT_SIDETRICK: + { + fixed_t destx, desty; + fixed_t zoff = 0; + + if (!mobj->target + || !mobj->target->health + || !mobj->target->player + || mobj->target->player->trickpanel <= TRICKSTATE_FORWARD) + { + P_RemoveMobj(mobj); + return false; + } + + // Flicker every other frame from first visibility + if (mobj->flags2 & MF2_BOSSDEAD) + { + mobj->renderflags |= RF_DONTDRAW; + } + else + { + mobj->renderflags &= ~RF_DONTDRAW; + mobj->renderflags |= (mobj->target->renderflags & RF_DONTDRAW); + } + + mobj->eflags = (mobj->eflags & ~MFE_VERTICALFLIP)|(mobj->target->eflags & MFE_VERTICALFLIP); + mobj->flags2 = ((mobj->flags2 & ~MF2_OBJECTFLIP)|(mobj->target->flags2 & MF2_OBJECTFLIP)) ^ MF2_BOSSDEAD; + + fixed_t scale = mobj->target->scale; + + // sweeping effect + if (mobj->target->player->trickpanel == TRICKSTATE_BACK) + { + const fixed_t saferange = (20*FRACUNIT)/21; + if (mobj->threshold < -saferange) + { + mobj->threshold = -saferange; + mobj->flags2 |= MF2_AMBUSH; + } + else while (mobj->threshold > saferange) + { + mobj->threshold -= 2*saferange; + mobj->flags2 |= MF2_AMBUSH; + } + + scale = P_ReturnThrustX(mobj, FixedAngle(90*mobj->threshold), scale); + + // This funny dealie is to make it so default + // scale is placed as standard, + // but variant threshold shifts upwards + fixed_t extraoffset = FixedMul(mobj->info->height, mobj->target->scale - scale); + if (mobj->threshold < 0) + extraoffset /= 2; + + // And this makes it swooce across the object. + extraoffset += FixedMul(mobj->threshold, mobj->target->height); + + zoff += P_MobjFlip(mobj) * extraoffset; + + mobj->threshold += (saferange/8); + } + + mobj->angle += mobj->movedir; + P_InstaScale(mobj, scale); + + destx = mobj->target->x; + desty = mobj->target->y; + + destx += P_ReturnThrustX(mobj, mobj->angle - ANGLE_90, mobj->radius*2); + desty += P_ReturnThrustY(mobj, mobj->angle - ANGLE_90, mobj->radius*2); + + if (mobj->eflags & MFE_VERTICALFLIP) + zoff += mobj->target->height - mobj->height; + + // Necessary to "ride" on Garden Top + zoff += mobj->target->sprzoff; + + if (mobj->flags2 & MF2_AMBUSH) + { + P_SetOrigin(mobj, destx, desty, mobj->target->z + zoff); + mobj->old_angle = mobj->angle; + mobj->flags2 &= ~MF2_AMBUSH; + } + else + { + P_MoveOrigin(mobj, destx, desty, mobj->target->z + zoff); + } + break; + } + case MT_FORWARDTRICK: + { + fixed_t destx, desty; + fixed_t zoff = 0; + + if (!mobj->target + || !mobj->target->health + || !mobj->target->player + || mobj->target->player->trickpanel != TRICKSTATE_FORWARD) + { + P_RemoveMobj(mobj); + return false; + } + + mobj->renderflags &= ~RF_DONTDRAW; + mobj->renderflags |= (mobj->target->renderflags & RF_DONTDRAW); + + mobj->eflags = (mobj->eflags & ~MFE_VERTICALFLIP)|(mobj->target->eflags & MFE_VERTICALFLIP); + mobj->flags2 = ((mobj->flags2 & ~MF2_OBJECTFLIP)|(mobj->target->flags2 & MF2_OBJECTFLIP)) ^ MF2_BOSSDEAD; + + // sweeping effect + P_InstaScale(mobj, (6*mobj->target->scale)/5); + + const fixed_t sweep = FixedMul(FRACUNIT - (mobj->threshold * 2), mobj->radius); + + destx = mobj->target->x; + desty = mobj->target->y; + + destx += P_ReturnThrustX(mobj, mobj->movedir, sweep); + desty += P_ReturnThrustY(mobj, mobj->movedir, sweep); + + const fixed_t sideways = P_ReturnThrustY(mobj, mobj->angle - mobj->movedir, mobj->radius); + destx += P_ReturnThrustX(mobj, mobj->movedir + ANGLE_90, sideways); + desty += P_ReturnThrustY(mobj, mobj->movedir + ANGLE_90, sideways); + + if (mobj->eflags & MFE_VERTICALFLIP) + zoff += mobj->target->height - (mobj->height + 18*mobj->target->scale); + else + zoff += 18*mobj->target->scale; + + // Necessary to "ride" on Garden Top + zoff += mobj->target->sprzoff; + if (mobj->flags2 & MF2_AMBUSH) { P_SetOrigin(mobj, destx, desty, mobj->target->z + zoff); @@ -8425,6 +8574,20 @@ static boolean P_MobjRegularThink(mobj_t *mobj) { P_MoveOrigin(mobj, destx, desty, mobj->target->z + zoff); } + + mobj->threshold += FRACUNIT/6; + if (mobj->threshold > FRACUNIT) + { + mobj_t *puff = P_SpawnGhostMobj(mobj); + if (puff) + { + puff->renderflags = (puff->renderflags & ~RF_TRANSMASK)|RF_ADD; + } + + mobj->threshold -= FRACUNIT; + mobj->flags2 |= MF2_AMBUSH; + } + break; } case MT_LIGHTNINGSHIELD: @@ -8673,6 +8836,26 @@ static boolean P_MobjRegularThink(mobj_t *mobj) Obj_BlockBodyThink(mobj); break; } + case MT_CHARGEAURA: + { + Obj_ChargeAuraThink(mobj); + break; + } + case MT_CHARGEFALL: + { + Obj_ChargeFallThink(mobj); + break; + } + case MT_CHARGERELEASE: + { + Obj_ChargeReleaseThink(mobj); + break; + } + case MT_CHARGEEXTRA: + { + Obj_ChargeExtraThink(mobj); + break; + } case MT_GUARDBREAK: { Obj_GuardBreakThink(mobj); @@ -12409,8 +12592,8 @@ void P_SpawnPlayer(INT32 playernum) p->griefValue = 0; K_InitStumbleIndicator(p); - - K_InitSliptideZipIndicator(p); + K_InitWavedashIndicator(p); + K_InitTrickIndicator(p); if (gametyperules & GTR_ITEMARROWS) { diff --git a/src/p_saveg.c b/src/p_saveg.c index ea59a1ccd..6fa7a9363 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -65,7 +65,7 @@ savedata_cup_t cupsavedata; #define ARCHIVEBLOCK_RNG 0x7FAAB5BD // Note: This cannot be bigger -// than an UINT16 +// than an UINT16 (for now) typedef enum { AWAYVIEW = 0x0001, @@ -75,12 +75,13 @@ typedef enum SKYBOXCENTER = 0x0010, HOVERHYUDORO = 0x0020, STUMBLE = 0x0040, - SLIPTIDEZIP = 0x0080, + WAVEDASH = 0x0080, RINGSHOOTER = 0x0100, WHIP = 0x0200, HAND = 0x0400, FLICKYATTACKER = 0x0800, FLICKYCONTROLLER = 0x1000, + TRICKINDICATOR = 0x2000, } player_saveflags; static inline void P_ArchivePlayer(savebuffer_t *save) @@ -310,8 +311,11 @@ static void P_NetArchivePlayers(savebuffer_t *save) if (players[i].stumbleIndicator) flags |= STUMBLE; - if (players[i].sliptideZipIndicator) - flags |= SLIPTIDEZIP; + if (players[i].wavedashIndicator) + flags |= WAVEDASH; + + if (players[i].trickIndicator) + flags |= TRICKINDICATOR; if (players[i].whip) flags |= WHIP; @@ -348,8 +352,11 @@ static void P_NetArchivePlayers(savebuffer_t *save) if (flags & STUMBLE) WRITEUINT32(save->p, players[i].stumbleIndicator->mobjnum); - if (flags & SLIPTIDEZIP) - WRITEUINT32(save->p, players[i].sliptideZipIndicator->mobjnum); + if (flags & WAVEDASH) + WRITEUINT32(save->p, players[i].wavedashIndicator->mobjnum); + + if (flags & TRICKINDICATOR) + WRITEUINT32(save->p, players[i].trickIndicator->mobjnum); if (flags & WHIP) WRITEUINT32(save->p, players[i].whip->mobjnum); @@ -394,6 +401,7 @@ static void P_NetArchivePlayers(savebuffer_t *save) WRITEUINT32(save->p, K_GetWaypointHeapIndex(players[i].currentwaypoint)); WRITEUINT32(save->p, K_GetWaypointHeapIndex(players[i].nextwaypoint)); WRITEUINT32(save->p, players[i].airtime); + WRITEUINT32(save->p, players[i].lastairtime); WRITEUINT8(save->p, players[i].startboost); WRITEUINT8(save->p, players[i].dropdashboost); @@ -536,9 +544,12 @@ static void P_NetArchivePlayers(savebuffer_t *save) WRITEUINT8(save->p, players[i].tripwireReboundDelay); - WRITEUINT16(save->p, players[i].sliptideZip); - WRITEUINT8(save->p, players[i].sliptideZipDelay); - WRITEUINT16(save->p, players[i].sliptideZipBoost); + WRITEUINT16(save->p, players[i].wavedash); + WRITEUINT8(save->p, players[i].wavedashdelay); + WRITEUINT16(save->p, players[i].wavedashboost); + WRITEUINT16(save->p, players[i].trickcharge); + + WRITEUINT16(save->p, players[i].infinitether); WRITEUINT8(save->p, players[i].lastsafelap); @@ -556,6 +567,7 @@ static void P_NetArchivePlayers(savebuffer_t *save) WRITEINT16(save->p, players[i].incontrol); WRITEUINT8(save->p, players[i].markedfordeath); + WRITEUINT8(save->p, players[i].dotrickfx); WRITEUINT8(save->p, players[i].ringboxdelay); WRITEUINT8(save->p, players[i].ringboxaward); @@ -878,8 +890,11 @@ static void P_NetUnArchivePlayers(savebuffer_t *save) if (flags & STUMBLE) players[i].stumbleIndicator = (mobj_t *)(size_t)READUINT32(save->p); - if (flags & SLIPTIDEZIP) - players[i].sliptideZipIndicator = (mobj_t *)(size_t)READUINT32(save->p); + if (flags & WAVEDASH) + players[i].wavedashIndicator = (mobj_t *)(size_t)READUINT32(save->p); + + if (flags & TRICKINDICATOR) + players[i].trickIndicator = (mobj_t *)(size_t)READUINT32(save->p); if (flags & WHIP) players[i].whip = (mobj_t *)(size_t)READUINT32(save->p); @@ -925,6 +940,7 @@ static void P_NetUnArchivePlayers(savebuffer_t *save) players[i].currentwaypoint = (waypoint_t *)(size_t)READUINT32(save->p); players[i].nextwaypoint = (waypoint_t *)(size_t)READUINT32(save->p); players[i].airtime = READUINT32(save->p); + players[i].lastairtime = READUINT32(save->p); players[i].startboost = READUINT8(save->p); players[i].dropdashboost = READUINT8(save->p); @@ -1067,9 +1083,12 @@ static void P_NetUnArchivePlayers(savebuffer_t *save) players[i].tripwireReboundDelay = READUINT8(save->p); - players[i].sliptideZip = READUINT16(save->p); - players[i].sliptideZipDelay = READUINT8(save->p); - players[i].sliptideZipBoost = READUINT16(save->p); + players[i].wavedash = READUINT16(save->p); + players[i].wavedashdelay = READUINT8(save->p); + players[i].wavedashboost = READUINT16(save->p); + players[i].trickcharge = READUINT16(save->p); + + players[i].infinitether = READUINT16(save->p); players[i].lastsafelap = READUINT8(save->p); @@ -1087,6 +1106,7 @@ static void P_NetUnArchivePlayers(savebuffer_t *save) players[i].incontrol = READINT16(save->p); players[i].markedfordeath = READUINT8(save->p); + players[i].dotrickfx = READUINT8(save->p); players[i].ringboxdelay = READUINT8(save->p); players[i].ringboxaward = READUINT8(save->p); @@ -5674,12 +5694,19 @@ static void P_RelinkPointers(void) if (!P_SetTarget(&players[i].stumbleIndicator, P_FindNewPosition(temp))) CONS_Debug(DBG_GAMELOGIC, "stumbleIndicator not found on player %d\n", i); } - if (players[i].sliptideZipIndicator) + if (players[i].wavedashIndicator) { - temp = (UINT32)(size_t)players[i].sliptideZipIndicator; - players[i].sliptideZipIndicator = NULL; - if (!P_SetTarget(&players[i].sliptideZipIndicator, P_FindNewPosition(temp))) - CONS_Debug(DBG_GAMELOGIC, "sliptideZipIndicator not found on player %d\n", i); + temp = (UINT32)(size_t)players[i].wavedashIndicator; + players[i].wavedashIndicator = NULL; + if (!P_SetTarget(&players[i].wavedashIndicator, P_FindNewPosition(temp))) + CONS_Debug(DBG_GAMELOGIC, "wavedashIndicator not found on player %d\n", i); + } + if (players[i].trickIndicator) + { + temp = (UINT32)(size_t)players[i].trickIndicator; + players[i].trickIndicator = NULL; + if (!P_SetTarget(&players[i].trickIndicator, P_FindNewPosition(temp))) + CONS_Debug(DBG_GAMELOGIC, "trickIndicator not found on player %d\n", i); } if (players[i].whip) { diff --git a/src/p_user.c b/src/p_user.c index 516bc168a..fbb03d497 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -478,7 +478,7 @@ void P_ResetPlayer(player_t *player) player->onconveyor = 0; //player->drift = player->driftcharge = 0; - player->trickpanel = 0; + player->trickpanel = TRICKSTATE_NONE; player->glanceDir = 0; player->fastfall = 0; @@ -1109,6 +1109,7 @@ mobj_t *P_SpawnGhostMobj(mobj_t *mobj) P_SetTarget(&ghost->target, mobj); P_SetScale(ghost, mobj->scale); + ghost->scalespeed = mobj->scalespeed; ghost->destscale = mobj->scale; if (mobj->eflags & MFE_VERTICALFLIP) @@ -1163,6 +1164,7 @@ mobj_t *P_SpawnGhostMobj(mobj_t *mobj) ghost->old_angle = (mobj->player ? mobj->player->old_drawangle2 : mobj->old_angle2); ghost->old_pitch = mobj->old_pitch2; ghost->old_roll = mobj->old_roll2; + ghost->old_scale = mobj->old_scale2; K_ReduceVFX(ghost, mobj->player); @@ -2468,18 +2470,21 @@ void P_MovePlayer(player_t *player) } else { - K_KartMoveAnimation(player); - - if (player->trickpanel == 2) + if (player->trickpanel > TRICKSTATE_READY) { - player->drawangle += ANGLE_22h; - } - else if (player->trickpanel >= 3) - { - player->drawangle -= ANGLE_22h; + if (player->trickpanel <= TRICKSTATE_RIGHT) // right/forward + { + player->drawangle += ANGLE_22h; + } + else //if (player->trickpanel >= TRICKSTATE_LEFT) // left/back + { + player->drawangle -= ANGLE_22h; + } } else { + K_KartMoveAnimation(player); + player->drawangle = player->mo->angle; if (player->aizdriftturn) @@ -4056,7 +4061,8 @@ void P_PlayerThink(player_t *player) PlayerPointerErase(player->followmobj); PlayerPointerErase(player->stumbleIndicator); - PlayerPointerErase(player->sliptideZipIndicator); + PlayerPointerErase(player->wavedashIndicator); + PlayerPointerErase(player->trickIndicator); PlayerPointerErase(player->whip); PlayerPointerErase(player->hand); PlayerPointerErase(player->ringShooter); @@ -4078,6 +4084,7 @@ void P_PlayerThink(player_t *player) if (P_IsObjectOnGround(player->mo) && !P_PlayerInPain(player)) // This isn't airtime, but it's control loss all the same. { + player->lastairtime = player->airtime; player->airtime = 0; } else diff --git a/src/sounds.c b/src/sounds.c index cbb5836a2..dcfa01cc3 100644 --- a/src/sounds.c +++ b/src/sounds.c @@ -1119,6 +1119,10 @@ sfxinfo_t S_sfx[NUMSFX] = {"fshld2", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Flame Shield burst"}, {"fshld3", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Flame Shield cooldown"}, + // RR - Trick Panel + {"trick0", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Trick confirm"}, + {"trick1", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Trick"}, + // RR - Ballhog Charge {"bhog00", false, 64, 64, -1, NULL, 0, -1, -1, LUMPERROR, "Ballhog charging"}, {"bhog01", false, 64, 64, -1, NULL, 0, -1, -1, LUMPERROR, "Ballhog charging"}, diff --git a/src/sounds.h b/src/sounds.h index a19d2b4ed..0d686b3c2 100644 --- a/src/sounds.h +++ b/src/sounds.h @@ -1187,6 +1187,10 @@ typedef enum sfx_fshld2, sfx_fshld3, + // RR - Trick panels + sfx_trick0, + sfx_trick1, + // RR - Ballhog Charge sfx_bhog00, sfx_bhog01,