mirror of
https://github.com/KartKrewDev/RingRacers.git
synced 2025-10-30 08:01:28 +00:00
Merge branch 'special-stages' into 'master'
[Special stage prep] GP Bonus Stages + timelimit rework + Hitlag ticking fixes Closes #236 See merge request KartKrew/Kart!739
This commit is contained in:
commit
95096fbc9a
35 changed files with 1493 additions and 936 deletions
|
|
@ -124,3 +124,4 @@ k_terrain.c
|
|||
k_director.c
|
||||
k_follower.c
|
||||
k_profiles.c
|
||||
k_specialstage.c
|
||||
|
|
|
|||
|
|
@ -3877,31 +3877,23 @@ void SV_StopServer(void)
|
|||
}
|
||||
|
||||
// called at singleplayer start and stopdemo
|
||||
void SV_StartSinglePlayerServer(void)
|
||||
void SV_StartSinglePlayerServer(INT32 dogametype, boolean donetgame)
|
||||
{
|
||||
INT32 lastgametype = gametype;
|
||||
server = true;
|
||||
netgame = false;
|
||||
multiplayer = false;
|
||||
multiplayer = (modeattacking == ATTACKING_NONE);
|
||||
joinedIP[0] = '\0'; // Make sure to empty this so that we don't save garbage when we start our own game. (because yes we use this for netgames too....)
|
||||
|
||||
if ((modeattacking == ATTACKING_CAPSULES) || (bossinfo.boss == true))
|
||||
{
|
||||
G_SetGametype(GT_BATTLE);
|
||||
}
|
||||
else
|
||||
{
|
||||
G_SetGametype(GT_RACE);
|
||||
}
|
||||
netgame = false; // so setting timelimit works... (XD_NETVAR doesn't play nice with SV_StopServer)
|
||||
|
||||
G_SetGametype(dogametype);
|
||||
if (gametype != lastgametype)
|
||||
D_GameTypeChanged(lastgametype);
|
||||
|
||||
netgame = donetgame;
|
||||
|
||||
// no more tic the game with this settings!
|
||||
SV_StopServer();
|
||||
|
||||
if (splitscreen)
|
||||
multiplayer = true;
|
||||
}
|
||||
|
||||
static void SV_SendRefuse(INT32 node, const char *reason)
|
||||
|
|
|
|||
|
|
@ -473,7 +473,7 @@ void SendKick(UINT8 playernum, UINT8 msg);
|
|||
void NetKeepAlive(void);
|
||||
void NetUpdate(void);
|
||||
|
||||
void SV_StartSinglePlayerServer(void);
|
||||
void SV_StartSinglePlayerServer(INT32 dogametype, boolean donetgame);
|
||||
boolean SV_SpawnServer(void);
|
||||
void SV_StopServer(void);
|
||||
void SV_ResetServer(void);
|
||||
|
|
|
|||
35
src/d_main.c
35
src/d_main.c
|
|
@ -75,6 +75,7 @@
|
|||
#include "k_boss.h"
|
||||
#include "doomstat.h"
|
||||
#include "m_random.h" // P_ClearRandom
|
||||
#include "k_specialstage.h"
|
||||
|
||||
#ifdef CMAKECONFIG
|
||||
#include "config.h"
|
||||
|
|
@ -983,6 +984,9 @@ void D_StartTitle(void)
|
|||
// Reset boss info
|
||||
K_ResetBossInfo();
|
||||
|
||||
// Reset Special Stage
|
||||
K_ResetSpecialStage();
|
||||
|
||||
// empty maptol so mario/etc sounds don't play in sound test when they shouldn't
|
||||
maptol = 0;
|
||||
|
||||
|
|
@ -1807,29 +1811,20 @@ void D_SRB2Main(void)
|
|||
INT16 newskill = -1;
|
||||
const char *sskill = M_GetNextParm();
|
||||
|
||||
const char *masterstr = "Master";
|
||||
|
||||
if (!strcasecmp(masterstr, sskill))
|
||||
for (j = 0; gpdifficulty_cons_t[j].strvalue; j++)
|
||||
{
|
||||
newskill = KARTGP_MASTER;
|
||||
if (!strcasecmp(gpdifficulty_cons_t[j].strvalue, sskill))
|
||||
{
|
||||
newskill = (INT16)gpdifficulty_cons_t[j].value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (j = 0; kartspeed_cons_t[j].strvalue; j++)
|
||||
{
|
||||
if (!strcasecmp(kartspeed_cons_t[j].strvalue, sskill))
|
||||
{
|
||||
newskill = (INT16)kartspeed_cons_t[j].value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!kartspeed_cons_t[j].strvalue) // reached end of the list with no match
|
||||
{
|
||||
j = atoi(sskill); // assume they gave us a skill number, which is okay too
|
||||
if (j >= KARTSPEED_EASY && j <= KARTGP_MASTER)
|
||||
newskill = (INT16)j;
|
||||
}
|
||||
if (!gpdifficulty_cons_t[j].strvalue) // reached end of the list with no match
|
||||
{
|
||||
j = atoi(sskill); // assume they gave us a skill number, which is okay too
|
||||
if (j >= KARTSPEED_EASY && j <= KARTGP_MASTER)
|
||||
newskill = (INT16)j;
|
||||
}
|
||||
|
||||
if (grandprixinfo.gp == true)
|
||||
|
|
|
|||
206
src/d_netcmd.c
206
src/d_netcmd.c
|
|
@ -62,6 +62,7 @@
|
|||
#include "doomstat.h"
|
||||
#include "deh_tables.h"
|
||||
#include "m_perfstats.h"
|
||||
#include "k_specialstage.h"
|
||||
|
||||
#ifdef HAVE_DISCORDRPC
|
||||
#include "discord.h"
|
||||
|
|
@ -448,6 +449,7 @@ consvar_t cv_kartdebugnodes = CVAR_INIT ("debugnodes", "Off", CV_CHEAT, CV_OnOff
|
|||
consvar_t cv_kartdebugcolorize = CVAR_INIT ("debugcolorize", "Off", CV_CHEAT, CV_OnOff, NULL);
|
||||
consvar_t cv_kartdebugdirector = CVAR_INIT ("debugdirector", "Off", CV_CHEAT, CV_OnOff, NULL);
|
||||
consvar_t cv_spbtest = CVAR_INIT ("spbtest", "Off", CV_CHEAT|CV_NETVAR, CV_OnOff, NULL);
|
||||
consvar_t cv_gptest = CVAR_INIT ("gptest", "Off", CV_CHEAT|CV_NETVAR, CV_OnOff, NULL);
|
||||
|
||||
static CV_PossibleValue_t votetime_cons_t[] = {{10, "MIN"}, {3600, "MAX"}, {0, NULL}};
|
||||
consvar_t cv_votetime = CVAR_INIT ("votetime", "20", CV_NETVAR, votetime_cons_t, NULL);
|
||||
|
|
@ -471,9 +473,9 @@ consvar_t cv_overtime = CVAR_INIT ("overtime", "Yes", CV_NETVAR, CV_YesNo, NULL)
|
|||
consvar_t cv_rollingdemos = CVAR_INIT ("rollingdemos", "On", CV_SAVE, CV_OnOff, NULL);
|
||||
|
||||
static CV_PossibleValue_t pointlimit_cons_t[] = {{1, "MIN"}, {MAXSCORE, "MAX"}, {0, "None"}, {0, NULL}};
|
||||
consvar_t cv_pointlimit = CVAR_INIT ("pointlimit", "None", CV_SAVE|CV_NETVAR|CV_CALL|CV_NOINIT, pointlimit_cons_t, PointLimit_OnChange);
|
||||
consvar_t cv_pointlimit = CVAR_INIT ("pointlimit", "None", CV_NETVAR|CV_CALL|CV_NOINIT, pointlimit_cons_t, PointLimit_OnChange);
|
||||
static CV_PossibleValue_t timelimit_cons_t[] = {{1, "MIN"}, {30, "MAX"}, {0, "None"}, {0, NULL}};
|
||||
consvar_t cv_timelimit = CVAR_INIT ("timelimit", "None", CV_SAVE|CV_NETVAR|CV_CALL|CV_NOINIT, timelimit_cons_t, TimeLimit_OnChange);
|
||||
consvar_t cv_timelimit = CVAR_INIT ("timelimit", "None", CV_NETVAR|CV_CALL|CV_NOINIT, timelimit_cons_t, TimeLimit_OnChange);
|
||||
|
||||
static CV_PossibleValue_t numlaps_cons_t[] = {{1, "MIN"}, {MAX_LAPS, "MAX"}, {0, "Map default"}, {0, NULL}};
|
||||
consvar_t cv_numlaps = CVAR_INIT ("numlaps", "Map default", CV_SAVE|CV_NETVAR|CV_CALL|CV_CHEAT, numlaps_cons_t, NumLaps_OnChange);
|
||||
|
|
@ -2570,15 +2572,19 @@ void D_MapChange(INT32 mapnum, INT32 newgametype, boolean pencoremode, boolean r
|
|||
if ((netgame || multiplayer) && !((gametype == newgametype) && (gametypedefaultrules[newgametype] & GTR_CAMPAIGN)))
|
||||
FLS = false;
|
||||
|
||||
if (grandprixinfo.gp == true)
|
||||
{
|
||||
// Too lazy to change the input value for every instance of this function.......
|
||||
pencoremode = grandprixinfo.encore;
|
||||
}
|
||||
else if (bossinfo.boss == true)
|
||||
// Too lazy to change the input value for every instance of this function.......
|
||||
if (bossinfo.boss == true)
|
||||
{
|
||||
pencoremode = bossinfo.encore;
|
||||
}
|
||||
else if (specialStage.active == true)
|
||||
{
|
||||
pencoremode = specialStage.encore;
|
||||
}
|
||||
else if (grandprixinfo.gp == true)
|
||||
{
|
||||
pencoremode = grandprixinfo.encore;
|
||||
}
|
||||
|
||||
if (delay != 2)
|
||||
{
|
||||
|
|
@ -2938,6 +2944,7 @@ static void Command_Map_f(void)
|
|||
if (newgametype == GT_BATTLE)
|
||||
{
|
||||
grandprixinfo.gp = false;
|
||||
specialStage.active = false;
|
||||
K_ResetBossInfo();
|
||||
|
||||
if (mapheaderinfo[newmapnum-1] &&
|
||||
|
|
@ -2947,66 +2954,71 @@ static void Command_Map_f(void)
|
|||
bossinfo.encore = newencoremode;
|
||||
}
|
||||
}
|
||||
else // default GP
|
||||
else
|
||||
{
|
||||
grandprixinfo.gamespeed = (cv_kartspeed.value == KARTSPEED_AUTO ? KARTSPEED_NORMAL : cv_kartspeed.value);
|
||||
grandprixinfo.masterbots = false;
|
||||
|
||||
if (option_skill)
|
||||
if (mapheaderinfo[newmapnum-1] &&
|
||||
mapheaderinfo[newmapnum-1]->typeoflevel & TOL_SPECIAL) // Special Stage
|
||||
{
|
||||
const char *masterstr = "Master";
|
||||
const char *skillname = COM_Argv(option_skill + 1);
|
||||
INT32 newskill = -1;
|
||||
INT32 j;
|
||||
grandprixinfo.gp = false;
|
||||
bossinfo.boss = false;
|
||||
|
||||
if (!strcasecmp(masterstr, skillname))
|
||||
specialStage.active = true;
|
||||
specialStage.encore = newencoremode;
|
||||
}
|
||||
else // default GP
|
||||
{
|
||||
grandprixinfo.gamespeed = (cv_kartspeed.value == KARTSPEED_AUTO ? KARTSPEED_NORMAL : cv_kartspeed.value);
|
||||
grandprixinfo.masterbots = false;
|
||||
|
||||
if (option_skill)
|
||||
{
|
||||
newskill = KARTGP_MASTER;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (j = 0; kartspeed_cons_t[j].strvalue; j++)
|
||||
const char *skillname = COM_Argv(option_skill + 1);
|
||||
INT32 newskill = -1;
|
||||
INT32 j;
|
||||
|
||||
for (j = 0; gpdifficulty_cons_t[j].strvalue; j++)
|
||||
{
|
||||
if (!strcasecmp(kartspeed_cons_t[j].strvalue, skillname))
|
||||
if (!strcasecmp(gpdifficulty_cons_t[j].strvalue, skillname))
|
||||
{
|
||||
newskill = (INT16)kartspeed_cons_t[j].value;
|
||||
newskill = (INT16)gpdifficulty_cons_t[j].value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!kartspeed_cons_t[j].strvalue) // reached end of the list with no match
|
||||
if (!gpdifficulty_cons_t[j].strvalue) // reached end of the list with no match
|
||||
{
|
||||
INT32 num = atoi(COM_Argv(option_skill + 1)); // assume they gave us a skill number, which is okay too
|
||||
if (num >= KARTSPEED_EASY && num <= KARTGP_MASTER)
|
||||
newskill = (INT16)num;
|
||||
}
|
||||
|
||||
if (newskill != -1)
|
||||
{
|
||||
if (newskill == KARTGP_MASTER)
|
||||
{
|
||||
grandprixinfo.gamespeed = KARTSPEED_HARD;
|
||||
grandprixinfo.masterbots = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
grandprixinfo.gamespeed = newskill;
|
||||
grandprixinfo.masterbots = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (newskill != -1)
|
||||
{
|
||||
if (newskill == KARTGP_MASTER)
|
||||
{
|
||||
grandprixinfo.gamespeed = KARTSPEED_HARD;
|
||||
grandprixinfo.masterbots = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
grandprixinfo.gamespeed = newskill;
|
||||
grandprixinfo.masterbots = false;
|
||||
}
|
||||
}
|
||||
grandprixinfo.encore = newencoremode;
|
||||
|
||||
grandprixinfo.gp = true;
|
||||
grandprixinfo.roundnum = 0;
|
||||
grandprixinfo.cup = NULL;
|
||||
grandprixinfo.wonround = false;
|
||||
|
||||
bossinfo.boss = false;
|
||||
specialStage.active = false;
|
||||
|
||||
grandprixinfo.initalize = true;
|
||||
}
|
||||
|
||||
grandprixinfo.encore = newencoremode;
|
||||
|
||||
grandprixinfo.gp = true;
|
||||
grandprixinfo.roundnum = 0;
|
||||
grandprixinfo.cup = NULL;
|
||||
grandprixinfo.wonround = false;
|
||||
|
||||
bossinfo.boss = false;
|
||||
|
||||
grandprixinfo.initalize = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -4020,7 +4032,7 @@ void Schedule_Run(void)
|
|||
return;
|
||||
}
|
||||
|
||||
if (K_CanChangeRules() == false)
|
||||
if (K_CanChangeRules(false) == false)
|
||||
{
|
||||
// Don't engage in automation while in a restricted context.
|
||||
return;
|
||||
|
|
@ -4156,7 +4168,7 @@ void Automate_Run(automateEvents_t type)
|
|||
return;
|
||||
}
|
||||
|
||||
if (K_CanChangeRules() == false)
|
||||
if (K_CanChangeRules(false) == false)
|
||||
{
|
||||
// Don't engage in automation while in a restricted context.
|
||||
return;
|
||||
|
|
@ -4900,7 +4912,12 @@ void ItemFinder_OnChange(void)
|
|||
*/
|
||||
static void PointLimit_OnChange(void)
|
||||
{
|
||||
// Don't allow pointlimit in Single Player/Co-Op/Race!
|
||||
if (K_CanChangeRules(false) == false)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Don't allow pointlimit in non-pointlimited gametypes!
|
||||
if (server && Playing() && !(gametyperules & GTR_POINTLIMIT))
|
||||
{
|
||||
if (cv_pointlimit.value)
|
||||
|
|
@ -4915,7 +4932,7 @@ static void PointLimit_OnChange(void)
|
|||
cv_pointlimit.value,
|
||||
cv_pointlimit.value > 1 ? "s" : "");
|
||||
}
|
||||
else if (netgame || multiplayer)
|
||||
else
|
||||
CONS_Printf(M_GetText("Point limit disabled\n"));
|
||||
}
|
||||
|
||||
|
|
@ -4938,6 +4955,8 @@ Lagless_OnChange (void)
|
|||
}
|
||||
|
||||
UINT32 timelimitintics = 0;
|
||||
UINT32 extratimeintics = 0;
|
||||
UINT32 secretextratime = 0;
|
||||
|
||||
/** Deals with a timelimit change by printing the change to the console.
|
||||
* If the gametype is single player, cooperative, or race, the timelimit is
|
||||
|
|
@ -4949,26 +4968,40 @@ UINT32 timelimitintics = 0;
|
|||
*/
|
||||
static void TimeLimit_OnChange(void)
|
||||
{
|
||||
// Don't allow timelimit in Single Player/Co-Op/Race!
|
||||
if (server && Playing() && cv_timelimit.value != 0 && (bossinfo.boss || !(gametyperules & GTR_TIMELIMIT)))
|
||||
if (K_CanChangeRules(false) == false)
|
||||
{
|
||||
CV_SetValue(&cv_timelimit, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
if (cv_timelimit.value != 0)
|
||||
if (gamestate == GS_LEVEL && leveltime < starttime)
|
||||
{
|
||||
CONS_Printf(M_GetText("Rounds will end after %d minute%s.\n"),cv_timelimit.value,cv_timelimit.value == 1 ? "" : "s"); // Graue 11-17-2003
|
||||
timelimitintics = cv_timelimit.value * (60*TICRATE);
|
||||
if (cv_timelimit.value)
|
||||
{
|
||||
CONS_Printf(M_GetText("Time limit has been set to %d minute%s.\n"), cv_timelimit.value,cv_timelimit.value == 1 ? "" : "s");
|
||||
}
|
||||
else
|
||||
{
|
||||
CONS_Printf(M_GetText("Time limit has been disabled.\n"));
|
||||
}
|
||||
|
||||
// Note the deliberate absence of any code preventing
|
||||
// pointlimit and timelimit from being set simultaneously.
|
||||
// Some people might like to use them together. It works.
|
||||
}
|
||||
timelimitintics = cv_timelimit.value * (60*TICRATE);
|
||||
extratimeintics = secretextratime = 0;
|
||||
|
||||
#ifdef HAVE_DISCORDRPC
|
||||
DRPC_UpdatePresence();
|
||||
DRPC_UpdatePresence();
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
if (cv_timelimit.value)
|
||||
{
|
||||
CONS_Printf(M_GetText("Time limit will be %d minute%s next round.\n"), cv_timelimit.value,cv_timelimit.value == 1 ? "" : "s");
|
||||
}
|
||||
else
|
||||
{
|
||||
CONS_Printf(M_GetText("Time limit will be disabled next round.\n"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Adjusts certain settings to match a changed gametype.
|
||||
|
|
@ -4995,7 +5028,7 @@ void D_GameTypeChanged(INT32 lastgametype)
|
|||
|
||||
// Only do the following as the server, not as remote admin.
|
||||
// There will always be a server, and this only needs to be done once.
|
||||
if (server && (multiplayer || netgame))
|
||||
if (server && multiplayer)
|
||||
{
|
||||
if (!cv_timelimit.changed) // user hasn't changed limits
|
||||
{
|
||||
|
|
@ -5006,27 +5039,6 @@ void D_GameTypeChanged(INT32 lastgametype)
|
|||
CV_SetValue(&cv_pointlimit, pointlimits[gametype]);
|
||||
}
|
||||
}
|
||||
/* -- no longer useful
|
||||
else if (!multiplayer && !netgame)
|
||||
{
|
||||
G_SetGametype(GT_RACE);
|
||||
}
|
||||
*/
|
||||
|
||||
// reset timelimit and pointlimit in race/coop, prevent stupid cheats
|
||||
if (server)
|
||||
{
|
||||
if (!(gametyperules & GTR_TIMELIMIT))
|
||||
{
|
||||
if (cv_timelimit.value)
|
||||
CV_SetValue(&cv_timelimit, 0);
|
||||
}
|
||||
if (!(gametyperules & GTR_POINTLIMIT))
|
||||
{
|
||||
if (cv_pointlimit.value)
|
||||
CV_SetValue(&cv_pointlimit, 0);
|
||||
}
|
||||
}
|
||||
|
||||
// don't retain teams in other modes or between changes from ctf to team match.
|
||||
// also, stop any and all forms of team scrambling that might otherwise take place.
|
||||
|
|
@ -5752,6 +5764,10 @@ void Command_Retry_f(void)
|
|||
{
|
||||
CONS_Printf(M_GetText("This only works in singleplayer games.\n"));
|
||||
}
|
||||
else if (grandprixinfo.gp == true && grandprixinfo.eventmode != GPEVENT_NONE)
|
||||
{
|
||||
CONS_Printf(M_GetText("You can't retry right now!\n"));
|
||||
}
|
||||
else
|
||||
{
|
||||
M_ClearMenus(true);
|
||||
|
|
@ -6560,12 +6576,12 @@ static void Command_ShowTime_f(void)
|
|||
// SRB2Kart: On change messages
|
||||
static void NumLaps_OnChange(void)
|
||||
{
|
||||
if (K_CanChangeRules() == false)
|
||||
if (K_CanChangeRules(false) == false)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (leveltime < starttime)
|
||||
if (gamestate == GS_LEVEL && leveltime < starttime)
|
||||
{
|
||||
CONS_Printf(M_GetText("Number of laps have been set to %d.\n"), cv_numlaps.value);
|
||||
numlaps = (UINT8)cv_numlaps.value;
|
||||
|
|
@ -6578,12 +6594,12 @@ static void NumLaps_OnChange(void)
|
|||
|
||||
static void KartFrantic_OnChange(void)
|
||||
{
|
||||
if (K_CanChangeRules() == false)
|
||||
if (K_CanChangeRules(false) == false)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (leveltime < starttime)
|
||||
if (gamestate == GS_LEVEL && leveltime < starttime)
|
||||
{
|
||||
CONS_Printf(M_GetText("Frantic items has been set to %s.\n"), cv_kartfrantic.value ? M_GetText("on") : M_GetText("off"));
|
||||
franticitems = (boolean)cv_kartfrantic.value;
|
||||
|
|
@ -6596,12 +6612,12 @@ static void KartFrantic_OnChange(void)
|
|||
|
||||
static void KartSpeed_OnChange(void)
|
||||
{
|
||||
if (K_CanChangeRules() == false)
|
||||
if (K_CanChangeRules(false) == false)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (leveltime < starttime && cv_kartspeed.value != KARTSPEED_AUTO)
|
||||
if (gamestate == GS_LEVEL && leveltime < starttime && cv_kartspeed.value != KARTSPEED_AUTO)
|
||||
{
|
||||
CONS_Printf(M_GetText("Game speed has been changed to \"%s\".\n"), cv_kartspeed.string);
|
||||
gamespeed = (UINT8)cv_kartspeed.value;
|
||||
|
|
@ -6614,7 +6630,7 @@ static void KartSpeed_OnChange(void)
|
|||
|
||||
static void KartEncore_OnChange(void)
|
||||
{
|
||||
if (K_CanChangeRules() == false)
|
||||
if (K_CanChangeRules(false) == false)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
|
@ -6624,7 +6640,7 @@ static void KartEncore_OnChange(void)
|
|||
|
||||
static void KartEliminateLast_OnChange(void)
|
||||
{
|
||||
if (K_CanChangeRules() == false)
|
||||
if (K_CanChangeRules(false) == false)
|
||||
{
|
||||
CV_StealthSet(&cv_karteliminatelast, cv_karteliminatelast.defaultvalue);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ extern consvar_t cv_itemrespawn;
|
|||
extern consvar_t cv_pointlimit;
|
||||
extern consvar_t cv_timelimit;
|
||||
extern consvar_t cv_numlaps;
|
||||
extern UINT32 timelimitintics;
|
||||
extern UINT32 timelimitintics, extratimeintics, secretextratime;
|
||||
extern consvar_t cv_allowexitlevel;
|
||||
|
||||
extern consvar_t cv_autobalance;
|
||||
|
|
@ -120,7 +120,8 @@ extern consvar_t cv_kartusepwrlv;
|
|||
extern consvar_t cv_votetime;
|
||||
|
||||
extern consvar_t cv_kartdebugitem, cv_kartdebugamount, cv_kartdebugdistribution, cv_kartdebughuddrop;
|
||||
extern consvar_t cv_kartdebugnodes, cv_kartdebugcolorize, cv_kartdebugdirector, cv_spbtest;
|
||||
extern consvar_t cv_kartdebugnodes, cv_kartdebugcolorize, cv_kartdebugdirector;
|
||||
extern consvar_t cv_spbtest, cv_gptest;
|
||||
extern consvar_t cv_kartdebugwaypoints, cv_kartdebugbotpredict;
|
||||
|
||||
extern consvar_t cv_itemfinder;
|
||||
|
|
|
|||
|
|
@ -237,7 +237,8 @@ typedef enum
|
|||
khud_lapanimation, // Used to show the lap start wing logo animation
|
||||
khud_laphand, // Lap hand gfx to use; 0 = none, 1 = :ok_hand:, 2 = :thumbs_up:, 3 = :thumps_down:
|
||||
|
||||
// Start
|
||||
// Big text
|
||||
khud_finish, // Set when completing a round
|
||||
khud_fault, // Set when faulting during the starting countdown
|
||||
|
||||
// Camera
|
||||
|
|
|
|||
|
|
@ -3052,7 +3052,15 @@ void readcupheader(MYFILE *f, cupheader_t *cup)
|
|||
}
|
||||
else if (fastcmp(word, "LEVELLIST"))
|
||||
{
|
||||
cup->numlevels = 0;
|
||||
while (cup->numlevels > 0)
|
||||
{
|
||||
cup->numlevels--;
|
||||
Z_Free(cup->levellist[cup->numlevels]);
|
||||
cup->levellist[cup->numlevels] = NULL;
|
||||
if (cup->cachedlevels[cup->numlevels] == NEXTMAP_INVALID)
|
||||
continue;
|
||||
mapheaderinfo[cup->cachedlevels[cup->numlevels]]->cup = NULL;
|
||||
}
|
||||
|
||||
tmp = strtok(word2,",");
|
||||
do {
|
||||
|
|
@ -3069,11 +3077,15 @@ void readcupheader(MYFILE *f, cupheader_t *cup)
|
|||
}
|
||||
else if (fastcmp(word, "BONUSGAME"))
|
||||
{
|
||||
Z_Free(cup->levellist[CUPCACHE_BONUS]);
|
||||
cup->levellist[CUPCACHE_BONUS] = Z_StrDup(word2);
|
||||
cup->cachedlevels[CUPCACHE_BONUS] = NEXTMAP_INVALID;
|
||||
}
|
||||
else if (fastcmp(word, "SPECIALSTAGE"))
|
||||
{
|
||||
Z_Free(cup->levellist[CUPCACHE_SPECIAL]);
|
||||
cup->levellist[CUPCACHE_SPECIAL] = Z_StrDup(word2);
|
||||
cup->cachedlevels[CUPCACHE_SPECIAL] = NEXTMAP_INVALID;
|
||||
}
|
||||
else if (fastcmp(word, "EMERALDNUM"))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -670,6 +670,11 @@ extern int compuncommitted;
|
|||
/// Experimental attempts at preventing MF_PAPERCOLLISION objects from getting stuck in walls.
|
||||
//#define PAPER_COLLISIONCORRECTION
|
||||
|
||||
#ifdef DEVELOP
|
||||
// Easily make it so that overtime works offline
|
||||
#define TESTOVERTIMEINFREEPLAY
|
||||
#endif
|
||||
|
||||
/// FINALLY some real clipping that doesn't make walls dissappear AND speeds the game up
|
||||
/// (that was the original comment from SRB2CB, sadly it is a lie and actually slows game down)
|
||||
/// on the bright side it fixes some weird issues with translucent walls
|
||||
|
|
|
|||
|
|
@ -518,6 +518,7 @@ enum TypeOfLevel
|
|||
TOL_RACE = 0x0001, ///< Race
|
||||
TOL_BATTLE = 0x0002, ///< Battle
|
||||
TOL_BOSS = 0x0004, ///< Boss (variant of battle, but forbidden)
|
||||
TOL_SPECIAL = 0x0008, ///< Special Stage (variant of race, but forbidden)
|
||||
|
||||
// Modifiers
|
||||
TOL_TV = 0x0100 ///< Midnight Channel specific: draw TV like overlay on HUD
|
||||
|
|
|
|||
|
|
@ -2386,10 +2386,8 @@ void F_EndCutScene(void)
|
|||
F_StartGameEvaluation();
|
||||
else if (cutnum == introtoplay-1)
|
||||
D_StartTitle();
|
||||
else if (nextmap < NEXTMAP_SPECIAL)
|
||||
G_NextLevel();
|
||||
else
|
||||
G_EndGame();
|
||||
G_NextLevel();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
249
src/g_game.c
249
src/g_game.c
|
|
@ -58,6 +58,7 @@
|
|||
#include "k_respawn.h"
|
||||
#include "k_grandprix.h"
|
||||
#include "k_boss.h"
|
||||
#include "k_specialstage.h"
|
||||
#include "k_bot.h"
|
||||
#include "doomstat.h"
|
||||
|
||||
|
|
@ -2224,6 +2225,7 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
|
|||
|
||||
INT32 starpostnum;
|
||||
INT32 exiting;
|
||||
INT32 khudfinish;
|
||||
INT32 khudcardanimation;
|
||||
INT16 totalring;
|
||||
UINT8 laps;
|
||||
|
|
@ -2297,6 +2299,9 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
|
|||
botdiffincrease = players[player].botvars.diffincrease;
|
||||
botrival = players[player].botvars.rival;
|
||||
|
||||
totalring = players[player].totalring;
|
||||
xtralife = players[player].xtralife;
|
||||
|
||||
pflags = (players[player].pflags & (PF_WANTSTOJOIN|PF_KICKSTARTACCEL|PF_SHRINKME|PF_SHRINKACTIVE));
|
||||
|
||||
// SRB2kart
|
||||
|
|
@ -2315,12 +2320,11 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
|
|||
nocontrol = 0;
|
||||
laps = 0;
|
||||
latestlap = 0;
|
||||
totalring = 0;
|
||||
roundscore = 0;
|
||||
exiting = 0;
|
||||
khudfinish = 0;
|
||||
khudcardanimation = 0;
|
||||
starpostnum = 0;
|
||||
xtralife = 0;
|
||||
|
||||
follower = NULL;
|
||||
}
|
||||
|
|
@ -2357,16 +2361,22 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
|
|||
laps = players[player].laps;
|
||||
latestlap = players[player].latestlap;
|
||||
|
||||
totalring = players[player].totalring;
|
||||
roundscore = players[player].roundscore;
|
||||
|
||||
exiting = players[player].exiting;
|
||||
khudcardanimation = (exiting > 0) ? players[player].karthud[khud_cardanimation] : 0;
|
||||
if (exiting > 0)
|
||||
{
|
||||
khudfinish = players[player].karthud[khud_finish];
|
||||
khudcardanimation = players[player].karthud[khud_cardanimation];
|
||||
}
|
||||
else
|
||||
{
|
||||
khudfinish = 0;
|
||||
khudcardanimation = 0;
|
||||
}
|
||||
|
||||
starpostnum = players[player].starpostnum;
|
||||
|
||||
xtralife = players[player].xtralife;
|
||||
|
||||
follower = players[player].follower;
|
||||
|
||||
pflags |= (players[player].pflags & (PF_STASIS|PF_ELIMINATED|PF_NOCONTEST|PF_FAULT|PF_LOSTLIFE));
|
||||
|
|
@ -2406,6 +2416,7 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
|
|||
|
||||
p->starpostnum = starpostnum;
|
||||
p->exiting = exiting;
|
||||
p->karthud[khud_finish] = khudfinish;
|
||||
p->karthud[khud_cardanimation] = khudcardanimation;
|
||||
|
||||
p->laps = laps;
|
||||
|
|
@ -2908,7 +2919,7 @@ void G_ExitLevel(void)
|
|||
}
|
||||
}
|
||||
}
|
||||
else if (grandprixinfo.gp == true)
|
||||
else if (grandprixinfo.gp == true && grandprixinfo.eventmode == GPEVENT_NONE)
|
||||
{
|
||||
youlost = (grandprixinfo.wonround != true);
|
||||
}
|
||||
|
|
@ -3144,6 +3155,7 @@ tolinfo_t TYPEOFLEVEL[NUMTOLNAMES] = {
|
|||
{"RACE",TOL_RACE},
|
||||
{"BATTLE",TOL_BATTLE},
|
||||
{"BOSS",TOL_BOSS},
|
||||
{"SPECIAL",TOL_SPECIAL},
|
||||
{"TV",TOL_TV},
|
||||
{NULL, 0}
|
||||
};
|
||||
|
|
@ -3221,14 +3233,14 @@ boolean G_GametypeUsesLives(void)
|
|||
if (modeattacking || metalrecording) // NOT in Record Attack
|
||||
return false;
|
||||
|
||||
if (bossinfo.boss == true) // Fighting a boss?
|
||||
if ((grandprixinfo.gp == true) // In Grand Prix
|
||||
&& (gametype == GT_RACE) // NOT in bonus round
|
||||
&& grandprixinfo.eventmode == GPEVENT_NONE) // NOT in bonus
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if ((grandprixinfo.gp == true) // In Grand Prix
|
||||
&& (gametype == GT_RACE) // NOT in bonus round
|
||||
&& !G_IsSpecialStage(gamemap)) // NOT in special stage
|
||||
if (bossinfo.boss == true) // Fighting a boss?
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
|
@ -3643,11 +3655,11 @@ static void G_UpdateVisited(void)
|
|||
return;
|
||||
|
||||
// Update visitation flags
|
||||
mapheaderinfo[gamemap-1]->mapvisited |= MV_BEATEN;
|
||||
mapheaderinfo[prevmap]->mapvisited |= MV_BEATEN;
|
||||
|
||||
if (encoremode == true)
|
||||
{
|
||||
mapheaderinfo[gamemap-1]->mapvisited |= MV_ENCORE;
|
||||
mapheaderinfo[prevmap]->mapvisited |= MV_ENCORE;
|
||||
}
|
||||
|
||||
if (modeattacking)
|
||||
|
|
@ -3694,6 +3706,7 @@ static void G_HandleSaveLevel(void)
|
|||
|
||||
static void G_GetNextMap(void)
|
||||
{
|
||||
boolean spec = G_IsSpecialStage(prevmap+1);
|
||||
INT32 i;
|
||||
|
||||
// go to next level
|
||||
|
|
@ -3710,14 +3723,94 @@ static void G_GetNextMap(void)
|
|||
}
|
||||
else
|
||||
{
|
||||
if (grandprixinfo.roundnum >= grandprixinfo.cup->numlevels) // On final map
|
||||
INT32 lastgametype = gametype;
|
||||
|
||||
// If we're in a GP event, don't immediately follow it up with another.
|
||||
// I also suspect this will not work with online GP so I'm gonna prevent it right now.
|
||||
// The server might have to communicate eventmode (alongside other GP data) in XD_MAP later.
|
||||
if (netgame || grandprixinfo.eventmode != GPEVENT_NONE)
|
||||
{
|
||||
grandprixinfo.eventmode = GPEVENT_NONE;
|
||||
|
||||
G_SetGametype(GT_RACE);
|
||||
if (gametype != lastgametype)
|
||||
D_GameTypeChanged(lastgametype);
|
||||
|
||||
specialStage.active = false;
|
||||
bossinfo.boss = false;
|
||||
}
|
||||
// Special stage
|
||||
else if (grandprixinfo.roundnum >= grandprixinfo.cup->numlevels)
|
||||
{
|
||||
INT16 totaltotalring = 0;
|
||||
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
if (!playeringame[i])
|
||||
continue;
|
||||
if (players[i].spectator)
|
||||
continue;
|
||||
if (players[i].bot)
|
||||
continue;
|
||||
totaltotalring += players[i].totalring;
|
||||
}
|
||||
|
||||
if (totaltotalring >= 50)
|
||||
{
|
||||
const INT32 cupLevelNum = grandprixinfo.cup->cachedlevels[CUPCACHE_SPECIAL];
|
||||
if (cupLevelNum < nummapheaders && mapheaderinfo[cupLevelNum]
|
||||
&& mapheaderinfo[cupLevelNum]->typeoflevel & (TOL_SPECIAL|TOL_BOSS|TOL_BATTLE))
|
||||
{
|
||||
grandprixinfo.eventmode = GPEVENT_SPECIAL;
|
||||
nextmap = cupLevelNum;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (grandprixinfo.roundnum == (grandprixinfo.cup->numlevels+1)/2) // 3 for a 5-map cup
|
||||
{
|
||||
// todo any other condition?
|
||||
{
|
||||
const INT32 cupLevelNum = grandprixinfo.cup->cachedlevels[CUPCACHE_BONUS];
|
||||
if (cupLevelNum < nummapheaders && mapheaderinfo[cupLevelNum]
|
||||
&& mapheaderinfo[cupLevelNum]->typeoflevel & (TOL_BOSS|TOL_BATTLE))
|
||||
{
|
||||
grandprixinfo.eventmode = GPEVENT_BONUS;
|
||||
nextmap = cupLevelNum;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (grandprixinfo.eventmode != GPEVENT_NONE)
|
||||
{
|
||||
// nextmap is set above
|
||||
const INT32 newtol = mapheaderinfo[nextmap]->typeoflevel;
|
||||
|
||||
if (newtol & TOL_SPECIAL)
|
||||
{
|
||||
specialStage.active = true;
|
||||
specialStage.encore = grandprixinfo.encore;
|
||||
}
|
||||
else //(if newtol & (TOL_BATTLE|TOL_BOSS)) -- safe to assume??
|
||||
{
|
||||
G_SetGametype(GT_BATTLE);
|
||||
if (gametype != lastgametype)
|
||||
D_GameTypeChanged(lastgametype);
|
||||
if (newtol & TOL_BOSS)
|
||||
{
|
||||
K_ResetBossInfo();
|
||||
bossinfo.boss = true;
|
||||
bossinfo.encore = grandprixinfo.encore;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (grandprixinfo.roundnum >= grandprixinfo.cup->numlevels) // On final map
|
||||
{
|
||||
nextmap = NEXTMAP_CEREMONY; // ceremonymap
|
||||
}
|
||||
else
|
||||
{
|
||||
// Proceed to next map
|
||||
const INT32 cupLevelNum =grandprixinfo.cup->cachedlevels[grandprixinfo.roundnum];
|
||||
const INT32 cupLevelNum = grandprixinfo.cup->cachedlevels[grandprixinfo.roundnum];
|
||||
|
||||
if (cupLevelNum < nummapheaders && mapheaderinfo[cupLevelNum])
|
||||
{
|
||||
|
|
@ -3799,14 +3892,7 @@ static void G_GetNextMap(void)
|
|||
// Didn't get a nextmap before reaching the end?
|
||||
if (gettingresult != 2)
|
||||
{
|
||||
if (marathonmode)
|
||||
{
|
||||
nextmap = NEXTMAP_CEREMONY; // ceremonymap
|
||||
}
|
||||
else
|
||||
{
|
||||
nextmap = NEXTMAP_TITLE;
|
||||
}
|
||||
nextmap = NEXTMAP_CEREMONY; // ceremonymap
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
@ -3834,19 +3920,39 @@ static void G_GetNextMap(void)
|
|||
nextmap = cm;
|
||||
}
|
||||
|
||||
if (!marathonmode)
|
||||
if (K_CanChangeRules(true))
|
||||
{
|
||||
if (cv_advancemap.value == 0) // Stay on same map.
|
||||
switch (cv_advancemap.value)
|
||||
{
|
||||
nextmap = prevmap;
|
||||
}
|
||||
else if (cv_advancemap.value == 2) // Go to random map.
|
||||
{
|
||||
nextmap = G_RandMap(G_TOLFlag(gametype), prevmap, 0, 0, false, NULL);
|
||||
}
|
||||
else if (nextmap >= NEXTMAP_SPECIAL) // Loop back around
|
||||
{
|
||||
nextmap = G_GetFirstMapOfGametype(gametype);
|
||||
case 0: // Stay on same map.
|
||||
nextmap = prevmap;
|
||||
break;
|
||||
case 3: // Voting screen.
|
||||
{
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
if (!playeringame[i])
|
||||
continue;
|
||||
if (players[i].spectator)
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
if (i != MAXPLAYERS)
|
||||
{
|
||||
nextmap = NEXTMAP_VOTING;
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* FALLTHRU */
|
||||
case 2: // Go to random map.
|
||||
nextmap = G_RandMap(G_TOLFlag(gametype), prevmap, 0, 0, false, NULL);
|
||||
break;
|
||||
default:
|
||||
if (nextmap >= NEXTMAP_SPECIAL) // Loop back around
|
||||
{
|
||||
nextmap = G_GetFirstMapOfGametype(gametype);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3854,6 +3960,9 @@ static void G_GetNextMap(void)
|
|||
// We are committed to this map now.
|
||||
if (nextmap == NEXTMAP_INVALID || (nextmap < NEXTMAP_SPECIAL && (nextmap >= nummapheaders || !mapheaderinfo[nextmap] || mapheaderinfo[nextmap]->lumpnum == LUMPERROR)))
|
||||
I_Error("G_GetNextMap: Internal map ID %d not found (nummapheaders = %d)\n", nextmap, nummapheaders);
|
||||
|
||||
if (!spec)
|
||||
lastmap = nextmap;
|
||||
}
|
||||
|
||||
//
|
||||
|
|
@ -3862,8 +3971,6 @@ static void G_GetNextMap(void)
|
|||
static void G_DoCompleted(void)
|
||||
{
|
||||
INT32 i, j = 0;
|
||||
boolean spec = G_IsSpecialStage(gamemap);
|
||||
SINT8 powertype = K_UsingPowerLevels();
|
||||
|
||||
if (modeattacking && pausedelay)
|
||||
pausedelay = 0;
|
||||
|
|
@ -3906,8 +4013,9 @@ static void G_DoCompleted(void)
|
|||
}
|
||||
}
|
||||
|
||||
// See Y_StartIntermission timer handling
|
||||
if ((gametyperules & GTR_CIRCUIT) && ((multiplayer && demo.playback) || j == r_splitscreen+1) && (!K_CanChangeRules(false) || cv_inttime.value > 0))
|
||||
// play some generic music if there's no win/cool/lose music going on (for exitlevel commands)
|
||||
if ((gametyperules & GTR_CIRCUIT) && ((multiplayer && demo.playback) || j == r_splitscreen+1) && (cv_inttime.value > 0))
|
||||
S_ChangeMusicInternal("racent", true);
|
||||
|
||||
if (automapactive)
|
||||
|
|
@ -3919,14 +4027,8 @@ static void G_DoCompleted(void)
|
|||
|
||||
if (!demo.playback)
|
||||
{
|
||||
G_GetNextMap();
|
||||
|
||||
// Remember last map for when you come out of the special stage.
|
||||
if (!spec)
|
||||
lastmap = nextmap;
|
||||
|
||||
// Set up power level gametype scrambles
|
||||
K_SetPowerLevelScrambles(powertype);
|
||||
K_SetPowerLevelScrambles(K_UsingPowerLevels());
|
||||
}
|
||||
|
||||
// If the current gametype has no intermission screen set, then don't start it.
|
||||
|
|
@ -3937,7 +4039,6 @@ static void G_DoCompleted(void)
|
|||
|| (intertype == int_none))
|
||||
{
|
||||
G_UpdateVisited();
|
||||
G_HandleSaveLevel();
|
||||
G_AfterIntermission();
|
||||
}
|
||||
else
|
||||
|
|
@ -3945,7 +4046,6 @@ static void G_DoCompleted(void)
|
|||
G_SetGamestate(GS_INTERMISSION);
|
||||
Y_StartIntermission();
|
||||
G_UpdateVisited();
|
||||
G_HandleSaveLevel();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -3979,14 +4079,17 @@ void G_AfterIntermission(void)
|
|||
return;
|
||||
}
|
||||
|
||||
if (gamestate != GS_VOTING)
|
||||
{
|
||||
G_GetNextMap();
|
||||
G_HandleSaveLevel();
|
||||
}
|
||||
|
||||
if ((gametyperules & GTR_CAMPAIGN) && mapheaderinfo[prevmap]->cutscenenum && !modeattacking && skipstats <= 1 && (gamecomplete || !(marathonmode & MA_NOCUTSCENES))) // Start a custom cutscene.
|
||||
F_StartCustomCutscene(mapheaderinfo[prevmap]->cutscenenum-1, false, false);
|
||||
else
|
||||
{
|
||||
if (nextmap < NEXTMAP_SPECIAL)
|
||||
G_NextLevel();
|
||||
else
|
||||
G_EndGame();
|
||||
G_NextLevel();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -3998,25 +4101,15 @@ void G_AfterIntermission(void)
|
|||
//
|
||||
void G_NextLevel(void)
|
||||
{
|
||||
if (gamestate != GS_VOTING)
|
||||
if (nextmap >= NEXTMAP_SPECIAL)
|
||||
{
|
||||
if ((cv_advancemap.value == 3) && grandprixinfo.gp == false && bossinfo.boss == false && !modeattacking && !skipstats && (multiplayer || netgame))
|
||||
{
|
||||
UINT8 i;
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
if (playeringame[i] && !players[i].spectator)
|
||||
{
|
||||
gameaction = ga_startvote;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
forceresetplayers = false;
|
||||
deferencoremode = (cv_kartencore.value == 1);
|
||||
G_EndGame();
|
||||
return;
|
||||
}
|
||||
|
||||
forceresetplayers = false;
|
||||
deferencoremode = (cv_kartencore.value == 1);
|
||||
|
||||
gameaction = ga_worlddone;
|
||||
}
|
||||
|
||||
|
|
@ -4043,7 +4136,11 @@ static void G_DoWorldDone(void)
|
|||
static void G_DoStartVote(void)
|
||||
{
|
||||
if (server)
|
||||
{
|
||||
if (gamestate == GS_VOTING)
|
||||
I_Error("G_DoStartVote: NEXTMAP_VOTING causes recursive vote!");
|
||||
D_SetupVote();
|
||||
}
|
||||
gameaction = ga_nothing;
|
||||
}
|
||||
|
||||
|
|
@ -4121,8 +4218,12 @@ static void G_DoContinued(void)
|
|||
// when something new is added.
|
||||
void G_EndGame(void)
|
||||
{
|
||||
if (demo.recording && (modeattacking || demo.savemode != DSM_NOTSAVING))
|
||||
G_SaveDemo();
|
||||
// Handle voting
|
||||
if (nextmap == NEXTMAP_VOTING)
|
||||
{
|
||||
gameaction = ga_startvote;
|
||||
return;
|
||||
}
|
||||
|
||||
// Only do evaluation and credits in singleplayer contexts
|
||||
if (!netgame && (gametyperules & GTR_CAMPAIGN))
|
||||
|
|
@ -4711,6 +4812,7 @@ cleanup:
|
|||
void G_DeferedInitNew(boolean pencoremode, INT32 map, INT32 pickedchar, UINT8 ssplayers, boolean FLS)
|
||||
{
|
||||
UINT16 color = SKINCOLOR_NONE;
|
||||
INT32 dogametype;
|
||||
|
||||
paused = false;
|
||||
|
||||
|
|
@ -4721,8 +4823,17 @@ void G_DeferedInitNew(boolean pencoremode, INT32 map, INT32 pickedchar, UINT8 ss
|
|||
|
||||
G_ResetRandMapBuffer();
|
||||
|
||||
if ((modeattacking == ATTACKING_CAPSULES) || (bossinfo.boss == true))
|
||||
{
|
||||
dogametype = GT_BATTLE;
|
||||
}
|
||||
else
|
||||
{
|
||||
dogametype = GT_RACE;
|
||||
}
|
||||
|
||||
// this leave the actual game if needed
|
||||
SV_StartSinglePlayerServer();
|
||||
SV_StartSinglePlayerServer(dogametype, false);
|
||||
|
||||
if (splitscreen != ssplayers)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -44,7 +44,8 @@ typedef enum
|
|||
NEXTMAP_EVALUATION = INT16_MAX-2,
|
||||
NEXTMAP_CREDITS = INT16_MAX-3,
|
||||
NEXTMAP_CEREMONY = INT16_MAX-4,
|
||||
NEXTMAP_INVALID = INT16_MAX-5, // Always last (swap with NEXTMAP_RESERVED when removing that)
|
||||
NEXTMAP_VOTING = INT16_MAX-5,
|
||||
NEXTMAP_INVALID = INT16_MAX-6, // Always last
|
||||
NEXTMAP_SPECIAL = NEXTMAP_INVALID
|
||||
} nextmapspecial_t;
|
||||
|
||||
|
|
|
|||
|
|
@ -2416,7 +2416,7 @@ static void HU_DrawRankings(void)
|
|||
|
||||
if ((gametyperules & (GTR_TIMELIMIT|GTR_POINTLIMIT)) && !bossinfo.boss)
|
||||
{
|
||||
if ((gametyperules & GTR_TIMELIMIT) && cv_timelimit.value && timelimitintics > 0)
|
||||
if ((gametyperules & GTR_TIMELIMIT) && timelimitintics > 0)
|
||||
{
|
||||
UINT32 timeval = (timelimitintics + starttime + 1 - leveltime);
|
||||
if (timeval > timelimitintics+1)
|
||||
|
|
|
|||
|
|
@ -127,12 +127,16 @@ void K_CheckBumpers(void)
|
|||
winnerscoreadd -= players[i].roundscore;
|
||||
}
|
||||
|
||||
if (K_CanChangeRules() == false)
|
||||
if (K_CanChangeRules(true) == false)
|
||||
{
|
||||
if (nobumpers)
|
||||
{
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
if (!playeringame[i])
|
||||
continue;
|
||||
if (players[i].spectator)
|
||||
continue;
|
||||
players[i].pflags |= PF_NOCONTEST;
|
||||
P_DoPlayerExit(&players[i]);
|
||||
}
|
||||
|
|
@ -144,7 +148,8 @@ void K_CheckBumpers(void)
|
|||
if (!battlecapsules)
|
||||
{
|
||||
// Reset map to turn on battle capsules
|
||||
D_MapChange(gamemap, gametype, encoremode, true, 0, false, false);
|
||||
if (server)
|
||||
D_MapChange(gamemap, gametype, encoremode, true, 0, false, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -152,6 +157,10 @@ void K_CheckBumpers(void)
|
|||
{
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
if (!playeringame[i])
|
||||
continue;
|
||||
if (players[i].spectator)
|
||||
continue;
|
||||
players[i].pflags |= PF_NOCONTEST;
|
||||
P_DoPlayerExit(&players[i]);
|
||||
}
|
||||
|
|
@ -173,7 +182,13 @@ void K_CheckBumpers(void)
|
|||
K_KartUpdatePosition(&players[i]);
|
||||
|
||||
for (i = 0; i < MAXPLAYERS; i++) // and it can't be merged with this loop because it needs to be all updated before exiting... multi-loops suck...
|
||||
{
|
||||
if (!playeringame[i])
|
||||
continue;
|
||||
if (players[i].spectator)
|
||||
continue;
|
||||
P_DoPlayerExit(&players[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void K_CheckEmeralds(player_t *player)
|
||||
|
|
@ -795,29 +810,13 @@ void K_SpawnPlayerBattleBumpers(player_t *p)
|
|||
}
|
||||
}
|
||||
|
||||
void K_BattleInit(void)
|
||||
void K_BattleInit(boolean singleplayercontext)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
if ((gametyperules & GTR_CAPSULES) && !battlecapsules && !bossinfo.boss)
|
||||
if ((gametyperules & GTR_CAPSULES) && singleplayercontext && !battlecapsules && !bossinfo.boss)
|
||||
{
|
||||
mapthing_t *mt;
|
||||
if (modeattacking != ATTACKING_CAPSULES)
|
||||
{
|
||||
UINT8 n = 0;
|
||||
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
if (!playeringame[i] || players[i].spectator)
|
||||
continue;
|
||||
n++;
|
||||
}
|
||||
|
||||
if (n > 1)
|
||||
goto aftercapsules;
|
||||
}
|
||||
|
||||
mt = mapthings;
|
||||
mapthing_t *mt = mapthings;
|
||||
for (i = 0; i < nummapthings; i++, mt++)
|
||||
{
|
||||
if (mt->type == mobjinfo[MT_BATTLECAPSULE].doomednum)
|
||||
|
|
@ -826,7 +825,6 @@ void K_BattleInit(void)
|
|||
|
||||
battlecapsules = true;
|
||||
}
|
||||
aftercapsules:
|
||||
|
||||
if (gametyperules & GTR_BUMPERS)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -29,6 +29,6 @@ void K_RunPaperItemSpawners(void);
|
|||
void K_RunBattleOvertime(void);
|
||||
void K_SetupMovingCapsule(mapthing_t *mt, mobj_t *mobj);
|
||||
void K_SpawnPlayerBattleBumpers(player_t *p);
|
||||
void K_BattleInit(void);
|
||||
void K_BattleInit(boolean singleplayercontext);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
10
src/k_bot.c
10
src/k_bot.c
|
|
@ -1261,18 +1261,12 @@ void K_BuildBotTiccmd(player_t *player, ticcmd_t *cmd)
|
|||
INT32 turnamt = 0;
|
||||
line_t *botController = NULL;
|
||||
|
||||
// Can't build a ticcmd if we aren't spawned...
|
||||
if (!player->mo)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Remove any existing controls
|
||||
memset(cmd, 0, sizeof(ticcmd_t));
|
||||
|
||||
if (gamestate != GS_LEVEL)
|
||||
if (gamestate != GS_LEVEL || !player->mo || player->spectator)
|
||||
{
|
||||
// Not in a level.
|
||||
// Not in the level.
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
|
||||
#include "k_grandprix.h"
|
||||
#include "k_boss.h"
|
||||
#include "k_specialstage.h"
|
||||
#include "doomdef.h"
|
||||
#include "d_player.h"
|
||||
#include "g_game.h"
|
||||
|
|
@ -96,14 +97,14 @@ INT16 K_CalculateGPRankPoints(UINT8 position, UINT8 numplayers)
|
|||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
SINT8 K_BotDefaultSkin(void)
|
||||
UINT8 K_BotDefaultSkin(void)
|
||||
|
||||
See header file for description.
|
||||
--------------------------------------------------*/
|
||||
SINT8 K_BotDefaultSkin(void)
|
||||
UINT8 K_BotDefaultSkin(void)
|
||||
{
|
||||
const char *defaultbotskinname = "eggrobo";
|
||||
SINT8 defaultbotskin = R_SkinAvailable(defaultbotskinname);
|
||||
INT32 defaultbotskin = R_SkinAvailable(defaultbotskinname);
|
||||
|
||||
if (defaultbotskin == -1)
|
||||
{
|
||||
|
|
@ -111,7 +112,7 @@ SINT8 K_BotDefaultSkin(void)
|
|||
defaultbotskin = 0;
|
||||
}
|
||||
|
||||
return defaultbotskin;
|
||||
return (UINT8)defaultbotskin;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
|
|
@ -121,7 +122,7 @@ SINT8 K_BotDefaultSkin(void)
|
|||
--------------------------------------------------*/
|
||||
void K_InitGrandPrixBots(void)
|
||||
{
|
||||
const SINT8 defaultbotskin = K_BotDefaultSkin();
|
||||
const UINT8 defaultbotskin = K_BotDefaultSkin();
|
||||
|
||||
const UINT8 startingdifficulty = K_BotStartingDifficulty(grandprixinfo.gamespeed);
|
||||
UINT8 difficultylevels[MAXPLAYERS];
|
||||
|
|
@ -132,7 +133,9 @@ void K_InitGrandPrixBots(void)
|
|||
UINT8 numplayers = 0;
|
||||
UINT8 competitors[MAXSPLITSCREENPLAYERS];
|
||||
|
||||
boolean skinusable[MAXSKINS];
|
||||
UINT8 usableskins;
|
||||
UINT8 grabskins[MAXSKINS+1];
|
||||
|
||||
UINT8 botskinlist[MAXPLAYERS];
|
||||
UINT8 botskinlistpos = 0;
|
||||
|
||||
|
|
@ -142,18 +145,12 @@ void K_InitGrandPrixBots(void)
|
|||
memset(competitors, MAXPLAYERS, sizeof (competitors));
|
||||
memset(botskinlist, defaultbotskin, sizeof (botskinlist));
|
||||
|
||||
// init usable bot skins list
|
||||
for (i = 0; i < MAXSKINS; i++)
|
||||
// Init usable bot skins list
|
||||
for (usableskins = 0; usableskins < numskins; usableskins++)
|
||||
{
|
||||
if (i < numskins)
|
||||
{
|
||||
skinusable[i] = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
skinusable[i] = false;
|
||||
}
|
||||
grabskins[usableskins] = usableskins;
|
||||
}
|
||||
grabskins[usableskins] = MAXSKINS;
|
||||
|
||||
#if MAXPLAYERS != 16
|
||||
I_Error("GP bot difficulty levels need rebalanced for the new player count!\n");
|
||||
|
|
@ -192,7 +189,7 @@ void K_InitGrandPrixBots(void)
|
|||
if (numplayers < MAXSPLITSCREENPLAYERS && !players[i].spectator)
|
||||
{
|
||||
competitors[numplayers] = i;
|
||||
skinusable[players[i].skin] = false;
|
||||
grabskins[players[i].skin] = MAXSKINS;
|
||||
numplayers++;
|
||||
}
|
||||
else
|
||||
|
|
@ -219,52 +216,46 @@ void K_InitGrandPrixBots(void)
|
|||
{
|
||||
player_t *p = &players[competitors[j]];
|
||||
char *rivalname = skins[p->skin].rivals[i];
|
||||
SINT8 rivalnum = R_SkinAvailable(rivalname);
|
||||
INT32 rivalnum = R_SkinAvailable(rivalname);
|
||||
|
||||
if (rivalnum != -1 && skinusable[rivalnum])
|
||||
// Intentionally referenced before (currently dummied out) unlock check. Such a tease!
|
||||
if (rivalnum != -1 && grabskins[(UINT8)rivalnum] != MAXSKINS)
|
||||
{
|
||||
botskinlist[botskinlistpos] = rivalnum;
|
||||
skinusable[rivalnum] = false;
|
||||
botskinlistpos++;
|
||||
botskinlist[botskinlistpos++] = (UINT8)rivalnum;
|
||||
grabskins[(UINT8)rivalnum] = MAXSKINS;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Rearrange usable bot skins list to prevent gaps for randomised selection
|
||||
for (i = 0; i < usableskins; i++)
|
||||
{
|
||||
if (!(grabskins[i] == MAXSKINS /*|| K_SkinLocked(grabskins[i])*/))
|
||||
continue;
|
||||
while (usableskins > i && (grabskins[usableskins] == MAXSKINS /*|| K_SkinLocked(grabskins[i])*/))
|
||||
{
|
||||
usableskins--;
|
||||
}
|
||||
grabskins[i] = grabskins[usableskins];
|
||||
grabskins[usableskins] = MAXSKINS;
|
||||
}
|
||||
|
||||
// Pad the remaining list with random skins if we need to
|
||||
if (botskinlistpos < wantedbots)
|
||||
{
|
||||
for (i = botskinlistpos; i < wantedbots; i++)
|
||||
while (botskinlistpos < wantedbots)
|
||||
{
|
||||
UINT8 val = M_RandomKey(numskins);
|
||||
UINT8 loops = 0;
|
||||
UINT8 skinnum = defaultbotskin;
|
||||
|
||||
while (!skinusable[val])
|
||||
if (usableskins > 0)
|
||||
{
|
||||
if (loops >= numskins)
|
||||
{
|
||||
// no more skins
|
||||
break;
|
||||
}
|
||||
|
||||
val++;
|
||||
|
||||
if (val >= numskins)
|
||||
{
|
||||
val = 0;
|
||||
}
|
||||
|
||||
loops++;
|
||||
UINT8 index = M_RandomKey(usableskins);
|
||||
skinnum = grabskins[index];
|
||||
grabskins[index] = grabskins[--usableskins];
|
||||
}
|
||||
|
||||
if (loops >= numskins)
|
||||
{
|
||||
// leave the rest of the table as the default skin
|
||||
break;
|
||||
}
|
||||
|
||||
botskinlist[i] = val;
|
||||
skinusable[val] = false;
|
||||
botskinlist[botskinlistpos++] = skinnum;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -341,6 +332,16 @@ void K_UpdateGrandPrixBots(void)
|
|||
UINT16 newrivalscore = 0;
|
||||
UINT8 i;
|
||||
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
if (!playeringame[i] || !players[i].bot)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
players[i].spectator = (grandprixinfo.eventmode != GPEVENT_NONE);
|
||||
}
|
||||
|
||||
// Find the rival.
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
|
|
@ -519,38 +520,49 @@ void K_IncreaseBotDifficulty(player_t *bot)
|
|||
--------------------------------------------------*/
|
||||
void K_RetireBots(void)
|
||||
{
|
||||
const SINT8 defaultbotskin = K_BotDefaultSkin();
|
||||
const UINT8 defaultbotskin = K_BotDefaultSkin();
|
||||
SINT8 newDifficulty;
|
||||
|
||||
boolean skinusable[MAXSKINS];
|
||||
UINT8 usableskins;
|
||||
UINT8 grabskins[MAXSKINS+1];
|
||||
|
||||
UINT8 i;
|
||||
|
||||
if (grandprixinfo.gp == true && grandprixinfo.roundnum >= grandprixinfo.cup->numlevels)
|
||||
if (grandprixinfo.gp == true
|
||||
&& ((grandprixinfo.roundnum >= grandprixinfo.cup->numlevels)
|
||||
|| grandprixinfo.eventmode != GPEVENT_NONE))
|
||||
{
|
||||
// Was last map, no replacement.
|
||||
// No replacement.
|
||||
return;
|
||||
}
|
||||
|
||||
// init usable bot skins list
|
||||
for (i = 0; i < MAXSKINS; i++)
|
||||
// Init usable bot skins list
|
||||
for (usableskins = 0; usableskins < numskins; usableskins++)
|
||||
{
|
||||
if (i < numskins)
|
||||
{
|
||||
skinusable[i] = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
skinusable[i] = false;
|
||||
}
|
||||
grabskins[usableskins] = usableskins;
|
||||
}
|
||||
grabskins[usableskins] = MAXSKINS;
|
||||
|
||||
// Exclude player skins
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
if (playeringame[i] && !players[i].spectator)
|
||||
{
|
||||
skinusable[players[i].skin] = false;
|
||||
}
|
||||
if (!playeringame[i])
|
||||
continue;
|
||||
if (players[i].spectator)
|
||||
continue;
|
||||
|
||||
grabskins[players[i].skin] = MAXSKINS;
|
||||
}
|
||||
|
||||
// Rearrange usable bot skins list to prevent gaps for randomised selection
|
||||
for (i = 0; i < usableskins; i++)
|
||||
{
|
||||
if (!(grabskins[i] == MAXSKINS /*|| K_SkinLocked(grabskins[i])*/))
|
||||
continue;
|
||||
while (usableskins > i && (grabskins[usableskins] == MAXSKINS /*|| K_SkinLocked(grabskins[i])*/))
|
||||
usableskins--;
|
||||
grabskins[i] = grabskins[usableskins];
|
||||
grabskins[usableskins] = MAXSKINS;
|
||||
}
|
||||
|
||||
if (!grandprixinfo.gp) // Sure, let's let this happen all the time :)
|
||||
|
|
@ -576,49 +588,24 @@ void K_RetireBots(void)
|
|||
{
|
||||
player_t *bot = NULL;
|
||||
|
||||
if (!playeringame[i] || !players[i].bot)
|
||||
if (!playeringame[i] || !players[i].bot || players[i].spectator)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
bot = &players[i];
|
||||
|
||||
if (bot->spectator)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (bot->pflags & PF_NOCONTEST)
|
||||
{
|
||||
UINT8 skinnum = P_RandomKey(PR_UNDEFINED, numskins);
|
||||
UINT8 loops = 0;
|
||||
UINT8 skinnum = defaultbotskin;
|
||||
|
||||
while (!skinusable[skinnum])
|
||||
if (usableskins > 0)
|
||||
{
|
||||
if (loops >= numskins)
|
||||
{
|
||||
// no more skins
|
||||
break;
|
||||
}
|
||||
|
||||
skinnum++;
|
||||
|
||||
if (skinnum >= numskins)
|
||||
{
|
||||
skinnum = 0;
|
||||
}
|
||||
|
||||
loops++;
|
||||
UINT8 index = P_RandomKey(PR_RULESCRAMBLE, usableskins);
|
||||
skinnum = grabskins[index];
|
||||
grabskins[index] = grabskins[--usableskins];
|
||||
}
|
||||
|
||||
if (loops >= numskins)
|
||||
{
|
||||
// Use default skin
|
||||
skinnum = defaultbotskin;
|
||||
}
|
||||
|
||||
skinusable[skinnum] = false;
|
||||
|
||||
bot->botvars.difficulty = newDifficulty;
|
||||
bot->botvars.diffincrease = 0;
|
||||
|
||||
|
|
@ -671,7 +658,7 @@ void K_FakeBotResults(player_t *bot)
|
|||
}
|
||||
|
||||
// hey, you "won"
|
||||
bot->exiting = 2;
|
||||
bot->exiting = 1;
|
||||
bot->realtime += (bot->distancetofinish / distfactor);
|
||||
bot->distancetofinish = 0;
|
||||
K_IncreaseBotDifficulty(bot);
|
||||
|
|
@ -710,18 +697,12 @@ void K_PlayerLoseLife(player_t *player)
|
|||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
boolean K_CanChangeRules(void)
|
||||
boolean K_CanChangeRules(boolean allowdemos)
|
||||
|
||||
See header file for description.
|
||||
--------------------------------------------------*/
|
||||
boolean K_CanChangeRules(void)
|
||||
boolean K_CanChangeRules(boolean allowdemos)
|
||||
{
|
||||
if (demo.playback)
|
||||
{
|
||||
// We've already got our important settings!
|
||||
return false;
|
||||
}
|
||||
|
||||
if (grandprixinfo.gp == true && grandprixinfo.roundnum > 0)
|
||||
{
|
||||
// Don't cheat the rules of the GP!
|
||||
|
|
@ -734,11 +715,29 @@ boolean K_CanChangeRules(void)
|
|||
return false;
|
||||
}
|
||||
|
||||
if (modeattacking == true)
|
||||
if (specialStage.active == true)
|
||||
{
|
||||
// Don't cheat special stages!
|
||||
return false;
|
||||
}
|
||||
|
||||
if (marathonmode)
|
||||
{
|
||||
// Don't cheat the endurance challenge!
|
||||
return false;
|
||||
}
|
||||
|
||||
if (modeattacking != ATTACKING_NONE)
|
||||
{
|
||||
// Don't cheat the rules of Time Trials!
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!allowdemos && demo.playback)
|
||||
{
|
||||
// We've already got our important settings!
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,6 +16,10 @@
|
|||
#include "doomdef.h"
|
||||
#include "doomstat.h"
|
||||
|
||||
#define GPEVENT_NONE 0
|
||||
#define GPEVENT_BONUS 1
|
||||
#define GPEVENT_SPECIAL 2
|
||||
|
||||
extern struct grandprixinfo
|
||||
{
|
||||
boolean gp; ///< If true, then we are in a Grand Prix.
|
||||
|
|
@ -26,6 +30,7 @@ extern struct grandprixinfo
|
|||
boolean masterbots; ///< If true, all bots should be max difficulty (Master Mode)
|
||||
boolean initalize; ///< If true, we need to initialize a new session.
|
||||
boolean wonround; ///< If false, then we retry the map instead of going to the next.
|
||||
UINT8 eventmode; ///< See GPEVENT_ constants
|
||||
} grandprixinfo;
|
||||
|
||||
|
||||
|
|
@ -63,13 +68,13 @@ INT16 K_CalculateGPRankPoints(UINT8 position, UINT8 numplayers);
|
|||
|
||||
|
||||
/*--------------------------------------------------
|
||||
SINT8 K_BotDefaultSkin(void);
|
||||
UINT8 K_BotDefaultSkin(void);
|
||||
|
||||
Returns the skin number of the skin the game
|
||||
uses as a fallback option.
|
||||
--------------------------------------------------*/
|
||||
|
||||
SINT8 K_BotDefaultSkin(void);
|
||||
UINT8 K_BotDefaultSkin(void);
|
||||
|
||||
|
||||
/*--------------------------------------------------
|
||||
|
|
@ -147,18 +152,18 @@ void K_PlayerLoseLife(player_t *player);
|
|||
|
||||
|
||||
/*--------------------------------------------------
|
||||
boolean K_CanChangeRules(void);
|
||||
boolean K_CanChangeRules(boolean allowdemos);
|
||||
|
||||
Returns whenver or not the server is allowed
|
||||
to change the game rules.
|
||||
|
||||
Input Arguments:-
|
||||
None
|
||||
allowdemos - permits this behavior during demo playback
|
||||
|
||||
Return:-
|
||||
true if can change important gameplay rules, otherwise false.
|
||||
--------------------------------------------------*/
|
||||
|
||||
boolean K_CanChangeRules(void);
|
||||
boolean K_CanChangeRules(boolean allowdemos);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
428
src/k_hud.c
428
src/k_hud.c
|
|
@ -12,6 +12,7 @@
|
|||
#include "k_hud.h"
|
||||
#include "k_kart.h"
|
||||
#include "k_battle.h"
|
||||
#include "k_grandprix.h"
|
||||
#include "k_boss.h"
|
||||
#include "k_color.h"
|
||||
#include "k_director.h"
|
||||
|
|
@ -75,7 +76,9 @@ static patch_t *kp_winnernum[NUMPOSFRAMES];
|
|||
static patch_t *kp_facenum[MAXPLAYERS+1];
|
||||
static patch_t *kp_facehighlight[8];
|
||||
|
||||
static patch_t *kp_nocontestminimap;
|
||||
static patch_t *kp_spbminimap;
|
||||
static patch_t *kp_capsuleminimap[2];
|
||||
|
||||
static patch_t *kp_ringsticker[2];
|
||||
static patch_t *kp_ringstickersplit[4];
|
||||
|
|
@ -311,7 +314,11 @@ void K_LoadKartHUDGraphics(void)
|
|||
HU_UpdatePatch(&kp_facehighlight[i], "%s", buffer);
|
||||
}
|
||||
|
||||
// Special minimap icons
|
||||
HU_UpdatePatch(&kp_nocontestminimap, "MINIDEAD");
|
||||
HU_UpdatePatch(&kp_spbminimap, "SPBMMAP");
|
||||
HU_UpdatePatch(&kp_capsuleminimap[0], "MINICAP1");
|
||||
HU_UpdatePatch(&kp_capsuleminimap[1], "MINICAP2");
|
||||
|
||||
// Rings & Lives
|
||||
HU_UpdatePatch(&kp_ringsticker[0], "RNGBACKA");
|
||||
|
|
@ -1385,33 +1392,40 @@ void K_drawKartTimestamp(tic_t drawtime, INT32 TX, INT32 TY, INT16 emblemmap, UI
|
|||
// TIME_Y = 6; // 6
|
||||
|
||||
tic_t worktime;
|
||||
boolean dontdraw = false;
|
||||
INT32 jitter = 0;
|
||||
|
||||
INT32 splitflags = 0;
|
||||
if (!mode)
|
||||
{
|
||||
splitflags = V_HUDTRANS|V_SLIDEIN|V_SNAPTOTOP|V_SNAPTORIGHT|V_SPLITSCREEN;
|
||||
|
||||
#ifndef TESTOVERTIMEINFREEPLAY
|
||||
if (battlecapsules) // capsules override any time limit settings
|
||||
;
|
||||
else
|
||||
#endif
|
||||
if (bossinfo.boss == true)
|
||||
;
|
||||
else if (timelimitintics > 0 && (gametyperules & GTR_TIMELIMIT)) // TODO
|
||||
if (timelimitintics > 0)
|
||||
{
|
||||
if (drawtime >= timelimitintics)
|
||||
{
|
||||
if (((drawtime-timelimitintics)/TICRATE) & 1)
|
||||
{
|
||||
dontdraw = true;
|
||||
}
|
||||
jitter = 2;
|
||||
if (drawtime & 2)
|
||||
jitter = -jitter;
|
||||
drawtime = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
drawtime = timelimitintics - drawtime;
|
||||
if (secretextratime)
|
||||
;
|
||||
else if (extratimeintics)
|
||||
{
|
||||
jitter = 2;
|
||||
if (leveltime & 1)
|
||||
jitter = -jitter;
|
||||
}
|
||||
else if (drawtime <= 5*TICRATE)
|
||||
{
|
||||
jitter = ((drawtime <= 3*TICRATE) && (((drawtime-1) % TICRATE) >= TICRATE-2))
|
||||
? 3 : 1;
|
||||
if (drawtime & 2)
|
||||
jitter = -jitter;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1422,57 +1436,39 @@ void K_drawKartTimestamp(tic_t drawtime, INT32 TX, INT32 TY, INT16 emblemmap, UI
|
|||
|
||||
worktime = drawtime/(60*TICRATE);
|
||||
|
||||
if (worktime >= 100)
|
||||
{
|
||||
jitter = (drawtime & 1 ? 1 : -1);
|
||||
worktime = 99;
|
||||
drawtime = (100*(60*TICRATE))-1;
|
||||
}
|
||||
|
||||
if (mode && !drawtime)
|
||||
V_DrawKartString(TX, TY+3, splitflags, va("--'--\"--"));
|
||||
else if (dontdraw) // overtime flash
|
||||
;
|
||||
else if (worktime < 100) // 99:99:99 only
|
||||
else
|
||||
{
|
||||
// zero minute
|
||||
if (worktime < 10)
|
||||
{
|
||||
V_DrawKartString(TX, TY+3, splitflags, va("0"));
|
||||
// minutes time 0 __ __
|
||||
V_DrawKartString(TX+12, TY+3, splitflags, va("%d", worktime));
|
||||
}
|
||||
// minutes time 0 __ __
|
||||
else
|
||||
V_DrawKartString(TX, TY+3, splitflags, va("%d", worktime));
|
||||
// minutes time 00 __ __
|
||||
V_DrawKartString(TX, TY+3+jitter, splitflags, va("%d", worktime/10));
|
||||
V_DrawKartString(TX+12, TY+3-jitter, splitflags, va("%d", worktime%10));
|
||||
|
||||
// apostrophe location _'__ __
|
||||
V_DrawKartString(TX+24, TY+3, splitflags, va("'"));
|
||||
|
||||
worktime = (drawtime/TICRATE % 60);
|
||||
|
||||
// zero second _ 0_ __
|
||||
if (worktime < 10)
|
||||
{
|
||||
V_DrawKartString(TX+36, TY+3, splitflags, va("0"));
|
||||
// seconds time _ _0 __
|
||||
V_DrawKartString(TX+48, TY+3, splitflags, va("%d", worktime));
|
||||
}
|
||||
// zero second _ 00 __
|
||||
else
|
||||
V_DrawKartString(TX+36, TY+3, splitflags, va("%d", worktime));
|
||||
// seconds time _ 00 __
|
||||
V_DrawKartString(TX+36, TY+3+jitter, splitflags, va("%d", worktime/10));
|
||||
V_DrawKartString(TX+48, TY+3-jitter, splitflags, va("%d", worktime%10));
|
||||
|
||||
// quotation mark location _ __"__
|
||||
V_DrawKartString(TX+60, TY+3, splitflags, va("\""));
|
||||
|
||||
worktime = G_TicsToCentiseconds(drawtime);
|
||||
|
||||
// zero tick _ __ 0_
|
||||
if (worktime < 10)
|
||||
{
|
||||
V_DrawKartString(TX+72, TY+3, splitflags, va("0"));
|
||||
// tics _ __ _0
|
||||
V_DrawKartString(TX+84, TY+3, splitflags, va("%d", worktime));
|
||||
}
|
||||
// zero tick _ __ 00
|
||||
else
|
||||
V_DrawKartString(TX+72, TY+3, splitflags, va("%d", worktime));
|
||||
// tics _ __ 00
|
||||
V_DrawKartString(TX+72, TY+3+jitter, splitflags, va("%d", worktime/10));
|
||||
V_DrawKartString(TX+84, TY+3-jitter, splitflags, va("%d", worktime%10));
|
||||
}
|
||||
else if ((drawtime/TICRATE) & 1)
|
||||
V_DrawKartString(TX, TY+3, splitflags, va("99'59\"99"));
|
||||
|
||||
if (emblemmap && (modeattacking || (mode == 1)) && !demo.playback) // emblem time!
|
||||
{
|
||||
|
|
@ -3326,16 +3322,15 @@ static void K_drawKartMinimapIcon(fixed_t objx, fixed_t objy, INT32 hudx, INT32
|
|||
|
||||
static void K_drawKartMinimap(void)
|
||||
{
|
||||
patch_t *AutomapPic;
|
||||
patch_t *AutomapPic, *workingPic;
|
||||
INT32 i = 0;
|
||||
INT32 x, y;
|
||||
INT32 minimaptrans = 4;
|
||||
INT32 splitflags = 0;
|
||||
UINT8 skin = 0;
|
||||
UINT8 *colormap = NULL;
|
||||
SINT8 localplayers[4];
|
||||
SINT8 localplayers[MAXSPLITSCREENPLAYERS];
|
||||
SINT8 numlocalplayers = 0;
|
||||
INT32 hyu = hyudorotime;
|
||||
mobj_t *mobj, *next; // for SPB drawing (or any other item(s) we may wanna draw, I dunno!)
|
||||
fixed_t interpx, interpy;
|
||||
|
||||
|
|
@ -3412,12 +3407,9 @@ static void K_drawKartMinimap(void)
|
|||
}
|
||||
|
||||
// initialize
|
||||
for (i = 0; i < 4; i++)
|
||||
for (i = 0; i < MAXSPLITSCREENPLAYERS; i++)
|
||||
localplayers[i] = -1;
|
||||
|
||||
if (gametype == GT_RACE)
|
||||
hyu *= 2; // double in race
|
||||
|
||||
// Player's tiny icons on the Automap. (drawn opposite direction so player 1 is drawn last in splitscreen)
|
||||
if (ghosts)
|
||||
{
|
||||
|
|
@ -3448,8 +3440,7 @@ static void K_drawKartMinimap(void)
|
|||
if (!stplyr->mo || stplyr->spectator || stplyr->exiting)
|
||||
return;
|
||||
|
||||
localplayers[numlocalplayers] = stplyr-players;
|
||||
numlocalplayers++;
|
||||
localplayers[numlocalplayers++] = stplyr-players;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -3457,50 +3448,60 @@ static void K_drawKartMinimap(void)
|
|||
{
|
||||
if (!playeringame[i])
|
||||
continue;
|
||||
if (!players[i].mo || players[i].spectator || players[i].exiting)
|
||||
if (!players[i].mo || players[i].spectator || !players[i].mo->skin || players[i].exiting)
|
||||
continue;
|
||||
|
||||
if (i != displayplayers[0] || r_splitscreen)
|
||||
{
|
||||
if (gametype == GT_BATTLE && players[i].bumpers <= 0)
|
||||
continue;
|
||||
|
||||
if (players[i].hyudorotimer > 0)
|
||||
{
|
||||
if (!((players[i].hyudorotimer < TICRATE/2
|
||||
|| players[i].hyudorotimer > hyu-(TICRATE/2))
|
||||
&& !(leveltime & 1)))
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (i == displayplayers[0] || i == displayplayers[1] || i == displayplayers[2] || i == displayplayers[3])
|
||||
{
|
||||
// Draw display players on top of everything else
|
||||
localplayers[numlocalplayers] = i;
|
||||
numlocalplayers++;
|
||||
localplayers[numlocalplayers++] = i;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (players[i].mo->skin)
|
||||
skin = ((skin_t*)players[i].mo->skin)-skins;
|
||||
else
|
||||
skin = 0;
|
||||
// Now we know it's not a display player, handle non-local player exceptions.
|
||||
if ((gametyperules & GTR_BUMPERS) && players[i].bumpers <= 0)
|
||||
continue;
|
||||
|
||||
if (players[i].mo->color)
|
||||
if (players[i].hyudorotimer > 0)
|
||||
{
|
||||
if (players[i].mo->colorized)
|
||||
colormap = R_GetTranslationColormap(TC_RAINBOW, players[i].mo->color, GTC_CACHE);
|
||||
else
|
||||
colormap = R_GetTranslationColormap(skin, players[i].mo->color, GTC_CACHE);
|
||||
if (!((players[i].hyudorotimer < TICRATE/2
|
||||
|| players[i].hyudorotimer > hyudorotime-(TICRATE/2))
|
||||
&& !(leveltime & 1)))
|
||||
continue;
|
||||
}
|
||||
|
||||
mobj = players[i].mo;
|
||||
|
||||
if (mobj->health <= 0 && (players[i].pflags & PF_NOCONTEST))
|
||||
{
|
||||
workingPic = kp_nocontestminimap;
|
||||
R_GetTranslationColormap(0, mobj->color, GTC_CACHE);
|
||||
|
||||
if (mobj->tracer && !P_MobjWasRemoved(mobj->tracer))
|
||||
mobj = mobj->tracer;
|
||||
}
|
||||
else
|
||||
colormap = NULL;
|
||||
{
|
||||
skin = ((skin_t*)mobj->skin)-skins;
|
||||
|
||||
interpx = R_InterpolateFixed(players[i].mo->old_x, players[i].mo->x);
|
||||
interpy = R_InterpolateFixed(players[i].mo->old_y, players[i].mo->y);
|
||||
workingPic = faceprefix[skin][FACE_MINIMAP];
|
||||
|
||||
if (mobj->color)
|
||||
{
|
||||
if (mobj->colorized)
|
||||
colormap = R_GetTranslationColormap(TC_RAINBOW, mobj->color, GTC_CACHE);
|
||||
else
|
||||
colormap = R_GetTranslationColormap(skin, mobj->color, GTC_CACHE);
|
||||
}
|
||||
else
|
||||
colormap = NULL;
|
||||
}
|
||||
|
||||
interpx = R_InterpolateFixed(mobj->old_x, mobj->x);
|
||||
interpy = R_InterpolateFixed(mobj->old_y, mobj->y);
|
||||
|
||||
K_drawKartMinimapIcon(interpx, interpy, x, y, splitflags, faceprefix[skin][FACE_MINIMAP], colormap, AutomapPic);
|
||||
|
||||
// Target reticule
|
||||
if ((gametype == GT_RACE && players[i].position == spbplace)
|
||||
|| (gametype == GT_BATTLE && K_IsPlayerWanted(&players[i])))
|
||||
|
|
@ -3510,27 +3511,48 @@ static void K_drawKartMinimap(void)
|
|||
}
|
||||
}
|
||||
|
||||
// draw SPB(s?)
|
||||
// draw minimap-pertinent objects
|
||||
for (mobj = kitemcap; mobj; mobj = next)
|
||||
{
|
||||
next = mobj->itnext;
|
||||
if (mobj->type == MT_SPB)
|
||||
|
||||
workingPic = NULL;
|
||||
colormap = NULL;
|
||||
|
||||
if (mobj->health <= 0)
|
||||
continue;
|
||||
|
||||
switch (mobj->type)
|
||||
{
|
||||
colormap = NULL;
|
||||
|
||||
if (mobj->target && !P_MobjWasRemoved(mobj->target))
|
||||
{
|
||||
if (mobj->player && mobj->player->skincolor)
|
||||
colormap = R_GetTranslationColormap(TC_RAINBOW, mobj->player->skincolor, GTC_CACHE);
|
||||
else if (mobj->color)
|
||||
case MT_SPB:
|
||||
workingPic = kp_spbminimap;
|
||||
#if 0
|
||||
if (mobj->target && !P_MobjWasRemoved(mobj->target) && mobj->target->player && mobj->target->player->skincolor)
|
||||
{
|
||||
colormap = R_GetTranslationColormap(TC_RAINBOW, mobj->target->player->skincolor, GTC_CACHE);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
if (mobj->color)
|
||||
{
|
||||
colormap = R_GetTranslationColormap(TC_RAINBOW, mobj->color, GTC_CACHE);
|
||||
}
|
||||
}
|
||||
|
||||
interpx = R_InterpolateFixed(mobj->old_x, mobj->x);
|
||||
interpy = R_InterpolateFixed(mobj->old_y, mobj->y);
|
||||
|
||||
K_drawKartMinimapIcon(interpx, interpy, x, y, splitflags, kp_spbminimap, colormap, AutomapPic);
|
||||
break;
|
||||
case MT_BATTLECAPSULE:
|
||||
workingPic = kp_capsuleminimap[(mobj->extravalue1 != 0 ? 1 : 0)];
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (!workingPic)
|
||||
continue;
|
||||
|
||||
interpx = R_InterpolateFixed(mobj->old_x, mobj->x);
|
||||
interpy = R_InterpolateFixed(mobj->old_y, mobj->y);
|
||||
|
||||
K_drawKartMinimapIcon(interpx, interpy, x, y, splitflags, workingPic, colormap, AutomapPic);
|
||||
}
|
||||
|
||||
// draw our local players here, opaque.
|
||||
|
|
@ -3569,28 +3591,43 @@ static void K_drawKartMinimap(void)
|
|||
|
||||
for (i = 0; i < numlocalplayers; i++)
|
||||
{
|
||||
if (i == -1)
|
||||
if (localplayers[i] == -1)
|
||||
continue; // this doesn't interest us
|
||||
|
||||
if (players[localplayers[i]].mo->skin)
|
||||
skin = ((skin_t*)players[localplayers[i]].mo->skin)-skins;
|
||||
else
|
||||
skin = 0;
|
||||
if ((players[i].hyudorotimer > 0) && (leveltime & 1))
|
||||
continue;
|
||||
|
||||
if (players[localplayers[i]].mo->color)
|
||||
mobj = players[localplayers[i]].mo;
|
||||
|
||||
if (mobj->health <= 0 && (players[localplayers[i]].pflags & PF_NOCONTEST))
|
||||
{
|
||||
if (players[localplayers[i]].mo->colorized)
|
||||
colormap = R_GetTranslationColormap(TC_RAINBOW, players[localplayers[i]].mo->color, GTC_CACHE);
|
||||
else
|
||||
colormap = R_GetTranslationColormap(skin, players[localplayers[i]].mo->color, GTC_CACHE);
|
||||
workingPic = kp_nocontestminimap;
|
||||
R_GetTranslationColormap(0, mobj->color, GTC_CACHE);
|
||||
|
||||
if (mobj->tracer && !P_MobjWasRemoved(mobj->tracer))
|
||||
mobj = mobj->tracer;
|
||||
}
|
||||
else
|
||||
colormap = NULL;
|
||||
{
|
||||
skin = ((skin_t*)mobj->skin)-skins;
|
||||
|
||||
interpx = R_InterpolateFixed(players[localplayers[i]].mo->old_x, players[localplayers[i]].mo->x);
|
||||
interpy = R_InterpolateFixed(players[localplayers[i]].mo->old_y, players[localplayers[i]].mo->y);
|
||||
workingPic = faceprefix[skin][FACE_MINIMAP];
|
||||
|
||||
K_drawKartMinimapIcon(interpx, interpy, x, y, splitflags, faceprefix[skin][FACE_MINIMAP], colormap, AutomapPic);
|
||||
if (mobj->color)
|
||||
{
|
||||
if (mobj->colorized)
|
||||
colormap = R_GetTranslationColormap(TC_RAINBOW, mobj->color, GTC_CACHE);
|
||||
else
|
||||
colormap = R_GetTranslationColormap(skin, mobj->color, GTC_CACHE);
|
||||
}
|
||||
else
|
||||
colormap = NULL;
|
||||
}
|
||||
|
||||
interpx = R_InterpolateFixed(mobj->old_x, mobj->x);
|
||||
interpy = R_InterpolateFixed(mobj->old_y, mobj->y);
|
||||
|
||||
K_drawKartMinimapIcon(interpx, interpy, x, y, splitflags, workingPic, colormap, AutomapPic);
|
||||
|
||||
// Target reticule
|
||||
if ((gametype == GT_RACE && players[localplayers[i]].position == spbplace)
|
||||
|
|
@ -3601,6 +3638,60 @@ static void K_drawKartMinimap(void)
|
|||
}
|
||||
}
|
||||
|
||||
static void K_drawKartFinish(boolean finish)
|
||||
{
|
||||
INT32 timer, minsplitstationary, pnum = 0, splitflags = V_SPLITSCREEN;
|
||||
patch_t **kptodraw;
|
||||
|
||||
if (finish)
|
||||
{
|
||||
timer = stplyr->karthud[khud_finish];
|
||||
kptodraw = kp_racefinish;
|
||||
minsplitstationary = 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
timer = stplyr->karthud[khud_fault];
|
||||
kptodraw = kp_racefault;
|
||||
minsplitstationary = 1;
|
||||
}
|
||||
|
||||
if (!timer || timer > 2*TICRATE)
|
||||
return;
|
||||
|
||||
if ((timer % (2*5)) / 5) // blink
|
||||
pnum = 1;
|
||||
|
||||
if (r_splitscreen > 0)
|
||||
pnum += (r_splitscreen > 1) ? 2 : 4;
|
||||
|
||||
if (r_splitscreen >= minsplitstationary) // 3/4p, stationary FIN
|
||||
{
|
||||
V_DrawScaledPatch(STCD_X - (SHORT(kptodraw[pnum]->width)/2), STCD_Y - (SHORT(kptodraw[pnum]->height)/2), splitflags, kptodraw[pnum]);
|
||||
return;
|
||||
}
|
||||
|
||||
//else -- 1/2p, scrolling FINISH
|
||||
{
|
||||
INT32 x, xval, ox, interpx;
|
||||
|
||||
x = ((vid.width<<FRACBITS)/vid.dupx);
|
||||
xval = (SHORT(kptodraw[pnum]->width)<<FRACBITS);
|
||||
x = ((TICRATE - timer)*(xval > x ? xval : x))/TICRATE;
|
||||
ox = ((TICRATE - (timer - 1))*(xval > x ? xval : x))/TICRATE;
|
||||
|
||||
interpx = R_InterpolateFixed(ox, x);
|
||||
|
||||
if (r_splitscreen && stplyr == &players[displayplayers[1]])
|
||||
interpx = -interpx;
|
||||
|
||||
V_DrawFixedPatch(interpx + (STCD_X<<FRACBITS) - (xval>>1),
|
||||
(STCD_Y<<FRACBITS) - (SHORT(kptodraw[pnum]->height)<<(FRACBITS-1)),
|
||||
FRACUNIT,
|
||||
splitflags, kptodraw[pnum], NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static void K_drawKartStartBulbs(void)
|
||||
{
|
||||
const UINT8 start_animation[14] = {
|
||||
|
|
@ -3765,39 +3856,11 @@ static void K_drawKartStartCountdown(void)
|
|||
|
||||
if (stplyr->karthud[khud_fault] != 0)
|
||||
{
|
||||
INT32 x, xval;
|
||||
|
||||
if (r_splitscreen > 1) // 3/4p, stationary FIN
|
||||
{
|
||||
pnum += 2;
|
||||
}
|
||||
else if (r_splitscreen == 1) // wide splitscreen
|
||||
{
|
||||
pnum += 4;
|
||||
}
|
||||
|
||||
if ((leveltime % (2*5)) / 5) // blink
|
||||
pnum += 1;
|
||||
|
||||
if (r_splitscreen == 0)
|
||||
{
|
||||
x = ((vid.width<<FRACBITS)/vid.dupx);
|
||||
xval = (SHORT(kp_racefault[pnum]->width)<<FRACBITS);
|
||||
x = ((TICRATE - stplyr->karthud[khud_fault])*(xval > x ? xval : x))/TICRATE;
|
||||
|
||||
V_DrawFixedPatch(x + (STCD_X<<FRACBITS) - (xval>>1),
|
||||
(STCD_Y<<FRACBITS) - (SHORT(kp_racefault[pnum]->height)<<(FRACBITS-1)),
|
||||
FRACUNIT,
|
||||
V_SPLITSCREEN, kp_racefault[pnum], NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
V_DrawScaledPatch(STCD_X - (SHORT(kp_racefault[pnum]->width)/2), STCD_Y - (SHORT(kp_racefault[pnum]->height)/2), V_SPLITSCREEN, kp_racefault[pnum]);
|
||||
}
|
||||
K_drawKartFinish(false);
|
||||
}
|
||||
else if (leveltime >= introtime && leveltime < starttime-(3*TICRATE))
|
||||
{
|
||||
if (bossinfo.boss == false)
|
||||
if (numbulbs > 1)
|
||||
K_drawKartStartBulbs();
|
||||
}
|
||||
else
|
||||
|
|
@ -3839,47 +3902,6 @@ static void K_drawKartStartCountdown(void)
|
|||
}
|
||||
}
|
||||
|
||||
static void K_drawKartFinish(void)
|
||||
{
|
||||
INT32 pnum = 0, splitflags = V_SPLITSCREEN;
|
||||
|
||||
if (!stplyr->karthud[khud_cardanimation] || stplyr->karthud[khud_cardanimation] >= 2*TICRATE)
|
||||
return;
|
||||
|
||||
if ((stplyr->karthud[khud_cardanimation] % (2*5)) / 5) // blink
|
||||
pnum = 1;
|
||||
|
||||
if (r_splitscreen > 1) // 3/4p, stationary FIN
|
||||
{
|
||||
pnum += 2;
|
||||
V_DrawScaledPatch(STCD_X - (SHORT(kp_racefinish[pnum]->width)/2), STCD_Y - (SHORT(kp_racefinish[pnum]->height)/2), splitflags, kp_racefinish[pnum]);
|
||||
return;
|
||||
}
|
||||
|
||||
//else -- 1/2p, scrolling FINISH
|
||||
{
|
||||
INT32 x, xval, ox, interpx;
|
||||
|
||||
if (r_splitscreen) // wide splitscreen
|
||||
pnum += 4;
|
||||
|
||||
x = ((vid.width<<FRACBITS)/vid.dupx);
|
||||
xval = (SHORT(kp_racefinish[pnum]->width)<<FRACBITS);
|
||||
x = ((TICRATE - stplyr->karthud[khud_cardanimation])*(xval > x ? xval : x))/TICRATE;
|
||||
ox = ((TICRATE - (stplyr->karthud[khud_cardanimation] - 1))*(xval > x ? xval : x))/TICRATE;
|
||||
|
||||
interpx = R_InterpolateFixed(ox, x);
|
||||
|
||||
if (r_splitscreen && stplyr == &players[displayplayers[1]])
|
||||
interpx = -interpx;
|
||||
|
||||
V_DrawFixedPatch(interpx + (STCD_X<<FRACBITS) - (xval>>1),
|
||||
(STCD_Y<<FRACBITS) - (SHORT(kp_racefinish[pnum]->height)<<(FRACBITS-1)),
|
||||
FRACUNIT,
|
||||
splitflags, kp_racefinish[pnum], NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static void K_drawBattleFullscreen(void)
|
||||
{
|
||||
INT32 x = BASEVIDWIDTH/2;
|
||||
|
|
@ -3931,19 +3953,19 @@ static void K_drawBattleFullscreen(void)
|
|||
{
|
||||
if (stplyr == &players[displayplayers[0]])
|
||||
V_DrawFadeScreen(0xFF00, 16);
|
||||
if (stplyr->exiting < 6*TICRATE && !stplyr->spectator)
|
||||
if (exitcountdown <= 6*TICRATE && !stplyr->spectator)
|
||||
{
|
||||
patch_t *p = kp_battlecool;
|
||||
|
||||
if (K_IsPlayerLosing(stplyr))
|
||||
p = kp_battlelose;
|
||||
else if (stplyr->position == 1)
|
||||
else if (stplyr->position == 1 && (!battlecapsules || numtargets >= maptargets))
|
||||
p = kp_battlewin;
|
||||
|
||||
V_DrawFixedPatch(x<<FRACBITS, y<<FRACBITS, scale, splitflags, p, NULL);
|
||||
}
|
||||
else
|
||||
K_drawKartFinish();
|
||||
|
||||
K_drawKartFinish(true);
|
||||
}
|
||||
else if (stplyr->bumpers <= 0 && stplyr->karmadelay && !stplyr->spectator && drawcomebacktimer)
|
||||
{
|
||||
|
|
@ -3985,7 +4007,7 @@ static void K_drawBattleFullscreen(void)
|
|||
}
|
||||
}
|
||||
|
||||
if (netgame && !stplyr->spectator) // FREE PLAY?
|
||||
// FREE PLAY?
|
||||
{
|
||||
UINT8 i;
|
||||
|
||||
|
|
@ -3994,11 +4016,11 @@ static void K_drawBattleFullscreen(void)
|
|||
{
|
||||
if (i == displayplayers[0])
|
||||
continue;
|
||||
if (playeringame[i] && !stplyr->spectator)
|
||||
return;
|
||||
if (playeringame[i] && !players[i].spectator)
|
||||
break;
|
||||
}
|
||||
|
||||
if (LUA_HudEnabled(hud_freeplay))
|
||||
if (i != MAXPLAYERS)
|
||||
K_drawKartFreePlay();
|
||||
}
|
||||
}
|
||||
|
|
@ -4392,8 +4414,13 @@ static void K_drawTrickCool(void)
|
|||
|
||||
void K_drawKartFreePlay(void)
|
||||
{
|
||||
// no splitscreen support because it's not FREE PLAY if you have more than one player in-game
|
||||
// (you fool, you can take splitscreen online. :V)
|
||||
// Doesn't support splitscreens higher than 2 for real estate reasons.
|
||||
|
||||
if (!LUA_HudEnabled(hud_freeplay))
|
||||
return;
|
||||
|
||||
if (modeattacking || grandprixinfo.gp || bossinfo.boss || stplyr->spectator)
|
||||
return;
|
||||
|
||||
if (lt_exitticker < TICRATE/2)
|
||||
return;
|
||||
|
|
@ -4402,7 +4429,7 @@ void K_drawKartFreePlay(void)
|
|||
return;
|
||||
|
||||
V_DrawKartString((BASEVIDWIDTH - (LAPS_X+1)) - 72, // mirror the laps thingy
|
||||
LAPS_Y+3, V_HUDTRANS|V_SLIDEIN|V_SNAPTOBOTTOM|V_SNAPTORIGHT, "FREE PLAY");
|
||||
LAPS_Y+3, V_HUDTRANS|V_SLIDEIN|V_SNAPTOBOTTOM|V_SNAPTORIGHT|V_SPLITSCREEN, "FREE PLAY");
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -4750,7 +4777,7 @@ void K_drawKartHUD(void)
|
|||
if (gametype == GT_RACE && !freecam)
|
||||
{
|
||||
if (stplyr->exiting)
|
||||
K_drawKartFinish();
|
||||
K_drawKartFinish(true);
|
||||
else if (stplyr->karthud[khud_lapanimation] && !r_splitscreen)
|
||||
K_drawLapStartAnim();
|
||||
}
|
||||
|
|
@ -4766,11 +4793,8 @@ void K_drawKartHUD(void)
|
|||
V_DrawScaledPatch(BASEVIDWIDTH/2 - (SHORT(kp_yougotem->width)/2), 32, V_HUDTRANS, kp_yougotem);
|
||||
|
||||
// Draw FREE PLAY.
|
||||
if (islonesome && !modeattacking && !bossinfo.boss && !stplyr->spectator)
|
||||
{
|
||||
if (LUA_HudEnabled(hud_freeplay))
|
||||
K_drawKartFreePlay();
|
||||
}
|
||||
if (islonesome)
|
||||
K_drawKartFreePlay();
|
||||
|
||||
if (r_splitscreen == 0 && (stplyr->pflags & PF_WRONGWAY) && ((leveltime / 8) & 1))
|
||||
{
|
||||
|
|
|
|||
204
src/k_kart.c
204
src/k_kart.c
|
|
@ -40,6 +40,8 @@
|
|||
#include "k_collide.h"
|
||||
#include "k_follower.h"
|
||||
#include "k_objects.h"
|
||||
#include "k_grandprix.h"
|
||||
#include "k_specialstage.h"
|
||||
|
||||
// SOME IMPORTANT VARIABLES DEFINED IN DOOMDEF.H:
|
||||
// gamespeed is cc (0 for easy, 1 for normal, 2 for hard)
|
||||
|
|
@ -95,70 +97,86 @@ void K_TimerReset(void)
|
|||
{
|
||||
starttime = introtime = 3;
|
||||
numbulbs = 1;
|
||||
inDuel = false;
|
||||
inDuel = rainbowstartavailable = false;
|
||||
timelimitintics = extratimeintics = secretextratime = 0;
|
||||
}
|
||||
|
||||
void K_TimerInit(void)
|
||||
{
|
||||
UINT8 i;
|
||||
UINT8 numPlayers = 0;//, numspec = 0;
|
||||
UINT8 numPlayers = 0;
|
||||
boolean domodeattack = ((modeattacking != ATTACKING_NONE)
|
||||
|| (grandprixinfo.gp == true && grandprixinfo.eventmode != GPEVENT_NONE));
|
||||
|
||||
if (!bossinfo.boss)
|
||||
if (specialStage.active == true)
|
||||
{
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
K_InitSpecialStage();
|
||||
}
|
||||
else if (bossinfo.boss == false)
|
||||
{
|
||||
if (!domodeattack)
|
||||
{
|
||||
if (!playeringame[i])
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
continue;
|
||||
if (!playeringame[i] || players[i].spectator)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
numPlayers++;
|
||||
}
|
||||
|
||||
if (players[i].spectator == true)
|
||||
if (numPlayers < 2)
|
||||
{
|
||||
//numspec++;
|
||||
continue;
|
||||
domodeattack = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
numbulbs = 5;
|
||||
rainbowstartavailable = true;
|
||||
|
||||
numPlayers++;
|
||||
}
|
||||
// 1v1 activates DUEL rules!
|
||||
inDuel = (numPlayers == 2);
|
||||
|
||||
// 1v1 activates DUEL rules!
|
||||
inDuel = (numPlayers == 2);
|
||||
|
||||
if (numPlayers >= 2)
|
||||
{
|
||||
rainbowstartavailable = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
rainbowstartavailable = false;
|
||||
}
|
||||
|
||||
// No intro in Record Attack / 1v1
|
||||
// Leave unset for the value in K_TimerReset
|
||||
if (numPlayers > 2)
|
||||
{
|
||||
introtime = (108) + 5; // 108 for rotation, + 5 for white fade
|
||||
}
|
||||
|
||||
numbulbs = 5;
|
||||
|
||||
if (numPlayers > 2)
|
||||
{
|
||||
numbulbs += (numPlayers-2);
|
||||
if (!inDuel)
|
||||
{
|
||||
introtime = (108) + 5; // 108 for rotation, + 5 for white fade
|
||||
numbulbs += (numPlayers-2); // Extra POSITION!! time
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
starttime = (introtime + (3*TICRATE)) + ((2*TICRATE) + (numbulbs * bulbtime)); // Start countdown time, + buffer time
|
||||
}
|
||||
|
||||
// NOW you can try to spawn in the Battle capsules, if there's not enough players for a match
|
||||
K_BattleInit();
|
||||
K_BattleInit(domodeattack);
|
||||
|
||||
if ((gametyperules & GTR_TIMELIMIT) && !bossinfo.boss && !modeattacking)
|
||||
{
|
||||
if (!K_CanChangeRules(true))
|
||||
{
|
||||
if (battlecapsules)
|
||||
{
|
||||
timelimitintics = (20*TICRATE);
|
||||
}
|
||||
else
|
||||
{
|
||||
timelimitintics = timelimits[gametype] * (60*TICRATE);
|
||||
}
|
||||
}
|
||||
else
|
||||
#ifndef TESTOVERTIMEINFREEPLAY
|
||||
if (!battlecapsules)
|
||||
#endif
|
||||
{
|
||||
timelimitintics = cv_timelimit.value * (60*TICRATE);
|
||||
}
|
||||
}
|
||||
|
||||
if (inDuel == true)
|
||||
{
|
||||
K_SpawnDuelOnlyItems();
|
||||
}
|
||||
|
||||
//CONS_Printf("numbulbs set to %d (%d players, %d spectators) on tic %d\n", numbulbs, numPlayers, numspec, leveltime);
|
||||
}
|
||||
|
||||
UINT32 K_GetPlayerDontDrawFlag(player_t *player)
|
||||
|
|
@ -316,6 +334,7 @@ void K_RegisterKartStuff(void)
|
|||
CV_RegisterVar(&cv_kartdebugcolorize);
|
||||
CV_RegisterVar(&cv_kartdebugdirector);
|
||||
CV_RegisterVar(&cv_spbtest);
|
||||
CV_RegisterVar(&cv_gptest);
|
||||
}
|
||||
|
||||
//}
|
||||
|
|
@ -325,10 +344,10 @@ boolean K_IsPlayerLosing(player_t *player)
|
|||
INT32 winningpos = 1;
|
||||
UINT8 i, pcount = 0;
|
||||
|
||||
if (battlecapsules && player->bumpers <= 0)
|
||||
return true; // DNF in break the capsules
|
||||
if (battlecapsules && numtargets == 0)
|
||||
return true; // Didn't even TRY?
|
||||
|
||||
if (bossinfo.boss)
|
||||
if (battlecapsules || bossinfo.boss)
|
||||
return (player->bumpers <= 0); // anything short of DNF is COOL
|
||||
|
||||
if (player->position == 1)
|
||||
|
|
@ -467,6 +486,40 @@ static UINT8 K_KartItemOddsBattle[NUMKARTRESULTS][2] =
|
|||
{ 5, 1 } // Jawz x2
|
||||
};
|
||||
|
||||
static UINT8 K_KartItemOddsSpecial[NUMKARTRESULTS-1][4] =
|
||||
{
|
||||
//M N O P
|
||||
{ 1, 1, 0, 0 }, // Sneaker
|
||||
{ 0, 0, 0, 0 }, // Rocket Sneaker
|
||||
{ 0, 0, 0, 0 }, // Invincibility
|
||||
{ 0, 0, 0, 0 }, // Banana
|
||||
{ 0, 0, 0, 0 }, // Eggman Monitor
|
||||
{ 1, 1, 0, 0 }, // Orbinaut
|
||||
{ 1, 1, 0, 0 }, // Jawz
|
||||
{ 0, 0, 0, 0 }, // Mine
|
||||
{ 0, 0, 0, 0 }, // Land Mine
|
||||
{ 0, 0, 0, 0 }, // Ballhog
|
||||
{ 0, 0, 0, 1 }, // Self-Propelled Bomb
|
||||
{ 0, 0, 0, 0 }, // Grow
|
||||
{ 0, 0, 0, 0 }, // Shrink
|
||||
{ 0, 0, 0, 0 }, // Lightning Shield
|
||||
{ 0, 0, 0, 0 }, // Bubble Shield
|
||||
{ 0, 0, 0, 0 }, // Flame Shield
|
||||
{ 0, 0, 0, 0 }, // Hyudoro
|
||||
{ 0, 0, 0, 0 }, // Pogo Spring
|
||||
{ 0, 0, 0, 0 }, // Super Ring
|
||||
{ 0, 0, 0, 0 }, // Kitchen Sink
|
||||
{ 0, 0, 0, 0 }, // Drop Target
|
||||
{ 0, 0, 0, 0 }, // Garden Top
|
||||
{ 0, 1, 1, 0 }, // Sneaker x2
|
||||
{ 0, 0, 1, 1 }, // Sneaker x3
|
||||
{ 0, 0, 0, 0 }, // Banana x3
|
||||
{ 0, 0, 0, 0 }, // Banana x10
|
||||
{ 0, 1, 1, 0 }, // Orbinaut x3
|
||||
{ 0, 0, 1, 1 }, // Orbinaut x4
|
||||
{ 0, 0, 1, 1 } // Jawz x2
|
||||
};
|
||||
|
||||
#define DISTVAR (2048) // Magic number distance for use with item roulette tiers
|
||||
#define SPBSTARTDIST (6*DISTVAR) // Distance when SPB can start appearing
|
||||
#define SPBFORCEDIST (12*DISTVAR) // Distance when SPB is forced onto the next person who rolls an item
|
||||
|
|
@ -6449,7 +6502,8 @@ static void K_DoShrink(player_t *user)
|
|||
{
|
||||
next = mobj->itnext;
|
||||
|
||||
if (mobj->type == MT_SPB)
|
||||
if (mobj->type == MT_SPB
|
||||
|| mobj->type == MT_BATTLECAPSULE)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
|
@ -7762,7 +7816,7 @@ void K_KartPlayerHUDUpdate(player_t *player)
|
|||
|
||||
if (!(player->pflags & PF_FAULT))
|
||||
player->karthud[khud_fault] = 0;
|
||||
else if (player->karthud[khud_fault] > 0 && player->karthud[khud_fault] < 2*TICRATE)
|
||||
else if (player->karthud[khud_fault] > 0 && player->karthud[khud_fault] <= 2*TICRATE)
|
||||
player->karthud[khud_fault]++;
|
||||
|
||||
if (player->karthud[khud_itemblink] && player->karthud[khud_itemblink]-- <= 0)
|
||||
|
|
@ -7771,30 +7825,33 @@ void K_KartPlayerHUDUpdate(player_t *player)
|
|||
player->karthud[khud_itemblink] = 0;
|
||||
}
|
||||
|
||||
if (gametype == GT_RACE)
|
||||
if (!(gametyperules & GTR_SPHERES))
|
||||
{
|
||||
// 0 is the fast spin animation, set at 30 tics of ring boost or higher!
|
||||
if (player->ringboost >= 30)
|
||||
player->karthud[khud_ringdelay] = 0;
|
||||
else
|
||||
player->karthud[khud_ringdelay] = ((RINGANIM_DELAYMAX+1) * (30 - player->ringboost)) / 30;
|
||||
if (player->mo && player->mo->hitlag <= 0)
|
||||
{
|
||||
// 0 is the fast spin animation, set at 30 tics of ring boost or higher!
|
||||
if (player->ringboost >= 30)
|
||||
player->karthud[khud_ringdelay] = 0;
|
||||
else
|
||||
player->karthud[khud_ringdelay] = ((RINGANIM_DELAYMAX+1) * (30 - player->ringboost)) / 30;
|
||||
|
||||
if (player->karthud[khud_ringframe] == 0 && player->karthud[khud_ringdelay] > RINGANIM_DELAYMAX)
|
||||
{
|
||||
player->karthud[khud_ringframe] = 0;
|
||||
player->karthud[khud_ringtics] = 0;
|
||||
}
|
||||
else if ((player->karthud[khud_ringtics]--) <= 0)
|
||||
{
|
||||
if (player->karthud[khud_ringdelay] == 0) // fast spin animation
|
||||
if (player->karthud[khud_ringframe] == 0 && player->karthud[khud_ringdelay] > RINGANIM_DELAYMAX)
|
||||
{
|
||||
player->karthud[khud_ringframe] = ((player->karthud[khud_ringframe]+2) % RINGANIM_NUMFRAMES);
|
||||
player->karthud[khud_ringframe] = 0;
|
||||
player->karthud[khud_ringtics] = 0;
|
||||
}
|
||||
else
|
||||
else if ((player->karthud[khud_ringtics]--) <= 0)
|
||||
{
|
||||
player->karthud[khud_ringframe] = ((player->karthud[khud_ringframe]+1) % RINGANIM_NUMFRAMES);
|
||||
player->karthud[khud_ringtics] = min(RINGANIM_DELAYMAX, player->karthud[khud_ringdelay])-1;
|
||||
if (player->karthud[khud_ringdelay] == 0) // fast spin animation
|
||||
{
|
||||
player->karthud[khud_ringframe] = ((player->karthud[khud_ringframe]+2) % RINGANIM_NUMFRAMES);
|
||||
player->karthud[khud_ringtics] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
player->karthud[khud_ringframe] = ((player->karthud[khud_ringframe]+1) % RINGANIM_NUMFRAMES);
|
||||
player->karthud[khud_ringtics] = min(RINGANIM_DELAYMAX, player->karthud[khud_ringdelay])-1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -7824,16 +7881,20 @@ void K_KartPlayerHUDUpdate(player_t *player)
|
|||
player->karthud[khud_ringspblock] = (leveltime % 14); // reset to normal anim next time
|
||||
}
|
||||
|
||||
if (player->exiting)
|
||||
{
|
||||
if (player->karthud[khud_finish] <= 2*TICRATE)
|
||||
player->karthud[khud_finish]++;
|
||||
}
|
||||
else
|
||||
player->karthud[khud_finish] = 0;
|
||||
|
||||
if ((gametyperules & GTR_BUMPERS) && (player->exiting || player->karmadelay))
|
||||
{
|
||||
if (player->exiting)
|
||||
{
|
||||
if (player->exiting < 6*TICRATE)
|
||||
if (exitcountdown < 6*TICRATE)
|
||||
player->karthud[khud_cardanimation] += ((164-player->karthud[khud_cardanimation])/8)+1;
|
||||
else if (player->exiting == 6*TICRATE)
|
||||
player->karthud[khud_cardanimation] = 0;
|
||||
else if (player->karthud[khud_cardanimation] < 2*TICRATE)
|
||||
player->karthud[khud_cardanimation]++;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -7848,11 +7909,6 @@ void K_KartPlayerHUDUpdate(player_t *player)
|
|||
if (player->karthud[khud_cardanimation] < 0)
|
||||
player->karthud[khud_cardanimation] = 0;
|
||||
}
|
||||
else if (gametype == GT_RACE && player->exiting)
|
||||
{
|
||||
if (player->karthud[khud_cardanimation] < 2*TICRATE)
|
||||
player->karthud[khud_cardanimation]++;
|
||||
}
|
||||
else
|
||||
player->karthud[khud_cardanimation] = 0;
|
||||
}
|
||||
|
|
@ -8409,8 +8465,6 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
|
|||
|
||||
K_UpdateTripwire(player);
|
||||
|
||||
K_KartPlayerHUDUpdate(player);
|
||||
|
||||
if (battleovertime.enabled && !(player->pflags & PF_ELIMINATED) && player->bumpers <= 0 && player->karmadelay <= 0)
|
||||
{
|
||||
if (player->overtimekarma)
|
||||
|
|
@ -11513,7 +11567,7 @@ void K_CheckSpectateStatus(void)
|
|||
return;
|
||||
continue;
|
||||
}
|
||||
else if (!(players[i].pflags & PF_WANTSTOJOIN))
|
||||
else if (players[i].bot || !(players[i].pflags & PF_WANTSTOJOIN))
|
||||
continue;
|
||||
|
||||
respawnlist[numjoiners++] = i;
|
||||
|
|
|
|||
|
|
@ -3443,9 +3443,7 @@ void M_CupSelectHandler(INT32 choice)
|
|||
// Don't restart the server if we're already in a game lol
|
||||
if (gamestate == GS_MENU)
|
||||
{
|
||||
SV_StartSinglePlayerServer();
|
||||
multiplayer = true; // yeah, SV_StartSinglePlayerServer clobbers this...
|
||||
netgame = levellist.netgame; // ^ ditto.
|
||||
SV_StartSinglePlayerServer(levellist.newgametype, levellist.netgame);
|
||||
}
|
||||
|
||||
levelNum = grandprixinfo.cup->cachedlevels[0];
|
||||
|
|
@ -3600,9 +3598,7 @@ void M_LevelSelectHandler(INT32 choice)
|
|||
F_WipeEndScreen();
|
||||
F_RunWipe(wipedefs[wipe_level_toblack], false, "FADEMAP0", false, false);
|
||||
|
||||
SV_StartSinglePlayerServer();
|
||||
multiplayer = true; // yeah, SV_StartSinglePlayerServer clobbers this...
|
||||
netgame = levellist.netgame; // ^ ditto.
|
||||
SV_StartSinglePlayerServer(levellist.newgametype, levellist.netgame);
|
||||
|
||||
CV_StealthSet(&cv_kartbot, cv_dummymatchbots.string);
|
||||
CV_StealthSet(&cv_kartencore, (cv_dummygpencore.value == 1) ? "On" : "Auto");
|
||||
|
|
@ -3700,7 +3696,7 @@ void M_StartTimeAttack(INT32 choice)
|
|||
F_WipeEndScreen();
|
||||
F_RunWipe(wipedefs[wipe_level_toblack], false, "FADEMAP0", false, false);
|
||||
|
||||
SV_StartSinglePlayerServer();
|
||||
SV_StartSinglePlayerServer(levellist.newgametype, false);
|
||||
|
||||
gpath = va("%s"PATHSEP"media"PATHSEP"replay"PATHSEP"%s",
|
||||
srb2home, timeattackfolder);
|
||||
|
|
@ -4398,7 +4394,7 @@ void M_InitOptions(INT32 choice)
|
|||
|
||||
// enable gameplay & server options under the right circumstances.
|
||||
if (gamestate == GS_MENU
|
||||
|| ((server || IsPlayerAdmin(consoleplayer)) && K_CanChangeRules()))
|
||||
|| ((server || IsPlayerAdmin(consoleplayer)) && K_CanChangeRules(false)))
|
||||
{
|
||||
OPTIONS_MainDef.menuitems[mopt_gameplay].status = IT_STRING | IT_SUBMENU;
|
||||
OPTIONS_MainDef.menuitems[mopt_server].status = IT_STRING | IT_SUBMENU;
|
||||
|
|
@ -5734,7 +5730,7 @@ void M_OpenPauseMenu(void)
|
|||
|
||||
Dummymenuplayer_OnChange(); // Make sure the consvar is within bounds of the amount of splitscreen players we have.
|
||||
|
||||
if (K_CanChangeRules())
|
||||
if (K_CanChangeRules(false))
|
||||
{
|
||||
PAUSE_Main[mpause_psetup].status = IT_STRING | IT_CALL;
|
||||
|
||||
|
|
|
|||
139
src/k_specialstage.c
Normal file
139
src/k_specialstage.c
Normal file
|
|
@ -0,0 +1,139 @@
|
|||
// DR. ROBOTNIK'S RING RACERS
|
||||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) 2022 by Sally "TehRealSalt" Cochenour
|
||||
// Copyright (C) 2022 by Kart Krew
|
||||
//
|
||||
// This program is free software distributed under the
|
||||
// terms of the GNU General Public License, version 2.
|
||||
// See the 'LICENSE' file for more details.
|
||||
//-----------------------------------------------------------------------------
|
||||
/// \file k_specialstage.c
|
||||
/// \brief Special Stage game logic
|
||||
|
||||
#include "k_specialstage.h"
|
||||
#include "doomdef.h"
|
||||
#include "d_player.h"
|
||||
#include "g_game.h"
|
||||
#include "p_local.h"
|
||||
#include "k_kart.h"
|
||||
#include "s_sound.h"
|
||||
#include "st_stuff.h"
|
||||
#include "z_zone.h"
|
||||
#include "k_waypoint.h"
|
||||
|
||||
struct specialStage specialStage;
|
||||
|
||||
/*--------------------------------------------------
|
||||
void K_ResetSpecialStage(void)
|
||||
|
||||
See header file for description.
|
||||
--------------------------------------------------*/
|
||||
void K_ResetSpecialStage(void)
|
||||
{
|
||||
memset(&specialStage, 0, sizeof(struct specialStage));
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
void K_InitSpecialStage(void)
|
||||
|
||||
See header file for description.
|
||||
--------------------------------------------------*/
|
||||
void K_InitSpecialStage(void)
|
||||
{
|
||||
INT32 i;
|
||||
|
||||
specialStage.beamDist = UINT32_MAX; // TODO: make proper value
|
||||
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
player_t *player = NULL;
|
||||
|
||||
if (playeringame[i] == false)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
player = &players[i];
|
||||
if (player->spectator == true)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (player->mo == NULL || P_MobjWasRemoved(player->mo) == true)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Rolling start? lol
|
||||
P_InstaThrust(player->mo, player->mo->angle, K_GetKartSpeed(player, false, false));
|
||||
}
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
static void K_MoveExitBeam(void)
|
||||
|
||||
Updates the exit beam.
|
||||
--------------------------------------------------*/
|
||||
static void K_MoveExitBeam(void)
|
||||
{
|
||||
UINT32 moveDist = 0;
|
||||
INT32 i;
|
||||
|
||||
if (leveltime <= 2)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
moveDist = (8 * mapobjectscale) / FRACUNIT;
|
||||
|
||||
if (specialStage.beamDist <= moveDist)
|
||||
{
|
||||
specialStage.beamDist = 0;
|
||||
|
||||
// TODO: Fail Special Stage
|
||||
}
|
||||
else
|
||||
{
|
||||
specialStage.beamDist -= moveDist;
|
||||
}
|
||||
|
||||
// Find players who are now outside of the level.
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
player_t *player = NULL;
|
||||
|
||||
if (playeringame[i] == false)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
player = &players[i];
|
||||
|
||||
if (player->spectator == true
|
||||
|| player->exiting > 0
|
||||
|| (player->pflags & PF_NOCONTEST))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (player->distancetofinish > specialStage.beamDist)
|
||||
{
|
||||
P_DoTimeOver(player);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
void K_TickSpecialStage(void)
|
||||
|
||||
See header file for description.
|
||||
--------------------------------------------------*/
|
||||
void K_TickSpecialStage(void)
|
||||
{
|
||||
if (specialStage.active == false)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
K_MoveExitBeam();
|
||||
}
|
||||
55
src/k_specialstage.h
Normal file
55
src/k_specialstage.h
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
// DR. ROBOTNIK'S RING RACERS
|
||||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) 2022 by Sally "TehRealSalt" Cochenour
|
||||
// Copyright (C) 2022 by Kart Krew
|
||||
//
|
||||
// This program is free software distributed under the
|
||||
// terms of the GNU General Public License, version 2.
|
||||
// See the 'LICENSE' file for more details.
|
||||
//-----------------------------------------------------------------------------
|
||||
/// \file k_specialstage.h
|
||||
/// \brief Special Stage game logic
|
||||
|
||||
#ifndef __K_SPECIALSTAGE__
|
||||
#define __K_SPECIALSTAGE__
|
||||
|
||||
#include "doomdef.h"
|
||||
#include "doomstat.h"
|
||||
|
||||
extern struct specialStage
|
||||
{
|
||||
boolean active; ///< If true, then we are in a special stage
|
||||
boolean encore; ///< Copy of encore, just to make sure you can't cheat it with cvars
|
||||
|
||||
UINT32 beamDist; ///< Where the exit beam is.
|
||||
mobj_t *capsule; ///< The Chaos Emerald capsule.
|
||||
} specialStage;
|
||||
|
||||
/*--------------------------------------------------
|
||||
void K_ResetSpecialStage(void);
|
||||
|
||||
Resets Special Stage information to a clean slate.
|
||||
--------------------------------------------------*/
|
||||
|
||||
void K_ResetSpecialStage(void);
|
||||
|
||||
|
||||
/*--------------------------------------------------
|
||||
void K_InitSpecialStage(void);
|
||||
|
||||
Initializes Special Stage data on map load.
|
||||
--------------------------------------------------*/
|
||||
|
||||
void K_InitSpecialStage(void);
|
||||
|
||||
|
||||
/*--------------------------------------------------
|
||||
void K_TickSpecialStage(void);
|
||||
|
||||
Updates Special Stage data each frame.
|
||||
--------------------------------------------------*/
|
||||
|
||||
void K_TickSpecialStage(void);
|
||||
|
||||
|
||||
#endif
|
||||
|
|
@ -205,7 +205,7 @@ int LUA_PushGlobals(lua_State *L, const char *word)
|
|||
lua_pushinteger(L, redscore);
|
||||
return 1;
|
||||
} else if (fastcmp(word,"timelimit")) {
|
||||
lua_pushinteger(L, cv_timelimit.value);
|
||||
lua_pushinteger(L, timelimitintics);
|
||||
return 1;
|
||||
} else if (fastcmp(word,"pointlimit")) {
|
||||
lua_pushinteger(L, cv_pointlimit.value);
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ typedef enum
|
|||
PR_PLAYERSTARTS, // Player starts
|
||||
PR_VOICES, // Player voice sounds
|
||||
|
||||
PR_RULESCRAMBLE, // Netgame rule scrambing events
|
||||
PR_RULESCRAMBLE, // Rule scrambing events
|
||||
|
||||
PR_ITEM_ROULETTE, // Item results
|
||||
PR_ITEM_RINGS, // Flung ring/bumper/player (on death)
|
||||
|
|
|
|||
|
|
@ -4032,9 +4032,10 @@ void A_AttractChase(mobj_t *actor)
|
|||
|
||||
if (
|
||||
actor->tracer->player && actor->tracer->health
|
||||
&& actor->tracer->player->itemtype == KITEM_LIGHTNINGSHIELD
|
||||
&& RINGTOTAL(actor->tracer->player) < 20
|
||||
&& !(actor->tracer->player->pflags & PF_RINGLOCK)
|
||||
&& ((gametyperules & GTR_SPHERES)
|
||||
|| (actor->tracer->player->itemtype == KITEM_LIGHTNINGSHIELD
|
||||
&& RINGTOTAL(actor->tracer->player) < 20
|
||||
&& !(actor->tracer->player->pflags & PF_RINGLOCK)))
|
||||
//&& P_CheckSight(actor, actor->tracer)
|
||||
)
|
||||
{
|
||||
|
|
|
|||
145
src/p_inter.c
145
src/p_inter.c
|
|
@ -590,14 +590,9 @@ void P_TouchStarPost(mobj_t *post, player_t *player, boolean snaptopost)
|
|||
player->starpostnum = post->health;
|
||||
}
|
||||
|
||||
// Easily make it so that overtime works offline
|
||||
#define TESTOVERTIMEINFREEPLAY
|
||||
|
||||
/** Checks if the level timer is over the timelimit and the round should end,
|
||||
* unless you are in overtime. In which case leveltime may stretch out beyond
|
||||
* timelimitintics and overtime's status will be checked here each tick.
|
||||
* Verify that the value of ::cv_timelimit is greater than zero before
|
||||
* calling this function.
|
||||
*
|
||||
* \sa cv_timelimit, P_CheckPointLimit, P_UpdateSpecials
|
||||
*/
|
||||
|
|
@ -605,27 +600,61 @@ void P_CheckTimeLimit(void)
|
|||
{
|
||||
INT32 i;
|
||||
|
||||
if (!cv_timelimit.value)
|
||||
if (exitcountdown)
|
||||
return;
|
||||
|
||||
#ifndef TESTOVERTIMEINFREEPLAY
|
||||
if (battlecapsules) // capsules override any time limit settings
|
||||
return;
|
||||
#endif
|
||||
|
||||
if (!(gametyperules & GTR_TIMELIMIT))
|
||||
if (!timelimitintics)
|
||||
return;
|
||||
|
||||
if (bossinfo.boss == true)
|
||||
if (leveltime < starttime)
|
||||
{
|
||||
if (secretextratime)
|
||||
secretextratime--;
|
||||
return;
|
||||
}
|
||||
|
||||
if (leveltime < (timelimitintics + starttime))
|
||||
{
|
||||
if (secretextratime)
|
||||
{
|
||||
secretextratime--;
|
||||
timelimitintics++;
|
||||
}
|
||||
else if (extratimeintics)
|
||||
{
|
||||
timelimitintics++;
|
||||
if (leveltime & 1)
|
||||
;
|
||||
else
|
||||
{
|
||||
if (extratimeintics > 20)
|
||||
{
|
||||
extratimeintics -= 20;
|
||||
timelimitintics += 20;
|
||||
}
|
||||
else
|
||||
{
|
||||
timelimitintics += extratimeintics;
|
||||
extratimeintics = 0;
|
||||
}
|
||||
S_StartSound(NULL, sfx_ptally);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (timelimitintics + starttime - leveltime <= 3*TICRATE)
|
||||
{
|
||||
if (((timelimitintics + starttime - leveltime) % TICRATE) == 0)
|
||||
S_StartSound(NULL, sfx_s3ka7);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (gameaction == ga_completed)
|
||||
return;
|
||||
|
||||
if ((cv_overtime.value) && (gametyperules & GTR_OVERTIME))
|
||||
if ((grandprixinfo.gp == false) && (cv_overtime.value) && (gametyperules & GTR_OVERTIME))
|
||||
{
|
||||
#ifndef TESTOVERTIMEINFREEPLAY
|
||||
boolean foundone = false; // Overtime is used for closing off down to a specific item.
|
||||
|
|
@ -700,8 +729,6 @@ void P_CheckTimeLimit(void)
|
|||
}
|
||||
|
||||
/** Checks if a player's score is over the pointlimit and the round should end.
|
||||
* Verify that the value of ::cv_pointlimit is greater than zero before
|
||||
* calling this function.
|
||||
*
|
||||
* \sa cv_pointlimit, P_CheckTimeLimit, P_UpdateSpecials
|
||||
*/
|
||||
|
|
@ -709,16 +736,19 @@ void P_CheckPointLimit(void)
|
|||
{
|
||||
INT32 i;
|
||||
|
||||
if (!cv_pointlimit.value)
|
||||
if (exitcountdown)
|
||||
return;
|
||||
|
||||
if (!(multiplayer || netgame))
|
||||
if (!K_CanChangeRules(true))
|
||||
return;
|
||||
|
||||
if (!cv_pointlimit.value)
|
||||
return;
|
||||
|
||||
if (!(gametyperules & GTR_POINTLIMIT))
|
||||
return;
|
||||
|
||||
if (bossinfo.boss == true)
|
||||
if (battlecapsules)
|
||||
return;
|
||||
|
||||
// pointlimit is nonzero, check if it's been reached by this player
|
||||
|
|
@ -852,7 +882,7 @@ boolean P_CheckRacers(void)
|
|||
}
|
||||
|
||||
// Everyone should be done playing at this point now.
|
||||
racecountdown = exitcountdown = 0;
|
||||
racecountdown = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -860,7 +890,7 @@ boolean P_CheckRacers(void)
|
|||
{
|
||||
// There might be bots that are still going,
|
||||
// but all of the humans are done, so we can exit now.
|
||||
racecountdown = exitcountdown = 0;
|
||||
racecountdown = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -881,7 +911,7 @@ boolean P_CheckRacers(void)
|
|||
{
|
||||
tic_t countdown = 30*TICRATE; // 30 seconds left to finish, get going!
|
||||
|
||||
if (K_CanChangeRules() == true)
|
||||
if (K_CanChangeRules(true) == true)
|
||||
{
|
||||
// Custom timer
|
||||
countdown = cv_countdowntime.value * TICRATE;
|
||||
|
|
@ -1262,6 +1292,9 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget
|
|||
kart->old_x = target->old_x;
|
||||
kart->old_y = target->old_y;
|
||||
kart->old_z = target->old_z;
|
||||
|
||||
if (target->player->pflags & PF_NOCONTEST)
|
||||
P_SetTarget(&target->tracer, kart);
|
||||
}
|
||||
|
||||
if (source && !P_MobjWasRemoved(source))
|
||||
|
|
@ -1426,40 +1459,94 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget
|
|||
|
||||
case MT_BATTLECAPSULE:
|
||||
{
|
||||
UINT8 i;
|
||||
mobj_t *cur;
|
||||
angle_t dir = 0;
|
||||
|
||||
numtargets++;
|
||||
target->fuse = 16;
|
||||
target->flags |= MF_NOCLIP|MF_NOCLIPTHING;
|
||||
|
||||
if (inflictor)
|
||||
{
|
||||
dir = R_PointToAngle2(inflictor->x, inflictor->y, target->x, target->y);
|
||||
P_Thrust(target, dir, P_AproxDistance(inflictor->momx, inflictor->momy)/12);
|
||||
}
|
||||
else if (source)
|
||||
dir = R_PointToAngle2(source->x, source->y, target->x, target->y);
|
||||
|
||||
target->momz += 8 * target->scale * P_MobjFlip(target);
|
||||
target->flags &= ~MF_NOGRAVITY;
|
||||
|
||||
cur = target->hnext;
|
||||
|
||||
while (cur && !P_MobjWasRemoved(cur))
|
||||
{
|
||||
cur->momx = target->momx;
|
||||
cur->momy = target->momy;
|
||||
cur->momz = target->momz;
|
||||
|
||||
// Shoot every piece outward
|
||||
if (!(cur->x == target->x && cur->y == target->y))
|
||||
{
|
||||
P_InstaThrust(cur,
|
||||
P_Thrust(cur,
|
||||
R_PointToAngle2(target->x, target->y, cur->x, cur->y),
|
||||
R_PointToDist2(target->x, target->y, cur->x, cur->y) / 12
|
||||
);
|
||||
}
|
||||
|
||||
cur->momz = 8 * target->scale * P_MobjFlip(target);
|
||||
|
||||
cur->flags &= ~MF_NOGRAVITY;
|
||||
cur->tics = TICRATE;
|
||||
cur->frame &= ~FF_ANIMATE; // Stop animating the propellers
|
||||
|
||||
cur->hitlag = target->hitlag;
|
||||
cur->eflags |= MFE_DAMAGEHITLAG;
|
||||
|
||||
cur = cur->hnext;
|
||||
}
|
||||
|
||||
// All targets busted!
|
||||
if (numtargets >= maptargets)
|
||||
S_StartSound(target, sfx_mbs60);
|
||||
|
||||
if ((gametyperules & GTR_POINTLIMIT) && (source && source->player))
|
||||
{
|
||||
UINT8 i;
|
||||
/*mobj_t * ring;
|
||||
for (i = 0; i < 2; i++)
|
||||
{
|
||||
dir += (ANGLE_MAX/3);
|
||||
ring = P_SpawnMobj(target->x, target->y, target->z, MT_RING);
|
||||
ring->angle = dir;
|
||||
P_InstaThrust(ring, dir, 16*ring->scale);
|
||||
ring->momz = 8 * target->scale * P_MobjFlip(target);
|
||||
P_SetTarget(&ring->tracer, source);
|
||||
source->player->pickuprings++;
|
||||
}*/
|
||||
|
||||
P_AddPlayerScore(source->player, 1);
|
||||
K_SpawnBattlePoints(source->player, NULL, 1);
|
||||
}
|
||||
|
||||
// All targets busted!
|
||||
if (++numtargets >= maptargets)
|
||||
{
|
||||
boolean givelife = false;
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
if (!playeringame[i] || players[i].spectator)
|
||||
continue;
|
||||
P_DoPlayerExit(&players[i]);
|
||||
if (!grandprixinfo.gp)
|
||||
continue;
|
||||
P_GivePlayerLives(&players[i], 1);
|
||||
givelife = true;
|
||||
}
|
||||
|
||||
if (givelife)
|
||||
S_StartSound(NULL, sfx_cdfm73);
|
||||
}
|
||||
else if (timelimitintics)
|
||||
{
|
||||
S_StartSound(NULL, sfx_s221);
|
||||
extratimeintics += 10*TICRATE;
|
||||
secretextratime = TICRATE/2;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -5157,10 +5157,14 @@ boolean P_IsKartItem(INT32 type)
|
|||
case MT_JAWZ_SHIELD:
|
||||
case MT_SSMINE_SHIELD:
|
||||
case MT_SINK_SHIELD:
|
||||
case MT_SPB:
|
||||
case MT_HYUDORO:
|
||||
return true;
|
||||
|
||||
// Primarily for minimap data, handle with care
|
||||
case MT_SPB:
|
||||
case MT_BATTLECAPSULE:
|
||||
return true;
|
||||
|
||||
default:
|
||||
return P_IsKartFieldItem(type);
|
||||
}
|
||||
|
|
@ -9407,6 +9411,9 @@ void P_MobjThinker(mobj_t *mobj)
|
|||
K_HandleDirectionalInfluence(mobj->player);
|
||||
}
|
||||
|
||||
if (P_IsKartItem(mobj->type)) // mobj is a kart item we want on the list:
|
||||
P_AddKartItem(mobj); // add to kitem list
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4597,6 +4597,10 @@ static void P_NetArchiveMisc(boolean resending)
|
|||
WRITEUINT32(save_p, starttime);
|
||||
WRITEUINT8(save_p, numbulbs);
|
||||
|
||||
WRITEUINT32(save_p, timelimitintics);
|
||||
WRITEUINT32(save_p, extratimeintics);
|
||||
WRITEUINT32(save_p, secretextratime);
|
||||
|
||||
// Is it paused?
|
||||
if (paused)
|
||||
WRITEUINT8(save_p, 0x2f);
|
||||
|
|
|
|||
|
|
@ -96,8 +96,8 @@
|
|||
#include "k_boss.h"
|
||||
#include "k_terrain.h" // TRF_TRIPWIRE
|
||||
#include "k_brightmap.h"
|
||||
#include "k_terrain.h" // TRF_TRIPWIRE
|
||||
#include "k_director.h" // K_InitDirector
|
||||
#include "k_specialstage.h"
|
||||
|
||||
// Replay names have time
|
||||
#if !defined (UNDER_CE)
|
||||
|
|
@ -3565,7 +3565,7 @@ static void P_InitLevelSettings(void)
|
|||
// SRB2Kart: map load variables
|
||||
if (grandprixinfo.gp == true)
|
||||
{
|
||||
if (gametype == GT_BATTLE)
|
||||
if ((gametyperules & GTR_BUMPERS))
|
||||
{
|
||||
gamespeed = KARTSPEED_EASY;
|
||||
}
|
||||
|
|
@ -3584,7 +3584,10 @@ static void P_InitLevelSettings(void)
|
|||
else if (modeattacking)
|
||||
{
|
||||
// Just play it safe and set everything
|
||||
gamespeed = KARTSPEED_HARD;
|
||||
if ((gametyperules & GTR_BUMPERS))
|
||||
gamespeed = KARTSPEED_EASY;
|
||||
else
|
||||
gamespeed = KARTSPEED_HARD;
|
||||
franticitems = false;
|
||||
}
|
||||
else
|
||||
|
|
@ -3848,20 +3851,29 @@ static void P_InitGametype(void)
|
|||
if (modeattacking && !demo.playback)
|
||||
P_LoadRecordGhosts();
|
||||
|
||||
numlaps = 0;
|
||||
if (gametyperules & GTR_CIRCUIT)
|
||||
{
|
||||
if ((netgame || multiplayer) && cv_numlaps.value
|
||||
if (K_CanChangeRules(true) && cv_numlaps.value
|
||||
&& (!(mapheaderinfo[gamemap - 1]->levelflags & LF_SECTIONRACE)
|
||||
|| (mapheaderinfo[gamemap - 1]->numlaps > cv_numlaps.value)))
|
||||
{
|
||||
numlaps = cv_numlaps.value;
|
||||
}
|
||||
else if ((grandprixinfo.gp == true)
|
||||
&& (grandprixinfo.eventmode == GPEVENT_NONE)
|
||||
&& cv_gptest.value)
|
||||
{
|
||||
numlaps = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
numlaps = mapheaderinfo[gamemap - 1]->numlaps;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
numlaps = 0;
|
||||
}
|
||||
|
||||
wantedcalcdelay = wantedfrequency*2;
|
||||
|
||||
|
|
@ -4474,6 +4486,42 @@ UINT8 P_InitMapData(INT32 numexistingmapheaders)
|
|||
continue;
|
||||
}
|
||||
|
||||
// Always check for cup cache reassociations.
|
||||
// (The core assumption is that cups < headers.)
|
||||
{
|
||||
cupheader_t *cup = kartcupheaders;
|
||||
INT32 j;
|
||||
|
||||
while (cup)
|
||||
{
|
||||
for (j = 0; j < CUPCACHE_MAX; j++)
|
||||
{
|
||||
// No level in this slot?
|
||||
if (!cup->levellist[j])
|
||||
continue;
|
||||
|
||||
// Already discovered?
|
||||
if (cup->cachedlevels[j] != NEXTMAP_INVALID)
|
||||
continue;
|
||||
|
||||
// Not your name?
|
||||
if (strcasecmp(cup->levellist[j], name) != 0)
|
||||
continue;
|
||||
|
||||
// Only panic about back-reference for non-bonus material.
|
||||
if (j < MAXLEVELLIST)
|
||||
{
|
||||
if (mapheaderinfo[i]->cup)
|
||||
I_Error("P_InitMapData: Map %s cannot appear in cups multiple times! (First in %s, now in %s)", name, mapheaderinfo[i]->cup->name, cup->name);
|
||||
mapheaderinfo[i]->cup = cup;
|
||||
}
|
||||
|
||||
cup->cachedlevels[j] = i;
|
||||
}
|
||||
cup = cup->next;
|
||||
}
|
||||
}
|
||||
|
||||
// No change?
|
||||
if (mapheaderinfo[i]->lumpnum == maplump)
|
||||
continue;
|
||||
|
|
@ -4527,37 +4575,6 @@ UINT8 P_InitMapData(INT32 numexistingmapheaders)
|
|||
}
|
||||
|
||||
vres_Free(virtmap);
|
||||
|
||||
// Now associate it with a cup cache.
|
||||
// (The core assumption is that cups < headers.)
|
||||
if (i >= numexistingmapheaders)
|
||||
{
|
||||
cupheader_t *cup = kartcupheaders;
|
||||
INT32 j;
|
||||
while (cup)
|
||||
{
|
||||
for (j = 0; j < CUPCACHE_MAX; j++)
|
||||
{
|
||||
// Already discovered?
|
||||
if (cup->cachedlevels[j] != NEXTMAP_INVALID)
|
||||
continue;
|
||||
|
||||
if (!cup->levellist[j] || strcasecmp(cup->levellist[j], name) != 0)
|
||||
continue;
|
||||
|
||||
// Only panic about back-reference for non-bonus material.
|
||||
if (j < MAXLEVELLIST || j == CUPCACHE_SPECIAL)
|
||||
{
|
||||
if (mapheaderinfo[i]->cup)
|
||||
I_Error("P_InitMapData: Map %s cannot appear in cups multiple times! (First in %s, now in %s)", name, mapheaderinfo[i]->cup->name, cup->name);
|
||||
mapheaderinfo[i]->cup = cup;
|
||||
}
|
||||
|
||||
cup->cachedlevels[j] = i;
|
||||
}
|
||||
cup = cup->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
33
src/p_tick.c
33
src/p_tick.c
|
|
@ -37,6 +37,7 @@
|
|||
#include "k_boss.h"
|
||||
#include "k_waypoint.h"
|
||||
#include "k_director.h"
|
||||
#include "k_specialstage.h"
|
||||
|
||||
tic_t leveltime;
|
||||
|
||||
|
|
@ -594,20 +595,32 @@ void P_Ticker(boolean run)
|
|||
|
||||
ps_playerthink_time = I_GetPreciseTime();
|
||||
|
||||
#define PLAYERCONDITION(i) (playeringame[i] && players[i].mo && !P_MobjWasRemoved(players[i].mo))
|
||||
// First loop: Ensure all players' distance to the finish line are all accurate
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
if (playeringame[i] && players[i].mo && !P_MobjWasRemoved(players[i].mo))
|
||||
K_UpdateDistanceFromFinishLine(&players[i]);
|
||||
{
|
||||
if (!PLAYERCONDITION(i))
|
||||
continue;
|
||||
K_UpdateDistanceFromFinishLine(&players[i]);
|
||||
}
|
||||
|
||||
// Second loop: Ensure all player positions reflect everyone's distances
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
if (playeringame[i] && players[i].mo && !P_MobjWasRemoved(players[i].mo))
|
||||
K_KartUpdatePosition(&players[i]);
|
||||
{
|
||||
if (!PLAYERCONDITION(i))
|
||||
continue;
|
||||
K_KartUpdatePosition(&players[i]);
|
||||
}
|
||||
|
||||
// OK! Now that we got all of that sorted, players can think!
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
if (playeringame[i] && players[i].mo && !P_MobjWasRemoved(players[i].mo))
|
||||
P_PlayerThink(&players[i]);
|
||||
{
|
||||
if (!PLAYERCONDITION(i))
|
||||
continue;
|
||||
P_PlayerThink(&players[i]);
|
||||
K_KartPlayerHUDUpdate(&players[i]);
|
||||
}
|
||||
#undef PLAYERCONDITION
|
||||
|
||||
ps_playerthink_time = I_GetPreciseTime() - ps_playerthink_time;
|
||||
}
|
||||
|
|
@ -690,12 +703,20 @@ void P_Ticker(boolean run)
|
|||
racecountdown--;
|
||||
|
||||
if (exitcountdown > 1)
|
||||
{
|
||||
exitcountdown--;
|
||||
if (server && exitcountdown == 1)
|
||||
{
|
||||
SendNetXCmd(XD_EXITLEVEL, NULL, 0);
|
||||
}
|
||||
}
|
||||
|
||||
K_RunItemCooldowns();
|
||||
|
||||
K_BossInfoTicker();
|
||||
|
||||
K_TickSpecialStage();
|
||||
|
||||
if ((gametyperules & GTR_BUMPERS))
|
||||
{
|
||||
if (wantedcalcdelay && --wantedcalcdelay <= 0)
|
||||
|
|
|
|||
351
src/p_user.c
351
src/p_user.c
|
|
@ -505,7 +505,6 @@ INT32 P_GivePlayerRings(player_t *player, INT32 num_rings)
|
|||
num_rings -= (test+20);
|
||||
|
||||
player->rings += num_rings;
|
||||
//player->totalring += num_rings; // Used for GP lives later -- maybe you might want to move this earlier to discourage ring debt...
|
||||
|
||||
return num_rings;
|
||||
}
|
||||
|
|
@ -1261,72 +1260,81 @@ void P_DoPlayerExit(player_t *player)
|
|||
K_PlayerLoseLife(player);
|
||||
}
|
||||
|
||||
if ((gametyperules & GTR_CIRCUIT)) // If in Race Mode, allow
|
||||
player->exiting = 1;
|
||||
|
||||
if (!player->spectator)
|
||||
{
|
||||
player->exiting = raceexittime+2;
|
||||
K_KartUpdatePosition(player);
|
||||
|
||||
if (cv_kartvoices.value)
|
||||
if ((gametyperules & GTR_CIRCUIT)) // If in Race Mode, allow
|
||||
{
|
||||
if (P_IsDisplayPlayer(player))
|
||||
K_KartUpdatePosition(player);
|
||||
|
||||
if (cv_kartvoices.value)
|
||||
{
|
||||
sfxenum_t sfx_id;
|
||||
if (losing)
|
||||
sfx_id = ((skin_t *)player->mo->skin)->soundsid[S_sfx[sfx_klose].skinsound];
|
||||
else
|
||||
sfx_id = ((skin_t *)player->mo->skin)->soundsid[S_sfx[sfx_kwin].skinsound];
|
||||
S_StartSound(NULL, sfx_id);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (losing)
|
||||
S_StartSound(player->mo, sfx_klose);
|
||||
else
|
||||
S_StartSound(player->mo, sfx_kwin);
|
||||
}
|
||||
}
|
||||
|
||||
if (cv_inttime.value > 0)
|
||||
P_EndingMusic(player);
|
||||
|
||||
if (P_CheckRacers())
|
||||
player->exiting = raceexittime+1;
|
||||
}
|
||||
else if ((gametyperules & GTR_BUMPERS)) // Battle Mode exiting
|
||||
{
|
||||
player->exiting = battleexittime+1;
|
||||
P_EndingMusic(player);
|
||||
}
|
||||
else
|
||||
player->exiting = raceexittime+2; // Accidental death safeguard???
|
||||
|
||||
if (grandprixinfo.gp == true)
|
||||
{
|
||||
if (player->bot)
|
||||
{
|
||||
// Bots are going to get harder... :)
|
||||
K_IncreaseBotDifficulty(player);
|
||||
}
|
||||
else if (!losing)
|
||||
{
|
||||
const UINT8 lifethreshold = 20;
|
||||
UINT8 extra = 0;
|
||||
|
||||
// YOU WIN
|
||||
grandprixinfo.wonround = true;
|
||||
|
||||
// Increase your total rings
|
||||
if (RINGTOTAL(player) > 0)
|
||||
{
|
||||
player->totalring += RINGTOTAL(player);
|
||||
|
||||
extra = player->totalring / lifethreshold;
|
||||
|
||||
if (extra > player->xtralife)
|
||||
if (P_IsDisplayPlayer(player))
|
||||
{
|
||||
P_GivePlayerLives(player, extra - player->xtralife);
|
||||
S_StartSound(NULL, sfx_cdfm73);
|
||||
player->xtralife = extra;
|
||||
sfxenum_t sfx_id;
|
||||
if (losing)
|
||||
sfx_id = ((skin_t *)player->mo->skin)->soundsid[S_sfx[sfx_klose].skinsound];
|
||||
else
|
||||
sfx_id = ((skin_t *)player->mo->skin)->soundsid[S_sfx[sfx_kwin].skinsound];
|
||||
S_StartSound(NULL, sfx_id);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (losing)
|
||||
S_StartSound(player->mo, sfx_klose);
|
||||
else
|
||||
S_StartSound(player->mo, sfx_kwin);
|
||||
}
|
||||
}
|
||||
|
||||
// See Y_StartIntermission timer handling
|
||||
if (!K_CanChangeRules(false) || cv_inttime.value > 0)
|
||||
P_EndingMusic(player);
|
||||
|
||||
if (P_CheckRacers() && !exitcountdown)
|
||||
exitcountdown = raceexittime+1;
|
||||
}
|
||||
else if ((gametyperules & GTR_BUMPERS)) // Battle Mode exiting
|
||||
{
|
||||
if (!exitcountdown)
|
||||
exitcountdown = battleexittime+1;
|
||||
P_EndingMusic(player);
|
||||
}
|
||||
else // Accidental death safeguard???
|
||||
{
|
||||
if (!exitcountdown)
|
||||
exitcountdown = raceexittime+2;
|
||||
}
|
||||
|
||||
if (grandprixinfo.gp == true)
|
||||
{
|
||||
if (player->bot)
|
||||
{
|
||||
// Bots are going to get harder... :)
|
||||
K_IncreaseBotDifficulty(player);
|
||||
}
|
||||
else if (!losing)
|
||||
{
|
||||
const UINT8 lifethreshold = 20;
|
||||
UINT8 extra = 0;
|
||||
|
||||
// YOU WIN
|
||||
grandprixinfo.wonround = true;
|
||||
|
||||
// Increase your total rings
|
||||
if (RINGTOTAL(player) > 0)
|
||||
{
|
||||
player->totalring += RINGTOTAL(player);
|
||||
|
||||
extra = player->totalring / lifethreshold;
|
||||
|
||||
if (extra > player->xtralife)
|
||||
{
|
||||
P_GivePlayerLives(player, extra - player->xtralife);
|
||||
S_StartSound(NULL, sfx_cdfm73);
|
||||
player->xtralife = extra;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3853,8 +3861,6 @@ void P_PlayerThink(player_t *player)
|
|||
|
||||
player->old_drawangle = player->drawangle;
|
||||
|
||||
player->pflags &= ~PF_HITFINISHLINE;
|
||||
|
||||
if (player->awayviewmobj && P_MobjWasRemoved(player->awayviewmobj))
|
||||
{
|
||||
P_SetTarget(&player->awayviewmobj, NULL); // remove awayviewmobj asap if invalid
|
||||
|
|
@ -3867,11 +3873,6 @@ void P_PlayerThink(player_t *player)
|
|||
if (player->awayviewtics && player->awayviewtics != -1)
|
||||
player->awayviewtics--;
|
||||
|
||||
if (player->mo->hitlag > 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Track airtime
|
||||
if (P_IsObjectOnGround(player->mo)
|
||||
&& !P_PlayerInPain(player)) // This isn't airtime, but it's control loss all the same.
|
||||
|
|
@ -3946,21 +3947,6 @@ void P_PlayerThink(player_t *player)
|
|||
{
|
||||
if (gametyperules & GTR_CIRCUIT)
|
||||
{
|
||||
INT32 i;
|
||||
|
||||
// Check if all the players in the race have finished. If so, end the level.
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
if (playeringame[i] && !players[i].spectator)
|
||||
{
|
||||
if (!players[i].exiting && !(players[i].pflags & PF_NOCONTEST) && players[i].lives > 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i == MAXPLAYERS && player->exiting == raceexittime+2) // finished
|
||||
player->exiting = raceexittime+1;
|
||||
|
||||
#if 0
|
||||
// If 10 seconds are left on the timer,
|
||||
// begin the drown music for countdown!
|
||||
|
|
@ -3985,45 +3971,6 @@ void P_PlayerThink(player_t *player)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If it is set, start subtracting
|
||||
// Don't allow it to go back to 0
|
||||
if (player->exiting > 1 && (player->exiting < raceexittime+2 || !(gametyperules & GTR_CIRCUIT))) // SRB2kart - "&& player->exiting > 1"
|
||||
player->exiting--;
|
||||
|
||||
if (player->exiting && exitcountdown)
|
||||
player->exiting = 99; // SRB2kart
|
||||
|
||||
if (player->exiting == 2 || exitcountdown == 2)
|
||||
{
|
||||
if (server)
|
||||
{
|
||||
SendNetXCmd(XD_EXITLEVEL, NULL, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check water content, set stuff in mobj
|
||||
P_MobjCheckWater(player->mo);
|
||||
|
||||
#ifndef SECTORSPECIALSAFTERTHINK
|
||||
if (player->onconveyor != 1 || !P_IsObjectOnGround(player->mo))
|
||||
player->onconveyor = 0;
|
||||
// check special sectors : damage & secrets
|
||||
|
||||
if (!player->spectator)
|
||||
P_PlayerInSpecialSector(player);
|
||||
#endif
|
||||
|
||||
if (player->playerstate == PST_DEAD)
|
||||
{
|
||||
if (player->spectator)
|
||||
player->mo->renderflags |= RF_GHOSTLY;
|
||||
else
|
||||
player->mo->renderflags &= ~RF_GHOSTLYMASK;
|
||||
P_DeathThink(player);
|
||||
LUA_HookPlayer(player, HOOK(PlayerThink));
|
||||
return;
|
||||
}
|
||||
|
||||
// Make sure spectators always have a score and ring count of 0.
|
||||
|
|
@ -4062,7 +4009,103 @@ void P_PlayerThink(player_t *player)
|
|||
}
|
||||
}
|
||||
|
||||
if ((netgame || multiplayer) && player->spectator && cmd->buttons & BT_ATTACK && !player->flashing)
|
||||
if (cmd->flags & TICCMD_TYPING)
|
||||
{
|
||||
/*
|
||||
typing_duration is slow to start and slow to stop.
|
||||
|
||||
typing_timer counts down a grace period before the player is not
|
||||
actually considered typing anymore.
|
||||
*/
|
||||
if (cmd->flags & TICCMD_KEYSTROKE)
|
||||
{
|
||||
/* speed up if we are typing quickly! */
|
||||
if (player->typing_duration > 0 && player->typing_timer > 12)
|
||||
{
|
||||
if (player->typing_duration < 16)
|
||||
{
|
||||
player->typing_duration = 24;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* slows down a tiny bit as it approaches the next dot */
|
||||
const UINT8 step = (((player->typing_duration + 15) & ~15) -
|
||||
player->typing_duration) / 2;
|
||||
player->typing_duration += max(step, 4);
|
||||
}
|
||||
}
|
||||
|
||||
player->typing_timer = 15;
|
||||
}
|
||||
else if (player->typing_timer > 0)
|
||||
{
|
||||
player->typing_timer--;
|
||||
}
|
||||
|
||||
/* if we are in the grace period (including currently typing) */
|
||||
if (player->typing_timer + player->typing_duration > 0)
|
||||
{
|
||||
/* always end the cycle on two dots */
|
||||
if (player->typing_timer == 0 &&
|
||||
(player->typing_duration < 16 || player->typing_duration == 40))
|
||||
{
|
||||
player->typing_duration = 0;
|
||||
}
|
||||
else if (player->typing_duration < 63)
|
||||
{
|
||||
player->typing_duration++;
|
||||
}
|
||||
else
|
||||
{
|
||||
player->typing_duration = 16;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
player->typing_timer = 0;
|
||||
player->typing_duration = 0;
|
||||
}
|
||||
|
||||
/* ------------------------------------------ /
|
||||
ALL ABOVE THIS BLOCK OCCURS EVEN WITH HITLAG
|
||||
/ ------------------------------------------ */
|
||||
|
||||
if (player->mo->hitlag > 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* ------------------------------------------ /
|
||||
ALL BELOW THIS BLOCK IS STOPPED DURING HITLAG
|
||||
/ ------------------------------------------ */
|
||||
|
||||
player->pflags &= ~PF_HITFINISHLINE;
|
||||
|
||||
// check water content, set stuff in mobj
|
||||
P_MobjCheckWater(player->mo);
|
||||
|
||||
#ifndef SECTORSPECIALSAFTERTHINK
|
||||
if (player->onconveyor != 1 || !P_IsObjectOnGround(player->mo))
|
||||
player->onconveyor = 0;
|
||||
// check special sectors : damage & secrets
|
||||
|
||||
if (!player->spectator)
|
||||
P_PlayerInSpecialSector(player);
|
||||
#endif
|
||||
|
||||
if (player->playerstate == PST_DEAD)
|
||||
{
|
||||
if (player->spectator)
|
||||
player->mo->renderflags |= RF_GHOSTLY;
|
||||
else
|
||||
player->mo->renderflags &= ~RF_GHOSTLYMASK;
|
||||
P_DeathThink(player);
|
||||
LUA_HookPlayer(player, HOOK(PlayerThink));
|
||||
return;
|
||||
}
|
||||
|
||||
if ((netgame || multiplayer) && player->spectator && !player->bot && cmd->buttons & BT_ATTACK && !player->flashing)
|
||||
{
|
||||
player->pflags ^= PF_WANTSTOJOIN;
|
||||
player->flashing = TICRATE/2 + 1;
|
||||
|
|
@ -4144,64 +4187,6 @@ void P_PlayerThink(player_t *player)
|
|||
player->mo->renderflags &= ~RF_DONTDRAW;
|
||||
}
|
||||
|
||||
if (cmd->flags & TICCMD_TYPING)
|
||||
{
|
||||
/*
|
||||
typing_duration is slow to start and slow to stop.
|
||||
|
||||
typing_timer counts down a grace period before the player is not
|
||||
actually considered typing anymore.
|
||||
*/
|
||||
if (cmd->flags & TICCMD_KEYSTROKE)
|
||||
{
|
||||
/* speed up if we are typing quickly! */
|
||||
if (player->typing_duration > 0 && player->typing_timer > 12)
|
||||
{
|
||||
if (player->typing_duration < 16)
|
||||
{
|
||||
player->typing_duration = 24;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* slows down a tiny bit as it approaches the next dot */
|
||||
const UINT8 step = (((player->typing_duration + 15) & ~15) -
|
||||
player->typing_duration) / 2;
|
||||
player->typing_duration += max(step, 4);
|
||||
}
|
||||
}
|
||||
|
||||
player->typing_timer = 15;
|
||||
}
|
||||
else if (player->typing_timer > 0)
|
||||
{
|
||||
player->typing_timer--;
|
||||
}
|
||||
|
||||
/* if we are in the grace period (including currently typing) */
|
||||
if (player->typing_timer + player->typing_duration > 0)
|
||||
{
|
||||
/* always end the cycle on two dots */
|
||||
if (player->typing_timer == 0 &&
|
||||
(player->typing_duration < 16 || player->typing_duration == 40))
|
||||
{
|
||||
player->typing_duration = 0;
|
||||
}
|
||||
else if (player->typing_duration < 63)
|
||||
{
|
||||
player->typing_duration++;
|
||||
}
|
||||
else
|
||||
{
|
||||
player->typing_duration = 16;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
player->typing_timer = 0;
|
||||
player->typing_duration = 0;
|
||||
}
|
||||
|
||||
if (player->stairjank > 0)
|
||||
{
|
||||
player->stairjank--;
|
||||
|
|
|
|||
|
|
@ -437,6 +437,7 @@ static patch_t *tcol2;
|
|||
|
||||
static patch_t *tcroundbar;
|
||||
static patch_t *tcround;
|
||||
static patch_t *tcbonus;
|
||||
|
||||
static patch_t *tccircletop;
|
||||
static patch_t *tccirclebottom;
|
||||
|
|
@ -446,6 +447,8 @@ static patch_t *tcbanner;
|
|||
static patch_t *tcbanner2;
|
||||
|
||||
static patch_t *tcroundnum[10];
|
||||
static patch_t *tcroundbonus;
|
||||
|
||||
static patch_t *tcactnum[10];
|
||||
static patch_t *tcact;
|
||||
|
||||
|
|
@ -495,6 +498,7 @@ static void ST_cacheLevelTitle(void)
|
|||
|
||||
tcroundbar = (patch_t *)W_CachePatchName("TCBB0", PU_HUDGFX);
|
||||
tcround = (patch_t *)W_CachePatchName("TCROUND", PU_HUDGFX);
|
||||
tcbonus = (patch_t *)W_CachePatchName("TCBONUS", PU_HUDGFX);
|
||||
|
||||
tccircletop = (patch_t *)W_CachePatchName("TCSN1", PU_HUDGFX);
|
||||
tccirclebottom =(patch_t *)W_CachePatchName("TCSN2", PU_HUDGFX);
|
||||
|
|
@ -514,6 +518,7 @@ static void ST_cacheLevelTitle(void)
|
|||
sprintf(buf, "TT_RND%d", i);
|
||||
tcroundnum[i-1] = (patch_t *)W_CachePatchName(buf, PU_HUDGFX);
|
||||
}
|
||||
tcroundbonus = (patch_t *)W_CachePatchName("TT_RNDB", PU_HUDGFX);
|
||||
|
||||
// Cache act #
|
||||
for (i=0; i < 10; i++)
|
||||
|
|
@ -579,7 +584,7 @@ void ST_runTitleCard(void)
|
|||
{
|
||||
boolean run = !(paused || P_AutoPause());
|
||||
INT32 auxticker;
|
||||
boolean gp = (grandprixinfo.gp && grandprixinfo.roundnum); // check whether we're in grandprix
|
||||
boolean gp = (marathonmode || (grandprixinfo.gp && grandprixinfo.roundnum));
|
||||
|
||||
if (!G_IsTitleCardAvailable())
|
||||
return;
|
||||
|
|
@ -764,7 +769,7 @@ void ST_drawTitleCard(void)
|
|||
char *lvlttl = mapheaderinfo[gamemap-1]->lvlttl;
|
||||
char *zonttl = mapheaderinfo[gamemap-1]->zonttl; // SRB2kart
|
||||
UINT8 actnum = mapheaderinfo[gamemap-1]->actnum;
|
||||
boolean gp = (grandprixinfo.gp && grandprixinfo.roundnum);
|
||||
boolean gp = (marathonmode || (grandprixinfo.gp && grandprixinfo.roundnum));
|
||||
|
||||
INT32 acttimer;
|
||||
fixed_t actscale;
|
||||
|
|
@ -895,7 +900,9 @@ void ST_drawTitleCard(void)
|
|||
V_DrawFixedPatch(roundx*FRACUNIT, ((-32) + (lt_ticker%32))*FRACUNIT, FRACUNIT, V_SNAPTOTOP|V_SNAPTOLEFT, tcroundbar, NULL);
|
||||
// Draw ROUND text
|
||||
if (gp)
|
||||
V_DrawFixedPatch((roundx+10)*FRACUNIT, roundy*FRACUNIT, FRACUNIT, V_SNAPTOTOP|V_SNAPTOLEFT, tcround, NULL);
|
||||
V_DrawFixedPatch((roundx+10)*FRACUNIT, roundy*FRACUNIT, FRACUNIT, V_SNAPTOTOP|V_SNAPTOLEFT,
|
||||
((grandprixinfo.gp && grandprixinfo.eventmode) ? tcbonus : tcround),
|
||||
NULL);
|
||||
|
||||
// round num background
|
||||
V_DrawFixedPatch(roundnumx*FRACUNIT, roundnumy*FRACUNIT, FRACUNIT, V_SNAPTOBOTTOM|V_SNAPTOLEFT, tccirclebg, NULL);
|
||||
|
|
@ -912,9 +919,31 @@ void ST_drawTitleCard(void)
|
|||
}
|
||||
}
|
||||
|
||||
// If possible, draw round number
|
||||
if (gp && grandprixinfo.roundnum > 0 && grandprixinfo.roundnum < 11) // Check boundaries JUST IN CASE.
|
||||
V_DrawFixedPatch(roundnumx*FRACUNIT, roundnumy*FRACUNIT, FRACUNIT, V_SNAPTOBOTTOM|V_SNAPTOLEFT, tcroundnum[grandprixinfo.roundnum-1], NULL);
|
||||
// If possible, draw round number/icon
|
||||
if (gp)
|
||||
{
|
||||
patch_t *roundico = NULL;
|
||||
if (marathonmode)
|
||||
; // TODO: Ruby
|
||||
else switch (grandprixinfo.eventmode)
|
||||
{
|
||||
case GPEVENT_BONUS:
|
||||
roundico = tcroundbonus; // TODO don't show capsule if we have other bonus types
|
||||
break;
|
||||
/*case GPEVENT_SPECIAL:
|
||||
; // TODO: Emerald/mount
|
||||
break;*/
|
||||
case GPEVENT_NONE:
|
||||
if (grandprixinfo.roundnum > 0 && grandprixinfo.roundnum < 11) // Check boundaries JUST IN CASE.
|
||||
roundico = tcroundnum[grandprixinfo.roundnum-1];
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (roundico)
|
||||
V_DrawFixedPatch(roundnumx*FRACUNIT, roundnumy*FRACUNIT, FRACUNIT, V_SNAPTOBOTTOM|V_SNAPTOLEFT, roundico, NULL);
|
||||
}
|
||||
|
||||
// Draw both halves of the egg
|
||||
V_DrawFixedPatch(eggx1*FRACUNIT, eggy1*FRACUNIT, FRACUNIT, V_SNAPTOBOTTOM|V_SNAPTOLEFT, tccircletop, NULL);
|
||||
|
|
|
|||
|
|
@ -657,18 +657,8 @@ void Y_Ticker(void)
|
|||
P_DoTeamscrambling();
|
||||
}*/
|
||||
|
||||
// multiplayer uses timer (based on cv_inttime)
|
||||
if (timer)
|
||||
{
|
||||
if (!--timer)
|
||||
{
|
||||
Y_EndIntermission();
|
||||
G_AfterIntermission();
|
||||
return;
|
||||
}
|
||||
}
|
||||
// single player is hardcoded to go away after awhile
|
||||
else if (intertic == endtic)
|
||||
if ((timer && !--timer)
|
||||
|| (intertic == endtic))
|
||||
{
|
||||
Y_EndIntermission();
|
||||
G_AfterIntermission();
|
||||
|
|
@ -680,10 +670,10 @@ void Y_Ticker(void)
|
|||
|
||||
if (intertype == int_race || intertype == int_battle || intertype == int_battletime)
|
||||
{
|
||||
//if (!(multiplayer && demo.playback)) // Don't advance to rankings in replays
|
||||
{
|
||||
if (!data.rankingsmode && sorttic != -1 && (intertic >= sorttic + 8))
|
||||
{
|
||||
// Anything with post-intermission consequences here should also occur in Y_EndIntermission.
|
||||
K_RetireBots();
|
||||
Y_CalculateMatchData(1, Y_CompareRank);
|
||||
}
|
||||
|
|
@ -746,8 +736,8 @@ void Y_Ticker(void)
|
|||
S_StartSound(NULL, (kaching ? sfx_chchng : sfx_ptally));
|
||||
Y_CalculateMatchData(2, Y_CompareRank);
|
||||
}
|
||||
else
|
||||
endtic = intertic + 3*TICRATE; // 3 second pause after end of tally
|
||||
/*else -- This is how to define an endtic, but we currently use timer for both SP and MP.
|
||||
endtic = intertic + 3*TICRATE;*/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -763,21 +753,26 @@ void Y_DetermineIntermissionType(void)
|
|||
// set to int_none initially
|
||||
intertype = int_none;
|
||||
|
||||
if (intermissiontypes[gametype] != int_none)
|
||||
intertype = intermissiontypes[gametype];
|
||||
else if (gametype == GT_RACE)
|
||||
if (gametype == GT_RACE)
|
||||
intertype = int_race;
|
||||
else if (gametype == GT_BATTLE)
|
||||
{
|
||||
UINT8 i = 0, nump = 0;
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
if (grandprixinfo.gp == true && bossinfo.boss == false)
|
||||
intertype = int_none;
|
||||
else
|
||||
{
|
||||
if (!playeringame[i] || players[i].spectator)
|
||||
continue;
|
||||
nump++;
|
||||
UINT8 i = 0, nump = 0;
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
if (!playeringame[i] || players[i].spectator)
|
||||
continue;
|
||||
nump++;
|
||||
}
|
||||
intertype = (nump < 2 ? int_battletime : int_battle);
|
||||
}
|
||||
intertype = (nump < 2 ? int_battletime : int_battle);
|
||||
}
|
||||
else //if (intermissiontypes[gametype] != int_none)
|
||||
intertype = intermissiontypes[gametype];
|
||||
}
|
||||
|
||||
//
|
||||
|
|
@ -806,23 +801,32 @@ void Y_StartIntermission(void)
|
|||
powertype = K_UsingPowerLevels();
|
||||
|
||||
// determine the tic the intermission ends
|
||||
if (!multiplayer || demo.playback)
|
||||
// Technically cv_inttime is saved to demos... but this permits having extremely long timers for post-netgame chatting without stranding you on the intermission in netreplays.
|
||||
if (!K_CanChangeRules(false))
|
||||
{
|
||||
timer = ((nump >= 2) ? 10 : 5)*TICRATE;
|
||||
timer = 10*TICRATE;
|
||||
}
|
||||
else
|
||||
{
|
||||
timer = cv_inttime.value*TICRATE;
|
||||
|
||||
if (!timer)
|
||||
timer = 1; // prevent a weird bug
|
||||
}
|
||||
|
||||
// determine the tic everybody's scores/PWR starts getting sorted
|
||||
sorttic = -1;
|
||||
if (multiplayer || nump >= 2)
|
||||
if (!timer)
|
||||
{
|
||||
sorttic = max((timer/2) - 2*TICRATE, 2*TICRATE); // 8 second pause after match results
|
||||
// Prevent a weird bug
|
||||
timer = 1;
|
||||
}
|
||||
else if (nump < 2 && !netgame)
|
||||
{
|
||||
// No PWR/global score, skip it
|
||||
timer /= 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Minimum two seconds for match results, then two second slideover approx halfway through
|
||||
sorttic = max((timer/2) - 2*TICRATE, 2*TICRATE);
|
||||
}
|
||||
|
||||
if (intermissiontypes[gametype] != int_none)
|
||||
|
|
@ -841,7 +845,7 @@ void Y_StartIntermission(void)
|
|||
case int_battle:
|
||||
case int_battletime:
|
||||
{
|
||||
if (cv_inttime.value > 0)
|
||||
if (timer > 1)
|
||||
S_ChangeMusicInternal("racent", true); // loop it
|
||||
|
||||
// Calculate who won
|
||||
|
|
@ -897,7 +901,11 @@ void Y_StartIntermission(void)
|
|||
//
|
||||
void Y_EndIntermission(void)
|
||||
{
|
||||
K_RetireBots();
|
||||
if (!data.rankingsmode)
|
||||
{
|
||||
K_RetireBots();
|
||||
}
|
||||
|
||||
Y_UnloadData();
|
||||
|
||||
endtic = -1;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue