diff --git a/src/d_netcmd.c b/src/d_netcmd.c index ac05208a8..7634c68b0 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -5569,7 +5569,7 @@ static void Got_GiveItemcmd(UINT8 **cp, INT32 playernum) } K_StripItems(&players[playernum]); - players[playernum].itemroulette = 0; + players[playernum].itemroulette = KROULETTE_DISABLED; players[playernum].itemtype = item; players[playernum].itemamount = amt; diff --git a/src/d_player.h b/src/d_player.h index 7b5e2b5a3..674a69e92 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -185,6 +185,23 @@ typedef enum NUMKARTRESULTS } kartitems_t; +typedef enum { + KROULETTE_DISABLED, + KROULETTE_ACTIVE, +} kartroulette_t; + +typedef enum { + KROULETTETYPE_NORMAL, + KROULETTETYPE_KARMA, + KROULETTETYPE_EGGMAN, +} kartroulettetype_t; + +typedef enum { + KITEMBLINKMODE_NORMAL, + KITEMBLINKMODE_MASHED, + KITEMBLINKMODE_KARMA, +} kartitemblinkmode_t; + typedef enum { KSHIELD_NONE = 0, diff --git a/src/deh_tables.c b/src/deh_tables.c index 0a35ee43c..7e5bfd2c6 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -1451,6 +1451,20 @@ struct int_const_s const INT_CONST[] = { // kartitems_t {"KITEM_LIGHTNINGSHIELD",KITEM_THUNDERSHIELD}, + // kartroulette_t + {"KROULETTE_DISABLED",KROULETTE_DISABLED}, + {"KROULETTE_ACTIVE",KROULETTE_ACTIVE}, + + // kartroulettetype_t + {"KROULETTETYPE_NORMAL",KROULETTETYPE_NORMAL}, + {"KROULETTETYPE_KARMA",KROULETTETYPE_KARMA}, + {"KROULETTETYPE_EGGMAN",KROULETTETYPE_EGGMAN}, + + // kartitemblinkmode_t + {"KITEMBLINKMODE_NORMAL",KITEMBLINKMODE_NORMAL}, + {"KITEMBLINKMODE_MASHED",KITEMBLINKMODE_MASHED}, + {"KITEMBLINKMODE_KARMA",KITEMBLINKMODE_KARMA}, + // kartspinoutflags_t {"KSPIN_THRUST",KSPIN_THRUST}, {"KSPIN_IFRAMES",KSPIN_IFRAMES}, diff --git a/src/g_game.c b/src/g_game.c index cdf4e70a6..3f36d9862 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -2439,9 +2439,9 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps) // SRB2kart if (betweenmaps || leveltime <= starttime || spectator == true) { - itemroulette = 0; - previtemroulette = 0; - roulettetype = 0; + itemroulette = KROULETTE_DISABLED; + previtemroulette = KROULETTE_DISABLED; + roulettetype = KROULETTETYPE_NORMAL; itemtype = 0; itemamount = 0; growshrinktimer = 0; @@ -2473,8 +2473,8 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps) } else { - itemroulette = (players[player].itemroulette > 0 ? 1 : 0); - previtemroulette = (players[player].previtemroulette > 0 ? 1 : 0); + itemroulette = (players[player].itemroulette > KROULETTE_DISABLED ? KROULETTE_ACTIVE : KROULETTE_DISABLED); + previtemroulette = (players[player].previtemroulette > KROULETTE_DISABLED ? KROULETTE_ACTIVE : KROULETTE_DISABLED); roulettetype = players[player].roulettetype; if (players[player].itemflags & IF_ITEMOUT) diff --git a/src/k_bot.cpp b/src/k_bot.cpp index c96b4a708..e7feb6792 100644 --- a/src/k_bot.cpp +++ b/src/k_bot.cpp @@ -1067,6 +1067,8 @@ static void K_WaypointGetDirectionVector(waypoint_t *wp1, waypoint_t *wp2, vecto FV3_Normalize(a_o); } +#define MINBOTDRIFT (KART_FULLTURN * 2) / 3 // 0.66 + /*-------------------------------------------------- static INT32 K_BotStartDrift(player_t* player) @@ -1282,6 +1284,11 @@ static INT32 K_HandleBotTrack(player_t *player, ticcmd_t *cmd, botprediction_t * turnamt = 0; } + fixed_t minspeed = (10 * player->mo->scale); + + // 0.5 on Easy, 1.0 on Normal, 1.5 on Hard. + INT32 mindriftamt = FixedMul(MINBOTDRIFT * (cv_kartspeed.value + 1), 2 * FRACUNIT); + // Start or continue a drift. if (player->botvars.drifttime) { @@ -1291,6 +1298,18 @@ static INT32 K_HandleBotTrack(player_t *player, ticcmd_t *cmd, botprediction_t * { turnamt = KART_FULLTURN * -player->botvars.driftturn; } + else if ((player->botvars.powersliding) && (player->speed >= minspeed)) + { + // Force a mostly inward drift during powerslides. + if (player->botvars.driftturn < 0) + { + turnamt = std::min(KART_FULLTURN, std::max(mindriftamt, turnamt)); + } + else + { + turnamt = std::min(-MINBOTDRIFT, std::max(-mindriftamt, turnamt)); + } + } cmd->buttons |= BT_DRIFT; } @@ -1313,6 +1332,8 @@ static INT32 K_HandleBotTrack(player_t *player, ticcmd_t *cmd, botprediction_t * return turnamt; } +#undef MINBOTDRIFT + /*-------------------------------------------------- static INT32 K_HandleBotReverse(const player_t *player, ticcmd_t *cmd, botprediction_t *predict) diff --git a/src/k_collide.c b/src/k_collide.c index e24950cde..bc08097f7 100644 --- a/src/k_collide.c +++ b/src/k_collide.c @@ -242,8 +242,8 @@ boolean K_EggItemCollide(mobj_t *t1, mobj_t *t2) { K_DropItems(t2->player); //K_StripItems(t2->player); //K_StripOther(t2->player); - t2->player->itemroulette = 1; - t2->player->roulettetype = 2; + t2->player->itemroulette = KROULETTE_ACTIVE; + t2->player->roulettetype = KROULETTETYPE_EGGMAN; } if (t2->player->flamestore && t2->player->itemtype == KITEM_FLAMESHIELD) diff --git a/src/k_hud.c b/src/k_hud.c index 701ec7bdc..182c5d9b3 100644 --- a/src/k_hud.c +++ b/src/k_hud.c @@ -4297,44 +4297,48 @@ K_drawMiniPing (void) } } +static patch_t *K_GetSmallStaticCachedItemPatch(kartitems_t item) +{ + UINT8 offset; + + item = K_ItemResultToType(item); + + switch (item) + { + case KITEM_INVINCIBILITY: + offset = 7; + break; + + case KITEM_BANANA: + offset = 4; + break; + + case KITEM_ORBINAUT: + offset = 4; + break; + + case KITEM_JAWZ: + offset = 2; + break; + + case KITEM_SNEAKER: + offset = 3; + break; + + default: + offset = 1; + } + + return K_GetCachedItemPatch(item, offset); +} + static void K_drawDistributionDebugger(void) { - patch_t *items[NUMKARTRESULTS] = { - kp_sadface[1], - kp_sneaker[3], - kp_rocketsneaker[1], - kp_invincibility[7], - kp_banana[4], - kp_eggman[1], - kp_orbinaut[4], - kp_jawz[2], - kp_mine[1], - kp_ballhog[1], - kp_selfpropelledbomb[1], - kp_grow[1], - kp_shrink[1], - kp_thundershield[1], - kp_hyudoro[1], - kp_pogospring[1], - kp_kitchensink[1], - kp_superring[1], - kp_landmine[1], - kp_bubbleshield[1], - kp_flameshield[1], - kp_droptarget[1], - - kp_sneaker[3], - kp_sneaker[3], - kp_banana[4], - kp_banana[4], - kp_orbinaut[4], - kp_orbinaut[4], - kp_jawz[2] - }; UINT8 useodds = 0; UINT8 pingame = 0, bestbumper = 0; UINT32 pdis = 0; INT32 i; + INT32 item; INT32 x = -9, y = -9; boolean dontforcespb = false; boolean spbrush = false; @@ -4354,7 +4358,7 @@ static void K_drawDistributionDebugger(void) bestbumper = players[i].bumper; } - if (!(K_UsingLegacyCheckpoints())) + if (!K_UsingLegacyCheckpoints()) { // lovely double loop...... for (i = 0; i < MAXPLAYERS; i++) @@ -4368,6 +4372,123 @@ static void K_drawDistributionDebugger(void) } } } + else + { + // Pain and fucking suffering. + SINT8 sortedPlayers[MAXPLAYERS]; + UINT8 sortLength = 0; + + memset(sortedPlayers, -1, sizeof(sortedPlayers)); + + if (stplyr->mo != NULL && P_MobjWasRemoved(stplyr->mo) == false) + { + // Sort all of the players ahead of you. + // Then tally up their distances in a conga line. + + // This will create a much more consistent item + // distance algorithm than the "spider web" thing + // that it was doing before. + + // Add yourself to the list. + // You'll always be the end of the list, + // so we can also calculate the length here. + sortedPlayers[ stplyr->position - 1 ] = stplyr - players; + sortLength = stplyr->position; + + // Will only need to do this if there's goint to be + // more than yourself in the list. + if (sortLength > 1) + { + SINT8 firstIndex = -1; + SINT8 secondIndex = -1; + INT32 startFrom = INT32_MAX; + + // Add all of the other players. + for (i = 0; i < MAXPLAYERS; i++) + { + INT32 pos = INT32_MAX; + + if (!playeringame[i] || players[i].spectator) + { + continue; + } + + if (players[i].mo == NULL || P_MobjWasRemoved(players[i].mo) == true) + { + continue; + } + + pos = players[i].position; + + if (pos <= 0 || pos > MAXPLAYERS) + { + // Invalid position. + continue; + } + + if (pos >= stplyr->position) + { + // Tied / behind us. + // Also handles ourselves, obviously. + continue; + } + + // Ties are done with port priority, if there are any. + if (sortedPlayers[ pos - 1 ] == -1) + { + sortedPlayers[ pos - 1 ] = i; + } + } + + // The chance of this list having gaps is improbable, + // but not impossible. So we need to spend some extra time + // to prevent the gaps from mattering. + for (i = 0; i < sortLength-1; i++) + { + if (sortedPlayers[i] >= 0 && sortedPlayers[i] < MAXPLAYERS) + { + // First valid index in the list found. + firstIndex = sortedPlayers[i]; + + // Start the next loop after this player. + startFrom = i + 1; + break; + } + } + + if (firstIndex >= 0 && firstIndex < MAXPLAYERS + && startFrom < sortLength) + { + // First index is valid, so we can + // start comparing the players. + + player_t *firstPlayer = NULL; + player_t *secondPlayer = NULL; + + for (i = startFrom; i < sortLength; i++) + { + if (sortedPlayers[i] >= 0 && sortedPlayers[i] < MAXPLAYERS) + { + secondIndex = sortedPlayers[i]; + + firstPlayer = &players[firstIndex]; + secondPlayer = &players[secondIndex]; + + // Add the distance to the player behind you. + pdis += P_AproxDistance(P_AproxDistance( + firstPlayer->mo->x - secondPlayer->mo->x, + firstPlayer->mo->y - secondPlayer->mo->y), + firstPlayer->mo->z - secondPlayer->mo->z) / FRACUNIT; + + // Advance to next index. + firstIndex = secondIndex; + } + } + } + } + } + + } if (spbplace != -1 && stplyr->position == spbplace+1) { @@ -4377,17 +4498,12 @@ static void K_drawDistributionDebugger(void) spbrush = true; } + pdis = K_ScaleItemDistance(pdis, pingame, spbrush); - if (!(K_UsingLegacyCheckpoints())) + if (stplyr->bot && stplyr->botvars.rival) { - - pdis = K_ScaleItemDistance(pdis, pingame, spbrush); - - if (stplyr->bot && stplyr->botvars.rival) - { - // Rival has better odds :) - pdis = (15 * pdis) / 14; - } + // Rival has better odds :) + pdis = (15 * pdis) / 14; } if (K_UsingLegacyCheckpoints()) @@ -4398,31 +4514,30 @@ static void K_drawDistributionDebugger(void) if (pingame == 1) { if (stplyr->itemroulette && (stplyr->cmd.buttons & BT_ATTACK) && cv_superring.value && (K_RingsActive() == true)) - V_DrawScaledPatch(x, y, V_SPLITSCREEN|V_HUDTRANS|V_SNAPTOTOP, kp_superring[1]); + V_DrawScaledPatch(x, y, V_SPLITSCREEN|V_HUDTRANS|V_SNAPTOTOP, K_GetSmallStaticCachedItemPatch(KITEM_SUPERRING)); else - V_DrawScaledPatch(x, y, V_SPLITSCREEN|V_HUDTRANS|V_SNAPTOTOP, items[1]); + V_DrawScaledPatch(x, y, V_SPLITSCREEN|V_HUDTRANS|V_SNAPTOTOP, K_GetSmallStaticCachedItemPatch(KITEM_SNEAKER)); V_DrawThinString(x+11, y+31, V_SPLITSCREEN|V_HUDTRANS|V_SNAPTOTOP, va("%d", 200)); } else if (useodds == 69) { - V_DrawScaledPatch(x, y, V_SPLITSCREEN|V_HUDTRANS|V_SNAPTOTOP, items[11]); + V_DrawScaledPatch(x, y, V_SPLITSCREEN|V_HUDTRANS|V_SNAPTOTOP, K_GetSmallStaticCachedItemPatch(KITEM_SPB)); V_DrawThinString(x+11, y+31, V_SPLITSCREEN|V_HUDTRANS|V_SNAPTOTOP, va("%d", 200)); } else { - for (i = 1; i < NUMKARTRESULTS; i++) + for (item = 1; item < NUMKARTRESULTS; item++) { INT32 itemodds; - - + INT32 amount; if (K_UsingLegacyCheckpoints()) - itemodds = K_KartGetLegacyItemOdds(useodds, i, 0, spbrush); + itemodds = K_KartGetLegacyItemOdds(useodds, item, 0, spbrush); else itemodds = K_KartGetItemOdds( - useodds, i, + useodds, item, stplyr->distancetofinish, 0, spbrush, stplyr->bot, (stplyr->bot && stplyr->botvars.rival) @@ -4431,34 +4546,17 @@ static void K_drawDistributionDebugger(void) if (itemodds <= 0) continue; - V_DrawScaledPatch(x, y, V_SPLITSCREEN|V_HUDTRANS|V_SNAPTOTOP, items[i]); + V_DrawScaledPatch(x, y, V_SPLITSCREEN|V_HUDTRANS|V_SNAPTOTOP, K_GetSmallStaticCachedItemPatch(item)); V_DrawThinString(x+11, y+31, V_SPLITSCREEN|V_HUDTRANS|V_SNAPTOTOP, va("%d", itemodds)); // Display amount for multi-items - if (i >= NUMKARTITEMS) + amount = K_ItemResultToAmount(item); + if (amount > 1) { - INT32 amount; - switch (i) - { - case KRITEM_TENFOLDBANANA: - amount = 10; - break; - case KRITEM_QUADORBINAUT: - amount = 4; - break; - case KRITEM_DUALJAWZ: - amount = 2; - break; - case KRITEM_DUALSNEAKER: - amount = 2; - break; - default: - amount = 3; - break; - } V_DrawString(x+24, y+31, V_SPLITSCREEN|V_ALLOWLOWERCASE|V_HUDTRANS|V_SNAPTOTOP, va("x%d", amount)); } + x += 32; if (x >= 297) { @@ -4475,6 +4573,8 @@ static void K_drawDistributionDebugger(void) else V_DrawString(0, 0, V_SPLITSCREEN|V_HUDTRANS|V_SNAPTOTOP, va("USEODDS %d", useodds)); + V_DrawString(150, 0, V_SPLITSCREEN|V_HUDTRANS|V_SNAPTOTOP, va("PDIS %d", pdis)); + if (K_UsingLegacyCheckpoints()) V_DrawSmallString(70, 0, V_SPLITSCREEN|V_HUDTRANS|V_SNAPTOTOP, "Legacy Distance Mode"); diff --git a/src/k_kart.c b/src/k_kart.c index 2e92d3741..d81e5dbce 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -523,6 +523,70 @@ INT32 K_GetShieldFromItem(INT32 item) } } +SINT8 K_ItemResultToType(SINT8 getitem) +{ + if (getitem <= 0 || getitem >= NUMKARTRESULTS) // Sad (Fallback) + { + if (getitem != 0) + { + CONS_Printf("ERROR: K_GetItemResultToItemType - Item roulette gave bad item (%d) :(\n", getitem); + } + + return KITEM_SAD; + } + + if (getitem >= NUMKARTITEMS) + { + switch (getitem) + { + case KRITEM_DUALSNEAKER: + case KRITEM_TRIPLESNEAKER: + return KITEM_SNEAKER; + + case KRITEM_TRIPLEBANANA: + case KRITEM_TENFOLDBANANA: + return KITEM_BANANA; + + case KRITEM_TRIPLEORBINAUT: + case KRITEM_QUADORBINAUT: + return KITEM_ORBINAUT; + + case KRITEM_DUALJAWZ: + return KITEM_JAWZ; + + default: + I_Error("Bad item redirect for result %d\n", getitem); + break; + } + } + + return getitem; +} + +UINT8 K_ItemResultToAmount(SINT8 getitem) +{ + switch (getitem) + { + case KRITEM_DUALSNEAKER: + case KRITEM_DUALJAWZ: + return 2; + + case KRITEM_TRIPLESNEAKER: + case KRITEM_TRIPLEBANANA: + case KRITEM_TRIPLEORBINAUT: + return 3; + + case KRITEM_QUADORBINAUT: + return 4; + + case KRITEM_TENFOLDBANANA: + return 10; + + default: + return 1; + } +} + /** \brief Item Roulette for Kart \param player player @@ -541,49 +605,11 @@ static void K_KartGetItemResult(player_t *player, SINT8 getitem) player->botvars.itemdelay = TICRATE; player->botvars.itemconfirm = 0; - switch (getitem) - { - // Special roulettes first, then the generic ones are handled by default - case KRITEM_DUALSNEAKER: // Sneaker x2 - player->itemtype = KITEM_SNEAKER; - player->itemamount = 2; - break; - case KRITEM_TRIPLESNEAKER: // Sneaker x3 - player->itemtype = KITEM_SNEAKER; - player->itemamount = 3; - break; - case KRITEM_TRIPLEBANANA: // Banana x3 - player->itemtype = KITEM_BANANA; - player->itemamount = 3; - break; - case KRITEM_TENFOLDBANANA: // Banana x10 - player->itemtype = KITEM_BANANA; - player->itemamount = 10; - break; - case KRITEM_TRIPLEORBINAUT: // Orbinaut x3 - player->itemtype = KITEM_ORBINAUT; - player->itemamount = 3; - break; - case KRITEM_QUADORBINAUT: // Orbinaut x4 - player->itemtype = KITEM_ORBINAUT; - player->itemamount = 4; - break; - case KRITEM_DUALJAWZ: // Jawz x2 - player->itemtype = KITEM_JAWZ; - player->itemamount = 2; - break; - default: - if (getitem <= 0 || getitem >= NUMKARTRESULTS) // Sad (Fallback) - { - if (getitem != 0) - CONS_Printf("ERROR: P_KartGetItemResult - Item roulette gave bad item (%d) :(\n", getitem); - player->itemtype = KITEM_SAD; - } - else - player->itemtype = getitem; - player->itemamount = 1; - break; - } + player->itemtype = K_ItemResultToType(getitem); + UINT8 itemamount = K_ItemResultToAmount(getitem); + if (cv_kartdebugitem.value != KITEM_NONE && cv_kartdebugitem.value == player->itemtype && cv_kartdebugamount.value > 1) + itemamount = cv_kartdebugamount.value; + player->itemamount = itemamount; } fixed_t K_ItemOddsScale(UINT8 numPlayers, boolean spbrush) @@ -1118,7 +1144,7 @@ UINT8 K_FindUseodds(player_t *player, fixed_t mashed, UINT32 pdis, UINT8 bestbum if (gametyperules & GTR_BATTLEODDS) // Battle Mode { - if (player->roulettetype == 1 && oddsvalid[1] == true) + if (player->roulettetype == KROULETTETYPE_KARMA && oddsvalid[1] == true) { // 1 is the extreme odds of player-controlled "Karma" items useodds = 1; @@ -1327,7 +1353,7 @@ INT32 K_FindLegacyUseodds(player_t *player, fixed_t mashed, INT32 pingame, INT32 if (gametyperules & GTR_BATTLEODDS) // Battle Mode { - if (player->roulettetype == 1 && oddsvalid[1] == true) + if (player->roulettetype == KROULETTETYPE_KARMA && oddsvalid[1] == true) { // 1 is the extreme odds of player-controlled "Karma" items useodds = 1; @@ -1356,6 +1382,12 @@ INT32 K_FindLegacyUseodds(player_t *player, fixed_t mashed, INT32 pingame, INT32 pdis = K_ScaleItemDistance(pdis, pingame, spbrush); + if (player->bot && player->botvars.rival) + { + // Rival has better odds :) + pdis = (15 * pdis) / 14; + } + if (pingame == 1 && oddsvalid[0]) { // Record Attack / FREE PLAY @@ -1531,13 +1563,13 @@ static void K_KartItemRoulette(player_t *player, ticcmd_t *cmd) } } - if (spbplace != -1 && player->position == spbplace+1) - { - // SPB Rush Mode: It's 2nd place's job to catch-up items and make 1st place's job hell - if (!(K_UsingLegacyCheckpoints())) - pdis = (3 * pdis) / 2; - spbrush = true; - } + if (spbplace != -1 && player->position == spbplace+1) + { + // SPB Rush Mode: It's 2nd place's job to catch-up items and make 1st place's job hell + if (!(K_UsingLegacyCheckpoints())) + pdis = (3 * pdis) / 2; + spbrush = true; + } if (!(K_UsingLegacyCheckpoints())) { @@ -1553,11 +1585,11 @@ static void K_KartItemRoulette(player_t *player, ticcmd_t *cmd) // SPECIAL CASE No. 1: // Fake Eggman items - if (player->roulettetype == 2) + if (player->roulettetype == KROULETTETYPE_EGGMAN) { player->eggmanexplode = 4*TICRATE; - player->itemroulette = 0; - player->roulettetype = 0; + player->itemroulette = KROULETTE_DISABLED; + player->roulettetype = KROULETTETYPE_NORMAL; if (P_IsDisplayPlayer(player)) S_StartSound(NULL, sfx_itrole); return; @@ -1568,11 +1600,10 @@ static void K_KartItemRoulette(player_t *player, ticcmd_t *cmd) if (cv_kartdebugitem.value != 0 && !modeattacking) { K_KartGetItemResult(player, cv_kartdebugitem.value); - player->itemamount = cv_kartdebugamount.value; player->itemblink = TICRATE; - player->itemblinkmode = 2; - player->itemroulette = 0; - player->roulettetype = 0; + player->itemblinkmode = KITEMBLINKMODE_KARMA; + player->itemroulette = KROULETTE_DISABLED; + player->roulettetype = KROULETTETYPE_NORMAL; if (P_IsDisplayPlayer(player)) S_StartSound(NULL, sfx_dbgsal); return; @@ -1586,9 +1617,9 @@ static void K_KartItemRoulette(player_t *player, ticcmd_t *cmd) K_KartGetItemResult(player, itemroll); player->itemblink = TICRATE; - player->itemblinkmode = 0; - player->itemroulette = 0; - player->roulettetype = 0; + player->itemblinkmode = KITEMBLINKMODE_NORMAL; + player->itemroulette = KROULETTE_DISABLED; + player->roulettetype = KROULETTETYPE_NORMAL; if (P_IsDisplayPlayer(player)) S_StartSound(NULL, sfx_itrolf); return; @@ -1605,7 +1636,7 @@ static void K_KartItemRoulette(player_t *player, ticcmd_t *cmd) if (mashed && ((K_RingsActive() == true) && (modeattacking || cv_superring.value))) // ANY mashed value? You get rings. { K_KartGetItemResult(player, KITEM_SUPERRING); - player->itemblinkmode = 1; + player->itemblinkmode = KITEMBLINKMODE_MASHED; if (P_IsDisplayPlayer(player)) S_StartSound(NULL, sfx_itrolm); } @@ -1615,7 +1646,7 @@ static void K_KartItemRoulette(player_t *player, ticcmd_t *cmd) K_KartGetItemResult(player, KITEM_SNEAKER); else // Default to sad if nothing's enabled... K_KartGetItemResult(player, KITEM_SAD); - player->itemblinkmode = 0; + player->itemblinkmode = KITEMBLINKMODE_NORMAL; if (P_IsDisplayPlayer(player)) S_StartSound(NULL, sfx_itrolf); } @@ -1625,29 +1656,29 @@ static void K_KartItemRoulette(player_t *player, ticcmd_t *cmd) if (mashed && (bossinfo.boss || cv_banana.value) && !itembreaker) // ANY mashed value? You get a banana. { K_KartGetItemResult(player, KITEM_BANANA); - player->itemblinkmode = 1; + player->itemblinkmode = KITEMBLINKMODE_MASHED; if (P_IsDisplayPlayer(player)) S_StartSound(NULL, sfx_itrolm); } else if (bossinfo.boss) { K_KartGetItemResult(player, KITEM_ORBINAUT); - player->itemblinkmode = 0; + player->itemblinkmode = KITEMBLINKMODE_NORMAL; if (P_IsDisplayPlayer(player)) S_StartSound(NULL, sfx_itrolf); } else if (itembreaker) { K_KartGetItemResult(player, KITEM_SNEAKER); - player->itemblinkmode = 1; + player->itemblinkmode = KITEMBLINKMODE_MASHED; if (P_IsDisplayPlayer(player)) S_StartSound(NULL, sfx_itrolm); } } player->itemblink = TICRATE; - player->itemroulette = 0; - player->roulettetype = 0; + player->itemroulette = KROULETTE_DISABLED; + player->roulettetype = KROULETTETYPE_NORMAL; return; } @@ -1660,9 +1691,9 @@ static void K_KartItemRoulette(player_t *player, ticcmd_t *cmd) { K_KartGetItemResult(player, KITEM_SUPERRING); player->itemblink = TICRATE; - player->itemblinkmode = 1; - player->itemroulette = 0; - player->roulettetype = 0; + player->itemblinkmode = KITEMBLINKMODE_MASHED; + player->itemroulette = KROULETTE_DISABLED; + player->roulettetype = KROULETTETYPE_NORMAL; if (P_IsDisplayPlayer(player)) S_StartSound(NULL, sfx_itrolm); return; @@ -1679,9 +1710,9 @@ static void K_KartItemRoulette(player_t *player, ticcmd_t *cmd) { K_KartGetItemResult(player, KITEM_SPB); player->itemblink = TICRATE; - player->itemblinkmode = 2; - player->itemroulette = 0; - player->roulettetype = 0; + player->itemblinkmode = KITEMBLINKMODE_KARMA; + player->itemroulette = KROULETTE_DISABLED; + player->roulettetype = KROULETTETYPE_NORMAL; if (P_IsDisplayPlayer(player)) S_StartSound(NULL, sfx_itrolk); return; @@ -1704,9 +1735,9 @@ static void K_KartItemRoulette(player_t *player, ticcmd_t *cmd) { K_KartGetItemResult(player, KITEM_SPB); player->itemblink = TICRATE; - player->itemblinkmode = 2; - player->itemroulette = 0; - player->roulettetype = 0; + player->itemblinkmode = KITEMBLINKMODE_KARMA; + player->itemroulette = KROULETTE_DISABLED; + player->roulettetype = KROULETTETYPE_NORMAL; if (P_IsDisplayPlayer(player)) S_StartSound(NULL, sfx_itrolk); return; @@ -1745,13 +1776,13 @@ static void K_KartItemRoulette(player_t *player, ticcmd_t *cmd) } if (P_IsDisplayPlayer(player)) - S_StartSound(NULL, ((player->roulettetype == 1) ? sfx_itrolk : (mashed ? sfx_itrolm : sfx_itrolf))); + S_StartSound(NULL, ((player->roulettetype == KROULETTETYPE_KARMA) ? sfx_itrolk : (mashed ? sfx_itrolm : sfx_itrolf))); player->itemblink = TICRATE; - player->itemblinkmode = ((player->roulettetype == 1) ? 2 : (mashed ? 1 : 0)); + player->itemblinkmode = ((player->roulettetype == KROULETTETYPE_KARMA) ? KITEMBLINKMODE_KARMA : (mashed ? KITEMBLINKMODE_MASHED : KITEMBLINKMODE_NORMAL)); - player->itemroulette = 0; // Since we're done, clear the roulette number - player->roulettetype = 0; // This too + player->itemroulette = KROULETTE_DISABLED; // Since we're done, clear the roulette number + player->roulettetype = KROULETTETYPE_NORMAL; // This too } //} @@ -6050,9 +6081,6 @@ mobj_t *K_CreatePaperItem(fixed_t x, fixed_t y, fixed_t z, angle_t angle, SINT8 if (totalspawnchance > 0) { - UINT8 newType; - UINT8 newAmount; - totalspawnchance = P_RandomKey(totalspawnchance); for (i = 0; i < NUMKARTRESULTS && spawnchance[i] <= totalspawnchance; i++); @@ -6060,42 +6088,8 @@ mobj_t *K_CreatePaperItem(fixed_t x, fixed_t y, fixed_t z, angle_t angle, SINT8 // K_KartGetItemResult requires a player // but item roulette will need rewritten to change this - switch (i) - { - // Special roulettes first, then the generic ones are handled by default - case KRITEM_DUALSNEAKER: // Sneaker x2 - newType = KITEM_SNEAKER; - newAmount = 2; - break; - case KRITEM_TRIPLESNEAKER: // Sneaker x3 - newType = KITEM_SNEAKER; - newAmount = 3; - break; - case KRITEM_TRIPLEBANANA: // Banana x3 - newType = KITEM_BANANA; - newAmount = 3; - break; - case KRITEM_TENFOLDBANANA: // Banana x10 - newType = KITEM_BANANA; - newAmount = 10; - break; - case KRITEM_TRIPLEORBINAUT: // Orbinaut x3 - newType = KITEM_ORBINAUT; - newAmount = 3; - break; - case KRITEM_QUADORBINAUT: // Orbinaut x4 - newType = KITEM_ORBINAUT; - newAmount = 4; - break; - case KRITEM_DUALJAWZ: // Jawz x2 - newType = KITEM_JAWZ; - newAmount = 2; - break; - default: - newType = i; - newAmount = 1; - break; - } + const UINT8 newType = K_ItemResultToType(i); + const UINT8 newAmount = K_ItemResultToAmount(i); if (newAmount > 1) { @@ -7728,7 +7722,7 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) if (player->itemblink && player->itemblink-- <= 0) { - player->itemblinkmode = 0; + player->itemblinkmode = KITEMBLINKMODE_NORMAL; player->itemblink = 0; } @@ -7821,7 +7815,9 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) K_KartItemRoulette(player, cmd); // Gain rings when roulette starts. - if (player->itemroulette > 0 && player->previtemroulette == 0) + if (player->itemroulette > KROULETTE_DISABLED + && player->previtemroulette == KROULETTE_DISABLED + && player->roulettetype != KROULETTETYPE_EGGMAN) { K_AwardScaledPlayerRings(player, ASR_ITEMBOX); } @@ -9705,8 +9701,8 @@ void K_StripItems(player_t *player) if (!player->itemroulette || player->roulettetype != 2) { - player->itemroulette = 0; - player->roulettetype = 0; + player->itemroulette = KROULETTE_DISABLED; + player->roulettetype = KROULETTETYPE_NORMAL; } player->hyudorotimer = 0; @@ -9723,8 +9719,8 @@ void K_StripItems(player_t *player) void K_StripOther(player_t *player) { - player->itemroulette = 0; - player->roulettetype = 0; + player->itemroulette = KROULETTE_DISABLED; + player->roulettetype = KROULETTETYPE_NORMAL; player->invincibilitytimer = 0; if (player->growshrinktimer) diff --git a/src/k_kart.h b/src/k_kart.h index 2579a53f6..4890f92bc 100644 --- a/src/k_kart.h +++ b/src/k_kart.h @@ -128,6 +128,8 @@ INT32 K_KartGetLegacyItemOdds(UINT8 pos, SINT8 item, fixed_t mashed, boolean spb INT32 K_GetRollingRouletteItem(player_t *player); INT32 K_GetShieldFromPlayer(player_t *player); INT32 K_GetShieldFromItem(INT32 item); +SINT8 K_ItemResultToType(SINT8 getitem); +UINT8 K_ItemResultToAmount(SINT8 getitem); fixed_t K_GetMobjWeight(mobj_t *mobj, mobj_t *against); boolean K_KartBouncing(mobj_t *mobj1, mobj_t *mobj2, boolean bounce, boolean solid); void K_KartPainEnergyFling(player_t *player); diff --git a/src/p_enemy.c b/src/p_enemy.c index 35c3da2ae..d45b3fbb6 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -10606,7 +10606,7 @@ void A_ItemPop(mobj_t *actor) if (!((gametyperules & GTR_BUMPERS) && actor->target->player->bumper <= 0) && !itembreaker) { - actor->target->player->itemroulette = 1; + actor->target->player->itemroulette = KROULETTE_ACTIVE; } else if (itembreaker) { diff --git a/src/p_inter.c b/src/p_inter.c index 9cee82a17..e1d4d5674 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -136,7 +136,7 @@ boolean P_CanPickupItem(player_t *player, UINT8 weapon) return false; // Already have fake - if (player->roulettetype == 2 + if (player->roulettetype == KROULETTETYPE_EGGMAN || player->eggmanexplode) return false; } @@ -457,8 +457,8 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) special->target->player->karmadelay = comebacktime; - player->itemroulette = 1; - player->roulettetype = 1; + player->itemroulette = KROULETTE_ACTIVE; + player->roulettetype = KROULETTETYPE_KARMA; } else if (special->target->player->karmamode == 2 && P_CanPickupItem(player, 2)) { @@ -496,8 +496,8 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) K_DropItems(player); //K_StripItems(player); //K_StripOther(player); - player->itemroulette = 1; - player->roulettetype = 2; + player->itemroulette = KROULETTE_ACTIVE; + player->roulettetype = KROULETTETYPE_EGGMAN; if (special->target->player->eggmanblame >= 0 && special->target->player->eggmanblame < MAXPLAYERS @@ -591,8 +591,8 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) if (special->fuse || !P_CanPickupItem(player, 1) || ((gametyperules & GTR_BUMPERS) && player->bumper <= 0)) return; - player->itemroulette = 1; - player->roulettetype = 1; + player->itemroulette = KROULETTE_ACTIVE; + player->roulettetype = KROULETTETYPE_KARMA; // Karma fireworks for (i = 0; i < 5; i++) @@ -1713,9 +1713,9 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget player->itemamount = max(1, target->movecount); } player->itemblink = TICRATE; - player->itemblinkmode = 0; - player->itemroulette = 0; - player->roulettetype = 0; + player->itemblinkmode = KITEMBLINKMODE_NORMAL; + player->itemroulette = KROULETTE_DISABLED; + player->roulettetype = KROULETTETYPE_NORMAL; if (P_IsDisplayPlayer(player)) S_StartSound(NULL, sfx_itrolf); } diff --git a/src/p_map.c b/src/p_map.c index dd0a935f5..e629db522 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -1732,7 +1732,7 @@ static BlockItReturn_t PIT_CheckLine(line_t *ld) { fixed_t textop, texbottom; - P_GetMidtextureTopBottom(ld, &open, + P_GetTripwireTopBottom(ld, g_tm.x, g_tm.y, &textop, &texbottom); /* The effect handling is done later but it won't diff --git a/src/p_maputl.c b/src/p_maputl.c index f6568e23b..9069026dd 100644 --- a/src/p_maputl.c +++ b/src/p_maputl.c @@ -496,6 +496,95 @@ P_GetMidtextureTopBottom return true; } +boolean +P_GetTripwireTopBottom +( line_t * linedef, + fixed_t x, + fixed_t y, + fixed_t * return_top, + fixed_t * return_bottom) +{ + side_t *side = &sides[linedef->sidenum[0]]; + fixed_t textop, texbottom, texheight; + INT32 texnum = R_GetTextureNum(side->midtexture); // make sure the texture is actually valid + + sector_t *front = linedef->frontsector; + sector_t *back = linedef->backsector; + fixed_t z; + + if (!texnum) + return false; + + textop = P_GetSectorCeilingZAt(front, x, y); + texbottom = P_GetSectorFloorZAt(front, x, y); + + if (back) + { + z = P_GetSectorCeilingZAt(back, x, y); + + if (z < textop) + textop = z; + + z = P_GetSectorFloorZAt(back, x, y); + + if (z > texbottom) + texbottom = z; + } + + // Get the midtexture's height + texheight = textures[texnum]->height << FRACBITS; + + // Set texbottom and textop to the Z coordinates of the texture's boundaries +#if 0 + // don't remove this code unless solid midtextures + // on non-solid polyobjects should NEVER happen in the future + if (linedef->polyobj && (linedef->polyobj->flags & POF_TESTHEIGHT)) + { + if ((linedef->flags & ML_WRAPMIDTEX) && !side->repeatcnt) // "infinite" repeat + { + texbottom = back->floorheight + side->rowoffset; + textop = back->ceilingheight + side->rowoffset; + } + else if (linedef->flags & ML_MIDPEG) + { + texbottom = back->floorheight + side->rowoffset; + textop = texbottom + texheight*(side->repeatcnt+1); + } + else + { + textop = back->ceilingheight + side->rowoffset; + texbottom = textop - texheight*(side->repeatcnt+1); + } + } + else +#endif + { + if ((linedef->flags & ML_WRAPMIDTEX) && !side->repeatcnt) // "infinite" repeat + { + texbottom += side->rowoffset; + textop += side->rowoffset; + } + else if (linedef->flags & ML_MIDPEG) + { + texbottom += side->rowoffset; + textop = texbottom + texheight*(side->repeatcnt+1); + } + else + { + textop += side->rowoffset; + texbottom = textop - texheight*(side->repeatcnt+1); + } + } + + if (return_top) + *return_top = textop; + + if (return_bottom) + *return_bottom = texbottom; + + return true; +} + static boolean P_MidtextureIsSolid(line_t *linedef, mobj_t *mobj) { if (linedef->polyobj) @@ -514,6 +603,51 @@ static boolean P_MidtextureIsSolid(line_t *linedef, mobj_t *mobj) return ((linedef->flags & ML_MIDSOLID) == ML_MIDSOLID); } +static void P_ProcessMidtextureTopBottom +( + fixed_t textop, + fixed_t texbottom, + mobj_t *mobj, + fixed_t thingtop, + opening_t *open, + fixed_t *topedge, + fixed_t *botedge, + int hi, + int lo +) +{ + fixed_t texmid, delta1, delta2; + texmid = texbottom+(textop-texbottom)/2; + + delta1 = abs(mobj->z - texmid); + delta2 = abs(thingtop - texmid); + + if (delta1 > delta2) + { + // Below + if (open->ceiling > texbottom) + { + topedge[lo] -= ( open->ceiling - texbottom ); + + open->ceiling = texbottom; + open->ceilingstep = ( thingtop - topedge[lo] ); + open->ceilingdrop = ( topedge[hi] - topedge[lo] ); + } + } + else + { + // Above + if (open->floor < textop) + { + botedge[hi] += ( textop - open->floor ); + + open->floor = textop; + open->floorstep = ( botedge[hi] - mobj->z ); + open->floordrop = ( botedge[hi] - botedge[lo] ); + } + } +} + void P_LineOpening(line_t *linedef, mobj_t *mobj, opening_t *open) { enum { FRONT, BACK }; @@ -620,39 +754,14 @@ void P_LineOpening(line_t *linedef, mobj_t *mobj, opening_t *open) if (P_MidtextureIsSolid(linedef, mobj) == true) { fixed_t textop, texbottom; - fixed_t texmid, delta1, delta2; - if (P_GetMidtextureTopBottom(linedef, open, &textop, &texbottom)) + if (P_IsLineTripWire(linedef) && P_GetTripwireTopBottom(linedef, cross.x, cross.y, &textop, &texbottom)) { - texmid = texbottom+(textop-texbottom)/2; - - delta1 = abs(mobj->z - texmid); - delta2 = abs(thingtop - texmid); - - if (delta1 > delta2) - { - // Below - if (open->ceiling > texbottom) - { - topedge[lo] -= ( open->ceiling - texbottom ); - - open->ceiling = texbottom; - open->ceilingstep = ( thingtop - topedge[lo] ); - open->ceilingdrop = ( topedge[hi] - topedge[lo] ); - } - } - else - { - // Above - if (open->floor < textop) - { - botedge[hi] += ( textop - open->floor ); - - open->floor = textop; - open->floorstep = ( botedge[hi] - mobj->z ); - open->floordrop = ( botedge[hi] - botedge[lo] ); - } - } + P_ProcessMidtextureTopBottom(textop, texbottom, mobj, thingtop, open, topedge, botedge, hi, lo); + } + else if (P_GetMidtextureTopBottom(linedef, open, &textop, &texbottom)) + { + P_ProcessMidtextureTopBottom(textop, texbottom, mobj, thingtop, open, topedge, botedge, hi, lo); } } diff --git a/src/p_maputl.h b/src/p_maputl.h index f005a4957..c31c0ff4b 100644 --- a/src/p_maputl.h +++ b/src/p_maputl.h @@ -78,6 +78,7 @@ void P_CreatePrecipSecNodeList(precipmobj_t *thing, fixed_t x,fixed_t y); void P_HitSpecialLines(mobj_t *thing, fixed_t x, fixed_t y, fixed_t momx, fixed_t momy); boolean P_GetMidtextureTopBottom(line_t *linedef, opening_t *open, fixed_t *return_top, fixed_t *return_bottom); +boolean P_GetTripwireTopBottom(line_t *linedef, fixed_t x, fixed_t y, fixed_t *return_top, fixed_t *return_bottom); typedef enum {