diff --git a/src/deh_tables.c b/src/deh_tables.c index b36fa412c..7a730b6ce 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -367,6 +367,7 @@ const char *const STATE_LIST[] = { // array length left dynamic for sanity testi "S_KART_SPINOUT", "S_KART_DEAD", "S_KART_SIGN", + "S_KART_SIGL", // technically the player goes here but it's an infinite tic state "S_OBJPLACE_DUMMY", diff --git a/src/info.c b/src/info.c index b1f696e79..0a311d369 100644 --- a/src/info.c +++ b/src/info.c @@ -916,7 +916,7 @@ char spr2names[NUMPLAYERSPRITES][5] = "SPIN", // Spinout "DEAD", // Dead - "SIGN", // Finish signpost + "SIGN", "SIGL", // Finish signpost "XTRA", // Three Faces of Darkness "TALK", // Dialogue }; @@ -959,6 +959,7 @@ playersprite_t spr2defaults[NUMPLAYERSPRITES] = { 0, // SPR2_DEAD 0, // SPR2_SIGN + SPR2_SIGN, // SPR2_SIGL 0, // SPR2_XTRA 0, // SPR2_TALK }; @@ -1018,7 +1019,8 @@ state_t states[NUMSTATES] = {SPR_PLAY, SPR2_DRRI, 1, {NULL}, 0, 0, S_KART_DRIFT_R_IN}, // S_KART_DRIFT_R_IN {SPR_PLAY, SPR2_SPIN|FF_ANIMATE, 350, {NULL}, 0, 1, S_KART_STILL}, // S_KART_SPINOUT {SPR_PLAY, SPR2_DEAD, 3, {NULL}, 0, 0, S_KART_DEAD}, // S_KART_DEAD - {SPR_PLAY, SPR2_SIGN|FF_PAPERSPRITE, 1, {NULL}, 0, 0, S_KART_SIGN}, // S_KART_SIGN + {SPR_PLAY, SPR2_SIGN|FF_ANIMATE|FF_PAPERSPRITE, -1, {NULL}, 0, 1, 0}, // S_KART_SIGN + {SPR_PLAY, SPR2_SIGL|FF_ANIMATE|FF_PAPERSPRITE, -1, {NULL}, 0, 1, 0}, // S_KART_SIGL {SPR_NULL, 0, -1, {NULL}, 0, 0, S_OBJPLACE_DUMMY}, // S_OBJPLACE_DUMMY diff --git a/src/info.h b/src/info.h index dc5257a08..1a4054638 100644 --- a/src/info.h +++ b/src/info.h @@ -1469,7 +1469,7 @@ typedef enum playersprite SPR2_DRRN, SPR2_DRRO, SPR2_DRRI, SPR2_SPIN, SPR2_DEAD, - SPR2_SIGN, + SPR2_SIGN, SPR2_SIGL, SPR2_XTRA, SPR2_TALK, @@ -1525,6 +1525,7 @@ typedef enum state S_KART_SPINOUT, S_KART_DEAD, S_KART_SIGN, + S_KART_SIGL, // technically the player goes here but it's an infinite tic state S_OBJPLACE_DUMMY, diff --git a/src/k_race.c b/src/k_race.c index a6d8f2674..0a1b64a02 100644 --- a/src/k_race.c +++ b/src/k_race.c @@ -423,7 +423,7 @@ void K_RunFinishLineBeam(void) } /*-------------------------------------------------- - UINT8 K_RaceLapCount(void); + UINT8 K_RaceLapCount(INT16 mapNum); See header file for description. --------------------------------------------------*/ diff --git a/src/k_tally.cpp b/src/k_tally.cpp index 076047afa..3e5c16f27 100644 --- a/src/k_tally.cpp +++ b/src/k_tally.cpp @@ -17,7 +17,6 @@ #include "k_kart.h" #include "k_rank.h" #include "k_grandprix.h" -#include "k_race.h" #include "k_battle.h" #include "k_boss.h" #include "k_specialstage.h" @@ -44,7 +43,7 @@ boolean level_tally_t::UseBonuses(void) } // No bonuses / ranking in FREE PLAY or Time Attack - return (K_TimeAttackRules() == false || grandprixinfo.gp == true); + return (grandprixinfo.gp == true || K_TimeAttackRules() == false); } void level_tally_t::DetermineBonuses(void) @@ -330,7 +329,7 @@ void level_tally_t::Init(player_t *player) if ((gametypes[gt]->rules & GTR_CIRCUIT) == GTR_CIRCUIT) { laps = player->lapPoints; - totalLaps = K_RaceLapCount(gamemap-1); + totalLaps = numlaps; if (inDuel == false) { diff --git a/src/p_mobj.c b/src/p_mobj.c index f818695cf..599dd37e8 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -8631,9 +8631,8 @@ static boolean P_MobjRegularThink(mobj_t *mobj) case MT_SIGN: // Kart's unique sign behavior if (mobj->movecount != 0) { - mobj_t *cur = mobj->hnext; - SINT8 newskin = -1; - UINT8 newcolor = SKINCOLOR_NONE; + player_t *newplayer = NULL; + angle_t endangle = FixedAngle(mobj->extravalue1 << FRACBITS); if (mobj->movecount == 1) @@ -8647,8 +8646,11 @@ static boolean P_MobjRegularThink(mobj_t *mobj) mobj->momz = 0; mobj->movecount = 2; - newskin = ((skin_t*)mobj->target->skin) - skins; - newcolor = mobj->target->player->skincolor; + if (!P_MobjWasRemoved(mobj->target)) + { + // Guarantee correct display of the player + newplayer = mobj->target->player; + } } else { @@ -8675,8 +8677,11 @@ static boolean P_MobjRegularThink(mobj_t *mobj) { if (ticstilimpact <= 8) { - newskin = ((skin_t*)mobj->target->skin) - skins; - newcolor = mobj->target->player->skincolor; + if (!P_MobjWasRemoved(mobj->target)) + { + // In anticipation of final declaration... + newplayer = mobj->target->player; + } } else { @@ -8688,25 +8693,33 @@ static boolean P_MobjRegularThink(mobj_t *mobj) for (i = 0; i < MAXPLAYERS; i++) { - if (playeringame[i] && !players[i].spectator) - { - plist[plistlen] = i; - plistlen++; - } + if (!playeringame[i]) + continue; + if (players[i].spectator == true) + continue; + + plist[plistlen++] = i; } - if (plistlen <= 1) + if (plistlen) + { + if (plistlen > 1) + { + // Pick another player in the server! + plistlen = P_RandomKey(PR_SPARKLE, plistlen+1); + } + else + { + // One entry, grab the head. + plistlen = 0; + } + + newplayer = &players[plist[plistlen]]; + } + else if (!P_MobjWasRemoved(mobj->target)) { // Default to the winner - newskin = ((skin_t*)mobj->target->skin) - skins; - newcolor = mobj->target->player->skincolor; - } - else - { - // Pick another player in the server! - player_t *p = &players[plist[P_RandomKey(PR_SPARKLE, plistlen)]]; - newskin = ((skin_t*)p->mo->skin) - skins; - newcolor = p->skincolor; + newplayer = mobj->target->player; } } } @@ -8718,6 +8731,47 @@ static boolean P_MobjRegularThink(mobj_t *mobj) mobj->angle += ANGLE_11hh; } + boolean newperfect = false; + if ( + (newplayer != NULL) + && (gamespeed != KARTSPEED_EASY) + && (newplayer->tally.active == true) + && (newplayer->tally.totalLaps > 0) // Only true if not Time Attack + && (newplayer->tally.laps >= newplayer->tally.totalLaps) + ) + { + UINT8 pnum = (newplayer-players); + UINT32 skinflags = (demo.playback) + ? demo.skinlist[demo.currentskinid[pnum]].flags + : skins[newplayer->skin].flags; + + if (skinflags & SF_IRONMAN) + { + UINT8 i, maxdifficulty = 0; + for (i = 0; i < MAXPLAYERS; i++) + { + if (!playeringame[i]) + continue; + if (players[i].spectator == true) + continue; + if (i == pnum) + continue; + + // Any other player being a human permits Magician L-taunting. + if (players[i].bot == false) + break; + + // Otherwise, guarantee this player faced a challenge first. + if (maxdifficulty >= players[i].botvars.difficulty) + continue; + maxdifficulty = players[i].botvars.difficulty; + } + + newperfect = (i < MAXPLAYERS || maxdifficulty >= (MAXBOTDIFFICULTY/2)); + } + } + + mobj_t *cur = mobj->hnext; while (cur && !P_MobjWasRemoved(cur)) { fixed_t amt = cur->extravalue1 * mobj->scale; @@ -8726,21 +8780,25 @@ static boolean P_MobjRegularThink(mobj_t *mobj) if (cur->state == &states[S_SIGN_FACE]) { - if (newcolor != SKINCOLOR_NONE) + if (newplayer != NULL) { - cur->color = skincolors[newcolor].invcolor; - cur->frame = cur->state->frame + skincolors[newcolor].invshade; + cur->color = skincolors[newplayer->skincolor].invcolor; + cur->frame = cur->state->frame + skincolors[newplayer->skincolor].invshade; } } - else if (cur->state == &states[S_KART_SIGN]) + else if (cur->state == &states[S_KART_SIGN] + || cur->state == &states[S_KART_SIGL]) { z += (5*mobj->scale); amt += 1; - if (newskin != -1) + if (newplayer != NULL) { - cur->skin = &skins[newskin]; - cur->color = newcolor; + cur->skin = &skins[newplayer->skin]; + cur->color = newplayer->skincolor; + // Even if we didn't have the Perfect Sign to consider, + // it's still necessary to refresh SPR2 on skin changes. + P_SetMobjState(cur, (newperfect == true) ? S_KART_SIGL : S_KART_SIGN); } } else if (cur->state == &states[S_SIGN_ERROR]) diff --git a/src/p_spec.c b/src/p_spec.c index 79cb28377..a9dc3760f 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -4488,6 +4488,7 @@ static void P_SetupSignObject(mobj_t *sign, mobj_t *pmo, boolean error) sign->movefactor = sign->z; sign->z += (576*sign->scale) * P_MobjFlip(sign); + sign->old_z = sign->z; // interp hijack sign->movecount = 1; sign->extravalue1 = AngleFixed(sign->angle) >> FRACBITS;