diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 438cdcd54..dad02aa14 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -324,6 +324,7 @@ consvar_t cv_1up = {"tv_1up", "5", CV_NETVAR|CV_CHEAT, chanc consvar_t cv_eggmanbox = {"tv_eggman", "5", CV_NETVAR|CV_CHEAT, chances_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};*/ // SRB2kart +consvar_t cv_superring = {"superring", "On", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_sneaker = {"sneaker", "On", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_rocketsneaker = {"rocketsneaker", "On", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_invincibility = {"invincibility", "On", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; diff --git a/src/d_netcmd.h b/src/d_netcmd.h index c590eee65..80a4eead3 100644 --- a/src/d_netcmd.h +++ b/src/d_netcmd.h @@ -101,7 +101,7 @@ extern consvar_t cv_1up, cv_eggmanbox; extern consvar_t cv_recycler;*/ // SRB2kart items -extern consvar_t cv_sneaker, cv_rocketsneaker, cv_invincibility, cv_banana; +extern consvar_t cv_superring, cv_sneaker, cv_rocketsneaker, cv_invincibility, cv_banana; extern consvar_t cv_eggmanmonitor, cv_orbinaut, cv_jawz, cv_mine; extern consvar_t cv_ballhog, cv_selfpropelledbomb, cv_grow, cv_shrink; extern consvar_t cv_thundershield, cv_hyudoro, cv_pogospring, cv_kitchensink; diff --git a/src/d_player.h b/src/d_player.h index b430f20a4..a3f4b39bb 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -234,6 +234,7 @@ typedef enum { KITEM_SAD = -1, KITEM_NONE = 0, + KITEM_SUPERRING, KITEM_SNEAKER, KITEM_ROCKETSNEAKER, KITEM_INVINCIBILITY, @@ -288,7 +289,7 @@ typedef enum k_enginesnd, // Engine sound number you're on. k_floorboost, // Prevents Sneaker sounds for a breif duration when triggered by a floor panel - k_spinouttype, // Determines whether to thrust forward or not while spinning out; 0 = move forwards, 1 = stay still + k_spinouttype, // Determines whether to thrust forward or not while spinning out; 0 = move forwards, 1 = stay still, 2 = stay still & no flashing tics k_drift, // Drifting Left or Right, plus a bigger counter = sharper turn k_driftend, // Drift has ended, used to adjust character angle after drift @@ -296,6 +297,9 @@ typedef enum k_driftboost, // Boost you get from drifting 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_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 k_offroad, // In Super Mario Kart, going offroad has lee-way of about 1 second before you start losing speed k_pogospring, // Pogo spring bounce effect @@ -325,6 +329,7 @@ typedef enum k_hyudorotimer, // Duration of the Hyudoro offroad effect itself k_stealingtimer, // You are stealing an item, this is your timer k_stolentimer, // You are being stolen from, this is your timer + k_superring, // Spawn rings on top of you every tic! k_sneakertimer, // Duration of the Sneaker Boost itself k_growshrinktimer, // > 0 = Big, < 0 = small k_squishedtimer, // Squished frame timer diff --git a/src/dehacked.c b/src/dehacked.c index 11aed24d0..6ea0c2ea7 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -8283,6 +8283,9 @@ static const char *const KARTSTUFF_LIST[] = { "DRIFTBOOST", "BOOSTCHARGE", "STARTBOOST", + "RINGS", + "RINGDELAY", + "RINGBOOST", "JMP", "OFFROAD", "POGOSPRING", @@ -8309,6 +8312,7 @@ static const char *const KARTSTUFF_LIST[] = { "HYUDOROTIMER", "STEALINGTIMER", "STOLENTIMER", + "SUPERRING", "SNEAKERTIMER", "GROWSHRINKTIMER", "SQUISHEDTIMER", @@ -8866,6 +8870,7 @@ 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}, diff --git a/src/info.c b/src/info.c index 5701f1c9e..1142a2562 100644 --- a/src/info.c +++ b/src/info.c @@ -5444,8 +5444,8 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL, // xdeathstate sfx_itemup, // deathsound 38*FRACUNIT, // speed - 16*FRACUNIT, // radius - 24*FRACUNIT, // height + 24*FRACUNIT, // radius + 48*FRACUNIT, // height 0, // display offset 100, // mass 0, // damage @@ -5471,13 +5471,13 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL, // xdeathstate sfx_itemup, // deathsound 38*FRACUNIT, // speed - 15*FRACUNIT, // radius - 24*FRACUNIT, // height + 24*FRACUNIT, // radius + 48*FRACUNIT, // height 0, // display offset 100, // mass 0, // damage sfx_None, // activesound - MF_SLIDEME|MF_SPECIAL, // flags + MF_SLIDEME|MF_BOUNCE|MF_SPECIAL|MF_DONTENCOREMAP, // flags S_NULL // raisestate }, diff --git a/src/k_kart.c b/src/k_kart.c index 468f54381..07b1698b7 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -397,6 +397,7 @@ UINT8 K_GetKartColorByName(const char *name) void K_RegisterKartStuff(void) { + CV_RegisterVar(&cv_superring); CV_RegisterVar(&cv_sneaker); CV_RegisterVar(&cv_rocketsneaker); CV_RegisterVar(&cv_invincibility); @@ -496,12 +497,13 @@ boolean K_IsPlayerWanted(player_t *player) static INT32 K_KartItemOddsRace[NUMKARTRESULTS][10] = { //P-Odds 0 1 2 3 4 5 6 7 8 9 - /*Sneaker*/ {20, 0, 0, 4, 6, 6, 0, 0, 0, 0 }, // Sneaker + /*Super Ring*/ {10, 2, 1, 1, 0, 0, 0, 0, 0, 0 }, // Super Ring + /*Sneaker*/ {10, 0, 0, 4, 6, 6, 0, 0, 0, 0 }, // Sneaker /*Rocket Sneaker*/ { 0, 0, 0, 0, 0, 1, 3, 5, 3, 0 }, // Rocket Sneaker /*Invincibility*/ { 0, 0, 0, 0, 0, 1, 4, 6,14, 0 }, // Invincibility /*Banana*/ { 0,10, 4, 2, 1, 0, 0, 0, 0, 0 }, // Banana /*Eggman Monitor*/ { 0, 3, 2, 1, 0, 0, 0, 0, 0, 0 }, // Eggman Monitor - /*Orbinaut*/ { 0, 8, 6, 4, 2, 0, 0, 0, 0, 0 }, // Orbinaut + /*Orbinaut*/ { 0, 6, 5, 3, 2, 0, 0, 0, 0, 0 }, // Orbinaut /*Jawz*/ { 0, 0, 3, 2, 1, 1, 0, 0, 0, 0 }, // Jawz /*Mine*/ { 0, 0, 2, 2, 1, 0, 0, 0, 0, 0 }, // Mine /*Ballhog*/ { 0, 0, 0, 2, 1, 0, 0, 0, 0, 0 }, // Ballhog @@ -523,6 +525,7 @@ static INT32 K_KartItemOddsRace[NUMKARTRESULTS][10] = static INT32 K_KartItemOddsBattle[NUMKARTRESULTS][6] = { //P-Odds 0 1 2 3 4 5 + /*Super Ring*/ { 0, 0, 0, 0, 0, 0 }, // Super Ring /*Sneaker*/ { 3, 2, 2, 2, 0, 2 }, // Sneaker /*Rocket Sneaker*/ { 0, 0, 0, 0, 0, 0 }, // Rocket Sneaker /*Invincibility*/ { 0, 1, 2, 3, 4, 2 }, // Invincibility @@ -617,6 +620,7 @@ static INT32 K_KartGetItemOdds(UINT8 pos, SINT8 item, fixed_t mashed) SINT8 first = -1, second = -1; INT32 secondist = 0; boolean itemenabled[NUMKARTRESULTS-1] = { + cv_superring.value, cv_sneaker.value, cv_rocketsneaker.value, cv_invincibility.value, @@ -1051,6 +1055,33 @@ static fixed_t K_GetMobjWeight(mobj_t *mobj, mobj_t *against) return weight; } +// This kind of wipeout happens with no rings -- doesn't remove a bumper, has no invulnerability, and is much shorter. +static void K_BumpWipeoutPlayer(player_t *player, INT32 length) +{ + if (player->health <= 0) + return; + + if (player->powers[pw_flashing] > 0 || player->kartstuff[k_squishedtimer] > 0 || player->kartstuff[k_spinouttimer] > 0 + || player->kartstuff[k_invincibilitytimer] > 0 || player->kartstuff[k_growshrinktimer] > 0 || player->kartstuff[k_hyudorotimer] > 0 + || (G_BattleGametype() && ((player->kartstuff[k_bumper] <= 0 && player->kartstuff[k_comebacktimer]) || player->kartstuff[k_comebackmode] == 1))) + return; + + player->kartstuff[k_driftboost] = 0; + player->kartstuff[k_drift] = 0; + player->kartstuff[k_driftcharge] = 0; + player->kartstuff[k_pogospring] = 0; + + player->kartstuff[k_spinouttype] = 2; + player->kartstuff[k_spinouttimer] = length; + player->kartstuff[k_wipeoutslow] = min(length-1, wipeoutslowtime+1); + + if (player->mo->state != &states[S_KART_SPIN]) + P_SetPlayerMobjState(player->mo, S_KART_SPIN); + + K_DropHnextList(player); + return; +} + void K_KartBouncing(mobj_t *mobj1, mobj_t *mobj2, boolean bounce, boolean solid) { mobj_t *fx; @@ -1199,11 +1230,21 @@ void K_KartBouncing(mobj_t *mobj1, mobj_t *mobj2, boolean bounce, boolean solid) mobj1->player->rmomx = mobj1->momx - mobj1->player->cmomx; mobj1->player->rmomy = mobj1->momy - mobj1->player->cmomy; mobj1->player->kartstuff[k_justbumped] = bumptime; + if (mobj1->player->kartstuff[k_spinouttimer]) { mobj1->player->kartstuff[k_wipeoutslow] = wipeoutslowtime+1; mobj1->player->kartstuff[k_spinouttimer] = max(wipeoutslowtime+1, mobj1->player->kartstuff[k_spinouttimer]); } + else if (mobj2->player) // Player VS player bumping only + { + if (mobj1->player->kartstuff[k_rings] <= 0) + { + K_BumpWipeoutPlayer(mobj1->player, TICRATE + (4 * (mobj2->player->kartweight - mobj1->player->kartweight))); + P_PlayRinglossSound(mobj1); + } + P_PlayerRingBurst(mobj1->player, 1); + } } if (mobj2->player) @@ -1211,11 +1252,21 @@ void K_KartBouncing(mobj_t *mobj1, mobj_t *mobj2, boolean bounce, boolean solid) mobj2->player->rmomx = mobj2->momx - mobj2->player->cmomx; mobj2->player->rmomy = mobj2->momy - mobj2->player->cmomy; mobj2->player->kartstuff[k_justbumped] = bumptime; + if (mobj2->player->kartstuff[k_spinouttimer]) { mobj2->player->kartstuff[k_wipeoutslow] = wipeoutslowtime+1; mobj2->player->kartstuff[k_spinouttimer] = max(wipeoutslowtime+1, mobj2->player->kartstuff[k_spinouttimer]); } + else if (mobj1->player) // Player VS player bumping only + { + if (mobj2->player->kartstuff[k_rings] <= 0) + { + K_BumpWipeoutPlayer(mobj2->player, TICRATE + (4 * (mobj1->player->kartweight - mobj2->player->kartweight))); + P_PlayRinglossSound(mobj2); + } + P_PlayerRingBurst(mobj2->player, 1); + } } } @@ -1281,6 +1332,67 @@ static void K_UpdateOffroad(player_t *player) player->kartstuff[k_offroad] = 0; } +void K_KartPainEnergyFling(player_t *player) +{ + static const UINT8 numfling = 5; + INT32 i; + mobj_t *mo; + angle_t fa; + fixed_t ns; + fixed_t z; + + // Better safe than sorry. + if (!player) + return; + + // P_PlayerRingBurst: "There's no ring spilling in kart, so I'm hijacking this for the same thing as TD" + // :oh: + + for (i = 0; i < numfling; i++) + { + INT32 objType = mobjinfo[MT_FLINGENERGY].reactiontime; + fixed_t momxy, momz; // base horizonal/vertical thrusts + + z = player->mo->z; + if (player->mo->eflags & MFE_VERTICALFLIP) + z += player->mo->height - mobjinfo[objType].height; + + mo = P_SpawnMobj(player->mo->x, player->mo->y, z, objType); + + mo->fuse = 8*TICRATE; + P_SetTarget(&mo->target, player->mo); + + mo->destscale = player->mo->scale; + P_SetScale(mo, player->mo->scale); + + // Angle offset by player angle, then slightly offset by amount of fling + fa = ((i*FINEANGLES/16) + (player->mo->angle>>ANGLETOFINESHIFT) - ((numfling-1)*FINEANGLES/32)) & FINEMASK; + + if (i > 15) + { + momxy = 3*FRACUNIT; + momz = 4*FRACUNIT; + } + else + { + momxy = 28*FRACUNIT; + momz = 3*FRACUNIT; + } + + ns = FixedMul(momxy, mo->scale); + mo->momx = FixedMul(FINECOSINE(fa),ns); + + ns = momz; + P_SetObjectMomZ(mo, ns, false); + + if (i & 1) + P_SetObjectMomZ(mo, ns, true); + + if (player->mo->eflags & MFE_VERTICALFLIP) + mo->momz *= -1; + } +} + // These have to go earlier than its sisters because of K_RespawnChecker... void K_MatchGenericExtraFlags(mobj_t *mo, mobj_t *master) { @@ -1447,6 +1559,7 @@ void K_RespawnChecker(player_t *player) player->mo->colorized = false; player->kartstuff[k_dropdash] = 0; player->kartstuff[k_respawn] = 0; + P_PlayerRingBurst(player, 3); } } } @@ -1572,6 +1685,16 @@ void K_PlayOvertakeSound(mobj_t *source) K_RegularVoiceTimers(source->player); } +void K_PlayPainSound(mobj_t *source) +{ + sfxenum_t pick = P_RandomKey(2); // Gotta roll the RNG every time this is called for sync reasons + + if (cv_kartvoices.value) + S_StartSound(source, sfx_khurt1 + pick); + + K_RegularVoiceTimers(source->player); +} + void K_PlayHitEmSound(mobj_t *source) { if (cv_kartvoices.value) @@ -1667,6 +1790,12 @@ static void K_GetKartBoostPower(player_t *player) speedboost = max(speedboost, FRACUNIT/5); // + 20% } + if (player->kartstuff[k_ringboost]) // Ring Boost + { + speedboost = max(speedboost, FRACUNIT/8); // + 12.5% + accelboost = max(accelboost, 2*FRACUNIT); // + 200% + } + if (player->kartstuff[k_driftboost]) // Drift Boost { speedboost = max(speedboost, FRACUNIT/4); // + 25% @@ -1867,7 +1996,6 @@ void K_SpinPlayer(player_t *player, mobj_t *source, INT32 type, mobj_t *inflicto (void)inflictor; // in case some weirdo doesn't want Lua. #endif - if (!trapitem && G_BattleGametype()) { if (K_IsPlayerWanted(player)) @@ -1879,7 +2007,7 @@ void K_SpinPlayer(player_t *player, mobj_t *source, INT32 type, mobj_t *inflicto if (player->health <= 0) return; - if (player->powers[pw_flashing] > 0 || player->kartstuff[k_squishedtimer] > 0 || player->kartstuff[k_spinouttimer] > 0 + if (player->powers[pw_flashing] > 0 || player->kartstuff[k_squishedtimer] > 0 || (player->kartstuff[k_spinouttimer] > 0 && player->kartstuff[k_spinouttype] != 2) || player->kartstuff[k_invincibilitytimer] > 0 || player->kartstuff[k_growshrinktimer] > 0 || player->kartstuff[k_hyudorotimer] > 0 || (G_BattleGametype() && ((player->kartstuff[k_bumper] <= 0 && player->kartstuff[k_comebacktimer]) || player->kartstuff[k_comebackmode] == 1))) { @@ -1949,7 +2077,7 @@ void K_SpinPlayer(player_t *player, mobj_t *source, INT32 type, mobj_t *inflicto player->kartstuff[k_spinouttype] = type; - if (player->kartstuff[k_spinouttype] <= 0) // type 0 is spinout, type 1 is wipeout + if (player->kartstuff[k_spinouttype] <= 0) // type 0 is spinout, type 1 is wipeout, type 2 is no-invuln wipeout { // At spinout, player speed is increased to 1/4 their regular speed, moving them forward if (player->speed < K_GetKartSpeed(player, true)/4) @@ -1960,6 +2088,10 @@ void K_SpinPlayer(player_t *player, mobj_t *source, INT32 type, mobj_t *inflicto player->kartstuff[k_spinouttimer] = (3*TICRATE/2)+2; player->powers[pw_flashing] = K_GetKartFlashing(player); + P_PlayRinglossSound(player->mo); + P_PlayerRingBurst(player, 5); + K_PlayPainSound(player->mo); + if (player->mo->state != &states[S_KART_SPIN]) P_SetPlayerMobjState(player->mo, S_KART_SPIN); @@ -2096,6 +2228,8 @@ void K_SquishPlayer(player_t *player, mobj_t *source, mobj_t *inflictor) P_SetPlayerMobjState(player->mo, S_KART_SQUISH); P_PlayRinglossSound(player->mo); + P_PlayerRingBurst(player, 5); + K_PlayPainSound(player->mo); player->kartstuff[k_instashield] = 15; if (cv_kartdebughuddrop.value && !modeattacking) @@ -2132,8 +2266,7 @@ void K_ExplodePlayer(player_t *player, mobj_t *source, mobj_t *inflictor) // A b if (player->health <= 0) return; - if (/*player->powers[pw_flashing] > 0 || player->kartstuff[k_squishedtimer] > 0 || player->kartstuff[k_spinouttimer] > 0 // Explosions should combo, because of SPB and Eggman - ||*/player->kartstuff[k_invincibilitytimer] > 0 || player->kartstuff[k_growshrinktimer] > 0 || player->kartstuff[k_hyudorotimer] > 0 + if (player->kartstuff[k_invincibilitytimer] > 0 || player->kartstuff[k_growshrinktimer] > 0 || player->kartstuff[k_hyudorotimer] > 0 // Do not check spinout, because SPB and Eggman should combo || (G_BattleGametype() && ((player->kartstuff[k_bumper] <= 0 && player->kartstuff[k_comebacktimer]) || player->kartstuff[k_comebackmode] == 1))) { if (!force) // ShouldDamage can bypass that, again. @@ -2162,7 +2295,7 @@ void K_ExplodePlayer(player_t *player, mobj_t *source, mobj_t *inflictor) // A b player->kartstuff[k_pogospring] = 0; // This is the only part that SHOULDN'T combo :VVVVV - if (G_BattleGametype() && !(player->powers[pw_flashing] > 0 || player->kartstuff[k_squishedtimer] > 0 || player->kartstuff[k_spinouttimer] > 0)) + if (G_BattleGametype() && !(player->powers[pw_flashing] > 0 || player->kartstuff[k_squishedtimer] > 0 || (player->kartstuff[k_spinouttimer] > 0 && player->kartstuff[k_spinouttype] != 2))) { if (source && source->player && player != source->player) { @@ -2216,6 +2349,8 @@ void K_ExplodePlayer(player_t *player, mobj_t *source, mobj_t *inflictor) // A b P_SetPlayerMobjState(player->mo, S_KART_SPIN); P_PlayRinglossSound(player->mo); + P_PlayerRingBurst(player, 5); + K_PlayPainSound(player->mo); if (P_IsLocalPlayer(player)) { @@ -2250,7 +2385,7 @@ void K_StealBumper(player_t *player, player_t *victim, boolean force) if (player->kartstuff[k_squishedtimer] > 0 || player->kartstuff[k_spinouttimer] > 0) return; - if (victim->powers[pw_flashing] > 0 || victim->kartstuff[k_squishedtimer] > 0 || victim->kartstuff[k_spinouttimer] > 0 + if (victim->powers[pw_flashing] > 0 || victim->kartstuff[k_squishedtimer] > 0 || (victim->kartstuff[k_spinouttimer] > 0 && victim->kartstuff[k_spinouttype] != 2) || victim->kartstuff[k_invincibilitytimer] > 0 || victim->kartstuff[k_growshrinktimer] > 0 || victim->kartstuff[k_hyudorotimer] > 0) { K_DoInstashield(victim); @@ -4185,7 +4320,7 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) K_GetKartBoostPower(player); // Speed lines - if ((player->kartstuff[k_sneakertimer] || player->kartstuff[k_driftboost] || player->kartstuff[k_startboost]) && player->speed > 0) + if ((player->kartstuff[k_sneakertimer] || player->kartstuff[k_ringboost] || player->kartstuff[k_driftboost] || player->kartstuff[k_startboost]) && player->speed > 0) { mobj_t *fast = P_SpawnMobj(player->mo->x + (P_RandomRange(-36,36) * player->mo->scale), player->mo->y + (P_RandomRange(-36,36) * player->mo->scale), @@ -4243,6 +4378,10 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) player->mo->color = player->skincolor; } } + else if (player->kartstuff[k_ringboost] && (leveltime & 1)) // ring boosting + { + player->mo->colorized = true; + } else { player->mo->colorized = false; @@ -4280,8 +4419,13 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) player->kartstuff[k_timeovercam] = 0; + // Specific hack because it insists on setting flashing tics during this anyway... + if (player->kartstuff[k_spinouttype] == 2) + { + player->powers[pw_flashing] = 0; + } // Make ABSOLUTELY SURE that your flashing tics don't get set WHILE you're still in hit animations. - if (player->kartstuff[k_spinouttimer] != 0 + else if (player->kartstuff[k_spinouttimer] != 0 || player->kartstuff[k_wipeoutslow] != 0 || player->kartstuff[k_squishedtimer] != 0) { @@ -4294,19 +4438,21 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) if (player->kartstuff[k_spinouttimer]) { - if ((P_IsObjectOnGround(player->mo) || player->kartstuff[k_spinouttype] == 1) + if ((P_IsObjectOnGround(player->mo) + || (player->kartstuff[k_spinouttype] != 0)) && (player->kartstuff[k_sneakertimer] == 0)) { player->kartstuff[k_spinouttimer]--; if (player->kartstuff[k_wipeoutslow] > 1) player->kartstuff[k_wipeoutslow]--; - if (player->kartstuff[k_spinouttimer] == 0) - player->kartstuff[k_spinouttype] = 0; // Reset type + // Actually, this caused more problems than it solved. Just make sure you set type before you spinout. Which K_SpinPlayer always does. + /*if (player->kartstuff[k_spinouttimer] == 0) + player->kartstuff[k_spinouttype] = 0;*/ // Reset type } } else { - if (player->kartstuff[k_wipeoutslow] == 1) + if (player->kartstuff[k_wipeoutslow] >= 1) player->mo->friction = ORIG_FRICTION; player->kartstuff[k_wipeoutslow] = 0; if (!comeback) @@ -4322,6 +4468,17 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) /*if (player->kartstuff[k_thunderanim]) player->kartstuff[k_thunderanim]--;*/ + if (player->kartstuff[k_rings] > 20) + player->kartstuff[k_rings] = 20; + else if (player->kartstuff[k_rings] < -20) + player->kartstuff[k_rings] = -20; + + if (player->kartstuff[k_ringdelay]) + player->kartstuff[k_ringdelay]--; + + if (player->kartstuff[k_ringboost]) + player->kartstuff[k_ringboost]--; + if (player->kartstuff[k_sneakertimer]) { player->kartstuff[k_sneakertimer]--; @@ -4353,6 +4510,20 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) K_RemoveGrowShrink(player); } + if (player->kartstuff[k_superring]) + { + if (player->kartstuff[k_superring] % 3 == 0) + { + mobj_t *ring = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_RING); + ring->extravalue1 = 1; // Ring collect animation timer + ring->angle = player->mo->angle; // animation angle + P_SetTarget(&ring->target, player->mo); // toucher for thinker + if (player->kartstuff[k_superring] <= 3) + ring->cvmem = 1; // play caching when collected + } + player->kartstuff[k_superring]--; + } + if (player->kartstuff[k_stealingtimer] == 0 && player->kartstuff[k_stolentimer] == 0 && player->kartstuff[k_rocketsneakertimer]) player->kartstuff[k_rocketsneakertimer]--; @@ -5027,6 +5198,21 @@ void K_MoveKartPlayer(player_t *player, boolean onground) if (player->kartstuff[k_rocketsneakertimer] < 1) player->kartstuff[k_rocketsneakertimer] = 1; } + // Ring boosts with no item + 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; @@ -5035,6 +5221,13 @@ void K_MoveKartPlayer(player_t *player, boolean onground) { switch (player->kartstuff[k_itemtype]) { + case KITEM_SUPERRING: + if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO) + { + player->kartstuff[k_superring] += (10*3); + player->kartstuff[k_itemamount]--; + } + break; case KITEM_SNEAKER: if (ATTACK_IS_DOWN && !HOLDING_ITEM && onground && NO_HYUDORO) { @@ -5373,6 +5566,10 @@ void K_MoveKartPlayer(player_t *player, boolean onground) } } + // Prevent ring misfire + if (player->kartstuff[k_itemtype] != KITEM_NONE) + player->kartstuff[k_ringdelay] = 15; + // No more! if (!player->kartstuff[k_itemamount]) { @@ -5899,6 +6096,10 @@ static patch_t *kp_winnernum[NUMPOSFRAMES]; static patch_t *kp_facenum[MAXPLAYERS+1]; static patch_t *kp_facehighlight[8]; +static patch_t *kp_ringsticker[2]; +static patch_t *kp_ring[6]; +static patch_t *kp_ringdebtminus; + static patch_t *kp_rankbumper; static patch_t *kp_tinybumper[2]; static patch_t *kp_ranknobumpers; @@ -5917,6 +6118,7 @@ static patch_t *kp_itemtimer[2]; static patch_t *kp_itemmulsticker[2]; static patch_t *kp_itemx; +static patch_t *kp_superring[2]; static patch_t *kp_sneaker[2]; static patch_t *kp_rocketsneaker[2]; static patch_t *kp_invincibility[13]; @@ -6037,6 +6239,19 @@ void K_LoadKartHUDGraphics(void) kp_facehighlight[i] = (patch_t *) W_CachePatchName(buffer, PU_HUDGFX); } + // Rings & Lives + kp_ringsticker[0] = W_CachePatchName("RNGBACKA", PU_HUDGFX); + kp_ringsticker[1] = W_CachePatchName("RNGBACKB", PU_HUDGFX); + + sprintf(buffer, "K_RINGx"); + for (i = 0; i < 6; i++) + { + buffer[6] = '0'+(i+1); + kp_ring[i] = (patch_t *) W_CachePatchName(buffer, PU_HUDGFX); + } + + kp_ringdebtminus = W_CachePatchName("RDEBTMIN", PU_HUDGFX); + // Extra ranking icons kp_rankbumper = W_CachePatchName("K_BLNICO", PU_HUDGFX); kp_tinybumper[0] = W_CachePatchName("K_BLNA", PU_HUDGFX); @@ -6060,6 +6275,7 @@ void K_LoadKartHUDGraphics(void) kp_itemmulsticker[0] = W_CachePatchName("K_ITMUL", PU_HUDGFX); kp_itemx = W_CachePatchName("K_ITX", PU_HUDGFX); + kp_superring[0] = W_CachePatchName("K_ITRING", PU_HUDGFX); kp_sneaker[0] = W_CachePatchName("K_ITSHOE", PU_HUDGFX); kp_rocketsneaker[0] = W_CachePatchName("K_ITRSHE", PU_HUDGFX); @@ -6095,6 +6311,7 @@ void K_LoadKartHUDGraphics(void) kp_itemtimer[1] = W_CachePatchName("K_ISIMER", PU_HUDGFX); kp_itemmulsticker[1] = W_CachePatchName("K_ISMUL", PU_HUDGFX); + kp_superring[1] = W_CachePatchName("K_ISRING", PU_HUDGFX); kp_sneaker[1] = W_CachePatchName("K_ISSHOE", PU_HUDGFX); kp_rocketsneaker[1] = W_CachePatchName("K_ISRSHE", PU_HUDGFX); sprintf(buffer, "K_ISINVx"); @@ -6205,6 +6422,8 @@ 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"); @@ -6457,7 +6676,7 @@ static void K_drawKartItem(void) if (stplyr->skincolor) localcolor = stplyr->skincolor; - switch((stplyr->kartstuff[k_itemroulette] % (14*3)) / 3) + switch((stplyr->kartstuff[k_itemroulette] % (15*3)) / 3) { // Each case is handled in threes, to give three frames of in-game time to see the item on the roulette case 0: // Sneaker @@ -6516,11 +6735,15 @@ static void K_drawKartItem(void) localpatch = kp_thundershield[offset]; //localcolor = SKINCOLOR_CYAN; break; - /*case 14: // Pogo Spring + case 14: // Super Ring + localpatch = kp_superring[offset]; + //localcolor = SKINCOLOR_GOLD; + break; + /*case 15: // Pogo Spring localpatch = kp_pogospring[offset]; localcolor = SKINCOLOR_TANGERINE; break; - case 15: // Kitchen Sink + case 16: // Kitchen Sink localpatch = kp_kitchensink[offset]; localcolor = SKINCOLOR_STEEL; break;*/ @@ -6581,6 +6804,9 @@ 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; @@ -6736,7 +6962,6 @@ static void K_drawKartItem(void) // Quick Eggman numbers if (stplyr->kartstuff[k_eggmanexplode] > 1 /*&& stplyr->kartstuff[k_eggmanexplode] <= 3*TICRATE*/) V_DrawScaledPatch(fx+17, fy+13-offset, V_HUDTRANS|fflags, kp_eggnum[min(3, G_TicsToSeconds(stplyr->kartstuff[k_eggmanexplode]))]); - } void K_drawKartTimestamp(tic_t drawtime, INT32 TX, INT32 TY, INT16 emblemmap, UINT8 mode) @@ -7327,6 +7552,47 @@ static void K_drawKartLaps(void) } } +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; + + if (stplyr->kartstuff[k_rings] <= 0 && (leveltime/5 & 1)) + debtmap = R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_CRIMSON, 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-17, V_HUDTRANS|splitflags, kp_ring[0], debtmap); + + if (stplyr->kartstuff[k_rings] < 0) + { + 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); + } + 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); + } + + 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); + + 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)]); + } +} + static void K_drawKartSpeedometer(void) { fixed_t convSpeed; @@ -8287,6 +8553,7 @@ static void K_drawLapStartAnim(void) void K_drawKartFreePlay(UINT32 flashtime) { // no splitscreen support because it's not FREE PLAY if you have more than one player in-game + // (you fool, you can take splitscreen online. :V) if ((flashtime % TICRATE) < TICRATE/2) return; @@ -8299,6 +8566,7 @@ static void K_drawDistributionDebugger(void) { patch_t *items[NUMKARTRESULTS] = { kp_sadface[1], + kp_superring[1], kp_sneaker[1], kp_rocketsneaker[1], kp_invincibility[7], @@ -8497,6 +8765,8 @@ void K_drawKartHUD(void) #endif K_drawKartLaps(); + K_drawKartRingsAndLives(); + if (!splitscreen) { // Draw the speedometer diff --git a/src/k_kart.h b/src/k_kart.h index dc37956af..fe2a9a5b2 100644 --- a/src/k_kart.h +++ b/src/k_kart.h @@ -23,6 +23,7 @@ void K_RegisterKartStuff(void); boolean K_IsPlayerLosing(player_t *player); boolean K_IsPlayerWanted(player_t *player); void K_KartBouncing(mobj_t *mobj1, mobj_t *mobj2, boolean bounce, boolean solid); +void K_KartPainEnergyFling(player_t *player); void K_MatchGenericExtraFlags(mobj_t *mo, mobj_t *master); void K_RespawnChecker(player_t *player); void K_KartMoveAnimation(player_t *player); @@ -69,6 +70,7 @@ void K_CheckSpectateStatus(void); void K_PlayAttackTaunt(mobj_t *source); void K_PlayBoostTaunt(mobj_t *source); void K_PlayOvertakeSound(mobj_t *source); +void K_PlayPainSound(mobj_t *source); void K_PlayHitEmSound(mobj_t *source); void K_PlayPowerGloatSound(mobj_t *source); diff --git a/src/lua_baselib.c b/src/lua_baselib.c index 78f972f87..6af0e4aeb 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -1205,37 +1205,6 @@ static int lib_pPlayerRingBurst(lua_State *L) return 0; } -static int lib_pPlayerWeaponPanelBurst(lua_State *L) -{ - player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER)); - NOHUD - if (!player) - return LUA_ErrInvalid(L, "player_t"); - P_PlayerWeaponPanelBurst(player); - return 0; -} - -static int lib_pPlayerWeaponAmmoBurst(lua_State *L) -{ - player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER)); - NOHUD - if (!player) - return LUA_ErrInvalid(L, "player_t"); - P_PlayerWeaponAmmoBurst(player); - return 0; -} - -static int lib_pPlayerEmeraldBurst(lua_State *L) -{ - player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER)); - boolean toss = lua_optboolean(L, 2); - NOHUD - if (!player) - return LUA_ErrInvalid(L, "player_t"); - P_PlayerEmeraldBurst(player, toss); - return 0; -} - static int lib_pPlayerFlagBurst(lua_State *L) { player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER)); @@ -2163,6 +2132,16 @@ static int lib_kOvertakeSound(lua_State *L) return 0; } +static int lib_kPainSound(lua_State *L) +{ + mobj_t *mobj = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ)); + NOHUD + if (!mobj->player) + return luaL_error(L, "K_PlayPainSound: mobj_t isn't a player object."); //Nothing bad would happen if we let it run the func, but telling why it ain't doing anything is helpful. + K_PlayPainSound(mobj); + return 0; +} + static int lib_kHitEmSound(lua_State *L) { mobj_t *mobj = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ)); @@ -2682,9 +2661,6 @@ static luaL_Reg lib[] = { {"P_DamageMobj",lib_pDamageMobj}, {"P_KillMobj",lib_pKillMobj}, {"P_PlayerRingBurst",lib_pPlayerRingBurst}, - {"P_PlayerWeaponPanelBurst",lib_pPlayerWeaponPanelBurst}, - {"P_PlayerWeaponAmmoBurst",lib_pPlayerWeaponAmmoBurst}, - {"P_PlayerEmeraldBurst",lib_pPlayerEmeraldBurst}, {"P_PlayerFlagBurst",lib_pPlayerFlagBurst}, {"P_PlayRinglossSound",lib_pPlayRinglossSound}, {"P_PlayDeathSound",lib_pPlayDeathSound}, @@ -2769,6 +2745,7 @@ static luaL_Reg lib[] = { {"K_PlayPowerGloatSund", lib_kGloatSound}, {"K_PlayOvertakeSound", lib_kOvertakeSound}, {"K_PlayLossSound", lib_kLossSound}, + {"K_PlayPainSound", lib_kPainSound}, {"K_PlayHitEmSound", lib_kHitEmSound}, {"K_GetKartColorByName",lib_kGetKartColorByName}, {"K_IsPlayerLosing",lib_kIsPlayerLosing}, diff --git a/src/m_menu.c b/src/m_menu.c index 615b8c893..4e8d07a09 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -1513,7 +1513,7 @@ static menuitem_t OP_AdvServerOptionsMenu[] = {IT_STRING | IT_CVAR, NULL, "Karma Comeback", &cv_kartcomeback, 66}, };*/ -#define ITEMTOGGLEBOTTOMRIGHT +//#define ITEMTOGGLEBOTTOMRIGHT static menuitem_t OP_MonitorToggleMenu[] = { @@ -1541,6 +1541,7 @@ static menuitem_t OP_MonitorToggleMenu[] = {IT_KEYHANDLER | IT_NOTHING, NULL, "Thunder Shields", M_HandleMonitorToggles, KITEM_THUNDERSHIELD}, {IT_KEYHANDLER | IT_NOTHING, NULL, "Hyudoros", M_HandleMonitorToggles, KITEM_HYUDORO}, {IT_KEYHANDLER | IT_NOTHING, NULL, "Pogo Springs", M_HandleMonitorToggles, KITEM_POGOSPRING}, + {IT_KEYHANDLER | IT_NOTHING, NULL, "Super Rings", M_HandleMonitorToggles, KITEM_SUPERRING}, {IT_KEYHANDLER | IT_NOTHING, NULL, "Kitchen Sinks", M_HandleMonitorToggles, KITEM_KITCHENSINK}, #ifdef ITEMTOGGLEBOTTOMRIGHT {IT_KEYHANDLER | IT_NOTHING, NULL, "---", M_HandleMonitorToggles, 255}, @@ -9563,6 +9564,7 @@ static void M_HandleVideoMode(INT32 ch) // Monitor Toggles // =============== static consvar_t *kartitemcvs[NUMKARTRESULTS-1] = { + &cv_superring, &cv_sneaker, &cv_rocketsneaker, &cv_invincibility, diff --git a/src/p_enemy.c b/src/p_enemy.c index 9d3aa9519..843666db7 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -3615,57 +3615,137 @@ void A_AttractChase(mobj_t *actor) if (LUA_CallAction("A_AttractChase", actor)) return; #endif + if (actor->flags2 & MF2_NIGHTSPULL || !actor->health) return; - // 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; + if (actor->extravalue1) // SRB2Kart + { + if (!actor->target || P_MobjWasRemoved(actor->target) || !actor->target->player) + { + P_RemoveMobj(actor); + return; + } + + if (actor->extravalue2) // Using for ring boost + { + if (actor->extravalue1 >= 21) + { +#define RINGBOOSTPWR (((9 - actor->target->player->kartspeed) + (9 - actor->target->player->kartweight)) / 2) + // Base add is 3 tics for 9,9, adds 1.5 tics for each point closer to the 1,1 end + actor->target->player->kartstuff[k_ringboost] += ((3*RINGBOOSTPWR)/2) + 3; + S_StartSound(actor->target, sfx_s1b5); + actor->momx = (3*actor->target->momx)/4; + actor->momy = (3*actor->target->momy)/4; + actor->momz = (3*actor->target->momz)/4; + P_KillMobj(actor, actor->target, actor->target); + return; + } + else + { + fixed_t offz = FixedMul(80*actor->target->scale, FINESINE(FixedAngle((90 - (9 * abs(10 - actor->extravalue1))) << FRACBITS) >> ANGLETOFINESHIFT)); + //P_SetScale(actor, (actor->destscale = actor->target->scale)); + P_TeleportMove(actor, actor->target->x, actor->target->y, actor->target->z + actor->target->height + offz); + actor->extravalue1++; + } + } + else // Collecting + { + if (actor->extravalue1 >= 16) + { + P_GivePlayerRings(actor->target->player, 1); + if (actor->cvmem) // caching + S_StartSound(actor->target, sfx_s1c5); + else + S_StartSound(actor->target, sfx_s227); + P_RemoveMobj(actor); + return; + } + else + { + fixed_t dist = (actor->target->radius/4) * (16 - actor->extravalue1); + + P_SetScale(actor, (actor->destscale = actor->target->scale - ((actor->target->scale/14) * actor->extravalue1))); + P_TeleportMove(actor, + actor->target->x + FixedMul(dist, FINECOSINE(actor->angle >> ANGLETOFINESHIFT)), + actor->target->y + FixedMul(dist, FINESINE(actor->angle >> ANGLETOFINESHIFT)), + actor->target->z + (24 * actor->target->scale)); + + actor->angle += ANG30; + actor->extravalue1++; + } + } + } 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) { - 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; + // Don't immediately pick up spilled rings + 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 + if (actor->type == (mobjtype_t)actor->info->reactiontime) + { + const fixed_t destspeed = FRACUNIT; + fixed_t oldspeed = R_PointToDist2(0, 0, actor->momx, actor->momy); + + if (oldspeed > destspeed) + { + fixed_t newspeed = max(destspeed, oldspeed - (FRACUNIT / TICRATE)); + + actor->momx = FixedMul(FixedDiv(actor->momx, oldspeed), newspeed); + actor->momy = FixedMul(FixedDiv(actor->momy, oldspeed), newspeed); + } + } + + // 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) + { + 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; + } + + 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 + { + // Lost attracted rings don't through walls anymore. + actor->flags &= ~MF_NOCLIP; + P_SetTarget(&actor->tracer, NULL); + return; + } + + // 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); } - - 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 - { - // Lost attracted rings don't through walls anymore. - actor->flags &= ~MF_NOCLIP; - P_SetTarget(&actor->tracer, NULL); - return; - } - - // 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); } // Function: A_DropMine diff --git a/src/p_inter.c b/src/p_inter.c index dd27858fc..dbe0b349f 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -116,7 +116,7 @@ boolean P_CanPickupItem(player_t *player, UINT8 weapon) { // Invulnerable if (player->powers[pw_flashing] > 0 - || player->kartstuff[k_spinouttimer] > 0 + || (player->kartstuff[k_spinouttimer] > 0 && player->kartstuff[k_spinouttype] != 2) || player->kartstuff[k_squishedtimer] > 0 || player->kartstuff[k_invincibilitytimer] > 0 || player->kartstuff[k_growshrinktimer] > 0 @@ -678,15 +678,26 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) /* FALLTHRU */ case MT_RING: case MT_FLINGRING: + if (special->extravalue1) + return; + + // Don't immediately pick up spilled rings + if (special->threshold > 0) + return; + if (!(P_CanPickupItem(player, 0))) return; - special->momx = special->momy = special->momz = 0; - P_GivePlayerRings(player, 1); + // Reached the cap, don't waste 'em! + if (player->kartstuff[k_rings] >= 20) + return; - if ((maptol & TOL_NIGHTS) && special->type != MT_FLINGRING) - P_DoNightsScore(player); - break; + 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 + return; case MT_COIN: case MT_FLINGCOIN: @@ -2806,16 +2817,8 @@ static inline boolean P_TagDamage(mobj_t *target, mobj_t *inflictor, mobj_t *sou return true; } - if (target->health <= 1) // Death - { - P_PlayDeathSound(target); - P_PlayVictorySound(source); // Killer laughs at you! LAUGHS! BWAHAHAHHAHAA!! - } - else if (target->health > 1) // Ring loss - { - P_PlayRinglossSound(target); - P_PlayerRingBurst(player, player->mo->health - 1); - } + P_PlayRinglossSound(target); + P_PlayerRingBurst(player, 5); if (inflictor && ((inflictor->flags & MF_MISSILE) || inflictor->player) && player->powers[pw_super] && ALL7EMERALDS(player->powers[pw_emeralds])) { @@ -2871,14 +2874,9 @@ static inline boolean P_PlayerHitsPlayer(mobj_t *target, mobj_t *inflictor, mobj static void P_KillPlayer(player_t *player, mobj_t *source, INT32 damage) { - player->pflags &= ~(PF_CARRIED|PF_SLIDING|PF_ITEMHANG|PF_MACESPIN|PF_ROPEHANG|PF_NIGHTSMODE); + (void)source; - // Burst weapons and emeralds in Match/CTF only - if (source && (G_BattleGametype())) - { - P_PlayerRingBurst(player, player->health - 1); - P_PlayerEmeraldBurst(player, false); - } + player->pflags &= ~(PF_CARRIED|PF_SLIDING|PF_ITEMHANG|PF_MACESPIN|PF_ROPEHANG|PF_NIGHTSMODE); // Get rid of shield player->powers[pw_shield] = SH_NONE; @@ -2894,32 +2892,6 @@ static void P_KillPlayer(player_t *player, mobj_t *source, INT32 damage) P_SetPlayerMobjState(player->mo, player->mo->info->deathstate); - /*if (gametype == GT_CTF && (player->gotflag & (GF_REDFLAG|GF_BLUEFLAG))) - { - P_PlayerFlagBurst(player, false); - if (source && source->player) - { - // Award no points when players shoot each other when cv_friendlyfire is on. - if (!G_GametypeHasTeams() || !(source->player->ctfteam == player->ctfteam && source != player->mo)) - P_AddPlayerScore(source->player, 1); - } - } - if (source && source->player && !player->powers[pw_super]) //don't score points against super players - { - // Award no points when players shoot each other when cv_friendlyfire is on. - if (!G_GametypeHasTeams() || !(source->player->ctfteam == player->ctfteam && source != player->mo)) - P_AddPlayerScore(source->player, 1); - } - - // If the player was super, tell them he/she ain't so super nomore. - if (gametype != GT_COOP && player->powers[pw_super]) - { - S_StartSound(NULL, sfx_s3k66); //let all players hear it. - HU_SetCEchoFlags(0); - HU_SetCEchoDuration(5); - HU_DoCEcho(va("%s\\is no longer super.\\\\\\\\", player_names[player-players])); - }*/ - if (player->pflags & PF_TIMEOVER) { mobj_t *boom; @@ -2952,66 +2924,6 @@ static void P_KillPlayer(player_t *player, mobj_t *source, INT32 damage) } } -/* -static inline void P_SuperDamage(player_t *player, mobj_t *inflictor, mobj_t *source, INT32 damage) // SRB2kart - unused. -{ - fixed_t fallbackspeed; - angle_t ang; - - P_ForceFeed(player, 40, 10, TICRATE, 40 + min(damage, 100)*2); - - if (player->mo->eflags & MFE_VERTICALFLIP) - player->mo->z--; - else - player->mo->z++; - - if (player->mo->eflags & MFE_UNDERWATER) - P_SetObjectMomZ(player->mo, FixedDiv(10511*FRACUNIT,2600*FRACUNIT), false); - else - P_SetObjectMomZ(player->mo, FixedDiv(69*FRACUNIT,10*FRACUNIT), false); - - ang = R_PointToAngle2(inflictor->x, inflictor->y, player->mo->x, player->mo->y); - - // explosion and rail rings send you farther back, making it more difficult - // to recover - if (inflictor->flags2 & MF2_SCATTER && source) - { - fixed_t dist = P_AproxDistance(P_AproxDistance(source->x-player->mo->x, source->y-player->mo->y), source->z-player->mo->z); - - dist = FixedMul(128*FRACUNIT, inflictor->scale) - dist/4; - - if (dist < FixedMul(4*FRACUNIT, inflictor->scale)) - dist = FixedMul(4*FRACUNIT, inflictor->scale); - - fallbackspeed = dist; - } - else if (inflictor->flags2 & MF2_EXPLOSION) - { - if (inflictor->flags2 & MF2_RAILRING) - fallbackspeed = FixedMul(28*FRACUNIT, inflictor->scale); // 7x - else - fallbackspeed = FixedMul(20*FRACUNIT, inflictor->scale); // 5x - } - else if (inflictor->flags2 & MF2_RAILRING) - fallbackspeed = FixedMul(16*FRACUNIT, inflictor->scale); // 4x - else - fallbackspeed = FixedMul(4*FRACUNIT, inflictor->scale); // the usual amount of force - - P_InstaThrust(player->mo, ang, fallbackspeed); - - // SRB2kart - This shouldn't be reachable, but this frame is invalid. - //if (player->charflags & SF_SUPERANIMS) - // P_SetPlayerMobjState(player->mo, S_PLAY_SUPERHIT); - //else - P_SetPlayerMobjState(player->mo, player->mo->info->painstate); - - P_ResetPlayer(player); - - if (player->timeshit != UINT8_MAX) - ++player->timeshit; -} -*/ - void P_RemoveShield(player_t *player) { if (player->powers[pw_shield] & SH_FORCE) @@ -3040,75 +2952,6 @@ void P_RemoveShield(player_t *player) player->powers[pw_shield] = player->powers[pw_shield] & SH_STACK; } -/* -static void P_ShieldDamage(player_t *player, mobj_t *inflictor, mobj_t *source, INT32 damage) // SRB2kart - unused. -{ - // Must do pain first to set flashing -- P_RemoveShield can cause damage - P_DoPlayerPain(player, source, inflictor); - - P_RemoveShield(player); - - P_ForceFeed(player, 40, 10, TICRATE, 40 + min(damage, 100)*2); - - if (source && (source->type == MT_SPIKE || (source->type == MT_NULL && source->threshold == 43))) // spikes - S_StartSound(player->mo, sfx_spkdth); - else - S_StartSound (player->mo, sfx_shldls); // Ba-Dum! Shield loss. - - if (gametype == GT_CTF && (player->gotflag & (GF_REDFLAG|GF_BLUEFLAG))) - { - P_PlayerFlagBurst(player, false); - if (source && source->player) - { - // Award no points when players shoot each other when cv_friendlyfire is on. - if (!G_GametypeHasTeams() || !(source->player->ctfteam == player->ctfteam && source != player->mo)) - P_AddPlayerScore(source->player, 25); - } - } - if (source && source->player && !player->powers[pw_super]) //don't score points against super players - { - // Award no points when players shoot each other when cv_friendlyfire is on. - if (!G_GametypeHasTeams() || !(source->player->ctfteam == player->ctfteam && source != player->mo)) - P_AddPlayerScore(source->player, cv_match_scoring.value == 1 ? 25 : 50); - } -} -*/ - -static void P_RingDamage(player_t *player, mobj_t *inflictor, mobj_t *source, INT32 damage) -{ - //const UINT8 scoremultiply = ((K_IsWantedPlayer(player) && !trapitem) : 2 ? 1); - - if (!(inflictor && ((inflictor->flags & MF_MISSILE) || inflictor->player) && player->powers[pw_super] && ALL7EMERALDS(player->powers[pw_emeralds]))) - { - P_DoPlayerPain(player, source, inflictor); - - P_ForceFeed(player, 40, 10, TICRATE, 40 + min(damage, 100)*2); - - if (source && (source->type == MT_SPIKE || (source->type == MT_NULL && source->threshold == 43))) // spikes - S_StartSound(player->mo, sfx_spkdth); - } - - /*if (source && source->player && !player->powers[pw_super]) //don't score points against super players - { - // Award no points when players shoot each other when cv_friendlyfire is on. - if (!G_GametypeHasTeams() || !(source->player->ctfteam == player->ctfteam && source != player->mo)) - P_AddPlayerScore(source->player, scoremultiply); - } - - if (gametype == GT_CTF && (player->gotflag & (GF_REDFLAG|GF_BLUEFLAG))) - { - P_PlayerFlagBurst(player, false); - if (source && source->player) - { - // Award no points when players shoot each other when cv_friendlyfire is on. - if (!G_GametypeHasTeams() || !(source->player->ctfteam == player->ctfteam && source != player->mo)) - P_AddPlayerScore(source->player, scoremultiply); - } - }*/ - - // Ring loss sound plays despite hitting spikes - P_PlayRinglossSound(player->mo); // Ringledingle! -} /** Damages an object, which may or may not be a player. * For melee attacks, source and inflictor are the same. @@ -3326,10 +3169,10 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da || inflictor->type == MT_SMK_THWOMP || inflictor->player)) { player->kartstuff[k_sneakertimer] = 0; + K_SpinPlayer(player, source, 1, inflictor, false); - damage = player->mo->health - 1; - P_RingDamage(player, inflictor, source, damage); - P_PlayerRingBurst(player, 5); + K_KartPainEnergyFling(player); + if (P_IsLocalPlayer(player)) { quake.intensity = 32*FRACUNIT; @@ -3337,110 +3180,10 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da } } else - { K_SpinPlayer(player, source, 0, inflictor, false); - } + return true; } - /* // SRB2kart - don't need these - else if (metalrecording) - { - if (!inflictor) - inflictor = source; - if (inflictor && inflictor->flags & MF_ENEMY) - { // Metal Sonic destroy enemy !! - P_KillMobj(inflictor, NULL, target); - return false; - } - else if (inflictor && inflictor->flags & MF_MISSILE) - return false; // Metal Sonic walk through flame !! - else - { // Oh no! Metal Sonic is hit !! - P_ShieldDamage(player, inflictor, source, damage); - return true; - } - } - else if (player->powers[pw_invulnerability] || player->powers[pw_flashing] // ignore bouncing & such in invulnerability - || (player->powers[pw_super] && !(ALL7EMERALDS(player->powers[pw_emeralds]) && inflictor && ((inflictor->flags & MF_MISSILE) || inflictor->player)))) - { - if (force || (inflictor && (inflictor->flags & MF_MISSILE) - && (inflictor->flags2 & MF2_SUPERFIRE) - && player->powers[pw_super])) - { -#ifdef HAVE_BLUA - if (!LUAh_MobjDamage(target, inflictor, source, damage)) -#endif - P_SuperDamage(player, inflictor, source, damage); - return true; - } - else - return false; - } -#ifdef HAVE_BLUA - else if (LUAh_MobjDamage(target, inflictor, source, damage)) - return true; -#endif - else if (!player->powers[pw_super] && (player->powers[pw_shield] || player->bot)) //If One-Hit Shield - { - P_ShieldDamage(player, inflictor, source, damage); - damage = 0; - } - else if (player->mo->health > 1) // No shield but have rings. - { - damage = player->mo->health - 1; - P_RingDamage(player, inflictor, source, damage); - } - else // No shield, no rings, no invincibility. - { - // To reduce griefing potential, don't allow players to be killed - // by friendly fire. Spilling their rings and other items is enough. - if (force || !(G_GametypeHasTeams() - && source && source->player && (source->player->ctfteam == player->ctfteam) - && cv_friendlyfire.value)) - { - damage = 1; - P_KillPlayer(player, source, damage); - } - else - { - damage = 0; - P_ShieldDamage(player, inflictor, source, damage); - } - } - */ - - if (inflictor && ((inflictor->flags & MF_MISSILE) || inflictor->player) && player->powers[pw_super] && ALL7EMERALDS(player->powers[pw_emeralds])) - { - if (player->powers[pw_shield]) - { - P_RemoveShield(player); - return true; - } - else - { - player->health -= (10 * (1 << (INT32)(player->powers[pw_super] / 10500))); - if (player->health < 2) - player->health = 2; - } - - if (gametype == GT_CTF && (player->gotflag & (GF_REDFLAG|GF_BLUEFLAG))) - P_PlayerFlagBurst(player, false); - } - else - { - player->health -= damage; // mirror mobj health here - if (damage < 10000) - { - target->player->powers[pw_flashing] = K_GetKartFlashing(target->player); - if (damage > 0) // don't spill emeralds/ammo/panels for shield damage - P_PlayerRingBurst(player, damage); - } - } - - if (player->health < 0) - player->health = 0; - - P_ForceFeed(player, 40, 10, TICRATE, 40 + min(damage, 100)*2); } // Killing dead. Just for kicks. @@ -3515,7 +3258,7 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da /** Spills an injured player's rings. * * \param player The player who is losing rings. - * \param num_rings Number of rings lost. A maximum of 32 rings will be + * \param num_rings Number of rings lost. A maximum of 20 rings will be * spawned. * \sa P_PlayerFlagBurst */ @@ -3526,32 +3269,34 @@ void P_PlayerRingBurst(player_t *player, INT32 num_rings) angle_t fa; fixed_t ns; fixed_t z; + fixed_t momxy = 5<mo->health <= 1) - num_rings = 5; + // 20 is the ring cap in kart + if (num_rings > 20) + num_rings = 20; + else if (num_rings <= 0) + return; - if (num_rings > 32 && !(player->pflags & PF_NIGHTSFALL)) - num_rings = 32; + // Cap the maximum loss automatically to 2 in ring debt + if (player->kartstuff[k_rings] < 0 && num_rings > 2) + num_rings = 2; - if (player->powers[pw_emeralds]) - P_PlayerEmeraldBurst(player, false); + P_GivePlayerRings(player, -num_rings); - // Spill weapons first - if (player->ringweapons) - P_PlayerWeaponPanelBurst(player); + // determine first angle + fa = player->mo->angle + ((P_RandomByte() & 1) ? -ANGLE_90 : ANGLE_90); - // Spill the ammo - P_PlayerWeaponAmmoBurst(player); - - // There's no ring spilling in kart, so I'm hijacking this for the same thing as TD for (i = 0; i < num_rings; i++) { - INT32 objType = mobjinfo[MT_FLINGENERGY].reactiontime; + INT32 objType = mobjinfo[MT_RING].reactiontime; z = player->mo->z; if (player->mo->eflags & MFE_VERTICALFLIP) @@ -3559,379 +3304,34 @@ void P_PlayerRingBurst(player_t *player, INT32 num_rings) mo = P_SpawnMobj(player->mo->x, player->mo->y, z, objType); - mo->fuse = 8*TICRATE; + mo->threshold = 10; + mo->fuse = 15*TICRATE; P_SetTarget(&mo->target, player->mo); mo->destscale = player->mo->scale; P_SetScale(mo, player->mo->scale); - // Angle offset by player angle, then slightly offset by amount of rings - fa = ((i*FINEANGLES/16) + (player->mo->angle>>ANGLETOFINESHIFT) - ((num_rings-1)*FINEANGLES/32)) & FINEMASK; - - // Make rings spill out around the player in 16 directions like SA, but spill like Sonic 2. - // Technically a non-SA way of spilling rings. They just so happen to be a little similar. - if (player->pflags & PF_NIGHTSFALL) + // Angle / height offset changes every other ring + if (i != 0) { - ns = FixedMul(((i*FRACUNIT)/16)+2*FRACUNIT, mo->scale); - mo->momx = FixedMul(FINECOSINE(fa),ns); - - if (!(twodlevel || (player->mo->flags2 & MF2_TWOD))) - mo->momy = FixedMul(FINESINE(fa),ns); - - P_SetObjectMomZ(mo, 8*FRACUNIT, false); - mo->fuse = 20*TICRATE; // Adjust fuse for NiGHTS - } - else - { - fixed_t momxy, momz; // base horizonal/vertical thrusts - - if (i > 15) - { - momxy = 3*FRACUNIT; - momz = 4*FRACUNIT; - } - else - { - momxy = 28*FRACUNIT; - momz = 3*FRACUNIT; - } - - ns = FixedMul(momxy, mo->scale); - mo->momx = FixedMul(FINECOSINE(fa),ns); - - if (!(twodlevel || (player->mo->flags2 & MF2_TWOD))) - mo->momy = FixedMul(FINESINE(fa),ns); - - ns = momz; - P_SetObjectMomZ(mo, ns, false); - if (i & 1) - P_SetObjectMomZ(mo, ns, true); + { + momxy -= FRACUNIT; + momz += 2<scale); + mo->momx = FixedMul(FINECOSINE(fa>>ANGLETOFINESHIFT), ns); + mo->momy = FixedMul(FINESINE(fa>>ANGLETOFINESHIFT), ns); + + ns = FixedMul(momz, mo->scale); + P_SetObjectMomZ(mo, ns, false); + if (player->mo->eflags & MFE_VERTICALFLIP) mo->momz *= -1; } - - player->losstime += 10*TICRATE; - - if (P_IsObjectOnGround(player->mo)) - player->pflags &= ~PF_NIGHTSFALL; - - return; -} - -void P_PlayerWeaponPanelBurst(player_t *player) -{ - mobj_t *mo; - angle_t fa; - fixed_t ns; - INT32 i; - fixed_t z; - - INT32 num_weapons = M_CountBits((UINT32)player->ringweapons, NUM_WEAPONS-1); - UINT16 ammoamt = 0; - - for (i = 0; i < num_weapons; i++) - { - mobjtype_t weptype = 0; - powertype_t power = 0; - - if (player->ringweapons & RW_BOUNCE) // Bounce - { - weptype = MT_BOUNCEPICKUP; - player->ringweapons &= ~RW_BOUNCE; - power = pw_bouncering; - } - else if (player->ringweapons & RW_RAIL) // Rail - { - weptype = MT_RAILPICKUP; - player->ringweapons &= ~RW_RAIL; - power = pw_railring; - } - else if (player->ringweapons & RW_AUTO) // Auto - { - weptype = MT_AUTOPICKUP; - player->ringweapons &= ~RW_AUTO; - power = pw_automaticring; - } - else if (player->ringweapons & RW_EXPLODE) // Explode - { - weptype = MT_EXPLODEPICKUP; - player->ringweapons &= ~RW_EXPLODE; - power = pw_explosionring; - } - else if (player->ringweapons & RW_SCATTER) // Scatter - { - weptype = MT_SCATTERPICKUP; - player->ringweapons &= ~RW_SCATTER; - power = pw_scatterring; - } - else if (player->ringweapons & RW_GRENADE) // Grenade - { - weptype = MT_GRENADEPICKUP; - player->ringweapons &= ~RW_GRENADE; - power = pw_grenadering; - } - - if (!weptype) // ??? - continue; - - if (player->powers[power] >= mobjinfo[weptype].reactiontime) - ammoamt = (UINT16)mobjinfo[weptype].reactiontime; - else - ammoamt = player->powers[power]; - - player->powers[power] -= ammoamt; - - z = player->mo->z; - if (player->mo->eflags & MFE_VERTICALFLIP) - z += player->mo->height - mobjinfo[weptype].height; - - mo = P_SpawnMobj(player->mo->x, player->mo->y, z, weptype); - mo->reactiontime = ammoamt; - mo->flags2 |= MF2_DONTRESPAWN; - mo->flags &= ~(MF_NOGRAVITY|MF_NOCLIPHEIGHT); - P_SetTarget(&mo->target, player->mo); - mo->fuse = 12*TICRATE; - mo->destscale = player->mo->scale; - P_SetScale(mo, player->mo->scale); - - // Angle offset by player angle - fa = ((i*FINEANGLES/16) + (player->mo->angle>>ANGLETOFINESHIFT)) & FINEMASK; - - // Make rings spill out around the player in 16 directions like SA, but spill like Sonic 2. - // Technically a non-SA way of spilling rings. They just so happen to be a little similar. - - // >16 ring type spillout - ns = FixedMul(3*FRACUNIT, mo->scale); - mo->momx = FixedMul(FINECOSINE(fa),ns); - - if (!(twodlevel || (player->mo->flags2 & MF2_TWOD))) - mo->momy = FixedMul(FINESINE(fa),ns); - - P_SetObjectMomZ(mo, 4*FRACUNIT, false); - - if (i & 1) - P_SetObjectMomZ(mo, 4*FRACUNIT, true); - } -} - -void P_PlayerWeaponAmmoBurst(player_t *player) -{ - mobj_t *mo; - angle_t fa; - fixed_t ns; - INT32 i = 0; - fixed_t z; - - mobjtype_t weptype = 0; - powertype_t power = 0; - - while (true) - { - if (player->powers[pw_bouncering]) - { - weptype = MT_BOUNCERING; - power = pw_bouncering; - } - else if (player->powers[pw_railring]) - { - weptype = MT_RAILRING; - power = pw_railring; - } - else if (player->powers[pw_infinityring]) - { - weptype = MT_INFINITYRING; - power = pw_infinityring; - } - else if (player->powers[pw_automaticring]) - { - weptype = MT_AUTOMATICRING; - power = pw_automaticring; - } - else if (player->powers[pw_explosionring]) - { - weptype = MT_EXPLOSIONRING; - power = pw_explosionring; - } - else if (player->powers[pw_scatterring]) - { - weptype = MT_SCATTERRING; - power = pw_scatterring; - } - else if (player->powers[pw_grenadering]) - { - weptype = MT_GRENADERING; - power = pw_grenadering; - } - else - break; // All done! - - z = player->mo->z; - if (player->mo->eflags & MFE_VERTICALFLIP) - z += player->mo->height - mobjinfo[weptype].height; - - mo = P_SpawnMobj(player->mo->x, player->mo->y, z, weptype); - mo->health = player->powers[power]; - mo->flags2 |= MF2_DONTRESPAWN; - mo->flags &= ~(MF_NOGRAVITY|MF_NOCLIPHEIGHT); - P_SetTarget(&mo->target, player->mo); - - player->powers[power] = 0; - mo->fuse = 12*TICRATE; - - mo->destscale = player->mo->scale; - P_SetScale(mo, player->mo->scale); - - // Angle offset by player angle - fa = ((i*FINEANGLES/16) + (player->mo->angle>>ANGLETOFINESHIFT)) & FINEMASK; - - // Spill them! - ns = FixedMul(2*FRACUNIT, mo->scale); - mo->momx = FixedMul(FINECOSINE(fa), ns); - - if (!(twodlevel || (player->mo->flags2 & MF2_TWOD))) - mo->momy = FixedMul(FINESINE(fa),ns); - - P_SetObjectMomZ(mo, 3*FRACUNIT, false); - - if (i & 1) - P_SetObjectMomZ(mo, 3*FRACUNIT, true); - - i++; - } -} - -// -// P_PlayerEmeraldBurst -// -// Spills ONLY emeralds. -// -void P_PlayerEmeraldBurst(player_t *player, boolean toss) -{ - INT32 i; - angle_t fa; - fixed_t ns; - fixed_t z = 0, momx = 0, momy = 0; - - // Better safe than sorry. - if (!player) - return; - - // Spill power stones - if (player->powers[pw_emeralds]) - { - INT32 num_stones = 0; - - if (player->powers[pw_emeralds] & EMERALD1) - num_stones++; - if (player->powers[pw_emeralds] & EMERALD2) - num_stones++; - if (player->powers[pw_emeralds] & EMERALD3) - num_stones++; - if (player->powers[pw_emeralds] & EMERALD4) - num_stones++; - if (player->powers[pw_emeralds] & EMERALD5) - num_stones++; - if (player->powers[pw_emeralds] & EMERALD6) - num_stones++; - if (player->powers[pw_emeralds] & EMERALD7) - num_stones++; - - for (i = 0; i < num_stones; i++) - { - INT32 stoneflag = 0; - statenum_t statenum = S_CEMG1; - mobj_t *mo; - - if (player->powers[pw_emeralds] & EMERALD1) - { - stoneflag = EMERALD1; - statenum = S_CEMG1; - } - else if (player->powers[pw_emeralds] & EMERALD2) - { - stoneflag = EMERALD2; - statenum = S_CEMG2; - } - else if (player->powers[pw_emeralds] & EMERALD3) - { - stoneflag = EMERALD3; - statenum = S_CEMG3; - } - else if (player->powers[pw_emeralds] & EMERALD4) - { - stoneflag = EMERALD4; - statenum = S_CEMG4; - } - else if (player->powers[pw_emeralds] & EMERALD5) - { - stoneflag = EMERALD5; - statenum = S_CEMG5; - } - else if (player->powers[pw_emeralds] & EMERALD6) - { - stoneflag = EMERALD6; - statenum = S_CEMG6; - } - else if (player->powers[pw_emeralds] & EMERALD7) - { - stoneflag = EMERALD7; - statenum = S_CEMG7; - } - - if (!stoneflag) // ??? - continue; - - player->powers[pw_emeralds] &= ~stoneflag; - - if (toss) - { - fa = player->mo->angle>>ANGLETOFINESHIFT; - - z = player->mo->z + player->mo->height; - if (player->mo->eflags & MFE_VERTICALFLIP) - z -= mobjinfo[MT_FLINGEMERALD].height + player->mo->height; - ns = FixedMul(8*FRACUNIT, player->mo->scale); - } - else - { - fa = ((255 / num_stones) * i) * FINEANGLES/256; - - z = player->mo->z + (player->mo->height / 2); - if (player->mo->eflags & MFE_VERTICALFLIP) - z -= mobjinfo[MT_FLINGEMERALD].height; - ns = FixedMul(4*FRACUNIT, player->mo->scale); - } - - momx = FixedMul(FINECOSINE(fa), ns); - - if (!(twodlevel || (player->mo->flags2 & MF2_TWOD))) - momy = FixedMul(FINESINE(fa),ns); - else - momy = 0; - - mo = P_SpawnMobj(player->mo->x, player->mo->y, z, MT_FLINGEMERALD); - mo->health = 1; - mo->threshold = stoneflag; - mo->flags2 |= (MF2_DONTRESPAWN|MF2_SLIDEPUSH); - mo->flags &= ~(MF_NOGRAVITY|MF_NOCLIPHEIGHT); - P_SetTarget(&mo->target, player->mo); - mo->fuse = 12*TICRATE; - P_SetMobjState(mo, statenum); - - mo->momx = momx; - mo->momy = momy; - - P_SetObjectMomZ(mo, 3*FRACUNIT, false); - - if (player->mo->eflags & MFE_VERTICALFLIP) - mo->momz = -mo->momz; - - if (toss) - player->tossdelay = 2*TICRATE; - } - } } /** Makes an injured or dead player lose possession of the flag. diff --git a/src/p_local.h b/src/p_local.h index cf1387fee..4030b2579 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -393,9 +393,6 @@ void P_RemoveShield(player_t *player); boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 damage); void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source); void P_PlayerRingBurst(player_t *player, INT32 num_rings); /// \todo better fit in p_user.c -void P_PlayerWeaponPanelBurst(player_t *player); -void P_PlayerWeaponAmmoBurst(player_t *player); -void P_PlayerEmeraldBurst(player_t *player, boolean toss); void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck); void P_PlayerFlagBurst(player_t *player, boolean toss); diff --git a/src/p_mobj.c b/src/p_mobj.c index 746fc1afd..141f2d61e 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -2021,7 +2021,7 @@ void P_XYMovement(mobj_t *mo) #endif //{ SRB2kart stuff - if (mo->type == MT_ORBINAUT || mo->type == MT_JAWZ_DUD || mo->type == MT_JAWZ || mo->type == MT_BALLHOG) //(mo->type == MT_JAWZ && !mo->tracer)) + if (mo->type == MT_ORBINAUT || mo->type == MT_JAWZ_DUD || mo->type == MT_JAWZ || mo->type == MT_BALLHOG || mo->type == MT_FLINGRING) //(mo->type == MT_JAWZ && !mo->tracer)) return; if (mo->player && (mo->player->kartstuff[k_spinouttimer] && !mo->player->kartstuff[k_wipeoutslow]) && mo->player->speed <= mo->player->normalspeed/2) @@ -2572,11 +2572,11 @@ static boolean P_ZMovement(mobj_t *mo) mom.z = -mom.z; else // Flingrings bounce - if (mo->type == MT_FLINGRING + if (/*mo->type == MT_FLINGRING || mo->type == MT_FLINGCOIN || P_WeaponOrPanel(mo->type) || mo->type == MT_FLINGEMERALD - || mo->type == MT_BIGTUMBLEWEED + ||*/ mo->type == MT_BIGTUMBLEWEED || mo->type == MT_LITTLETUMBLEWEED || mo->type == MT_CANNONBALLDECOR || mo->type == MT_FALLINGROCK) @@ -10371,8 +10371,8 @@ void P_RemoveMobj(mobj_t *mobj) // Rings only, please! if (mobj->spawnpoint && - (mobj->type == MT_RING - || mobj->type == MT_COIN + (/*mobj->type == MT_RING + ||*/ mobj->type == MT_COIN || mobj->type == MT_BLUEBALL || mobj->type == MT_REDTEAMRING || mobj->type == MT_BLUETEAMRING @@ -12073,7 +12073,7 @@ ML_NOCLIMB : Direction not controllable void P_SpawnHoopsAndRings(mapthing_t *mthing) { mobj_t *mobj = NULL; - INT32 /*r,*/ i; + INT32 r, i; fixed_t x, y, z, finalx, finaly, finalz; sector_t *sec; TVector v, *res; @@ -12360,8 +12360,6 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing) return; } - else return; // srb2kart - no rings or ring-like objects in R1 - /* // Wing logo item. else if (mthing->type == mobjinfo[MT_NIGHTSWING].doomednum) { @@ -12655,7 +12653,8 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing) } } return; - }*/ + } + else return; } // diff --git a/src/p_user.c b/src/p_user.c index 76f57a9ba..11867a8b0 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -946,50 +946,19 @@ void P_ResetPlayer(player_t *player) // void P_GivePlayerRings(player_t *player, INT32 num_rings) { - if (player->bot) - player = &players[consoleplayer]; - if (!player->mo) return; - player->mo->health += num_rings; - player->health += num_rings; + if (G_BattleGametype()) // No rings in Battle Mode + return; - if (!G_IsSpecialStage(gamemap) || !useNightsSS) - player->totalring += num_rings; + player->kartstuff[k_rings] += num_rings; + //player->totalring += num_rings; // Used for GP lives later - //{ SRB2kart - rings don't really do anything, but we don't want the player spilling them later. - /* - // Can only get up to 9999 rings, sorry! - if (player->mo->health > 10000) - { - player->mo->health = 10000; - player->health = 10000; - } - else if (player->mo->health < 1)*/ - { - player->mo->health = 1; - player->health = 1; - } - //} - - // Now extra life bonuses are handled here instead of in P_MovePlayer, since why not? - if (!ultimatemode && !modeattacking && !G_IsSpecialStage(gamemap) && G_GametypeUsesLives()) - { - INT32 gainlives = 0; - - while (player->xtralife < maxXtraLife && player->health > 100 * (player->xtralife+1)) - { - ++gainlives; - ++player->xtralife; - } - - if (gainlives) - { - P_GivePlayerLives(player, gainlives); - P_PlayLivesJingle(player); - } - } + if (player->kartstuff[k_rings] > 20) + player->kartstuff[k_rings] = 20; // Caps at 20 rings, sorry! + else if (player->kartstuff[k_rings] < -20) + player->kartstuff[k_rings] = -20; // Chaotix ring debt! } // @@ -1114,11 +1083,10 @@ void P_PlayLivesJingle(player_t *player) void P_PlayRinglossSound(mobj_t *source) { - sfxenum_t key = P_RandomKey(2); - if (cv_kartvoices.value) - S_StartSound(source, (mariomode) ? sfx_mario8 : sfx_khurt1 + key); + if (source->player && source->player->kartstuff[k_rings] <= 0) + S_StartSound(source, sfx_s1a6); else - S_StartSound(source, sfx_slip); + S_StartSound(source, sfx_s1c6); } void P_PlayDeathSound(mobj_t *source) @@ -9294,7 +9262,8 @@ void P_PlayerThink(player_t *player) #if 1 // "Blur" a bit when you have speed shoes and are going fast enough if ((player->powers[pw_super] || player->powers[pw_sneakers] - || player->kartstuff[k_driftboost] || player->kartstuff[k_sneakertimer] || player->kartstuff[k_startboost]) && !player->kartstuff[k_invincibilitytimer] // SRB2kart + || player->kartstuff[k_driftboost] || player->kartstuff[k_ringboost] || player->kartstuff[k_sneakertimer] || player->kartstuff[k_startboost]) + && !player->kartstuff[k_invincibilitytimer] // SRB2kart && (player->speed + abs(player->mo->momz)) > FixedMul(20*FRACUNIT,player->mo->scale)) { mobj_t *gmobj = P_SpawnGhostMobj(player->mo);