diff --git a/src/d_main.c b/src/d_main.c index 29a91686..5cf95f4b 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -1162,7 +1162,7 @@ void D_SRB2Main(void) if (s) // Check for NULL? { if (!W_VerifyNMUSlumps(s)) - G_SetGameModified(true); + G_SetGameModified(true, false); D_AddFile(s); } } @@ -1189,7 +1189,7 @@ void D_SRB2Main(void) else { if (!M_CheckParm("-server")) - G_SetGameModified(true); + G_SetGameModified(true, true); autostart = true; } } diff --git a/src/d_netcmd.c b/src/d_netcmd.c index a015b8e7..6df7718e 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -214,7 +214,7 @@ static CV_PossibleValue_t autobalance_cons_t[] = {{0, "MIN"}, {4, "MAX"}, {0, NU static CV_PossibleValue_t teamscramble_cons_t[] = {{0, "Off"}, {1, "Random"}, {2, "Points"}, {0, NULL}}; static CV_PossibleValue_t startingliveslimit_cons_t[] = {{1, "MIN"}, {99, "MAX"}, {0, NULL}}; -static CV_PossibleValue_t sleeping_cons_t[] = {{-1, "MIN"}, {1000/TICRATE, "MAX"}, {0, NULL}}; +static CV_PossibleValue_t sleeping_cons_t[] = {{0, "MIN"}, {1000/TICRATE, "MAX"}, {0, NULL}}; static CV_PossibleValue_t competitionboxes_cons_t[] = {{0, "Normal"}, {1, "Random"}, {2, "Teleports"}, {3, "None"}, {0, NULL}}; @@ -447,7 +447,7 @@ consvar_t cv_runscripts = {"runscripts", "Yes", 0, CV_YesNo, NULL, 0, NULL, NULL consvar_t cv_pause = {"pausepermission", "Server", CV_NETVAR, pause_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_mute = {"mute", "Off", CV_NETVAR|CV_CALL, CV_OnOff, Mute_OnChange, 0, NULL, NULL, 0, 0, NULL}; -consvar_t cv_sleep = {"cpusleep", "-1", CV_SAVE, sleeping_cons_t, NULL, -1, NULL, NULL, 0, 0, NULL}; +consvar_t cv_sleep = {"cpusleep", "1", CV_SAVE, sleeping_cons_t, NULL, -1, NULL, NULL, 0, 0, NULL}; INT16 gametype = GT_RACE; // SRB2kart boolean forceresetplayers = false; @@ -2209,10 +2209,12 @@ static void Command_Map_f(void) return; } - if (!(netgame || multiplayer) && (!modifiedgame || savemoddata)) + if (!(netgame || multiplayer) && !majormods) { if (COM_CheckParm("-force")) - G_SetGameModified(false); + { + G_SetGameModified(false, true); + } else { CONS_Printf(M_GetText("Sorry, level change disabled in single player.\n")); @@ -3791,7 +3793,7 @@ static void Command_RunSOC(void) if (!P_RunSOC(fn)) CONS_Printf(M_GetText("Could not find SOC.\n")); else - G_SetGameModified(multiplayer); + G_SetGameModified(multiplayer, false); return; } @@ -3845,7 +3847,7 @@ static void Got_RunSOCcmd(UINT8 **cp, INT32 playernum) } P_RunSOC(filename); - G_SetGameModified(true); + G_SetGameModified(true, false); } /** Adds a pwad at runtime. @@ -3882,7 +3884,7 @@ static void Command_Addfile(void) CONS_Printf(M_GetText("Only the server or a remote admin can use this.\n")); return; } - G_SetGameModified(multiplayer); + G_SetGameModified(multiplayer, false); } // Add file on your client directly if it is trivial, or you aren't in a netgame. @@ -4128,7 +4130,7 @@ static void Got_Addfilecmd(UINT8 **cp, INT32 playernum) return; } - G_SetGameModified(true); + G_SetGameModified(true, false); } static void Command_ListWADS_f(void) @@ -4485,7 +4487,7 @@ static void Ringslinger_OnChange(void) } if (cv_ringslinger.value) // Only if it's been turned on - G_SetGameModified(multiplayer); + G_SetGameModified(multiplayer, true); } static void Gravity_OnChange(void) @@ -4506,7 +4508,7 @@ static void Gravity_OnChange(void) #endif if (!CV_IsSetToDefault(&cv_gravity)) - G_SetGameModified(multiplayer); + G_SetGameModified(multiplayer, true); gravity = cv_gravity.value; } @@ -4902,7 +4904,7 @@ static void Fishcake_OnChange(void) // so don't make modifiedgame always on! if (cv_debug) { - G_SetGameModified(multiplayer); + G_SetGameModified(multiplayer, true); } else if (cv_debug != cv_fishcake.value) @@ -4918,12 +4920,14 @@ static void Fishcake_OnChange(void) */ static void Command_Isgamemodified_f(void) { - if (savemoddata) - CONS_Printf(M_GetText("modifiedgame is true, but you can save medal and record data in this mod.\n")); + if (majormods) + CONS_Printf("The game has been modified with major add-ons, so you cannot play Record Attack.\n"); + else if (savemoddata) + CONS_Printf("The game has been modified with an add-on with its own save data, so you can play Record Attack and earn medals.\n"); else if (modifiedgame) - CONS_Printf(M_GetText("modifiedgame is true, extras will not be unlocked\n")); + CONS_Printf("The game has been modified with only minor add-ons. You can play Record Attack, earn medals and unlock extras.\n"); else - CONS_Printf(M_GetText("modifiedgame is false, you can unlock extras\n")); + CONS_Printf("The game has not been modified. You can play Record Attack, earn medals and unlock extras.\n"); } static void Command_Cheats_f(void) diff --git a/src/d_netfil.c b/src/d_netfil.c index c7cfdbc1..99a05840 100644 --- a/src/d_netfil.c +++ b/src/d_netfil.c @@ -426,7 +426,7 @@ void CL_LoadServerFiles(void) else if (fileneeded[i].status == FS_FOUND) { P_AddWadFile(fileneeded[i].filename); - G_SetGameModified(true); + G_SetGameModified(true, false); fileneeded[i].status = FS_OPEN; } else if (fileneeded[i].status == FS_MD5SUMBAD) diff --git a/src/d_player.h b/src/d_player.h index 27fdef8d..5ce9066b 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -348,10 +348,11 @@ typedef enum k_wanted, // Timer for determining WANTED status, lowers when hitting people, prevents the game turning into Camp Lazlo k_yougotem, // "You Got Em" gfx when hitting someone as a karma player via a method that gets you back in the game instantly - // v1.0.2 vars + // v1.0.2+ vars k_itemblink, // Item flashing after roulette, prevents Hyudoro stealing AND serves as a mashing indicator k_itemblinkmode, // Type of flashing: 0 = white (normal), 1 = red (mashing), 2 = rainbow (enhanced items) k_getsparks, // Disable drift sparks at low speed, JUST enough to give acceleration the actual headstart above speed + k_jawztargetdelay, // Delay for Jawz target switching, to make it less twitchy NUMKARTSTUFF } kartstufftype_t; diff --git a/src/dehacked.c b/src/dehacked.c index b9e29bc4..b03530a4 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -21,6 +21,7 @@ #include "w_wad.h" #include "m_menu.h" #include "m_misc.h" +#include "filesrch.h" // for refreshdirmenu #include "f_finale.h" #include "dehacked.h" #include "st_stuff.h" @@ -79,8 +80,6 @@ static powertype_t get_power(const char *word); boolean deh_loaded = false; static int dbg_line; -static boolean gamedataadded = false; - #ifdef DELFILE typedef struct undehacked_s { @@ -602,6 +601,14 @@ done: Z_Free(s); } +static int freeslotusage[2][2] = {{0, 0}, {0, 0}}; // [S_, MT_][max, previous .wad's max] + +void DEH_UpdateMaxFreeslots(void) +{ + freeslotusage[0][1] = freeslotusage[0][0]; + freeslotusage[1][1] = freeslotusage[1][0]; +} + // TODO: Figure out how to do undolines for this.... // TODO: Warnings for running out of freeslots static void readfreeslots(MYFILE *f) @@ -664,6 +671,7 @@ static void readfreeslots(MYFILE *f) if (!FREE_STATES[i]) { FREE_STATES[i] = Z_Malloc(strlen(word)+1, PU_STATIC, NULL); strcpy(FREE_STATES[i],word); + freeslotusage[0][0]++; break; } } @@ -673,6 +681,7 @@ static void readfreeslots(MYFILE *f) if (!FREE_MOBJS[i]) { FREE_MOBJS[i] = Z_Malloc(strlen(word)+1, PU_STATIC, NULL); strcpy(FREE_MOBJS[i],word); + freeslotusage[1][0]++; break; } } @@ -3139,6 +3148,7 @@ static void readmaincfg(MYFILE *f) strlcpy(gamedatafilename, word2, sizeof (gamedatafilename)); strlwr(gamedatafilename); savemoddata = true; + majormods = false; // Also save a time attack folder filenamelen = strlen(gamedatafilename)-4; // Strip off the extension @@ -3151,7 +3161,7 @@ static void readmaincfg(MYFILE *f) // can't use sprintf since there is %u in savegamename strcatbf(savegamename, srb2home, PATHSEP); - gamedataadded = true; + refreshdirmenu |= REFRESHDIR_GAMEDATA; } else if (fastcmp(word, "RESETDATA")) { @@ -3382,8 +3392,6 @@ static void DEH_LoadDehackedFile(MYFILE *f, UINT16 wad) for (i = 0; i < NUMSFX; i++) savesfxnames[i] = S_sfx[i].name; - gamedataadded = false; - // it doesn't test the version of SRB2 and version of dehacked file dbg_line = -1; // start at -1 so the first line is 0. while (!myfeof(f)) @@ -3417,10 +3425,12 @@ static void DEH_LoadDehackedFile(MYFILE *f, UINT16 wad) if (fastcmp(word, "FREESLOT")) { readfreeslots(f); + // This is not a major mod. continue; } else if (fastcmp(word, "MAINCFG")) { + G_SetGameModified(multiplayer, true); readmaincfg(f); DEH_WriteUndoline(word, "", UNDO_HEADER); continue; @@ -3429,6 +3439,7 @@ static void DEH_LoadDehackedFile(MYFILE *f, UINT16 wad) { readwipes(f); DEH_WriteUndoline(word, "", UNDO_HEADER); + // This is not a major mod. continue; } word2 = strtok(NULL, " "); @@ -3449,6 +3460,7 @@ static void DEH_LoadDehackedFile(MYFILE *f, UINT16 wad) ignorelines(f); } DEH_WriteUndoline(word, word2, UNDO_HEADER); + // This is not a major mod. continue; } if (word2) @@ -3462,19 +3474,25 @@ static void DEH_LoadDehackedFile(MYFILE *f, UINT16 wad) // Read texture from spec file. readtexture(f, word2); DEH_WriteUndoline(word, word2, UNDO_HEADER); + // This is not a major mod. } else if (fastcmp(word, "PATCH")) { // Read patch from spec file. readpatch(f, word2, wad); DEH_WriteUndoline(word, word2, UNDO_HEADER); + // This is not a major mod. } else if (fastcmp(word, "THING") || fastcmp(word, "MOBJ") || fastcmp(word, "OBJECT")) { if (i == 0 && word2[0] != '0') // If word2 isn't a number i = get_mobjtype(word2); // find a thing by name if (i < NUMMOBJTYPES && i >= 0) + { + if (i < (MT_FIRSTFREESLOT+freeslotusage[1][1])) + G_SetGameModified(multiplayer, true); // affecting something earlier than the first freeslot allocated in this .wad? DENIED readthing(f, i); + } else { deh_warning("Thing %d out of range (0 - %d)", i, NUMMOBJTYPES-1); @@ -3485,6 +3503,7 @@ static void DEH_LoadDehackedFile(MYFILE *f, UINT16 wad) /* else if (fastcmp(word, "ANIMTEX")) { readAnimTex(f, i); + // This is not a major mod. }*/ else if (fastcmp(word, "LIGHT")) { @@ -3498,6 +3517,7 @@ static void DEH_LoadDehackedFile(MYFILE *f, UINT16 wad) ignorelines(f); } DEH_WriteUndoline(word, word2, UNDO_HEADER); + // This is not a major mod. #endif } else if (fastcmp(word, "SPRITE")) @@ -3513,6 +3533,7 @@ static void DEH_LoadDehackedFile(MYFILE *f, UINT16 wad) ignorelines(f); } DEH_WriteUndoline(word, word2, UNDO_HEADER); + // This is not a major mod. #endif } else if (fastcmp(word, "LEVEL")) @@ -3525,7 +3546,11 @@ static void DEH_LoadDehackedFile(MYFILE *f, UINT16 wad) i = M_MapNumber(word2[0], word2[1]); if (i > 0 && i <= NUMMAPS) + { + if (mapheaderinfo[i]) + G_SetGameModified(multiplayer, true); // only mark as a major mod if it replaces an already-existing mapheaderinfo readlevelheader(f, i); + } else { deh_warning("Level number %d out of range (1 - %d)", i, NUMMAPS); @@ -3543,13 +3568,18 @@ static void DEH_LoadDehackedFile(MYFILE *f, UINT16 wad) ignorelines(f); } DEH_WriteUndoline(word, word2, UNDO_HEADER); + //G_SetGameModified(multiplayer, true); -- might have to reconsider in a future update } else if (fastcmp(word, "FRAME") || fastcmp(word, "STATE")) { if (i == 0 && word2[0] != '0') // If word2 isn't a number i = get_state(word2); // find a state by name if (i < NUMSTATES && i >= 0) + { + if (i < (S_FIRSTFREESLOT+freeslotusage[0][1])) + G_SetGameModified(multiplayer, true); // affecting something earlier than the first freeslot allocated in this .wad? DENIED readframe(f, i); + } else { deh_warning("Frame %d out of range (0 - %d)", i, NUMSTATES-1); @@ -3578,6 +3608,7 @@ static void DEH_LoadDehackedFile(MYFILE *f, UINT16 wad) } else deh_warning("pointer (Frame %d) : missing ')'", i); + G_SetGameModified(multiplayer, true); }*/ else if (fastcmp(word, "SOUND")) { @@ -3591,6 +3622,7 @@ static void DEH_LoadDehackedFile(MYFILE *f, UINT16 wad) ignorelines(f); } DEH_WriteUndoline(word, word2, UNDO_HEADER); + // This is not a major mod. } /* else if (fastcmp(word, "SPRITE")) { @@ -3611,6 +3643,7 @@ static void DEH_LoadDehackedFile(MYFILE *f, UINT16 wad) } else deh_warning("Sprite %d doesn't exist",i); + // This is not a major mod. }*/ else if (fastcmp(word, "HUDITEM")) { @@ -3624,10 +3657,11 @@ static void DEH_LoadDehackedFile(MYFILE *f, UINT16 wad) ignorelines(f); } DEH_WriteUndoline(word, word2, UNDO_HEADER); + // This is not a major mod. } else if (fastcmp(word, "EMBLEM")) { - if (!gamedataadded) + if (!(refreshdirmenu & REFRESHDIR_GAMEDATA)) { deh_warning("You must define a custom gamedata to use \"%s\"", word); ignorelines(f); @@ -3647,7 +3681,7 @@ static void DEH_LoadDehackedFile(MYFILE *f, UINT16 wad) } else if (fastcmp(word, "EXTRAEMBLEM")) { - if (!gamedataadded) + if (!(refreshdirmenu & REFRESHDIR_GAMEDATA)) { deh_warning("You must define a custom gamedata to use \"%s\"", word); ignorelines(f); @@ -3667,7 +3701,7 @@ static void DEH_LoadDehackedFile(MYFILE *f, UINT16 wad) } else if (fastcmp(word, "UNLOCKABLE")) { - if (!gamedataadded) + if (!(refreshdirmenu & REFRESHDIR_GAMEDATA)) { deh_warning("You must define a custom gamedata to use \"%s\"", word); ignorelines(f); @@ -3683,7 +3717,7 @@ static void DEH_LoadDehackedFile(MYFILE *f, UINT16 wad) } else if (fastcmp(word, "CONDITIONSET")) { - if (!gamedataadded) + if (!(refreshdirmenu & REFRESHDIR_GAMEDATA)) { deh_warning("You must define a custom gamedata to use \"%s\"", word); ignorelines(f); @@ -3718,7 +3752,7 @@ static void DEH_LoadDehackedFile(MYFILE *f, UINT16 wad) { boolean clearall = (fastcmp(word2, "ALL")); - if (!gamedataadded) + if (!(refreshdirmenu & REFRESHDIR_GAMEDATA)) { deh_warning("You must define a custom gamedata to use \"%s\"", word); continue; @@ -3755,8 +3789,8 @@ static void DEH_LoadDehackedFile(MYFILE *f, UINT16 wad) deh_warning("No word in this line: %s", s); } // end while - if (gamedataadded) - G_LoadGameData(); + /*if (gamedataadded) -- REFRESHDIR_GAMEDATA murdered this + G_LoadGameData();*/ dbg_line = -1; if (deh_num_warning) @@ -8299,7 +8333,8 @@ static const char *const KARTSTUFF_LIST[] = { "ITEMBLINK", "ITEMBLINKMODE", - "GETSPARKS" + "GETSPARKS", + "JAWZTARGETDELAY" }; static const char *const HUDITEMS_LIST[] = { @@ -9356,6 +9391,7 @@ static inline int lib_freeslot(lua_State *L) CONS_Printf("State S_%s allocated.\n",word); FREE_STATES[i] = Z_Malloc(strlen(word)+1, PU_STATIC, NULL); strcpy(FREE_STATES[i],word); + freeslotusage[0][0]++; lua_pushinteger(L, i); r++; break; @@ -9371,6 +9407,7 @@ static inline int lib_freeslot(lua_State *L) CONS_Printf("MobjType MT_%s allocated.\n",word); FREE_MOBJS[i] = Z_Malloc(strlen(word)+1, PU_STATIC, NULL); strcpy(FREE_MOBJS[i],word); + freeslotusage[1][0]++; lua_pushinteger(L, i); r++; break; @@ -9740,6 +9777,9 @@ static inline int lib_getenum(lua_State *L) } else if (fastcmp(word,"modifiedgame")) { lua_pushboolean(L, modifiedgame && !savemoddata); return 1; + } else if (fastcmp(word,"majormods")) { + lua_pushboolean(L, majormods); + return 1; } else if (fastcmp(word,"menuactive")) { lua_pushboolean(L, menuactive); return 1; diff --git a/src/dehacked.h b/src/dehacked.h index 683fe7d9..0d6cc902 100644 --- a/src/dehacked.h +++ b/src/dehacked.h @@ -37,6 +37,8 @@ void DEH_UnloadDehackedWad(UINT16 wad); void DEH_LoadDehackedLump(lumpnum_t lumpnum); void DEH_LoadDehackedLumpPwad(UINT16 wad, UINT16 lump); +void DEH_UpdateMaxFreeslots(void); + void DEH_Check(void); fixed_t get_number(const char *word); diff --git a/src/doomstat.h b/src/doomstat.h index 6d710e28..9ae2726d 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -54,6 +54,7 @@ extern boolean gamecomplete; // Set if homebrew PWAD stuff has been added. extern boolean modifiedgame; +extern boolean majormods; extern UINT16 mainwads; extern boolean savemoddata; // This mod saves time/emblem data. extern boolean disableSpeedAdjust; // Don't alter the duration of player states if true @@ -280,6 +281,8 @@ typedef struct #define LF2_NIGHTSATTACK 8 ///< Show this map in NiGHTS mode menu #define LF2_NOVISITNEEDED 16 ///< Available in time attack/nights mode without visiting the level +#define LF2_EXISTSHACK 128 ///< Map lump exists; as noted, a single-bit hack that can be freely movable to other variables without concern. + // Save override #define SAVE_NEVER -1 #define SAVE_DEFAULT 0 diff --git a/src/filesrch.h b/src/filesrch.h index 4186271b..01a52848 100644 --- a/src/filesrch.h +++ b/src/filesrch.h @@ -88,7 +88,8 @@ typedef enum REFRESHDIR_WARNING = 4, REFRESHDIR_ERROR = 8, REFRESHDIR_NOTLOADED = 16, - REFRESHDIR_MAX = 32 + REFRESHDIR_MAX = 32, + REFRESHDIR_GAMEDATA = 64 } refreshdir_enum; void closefilemenu(boolean validsize); diff --git a/src/g_game.c b/src/g_game.c index ee004b64..f0d221ff 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -16,6 +16,7 @@ #include "d_main.h" #include "d_player.h" #include "f_finale.h" +#include "filesrch.h" // for refreshdirmenu #include "p_setup.h" #include "p_saveg.h" #include "i_system.h" @@ -86,7 +87,8 @@ INT16 lastmapsaved = 0; // Last map we auto-saved at boolean gamecomplete = false; UINT16 mainwads = 0; -boolean modifiedgame; // Set if homebrew PWAD stuff has been added. +boolean modifiedgame = false; // Set if homebrew PWAD stuff has been added. +boolean majormods = false; // Set if Lua/Gameplay SOC/replacement map has been added. boolean savemoddata = false; UINT8 paused; UINT8 modeattacking = ATTACKING_NONE; @@ -752,16 +754,21 @@ void G_SetNightsRecords(void) }*/ // for consistency among messages: this modifies the game and removes savemoddata. -void G_SetGameModified(boolean silent) +void G_SetGameModified(boolean silent, boolean major) { - if (modifiedgame && !savemoddata) + if ((majormods && modifiedgame) || !mainwads || (refreshdirmenu & REFRESHDIR_GAMEDATA)) // new gamedata amnesty? return; modifiedgame = true; - savemoddata = false; + + if (!major) + return; + + //savemoddata = false; -- there is literally no reason to do this anymore. + majormods = true; if (!silent) - CONS_Alert(CONS_NOTICE, M_GetText("Game must be restarted to record statistics.\n")); + CONS_Alert(CONS_NOTICE, M_GetText("Game must be restarted to play record attack.\n")); // If in record attack recording, cancel it. if (modeattacking) @@ -3942,7 +3949,6 @@ void G_LoadGameData(void) // Saves the main data file, which stores information such as emblems found, etc. void G_SaveGameData(boolean force) { - const boolean wasmodified = modifiedgame; size_t length; INT32 i, j; UINT8 btemp; @@ -3959,9 +3965,7 @@ void G_SaveGameData(boolean force) return; } - if (force) // SRB2Kart: for enabling unlocks online, even if the game is modified - modifiedgame = savemoddata; // L-let's just sort of... hack around the cheat protection, because I'm too worried about just removing it @@; - else if (modifiedgame && !savemoddata) + if (majormods && !force) { free(savebuffer); save_p = savebuffer = NULL; @@ -3974,7 +3978,7 @@ void G_SaveGameData(boolean force) WRITEUINT32(save_p, totalplaytime); WRITEUINT32(save_p, matchesplayed); - btemp = (UINT8)(savemoddata || modifiedgame); + btemp = (UINT8)(savemoddata); // what used to be here was profoundly dunderheaded WRITEUINT8(save_p, btemp); // TODO put another cipher on these things? meh, I don't care... @@ -4060,9 +4064,6 @@ void G_SaveGameData(boolean force) FIL_WriteFile(va(pandf, srb2home, gamedatafilename), savebuffer, length); free(savebuffer); save_p = savebuffer = NULL; - - if (force) // Eeeek, I'm sorry for my sins! - modifiedgame = wasmodified; } #define VERSIONSIZE 16 @@ -5150,22 +5151,20 @@ void G_GhostTicker(void) if (ziptic & EZT_HIT) { // Spawn hit poofs for killing things! UINT16 i, count = READUINT16(g->p), health; - UINT32 type; + //UINT32 type; fixed_t x,y,z; angle_t angle; mobj_t *poof; for (i = 0; i < count; i++) { g->p += 4; // reserved - type = READUINT32(g->p); + g->p += 4; // backwards compat., type used to be here health = READUINT16(g->p); x = READFIXED(g->p); y = READFIXED(g->p); z = READFIXED(g->p); angle = READANGLE(g->p); - if (!(mobjinfo[type].flags & MF_SHOOTABLE) - || !(mobjinfo[type].flags & (MF_ENEMY|MF_MONITOR)) - || health != 0 || i >= 4) // only spawn for the first 4 hits per frame, to prevent ghosts from splode-spamming too bad. + if (health != 0 || i >= 4) // only spawn for the first 4 hits per frame, to prevent ghosts from splode-spamming too bad. continue; poof = P_SpawnMobj(x, y, z, MT_GHOST); poof->angle = angle; @@ -5921,6 +5920,32 @@ void G_DoPlayDemo(char *defdemoname) return; } + // Skin not loaded? + if (!SetPlayerSkin(0, skin)) + { + snprintf(msg, 1024, M_GetText("%s features a character that is not currently loaded.\n"), pdemoname); + CONS_Alert(CONS_ERROR, "%s", msg); + M_StartMessage(msg, NULL, MM_NOTHING); + Z_Free(pdemoname); + Z_Free(demobuffer); + demoplayback = false; + titledemo = false; + return; + } + + // ...*map* not loaded? + if (!gamemap || (gamemap > NUMMAPS) || !mapheaderinfo[gamemap-1] || !(mapheaderinfo[gamemap-1]->menuflags & LF2_EXISTSHACK)) + { + snprintf(msg, 1024, M_GetText("%s features a course that is not currently loaded.\n"), pdemoname); + CONS_Alert(CONS_ERROR, "%s", msg); + M_StartMessage(msg, NULL, MM_NOTHING); + Z_Free(pdemoname); + Z_Free(demobuffer); + demoplayback = false; + titledemo = false; + return; + } + Z_Free(pdemoname); memset(&oldcmd,0,sizeof(oldcmd)); @@ -5952,9 +5977,6 @@ void G_DoPlayDemo(char *defdemoname) P_SetRandSeed(randseed); G_InitNew(false, G_BuildMapName(gamemap), true, true); // Doesn't matter whether you reset or not here, given changes to resetplayer. - // Set skin - SetPlayerSkin(0, skin); - // Set color for (i = 0; i < MAXSKINCOLORS; i++) if (!stricmp(KartColor_Names[i],color)) // SRB2kart @@ -6004,6 +6026,7 @@ void G_AddGhost(char *defdemoname) UINT8 *buffer,*p; mapthing_t *mthing; UINT16 count, ghostversion; + skin_t *ghskin = &skins[0]; name[16] = '\0'; skin[16] = '\0'; @@ -6149,6 +6172,21 @@ void G_AddGhost(char *defdemoname) return; } + for (i = 0; i < numskins; i++) + if (!stricmp(skins[i].name,skin)) + { + ghskin = &skins[i]; + break; + } + + if (i == numskins) + { + CONS_Alert(CONS_NOTICE, M_GetText("Failed to add ghost %s: Invalid character.\n"), pdemoname); + Z_Free(pdemoname); + Z_Free(buffer); + return; + } + gh = Z_Calloc(sizeof(demoghost), PU_LEVEL, NULL); gh->next = ghosts; gh->buffer = buffer; @@ -6194,14 +6232,7 @@ void G_AddGhost(char *defdemoname) gh->oldmo.z = gh->mo->z; // Set skin - gh->mo->skin = &skins[0]; - for (i = 0; i < numskins; i++) - if (!stricmp(skins[i].name,skin)) - { - gh->mo->skin = &skins[i]; - break; - } - gh->oldmo.skin = gh->mo->skin; + gh->mo->skin = gh->oldmo.skin = ghskin; // Set color gh->mo->color = ((skin_t*)gh->mo->skin)->prefcolor; diff --git a/src/g_game.h b/src/g_game.h index 6d11a4a0..fc7a4a4f 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -226,7 +226,7 @@ boolean G_GetRetryFlag(void); void G_LoadGameData(void); void G_LoadGameSettings(void); -void G_SetGameModified(boolean silent); +void G_SetGameModified(boolean silent, boolean major); void G_SetGamestate(gamestate_t newstate); diff --git a/src/info.c b/src/info.c index ea9eac9d..ccdfa3cf 100644 --- a/src/info.c +++ b/src/info.c @@ -15449,7 +15449,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_ORBINAUT_SHIELDDEAD, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound - 10*FRACUNIT, // speed + 4*FRACUNIT, // speed 16*FRACUNIT, // radius 32*FRACUNIT, // height 0, // display offset @@ -15530,7 +15530,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_JAWZ_DEAD1, // deathstate S_JAWZ_DEAD2, // xdeathstate sfx_None, // deathsound - 10*FRACUNIT, // speed + 4*FRACUNIT, // speed 16*FRACUNIT, // radius 32*FRACUNIT, // height 0, // display offset diff --git a/src/k_kart.c b/src/k_kart.c index f01f0d0b..37c70681 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -499,9 +499,9 @@ static INT32 K_KartItemOddsRace[NUMKARTRESULTS][10] = /*Sneaker*/ {20, 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, 9, 4, 2, 1, 0, 0, 0, 0, 0 }, // Banana - /*Eggman Monitor*/ { 0, 4, 3, 2, 0, 0, 0, 0, 0, 0 }, // Eggman Monitor - /*Orbinaut*/ { 0, 6, 5, 3, 2, 0, 0, 0, 0, 0 }, // Orbinaut + /*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 /*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 @@ -616,6 +616,32 @@ static INT32 K_KartGetItemOdds(UINT8 pos, SINT8 item, fixed_t mashed) UINT8 pingame = 0, pexiting = 0, pinvin = 0; SINT8 first = -1, second = -1; INT32 secondist = 0; + boolean itemenabled[NUMKARTRESULTS] = { + cv_sneaker.value, + cv_rocketsneaker.value, + cv_invincibility.value, + cv_banana.value, + cv_eggmanmonitor.value, + cv_orbinaut.value, + cv_jawz.value, + cv_mine.value, + cv_ballhog.value, + cv_selfpropelledbomb.value, + cv_grow.value, + cv_shrink.value, + cv_thundershield.value, + cv_hyudoro.value, + cv_kitchensink.value, + cv_triplesneaker.value, + cv_triplebanana.value, + cv_decabanana.value, + cv_tripleorbinaut.value, + cv_quadorbinaut.value, + cv_dualjawz.value + }; + + if (!itemenabled[item] && !modeattacking) + return 0; if (G_BattleGametype()) newodds = K_KartItemOddsBattle[item-1][pos]; @@ -626,21 +652,24 @@ static INT32 K_KartGetItemOdds(UINT8 pos, SINT8 item, fixed_t mashed) { if (!playeringame[i] || players[i].spectator) continue; - - pingame++; + if (!G_BattleGametype() || players[i].kartstuff[k_bumper]) + pingame++; if (players[i].exiting) pexiting++; if (players[i].mo) { - if (players[i].kartstuff[k_position] == 1 && first == -1) - first = i; - if (players[i].kartstuff[k_position] == 2 && second == -1) - second = i; if (players[i].kartstuff[k_itemtype] == KITEM_INVINCIBILITY || players[i].kartstuff[k_itemtype] == KITEM_GROW || players[i].kartstuff[k_invincibilitytimer] || players[i].kartstuff[k_growshrinktimer] > 0) pinvin++; + if (!G_BattleGametype()) + { + if (players[i].kartstuff[k_position] == 1 && first == -1) + first = i; + if (players[i].kartstuff[k_position] == 2 && second == -1) + second = i; + } } } @@ -650,120 +679,61 @@ static INT32 K_KartGetItemOdds(UINT8 pos, SINT8 item, fixed_t mashed) players[first].mo->y - players[second].mo->y), players[first].mo->z - players[second].mo->z) / mapobjectscale; if (franticitems) - secondist = (15*secondist/14); - if (pingame < 8 && !G_BattleGametype()) - secondist = ((28+(8-pingame))*secondist/28); + secondist = (15 * secondist) / 14; + secondist = ((28 + (8-pingame)) * secondist) / 28; } // POWERITEMODDS handles all of the "frantic item" related functionality, for all of our powerful items. // First, it multiplies it by 2 if franticitems is true; easy-peasy. // Next, it multiplies it again if it's in SPB mode and 2nd needs to apply pressure to 1st. - // Then, it multiplies it further if there's less than 8 players in game. - // This is done to make low player count races more fair & interesting. (1v1s are basically the same as franticitems false in a normal race) + // Then, it multiplies it further if there's less than 5 players in game. + // This is done to make low player count races more fair & interesting. (2P normal would be about halfway between 8P normal and 8P frantic) // Lastly, it *divides* it by your mashed value, which was determined in K_KartItemRoulette, to punish those who are impatient. - // The last two are very fractional and complicated, very sorry! #define POWERITEMODDS(odds) \ if (franticitems) \ - odds *= 2; \ - if (pingame < 8 && !G_BattleGametype()) \ - odds = FixedMul(odds*FRACUNIT, FRACUNIT+min((8-pingame)*(FRACUNIT/25), FRACUNIT))/FRACUNIT; \ + odds <<= 1; \ + odds = FixedMul(odds<> FRACBITS; \ if (mashed > 0) \ - odds = FixedDiv(odds*FRACUNIT, mashed+FRACUNIT)/FRACUNIT \ + odds = FixedDiv(odds<> FRACBITS \ switch (item) { - case KITEM_SNEAKER: - if ((!cv_sneaker.value) && (!modeattacking)) newodds = 0; - break; - case KITEM_ROCKETSNEAKER: - POWERITEMODDS(newodds); - if (!cv_rocketsneaker.value) newodds = 0; - break; case KITEM_INVINCIBILITY: - POWERITEMODDS(newodds); - if ((!cv_invincibility.value) || (pinvin >= 2)) newodds = 0; - break; - case KITEM_BANANA: - if (!cv_banana.value) newodds = 0; - break; - case KITEM_EGGMAN: - if (!cv_eggmanmonitor.value) newodds = 0; - break; - case KITEM_ORBINAUT: - if (!cv_orbinaut.value) newodds = 0; - break; + case KITEM_GROW: + if (pinvin >= max(1, (pingame+2) / 4)) + newodds = 0; + else + /* FALLTHRU */ + case KITEM_ROCKETSNEAKER: case KITEM_JAWZ: - POWERITEMODDS(newodds); - if (!cv_jawz.value) newodds = 0; - break; case KITEM_MINE: - POWERITEMODDS(newodds); - if (!cv_mine.value) newodds = 0; - break; case KITEM_BALLHOG: + case KITEM_THUNDERSHIELD: + case KRITEM_TRIPLESNEAKER: + case KRITEM_TRIPLEBANANA: + case KRITEM_TENFOLDBANANA: + case KRITEM_TRIPLEORBINAUT: + case KRITEM_QUADORBINAUT: + case KRITEM_DUALJAWZ: POWERITEMODDS(newodds); - if (!cv_ballhog.value) newodds = 0; break; case KITEM_SPB: //POWERITEMODDS(newodds); - if (((!cv_selfpropelledbomb.value) - || (indirectitemcooldown > 0) - || (pexiting > 0) - || (secondist/distvar < 3)) + if (((indirectitemcooldown > 0) || (pexiting > 0) || (secondist/distvar < 3)) && (pos != 9)) // Force SPB newodds = 0; - newodds *= min((secondist/distvar)-4, 3); - break; - case KITEM_GROW: - POWERITEMODDS(newodds); - if ((!cv_grow.value) || (pinvin >= 2)) newodds = 0; + else + newodds *= min((secondist/distvar)-4, 3); break; case KITEM_SHRINK: POWERITEMODDS(newodds); - if ((!cv_shrink.value) - || (indirectitemcooldown > 0) - || (pingame-1 <= pexiting)) newodds = 0; - break; - case KITEM_THUNDERSHIELD: - POWERITEMODDS(newodds); - if (!cv_thundershield.value) newodds = 0; - break; - case KITEM_HYUDORO: - if (!cv_hyudoro.value) newodds = 0; - break; - case KITEM_POGOSPRING: - if (!cv_pogospring.value) newodds = 0; - break; - case KITEM_KITCHENSINK: - newodds = 0; // Not obtained via normal means. - break; - case KRITEM_TRIPLESNEAKER: - POWERITEMODDS(newodds); - if (!cv_triplesneaker.value) newodds = 0; - break; - case KRITEM_TRIPLEBANANA: - POWERITEMODDS(newodds); - if (!cv_triplebanana.value) newodds = 0; - break; - case KRITEM_TENFOLDBANANA: - POWERITEMODDS(newodds); - if (!cv_decabanana.value) newodds = 0; - break; - case KRITEM_TRIPLEORBINAUT: - POWERITEMODDS(newodds); - if (!cv_tripleorbinaut.value) newodds = 0; - break; - case KRITEM_QUADORBINAUT: - POWERITEMODDS(newodds); - if (!cv_quadorbinaut.value) newodds = 0; - break; - case KRITEM_DUALJAWZ: - POWERITEMODDS(newodds); - if (!cv_dualjawz.value) newodds = 0; + if ((indirectitemcooldown > 0) || (pingame-1 <= pexiting)) + newodds = 0; break; default: break; } + #undef POWERITEMODDS return newodds; @@ -851,11 +821,12 @@ static INT32 K_FindUseodds(player_t *player, fixed_t mashed, INT32 pingame, INT3 if (oddsvalid[8]) SETUPDISTTABLE(8,1); if (franticitems) // Frantic items make the distances between everyone artifically higher, for crazier items - pdis = (15*pdis)/14; + pdis = (15 * pdis) / 14; + if (spbrush) // SPB Rush Mode: It's 2nd place's job to catch-up items and make 1st place's job hell - pdis = (3*pdis)/2; - if (pingame < 8) - pdis = ((28+(8-pingame))*pdis)/28; + pdis = (3 * pdis) / 2; + + pdis = ((28 + (8-pingame)) * pdis) / 28; if (pingame == 1 && oddsvalid[0]) // Record Attack, or just alone useodds = 0; @@ -1097,6 +1068,26 @@ void K_KartBouncing(mobj_t *mobj1, mobj_t *mobj2, boolean bounce, boolean solid) || (mobj2->player && mobj2->player->kartstuff[k_respawn])) return; + { // Don't bump if you're flashing + INT32 flash; + + flash = K_GetKartFlashing(mobj1->player); + if (mobj1->player && mobj1->player->powers[pw_flashing] > 0 && mobj1->player->powers[pw_flashing] < flash) + { + if (mobj1->player->powers[pw_flashing] < flash-1) + mobj1->player->powers[pw_flashing]++; + return; + } + + flash = K_GetKartFlashing(mobj2->player); + if (mobj2->player && mobj2->player->powers[pw_flashing] > 0 && mobj2->player->powers[pw_flashing] < flash) + { + if (mobj2->player->powers[pw_flashing] < flash-1) + mobj2->player->powers[pw_flashing]++; + return; + } + } + // Don't bump if you've recently bumped if (mobj1->player && mobj1->player->kartstuff[k_justbumped]) { @@ -1211,8 +1202,8 @@ void K_KartBouncing(mobj_t *mobj1, mobj_t *mobj2, boolean bounce, boolean solid) mobj1->player->kartstuff[k_justbumped] = bumptime; if (mobj1->player->kartstuff[k_spinouttimer]) { - mobj1->player->kartstuff[k_wipeoutslow] += wipeoutslowtime+1; - mobj1->player->kartstuff[k_spinouttimer] += wipeoutslowtime+1; + mobj1->player->kartstuff[k_wipeoutslow] = wipeoutslowtime+1; + mobj1->player->kartstuff[k_spinouttimer] = max(wipeoutslowtime+1, mobj1->player->kartstuff[k_spinouttimer]); } } @@ -1223,8 +1214,8 @@ void K_KartBouncing(mobj_t *mobj1, mobj_t *mobj2, boolean bounce, boolean solid) mobj2->player->kartstuff[k_justbumped] = bumptime; if (mobj2->player->kartstuff[k_spinouttimer]) { - mobj2->player->kartstuff[k_wipeoutslow] += wipeoutslowtime+1; - mobj2->player->kartstuff[k_spinouttimer] += wipeoutslowtime+1; + mobj2->player->kartstuff[k_wipeoutslow] = wipeoutslowtime+1; + mobj2->player->kartstuff[k_spinouttimer] = max(wipeoutslowtime+1, mobj2->player->kartstuff[k_spinouttimer]); } } } @@ -1248,9 +1239,8 @@ static UINT8 K_CheckOffroadCollide(mobj_t *mo, sector_t *sec) for (i = 2; i < 5; i++) { if ((sec2 && GETSECSPECIAL(sec2->special, 1) == i) - || (P_IsObjectOnRealGround(mo, sec) - && GETSECSPECIAL(sec->special, 1) == i)) - return i; + || (P_IsObjectOnRealGround(mo, sec) && GETSECSPECIAL(sec->special, 1) == i)) + return i-1; } return 0; @@ -1264,33 +1254,20 @@ static UINT8 K_CheckOffroadCollide(mobj_t *mo, sector_t *sec) */ static void K_UpdateOffroad(player_t *player) { - fixed_t kartweight = player->kartweight; fixed_t offroad; sector_t *nextsector = R_PointInSubsector( player->mo->x + player->mo->momx*2, player->mo->y + player->mo->momy*2)->sector; + UINT8 offroadstrength = K_CheckOffroadCollide(player->mo, nextsector); - fixed_t offroadstrength = 0; - - if (K_CheckOffroadCollide(player->mo, nextsector) == 2) // Weak Offroad - offroadstrength = 1; - else if (K_CheckOffroadCollide(player->mo, nextsector) == 3) // Mid Offroad - offroadstrength = 2; - else if (K_CheckOffroadCollide(player->mo, nextsector) == 4) // Strong Offroad - offroadstrength = 3; - - // If you are offroad, a timer starts. Depending on your weight value, the timer increments differently. - //if ((nextsector->special & 256) && nextsector->special != 768 - // && nextsector->special != 1024 && nextsector->special != 4864) + // If you are in offroad, a timer starts. if (offroadstrength) { if (K_CheckOffroadCollide(player->mo, player->mo->subsector->sector) && player->kartstuff[k_offroad] == 0) - player->kartstuff[k_offroad] = 16; + player->kartstuff[k_offroad] = (TICRATE/2); if (player->kartstuff[k_offroad] > 0) { - // 1872 is the magic number - 35 frames adds up to approximately 65536. 1872/4 = 468/3 = 156 - // A higher kart weight means you can stay offroad for longer without losing speed - offroad = (1872 + 5*156 - kartweight*156)*offroadstrength; + offroad = (offroadstrength << FRACBITS) / (TICRATE/2); //if (player->kartstuff[k_growshrinktimer] > 1) // grow slows down half as fast // offroad /= 2; @@ -1298,8 +1275,8 @@ static void K_UpdateOffroad(player_t *player) player->kartstuff[k_offroad] += offroad; } - if (player->kartstuff[k_offroad] > FRACUNIT*offroadstrength) - player->kartstuff[k_offroad] = FRACUNIT*offroadstrength; + if (player->kartstuff[k_offroad] > (offroadstrength << FRACBITS)) + player->kartstuff[k_offroad] = (offroadstrength << FRACBITS); } else player->kartstuff[k_offroad] = 0; @@ -1649,10 +1626,8 @@ static void K_GetKartBoostPower(player_t *player) && player->kartstuff[k_offroad] >= 0) boostpower = FixedDiv(boostpower, player->kartstuff[k_offroad] + FRACUNIT); - if (player->kartstuff[k_itemtype] == KITEM_KITCHENSINK) - boostpower = max((TICRATE/2), (5*TICRATE)-(player->kartstuff[k_bananadrag]/2))*boostpower/(5*TICRATE); - else if (player->kartstuff[k_bananadrag] > TICRATE) - boostpower = 4*boostpower/5; + if (player->kartstuff[k_bananadrag] > TICRATE) + boostpower = (4*boostpower)/5; // Banana drag/offroad dust if (boostpower < FRACUNIT @@ -2534,7 +2509,17 @@ static mobj_t *K_SpawnKartMissile(mobj_t *source, mobjtype_t type, angle_t an, I break; case MT_JAWZ: if (source && source->player) + { + INT32 lasttarg = source->player->kartstuff[k_lastjawztarget]; th->cvmem = source->player->skincolor; + if ((lasttarg >= 0 && lasttarg < MAXPLAYERS) + && playeringame[lasttarg] + && !players[lasttarg].spectator + && players[lasttarg].mo) + { + P_SetTarget(&th->tracer, players[lasttarg].mo); + } + } else th->cvmem = SKINCOLOR_KETCHUP; /* FALLTHRU */ @@ -3658,6 +3643,7 @@ static void K_MoveHeldObjects(player_t *player) case MT_JAWZ_SHIELD: { mobj_t *cur = player->mo->hnext; + fixed_t speed = ((8 - min(4, player->kartstuff[k_itemamount])) * cur->info->speed) / 7; player->kartstuff[k_bananadrag] = 0; // Just to make sure @@ -3675,10 +3661,10 @@ static void K_MoveHeldObjects(player_t *player) cur->color = player->skincolor; cur->angle -= ANGLE_90; - cur->angle += FixedAngle(cur->info->speed); + cur->angle += FixedAngle(speed); if (cur->extravalue1 < radius) - cur->extravalue1 += FixedMul(P_AproxDistance(cur->extravalue1, radius), FRACUNIT/12); + cur->extravalue1 += P_AproxDistance(cur->extravalue1, radius) / 12; if (cur->extravalue1 > radius) cur->extravalue1 = radius; @@ -3938,13 +3924,14 @@ player_t *K_FindJawzTarget(mobj_t *actor, player_t *source) if (thisang > ANGLE_180) thisang = InvAngle(thisang); - if (thisang > ANGLE_45) // Don't go for people who are behind you - continue; - // Jawz only go after the person directly ahead of you in race... sort of literally now! if (G_RaceGametype()) { - if (player->kartstuff[k_position] >= source->kartstuff[k_position]) // Don't pay attention to people behind you + // Don't go for people who are behind you + if (thisang > ANGLE_67h) + continue; + // Don't pay attention to people who aren't above your position + if (player->kartstuff[k_position] >= source->kartstuff[k_position]) continue; if ((best == -1) || (player->kartstuff[k_position] > best)) { @@ -3957,6 +3944,11 @@ player_t *K_FindJawzTarget(mobj_t *actor, player_t *source) fixed_t thisdist; fixed_t thisavg; + // Don't go for people who are behind you + if (thisang > ANGLE_45) + continue; + + // Don't pay attention to dead players if (player->kartstuff[k_bumper] <= 0) continue; @@ -4470,12 +4462,22 @@ void K_KartPlayerAfterThink(player_t *player) // Jawz reticule (seeking) if (player->kartstuff[k_itemtype] == KITEM_JAWZ && player->kartstuff[k_itemheld]) { - player_t *targ = K_FindJawzTarget(player->mo, player); + INT32 lasttarg = player->kartstuff[k_lastjawztarget]; + player_t *targ; mobj_t *ret; - if (!targ) + if (player->kartstuff[k_jawztargetdelay] && playeringame[lasttarg] && !players[lasttarg].spectator) + { + targ = &players[lasttarg]; + player->kartstuff[k_jawztargetdelay]--; + } + else + targ = K_FindJawzTarget(player->mo, player); + + if (!targ || !targ->mo || P_MobjWasRemoved(targ->mo)) { player->kartstuff[k_lastjawztarget] = -1; + player->kartstuff[k_jawztargetdelay] = 0; return; } @@ -4485,7 +4487,7 @@ void K_KartPlayerAfterThink(player_t *player) ret->tics = 1; ret->color = player->skincolor; - if (targ-players != player->kartstuff[k_lastjawztarget]) + if (targ-players != lasttarg) { if (P_IsLocalPlayer(player) || P_IsLocalPlayer(targ)) S_StartSound(NULL, sfx_s3k89); @@ -4493,11 +4495,13 @@ void K_KartPlayerAfterThink(player_t *player) S_StartSound(targ->mo, sfx_s3k89); player->kartstuff[k_lastjawztarget] = targ-players; + player->kartstuff[k_jawztargetdelay] = 5; } } else { player->kartstuff[k_lastjawztarget] = -1; + player->kartstuff[k_jawztargetdelay] = 0; } } @@ -4670,8 +4674,6 @@ static void K_KartDrift(player_t *player, boolean onground) player->kartstuff[k_driftend] = 0; } - - // Incease/decrease the drift value to continue drifting in that direction if (player->kartstuff[k_spinouttimer] == 0 && player->kartstuff[k_jmp] == 1 && onground && player->kartstuff[k_drift] != 0) { @@ -4701,7 +4703,7 @@ static void K_KartDrift(player_t *player, boolean onground) } // Disable drift-sparks until you're going fast enough - if (player->kartstuff[k_getsparks] == 0) + if (player->kartstuff[k_getsparks] == 0 || player->kartstuff[k_offroad]) driftadditive = 0; if (player->speed > minspeed*2) player->kartstuff[k_getsparks] = 1; @@ -5143,7 +5145,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground) for (moloop = 0; moloop < player->kartstuff[k_itemamount]; moloop++) { - newangle = FixedAngle(((360/player->kartstuff[k_itemamount])*moloop)*FRACUNIT) + ANGLE_90; + newangle = (player->mo->angle + ANGLE_157h) + FixedAngle(((360 / player->kartstuff[k_itemamount]) * moloop) << FRACBITS) + ANGLE_90; mo = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_ORBINAUT_SHIELD); if (!mo) { @@ -5184,7 +5186,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground) for (moloop = 0; moloop < player->kartstuff[k_itemamount]; moloop++) { - newangle = FixedAngle(((360/player->kartstuff[k_itemamount])*moloop)*FRACUNIT) + ANGLE_90; + newangle = (player->mo->angle + ANGLE_157h) + FixedAngle(((360 / player->kartstuff[k_itemamount]) * moloop) << FRACBITS) + ANGLE_90; mo = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_JAWZ_SHIELD); if (!mo) { @@ -5428,10 +5430,15 @@ void K_MoveKartPlayer(player_t *player, boolean onground) } // Friction - if (player->speed > 0 && cmd->forwardmove == 0 && player->mo->friction == 59392) - player->mo->friction += 4608; - if (player->speed > 0 && cmd->forwardmove < 0 && player->mo->friction == 59392) - player->mo->friction += 1608; + if (!player->kartstuff[k_offroad]) + { + if (player->speed > 0 && cmd->forwardmove == 0 && player->mo->friction == 59392) + player->mo->friction += 4608; + if (player->speed > 0 && cmd->forwardmove < 0 && player->mo->friction == 59392) + player->mo->friction += 1608; + } + + // Karma ice physics if (G_BattleGametype() && player->kartstuff[k_bumper] <= 0) { player->mo->friction += 1228; @@ -5451,11 +5458,14 @@ void K_MoveKartPlayer(player_t *player, boolean onground) if (player->mo->movefactor < 32) player->mo->movefactor = 32; } + + // Wipeout slowdown if (player->kartstuff[k_spinouttimer] && player->kartstuff[k_wipeoutslow]) { - player->mo->friction -= FixedMul(1228, player->kartstuff[k_offroad]); - if (player->kartstuff[k_wipeoutslow] == 1) + if (player->kartstuff[k_offroad]) player->mo->friction -= 4912; + if (player->kartstuff[k_wipeoutslow] == 1) + player->mo->friction -= 9824; } K_KartDrift(player, onground); @@ -7105,19 +7115,15 @@ void HU_DrawTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scorelines, I continue; //ignore them. if (netgame // don't draw it offline - && tab[i].num != serverplayer) + && tab[i].num != serverplayer) HU_drawPing(x + ((i < 8) ? -19 : rightoffset + 13), y+2, playerpingtable[tab[i].num], false); - if (scorelines > 8) - strlcpy(strtime, tab[i].name, 6); - else - STRBUFCPY(strtime, tab[i].name); + STRBUFCPY(strtime, tab[i].name); - V_DrawString(x + 20, y, - ((tab[i].num == whiteplayer) - ? hilicol|V_ALLOWLOWERCASE - : V_ALLOWLOWERCASE), - strtime); + if (scorelines > 8) + V_DrawThinString(x + 20, y, ((tab[i].num == whiteplayer) ? hilicol : 0)|V_ALLOWLOWERCASE|V_6WIDTHSPACE, strtime); + else + V_DrawString(x + 20, y, ((tab[i].num == whiteplayer) ? hilicol : 0)|V_ALLOWLOWERCASE, strtime); if (players[tab[i].num].mo->color) { @@ -7157,12 +7163,24 @@ void HU_DrawTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scorelines, I if (G_RaceGametype()) { #define timestring(time) va("%i'%02i\"%02i", G_TicsToMinutes(time, true), G_TicsToSeconds(time), G_TicsToCentiseconds(time)) - if (players[tab[i].num].exiting) - V_DrawRightAlignedString(x+rightoffset, y, hilicol, timestring(players[tab[i].num].realtime)); - else if (players[tab[i].num].pflags & PF_TIMEOVER) - V_DrawRightAlignedThinString(x+rightoffset, y-1, 0, "NO CONTEST."); - else if (circuitmap) - V_DrawRightAlignedString(x+rightoffset, y, 0, va("Lap %d", tab[i].count)); + if (scorelines > 8) + { + if (players[tab[i].num].exiting) + V_DrawRightAlignedThinString(x+rightoffset, y-1, hilicol|V_6WIDTHSPACE, timestring(players[tab[i].num].realtime)); + else if (players[tab[i].num].pflags & PF_TIMEOVER) + V_DrawRightAlignedThinString(x+rightoffset, y-1, V_6WIDTHSPACE, "NO CONTEST."); + else if (circuitmap) + V_DrawRightAlignedThinString(x+rightoffset, y-1, V_6WIDTHSPACE, va("Lap %d", tab[i].count)); + } + else + { + if (players[tab[i].num].exiting) + V_DrawRightAlignedString(x+rightoffset, y, hilicol, timestring(players[tab[i].num].realtime)); + else if (players[tab[i].num].pflags & PF_TIMEOVER) + V_DrawRightAlignedThinString(x+rightoffset, y-1, 0, "NO CONTEST."); + else if (circuitmap) + V_DrawRightAlignedString(x+rightoffset, y, 0, va("Lap %d", tab[i].count)); + } #undef timestring } else diff --git a/src/lua_hudlib.c b/src/lua_hudlib.c index ca952a00..cd8e0392 100644 --- a/src/lua_hudlib.c +++ b/src/lua_hudlib.c @@ -34,6 +34,8 @@ static UINT8 hud_enabled[(hud_MAX/8)+1]; static UINT8 hudAvailable; // hud hooks field +static UINT8 camnum = 1; + // must match enum hud in lua_hud.h static const char *const hud_disable_options[] = { "stagetitle", @@ -134,7 +136,8 @@ enum cameraf { camera_height, camera_momx, camera_momy, - camera_momz + camera_momz, + camera_pnum }; @@ -153,6 +156,7 @@ static const char *const camera_opt[] = { "momx", "momy", "momz", + "pnum", NULL}; static int lib_getHudInfo(lua_State *L) @@ -308,6 +312,9 @@ static int camera_get(lua_State *L) case camera_momz: lua_pushinteger(L, cam->momz); break; + case camera_pnum: + lua_pushinteger(L, camnum); + break; } return 1; } @@ -772,13 +779,25 @@ void LUAh_GameHUD(player_t *stplayr) LUA_PushUserdata(gL, stplayr, META_PLAYER); if (splitscreen > 2 && stplayr == &players[fourthdisplayplayer]) + { LUA_PushUserdata(gL, &camera4, META_CAMERA); + camnum = 4; + } else if (splitscreen > 1 && stplayr == &players[thirddisplayplayer]) + { LUA_PushUserdata(gL, &camera3, META_CAMERA); + camnum = 3; + } else if (splitscreen && stplayr == &players[secondarydisplayplayer]) + { LUA_PushUserdata(gL, &camera2, META_CAMERA); + camnum = 2; + } else + { LUA_PushUserdata(gL, &camera, META_CAMERA); + camnum = 1; + } lua_pushnil(gL); while (lua_next(gL, -5) != 0) { diff --git a/src/lua_script.c b/src/lua_script.c index 34a26052..1f87d33e 100644 --- a/src/lua_script.c +++ b/src/lua_script.c @@ -212,6 +212,9 @@ void LUA_LoadLump(UINT16 wad, UINT16 lump) LUA_LoadFile(&f, name); // actually load file! + // Okay, we've modified the game beyond the point of no return. + G_SetGameModified(multiplayer, true); + free(name); Z_Free(f.data); } diff --git a/src/m_cheat.c b/src/m_cheat.c index 38d8cc7a..2fc2e85c 100644 --- a/src/m_cheat.c +++ b/src/m_cheat.c @@ -121,7 +121,7 @@ static UINT8 cheatf_devmode(void) S_StartSound(0, sfx_itemup); // Just unlock all the things and turn on -debug and console devmode. - G_SetGameModified(false); + G_SetGameModified(false, false); // might need to revist the latter later for (i = 0; i < MAXUNLOCKABLES; i++) unlockables[i].unlocked = true; devparm = true; @@ -295,7 +295,7 @@ void Command_CheatNoClip_f(void) plyr->pflags ^= PF_NOCLIP; CONS_Printf(M_GetText("No Clipping %s\n"), plyr->pflags & PF_NOCLIP ? M_GetText("On") : M_GetText("Off")); - G_SetGameModified(multiplayer); + G_SetGameModified(multiplayer, true); } void Command_CheatGod_f(void) @@ -310,7 +310,7 @@ void Command_CheatGod_f(void) plyr->pflags ^= PF_GODMODE; CONS_Printf(M_GetText("Sissy Mode %s\n"), plyr->pflags & PF_GODMODE ? M_GetText("On") : M_GetText("Off")); - G_SetGameModified(multiplayer); + G_SetGameModified(multiplayer, true); } void Command_CheatNoTarget_f(void) @@ -325,7 +325,7 @@ void Command_CheatNoTarget_f(void) plyr->pflags ^= PF_INVIS; CONS_Printf(M_GetText("SEP Field %s\n"), plyr->pflags & PF_INVIS ? M_GetText("On") : M_GetText("Off")); - G_SetGameModified(multiplayer); + G_SetGameModified(multiplayer, true); } void Command_Scale_f(void) @@ -727,7 +727,7 @@ void Command_Devmode_f(void) return; } - G_SetGameModified(multiplayer); + G_SetGameModified(multiplayer, true); } /*void Command_Setrings_f(void) @@ -1267,7 +1267,7 @@ void Command_ObjectPlace_f(void) REQUIRE_SINGLEPLAYER; REQUIRE_NOULTIMATE; - G_SetGameModified(multiplayer); + G_SetGameModified(multiplayer, true); // Entering objectplace? if (!objectplacing) diff --git a/src/m_cond.c b/src/m_cond.c index 35eccd1c..b777e7d2 100644 --- a/src/m_cond.c +++ b/src/m_cond.c @@ -385,8 +385,7 @@ UINT8 M_UpdateUnlockablesAndExtraEmblems(boolean force) char cechoText[992] = ""; UINT8 cechoLines = 0; - if (modifiedgame && !savemoddata - && !force) // SRB2Kart: for enabling unlocks online in modified servers + if (majormods && !force) // SRB2Kart: for enabling unlocks online in modified servers return false; M_CheckUnlockConditions(); diff --git a/src/m_menu.c b/src/m_menu.c index f0831a17..d8b1c2d7 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -274,14 +274,13 @@ static menu_t SP_TimeAttackDef, SP_ReplayDef, SP_GuestReplayDef, SP_GhostDef; #ifndef NONET static void M_StartServerMenu(INT32 choice); static void M_ConnectMenu(INT32 choice); -#endif -static void M_StartOfflineServerMenu(INT32 choice); -static void M_StartServer(INT32 choice); -#ifndef NONET +static void M_ConnectMenuModChecks(INT32 choice); static void M_Refresh(INT32 choice); static void M_Connect(INT32 choice); static void M_ChooseRoom(INT32 choice); #endif +static void M_StartOfflineServerMenu(INT32 choice); +static void M_StartServer(INT32 choice); static void M_SetupMultiPlayer(INT32 choice); static void M_SetupMultiPlayer2(INT32 choice); static void M_SetupMultiPlayer3(INT32 choice); @@ -443,7 +442,7 @@ static CV_PossibleValue_t serversort_cons_t[] = { {5,"Gametype"}, {0,NULL} }; -consvar_t cv_serversort = {"serversort", "Ping", CV_HIDEN | CV_CALL, serversort_cons_t, M_SortServerList, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_serversort = {"serversort", "Ping", CV_CALL, serversort_cons_t, M_SortServerList, 0, NULL, NULL, 0, 0, NULL}; // autorecord demos for time attack static consvar_t cv_autorecord = {"autorecord", "Yes", 0, CV_YesNo, NULL, 0, NULL, NULL, 0, 0, NULL}; @@ -935,11 +934,11 @@ static menuitem_t MP_MainMenu[] = {IT_HEADER, NULL, "Join a game", NULL, 132-24}, #ifndef NONET - {IT_STRING|IT_CALL, NULL, "Internet server browser...",M_ConnectMenu, 142-24}, + {IT_STRING|IT_CALL, NULL, "Internet server browser...",M_ConnectMenuModChecks, 142-24}, {IT_STRING|IT_KEYHANDLER, NULL, "Specify IPv4 address:", M_HandleConnectIP, 150-24}, #else - {IT_GRAYEDOUT, NULL, "Internet server browser...",M_ConnectMenu, 142-24}, - {IT_GRAYEDOUT, NULL, "Specify IPv4 address:", M_HandleConnectIP, 150-24}, + {IT_GRAYEDOUT, NULL, "Internet server browser...",NULL, 142-24}, + {IT_GRAYEDOUT, NULL, "Specify IPv4 address:", NULL, 150-24}, #endif //{IT_HEADER, NULL, "Player setup", NULL, 80}, //{IT_STRING|IT_CALL, NULL, "Name, character, color...", M_SetupMultiPlayer, 90}, @@ -2739,10 +2738,10 @@ boolean M_Responder(event_t *ev) || (currentMenu->menuitems[itemOn].status & IT_TYPE)==IT_SUBMENU) && (currentMenu->menuitems[itemOn].status & IT_CALLTYPE)) { - if (((currentMenu->menuitems[itemOn].status & IT_CALLTYPE) & IT_CALL_NOTMODIFIED) && modifiedgame && !savemoddata) + if (((currentMenu->menuitems[itemOn].status & IT_CALLTYPE) & IT_CALL_NOTMODIFIED) && majormods) { S_StartSound(NULL, sfx_menu1); - M_StartMessage(M_GetText("This cannot be done with add-ons\nor in a cheated game.\n\n(Press a key)\n"), NULL, MM_NOTHING); + M_StartMessage(M_GetText("This cannot be done with complex add-ons\nor in a cheated game.\n\n(Press a key)\n"), NULL, MM_NOTHING); return true; } } @@ -4527,9 +4526,14 @@ static char *M_AddonsHeaderPath(void) #define CLEARNAME Z_Free(refreshdirname);\ refreshdirname = NULL +static boolean prevmajormods = false; + static void M_AddonsClearName(INT32 choice) { - CLEARNAME; + if (!majormods || prevmajormods) + { + CLEARNAME; + } M_StopMessage(choice); } @@ -4539,10 +4543,17 @@ static boolean M_AddonsRefresh(void) if ((refreshdirmenu & REFRESHDIR_NORMAL) && !preparefilemenu(true)) { UNEXIST; + if (refreshdirname) + { + CLEARNAME; + } return true; } - if (refreshdirmenu & REFRESHDIR_ADDFILE) + if (!majormods && prevmajormods) + prevmajormods = false; + + if ((refreshdirmenu & REFRESHDIR_ADDFILE) || (majormods && !prevmajormods)) { char *message = NULL; @@ -4550,7 +4561,7 @@ static boolean M_AddonsRefresh(void) { S_StartSound(NULL, sfx_s26d); if (refreshdirmenu & REFRESHDIR_MAX) - message = va("%c%s\x80\nMaximum number of add-ons reached.\nA file could not be loaded.\nIf you want to play with this add-on, restart the game to clear existing ones.\n\n(Press a key)\n", ('\x80' + (highlightflags>>V_CHARCOLORSHIFT)), refreshdirname); + message = va("%c%s\x80\nMaximum number of add-ons reached.\nA file could not be loaded.\nIf you wish to play with this add-on, restart the game to clear existing ones.\n\n(Press a key)\n", ('\x80' + (highlightflags>>V_CHARCOLORSHIFT)), refreshdirname); else message = va("%c%s\x80\nA file was not loaded.\nCheck the console log for more information.\n\n(Press a key)\n", ('\x80' + (highlightflags>>V_CHARCOLORSHIFT)), refreshdirname); } @@ -4559,6 +4570,12 @@ static boolean M_AddonsRefresh(void) S_StartSound(NULL, sfx_s224); message = va("%c%s\x80\nA file was loaded with %s.\nCheck the console log for more information.\n\n(Press a key)\n", ('\x80' + (highlightflags>>V_CHARCOLORSHIFT)), refreshdirname, ((refreshdirmenu & REFRESHDIR_ERROR) ? "errors" : "warnings")); } + else if (majormods && !prevmajormods) + { + S_StartSound(NULL, sfx_s221); + message = va("%c%s\x80\nGameplay has now been modified.\nIf you wish to play Record Attack mode, restart the game to clear existing add-ons.\n\n(Press a key)\n", ('\x80' + (highlightflags>>V_CHARCOLORSHIFT)), refreshdirname); + prevmajormods = majormods; + } if (message) { @@ -4709,7 +4726,7 @@ static void M_DrawAddons(void) V_DrawSmallScaledPatch(x, y + 4, (menusearch[0] ? 0 : V_TRANSLUCENT), addonsp[NUM_EXT+3]); x = BASEVIDWIDTH - x - 16; - V_DrawSmallScaledPatch(x, y + 4, ((!modifiedgame || savemoddata) ? 0 : V_TRANSLUCENT), addonsp[NUM_EXT+4]); + V_DrawSmallScaledPatch(x, y + 4, ((!majormods) ? 0 : V_TRANSLUCENT), addonsp[NUM_EXT+4]); if (modifiedgame) V_DrawSmallScaledPatch(x, y + 4, 0, addonsp[NUM_EXT+2]); @@ -5106,7 +5123,7 @@ static void M_GetAllEmeralds(INT32 choice) emeralds = ((EMERALD7)*2)-1; M_StartMessage(M_GetText("You now have all 7 emeralds.\nUse them wisely.\nWith great power comes great ring drain.\n"),NULL,MM_NOTHING); - G_SetGameModified(multiplayer); + G_SetGameModified(multiplayer, true); } static void M_DestroyRobotsResponse(INT32 ch) @@ -5117,7 +5134,7 @@ static void M_DestroyRobotsResponse(INT32 ch) // Destroy all robots P_DestroyRobots(); - G_SetGameModified(multiplayer); + G_SetGameModified(multiplayer, true); } static void M_DestroyRobots(INT32 choice) @@ -7384,6 +7401,20 @@ static void M_ConnectMenu(INT32 choice) M_Refresh(0); } +static void M_ConnectMenuModChecks(INT32 choice) +{ + (void)choice; + // okay never mind we want to COMMUNICATE to the player pre-emptively instead of letting them try and then get confused when it doesn't work + + if (modifiedgame) + { + M_StartMessage(M_GetText("Add-ons are currently loaded.\n\nYou will only be able to join a server if\nit has the same ones loaded in the same order, which may be unlikely.\n\nIf you wish to play on other servers,\nrestart the game to clear existing add-ons.\n\n(Press a key)\n"),M_ConnectMenu,MM_EVENTHANDLER); + return; + } + + M_ConnectMenu(-1); +} + static UINT32 roomIds[NUM_LIST_ROOMS]; static void M_RoomMenu(INT32 choice) diff --git a/src/p_enemy.c b/src/p_enemy.c index 8a6d7597..9d3aa951 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -8264,8 +8264,8 @@ void A_JawzChase(mobj_t *actor) if (actor->tracer) { - if (G_RaceGametype()) // Stop looking after first target in race - actor->extravalue1 = 1; + /*if (G_RaceGametype()) // Stop looking after first target in race + actor->extravalue1 = 1;*/ if (actor->tracer->health) { diff --git a/src/p_map.c b/src/p_map.c index c307e572..41e5a455 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -752,9 +752,7 @@ static boolean PIT_CheckThing(mobj_t *thing) // Player Damage P_DamageMobj(thing, tmthing, tmthing->target, 1); K_KartBouncing(thing, tmthing, false, false); - - if (tmthing->type == MT_ORBINAUT || tmthing->type == MT_JAWZ || tmthing->type == MT_JAWZ_DUD) - S_StartSound(thing, sfx_s3k7b); + S_StartSound(thing, sfx_s3k7b); // This Item Damage if (tmthing->eflags & MFE_VERTICALFLIP) @@ -1035,9 +1033,7 @@ static boolean PIT_CheckThing(mobj_t *thing) // Player Damage P_DamageMobj(tmthing, thing, thing->target, 1); K_KartBouncing(tmthing, thing, false, false); - - if (thing->type == MT_ORBINAUT || thing->type == MT_JAWZ || thing->type == MT_JAWZ_DUD) - S_StartSound(tmthing, sfx_s3k7b); + S_StartSound(tmthing, sfx_s3k7b); // Other Item Damage if (thing->eflags & MFE_VERTICALFLIP) @@ -3231,129 +3227,6 @@ isblocking: return false; // stop } -// -// P_IsClimbingValid -// -// Unlike P_DoClimbing, don't use when up against a one-sided linedef. -// -static boolean P_IsClimbingValid(player_t *player, angle_t angle) -{ - fixed_t platx, platy; - subsector_t *glidesector; - fixed_t floorz, ceilingz; - - platx = P_ReturnThrustX(player->mo, angle, player->mo->radius + FixedMul(8*FRACUNIT, player->mo->scale)); - platy = P_ReturnThrustY(player->mo, angle, player->mo->radius + FixedMul(8*FRACUNIT, player->mo->scale)); - - glidesector = R_PointInSubsector(player->mo->x + platx, player->mo->y + platy); - -#ifdef ESLOPE - floorz = glidesector->sector->f_slope ? P_GetZAt(glidesector->sector->f_slope, player->mo->x, player->mo->y) : glidesector->sector->floorheight; - ceilingz = glidesector->sector->c_slope ? P_GetZAt(glidesector->sector->c_slope, player->mo->x, player->mo->y) : glidesector->sector->ceilingheight; -#else - floorz = glidesector->sector->floorheight; - ceilingz = glidesector->sector->ceilingheight; -#endif - - if (glidesector->sector != player->mo->subsector->sector) - { - boolean floorclimb = false; - fixed_t topheight, bottomheight; - - if (glidesector->sector->ffloors) - { - ffloor_t *rover; - for (rover = glidesector->sector->ffloors; rover; rover = rover->next) - { - if (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_BLOCKPLAYER)) - continue; - - topheight = *rover->topheight; - bottomheight = *rover->bottomheight; - -#ifdef ESLOPE - if (*rover->t_slope) - topheight = P_GetZAt(*rover->t_slope, player->mo->x, player->mo->y); - if (*rover->b_slope) - bottomheight = P_GetZAt(*rover->b_slope, player->mo->x, player->mo->y); -#endif - - floorclimb = true; - - if (player->mo->eflags & MFE_VERTICALFLIP) - { - if ((topheight < player->mo->z + player->mo->height) && ((player->mo->z + player->mo->height + player->mo->momz) < topheight)) - { - floorclimb = true; - } - if (topheight < player->mo->z) // Waaaay below the ledge. - { - floorclimb = false; - } - if (bottomheight > player->mo->z + player->mo->height - FixedMul(16*FRACUNIT,player->mo->scale)) - { - floorclimb = false; - } - } - else - { - if ((bottomheight > player->mo->z) && ((player->mo->z - player->mo->momz) > bottomheight)) - { - floorclimb = true; - } - if (bottomheight > player->mo->z + player->mo->height) // Waaaay below the ledge. - { - floorclimb = false; - } - if (topheight < player->mo->z + FixedMul(16*FRACUNIT,player->mo->scale)) - { - floorclimb = false; - } - } - - if (floorclimb) - break; - } - } - - if (player->mo->eflags & MFE_VERTICALFLIP) - { - if ((floorz <= player->mo->z + player->mo->height) - && ((player->mo->z + player->mo->height - player->mo->momz) <= floorz)) - floorclimb = true; - - if ((floorz > player->mo->z) - && glidesector->sector->floorpic == skyflatnum) - return false; - - if ((player->mo->z + player->mo->height - FixedMul(16*FRACUNIT,player->mo->scale) > ceilingz) - || (player->mo->z + player->mo->height <= floorz)) - floorclimb = true; - } - else - { - if ((ceilingz >= player->mo->z) - && ((player->mo->z - player->mo->momz) >= ceilingz)) - floorclimb = true; - - if ((ceilingz < player->mo->z+player->mo->height) - && glidesector->sector->ceilingpic == skyflatnum) - return false; - - if ((player->mo->z + FixedMul(16*FRACUNIT,player->mo->scale) < ceilingz) - || (player->mo->z >= ceilingz)) - floorclimb = true; - } - - if (!floorclimb) - return false; - - return true; - } - - return false; -} - // // PTR_SlideTraverse // @@ -3407,117 +3280,7 @@ isblocking: P_ProcessSpecialSector(slidemo->player, slidemo->subsector->sector, li->polyobj->lines[0]->backsector); } - if (slidemo->player && (slidemo->player->pflags & PF_GLIDING || slidemo->player->climbing) - && slidemo->player->charability == CA_GLIDEANDCLIMB) - { - line_t *checkline = li; - sector_t *checksector; - ffloor_t *rover; - fixed_t topheight, bottomheight; - boolean fofline = false; - INT32 side = P_PointOnLineSide(slidemo->x, slidemo->y, li); - - if (!side && li->backsector) - checksector = li->backsector; - else - checksector = li->frontsector; - - if (checksector->ffloors) - { - for (rover = checksector->ffloors; rover; rover = rover->next) - { - if (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_BLOCKPLAYER) || (rover->flags & FF_BUSTUP)) - continue; - - topheight = *rover->topheight; - bottomheight = *rover->bottomheight; - -#ifdef ESLOPE - if (*rover->t_slope) - topheight = P_GetZAt(*rover->t_slope, slidemo->x, slidemo->y); - if (*rover->b_slope) - bottomheight = P_GetZAt(*rover->b_slope, slidemo->x, slidemo->y); -#endif - - if (topheight < slidemo->z) - continue; - - if (bottomheight > slidemo->z + slidemo->height) - continue; - - // Got this far, so I guess it's climbable. // TODO: Climbing check, also, better method to do this? - if (rover->master->flags & ML_TFERLINE) - { - size_t linenum = li-checksector->lines[0]; - checkline = rover->master->frontsector->lines[0] + linenum; - fofline = true; - } - - break; - } - } - - // see about climbing on the wall - if (!(checkline->flags & ML_NOCLIMB)) - { - boolean canclimb; - angle_t climbangle, climbline; - INT32 whichside = P_PointOnLineSide(slidemo->x, slidemo->y, li); - - climbangle = climbline = R_PointToAngle2(li->v1->x, li->v1->y, li->v2->x, li->v2->y); - - if (whichside) // on second side? - climbline += ANGLE_180; - - climbangle += (ANGLE_90 * (whichside ? -1 : 1)); - - canclimb = (li->backsector ? P_IsClimbingValid(slidemo->player, climbangle) : true); - - if (((!slidemo->player->climbing && abs((signed)(slidemo->angle - ANGLE_90 - climbline)) < ANGLE_45) - || (slidemo->player->climbing == 1 && abs((signed)(slidemo->angle - climbline)) < ANGLE_135)) - && canclimb) - { - slidemo->angle = climbangle; - if (!demoplayback || P_AnalogMove(slidemo->player)) - { - if (slidemo->player == &players[consoleplayer]) - localangle = slidemo->angle; - else if (slidemo->player == &players[secondarydisplayplayer]) - localangle2 = slidemo->angle; - else if (slidemo->player == &players[thirddisplayplayer]) - localangle3 = slidemo->angle; - else if (slidemo->player == &players[fourthdisplayplayer]) - localangle4 = slidemo->angle; - } - - if (!slidemo->player->climbing) - { - S_StartSound(slidemo->player->mo, sfx_s3k4a); - slidemo->player->climbing = 5; - } - - slidemo->player->pflags &= ~(PF_GLIDING|PF_SPINNING|PF_JUMPED|PF_THOKKED); - slidemo->player->glidetime = 0; - slidemo->player->secondjump = 0; - - if (slidemo->player->climbing > 1) - slidemo->momz = slidemo->momx = slidemo->momy = 0; - - if (fofline) - whichside = 0; - - if (!whichside) - { - slidemo->player->lastsidehit = checkline->sidenum[whichside]; - slidemo->player->lastlinehit = (INT16)(checkline - lines); - } - - P_Thrust(slidemo, slidemo->angle, FixedMul(5*FRACUNIT, slidemo->scale)); - } - } - } - - if (in->frac < bestslidefrac && (!slidemo->player || !slidemo->player->climbing)) + if (in->frac < bestslidefrac) { secondslidefrac = bestslidefrac; secondslideline = bestslideline; diff --git a/src/p_mobj.c b/src/p_mobj.c index f71ff209..746fc1af 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -1354,7 +1354,7 @@ fixed_t P_GetMobjGravity(mobj_t *mo) if (wasflip == !(mo->eflags & MFE_VERTICALFLIP)) // note!! == ! is not equivalent to != here - turns numeric into bool this way P_PlayerFlip(mo); if (mo->player->kartstuff[k_pogospring]) - gravityadd = FixedMul(gravityadd, 5*FRACUNIT/2); + gravityadd = (5*gravityadd)/2; } else { @@ -1404,11 +1404,12 @@ fixed_t P_GetMobjGravity(mobj_t *mo) break; case MT_BANANA: case MT_EGGMANITEM: + case MT_ORBINAUT: + case MT_JAWZ: + case MT_JAWZ_DUD: case MT_SSMINE: - gravityadd = FixedMul(gravityadd, 5*FRACUNIT/2); - break; case MT_SINK: - gravityadd = FixedMul(gravityadd, 5*FRACUNIT); // Double gravity + gravityadd = (5*gravityadd)/2; break; case MT_SIGN: gravityadd /= 8; @@ -3233,8 +3234,7 @@ boolean P_CanRunOnWater(player_t *player, ffloor_t *rover) #endif *rover->topheight; - if (!(player->pflags & PF_NIGHTSMODE) && !player->homing - && (((player->charability == CA_SWIM) || player->powers[pw_super] || player->charflags & SF_RUNONWATER) && player->mo->ceilingz-topheight >= player->mo->height) + if (((player->charflags & SF_RUNONWATER) && player->mo->ceilingz-topheight >= player->mo->height) && (rover->flags & FF_SWIMMABLE) && !(player->pflags & PF_SPINNING) && player->speed > FixedMul(player->runspeed, player->mo->scale) && !(player->pflags & PF_SLIDING) && abs(player->mo->z - topheight) < FixedMul(30*FRACUNIT, player->mo->scale)) diff --git a/src/p_setup.c b/src/p_setup.c index 49b22184..912791cf 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -234,7 +234,7 @@ static void P_ClearSingleMapHeaderInfo(INT16 i) DEH_WriteUndoline("LEVELFLAGS", va("%d", mapheaderinfo[num]->levelflags), UNDO_NONE); mapheaderinfo[num]->levelflags = 0; DEH_WriteUndoline("MENUFLAGS", va("%d", mapheaderinfo[num]->menuflags), UNDO_NONE); - mapheaderinfo[num]->menuflags = 0; + mapheaderinfo[num]->menuflags = (mainwads ? 0 : LF2_EXISTSHACK); // see p_setup.c - prevents replacing maps in addons with easier versions // TODO grades support for delfile (pfft yeah right) P_DeleteGrades(num); // SRB2Kart @@ -1120,7 +1120,7 @@ static inline void P_SpawnEmblems(void) static void P_SpawnSecretItems(boolean loademblems) { // Now let's spawn those funky emblem things! Tails 12-08-2002 - if (netgame || multiplayer || (modifiedgame && !savemoddata)) // No cheating!! + if (netgame || multiplayer || majormods) // No cheating!! return; if (loademblems) @@ -3272,7 +3272,7 @@ boolean P_SetupLevel(boolean skipprecip) nextmapoverride = 0; skipstats = false; - if (!(netgame || multiplayer) && (!modifiedgame || savemoddata)) + if (!(netgame || multiplayer) && !majormods) mapvisited[gamemap-1] |= MV_VISITED; levelloading = false; @@ -3455,6 +3455,14 @@ boolean P_AddWadFile(const char *wadfilename) continue; num = (INT16)M_MapNumber(name[3], name[4]); + // we want to record whether this map exists. if it doesn't have a header, we can assume it's not relephant + if (num <= NUMMAPS && mapheaderinfo[num-1]) + { + if (mapheaderinfo[num-1]->menuflags & LF2_EXISTSHACK) + G_SetGameModified(multiplayer, true); // oops, double-defined - no record attack privileges for you + mapheaderinfo[num-1]->menuflags |= LF2_EXISTSHACK; + } + //If you replaced the map you're on, end the level when done. if (num == gamemap) replacedcurrentmap = true; @@ -3481,6 +3489,8 @@ boolean P_AddWadFile(const char *wadfilename) SendNetXCmd(XD_EXITLEVEL, NULL, 0); } + refreshdirmenu &= ~REFRESHDIR_GAMEDATA; // Under usual circumstances we'd wait for REFRESHDIR_GAMEDATA to disappear the next frame, but it's a bit too dangerous for that... + return true; } diff --git a/src/p_spec.c b/src/p_spec.c index ca4967ce..24f56c43 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -1758,12 +1758,12 @@ boolean P_RunTriggerLinedef(line_t *triggerline, mobj_t *actor, sector_t *caller switch (specialtype) { - case 305: // continuous + /*case 305: // continuous case 306: // each time case 307: // once if (!(actor && actor->player && actor->player->charability == dist/10)) return false; - break; + break;*/ case 309: // continuous case 310: // each time // Only red team members can activate this. @@ -3864,14 +3864,6 @@ DoneSection2: P_InstaThrust(player->mo, player->mo->angle, linespeed); - /*if (GETSECSPECIAL(sector->special, 3) == 6 && (player->charability2 == CA2_SPINDASH)) // SRB2kart - { - if (!(player->pflags & PF_SPINNING)) - player->pflags |= PF_SPINNING; - - //P_SetPlayerMobjState(player->mo, S_PLAY_ATK1); - }*/ - player->kartstuff[k_dashpadcooldown] = TICRATE/3; player->kartstuff[k_drift] = 0; player->kartstuff[k_driftcharge] = 0; @@ -5781,7 +5773,7 @@ void P_SpawnSpecials(INT32 fromnetsave) lines[i].special = 0; continue; } - /*else -- commented out because irrelevant to kart + /*else -- commented out because irrelevant to kart. keeping here because we can use these flags for something else now { if ((players[consoleplayer].charability == CA_THOK && (lines[i].flags & ML_NOSONIC)) || (players[consoleplayer].charability == CA_FLY && (lines[i].flags & ML_NOTAILS)) @@ -7997,12 +7989,13 @@ static void P_SearchForDisableLinedefs(void) } else if ((lines[i].flags & ML_NETONLY) == ML_NETONLY) continue; // Net-only never triggers in single player - else if (players[consoleplayer].charability == CA_THOK && (lines[i].flags & ML_NOSONIC)) + // commented out because irrelevant to kart. keeping here because we can use these flags for something else now + /*else if (players[consoleplayer].charability == CA_THOK && (lines[i].flags & ML_NOSONIC)) continue; else if (players[consoleplayer].charability == CA_FLY && (lines[i].flags & ML_NOTAILS)) continue; else if (players[consoleplayer].charability == CA_GLIDEANDCLIMB && (lines[i].flags & ML_NOKNUX)) - continue; + continue;*/ // Disable any linedef specials with our tag. for (j = -1; (j = P_FindLineFromLineTag(&lines[i], j)) >= 0;) diff --git a/src/p_user.c b/src/p_user.c index d7423d80..ce411d2d 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -7323,74 +7323,6 @@ static void P_MovePlayer(player_t *player) if (CheckForBustableBlocks) P_CheckBustableBlocks(player); - // Special handling for - // gliding in 2D mode - if ((twodlevel || player->mo->flags2 & MF2_TWOD) && player->pflags & PF_GLIDING && player->charability == CA_GLIDEANDCLIMB - && !(player->mo->flags & MF_NOCLIP)) - { - msecnode_t *node; // only place it's being used in P_MovePlayer now - fixed_t oldx; - fixed_t oldy; - fixed_t floorz, ceilingz; - - oldx = player->mo->x; - oldy = player->mo->y; - - P_UnsetThingPosition(player->mo); - player->mo->x += player->mo->momx; - player->mo->y += player->mo->momy; - P_SetThingPosition(player->mo); - - for (node = player->mo->touching_sectorlist; node; node = node->m_sectorlist_next) - { - if (!node->m_sector) - break; - - if (node->m_sector->ffloors) - { - ffloor_t *rover; - fixed_t topheight, bottomheight; - - for (rover = node->m_sector->ffloors; rover; rover = rover->next) - { - if (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_BLOCKPLAYER)) - continue; - - topheight = P_GetFOFTopZ(player->mo, node->m_sector, rover, player->mo->x, player->mo->y, NULL); - bottomheight = P_GetFOFBottomZ(player->mo, node->m_sector, rover, player->mo->x, player->mo->y, NULL); - if (topheight > player->mo->z && bottomheight < player->mo->z) - { - P_ResetPlayer(player); - S_StartSound(player->mo, sfx_s3k4a); - player->climbing = 5; - player->mo->momx = player->mo->momy = player->mo->momz = 0; - break; - } - } - } - - floorz = P_GetFloorZ(player->mo, node->m_sector, player->mo->x, player->mo->y, NULL); - ceilingz = P_GetCeilingZ(player->mo, node->m_sector, player->mo->x, player->mo->y, NULL); - - if (player->mo->z+player->mo->height > ceilingz - && node->m_sector->ceilingpic == skyflatnum) - continue; - - if (floorz > player->mo->z || ceilingz < player->mo->z) - { - P_ResetPlayer(player); - S_StartSound(player->mo, sfx_s3k4a); - player->climbing = 5; - player->mo->momx = player->mo->momy = player->mo->momz = 0; - break; - } - } - P_UnsetThingPosition(player->mo); - player->mo->x = oldx; - player->mo->y = oldy; - P_SetThingPosition(player->mo); - } - // Check for a BOUNCY sector! if (CheckForBouncySector) P_CheckBouncySectors(player); diff --git a/src/r_things.c b/src/r_things.c index d6234d4b..135ae6a2 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -2635,7 +2635,7 @@ INT32 R_SkinAvailable(const char *name) } // network code calls this when a 'skin change' is received -void SetPlayerSkin(INT32 playernum, const char *skinname) +boolean SetPlayerSkin(INT32 playernum, const char *skinname) { INT32 i; player_t *player = &players[playernum]; @@ -2646,7 +2646,7 @@ void SetPlayerSkin(INT32 playernum, const char *skinname) if (stricmp(skins[i].name, skinname) == 0) { SetPlayerSkinByNum(playernum, i); - return; + return true; } } @@ -2656,6 +2656,7 @@ void SetPlayerSkin(INT32 playernum, const char *skinname) CONS_Alert(CONS_WARNING, M_GetText("Player %d (%s) skin '%s' not found\n"), playernum, player_names[playernum], skinname); SetPlayerSkinByNum(playernum, 0); + return false; } // Same as SetPlayerSkin, but uses the skin #. @@ -2894,27 +2895,27 @@ void R_AddSkins(UINT16 wadnum) #define FULLPROCESS(field) else if (!stricmp(stoken, #field)) skin->field = get_number(value); // character type identification FULLPROCESS(flags) - FULLPROCESS(ability) - FULLPROCESS(ability2) + //FULLPROCESS(ability) + //FULLPROCESS(ability2) - FULLPROCESS(thokitem) - FULLPROCESS(spinitem) - FULLPROCESS(revitem) + //FULLPROCESS(thokitem) + //FULLPROCESS(spinitem) + //FULLPROCESS(revitem) #undef FULLPROCESS #define GETSPEED(field) else if (!stricmp(stoken, #field)) skin->field = atoi(value)<field = atoi(value); +/*#define GETINT(field) else if (!stricmp(stoken, #field)) skin->field = atoi(value); GETINT(thrustfactor) GETINT(accelstart) GETINT(acceleration) -#undef GETINT +#undef GETINT*/ #define GETKARTSTAT(field) \ else if (!stricmp(stoken, #field)) \ @@ -2933,8 +2934,8 @@ void R_AddSkins(UINT16 wadnum) else if (!stricmp(stoken, "prefcolor")) skin->prefcolor = K_GetKartColorByName(value); - else if (!stricmp(stoken, "jumpfactor")) - skin->jumpfactor = FLOAT_TO_FIXED(atof(value)); + //else if (!stricmp(stoken, "jumpfactor")) + //skin->jumpfactor = FLOAT_TO_FIXED(atof(value)); else if (!stricmp(stoken, "highresscale")) skin->highresscale = FLOAT_TO_FIXED(atof(value)); else @@ -3044,6 +3045,9 @@ next_token: HWR_AddPlayerMD2(numskins); #endif + if (skin->flags & SF_RUNONWATER) // this is literally the only way a skin can be a major mod... this might be a bit heavy handed + G_SetGameModified(multiplayer, true); + numskins++; } return; diff --git a/src/r_things.h b/src/r_things.h index 53784415..01d8fc07 100644 --- a/src/r_things.h +++ b/src/r_things.h @@ -194,7 +194,7 @@ typedef struct drawnode_s extern INT32 numskins; extern skin_t skins[MAXSKINS]; -void SetPlayerSkin(INT32 playernum,const char *skinname); +boolean SetPlayerSkin(INT32 playernum,const char *skinname); void SetPlayerSkinByNum(INT32 playernum,INT32 skinnum); // Tails 03-16-2002 INT32 R_SkinAvailable(const char *name); void R_AddSkins(UINT16 wadnum); diff --git a/src/sdl/i_system.c b/src/sdl/i_system.c index 2154a070..f360072a 100644 --- a/src/sdl/i_system.c +++ b/src/sdl/i_system.c @@ -3018,7 +3018,7 @@ void I_StartupTimer(void) void I_Sleep(void) { - if (cv_sleep.value != -1) + if (cv_sleep.value > 0) SDL_Delay(cv_sleep.value); } diff --git a/src/sdl12/i_system.c b/src/sdl12/i_system.c index 0e5adbb4..d055a4ca 100644 --- a/src/sdl12/i_system.c +++ b/src/sdl12/i_system.c @@ -2914,7 +2914,7 @@ void I_StartupTimer(void) void I_Sleep(void) { #if !(defined (_arch_dreamcast) || defined (_XBOX)) - if (cv_sleep.value != -1) + if (cv_sleep.value > 0) SDL_Delay(cv_sleep.value); #endif } diff --git a/src/w_wad.c b/src/w_wad.c index 63bee97d..efa09ce4 100644 --- a/src/w_wad.c +++ b/src/w_wad.c @@ -34,6 +34,7 @@ #include "z_zone.h" #include "fastcmp.h" +#include "g_game.h" // G_LoadGameData #include "filesrch.h" #include "i_video.h" // rendermode @@ -799,6 +800,10 @@ UINT16 W_InitFile(const char *filename) break; } + if (refreshdirmenu & REFRESHDIR_GAMEDATA) + G_LoadGameData(); + DEH_UpdateMaxFreeslots(); + W_InvalidateLumpnumCache(); return wadfile->numlumps; } diff --git a/src/win32/win_sys.c b/src/win32/win_sys.c index 75aca68d..fa9d6d64 100644 --- a/src/win32/win_sys.c +++ b/src/win32/win_sys.c @@ -261,7 +261,7 @@ tic_t I_GetTime(void) void I_Sleep(void) { - if (cv_sleep.value != -1) + if (cv_sleep.value > 0) Sleep(cv_sleep.value); } diff --git a/src/win32ce/win_sys.c b/src/win32ce/win_sys.c index 3b6a4725..091171b5 100644 --- a/src/win32ce/win_sys.c +++ b/src/win32ce/win_sys.c @@ -265,7 +265,7 @@ tic_t I_GetTime(void) void I_Sleep(void) { - if (cv_sleep.value != -1) + if (cv_sleep.value > 0) Sleep(cv_sleep.value); } diff --git a/src/y_inter.c b/src/y_inter.c index 021519e3..095b4ad3 100644 --- a/src/y_inter.c +++ b/src/y_inter.c @@ -432,7 +432,7 @@ void Y_IntermissionDrawer(void) if (data.match.encore) V_DrawCenteredString(-4 + x + BASEVIDWIDTH/2, 12-8, hilicol, "ENCORE MODE"); - if (!gutter) + if (data.match.numplayers > NUMFORNEWCOLUMN) { V_DrawFill(x+156, 24, 1, 158, 0); V_DrawFill((x-3) - duptweak, 182, dupadjust-2, 1, 0); @@ -474,16 +474,12 @@ void Y_IntermissionDrawer(void) V_DrawScaledPatch(x+16, y-4, 0, W_CachePatchName(va("K_CHILI%d", cursorframe+1), PU_CACHE)); } - if (!gutter) - strlcpy(strtime, data.match.name[i], 6); - else - STRBUFCPY(strtime, data.match.name[i]); + STRBUFCPY(strtime, data.match.name[i]); - V_DrawString(x+36, y, - ((data.match.num[i] == whiteplayer) - ? hilicol|V_ALLOWLOWERCASE - : V_ALLOWLOWERCASE), - strtime); + if (data.match.numplayers > NUMFORNEWCOLUMN) + V_DrawThinString(x+36, y-1, ((data.match.num[i] == whiteplayer) ? hilicol : 0)|V_ALLOWLOWERCASE|V_6WIDTHSPACE, strtime); + else + V_DrawString(x+36, y, ((data.match.num[i] == whiteplayer) ? hilicol : 0)|V_ALLOWLOWERCASE, strtime); if (data.match.rankingsmode) { @@ -494,17 +490,23 @@ void Y_IntermissionDrawer(void) else snprintf(strtime, sizeof strtime, "(+ %d)", data.match.increase[data.match.num[i]]); - V_DrawRightAlignedString(x+120+gutter, y, 0, strtime); + if (data.match.numplayers > NUMFORNEWCOLUMN) + V_DrawRightAlignedThinString(x+135+gutter, y-1, V_6WIDTHSPACE, strtime); + else + V_DrawRightAlignedString(x+120+gutter, y, 0, strtime); } snprintf(strtime, sizeof strtime, "%d", data.match.val[i]); - V_DrawRightAlignedString(x+152+gutter, y, 0, strtime); + if (data.match.numplayers > NUMFORNEWCOLUMN) + V_DrawRightAlignedThinString(x+152+gutter, y-1, V_6WIDTHSPACE, strtime); + else + V_DrawRightAlignedString(x+152+gutter, y, 0, strtime); } else { if (data.match.val[i] == (UINT32_MAX-1)) - V_DrawRightAlignedThinString(x+152+gutter, y-1, 0, "NO CONTEST."); + V_DrawRightAlignedThinString(x+152+gutter, y-1, (data.match.numplayers > NUMFORNEWCOLUMN ? V_6WIDTHSPACE : 0), "NO CONTEST."); else { if (intertype == int_race) @@ -513,10 +515,18 @@ void Y_IntermissionDrawer(void) G_TicsToSeconds(data.match.val[i]), G_TicsToCentiseconds(data.match.val[i])); strtime[sizeof strtime - 1] = '\0'; - V_DrawRightAlignedString(x+152+gutter, y, 0, strtime); + if (data.match.numplayers > NUMFORNEWCOLUMN) + V_DrawRightAlignedThinString(x+152+gutter, y-1, V_6WIDTHSPACE, strtime); + else + V_DrawRightAlignedString(x+152+gutter, y, 0, strtime); } else - V_DrawRightAlignedString(x+152+gutter, y, 0, va("%i", data.match.val[i])); + { + if (data.match.numplayers > NUMFORNEWCOLUMN) + V_DrawRightAlignedThinString(x+152+gutter, y-1, V_6WIDTHSPACE, va("%i", data.match.val[i])); + else + V_DrawRightAlignedString(x+152+gutter, y, 0, va("%i", data.match.val[i])); + } } } @@ -786,7 +796,7 @@ void Y_StartIntermission(void) } case int_race: // (time-only race) { - if ((!modifiedgame || savemoddata) && !multiplayer && !demoplayback) // remove this once we have a proper time attack screen + if (!majormods && !multiplayer && !demoplayback) // remove this once we have a proper time attack screen { // Update visitation flags mapvisited[gamemap-1] |= MV_BEATEN;