mirror of
https://github.com/KartKrewDev/RingRacers.git
synced 2025-12-24 08:52:33 +00:00
Merge branch 'podium' into 'master'
Podium See merge request KartKrew/Kart!1014
This commit is contained in:
commit
cdc56ab2cc
51 changed files with 2541 additions and 451 deletions
|
|
@ -134,6 +134,8 @@ add_executable(SRB2SDL2 MACOSX_BUNDLE WIN32
|
|||
k_profiles.c
|
||||
k_specialstage.c
|
||||
k_roulette.c
|
||||
k_podium.c
|
||||
k_rank.c
|
||||
)
|
||||
|
||||
if(SRB2_CONFIG_ENABLE_WEBM_MOVIES)
|
||||
|
|
|
|||
|
|
@ -50,6 +50,7 @@ extern "C" {
|
|||
#include "../m_cond.h"
|
||||
#include "../r_skins.h"
|
||||
#include "../k_battle.h"
|
||||
#include "../k_podium.h"
|
||||
}
|
||||
|
||||
#include "call-funcs.hpp"
|
||||
|
|
@ -445,6 +446,25 @@ bool CallFunc_PolyWait(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Wo
|
|||
return true; // Execution interrupted
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
bool CallFunc_CameraWait(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC)
|
||||
|
||||
Pauses the thread until the tagged
|
||||
camera is done moving.
|
||||
--------------------------------------------------*/
|
||||
bool CallFunc_CameraWait(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC)
|
||||
{
|
||||
(void)argC;
|
||||
|
||||
thread->state = {
|
||||
ACSVM::ThreadState::WaitTag,
|
||||
argV[0],
|
||||
ACS_TAGTYPE_CAMERA
|
||||
};
|
||||
|
||||
return true; // Execution interrupted
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
bool CallFunc_ChangeFloor(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC)
|
||||
|
||||
|
|
@ -1332,3 +1352,59 @@ bool CallFunc_EncoreMode(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::
|
|||
thread->dataStk.push(encoremode);
|
||||
return false;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
bool CallFunc_PodiumPosition(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC)
|
||||
|
||||
Returns the best position of all non-CPU players.
|
||||
--------------------------------------------------*/
|
||||
bool CallFunc_PodiumPosition(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC)
|
||||
{
|
||||
UINT8 ret = MAXPLAYERS;
|
||||
INT32 i;
|
||||
|
||||
(void)argV;
|
||||
(void)argC;
|
||||
|
||||
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->bot == true)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
ret = std::min(ret, player->position);
|
||||
}
|
||||
|
||||
thread->dataStk.push(ret);
|
||||
return false;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
bool CallFunc_PodiumFinish(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC)
|
||||
|
||||
Ends the podium sequence. Doesn't do anything
|
||||
outside of podium maps.
|
||||
--------------------------------------------------*/
|
||||
bool CallFunc_PodiumFinish(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC)
|
||||
{
|
||||
(void)argV;
|
||||
(void)argC;
|
||||
|
||||
K_FinishCeremony();
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -50,6 +50,7 @@ bool CallFunc_Random(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word
|
|||
bool CallFunc_ThingCount(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC);
|
||||
bool CallFunc_TagWait(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC);
|
||||
bool CallFunc_PolyWait(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC);
|
||||
bool CallFunc_CameraWait(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC);
|
||||
bool CallFunc_ChangeFloor(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC);
|
||||
bool CallFunc_ChangeCeiling(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC);
|
||||
bool CallFunc_LineSide(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC);
|
||||
|
|
@ -84,4 +85,7 @@ bool CallFunc_PlayerLap(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::W
|
|||
bool CallFunc_LowestLap(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC);
|
||||
bool CallFunc_EncoreMode(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC);
|
||||
|
||||
bool CallFunc_PodiumPosition(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC);
|
||||
bool CallFunc_PodiumFinish(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC);
|
||||
|
||||
#endif // __SRB2_ACS_CALL_FUNCS_HPP__
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ extern "C" {
|
|||
#include "../p_spec.h"
|
||||
#include "../w_wad.h"
|
||||
#include "../z_zone.h"
|
||||
#include "../p_local.h"
|
||||
}
|
||||
|
||||
#include "environment.hpp"
|
||||
|
|
@ -160,6 +161,10 @@ Environment::Environment()
|
|||
addFuncDataACS0( 307, addCallFunc(CallFunc_PlayerLap));
|
||||
addFuncDataACS0( 308, addCallFunc(CallFunc_LowestLap));
|
||||
addFuncDataACS0( 309, addCallFunc(CallFunc_EncoreMode));
|
||||
|
||||
addFuncDataACS0( 500, addCallFunc(CallFunc_CameraWait));
|
||||
addFuncDataACS0( 501, addCallFunc(CallFunc_PodiumPosition));
|
||||
addFuncDataACS0( 502, addCallFunc(CallFunc_PodiumFinish));
|
||||
}
|
||||
|
||||
ACSVM::Thread *Environment::allocThread()
|
||||
|
|
@ -262,6 +267,17 @@ bool Environment::checkTag(ACSVM::Word type, ACSVM::Word tag)
|
|||
const polyobj_t *po = Polyobj_GetForNum(tag);
|
||||
return (po == nullptr || po->thinker == nullptr);
|
||||
}
|
||||
|
||||
case ACS_TAGTYPE_CAMERA:
|
||||
{
|
||||
const mobj_t *camera = P_FindObjectTypeFromTag(MT_ALTVIEWMAN, tag);
|
||||
if (camera == nullptr || camera->spawnpoint == nullptr)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return (camera->tracer == nullptr || P_MobjWasRemoved(camera->tracer) == true);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -57,6 +57,7 @@ enum acs_tagType_e
|
|||
{
|
||||
ACS_TAGTYPE_POLYOBJ,
|
||||
ACS_TAGTYPE_SECTOR,
|
||||
ACS_TAGTYPE_CAMERA,
|
||||
};
|
||||
|
||||
class ThreadInfo : public ACSVM::ThreadInfo
|
||||
|
|
|
|||
|
|
@ -1839,6 +1839,25 @@ static void CON_DrawConsole(void)
|
|||
|
||||
// Console refresh drawer, call each frame
|
||||
//
|
||||
static boolean CON_GamestateDrawHudLines(void)
|
||||
{
|
||||
switch (gamestate)
|
||||
{
|
||||
case GS_LEVEL:
|
||||
case GS_INTERMISSION:
|
||||
case GS_VOTING:
|
||||
case GS_CUTSCENE:
|
||||
case GS_CREDITS:
|
||||
case GS_EVALUATION:
|
||||
case GS_WAITINGPLAYERS:
|
||||
case GS_CEREMONY:
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void CON_Drawer(void)
|
||||
{
|
||||
Lock_state();
|
||||
|
|
@ -1858,8 +1877,7 @@ void CON_Drawer(void)
|
|||
|
||||
if (con_curlines > 0)
|
||||
CON_DrawConsole();
|
||||
else if (gamestate == GS_LEVEL || gamestate == GS_INTERMISSION || gamestate == GS_CUTSCENE || gamestate == GS_CREDITS
|
||||
|| gamestate == GS_VOTING || gamestate == GS_EVALUATION || gamestate == GS_WAITINGPLAYERS)
|
||||
else if (CON_GamestateDrawHudLines() == true)
|
||||
CON_DrawHudlines();
|
||||
|
||||
Unlock_state();
|
||||
|
|
|
|||
|
|
@ -1272,7 +1272,7 @@ static void CL_LoadReceivedSavegame(boolean reloading)
|
|||
paused = false;
|
||||
demo.playback = false;
|
||||
demo.title = false;
|
||||
titlemapinaction = TITLEMAP_OFF;
|
||||
titlemapinaction = false;
|
||||
automapactive = false;
|
||||
|
||||
// load a base level
|
||||
|
|
@ -2542,7 +2542,7 @@ void CL_ClearPlayer(INT32 playernum)
|
|||
int i;
|
||||
|
||||
// Handle mobj_t pointers.
|
||||
if (gamestate == GS_LEVEL)
|
||||
if (G_GamestateUsesLevel() == true)
|
||||
{
|
||||
if (players[playernum].follower)
|
||||
{
|
||||
|
|
@ -2557,7 +2557,7 @@ void CL_ClearPlayer(INT32 playernum)
|
|||
|
||||
P_SetTarget(&players[playernum].skybox.viewpoint, NULL);
|
||||
P_SetTarget(&players[playernum].skybox.centerpoint, NULL);
|
||||
P_SetTarget(&players[playernum].awayviewmobj, NULL);
|
||||
P_SetTarget(&players[playernum].awayview.mobj, NULL);
|
||||
P_SetTarget(&players[playernum].followmobj, NULL);
|
||||
P_SetTarget(&players[playernum].hoverhyudoro, NULL);
|
||||
P_SetTarget(&players[playernum].stumbleIndicator, NULL);
|
||||
|
|
@ -3771,9 +3771,6 @@ static void Got_AddBot(UINT8 **p, INT32 playernum)
|
|||
sprintf(player_names[newplayernum], "%s", skins[skinnum].realname);
|
||||
SetPlayerSkinByNum(newplayernum, skinnum);
|
||||
|
||||
players[newplayernum].spectator = !(gametyperules & GTR_BOTS)
|
||||
|| (grandprixinfo.gp == true && grandprixinfo.eventmode != GPEVENT_NONE);
|
||||
|
||||
if (netgame)
|
||||
{
|
||||
HU_AddChatText(va("\x82*Bot %d has been added to the game", newplayernum+1), false);
|
||||
|
|
|
|||
57
src/d_main.c
57
src/d_main.c
|
|
@ -76,6 +76,7 @@
|
|||
#include "m_random.h" // P_ClearRandom
|
||||
#include "k_specialstage.h"
|
||||
#include "acs/interface.h"
|
||||
#include "k_podium.h"
|
||||
|
||||
#ifdef HWRENDER
|
||||
#include "hardware/hw_main.h" // 3D View Rendering
|
||||
|
|
@ -344,8 +345,8 @@ static void D_Display(void)
|
|||
if (rendermode != render_none)
|
||||
{
|
||||
// Fade to black first
|
||||
if (!(gamestate == GS_LEVEL || (gamestate == GS_TITLESCREEN && titlemapinaction)) // fades to black on its own timing, always
|
||||
&& wipetypepre != UINT8_MAX)
|
||||
if (G_GamestateUsesLevel() == false // fades to black on its own timing, always
|
||||
&& wipetypepre != UINT8_MAX)
|
||||
{
|
||||
F_WipeStartScreen();
|
||||
F_WipeColorFill(31);
|
||||
|
|
@ -353,7 +354,7 @@ static void D_Display(void)
|
|||
F_RunWipe(wipedefindex, wipetypepre, gamestate != GS_MENU, "FADEMAP0", false, false);
|
||||
}
|
||||
|
||||
if (gamestate != GS_LEVEL && rendermode != render_none)
|
||||
if (G_GamestateUsesLevel() == false && rendermode != render_none)
|
||||
{
|
||||
V_SetPaletteLump("PLAYPAL"); // Reset the palette
|
||||
R_ReInitColormaps(0, NULL, 0);
|
||||
|
|
@ -406,6 +407,13 @@ static void D_Display(void)
|
|||
HU_Drawer();
|
||||
break;
|
||||
|
||||
case GS_CEREMONY:
|
||||
if (!gametic)
|
||||
break;
|
||||
HU_Erase();
|
||||
HU_Drawer();
|
||||
break;
|
||||
|
||||
case GS_MENU:
|
||||
break;
|
||||
|
||||
|
|
@ -470,7 +478,7 @@ static void D_Display(void)
|
|||
|
||||
// clean up border stuff
|
||||
// see if the border needs to be initially drawn
|
||||
if (gamestate == GS_LEVEL || (gamestate == GS_TITLESCREEN && titlemapinaction && curbghide && (!hidetitlemap)))
|
||||
if (G_GamestateUsesLevel() == true)
|
||||
{
|
||||
if (!automapactive && !dedicated && cv_renderview.value)
|
||||
{
|
||||
|
|
@ -566,14 +574,30 @@ static void D_Display(void)
|
|||
|
||||
ps_uitime = I_GetPreciseTime();
|
||||
|
||||
if (gamestate == GS_LEVEL)
|
||||
switch (gamestate)
|
||||
{
|
||||
ST_Drawer();
|
||||
F_TextPromptDrawer();
|
||||
HU_Drawer();
|
||||
case GS_LEVEL:
|
||||
{
|
||||
ST_Drawer();
|
||||
F_TextPromptDrawer();
|
||||
HU_Drawer();
|
||||
break;
|
||||
}
|
||||
case GS_TITLESCREEN:
|
||||
{
|
||||
F_TitleScreenDrawer();
|
||||
break;
|
||||
}
|
||||
case GS_CEREMONY:
|
||||
{
|
||||
K_CeremonyDrawer();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
F_TitleScreenDrawer();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -583,7 +607,7 @@ static void D_Display(void)
|
|||
|
||||
// change gamma if needed
|
||||
// (GS_LEVEL handles this already due to level-specific palettes)
|
||||
if (forcerefresh && !(gamestate == GS_LEVEL || (gamestate == GS_TITLESCREEN && titlemapinaction)))
|
||||
if (forcerefresh && G_GamestateUsesLevel() == false)
|
||||
V_SetPalette(0);
|
||||
|
||||
// draw pause pic
|
||||
|
|
@ -752,17 +776,6 @@ void D_SRB2Loop(void)
|
|||
because I_FinishUpdate was called afterward
|
||||
*/
|
||||
|
||||
#if 0
|
||||
/* Smells like a hack... Don't fade Sonic's ass into the title screen. */
|
||||
if (gamestate != GS_TITLESCREEN)
|
||||
{
|
||||
static lumpnum_t gstartuplumpnum = W_CheckNumForName("STARTUP");
|
||||
if (gstartuplumpnum == LUMPERROR)
|
||||
gstartuplumpnum = W_GetNumForName("MISSING");
|
||||
V_DrawScaledPatch(0, 0, 0, W_CachePatchNum(gstartuplumpnum, PU_PATCH));
|
||||
}
|
||||
#endif
|
||||
|
||||
for (;;)
|
||||
{
|
||||
// capbudget is the minimum precise_t duration of a single loop iteration
|
||||
|
|
|
|||
|
|
@ -453,6 +453,7 @@ consvar_t cv_kartdebugcolorize = CVAR_INIT ("debugcolorize", "Off", CV_CHEAT, CV
|
|||
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);
|
||||
consvar_t cv_debugrank = CVAR_INIT ("debugrank", "Off", CV_CHEAT, CV_OnOff, NULL);
|
||||
|
||||
static CV_PossibleValue_t capsuletest_cons_t[] = {
|
||||
{CV_CAPSULETEST_OFF, "Off"},
|
||||
|
|
@ -5330,14 +5331,22 @@ static void Command_Mapmd5_f(void)
|
|||
|
||||
static void Command_ExitLevel_f(void)
|
||||
{
|
||||
if (!(netgame || multiplayer) && !CV_CheatsEnabled())
|
||||
CONS_Printf(M_GetText("This only works in a netgame.\n"));
|
||||
else if (!(server || (IsPlayerAdmin(consoleplayer))))
|
||||
if (!(server || (IsPlayerAdmin(consoleplayer))))
|
||||
{
|
||||
CONS_Printf(M_GetText("Only the server or a remote admin can use this.\n"));
|
||||
}
|
||||
else if (K_CanChangeRules(false) == false && CV_CheatsEnabled() == false)
|
||||
{
|
||||
CONS_Printf(M_GetText("This cannot be used without cheats enabled.\n"));
|
||||
}
|
||||
else if (( gamestate != GS_LEVEL && gamestate != GS_CREDITS ) || demo.playback)
|
||||
{
|
||||
CONS_Printf(M_GetText("You must be in a level to use this.\n"));
|
||||
}
|
||||
else
|
||||
{
|
||||
SendNetXCmd(XD_EXITLEVEL, NULL, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static void Got_ExitLevelcmd(UINT8 **cp, INT32 playernum)
|
||||
|
|
|
|||
|
|
@ -96,6 +96,7 @@ extern consvar_t cv_kartdebugitem, cv_kartdebugamount, cv_kartdebugdistribution,
|
|||
extern consvar_t cv_kartdebugnodes, cv_kartdebugcolorize, cv_kartdebugdirector;
|
||||
extern consvar_t cv_spbtest, cv_gptest, cv_reducevfx;
|
||||
extern consvar_t cv_kartdebugwaypoints, cv_kartdebugbotpredict;
|
||||
extern consvar_t cv_debugrank;
|
||||
|
||||
typedef enum {
|
||||
CV_CAPSULETEST_OFF,
|
||||
|
|
|
|||
|
|
@ -384,6 +384,13 @@ typedef struct {
|
|||
boolean flip;
|
||||
} sonicloopvars_t;
|
||||
|
||||
// player_t struct for all alternative viewpoint variables
|
||||
struct altview_t
|
||||
{
|
||||
mobj_t *mobj;
|
||||
INT32 tics;
|
||||
};
|
||||
|
||||
// ========================================================================
|
||||
// PLAYER STRUCTURE
|
||||
// ========================================================================
|
||||
|
|
@ -627,6 +634,7 @@ struct player_t
|
|||
tic_t realtime; // integer replacement for leveltime
|
||||
UINT8 laps; // Number of laps (optional)
|
||||
UINT8 latestlap;
|
||||
UINT32 lapPoints; // Points given from laps
|
||||
INT32 starpostnum; // The number of the last starpost you hit
|
||||
|
||||
UINT8 ctfteam; // 0 == Spectator, 1 == Red, 2 == Blue
|
||||
|
|
@ -644,9 +652,7 @@ struct player_t
|
|||
|
||||
INT32 onconveyor; // You are on a conveyor belt if nonzero
|
||||
|
||||
mobj_t *awayviewmobj;
|
||||
INT32 awayviewtics;
|
||||
angle_t awayviewaiming; // Used for cut-away view
|
||||
altview_t awayview;
|
||||
|
||||
boolean spectator;
|
||||
tic_t spectatewait; // reimplementable as UINT8 queue - How long have you been waiting as a spectator
|
||||
|
|
|
|||
|
|
@ -2559,6 +2559,10 @@ void readmaincfg(MYFILE *f, boolean mainfile)
|
|||
INT32 value;
|
||||
boolean doClearLevels = false;
|
||||
|
||||
#ifdef DEVELOP
|
||||
(void)mainfile;
|
||||
#endif
|
||||
|
||||
do
|
||||
{
|
||||
if (myfgets(s, MAXLINELEN, f))
|
||||
|
|
@ -2630,10 +2634,12 @@ void readmaincfg(MYFILE *f, boolean mainfile)
|
|||
//clear_levels();
|
||||
doClearLevels = true;
|
||||
}
|
||||
#ifndef DEVELOP
|
||||
else if (!mainfile && !gamedataadded)
|
||||
{
|
||||
deh_warning("You must define a custom gamedata to use \"%s\"", word);
|
||||
}
|
||||
#endif
|
||||
else if (fastcmp(word, "CLEARLEVELS"))
|
||||
{
|
||||
doClearLevels = (UINT8)(value == 0 || word2[0] == 'F' || word2[0] == 'N');
|
||||
|
|
@ -2741,6 +2747,7 @@ void readmaincfg(MYFILE *f, boolean mainfile)
|
|||
}
|
||||
else if (fastcmp(word, "TITLEMAP"))
|
||||
{
|
||||
Z_Free(titlemap);
|
||||
titlemap = Z_StrDup(word2);
|
||||
titlechanged = true;
|
||||
}
|
||||
|
|
@ -2835,13 +2842,20 @@ void readmaincfg(MYFILE *f, boolean mainfile)
|
|||
}
|
||||
else if (fastcmp(word, "BOOTMAP"))
|
||||
{
|
||||
Z_Free(bootmap);
|
||||
bootmap = Z_StrDup(word2);
|
||||
//titlechanged = true;
|
||||
}
|
||||
else if (fastcmp(word, "TUTORIALMAP"))
|
||||
{
|
||||
Z_Free(tutorialmap);
|
||||
tutorialmap = Z_StrDup(word2);
|
||||
}
|
||||
else if (fastcmp(word, "PODIUMMAP"))
|
||||
{
|
||||
Z_Free(podiummap);
|
||||
podiummap = Z_StrDup(word2);
|
||||
}
|
||||
else
|
||||
deh_warning("Maincfg: unknown word '%s'", word);
|
||||
}
|
||||
|
|
@ -2980,6 +2994,14 @@ void readwipes(MYFILE *f)
|
|||
else if (fastcmp(pword, "FINAL"))
|
||||
wipeoffset = wipe_gameend_final;
|
||||
}
|
||||
else if (fastncmp(word, "CEREMONY_", 9))
|
||||
{
|
||||
pword = word + 9;
|
||||
if (fastcmp(pword, "TOBLACK"))
|
||||
wipeoffset = wipe_ceremony_toblack;
|
||||
else if (fastcmp(pword, "FINAL"))
|
||||
wipeoffset = wipe_ceremony_final;
|
||||
}
|
||||
else if (fastncmp(word, "ENCORE_", 7))
|
||||
{
|
||||
pword = word + 7;
|
||||
|
|
|
|||
|
|
@ -212,6 +212,8 @@ extern char * bootmap; //bootmap for loading a map on startup
|
|||
extern char * tutorialmap; // map to load for tutorial
|
||||
extern boolean tutorialmode; // are we in a tutorial right now?
|
||||
|
||||
extern char * podiummap; // map to load for podium
|
||||
|
||||
extern boolean looptitle;
|
||||
|
||||
// CTF colors.
|
||||
|
|
|
|||
|
|
@ -44,13 +44,14 @@
|
|||
|
||||
// SRB2Kart
|
||||
#include "k_menu.h"
|
||||
#include "k_grandprix.h"
|
||||
|
||||
// Stage of animation:
|
||||
// 0 = text, 1 = art screen
|
||||
INT32 finalecount;
|
||||
INT32 titlescrollxspeed = 16;
|
||||
INT32 titlescrollyspeed = 0;
|
||||
UINT8 titlemapinaction = TITLEMAP_OFF;
|
||||
boolean titlemapinaction = false;
|
||||
|
||||
static INT32 timetonext; // Delay between screen changes
|
||||
|
||||
|
|
@ -62,7 +63,7 @@ static tic_t stoptimer;
|
|||
static boolean keypressed = false;
|
||||
|
||||
static INT32 menuanimtimer; // Title screen: background animation timing
|
||||
mobj_t *titlemapcameraref = NULL;
|
||||
altview_t titlemapcam = {0};
|
||||
|
||||
// menu presentation state
|
||||
char curbgname[9];
|
||||
|
|
@ -1835,14 +1836,14 @@ void F_StartTitleScreen(void)
|
|||
mapthing_t *startpos;
|
||||
|
||||
gamestate_t prevwipegamestate = wipegamestate;
|
||||
titlemapinaction = TITLEMAP_LOADING;
|
||||
titlemapcameraref = NULL;
|
||||
titlemapinaction = true;
|
||||
P_SetTarget(&titlemapcam.mobj, NULL);
|
||||
gamemap = titleMapNum+1;
|
||||
|
||||
maptol = mapheaderinfo[titleMapNum]->typeoflevel;
|
||||
globalweather = mapheaderinfo[titleMapNum]->weather;
|
||||
|
||||
G_DoLoadLevel(true);
|
||||
G_DoLoadLevelEx(true, GS_TITLESCREEN);
|
||||
if (!titlemap)
|
||||
return;
|
||||
|
||||
|
|
@ -1878,13 +1879,12 @@ void F_StartTitleScreen(void)
|
|||
}
|
||||
else
|
||||
{
|
||||
titlemapinaction = TITLEMAP_OFF;
|
||||
G_SetGamestate(GS_TITLESCREEN);
|
||||
titlemapinaction = false;
|
||||
gamemap = 1; // g_game.c
|
||||
CON_ClearHUD();
|
||||
}
|
||||
|
||||
G_SetGamestate(GS_TITLESCREEN);
|
||||
|
||||
// IWAD dependent stuff.
|
||||
|
||||
animtimer = skullAnimCounter = 0;
|
||||
|
|
@ -2139,7 +2139,7 @@ void F_TitleScreenTicker(boolean run)
|
|||
mobj_t *cameraref = NULL;
|
||||
|
||||
// If there's a Line 422 Switch Cut-Away view, don't force us.
|
||||
if (!titlemapcameraref || titlemapcameraref->type != MT_ALTVIEWMAN)
|
||||
if (titlemapcam.mobj == NULL || titlemapcam.mobj->type != MT_ALTVIEWMAN)
|
||||
{
|
||||
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
|
||||
{
|
||||
|
|
@ -2154,20 +2154,27 @@ void F_TitleScreenTicker(boolean run)
|
|||
if (mo2->type != MT_ALTVIEWMAN)
|
||||
continue;
|
||||
|
||||
cameraref = titlemapcameraref = mo2;
|
||||
cameraref = mo2;
|
||||
break;
|
||||
}
|
||||
|
||||
if (cameraref != NULL)
|
||||
{
|
||||
P_SetTarget(&titlemapcam.mobj, cameraref);
|
||||
}
|
||||
}
|
||||
else
|
||||
cameraref = titlemapcameraref;
|
||||
{
|
||||
cameraref = titlemapcam.mobj;
|
||||
}
|
||||
|
||||
if (cameraref)
|
||||
if (cameraref != NULL)
|
||||
{
|
||||
camera[0].x = cameraref->x;
|
||||
camera[0].y = cameraref->y;
|
||||
camera[0].z = cameraref->z;
|
||||
camera[0].angle = cameraref->angle;
|
||||
camera[0].aiming = cameraref->cusval;
|
||||
camera[0].aiming = cameraref->pitch;
|
||||
camera[0].subsector = cameraref->subsector;
|
||||
}
|
||||
else
|
||||
|
|
|
|||
|
|
@ -104,17 +104,10 @@ extern INT16 ttloop;
|
|||
extern UINT16 tttics;
|
||||
extern boolean ttavailable[6];
|
||||
|
||||
|
||||
typedef enum
|
||||
{
|
||||
TITLEMAP_OFF = 0,
|
||||
TITLEMAP_LOADING,
|
||||
TITLEMAP_RUNNING
|
||||
} titlemap_enum;
|
||||
|
||||
// Current menu parameters
|
||||
|
||||
extern mobj_t *titlemapcameraref;
|
||||
extern altview_t titlemapcam;
|
||||
|
||||
extern char curbgname[9];
|
||||
extern SINT8 curfadevalue;
|
||||
extern INT32 curbgcolor;
|
||||
|
|
@ -184,6 +177,7 @@ enum
|
|||
wipe_credits_toblack,
|
||||
wipe_evaluation_toblack,
|
||||
wipe_gameend_toblack,
|
||||
wipe_ceremony_toblack,
|
||||
wipe_intro_toblack,
|
||||
wipe_ending_toblack,
|
||||
wipe_cutscene_toblack,
|
||||
|
|
@ -202,6 +196,7 @@ enum
|
|||
wipe_credits_final,
|
||||
wipe_evaluation_final,
|
||||
wipe_gameend_final,
|
||||
wipe_ceremony_final,
|
||||
wipe_intro_final,
|
||||
wipe_ending_final,
|
||||
wipe_cutscene_final,
|
||||
|
|
|
|||
130
src/f_wipe.c
130
src/f_wipe.c
|
|
@ -64,6 +64,7 @@ UINT8 wipedefs[NUMWIPEDEFS] = {
|
|||
99, // wipe_credits_toblack
|
||||
0, // wipe_evaluation_toblack
|
||||
0, // wipe_gameend_toblack
|
||||
0, // wipe_ceremony_toblack
|
||||
UINT8_MAX, // wipe_intro_toblack (hardcoded)
|
||||
99, // wipe_ending_toblack (hardcoded)
|
||||
99, // wipe_cutscene_toblack (hardcoded)
|
||||
|
|
@ -80,6 +81,7 @@ UINT8 wipedefs[NUMWIPEDEFS] = {
|
|||
99, // wipe_credits_final
|
||||
0, // wipe_evaluation_final
|
||||
0, // wipe_gameend_final
|
||||
0, // wipe_ceremony_final
|
||||
99, // wipe_intro_final (hardcoded)
|
||||
99, // wipe_ending_final (hardcoded)
|
||||
99 // wipe_cutscene_final (hardcoded)
|
||||
|
|
@ -88,15 +90,16 @@ UINT8 wipedefs[NUMWIPEDEFS] = {
|
|||
static boolean g_wipedef_toblack[NUMWIPEDEFS] = {
|
||||
true, // wipe_credits_intermediate (0)
|
||||
|
||||
true, // wipe_level_toblack
|
||||
true, // wipe_intermission_toblack
|
||||
true, // wipe_voting_toblack,
|
||||
true, // wipe_continuing_toblack
|
||||
true, // wipe_titlescreen_toblack
|
||||
true, // wipe_menu_toblack
|
||||
true, // wipe_level_toblack
|
||||
true, // wipe_intermission_toblack
|
||||
true, // wipe_voting_toblack,
|
||||
true, // wipe_continuing_toblack
|
||||
true, // wipe_titlescreen_toblack
|
||||
true, // wipe_menu_toblack
|
||||
true, // wipe_credits_toblack
|
||||
true, // wipe_evaluation_toblack
|
||||
true, // wipe_gameend_toblack
|
||||
true, // wipe_evaluation_toblack
|
||||
true, // wipe_gameend_toblack
|
||||
true, // wipe_ceremony_toblack
|
||||
true, // wipe_intro_toblack (hardcoded)
|
||||
true, // wipe_ending_toblack (hardcoded)
|
||||
true, // wipe_cutscene_toblack (hardcoded)
|
||||
|
|
@ -105,14 +108,15 @@ static boolean g_wipedef_toblack[NUMWIPEDEFS] = {
|
|||
false, // wipe_encore_towhite
|
||||
|
||||
true, // wipe_level_final
|
||||
true, // wipe_intermission_final
|
||||
true, // wipe_voting_final
|
||||
true, // wipe_continuing_final
|
||||
true, // wipe_titlescreen_final
|
||||
true, // wipe_menu_final
|
||||
true, // wipe_intermission_final
|
||||
true, // wipe_voting_final
|
||||
true, // wipe_continuing_final
|
||||
true, // wipe_titlescreen_final
|
||||
true, // wipe_menu_final
|
||||
true, // wipe_credits_final
|
||||
true, // wipe_evaluation_final
|
||||
true, // wipe_gameend_final
|
||||
true, // wipe_evaluation_final
|
||||
true, // wipe_gameend_final
|
||||
true, // wipe_ceremony_final
|
||||
true, // wipe_intro_final (hardcoded)
|
||||
true, // wipe_ending_final (hardcoded)
|
||||
true // wipe_cutscene_final (hardcoded)
|
||||
|
|
@ -121,15 +125,16 @@ static boolean g_wipedef_toblack[NUMWIPEDEFS] = {
|
|||
static boolean g_wipedef_toinvert[NUMWIPEDEFS] = {
|
||||
false, // wipe_credits_intermediate (0)
|
||||
|
||||
false, // wipe_level_toblack
|
||||
false, // wipe_intermission_toblack
|
||||
false, // wipe_voting_toblack,
|
||||
false, // wipe_continuing_toblack
|
||||
false, // wipe_titlescreen_toblack
|
||||
false, // wipe_menu_toblack
|
||||
false, // wipe_level_toblack
|
||||
false, // wipe_intermission_toblack
|
||||
false, // wipe_voting_toblack,
|
||||
false, // wipe_continuing_toblack
|
||||
false, // wipe_titlescreen_toblack
|
||||
false, // wipe_menu_toblack
|
||||
false, // wipe_credits_toblack
|
||||
false, // wipe_evaluation_toblack
|
||||
false, // wipe_gameend_toblack
|
||||
false, // wipe_evaluation_toblack
|
||||
false, // wipe_gameend_toblack
|
||||
false, // wipe_ceremony_toblack
|
||||
false, // wipe_intro_toblack (hardcoded)
|
||||
false, // wipe_ending_toblack (hardcoded)
|
||||
false, // wipe_cutscene_toblack (hardcoded)
|
||||
|
|
@ -138,14 +143,15 @@ static boolean g_wipedef_toinvert[NUMWIPEDEFS] = {
|
|||
false, // wipe_encore_towhite
|
||||
|
||||
false, // wipe_level_final
|
||||
false, // wipe_intermission_final
|
||||
false, // wipe_voting_final
|
||||
false, // wipe_continuing_final
|
||||
false, // wipe_titlescreen_final
|
||||
false, // wipe_menu_final
|
||||
false, // wipe_intermission_final
|
||||
false, // wipe_voting_final
|
||||
false, // wipe_continuing_final
|
||||
false, // wipe_titlescreen_final
|
||||
false, // wipe_menu_final
|
||||
false, // wipe_credits_final
|
||||
false, // wipe_evaluation_final
|
||||
false, // wipe_gameend_final
|
||||
false, // wipe_evaluation_final
|
||||
false, // wipe_gameend_final
|
||||
false, // wipe_ceremony_final
|
||||
false, // wipe_intro_final (hardcoded)
|
||||
false, // wipe_ending_final (hardcoded)
|
||||
false // wipe_cutscene_final (hardcoded)
|
||||
|
|
@ -154,15 +160,16 @@ static boolean g_wipedef_toinvert[NUMWIPEDEFS] = {
|
|||
static boolean g_wipedef_towhite[NUMWIPEDEFS] = {
|
||||
false, // wipe_credits_intermediate (0)
|
||||
|
||||
false, // wipe_level_toblack
|
||||
false, // wipe_intermission_toblack
|
||||
false, // wipe_voting_toblack,
|
||||
false, // wipe_continuing_toblack
|
||||
false, // wipe_titlescreen_toblack
|
||||
false, // wipe_menu_toblack
|
||||
false, // wipe_level_toblack
|
||||
false, // wipe_intermission_toblack
|
||||
false, // wipe_voting_toblack,
|
||||
false, // wipe_continuing_toblack
|
||||
false, // wipe_titlescreen_toblack
|
||||
false, // wipe_menu_toblack
|
||||
false, // wipe_credits_toblack
|
||||
false, // wipe_evaluation_toblack
|
||||
false, // wipe_gameend_toblack
|
||||
false, // wipe_evaluation_toblack
|
||||
false, // wipe_gameend_toblack
|
||||
false, // wipe_ceremony_toblack
|
||||
false, // wipe_intro_toblack (hardcoded)
|
||||
false, // wipe_ending_toblack (hardcoded)
|
||||
false, // wipe_cutscene_toblack (hardcoded)
|
||||
|
|
@ -171,14 +178,15 @@ static boolean g_wipedef_towhite[NUMWIPEDEFS] = {
|
|||
true, // wipe_encore_towhite
|
||||
|
||||
false, // wipe_level_final
|
||||
false, // wipe_intermission_final
|
||||
false, // wipe_voting_final
|
||||
false, // wipe_continuing_final
|
||||
false, // wipe_titlescreen_final
|
||||
false, // wipe_menu_final
|
||||
false, // wipe_intermission_final
|
||||
false, // wipe_voting_final
|
||||
false, // wipe_continuing_final
|
||||
false, // wipe_titlescreen_final
|
||||
false, // wipe_menu_final
|
||||
false, // wipe_credits_final
|
||||
false, // wipe_evaluation_final
|
||||
false, // wipe_gameend_final
|
||||
false, // wipe_evaluation_final
|
||||
false, // wipe_gameend_final
|
||||
false, // wipe_ceremony_final
|
||||
false, // wipe_intro_final (hardcoded)
|
||||
false, // wipe_ending_final (hardcoded)
|
||||
false // wipe_cutscene_final (hardcoded)
|
||||
|
|
@ -187,15 +195,16 @@ static boolean g_wipedef_towhite[NUMWIPEDEFS] = {
|
|||
static boolean g_wipedef_crossfade[NUMWIPEDEFS] = {
|
||||
false, // wipe_credits_intermediate (0)
|
||||
|
||||
false, // wipe_level_toblack
|
||||
false, // wipe_intermission_toblack
|
||||
false, // wipe_voting_toblack,
|
||||
false, // wipe_continuing_toblack
|
||||
false, // wipe_titlescreen_toblack
|
||||
false, // wipe_menu_toblack
|
||||
false, // wipe_level_toblack
|
||||
false, // wipe_intermission_toblack
|
||||
false, // wipe_voting_toblack,
|
||||
false, // wipe_continuing_toblack
|
||||
false, // wipe_titlescreen_toblack
|
||||
false, // wipe_menu_toblack
|
||||
false, // wipe_credits_toblack
|
||||
false, // wipe_evaluation_toblack
|
||||
false, // wipe_gameend_toblack
|
||||
false, // wipe_evaluation_toblack
|
||||
false, // wipe_gameend_toblack
|
||||
false, // wipe_ceremony_toblack
|
||||
false, // wipe_intro_toblack (hardcoded)
|
||||
false, // wipe_ending_toblack (hardcoded)
|
||||
false, // wipe_cutscene_toblack (hardcoded)
|
||||
|
|
@ -204,14 +213,15 @@ static boolean g_wipedef_crossfade[NUMWIPEDEFS] = {
|
|||
false, // wipe_encore_towhite
|
||||
|
||||
true, // wipe_level_final
|
||||
true, // wipe_intermission_final
|
||||
true, // wipe_voting_final
|
||||
true, // wipe_continuing_final
|
||||
true, // wipe_titlescreen_final
|
||||
true, // wipe_menu_final
|
||||
true, // wipe_intermission_final
|
||||
true, // wipe_voting_final
|
||||
true, // wipe_continuing_final
|
||||
true, // wipe_titlescreen_final
|
||||
true, // wipe_menu_final
|
||||
true, // wipe_credits_final
|
||||
true, // wipe_evaluation_final
|
||||
true, // wipe_gameend_final
|
||||
true, // wipe_evaluation_final
|
||||
true, // wipe_gameend_final
|
||||
true, // wipe_ceremony_final
|
||||
true, // wipe_intro_final (hardcoded)
|
||||
true, // wipe_ending_final (hardcoded)
|
||||
true // wipe_cutscene_final (hardcoded)
|
||||
|
|
|
|||
211
src/g_game.c
211
src/g_game.c
|
|
@ -62,6 +62,8 @@
|
|||
#include "k_bot.h"
|
||||
#include "doomstat.h"
|
||||
#include "k_director.h"
|
||||
#include "k_podium.h"
|
||||
#include "k_rank.h"
|
||||
|
||||
#ifdef HAVE_DISCORDRPC
|
||||
#include "discord.h"
|
||||
|
|
@ -164,6 +166,8 @@ char * bootmap = NULL; //bootmap for loading a map on startup
|
|||
char * tutorialmap = NULL; // map to load for tutorial
|
||||
boolean tutorialmode = false; // are we in a tutorial right now?
|
||||
|
||||
char * podiummap = NULL; // map to load for podium
|
||||
|
||||
boolean looptitle = true;
|
||||
|
||||
UINT16 skincolor_redteam = SKINCOLOR_RED;
|
||||
|
|
@ -1449,9 +1453,9 @@ static void weaponPrefChange4(void)
|
|||
}
|
||||
|
||||
//
|
||||
// G_DoLoadLevel
|
||||
// G_DoLoadLevelEx
|
||||
//
|
||||
void G_DoLoadLevel(boolean resetplayer)
|
||||
void G_DoLoadLevelEx(boolean resetplayer, gamestate_t newstate)
|
||||
{
|
||||
boolean doAutomate = false;
|
||||
INT32 i;
|
||||
|
|
@ -1461,7 +1465,7 @@ void G_DoLoadLevel(boolean resetplayer)
|
|||
|
||||
levelstarttic = gametic; // for time calculation
|
||||
|
||||
if (wipegamestate == GS_LEVEL)
|
||||
if (wipegamestate == newstate)
|
||||
wipegamestate = -1; // force a wipe
|
||||
|
||||
if (cv_currprofile.value == -1 && !demo.playback)
|
||||
|
|
@ -1478,31 +1482,33 @@ void G_DoLoadLevel(boolean resetplayer)
|
|||
Y_EndVote();
|
||||
|
||||
// cleanup
|
||||
if (titlemapinaction == TITLEMAP_LOADING)
|
||||
// Is this actually necessary? Doesn't F_StartTitleScreen already do a significantly more comprehensive check?
|
||||
if (newstate == GS_TITLESCREEN)
|
||||
{
|
||||
//if (W_CheckNumForName(G_BuildMapName(gamemap)) == LUMPERROR)
|
||||
if (gamemap < 1 || gamemap > nummapheaders)
|
||||
{
|
||||
G_SetGamestate(GS_TITLESCREEN);
|
||||
titlemapinaction = false;
|
||||
|
||||
Z_Free(titlemap);
|
||||
titlemap = NULL; // let's not infinite recursion ok
|
||||
|
||||
Command_ExitGame_f();
|
||||
return;
|
||||
}
|
||||
|
||||
titlemapinaction = TITLEMAP_RUNNING;
|
||||
}
|
||||
else
|
||||
titlemapinaction = TITLEMAP_OFF;
|
||||
|
||||
// Doing this matches HOSTMOD behavior.
|
||||
// Is that desired? IDK
|
||||
doAutomate = (gamestate != GS_LEVEL);
|
||||
doAutomate = (gamestate != GS_LEVEL && newstate == GS_LEVEL);
|
||||
|
||||
G_SetGamestate(GS_LEVEL);
|
||||
G_SetGamestate(newstate);
|
||||
if (wipegamestate == GS_MENU)
|
||||
M_ClearMenus(true);
|
||||
I_UpdateMouseGrab();
|
||||
|
||||
K_ResetCeremony();
|
||||
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
if (resetplayer || (playeringame[i] && players[i].playerstate == PST_DEAD))
|
||||
|
|
@ -1543,6 +1549,11 @@ void G_DoLoadLevel(boolean resetplayer)
|
|||
}
|
||||
}
|
||||
|
||||
void G_DoLoadLevel(boolean resetplayer)
|
||||
{
|
||||
G_DoLoadLevelEx(resetplayer, GS_LEVEL);
|
||||
}
|
||||
|
||||
//
|
||||
// Start the title card.
|
||||
//
|
||||
|
|
@ -1573,7 +1584,7 @@ void G_StartTitleCard(void)
|
|||
}
|
||||
|
||||
// start the title card
|
||||
WipeStageTitle = (!titlemapinaction);
|
||||
WipeStageTitle = (gamestate == GS_LEVEL);
|
||||
}
|
||||
|
||||
//
|
||||
|
|
@ -1717,6 +1728,21 @@ boolean G_Responder(event_t *ev)
|
|||
return true;
|
||||
}
|
||||
}
|
||||
else if (gamestate == GS_CEREMONY)
|
||||
{
|
||||
if (HU_Responder(ev))
|
||||
{
|
||||
hu_keystrokes = true;
|
||||
return true; // chat ate the event
|
||||
}
|
||||
|
||||
if (K_CeremonyResponder(ev))
|
||||
{
|
||||
nextmap = NEXTMAP_TITLE;
|
||||
G_EndGame();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (gamestate == GS_CONTINUING)
|
||||
{
|
||||
return true;
|
||||
|
|
@ -1727,11 +1753,13 @@ boolean G_Responder(event_t *ev)
|
|||
return true;
|
||||
}
|
||||
else if (gamestate == GS_INTERMISSION || gamestate == GS_VOTING || gamestate == GS_EVALUATION)
|
||||
{
|
||||
if (HU_Responder(ev))
|
||||
{
|
||||
hu_keystrokes = true;
|
||||
return true; // chat ate the event
|
||||
}
|
||||
}
|
||||
|
||||
if (gamestate == GS_LEVEL && ev->type == ev_keydown && multiplayer && demo.playback && !demo.freecam)
|
||||
{
|
||||
|
|
@ -2099,7 +2127,7 @@ void G_Ticker(boolean run)
|
|||
marathontime++;
|
||||
|
||||
P_MapStart();
|
||||
// do player reborns if needed
|
||||
|
||||
if (gamestate == GS_LEVEL)
|
||||
{
|
||||
// Or, alternatively, retry.
|
||||
|
|
@ -2117,11 +2145,28 @@ void G_Ticker(boolean run)
|
|||
|
||||
D_MapChange(gamemap, gametype, (cv_kartencore.value == 1), false, 1, false, false);
|
||||
}
|
||||
}
|
||||
|
||||
// do player reborns if needed
|
||||
if (G_GamestateUsesLevel() == true)
|
||||
{
|
||||
boolean changed = false;
|
||||
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
if (playeringame[i] && players[i].playerstate == PST_REBORN)
|
||||
{
|
||||
G_DoReborn(i);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (changed == true)
|
||||
{
|
||||
K_UpdateAllPlayerPositions();
|
||||
}
|
||||
}
|
||||
|
||||
P_MapEnd();
|
||||
|
||||
// do things to change the game state
|
||||
|
|
@ -2175,7 +2220,6 @@ void G_Ticker(boolean run)
|
|||
F_TextPromptTicker();
|
||||
AM_Ticker();
|
||||
HU_Ticker();
|
||||
|
||||
break;
|
||||
|
||||
case GS_INTERMISSION:
|
||||
|
|
@ -2237,6 +2281,11 @@ void G_Ticker(boolean run)
|
|||
F_TitleScreenTicker(run);
|
||||
break;
|
||||
|
||||
case GS_CEREMONY:
|
||||
P_Ticker(run);
|
||||
K_CeremonyTicker(run);
|
||||
break;
|
||||
|
||||
case GS_WAITINGPLAYERS:
|
||||
if (netgame)
|
||||
F_WaitingPlayersTicker();
|
||||
|
|
@ -2349,6 +2398,7 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
|
|||
INT16 totalring;
|
||||
UINT8 laps;
|
||||
UINT8 latestlap;
|
||||
UINT32 lapPoints;
|
||||
UINT16 skincolor;
|
||||
INT32 skin;
|
||||
UINT8 availabilities[MAXAVAILABILITY];
|
||||
|
|
@ -2469,6 +2519,7 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
|
|||
nocontrol = 0;
|
||||
laps = 0;
|
||||
latestlap = 0;
|
||||
lapPoints = 0;
|
||||
roundscore = 0;
|
||||
exiting = 0;
|
||||
khudfinish = 0;
|
||||
|
|
@ -2504,6 +2555,7 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
|
|||
|
||||
laps = players[player].laps;
|
||||
latestlap = players[player].latestlap;
|
||||
lapPoints = players[player].lapPoints;
|
||||
|
||||
roundscore = players[player].roundscore;
|
||||
|
||||
|
|
@ -2528,7 +2580,7 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
|
|||
{
|
||||
follower = players[player].follower;
|
||||
P_SetTarget(&players[player].follower, NULL);
|
||||
P_SetTarget(&players[player].awayviewmobj, NULL);
|
||||
P_SetTarget(&players[player].awayview.mobj, NULL);
|
||||
P_SetTarget(&players[player].stumbleIndicator, NULL);
|
||||
P_SetTarget(&players[player].followmobj, NULL);
|
||||
|
||||
|
|
@ -2576,6 +2628,7 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
|
|||
|
||||
p->laps = laps;
|
||||
p->latestlap = latestlap;
|
||||
p->lapPoints = lapPoints;
|
||||
p->totalring = totalring;
|
||||
|
||||
p->bot = bot;
|
||||
|
|
@ -2732,7 +2785,7 @@ void G_MovePlayerToSpawnOrStarpost(INT32 playernum)
|
|||
#else
|
||||
// Player's first spawn should be at the "map start".
|
||||
// I.e. level load or join mid game.
|
||||
if (leveltime > starttime && players[playernum].jointime > 0)
|
||||
if (leveltime > starttime && players[playernum].jointime > 1 && K_PodiumSequence() == false)
|
||||
P_MovePlayerToStarpost(playernum);
|
||||
else
|
||||
P_MovePlayerToSpawn(playernum, G_FindMapStart(playernum));
|
||||
|
|
@ -2828,7 +2881,9 @@ mapthing_t *G_FindRaceStart(INT32 playernum)
|
|||
|
||||
// SRB2Kart: figure out player spawn pos from points
|
||||
if (!playeringame[playernum] || players[playernum].spectator)
|
||||
{
|
||||
return playerstarts[0]; // go to first spot if you're a spectator
|
||||
}
|
||||
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
|
|
@ -2911,6 +2966,42 @@ mapthing_t *G_FindRaceStart(INT32 playernum)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
mapthing_t *G_FindPodiumStart(INT32 playernum)
|
||||
{
|
||||
const boolean doprints = P_IsLocalPlayer(&players[playernum]);
|
||||
|
||||
if (numcoopstarts)
|
||||
{
|
||||
UINT8 pos = K_GetPodiumPosition(&players[playernum]) - 1;
|
||||
UINT8 i;
|
||||
|
||||
if (G_CheckSpot(playernum, playerstarts[pos % numcoopstarts]))
|
||||
{
|
||||
return playerstarts[pos % numcoopstarts];
|
||||
}
|
||||
|
||||
// Your spot isn't available? Find whatever you can get first.
|
||||
for (i = 0; i < numcoopstarts; i++)
|
||||
{
|
||||
if (G_CheckSpot(playernum, playerstarts[(pos + i) % numcoopstarts]))
|
||||
{
|
||||
return playerstarts[(pos + i) % numcoopstarts];
|
||||
}
|
||||
}
|
||||
|
||||
if (doprints)
|
||||
{
|
||||
CONS_Alert(CONS_WARNING, M_GetText("Could not spawn at any Podium starts!\n"));
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (doprints)
|
||||
CONS_Alert(CONS_WARNING, M_GetText("No Podium starts in this map!\n"));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Find a Co-op start, or fallback into other types of starts.
|
||||
static inline mapthing_t *G_FindRaceStartOrFallback(INT32 playernum)
|
||||
{
|
||||
|
|
@ -2947,9 +3038,14 @@ mapthing_t *G_FindMapStart(INT32 playernum)
|
|||
if (!playeringame[playernum])
|
||||
return NULL;
|
||||
|
||||
// -- Podium --
|
||||
// Single special behavior
|
||||
if (K_PodiumSequence() == true)
|
||||
spawnpoint = G_FindPodiumStart(playernum);
|
||||
|
||||
// -- Time Attack --
|
||||
// Order: Race->DM->CTF
|
||||
if (K_TimeAttackRules() == true)
|
||||
else if (K_TimeAttackRules() == true)
|
||||
spawnpoint = G_FindRaceStartOrFallback(playernum);
|
||||
|
||||
// -- CTF --
|
||||
|
|
@ -3096,13 +3192,20 @@ void G_ExitLevel(void)
|
|||
if (i == MAXPLAYERS)
|
||||
{
|
||||
// GAME OVER, try again from the start!
|
||||
|
||||
if (netgame)
|
||||
if (grandprixinfo.gp == true
|
||||
&& grandprixinfo.eventmode == GPEVENT_SPECIAL)
|
||||
{
|
||||
; // restart cup here if we do online GP
|
||||
// We were in a Special Stage.
|
||||
// We can still progress to the podium when we game over here.
|
||||
doretry = false;
|
||||
}
|
||||
else if (netgame)
|
||||
{
|
||||
; // Restart cup here whenever we do Online GP
|
||||
}
|
||||
else
|
||||
{
|
||||
// Back to the menu with you.
|
||||
D_QuitNetGame();
|
||||
CL_Reset();
|
||||
D_ClearState();
|
||||
|
|
@ -3111,11 +3214,14 @@ void G_ExitLevel(void)
|
|||
}
|
||||
else
|
||||
{
|
||||
// Go redo this course.
|
||||
// We have lives, just redo this one course.
|
||||
G_SetRetryFlag();
|
||||
}
|
||||
|
||||
return;
|
||||
if (doretry == true)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
gameaction = ga_completed;
|
||||
|
|
@ -3806,20 +3912,9 @@ static void G_GetNextMap(void)
|
|||
// Special stage
|
||||
else if (grandprixinfo.roundnum >= grandprixinfo.cup->numlevels)
|
||||
{
|
||||
INT16 totaltotalring = 0;
|
||||
gp_rank_e grade = K_CalculateGPGrade(&grandprixinfo.rank);
|
||||
|
||||
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)
|
||||
if (grade >= GRADE_A) // On A rank pace? Then you get a chance for S rank!
|
||||
{
|
||||
const INT32 cupLevelNum = grandprixinfo.cup->cachedlevels[CUPCACHE_SPECIAL];
|
||||
if (cupLevelNum < nummapheaders && mapheaderinfo[cupLevelNum])
|
||||
|
|
@ -4047,6 +4142,9 @@ static void G_DoCompleted(void)
|
|||
G_SetGamestate(GS_NULL);
|
||||
wipegamestate = GS_NULL;
|
||||
|
||||
grandprixinfo.rank.capsules += numtargets;
|
||||
grandprixinfo.rank.position = MAXPLAYERS;
|
||||
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
if (playeringame[i])
|
||||
|
|
@ -4072,6 +4170,11 @@ static void G_DoCompleted(void)
|
|||
}
|
||||
|
||||
G_PlayerFinishLevel(i); // take away cards and stuff
|
||||
|
||||
if (players[i].bot == false)
|
||||
{
|
||||
grandprixinfo.rank.position = min(grandprixinfo.rank.position, K_GetPodiumPosition(&players[i]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -4281,8 +4384,10 @@ void G_EndGame(void)
|
|||
{
|
||||
if (nextmap == NEXTMAP_CEREMONY) // end game with ceremony
|
||||
{
|
||||
/*F_StartEnding(); -- temporary
|
||||
return;*/
|
||||
if (K_StartCeremony() == true)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (nextmap == NEXTMAP_CREDITS) // end game with credits
|
||||
{
|
||||
|
|
@ -5061,6 +5166,16 @@ void G_InitNew(UINT8 pencoremode, INT32 map, boolean resetplayer, boolean skippr
|
|||
return;
|
||||
}
|
||||
|
||||
if (map == G_MapNumber(podiummap)+1)
|
||||
{
|
||||
// Didn't want to do this, but it needs to be here
|
||||
// for it to work on startup.
|
||||
if (K_StartCeremony() == true)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
gamemap = map;
|
||||
|
||||
maptol = mapheaderinfo[gamemap-1]->typeoflevel;
|
||||
|
|
@ -5355,6 +5470,22 @@ void G_SetGamestate(gamestate_t newstate)
|
|||
#endif
|
||||
}
|
||||
|
||||
boolean G_GamestateUsesLevel(void)
|
||||
{
|
||||
switch (gamestate)
|
||||
{
|
||||
case GS_TITLESCREEN:
|
||||
return titlemapinaction;
|
||||
|
||||
case GS_LEVEL:
|
||||
case GS_CEREMONY:
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* These functions handle the exitgame flag. Before, when the user
|
||||
chose to end a game, it happened immediately, which could cause
|
||||
crashes if the game was in the middle of something. Now, a flag
|
||||
|
|
@ -5381,6 +5512,11 @@ boolean G_GetExitGameFlag(void)
|
|||
// Same deal with retrying.
|
||||
void G_SetRetryFlag(void)
|
||||
{
|
||||
if (retrying == false)
|
||||
{
|
||||
grandprixinfo.rank.continuesUsed++;
|
||||
}
|
||||
|
||||
retrying = true;
|
||||
}
|
||||
|
||||
|
|
@ -5438,4 +5574,3 @@ INT32 G_TicsToMilliseconds(tic_t tics)
|
|||
{
|
||||
return (INT32)((tics%TICRATE) * (1000.00f/TICRATE));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -156,6 +156,7 @@ INT32 G_FindMapByNameOrCode(const char *query, char **foundmapnamep);
|
|||
mapthing_t *G_FindTeamStart(INT32 playernum);
|
||||
mapthing_t *G_FindBattleStart(INT32 playernum);
|
||||
mapthing_t *G_FindRaceStart(INT32 playernum);
|
||||
mapthing_t *G_FindPodiumStart(INT32 playernum);
|
||||
mapthing_t *G_FindMapStart(INT32 playernum);
|
||||
void G_MovePlayerToSpawnOrStarpost(INT32 playernum);
|
||||
void G_SpawnPlayer(INT32 playernum);
|
||||
|
|
@ -164,6 +165,7 @@ void G_SpawnPlayer(INT32 playernum);
|
|||
// A normal game starts at map 1, but a warp test can start elsewhere
|
||||
void G_DeferedInitNew(boolean pencoremode, INT32 map, INT32 pickedchar,
|
||||
UINT8 ssplayers, boolean FLS);
|
||||
void G_DoLoadLevelEx(boolean resetplayer, gamestate_t newstate);
|
||||
void G_DoLoadLevel(boolean resetplayer);
|
||||
|
||||
void G_StartTitleCard(void);
|
||||
|
|
@ -250,8 +252,6 @@ void G_LoadGameSettings(void);
|
|||
void G_SetGameModified(boolean silent, boolean major);
|
||||
void G_SetUsedCheats(void);
|
||||
|
||||
void G_SetGamestate(gamestate_t newstate);
|
||||
|
||||
// Gamedata record shit
|
||||
void G_AllocMainRecordData(INT16 i);
|
||||
void G_ClearRecords(void);
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ typedef enum
|
|||
GS_CREDITS, // credit sequence
|
||||
GS_EVALUATION, // Evaluation at the end of a game.
|
||||
GS_GAMEEND, // game end sequence - "did you get all those chaos emeralds?"
|
||||
GS_CEREMONY, // RR: Podium sequence
|
||||
|
||||
// Hardcoded fades or other fading methods
|
||||
GS_INTRO, // introduction
|
||||
|
|
@ -58,10 +59,13 @@ typedef enum
|
|||
} gameaction_t;
|
||||
|
||||
extern gamestate_t gamestate;
|
||||
extern UINT8 titlemapinaction;
|
||||
extern boolean titlemapinaction;
|
||||
extern UINT8 ultimatemode; // was sk_insane
|
||||
extern gameaction_t gameaction;
|
||||
|
||||
void G_SetGamestate(gamestate_t newstate);
|
||||
boolean G_GamestateUsesLevel(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -21281,7 +21281,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
|
|||
10, // mass
|
||||
0, // damage
|
||||
sfx_None, // activesound
|
||||
MF_NOTHINK|MF_NOBLOCKMAP|MF_NOGRAVITY, // flags
|
||||
MF_NOBLOCKMAP|MF_NOGRAVITY, // flags
|
||||
S_NULL // raisestate
|
||||
},
|
||||
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@
|
|||
#include "k_boss.h" // bossinfo.valid
|
||||
#include "p_spec.h"
|
||||
#include "k_objects.h"
|
||||
#include "k_rank.h"
|
||||
|
||||
// Battle overtime info
|
||||
struct battleovertime battleovertime;
|
||||
|
|
|
|||
75
src/k_bot.c
75
src/k_bot.c
|
|
@ -28,7 +28,7 @@
|
|||
#include "r_things.h" // numskins
|
||||
#include "k_race.h" // finishBeamLine
|
||||
#include "m_perfstats.h"
|
||||
|
||||
#include "k_podium.h"
|
||||
|
||||
/*--------------------------------------------------
|
||||
boolean K_AddBot(UINT8 skin, UINT8 difficulty, UINT8 *p)
|
||||
|
|
@ -261,6 +261,9 @@ void K_UpdateMatchRaceBots(void)
|
|||
--------------------------------------------------*/
|
||||
boolean K_PlayerUsesBotMovement(player_t *player)
|
||||
{
|
||||
if (K_PodiumSequence() == true)
|
||||
return true;
|
||||
|
||||
if (player->exiting)
|
||||
return true;
|
||||
|
||||
|
|
@ -1264,6 +1267,63 @@ static INT32 K_HandleBotReverse(player_t *player, ticcmd_t *cmd, botprediction_t
|
|||
return turnamt;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
static void K_BotPodiumTurning(player_t *player, ticcmd_t *cmd)
|
||||
|
||||
Calculates bot turning for the podium cutscene.
|
||||
--------------------------------------------------*/
|
||||
static void K_BotPodiumTurning(player_t *player, ticcmd_t *cmd)
|
||||
{
|
||||
const angle_t destAngle = R_PointToAngle2(
|
||||
player->mo->x, player->mo->y,
|
||||
player->currentwaypoint->mobj->x, player->currentwaypoint->mobj->y
|
||||
);
|
||||
const INT32 delta = AngleDeltaSigned(destAngle, player->mo->angle);
|
||||
const INT16 handling = K_GetKartTurnValue(player, KART_FULLTURN);
|
||||
fixed_t mul = FixedDiv(delta, (angle_t)(handling << TICCMD_REDUCE));
|
||||
|
||||
if (mul > FRACUNIT)
|
||||
{
|
||||
mul = FRACUNIT;
|
||||
}
|
||||
|
||||
if (mul < -FRACUNIT)
|
||||
{
|
||||
mul = -FRACUNIT;
|
||||
}
|
||||
|
||||
cmd->turning = FixedMul(mul, KART_FULLTURN);
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
static void K_BuildBotPodiumTiccmd(player_t *player, ticcmd_t *cmd)
|
||||
|
||||
Calculates all bot movement for the podium cutscene.
|
||||
--------------------------------------------------*/
|
||||
static void K_BuildBotPodiumTiccmd(player_t *player, ticcmd_t *cmd)
|
||||
{
|
||||
if (player->currentwaypoint == NULL)
|
||||
{
|
||||
// We've reached the end of our path.
|
||||
// Simply stop moving.
|
||||
return;
|
||||
}
|
||||
|
||||
if (K_GetWaypointIsSpawnpoint(player->currentwaypoint) == false)
|
||||
{
|
||||
// Hacky flag reuse: slow down before reaching your podium stand.
|
||||
cmd->forwardmove = MAXPLMOVE * 3 / 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
cmd->forwardmove = MAXPLMOVE;
|
||||
}
|
||||
|
||||
cmd->buttons |= BT_ACCELERATE;
|
||||
|
||||
K_BotPodiumTurning(player, cmd);
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
void K_BuildBotTiccmd(player_t *player, ticcmd_t *cmd)
|
||||
|
||||
|
|
@ -1282,7 +1342,9 @@ void K_BuildBotTiccmd(player_t *player, ticcmd_t *cmd)
|
|||
// Remove any existing controls
|
||||
memset(cmd, 0, sizeof(ticcmd_t));
|
||||
|
||||
if (gamestate != GS_LEVEL || !player->mo || player->spectator)
|
||||
if (player->mo == NULL
|
||||
|| player->spectator == true
|
||||
|| G_GamestateUsesLevel() == false)
|
||||
{
|
||||
// Not in the level.
|
||||
return;
|
||||
|
|
@ -1294,6 +1356,12 @@ void K_BuildBotTiccmd(player_t *player, ticcmd_t *cmd)
|
|||
return;
|
||||
}
|
||||
|
||||
if (K_PodiumSequence() == true)
|
||||
{
|
||||
K_BuildBotPodiumTiccmd(player, cmd);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(gametyperules & GTR_BOTS) // No bot behaviors
|
||||
|| K_GetNumWaypoints() == 0 // No waypoints
|
||||
|| leveltime <= introtime // During intro camera
|
||||
|
|
@ -1556,6 +1624,9 @@ void K_UpdateBotGameplayVars(player_t *player)
|
|||
{
|
||||
const line_t *botController;
|
||||
|
||||
player->botvars.controller = UINT16_MAX;
|
||||
player->botvars.rubberband = FRACUNIT;
|
||||
|
||||
if (gamestate != GS_LEVEL || !player->mo)
|
||||
{
|
||||
// Not in the level.
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@
|
|||
#include "g_game.h" // Sink snipe print
|
||||
#include "k_objects.h"
|
||||
#include "k_roulette.h"
|
||||
#include "k_podium.h"
|
||||
|
||||
angle_t K_GetCollideAngle(mobj_t *t1, mobj_t *t2)
|
||||
{
|
||||
|
|
@ -811,6 +812,12 @@ boolean K_PvPTouchDamage(mobj_t *t1, mobj_t *t2)
|
|||
boolean stungT1 = false;
|
||||
boolean stungT2 = false;
|
||||
|
||||
if (K_PodiumSequence() == true)
|
||||
{
|
||||
// Always regular bumps, no ring toss.
|
||||
return false;
|
||||
}
|
||||
|
||||
// Clash instead of damage if both parties have any of these conditions
|
||||
t1Condition = (K_IsBigger(t1, t2) == true)
|
||||
|| (t1->player->invincibilitytimer > 0)
|
||||
|
|
|
|||
|
|
@ -114,6 +114,24 @@ UINT8 K_BotDefaultSkin(void)
|
|||
return (UINT8)defaultbotskin;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
UINT8 K_GetGPPlayerCount(UINT8 humans)
|
||||
|
||||
See header file for description.
|
||||
--------------------------------------------------*/
|
||||
UINT8 K_GetGPPlayerCount(UINT8 humans)
|
||||
{
|
||||
UINT8 playerCount = 8;
|
||||
|
||||
if (humans > 2)
|
||||
{
|
||||
// Add 3 bots per player beyond 2P
|
||||
playerCount += (humans - 2) * 3;
|
||||
}
|
||||
|
||||
return playerCount;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
void K_InitGrandPrixBots(void)
|
||||
|
||||
|
|
@ -198,12 +216,7 @@ void K_InitGrandPrixBots(void)
|
|||
}
|
||||
}
|
||||
|
||||
if (numplayers > 2)
|
||||
{
|
||||
// Add 3 bots per player beyond 2P
|
||||
playercount += (numplayers-2) * 3;
|
||||
}
|
||||
|
||||
playercount = K_GetGPPlayerCount(numplayers);
|
||||
wantedbots = playercount - numplayers;
|
||||
|
||||
// Create rival list
|
||||
|
|
|
|||
|
|
@ -15,14 +15,18 @@
|
|||
|
||||
#include "doomdef.h"
|
||||
#include "doomstat.h"
|
||||
#include "k_rank.h" // gpRank_t
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define GPEVENT_NONE 0
|
||||
#define GPEVENT_BONUS 1
|
||||
#define GPEVENT_SPECIAL 2
|
||||
typedef enum
|
||||
{
|
||||
GPEVENT_NONE = 0,
|
||||
GPEVENT_BONUS,
|
||||
GPEVENT_SPECIAL,
|
||||
} gpEvent_e;
|
||||
|
||||
extern struct grandprixinfo
|
||||
{
|
||||
|
|
@ -34,10 +38,10 @@ 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
|
||||
gpEvent_e eventmode; ///< Special event mode, bots are set to spectate and a special gametype is played
|
||||
gpRank_t rank; ///< Struct containing grading information. (See also: k_rank.h)
|
||||
} grandprixinfo;
|
||||
|
||||
|
||||
/*--------------------------------------------------
|
||||
UINT8 K_BotStartingDifficulty(SINT8 value);
|
||||
|
||||
|
|
@ -81,6 +85,23 @@ INT16 K_CalculateGPRankPoints(UINT8 position, UINT8 numplayers);
|
|||
UINT8 K_BotDefaultSkin(void);
|
||||
|
||||
|
||||
/*--------------------------------------------------
|
||||
UINT8 K_GetGPPlayerCount(UINT8 humans)
|
||||
|
||||
Counts the number of total players,
|
||||
including humans and bots, to put into
|
||||
a GP session.
|
||||
|
||||
Input Arguments:-
|
||||
humans - Number of human players.
|
||||
|
||||
Return:-
|
||||
Number of both human players and CPU.
|
||||
--------------------------------------------------*/
|
||||
|
||||
UINT8 K_GetGPPlayerCount(UINT8 humans);
|
||||
|
||||
|
||||
/*--------------------------------------------------
|
||||
void K_InitGrandPrixBots(void);
|
||||
|
||||
|
|
@ -170,6 +191,7 @@ void K_PlayerLoseLife(player_t *player);
|
|||
|
||||
boolean K_CanChangeRules(boolean allowdemos);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
|
|
|||
59
src/k_hud.c
59
src/k_hud.c
|
|
@ -37,6 +37,8 @@
|
|||
#include "r_fps.h"
|
||||
#include "m_random.h"
|
||||
#include "k_roulette.h"
|
||||
#include "k_bot.h"
|
||||
#include "k_rank.h"
|
||||
|
||||
//{ Patch Definitions
|
||||
static patch_t *kp_nodraw;
|
||||
|
|
@ -3005,7 +3007,7 @@ static void K_drawKartPlayerCheck(void)
|
|||
return;
|
||||
}
|
||||
|
||||
if (stplyr->spectator || stplyr->awayviewtics)
|
||||
if (stplyr->spectator || stplyr->awayview.tics)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
|
@ -3254,7 +3256,7 @@ static void K_drawKartNameTags(void)
|
|||
return;
|
||||
}
|
||||
|
||||
if (stplyr->awayviewtics)
|
||||
if (stplyr->awayview.tics)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
|
@ -4815,6 +4817,58 @@ static void K_DrawWaypointDebugger(void)
|
|||
}
|
||||
}
|
||||
|
||||
static void K_DrawGPRankDebugger(void)
|
||||
{
|
||||
gp_rank_e grade = GRADE_E;
|
||||
char gradeChar = '?';
|
||||
|
||||
if (cv_debugrank.value == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (stplyr != &players[displayplayers[0]]) // only for p1
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (grandprixinfo.gp == false)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
grade = K_CalculateGPGrade(&grandprixinfo.rank);
|
||||
|
||||
V_DrawThinString(0, 0, V_SNAPTOTOP|V_SNAPTOLEFT|V_6WIDTHSPACE|V_ALLOWLOWERCASE,
|
||||
va("POS: %d / %d", grandprixinfo.rank.position, RANK_NEUTRAL_POSITION));
|
||||
V_DrawThinString(0, 10, V_SNAPTOTOP|V_SNAPTOLEFT|V_6WIDTHSPACE|V_ALLOWLOWERCASE,
|
||||
va("PTS: %d / %d", grandprixinfo.rank.winPoints, grandprixinfo.rank.totalPoints));
|
||||
V_DrawThinString(0, 20, V_SNAPTOTOP|V_SNAPTOLEFT|V_6WIDTHSPACE|V_ALLOWLOWERCASE,
|
||||
va("LAPS: %d / %d", grandprixinfo.rank.laps, grandprixinfo.rank.totalLaps));
|
||||
V_DrawThinString(0, 30, V_SNAPTOTOP|V_SNAPTOLEFT|V_6WIDTHSPACE|V_ALLOWLOWERCASE,
|
||||
va("CONTINUES: %d", grandprixinfo.rank.continuesUsed));
|
||||
V_DrawThinString(0, 40, V_SNAPTOTOP|V_SNAPTOLEFT|V_6WIDTHSPACE|V_ALLOWLOWERCASE,
|
||||
va("CAPSULES: %d / %d", grandprixinfo.rank.capsules, grandprixinfo.rank.totalCapsules));
|
||||
V_DrawThinString(0, 50, V_SNAPTOTOP|V_SNAPTOLEFT|V_6WIDTHSPACE|V_ALLOWLOWERCASE,
|
||||
va("RINGS: %d / %d", grandprixinfo.rank.rings, grandprixinfo.rank.totalRings));
|
||||
V_DrawThinString(0, 60, V_SNAPTOTOP|V_SNAPTOLEFT|V_6WIDTHSPACE|V_ALLOWLOWERCASE,
|
||||
va("EMERALD: %s", (grandprixinfo.rank.specialWon == true) ? "YES" : "NO"));
|
||||
|
||||
switch (grade)
|
||||
{
|
||||
case GRADE_E: { gradeChar = 'E'; break; }
|
||||
case GRADE_D: { gradeChar = 'D'; break; }
|
||||
case GRADE_C: { gradeChar = 'C'; break; }
|
||||
case GRADE_B: { gradeChar = 'B'; break; }
|
||||
case GRADE_A: { gradeChar = 'A'; break; }
|
||||
case GRADE_S: { gradeChar = 'S'; break; }
|
||||
default: { break; }
|
||||
}
|
||||
|
||||
V_DrawThinString(0, 80, V_SNAPTOTOP|V_SNAPTOLEFT|V_6WIDTHSPACE|V_ALLOWLOWERCASE|V_YELLOWMAP,
|
||||
va(" ** FINAL GRADE: %c", gradeChar));
|
||||
}
|
||||
|
||||
void K_drawKartHUD(void)
|
||||
{
|
||||
boolean islonesome = false;
|
||||
|
|
@ -5086,4 +5140,5 @@ void K_drawKartHUD(void)
|
|||
|
||||
K_DrawWaypointDebugger();
|
||||
K_DrawDirectorDebugger();
|
||||
K_DrawGPRankDebugger();
|
||||
}
|
||||
|
|
|
|||
257
src/k_kart.c
257
src/k_kart.c
|
|
@ -43,6 +43,7 @@
|
|||
#include "k_boss.h"
|
||||
#include "k_specialstage.h"
|
||||
#include "k_roulette.h"
|
||||
#include "k_podium.h"
|
||||
|
||||
// SOME IMPORTANT VARIABLES DEFINED IN DOOMDEF.H:
|
||||
// gamespeed is cc (0 for easy, 1 for normal, 2 for hard)
|
||||
|
|
@ -109,6 +110,12 @@ void K_TimerInit(void)
|
|||
boolean domodeattack = ((modeattacking != ATTACKING_NONE)
|
||||
|| (grandprixinfo.gp == true && grandprixinfo.eventmode != GPEVENT_NONE));
|
||||
|
||||
if (K_PodiumSequence() == true)
|
||||
{
|
||||
// Leave it alone for podium
|
||||
return;
|
||||
}
|
||||
|
||||
// Rooooooolllling staaaaaaart
|
||||
if ((gametyperules & (GTR_ROLLINGSTART|GTR_CIRCUIT)) == (GTR_ROLLINGSTART|GTR_CIRCUIT))
|
||||
{
|
||||
|
|
@ -340,6 +347,7 @@ void K_RegisterKartStuff(void)
|
|||
CV_RegisterVar(&cv_kartdebugnodes);
|
||||
CV_RegisterVar(&cv_kartdebugcolorize);
|
||||
CV_RegisterVar(&cv_kartdebugdirector);
|
||||
CV_RegisterVar(&cv_debugrank);
|
||||
CV_RegisterVar(&cv_spbtest);
|
||||
CV_RegisterVar(&cv_gptest);
|
||||
CV_RegisterVar(&cv_capsuletest);
|
||||
|
|
@ -354,6 +362,12 @@ boolean K_IsPlayerLosing(player_t *player)
|
|||
INT32 winningpos = 1;
|
||||
UINT8 i, pcount = 0;
|
||||
|
||||
if (K_PodiumSequence() == true)
|
||||
{
|
||||
// Need to be in top 3 to win.
|
||||
return (player->position > 3);
|
||||
}
|
||||
|
||||
if (player->pflags & PF_NOCONTEST)
|
||||
return true;
|
||||
|
||||
|
|
@ -1226,6 +1240,11 @@ static boolean K_TryDraft(player_t *player, mobj_t *dest, fixed_t minDist, fixed
|
|||
angle_t yourangle, theirangle, diff;
|
||||
#endif
|
||||
|
||||
if (K_PodiumSequence() == true)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifndef EASYDRAFTTEST
|
||||
// Don't draft on yourself :V
|
||||
if (dest->player && dest->player == player)
|
||||
|
|
@ -3215,27 +3234,42 @@ fixed_t K_GetKartSpeedFromStat(UINT8 kartspeed)
|
|||
fixed_t K_GetKartSpeed(player_t *player, boolean doboostpower, boolean dorubberband)
|
||||
{
|
||||
const boolean mobjValid = (player->mo != NULL && P_MobjWasRemoved(player->mo) == false);
|
||||
fixed_t finalspeed = K_GetKartSpeedFromStat(player->kartspeed);
|
||||
fixed_t finalspeed = 0;
|
||||
|
||||
if (gametyperules & GTR_BUMPERS && player->bumpers <= 0)
|
||||
finalspeed = 3 * finalspeed / 2;
|
||||
|
||||
if (player->spheres > 0)
|
||||
if (K_PodiumSequence() == true)
|
||||
{
|
||||
fixed_t sphereAdd = (FRACUNIT/40); // 100% at max
|
||||
finalspeed = FixedMul(finalspeed, FRACUNIT + (sphereAdd * player->spheres));
|
||||
// Make 1st reach their podium faster!
|
||||
finalspeed = K_GetKartSpeedFromStat(max(1, 11 - (player->position * 3)));
|
||||
|
||||
// Ignore other speed boosts.
|
||||
doboostpower = dorubberband = false;
|
||||
}
|
||||
|
||||
if (K_PlayerUsesBotMovement(player))
|
||||
else
|
||||
{
|
||||
// Increase bot speed by 1-10% depending on difficulty
|
||||
fixed_t add = (player->botvars.difficulty * (FRACUNIT/10)) / DIFFICULTBOT;
|
||||
finalspeed = FixedMul(finalspeed, FRACUNIT + add);
|
||||
finalspeed = K_GetKartSpeedFromStat(player->kartspeed);
|
||||
|
||||
if (player->bot && player->botvars.rival)
|
||||
if (gametyperules & GTR_BUMPERS && player->bumpers <= 0)
|
||||
{
|
||||
// +10% top speed for the rival
|
||||
finalspeed = FixedMul(finalspeed, 11*FRACUNIT/10);
|
||||
finalspeed = 3 * finalspeed / 2;
|
||||
}
|
||||
|
||||
if (player->spheres > 0)
|
||||
{
|
||||
fixed_t sphereAdd = (FRACUNIT/40); // 100% at max
|
||||
finalspeed = FixedMul(finalspeed, FRACUNIT + (sphereAdd * player->spheres));
|
||||
}
|
||||
|
||||
if (K_PlayerUsesBotMovement(player))
|
||||
{
|
||||
// Increase bot speed by 1-10% depending on difficulty
|
||||
fixed_t add = (player->botvars.difficulty * (FRACUNIT/10)) / DIFFICULTBOT;
|
||||
finalspeed = FixedMul(finalspeed, FRACUNIT + add);
|
||||
|
||||
if (player->bot && player->botvars.rival)
|
||||
{
|
||||
// +10% top speed for the rival
|
||||
finalspeed = FixedMul(finalspeed, 11*FRACUNIT/10);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -3263,16 +3297,32 @@ fixed_t K_GetKartSpeed(player_t *player, boolean doboostpower, boolean dorubberb
|
|||
fixed_t K_GetKartAccel(player_t *player)
|
||||
{
|
||||
fixed_t k_accel = 121;
|
||||
UINT8 stat = (9 - player->kartspeed);
|
||||
|
||||
k_accel += 17 * (9 - player->kartspeed); // 121 - 257
|
||||
if (K_PodiumSequence() == true)
|
||||
{
|
||||
// Normalize to Metal's accel
|
||||
stat = 1;
|
||||
}
|
||||
|
||||
k_accel += 17 * stat; // 121 - 257
|
||||
|
||||
if (K_PodiumSequence() == true)
|
||||
{
|
||||
return FixedMul(k_accel, FRACUNIT / 4);
|
||||
}
|
||||
|
||||
// karma bomb gets 2x acceleration
|
||||
if ((gametyperules & GTR_BUMPERS) && player->bumpers <= 0)
|
||||
{
|
||||
k_accel *= 2;
|
||||
}
|
||||
|
||||
// Marble Garden Top gets 1200% accel
|
||||
if (player->curshield == KSHIELD_TOP)
|
||||
{
|
||||
k_accel *= 12;
|
||||
}
|
||||
|
||||
return FixedMul(k_accel, (FRACUNIT + player->accelboost) / 4);
|
||||
}
|
||||
|
|
@ -3403,7 +3453,7 @@ fixed_t K_GetNewSpeed(player_t *player)
|
|||
// Don't calculate the acceleration as ever being above top speed
|
||||
if (oldspeed > p_speed)
|
||||
oldspeed = p_speed;
|
||||
newspeed = FixedDiv(FixedDiv(FixedMul(oldspeed, accelmax - p_accel) + FixedMul(p_speed, p_accel), accelmax), ORIG_FRICTION);
|
||||
newspeed = FixedDiv(FixedDiv(FixedMul(oldspeed, accelmax - p_accel) + FixedMul(p_speed, p_accel), accelmax), K_PlayerBaseFriction(ORIG_FRICTION));
|
||||
|
||||
finalspeed = newspeed - oldspeed;
|
||||
|
||||
|
|
@ -6975,6 +7025,13 @@ static void K_UpdateEngineSounds(player_t *player)
|
|||
INT32 targetsnd = 0;
|
||||
INT32 i;
|
||||
|
||||
if (leveltime < 8 || player->spectator || gamestate != GS_LEVEL)
|
||||
{
|
||||
// Silence the engines, and reset sound number while we're at it.
|
||||
player->karthud[khud_enginesnd] = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
s = (player->kartspeed - 1) / 3;
|
||||
w = (player->kartweight - 1) / 3;
|
||||
|
||||
|
|
@ -6987,13 +7044,6 @@ static void K_UpdateEngineSounds(player_t *player)
|
|||
|
||||
class = s + (3*w);
|
||||
|
||||
if (leveltime < 8 || player->spectator)
|
||||
{
|
||||
// Silence the engines, and reset sound number while we're at it.
|
||||
player->karthud[khud_enginesnd] = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
#if 0
|
||||
if ((leveltime % 8) != ((player-players) % 8)) // Per-player offset, to make engines sound distinct!
|
||||
#else
|
||||
|
|
@ -8471,6 +8521,12 @@ static waypoint_t *K_GetPlayerNextWaypoint(player_t *player)
|
|||
--------------------------------------------------*/
|
||||
void K_UpdateDistanceFromFinishLine(player_t *const player)
|
||||
{
|
||||
if (K_PodiumSequence() == true)
|
||||
{
|
||||
K_UpdatePodiumWaypoints(player);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((player != NULL) && (player->mo != NULL))
|
||||
{
|
||||
waypoint_t *finishline = K_GetFinishLineWaypoint();
|
||||
|
|
@ -8837,6 +8893,15 @@ INT16 K_GetKartTurnValue(player_t *player, INT16 turnvalue)
|
|||
p_speed = min(currentSpeed, (p_maxspeed * 2));
|
||||
}
|
||||
|
||||
if (K_PodiumSequence() == true)
|
||||
{
|
||||
// Normalize turning for podium
|
||||
weightadjust = FixedDiv((p_maxspeed * 3), (p_maxspeed * 3) + (2 * FRACUNIT));
|
||||
turnfixed = FixedMul(turnfixed, weightadjust);
|
||||
turnfixed *= 2;
|
||||
return (turnfixed / FRACUNIT);
|
||||
}
|
||||
|
||||
weightadjust = FixedDiv((p_maxspeed * 3) - p_speed, (p_maxspeed * 3) + (player->kartweight * FRACUNIT));
|
||||
|
||||
if (K_PlayerUsesBotMovement(player))
|
||||
|
|
@ -9263,64 +9328,79 @@ void K_KartUpdatePosition(player_t *player)
|
|||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
if (K_PodiumSequence() == true)
|
||||
{
|
||||
if (!playeringame[i] || players[i].spectator || !players[i].mo)
|
||||
continue;
|
||||
position = K_GetPodiumPosition(player);
|
||||
|
||||
realplayers++;
|
||||
|
||||
if (gametyperules & GTR_CIRCUIT)
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
if (player->exiting) // End of match standings
|
||||
{
|
||||
// Only time matters
|
||||
if (players[i].realtime < player->realtime)
|
||||
position++;
|
||||
}
|
||||
else
|
||||
{
|
||||
// I'm a lap behind this player OR
|
||||
// My distance to the finish line is higher, so I'm behind
|
||||
if ((players[i].laps > player->laps)
|
||||
|| (players[i].distancetofinish < player->distancetofinish))
|
||||
{
|
||||
position++;
|
||||
}
|
||||
}
|
||||
if (!playeringame[i] || players[i].spectator || !players[i].mo)
|
||||
continue;
|
||||
|
||||
realplayers++;
|
||||
}
|
||||
else
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
if (player->exiting) // End of match standings
|
||||
{
|
||||
// Only score matters
|
||||
if (players[i].roundscore > player->roundscore)
|
||||
position++;
|
||||
}
|
||||
else
|
||||
{
|
||||
UINT8 myEmeralds = K_NumEmeralds(player);
|
||||
UINT8 yourEmeralds = K_NumEmeralds(&players[i]);
|
||||
if (!playeringame[i] || players[i].spectator || !players[i].mo)
|
||||
continue;
|
||||
|
||||
// First compare all points
|
||||
if (players[i].roundscore > player->roundscore)
|
||||
realplayers++;
|
||||
|
||||
if (gametyperules & GTR_CIRCUIT)
|
||||
{
|
||||
if (player->exiting) // End of match standings
|
||||
{
|
||||
position++;
|
||||
// Only time matters
|
||||
if (players[i].realtime < player->realtime)
|
||||
position++;
|
||||
}
|
||||
else if (players[i].roundscore == player->roundscore)
|
||||
else
|
||||
{
|
||||
// Emeralds are a tie breaker
|
||||
if (yourEmeralds > myEmeralds)
|
||||
// I'm a lap behind this player OR
|
||||
// My distance to the finish line is higher, so I'm behind
|
||||
if ((players[i].laps > player->laps)
|
||||
|| (players[i].distancetofinish < player->distancetofinish))
|
||||
{
|
||||
position++;
|
||||
}
|
||||
else if (yourEmeralds == myEmeralds)
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (player->exiting) // End of match standings
|
||||
{
|
||||
// Only score matters
|
||||
if (players[i].roundscore > player->roundscore)
|
||||
position++;
|
||||
}
|
||||
else
|
||||
{
|
||||
UINT8 myEmeralds = K_NumEmeralds(player);
|
||||
UINT8 yourEmeralds = K_NumEmeralds(&players[i]);
|
||||
|
||||
// First compare all points
|
||||
if (players[i].roundscore > player->roundscore)
|
||||
{
|
||||
// Bumpers are the second tier tie breaker
|
||||
if (players[i].bumpers > player->bumpers)
|
||||
position++;
|
||||
}
|
||||
else if (players[i].roundscore == player->roundscore)
|
||||
{
|
||||
// Emeralds are a tie breaker
|
||||
if (yourEmeralds > myEmeralds)
|
||||
{
|
||||
position++;
|
||||
}
|
||||
else if (yourEmeralds == myEmeralds)
|
||||
{
|
||||
// Bumpers are the second tier tie breaker
|
||||
if (players[i].bumpers > player->bumpers)
|
||||
{
|
||||
position++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -9378,6 +9458,29 @@ void K_KartUpdatePosition(player_t *player)
|
|||
player->position = position;
|
||||
}
|
||||
|
||||
void K_UpdateAllPlayerPositions(void)
|
||||
{
|
||||
INT32 i;
|
||||
|
||||
// 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]);
|
||||
}
|
||||
}
|
||||
|
||||
// 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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// K_StripItems
|
||||
//
|
||||
|
|
@ -9917,18 +10020,38 @@ static void K_AirFailsafe(player_t *player)
|
|||
}
|
||||
}
|
||||
|
||||
//
|
||||
// K_PlayerBaseFriction
|
||||
//
|
||||
fixed_t K_PlayerBaseFriction(fixed_t original)
|
||||
{
|
||||
fixed_t frict = original;
|
||||
|
||||
if (K_PodiumSequence() == true)
|
||||
{
|
||||
frict -= FRACUNIT >> 4;
|
||||
}
|
||||
|
||||
if (frict > FRACUNIT) { frict = FRACUNIT; }
|
||||
if (frict < 0) { frict = 0; }
|
||||
|
||||
return frict;
|
||||
}
|
||||
|
||||
//
|
||||
// K_AdjustPlayerFriction
|
||||
//
|
||||
void K_AdjustPlayerFriction(player_t *player)
|
||||
{
|
||||
fixed_t prevfriction = player->mo->friction;
|
||||
const fixed_t prevfriction = K_PlayerBaseFriction(player->mo->friction);
|
||||
|
||||
if (P_IsObjectOnGround(player->mo) == false)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
player->mo->friction = prevfriction;
|
||||
|
||||
// Reduce friction after hitting a spring
|
||||
if (player->tiregrease)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -139,6 +139,7 @@ INT32 K_GetKartDriftSparkValueForStage(player_t *player, UINT8 stage);
|
|||
void K_SpawnDriftBoostExplosion(player_t *player, int stage);
|
||||
void K_SpawnDriftElectricSparks(player_t *player, int color, boolean shockwave);
|
||||
void K_KartUpdatePosition(player_t *player);
|
||||
void K_UpdateAllPlayerPositions(void);
|
||||
SINT8 K_GetTotallyRandomResult(UINT8 useodds);
|
||||
mobj_t *K_CreatePaperItem(fixed_t x, fixed_t y, fixed_t z, angle_t angle, SINT8 flip, UINT8 type, UINT8 amount);
|
||||
void K_DropItems(player_t *player);
|
||||
|
|
@ -176,6 +177,7 @@ fixed_t K_3dKartMovement(player_t *player);
|
|||
boolean K_PlayerEBrake(player_t *player);
|
||||
SINT8 K_Sliptiding(player_t *player);
|
||||
boolean K_FastFallBounce(player_t *player);
|
||||
fixed_t K_PlayerBaseFriction(fixed_t original);
|
||||
void K_AdjustPlayerFriction(player_t *player);
|
||||
void K_MoveKartPlayer(player_t *player, boolean onground);
|
||||
void K_CheckSpectateStatus(void);
|
||||
|
|
|
|||
|
|
@ -201,6 +201,23 @@ boolean M_PrevOpt(void)
|
|||
return true;
|
||||
}
|
||||
|
||||
static boolean M_GamestateCanOpenMenu(void)
|
||||
{
|
||||
switch (gamestate)
|
||||
{
|
||||
case GS_INTRO:
|
||||
case GS_CUTSCENE:
|
||||
case GS_GAMEEND:
|
||||
case GS_CREDITS:
|
||||
case GS_EVALUATION:
|
||||
case GS_CEREMONY:
|
||||
return false;
|
||||
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// M_Responder
|
||||
//
|
||||
|
|
@ -208,9 +225,9 @@ boolean M_Responder(event_t *ev)
|
|||
{
|
||||
menuKey = -1;
|
||||
|
||||
if (dedicated || (demo.playback && demo.title)
|
||||
|| gamestate == GS_INTRO || gamestate == GS_CUTSCENE || gamestate == GS_GAMEEND
|
||||
|| gamestate == GS_CREDITS || gamestate == GS_EVALUATION)
|
||||
if (dedicated
|
||||
|| (demo.playback && demo.title)
|
||||
|| M_GamestateCanOpenMenu() == false)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
504
src/k_podium.c
Normal file
504
src/k_podium.c
Normal file
|
|
@ -0,0 +1,504 @@
|
|||
// DR. ROBOTNIK'S RING RACERS
|
||||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) by Sally "TehRealSalt" Cochenour
|
||||
// Copyright (C) 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_podium.c
|
||||
/// \brief Grand Prix podium cutscene
|
||||
|
||||
#include "k_podium.h"
|
||||
|
||||
#include "doomdef.h"
|
||||
#include "doomstat.h"
|
||||
#include "d_main.h"
|
||||
#include "d_netcmd.h"
|
||||
#include "f_finale.h"
|
||||
#include "g_game.h"
|
||||
#include "hu_stuff.h"
|
||||
#include "r_local.h"
|
||||
#include "s_sound.h"
|
||||
#include "i_time.h"
|
||||
#include "i_video.h"
|
||||
#include "v_video.h"
|
||||
#include "w_wad.h"
|
||||
#include "z_zone.h"
|
||||
#include "i_system.h"
|
||||
#include "i_threads.h"
|
||||
#include "dehacked.h"
|
||||
#include "g_input.h"
|
||||
#include "console.h"
|
||||
#include "m_random.h"
|
||||
#include "m_misc.h" // moviemode functionality
|
||||
#include "y_inter.h"
|
||||
#include "m_cond.h"
|
||||
#include "p_local.h"
|
||||
#include "p_setup.h"
|
||||
#include "st_stuff.h" // hud hiding
|
||||
#include "fastcmp.h"
|
||||
|
||||
#include "lua_hud.h"
|
||||
#include "lua_hook.h"
|
||||
|
||||
#include "k_menu.h"
|
||||
#include "k_grandprix.h"
|
||||
#include "k_rank.h"
|
||||
|
||||
static struct podiumData_s
|
||||
{
|
||||
boolean ranking;
|
||||
gpRank_t rank;
|
||||
gp_rank_e grade;
|
||||
UINT8 state;
|
||||
UINT8 delay;
|
||||
UINT8 fade;
|
||||
} podiumData;
|
||||
|
||||
#define PODIUM_STATES (9) // TODO: enum when this actually gets made
|
||||
|
||||
/*--------------------------------------------------
|
||||
boolean K_PodiumSequence(void)
|
||||
|
||||
See header file for description.
|
||||
--------------------------------------------------*/
|
||||
boolean K_PodiumSequence(void)
|
||||
{
|
||||
return (gamestate == GS_CEREMONY);
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
UINT8 K_GetPodiumPosition(player_t *player)
|
||||
|
||||
See header file for description.
|
||||
--------------------------------------------------*/
|
||||
UINT8 K_GetPodiumPosition(player_t *player)
|
||||
{
|
||||
UINT8 position = 1;
|
||||
INT32 i;
|
||||
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
player_t *other = NULL;
|
||||
if (playeringame[i] == false)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
other = &players[i];
|
||||
if (other->spectator == true)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (other->score > player->score)
|
||||
{
|
||||
// Final score is the important part.
|
||||
position++;
|
||||
}
|
||||
else if (other->score == player->score)
|
||||
{
|
||||
if (other->bot == false && player->bot == true)
|
||||
{
|
||||
// Bots are never as important as players.
|
||||
position++;
|
||||
}
|
||||
else if (i < player - players)
|
||||
{
|
||||
// Port priority is the final tie breaker.
|
||||
position++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return position;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
static void K_SetPodiumWaypoint(player_t *const player, waypoint_t *const waypoint)
|
||||
|
||||
Changes the player's current and next waypoints, for
|
||||
use during the podium sequence.
|
||||
|
||||
Input Arguments:-
|
||||
player - The player to update the waypoints of.
|
||||
waypoint - The new current waypoint.
|
||||
|
||||
Return:-
|
||||
None
|
||||
--------------------------------------------------*/
|
||||
static void K_SetPodiumWaypoint(player_t *const player, waypoint_t *const waypoint)
|
||||
{
|
||||
// Set the new waypoint.
|
||||
player->currentwaypoint = waypoint;
|
||||
|
||||
if ((waypoint == NULL)
|
||||
|| (waypoint->nextwaypoints == NULL)
|
||||
|| (waypoint->numnextwaypoints == 0U))
|
||||
{
|
||||
// No waypoint, or no next waypoint.
|
||||
player->nextwaypoint = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
// Simply use the first available next waypoint.
|
||||
// No need for split paths in these cutscenes.
|
||||
player->nextwaypoint = waypoint->nextwaypoints[0];
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
void K_InitializePodiumWaypoint(player_t *const player)
|
||||
|
||||
See header file for description.
|
||||
--------------------------------------------------*/
|
||||
void K_InitializePodiumWaypoint(player_t *const player)
|
||||
{
|
||||
if ((player != NULL) && (player->mo != NULL))
|
||||
{
|
||||
player->position = K_GetPodiumPosition(player);
|
||||
|
||||
if (player->position > 0 && player->position <= MAXPLAYERS)
|
||||
{
|
||||
// Initialize our first waypoint to the one that
|
||||
// matches our position.
|
||||
K_SetPodiumWaypoint(player, K_GetWaypointFromID(player->position));
|
||||
}
|
||||
else
|
||||
{
|
||||
// None does, so remove it if we happen to have one.
|
||||
K_SetPodiumWaypoint(player, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
void K_UpdatePodiumWaypoints(player_t *const player)
|
||||
|
||||
See header file for description.
|
||||
--------------------------------------------------*/
|
||||
void K_UpdatePodiumWaypoints(player_t *const player)
|
||||
{
|
||||
if ((player != NULL) && (player->mo != NULL))
|
||||
{
|
||||
if (player->currentwaypoint != NULL)
|
||||
{
|
||||
const fixed_t xydist = P_AproxDistance(
|
||||
player->mo->x - player->currentwaypoint->mobj->x,
|
||||
player->mo->y - player->currentwaypoint->mobj->y
|
||||
);
|
||||
const fixed_t xyzdist = P_AproxDistance(
|
||||
xydist,
|
||||
player->mo->z - player->currentwaypoint->mobj->z
|
||||
);
|
||||
//const fixed_t speed = P_AproxDistance(player->mo->momx, player->mo->momy);
|
||||
|
||||
if (xyzdist <= player->mo->radius + player->currentwaypoint->mobj->radius)
|
||||
{
|
||||
// Reached waypoint, go to the next waypoint.
|
||||
K_SetPodiumWaypoint(player, player->nextwaypoint);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
boolean K_StartCeremony(void)
|
||||
|
||||
See header file for description.
|
||||
--------------------------------------------------*/
|
||||
boolean K_StartCeremony(void)
|
||||
{
|
||||
INT32 podiumMapNum = nummapheaders;
|
||||
INT32 i;
|
||||
|
||||
if (grandprixinfo.gp == false)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (podiummap
|
||||
&& ((podiumMapNum = G_MapNumber(podiummap)) < nummapheaders)
|
||||
&& mapheaderinfo[podiumMapNum]
|
||||
&& mapheaderinfo[podiumMapNum]->lumpnum != LUMPERROR)
|
||||
{
|
||||
P_SetTarget(&titlemapcam.mobj, NULL);
|
||||
|
||||
gamemap = podiumMapNum+1;
|
||||
|
||||
maptol = mapheaderinfo[gamemap-1]->typeoflevel;
|
||||
globalweather = mapheaderinfo[gamemap-1]->weather;
|
||||
|
||||
// Make sure all of the GAME OVER'd players can spawn
|
||||
// and be present for the podium
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
if (playeringame[i] && !players[i].spectator && !players[i].bot)
|
||||
{
|
||||
players[i].lives = max(1, players[i].lives);
|
||||
}
|
||||
}
|
||||
|
||||
G_SetGametype(GT_RACE);
|
||||
G_DoLoadLevelEx(false, GS_CEREMONY);
|
||||
|
||||
r_splitscreen = 0; // Only one screen for the ceremony
|
||||
R_ExecuteSetViewSize();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
void K_FinishCeremony(void)
|
||||
|
||||
See header file for description.
|
||||
--------------------------------------------------*/
|
||||
void K_FinishCeremony(void)
|
||||
{
|
||||
if (K_PodiumSequence() == false)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
podiumData.ranking = true;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
void K_ResetCeremony(void)
|
||||
|
||||
See header file for description.
|
||||
--------------------------------------------------*/
|
||||
void K_ResetCeremony(void)
|
||||
{
|
||||
memset(&podiumData, 0, sizeof(struct podiumData_s));
|
||||
|
||||
if (K_PodiumSequence() == false)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
podiumData.rank = grandprixinfo.rank;
|
||||
podiumData.grade = K_CalculateGPGrade(&podiumData.rank);
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
void K_CeremonyTicker(boolean run)
|
||||
|
||||
See header file for description.
|
||||
--------------------------------------------------*/
|
||||
void K_CeremonyTicker(boolean run)
|
||||
{
|
||||
// don't trigger if doing anything besides idling
|
||||
if (gameaction != ga_nothing || gamestate != GS_CEREMONY)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
P_TickAltView(&titlemapcam);
|
||||
|
||||
if (titlemapcam.mobj != NULL)
|
||||
{
|
||||
camera[0].x = titlemapcam.mobj->x;
|
||||
camera[0].y = titlemapcam.mobj->y;
|
||||
camera[0].z = titlemapcam.mobj->z;
|
||||
camera[0].angle = titlemapcam.mobj->angle;
|
||||
camera[0].aiming = titlemapcam.mobj->pitch;
|
||||
camera[0].subsector = titlemapcam.mobj->subsector;
|
||||
}
|
||||
|
||||
if (podiumData.ranking == false)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (run == true)
|
||||
{
|
||||
if (podiumData.fade < 16)
|
||||
{
|
||||
podiumData.fade++;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (podiumData.state < PODIUM_STATES)
|
||||
{
|
||||
podiumData.delay++;
|
||||
|
||||
if (podiumData.delay > TICRATE/2)
|
||||
{
|
||||
podiumData.state++;
|
||||
podiumData.delay = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
boolean K_CeremonyResponder(event_t *event)
|
||||
|
||||
See header file for description.
|
||||
--------------------------------------------------*/
|
||||
boolean K_CeremonyResponder(event_t *event)
|
||||
{
|
||||
INT32 key = event->data1;
|
||||
|
||||
if (podiumData.ranking == false || podiumData.state < PODIUM_STATES)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// remap virtual keys (mouse & joystick buttons)
|
||||
switch (key)
|
||||
{
|
||||
case KEY_MOUSE1:
|
||||
key = KEY_ENTER;
|
||||
break;
|
||||
case KEY_MOUSE1 + 1:
|
||||
key = KEY_BACKSPACE;
|
||||
break;
|
||||
case KEY_JOY1:
|
||||
case KEY_JOY1 + 2:
|
||||
key = KEY_ENTER;
|
||||
break;
|
||||
case KEY_JOY1 + 3:
|
||||
key = 'n';
|
||||
break;
|
||||
case KEY_JOY1 + 1:
|
||||
key = KEY_BACKSPACE;
|
||||
break;
|
||||
case KEY_HAT1:
|
||||
key = KEY_UPARROW;
|
||||
break;
|
||||
case KEY_HAT1 + 1:
|
||||
key = KEY_DOWNARROW;
|
||||
break;
|
||||
case KEY_HAT1 + 2:
|
||||
key = KEY_LEFTARROW;
|
||||
break;
|
||||
case KEY_HAT1 + 3:
|
||||
key = KEY_RIGHTARROW;
|
||||
break;
|
||||
}
|
||||
|
||||
if (event->type != ev_keydown)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (key != KEY_ESCAPE && key != KEY_ENTER && key != KEY_BACKSPACE)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
void K_CeremonyDrawer(void)
|
||||
|
||||
See header file for description.
|
||||
--------------------------------------------------*/
|
||||
void K_CeremonyDrawer(void)
|
||||
{
|
||||
if (podiumData.ranking == true)
|
||||
{
|
||||
char gradeChar = '?';
|
||||
INT32 x = 64;
|
||||
INT32 y = 48;
|
||||
INT32 i;
|
||||
|
||||
switch (podiumData.grade)
|
||||
{
|
||||
case GRADE_E: { gradeChar = 'E'; break; }
|
||||
case GRADE_D: { gradeChar = 'D'; break; }
|
||||
case GRADE_C: { gradeChar = 'C'; break; }
|
||||
case GRADE_B: { gradeChar = 'B'; break; }
|
||||
case GRADE_A: { gradeChar = 'A'; break; }
|
||||
case GRADE_S: { gradeChar = 'S'; break; }
|
||||
default: { break; }
|
||||
}
|
||||
|
||||
V_DrawFadeScreen(0xFF00, podiumData.fade);
|
||||
|
||||
for (i = 0; i <= podiumData.state; i++)
|
||||
{
|
||||
switch (i)
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
V_DrawString(x, y, V_ALLOWLOWERCASE,
|
||||
va("POS: %d / %d", podiumData.rank.position, RANK_NEUTRAL_POSITION)
|
||||
);
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
V_DrawString(x, y, V_ALLOWLOWERCASE,
|
||||
va("PTS: %d / %d", podiumData.rank.winPoints, podiumData.rank.totalPoints)
|
||||
);
|
||||
break;
|
||||
}
|
||||
case 3:
|
||||
{
|
||||
V_DrawString(x, y, V_ALLOWLOWERCASE,
|
||||
va("LAPS: %d / %d", podiumData.rank.laps, podiumData.rank.totalLaps)
|
||||
);
|
||||
break;
|
||||
}
|
||||
case 4:
|
||||
{
|
||||
V_DrawString(x, y, V_ALLOWLOWERCASE,
|
||||
va("CONTINUES: %d", podiumData.rank.continuesUsed)
|
||||
);
|
||||
break;
|
||||
}
|
||||
case 5:
|
||||
{
|
||||
V_DrawString(x, y, V_ALLOWLOWERCASE,
|
||||
va("CAPSULES: %d / %d", podiumData.rank.capsules, podiumData.rank.totalCapsules)
|
||||
);
|
||||
break;
|
||||
}
|
||||
case 6:
|
||||
{
|
||||
V_DrawString(x, y, V_ALLOWLOWERCASE,
|
||||
va("RINGS: %d / %d", podiumData.rank.rings, podiumData.rank.totalRings)
|
||||
);
|
||||
break;
|
||||
}
|
||||
case 7:
|
||||
{
|
||||
V_DrawString(x, y, V_ALLOWLOWERCASE,
|
||||
va("EMERALD: %s", (podiumData.rank.specialWon == true) ? "YES" : "NO")
|
||||
);
|
||||
break;
|
||||
}
|
||||
case 8:
|
||||
{
|
||||
V_DrawString(x, y + 10, V_YELLOWMAP|V_ALLOWLOWERCASE,
|
||||
va(" ** FINAL GRADE: %c", gradeChar)
|
||||
);
|
||||
break;
|
||||
}
|
||||
case 9:
|
||||
{
|
||||
V_DrawThinString(2, BASEVIDHEIGHT - 10, V_SNAPTOBOTTOM|V_SNAPTOLEFT|V_6WIDTHSPACE|V_ALLOWLOWERCASE,
|
||||
"Press some button type deal to continue"
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
y += 10;
|
||||
}
|
||||
}
|
||||
|
||||
if (timeinmap < 16)
|
||||
{
|
||||
// Level fade-in
|
||||
V_DrawCustomFadeScreen(((levelfadecol == 0) ? "FADEMAP1" : "FADEMAP0"), 31-(timeinmap*2));
|
||||
}
|
||||
}
|
||||
178
src/k_podium.h
Normal file
178
src/k_podium.h
Normal file
|
|
@ -0,0 +1,178 @@
|
|||
// DR. ROBOTNIK'S RING RACERS
|
||||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) by Sally "TehRealSalt" Cochenour
|
||||
// Copyright (C) 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_podium.h
|
||||
/// \brief Grand Prix podium cutscene
|
||||
|
||||
#ifndef __K_PODIUM__
|
||||
#define __K_PODIUM__
|
||||
|
||||
#include "doomtype.h"
|
||||
#include "d_event.h"
|
||||
#include "p_mobj.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*--------------------------------------------------
|
||||
boolean K_PodiumSequence(void);
|
||||
|
||||
Returns whenver or not we are in the podium
|
||||
cutscene mode.
|
||||
|
||||
Input Arguments:-
|
||||
N/A
|
||||
|
||||
Return:-
|
||||
true if we're in GS_CEREMONY, otherwise false.
|
||||
--------------------------------------------------*/
|
||||
|
||||
boolean K_PodiumSequence(void);
|
||||
|
||||
|
||||
/*--------------------------------------------------
|
||||
UINT8 K_GetPodiumPosition(player_t *player);
|
||||
|
||||
Calculates what the player's position would
|
||||
be at the final standings.
|
||||
|
||||
Input Arguments:-
|
||||
player - The player to do the calculation for.
|
||||
|
||||
Return:-
|
||||
The player's final position, as a number
|
||||
between 1 and MAXPLAYERS.
|
||||
--------------------------------------------------*/
|
||||
|
||||
UINT8 K_GetPodiumPosition(player_t *player);
|
||||
|
||||
|
||||
/*--------------------------------------------------
|
||||
void K_InitializePodiumWaypoint(player_t *const player);
|
||||
|
||||
Sets a bot's current waypoint to one matching
|
||||
their final podium position.
|
||||
|
||||
Input Arguments:-
|
||||
player - The podium bot to update.
|
||||
|
||||
Return:-
|
||||
N/A
|
||||
--------------------------------------------------*/
|
||||
|
||||
void K_InitializePodiumWaypoint(player_t *const player);
|
||||
|
||||
|
||||
/*--------------------------------------------------
|
||||
void K_UpdatePodiumWaypoints(player_t *const player);
|
||||
|
||||
Helps a bot move along a predetermined path by
|
||||
updating their current and next waypoints as
|
||||
they move. Intended for the podium sequence.
|
||||
|
||||
Input Arguments:-
|
||||
player - The podium bot to update.
|
||||
|
||||
Return:-
|
||||
N/A
|
||||
--------------------------------------------------*/
|
||||
|
||||
void K_UpdatePodiumWaypoints(player_t *const player);
|
||||
|
||||
|
||||
/*--------------------------------------------------
|
||||
boolean K_StartCeremony(void);
|
||||
|
||||
Loads the podium map and changes the gamestate
|
||||
to the podium cutscene mode.
|
||||
|
||||
Input Arguments:-
|
||||
N/A
|
||||
|
||||
Return:-
|
||||
true if successful, otherwise false. Can fail
|
||||
if there is no podium map defined.
|
||||
--------------------------------------------------*/
|
||||
|
||||
boolean K_StartCeremony(void);
|
||||
|
||||
|
||||
/*--------------------------------------------------
|
||||
void K_FinishCeremony(void);
|
||||
|
||||
Called at the end of the podium cutscene,
|
||||
displays the ranking screen and starts
|
||||
accepting input.
|
||||
--------------------------------------------------*/
|
||||
|
||||
void K_FinishCeremony(void);
|
||||
|
||||
|
||||
/*--------------------------------------------------
|
||||
void K_ResetCeremony(void);
|
||||
|
||||
Called on level load, to reset all of the
|
||||
podium variables.
|
||||
--------------------------------------------------*/
|
||||
|
||||
void K_ResetCeremony(void);
|
||||
|
||||
|
||||
/*--------------------------------------------------
|
||||
void K_CeremonyTicker(boolean run);
|
||||
|
||||
Ticker function to be ran during the podium
|
||||
cutscene mode gamestate. Handles updating
|
||||
the camera.
|
||||
|
||||
Input Arguments:-
|
||||
run - Set to true when we're running a
|
||||
new game frame.
|
||||
|
||||
Return:-
|
||||
N/A
|
||||
--------------------------------------------------*/
|
||||
|
||||
void K_CeremonyTicker(boolean run);
|
||||
|
||||
|
||||
/*--------------------------------------------------
|
||||
void K_CeremonyResponder(event_t *ev);
|
||||
|
||||
Responder function to be ran during the podium
|
||||
cutscene mode gamestate. Handles key presses
|
||||
ending the podium scene.
|
||||
|
||||
Input Arguments:-
|
||||
ev - The player input event.
|
||||
|
||||
Return:-
|
||||
true to end the podium cutscene and return
|
||||
to the title screen, otherwise false.
|
||||
--------------------------------------------------*/
|
||||
|
||||
boolean K_CeremonyResponder(event_t *ev);
|
||||
|
||||
|
||||
/*--------------------------------------------------
|
||||
void K_CeremonyDrawer(void);
|
||||
|
||||
Handles the ranking screen and other HUD for
|
||||
the podium cutscene.
|
||||
--------------------------------------------------*/
|
||||
|
||||
void K_CeremonyDrawer(void);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // __K_PODIUM__
|
||||
416
src/k_rank.c
Normal file
416
src/k_rank.c
Normal file
|
|
@ -0,0 +1,416 @@
|
|||
// DR. ROBOTNIK'S RING RACERS
|
||||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) by Sally "TehRealSalt" Cochenour
|
||||
// Copyright (C) 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_rank.c
|
||||
/// \brief Grand Prix mode ranking
|
||||
|
||||
#include "k_rank.h"
|
||||
#include "k_grandprix.h"
|
||||
#include "k_specialstage.h"
|
||||
#include "doomdef.h"
|
||||
#include "d_player.h"
|
||||
#include "g_game.h"
|
||||
#include "k_bot.h"
|
||||
#include "k_kart.h"
|
||||
#include "m_random.h"
|
||||
#include "r_things.h"
|
||||
#include "fastcmp.h"
|
||||
#include "byteptr.h"
|
||||
|
||||
// I was ALMOST tempted to start tearing apart all
|
||||
// of the map loading code and turning it into C++
|
||||
// and making it properly split between read-only
|
||||
// and true level loading and clean up all of the
|
||||
// global variable garbage it uses ... but I stopped
|
||||
// myself. So here's code duplication hell instead.
|
||||
static UINT32 g_rankCapsules_mapthingsPos[UINT16_MAX];
|
||||
static size_t g_rankCapsules_nummapthings = 0;
|
||||
static boolean g_rankCapsules_udmf = false;
|
||||
static UINT32 g_rankCapsules_count = 0;
|
||||
|
||||
/*--------------------------------------------------
|
||||
static void RankCapsules_TextmapCount(size_t size)
|
||||
|
||||
Counts the number of map things and records
|
||||
the structure positions, for the result of
|
||||
RankCapsules_CountFromMap.
|
||||
|
||||
Input Arguments:-
|
||||
size - Length of the TEXTMAP lump.
|
||||
|
||||
Return:-
|
||||
N/A
|
||||
--------------------------------------------------*/
|
||||
static UINT32 RankCapsules_TextmapCount(size_t size)
|
||||
{
|
||||
const char *tkn = M_TokenizerRead(0);
|
||||
UINT8 brackets = 0;
|
||||
|
||||
g_rankCapsules_nummapthings = 0;
|
||||
|
||||
// Look for namespace at the beginning.
|
||||
if (!fastcmp(tkn, "namespace"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if namespace is valid.
|
||||
tkn = M_TokenizerRead(0);
|
||||
|
||||
while ((tkn = M_TokenizerRead(0)) && M_TokenizerGetEndPos() < size)
|
||||
{
|
||||
// Avoid anything inside bracketed stuff, only look for external keywords.
|
||||
if (brackets)
|
||||
{
|
||||
if (fastcmp(tkn, "}"))
|
||||
brackets--;
|
||||
}
|
||||
else if (fastcmp(tkn, "{"))
|
||||
brackets++;
|
||||
// Check for valid fields.
|
||||
else if (fastcmp(tkn, "thing"))
|
||||
g_rankCapsules_mapthingsPos[g_rankCapsules_nummapthings++] = M_TokenizerGetEndPos();
|
||||
}
|
||||
|
||||
if (brackets)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
static void RankCapsules_LoadTextmap(void)
|
||||
|
||||
Loads UDMF map data for the result of
|
||||
RankCapsules_CountFromMap.
|
||||
--------------------------------------------------*/
|
||||
static void RankCapsules_LoadTextmap(void)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < g_rankCapsules_nummapthings; i++)
|
||||
{
|
||||
const char *param, *val;
|
||||
|
||||
M_TokenizerSetEndPos(g_rankCapsules_mapthingsPos[i]);
|
||||
param = M_TokenizerRead(0);
|
||||
|
||||
if (!fastcmp(param, "{"))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
while (true)
|
||||
{
|
||||
param = M_TokenizerRead(0);
|
||||
|
||||
if (fastcmp(param, "}"))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
val = M_TokenizerRead(1);
|
||||
|
||||
if (fastcmp(param, "type"))
|
||||
{
|
||||
UINT16 type = atol(val);
|
||||
|
||||
if (type == mobjinfo[MT_BATTLECAPSULE].doomednum)
|
||||
{
|
||||
g_rankCapsules_count++;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
static void RankCapsules_LoadThingsLump(UINT8 *data)
|
||||
|
||||
Loads binary map data for the result of
|
||||
RankCapsules_CountFromMap.
|
||||
|
||||
Input Arguments:-
|
||||
data - Pointer to a THINGS lump.
|
||||
|
||||
Return:-
|
||||
N/A
|
||||
--------------------------------------------------*/
|
||||
static void RankCapsules_LoadThingsLump(UINT8 *data)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < g_rankCapsules_nummapthings; i++)
|
||||
{
|
||||
UINT16 type = 0;
|
||||
|
||||
data += 2; // x
|
||||
data += 2; // y
|
||||
|
||||
data += 2; // angle
|
||||
type = READUINT16(data); // type
|
||||
type &= 4095;
|
||||
|
||||
data += 2; // options
|
||||
|
||||
if (type == mobjinfo[MT_BATTLECAPSULE].doomednum)
|
||||
{
|
||||
g_rankCapsules_count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
static boolean RankCapsules_LoadMapData(const virtres_t *virt)
|
||||
|
||||
Loads either UDMF or binary map data, for the
|
||||
result of RankCapsules_CountFromMap.
|
||||
|
||||
Input Arguments:-
|
||||
virt - Pointer to the map's virtual resource.
|
||||
|
||||
Return:-
|
||||
true if we could successfully load the map data,
|
||||
otherwise false.
|
||||
--------------------------------------------------*/
|
||||
static boolean RankCapsules_LoadMapData(const virtres_t *virt)
|
||||
{
|
||||
virtlump_t *virtthings = NULL;
|
||||
|
||||
// Count map data.
|
||||
if (g_rankCapsules_udmf) // Count how many entries for each type we got in textmap.
|
||||
{
|
||||
virtlump_t *textmap = vres_Find(virt, "TEXTMAP");
|
||||
M_TokenizerOpen((char *)textmap->data);
|
||||
if (!RankCapsules_TextmapCount(textmap->size))
|
||||
{
|
||||
M_TokenizerClose();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
virtthings = vres_Find(virt, "THINGS");
|
||||
|
||||
if (!virtthings)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Traditional doom map format just assumes the number of elements from the lump sizes.
|
||||
g_rankCapsules_nummapthings = virtthings->size / (5 * sizeof (INT16));
|
||||
}
|
||||
|
||||
// Load map data.
|
||||
if (g_rankCapsules_udmf)
|
||||
{
|
||||
RankCapsules_LoadTextmap();
|
||||
M_TokenizerClose();
|
||||
}
|
||||
else
|
||||
{
|
||||
RankCapsules_LoadThingsLump(virtthings->data);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
static UINT32 RankCapsules_CountFromMap(const virtres_t *virt)
|
||||
|
||||
Counts the number of capsules in a map, without
|
||||
needing to fully load it.
|
||||
|
||||
Input Arguments:-
|
||||
virt - Pointer to the map's virtual resource.
|
||||
|
||||
Return:-
|
||||
Number of MT_BATTLECAPSULE instances found.
|
||||
--------------------------------------------------*/
|
||||
static UINT32 RankCapsules_CountFromMap(const virtres_t *virt)
|
||||
{
|
||||
virtlump_t *textmap = vres_Find(virt, "TEXTMAP");
|
||||
|
||||
g_rankCapsules_udmf = (textmap != NULL);
|
||||
g_rankCapsules_count = 0;
|
||||
|
||||
if (RankCapsules_LoadMapData(virt) == true)
|
||||
{
|
||||
return g_rankCapsules_count;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
void K_InitGrandPrixRank(gpRank_t *rankData)
|
||||
|
||||
See header file for description.
|
||||
--------------------------------------------------*/
|
||||
void K_InitGrandPrixRank(gpRank_t *rankData)
|
||||
{
|
||||
UINT8 numHumans = 0;
|
||||
UINT32 laps = 0;
|
||||
INT32 i;
|
||||
|
||||
memset(rankData, 0, sizeof(gpRank_t));
|
||||
|
||||
if (grandprixinfo.cup == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
if (playeringame[i])
|
||||
{
|
||||
if (numHumans < MAXSPLITSCREENPLAYERS && players[i].spectator == false)
|
||||
{
|
||||
numHumans++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate players
|
||||
rankData->players = numHumans;
|
||||
rankData->totalPlayers = K_GetGPPlayerCount(numHumans);
|
||||
|
||||
// Initialize to the neutral value.
|
||||
rankData->position = RANK_NEUTRAL_POSITION;
|
||||
|
||||
// Calculate total of points
|
||||
// (Should this account for all coop players?)
|
||||
for (i = 0; i < numHumans; i++)
|
||||
{
|
||||
rankData->totalPoints += grandprixinfo.cup->numlevels * K_CalculateGPRankPoints(i + 1, rankData->totalPlayers);
|
||||
}
|
||||
|
||||
rankData->totalRings = grandprixinfo.cup->numlevels * numHumans * 20;
|
||||
|
||||
for (i = 0; i < grandprixinfo.cup->numlevels; i++)
|
||||
{
|
||||
const INT32 cupLevelNum = grandprixinfo.cup->cachedlevels[i];
|
||||
if (cupLevelNum < nummapheaders && mapheaderinfo[cupLevelNum] != NULL)
|
||||
{
|
||||
laps += mapheaderinfo[cupLevelNum]->numlaps;
|
||||
}
|
||||
}
|
||||
|
||||
// +1, since 1st place laps are worth 2 pts.
|
||||
for (i = 0; i < numHumans+1; i++)
|
||||
{
|
||||
rankData->totalLaps += laps;
|
||||
}
|
||||
|
||||
// Search through all of the cup's bonus levels
|
||||
// for an accurate count of how many capsules they have.
|
||||
for (i = 0; i < grandprixinfo.cup->numbonus; i++)
|
||||
{
|
||||
const INT32 cupLevelNum = grandprixinfo.cup->cachedlevels[CUPCACHE_BONUS + i];
|
||||
if (cupLevelNum < nummapheaders && mapheaderinfo[cupLevelNum] != NULL)
|
||||
{
|
||||
lumpnum_t lp = mapheaderinfo[cupLevelNum]->lumpnum;
|
||||
virtres_t *virt = NULL;
|
||||
|
||||
if (lp == LUMPERROR)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
virt = vres_GetMap(lp);
|
||||
if (virt == NULL)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
rankData->totalCapsules += RankCapsules_CountFromMap(virt);
|
||||
vres_Free(virt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
gp_rank_e K_CalculateGPGrade(gpRank_t *rankData)
|
||||
|
||||
See header file for description.
|
||||
--------------------------------------------------*/
|
||||
gp_rank_e K_CalculateGPGrade(gpRank_t *rankData)
|
||||
{
|
||||
static const fixed_t gradePercents[GRADE_A] = {
|
||||
7*FRACUNIT/20, // D: 35% or higher
|
||||
10*FRACUNIT/20, // C: 50% or higher
|
||||
14*FRACUNIT/20, // B: 70% or higher
|
||||
17*FRACUNIT/20 // A: 85% or higher
|
||||
};
|
||||
|
||||
gp_rank_e retGrade = GRADE_E;
|
||||
|
||||
const INT32 positionWeight = 150;
|
||||
const INT32 pointsWeight = 100;
|
||||
const INT32 lapsWeight = 100;
|
||||
const INT32 capsulesWeight = 100;
|
||||
const INT32 ringsWeight = 50;
|
||||
const INT32 total = positionWeight + pointsWeight + lapsWeight + capsulesWeight + ringsWeight;
|
||||
const INT32 continuesPenalty = 20;
|
||||
|
||||
INT32 ours = 0;
|
||||
fixed_t percent = 0;
|
||||
|
||||
if (rankData->position > 0)
|
||||
{
|
||||
const INT32 sc = (rankData->position - 1);
|
||||
const INT32 loser = (RANK_NEUTRAL_POSITION - 1);
|
||||
ours += ((loser - sc) * positionWeight) / loser;
|
||||
}
|
||||
|
||||
if (rankData->totalPoints > 0)
|
||||
{
|
||||
ours += (rankData->winPoints * pointsWeight) / rankData->totalPoints;
|
||||
}
|
||||
|
||||
if (rankData->totalLaps > 0)
|
||||
{
|
||||
ours += (rankData->laps * lapsWeight) / rankData->totalLaps;
|
||||
}
|
||||
|
||||
if (rankData->totalCapsules > 0)
|
||||
{
|
||||
ours += (rankData->capsules * capsulesWeight) / rankData->totalCapsules;
|
||||
}
|
||||
|
||||
if (rankData->totalRings > 0)
|
||||
{
|
||||
ours += (rankData->rings * ringsWeight) / rankData->totalRings;
|
||||
}
|
||||
|
||||
ours -= rankData->continuesUsed * continuesPenalty;
|
||||
|
||||
percent = FixedDiv(ours, total);
|
||||
|
||||
for (retGrade = 0; retGrade < GRADE_A; retGrade++)
|
||||
{
|
||||
if (percent < gradePercents[retGrade])
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (rankData->specialWon == true)
|
||||
{
|
||||
// Winning the Special Stage gives you
|
||||
// a free grade increase.
|
||||
retGrade++;
|
||||
}
|
||||
|
||||
return retGrade;
|
||||
}
|
||||
96
src/k_rank.h
Normal file
96
src/k_rank.h
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
// DR. ROBOTNIK'S RING RACERS
|
||||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) by Sally "TehRealSalt" Cochenour
|
||||
// Copyright (C) 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_rank.h
|
||||
/// \brief Grand Prix mode ranking
|
||||
|
||||
#ifndef __K_RANK__
|
||||
#define __K_RANK__
|
||||
|
||||
#include "doomdef.h"
|
||||
#include "doomstat.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct gpRank_t
|
||||
{
|
||||
UINT8 players;
|
||||
UINT8 totalPlayers;
|
||||
|
||||
UINT8 position;
|
||||
|
||||
UINT32 winPoints;
|
||||
UINT32 totalPoints;
|
||||
|
||||
UINT32 laps;
|
||||
UINT32 totalLaps;
|
||||
|
||||
UINT32 continuesUsed;
|
||||
|
||||
UINT32 capsules;
|
||||
UINT32 totalCapsules;
|
||||
|
||||
UINT32 rings;
|
||||
UINT32 totalRings;
|
||||
|
||||
boolean specialWon;
|
||||
};
|
||||
|
||||
typedef enum
|
||||
{
|
||||
GRADE_E,
|
||||
GRADE_D,
|
||||
GRADE_C,
|
||||
GRADE_B,
|
||||
GRADE_A,
|
||||
GRADE_S
|
||||
} gp_rank_e;
|
||||
|
||||
// 3rd place is neutral, anything below is a penalty
|
||||
#define RANK_NEUTRAL_POSITION (3)
|
||||
|
||||
/*--------------------------------------------------
|
||||
void K_InitGrandPrixRank(gpRank_t *rankData);
|
||||
|
||||
Calculates rank requirements for a GP session.
|
||||
|
||||
Input Arguments:-
|
||||
rankData - Pointer to struct that contains all
|
||||
of the information required to calculate GP rank.
|
||||
|
||||
Return:-
|
||||
N/A
|
||||
--------------------------------------------------*/
|
||||
|
||||
void K_InitGrandPrixRank(gpRank_t *rankData);
|
||||
|
||||
|
||||
/*--------------------------------------------------
|
||||
gp_rank_e K_CalculateGPGrade(gpRank_t *rankData);
|
||||
|
||||
Calculates the player's grade using the
|
||||
variables from gpRank.
|
||||
|
||||
Input Arguments:-
|
||||
rankData - struct containing existing rank data.
|
||||
|
||||
Return:-
|
||||
gp_rank_e representing the total grade.
|
||||
--------------------------------------------------*/
|
||||
|
||||
gp_rank_e K_CalculateGPGrade(gpRank_t *rankData);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
@ -235,6 +235,29 @@ INT32 K_GetWaypointID(waypoint_t *waypoint)
|
|||
return waypointid;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
waypoint_t *K_GetWaypointFromID(INT32 waypointID)
|
||||
|
||||
See header file for description.
|
||||
--------------------------------------------------*/
|
||||
waypoint_t *K_GetWaypointFromID(INT32 waypointID)
|
||||
{
|
||||
waypoint_t *waypoint = NULL;
|
||||
size_t i = SIZE_MAX;
|
||||
|
||||
for (i = 0; i < numwaypoints; i++)
|
||||
{
|
||||
waypoint = &waypointheap[i];
|
||||
|
||||
if (K_GetWaypointID(waypoint) == waypointID)
|
||||
{
|
||||
return waypoint;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
UINT32 K_GetCircuitLength(void)
|
||||
|
||||
|
|
|
|||
|
|
@ -141,9 +141,25 @@ INT32 K_GetWaypointNextID(waypoint_t *waypoint);
|
|||
Return:-
|
||||
The waypoint ID, -1 if there is no waypoint or mobj.
|
||||
--------------------------------------------------*/
|
||||
|
||||
INT32 K_GetWaypointID(waypoint_t *waypoint);
|
||||
|
||||
|
||||
/*--------------------------------------------------
|
||||
waypoint_t *K_GetWaypointFromID(INT32 waypointID)
|
||||
|
||||
Returns the first waypoint with the specified ID.
|
||||
|
||||
Input Arguments:-
|
||||
waypointID - The ID of the waypoint to get
|
||||
|
||||
Return:-
|
||||
The first waypoint with this ID, NULL if the ID doesn't exist at all in the map
|
||||
--------------------------------------------------*/
|
||||
|
||||
waypoint_t *K_GetWaypointFromID(INT32 waypointID);
|
||||
|
||||
|
||||
/*--------------------------------------------------
|
||||
UINT32 K_GetCircuitLength(void)
|
||||
|
||||
|
|
|
|||
|
|
@ -482,12 +482,10 @@ static int player_get(lua_State *L)
|
|||
lua_pushinteger(L, plr->timeshitprev);
|
||||
else if (fastcmp(field,"onconveyor"))
|
||||
lua_pushinteger(L, plr->onconveyor);
|
||||
else if (fastcmp(field,"awayviewmobj"))
|
||||
LUA_PushUserdata(L, plr->awayviewmobj, META_MOBJ);
|
||||
else if (fastcmp(field,"awayviewtics"))
|
||||
lua_pushinteger(L, plr->awayviewtics);
|
||||
else if (fastcmp(field,"awayviewaiming"))
|
||||
lua_pushangle(L, plr->awayviewaiming);
|
||||
else if (fastcmp(field,"awayviewmobj")) // FIXME: struct
|
||||
LUA_PushUserdata(L, plr->awayview.mobj, META_MOBJ);
|
||||
else if (fastcmp(field,"awayviewtics")) // FIXME: struct
|
||||
lua_pushinteger(L, plr->awayview.tics);
|
||||
|
||||
else if (fastcmp(field,"spectator"))
|
||||
lua_pushboolean(L, plr->spectator);
|
||||
|
|
@ -848,21 +846,19 @@ static int player_set(lua_State *L)
|
|||
plr->timeshitprev = (UINT8)luaL_checkinteger(L, 3);
|
||||
else if (fastcmp(field,"onconveyor"))
|
||||
plr->onconveyor = (INT32)luaL_checkinteger(L, 3);
|
||||
else if (fastcmp(field,"awayviewmobj"))
|
||||
else if (fastcmp(field,"awayviewmobj")) // FIXME: struct
|
||||
{
|
||||
mobj_t *mo = NULL;
|
||||
if (!lua_isnil(L, 3))
|
||||
mo = *((mobj_t **)luaL_checkudata(L, 3, META_MOBJ));
|
||||
P_SetTarget(&plr->awayviewmobj, mo);
|
||||
P_SetTarget(&plr->awayview.mobj, mo);
|
||||
}
|
||||
else if (fastcmp(field,"awayviewtics"))
|
||||
else if (fastcmp(field,"awayviewtics")) // FIXME: struct
|
||||
{
|
||||
plr->awayviewtics = (INT32)luaL_checkinteger(L, 3);
|
||||
if (plr->awayviewtics && !plr->awayviewmobj) // awayviewtics must ALWAYS have an awayviewmobj set!!
|
||||
P_SetTarget(&plr->awayviewmobj, plr->mo); // but since the script might set awayviewmobj immediately AFTER setting awayviewtics, use player mobj as filler for now.
|
||||
plr->awayview.tics = (INT32)luaL_checkinteger(L, 3);
|
||||
if (plr->awayview.tics && !plr->awayview.mobj) // awayviewtics must ALWAYS have an awayviewmobj set!!
|
||||
P_SetTarget(&plr->awayview.mobj, plr->mo); // but since the script might set awayviewmobj immediately AFTER setting awayviewtics, use player mobj as filler for now.
|
||||
}
|
||||
else if (fastcmp(field,"awayviewaiming"))
|
||||
plr->awayviewaiming = luaL_checkangle(L, 3);
|
||||
else if (fastcmp(field,"spectator"))
|
||||
plr->spectator = lua_toboolean(L, 3);
|
||||
else if (fastcmp(field,"bot"))
|
||||
|
|
|
|||
|
|
@ -212,7 +212,7 @@ int LUA_PushGlobals(lua_State *L, const char *word)
|
|||
lua_pushstring(L, titlemap);
|
||||
return 1;
|
||||
} else if (fastcmp(word,"titlemapinaction")) {
|
||||
lua_pushboolean(L, (titlemapinaction != TITLEMAP_OFF));
|
||||
lua_pushboolean(L, titlemapinaction);
|
||||
return 1;
|
||||
} else if (fastcmp(word,"bootmap")) {
|
||||
lua_pushstring(L, bootmap);
|
||||
|
|
@ -223,6 +223,9 @@ int LUA_PushGlobals(lua_State *L, const char *word)
|
|||
} else if (fastcmp(word,"tutorialmode")) {
|
||||
lua_pushboolean(L, tutorialmode);
|
||||
return 1;
|
||||
} else if (fastcmp(word,"podiummap")) {
|
||||
lua_pushstring(L, podiummap);
|
||||
return 1;
|
||||
// end map vars
|
||||
// begin CTF colors
|
||||
} else if (fastcmp(word,"skincolor_redteam")) {
|
||||
|
|
|
|||
|
|
@ -139,7 +139,7 @@ void COM_Lua_f(void);
|
|||
// #define HAVE_LUA_SEGS
|
||||
|
||||
#define ISINLEVEL \
|
||||
(gamestate == GS_LEVEL || titlemapinaction)
|
||||
(G_GamestateUsesLevel())
|
||||
|
||||
#define INLEVEL if (! ISINLEVEL)\
|
||||
return luaL_error(L, "This can only be used in a level!");
|
||||
|
|
|
|||
|
|
@ -255,10 +255,7 @@ static void M_DrawRenderStats(void)
|
|||
perfstatcol_t batchcalls_col = {220, 200, V_PURPLEMAP, batchcalls_row};
|
||||
|
||||
|
||||
boolean rendering = (
|
||||
gamestate == GS_LEVEL ||
|
||||
(gamestate == GS_TITLESCREEN && titlemapinaction)
|
||||
);
|
||||
boolean rendering = G_GamestateUsesLevel();
|
||||
|
||||
draw_row = 10;
|
||||
M_DrawPerfTiming(&frametime_col);
|
||||
|
|
@ -619,8 +616,9 @@ void M_DrawPerfStats(void)
|
|||
}
|
||||
else if (cv_perfstats.value == PS_THINKFRAME) // lua thinkframe
|
||||
{
|
||||
if (!(gamestate == GS_LEVEL || (gamestate == GS_TITLESCREEN && titlemapinaction)))
|
||||
if (G_GamestateUsesLevel() == false)
|
||||
return;
|
||||
|
||||
if (vid.width < 640 || vid.height < 400) // low resolution
|
||||
{
|
||||
// it's not gonna fit very well..
|
||||
|
|
|
|||
|
|
@ -4165,8 +4165,8 @@ void A_OverlayThink(mobj_t *actor)
|
|||
{
|
||||
angle_t viewingangle;
|
||||
|
||||
if (players[displayplayers[0]].awayviewtics)
|
||||
viewingangle = R_PointToAngle2(actor->target->x, actor->target->y, players[displayplayers[0]].awayviewmobj->x, players[displayplayers[0]].awayviewmobj->y);
|
||||
if (players[displayplayers[0]].awayview.tics)
|
||||
viewingangle = R_PointToAngle2(actor->target->x, actor->target->y, players[displayplayers[0]].awayview.mobj->x, players[displayplayers[0]].awayview.mobj->y);
|
||||
else if (!camera[0].chase && players[displayplayers[0]].mo)
|
||||
viewingangle = R_PointToAngle2(actor->target->x, actor->target->y, players[displayplayers[0]].mo->x, players[displayplayers[0]].mo->y);
|
||||
else
|
||||
|
|
@ -9390,6 +9390,10 @@ void A_SetScale(mobj_t *actor)
|
|||
}
|
||||
|
||||
locvar1 = FixedMul(locvar1, mapobjectscale); // SRB2Kart
|
||||
if (target->spawnpoint != NULL)
|
||||
{
|
||||
locvar1 = FixedMul(locvar1, target->spawnpoint->scale);
|
||||
}
|
||||
|
||||
target->destscale = locvar1; // destination scale
|
||||
if (!(locvar2 & 65535))
|
||||
|
|
|
|||
|
|
@ -197,6 +197,8 @@ void P_HaltPlayerOrbit(player_t *player);
|
|||
void P_ExitPlayerOrbit(player_t *player);
|
||||
boolean P_PlayerOrbit(player_t *player);
|
||||
|
||||
void P_TickAltView(altview_t *view);
|
||||
|
||||
void P_MovePlayer(player_t *player);
|
||||
void P_PlayerThink(player_t *player);
|
||||
void P_PlayerAfterThink(player_t *player);
|
||||
|
|
|
|||
119
src/p_mobj.c
119
src/p_mobj.c
|
|
@ -47,6 +47,8 @@
|
|||
#include "k_objects.h"
|
||||
#include "k_grandprix.h"
|
||||
#include "k_director.h"
|
||||
#include "m_easing.h"
|
||||
#include "k_podium.h"
|
||||
|
||||
static CV_PossibleValue_t CV_BobSpeed[] = {{0, "MIN"}, {4*FRACUNIT, "MAX"}, {0, NULL}};
|
||||
consvar_t cv_movebob = CVAR_INIT ("movebob", "1.0", CV_FLOAT|CV_SAVE, CV_BobSpeed, NULL);
|
||||
|
|
@ -3779,15 +3781,16 @@ void P_CalcChasePostImg(player_t *player, camera_t *thiscam)
|
|||
{
|
||||
postimg = postimg_mirror;
|
||||
}
|
||||
else if (player->awayviewtics && player->awayviewmobj && !P_MobjWasRemoved(player->awayviewmobj)) // Camera must obviously exist
|
||||
else if (player->awayview.tics && player->awayview.mobj && !P_MobjWasRemoved(player->awayview.mobj)) // Camera must obviously exist
|
||||
{
|
||||
camera_t dummycam;
|
||||
dummycam.subsector = player->awayviewmobj->subsector;
|
||||
dummycam.x = player->awayviewmobj->x;
|
||||
dummycam.y = player->awayviewmobj->y;
|
||||
dummycam.z = player->awayviewmobj->z;
|
||||
//dummycam.height = 40*FRACUNIT; // alt view height is 20*FRACUNIT
|
||||
dummycam.height = 0; // Why? Remote viewpoint cameras have no height.
|
||||
|
||||
dummycam.subsector = player->awayview.mobj->subsector;
|
||||
dummycam.x = player->awayview.mobj->x;
|
||||
dummycam.y = player->awayview.mobj->y;
|
||||
dummycam.z = player->awayview.mobj->z;
|
||||
dummycam.height = 0;
|
||||
|
||||
// Are we in water?
|
||||
if (P_CameraCheckWater(&dummycam))
|
||||
postimg = postimg_water;
|
||||
|
|
@ -8088,8 +8091,8 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
|
|||
angle_t viewingangle;
|
||||
statenum_t curstate = ((mobj->tics == 1) ? (mobj->state->nextstate) : ((statenum_t)(mobj->state-states)));
|
||||
|
||||
if (players[displayplayers[0]].awayviewtics)
|
||||
viewingangle = R_PointToAngle2(mobj->target->x, mobj->target->y, players[displayplayers[0]].awayviewmobj->x, players[displayplayers[0]].awayviewmobj->y);
|
||||
if (players[displayplayers[0]].awayview.tics)
|
||||
viewingangle = R_PointToAngle2(mobj->target->x, mobj->target->y, players[displayplayers[0]].awayview.mobj->x, players[displayplayers[0]].awayview.mobj->y);
|
||||
else if (!camera[0].chase && players[displayplayers[0]].mo)
|
||||
viewingangle = R_PointToAngle2(mobj->target->x, mobj->target->y, players[displayplayers[0]].mo->x, players[displayplayers[0]].mo->y);
|
||||
else
|
||||
|
|
@ -8219,8 +8222,8 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
|
|||
{
|
||||
angle_t viewingangle;
|
||||
|
||||
if (players[displayplayers[0]].awayviewtics)
|
||||
viewingangle = R_PointToAngle2(mobj->target->x, mobj->target->y, players[displayplayers[0]].awayviewmobj->x, players[displayplayers[0]].awayviewmobj->y);
|
||||
if (players[displayplayers[0]].awayview.tics)
|
||||
viewingangle = R_PointToAngle2(mobj->target->x, mobj->target->y, players[displayplayers[0]].awayview.mobj->x, players[displayplayers[0]].awayview.mobj->y);
|
||||
else if (!camera[0].chase && players[displayplayers[0]].mo)
|
||||
viewingangle = R_PointToAngle2(mobj->target->x, mobj->target->y, players[displayplayers[0]].mo->x, players[displayplayers[0]].mo->y);
|
||||
else
|
||||
|
|
@ -8324,8 +8327,8 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
|
|||
{
|
||||
angle_t viewingangle;
|
||||
|
||||
if (players[displayplayers[0]].awayviewtics)
|
||||
viewingangle = R_PointToAngle2(mobj->target->x, mobj->target->y, players[displayplayers[0]].awayviewmobj->x, players[displayplayers[0]].awayviewmobj->y);
|
||||
if (players[displayplayers[0]].awayview.tics)
|
||||
viewingangle = R_PointToAngle2(mobj->target->x, mobj->target->y, players[displayplayers[0]].awayview.mobj->x, players[displayplayers[0]].awayview.mobj->y);
|
||||
else if (!camera[0].chase && players[displayplayers[0]].mo)
|
||||
viewingangle = R_PointToAngle2(mobj->target->x, mobj->target->y, players[displayplayers[0]].mo->x, players[displayplayers[0]].mo->y);
|
||||
else
|
||||
|
|
@ -9487,6 +9490,66 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
|
|||
case MT_MONITOR_PART:
|
||||
Obj_MonitorPartThink(mobj);
|
||||
break;
|
||||
case MT_ALTVIEWMAN:
|
||||
{
|
||||
mobj->momx = mobj->momy = mobj->momz = 0;
|
||||
|
||||
if (mobj->movefactor <= 0)
|
||||
{
|
||||
mobj->movefactor = FRACUNIT / TICRATE; // default speed
|
||||
}
|
||||
|
||||
if (mobj->tracer != NULL && P_MobjWasRemoved(mobj->tracer) == false)
|
||||
{
|
||||
fixed_t newX = Easing_Linear(mobj->movecount, mobj->extravalue1, mobj->tracer->x);
|
||||
fixed_t newY = Easing_Linear(mobj->movecount, mobj->extravalue2, mobj->tracer->y);
|
||||
fixed_t newZ = Easing_Linear(mobj->movecount, mobj->cusval, mobj->tracer->z);
|
||||
|
||||
mobj->angle = Easing_Linear(mobj->movecount, mobj->movedir, mobj->tracer->angle);
|
||||
mobj->pitch = Easing_Linear(mobj->movecount, mobj->lastlook, mobj->tracer->pitch);
|
||||
|
||||
mobj->momx = newX - mobj->x;
|
||||
mobj->momy = newY - mobj->y;
|
||||
mobj->momz = newZ - mobj->z;
|
||||
|
||||
mobj->movecount += mobj->movefactor;
|
||||
|
||||
if (mobj->movecount >= FRACUNIT)
|
||||
{
|
||||
mobj->movecount = mobj->movecount % FRACUNIT; // time
|
||||
|
||||
mobj->movedir = mobj->tracer->angle; // start angle
|
||||
mobj->lastlook = mobj->tracer->pitch; // start pitch
|
||||
mobj->extravalue1 = mobj->tracer->x; // start x
|
||||
mobj->extravalue2 = mobj->tracer->y; // start y
|
||||
mobj->cusval = mobj->tracer->z; // start z
|
||||
|
||||
P_SetTarget(&mobj->tracer, P_GetNextTubeWaypoint(mobj->tracer, false));
|
||||
}
|
||||
}
|
||||
|
||||
// If target is valid, then we'll focus on it.
|
||||
if (mobj->target != NULL && P_MobjWasRemoved(mobj->target) == false)
|
||||
{
|
||||
mobj->angle = R_PointToAngle2(
|
||||
mobj->x,
|
||||
mobj->y,
|
||||
mobj->target->x,
|
||||
mobj->target->y
|
||||
);
|
||||
|
||||
mobj->pitch = R_PointToAngle2(
|
||||
0,
|
||||
mobj->z,
|
||||
R_PointToDist2(
|
||||
mobj->x, mobj->y,
|
||||
mobj->target->x, mobj->target->y
|
||||
),
|
||||
mobj->target->z + (mobj->target->height >> 1)
|
||||
);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// check mobj against possible water content, before movement code
|
||||
P_MobjCheckWater(mobj);
|
||||
|
|
@ -10464,9 +10527,6 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type)
|
|||
else
|
||||
switch (mobj->type)
|
||||
{
|
||||
case MT_ALTVIEWMAN:
|
||||
if (titlemapinaction) mobj->flags &= ~MF_NOTHINK;
|
||||
break;
|
||||
case MT_LOCKONINF:
|
||||
P_SetScale(mobj, (mobj->destscale = 3*mobj->scale));
|
||||
break;
|
||||
|
|
@ -11661,7 +11721,9 @@ void P_SpawnPlayer(INT32 playernum)
|
|||
mobj_t *mobj;
|
||||
|
||||
if (p->playerstate == PST_REBORN)
|
||||
G_PlayerReborn(playernum, false);
|
||||
{
|
||||
G_PlayerReborn(playernum, (p->jointime <= 1));
|
||||
}
|
||||
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
|
|
@ -11686,7 +11748,8 @@ void P_SpawnPlayer(INT32 playernum)
|
|||
}
|
||||
else if (p->bot)
|
||||
{
|
||||
if (grandprixinfo.gp == true && grandprixinfo.eventmode != GPEVENT_NONE)
|
||||
if (K_PodiumSequence() == false
|
||||
&& (!(gametyperules & GTR_BOTS) || (grandprixinfo.gp == true && grandprixinfo.eventmode != GPEVENT_NONE)))
|
||||
{
|
||||
// Bots aren't supposed to be here.
|
||||
p->spectator = true;
|
||||
|
|
@ -11750,7 +11813,7 @@ void P_SpawnPlayer(INT32 playernum)
|
|||
p->skincolor = skincolor_blueteam;
|
||||
}
|
||||
|
||||
if (leveltime > introtime)
|
||||
if (leveltime > introtime && K_PodiumSequence() == false)
|
||||
p->flashing = K_GetKartFlashing(p); // Babysitting deterrent
|
||||
|
||||
mobj = P_SpawnMobj(0, 0, 0, MT_PLAYER);
|
||||
|
|
@ -11895,6 +11958,11 @@ void P_AfterPlayerSpawn(INT32 playernum)
|
|||
|
||||
if (CheckForReverseGravity)
|
||||
P_CheckGravity(mobj, false);
|
||||
|
||||
if (K_PodiumSequence() == true)
|
||||
{
|
||||
K_InitializePodiumWaypoint(p);
|
||||
}
|
||||
}
|
||||
|
||||
// spawn it at a playerspawn mapthing
|
||||
|
|
@ -11977,7 +12045,7 @@ void P_MovePlayerToSpawn(INT32 playernum, mapthing_t *mthing)
|
|||
mobj->angle = angle;
|
||||
|
||||
// FAULT
|
||||
if (leveltime > introtime && !p->spectator)
|
||||
if (gamestate == GS_LEVEL && leveltime > introtime && !p->spectator)
|
||||
{
|
||||
K_DoIngameRespawn(p);
|
||||
}
|
||||
|
|
@ -12055,6 +12123,7 @@ void P_MovePlayerToStarpost(INT32 playernum)
|
|||
|
||||
fixed_t P_GetMobjSpawnHeight(const mobjtype_t mobjtype, const fixed_t x, const fixed_t y, const fixed_t dz, const fixed_t offset, const boolean flip, const fixed_t scale)
|
||||
{
|
||||
const fixed_t finalScale = FixedMul(scale, mapobjectscale);
|
||||
const subsector_t *ss = R_PointInSubsector(x, y);
|
||||
|
||||
// Axis objects snap to the floor.
|
||||
|
|
@ -12063,9 +12132,9 @@ fixed_t P_GetMobjSpawnHeight(const mobjtype_t mobjtype, const fixed_t x, const f
|
|||
|
||||
// Establish height.
|
||||
if (flip)
|
||||
return P_GetSectorCeilingZAt(ss->sector, x, y) - dz - FixedMul(scale, offset + mobjinfo[mobjtype].height);
|
||||
return P_GetSectorCeilingZAt(ss->sector, x, y) - dz - FixedMul(finalScale, offset + mobjinfo[mobjtype].height);
|
||||
else
|
||||
return P_GetSectorFloorZAt(ss->sector, x, y) + dz + FixedMul(scale, offset);
|
||||
return P_GetSectorFloorZAt(ss->sector, x, y) + dz + FixedMul(finalScale, offset);
|
||||
}
|
||||
|
||||
fixed_t P_GetMapThingSpawnHeight(const mobjtype_t mobjtype, const mapthing_t* mthing, const fixed_t x, const fixed_t y)
|
||||
|
|
@ -13364,16 +13433,14 @@ static boolean P_SetupSpawnedMapThing(mapthing_t *mthing, mobj_t *mobj, boolean
|
|||
|
||||
static mobj_t *P_SpawnMobjFromMapThing(mapthing_t *mthing, fixed_t x, fixed_t y, fixed_t z, mobjtype_t i)
|
||||
{
|
||||
fixed_t relativise = FixedDiv(mthing->scale, mapobjectscale);
|
||||
|
||||
mobj_t *mobj = NULL;
|
||||
boolean doangle = true;
|
||||
|
||||
mobj = P_SpawnMobj(x, y, z, i);
|
||||
mobj->spawnpoint = mthing;
|
||||
|
||||
P_SetScale(mobj, FixedMul(mobj->scale, relativise));
|
||||
mobj->destscale = FixedMul(mobj->destscale, relativise);
|
||||
P_SetScale(mobj, FixedMul(mobj->scale, mthing->scale));
|
||||
mobj->destscale = FixedMul(mobj->destscale, mthing->scale);
|
||||
|
||||
if (!P_SetupSpawnedMapThing(mthing, mobj, &doangle))
|
||||
return mobj;
|
||||
|
|
|
|||
|
|
@ -137,8 +137,7 @@ static void P_NetArchivePlayers(savebuffer_t *save)
|
|||
WRITEANGLE(save->p, players[i].drawangle);
|
||||
WRITEANGLE(save->p, players[i].viewrollangle);
|
||||
WRITEANGLE(save->p, players[i].tilt);
|
||||
WRITEANGLE(save->p, players[i].awayviewaiming);
|
||||
WRITEINT32(save->p, players[i].awayviewtics);
|
||||
WRITEINT32(save->p, players[i].awayview.tics);
|
||||
|
||||
WRITEUINT8(save->p, players[i].playerstate);
|
||||
WRITEUINT32(save->p, players[i].pflags);
|
||||
|
|
@ -179,6 +178,7 @@ static void P_NetArchivePlayers(savebuffer_t *save)
|
|||
WRITEUINT32(save->p, players[i].realtime);
|
||||
WRITEUINT8(save->p, players[i].laps);
|
||||
WRITEUINT8(save->p, players[i].latestlap);
|
||||
WRITEUINT32(save->p, players[i].lapPoints);
|
||||
WRITEINT32(save->p, players[i].starpostnum);
|
||||
|
||||
WRITEUINT8(save->p, players[i].ctfteam);
|
||||
|
|
@ -197,7 +197,7 @@ static void P_NetArchivePlayers(savebuffer_t *save)
|
|||
|
||||
WRITEUINT8(save->p, players[i].splitscreenindex);
|
||||
|
||||
if (players[i].awayviewmobj)
|
||||
if (players[i].awayview.mobj)
|
||||
flags |= AWAYVIEW;
|
||||
|
||||
if (players[i].followmobj)
|
||||
|
|
@ -227,7 +227,7 @@ static void P_NetArchivePlayers(savebuffer_t *save)
|
|||
WRITEUINT32(save->p, players[i].skybox.centerpoint->mobjnum);
|
||||
|
||||
if (flags & AWAYVIEW)
|
||||
WRITEUINT32(save->p, players[i].awayviewmobj->mobjnum);
|
||||
WRITEUINT32(save->p, players[i].awayview.mobj->mobjnum);
|
||||
|
||||
if (flags & FOLLOWITEM)
|
||||
WRITEUINT32(save->p, players[i].followmobj->mobjnum);
|
||||
|
|
@ -527,8 +527,7 @@ static void P_NetUnArchivePlayers(savebuffer_t *save)
|
|||
players[i].drawangle = players[i].old_drawangle = READANGLE(save->p);
|
||||
players[i].viewrollangle = READANGLE(save->p);
|
||||
players[i].tilt = READANGLE(save->p);
|
||||
players[i].awayviewaiming = READANGLE(save->p);
|
||||
players[i].awayviewtics = READINT32(save->p);
|
||||
players[i].awayview.tics = READINT32(save->p);
|
||||
|
||||
players[i].playerstate = READUINT8(save->p);
|
||||
players[i].pflags = READUINT32(save->p);
|
||||
|
|
@ -569,6 +568,7 @@ static void P_NetUnArchivePlayers(savebuffer_t *save)
|
|||
players[i].realtime = READUINT32(save->p); // integer replacement for leveltime
|
||||
players[i].laps = READUINT8(save->p); // Number of laps (optional)
|
||||
players[i].latestlap = READUINT8(save->p);
|
||||
players[i].lapPoints = READUINT32(save->p);
|
||||
players[i].starpostnum = READINT32(save->p);
|
||||
|
||||
players[i].ctfteam = READUINT8(save->p); // 1 == Red, 2 == Blue
|
||||
|
|
@ -596,7 +596,7 @@ static void P_NetUnArchivePlayers(savebuffer_t *save)
|
|||
players[i].skybox.centerpoint = (mobj_t *)(size_t)READUINT32(save->p);
|
||||
|
||||
if (flags & AWAYVIEW)
|
||||
players[i].awayviewmobj = (mobj_t *)(size_t)READUINT32(save->p);
|
||||
players[i].awayview.mobj = (mobj_t *)(size_t)READUINT32(save->p);
|
||||
|
||||
if (flags & FOLLOWITEM)
|
||||
players[i].followmobj = (mobj_t *)(size_t)READUINT32(save->p);
|
||||
|
|
@ -4684,12 +4684,12 @@ static void P_RelinkPointers(void)
|
|||
if (!P_SetTarget(&players[i].skybox.centerpoint, P_FindNewPosition(temp)))
|
||||
CONS_Debug(DBG_GAMELOGIC, "skybox.centerpoint not found on player %d\n", i);
|
||||
}
|
||||
if (players[i].awayviewmobj)
|
||||
if (players[i].awayview.mobj)
|
||||
{
|
||||
temp = (UINT32)(size_t)players[i].awayviewmobj;
|
||||
players[i].awayviewmobj = NULL;
|
||||
if (!P_SetTarget(&players[i].awayviewmobj, P_FindNewPosition(temp)))
|
||||
CONS_Debug(DBG_GAMELOGIC, "awayviewmobj not found on player %d\n", i);
|
||||
temp = (UINT32)(size_t)players[i].awayview.mobj;
|
||||
players[i].awayview.mobj = NULL;
|
||||
if (!P_SetTarget(&players[i].awayview.mobj, P_FindNewPosition(temp)))
|
||||
CONS_Debug(DBG_GAMELOGIC, "awayview.mobj not found on player %d\n", i);
|
||||
}
|
||||
if (players[i].followmobj)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -101,6 +101,8 @@
|
|||
#include "k_specialstage.h"
|
||||
#include "acs/interface.h"
|
||||
#include "doomstat.h" // MAXMUSNAMES
|
||||
#include "k_podium.h"
|
||||
#include "k_rank.h"
|
||||
|
||||
// Replay names have time
|
||||
#if !defined (UNDER_CE)
|
||||
|
|
@ -1278,7 +1280,7 @@ static void P_LoadThings(UINT8 *data)
|
|||
mt->options = READUINT16(data);
|
||||
mt->extrainfo = (UINT8)(mt->type >> 12);
|
||||
Tag_FSet(&mt->tags, 0);
|
||||
mt->scale = mapobjectscale;
|
||||
mt->scale = FRACUNIT;
|
||||
memset(mt->args, 0, NUMMAPTHINGARGS*sizeof(*mt->args));
|
||||
memset(mt->stringargs, 0x00, NUMMAPTHINGSTRINGARGS*sizeof(*mt->stringargs));
|
||||
mt->special = 0;
|
||||
|
|
@ -1783,7 +1785,7 @@ static void ParseTextmapThingParameter(UINT32 i, const char *param, const char *
|
|||
else if (fastcmp(param, "type"))
|
||||
mapthings[i].type = atol(val);
|
||||
else if (fastcmp(param, "scale") || fastcmp(param, "scalex") || fastcmp(param, "scaley"))
|
||||
mapthings[i].scale = FixedMul(mapobjectscale, FLOAT_TO_FIXED(atof(val)));
|
||||
mapthings[i].scale = FLOAT_TO_FIXED(atof(val));
|
||||
// Flags
|
||||
else if (fastcmp(param, "flip") && fastcmp("true", val))
|
||||
mapthings[i].options |= MTF_OBJECTFLIP;
|
||||
|
|
@ -2731,7 +2733,7 @@ static void P_LoadTextmap(void)
|
|||
mt->z = 0;
|
||||
mt->extrainfo = 0;
|
||||
Tag_FSet(&mt->tags, 0);
|
||||
mt->scale = mapobjectscale;
|
||||
mt->scale = FRACUNIT;
|
||||
memset(mt->args, 0, NUMMAPTHINGARGS*sizeof(*mt->args));
|
||||
memset(mt->stringargs, 0x00, NUMMAPTHINGSTRINGARGS*sizeof(*mt->stringargs));
|
||||
mt->special = 0;
|
||||
|
|
@ -7083,7 +7085,11 @@ static void P_InitLevelSettings(void)
|
|||
gamespeed = KARTSPEED_EASY;
|
||||
franticitems = false;
|
||||
|
||||
if (grandprixinfo.gp == true)
|
||||
if (K_PodiumSequence() == true)
|
||||
{
|
||||
; // NOP
|
||||
}
|
||||
else if (grandprixinfo.gp == true)
|
||||
{
|
||||
if (gametyperules & GTR_CIRCUIT)
|
||||
{
|
||||
|
|
@ -7359,7 +7365,7 @@ static void P_InitPlayers(void)
|
|||
|
||||
players[i].mo = NULL;
|
||||
|
||||
if (!(gametyperules & GTR_CIRCUIT))
|
||||
if (!(gametyperules & GTR_CIRCUIT) && K_PodiumSequence() == false)
|
||||
{
|
||||
G_DoReborn(i);
|
||||
}
|
||||
|
|
@ -7368,6 +7374,8 @@ static void P_InitPlayers(void)
|
|||
G_SpawnPlayer(i);
|
||||
}
|
||||
}
|
||||
|
||||
K_UpdateAllPlayerPositions();
|
||||
}
|
||||
|
||||
static void P_InitGametype(void)
|
||||
|
|
@ -7377,6 +7385,26 @@ static void P_InitGametype(void)
|
|||
spectateGriefed = 0;
|
||||
K_CashInPowerLevels(); // Pushes power level changes even if intermission was skipped
|
||||
|
||||
if (grandprixinfo.gp == true)
|
||||
{
|
||||
if (grandprixinfo.initalize == true)
|
||||
{
|
||||
K_InitGrandPrixRank(&grandprixinfo.rank);
|
||||
K_InitGrandPrixBots();
|
||||
grandprixinfo.initalize = false;
|
||||
}
|
||||
else if (grandprixinfo.wonround == true)
|
||||
{
|
||||
K_UpdateGrandPrixBots();
|
||||
grandprixinfo.wonround = false;
|
||||
}
|
||||
}
|
||||
else if (!modeattacking)
|
||||
{
|
||||
// We're in a Match Race, use simplistic randomized bots.
|
||||
K_UpdateMatchRaceBots();
|
||||
}
|
||||
|
||||
P_InitPlayers();
|
||||
|
||||
if (modeattacking && !demo.playback)
|
||||
|
|
@ -7419,7 +7447,7 @@ static void P_InitGametype(void)
|
|||
|
||||
// Start recording replay in multiplayer with a temp filename
|
||||
//@TODO I'd like to fix dedis crashing when recording replays for the future too...
|
||||
if (!demo.playback && multiplayer && !dedicated)
|
||||
if (gamestate == GS_LEVEL && !demo.playback && multiplayer && !dedicated)
|
||||
{
|
||||
char buf[MAX_WADPATH];
|
||||
char ver[128];
|
||||
|
|
@ -7697,7 +7725,7 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate)
|
|||
|
||||
// Fade out music here. Deduct 2 tics so the fade volume actually reaches 0.
|
||||
// But don't halt the music! S_Start will take care of that. This dodges a MIDI crash bug.
|
||||
if (!(reloadinggamestate || titlemapinaction))
|
||||
if (!(reloadinggamestate || gamestate != GS_LEVEL))
|
||||
S_FadeMusic(0, FixedMul(
|
||||
FixedDiv((F_GetWipeLength(wipedefs[wipe_level_toblack])-2)*NEWTICRATERATIO, NEWTICRATE), MUSICRATE));
|
||||
|
||||
|
|
@ -7705,7 +7733,7 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate)
|
|||
if (rendermode != render_none)
|
||||
V_ReloadPalette(); // Set the level palette
|
||||
|
||||
if (!(reloadinggamestate || titlemapinaction))
|
||||
if (!(reloadinggamestate || gamestate != GS_LEVEL))
|
||||
{
|
||||
if (ranspecialwipe == 2)
|
||||
{
|
||||
|
|
@ -7745,8 +7773,11 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate)
|
|||
|
||||
F_RunWipe(wipetype, wipedefs[wipetype], false, ((levelfadecol == 0) ? "FADEMAP1" : "FADEMAP0"), false, false);
|
||||
}
|
||||
/*if (!titlemapinaction)
|
||||
wipegamestate = GS_LEVEL;*/
|
||||
|
||||
/*
|
||||
if (!titlemapinaction)
|
||||
wipegamestate = GS_LEVEL;
|
||||
*/
|
||||
|
||||
// Close text prompt before freeing the old level
|
||||
F_EndTextPrompt(false, true);
|
||||
|
|
@ -7948,7 +7979,7 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate)
|
|||
P_MapEnd(); // tm.thing is no longer needed from this point onwards
|
||||
|
||||
// Took me 3 hours to figure out why my progression kept on getting overwritten with the titlemap...
|
||||
if (!titlemapinaction)
|
||||
if (gamestate == GS_LEVEL)
|
||||
{
|
||||
if (!lastmaploaded) // Start a new game?
|
||||
{
|
||||
|
|
@ -7961,27 +7992,6 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate)
|
|||
lastmaploaded = gamemap; // HAS to be set after saving!!
|
||||
}
|
||||
|
||||
if (reloadinggamestate)
|
||||
;
|
||||
else if (grandprixinfo.gp == true)
|
||||
{
|
||||
if (grandprixinfo.initalize == true)
|
||||
{
|
||||
K_InitGrandPrixBots();
|
||||
grandprixinfo.initalize = false;
|
||||
}
|
||||
else if (grandprixinfo.wonround == true)
|
||||
{
|
||||
K_UpdateGrandPrixBots();
|
||||
grandprixinfo.wonround = false;
|
||||
}
|
||||
}
|
||||
else if (!modeattacking)
|
||||
{
|
||||
// We're in a Match Race, use simplistic randomized bots.
|
||||
K_UpdateMatchRaceBots();
|
||||
}
|
||||
|
||||
if (!fromnetsave) // uglier hack
|
||||
{ // to make a newly loaded level start on the second frame.
|
||||
INT32 buf = gametic % BACKUPTICS;
|
||||
|
|
|
|||
210
src/p_spec.c
210
src/p_spec.c
|
|
@ -2007,6 +2007,40 @@ static void K_HandleLapIncrement(player_t *player)
|
|||
}
|
||||
}
|
||||
|
||||
if (player->laps > player->latestlap)
|
||||
{
|
||||
if (player->laps > 1)
|
||||
{
|
||||
// save best lap for record attack
|
||||
if (modeattacking && player == &players[consoleplayer])
|
||||
{
|
||||
if (curlap < bestlap || bestlap == 0)
|
||||
{
|
||||
bestlap = curlap;
|
||||
}
|
||||
|
||||
curlap = 0;
|
||||
}
|
||||
|
||||
// Update power levels for this lap.
|
||||
K_UpdatePowerLevels(player, player->laps, false);
|
||||
|
||||
if (nump > 1 && K_IsPlayerLosing(player) == false)
|
||||
{
|
||||
if (nump > 2 && player->position == 1) // 1st place in 1v1 uses thumbs up
|
||||
{
|
||||
player->lapPoints += 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
player->lapPoints++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
player->latestlap = player->laps;
|
||||
}
|
||||
|
||||
// finished race exit setup
|
||||
if (player->laps > numlaps)
|
||||
{
|
||||
|
|
@ -2034,32 +2068,8 @@ static void K_HandleLapIncrement(player_t *player)
|
|||
SetRandomFakePlayerSkin(player, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (player->laps > player->latestlap)
|
||||
{
|
||||
if (player->laps > 1)
|
||||
{
|
||||
// save best lap for record attack
|
||||
if (modeattacking && player == &players[consoleplayer])
|
||||
{
|
||||
if (curlap < bestlap || bestlap == 0)
|
||||
{
|
||||
bestlap = curlap;
|
||||
}
|
||||
|
||||
curlap = 0;
|
||||
}
|
||||
|
||||
// Update power levels for this lap.
|
||||
K_UpdatePowerLevels(player, player->laps, false);
|
||||
}
|
||||
|
||||
player->latestlap = player->laps;
|
||||
}
|
||||
|
||||
thwompsactive = true; // Lap 2 effects
|
||||
|
||||
lowestLap = P_FindLowestLap();
|
||||
|
||||
for (i = 0; i < numlines; i++)
|
||||
|
|
@ -2412,7 +2422,7 @@ static void P_SwitchSkybox(INT32 args, player_t *player, skybox_t *skybox)
|
|||
}
|
||||
}
|
||||
|
||||
static mobj_t* P_FindObjectTypeFromTag(mobjtype_t type, mtag_t tag)
|
||||
mobj_t* P_FindObjectTypeFromTag(mobjtype_t type, mtag_t tag)
|
||||
{
|
||||
if (udmf)
|
||||
{
|
||||
|
|
@ -3001,35 +3011,139 @@ boolean P_ProcessSpecial(activator_t *activator, INT16 special, INT32 *args, cha
|
|||
|
||||
case 422: // Cut away to another view
|
||||
{
|
||||
mobj_t *altview;
|
||||
INT32 aim;
|
||||
altview_t *modifyView = NULL;
|
||||
mobj_t *newViewMobj = NULL;
|
||||
|
||||
if ((!mo || !mo->player) && !titlemapinaction) // only players have views, and title screens
|
||||
return false;
|
||||
|
||||
altview = P_FindObjectTypeFromTag(MT_ALTVIEWMAN, args[0]);
|
||||
if (!altview || !altview->spawnpoint)
|
||||
return false;
|
||||
|
||||
// If titlemap, set the camera ref for title's thinker
|
||||
// This is not revoked until overwritten; awayviewtics is ignored
|
||||
if (titlemapinaction)
|
||||
titlemapcameraref = altview;
|
||||
if (gamestate != GS_LEVEL)
|
||||
{
|
||||
modifyView = &titlemapcam;
|
||||
}
|
||||
else if (mo != NULL && mo->player != NULL)
|
||||
{
|
||||
modifyView = &mo->player->awayview;
|
||||
}
|
||||
else
|
||||
{
|
||||
P_SetTarget(&mo->player->awayviewmobj, altview);
|
||||
mo->player->awayviewtics = args[1];
|
||||
return false;
|
||||
}
|
||||
|
||||
aim = (backwardsCompat) ? args[2] : altview->spawnpoint->pitch;
|
||||
aim = (aim + 360) % 360;
|
||||
aim *= (ANGLE_90>>8);
|
||||
aim /= 90;
|
||||
aim <<= 8;
|
||||
if (titlemapinaction)
|
||||
titlemapcameraref->cusval = (angle_t)aim;
|
||||
newViewMobj = P_FindObjectTypeFromTag(MT_ALTVIEWMAN, args[0]);
|
||||
if (newViewMobj == NULL || newViewMobj->spawnpoint == NULL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
P_SetTarget(&modifyView->mobj, newViewMobj);
|
||||
|
||||
if (gamestate != GS_LEVEL)
|
||||
{
|
||||
// If titlemap, awayview.tics is ignored
|
||||
modifyView->tics = -1;
|
||||
}
|
||||
else
|
||||
mo->player->awayviewaiming = (angle_t)aim;
|
||||
{
|
||||
modifyView->tics = args[1];
|
||||
}
|
||||
|
||||
if (args[2] != 0)
|
||||
{
|
||||
switch (args[2])
|
||||
{
|
||||
case TMCAM_FIRST:
|
||||
case TMCAM_SECOND:
|
||||
case TMCAM_THIRD:
|
||||
{
|
||||
mobj_t *firstPlace = NULL;
|
||||
INT32 i;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if (player->position == abs(args[2])) // a bit of a hack
|
||||
{
|
||||
firstPlace = player->mo;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
P_SetTarget(
|
||||
&newViewMobj->target,
|
||||
firstPlace
|
||||
);
|
||||
break;
|
||||
}
|
||||
case TMCAM_CONSOLE:
|
||||
{
|
||||
mobj_t *consoleMo = NULL;
|
||||
if (playeringame[consoleplayer] == true)
|
||||
{
|
||||
consoleMo = players[consoleplayer].mo;
|
||||
}
|
||||
|
||||
P_SetTarget(
|
||||
&newViewMobj->target,
|
||||
consoleMo
|
||||
);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
P_SetTarget(
|
||||
&newViewMobj->target,
|
||||
P_FindMobjFromTID(args[2], NULL, NULL)
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
P_SetTarget(&newViewMobj->target, NULL);
|
||||
}
|
||||
|
||||
if (args[3] > 0 && args[3] <= NUMTUBEWAYPOINTSEQUENCES)
|
||||
{
|
||||
P_SetTarget(
|
||||
&newViewMobj->tracer,
|
||||
P_GetFirstTubeWaypoint(args[3] - 1)
|
||||
);
|
||||
newViewMobj->movecount = 0; // time
|
||||
newViewMobj->movedir = newViewMobj->angle; // start angle
|
||||
newViewMobj->lastlook = newViewMobj->pitch; // start pitch
|
||||
newViewMobj->extravalue1 = newViewMobj->x; // start x
|
||||
newViewMobj->extravalue2 = newViewMobj->y; // start y
|
||||
newViewMobj->cusval = newViewMobj->z; // start z
|
||||
|
||||
if (args[4] > 0)
|
||||
{
|
||||
newViewMobj->movefactor = FRACUNIT / args[4];
|
||||
}
|
||||
else
|
||||
{
|
||||
newViewMobj->movefactor = FRACUNIT / TICRATE; // default speed
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
P_SetTarget(&newViewMobj->tracer, NULL);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
|
|||
10
src/p_spec.h
10
src/p_spec.h
|
|
@ -519,6 +519,14 @@ typedef enum
|
|||
TMLOOP_BETA = 1,
|
||||
} textmaploopendpointtype_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
TMCAM_FIRST = -1,
|
||||
TMCAM_SECOND = -2,
|
||||
TMCAM_THIRD = -3,
|
||||
TMCAM_CONSOLE = -4,
|
||||
} textmapcamerafollow_t;
|
||||
|
||||
// GETSECSPECIAL (specialval, section)
|
||||
//
|
||||
// Pulls out the special # from a particular section.
|
||||
|
|
@ -574,6 +582,8 @@ void P_CrossSpecialLine(line_t *line, INT32 side, mobj_t *thing);
|
|||
void P_PushSpecialLine(line_t *line, mobj_t *thing);
|
||||
void P_ActivateThingSpecial(mobj_t *mo, mobj_t *source);
|
||||
|
||||
mobj_t* P_FindObjectTypeFromTag(mobjtype_t type, mtag_t tag);
|
||||
|
||||
//
|
||||
// Special activation info
|
||||
//
|
||||
|
|
|
|||
50
src/p_tick.c
50
src/p_tick.c
|
|
@ -78,7 +78,7 @@ void Command_Numthinkers_f(void)
|
|||
thinklistnum_t end = NUM_THINKERLISTS - 1;
|
||||
thinklistnum_t i;
|
||||
|
||||
if (gamestate != GS_LEVEL)
|
||||
if (G_GamestateUsesLevel() == false)
|
||||
{
|
||||
CONS_Printf(M_GetText("You must be in a level to use this.\n"));
|
||||
return;
|
||||
|
|
@ -149,7 +149,7 @@ void Command_CountMobjs_f(void)
|
|||
mobjtype_t i;
|
||||
INT32 count;
|
||||
|
||||
if (gamestate != GS_LEVEL)
|
||||
if (G_GamestateUsesLevel() == false)
|
||||
{
|
||||
CONS_Printf(M_GetText("You must be in a level to use this.\n"));
|
||||
return;
|
||||
|
|
@ -532,10 +532,12 @@ void P_Ticker(boolean run)
|
|||
|
||||
// Increment jointime and quittime even if paused
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
if (playeringame[i])
|
||||
{
|
||||
players[i].jointime++;
|
||||
}
|
||||
}
|
||||
|
||||
if (objectplacing)
|
||||
{
|
||||
|
|
@ -602,32 +604,16 @@ 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 (!PLAYERCONDITION(i))
|
||||
continue;
|
||||
K_UpdateDistanceFromFinishLine(&players[i]);
|
||||
}
|
||||
|
||||
// Second loop: Ensure all player positions reflect everyone's distances
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
if (!PLAYERCONDITION(i))
|
||||
continue;
|
||||
K_KartUpdatePosition(&players[i]);
|
||||
}
|
||||
K_UpdateAllPlayerPositions();
|
||||
|
||||
// OK! Now that we got all of that sorted, players can think!
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
if (!PLAYERCONDITION(i))
|
||||
if (!(playeringame[i] && players[i].mo && !P_MobjWasRemoved(players[i].mo)))
|
||||
continue;
|
||||
P_PlayerThink(&players[i]);
|
||||
K_KartPlayerHUDUpdate(&players[i]);
|
||||
}
|
||||
#undef PLAYERCONDITION
|
||||
|
||||
ps_playerthink_time = I_GetPreciseTime() - ps_playerthink_time;
|
||||
}
|
||||
|
|
@ -795,10 +781,12 @@ void P_Ticker(boolean run)
|
|||
}
|
||||
}
|
||||
|
||||
K_UpdateDirector();
|
||||
|
||||
// Always move the camera.
|
||||
P_RunChaseCameras();
|
||||
if (gamestate == GS_LEVEL)
|
||||
{
|
||||
// Move the camera during levels.
|
||||
K_UpdateDirector();
|
||||
P_RunChaseCameras();
|
||||
}
|
||||
|
||||
LUA_HOOK(PostThinkFrame);
|
||||
|
||||
|
|
@ -867,19 +855,11 @@ void P_PreTicker(INT32 frames)
|
|||
|
||||
R_UpdateMobjInterpolators();
|
||||
|
||||
// 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]);
|
||||
|
||||
// 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]);
|
||||
|
||||
// OK! Now that we got all of that sorted, players can think!
|
||||
LUA_HOOK(PreThinkFrame);
|
||||
|
||||
K_UpdateAllPlayerPositions();
|
||||
|
||||
// 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))
|
||||
{
|
||||
|
|
|
|||
49
src/p_user.c
49
src/p_user.c
|
|
@ -58,6 +58,8 @@
|
|||
#include "k_terrain.h" // K_SpawnSplashForMobj
|
||||
#include "k_color.h"
|
||||
#include "k_follower.h"
|
||||
#include "k_battle.h"
|
||||
#include "k_rank.h"
|
||||
|
||||
#ifdef HW3SOUND
|
||||
#include "hardware/hw3sound.h"
|
||||
|
|
@ -1284,7 +1286,7 @@ void P_DoPlayerExit(player_t *player)
|
|||
|
||||
if ((gametyperules & GTR_CIRCUIT)) // If in Race Mode, allow
|
||||
{
|
||||
K_KartUpdatePosition(player);
|
||||
K_UpdateAllPlayerPositions();
|
||||
|
||||
if (cv_kartvoices.value)
|
||||
{
|
||||
|
|
@ -1353,6 +1355,7 @@ void P_DoPlayerExit(player_t *player)
|
|||
if (RINGTOTAL(player) > 0)
|
||||
{
|
||||
player->totalring += RINGTOTAL(player);
|
||||
grandprixinfo.rank.rings += RINGTOTAL(player);
|
||||
|
||||
extra = player->totalring / lifethreshold;
|
||||
|
||||
|
|
@ -1363,6 +1366,16 @@ void P_DoPlayerExit(player_t *player)
|
|||
player->xtralife = extra;
|
||||
}
|
||||
}
|
||||
|
||||
if (grandprixinfo.eventmode == GPEVENT_NONE)
|
||||
{
|
||||
grandprixinfo.rank.winPoints += K_CalculateGPRankPoints(player->position, grandprixinfo.rank.totalPlayers);
|
||||
grandprixinfo.rank.laps += player->lapPoints;
|
||||
}
|
||||
else if (grandprixinfo.eventmode == GPEVENT_SPECIAL)
|
||||
{
|
||||
grandprixinfo.rank.specialWon = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3670,10 +3683,10 @@ static void P_CalcPostImg(player_t *player)
|
|||
else
|
||||
pviewheight = player->mo->z + player->viewheight;
|
||||
|
||||
if (player->awayviewtics && player->awayviewmobj && !P_MobjWasRemoved(player->awayviewmobj))
|
||||
if (player->awayview.tics && player->awayview.mobj && !P_MobjWasRemoved(player->awayview.mobj))
|
||||
{
|
||||
sector = player->awayviewmobj->subsector->sector;
|
||||
pviewheight = player->awayviewmobj->z + 20*FRACUNIT;
|
||||
sector = player->awayview.mobj->subsector->sector;
|
||||
pviewheight = player->awayview.mobj->z;
|
||||
}
|
||||
|
||||
for (i = 0; i <= (unsigned)r_splitscreen; i++)
|
||||
|
|
@ -3997,6 +4010,25 @@ DoABarrelRoll (player_t *player)
|
|||
player->tilt = slope;
|
||||
}
|
||||
|
||||
void P_TickAltView(altview_t *view)
|
||||
{
|
||||
if (view->mobj != NULL && P_MobjWasRemoved(view->mobj) == true)
|
||||
{
|
||||
P_SetTarget(&view->mobj, NULL); // remove view->mobj asap if invalid
|
||||
view->tics = 0; // reset to zero
|
||||
}
|
||||
|
||||
if (view->tics > 0)
|
||||
{
|
||||
view->tics--;
|
||||
|
||||
if (view->tics == 0)
|
||||
{
|
||||
P_SetTarget(&view->mobj, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// P_PlayerThink
|
||||
//
|
||||
|
|
@ -4020,18 +4052,11 @@ void P_PlayerThink(player_t *player)
|
|||
|
||||
player->old_drawangle = player->drawangle;
|
||||
|
||||
if (player->awayviewmobj && P_MobjWasRemoved(player->awayviewmobj))
|
||||
{
|
||||
P_SetTarget(&player->awayviewmobj, NULL); // remove awayviewmobj asap if invalid
|
||||
player->awayviewtics = 0; // reset to zero
|
||||
}
|
||||
P_TickAltView(&player->awayview);
|
||||
|
||||
if (player->flashcount)
|
||||
player->flashcount--;
|
||||
|
||||
if (player->awayviewtics && player->awayviewtics != -1)
|
||||
player->awayviewtics--;
|
||||
|
||||
// Track airtime
|
||||
if (P_IsObjectOnGround(player->mo)
|
||||
&& !P_PlayerInPain(player)) // This isn't airtime, but it's control loss all the same.
|
||||
|
|
|
|||
39
src/r_main.c
39
src/r_main.c
|
|
@ -928,7 +928,22 @@ void R_ApplyViewMorph(int s)
|
|||
|
||||
angle_t R_ViewRollAngle(const player_t *player)
|
||||
{
|
||||
angle_t roll = player->viewrollangle;
|
||||
angle_t roll = 0;
|
||||
|
||||
if (gamestate != GS_LEVEL)
|
||||
{
|
||||
// FIXME: The way this is implemented is totally
|
||||
// incompatible with cameras that aren't directly
|
||||
// tied to the player. (podium, titlemap,
|
||||
// MT_ALTVIEWMAN in general)
|
||||
|
||||
// All of these player variables should affect their
|
||||
// camera_t in P_MoveChaseCamera, and then this
|
||||
// just returns that variable instead.
|
||||
return 0;
|
||||
}
|
||||
|
||||
roll = player->viewrollangle;
|
||||
|
||||
if (cv_tilting.value)
|
||||
{
|
||||
|
|
@ -1192,10 +1207,10 @@ static void R_SetupAimingFrame(int s)
|
|||
player_t *player = &players[displayplayers[s]];
|
||||
camera_t *thiscam = &camera[s];
|
||||
|
||||
if (player->awayviewtics)
|
||||
if (player->awayview.tics)
|
||||
{
|
||||
newview->aim = player->awayviewaiming;
|
||||
newview->angle = player->awayviewmobj->angle;
|
||||
newview->aim = player->awayview.mobj->pitch;
|
||||
newview->angle = player->awayview.mobj->angle;
|
||||
}
|
||||
else if (thiscam && thiscam->chase)
|
||||
{
|
||||
|
|
@ -1237,15 +1252,15 @@ void R_SetupFrame(int s)
|
|||
|
||||
R_SetupAimingFrame(s);
|
||||
|
||||
if (player->awayviewtics)
|
||||
if (player->awayview.tics)
|
||||
{
|
||||
// cut-away view stuff
|
||||
r_viewmobj = player->awayviewmobj; // should be a MT_ALTVIEWMAN
|
||||
r_viewmobj = player->awayview.mobj; // should be a MT_ALTVIEWMAN
|
||||
I_Assert(r_viewmobj != NULL);
|
||||
|
||||
newview->x = r_viewmobj->x;
|
||||
newview->y = r_viewmobj->y;
|
||||
newview->z = r_viewmobj->z + 20*FRACUNIT;
|
||||
newview->z = r_viewmobj->z;
|
||||
|
||||
R_SetupCommonFrame(player, r_viewmobj->subsector);
|
||||
}
|
||||
|
|
@ -1306,10 +1321,10 @@ void R_SkyboxFrame(int s)
|
|||
vector3_t campos = {0,0,0}; // Position of player's actual view point
|
||||
mobj_t *center = player->skybox.centerpoint;
|
||||
|
||||
if (player->awayviewtics) {
|
||||
campos.x = player->awayviewmobj->x;
|
||||
campos.y = player->awayviewmobj->y;
|
||||
campos.z = player->awayviewmobj->z + 20*FRACUNIT;
|
||||
if (player->awayview.tics) {
|
||||
campos.x = player->awayview.mobj->x;
|
||||
campos.y = player->awayview.mobj->y;
|
||||
campos.z = player->awayview.mobj->z;
|
||||
} else if (thiscam->chase) {
|
||||
campos.x = thiscam->x;
|
||||
campos.y = thiscam->y;
|
||||
|
|
@ -1403,7 +1418,7 @@ boolean R_IsViewpointThirdPerson(player_t *player, boolean skybox)
|
|||
boolean chasecam = R_ViewpointHasChasecam(player);
|
||||
|
||||
// cut-away view stuff
|
||||
if (player->awayviewtics || skybox)
|
||||
if (player->awayview.tics || skybox)
|
||||
return chasecam;
|
||||
// use outside cam view
|
||||
else if (!player->spectator && chasecam)
|
||||
|
|
|
|||
|
|
@ -540,9 +540,9 @@ void S_StartSoundAtVolume(const void *origin_p, sfxenum_t sfx_id, INT32 volume)
|
|||
continue;
|
||||
}
|
||||
|
||||
if (player->awayviewtics)
|
||||
if (player->awayview.tics)
|
||||
{
|
||||
listenmobj[i] = player->awayviewmobj;
|
||||
listenmobj[i] = player->awayview.mobj;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -572,7 +572,7 @@ void S_StartSoundAtVolume(const void *origin_p, sfxenum_t sfx_id, INT32 volume)
|
|||
continue;
|
||||
}
|
||||
|
||||
if (camera[i].chase && !player->awayviewtics)
|
||||
if (camera[i].chase && !player->awayview.tics)
|
||||
{
|
||||
listener[i].x = camera[i].x;
|
||||
listener[i].y = camera[i].y;
|
||||
|
|
@ -827,9 +827,9 @@ void S_UpdateSounds(void)
|
|||
continue;
|
||||
}
|
||||
|
||||
if (player->awayviewtics)
|
||||
if (player->awayview.tics)
|
||||
{
|
||||
listenmobj[i] = player->awayviewmobj;
|
||||
listenmobj[i] = player->awayview.mobj;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -858,7 +858,7 @@ void S_UpdateSounds(void)
|
|||
continue;
|
||||
}
|
||||
|
||||
if (camera[i].chase && !player->awayviewtics)
|
||||
if (camera[i].chase && !player->awayview.tics)
|
||||
{
|
||||
listener[i].x = camera[i].x;
|
||||
listener[i].y = camera[i].y;
|
||||
|
|
|
|||
|
|
@ -46,6 +46,7 @@ TYPEDEF (respawnvars_t);
|
|||
TYPEDEF (botvars_t);
|
||||
TYPEDEF (skybox_t);
|
||||
TYPEDEF (itemroulette_t);
|
||||
TYPEDEF (altview_t);
|
||||
TYPEDEF (player_t);
|
||||
|
||||
// d_clisrv.h
|
||||
|
|
@ -197,6 +198,9 @@ TYPEDEF (t_floor_t);
|
|||
// k_waypoint.h
|
||||
TYPEDEF (waypoint_t);
|
||||
|
||||
// k_rank.h
|
||||
TYPEDEF (gpRank_t);
|
||||
|
||||
// lua_hudlib_drawlist.h
|
||||
typedef struct huddrawlist_s *huddrawlist_h;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue