diff --git a/src/d_netcmd.c b/src/d_netcmd.c index e3435b39f..7c3298bf9 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -357,6 +357,8 @@ consvar_t cv_selfpropelledbomb = {"selfpropelledbomb", "On", CV_NETVAR|CV_CHEAT consvar_t cv_grow = {"grow", "On", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_shrink = {"shrink", "On", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_thundershield = {"thundershield", "On", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_bubbleshield = {"bubbleshield", "On", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_flameshield = {"flameshield", "On", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_hyudoro = {"hyudoro", "On", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_pogospring = {"pogospring", "On", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_kitchensink = {"kitchensink", "On", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; diff --git a/src/d_netcmd.h b/src/d_netcmd.h index 8238dea2b..81854bc71 100644 --- a/src/d_netcmd.h +++ b/src/d_netcmd.h @@ -104,7 +104,8 @@ extern consvar_t cv_recycler;*/ extern consvar_t cv_superring, cv_sneaker, cv_rocketsneaker, cv_invincibility, cv_banana; extern consvar_t cv_eggmanmonitor, cv_orbinaut, cv_jawz, cv_mine; extern consvar_t cv_ballhog, cv_selfpropelledbomb, cv_grow, cv_shrink; -extern consvar_t cv_thundershield, cv_hyudoro, cv_pogospring, cv_kitchensink; +extern consvar_t cv_thundershield, cv_bubbleshield, cv_flameshield; +extern consvar_t cv_hyudoro, cv_pogospring, cv_kitchensink; extern consvar_t cv_triplesneaker, cv_triplebanana, cv_decabanana; extern consvar_t cv_tripleorbinaut, cv_quadorbinaut, cv_dualjawz; diff --git a/src/d_player.h b/src/d_player.h index 07e0f7a97..2465b90ef 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -217,6 +217,8 @@ typedef enum KITEM_GROW, KITEM_SHRINK, KITEM_THUNDERSHIELD, + KITEM_BUBBLESHIELD, + KITEM_FLAMESHIELD, KITEM_HYUDORO, KITEM_POGOSPRING, KITEM_SUPERRING, @@ -235,6 +237,15 @@ typedef enum NUMKARTRESULTS } kartitems_t; +typedef enum +{ + KSHIELD_NONE = 0, + KSHIELD_THUNDER = 1, + KSHIELD_BUBBLE = 2, + KSHIELD_FLAME = 3, + NUMKARTSHIELDS +} kartshields_t; + //{ SRB2kart - kartstuff typedef enum { @@ -290,20 +301,25 @@ typedef enum k_itemtype, // KITEM_ constant for item number k_itemamount, // Amount of said item k_itemheld, // Are you holding an item? + k_holdready, // Hold button-style item is ready to activate // Some items use timers for their duration or effects - //k_thunderanim, // Duration of Thunder Shield's use animation k_curshield, // 0 = no shield, 1 = thunder shield k_hyudorotimer, // Duration of the Hyudoro offroad effect itself k_stealingtimer, // You are stealing an item, this is your timer k_stolentimer, // You are being stolen from, this is your timer k_superring, // Spawn rings on top of you every tic! k_sneakertimer, // Duration of the Sneaker Boost itself - k_levelbooster, // Duration of a level booster's boost (same as sneaker, but separated for ) + k_levelbooster, // Duration of a level booster's boost (same as sneaker, but separated for boost stacking) k_growshrinktimer, // > 0 = Big, < 0 = small k_squishedtimer, // Squished frame timer k_rocketsneakertimer, // Rocket Sneaker duration timer k_invincibilitytimer, // Invincibility timer + k_bubblecool, // Bubble Shield use cooldown + k_bubbleblowup, // Bubble Shield usage blowup + k_flamedash, // Flame Shield dash power + k_flamemeter, // Flame Shield dash meter left + k_flamelength, // Flame Shield dash meter, number of segments k_eggmanheld, // Eggman monitor held, separate from k_itemheld so it doesn't stop you from getting items k_eggmanexplode, // Fake item recieved, explode in a few seconds k_eggmanblame, // Fake item recieved, who set this fake @@ -325,7 +341,6 @@ typedef enum k_getsparks, // Disable drift sparks at low speed, JUST enough to give acceleration the actual headstart above speed k_jawztargetdelay, // Delay for Jawz target switching, to make it less twitchy k_spectatewait, // How long have you been waiting as a spectator - k_growcancel, // Hold the item button down to cancel Grow k_tiregrease, // Reduced friction timer after hitting a horizontal spring k_springstars, // Spawn stars around a player when they hit a spring k_springcolor, // Color of spring stars @@ -372,6 +387,9 @@ typedef enum // QUICKLY GET EITHER SNEAKER OR LEVEL BOOSTER SINCE THEY ARE FUNCTIONALLY IDENTICAL #define EITHERSNEAKER(p) (p->kartstuff[k_sneakertimer] || p->kartstuff[k_levelbooster]) +// QUICKLY GET RING TOTAL, INCLUDING RINGS CURRENTLY IN THE PICKUP ANIMATION +#define RINGTOTAL(p) (p->kartstuff[k_rings] + p->kartstuff[k_pickuprings]) + //} #define WEP_AUTO 1 diff --git a/src/dehacked.c b/src/dehacked.c index 468f3aae0..e2a95eb83 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -1887,6 +1887,7 @@ static actionpointer_t actionpointers[] = {{A_ReaperThinker}, "A_REAPERTHINKER"}, //SRB2kart {{A_MementosTPParticles}, "A_MEMENTOSTPPARTICLES"}, //SRB2kart {{A_FlameParticle}, "A_FLAMEPARTICLE"}, // SRB2kart + {{A_FlameShieldPaper}, "A_FLAMESHIELDPAPER"}, // SRB2kart {{A_OrbitNights}, "A_ORBITNIGHTS"}, {{A_GhostMe}, "A_GHOSTME"}, {{A_SetObjectState}, "A_SETOBJECTSTATE"}, @@ -6646,6 +6647,85 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_THUNDERSHIELD23", "S_THUNDERSHIELD24", + // Bubble Shield + "S_BUBBLESHIELD1", + "S_BUBBLESHIELD2", + "S_BUBBLESHIELD3", + "S_BUBBLESHIELD4", + "S_BUBBLESHIELD5", + "S_BUBBLESHIELD6", + "S_BUBBLESHIELD7", + "S_BUBBLESHIELD8", + "S_BUBBLESHIELD9", + "S_BUBBLESHIELD10", + "S_BUBBLESHIELD11", + "S_BUBBLESHIELD12", + "S_BUBBLESHIELD13", + "S_BUBBLESHIELD14", + "S_BUBBLESHIELD15", + "S_BUBBLESHIELD16", + "S_BUBBLESHIELD17", + "S_BUBBLESHIELD18", + "S_BUBBLESHIELDBLOWUP", + "S_BUBBLESHIELDTRAP1", + "S_BUBBLESHIELDTRAP2", + "S_BUBBLESHIELDTRAP3", + "S_BUBBLESHIELDTRAP4", + "S_BUBBLESHIELDTRAP5", + "S_BUBBLESHIELDTRAP6", + "S_BUBBLESHIELDTRAP7", + "S_BUBBLESHIELDTRAP8", + "S_BUBBLESHIELDWAVE1", + "S_BUBBLESHIELDWAVE2", + "S_BUBBLESHIELDWAVE3", + "S_BUBBLESHIELDWAVE4", + "S_BUBBLESHIELDWAVE5", + "S_BUBBLESHIELDWAVE6", + + // Flame Shield + "S_FLAMESHIELD1", + "S_FLAMESHIELD2", + "S_FLAMESHIELD3", + "S_FLAMESHIELD4", + "S_FLAMESHIELD5", + "S_FLAMESHIELD6", + "S_FLAMESHIELD7", + "S_FLAMESHIELD8", + "S_FLAMESHIELD9", + "S_FLAMESHIELD10", + "S_FLAMESHIELD11", + "S_FLAMESHIELD12", + "S_FLAMESHIELD13", + "S_FLAMESHIELD14", + "S_FLAMESHIELD15", + "S_FLAMESHIELD16", + "S_FLAMESHIELD17", + "S_FLAMESHIELD18", + + "S_FLAMESHIELDDASH1", + "S_FLAMESHIELDDASH2", + "S_FLAMESHIELDDASH3", + "S_FLAMESHIELDDASH4", + "S_FLAMESHIELDDASH5", + "S_FLAMESHIELDDASH6", + "S_FLAMESHIELDDASH7", + "S_FLAMESHIELDDASH8", + "S_FLAMESHIELDDASH9", + "S_FLAMESHIELDDASH10", + "S_FLAMESHIELDDASH11", + "S_FLAMESHIELDDASH12", + + "S_FLAMESHIELDDASH2_UNDERLAY", + "S_FLAMESHIELDDASH5_UNDERLAY", + "S_FLAMESHIELDDASH8_UNDERLAY", + "S_FLAMESHIELDDASH11_UNDERLAY", + + "S_FLAMESHIELDPAPER", + "S_FLAMESHIELDLINE1", + "S_FLAMESHIELDLINE2", + "S_FLAMESHIELDLINE3", + "S_FLAMESHIELDFLASH", + // The legend "S_SINK", "S_SINK_SHIELD", @@ -7802,7 +7882,12 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s "MT_SPB", // Self-Propelled Bomb "MT_SPBEXPLOSION", - "MT_THUNDERSHIELD", // Thunder Shield stuff + "MT_THUNDERSHIELD", // Shields + "MT_BUBBLESHIELD", + "MT_FLAMESHIELD", + "MT_FLAMESHIELDUNDERLAY", + "MT_FLAMESHIELDPAPER", + "MT_BUBBLESHIELDTRAP", "MT_SINK", // Kitchen Sink Stuff "MT_SINK_SHIELD", @@ -8478,6 +8563,7 @@ static const char *const KARTSTUFF_LIST[] = { "ITEMTYPE", "ITEMAMOUNT", "ITEMHELD", + "HOLDREADY", "CURSHIELD", "HYUDOROTIMER", @@ -8490,6 +8576,11 @@ static const char *const KARTSTUFF_LIST[] = { "SQUISHEDTIMER", "ROCKETSNEAKERTIMER", "INVINCIBILITYTIMER", + "BUBBLECOOL", + "BUBBLEBLOWUP", + "FLAMEDASH", + "FLAMEMETER", + "FLAMELENGTH", "EGGMANHELD", "EGGMANEXPLODE", "EGGMANBLAME", @@ -8509,7 +8600,6 @@ static const char *const KARTSTUFF_LIST[] = { "GETSPARKS", "JAWZTARGETDELAY", "SPECTATEWAIT", - "GROWCANCEL", "TIREGREASE", "SPRINGSTARS", "SPRINGCOLOR", @@ -9037,6 +9127,8 @@ struct { {"KITEM_GROW",KITEM_GROW}, {"KITEM_SHRINK",KITEM_SHRINK}, {"KITEM_THUNDERSHIELD",KITEM_THUNDERSHIELD}, + {"KITEM_BUBBLESHIELD",KITEM_BUBBLESHIELD}, + {"KITEM_FLAMESHIELD",KITEM_FLAMESHIELD}, {"KITEM_HYUDORO",KITEM_HYUDORO}, {"KITEM_POGOSPRING",KITEM_POGOSPRING}, {"KITEM_SUPERRING",KITEM_SUPERRING}, @@ -9050,6 +9142,13 @@ struct { {"KRITEM_DUALJAWZ",KRITEM_DUALJAWZ}, {"NUMKARTRESULTS",NUMKARTRESULTS}, + // kartshields_t + {"KSHIELD_NONE",KSHIELD_NONE}, + {"KSHIELD_THUNDER",KSHIELD_THUNDER}, + {"KSHIELD_BUBBLE",KSHIELD_BUBBLE}, + {"KSHIELD_FLAME",KSHIELD_FLAME}, + {"NUMKARTSHIELDS",NUMKARTSHIELDS}, + // translation colormaps {"TC_DEFAULT",TC_DEFAULT}, {"TC_BOSS",TC_BOSS}, diff --git a/src/doomstat.h b/src/doomstat.h index 3a89e8d28..952586231 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -465,12 +465,14 @@ extern INT32 hyudorotime; extern INT32 stealtime; extern INT32 sneakertime; extern INT32 itemtime; +extern INT32 bubbletime; extern INT32 comebacktime; extern INT32 bumptime; extern INT32 greasetics; extern INT32 wipeoutslowtime; extern INT32 wantedreduce; extern INT32 wantedfrequency; +extern INT32 flameseg; extern UINT8 introtoplay; extern UINT8 creditscutscene; diff --git a/src/g_game.c b/src/g_game.c index f9059ab60..684e73492 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -226,12 +226,14 @@ INT32 hyudorotime = 7*TICRATE; INT32 stealtime = TICRATE/2; INT32 sneakertime = TICRATE + (TICRATE/3); INT32 itemtime = 8*TICRATE; +INT32 bubbletime = TICRATE/2; INT32 comebacktime = 10*TICRATE; INT32 bumptime = 6; INT32 greasetics = 3*TICRATE; INT32 wipeoutslowtime = 20; INT32 wantedreduce = 5*TICRATE; INT32 wantedfrequency = 10*TICRATE; +INT32 flameseg = TICRATE/4; INT32 gameovertics = 15*TICRATE; diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index b7675a21b..01cc9b01f 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -2023,7 +2023,7 @@ static void HWR_StoreWallRange(double startfrac, double endfrac) // Single sided line... Deal only with the middletexture (if one exists) gr_midtexture = R_GetTextureNum(gr_sidedef->midtexture); if (gr_midtexture - && gr_linedef->special != 41) // Ignore horizon line for OGL + && gr_linedef->special != HORIZONSPECIAL) // Ignore horizon line for OGL { { fixed_t texturevpeg; diff --git a/src/info.c b/src/info.c index ab9dd44eb..981773387 100644 --- a/src/info.c +++ b/src/info.c @@ -57,20 +57,22 @@ char sprnames[NUMSPRITES + 1][5] = "SRBL","SRBM","SRBN","SRBO", //SRB2kart Sprites "RNDM","RPOP","SGNS","FAST","DSHR","BOST","BOSM","KFRE","KINV","KINF", - "WIPD","DRIF","BDRF","DUST","DRWS","RSHE","FITM","BANA","ORBN","JAWZ", - "SSMN","KRBM","BHOG","BHBM","SPBM","THNS","SINK","SITR","KBLN","DEZL", - "POKE","AUDI","DECO","DOOD","SNES","GBAS","SPRS","BUZB","CHOM","SACO", - "CRAB","BRNG","BUMP","FLEN","CLAS","PSHW","ISTA","ISTB","ARRO","ITEM", - "ITMO","ITMI","ITMN","WANT","PBOM","HIT1","HIT2","HIT3","RETI","AIDU", - "KSPK","LZI1","LZI2","KLIT","FZSM","FZBM","FPRT","SBUS","MARB","FUFO", - "RUST","BLON","VAPE","HTZA","HTZB","SGVA","SGVB","SGVC","PGTR","PGF1", - "PGF2","PGF3","PGBH","DPLR","SPTL","ENM1","GARU","MARR","REAP","JITB", - "CDMO","CDBU","PINE","PPLR","DPPT","AATR","COCO","BDST","FROG","CBRA", - "HOLE","BBRA","EGFG","SMKP","MTYM","THWP","SNOB","ICEB","CNDL","DOCH", - "DUCK","GTRE","CHES","CHIM","DRGN","LZMN","PGSS","ZTCH","MKMA","MKMP", - "RTCH","BOWL","BOWH","BRRL","BRRR","HRSE","TOAH","BFRT","OFRT","RFRT", - "PFRT","ASPK","HBST","HBSO","HBSF","WBLZ","WBLN","FWRK","MXCL","RGSP", - "DRAF","GRES","OTFG","DBOS","XMS4","XMS5","VIEW" + "WIPD","DRIF","BDRF","DUST","DRWS","RSHE","FITM","BANA","ORBN","JAWZ","SSMN", + "KRBM","BHOG","BHBM","SPBM","THNS","BUBS","BWVE", + "FLMS","FLMD","FLMP","FLML","FLMF", + "SINK","SITR", + "KBLN","DEZL","POKE","AUDI","DECO","DOOD","SNES","GBAS","SPRS","BUZB", + "CHOM","SACO","CRAB","BRNG","BUMP","FLEN","CLAS","PSHW","ISTA", + "ISTB","ARRO","ITEM","ITMO","ITMI","ITMN","WANT","PBOM","HIT1","HIT2", + "HIT3","RETI","AIDU","KSPK","LZI1","LZI2","KLIT","FZSM","FZBM","FPRT", + "SBUS","MARB","FUFO","RUST","BLON","VAPE","HTZA","HTZB","SGVA","SGVB", + "SGVC","PGTR","PGF1","PGF2","PGF3","PGBH","DPLR","SPTL","ENM1","GARU", + "MARR","REAP","JITB","CDMO","CDBU","PINE","PPLR","DPPT","AATR","COCO", + "BDST","FROG","CBRA","HOLE","BBRA","EGFG","SMKP","MTYM","THWP","SNOB", + "ICEB","CNDL","DOCH","DUCK","GTRE","CHES","CHIM","DRGN","LZMN","PGSS", + "ZTCH","MKMA","MKMP","RTCH","BOWL","BOWH","BRRL","BRRR","HRSE","TOAH", + "BFRT","OFRT","RFRT","PFRT","ASPK","HBST","HBSO","HBSF","WBLZ","WBLN", + "FWRK","MXCL","RGSP","DRAF","GRES","OTFG","DBOS","XMS4","XMS5","VIEW" }; // Doesn't work with g++, needs actionf_p1 (don't modify this comment) @@ -2866,6 +2868,83 @@ state_t states[NUMSTATES] = {SPR_THNS, FF_FULLBRIGHT|1, 2, {NULL}, 0, 0, S_THUNDERSHIELD24}, // S_THUNDERSHIELD23 {SPR_THNS, FF_FULLBRIGHT|0, 2, {NULL}, 0, 0, S_THUNDERSHIELD1}, // S_THUNDERSHIELD24 + {SPR_BUBS, FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_BUBBLESHIELD2}, // S_BUBBLESHIELD1 + {SPR_BUBS, FF_FULLBRIGHT|13, 2, {NULL}, 0, 0, S_BUBBLESHIELD3}, // S_BUBBLESHIELD2 + {SPR_BUBS, FF_FULLBRIGHT|1, 2, {NULL}, 0, 0, S_BUBBLESHIELD4}, // S_BUBBLESHIELD3 + {SPR_BUBS, FF_FULLBRIGHT|13, 2, {NULL}, 0, 0, S_BUBBLESHIELD5}, // S_BUBBLESHIELD4 + {SPR_BUBS, FF_FULLBRIGHT|2, 2, {NULL}, 0, 0, S_BUBBLESHIELD6}, // S_BUBBLESHIELD5 + {SPR_BUBS, FF_FULLBRIGHT|13, 2, {NULL}, 0, 0, S_BUBBLESHIELD7}, // S_BUBBLESHIELD6 + {SPR_BUBS, FF_FULLBRIGHT|3, 2, {NULL}, 0, 0, S_BUBBLESHIELD8}, // S_BUBBLESHIELD7 + {SPR_BUBS, FF_FULLBRIGHT|13, 2, {NULL}, 0, 0, S_BUBBLESHIELD9}, // S_BUBBLESHIELD8 + {SPR_BUBS, FF_FULLBRIGHT|4, 2, {NULL}, 0, 0, S_BUBBLESHIELD10}, // S_BUBBLESHIELD9 + {SPR_BUBS, FF_FULLBRIGHT|13, 2, {NULL}, 0, 0, S_BUBBLESHIELD11}, // S_BUBBLESHIELD10 + {SPR_BUBS, FF_FULLBRIGHT|5, 2, {NULL}, 0, 0, S_BUBBLESHIELD12}, // S_BUBBLESHIELD11 + {SPR_BUBS, FF_FULLBRIGHT|13, 2, {NULL}, 0, 0, S_BUBBLESHIELD13}, // S_BUBBLESHIELD12 + {SPR_BUBS, FF_FULLBRIGHT|6, 2, {NULL}, 0, 0, S_BUBBLESHIELD14}, // S_BUBBLESHIELD13 + {SPR_BUBS, FF_FULLBRIGHT|13, 2, {NULL}, 0, 0, S_BUBBLESHIELD15}, // S_BUBBLESHIELD14 + {SPR_BUBS, FF_FULLBRIGHT|7, 2, {NULL}, 0, 0, S_BUBBLESHIELD16}, // S_BUBBLESHIELD15 + {SPR_BUBS, FF_FULLBRIGHT|13, 2, {NULL}, 0, 0, S_BUBBLESHIELD17}, // S_BUBBLESHIELD16 + {SPR_BUBS, FF_FULLBRIGHT|8, 2, {NULL}, 0, 0, S_BUBBLESHIELD18}, // S_BUBBLESHIELD17 + {SPR_BUBS, FF_FULLBRIGHT|13, 2, {NULL}, 0, 0, S_BUBBLESHIELD1}, // S_BUBBLESHIELD18 + {SPR_BUBS, FF_FULLBRIGHT|13, -1, {NULL}, 0, 0, S_BUBBLESHIELDBLOWUP}, // S_BUBBLESHIELDBLOWUP + {SPR_BUBS, FF_FULLBRIGHT|13, 2, {NULL}, 0, 0, S_BUBBLESHIELDTRAP2}, // S_BUBBLESHIELDTRAP1 + {SPR_BUBS, FF_FULLBRIGHT|14, 2, {NULL}, 0, 0, S_BUBBLESHIELDTRAP3}, // S_BUBBLESHIELDTRAP2 + {SPR_BUBS, FF_FULLBRIGHT|15, 2, {NULL}, 0, 0, S_BUBBLESHIELDTRAP4}, // S_BUBBLESHIELDTRAP3 + {SPR_BUBS, FF_FULLBRIGHT|14, 2, {NULL}, 0, 0, S_BUBBLESHIELDTRAP5}, // S_BUBBLESHIELDTRAP4 + {SPR_BUBS, FF_FULLBRIGHT|13, 2, {NULL}, 0, 0, S_BUBBLESHIELDTRAP6}, // S_BUBBLESHIELDTRAP5 + {SPR_BUBS, FF_FULLBRIGHT|12, 2, {NULL}, 0, 0, S_BUBBLESHIELDTRAP7}, // S_BUBBLESHIELDTRAP6 + {SPR_BUBS, FF_FULLBRIGHT|11, 2, {NULL}, 0, 0, S_BUBBLESHIELDTRAP8}, // S_BUBBLESHIELDTRAP7 + {SPR_BUBS, FF_FULLBRIGHT|12, 2, {NULL}, 0, 0, S_BUBBLESHIELDTRAP1}, // S_BUBBLESHIELDTRAP8 + {SPR_BWVE, FF_FULLBRIGHT, 1, {NULL}, 0, 0, S_BUBBLESHIELDWAVE2}, // S_BUBBLESHIELDWAVE1 + {SPR_BWVE, FF_FULLBRIGHT|1, 1, {NULL}, 0, 0, S_BUBBLESHIELDWAVE3}, // S_BUBBLESHIELDWAVE2 + {SPR_BWVE, FF_FULLBRIGHT|2, 1, {NULL}, 0, 0, S_BUBBLESHIELDWAVE4}, // S_BUBBLESHIELDWAVE3 + {SPR_BWVE, FF_FULLBRIGHT|3, 1, {NULL}, 0, 0, S_BUBBLESHIELDWAVE5}, // S_BUBBLESHIELDWAVE4 + {SPR_BWVE, FF_FULLBRIGHT|4, 1, {NULL}, 0, 0, S_BUBBLESHIELDWAVE6}, // S_BUBBLESHIELDWAVE5 + {SPR_BWVE, FF_FULLBRIGHT|5, 1, {NULL}, 0, 0, S_NULL}, // S_BUBBLESHIELDWAVE6 + + {SPR_FLMS, FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_FLAMESHIELD2}, // S_FLAMESHIELD1 + {SPR_FLMS, FF_FULLBRIGHT|9, 2, {NULL}, 0, 0, S_FLAMESHIELD3}, // S_FLAMESHIELD2 + {SPR_FLMS, FF_FULLBRIGHT|1, 2, {NULL}, 0, 0, S_FLAMESHIELD4}, // S_FLAMESHIELD3 + {SPR_FLMS, FF_FULLBRIGHT|10, 2, {NULL}, 0, 0, S_FLAMESHIELD5}, // S_FLAMESHIELD4 + {SPR_FLMS, FF_FULLBRIGHT|2, 2, {NULL}, 0, 0, S_FLAMESHIELD6}, // S_FLAMESHIELD5 + {SPR_FLMS, FF_FULLBRIGHT|11, 2, {NULL}, 0, 0, S_FLAMESHIELD7}, // S_FLAMESHIELD6 + {SPR_FLMS, FF_FULLBRIGHT|3, 2, {NULL}, 0, 0, S_FLAMESHIELD8}, // S_FLAMESHIELD7 + {SPR_FLMS, FF_FULLBRIGHT|12, 2, {NULL}, 0, 0, S_FLAMESHIELD9}, // S_FLAMESHIELD8 + {SPR_FLMS, FF_FULLBRIGHT|4, 2, {NULL}, 0, 0, S_FLAMESHIELD10}, // S_FLAMESHIELD9 + {SPR_FLMS, FF_FULLBRIGHT|13, 2, {NULL}, 0, 0, S_FLAMESHIELD11}, // S_FLAMESHIELD10 + {SPR_FLMS, FF_FULLBRIGHT|5, 2, {NULL}, 0, 0, S_FLAMESHIELD12}, // S_FLAMESHIELD11 + {SPR_FLMS, FF_FULLBRIGHT|14, 2, {NULL}, 0, 0, S_FLAMESHIELD13}, // S_FLAMESHIELD12 + {SPR_FLMS, FF_FULLBRIGHT|6, 2, {NULL}, 0, 0, S_FLAMESHIELD14}, // S_FLAMESHIELD13 + {SPR_FLMS, FF_FULLBRIGHT|15, 2, {NULL}, 0, 0, S_FLAMESHIELD15}, // S_FLAMESHIELD14 + {SPR_FLMS, FF_FULLBRIGHT|7, 2, {NULL}, 0, 0, S_FLAMESHIELD16}, // S_FLAMESHIELD15 + {SPR_FLMS, FF_FULLBRIGHT|16, 2, {NULL}, 0, 0, S_FLAMESHIELD17}, // S_FLAMESHIELD16 + {SPR_FLMS, FF_FULLBRIGHT|8, 2, {NULL}, 0, 0, S_FLAMESHIELD18}, // S_FLAMESHIELD17 + {SPR_FLMS, FF_FULLBRIGHT|17, 2, {NULL}, 0, 0, S_FLAMESHIELD1}, // S_FLAMESHIELD18 + + {SPR_FLMD, FF_FULLBRIGHT|1, 1, {NULL}, 0, 0, S_FLAMESHIELDDASH2}, // S_FLAMESHIELDDASH1 + {SPR_FLMD, FF_FULLBRIGHT|5, 1, {NULL}, 0, 0, S_FLAMESHIELDDASH3}, // S_FLAMESHIELDDASH2 + {SPR_FLMD, FF_FULLBRIGHT, 1, {A_FlameShieldPaper}, 0, 2, S_FLAMESHIELDDASH4}, // S_FLAMESHIELDDASH3 + {SPR_FLMD, FF_FULLBRIGHT|2, 1, {NULL}, 0, 0, S_FLAMESHIELDDASH5}, // S_FLAMESHIELDDASH4 + {SPR_FLMD, FF_FULLBRIGHT|6, 1, {NULL}, 0, 0, S_FLAMESHIELDDASH6}, // S_FLAMESHIELDDASH5 + {SPR_FLMD, FF_FULLBRIGHT, 1, {A_FlameShieldPaper}, 1, 3, S_FLAMESHIELDDASH7}, // S_FLAMESHIELDDASH6 + {SPR_FLMD, FF_FULLBRIGHT|3, 1, {NULL}, 0, 0, S_FLAMESHIELDDASH8}, // S_FLAMESHIELDDASH7 + {SPR_FLMD, FF_FULLBRIGHT|7, 1, {NULL}, 0, 0, S_FLAMESHIELDDASH9}, // S_FLAMESHIELDDASH8 + {SPR_FLMD, FF_FULLBRIGHT, 1, {A_FlameShieldPaper}, 2, 0, S_FLAMESHIELDDASH10}, // S_FLAMESHIELDDASH9 + {SPR_FLMD, FF_FULLBRIGHT|4, 1, {NULL}, 0, 0, S_FLAMESHIELDDASH11}, // S_FLAMESHIELDDASH10 + {SPR_FLMD, FF_FULLBRIGHT|8, 1, {NULL}, 0, 0, S_FLAMESHIELDDASH12}, // S_FLAMESHIELDDASH11 + {SPR_FLMD, FF_FULLBRIGHT, 1, {A_FlameShieldPaper}, 3, 1, S_FLAMESHIELDDASH1}, // S_FLAMESHIELDDASH12 + + {SPR_FLMD, FF_FULLBRIGHT|9, 2, {NULL}, 0, 0, S_NULL}, // S_FLAMESHIELDDASH2_UNDERLAY + {SPR_FLMD, FF_FULLBRIGHT|10, 2, {NULL}, 0, 0, S_NULL}, // S_FLAMESHIELDDASH5_UNDERLAY + {SPR_FLMD, FF_FULLBRIGHT|11, 2, {NULL}, 0, 0, S_NULL}, // S_FLAMESHIELDDASH8_UNDERLAY + {SPR_FLMD, FF_FULLBRIGHT|12, 2, {NULL}, 0, 0, S_NULL}, // S_FLAMESHIELDDASH11_UNDERLAY + + {SPR_FLMP, FF_FULLBRIGHT|FF_PAPERSPRITE, 2, {NULL}, 0, 0, S_NULL}, // S_FLAMESHIELDPAPER + {SPR_FLML, FF_FULLBRIGHT|FF_PAPERSPRITE|FF_ANIMATE, 7, {NULL}, 6, 1, S_NULL}, // S_FLAMESHIELDLINE1 + {SPR_FLML, FF_FULLBRIGHT|FF_PAPERSPRITE|FF_ANIMATE|7, 7, {NULL}, 6, 1, S_NULL}, // S_FLAMESHIELDLINE2 + {SPR_FLML, FF_FULLBRIGHT|FF_PAPERSPRITE|FF_ANIMATE|14, 7, {NULL}, 6, 1, S_NULL}, // S_FLAMESHIELDLINE3 + {SPR_FLMF, FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_NULL}, // S_FLAMESHIELDFLASH + {SPR_SINK, 0, 1, {A_SmokeTrailer}, MT_SINKTRAIL, 0, S_SINK}, // S_SINK {SPR_SINK, 0|FF_TRANS80|FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_SINK_SHIELD}, // S_SINK_SHIELD {SPR_SITR, 0, 1, {NULL}, 0, 0, S_SINKTRAIL2}, // S_SINKTRAIL1 @@ -15582,7 +15661,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 1, // damage sfx_cdfm28, // activesound - MF_SPECIAL|MF_BOUNCE|MF_SHOOTABLE|MF_DONTENCOREMAP, // flags + MF_BOUNCE|MF_SHOOTABLE|MF_DONTENCOREMAP, // flags S_NULL // raisestate }, @@ -15609,7 +15688,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 1, // damage sfx_None, // activesound - MF_SPECIAL|MF_SHOOTABLE|MF_NOGRAVITY|MF_SCENERY|MF_DONTENCOREMAP, // flags + MF_SHOOTABLE|MF_NOGRAVITY|MF_SCENERY|MF_DONTENCOREMAP, // flags S_NULL // raisestate }, @@ -16143,7 +16222,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL, // xdeathstate sfx_None, // deathsound 8, // speed - 20*FRACUNIT, // radius + 28*FRACUNIT, // radius 56*FRACUNIT, // height 1, // display offset 16, // mass @@ -16153,6 +16232,141 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL // raisestate }, + { // MT_BUBBLESHIELD + -1, // doomednum + S_BUBBLESHIELD1, // 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 + 8, // speed + 28*FRACUNIT, // radius + 56*FRACUNIT, // height + 1, // display offset + 16, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID|MF_NOCLIP|MF_NOGRAVITY|MF_DONTENCOREMAP, // flags + S_NULL // raisestate + }, + + { // MT_FLAMESHIELD + -1, // doomednum + S_FLAMESHIELD1, // 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 + 8, // speed + 28*FRACUNIT, // radius + 56*FRACUNIT, // height + 1, // display offset + 16, // mass + 0, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_NOCLIP|MF_NOGRAVITY|MF_DONTENCOREMAP, // flags + S_NULL // raisestate + }, + + { // MT_FLAMESHIELDUNDERLAY + -1, // doomednum + S_FLAMESHIELDDASH2_UNDERLAY, // 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 + 8<player->kartstuff[k_hyudorotimer]) return true; // no interaction - // Player Damage - P_DamageMobj(t2, t1, t1->target, 1); - K_KartBouncing(t2, t1, false, false); - S_StartSound(t2, sfx_s3k7b); + if (t2->player->kartstuff[k_flamedash] && t2->player->kartstuff[k_itemtype] == KITEM_FLAMESHIELD) + { + // Melt item + S_StartSound(t2, sfx_s3k43); + } + else + { + // Player Damage + P_DamageMobj(t2, t1, t1->target, 1); + K_KartBouncing(t2, t1, false, false); + S_StartSound(t2, sfx_s3k7b); + } damageitem = true; } @@ -126,8 +134,16 @@ boolean K_BananaBallhogCollide(mobj_t *t1, mobj_t *t2) if (t1->type == MT_BANANA && t1->health > 1) S_StartSound(t2, sfx_bsnipe); - // Player Damage - K_SpinPlayer(t2->player, t1->target, 0, t1, (t1->type == MT_BANANA || t1->type == MT_BANANA_SHIELD)); + if (t2->player->kartstuff[k_flamedash] && t2->player->kartstuff[k_itemtype] == KITEM_FLAMESHIELD) + { + // Melt item + S_StartSound(t2, sfx_s3k43); + } + else + { + // Player Damage + K_SpinPlayer(t2->player, t1->target, 0, t1, (t1->type == MT_BANANA || t1->type == MT_BANANA_SHIELD)); + } damageitem = true; } @@ -181,9 +197,73 @@ boolean K_EggItemCollide(mobj_t *t1, mobj_t *t2) { // Push fakes out of other item boxes if (t2->type == MT_RANDOMITEM || t2->type == MT_EGGMANITEM) + { P_InstaThrust(t1, R_PointToAngle2(t2->x, t2->y, t1->x, t1->y), t2->radius/4); + return true; + } + + if (t2->player) + { + if ((t1->target == t2 || t1->target == t2->target) && (t1->threshold > 0)) + return true; + + if (t1->health <= 0 || t2->health <= 0) + return true; + + if (!P_CanPickupItem(t2->player, 2)) + return true; + + if (G_BattleGametype() && t2->player->kartstuff[k_bumper] <= 0) + { + if (t2->player->kartstuff[k_comebackmode] || t2->player->kartstuff[k_comebacktimer]) + return true; + t2->player->kartstuff[k_comebackmode] = 2; + } + else + { + K_DropItems(t2->player); //K_StripItems(t2->player); + //K_StripOther(t2->player); + t2->player->kartstuff[k_itemroulette] = 1; + t2->player->kartstuff[k_roulettetype] = 2; + } + + if (t2->player->kartstuff[k_flamedash] && t2->player->kartstuff[k_itemtype] == KITEM_FLAMESHIELD) + { + // Melt item + S_StartSound(t2, sfx_s3k43); + P_KillMobj(t1, t2, t2); + return true; + } + else + { + mobj_t *poof = P_SpawnMobj(t1->x, t1->y, t1->z, MT_EXPLODE); + S_StartSound(poof, t1->info->deathsound); + +#if 0 + // Eggbox snipe! + if (t1->type == MT_EGGMANITEM && t1->health > 1) + S_StartSound(t2, sfx_bsnipe); +#endif + + if (t1->target && t1->target->player) + { + if (G_RaceGametype() || t1->target->player->kartstuff[k_bumper] > 0) + t2->player->kartstuff[k_eggmanblame] = t1->target->player-players; + else + t2->player->kartstuff[k_eggmanblame] = t2->player-players; + + if (t1->target->hnext == t1) + { + P_SetTarget(&t1->target->hnext, NULL); + t1->target->player->kartstuff[k_eggmanheld] = 0; + } + } + + P_RemoveMobj(t1); + return true; + } + } - // Player collision is handled by TouchSpecial return true; } diff --git a/src/k_kart.c b/src/k_kart.c index 3badb2d68..1cf0eb365 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -559,6 +559,8 @@ void K_RegisterKartStuff(void) CV_RegisterVar(&cv_grow); CV_RegisterVar(&cv_shrink); CV_RegisterVar(&cv_thundershield); + CV_RegisterVar(&cv_bubbleshield); + CV_RegisterVar(&cv_flameshield); CV_RegisterVar(&cv_hyudoro); CV_RegisterVar(&cv_pogospring); CV_RegisterVar(&cv_superring); @@ -640,30 +642,61 @@ fixed_t K_GetKartGameSpeedScalar(SINT8 value) //{ SRB2kart Roulette Code - Position Based +consvar_t *KartItemCVars[NUMKARTRESULTS-1] = +{ + &cv_sneaker, + &cv_rocketsneaker, + &cv_invincibility, + &cv_banana, + &cv_eggmanmonitor, + &cv_orbinaut, + &cv_jawz, + &cv_mine, + &cv_ballhog, + &cv_selfpropelledbomb, + &cv_grow, + &cv_shrink, + &cv_thundershield, + &cv_bubbleshield, + &cv_flameshield, + &cv_hyudoro, + &cv_pogospring, + &cv_superring, + &cv_kitchensink, + &cv_triplesneaker, + &cv_triplebanana, + &cv_decabanana, + &cv_tripleorbinaut, + &cv_quadorbinaut, + &cv_dualjawz +}; + #define NUMKARTODDS 80 // Less ugly 2D arrays -static INT32 K_KartItemOddsRace[NUMKARTRESULTS][8] = +static INT32 K_KartItemOddsRace[NUMKARTRESULTS-1][8] = { //P-Odds 0 1 2 3 4 5 6 7 - /*Sneaker*/ { 0, 0, 4, 6, 7, 0, 0, 0 }, // Sneaker - /*Rocket Sneaker*/ { 0, 0, 0, 0, 1, 4, 5, 3 }, // Rocket Sneaker - /*Invincibility*/ { 0, 0, 0, 0, 1, 4, 6,10 }, // Invincibility - /*Banana*/ { 9, 4, 2, 1, 0, 0, 0, 0 }, // Banana - /*Eggman Monitor*/ { 3, 2, 1, 0, 0, 0, 0, 0 }, // Eggman Monitor - /*Orbinaut*/ { 7, 6, 4, 2, 0, 0, 0, 0 }, // Orbinaut + /*Sneaker*/ { 0, 0, 2, 4, 6, 0, 0, 0 }, // Sneaker + /*Rocket Sneaker*/ { 0, 0, 0, 0, 0, 2, 4, 6 }, // Rocket Sneaker + /*Invincibility*/ { 0, 0, 0, 0, 1, 4, 7, 9 }, // Invincibility + /*Banana*/ { 7, 3, 2, 0, 0, 0, 0, 0 }, // Banana + /*Eggman Monitor*/ { 3, 2, 0, 0, 0, 0, 0, 0 }, // Eggman Monitor + /*Orbinaut*/ { 7, 4, 3, 2, 0, 0, 0, 0 }, // Orbinaut /*Jawz*/ { 0, 3, 2, 1, 1, 0, 0, 0 }, // Jawz /*Mine*/ { 0, 2, 2, 1, 0, 0, 0, 0 }, // Mine /*Ballhog*/ { 0, 0, 2, 1, 0, 0, 0, 0 }, // Ballhog /*Self-Propelled Bomb*/ { 0, 1, 2, 3, 4, 2, 2, 0 }, // Self-Propelled Bomb - /*Grow*/ { 0, 0, 0, 0, 0, 2, 5, 7 }, // Grow + /*Grow*/ { 0, 0, 0, 1, 2, 3, 0, 0 }, // Grow /*Shrink*/ { 0, 0, 0, 0, 0, 0, 2, 0 }, // Shrink /*Thunder Shield*/ { 1, 2, 0, 0, 0, 0, 0, 0 }, // Thunder Shield - /*Hyudoro*/ { 0, 0, 0, 1, 2, 1, 0, 0 }, // Hyudoro + /*Bubble Shield*/ { 0, 2, 3, 3, 1, 0, 0, 0 }, // Bubble Shield + /*Flame Shield*/ { 0, 0, 0, 0, 0, 1, 3, 5 }, // Flame Shield + /*Hyudoro*/ { 0, 0, 0, 1, 2, 0, 0, 0 }, // Hyudoro /*Pogo Spring*/ { 0, 0, 0, 0, 0, 0, 0, 0 }, // Pogo Spring /*Super Ring*/ { 2, 1, 1, 0, 0, 0, 0, 0 }, // Super Ring /*Kitchen Sink*/ { 0, 0, 0, 0, 0, 0, 0, 0 }, // Kitchen Sink - /*Sneaker x3*/ { 0, 0, 0, 3, 7, 9, 2, 0 }, // Sneaker x3 + /*Sneaker x3*/ { 0, 0, 0, 2, 6,10, 5, 0 }, // Sneaker x3 /*Banana x3*/ { 0, 1, 1, 0, 0, 0, 0, 0 }, // Banana x3 /*Banana x10*/ { 0, 0, 0, 1, 0, 0, 0, 0 }, // Banana x10 /*Orbinaut x3*/ { 0, 0, 1, 0, 0, 0, 0, 0 }, // Orbinaut x3 @@ -671,7 +704,7 @@ static INT32 K_KartItemOddsRace[NUMKARTRESULTS][8] = /*Jawz x2*/ { 0, 0, 1, 2, 0, 0, 0, 0 } // Jawz x2 }; -static INT32 K_KartItemOddsBattle[NUMKARTRESULTS][6] = +static INT32 K_KartItemOddsBattle[NUMKARTRESULTS-1][6] = { //P-Odds 0 1 2 3 4 5 /*Sneaker*/ { 3, 2, 2, 2, 0, 2 }, // Sneaker @@ -687,6 +720,8 @@ static INT32 K_KartItemOddsBattle[NUMKARTRESULTS][6] = /*Grow*/ { 0, 0, 1, 2, 4, 2 }, // Grow /*Shrink*/ { 0, 0, 0, 0, 0, 0 }, // Shrink /*Thunder Shield*/ { 0, 0, 0, 0, 0, 0 }, // Thunder Shield + /*Bubble Shield*/ { 0, 0, 0, 0, 0, 0 }, // Bubble Shield + /*Flame Shield*/ { 0, 0, 0, 0, 0, 0 }, // Flame Shield /*Hyudoro*/ { 1, 1, 0, 0, 0, 0 }, // Hyudoro /*Pogo Spring*/ { 1, 1, 0, 0, 0, 0 }, // Pogo Spring /*Super Ring*/ { 0, 0, 0, 0, 0, 0 }, // Super Ring @@ -701,6 +736,17 @@ static INT32 K_KartItemOddsBattle[NUMKARTRESULTS][6] = #define DISTVAR (2048) // Magic number distance for use with item roulette tiers +INT32 K_GetShieldFromItem(INT32 item) +{ + switch (item) + { + case KITEM_THUNDERSHIELD: return KSHIELD_THUNDER; + case KITEM_BUBBLESHIELD: return KSHIELD_BUBBLE; + case KITEM_FLAMESHIELD: return KSHIELD_FLAME; + default: return KSHIELD_NONE; + } +} + /** \brief Item Roulette for Kart \param player player @@ -768,48 +814,32 @@ static INT32 K_KartGetItemOdds(UINT8 pos, SINT8 item, fixed_t mashed, boolean sp INT32 newodds; INT32 i; UINT8 pingame = 0, pexiting = 0; - boolean thunderisout = false; SINT8 first = -1, second = -1; INT32 secondist = 0; - boolean itemenabled[NUMKARTRESULTS-1] = { - cv_sneaker.value, - cv_rocketsneaker.value, - cv_invincibility.value, - cv_banana.value, - cv_eggmanmonitor.value, - cv_orbinaut.value, - cv_jawz.value, - cv_mine.value, - cv_ballhog.value, - cv_selfpropelledbomb.value, - cv_grow.value, - cv_shrink.value, - cv_thundershield.value, - cv_hyudoro.value, - cv_pogospring.value, - cv_superring.value, - cv_kitchensink.value, - cv_triplesneaker.value, - cv_triplebanana.value, - cv_decabanana.value, - cv_tripleorbinaut.value, - cv_quadorbinaut.value, - cv_dualjawz.value - }; + INT32 shieldtype = KSHIELD_NONE; I_Assert(item > KITEM_NONE); // too many off by one scenarioes. + I_Assert(KartItemCVars[NUMKARTRESULTS-2] != NULL); // Make sure this exists - if (!itemenabled[item-1] && !modeattacking) + if (!KartItemCVars[item-1]->value && !modeattacking) return 0; if (G_BattleGametype()) + { + I_Assert(pos < 6); // DO NOT allow positions past the bounds of the table newodds = K_KartItemOddsBattle[item-1][pos]; + } else + { + I_Assert(pos < 8); // Ditto newodds = K_KartItemOddsRace[item-1][pos]; + } // Base multiplication to ALL item odds to simulate fractional precision newodds *= 4; + shieldtype = K_GetShieldFromItem(item); + for (i = 0; i < MAXPLAYERS; i++) { if (!playeringame[i] || players[i].spectator) @@ -821,18 +851,18 @@ static INT32 K_KartGetItemOdds(UINT8 pos, SINT8 item, fixed_t mashed, boolean sp if (players[i].exiting) pexiting++; - if (players[i].mo) + if (shieldtype != KSHIELD_NONE && shieldtype == K_GetShieldFromItem(players[i].kartstuff[k_itemtype])) { - if (players[i].kartstuff[k_itemtype] == KITEM_THUNDERSHIELD) - thunderisout = true; + // Don't allow more than one of each shield type at a time + return 0; + } - if (!G_BattleGametype()) - { - if (players[i].kartstuff[k_position] == 1 && first == -1) - first = i; - if (players[i].kartstuff[k_position] == 2 && second == -1) - second = i; - } + if (players[i].mo && G_RaceGametype()) + { + if (players[i].kartstuff[k_position] == 1 && first == -1) + first = i; + if (players[i].kartstuff[k_position] == 2 && second == -1) + second = i; } } @@ -881,29 +911,43 @@ static INT32 K_KartGetItemOdds(UINT8 pos, SINT8 item, fixed_t mashed, boolean sp case KITEM_INVINCIBILITY: case KITEM_MINE: case KITEM_GROW: + case KITEM_BUBBLESHIELD: + case KITEM_FLAMESHIELD: if (COOLDOWNONSTART) newodds = 0; else POWERITEMODDS(newodds); break; case KITEM_SPB: - if ((indirectitemcooldown > 0) || (secondist/DISTVAR < 3) - || (first != -1 && players[first].distancetofinish > 8*DISTVAR)) // No SPB near the end of the race + if ((indirectitemcooldown > 0) || COOLDOWNONSTART + || (first != -1 && players[first].distancetofinish < 8*DISTVAR)) // No SPB near the end of the race + { newodds = 0; + } else - newodds *= min((secondist/DISTVAR)-4, 3); // POWERITEMODDS(newodds); + { + INT32 multiplier = (secondist - (5*DISTVAR)) / DISTVAR; + + if (multiplier < 0) + multiplier = 0; + if (multiplier > 3) + multiplier = 3; + + newodds *= multiplier; + } break; case KITEM_SHRINK: - if ((indirectitemcooldown > 0) || (pingame-1 <= pexiting) || COOLDOWNONSTART) + if ((indirectitemcooldown > 0) || COOLDOWNONSTART || (pingame-1 <= pexiting)) newodds = 0; else POWERITEMODDS(newodds); break; case KITEM_THUNDERSHIELD: - if (thunderisout || spbplace != -1) + if (spbplace != -1 || COOLDOWNONSTART) newodds = 0; else POWERITEMODDS(newodds); + break; case KITEM_HYUDORO: if ((hyubgone > 0) || COOLDOWNONSTART) newodds = 0; @@ -1091,7 +1135,7 @@ static void K_KartItemRoulette(player_t *player, ticcmd_t *cmd) } if (mapobjectscale != FRACUNIT) - pdis = FixedDiv(pdis, mapobjectscale); + pdis = FixedDiv(pdis * FRACUNIT, mapobjectscale) / FRACUNIT; if (franticitems) // Frantic items make the distances between everyone artifically higher, for crazier items pdis = (15 * pdis) / 14; @@ -1184,16 +1228,35 @@ static void K_KartItemRoulette(player_t *player, ticcmd_t *cmd) return; } - // SPECIAL CASE No. 4: - // Being in ring debt occasionally forces Super Ring on you if you mashed - if (mashed && player->kartstuff[k_rings] < 0 && cv_superring.value) + if (G_RaceGametype()) { - INT32 debtamount = min(20, abs(player->kartstuff[k_rings])); - if (P_RandomChance((debtamount*FRACUNIT)/20)) + // SPECIAL CASE No. 4: + // Being in ring debt occasionally forces Super Ring on you if you mashed + if (mashed && player->kartstuff[k_rings] < 0 && cv_superring.value) { - K_KartGetItemResult(player, KITEM_SUPERRING); + INT32 debtamount = min(20, abs(player->kartstuff[k_rings])); + if (P_RandomChance((debtamount*FRACUNIT)/20)) + { + K_KartGetItemResult(player, KITEM_SUPERRING); + player->karthud[khud_itemblink] = TICRATE; + player->karthud[khud_itemblinkmode] = 1; + player->kartstuff[k_itemroulette] = 0; + player->kartstuff[k_roulettetype] = 0; + if (P_IsDisplayPlayer(player)) + S_StartSound(NULL, (mashed ? sfx_itrolm : sfx_itrolf)); + return; + } + } + + // SPECIAL CASE No. 5: + // Force SPB onto 2nd if they get too far behind + if (player->kartstuff[k_position] == 2 && pdis > (DISTVAR*8) + && spbplace == -1 && !indirectitemcooldown && !dontforcespb + && cv_selfpropelledbomb.value) + { + K_KartGetItemResult(player, KITEM_SPB); player->karthud[khud_itemblink] = TICRATE; - player->karthud[khud_itemblinkmode] = 1; + player->karthud[khud_itemblinkmode] = (mashed ? 1 : 0); player->kartstuff[k_itemroulette] = 0; player->kartstuff[k_roulettetype] = 0; if (P_IsDisplayPlayer(player)) @@ -1202,22 +1265,6 @@ static void K_KartItemRoulette(player_t *player, ticcmd_t *cmd) } } - // SPECIAL CASE No. 5: - // Force SPB onto 2nd if they get too far behind - if (player->kartstuff[k_position] == 2 && pdis > (DISTVAR*6) - && spbplace == -1 && !indirectitemcooldown && !dontforcespb - && cv_selfpropelledbomb.value) - { - K_KartGetItemResult(player, KITEM_SPB); - player->karthud[khud_itemblink] = TICRATE; - player->karthud[khud_itemblinkmode] = (mashed ? 1 : 0); - player->kartstuff[k_itemroulette] = 0; - player->kartstuff[k_roulettetype] = 0; - if (P_IsDisplayPlayer(player)) - S_StartSound(NULL, (mashed ? sfx_itrolm : sfx_itrolf)); - return; - } - // NOW that we're done with all of those specialized cases, we can move onto the REAL item roulette tables. // Initializes existing spawnchance values for (i = 0; i < NUMKARTRESULTS; i++) @@ -1257,52 +1304,72 @@ static void K_KartItemRoulette(player_t *player, ticcmd_t *cmd) //{ SRB2kart p_user.c Stuff +static fixed_t K_PlayerWeight(mobj_t *mobj, mobj_t *against) +{ + fixed_t weight = 5*FRACUNIT; + + if (!mobj->player) + return weight; + + if (against && !P_MobjWasRemoved(against) && against->player + && ((!against->player->kartstuff[k_spinouttimer] && mobj->player->kartstuff[k_spinouttimer]) // You're in spinout + || (against->player->kartstuff[k_itemtype] == KITEM_BUBBLESHIELD && mobj->player->kartstuff[k_itemtype] != KITEM_BUBBLESHIELD))) // They have a Bubble Shield + { + weight = 0; // This player does not cause any bump action + } + else + { + weight = (mobj->player->kartweight) * FRACUNIT; + if (mobj->player->speed > K_GetKartSpeed(mobj->player, false)) + weight += (mobj->player->speed - K_GetKartSpeed(mobj->player, false))/8; + if (mobj->player->kartstuff[k_itemtype] == KITEM_BUBBLESHIELD) + weight += 9*FRACUNIT; + } + + return weight; +} + static fixed_t K_GetMobjWeight(mobj_t *mobj, mobj_t *against) { - fixed_t weight = 5<type) { case MT_PLAYER: if (!mobj->player) break; - if (against->player && !against->player->kartstuff[k_spinouttimer] && mobj->player->kartstuff[k_spinouttimer]) - weight = 0; // Do not bump - else - { - weight = (mobj->player->kartweight)<player->speed > K_GetKartSpeed(mobj->player, false)) - weight += (mobj->player->speed - K_GetKartSpeed(mobj->player, false))/8; - } + weight = K_PlayerWeight(mobj, against); + break; + case MT_BUBBLESHIELD: + weight = K_PlayerWeight(mobj->target, against); break; case MT_FALLINGROCK: if (against->player) { - if (against->player->kartstuff[k_invincibilitytimer] - || against->player->kartstuff[k_growshrinktimer] > 0) + if (against->player->kartstuff[k_invincibilitytimer] || against->player->kartstuff[k_growshrinktimer] > 0) weight = 0; else - weight = (against->player->kartweight)<player) - weight = (against->player->kartweight)<player) - weight = (against->player->kartweight+3)<scale); } // This kind of wipeout happens with no rings -- doesn't remove a bumper, has no invulnerability, and is much shorter. @@ -1465,7 +1532,10 @@ void K_KartBouncing(mobj_t *mobj1, mobj_t *mobj2, boolean bounce, boolean solid) } // Do the bump fx when we've CONFIRMED we can bump. - S_StartSound(mobj1, sfx_s3k49); + if ((mobj1->player && mobj1->player->kartstuff[k_itemtype] == KITEM_BUBBLESHIELD) || (mobj2->player && mobj2->player->kartstuff[k_itemtype] == KITEM_BUBBLESHIELD)) + S_StartSound(mobj1, sfx_s3k44); + else + S_StartSound(mobj1, sfx_s3k49); fx = P_SpawnMobj(mobj1->x/2 + mobj2->x/2, mobj1->y/2 + mobj2->y/2, mobj1->z/2 + mobj2->z/2, MT_BUMP); if (mobj1->eflags & MFE_VERTICALFLIP) @@ -1489,7 +1559,8 @@ void K_KartBouncing(mobj_t *mobj1, mobj_t *mobj2, boolean bounce, boolean solid) mobj1->player->kartstuff[k_spinouttimer] = max(wipeoutslowtime+1, mobj1->player->kartstuff[k_spinouttimer]); //mobj1->player->kartstuff[k_spinouttype] = 1; // Enforce type } - else if (mobj2->player) // Player VS player bumping only + else if (mobj2->player // Player VS player bumping only + && (K_GetShieldFromItem(mobj1->player->kartstuff[k_itemtype]) == KSHIELD_NONE)) // Ignore for shields { if (mobj1->player->kartstuff[k_rings] <= 0) { @@ -1513,7 +1584,8 @@ void K_KartBouncing(mobj_t *mobj1, mobj_t *mobj2, boolean bounce, boolean solid) mobj2->player->kartstuff[k_spinouttimer] = max(wipeoutslowtime+1, mobj2->player->kartstuff[k_spinouttimer]); //mobj2->player->kartstuff[k_spinouttype] = 1; // Enforce type } - else if (mobj1->player) // Player VS player bumping only + else if (mobj1->player // Player VS player bumping only + && (K_GetShieldFromItem(mobj2->player->kartstuff[k_itemtype]) == KSHIELD_NONE)) // Ignore for shields { if (mobj2->player->kartstuff[k_rings] <= 0) { @@ -1587,11 +1659,16 @@ static void K_DrawDraftCombiring(player_t *player, player_t *victim, fixed_t cur SKINCOLOR_TAFFY }; fixed_t minimumdist = FixedMul(RING_DIST>>1, player->mo->scale); - UINT8 c = FixedMul(CHAOTIXBANDCOLORS<> FRACBITS; UINT8 n = CHAOTIXBANDLEN; UINT8 offset = ((leveltime / 3) % 3); fixed_t stepx, stepy, stepz; fixed_t curx, cury, curz; + UINT8 c; + + if (maxdist == 0) + c = 0; + else + c = FixedMul(CHAOTIXBANDCOLORS<> FRACBITS; stepx = (victim->mo->x - player->mo->x) / CHAOTIXBANDLEN; stepy = (victim->mo->y - player->mo->y) / CHAOTIXBANDLEN; @@ -1643,13 +1720,21 @@ static void K_UpdateDraft(player_t *player) UINT8 leniency; UINT8 i; - // Distance you have to be to draft. If you're still accelerating, then this distance is lessened. - // This distance biases toward low weight! (min weight gets 4096 units, max weight gets 3072 units) - // This distance is also scaled based on game speed. - draftdistance = (3072 + (128 * (9 - player->kartweight))) * player->mo->scale; - if (player->speed < topspd) - draftdistance = FixedMul(draftdistance, FixedDiv(player->speed, topspd)); - draftdistance = FixedMul(draftdistance, K_GetKartGameSpeedScalar(gamespeed)); + if (player->kartstuff[k_itemtype] == KITEM_FLAMESHIELD) + { + // Flame Shield gets infinite draft distance as its passive effect. + draftdistance = 0; + } + else + { + // Distance you have to be to draft. If you're still accelerating, then this distance is lessened. + // This distance biases toward low weight! (min weight gets 4096 units, max weight gets 3072 units) + // This distance is also scaled based on game speed. + draftdistance = (3072 + (128 * (9 - player->kartweight))) * player->mo->scale; + if (player->speed < topspd) + draftdistance = FixedMul(draftdistance, FixedDiv(player->speed, topspd)); + draftdistance = FixedMul(draftdistance, K_GetKartGameSpeedScalar(gamespeed)); + } // On the contrary, the leniency period biases toward high weight. // (See also: the leniency variable in K_SpawnDraftDust) @@ -1709,7 +1794,7 @@ static void K_UpdateDraft(player_t *player) continue; // Not close enough to draft. - if (dist > draftdistance) + if (dist > draftdistance && draftdistance > 0) continue; #endif @@ -2463,6 +2548,12 @@ static void K_GetKartBoostPower(player_t *player) if (player->kartstuff[k_invincibilitytimer]) // Invincibility ADDBOOST((3*FRACUNIT)/8, 3*FRACUNIT); // + 37.5% top speed, + 300% acceleration + if (player->kartstuff[k_flamedash]) // Flame Shield dash + { + fixed_t dashval = ((player->kartstuff[k_flamedash]<kartstuff[k_startboost]) // Startup Boost ADDBOOST(FRACUNIT/4, 6*FRACUNIT); // + 25% top speed, + 600% acceleration @@ -2472,13 +2563,8 @@ static void K_GetKartBoostPower(player_t *player) if (player->kartstuff[k_ringboost]) // Ring Boost ADDBOOST(FRACUNIT/5, 4*FRACUNIT); // + 20% top speed, + 400% acceleration - if (player->kartstuff[k_growshrinktimer] > 0) // Grow - { - // Grow's design is weird with booster stacking. - // We'll see how to replace its design BEFORE v2 gets released. - speedboost += (FRACUNIT/5); // + 20% - //numboosts++; // Don't add any boost afterimages to Grow - } + if (player->kartstuff[k_eggmanexplode]) // Ready-to-explode + ADDBOOST(FRACUNIT/5, FRACUNIT); // + 20% top speed, + 100% acceleration if (player->kartstuff[k_draftpower] > 0) // Drafting { @@ -2765,7 +2851,6 @@ static void K_RemoveGrowShrink(player_t *player) } player->kartstuff[k_growshrinktimer] = 0; - player->kartstuff[k_growcancel] = -1; P_RestoreMusic(player); } @@ -3290,7 +3375,6 @@ static mobj_t *K_SpawnKartMissile(mobj_t *source, mobjtype_t type, angle_t an, I th = P_SpawnMobj(x, y, z, type); th->flags2 |= flags2; - th->threshold = 10; if (th->info->seesound) @@ -3298,6 +3382,9 @@ static mobj_t *K_SpawnKartMissile(mobj_t *source, mobjtype_t type, angle_t an, I P_SetTarget(&th->target, source); + P_SetScale(th, source->scale); + th->destscale = source->destscale; + if (P_IsObjectOnGround(source)) { // floorz and ceilingz aren't properly set to account for FOFs and Polyobjects on spawn @@ -3348,16 +3435,25 @@ static mobj_t *K_SpawnKartMissile(mobj_t *source, mobjtype_t type, angle_t an, I case MT_SPB: th->movefactor = finalspeed; break; + case MT_BUBBLESHIELDTRAP: + P_SetScale(th, ((5*th->destscale)>>2)*4); + th->destscale = (5*th->destscale)>>2; + S_StartSound(th, sfx_s3kbfl); + S_StartSound(th, sfx_cdfm35); + break; default: break; } - x = x + P_ReturnThrustX(source, an, source->radius + th->radius); - y = y + P_ReturnThrustY(source, an, source->radius + th->radius); - throwmo = P_SpawnMobj(x, y, z, MT_FIREDITEM); - throwmo->movecount = 1; - throwmo->movedir = source->angle - an; - P_SetTarget(&throwmo->target, source); + if (type != MT_BUBBLESHIELDTRAP) + { + x = x + P_ReturnThrustX(source, an, source->radius + th->radius); + y = y + P_ReturnThrustY(source, an, source->radius + th->radius); + throwmo = P_SpawnMobj(x, y, z, MT_FIREDITEM); + throwmo->movecount = 1; + throwmo->movedir = source->angle - an; + P_SetTarget(&throwmo->target, source); + } return NULL; } @@ -4057,8 +4153,16 @@ static mobj_t *K_ThrowKartItem(player_t *player, boolean missile, mobjtype_t map { mobj_t *lasttrail = K_FindLastTrailMobj(player); - if (lasttrail) + if (mapthing == MT_BUBBLESHIELDTRAP) // Drop directly on top of you. { + newangle = player->mo->angle; + newx = player->mo->x + player->mo->momx; + newy = player->mo->y + player->mo->momy; + newz = player->mo->z; + } + else if (lasttrail) + { + newangle = lasttrail->angle; newx = lasttrail->x; newy = lasttrail->y; newz = lasttrail->z; @@ -4081,6 +4185,9 @@ static mobj_t *K_ThrowKartItem(player_t *player, boolean missile, mobjtype_t map mo->threshold = 10; P_SetTarget(&mo->target, player->mo); + P_SetScale(mo, player->mo->scale); + mo->destscale = player->mo->destscale; + if (P_IsObjectOnGround(player->mo)) { // floorz and ceilingz aren't properly set to account for FOFs and Polyobjects on spawn @@ -4110,6 +4217,12 @@ static mobj_t *K_ThrowKartItem(player_t *player, boolean missile, mobjtype_t map if (mapthing == MT_SSMINE) mo->extravalue1 = 49; // Pads the start-up length from 21 frames to a full 2 seconds + else if (mapthing == MT_BUBBLESHIELDTRAP) + { + P_SetScale(mo, ((5*mo->destscale)>>2)*4); + mo->destscale = (5*mo->destscale)>>2; + S_StartSound(mo, sfx_s3kbfl); + } } } @@ -4169,7 +4282,6 @@ static void K_DoThunderShield(player_t *player) angle_t an; S_StartSound(player->mo, sfx_zio3); - //player->kartstuff[k_thunderanim] = 35; P_NukeEnemies(player->mo, player->mo, RING_DIST/4); // spawn vertical bolt @@ -4212,6 +4324,27 @@ static void K_DoThunderShield(player_t *player) #undef THUNDERRADIUS +static void K_FlameDashLeftoverSmoke(mobj_t *src) +{ + UINT8 i; + + for (i = 0; i < 2; i++) + { + mobj_t *smoke = P_SpawnMobj(src->x, src->y, src->z+(8<scale); + smoke->destscale = 3*src->scale/2; + smoke->scalespeed = src->scale/12; + + smoke->momx = 3*src->momx/4; + smoke->momy = 3*src->momy/4; + smoke->momz = 3*src->momz/4; + + P_Thrust(smoke, src->angle + FixedAngle(P_RandomRange(135, 225)<scale); + smoke->momz += P_RandomRange(0, 4) * src->scale; + } +} + static void K_DoHyudoroSteal(player_t *player) { INT32 i, numplayers = 0; @@ -4219,6 +4352,10 @@ static void K_DoHyudoroSteal(player_t *player) INT32 stealplayer = -1; // The player that's getting stolen from INT32 prandom = 0; boolean sink = P_RandomChance(FRACUNIT/64); + INT32 hyu = hyudorotime; + + if (G_RaceGametype()) + hyu *= 2; // double in race for (i = 0; i < MAXPLAYERS; i++) { @@ -4245,7 +4382,7 @@ static void K_DoHyudoroSteal(player_t *player) if (sink && numplayers > 0 && cv_kitchensink.value) // BEHOLD THE KITCHEN SINK { - player->kartstuff[k_hyudorotimer] = hyudorotime; + player->kartstuff[k_hyudorotimer] = hyu; player->kartstuff[k_stealingtimer] = stealtime; player->kartstuff[k_itemtype] = KITEM_KITCHENSINK; @@ -4255,7 +4392,7 @@ static void K_DoHyudoroSteal(player_t *player) } else if ((G_RaceGametype() && player->kartstuff[k_position] == 1) || numplayers == 0) // No-one can be stolen from? Oh well... { - player->kartstuff[k_hyudorotimer] = hyudorotime; + player->kartstuff[k_hyudorotimer] = hyu; player->kartstuff[k_stealingtimer] = stealtime; return; } @@ -4270,7 +4407,7 @@ static void K_DoHyudoroSteal(player_t *player) if (stealplayer > -1) // Now here's where we do the stealing, has to be done here because we still know the player we're stealing from { - player->kartstuff[k_hyudorotimer] = hyudorotime; + player->kartstuff[k_hyudorotimer] = hyu; player->kartstuff[k_stealingtimer] = stealtime; players[stealplayer].kartstuff[k_stolentimer] = stealtime; @@ -4530,12 +4667,24 @@ void K_DropHnextList(player_t *player) flip = P_MobjFlip(player->mo); ponground = P_IsObjectOnGround(player->mo); - if (player->kartstuff[k_itemtype] == KITEM_THUNDERSHIELD && player->kartstuff[k_itemamount]) + if (player->kartstuff[k_itemtype] == KITEM_THUNDERSHIELD) { K_DoThunderShield(player); - player->kartstuff[k_itemamount] = 0; player->kartstuff[k_itemtype] = KITEM_NONE; - player->kartstuff[k_curshield] = 0; + player->kartstuff[k_itemamount] = 0; + player->kartstuff[k_curshield] = KSHIELD_NONE; + } + else if (player->kartstuff[k_itemtype] == KITEM_BUBBLESHIELD) + { + player->kartstuff[k_itemtype] = KITEM_NONE; + player->kartstuff[k_itemamount] = 0; + player->kartstuff[k_curshield] = KSHIELD_NONE; + } + else if (player->kartstuff[k_itemtype] == KITEM_FLAMESHIELD) + { + player->kartstuff[k_itemtype] = KITEM_NONE; + player->kartstuff[k_itemamount] = 0; + player->kartstuff[k_curshield] = KSHIELD_NONE; } nextwork = work->hnext; @@ -4657,9 +4806,12 @@ void K_DropHnextList(player_t *player) // For getting EXTRA hit! void K_DropItems(player_t *player) { - boolean thunderhack = (player->kartstuff[k_curshield] && player->kartstuff[k_itemtype] == KITEM_THUNDERSHIELD); + INT32 shieldhack = 0; - if (thunderhack) + if (player->kartstuff[k_curshield]) + shieldhack = K_GetShieldFromItem(player->kartstuff[k_itemtype]); + + if (shieldhack) player->kartstuff[k_itemtype] = KITEM_NONE; K_DropHnextList(player); @@ -4678,7 +4830,13 @@ void K_DropItems(player_t *player) if (drop->eflags & MFE_UNDERWATER) drop->momz = (117 * drop->momz) / 200; - drop->threshold = (thunderhack ? KITEM_THUNDERSHIELD : player->kartstuff[k_itemtype]); + switch (shieldhack) + { + case KSHIELD_THUNDER: drop->threshold = KITEM_THUNDERSHIELD; break; + case KSHIELD_BUBBLE: drop->threshold = KITEM_BUBBLESHIELD; break; + case KSHIELD_FLAME: drop->threshold = KITEM_FLAMESHIELD; break; + default: drop->threshold = player->kartstuff[k_itemtype]; break; + } drop->movecount = player->kartstuff[k_itemamount]; drop->flags |= MF_NOCLIPTHING; @@ -5382,17 +5540,17 @@ static void K_UpdateInvincibilitySounds(player_t *player) { if (cv_kartinvinsfx.value) { - if (player->kartstuff[k_growshrinktimer] > 0) // Prioritize Grow - sfxnum = sfx_alarmg; - else if (player->kartstuff[k_invincibilitytimer] > 0) + if (player->kartstuff[k_invincibilitytimer] > 0) // Prioritize invincibility sfxnum = sfx_alarmi; + else if (player->kartstuff[k_growshrinktimer] > 0) + sfxnum = sfx_alarmg; } else { - if (player->kartstuff[k_growshrinktimer] > 0) - sfxnum = sfx_kgrow; - else if (player->kartstuff[k_invincibilitytimer] > 0) + if (player->kartstuff[k_invincibilitytimer] > 0) sfxnum = sfx_kinvnc; + else if (player->kartstuff[k_growshrinktimer] > 0) + sfxnum = sfx_kgrow; } } @@ -5514,6 +5672,68 @@ void K_KartPlayerHUDUpdate(player_t *player) #undef RINGANIM_DELAYMAX +// SRB2Kart: blockmap iterate for attraction shield users +static mobj_t *attractmo; +static fixed_t attractdist; +static inline boolean PIT_AttractingRings(mobj_t *thing) +{ + if (!attractmo || P_MobjWasRemoved(attractmo)) + return false; + + if (!attractmo->player) + return false; // not a player + + if (thing->health <= 0 || !thing) + return true; // dead + + if (thing->type != MT_RING && thing->type != MT_FLINGRING) + return true; // not a ring + + if (thing->extravalue1) + return true; // in special ring animation + + if (thing->cusval) + return true; // already attracted + + // see if it went over / under + if (attractmo->z - (attractdist>>2) > thing->z + thing->height) + return true; // overhead + if (attractmo->z + attractmo->height + (attractdist>>2) < thing->z) + return true; // underneath + + if (P_AproxDistance(attractmo->x - thing->x, attractmo->y - thing->y) < attractdist) + return true; // Too far away + + // set target + P_SetTarget(&thing->tracer, attractmo); + // flag to show it's been attracted once before + thing->cusval = 1; + return true; // find other rings +} + +/** Looks for rings near a player in the blockmap. + * + * \param pmo Player object looking for rings to attract + * \sa A_AttractChase + */ +static void K_LookForRings(mobj_t *pmo) +{ + INT32 bx, by, xl, xh, yl, yh; + attractdist = FixedMul(RING_DIST, pmo->scale)>>2; + + // Use blockmap to check for nearby rings + yh = (unsigned)(pmo->y + attractdist - bmaporgy)>>MAPBLOCKSHIFT; + yl = (unsigned)(pmo->y - attractdist - bmaporgy)>>MAPBLOCKSHIFT; + xh = (unsigned)(pmo->x + attractdist - bmaporgx)>>MAPBLOCKSHIFT; + xl = (unsigned)(pmo->x - attractdist - bmaporgx)>>MAPBLOCKSHIFT; + + attractmo = pmo; + + for (by = yl; by <= yh; by++) + for (bx = xl; bx <= xh; bx++) + P_BlockThingsIterator(bx, by, PIT_AttractingRings); +} + /** \brief Decreases various kart timers and powers per frame. Called in P_PlayerThink in p_user.c \param player player object passed from P_PlayerThink @@ -5551,17 +5771,27 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) { // Speed lines if (EITHERSNEAKER(player) || player->kartstuff[k_ringboost] - || player->kartstuff[k_driftboost] || player->kartstuff[k_startboost]) + || player->kartstuff[k_driftboost] || player->kartstuff[k_startboost] + || player->kartstuff[k_eggmanexplode]) { mobj_t *fast = P_SpawnMobj(player->mo->x + (P_RandomRange(-36,36) * player->mo->scale), player->mo->y + (P_RandomRange(-36,36) * player->mo->scale), player->mo->z + (player->mo->height/2) + (P_RandomRange(-20,20) * player->mo->scale), MT_FASTLINE); + fast->angle = R_PointToAngle2(0, 0, player->mo->momx, player->mo->momy); fast->momx = 3*player->mo->momx/4; fast->momy = 3*player->mo->momy/4; fast->momz = 3*player->mo->momz/4; + K_MatchGenericExtraFlags(fast, player->mo); + + // Make it red when you have the eggman speed boost + if (player->kartstuff[k_eggmanexplode]) + { + fast->color = SKINCOLOR_RED; + fast->colorized = true; + } } if (player->kartstuff[k_numboosts] > 0) // Boosting after images @@ -5710,6 +5940,9 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) player->mo->colorized = false; } + if (player->kartstuff[k_itemtype] == KITEM_NONE) + player->kartstuff[k_holdready] = 0; + // DKR style camera for boosting if (player->karthud[khud_boostcam] != 0 || player->karthud[khud_destboostcam] != 0) { @@ -5796,6 +6029,9 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) if (player->kartstuff[k_levelbooster]) player->kartstuff[k_levelbooster]--; + if (player->kartstuff[k_flamedash]) + player->kartstuff[k_flamedash]--; + if (EITHERSNEAKER(player) && player->kartstuff[k_wipeoutslow] > 0 && player->kartstuff[k_wipeoutslow] < wipeoutslowtime+1) player->kartstuff[k_wipeoutslow] = wipeoutslowtime+1; @@ -5930,6 +6166,29 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) } } + if (player->kartstuff[k_itemtype] == KITEM_THUNDERSHIELD) + { + if (RINGTOTAL(player) < 20 && !player->kartstuff[k_ringlock]) + K_LookForRings(player->mo); + } + + if (player->kartstuff[k_itemtype] == KITEM_BUBBLESHIELD) + { + if (player->kartstuff[k_bubblecool]) + player->kartstuff[k_bubblecool]--; + } + else + { + player->kartstuff[k_bubbleblowup] = 0; + player->kartstuff[k_bubblecool] = 0; + } + + if (player->kartstuff[k_itemtype] != KITEM_FLAMESHIELD || player->exiting) + { + if (player->kartstuff[k_flamedash]) + K_FlameDashLeftoverSmoke(player->mo); + } + if (player->kartstuff[k_comebacktimer]) player->kartstuff[k_comebackmode] = 0; @@ -6443,7 +6702,7 @@ INT16 K_GetKartTurnValue(player_t *player, INT16 turnvalue) turnvalue = FixedMul(turnvalue, adjustangle); // Weight has a small effect on turning if (EITHERSNEAKER(player) || player->kartstuff[k_invincibilitytimer] || player->kartstuff[k_growshrinktimer] > 0) - turnvalue = FixedMul(turnvalue, FixedDiv(5*FRACUNIT, 4*FRACUNIT)); + turnvalue = FixedMul(turnvalue, (5*FRACUNIT)/4); return turnvalue; } @@ -6783,8 +7042,7 @@ void K_StripItems(player_t *player) player->kartstuff[k_stealingtimer] = 0; player->kartstuff[k_stolentimer] = 0; - player->kartstuff[k_curshield] = 0; - //player->kartstuff[k_thunderanim] = 0; + player->kartstuff[k_curshield] = KSHIELD_NONE; player->kartstuff[k_bananadrag] = 0; player->kartstuff[k_sadtimer] = 0; @@ -6807,66 +7065,32 @@ void K_StripOther(player_t *player) } } -// SRB2Kart: blockmap iterate for attraction shield users -static mobj_t *attractmo; -static fixed_t attractdist; -static inline boolean PIT_AttractingRings(mobj_t *thing) +static INT32 K_FlameShieldMax(player_t *player) { - if (!attractmo || P_MobjWasRemoved(attractmo)) - return false; + UINT32 disttofinish = 0; + UINT8 numplayers = 0; + UINT8 i; - if (!attractmo->player) - return false; // not a player + for (i = 0; i < MAXPLAYERS; i++) + { + if (playeringame[i] && !players[i].spectator) + numplayers++; + if (players[i].kartstuff[k_position] == 1) + disttofinish = players[i].distancetofinish; + } - if (thing->health <= 0 || !thing) - return true; // dead + if (numplayers <= 1) + { + return 16; // max when alone, for testing + } + else if (player->kartstuff[k_position] == 1) + { + return 0; // minimum for first + } - if (thing->type != MT_RING && thing->type != MT_FLINGRING) - return true; // not a ring + disttofinish = player->distancetofinish - disttofinish; - if (thing->extravalue1) - return true; // in special ring animation - - if (thing->cusval) - return true; // already attracted - - // see if it went over / under - if (attractmo->z - (attractdist>>2) > thing->z + thing->height) - return true; // overhead - if (attractmo->z + attractmo->height + (attractdist>>2) < thing->z) - return true; // underneath - - if (P_AproxDistance(attractmo->x - thing->x, attractmo->y - thing->y) < attractdist) - return true; // Too far away - - // set target - P_SetTarget(&thing->tracer, attractmo); - // flag to show it's been attracted once before - thing->cusval = 1; - return true; // find other rings -} - -/** Looks for rings near a player in the blockmap. - * - * \param pmo Player object looking for rings to attract - * \sa A_AttractChase - */ -static void K_LookForRings(mobj_t *pmo) -{ - INT32 bx, by, xl, xh, yl, yh; - attractdist = FixedMul(RING_DIST, pmo->scale)>>2; - - // Use blockmap to check for nearby rings - yh = (unsigned)(pmo->y + attractdist - bmaporgy)>>MAPBLOCKSHIFT; - yl = (unsigned)(pmo->y - attractdist - bmaporgy)>>MAPBLOCKSHIFT; - xh = (unsigned)(pmo->x + attractdist - bmaporgx)>>MAPBLOCKSHIFT; - xl = (unsigned)(pmo->x - attractdist - bmaporgx)>>MAPBLOCKSHIFT; - - attractmo = pmo; - - for (by = yl; by <= yh; by++) - for (bx = xl; bx <= xh; bx++) - P_BlockThingsIterator(bx, by, PIT_AttractingRings); + return min(16, 1 + (disttofinish / DISTVAR)); } // @@ -6906,7 +7130,6 @@ void K_MoveKartPlayer(player_t *player, boolean onground) && NO_HYUDORO && !(HOLDING_ITEM || player->kartstuff[k_itemamount] || player->kartstuff[k_itemroulette] - || player->kartstuff[k_growshrinktimer] > 0 || player->kartstuff[k_rocketsneakertimer] || player->kartstuff[k_eggmanexplode])) player->kartstuff[k_userings] = 1; @@ -7004,28 +7227,6 @@ void K_MoveKartPlayer(player_t *player, boolean onground) player->kartstuff[k_rocketsneakertimer] = 1; } } - // Grow Canceling - else if (player->kartstuff[k_growshrinktimer] > 0) - { - if (player->kartstuff[k_growcancel] >= 0) - { - if (cmd->buttons & BT_ATTACK) - { - player->kartstuff[k_growcancel]++; - if (player->kartstuff[k_growcancel] > 26) - K_RemoveGrowShrink(player); - } - else - player->kartstuff[k_growcancel] = 0; - } - else - { - if ((cmd->buttons & BT_ATTACK) || (player->pflags & PF_ATTACKDOWN)) - player->kartstuff[k_growcancel] = -1; - else - player->kartstuff[k_growcancel] = 0; - } - } else if (player->kartstuff[k_itemamount] <= 0) { player->kartstuff[k_itemamount] = player->kartstuff[k_itemheld] = 0; @@ -7277,8 +7478,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground) } break; case KITEM_GROW: - if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO - && player->kartstuff[k_growshrinktimer] <= 0) // Grow holds the item box hostage + if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO) { if (player->kartstuff[k_growshrinktimer] < 0) // If you're shrunk, then "grow" will just make you normal again. K_RemoveGrowShrink(player); @@ -7307,14 +7507,15 @@ void K_MoveKartPlayer(player_t *player, boolean onground) } break; case KITEM_THUNDERSHIELD: - if (player->kartstuff[k_curshield] != 1) + if (player->kartstuff[k_curshield] != KSHIELD_THUNDER) { mobj_t *shield = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_THUNDERSHIELD); P_SetScale(shield, (shield->destscale = (5*shield->destscale)>>2)); P_SetTarget(&shield->target, player->mo); - S_StartSound(shield, sfx_s3k41); - player->kartstuff[k_curshield] = 1; + S_StartSound(player->mo, sfx_s3k41); + player->kartstuff[k_curshield] = KSHIELD_THUNDER; } + if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO) { K_DoThunderShield(player); @@ -7322,6 +7523,126 @@ void K_MoveKartPlayer(player_t *player, boolean onground) K_PlayAttackTaunt(player->mo); } break; + case KITEM_BUBBLESHIELD: + if (player->kartstuff[k_curshield] != KSHIELD_BUBBLE) + { + mobj_t *shield = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_BUBBLESHIELD); + P_SetScale(shield, (shield->destscale = (5*shield->destscale)>>2)); + P_SetTarget(&shield->target, player->mo); + S_StartSound(player->mo, sfx_s3k3f); + player->kartstuff[k_curshield] = KSHIELD_BUBBLE; + } + + if (!HOLDING_ITEM && NO_HYUDORO) + { + if ((cmd->buttons & BT_ATTACK) && player->kartstuff[k_holdready]) + { + if (player->kartstuff[k_bubbleblowup] == 0) + S_StartSound(player->mo, sfx_s3k75); + + player->kartstuff[k_bubbleblowup]++; + player->kartstuff[k_bubblecool] = player->kartstuff[k_bubbleblowup]*4; + + if (player->kartstuff[k_bubbleblowup] > bubbletime*2) + { + K_ThrowKartItem(player, (player->kartstuff[k_throwdir] > 0), MT_BUBBLESHIELDTRAP, -1, 0); + K_PlayAttackTaunt(player->mo); + player->kartstuff[k_bubbleblowup] = 0; + player->kartstuff[k_bubblecool] = 0; + player->kartstuff[k_holdready] = 0; + player->kartstuff[k_itemamount]--; + } + } + else + { + if (player->kartstuff[k_bubbleblowup] > bubbletime) + player->kartstuff[k_bubbleblowup] = bubbletime; + + if (player->kartstuff[k_bubbleblowup]) + player->kartstuff[k_bubbleblowup]--; + + player->kartstuff[k_holdready] = (player->kartstuff[k_bubblecool] ? 0 : 1); + } + } + break; + case KITEM_FLAMESHIELD: + if (player->kartstuff[k_curshield] != KSHIELD_FLAME) + { + mobj_t *shield = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_FLAMESHIELD); + P_SetScale(shield, (shield->destscale = (5*shield->destscale)>>2)); + P_SetTarget(&shield->target, player->mo); + S_StartSound(player->mo, sfx_s3k3e); + player->kartstuff[k_curshield] = KSHIELD_FLAME; + } + + if (!HOLDING_ITEM && NO_HYUDORO) + { + INT32 destlen = K_FlameShieldMax(player); + INT32 flamemax = 0; + + if (player->kartstuff[k_flamelength] < destlen) + player->kartstuff[k_flamelength]++; // Can always go up! + + flamemax = player->kartstuff[k_flamelength] * flameseg; + if (flamemax > 0) + flamemax += TICRATE; // leniency period + + if ((cmd->buttons & BT_ATTACK) && player->kartstuff[k_holdready]) + { + if (player->kartstuff[k_flamemeter] < 0) + player->kartstuff[k_flamemeter] = 0; + + if (player->kartstuff[k_flamedash] == 0) + { + S_StartSound(player->mo, sfx_s3k43); + K_PlayBoostTaunt(player->mo); + } + + player->kartstuff[k_flamedash] += 2; + player->kartstuff[k_flamemeter] += 2; + + if (!onground) + { + P_Thrust( + player->mo, R_PointToAngle2(0, 0, player->mo->momx, player->mo->momy), + FixedMul(player->mo->scale, K_GetKartGameSpeedScalar(gamespeed)) + ); + } + + if (player->kartstuff[k_flamemeter] > flamemax) + { + P_Thrust( + player->mo, player->mo->angle, + FixedMul((50*player->mo->scale), K_GetKartGameSpeedScalar(gamespeed)) + ); + + player->kartstuff[k_flamemeter] = 0; + player->kartstuff[k_flamelength] = 0; + player->kartstuff[k_holdready] = 0; + player->kartstuff[k_itemamount]--; + } + } + else + { + player->kartstuff[k_holdready] = 1; + + if (player->kartstuff[k_flamemeter] > 0) + player->kartstuff[k_flamemeter]--; + + if (player->kartstuff[k_flamelength] > destlen) + { + player->kartstuff[k_flamelength]--; // Can ONLY go down if you're not using it + + flamemax = player->kartstuff[k_flamelength] * flameseg; + if (flamemax > 0) + flamemax += TICRATE; // leniency period + } + + if (player->kartstuff[k_flamemeter] > flamemax) + player->kartstuff[k_flamemeter] = flamemax; + } + } + break; case KITEM_HYUDORO: if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO) { @@ -7394,20 +7715,18 @@ void K_MoveKartPlayer(player_t *player, boolean onground) player->kartstuff[k_itemtype] = KITEM_NONE; } + if (K_GetShieldFromItem(player->kartstuff[k_itemtype]) == KSHIELD_NONE) + { + player->kartstuff[k_curshield] = KSHIELD_NONE; // RESET shield type + player->kartstuff[k_bubbleblowup] = 0; + player->kartstuff[k_bubblecool] = 0; + player->kartstuff[k_flamelength] = 0; + player->kartstuff[k_flamemeter] = 0; + } + if (spbplace == -1 || player->kartstuff[k_position] != spbplace) player->kartstuff[k_ringlock] = 0; // reset ring lock - if (player->kartstuff[k_itemtype] == KITEM_THUNDERSHIELD) - { - if ((player->kartstuff[k_rings]+player->kartstuff[k_pickuprings]) < 20 && !player->kartstuff[k_ringlock]) - K_LookForRings(player->mo); - } - else - player->kartstuff[k_curshield] = 0; - - if (player->kartstuff[k_growshrinktimer] <= 0) - player->kartstuff[k_growcancel] = -1; - if (player->kartstuff[k_itemtype] == KITEM_SPB || player->kartstuff[k_itemtype] == KITEM_SHRINK || player->kartstuff[k_growshrinktimer] < 0) @@ -7415,6 +7734,11 @@ void K_MoveKartPlayer(player_t *player, boolean onground) if (player->kartstuff[k_hyudorotimer] > 0) { + INT32 hyu = hyudorotime; + + if (G_RaceGametype()) + hyu *= 2; // double in race + if (r_splitscreen) { if (leveltime & 1) @@ -7422,7 +7746,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground) else player->mo->flags2 &= ~MF2_DONTDRAW; - if (player->kartstuff[k_hyudorotimer] >= (1*TICRATE/2) && player->kartstuff[k_hyudorotimer] <= hyudorotime-(1*TICRATE/2)) + if (player->kartstuff[k_hyudorotimer] >= (TICRATE/2) && player->kartstuff[k_hyudorotimer] <= hyu-(TICRATE/2)) { if (player == &players[displayplayers[1]]) player->mo->eflags |= MFE_DRAWONLYFORP2; @@ -7441,7 +7765,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground) else { if (P_IsDisplayPlayer(player) - || (!P_IsDisplayPlayer(player) && (player->kartstuff[k_hyudorotimer] < (1*TICRATE/2) || player->kartstuff[k_hyudorotimer] > hyudorotime-(1*TICRATE/2)))) + || (!P_IsDisplayPlayer(player) && (player->kartstuff[k_hyudorotimer] < (TICRATE/2) || player->kartstuff[k_hyudorotimer] > hyu-(TICRATE/2)))) { if (leveltime & 1) player->mo->flags2 |= MF2_DONTDRAW; @@ -7803,6 +8127,8 @@ static patch_t *kp_selfpropelledbomb[2]; static patch_t *kp_grow[2]; static patch_t *kp_shrink[2]; static patch_t *kp_thundershield[2]; +static patch_t *kp_bubbleshield[2]; +static patch_t *kp_flameshield[2]; static patch_t *kp_hyudoro[2]; static patch_t *kp_pogospring[2]; static patch_t *kp_kitchensink[2]; @@ -7812,6 +8138,9 @@ static patch_t *kp_check[6]; static patch_t *kp_eggnum[4]; +static patch_t *kp_flameshieldmeter[104][2]; +static patch_t *kp_flameshieldmeter_bg[16][2]; + static patch_t *kp_fpview[3]; static patch_t *kp_inputwheel[5]; @@ -8018,11 +8347,30 @@ void K_LoadKartHUDGraphics(void) kp_grow[0] = W_CachePatchName("K_ITGROW", PU_HUDGFX); kp_shrink[0] = W_CachePatchName("K_ITSHRK", PU_HUDGFX); kp_thundershield[0] = W_CachePatchName("K_ITTHNS", PU_HUDGFX); + kp_bubbleshield[0] = W_CachePatchName("K_ITBUBS", PU_HUDGFX); + kp_flameshield[0] = W_CachePatchName("K_ITFLMS", PU_HUDGFX); kp_hyudoro[0] = W_CachePatchName("K_ITHYUD", PU_HUDGFX); kp_pogospring[0] = W_CachePatchName("K_ITPOGO", PU_HUDGFX); kp_kitchensink[0] = W_CachePatchName("K_ITSINK", PU_HUDGFX); kp_sadface[0] = W_CachePatchName("K_ITSAD", PU_HUDGFX); + sprintf(buffer, "FSMFGxxx"); + for (i = 0; i < 104; i++) + { + buffer[5] = '0'+((i+1)/100); + buffer[6] = '0'+(((i+1)/10)%10); + buffer[7] = '0'+((i+1)%10); + kp_flameshieldmeter[i][0] = (patch_t *) W_CachePatchName(buffer, PU_HUDGFX); + } + + sprintf(buffer, "FSMBG0xx"); + for (i = 0; i < 16; i++) + { + buffer[6] = '0'+((i+1)/10); + buffer[7] = '0'+((i+1)%10); + kp_flameshieldmeter_bg[i][0] = (patch_t *) W_CachePatchName(buffer, PU_HUDGFX); + } + // Splitscreen kp_itembg[2] = W_CachePatchName("K_ISBG", PU_HUDGFX); kp_itembg[3] = W_CachePatchName("K_ISBGD", PU_HUDGFX); @@ -8048,11 +8396,30 @@ void K_LoadKartHUDGraphics(void) kp_grow[1] = W_CachePatchName("K_ISGROW", PU_HUDGFX); kp_shrink[1] = W_CachePatchName("K_ISSHRK", PU_HUDGFX); kp_thundershield[1] = W_CachePatchName("K_ISTHNS", PU_HUDGFX); + kp_bubbleshield[1] = W_CachePatchName("K_ISBUBS", PU_HUDGFX); + kp_flameshield[1] = W_CachePatchName("K_ISFLMS", PU_HUDGFX); kp_hyudoro[1] = W_CachePatchName("K_ISHYUD", PU_HUDGFX); kp_pogospring[1] = W_CachePatchName("K_ISPOGO", PU_HUDGFX); kp_kitchensink[1] = W_CachePatchName("K_ISSINK", PU_HUDGFX); kp_sadface[1] = W_CachePatchName("K_ISSAD", PU_HUDGFX); + sprintf(buffer, "FSMFSxxx"); + for (i = 0; i < 104; i++) + { + buffer[5] = '0'+((i+1)/100); + buffer[6] = '0'+(((i+1)/10)%10); + buffer[7] = '0'+((i+1)%10); + kp_flameshieldmeter[i][1] = (patch_t *) W_CachePatchName(buffer, PU_HUDGFX); + } + + sprintf(buffer, "FSMBS0xx"); + for (i = 0; i < 16; i++) + { + buffer[6] = '0'+((i+1)/10); + buffer[7] = '0'+((i+1)%10); + kp_flameshieldmeter_bg[i][1] = (patch_t *) W_CachePatchName(buffer, PU_HUDGFX); + } + // CHECK indicators sprintf(buffer, "K_CHECKx"); for (i = 0; i < 6; i++) @@ -8185,6 +8552,10 @@ const char *K_GetItemPatch(UINT8 item, boolean tiny) return (tiny ? "K_ISSHRK" : "K_ITSHRK"); case KITEM_THUNDERSHIELD: return (tiny ? "K_ISTHNS" : "K_ITTHNS"); + case KITEM_BUBBLESHIELD: + return (tiny ? "K_ISBUBS" : "K_ITBUBS"); + case KITEM_FLAMESHIELD: + return (tiny ? "K_ISFLMS" : "K_ITFLMS"); case KITEM_HYUDORO: return (tiny ? "K_ISHYUD" : "K_ITHYUD"); case KITEM_POGOSPRING: @@ -8516,19 +8887,6 @@ static void K_drawKartItem(void) else localpatch = kp_nodraw; } - else if (stplyr->kartstuff[k_growshrinktimer] > 0) - { - if (stplyr->kartstuff[k_growcancel] > 0) - { - itembar = stplyr->kartstuff[k_growcancel]; - maxl = 26; - } - - if (leveltime & 1) - localpatch = kp_grow[offset]; - else - localpatch = kp_nodraw; - } else if (stplyr->kartstuff[k_sadtimer] > 0) { if (leveltime & 2) @@ -8585,6 +8943,14 @@ static void K_drawKartItem(void) localpatch = kp_thundershield[offset]; localbg = kp_itembg[offset+1]; break; + case KITEM_BUBBLESHIELD: + localpatch = kp_bubbleshield[offset]; + localbg = kp_itembg[offset+1]; + break; + case KITEM_FLAMESHIELD: + localpatch = kp_flameshield[offset]; + localbg = kp_itembg[offset+1]; + break; case KITEM_HYUDORO: localpatch = kp_hyudoro[offset]; break; @@ -8699,6 +9065,51 @@ static void K_drawKartItem(void) // Quick Eggman numbers if (stplyr->kartstuff[k_eggmanexplode] > 1 /*&& stplyr->kartstuff[k_eggmanexplode] <= 3*TICRATE*/) V_DrawScaledPatch(fx+17, fy+13-offset, V_HUDTRANS|fflags, kp_eggnum[min(3, G_TicsToSeconds(stplyr->kartstuff[k_eggmanexplode]))]); + + if (stplyr->kartstuff[k_itemtype] == KITEM_FLAMESHIELD && stplyr->kartstuff[k_flamelength] > 0) + { + INT32 numframes = 104; + INT32 absolutemax = 16 * flameseg; + INT32 flamemax = stplyr->kartstuff[k_flamelength] * flameseg; + INT32 flamemeter = min(stplyr->kartstuff[k_flamemeter], flamemax); + + INT32 bf = 16 - stplyr->kartstuff[k_flamelength]; + INT32 ff = numframes - ((flamemeter * numframes) / absolutemax); + INT32 fmin = (8 * (bf-1)); + + INT32 xo = 6, yo = 4; + INT32 flip = 0; + + if (offset) + { + xo++; + + if (stplyr == &players[displayplayers[0]] || stplyr == &players[displayplayers[2]]) // Flip for P1 and P3 (yes, that's correct) + { + xo -= 62; + flip = V_FLIP; + } + } + + if (ff < fmin) + ff = fmin; + + if (bf >= 0 && bf < 16) + V_DrawScaledPatch(fx-xo, fy-yo, V_HUDTRANS|fflags|flip, kp_flameshieldmeter_bg[bf][offset]); + + if (ff >= 0 && ff < numframes && stplyr->kartstuff[k_flamemeter] > 0) + { + if ((stplyr->kartstuff[k_flamemeter] > flamemax) && (leveltime & 1)) + { + UINT8 *fsflash = R_GetTranslationColormap(TC_BLINK, SKINCOLOR_WHITE, GTC_CACHE); + V_DrawMappedPatch(fx-xo, fy-yo, V_HUDTRANS|fflags|flip, kp_flameshieldmeter[ff][offset], fsflash); + } + else + { + V_DrawScaledPatch(fx-xo, fy-yo, V_HUDTRANS|fflags|flip, kp_flameshieldmeter[ff][offset]); + } + } + } } void K_drawKartTimestamp(tic_t drawtime, INT32 TX, INT32 TY, INT16 emblemmap, UINT8 mode) @@ -10583,6 +10994,8 @@ static void K_drawDistributionDebugger(void) kp_grow[1], kp_shrink[1], kp_thundershield[1], + kp_bubbleshield[1], + kp_flameshield[1], kp_hyudoro[1], kp_pogospring[1], kp_superring[1], diff --git a/src/k_kart.h b/src/k_kart.h index d5f84a7af..273d8bcb1 100644 --- a/src/k_kart.h +++ b/src/k_kart.h @@ -8,6 +8,7 @@ #include "doomdef.h" #include "d_player.h" // Need for player_t +#include "command.h" // Need for player_t #define KART_FULLTURN 800 @@ -22,6 +23,10 @@ void K_RegisterKartStuff(void); boolean K_IsPlayerLosing(player_t *player); fixed_t K_GetKartGameSpeedScalar(SINT8 value); + +extern consvar_t *KartItemCVars[NUMKARTRESULTS-1]; + +INT32 K_GetShieldFromItem(INT32 item); void K_KartBouncing(mobj_t *mobj1, mobj_t *mobj2, boolean bounce, boolean solid); void K_KartPainEnergyFling(player_t *player); void K_FlipFromObject(mobj_t *mo, mobj_t *master); diff --git a/src/m_menu.c b/src/m_menu.c index 897db4709..aa9113dbf 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -10636,31 +10636,6 @@ static void M_HandleVideoMode(INT32 ch) // =============== // Monitor Toggles // =============== -static consvar_t *kartitemcvs[NUMKARTRESULTS-1] = { - &cv_sneaker, - &cv_rocketsneaker, - &cv_invincibility, - &cv_banana, - &cv_eggmanmonitor, - &cv_orbinaut, - &cv_jawz, - &cv_mine, - &cv_ballhog, - &cv_selfpropelledbomb, - &cv_grow, - &cv_shrink, - &cv_thundershield, - &cv_hyudoro, - &cv_pogospring, - &cv_superring, - &cv_kitchensink, - &cv_triplesneaker, - &cv_triplebanana, - &cv_decabanana, - &cv_tripleorbinaut, - &cv_quadorbinaut, - &cv_dualjawz -}; static tic_t shitsfree = 0; @@ -10729,7 +10704,7 @@ static void M_DrawMonitorToggles(void) continue; } - cv = kartitemcvs[currentMenu->menuitems[thisitem].alphaKey-1]; + cv = KartItemCVars[currentMenu->menuitems[thisitem].alphaKey-1]; translucent = (cv->value ? 0 : V_TRANSLUCENT); switch (currentMenu->menuitems[thisitem].alphaKey) @@ -10798,7 +10773,7 @@ static void M_DrawMonitorToggles(void) } else { - cv = kartitemcvs[currentMenu->menuitems[itemOn].alphaKey-1]; + cv = KartItemCVars[currentMenu->menuitems[itemOn].alphaKey-1]; translucent = (cv->value ? 0 : V_TRANSLUCENT); switch (currentMenu->menuitems[itemOn].alphaKey) @@ -10914,14 +10889,14 @@ static void M_HandleMonitorToggles(INT32 choice) S_StartSound(NULL, sfx_s1b4); for (i = 0; i < NUMKARTRESULTS-1; i++) { - if (kartitemcvs[i]->value == v) - CV_AddValue(kartitemcvs[i], 1); + if (KartItemCVars[i]->value == v) + CV_AddValue(KartItemCVars[i], 1); } } else { S_StartSound(NULL, sfx_s1ba); - CV_AddValue(kartitemcvs[currentMenu->menuitems[itemOn].alphaKey-1], 1); + CV_AddValue(KartItemCVars[currentMenu->menuitems[itemOn].alphaKey-1], 1); } break; diff --git a/src/p_enemy.c b/src/p_enemy.c index 49416aec4..1b6556eca 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -203,6 +203,7 @@ void A_MayonakaArrow(mobj_t *actor); //SRB2kart void A_ReaperThinker(mobj_t *actor); //SRB2kart void A_MementosTPParticles(mobj_t *actor); //SRB2kart void A_FlameParticle(mobj_t *actor); // SRB2kart +void A_FlameShieldPaper(mobj_t *actor); // SRB2kart void A_OrbitNights(mobj_t *actor); void A_GhostMe(mobj_t *actor); void A_SetObjectState(mobj_t *actor); @@ -3678,7 +3679,7 @@ void A_AttractChase(mobj_t *actor) if (actor->tracer && actor->tracer->player && actor->tracer->health //&& P_CheckSight(actor, actor->tracer) && actor->tracer->player->kartstuff[k_itemtype] == KITEM_THUNDERSHIELD - && (actor->tracer->player->kartstuff[k_rings]+actor->tracer->player->kartstuff[k_pickuprings]) < 20 + && RINGTOTAL(actor->tracer->player) < 20 && !actor->tracer->player->kartstuff[k_ringlock]) { fixed_t dist; @@ -9328,6 +9329,52 @@ void A_FlameParticle(mobj_t *actor) par->momz = actor->scale<<1; } +void A_FlameShieldPaper(mobj_t *actor) +{ + INT32 framea = 0; + INT32 frameb = 0; + INT32 locvar1 = var1; + INT32 locvar2 = var2; + UINT8 i; + +#ifdef HAVE_BLUA + if (LUA_CallAction("A_FlameShieldPaper", actor)) + return; +#endif + + framea = (locvar1 & FF_FRAMEMASK); + frameb = (locvar2 & FF_FRAMEMASK); + + for (i = 0; i < 2; i++) + { + INT32 perpendicular = ((i & 1) ? -ANGLE_90 : ANGLE_90); + fixed_t newx = actor->x + P_ReturnThrustX(NULL, actor->angle + perpendicular, 8*actor->scale); + fixed_t newy = actor->y + P_ReturnThrustY(NULL, actor->angle + perpendicular, 8*actor->scale); + mobj_t *paper = P_SpawnMobj(newx, newy, actor->z, MT_FLAMESHIELDPAPER); + + P_SetTarget(&paper->target, actor); + P_SetScale(paper, actor->scale); + paper->destscale = actor->destscale; + + P_SetMobjState(paper, S_FLAMESHIELDPAPER); + paper->frame &= ~FF_FRAMEMASK; + + paper->angle = actor->angle + ANGLE_45; + + if (i & 1) + { + paper->angle -= ANGLE_90; + paper->frame |= frameb; + } + else + { + paper->frame |= framea; + } + + paper->extravalue1 = i; + } +} + //} // Function: A_OrbitNights diff --git a/src/p_inter.c b/src/p_inter.c index a1f507445..8cc307571 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -109,7 +109,7 @@ boolean P_CanPickupItem(player_t *player, UINT8 weapon) return false; /*if (G_BattleGametype() && player->kartstuff[k_bumper] <= 0) // No bumpers in Match - return false;*/ + return false;*/ if (weapon) { @@ -117,12 +117,7 @@ boolean P_CanPickupItem(player_t *player, UINT8 weapon) if (weapon == 2) { // Invulnerable - if (player->powers[pw_flashing] > 0 - || (player->kartstuff[k_spinouttimer] > 0 && player->kartstuff[k_spinouttype] != 2) - || player->kartstuff[k_squishedtimer] > 0 - || player->kartstuff[k_invincibilitytimer] > 0 - || player->kartstuff[k_growshrinktimer] > 0 - || player->kartstuff[k_hyudorotimer] > 0) + if (player->powers[pw_flashing] > 0) return false; // Already have fake @@ -134,7 +129,7 @@ boolean P_CanPickupItem(player_t *player, UINT8 weapon) { // Item-specific timer going off if (player->kartstuff[k_stealingtimer] || player->kartstuff[k_stolentimer] - || player->kartstuff[k_growshrinktimer] > 0 || player->kartstuff[k_rocketsneakertimer] + || player->kartstuff[k_rocketsneakertimer] || player->kartstuff[k_eggmanexplode]) return false; @@ -144,8 +139,8 @@ boolean P_CanPickupItem(player_t *player, UINT8 weapon) || player->kartstuff[k_itemheld]) return false; - if (weapon == 3 && player->kartstuff[k_itemtype] == KITEM_THUNDERSHIELD) - return false; // No stacking thunder shields! + if (weapon == 3 && K_GetShieldFromItem(player->kartstuff[k_itemtype]) != KSHIELD_NONE) + return false; // No stacking shields! } } @@ -391,58 +386,6 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) P_SetTarget(&special->target, toucher); P_KillMobj(special, toucher, toucher); break; - case MT_EGGMANITEM_SHIELD: // SRB2kart - case MT_EGGMANITEM: - if ((special->target == toucher || special->target == toucher->target) && (special->threshold > 0)) - return; - - if (special->health <= 0 || toucher->health <= 0) - return; - - if (!P_CanPickupItem(player, 2)) - return; - - if (G_BattleGametype() && player->kartstuff[k_bumper] <= 0) - { - if (player->kartstuff[k_comebackmode] || player->kartstuff[k_comebacktimer]) - return; - player->kartstuff[k_comebackmode] = 2; - } - else - { - K_DropItems(player); //K_StripItems(player); - //K_StripOther(player); - player->kartstuff[k_itemroulette] = 1; - player->kartstuff[k_roulettetype] = 2; - } - -#if 0 - // Eggbox snipe! - if (special->type == MT_EGGMANITEM && special->health > 1) - S_StartSound(toucher, sfx_bsnipe); -#endif - - { - mobj_t *poof = P_SpawnMobj(special->x, special->y, special->z, MT_EXPLODE); - S_StartSound(poof, special->info->deathsound); - } - - if (special->target && special->target->player) - { - if (G_RaceGametype() || special->target->player->kartstuff[k_bumper] > 0) - player->kartstuff[k_eggmanblame] = special->target->player-players; - else - player->kartstuff[k_eggmanblame] = player-players; - - if (special->target->hnext == special) - { - P_SetTarget(&special->target->hnext, NULL); - special->target->player->kartstuff[k_eggmanheld] = 0; - } - } - - P_RemoveMobj(special); - return; case MT_KARMAHITBOX: if (!special->target->player) return; @@ -597,11 +540,12 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) { mobj_t *spbexplode; - if (player->kartstuff[k_invincibilitytimer] > 0 || player->kartstuff[k_growshrinktimer] > 0 || player->kartstuff[k_hyudorotimer] > 0) + if (player->kartstuff[k_bubbleblowup] > 0) { - //player->powers[pw_flashing] = 0; K_DropHnextList(player); - K_StripItems(player); + special->extravalue1 = 2; // WAIT... + special->extravalue2 = 52; // Slightly over the respawn timer length + return; } S_StopSound(special); // Don't continue playing the gurgle or the siren @@ -631,7 +575,9 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) return; // kill - if (player->kartstuff[k_invincibilitytimer] > 0 || player->kartstuff[k_growshrinktimer] > 0) + if (player->kartstuff[k_invincibilitytimer] > 0 + || player->kartstuff[k_growshrinktimer] > 0 + || player->kartstuff[k_flamedash] > 0) { P_KillMobj(special, toucher, toucher); return; @@ -675,6 +621,25 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) case MT_BALLOON: // SRB2kart P_SetObjectMomZ(toucher, 20<target == toucher || special->target == toucher->target) && (special->threshold > 0)) + return; + + if (special->tracer && !P_MobjWasRemoved(special->tracer)) + return; + + if (special->health <= 0 || toucher->health <= 0) + return; + + if (!player->mo || player->spectator) + return; + + // attach to player! + P_SetTarget(&special->tracer, toucher); + toucher->flags |= MF_NOGRAVITY; + toucher->momz = (8*toucher->scale) * P_MobjFlip(toucher); + S_StartSound(toucher, sfx_s1b2); + return; // ***************************************** // // Rings, coins, spheres, weapon panels, etc // @@ -706,7 +671,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) return; // Reached the cap, don't waste 'em! - if ((player->kartstuff[k_rings] + player->kartstuff[k_pickuprings]) >= 20) + if (RINGTOTAL(player) >= 20) return; special->momx = special->momy = special->momz = 0; @@ -3332,8 +3297,8 @@ void P_PlayerRingBurst(player_t *player, INT32 num_rings) if (!player) return; - // Has a shield? Don't lose your rings! - if (player->kartstuff[k_itemtype] == KITEM_THUNDERSHIELD) + // Have a shield? You get hit, but don't lose your rings! + if (K_GetShieldFromItem(player->kartstuff[k_itemtype]) != KSHIELD_NONE) return; // 20 is the ring cap in kart diff --git a/src/p_map.c b/src/p_map.c index 559b9a461..9a3864f2c 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -841,7 +841,7 @@ static boolean PIT_CheckThing(mobj_t *thing) return K_SMKIceBlockCollide(thing, tmthing); } - if (tmthing->type == MT_EGGMANITEM) + if (tmthing->type == MT_EGGMANITEM || tmthing->type == MT_EGGMANITEM_SHIELD) { // see if it went over / under if (tmthing->z > thing->z + thing->height) @@ -849,10 +849,9 @@ static boolean PIT_CheckThing(mobj_t *thing) if (tmthing->z + tmthing->height < thing->z) return true; // underneath - K_EggItemCollide(tmthing, thing); - return true; + return K_EggItemCollide(tmthing, thing); } - else if (thing->type == MT_EGGMANITEM) + else if (thing->type == MT_EGGMANITEM || thing->type == MT_EGGMANITEM_SHIELD) { // see if it went over / under if (tmthing->z > thing->z + thing->height) @@ -860,13 +859,134 @@ static boolean PIT_CheckThing(mobj_t *thing) if (tmthing->z + tmthing->height < thing->z) return true; // underneath - K_EggItemCollide(thing, tmthing); - return true; + return K_EggItemCollide(thing, tmthing); } if (tmthing->type == MT_RANDOMITEM) return true; + // Bubble Shield reflect + if (((thing->type == MT_BUBBLESHIELD && thing->target->player && thing->target->player->kartstuff[k_bubbleblowup]) + || (thing->player && thing->player->kartstuff[k_bubbleblowup])) + && (tmthing->type == MT_ORBINAUT || tmthing->type == MT_JAWZ || tmthing->type == MT_JAWZ_DUD + || tmthing->type == MT_BANANA || tmthing->type == MT_EGGMANITEM || tmthing->type == MT_BALLHOG + || tmthing->type == MT_SSMINE || tmthing->type == MT_SINK + || (tmthing->type == MT_PLAYER && thing->target != tmthing))) + { + // see if it went over / under + if (tmthing->z > thing->z + thing->height) + return true; // overhead + if (tmthing->z + tmthing->height < thing->z) + return true; // underneath + + if (tmthing->type == MT_PLAYER) + { + // Counter desyncs + /*mobj_t *oldthing = thing; + mobj_t *oldtmthing = tmthing; + + P_Thrust(tmthing, R_PointToAngle2(thing->x, thing->y, tmthing->x, tmthing->y), 4*thing->scale); + + thing = oldthing; + P_SetTarget(&tmthing, oldtmthing);*/ + + if (tmthing->player->kartstuff[k_spinouttimer] || tmthing->player->kartstuff[k_squishedtimer] + || tmthing->player->powers[pw_flashing] || tmthing->player->kartstuff[k_hyudorotimer] + || tmthing->player->kartstuff[k_justbumped] || tmthing->scale > thing->scale + (mapobjectscale/8)) + return true; + + // Player Damage + K_SpinPlayer(tmthing->player, thing, 0, ((thing->type == MT_BUBBLESHIELD) ? thing->target : thing), false); + S_StartSound(thing, sfx_s3k44); + } + else + { + if (!tmthing->threshold) + { + if (!tmthing->momx && !tmthing->momy) + { + tmthing->momz += (24*tmthing->scale) * P_MobjFlip(tmthing); + } + else + { + tmthing->momx = -tmthing->momx; + tmthing->momy = -tmthing->momy; + tmthing->momz = -tmthing->momz; + tmthing->angle += ANGLE_180; + } + if (tmthing->type == MT_JAWZ) + P_SetTarget(&tmthing->tracer, tmthing->target); // Back to the source! + tmthing->threshold = 10; + S_StartSound(thing, sfx_s3k44); + } + } + + // no interaction + return true; + } + else if (((tmthing->type == MT_BUBBLESHIELD && tmthing->target->player && tmthing->target->player->kartstuff[k_bubbleblowup]) + || (tmthing->player && tmthing->player->kartstuff[k_bubbleblowup])) + && (thing->type == MT_ORBINAUT || thing->type == MT_JAWZ || thing->type == MT_JAWZ_DUD + || thing->type == MT_BANANA || thing->type == MT_EGGMANITEM || thing->type == MT_BALLHOG + || thing->type == MT_SSMINE || thing->type == MT_SINK + || (thing->type == MT_PLAYER && tmthing->target != thing))) + { + // see if it went over / under + if (tmthing->z > thing->z + thing->height) + return true; // overhead + if (tmthing->z + tmthing->height < thing->z) + return true; // underneath + + if (thing->type == MT_PLAYER) + { + // Counter desyncs + /*mobj_t *oldthing = thing; + mobj_t *oldtmthing = tmthing; + + P_Thrust(thing, R_PointToAngle2(tmthing->x, tmthing->y, thing->x, thing->y), 4*tmthing->scale); + + thing = oldthing; + P_SetTarget(&tmthing, oldtmthing);*/ + + if (thing->player->kartstuff[k_spinouttimer] || thing->player->kartstuff[k_squishedtimer] + || thing->player->powers[pw_flashing] || thing->player->kartstuff[k_hyudorotimer] + || thing->player->kartstuff[k_justbumped] || thing->scale > tmthing->scale + (mapobjectscale/8)) + return true; + + // Player Damage + K_SpinPlayer(thing->player, tmthing, 0, ((tmthing->type == MT_BUBBLESHIELD) ? tmthing->target : tmthing), false); + S_StartSound(tmthing, sfx_s3k44); + } + else + { + if (!thing->threshold) + { + if (!thing->momx && !thing->momy) + { + thing->momz += (24*thing->scale) * P_MobjFlip(thing); + } + else + { + thing->momx = -thing->momx; + thing->momy = -thing->momy; + thing->momz = -thing->momz; + thing->angle += ANGLE_180; + } + if (thing->type == MT_JAWZ) + P_SetTarget(&thing->tracer, thing->target); // Back to the source! + thing->threshold = 10; + S_StartSound(tmthing, sfx_s3k44); + } + } + + // no interaction + return true; + } + + // double make sure bubbles won't collide with anything else + if (thing->type == MT_BUBBLESHIELD || tmthing->type == MT_BUBBLESHIELD) + return true; + if (tmthing->type == MT_ORBINAUT || tmthing->type == MT_JAWZ || tmthing->type == MT_JAWZ_DUD || tmthing->type == MT_ORBINAUT_SHIELD || tmthing->type == MT_JAWZ_SHIELD) { @@ -1296,7 +1416,6 @@ static boolean PIT_CheckThing(mobj_t *thing) // Make sure they aren't able to damage you ANYWHERE along the Z axis, you have to be TOUCHING the person. && !(thing->z + thing->height < tmthing->z || thing->z > tmthing->z + tmthing->height)) { - if (tmthing->scale > thing->scale + (mapobjectscale/8)) // SRB2kart - Handle squishes first! K_SquishPlayer(thing->player, tmthing, tmthing); else if (thing->scale > tmthing->scale + (mapobjectscale/8)) @@ -1305,6 +1424,12 @@ static boolean PIT_CheckThing(mobj_t *thing) P_DamageMobj(thing, tmthing, tmthing, 1); else if (thing->player->kartstuff[k_invincibilitytimer] && !tmthing->player->kartstuff[k_invincibilitytimer]) P_DamageMobj(tmthing, thing, thing, 1); + else if ((tmthing->player->kartstuff[k_flamedash] && tmthing->player->kartstuff[k_itemtype] == KITEM_FLAMESHIELD) + && !(thing->player->kartstuff[k_flamedash] && thing->player->kartstuff[k_itemtype] == KITEM_FLAMESHIELD)) // SRB2kart - Then flame shield! + P_DamageMobj(thing, tmthing, tmthing, 1); + else if ((thing->player->kartstuff[k_flamedash] && thing->player->kartstuff[k_itemtype] == KITEM_FLAMESHIELD) + && !(tmthing->player->kartstuff[k_flamedash] && tmthing->player->kartstuff[k_itemtype] == KITEM_FLAMESHIELD)) // SRB2kart - Then flame shield! + P_DamageMobj(tmthing, thing, thing, 1); /*if (G_BattleGametype() && (!G_GametypeHasTeams() || tmthing->player->ctfteam != thing->player->ctfteam)) { diff --git a/src/p_mobj.c b/src/p_mobj.c index a1ac18dc9..666818ef3 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -1722,6 +1722,10 @@ void P_XYMovement(mobj_t *mo) P_InstaThrust(mo, R_PointToAngle2(mo->x, mo->y, mo->x + xmove, mo->y + ymove)+ANGLE_90, 16*FRACUNIT); } } + + // Bubble bounce + if (mo->type == MT_BUBBLESHIELDTRAP) + S_StartSound(mo, sfx_s3k44); //} // Bounce ring algorithm @@ -1933,7 +1937,7 @@ void P_XYMovement(mobj_t *mo) #endif //{ SRB2kart stuff - if (mo->type == MT_BALLHOG || mo->type == MT_FLINGRING) //(mo->type == MT_JAWZ && !mo->tracer)) + if (mo->type == MT_FLINGRING || mo->type == MT_BALLHOG || mo->type == MT_BUBBLESHIELDTRAP) return; if (mo->player && (mo->player->kartstuff[k_spinouttimer] && !mo->player->kartstuff[k_wipeoutslow]) && mo->player->speed <= K_GetKartSpeed(mo->player, false)/2) @@ -2270,6 +2274,7 @@ static boolean P_ZMovement(mobj_t *mo) case MT_JAWZ_DUD: case MT_BALLHOG: case MT_SSMINE: + case MT_BUBBLESHIELDTRAP: // Remove stuff from death pits. if (P_CheckDeathPitCollide(mo)) { @@ -6767,17 +6772,6 @@ void P_MobjThinker(mobj_t *mobj) else mobj->tracer->flags2 |= MF2_DONTDRAW; } - else if (mobj->target->player->kartstuff[k_growshrinktimer] > 0) - { - P_SetMobjState(mobj, S_PLAYERARROW_BOX); - mobj->tracer->sprite = SPR_ITEM; - mobj->tracer->frame = FF_FULLBRIGHT|KITEM_GROW; - - if (leveltime & 1) - mobj->tracer->flags2 &= ~MF2_DONTDRAW; - else - mobj->tracer->flags2 |= MF2_DONTDRAW; - } else if (mobj->target->player->kartstuff[k_itemtype] && mobj->target->player->kartstuff[k_itemamount] > 0) { P_SetMobjState(mobj, S_PLAYERARROW_BOX); @@ -8414,6 +8408,30 @@ void P_MobjThinker(mobj_t *mobj) mobj->target->y + FINESINE(mobj->angle >> ANGLETOFINESHIFT), mobj->z + mobj->target->height * P_MobjFlip(mobj)); break; + case MT_FLAMESHIELDPAPER: + if (!mobj->target || P_MobjWasRemoved(mobj->target)) + { + P_RemoveMobj(mobj); + return; + } + + mobj->z = mobj->target->z; + + K_MatchGenericExtraFlags(mobj, mobj->target); + + { + INT32 perpendicular = ((mobj->extravalue1 & 1) ? -ANGLE_90 : ANGLE_90); + fixed_t newx = mobj->target->x + P_ReturnThrustX(NULL, mobj->target->angle + perpendicular, 8*mobj->target->scale); + fixed_t newy = mobj->target->y + P_ReturnThrustY(NULL, mobj->target->angle + perpendicular, 8*mobj->target->scale); + + P_TeleportMove(mobj, newx, newy, mobj->target->z); + + if (mobj->extravalue1 & 1) + mobj->angle = mobj->target->angle - ANGLE_45; + else + mobj->angle = mobj->target->angle + ANGLE_45; + } + break; case MT_TIREGREASE: if (!mobj->target || P_MobjWasRemoved(mobj->target) || !mobj->target->player || !mobj->target->player->kartstuff[k_tiregrease]) @@ -8467,12 +8485,13 @@ void P_MobjThinker(mobj_t *mobj) case MT_THUNDERSHIELD: { fixed_t destx, desty; - if (!mobj->target || !mobj->target->health || (mobj->target->player && mobj->target->player->kartstuff[k_curshield] != 1)) + if (!mobj->target || !mobj->target->health || !mobj->target->player + || mobj->target->player->kartstuff[k_curshield] != KSHIELD_THUNDER) { P_RemoveMobj(mobj); return; } - P_SetScale(mobj, (mobj->destscale = (5*mobj->target->destscale)>>2)); + P_SetScale(mobj, (mobj->destscale = (5*mobj->target->scale)>>2)); if (!r_splitscreen /*&& rendermode != render_soft*/) { @@ -8486,8 +8505,9 @@ void P_MobjThinker(mobj_t *mobj) else viewingangle = R_PointToAngle2(mobj->target->x, mobj->target->y, camera[0].x, camera[0].y); - if (curstate > S_THUNDERSHIELD15) + if (curstate > S_THUNDERSHIELD15 && curstate <= S_THUNDERSHIELD24) viewingangle += ANGLE_180; + destx = mobj->target->x + P_ReturnThrustX(mobj->target, viewingangle, mobj->scale>>4); desty = mobj->target->y + P_ReturnThrustY(mobj->target, viewingangle, mobj->scale>>4); } @@ -8500,6 +8520,250 @@ void P_MobjThinker(mobj_t *mobj) P_TeleportMove(mobj, destx, desty, mobj->target->z); break; } + case MT_BUBBLESHIELD: + { + fixed_t destx, desty; + fixed_t scale; + statenum_t curstate; + + if (!mobj->target || !mobj->target->health || !mobj->target->player + || mobj->target->player->kartstuff[k_curshield] != KSHIELD_BUBBLE) + { + P_RemoveMobj(mobj); + return; + } + + scale = (5*mobj->target->scale)>>2; + curstate = ((mobj->tics == 1) ? (mobj->state->nextstate) : ((statenum_t)(mobj->state-states))); + + if (mobj->target->player->kartstuff[k_bubbleblowup]) + { + INT32 blow = mobj->target->player->kartstuff[k_bubbleblowup]; + if (blow > bubbletime) + blow = bubbletime; + + if (curstate != S_BUBBLESHIELDBLOWUP) + P_SetMobjState(mobj, S_BUBBLESHIELDBLOWUP); + + mobj->angle += ANGLE_22h; + mobj->flags2 &= ~MF2_SHADOW; + scale += (blow * (3*scale)) / bubbletime; + + mobj->frame = (states[S_BUBBLESHIELDBLOWUP].frame + mobj->extravalue1); + if ((mobj->target->player->kartstuff[k_bubbleblowup] > bubbletime) && (leveltime & 1)) + mobj->frame = (states[S_BUBBLESHIELDBLOWUP].frame + 5); + + if (mobj->extravalue1 < 4 && mobj->extravalue2 < blow && !mobj->cvmem && (leveltime & 1)) // Growing + { + mobj->extravalue1++; + if (mobj->extravalue1 >= 4) + mobj->cvmem = 1; // shrink back down + } + else if ((mobj->extravalue1 > -4 && mobj->extravalue2 > blow) + || (mobj->cvmem && mobj->extravalue1 > 0)) // Shrinking + mobj->extravalue1--; + + if (P_IsObjectOnGround(mobj->target)) + { + UINT8 i; + + for (i = 0; i < 2; i++) + { + angle_t a = mobj->angle + ((i & 1) ? ANGLE_180 : 0); + fixed_t ws = (mobj->target->scale>>1); + mobj_t *wave; + + ws += (blow * ws) / bubbletime; + + wave = P_SpawnMobj( + (mobj->target->x - mobj->target->momx) + P_ReturnThrustX(NULL, a, mobj->radius - (21*ws)), + (mobj->target->y - mobj->target->momy) + P_ReturnThrustY(NULL, a, mobj->radius - (21*ws)), + (mobj->target->z - mobj->target->momz), MT_THOK); + + wave->flags &= ~(MF_NOCLIPHEIGHT|MF_NOGRAVITY); + P_SetScale(wave, (wave->destscale = ws)); + + P_SetMobjState(wave, S_BUBBLESHIELDWAVE1); + + wave->momx = mobj->target->momx; + wave->momy = mobj->target->momy; + wave->momz = mobj->target->momz; + } + } + } + else + { + mobj->cvmem = 0; + mobj->angle = mobj->target->angle; + + if (curstate == S_BUBBLESHIELDBLOWUP) + { + if (mobj->extravalue1 != 0) + { + mobj->frame = (states[S_BUBBLESHIELDBLOWUP].frame + mobj->extravalue1); + + if (mobj->extravalue1 < 0 && (leveltime & 1)) + mobj->extravalue1++; + else if (mobj->extravalue1 > 0) + mobj->extravalue1--; + } + else + { + P_SetMobjState(mobj, S_BUBBLESHIELD1); + mobj->extravalue1 = 0; + } + } + else + { + if (mobj->target->player->kartstuff[k_bubblecool] && ((curstate-S_BUBBLESHIELD1) & 1)) + mobj->flags2 |= MF2_SHADOW; + else + mobj->flags2 &= ~MF2_SHADOW; + } + } + + mobj->extravalue2 = mobj->target->player->kartstuff[k_bubbleblowup]; + P_SetScale(mobj, (mobj->destscale = scale)); + + if (!splitscreen /*&& rendermode != render_soft*/) + { + angle_t viewingangle; + + if (players[displayplayers[0]].awayviewtics) + viewingangle = R_PointToAngle2(mobj->target->x, mobj->target->y, players[displayplayers[0]].awayviewmobj->x, players[displayplayers[0]].awayviewmobj->y); + else if (!camera[0].chase && players[displayplayers[0]].mo) + viewingangle = R_PointToAngle2(mobj->target->x, mobj->target->y, players[displayplayers[0]].mo->x, players[displayplayers[0]].mo->y); + else + viewingangle = R_PointToAngle2(mobj->target->x, mobj->target->y, camera[0].x, camera[0].y); + + destx = mobj->target->x + P_ReturnThrustX(mobj->target, viewingangle, mobj->scale>>4); + desty = mobj->target->y + P_ReturnThrustY(mobj->target, viewingangle, mobj->scale>>4); + } + else + { + destx = mobj->target->x; + desty = mobj->target->y; + } + + P_TeleportMove(mobj, destx, desty, mobj->target->z); + break; + } + case MT_FLAMESHIELD: + { + fixed_t destx, desty; + statenum_t curstate; + statenum_t underlayst = S_NULL; + INT32 flamemax = mobj->target->player->kartstuff[k_flamelength] * flameseg; + + if (!mobj->target || !mobj->target->health || !mobj->target->player + || mobj->target->player->kartstuff[k_curshield] != KSHIELD_FLAME) + { + P_RemoveMobj(mobj); + return; + } + P_SetScale(mobj, (mobj->destscale = (5*mobj->target->scale)>>2)); + + curstate = ((mobj->tics == 1) ? (mobj->state->nextstate) : ((statenum_t)(mobj->state-states))); + + if (mobj->target->player->kartstuff[k_flamedash]) + { + if (!(curstate >= S_FLAMESHIELDDASH1 && curstate <= S_FLAMESHIELDDASH12)) + P_SetMobjState(mobj, S_FLAMESHIELDDASH1); + + if (curstate == S_FLAMESHIELDDASH2) + underlayst = S_FLAMESHIELDDASH2_UNDERLAY; + else if (curstate == S_FLAMESHIELDDASH5) + underlayst = S_FLAMESHIELDDASH5_UNDERLAY; + else if (curstate == S_FLAMESHIELDDASH8) + underlayst = S_FLAMESHIELDDASH8_UNDERLAY; + else if (curstate == S_FLAMESHIELDDASH11) + underlayst = S_FLAMESHIELDDASH11_UNDERLAY; + + if (leveltime & 1) + { + UINT8 i; + UINT8 nl = 2; + + if (mobj->target->player->kartstuff[k_flamedash] > mobj->extravalue1) + nl = 3; + + for (i = 0; i < nl; i++) + { + mobj_t *fast = P_SpawnMobj(mobj->x + (P_RandomRange(-36,36) * mobj->scale), + mobj->y + (P_RandomRange(-36,36) * mobj->scale), + mobj->z + (mobj->height/2) + (P_RandomRange(-20,20) * mobj->scale), + MT_FASTLINE); + + fast->angle = mobj->angle; + fast->momx = 3*mobj->target->momx/4; + fast->momy = 3*mobj->target->momy/4; + fast->momz = 3*mobj->target->momz/4; + + K_MatchGenericExtraFlags(fast, mobj); + P_SetMobjState(fast, S_FLAMESHIELDLINE1 + i); + } + } + } + else + { + if (curstate >= S_FLAMESHIELDDASH1 && curstate <= S_FLAMESHIELDDASH12) + P_SetMobjState(mobj, S_FLAMESHIELD1); + } + + mobj->extravalue1 = mobj->target->player->kartstuff[k_flamedash]; + + if (mobj->target->player->kartstuff[k_flamemeter] > flamemax) + { + mobj_t *flash = P_SpawnMobj(mobj->x + mobj->target->momx, mobj->y + mobj->target->momy, mobj->z + mobj->target->momz, MT_THOK); + P_SetMobjState(flash, S_FLAMESHIELDFLASH); + + if (leveltime & 1) + { + flash->frame |= 2 + ((leveltime / 2) % 4); + } + else + { + flash->frame |= ((leveltime / 2) % 2); + } + } + + if (!splitscreen /*&& rendermode != render_soft*/) + { + angle_t viewingangle; + + if (players[displayplayers[0]].awayviewtics) + viewingangle = R_PointToAngle2(mobj->target->x, mobj->target->y, players[displayplayers[0]].awayviewmobj->x, players[displayplayers[0]].awayviewmobj->y); + else if (!camera[0].chase && players[displayplayers[0]].mo) + viewingangle = R_PointToAngle2(mobj->target->x, mobj->target->y, players[displayplayers[0]].mo->x, players[displayplayers[0]].mo->y); + else + viewingangle = R_PointToAngle2(mobj->target->x, mobj->target->y, camera[0].x, camera[0].y); + + if (curstate >= S_FLAMESHIELD1 && curstate < S_FLAMESHIELDDASH1 && ((curstate-S_FLAMESHIELD1) & 1)) + viewingangle += ANGLE_180; + + destx = mobj->target->x + P_ReturnThrustX(mobj->target, viewingangle, mobj->scale>>4); + desty = mobj->target->y + P_ReturnThrustY(mobj->target, viewingangle, mobj->scale>>4); + } + else + { + destx = mobj->target->x; + desty = mobj->target->y; + } + + P_TeleportMove(mobj, destx, desty, mobj->target->z); + if (mobj->target->momx || mobj->target->momy) + mobj->angle = R_PointToAngle2(0, 0, mobj->target->momx, mobj->target->momy); + else + mobj->angle = mobj->target->angle; + + if (underlayst != S_NULL) + { + mobj_t *underlay = P_SpawnMobj(mobj->target->x, mobj->target->y, mobj->target->z, MT_FLAMESHIELDUNDERLAY); + underlay->angle = mobj->angle; + P_SetMobjState(underlay, underlayst); + } + break; + } case MT_ROCKETSNEAKER: if (!mobj->target || !mobj->target->health) { @@ -9238,6 +9502,154 @@ void P_MobjThinker(mobj_t *mobj) } } break; + case MT_BUBBLESHIELDTRAP: + if (leveltime % 180 == 0) + S_StartSound(mobj, sfx_s3kbfl); + + if (mobj->tracer && !P_MobjWasRemoved(mobj->tracer) && mobj->tracer->player) + { + player_t *player = mobj->tracer->player; + fixed_t destx, desty, curfz, destfz; + boolean blockmove = false; + + mobj->flags = MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOCLIPTHING|MF_NOGRAVITY|MF_DONTENCOREMAP; + mobj->extravalue1 = 1; + + mobj->cvmem /= 2; + mobj->momz = 0; + mobj->destscale = ((5*mobj->tracer->scale)>>2) + (mobj->tracer->scale>>3); + + mobj->tracer->momz = (8*mobj->tracer->scale) * P_MobjFlip(mobj->tracer); + + mobj->tracer->momx = (31*mobj->tracer->momx)/32; + mobj->tracer->momy = (31*mobj->tracer->momy)/32; + + destx = mobj->x + mobj->tracer->momx; + desty = mobj->y + mobj->tracer->momy; + + if (mobj->tracer->eflags & MFE_VERTICALFLIP) + { + curfz = P_GetCeilingZ(mobj->tracer, mobj->tracer->subsector->sector, mobj->tracer->x, mobj->tracer->y, NULL); + destfz = P_GetCeilingZ(mobj->tracer, R_PointInSubsector(destx, desty)->sector, destx, desty, NULL); + blockmove = (curfz - destfz >= 24*mobj->scale); + } + else + { + curfz = P_GetFloorZ(mobj->tracer, mobj->tracer->subsector->sector, mobj->tracer->x, mobj->tracer->y, NULL); + destfz = P_GetFloorZ(mobj->tracer, R_PointInSubsector(destx, desty)->sector, destx, desty, NULL); + blockmove = (destfz - curfz >= 24*mobj->scale); + } + + if (blockmove) + { + mobj->tracer->momx = mobj->tracer->momy = 0; + } + + P_TeleportMove(mobj, + mobj->tracer->x + P_ReturnThrustX(NULL, mobj->tracer->angle+ANGLE_90, (mobj->cvmem)<tracer->y + P_ReturnThrustY(NULL, mobj->tracer->angle+ANGLE_90, (mobj->cvmem)<tracer->z - (4*mobj->tracer->scale) + (P_RandomRange(-abs(mobj->cvmem), abs(mobj->cvmem))<movecount > 4*TICRATE) + { + S_StartSound(mobj->tracer, sfx_s3k77); + mobj->tracer->flags &= ~MF_NOGRAVITY; + P_KillMobj(mobj, mobj->tracer, mobj->tracer); + break; + } + + if (abs(player->cmd.driftturn) > 100) + { + INT32 lastsign = 0; + if (mobj->lastlook > 0) + lastsign = 1; + else if (mobj->lastlook < 0) + lastsign = -1; + + if ((player->cmd.driftturn > 0 && lastsign < 0) + || (player->cmd.driftturn < 0 && lastsign > 0)) + { + mobj->movecount += (TICRATE/2); + mobj->cvmem = 8*lastsign; + S_StartSound(mobj, sfx_s3k7a); + } + + mobj->lastlook = player->cmd.driftturn; + } + + mobj->movecount++; + } + else if (mobj->extravalue1) // lost your player somehow, DIE + { + P_KillMobj(mobj, NULL, NULL); + break; + } + else + { + mobj->destscale = (5*mapobjectscale)>>2; + + if (mobj->threshold > 0) + mobj->threshold--; + + if (abs(mobj->momx) < 8*mobj->destscale && abs(mobj->momy) < 8*mobj->destscale) + { + // Stop, give light gravity + mobj->momx = mobj->momy = 0; + mobj->momz = -(mobj->scale * P_MobjFlip(mobj)); + } + else + { + UINT8 i; + mobj_t *ghost = P_SpawnGhostMobj(mobj); + + if (mobj->target && !P_MobjWasRemoved(mobj->target) && mobj->target->player) + { + ghost->color = mobj->target->player->skincolor; + ghost->colorized = true; + } + + mobj->momx = (23*mobj->momx)/24; + mobj->momy = (23*mobj->momy)/24; + + mobj->angle = R_PointToAngle2(0,0,mobj->momx,mobj->momy); + + if ((mobj->z - mobj->floorz) < (24*mobj->scale) && (leveltime % 3 != 0)) + { + // Cool wave effects! + for (i = 0; i < 2; i++) + { + angle_t aoff; + SINT8 sign = 1; + mobj_t *wave; + + if (i & 1) + sign = -1; + else + sign = 1; + + aoff = (mobj->angle + ANGLE_180) + (ANGLE_45 * sign); + + wave = P_SpawnMobj(mobj->x + FixedMul(mobj->radius, FINECOSINE(aoff>>ANGLETOFINESHIFT)), + mobj->y + FixedMul(mobj->radius, FINESINE(aoff>>ANGLETOFINESHIFT)), + mobj->z, MT_THOK); + + wave->flags &= ~(MF_NOCLIPHEIGHT|MF_NOGRAVITY); + P_SetScale(wave, (wave->destscale = mobj->scale/2)); + + P_SetMobjState(wave, S_BUBBLESHIELDWAVE1); + if (leveltime & 1) + wave->tics++; + + P_SetTarget(&wave->target, mobj); + wave->angle = mobj->angle - (ANGLE_90 * sign); // point completely perpendicular from the bubble + K_FlipFromObject(wave, mobj); + + P_Thrust(wave, wave->angle, 4*mobj->scale); + } + } + } + } + break; case MT_KARMAFIREWORK: if (mobj->flags & MF_NOGRAVITY) break; @@ -10182,7 +10594,6 @@ static void P_DefaultMobjShadowScale(mobj_t *thing) case MT_SSMINE_SHIELD: case MT_BALLHOG: case MT_SINK: - case MT_THUNDERSHIELD: case MT_ROCKETSNEAKER: case MT_SPB: thing->shadowscale = 3*FRACUNIT/2; @@ -10202,6 +10613,12 @@ static void P_DefaultMobjShadowScale(mobj_t *thing) thing->shadowscale = 3*FRACUNIT/2; thing->whiteshadow = false; break; + case MT_THUNDERSHIELD: + case MT_BUBBLESHIELD: + case MT_BUBBLESHIELDTRAP: + case MT_FLAMESHIELD: + thing->shadowscale = FRACUNIT; + break; case MT_RING: case MT_FLOATINGITEM: thing->shadowscale = FRACUNIT/2; diff --git a/src/p_user.c b/src/p_user.c index 22149f408..16038fade 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -1083,7 +1083,7 @@ void P_PlayLivesJingle(player_t *player) void P_PlayRinglossSound(mobj_t *source) { - if (source->player && source->player->kartstuff[k_itemtype] == KITEM_THUNDERSHIELD) + if (source->player && K_GetShieldFromItem(source->player->kartstuff[k_itemtype]) != KSHIELD_NONE) S_StartSound(source, sfx_s1a3); // Shield hit (no ring loss) else if (source->player && source->player->kartstuff[k_rings] <= 0) S_StartSound(source, sfx_s1a6); // Ring debt (lessened ring loss) @@ -1218,10 +1218,10 @@ void P_RestoreMusic(player_t *player) #define setbests(p) \ if (players[p].playerstate == PST_LIVE) \ { \ - if (players[p].kartstuff[k_growshrinktimer] > bestlocaltimer) \ - { wantedmus = 2; bestlocaltimer = players[p].kartstuff[k_growshrinktimer]; } \ - else if (players[p].kartstuff[k_invincibilitytimer] > bestlocaltimer) \ + if (players[p].kartstuff[k_invincibilitytimer] > bestlocaltimer) \ { wantedmus = 1; bestlocaltimer = players[p].kartstuff[k_invincibilitytimer]; } \ + else if (players[p].kartstuff[k_growshrinktimer] > bestlocaltimer) \ + { wantedmus = 2; bestlocaltimer = players[p].kartstuff[k_growshrinktimer]; } \ } setbests(displayplayers[0]); setbests(displayplayers[1]); @@ -1235,10 +1235,10 @@ void P_RestoreMusic(player_t *player) { if (player->playerstate == PST_LIVE) { - if (player->kartstuff[k_growshrinktimer] > 1) - wantedmus = 2; - else if (player->kartstuff[k_invincibilitytimer] > 1) + if (player->kartstuff[k_invincibilitytimer] > 1) wantedmus = 1; + else if (player->kartstuff[k_growshrinktimer] > 1) + wantedmus = 2; } } @@ -6142,7 +6142,8 @@ static void P_MovePlayer(player_t *player) //////////////////////////// // SRB2kart - Drifting smoke and fire - if (EITHERSNEAKER(player) && onground && (leveltime & 1)) + if ((EITHERSNEAKER(player) || player->kartstuff[k_flamedash]) + && onground && (leveltime & 1)) K_SpawnBoostTrail(player); if (player->kartstuff[k_invincibilitytimer] > 0) diff --git a/src/r_defs.h b/src/r_defs.h index 52a3be80e..c8a72044d 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -406,6 +406,8 @@ typedef enum ST_NEGATIVE } slopetype_t; +#define HORIZONSPECIAL 41 + typedef struct line_s { // Vertices, from v1 to v2. diff --git a/src/r_segs.c b/src/r_segs.c index 399f514bc..2304540fe 100644 --- a/src/r_segs.c +++ b/src/r_segs.c @@ -2687,7 +2687,7 @@ void R_StoreWallRange(INT32 start, INT32 stop) worldbottomslope >>= 4; #endif - if (linedef->special == 41) { // HORIZON LINES + if (linedef->special == HORIZONSPECIAL) { // HORIZON LINES topstep = bottomstep = 0; topfrac = bottomfrac = (centeryfrac>>4); topfrac++; // Prevent 1px HOM @@ -2817,12 +2817,23 @@ void R_StoreWallRange(INT32 start, INT32 stop) ffloor[i].f_pos >>= 4; #ifdef ESLOPE ffloor[i].f_pos_slope >>= 4; - ffloor[i].f_frac = (centeryfrac>>4) - FixedMul(ffloor[i].f_pos, rw_scale); - ffloor[i].f_step = ((centeryfrac>>4) - FixedMul(ffloor[i].f_pos_slope, ds_p->scale2) - ffloor[i].f_frac)/(range); -#else - ffloor[i].f_step = FixedMul(-rw_scalestep, ffloor[i].f_pos); - ffloor[i].f_frac = (centeryfrac>>4) - FixedMul(ffloor[i].f_pos, rw_scale); #endif + if (linedef->special == HORIZONSPECIAL) // Horizon lines extend FOFs in contact with them too. + { + ffloor[i].f_step = 0; + ffloor[i].f_frac = (centeryfrac>>4); + topfrac++; // Prevent 1px HOM + } + else + { +#ifdef ESLOPE + ffloor[i].f_frac = (centeryfrac>>4) - FixedMul(ffloor[i].f_pos, rw_scale); + ffloor[i].f_step = ((centeryfrac>>4) - FixedMul(ffloor[i].f_pos_slope, ds_p->scale2) - ffloor[i].f_frac)/(range); +#else + ffloor[i].f_step = FixedMul(-rw_scalestep, ffloor[i].f_pos); + ffloor[i].f_frac = (centeryfrac>>4) - FixedMul(ffloor[i].f_pos, rw_scale); +#endif + } } } diff --git a/src/sounds.c b/src/sounds.c index adae99df5..b64dda5cb 100644 --- a/src/sounds.c +++ b/src/sounds.c @@ -408,13 +408,13 @@ sfxinfo_t S_sfx[NUMSFX] = {"s3k3b", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR}, {"s3k3c", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR}, {"s3k3d", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR}, - {"s3k3e", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR}, - {"s3k3f", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR}, + {"s3k3e", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR}, // Kart Flame Shield spawned + {"s3k3f", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR}, // Kart Bubble Shield spawned {"s3k40", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR}, - {"s3k41", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR}, - {"s3k42", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR}, // Kart Thunder Shield spawned - {"s3k43", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR}, - {"s3k44", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR}, + {"s3k41", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR}, // Kart Thunder Shield spawned + {"s3k42", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR}, + {"s3k43", false, 96, 48, -1, NULL, 0, -1, -1, LUMPERROR}, + {"s3k44", false, 96, 0, -1, NULL, 0, -1, -1, LUMPERROR}, // Kart Bubble Shield reflect {"s3k45", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR}, {"s3k46", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR}, {"s3k47", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR}, // Kart AIZ dust