diff --git a/src/d_player.h b/src/d_player.h index a5d73ec7..1eabeb6e 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -354,6 +354,7 @@ 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 NUMKARTSTUFF } kartstufftype_t; diff --git a/src/dehacked.c b/src/dehacked.c index e3db120f..231f0aa8 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -7150,6 +7150,13 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_KARMAFIREWORK4", "S_KARMAFIREWORKTRAIL", + // Opaque smoke version, to prevent lag + "S_OPAQUESMOKE1", + "S_OPAQUESMOKE2", + "S_OPAQUESMOKE3", + "S_OPAQUESMOKE4", + "S_OPAQUESMOKE5", + #ifdef SEENAMES "S_NAMECHECK", #endif @@ -8383,7 +8390,8 @@ static const char *const KARTSTUFF_LIST[] = { "ITEMBLINKMODE", "GETSPARKS", "JAWZTARGETDELAY", - "SPECTATEWAIT" + "SPECTATEWAIT", + "GROWCANCEL" }; #endif @@ -9887,6 +9895,9 @@ static inline int lib_getenum(lua_State *L) } else if (fastcmp(word,"indirectitemcooldown")) { lua_pushinteger(L, indirectitemcooldown); return 1; + } else if (fastcmp(word,"hyubgone")) { + lua_pushinteger(L, hyubgone); + return 1; } else if (fastcmp(word,"thwompsactive")) { lua_pushboolean(L, thwompsactive); return 1; diff --git a/src/doomstat.h b/src/doomstat.h index 9ae2726d..0f057273 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -468,6 +468,7 @@ extern boolean comeback; extern SINT8 battlewanted[4]; extern tic_t wantedcalcdelay; extern tic_t indirectitemcooldown; +extern tic_t hyubgone; extern tic_t mapreset; extern UINT8 nospectategrief; extern boolean thwompsactive; diff --git a/src/g_game.c b/src/g_game.c index 003c11e9..e6aeb9e7 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -267,6 +267,7 @@ SINT8 pickedvote; // What vote the host rolls SINT8 battlewanted[4]; // WANTED players in battle, worth x2 points tic_t wantedcalcdelay; // Time before it recalculates WANTED tic_t indirectitemcooldown; // Cooldown before any more Shrink, SPB, or any other item that works indirectly is awarded +tic_t hyubgone; // Cooldown before hyudoro is allowed to be rerolled tic_t mapreset; // Map reset delay when enough players have joined an empty game UINT8 nospectategrief; // How many players need to be in-game to eliminate last; for preventing spectate griefing boolean thwompsactive; // Thwomps activate on lap 2 diff --git a/src/info.c b/src/info.c index 5701f1c9..84cb4cd4 100644 --- a/src/info.c +++ b/src/info.c @@ -3140,11 +3140,11 @@ state_t states[NUMSTATES] = {SPR_NULL, 0, 1, {A_FZBoomSmoke}, 1, 0, S_FZEROBOOM12}, // S_FZEROBOOM11 {SPR_NULL, 0, 1, {A_FZBoomSmoke}, 0, 0, S_NULL}, // S_FZEROBOOM12 - {SPR_SMOK, FF_TRANS30, 30, {NULL}, 0, 0, S_FZSLOWSMOKE2}, // S_FZSLOWSMOKE1 - {SPR_SMOK, FF_TRANS30|1, 30, {NULL}, 0, 0, S_FZSLOWSMOKE3}, // S_FZSLOWSMOKE2 - {SPR_SMOK, FF_TRANS30|2, 30, {NULL}, 0, 0, S_FZSLOWSMOKE4}, // S_FZSLOWSMOKE3 - {SPR_SMOK, FF_TRANS30|3, 30, {NULL}, 0, 0, S_FZSLOWSMOKE5}, // S_FZSLOWSMOKE4 - {SPR_SMOK, FF_TRANS30|4, 30, {NULL}, 0, 0, S_NULL}, // S_FZSLOWSMOKE5 + {SPR_SMOK, 0, 30, {NULL}, 0, 0, S_FZSLOWSMOKE2}, // S_FZSLOWSMOKE1 + {SPR_SMOK, 1, 30, {NULL}, 0, 0, S_FZSLOWSMOKE3}, // S_FZSLOWSMOKE2 + {SPR_SMOK, 2, 30, {NULL}, 0, 0, S_FZSLOWSMOKE4}, // S_FZSLOWSMOKE3 + {SPR_SMOK, 3, 30, {NULL}, 0, 0, S_FZSLOWSMOKE5}, // S_FZSLOWSMOKE4 + {SPR_SMOK, 4, 30, {NULL}, 0, 0, S_NULL}, // S_FZSLOWSMOKE5 // Various plants {SPR_SBUS, 0, -1, {NULL}, 0, 0, S_NULL}, // S_SONICBUSH @@ -3394,6 +3394,13 @@ state_t states[NUMSTATES] = {SPR_FWRK, 3|FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_KARMAFIREWORK1}, // S_KARMAFIREWORK4 {SPR_FWRK, 4|FF_FULLBRIGHT, TICRATE, {NULL}, 0, 0, S_NULL}, // S_KARMAFIREWORKTRAIL + // Opaque smoke + {SPR_SMOK, 0, 4, {NULL}, 0, 0, S_OPAQUESMOKE2}, // S_OPAQUESMOKE1 + {SPR_SMOK, 1, 5, {NULL}, 0, 0, S_OPAQUESMOKE3}, // S_OPAQUESMOKE2 + {SPR_SMOK, 2, 6, {NULL}, 0, 0, S_OPAQUESMOKE4}, // S_OPAQUESMOKE3 + {SPR_SMOK, 3, 7, {NULL}, 0, 0, S_OPAQUESMOKE5}, // S_OPAQUESMOKE4 + {SPR_SMOK, 4, 8, {NULL}, 0, 0, S_NULL}, // S_OPAQUESMOKE5 + #ifdef SEENAMES {SPR_NULL, 0, 1, {NULL}, 0, 0, S_NULL}, // S_NAMECHECK #endif @@ -15574,7 +15581,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 1, // spawnhealth S_NULL, // seestate sfx_tossed, // seesound - 6*TICRATE, // reactiontime + 0, // reactiontime sfx_None, // attacksound S_NULL, // painstate 192*FRACUNIT, // painchance diff --git a/src/info.h b/src/info.h index 157c72e1..0e23a07c 100644 --- a/src/info.h +++ b/src/info.h @@ -4052,6 +4052,12 @@ typedef enum state S_KARMAFIREWORK4, S_KARMAFIREWORKTRAIL, + S_OPAQUESMOKE1, + S_OPAQUESMOKE2, + S_OPAQUESMOKE3, + S_OPAQUESMOKE4, + S_OPAQUESMOKE5, + #ifdef SEENAMES S_NAMECHECK, #endif diff --git a/src/k_kart.c b/src/k_kart.c index f5fe06bc..dee5df73 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -622,6 +622,11 @@ static INT32 K_KartItemOddsBattle[NUMKARTRESULTS][6] = */ static void K_KartGetItemResult(player_t *player, SINT8 getitem) { + if (getitem == KITEM_SPB || getitem == KITEM_SHRINK) // Indirect items + indirectitemcooldown = 20*TICRATE; + if (getitem == KITEM_HYUDORO) // Hyudoro cooldown + hyubgone = 5*TICRATE; + switch (getitem) { // Special roulettes first, then the generic ones are handled by default @@ -649,10 +654,6 @@ static void K_KartGetItemResult(player_t *player, SINT8 getitem) player->kartstuff[k_itemtype] = KITEM_JAWZ; player->kartstuff[k_itemamount] = 2; break; - case KITEM_SPB: - case KITEM_SHRINK: // Indirect items - indirectitemcooldown = 20*TICRATE; - /* FALLTHRU */ default: if (getitem <= 0 || getitem >= NUMKARTRESULTS) // Sad (Fallback) { @@ -674,12 +675,13 @@ static void K_KartGetItemResult(player_t *player, SINT8 getitem) \return void */ -static INT32 K_KartGetItemOdds(UINT8 pos, SINT8 item, fixed_t mashed) +static INT32 K_KartGetItemOdds(UINT8 pos, SINT8 item, fixed_t mashed, boolean spbrush) { const INT32 distvar = (64*14); INT32 newodds; INT32 i; UINT8 pingame = 0, pexiting = 0, pinvin = 0; + boolean thunderisout = false; SINT8 first = -1, second = -1; INT32 secondist = 0; boolean itemenabled[NUMKARTRESULTS-1] = { @@ -724,10 +726,13 @@ static INT32 K_KartGetItemOdds(UINT8 pos, SINT8 item, fixed_t mashed) { if (!playeringame[i] || players[i].spectator) continue; + if (!G_BattleGametype() || players[i].kartstuff[k_bumper]) pingame++; + if (players[i].exiting) pexiting++; + if (players[i].mo) { if (players[i].kartstuff[k_itemtype] == KITEM_INVINCIBILITY @@ -735,6 +740,10 @@ static INT32 K_KartGetItemOdds(UINT8 pos, SINT8 item, fixed_t mashed) || players[i].kartstuff[k_invincibilitytimer] || players[i].kartstuff[k_growshrinktimer] > 0) pinvin++; + + if (players[i].kartstuff[k_itemtype] == KITEM_THUNDERSHIELD) + thunderisout = true; + if (!G_BattleGametype()) { if (players[i].kartstuff[k_position] == 1 && first == -1) @@ -758,29 +767,35 @@ static INT32 K_KartGetItemOdds(UINT8 pos, SINT8 item, fixed_t mashed) // POWERITEMODDS handles all of the "frantic item" related functionality, for all of our powerful items. // First, it multiplies it by 2 if franticitems is true; easy-peasy. // Next, it multiplies it again if it's in SPB mode and 2nd needs to apply pressure to 1st. - // Then, it multiplies it further if there's less than 5 players in game. - // This is done to make low player count races more fair & interesting. (2P normal would be about halfway between 8P normal and 8P frantic) - // Lastly, it *divides* it by your mashed value, which was determined in K_KartItemRoulette, to punish those who are impatient. + // Then, it multiplies it further if the player count isn't equal to 8. + // This is done to make low player count races more interesting and high player count rates more fair. + // (2P normal would be about halfway between 8P normal and 8P frantic.) + // (This scaling is not done for SPB Rush, so that catchup strength is not weakened.) + // Lastly, it *divides* it by your mashed value, which was determined in K_KartItemRoulette, for lesser items needed in a pinch. + +#define PLAYERSCALING (8 - (spbrush ? 2 : pingame)) + #define POWERITEMODDS(odds) \ if (franticitems) \ odds <<= 1; \ - odds = FixedMul(odds<> FRACBITS; \ + odds = FixedMul(odds<> FRACBITS; \ if (mashed > 0) \ odds = FixedDiv(odds<> FRACBITS \ +#define COOLDOWNONSTART (leveltime < (30*TICRATE)+starttime) + switch (item) { case KITEM_INVINCIBILITY: case KITEM_GROW: - if (pinvin >= max(1, (pingame+2) / 4)) + if (pinvin >= max(1, (pingame+3) / 4) || COOLDOWNONSTART) newodds = 0; else - /* FALLTHRU */ + POWERITEMODDS(newodds); + break; case KITEM_ROCKETSNEAKER: case KITEM_JAWZ: - case KITEM_MINE: case KITEM_BALLHOG: - case KITEM_THUNDERSHIELD: case KRITEM_TRIPLESNEAKER: case KRITEM_TRIPLEBANANA: case KRITEM_TENFOLDBANANA: @@ -789,17 +804,32 @@ static INT32 K_KartGetItemOdds(UINT8 pos, SINT8 item, fixed_t mashed) case KRITEM_DUALJAWZ: POWERITEMODDS(newodds); break; + case KITEM_MINE: + if (COOLDOWNONSTART) + newodds = 0; + else + POWERITEMODDS(newodds); + break; case KITEM_SPB: - //POWERITEMODDS(newodds); if (((indirectitemcooldown > 0) || (pexiting > 0) || (secondist/distvar < 3)) && (pos != 9)) // Force SPB newodds = 0; else - newodds *= min((secondist/distvar)-4, 3); + newodds *= min((secondist/distvar)-4, 3); // POWERITEMODDS(newodds); break; case KITEM_SHRINK: - POWERITEMODDS(newodds); - if ((indirectitemcooldown > 0) || (pingame-1 <= pexiting)) + if ((indirectitemcooldown > 0) || (pingame-1 <= pexiting) || COOLDOWNONSTART) + newodds = 0; + else + POWERITEMODDS(newodds); + break; + case KITEM_THUNDERSHIELD: + if (thunderisout) + newodds = 0; + else + POWERITEMODDS(newodds); + case KITEM_HYUDORO: + if ((hyubgone > 0) || COOLDOWNONSTART) newodds = 0; break; default: @@ -835,7 +865,7 @@ static INT32 K_FindUseodds(player_t *player, fixed_t mashed, INT32 pingame, INT3 for (j = 1; j < NUMKARTRESULTS; j++) { - if (K_KartGetItemOdds(i, j, mashed) > 0) + if (K_KartGetItemOdds(i, j, mashed, spbrush) > 0) { available = true; break; @@ -941,6 +971,7 @@ static void K_KartItemRoulette(player_t *player, ticcmd_t *cmd) INT32 bestbumper = 0; fixed_t mashed = 0; boolean dontforcespb = false; + boolean spbrush = false; // This makes the roulette cycle through items - if this is 0, you shouldn't be here. if (player->kartstuff[k_itemroulette]) @@ -1033,15 +1064,18 @@ static void K_KartItemRoulette(player_t *player, ticcmd_t *cmd) return; } + if (G_RaceGametype()) + spbrush = (spbplace != -1 && player->kartstuff[k_position] == spbplace+1); + // Initializes existing spawnchance values for (i = 0; i < NUMKARTRESULTS; i++) spawnchance[i] = 0; // Split into another function for a debug function below - useodds = K_FindUseodds(player, mashed, pingame, bestbumper, (spbplace != -1 && player->kartstuff[k_position] == spbplace+1), dontforcespb); + useodds = K_FindUseodds(player, mashed, pingame, bestbumper, spbrush, dontforcespb); for (i = 1; i < NUMKARTRESULTS; i++) - spawnchance[i] = (totalspawnchance += K_KartGetItemOdds(useodds, i, mashed)); + spawnchance[i] = (totalspawnchance += K_KartGetItemOdds(useodds, i, mashed, spbrush)); // Award the player whatever power is rolled if (totalspawnchance > 0) @@ -2043,16 +2077,19 @@ void K_SpinPlayer(player_t *player, mobj_t *source, INT32 type, mobj_t *inflicto static void K_RemoveGrowShrink(player_t *player) { player->kartstuff[k_growshrinktimer] = 0; + player->kartstuff[k_growcancel] = 0; if (player->mo && !P_MobjWasRemoved(player->mo)) { if (player->kartstuff[k_invincibilitytimer] == 0) player->mo->color = player->skincolor; + player->mo->scalespeed = mapobjectscale/TICRATE; player->mo->destscale = mapobjectscale; if (cv_kartdebugshrink.value && !modeattacking && !player->bot) player->mo->destscale = (6*player->mo->destscale)/8; } + P_RestoreMusic(player); } @@ -2180,6 +2217,7 @@ void K_ExplodePlayer(player_t *player, mobj_t *source, mobj_t *inflictor) // A b #ifdef HAVE_BLUA boolean force = false; // Used to check if Lua ShouldExplode should get us damaged reguardless of flashtics or heck knows what. UINT8 shouldForce = LUAh_ShouldExplode(player, inflictor, source); + if (P_MobjWasRemoved(player->mo)) return; // mobj was removed (in theory that shouldn't happen) if (shouldForce == 1) @@ -2190,6 +2228,7 @@ void K_ExplodePlayer(player_t *player, mobj_t *source, mobj_t *inflictor) // A b #else static const boolean force = false; #endif + if (G_BattleGametype()) { if (K_IsPlayerWanted(player)) @@ -2271,13 +2310,13 @@ void K_ExplodePlayer(player_t *player, mobj_t *source, mobj_t *inflictor) // A b } player->kartstuff[k_spinouttype] = 1; - player->kartstuff[k_spinouttimer] = 2*TICRATE+(TICRATE/2); + player->kartstuff[k_spinouttimer] = (3*TICRATE/2)+2; player->powers[pw_flashing] = K_GetKartFlashing(player); if (inflictor && inflictor->type == MT_SPBEXPLOSION && inflictor->extravalue1) { - player->kartstuff[k_spinouttimer] = ((3*player->kartstuff[k_spinouttimer])/2)+1; + player->kartstuff[k_spinouttimer] = ((5*player->kartstuff[k_spinouttimer])/2)+1; player->mo->momz *= 2; } @@ -2476,6 +2515,7 @@ void K_SpawnMineExplosion(mobj_t *source, UINT8 color) for (i = 0; i < 32; i++) { dust = P_SpawnMobj(source->x, source->y, source->z, MT_SMOKE); + P_SetMobjState(dust, S_OPAQUESMOKE1); dust->angle = (ANGLE_180/16) * i; P_SetScale(dust, source->scale); dust->destscale = source->scale*10; @@ -2503,6 +2543,7 @@ void K_SpawnMineExplosion(mobj_t *source, UINT8 color) dust = P_SpawnMobj(source->x + P_RandomRange(-radius, radius)*FRACUNIT, source->y + P_RandomRange(-radius, radius)*FRACUNIT, source->z + P_RandomRange(0, height)*FRACUNIT, MT_SMOKE); + P_SetMobjState(dust, S_OPAQUESMOKE1); P_SetScale(dust, source->scale); dust->destscale = source->scale*10; dust->scalespeed = source->scale/12; @@ -2972,7 +3013,8 @@ static mobj_t *K_FindLastTrailMobj(player_t *player) static mobj_t *K_ThrowKartItem(player_t *player, boolean missile, mobjtype_t mapthing, INT32 defaultDir, INT32 altthrow) { mobj_t *mo; - INT32 dir, PROJSPEED; + INT32 dir; + fixed_t PROJSPEED; angle_t newangle; fixed_t newx, newy, newz; mobj_t *throwmo; @@ -3010,12 +3052,19 @@ static mobj_t *K_ThrowKartItem(player_t *player, boolean missile, mobjtype_t map { if (altthrow == 2) // Kitchen sink throwing { +#if 0 if (player->kartstuff[k_throwdir] == 1) dir = 3; else if (player->kartstuff[k_throwdir] == -1) dir = 1; else dir = 2; +#else + if (player->kartstuff[k_throwdir] == 1) + dir = 2; + else + dir = 1; +#endif } else { @@ -3089,12 +3138,14 @@ static mobj_t *K_ThrowKartItem(player_t *player, boolean missile, mobjtype_t map if (mo) { angle_t fa = player->mo->angle>>ANGLETOFINESHIFT; - INT32 HEIGHT = (20 + (dir*10))*mapobjectscale + player->mo->momz; + fixed_t HEIGHT = (20 + (dir*10))*mapobjectscale + player->mo->momz; - mo->momx = player->mo->momx + FixedMul(FINECOSINE(fa), (altthrow == 2 ? 2*PROJSPEED/3 : PROJSPEED)); - mo->momy = player->mo->momy + FixedMul(FINESINE(fa), (altthrow == 2 ? 2*PROJSPEED/3 : PROJSPEED)); + mo->momx = player->mo->momx + FixedMul(FINECOSINE(fa), PROJSPEED*dir); + mo->momy = player->mo->momy + FixedMul(FINESINE(fa), PROJSPEED*dir); mo->momz = P_MobjFlip(player->mo) * HEIGHT; + mo->extravalue2 = dir; + if (mo->eflags & MFE_UNDERWATER) mo->momz = (117 * mo->momz) / 200; @@ -3162,12 +3213,68 @@ static mobj_t *K_ThrowKartItem(player_t *player, boolean missile, mobjtype_t map if (player->mo->eflags & MFE_VERTICALFLIP) mo->eflags |= MFE_VERTICALFLIP; + + if (mapthing == MT_SSMINE) + mo->extravalue1 = 49; // Pads the start-up length from 21 frames to a full 2 seconds } } return mo; } +void K_PuntMine(mobj_t *thismine, mobj_t *punter) +{ + angle_t fa = R_PointToAngle2(0, 0, punter->momx, punter->momy) >> ANGLETOFINESHIFT; + fixed_t z = 30*mapobjectscale + punter->momz; + fixed_t spd; + mobj_t *mine; + + if (!thismine || P_MobjWasRemoved(thismine)) + return; + + if (thismine->type == MT_SSMINE_SHIELD) // Create a new mine + { + mine = P_SpawnMobj(thismine->x, thismine->y, thismine->z, MT_SSMINE); + P_SetTarget(&mine->target, thismine->target); + mine->angle = thismine->angle; + mine->flags2 = thismine->flags2; + mine->floorz = thismine->floorz; + mine->ceilingz = thismine->ceilingz; + P_RemoveMobj(thismine); + } + else + mine = thismine; + + if (!mine || P_MobjWasRemoved(mine)) + return; + + switch (gamespeed) + { + case 0: + spd = 68*mapobjectscale; // Avg Speed is 34 + break; + case 2: + spd = 96*mapobjectscale; // Avg Speed is 48 + break; + default: + spd = 82*mapobjectscale; // Avg Speed is 41 + break; + } + + mine->flags |= MF_NOCLIPTHING; + + P_SetMobjState(mine, S_SSMINE_AIR1); + mine->threshold = 10; + mine->extravalue1 = 0; + mine->reactiontime = mine->info->reactiontime; + + mine->momx = punter->momx + FixedMul(FINECOSINE(fa), spd); + mine->momy = punter->momy + FixedMul(FINESINE(fa), spd); + mine->momz = P_MobjFlip(mine) * z; + + mine->flags &= ~MF_NOCLIPTHING; +} + #define THUNDERRADIUS 320 static void K_DoThunderShield(player_t *player) @@ -3382,14 +3489,14 @@ static void K_DoShrink(player_t *user) { // Start shrinking! K_DropItems(&players[i]); + players[i].kartstuff[k_growshrinktimer] = -(20*TICRATE); - if (!P_MobjWasRemoved(players[i].mo)) + if (players[i].mo && !P_MobjWasRemoved(players[i].mo)) { players[i].mo->scalespeed = mapobjectscale/TICRATE; players[i].mo->destscale = (6*mapobjectscale)/8; if (cv_kartdebugshrink.value && !modeattacking && !players[i].bot) players[i].mo->destscale = (6*players[i].mo->destscale)/8; - players[i].kartstuff[k_growshrinktimer] = -(200+(40*(MAXPLAYERS-players[i].kartstuff[k_position]))); } } @@ -5127,6 +5234,18 @@ void K_MoveKartPlayer(player_t *player, boolean onground) if (player->kartstuff[k_rocketsneakertimer] < 1) player->kartstuff[k_rocketsneakertimer] = 1; } + // Grow Canceling + else if (player->kartstuff[k_growshrinktimer] > 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 (player->kartstuff[k_itemamount] <= 0) { player->kartstuff[k_itemamount] = player->kartstuff[k_itemheld] = 0; @@ -5483,6 +5602,9 @@ void K_MoveKartPlayer(player_t *player, boolean onground) if (player->kartstuff[k_itemtype] != KITEM_THUNDERSHIELD) player->kartstuff[k_curshield] = 0; + if (player->kartstuff[k_growshrinktimer] <= 0) + player->kartstuff[k_growcancel] = 0; + if (player->kartstuff[k_itemtype] == KITEM_SPB || player->kartstuff[k_itemtype] == KITEM_SHRINK || player->kartstuff[k_growshrinktimer] < 0) @@ -6547,6 +6669,8 @@ static void K_drawKartItem(void) //INT32 splitflags = K_calcSplitFlags(V_SNAPTOTOP|V_SNAPTOLEFT); const INT32 numberdisplaymin = ((!offset && stplyr->kartstuff[k_itemtype] == KITEM_ORBINAUT) ? 5 : 2); INT32 itembar = 0; + INT32 maxl = 0; // itembar's normal highest value + const INT32 barlength = (splitscreen > 1 ? 12 : 26); UINT8 localcolor = SKINCOLOR_NONE; SINT8 colormode = TC_RAINBOW; UINT8 *colmap = NULL; @@ -6655,6 +6779,8 @@ static void K_drawKartItem(void) else if (stplyr->kartstuff[k_rocketsneakertimer] > 1) { itembar = stplyr->kartstuff[k_rocketsneakertimer]; + maxl = (itemtime*3) - barlength; + if (leveltime & 1) localpatch = kp_rocketsneaker[offset]; else @@ -6662,6 +6788,12 @@ static void K_drawKartItem(void) } else if (stplyr->kartstuff[k_growshrinktimer] > 0) { + if (stplyr->kartstuff[k_growcancel]) + { + itembar = stplyr->kartstuff[k_growcancel]; + maxl = 26; + } + if (leveltime & 1) localpatch = kp_grow[offset]; else @@ -6813,8 +6945,6 @@ static void K_drawKartItem(void) // Extensible meter, currently only used for rocket sneaker... if (itembar && hudtrans) { - const INT32 barlength = (splitscreen > 1 ? 12 : 26); - const INT32 maxl = (itemtime*3) - barlength; // timer's normal highest value const INT32 fill = ((itembar*barlength)/maxl); const INT32 length = min(barlength, fill); const INT32 height = (offset ? 1 : 2); @@ -7751,8 +7881,12 @@ static void K_drawKartMinimapHead(mobj_t *mo, INT32 x, INT32 y, INT32 flags, pat else colormap = R_GetTranslationColormap(skin, mo->color, GTC_CACHE); V_DrawFixedPatch(amxpos, amypos, FRACUNIT, flags, facemmapprefix[skin], colormap); - if (mo->player && K_IsPlayerWanted(mo->player)) + if (mo->player + && ((G_RaceGametype() && mo->player->kartstuff[k_position] == spbplace) + || (G_BattleGametype() && K_IsPlayerWanted(mo->player)))) + { V_DrawFixedPatch(amxpos - (4<kartstuff[k_position] == spbplace+1), dontforcespb); + if (G_RaceGametype()) + spbrush = (spbplace != -1 && stplyr->kartstuff[k_position] == spbplace+1); + + useodds = K_FindUseodds(stplyr, 0, pingame, bestbumper, spbrush, dontforcespb); for (i = 1; i < NUMKARTRESULTS; i++) { - const INT32 itemodds = K_KartGetItemOdds(useodds, i, 0); + const INT32 itemodds = K_KartGetItemOdds(useodds, i, 0, spbrush); if (itemodds <= 0) continue; diff --git a/src/k_kart.h b/src/k_kart.h index e193b662..9bf12d98 100644 --- a/src/k_kart.h +++ b/src/k_kart.h @@ -41,6 +41,7 @@ void K_SpawnBoostTrail(player_t *player); void K_SpawnSparkleTrail(mobj_t *mo); void K_SpawnWipeoutTrail(mobj_t *mo, boolean translucent); void K_DriftDustHandling(mobj_t *spawner); +void K_PuntMine(mobj_t *mine, mobj_t *punter); void K_DoSneaker(player_t *player, INT32 type); void K_DoPogoSpring(mobj_t *mo, fixed_t vertispeed, UINT8 sound); void K_KillBananaChain(mobj_t *banana, mobj_t *inflictor, mobj_t *source); diff --git a/src/p_inter.c b/src/p_inter.c index dd27858f..7da581a5 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -411,6 +411,12 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) 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); diff --git a/src/p_map.c b/src/p_map.c index ccb66676..843f588c 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -853,7 +853,7 @@ static boolean PIT_CheckThing(mobj_t *thing) if (thing->type == MT_PLAYER) { - S_StartSound(NULL, sfx_cgot); //let all players hear it. + S_StartSound(NULL, sfx_bsnipe); //let all players hear it. HU_SetCEchoFlags(0); HU_SetCEchoDuration(5); HU_DoCEcho(va("%s\\was hit by a kitchen sink.\\\\\\\\", player_names[thing->player-players])); @@ -915,6 +915,10 @@ static boolean PIT_CheckThing(mobj_t *thing) if (thing->type == MT_PLAYER) { + // Banana snipe! + if (tmthing->type == MT_BANANA && tmthing->health > 1) + S_StartSound(thing, sfx_bsnipe); + // Player Damage K_SpinPlayer(thing->player, tmthing->target, 0, tmthing, (tmthing->type == MT_BANANA || tmthing->type == MT_BANANA_SHIELD)); @@ -983,7 +987,12 @@ static boolean PIT_CheckThing(mobj_t *thing) if (thing->type == MT_PLAYER) { - P_KillMobj(tmthing, thing, thing); + // Bomb punting + if ((tmthing->state >= &states[S_SSMINE1] && tmthing->state <= &states[S_SSMINE4]) + || (tmthing->state >= &states[S_SSMINE_DEPLOY8] && tmthing->state <= &states[S_SSMINE_DEPLOY13])) + P_KillMobj(tmthing, thing, thing); + else + K_PuntMine(tmthing, thing); } else if (thing->type == MT_ORBINAUT || thing->type == MT_JAWZ || thing->type == MT_JAWZ_DUD || thing->type == MT_ORBINAUT_SHIELD || thing->type == MT_JAWZ_SHIELD) @@ -1062,6 +1071,10 @@ static boolean PIT_CheckThing(mobj_t *thing) if (tmthing->health <= 0 || thing->health <= 0) return true; + // Banana snipe! + if (thing->type == MT_BANANA && thing->health > 1) + S_StartSound(tmthing, sfx_bsnipe); + // Player Damage K_SpinPlayer(tmthing->player, thing->target, 0, tmthing, (thing->type == MT_BANANA || thing->type == MT_BANANA_SHIELD)); @@ -1085,7 +1098,12 @@ static boolean PIT_CheckThing(mobj_t *thing) if (tmthing->health <= 0 || thing->health <= 0) return true; - P_KillMobj(thing, tmthing, tmthing); + // Bomb punting + if ((thing->state >= &states[S_SSMINE1] && thing->state <= &states[S_SSMINE4]) + || (thing->state >= &states[S_SSMINE_DEPLOY8] && thing->state <= &states[S_SSMINE_DEPLOY13])) + P_KillMobj(thing, tmthing, tmthing); + else + K_PuntMine(thing, tmthing); } else if (thing->type == MT_MINEEXPLOSION && tmthing->player) { diff --git a/src/p_mobj.c b/src/p_mobj.c index fd42a1d7..7f4e747c 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -1404,11 +1404,14 @@ fixed_t P_GetMobjGravity(mobj_t *mo) break; case MT_BANANA: case MT_EGGMANITEM: + case MT_SSMINE: + case MT_SINK: + if (mo->extravalue2 > 0) + gravityadd *= mo->extravalue2; + /* FALLTHRU */ case MT_ORBINAUT: case MT_JAWZ: case MT_JAWZ_DUD: - case MT_SSMINE: - case MT_SINK: gravityadd = (5*gravityadd)/2; break; case MT_SIGN: @@ -6651,6 +6654,7 @@ void P_MobjThinker(mobj_t *mobj) fixed_t y = P_RandomRange(-35, 35)*mobj->scale; fixed_t z = P_RandomRange(0, 70)*mobj->scale; mobj_t *smoke = P_SpawnMobj(mobj->x + x, mobj->y + y, mobj->z + z, MT_SMOKE); + P_SetMobjState(smoke, S_OPAQUESMOKE1); smoke->scale = mobj->scale * 2; smoke->destscale = mobj->scale * 6; smoke->momz = P_RandomRange(4, 9)*FRACUNIT; @@ -6672,6 +6676,7 @@ void P_MobjThinker(mobj_t *mobj) else { mobj_t *smoke = P_SpawnMobj(mobj->x + x, mobj->y + y, mobj->z + z, MT_SMOKE); + P_SetMobjState(smoke, S_OPAQUESMOKE1); smoke->scale = mobj->scale; smoke->destscale = mobj->scale*2; } @@ -8190,28 +8195,26 @@ void P_MobjThinker(mobj_t *mobj) mobj->color = mobj->target->player->skincolor; else mobj->color = SKINCOLOR_KETCHUP; + if (mobj->momx || mobj->momy) P_SpawnGhostMobj(mobj); - if (P_IsObjectOnGround(mobj)) + + if (P_IsObjectOnGround(mobj) && (mobj->state == &states[S_SSMINE_AIR1] || mobj->state == &states[S_SSMINE_AIR2])) { - if (mobj->state == &states[S_SSMINE_AIR1] || mobj->state == &states[S_SSMINE_AIR2]) - P_SetMobjState(mobj, S_SSMINE_DEPLOY1); - if (mobj->reactiontime >= mobj->info->reactiontime) + if (mobj->extravalue1 > 0) + mobj->extravalue1--; + else { mobj->momx = mobj->momy = 0; S_StartSound(mobj, mobj->info->activesound); - mobj->reactiontime--; + P_SetMobjState(mobj, S_SSMINE_DEPLOY1); } } - if (mobj->reactiontime && mobj->reactiontime < mobj->info->reactiontime) - { - mobj->reactiontime--; - if (!mobj->reactiontime) - P_KillMobj(mobj, NULL, NULL); - } + if ((mobj->state >= &states[S_SSMINE1] && mobj->state <= &states[S_SSMINE4]) || (mobj->state >= &states[S_SSMINE_DEPLOY8] && mobj->state <= &states[S_SSMINE_DEPLOY13])) A_GrenadeRing(mobj); + if (mobj->threshold > 0) mobj->threshold--; break; diff --git a/src/p_saveg.c b/src/p_saveg.c index 71bb5668..0f199f8c 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -3320,6 +3320,7 @@ static void P_NetArchiveMisc(void) WRITEUINT32(save_p, wantedcalcdelay); WRITEUINT32(save_p, indirectitemcooldown); + WRITEUINT32(save_p, hyubgone); WRITEUINT32(save_p, mapreset); WRITEUINT8(save_p, nospectategrief); WRITEUINT8(save_p, thwompsactive); @@ -3428,6 +3429,7 @@ static inline boolean P_NetUnArchiveMisc(void) wantedcalcdelay = READUINT32(save_p); indirectitemcooldown = READUINT32(save_p); + hyubgone = READUINT32(save_p); mapreset = READUINT32(save_p); nospectategrief = READUINT8(save_p); thwompsactive = (boolean)READUINT8(save_p); diff --git a/src/p_setup.c b/src/p_setup.c index 1acfb7a3..ba4554e6 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -3243,6 +3243,7 @@ boolean P_SetupLevel(boolean skipprecip) wantedcalcdelay = wantedfrequency*2; indirectitemcooldown = 0; + hyubgone = 0; mapreset = 0; nospectategrief = 0; thwompsactive = false; diff --git a/src/p_tick.c b/src/p_tick.c index b46b248b..85eaea9b 100644 --- a/src/p_tick.c +++ b/src/p_tick.c @@ -680,6 +680,8 @@ void P_Ticker(boolean run) if (indirectitemcooldown) indirectitemcooldown--; + if (hyubgone) + hyubgone--; if (G_BattleGametype()) { diff --git a/src/sounds.c b/src/sounds.c index a3bc8bf4..61fddb76 100644 --- a/src/sounds.c +++ b/src/sounds.c @@ -815,6 +815,7 @@ sfxinfo_t S_sfx[NUMSFX] = {"chain", false, 255, 8, -1, NULL, 0, -1, -1, LUMPERROR}, // Mementos Reaper {"mkuma", false, 96, 8, -1, NULL, 0, -1, -1, LUMPERROR}, // Trigger Happy Havoc Monokuma {"toada", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR}, // Arid Sands Toad scream + {"bsnipe", false, 96, 8, -1, NULL, 0, -1, -1, LUMPERROR}, // Banana sniping {"itfree", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR}, // :shitsfree: {"dbgsal", false, 255, 8, -1, NULL, 0, -1, -1, LUMPERROR}, // Debug notification diff --git a/src/sounds.h b/src/sounds.h index 4c341d49..bb46ea9d 100644 --- a/src/sounds.h +++ b/src/sounds.h @@ -890,6 +890,7 @@ typedef enum sfx_chain, sfx_mkuma, sfx_toada, + sfx_bsnipe, sfx_itfree, sfx_dbgsal,