From db8f23561dfee29390c63afebd9620d8651c5a2a Mon Sep 17 00:00:00 2001 From: TehRealSalt Date: Sat, 9 Mar 2019 04:33:46 -0500 Subject: [PATCH] Minor (but important!) polishing - Thunder Shield now attracts rings - Colorize the ring counter at max yellow - Rings in the collecting animation are considered for determining if you can't pick up rings anymore, preventing a LOT of rings being deleted from the map over time. - Flung rings don't lose speed over time anymore - Flund rings last way longer - Using rings is much less touchy (holding the button from before an item roulette will let you continue using them until you let go, using certain items won't make you use a couple rings afterwards) - 0 rings is now counted as debt when getting hit, making debt easier to get out of (getting hit by a spike now would put you at -2 instead of -5) - Move Super Ring toward the end of the item (so I don't have to modify gfx.kart to fix dropped items) --- src/d_player.h | 4 +- src/dehacked.c | 4 +- src/k_kart.c | 863 ++++++++++++++++++++++++++----------------------- src/p_enemy.c | 116 ++++--- src/p_inter.c | 10 +- src/p_mobj.c | 19 +- 6 files changed, 545 insertions(+), 471 deletions(-) diff --git a/src/d_player.h b/src/d_player.h index ca7ef4d4b..74b1e4885 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -234,7 +234,6 @@ typedef enum { KITEM_SAD = -1, KITEM_NONE = 0, - KITEM_SUPERRING, KITEM_SNEAKER, KITEM_ROCKETSNEAKER, KITEM_INVINCIBILITY, @@ -250,6 +249,7 @@ typedef enum KITEM_THUNDERSHIELD, KITEM_HYUDORO, KITEM_POGOSPRING, + KITEM_SUPERRING, KITEM_KITCHENSINK, NUMKARTITEMS, @@ -298,6 +298,8 @@ typedef enum k_boostcharge, // Charge-up for boosting at the start of the race k_startboost, // Boost you get from start of race or respawn drop dash k_rings, // Number of held rings + k_pickuprings, // Number of rings being picked up before added to the counter (prevents rings from being deleted forever over 20) + k_userings, // Have to be not holding the item button to change from using rings to using items (or vice versa), to prevent some weirdness with the button k_ringdelay, // 3 tic delay between every ring usage k_ringboost, // Ring boost timer k_jmp, // In Mario Kart, letting go of the jump button stops the drift diff --git a/src/dehacked.c b/src/dehacked.c index ad9bc151a..eda1e41fb 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -8355,6 +8355,8 @@ static const char *const KARTSTUFF_LIST[] = { "BOOSTCHARGE", "STARTBOOST", "RINGS", + "PICKUPRINGS", + "USERINGS", "RINGDELAY", "RINGBOOST", "JMP", @@ -8943,7 +8945,6 @@ struct { // kartitems_t {"KITEM_SAD",KITEM_SAD}, // Actual items (can be set for k_itemtype) {"KITEM_NONE",KITEM_NONE}, - {"KITEM_SUPERRING",KITEM_SUPERRING}, {"KITEM_SNEAKER",KITEM_SNEAKER}, {"KITEM_ROCKETSNEAKER",KITEM_ROCKETSNEAKER}, {"KITEM_INVINCIBILITY",KITEM_INVINCIBILITY}, @@ -8959,6 +8960,7 @@ struct { {"KITEM_THUNDERSHIELD",KITEM_THUNDERSHIELD}, {"KITEM_HYUDORO",KITEM_HYUDORO}, {"KITEM_POGOSPRING",KITEM_POGOSPRING}, + {"KITEM_SUPERRING",KITEM_SUPERRING}, {"KITEM_KITCHENSINK",KITEM_KITCHENSINK}, {"NUMKARTITEMS",NUMKARTITEMS}, {"KRITEM_TRIPLESNEAKER",KRITEM_TRIPLESNEAKER}, // Additional roulette IDs (not usable for much in Lua besides K_GetItemPatch) diff --git a/src/k_kart.c b/src/k_kart.c index 935b0bd9a..c3e22f2e8 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -1136,6 +1136,24 @@ static void K_KartItemRoulette(player_t *player, ticcmd_t *cmd) } // SPECIAL CASE No. 4: + // Being in ring debt occasionally forces Super Ring on you + if (player->kartstuff[k_rings] <= 0 && cv_superring.value) + { + INT32 debtamount = min(20, abs(player->kartstuff[k_rings])+1); + if (P_RandomChance((debtamount*FRACUNIT)/20)) + { + K_KartGetItemResult(player, KITEM_SUPERRING); + player->kartstuff[k_itemblink] = TICRATE; + player->kartstuff[k_itemblinkmode] = (mashed ? 1 : 0); + player->kartstuff[k_itemroulette] = 0; + player->kartstuff[k_roulettetype] = 0; + if (P_IsLocalPlayer(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*6) && spbplace == -1 && !indirectitemcooldown && !dontforcespb @@ -1148,6 +1166,7 @@ static void K_KartItemRoulette(player_t *player, ticcmd_t *cmd) player->kartstuff[k_roulettetype] = 0; if (P_IsLocalPlayer(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. @@ -1418,6 +1437,7 @@ void K_KartBouncing(mobj_t *mobj1, mobj_t *mobj2, boolean bounce, boolean solid) { mobj1->player->kartstuff[k_wipeoutslow] = wipeoutslowtime+1; 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 { @@ -1440,6 +1460,7 @@ void K_KartBouncing(mobj_t *mobj1, mobj_t *mobj2, boolean bounce, boolean solid) { mobj2->player->kartstuff[k_wipeoutslow] = wipeoutslowtime+1; 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 { @@ -1742,6 +1763,7 @@ void K_RespawnChecker(player_t *player) player->mo->colorized = false; player->kartstuff[k_dropdash] = 0; player->kartstuff[k_respawn] = 0; + //P_PlayRinglossSound(player->mo); P_PlayerRingBurst(player, 3); } } @@ -4804,6 +4826,7 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) ring->extravalue1 = 1; // Ring collect animation timer ring->angle = player->mo->angle; // animation angle P_SetTarget(&ring->target, player->mo); // toucher for thinker + player->kartstuff[k_pickuprings]++; if (player->kartstuff[k_superring] <= 3) ring->cvmem = 1; // play caching when collected } @@ -5428,7 +5451,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground) else if (cmd->buttons & BT_ATTACK) player->pflags |= PF_ATTACKDOWN; - if (player && player->mo && player->mo->health > 0 && !player->spectator && !(player->exiting || mapreset) + if (player && player->mo && player->mo->health > 0 && !player->spectator && !(player->exiting || mapreset) && leveltime > starttime && player->kartstuff[k_spinouttimer] == 0 && player->kartstuff[k_squishedtimer] == 0 && player->kartstuff[k_respawn] == 0) { // First, the really specific, finicky items that function without the item being directly in your item slot. @@ -5464,418 +5487,436 @@ void K_MoveKartPlayer(player_t *player, boolean onground) S_StartSound(player->mo, sfx_s254); } } - // Eggman Monitor exploding - else if (player->kartstuff[k_eggmanexplode]) - { - if (ATTACK_IS_DOWN && player->kartstuff[k_eggmanexplode] <= 3*TICRATE && player->kartstuff[k_eggmanexplode] > 1) - player->kartstuff[k_eggmanexplode] = 1; - } - // Eggman Monitor throwing - else if (player->kartstuff[k_eggmanheld]) - { - if (ATTACK_IS_DOWN) - { - K_ThrowKartItem(player, false, MT_EGGMANITEM, -1, 0); - K_PlayAttackTaunt(player->mo); - player->kartstuff[k_eggmanheld] = 0; - K_UpdateHnextList(player, true); - } - } - // Rocket Sneaker usage - else if (player->kartstuff[k_rocketsneakertimer] > 1) - { - if (ATTACK_IS_DOWN && !HOLDING_ITEM && onground && NO_HYUDORO) - { - K_DoSneaker(player, 2); - K_PlayBoostTaunt(player->mo); - player->kartstuff[k_rocketsneakertimer] -= 2*TICRATE; - 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; - } - // Ring boosting - else if (player->kartstuff[k_itemtype] == KITEM_NONE) - { - if ((player->pflags & PF_ATTACKDOWN) && !HOLDING_ITEM && NO_HYUDORO - && !player->kartstuff[k_itemroulette] && !player->kartstuff[k_ringdelay] - && player->kartstuff[k_rings] > 0) - { - mobj_t *ring = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_RING); - ring->extravalue1 = 1; // Ring use animation timer - ring->extravalue2 = 1; // Ring use animation flag - P_SetTarget(&ring->target, player->mo); // user - player->kartstuff[k_rings]--; - player->kartstuff[k_ringdelay] = 3; - } - } - else if (player->kartstuff[k_itemamount] <= 0) - { - player->kartstuff[k_itemamount] = player->kartstuff[k_itemheld] = 0; - } else { - switch (player->kartstuff[k_itemtype]) + // Ring boosting + if (player->kartstuff[k_userings]) { - case KITEM_SUPERRING: - if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO) + if ((player->pflags & PF_ATTACKDOWN) && !HOLDING_ITEM && NO_HYUDORO + && !player->kartstuff[k_itemroulette] && !player->kartstuff[k_ringdelay] + && player->kartstuff[k_rings] > 0) + { + mobj_t *ring = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_RING); + ring->extravalue1 = 1; // Ring use animation timer + ring->extravalue2 = 1; // Ring use animation flag + P_SetTarget(&ring->target, player->mo); // user + player->kartstuff[k_rings]--; + player->kartstuff[k_ringdelay] = 3; + } + } + // Other items + else + { + // Eggman Monitor exploding + if (player->kartstuff[k_eggmanexplode]) + { + if (ATTACK_IS_DOWN && player->kartstuff[k_eggmanexplode] <= 3*TICRATE && player->kartstuff[k_eggmanexplode] > 1) + player->kartstuff[k_eggmanexplode] = 1; + } + // Eggman Monitor throwing + else if (player->kartstuff[k_eggmanheld]) + { + if (ATTACK_IS_DOWN) { - player->kartstuff[k_superring] += (10*3); - player->kartstuff[k_itemamount]--; + K_ThrowKartItem(player, false, MT_EGGMANITEM, -1, 0); + K_PlayAttackTaunt(player->mo); + player->kartstuff[k_eggmanheld] = 0; + K_UpdateHnextList(player, true); } - break; - case KITEM_SNEAKER: + } + // Rocket Sneaker usage + else if (player->kartstuff[k_rocketsneakertimer] > 1) + { if (ATTACK_IS_DOWN && !HOLDING_ITEM && onground && NO_HYUDORO) { - K_DoSneaker(player, 1); + K_DoSneaker(player, 2); K_PlayBoostTaunt(player->mo); - player->kartstuff[k_itemamount]--; + player->kartstuff[k_rocketsneakertimer] -= 2*TICRATE; + if (player->kartstuff[k_rocketsneakertimer] < 1) + player->kartstuff[k_rocketsneakertimer] = 1; } - break; - case KITEM_ROCKETSNEAKER: - if (ATTACK_IS_DOWN && !HOLDING_ITEM && onground && NO_HYUDORO - && player->kartstuff[k_rocketsneakertimer] == 0) + } + // Grow Canceling + else if (player->kartstuff[k_growshrinktimer] > 0) + { + if (cmd->buttons & BT_ATTACK) { - INT32 moloop; - mobj_t *mo = NULL; - mobj_t *prev = player->mo; - - K_PlayBoostTaunt(player->mo); - //player->kartstuff[k_itemheld] = 1; - S_StartSound(player->mo, sfx_s3k3a); - - //K_DoSneaker(player, 2); - - player->kartstuff[k_rocketsneakertimer] = (itemtime*3); - player->kartstuff[k_itemamount]--; - K_UpdateHnextList(player, true); - - for (moloop = 0; moloop < 2; moloop++) - { - mo = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_ROCKETSNEAKER); - mo->flags |= MF_NOCLIPTHING; - mo->angle = player->mo->angle; - mo->threshold = 10; - mo->movecount = moloop%2; - mo->movedir = mo->lastlook = moloop+1; - P_SetTarget(&mo->target, player->mo); - P_SetTarget(&mo->hprev, prev); - P_SetTarget(&prev->hnext, mo); - prev = mo; - } + player->kartstuff[k_growcancel]++; + if (player->kartstuff[k_growcancel] > 26) + K_RemoveGrowShrink(player); } - break; - case KITEM_INVINCIBILITY: - if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO) // Doesn't hold your item slot hostage normally, so you're free to waste it if you have multiple + else + player->kartstuff[k_growcancel] = 0; + } + else if (player->kartstuff[k_itemamount] <= 0) + { + player->kartstuff[k_itemamount] = player->kartstuff[k_itemheld] = 0; + } + else + { + switch (player->kartstuff[k_itemtype]) { - if (!player->kartstuff[k_invincibilitytimer]) - { - mobj_t *overlay = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_INVULNFLASH); - P_SetTarget(&overlay->target, player->mo); - overlay->destscale = player->mo->scale; - P_SetScale(overlay, player->mo->scale); - } - player->kartstuff[k_invincibilitytimer] = itemtime+(2*TICRATE); // 10 seconds - P_RestoreMusic(player); - if (!P_IsLocalPlayer(player)) - S_StartSound(player->mo, (cv_kartinvinsfx.value ? sfx_alarmi : sfx_kinvnc)); - K_PlayPowerGloatSound(player->mo); - player->kartstuff[k_itemamount]--; - } - break; - case KITEM_BANANA: - if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO) - { - INT32 moloop; - mobj_t *mo; - mobj_t *prev = player->mo; - - //K_PlayAttackTaunt(player->mo); - player->kartstuff[k_itemheld] = 1; - S_StartSound(player->mo, sfx_s254); - - for (moloop = 0; moloop < player->kartstuff[k_itemamount]; moloop++) - { - mo = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_BANANA_SHIELD); - if (!mo) + case KITEM_SNEAKER: + if (ATTACK_IS_DOWN && !HOLDING_ITEM && onground && NO_HYUDORO) { - player->kartstuff[k_itemamount] = moloop; - break; + K_DoSneaker(player, 1); + K_PlayBoostTaunt(player->mo); + player->kartstuff[k_itemamount]--; } - mo->flags |= MF_NOCLIPTHING; - mo->threshold = 10; - mo->movecount = player->kartstuff[k_itemamount]; - mo->movedir = moloop+1; - P_SetTarget(&mo->target, player->mo); - P_SetTarget(&mo->hprev, prev); - P_SetTarget(&prev->hnext, mo); - prev = mo; - } - } - else if (ATTACK_IS_DOWN && player->kartstuff[k_itemheld]) // Banana x3 thrown - { - K_ThrowKartItem(player, false, MT_BANANA, -1, 0); - K_PlayAttackTaunt(player->mo); - player->kartstuff[k_itemamount]--; - K_UpdateHnextList(player, false); - } - break; - case KITEM_EGGMAN: - if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO) - { - mobj_t *mo; - player->kartstuff[k_itemamount]--; - player->kartstuff[k_eggmanheld] = 1; - S_StartSound(player->mo, sfx_s254); - mo = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_EGGMANITEM_SHIELD); - if (mo) - { - mo->flags |= MF_NOCLIPTHING; - mo->threshold = 10; - mo->movecount = 1; - mo->movedir = 1; - P_SetTarget(&mo->target, player->mo); - P_SetTarget(&player->mo->hnext, mo); - } - } - break; - case KITEM_ORBINAUT: - if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO) - { - angle_t newangle; - INT32 moloop; - mobj_t *mo = NULL; - mobj_t *prev = player->mo; - - //K_PlayAttackTaunt(player->mo); - player->kartstuff[k_itemheld] = 1; - S_StartSound(player->mo, sfx_s3k3a); - - for (moloop = 0; moloop < player->kartstuff[k_itemamount]; moloop++) - { - newangle = (player->mo->angle + ANGLE_157h) + FixedAngle(((360 / player->kartstuff[k_itemamount]) * moloop) << FRACBITS) + ANGLE_90; - mo = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_ORBINAUT_SHIELD); - if (!mo) + break; + case KITEM_ROCKETSNEAKER: + if (ATTACK_IS_DOWN && !HOLDING_ITEM && onground && NO_HYUDORO + && player->kartstuff[k_rocketsneakertimer] == 0) { - player->kartstuff[k_itemamount] = moloop; - break; + INT32 moloop; + mobj_t *mo = NULL; + mobj_t *prev = player->mo; + + K_PlayBoostTaunt(player->mo); + //player->kartstuff[k_itemheld] = 1; + S_StartSound(player->mo, sfx_s3k3a); + + //K_DoSneaker(player, 2); + + player->kartstuff[k_rocketsneakertimer] = (itemtime*3); + player->kartstuff[k_itemamount]--; + K_UpdateHnextList(player, true); + + for (moloop = 0; moloop < 2; moloop++) + { + mo = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_ROCKETSNEAKER); + mo->flags |= MF_NOCLIPTHING; + mo->angle = player->mo->angle; + mo->threshold = 10; + mo->movecount = moloop%2; + mo->movedir = mo->lastlook = moloop+1; + P_SetTarget(&mo->target, player->mo); + P_SetTarget(&mo->hprev, prev); + P_SetTarget(&prev->hnext, mo); + prev = mo; + } } - mo->flags |= MF_NOCLIPTHING; - mo->angle = newangle; - mo->threshold = 10; - mo->movecount = player->kartstuff[k_itemamount]; - mo->movedir = mo->lastlook = moloop+1; - mo->color = player->skincolor; - P_SetTarget(&mo->target, player->mo); - P_SetTarget(&mo->hprev, prev); - P_SetTarget(&prev->hnext, mo); - prev = mo; - } - } - else if (ATTACK_IS_DOWN && player->kartstuff[k_itemheld]) // Orbinaut x3 thrown - { - K_ThrowKartItem(player, true, MT_ORBINAUT, 1, 0); - K_PlayAttackTaunt(player->mo); - player->kartstuff[k_itemamount]--; - K_UpdateHnextList(player, false); - } - break; - case KITEM_JAWZ: - if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO) - { - angle_t newangle; - INT32 moloop; - mobj_t *mo = NULL; - mobj_t *prev = player->mo; - - //K_PlayAttackTaunt(player->mo); - player->kartstuff[k_itemheld] = 1; - S_StartSound(player->mo, sfx_s3k3a); - - for (moloop = 0; moloop < player->kartstuff[k_itemamount]; moloop++) - { - newangle = (player->mo->angle + ANGLE_157h) + FixedAngle(((360 / player->kartstuff[k_itemamount]) * moloop) << FRACBITS) + ANGLE_90; - mo = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_JAWZ_SHIELD); - if (!mo) + break; + case KITEM_INVINCIBILITY: + if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO) // Doesn't hold your item slot hostage normally, so you're free to waste it if you have multiple { - player->kartstuff[k_itemamount] = moloop; - break; + if (!player->kartstuff[k_invincibilitytimer]) + { + mobj_t *overlay = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_INVULNFLASH); + P_SetTarget(&overlay->target, player->mo); + overlay->destscale = player->mo->scale; + P_SetScale(overlay, player->mo->scale); + } + player->kartstuff[k_invincibilitytimer] = itemtime+(2*TICRATE); // 10 seconds + P_RestoreMusic(player); + if (!P_IsLocalPlayer(player)) + S_StartSound(player->mo, (cv_kartinvinsfx.value ? sfx_alarmi : sfx_kinvnc)); + K_PlayPowerGloatSound(player->mo); + player->kartstuff[k_itemamount]--; } - mo->flags |= MF_NOCLIPTHING; - mo->angle = newangle; - mo->threshold = 10; - mo->movecount = player->kartstuff[k_itemamount]; - mo->movedir = mo->lastlook = moloop+1; - P_SetTarget(&mo->target, player->mo); - P_SetTarget(&mo->hprev, prev); - P_SetTarget(&prev->hnext, mo); - prev = mo; - } + break; + case KITEM_BANANA: + if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO) + { + INT32 moloop; + mobj_t *mo; + mobj_t *prev = player->mo; + + //K_PlayAttackTaunt(player->mo); + player->kartstuff[k_itemheld] = 1; + S_StartSound(player->mo, sfx_s254); + + for (moloop = 0; moloop < player->kartstuff[k_itemamount]; moloop++) + { + mo = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_BANANA_SHIELD); + if (!mo) + { + player->kartstuff[k_itemamount] = moloop; + break; + } + mo->flags |= MF_NOCLIPTHING; + mo->threshold = 10; + mo->movecount = player->kartstuff[k_itemamount]; + mo->movedir = moloop+1; + P_SetTarget(&mo->target, player->mo); + P_SetTarget(&mo->hprev, prev); + P_SetTarget(&prev->hnext, mo); + prev = mo; + } + } + else if (ATTACK_IS_DOWN && player->kartstuff[k_itemheld]) // Banana x3 thrown + { + K_ThrowKartItem(player, false, MT_BANANA, -1, 0); + K_PlayAttackTaunt(player->mo); + player->kartstuff[k_itemamount]--; + K_UpdateHnextList(player, false); + } + break; + case KITEM_EGGMAN: + if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO) + { + mobj_t *mo; + player->kartstuff[k_itemamount]--; + player->kartstuff[k_eggmanheld] = 1; + S_StartSound(player->mo, sfx_s254); + mo = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_EGGMANITEM_SHIELD); + if (mo) + { + mo->flags |= MF_NOCLIPTHING; + mo->threshold = 10; + mo->movecount = 1; + mo->movedir = 1; + P_SetTarget(&mo->target, player->mo); + P_SetTarget(&player->mo->hnext, mo); + } + } + break; + case KITEM_ORBINAUT: + if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO) + { + angle_t newangle; + INT32 moloop; + mobj_t *mo = NULL; + mobj_t *prev = player->mo; + + //K_PlayAttackTaunt(player->mo); + player->kartstuff[k_itemheld] = 1; + S_StartSound(player->mo, sfx_s3k3a); + + for (moloop = 0; moloop < player->kartstuff[k_itemamount]; moloop++) + { + newangle = (player->mo->angle + ANGLE_157h) + FixedAngle(((360 / player->kartstuff[k_itemamount]) * moloop) << FRACBITS) + ANGLE_90; + mo = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_ORBINAUT_SHIELD); + if (!mo) + { + player->kartstuff[k_itemamount] = moloop; + break; + } + mo->flags |= MF_NOCLIPTHING; + mo->angle = newangle; + mo->threshold = 10; + mo->movecount = player->kartstuff[k_itemamount]; + mo->movedir = mo->lastlook = moloop+1; + mo->color = player->skincolor; + P_SetTarget(&mo->target, player->mo); + P_SetTarget(&mo->hprev, prev); + P_SetTarget(&prev->hnext, mo); + prev = mo; + } + } + else if (ATTACK_IS_DOWN && player->kartstuff[k_itemheld]) // Orbinaut x3 thrown + { + K_ThrowKartItem(player, true, MT_ORBINAUT, 1, 0); + K_PlayAttackTaunt(player->mo); + player->kartstuff[k_itemamount]--; + K_UpdateHnextList(player, false); + } + break; + case KITEM_JAWZ: + if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO) + { + angle_t newangle; + INT32 moloop; + mobj_t *mo = NULL; + mobj_t *prev = player->mo; + + //K_PlayAttackTaunt(player->mo); + player->kartstuff[k_itemheld] = 1; + S_StartSound(player->mo, sfx_s3k3a); + + for (moloop = 0; moloop < player->kartstuff[k_itemamount]; moloop++) + { + newangle = (player->mo->angle + ANGLE_157h) + FixedAngle(((360 / player->kartstuff[k_itemamount]) * moloop) << FRACBITS) + ANGLE_90; + mo = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_JAWZ_SHIELD); + if (!mo) + { + player->kartstuff[k_itemamount] = moloop; + break; + } + mo->flags |= MF_NOCLIPTHING; + mo->angle = newangle; + mo->threshold = 10; + mo->movecount = player->kartstuff[k_itemamount]; + mo->movedir = mo->lastlook = moloop+1; + P_SetTarget(&mo->target, player->mo); + P_SetTarget(&mo->hprev, prev); + P_SetTarget(&prev->hnext, mo); + prev = mo; + } + } + else if (ATTACK_IS_DOWN && HOLDING_ITEM && player->kartstuff[k_itemheld]) // Jawz thrown + { + if (player->kartstuff[k_throwdir] == 1 || player->kartstuff[k_throwdir] == 0) + K_ThrowKartItem(player, true, MT_JAWZ, 1, 0); + else if (player->kartstuff[k_throwdir] == -1) // Throwing backward gives you a dud that doesn't home in + K_ThrowKartItem(player, true, MT_JAWZ_DUD, -1, 0); + K_PlayAttackTaunt(player->mo); + player->kartstuff[k_itemamount]--; + K_UpdateHnextList(player, false); + } + break; + case KITEM_MINE: + if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO) + { + mobj_t *mo; + player->kartstuff[k_itemheld] = 1; + S_StartSound(player->mo, sfx_s254); + mo = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_SSMINE_SHIELD); + if (mo) + { + mo->flags |= MF_NOCLIPTHING; + mo->threshold = 10; + mo->movecount = 1; + mo->movedir = 1; + P_SetTarget(&mo->target, player->mo); + P_SetTarget(&player->mo->hnext, mo); + } + } + else if (ATTACK_IS_DOWN && player->kartstuff[k_itemheld]) + { + K_ThrowKartItem(player, false, MT_SSMINE, 1, 1); + K_PlayAttackTaunt(player->mo); + player->kartstuff[k_itemamount]--; + player->kartstuff[k_itemheld] = 0; + K_UpdateHnextList(player, true); + } + break; + case KITEM_BALLHOG: + if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO) + { + player->kartstuff[k_itemamount]--; + K_ThrowKartItem(player, true, MT_BALLHOG, 1, 0); + K_PlayAttackTaunt(player->mo); + } + break; + case KITEM_SPB: + if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO) + { + player->kartstuff[k_itemamount]--; + K_ThrowKartItem(player, true, MT_SPB, 1, 0); + K_PlayAttackTaunt(player->mo); + } + break; + case KITEM_GROW: + if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO + && player->kartstuff[k_growshrinktimer] <= 0) // Grow holds the item box hostage + { + K_PlayPowerGloatSound(player->mo); + player->mo->scalespeed = mapobjectscale/TICRATE; + player->mo->destscale = (3*mapobjectscale)/2; + if (cv_kartdebugshrink.value && !modeattacking && !player->bot) + player->mo->destscale = (6*player->mo->destscale)/8; + player->kartstuff[k_growshrinktimer] = itemtime+(4*TICRATE); // 12 seconds + P_RestoreMusic(player); + if (!P_IsLocalPlayer(player)) + S_StartSound(player->mo, (cv_kartinvinsfx.value ? sfx_alarmg : sfx_kgrow)); + S_StartSound(player->mo, sfx_kc5a); + player->kartstuff[k_itemamount]--; + } + break; + case KITEM_SHRINK: + if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO) + { + K_DoShrink(player); + player->kartstuff[k_itemamount]--; + K_PlayPowerGloatSound(player->mo); + } + break; + case KITEM_THUNDERSHIELD: + if (player->kartstuff[k_curshield] != 1) + { + 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; + } + if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO) + { + K_DoThunderShield(player); + player->kartstuff[k_itemamount]--; + K_PlayAttackTaunt(player->mo); + } + break; + case KITEM_HYUDORO: + if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO) + { + player->kartstuff[k_itemamount]--; + K_DoHyudoroSteal(player); // yes. yes they do. + } + break; + case KITEM_POGOSPRING: + if (ATTACK_IS_DOWN && !HOLDING_ITEM && onground && NO_HYUDORO + && !player->kartstuff[k_pogospring]) + { + K_PlayBoostTaunt(player->mo); + K_DoPogoSpring(player->mo, 32<kartstuff[k_pogospring] = 1; + player->kartstuff[k_itemamount]--; + } + break; + case KITEM_SUPERRING: + if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO) + { + player->kartstuff[k_superring] += (10*3); + player->kartstuff[k_itemamount]--; + } + break; + case KITEM_KITCHENSINK: + if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO) + { + mobj_t *mo; + player->kartstuff[k_itemheld] = 1; + S_StartSound(player->mo, sfx_s254); + mo = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_SINK_SHIELD); + if (mo) + { + mo->flags |= MF_NOCLIPTHING; + mo->threshold = 10; + mo->movecount = 1; + mo->movedir = 1; + P_SetTarget(&mo->target, player->mo); + P_SetTarget(&player->mo->hnext, mo); + } + } + else if (ATTACK_IS_DOWN && HOLDING_ITEM && player->kartstuff[k_itemheld]) // Sink thrown + { + K_ThrowKartItem(player, false, MT_SINK, 1, 2); + K_PlayAttackTaunt(player->mo); + player->kartstuff[k_itemamount]--; + player->kartstuff[k_itemheld] = 0; + K_UpdateHnextList(player, true); + } + break; + case KITEM_SAD: + if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO + && !player->kartstuff[k_sadtimer]) + { + player->kartstuff[k_sadtimer] = stealtime; + player->kartstuff[k_itemamount]--; + } + break; + default: + break; } - else if (ATTACK_IS_DOWN && HOLDING_ITEM && player->kartstuff[k_itemheld]) // Jawz thrown - { - if (player->kartstuff[k_throwdir] == 1 || player->kartstuff[k_throwdir] == 0) - K_ThrowKartItem(player, true, MT_JAWZ, 1, 0); - else if (player->kartstuff[k_throwdir] == -1) // Throwing backward gives you a dud that doesn't home in - K_ThrowKartItem(player, true, MT_JAWZ_DUD, -1, 0); - K_PlayAttackTaunt(player->mo); - player->kartstuff[k_itemamount]--; - K_UpdateHnextList(player, false); - } - break; - case KITEM_MINE: - if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO) - { - mobj_t *mo; - player->kartstuff[k_itemheld] = 1; - S_StartSound(player->mo, sfx_s254); - mo = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_SSMINE_SHIELD); - if (mo) - { - mo->flags |= MF_NOCLIPTHING; - mo->threshold = 10; - mo->movecount = 1; - mo->movedir = 1; - P_SetTarget(&mo->target, player->mo); - P_SetTarget(&player->mo->hnext, mo); - } - } - else if (ATTACK_IS_DOWN && player->kartstuff[k_itemheld]) - { - K_ThrowKartItem(player, false, MT_SSMINE, 1, 1); - K_PlayAttackTaunt(player->mo); - player->kartstuff[k_itemamount]--; - player->kartstuff[k_itemheld] = 0; - K_UpdateHnextList(player, true); - } - break; - case KITEM_BALLHOG: - if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO) - { - player->kartstuff[k_itemamount]--; - K_ThrowKartItem(player, true, MT_BALLHOG, 1, 0); - K_PlayAttackTaunt(player->mo); - } - break; - case KITEM_SPB: - if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO) - { - player->kartstuff[k_itemamount]--; - K_ThrowKartItem(player, true, MT_SPB, 1, 0); - K_PlayAttackTaunt(player->mo); - } - break; - case KITEM_GROW: - if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO - && player->kartstuff[k_growshrinktimer] <= 0) // Grow holds the item box hostage - { - K_PlayPowerGloatSound(player->mo); - player->mo->scalespeed = mapobjectscale/TICRATE; - player->mo->destscale = (3*mapobjectscale)/2; - if (cv_kartdebugshrink.value && !modeattacking && !player->bot) - player->mo->destscale = (6*player->mo->destscale)/8; - player->kartstuff[k_growshrinktimer] = itemtime+(4*TICRATE); // 12 seconds - P_RestoreMusic(player); - if (!P_IsLocalPlayer(player)) - S_StartSound(player->mo, (cv_kartinvinsfx.value ? sfx_alarmg : sfx_kgrow)); - S_StartSound(player->mo, sfx_kc5a); - player->kartstuff[k_itemamount]--; - } - break; - case KITEM_SHRINK: - if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO) - { - K_DoShrink(player); - player->kartstuff[k_itemamount]--; - K_PlayPowerGloatSound(player->mo); - } - break; - case KITEM_THUNDERSHIELD: - if (player->kartstuff[k_curshield] != 1) - { - 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; - } - if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO) - { - K_DoThunderShield(player); - player->kartstuff[k_itemamount]--; - K_PlayAttackTaunt(player->mo); - } - break; - case KITEM_HYUDORO: - if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO) - { - player->kartstuff[k_itemamount]--; - K_DoHyudoroSteal(player); // yes. yes they do. - } - break; - case KITEM_POGOSPRING: - if (ATTACK_IS_DOWN && !HOLDING_ITEM && onground && NO_HYUDORO - && !player->kartstuff[k_pogospring]) - { - K_PlayBoostTaunt(player->mo); - K_DoPogoSpring(player->mo, 32<kartstuff[k_pogospring] = 1; - player->kartstuff[k_itemamount]--; - } - break; - case KITEM_KITCHENSINK: - if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO) - { - mobj_t *mo; - player->kartstuff[k_itemheld] = 1; - S_StartSound(player->mo, sfx_s254); - mo = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_SINK_SHIELD); - if (mo) - { - mo->flags |= MF_NOCLIPTHING; - mo->threshold = 10; - mo->movecount = 1; - mo->movedir = 1; - P_SetTarget(&mo->target, player->mo); - P_SetTarget(&player->mo->hnext, mo); - } - } - else if (ATTACK_IS_DOWN && HOLDING_ITEM && player->kartstuff[k_itemheld]) // Sink thrown - { - K_ThrowKartItem(player, false, MT_SINK, 1, 2); - K_PlayAttackTaunt(player->mo); - player->kartstuff[k_itemamount]--; - player->kartstuff[k_itemheld] = 0; - K_UpdateHnextList(player, true); - } - break; - case KITEM_SAD: - if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO - && !player->kartstuff[k_sadtimer]) - { - player->kartstuff[k_sadtimer] = stealtime; - player->kartstuff[k_itemamount]--; - } - break; - default: - break; + } } } // Prevent ring misfire - if (player->kartstuff[k_itemtype] != KITEM_NONE) - player->kartstuff[k_ringdelay] = 15; + if (!ATTACK_IS_DOWN) + { + if (player->kartstuff[k_itemtype] == KITEM_NONE + && !(player->kartstuff[k_growshrinktimer] + || player->kartstuff[k_rocketsneakertimer] + || player->kartstuff[k_eggmanheld] + || player->kartstuff[k_eggmanexplode] + || player->kartstuff[k_rocketsneakertimer] + || player->kartstuff[k_growshrinktimer])) + player->kartstuff[k_userings] = 1; + else + player->kartstuff[k_userings] = 0; + } // No more! if (!player->kartstuff[k_itemamount]) @@ -6732,8 +6773,6 @@ const char *K_GetItemPatch(UINT8 item, boolean tiny) { switch (item) { - case KITEM_SUPERRING: - return (tiny ? "K_ISRING" : "K_ITRING"); case KITEM_SNEAKER: case KRITEM_TRIPLESNEAKER: return (tiny ? "K_ISSHOE" : "K_ITSHOE"); @@ -6768,6 +6807,8 @@ const char *K_GetItemPatch(UINT8 item, boolean tiny) return (tiny ? "K_ISHYUD" : "K_ITHYUD"); case KITEM_POGOSPRING: return (tiny ? "K_ISPOGO" : "K_ITPOGO"); + case KITEM_SUPERRING: + return (tiny ? "K_ISRING" : "K_ITRING"); case KITEM_KITCHENSINK: return (tiny ? "K_ISSINK" : "K_ITSINK"); case KRITEM_TRIPLEORBINAUT: @@ -7124,9 +7165,6 @@ static void K_drawKartItem(void) switch(stplyr->kartstuff[k_itemtype]) { - case KITEM_SUPERRING: - localpatch = kp_superring[offset]; - break; case KITEM_SNEAKER: localpatch = kp_sneaker[offset]; break; @@ -7175,6 +7213,9 @@ static void K_drawKartItem(void) case KITEM_POGOSPRING: localpatch = kp_pogospring[offset]; break; + case KITEM_SUPERRING: + localpatch = kp_superring[offset]; + break; case KITEM_KITCHENSINK: localpatch = kp_kitchensink[offset]; break; @@ -7875,39 +7916,39 @@ static void K_drawKartRingsAndLives(void) INT32 splitflags = K_calcSplitFlags(V_SNAPTOBOTTOM|V_SNAPTOLEFT); UINT8 firstnum = ((abs(stplyr->kartstuff[k_rings]) / 10) % 10); UINT8 secondnum = (abs(stplyr->kartstuff[k_rings]) % 10); - UINT8 *debtmap = NULL; + UINT8 *ringmap = NULL; - if (stplyr->kartstuff[k_rings] <= 0 && (leveltime/5 & 1)) - debtmap = R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_CRIMSON, GTC_CACHE); + // Rings + if (stplyr->kartstuff[k_rings] <= 0 && (leveltime/5 & 1)) // In debt + ringmap = R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_CRIMSON, GTC_CACHE); + else if (stplyr->kartstuff[k_rings] >= 20) // Maxed out + ringmap = R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_YELLOW, GTC_CACHE); if (netgame) V_DrawScaledPatch(LAPS_X, LAPS_Y-11, V_HUDTRANS|splitflags, kp_ringsticker[1]); else V_DrawScaledPatch(LAPS_X, LAPS_Y-11, V_HUDTRANS|splitflags, kp_ringsticker[0]); - V_DrawMappedPatch(LAPS_X+7, LAPS_Y-16, V_HUDTRANS|splitflags, kp_ring[0], debtmap); + V_DrawMappedPatch(LAPS_X+7, LAPS_Y-16, V_HUDTRANS|splitflags, kp_ring[0], (stplyr->kartstuff[k_rings] <= 0 ? ringmap : NULL)); // Don't do maxed out gold mapping - if (stplyr->kartstuff[k_rings] < 0) + if (stplyr->kartstuff[k_rings] < 0) // Draw the minus for ring debt { - V_DrawMappedPatch(LAPS_X+23, LAPS_Y-11, V_HUDTRANS|splitflags, kp_ringdebtminus, debtmap); - V_DrawMappedPatch(LAPS_X+29, LAPS_Y-11, V_HUDTRANS|splitflags, kp_facenum[firstnum], debtmap); - V_DrawMappedPatch(LAPS_X+35, LAPS_Y-11, V_HUDTRANS|splitflags, kp_facenum[secondnum], debtmap); + V_DrawMappedPatch(LAPS_X+23, LAPS_Y-11, V_HUDTRANS|splitflags, kp_ringdebtminus, ringmap); + V_DrawMappedPatch(LAPS_X+29, LAPS_Y-11, V_HUDTRANS|splitflags, kp_facenum[firstnum], ringmap); + V_DrawMappedPatch(LAPS_X+35, LAPS_Y-11, V_HUDTRANS|splitflags, kp_facenum[secondnum], ringmap); } else { - V_DrawMappedPatch(LAPS_X+23, LAPS_Y-11, V_HUDTRANS|splitflags, kp_facenum[firstnum], debtmap); - V_DrawMappedPatch(LAPS_X+29, LAPS_Y-11, V_HUDTRANS|splitflags, kp_facenum[secondnum], debtmap); + V_DrawMappedPatch(LAPS_X+23, LAPS_Y-11, V_HUDTRANS|splitflags, kp_facenum[firstnum], ringmap); + V_DrawMappedPatch(LAPS_X+29, LAPS_Y-11, V_HUDTRANS|splitflags, kp_facenum[secondnum], ringmap); } + // Lives if (!netgame) { - UINT8 *colormap = R_GetTranslationColormap(stplyr->skin, stplyr->mo->color, GTC_CACHE); - - if (stplyr->mo->colorized) - colormap = R_GetTranslationColormap(TC_RAINBOW, stplyr->mo->color, GTC_CACHE); - + UINT8 *colormap = R_GetTranslationColormap(stplyr->skin, stplyr->skincolor, GTC_CACHE); V_DrawMappedPatch(LAPS_X+46, LAPS_Y-16, V_HUDTRANS|splitflags, facerankprefix[stplyr->skin], colormap); - V_DrawScaledPatch(LAPS_X+63, LAPS_Y-11, V_HUDTRANS|splitflags, kp_facenum[(stplyr->lives % 10)]); + V_DrawScaledPatch(LAPS_X+63, LAPS_Y-11, V_HUDTRANS|splitflags, kp_facenum[(stplyr->lives % 10)]); // make sure this doesn't overflow } } diff --git a/src/p_enemy.c b/src/p_enemy.c index 843666db7..3356a38d5 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -747,20 +747,24 @@ static boolean P_LookForShield(mobj_t *actor) if (player->health <= 0 || !player->mo) continue; // dead + if (!P_CheckSight(actor, player->mo)) + continue; // can't see + //When in CTF, don't pull rings that you cannot pick up. if ((actor->type == MT_REDTEAMRING && player->ctfteam != 1) || (actor->type == MT_BLUETEAMRING && player->ctfteam != 2)) continue; - if ((player->powers[pw_shield] & SH_NOSTACK) == SH_ATTRACT - && (P_AproxDistance(P_AproxDistance(actor->x-player->mo->x, actor->y-player->mo->y), actor->z-player->mo->z) < FixedMul(RING_DIST/4, player->mo->scale))) + if ((player->kartstuff[k_itemtype] == KITEM_THUNDERSHIELD) && ((player->kartstuff[k_rings]+player->kartstuff[k_pickuprings]) < 20) + && P_AproxDistance(actor->x-player->mo->x, actor->y-player->mo->y) < FixedMul(RING_DIST/4, player->mo->scale) + && P_AproxDistance(0, actor->z-player->mo->z) < FixedMul(RING_DIST/8, player->mo->scale)) { P_SetTarget(&actor->tracer, player->mo); return true; } } - //return false; + return false; } #ifdef WEIGHTEDRECYCLER @@ -3654,6 +3658,7 @@ void A_AttractChase(mobj_t *actor) if (actor->extravalue1 >= 16) { P_GivePlayerRings(actor->target->player, 1); + actor->target->player->kartstuff[k_pickuprings]--; if (actor->cvmem) // caching S_StartSound(actor->target, sfx_s1c5); else @@ -3682,69 +3687,76 @@ void A_AttractChase(mobj_t *actor) if (actor->threshold > 0) actor->threshold--; - // spilled rings flicker before disappearing - if (leveltime & 1 && actor->type == (mobjtype_t)actor->info->reactiontime && actor->fuse && actor->fuse < 2*TICRATE) - actor->flags2 |= MF2_DONTDRAW; - else - actor->flags2 &= ~MF2_DONTDRAW; - - // Flung rings lose speed over time + // spilled rings flicker before disappearing, and get capped to a certain speed if (actor->type == (mobjtype_t)actor->info->reactiontime) { - const fixed_t destspeed = FRACUNIT; + const fixed_t maxspeed = 4<momx, actor->momy); - if (oldspeed > destspeed) + if (oldspeed > maxspeed) { - fixed_t newspeed = max(destspeed, oldspeed - (FRACUNIT / TICRATE)); - + fixed_t newspeed = max(maxspeed, oldspeed-FRACUNIT); actor->momx = FixedMul(FixedDiv(actor->momx, oldspeed), newspeed); actor->momy = FixedMul(FixedDiv(actor->momy, oldspeed), newspeed); } + + if (actor->fuse && actor->fuse < 3*TICRATE && leveltime & 1) + actor->flags2 |= MF2_DONTDRAW; + else + actor->flags2 &= ~MF2_DONTDRAW; } - // Turn flingrings back into regular rings if attracted. - if (actor->tracer && actor->tracer->player - && (actor->tracer->player->powers[pw_shield] & SH_NOSTACK) != SH_ATTRACT - && actor->info->reactiontime && actor->type != (mobjtype_t)actor->info->reactiontime) + 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) { - mobj_t *newring; - newring = P_SpawnMobj(actor->x, actor->y, actor->z, actor->info->reactiontime); - newring->momx = actor->momx; - newring->momy = actor->momy; - newring->momz = actor->momz; - P_RemoveMobj(actor); - return; + fixed_t dist; + angle_t hang, vang; + + // If a flung ring gets attracted by a shield, change it into a normal ring. + if (actor->type == (mobjtype_t)actor->info->reactiontime) + { + P_SpawnMobj(actor->x, actor->y, actor->z, actor->info->painchance); + P_RemoveMobj(actor); + return; + } + + // Keep stuff from going down inside floors and junk + actor->flags &= ~MF_NOCLIPHEIGHT; + + // Let attracted rings move through walls and such. + actor->flags |= MF_NOCLIP; + + // flag to show it's been attracted once before + actor->cusval = 1; + + // P_Attract is too "smart" for Kart; keep it simple, stupid! + dist = P_AproxDistance(P_AproxDistance(actor->x - actor->tracer->x, actor->y - actor->tracer->y), actor->z - actor->tracer->z); + hang = R_PointToAngle2(actor->x, actor->y, actor->tracer->x, actor->tracer->y); + vang = R_PointToAngle2(actor->z , 0, actor->tracer->z, dist); + + actor->momx -= actor->momx>>4, actor->momy -= actor->momy>>4, actor->momz -= actor->momz>>4; + actor->momx += FixedMul(FINESINE(vang>>ANGLETOFINESHIFT), FixedMul(FINECOSINE(hang>>ANGLETOFINESHIFT), 2*actor->scale)); + actor->momy += FixedMul(FINESINE(vang>>ANGLETOFINESHIFT), FixedMul(FINESINE(hang>>ANGLETOFINESHIFT), 2*actor->scale)); + actor->momz += FixedMul(FINECOSINE(vang>>ANGLETOFINESHIFT), 2*actor->scale); } - - P_LookForShield(actor); // Go find 'em, boy! - - if (!actor->tracer - || !actor->tracer->player - || !actor->tracer->health - || !P_CheckSight(actor, actor->tracer)) // You have to be able to SEE it...sorta + else { - // Lost attracted rings don't through walls anymore. - actor->flags &= ~MF_NOCLIP; - P_SetTarget(&actor->tracer, NULL); - return; + // Turn rings back into flung rings if lost + if (actor->cusval && actor->info->reactiontime && actor->type != (mobjtype_t)actor->info->reactiontime) + { + mobj_t *newring; + newring = P_SpawnMobj(actor->x, actor->y, actor->z, actor->info->reactiontime); + P_InstaThrust(newring, P_RandomRange(0,7) * ANGLE_45, 2<momz = 5<fuse = 120*TICRATE; + P_RemoveMobj(actor); + return; + } + else + P_LookForShield(actor); // Go find 'em, boy! } - - // If a FlingRing gets attracted by a shield, change it into a normal ring. - if (actor->type == (mobjtype_t)actor->info->reactiontime) - { - P_SpawnMobj(actor->x, actor->y, actor->z, actor->info->painchance); - P_RemoveMobj(actor); - return; - } - - // Keep stuff from going down inside floors and junk - actor->flags &= ~MF_NOCLIPHEIGHT; - - // Let attracted rings move through walls and such. - actor->flags |= MF_NOCLIP; - - P_Attract(actor, actor->tracer, false); } } diff --git a/src/p_inter.c b/src/p_inter.c index 4b8ff8e8c..fe7619002 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -697,14 +697,16 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) return; // Reached the cap, don't waste 'em! - if (player->kartstuff[k_rings] >= 20) + if ((player->kartstuff[k_rings] + player->kartstuff[k_pickuprings]) >= 20) return; special->momx = special->momy = special->momz = 0; - // SRB2Kart + special->extravalue1 = 1; // Ring collect animation timer special->angle = R_PointToAngle2(toucher->x, toucher->y, special->x, special->y); // animation angle P_SetTarget(&special->target, toucher); // toucher for thinker + player->kartstuff[k_pickuprings]++; + return; case MT_COIN: @@ -3294,7 +3296,7 @@ void P_PlayerRingBurst(player_t *player, INT32 num_rings) return; // Cap the maximum loss automatically to 2 in ring debt - if (player->kartstuff[k_rings] < 0 && num_rings > 2) + if (player->kartstuff[k_rings] <= 0 && num_rings > 2) num_rings = 2; P_GivePlayerRings(player, -num_rings); @@ -3313,7 +3315,7 @@ void P_PlayerRingBurst(player_t *player, INT32 num_rings) mo = P_SpawnMobj(player->mo->x, player->mo->y, z, objType); mo->threshold = 10; - mo->fuse = 15*TICRATE; + mo->fuse = 120*TICRATE; P_SetTarget(&mo->target, player->mo); mo->destscale = player->mo->scale; diff --git a/src/p_mobj.c b/src/p_mobj.c index 2e136430b..c00bcc216 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -10729,6 +10729,8 @@ void P_PrecipitationEffects(void) // void P_RespawnSpecials(void) { + UINT8 p, pcount = 0; + tic_t time = 168*TICRATE; fixed_t x, y, z; subsector_t *ss; mobj_t *mo = NULL; @@ -10787,9 +10789,22 @@ void P_RespawnSpecials(void) if (iquehead == iquetail) return; + // wait time depends on player count + for (p = 0; p < MAXPLAYERS; p++) + { + if (!playeringame[p] || players[p].spectator) + pcount++; + } + + if (pcount > 1) + time -= pcount * (8*TICRATE); + else if (pcount == 1) // No respawn when alone + return; + else + time = 30*TICRATE; // Respawn things in empty dedicated servers + // the first item in the queue is the first to respawn - // wait at least 30 seconds - if (leveltime - itemrespawntime[iquetail] < (tic_t)cv_itemrespawntime.value*TICRATE) + if (leveltime - itemrespawntime[iquetail] < time) return; mthing = itemrespawnque[iquetail];