diff --git a/src/d_netcmd.c b/src/d_netcmd.c index af64b79fb..cb2a6b385 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -3134,7 +3134,7 @@ static void Got_Mapcmd(UINT8 **cp, INT32 playernum) else if (gametype != lastgametype) D_GameTypeChanged(lastgametype); // emulate consvar_t behavior for gametype - if (!(gametyperules & GTR_CIRCUIT) && !bossinfo.boss) + if (!(gametyperules & GTR_ENCORE) && !bossinfo.boss) pencoremode = false; skipprecutscene = ((flags & (1<<2)) != 0); diff --git a/src/deh_soc.c b/src/deh_soc.c index 599367a9d..73fd6cc9b 100644 --- a/src/deh_soc.c +++ b/src/deh_soc.c @@ -35,6 +35,7 @@ #include "fastcmp.h" #include "lua_script.h" // Reluctantly included for LUA_EvalMath #include "d_clisrv.h" +#include "v_video.h" #ifdef HWRENDER #include "hardware/hw_light.h" @@ -925,6 +926,7 @@ void readgametype(MYFILE *f, char *gtname) INT32 newgtpointlimit = 0; INT32 newgttimelimit = 0; INT16 newgtrankingstype = -1; + INT32 newgtcolor = V_YELLOWMAP; int newgtinttype = 0; char gtconst[MAXLINELEN]; @@ -1008,6 +1010,13 @@ void readgametype(MYFILE *f, char *gtname) newgttol = tol; } } + // Menu Color + else if (fastcmp(word, "MENUCOLOR")) + { + INT32 color = (INT32)get_number(word2); + // Mask out other flags so they aren't passed into menu code. + newgtcolor = color & V_CHARCOLORMASK; // V_ + } // The SOC probably provided gametype rules as words, // instead of using the RULES keyword. // Like for example "NOSPECTATORSPAWN = TRUE". @@ -1051,6 +1060,7 @@ void readgametype(MYFILE *f, char *gtname) intermissiontypes[newgtidx] = newgtinttype; pointlimits[newgtidx] = newgtpointlimit; timelimits[newgtidx] = newgttimelimit; + gametypecolor[newgtidx] = newgtcolor; // Write the new gametype name. Gametype_Names[newgtidx] = Z_StrDup((const char *)gtname); diff --git a/src/deh_tables.c b/src/deh_tables.c index 20a90bbb7..a90c9dd74 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -296,38 +296,29 @@ const char *const ITEMFLAG_LIST[] = { }; const char *const GAMETYPERULE_LIST[] = { - "CAMPAIGN", - "RINGSLINGER", - "SPECTATORS", - "LIVES", - "TEAMS", - "FIRSTPERSON", - "POWERSTONES", - "TEAMFLAGS", - "FRIENDLY", - "SPECIALSTAGES", - "EMERALDTOKENS", - "EMERALDHUNT", - "RACE", - "TAG", + "CIRCUIT", + "RACEODDS", + "BOTS", + "RINGS", + "BUMPERS", + "BATTLEODDS", + "PAPERITEMS", + "WANTED", + "KARMA", + "ITEMARROWS", + "ITEMBREAKER", + "BATTLESTARTS", "POINTLIMIT", "TIMELIMIT", "OVERTIME", - "HURTMESSAGES", - "FRIENDLYFIRE", - "STARTCOUNTDOWN", - "HIDEFROZEN", - "BLINDFOLDED", - "RESPAWNDELAY", - "PITYSHIELD", - "DEATHPENALTY", - "NOSPECTATORSPAWN", - "DEATHMATCHSTARTS", - "SPAWNINVUL", - "SPAWNENEMIES", - "ALLOWEXIT", - "NOTITLECARD", - "CUTSCENES", + "TEAMS", + "NOTEAMS", + "TEAMSTARTS", + "\x01", + "LIVES", + "SPECIALBOTS", + "FREEROAM", + "ENCORE", NULL }; diff --git a/src/doomstat.h b/src/doomstat.h index 8a4c716a0..a148e2dd7 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -493,34 +493,37 @@ enum GameTypeRules { // Race rules GTR_CIRCUIT = 1, // Enables the finish line, laps, and the waypoint system. - GTR_BOTS = 1<<2, // Allows bots in this gametype. Combine with BotTiccmd hooks to make bots support your gametype. - GTR_RINGS = 1<<3, // Allow Rings in this gametype. + GTR_RACEODDS = 1<<2, // ItemOdds used in this mode are for racing. + GTR_BOTS = 1<<3, // Allows bots in this gametype. Combine with BotTiccmd hooks to make bots support your gametype. + GTR_RINGS = 1<<4, // Allow Rings in this gametype. // Battle gametype rules - GTR_BUMPERS = 1<<4, // Enables the bumper health system - GTR_PAPERITEMS = 1<<5, // Replaces item boxes with paper item spawners - GTR_WANTED = 1<<6, // Enables the wanted anti-camping system - GTR_KARMA = 1<<7, // Enables the Karma system if you're out of bumpers - GTR_ITEMARROWS = 1<<8, // Show item box arrows above players - GTR_ITEMBREAKER = 1<<9, // Enables the use of Item Breaker in this Gamemode - GTR_BATTLESTARTS = 1<<10, // Use Battle Mode start positions. + GTR_BUMPERS = 1<<5, // Enables the bumper health system + GTR_BATTLEODDS = 1<<6, // ItemOdds used in this mode are for battling. + GTR_PAPERITEMS = 1<<7, // Replaces item boxes with paper item spawners + GTR_WANTED = 1<<8, // Enables the wanted anti-camping system + GTR_KARMA = 1<<9, // Enables the Karma system if you're out of bumpers + GTR_ITEMARROWS = 1<<10, // Show item box arrows above players + GTR_ITEMBREAKER = 1<<11, // Enables the use of Item Breaker in this Gamemode + GTR_BATTLESTARTS = 1<<12, // Use Battle Mode start positions. - GTR_POINTLIMIT = 1<<11, // Reaching point limit ends the round - GTR_TIMELIMIT = 1<<12, // Reaching time limit ends the round - GTR_OVERTIME = 1<<13, // Allow overtime behavior + GTR_POINTLIMIT = 1<<13, // Reaching point limit ends the round + GTR_TIMELIMIT = 1<<14, // Reaching time limit ends the round + GTR_OVERTIME = 1<<15, // Allow overtime behavior // Custom gametype rules - GTR_TEAMS = 1<<14, // Teams are forced on - GTR_NOTEAMS = 1<<15, // Teams are forced off - GTR_TEAMSTARTS = 1<<16, // Use team-based start positions + GTR_TEAMS = 1<<16, // Teams are forced on + GTR_NOTEAMS = 1<<17, // Teams are forced off + GTR_TEAMSTARTS = 1<<18, // Use team-based start positions // Grand Prix rules - //Free = 1<<17, - GTR_LIVES = 1<<18, // Lives system, players are forced to spectate during Game Over. - GTR_SPECIALBOTS = 1<<19, // Bot difficulty gets stronger between rounds, and the rival system is enabled. + //Free = 1<<19, + GTR_LIVES = 1<<20, // Lives system, players are forced to spectate during Game Over. + GTR_SPECIALBOTS = 1<<21, // Bot difficulty gets stronger between rounds, and the rival system is enabled. // Misc - GTR_FREEROAM = 1<<20, // Disables Countdown timer and control lock at the start of levels. + GTR_FREEROAM = 1<<22, // Disables Countdown timer and control lock at the start of levels. + GTR_ENCORE = 1<<23, // Enable Encore mode. // free: to and including 1<<31 }; diff --git a/src/g_game.c b/src/g_game.c index 627368e92..867db0b1c 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -3150,9 +3150,9 @@ const char *Gametype_ConstantNames[NUMGAMETYPES] = UINT32 gametypedefaultrules[NUMGAMETYPES] = { // Race - GTR_CIRCUIT|GTR_BOTS|GTR_RINGS, + GTR_CIRCUIT|GTR_BOTS|GTR_RINGS|GTR_ENCORE|GTR_RACEODDS, // Battle - GTR_BUMPERS|GTR_RINGS|GTR_KARMA|GTR_WANTED|GTR_ITEMARROWS|GTR_ITEMBREAKER|GTR_BATTLESTARTS|GTR_TIMELIMIT + GTR_BUMPERS|GTR_RINGS|GTR_KARMA|GTR_WANTED|GTR_ITEMARROWS|GTR_ITEMBREAKER|GTR_BATTLESTARTS|GTR_TIMELIMIT|GTR_BATTLEODDS }; // @@ -3277,6 +3277,12 @@ void G_UpdateGametypeSelections(void) gametype_cons_t[NUMGAMETYPES].strvalue = NULL; } +INT32 gametypecolor[NUMGAMETYPES] = +{ + V_SKYMAP, + V_REDMAP, +}; + // Gametype rankings INT16 gametyperankings[NUMGAMETYPES] = { @@ -3513,13 +3519,10 @@ UINT8 G_GetGametypeColor(INT16 gt) || gamestate == GS_TIMEATTACK) return orangemap[0]; - if (gt == GT_BATTLE) - return redmap[0]; + if (gametypecolor[gt]) + return *V_GetStringColormap(gametypecolor[gt]); - if (gt == GT_RACE) - return skymap[0]; - - return 255; // FALLBACK + return yellowmap[0]; // FALLBACK } /** Get the typeoflevel flag needed to indicate support of a gametype. diff --git a/src/g_game.h b/src/g_game.h index 82dc9683e..51c27fb84 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -206,12 +206,14 @@ void G_SaveGameOver(UINT32 slot, boolean modifylives); extern UINT32 gametypedefaultrules[NUMGAMETYPES]; extern UINT32 gametypetol[NUMGAMETYPES]; +extern INT32 gametypecolor[NUMGAMETYPES]; extern INT16 gametyperankings[NUMGAMETYPES]; void G_SetGametype(INT16 gametype); INT16 G_AddGametype(UINT32 rules); void G_AddGametypeConstant(INT16 gtype, const char *newgtconst); void G_UpdateGametypeSelections(void); +void G_SetGametypeColor(INT16 gtype,INT32 color); void G_AddTOL(UINT32 newtol, const char *tolname); void G_AddGametypeTOL(INT16 gtype, UINT32 newtol); INT32 G_GetGametypeByName(const char *gametypestr); diff --git a/src/hu_stuff.c b/src/hu_stuff.c index e6ceb1640..bb0fb3661 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -2465,7 +2465,12 @@ static void HU_DrawRankings(void) else if (modeattacking) hilicol = V_ORANGEMAP; else - hilicol = ((gametype == GT_RACE) ? V_SKYMAP : V_REDMAP); + { + if (gametypecolor[gametype]) + hilicol = gametypecolor[gametype]; + else + hilicol = V_YELLOWMAP; + } // draw the current gametype in the lower right if (modeattacking) diff --git a/src/k_hud.c b/src/k_hud.c index 32dcefd46..b87ad46d3 100644 --- a/src/k_hud.c +++ b/src/k_hud.c @@ -4475,7 +4475,7 @@ void K_drawKartHUD(void) } // Race overlays - if (gametype == GT_RACE && !freecam) + if ((gametyperules & GTR_CIRCUIT) && !freecam) { if (stplyr->exiting) K_drawKartFinish(); diff --git a/src/k_kart.c b/src/k_kart.c index cae1ca055..a111af58c 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -608,16 +608,20 @@ INT32 K_KartGetItemOdds( */ (void)bot; - if (gametype == GT_BATTLE) + if (gametyperules & GTR_BATTLEODDS) { I_Assert(pos < 2); // DO NOT allow positions past the bounds of the table newodds = K_KartItemOddsBattle[item-1][pos]; } - else + else if (gametyperules & GTR_RACEODDS) { I_Assert(pos < 8); // Ditto newodds = K_KartItemOddsRace[item-1][pos]; } + else + { + newodds = 0; + } // Base multiplication to ALL item odds to simulate fractional precision newodds *= 4; @@ -825,7 +829,7 @@ INT32 K_KartGetLegacyItemOdds(UINT8 pos, SINT8 item, fixed_t mashed, boolean spb if (!KartItemCVars[item-1]->value && !modeattacking) return 0; - if (gametype == GT_BATTLE) + if (gametyperules & GTR_BATTLEODDS) newodds = K_KartItemOddsBattle[item-1][pos]; else newodds = K_KartItemOddsRace[item-1][pos]; @@ -1000,7 +1004,7 @@ UINT8 K_FindUseodds(player_t *player, fixed_t mashed, UINT32 pdis, UINT8 bestbum UINT8 j; boolean available = false; - if (gametype == GT_BATTLE && i > 1) + if ((gametyperules & GTR_BATTLEODDS) && i > 1) { oddsvalid[i] = false; break; @@ -1028,7 +1032,7 @@ UINT8 K_FindUseodds(player_t *player, fixed_t mashed, UINT32 pdis, UINT8 bestbum for (i = num; i; --i) \ disttable[distlen++] = odds; - if (gametype == GT_BATTLE) // Battle Mode + if (gametyperules & GTR_BATTLEODDS) // Battle Mode { if (player->roulettetype == 1 && oddsvalid[1] == true) { @@ -1046,7 +1050,7 @@ UINT8 K_FindUseodds(player_t *player, fixed_t mashed, UINT32 pdis, UINT8 bestbum } } } - else + else if (gametyperules & GTR_RACEODDS) { SETUPDISTTABLE(0,1); SETUPDISTTABLE(1,1); @@ -1104,7 +1108,7 @@ INT32 K_FindLegacyUseodds(player_t *player, fixed_t mashed, INT32 pingame, INT32 INT32 j; boolean available = false; - if (gametype == GT_BATTLE && i > 1) + if ((gametyperules & GTR_BATTLEODDS) && i > 1) { oddsvalid[i] = false; break; @@ -1239,7 +1243,7 @@ INT32 K_FindLegacyUseodds(player_t *player, fixed_t mashed, INT32 pingame, INT32 for (i = num; i; --i) \ disttable[distlen++] = odds; - if (gametype == GT_BATTLE) // Battle Mode + if (gametyperules & GTR_BATTLEODDS) // Battle Mode { if (player->roulettetype == 1 && oddsvalid[1] == true) { @@ -1331,7 +1335,7 @@ INT32 K_GetRollingRouletteItem(player_t *player) roulette_size = 0; - if (gametype == GT_BATTLE) + if (gametyperules & GTR_BATTLEODDS) { odds_row = K_KartItemOddsBattle[0]; odds_row_size = sizeof K_KartItemOddsBattle[0]; @@ -1495,12 +1499,28 @@ static void K_KartItemRoulette(player_t *player, ticcmd_t *cmd) } // SPECIAL CASE No. 3: - // Record Attack / alone mashing behavior - if (modeattacking || pingame == 1) + // This Gametype never specified an odds type. Roll something random please! + if (!(gametyperules & GTR_RACEODDS) && !(gametyperules & GTR_BATTLEODDS)) { - if (gametype == GT_RACE) + SINT8 itemroll = P_RandomRange(KITEM_SNEAKER, NUMKARTITEMS - 1); + + K_KartGetItemResult(player, itemroll); + player->karthud[khud_itemblink] = TICRATE; + player->karthud[khud_itemblinkmode] = 0; + player->itemroulette = 0; + player->roulettetype = 0; + if (P_IsDisplayPlayer(player)) + S_StartSound(NULL, sfx_itrolf); + return; + } + + // SPECIAL CASE No. 4: + // Record Attack / alone mashing behavior + if ((modeattacking || pingame == 1) && ((gametyperules & GTR_RACEODDS) || (gametyperules & GTR_BATTLEODDS))) + { + if ((gametyperules & GTR_RACEODDS)) { - if (mashed && (modeattacking || (cv_superring.value && (K_RingsActive() == true)))) // ANY mashed value? You get rings. + if (mashed && ((K_RingsActive() == true) && (modeattacking || cv_superring.value))) // ANY mashed value? You get rings. { K_KartGetItemResult(player, KITEM_SUPERRING); player->karthud[khud_itemblinkmode] = 1; @@ -1518,7 +1538,7 @@ static void K_KartItemRoulette(player_t *player, ticcmd_t *cmd) S_StartSound(NULL, sfx_itrolf); } } - else if (gametype == GT_BATTLE) + else if (gametyperules & GTR_BATTLEODDS) { if (mashed && (bossinfo.boss || cv_banana.value) && !itembreaker) // ANY mashed value? You get a banana. { @@ -1534,16 +1554,6 @@ static void K_KartItemRoulette(player_t *player, ticcmd_t *cmd) if (P_IsDisplayPlayer(player)) S_StartSound(NULL, sfx_itrolf); } - else - { - if (modeattacking || cv_tripleorbinaut.value) // Waited patiently? You get Orbinaut x3! - K_KartGetItemResult(player, KRITEM_TRIPLEORBINAUT); - else // Default to sad if nothing's enabled... - K_KartGetItemResult(player, KITEM_SAD); - player->karthud[khud_itemblinkmode] = 0; - if (P_IsDisplayPlayer(player)) - S_StartSound(NULL, sfx_itrolf); - } } player->karthud[khud_itemblink] = TICRATE; @@ -1552,7 +1562,7 @@ static void K_KartItemRoulette(player_t *player, ticcmd_t *cmd) return; } - // SPECIAL CASE No. 4: + // SPECIAL CASE No. 5: // Being in ring debt occasionally forces Super Ring on you if you mashed if ((K_RingsActive() == true) && mashed && player->rings < 0 && cv_superring.value) { @@ -1572,7 +1582,7 @@ static void K_KartItemRoulette(player_t *player, ticcmd_t *cmd) if (!(numbosswaypoints > 0)) { - // SPECIAL CASE No. 5: + // SPECIAL CASE No. 6: // Force SPB onto 2nd if they get too far behind if ((gametyperules & GTR_CIRCUIT) && player->position == 2 && pdis > SPBFORCEDIST && spbplace == -1 && !indirectitemcooldown && !dontforcespb @@ -6523,7 +6533,7 @@ void K_KartPlayerHUDUpdate(player_t *player) if (player->karthud[khud_cardanimation] < 0) player->karthud[khud_cardanimation] = 0; } - else if (gametype == GT_RACE && player->exiting) + else if ((gametyperules & GTR_CIRCUIT) && player->exiting) { if (player->karthud[khud_cardanimation] < 2*TICRATE) player->karthud[khud_cardanimation]++; @@ -9764,9 +9774,6 @@ void K_MoveKartPlayer(player_t *player, boolean onground) { INT32 hyu = hyudorotime; - if (gametype == GT_RACE) - hyu *= 2; // double in race - if (leveltime & 1) { player->mo->renderflags |= RF_DONTDRAW; diff --git a/src/lua_baselib.c b/src/lua_baselib.c index 73ee51527..4d6010ba2 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -36,6 +36,7 @@ #include "m_menu.h" // Player Setup menu color stuff #include "p_spec.h" // P_StartQuake #include "i_system.h" // I_GetPreciseTime, I_GetPrecisePrecision +#include "v_video.h" #include "lua_script.h" #include "lua_libs.h" @@ -3049,6 +3050,7 @@ static int lib_gAddGametype(lua_State *L) INT32 newgtpointlimit = 0; INT32 newgttimelimit = 0; INT16 newgtrankingstype = -1; + INT32 newgtcolor = V_YELLOWMAP; int newgtinttype = 0; luaL_checktype(L, 1, LUA_TTABLE); @@ -3108,6 +3110,14 @@ static int lib_gAddGametype(lua_State *L) if (!lua_isnumber(L, 3)) TYPEERROR("defaulttimelimit", LUA_TNUMBER) newgttimelimit = (INT32)lua_tointeger(L, 3); + } else if (i == 9 || (k && fasticmp(k, "menucolor"))) { + if (!lua_isnumber(L, 3)) + TYPEERROR("menucolor", LUA_TNUMBER) + { + INT32 color = (INT32)lua_tointeger(L, 3); + // Mask out other flags so they aren't passed into menu code. + newgtcolor = color & V_CHARCOLORMASK; // V_ + } } lua_pop(L, 1); } @@ -3133,6 +3143,7 @@ static int lib_gAddGametype(lua_State *L) intermissiontypes[newgtidx] = newgtinttype; pointlimits[newgtidx] = newgtpointlimit; timelimits[newgtidx] = newgttimelimit; + gametypecolor[newgtidx] = newgtcolor; // Write the new gametype name. Gametype_Names[newgtidx] = gtname; diff --git a/src/m_menu.c b/src/m_menu.c index 3e12b90ed..d370da8df 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -1728,13 +1728,19 @@ inline static void M_GetGametypeColor(void) if (gt == GT_BATTLE || levellistmode == LLM_BOSS) { - highlightflags = V_REDMAP; + highlightflags = gametypecolor[gt]; warningflags = V_ORANGEMAP; return; } if (gt == GT_RACE) { - highlightflags = V_SKYMAP; + highlightflags = gametypecolor[gt]; + return; + } + + if (gametypecolor[gt]) + { + highlightflags = gametypecolor[gt]; return; } diff --git a/src/p_tick.c b/src/p_tick.c index 61d754dd7..862956742 100644 --- a/src/p_tick.c +++ b/src/p_tick.c @@ -28,6 +28,7 @@ #include "i_video.h" #include "r_fps.h" #include "r_main.h" +#include "f_finale.h" // Object place #include "m_cheat.h" @@ -775,7 +776,7 @@ void P_Ticker(boolean run) // Plays the music after the starting countdown. else { - if (!(gametyperules & GTR_FREEROAM)) + if (!(gametyperules & GTR_FREEROAM) && !(titlemapinaction == TITLEMAP_RUNNING)) { if (leveltime == starttime-(3*TICRATE)) { @@ -791,7 +792,7 @@ void P_Ticker(boolean run) } } - if (leveltime < starttime) // SRB2Kart + if (!(gametyperules & GTR_FREEROAM) && leveltime < starttime) // SRB2Kart S_ChangeMusicInternal((encoremode ? "estart" : "kstart"), false); // yes this will be spammed otherwise encore and some stuff WILL overwrite it else if (leveltime == starttime) // The GO! sound stops the level start ambience S_StopMusic(); diff --git a/src/s_sound.c b/src/s_sound.c index a3b093f73..586f772eb 100644 --- a/src/s_sound.c +++ b/src/s_sound.c @@ -2564,10 +2564,14 @@ void S_InitLevelMusic(boolean fromnetsave) S_StopMusic(); // Starting ambience should always be restarted, if playing. - if (leveltime < (starttime + (TICRATE/2))) // SRB2Kart + if (!(gametyperules & GTR_FREEROAM) && leveltime < (starttime + (TICRATE/2))) // SRB2Kart { S_ChangeMusicEx((encoremode ? "estart" : "kstart"), 0, false, mapmusposition, 0, 0); } + else if (!(gametyperules & GTR_FREEROAM) && leveltime < (starttime + (TICRATE/2))) + { + S_ChangeMusicEx(mapmusname, 0, false, mapmusposition, 0, 0); + } S_ResetMusicStack(); music_stack_noposition = false; diff --git a/src/y_inter.c b/src/y_inter.c index 7f0e4a762..0531c27de 100644 --- a/src/y_inter.c +++ b/src/y_inter.c @@ -556,7 +556,12 @@ void Y_IntermissionDrawer(void) else if (modeattacking) hilicol = V_ORANGEMAP; else - hilicol = ((intertype == int_race) ? V_SKYMAP : V_REDMAP); + { + if (gametypecolor[gametype]) + hilicol = gametypecolor[gametype]; + else + hilicol = V_YELLOWMAP; + } if (sorttic != -1 && intertic > sorttic) { @@ -1444,10 +1449,13 @@ void Y_VoteDrawer(void) INT32 hilicol, tickdown = (timer+1)/TICRATE; if (cons_menuhighlight.value) hilicol = cons_menuhighlight.value; - else if (gametype == GT_RACE) - hilicol = V_SKYMAP; - else //if (gametype == GT_BATTLE) - hilicol = V_REDMAP; + else + { + if (gametypecolor[gametype]) + hilicol = gametypecolor[gametype]; + else + hilicol = V_YELLOWMAP; + } V_DrawCenteredString(BASEVIDWIDTH/2, 188, hilicol, va("Vote ends in %d", tickdown)); }