mirror of
https://github.com/KartKrewDev/RingRacers.git
synced 2026-02-16 18:46:20 +00:00
Merge branch 'master' of https://git.do.srb2.org/KartKrew/Kart into conditions-cascading
# Conflicts: # src/k_grandprix.c # src/k_grandprix.h
This commit is contained in:
commit
d2c36c952a
71 changed files with 3514 additions and 571 deletions
|
|
@ -64,6 +64,8 @@ add_executable(SRB2SDL2 MACOSX_BUNDLE WIN32
|
|||
tables.c
|
||||
r_bsp.c
|
||||
r_data.c
|
||||
r_debug.cpp
|
||||
r_debug_parser.cpp
|
||||
r_draw.c
|
||||
r_fps.c
|
||||
r_main.c
|
||||
|
|
@ -134,6 +136,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)
|
||||
|
||||
|
|
@ -1335,3 +1355,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();
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
#define __SRB2_CXXUTIL_HPP__
|
||||
|
||||
#include <cstdlib>
|
||||
#include <functional>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
|
|
|
|||
|
|
@ -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,10 +2557,11 @@ 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);
|
||||
P_SetTarget(&players[playernum].sliptideZipIndicator, NULL);
|
||||
}
|
||||
|
||||
// Handle parties.
|
||||
|
|
@ -3765,9 +3766,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);
|
||||
|
|
|
|||
64
src/d_main.c
64
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
|
||||
|
|
@ -178,6 +179,7 @@ boolean capslock = 0; // gee i wonder what this does.
|
|||
void D_ProcessEvents(void)
|
||||
{
|
||||
event_t *ev;
|
||||
int i;
|
||||
|
||||
boolean eaten;
|
||||
boolean menuresponse = false;
|
||||
|
|
@ -251,6 +253,12 @@ void D_ProcessEvents(void)
|
|||
{
|
||||
M_MapMenuControls(NULL);
|
||||
}
|
||||
|
||||
// Update menu CMD
|
||||
for (i = 0; i < MAXSPLITSCREENPLAYERS; i++)
|
||||
{
|
||||
M_UpdateMenuCMD(i);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
|
|
@ -337,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);
|
||||
|
|
@ -346,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);
|
||||
|
|
@ -399,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;
|
||||
|
||||
|
|
@ -463,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)
|
||||
{
|
||||
|
|
@ -559,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
|
||||
{
|
||||
|
|
@ -576,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
|
||||
|
|
@ -745,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,
|
||||
|
|
|
|||
|
|
@ -404,6 +404,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
|
||||
// ========================================================================
|
||||
|
|
@ -647,6 +654,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
|
||||
|
|
@ -664,9 +672,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
|
||||
|
|
@ -695,7 +701,12 @@ struct player_t
|
|||
|
||||
UINT8 tripwireReboundDelay; // When failing Tripwire, brieftly lock out speed-based tripwire pass (anti-cheese)
|
||||
|
||||
UINT16 sliptideZip; // How long is our chained sliptide? Grant a proportional boost when it's over.
|
||||
UINT8 sliptideZipDelay; // How long since the last sliptide? Only boost once you've been straightened out for a bit.
|
||||
UINT16 sliptideZipBoost; // The actual boost granted from sliptideZip.
|
||||
|
||||
mobj_t *stumbleIndicator;
|
||||
mobj_t *sliptideZipIndicator;
|
||||
|
||||
#ifdef HWRENDER
|
||||
fixed_t fovadd; // adjust FOV for hw rendering
|
||||
|
|
|
|||
|
|
@ -2767,6 +2767,10 @@ void readmaincfg(MYFILE *f, boolean mainfile)
|
|||
INT32 value;
|
||||
boolean doClearLevels = false;
|
||||
|
||||
#ifdef DEVELOP
|
||||
(void)mainfile;
|
||||
#endif
|
||||
|
||||
do
|
||||
{
|
||||
if (myfgets(s, MAXLINELEN, f))
|
||||
|
|
@ -2842,10 +2846,12 @@ void readmaincfg(MYFILE *f, boolean mainfile)
|
|||
M_ClearStats();
|
||||
M_ClearSecrets();
|
||||
}
|
||||
#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');
|
||||
|
|
@ -2953,6 +2959,7 @@ void readmaincfg(MYFILE *f, boolean mainfile)
|
|||
}
|
||||
else if (fastcmp(word, "TITLEMAP"))
|
||||
{
|
||||
Z_Free(titlemap);
|
||||
titlemap = Z_StrDup(word2);
|
||||
titlechanged = true;
|
||||
}
|
||||
|
|
@ -3047,13 +3054,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);
|
||||
}
|
||||
|
|
@ -3192,6 +3206,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;
|
||||
|
|
|
|||
|
|
@ -3304,6 +3304,8 @@ const char *const STATE_LIST[] = { // array length left dynamic for sanity testi
|
|||
"S_MAGICIANBOXTOP",
|
||||
"S_MAGICIANBOXBOTTOM",
|
||||
|
||||
"S_SLIPTIDEZIP",
|
||||
|
||||
// Signpost sparkles
|
||||
"S_SIGNSPARK1",
|
||||
"S_SIGNSPARK2",
|
||||
|
|
@ -5323,6 +5325,8 @@ const char *const MOBJTYPE_LIST[] = { // array length left dynamic for sanity t
|
|||
"MT_MONITOR_PART",
|
||||
"MT_MONITOR_SHARD",
|
||||
"MT_MAGICIANBOX",
|
||||
|
||||
"MT_SLIPTIDEZIP",
|
||||
|
||||
"MT_SIGNSPARKLE",
|
||||
|
||||
|
|
@ -6303,6 +6307,7 @@ struct int_const_s const INT_CONST[] = {
|
|||
{"RF_FULLDARK",RF_FULLDARK},
|
||||
{"RF_SEMIBRIGHT",RF_SEMIBRIGHT},
|
||||
{"RF_NOCOLORMAPS",RF_NOCOLORMAPS},
|
||||
{"RF_ALWAYSONTOP",RF_ALWAYSONTOP},
|
||||
{"RF_SPRITETYPEMASK",RF_SPRITETYPEMASK},
|
||||
{"RF_PAPERSPRITE",RF_PAPERSPRITE},
|
||||
{"RF_FLOORSPRITE",RF_FLOORSPRITE},
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
@ -697,7 +699,6 @@ extern UINT8 gamespeed;
|
|||
extern boolean franticitems;
|
||||
extern boolean encoremode, prevencoremode;
|
||||
|
||||
extern UINT32 g_hiscore;
|
||||
extern tic_t wantedcalcdelay;
|
||||
extern tic_t itemCooldowns[NUMKARTITEMS - 1];
|
||||
extern tic_t mapreset;
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
212
src/g_game.c
212
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;
|
||||
|
|
@ -298,7 +302,6 @@ SINT8 votes[MAXPLAYERS]; // Each player's vote
|
|||
SINT8 pickedvote; // What vote the host rolls
|
||||
|
||||
// Server-sided, synched variables
|
||||
UINT32 g_hiscore; // Highest score (points) achieved by anyone in game
|
||||
tic_t wantedcalcdelay; // Time before it recalculates WANTED
|
||||
tic_t itemCooldowns[NUMKARTITEMS - 1]; // Cooldowns to prevent item spawning
|
||||
tic_t mapreset; // Map reset delay when enough players have joined an empty game
|
||||
|
|
@ -1449,9 +1452,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 +1464,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 +1481,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 +1548,11 @@ void G_DoLoadLevel(boolean resetplayer)
|
|||
}
|
||||
}
|
||||
|
||||
void G_DoLoadLevel(boolean resetplayer)
|
||||
{
|
||||
G_DoLoadLevelEx(resetplayer, GS_LEVEL);
|
||||
}
|
||||
|
||||
//
|
||||
// Start the title card.
|
||||
//
|
||||
|
|
@ -1573,7 +1583,7 @@ void G_StartTitleCard(void)
|
|||
}
|
||||
|
||||
// start the title card
|
||||
WipeStageTitle = (!titlemapinaction);
|
||||
WipeStageTitle = (gamestate == GS_LEVEL);
|
||||
}
|
||||
|
||||
//
|
||||
|
|
@ -1717,6 +1727,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 +1752,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 +2126,7 @@ void G_Ticker(boolean run)
|
|||
marathontime++;
|
||||
|
||||
P_MapStart();
|
||||
// do player reborns if needed
|
||||
|
||||
if (gamestate == GS_LEVEL)
|
||||
{
|
||||
// Or, alternatively, retry.
|
||||
|
|
@ -2117,11 +2144,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 +2219,6 @@ void G_Ticker(boolean run)
|
|||
F_TextPromptTicker();
|
||||
AM_Ticker();
|
||||
HU_Ticker();
|
||||
|
||||
break;
|
||||
|
||||
case GS_INTERMISSION:
|
||||
|
|
@ -2237,6 +2280,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();
|
||||
|
|
@ -2336,6 +2384,7 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
|
|||
INT16 totalring;
|
||||
UINT8 laps;
|
||||
UINT8 latestlap;
|
||||
UINT32 lapPoints;
|
||||
UINT16 skincolor;
|
||||
INT32 skin;
|
||||
UINT8 availabilities[MAXAVAILABILITY];
|
||||
|
|
@ -2459,6 +2508,7 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
|
|||
nocontrol = 0;
|
||||
laps = 0;
|
||||
latestlap = 0;
|
||||
lapPoints = 0;
|
||||
roundscore = 0;
|
||||
exiting = 0;
|
||||
khudfinish = 0;
|
||||
|
|
@ -2496,6 +2546,7 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
|
|||
|
||||
laps = players[player].laps;
|
||||
latestlap = players[player].latestlap;
|
||||
lapPoints = players[player].lapPoints;
|
||||
|
||||
roundscore = players[player].roundscore;
|
||||
|
||||
|
|
@ -2523,7 +2574,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);
|
||||
|
||||
|
|
@ -2571,6 +2622,7 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
|
|||
|
||||
p->laps = laps;
|
||||
p->latestlap = latestlap;
|
||||
p->lapPoints = lapPoints;
|
||||
p->totalring = totalring;
|
||||
|
||||
p->bot = bot;
|
||||
|
|
@ -2730,7 +2782,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));
|
||||
|
|
@ -2826,7 +2878,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++)
|
||||
{
|
||||
|
|
@ -2909,6 +2963,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)
|
||||
{
|
||||
|
|
@ -2945,9 +3035,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 --
|
||||
|
|
@ -3094,13 +3189,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();
|
||||
|
|
@ -3109,11 +3211,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;
|
||||
|
|
@ -3804,20 +3909,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])
|
||||
|
|
@ -4068,6 +4162,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])
|
||||
|
|
@ -4093,6 +4190,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]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -4302,8 +4404,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
|
||||
{
|
||||
|
|
@ -5116,6 +5220,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;
|
||||
|
|
@ -5410,6 +5524,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
|
||||
|
|
@ -5436,6 +5566,11 @@ boolean G_GetExitGameFlag(void)
|
|||
// Same deal with retrying.
|
||||
void G_SetRetryFlag(void)
|
||||
{
|
||||
if (retrying == false)
|
||||
{
|
||||
grandprixinfo.rank.continuesUsed++;
|
||||
}
|
||||
|
||||
retrying = true;
|
||||
}
|
||||
|
||||
|
|
@ -5493,4 +5628,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
|
||||
|
|
|
|||
33
src/info.c
33
src/info.c
|
|
@ -552,6 +552,8 @@ char sprnames[NUMSPRITES + 1][5] =
|
|||
"IMDB", // Item Monitor Small Shard (Debris)
|
||||
"MTWK", // Item Monitor Glass Twinkle
|
||||
|
||||
"SLPT", // Sliptide zip indicator
|
||||
|
||||
"WIPD", // Wipeout dust trail
|
||||
"DRIF", // Drift Sparks
|
||||
"BDRF", // Brake drift sparks
|
||||
|
|
@ -3930,6 +3932,8 @@ state_t states[NUMSTATES] =
|
|||
{SPR_MGBT, FF_FLOORSPRITE|0, -1, {NULL}, 0, 0, S_NULL}, // S_MAGICIANBOX_TOP
|
||||
{SPR_MGBB, FF_FLOORSPRITE|0, -1, {NULL}, 0, 0, S_NULL}, // S_MAGICIANBOX_BOTTOM
|
||||
|
||||
{SPR_SLPT, FF_PAPERSPRITE|0, -1, {NULL}, 0, 0, S_NULL}, // S_SLIPTIDEZIP
|
||||
|
||||
{SPR_SGNS, FF_ADD|FF_FULLBRIGHT, 1, {NULL}, 0, 0, S_SIGNSPARK2}, // S_SIGNSPARK1
|
||||
{SPR_SGNS, FF_ADD|FF_FULLBRIGHT|1, 1, {NULL}, 0, 0, S_SIGNSPARK3}, // S_SIGNSPARK2
|
||||
{SPR_SGNS, FF_ADD|FF_FULLBRIGHT|2, 1, {NULL}, 0, 0, S_SIGNSPARK4}, // S_SIGNSPARK3
|
||||
|
|
@ -21281,7 +21285,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
|
||||
},
|
||||
|
||||
|
|
@ -22583,6 +22587,33 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
|
|||
MF_NOGRAVITY|MF_NOCLIP|MF_NOCLIPTHING|MF_NOCLIPHEIGHT, // flags
|
||||
S_NULL // raisestate
|
||||
},
|
||||
|
||||
{ // MT_SLIPTIDEZIP
|
||||
-1, // doomednum
|
||||
S_SLIPTIDEZIP, // spawnstate
|
||||
1000, // spawnhealth
|
||||
S_NULL, // seestate
|
||||
sfx_None, // seesound
|
||||
0, // reactiontime
|
||||
sfx_None, // attacksound
|
||||
S_NULL, // painstate
|
||||
0, // painchance
|
||||
sfx_None, // painsound
|
||||
S_NULL, // meleestate
|
||||
S_NULL, // missilestate
|
||||
S_NULL, // deathstate
|
||||
S_NULL, // xdeathstate
|
||||
sfx_None, // deathsound
|
||||
0, // speed
|
||||
20*FRACUNIT, // radius
|
||||
20*FRACUNIT, // height
|
||||
0, // display offset
|
||||
100, // mass
|
||||
0, // damage
|
||||
sfx_None, // activesound
|
||||
MF_NOBLOCKMAP|MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_NOCLIPTHING|MF_DONTENCOREMAP, // flags
|
||||
S_NULL // raisestate
|
||||
},
|
||||
|
||||
{ // MT_SIGNSPARKLE
|
||||
-1, // doomednum
|
||||
|
|
|
|||
|
|
@ -1103,6 +1103,8 @@ typedef enum sprite
|
|||
SPR_IMDB, // Item Monitor Small Shard (Debris)
|
||||
SPR_MTWK, // Item Monitor Glass Twinkle
|
||||
|
||||
SPR_SLPT, // Sliptide zip indicator
|
||||
|
||||
SPR_WIPD, // Wipeout dust trail
|
||||
SPR_DRIF, // Drift Sparks
|
||||
SPR_BDRF, // Brake drift sparks
|
||||
|
|
@ -4339,6 +4341,8 @@ typedef enum state
|
|||
S_MAGICIANBOX_TOP,
|
||||
S_MAGICIANBOX_BOTTOM,
|
||||
|
||||
S_SLIPTIDEZIP,
|
||||
|
||||
// Signpost sparkles
|
||||
S_SIGNSPARK1,
|
||||
S_SIGNSPARK2,
|
||||
|
|
@ -6394,6 +6398,7 @@ typedef enum mobj_type
|
|||
MT_MONITOR_PART,
|
||||
MT_MONITOR_SHARD,
|
||||
MT_MAGICIANBOX,
|
||||
MT_SLIPTIDEZIP,
|
||||
|
||||
MT_SIGNSPARKLE,
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
@ -91,8 +92,10 @@ void K_CheckBumpers(void)
|
|||
{
|
||||
UINT8 i;
|
||||
UINT8 numingame = 0;
|
||||
UINT32 toproundscore = 0;
|
||||
UINT8 nobumpers = 0;
|
||||
UINT8 eliminated = 0;
|
||||
|
||||
const boolean singleplayer = (battlecapsules || bossinfo.valid);
|
||||
|
||||
if (!(gametyperules & GTR_BUMPERS))
|
||||
return;
|
||||
|
|
@ -110,37 +113,35 @@ void K_CheckBumpers(void)
|
|||
|
||||
numingame++;
|
||||
|
||||
if (players[i].roundscore > toproundscore)
|
||||
{
|
||||
toproundscore = players[i].roundscore;
|
||||
}
|
||||
|
||||
if (players[i].bumpers <= 0) // if you don't have any bumpers, you're probably not a winner
|
||||
{
|
||||
nobumpers++;
|
||||
}
|
||||
|
||||
if (players[i].pflags & PF_ELIMINATED)
|
||||
{
|
||||
eliminated++;
|
||||
}
|
||||
}
|
||||
|
||||
if (battlecapsules || bossinfo.valid)
|
||||
if (singleplayer
|
||||
? nobumpers > 0 && nobumpers >= numingame
|
||||
: eliminated >= numingame - 1)
|
||||
{
|
||||
if (nobumpers > 0 && nobumpers >= numingame)
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
if (!playeringame[i])
|
||||
continue;
|
||||
if (players[i].spectator)
|
||||
continue;
|
||||
if (!playeringame[i])
|
||||
continue;
|
||||
if (players[i].spectator)
|
||||
continue;
|
||||
|
||||
if (singleplayer)
|
||||
players[i].pflags |= PF_NOCONTEST;
|
||||
P_DoPlayerExit(&players[i]);
|
||||
}
|
||||
|
||||
P_DoPlayerExit(&players[i]);
|
||||
}
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
g_hiscore = toproundscore;
|
||||
}
|
||||
|
||||
if (numingame <= 1)
|
||||
{
|
||||
|
|
@ -183,10 +184,8 @@ void K_CheckEmeralds(player_t *player)
|
|||
continue;
|
||||
}
|
||||
|
||||
players[i].bumpers = 0;
|
||||
P_DoPlayerExit(&players[i]);
|
||||
}
|
||||
|
||||
K_CheckBumpers();
|
||||
}
|
||||
|
||||
UINT16 K_GetChaosEmeraldColor(UINT32 emeraldType)
|
||||
|
|
@ -791,7 +790,14 @@ void K_BattleInit(boolean singleplayercontext)
|
|||
{
|
||||
if (!playeringame[i] || players[i].spectator)
|
||||
continue;
|
||||
|
||||
players[i].bumpers = maxbumpers;
|
||||
|
||||
if (players[i].mo)
|
||||
{
|
||||
players[i].mo->health = maxbumpers;
|
||||
}
|
||||
|
||||
K_SpawnPlayerBattleBumpers(players+i);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
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)
|
||||
|
|
@ -251,6 +251,9 @@ void K_UpdateMatchRaceBots(void)
|
|||
--------------------------------------------------*/
|
||||
boolean K_PlayerUsesBotMovement(player_t *player)
|
||||
{
|
||||
if (K_PodiumSequence() == true)
|
||||
return true;
|
||||
|
||||
if (player->exiting)
|
||||
return true;
|
||||
|
||||
|
|
@ -1254,6 +1257,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)
|
||||
|
||||
|
|
@ -1272,7 +1332,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;
|
||||
|
|
@ -1284,6 +1346,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
|
||||
|
|
@ -1546,6 +1614,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)
|
||||
{
|
||||
|
|
@ -816,6 +817,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)
|
||||
|
|
|
|||
|
|
@ -95,6 +95,24 @@ INT16 K_CalculateGPRankPoints(UINT8 position, UINT8 numplayers)
|
|||
return points;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
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)
|
||||
|
||||
|
|
@ -179,12 +197,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);
|
||||
|
||||
|
|
@ -71,6 +75,23 @@ UINT8 K_BotStartingDifficulty(SINT8 value);
|
|||
INT16 K_CalculateGPRankPoints(UINT8 position, UINT8 numplayers);
|
||||
|
||||
|
||||
/*--------------------------------------------------
|
||||
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);
|
||||
|
||||
|
|
@ -160,6 +181,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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,17 +2,23 @@
|
|||
#include <cstddef>
|
||||
#include <vector>
|
||||
|
||||
#include "core/static_vec.hpp"
|
||||
|
||||
#include "k_battle.h"
|
||||
#include "k_boss.h"
|
||||
#include "k_hud.h"
|
||||
#include "k_objects.h"
|
||||
#include "m_fixed.h"
|
||||
#include "p_local.h"
|
||||
#include "p_mobj.h"
|
||||
#include "r_draw.h"
|
||||
#include "r_fps.h"
|
||||
#include "r_main.h"
|
||||
#include "st_stuff.h"
|
||||
#include "v_video.h"
|
||||
|
||||
using namespace srb2;
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
|
|
@ -21,10 +27,82 @@ struct TargetTracking
|
|||
mobj_t* mobj;
|
||||
vector3_t point;
|
||||
fixed_t camDist;
|
||||
|
||||
skincolornum_t color() const
|
||||
{
|
||||
switch (mobj->type)
|
||||
{
|
||||
case MT_OVERTIME_CENTER:
|
||||
return SKINCOLOR_BLUE;
|
||||
|
||||
case MT_MONITOR:
|
||||
case MT_EMERALD:
|
||||
return static_cast<skincolornum_t>(mobj->color);
|
||||
|
||||
case MT_PLAYER:
|
||||
return player_emeralds_color();
|
||||
|
||||
default:
|
||||
return SKINCOLOR_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
StaticVec<uint32_t, 7> player_emeralds_vec() const
|
||||
{
|
||||
StaticVec<uint32_t, 7> emeralds;
|
||||
|
||||
const player_t* player = mobj->player;
|
||||
|
||||
if (player == nullptr)
|
||||
{
|
||||
return emeralds;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 7; ++i)
|
||||
{
|
||||
const uint32_t emeraldFlag = (1U << i);
|
||||
|
||||
if (player->emeralds & emeraldFlag)
|
||||
{
|
||||
emeralds.push_back(emeraldFlag);
|
||||
}
|
||||
}
|
||||
|
||||
return emeralds;
|
||||
}
|
||||
|
||||
skincolornum_t player_emeralds_color() const
|
||||
{
|
||||
const StaticVec emeralds = player_emeralds_vec();
|
||||
|
||||
if (emeralds.empty())
|
||||
{
|
||||
return SKINCOLOR_NONE;
|
||||
}
|
||||
|
||||
constexpr tic_t kPeriod = TICRATE / 2;
|
||||
const int idx = (leveltime / kPeriod) % emeralds.size();
|
||||
|
||||
return static_cast<skincolornum_t>(K_GetChaosEmeraldColor(emeralds[idx]));
|
||||
}
|
||||
|
||||
const uint8_t* colormap() const
|
||||
{
|
||||
const skincolornum_t clr = color();
|
||||
|
||||
if (clr != SKINCOLOR_NONE)
|
||||
{
|
||||
return R_GetTranslationColormap(TC_RAINBOW, clr, GTC_CACHE);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
void K_DrawTargetTracking(const TargetTracking& target)
|
||||
{
|
||||
const uint8_t* colormap = target.colormap();
|
||||
|
||||
trackingResult_t result = {};
|
||||
int32_t timer = 0;
|
||||
|
||||
|
|
@ -175,10 +253,10 @@ void K_DrawTargetTracking(const TargetTracking& target)
|
|||
|
||||
if (targetPatch)
|
||||
{
|
||||
V_DrawFixedPatch(targetPos.x, targetPos.y, FRACUNIT, V_SPLITSCREEN, targetPatch, nullptr);
|
||||
V_DrawFixedPatch(targetPos.x, targetPos.y, FRACUNIT, V_SPLITSCREEN, targetPatch, colormap);
|
||||
}
|
||||
|
||||
V_DrawFixedPatch(arrowPos.x, arrowPos.y, FRACUNIT, V_SPLITSCREEN | arrowFlags, arrowPatch, nullptr);
|
||||
V_DrawFixedPatch(arrowPos.x, arrowPos.y, FRACUNIT, V_SPLITSCREEN | arrowFlags, arrowPatch, colormap);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -207,7 +285,7 @@ void K_DrawTargetTracking(const TargetTracking& target)
|
|||
FRACUNIT,
|
||||
V_SPLITSCREEN,
|
||||
patch,
|
||||
nullptr
|
||||
colormap
|
||||
);
|
||||
};
|
||||
|
||||
|
|
@ -229,7 +307,7 @@ void K_DrawTargetTracking(const TargetTracking& target)
|
|||
}
|
||||
}
|
||||
|
||||
bool is_player_tracking_target(const player_t *player)
|
||||
bool is_player_tracking_target(player_t *player = stplyr)
|
||||
{
|
||||
if ((gametyperules & (GTR_BUMPERS|GTR_CLOSERPLAYERS)) != (GTR_BUMPERS|GTR_CLOSERPLAYERS))
|
||||
{
|
||||
|
|
@ -253,17 +331,14 @@ bool is_player_tracking_target(const player_t *player)
|
|||
return player != stplyr;
|
||||
}
|
||||
|
||||
if (g_hiscore < 1) // SOMEONE should be scoring
|
||||
// Except for DUEL mode, Overtime hides all TARGETs except
|
||||
// the kiosk.
|
||||
if (battleovertime.enabled)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (player->roundscore < g_hiscore)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
return K_IsPlayerWanted(player);
|
||||
}
|
||||
|
||||
bool is_object_tracking_target(const mobj_t* mobj)
|
||||
|
|
@ -277,6 +352,15 @@ bool is_object_tracking_target(const mobj_t* mobj)
|
|||
case MT_PLAYER:
|
||||
return is_player_tracking_target(mobj->player);
|
||||
|
||||
case MT_OVERTIME_CENTER:
|
||||
return inDuel == false && battleovertime.enabled;
|
||||
|
||||
case MT_EMERALD:
|
||||
return is_player_tracking_target();
|
||||
|
||||
case MT_MONITOR:
|
||||
return is_player_tracking_target() && Obj_MonitorGetEmerald(mobj) != 0;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
471
src/k_kart.c
471
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;
|
||||
|
||||
|
|
@ -1229,6 +1243,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)
|
||||
|
|
@ -1812,6 +1831,11 @@ static void K_SpawnGenericSpeedLines(player_t *player, boolean top)
|
|||
fast->colorized = true;
|
||||
fast->renderflags |= RF_ADD;
|
||||
}
|
||||
else if (player->sliptideZipBoost)
|
||||
{
|
||||
fast->color = SKINCOLOR_WHITE;
|
||||
fast->colorized = true;
|
||||
}
|
||||
}
|
||||
|
||||
void K_SpawnNormalSpeedLines(player_t *player)
|
||||
|
|
@ -3014,6 +3038,10 @@ fixed_t K_GetSpindashChargeSpeed(player_t *player)
|
|||
return val;
|
||||
}
|
||||
|
||||
// v2 almost broke sliptiding when it fixed turning bugs!
|
||||
// This value is fine-tuned to feel like v1 again without reverting any of those changes.
|
||||
#define SLIPTIDEHANDLING 7*FRACUNIT/8
|
||||
|
||||
// sets boostpower, speedboost, accelboost, and handleboost to whatever we need it to be
|
||||
static void K_GetKartBoostPower(player_t *player)
|
||||
{
|
||||
|
|
@ -3021,10 +3049,6 @@ static void K_GetKartBoostPower(player_t *player)
|
|||
const fixed_t maxmetabolismincrease = FRACUNIT/2;
|
||||
const fixed_t metabolism = FRACUNIT - ((9-player->kartweight) * maxmetabolismincrease / 8);
|
||||
|
||||
// v2 almost broke sliptiding when it fixed turning bugs!
|
||||
// This value is fine-tuned to feel like v1 again without reverting any of those changes.
|
||||
const fixed_t sliptidehandling = FRACUNIT/2;
|
||||
|
||||
fixed_t boostpower = FRACUNIT;
|
||||
fixed_t speedboost = 0, accelboost = 0, handleboost = 0;
|
||||
UINT8 numboosts = 0;
|
||||
|
|
@ -3043,13 +3067,16 @@ static void K_GetKartBoostPower(player_t *player)
|
|||
boostpower = (4*boostpower)/5;
|
||||
|
||||
// Note: Handling will ONLY stack when sliptiding!
|
||||
// > (NB 2023-03-06: This was previously unintentionally applied while drifting as well.)
|
||||
// > (This only affected drifts where you were under the effect of multiple handling boosts.)
|
||||
// > (Revisit if Growvinciblity or sneaker-panels + power items feel too heavy while drifting!)
|
||||
// When you're not, it just uses the best instead of adding together, like the old behavior.
|
||||
#define ADDBOOST(s,a,h) { \
|
||||
numboosts++; \
|
||||
speedboost += FixedDiv(s, FRACUNIT + (metabolism * (numboosts-1))); \
|
||||
accelboost += FixedDiv(a, FRACUNIT + (metabolism * (numboosts-1))); \
|
||||
if (player->aizdriftstrat) \
|
||||
handleboost += FixedDiv(h, FRACUNIT + (metabolism * (numboosts-1))); \
|
||||
if (K_Sliptiding(player)) \
|
||||
handleboost += FixedDiv(h, FRACUNIT + (metabolism * (numboosts-1))/4); \
|
||||
else \
|
||||
handleboost = max(h, handleboost); \
|
||||
}
|
||||
|
|
@ -3059,18 +3086,18 @@ static void K_GetKartBoostPower(player_t *player)
|
|||
UINT8 i;
|
||||
for (i = 0; i < player->numsneakers; i++)
|
||||
{
|
||||
ADDBOOST(FRACUNIT/2, 8*FRACUNIT, sliptidehandling); // + 50% top speed, + 800% acceleration, +50% handling
|
||||
ADDBOOST(FRACUNIT/2, 8*FRACUNIT, SLIPTIDEHANDLING); // + 50% top speed, + 800% acceleration, +50% handling
|
||||
}
|
||||
}
|
||||
|
||||
if (player->invincibilitytimer) // Invincibility
|
||||
{
|
||||
ADDBOOST(3*FRACUNIT/8, 3*FRACUNIT, sliptidehandling/2); // + 37.5% top speed, + 300% acceleration, +25% handling
|
||||
ADDBOOST(3*FRACUNIT/8, 3*FRACUNIT, SLIPTIDEHANDLING/2); // + 37.5% top speed, + 300% acceleration, +25% handling
|
||||
}
|
||||
|
||||
if (player->growshrinktimer > 0) // Grow
|
||||
{
|
||||
ADDBOOST(0, 0, sliptidehandling/2); // + 0% top speed, + 0% acceleration, +25% handling
|
||||
ADDBOOST(0, 0, SLIPTIDEHANDLING/2); // + 0% top speed, + 0% acceleration, +25% handling
|
||||
}
|
||||
|
||||
if (player->flamedash) // Flame Shield dash
|
||||
|
|
@ -3079,10 +3106,16 @@ static void K_GetKartBoostPower(player_t *player)
|
|||
ADDBOOST(
|
||||
dash, // + infinite top speed
|
||||
3*FRACUNIT, // + 300% acceleration
|
||||
FixedMul(FixedDiv(dash, FRACUNIT/2), sliptidehandling/2) // + infinite handling
|
||||
FixedMul(FixedDiv(dash, FRACUNIT/2), SLIPTIDEHANDLING/2) // + infinite handling
|
||||
);
|
||||
}
|
||||
|
||||
if (player->sliptideZipBoost)
|
||||
{
|
||||
// NB: This is intentionally under the 25% threshold required to initiate a sliptide
|
||||
ADDBOOST(13*FRACUNIT/20, 4*FRACUNIT, 2*SLIPTIDEHANDLING/5); // + 65% top speed, + 400% acceleration, +20% handling
|
||||
}
|
||||
|
||||
if (player->spindashboost) // Spindash boost
|
||||
{
|
||||
const fixed_t MAXCHARGESPEED = K_GetSpindashChargeSpeed(player);
|
||||
|
|
@ -3098,7 +3131,7 @@ static void K_GetKartBoostPower(player_t *player)
|
|||
|
||||
if (player->startboost) // Startup Boost
|
||||
{
|
||||
ADDBOOST(FRACUNIT, 4*FRACUNIT, sliptidehandling); // + 100% top speed, + 400% acceleration, +50% handling
|
||||
ADDBOOST(FRACUNIT, 4*FRACUNIT, SLIPTIDEHANDLING); // + 100% top speed, + 400% acceleration, +50% handling
|
||||
}
|
||||
|
||||
if (player->driftboost) // Drift Boost
|
||||
|
|
@ -3128,7 +3161,7 @@ static void K_GetKartBoostPower(player_t *player)
|
|||
|
||||
if (player->gateBoost) // SPB Juicebox boost
|
||||
{
|
||||
ADDBOOST(3*FRACUNIT/4, 4*FRACUNIT, sliptidehandling/2); // + 75% top speed, + 400% acceleration, +25% handling
|
||||
ADDBOOST(3*FRACUNIT/4, 4*FRACUNIT, SLIPTIDEHANDLING/2); // + 75% top speed, + 400% acceleration, +25% handling
|
||||
}
|
||||
|
||||
if (player->ringboost) // Ring Boost
|
||||
|
|
@ -3218,27 +3251,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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -3266,16 +3314,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);
|
||||
}
|
||||
|
|
@ -3406,7 +3470,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;
|
||||
|
||||
|
|
@ -3876,6 +3940,31 @@ void K_InitStumbleIndicator(player_t *player)
|
|||
P_SetTarget(&new->target, player->mo);
|
||||
}
|
||||
|
||||
void K_InitSliptideZipIndicator(player_t *player)
|
||||
{
|
||||
mobj_t *new = NULL;
|
||||
|
||||
if (player == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (player->mo == NULL || P_MobjWasRemoved(player->mo) == true)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (player->stumbleIndicator != NULL && P_MobjWasRemoved(player->sliptideZipIndicator) == false)
|
||||
{
|
||||
P_RemoveMobj(player->sliptideZipIndicator);
|
||||
}
|
||||
|
||||
new = P_SpawnMobjFromMobj(player->mo, 0, 0, 0, MT_SLIPTIDEZIP);
|
||||
|
||||
P_SetTarget(&player->sliptideZipIndicator, new);
|
||||
P_SetTarget(&new->target, player->mo);
|
||||
}
|
||||
|
||||
void K_UpdateStumbleIndicator(player_t *player)
|
||||
{
|
||||
const angle_t fudge = ANG15;
|
||||
|
|
@ -3978,6 +4067,78 @@ void K_UpdateStumbleIndicator(player_t *player)
|
|||
}
|
||||
}
|
||||
|
||||
static boolean K_IsLosingSliptideZip(player_t *player)
|
||||
{
|
||||
if (player->mo == NULL || P_MobjWasRemoved(player->mo) == true)
|
||||
return true;
|
||||
if (!K_Sliptiding(player) && player->drift == 0 && P_IsObjectOnGround(player->mo) && player->sneakertimer == 0)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
void K_UpdateSliptideZipIndicator(player_t *player)
|
||||
{
|
||||
mobj_t *mobj = NULL;
|
||||
|
||||
if (player == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (player->mo == NULL || P_MobjWasRemoved(player->mo) == true)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (player->stumbleIndicator == NULL || P_MobjWasRemoved(player->stumbleIndicator) == true)
|
||||
{
|
||||
K_InitSliptideZipIndicator(player);
|
||||
return;
|
||||
}
|
||||
|
||||
mobj = player->sliptideZipIndicator;
|
||||
angle_t momentumAngle = R_PointToAngle2(0, 0, player->mo->momx, player->mo->momy);
|
||||
|
||||
P_MoveOrigin(mobj, player->mo->x - FixedMul(40*mapobjectscale, FINECOSINE(momentumAngle >> ANGLETOFINESHIFT)),
|
||||
player->mo->y - FixedMul(40*mapobjectscale, FINESINE(momentumAngle >> ANGLETOFINESHIFT)),
|
||||
player->mo->z + (player->mo->height / 2));
|
||||
mobj->angle = momentumAngle + ANGLE_90;
|
||||
P_SetScale(mobj, 3 * player->mo->scale / 2);
|
||||
|
||||
// No stored boost
|
||||
if (player->sliptideZip == 0)
|
||||
{
|
||||
mobj->renderflags |= RF_DONTDRAW;
|
||||
mobj->frame = 7;
|
||||
return;
|
||||
}
|
||||
|
||||
mobj->renderflags &= ~RF_DONTDRAW;
|
||||
|
||||
UINT32 chargeFrame = 7 - min(7, player->sliptideZip / 10);
|
||||
UINT32 decayFrame = min(7, player->sliptideZipDelay / 5);
|
||||
if (max(chargeFrame, decayFrame) > mobj->frame)
|
||||
mobj->frame++;
|
||||
else if (max(chargeFrame, decayFrame) < mobj->frame)
|
||||
mobj->frame--;
|
||||
|
||||
mobj->renderflags &= ~RF_TRANSMASK;
|
||||
mobj->renderflags |= RF_PAPERSPRITE;
|
||||
|
||||
if (K_IsLosingSliptideZip(player))
|
||||
{
|
||||
// Decay timer's ticking
|
||||
mobj->rollangle += 3*ANG30/4;
|
||||
if (leveltime % 2 == 0)
|
||||
mobj->renderflags |= RF_TRANS50;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Storing boost
|
||||
mobj->rollangle += 3*ANG15/4;
|
||||
}
|
||||
}
|
||||
|
||||
static boolean K_LastTumbleBounceCondition(player_t *player)
|
||||
{
|
||||
return (player->tumbleBounces > TUMBLEBOUNCES && player->tumbleHeight < 60);
|
||||
|
|
@ -4195,35 +4356,35 @@ void K_HandleBumperChanges(player_t *player, UINT8 prevBumpers)
|
|||
{
|
||||
player->pflags |= (PF_NOCONTEST|PF_ELIMINATED);
|
||||
}
|
||||
|
||||
P_KillMobj(player->mo, NULL, NULL, DMG_NORMAL);
|
||||
}
|
||||
|
||||
K_CalculateBattleWanted();
|
||||
K_CheckBumpers();
|
||||
}
|
||||
|
||||
void K_DestroyBumpers(player_t *player, UINT8 amount)
|
||||
UINT8 K_DestroyBumpers(player_t *player, UINT8 amount)
|
||||
{
|
||||
UINT8 oldBumpers = player->bumpers;
|
||||
|
||||
if (!(gametyperules & GTR_BUMPERS))
|
||||
{
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
|
||||
amount = min(amount, player->bumpers);
|
||||
|
||||
if (amount == 0)
|
||||
{
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
|
||||
player->bumpers -= amount;
|
||||
K_HandleBumperChanges(player, oldBumpers);
|
||||
|
||||
return amount;
|
||||
}
|
||||
|
||||
void K_TakeBumpersFromPlayer(player_t *player, player_t *victim, UINT8 amount)
|
||||
UINT8 K_TakeBumpersFromPlayer(player_t *player, player_t *victim, UINT8 amount)
|
||||
{
|
||||
UINT8 oldPlayerBumpers = player->bumpers;
|
||||
UINT8 oldVictimBumpers = victim->bumpers;
|
||||
|
|
@ -4232,14 +4393,14 @@ void K_TakeBumpersFromPlayer(player_t *player, player_t *victim, UINT8 amount)
|
|||
|
||||
if (!(gametyperules & GTR_BUMPERS))
|
||||
{
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
|
||||
amount = min(amount, victim->bumpers);
|
||||
|
||||
if (amount == 0)
|
||||
{
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
|
||||
while ((tookBumpers < amount) && (victim->bumpers > 0))
|
||||
|
|
@ -4294,7 +4455,7 @@ void K_TakeBumpersFromPlayer(player_t *player, player_t *victim, UINT8 amount)
|
|||
if (tookBumpers == 0)
|
||||
{
|
||||
// No change occured.
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Play steal sound
|
||||
|
|
@ -4302,6 +4463,8 @@ void K_TakeBumpersFromPlayer(player_t *player, player_t *victim, UINT8 amount)
|
|||
|
||||
K_HandleBumperChanges(player, oldPlayerBumpers);
|
||||
K_HandleBumperChanges(victim, oldVictimBumpers);
|
||||
|
||||
return tookBumpers;
|
||||
}
|
||||
|
||||
#define MINEQUAKEDIST 4096
|
||||
|
|
@ -6983,6 +7146,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;
|
||||
|
||||
|
|
@ -6995,13 +7165,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
|
||||
|
|
@ -7493,7 +7656,7 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
|
|||
if (player->sneakertimer || player->ringboost
|
||||
|| player->driftboost || player->startboost
|
||||
|| player->eggmanexplode || player->trickboost
|
||||
|| player->gateBoost)
|
||||
|| player->gateBoost || player->sliptideZipBoost)
|
||||
{
|
||||
#if 0
|
||||
if (player->invincibilitytimer)
|
||||
|
|
@ -7755,6 +7918,11 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
|
|||
player->startboost--;
|
||||
}
|
||||
|
||||
if (player->sliptideZipBoost > 0 && onground == true)
|
||||
{
|
||||
player->sliptideZipBoost--;
|
||||
}
|
||||
|
||||
if (player->spindashboost)
|
||||
{
|
||||
player->spindashboost--;
|
||||
|
|
@ -8124,6 +8292,8 @@ void K_KartPlayerAfterThink(player_t *player)
|
|||
|
||||
K_UpdateStumbleIndicator(player);
|
||||
|
||||
K_UpdateSliptideZipIndicator(player);
|
||||
|
||||
// Move held objects (Bananas, Orbinaut, etc)
|
||||
K_MoveHeldObjects(player);
|
||||
|
||||
|
|
@ -8479,6 +8649,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();
|
||||
|
|
@ -8845,6 +9021,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))
|
||||
|
|
@ -9201,7 +9386,7 @@ static void K_KartDrift(player_t *player, boolean onground)
|
|||
player->pflags &= ~PF_DRIFTEND;
|
||||
}
|
||||
|
||||
if ((player->handleboost == 0)
|
||||
if ((player->handleboost < (SLIPTIDEHANDLING/2))
|
||||
|| (!player->steering)
|
||||
|| (!player->aizdriftstrat)
|
||||
|| (player->steering > 0) != (player->aizdriftstrat > 0))
|
||||
|
|
@ -9215,6 +9400,8 @@ static void K_KartDrift(player_t *player, boolean onground)
|
|||
{
|
||||
K_SpawnAIZDust(player);
|
||||
|
||||
player->sliptideZip++;
|
||||
|
||||
if (abs(player->aizdrifttilt) < ANGLE_22h)
|
||||
{
|
||||
player->aizdrifttilt =
|
||||
|
|
@ -9232,6 +9419,40 @@ static void K_KartDrift(player_t *player, boolean onground)
|
|||
|
||||
if (!K_Sliptiding(player))
|
||||
{
|
||||
if (K_IsLosingSliptideZip(player) && player->sliptideZip > 0)
|
||||
{
|
||||
player->sliptideZipDelay++;
|
||||
if (player->sliptideZipDelay > TICRATE)
|
||||
{
|
||||
fixed_t maxZipPower = 2*FRACUNIT;
|
||||
fixed_t minZipPower = 1*FRACUNIT;
|
||||
fixed_t powerSpread = maxZipPower - minZipPower;
|
||||
|
||||
int minPenalty = 2*1 + (9-9); // Kinda doing a similar thing to driftspark stage timers here.
|
||||
int maxPenalty = 2*9 + (9-1); // 1/9 gets max, 9/1 gets min, everyone else gets something in between.
|
||||
int penaltySpread = maxPenalty - minPenalty;
|
||||
int yourPenalty = 2*player->kartspeed + (9 - player->kartweight); // And like driftsparks, speed hurts double.
|
||||
|
||||
yourPenalty -= minPenalty; // Normalize; minimum penalty should take away 0 power.
|
||||
|
||||
fixed_t yourPowerReduction = FixedDiv(yourPenalty * FRACUNIT, penaltySpread * FRACUNIT);
|
||||
fixed_t yourPower = maxZipPower - FixedMul(yourPowerReduction, powerSpread);
|
||||
int yourBoost = FixedInt(FixedMul(yourPower, player->sliptideZip * FRACUNIT));
|
||||
|
||||
/*
|
||||
CONS_Printf("SZ %d MZ %d mZ %d pwS %d mP %d MP %d peS %d yPe %d yPR %d yPw %d yB %d\n",
|
||||
player->sliptideZip, maxZipPower, minZipPower, powerSpread, minPenalty, maxPenalty, penaltySpread, yourPenalty, yourPowerReduction, yourPower, yourBoost);
|
||||
*/
|
||||
|
||||
player->sliptideZipBoost += yourBoost;
|
||||
|
||||
K_SpawnDriftBoostExplosion(player, 0);
|
||||
player->sliptideZip = 0;
|
||||
player->sliptideZipDelay = 0;
|
||||
S_StartSound(player->mo, sfx_s3kb6);
|
||||
}
|
||||
}
|
||||
|
||||
player->aizdrifttilt -= player->aizdrifttilt / 4;
|
||||
player->aizdriftturn -= player->aizdriftturn / 4;
|
||||
|
||||
|
|
@ -9240,6 +9461,10 @@ static void K_KartDrift(player_t *player, boolean onground)
|
|||
if (abs(player->aizdriftturn) < ANGLE_11hh)
|
||||
player->aizdriftturn = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
player->sliptideZipDelay = 0;
|
||||
}
|
||||
|
||||
if (player->drift
|
||||
&& ((buttons & BT_BRAKE)
|
||||
|
|
@ -9271,64 +9496,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++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -9386,6 +9626,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
|
||||
//
|
||||
|
|
@ -9680,6 +9943,9 @@ static void K_KartSpindashWind(mobj_t *parent)
|
|||
|
||||
P_SetTarget(&wind->target, parent);
|
||||
|
||||
if (parent->player && parent->player->sliptideZipBoost)
|
||||
P_SetScale(wind, wind->scale * 2);
|
||||
|
||||
if (parent->momx || parent->momy)
|
||||
wind->angle = R_PointToAngle2(0, 0, parent->momx, parent->momy);
|
||||
else
|
||||
|
|
@ -9755,6 +10021,11 @@ static void K_KartSpindash(player_t *player)
|
|||
K_KartSpindashWind(player->mo);
|
||||
}
|
||||
|
||||
if ((player->sliptideZipBoost > 0) && (spawnWind == true))
|
||||
{
|
||||
K_KartSpindashWind(player->mo);
|
||||
}
|
||||
|
||||
if (player->spindashboost > (TICRATE/2))
|
||||
{
|
||||
K_KartSpindashDust(player->mo);
|
||||
|
|
@ -9925,18 +10196,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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -99,12 +99,14 @@ angle_t K_StumbleSlope(angle_t angle, angle_t pitch, angle_t roll);
|
|||
void K_StumblePlayer(player_t *player);
|
||||
boolean K_CheckStumble(player_t *player, angle_t oldPitch, angle_t oldRoll, boolean fromAir);
|
||||
void K_InitStumbleIndicator(player_t *player);
|
||||
void K_InitSliptideZipIndicator(player_t *player);
|
||||
void K_UpdateStumbleIndicator(player_t *player);
|
||||
void K_UpdateSliptideZipIndicator(player_t *player);
|
||||
INT32 K_ExplodePlayer(player_t *player, mobj_t *inflictor, mobj_t *source);
|
||||
void K_DebtStingPlayer(player_t *player, mobj_t *source);
|
||||
void K_HandleBumperChanges(player_t *player, UINT8 prevBumpers);
|
||||
void K_DestroyBumpers(player_t *player, UINT8 amount);
|
||||
void K_TakeBumpersFromPlayer(player_t *player, player_t *victim, UINT8 amount);
|
||||
UINT8 K_DestroyBumpers(player_t *player, UINT8 amount);
|
||||
UINT8 K_TakeBumpersFromPlayer(player_t *player, player_t *victim, UINT8 amount);
|
||||
void K_MineFlashScreen(mobj_t *source);
|
||||
void K_SpawnMineExplosion(mobj_t *source, UINT8 color, tic_t delay);
|
||||
void K_RunFinishLineBeam(void);
|
||||
|
|
@ -139,6 +141,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 +179,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);
|
||||
|
|
|
|||
|
|
@ -571,6 +571,7 @@ void Addons_option_Onchange(void);
|
|||
void M_SortServerList(void);
|
||||
|
||||
void M_MapMenuControls(event_t *ev);
|
||||
void M_UpdateMenuCMD(UINT8 i);
|
||||
boolean M_Responder(event_t *ev);
|
||||
boolean M_MenuButtonPressed(UINT8 pid, UINT32 bt);
|
||||
boolean M_MenuButtonHeld(UINT8 pid, UINT32 bt);
|
||||
|
|
|
|||
|
|
@ -202,6 +202,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
|
||||
//
|
||||
|
|
@ -209,9 +226,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;
|
||||
}
|
||||
|
|
@ -713,7 +730,7 @@ void M_SetMenuDelay(UINT8 i)
|
|||
}
|
||||
}
|
||||
|
||||
static void M_UpdateMenuCMD(UINT8 i)
|
||||
void M_UpdateMenuCMD(UINT8 i)
|
||||
{
|
||||
UINT8 mp = max(1, setup_numplayers);
|
||||
|
||||
|
|
@ -749,19 +766,11 @@ static void M_UpdateMenuCMD(UINT8 i)
|
|||
|
||||
void M_MapMenuControls(event_t *ev)
|
||||
{
|
||||
INT32 i;
|
||||
|
||||
if (ev)
|
||||
{
|
||||
// update keys current state
|
||||
G_MapEventsToControls(ev);
|
||||
}
|
||||
|
||||
// Update menu CMD
|
||||
for (i = 0; i < MAXSPLITSCREENPLAYERS; i++)
|
||||
{
|
||||
M_UpdateMenuCMD(i);
|
||||
}
|
||||
}
|
||||
|
||||
boolean M_MenuButtonPressed(UINT8 pid, UINT32 bt)
|
||||
|
|
|
|||
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
|
||||
|
|
@ -150,8 +150,10 @@ void K_DoIngameRespawn(player_t *player)
|
|||
// FAULT
|
||||
if ((gametyperules & GTR_CIRCUIT) && leveltime < starttime)
|
||||
{
|
||||
if (!(mapheaderinfo[gamemap-1]->levelflags & LF_SECTIONRACE))
|
||||
player->respawn.wp = K_GetFinishLineWaypoint()->prevwaypoints[0];
|
||||
const waypoint_t *finish = K_GetFinishLineWaypoint();
|
||||
|
||||
if (!(mapheaderinfo[gamemap-1]->levelflags & LF_SECTIONRACE) && finish != NULL)
|
||||
player->respawn.wp = finish->prevwaypoints[0];
|
||||
K_DoFault(player);
|
||||
}
|
||||
|
||||
|
|
@ -159,6 +161,7 @@ void K_DoIngameRespawn(player_t *player)
|
|||
player->ringboost = 0;
|
||||
player->driftboost = player->strongdriftboost = 0;
|
||||
player->gateBoost = 0;
|
||||
player->sliptideZip = player->sliptideZipBoost = player->sliptideZipDelay = 0;
|
||||
|
||||
K_TumbleInterrupt(player);
|
||||
P_ResetPlayer(player);
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
@ -578,7 +601,7 @@ static void K_DebugWaypointDrawRadius(waypoint_t *const waypoint)
|
|||
|
||||
spawnX = waypointmobj->x;
|
||||
spawnY = waypointmobj->y;
|
||||
spawnZ = waypointmobj->z + 16*mapobjectscale;
|
||||
spawnZ = waypointmobj->z;
|
||||
|
||||
radiusOrb = P_SpawnMobj(spawnX, spawnY, spawnZ, MT_SPARK);
|
||||
|
||||
|
|
@ -586,8 +609,9 @@ static void K_DebugWaypointDrawRadius(waypoint_t *const waypoint)
|
|||
radiusOrb->tics = 1;
|
||||
|
||||
radiusOrb->frame &= ~FF_TRANSMASK;
|
||||
radiusOrb->frame |= FF_FULLBRIGHT;
|
||||
radiusOrb->frame |= FF_FULLBRIGHT|FF_REVERSESUBTRACT;
|
||||
radiusOrb->color = SKINCOLOR_PURPLE;
|
||||
radiusOrb->renderflags |= RF_ALWAYSONTOP;
|
||||
|
||||
radiusOrb->destscale = FixedDiv(waypointmobj->radius, spriteRadius);
|
||||
P_SetScale(radiusOrb, radiusOrb->destscale);
|
||||
|
|
@ -627,6 +651,7 @@ void K_DebugWaypointsVisualise(void)
|
|||
|
||||
debugmobj->frame &= ~FF_TRANSMASK;
|
||||
debugmobj->frame |= FF_FULLBRIGHT; //FF_TRANS20
|
||||
debugmobj->renderflags |= RF_ALWAYSONTOP;
|
||||
|
||||
// There's a waypoint setup for this mobj! So draw that it's a valid waypoint and draw lines to its connections
|
||||
if (waypoint != NULL)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -308,6 +308,12 @@ static int player_get(lua_State *L)
|
|||
lua_pushinteger(L, plr->tripwireLeniency);
|
||||
else if (fastcmp(field,"tripwireReboundDelay"))
|
||||
lua_pushinteger(L, plr->tripwireReboundDelay);
|
||||
else if (fastcmp(field,"sliptideZip"))
|
||||
lua_pushinteger(L, plr->sliptideZip);
|
||||
else if (fastcmp(field,"sliptideZipDelay"))
|
||||
lua_pushinteger(L, plr->sliptideZipDelay);
|
||||
else if (fastcmp(field,"sliptideZipBoost"))
|
||||
lua_pushinteger(L, plr->sliptideZipBoost);
|
||||
/*
|
||||
else if (fastcmp(field,"itemroulette"))
|
||||
lua_pushinteger(L, plr->itemroulette);
|
||||
|
|
@ -482,12 +488,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);
|
||||
|
|
@ -688,6 +692,12 @@ static int player_set(lua_State *L)
|
|||
plr->tripwireLeniency = luaL_checkinteger(L, 3);
|
||||
else if (fastcmp(field,"tripwireReboundDelay"))
|
||||
plr->tripwireReboundDelay = luaL_checkinteger(L, 3);
|
||||
else if (fastcmp(field,"sliptideZip"))
|
||||
plr->sliptideZip = luaL_checkinteger(L, 3);
|
||||
else if (fastcmp(field,"sliptideZipDelay"))
|
||||
plr->sliptideZipDelay = luaL_checkinteger(L, 3);
|
||||
else if (fastcmp(field,"sliptideZipBoost"))
|
||||
plr->sliptideZipBoost = luaL_checkinteger(L, 3);
|
||||
/*
|
||||
else if (fastcmp(field,"itemroulette"))
|
||||
plr->itemroulette = luaL_checkinteger(L, 3);
|
||||
|
|
@ -848,21 +858,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))
|
||||
|
|
|
|||
|
|
@ -1934,14 +1934,13 @@ static boolean P_KillPlayer(player_t *player, mobj_t *inflictor, mobj_t *source,
|
|||
return false;
|
||||
}
|
||||
|
||||
K_DestroyBumpers(player, 1);
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case DMG_DEATHPIT:
|
||||
// Respawn kill types
|
||||
player->roundconditions.fell_off = true;
|
||||
K_DoIngameRespawn(player);
|
||||
player->mo->health -= K_DestroyBumpers(player, 1);
|
||||
return false;
|
||||
case DMG_SPECTATOR:
|
||||
// disappearifies, but still gotta put items back in play
|
||||
|
|
@ -1998,10 +1997,11 @@ static boolean P_KillPlayer(player_t *player, mobj_t *inflictor, mobj_t *source,
|
|||
P_SetTarget(&boom->target, player->mo);
|
||||
}
|
||||
|
||||
K_DestroyBumpers(player, player->bumpers);
|
||||
player->pflags |= PF_ELIMINATED;
|
||||
}
|
||||
|
||||
K_DestroyBumpers(player, player->bumpers);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -2164,6 +2164,9 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
|
|||
const boolean hardhit = (type == DMG_EXPLODE || type == DMG_KARMA || type == DMG_TUMBLE); // This damage type can do evil stuff like ALWAYS combo
|
||||
INT16 ringburst = 5;
|
||||
|
||||
// Do not die from damage outside of bumpers health system
|
||||
damage = 0;
|
||||
|
||||
// Check if the player is allowed to be damaged!
|
||||
// If not, then spawn the instashield effect instead.
|
||||
if (!force)
|
||||
|
|
@ -2293,12 +2296,12 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
|
|||
K_TryHurtSoundExchange(target, source);
|
||||
|
||||
K_BattleAwardHit(source->player, player, inflictor, takeBumpers);
|
||||
K_TakeBumpersFromPlayer(source->player, player, takeBumpers);
|
||||
damage = K_TakeBumpersFromPlayer(source->player, player, takeBumpers);
|
||||
|
||||
if (type == DMG_KARMA)
|
||||
{
|
||||
// Destroy any remainder bumpers from the player for karma comeback damage
|
||||
K_DestroyBumpers(player, player->bumpers);
|
||||
damage = K_DestroyBumpers(player, player->bumpers);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -2321,7 +2324,7 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
|
|||
}
|
||||
else
|
||||
{
|
||||
K_DestroyBumpers(player, takeBumpers);
|
||||
damage = K_DestroyBumpers(player, takeBumpers);
|
||||
}
|
||||
|
||||
if (!(damagetype & DMG_STEAL))
|
||||
|
|
@ -2407,15 +2410,12 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
|
|||
if (type != DMG_STUMBLE)
|
||||
{
|
||||
player->instashield = 15;
|
||||
K_SetHitLagForObjects(target, inflictor, laglength, true);
|
||||
}
|
||||
|
||||
if (inflictor && !P_MobjWasRemoved(inflictor) && inflictor->type == MT_BANANA)
|
||||
{
|
||||
player->flipDI = true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
@ -2451,16 +2451,16 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
|
|||
|
||||
//K_SetHitLagForObjects(target, inflictor, laglength, true);
|
||||
|
||||
if (player)
|
||||
P_ResetPlayer(target->player);
|
||||
else
|
||||
if (!player)
|
||||
{
|
||||
P_SetMobjState(target, target->info->painstate);
|
||||
|
||||
if (!P_MobjWasRemoved(target))
|
||||
{
|
||||
// if not intent on another player,
|
||||
// chase after this one
|
||||
P_SetTarget(&target->target, source);
|
||||
if (!P_MobjWasRemoved(target))
|
||||
{
|
||||
// if not intent on another player,
|
||||
// chase after this one
|
||||
P_SetTarget(&target->target, source);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -66,6 +66,10 @@ extern "C" {
|
|||
|
||||
#define P_GetPlayerViewHeight(player) (41*player->mo->height/48)
|
||||
|
||||
#ifdef PARANOIA
|
||||
#define SCRAMBLE_REMOVED // Force debug build to crash when Removed mobj is accessed
|
||||
#endif
|
||||
|
||||
typedef enum
|
||||
{
|
||||
THINK_POLYOBJ,
|
||||
|
|
@ -197,6 +201,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);
|
||||
|
|
@ -282,6 +288,9 @@ extern mapthing_t *itemrespawnque[ITEMQUESIZE];
|
|||
extern tic_t itemrespawntime[ITEMQUESIZE];
|
||||
extern size_t iquehead, iquetail;
|
||||
extern consvar_t cv_gravity, cv_movebob;
|
||||
#ifdef SCRAMBLE_REMOVED
|
||||
extern consvar_t cv_scrambleremoved;
|
||||
#endif
|
||||
|
||||
void P_RespawnBattleBoxes(void);
|
||||
mobjtype_t P_GetMobjtype(UINT16 mthingtype);
|
||||
|
|
|
|||
143
src/p_mobj.c
143
src/p_mobj.c
|
|
@ -47,10 +47,14 @@
|
|||
#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);
|
||||
|
||||
consvar_t cv_scrambleremoved = CVAR_INIT ("scrambleremoved", "On", CV_NETVAR, CV_OnOff, NULL);
|
||||
|
||||
actioncache_t actioncachehead;
|
||||
|
||||
static mobj_t *overlaycap = NULL;
|
||||
|
|
@ -3783,15 +3787,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;
|
||||
|
|
@ -5269,6 +5274,11 @@ static boolean P_IsTrackerType(INT32 type)
|
|||
case MT_PLAYER:
|
||||
return true;
|
||||
|
||||
case MT_OVERTIME_CENTER:
|
||||
case MT_MONITOR:
|
||||
case MT_EMERALD:
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
|
@ -6390,6 +6400,7 @@ static void P_MobjSceneryThink(mobj_t *mobj)
|
|||
numx->destscale = scale;
|
||||
}
|
||||
|
||||
#if 0
|
||||
if (K_IsPlayerWanted(mobj->target->player) && mobj->movecount != 1)
|
||||
{
|
||||
mobj_t *wanted = P_SpawnMobj(mobj->x, mobj->y, mobj->z, MT_PLAYERWANTED);
|
||||
|
|
@ -6400,6 +6411,7 @@ static void P_MobjSceneryThink(mobj_t *mobj)
|
|||
mobj->movecount = 1;
|
||||
}
|
||||
else if (!K_IsPlayerWanted(mobj->target->player))
|
||||
#endif
|
||||
mobj->movecount = 0;
|
||||
}
|
||||
else
|
||||
|
|
@ -8092,8 +8104,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
|
||||
|
|
@ -8223,8 +8235,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
|
||||
|
|
@ -8328,8 +8340,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
|
||||
|
|
@ -9491,6 +9503,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);
|
||||
|
|
@ -10468,9 +10540,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;
|
||||
|
|
@ -11056,9 +11125,6 @@ mapthing_t *itemrespawnque[ITEMQUESIZE];
|
|||
tic_t itemrespawntime[ITEMQUESIZE];
|
||||
size_t iquehead, iquetail;
|
||||
|
||||
#ifdef PARANOIA
|
||||
#define SCRAMBLE_REMOVED // Force debug build to crash when Removed mobj is accessed
|
||||
#endif
|
||||
void P_RemoveMobj(mobj_t *mobj)
|
||||
{
|
||||
I_Assert(mobj != NULL);
|
||||
|
|
@ -11194,7 +11260,10 @@ void P_RemoveMobj(mobj_t *mobj)
|
|||
// DBG: set everything in mobj_t to 0xFF instead of leaving it. debug memory error.
|
||||
#ifdef SCRAMBLE_REMOVED
|
||||
// Invalidate mobj_t data to cause crashes if accessed!
|
||||
memset((UINT8 *)mobj + sizeof(thinker_t), 0xff, sizeof(mobj_t) - sizeof(thinker_t));
|
||||
if (cv_scrambleremoved.value)
|
||||
{
|
||||
memset((UINT8 *)mobj + sizeof(thinker_t), 0xff, sizeof(mobj_t) - sizeof(thinker_t));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
@ -11665,7 +11734,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++)
|
||||
{
|
||||
|
|
@ -11690,7 +11761,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;
|
||||
|
|
@ -11754,7 +11826,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);
|
||||
|
|
@ -11798,6 +11870,8 @@ void P_SpawnPlayer(INT32 playernum)
|
|||
|
||||
K_InitStumbleIndicator(p);
|
||||
|
||||
K_InitSliptideZipIndicator(p);
|
||||
|
||||
if (gametyperules & GTR_ITEMARROWS)
|
||||
{
|
||||
mobj_t *overheadarrow = P_SpawnMobj(mobj->x, mobj->y, mobj->z + mobj->height + 16*FRACUNIT, MT_PLAYERARROW);
|
||||
|
|
@ -11833,6 +11907,11 @@ void P_SpawnPlayer(INT32 playernum)
|
|||
p->bumpers = K_StartingBumperCount();
|
||||
K_SpawnPlayerBattleBumpers(p);
|
||||
}
|
||||
|
||||
if (p->bumpers > 0)
|
||||
{
|
||||
mobj->health = p->bumpers;
|
||||
}
|
||||
}
|
||||
|
||||
// I'm not refactoring the loop at the top of this file.
|
||||
|
|
@ -11894,6 +11973,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
|
||||
|
|
@ -11976,7 +12060,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);
|
||||
}
|
||||
|
|
@ -12054,6 +12138,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.
|
||||
|
|
@ -12062,9 +12147,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)
|
||||
|
|
@ -13363,16 +13448,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;
|
||||
|
|
|
|||
|
|
@ -67,6 +67,7 @@ typedef enum
|
|||
SKYBOXCENTER = 0x10,
|
||||
HOVERHYUDORO = 0x20,
|
||||
STUMBLE = 0x40,
|
||||
SLIPTIDEZIP = 0x80
|
||||
} player_saveflags;
|
||||
|
||||
static inline void P_ArchivePlayer(savebuffer_t *save)
|
||||
|
|
@ -137,8 +138,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 +179,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 +198,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)
|
||||
|
|
@ -218,6 +219,9 @@ static void P_NetArchivePlayers(savebuffer_t *save)
|
|||
if (players[i].stumbleIndicator)
|
||||
flags |= STUMBLE;
|
||||
|
||||
if (players[i].sliptideZipIndicator)
|
||||
flags |= SLIPTIDEZIP;
|
||||
|
||||
WRITEUINT16(save->p, flags);
|
||||
|
||||
if (flags & SKYBOXVIEW)
|
||||
|
|
@ -227,7 +231,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);
|
||||
|
|
@ -238,6 +242,9 @@ static void P_NetArchivePlayers(savebuffer_t *save)
|
|||
if (flags & STUMBLE)
|
||||
WRITEUINT32(save->p, players[i].stumbleIndicator->mobjnum);
|
||||
|
||||
if (flags & SLIPTIDEZIP)
|
||||
WRITEUINT32(save->p, players[i].sliptideZipIndicator->mobjnum);
|
||||
|
||||
WRITEUINT32(save->p, (UINT32)players[i].followitem);
|
||||
|
||||
WRITEUINT32(save->p, players[i].charflags);
|
||||
|
|
@ -397,6 +404,10 @@ static void P_NetArchivePlayers(savebuffer_t *save)
|
|||
|
||||
WRITEUINT8(save->p, players[i].tripwireReboundDelay);
|
||||
|
||||
WRITEUINT16(save->p, players[i].sliptideZip);
|
||||
WRITEUINT8(save->p, players[i].sliptideZipDelay);
|
||||
WRITEUINT16(save->p, players[i].sliptideZipBoost);
|
||||
|
||||
// respawnvars_t
|
||||
WRITEUINT8(save->p, players[i].respawn.state);
|
||||
WRITEUINT32(save->p, K_GetWaypointHeapIndex(players[i].respawn.wp));
|
||||
|
|
@ -527,8 +538,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 +579,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 +607,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);
|
||||
|
|
@ -607,6 +618,9 @@ static void P_NetUnArchivePlayers(savebuffer_t *save)
|
|||
if (flags & STUMBLE)
|
||||
players[i].stumbleIndicator = (mobj_t *)(size_t)READUINT32(save->p);
|
||||
|
||||
if (flags & SLIPTIDEZIP)
|
||||
players[i].sliptideZipIndicator = (mobj_t *)(size_t)READUINT32(save->p);
|
||||
|
||||
players[i].followitem = (mobjtype_t)READUINT32(save->p);
|
||||
|
||||
//SetPlayerSkinByNum(i, players[i].skin);
|
||||
|
|
@ -767,6 +781,10 @@ static void P_NetUnArchivePlayers(savebuffer_t *save)
|
|||
|
||||
players[i].tripwireReboundDelay = READUINT8(save->p);
|
||||
|
||||
players[i].sliptideZip = READUINT16(save->p);
|
||||
players[i].sliptideZipDelay = READUINT8(save->p);
|
||||
players[i].sliptideZipBoost = READUINT16(save->p);
|
||||
|
||||
// respawnvars_t
|
||||
players[i].respawn.state = READUINT8(save->p);
|
||||
players[i].respawn.wp = (waypoint_t *)(size_t)READUINT32(save->p);
|
||||
|
|
@ -4684,12 +4702,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)
|
||||
{
|
||||
|
|
@ -4746,6 +4764,13 @@ static void P_RelinkPointers(void)
|
|||
if (!P_SetTarget(&players[i].stumbleIndicator, P_FindNewPosition(temp)))
|
||||
CONS_Debug(DBG_GAMELOGIC, "stumbleIndicator not found on player %d\n", i);
|
||||
}
|
||||
if (players[i].sliptideZipIndicator)
|
||||
{
|
||||
temp = (UINT32)(size_t)players[i].sliptideZipIndicator;
|
||||
players[i].sliptideZipIndicator = NULL;
|
||||
if (!P_SetTarget(&players[i].sliptideZipIndicator, P_FindNewPosition(temp)))
|
||||
CONS_Debug(DBG_GAMELOGIC, "sliptideZipIndicator not found on player %d\n", i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -4983,8 +5008,6 @@ static void P_NetArchiveMisc(savebuffer_t *save, boolean resending)
|
|||
WRITESINT8(save->p, speedscramble);
|
||||
WRITESINT8(save->p, encorescramble);
|
||||
|
||||
WRITEUINT32(save->p, g_hiscore);
|
||||
|
||||
// battleovertime_t
|
||||
WRITEUINT16(save->p, battleovertime.enabled);
|
||||
WRITEFIXED(save->p, battleovertime.radius);
|
||||
|
|
@ -5154,8 +5177,6 @@ static inline boolean P_NetUnArchiveMisc(savebuffer_t *save, boolean reloading)
|
|||
speedscramble = READSINT8(save->p);
|
||||
encorescramble = READSINT8(save->p);
|
||||
|
||||
g_hiscore = READUINT32(save->p);
|
||||
|
||||
// battleovertime_t
|
||||
battleovertime.enabled = READUINT16(save->p);
|
||||
battleovertime.radius = READFIXED(save->p);
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
@ -7109,8 +7115,6 @@ static void P_InitLevelSettings(void)
|
|||
franticitems = (boolean)cv_kartfrantic.value;
|
||||
}
|
||||
|
||||
g_hiscore = 0;
|
||||
|
||||
memset(&battleovertime, 0, sizeof(struct battleovertime));
|
||||
speedscramble = encorescramble = -1;
|
||||
|
||||
|
|
@ -7359,7 +7363,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 +7372,8 @@ static void P_InitPlayers(void)
|
|||
G_SpawnPlayer(i);
|
||||
}
|
||||
}
|
||||
|
||||
K_UpdateAllPlayerPositions();
|
||||
}
|
||||
|
||||
static void P_InitGametype(void)
|
||||
|
|
@ -7377,6 +7383,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 +7445,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];
|
||||
|
|
@ -7698,7 +7724,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));
|
||||
|
||||
|
|
@ -7706,7 +7732,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)
|
||||
{
|
||||
|
|
@ -7746,8 +7772,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);
|
||||
|
|
@ -7949,7 +7978,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?
|
||||
{
|
||||
|
|
@ -7962,27 +7991,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
|
|
@ -2008,6 +2008,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)
|
||||
{
|
||||
|
|
@ -2035,32 +2069,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++)
|
||||
|
|
@ -2413,7 +2423,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)
|
||||
{
|
||||
|
|
@ -3002,35 +3012,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;
|
||||
|
||||
|
|
@ -800,10 +786,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);
|
||||
|
||||
|
|
@ -872,19 +860,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))
|
||||
{
|
||||
|
|
|
|||
62
src/p_user.c
62
src/p_user.c
|
|
@ -58,6 +58,9 @@
|
|||
#include "k_terrain.h" // K_SpawnSplashForMobj
|
||||
#include "k_color.h"
|
||||
#include "k_follower.h"
|
||||
#include "k_battle.h"
|
||||
#include "k_rank.h"
|
||||
#include "k_director.h"
|
||||
|
||||
#ifdef HW3SOUND
|
||||
#include "hardware/hw3sound.h"
|
||||
|
|
@ -1294,7 +1297,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)
|
||||
{
|
||||
|
|
@ -1363,6 +1366,7 @@ void P_DoPlayerExit(player_t *player)
|
|||
if (RINGTOTAL(player) > 0)
|
||||
{
|
||||
player->totalring += RINGTOTAL(player);
|
||||
grandprixinfo.rank.rings += RINGTOTAL(player);
|
||||
|
||||
extra = player->totalring / lifethreshold;
|
||||
|
||||
|
|
@ -1373,6 +1377,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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2783,11 +2797,23 @@ static void P_DeathThink(player_t *player)
|
|||
}
|
||||
}
|
||||
|
||||
if ((player->pflags & PF_ELIMINATED) && (gametyperules & GTR_BUMPERS))
|
||||
{
|
||||
playerGone = true;
|
||||
}
|
||||
|
||||
if (playerGone == false && player->deadtimer > TICRATE)
|
||||
{
|
||||
player->playerstate = PST_REBORN;
|
||||
}
|
||||
|
||||
// TODO: support splitscreen
|
||||
// Spectate another player after 2 seconds
|
||||
if (player == &players[consoleplayer] && playerGone == true && (gametyperules & GTR_BUMPERS) && player->deadtimer == 2*TICRATE)
|
||||
{
|
||||
K_ToggleDirector(true);
|
||||
}
|
||||
|
||||
// Keep time rolling
|
||||
if (!(player->exiting || mapreset) && !(player->pflags & PF_NOCONTEST) && !stoppedclock)
|
||||
{
|
||||
|
|
@ -3680,10 +3706,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++)
|
||||
|
|
@ -4007,6 +4033,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
|
||||
//
|
||||
|
|
@ -4030,18 +4075,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.
|
||||
|
|
|
|||
105
src/r_debug.cpp
Normal file
105
src/r_debug.cpp
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
// RING RACERS
|
||||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) 2023 by James Robert Roman.
|
||||
//
|
||||
// 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 r_debug.cpp
|
||||
/// \brief Software renderer debugging
|
||||
|
||||
#include <algorithm> // std::clamp
|
||||
|
||||
#include "cxxutil.hpp"
|
||||
#include "r_debug_detail.hpp"
|
||||
|
||||
#include "command.h"
|
||||
#include "m_fixed.h"
|
||||
#include "r_draw.h"
|
||||
#include "r_main.h"
|
||||
|
||||
using namespace srb2::r_debug;
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
CV_PossibleValue_t contrast_cons_t[] = {{-FRACUNIT, "MIN"}, {FRACUNIT, "MAX"}, {}};
|
||||
|
||||
}; // namespace
|
||||
|
||||
consvar_t cv_debugrender_contrast =
|
||||
CVAR_INIT("debugrender_contrast", "0.0", CV_CHEAT | CV_FLOAT, contrast_cons_t, nullptr);
|
||||
|
||||
consvar_t cv_debugrender_spriteclip = CVAR_INIT("debugrender_spriteclip", "Off", CV_CHEAT, CV_OnOff, nullptr);
|
||||
|
||||
UINT32 debugrender_highlight;
|
||||
|
||||
void R_CheckDebugHighlight(debugrender_highlight_t k)
|
||||
{
|
||||
// If highlighting is enabled for anything, surfaces
|
||||
// must be highlighted in one of two colors, depending on
|
||||
// whether they fall under focus of the debug.
|
||||
|
||||
if (debugrender_highlight)
|
||||
{
|
||||
r8_flatcolor = (debugrender_highlight & (1 << k)) ? detail::kHighlightOptions[k].color : 0x1F;
|
||||
}
|
||||
}
|
||||
|
||||
INT32 R_AdjustLightLevel(INT32 light)
|
||||
{
|
||||
if (!debugrender_highlight && cv_debugrender_contrast.value == 0)
|
||||
{
|
||||
return light;
|
||||
}
|
||||
|
||||
constexpr fixed_t kRange = (LIGHTLEVELS - 1) * FRACUNIT;
|
||||
const fixed_t adjust = FixedMul(cv_debugrender_contrast.value, kRange);
|
||||
|
||||
if (debugrender_highlight)
|
||||
{
|
||||
light = (kRange / 2) - (adjust / 2);
|
||||
|
||||
SRB2_ASSERT(light >= 0);
|
||||
SRB2_ASSERT(light <= kRange);
|
||||
}
|
||||
else
|
||||
{
|
||||
light = std::clamp((light * FRACUNIT) - adjust, 0, kRange);
|
||||
}
|
||||
|
||||
return light / FRACUNIT;
|
||||
}
|
||||
|
||||
void Command_Debugrender_highlight(void)
|
||||
{
|
||||
const bool changes = COM_Argc() > 1;
|
||||
|
||||
if (!CV_CheatsEnabled())
|
||||
{
|
||||
CONS_Printf("Cheats must be enabled.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (changes)
|
||||
{
|
||||
const char* arg = COM_Argv(1);
|
||||
|
||||
debugrender_highlight = 0; // always reset
|
||||
|
||||
if (COM_Argc() > 2 ||
|
||||
// approximate match "none"
|
||||
strncasecmp(arg, "none", strlen(arg)))
|
||||
{
|
||||
char* p = COM_Args();
|
||||
|
||||
while (p)
|
||||
{
|
||||
p = detail::parse_highlight_arg(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
detail::highlight_help(changes);
|
||||
}
|
||||
42
src/r_debug_detail.hpp
Normal file
42
src/r_debug_detail.hpp
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
// RING RACERS
|
||||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) 2023 by James Robert Roman.
|
||||
//
|
||||
// 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 r_debug_detail.cpp
|
||||
/// \brief Software renderer debugging, internal header
|
||||
|
||||
#ifndef __R_DEBUG_DETAIL__
|
||||
#define __R_DEBUG_DETAIL__
|
||||
|
||||
#include "r_main.h"
|
||||
|
||||
namespace srb2::r_debug::detail
|
||||
{
|
||||
|
||||
struct HighlightDesc
|
||||
{
|
||||
uint8_t color;
|
||||
const char* label;
|
||||
const char* description;
|
||||
};
|
||||
|
||||
constexpr HighlightDesc kHighlightOptions[NUM_SW_HI] = {
|
||||
{0x96, "planes", "Sector floor/ceiling"},
|
||||
{0x49, "fofplanes", "FOF top/bottom"},
|
||||
{0xB6, "fofsides", "FOF sides"},
|
||||
{0x7A, "midtextures", "Two-sided midtexture"},
|
||||
{0xC9, "walls", "Sector upper/lower texture, one-sided midtexture"},
|
||||
{0x23, "sprites", "Sprites"},
|
||||
{0x0F, "sky", "Sky texture"}};
|
||||
|
||||
char* skip_alnum(char* p, int mode);
|
||||
char* parse_highlight_arg(char* p);
|
||||
void highlight_help(bool only_on);
|
||||
|
||||
}; // srb2::r_debug::detail
|
||||
|
||||
#endif // __R_DEBUG_DETAIL__
|
||||
95
src/r_debug_parser.cpp
Normal file
95
src/r_debug_parser.cpp
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
// RING RACERS
|
||||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) 2023 by James Robert Roman.
|
||||
//
|
||||
// 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 r_debug_parser.cpp
|
||||
/// \brief Helper functions for the debugrender_highlight command
|
||||
|
||||
#include "r_debug_detail.hpp"
|
||||
|
||||
#include "doomdef.h"
|
||||
#include "r_main.h"
|
||||
|
||||
using namespace srb2::r_debug;
|
||||
using namespace srb2::r_debug::detail;
|
||||
|
||||
char* detail::skip_alnum(char* p, int mode)
|
||||
{
|
||||
while (*p != '\0' && !isalnum(*p) == !mode)
|
||||
{
|
||||
p++;
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
char* detail::parse_highlight_arg(char* p)
|
||||
{
|
||||
INT32 k;
|
||||
const HighlightDesc* key;
|
||||
|
||||
const auto old = static_cast<debugrender_highlight_t>(debugrender_highlight);
|
||||
|
||||
char* t;
|
||||
int c;
|
||||
|
||||
p = skip_alnum(p, 0); // skip "whitespace"
|
||||
|
||||
if (*p == '\0')
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
t = skip_alnum(p, 1); // find end of word
|
||||
|
||||
c = *t; // save to restore afterward
|
||||
*t = '\0'; // isolate word string
|
||||
|
||||
for (k = 0; (key = &kHighlightOptions[k]), k < NUM_SW_HI; ++k)
|
||||
{
|
||||
// allow an approximate match
|
||||
if (!strncasecmp(p, key->label, (t - p)))
|
||||
{
|
||||
debugrender_highlight |= (1 << k);
|
||||
// keep going to match multiple with same
|
||||
// prefix
|
||||
}
|
||||
}
|
||||
|
||||
if (debugrender_highlight == old)
|
||||
{
|
||||
// no change? Foolish user
|
||||
CONS_Alert(CONS_WARNING, "\"%s\" makes no sense\n", p);
|
||||
}
|
||||
|
||||
*t = c; // restore
|
||||
|
||||
return t; // skip to end of word
|
||||
}
|
||||
|
||||
void detail::highlight_help(bool only_on)
|
||||
{
|
||||
int32_t k;
|
||||
const HighlightDesc* key;
|
||||
|
||||
for (k = 0; (key = &kHighlightOptions[k]), k < NUM_SW_HI; ++k)
|
||||
{
|
||||
const bool on = (debugrender_highlight & (1 << k)) != 0;
|
||||
|
||||
if (!only_on || on)
|
||||
{
|
||||
CONS_Printf("%s\x80 \x87%s\x80 - %s\n", on ? "\x83 ON" : "\x85OFF", key->label, key->description);
|
||||
}
|
||||
}
|
||||
|
||||
if (!only_on)
|
||||
{
|
||||
CONS_Printf("\nYou can change the highlights by using a command like:\n\n"
|
||||
"\x87 debugrender_highlight planes sprites\n"
|
||||
"\x87 debugrender_highlight none\n");
|
||||
}
|
||||
}
|
||||
|
|
@ -932,6 +932,8 @@ typedef enum
|
|||
|
||||
RF_NOCOLORMAPS = 0x00000400, // Sprite is not drawn with colormaps
|
||||
|
||||
RF_ALWAYSONTOP = 0x00000800, // Sprite is drawn on top of level geometry
|
||||
|
||||
RF_SPRITETYPEMASK = 0x00003000, // --Different sprite types
|
||||
RF_PAPERSPRITE = 0x00001000, // Paper sprite
|
||||
RF_FLOORSPRITE = 0x00002000, // Floor sprite
|
||||
|
|
|
|||
|
|
@ -68,6 +68,8 @@ INT32 columnofs[MAXVIDWIDTH*4];
|
|||
|
||||
UINT8 *topleft;
|
||||
|
||||
UINT8 r8_flatcolor;
|
||||
|
||||
// =========================================================================
|
||||
// COLUMN DRAWING CODE STUFF
|
||||
// =========================================================================
|
||||
|
|
@ -81,6 +83,7 @@ UINT8 dc_hires; // under MSVC boolean is a byte, while on other systems, it a bi
|
|||
// soo lets make it a byte on all system for the ASM code
|
||||
UINT8 *dc_source;
|
||||
UINT8 *dc_brightmap;
|
||||
UINT8 *dc_lightmap;
|
||||
|
||||
// -----------------------
|
||||
// translucency stuff here
|
||||
|
|
@ -638,6 +641,7 @@ void R_DrawViewBorder(void)
|
|||
|
||||
#include "r_draw8.c"
|
||||
#include "r_draw8_npo2.c"
|
||||
#include "r_draw8_flat.c"
|
||||
|
||||
// ==========================================================================
|
||||
// INCLUDE 16bpp DRAWING CODE HERE
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ extern UINT8 *ylookup3[MAXVIDHEIGHT*4];
|
|||
extern UINT8 *ylookup4[MAXVIDHEIGHT*4];
|
||||
extern INT32 columnofs[MAXVIDWIDTH*4];
|
||||
extern UINT8 *topleft;
|
||||
extern UINT8 r8_flatcolor;
|
||||
|
||||
// -------------------------
|
||||
// COLUMN DRAWING CODE STUFF
|
||||
|
|
@ -43,6 +44,7 @@ extern UINT8 dc_hires;
|
|||
|
||||
extern UINT8 *dc_source; // first pixel in a column
|
||||
extern UINT8 *dc_brightmap; // brightmap texture column, can be NULL
|
||||
extern UINT8 *dc_lightmap; // lighting only
|
||||
|
||||
// translucency stuff here
|
||||
extern UINT8 *dc_transmap;
|
||||
|
|
@ -76,6 +78,8 @@ extern UINT8 *ds_source;
|
|||
extern UINT8 *ds_brightmap;
|
||||
extern UINT8 *ds_transmap;
|
||||
|
||||
extern UINT8 ds_flatcolor;
|
||||
|
||||
struct floatv3_t {
|
||||
float x, y, z;
|
||||
};
|
||||
|
|
@ -232,6 +236,11 @@ void R_DrawTiltedTranslucentFloorSprite_NPO2_8(void);
|
|||
void R_DrawTranslucentWaterSpan_NPO2_8(void);
|
||||
void R_DrawTiltedTranslucentWaterSpan_NPO2_8(void);
|
||||
|
||||
// Debugging - highlight surfaces in flat colors
|
||||
void R_DrawColumn_Flat_8(void);
|
||||
void R_DrawSpan_Flat_8(void);
|
||||
void R_DrawTiltedSpan_Flat_8(void);
|
||||
|
||||
#ifdef USEASM
|
||||
void ASMCALL R_DrawColumn_8_ASM(void);
|
||||
void ASMCALL R_DrawShadeColumn_8_ASM(void);
|
||||
|
|
|
|||
79
src/r_draw8_flat.c
Normal file
79
src/r_draw8_flat.c
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
// SONIC ROBO BLAST 2
|
||||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) 1998-2000 by DooM Legacy Team.
|
||||
// Copyright (C) 1999-2020 by Sonic Team Junior.
|
||||
// Copyright (C) 2023 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 r_draw8_flat.c
|
||||
/// \brief 8bpp span/column drawer functions for debugging (draws in flat colors only)
|
||||
/// \note no includes because this is included as part of r_draw.c
|
||||
|
||||
void R_DrawColumn_Flat_8 (void)
|
||||
{
|
||||
INT32 count;
|
||||
UINT8 color = dc_lightmap[r8_flatcolor];
|
||||
register UINT8 *dest;
|
||||
|
||||
count = dc_yh - dc_yl;
|
||||
|
||||
if (count < 0) // Zero length, column does not exceed a pixel.
|
||||
return;
|
||||
|
||||
#ifdef RANGECHECK
|
||||
if ((unsigned)dc_x >= (unsigned)vid.width || dc_yl < 0 || dc_yh >= vid.height)
|
||||
return;
|
||||
#endif
|
||||
|
||||
// Framebuffer destination address.
|
||||
// Use ylookup LUT to avoid multiply with ScreenWidth.
|
||||
// Use columnofs LUT for subwindows?
|
||||
|
||||
//dest = ylookup[dc_yl] + columnofs[dc_x];
|
||||
dest = &topleft[dc_yl*vid.width + dc_x];
|
||||
|
||||
count++;
|
||||
|
||||
do
|
||||
{
|
||||
*dest = color;
|
||||
dest += vid.width;
|
||||
} while (--count);
|
||||
}
|
||||
|
||||
void R_DrawSpan_Flat_8 (void)
|
||||
{
|
||||
UINT8 *dest = ylookup[ds_y] + columnofs[ds_x1];
|
||||
|
||||
memset(dest, ds_colormap[r8_flatcolor], (ds_x2 - ds_x1) + 1);
|
||||
}
|
||||
|
||||
void R_DrawTiltedSpan_Flat_8 (void)
|
||||
{
|
||||
// x1, x2 = ds_x1, ds_x2
|
||||
int width = ds_x2 - ds_x1;
|
||||
double iz = ds_szp->z + ds_szp->y*(centery-ds_y) + ds_szp->x*(ds_x1-centerx);
|
||||
|
||||
UINT8 *dest = ylookup[ds_y];
|
||||
|
||||
// Lighting is simple. It's just linear interpolation from start to end
|
||||
{
|
||||
float planelightfloat = PLANELIGHTFLOAT;
|
||||
float lightstart, lightend;
|
||||
|
||||
lightend = (iz + ds_szp->x*width) * planelightfloat;
|
||||
lightstart = iz * planelightfloat;
|
||||
|
||||
R_CalcTiltedLighting(FLOAT_TO_FIXED(lightstart), FLOAT_TO_FIXED(lightend));
|
||||
//CONS_Printf("tilted lighting %f to %f (foc %f)\n", lightstart, lightend, focallengthf);
|
||||
}
|
||||
|
||||
while (ds_x1 <= ds_x2)
|
||||
{
|
||||
dest[ds_x1] = planezlight[tiltlighting[ds_x1]][r8_flatcolor];
|
||||
ds_x1++;
|
||||
}
|
||||
}
|
||||
49
src/r_main.c
49
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)
|
||||
|
|
@ -1651,9 +1666,19 @@ void R_RegisterEngineStuff(void)
|
|||
CV_RegisterVar(&cv_maxportals);
|
||||
|
||||
CV_RegisterVar(&cv_movebob);
|
||||
#ifdef SCRAMBLE_REMOVED
|
||||
CV_RegisterVar(&cv_scrambleremoved);
|
||||
#endif
|
||||
|
||||
// Frame interpolation/uncapped
|
||||
CV_RegisterVar(&cv_fpscap);
|
||||
|
||||
CV_RegisterVar(&cv_drawpickups);
|
||||
|
||||
// debugging
|
||||
|
||||
CV_RegisterVar(&cv_debugrender_contrast);
|
||||
CV_RegisterVar(&cv_debugrender_spriteclip);
|
||||
|
||||
COM_AddCommand("debugrender_highlight", Command_Debugrender_highlight);
|
||||
}
|
||||
|
|
|
|||
25
src/r_main.h
25
src/r_main.h
|
|
@ -123,6 +123,31 @@ extern consvar_t cv_skybox;
|
|||
extern consvar_t cv_tailspickup;
|
||||
extern consvar_t cv_drawpickups;
|
||||
|
||||
// debugging
|
||||
|
||||
typedef enum {
|
||||
SW_HI_PLANES,
|
||||
SW_HI_FOFPLANES,
|
||||
SW_HI_FOFSIDES,
|
||||
SW_HI_MIDTEXTURES,
|
||||
SW_HI_WALLS,
|
||||
SW_HI_THINGS,
|
||||
SW_HI_SKY,
|
||||
|
||||
NUM_SW_HI
|
||||
} debugrender_highlight_t;
|
||||
|
||||
extern UINT32 debugrender_highlight;
|
||||
|
||||
void R_CheckDebugHighlight(debugrender_highlight_t type);
|
||||
INT32 R_AdjustLightLevel(INT32 light);
|
||||
|
||||
void Command_Debugrender_highlight(void);
|
||||
|
||||
extern consvar_t
|
||||
cv_debugrender_contrast,
|
||||
cv_debugrender_spriteclip;
|
||||
|
||||
// Called by startup code.
|
||||
void R_Init(void);
|
||||
|
||||
|
|
|
|||
|
|
@ -208,14 +208,17 @@ static void R_MapPlane(INT32 y, INT32 x1, INT32 x2)
|
|||
pindex = MAXLIGHTZ - 1;
|
||||
ds_colormap = planezlight[pindex];
|
||||
|
||||
if (currentplane->extra_colormap)
|
||||
ds_colormap = currentplane->extra_colormap->colormap + (ds_colormap - colormaps);
|
||||
|
||||
ds_fullbright = colormaps;
|
||||
if (encoremap && !currentplane->noencore)
|
||||
if (!debugrender_highlight)
|
||||
{
|
||||
ds_colormap += COLORMAP_REMAPOFFSET;
|
||||
ds_fullbright += COLORMAP_REMAPOFFSET;
|
||||
if (currentplane->extra_colormap)
|
||||
ds_colormap = currentplane->extra_colormap->colormap + (ds_colormap - colormaps);
|
||||
|
||||
ds_fullbright = colormaps;
|
||||
if (encoremap && !currentplane->noencore)
|
||||
{
|
||||
ds_colormap += COLORMAP_REMAPOFFSET;
|
||||
ds_fullbright += COLORMAP_REMAPOFFSET;
|
||||
}
|
||||
}
|
||||
|
||||
ds_y = y;
|
||||
|
|
@ -613,6 +616,8 @@ static void R_DrawSkyPlane(visplane_t *pl)
|
|||
INT32 x;
|
||||
INT32 angle;
|
||||
|
||||
R_CheckDebugHighlight(SW_HI_SKY);
|
||||
|
||||
// Reset column drawer function (note: couldn't we just call walldrawerfunc directly?)
|
||||
// (that is, unless we'll need to switch drawers in future for some reason)
|
||||
R_SetColumnFunc(BASEDRAWFUNC, false);
|
||||
|
|
@ -631,6 +636,7 @@ static void R_DrawSkyPlane(visplane_t *pl)
|
|||
dc_colormap += COLORMAP_REMAPOFFSET;
|
||||
dc_fullbright += COLORMAP_REMAPOFFSET;
|
||||
}
|
||||
dc_lightmap = colormaps;
|
||||
dc_texturemid = skytexturemid;
|
||||
dc_texheight = textureheight[skytexture]
|
||||
>>FRACBITS;
|
||||
|
|
@ -831,6 +837,7 @@ void R_DrawSinglePlane(visplane_t *pl)
|
|||
INT32 x, stop;
|
||||
ffloor_t *rover;
|
||||
INT32 type, spanfunctype = BASEDRAWFUNC;
|
||||
debugrender_highlight_t debug = 0;
|
||||
void (*mapfunc)(INT32, INT32, INT32) = R_MapPlane;
|
||||
|
||||
if (!(pl->minx <= pl->maxx))
|
||||
|
|
@ -911,10 +918,16 @@ void R_DrawSinglePlane(visplane_t *pl)
|
|||
light = (pl->lightlevel >> LIGHTSEGSHIFT);
|
||||
}
|
||||
else light = (pl->lightlevel >> LIGHTSEGSHIFT);
|
||||
|
||||
debug = SW_HI_FOFPLANES;
|
||||
}
|
||||
else
|
||||
{
|
||||
light = (pl->lightlevel >> LIGHTSEGSHIFT);
|
||||
|
||||
debug = SW_HI_PLANES;
|
||||
}
|
||||
|
||||
#ifndef NOWATER
|
||||
if (pl->ripple)
|
||||
{
|
||||
|
|
@ -1030,6 +1043,8 @@ void R_DrawSinglePlane(visplane_t *pl)
|
|||
if (light < 0)
|
||||
light = 0;
|
||||
|
||||
light = R_AdjustLightLevel(light);
|
||||
|
||||
if (pl->slope)
|
||||
{
|
||||
mapfunc = R_MapTiltedPlane;
|
||||
|
|
@ -1083,6 +1098,8 @@ void R_DrawSinglePlane(visplane_t *pl)
|
|||
}
|
||||
|
||||
|
||||
R_CheckDebugHighlight(debug);
|
||||
|
||||
// Use the correct span drawer depending on the powers-of-twoness
|
||||
R_SetSpanFunc(spanfunctype, !ds_powersoftwo, ds_brightmap != NULL);
|
||||
|
||||
|
|
|
|||
40
src/r_segs.c
40
src/r_segs.c
|
|
@ -185,6 +185,8 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2)
|
|||
transtable = 0;
|
||||
}
|
||||
|
||||
R_CheckDebugHighlight(SW_HI_MIDTEXTURES);
|
||||
|
||||
if (blendmode == AST_FOG)
|
||||
{
|
||||
R_SetColumnFunc(COLDRAWFUNC_FOG, bmnum != 0);
|
||||
|
|
@ -298,6 +300,8 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2)
|
|||
else if (P_ApplyLightOffset(lightnum))
|
||||
lightnum += curline->lightOffset;
|
||||
|
||||
lightnum = R_AdjustLightLevel(lightnum);
|
||||
|
||||
if (lightnum < 0)
|
||||
walllights = scalelight[0];
|
||||
else if (lightnum >= LIGHTLEVELS)
|
||||
|
|
@ -413,12 +417,14 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2)
|
|||
if ((rlight->flags & FOF_NOSHADE))
|
||||
continue;
|
||||
|
||||
if (rlight->lightnum < 0)
|
||||
lightnum = R_AdjustLightLevel(rlight->lightnum);
|
||||
|
||||
if (lightnum < 0)
|
||||
xwalllights = scalelight[0];
|
||||
else if (rlight->lightnum >= LIGHTLEVELS)
|
||||
else if (lightnum >= LIGHTLEVELS)
|
||||
xwalllights = scalelight[LIGHTLEVELS-1];
|
||||
else
|
||||
xwalllights = scalelight[rlight->lightnum];
|
||||
xwalllights = scalelight[lightnum];
|
||||
|
||||
pindex = FixedMul(spryscale, LIGHTRESOLUTIONFIX)>>LIGHTSCALESHIFT;
|
||||
|
||||
|
|
@ -436,6 +442,7 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2)
|
|||
if (height <= windowtop)
|
||||
{
|
||||
dc_colormap = rlight->rcolormap;
|
||||
dc_lightmap = xwalllights[pindex];
|
||||
dc_fullbright = colormaps;
|
||||
if (encoremap && !(ldef->flags & ML_TFERLINE))
|
||||
{
|
||||
|
|
@ -461,6 +468,7 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2)
|
|||
colfunc_2s(col, bmCol, -1);
|
||||
windowtop = windowbottom + 1;
|
||||
dc_colormap = rlight->rcolormap;
|
||||
dc_lightmap = xwalllights[pindex];
|
||||
dc_fullbright = colormaps;
|
||||
if (encoremap && !(ldef->flags & ML_TFERLINE))
|
||||
{
|
||||
|
|
@ -483,6 +491,7 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2)
|
|||
pindex = MAXLIGHTSCALE - 1;
|
||||
|
||||
dc_colormap = walllights[pindex];
|
||||
dc_lightmap = walllights[pindex];
|
||||
dc_fullbright = colormaps;
|
||||
if (encoremap && !(ldef->flags & ML_TFERLINE))
|
||||
{
|
||||
|
|
@ -638,6 +647,8 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
|
|||
texnum = R_GetTextureNum(sides[pfloor->master->sidenum[0]].midtexture);
|
||||
bmnum = R_GetTextureBrightmap(texnum);
|
||||
|
||||
R_CheckDebugHighlight(SW_HI_FOFSIDES);
|
||||
|
||||
R_SetColumnFunc(BASEDRAWFUNC, bmnum != 0);
|
||||
|
||||
if (pfloor->master->flags & ML_TFERLINE)
|
||||
|
|
@ -789,6 +800,8 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
|
|||
else if (P_ApplyLightOffset(lightnum))
|
||||
lightnum += curline->lightOffset;
|
||||
|
||||
lightnum = R_AdjustLightLevel(lightnum);
|
||||
|
||||
if (lightnum < 0)
|
||||
walllights = scalelight[0];
|
||||
else if (lightnum >= LIGHTLEVELS)
|
||||
|
|
@ -954,16 +967,15 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
|
|||
fixed_t height;
|
||||
fixed_t bheight = 0;
|
||||
INT32 solid = 0;
|
||||
INT32 lighteffect = 0;
|
||||
|
||||
for (i = 0; i < dc_numlights; i++)
|
||||
{
|
||||
// Check if the current light effects the colormap/lightlevel
|
||||
rlight = &dc_lightlist[i];
|
||||
lighteffect = !(dc_lightlist[i].flags & FOF_NOSHADE);
|
||||
if (lighteffect)
|
||||
xwalllights = NULL;
|
||||
if (!(dc_lightlist[i].flags & FOF_NOSHADE))
|
||||
{
|
||||
lightnum = rlight->lightnum;
|
||||
lightnum = R_AdjustLightLevel(rlight->lightnum);
|
||||
|
||||
if (lightnum < 0)
|
||||
xwalllights = scalelight[0];
|
||||
|
|
@ -1024,9 +1036,10 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
|
|||
|
||||
if (height <= windowtop)
|
||||
{
|
||||
if (lighteffect)
|
||||
if (xwalllights)
|
||||
{
|
||||
dc_colormap = rlight->rcolormap;
|
||||
dc_lightmap = xwalllights[pindex];
|
||||
dc_fullbright = colormaps;
|
||||
if (encoremap && !(curline->linedef->flags & ML_TFERLINE))
|
||||
{
|
||||
|
|
@ -1060,9 +1073,10 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
|
|||
windowtop = bheight;
|
||||
else
|
||||
windowtop = windowbottom + 1;
|
||||
if (lighteffect)
|
||||
if (xwalllights)
|
||||
{
|
||||
dc_colormap = rlight->rcolormap;
|
||||
dc_lightmap = xwalllights[pindex];
|
||||
dc_fullbright = colormaps;
|
||||
if (encoremap && !(curline->linedef->flags & ML_TFERLINE))
|
||||
{
|
||||
|
|
@ -1087,6 +1101,7 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
|
|||
pindex = MAXLIGHTSCALE - 1;
|
||||
|
||||
dc_colormap = walllights[pindex];
|
||||
dc_lightmap = walllights[pindex];
|
||||
dc_fullbright = colormaps;
|
||||
|
||||
if (encoremap && !(curline->linedef->flags & ML_TFERLINE))
|
||||
|
|
@ -1353,6 +1368,7 @@ static void R_RenderSegLoop (void)
|
|||
pindex = MAXLIGHTSCALE-1;
|
||||
|
||||
dc_colormap = walllights[pindex];
|
||||
dc_lightmap = walllights[pindex];
|
||||
dc_fullbright = colormaps;
|
||||
if (encoremap && !(curline->linedef->flags & ML_TFERLINE))
|
||||
{
|
||||
|
|
@ -1379,6 +1395,8 @@ static void R_RenderSegLoop (void)
|
|||
else if (P_ApplyLightOffset(lightnum))
|
||||
lightnum += curline->lightOffset;
|
||||
|
||||
lightnum = R_AdjustLightLevel(lightnum);
|
||||
|
||||
if (lightnum < 0)
|
||||
xwalllights = scalelight[0];
|
||||
else if (lightnum >= LIGHTLEVELS)
|
||||
|
|
@ -1618,6 +1636,8 @@ void R_StoreWallRange(INT32 start, INT32 stop)
|
|||
memset(&segleft, 0x00, sizeof(segleft));
|
||||
memset(&segright, 0x00, sizeof(segright));
|
||||
|
||||
R_CheckDebugHighlight(SW_HI_WALLS);
|
||||
|
||||
R_SetColumnFunc(BASEDRAWFUNC, false);
|
||||
|
||||
if (ds_p == drawsegs+maxdrawsegs)
|
||||
|
|
@ -2425,6 +2445,8 @@ void R_StoreWallRange(INT32 start, INT32 stop)
|
|||
if (P_ApplyLightOffset(lightnum))
|
||||
lightnum += curline->lightOffset;
|
||||
|
||||
lightnum = R_AdjustLightLevel(lightnum);
|
||||
|
||||
if (lightnum < 0)
|
||||
walllights = scalelight[0];
|
||||
else if (lightnum >= LIGHTLEVELS)
|
||||
|
|
|
|||
|
|
@ -939,6 +939,8 @@ static void R_DrawVisSprite(vissprite_t *vis)
|
|||
if (!dc_colormap)
|
||||
dc_colormap = colormaps;
|
||||
|
||||
dc_lightmap = colormaps;
|
||||
|
||||
dc_fullbright = colormaps;
|
||||
|
||||
if (encoremap && !vis->mobj->color && !(vis->mobj->flags & MF_DONTENCOREMAP))
|
||||
|
|
@ -1143,6 +1145,8 @@ static void R_DrawPrecipitationVisSprite(vissprite_t *vis)
|
|||
dc_fullbright += COLORMAP_REMAPOFFSET;
|
||||
}
|
||||
|
||||
dc_lightmap = colormaps;
|
||||
|
||||
dc_iscale = FixedDiv(FRACUNIT, vis->scale);
|
||||
dc_texturemid = FixedDiv(vis->texturemid, this_scale);
|
||||
dc_texheight = 0;
|
||||
|
|
@ -2971,6 +2975,9 @@ static void R_CreateDrawNodes(maskcount_t* mask, drawnode_t* head, boolean temps
|
|||
|
||||
for (rover = vsprsortedhead.prev; rover != &vsprsortedhead; rover = rover->prev)
|
||||
{
|
||||
const boolean alwaysontop = cv_debugrender_spriteclip.value || (rover->renderflags & RF_ALWAYSONTOP);
|
||||
const INT32 ontopflag = cv_debugrender_spriteclip.value ? 0 : (rover->renderflags & RF_ALWAYSONTOP);
|
||||
|
||||
if (rover->szt > vid.height || rover->sz < 0)
|
||||
continue;
|
||||
|
||||
|
|
@ -2978,6 +2985,25 @@ static void R_CreateDrawNodes(maskcount_t* mask, drawnode_t* head, boolean temps
|
|||
|
||||
for (r2 = head->next; r2 != head; r2 = r2->next)
|
||||
{
|
||||
if (alwaysontop)
|
||||
{
|
||||
// Only sort behind other sprites; sorts in
|
||||
// front of everything else.
|
||||
if (!r2->sprite)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Only sort behind other RF_ALWAYSONTOP sprites.
|
||||
// This avoids sorting behind a sprite that is
|
||||
// behind level geometry and thus sorting this
|
||||
// one behind level geometry too.
|
||||
if (r2->sprite->renderflags ^ ontopflag)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (r2->plane)
|
||||
{
|
||||
fixed_t planeobjectz, planecameraz;
|
||||
|
|
@ -3210,6 +3236,8 @@ static void R_DrawSprite(vissprite_t *spr)
|
|||
mfloorclip = spr->clipbot;
|
||||
mceilingclip = spr->cliptop;
|
||||
|
||||
R_CheckDebugHighlight(SW_HI_THINGS);
|
||||
|
||||
if (spr->cut & SC_BBOX)
|
||||
R_DrawThingBoundingBox(spr);
|
||||
else if (spr->cut & SC_SPLAT)
|
||||
|
|
@ -3238,6 +3266,16 @@ void R_ClipVisSprite(vissprite_t *spr, INT32 x1, INT32 x2, portal_t* portal)
|
|||
fixed_t lowscale;
|
||||
INT32 silhouette;
|
||||
|
||||
if ((spr->renderflags & RF_ALWAYSONTOP) || cv_debugrender_spriteclip.value)
|
||||
{
|
||||
for (x = x1; x <= x2; x++)
|
||||
{
|
||||
spr->clipbot[x] = (INT16)viewheight;
|
||||
spr->cliptop[x] = (INT16)con_clipviewtop;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
for (x = x1; x <= x2; x++)
|
||||
{
|
||||
spr->clipbot[x] = spr->cliptop[x] = CLIP_UNDEF;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
31
src/screen.c
31
src/screen.c
|
|
@ -64,6 +64,7 @@ void (*spanfuncs_npo2[SPANDRAWFUNC_MAX])(void);
|
|||
#ifdef USE_COL_SPAN_ASM
|
||||
void (*spanfuncs_asm[SPANDRAWFUNC_MAX])(void);
|
||||
#endif
|
||||
void (*spanfuncs_flat[SPANDRAWFUNC_MAX])(void);
|
||||
|
||||
// ------------------
|
||||
// global video state
|
||||
|
|
@ -170,6 +171,22 @@ void SCR_SetDrawFuncs(void)
|
|||
spanfuncs_npo2[SPANDRAWFUNC_TILTEDWATER] = R_DrawTiltedTranslucentWaterSpan_NPO2_8;
|
||||
spanfuncs_npo2[SPANDRAWFUNC_FOG] = NULL; // Not needed
|
||||
|
||||
// Debugging - highlight surfaces in flat colors
|
||||
spanfuncs_flat[BASEDRAWFUNC] = R_DrawSpan_Flat_8;
|
||||
spanfuncs_flat[SPANDRAWFUNC_TRANS] = R_DrawSpan_Flat_8;
|
||||
spanfuncs_flat[SPANDRAWFUNC_TILTED] = R_DrawTiltedSpan_Flat_8;
|
||||
spanfuncs_flat[SPANDRAWFUNC_TILTEDTRANS] = R_DrawTiltedSpan_Flat_8;
|
||||
spanfuncs_flat[SPANDRAWFUNC_SPLAT] = R_DrawSpan_Flat_8;
|
||||
spanfuncs_flat[SPANDRAWFUNC_TRANSSPLAT] = R_DrawSpan_Flat_8;
|
||||
spanfuncs_flat[SPANDRAWFUNC_TILTEDSPLAT] = R_DrawTiltedSpan_Flat_8;
|
||||
spanfuncs_flat[SPANDRAWFUNC_SPRITE] = R_DrawSpan_Flat_8;
|
||||
spanfuncs_flat[SPANDRAWFUNC_TRANSSPRITE] = R_DrawSpan_Flat_8;
|
||||
spanfuncs_flat[SPANDRAWFUNC_TILTEDSPRITE] = R_DrawTiltedSpan_Flat_8;
|
||||
spanfuncs_flat[SPANDRAWFUNC_TILTEDTRANSSPRITE] = R_DrawTiltedSpan_Flat_8;
|
||||
spanfuncs_flat[SPANDRAWFUNC_WATER] = R_DrawSpan_Flat_8;
|
||||
spanfuncs_flat[SPANDRAWFUNC_TILTEDWATER] = R_DrawTiltedSpan_Flat_8;
|
||||
spanfuncs_flat[SPANDRAWFUNC_FOG] = R_DrawSpan_Flat_8; // Not needed
|
||||
|
||||
#if (defined(RUSEASM) && defined(USE_COL_SPAN_ASM))
|
||||
if (R_ASM)
|
||||
{
|
||||
|
|
@ -220,13 +237,17 @@ void R_SetColumnFunc(size_t id, boolean brightmapped)
|
|||
|
||||
colfunctype = id;
|
||||
|
||||
if (debugrender_highlight != 0)
|
||||
{
|
||||
colfunc = R_DrawColumn_Flat_8;
|
||||
}
|
||||
#ifdef USE_COL_SPAN_ASM
|
||||
if (colfuncs_asm[id] != NULL && brightmapped == false)
|
||||
else if (colfuncs_asm[id] != NULL && brightmapped == false)
|
||||
{
|
||||
colfunc = colfuncs_asm[id];
|
||||
}
|
||||
else
|
||||
#endif
|
||||
else
|
||||
{
|
||||
colfunc = colfuncs[id];
|
||||
}
|
||||
|
|
@ -236,7 +257,11 @@ void R_SetSpanFunc(size_t id, boolean npo2, boolean brightmapped)
|
|||
{
|
||||
I_Assert(id < SPANDRAWFUNC_MAX);
|
||||
|
||||
if (spanfuncs_npo2[id] != NULL && npo2 == true)
|
||||
if (spanfuncs_flat[id] != NULL && debugrender_highlight != 0)
|
||||
{
|
||||
spanfunc = spanfuncs_flat[id];
|
||||
}
|
||||
else if (spanfuncs_npo2[id] != NULL && npo2 == true)
|
||||
{
|
||||
spanfunc = spanfuncs_npo2[id];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -179,6 +179,7 @@ extern void (*spanfuncs_npo2[SPANDRAWFUNC_MAX])(void);
|
|||
#ifdef USE_COL_SPAN_ASM
|
||||
extern void (*spanfuncs_asm[SPANDRAWFUNC_MAX])(void);
|
||||
#endif
|
||||
extern void (*spanfuncs_flat[SPANDRAWFUNC_MAX])(void);
|
||||
|
||||
// -----
|
||||
// CPUID
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@ TYPEDEF (botvars_t);
|
|||
TYPEDEF (roundconditions_t);
|
||||
TYPEDEF (skybox_t);
|
||||
TYPEDEF (itemroulette_t);
|
||||
TYPEDEF (altview_t);
|
||||
TYPEDEF (player_t);
|
||||
|
||||
// d_clisrv.h
|
||||
|
|
@ -198,6 +199,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