mirror of
https://github.com/KartKrewDev/RingRacers.git
synced 2025-10-30 08:01:28 +00:00
Merge branch 'master' of https://git.do.srb2.org/KartKrew/Kart into save_p-unglobal-alt
# Conflicts: # src/g_demo.c
This commit is contained in:
commit
80d19a8458
65 changed files with 2114 additions and 1613 deletions
|
|
@ -1,3 +1,5 @@
|
|||
cmake_minimum_required(VERSION 3.3 FATAL_ERROR)
|
||||
|
||||
set(CMAKE_BINARY_DIR "${BINARY_DIR}")
|
||||
set(CMAKE_CURRENT_BINARY_DIR "${BINARY_DIR}")
|
||||
|
||||
|
|
@ -7,7 +9,23 @@ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake/Mo
|
|||
include(GitUtilities)
|
||||
|
||||
git_current_branch(SRB2_COMP_BRANCH)
|
||||
git_summary(SRB2_COMP_REVISION)
|
||||
git_working_tree_dirty(SRB2_COMP_UNCOMMITTED)
|
||||
|
||||
git_summary(revision)
|
||||
string(REGEX REPLACE "([\"\\])" "\\\\\\1" SRB2_COMP_REVISION "${revision}")
|
||||
|
||||
if("${CMAKE_BUILD_TYPE}" STREQUAL "")
|
||||
set(CMAKE_BUILD_TYPE None)
|
||||
endif()
|
||||
|
||||
# These build types enable optimizations of some kind by default.
|
||||
set(optimized_build_types "MINSIZEREL;RELEASE;RELWITHDEBINFO")
|
||||
|
||||
string(TOUPPER "${CMAKE_BUILD_TYPE}" build_type)
|
||||
if("${build_type}" IN_LIST optimized_build_types)
|
||||
set(SRB2_COMP_OPTIMIZED TRUE)
|
||||
else()
|
||||
set(SRB2_COMP_OPTIMIZED FALSE)
|
||||
endif()
|
||||
|
||||
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/src/config.h.in" "${CMAKE_CURRENT_BINARY_DIR}/src/config.h")
|
||||
|
|
|
|||
|
|
@ -154,7 +154,7 @@ add_custom_command(
|
|||
# build time for accurate git information and before anything
|
||||
# that needs it, obviously.
|
||||
add_custom_target(_SRB2_reconf ALL
|
||||
COMMAND ${CMAKE_COMMAND} -DGIT_EXECUTABLE=${GIT_EXECUTABLE} -DBINARY_DIR=${CMAKE_CURRENT_BINARY_DIR}/.. -P ${CMAKE_CURRENT_SOURCE_DIR}/../cmake/Comptime.cmake
|
||||
COMMAND ${CMAKE_COMMAND} -DGIT_EXECUTABLE=${GIT_EXECUTABLE} -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} -DBINARY_DIR=${CMAKE_CURRENT_BINARY_DIR}/.. -P ${CMAKE_CURRENT_SOURCE_DIR}/../cmake/Comptime.cmake
|
||||
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/.."
|
||||
)
|
||||
add_dependencies(SRB2SDL2 _SRB2_reconf)
|
||||
|
|
|
|||
|
|
@ -11,6 +11,8 @@
|
|||
#include "config.h"
|
||||
const char *compbranch = SRB2_COMP_BRANCH;
|
||||
const char *comprevision = SRB2_COMP_REVISION;
|
||||
const char *comptype = CMAKE_BUILD_TYPE;
|
||||
const int compoptimized = SRB2_COMP_OPTIMIZED;
|
||||
|
||||
#elif (defined(COMPVERSION))
|
||||
#include "comptime.h"
|
||||
|
|
|
|||
|
|
@ -20,6 +20,9 @@
|
|||
#define COMPVERSION_UNCOMMITTED
|
||||
#endif
|
||||
|
||||
#define CMAKE_BUILD_TYPE "${CMAKE_BUILD_TYPE}"
|
||||
#cmakedefine01 SRB2_COMP_OPTIMIZED
|
||||
|
||||
#endif
|
||||
|
||||
/* Manually defined asset hashes for non-CMake builds
|
||||
|
|
|
|||
|
|
@ -358,7 +358,22 @@ static void CON_SetupColormaps(void)
|
|||
*memorysrc = (UINT8)(i & 0xFF); // remap each color to itself...
|
||||
|
||||
purplemap[0] = (UINT8)163;
|
||||
|
||||
yellowmap[0] = (UINT8)73;
|
||||
yellowmap[1] = (UINT8)73;
|
||||
yellowmap[3] = (UINT8)74;
|
||||
yellowmap[6] = (UINT8)74;
|
||||
yellowmap[7] = (UINT8)190;
|
||||
yellowmap[8] = (UINT8)190;
|
||||
yellowmap[10] = (UINT8)190;
|
||||
yellowmap[12] = (UINT8)190;
|
||||
yellowmap[14] = (UINT8)149;
|
||||
yellowmap[15] = (UINT8)149;
|
||||
yellowmap[16] = (UINT8)149;
|
||||
yellowmap[21] = (UINT8)152;
|
||||
yellowmap[23] = (UINT8)173;
|
||||
yellowmap[24] = (UINT8)167;
|
||||
|
||||
greenmap[0] = (UINT8)98;
|
||||
bluemap[0] = (UINT8)148;
|
||||
redmap[0] = (UINT8)34; // battle
|
||||
|
|
|
|||
|
|
@ -54,7 +54,6 @@
|
|||
#include "k_pwrlv.h"
|
||||
#include "k_bot.h"
|
||||
#include "k_grandprix.h"
|
||||
#include "k_boss.h"
|
||||
#include "doomstat.h"
|
||||
#include "s_sound.h" // sfx_syfail
|
||||
#include "m_cond.h" // netUnlocked
|
||||
|
|
@ -899,9 +898,6 @@ static void SV_SendServerInfo(INT32 node, tic_t servertime)
|
|||
UINT8 *p;
|
||||
size_t mirror_length;
|
||||
const char *httpurl = cv_httpsource.string;
|
||||
UINT8 prefgametype = (cv_kartgametypepreference.value == -1)
|
||||
? gametype
|
||||
: cv_kartgametypepreference.value;
|
||||
|
||||
netbuffer->packettype = PT_SERVERINFO;
|
||||
netbuffer->u.serverinfo._255 = 255;
|
||||
|
|
@ -933,7 +929,7 @@ static void SV_SendServerInfo(INT32 node, tic_t servertime)
|
|||
else
|
||||
netbuffer->u.serverinfo.refusereason = 0;
|
||||
|
||||
strncpy(netbuffer->u.serverinfo.gametypename, Gametype_Names[prefgametype],
|
||||
strncpy(netbuffer->u.serverinfo.gametypename, gametypes[gametype]->name,
|
||||
sizeof netbuffer->u.serverinfo.gametypename);
|
||||
netbuffer->u.serverinfo.modifiedgame = (UINT8)modifiedgame;
|
||||
netbuffer->u.serverinfo.cheatsenabled = CV_CheatsEnabled();
|
||||
|
|
@ -2077,8 +2073,9 @@ static void CL_ConnectToServer(void)
|
|||
Y_EndVote();
|
||||
|
||||
DEBFILE(va("waiting %d nodes\n", doomcom->numnodes));
|
||||
M_ClearMenus(true);
|
||||
G_SetGamestate(GS_WAITINGPLAYERS);
|
||||
if (wipegamestate == GS_MENU)
|
||||
M_ClearMenus(true);
|
||||
wipegamestate = GS_WAITINGPLAYERS;
|
||||
|
||||
ClearAdminPlayers();
|
||||
|
|
@ -3744,6 +3741,9 @@ 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);
|
||||
|
|
|
|||
41
src/d_main.c
41
src/d_main.c
|
|
@ -72,7 +72,6 @@
|
|||
|
||||
// SRB2Kart
|
||||
#include "k_grandprix.h"
|
||||
#include "k_boss.h"
|
||||
#include "doomstat.h"
|
||||
#include "m_random.h" // P_ClearRandom
|
||||
#include "k_specialstage.h"
|
||||
|
|
@ -963,12 +962,6 @@ void D_StartTitle(void)
|
|||
// Reset GP
|
||||
memset(&grandprixinfo, 0, sizeof(struct grandprixinfo));
|
||||
|
||||
// Reset boss info
|
||||
K_ResetBossInfo();
|
||||
|
||||
// Reset Special Stage
|
||||
K_ResetSpecialStage();
|
||||
|
||||
// empty maptol so mario/etc sounds don't play in sound test when they shouldn't
|
||||
maptol = 0;
|
||||
|
||||
|
|
@ -1200,13 +1193,14 @@ D_ConvertVersionNumbers (void)
|
|||
//
|
||||
void D_SRB2Main(void)
|
||||
{
|
||||
INT32 i, p;
|
||||
INT32 i, j, p;
|
||||
#ifdef DEVELOP
|
||||
INT32 pstartmap = 1; // default to first loaded map (Test Run)
|
||||
#else
|
||||
INT32 pstartmap = 0; // default to random map (0 is not a valid map number)
|
||||
#endif
|
||||
boolean autostart = false;
|
||||
INT32 newgametype = -1;
|
||||
|
||||
/* break the version string into version numbers, for netplay */
|
||||
D_ConvertVersionNumbers();
|
||||
|
|
@ -1519,11 +1513,6 @@ void D_SRB2Main(void)
|
|||
|
||||
CON_SetLoadingProgress(LOADED_HUINIT);
|
||||
|
||||
memset(timelimits, 0, sizeof(timelimits));
|
||||
memset(pointlimits, 0, sizeof(pointlimits));
|
||||
|
||||
timelimits[GT_BATTLE] = 2;
|
||||
|
||||
D_RegisterServerCommands();
|
||||
D_RegisterClientCommands(); // be sure that this is called before D_CheckNetGame
|
||||
R_RegisterEngineStuff();
|
||||
|
|
@ -1531,14 +1520,14 @@ void D_SRB2Main(void)
|
|||
|
||||
I_RegisterSysCommands();
|
||||
|
||||
M_Init();
|
||||
|
||||
//--------------------------------------------------------- CONFIG.CFG
|
||||
M_FirstLoadConfig(); // WARNING : this do a "COM_BufExecute()"
|
||||
|
||||
// Load Profiles now that default controls have been defined
|
||||
PR_LoadProfiles(); // load control profiles
|
||||
|
||||
M_Init();
|
||||
|
||||
#if (defined (__unix__) && !defined (MSDOS)) || defined (UNIXCOMMON) || defined (HAVE_SDL)
|
||||
VID_PrepareModeList(); // Regenerate Modelist according to cv_fullscreen
|
||||
#endif
|
||||
|
|
@ -1796,8 +1785,6 @@ void D_SRB2Main(void)
|
|||
if (M_CheckParm("-gametype") && M_IsNextParm())
|
||||
{
|
||||
// from Command_Map_f
|
||||
INT32 j;
|
||||
INT16 newgametype = -1;
|
||||
const char *sgametype = M_GetNextParm();
|
||||
|
||||
newgametype = G_GetGametypeByName(sgametype);
|
||||
|
|
@ -1805,7 +1792,7 @@ void D_SRB2Main(void)
|
|||
if (newgametype == -1) // reached end of the list with no match
|
||||
{
|
||||
j = atoi(sgametype); // assume they gave us a gametype number, which is okay too
|
||||
if (j >= 0 && j < gametypecount)
|
||||
if (j >= 0 && j < numgametypes)
|
||||
newgametype = (INT16)j;
|
||||
}
|
||||
|
||||
|
|
@ -1819,7 +1806,6 @@ void D_SRB2Main(void)
|
|||
|
||||
if (M_CheckParm("-skill") && M_IsNextParm())
|
||||
{
|
||||
INT32 j;
|
||||
INT16 newskill = -1;
|
||||
const char *sskill = M_GetNextParm();
|
||||
|
||||
|
|
@ -1872,11 +1858,20 @@ void D_SRB2Main(void)
|
|||
|
||||
if (grandprixinfo.gp == true && mapheaderinfo[pstartmap-1])
|
||||
{
|
||||
if (mapheaderinfo[pstartmap-1]->typeoflevel & TOL_SPECIAL)
|
||||
if (newgametype == -1)
|
||||
{
|
||||
specialStage.active = true;
|
||||
specialStage.encore = grandprixinfo.encore;
|
||||
grandprixinfo.eventmode = GPEVENT_SPECIAL;
|
||||
newgametype = G_GuessGametypeByTOL(mapheaderinfo[pstartmap-1]->typeoflevel);
|
||||
if (newgametype != -1)
|
||||
{
|
||||
j = gametype;
|
||||
G_SetGametype(newgametype);
|
||||
D_GameTypeChanged(j);
|
||||
}
|
||||
|
||||
if (gametyperules & (GTR_BOSS|GTR_CATCHER))
|
||||
grandprixinfo.eventmode = GPEVENT_SPECIAL;
|
||||
else if (gametype != GT_RACE)
|
||||
grandprixinfo.eventmode = GPEVENT_BONUS;
|
||||
}
|
||||
|
||||
G_SetUsedCheats();
|
||||
|
|
|
|||
245
src/d_netcmd.c
245
src/d_netcmd.c
|
|
@ -57,7 +57,6 @@
|
|||
#include "k_color.h"
|
||||
#include "k_respawn.h"
|
||||
#include "k_grandprix.h"
|
||||
#include "k_boss.h"
|
||||
#include "k_follower.h"
|
||||
#include "doomstat.h"
|
||||
#include "deh_tables.h"
|
||||
|
|
@ -399,10 +398,6 @@ consvar_t cv_kartbumpers = CVAR_INIT ("battlebumpers", "3", CV_NETVAR, kartbumpe
|
|||
consvar_t cv_kartfrantic = CVAR_INIT ("franticitems", "Off", CV_NETVAR|CV_CALL|CV_NOINIT, CV_OnOff, KartFrantic_OnChange);
|
||||
static CV_PossibleValue_t kartencore_cons_t[] = {{-1, "Auto"}, {0, "Off"}, {1, "On"}, {0, NULL}};
|
||||
consvar_t cv_kartencore = CVAR_INIT ("encore", "Auto", CV_NETVAR|CV_CALL|CV_NOINIT, kartencore_cons_t, KartEncore_OnChange);
|
||||
static CV_PossibleValue_t kartvoterulechanges_cons_t[] = {{0, "Never"}, {1, "Sometimes"}, {2, "Frequent"}, {3, "Always"}, {0, NULL}};
|
||||
consvar_t cv_kartvoterulechanges = CVAR_INIT ("voterulechanges", "Frequent", CV_NETVAR, kartvoterulechanges_cons_t, NULL);
|
||||
static CV_PossibleValue_t kartgametypepreference_cons_t[] = {{-1, "None"}, {GT_RACE, "Race"}, {GT_BATTLE, "Battle"}, {0, NULL}};
|
||||
consvar_t cv_kartgametypepreference = CVAR_INIT ("gametypepreference", "None", CV_NETVAR, kartgametypepreference_cons_t, NULL);
|
||||
static CV_PossibleValue_t kartspeedometer_cons_t[] = {{0, "Off"}, {1, "Percentage"}, {2, "Kilometers"}, {3, "Miles"}, {4, "Fracunits"}, {0, NULL}};
|
||||
consvar_t cv_kartspeedometer = CVAR_INIT ("speedometer", "Percentage", CV_SAVE, kartspeedometer_cons_t, NULL); // use tics in display
|
||||
static CV_PossibleValue_t kartvoices_cons_t[] = {{0, "Never"}, {1, "Tasteful"}, {2, "Meme"}, {0, NULL}};
|
||||
|
|
@ -485,10 +480,6 @@ consvar_t cv_timelimit = CVAR_INIT ("timelimit", "None", CV_NETVAR|CV_CALL|CV_NO
|
|||
static CV_PossibleValue_t numlaps_cons_t[] = {{1, "MIN"}, {MAX_LAPS, "MAX"}, {0, "Map default"}, {0, NULL}};
|
||||
consvar_t cv_numlaps = CVAR_INIT ("numlaps", "Map default", CV_SAVE|CV_NETVAR|CV_CALL|CV_CHEAT, numlaps_cons_t, NumLaps_OnChange);
|
||||
|
||||
// Point and time limits for every gametype
|
||||
INT32 pointlimits[NUMGAMETYPES];
|
||||
INT32 timelimits[NUMGAMETYPES];
|
||||
|
||||
consvar_t cv_forceskin = CVAR_INIT ("forceskin", "None", CV_NETVAR|CV_CALL|CV_CHEAT, NULL, ForceSkin_OnChange);
|
||||
|
||||
consvar_t cv_downloading = CVAR_INIT ("downloading", "On", 0, CV_OnOff, NULL);
|
||||
|
|
@ -557,13 +548,11 @@ char timedemo_csv_id[256];
|
|||
boolean timedemo_quit;
|
||||
|
||||
INT16 gametype = GT_RACE;
|
||||
UINT32 gametyperules = 0;
|
||||
INT16 gametypecount = GT_FIRSTFREESLOT;
|
||||
INT16 numgametypes = GT_FIRSTFREESLOT;
|
||||
|
||||
boolean forceresetplayers = false;
|
||||
boolean deferencoremode = false;
|
||||
UINT8 splitscreen = 0;
|
||||
boolean circuitmap = false;
|
||||
INT32 adminplayers[MAXPLAYERS];
|
||||
|
||||
// Scheduled commands.
|
||||
|
|
@ -2530,19 +2519,11 @@ void D_MapChange(INT32 mapnum, INT32 newgametype, boolean pencoremode, boolean r
|
|||
CONS_Debug(DBG_GAMELOGIC, "Map change: mapnum=%d gametype=%d pencoremode=%d resetplayers=%d delay=%d skipprecutscene=%d\n",
|
||||
mapnum, newgametype, pencoremode, resetplayers, delay, skipprecutscene);
|
||||
|
||||
if ((netgame || multiplayer) && !((gametype == newgametype) && (gametypedefaultrules[newgametype] & GTR_CAMPAIGN)))
|
||||
if ((netgame || multiplayer) && (grandprixinfo.gp != false))
|
||||
FLS = false;
|
||||
|
||||
// Too lazy to change the input value for every instance of this function.......
|
||||
if (bossinfo.boss == true)
|
||||
{
|
||||
pencoremode = bossinfo.encore;
|
||||
}
|
||||
else if (specialStage.active == true)
|
||||
{
|
||||
pencoremode = specialStage.encore;
|
||||
}
|
||||
else if (grandprixinfo.gp == true)
|
||||
if (grandprixinfo.gp == true)
|
||||
{
|
||||
pencoremode = grandprixinfo.encore;
|
||||
}
|
||||
|
|
@ -2596,14 +2577,13 @@ void D_SetupVote(void)
|
|||
UINT8 buf[5*2]; // four UINT16 maps (at twice the width of a UINT8), and two gametypes
|
||||
UINT8 *p = buf;
|
||||
INT32 i;
|
||||
UINT8 gt = (cv_kartgametypepreference.value == -1) ? gametype : cv_kartgametypepreference.value;
|
||||
UINT8 secondgt = G_SometimesGetDifferentGametype(gt);
|
||||
UINT8 secondgt = G_SometimesGetDifferentGametype();
|
||||
INT16 votebuffer[4] = {-1,-1,-1,0};
|
||||
|
||||
if ((cv_kartencore.value == 1) && (gametypedefaultrules[gt] & GTR_CIRCUIT))
|
||||
WRITEUINT8(p, (gt|VOTEMODIFIER_ENCORE));
|
||||
if ((cv_kartencore.value == 1) && (gametyperules & GTR_ENCORE))
|
||||
WRITEUINT8(p, (gametype|VOTEMODIFIER_ENCORE));
|
||||
else
|
||||
WRITEUINT8(p, gt);
|
||||
WRITEUINT8(p, gametype);
|
||||
WRITEUINT8(p, secondgt);
|
||||
secondgt &= ~VOTEMODIFIER_ENCORE;
|
||||
|
||||
|
|
@ -2613,9 +2593,9 @@ void D_SetupVote(void)
|
|||
if (i == 2) // sometimes a different gametype
|
||||
m = G_RandMap(G_TOLFlag(secondgt), prevmap, ((secondgt != gametype) ? 2 : 0), 0, true, votebuffer);
|
||||
else if (i >= 3) // unknown-random and formerly force-unknown MAP HELL
|
||||
m = G_RandMap(G_TOLFlag(gt), prevmap, 0, (i-2), (i < 4), votebuffer);
|
||||
m = G_RandMap(G_TOLFlag(gametype), prevmap, 0, (i-2), (i < 4), votebuffer);
|
||||
else
|
||||
m = G_RandMap(G_TOLFlag(gt), prevmap, 0, 0, true, votebuffer);
|
||||
m = G_RandMap(G_TOLFlag(gametype), prevmap, 0, 0, true, votebuffer);
|
||||
if (i < 3)
|
||||
votebuffer[i] = m;
|
||||
WRITEUINT16(p, m);
|
||||
|
|
@ -2758,13 +2738,7 @@ static void Command_Map_f(void)
|
|||
|
||||
if (option_gametype)
|
||||
{
|
||||
if (!multiplayer)
|
||||
{
|
||||
CONS_Printf(M_GetText(
|
||||
"You can't switch gametypes in single player!\n"));
|
||||
return;
|
||||
}
|
||||
else if (COM_Argc() < option_gametype + 2)/* no argument after? */
|
||||
if (COM_Argc() < option_gametype + 2)/* no argument after? */
|
||||
{
|
||||
CONS_Alert(CONS_ERROR,
|
||||
"No gametype name follows parameter '%s'.\n",
|
||||
|
|
@ -2822,7 +2796,7 @@ static void Command_Map_f(void)
|
|||
if (isdigit(gametypename[0]))
|
||||
{
|
||||
d = atoi(gametypename);
|
||||
if (d >= 0 && d < gametypecount)
|
||||
if (d >= 0 && d < numgametypes)
|
||||
newgametype = d;
|
||||
else
|
||||
{
|
||||
|
|
@ -2830,7 +2804,7 @@ static void Command_Map_f(void)
|
|||
"Gametype number %d is out of range. Use a number between"
|
||||
" 0 and %d inclusive. ...Or just use the name. :v\n",
|
||||
d,
|
||||
gametypecount-1);
|
||||
numgametypes-1);
|
||||
Z_Free(realmapname);
|
||||
Z_Free(mapname);
|
||||
return;
|
||||
|
|
@ -2839,13 +2813,23 @@ static void Command_Map_f(void)
|
|||
else
|
||||
{
|
||||
CONS_Alert(CONS_ERROR,
|
||||
"'%s' is not a gametype.\n",
|
||||
"'%s' is not a valid gametype.\n",
|
||||
gametypename);
|
||||
Z_Free(realmapname);
|
||||
Z_Free(mapname);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (Playing() && netgame && (gametypes[newgametype]->rules & GTR_FORBIDMP))
|
||||
{
|
||||
CONS_Alert(CONS_ERROR,
|
||||
"'%s' is not a net-compatible gametype.\n",
|
||||
gametypename);
|
||||
Z_Free(realmapname);
|
||||
Z_Free(mapname);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (!Playing())
|
||||
{
|
||||
|
|
@ -2853,7 +2837,15 @@ static void Command_Map_f(void)
|
|||
if (mapheaderinfo[newmapnum-1])
|
||||
{
|
||||
// Let's just guess so we don't have to specify the gametype EVERY time...
|
||||
newgametype = (mapheaderinfo[newmapnum-1]->typeoflevel & (TOL_BATTLE|TOL_BOSS)) ? GT_BATTLE : GT_RACE;
|
||||
newgametype = G_GuessGametypeByTOL(mapheaderinfo[newmapnum-1]->typeoflevel);
|
||||
|
||||
if (newgametype == -1)
|
||||
{
|
||||
CONS_Alert(CONS_WARNING, M_GetText("%s (%s) doesn't support any known gametype!\n"), realmapname, G_BuildMapName(newmapnum));
|
||||
Z_Free(realmapname);
|
||||
Z_Free(mapname);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2865,6 +2857,8 @@ static void Command_Map_f(void)
|
|||
if (!M_SecretUnlocked(SECRET_ENCORE, false) && newencoremode == true && !usingcheats)
|
||||
{
|
||||
CONS_Alert(CONS_NOTICE, M_GetText("You haven't unlocked Encore Mode yet!\n"));
|
||||
Z_Free(realmapname);
|
||||
Z_Free(mapname);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
@ -2885,8 +2879,7 @@ static void Command_Map_f(void)
|
|||
mapheaderinfo[newmapnum-1]->typeoflevel & G_TOLFlag(newgametype)
|
||||
))
|
||||
{
|
||||
CONS_Alert(CONS_WARNING, M_GetText("%s (%s) doesn't support %s mode!\n(Use -force to override)\n"), realmapname, G_BuildMapName(newmapnum),
|
||||
(multiplayer ? gametype_cons_t[newgametype].strvalue : "Single Player"));
|
||||
CONS_Alert(CONS_WARNING, M_GetText("%s (%s) doesn't support %s mode!\n(Use -force to override)\n"), realmapname, G_BuildMapName(newmapnum), gametypes[newgametype]->name);
|
||||
Z_Free(realmapname);
|
||||
Z_Free(mapname);
|
||||
return;
|
||||
|
|
@ -2895,8 +2888,7 @@ static void Command_Map_f(void)
|
|||
{
|
||||
fromlevelselect =
|
||||
( netgame || multiplayer ) &&
|
||||
newgametype == gametype &&
|
||||
gametypedefaultrules[newgametype] & GTR_CAMPAIGN;
|
||||
grandprixinfo.gp != false;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2952,35 +2944,18 @@ static void Command_Map_f(void)
|
|||
|
||||
grandprixinfo.eventmode = GPEVENT_NONE;
|
||||
|
||||
if (newgametype == GT_BATTLE)
|
||||
if (gametypes[newgametype]->rules & (GTR_BOSS|GTR_CATCHER))
|
||||
{
|
||||
grandprixinfo.eventmode = GPEVENT_SPECIAL;
|
||||
}
|
||||
else if (newgametype != GT_RACE)
|
||||
{
|
||||
grandprixinfo.eventmode = GPEVENT_BONUS;
|
||||
|
||||
if (mapheaderinfo[newmapnum-1] &&
|
||||
mapheaderinfo[newmapnum-1]->typeoflevel & TOL_BOSS)
|
||||
{
|
||||
bossinfo.boss = true;
|
||||
bossinfo.encore = newencoremode;
|
||||
}
|
||||
else
|
||||
{
|
||||
bossinfo.boss = false;
|
||||
K_ResetBossInfo();
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
if (!Playing())
|
||||
{
|
||||
if (mapheaderinfo[newmapnum-1] &&
|
||||
mapheaderinfo[newmapnum-1]->typeoflevel & TOL_SPECIAL) // Special Stage
|
||||
{
|
||||
specialStage.active = true;
|
||||
specialStage.encore = newencoremode;
|
||||
grandprixinfo.eventmode = GPEVENT_SPECIAL;
|
||||
}
|
||||
else
|
||||
{
|
||||
specialStage.active = false;
|
||||
}
|
||||
multiplayer = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -3029,12 +3004,12 @@ static void Got_Mapcmd(UINT8 **cp, INT32 playernum)
|
|||
gametype = READUINT8(*cp);
|
||||
G_SetGametype(gametype); // I fear putting that macro as an argument
|
||||
|
||||
if (gametype < 0 || gametype >= gametypecount)
|
||||
if (gametype < 0 || gametype >= numgametypes)
|
||||
gametype = lastgametype;
|
||||
else if (gametype != lastgametype)
|
||||
D_GameTypeChanged(lastgametype); // emulate consvar_t behavior for gametype
|
||||
|
||||
if (!(gametyperules & GTR_CIRCUIT) && !bossinfo.boss)
|
||||
if (!(gametyperules & GTR_ENCORE))
|
||||
pencoremode = false;
|
||||
|
||||
skipprecutscene = ((flags & (1<<2)) != 0);
|
||||
|
|
@ -3086,9 +3061,10 @@ static void Command_RandomMap(void)
|
|||
{
|
||||
INT32 oldmapnum;
|
||||
INT32 newmapnum;
|
||||
INT32 newgametype;
|
||||
boolean newencoremode;
|
||||
INT32 newgametype = (Playing() ? gametype : menugametype);
|
||||
boolean newencore = false;
|
||||
boolean newresetplayers;
|
||||
size_t option_gametype;
|
||||
|
||||
if (client && !IsPlayerAdmin(consoleplayer))
|
||||
{
|
||||
|
|
@ -3096,13 +3072,69 @@ static void Command_RandomMap(void)
|
|||
return;
|
||||
}
|
||||
|
||||
if ((option_gametype = COM_CheckPartialParm("-g")))
|
||||
{
|
||||
const char *gametypename;
|
||||
|
||||
if (COM_Argc() < option_gametype + 2)/* no argument after? */
|
||||
{
|
||||
CONS_Alert(CONS_ERROR,
|
||||
"No gametype name follows parameter '%s'.\n",
|
||||
COM_Argv(option_gametype));
|
||||
return;
|
||||
}
|
||||
|
||||
// new gametype value
|
||||
// use current one by default
|
||||
gametypename = COM_Argv(option_gametype + 1);
|
||||
|
||||
newgametype = G_GetGametypeByName(gametypename);
|
||||
|
||||
if (newgametype == -1) // reached end of the list with no match
|
||||
{
|
||||
/* Did they give us a gametype number? That's okay too! */
|
||||
if (isdigit(gametypename[0]))
|
||||
{
|
||||
INT16 d = atoi(gametypename);
|
||||
if (d >= 0 && d < numgametypes)
|
||||
newgametype = d;
|
||||
else
|
||||
{
|
||||
CONS_Alert(CONS_ERROR,
|
||||
"Gametype number %d is out of range. Use a number between"
|
||||
" 0 and %d inclusive. ...Or just use the name. :v\n",
|
||||
d,
|
||||
numgametypes-1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
CONS_Alert(CONS_ERROR,
|
||||
"'%s' is not a valid gametype.\n",
|
||||
gametypename);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (Playing() && netgame && (gametypes[newgametype]->rules & GTR_FORBIDMP))
|
||||
{
|
||||
CONS_Alert(CONS_ERROR,
|
||||
"'%s' is not a net-compatible gametype.\n",
|
||||
gametypename);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Handle singleplayer conditions.
|
||||
// The existing ones are way too annoyingly complicated and "anti-cheat" for my tastes.
|
||||
|
||||
if (Playing())
|
||||
{
|
||||
newgametype = gametype;
|
||||
newencoremode = encoremode;
|
||||
if (cv_kartencore.value == 1 && (gametypes[newgametype]->rules & GTR_ENCORE))
|
||||
{
|
||||
newencore = true;
|
||||
}
|
||||
newresetplayers = false;
|
||||
|
||||
if (gamestate == GS_LEVEL)
|
||||
|
|
@ -3116,14 +3148,12 @@ static void Command_RandomMap(void)
|
|||
}
|
||||
else
|
||||
{
|
||||
newgametype = cv_dummygametype.value; // Changed from cv_newgametype to match newmenus
|
||||
newencoremode = false;
|
||||
newresetplayers = true;
|
||||
oldmapnum = -1;
|
||||
}
|
||||
|
||||
newmapnum = G_RandMap(G_TOLFlag(newgametype), oldmapnum, 0, 0, false, NULL) + 1;
|
||||
D_MapChange(newmapnum, newgametype, newencoremode, newresetplayers, 0, false, false);
|
||||
D_MapChange(newmapnum, newgametype, newencore, newresetplayers, 0, false, false);
|
||||
}
|
||||
|
||||
static void Command_RestartLevel(void)
|
||||
|
|
@ -3742,7 +3772,7 @@ static void Got_Teamchange(UINT8 **cp, INT32 playernum)
|
|||
// Clear player score and rings if a spectator.
|
||||
if (players[playernum].spectator)
|
||||
{
|
||||
if (gametyperules & GTR_BUMPERS) // SRB2kart
|
||||
if (gametyperules & GTR_POINTLIMIT) // SRB2kart
|
||||
{
|
||||
players[playernum].roundscore = 0;
|
||||
K_CalculateBattleWanted();
|
||||
|
|
@ -4774,16 +4804,13 @@ static void Command_Version_f(void)
|
|||
else // 16-bit? 128-bit?
|
||||
CONS_Printf("Bits Unknown ");
|
||||
|
||||
CONS_Printf("%s ", comptype);
|
||||
|
||||
// No ASM?
|
||||
#ifdef NOASM
|
||||
CONS_Printf("\x85" "NOASM " "\x80");
|
||||
#endif
|
||||
|
||||
// Debug build
|
||||
#ifdef _DEBUG
|
||||
CONS_Printf("\x85" "DEBUG " "\x80");
|
||||
#endif
|
||||
|
||||
// DEVELOP build
|
||||
#if defined(TESTERS)
|
||||
CONS_Printf("\x88" "TESTERS " "\x80");
|
||||
|
|
@ -4812,15 +4839,9 @@ static void Command_ShowGametype_f(void)
|
|||
{
|
||||
const char *gametypestr = NULL;
|
||||
|
||||
if (!(netgame || multiplayer)) // print "Single player" instead of "Race"
|
||||
{
|
||||
CONS_Printf(M_GetText("Current gametype is %s\n"), "Single Player");
|
||||
return;
|
||||
}
|
||||
|
||||
// get name string for current gametype
|
||||
if (gametype >= 0 && gametype < gametypecount)
|
||||
gametypestr = Gametype_Names[gametype];
|
||||
if (gametype >= 0 && gametype < numgametypes)
|
||||
gametypestr = gametypes[gametype]->name;
|
||||
|
||||
if (gametypestr)
|
||||
CONS_Printf(M_GetText("Current gametype is %s\n"), gametypestr);
|
||||
|
|
@ -4999,10 +5020,10 @@ void D_GameTypeChanged(INT32 lastgametype)
|
|||
{
|
||||
const char *oldgt = NULL, *newgt = NULL;
|
||||
|
||||
if (lastgametype >= 0 && lastgametype < gametypecount)
|
||||
oldgt = Gametype_Names[lastgametype];
|
||||
if (gametype >= 0 && lastgametype < gametypecount)
|
||||
newgt = Gametype_Names[gametype];
|
||||
if (lastgametype >= 0 && lastgametype < numgametypes)
|
||||
oldgt = gametypes[lastgametype]->name;
|
||||
if (gametype >= 0 && gametype < numgametypes)
|
||||
newgt = gametypes[gametype]->name;
|
||||
|
||||
if (oldgt && newgt)
|
||||
CONS_Printf(M_GetText("Gametype was changed from %s to %s\n"), oldgt, newgt);
|
||||
|
|
@ -5014,11 +5035,11 @@ void D_GameTypeChanged(INT32 lastgametype)
|
|||
{
|
||||
if (!cv_timelimit.changed) // user hasn't changed limits
|
||||
{
|
||||
CV_SetValue(&cv_timelimit, timelimits[gametype]);
|
||||
CV_SetValue(&cv_timelimit, gametypes[gametype]->timelimit);
|
||||
}
|
||||
if (!cv_pointlimit.changed)
|
||||
{
|
||||
CV_SetValue(&cv_pointlimit, pointlimits[gametype]);
|
||||
CV_SetValue(&cv_pointlimit, gametypes[gametype]->pointlimit);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -5313,11 +5334,29 @@ static void Got_SetupVotecmd(UINT8 **cp, INT32 playernum)
|
|||
|
||||
// Strip illegal Encore flag.
|
||||
if ((gt & VOTEMODIFIER_ENCORE)
|
||||
&& !(gametypedefaultrules[(gt & ~VOTEMODIFIER_ENCORE)] & GTR_CIRCUIT))
|
||||
&& !(gametypes[(gt & ~VOTEMODIFIER_ENCORE)]->rules & GTR_ENCORE))
|
||||
{
|
||||
gt &= ~VOTEMODIFIER_ENCORE;
|
||||
}
|
||||
|
||||
if ((gt & ~VOTEMODIFIER_ENCORE) >= numgametypes)
|
||||
{
|
||||
gt &= ~VOTEMODIFIER_ENCORE;
|
||||
if (server)
|
||||
I_Error("Got_SetupVotecmd: Internal gametype ID %d not found (numgametypes = %d)", gt, numgametypes);
|
||||
CONS_Alert(CONS_WARNING, M_GetText("Vote setup with bad gametype ID %d received from %s\n"), gt, player_names[playernum]);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((secondgt & ~VOTEMODIFIER_ENCORE) >= numgametypes)
|
||||
{
|
||||
secondgt &= ~VOTEMODIFIER_ENCORE;
|
||||
if (server)
|
||||
I_Error("Got_SetupVotecmd: Internal second gametype ID %d not found (numgametypes = %d)", secondgt, numgametypes);
|
||||
CONS_Alert(CONS_WARNING, M_GetText("Vote setup with bad second gametype ID %d received from %s\n"), secondgt, player_names[playernum]);
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
tempvotelevels[i][0] = (UINT16)READUINT16(*cp);
|
||||
|
|
@ -5333,11 +5372,11 @@ static void Got_SetupVotecmd(UINT8 **cp, INT32 playernum)
|
|||
|
||||
// If third entry has an illelegal Encore flag... (illelegal!?)
|
||||
if ((secondgt & VOTEMODIFIER_ENCORE)
|
||||
&& !(gametypedefaultrules[(secondgt & ~VOTEMODIFIER_ENCORE)] & GTR_CIRCUIT))
|
||||
&& !(gametypes[(secondgt & ~VOTEMODIFIER_ENCORE)]->rules & GTR_ENCORE))
|
||||
{
|
||||
secondgt &= ~VOTEMODIFIER_ENCORE;
|
||||
// Apply it to the second entry instead, gametype permitting!
|
||||
if (gametypedefaultrules[gt] & GTR_CIRCUIT)
|
||||
if (gametypes[gt]->rules & GTR_ENCORE)
|
||||
{
|
||||
tempvotelevels[1][1] |= VOTEMODIFIER_ENCORE;
|
||||
}
|
||||
|
|
@ -5737,11 +5776,11 @@ void Command_Retry_f(void)
|
|||
{
|
||||
CONS_Printf(M_GetText("You must be in a level to use this.\n"));
|
||||
}
|
||||
else if (grandprixinfo.gp == false && bossinfo.boss == false)
|
||||
else if (grandprixinfo.gp == false)
|
||||
{
|
||||
CONS_Printf(M_GetText("This only works in singleplayer games.\n"));
|
||||
}
|
||||
else if (grandprixinfo.gp == true && grandprixinfo.eventmode != GPEVENT_NONE)
|
||||
else if (grandprixinfo.eventmode == GPEVENT_BONUS)
|
||||
{
|
||||
CONS_Printf(M_GetText("You can't retry right now!\n"));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -83,8 +83,6 @@ extern consvar_t cv_kartspeed;
|
|||
extern consvar_t cv_kartbumpers;
|
||||
extern consvar_t cv_kartfrantic;
|
||||
extern consvar_t cv_kartencore;
|
||||
extern consvar_t cv_kartvoterulechanges;
|
||||
extern consvar_t cv_kartgametypepreference;
|
||||
extern consvar_t cv_kartspeedometer;
|
||||
extern consvar_t cv_kartvoices;
|
||||
extern consvar_t cv_kartbot;
|
||||
|
|
|
|||
|
|
@ -309,11 +309,16 @@ static inline int lib_getenum(lua_State *L)
|
|||
}
|
||||
else if (fastncmp("GT_", word, 3)) {
|
||||
p = word;
|
||||
for (i = 0; Gametype_ConstantNames[i]; i++)
|
||||
if (fastcmp(p, Gametype_ConstantNames[i])) {
|
||||
i = 0;
|
||||
while (gametypes[i] != NULL)
|
||||
{
|
||||
if (fastcmp(p, gametypes[i]->constant))
|
||||
{
|
||||
lua_pushinteger(L, i);
|
||||
return 1;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
if (mathlib) return luaL_error(L, "gametype '%s' could not be found.\n", word);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -764,13 +764,13 @@ void readgametype(MYFILE *f, char *gtname)
|
|||
char *tmp;
|
||||
INT32 i, j;
|
||||
|
||||
INT16 newgtidx = 0;
|
||||
gametype_t *newgametype = NULL;
|
||||
|
||||
UINT32 newgtrules = 0;
|
||||
UINT32 newgttol = 0;
|
||||
INT32 newgtpointlimit = 0;
|
||||
INT32 newgttimelimit = 0;
|
||||
INT16 newgtrankingstype = -1;
|
||||
int newgtinttype = 0;
|
||||
UINT8 newgtinttype = 0;
|
||||
char gtconst[MAXLINELEN];
|
||||
|
||||
// Empty strings.
|
||||
|
|
@ -821,12 +821,6 @@ void readgametype(MYFILE *f, char *gtname)
|
|||
newgtpointlimit = (INT32)i;
|
||||
else if (fastcmp(word, "DEFAULTTIMELIMIT"))
|
||||
newgttimelimit = (INT32)i;
|
||||
// Rankings type
|
||||
else if (fastcmp(word, "RANKINGTYPE"))
|
||||
{
|
||||
// Case insensitive
|
||||
newgtrankingstype = (int)get_number(word2);
|
||||
}
|
||||
// Intermission type
|
||||
else if (fastcmp(word, "INTERMISSIONTYPE"))
|
||||
{
|
||||
|
|
@ -879,36 +873,54 @@ void readgametype(MYFILE *f, char *gtname)
|
|||
Z_Free(word2lwr);
|
||||
|
||||
// Ran out of gametype slots
|
||||
if (gametypecount == NUMGAMETYPEFREESLOTS)
|
||||
if (numgametypes == GT_LASTFREESLOT)
|
||||
{
|
||||
CONS_Alert(CONS_WARNING, "Ran out of free gametype slots!\n");
|
||||
I_Error("Out of Gametype Freeslots while allocating \"%s\"\nLoad less addons to fix this.", gtname);
|
||||
}
|
||||
|
||||
if (gtname[0] == '\0')
|
||||
{
|
||||
deh_warning("Custom gametype must have a name");
|
||||
return;
|
||||
}
|
||||
|
||||
if (strlen(gtname) >= MAXGAMETYPELENGTH)
|
||||
{
|
||||
deh_warning("Custom gametype \"%s\"'s name must be %d long at most", gtname, MAXGAMETYPELENGTH-1);
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < numgametypes; i++)
|
||||
if (fastcmp(gtname, gametypes[i]->name))
|
||||
break;
|
||||
|
||||
if (i < numgametypes)
|
||||
{
|
||||
deh_warning("Custom gametype \"%s\"'s name is already in use", gtname);
|
||||
return;
|
||||
}
|
||||
|
||||
// Add the new gametype
|
||||
newgtidx = G_AddGametype(newgtrules);
|
||||
G_AddGametypeTOL(newgtidx, newgttol);
|
||||
newgametype = Z_Calloc(sizeof (gametype_t), PU_STATIC, NULL);
|
||||
if (!newgametype)
|
||||
{
|
||||
I_Error("Out of memory allocating gametype \"%s\"", gtname);
|
||||
}
|
||||
|
||||
// Not covered by G_AddGametype alone.
|
||||
if (newgtrankingstype == -1)
|
||||
newgtrankingstype = newgtidx;
|
||||
gametyperankings[newgtidx] = newgtrankingstype;
|
||||
intermissiontypes[newgtidx] = newgtinttype;
|
||||
pointlimits[newgtidx] = newgtpointlimit;
|
||||
timelimits[newgtidx] = newgttimelimit;
|
||||
|
||||
// Write the new gametype name.
|
||||
Gametype_Names[newgtidx] = Z_StrDup((const char *)gtname);
|
||||
|
||||
// Write the constant name.
|
||||
if (gtconst[0] == '\0')
|
||||
strncpy(gtconst, gtname, MAXLINELEN);
|
||||
G_AddGametypeConstant(newgtidx, (const char *)gtconst);
|
||||
|
||||
// Update gametype_cons_t accordingly.
|
||||
G_UpdateGametypeSelections();
|
||||
newgametype->name = Z_StrDup((const char *)gtname);
|
||||
newgametype->rules = newgtrules;
|
||||
newgametype->constant = G_PrepareGametypeConstant((const char *)gtconst);
|
||||
newgametype->tol = newgttol;
|
||||
newgametype->intermission = newgtinttype;
|
||||
newgametype->pointlimit = newgtpointlimit;
|
||||
newgametype->timelimit = newgttimelimit;
|
||||
|
||||
CONS_Printf("Added gametype %s\n", Gametype_Names[newgtidx]);
|
||||
gametypes[numgametypes++] = newgametype;
|
||||
|
||||
CONS_Printf("Added gametype %s\n", gtname);
|
||||
}
|
||||
|
||||
void readlevelheader(MYFILE *f, char * name)
|
||||
|
|
@ -1128,7 +1140,7 @@ void readlevelheader(MYFILE *f, char * name)
|
|||
}
|
||||
else if (fastcmp(word, "TYPEOFLEVEL"))
|
||||
{
|
||||
if (i) // it's just a number
|
||||
if (i || isdigit(word2[0])) // it's just a number
|
||||
mapheaderinfo[num]->typeoflevel = (UINT32)i;
|
||||
else
|
||||
{
|
||||
|
|
@ -1267,12 +1279,12 @@ void readlevelheader(MYFILE *f, char * name)
|
|||
else
|
||||
mapheaderinfo[num]->menuflags &= ~LF2_NOTIMEATTACK;
|
||||
}
|
||||
else if (fastcmp(word, "VISITNEEDED"))
|
||||
else if (fastcmp(word, "FINISHNEEDED"))
|
||||
{
|
||||
if (i || word2[0] == 'T' || word2[0] == 'Y')
|
||||
mapheaderinfo[num]->menuflags |= LF2_VISITNEEDED;
|
||||
mapheaderinfo[num]->menuflags |= LF2_FINISHNEEDED;
|
||||
else
|
||||
mapheaderinfo[num]->menuflags &= ~LF2_VISITNEEDED;
|
||||
mapheaderinfo[num]->menuflags &= ~LF2_FINISHNEEDED;
|
||||
}
|
||||
else if (fastcmp(word, "GRAVITY"))
|
||||
mapheaderinfo[num]->gravity = FLOAT_TO_FIXED(atof(word2));
|
||||
|
|
@ -2267,6 +2279,8 @@ void readunlockable(MYFILE *f, INT32 num)
|
|||
unlockables[num].type = SECRET_TIMEATTACK;
|
||||
else if (fastcmp(word2, "BREAKTHECAPSULES"))
|
||||
unlockables[num].type = SECRET_BREAKTHECAPSULES;
|
||||
else if (fastcmp(word2, "SPECIALATTACK"))
|
||||
unlockables[num].type = SECRET_SPECIALATTACK;
|
||||
else if (fastcmp(word2, "SOUNDTEST"))
|
||||
unlockables[num].type = SECRET_SOUNDTEST;
|
||||
else if (fastcmp(word2, "ALTTITLE"))
|
||||
|
|
@ -3670,7 +3684,7 @@ sfxenum_t get_sfx(const char *word)
|
|||
return atoi(word);
|
||||
if (fastncmp("GT_",word,3))
|
||||
word += 3; // take off the GT_
|
||||
for (i = 0; i < NUMGAMETYPES; i++)
|
||||
for (i = 0; i < MAXGAMETYPES; i++)
|
||||
if (fastcmp(word, Gametype_ConstantNames[i]+3))
|
||||
return i;
|
||||
deh_warning("Couldn't find gametype named 'GT_%s'",word);
|
||||
|
|
|
|||
|
|
@ -5791,38 +5791,36 @@ const char *const PLAYERFLAG_LIST[] = {
|
|||
};
|
||||
|
||||
const char *const GAMETYPERULE_LIST[] = {
|
||||
"CAMPAIGN",
|
||||
"RINGSLINGER",
|
||||
"SPECTATORS",
|
||||
"LIVES",
|
||||
"TEAMS",
|
||||
"FIRSTPERSON",
|
||||
"CIRCUIT",
|
||||
"BOTS",
|
||||
|
||||
"BUMPERS",
|
||||
"SPHERES",
|
||||
"CLOSERPLAYERS",
|
||||
|
||||
"BATTLESTARTS",
|
||||
"PAPERITEMS",
|
||||
"POWERSTONES",
|
||||
"TEAMFLAGS",
|
||||
"FRIENDLY",
|
||||
"SPECIALSTAGES",
|
||||
"EMERALDTOKENS",
|
||||
"EMERALDHUNT",
|
||||
"RACE",
|
||||
"TAG",
|
||||
"KARMA",
|
||||
"ITEMARROWS",
|
||||
|
||||
"CAPSULES",
|
||||
"CATCHER",
|
||||
"ROLLINGSTART",
|
||||
"SPECIALSTART",
|
||||
"BOSS",
|
||||
|
||||
"POINTLIMIT",
|
||||
"TIMELIMIT",
|
||||
"OVERTIME",
|
||||
"HURTMESSAGES",
|
||||
"FRIENDLYFIRE",
|
||||
"STARTCOUNTDOWN",
|
||||
"HIDEFROZEN",
|
||||
"BLINDFOLDED",
|
||||
"RESPAWNDELAY",
|
||||
"PITYSHIELD",
|
||||
"DEATHPENALTY",
|
||||
"NOSPECTATORSPAWN",
|
||||
"DEATHMATCHSTARTS",
|
||||
"SPAWNINVUL",
|
||||
"SPAWNENEMIES",
|
||||
"ALLOWEXIT",
|
||||
"NOTITLECARD",
|
||||
"CUTSCENES",
|
||||
"ENCORE",
|
||||
|
||||
"TEAMS",
|
||||
"NOTEAMS",
|
||||
"TEAMSTARTS",
|
||||
|
||||
"NOMP",
|
||||
"NOCUPSELECT",
|
||||
NULL
|
||||
};
|
||||
|
||||
|
|
@ -6305,7 +6303,7 @@ struct int_const_s const INT_CONST[] = {
|
|||
{"LF2_HIDEINMENU",LF2_HIDEINMENU},
|
||||
{"LF2_HIDEINSTATS",LF2_HIDEINSTATS},
|
||||
{"LF2_NOTIMEATTACK",LF2_NOTIMEATTACK},
|
||||
{"LF2_VISITNEEDED",LF2_VISITNEEDED},
|
||||
{"LF2_FINISHNEEDED",LF2_FINISHNEEDED},
|
||||
|
||||
// Emeralds
|
||||
{"EMERALD_CHAOS1",EMERALD_CHAOS1},
|
||||
|
|
@ -6403,9 +6401,9 @@ struct int_const_s const INT_CONST[] = {
|
|||
|
||||
// Intermission types
|
||||
{"int_none",int_none},
|
||||
{"int_race",int_race},
|
||||
{"int_battle",int_battle},
|
||||
{"int_battletime", int_battletime},
|
||||
{"int_time",int_time},
|
||||
{"int_score",int_score},
|
||||
{"int_scoreortimeattack", int_scoreortimeattack},
|
||||
|
||||
// Jingles (jingletype_t)
|
||||
{"JT_NONE",JT_NONE},
|
||||
|
|
|
|||
|
|
@ -499,8 +499,8 @@ void DRPC_UpdatePresence(void)
|
|||
else
|
||||
{
|
||||
snprintf(detailstr, 48, "%s%s%s",
|
||||
gametype_cons_t[gametype].strvalue,
|
||||
(gametype == GT_RACE) ? va(" | %s", kartspeed_cons_t[gamespeed].strvalue) : "",
|
||||
gametypes[gametype]->name,
|
||||
(gametyperules & GTR_CIRCUIT) ? va(" | %s", kartspeed_cons_t[gamespeed].strvalue) : "",
|
||||
(encoremode == true) ? " | Encore" : ""
|
||||
);
|
||||
discordPresence.details = detailstr;
|
||||
|
|
|
|||
|
|
@ -664,7 +664,8 @@ UINT32 quickncasehash (const char *p, size_t n)
|
|||
|
||||
// Compile date and time and revision.
|
||||
extern const char *compdate, *comptime, *comprevision, *compbranch;
|
||||
extern int compuncommitted;
|
||||
extern int compuncommitted, compoptimized;
|
||||
extern const char *comptype;
|
||||
|
||||
// Disabled code and code under testing
|
||||
// None of these that are disabled in the normal build are guaranteed to work perfectly
|
||||
|
|
|
|||
113
src/doomstat.h
113
src/doomstat.h
|
|
@ -135,9 +135,9 @@ extern boolean usedCheats;
|
|||
extern boolean imcontinuing; // Temporary flag while continuing
|
||||
extern boolean metalrecording;
|
||||
|
||||
#define ATTACKING_NONE 0
|
||||
#define ATTACKING_TIME 1
|
||||
#define ATTACKING_CAPSULES 2
|
||||
#define ATTACKING_NONE 0
|
||||
#define ATTACKING_TIME 1
|
||||
#define ATTACKING_LAP (1<<1)
|
||||
extern UINT8 modeattacking;
|
||||
|
||||
// menu demo things
|
||||
|
|
@ -151,15 +151,9 @@ extern boolean addedtogame; // true after the server has added you
|
|||
// Only true if >1 player. netgame => multiplayer but not (multiplayer=>netgame)
|
||||
extern boolean multiplayer;
|
||||
|
||||
extern INT16 gametype;
|
||||
|
||||
extern UINT32 gametyperules;
|
||||
extern INT16 gametypecount;
|
||||
|
||||
extern UINT8 splitscreen;
|
||||
extern int r_splitscreen;
|
||||
|
||||
extern boolean circuitmap; // Does this level have 'circuit mode'?
|
||||
extern boolean fromlevelselect;
|
||||
extern boolean forceresetplayers, deferencoremode;
|
||||
|
||||
|
|
@ -449,71 +443,97 @@ struct mapheader_t
|
|||
#define LF_SECTIONRACE (1<<2) ///< Section race level
|
||||
#define LF_SUBTRACTNUM (1<<3) ///< Use subtractive position number (for bright levels)
|
||||
|
||||
#define LF2_HIDEINMENU (1<<0) ///< Hide in the multiplayer menu
|
||||
#define LF2_HIDEINSTATS (1<<1) ///< Hide in the statistics screen
|
||||
#define LF2_NOTIMEATTACK (1<<2) ///< Hide this map in Time Attack modes
|
||||
#define LF2_VISITNEEDED (1<<3) ///< Not available in Time Attack modes until you visit the level
|
||||
#define LF2_HIDEINMENU (1<<0) ///< Hide in the multiplayer menu
|
||||
#define LF2_HIDEINSTATS (1<<1) ///< Hide in the statistics screen
|
||||
#define LF2_NOTIMEATTACK (1<<2) ///< Hide this map in Time Attack modes
|
||||
#define LF2_FINISHNEEDED (1<<3) ///< Not available in Time Attack modes until you beat the level
|
||||
|
||||
extern mapheader_t** mapheaderinfo;
|
||||
extern INT32 nummapheaders, mapallocsize;
|
||||
|
||||
// Gametypes
|
||||
#define NUMGAMETYPEFREESLOTS 128
|
||||
#define NUMGAMETYPEFREESLOTS (MAXGAMETYPES-GT_FIRSTFREESLOT)
|
||||
#define MAXGAMETYPELENGTH 32
|
||||
|
||||
enum GameType
|
||||
{
|
||||
GT_RACE = 0,
|
||||
GT_BATTLE,
|
||||
GT_SPECIAL,
|
||||
GT_VERSUS,
|
||||
|
||||
GT_FIRSTFREESLOT,
|
||||
GT_LASTFREESLOT = GT_FIRSTFREESLOT + NUMGAMETYPEFREESLOTS - 1,
|
||||
NUMGAMETYPES
|
||||
GT_LASTFREESLOT = 127, // Previously (GT_FIRSTFREESLOT + NUMGAMETYPEFREESLOTS - 1) - it would be necessary to rewrite VOTEMODIFIER_ENCORE to go higher than this.
|
||||
MAXGAMETYPES
|
||||
};
|
||||
// If you alter this list, update deh_tables.c, MISC_ChangeGameTypeMenu in m_menu.c, and Gametype_Names in g_game.c
|
||||
// If you alter this list, update defaultgametypes and *gametypes in g_game.c
|
||||
|
||||
#define MAXTOL (1<<31)
|
||||
#define NUMBASETOLNAMES (5)
|
||||
#define NUMTOLNAMES (NUMBASETOLNAMES + NUMGAMETYPEFREESLOTS)
|
||||
|
||||
struct gametype_t
|
||||
{
|
||||
const char *name;
|
||||
const char *constant;
|
||||
UINT32 rules;
|
||||
UINT32 tol;
|
||||
UINT8 intermission;
|
||||
INT32 pointlimit;
|
||||
INT32 timelimit;
|
||||
};
|
||||
|
||||
extern gametype_t *gametypes[MAXGAMETYPES+1];
|
||||
extern INT16 numgametypes;
|
||||
|
||||
extern INT16 gametype;
|
||||
|
||||
// Gametype rules
|
||||
enum GameTypeRules
|
||||
{
|
||||
// Race rules
|
||||
GTR_CIRCUIT = 1, // Enables the finish line, laps, and the waypoint system.
|
||||
GTR_BOTS = 1<<2, // Allows bots in this gametype. Combine with BotTiccmd hooks to make bots support your gametype.
|
||||
GTR_CIRCUIT = 1, // Enables the finish line, laps, and the waypoint system.
|
||||
GTR_BOTS = 1<<1, // Allows bots in this gametype. Combine with BotTiccmd hooks to make bots support your gametype.
|
||||
|
||||
// Battle gametype rules
|
||||
GTR_BUMPERS = 1<<3, // Enables the bumper health system
|
||||
GTR_SPHERES = 1<<4, // Replaces rings with blue spheres
|
||||
GTR_PAPERITEMS = 1<<5, // Replaces item boxes with paper item spawners
|
||||
GTR_WANTED = 1<<6, // unused
|
||||
GTR_KARMA = 1<<7, // Enables the Karma system if you're out of bumpers
|
||||
GTR_ITEMARROWS = 1<<8, // Show item box arrows above players
|
||||
GTR_CAPSULES = 1<<9, // Enables the wanted anti-camping system
|
||||
GTR_BATTLESTARTS = 1<<10, // Use Battle Mode start positions.
|
||||
GTR_BUMPERS = 1<<2, // Enables the bumper health system
|
||||
GTR_SPHERES = 1<<3, // Replaces rings with blue spheres
|
||||
GTR_CLOSERPLAYERS = 1<<4, // Buffs spindash and draft power to bring everyone together, nerfs invincibility and grow to prevent excessive combos
|
||||
|
||||
GTR_POINTLIMIT = 1<<11, // Reaching point limit ends the round
|
||||
GTR_TIMELIMIT = 1<<12, // Reaching time limit ends the round
|
||||
GTR_OVERTIME = 1<<13, // Allow overtime behavior
|
||||
GTR_BATTLESTARTS = 1<<5, // Use Battle Mode start positions.
|
||||
GTR_PAPERITEMS = 1<<6, // Replaces item boxes with paper item spawners
|
||||
GTR_POWERSTONES = 1<<7, // Battle Emerald collectables.
|
||||
GTR_KARMA = 1<<8, // Enables the Karma system if you're out of bumpers
|
||||
GTR_ITEMARROWS = 1<<9, // Show item box arrows above players
|
||||
|
||||
// Custom gametype rules
|
||||
GTR_TEAMS = 1<<14, // Teams are forced on
|
||||
GTR_NOTEAMS = 1<<15, // Teams are forced off
|
||||
GTR_TEAMSTARTS = 1<<16, // Use team-based start positions
|
||||
// Bonus gametype rules
|
||||
GTR_CAPSULES = 1<<10, // Can enter Break The Capsules mode
|
||||
GTR_CATCHER = 1<<11, // UFO Catcher (only works with GTR_CIRCUIT)
|
||||
GTR_ROLLINGSTART = 1<<12, // Rolling start (only works with GTR_CIRCUIT)
|
||||
GTR_SPECIALSTART = 1<<13, // White fade instant start
|
||||
GTR_BOSS = 1<<14, // Boss intro and spawning
|
||||
|
||||
// Grand Prix rules
|
||||
GTR_CAMPAIGN = 1<<17, // Handles cup-based progression
|
||||
GTR_LIVES = 1<<18, // Lives system, players are forced to spectate during Game Over.
|
||||
GTR_SPECIALBOTS = 1<<19, // Bot difficulty gets stronger between rounds, and the rival system is enabled.
|
||||
// General purpose rules
|
||||
GTR_POINTLIMIT = 1<<15, // Reaching point limit ends the round
|
||||
GTR_TIMELIMIT = 1<<16, // Reaching time limit ends the round
|
||||
GTR_OVERTIME = 1<<17, // Allow overtime behavior
|
||||
GTR_ENCORE = 1<<18, // Alternate Encore mirroring, scripting, and texture remapping
|
||||
|
||||
GTR_NOCUPSELECT = 1<<20, // Your maps are not selected via cup. ...mutually exclusive with GTR_CAMPAIGN.
|
||||
GTR_TEAMS = 1<<19, // Teams are forced on
|
||||
GTR_NOTEAMS = 1<<20, // Teams are forced off
|
||||
GTR_TEAMSTARTS = 1<<21, // Use team-based start positions
|
||||
|
||||
GTR_NOMP = 1<<22, // No multiplayer
|
||||
GTR_NOCUPSELECT = 1<<23, // Your maps are not selected via cup.
|
||||
|
||||
// free: to and including 1<<31
|
||||
};
|
||||
// Remember to update GAMETYPERULE_LIST in deh_soc.c
|
||||
|
||||
// String names for gametypes
|
||||
extern const char *Gametype_Names[NUMGAMETYPES];
|
||||
extern const char *Gametype_ConstantNames[NUMGAMETYPES];
|
||||
#define GTR_FORBIDMP (GTR_NOMP|GTR_CATCHER|GTR_BOSS)
|
||||
|
||||
// Point and time limits for every gametype
|
||||
extern INT32 pointlimits[NUMGAMETYPES];
|
||||
extern INT32 timelimits[NUMGAMETYPES];
|
||||
// TODO: replace every instance
|
||||
#define gametyperules (gametypes[gametype]->rules)
|
||||
|
||||
// TypeOfLevel things
|
||||
enum TypeOfLevel
|
||||
|
|
@ -527,9 +547,10 @@ enum TypeOfLevel
|
|||
// Modifiers
|
||||
TOL_TV = 0x0100 ///< Midnight Channel specific: draw TV like overlay on HUD
|
||||
};
|
||||
// Make sure to update TYPEOFLEVEL too
|
||||
|
||||
#define MAXTOL (1<<31)
|
||||
#define NUMBASETOLNAMES (4)
|
||||
#define NUMBASETOLNAMES (5)
|
||||
#define NUMTOLNAMES (NUMBASETOLNAMES + NUMGAMETYPEFREESLOTS)
|
||||
|
||||
struct tolinfo_t
|
||||
|
|
|
|||
|
|
@ -1889,6 +1889,52 @@ void F_StartTitleScreen(void)
|
|||
F_CacheTitleScreen();
|
||||
}
|
||||
|
||||
void F_VersionDrawer(void)
|
||||
{
|
||||
// An adapted thing from old menus - most games have version info on the title screen now...
|
||||
INT32 texty = vid.height - 10*vid.dupy;
|
||||
|
||||
#define addtext(f, str) {\
|
||||
V_DrawThinString(vid.dupx, texty, V_NOSCALESTART|f, str);\
|
||||
texty -= 10*vid.dupy;\
|
||||
}
|
||||
if (customversionstring[0] != '\0')
|
||||
{
|
||||
addtext(V_ALLOWLOWERCASE, customversionstring);
|
||||
addtext(0, "Mod version:");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Development -- show revision / branch info
|
||||
#if defined(TESTERS)
|
||||
addtext(V_ALLOWLOWERCASE|V_SKYMAP, "Tester client");
|
||||
addtext(V_ALLOWLOWERCASE|V_TRANSLUCENT, va("%s", compdate));
|
||||
#elif defined(HOSTTESTERS)
|
||||
addtext(V_ALLOWLOWERCASE|V_REDMAP, "Netgame host for testers");
|
||||
addtext(V_ALLOWLOWERCASE|V_TRANSLUCENT, va("%s", compdate));
|
||||
#elif defined(DEVELOP)
|
||||
addtext(V_ALLOWLOWERCASE|V_TRANSLUCENT, comprevision);
|
||||
addtext(V_ALLOWLOWERCASE|V_TRANSLUCENT, compbranch);
|
||||
#else // Regular build
|
||||
addtext(V_ALLOWLOWERCASE|V_TRANSLUCENT, va("%s", VERSIONSTRING));
|
||||
#endif
|
||||
if (compoptimized)
|
||||
{
|
||||
addtext(V_ALLOWLOWERCASE|V_TRANSLUCENT, va("%s build", comptype));
|
||||
}
|
||||
else
|
||||
{
|
||||
addtext(V_ALLOWLOWERCASE|V_ORANGEMAP, va("%s build (no optimizations)", comptype));
|
||||
}
|
||||
|
||||
if (compuncommitted)
|
||||
{
|
||||
addtext(V_REDMAP|V_STRINGDANCE, "! UNCOMMITTED CHANGES !");
|
||||
}
|
||||
}
|
||||
#undef addtext
|
||||
}
|
||||
|
||||
// (no longer) De-Demo'd Title Screen
|
||||
void F_TitleScreenDrawer(void)
|
||||
{
|
||||
|
|
@ -1959,39 +2005,7 @@ void F_TitleScreenDrawer(void)
|
|||
|
||||
V_DrawFixedPatch(0, 0, FRACUNIT, 0, kts_copyright, NULL);
|
||||
|
||||
// An adapted thing from old menus - most games have version info on the title screen now...
|
||||
{
|
||||
INT32 texty = vid.height - 10*vid.dupy;
|
||||
#define addtext(f, str) {\
|
||||
V_DrawThinString(vid.dupx, texty, V_NOSCALESTART|f, str);\
|
||||
texty -= 10*vid.dupy;\
|
||||
}
|
||||
if (customversionstring[0] != '\0')
|
||||
{
|
||||
addtext(V_ALLOWLOWERCASE, customversionstring);
|
||||
addtext(0, "Mod version:");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Development -- show revision / branch info
|
||||
#if defined(TESTERS)
|
||||
addtext(V_ALLOWLOWERCASE|V_SKYMAP, "Tester client");
|
||||
addtext(V_ALLOWLOWERCASE|V_TRANSLUCENT, va("%s", compdate));
|
||||
#elif defined(HOSTTESTERS)
|
||||
addtext(V_ALLOWLOWERCASE|V_REDMAP, "Netgame host for testers");
|
||||
addtext(V_ALLOWLOWERCASE|V_TRANSLUCENT, va("%s", compdate));
|
||||
#elif defined(DEVELOP)
|
||||
addtext(V_ALLOWLOWERCASE|V_TRANSLUCENT, comprevision);
|
||||
addtext(V_ALLOWLOWERCASE|V_TRANSLUCENT, compbranch);
|
||||
#else // Regular build
|
||||
addtext(V_ALLOWLOWERCASE|V_TRANSLUCENT, va("%s", VERSIONSTRING));
|
||||
#endif
|
||||
if (compuncommitted)
|
||||
addtext(V_REDMAP|V_STRINGDANCE, "! UNCOMMITTED CHANGES !");
|
||||
}
|
||||
#undef addtext
|
||||
}
|
||||
|
||||
F_VersionDrawer();
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -60,6 +60,8 @@ void F_EndingDrawer(void);
|
|||
void F_CreditTicker(void);
|
||||
void F_CreditDrawer(void);
|
||||
|
||||
void F_VersionDrawer(void);
|
||||
|
||||
void F_StartCustomCutscene(INT32 cutscenenum, boolean precutscene, boolean resetplayer);
|
||||
void F_CutsceneDrawer(void);
|
||||
void F_EndCutScene(void);
|
||||
|
|
|
|||
183
src/g_demo.c
183
src/g_demo.c
|
|
@ -119,18 +119,14 @@ demoghost *ghosts = NULL;
|
|||
#define DEMOVERSION 0x0007
|
||||
#define DEMOHEADER "\xF0" "KartReplay" "\x0F"
|
||||
|
||||
#define DF_GHOST 0x01 // This demo contains ghost data too!
|
||||
#define DF_TIMEATTACK 0x02 // This demo is from Time Attack and contains its final completion time & best lap!
|
||||
#define DF_BREAKTHECAPSULES 0x04 // This demo is from Break the Capsules and contains its final completion time!
|
||||
#define DF_ATTACKMASK 0x06 // This demo is from ??? attack and contains ???
|
||||
#define DF_ATTACKMASK (ATTACKING_TIME|ATTACKING_LAP) // This demo contains time/lap data
|
||||
|
||||
// 0x08 free
|
||||
#define DF_GHOST 0x08 // This demo contains ghost data too!
|
||||
|
||||
#define DF_NONETMP 0x10 // multiplayer but not netgame
|
||||
|
||||
#define DF_LUAVARS 0x20 // this demo contains extra lua vars
|
||||
|
||||
#define DF_ATTACKSHIFT 1
|
||||
#define DF_ENCORE 0x40
|
||||
#define DF_MULTIPLAYER 0x80 // This demo was recorded in multiplayer mode!
|
||||
|
||||
|
|
@ -2341,10 +2337,19 @@ void G_BeginRecording(void)
|
|||
memset(name,0,sizeof(name));
|
||||
|
||||
demobuf.p = demobuf.buffer;
|
||||
demoflags = DF_GHOST|(multiplayer ? DF_MULTIPLAYER : (modeattacking<<DF_ATTACKSHIFT));
|
||||
|
||||
if (multiplayer && !netgame)
|
||||
demoflags |= DF_NONETMP;
|
||||
demoflags = DF_GHOST;
|
||||
|
||||
if (multiplayer)
|
||||
{
|
||||
demoflags |= DF_MULTIPLAYER;
|
||||
if (!netgame)
|
||||
demoflags |= DF_NONETMP;
|
||||
}
|
||||
else
|
||||
{
|
||||
demoflags |= modeattacking;
|
||||
}
|
||||
|
||||
if (encoremode)
|
||||
demoflags |= DF_ENCORE;
|
||||
|
|
@ -2375,7 +2380,9 @@ void G_BeginRecording(void)
|
|||
M_Memcpy(demobuf.p, mapmd5, 16); demobuf.p += 16;
|
||||
|
||||
WRITEUINT8(demobuf.p, demoflags);
|
||||
WRITEUINT8(demobuf.p, gametype & 0xFF);
|
||||
|
||||
WRITESTRINGN(demobuf.p, gametypes[gametype]->name, MAXGAMETYPELENGTH);
|
||||
|
||||
WRITEUINT8(demobuf.p, numlaps);
|
||||
|
||||
// file list
|
||||
|
|
@ -2384,21 +2391,18 @@ void G_BeginRecording(void)
|
|||
// character list
|
||||
G_SaveDemoSkins(&demobuf.p);
|
||||
|
||||
switch ((demoflags & DF_ATTACKMASK)>>DF_ATTACKSHIFT)
|
||||
if ((demoflags & DF_ATTACKMASK))
|
||||
{
|
||||
case ATTACKING_NONE: // 0
|
||||
break;
|
||||
case ATTACKING_TIME: // 1
|
||||
demotime_p = demobuf.p;
|
||||
demotime_p = demobuf.p;
|
||||
|
||||
if (demoflags & ATTACKING_TIME)
|
||||
WRITEUINT32(demobuf.p,UINT32_MAX); // time
|
||||
if (demoflags & ATTACKING_LAP)
|
||||
WRITEUINT32(demobuf.p,UINT32_MAX); // lap
|
||||
break;
|
||||
case ATTACKING_CAPSULES: // 2
|
||||
demotime_p = demobuf.p;
|
||||
WRITEUINT32(demobuf.p,UINT32_MAX); // time
|
||||
break;
|
||||
default: // 3
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
demotime_p = NULL;
|
||||
}
|
||||
|
||||
for (i = 0; i < PRNUMCLASS; i++)
|
||||
|
|
@ -2602,18 +2606,15 @@ void G_SetDemoTime(UINT32 ptime, UINT32 plap)
|
|||
{
|
||||
if (!demo.recording || !demotime_p)
|
||||
return;
|
||||
if (demoflags & DF_TIMEATTACK)
|
||||
if (demoflags & ATTACKING_TIME)
|
||||
{
|
||||
WRITEUINT32(demotime_p, ptime);
|
||||
}
|
||||
if (demoflags & ATTACKING_LAP)
|
||||
{
|
||||
WRITEUINT32(demotime_p, plap);
|
||||
demotime_p = NULL;
|
||||
}
|
||||
else if (demoflags & DF_BREAKTHECAPSULES)
|
||||
{
|
||||
WRITEUINT32(demotime_p, ptime);
|
||||
(void)plap;
|
||||
demotime_p = NULL;
|
||||
}
|
||||
demotime_p = NULL;
|
||||
}
|
||||
|
||||
// Returns bitfield:
|
||||
|
|
@ -2624,7 +2625,8 @@ UINT8 G_CmpDemoTime(char *oldname, char *newname)
|
|||
{
|
||||
UINT8 *buffer,*p;
|
||||
UINT8 flags;
|
||||
UINT32 oldtime, newtime, oldlap, newlap;
|
||||
UINT32 oldtime = UINT32_MAX, newtime = UINT32_MAX;
|
||||
UINT32 oldlap = UINT32_MAX, newlap = UINT32_MAX;
|
||||
UINT16 oldversion;
|
||||
size_t bufsize ATTRUNUSED;
|
||||
UINT8 c;
|
||||
|
|
@ -2654,23 +2656,22 @@ UINT8 G_CmpDemoTime(char *oldname, char *newname)
|
|||
SKIPSTRING(p); // gamemap
|
||||
p += 16; // map md5
|
||||
flags = READUINT8(p); // demoflags
|
||||
p++; // gametype
|
||||
SKIPSTRING(p); // gametype
|
||||
p++; // numlaps
|
||||
G_SkipDemoExtraFiles(&p);
|
||||
|
||||
G_SkipDemoSkins(&p);
|
||||
|
||||
aflags = flags & (DF_TIMEATTACK|DF_BREAKTHECAPSULES);
|
||||
aflags = flags & DF_ATTACKMASK;
|
||||
I_Assert(aflags);
|
||||
|
||||
if (flags & DF_TIMEATTACK)
|
||||
uselaps = true; // get around uninitalized error
|
||||
if (aflags & ATTACKING_LAP)
|
||||
uselaps = true;
|
||||
|
||||
newtime = READUINT32(p);
|
||||
if (aflags & ATTACKING_TIME)
|
||||
newtime = READUINT32(p);
|
||||
if (uselaps)
|
||||
newlap = READUINT32(p);
|
||||
else
|
||||
newlap = UINT32_MAX;
|
||||
|
||||
Z_Free(buffer);
|
||||
|
||||
|
|
@ -2714,7 +2715,7 @@ UINT8 G_CmpDemoTime(char *oldname, char *newname)
|
|||
SKIPSTRING(p); // gamemap
|
||||
p += 16; // mapmd5
|
||||
flags = READUINT8(p);
|
||||
p++; // gametype
|
||||
SKIPSTRING(p); // gametype
|
||||
p++; // numlaps
|
||||
G_SkipDemoExtraFiles(&p);
|
||||
if (!(flags & aflags))
|
||||
|
|
@ -2726,11 +2727,10 @@ UINT8 G_CmpDemoTime(char *oldname, char *newname)
|
|||
|
||||
G_SkipDemoSkins(&p);
|
||||
|
||||
oldtime = READUINT32(p);
|
||||
if (flags & ATTACKING_TIME)
|
||||
oldtime = READUINT32(p);
|
||||
if (uselaps)
|
||||
oldlap = READUINT32(p);
|
||||
else
|
||||
oldlap = 0;
|
||||
|
||||
Z_Free(buffer);
|
||||
|
||||
|
|
@ -2760,7 +2760,7 @@ void G_LoadDemoInfo(menudemo_t *pdemo)
|
|||
UINT8 version, subversion, pdemoflags, worknumskins, skinid;
|
||||
democharlist_t *skinlist = NULL;
|
||||
UINT16 pdemoversion, count;
|
||||
char mapname[MAXMAPLUMPNAME];
|
||||
char mapname[MAXMAPLUMPNAME],gtname[MAXGAMETYPELENGTH];
|
||||
INT32 i;
|
||||
|
||||
if (!FIL_ReadFile(pdemo->filepath, &infobuffer))
|
||||
|
|
@ -2824,7 +2824,9 @@ void G_LoadDemoInfo(menudemo_t *pdemo)
|
|||
return;
|
||||
}
|
||||
|
||||
pdemo->gametype = READUINT8(info_p);
|
||||
READSTRINGN(info_p, gtname, sizeof(gtname)); // gametype
|
||||
pdemo->gametype = G_GetGametypeByName(gtname);
|
||||
|
||||
pdemo->numlaps = READUINT8(info_p);
|
||||
|
||||
pdemo->addonstatus = G_CheckDemoExtraFiles(&info_p, true);
|
||||
|
|
@ -2936,9 +2938,11 @@ void G_DeferedPlayDemo(const char *name)
|
|||
|
||||
void G_DoPlayDemo(char *defdemoname)
|
||||
{
|
||||
UINT8 i, p, numslots = 0;
|
||||
INT32 i;
|
||||
UINT8 p, numslots = 0;
|
||||
lumpnum_t l;
|
||||
char color[MAXCOLORNAME+1],follower[17],mapname[MAXMAPLUMPNAME],*n,*pdemoname;
|
||||
char color[MAXCOLORNAME+1],follower[17],mapname[MAXMAPLUMPNAME],gtname[MAXGAMETYPELENGTH];
|
||||
char *n,*pdemoname;
|
||||
UINT8 availabilities[MAXPLAYERS][MAXAVAILABILITY];
|
||||
UINT8 version,subversion;
|
||||
UINT32 randseed[PRNUMCLASS];
|
||||
|
|
@ -2955,6 +2959,7 @@ void G_DoPlayDemo(char *defdemoname)
|
|||
|
||||
follower[16] = '\0';
|
||||
color[MAXCOLORNAME] = '\0';
|
||||
gtname[MAXGAMETYPELENGTH-1] = '\0';
|
||||
|
||||
// No demo name means we're restarting the current demo
|
||||
if (defdemoname == NULL)
|
||||
|
|
@ -3064,8 +3069,22 @@ void G_DoPlayDemo(char *defdemoname)
|
|||
demobuf.p += 16; // mapmd5
|
||||
|
||||
demoflags = READUINT8(demobuf.p);
|
||||
gametype = READUINT8(demobuf.p);
|
||||
G_SetGametype(gametype);
|
||||
|
||||
READSTRINGN(demobuf.p, gtname, sizeof(gtname)); // gametype
|
||||
i = G_GetGametypeByName(gtname);
|
||||
if (i < 0)
|
||||
{
|
||||
snprintf(msg, 1024, M_GetText("%s is in a gametype that is not currently loaded and cannot be played.\n"), pdemoname);
|
||||
CONS_Alert(CONS_ERROR, "%s", msg);
|
||||
M_StartMessage(msg, NULL, MM_NOTHING);
|
||||
Z_Free(pdemoname);
|
||||
Z_Free(demobuf.buffer);
|
||||
demo.playback = false;
|
||||
demo.title = false;
|
||||
return;
|
||||
}
|
||||
G_SetGametype(i);
|
||||
|
||||
numlaps = READUINT8(demobuf.p);
|
||||
|
||||
if (demo.title) // Titledemos should always play and ought to always be compatible with whatever wadlist is running.
|
||||
|
|
@ -3138,7 +3157,7 @@ void G_DoPlayDemo(char *defdemoname)
|
|||
return;
|
||||
}
|
||||
|
||||
modeattacking = (demoflags & DF_ATTACKMASK)>>DF_ATTACKSHIFT;
|
||||
modeattacking = (demoflags & DF_ATTACKMASK);
|
||||
multiplayer = !!(demoflags & DF_MULTIPLAYER);
|
||||
demo.netgame = (multiplayer && !(demoflags & DF_NONETMP));
|
||||
CON_ToggleOff();
|
||||
|
|
@ -3146,21 +3165,10 @@ void G_DoPlayDemo(char *defdemoname)
|
|||
hu_demotime = UINT32_MAX;
|
||||
hu_demolap = UINT32_MAX;
|
||||
|
||||
switch (modeattacking)
|
||||
{
|
||||
case ATTACKING_NONE: // 0
|
||||
break;
|
||||
case ATTACKING_TIME: // 1
|
||||
hu_demotime = READUINT32(demobuf.p);
|
||||
hu_demolap = READUINT32(demobuf.p);
|
||||
break;
|
||||
case ATTACKING_CAPSULES: // 2
|
||||
hu_demotime = READUINT32(demobuf.p);
|
||||
break;
|
||||
default: // 3
|
||||
modeattacking = ATTACKING_NONE;
|
||||
break;
|
||||
}
|
||||
if (modeattacking & ATTACKING_TIME)
|
||||
hu_demotime = READUINT32(demobuf.p);
|
||||
if (modeattacking & ATTACKING_LAP)
|
||||
hu_demolap = READUINT32(demobuf.p);
|
||||
|
||||
// Random seed
|
||||
for (i = 0; i < PRNUMCLASS; i++)
|
||||
|
|
@ -3534,7 +3542,7 @@ void G_AddGhost(char *defdemoname)
|
|||
return;
|
||||
}
|
||||
|
||||
p++; // gametype
|
||||
SKIPSTRING(p); // gametype
|
||||
p++; // numlaps
|
||||
G_SkipDemoExtraFiles(&p); // Don't wanna modify the file list for ghosts.
|
||||
|
||||
|
|
@ -3547,19 +3555,10 @@ void G_AddGhost(char *defdemoname)
|
|||
return;
|
||||
}
|
||||
|
||||
switch ((flags & DF_ATTACKMASK)>>DF_ATTACKSHIFT)
|
||||
{
|
||||
case ATTACKING_NONE: // 0
|
||||
break;
|
||||
case ATTACKING_TIME: // 1
|
||||
p += 8; // demo time, lap
|
||||
break;
|
||||
case ATTACKING_CAPSULES: // 2
|
||||
p += 4; // demo time
|
||||
break;
|
||||
default: // 3
|
||||
break;
|
||||
}
|
||||
if (flags & ATTACKING_TIME)
|
||||
p += 4;
|
||||
if (flags & ATTACKING_LAP)
|
||||
p += 4;
|
||||
|
||||
for (i = 0; i < PRNUMCLASS; i++)
|
||||
{
|
||||
|
|
@ -3589,9 +3588,10 @@ void G_AddGhost(char *defdemoname)
|
|||
p++; // player number - doesn't really need to be checked, TODO maybe support adding multiple players' ghosts at once
|
||||
|
||||
// any invalidating flags?
|
||||
if ((READUINT8(p) & (DEMO_SPECTATOR|DEMO_BOT)) != 0)
|
||||
i = READUINT8(p);
|
||||
if ((i & (DEMO_SPECTATOR|DEMO_BOT)) != 0)
|
||||
{
|
||||
CONS_Alert(CONS_NOTICE, M_GetText("Failed to add ghost %s: Invalid player slot.\n"), pdemoname);
|
||||
CONS_Alert(CONS_NOTICE, M_GetText("Failed to add ghost %s: Invalid player slot (spectator/bot)\n"), pdemoname);
|
||||
Z_Free(skinlist);
|
||||
Z_Free(pdemoname);
|
||||
Z_Free(buffer);
|
||||
|
|
@ -3602,6 +3602,8 @@ void G_AddGhost(char *defdemoname)
|
|||
M_Memcpy(name, p, 16);
|
||||
p += 16;
|
||||
|
||||
p += MAXAVAILABILITY;
|
||||
|
||||
// Skin
|
||||
i = READUINT8(p);
|
||||
if (i < worknumskins)
|
||||
|
|
@ -3622,7 +3624,7 @@ void G_AddGhost(char *defdemoname)
|
|||
|
||||
if (READUINT8(p) != 0xFF)
|
||||
{
|
||||
CONS_Alert(CONS_NOTICE, M_GetText("Failed to add ghost %s: Invalid player slot.\n"), pdemoname);
|
||||
CONS_Alert(CONS_NOTICE, M_GetText("Failed to add ghost %s: Invalid player slot (bad terminator)\n"), pdemoname);
|
||||
Z_Free(skinlist);
|
||||
Z_Free(pdemoname);
|
||||
Z_Free(buffer);
|
||||
|
|
@ -3757,25 +3759,16 @@ void G_UpdateStaffGhostName(lumpnum_t l)
|
|||
goto fail; // we don't NEED to do it here, but whatever
|
||||
}
|
||||
|
||||
p++; // Gametype
|
||||
SKIPSTRING(p); // gametype
|
||||
p++; // numlaps
|
||||
G_SkipDemoExtraFiles(&p);
|
||||
|
||||
G_SkipDemoSkins(&p);
|
||||
|
||||
switch ((flags & DF_ATTACKMASK)>>DF_ATTACKSHIFT)
|
||||
{
|
||||
case ATTACKING_NONE: // 0
|
||||
break;
|
||||
case ATTACKING_TIME: // 1
|
||||
p += 8; // demo time, lap
|
||||
break;
|
||||
case ATTACKING_CAPSULES: // 2
|
||||
p += 4; // demo time
|
||||
break;
|
||||
default: // 3
|
||||
break;
|
||||
}
|
||||
if (flags & ATTACKING_TIME)
|
||||
p += 4;
|
||||
if (flags & ATTACKING_LAP)
|
||||
p += 4;
|
||||
|
||||
for (i = 0; i < PRNUMCLASS; i++)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -86,7 +86,7 @@ struct menudemo_t {
|
|||
char title[65]; // Null-terminated for string prints
|
||||
UINT16 map;
|
||||
UINT8 addonstatus; // What do we need to do addon-wise to play this demo?
|
||||
UINT8 gametype;
|
||||
INT16 gametype;
|
||||
SINT8 kartspeed; // Add OR DF_ENCORE for encore mode, idk
|
||||
UINT8 numlaps;
|
||||
|
||||
|
|
|
|||
494
src/g_game.c
494
src/g_game.c
|
|
@ -317,9 +317,8 @@ typedef struct
|
|||
{
|
||||
INT16 *mapbuffer; // Pointer to zone memory
|
||||
INT32 lastnummapheaders; // Reset if nummapheaders != this
|
||||
UINT8 counttogametype; // Time to gametype change event
|
||||
} randmaps_t;
|
||||
static randmaps_t randmaps = {NULL, 0, 0};
|
||||
static randmaps_t randmaps = {NULL, 0};
|
||||
|
||||
static void G_ResetRandMapBuffer(void)
|
||||
{
|
||||
|
|
@ -329,7 +328,6 @@ static void G_ResetRandMapBuffer(void)
|
|||
randmaps.mapbuffer = Z_Malloc(randmaps.lastnummapheaders * sizeof(INT16), PU_STATIC, NULL);
|
||||
for (i = 0; i < randmaps.lastnummapheaders; i++)
|
||||
randmaps.mapbuffer[i] = -1;
|
||||
//intentionally not resetting randmaps.counttogametype here
|
||||
}
|
||||
|
||||
typedef struct joystickvector2_s
|
||||
|
|
@ -517,13 +515,18 @@ static void G_UpdateRecordReplays(void)
|
|||
players[consoleplayer].realtime = UINT32_MAX;
|
||||
}
|
||||
|
||||
if (((mapheaderinfo[gamemap-1]->mainrecord->time == 0) || (players[consoleplayer].realtime < mapheaderinfo[gamemap-1]->mainrecord->time))
|
||||
&& (players[consoleplayer].realtime < UINT32_MAX)) // DNF
|
||||
if (modeattacking & ATTACKING_TIME)
|
||||
{
|
||||
mapheaderinfo[gamemap-1]->mainrecord->time = players[consoleplayer].realtime;
|
||||
if (((mapheaderinfo[gamemap-1]->mainrecord->time == 0) || (players[consoleplayer].realtime < mapheaderinfo[gamemap-1]->mainrecord->time))
|
||||
&& (players[consoleplayer].realtime < UINT32_MAX)) // DNF
|
||||
mapheaderinfo[gamemap-1]->mainrecord->time = players[consoleplayer].realtime;
|
||||
}
|
||||
else
|
||||
{
|
||||
mapheaderinfo[gamemap-1]->mainrecord->time = 0;
|
||||
}
|
||||
|
||||
if (modeattacking == ATTACKING_TIME)
|
||||
if (modeattacking & ATTACKING_LAP)
|
||||
{
|
||||
if ((mapheaderinfo[gamemap-1]->mainrecord->lap == 0) || (bestlap < mapheaderinfo[gamemap-1]->mainrecord->lap))
|
||||
mapheaderinfo[gamemap-1]->mainrecord->lap = bestlap;
|
||||
|
|
@ -546,27 +549,32 @@ static void G_UpdateRecordReplays(void)
|
|||
strcat(gpath, PATHSEP);
|
||||
strcat(gpath, G_BuildMapName(gamemap));
|
||||
|
||||
snprintf(lastdemo, 255, "%s-%s-last.lmp", gpath, cv_chooseskin.string);
|
||||
snprintf(lastdemo, 255, "%s-%s-last.lmp", gpath, cv_skin[0].string);
|
||||
|
||||
gpath = Z_StrDup(gpath);
|
||||
|
||||
if (FIL_FileExists(lastdemo))
|
||||
if (modeattacking != ATTACKING_NONE && FIL_FileExists(lastdemo))
|
||||
{
|
||||
UINT8 *buf;
|
||||
size_t len = FIL_ReadFile(lastdemo, &buf);
|
||||
size_t len;
|
||||
|
||||
snprintf(bestdemo, 255, "%s-%s-time-best.lmp", gpath, cv_chooseskin.string);
|
||||
if (!FIL_FileExists(bestdemo) || G_CmpDemoTime(bestdemo, lastdemo) & 1)
|
||||
{ // Better time, save this demo.
|
||||
if (FIL_FileExists(bestdemo))
|
||||
remove(bestdemo);
|
||||
FIL_WriteFile(bestdemo, buf, len);
|
||||
CONS_Printf("\x83%s\x80 %s '%s'\n", M_GetText("NEW RECORD TIME!"), M_GetText("Saved replay as"), bestdemo);
|
||||
gpath = Z_StrDup(gpath);
|
||||
|
||||
len = FIL_ReadFile(lastdemo, &buf);
|
||||
|
||||
if (modeattacking & ATTACKING_TIME)
|
||||
{
|
||||
snprintf(bestdemo, 255, "%s-%s-time-best.lmp", gpath, cv_skin[0].string);
|
||||
if (!FIL_FileExists(bestdemo) || G_CmpDemoTime(bestdemo, lastdemo) & 1)
|
||||
{ // Better time, save this demo.
|
||||
if (FIL_FileExists(bestdemo))
|
||||
remove(bestdemo);
|
||||
FIL_WriteFile(bestdemo, buf, len);
|
||||
CONS_Printf("\x83%s\x80 %s '%s'\n", M_GetText("NEW RECORD TIME!"), M_GetText("Saved replay as"), bestdemo);
|
||||
}
|
||||
}
|
||||
|
||||
if (modeattacking == ATTACKING_TIME)
|
||||
if (modeattacking & ATTACKING_LAP)
|
||||
{
|
||||
snprintf(bestdemo, 255, "%s-%s-lap-best.lmp", gpath, cv_chooseskin.string);
|
||||
snprintf(bestdemo, 255, "%s-%s-lap-best.lmp", gpath, cv_skin[0].string);
|
||||
if (!FIL_FileExists(bestdemo) || G_CmpDemoTime(bestdemo, lastdemo) & (1<<1))
|
||||
{ // Better lap time, save this demo.
|
||||
if (FIL_FileExists(bestdemo))
|
||||
|
|
@ -579,9 +587,9 @@ static void G_UpdateRecordReplays(void)
|
|||
//CONS_Printf("%s '%s'\n", M_GetText("Saved replay as"), lastdemo);
|
||||
|
||||
Z_Free(buf);
|
||||
}
|
||||
|
||||
Z_Free(gpath);
|
||||
Z_Free(gpath);
|
||||
}
|
||||
|
||||
// Check emblems when level data is updated
|
||||
if ((earnedEmblems = M_CheckLevelEmblems()))
|
||||
|
|
@ -1409,7 +1417,7 @@ void G_StartTitleCard(void)
|
|||
{
|
||||
// The title card has been disabled for this map.
|
||||
// Oh well.
|
||||
if (!G_IsTitleCardAvailable() || demo.rewinding)
|
||||
if (demo.rewinding || !G_IsTitleCardAvailable())
|
||||
{
|
||||
WipeStageTitle = false;
|
||||
return;
|
||||
|
|
@ -1424,9 +1432,9 @@ void G_StartTitleCard(void)
|
|||
// play the sound
|
||||
{
|
||||
sfxenum_t kstart = sfx_kstart;
|
||||
if (bossinfo.boss)
|
||||
if (K_CheckBossIntro() == true)
|
||||
kstart = sfx_ssa021;
|
||||
else if (encoremode)
|
||||
else if (encoremode == true)
|
||||
kstart = sfx_ruby2;
|
||||
S_StartSound(NULL, kstart);
|
||||
}
|
||||
|
|
@ -1473,11 +1481,17 @@ void G_PreLevelTitleCard(void)
|
|||
//
|
||||
boolean G_IsTitleCardAvailable(void)
|
||||
{
|
||||
#if 0
|
||||
// Overwrites all other title card exceptions.
|
||||
if (K_CheckBossIntro() == true)
|
||||
return true;
|
||||
|
||||
// The current level has no name.
|
||||
if (!mapheaderinfo[gamemap-1]->lvlttl[0])
|
||||
return false;
|
||||
#endif
|
||||
|
||||
// Instant white fade.
|
||||
if (gametyperules & GTR_SPECIALSTART)
|
||||
return false;
|
||||
|
||||
// The title card is available.
|
||||
return true;
|
||||
|
|
@ -2789,22 +2803,9 @@ mapthing_t *G_FindMapStart(INT32 playernum)
|
|||
if (!playeringame[playernum])
|
||||
return NULL;
|
||||
|
||||
// -- Spectators --
|
||||
// Order in platform gametypes: Race->DM->CTF
|
||||
// And, with deathmatch starts: DM->CTF->Race
|
||||
if (players[playernum].spectator)
|
||||
{
|
||||
// In platform gametypes, spawn in Co-op starts first
|
||||
// Overriden by GTR_BATTLESTARTS.
|
||||
if (gametyperules & GTR_BATTLESTARTS && bossinfo.boss == false)
|
||||
spawnpoint = G_FindBattleStartOrFallback(playernum);
|
||||
else
|
||||
spawnpoint = G_FindRaceStartOrFallback(playernum);
|
||||
}
|
||||
|
||||
// -- Grand Prix / Time Attack --
|
||||
// -- Time Attack --
|
||||
// Order: Race->DM->CTF
|
||||
else if (grandprixinfo.gp || modeattacking)
|
||||
if (K_TimeAttackRules() == true)
|
||||
spawnpoint = G_FindRaceStartOrFallback(playernum);
|
||||
|
||||
// -- CTF --
|
||||
|
|
@ -2909,17 +2910,20 @@ void G_ExitLevel(void)
|
|||
if (gamestate == GS_LEVEL)
|
||||
{
|
||||
UINT8 i;
|
||||
boolean youlost = false;
|
||||
if (bossinfo.boss == true)
|
||||
boolean doretry = false;
|
||||
|
||||
if (!G_GametypeUsesLives())
|
||||
; // never force a retry
|
||||
else if (specialstageinfo.valid == true || (gametyperules & GTR_BOSS))
|
||||
{
|
||||
youlost = true;
|
||||
doretry = true;
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
if (playeringame[i] && !players[i].spectator && !players[i].bot)
|
||||
{
|
||||
if (players[i].bumpers > 0)
|
||||
if (!K_IsPlayerLosing(&players[i]))
|
||||
{
|
||||
youlost = false;
|
||||
doretry = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -2927,10 +2931,10 @@ void G_ExitLevel(void)
|
|||
}
|
||||
else if (grandprixinfo.gp == true && grandprixinfo.eventmode == GPEVENT_NONE)
|
||||
{
|
||||
youlost = (grandprixinfo.wonround != true);
|
||||
doretry = (grandprixinfo.wonround != true);
|
||||
}
|
||||
|
||||
if (youlost)
|
||||
if (doretry)
|
||||
{
|
||||
// You didn't win...
|
||||
|
||||
|
|
@ -2997,28 +3001,98 @@ void G_ExitLevel(void)
|
|||
}
|
||||
}
|
||||
|
||||
// See also the enum GameType in doomstat.h
|
||||
const char *Gametype_Names[NUMGAMETYPES] =
|
||||
static gametype_t defaultgametypes[] =
|
||||
{
|
||||
"Race", // GT_RACE
|
||||
"Battle" // GT_BATTLE
|
||||
// GT_RACE
|
||||
{
|
||||
"Race",
|
||||
"GT_RACE",
|
||||
GTR_CIRCUIT|GTR_BOTS|GTR_ENCORE,
|
||||
TOL_RACE,
|
||||
int_time,
|
||||
0,
|
||||
0,
|
||||
},
|
||||
|
||||
// GT_BATTLE
|
||||
{
|
||||
"Battle",
|
||||
"GT_BATTLE",
|
||||
GTR_SPHERES|GTR_BUMPERS|GTR_PAPERITEMS|GTR_POWERSTONES|GTR_KARMA|GTR_ITEMARROWS|GTR_CAPSULES|GTR_BATTLESTARTS|GTR_POINTLIMIT|GTR_TIMELIMIT|GTR_OVERTIME|GTR_CLOSERPLAYERS,
|
||||
TOL_BATTLE,
|
||||
int_scoreortimeattack,
|
||||
0,
|
||||
2,
|
||||
},
|
||||
|
||||
// GT_SPECIAL
|
||||
{
|
||||
"Special",
|
||||
"GT_SPECIAL",
|
||||
GTR_CATCHER|GTR_SPECIALSTART|GTR_ROLLINGSTART|GTR_CIRCUIT,
|
||||
TOL_SPECIAL,
|
||||
int_time,
|
||||
0,
|
||||
0,
|
||||
},
|
||||
|
||||
// GT_VERSUS
|
||||
{
|
||||
"Versus",
|
||||
"GT_VERSUS",
|
||||
GTR_BOSS|GTR_SPHERES|GTR_BUMPERS|GTR_POINTLIMIT|GTR_CLOSERPLAYERS|GTR_NOCUPSELECT|GTR_ENCORE,
|
||||
TOL_BOSS,
|
||||
int_scoreortimeattack,
|
||||
0,
|
||||
0,
|
||||
},
|
||||
};
|
||||
|
||||
// For dehacked
|
||||
const char *Gametype_ConstantNames[NUMGAMETYPES] =
|
||||
gametype_t *gametypes[MAXGAMETYPES+1] =
|
||||
{
|
||||
"GT_RACE", // GT_RACE
|
||||
"GT_BATTLE" // GT_BATTLE
|
||||
&defaultgametypes[GT_RACE],
|
||||
&defaultgametypes[GT_BATTLE],
|
||||
&defaultgametypes[GT_SPECIAL],
|
||||
&defaultgametypes[GT_VERSUS],
|
||||
};
|
||||
|
||||
// Gametype rules
|
||||
UINT32 gametypedefaultrules[NUMGAMETYPES] =
|
||||
//
|
||||
// G_GetGametypeByName
|
||||
//
|
||||
// Returns the number for the given gametype name string, or -1 if not valid.
|
||||
//
|
||||
INT32 G_GetGametypeByName(const char *gametypestr)
|
||||
{
|
||||
// Race
|
||||
GTR_CAMPAIGN|GTR_CIRCUIT|GTR_BOTS,
|
||||
// Battle
|
||||
GTR_SPHERES|GTR_BUMPERS|GTR_PAPERITEMS|GTR_KARMA|GTR_ITEMARROWS|GTR_CAPSULES|GTR_BATTLESTARTS|GTR_POINTLIMIT|GTR_TIMELIMIT|GTR_OVERTIME
|
||||
};
|
||||
INT32 i = 0;
|
||||
|
||||
while (gametypes[i] != NULL)
|
||||
{
|
||||
if (!stricmp(gametypestr, gametypes[i]->name))
|
||||
return i;
|
||||
i++;
|
||||
}
|
||||
|
||||
return -1; // unknown gametype
|
||||
}
|
||||
|
||||
//
|
||||
// G_GuessGametypeByTOL
|
||||
//
|
||||
// Returns the first valid number for the given typeoflevel, or -1 if not valid.
|
||||
//
|
||||
INT32 G_GuessGametypeByTOL(UINT32 tol)
|
||||
{
|
||||
INT32 i = 0;
|
||||
|
||||
while (gametypes[i] != NULL)
|
||||
{
|
||||
if (tol & gametypes[i]->tol)
|
||||
return i;
|
||||
i++;
|
||||
}
|
||||
|
||||
return -1; // unknown gametype
|
||||
}
|
||||
|
||||
//
|
||||
// G_SetGametype
|
||||
|
|
@ -3027,41 +3101,26 @@ UINT32 gametypedefaultrules[NUMGAMETYPES] =
|
|||
//
|
||||
void G_SetGametype(INT16 gtype)
|
||||
{
|
||||
if (gtype < 0 || gtype > numgametypes)
|
||||
{
|
||||
I_Error("G_SetGametype: Bad gametype change %d (was %d/\"%s\")", gtype, gametype, gametypes[gametype]->name);
|
||||
}
|
||||
|
||||
gametype = gtype;
|
||||
gametyperules = gametypedefaultrules[gametype];
|
||||
}
|
||||
|
||||
//
|
||||
// G_AddGametype
|
||||
//
|
||||
// Add a gametype. Returns the new gametype number.
|
||||
//
|
||||
INT16 G_AddGametype(UINT32 rules)
|
||||
{
|
||||
INT16 newgtype = gametypecount;
|
||||
gametypecount++;
|
||||
|
||||
// Set gametype rules.
|
||||
gametypedefaultrules[newgtype] = rules;
|
||||
Gametype_Names[newgtype] = "???";
|
||||
|
||||
// Update gametype_cons_t accordingly.
|
||||
G_UpdateGametypeSelections();
|
||||
|
||||
return newgtype;
|
||||
}
|
||||
|
||||
//
|
||||
// G_AddGametypeConstant
|
||||
// G_PrepareGametypeConstant
|
||||
//
|
||||
// Self-explanatory. Filters out "bad" characters.
|
||||
//
|
||||
void G_AddGametypeConstant(INT16 gtype, const char *newgtconst)
|
||||
char *G_PrepareGametypeConstant(const char *newgtconst)
|
||||
{
|
||||
size_t r = 0; // read
|
||||
size_t w = 0; // write
|
||||
char *gtconst = Z_Calloc(strlen(newgtconst) + 4, PU_STATIC, NULL);
|
||||
char *tmpconst = Z_Calloc(strlen(newgtconst) + 1, PU_STATIC, NULL);
|
||||
size_t len = strlen(newgtconst);
|
||||
char *gtconst = Z_Calloc(len + 4, PU_STATIC, NULL);
|
||||
char *tmpconst = Z_Calloc(len + 1, PU_STATIC, NULL);
|
||||
|
||||
// Copy the gametype name.
|
||||
strcpy(tmpconst, newgtconst);
|
||||
|
|
@ -3121,42 +3180,10 @@ void G_AddGametypeConstant(INT16 gtype, const char *newgtconst)
|
|||
// Free the temporary string.
|
||||
Z_Free(tmpconst);
|
||||
|
||||
// Finally, set the constant string.
|
||||
Gametype_ConstantNames[gtype] = gtconst;
|
||||
// Finally, return the constant string.
|
||||
return gtconst;
|
||||
}
|
||||
|
||||
//
|
||||
// G_UpdateGametypeSelections
|
||||
//
|
||||
// Updates gametype_cons_t.
|
||||
//
|
||||
void G_UpdateGametypeSelections(void)
|
||||
{
|
||||
INT32 i;
|
||||
for (i = 0; i < gametypecount; i++)
|
||||
{
|
||||
gametype_cons_t[i].value = i;
|
||||
gametype_cons_t[i].strvalue = Gametype_Names[i];
|
||||
}
|
||||
gametype_cons_t[NUMGAMETYPES].value = 0;
|
||||
gametype_cons_t[NUMGAMETYPES].strvalue = NULL;
|
||||
}
|
||||
|
||||
// Gametype rankings
|
||||
INT16 gametyperankings[NUMGAMETYPES] =
|
||||
{
|
||||
GT_RACE,
|
||||
GT_BATTLE,
|
||||
};
|
||||
|
||||
// Gametype to TOL (Type Of Level)
|
||||
UINT32 gametypetol[NUMGAMETYPES] =
|
||||
{
|
||||
TOL_RACE, // Race
|
||||
TOL_BATTLE, // Battle
|
||||
TOL_TV, // Midnight Channel effect
|
||||
};
|
||||
|
||||
tolinfo_t TYPEOFLEVEL[NUMTOLNAMES] = {
|
||||
{"RACE",TOL_RACE},
|
||||
{"BATTLE",TOL_BATTLE},
|
||||
|
|
@ -3183,51 +3210,6 @@ void G_AddTOL(UINT32 newtol, const char *tolname)
|
|||
TYPEOFLEVEL[i].flag = newtol;
|
||||
}
|
||||
|
||||
//
|
||||
// G_AddGametypeTOL
|
||||
//
|
||||
// Assigns a type of level to a gametype.
|
||||
//
|
||||
void G_AddGametypeTOL(INT16 gtype, UINT32 newtol)
|
||||
{
|
||||
gametypetol[gtype] = newtol;
|
||||
}
|
||||
|
||||
//
|
||||
// G_GetGametypeByName
|
||||
//
|
||||
// Returns the number for the given gametype name string, or -1 if not valid.
|
||||
//
|
||||
INT32 G_GetGametypeByName(const char *gametypestr)
|
||||
{
|
||||
INT32 i;
|
||||
|
||||
for (i = 0; i < gametypecount; i++)
|
||||
if (!stricmp(gametypestr, Gametype_Names[i]))
|
||||
return i;
|
||||
|
||||
return -1; // unknown gametype
|
||||
}
|
||||
|
||||
//
|
||||
// G_IsSpecialStage
|
||||
//
|
||||
// Returns TRUE if
|
||||
// the given map is a special stage.
|
||||
//
|
||||
boolean G_IsSpecialStage(INT32 mapnum)
|
||||
{
|
||||
mapnum--; // gamemap-based to 0 indexed
|
||||
|
||||
if (mapnum > nummapheaders || !mapheaderinfo[mapnum])
|
||||
return false;
|
||||
|
||||
if (!mapheaderinfo[mapnum]->cup || mapheaderinfo[mapnum]->cup->cachedlevels[CUPCACHE_SPECIAL] != mapnum)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//
|
||||
// G_GametypeUsesLives
|
||||
//
|
||||
|
|
@ -3240,13 +3222,7 @@ boolean G_GametypeUsesLives(void)
|
|||
return false;
|
||||
|
||||
if ((grandprixinfo.gp == true) // In Grand Prix
|
||||
&& (gametype == GT_RACE) // NOT in bonus round
|
||||
&& grandprixinfo.eventmode == GPEVENT_NONE) // NOT in bonus
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (bossinfo.boss == true) // Fighting a boss?
|
||||
&& grandprixinfo.eventmode != GPEVENT_BONUS) // NOT in bonus round
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
|
@ -3291,100 +3267,30 @@ boolean G_GametypeHasSpectators(void)
|
|||
//
|
||||
// G_SometimesGetDifferentGametype
|
||||
//
|
||||
// Oh, yeah, and we sometimes flip encore mode on here too.
|
||||
// Because gametypes are no longer on the vote screen, all this does is sometimes flip encore mode.
|
||||
// However, it remains a seperate function for long-term possibility.
|
||||
//
|
||||
INT16 G_SometimesGetDifferentGametype(UINT8 prefgametype)
|
||||
INT16 G_SometimesGetDifferentGametype(void)
|
||||
{
|
||||
// Most of the gametype references in this condition are intentionally not prefgametype.
|
||||
// This is so a server CAN continue playing a gametype if they like the taste of it.
|
||||
// The encore check needs prefgametype so can't use G_RaceGametype...
|
||||
boolean encorepossible = ((M_SecretUnlocked(SECRET_ENCORE, false) || encorescramble == 1)
|
||||
&& ((gametyperules|gametypedefaultrules[prefgametype]) & GTR_CIRCUIT));
|
||||
&& (gametyperules & GTR_ENCORE));
|
||||
UINT8 encoremodifier = 0;
|
||||
|
||||
// -- the below is only necessary if you want to use randmaps.mapbuffer here
|
||||
//if (randmaps.lastnummapheaders != nummapheaders)
|
||||
//G_ResetRandMapBuffer();
|
||||
|
||||
if (encorepossible)
|
||||
// FORCE to what was scrambled on intermission?
|
||||
if (encorepossible && encorescramble != -1)
|
||||
{
|
||||
if (encorescramble != -1)
|
||||
// FORCE to what was scrambled on intermission
|
||||
if ((encorescramble != 0) != (cv_kartencore.value == 1))
|
||||
{
|
||||
encorepossible = (boolean)encorescramble; // FORCE to what was scrambled on intermission
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (cv_kartvoterulechanges.value)
|
||||
{
|
||||
case 3: // always
|
||||
encorepossible = true;
|
||||
break;
|
||||
case 2: // frequent
|
||||
encorepossible = M_RandomChance(FRACUNIT>>1);
|
||||
break;
|
||||
case 1: // sometimes
|
||||
encorepossible = M_RandomChance(FRACUNIT>>2);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (encorepossible != (cv_kartencore.value == 1))
|
||||
encoremodifier = VOTEMODIFIER_ENCORE;
|
||||
}
|
||||
}
|
||||
|
||||
if (!cv_kartvoterulechanges.value) // never
|
||||
return (gametype|encoremodifier);
|
||||
|
||||
if (randmaps.counttogametype > 0 && (cv_kartvoterulechanges.value != 3))
|
||||
{
|
||||
randmaps.counttogametype--;
|
||||
return (gametype|encoremodifier);
|
||||
}
|
||||
|
||||
switch (cv_kartvoterulechanges.value) // okay, we're having a gametype change! when's the next one, luv?
|
||||
{
|
||||
case 1: // sometimes
|
||||
randmaps.counttogametype = 5; // per "cup"
|
||||
break;
|
||||
default:
|
||||
// fallthrough - happens when clearing buffer, but needs a reasonable countdown if cvar is modified
|
||||
case 2: // frequent
|
||||
randmaps.counttogametype = 2; // ...every 1/2th-ish cup?
|
||||
break;
|
||||
}
|
||||
|
||||
// Only this response is prefgametype-based.
|
||||
// todo custom gametypes
|
||||
if (prefgametype == GT_BATTLE)
|
||||
{
|
||||
// Intentionally does not use encoremodifier!
|
||||
if (cv_kartencore.value == 1)
|
||||
return (GT_RACE|VOTEMODIFIER_ENCORE);
|
||||
return (GT_RACE);
|
||||
}
|
||||
// This might appear wrong HERE, but the game will display the Encore possibility on the second voting choice instead.
|
||||
return (GT_BATTLE|encoremodifier);
|
||||
}
|
||||
|
||||
//
|
||||
// G_GetGametypeColor
|
||||
//
|
||||
// Pretty and consistent ^u^
|
||||
// See also M_GetGametypeColor (if that still exists).
|
||||
//
|
||||
UINT8 G_GetGametypeColor(INT16 gt)
|
||||
{
|
||||
if (modeattacking) // == ATTACKING_RECORD
|
||||
return orangemap[0];
|
||||
|
||||
if (gt == GT_BATTLE)
|
||||
return redmap[0];
|
||||
|
||||
if (gt == GT_RACE)
|
||||
return skymap[0];
|
||||
|
||||
return 255; // FALLBACK
|
||||
return (gametype|encoremodifier);
|
||||
}
|
||||
|
||||
/** Get the typeoflevel flag needed to indicate support of a gametype.
|
||||
|
|
@ -3394,7 +3300,9 @@ UINT8 G_GetGametypeColor(INT16 gt)
|
|||
*/
|
||||
UINT32 G_TOLFlag(INT32 pgametype)
|
||||
{
|
||||
return gametypetol[pgametype];
|
||||
if (pgametype >= 0 && pgametype < numgametypes)
|
||||
return gametypes[pgametype]->tol;
|
||||
return 0;
|
||||
}
|
||||
|
||||
INT16 G_GetFirstMapOfGametype(UINT8 pgametype)
|
||||
|
|
@ -3405,7 +3313,7 @@ INT16 G_GetFirstMapOfGametype(UINT8 pgametype)
|
|||
|
||||
templevelsearch.cup = NULL;
|
||||
templevelsearch.typeoflevel = G_TOLFlag(pgametype);
|
||||
templevelsearch.cupmode = (!(gametypedefaultrules[pgametype] & GTR_NOCUPSELECT));
|
||||
templevelsearch.cupmode = (!(gametypes[pgametype]->rules & GTR_NOCUPSELECT));
|
||||
templevelsearch.timeattack = false;
|
||||
templevelsearch.checklocked = true;
|
||||
|
||||
|
|
@ -3497,7 +3405,7 @@ tryagain:
|
|||
if (!mapheaderinfo[ix] || mapheaderinfo[ix]->lumpnum == LUMPERROR)
|
||||
continue;
|
||||
|
||||
if ((mapheaderinfo[ix]->typeoflevel & tolflags) != tolflags
|
||||
if (!(mapheaderinfo[ix]->typeoflevel & tolflags)
|
||||
|| ix == pprevmap
|
||||
|| M_MapLocked(ix+1)
|
||||
|| (usehellmaps != (mapheaderinfo[ix]->menuflags & LF2_HIDEINMENU))) // this is bad
|
||||
|
|
@ -3716,7 +3624,6 @@ static void G_HandleSaveLevel(void)
|
|||
|
||||
static void G_GetNextMap(void)
|
||||
{
|
||||
boolean spec = G_IsSpecialStage(prevmap+1);
|
||||
INT32 i;
|
||||
|
||||
// go to next level
|
||||
|
|
@ -3733,7 +3640,7 @@ static void G_GetNextMap(void)
|
|||
}
|
||||
else
|
||||
{
|
||||
INT32 lastgametype = gametype;
|
||||
INT32 lastgametype = gametype, newgametype = GT_RACE;
|
||||
// 5 levels, 2 bonus stages: after rounds 2 and 4 (but flexible enough to accomodate other solutions)
|
||||
UINT8 bonusmodulo = (grandprixinfo.cup->numlevels+1)/(grandprixinfo.cup->numbonus+1);
|
||||
UINT8 bonusindex = (grandprixinfo.roundnum / bonusmodulo) - 1;
|
||||
|
|
@ -3750,9 +3657,6 @@ static void G_GetNextMap(void)
|
|||
G_SetGametype(GT_RACE);
|
||||
if (gametype != lastgametype)
|
||||
D_GameTypeChanged(lastgametype);
|
||||
|
||||
specialStage.active = false;
|
||||
bossinfo.boss = false;
|
||||
}
|
||||
// Special stage
|
||||
else if (grandprixinfo.roundnum >= grandprixinfo.cup->numlevels)
|
||||
|
|
@ -3773,11 +3677,11 @@ static void G_GetNextMap(void)
|
|||
if (totaltotalring >= 50)
|
||||
{
|
||||
const INT32 cupLevelNum = grandprixinfo.cup->cachedlevels[CUPCACHE_SPECIAL];
|
||||
if (cupLevelNum < nummapheaders && mapheaderinfo[cupLevelNum]
|
||||
&& mapheaderinfo[cupLevelNum]->typeoflevel & (TOL_SPECIAL|TOL_BOSS|TOL_BATTLE))
|
||||
if (cupLevelNum < nummapheaders && mapheaderinfo[cupLevelNum])
|
||||
{
|
||||
grandprixinfo.eventmode = GPEVENT_SPECIAL;
|
||||
nextmap = cupLevelNum;
|
||||
newgametype = G_GuessGametypeByTOL(mapheaderinfo[cupLevelNum]->typeoflevel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3788,37 +3692,27 @@ static void G_GetNextMap(void)
|
|||
// todo any other condition?
|
||||
{
|
||||
const INT32 cupLevelNum = grandprixinfo.cup->cachedlevels[CUPCACHE_BONUS + bonusindex];
|
||||
if (cupLevelNum < nummapheaders && mapheaderinfo[cupLevelNum]
|
||||
&& mapheaderinfo[cupLevelNum]->typeoflevel & (TOL_BOSS|TOL_BATTLE))
|
||||
if (cupLevelNum < nummapheaders && mapheaderinfo[cupLevelNum])
|
||||
{
|
||||
grandprixinfo.eventmode = GPEVENT_BONUS;
|
||||
nextmap = cupLevelNum;
|
||||
newgametype = G_GuessGametypeByTOL(mapheaderinfo[cupLevelNum]->typeoflevel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (newgametype == -1)
|
||||
{
|
||||
// Don't permit invalid changes.
|
||||
grandprixinfo.eventmode = GPEVENT_NONE;
|
||||
newgametype = gametype;
|
||||
}
|
||||
|
||||
if (grandprixinfo.eventmode != GPEVENT_NONE)
|
||||
{
|
||||
// nextmap is set above
|
||||
const INT32 newtol = mapheaderinfo[nextmap]->typeoflevel;
|
||||
|
||||
if (newtol & TOL_SPECIAL)
|
||||
{
|
||||
specialStage.active = true;
|
||||
specialStage.encore = grandprixinfo.encore;
|
||||
}
|
||||
else //(if newtol & (TOL_BATTLE|TOL_BOSS)) -- safe to assume??
|
||||
{
|
||||
G_SetGametype(GT_BATTLE);
|
||||
if (gametype != lastgametype)
|
||||
D_GameTypeChanged(lastgametype);
|
||||
if (newtol & TOL_BOSS)
|
||||
{
|
||||
K_ResetBossInfo();
|
||||
bossinfo.boss = true;
|
||||
bossinfo.encore = grandprixinfo.encore;
|
||||
}
|
||||
}
|
||||
G_SetGametype(newgametype);
|
||||
if (gametype != lastgametype)
|
||||
D_GameTypeChanged(lastgametype);
|
||||
}
|
||||
else if (grandprixinfo.roundnum >= grandprixinfo.cup->numlevels) // On final map
|
||||
{
|
||||
|
|
@ -3842,10 +3736,6 @@ static void G_GetNextMap(void)
|
|||
}
|
||||
}
|
||||
}
|
||||
else if (bossinfo.boss == true)
|
||||
{
|
||||
nextmap = NEXTMAP_TITLE; // temporary
|
||||
}
|
||||
else
|
||||
{
|
||||
UINT32 tolflag = G_TOLFlag(gametype);
|
||||
|
|
@ -3984,7 +3874,9 @@ static void G_GetNextMap(void)
|
|||
if (nextmap == NEXTMAP_INVALID || (nextmap < NEXTMAP_SPECIAL && (nextmap >= nummapheaders || !mapheaderinfo[nextmap] || mapheaderinfo[nextmap]->lumpnum == LUMPERROR)))
|
||||
I_Error("G_GetNextMap: Internal map ID %d not found (nummapheaders = %d)\n", nextmap, nummapheaders);
|
||||
|
||||
#if 0 // This is a surprise tool that will help us later.
|
||||
if (!spec)
|
||||
#endif //#if 0
|
||||
lastmap = nextmap;
|
||||
}
|
||||
|
||||
|
|
@ -4108,7 +4000,7 @@ void G_AfterIntermission(void)
|
|||
G_HandleSaveLevel();
|
||||
}
|
||||
|
||||
if ((gametyperules & GTR_CAMPAIGN) && mapheaderinfo[prevmap]->cutscenenum && !modeattacking && skipstats <= 1 && (gamecomplete || !(marathonmode & MA_NOCUTSCENES))) // Start a custom cutscene.
|
||||
if ((grandprixinfo.gp == true) && mapheaderinfo[prevmap]->cutscenenum && !modeattacking && skipstats <= 1 && (gamecomplete || !(marathonmode & MA_NOCUTSCENES))) // Start a custom cutscene.
|
||||
F_StartCustomCutscene(mapheaderinfo[prevmap]->cutscenenum-1, false, false);
|
||||
else
|
||||
{
|
||||
|
|
@ -4245,7 +4137,7 @@ void G_EndGame(void)
|
|||
}
|
||||
|
||||
// Only do evaluation and credits in singleplayer contexts
|
||||
if (!netgame && (gametyperules & GTR_CAMPAIGN))
|
||||
if (!netgame && grandprixinfo.gp == true)
|
||||
{
|
||||
if (nextmap == NEXTMAP_CEREMONY) // end game with ceremony
|
||||
{
|
||||
|
|
@ -4883,7 +4775,6 @@ cleanup:
|
|||
void G_DeferedInitNew(boolean pencoremode, INT32 map, INT32 pickedchar, UINT8 ssplayers, boolean FLS)
|
||||
{
|
||||
UINT16 color = SKINCOLOR_NONE;
|
||||
INT32 dogametype;
|
||||
|
||||
paused = false;
|
||||
|
||||
|
|
@ -4894,17 +4785,8 @@ void G_DeferedInitNew(boolean pencoremode, INT32 map, INT32 pickedchar, UINT8 ss
|
|||
|
||||
G_ResetRandMapBuffer();
|
||||
|
||||
if ((modeattacking == ATTACKING_CAPSULES) || (bossinfo.boss == true))
|
||||
{
|
||||
dogametype = GT_BATTLE;
|
||||
}
|
||||
else
|
||||
{
|
||||
dogametype = GT_RACE;
|
||||
}
|
||||
|
||||
// this leave the actual game if needed
|
||||
SV_StartSinglePlayerServer(dogametype, false);
|
||||
SV_StartSinglePlayerServer(gametype, false);
|
||||
|
||||
if (splitscreen != ssplayers)
|
||||
{
|
||||
|
|
@ -5004,7 +4886,7 @@ void G_InitNew(UINT8 pencoremode, INT32 map, boolean resetplayer, boolean skippr
|
|||
automapactive = false;
|
||||
imcontinuing = false;
|
||||
|
||||
if ((gametyperules & GTR_CAMPAIGN) && !skipprecutscene && mapheaderinfo[gamemap-1]->precutscenenum && !modeattacking && !(marathonmode & MA_NOCUTSCENES)) // Start a custom cutscene.
|
||||
if ((grandprixinfo.gp == true) && !skipprecutscene && mapheaderinfo[gamemap-1]->precutscenenum && !modeattacking && !(marathonmode & MA_NOCUTSCENES)) // Start a custom cutscene.
|
||||
F_StartCustomCutscene(mapheaderinfo[gamemap-1]->precutscenenum-1, true, resetplayer);
|
||||
else
|
||||
{
|
||||
|
|
|
|||
15
src/g_game.h
15
src/g_game.h
|
|
@ -183,24 +183,17 @@ void G_SaveGame(UINT32 slot, INT16 mapnum);
|
|||
|
||||
void G_SaveGameOver(UINT32 slot, boolean modifylives);
|
||||
|
||||
extern UINT32 gametypedefaultrules[NUMGAMETYPES];
|
||||
extern UINT32 gametypetol[NUMGAMETYPES];
|
||||
extern INT16 gametyperankings[NUMGAMETYPES];
|
||||
|
||||
void G_SetGametype(INT16 gametype);
|
||||
INT16 G_AddGametype(UINT32 rules);
|
||||
void G_AddGametypeConstant(INT16 gtype, const char *newgtconst);
|
||||
void G_UpdateGametypeSelections(void);
|
||||
char *G_PrepareGametypeConstant(const char *newgtconst);
|
||||
void G_AddTOL(UINT32 newtol, const char *tolname);
|
||||
void G_AddGametypeTOL(INT16 gtype, UINT32 newtol);
|
||||
INT32 G_GetGametypeByName(const char *gametypestr);
|
||||
boolean G_IsSpecialStage(INT32 mapnum);
|
||||
INT32 G_GuessGametypeByTOL(UINT32 tol);
|
||||
|
||||
boolean G_GametypeUsesLives(void);
|
||||
boolean G_GametypeHasTeams(void);
|
||||
boolean G_GametypeHasSpectators(void);
|
||||
#define VOTEMODIFIER_ENCORE 0x80
|
||||
INT16 G_SometimesGetDifferentGametype(UINT8 prefgametype);
|
||||
UINT8 G_GetGametypeColor(INT16 gt);
|
||||
INT16 G_SometimesGetDifferentGametype(void);
|
||||
void G_ExitLevel(void);
|
||||
void G_NextLevel(void);
|
||||
void G_Continue(void);
|
||||
|
|
|
|||
132
src/hu_stuff.c
132
src/hu_stuff.c
|
|
@ -16,7 +16,7 @@
|
|||
#include "hu_stuff.h"
|
||||
#include "font.h"
|
||||
|
||||
#include "k_menu.h" // gametype_cons_t
|
||||
#include "k_menu.h" // highlightflags
|
||||
#include "m_cond.h" // emblems
|
||||
#include "m_misc.h" // word jumping
|
||||
|
||||
|
|
@ -55,7 +55,8 @@
|
|||
// SRB2Kart
|
||||
#include "s_sound.h" // song credits
|
||||
#include "k_kart.h"
|
||||
#include "k_boss.h"
|
||||
#include "k_battle.h"
|
||||
#include "k_grandprix.h"
|
||||
#include "k_color.h"
|
||||
#include "k_hud.h"
|
||||
#include "r_fps.h"
|
||||
|
|
@ -2392,60 +2393,110 @@ static inline void HU_DrawSpectatorTicker(void)
|
|||
static void HU_DrawRankings(void)
|
||||
{
|
||||
playersort_t tab[MAXPLAYERS];
|
||||
INT32 i, j, scorelines, hilicol, numplayersingame = 0;
|
||||
INT32 i, j, scorelines, numplayersingame = 0, hilicol = highlightflags;
|
||||
boolean completed[MAXPLAYERS];
|
||||
UINT32 whiteplayer = MAXPLAYERS;
|
||||
boolean timedone = false, pointsdone = false;
|
||||
|
||||
V_DrawFadeScreen(0xFF00, 16); // A little more readable, and prevents cheating the fades under other circumstances.
|
||||
|
||||
if (modeattacking)
|
||||
hilicol = V_ORANGEMAP;
|
||||
else
|
||||
hilicol = ((gametype == GT_RACE) ? V_SKYMAP : V_REDMAP);
|
||||
|
||||
// draw the current gametype in the lower right
|
||||
if (modeattacking)
|
||||
V_DrawString(4, 188, hilicol|V_SNAPTOBOTTOM|V_SNAPTOLEFT, "Record Attack");
|
||||
else
|
||||
V_DrawString(4, 188, hilicol|V_SNAPTOBOTTOM|V_SNAPTOLEFT, Gametype_Names[gametype]);
|
||||
if (grandprixinfo.gp == true)
|
||||
V_DrawString(4, 188, hilicol|V_SNAPTOBOTTOM|V_SNAPTOLEFT, "Grand Prix");
|
||||
else if (battlecapsules)
|
||||
V_DrawString(4, 188, hilicol|V_SNAPTOBOTTOM|V_SNAPTOLEFT, "Capsules");
|
||||
else if (gametype >= 0 && gametype < numgametypes)
|
||||
V_DrawString(4, 188, hilicol|V_SNAPTOBOTTOM|V_SNAPTOLEFT, gametypes[gametype]->name);
|
||||
|
||||
if ((gametyperules & (GTR_TIMELIMIT|GTR_POINTLIMIT)) && !bossinfo.boss)
|
||||
// Left hand side
|
||||
if (grandprixinfo.gp == true)
|
||||
{
|
||||
if ((gametyperules & GTR_TIMELIMIT) && timelimitintics > 0)
|
||||
const char *roundstr = NULL;
|
||||
V_DrawCenteredString(64, 8, 0, "ROUND");
|
||||
switch (grandprixinfo.eventmode)
|
||||
{
|
||||
UINT32 timeval = (timelimitintics + starttime + 1 - leveltime);
|
||||
if (timeval > timelimitintics+1)
|
||||
timeval = timelimitintics+1;
|
||||
timeval /= TICRATE;
|
||||
case GPEVENT_BONUS:
|
||||
roundstr = "BONUS";
|
||||
break;
|
||||
case GPEVENT_SPECIAL:
|
||||
roundstr = "SPECIAL";
|
||||
break;
|
||||
default:
|
||||
roundstr = va("%d", grandprixinfo.roundnum);
|
||||
break;
|
||||
}
|
||||
V_DrawCenteredString(64, 16, hilicol, roundstr);
|
||||
}
|
||||
else if ((gametyperules & GTR_TIMELIMIT) && timelimitintics > 0)
|
||||
{
|
||||
UINT32 timeval = (timelimitintics + starttime + 1 - leveltime);
|
||||
if (timeval > timelimitintics+1)
|
||||
timeval = timelimitintics+1;
|
||||
timeval /= TICRATE;
|
||||
|
||||
if (leveltime <= (timelimitintics + starttime))
|
||||
{
|
||||
V_DrawCenteredString(64, 8, 0, "TIME LEFT");
|
||||
V_DrawCenteredString(64, 16, hilicol, va("%u", timeval));
|
||||
}
|
||||
|
||||
// overtime
|
||||
if (!players[consoleplayer].exiting && (leveltime > (timelimitintics + starttime + TICRATE/2)) && cv_overtime.value)
|
||||
{
|
||||
V_DrawCenteredString(64, 8, 0, "TIME LEFT");
|
||||
V_DrawCenteredString(64, 16, hilicol, "OVERTIME");
|
||||
}
|
||||
if (leveltime <= (timelimitintics + starttime))
|
||||
{
|
||||
V_DrawCenteredString(64, 8, 0, "TIME LEFT");
|
||||
V_DrawCenteredString(64, 16, hilicol, va("%u", timeval));
|
||||
}
|
||||
|
||||
if ((gametyperules & GTR_POINTLIMIT) && cv_pointlimit.value > 0)
|
||||
// overtime
|
||||
if (!players[consoleplayer].exiting && (leveltime > (timelimitintics + starttime + TICRATE/2)) && cv_overtime.value)
|
||||
{
|
||||
V_DrawCenteredString(256, 8, 0, "POINT LIMIT");
|
||||
V_DrawCenteredString(256, 16, hilicol, va("%d", cv_pointlimit.value));
|
||||
V_DrawCenteredString(64, 8, 0, "TIME LEFT");
|
||||
V_DrawCenteredString(64, 16, hilicol, "OVERTIME");
|
||||
}
|
||||
|
||||
timedone = true;
|
||||
}
|
||||
else if ((gametyperules & GTR_POINTLIMIT) && cv_pointlimit.value > 0)
|
||||
{
|
||||
V_DrawCenteredString(64, 8, 0, "POINT LIMIT");
|
||||
V_DrawCenteredString(64, 16, hilicol, va("%d", cv_pointlimit.value));
|
||||
pointsdone = true;
|
||||
}
|
||||
else if (gametyperules & GTR_CIRCUIT)
|
||||
{
|
||||
V_DrawCenteredString(64, 8, 0, "LAPS");
|
||||
V_DrawCenteredString(64, 16, hilicol, va("%d", numlaps));
|
||||
}
|
||||
|
||||
// Right hand side
|
||||
if (battlecapsules == true)
|
||||
{
|
||||
if (numtargets < maptargets)
|
||||
{
|
||||
V_DrawCenteredString(256, 8, 0, "CAPSULES");
|
||||
V_DrawCenteredString(256, 16, hilicol, va("%d", maptargets - numtargets));
|
||||
}
|
||||
}
|
||||
else
|
||||
else if (!timedone && (gametyperules & GTR_TIMELIMIT) && timelimitintics > 0)
|
||||
{
|
||||
if (circuitmap)
|
||||
UINT32 timeval = (timelimitintics + starttime + 1 - leveltime);
|
||||
if (timeval > timelimitintics+1)
|
||||
timeval = timelimitintics+1;
|
||||
timeval /= TICRATE;
|
||||
|
||||
if (leveltime <= (timelimitintics + starttime))
|
||||
{
|
||||
V_DrawCenteredString(64, 8, 0, "LAP COUNT");
|
||||
V_DrawCenteredString(64, 16, hilicol, va("%d", numlaps));
|
||||
V_DrawCenteredString(256, 8, 0, "TIME LEFT");
|
||||
V_DrawCenteredString(256, 16, hilicol, va("%u", timeval));
|
||||
}
|
||||
|
||||
// overtime
|
||||
if (!players[consoleplayer].exiting && (leveltime > (timelimitintics + starttime + TICRATE/2)) && cv_overtime.value)
|
||||
{
|
||||
V_DrawCenteredString(256, 8, 0, "TIME LEFT");
|
||||
V_DrawCenteredString(256, 16, hilicol, "OVERTIME");
|
||||
}
|
||||
}
|
||||
else if (!pointsdone && (gametyperules & GTR_POINTLIMIT) && cv_pointlimit.value > 0)
|
||||
{
|
||||
V_DrawCenteredString(256, 8, 0, "POINT LIMIT");
|
||||
V_DrawCenteredString(256, 16, hilicol, va("%d", cv_pointlimit.value));
|
||||
}
|
||||
else if (gametyperules & GTR_CIRCUIT)
|
||||
{
|
||||
V_DrawCenteredString(256, 8, 0, "GAME SPEED");
|
||||
V_DrawCenteredString(256, 16, hilicol, kartspeed_cons_t[1+gamespeed].strvalue);
|
||||
}
|
||||
|
|
@ -2494,13 +2545,12 @@ static void HU_DrawRankings(void)
|
|||
|
||||
if ((gametyperules & GTR_CIRCUIT))
|
||||
{
|
||||
if (circuitmap)
|
||||
tab[scorelines].count = players[i].laps;
|
||||
else
|
||||
tab[scorelines].count = players[i].realtime;
|
||||
tab[scorelines].count = players[i].laps;
|
||||
}
|
||||
else
|
||||
{
|
||||
tab[scorelines].count = players[i].roundscore;
|
||||
}
|
||||
|
||||
scorelines++;
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@
|
|||
/// \brief SRB2Kart Battle Mode specific code
|
||||
|
||||
#include "k_battle.h"
|
||||
#include "k_boss.h"
|
||||
#include "k_kart.h"
|
||||
#include "doomtype.h"
|
||||
#include "doomdata.h"
|
||||
|
|
@ -146,7 +145,7 @@ void K_CheckBumpers(void)
|
|||
}
|
||||
else if (numingame <= 1)
|
||||
{
|
||||
if (!battlecapsules)
|
||||
if ((gametyperules & GTR_CAPSULES) && !battlecapsules)
|
||||
{
|
||||
// Reset map to turn on battle capsules
|
||||
if (server)
|
||||
|
|
@ -196,6 +195,11 @@ void K_CheckEmeralds(player_t *player)
|
|||
{
|
||||
UINT8 i;
|
||||
|
||||
if (!(gametyperules & GTR_POWERSTONES))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ALLCHAOSEMERALDS(player->emeralds))
|
||||
{
|
||||
return;
|
||||
|
|
@ -221,6 +225,29 @@ void K_CheckEmeralds(player_t *player)
|
|||
K_CheckBumpers();
|
||||
}
|
||||
|
||||
UINT16 K_GetChaosEmeraldColor(UINT32 emeraldType)
|
||||
{
|
||||
switch (emeraldType)
|
||||
{
|
||||
case EMERALD_CHAOS1:
|
||||
return SKINCOLOR_CHAOSEMERALD1;
|
||||
case EMERALD_CHAOS2:
|
||||
return SKINCOLOR_CHAOSEMERALD2;
|
||||
case EMERALD_CHAOS3:
|
||||
return SKINCOLOR_CHAOSEMERALD3;
|
||||
case EMERALD_CHAOS4:
|
||||
return SKINCOLOR_CHAOSEMERALD4;
|
||||
case EMERALD_CHAOS5:
|
||||
return SKINCOLOR_CHAOSEMERALD5;
|
||||
case EMERALD_CHAOS6:
|
||||
return SKINCOLOR_CHAOSEMERALD6;
|
||||
case EMERALD_CHAOS7:
|
||||
return SKINCOLOR_CHAOSEMERALD7;
|
||||
default:
|
||||
return SKINCOLOR_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
mobj_t *K_SpawnChaosEmerald(fixed_t x, fixed_t y, fixed_t z, angle_t angle, SINT8 flip, UINT32 emeraldType)
|
||||
{
|
||||
boolean validEmerald = true;
|
||||
|
|
@ -240,25 +267,13 @@ mobj_t *K_SpawnChaosEmerald(fixed_t x, fixed_t y, fixed_t z, angle_t angle, SINT
|
|||
switch (emeraldType)
|
||||
{
|
||||
case EMERALD_CHAOS1:
|
||||
emerald->color = SKINCOLOR_CHAOSEMERALD1;
|
||||
break;
|
||||
case EMERALD_CHAOS2:
|
||||
emerald->color = SKINCOLOR_CHAOSEMERALD2;
|
||||
break;
|
||||
case EMERALD_CHAOS3:
|
||||
emerald->color = SKINCOLOR_CHAOSEMERALD3;
|
||||
break;
|
||||
case EMERALD_CHAOS4:
|
||||
emerald->color = SKINCOLOR_CHAOSEMERALD4;
|
||||
break;
|
||||
case EMERALD_CHAOS5:
|
||||
emerald->color = SKINCOLOR_CHAOSEMERALD5;
|
||||
break;
|
||||
case EMERALD_CHAOS6:
|
||||
emerald->color = SKINCOLOR_CHAOSEMERALD6;
|
||||
break;
|
||||
case EMERALD_CHAOS7:
|
||||
emerald->color = SKINCOLOR_CHAOSEMERALD7;
|
||||
emerald->color = K_GetChaosEmeraldColor(emeraldType);
|
||||
break;
|
||||
default:
|
||||
CONS_Printf("Invalid emerald type %d\n", emeraldType);
|
||||
|
|
@ -336,12 +351,17 @@ UINT8 K_NumEmeralds(player_t *player)
|
|||
return num;
|
||||
}
|
||||
|
||||
static inline boolean IsOnInterval(tic_t interval)
|
||||
{
|
||||
return ((leveltime - starttime) % interval) == 0;
|
||||
}
|
||||
|
||||
void K_RunPaperItemSpawners(void)
|
||||
{
|
||||
const boolean overtime = (battleovertime.enabled >= 10*TICRATE);
|
||||
tic_t interval = 8*TICRATE;
|
||||
const tic_t interval = BATTLE_SPAWN_INTERVAL;
|
||||
|
||||
const boolean canmakeemeralds = true; //(!(battlecapsules || bossinfo.boss));
|
||||
const boolean canmakeemeralds = (gametyperules & GTR_POWERSTONES);
|
||||
|
||||
UINT32 emeraldsSpawned = 0;
|
||||
UINT32 firstUnspawnedEmerald = 0;
|
||||
|
|
@ -352,7 +372,7 @@ void K_RunPaperItemSpawners(void)
|
|||
UINT8 pcount = 0;
|
||||
INT16 i;
|
||||
|
||||
if (battlecapsules || bossinfo.boss)
|
||||
if (battlecapsules)
|
||||
{
|
||||
// Gametype uses paper items, but this specific expression doesn't
|
||||
return;
|
||||
|
|
@ -364,13 +384,7 @@ void K_RunPaperItemSpawners(void)
|
|||
return;
|
||||
}
|
||||
|
||||
if (overtime == true)
|
||||
{
|
||||
// Double frequency of items
|
||||
interval /= 2;
|
||||
}
|
||||
|
||||
if (((leveltime - starttime) % interval) != 0)
|
||||
if (!IsOnInterval(interval))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
|
@ -546,7 +560,7 @@ void K_RunPaperItemSpawners(void)
|
|||
}
|
||||
else
|
||||
{
|
||||
if (gametyperules & GTR_SPHERES)
|
||||
if ((gametyperules & GTR_SPHERES) && IsOnInterval(2 * interval))
|
||||
{
|
||||
drop = K_SpawnSphereBox(
|
||||
spotList[r]->x, spotList[r]->y, spotList[r]->z + (128 * mapobjectscale * flip),
|
||||
|
|
@ -789,7 +803,7 @@ void K_BattleInit(boolean singleplayercontext)
|
|||
{
|
||||
size_t i;
|
||||
|
||||
if ((gametyperules & GTR_CAPSULES) && singleplayercontext && !battlecapsules && !bossinfo.boss)
|
||||
if ((gametyperules & GTR_CAPSULES) && singleplayercontext && !battlecapsules)
|
||||
{
|
||||
mapthing_t *mt = mapthings;
|
||||
for (i = 0; i < nummapthings; i++, mt++)
|
||||
|
|
|
|||
|
|
@ -8,6 +8,9 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define BATTLE_SPAWN_INTERVAL (4*TICRATE)
|
||||
#define BATTLE_DESPAWN_TIME (15*TICRATE)
|
||||
|
||||
extern struct battleovertime
|
||||
{
|
||||
UINT16 enabled; ///< Has this been initalized yet?
|
||||
|
|
@ -25,6 +28,7 @@ boolean K_IsPlayerWanted(player_t *player);
|
|||
void K_SpawnBattlePoints(player_t *source, player_t *victim, UINT8 amount);
|
||||
void K_CheckBumpers(void);
|
||||
void K_CheckEmeralds(player_t *player);
|
||||
UINT16 K_GetChaosEmeraldColor(UINT32 emeraldType);
|
||||
mobj_t *K_SpawnChaosEmerald(fixed_t x, fixed_t y, fixed_t z, angle_t angle, SINT8 flip, UINT32 emeraldType);
|
||||
mobj_t *K_SpawnSphereBox(fixed_t x, fixed_t y, fixed_t z, angle_t angle, SINT8 flip, UINT8 amount);
|
||||
void K_DropEmeraldsFromPlayer(player_t *player, UINT32 emeraldType);
|
||||
|
|
|
|||
39
src/k_boss.c
39
src/k_boss.c
|
|
@ -23,7 +23,7 @@
|
|||
struct bossinfo bossinfo;
|
||||
|
||||
/*--------------------------------------------------
|
||||
void K_ClearBossInfo(void)
|
||||
void K_ResetBossInfo(void)
|
||||
|
||||
See header file for description.
|
||||
--------------------------------------------------*/
|
||||
|
|
@ -32,6 +32,8 @@ void K_ResetBossInfo(void)
|
|||
Z_Free(bossinfo.enemyname);
|
||||
Z_Free(bossinfo.subtitle);
|
||||
memset(&bossinfo, 0, sizeof(struct bossinfo));
|
||||
bossinfo.barlen = BOSSHEALTHBARLEN;
|
||||
bossinfo.titlesound = sfx_typri1;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
|
|
@ -43,7 +45,7 @@ void K_BossInfoTicker(void)
|
|||
{
|
||||
UINT8 i;
|
||||
|
||||
if (bossinfo.boss == false)
|
||||
if (bossinfo.valid == false)
|
||||
return;
|
||||
|
||||
// Update healthbar data. (only if the hud is visible)
|
||||
|
|
@ -55,7 +57,7 @@ void K_BossInfoTicker(void)
|
|||
bossinfo.visualbar--;
|
||||
// If the boss is dying, start shrinking the healthbar.
|
||||
if (bossinfo.visualbar == 0)
|
||||
bossinfo.barlen-= 2;
|
||||
bossinfo.barlen -= 2;
|
||||
}
|
||||
// Less than the actual health?
|
||||
else if (bossinfo.visualbar < bossinfo.healthbar)
|
||||
|
|
@ -108,6 +110,18 @@ void K_BossInfoTicker(void)
|
|||
|
||||
void K_InitBossHealthBar(const char *enemyname, const char *subtitle, sfxenum_t titlesound, fixed_t pinchmagnitude, UINT8 divisions)
|
||||
{
|
||||
if (!(gametyperules & GTR_BOSS))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
bossinfo.valid = true;
|
||||
|
||||
if (!leveltime)
|
||||
{
|
||||
bossinfo.coolintro = true;
|
||||
}
|
||||
|
||||
if (enemyname && enemyname[0])
|
||||
{
|
||||
Z_Free(bossinfo.enemyname);
|
||||
|
|
@ -158,6 +172,9 @@ void K_InitBossHealthBar(const char *enemyname, const char *subtitle, sfxenum_t
|
|||
|
||||
void K_UpdateBossHealthBar(fixed_t magnitude, tic_t jitterlen)
|
||||
{
|
||||
if (bossinfo.valid == false)
|
||||
return;
|
||||
|
||||
if (magnitude > FRACUNIT)
|
||||
magnitude = FRACUNIT;
|
||||
else if (magnitude < 0)
|
||||
|
|
@ -177,6 +194,9 @@ void K_DeclareWeakspot(mobj_t *spot, spottype_t spottype, UINT16 color, boolean
|
|||
{
|
||||
UINT8 i;
|
||||
|
||||
if (bossinfo.valid == false)
|
||||
return;
|
||||
|
||||
// First check whether the spot is already in the list and simply redeclaring weakness (for example, a vulnerable moment in the pattern).
|
||||
for (i = 0; i < NUMWEAKSPOTS; i++)
|
||||
if (bossinfo.weakspots[i].spot == spot)
|
||||
|
|
@ -206,3 +226,16 @@ void K_DeclareWeakspot(mobj_t *spot, spottype_t spottype, UINT16 color, boolean
|
|||
bossinfo.doweakspotsound = spottype;
|
||||
}
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
boolean K_CheckBossIntro(void);
|
||||
|
||||
See header file for description.
|
||||
--------------------------------------------------*/
|
||||
|
||||
boolean K_CheckBossIntro(void)
|
||||
{
|
||||
if (bossinfo.valid == false)
|
||||
return false;
|
||||
return bossinfo.coolintro;
|
||||
}
|
||||
|
|
|
|||
17
src/k_boss.h
17
src/k_boss.h
|
|
@ -43,7 +43,8 @@ struct weakspot_t
|
|||
|
||||
extern struct bossinfo
|
||||
{
|
||||
boolean boss; ///< If true, then we are fighting a boss
|
||||
boolean valid; ///< If true, then data in this struct is valid
|
||||
|
||||
UINT8 healthbar; ///< Actual health bar fill amount
|
||||
UINT8 visualbar; ///< Tracks above, but with delay
|
||||
fixed_t visualdiv; ///< How far apart health bar divisions should appear
|
||||
|
|
@ -52,7 +53,7 @@ extern struct bossinfo
|
|||
UINT8 barlen; ///< The length of the bar (only reduced when a boss is deceased)
|
||||
char *enemyname; ///< The name next to the bar
|
||||
weakspot_t weakspots[NUMWEAKSPOTS]; ///< Array of weak spots (for minimap/object tracking)
|
||||
boolean encore; ///< Copy of encore, just to make sure you can't cheat it with cvars
|
||||
boolean coolintro; ///< Determines whether the map start(s/ed) with a boss-specific intro.
|
||||
spottype_t doweakspotsound; ///< If nonzero, at least one weakspot was declared this tic
|
||||
tic_t titleshow; ///< Show this many letters on the titlecard
|
||||
sfxenum_t titlesound; ///< Sound to play when title typing
|
||||
|
|
@ -116,6 +117,18 @@ void K_UpdateBossHealthBar(fixed_t magnitude, tic_t jitterlen);
|
|||
|
||||
void K_DeclareWeakspot(mobj_t *spot, spottype_t spottype, UINT16 color, boolean minimap);
|
||||
|
||||
/*--------------------------------------------------
|
||||
boolean K_CheckBossIntro(void);
|
||||
|
||||
Checks whether the Versus-specific intro is playing for this map start.
|
||||
|
||||
Return:-
|
||||
true if cool intro in action,
|
||||
otherwise false.
|
||||
--------------------------------------------------*/
|
||||
|
||||
boolean K_CheckBossIntro(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -27,7 +27,6 @@
|
|||
#include "m_random.h"
|
||||
#include "r_things.h" // numskins
|
||||
#include "k_race.h" // finishBeamLine
|
||||
#include "k_boss.h"
|
||||
#include "m_perfstats.h"
|
||||
|
||||
|
||||
|
|
@ -168,7 +167,7 @@ void K_UpdateMatchRaceBots(void)
|
|||
}
|
||||
}
|
||||
|
||||
if (difficulty == 0 || !(gametyperules & GTR_BOTS) || bossinfo.boss == true)
|
||||
if (difficulty == 0 || !(gametyperules & GTR_BOTS))
|
||||
{
|
||||
wantedbots = 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -324,6 +324,11 @@ tic_t K_MineExplodeAttack(mobj_t *actor, fixed_t size, boolean spin)
|
|||
|
||||
if (!spin)
|
||||
{
|
||||
if (minehitlag == 0)
|
||||
{
|
||||
minehitlag = actor->hitlag;
|
||||
}
|
||||
|
||||
Obj_SpawnBrolyKi(actor, minehitlag);
|
||||
|
||||
return minehitlag;
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@
|
|||
/// \brief Grand Prix mode game logic & bot behaviors
|
||||
|
||||
#include "k_grandprix.h"
|
||||
#include "k_boss.h"
|
||||
#include "k_specialstage.h"
|
||||
#include "doomdef.h"
|
||||
#include "d_player.h"
|
||||
|
|
@ -339,7 +338,7 @@ void K_UpdateGrandPrixBots(void)
|
|||
continue;
|
||||
}
|
||||
|
||||
players[i].spectator = (grandprixinfo.eventmode != GPEVENT_NONE);
|
||||
players[i].spectator = !(gametyperules & GTR_BOTS) || (grandprixinfo.eventmode != GPEVENT_NONE);
|
||||
}
|
||||
|
||||
// Find the rival.
|
||||
|
|
@ -529,7 +528,7 @@ void K_RetireBots(void)
|
|||
UINT8 i;
|
||||
|
||||
if (grandprixinfo.gp == true
|
||||
&& ((grandprixinfo.roundnum >= grandprixinfo.cup->numlevels)
|
||||
&& ((grandprixinfo.cup != NULL && grandprixinfo.roundnum >= grandprixinfo.cup->numlevels)
|
||||
|| grandprixinfo.eventmode != GPEVENT_NONE))
|
||||
{
|
||||
// No replacement.
|
||||
|
|
@ -676,7 +675,7 @@ void K_PlayerLoseLife(player_t *player)
|
|||
return;
|
||||
}
|
||||
|
||||
if (player->spectator || player->exiting || player->bot || player->lives <= 0 || (player->pflags & PF_LOSTLIFE))
|
||||
if (player->spectator || (player->exiting && !(player->pflags & PF_NOCONTEST)) || player->bot || player->lives <= 0 || (player->pflags & PF_LOSTLIFE))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
|
@ -703,24 +702,12 @@ void K_PlayerLoseLife(player_t *player)
|
|||
--------------------------------------------------*/
|
||||
boolean K_CanChangeRules(boolean allowdemos)
|
||||
{
|
||||
if (grandprixinfo.gp == true && grandprixinfo.roundnum > 0)
|
||||
if (grandprixinfo.gp == true /*&& grandprixinfo.roundnum > 0*/)
|
||||
{
|
||||
// Don't cheat the rules of the GP!
|
||||
return false;
|
||||
}
|
||||
|
||||
if (bossinfo.boss == true)
|
||||
{
|
||||
// Don't cheat the boss!
|
||||
return false;
|
||||
}
|
||||
|
||||
if (specialStage.active == true)
|
||||
{
|
||||
// Don't cheat special stages!
|
||||
return false;
|
||||
}
|
||||
|
||||
if (marathonmode)
|
||||
{
|
||||
// Don't cheat the endurance challenge!
|
||||
|
|
|
|||
225
src/k_hud.c
225
src/k_hud.c
|
|
@ -1863,7 +1863,7 @@ static boolean K_drawKartPositionFaces(void)
|
|||
ranklines--;
|
||||
i = ranklines;
|
||||
|
||||
if (gametype == GT_BATTLE || strank <= 2) // too close to the top, or playing battle, or a spectator? would have had (strank == -1) called out, but already caught by (strank <= 2)
|
||||
if ((gametyperules & GTR_POINTLIMIT) || strank <= 2) // too close to the top, or playing battle, or a spectator? would have had (strank == -1) called out, but already caught by (strank <= 2)
|
||||
{
|
||||
if (i > 4) // could be both...
|
||||
i = 4;
|
||||
|
|
@ -1951,7 +1951,7 @@ static boolean K_drawKartPositionFaces(void)
|
|||
if (i == strank)
|
||||
V_DrawScaledPatch(FACE_X, Y, V_HUDTRANS|V_SLIDEIN|V_SNAPTOLEFT, kp_facehighlight[(leveltime / 4) % 8]);
|
||||
|
||||
if (gametype == GT_BATTLE && players[rankplayer[i]].bumpers <= 0)
|
||||
if ((gametyperules & GTR_BUMPERS) && players[rankplayer[i]].bumpers <= 0)
|
||||
V_DrawScaledPatch(FACE_X-4, Y-3, V_HUDTRANS|V_SLIDEIN|V_SNAPTOLEFT, kp_ranknobumpers);
|
||||
else
|
||||
{
|
||||
|
|
@ -1973,7 +1973,7 @@ static void K_drawBossHealthBar(void)
|
|||
UINT8 i = 0, barstatus = 1, randlen = 0, darken = 0;
|
||||
const INT32 startx = BASEVIDWIDTH - 23;
|
||||
INT32 starty = BASEVIDHEIGHT - 25;
|
||||
INT32 rolrand = 0;
|
||||
INT32 rolrand = 0, randtemp = 0;
|
||||
boolean randsign = false;
|
||||
|
||||
if (bossinfo.barlen <= 1)
|
||||
|
|
@ -2019,7 +2019,9 @@ static void K_drawBossHealthBar(void)
|
|||
barstatus = 2;
|
||||
}
|
||||
|
||||
randlen = M_RandomKey(bossinfo.visualbar-(bossinfo.visualdiv/(2*FRACUNIT)))+1;
|
||||
randtemp = bossinfo.visualbar-(bossinfo.visualdiv/(2*FRACUNIT));
|
||||
if (randtemp > 0)
|
||||
randlen = M_RandomKey(randtemp)+1;
|
||||
randsign = M_RandomChance(FRACUNIT/2);
|
||||
|
||||
// Right wing.
|
||||
|
|
@ -2034,7 +2036,9 @@ static void K_drawBossHealthBar(void)
|
|||
randlen--;
|
||||
if (!randlen)
|
||||
{
|
||||
randlen = M_RandomKey(bossinfo.visualbar-(bossinfo.visualdiv/(2*FRACUNIT)))+1;
|
||||
randtemp = bossinfo.visualbar-(bossinfo.visualdiv/(2*FRACUNIT));
|
||||
if (randtemp > 0)
|
||||
randlen = M_RandomKey(randtemp)+1;
|
||||
if (barstatus > 1)
|
||||
{
|
||||
rolrand = M_RandomKey(barstatus)+1;
|
||||
|
|
@ -2265,7 +2269,7 @@ void K_DrawTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scorelines, IN
|
|||
colormap = R_GetTranslationColormap(players[tab[i].num].skin, players[tab[i].num].mo->color, GTC_CACHE);
|
||||
|
||||
V_DrawMappedPatch(x, y-4, 0, faceprefix[players[tab[i].num].skin][FACE_RANK], colormap);
|
||||
/*if (gametype == GT_BATTLE && players[tab[i].num].bumpers > 0) -- not enough space for this
|
||||
/*if ((gametyperules & GTR_BUMPERS) && players[tab[i].num].bumpers > 0) -- not enough space for this
|
||||
{
|
||||
INT32 bumperx = x+19;
|
||||
V_DrawMappedPatch(bumperx-2, y-4, 0, kp_tinybumper[0], colormap);
|
||||
|
|
@ -2280,7 +2284,7 @@ void K_DrawTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scorelines, IN
|
|||
if (tab[i].num == whiteplayer)
|
||||
V_DrawScaledPatch(x, y-4, 0, kp_facehighlight[(leveltime / 4) % 8]);
|
||||
|
||||
if (gametype == GT_BATTLE && players[tab[i].num].bumpers <= 0)
|
||||
if ((gametyperules & GTR_BUMPERS) && players[tab[i].num].bumpers <= 0)
|
||||
V_DrawScaledPatch(x-4, y-7, 0, kp_ranknobumpers);
|
||||
else
|
||||
{
|
||||
|
|
@ -2291,7 +2295,7 @@ void K_DrawTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scorelines, IN
|
|||
V_DrawScaledPatch(x-5, y+6, 0, kp_facenum[pos]);
|
||||
}
|
||||
|
||||
if (gametype == GT_RACE)
|
||||
if ((gametyperules & GTR_CIRCUIT))
|
||||
{
|
||||
#define timestring(time) va("%i'%02i\"%02i", G_TicsToMinutes(time, true), G_TicsToSeconds(time), G_TicsToCentiseconds(time))
|
||||
if (scorelines >= 8)
|
||||
|
|
@ -2300,7 +2304,7 @@ void K_DrawTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scorelines, IN
|
|||
V_DrawRightAlignedThinString(x+rightoffset, y-1, hilicol|V_6WIDTHSPACE, timestring(players[tab[i].num].realtime));
|
||||
else if (players[tab[i].num].pflags & PF_NOCONTEST)
|
||||
V_DrawRightAlignedThinString(x+rightoffset, y-1, V_6WIDTHSPACE, "NO CONTEST.");
|
||||
else if (circuitmap)
|
||||
else
|
||||
V_DrawRightAlignedThinString(x+rightoffset, y-1, V_6WIDTHSPACE, va("Lap %d", tab[i].count));
|
||||
}
|
||||
else
|
||||
|
|
@ -2309,7 +2313,7 @@ void K_DrawTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scorelines, IN
|
|||
V_DrawRightAlignedString(x+rightoffset, y, hilicol, timestring(players[tab[i].num].realtime));
|
||||
else if (players[tab[i].num].pflags & PF_NOCONTEST)
|
||||
V_DrawRightAlignedThinString(x+rightoffset, y-1, 0, "NO CONTEST.");
|
||||
else if (circuitmap)
|
||||
else
|
||||
V_DrawRightAlignedString(x+rightoffset, y, 0, va("Lap %d", tab[i].count));
|
||||
}
|
||||
#undef timestring
|
||||
|
|
@ -2326,40 +2330,13 @@ void K_DrawTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scorelines, IN
|
|||
}
|
||||
}
|
||||
|
||||
#define RINGANIM_FLIPFRAME (RINGANIM_NUMFRAMES/2)
|
||||
|
||||
static void K_drawKartLapsAndRings(void)
|
||||
static void K_drawKartLaps(void)
|
||||
{
|
||||
const boolean uselives = G_GametypeUsesLives();
|
||||
SINT8 ringanim_realframe = stplyr->karthud[khud_ringframe];
|
||||
INT32 splitflags = V_SNAPTOBOTTOM|V_SNAPTOLEFT|V_SPLITSCREEN;
|
||||
UINT8 rn[2];
|
||||
INT32 ringflip = 0;
|
||||
UINT8 *ringmap = NULL;
|
||||
boolean colorring = false;
|
||||
INT32 ringx = 0;
|
||||
|
||||
rn[0] = ((abs(stplyr->rings) / 10) % 10);
|
||||
rn[1] = (abs(stplyr->rings) % 10);
|
||||
|
||||
if (stplyr->rings <= 0 && (leveltime/5 & 1)) // In debt
|
||||
{
|
||||
ringmap = R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_CRIMSON, GTC_CACHE);
|
||||
colorring = true;
|
||||
}
|
||||
else if (stplyr->rings >= 20) // Maxed out
|
||||
ringmap = R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_YELLOW, GTC_CACHE);
|
||||
|
||||
if (stplyr->karthud[khud_ringframe] > RINGANIM_FLIPFRAME)
|
||||
{
|
||||
ringflip = V_FLIP;
|
||||
ringanim_realframe = RINGANIM_NUMFRAMES-stplyr->karthud[khud_ringframe];
|
||||
ringx += SHORT((r_splitscreen > 1) ? kp_smallring[ringanim_realframe]->width : kp_ring[ringanim_realframe]->width);
|
||||
}
|
||||
|
||||
if (r_splitscreen > 1)
|
||||
{
|
||||
INT32 fx = 0, fy = 0, fr = 0;
|
||||
INT32 fx = 0, fy = 0;
|
||||
INT32 flipflag = 0;
|
||||
|
||||
// pain and suffering defined below
|
||||
|
|
@ -2385,8 +2362,6 @@ static void K_drawKartLapsAndRings(void)
|
|||
}
|
||||
}
|
||||
|
||||
fr = fx;
|
||||
|
||||
// Laps
|
||||
V_DrawScaledPatch(fx-2 + (flipflag ? (SHORT(kp_ringstickersplit[1]->width) - 3) : 0), fy, V_HUDTRANS|V_SLIDEIN|splitflags|flipflag, kp_ringstickersplit[0]);
|
||||
|
||||
|
|
@ -2413,6 +2388,75 @@ static void K_drawKartLapsAndRings(void)
|
|||
V_DrawScaledPatch(fx+13, fy, V_HUDTRANS|V_SLIDEIN|splitflags, kp_facenum[(stplyr->laps) % 10]);
|
||||
V_DrawScaledPatch(fx+27, fy, V_HUDTRANS|V_SLIDEIN|splitflags, kp_facenum[(numlaps) % 10]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Laps
|
||||
V_DrawScaledPatch(LAPS_X, LAPS_Y, V_HUDTRANS|V_SLIDEIN|splitflags, kp_lapsticker);
|
||||
V_DrawKartString(LAPS_X+33, LAPS_Y+3, V_HUDTRANS|V_SLIDEIN|splitflags, va("%d/%d", min(stplyr->laps, numlaps), numlaps));
|
||||
}
|
||||
}
|
||||
|
||||
#define RINGANIM_FLIPFRAME (RINGANIM_NUMFRAMES/2)
|
||||
|
||||
static void K_drawRingCounter(void)
|
||||
{
|
||||
const boolean uselives = G_GametypeUsesLives();
|
||||
SINT8 ringanim_realframe = stplyr->karthud[khud_ringframe];
|
||||
INT32 splitflags = V_SNAPTOBOTTOM|V_SNAPTOLEFT|V_SPLITSCREEN;
|
||||
UINT8 rn[2];
|
||||
INT32 ringflip = 0;
|
||||
UINT8 *ringmap = NULL;
|
||||
boolean colorring = false;
|
||||
INT32 ringx = 0, fy = 0;
|
||||
|
||||
rn[0] = ((abs(stplyr->rings) / 10) % 10);
|
||||
rn[1] = (abs(stplyr->rings) % 10);
|
||||
|
||||
if (stplyr->rings <= 0 && (leveltime/5 & 1)) // In debt
|
||||
{
|
||||
ringmap = R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_CRIMSON, GTC_CACHE);
|
||||
colorring = true;
|
||||
}
|
||||
else if (stplyr->rings >= 20) // Maxed out
|
||||
ringmap = R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_YELLOW, GTC_CACHE);
|
||||
|
||||
if (stplyr->karthud[khud_ringframe] > RINGANIM_FLIPFRAME)
|
||||
{
|
||||
ringflip = V_FLIP;
|
||||
ringanim_realframe = RINGANIM_NUMFRAMES-stplyr->karthud[khud_ringframe];
|
||||
ringx += SHORT((r_splitscreen > 1) ? kp_smallring[ringanim_realframe]->width : kp_ring[ringanim_realframe]->width);
|
||||
}
|
||||
|
||||
if (r_splitscreen > 1)
|
||||
{
|
||||
INT32 fx = 0, fr = 0;
|
||||
INT32 flipflag = 0;
|
||||
|
||||
// pain and suffering defined below
|
||||
if (r_splitscreen < 2) // don't change shit for THIS splitscreen.
|
||||
{
|
||||
fx = LAPS_X;
|
||||
fy = LAPS_Y;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (stplyr == &players[displayplayers[0]] || stplyr == &players[displayplayers[2]]) // If we are P1 or P3...
|
||||
{
|
||||
fx = LAPS_X;
|
||||
fy = LAPS_Y;
|
||||
splitflags = V_SNAPTOLEFT|V_SNAPTOBOTTOM|V_SPLITSCREEN;
|
||||
}
|
||||
else // else, that means we're P2 or P4.
|
||||
{
|
||||
fx = LAPS2_X;
|
||||
fy = LAPS2_Y;
|
||||
splitflags = V_SNAPTORIGHT|V_SNAPTOBOTTOM|V_SPLITSCREEN;
|
||||
flipflag = V_FLIP; // make the string right aligned and other shit
|
||||
}
|
||||
}
|
||||
|
||||
fr = fx;
|
||||
|
||||
// Rings
|
||||
if (!uselives)
|
||||
|
|
@ -2447,41 +2491,42 @@ static void K_drawKartLapsAndRings(void)
|
|||
}
|
||||
else
|
||||
{
|
||||
// Laps
|
||||
V_DrawScaledPatch(LAPS_X, LAPS_Y, V_HUDTRANS|V_SLIDEIN|splitflags, kp_lapsticker);
|
||||
V_DrawKartString(LAPS_X+33, LAPS_Y+3, V_HUDTRANS|V_SLIDEIN|splitflags, va("%d/%d", min(stplyr->laps, numlaps), numlaps));
|
||||
fy = LAPS_Y-11;
|
||||
|
||||
if ((gametyperules & (GTR_BUMPERS|GTR_CIRCUIT)) == GTR_BUMPERS)
|
||||
fy -= 4;
|
||||
|
||||
// Rings
|
||||
if (!uselives)
|
||||
V_DrawScaledPatch(LAPS_X, LAPS_Y-11, V_HUDTRANS|V_SLIDEIN|splitflags, kp_ringsticker[1]);
|
||||
V_DrawScaledPatch(LAPS_X, fy, V_HUDTRANS|V_SLIDEIN|splitflags, kp_ringsticker[1]);
|
||||
else
|
||||
V_DrawScaledPatch(LAPS_X, LAPS_Y-11, V_HUDTRANS|V_SLIDEIN|splitflags, kp_ringsticker[0]);
|
||||
V_DrawScaledPatch(LAPS_X, fy, V_HUDTRANS|V_SLIDEIN|splitflags, kp_ringsticker[0]);
|
||||
|
||||
V_DrawMappedPatch(LAPS_X+ringx+7, LAPS_Y-16, V_HUDTRANS|V_SLIDEIN|splitflags|ringflip, kp_ring[ringanim_realframe], (colorring ? ringmap : NULL));
|
||||
V_DrawMappedPatch(LAPS_X+ringx+7, fy-5, V_HUDTRANS|V_SLIDEIN|splitflags|ringflip, kp_ring[ringanim_realframe], (colorring ? ringmap : NULL));
|
||||
|
||||
if (stplyr->rings < 0) // Draw the minus for ring debt
|
||||
{
|
||||
V_DrawMappedPatch(LAPS_X+23, LAPS_Y-11, V_HUDTRANS|V_SLIDEIN|splitflags, kp_ringdebtminus, ringmap);
|
||||
V_DrawMappedPatch(LAPS_X+29, LAPS_Y-11, V_HUDTRANS|V_SLIDEIN|splitflags, kp_facenum[rn[0]], ringmap);
|
||||
V_DrawMappedPatch(LAPS_X+35, LAPS_Y-11, V_HUDTRANS|V_SLIDEIN|splitflags, kp_facenum[rn[1]], ringmap);
|
||||
V_DrawMappedPatch(LAPS_X+23, fy, V_HUDTRANS|V_SLIDEIN|splitflags, kp_ringdebtminus, ringmap);
|
||||
V_DrawMappedPatch(LAPS_X+29, fy, V_HUDTRANS|V_SLIDEIN|splitflags, kp_facenum[rn[0]], ringmap);
|
||||
V_DrawMappedPatch(LAPS_X+35, fy, V_HUDTRANS|V_SLIDEIN|splitflags, kp_facenum[rn[1]], ringmap);
|
||||
}
|
||||
else
|
||||
{
|
||||
V_DrawMappedPatch(LAPS_X+23, LAPS_Y-11, V_HUDTRANS|V_SLIDEIN|splitflags, kp_facenum[rn[0]], ringmap);
|
||||
V_DrawMappedPatch(LAPS_X+29, LAPS_Y-11, V_HUDTRANS|V_SLIDEIN|splitflags, kp_facenum[rn[1]], ringmap);
|
||||
V_DrawMappedPatch(LAPS_X+23, fy, V_HUDTRANS|V_SLIDEIN|splitflags, kp_facenum[rn[0]], ringmap);
|
||||
V_DrawMappedPatch(LAPS_X+29, fy, V_HUDTRANS|V_SLIDEIN|splitflags, kp_facenum[rn[1]], ringmap);
|
||||
}
|
||||
|
||||
// SPB ring lock
|
||||
if (stplyr->pflags & PF_RINGLOCK)
|
||||
V_DrawScaledPatch(LAPS_X-5, LAPS_Y-28, V_HUDTRANS|V_SLIDEIN|splitflags, kp_ringspblock[stplyr->karthud[khud_ringspblock]]);
|
||||
V_DrawScaledPatch(LAPS_X-5, fy-17, V_HUDTRANS|V_SLIDEIN|splitflags, kp_ringspblock[stplyr->karthud[khud_ringspblock]]);
|
||||
|
||||
// Lives
|
||||
if (uselives)
|
||||
{
|
||||
UINT8 *colormap = R_GetTranslationColormap(stplyr->skin, stplyr->skincolor, GTC_CACHE);
|
||||
V_DrawMappedPatch(LAPS_X+46, LAPS_Y-16, V_HUDTRANS|V_SLIDEIN|splitflags, faceprefix[stplyr->skin][FACE_RANK], colormap);
|
||||
V_DrawMappedPatch(LAPS_X+46, fy-5, V_HUDTRANS|V_SLIDEIN|splitflags, faceprefix[stplyr->skin][FACE_RANK], colormap);
|
||||
if (stplyr->lives >= 0)
|
||||
V_DrawScaledPatch(LAPS_X+63, LAPS_Y-11, V_HUDTRANS|V_SLIDEIN|splitflags, kp_facenum[(stplyr->lives % 10)]); // make sure this doesn't overflow OR underflow
|
||||
V_DrawScaledPatch(LAPS_X+63, fy, V_HUDTRANS|V_SLIDEIN|splitflags, kp_facenum[(stplyr->lives % 10)]); // make sure this doesn't overflow OR underflow
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2498,7 +2543,7 @@ static void K_drawKartAccessibilityIcons(INT32 fx)
|
|||
|
||||
if (r_splitscreen < 2) // adjust to speedometer height
|
||||
{
|
||||
if (gametype == GT_BATTLE)
|
||||
if ((gametyperules & (GTR_BUMPERS|GTR_CIRCUIT)) == GTR_BUMPERS)
|
||||
fy -= 4;
|
||||
}
|
||||
else
|
||||
|
|
@ -2588,7 +2633,7 @@ static void K_drawKartSpeedometer(void)
|
|||
numbers[1] = ((convSpeed / 10) % 10);
|
||||
numbers[2] = (convSpeed % 10);
|
||||
|
||||
if (gametype == GT_BATTLE)
|
||||
if ((gametyperules & (GTR_BUMPERS|GTR_CIRCUIT)) == GTR_BUMPERS)
|
||||
battleoffset = -4;
|
||||
|
||||
V_DrawScaledPatch(LAPS_X, LAPS_Y-25 + battleoffset, V_HUDTRANS|V_SLIDEIN|splitflags, kp_speedometersticker);
|
||||
|
|
@ -2793,14 +2838,15 @@ static void K_drawKartBumpersOrKarma(void)
|
|||
else
|
||||
V_DrawMappedPatch(LAPS_X, LAPS_Y, V_HUDTRANS|V_SLIDEIN|splitflags, kp_bumpersticker, colormap);
|
||||
|
||||
if (bossinfo.boss)
|
||||
V_DrawKartString(LAPS_X+47, LAPS_Y+3, V_HUDTRANS|V_SLIDEIN|splitflags, va("%d/%d", stplyr->bumpers, maxbumper));
|
||||
else // TODO BETTER HUD
|
||||
if (gametyperules & GTR_KARMA) // TODO BETTER HUD
|
||||
V_DrawKartString(LAPS_X+47, LAPS_Y+3, V_HUDTRANS|V_SLIDEIN|splitflags, va("%d/%d %d", stplyr->bumpers, maxbumper, stplyr->overtimekarma / TICRATE));
|
||||
else
|
||||
V_DrawKartString(LAPS_X+47, LAPS_Y+3, V_HUDTRANS|V_SLIDEIN|splitflags, va("%d/%d", stplyr->bumpers, maxbumper));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
static void K_drawKartWanted(void)
|
||||
{
|
||||
UINT8 i, numwanted = 0;
|
||||
|
|
@ -2875,6 +2921,7 @@ static void K_drawKartWanted(void)
|
|||
}
|
||||
}
|
||||
}
|
||||
#endif //if 0
|
||||
|
||||
static void K_drawKartPlayerCheck(void)
|
||||
{
|
||||
|
|
@ -3358,7 +3405,7 @@ static void K_drawKartNameTags(void)
|
|||
c.z = viewz;
|
||||
|
||||
// Maybe shouldn't be handling this here... but the camera info is too good.
|
||||
if (bossinfo.boss)
|
||||
if (bossinfo.valid == true)
|
||||
{
|
||||
weakspotdraw_t weakspotdraw[NUMWEAKSPOTS];
|
||||
UINT8 numdraw = 0;
|
||||
|
|
@ -3810,7 +3857,7 @@ static void K_drawKartMinimap(void)
|
|||
y -= SHORT(AutomapPic->topoffset);
|
||||
|
||||
// Draw the super item in Battle
|
||||
if (gametype == GT_BATTLE && battleovertime.enabled)
|
||||
if ((gametyperules & GTR_OVERTIME) && battleovertime.enabled)
|
||||
{
|
||||
if (battleovertime.enabled >= 10*TICRATE || (battleovertime.enabled & 1))
|
||||
{
|
||||
|
|
@ -3920,8 +3967,8 @@ static void K_drawKartMinimap(void)
|
|||
K_drawKartMinimapIcon(interpx, interpy, x, y, splitflags, faceprefix[skin][FACE_MINIMAP], colormap, AutomapPic);
|
||||
|
||||
// Target reticule
|
||||
if ((gametype == GT_RACE && players[i].position == spbplace)
|
||||
|| (gametype == GT_BATTLE && K_IsPlayerWanted(&players[i])))
|
||||
if (((gametyperules & GTR_CIRCUIT) && players[i].position == spbplace)
|
||||
|| ((gametyperules & (GTR_BOSS|GTR_POINTLIMIT)) == GTR_POINTLIMIT && K_IsPlayerWanted(&players[i])))
|
||||
{
|
||||
K_drawKartMinimapIcon(interpx, interpy, x, y, splitflags, kp_wantedreticle, NULL, AutomapPic);
|
||||
}
|
||||
|
|
@ -3979,7 +4026,7 @@ static void K_drawKartMinimap(void)
|
|||
}
|
||||
|
||||
// ...but first, any boss targets.
|
||||
if (bossinfo.boss)
|
||||
if (bossinfo.valid == true)
|
||||
{
|
||||
for (i = 0; i < NUMWEAKSPOTS; i++)
|
||||
{
|
||||
|
|
@ -4047,8 +4094,8 @@ static void K_drawKartMinimap(void)
|
|||
K_drawKartMinimapIcon(interpx, interpy, x, y, splitflags, workingPic, colormap, AutomapPic);
|
||||
|
||||
// Target reticule
|
||||
if ((gametype == GT_RACE && players[localplayers[i]].position == spbplace)
|
||||
|| (gametype == GT_BATTLE && K_IsPlayerWanted(&players[localplayers[i]])))
|
||||
if (((gametyperules & GTR_CIRCUIT) && players[localplayers[i]].position == spbplace)
|
||||
|| ((gametyperules & (GTR_BOSS|GTR_POINTLIMIT)) == GTR_POINTLIMIT && K_IsPlayerWanted(&players[localplayers[i]])))
|
||||
{
|
||||
K_drawKartMinimapIcon(interpx, interpy, x, y, splitflags, kp_wantedreticle, NULL, AutomapPic);
|
||||
}
|
||||
|
|
@ -4836,7 +4883,7 @@ void K_drawKartFreePlay(void)
|
|||
if (!LUA_HudEnabled(hud_freeplay))
|
||||
return;
|
||||
|
||||
if (modeattacking || grandprixinfo.gp || bossinfo.boss || stplyr->spectator)
|
||||
if (modeattacking || grandprixinfo.gp || bossinfo.valid || stplyr->spectator)
|
||||
return;
|
||||
|
||||
if (lt_exitticker < TICRATE/2)
|
||||
|
|
@ -5024,10 +5071,10 @@ void K_drawKartHUD(void)
|
|||
return;
|
||||
}
|
||||
|
||||
battlefullscreen = ((gametyperules & (GTR_BUMPERS|GTR_KARMA)) == (GTR_BUMPERS|GTR_KARMA)
|
||||
battlefullscreen = (!(gametyperules & GTR_CIRCUIT)
|
||||
&& (stplyr->exiting
|
||||
|| (stplyr->bumpers <= 0
|
||||
&& stplyr->karmadelay > 0
|
||||
|| ((gametyperules & GTR_BUMPERS) && (stplyr->bumpers <= 0)
|
||||
&& ((gametyperules & GTR_KARMA) && (stplyr->karmadelay > 0))
|
||||
&& !(stplyr->pflags & PF_ELIMINATED)
|
||||
&& stplyr->playerstate == PST_LIVE)));
|
||||
|
||||
|
|
@ -5043,11 +5090,13 @@ void K_drawKartHUD(void)
|
|||
K_drawKartNameTags();
|
||||
|
||||
// Draw WANTED status
|
||||
#if 0
|
||||
if (gametype == GT_BATTLE)
|
||||
{
|
||||
if (LUA_HudEnabled(hud_wanted))
|
||||
K_drawKartWanted();
|
||||
}
|
||||
#endif
|
||||
|
||||
if (LUA_HudEnabled(hud_minimap))
|
||||
K_drawKartMinimap();
|
||||
|
|
@ -5094,32 +5143,26 @@ void K_drawKartHUD(void)
|
|||
{
|
||||
if (LUA_HudEnabled(hud_position))
|
||||
{
|
||||
if (bossinfo.boss)
|
||||
if (bossinfo.valid)
|
||||
{
|
||||
K_drawBossHealthBar();
|
||||
}
|
||||
else if (gametype == GT_RACE) // Race-only elements (not currently gametyperuleable)
|
||||
else if (freecam)
|
||||
;
|
||||
else if ((gametyperules & GTR_POWERSTONES))
|
||||
{
|
||||
if (!islonesome)
|
||||
{
|
||||
// Draw the numerical position
|
||||
K_DrawKartPositionNum(stplyr->position);
|
||||
}
|
||||
}
|
||||
else if (gametype == GT_BATTLE) // Battle-only (ditto)
|
||||
{
|
||||
if (!freecam && !battlecapsules)
|
||||
{
|
||||
if (!battlecapsules)
|
||||
K_drawKartEmeralds();
|
||||
}
|
||||
}
|
||||
else if (!islonesome)
|
||||
K_DrawKartPositionNum(stplyr->position);
|
||||
}
|
||||
|
||||
if (LUA_HudEnabled(hud_gametypeinfo))
|
||||
{
|
||||
if (gametyperules & GTR_CIRCUIT)
|
||||
{
|
||||
K_drawKartLapsAndRings();
|
||||
K_drawKartLaps();
|
||||
}
|
||||
else if (gametyperules & GTR_BUMPERS)
|
||||
{
|
||||
|
|
@ -5141,8 +5184,12 @@ void K_drawKartHUD(void)
|
|||
{
|
||||
K_drawBlueSphereMeter();
|
||||
}
|
||||
else
|
||||
{
|
||||
K_drawRingCounter();
|
||||
}
|
||||
|
||||
if (modeattacking && !bossinfo.boss)
|
||||
if (modeattacking && !bossinfo.valid)
|
||||
{
|
||||
// Draw the input UI
|
||||
if (LUA_HudEnabled(hud_position))
|
||||
|
|
@ -5172,10 +5219,12 @@ void K_drawKartHUD(void)
|
|||
}
|
||||
|
||||
// Race overlays
|
||||
if (gametype == GT_RACE && !freecam)
|
||||
if (!freecam)
|
||||
{
|
||||
if (stplyr->exiting)
|
||||
K_drawKartFinish(true);
|
||||
else if (!(gametyperules & GTR_CIRCUIT))
|
||||
;
|
||||
else if (stplyr->karthud[khud_lapanimation] && !r_splitscreen)
|
||||
K_drawLapStartAnim();
|
||||
}
|
||||
|
|
@ -5187,7 +5236,7 @@ void K_drawKartHUD(void)
|
|||
if (modeattacking || freecam) // everything after here is MP and debug only
|
||||
return;
|
||||
|
||||
if (gametype == GT_BATTLE && !r_splitscreen && (stplyr->karthud[khud_yougotem] % 2)) // * YOU GOT EM *
|
||||
if ((gametyperules & GTR_KARMA) && !r_splitscreen && (stplyr->karthud[khud_yougotem] % 2)) // * YOU GOT EM *
|
||||
V_DrawScaledPatch(BASEVIDWIDTH/2 - (SHORT(kp_yougotem->width)/2), 32, V_HUDTRANS, kp_yougotem);
|
||||
|
||||
// Draw FREE PLAY.
|
||||
|
|
|
|||
301
src/k_kart.c
301
src/k_kart.c
|
|
@ -6,7 +6,6 @@
|
|||
|
||||
#include "k_kart.h"
|
||||
#include "k_battle.h"
|
||||
#include "k_boss.h"
|
||||
#include "k_pwrlv.h"
|
||||
#include "k_color.h"
|
||||
#include "k_respawn.h"
|
||||
|
|
@ -41,6 +40,7 @@
|
|||
#include "k_follower.h"
|
||||
#include "k_objects.h"
|
||||
#include "k_grandprix.h"
|
||||
#include "k_boss.h"
|
||||
#include "k_specialstage.h"
|
||||
#include "k_roulette.h"
|
||||
|
||||
|
|
@ -109,11 +109,43 @@ void K_TimerInit(void)
|
|||
boolean domodeattack = ((modeattacking != ATTACKING_NONE)
|
||||
|| (grandprixinfo.gp == true && grandprixinfo.eventmode != GPEVENT_NONE));
|
||||
|
||||
if (specialStage.active == true)
|
||||
// Rooooooolllling staaaaaaart
|
||||
if ((gametyperules & (GTR_ROLLINGSTART|GTR_CIRCUIT)) == (GTR_ROLLINGSTART|GTR_CIRCUIT))
|
||||
{
|
||||
S_StartSound(NULL, sfx_s25f);
|
||||
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
player_t *player = NULL;
|
||||
|
||||
if (playeringame[i] == false)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
player = &players[i];
|
||||
if (player->spectator == true)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (player->mo == NULL || P_MobjWasRemoved(player->mo) == true)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Rolling start? lol
|
||||
P_InstaThrust(player->mo, player->mo->angle, K_GetKartSpeed(player, false, false));
|
||||
}
|
||||
}
|
||||
|
||||
if ((gametyperules & (GTR_CATCHER|GTR_CIRCUIT)) == (GTR_CATCHER|GTR_CIRCUIT))
|
||||
{
|
||||
K_InitSpecialStage();
|
||||
}
|
||||
else if (bossinfo.boss == false)
|
||||
else if (K_CheckBossIntro() == true)
|
||||
;
|
||||
else
|
||||
{
|
||||
if (!domodeattack)
|
||||
{
|
||||
|
|
@ -152,7 +184,7 @@ void K_TimerInit(void)
|
|||
|
||||
K_BattleInit(domodeattack);
|
||||
|
||||
if ((gametyperules & GTR_TIMELIMIT) && !bossinfo.boss && !modeattacking)
|
||||
if ((gametyperules & GTR_TIMELIMIT) && !modeattacking)
|
||||
{
|
||||
if (!K_CanChangeRules(true))
|
||||
{
|
||||
|
|
@ -162,7 +194,7 @@ void K_TimerInit(void)
|
|||
}
|
||||
else
|
||||
{
|
||||
timelimitintics = timelimits[gametype] * (60*TICRATE);
|
||||
timelimitintics = gametypes[gametype]->timelimit * (60*TICRATE);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
@ -310,8 +342,6 @@ void K_RegisterKartStuff(void)
|
|||
CV_RegisterVar(&cv_kartbumpers);
|
||||
CV_RegisterVar(&cv_kartfrantic);
|
||||
CV_RegisterVar(&cv_kartencore);
|
||||
CV_RegisterVar(&cv_kartvoterulechanges);
|
||||
CV_RegisterVar(&cv_kartgametypepreference);
|
||||
CV_RegisterVar(&cv_kartspeedometer);
|
||||
CV_RegisterVar(&cv_kartvoices);
|
||||
CV_RegisterVar(&cv_kartbot);
|
||||
|
|
@ -342,15 +372,21 @@ boolean K_IsPlayerLosing(player_t *player)
|
|||
INT32 winningpos = 1;
|
||||
UINT8 i, pcount = 0;
|
||||
|
||||
if (player->pflags & PF_NOCONTEST)
|
||||
return true;
|
||||
|
||||
if (battlecapsules && numtargets == 0)
|
||||
return true; // Didn't even TRY?
|
||||
|
||||
if (battlecapsules || bossinfo.boss)
|
||||
if (battlecapsules || (gametyperules & GTR_BOSS))
|
||||
return (player->bumpers <= 0); // anything short of DNF is COOL
|
||||
|
||||
if (player->position == 1)
|
||||
return false;
|
||||
|
||||
if (specialstageinfo.valid == true)
|
||||
return false; // anything short of DNF is COOL
|
||||
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
if (!playeringame[i] || players[i].spectator)
|
||||
|
|
@ -515,7 +551,7 @@ boolean K_TimeAttackRules(void)
|
|||
UINT8 playing = 0;
|
||||
UINT8 i;
|
||||
|
||||
if (specialStage.active == true)
|
||||
if ((gametyperules & (GTR_CATCHER|GTR_CIRCUIT)) == (GTR_CATCHER|GTR_CIRCUIT))
|
||||
{
|
||||
// Kind of a hack -- Special Stages
|
||||
// are expected to be 1-player, so
|
||||
|
|
@ -1272,10 +1308,9 @@ static boolean K_TryDraft(player_t *player, mobj_t *dest, fixed_t minDist, fixed
|
|||
player->draftpower += add;
|
||||
}
|
||||
|
||||
if (gametype == GT_BATTLE)
|
||||
if (gametyperules & GTR_CLOSERPLAYERS)
|
||||
{
|
||||
// TODO: gametyperules
|
||||
// Double speed in Battle
|
||||
// Double speed in smaller environments
|
||||
player->draftpower += add;
|
||||
}
|
||||
}
|
||||
|
|
@ -1304,8 +1339,7 @@ static boolean K_TryDraft(player_t *player, mobj_t *dest, fixed_t minDist, fixed
|
|||
*/
|
||||
static void K_UpdateDraft(player_t *player)
|
||||
{
|
||||
const boolean addUfo = ((specialStage.active == true)
|
||||
&& (specialStage.ufo != NULL && P_MobjWasRemoved(specialStage.ufo) == false));
|
||||
mobj_t *addUfo = K_GetPossibleSpecialTarget();
|
||||
|
||||
fixed_t topspd = K_GetKartSpeed(player, false, false);
|
||||
fixed_t draftdistance;
|
||||
|
|
@ -1335,9 +1369,8 @@ static void K_UpdateDraft(player_t *player)
|
|||
|
||||
minDist = 640 * player->mo->scale;
|
||||
|
||||
if (gametype == GT_BATTLE)
|
||||
if (gametyperules & GTR_CLOSERPLAYERS)
|
||||
{
|
||||
// TODO: gametyperules
|
||||
minDist /= 4;
|
||||
draftdistance *= 2;
|
||||
leniency *= 4;
|
||||
|
|
@ -1346,10 +1379,10 @@ static void K_UpdateDraft(player_t *player)
|
|||
// Not enough speed to draft.
|
||||
if (player->speed >= 20 * player->mo->scale)
|
||||
{
|
||||
if (addUfo == true)
|
||||
if (addUfo != NULL)
|
||||
{
|
||||
// Tether off of the UFO!
|
||||
if (K_TryDraft(player, specialStage.ufo, minDist, draftdistance, leniency) == true)
|
||||
if (K_TryDraft(player, addUfo, minDist, draftdistance, leniency) == true)
|
||||
{
|
||||
return; // Finished doing our draft.
|
||||
}
|
||||
|
|
@ -1403,11 +1436,11 @@ static void K_UpdateDraft(player_t *player)
|
|||
fixed_t dist = P_AproxDistance(P_AproxDistance(victim->mo->x - player->mo->x, victim->mo->y - player->mo->y), victim->mo->z - player->mo->z);
|
||||
K_DrawDraftCombiring(player, victim->mo, dist, draftdistance, true);
|
||||
}
|
||||
else if (addUfo == true)
|
||||
else if (addUfo != NULL)
|
||||
{
|
||||
// kind of a hack to not have to mess with how lastdraft works
|
||||
fixed_t dist = P_AproxDistance(P_AproxDistance(specialStage.ufo->x - player->mo->x, specialStage.ufo->y - player->mo->y), specialStage.ufo->z - player->mo->z);
|
||||
K_DrawDraftCombiring(player, specialStage.ufo, dist, draftdistance, true);
|
||||
fixed_t dist = P_AproxDistance(P_AproxDistance(addUfo->x - player->mo->x, addUfo->y - player->mo->y), addUfo->z - player->mo->z);
|
||||
K_DrawDraftCombiring(player, addUfo, dist, draftdistance, true);
|
||||
}
|
||||
}
|
||||
else // Remove draft speed boost.
|
||||
|
|
@ -2454,7 +2487,7 @@ void K_PlayOvertakeSound(mobj_t *source)
|
|||
{
|
||||
boolean tasteful = (!source->player || !source->player->karthud[khud_voices]);
|
||||
|
||||
if (!gametype == GT_RACE) // Only in race
|
||||
if (!(gametyperules & GTR_CIRCUIT)) // Only in race
|
||||
return;
|
||||
|
||||
// 4 seconds from before race begins, 10 seconds afterwards
|
||||
|
|
@ -2963,8 +2996,7 @@ fixed_t K_GetSpindashChargeSpeed(player_t *player)
|
|||
// (can be higher than this value when overcharged)
|
||||
const fixed_t val = (10*FRACUNIT/277) + (((player->kartspeed + player->kartweight) + 2) * FRACUNIT) / 45;
|
||||
|
||||
// TODO: gametyperules
|
||||
return (gametype == GT_BATTLE) ? (4 * val) : val;
|
||||
return (gametyperules & GTR_CLOSERPLAYERS) ? (4 * val) : val;
|
||||
}
|
||||
|
||||
// sets boostpower, speedboost, accelboost, and handleboost to whatever we need it to be
|
||||
|
|
@ -3099,9 +3131,8 @@ static void K_GetKartBoostPower(player_t *player)
|
|||
// 30% - 44%, each point of speed adds 1.75%
|
||||
fixed_t draftspeed = ((3*FRACUNIT)/10) + ((player->kartspeed-1) * ((7*FRACUNIT)/400));
|
||||
|
||||
if (gametype == GT_BATTLE)
|
||||
if (gametyperules & GTR_CLOSERPLAYERS)
|
||||
{
|
||||
// TODO: gametyperules
|
||||
draftspeed *= 2;
|
||||
}
|
||||
|
||||
|
|
@ -3224,7 +3255,7 @@ fixed_t K_GetKartAccel(player_t *player)
|
|||
k_accel += 17 * (9 - player->kartspeed); // 121 - 257
|
||||
|
||||
// karma bomb gets 2x acceleration
|
||||
if (gametype == GT_BATTLE && player->bumpers <= 0)
|
||||
if ((gametyperules & GTR_BUMPERS) && player->bumpers <= 0)
|
||||
k_accel *= 2;
|
||||
|
||||
// Marble Garden Top gets 1200% accel
|
||||
|
|
@ -3238,9 +3269,8 @@ UINT16 K_GetKartFlashing(player_t *player)
|
|||
{
|
||||
UINT16 tics = flashingtics;
|
||||
|
||||
if (gametype == GT_BATTLE)
|
||||
if (gametyperules & GTR_BUMPERS)
|
||||
{
|
||||
// TODO: gametyperules
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
@ -3303,7 +3333,8 @@ SINT8 K_GetForwardMove(player_t *player)
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (player->sneakertimer || player->spindashboost)
|
||||
if (player->sneakertimer || player->spindashboost
|
||||
|| (((gametyperules & (GTR_ROLLINGSTART|GTR_CIRCUIT)) == (GTR_ROLLINGSTART|GTR_CIRCUIT)) && (leveltime < TICRATE/2)))
|
||||
{
|
||||
return MAXPLMOVE;
|
||||
}
|
||||
|
|
@ -3545,6 +3576,12 @@ void K_BattleAwardHit(player_t *player, player_t *victim, mobj_t *inflictor, UIN
|
|||
UINT8 points = 1;
|
||||
boolean trapItem = false;
|
||||
|
||||
if (!(gametyperules & GTR_POINTLIMIT))
|
||||
{
|
||||
// No points in this gametype.
|
||||
return;
|
||||
}
|
||||
|
||||
if (player == NULL || victim == NULL)
|
||||
{
|
||||
// Invalid player or victim
|
||||
|
|
@ -3580,11 +3617,8 @@ void K_BattleAwardHit(player_t *player, player_t *victim, mobj_t *inflictor, UIN
|
|||
}
|
||||
}
|
||||
|
||||
if (gametyperules & GTR_POINTLIMIT)
|
||||
{
|
||||
P_AddPlayerScore(player, points);
|
||||
K_SpawnBattlePoints(player, victim, points);
|
||||
}
|
||||
P_AddPlayerScore(player, points);
|
||||
K_SpawnBattlePoints(player, victim, points);
|
||||
}
|
||||
|
||||
void K_SpinPlayer(player_t *player, mobj_t *inflictor, mobj_t *source, INT32 type)
|
||||
|
|
@ -4132,7 +4166,7 @@ void K_HandleBumperChanges(player_t *player, UINT8 prevBumpers)
|
|||
|
||||
player->karmadelay = comebacktime;
|
||||
|
||||
if (bossinfo.boss)
|
||||
if (gametyperules & GTR_BOSS)
|
||||
{
|
||||
P_DoTimeOver(player);
|
||||
}
|
||||
|
|
@ -5056,7 +5090,7 @@ void K_SpawnDraftDust(mobj_t *mo)
|
|||
{
|
||||
UINT8 leniency = (3*TICRATE)/4 + ((mo->player->kartweight-1) * (TICRATE/4));
|
||||
|
||||
if (gametype == GT_BATTLE)
|
||||
if (gametyperules & GTR_CLOSERPLAYERS)
|
||||
leniency *= 4;
|
||||
|
||||
ang = mo->player->drawangle;
|
||||
|
|
@ -6183,17 +6217,48 @@ void K_DropHnextList(player_t *player, boolean keepshields)
|
|||
}
|
||||
}
|
||||
|
||||
SINT8 K_GetTotallyRandomResult(UINT8 useodds)
|
||||
{
|
||||
itemroulette_t rouletteData = {0};
|
||||
INT32 spawnchance[NUMKARTRESULTS];
|
||||
INT32 totalspawnchance = 0;
|
||||
INT32 i;
|
||||
|
||||
memset(spawnchance, 0, sizeof (spawnchance));
|
||||
|
||||
K_FillItemRouletteData(NULL, &rouletteData);
|
||||
|
||||
for (i = 1; i < NUMKARTRESULTS; i++)
|
||||
{
|
||||
spawnchance[i] = (
|
||||
totalspawnchance += K_KartGetItemOdds(NULL, &rouletteData, useodds, i)
|
||||
);
|
||||
}
|
||||
|
||||
if (totalspawnchance > 0)
|
||||
{
|
||||
totalspawnchance = P_RandomKey(PR_ITEM_ROULETTE, totalspawnchance);
|
||||
for (i = 0; i < NUMKARTRESULTS && spawnchance[i] <= totalspawnchance; i++);
|
||||
}
|
||||
else
|
||||
{
|
||||
i = KITEM_SAD;
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
mobj_t *K_CreatePaperItem(fixed_t x, fixed_t y, fixed_t z, angle_t angle, SINT8 flip, UINT8 type, UINT8 amount)
|
||||
{
|
||||
mobj_t *drop = P_SpawnMobj(x, y, z, MT_FLOATINGITEM);
|
||||
mobj_t *backdrop = P_SpawnMobjFromMobj(drop, 0, 0, 0, MT_OVERLAY);
|
||||
|
||||
|
||||
P_SetTarget(&backdrop->target, drop);
|
||||
P_SetMobjState(backdrop, S_ITEMBACKDROP);
|
||||
|
||||
P_SetScale(drop, drop->scale>>4);
|
||||
drop->destscale = (3*drop->destscale)/2;
|
||||
|
||||
|
||||
drop->angle = angle;
|
||||
P_Thrust(drop,
|
||||
FixedAngle(P_RandomFixed(PR_ITEM_ROULETTE) * 180) + angle,
|
||||
|
|
@ -6205,62 +6270,31 @@ mobj_t *K_CreatePaperItem(fixed_t x, fixed_t y, fixed_t z, angle_t angle, SINT8
|
|||
|
||||
if (type == 0)
|
||||
{
|
||||
itemroulette_t rouletteData = {0};
|
||||
UINT8 useodds = 0;
|
||||
INT32 spawnchance[NUMKARTRESULTS];
|
||||
INT32 totalspawnchance = 0;
|
||||
INT32 i;
|
||||
const SINT8 i = K_GetTotallyRandomResult(amount);
|
||||
|
||||
memset(spawnchance, 0, sizeof (spawnchance));
|
||||
// TODO: this is bad!
|
||||
// K_KartGetItemResult requires a player
|
||||
// but item roulette will need rewritten to change this
|
||||
|
||||
useodds = amount;
|
||||
const SINT8 newType = K_ItemResultToType(i);
|
||||
const UINT8 newAmount = K_ItemResultToAmount(i);
|
||||
|
||||
K_FillItemRouletteData(NULL, &rouletteData);
|
||||
|
||||
for (i = 1; i < NUMKARTRESULTS; i++)
|
||||
if (newAmount > 1)
|
||||
{
|
||||
spawnchance[i] = (
|
||||
totalspawnchance += K_KartGetItemOdds(NULL, &rouletteData, useodds, i)
|
||||
);
|
||||
}
|
||||
UINT8 j;
|
||||
|
||||
if (totalspawnchance > 0)
|
||||
{
|
||||
UINT8 newType;
|
||||
UINT8 newAmount;
|
||||
|
||||
totalspawnchance = P_RandomKey(PR_ITEM_ROULETTE, totalspawnchance);
|
||||
for (i = 0; i < NUMKARTRESULTS && spawnchance[i] <= totalspawnchance; i++);
|
||||
|
||||
// TODO: this is bad!
|
||||
// K_KartGetItemResult requires a player
|
||||
// but item roulette will need rewritten to change this
|
||||
|
||||
newType = K_ItemResultToType(i);
|
||||
newAmount = K_ItemResultToAmount(i);
|
||||
|
||||
if (newAmount > 1)
|
||||
for (j = 0; j < newAmount-1; j++)
|
||||
{
|
||||
UINT8 j;
|
||||
|
||||
for (j = 0; j < newAmount-1; j++)
|
||||
{
|
||||
K_CreatePaperItem(
|
||||
x, y, z,
|
||||
angle, flip,
|
||||
newType, 1
|
||||
);
|
||||
}
|
||||
K_CreatePaperItem(
|
||||
x, y, z,
|
||||
angle, flip,
|
||||
newType, 1
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
drop->threshold = newType;
|
||||
drop->movecount = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
drop->threshold = 1;
|
||||
drop->movecount = 1;
|
||||
}
|
||||
drop->threshold = newType;
|
||||
drop->movecount = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -6273,6 +6307,11 @@ mobj_t *K_CreatePaperItem(fixed_t x, fixed_t y, fixed_t z, angle_t angle, SINT8
|
|||
P_SetTarget(&backdrop->tracer, drop);
|
||||
backdrop->flags2 |= MF2_LINKDRAW;
|
||||
|
||||
if (gametyperules & GTR_BUMPERS)
|
||||
{
|
||||
drop->fuse = BATTLE_DESPAWN_TIME;
|
||||
}
|
||||
|
||||
return drop;
|
||||
}
|
||||
|
||||
|
|
@ -6793,10 +6832,10 @@ mobj_t *K_FindJawzTarget(mobj_t *actor, player_t *source, angle_t range)
|
|||
mobj_t *wtarg = NULL;
|
||||
INT32 i;
|
||||
|
||||
if (specialStage.active == true)
|
||||
if (specialstageinfo.valid == true)
|
||||
{
|
||||
// Always target the UFO.
|
||||
return specialStage.ufo;
|
||||
// Always target the UFO (but not the emerald)
|
||||
return K_GetPossibleSpecialTarget();
|
||||
}
|
||||
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
|
|
@ -7472,7 +7511,7 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
|
|||
K_SpawnGrowShrinkParticles(player->mo, player->growshrinktimer);
|
||||
}
|
||||
|
||||
if (gametype == GT_RACE && player->rings <= 0) // spawn ring debt indicator
|
||||
if (!(gametyperules & GTR_SPHERES) && player->rings <= 0) // spawn ring debt indicator
|
||||
{
|
||||
mobj_t *debtflag = P_SpawnMobj(player->mo->x + player->mo->momx, player->mo->y + player->mo->momy,
|
||||
player->mo->z + P_GetMobjZMovement(player->mo) + player->mo->height + (24*player->mo->scale), MT_THOK);
|
||||
|
|
@ -7538,8 +7577,6 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
|
|||
//CONS_Printf("cam: %d, dest: %d\n", player->karthud[khud_boostcam], player->karthud[khud_destboostcam]);
|
||||
}
|
||||
|
||||
player->karthud[khud_timeovercam] = 0;
|
||||
|
||||
// Make ABSOLUTELY SURE that your flashing tics don't get set WHILE you're still in hit animations.
|
||||
if (player->spinouttimer != 0 || player->wipeoutslow != 0)
|
||||
{
|
||||
|
|
@ -7790,7 +7827,7 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
|
|||
|
||||
if (player->eggmanexplode)
|
||||
{
|
||||
if (player->spectator || (gametype == GT_BATTLE && !player->bumpers))
|
||||
if (player->spectator || ((gametyperules & GTR_BUMPERS) && player->bumpers <= 0))
|
||||
player->eggmanexplode = 0;
|
||||
else
|
||||
{
|
||||
|
|
@ -8032,10 +8069,11 @@ void K_KartPlayerAfterThink(player_t *player)
|
|||
|
||||
mobj_t *ret = NULL;
|
||||
|
||||
if (specialStage.active == true && lastTargID == MAXPLAYERS)
|
||||
if (specialstageinfo.valid == true
|
||||
&& lastTargID == MAXPLAYERS)
|
||||
{
|
||||
// Aiming at the UFO.
|
||||
lastTarg = specialStage.ufo;
|
||||
// Aiming at the UFO (but never the emerald).
|
||||
lastTarg = K_GetPossibleSpecialTarget();
|
||||
}
|
||||
else if ((lastTargID >= 0 && lastTargID <= MAXPLAYERS)
|
||||
&& playeringame[lastTargID] == true)
|
||||
|
|
@ -9332,15 +9370,18 @@ static INT32 K_FlameShieldMax(player_t *player)
|
|||
UINT8 numplayers = 0;
|
||||
UINT8 i;
|
||||
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
if (gametyperules & GTR_CIRCUIT)
|
||||
{
|
||||
if (playeringame[i] && !players[i].spectator)
|
||||
numplayers++;
|
||||
if (players[i].position == 1)
|
||||
disttofinish = players[i].distancetofinish;
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
if (playeringame[i] && !players[i].spectator)
|
||||
numplayers++;
|
||||
if (players[i].position == 1)
|
||||
disttofinish = players[i].distancetofinish;
|
||||
}
|
||||
}
|
||||
|
||||
if (numplayers <= 1 || gametype == GT_BATTLE)
|
||||
if (numplayers <= 1)
|
||||
{
|
||||
return 16; // max when alone, for testing
|
||||
// and when in battle, for chaos
|
||||
|
|
@ -9594,8 +9635,7 @@ static void K_KartSpindash(player_t *player)
|
|||
{
|
||||
fixed_t thrust = FixedMul(player->mo->scale, player->spindash*FRACUNIT/5);
|
||||
|
||||
// TODO: gametyperules
|
||||
if (gametype == GT_BATTLE)
|
||||
if (gametyperules & GTR_CLOSERPLAYERS)
|
||||
thrust *= 2;
|
||||
|
||||
// Give a bit of a boost depending on charge.
|
||||
|
|
@ -10402,8 +10442,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
|
|||
player->mo->destscale = FixedMul(player->mo->destscale, SHRINK_SCALE);
|
||||
}
|
||||
|
||||
// TODO: gametyperules
|
||||
player->growshrinktimer = max(player->growshrinktimer, (gametype == GT_BATTLE ? 8 : 12) * TICRATE);
|
||||
player->growshrinktimer = max(player->growshrinktimer, ((gametyperules & GTR_CLOSERPLAYERS) ? 8 : 12) * TICRATE);
|
||||
|
||||
if (player->invincibilitytimer > 0)
|
||||
{
|
||||
|
|
@ -10561,8 +10600,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
|
|||
|
||||
if ((cmd->buttons & BT_ATTACK) && (player->pflags & PF_HOLDREADY))
|
||||
{
|
||||
// TODO: gametyperules
|
||||
const INT32 incr = gametype == GT_BATTLE ? 4 : 2;
|
||||
const INT32 incr = (gametyperules & GTR_CLOSERPLAYERS) ? 4 : 2;
|
||||
|
||||
if (player->flamedash == 0)
|
||||
{
|
||||
|
|
@ -10598,8 +10636,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
|
|||
{
|
||||
player->pflags |= PF_HOLDREADY;
|
||||
|
||||
// TODO: gametyperules
|
||||
if (gametype != GT_BATTLE || leveltime % 6 == 0)
|
||||
if (!(gametyperules & GTR_CLOSERPLAYERS) || leveltime % 6 == 0)
|
||||
{
|
||||
if (player->flamemeter > 0)
|
||||
player->flamemeter--;
|
||||
|
|
@ -10721,18 +10758,13 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
|
|||
|
||||
if (player->hyudorotimer > 0)
|
||||
{
|
||||
INT32 hyu = hyudorotime;
|
||||
|
||||
if (gametype == GT_RACE)
|
||||
hyu *= 2; // double in race
|
||||
|
||||
if (leveltime & 1)
|
||||
{
|
||||
player->mo->renderflags |= RF_DONTDRAW;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (player->hyudorotimer >= (TICRATE/2) && player->hyudorotimer <= hyu-(TICRATE/2))
|
||||
if (player->hyudorotimer >= (TICRATE/2) && player->hyudorotimer <= hyudorotime-(TICRATE/2))
|
||||
player->mo->renderflags &= ~K_GetPlayerDontDrawFlag(player);
|
||||
else
|
||||
player->mo->renderflags &= ~RF_DONTDRAW;
|
||||
|
|
@ -10745,17 +10777,17 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
|
|||
player->mo->renderflags &= ~RF_DONTDRAW;
|
||||
}
|
||||
|
||||
if (gametype == GT_BATTLE && player->bumpers <= 0) // dead in match? you da bomb
|
||||
if (!(gametyperules & GTR_BUMPERS) || player->bumpers > 0)
|
||||
{
|
||||
player->mo->renderflags &= ~(RF_TRANSMASK|RF_BRIGHTMASK);
|
||||
}
|
||||
else // dead in match? you da bomb
|
||||
{
|
||||
K_DropItems(player); //K_StripItems(player);
|
||||
K_StripOther(player);
|
||||
player->mo->renderflags |= RF_GHOSTLY;
|
||||
player->flashing = player->karmadelay;
|
||||
}
|
||||
else if (gametype == GT_RACE || player->bumpers > 0)
|
||||
{
|
||||
player->mo->renderflags &= ~(RF_TRANSMASK|RF_BRIGHTMASK);
|
||||
}
|
||||
|
||||
if (player->trickpanel == 1)
|
||||
{
|
||||
|
|
@ -10968,7 +11000,7 @@ void K_CheckSpectateStatus(void)
|
|||
continue;
|
||||
if (leveltime > (starttime + 20*TICRATE)) // DON'T allow if the match is 20 seconds in
|
||||
return;
|
||||
if (gametype == GT_RACE && players[i].laps >= 2) // DON'T allow if the race is at 2 laps
|
||||
if ((gametyperules & GTR_CIRCUIT) && players[i].laps >= 2) // DON'T allow if the race is at 2 laps
|
||||
return;
|
||||
continue;
|
||||
}
|
||||
|
|
@ -11164,4 +11196,27 @@ void K_HandleDirectionalInfluence(player_t *player)
|
|||
player->mo->momy = FixedMul(speed, finalY);
|
||||
}
|
||||
|
||||
void K_UpdateMobjItemOverlay(mobj_t *part, SINT8 itemType, UINT8 itemCount)
|
||||
{
|
||||
switch (itemType)
|
||||
{
|
||||
case KITEM_ORBINAUT:
|
||||
part->sprite = SPR_ITMO;
|
||||
part->frame = FF_FULLBRIGHT|FF_PAPERSPRITE|K_GetOrbinautItemFrame(itemCount);
|
||||
break;
|
||||
case KITEM_INVINCIBILITY:
|
||||
part->sprite = SPR_ITMI;
|
||||
part->frame = FF_FULLBRIGHT|FF_PAPERSPRITE|K_GetInvincibilityItemFrame();
|
||||
break;
|
||||
case KITEM_SAD:
|
||||
part->sprite = SPR_ITEM;
|
||||
part->frame = FF_FULLBRIGHT|FF_PAPERSPRITE;
|
||||
break;
|
||||
default:
|
||||
part->sprite = SPR_ITEM;
|
||||
part->frame = FF_FULLBRIGHT|FF_PAPERSPRITE|(itemType);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//}
|
||||
|
|
|
|||
|
|
@ -138,6 +138,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);
|
||||
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);
|
||||
void K_DropRocketSneaker(player_t *player);
|
||||
|
|
@ -197,6 +198,8 @@ fixed_t K_ItemScaleForPlayer(player_t *player);
|
|||
void K_SetItemOut(player_t *player);
|
||||
void K_UnsetItemOut(player_t *player);
|
||||
|
||||
void K_UpdateMobjItemOverlay(mobj_t *part, SINT8 itemType, UINT8 itemCount);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
|
|
|||
13
src/k_menu.h
13
src/k_menu.h
|
|
@ -119,7 +119,11 @@ struct menucolor_t {
|
|||
|
||||
extern menucolor_t *menucolorhead, *menucolortail;
|
||||
|
||||
extern CV_PossibleValue_t gametype_cons_t[];
|
||||
extern INT16 menugametype;
|
||||
void M_NextMenuGametype(UINT32 forbidden);
|
||||
void M_PrevMenuGametype(UINT32 forbidden);
|
||||
void M_HandleHostMenuGametype(INT32 choice);
|
||||
void M_HandlePauseMenuGametype(INT32 choice);
|
||||
|
||||
//
|
||||
// MENU TYPEDEFS
|
||||
|
|
@ -417,6 +421,7 @@ extern menu_t MISC_StatisticsDef;
|
|||
typedef enum
|
||||
{
|
||||
mpause_addons = 0,
|
||||
mpause_changegametype,
|
||||
mpause_switchmap,
|
||||
mpause_restartmap,
|
||||
mpause_tryagain,
|
||||
|
|
@ -435,9 +440,6 @@ typedef enum
|
|||
mpause_title,
|
||||
} mpause_e;
|
||||
|
||||
extern menuitem_t PAUSE_GamemodesMenu[];
|
||||
extern menu_t PAUSE_GamemodesDef;
|
||||
|
||||
extern menuitem_t PAUSE_PlaybackMenu[];
|
||||
extern menu_t PAUSE_PlaybackMenuDef;
|
||||
|
||||
|
|
@ -696,7 +698,6 @@ extern struct cupgrid_s {
|
|||
size_t cappages;
|
||||
tic_t previewanim;
|
||||
boolean grandprix; // Setup grand prix server after picking
|
||||
boolean netgame; // Start the game in an actual server
|
||||
} cupgrid;
|
||||
|
||||
typedef struct levelsearch_s {
|
||||
|
|
@ -713,6 +714,7 @@ extern struct levellist_s {
|
|||
UINT16 dest;
|
||||
INT16 choosemap;
|
||||
UINT8 newgametype;
|
||||
UINT8 guessgt;
|
||||
levelsearch_t levelsearch;
|
||||
boolean netgame; // Start the game in an actual server
|
||||
} levellist;
|
||||
|
|
@ -773,7 +775,6 @@ void M_MPOptSelect(INT32 choice);
|
|||
void M_MPOptSelectInit(INT32 choice);
|
||||
void M_MPOptSelectTick(void);
|
||||
boolean M_MPResetOpts(void);
|
||||
extern consvar_t cv_dummygametype; // lazy hack to allow us to select the GT on the server host submenu
|
||||
extern consvar_t cv_dummyip; // I HAVE
|
||||
// HAVE YOUR IP ADDRESS (This just the hack Cvar we'll type into and then it apends itself to "connect" in the console for IP join)
|
||||
|
||||
|
|
|
|||
|
|
@ -89,12 +89,15 @@ menuitem_t PLAY_GamemodesMenu[] =
|
|||
{IT_STRING | IT_CALL, "Race", "A contest to see who's the fastest of them all!",
|
||||
NULL, {.routine = M_SetupRaceMenu}, 0, 0},
|
||||
|
||||
{IT_STRING | IT_CALL, "Battle", "It's last hedgehog standing in this free-for-all!",
|
||||
{IT_STRING | IT_CALL, "Battle", "It's last kart standing in this free-for-all!",
|
||||
"MENIMG00", {.routine = M_LevelSelectInit}, 0, GT_BATTLE},
|
||||
|
||||
{IT_STRING | IT_CALL, "Capsules", "Bust up all of the capsules in record time!",
|
||||
NULL, {.routine = M_LevelSelectInit}, 1, GT_BATTLE},
|
||||
|
||||
{IT_STRING | IT_CALL, "Special", "Strike your target and secure the prize!",
|
||||
NULL, {.routine = M_LevelSelectInit}, 1, GT_SPECIAL},
|
||||
|
||||
{IT_STRING | IT_CALL, "Back", NULL, NULL, {.routine = M_GoBack}, 0, 0},
|
||||
};
|
||||
|
||||
|
|
@ -359,8 +362,8 @@ menuitem_t PLAY_MP_Host[] =
|
|||
{IT_STRING | IT_CVAR, "Max. Players", "Set how many players can play at once. Others will spectate.",
|
||||
NULL, {.cvar = &cv_maxplayers}, 0, 0},
|
||||
|
||||
{IT_STRING | IT_CVAR, "Gamemode", "Are we racing? Or perhaps battling?",
|
||||
NULL, {.cvar = &cv_dummygametype}, 0, 0},
|
||||
{IT_STRING | IT_KEYHANDLER, "Gamemode", "Choose the type of play on your server.",
|
||||
NULL, {.routine = M_HandleHostMenuGametype}, 0, 0},
|
||||
|
||||
{IT_STRING | IT_CALL, "GO", "Select a map with the currently selected gamemode",
|
||||
NULL, {.routine = M_MPSetupNetgameMapSelect}, 0, 0},
|
||||
|
|
@ -1132,9 +1135,6 @@ menuitem_t OPTIONS_Server[] =
|
|||
{IT_STRING | IT_CVAR, "Vote Timer", "Set how long players have to vote.",
|
||||
NULL, {.cvar = &cv_votetime}, 0, 0},
|
||||
|
||||
{IT_STRING | IT_CVAR, "Vote Mode Change", "Set how often voting proposes a different gamemode.",
|
||||
NULL, {.cvar = &cv_kartvoterulechanges}, 0, 0},
|
||||
|
||||
|
||||
{IT_SPACE | IT_NOTHING, NULL, NULL,
|
||||
NULL, {NULL}, 0, 0},
|
||||
|
|
@ -1593,8 +1593,11 @@ menuitem_t PAUSE_Main[] =
|
|||
{IT_STRING | IT_CALL, "ADDONS", "M_ICOADD",
|
||||
NULL, {.routine = M_Addons}, 0, 0},
|
||||
|
||||
{IT_STRING | IT_SUBMENU, "CHANGE MAP", "M_ICOMAP",
|
||||
NULL, {.submenu = &PAUSE_GamemodesDef}, 0, 0},
|
||||
{IT_STRING | IT_KEYHANDLER, "GAMETYPE", "M_ICOGAM",
|
||||
NULL, {.routine = M_HandlePauseMenuGametype}, 0, 0},
|
||||
|
||||
{IT_STRING | IT_CALL, "CHANGE MAP", "M_ICOMAP",
|
||||
NULL, {.routine = M_LevelSelectInit}, 0, -1},
|
||||
|
||||
{IT_STRING | IT_CALL, "RESTART MAP", "M_ICORE",
|
||||
NULL, {.routine = M_RestartMap}, 0, 0},
|
||||
|
|
@ -1647,20 +1650,6 @@ menu_t PAUSE_MainDef = {
|
|||
M_PauseInputs
|
||||
};
|
||||
|
||||
// PAUSE : Map switching gametype selection (In case you want to pick from battle / race...)
|
||||
menuitem_t PAUSE_GamemodesMenu[] =
|
||||
{
|
||||
{IT_STRING | IT_CALL, "Race", "Select which gamemode to choose a new map from.",
|
||||
NULL, {.routine = M_LevelSelectInit}, 0, GT_RACE},
|
||||
|
||||
{IT_STRING | IT_CALL, "Battle", "Select which gamemode to choose a new map from.",
|
||||
NULL, {.routine = M_LevelSelectInit}, 0, GT_BATTLE},
|
||||
|
||||
{IT_STRING | IT_CALL, "Back", NULL, NULL, {.routine = M_GoBack}, 0, 0},
|
||||
};
|
||||
|
||||
menu_t PAUSE_GamemodesDef = KARTGAMEMODEMENU(PAUSE_GamemodesMenu, &PAUSE_MainDef);
|
||||
|
||||
// Replay popup menu
|
||||
menuitem_t PAUSE_PlaybackMenu[] =
|
||||
{
|
||||
|
|
|
|||
197
src/k_menudraw.c
197
src/k_menudraw.c
|
|
@ -541,12 +541,7 @@ void M_Drawer(void)
|
|||
}
|
||||
else
|
||||
{
|
||||
#ifdef DEVELOP // Development -- show revision / branch info
|
||||
V_DrawThinString(vid.dupx, vid.height - 20*vid.dupy, V_NOSCALESTART|V_TRANSLUCENT|V_ALLOWLOWERCASE, compbranch);
|
||||
V_DrawThinString(vid.dupx, vid.height - 10*vid.dupy, V_NOSCALESTART|V_TRANSLUCENT|V_ALLOWLOWERCASE, comprevision);
|
||||
#else // Regular build
|
||||
V_DrawThinString(vid.dupx, vid.height - 10*vid.dupy, V_NOSCALESTART|V_TRANSLUCENT|V_ALLOWLOWERCASE, va("%s", VERSIONSTRING));
|
||||
#endif
|
||||
F_VersionDrawer();
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -1933,7 +1928,7 @@ static void M_DrawCupPreview(INT16 y, levelsearch_t *levelsearch)
|
|||
|
||||
V_DrawFill(0, y, BASEVIDWIDTH, 54, 31);
|
||||
|
||||
if (levelsearch->cup && !M_CupLocked(levelsearch->cup))
|
||||
if (levelsearch->cup && maxlevels > 0)
|
||||
{
|
||||
add = (cupgrid.previewanim / 82) % maxlevels;
|
||||
map = start;
|
||||
|
|
@ -1979,16 +1974,18 @@ static void M_DrawCupPreview(INT16 y, levelsearch_t *levelsearch)
|
|||
}
|
||||
}
|
||||
|
||||
static void M_DrawCupTitle(INT16 y, cupheader_t *cup)
|
||||
static void M_DrawCupTitle(INT16 y, levelsearch_t *levelsearch)
|
||||
{
|
||||
UINT8 temp = 0;
|
||||
|
||||
V_DrawScaledPatch(0, y, 0, W_CachePatchName("MENUHINT", PU_CACHE));
|
||||
|
||||
if (cup)
|
||||
if (levelsearch->cup)
|
||||
{
|
||||
boolean unlocked = !M_CupLocked(cup);
|
||||
boolean unlocked = (M_GetFirstLevelInList(&temp, levelsearch) != NEXTMAP_INVALID);
|
||||
UINT8 *colormap = R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_GREY, GTC_MENUCACHE);
|
||||
patch_t *icon = W_CachePatchName(cup->icon, PU_CACHE);
|
||||
const char *str = (unlocked ? va("%s Cup", cup->name) : "???");
|
||||
patch_t *icon = W_CachePatchName(levelsearch->cup->icon, PU_CACHE);
|
||||
const char *str = (unlocked ? va("%s Cup", levelsearch->cup->name) : "???");
|
||||
INT16 offset = V_LSTitleLowStringWidth(str, 0) / 2;
|
||||
|
||||
V_DrawLSTitleLowString(BASEVIDWIDTH/2 - offset, y+6, 0, str);
|
||||
|
|
@ -2002,32 +1999,35 @@ static void M_DrawCupTitle(INT16 y, cupheader_t *cup)
|
|||
else
|
||||
{
|
||||
if (currentMenu == &PLAY_LevelSelectDef)
|
||||
V_DrawCenteredLSTitleLowString(BASEVIDWIDTH/2, y+6, 0, va("%s Mode", Gametype_Names[levellist.newgametype]));
|
||||
{
|
||||
UINT8 namedgt = (levellist.guessgt != MAXGAMETYPES) ? levellist.guessgt : levellist.newgametype;
|
||||
V_DrawCenteredLSTitleLowString(BASEVIDWIDTH/2, y+6, 0, va("%s Mode", gametypes[namedgt]->name));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void M_DrawCupSelect(void)
|
||||
{
|
||||
UINT8 i, j;
|
||||
UINT8 i, j, temp = 0;
|
||||
levelsearch_t templevelsearch = levellist.levelsearch; // full copy
|
||||
templevelsearch.cup = cupgrid.builtgrid[CUPMENU_CURSORID];
|
||||
|
||||
for (i = 0; i < CUPMENU_COLUMNS; i++)
|
||||
{
|
||||
for (j = 0; j < CUPMENU_ROWS; j++)
|
||||
{
|
||||
size_t id = (i + (j * CUPMENU_COLUMNS)) + (cupgrid.pageno * (CUPMENU_COLUMNS * CUPMENU_ROWS));
|
||||
cupheader_t *iconcup = cupgrid.builtgrid[id];
|
||||
patch_t *patch = NULL;
|
||||
INT16 x, y;
|
||||
INT16 icony = 7;
|
||||
|
||||
if (!iconcup)
|
||||
if (!cupgrid.builtgrid[id])
|
||||
break;
|
||||
|
||||
/*if (iconcup->emeraldnum == 0)
|
||||
templevelsearch.cup = cupgrid.builtgrid[id];
|
||||
|
||||
/*if (templevelsearch.cup->emeraldnum == 0)
|
||||
patch = W_CachePatchName("CUPMON3A", PU_CACHE);
|
||||
else*/ if (iconcup->emeraldnum > 7)
|
||||
else*/ if (templevelsearch.cup->emeraldnum > 7)
|
||||
{
|
||||
patch = W_CachePatchName("CUPMON2A", PU_CACHE);
|
||||
icony = 5;
|
||||
|
|
@ -2040,14 +2040,14 @@ void M_DrawCupSelect(void)
|
|||
|
||||
V_DrawScaledPatch(x, y, 0, patch);
|
||||
|
||||
if (M_CupLocked(iconcup))
|
||||
if (M_GetFirstLevelInList(&temp, &templevelsearch) == NEXTMAP_INVALID)
|
||||
{
|
||||
patch_t *st = W_CachePatchName(va("ICONST0%d", (cupgrid.previewanim % 4) + 1), PU_CACHE);
|
||||
V_DrawScaledPatch(x + 8, y + icony, 0, st);
|
||||
}
|
||||
else
|
||||
{
|
||||
V_DrawScaledPatch(x + 8, y + icony, 0, W_CachePatchName(iconcup->icon, PU_CACHE));
|
||||
V_DrawScaledPatch(x + 8, y + icony, 0, W_CachePatchName(templevelsearch.cup->icon, PU_CACHE));
|
||||
V_DrawScaledPatch(x + 8, y + icony, 0, W_CachePatchName("CUPBOX", PU_CACHE));
|
||||
}
|
||||
}
|
||||
|
|
@ -2058,8 +2058,10 @@ void M_DrawCupSelect(void)
|
|||
0, W_CachePatchName("CUPCURS", PU_CACHE)
|
||||
);
|
||||
|
||||
templevelsearch.cup = cupgrid.builtgrid[CUPMENU_CURSORID];
|
||||
|
||||
M_DrawCupPreview(146 + (24*menutransition.tics), &templevelsearch);
|
||||
M_DrawCupTitle(120 - (24*menutransition.tics), templevelsearch.cup);
|
||||
M_DrawCupTitle(120 - (24*menutransition.tics), &templevelsearch);
|
||||
}
|
||||
|
||||
static void M_DrawHighLowLevelTitle(INT16 x, INT16 y, INT16 map)
|
||||
|
|
@ -2225,7 +2227,7 @@ void M_DrawLevelSelect(void)
|
|||
map = M_GetNextLevelInList(map, &j, &levellist.levelsearch);
|
||||
}
|
||||
|
||||
M_DrawCupTitle(tay, levellist.levelsearch.cup);
|
||||
M_DrawCupTitle(tay, &levellist.levelsearch);
|
||||
}
|
||||
|
||||
void M_DrawTimeAttack(void)
|
||||
|
|
@ -2261,7 +2263,8 @@ void M_DrawTimeAttack(void)
|
|||
laprec = mapheaderinfo[map]->mainrecord->lap;
|
||||
}
|
||||
|
||||
if (levellist.newgametype != GT_BATTLE)
|
||||
if ((gametypes[levellist.newgametype]->rules & GTR_CIRCUIT)
|
||||
&& (mapheaderinfo[map]->numlaps != 1))
|
||||
{
|
||||
V_DrawRightAlignedString(rightedge-12, timeheight, highlightflags, "BEST LAP:");
|
||||
K_drawKartTimestamp(laprec, 162+t, timeheight+6, 0, 2);
|
||||
|
|
@ -2462,6 +2465,20 @@ void M_DrawMPHost(void)
|
|||
}
|
||||
break;
|
||||
}
|
||||
case IT_KEYHANDLER:
|
||||
{
|
||||
if (currentMenu->menuitems[i].itemaction.routine != M_HandleHostMenuGametype)
|
||||
break;
|
||||
|
||||
w = V_ThinStringWidth(gametypes[menugametype]->name, V_6WIDTHSPACE);
|
||||
V_DrawThinString(xp + 138 - w, yp, highlightflags|V_6WIDTHSPACE, gametypes[menugametype]->name);
|
||||
if (i == itemOn)
|
||||
{
|
||||
V_DrawCharacter(xp + 138 - 10 - w - (skullAnimCounter/5), yp, '\x1C' | highlightflags, false); // left arrow
|
||||
V_DrawCharacter(xp + 138 + 2 + (skullAnimCounter/5), yp, '\x1D' | highlightflags, false); // right arrow
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
xp += 5;
|
||||
|
|
@ -3680,27 +3697,19 @@ void M_DrawPause(void)
|
|||
case IT_STRING:
|
||||
{
|
||||
patch_t *pp;
|
||||
UINT8 *colormap = NULL;
|
||||
|
||||
if (i == itemOn)
|
||||
if (i == itemOn && (i == mpause_restartmap || i == mpause_tryagain))
|
||||
{
|
||||
if (i == mpause_restartmap || i == mpause_tryagain)
|
||||
{
|
||||
pp = W_CachePatchName(
|
||||
va("M_ICOR2%c", ('A'+(pausemenu.ticker & 1))),
|
||||
PU_CACHE);
|
||||
}
|
||||
else
|
||||
{
|
||||
char iconame[9]; // 8 chars + \0
|
||||
strcpy(iconame, currentMenu->menuitems[i].tooltip);
|
||||
iconame[7] = '2'; // Yes this is a stupid hack. Replace the last character with a 2 when we're selecting this graphic.
|
||||
|
||||
pp = W_CachePatchName(iconame, PU_CACHE);
|
||||
}
|
||||
pp = W_CachePatchName(
|
||||
va("M_ICOR2%c", ('A'+(pausemenu.ticker & 1))),
|
||||
PU_CACHE);
|
||||
}
|
||||
else
|
||||
{
|
||||
pp = W_CachePatchName(currentMenu->menuitems[i].tooltip, PU_CACHE);
|
||||
if (i == itemOn)
|
||||
colormap = yellowmap;
|
||||
}
|
||||
|
||||
// 294 - 261 = 33
|
||||
|
|
@ -3711,7 +3720,7 @@ void M_DrawPause(void)
|
|||
// This double ternary is awful, yes.
|
||||
|
||||
dypos = ypos + pausemenu.offset;
|
||||
V_DrawFixedPatch( ((i == itemOn ? (294 - pausemenu.offset*2/3 * (dypos > 100 ? 1 : -1)) : 261) + offset) << FRACBITS, (dypos)*FRACUNIT, FRACUNIT, 0, pp, NULL);
|
||||
V_DrawFixedPatch( ((i == itemOn ? (294 - pausemenu.offset*2/3 * (dypos > 100 ? 1 : -1)) : 261) + offset) << FRACBITS, (dypos)*FRACUNIT, FRACUNIT, 0, pp, colormap);
|
||||
|
||||
ypos += 50;
|
||||
itemsdrawn++; // We drew that!
|
||||
|
|
@ -3760,12 +3769,26 @@ void M_DrawPause(void)
|
|||
word1[word1len] = '\0';
|
||||
word2[word2len] = '\0';
|
||||
|
||||
// If there's no 2nd word, take this opportunity to center this line of text.
|
||||
if (word1len)
|
||||
V_DrawCenteredLSTitleHighString(220 + offset*2, 75 + (!word2len ? 10 : 0), 0, word1);
|
||||
if (itemOn == mpause_changegametype)
|
||||
{
|
||||
INT32 w = V_LSTitleLowStringWidth(gametypes[menugametype]->name, 0)/2;
|
||||
|
||||
if (word2len)
|
||||
V_DrawCenteredLSTitleLowString(220 + offset*2, 103, 0, word2);
|
||||
if (word1len)
|
||||
V_DrawCenteredLSTitleHighString(220 + offset*2, 75, 0, word1);
|
||||
|
||||
V_DrawLSTitleLowString(220-w + offset*2, 103, V_YELLOWMAP, gametypes[menugametype]->name);
|
||||
V_DrawCharacter(220-w + offset*2 - 8 - (skullAnimCounter/5), 103+6, '\x1C' | V_YELLOWMAP, false); // left arrow
|
||||
V_DrawCharacter(220+w + offset*2 + 4 + (skullAnimCounter/5), 103+6, '\x1D' | V_YELLOWMAP, false); // right arrow
|
||||
}
|
||||
else
|
||||
{
|
||||
// If there's no 2nd word, take this opportunity to center this line of text.
|
||||
if (word1len)
|
||||
V_DrawCenteredLSTitleHighString(220 + offset*2, 75 + (!word2len ? 10 : 0), 0, word1);
|
||||
|
||||
if (word2len)
|
||||
V_DrawCenteredLSTitleLowString(220 + offset*2, 103, 0, word2);
|
||||
}
|
||||
}
|
||||
|
||||
tic_t playback_last_menu_interaction_leveltime = 0;
|
||||
|
|
@ -3964,9 +3987,22 @@ static void M_DrawReplayHutReplayInfo(menudemo_t *demoref)
|
|||
if (demoref->numlaps)
|
||||
V_DrawThinString(x, y+9, V_SNAPTOTOP|V_ALLOWLOWERCASE, va("(%d laps)", demoref->numlaps));
|
||||
|
||||
V_DrawString(x, y+20, V_SNAPTOTOP|V_ALLOWLOWERCASE, demoref->gametype == GT_RACE ?
|
||||
va("Race (%s speed)", kartspeed_cons_t[(demoref->kartspeed & ~DF_ENCORE) + 1].strvalue) :
|
||||
"Battle Mode");
|
||||
{
|
||||
const char *gtstring;
|
||||
if (demoref->gametype < 0)
|
||||
{
|
||||
gtstring = "Custom (not loaded)";
|
||||
}
|
||||
else
|
||||
{
|
||||
gtstring = gametypes[demoref->gametype]->name;
|
||||
|
||||
if ((gametypes[demoref->gametype]->rules & GTR_CIRCUIT))
|
||||
gtstring = va("%s (%s)", gtstring, kartspeed_cons_t[(demoref->kartspeed & ~DF_ENCORE) + 1].strvalue);
|
||||
}
|
||||
|
||||
V_DrawString(x, y+20, V_SNAPTOTOP|V_ALLOWLOWERCASE, gtstring);
|
||||
}
|
||||
|
||||
if (!demoref->standings[0].ranking)
|
||||
{
|
||||
|
|
@ -3979,30 +4015,33 @@ static void M_DrawReplayHutReplayInfo(menudemo_t *demoref)
|
|||
V_DrawThinString(x, y+29, V_SNAPTOTOP|highlightflags, "WINNER");
|
||||
V_DrawString(x+38, y+30, V_SNAPTOTOP|V_ALLOWLOWERCASE, demoref->standings[0].name);
|
||||
|
||||
if (demoref->gametype == GT_RACE)
|
||||
if (demoref->gametype >= 0)
|
||||
{
|
||||
V_DrawThinString(x, y+39, V_SNAPTOTOP|highlightflags, "TIME");
|
||||
}
|
||||
else
|
||||
{
|
||||
V_DrawThinString(x, y+39, V_SNAPTOTOP|highlightflags, "SCORE");
|
||||
}
|
||||
if (gametypes[demoref->gametype]->rules & GTR_POINTLIMIT)
|
||||
{
|
||||
V_DrawThinString(x, y+39, V_SNAPTOTOP|highlightflags, "SCORE");
|
||||
}
|
||||
else
|
||||
{
|
||||
V_DrawThinString(x, y+39, V_SNAPTOTOP|highlightflags, "TIME");
|
||||
}
|
||||
|
||||
if (demoref->standings[0].timeorscore == (UINT32_MAX-1))
|
||||
{
|
||||
V_DrawThinString(x+32, y+39, V_SNAPTOTOP, "NO CONTEST");
|
||||
}
|
||||
else if (demoref->gametype == GT_RACE)
|
||||
{
|
||||
V_DrawRightAlignedString(x+84, y+40, V_SNAPTOTOP, va("%d'%02d\"%02d",
|
||||
G_TicsToMinutes(demoref->standings[0].timeorscore, true),
|
||||
G_TicsToSeconds(demoref->standings[0].timeorscore),
|
||||
G_TicsToCentiseconds(demoref->standings[0].timeorscore)
|
||||
));
|
||||
}
|
||||
else
|
||||
{
|
||||
V_DrawString(x+32, y+40, V_SNAPTOTOP, va("%d", demoref->standings[0].timeorscore));
|
||||
if (demoref->standings[0].timeorscore == (UINT32_MAX-1))
|
||||
{
|
||||
V_DrawThinString(x+32, y+39, V_SNAPTOTOP, "NO CONTEST");
|
||||
}
|
||||
else if (gametypes[demoref->gametype]->rules & GTR_POINTLIMIT)
|
||||
{
|
||||
V_DrawString(x+32, y+40, V_SNAPTOTOP, va("%d", demoref->standings[0].timeorscore));
|
||||
}
|
||||
else
|
||||
{
|
||||
V_DrawRightAlignedString(x+84, y+40, V_SNAPTOTOP, va("%d'%02d\"%02d",
|
||||
G_TicsToMinutes(demoref->standings[0].timeorscore, true),
|
||||
G_TicsToSeconds(demoref->standings[0].timeorscore),
|
||||
G_TicsToCentiseconds(demoref->standings[0].timeorscore)
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
// Character face!
|
||||
|
|
@ -4197,14 +4236,16 @@ void M_DrawReplayStartMenu(void)
|
|||
|
||||
if (demoref->standings[i].timeorscore == UINT32_MAX-1)
|
||||
V_DrawThinString(BASEVIDWIDTH-92, STARTY + i*20 + 9, V_SNAPTOTOP, "NO CONTEST");
|
||||
else if (demoref->gametype == GT_RACE)
|
||||
else if (demoref->gametype < 0)
|
||||
;
|
||||
else if (gametypes[demoref->gametype]->rules & GTR_POINTLIMIT)
|
||||
V_DrawString(BASEVIDWIDTH-92, STARTY + i*20 + 9, V_SNAPTOTOP, va("%d", demoref->standings[i].timeorscore));
|
||||
else
|
||||
V_DrawRightAlignedString(BASEVIDWIDTH-40, STARTY + i*20 + 9, V_SNAPTOTOP, va("%d'%02d\"%02d",
|
||||
G_TicsToMinutes(demoref->standings[i].timeorscore, true),
|
||||
G_TicsToSeconds(demoref->standings[i].timeorscore),
|
||||
G_TicsToCentiseconds(demoref->standings[i].timeorscore)
|
||||
));
|
||||
else
|
||||
V_DrawString(BASEVIDWIDTH-92, STARTY + i*20 + 9, V_SNAPTOTOP, va("%d", demoref->standings[i].timeorscore));
|
||||
|
||||
// Character face!
|
||||
|
||||
|
|
@ -4692,6 +4733,16 @@ static void M_DrawChallengePreview(INT32 x, INT32 y)
|
|||
specialmap = btcmapcache;
|
||||
break;
|
||||
}
|
||||
case SECRET_SPECIALATTACK:
|
||||
{
|
||||
static UINT16 sscmapcache = NEXTMAP_INVALID;
|
||||
if (sscmapcache > nummapheaders)
|
||||
{
|
||||
sscmapcache = G_RandMap(G_TOLFlag(GT_SPECIAL), -1, 2, 0, false, NULL);
|
||||
}
|
||||
specialmap = sscmapcache;
|
||||
break;
|
||||
}
|
||||
case SECRET_HARDSPEED:
|
||||
{
|
||||
static UINT16 hardmapcache = NEXTMAP_INVALID;
|
||||
|
|
|
|||
527
src/k_menufunc.c
527
src/k_menufunc.c
|
|
@ -147,10 +147,6 @@ consvar_t cv_menujam_update = CVAR_INIT ("menujam_update", "Off", CV_SAVE, CV_On
|
|||
static CV_PossibleValue_t menujam_cons_t[] = {{0, "menu"}, {1, "menu2"}, {2, "menu3"}, {0, NULL}};
|
||||
static consvar_t cv_menujam = CVAR_INIT ("menujam", "0", CV_SAVE, menujam_cons_t, NULL);
|
||||
|
||||
// This gametype list is integral for many different reasons.
|
||||
// When you add gametypes here, don't forget to update them in dehacked.c and doomstat.h!
|
||||
CV_PossibleValue_t gametype_cons_t[NUMGAMETYPES+1];
|
||||
|
||||
static CV_PossibleValue_t serversort_cons_t[] = {
|
||||
{0,"Ping"},
|
||||
{1,"AVG. Power Level"},
|
||||
|
|
@ -189,18 +185,18 @@ static CV_PossibleValue_t dummyteam_cons_t[] = {{0, "Spectator"}, {1, "Red"}, {2
|
|||
static CV_PossibleValue_t dummyspectate_cons_t[] = {{0, "Spectator"}, {1, "Playing"}, {0, NULL}};
|
||||
static CV_PossibleValue_t dummyscramble_cons_t[] = {{0, "Random"}, {1, "Points"}, {0, NULL}};
|
||||
static CV_PossibleValue_t dummystaff_cons_t[] = {{0, "MIN"}, {100, "MAX"}, {0, NULL}};
|
||||
static CV_PossibleValue_t dummygametype_cons_t[] = {{0, "Race"}, {1, "Battle"}, {0, NULL}};
|
||||
|
||||
//static consvar_t cv_dummymenuplayer = CVAR_INIT ("dummymenuplayer", "P1", CV_HIDDEN|CV_CALL, dummymenuplayer_cons_t, Dummymenuplayer_OnChange);
|
||||
static consvar_t cv_dummyteam = CVAR_INIT ("dummyteam", "Spectator", CV_HIDDEN, dummyteam_cons_t, NULL);
|
||||
//static cv_dummyspectate = CVAR_INITconsvar_t ("dummyspectate", "Spectator", CV_HIDDEN, dummyspectate_cons_t, NULL);
|
||||
static consvar_t cv_dummyscramble = CVAR_INIT ("dummyscramble", "Random", CV_HIDDEN, dummyscramble_cons_t, NULL);
|
||||
static consvar_t cv_dummystaff = CVAR_INIT ("dummystaff", "0", CV_HIDDEN|CV_CALL, dummystaff_cons_t, Dummystaff_OnChange);
|
||||
consvar_t cv_dummygametype = CVAR_INIT ("dummygametype", "Race", CV_HIDDEN, dummygametype_cons_t, NULL);
|
||||
consvar_t cv_dummyip = CVAR_INIT ("dummyip", "", CV_HIDDEN, NULL, NULL);
|
||||
consvar_t cv_dummymenuplayer = CVAR_INIT ("dummymenuplayer", "P1", CV_HIDDEN|CV_CALL, dummymenuplayer_cons_t, Dummymenuplayer_OnChange);
|
||||
consvar_t cv_dummyspectate = CVAR_INIT ("dummyspectate", "Spectator", CV_HIDDEN, dummyspectate_cons_t, NULL);
|
||||
|
||||
INT16 menugametype = GT_RACE;
|
||||
|
||||
consvar_t cv_dummyprofilename = CVAR_INIT ("dummyprofilename", "", CV_HIDDEN, NULL, NULL);
|
||||
consvar_t cv_dummyprofileplayername = CVAR_INIT ("dummyprofileplayername", "", CV_HIDDEN, NULL, NULL);
|
||||
consvar_t cv_dummyprofilekickstart = CVAR_INIT ("dummyprofilekickstart", "Off", CV_HIDDEN, CV_OnOff, NULL);
|
||||
|
|
@ -1009,6 +1005,8 @@ void M_ClearMenus(boolean callexitmenufunc)
|
|||
if (!menuactive)
|
||||
return;
|
||||
|
||||
CON_ClearHUD();
|
||||
|
||||
if (currentMenu->quitroutine && callexitmenufunc && !currentMenu->quitroutine())
|
||||
return; // we can't quit this menu (also used to set parameter from the menu)
|
||||
|
||||
|
|
@ -1713,7 +1711,6 @@ void M_Init(void)
|
|||
CV_RegisterVar(&cv_dummyspectate);
|
||||
CV_RegisterVar(&cv_dummyscramble);
|
||||
CV_RegisterVar(&cv_dummystaff);
|
||||
CV_RegisterVar(&cv_dummygametype);
|
||||
CV_RegisterVar(&cv_dummyip);
|
||||
|
||||
CV_RegisterVar(&cv_dummyprofilename);
|
||||
|
|
@ -3295,25 +3292,40 @@ void M_SetupGametypeMenu(INT32 choice)
|
|||
|
||||
PLAY_GamemodesDef.prevMenu = currentMenu;
|
||||
|
||||
// Battle and Capsules disabled
|
||||
// Battle and Capsules (and Special) disabled
|
||||
PLAY_GamemodesMenu[1].status = IT_DISABLED;
|
||||
PLAY_GamemodesMenu[2].status = IT_DISABLED;
|
||||
PLAY_GamemodesMenu[3].status = IT_DISABLED;
|
||||
|
||||
if (cv_splitplayers.value > 1)
|
||||
{
|
||||
// Re-add Battle
|
||||
PLAY_GamemodesMenu[1].status = IT_STRING | IT_CALL;
|
||||
}
|
||||
else if (M_SecretUnlocked(SECRET_BREAKTHECAPSULES, true))
|
||||
{
|
||||
// Re-add Capsules
|
||||
PLAY_GamemodesMenu[2].status = IT_STRING | IT_CALL;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Only one non-Back entry, let's skip straight to Race.
|
||||
M_SetupRaceMenu(-1);
|
||||
return;
|
||||
boolean anyunlocked = false;
|
||||
|
||||
if (M_SecretUnlocked(SECRET_BREAKTHECAPSULES, true))
|
||||
{
|
||||
// Re-add Capsules
|
||||
PLAY_GamemodesMenu[2].status = IT_STRING | IT_CALL;
|
||||
anyunlocked = true;
|
||||
}
|
||||
|
||||
if (M_SecretUnlocked(SECRET_SPECIALATTACK, true))
|
||||
{
|
||||
// Re-add Special
|
||||
PLAY_GamemodesMenu[3].status = IT_STRING | IT_CALL;
|
||||
anyunlocked = true;
|
||||
}
|
||||
|
||||
if (!anyunlocked)
|
||||
{
|
||||
// Only one non-Back entry, let's skip straight to Race.
|
||||
M_SetupRaceMenu(-1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
M_SetupNextMenu(&PLAY_GamemodesDef, false);
|
||||
|
|
@ -3406,9 +3418,6 @@ boolean M_CanShowLevelInList(INT16 mapnum, levelsearch_t *levelsearch)
|
|||
if (mapheaderinfo[mapnum]->lumpnum == LUMPERROR)
|
||||
return false;
|
||||
|
||||
if (levelsearch->checklocked && M_MapLocked(mapnum+1))
|
||||
return false; // not unlocked
|
||||
|
||||
// Check for TOL
|
||||
if (!(mapheaderinfo[mapnum]->typeoflevel & levelsearch->typeoflevel))
|
||||
return false;
|
||||
|
|
@ -3427,6 +3436,19 @@ boolean M_CanShowLevelInList(INT16 mapnum, levelsearch_t *levelsearch)
|
|||
&& mapheaderinfo[mapnum]->cup != levelsearch->cup)
|
||||
return false;
|
||||
|
||||
// Finally, the most complex check: does the map have lock conditions?
|
||||
if (levelsearch->checklocked)
|
||||
{
|
||||
// Check for completion
|
||||
if ((mapheaderinfo[mapnum]->menuflags & LF2_FINISHNEEDED)
|
||||
&& !(mapheaderinfo[mapnum]->mapvisited & MV_BEATEN))
|
||||
return false;
|
||||
|
||||
// Check for unlock
|
||||
if (M_MapLocked(mapnum+1))
|
||||
return false;
|
||||
}
|
||||
|
||||
// Survived our checks.
|
||||
return true;
|
||||
}
|
||||
|
|
@ -3440,6 +3462,9 @@ UINT16 M_CountLevelsToShowInList(levelsearch_t *levelsearch)
|
|||
|
||||
if (levelsearch->cup)
|
||||
{
|
||||
if (levelsearch->checklocked && M_CupLocked(levelsearch->cup))
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < CUPCACHE_MAX; i++)
|
||||
{
|
||||
if (!M_CanShowLevelInList(levelsearch->cup->cachedlevels[i], levelsearch))
|
||||
|
|
@ -3466,6 +3491,12 @@ UINT16 M_GetFirstLevelInList(UINT8 *i, levelsearch_t *levelsearch)
|
|||
|
||||
if (levelsearch->cup)
|
||||
{
|
||||
if (levelsearch->checklocked && M_CupLocked(levelsearch->cup))
|
||||
{
|
||||
*i = CUPCACHE_MAX;
|
||||
return NEXTMAP_INVALID;
|
||||
}
|
||||
|
||||
*i = 0;
|
||||
mapnum = NEXTMAP_INVALID;
|
||||
for (; *i < CUPCACHE_MAX; (*i)++)
|
||||
|
|
@ -3530,20 +3561,39 @@ static void M_LevelSelectScrollDest(void)
|
|||
}
|
||||
|
||||
// Builds the level list we'll be using from the gametype we're choosing and send us to the apropriate menu.
|
||||
static void M_LevelListFromGametype(INT16 gt)
|
||||
static boolean M_LevelListFromGametype(INT16 gt)
|
||||
{
|
||||
static boolean first = true;
|
||||
if (first || gt != levellist.newgametype)
|
||||
UINT8 temp = 0;
|
||||
|
||||
if (first || gt != levellist.newgametype || levellist.guessgt != MAXGAMETYPES)
|
||||
{
|
||||
if (first)
|
||||
{
|
||||
cupgrid.cappages = 0;
|
||||
cupgrid.builtgrid = NULL;
|
||||
}
|
||||
|
||||
levellist.newgametype = gt;
|
||||
|
||||
levellist.levelsearch.typeoflevel = G_TOLFlag(gt);
|
||||
levellist.levelsearch.cupmode = (!(gametypedefaultrules[gt] & GTR_NOCUPSELECT));
|
||||
if (levellist.levelsearch.timeattack == true && gt == GT_SPECIAL)
|
||||
{
|
||||
// Sneak in an extra.
|
||||
levellist.levelsearch.typeoflevel |= G_TOLFlag(GT_VERSUS);
|
||||
levellist.guessgt = gt;
|
||||
}
|
||||
else
|
||||
{
|
||||
levellist.guessgt = MAXGAMETYPES;
|
||||
}
|
||||
|
||||
levellist.levelsearch.cupmode = (!(gametypes[gt]->rules & GTR_NOCUPSELECT));
|
||||
levellist.levelsearch.cup = NULL;
|
||||
|
||||
first = false;
|
||||
}
|
||||
|
||||
PLAY_CupSelectDef.prevMenu = currentMenu;
|
||||
|
||||
// Obviously go to Cup Select in gametypes that have cups.
|
||||
// Use a really long level select in gametypes that don't use cups.
|
||||
|
||||
|
|
@ -3551,32 +3601,35 @@ static void M_LevelListFromGametype(INT16 gt)
|
|||
{
|
||||
levelsearch_t templevelsearch = levellist.levelsearch; // full copy
|
||||
size_t currentid = 0, highestunlockedid = 0;
|
||||
const size_t unitlen = sizeof(cupheader_t*) * (CUPMENU_COLUMNS * CUPMENU_ROWS);
|
||||
const size_t pagelen = sizeof(cupheader_t*) * (CUPMENU_COLUMNS * CUPMENU_ROWS);
|
||||
boolean foundany = false;
|
||||
|
||||
templevelsearch.cup = kartcupheaders;
|
||||
templevelsearch.checklocked = false;
|
||||
|
||||
// Make sure there's valid cups before going to this menu.
|
||||
#if 0
|
||||
// Make sure there's valid cups before going to this menu. -- rip sweet prince
|
||||
if (templevelsearch.cup == NULL)
|
||||
I_Error("Can you really call this a racing game, I didn't recieve any Cups on my pillow or anything");
|
||||
#endif
|
||||
|
||||
if (!cupgrid.builtgrid)
|
||||
if (cupgrid.cappages == 0)
|
||||
{
|
||||
cupgrid.cappages = 2;
|
||||
cupgrid.builtgrid = Z_Calloc(
|
||||
cupgrid.cappages * unitlen,
|
||||
cupgrid.cappages * pagelen,
|
||||
PU_STATIC,
|
||||
cupgrid.builtgrid);
|
||||
NULL);
|
||||
|
||||
if (!cupgrid.builtgrid)
|
||||
{
|
||||
I_Error("M_LevelListFromGametype: Not enough memory to allocate builtgrid");
|
||||
}
|
||||
}
|
||||
memset(cupgrid.builtgrid, 0, cupgrid.cappages * unitlen);
|
||||
memset(cupgrid.builtgrid, 0, cupgrid.cappages * pagelen);
|
||||
|
||||
while (templevelsearch.cup)
|
||||
{
|
||||
templevelsearch.checklocked = false;
|
||||
if (!M_CountLevelsToShowInList(&templevelsearch))
|
||||
{
|
||||
// No valid maps, skip.
|
||||
|
|
@ -3584,10 +3637,12 @@ static void M_LevelListFromGametype(INT16 gt)
|
|||
continue;
|
||||
}
|
||||
|
||||
if ((currentid * sizeof(cupheader_t*)) >= cupgrid.cappages * unitlen)
|
||||
foundany = true;
|
||||
|
||||
if ((currentid * sizeof(cupheader_t*)) >= cupgrid.cappages * pagelen)
|
||||
{
|
||||
// Double the size of the buffer, and clear the other stuff.
|
||||
const size_t firstlen = cupgrid.cappages * unitlen;
|
||||
const size_t firstlen = cupgrid.cappages * pagelen;
|
||||
cupgrid.builtgrid = Z_Realloc(cupgrid.builtgrid,
|
||||
firstlen * 2,
|
||||
PU_STATIC, NULL);
|
||||
|
|
@ -3603,7 +3658,8 @@ static void M_LevelListFromGametype(INT16 gt)
|
|||
|
||||
cupgrid.builtgrid[currentid] = templevelsearch.cup;
|
||||
|
||||
if (!M_CupLocked(templevelsearch.cup))
|
||||
templevelsearch.checklocked = true;
|
||||
if (M_GetFirstLevelInList(&temp, &templevelsearch) != NEXTMAP_INVALID)
|
||||
{
|
||||
highestunlockedid = currentid;
|
||||
if (Playing() && mapheaderinfo[gamemap-1] && mapheaderinfo[gamemap-1]->cup == templevelsearch.cup)
|
||||
|
|
@ -3618,16 +3674,29 @@ static void M_LevelListFromGametype(INT16 gt)
|
|||
templevelsearch.cup = templevelsearch.cup->next;
|
||||
}
|
||||
|
||||
if (foundany == false)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
cupgrid.numpages = (highestunlockedid / (CUPMENU_COLUMNS * CUPMENU_ROWS)) + 1;
|
||||
if (cupgrid.pageno >= cupgrid.numpages)
|
||||
{
|
||||
cupgrid.pageno = 0;
|
||||
}
|
||||
|
||||
PLAY_CupSelectDef.prevMenu = currentMenu;
|
||||
PLAY_LevelSelectDef.prevMenu = &PLAY_CupSelectDef;
|
||||
M_SetupNextMenu(&PLAY_CupSelectDef, false);
|
||||
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Okay, just a list of maps then.
|
||||
|
||||
if (M_GetFirstLevelInList(&temp, &levellist.levelsearch) == NEXTMAP_INVALID)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Reset position properly if you go back & forth between gametypes
|
||||
|
|
@ -3643,6 +3712,7 @@ static void M_LevelListFromGametype(INT16 gt)
|
|||
PLAY_LevelSelectDef.prevMenu = currentMenu;
|
||||
M_SetupNextMenu(&PLAY_LevelSelectDef, false);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Init level select for use in local play using the last choice we made.
|
||||
|
|
@ -3651,10 +3721,11 @@ static void M_LevelListFromGametype(INT16 gt)
|
|||
|
||||
void M_LevelSelectInit(INT32 choice)
|
||||
{
|
||||
INT32 gt = currentMenu->menuitems[itemOn].mvar2;
|
||||
|
||||
(void)choice;
|
||||
|
||||
// Make sure this is reset as we'll only be using this function for offline games!
|
||||
cupgrid.netgame = false;
|
||||
levellist.netgame = false;
|
||||
levellist.levelsearch.checklocked = true;
|
||||
|
||||
|
|
@ -3677,7 +3748,111 @@ void M_LevelSelectInit(INT32 choice)
|
|||
return;
|
||||
}
|
||||
|
||||
M_LevelListFromGametype(currentMenu->menuitems[itemOn].mvar2);
|
||||
if (gt == -1)
|
||||
{
|
||||
gt = menugametype;
|
||||
}
|
||||
|
||||
if (!M_LevelListFromGametype(gt))
|
||||
{
|
||||
S_StartSound(NULL, sfx_s3kb2);
|
||||
M_StartMessage(va("No levels available for\n%s Mode!\n\nPress (B)\n", gametypes[gt]->name), NULL, MM_NOTHING);
|
||||
}
|
||||
}
|
||||
|
||||
static void M_LevelSelected(INT16 add)
|
||||
{
|
||||
UINT8 i = 0;
|
||||
INT16 map = M_GetFirstLevelInList(&i, &levellist.levelsearch);
|
||||
|
||||
while (add > 0)
|
||||
{
|
||||
map = M_GetNextLevelInList(map, &i, &levellist.levelsearch);
|
||||
|
||||
if (map >= nummapheaders)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
add--;
|
||||
}
|
||||
|
||||
if (map >= nummapheaders)
|
||||
{
|
||||
// This shouldn't happen
|
||||
return;
|
||||
}
|
||||
|
||||
levellist.choosemap = map;
|
||||
|
||||
if (levellist.levelsearch.timeattack)
|
||||
{
|
||||
S_StartSound(NULL, sfx_s3k63);
|
||||
|
||||
if (levellist.guessgt != MAXGAMETYPES)
|
||||
levellist.newgametype = G_GuessGametypeByTOL(levellist.levelsearch.typeoflevel);
|
||||
|
||||
PLAY_TimeAttackDef.lastOn = ta_start;
|
||||
PLAY_TimeAttackDef.prevMenu = currentMenu;
|
||||
M_SetupNextMenu(&PLAY_TimeAttackDef, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (gamestate == GS_MENU)
|
||||
{
|
||||
UINT8 ssplayers = cv_splitplayers.value-1;
|
||||
|
||||
netgame = false;
|
||||
multiplayer = true;
|
||||
|
||||
strncpy(connectedservername, cv_servername.string, MAXSERVERNAME);
|
||||
|
||||
// Still need to reset devmode
|
||||
cht_debug = 0;
|
||||
|
||||
if (demo.playback)
|
||||
G_StopDemo();
|
||||
if (metalrecording)
|
||||
G_StopMetalDemo();
|
||||
|
||||
/*if (levellist.choosemap == 0)
|
||||
levellist.choosemap = G_RandMap(G_TOLFlag(levellist.newgametype), -1, 0, 0, false, NULL);*/
|
||||
|
||||
if (cv_maxconnections.value < ssplayers+1)
|
||||
CV_SetValue(&cv_maxconnections, ssplayers+1);
|
||||
|
||||
if (splitscreen != ssplayers)
|
||||
{
|
||||
splitscreen = ssplayers;
|
||||
SplitScreen_OnChange();
|
||||
}
|
||||
|
||||
S_StartSound(NULL, sfx_s3k63);
|
||||
|
||||
paused = false;
|
||||
|
||||
// Early fadeout to let the sound finish playing
|
||||
F_WipeStartScreen();
|
||||
V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 31);
|
||||
F_WipeEndScreen();
|
||||
F_RunWipe(wipedefs[wipe_level_toblack], false, "FADEMAP0", false, false);
|
||||
|
||||
SV_StartSinglePlayerServer(levellist.newgametype, levellist.netgame);
|
||||
|
||||
CV_StealthSet(&cv_kartbot, cv_dummymatchbots.string);
|
||||
CV_StealthSet(&cv_kartencore, (cv_dummygpencore.value == 1) ? "On" : "Auto");
|
||||
CV_StealthSet(&cv_kartspeed, (cv_dummykartspeed.value == KARTSPEED_NORMAL) ? "Auto" : cv_dummykartspeed.string);
|
||||
|
||||
D_MapChange(levellist.choosemap+1, levellist.newgametype, (cv_kartencore.value == 1), 1, 1, false, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
// directly do the map change
|
||||
D_MapChange(levellist.choosemap+1, levellist.newgametype, (cv_kartencore.value == 1), 1, 1, false, false);
|
||||
}
|
||||
|
||||
M_ClearMenus(true);
|
||||
}
|
||||
}
|
||||
|
||||
void M_CupSelectHandler(INT32 choice)
|
||||
|
|
@ -3733,13 +3908,18 @@ void M_CupSelectHandler(INT32 choice)
|
|||
|
||||
if (M_MenuConfirmPressed(pid) /*|| M_MenuButtonPressed(pid, MBT_START)*/)
|
||||
{
|
||||
INT16 count;
|
||||
cupheader_t *newcup = cupgrid.builtgrid[CUPMENU_CURSORID];
|
||||
cupheader_t *oldcup = levellist.levelsearch.cup;
|
||||
|
||||
M_SetMenuDelay(pid);
|
||||
|
||||
levellist.levelsearch.cup = newcup;
|
||||
count = M_CountLevelsToShowInList(&levellist.levelsearch);
|
||||
|
||||
if ((!newcup)
|
||||
|| (M_CupLocked(newcup))
|
||||
|| (newcup->cachedlevels[0] == NEXTMAP_INVALID))
|
||||
|| (count <= 0)
|
||||
|| (cupgrid.grandprix == true && newcup->cachedlevels[0] == NEXTMAP_INVALID))
|
||||
{
|
||||
S_StartSound(NULL, sfx_s3kb2);
|
||||
return;
|
||||
|
|
@ -3803,13 +3983,17 @@ void M_CupSelectHandler(INT32 choice)
|
|||
|
||||
M_ClearMenus(true);
|
||||
}
|
||||
else if (count == 1)
|
||||
{
|
||||
PLAY_TimeAttackDef.transitionID = currentMenu->transitionID+1;
|
||||
M_LevelSelected(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Keep cursor position if you select the same cup again, reset if it's a different cup
|
||||
if (levellist.levelsearch.cup != newcup)
|
||||
if (oldcup != newcup || levellist.cursor >= count)
|
||||
{
|
||||
levellist.cursor = 0;
|
||||
levellist.levelsearch.cup = newcup;
|
||||
}
|
||||
|
||||
M_LevelSelectScrollDest();
|
||||
|
|
@ -3868,94 +4052,10 @@ void M_LevelSelectHandler(INT32 choice)
|
|||
|
||||
if (M_MenuConfirmPressed(pid) /*|| M_MenuButtonPressed(pid, MBT_START)*/)
|
||||
{
|
||||
UINT8 i = 0;
|
||||
INT16 map = M_GetFirstLevelInList(&i, &levellist.levelsearch);
|
||||
INT16 add = levellist.cursor;
|
||||
|
||||
M_SetMenuDelay(pid);
|
||||
|
||||
while (add > 0)
|
||||
{
|
||||
map = M_GetNextLevelInList(map, &i, &levellist.levelsearch);
|
||||
|
||||
if (map >= nummapheaders)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
add--;
|
||||
}
|
||||
|
||||
if (map >= nummapheaders)
|
||||
{
|
||||
// This shouldn't happen
|
||||
return;
|
||||
}
|
||||
|
||||
levellist.choosemap = map;
|
||||
|
||||
if (levellist.levelsearch.timeattack)
|
||||
{
|
||||
M_SetupNextMenu(&PLAY_TimeAttackDef, false);
|
||||
S_StartSound(NULL, sfx_s3k63);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (gamestate == GS_MENU)
|
||||
{
|
||||
UINT8 ssplayers = cv_splitplayers.value-1;
|
||||
|
||||
netgame = false;
|
||||
multiplayer = true;
|
||||
|
||||
strncpy(connectedservername, cv_servername.string, MAXSERVERNAME);
|
||||
|
||||
// Still need to reset devmode
|
||||
cht_debug = 0;
|
||||
|
||||
if (demo.playback)
|
||||
G_StopDemo();
|
||||
if (metalrecording)
|
||||
G_StopMetalDemo();
|
||||
|
||||
/*if (levellist.choosemap == 0)
|
||||
levellist.choosemap = G_RandMap(G_TOLFlag(levellist.newgametype), -1, 0, 0, false, NULL);*/
|
||||
|
||||
if (cv_maxconnections.value < ssplayers+1)
|
||||
CV_SetValue(&cv_maxconnections, ssplayers+1);
|
||||
|
||||
if (splitscreen != ssplayers)
|
||||
{
|
||||
splitscreen = ssplayers;
|
||||
SplitScreen_OnChange();
|
||||
}
|
||||
|
||||
S_StartSound(NULL, sfx_s3k63);
|
||||
|
||||
paused = false;
|
||||
|
||||
// Early fadeout to let the sound finish playing
|
||||
F_WipeStartScreen();
|
||||
V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 31);
|
||||
F_WipeEndScreen();
|
||||
F_RunWipe(wipedefs[wipe_level_toblack], false, "FADEMAP0", false, false);
|
||||
|
||||
SV_StartSinglePlayerServer(levellist.newgametype, levellist.netgame);
|
||||
|
||||
CV_StealthSet(&cv_kartbot, cv_dummymatchbots.string);
|
||||
CV_StealthSet(&cv_kartencore, (cv_dummygpencore.value == 1) ? "On" : "Auto");
|
||||
CV_StealthSet(&cv_kartspeed, (cv_dummykartspeed.value == KARTSPEED_NORMAL) ? "Auto" : cv_dummykartspeed.string);
|
||||
|
||||
D_MapChange(levellist.choosemap+1, levellist.newgametype, (cv_kartencore.value == 1), 1, 1, false, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
// directly do the map change
|
||||
D_MapChange(levellist.choosemap+1, levellist.newgametype, (cv_kartencore.value == 1), 1, 1, false, false);
|
||||
}
|
||||
|
||||
M_ClearMenus(true);
|
||||
}
|
||||
PLAY_TimeAttackDef.transitionID = currentMenu->transitionID;
|
||||
M_LevelSelected(levellist.cursor);
|
||||
}
|
||||
else if (M_MenuBackPressed(pid))
|
||||
{
|
||||
|
|
@ -4006,14 +4106,12 @@ void M_StartTimeAttack(INT32 choice)
|
|||
|
||||
(void)choice;
|
||||
|
||||
switch (levellist.newgametype)
|
||||
modeattacking = ATTACKING_TIME;
|
||||
|
||||
if ((gametypes[levellist.newgametype]->rules & GTR_CIRCUIT)
|
||||
&& (mapheaderinfo[levellist.choosemap]->numlaps != 1))
|
||||
{
|
||||
case GT_BATTLE:
|
||||
modeattacking = ATTACKING_CAPSULES;
|
||||
break;
|
||||
default:
|
||||
modeattacking = ATTACKING_TIME;
|
||||
break;
|
||||
modeattacking |= ATTACKING_LAP;
|
||||
}
|
||||
|
||||
// Still need to reset devmode
|
||||
|
|
@ -4078,6 +4176,7 @@ void M_MPOptSelectInit(INT32 choice)
|
|||
{
|
||||
INT16 arrcpy[3][3] = {{0,68,0}, {0,12,0}, {0,74,0}};
|
||||
UINT8 i = 0, j = 0; // To copy the array into the struct
|
||||
const UINT32 forbidden = GTR_FORBIDMP;
|
||||
|
||||
(void)choice;
|
||||
|
||||
|
|
@ -4088,6 +4187,10 @@ void M_MPOptSelectInit(INT32 choice)
|
|||
for (j = 0; j < 3; j++)
|
||||
mpmenu.modewinextend[i][j] = arrcpy[i][j]; // I miss Lua already
|
||||
|
||||
// Guarantee menugametype is good
|
||||
M_NextMenuGametype(forbidden);
|
||||
M_PrevMenuGametype(forbidden);
|
||||
|
||||
M_SetupNextMenu(&PLAY_MP_OptSelectDef, false);
|
||||
}
|
||||
|
||||
|
|
@ -4119,41 +4222,93 @@ void M_MPHostInit(INT32 choice)
|
|||
itemOn = mhost_go;
|
||||
}
|
||||
|
||||
void M_NextMenuGametype(UINT32 forbidden)
|
||||
{
|
||||
const INT16 currentmenugametype = menugametype;
|
||||
do
|
||||
{
|
||||
menugametype++;
|
||||
if (menugametype >= numgametypes)
|
||||
menugametype = 0;
|
||||
|
||||
if (!(gametypes[menugametype]->rules & forbidden))
|
||||
break;
|
||||
} while (menugametype != currentmenugametype);
|
||||
}
|
||||
|
||||
void M_PrevMenuGametype(UINT32 forbidden)
|
||||
{
|
||||
const INT16 currentmenugametype = menugametype;
|
||||
do
|
||||
{
|
||||
if (menugametype == 0)
|
||||
menugametype = numgametypes;
|
||||
menugametype--;
|
||||
|
||||
if (!(gametypes[menugametype]->rules & forbidden))
|
||||
break;
|
||||
} while (menugametype != currentmenugametype);
|
||||
}
|
||||
|
||||
void M_HandleHostMenuGametype(INT32 choice)
|
||||
{
|
||||
const UINT8 pid = 0;
|
||||
const UINT32 forbidden = GTR_FORBIDMP;
|
||||
|
||||
(void)choice;
|
||||
|
||||
if (M_MenuBackPressed(pid))
|
||||
{
|
||||
M_GoBack(0);
|
||||
M_SetMenuDelay(pid);
|
||||
return;
|
||||
}
|
||||
else if (menucmd[pid].dpad_lr > 0 || M_MenuConfirmPressed(pid))
|
||||
{
|
||||
M_NextMenuGametype(forbidden);
|
||||
S_StartSound(NULL, sfx_s3k5b);
|
||||
M_SetMenuDelay(pid);
|
||||
}
|
||||
else if (menucmd[pid].dpad_lr < 0)
|
||||
{
|
||||
M_PrevMenuGametype(forbidden);
|
||||
S_StartSound(NULL, sfx_s3k5b);
|
||||
M_SetMenuDelay(pid);
|
||||
}
|
||||
|
||||
if (menucmd[pid].dpad_ud > 0)
|
||||
{
|
||||
M_NextOpt();
|
||||
S_StartSound(NULL, sfx_s3k5b);
|
||||
M_SetMenuDelay(pid);
|
||||
}
|
||||
else if (menucmd[pid].dpad_ud < 0)
|
||||
{
|
||||
M_PrevOpt();
|
||||
S_StartSound(NULL, sfx_s3k5b);
|
||||
M_SetMenuDelay(pid);
|
||||
}
|
||||
}
|
||||
|
||||
void M_MPSetupNetgameMapSelect(INT32 choice)
|
||||
{
|
||||
|
||||
INT16 gt = GT_RACE;
|
||||
(void)choice;
|
||||
|
||||
// Yep, we'll be starting a netgame.
|
||||
levellist.netgame = true;
|
||||
cupgrid.netgame = true;
|
||||
// Make sure we reset those
|
||||
levellist.levelsearch.timeattack = false;
|
||||
levellist.levelsearch.checklocked = true;
|
||||
cupgrid.grandprix = false;
|
||||
|
||||
// In case we ever want to add new gamemodes there somehow, have at it!
|
||||
switch (cv_dummygametype.value)
|
||||
{
|
||||
case 1: // Battle
|
||||
{
|
||||
gt = GT_BATTLE;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
gt = GT_RACE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// okay this is REALLY stupid but this fixes the host menu re-folding on itself when we go back.
|
||||
mpmenu.modewinextend[0][0] = 1;
|
||||
|
||||
M_LevelListFromGametype(gt); // Setup the level select.
|
||||
// (This will also automatically send us to the apropriate menu)
|
||||
if (!M_LevelListFromGametype(menugametype))
|
||||
{
|
||||
S_StartSound(NULL, sfx_s3kb2);
|
||||
M_StartMessage(va("No levels available for\n%s Mode!\n\nPress (B)\n", gametypes[menugametype]->name), NULL, MM_NOTHING);
|
||||
}
|
||||
}
|
||||
|
||||
// MULTIPLAYER JOIN BY IP
|
||||
|
|
@ -6063,6 +6218,7 @@ void M_OpenPauseMenu(void)
|
|||
// By default, disable anything sensitive:
|
||||
|
||||
PAUSE_Main[mpause_addons].status = IT_DISABLED;
|
||||
PAUSE_Main[mpause_changegametype].status = IT_DISABLED;
|
||||
PAUSE_Main[mpause_switchmap].status = IT_DISABLED;
|
||||
PAUSE_Main[mpause_restartmap].status = IT_DISABLED;
|
||||
PAUSE_Main[mpause_tryagain].status = IT_DISABLED;
|
||||
|
|
@ -6084,14 +6240,10 @@ void M_OpenPauseMenu(void)
|
|||
|
||||
if (server || IsPlayerAdmin(consoleplayer))
|
||||
{
|
||||
PAUSE_Main[mpause_switchmap].status = IT_STRING | IT_SUBMENU;
|
||||
for (i = 0; i < PAUSE_GamemodesDef.numitems; i++)
|
||||
{
|
||||
if (PAUSE_GamemodesMenu[i].mvar2 != gametype)
|
||||
continue;
|
||||
PAUSE_GamemodesDef.lastOn = i;
|
||||
break;
|
||||
}
|
||||
PAUSE_Main[mpause_changegametype].status = IT_STRING | IT_KEYHANDLER;
|
||||
menugametype = gametype;
|
||||
|
||||
PAUSE_Main[mpause_switchmap].status = IT_STRING | IT_CALL;
|
||||
PAUSE_Main[mpause_restartmap].status = IT_STRING | IT_CALL;
|
||||
PAUSE_Main[mpause_addons].status = IT_STRING | IT_CALL;
|
||||
}
|
||||
|
|
@ -6192,6 +6344,46 @@ boolean M_PauseInputs(INT32 ch)
|
|||
return false;
|
||||
}
|
||||
|
||||
// Change gametype
|
||||
void M_HandlePauseMenuGametype(INT32 choice)
|
||||
{
|
||||
const UINT8 pid = 0;
|
||||
const UINT32 forbidden = GTR_FORBIDMP;
|
||||
|
||||
(void)choice;
|
||||
|
||||
if (M_MenuConfirmPressed(pid))
|
||||
{
|
||||
if (menugametype != gametype)
|
||||
{
|
||||
M_ClearMenus(true);
|
||||
COM_ImmedExecute(va("randommap -gt %s", gametypes[menugametype]->name));
|
||||
return;
|
||||
}
|
||||
|
||||
M_SetMenuDelay(pid);
|
||||
S_StartSound(NULL, sfx_s3k7b);
|
||||
}
|
||||
else if (M_MenuExtraPressed(pid))
|
||||
{
|
||||
menugametype = gametype;
|
||||
M_SetMenuDelay(pid);
|
||||
S_StartSound(NULL, sfx_s3k7b);
|
||||
}
|
||||
else if (menucmd[pid].dpad_lr > 0)
|
||||
{
|
||||
M_NextMenuGametype(forbidden);
|
||||
S_StartSound(NULL, sfx_s3k5b);
|
||||
M_SetMenuDelay(pid);
|
||||
}
|
||||
else if (menucmd[pid].dpad_lr < 0)
|
||||
{
|
||||
M_PrevMenuGametype(forbidden);
|
||||
S_StartSound(NULL, sfx_s3k5b);
|
||||
M_SetMenuDelay(pid);
|
||||
}
|
||||
}
|
||||
|
||||
// Restart map
|
||||
void M_RestartMap(INT32 choice)
|
||||
{
|
||||
|
|
@ -6269,7 +6461,7 @@ void M_EndGame(INT32 choice)
|
|||
if (!Playing())
|
||||
return;
|
||||
|
||||
M_StartMessage(M_GetText("Are you sure you want to return\nto the title screen?\nPress (A) to confirm or (B) to cancel\n"), FUNCPTRCAST(M_ExitGameResponse), MM_YESNO);
|
||||
M_StartMessage(M_GetText("Are you sure you want to\nreturn to the menu?\nPress (A) to confirm or (B) to cancel\n"), FUNCPTRCAST(M_ExitGameResponse), MM_YESNO);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -7546,9 +7738,16 @@ void M_Statistics(INT32 choice)
|
|||
if (!mapheaderinfo[i])
|
||||
continue;
|
||||
|
||||
// Check for no visibility + legacy box
|
||||
if (mapheaderinfo[i]->menuflags & (LF2_NOTIMEATTACK|LF2_HIDEINSTATS|LF2_HIDEINMENU))
|
||||
continue;
|
||||
|
||||
// Check for completion
|
||||
if ((mapheaderinfo[i]->menuflags & LF2_FINISHNEEDED)
|
||||
&& !(mapheaderinfo[i]->mapvisited & MV_BEATEN))
|
||||
continue;
|
||||
|
||||
// Check for unlock
|
||||
if (M_MapLocked(i+1))
|
||||
continue;
|
||||
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ void Obj_DuelBombInit(mobj_t *bomb);
|
|||
|
||||
/* Broly Ki */
|
||||
mobj_t *Obj_SpawnBrolyKi(mobj_t *source, tic_t duration);
|
||||
void Obj_BrolyKiThink(mobj_t *ki);
|
||||
boolean Obj_BrolyKiThink(mobj_t *ki);
|
||||
|
||||
/* Special Stage UFO */
|
||||
waypoint_t *K_GetSpecialUFOWaypoint(mobj_t *ufo);
|
||||
|
|
|
|||
|
|
@ -16,7 +16,6 @@
|
|||
#include "m_cond.h" // M_UpdateUnlockablesAndExtraEmblems
|
||||
#include "p_tick.h" // leveltime
|
||||
#include "k_grandprix.h"
|
||||
#include "k_boss.h"
|
||||
#include "k_profiles.h"
|
||||
|
||||
// Client-sided calculations done for Power Levels.
|
||||
|
|
@ -38,7 +37,7 @@ SINT8 K_UsingPowerLevels(void)
|
|||
{
|
||||
SINT8 pt = PWRLV_DISABLED;
|
||||
|
||||
if (!cv_kartusepwrlv.value || !(netgame || (demo.playback && demo.netgame)) || grandprixinfo.gp == true || bossinfo.boss == true)
|
||||
if (!cv_kartusepwrlv.value || !(netgame || (demo.playback && demo.netgame)) || grandprixinfo.gp == true)
|
||||
{
|
||||
return PWRLV_DISABLED;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -400,7 +400,7 @@ static void K_DrawFinishLineBeamForLine(fixed_t offset, angle_t aiming, line_t *
|
|||
|
||||
void K_RunFinishLineBeam(void)
|
||||
{
|
||||
if (!(leveltime < starttime || rainbowstartavailable == true))
|
||||
if ((gametyperules & GTR_ROLLINGSTART) || !(leveltime < starttime || rainbowstartavailable == true))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -175,14 +175,14 @@ void K_DoIngameRespawn(player_t *player)
|
|||
mapthing_t *beststart = NULL;
|
||||
UINT8 numstarts = 0;
|
||||
|
||||
if (gametype == GT_RACE)
|
||||
{
|
||||
numstarts = numcoopstarts;
|
||||
}
|
||||
else if (gametype == GT_BATTLE)
|
||||
if (gametyperules & GTR_BATTLESTARTS)
|
||||
{
|
||||
numstarts = numdmstarts;
|
||||
}
|
||||
else
|
||||
{
|
||||
numstarts = numcoopstarts;
|
||||
}
|
||||
|
||||
if (numstarts > 0)
|
||||
{
|
||||
|
|
@ -193,17 +193,13 @@ void K_DoIngameRespawn(player_t *player)
|
|||
UINT32 dist = UINT32_MAX;
|
||||
mapthing_t *checkstart = NULL;
|
||||
|
||||
if (gametype == GT_RACE)
|
||||
{
|
||||
checkstart = playerstarts[i];
|
||||
}
|
||||
else if (gametype == GT_BATTLE)
|
||||
if (gametyperules & GTR_BATTLESTARTS)
|
||||
{
|
||||
checkstart = deathmatchstarts[i];
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
checkstart = playerstarts[i];
|
||||
}
|
||||
|
||||
dist = (UINT32)P_AproxDistance((player->mo->x >> FRACBITS) - checkstart->x,
|
||||
|
|
|
|||
|
|
@ -176,6 +176,12 @@ static UINT8 K_KartItemOddsSpecial[NUMKARTRESULTS-1][4] =
|
|||
{ 0, 0, 0, 0 } // Gachabom x3
|
||||
};
|
||||
|
||||
static kartitems_t K_KartItemReelSpecialEnd[] =
|
||||
{
|
||||
KITEM_SUPERRING,
|
||||
KITEM_NONE
|
||||
};
|
||||
|
||||
static kartitems_t K_KartItemReelTimeAttack[] =
|
||||
{
|
||||
KITEM_SNEAKER,
|
||||
|
|
@ -359,7 +365,7 @@ static UINT32 K_GetItemRouletteDistance(const player_t *player, UINT8 numPlayers
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (specialStage.active == true)
|
||||
if (specialstageinfo.valid == true)
|
||||
{
|
||||
UINT32 ufoDis = K_GetSpecialUFODistance();
|
||||
|
||||
|
|
@ -506,7 +512,7 @@ INT32 K_KartGetItemOdds(const player_t *player, itemroulette_t *const roulette,
|
|||
I_Assert(pos < 2); // DO NOT allow positions past the bounds of the table
|
||||
newOdds = K_KartItemOddsBattle[item-1][pos];
|
||||
}
|
||||
else if (specialStage.active == true)
|
||||
else if (specialstageinfo.valid == true)
|
||||
{
|
||||
I_Assert(pos < 4); // Ditto
|
||||
newOdds = K_KartItemOddsSpecial[item-1][pos];
|
||||
|
|
@ -573,7 +579,7 @@ INT32 K_KartGetItemOdds(const player_t *player, itemroulette_t *const roulette,
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (specialStage.active == false)
|
||||
if (specialstageinfo.valid == false)
|
||||
{
|
||||
if (roulette->firstDist < ENDDIST*2 // No SPB when 1st is almost done
|
||||
|| position == 1) // No SPB for 1st ever
|
||||
|
|
@ -705,7 +711,7 @@ static UINT8 K_FindUseodds(const player_t *player, itemroulette_t *const roulett
|
|||
oddsValid[i] = false;
|
||||
continue;
|
||||
}
|
||||
else if (specialStage.active == true && i > 3)
|
||||
else if (specialstageinfo.valid == true && i > 3)
|
||||
{
|
||||
oddsValid[i] = false;
|
||||
continue;
|
||||
|
|
@ -734,7 +740,7 @@ static UINT8 K_FindUseodds(const player_t *player, itemroulette_t *const roulett
|
|||
}
|
||||
else
|
||||
{
|
||||
if (specialStage.active == true) // Special Stages
|
||||
if (specialstageinfo.valid == true) // Special Stages
|
||||
{
|
||||
SETUPDISTTABLE(0,2);
|
||||
SETUPDISTTABLE(1,2);
|
||||
|
|
@ -808,7 +814,7 @@ static boolean K_ForcedSPB(const player_t *player, itemroulette_t *const roulett
|
|||
return false;
|
||||
}
|
||||
|
||||
if (specialStage.active == true)
|
||||
if (specialstageinfo.valid == true)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
|
@ -904,7 +910,7 @@ static void K_InitRoulette(itemroulette_t *const roulette)
|
|||
roulette->exiting++;
|
||||
}
|
||||
|
||||
if (specialStage.active == true)
|
||||
if (specialstageinfo.valid == true)
|
||||
{
|
||||
UINT32 dis = K_UndoMapScaling(players[i].distancetofinish);
|
||||
if (dis < roulette->secondDist)
|
||||
|
|
@ -926,7 +932,7 @@ static void K_InitRoulette(itemroulette_t *const roulette)
|
|||
}
|
||||
}
|
||||
|
||||
if (specialStage.active == true)
|
||||
if (specialstageinfo.valid == true)
|
||||
{
|
||||
roulette->firstDist = K_UndoMapScaling(K_GetSpecialUFODistance());
|
||||
}
|
||||
|
|
@ -1113,8 +1119,19 @@ void K_FillItemRouletteData(const player_t *player, itemroulette_t *const roulet
|
|||
}
|
||||
|
||||
// SPECIAL CASE No. 2:
|
||||
// Use a special, pre-determined item reel for Time Attack / Free Play
|
||||
if (bossinfo.boss == true)
|
||||
// Use a special, pre-determined item reel for Time Attack / Free Play / End of Sealed Stars
|
||||
if (specialstageinfo.valid)
|
||||
{
|
||||
if (K_GetPossibleSpecialTarget() == NULL)
|
||||
{
|
||||
for (i = 0; K_KartItemReelSpecialEnd[i] != KITEM_NONE; i++)
|
||||
{
|
||||
K_PushToRouletteItemList(roulette, K_KartItemReelSpecialEnd[i]);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (gametyperules & GTR_BOSS)
|
||||
{
|
||||
for (i = 0; K_KartItemReelBoss[i] != KITEM_NONE; i++)
|
||||
{
|
||||
|
|
@ -1125,25 +1142,17 @@ void K_FillItemRouletteData(const player_t *player, itemroulette_t *const roulet
|
|||
}
|
||||
else if (K_TimeAttackRules() == true)
|
||||
{
|
||||
switch (gametype)
|
||||
kartitems_t *presetlist = K_KartItemReelTimeAttack;
|
||||
|
||||
// If the objective is not to go fast, it's to cause serious damage.
|
||||
if (gametyperules & GTR_CAPSULES)
|
||||
{
|
||||
case GT_RACE:
|
||||
default:
|
||||
{
|
||||
for (i = 0; K_KartItemReelTimeAttack[i] != KITEM_NONE; i++)
|
||||
{
|
||||
K_PushToRouletteItemList(roulette, K_KartItemReelTimeAttack[i]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case GT_BATTLE:
|
||||
{
|
||||
for (i = 0; K_KartItemReelBreakTheCapsules[i] != KITEM_NONE; i++)
|
||||
{
|
||||
K_PushToRouletteItemList(roulette, K_KartItemReelBreakTheCapsules[i]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
presetlist = K_KartItemReelBreakTheCapsules;
|
||||
}
|
||||
|
||||
for (i = 0; presetlist[i] != KITEM_NONE; i++)
|
||||
{
|
||||
K_PushToRouletteItemList(roulette, presetlist[i]);
|
||||
}
|
||||
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@
|
|||
#include "k_waypoint.h"
|
||||
#include "k_objects.h"
|
||||
|
||||
struct specialStage specialStage;
|
||||
struct specialstageinfo specialstageinfo;
|
||||
|
||||
/*--------------------------------------------------
|
||||
void K_ResetSpecialStage(void)
|
||||
|
|
@ -31,7 +31,8 @@ struct specialStage specialStage;
|
|||
--------------------------------------------------*/
|
||||
void K_ResetSpecialStage(void)
|
||||
{
|
||||
memset(&specialStage, 0, sizeof(struct specialStage));
|
||||
memset(&specialstageinfo, 0, sizeof(struct specialstageinfo));
|
||||
specialstageinfo.beamDist = UINT32_MAX;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
|
|
@ -41,34 +42,15 @@ void K_ResetSpecialStage(void)
|
|||
--------------------------------------------------*/
|
||||
void K_InitSpecialStage(void)
|
||||
{
|
||||
INT32 i;
|
||||
|
||||
specialStage.beamDist = UINT32_MAX; // TODO: make proper value
|
||||
P_SetTarget(&specialStage.ufo, Obj_CreateSpecialUFO());
|
||||
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
if ((gametyperules & (GTR_CATCHER|GTR_CIRCUIT)) != (GTR_CATCHER|GTR_CIRCUIT))
|
||||
{
|
||||
player_t *player = NULL;
|
||||
|
||||
if (playeringame[i] == false)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
player = &players[i];
|
||||
if (player->spectator == true)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (player->mo == NULL || P_MobjWasRemoved(player->mo) == true)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Rolling start? lol
|
||||
P_InstaThrust(player->mo, player->mo->angle, K_GetKartSpeed(player, false, false));
|
||||
return;
|
||||
}
|
||||
|
||||
specialstageinfo.valid = true;
|
||||
|
||||
specialstageinfo.beamDist = UINT32_MAX; // TODO: make proper value
|
||||
P_SetTarget(&specialstageinfo.ufo, Obj_CreateSpecialUFO());
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
|
|
@ -88,15 +70,15 @@ static void K_MoveExitBeam(void)
|
|||
|
||||
moveDist = (8 * mapobjectscale) / FRACUNIT;
|
||||
|
||||
if (specialStage.beamDist <= moveDist)
|
||||
if (specialstageinfo.beamDist <= moveDist)
|
||||
{
|
||||
specialStage.beamDist = 0;
|
||||
specialstageinfo.beamDist = 0;
|
||||
|
||||
// TODO: Fail Special Stage
|
||||
}
|
||||
else
|
||||
{
|
||||
specialStage.beamDist -= moveDist;
|
||||
specialstageinfo.beamDist -= moveDist;
|
||||
}
|
||||
|
||||
// Find players who are now outside of the level.
|
||||
|
|
@ -118,7 +100,7 @@ static void K_MoveExitBeam(void)
|
|||
continue;
|
||||
}
|
||||
|
||||
if (player->distancetofinish > specialStage.beamDist)
|
||||
if (player->distancetofinish > specialstageinfo.beamDist)
|
||||
{
|
||||
P_DoTimeOver(player);
|
||||
}
|
||||
|
|
@ -132,10 +114,30 @@ static void K_MoveExitBeam(void)
|
|||
--------------------------------------------------*/
|
||||
void K_TickSpecialStage(void)
|
||||
{
|
||||
if (specialStage.active == false)
|
||||
if (specialstageinfo.valid == false)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (P_MobjWasRemoved(specialstageinfo.ufo))
|
||||
{
|
||||
P_SetTarget(&specialstageinfo.ufo, NULL);
|
||||
}
|
||||
|
||||
K_MoveExitBeam();
|
||||
}
|
||||
|
||||
mobj_t *K_GetPossibleSpecialTarget(void)
|
||||
{
|
||||
if (specialstageinfo.valid == false)
|
||||
return NULL;
|
||||
|
||||
if (specialstageinfo.ufo == NULL
|
||||
|| P_MobjWasRemoved(specialstageinfo.ufo))
|
||||
return NULL;
|
||||
|
||||
if (specialstageinfo.ufo->health <= 1) //UFOEmeraldChase(specialstageinfo.ufo)
|
||||
return NULL;
|
||||
|
||||
return specialstageinfo.ufo;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,14 +20,13 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern struct specialStage
|
||||
extern struct specialstageinfo
|
||||
{
|
||||
boolean active; ///< If true, then we are in a special stage
|
||||
boolean encore; ///< Copy of encore, just to make sure you can't cheat it with cvars
|
||||
boolean valid; ///< If true, then data in this struct is valid
|
||||
|
||||
UINT32 beamDist; ///< Where the exit beam is.
|
||||
mobj_t *ufo; ///< The Chaos Emerald capsule.
|
||||
} specialStage;
|
||||
} specialstageinfo;
|
||||
|
||||
/*--------------------------------------------------
|
||||
void K_ResetSpecialStage(void);
|
||||
|
|
@ -55,6 +54,18 @@ void K_InitSpecialStage(void);
|
|||
|
||||
void K_TickSpecialStage(void);
|
||||
|
||||
/*--------------------------------------------------
|
||||
mobj_t *K_GetPossibleSpecialTarget(void)
|
||||
|
||||
Gets the global special stage target if valid
|
||||
(for Jawz, tether, etc)
|
||||
|
||||
Return:-
|
||||
Target or NULL
|
||||
--------------------------------------------------*/
|
||||
|
||||
mobj_t *K_GetPossibleSpecialTarget(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -2971,15 +2971,16 @@ static int lib_gAddGametype(lua_State *L)
|
|||
const char *k;
|
||||
lua_Integer i;
|
||||
|
||||
gametype_t *newgametype = NULL;
|
||||
|
||||
const char *gtname = NULL;
|
||||
const char *gtconst = NULL;
|
||||
INT16 newgtidx = 0;
|
||||
UINT32 newgtrules = 0;
|
||||
UINT32 newgttol = 0;
|
||||
INT32 newgtpointlimit = 0;
|
||||
INT32 newgttimelimit = 0;
|
||||
INT16 newgtrankingstype = -1;
|
||||
int newgtinttype = 0;
|
||||
UINT8 newgtinttype = 0;
|
||||
INT16 j;
|
||||
|
||||
luaL_checktype(L, 1, LUA_TTABLE);
|
||||
lua_settop(L, 1); // Clear out all other possible arguments, leaving only the first one.
|
||||
|
|
@ -2988,8 +2989,10 @@ static int lib_gAddGametype(lua_State *L)
|
|||
return luaL_error(L, "This function cannot be called from within a hook or coroutine!");
|
||||
|
||||
// Ran out of gametype slots
|
||||
if (gametypecount == NUMGAMETYPEFREESLOTS)
|
||||
return luaL_error(L, "Ran out of free gametype slots!");
|
||||
if (numgametypes == GT_LASTFREESLOT)
|
||||
{
|
||||
I_Error("Out of Gametype Freeslots while allocating \"%s\"\nLoad less addons to fix this.", gtname);
|
||||
}
|
||||
|
||||
#define FIELDERROR(f, e) luaL_error(L, "bad value for " LUA_QL(f) " in table passed to " LUA_QL("G_AddGametype") " (%s)", e);
|
||||
#define TYPEERROR(f, t) FIELDERROR(f, va("%s expected, got %s", lua_typename(L, t), luaL_typename(L, -1)))
|
||||
|
|
@ -3022,19 +3025,15 @@ static int lib_gAddGametype(lua_State *L)
|
|||
if (!lua_isnumber(L, 3))
|
||||
TYPEERROR("typeoflevel", LUA_TNUMBER)
|
||||
newgttol = (UINT32)lua_tointeger(L, 3);
|
||||
} else if (i == 5 || (k && fasticmp(k, "rankingtype"))) {
|
||||
if (!lua_isnumber(L, 3))
|
||||
TYPEERROR("rankingtype", LUA_TNUMBER)
|
||||
newgtrankingstype = (INT16)lua_tointeger(L, 3);
|
||||
} else if (i == 6 || (k && fasticmp(k, "intermissiontype"))) {
|
||||
} else if (i == 5 || (k && fasticmp(k, "intermissiontype"))) {
|
||||
if (!lua_isnumber(L, 3))
|
||||
TYPEERROR("intermissiontype", LUA_TNUMBER)
|
||||
newgtinttype = (int)lua_tointeger(L, 3);
|
||||
} else if (i == 7 || (k && fasticmp(k, "defaultpointlimit"))) {
|
||||
} else if (i == 6 || (k && fasticmp(k, "defaultpointlimit"))) {
|
||||
if (!lua_isnumber(L, 3))
|
||||
TYPEERROR("defaultpointlimit", LUA_TNUMBER)
|
||||
newgtpointlimit = (INT32)lua_tointeger(L, 3);
|
||||
} else if (i == 8 || (k && fasticmp(k, "defaulttimelimit"))) {
|
||||
} else if (i == 7 || (k && fasticmp(k, "defaulttimelimit"))) {
|
||||
if (!lua_isnumber(L, 3))
|
||||
TYPEERROR("defaulttimelimit", LUA_TNUMBER)
|
||||
newgttimelimit = (INT32)lua_tointeger(L, 3);
|
||||
|
|
@ -3045,38 +3044,44 @@ static int lib_gAddGametype(lua_State *L)
|
|||
#undef FIELDERROR
|
||||
#undef TYPEERROR
|
||||
|
||||
if (gtname == NULL)
|
||||
return luaL_error(L, "Custom gametype must have a name");
|
||||
|
||||
if (strlen(gtname) >= MAXGAMETYPELENGTH)
|
||||
return luaL_error(L, "Custom gametype \"%s\"'s name must be %d long at most", gtname, MAXGAMETYPELENGTH-1);
|
||||
|
||||
for (j = 0; j < numgametypes; j++)
|
||||
if (!strcmp(gtname, gametypes[j]->name))
|
||||
break;
|
||||
|
||||
if (j < numgametypes)
|
||||
return luaL_error(L, "Custom gametype \"%s\"'s name is already in use", gtname);
|
||||
|
||||
// pop gametype table
|
||||
lua_pop(L, 1);
|
||||
|
||||
// Set defaults
|
||||
if (gtname == NULL)
|
||||
gtname = Z_StrDup("Unnamed gametype");
|
||||
|
||||
// Add the new gametype
|
||||
newgtidx = G_AddGametype(newgtrules);
|
||||
G_AddGametypeTOL(newgtidx, newgttol);
|
||||
newgametype = Z_Calloc(sizeof (gametype_t), PU_STATIC, NULL);
|
||||
if (!newgametype)
|
||||
{
|
||||
I_Error("Out of memory allocating gametype \"%s\"", gtname);
|
||||
}
|
||||
|
||||
// Not covered by G_AddGametype alone.
|
||||
if (newgtrankingstype == -1)
|
||||
newgtrankingstype = newgtidx;
|
||||
gametyperankings[newgtidx] = newgtrankingstype;
|
||||
intermissiontypes[newgtidx] = newgtinttype;
|
||||
pointlimits[newgtidx] = newgtpointlimit;
|
||||
timelimits[newgtidx] = newgttimelimit;
|
||||
|
||||
// Write the new gametype name.
|
||||
Gametype_Names[newgtidx] = gtname;
|
||||
|
||||
// Write the constant name.
|
||||
if (gtconst == NULL)
|
||||
gtconst = gtname;
|
||||
G_AddGametypeConstant(newgtidx, gtconst);
|
||||
|
||||
// Update gametype_cons_t accordingly.
|
||||
G_UpdateGametypeSelections();
|
||||
newgametype->name = gtname;
|
||||
newgametype->rules = newgtrules;
|
||||
newgametype->constant = G_PrepareGametypeConstant(gtconst);
|
||||
newgametype->tol = newgttol;
|
||||
newgametype->intermission = newgtinttype;
|
||||
newgametype->pointlimit = newgtpointlimit;
|
||||
newgametype->timelimit = newgttimelimit;
|
||||
|
||||
gametypes[numgametypes++] = newgametype;
|
||||
|
||||
// done
|
||||
CONS_Printf("Added gametype %s\n", Gametype_Names[newgtidx]);
|
||||
CONS_Printf("Added gametype %s\n", gtname);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -3284,15 +3289,6 @@ static int lib_gExitLevel(lua_State *L)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int lib_gIsSpecialStage(lua_State *L)
|
||||
{
|
||||
INT32 mapnum = luaL_optinteger(L, 1, gamemap);
|
||||
//HUDSAFE
|
||||
INLEVEL
|
||||
lua_pushboolean(L, G_IsSpecialStage(mapnum));
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int lib_gGametypeUsesLives(lua_State *L)
|
||||
{
|
||||
//HUDSAFE
|
||||
|
|
@ -4101,7 +4097,6 @@ static luaL_Reg lib[] = {
|
|||
{"G_DoReborn",lib_gDoReborn},
|
||||
{"G_SetCustomExitVars",lib_gSetCustomExitVars},
|
||||
{"G_ExitLevel",lib_gExitLevel},
|
||||
{"G_IsSpecialStage",lib_gIsSpecialStage},
|
||||
{"G_GametypeUsesLives",lib_gGametypeUsesLives},
|
||||
{"G_GametypeHasTeams",lib_gGametypeHasTeams},
|
||||
{"G_GametypeHasSpectators",lib_gGametypeHasSpectators},
|
||||
|
|
|
|||
|
|
@ -162,9 +162,6 @@ int LUA_PushGlobals(lua_State *L, const char *word)
|
|||
} else if (fastcmp(word,"maptol")) {
|
||||
lua_pushinteger(L, maptol);
|
||||
return 1;
|
||||
} else if (fastcmp(word,"circuitmap")) {
|
||||
lua_pushboolean(L, circuitmap);
|
||||
return 1;
|
||||
} else if (fastcmp(word,"stoppedclock")) {
|
||||
lua_pushboolean(L, stoppedclock);
|
||||
return 1;
|
||||
|
|
|
|||
|
|
@ -570,7 +570,10 @@ static char *M_BuildConditionTitle(UINT16 map)
|
|||
{
|
||||
char *title, *ref;
|
||||
|
||||
if (M_MapLocked(map+1))
|
||||
if (((mapheaderinfo[map]->menuflags & LF2_FINISHNEEDED)
|
||||
// the following is intentionally not MV_BEATEN, just in case the title is for "Finish a round on X"
|
||||
&& !(mapheaderinfo[map]->mapvisited & MV_VISITED))
|
||||
|| M_MapLocked(map+1))
|
||||
return Z_StrDup("???");
|
||||
|
||||
title = ref = G_BuildMapTitle(map+1);
|
||||
|
|
@ -629,7 +632,7 @@ static const char *M_GetConditionString(condition_t *cn)
|
|||
|
||||
title = BUILDCONDITIONTITLE(cn->requirement);
|
||||
work = va("%s %s%s",
|
||||
(cn->type == UC_MAPVISITED) ? "Visit" : "Beat",
|
||||
(cn->type == UC_MAPVISITED) ? "Visit" : "Finish a round on",
|
||||
title,
|
||||
(cn->type == UC_MAPENCORE) ? " in Encore Mode" : "");
|
||||
Z_Free(title);
|
||||
|
|
|
|||
|
|
@ -123,7 +123,8 @@ typedef enum
|
|||
|
||||
// Menu restrictions
|
||||
SECRET_TIMEATTACK, // Permit Time attack
|
||||
SECRET_BREAKTHECAPSULES, // Permit SP Capsules
|
||||
SECRET_BREAKTHECAPSULES, // Permit SP Capsule attack
|
||||
SECRET_SPECIALATTACK, // Permit Special attack (You're blue now!)
|
||||
SECRET_SOUNDTEST, // Permit Sound Test
|
||||
SECRET_ALTTITLE, // Permit alternate titlescreen
|
||||
|
||||
|
|
|
|||
|
|
@ -34,14 +34,16 @@ Obj_SpawnBrolyKi
|
|||
( mobj_t * source,
|
||||
tic_t duration)
|
||||
{
|
||||
mobj_t *x = P_SpawnMobjFromMobj(
|
||||
source, 0, 0, 0, MT_BROLY);
|
||||
mobj_t *x;
|
||||
|
||||
if (duration == 0)
|
||||
if (duration <= 0)
|
||||
{
|
||||
return x;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
x = P_SpawnMobjFromMobj(
|
||||
source, 0, 0, 0, MT_BROLY);
|
||||
|
||||
// Shrink into center of source object.
|
||||
x->z = (source->z + source->height / 2);
|
||||
|
||||
|
|
@ -61,12 +63,20 @@ Obj_SpawnBrolyKi
|
|||
return x;
|
||||
}
|
||||
|
||||
void
|
||||
boolean
|
||||
Obj_BrolyKiThink (mobj_t *x)
|
||||
{
|
||||
if (broly_duration(x) <= 0)
|
||||
{
|
||||
P_RemoveMobj(x);
|
||||
return false;
|
||||
}
|
||||
|
||||
const fixed_t
|
||||
t = get_unit_linear(x),
|
||||
n = Easing_OutSine(t, 0, broly_maxscale(x));
|
||||
|
||||
P_InstaScale(x, n);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -549,7 +549,7 @@ static void SPBSeek(mobj_t *spb, mobj_t *bestMobj)
|
|||
|
||||
SetSPBSpeed(spb, xySpeed, zSpeed);
|
||||
|
||||
if (specialStage.active == false)
|
||||
if (specialstageinfo.valid == false)
|
||||
{
|
||||
// see if a player is near us, if they are, try to hit them by slightly thrusting towards them, otherwise, bleh!
|
||||
steerDist = 1536 * mapobjectscale;
|
||||
|
|
@ -857,6 +857,27 @@ void Obj_SPBThink(mobj_t *spb)
|
|||
ghost->colorized = true;
|
||||
}
|
||||
|
||||
if (spb_nothink(spb) <= 1)
|
||||
{
|
||||
if (specialstageinfo.valid == true)
|
||||
{
|
||||
bestRank = 0;
|
||||
|
||||
if ((bestMobj = K_GetPossibleSpecialTarget()) == NULL)
|
||||
{
|
||||
// experimental - I think it's interesting IMO
|
||||
Obj_MantaRingCreate(
|
||||
spb,
|
||||
spb_owner(spb),
|
||||
NULL
|
||||
);
|
||||
|
||||
spb->fuse = TICRATE/3;
|
||||
spb_nothink(spb) = spb->fuse + 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (spb_nothink(spb) > 0)
|
||||
{
|
||||
// Init values, don't think yet.
|
||||
|
|
@ -874,15 +895,6 @@ void Obj_SPBThink(mobj_t *spb)
|
|||
}
|
||||
else
|
||||
{
|
||||
if (specialStage.active == true)
|
||||
{
|
||||
if (specialStage.ufo != NULL && P_MobjWasRemoved(specialStage.ufo) == false)
|
||||
{
|
||||
bestRank = 1;
|
||||
bestMobj = specialStage.ufo;
|
||||
}
|
||||
}
|
||||
|
||||
// Find the player with the best rank
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -239,9 +239,9 @@ static void UFOUpdateAngle(mobj_t *ufo)
|
|||
|
||||
waypoint_t *K_GetSpecialUFOWaypoint(mobj_t *ufo)
|
||||
{
|
||||
if ((ufo == NULL) && (specialStage.active == true))
|
||||
if ((ufo == NULL) && (specialstageinfo.valid == true))
|
||||
{
|
||||
ufo = specialStage.ufo;
|
||||
ufo = specialstageinfo.ufo;
|
||||
}
|
||||
|
||||
if (ufo != NULL && P_MobjWasRemoved(ufo) == false
|
||||
|
|
@ -281,10 +281,11 @@ static void UFOMove(mobj_t *ufo)
|
|||
if (curWaypoint == NULL || destWaypoint == NULL)
|
||||
{
|
||||
// Waypoints aren't valid.
|
||||
// Just stand still.
|
||||
// Just go straight up.
|
||||
// :japanese_ogre: : "Abrupt and funny is the funniest way to end the special stage anyways"
|
||||
ufo->momx = 0;
|
||||
ufo->momy = 0;
|
||||
ufo->momz = 0;
|
||||
ufo->momz = ufo_speed(ufo);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -365,8 +366,23 @@ static void UFOMove(mobj_t *ufo)
|
|||
|
||||
if (reachedEnd == true)
|
||||
{
|
||||
CONS_Printf("You lost...\n");
|
||||
ufo_waypoint(ufo) = -1; // Invalidate
|
||||
UINT8 i;
|
||||
|
||||
// Invalidate UFO/emerald
|
||||
ufo_waypoint(ufo) = -1;
|
||||
ufo->flags &= ~(MF_SPECIAL|MF_PICKUPFROMBELOW);
|
||||
|
||||
// Disable player
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
if (!playeringame[i])
|
||||
continue;
|
||||
if (players[i].spectator)
|
||||
continue;
|
||||
|
||||
players[i].pflags |= PF_NOCONTEST;
|
||||
P_DoPlayerExit(&players[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (pathfindsuccess == true)
|
||||
|
|
@ -591,6 +607,8 @@ boolean Obj_SpecialUFODamage(mobj_t *ufo, mobj_t *inflictor, mobj_t *source, UIN
|
|||
ufo->flags = (ufo->flags & ~MF_SHOOTABLE) | (MF_SPECIAL|MF_PICKUPFROMBELOW);
|
||||
ufo->shadowscale = FRACUNIT/3;
|
||||
|
||||
P_LinedefExecute(LE_PINCHPHASE, ufo, NULL);
|
||||
|
||||
ufo_speed(ufo) += addSpeed; // Even more speed!
|
||||
return true;
|
||||
}
|
||||
|
|
@ -655,7 +673,10 @@ void Obj_UFOPieceThink(mobj_t *piece)
|
|||
fixed_t sc = FixedDiv(FixedDiv(ufo->ceilingz - stemZ, piece->scale), 15 * FRACUNIT);
|
||||
|
||||
UFOMoveTo(piece, ufo->x, ufo->y, stemZ);
|
||||
piece->spriteyscale = sc;
|
||||
if (sc > 0)
|
||||
{
|
||||
piece->spriteyscale = sc;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
|
@ -820,11 +841,11 @@ mobj_t *Obj_CreateSpecialUFO(void)
|
|||
|
||||
UINT32 K_GetSpecialUFODistance(void)
|
||||
{
|
||||
if (specialStage.active == true)
|
||||
if (specialstageinfo.valid == true)
|
||||
{
|
||||
if (specialStage.ufo != NULL && P_MobjWasRemoved(specialStage.ufo) == false)
|
||||
if (specialstageinfo.ufo != NULL && P_MobjWasRemoved(specialstageinfo.ufo) == false)
|
||||
{
|
||||
return (UINT32)ufo_distancetofinish(specialStage.ufo);
|
||||
return (UINT32)ufo_distancetofinish(specialstageinfo.ufo);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -13053,7 +13053,7 @@ void A_ItemPop(mobj_t *actor)
|
|||
}
|
||||
|
||||
// Here at mapload in battle?
|
||||
if ((gametyperules & GTR_BUMPERS) && (actor->flags2 & MF2_BOSSNOTRAP))
|
||||
if (!(gametyperules & GTR_CIRCUIT) && (actor->flags2 & MF2_BOSSNOTRAP))
|
||||
{
|
||||
numgotboxes++;
|
||||
|
||||
|
|
|
|||
|
|
@ -32,9 +32,9 @@
|
|||
// SRB2kart
|
||||
#include "k_kart.h"
|
||||
#include "k_battle.h"
|
||||
#include "k_specialstage.h"
|
||||
#include "k_pwrlv.h"
|
||||
#include "k_grandprix.h"
|
||||
#include "k_boss.h"
|
||||
#include "k_respawn.h"
|
||||
#include "p_spec.h"
|
||||
#include "k_objects.h"
|
||||
|
|
@ -414,6 +414,8 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
|
|||
if (toucher->hitlag > 0)
|
||||
return;
|
||||
|
||||
P_LinedefExecute(LE_BOSSDEAD, toucher, NULL);
|
||||
|
||||
CONS_Printf("You win!\n");
|
||||
break;
|
||||
/*
|
||||
|
|
@ -859,7 +861,7 @@ boolean P_CheckRacers(void)
|
|||
// Check if all the players in the race have finished. If so, end the level.
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
if (!playeringame[i] || players[i].spectator || players[i].lives <= 0)
|
||||
if (!playeringame[i] || players[i].spectator || (players[i].lives <= 0 && !players[i].exiting))
|
||||
{
|
||||
// Y'all aren't even playing
|
||||
continue;
|
||||
|
|
@ -893,7 +895,7 @@ boolean P_CheckRacers(void)
|
|||
}
|
||||
}
|
||||
|
||||
if (numPlaying <= 1)
|
||||
if (numPlaying <= 1 || specialstageinfo.valid == true)
|
||||
{
|
||||
// Never do this without enough players.
|
||||
eliminateLast = false;
|
||||
|
|
@ -1097,7 +1099,7 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget
|
|||
{
|
||||
P_SetTarget(&target->target, source);
|
||||
|
||||
if (gametyperules & GTR_BUMPERS)
|
||||
if (!(gametyperules & GTR_CIRCUIT))
|
||||
{
|
||||
target->fuse = 2;
|
||||
}
|
||||
|
|
@ -2198,7 +2200,7 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
|
|||
{
|
||||
tic_t kinvextend;
|
||||
|
||||
if (gametype == GT_BATTLE)
|
||||
if (gametyperules & GTR_CLOSERPLAYERS)
|
||||
kinvextend = 2*TICRATE;
|
||||
else
|
||||
kinvextend = 5*TICRATE;
|
||||
|
|
|
|||
83
src/p_mobj.c
83
src/p_mobj.c
|
|
@ -39,7 +39,6 @@
|
|||
// SRB2kart
|
||||
#include "k_kart.h"
|
||||
#include "k_battle.h"
|
||||
#include "k_boss.h"
|
||||
#include "k_color.h"
|
||||
#include "k_respawn.h"
|
||||
#include "k_bot.h"
|
||||
|
|
@ -4346,25 +4345,7 @@ static void P_RefreshItemCapsuleParts(mobj_t *mobj)
|
|||
part->threshold = mobj->threshold;
|
||||
part->movecount = mobj->movecount;
|
||||
|
||||
switch (itemType)
|
||||
{
|
||||
case KITEM_ORBINAUT:
|
||||
part->sprite = SPR_ITMO;
|
||||
part->frame = FF_FULLBRIGHT|FF_PAPERSPRITE|K_GetOrbinautItemFrame(mobj->movecount);
|
||||
break;
|
||||
case KITEM_INVINCIBILITY:
|
||||
part->sprite = SPR_ITMI;
|
||||
part->frame = FF_FULLBRIGHT|FF_PAPERSPRITE|K_GetInvincibilityItemFrame();
|
||||
break;
|
||||
case KITEM_SAD:
|
||||
part->sprite = SPR_ITEM;
|
||||
part->frame = FF_FULLBRIGHT|FF_PAPERSPRITE;
|
||||
break;
|
||||
default:
|
||||
part->sprite = SPR_ITEM;
|
||||
part->frame = FF_FULLBRIGHT|FF_PAPERSPRITE|(itemType);
|
||||
break;
|
||||
}
|
||||
K_UpdateMobjItemOverlay(part, itemType, mobj->movecount);
|
||||
|
||||
// update number frame
|
||||
if (K_GetShieldFromItem(itemType) != KSHIELD_NONE) // shields don't stack, so don't show a number
|
||||
|
|
@ -6163,7 +6144,7 @@ static void P_MobjSceneryThink(mobj_t *mobj)
|
|||
mobj->color = mobj->target->color;
|
||||
K_MatchGenericExtraFlags(mobj, mobj->target);
|
||||
|
||||
if ((gametype == GT_RACE || mobj->target->player->bumpers <= 0)
|
||||
if ((!(gametyperules & GTR_BUMPERS) || mobj->target->player->bumpers <= 0)
|
||||
#if 1 // Set to 0 to test without needing to host
|
||||
|| (P_IsDisplayPlayer(mobj->target->player))
|
||||
#endif
|
||||
|
|
@ -6534,7 +6515,10 @@ static void P_MobjSceneryThink(mobj_t *mobj)
|
|||
mobj->renderflags ^= RF_DONTDRAW;
|
||||
break;
|
||||
case MT_BROLY:
|
||||
Obj_BrolyKiThink(mobj);
|
||||
if (Obj_BrolyKiThink(mobj) == false)
|
||||
{
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case MT_VWREF:
|
||||
case MT_VWREB:
|
||||
|
|
@ -8362,7 +8346,7 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
|
|||
statenum_t state = (mobj->state-states);
|
||||
|
||||
if (!mobj->target || !mobj->target->health || !mobj->target->player || mobj->target->player->spectator
|
||||
|| (gametype == GT_RACE || mobj->target->player->bumpers))
|
||||
|| (!(gametyperules & GTR_BUMPERS) || mobj->target->player->bumpers))
|
||||
{
|
||||
P_RemoveMobj(mobj);
|
||||
return false;
|
||||
|
|
@ -9366,7 +9350,7 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
|
|||
{
|
||||
if (gametyperules & GTR_PAPERITEMS)
|
||||
{
|
||||
if (battlecapsules == true || bossinfo.boss == true)
|
||||
if (battlecapsules == true)
|
||||
{
|
||||
;
|
||||
}
|
||||
|
|
@ -9389,12 +9373,12 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
|
|||
}
|
||||
// FALLTHRU
|
||||
case MT_SPHEREBOX:
|
||||
if (gametype == GT_BATTLE && mobj->threshold == 70)
|
||||
if (mobj->threshold == 70)
|
||||
{
|
||||
mobj->color = K_RainbowColor(leveltime);
|
||||
mobj->colorized = true;
|
||||
|
||||
if (battleovertime.enabled)
|
||||
if ((gametyperules & GTR_OVERTIME) && battleovertime.enabled)
|
||||
{
|
||||
angle_t ang = FixedAngle((leveltime % 360) << FRACBITS);
|
||||
fixed_t z = battleovertime.z;
|
||||
|
|
@ -9528,13 +9512,39 @@ for (i = ((mobj->flags2 & MF2_STRONGBOX) ? strongboxamt : weakboxamt); i; --i) s
|
|||
P_RemoveMobj(mobj); // make sure they disappear
|
||||
}
|
||||
|
||||
static boolean P_CanFlickerFuse(mobj_t *mobj)
|
||||
{
|
||||
switch (mobj->type)
|
||||
{
|
||||
case MT_SNAPPER_HEAD:
|
||||
case MT_SNAPPER_LEG:
|
||||
case MT_MINECARTSEG:
|
||||
return true;
|
||||
|
||||
case MT_RANDOMITEM:
|
||||
case MT_EGGMANITEM:
|
||||
case MT_FALLINGROCK:
|
||||
case MT_FLOATINGITEM:
|
||||
if (mobj->fuse <= TICRATE)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
static boolean P_FuseThink(mobj_t *mobj)
|
||||
{
|
||||
if (mobj->type == MT_SNAPPER_HEAD || mobj->type == MT_SNAPPER_LEG || mobj->type == MT_MINECARTSEG)
|
||||
mobj->renderflags ^= RF_DONTDRAW;
|
||||
|
||||
if (mobj->fuse <= TICRATE && (mobj->type == MT_RANDOMITEM || mobj->type == MT_EGGMANITEM || mobj->type == MT_FALLINGROCK))
|
||||
if (P_CanFlickerFuse(mobj))
|
||||
{
|
||||
mobj->renderflags ^= RF_DONTDRAW;
|
||||
}
|
||||
|
||||
mobj->fuse--;
|
||||
|
||||
|
|
@ -9582,7 +9592,7 @@ static boolean P_FuseThink(mobj_t *mobj)
|
|||
{
|
||||
;
|
||||
}
|
||||
else if ((gametyperules & GTR_BUMPERS) && (mobj->state == &states[S_INVISIBLE]))
|
||||
else if (!(gametyperules & GTR_CIRCUIT) && (mobj->state == &states[S_INVISIBLE]))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
|
@ -11420,7 +11430,7 @@ void P_RespawnBattleBoxes(void)
|
|||
{
|
||||
thinker_t *th;
|
||||
|
||||
if (!(gametyperules & GTR_BUMPERS))
|
||||
if (gametyperules & GTR_CIRCUIT)
|
||||
return;
|
||||
|
||||
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
|
||||
|
|
@ -11685,13 +11695,16 @@ void P_SpawnPlayer(INT32 playernum)
|
|||
|
||||
K_InitStumbleIndicator(p);
|
||||
|
||||
if (gametyperules & GTR_BUMPERS)
|
||||
if (gametyperules & GTR_ITEMARROWS)
|
||||
{
|
||||
mobj_t *overheadarrow = P_SpawnMobj(mobj->x, mobj->y, mobj->z + mobj->height + 16*FRACUNIT, MT_PLAYERARROW);
|
||||
P_SetTarget(&overheadarrow->target, mobj);
|
||||
overheadarrow->renderflags |= RF_DONTDRAW;
|
||||
P_SetScale(overheadarrow, mobj->destscale);
|
||||
}
|
||||
|
||||
if (gametyperules & GTR_BUMPERS)
|
||||
{
|
||||
if (p->spectator)
|
||||
{
|
||||
// HEY! No being cheap...
|
||||
|
|
@ -12075,7 +12088,7 @@ static boolean P_AllowMobjSpawn(mapthing_t* mthing, mobjtype_t i)
|
|||
|
||||
// No bosses outside of a combat situation.
|
||||
// (just in case we want boss arenas to do double duty as battle maps)
|
||||
if (!bossinfo.boss && (mobjinfo[i].flags & MF_BOSS))
|
||||
if (!(gametyperules & GTR_BOSS) && (mobjinfo[i].flags & MF_BOSS))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
|
@ -12096,7 +12109,7 @@ static mobjtype_t P_GetMobjtypeSubstitute(mapthing_t *mthing, mobjtype_t i)
|
|||
if ((i == MT_RING) && (gametyperules & GTR_SPHERES))
|
||||
return MT_BLUESPHERE;
|
||||
|
||||
if ((i == MT_RANDOMITEM) && (gametyperules & (GTR_PAPERITEMS|GTR_CIRCUIT)) == (GTR_PAPERITEMS|GTR_CIRCUIT) && !bossinfo.boss)
|
||||
if ((i == MT_RANDOMITEM) && (gametyperules & (GTR_PAPERITEMS|GTR_CIRCUIT)) == (GTR_PAPERITEMS|GTR_CIRCUIT))
|
||||
return MT_PAPERITEMSPOT;
|
||||
|
||||
return i;
|
||||
|
|
|
|||
|
|
@ -6820,7 +6820,6 @@ static void P_InitLevelSettings(void)
|
|||
rflagpoint = bflagpoint = NULL;
|
||||
|
||||
// circuit, race and competition stuff
|
||||
circuitmap = false;
|
||||
numstarposts = 0;
|
||||
timeinmap = 0;
|
||||
|
||||
|
|
@ -6842,7 +6841,7 @@ static void P_InitLevelSettings(void)
|
|||
if (playeringame[i] && !players[i].spectator)
|
||||
p++;
|
||||
|
||||
if (grandprixinfo.gp == false && bossinfo.boss == false)
|
||||
if (grandprixinfo.gp == false)
|
||||
players[i].lives = 3;
|
||||
|
||||
G_PlayerReborn(i, true);
|
||||
|
|
@ -6852,39 +6851,27 @@ static void P_InitLevelSettings(void)
|
|||
racecountdown = exitcountdown = exitfadestarted = 0;
|
||||
curlap = bestlap = 0; // SRB2Kart
|
||||
|
||||
// SRB2Kart: map load variables
|
||||
// Gamespeed and frantic items
|
||||
gamespeed = KARTSPEED_EASY;
|
||||
franticitems = false;
|
||||
|
||||
if (grandprixinfo.gp == true)
|
||||
{
|
||||
if ((gametyperules & GTR_BUMPERS))
|
||||
{
|
||||
gamespeed = KARTSPEED_EASY;
|
||||
}
|
||||
else
|
||||
if (gametyperules & GTR_CIRCUIT)
|
||||
{
|
||||
gamespeed = grandprixinfo.gamespeed;
|
||||
}
|
||||
|
||||
franticitems = false;
|
||||
}
|
||||
else if (bossinfo.boss)
|
||||
{
|
||||
gamespeed = KARTSPEED_EASY;
|
||||
franticitems = false;
|
||||
}
|
||||
else if (modeattacking)
|
||||
{
|
||||
// Just play it safe and set everything
|
||||
if ((gametyperules & GTR_BUMPERS))
|
||||
gamespeed = KARTSPEED_EASY;
|
||||
else
|
||||
if (gametyperules & GTR_CIRCUIT)
|
||||
{
|
||||
gamespeed = KARTSPEED_HARD;
|
||||
franticitems = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((gametyperules & GTR_BUMPERS))
|
||||
gamespeed = KARTSPEED_EASY;
|
||||
else
|
||||
if (gametyperules & GTR_CIRCUIT)
|
||||
{
|
||||
if (cv_kartspeed.value == KARTSPEED_AUTO)
|
||||
gamespeed = ((speedscramble == -1) ? KARTSPEED_NORMAL : (UINT8)speedscramble);
|
||||
|
|
@ -6899,6 +6886,9 @@ static void P_InitLevelSettings(void)
|
|||
|
||||
memset(&battleovertime, 0, sizeof(struct battleovertime));
|
||||
speedscramble = encorescramble = -1;
|
||||
|
||||
K_ResetSpecialStage();
|
||||
K_ResetBossInfo();
|
||||
}
|
||||
|
||||
#if 0
|
||||
|
|
@ -7000,20 +6990,23 @@ static void P_LoadRecordGhosts(void)
|
|||
gpath = Z_StrDup(va("%s"PATHSEP"media"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s", srb2home, timeattackfolder, G_BuildMapName(gamemap)));
|
||||
|
||||
// Best Time ghost
|
||||
if (cv_ghost_besttime.value)
|
||||
if (modeattacking & ATTACKING_TIME)
|
||||
{
|
||||
for (i = 0; i < numskins; ++i)
|
||||
if (cv_ghost_besttime.value)
|
||||
{
|
||||
if (cv_ghost_besttime.value == 1 && players[consoleplayer].skin != i)
|
||||
continue;
|
||||
for (i = 0; i < numskins; ++i)
|
||||
{
|
||||
if (cv_ghost_besttime.value == 1 && players[consoleplayer].skin != i)
|
||||
continue;
|
||||
|
||||
if (FIL_FileExists(va("%s-%s-time-best.lmp", gpath, skins[i].name)))
|
||||
G_AddGhost(va("%s-%s-time-best.lmp", gpath, skins[i].name));
|
||||
if (FIL_FileExists(va("%s-%s-time-best.lmp", gpath, skins[i].name)))
|
||||
G_AddGhost(va("%s-%s-time-best.lmp", gpath, skins[i].name));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Best Lap ghost
|
||||
if (modeattacking != ATTACKING_CAPSULES)
|
||||
if (modeattacking & ATTACKING_LAP)
|
||||
{
|
||||
if (cv_ghost_bestlap.value)
|
||||
{
|
||||
|
|
@ -7220,7 +7213,6 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate)
|
|||
|
||||
// This is needed. Don't touch.
|
||||
maptol = mapheaderinfo[gamemap-1]->typeoflevel;
|
||||
gametyperules = gametypedefaultrules[gametype];
|
||||
|
||||
CON_Drawer(); // let the user know what we are going to do
|
||||
I_FinishUpdate(); // page flip or blit buffer
|
||||
|
|
@ -7334,13 +7326,6 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate)
|
|||
}
|
||||
G_ClearModeAttackRetryFlag();
|
||||
}
|
||||
/*
|
||||
else if (rendermode != render_none && G_IsSpecialStage(gamemap))
|
||||
{
|
||||
P_RunSpecialStageWipe();
|
||||
ranspecialwipe = 1;
|
||||
}
|
||||
*/
|
||||
|
||||
// Make sure all sounds are stopped before Z_FreeTags.
|
||||
S_StopSounds();
|
||||
|
|
@ -7375,7 +7360,20 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate)
|
|||
S_Start();
|
||||
}
|
||||
|
||||
levelfadecol = (encoremode ? 0 : 31);
|
||||
if (gametyperules & GTR_SPECIALSTART)
|
||||
{
|
||||
if (ranspecialwipe != 2)
|
||||
S_StartSound(NULL, sfx_s3kaf);
|
||||
levelfadecol = 0;
|
||||
}
|
||||
else if (encoremode)
|
||||
{
|
||||
levelfadecol = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
levelfadecol = 31;
|
||||
}
|
||||
|
||||
if (rendermode != render_none)
|
||||
{
|
||||
|
|
@ -7611,19 +7609,6 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate)
|
|||
K_UpdateMatchRaceBots();
|
||||
}
|
||||
|
||||
if (bossinfo.boss)
|
||||
{
|
||||
// Reset some pesky boss state that can't be handled elsewhere.
|
||||
bossinfo.barlen = BOSSHEALTHBARLEN;
|
||||
bossinfo.visualbar = 0;
|
||||
Z_Free(bossinfo.enemyname);
|
||||
Z_Free(bossinfo.subtitle);
|
||||
bossinfo.enemyname = bossinfo.subtitle = NULL;
|
||||
bossinfo.titleshow = 0;
|
||||
bossinfo.titlesound = sfx_typri1;
|
||||
memset(&(bossinfo.weakspots), 0, sizeof(weakspot_t)*NUMWEAKSPOTS);
|
||||
}
|
||||
|
||||
if (!fromnetsave) // uglier hack
|
||||
{ // to make a newly loaded level start on the second frame.
|
||||
INT32 buf = gametic % BACKUPTICS;
|
||||
|
|
@ -7769,7 +7754,7 @@ UINT8 P_InitMapData(boolean existingmapheaders)
|
|||
for (i = 0; i < nummapheaders; ++i)
|
||||
{
|
||||
name = mapheaderinfo[i]->lumpname;
|
||||
maplump = W_CheckNumForMap(name);
|
||||
maplump = W_CheckNumForMap(name, (mapheaderinfo[i]->lumpnum == LUMPERROR));
|
||||
|
||||
// Always check for cup cache reassociations.
|
||||
// (The core assumption is that cups < headers.)
|
||||
|
|
|
|||
19
src/p_spec.c
19
src/p_spec.c
|
|
@ -43,6 +43,7 @@
|
|||
|
||||
// SRB2kart
|
||||
#include "k_kart.h"
|
||||
#include "k_specialstage.h"
|
||||
#include "console.h" // CON_LogMessage
|
||||
#include "k_respawn.h"
|
||||
#include "k_terrain.h"
|
||||
|
|
@ -1843,7 +1844,7 @@ static void K_HandleLapIncrement(player_t *player)
|
|||
{
|
||||
if (player)
|
||||
{
|
||||
if (leveltime < starttime)
|
||||
if (leveltime < starttime && !(gametyperules & GTR_ROLLINGSTART))
|
||||
{
|
||||
// Will fault the player
|
||||
K_DoIngameRespawn(player);
|
||||
|
|
@ -1902,7 +1903,7 @@ static void K_HandleLapIncrement(player_t *player)
|
|||
|
||||
if (P_IsDisplayPlayer(player))
|
||||
{
|
||||
if (player->laps == numlaps) // final lap
|
||||
if (numlaps > 1 && player->laps == numlaps) // final lap
|
||||
S_StartSound(NULL, sfx_s3k68);
|
||||
else if ((player->laps > 1) && (player->laps < numlaps)) // non-final lap
|
||||
S_StartSound(NULL, sfx_s221);
|
||||
|
|
@ -1925,6 +1926,14 @@ static void K_HandleLapIncrement(player_t *player)
|
|||
// finished race exit setup
|
||||
if (player->laps > numlaps)
|
||||
{
|
||||
if (specialstageinfo.valid == true)
|
||||
{
|
||||
// Don't permit a win just by sneaking ahead of the UFO/emerald.
|
||||
if (!(specialstageinfo.ufo == NULL || P_MobjWasRemoved(specialstageinfo.ufo)))
|
||||
{
|
||||
player->pflags |= PF_NOCONTEST;
|
||||
}
|
||||
}
|
||||
P_DoPlayerExit(player);
|
||||
P_SetupSignExit(player);
|
||||
}
|
||||
|
|
@ -6662,12 +6671,6 @@ void P_SpawnSpecials(boolean fromnetsave)
|
|||
break;
|
||||
}
|
||||
|
||||
// SRB2Kart
|
||||
case 2001: // Finish Line
|
||||
if ((gametyperules & GTR_CIRCUIT))
|
||||
circuitmap = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -361,7 +361,7 @@ static inline void P_RunThinkers(void)
|
|||
if (gametyperules & GTR_PAPERITEMS)
|
||||
K_RunPaperItemSpawners();
|
||||
|
||||
if ((gametyperules & GTR_BUMPERS) && battleovertime.enabled)
|
||||
if ((gametyperules & GTR_OVERTIME) && battleovertime.enabled)
|
||||
K_RunBattleOvertime();
|
||||
}
|
||||
|
||||
|
|
@ -646,7 +646,7 @@ void P_Ticker(boolean run)
|
|||
P_PlayerAfterThink(&players[i]);
|
||||
|
||||
// Bosses have a punchy start, so no position.
|
||||
if (bossinfo.boss == true)
|
||||
if (K_CheckBossIntro() == true)
|
||||
{
|
||||
if (leveltime == 3)
|
||||
{
|
||||
|
|
@ -719,7 +719,7 @@ void P_Ticker(boolean run)
|
|||
|
||||
K_TickSpecialStage();
|
||||
|
||||
if ((gametyperules & GTR_BUMPERS))
|
||||
if ((gametyperules & GTR_POINTLIMIT))
|
||||
{
|
||||
if (wantedcalcdelay && --wantedcalcdelay <= 0)
|
||||
K_CalculateBattleWanted();
|
||||
|
|
|
|||
39
src/p_user.c
39
src/p_user.c
|
|
@ -54,6 +54,7 @@
|
|||
#include "k_bot.h"
|
||||
#include "k_grandprix.h"
|
||||
#include "k_boss.h"
|
||||
#include "k_specialstage.h"
|
||||
#include "k_terrain.h" // K_SpawnSplashForMobj
|
||||
#include "k_color.h"
|
||||
#include "k_follower.h"
|
||||
|
|
@ -501,7 +502,7 @@ INT32 P_GivePlayerRings(player_t *player, INT32 num_rings)
|
|||
if (!player->mo)
|
||||
return 0;
|
||||
|
||||
if ((gametyperules & GTR_BUMPERS)) // No rings in Battle Mode
|
||||
if ((gametyperules & GTR_SPHERES)) // No rings in Battle Mode
|
||||
return 0;
|
||||
|
||||
test = player->rings + num_rings;
|
||||
|
|
@ -519,6 +520,9 @@ INT32 P_GivePlayerSpheres(player_t *player, INT32 num_spheres)
|
|||
{
|
||||
num_spheres += player->spheres;
|
||||
|
||||
if (!(gametyperules & GTR_SPHERES)) // No spheres in Race mode)
|
||||
return 0;
|
||||
|
||||
// Not alive
|
||||
if ((gametyperules & GTR_BUMPERS) && (player->bumpers <= 0))
|
||||
return 0;
|
||||
|
|
@ -554,7 +558,7 @@ void P_GivePlayerLives(player_t *player, INT32 numlives)
|
|||
// Adds to the player's score
|
||||
void P_AddPlayerScore(player_t *player, UINT32 amount)
|
||||
{
|
||||
if (!((gametyperules & GTR_BUMPERS)))
|
||||
if (!((gametyperules & GTR_POINTLIMIT)))
|
||||
return;
|
||||
|
||||
if (player->exiting) // srb2kart
|
||||
|
|
@ -720,6 +724,7 @@ boolean P_EndingMusic(player_t *player)
|
|||
{
|
||||
char buffer[9];
|
||||
boolean looping = true;
|
||||
boolean racetracks = !!(gametyperules & GTR_CIRCUIT);
|
||||
INT32 bestlocalpos, test;
|
||||
player_t *bestlocalplayer;
|
||||
|
||||
|
|
@ -773,7 +778,7 @@ boolean P_EndingMusic(player_t *player)
|
|||
|
||||
#undef getplayerpos
|
||||
|
||||
if ((gametyperules & GTR_CIRCUIT) && bestlocalpos == MAXPLAYERS+1)
|
||||
if (racetracks == true && bestlocalpos == MAXPLAYERS+1)
|
||||
sprintf(buffer, "k*fail"); // F-Zero death results theme
|
||||
else
|
||||
{
|
||||
|
|
@ -787,9 +792,11 @@ boolean P_EndingMusic(player_t *player)
|
|||
|
||||
S_SpeedMusic(1.0f);
|
||||
|
||||
if ((gametyperules & GTR_CIRCUIT))
|
||||
if (racetracks == true)
|
||||
{
|
||||
buffer[1] = 'r';
|
||||
else if ((gametyperules & GTR_BUMPERS))
|
||||
}
|
||||
else
|
||||
{
|
||||
buffer[1] = 'b';
|
||||
looping = false;
|
||||
|
|
@ -828,7 +835,8 @@ void P_RestoreMusic(player_t *player)
|
|||
return;
|
||||
|
||||
// Event - Level Start
|
||||
if (bossinfo.boss == false && (leveltime < (starttime + (TICRATE/2)))) // see also where time overs are handled
|
||||
if ((K_CheckBossIntro() == false)
|
||||
&& (leveltime < (starttime + (TICRATE/2)))) // see also where time overs are handled
|
||||
return;
|
||||
|
||||
{
|
||||
|
|
@ -1303,7 +1311,16 @@ void P_DoPlayerExit(player_t *player)
|
|||
P_EndingMusic(player);
|
||||
|
||||
if (P_CheckRacers() && !exitcountdown)
|
||||
exitcountdown = raceexittime+1;
|
||||
{
|
||||
if (specialstageinfo.valid == true && losing == true)
|
||||
{
|
||||
exitcountdown = (5*TICRATE)/2;
|
||||
}
|
||||
else
|
||||
{
|
||||
exitcountdown = raceexittime+1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ((gametyperules & GTR_BUMPERS)) // Battle Mode exiting
|
||||
{
|
||||
|
|
@ -2622,7 +2639,7 @@ static void P_DeathThink(player_t *player)
|
|||
player->realtime = leveltime - starttime;
|
||||
if (player == &players[consoleplayer])
|
||||
{
|
||||
if (player->spectator || !circuitmap)
|
||||
if (player->spectator)
|
||||
curlap = 0;
|
||||
else if (curlap != UINT32_MAX)
|
||||
curlap++; // This is too complicated to sync to realtime, just sorta hope for the best :V
|
||||
|
|
@ -3044,7 +3061,7 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall
|
|||
return true;
|
||||
}
|
||||
|
||||
if ((player->pflags & PF_NOCONTEST) && (gametyperules & GTR_CIRCUIT)) // 1 for momentum keep, 2 for turnaround
|
||||
if ((player->pflags & PF_NOCONTEST) && (gametyperules & GTR_CIRCUIT) && player->karthud[khud_timeovercam] != 0) // 1 for momentum keep, 2 for turnaround
|
||||
timeover = (player->karthud[khud_timeovercam] > 2*TICRATE ? 2 : 1);
|
||||
else
|
||||
timeover = 0;
|
||||
|
|
@ -3612,7 +3629,7 @@ void P_DoTimeOver(player_t *player)
|
|||
legitimateexit = true; // SRB2kart: losing a race is still seeing it through to the end :p
|
||||
}
|
||||
|
||||
if (netgame && !player->bot && !bossinfo.boss)
|
||||
if (netgame && !player->bot && !(gametyperules & GTR_BOSS))
|
||||
{
|
||||
CON_LogMessage(va(M_GetText("%s ran out of time.\n"), player_names[player-players]));
|
||||
}
|
||||
|
|
@ -3981,7 +3998,7 @@ void P_PlayerThink(player_t *player)
|
|||
player->realtime = leveltime - starttime;
|
||||
if (player == &players[consoleplayer])
|
||||
{
|
||||
if (player->spectator || !circuitmap)
|
||||
if (player->spectator)
|
||||
curlap = 0;
|
||||
else if (curlap != UINT32_MAX)
|
||||
curlap++; // This is too complicated to sync to realtime, just sorta hope for the best :V
|
||||
|
|
|
|||
|
|
@ -30,7 +30,6 @@
|
|||
#include "m_misc.h" // for tunes command
|
||||
#include "m_cond.h" // for conditionsets
|
||||
#include "lua_hook.h" // MusicChange hook
|
||||
#include "k_boss.h" // bossinfo
|
||||
#include "byteptr.h"
|
||||
|
||||
#ifdef HW3SOUND
|
||||
|
|
|
|||
|
|
@ -597,7 +597,7 @@ void ST_runTitleCard(void)
|
|||
|
||||
// SRB2KART
|
||||
// side Zig-Zag positions...
|
||||
if (bossinfo.boss == true)
|
||||
if (K_CheckBossIntro() == true)
|
||||
{
|
||||
// Handle name info...
|
||||
if (bossinfo.enemyname)
|
||||
|
|
@ -792,7 +792,7 @@ void ST_drawTitleCard(void)
|
|||
if (lt_ticker < TTANIMSTART)
|
||||
V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, levelfadecol);
|
||||
|
||||
if (bossinfo.boss == true)
|
||||
if (K_CheckBossIntro() == true)
|
||||
{
|
||||
// WARNING!
|
||||
// https://twitter.com/matthewseiji/status/1485003284196716544
|
||||
|
|
@ -802,7 +802,7 @@ void ST_drawTitleCard(void)
|
|||
#define HITIME 15
|
||||
patch_t *localwarn = (encoremode ? twarn2 : twarn);
|
||||
INT32 transp = (lt_ticker+HITIME) % (LOTIME+HITIME);
|
||||
boolean encorehack = (encoremode && lt_ticker <= PRELEVELTIME+4);
|
||||
boolean encorehack = ((levelfadecol == 0) && lt_ticker <= PRELEVELTIME+4);
|
||||
|
||||
if ((localwarn->width > 0) && (lt_ticker + (HITIME-transp) <= lt_endtime))
|
||||
{
|
||||
|
|
@ -1253,15 +1253,15 @@ void ST_Drawer(void)
|
|||
switch (demo.savemode)
|
||||
{
|
||||
case DSM_NOTSAVING:
|
||||
V_DrawRightAlignedThinString(BASEVIDWIDTH - 2, 2, V_HUDTRANS|V_SNAPTOTOP|V_SNAPTORIGHT|V_ALLOWLOWERCASE|((gametyperules & GTR_BUMPERS) ? V_REDMAP : V_SKYMAP), "(B) or (X): Save replay");
|
||||
V_DrawRightAlignedThinString(BASEVIDWIDTH - 2, 2, V_HUDTRANS|V_SNAPTOTOP|V_SNAPTORIGHT|V_ALLOWLOWERCASE|V_YELLOWMAP, "(B) or (X): Save replay");
|
||||
break;
|
||||
|
||||
case DSM_WILLAUTOSAVE:
|
||||
V_DrawRightAlignedThinString(BASEVIDWIDTH - 2, 2, V_HUDTRANS|V_SNAPTOTOP|V_SNAPTORIGHT|V_ALLOWLOWERCASE|((gametyperules & GTR_BUMPERS) ? V_REDMAP : V_SKYMAP), "Replay will be saved. (Look Backward: Change title)");
|
||||
V_DrawRightAlignedThinString(BASEVIDWIDTH - 2, 2, V_HUDTRANS|V_SNAPTOTOP|V_SNAPTORIGHT|V_ALLOWLOWERCASE|V_YELLOWMAP, "Replay will be saved. (Look Backward: Change title)");
|
||||
break;
|
||||
|
||||
case DSM_WILLSAVE:
|
||||
V_DrawRightAlignedThinString(BASEVIDWIDTH - 2, 2, V_HUDTRANS|V_SNAPTOTOP|V_SNAPTORIGHT|V_ALLOWLOWERCASE|((gametyperules & GTR_BUMPERS) ? V_REDMAP : V_SKYMAP), "Replay will be saved.");
|
||||
V_DrawRightAlignedThinString(BASEVIDWIDTH - 2, 2, V_HUDTRANS|V_SNAPTOTOP|V_SNAPTORIGHT|V_ALLOWLOWERCASE|V_YELLOWMAP, "Replay will be saved.");
|
||||
break;
|
||||
|
||||
case DSM_TITLEENTRY:
|
||||
|
|
|
|||
|
|
@ -111,6 +111,7 @@ TYPEDEF (textpage_t);
|
|||
TYPEDEF (textprompt_t);
|
||||
TYPEDEF (mappoint_t);
|
||||
TYPEDEF (customoption_t);
|
||||
TYPEDEF (gametype_t);
|
||||
TYPEDEF (mapheader_t);
|
||||
TYPEDEF (tolinfo_t);
|
||||
TYPEDEF (cupheader_t);
|
||||
|
|
|
|||
|
|
@ -585,16 +585,16 @@ void V_AdjustXYWithSnap(INT32 *x, INT32 *y, UINT32 options, INT32 dupx, INT32 du
|
|||
}
|
||||
}
|
||||
|
||||
if (options & V_SLIDEIN)
|
||||
if ((options & V_SLIDEIN))
|
||||
{
|
||||
const tic_t length = TICRATE/4;
|
||||
tic_t timer = lt_exitticker;
|
||||
if (bossinfo.boss == true)
|
||||
if (K_CheckBossIntro() == true || G_IsTitleCardAvailable() == false)
|
||||
{
|
||||
if (leveltime <= 3)
|
||||
if (leveltime <= 16)
|
||||
timer = 0;
|
||||
else
|
||||
timer = leveltime-3;
|
||||
timer = leveltime-16;
|
||||
}
|
||||
|
||||
if (timer < length)
|
||||
|
|
|
|||
|
|
@ -1309,12 +1309,12 @@ lumpnum_t W_CheckNumForLongName(const char *name)
|
|||
|
||||
// Look for valid map data through all added files in descendant order.
|
||||
// Get a map marker for WADs, and a standalone WAD file lump inside PK3s.
|
||||
lumpnum_t W_CheckNumForMap(const char *name)
|
||||
lumpnum_t W_CheckNumForMap(const char *name, boolean checktofirst)
|
||||
{
|
||||
lumpnum_t check = INT16_MAX;
|
||||
UINT32 uhash, hash = quickncasehash(name, LUMPNUMCACHENAME);
|
||||
INT32 i;
|
||||
UINT16 firstfile = (partadd_earliestfile == UINT16_MAX) ? 0 : partadd_earliestfile;
|
||||
UINT16 firstfile = (checktofirst || (partadd_earliestfile == UINT16_MAX)) ? 0 : partadd_earliestfile;
|
||||
|
||||
// Check the lumpnumcache first. Loop backwards so that we check
|
||||
// most recent entries first
|
||||
|
|
|
|||
|
|
@ -171,7 +171,7 @@ UINT16 W_CheckNumForFullNamePK3(const char *name, UINT16 wad, UINT16 startlump);
|
|||
UINT16 W_CheckNumForFolderStartPK3(const char *name, UINT16 wad, UINT16 startlump);
|
||||
UINT16 W_CheckNumForFolderEndPK3(const char *name, UINT16 wad, UINT16 startlump);
|
||||
|
||||
lumpnum_t W_CheckNumForMap(const char *name);
|
||||
lumpnum_t W_CheckNumForMap(const char *name, boolean checktofirst);
|
||||
lumpnum_t W_CheckNumForName(const char *name);
|
||||
lumpnum_t W_CheckNumForLongName(const char *name);
|
||||
lumpnum_t W_GetNumForName(const char *name); // like W_CheckNumForName but I_Error on LUMPERROR
|
||||
|
|
|
|||
|
|
@ -98,7 +98,6 @@ static INT32 endtic = -1;
|
|||
static INT32 sorttic = -1;
|
||||
|
||||
intertype_t intertype = int_none;
|
||||
intertype_t intermissiontypes[NUMGAMETYPES];
|
||||
|
||||
static huddrawlist_h luahuddrawlist_intermission;
|
||||
|
||||
|
|
@ -210,7 +209,7 @@ static void Y_CalculateMatchData(UINT8 rankingsmode, void (*comparison)(INT32))
|
|||
else
|
||||
{
|
||||
// set up the levelstring
|
||||
if (bossinfo.boss == true && bossinfo.enemyname)
|
||||
if (bossinfo.valid == true && bossinfo.enemyname)
|
||||
{
|
||||
snprintf(data.levelstring,
|
||||
sizeof data.levelstring,
|
||||
|
|
@ -335,7 +334,7 @@ static void Y_CalculateMatchData(UINT8 rankingsmode, void (*comparison)(INT32))
|
|||
//
|
||||
void Y_IntermissionDrawer(void)
|
||||
{
|
||||
INT32 i, whiteplayer = MAXPLAYERS, x = 4, hilicol = V_YELLOWMAP; // fallback
|
||||
INT32 i, whiteplayer = MAXPLAYERS, x = 4, hilicol = highlightflags;
|
||||
|
||||
if (intertype == int_none || rendermode == render_none)
|
||||
return;
|
||||
|
|
@ -358,11 +357,6 @@ void Y_IntermissionDrawer(void)
|
|||
if (!r_splitscreen)
|
||||
whiteplayer = demo.playback ? displayplayers[0] : consoleplayer;
|
||||
|
||||
if (modeattacking)
|
||||
hilicol = V_ORANGEMAP;
|
||||
else
|
||||
hilicol = ((intertype == int_race) ? V_SKYMAP : V_REDMAP);
|
||||
|
||||
if (sorttic != -1 && intertic > sorttic)
|
||||
{
|
||||
INT32 count = (intertic - sorttic);
|
||||
|
|
@ -375,7 +369,7 @@ void Y_IntermissionDrawer(void)
|
|||
x += (((16 - count) * vid.width) / (8 * vid.dupx));
|
||||
}
|
||||
|
||||
if (intertype == int_race || intertype == int_battle || intertype == int_battletime)
|
||||
if (intertype == int_time || intertype == int_score)
|
||||
{
|
||||
#define NUMFORNEWCOLUMN 8
|
||||
INT32 y = 41, gutter = ((data.numplayers > NUMFORNEWCOLUMN) ? 0 : (BASEVIDWIDTH/2));
|
||||
|
|
@ -398,7 +392,7 @@ void Y_IntermissionDrawer(void)
|
|||
{
|
||||
switch (intertype)
|
||||
{
|
||||
case int_battle:
|
||||
case int_score:
|
||||
timeheader = "SCORE";
|
||||
break;
|
||||
default:
|
||||
|
|
@ -533,7 +527,7 @@ void Y_IntermissionDrawer(void)
|
|||
V_DrawRightAlignedThinString(x+152+gutter, y-1, (data.numplayers > NUMFORNEWCOLUMN ? V_6WIDTHSPACE : 0), "NO CONTEST.");
|
||||
else
|
||||
{
|
||||
if (intertype == int_race || intertype == int_battletime)
|
||||
if (intertype == int_time)
|
||||
{
|
||||
snprintf(strtime, sizeof strtime, "%i'%02i\"%02i", G_TicsToMinutes(data.val[i], true),
|
||||
G_TicsToSeconds(data.val[i]), G_TicsToCentiseconds(data.val[i]));
|
||||
|
|
@ -575,7 +569,7 @@ skiptallydrawer:
|
|||
if (!LUA_HudEnabled(hud_intermissionmessages))
|
||||
return;
|
||||
|
||||
if (timer && grandprixinfo.gp == false && bossinfo.boss == false && !modeattacking)
|
||||
if (timer && grandprixinfo.gp == false && !modeattacking)
|
||||
{
|
||||
char *string;
|
||||
INT32 tickdown = (timer+1)/TICRATE;
|
||||
|
|
@ -669,7 +663,7 @@ void Y_Ticker(void)
|
|||
if (intertic < TICRATE || intertic & 1 || endtic != -1)
|
||||
return;
|
||||
|
||||
if (intertype == int_race || intertype == int_battle || intertype == int_battletime)
|
||||
if (intertype == int_time || intertype == int_score)
|
||||
{
|
||||
{
|
||||
if (!data.rankingsmode && sorttic != -1 && (intertic >= sorttic + 8))
|
||||
|
|
@ -751,29 +745,28 @@ void Y_Ticker(void)
|
|||
//
|
||||
void Y_DetermineIntermissionType(void)
|
||||
{
|
||||
// set to int_none initially
|
||||
intertype = int_none;
|
||||
|
||||
if (gametype == GT_RACE)
|
||||
intertype = int_race;
|
||||
else if (gametype == GT_BATTLE)
|
||||
// no intermission for GP events
|
||||
if (grandprixinfo.gp == true && grandprixinfo.eventmode != GPEVENT_NONE)
|
||||
{
|
||||
if (grandprixinfo.gp == true && bossinfo.boss == false)
|
||||
intertype = int_none;
|
||||
else
|
||||
{
|
||||
UINT8 i = 0, nump = 0;
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
if (!playeringame[i] || players[i].spectator)
|
||||
continue;
|
||||
nump++;
|
||||
}
|
||||
intertype = (nump < 2 ? int_battletime : int_battle);
|
||||
}
|
||||
intertype = int_none;
|
||||
return;
|
||||
}
|
||||
|
||||
// set initially
|
||||
intertype = gametypes[gametype]->intermission;
|
||||
|
||||
// special cases
|
||||
if (intertype == int_scoreortimeattack)
|
||||
{
|
||||
UINT8 i = 0, nump = 0;
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
if (!playeringame[i] || players[i].spectator)
|
||||
continue;
|
||||
nump++;
|
||||
}
|
||||
intertype = (nump < 2 ? int_time : int_score);
|
||||
}
|
||||
else //if (intermissiontypes[gametype] != int_none)
|
||||
intertype = intermissiontypes[gametype];
|
||||
}
|
||||
|
||||
//
|
||||
|
|
@ -830,9 +823,6 @@ void Y_StartIntermission(void)
|
|||
sorttic = max((timer/2) - 2*TICRATE, 2*TICRATE);
|
||||
}
|
||||
|
||||
if (intermissiontypes[gametype] != int_none)
|
||||
intertype = intermissiontypes[gametype];
|
||||
|
||||
// We couldn't display the intermission even if we wanted to.
|
||||
// But we still need to give the players their score bonuses, dummy.
|
||||
//if (dedicated) return;
|
||||
|
|
@ -841,23 +831,18 @@ void Y_StartIntermission(void)
|
|||
if (prevmap >= nummapheaders || !mapheaderinfo[prevmap])
|
||||
I_Error("Y_StartIntermission: Internal map ID %d not found (nummapheaders = %d)", prevmap, nummapheaders);
|
||||
|
||||
if (!(gametyperules & GTR_CIRCUIT) && (timer > 1))
|
||||
S_ChangeMusicInternal("racent", true); // loop it
|
||||
|
||||
switch (intertype)
|
||||
{
|
||||
case int_battle:
|
||||
case int_battletime:
|
||||
case int_score:
|
||||
{
|
||||
if (timer > 1)
|
||||
S_ChangeMusicInternal("racent", true); // loop it
|
||||
|
||||
// Calculate who won
|
||||
if (intertype == int_battle)
|
||||
{
|
||||
Y_CalculateMatchData(0, Y_CompareScore);
|
||||
break;
|
||||
}
|
||||
Y_CalculateMatchData(0, Y_CompareScore);
|
||||
break;
|
||||
}
|
||||
// FALLTHRU
|
||||
case int_race:
|
||||
case int_time:
|
||||
{
|
||||
// Calculate who won
|
||||
Y_CalculateMatchData(0, Y_CompareTime);
|
||||
|
|
@ -1224,12 +1209,8 @@ void Y_VoteDrawer(void)
|
|||
|
||||
if (timer)
|
||||
{
|
||||
INT32 hilicol, tickdown = (timer+1)/TICRATE;
|
||||
if (gametype == GT_RACE)
|
||||
hilicol = V_SKYMAP;
|
||||
else //if (gametype == GT_BATTLE)
|
||||
hilicol = V_REDMAP;
|
||||
V_DrawCenteredString(BASEVIDWIDTH/2, 188, hilicol,
|
||||
INT32 tickdown = (timer+1)/TICRATE;
|
||||
V_DrawCenteredString(BASEVIDWIDTH/2, 188, V_YELLOWMAP,
|
||||
va("Vote ends in %d", tickdown));
|
||||
}
|
||||
}
|
||||
|
|
@ -1569,9 +1550,9 @@ void Y_StartVote(void)
|
|||
levelinfo[i].str[sizeof levelinfo[i].str - 1] = '\0';
|
||||
|
||||
// set up the gtc and gts
|
||||
levelinfo[i].gtc = G_GetGametypeColor(votelevels[i][1]);
|
||||
levelinfo[i].gtc = 73; // yellowmap[0] -- TODO rewrite vote screen
|
||||
if (i == 2 && votelevels[i][1] != votelevels[0][1])
|
||||
levelinfo[i].gts = Gametype_Names[votelevels[i][1]];
|
||||
levelinfo[i].gts = gametypes[votelevels[i][1]]->name;
|
||||
else
|
||||
levelinfo[i].gts = NULL;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,13 +33,12 @@ void Y_SetupVoteFinish(SINT8 pick, SINT8 level);
|
|||
typedef enum
|
||||
{
|
||||
int_none,
|
||||
int_race, // Race
|
||||
int_battle, // Battle (score-based)
|
||||
int_battletime, // Battle (time-based)
|
||||
int_time, // Always time
|
||||
int_score, // Always score
|
||||
int_scoreortimeattack, // Score unless 1P
|
||||
} intertype_t;
|
||||
|
||||
extern intertype_t intertype;
|
||||
extern intertype_t intermissiontypes[NUMGAMETYPES];
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue