diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 53eeb5248..d08fe0faa 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -301,13 +301,25 @@ target_compile_definitions(SRB2SDL2 PRIVATE -DCMAKECONFIG) # ${SRB2_BLUA_HEADERS} #) +## strip debug symbols into separate file when using gcc. +## to be consistent with Makefile, don't generate for OS X. +if((CMAKE_COMPILER_IS_GNUCC) AND NOT (${CMAKE_SYSTEM} MATCHES Darwin)) + if((${CMAKE_BUILD_TYPE} MATCHES Debug) OR (${CMAKE_BUILD_TYPE} MATCHES RelWithDebInfo)) + if(${CMAKE_BUILD_TYPE} MATCHES Debug) + set(OBJCOPY_ONLY_KEEP_DEBUG "--only-keep-debug") + endif() + message(STATUS "Will make separate debug symbols in *.debug") + add_custom_command(TARGET SRB2SDL2 POST_BUILD + COMMAND ${OBJCOPY} ${OBJCOPY_ONLY_KEEP_DEBUG} $ $.debug + COMMAND ${OBJCOPY} --strip-debug $ + COMMAND ${OBJCOPY} --add-gnu-debuglink=$.debug $ + ) + endif() +endif() + add_subdirectory(sdl) add_subdirectory(objects) -if(${CMAKE_SYSTEM} MATCHES Windows) - add_subdirectory(win32) -endif() - if(NOT ${SRB2_SDL2_AVAILABLE}) message(FATAL_ERROR "There are no targets available to build an SRB2Kart executable. :(") endif() diff --git a/src/command.c b/src/command.c index a0f2967bf..6bbf58c44 100644 --- a/src/command.c +++ b/src/command.c @@ -1641,34 +1641,14 @@ void CV_SaveVars(UINT8 **p, boolean in_demo) // the client will reset all netvars to default before loading WRITEUINT16(*p, 0x0000); for (cvar = consvar_vars; cvar; cvar = cvar->next) - if (((cvar->flags & CV_NETVAR) && !CV_IsSetToDefault(cvar)) || (in_demo && cvar->netid == cv_numlaps.netid)) + if ((cvar->flags & CV_NETVAR) && !CV_IsSetToDefault(cvar)) { if (in_demo) WRITESTRING(*p, cvar->name); else WRITEUINT16(*p, cvar->netid); - // UGLY HACK: Save proper lap count in net replays - if (in_demo && cvar->netid == cv_numlaps.netid) - { - if (cv_basenumlaps.value && - (!(mapheaderinfo[gamemap - 1]->levelflags & LF_SECTIONRACE) - || (mapheaderinfo[gamemap - 1]->numlaps > cv_basenumlaps.value)) - ) - { - WRITESTRING(*p, cv_basenumlaps.string); - } - else - { - char buf[9]; - sprintf(buf, "%d", mapheaderinfo[gamemap - 1]->numlaps); - WRITESTRING(*p, buf); - } - } - else - { - WRITESTRING(*p, cvar->string); - } + WRITESTRING(*p, cvar->string); WRITEUINT8(*p, false); ++count; diff --git a/src/d_main.c b/src/d_main.c index 9c5b6e254..ba79857e1 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -888,7 +888,11 @@ void D_SRB2Loop(void) if (!singletics) { INT64 elapsed = (INT64)(finishprecise - enterprecise); - if (elapsed > 0 && (INT64)capbudget > elapsed) + + // in the case of "match refresh rate" + vsync, don't sleep at all + const boolean vsync_with_match_refresh = cv_vidwait.value && cv_fpscap.value == 0; + + if (elapsed > 0 && (INT64)capbudget > elapsed && !vsync_with_match_refresh) { I_SleepDuration(capbudget - (finishprecise - enterprecise)); } diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 99fcbded3..7e8143427 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -102,7 +102,6 @@ static void Got_DiscordInfo(UINT8 **cp, INT32 playernum); static void PointLimit_OnChange(void); static void TimeLimit_OnChange(void); static void NumLaps_OnChange(void); -static void BaseNumLaps_OnChange(void); static void Mute_OnChange(void); static void AutoBalance_OnChange(void); @@ -141,7 +140,6 @@ static void Color4_OnChange(void); static void DummyConsvar_OnChange(void); static void SoundTest_OnChange(void); -static void BaseNumLaps_OnChange(void); static void KartFrantic_OnChange(void); static void KartSpeed_OnChange(void); static void KartEncore_OnChange(void); @@ -467,10 +465,9 @@ static CV_PossibleValue_t pointlimit_cons_t[] = {{1, "MIN"}, {MAXSCORE, "MAX"}, consvar_t cv_pointlimit = CVAR_INIT ("pointlimit", "None", CV_SAVE|CV_NETVAR|CV_CALL|CV_NOINIT, pointlimit_cons_t, PointLimit_OnChange); static CV_PossibleValue_t timelimit_cons_t[] = {{1, "MIN"}, {30, "MAX"}, {0, "None"}, {0, NULL}}; consvar_t cv_timelimit = CVAR_INIT ("timelimit", "None", CV_SAVE|CV_NETVAR|CV_CALL|CV_NOINIT, timelimit_cons_t, TimeLimit_OnChange); -static CV_PossibleValue_t numlaps_cons_t[] = {{1, "MIN"}, {99, "MAX"}, {0, NULL}}; -consvar_t cv_numlaps = CVAR_INIT ("numlaps", "3", CV_NETVAR|CV_CALL|CV_NOINIT, numlaps_cons_t, NumLaps_OnChange); -static CV_PossibleValue_t basenumlaps_cons_t[] = {{1, "MIN"}, {99, "MAX"}, {0, "Map default"}, {0, NULL}}; -consvar_t cv_basenumlaps = CVAR_INIT ("basenumlaps", "Map default", CV_SAVE|CV_NETVAR|CV_CALL|CV_CHEAT, basenumlaps_cons_t, BaseNumLaps_OnChange); + +static CV_PossibleValue_t numlaps_cons_t[] = {{1, "MIN"}, {MAX_LAPS, "MAX"}, {0, "Map default"}, {0, NULL}}; +consvar_t cv_numlaps = CVAR_INIT ("numlaps", "Map default", CV_SAVE|CV_NETVAR|CV_CALL|CV_CHEAT, numlaps_cons_t, NumLaps_OnChange); // Point and time limits for every gametype INT32 pointlimits[NUMGAMETYPES]; @@ -691,7 +688,6 @@ void D_RegisterServerCommands(void) // misc CV_RegisterVar(&cv_pointlimit); CV_RegisterVar(&cv_numlaps); - CV_RegisterVar(&cv_basenumlaps); CV_RegisterVar(&cv_autobalance); CV_RegisterVar(&cv_teamscramble); @@ -4480,24 +4476,6 @@ static void PointLimit_OnChange(void) CONS_Printf(M_GetText("Point limit disabled\n")); } -static void NumLaps_OnChange(void) -{ - if (K_CanChangeRules() == false) - { - return; - } - - if ((mapheaderinfo[gamemap - 1]->levelflags & LF_SECTIONRACE) - && (cv_numlaps.value > mapheaderinfo[gamemap - 1]->numlaps)) - { - CV_StealthSetValue(&cv_numlaps, mapheaderinfo[gamemap - 1]->numlaps); - } - - // Just don't be verbose - if (gametyperules & GTR_CIRCUIT) - CONS_Printf(M_GetText("Number of laps set to %d\n"), cv_numlaps.value); -} - static void NetTimeout_OnChange(void) { connectiontimeout = (tic_t)cv_nettimeout.value; @@ -5759,22 +5737,24 @@ static void Command_ShowTime_f(void) } // SRB2Kart: On change messages -static void BaseNumLaps_OnChange(void) +static void NumLaps_OnChange(void) { - if (K_CanChangeRules() == true) + if (K_CanChangeRules() == false) { - const char *str = va("%d", cv_basenumlaps.value); + return; + } - if (cv_basenumlaps.value == 0) - { - str = "map defaults"; - } - - CONS_Printf(M_GetText("Number of laps will be changed to %s next round.\n"), str); + if (leveltime < starttime) + { + CONS_Printf(M_GetText("Number of laps have been set to %d.\n"), cv_numlaps.value); + numlaps = (UINT8)cv_numlaps.value; + } + else + { + CONS_Printf(M_GetText("Number of laps will be set to %d next round.\n"), cv_numlaps.value); } } - static void KartFrantic_OnChange(void) { if (K_CanChangeRules() == false) diff --git a/src/d_netcmd.h b/src/d_netcmd.h index f6d172bcc..e84342795 100644 --- a/src/d_netcmd.h +++ b/src/d_netcmd.h @@ -42,7 +42,6 @@ extern consvar_t cv_itemrespawn; extern consvar_t cv_pointlimit; extern consvar_t cv_timelimit; extern consvar_t cv_numlaps; -extern consvar_t cv_basenumlaps; extern UINT32 timelimitintics; extern consvar_t cv_allowexitlevel; diff --git a/src/d_player.h b/src/d_player.h index 36a30cb5c..a679f0776 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -258,6 +258,7 @@ typedef enum #define TRICKDELAY (TICRATE/4) #define TUMBLEBOUNCES 3 +#define TUMBLEGRAVITY (4*FRACUNIT) #define BALLHOGINCREMENT (7) @@ -541,6 +542,7 @@ typedef struct player_s INT16 totalring; // Total number of rings obtained for GP tic_t realtime; // integer replacement for leveltime UINT8 laps; // Number of laps (optional) + UINT8 latestlap; INT32 starpostnum; // The number of the last starpost you hit UINT8 ctfteam; // 0 == Spectator, 1 == Red, 2 == Blue diff --git a/src/doomstat.h b/src/doomstat.h index 4e782e59c..791504815 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -700,6 +700,7 @@ extern INT16 scramblecount; //for CTF team scramble extern INT32 cheats; // SRB2kart +extern UINT8 numlaps; extern UINT8 gamespeed; extern boolean franticitems; extern boolean encoremode, prevencoremode; diff --git a/src/g_demo.c b/src/g_demo.c index a5f658a62..24ee6cd4e 100644 --- a/src/g_demo.c +++ b/src/g_demo.c @@ -1999,6 +1999,7 @@ void G_BeginRecording(void) WRITEUINT8(demo_p, demoflags); WRITEUINT8(demo_p, gametype & 0xFF); + WRITEUINT8(demo_p, numlaps); // file list m = demo_p;/* file count */ @@ -2429,6 +2430,7 @@ UINT8 G_CmpDemoTime(char *oldname, char *newname) p += 16; // map md5 flags = READUINT8(p); // demoflags p++; // gametype + p++; // numlaps G_SkipDemoExtraFiles(&p); aflags = flags & (DF_TIMEATTACK|DF_BREAKTHECAPSULES); @@ -2486,6 +2488,7 @@ UINT8 G_CmpDemoTime(char *oldname, char *newname) p += 16; // mapmd5 flags = READUINT8(p); p++; // gametype + p++; // numlaps G_SkipDemoExtraFiles(&p); if (!(flags & aflags)) { @@ -2600,6 +2603,7 @@ void G_LoadDemoInfo(menudemo_t *pdemo) } pdemo->gametype = READUINT8(info_p); + pdemo->numlaps = READUINT8(info_p); pdemo->addonstatus = G_CheckDemoExtraFiles(&info_p, true); info_p += 4; // RNG seed @@ -2626,20 +2630,11 @@ void G_LoadDemoInfo(menudemo_t *pdemo) if (!stricmp(kartspeed_cons_t[j].strvalue, svalue)) pdemo->kartspeed = kartspeed_cons_t[j].value; } - else if (netid == cv_basenumlaps.netid && pdemo->gametype == GT_RACE) - pdemo->numlaps = atoi(svalue); } if (pdemoflags & DF_ENCORE) pdemo->kartspeed |= DF_ENCORE; - /*// Temporary info until this is actually present in replays. - (void)extrainfo_p; - sprintf(pdemo->winnername, "transrights420"); - pdemo->winnerskin = 1; - pdemo->winnercolor = SKINCOLOR_MOONSET; - pdemo->winnertime = 6666;*/ - // Read standings! count = 0; @@ -2835,6 +2830,7 @@ void G_DoPlayDemo(char *defdemoname) demoflags = READUINT8(demo_p); gametype = READUINT8(demo_p); G_SetGametype(gametype); + numlaps = READUINT8(demo_p); if (demo.title) // Titledemos should always play and ought to always be compatible with whatever wadlist is running. G_SkipDemoExtraFiles(&demo_p); @@ -3258,6 +3254,7 @@ void G_AddGhost(char *defdemoname) } p++; // gametype + p++; // numlaps G_SkipDemoExtraFiles(&p); // Don't wanna modify the file list for ghosts. switch ((flags & DF_ATTACKMASK)>>DF_ATTACKSHIFT) @@ -3475,7 +3472,7 @@ void G_UpdateStaffGhostName(lumpnum_t l) } p++; // Gametype - + p++; // numlaps G_SkipDemoExtraFiles(&p); switch ((flags & DF_ATTACKMASK)>>DF_ATTACKSHIFT) diff --git a/src/g_game.c b/src/g_game.c index 2939dee2e..68286da99 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -303,6 +303,7 @@ INT32 cheats; //for multiplayer cheat commands // SRB2Kart // Cvars that we don't want changed mid-game +UINT8 numlaps; // Removed from Cvar hell UINT8 gamespeed; // Game's current speed (or difficulty, or cc, or etc); 0 for easy, 1 for normal, 2 for hard boolean encoremode = false; // Encore Mode currently enabled? boolean prevencoremode; @@ -2198,6 +2199,7 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps) INT32 khudcardanimation; INT16 totalring; UINT8 laps; + UINT8 latestlap; UINT16 skincolor; INT32 skin; UINT32 availabilities; @@ -2284,6 +2286,7 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps) khudfault = 0; nocontrol = 0; laps = 0; + latestlap = 0; totalring = 0; roundscore = 0; exiting = 0; @@ -2324,6 +2327,8 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps) nocontrol = players[player].nocontrol; laps = players[player].laps; + latestlap = players[player].latestlap; + totalring = players[player].totalring; roundscore = players[player].roundscore; @@ -2380,6 +2385,7 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps) p->karthud[khud_cardanimation] = khudcardanimation; p->laps = laps; + p->latestlap = latestlap; p->totalring = totalring; p->bot = bot; @@ -3610,11 +3616,14 @@ static void G_DoCompleted(void) wipegamestate = GS_NULL; for (i = 0; i < MAXPLAYERS; i++) + { if (playeringame[i]) { // SRB2Kart: exitlevel shouldn't get you the points if (!players[i].exiting && !(players[i].pflags & PF_NOCONTEST)) { + clientPowerAdd[i] = 0; + if (players[i].bot) { K_FakeBotResults(&players[i]); @@ -3632,6 +3641,7 @@ static void G_DoCompleted(void) G_PlayerFinishLevel(i); // take away cards and stuff } + } // play some generic music if there's no win/cool/lose music going on (for exitlevel commands) if ((gametyperules & GTR_CIRCUIT) && ((multiplayer && demo.playback) || j == r_splitscreen+1) && (cv_inttime.value > 0)) diff --git a/src/hu_stuff.c b/src/hu_stuff.c index 194f1de0b..f4f52f5cf 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -2421,7 +2421,7 @@ static void HU_DrawRankings(void) if (circuitmap) { V_DrawCenteredString(64, 8, 0, "LAP COUNT"); - V_DrawCenteredString(64, 16, hilicol, va("%d", cv_numlaps.value)); + V_DrawCenteredString(64, 16, hilicol, va("%d", numlaps)); } V_DrawCenteredString(256, 8, 0, "GAME SPEED"); diff --git a/src/k_collide.c b/src/k_collide.c index 7b0854a01..128364cfc 100644 --- a/src/k_collide.c +++ b/src/k_collide.c @@ -675,6 +675,12 @@ static inline BlockItReturn_t PIT_LightningShieldAttack(mobj_t *thing) return BMIT_ABORT; } + if (thing == NULL || P_MobjWasRemoved(thing)) + { + // Invalid? + return BMIT_ABORT; + } + if (thing == lightningSource) { // Don't explode yourself!! diff --git a/src/k_hud.c b/src/k_hud.c index 4e9a4544f..f47c3e04b 100644 --- a/src/k_hud.c +++ b/src/k_hud.c @@ -1716,7 +1716,7 @@ static void K_DrawKartPositionNum(INT32 num) { localpatch = kp_winnernum[(leveltime % (NUMWINFRAMES*3)) / 3]; } - else if (stplyr->laps >= cv_numlaps.value || stplyr->exiting) // Check for the final lap, or won + else if (stplyr->laps >= numlaps || stplyr->exiting) // Check for the final lap, or won { boolean useRedNums = K_IsPlayerLosing(stplyr); @@ -2347,7 +2347,7 @@ static void K_drawKartLapsAndRings(void) V_DrawScaledPatch(fx, fy, V_HUDTRANS|V_SLIDEIN|splitflags, kp_splitlapflag); V_DrawScaledPatch(fx+22, fy, V_HUDTRANS|V_SLIDEIN|splitflags, frameslash); - if (cv_numlaps.value >= 10) + if (numlaps >= 10) { UINT8 ln[2]; ln[0] = ((stplyr->laps / 10) % 10); @@ -2356,8 +2356,8 @@ static void K_drawKartLapsAndRings(void) V_DrawScaledPatch(fx+13, fy, V_HUDTRANS|V_SLIDEIN|splitflags, fontv[PINGNUM_FONT].font[ln[0]]); V_DrawScaledPatch(fx+17, fy, V_HUDTRANS|V_SLIDEIN|splitflags, fontv[PINGNUM_FONT].font[ln[1]]); - ln[0] = ((abs(cv_numlaps.value) / 10) % 10); - ln[1] = (abs(cv_numlaps.value) % 10); + ln[0] = ((numlaps / 10) % 10); + ln[1] = (numlaps % 10); V_DrawScaledPatch(fx+27, fy, V_HUDTRANS|V_SLIDEIN|splitflags, fontv[PINGNUM_FONT].font[ln[0]]); V_DrawScaledPatch(fx+31, fy, V_HUDTRANS|V_SLIDEIN|splitflags, fontv[PINGNUM_FONT].font[ln[1]]); @@ -2365,7 +2365,7 @@ static void K_drawKartLapsAndRings(void) else { V_DrawScaledPatch(fx+13, fy, V_HUDTRANS|V_SLIDEIN|splitflags, kp_facenum[(stplyr->laps) % 10]); - V_DrawScaledPatch(fx+27, fy, V_HUDTRANS|V_SLIDEIN|splitflags, kp_facenum[(cv_numlaps.value) % 10]); + V_DrawScaledPatch(fx+27, fy, V_HUDTRANS|V_SLIDEIN|splitflags, kp_facenum[(numlaps) % 10]); } // Rings @@ -2403,7 +2403,7 @@ static void K_drawKartLapsAndRings(void) { // Laps V_DrawScaledPatch(LAPS_X, LAPS_Y, V_HUDTRANS|V_SLIDEIN|splitflags, kp_lapsticker); - V_DrawKartString(LAPS_X+33, LAPS_Y+3, V_HUDTRANS|V_SLIDEIN|splitflags, va("%d/%d", min(stplyr->laps, cv_numlaps.value), cv_numlaps.value)); + V_DrawKartString(LAPS_X+33, LAPS_Y+3, V_HUDTRANS|V_SLIDEIN|splitflags, va("%d/%d", min(stplyr->laps, numlaps), numlaps)); // Rings if (!uselives) @@ -4377,7 +4377,7 @@ static void K_drawLapStartAnim(void) kp_lapanim_hand[stplyr->karthud[khud_laphand]-1], NULL); } - if (stplyr->laps == (UINT8)(cv_numlaps.value)) + if (stplyr->laps == (UINT8)(numlaps)) { newval = (62 - (32 * max(0, progress - 76))) * FRACUNIT; oldval = (62 - (32 * max(0, progressOld - 76))) * FRACUNIT; diff --git a/src/k_kart.c b/src/k_kart.c index 0c6da131f..2b9bfe46c 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -357,15 +357,15 @@ static INT32 K_KartItemOddsRace[NUMKARTRESULTS-1][8] = /*Invincibility*/ { 0, 0, 0, 0, 3, 4, 6, 9 }, // Invincibility /*Banana*/ { 2, 3, 1, 0, 0, 0, 0, 0 }, // Banana /*Eggman Monitor*/ { 1, 2, 0, 0, 0, 0, 0, 0 }, // Eggman Monitor - /*Orbinaut*/ { 5, 4, 2, 2, 0, 0, 0, 0 }, // Orbinaut - /*Jawz*/ { 0, 3, 2, 1, 1, 0, 0, 0 }, // Jawz - /*Mine*/ { 0, 2, 3, 1, 0, 0, 0, 0 }, // Mine + /*Orbinaut*/ { 5, 5, 2, 2, 0, 0, 0, 0 }, // Orbinaut + /*Jawz*/ { 0, 4, 2, 1, 0, 0, 0, 0 }, // Jawz + /*Mine*/ { 0, 3, 3, 1, 0, 0, 0, 0 }, // Mine /*Land Mine*/ { 3, 0, 0, 0, 0, 0, 0, 0 }, // Land Mine /*Ballhog*/ { 0, 0, 2, 2, 0, 0, 0, 0 }, // Ballhog /*Self-Propelled Bomb*/ { 0, 0, 0, 0, 0, 2, 4, 0 }, // Self-Propelled Bomb /*Grow*/ { 0, 0, 0, 1, 2, 3, 0, 0 }, // Grow /*Shrink*/ { 0, 0, 0, 0, 0, 0, 2, 0 }, // Shrink - /*Lightning Shield*/ { 1, 2, 0, 0, 0, 0, 0, 0 }, // Lightning Shield + /*Lightning Shield*/ { 1, 0, 0, 0, 0, 0, 0, 0 }, // Lightning Shield /*Bubble Shield*/ { 0, 1, 2, 1, 0, 0, 0, 0 }, // Bubble Shield /*Flame Shield*/ { 0, 0, 0, 0, 0, 1, 3, 5 }, // Flame Shield /*Hyudoro*/ { 3, 0, 0, 0, 0, 0, 0, 0 }, // Hyudoro @@ -373,13 +373,13 @@ static INT32 K_KartItemOddsRace[NUMKARTRESULTS-1][8] = /*Super Ring*/ { 2, 1, 1, 0, 0, 0, 0, 0 }, // Super Ring /*Kitchen Sink*/ { 0, 0, 0, 0, 0, 0, 0, 0 }, // Kitchen Sink /*Drop Target*/ { 3, 0, 0, 0, 0, 0, 0, 0 }, // Drop Target - /*Sneaker x2*/ { 0, 0, 2, 2, 1, 0, 0, 0 }, // Sneaker x2 - /*Sneaker x3*/ { 0, 0, 0, 2, 6,10, 5, 0 }, // Sneaker x3 + /*Sneaker x2*/ { 0, 0, 2, 2, 2, 0, 0, 0 }, // Sneaker x2 + /*Sneaker x3*/ { 0, 0, 0, 1, 6,10, 5, 0 }, // Sneaker x3 /*Banana x3*/ { 0, 1, 1, 0, 0, 0, 0, 0 }, // Banana x3 /*Banana x10*/ { 0, 0, 0, 1, 0, 0, 0, 0 }, // Banana x10 /*Orbinaut x3*/ { 0, 0, 1, 0, 0, 0, 0, 0 }, // Orbinaut x3 - /*Orbinaut x4*/ { 0, 0, 0, 1, 1, 0, 0, 0 }, // Orbinaut x4 - /*Jawz x2*/ { 0, 0, 1, 2, 0, 0, 0, 0 } // Jawz x2 + /*Orbinaut x4*/ { 0, 0, 0, 2, 0, 0, 0, 0 }, // Orbinaut x4 + /*Jawz x2*/ { 0, 0, 1, 2, 1, 0, 0, 0 } // Jawz x2 }; static INT32 K_KartItemOddsBattle[NUMKARTRESULTS][2] = @@ -1704,9 +1704,13 @@ static void K_DrawDraftCombiring(player_t *player, player_t *victim, fixed_t cur UINT8 c; if (maxdist == 0) - c = 0; + { + c = leveltime % CHAOTIXBANDCOLORS; + } else + { c = FixedMul(CHAOTIXBANDCOLORS<> FRACBITS; + } stepx = (victim->mo->x - player->mo->x) / CHAOTIXBANDLEN; stepy = (victim->mo->y - player->mo->y) / CHAOTIXBANDLEN; @@ -1725,8 +1729,16 @@ static void K_DrawDraftCombiring(player_t *player, player_t *victim, fixed_t cur curz + (P_RandomRange(24,48)*mapobjectscale), MT_SIGNSPARKLE); - P_SetMobjState(band, S_SIGNSPARK1 + (leveltime % 11)); - P_SetScale(band, (band->destscale = (3*player->mo->scale)/2)); + if (maxdist == 0) + { + P_SetMobjState(band, S_KSPARK1 + (leveltime % 8)); + P_SetScale(band, (band->destscale = player->mo->scale)); + } + else + { + P_SetMobjState(band, S_SIGNSPARK1 + (leveltime % 11)); + P_SetScale(band, (band->destscale = (3*player->mo->scale)/2)); + } band->color = colors[c]; band->colorized = true; @@ -1896,9 +1908,14 @@ static void K_UpdateDraft(player_t *player) } // No one to draft off of? Then you can knock that off. - if (player->draftleeway) // Prevent small disruptions from stopping your draft. + if (player->draftleeway > 0) // Prevent small disruptions from stopping your draft. { - player->draftleeway--; + if (P_IsObjectOnGround(player->mo) == true) + { + // Allow maintaining tether in air setpieces. + player->draftleeway--; + } + if (player->lastdraft >= 0 && player->lastdraft < MAXPLAYERS && playeringame[player->lastdraft] @@ -2979,15 +2996,14 @@ INT16 K_GetSpindashChargeTime(player_t *player) fixed_t K_GetSpindashChargeSpeed(player_t *player) { // more speed for higher weight & speed - // Tails = +6.25%, Fang = +20.31%, Mighty = +20.31%, Metal = +25% + // Tails = +18.75%, Fang = +46.88%, Mighty = +46.88%, Metal = +56.25% // (can be higher than this value when overcharged) - const fixed_t val = (player->kartspeed + player->kartweight) * (FRACUNIT/32); + const fixed_t val = ((player->kartspeed + player->kartweight) + 2) * (FRACUNIT/32); // TODO: gametyperules return (gametype == GT_BATTLE) ? (4 * val) : val; } - // sets boostpower, speedboost, accelboost, and handleboost to whatever we need it to be static void K_GetKartBoostPower(player_t *player) { @@ -3072,7 +3088,7 @@ static void K_GetKartBoostPower(player_t *player) if (player->startboost) // Startup Boost { - ADDBOOST(FRACUNIT/2, 4*FRACUNIT, 0); // + 50% top speed, + 400% acceleration, +0% handling + ADDBOOST(FRACUNIT, 4*FRACUNIT, sliptidehandling/2); // + 100% top speed, + 400% acceleration, +25% handling } if (player->driftboost) // Drift Boost @@ -3113,6 +3129,12 @@ static void K_GetKartBoostPower(player_t *player) draftspeed *= 2; } + if (player->itemtype == KITEM_LIGHTNINGSHIELD) + { + // infinite tether + draftspeed *= 2; + } + speedboost += FixedMul(draftspeed, player->draftpower); // (Drafting suffers no boost stack penalty.) numboosts++; } @@ -3616,9 +3638,25 @@ static void K_RemoveGrowShrink(player_t *player) P_RestoreMusic(player); } +static fixed_t K_TumbleZ(mobj_t *mo, fixed_t input) +{ + // Scales base tumble gravity to FRACUNIT + const fixed_t baseGravity = FixedMul(DEFAULT_GRAVITY, TUMBLEGRAVITY); + + // Adapt momz w/ gravity + fixed_t gravityAdjust = FixedDiv(P_GetMobjGravity(mo), baseGravity); + + if (mo->eflags & MFE_UNDERWATER) + { + // Reverse doubled falling speed. + gravityAdjust /= 2; + } + + return FixedMul(input, -gravityAdjust); +} + void K_TumblePlayer(player_t *player, mobj_t *inflictor, mobj_t *source) { - fixed_t gravityadjust; (void)source; K_DirectorFollowAttack(player, inflictor, source); @@ -3647,16 +3685,7 @@ void K_TumblePlayer(player_t *player, mobj_t *inflictor, mobj_t *source) S_StartSound(player->mo, sfx_s3k9b); - // adapt momz w/ gravity? - // as far as kart goes normal gravity is 2 (FRACUNIT*2) - - gravityadjust = P_GetMobjGravity(player->mo)/2; // so we'll halve it for our calculations. - - if (player->mo->eflags & MFE_UNDERWATER) - gravityadjust /= 2; // halve "gravity" underwater - - // and then modulate momz like that... - player->mo->momz = -gravityadjust * player->tumbleHeight; + player->mo->momz = K_TumbleZ(player->mo, player->tumbleHeight * FRACUNIT); P_SetPlayerMobjState(player->mo, S_KART_SPINOUT); @@ -3671,8 +3700,6 @@ static boolean K_LastTumbleBounceCondition(player_t *player) static void K_HandleTumbleBounce(player_t *player) { - fixed_t gravityadjust; - player->tumbleBounces++; player->tumbleHeight = (player->tumbleHeight * ((player->tumbleHeight > 100) ? 3 : 4)) / 5; player->pflags &= ~PF_TUMBLESOUND; @@ -3705,7 +3732,7 @@ static void K_HandleTumbleBounce(player_t *player) // A bit of damage hitlag. // This gives a window for DI!! - K_AddHitLag(player->mo, 6, true); + K_AddHitLag(player->mo, 3, true); if (P_IsDisplayPlayer(player) && player->tumbleHeight >= 40) P_StartQuake((player->tumbleHeight*3/2)<mo->momx = player->mo->momx / 2; player->mo->momy = player->mo->momy / 2; - // adapt momz w/ gravity? - // as far as kart goes normal gravity is 2 (FRACUNIT*2) - - gravityadjust = P_GetMobjGravity(player->mo)/2; // so we'll halve it for our calculations. - - if (player->mo->eflags & MFE_UNDERWATER) - gravityadjust /= 2; // halve "gravity" underwater - // and then modulate momz like that... - player->mo->momz = -gravityadjust * player->tumbleHeight; + player->mo->momz = K_TumbleZ(player->mo, player->tumbleHeight * FRACUNIT); } // Play a falling sound when you start falling while tumbling and you're nowhere near done bouncing @@ -3741,6 +3760,21 @@ static void K_HandleTumbleSound(player_t *player) } } +void K_TumbleInterrupt(player_t *player) +{ + // If player was tumbling, set variables so that they don't tumble like crazy after they're done respawning + if (player->tumbleBounces > 0) + { + player->tumbleBounces = 0; // MAXBOUNCES-1; + player->pflags &= ~PF_TUMBLELASTBOUNCE; + //players->tumbleHeight = 20; + + players->mo->rollangle = 0; + player->spinouttype = KSPIN_WIPEOUT; + player->spinouttimer = player->wipeoutslow = TICRATE+2; + } +} + void K_ApplyTripWire(player_t *player, tripwirestate_t state) { if (state == TRIP_PASSED) @@ -7243,6 +7277,8 @@ static void K_LookForRings(mobj_t *pmo) */ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) { + const boolean onground = P_IsObjectOnGround(player->mo); + K_UpdateOffroad(player); K_UpdateDraft(player); K_UpdateEngineSounds(player); // Thanks, VAda! @@ -7514,8 +7550,10 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) if (player->strongdriftboost) player->strongdriftboost--; - if (player->startboost) + if (player->startboost > 0 && onground == true) + { player->startboost--; + } if (player->spindashboost) { @@ -8248,7 +8286,7 @@ void K_UpdateDistanceFromFinishLine(player_t *const player) // distance calculation to work easily if ((mapheaderinfo[gamemap - 1]->levelflags & LF_SECTIONRACE) == 0U) { - const UINT8 numfulllapsleft = ((UINT8)cv_numlaps.value - player->laps); + const UINT8 numfulllapsleft = ((UINT8)numlaps - player->laps); player->distancetofinish += numfulllapsleft * K_GetCircuitLength(); diff --git a/src/k_kart.h b/src/k_kart.h index 3444285de..c09633eee 100644 --- a/src/k_kart.h +++ b/src/k_kart.h @@ -73,6 +73,7 @@ void K_DoPowerClash(player_t *t1, player_t *t2); void K_BattleAwardHit(player_t *player, player_t *victim, mobj_t *inflictor, UINT8 bumpersRemoved); void K_SpinPlayer(player_t *player, mobj_t *inflictor, mobj_t *source, INT32 type); void K_TumblePlayer(player_t *player, mobj_t *inflictor, mobj_t *source); +void K_TumbleInterrupt(player_t *player); INT32 K_ExplodePlayer(player_t *player, mobj_t *inflictor, mobj_t *source); void K_DebtStingPlayer(player_t *player, mobj_t *source); void K_HandleBumperChanges(player_t *player, UINT8 prevBumpers); diff --git a/src/k_pwrlv.c b/src/k_pwrlv.c index 22c386191..cd3ee1827 100644 --- a/src/k_pwrlv.c +++ b/src/k_pwrlv.c @@ -1,5 +1,12 @@ -/// \file k_pwrlv.c -/// \brief SRB2Kart Power Levels +// DR. ROBOTNIK'S RING RACERS +//----------------------------------------------------------------------------- +// Copyright (C) 2018-2022 by Sally Cochenour +// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. +//----------------------------------------------------------------------------- +// \brief Power Level system #include "k_pwrlv.h" #include "d_netcmd.h" @@ -19,9 +26,12 @@ UINT16 vspowerlevel[PWRLV_NUMTYPES]; // This is done so that clients will never be able to hack someone else's score over the server. UINT16 clientpowerlevels[MAXPLAYERS][PWRLV_NUMTYPES]; -// Which players spec-scummed, and their power level before scumming. -// On race finish, everyone is considered to have "won" against these people. -INT16 nospectategrief[MAXPLAYERS]; +// Total calculated power add during the match, +// totalled at the end of the round. +INT16 clientPowerAdd[MAXPLAYERS]; + +// Players who spectated mid-race +UINT8 spectateGriefed = 0; // Game setting scrambles based on server Power Level SINT8 speedscramble = -1; @@ -52,8 +62,14 @@ void K_ClearClientPowerLevels(void) { UINT8 i, j; for (i = 0; i < MAXPLAYERS; i++) + { + clientPowerAdd[i] = 0; + for (j = 0; j < PWRLV_NUMTYPES; j++) + { clientpowerlevels[i][j] = 0; + } + } } // Adapted from this: http://wiki.tockdom.com/wiki/Player_Rating @@ -71,7 +87,7 @@ INT16 K_CalculatePowerLevelInc(INT16 diff) diff = -MAXDIFF; #undef MAXDIFF - x = ((diff-2)<> FRACBITS); } +INT16 K_PowerLevelPlacementScore(player_t *player) +{ + if ((player->pflags & PF_NOCONTEST) || (player->spectator)) + { + return 0; + } + + if (gametyperules & GTR_CIRCUIT) + { + return MAXPLAYERS - player->position; + } + else + { + return player->score; + } +} + INT16 K_CalculatePowerLevelAvg(void) { fixed_t avg = 0; @@ -143,7 +176,269 @@ INT16 K_CalculatePowerLevelAvg(void) return (INT16)(avg >> FRACBITS); } -// -- K_UpdatePowerLevels could not be moved here due to usage of y_data, unfortunately. -- +void K_UpdatePowerLevels(player_t *player, UINT8 lap, boolean forfeit) +{ + const UINT8 playerNum = player - players; + const boolean exitBonus = ((lap > numlaps) || (player->pflags & PF_NOCONTEST)); + + SINT8 powerType = K_UsingPowerLevels(); + + INT16 yourScore = 0; + UINT16 yourPower = 0; + + UINT8 i; + + // Compare every single player against each other for power level increases. + // Every player you won against gives you more points, and vice versa. + // The amount of points won per match-up depends on the difference between the loser's power and the winner's power. + // See K_CalculatePowerLevelInc for more info. + + if (powerType == PWRLV_DISABLED) + { + return; + } + + if (!playeringame[playerNum] || player->spectator) + { + return; + } + + //CONS_Printf("\n========\n"); + //CONS_Printf("* Power Level change for player %s (LAP %d) *\n", player_names[playerNum], lap); + //CONS_Printf("========\n"); + + yourPower = clientpowerlevels[playerNum][powerType]; + if (yourPower == 0) + { + // Guests don't record power level changes. + return; + } + + //CONS_Printf("%s's PWR.LV: %d\n", player_names[playerNum], yourPower); + + yourScore = K_PowerLevelPlacementScore(player); + //CONS_Printf("%s's gametype score: %d\n", player_names[playerNum], yourScore); + + //CONS_Printf("========\n"); + for (i = 0; i < MAXPLAYERS; i++) + { + UINT16 theirScore = 0; + INT16 theirPower = 0; + + INT16 diff = 0; // Loser PWR.LV - Winner PWR.LV + INT16 inc = 0; // Total pt increment + + boolean won = false; + + if (i == playerNum) // Same person + { + continue; + } + + if (!playeringame[i] || players[i].spectator) + { + continue; + } + + //CONS_Printf("%s VS %s:\n", player_names[playerNum], player_names[i]); + + theirPower = clientpowerlevels[i][powerType]; + if (theirPower == 0) + { + // No power level (splitscreen guests, bots) + continue; + } + + //CONS_Printf("%s's PWR.LV: %d\n", player_names[i], theirPower); + + theirScore = K_PowerLevelPlacementScore(&players[i]); + //CONS_Printf("%s's gametype score: %d\n", player_names[i], theirScore); + + if (yourScore == theirScore && forfeit == false) // Tie -- neither get any points for this match up. + { + //CONS_Printf("TIE, no change.\n"); + continue; + } + + won = (yourScore > theirScore); + + if (won == true && forfeit == false) // This player won! + { + diff = theirPower - yourPower; + inc += K_CalculatePowerLevelInc(diff); + //CONS_Printf("WON! Diff is %d, increment is %d\n", diff, inc); + } + else // This player lost... + { + diff = yourPower - theirPower; + inc -= K_CalculatePowerLevelInc(diff); + //CONS_Printf("LOST... Diff is %d, increment is %d\n", diff, inc); + } + + if (exitBonus == false) + { + INT16 prevInc = inc; + + inc /= max(numlaps-1, 1); + + if (inc == 0) + { + if (prevInc > 0) + { + inc = 1; + } + else if (prevInc < 0) + { + inc = -1; + } + } + + //CONS_Printf("Reduced (%d / %d = %d) because it's not the end of the race\n", prevInc, numlaps, inc); + } + + //CONS_Printf("========\n"); + + if (inc == 0) + { + CONS_Printf("Total Result: No increment, no change.\n"); + continue; + } + + //CONS_Printf("Total Result:\n"); + //CONS_Printf("Increment: %d\n", inc); + + //CONS_Printf("%s current: %d\n", player_names[playerNum], clientPowerAdd[playerNum]); + clientPowerAdd[playerNum] += inc; + //CONS_Printf("%s final: %d\n", player_names[playerNum], clientPowerAdd[playerNum]); + + //CONS_Printf("%s current: %d\n", player_names[i], clientPowerAdd[i]); + clientPowerAdd[i] -= inc; + //CONS_Printf("%s final: %d\n", player_names[i], clientPowerAdd[i]); + + //CONS_Printf("========\n"); + } +} + +void K_UpdatePowerLevelsOnFailure(player_t *player) +{ + // Update upon spectate / quit / NO CONTEST + INT16 lapsLeft = 0; + UINT8 i; + + lapsLeft = (numlaps - player->latestlap) + 1; + + if (lapsLeft <= 0) + { + return; + } + + for (i = 0; i < lapsLeft; i++) + { + K_UpdatePowerLevels(player, player->latestlap + (i + 1), true); + } + + player->latestlap = numlaps+1; +} + +INT16 K_FinalPowerIncrement(player_t *player, INT16 yourPower, INT16 baseInc) +{ + INT16 inc = baseInc; + UINT8 numPlayers = 0; + UINT8 i; + + if (yourPower == 0) + { + // Guests don't record power level changes. + return 0; + } + + for (i = 0; i < MAXPLAYERS; i++) + { + if (!playeringame[i] || players[i].spectator) + { + continue; + } + + numPlayers++; + } + + if (inc <= 0) + { + if (player->position == 1) + { + // Won the whole match? + // Get at least one point. + inc = 1; + } + else + { + // You trade points in 1v1s, + // but is more lenient in bigger lobbies. + inc /= max(1, numPlayers-1); + + if (inc == 0) + { + if (baseInc > 0) + { + inc = 1; + } + else if (baseInc < 0) + { + inc = -1; + } + } + } + } + + if (yourPower + inc > PWRLVRECORD_MAX) + { + inc -= ((yourPower + inc) - PWRLVRECORD_MAX); + } + + if (yourPower + inc < PWRLVRECORD_MIN) + { + inc -= ((yourPower + inc) - PWRLVRECORD_MIN); + } + + return inc; +} + +void K_CashInPowerLevels(void) +{ + SINT8 powerType = K_UsingPowerLevels(); + UINT8 i; + + //CONS_Printf("\n========\n"); + //CONS_Printf("Cashing in power level changes...\n"); + //CONS_Printf("========\n"); + + for (i = 0; i < MAXPLAYERS; i++) + { + if (playeringame[i] == true && powerType != PWRLV_DISABLED) + { + INT16 inc = K_FinalPowerIncrement(&players[i], clientpowerlevels[i][powerType], clientPowerAdd[i]); + clientpowerlevels[i][powerType] += inc; + + //CONS_Printf("%s: %d -> %d (%d)\n", player_names[i], clientpowerlevels[i][powerType] - inc, clientpowerlevels[i][powerType], inc); + + if (!demo.playback && i == consoleplayer && inc != 0) + { + vspowerlevel[powerType] = clientpowerlevels[i][powerType]; + + if (M_UpdateUnlockablesAndExtraEmblems()) + { + S_StartSound(NULL, sfx_ncitem); + } + + G_SaveGameData(); + } + } + + clientPowerAdd[i] = 0; + } + + //CONS_Printf("========\n"); +} void K_SetPowerLevelScrambles(SINT8 powertype) { @@ -227,7 +522,7 @@ void K_SetPowerLevelScrambles(SINT8 powertype) { case 5: speed = KARTSPEED_HARD; - encore = true; + encore = P_RandomChance(FRACUNIT>>1); break; case 4: speed = P_RandomChance((7<>2); break; case 2: - speed = 1; + speed = KARTSPEED_NORMAL; encore = P_RandomChance(FRACUNIT>>3); break; case 1: default: @@ -254,7 +549,7 @@ void K_SetPowerLevelScrambles(SINT8 powertype) CONS_Debug(DBG_GAMELOGIC, "Rolled speed: %d\n", speed); CONS_Debug(DBG_GAMELOGIC, "Rolled encore: %s\n", (encore ? "true" : "false")); - if (cv_kartspeed.value == -1) + if (cv_kartspeed.value == KARTSPEED_AUTO) speedscramble = speed; else speedscramble = -1; @@ -270,88 +565,89 @@ void K_SetPowerLevelScrambles(SINT8 powertype) } } -void K_PlayerForfeit(UINT8 playernum, boolean pointloss) +void K_PlayerForfeit(UINT8 playerNum, boolean pointLoss) { UINT8 p = 0; - INT32 powertype = PWRLV_DISABLED; - UINT16 yourpower = PWRLVRECORD_DEF; - UINT16 theirpower = PWRLVRECORD_DEF; - INT16 diff = 0; // Loser PWR.LV - Winner PWR.LV + + SINT8 powerType = PWRLV_DISABLED; + UINT16 yourPower = 0; INT16 inc = 0; + UINT8 i; // power level & spectating is netgames only if (!netgame) + { return; - - // This server isn't using power levels anyway! - if (!cv_kartusepwrlv.value) - return; + } // Hey, I just got here! - if (players[playernum].jointime <= 1) + if (players[playerNum].jointime <= 1) + { return; + } - // 20 sec into the match counts as a forfeit -- automatic loss against every other player in the match. + // 20 sec into a match counts as a forfeit -- automatic loss against every other player in the match. if (gamestate != GS_LEVEL || leveltime <= starttime+(20*TICRATE)) + { return; + } + + spectateGriefed++; + + // This server isn't using power levels, so don't mess with them. + if (!cv_kartusepwrlv.value) + { + return; + } for (i = 0; i < MAXPLAYERS; i++) { - if (playeringame[i] && !players[i].spectator) + if ((playeringame[i] && !players[i].spectator) + || (i == playerNum)) + { p++; + } } if (p < 2) // no players - return; - - if ((gametyperules & GTR_CIRCUIT)) - powertype = PWRLV_RACE; - else if ((gametyperules & GTR_BUMPERS)) - powertype = PWRLV_BATTLE; - - if (powertype == PWRLV_DISABLED) // No power type?! - return; - - if (clientpowerlevels[playernum][powertype] == 0) // splitscreen guests don't record power level changes - return; - yourpower = clientpowerlevels[playernum][powertype]; - - // Set up the point compensation. - nospectategrief[playernum] = yourpower; - - if (!pointloss) // This is set for stuff like sync-outs, which shouldn't be so harsh on the victim! - return; - - for (i = 0; i < MAXPLAYERS; i++) { - if (i == playernum) - continue; - - if (clientpowerlevels[i][powertype] == 0) // No power level (splitscreen guests, bots) - continue; - - theirpower = clientpowerlevels[i][powertype]; - - diff = yourpower - theirpower; - inc -= K_CalculatePowerLevelInc(diff); + return; } - if (inc == 0) // No change. - return; + powerType = K_UsingPowerLevels(); - if (yourpower + inc > PWRLVRECORD_MAX) // I mean... we're subtracting... but y'know how it is :V - inc -= ((yourpower + inc) - PWRLVRECORD_MAX); - if (yourpower + inc < PWRLVRECORD_MIN) - inc -= ((yourpower + inc) - PWRLVRECORD_MIN); - - clientpowerlevels[playernum][powertype] += inc; - - if (!demo.playback && playernum == consoleplayer) + if (powerType == PWRLV_DISABLED) // No power type?! { - vspowerlevel[powertype] = clientpowerlevels[playernum][powertype]; + return; + } + + yourPower = clientpowerlevels[playerNum][powerType]; + if (yourPower == 0) // splitscreen guests don't record power level changes + { + return; + } + + K_UpdatePowerLevelsOnFailure(&players[playerNum]); + inc = K_FinalPowerIncrement(&players[playerNum], yourPower, clientPowerAdd[playerNum]); + + if (inc >= 0) + { + // Don't record no change or increases. + return; + } + + // pointLoss isn't set for stuff like sync-outs, + // which shouldn't be so harsh on the victim! + if (!demo.playback && pointLoss == true && playerNum == consoleplayer) + { + vspowerlevel[powerType] = yourPower + inc; + if (M_UpdateUnlockablesAndExtraEmblems()) + { S_StartSound(NULL, sfx_ncitem); - G_SaveGameData(); // save your punishment! + } + + G_SaveGameData(); } } diff --git a/src/k_pwrlv.h b/src/k_pwrlv.h index 579e298af..9e5645c2f 100644 --- a/src/k_pwrlv.h +++ b/src/k_pwrlv.h @@ -1,16 +1,30 @@ +// DR. ROBOTNIK'S RING RACERS +//----------------------------------------------------------------------------- +// Copyright (C) 2018-2022 by Sally Cochenour +// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. +//----------------------------------------------------------------------------- +// \brief Power Level system + #ifndef __K_PWRLV__ #define __K_PWRLV__ #include "doomtype.h" #include "doomdef.h" +#include "d_player.h" -#define PWRLV_DISABLED -1 -#define PWRLV_RACE 0 -#define PWRLV_BATTLE 1 -#define PWRLV_NUMTYPES 2 +typedef enum +{ + PWRLV_DISABLED = -1, + PWRLV_RACE = 0, + PWRLV_BATTLE = 1, + PWRLV_NUMTYPES = 2, +} pwrlv_type_t; #define PWRLVRECORD_START 1000 -#define PWRLVRECORD_DEF 5000 +#define PWRLVRECORD_MEDIAN 5000 #define PWRLVRECORD_MIN 1 #define PWRLVRECORD_MAX 9999 @@ -19,13 +33,18 @@ extern SINT8 encorescramble; extern UINT16 vspowerlevel[PWRLV_NUMTYPES]; extern UINT16 clientpowerlevels[MAXPLAYERS][PWRLV_NUMTYPES]; -extern INT16 nospectategrief[MAXPLAYERS]; +extern INT16 clientPowerAdd[MAXPLAYERS]; +extern UINT8 spectateGriefed; SINT8 K_UsingPowerLevels(void); void K_ClearClientPowerLevels(void); INT16 K_CalculatePowerLevelInc(INT16 diff); +INT16 K_PowerLevelPlacementScore(player_t *player); INT16 K_CalculatePowerLevelAvg(void); -//void K_UpdatePowerLevels(void); +void K_UpdatePowerLevels(player_t *player, UINT8 lap, boolean forfeit); +void K_UpdatePowerLevelsOnFailure(player_t *player); +INT16 K_FinalPowerIncrement(player_t *player, INT16 yourPower, INT16 increment); +void K_CashInPowerLevels(void); void K_SetPowerLevelScrambles(SINT8 powertype); void K_PlayerForfeit(UINT8 playernum, boolean nopointloss); diff --git a/src/k_respawn.c b/src/k_respawn.c index 1132f182b..9a8cc38e8 100644 --- a/src/k_respawn.c +++ b/src/k_respawn.c @@ -151,18 +151,8 @@ void K_DoIngameRespawn(player_t *player) player->ringboost = 0; player->driftboost = player->strongdriftboost = 0; - - // If player was tumbling, set variables so that they don't tumble like crazy after they're done respawning - if (player->tumbleBounces > 0) - { - player->tumbleBounces = 0; // MAXBOUNCES-1; - player->pflags &= ~PF_TUMBLELASTBOUNCE; - //players->tumbleHeight = 20; - players->mo->rollangle = 0; - player->spinouttype = KSPIN_WIPEOUT; - player->spinouttimer = player->wipeoutslow = (3*TICRATE/2)+2; - } + K_TumbleInterrupt(player); P_ResetPlayer(player); // Set up respawn position if invalid diff --git a/src/lua_playerlib.c b/src/lua_playerlib.c index 7984b053b..8522d7109 100644 --- a/src/lua_playerlib.c +++ b/src/lua_playerlib.c @@ -448,6 +448,8 @@ static int player_get(lua_State *L) lua_pushinteger(L, plr->realtime); else if (fastcmp(field,"laps")) lua_pushinteger(L, plr->laps); + else if (fastcmp(field,"latestlap")) + lua_pushinteger(L, plr->latestlap); else if (fastcmp(field,"ctfteam")) lua_pushinteger(L, plr->ctfteam); else if (fastcmp(field,"checkskip")) @@ -790,6 +792,8 @@ static int player_set(lua_State *L) plr->realtime = (tic_t)luaL_checkinteger(L, 3); else if (fastcmp(field,"laps")) plr->laps = (UINT8)luaL_checkinteger(L, 3); + else if (fastcmp(field,"latestlap")) + plr->latestlap = (UINT8)luaL_checkinteger(L, 3); else if (fastcmp(field,"ctfteam")) plr->ctfteam = (INT32)luaL_checkinteger(L, 3); else if (fastcmp(field,"checkskip")) diff --git a/src/lua_script.c b/src/lua_script.c index 8aea589db..1511fdf0d 100644 --- a/src/lua_script.c +++ b/src/lua_script.c @@ -391,7 +391,7 @@ int LUA_PushGlobals(lua_State *L, const char *word) lua_pushinteger(L, mapobjectscale); return 1; } else if (fastcmp(word,"numlaps")) { - lua_pushinteger(L, cv_numlaps.value); + lua_pushinteger(L, numlaps); return 1; } else if (fastcmp(word,"racecountdown")) { lua_pushinteger(L, racecountdown); diff --git a/src/m_menu.c b/src/m_menu.c index b7299fc9b..58a40176e 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -1478,17 +1478,17 @@ static menuitem_t OP_GameOptionsMenu[] = {IT_STRING | IT_SUBMENU, NULL, "Random Item Toggles...", {.submenu = &OP_MonitorToggleDef}, 10}, {IT_STRING | IT_CVAR, NULL, "Game Speed", {.cvar = &cv_kartspeed}, 30}, - {IT_STRING | IT_CVAR, NULL, "Frantic Items", {.cvar = &cv_kartfrantic}, 40}, + {IT_STRING | IT_CVAR, NULL, "Frantic Items", {.cvar = &cv_kartfrantic}, 40}, {IT_SECRET, NULL, "Encore Mode", {.cvar = &cv_kartencore}, 50}, - {IT_STRING | IT_CVAR, NULL, "Number of Laps", {.cvar = &cv_basenumlaps}, 70}, + {IT_STRING | IT_CVAR, NULL, "Number of Laps", {.cvar = &cv_numlaps}, 70}, {IT_STRING | IT_CVAR, NULL, "Exit Countdown Timer", {.cvar = &cv_countdowntime}, 80}, {IT_STRING | IT_CVAR, NULL, "Time Limit", {.cvar = &cv_timelimit}, 100}, - {IT_STRING | IT_CVAR, NULL, "Starting Bumpers", {.cvar = &cv_kartbumpers}, 110}, - {IT_STRING | IT_CVAR, NULL, "Karma Comeback", {.cvar = &cv_kartcomeback}, 120}, + {IT_STRING | IT_CVAR, NULL, "Starting Bumpers", {.cvar = &cv_kartbumpers}, 110}, + {IT_STRING | IT_CVAR, NULL, "Karma Comeback", {.cvar = &cv_kartcomeback}, 120}, - {IT_STRING | IT_CVAR, NULL, "Track Power Levels", {.cvar = &cv_kartusepwrlv}, 140}, + {IT_STRING | IT_CVAR, NULL, "Track Power Levels", {.cvar = &cv_kartusepwrlv}, 140}, }; static menuitem_t OP_ServerOptionsMenu[] = diff --git a/src/objects/CMakeLists.txt b/src/objects/CMakeLists.txt new file mode 100644 index 000000000..4e9c67d2f --- /dev/null +++ b/src/objects/CMakeLists.txt @@ -0,0 +1 @@ +target_sourcefile(c) diff --git a/src/p_enemy.c b/src/p_enemy.c index 724cb8f39..2c69e7bfe 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -14032,21 +14032,21 @@ void A_LightningFollowPlayer(mobj_t *actor) if (!actor->target) return; + if (actor->extravalue1) // Make the radius also follow the player somewhat accuratly { - if (actor->extravalue1) // Make the radius also follow the player somewhat accuratly - { - sx = actor->target->x + FixedMul((actor->target->scale*actor->extravalue1), FINECOSINE((actor->angle)>>ANGLETOFINESHIFT)); - sy = actor->target->y + FixedMul((actor->target->scale*actor->extravalue1), FINESINE((actor->angle)>>ANGLETOFINESHIFT)); - P_MoveOrigin(actor, sx, sy, actor->target->z); - } - else // else just teleport to player directly - P_MoveOrigin(actor, actor->target->x, actor->target->y, actor->target->z); - - K_MatchGenericExtraFlags(actor, actor->target); // copy our target for graviflip - actor->momx = actor->target->momx; - actor->momy = actor->target->momy; - actor->momz = actor->target->momz; // Give momentum since we don't teleport to our player literally every frame. + sx = actor->target->x + FixedMul((actor->target->scale*actor->extravalue1), FINECOSINE((actor->angle)>>ANGLETOFINESHIFT)); + sy = actor->target->y + FixedMul((actor->target->scale*actor->extravalue1), FINESINE((actor->angle)>>ANGLETOFINESHIFT)); + P_MoveOrigin(actor, sx, sy, actor->target->z); } + else // else just teleport to player directly + { + P_MoveOrigin(actor, actor->target->x, actor->target->y, actor->target->z); + } + + K_MatchGenericExtraFlags(actor, actor->target); // copy our target for graviflip + actor->momx = actor->target->momx; + actor->momy = actor->target->momy; + actor->momz = actor->target->momz; // Give momentum since we don't teleport to our player literally every frame. } // A_FZBoomFlash: diff --git a/src/p_inter.c b/src/p_inter.c index c394a3773..c4b8bf7f9 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -792,16 +792,11 @@ boolean P_CheckRacers(void) boolean eliminatelast = cv_karteliminatelast.value; boolean everyonedone = true; boolean eliminatebots = false; - boolean griefed = false; + const boolean griefed = (spectateGriefed > 0); // Check if all the players in the race have finished. If so, end the level. for (i = 0; i < MAXPLAYERS; i++) { - if (nospectategrief[i] != -1) // prevent spectate griefing - { - griefed = true; - } - if (!playeringame[i] || players[i].spectator || players[i].lives <= 0) // Not playing { // Y'all aren't even playing @@ -922,7 +917,7 @@ boolean P_CheckRacers(void) // We're still playing, but no one else is, so we need to reset spectator griefing. if (numplayersingame <= 1) { - memset(nospectategrief, -1, sizeof (nospectategrief)); + spectateGriefed = 0; } // Turns out we're still having a good time & playing the game, we didn't have to do anything :) diff --git a/src/p_local.h b/src/p_local.h index bb0d02fb2..0e03b8482 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -28,6 +28,9 @@ //#define VIEWHEIGHTS "41" +// Maximum laps per map. +#define MAX_LAPS 99 + // Maximum player score. #define MAXSCORE 99999990 // 999999990 diff --git a/src/p_map.c b/src/p_map.c index 9bab04a97..3d6938ed2 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -417,6 +417,7 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object) P_SetTarget(&spring->target, object); } + K_TumbleInterrupt(object->player); P_ResetPlayer(object->player); object->player->springstars = max(vertispeed, horizspeed) / FRACUNIT / 2; diff --git a/src/p_mobj.c b/src/p_mobj.c index ed4e35c14..af7c86847 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -1130,7 +1130,7 @@ fixed_t P_GetMobjGravity(mobj_t *mo) if (mo->player->tumbleBounces > 0) { - gravityadd = (5*gravityadd)/2; + gravityadd = FixedMul(TUMBLEGRAVITY, gravityadd); } } else @@ -11011,16 +11011,20 @@ void P_RespawnSpecials(void) else { if (pcount == 1) // No respawn when alone + { return; + } else if (pcount > 1) { - time = (120 - ((pcount-2) * 10)) * TICRATE; + time = (120 - ((pcount-2) * 20)) * TICRATE; // If the map is longer or shorter than 3 laps, then adjust ring respawn to account for this. // 5 lap courses would have more retreaded ground, while 2 lap courses would have less. if ((mapheaderinfo[gamemap-1]->numlaps != 3) - && !(mapheaderinfo[gamemap-1]->levelflags & LF_SECTIONRACE)) + && !(mapheaderinfo[gamemap-1]->levelflags & LF_SECTIONRACE)) + { time = (time * 3) / max(1, mapheaderinfo[gamemap-1]->numlaps); + } if (time < 10*TICRATE) { diff --git a/src/p_saveg.c b/src/p_saveg.c index 609784391..5ab1a721a 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -106,6 +106,7 @@ static void P_NetArchivePlayers(void) { WRITEINT16(save_p, clientpowerlevels[i][j]); } + WRITEINT16(save_p, clientPowerAdd[i]); if (!playeringame[i]) continue; @@ -167,6 +168,7 @@ static void P_NetArchivePlayers(void) WRITEINT16(save_p, players[i].totalring); WRITEUINT32(save_p, players[i].realtime); WRITEUINT8(save_p, players[i].laps); + WRITEUINT8(save_p, players[i].latestlap); WRITEINT32(save_p, players[i].starpostnum); WRITEUINT8(save_p, players[i].ctfteam); @@ -406,6 +408,7 @@ static void P_NetUnArchivePlayers(void) { clientpowerlevels[i][j] = READINT16(save_p); } + clientPowerAdd[i] = READINT16(save_p); // Do NOT memset player struct to 0 // other areas may initialize data elsewhere @@ -468,6 +471,7 @@ static void P_NetUnArchivePlayers(void) players[i].totalring = READINT16(save_p); // Total number of rings obtained for GP players[i].realtime = READUINT32(save_p); // integer replacement for leveltime players[i].laps = READUINT8(save_p); // Number of laps (optional) + players[i].latestlap = READUINT8(save_p); players[i].starpostnum = READINT32(save_p); players[i].ctfteam = READUINT8(save_p); // 1 == Red, 2 == Blue @@ -4499,6 +4503,7 @@ static void P_NetArchiveMisc(boolean resending) WRITEUINT8(save_p, battlecapsules); WRITEUINT8(save_p, gamespeed); + WRITEUINT8(save_p, numlaps); WRITEUINT8(save_p, franticitems); WRITEUINT8(save_p, comeback); @@ -4519,8 +4524,7 @@ static void P_NetArchiveMisc(boolean resending) WRITEUINT32(save_p, indirectitemcooldown); WRITEUINT32(save_p, mapreset); - for (i = 0; i < MAXPLAYERS; i++) - WRITEINT16(save_p, nospectategrief[i]); + WRITEUINT8(save_p, spectateGriefed); WRITEUINT8(save_p, thwompsactive); WRITEUINT8(save_p, lastLowestLap); @@ -4648,6 +4652,7 @@ static inline boolean P_NetUnArchiveMisc(boolean reloading) battlecapsules = (boolean)READUINT8(save_p); gamespeed = READUINT8(save_p); + numlaps = READUINT8(save_p); franticitems = (boolean)READUINT8(save_p); comeback = (boolean)READUINT8(save_p); @@ -4668,8 +4673,7 @@ static inline boolean P_NetUnArchiveMisc(boolean reloading) indirectitemcooldown = READUINT32(save_p); mapreset = READUINT32(save_p); - for (i = 0; i < MAXPLAYERS; i++) - nospectategrief[i] = READINT16(save_p); + spectateGriefed = READUINT8(save_p); thwompsactive = (boolean)READUINT8(save_p); lastLowestLap = READUINT8(save_p); diff --git a/src/p_setup.c b/src/p_setup.c index a9701511b..20d45052c 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -4063,25 +4063,37 @@ static void P_InitPlayers(void) static void P_InitGametype(void) { + spectateGriefed = 0; + K_CashInPowerLevels(); // Pushes power level changes even if intermission was skipped + P_InitPlayers(); if (modeattacking && !demo.playback) P_LoadRecordGhosts(); - if ((gametyperules & GTR_CIRCUIT) && server) + numlaps = 0; + if (gametyperules & GTR_CIRCUIT) { - if ((netgame || multiplayer) && cv_basenumlaps.value + if ((netgame || multiplayer) && cv_numlaps.value && (!(mapheaderinfo[gamemap - 1]->levelflags & LF_SECTIONRACE) - || (mapheaderinfo[gamemap - 1]->numlaps > cv_basenumlaps.value))) + || (mapheaderinfo[gamemap - 1]->numlaps > cv_numlaps.value))) { - CV_StealthSetValue(&cv_numlaps, cv_basenumlaps.value); + numlaps = cv_numlaps.value; } else { - CV_StealthSetValue(&cv_numlaps, mapheaderinfo[gamemap - 1]->numlaps); + numlaps = mapheaderinfo[gamemap - 1]->numlaps; } } + wantedcalcdelay = wantedfrequency*2; + indirectitemcooldown = 0; + mapreset = 0; + + thwompsactive = false; + lastLowestLap = 0; + spbplace = -1; + // Start recording replay in multiplayer with a temp filename //@TODO I'd like to fix dedis crashing when recording replays for the future too... if (!demo.playback && multiplayer && !dedicated) @@ -4117,6 +4129,7 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate) // Map header should always be in place at this point INT32 i, ranspecialwipe = 0; sector_t *ss; + levelloading = true; // This is needed. Don't touch. @@ -4430,17 +4443,6 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate) K_InitDirector(); } - wantedcalcdelay = wantedfrequency*2; - indirectitemcooldown = 0; - mapreset = 0; - - for (i = 0; i < MAXPLAYERS; i++) - nospectategrief[i] = -1; - - thwompsactive = false; - lastLowestLap = 0; - spbplace = -1; - // clear special respawning que iquehead = iquetail = 0; diff --git a/src/p_spec.c b/src/p_spec.c index ccb31d447..4de87e70d 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -1917,14 +1917,6 @@ static void K_HandleLapIncrement(player_t *player) player->karthud[khud_laphand] = 0; // No hands in FREE PLAY player->karthud[khud_lapanimation] = 80; - - // save best lap for record attack - if (player == &players[consoleplayer]) - { - if (curlap < bestlap || bestlap == 0) - bestlap = curlap; - curlap = 0; - } } if (rainbowstartavailable == true) @@ -1938,18 +1930,18 @@ static void K_HandleLapIncrement(player_t *player) rainbowstartavailable = false; } - if (netgame && player->laps >= (UINT8)cv_numlaps.value) + if (netgame && player->laps >= numlaps) CON_LogMessage(va(M_GetText("%s has finished the race.\n"), player_names[player-players])); player->starpostnum = 0; if (P_IsDisplayPlayer(player)) { - if (player->laps == (UINT8)(cv_numlaps.value)) // final lap + if (player->laps == numlaps) // final lap S_StartSound(NULL, sfx_s3k68); - else if ((player->laps > 1) && (player->laps < (UINT8)(cv_numlaps.value))) // non-final lap + else if ((player->laps > 1) && (player->laps < numlaps)) // non-final lap S_StartSound(NULL, sfx_s221); - else if (player->laps > (UINT8)(cv_numlaps.value)) + else if (player->laps > numlaps) { // finished S_StartSound(NULL, sfx_s3k6a); @@ -1958,7 +1950,7 @@ static void K_HandleLapIncrement(player_t *player) } else { - if ((player->laps > (UINT8)(cv_numlaps.value)) && (player->position == 1)) + if ((player->laps > numlaps) && (player->position == 1)) { // opponent finished S_StartSound(NULL, sfx_s253); @@ -1966,12 +1958,34 @@ static void K_HandleLapIncrement(player_t *player) } // finished race exit setup - if (player->laps > (unsigned)cv_numlaps.value) + if (player->laps > numlaps) { P_DoPlayerExit(player); P_SetupSignExit(player); } + if (player->laps > player->latestlap) + { + if (player->laps > 1) + { + // save best lap for record attack + if (modeattacking && player == &players[consoleplayer]) + { + if (curlap < bestlap || bestlap == 0) + { + bestlap = curlap; + } + + curlap = 0; + } + + // Update power levels for this lap. + K_UpdatePowerLevels(player, player->laps, false); + } + + player->latestlap = player->laps; + } + thwompsactive = true; // Lap 2 effects lowestLap = P_FindLowestLap(); diff --git a/src/p_user.c b/src/p_user.c index ffc53012b..ec4d540c1 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -873,7 +873,7 @@ void P_RestoreMusic(player_t *player) #if 0 // Event - Final Lap // Still works for GME, but disabled for consistency - if ((gametyperules & GTR_CIRCUIT) && player->laps >= (UINT8)(cv_numlaps.value)) + if ((gametyperules & GTR_CIRCUIT) && player->laps >= numlaps) S_SpeedMusic(1.2f); #endif if (mapmusresume && cv_resume.value) @@ -3851,6 +3851,7 @@ void P_DoTimeOver(player_t *player) } player->pflags |= PF_NOCONTEST; + K_UpdatePowerLevelsOnFailure(player); if (G_GametypeUsesLives()) { diff --git a/src/sdl/CMakeLists.txt b/src/sdl/CMakeLists.txt index 65ff383ed..65550906e 100644 --- a/src/sdl/CMakeLists.txt +++ b/src/sdl/CMakeLists.txt @@ -79,11 +79,11 @@ if(${SDL2_FOUND}) endif() if(${CMAKE_SYSTEM} MATCHES Windows) - set_target_properties(SRB2SDL2 PROPERTIES OUTPUT_NAME srb2win) + set_target_properties(SRB2SDL2 PROPERTIES OUTPUT_NAME srb2kart) elseif(${CMAKE_SYSTEM} MATCHES Linux) - set_target_properties(SRB2SDL2 PROPERTIES OUTPUT_NAME lsdlsrb2) + set_target_properties(SRB2SDL2 PROPERTIES OUTPUT_NAME lsdlsrb2kart) else() - set_target_properties(SRB2SDL2 PROPERTIES OUTPUT_NAME srb2) + set_target_properties(SRB2SDL2 PROPERTIES OUTPUT_NAME srb2kart) endif() if(${CMAKE_SYSTEM} MATCHES Darwin) @@ -124,6 +124,14 @@ if(${SDL2_FOUND}) endif() endif() + if(${CMAKE_SYSTEM} MATCHES Windows AND ${CMAKE_C_COMPILER_ID} MATCHES "GNU" AND ${SRB2_SYSTEM_BITS} EQUAL 32) + target_link_libraries(SRB2SDL2 PRIVATE + "${CMAKE_CURRENT_SOURCE_DIR}/../../libs/drmingw/lib/win32/libexchndl.a" + "${CMAKE_CURRENT_SOURCE_DIR}/../../libs/drmingw/lib/win32/libmgwhelp.a" + ) + target_include_directories(SRB2SDL2 PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/../../libs/drmingw/include") + endif() + #target_link_libraries(SRB2SDL2 PRIVATE SRB2Core) if(${SRB2_USEASM}) @@ -168,24 +176,9 @@ if(${SDL2_FOUND}) target_compile_definitions(SRB2SDL2 PRIVATE -DDIRECTFULLSCREEN -DHAVE_SDL + -DHAVE_THREADS ) - ## strip debug symbols into separate file when using gcc. - ## to be consistent with Makefile, don't generate for OS X. - if((CMAKE_COMPILER_IS_GNUCC) AND NOT (${CMAKE_SYSTEM} MATCHES Darwin)) - if((${CMAKE_BUILD_TYPE} MATCHES Debug) OR (${CMAKE_BUILD_TYPE} MATCHES RelWithDebInfo)) - if(${CMAKE_BUILD_TYPE} MATCHES Debug) - set(OBJCOPY_ONLY_KEEP_DEBUG "--only-keep-debug") - endif() - message(STATUS "Will make separate debug symbols in *.debug") - add_custom_command(TARGET SRB2SDL2 POST_BUILD - COMMAND ${OBJCOPY} ${OBJCOPY_ONLY_KEEP_DEBUG} $ $.debug - COMMAND ${OBJCOPY} --strip-debug $ - COMMAND ${OBJCOPY} --add-gnu-debuglink=$.debug $ - ) - endif() - endif() - #### Installation #### if(${CMAKE_SYSTEM} MATCHES Darwin) install(TARGETS SRB2SDL2 diff --git a/src/y_inter.c b/src/y_inter.c index d612f0e75..d66a82dcb 100644 --- a/src/y_inter.c +++ b/src/y_inter.c @@ -214,7 +214,7 @@ static void Y_CalculateMatchData(UINT8 rankingsmode, void (*comparison)(INT32)) { INT32 i, j; boolean completed[MAXPLAYERS]; - INT32 numplayersingame = 0, numgriefers = 0; + INT32 numplayersingame = 0; // Initialize variables if (rankingsmode > 1) @@ -273,9 +273,6 @@ static void Y_CalculateMatchData(UINT8 rankingsmode, void (*comparison)(INT32)) { data.val[i] = UINT32_MAX; - if (nospectategrief[i] != -1) - numgriefers++; - if (!playeringame[i] || players[i].spectator) { data.increase[i] = INT16_MIN; @@ -324,10 +321,10 @@ static void Y_CalculateMatchData(UINT8 rankingsmode, void (*comparison)(INT32)) { if ((powertype == PWRLV_DISABLED) && !(players[i].pflags & PF_NOCONTEST) - && (data.pos[data.numplayers] < (numplayersingame + numgriefers))) + && (data.pos[data.numplayers] < (numplayersingame + spectateGriefed))) { // Online rank is handled further below in this file. - data.increase[i] = K_CalculateGPRankPoints(data.pos[data.numplayers], numplayersingame + numgriefers); + data.increase[i] = K_CalculateGPRankPoints(data.pos[data.numplayers], numplayersingame + spectateGriefed); players[i].score += data.increase[i]; } @@ -890,157 +887,6 @@ void Y_Ticker(void) } } -static void K_UpdatePowerLevels(void) -{ - INT32 i, j; - INT32 numplayersingame = 0, numgriefers = 0; - INT16 increment[MAXPLAYERS]; - - // Compare every single player against each other for power level increases. - // Every player you won against gives you more points, and vice versa. - // The amount of points won per match-up depends on the difference between the loser's power and the winner's power. - // See K_CalculatePowerLevelInc for more info. - - for (i = 0; i < MAXPLAYERS; i++) - { - increment[i] = 0; - - if (nospectategrief[i] != -1) - numgriefers++; - - if (!playeringame[i] || players[i].spectator) - continue; - - numplayersingame++; - } - - for (i = 0; i < numplayersingame; i++) - { - UINT16 yourpower = PWRLVRECORD_DEF; - UINT16 theirpower = PWRLVRECORD_DEF; - INT16 diff = 0; // Loser PWR.LV - Winner PWR.LV - INT16 inc = 0; // Total pt increment - UINT8 ipnum = data.num[i]; - UINT8 jpnum; - - CONS_Debug(DBG_GAMELOGIC, "Power Level Gain for player %d:\n", ipnum); - - if (clientpowerlevels[ipnum][powertype] == 0) // splitscreen guests don't record power level changes - continue; - yourpower = clientpowerlevels[ipnum][powertype]; - - CONS_Debug(DBG_GAMELOGIC, "Player %d's PWR.LV: %d\n", ipnum, yourpower); - - for (j = 0; j < numplayersingame; j++) - { - boolean won = false; - - jpnum = data.num[j]; - - if (i == j || ipnum == jpnum) // Same person - continue; - - CONS_Debug(DBG_GAMELOGIC, "Player %d VS Player %d:\n", ipnum, jpnum); - - if (data.val[i] == data.val[j]) // Tie -- neither get any points for this match up. - { - CONS_Debug(DBG_GAMELOGIC, "TIE, no change.\n"); - continue; - } - - if (clientpowerlevels[jpnum][powertype] == 0) // No power level (splitscreen guests, bots) - continue; - - theirpower = clientpowerlevels[jpnum][powertype]; - - CONS_Debug(DBG_GAMELOGIC, "Player %d's PWR.LV: %d\n", jpnum, theirpower); - - if ((gametyperules & GTR_CIRCUIT)) - { - if (data.val[i] < data.val[j]) - won = true; - } - else - { - if (data.val[i] > data.val[j]) - won = true; - } - - if (won) // This player won! - { - diff = theirpower - yourpower; - inc += K_CalculatePowerLevelInc(diff); - CONS_Debug(DBG_GAMELOGIC, "WON! Diff is %d, total increment is %d\n", diff, inc); - } - else // This player lost... - { - diff = yourpower - theirpower; - inc -= K_CalculatePowerLevelInc(diff); - CONS_Debug(DBG_GAMELOGIC, "LOST... Diff is %d, total increment is %d\n", diff, inc); - } - } - - if (numgriefers != 0) // Automatic win against quitters. - { - for (jpnum = 0; jpnum < MAXPLAYERS; jpnum++) - { - if (nospectategrief[jpnum] == -1) // Empty slot - continue; - - if (ipnum == jpnum) // Same person - continue; - - CONS_Debug(DBG_GAMELOGIC, "Player %d VS Player %d (griefer):\n", ipnum, jpnum); - - if (nospectategrief[jpnum] == 0) // No power level (splitscreen guests, bots) - continue; - - theirpower = nospectategrief[jpnum]; - - CONS_Debug(DBG_GAMELOGIC, "Player %d's PWR.LV: %d\n", jpnum, theirpower); - - diff = theirpower - yourpower; - inc += K_CalculatePowerLevelInc(diff); - CONS_Debug(DBG_GAMELOGIC, "AUTO-WON! Diff is %d, total increment is %d\n", diff, inc); - } - } - - if (inc == 0) - { - data.increase[ipnum] = INT16_MIN; - CONS_Debug(DBG_GAMELOGIC, "Total Result: No increment, no change.\n"); - continue; - } - - if (yourpower + inc > PWRLVRECORD_MAX) - inc -= ((yourpower + inc) - PWRLVRECORD_MAX); - if (yourpower + inc < PWRLVRECORD_MIN) - inc -= ((yourpower + inc) - PWRLVRECORD_MIN); - - CONS_Debug(DBG_GAMELOGIC, "Total Result: Increment of %d.\n", inc); - increment[ipnum] = inc; - } - - CONS_Debug(DBG_GAMELOGIC, "Setting final power levels...\n"); - for (i = 0; i < MAXPLAYERS; i++) - { - if (increment[i] == 0) - continue; - - data.increase[i] = increment[i]; - clientpowerlevels[i][powertype] += data.increase[i]; - - if (!demo.playback && i == consoleplayer) - { - CONS_Debug(DBG_GAMELOGIC, "Player %d is you! Saving...\n", i); - vspowerlevel[powertype] = clientpowerlevels[i][powertype]; - if (M_UpdateUnlockablesAndExtraEmblems()) - S_StartSound(NULL, sfx_ncitem); - G_SaveGameData(); - } - } -} - // // Y_DetermineIntermissionType // @@ -1121,7 +967,7 @@ void Y_StartIntermission(void) //if (dedicated) return; // This should always exist, but just in case... - if(!mapheaderinfo[prevmap]) + if (!mapheaderinfo[prevmap]) P_AllocMapHeader(prevmap); switch (intertype) @@ -1157,7 +1003,18 @@ void Y_StartIntermission(void) if (powertype != PWRLV_DISABLED) { - K_UpdatePowerLevels(); + for (i = 0; i < MAXPLAYERS; i++) + { + // Kind of a hack to do this here, + // but couldn't think of a better way. + data.increase[i] = K_FinalPowerIncrement( + &players[i], + clientpowerlevels[i][powertype], + clientPowerAdd[i] + ); + } + + K_CashInPowerLevels(); } //if (intertype == int_race || intertype == int_battle)