Merge branch 'master' into terrain-optimise-fresh

This commit is contained in:
SteelT 2022-09-11 00:36:06 -04:00
commit 51aca52624
90 changed files with 17206 additions and 15606 deletions

View file

@ -31,7 +31,6 @@ m_cheat.c
m_cond.c
m_easing.c
m_fixed.c
m_menu.c
m_misc.c
m_perfstats.c
m_random.c
@ -115,7 +114,12 @@ k_botsearch.c
k_grandprix.c
k_boss.c
k_hud.c
k_menudef.c
k_menufunc.c
k_menudraw.c
k_terrain.c
k_brightmap.c
k_terrain.c
k_director.c
k_follower.c
k_profiles.c

View file

@ -462,7 +462,7 @@ boolean AM_Responder(event_t *ev)
{
//faB: prevent alt-tab in win32 version to activate automap just before
// minimizing the app; doesn't do any harm to the DOS version
if (!gamekeydown[KEY_LALT] && !gamekeydown[KEY_RALT])
if (!gamekeydown[0][KEY_LALT] && !gamekeydown[0][KEY_RALT])
{
bigstate = 0; //added : 24-01-98 : toggle off large view
AM_Start();

View file

@ -21,7 +21,7 @@
#include "command.h"
#include "console.h"
#include "z_zone.h"
#include "m_menu.h"
#include "k_menu.h"
#include "m_misc.h"
#include "m_fixed.h"
#include "m_argv.h"
@ -35,6 +35,7 @@
#include "lua_script.h"
#include "d_netfil.h" // findfile
#include "r_data.h" // Color_cons_t
#include "r_skins.h"
//========
// protos.
@ -81,10 +82,23 @@ CV_PossibleValue_t kartspeed_cons_t[] = {
{KARTSPEED_HARD, "Hard"},
{0, NULL}
};
CV_PossibleValue_t dummykartspeed_cons_t[] = {
{KARTSPEED_EASY, "Easy"},
{KARTSPEED_NORMAL, "Normal"},
{KARTSPEED_HARD, "Hard"},
{0, NULL}
};
CV_PossibleValue_t gpdifficulty_cons_t[] = {
{KARTSPEED_EASY, "Easy"},
{KARTSPEED_NORMAL, "Normal"},
{KARTSPEED_HARD, "Hard"},
{KARTGP_MASTER, "Master"},
{0, NULL}
};
// Filter consvars by EXECVERSION
// First implementation is 2 (1.0.2), so earlier configs default at 1 (1.0.0)
// Also set CV_HIDEN during runtime, after config is loaded
// Also set CV_HIDDEN during runtime, after config is loaded
static boolean execversion_enabled = false;
consvar_t cv_execversion = CVAR_INIT ("execversion","1",CV_CALL,CV_Unsigned, CV_EnforceExecVersion);
@ -1255,7 +1269,7 @@ void CV_RegisterVar(consvar_t *variable)
}
// link the variable in
if (!(variable->flags & CV_HIDEN))
if (!(variable->flags & CV_HIDDEN))
{
variable->next = consvar_vars;
consvar_vars = variable;
@ -1537,8 +1551,7 @@ finish:
// landing point for possiblevalue failures
badinput:
if (var != &cv_nextmap) // Suppress errors for cv_nextmap
CONS_Printf(M_GetText("\"%s\" is not a possible value for \"%s\"\n"), valstr, var->name);
CONS_Printf(M_GetText("\"%s\" is not a possible value for \"%s\"\n"), valstr, var->name);
// default value not valid... ?!
if (var->defaultvalue == valstr)
@ -1804,6 +1817,15 @@ static void CV_SetCVar(consvar_t *var, const char *value, boolean stealth)
return;
}
if (var == &cv_kartspeed && !M_SecretUnlocked(SECRET_HARDSPEED))
{
if (!stricmp(value, "Hard") || atoi(value) >= KARTSPEED_HARD)
{
CONS_Printf(M_GetText("You haven't unlocked this yet!\n"));
return;
}
}
if (var == &cv_forceskin)
{
INT32 skin = R_SkinAvailable(value);
@ -1939,6 +1961,7 @@ void CV_AddValue(consvar_t *var, INT32 increment)
if (var->PossibleValue)
{
/*
if (var == &cv_nextmap)
{
// Special case for the nextmap variable, used only directly from the menu
@ -1972,9 +1995,11 @@ void CV_AddValue(consvar_t *var, INT32 increment)
return;
}
}
else
*/
#define MINVAL 0
#define MAXVAL 1
else if (var->PossibleValue[MINVAL].strvalue && !strcmp(var->PossibleValue[MINVAL].strvalue, "MIN"))
if (var->PossibleValue[MINVAL].strvalue && !strcmp(var->PossibleValue[MINVAL].strvalue, "MIN"))
{
#ifdef PARANOIA
if (!var->PossibleValue[MAXVAL].strvalue)
@ -2079,9 +2104,16 @@ void CV_AddValue(consvar_t *var, INT32 increment)
return;
}
}
else if (var == &cv_kartspeed)
else if (var->PossibleValue == kartspeed_cons_t
|| var->PossibleValue == dummykartspeed_cons_t
|| var->PossibleValue == gpdifficulty_cons_t)
{
max = (M_SecretUnlocked(SECRET_HARDSPEED) ? 3 : 2);
if (!M_SecretUnlocked(SECRET_HARDSPEED))
{
max = KARTSPEED_NORMAL+1;
if (var->PossibleValue == kartspeed_cons_t)
max++; // Accommodate KARTSPEED_AUTO
}
}
#ifdef PARANOIA
if (currentindice == -1)
@ -2122,58 +2154,10 @@ static void CV_EnforceExecVersion(void)
CV_StealthSetValue(&cv_execversion, EXECVERSION);
}
static boolean CV_FilterJoyAxisVars(consvar_t *v, const char *valstr)
{
#if 1
// We don't have changed axis defaults yet
(void)v;
(void)valstr;
#else
UINT8 i;
// If ALL axis settings are previous defaults, set them to the new defaults
// EXECVERSION < 26 (2.1.21)
for (i = 0; i < 4; i++)
{
if (joyaxis_default[i])
{
if (!stricmp(v->name, "joyaxis_fire"))
{
if (joyaxis_count[i] > 7) return false;
else if (joyaxis_count[i] == 7) return true;
if (!stricmp(valstr, "None")) joyaxis_count[i]++;
else joyaxis_default[i] = false;
}
// reset all axis settings to defaults
if (joyaxis_count[i] == 7)
{
switch (i)
{
default:
COM_BufInsertText(va("%s \"%s\"\n", cv_turnaxis[0].name, cv_turnaxis[0].defaultvalue));
COM_BufInsertText(va("%s \"%s\"\n", cv_moveaxis[0].name, cv_moveaxis[0].defaultvalue));
COM_BufInsertText(va("%s \"%s\"\n", cv_brakeaxis[0].name, cv_brakeaxis[0].defaultvalue));
COM_BufInsertText(va("%s \"%s\"\n", cv_aimaxis[0].name, cv_aimaxis[0].defaultvalue));
COM_BufInsertText(va("%s \"%s\"\n", cv_lookaxis[0].name, cv_lookaxis[0].defaultvalue));
COM_BufInsertText(va("%s \"%s\"\n", cv_fireaxis[0].name, cv_fireaxis[0].defaultvalue));
COM_BufInsertText(va("%s \"%s\"\n", cv_driftaxis[0].name, cv_driftaxis[0].defaultvalue));
break;
}
joyaxis_count[i]++;
return false;
}
}
}
#endif
// we haven't reached our counts yet, or we're not default
return true;
}
static boolean CV_FilterVarByVersion(consvar_t *v, const char *valstr)
{
(void)valstr;
// True means allow the CV change, False means block it
// We only care about CV_SAVE because this filters the user's config files
@ -2191,11 +2175,6 @@ static boolean CV_FilterVarByVersion(consvar_t *v, const char *valstr)
|| !stricmp(v->name, "mousemove2"))
return false;
#endif
// axis defaults were changed to be friendly to 360 controllers
// if ALL axis settings are defaults, then change them to new values
if (!CV_FilterJoyAxisVars(v, valstr))
return false;
}
return true;

View file

@ -120,7 +120,7 @@ typedef enum
CV_SHOWMODIF = 128, // say something when modified
CV_SHOWMODIFONETIME = 256, // same but will be reset to 0 when modified, set in toggle
CV_NOSHOWHELP = 512, // Don't show variable in the HELP list Tails 08-13-2002
CV_HIDEN = 1024, // variable is not part of the cvar list so cannot be accessed by the console
CV_HIDDEN = 1024, // variable is not part of the cvar list so cannot be accessed by the console
// can only be set when we have the pointer to it
// used on menus
CV_CHEAT = 2048, // Don't let this be used in multiplayer unless cheats are on.
@ -175,7 +175,7 @@ extern CV_PossibleValue_t CV_Natural[];
#define KARTSPEED_NORMAL 1
#define KARTSPEED_HARD 2
#define KARTGP_MASTER 3 // Not a speed setting, gives the hardest speed with maxed out bots
extern CV_PossibleValue_t kartspeed_cons_t[];
extern CV_PossibleValue_t kartspeed_cons_t[], dummykartspeed_cons_t[], gpdifficulty_cons_t[];
extern consvar_t cv_execversion;

View file

@ -31,7 +31,7 @@
#include "i_system.h"
#include "i_threads.h"
#include "d_main.h"
#include "m_menu.h"
#include "k_menu.h"
#include "filesrch.h"
#include "m_misc.h"
@ -154,28 +154,6 @@ static CV_PossibleValue_t backcolor_cons_t[] = {{0, "White"}, {1, "Black"}, {
{0, NULL}};
consvar_t cons_backcolor = CVAR_INIT ("con_backcolor", "Black", CV_CALL|CV_SAVE, backcolor_cons_t, CONS_backcolor_Change);
static CV_PossibleValue_t menuhighlight_cons_t[] =
{
{0, "Game type"},
{V_YELLOWMAP, "Always yellow"},
{V_PURPLEMAP, "Always purple"},
{V_GREENMAP, "Always green"},
{V_BLUEMAP, "Always blue"},
{V_REDMAP, "Always red"},
{V_GRAYMAP, "Always gray"},
{V_ORANGEMAP, "Always orange"},
{V_SKYMAP, "Always sky-blue"},
{V_GOLDMAP, "Always gold"},
{V_LAVENDERMAP, "Always lavender"},
{V_AQUAMAP, "Always aqua-green"},
{V_MAGENTAMAP, "Always magenta"},
{V_PINKMAP, "Always pink"},
{V_BROWNMAP, "Always brown"},
{V_TANMAP, "Always tan"},
{0, NULL}
};
consvar_t cons_menuhighlight = CVAR_INIT ("menuhighlight", "Game type", CV_SAVE, menuhighlight_cons_t, NULL);
static void CON_Print(char *msg);
//
@ -466,7 +444,6 @@ void CON_Init(void)
CV_RegisterVar(&cons_height);
CV_RegisterVar(&cons_backpic);
CV_RegisterVar(&cons_backcolor);
CV_RegisterVar(&cons_menuhighlight);
COM_AddCommand("bind", CONS_Bind_f);
}
else
@ -938,7 +915,7 @@ boolean CON_Responder(event_t *ev)
if (modeattacking || metalrecording || marathonmode)
return false;
if (ev->data1 >= KEY_MOUSE1) // See also: HUD_Responder
if (ev->data1 >= NUMKEYS) // See also: HUD_Responder
{
INT32 i;
for (i = 0; i < num_gamecontrols; i++)

View file

@ -60,7 +60,7 @@ extern INT32 con_clearlines; // lines of top of screen to refresh
extern boolean con_hudupdate; // hud messages have changed, need refresh
extern UINT32 con_scalefactor; // console text scale factor
extern consvar_t cons_backcolor, cons_menuhighlight;
extern consvar_t cons_backcolor;
extern UINT8 *yellowmap, *purplemap, *greenmap, *bluemap, *graymap, *redmap, *orangemap,\
*skymap, *goldmap, *lavendermap, *aquamap, *magentamap, *pinkmap, *brownmap, *tanmap;

View file

@ -27,7 +27,7 @@
#include "hu_stuff.h"
#include "keys.h"
#include "g_input.h" // JOY1
#include "m_menu.h"
#include "k_menu.h"
#include "console.h"
#include "d_netfil.h"
#include "byteptr.h"
@ -903,13 +903,13 @@ static void SV_SendServerInfo(INT32 node, tic_t servertime)
netbuffer->u.serverinfo.leveltime = (tic_t)LONG(leveltime);
netbuffer->u.serverinfo.numberofplayer = (UINT8)D_NumPlayers();
netbuffer->u.serverinfo.maxplayer = (UINT8)(min((dedicated ? MAXPLAYERS-1 : MAXPLAYERS), cv_maxplayers.value));
netbuffer->u.serverinfo.maxplayer = (UINT8)(min((dedicated ? MAXPLAYERS-1 : MAXPLAYERS), cv_maxconnections.value));
if (!node)
netbuffer->u.serverinfo.refusereason = 0;
else if (!cv_allownewplayer.value)
netbuffer->u.serverinfo.refusereason = 1;
else if (D_NumPlayers() >= cv_maxplayers.value)
else if (D_NumPlayers() >= cv_maxconnections.value)
netbuffer->u.serverinfo.refusereason = 2;
else
netbuffer->u.serverinfo.refusereason = 0;
@ -1073,7 +1073,7 @@ static boolean SV_SendServerConfig(INT32 node)
netbuffer->u.servercfg.gametype = (UINT8)gametype;
netbuffer->u.servercfg.modifiedgame = (UINT8)modifiedgame;
netbuffer->u.servercfg.maxplayer = (UINT8)(min((dedicated ? MAXPLAYERS-1 : MAXPLAYERS), cv_maxplayers.value));
netbuffer->u.servercfg.maxplayer = (UINT8)(min((dedicated ? MAXPLAYERS-1 : MAXPLAYERS), cv_maxconnections.value));
netbuffer->u.servercfg.allownewplayer = cv_allownewplayer.value;
netbuffer->u.servercfg.discordinvites = (boolean)cv_discordinvites.value;
@ -1486,7 +1486,7 @@ static void M_ConfirmConnect(event_t *ev)
#ifndef NONET
if (ev->type == ev_keydown)
{
if (ev->data1 == ' ' || ev->data1 == 'y' || ev->data1 == KEY_ENTER || ev->data1 == gamecontrol[0][gc_accelerate][0] || ev->data1 == gamecontrol[0][gc_accelerate][1])
if (G_PlayerInputDown(0, gc_a, 1))
{
if (totalfilesrequestednum > 0)
{
@ -1509,7 +1509,7 @@ static void M_ConfirmConnect(event_t *ev)
M_ClearMenus(true);
}
else if (ev->data1 == 'n' || ev->data1 == KEY_ESCAPE|| ev->data1 == gamecontrol[0][gc_brake][0] || ev->data1 == gamecontrol[0][gc_brake][1])
else if (G_PlayerInputDown(0, gc_x, 1))
{
cl_mode = CL_ABORTED;
M_ClearMenus(true);
@ -1910,6 +1910,8 @@ static boolean CL_ServerConnectionTicker(const char *tmpsave, tic_t *oldtic, tic
{
I_OsPolling();
memset(deviceResponding, false, sizeof (deviceResponding));
if (cl_mode == CL_CONFIRMCONNECT)
{
D_ProcessEvents(); //needed for menu system to receive inputs
@ -1920,7 +1922,7 @@ static boolean CL_ServerConnectionTicker(const char *tmpsave, tic_t *oldtic, tic
G_MapEventsToControls(&events[eventtail]);
}
if ((gamekeydown[KEY_ESCAPE] || gamekeydown[KEY_JOY1+1]) || cl_mode == CL_ABORTED)
if (G_PlayerInputDown(0, gc_x, 1) || cl_mode == CL_ABORTED)
{
CONS_Printf(M_GetText("Network game synchronization aborted.\n"));
// M_StartMessage(M_GetText("Network game synchronization aborted.\n\nPress ESC\n"), NULL, MM_NOTHING);
@ -1928,7 +1930,8 @@ static boolean CL_ServerConnectionTicker(const char *tmpsave, tic_t *oldtic, tic
D_QuitNetGame();
CL_Reset();
D_StartTitle();
memset(gamekeydown, 0, NUMKEYS);
memset(gamekeydown, 0, sizeof (gamekeydown));
memset(deviceResponding, false, sizeof (deviceResponding));
return false;
}
@ -1951,11 +1954,11 @@ static boolean CL_ServerConnectionTicker(const char *tmpsave, tic_t *oldtic, tic
}
CL_DrawConnectionStatus();
#ifdef HAVE_THREADS
I_lock_mutex(&m_menu_mutex);
I_lock_mutex(&k_menu_mutex);
#endif
M_Drawer(); //Needed for drawing messageboxes on the connection screen
#ifdef HAVE_THREADS
I_unlock_mutex(m_menu_mutex);
I_unlock_mutex(k_menu_mutex);
#endif
I_UpdateNoVsync(); // page flip or blit buffer
if (moviemode)
@ -2011,6 +2014,8 @@ static void CL_ConnectToServer(void)
CONS_Printf(M_GetText("Contacting the server...\n"));
}
if (cv_currprofile.value == -1)
PR_ApplyProfilePretend(cv_ttlprofilen.value, 0);
if (gamestate == GS_INTERMISSION)
Y_EndIntermission(); // clean up intermission graphics etc
if (gamestate == GS_VOTING)
@ -2018,6 +2023,8 @@ static void CL_ConnectToServer(void)
DEBFILE(va("waiting %d nodes\n", doomcom->numnodes));
G_SetGamestate(GS_WAITINGPLAYERS);
if (wipegamestate == GS_MENU)
M_ClearMenus(true);
wipegamestate = GS_WAITINGPLAYERS;
ClearAdminPlayers();
@ -2033,11 +2040,14 @@ static void CL_ConnectToServer(void)
if (i != -1)
{
char *gametypestr = serverlist[i].info.gametypename;
CONS_Printf(M_GetText("Connecting to: %s\n"), serverlist[i].info.servername);
CON_LogMessage(va(M_GetText("Connecting to: %s\n"), serverlist[i].info.servername));
gametypestr[sizeof serverlist[i].info.gametypename - 1] = '\0';
CONS_Printf(M_GetText("Gametype: %s\n"), gametypestr);
CONS_Printf(M_GetText("Version: %d.%d\n"),
serverlist[i].info.version, serverlist[i].info.subversion);
CON_LogMessage(va(M_GetText("Gametype: %s\n"), gametypestr));
CON_LogMessage(va(M_GetText("Version: %d.%d\n"),
serverlist[i].info.version, serverlist[i].info.subversion));
}
SL_ClearServerList(servernode);
#endif
@ -2069,6 +2079,16 @@ static void CL_ConnectToServer(void)
DEBFILE(va("Synchronisation Finished\n"));
displayplayers[0] = consoleplayer;
// At this point we've succesfully joined the server, if we joined by IP (ie: a valid joinedIP string), save it!
// @TODO: Save the proper server name, right now it doesn't seem like we can consistently retrieve it from the serverlist....?
// It works... sometimes but not always which is weird.
if (*joinedIP && strlen(joinedIP)) // false if we have "" which is \0
M_AddToJoinedIPs(joinedIP, netbuffer->u.serverinfo.servername);
strcpy(joinedIP, ""); // And empty this for good measure regardless of whether or not we actually used it.
}
#ifndef NONET
@ -2237,6 +2257,10 @@ static void Command_ReloadBan(void) //recheck ban.txt
static void Command_connect(void)
{
// By default, clear the saved address that we'd save after succesfully joining just to be sure:
strcpy(joinedIP, "");
if (COM_Argc() < 2 || *COM_Argv(1) == 0)
{
CONS_Printf(M_GetText(
@ -2252,6 +2276,33 @@ static void Command_connect(void)
CONS_Printf(M_GetText("You cannot connect while in a game. End this game first.\n"));
return;
}
else if (cv_currprofile.value == 0)
{
CONS_Printf(M_GetText("You cannot connect while using the Guest Profile. Use a Custom Profile to play Online.\n"));
return;
}
else if (cv_currprofile.value == -1)
{
// No profile set, we're attempting to connect from the title screen. (Discord RPC / connect command)
// Automatically apply the last profiles for every potential split player.
// Make sure Player 1's Profile ISN'T the guest profile even if we do that.
UINT8 i;
CONS_Printf(M_GetText("No Profile set, attempting to use last used Profiles...\n"));
for (i = 0; i < cv_splitplayers.value; i++)
{
if (cv_lastprofile[i].value || i > 0)
PR_ApplyProfile(cv_lastprofile[i].value, i);
else
{
CONS_Printf(M_GetText("Player 1's last used Profile is the Guest Profile, which cannot be used to play Online.\n"));
return;
}
}
CONS_Printf(M_GetText("Profiles have been automatically set according to the last used Profiles.\n"));
}
// modified game check: no longer handled
// we don't request a restart unless the filelist differs
@ -2292,6 +2343,10 @@ static void Command_connect(void)
servernode = I_NetMakeNodewPort(COM_Argv(1), COM_Argv(2));
else // address only, or address:port
servernode = I_NetMakeNode(COM_Argv(1));
// Last IPs joined:
// Keep the address we typed in memory so that we can save it if we *succesfully* join the server
strcpy(joinedIP, COM_Argv(1));
}
else
{
@ -2310,6 +2365,7 @@ static void Command_connect(void)
SplitScreen_OnChange();
}
M_ClearMenus(true);
CL_ConnectToServer();
}
#endif
@ -3042,7 +3098,7 @@ consvar_t cv_joinnextround = CVAR_INIT ("joinnextround", "Off", CV_NETVAR, CV_On
#endif
static CV_PossibleValue_t maxplayers_cons_t[] = {{2, "MIN"}, {MAXPLAYERS, "MAX"}, {0, NULL}};
consvar_t cv_maxplayers = CVAR_INIT ("maxplayers", "8", CV_SAVE|CV_CALL, maxplayers_cons_t, Joinable_OnChange);
consvar_t cv_maxconnections = CVAR_INIT ("maxconnections", "16", CV_SAVE|CV_CALL, maxplayers_cons_t, Joinable_OnChange);
static CV_PossibleValue_t joindelay_cons_t[] = {{1, "MIN"}, {3600, "MAX"}, {0, "Off"}, {0, NULL}};
consvar_t cv_joindelay = CVAR_INIT ("joindelay", "10", CV_SAVE|CV_NETVAR, joindelay_cons_t, NULL);
@ -3078,7 +3134,7 @@ static void Joinable_OnChange(void)
if (!server)
return;
maxplayer = (UINT8)(min((dedicated ? MAXPLAYERS-1 : MAXPLAYERS), cv_maxplayers.value));
maxplayer = (UINT8)(min((dedicated ? MAXPLAYERS-1 : MAXPLAYERS), cv_maxconnections.value));
WRITEUINT8(p, maxplayer);
WRITEUINT8(p, cv_allownewplayer.value);
@ -3470,6 +3526,7 @@ static void Got_AddBot(UINT8 **p, INT32 playernum)
players[newplayernum].splitscreenindex = 0;
players[newplayernum].bot = true;
players[newplayernum].botvars.difficulty = difficulty;
players[newplayernum].lives = 9;
players[newplayernum].skincolor = skins[skinnum].prefcolor;
sprintf(player_names[newplayernum], "%s", skins[skinnum].realname);
@ -3614,7 +3671,7 @@ boolean SV_SpawnServer(void)
if (!serverrunning)
{
CONS_Printf(M_GetText("Starting Server....\n"));
CON_LogMessage(M_GetText("Starting Server....\n"));
serverrunning = true;
SV_ResetServer();
SV_GenContext();
@ -3670,6 +3727,7 @@ void SV_StartSinglePlayerServer(void)
server = true;
netgame = false;
multiplayer = false;
strcpy(joinedIP, ""); // Make sure to empty this so that we don't save garbage when we start our own game. (because yes we use this for netgames too....)
if ((modeattacking == ATTACKING_CAPSULES) || (bossinfo.boss == true))
{
@ -3728,7 +3786,7 @@ static void HandleConnect(SINT8 node)
// Sal: Dedicated mode is INCREDIBLY hacked together.
// If a server filled out, then it'd overwrite the host and turn everyone into weird husks.....
// It's too much effort to legimately fix right now. Just prevent it from reaching that state.
UINT8 maxplayers = min((dedicated ? MAXPLAYERS-1 : MAXPLAYERS), cv_maxplayers.value);
UINT8 maxplayers = min((dedicated ? MAXPLAYERS-1 : MAXPLAYERS), cv_maxconnections.value);
if (bannednode && bannednode[node])
SV_SendRefuse(node, M_GetText("You have been banned\nfrom the server."));
@ -5583,11 +5641,11 @@ void NetUpdate(void)
{
resptime = nowtime;
#ifdef HAVE_THREADS
I_lock_mutex(&m_menu_mutex);
I_lock_mutex(&k_menu_mutex);
#endif
M_Ticker();
#ifdef HAVE_THREADS
I_unlock_mutex(m_menu_mutex);
I_unlock_mutex(k_menu_mutex);
#endif
CON_Ticker();
}

View file

@ -445,7 +445,7 @@ extern tic_t servermaxping;
extern boolean server_lagless;
extern consvar_t cv_netticbuffer, cv_allownewplayer, cv_maxplayers, cv_joindelay;
extern consvar_t cv_netticbuffer, cv_allownewplayer, cv_maxconnections, cv_joindelay;
extern consvar_t cv_resynchattempts, cv_blamecfail;
extern consvar_t cv_maxsend, cv_noticedownload, cv_downloadspeed;

View file

@ -25,9 +25,6 @@ typedef enum
ev_console,
ev_mouse,
ev_joystick,
ev_joystick2,
ev_joystick3,
ev_joystick4,
} evtype_t;
// Event structure.
@ -37,6 +34,7 @@ typedef struct
INT32 data1; // keys / mouse/joystick buttons
INT32 data2; // mouse/joystick x move
INT32 data3; // mouse/joystick y move
INT32 device; // which player's device it belongs to
} event_t;
//

View file

@ -44,7 +44,7 @@
#include "i_threads.h"
#include "i_video.h"
#include "m_argv.h"
#include "m_menu.h"
#include "k_menu.h"
#include "m_misc.h"
#include "p_setup.h"
#include "p_saveg.h"
@ -184,7 +184,9 @@ void D_ProcessEvents(void)
event_t *ev;
boolean eaten;
boolean menuresponse = false;
memset(deviceResponding, false, sizeof (deviceResponding));
for (; eventtail != eventhead; eventtail = (eventtail+1) & (MAXEVENTS-1))
{
ev = &events[eventtail];
@ -205,25 +207,6 @@ void D_ProcessEvents(void)
continue;
}
// Menu input
#ifdef HAVE_THREADS
I_lock_mutex(&m_menu_mutex);
#endif
{
eaten = M_Responder(ev);
}
#ifdef HAVE_THREADS
I_unlock_mutex(m_menu_mutex);
#endif
if (eaten)
continue; // menu ate the event
// Demo input:
if (demo.playback)
if (M_DemoResponder(ev))
continue; // demo ate the event
// console input
#ifdef HAVE_THREADS
I_lock_mutex(&con_mutex);
@ -241,8 +224,37 @@ void D_ProcessEvents(void)
continue; // ate the event
}
// Menu input
menuresponse = true;
#ifdef HAVE_THREADS
I_lock_mutex(&k_menu_mutex);
#endif
{
eaten = M_Responder(ev);
}
#ifdef HAVE_THREADS
I_unlock_mutex(k_menu_mutex);
#endif
if (eaten)
continue; // menu ate the event
// Demo input:
/*
if (demo.playback)
if (M_DemoResponder(ev))
continue; // demo ate the event
*/
G_Responder(ev);
}
// Reset menu controls when no event is processed
if (!menuresponse)
{
M_MapMenuControls(NULL);
}
}
//
@ -321,7 +333,7 @@ static void D_Display(void)
// set for all later
wipedefindex = gamestate; // wipe_xxx_toblack
if (gamestate == GS_TITLESCREEN && wipegamestate != GS_INTRO)
wipedefindex = wipe_timeattack_toblack;
wipedefindex = wipe_titlescreen_toblack;
if (wipetypepre < 0 || !F_WipeExists(wipetypepre))
wipetypepre = wipedefs[wipedefindex];
@ -335,7 +347,7 @@ static void D_Display(void)
F_WipeStartScreen();
F_WipeColorFill(31);
F_WipeEndScreen();
F_RunWipe(wipetypepre, gamestate != GS_TIMEATTACK, "FADEMAP0", false, false);
F_RunWipe(wipetypepre, gamestate != GS_MENU, "FADEMAP0", false, false);
}
if (gamestate != GS_LEVEL && rendermode != render_none)
@ -348,7 +360,7 @@ static void D_Display(void)
}
else //dedicated servers
{
F_RunWipe(wipedefs[wipedefindex], gamestate != GS_TIMEATTACK, "FADEMAP0", false, false);
F_RunWipe(wipedefs[wipedefindex], gamestate != GS_MENU, "FADEMAP0", false, false);
wipegamestate = gamestate;
}
@ -388,7 +400,7 @@ static void D_Display(void)
HU_Drawer();
break;
case GS_TIMEATTACK:
case GS_MENU:
break;
case GS_INTRO:
@ -541,9 +553,8 @@ static void D_Display(void)
if (rendermode == render_soft)
{
VID_BlitLinearScreen(screens[0], screens[1], vid.width*vid.bpp, vid.height, vid.width*vid.bpp, vid.rowbytes);
Y_ConsiderScreenBuffer();
usebuffer = true;
}
lastdraw = false;
}
@ -595,11 +606,11 @@ static void D_Display(void)
vid.recalc = 0;
#ifdef HAVE_THREADS
I_lock_mutex(&m_menu_mutex);
I_lock_mutex(&k_menu_mutex);
#endif
M_Drawer(); // menu is drawn even on top of everything
#ifdef HAVE_THREADS
I_unlock_mutex(m_menu_mutex);
I_unlock_mutex(k_menu_mutex);
#endif
// focus lost moved to M_Drawer
@ -623,7 +634,7 @@ static void D_Display(void)
{
F_WipeEndScreen();
F_RunWipe(wipedefs[wipedefindex], gamestate != GS_TIMEATTACK && gamestate != GS_TITLESCREEN, "FADEMAP0", true, false);
F_RunWipe(wipedefs[wipedefindex], gamestate != GS_MENU && gamestate != GS_TITLESCREEN, "FADEMAP0", true, false);
}
// reset counters so timedemo doesn't count the wipe duration
@ -990,25 +1001,13 @@ void D_StartTitle(void)
G_SetGametype(GT_RACE); // SRB2kart
paused = false;
advancedemo = false;
F_InitMenuPresValues();
F_StartTitleScreen();
currentMenu = &MainDef; // reset the current menu ID
// Reset the palette
if (rendermode != render_none)
V_SetPaletteLump("PLAYPAL");
// The title screen is obviously not a tutorial! (Unless I'm mistaken)
/*
if (tutorialmode && tutorialgcs)
{
G_CopyControls(gamecontrol[0], gamecontroldefault[0][gcs_custom], gcl_full, num_gcl_full); // using gcs_custom as temp storage
M_StartMessage("Do you want to \x82save the recommended \x82movement controls?\x80\n\nPress 'Y' or 'Enter' to confirm\nPress 'N' or any key to keep \nyour current controls",
M_TutorialSaveControlResponse, MM_YESNO);
}
*/
tutorialmode = false;
}
@ -1270,6 +1269,9 @@ void D_SRB2Main(void)
strcpy(savegamename, SAVEGAMENAME"%u.ssg");
strcpy(liveeventbackup, "live"SAVEGAMENAME".bkp"); // intentionally not ending with .ssg
// Init the joined IP table for quick rejoining of past games.
M_InitJoinedIPArray();
{
const char *userhome = D_Home(); //Alam: path to home
@ -1342,6 +1344,8 @@ void D_SRB2Main(void)
}
}
M_LoadJoinedIPs(); // load joined ips
// Create addons dir
snprintf(addonsdir, sizeof addonsdir, "%s%s%s", srb2home, PATHSEP, "addons");
I_mkdir(addonsdir, 0755);
@ -1398,13 +1402,6 @@ void D_SRB2Main(void)
// adapt tables to SRB2's needs, including extra slots for dehacked file support
P_PatchInfoTables();
// initiate menu metadata before SOCcing them
M_InitMenuPresTables();
// init title screen display params
if (M_GetUrlProtocolArg() || M_CheckParm("-connect"))
F_InitMenuPresValues();
//---------------------------------------------------- READY TIME
// we need to check for dedicated before initialization of some subsystems
@ -1415,10 +1412,6 @@ void D_SRB2Main(void)
// Make backups of some SOCcable tables.
P_BackupTables();
// Setup character tables
// Have to be done here before files are loaded
M_InitCharacterTables();
// load wad, including the main wad file
CONS_Printf("W_InitMultipleFiles(): Adding IWAD and main PWADs.\n");
W_InitMultipleFiles(startupiwads, false);
@ -1565,6 +1558,9 @@ void D_SRB2Main(void)
//--------------------------------------------------------- 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)
@ -1717,9 +1713,9 @@ void D_SRB2Main(void)
// user settings come before "+" parameters.
if (dedicated)
COM_ImmedExecute(va("exec \"%s"PATHSEP"kartserv.cfg\"\n", srb2home));
COM_ImmedExecute(va("exec \"%s"PATHSEP"ringserv.cfg\"\n", srb2home));
else
COM_ImmedExecute(va("exec \"%s"PATHSEP"kartexec.cfg\" -noerror\n", srb2home));
COM_ImmedExecute(va("exec \"%s"PATHSEP"ringexec.cfg\" -noerror\n", srb2home));
if (!autostart)
M_PushSpecialParameters(); // push all "+" parameters at the command buffer
@ -1785,6 +1781,10 @@ void D_SRB2Main(void)
CV_ClearChangedFlags();
// Has to be done before anything else so skin, color, etc in command buffer has an affect.
// ttlprofilen used because it's roughly equivalent in functionality - a QoL aid for quickly getting from startup to action
PR_ApplyProfile(cv_ttlprofilen.value, 0);
// Do this here so if you run SRB2 with eg +timelimit 5, the time limit counts
// as having been modified for the first game.
M_PushSpecialParameters(); // push all "+" parameter at the command buffer
@ -1886,7 +1886,6 @@ void D_SRB2Main(void)
}
else if (M_CheckParm("-skipintro"))
{
F_InitMenuPresValues();
F_StartTitleScreen();
}
else

View file

@ -14,6 +14,7 @@
#ifndef __D_MAIN__
#define __D_MAIN__
#include "k_profiles.h" // PR_LoadProfiles()
#include "d_event.h"
#include "w_wad.h" // for MAX_WADFILES

View file

@ -21,7 +21,7 @@
#include "g_game.h"
#include "hu_stuff.h"
#include "g_input.h"
#include "m_menu.h"
#include "k_menu.h"
#include "r_local.h"
#include "r_skins.h"
#include "p_local.h"
@ -231,7 +231,7 @@ static CV_PossibleValue_t joyport_cons_t[] = {{1, "/dev/js0"}, {2, "/dev/js1"},
{4, "/dev/js3"}, {0, NULL}};
#else
// accept whatever value - it is in fact the joystick device number
#define usejoystick_cons_t NULL
static CV_PossibleValue_t usejoystick_cons_t[] = {{-1, "MIN"}, {MAXGAMEPADS, "MAX"}, {0, NULL}};
#endif
static CV_PossibleValue_t teamscramble_cons_t[] = {{0, "Off"}, {1, "Random"}, {2, "Points"}, {0, NULL}};
@ -249,11 +249,11 @@ static consvar_t cv_fishcake = CVAR_INIT ("fishcake", "Off", CV_CALL|CV_NOSHOWHE
#endif
static consvar_t cv_dummyconsvar = CVAR_INIT ("dummyconsvar", "Off", CV_CALL|CV_NOSHOWHELP, CV_OnOff, DummyConsvar_OnChange);
consvar_t cv_restrictskinchange = CVAR_INIT ("restrictskinchange", "No", CV_NETVAR|CV_CHEAT, CV_YesNo, NULL);
consvar_t cv_restrictskinchange = CVAR_INIT ("restrictskinchange", "Yes", CV_NETVAR|CV_CHEAT, CV_YesNo, NULL);
consvar_t cv_allowteamchange = CVAR_INIT ("allowteamchange", "Yes", CV_NETVAR, CV_YesNo, NULL);
static CV_PossibleValue_t ingamecap_cons_t[] = {{0, "MIN"}, {MAXPLAYERS-1, "MAX"}, {0, NULL}};
consvar_t cv_ingamecap = CVAR_INIT ("ingamecap", "0", CV_NETVAR, ingamecap_cons_t, NULL);
static CV_PossibleValue_t maxplayers_cons_t[] = {{1, "MIN"}, {MAXPLAYERS, "MAX"}, {0, NULL}};
consvar_t cv_maxplayers = CVAR_INIT ("maxplayers", "8", CV_NETVAR, maxplayers_cons_t, NULL);
consvar_t cv_startinglives = CVAR_INIT ("startinglives", "3", CV_NETVAR|CV_CHEAT|CV_NOSHOWHELP, startingliveslimit_cons_t, NULL);
@ -301,6 +301,28 @@ consvar_t cv_followercolor[MAXSPLITSCREENPLAYERS] = {
CVAR_INIT ("followercolor4", "1", CV_SAVE|CV_CALL|CV_NOINIT, Followercolor_cons_t, Followercolor4_OnChange)
};
// last selected profile, unaccessible cvar only set internally but is saved.
// It's used to know what profile to autoload you to when you get into the character setup.
static CV_PossibleValue_t lastprofile_cons_t[] = {{-1, "MIN"}, {MAXPROFILES, "MAX"}, {0, NULL}};
consvar_t cv_lastprofile[MAXSPLITSCREENPLAYERS] = {
CVAR_INIT ("lastprofile", "0", CV_SAVE|CV_HIDDEN, lastprofile_cons_t, NULL),
CVAR_INIT ("lastprofile2", "0", CV_SAVE|CV_HIDDEN, lastprofile_cons_t, NULL),
CVAR_INIT ("lastprofile3", "0", CV_SAVE|CV_HIDDEN, lastprofile_cons_t, NULL),
CVAR_INIT ("lastprofile4", "0", CV_SAVE|CV_HIDDEN, lastprofile_cons_t, NULL),
};
// currently loaded profile for P1 menuing.
// You choose this profile when starting the game, this will also set lastprofile[0]
consvar_t cv_currprofile = CVAR_INIT ("currprofile", "-1", CV_HIDDEN, lastprofile_cons_t, NULL);
// This one is used exclusively for the titlescreen
consvar_t cv_ttlprofilen = CVAR_INIT ("ttlprofilen", "0", CV_SAVE, lastprofile_cons_t, NULL);
// Cvar for using splitscreen with 1 device.
consvar_t cv_splitdevice = CVAR_INIT ("splitdevice", "Off", CV_SAVE, CV_OnOff, NULL);
consvar_t cv_skipmapcheck = CVAR_INIT ("skipmapcheck", "Off", CV_SAVE, CV_OnOff, NULL);
INT32 cv_debug;
@ -308,10 +330,10 @@ INT32 cv_debug;
consvar_t cv_usemouse = CVAR_INIT ("use_mouse", "Off", CV_SAVE|CV_CALL,usemouse_cons_t, I_StartupMouse);
consvar_t cv_usejoystick[MAXSPLITSCREENPLAYERS] = {
CVAR_INIT ("use_gamepad", "1", CV_SAVE|CV_CALL, usejoystick_cons_t, I_InitJoystick1),
CVAR_INIT ("use_gamepad2", "2", CV_SAVE|CV_CALL, usejoystick_cons_t, I_InitJoystick2),
CVAR_INIT ("use_joystick3", "3", CV_SAVE|CV_CALL, usejoystick_cons_t, I_InitJoystick3),
CVAR_INIT ("use_joystick4", "4", CV_SAVE|CV_CALL, usejoystick_cons_t, I_InitJoystick4)
CVAR_INIT ("use_device", "1", CV_SAVE|CV_CALL, usejoystick_cons_t, I_InitJoystick1),
CVAR_INIT ("use_device2", "2", CV_SAVE|CV_CALL, usejoystick_cons_t, I_InitJoystick2),
CVAR_INIT ("use_device3", "3", CV_SAVE|CV_CALL, usejoystick_cons_t, I_InitJoystick3),
CVAR_INIT ("use_device4", "4", CV_SAVE|CV_CALL, usejoystick_cons_t, I_InitJoystick4)
};
#if (defined (LJOYSTICK) || defined (HAVE_SDL))
@ -590,23 +612,17 @@ const char *netxcmdnames[MAXNETXCMD - 1] =
void D_RegisterServerCommands(void)
{
INT32 i;
Forceskin_cons_t[0].value = -1;
Forceskin_cons_t[0].strvalue = "Off";
for (i = 0; i < NUMGAMETYPES; 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;
// Set the values to 0/NULL, it will be overwritten later when a skin is assigned to the slot.
for (i = 1; i < MAXSKINS; i++)
{
Forceskin_cons_t[i].value = 0;
Forceskin_cons_t[i].strvalue = NULL;
}
RegisterNetXCmd(XD_NAMEANDCOLOR, Got_NameAndColor);
RegisterNetXCmd(XD_WEAPONPREF, Got_WeaponPref);
RegisterNetXCmd(XD_POWERLEVEL, Got_PowerLevel);
@ -721,11 +737,11 @@ void D_RegisterServerCommands(void)
CV_RegisterVar(&cv_allowexitlevel);
CV_RegisterVar(&cv_restrictskinchange);
CV_RegisterVar(&cv_allowteamchange);
CV_RegisterVar(&cv_ingamecap);
CV_RegisterVar(&cv_maxplayers);
CV_RegisterVar(&cv_respawntime);
// d_clisrv
CV_RegisterVar(&cv_maxplayers);
CV_RegisterVar(&cv_maxconnections);
CV_RegisterVar(&cv_joindelay);
CV_RegisterVar(&cv_resynchattempts);
CV_RegisterVar(&cv_maxsend);
@ -876,8 +892,13 @@ void D_RegisterClientCommands(void)
CV_RegisterVar(&cv_skin[i]);
CV_RegisterVar(&cv_follower[i]);
CV_RegisterVar(&cv_followercolor[i]);
CV_RegisterVar(&cv_lastprofile[i]);
}
CV_RegisterVar(&cv_currprofile);
CV_RegisterVar(&cv_ttlprofilen);
CV_RegisterVar(&cv_splitdevice);
// preferred number of players
CV_RegisterVar(&cv_splitplayers);
@ -931,7 +952,7 @@ void D_RegisterClientCommands(void)
CV_RegisterVar(&cv_bsaturation);
CV_RegisterVar(&cv_msaturation);
// m_menu.c
// k_menu.c
//CV_RegisterVar(&cv_compactscoreboard);
CV_RegisterVar(&cv_chatheight);
CV_RegisterVar(&cv_chatwidth);
@ -950,15 +971,7 @@ void D_RegisterClientCommands(void)
{
CV_RegisterVar(&cv_kickstartaccel[i]);
CV_RegisterVar(&cv_shrinkme[i]);
CV_RegisterVar(&cv_turnaxis[i]);
CV_RegisterVar(&cv_moveaxis[i]);
CV_RegisterVar(&cv_brakeaxis[i]);
CV_RegisterVar(&cv_aimaxis[i]);
CV_RegisterVar(&cv_lookaxis[i]);
CV_RegisterVar(&cv_fireaxis[i]);
CV_RegisterVar(&cv_driftaxis[i]);
CV_RegisterVar(&cv_deadzone[i]);
CV_RegisterVar(&cv_digitaldeadzone[i]);
}
// filesrch.c
@ -1310,6 +1323,8 @@ UINT8 CanChangeSkin(INT32 playernum)
// Server has skin change restrictions.
if (cv_restrictskinchange.value)
{
UINT8 i;
// Can change skin during initial countdown.
if (leveltime < starttime)
return true;
@ -1318,8 +1333,22 @@ UINT8 CanChangeSkin(INT32 playernum)
if (players[playernum].spectator || players[playernum].playerstate == PST_DEAD || players[playernum].playerstate == PST_REBORN)
return true;
return false;
// Check for freeeplay
for (i = 0; i < MAXPLAYERS; i++)
{
if (i == consoleplayer)
continue;
if (playeringame[i] && !players[i].spectator && gamestate == GS_LEVEL)
return false; // Not freeplay!
}
// if we've gotten here, then it's freeplay, and switching anytime is fair game.
return true;
}
// if restrictskinchange is off and we're trying to change skins, don't allow changing skins while moving after the race has started.
else if (gamestate == GS_LEVEL && leveltime >= starttime)
return (!P_PlayerMoving(playernum));
return true;
}
@ -1864,21 +1893,23 @@ static void Got_LeaveParty(UINT8 **cp,INT32 playernum)
void D_SendPlayerConfig(UINT8 n)
{
const profile_t *pr = PR_GetProfile(cv_lastprofile[n].value);
UINT8 buf[4];
UINT8 *p = buf;
SendNameAndColor(n);
SendWeaponPref(n);
if (n == 0)
if (pr != NULL)
{
// Send it over
WRITEUINT16(p, vspowerlevel[PWRLV_RACE]);
WRITEUINT16(p, vspowerlevel[PWRLV_BATTLE]);
WRITEUINT16(p, pr->powerlevels[PWRLV_RACE]);
WRITEUINT16(p, pr->powerlevels[PWRLV_BATTLE]);
}
else
{
// Splitscreen players have invalid powerlevel
// Guest players have no power level
WRITEUINT16(p, 0);
WRITEUINT16(p, 0);
}
@ -2372,10 +2403,12 @@ void D_MapChange(INT32 mapnum, INT32 newgametype, boolean pencoremode, boolean r
// The supplied data are assumed to be good.
I_Assert(delay >= 0 && delay <= 2);
/*
if (mapnum != -1)
{
CV_SetValue(&cv_nextmap, mapnum);
}
*/
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);
@ -2838,10 +2871,6 @@ static void Command_Map_f(void)
return;
}
if (tutorialmode && tutorialgcs)
{
G_CopyControls(gamecontrol[0], gamecontroldefault[0][gcs_custom], gcl_full, num_gcl_full); // using gcs_custom as temp storage
}
tutorialmode = false; // warping takes us out of tutorial mode
D_MapChange(newmapnum, newgametype, newencoremode, newresetplayers, 0, false, fromlevelselect);
@ -2964,7 +2993,7 @@ static void Command_Pause(void)
}
else if (modeattacking) // in time attack, pausing restarts the map
{
M_ModeAttackRetry(0); // directly call from m_menu;
//M_ModeAttackRetry(0); // directly call from m_menu;
return;
}
@ -4550,6 +4579,7 @@ void D_GameTypeChanged(INT32 lastgametype)
if (oldgt && newgt)
CONS_Printf(M_GetText("Gametype was changed from %s to %s\n"), oldgt, newgt);
}
// Only do the following as the server, not as remote admin.
// There will always be a server, and this only needs to be done once.
if (server && (multiplayer || netgame))
@ -5022,7 +5052,7 @@ void Command_Retry_f(void)
}
else if (grandprixinfo.gp == false && bossinfo.boss == false)
{
CONS_Printf(M_GetText("This only works in Grand Prix or Mission Mode.\n"));
CONS_Printf(M_GetText("This only works in singleplayer games.\n"));
}
else
{
@ -5482,7 +5512,7 @@ static void Followercolor4_OnChange(void)
}
}
/** Sends a skin change for the console player, unless that player is moving.
/** Sends a skin change for the console player, unless that player is moving. Also forces them to spectate if the change is done during gameplay
* \sa cv_skin, Skin2_OnChange, Color_OnChange
* \author Graue <graue@oceanbase.org>
*/
@ -5498,7 +5528,7 @@ static void Skin_OnChange(void)
return;
}
if (CanChangeSkin(consoleplayer) && !P_PlayerMoving(consoleplayer))
if (CanChangeSkin(consoleplayer))
SendNameAndColor(0);
else
{
@ -5508,7 +5538,7 @@ static void Skin_OnChange(void)
}
/** Sends a skin change for the secondary splitscreen player, unless that
* player is moving.
* player is moving. Forces spectate the player if the change is done during gameplay.
* \sa cv_skin2, Skin_OnChange, Color2_OnChange
* \author Graue <graue@oceanbase.org>
*/
@ -5517,7 +5547,7 @@ static void Skin2_OnChange(void)
if (!Playing() || !splitscreen)
return; // do whatever you want
if (CanChangeSkin(g_localplayers[1]) && !P_PlayerMoving(g_localplayers[1]))
if (CanChangeSkin(g_localplayers[1]))
SendNameAndColor(1);
else
{
@ -5531,7 +5561,7 @@ static void Skin3_OnChange(void)
if (!Playing() || splitscreen < 2)
return; // do whatever you want
if (CanChangeSkin(g_localplayers[2]) && !P_PlayerMoving(g_localplayers[2]))
if (CanChangeSkin(g_localplayers[2]))
SendNameAndColor(2);
else
{
@ -5545,7 +5575,7 @@ static void Skin4_OnChange(void)
if (!Playing() || splitscreen < 3)
return; // do whatever you want
if (CanChangeSkin(g_localplayers[3]) && !P_PlayerMoving(g_localplayers[3]))
if (CanChangeSkin(g_localplayers[3]))
SendNameAndColor(3);
else
{
@ -5776,13 +5806,6 @@ static void KartFrantic_OnChange(void)
static void KartSpeed_OnChange(void)
{
if (!M_SecretUnlocked(SECRET_HARDSPEED) && cv_kartspeed.value == KARTSPEED_HARD)
{
CONS_Printf(M_GetText("You haven't earned this yet.\n"));
CV_StealthSet(&cv_kartspeed, cv_kartspeed.defaultvalue);
return;
}
if (K_CanChangeRules() == false)
{
return;

View file

@ -23,6 +23,19 @@ extern consvar_t cv_playercolor[MAXSPLITSCREENPLAYERS];
extern consvar_t cv_skin[MAXSPLITSCREENPLAYERS];
extern consvar_t cv_follower[MAXSPLITSCREENPLAYERS];
extern consvar_t cv_followercolor[MAXSPLITSCREENPLAYERS];
extern consvar_t cv_lastprofile[MAXSPLITSCREENPLAYERS];
// current profile loaded.
// Used to know how to make the options menu behave among other things.
extern consvar_t cv_currprofile;
// This is used to save the last profile you used on the title screen.
// that way you can mash n all...
extern consvar_t cv_ttlprofilen;
// CVar that allows starting as many splitscreens as you want with one device
// Intended for use with testing
extern consvar_t cv_splitdevice;
// preferred number of players
extern consvar_t cv_splitplayers;
@ -56,7 +69,7 @@ extern consvar_t cv_runscripts;
extern consvar_t cv_mute;
extern consvar_t cv_pause;
extern consvar_t cv_restrictskinchange, cv_allowteamchange, cv_ingamecap, cv_respawntime;
extern consvar_t cv_restrictskinchange, cv_allowteamchange, cv_maxplayers, cv_respawntime;
// SRB2kart items
extern consvar_t cv_superring, cv_sneaker, cv_rocketsneaker, cv_invincibility, cv_banana;
@ -85,7 +98,7 @@ extern consvar_t cv_kartusepwrlv;
extern consvar_t cv_votetime;
extern consvar_t cv_kartdebugitem, cv_kartdebugamount, cv_kartallowgiveitem, cv_kartdebugdistribution, cv_kartdebughuddrop;
extern consvar_t cv_kartdebugitem, cv_kartdebugamount, cv_kartallowgiveitem, cv_kartdebugshrink, cv_kartdebugdistribution, cv_kartdebughuddrop;
extern consvar_t cv_kartdebugcheckpoint, cv_kartdebugnodes, cv_kartdebugcolorize, cv_kartdebugdirector;
extern consvar_t cv_kartdebugwaypoints, cv_kartdebugbotpredict;

View file

@ -54,7 +54,7 @@
#include "byteptr.h"
#include "p_setup.h"
#include "m_misc.h"
#include "m_menu.h"
#include "k_menu.h"
#include "md5.h"
#include "filesrch.h"

View file

@ -443,6 +443,8 @@ typedef struct player_s
fixed_t spindashspeed; // Spindash release speed
UINT8 spindashboost; // Spindash release boost timer
fixed_t fastfall; // Fast fall momentum
UINT8 numboosts; // Count of how many boosts are being stacked, for after image spawning
fixed_t boostpower; // Base boost value, for offroad
fixed_t speedboost; // Boost value smoothing for max speed
@ -504,8 +506,8 @@ typedef struct player_s
SINT8 lastjawztarget; // (-1 to 15) - Last person you target with jawz, for playing the target switch sfx
UINT8 jawztargetdelay; // (0 to 5) - Delay for Jawz target switching, to make it less twitchy
UINT8 confirmInflictor; // Player ID that dealt damage to you
UINT8 confirmInflictorDelay; // Delay before playing the sound
UINT8 confirmVictim; // Player ID that you dealt damage to
UINT8 confirmVictimDelay; // Delay before playing the sound
UINT8 trickpanel; // Trick panel state
UINT8 tricktime; // Increases while you're tricking. You can't input any trick until it's reached a certain threshold

View file

@ -33,13 +33,14 @@ typedef enum
BT_LOOKBACK = 1<<5, // Look Backward
BT_EBRAKEMASK = (BT_ACCELERATE|BT_BRAKE),
BT_SPINDASHMASK = (BT_ACCELERATE|BT_BRAKE|BT_DRIFT),
// free: 1<<6 to 1<<12
// Lua garbage
BT_CUSTOM1 = 1<<13,
BT_CUSTOM2 = 1<<14,
BT_CUSTOM3 = 1<<15,
BT_LUAA = 1<<13,
BT_LUAB = 1<<14,
BT_LUAC = 1<<15,
} buttoncode_t;
// The data sampled per tick (single player)

View file

@ -13,7 +13,7 @@
#include "g_game.h"
#include "s_sound.h"
#include "z_zone.h"
#include "m_menu.h"
#include "k_menu.h"
#include "m_misc.h"
#include "p_local.h"
#include "st_stuff.h"
@ -486,16 +486,6 @@ static inline int lib_getenum(lua_State *L)
if (mathlib) return luaL_error(L, "NiGHTS grade '%s' could not be found.\n", word);
return 0;
}
else if (fastncmp("MN_",word,3)) {
p = word+3;
for (i = 0; i < NUMMENUTYPES; i++)
if (fastcmp(p, MENUTYPES_LIST[i])) {
lua_pushinteger(L, i);
return 1;
}
if (mathlib) return luaL_error(L, "menutype '%s' could not be found.\n", word);
return 0;
}
else if (fastncmp("PRECIP_",word,7)) {
p = word+7;
for (i = 0; i < MAXPRECIP; i++)

View file

@ -20,7 +20,7 @@
#include "z_zone.h"
#include "w_wad.h"
#include "y_inter.h"
#include "m_menu.h"
#include "k_menu.h"
#include "m_misc.h"
#include "f_finale.h"
#include "st_stuff.h"
@ -164,200 +164,6 @@ void clear_levels(void)
P_AllocMapHeader(gamemap-1);
}
static boolean findFreeSlot(INT32 *num)
{
// Send the character select entry to a free slot.
while (*num < MAXSKINS && (description[*num].used))
*num = *num+1;
// No more free slots. :(
if (*num >= MAXSKINS)
return false;
// Redesign your logo. (See M_DrawSetupChoosePlayerMenu in m_menu.c...)
description[*num].picname[0] = '\0';
description[*num].nametag[0] = '\0';
description[*num].displayname[0] = '\0';
description[*num].oppositecolor = SKINCOLOR_NONE;
description[*num].tagtextcolor = SKINCOLOR_NONE;
description[*num].tagoutlinecolor = SKINCOLOR_NONE;
// Found one! ^_^
return (description[*num].used = true);
}
// Reads a player.
// For modifying the character select screen
void readPlayer(MYFILE *f, INT32 num)
{
char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL);
char *word;
char *word2;
char *displayname = ZZ_Alloc(MAXLINELEN+1);
INT32 i;
boolean slotfound = false;
#define SLOTFOUND \
if (!slotfound && (slotfound = findFreeSlot(&num)) == false) \
goto done;
displayname[MAXLINELEN] = '\0';
do
{
if (myfgets(s, MAXLINELEN, f))
{
if (s[0] == '\n')
break;
for (i = 0; i < MAXLINELEN-3; i++)
{
char *tmp;
if (s[i] == '=')
{
tmp = &s[i+2];
strncpy(displayname, tmp, SKINNAMESIZE);
break;
}
}
word = strtok(s, " ");
if (word)
strupr(word);
else
break;
if (fastcmp(word, "PLAYERTEXT"))
{
char *playertext = NULL;
SLOTFOUND
for (i = 0; i < MAXLINELEN-3; i++)
{
if (s[i] == '=')
{
playertext = &s[i+2];
break;
}
}
if (playertext)
{
strcpy(description[num].notes, playertext);
strcat(description[num].notes, myhashfgets(playertext, sizeof (description[num].notes), f));
}
else
strcpy(description[num].notes, "");
// For some reason, cutting the string did not work above. Most likely due to strcpy or strcat...
// It works down here, though.
{
INT32 numline = 0;
for (i = 0; (size_t)i < sizeof(description[num].notes)-1; i++)
{
if (numline < 20 && description[num].notes[i] == '\n')
numline++;
if (numline >= 20 || description[num].notes[i] == '\0' || description[num].notes[i] == '#')
break;
}
}
description[num].notes[strlen(description[num].notes)-1] = '\0';
description[num].notes[i] = '\0';
continue;
}
word2 = strtok(NULL, " = ");
if (word2)
strupr(word2);
else
break;
if (word2[strlen(word2)-1] == '\n')
word2[strlen(word2)-1] = '\0';
i = atoi(word2);
if (fastcmp(word, "PICNAME"))
{
SLOTFOUND
strncpy(description[num].picname, word2, 8);
}
// new character select
else if (fastcmp(word, "DISPLAYNAME"))
{
SLOTFOUND
// replace '#' with line breaks
// (also remove any '\n')
{
char *cur = NULL;
// remove '\n'
cur = strchr(displayname, '\n');
if (cur)
*cur = '\0';
// turn '#' into '\n'
cur = strchr(displayname, '#');
while (cur)
{
*cur = '\n';
cur = strchr(cur, '#');
}
}
// copy final string
strncpy(description[num].displayname, displayname, SKINNAMESIZE);
}
else if (fastcmp(word, "OPPOSITECOLOR") || fastcmp(word, "OPPOSITECOLOUR"))
{
SLOTFOUND
description[num].oppositecolor = (UINT16)get_number(word2);
}
else if (fastcmp(word, "NAMETAG") || fastcmp(word, "TAGNAME"))
{
SLOTFOUND
strncpy(description[num].nametag, word2, 8);
}
else if (fastcmp(word, "TAGTEXTCOLOR") || fastcmp(word, "TAGTEXTCOLOUR"))
{
SLOTFOUND
description[num].tagtextcolor = (UINT16)get_number(word2);
}
else if (fastcmp(word, "TAGOUTLINECOLOR") || fastcmp(word, "TAGOUTLINECOLOUR"))
{
SLOTFOUND
description[num].tagoutlinecolor = (UINT16)get_number(word2);
}
else if (fastcmp(word, "STATUS"))
{
/*
You MAY disable previous entries if you so desire...
But try to enable something that's already enabled and you will be sent to a free slot.
Because of this, you are allowed to edit any previous entries you like, but only if you
signal that you are purposely doing so by disabling and then reenabling the slot.
*/
if (i && !slotfound && (slotfound = findFreeSlot(&num)) == false)
goto done;
description[num].used = (!!i);
}
else if (fastcmp(word, "SKINNAME"))
{
// Send to free slot.
SLOTFOUND
strlcpy(description[num].skinname, word2, sizeof description[num].skinname);
strlwr(description[num].skinname);
}
else
deh_warning("readPlayer %d: unknown word '%s'", num, word);
}
} while (!myfeof(f)); // finish when the line is empty
#undef SLOTFOUND
done:
Z_Free(displayname);
Z_Free(s);
}
// TODO: Figure out how to do undolines for this....
// TODO: Warnings for running out of freeslots
void readfreeslots(MYFILE *f)
@ -1113,7 +919,6 @@ void readsprite2(MYFILE *f, INT32 num)
Z_Free(s);
}
// copypasted from readPlayer :]
void readgametype(MYFILE *f, char *gtname)
{
char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL);
@ -2258,194 +2063,6 @@ void readtextprompt(MYFILE *f, INT32 num)
Z_Free(s);
}
void readmenu(MYFILE *f, INT32 num)
{
char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL);
char *word = s;
char *word2;
char *tmp;
INT32 value;
do
{
if (myfgets(s, MAXLINELEN, f))
{
if (s[0] == '\n')
break;
// First remove trailing newline, if there is one
tmp = strchr(s, '\n');
if (tmp)
*tmp = '\0';
tmp = strchr(s, '#');
if (tmp)
*tmp = '\0';
if (s == tmp)
continue; // Skip comment lines, but don't break.
// Get the part before the " = "
tmp = strchr(s, '=');
if (tmp)
*(tmp-1) = '\0';
else
break;
strupr(word);
// Now get the part after
word2 = (tmp += 2);
strupr(word2);
value = atoi(word2); // used for numerical settings
if (fastcmp(word, "BACKGROUNDNAME"))
{
strncpy(menupres[num].bgname, word2, 8);
titlechanged = true;
}
else if (fastcmp(word, "HIDEBACKGROUND"))
{
menupres[num].bghide = (boolean)(value || word2[0] == 'T' || word2[0] == 'Y');
titlechanged = true;
}
else if (fastcmp(word, "BACKGROUNDCOLOR"))
{
menupres[num].bgcolor = get_number(word2);
titlechanged = true;
}
else if (fastcmp(word, "HIDETITLEPICS") || fastcmp(word, "HIDEPICS") || fastcmp(word, "TITLEPICSHIDE"))
{
// true by default, except MM_MAIN
menupres[num].hidetitlepics = (boolean)(value || word2[0] == 'T' || word2[0] == 'Y');
titlechanged = true;
}
else if (fastcmp(word, "TITLEPICSMODE"))
{
if (fastcmp(word2, "USER"))
menupres[num].ttmode = TTMODE_USER;
else if (fastcmp(word2, "HIDE") || fastcmp(word2, "HIDDEN") || fastcmp(word2, "NONE"))
{
menupres[num].ttmode = TTMODE_USER;
menupres[num].ttname[0] = 0;
menupres[num].hidetitlepics = true;
}
else if (fastcmp(word2, "RINGRACERS"))
menupres[num].ttmode = TTMODE_RINGRACERS;
else if (fastcmp(word2, "OLD"))
menupres[num].ttmode = TTMODE_OLD;
titlechanged = true;
}
else if (fastcmp(word, "TITLEPICSSCALE"))
{
// Don't handle Alacroix special case here; see Maincfg section.
menupres[num].ttscale = max(1, min(8, (UINT8)get_number(word2)));
titlechanged = true;
}
else if (fastcmp(word, "TITLEPICSNAME"))
{
strncpy(menupres[num].ttname, word2, 9);
titlechanged = true;
}
else if (fastcmp(word, "TITLEPICSX"))
{
menupres[num].ttx = (INT16)get_number(word2);
titlechanged = true;
}
else if (fastcmp(word, "TITLEPICSY"))
{
menupres[num].tty = (INT16)get_number(word2);
titlechanged = true;
}
else if (fastcmp(word, "TITLEPICSLOOP"))
{
menupres[num].ttloop = (INT16)get_number(word2);
titlechanged = true;
}
else if (fastcmp(word, "TITLEPICSTICS"))
{
menupres[num].tttics = (UINT16)get_number(word2);
titlechanged = true;
}
else if (fastcmp(word, "TITLESCROLLSPEED") || fastcmp(word, "TITLESCROLLXSPEED")
|| fastcmp(word, "SCROLLSPEED") || fastcmp(word, "SCROLLXSPEED"))
{
menupres[num].titlescrollxspeed = get_number(word2);
titlechanged = true;
}
else if (fastcmp(word, "TITLESCROLLYSPEED") || fastcmp(word, "SCROLLYSPEED"))
{
menupres[num].titlescrollyspeed = get_number(word2);
titlechanged = true;
}
else if (fastcmp(word, "MUSIC"))
{
strncpy(menupres[num].musname, word2, 7);
menupres[num].musname[6] = 0;
titlechanged = true;
}
else if (fastcmp(word, "MUSICTRACK"))
{
menupres[num].mustrack = ((UINT16)value - 1);
titlechanged = true;
}
else if (fastcmp(word, "MUSICLOOP"))
{
// true by default except MM_MAIN
menupres[num].muslooping = (value || word2[0] == 'T' || word2[0] == 'Y');
titlechanged = true;
}
else if (fastcmp(word, "NOMUSIC"))
{
menupres[num].musstop = (value || word2[0] == 'T' || word2[0] == 'Y');
titlechanged = true;
}
else if (fastcmp(word, "IGNOREMUSIC"))
{
menupres[num].musignore = (value || word2[0] == 'T' || word2[0] == 'Y');
titlechanged = true;
}
else if (fastcmp(word, "FADESTRENGTH"))
{
// one-based, <= 0 means use default value. 1-32
menupres[num].fadestrength = get_number(word2)-1;
titlechanged = true;
}
else if (fastcmp(word, "NOENTERBUBBLE"))
{
menupres[num].enterbubble = !(value || word2[0] == 'T' || word2[0] == 'Y');
titlechanged = true;
}
else if (fastcmp(word, "NOEXITBUBBLE"))
{
menupres[num].exitbubble = !(value || word2[0] == 'T' || word2[0] == 'Y');
titlechanged = true;
}
else if (fastcmp(word, "ENTERTAG"))
{
menupres[num].entertag = get_number(word2);
titlechanged = true;
}
else if (fastcmp(word, "EXITTAG"))
{
menupres[num].exittag = get_number(word2);
titlechanged = true;
}
else if (fastcmp(word, "ENTERWIPE"))
{
menupres[num].enterwipe = get_number(word2);
titlechanged = true;
}
else if (fastcmp(word, "EXITWIPE"))
{
menupres[num].exitwipe = get_number(word2);
titlechanged = true;
}
}
} while (!myfeof(f)); // finish when the line is empty
Z_Free(s);
}
void readframe(MYFILE *f, INT32 num)
{
char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL);
@ -3658,13 +3275,13 @@ void readwipes(MYFILE *f)
else if (fastcmp(pword, "FINAL"))
wipeoffset = wipe_titlescreen_final;
}
else if (fastncmp(word, "TIMEATTACK_", 11))
else if (fastncmp(word, "MENU_", 11))
{
pword = word + 11;
if (fastcmp(pword, "TOBLACK"))
wipeoffset = wipe_timeattack_toblack;
wipeoffset = wipe_menu_toblack;
else if (fastcmp(pword, "FINAL"))
wipeoffset = wipe_timeattack_final;
wipeoffset = wipe_menu_final;
}
else if (fastncmp(word, "CREDITS_", 8))
{
@ -3869,6 +3486,7 @@ void readfollower(MYFILE *f)
followers[numfollowers].bobamp = 4*FRACUNIT;
followers[numfollowers].hitconfirmtime = TICRATE;
followers[numfollowers].defaultcolor = SKINCOLOR_GREEN;
strcpy(followers[numfollowers].icon, "M_NORANK");
do
{
@ -3902,6 +3520,11 @@ void readfollower(MYFILE *f)
strcpy(followers[numfollowers].name, word2);
nameset = true;
}
else if (fastcmp(word, "ICON"))
{
strcpy(followers[numfollowers].icon, word2);
nameset = true;
}
else if (fastcmp(word, "MODE"))
{
if (word2)
@ -4268,20 +3891,6 @@ sfxenum_t get_sfx(const char *word)
return sfx_None;
}
menutype_t get_menutype(const char *word)
{ // Returns the value of MN_ enumerations
menutype_t i;
if (*word >= '0' && *word <= '9')
return atoi(word);
if (fastncmp("MN_",word,3))
word += 3; // take off the MN_
for (i = 0; i < NUMMENUTYPES; i++)
if (fastcmp(word, MENUTYPES_LIST[i]))
return i;
deh_warning("Couldn't find menutype named 'MN_%s'",word);
return MN_NONE;
}
/*static INT16 get_gametype(const char *word)
{ // Returns the value of GT_ enumerations
INT16 i;

View file

@ -21,7 +21,7 @@
#include "m_argv.h"
#include "z_zone.h"
#include "w_wad.h"
#include "m_menu.h"
#include "k_menu.h"
#include "m_misc.h"
#include "f_finale.h"
#include "st_stuff.h"
@ -52,7 +52,6 @@ statenum_t get_state(const char *word);
spritenum_t get_sprite(const char *word);
playersprite_t get_sprite2(const char *word);
sfxenum_t get_sfx(const char *word);
menutype_t get_menutype(const char *word);
//INT16 get_gametype(const char *word);
//powertype_t get_power(const char *word);
skincolornum_t get_skincolor(const char *word);
@ -79,7 +78,6 @@ void readlight(MYFILE *f, INT32 num);
void readskincolor(MYFILE *f, INT32 num);
void readthing(MYFILE *f, INT32 num);
void readfreeslots(MYFILE *f);
void readPlayer(MYFILE *f, INT32 num);
void clear_levels(void);
void clear_conditionsets(void);

View file

@ -13,7 +13,7 @@
#include "doomdef.h" // Constants
#include "s_sound.h" // Sound constants
#include "info.h" // Mobj, state, sprite, etc constants
#include "m_menu.h" // Menu constants
#include "k_menu.h" // Menu constants
#include "y_inter.h" // Intermission constants
#include "p_local.h" // some more constants
#include "r_draw.h" // Colormap constants
@ -6011,101 +6011,6 @@ const char *const HUDITEMS_LIST[] = {
"POWERUPS"
};
const char *const MENUTYPES_LIST[] = {
"NONE",
"MAIN",
// Single Player
"SP_MAIN",
"SP_LOAD",
"SP_PLAYER",
"SP_LEVELSELECT",
"SP_LEVELSTATS",
"SP_TIMEATTACK",
"SP_TIMEATTACK_LEVELSELECT",
"SP_GUESTREPLAY",
"SP_REPLAY",
"SP_GHOST",
"SP_NIGHTSATTACK",
"SP_NIGHTS_LEVELSELECT",
"SP_NIGHTS_GUESTREPLAY",
"SP_NIGHTS_REPLAY",
"SP_NIGHTS_GHOST",
// Multiplayer
"MP_MAIN",
"MP_SPLITSCREEN", // SplitServer
"MP_SERVER",
"MP_CONNECT",
"MP_ROOM",
"MP_PLAYERSETUP", // MP_PlayerSetupDef shared with SPLITSCREEN if #defined NONET
"MP_SERVER_OPTIONS",
// Options
"OP_MAIN",
"OP_P1CONTROLS",
"OP_CHANGECONTROLS", // OP_ChangeControlsDef shared with P2
"OP_P1MOUSE",
"OP_P1JOYSTICK",
"OP_JOYSTICKSET", // OP_JoystickSetDef shared with P2
"OP_P1CAMERA",
"OP_P2CONTROLS",
"OP_P2MOUSE",
"OP_P2JOYSTICK",
"OP_P2CAMERA",
"OP_PLAYSTYLE",
"OP_VIDEO",
"OP_VIDEOMODE",
"OP_COLOR",
"OP_OPENGL",
"OP_OPENGL_LIGHTING",
"OP_SOUND",
"OP_SERVER",
"OP_MONITORTOGGLE",
"OP_DATA",
"OP_ADDONS",
"OP_SCREENSHOTS",
"OP_ERASEDATA",
// Extras
"SR_MAIN",
"SR_PANDORA",
"SR_LEVELSELECT",
"SR_UNLOCKCHECKLIST",
"SR_EMBLEMHINT",
"SR_PLAYER",
"SR_SOUNDTEST",
// Addons (Part of MISC, but let's make it our own)
"AD_MAIN",
// MISC
// "MESSAGE",
// "SPAUSE",
// "MPAUSE",
// "SCRAMBLETEAM",
// "CHANGETEAM",
// "CHANGELEVEL",
// "MAPAUSE",
// "HELP",
"SPECIAL"
};
struct int_const_s const INT_CONST[] = {
// If a mod removes some variables here,
// please leave the names in-tact and just set
@ -6574,9 +6479,9 @@ struct int_const_s const INT_CONST[] = {
{"BT_DRIFT",BT_DRIFT},
{"BT_BRAKE",BT_BRAKE},
{"BT_ATTACK",BT_ATTACK},
{"BT_CUSTOM1",BT_CUSTOM1}, // Lua customizable
{"BT_CUSTOM2",BT_CUSTOM2}, // Lua customizable
{"BT_CUSTOM3",BT_CUSTOM3}, // Lua customizable
{"BT_LUAA",BT_LUAA}, // Lua customizable
{"BT_LUAB",BT_LUAB}, // Lua customizable
{"BT_LUAC",BT_LUAC}, // Lua customizable
// Lua command registration flags
{"COM_ADMIN",COM_ADMIN},
@ -6598,8 +6503,7 @@ struct int_const_s const INT_CONST[] = {
{"CV_SHOWMODIF",CV_SHOWMODIF},
{"CV_SHOWMODIFONETIME",CV_SHOWMODIFONETIME},
{"CV_NOSHOWHELP",CV_NOSHOWHELP},
{"CV_HIDEN",CV_HIDEN},
{"CV_HIDDEN",CV_HIDEN},
{"CV_HIDDEN",CV_HIDDEN},
{"CV_CHEAT",CV_CHEAT},
{"CV_NOLUA",CV_NOLUA},
@ -6707,7 +6611,7 @@ struct int_const_s const INT_CONST[] = {
{"GS_INTERMISSION",GS_INTERMISSION},
{"GS_CONTINUING",GS_CONTINUING},
{"GS_TITLESCREEN",GS_TITLESCREEN},
{"GS_TIMEATTACK",GS_TIMEATTACK},
{"GS_MENU",GS_MENU},
{"GS_CREDITS",GS_CREDITS},
{"GS_EVALUATION",GS_EVALUATION},
{"GS_GAMEEND",GS_GAMEEND},

View file

@ -69,7 +69,6 @@ extern const char *COLOR_ENUMS[];
extern const char *const POWERS_LIST[];
extern const char *const KARTHUD_LIST[];
extern const char *const HUDITEMS_LIST[];
extern const char *const MENUTYPES_LIST[];
extern struct int_const_s const INT_CONST[];

View file

@ -11,6 +11,7 @@
/// \brief Load dehacked file and change tables and text
#include "doomdef.h"
#include "m_cond.h"
#include "deh_soc.h"
#include "deh_tables.h"
@ -245,18 +246,7 @@ static void DEH_LoadDehackedFile(MYFILE *f, boolean mainfile)
else
i = 0;
if (fastcmp(word, "CHARACTER"))
{
if (i >= 0 && i < 32)
readPlayer(f, i);
else
{
deh_warning("Character %d out of range (0 - 31)", i);
ignorelines(f);
}
continue;
}
else if (fastcmp(word, "EMBLEM"))
if (fastcmp(word, "EMBLEM"))
{
if (!mainfile && !gamedataadded)
{
@ -495,19 +485,6 @@ static void DEH_LoadDehackedFile(MYFILE *f, boolean mainfile)
ignorelines(f);
}
}
else if (fastcmp(word, "MENU"))
{
if (i == 0 && word2[0] != '0') // If word2 isn't a number
i = get_menutype(word2); // find a huditem by name
if (i >= 1 && i < NUMMENUTYPES)
readmenu(f, i);
else
{
// zero-based, but let's start at 1
deh_warning("Menu number %d out of range (1 - %d)", i, NUMMENUTYPES-1);
ignorelines(f);
}
}
else if (fastcmp(word, "UNLOCKABLE"))
{
if (!mainfile && !gamedataadded)
@ -564,6 +541,7 @@ static void DEH_LoadDehackedFile(MYFILE *f, boolean mainfile)
{
cup = Z_Calloc(sizeof (cupheader_t), PU_STATIC, NULL);
cup->id = numkartcupheaders;
cup->unlockrequired = -1;
deh_strlcpy(cup->name, word2,
sizeof(cup->name), va("Cup header %s: name", word2));
if (prev != NULL)

View file

@ -20,7 +20,7 @@
#include "i_net.h"
#include "g_game.h"
#include "p_tick.h"
#include "m_menu.h" // gametype_cons_t
#include "k_menu.h" // gametype_cons_t
#include "r_things.h" // skins
#include "mserv.h" // cv_advertise
#include "z_zone.h"
@ -267,7 +267,7 @@ static void DRPC_HandleJoinRequest(const DiscordUser *requestUser)
else
{
discordRequestList = newRequest;
M_RefreshPauseMenu();
//M_RefreshPauseMenu();
}
// Made it to the end, request was valid, so play the request sound :)

View file

@ -162,7 +162,7 @@ extern char logfilename[1024];
// Comment out this line to completely disable update alerts (recommended for testing, but not for release)
#ifndef BETAVERSION
#define UPDATE_ALERT
//#define UPDATE_ALERT
#endif
// The string used in the alert that pops up in the event of an update being available.
@ -205,8 +205,10 @@ extern char logfilename[1024];
#define PLAYERSMASK (MAXPLAYERS-1)
#define MAXPLAYERNAME 21
#define MAXSPLITSCREENPLAYERS 4 // Max number of players on a single computer
#define MAXGAMEPADS (MAXSPLITSCREENPLAYERS * 2) // Number of gamepads we'll be allowing
#define MAXSKINS UINT8_MAX
#define SKINNAMESIZE 16 // Moved from r_skins.h as including that particular header causes issues later down the line.
#define COLORRAMPSIZE 16
#define MAXCOLORNAME 32
@ -225,6 +227,10 @@ typedef struct skincolor_s
boolean accessible; // Accessible by the color command + setup menu
} skincolor_t;
#define FOLLOWERCOLOR_MATCH UINT16_MAX
#define FOLLOWERCOLOR_OPPOSITE (UINT16_MAX-1)
UINT16 K_GetEffectiveFollowerColor(UINT16 followercolor, UINT16 playercolor);
typedef enum
{
SKINCOLOR_NONE = 0,

View file

@ -195,7 +195,6 @@ extern INT16 bootmap; //bootmap for loading a map on startup
extern INT16 tutorialmap; // map to load for tutorial
extern boolean tutorialmode; // are we in a tutorial right now?
extern INT32 tutorialgcs; // which control scheme is loaded?
extern boolean looptitle;

View file

@ -27,7 +27,6 @@
#include "z_zone.h"
#include "i_system.h"
#include "i_threads.h"
#include "m_menu.h"
#include "dehacked.h"
#include "g_input.h"
#include "console.h"
@ -42,6 +41,9 @@
#include "lua_hud.h"
// SRB2Kart
#include "k_menu.h"
// Stage of animation:
// 0 = text, 1 = art screen
INT32 finalecount;
@ -53,7 +55,6 @@ static INT32 timetonext; // Delay between screen changes
static tic_t animtimer; // Used for some animation timings
static tic_t credbgtimer; // Credits background
static INT16 skullAnimCounter; // Prompts: Chevron animation
static tic_t stoptimer;
@ -65,7 +66,7 @@ mobj_t *titlemapcameraref = NULL;
// menu presentation state
char curbgname[9];
SINT8 curfadevalue;
INT32 curbgcolor;
INT32 curbgcolor = -1; // Please stop assaulting my eyes.
INT32 curbgxspeed;
INT32 curbgyspeed;
boolean curbghide;
@ -427,11 +428,11 @@ void F_IntroTicker(void)
I_OsPolling();
I_UpdateNoBlit();
#ifdef HAVE_THREADS
I_lock_mutex(&m_menu_mutex);
I_lock_mutex(&k_menu_mutex);
#endif
M_Drawer(); // menu is drawn even on top of wipes
#ifdef HAVE_THREADS
I_unlock_mutex(m_menu_mutex);
I_unlock_mutex(k_menu_mutex);
#endif
I_FinishUpdate(); // Update the screen with the image Tails 06-19-2001
@ -1682,11 +1683,9 @@ void F_GameEndTicker(void)
// TITLE SCREEN
// ==============
void F_InitMenuPresValues(void)
static void F_InitMenuPresValues(void)
{
menuanimtimer = 0;
prevMenuId = 0;
activeMenuId = MainDef.menuid;
// Set defaults for presentation values
strncpy(curbgname, "TITLESKY", 9);
@ -1705,11 +1704,6 @@ void F_InitMenuPresValues(void)
curttloop = ttloop;
curtttics = tttics;
// Find current presentation values
//M_SetMenuCurBackground((gamestate == GS_TIMEATTACK) ? "RECATTBG" : "TITLESKY");
//M_SetMenuCurFadeValue(16);
//M_SetMenuCurTitlePics();
LUA_HUD_DestroyDrawList(luahuddrawlist_title);
luahuddrawlist_title = LUA_HUD_CreateDrawList();
}
@ -1842,11 +1836,13 @@ static void F_CacheTitleScreen(void)
void F_StartTitleScreen(void)
{
setup_numplayers = 0;
if (gamestate != GS_TITLESCREEN && gamestate != GS_WAITINGPLAYERS)
{
ttuser_count = 0;
finalecount = 0;
wipetypepost = menupres[MN_MAIN].enterwipe;
wipetypepost = 0;
}
else
wipegamestate = GS_TITLESCREEN;
@ -1898,10 +1894,6 @@ void F_StartTitleScreen(void)
camera[0].chase = true;
camera[0].height = 0;
// Run enter linedef exec for MN_MAIN, since this is where we start
if (menupres[MN_MAIN].entertag)
P_LinedefExecute(menupres[MN_MAIN].entertag, players[displayplayers[0]].mo, NULL);
wipegamestate = prevwipegamestate;
}
else
@ -1920,6 +1912,7 @@ void F_StartTitleScreen(void)
demoDelayLeft = demoDelayTime;
demoIdleLeft = demoIdleTime;
F_InitMenuPresValues();
F_CacheTitleScreen();
}
@ -1936,6 +1929,8 @@ void F_TitleScreenDrawer(void)
V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, curbgcolor);
else if (!curbghide || !titlemapinaction || gamestate == GS_WAITINGPLAYERS)
F_SkyScroll(curbgxspeed, curbgyspeed, curbgname);
else
V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 31);
// Don't draw outside of the title screen, or if the patch isn't there.
if (gamestate != GS_TITLESCREEN && gamestate != GS_WAITINGPLAYERS)
@ -2115,18 +2110,10 @@ luahook:
LUA_HUD_DrawList(luahuddrawlist_title);
}
// separate animation timer for backgrounds, since we also count
// during GS_TIMEATTACK
void F_MenuPresTicker(boolean run)
{
if (run)
menuanimtimer++;
}
// (no longer) De-Demo'd Title Screen
void F_TitleScreenTicker(boolean run)
{
F_MenuPresTicker(true); // title sky
menuanimtimer++; // title sky
if (run)
{
@ -2135,10 +2122,7 @@ void F_TitleScreenTicker(boolean run)
if (finalecount == 1)
{
// Now start the music
if (menupres[MN_MAIN].musname[0])
S_ChangeMusic(menupres[MN_MAIN].musname, menupres[MN_MAIN].mustrack, menupres[MN_MAIN].muslooping);
else
S_ChangeMusicInternal("_title", looptitle);
S_ChangeMusicInternal("_title", looptitle);
}
}
@ -2853,12 +2837,13 @@ void F_StartTextPrompt(INT32 promptnum, INT32 pagenum, mobj_t *mo, UINT16 postex
static boolean F_GetTextPromptTutorialTag(char *tag, INT32 length)
{
INT32 gcs = gcs_custom;
INT32 gcs = 0;
boolean suffixed = true;
if (!tag || !tag[0] || !tutorialmode)
return false;
/*
if (!strncmp(tag, "TAA", 3)) // Accelerate
gcs = G_GetControlScheme(gamecontrol[0], gcl_accelerate, num_gcl_accelerate);
else if (!strncmp(tag, "TAB", 3)) // Brake
@ -2873,14 +2858,10 @@ static boolean F_GetTextPromptTutorialTag(char *tag, INT32 length)
gcs = G_GetControlScheme(gamecontrol[0], gcl_item, num_gcl_item);
else
gcs = G_GetControlScheme(gamecontrol[0], gcl_full, num_gcl_full);
*/
switch (gcs)
{
case gcs_kart:
// strncat(tag, "KART", length);
suffixed = false;
break;
default:
strncat(tag, "CUSTOM", length);
break;

View file

@ -129,9 +129,6 @@ extern UINT16 curtttics;
#define TITLEBACKGROUNDACTIVE (curfadevalue >= 0 || curbgname[0])
void F_InitMenuPresValues(void);
void F_MenuPresTicker(boolean run);
//
// WIPE
//
@ -163,7 +160,7 @@ enum
wipe_voting_toblack,
wipe_continuing_toblack,
wipe_titlescreen_toblack,
wipe_timeattack_toblack,
wipe_menu_toblack,
wipe_credits_toblack,
wipe_evaluation_toblack,
wipe_gameend_toblack,
@ -181,7 +178,7 @@ enum
wipe_voting_final,
wipe_continuing_final,
wipe_titlescreen_final,
wipe_timeattack_final,
wipe_menu_final,
wipe_credits_final,
wipe_evaluation_final,
wipe_gameend_final,

View file

@ -26,7 +26,6 @@
#include "i_time.h"
#include "i_system.h"
#include "i_threads.h"
#include "m_menu.h"
#include "console.h"
#include "d_main.h"
#include "m_misc.h" // movie mode
@ -43,6 +42,9 @@
#define NOWIPE // do not enable wipe image post processing for ARM, SH and MIPS CPUs
#endif
// SRB2Kart
#include "k_menu.h"
typedef struct fademask_s {
UINT8* mask;
UINT16 width, height;
@ -58,7 +60,7 @@ UINT8 wipedefs[NUMWIPEDEFS] = {
0, // wipe_voting_toblack,
0, // wipe_continuing_toblack
0, // wipe_titlescreen_toblack
0, // wipe_timeattack_toblack
1, // wipe_menu_toblack
99, // wipe_credits_toblack
0, // wipe_evaluation_toblack
0, // wipe_gameend_toblack
@ -74,7 +76,7 @@ UINT8 wipedefs[NUMWIPEDEFS] = {
0, // wipe_voting_final
0, // wipe_continuing_final
0, // wipe_titlescreen_final
0, // wipe_timeattack_final
1, // wipe_menu_final
99, // wipe_credits_final
0, // wipe_evaluation_final
0, // wipe_gameend_final
@ -509,11 +511,11 @@ void F_RunWipe(UINT8 wipetype, boolean drawMenu, const char *colormap, boolean r
if (drawMenu)
{
#ifdef HAVE_THREADS
I_lock_mutex(&m_menu_mutex);
I_lock_mutex(&k_menu_mutex);
#endif
M_Drawer(); // menu is drawn even on top of wipes
#ifdef HAVE_THREADS
I_unlock_mutex(m_menu_mutex);
I_unlock_mutex(k_menu_mutex);
#endif
}

View file

@ -32,7 +32,7 @@
#include "d_netfil.h"
#include "m_misc.h"
#include "z_zone.h"
#include "m_menu.h" // Addons_option_Onchange
#include "k_menu.h" // Addons_option_Onchange
#if (defined (_WIN32) && !defined (_WIN32_WCE)) && defined (_MSC_VER) && !defined (_XBOX)
@ -561,15 +561,15 @@ char exttable[NUM_EXT_TABLE][7] = { // maximum extension length (currently 4) pl
char filenamebuf[MAX_WADFILES][MAX_WADPATH];
static boolean filemenucmp(char *haystack, char *needle)
static boolean filemenucmp(char *haystack)
{
static char localhaystack[128];
strlcpy(localhaystack, haystack, 128);
if (!cv_addons_search_case.value)
strupr(localhaystack);
if (cv_addons_search_type.value)
return (strstr(localhaystack, needle) != 0);
return (!strncmp(localhaystack, needle, menusearch[0]));
return (strstr(localhaystack, menusearch+1) != 0);
return (!strncmp(localhaystack, menusearch+1, menusearch[0]));
}
void closefilemenu(boolean validsize)
@ -616,7 +616,6 @@ void closefilemenu(boolean validsize)
void searchfilemenu(char *tempname)
{
size_t i, first;
char localmenusearch[MAXSTRINGLENGTH] = "";
if (dirmenu)
{
@ -662,14 +661,10 @@ void searchfilemenu(char *tempname)
return;
}
strcpy(localmenusearch, menusearch+1);
if (!cv_addons_search_case.value)
strupr(localmenusearch);
sizedirmenu = 0;
for (i = first; i < sizecoredirmenu; i++)
{
if (filemenucmp(coredirmenu[i]+DIR_STRING, localmenusearch))
if (filemenucmp(coredirmenu[i]+DIR_STRING))
sizedirmenu++;
}
@ -691,7 +686,7 @@ void searchfilemenu(char *tempname)
sizedirmenu = 0;
for (i = first; i < sizecoredirmenu; i++)
{
if (filemenucmp(coredirmenu[i]+DIR_STRING, localmenusearch))
if (filemenucmp(coredirmenu[i]+DIR_STRING))
{
if (tempname && !strcmp(coredirmenu[i]+DIR_STRING, tempname))
{
@ -724,7 +719,10 @@ boolean preparefilemenu(boolean samedepth, boolean replayhut)
tempname = Z_StrDup(dirmenu[dir_on[menudepthleft]]+DIR_STRING); // don't need to I_Error if can't make - not important, just QoL
}
else
{
menusearch[0] = menusearch[1] = 0; // clear search
CV_StealthSet(&cv_dummyaddonsearch, "");
}
if (!(dirhandle = opendir(menupath))) // get directory
{

View file

@ -6,7 +6,7 @@
#include "doomdef.h"
#include "d_netfil.h"
#include "m_menu.h" // MAXSTRINGLENGTH
#include "k_menu.h" // MAXSTRINGLENGTH
extern consvar_t cv_addons_option, cv_addons_folder, cv_addons_md5, cv_addons_showall, cv_addons_search_case, cv_addons_search_type;

View file

@ -26,7 +26,7 @@
#include "g_game.h"
#include "g_demo.h"
#include "m_misc.h"
#include "m_menu.h"
#include "k_menu.h"
#include "m_argv.h"
#include "hu_stuff.h"
#include "z_zone.h"
@ -3888,7 +3888,7 @@ boolean G_DemoTitleResponder(event_t *ev)
return true;
}
if (ch == KEY_ENTER || ch >= KEY_MOUSE1)
if (ch == KEY_ENTER || ch >= NUMKEYS)
{
demo.savemode = DSM_WILLSAVE;
return true;

View file

@ -33,7 +33,7 @@
#include "g_demo.h"
#include "m_cheat.h"
#include "m_misc.h"
#include "m_menu.h"
#include "k_menu.h"
#include "m_argv.h"
#include "hu_stuff.h"
#include "st_stuff.h"
@ -75,8 +75,8 @@ JoyType_t Joystick[MAXSPLITSCREENPLAYERS];
#define SAVEGAMESIZE (1024)
// SRB2kart
char gamedatafilename[64] = "kartdata.dat";
char timeattackfolder[64] = "kart";
char gamedatafilename[64] = "ringdata.dat";
char timeattackfolder[64] = "ringracers";
char customversionstring[32] = "\0";
static void G_DoCompleted(void);
@ -160,7 +160,6 @@ INT16 bootmap; //bootmap for loading a map on startup
INT16 tutorialmap = 0; // map to load for tutorial
boolean tutorialmode = false; // are we in a tutorial right now?
INT32 tutorialgcs = gcs_custom; // which control scheme is loaded?
boolean looptitle = true;
@ -353,22 +352,6 @@ static void weaponPrefChange2(void);
static void weaponPrefChange3(void);
static void weaponPrefChange4(void);
static CV_PossibleValue_t joyaxis_cons_t[] = {{0, "None"},
{1, "X-Axis"}, {2, "Y-Axis"}, {-1, "X-Axis-"}, {-2, "Y-Axis-"},
#if JOYAXISSET > 1
{3, "Z-Axis"}, {4, "X-Rudder"}, {-3, "Z-Axis-"}, {-4, "X-Rudder-"},
#endif
#if JOYAXISSET > 2
{5, "Y-Rudder"}, {6, "Z-Rudder"}, {-5, "Y-Rudder-"}, {-6, "Z-Rudder-"},
#endif
#if JOYAXISSET > 3
{7, "U-Axis"}, {8, "V-Axis"}, {-7, "U-Axis-"}, {-8, "V-Axis-"},
#endif
{0, NULL}};
#if JOYAXISSET > 4
"More Axis Sets"
#endif
// don't mind me putting these here, I was lazy to figure out where else I could put those without blowing up the compiler.
// chat timer thingy
@ -425,68 +408,12 @@ consvar_t cv_shrinkme[MAXSPLITSCREENPLAYERS] = {
CVAR_INIT ("shrinkme4", "Off", CV_CALL, CV_OnOff, weaponPrefChange4)
};
consvar_t cv_turnaxis[MAXSPLITSCREENPLAYERS] = {
CVAR_INIT ("joyaxis_turn", "X-Axis", CV_SAVE, joyaxis_cons_t, NULL),
CVAR_INIT ("joyaxis2_turn", "X-Axis", CV_SAVE, joyaxis_cons_t, NULL),
CVAR_INIT ("joyaxis3_turn", "X-Axis", CV_SAVE, joyaxis_cons_t, NULL),
CVAR_INIT ("joyaxis4_turn", "X-Axis", CV_SAVE, joyaxis_cons_t, NULL)
};
consvar_t cv_moveaxis[MAXSPLITSCREENPLAYERS] = {
CVAR_INIT ("joyaxis_move", "None", CV_SAVE, joyaxis_cons_t, NULL),
CVAR_INIT ("joyaxis_move2", "None", CV_SAVE, joyaxis_cons_t, NULL),
CVAR_INIT ("joyaxis_move3", "None", CV_SAVE, joyaxis_cons_t, NULL),
CVAR_INIT ("joyaxis_move4", "None", CV_SAVE, joyaxis_cons_t, NULL)
};
consvar_t cv_brakeaxis[MAXSPLITSCREENPLAYERS] = {
CVAR_INIT ("joyaxis_brake", "None", CV_SAVE, joyaxis_cons_t, NULL),
CVAR_INIT ("joyaxis2_brake", "None", CV_SAVE, joyaxis_cons_t, NULL),
CVAR_INIT ("joyaxis3_brake", "None", CV_SAVE, joyaxis_cons_t, NULL),
CVAR_INIT ("joyaxis4_brake", "None", CV_SAVE, joyaxis_cons_t, NULL)
};
consvar_t cv_aimaxis[MAXSPLITSCREENPLAYERS] = {
CVAR_INIT ("joyaxis_aim", "Y-Axis", CV_SAVE, joyaxis_cons_t, NULL),
CVAR_INIT ("joyaxis2_aim", "Y-Axis", CV_SAVE, joyaxis_cons_t, NULL),
CVAR_INIT ("joyaxis3_aim", "Y-Axis", CV_SAVE, joyaxis_cons_t, NULL),
CVAR_INIT ("joyaxis4_aim", "Y-Axis", CV_SAVE, joyaxis_cons_t, NULL)
};
consvar_t cv_lookaxis[MAXSPLITSCREENPLAYERS] = {
CVAR_INIT ("joyaxis_look", "None", CV_SAVE, joyaxis_cons_t, NULL),
CVAR_INIT ("joyaxis2_look", "None", CV_SAVE, joyaxis_cons_t, NULL),
CVAR_INIT ("joyaxis3_look", "None", CV_SAVE, joyaxis_cons_t, NULL),
CVAR_INIT ("joyaxis4_look", "None", CV_SAVE, joyaxis_cons_t, NULL)
};
consvar_t cv_fireaxis[MAXSPLITSCREENPLAYERS] = {
CVAR_INIT ("joyaxis_fire", "Z-Axis", CV_SAVE, joyaxis_cons_t, NULL),
CVAR_INIT ("joyaxis_fire2", "Z-Axis", CV_SAVE, joyaxis_cons_t, NULL),
CVAR_INIT ("joyaxis_fire3", "Z-Axis", CV_SAVE, joyaxis_cons_t, NULL),
CVAR_INIT ("joyaxis_fire4", "Z-Axis", CV_SAVE, joyaxis_cons_t, NULL)
};
consvar_t cv_driftaxis[MAXSPLITSCREENPLAYERS] = {
CVAR_INIT ("joyaxis_drift", "Z-Rudder", CV_SAVE, joyaxis_cons_t, NULL),
CVAR_INIT ("joyaxis2_drift", "Z-Rudder", CV_SAVE, joyaxis_cons_t, NULL),
CVAR_INIT ("joyaxis3_drift", "Z-Rudder", CV_SAVE, joyaxis_cons_t, NULL),
CVAR_INIT ("joyaxis4_drift", "Z-Rudder", CV_SAVE, joyaxis_cons_t, NULL)
};
static CV_PossibleValue_t zerotoone_cons_t[] = {{0, "MIN"}, {FRACUNIT, "MAX"}, {0, NULL}};
consvar_t cv_deadzone[MAXSPLITSCREENPLAYERS] = {
CVAR_INIT ("joy_deadzone", "0.125", CV_FLOAT|CV_SAVE, zerotoone_cons_t, NULL),
CVAR_INIT ("joy2_deadzone", "0.125", CV_FLOAT|CV_SAVE, zerotoone_cons_t, NULL),
CVAR_INIT ("joy3_deadzone", "0.125", CV_FLOAT|CV_SAVE, zerotoone_cons_t, NULL),
CVAR_INIT ("joy4_deadzone", "0.125", CV_FLOAT|CV_SAVE, zerotoone_cons_t, NULL)
};
consvar_t cv_digitaldeadzone[MAXSPLITSCREENPLAYERS] = {
CVAR_INIT ("joy_digdeadzone", "0.25", CV_FLOAT|CV_SAVE, zerotoone_cons_t, NULL),
CVAR_INIT ("joy2_digdeadzone", "0.25", CV_FLOAT|CV_SAVE, zerotoone_cons_t, NULL),
CVAR_INIT ("joy3_digdeadzone", "0.25", CV_FLOAT|CV_SAVE, zerotoone_cons_t, NULL),
CVAR_INIT ("joy4_digdeadzone", "0.25", CV_FLOAT|CV_SAVE, zerotoone_cons_t, NULL)
CVAR_INIT ("deadzone", "0.25", CV_FLOAT|CV_SAVE, zerotoone_cons_t, NULL),
CVAR_INIT ("deadzone2", "0.25", CV_FLOAT|CV_SAVE, zerotoone_cons_t, NULL),
CVAR_INIT ("deadzone3", "0.25", CV_FLOAT|CV_SAVE, zerotoone_cons_t, NULL),
CVAR_INIT ("deadzone4", "0.25", CV_FLOAT|CV_SAVE, zerotoone_cons_t, NULL)
};
// now automatically allocated in D_RegisterClientCommands
@ -672,9 +599,10 @@ const char *G_BuildMapName(INT32 map)
{
static char mapname[10] = "MAPXX"; // internal map name (wad resource name)
I_Assert(map >= 0);
I_Assert(map > 0);
I_Assert(map <= NUMMAPS);
#if 0
if (map == 0) // hack???
{
if (gamestate == GS_TITLESCREEN)
@ -685,6 +613,7 @@ const char *G_BuildMapName(INT32 map)
map = prevmap;
map = G_RandMap(G_TOLFlag(cv_newgametype.value), map, 0, 0, false, NULL)+1;
}
#endif
if (map < 100)
sprintf(&mapname[3], "%.2d", map);
@ -736,74 +665,161 @@ INT16 G_SoftwareClipAimingPitch(INT32 *aiming)
return (INT16)((*aiming)>>16);
}
INT32 PlayerJoyAxis(UINT8 player, axis_input_e axissel)
// Default controls for keyboard. These are hardcoded and cannot be changed.
static INT32 keyboardMenuDefaults[][2] = {
{gc_a, KEY_ENTER},
{gc_c, KEY_BACKSPACE},
{gc_x, KEY_ESCAPE},
{gc_left, KEY_LEFTARROW},
{gc_right, KEY_RIGHTARROW},
{gc_up, KEY_UPARROW},
{gc_down, KEY_DOWNARROW},
// special control
{gc_start, KEY_ESCAPE},
// 8 total controls*
};
#define KEYBOARDDEFAULTSSPLIT 7
INT32 G_PlayerInputAnalog(UINT8 p, INT32 gc, UINT8 menuPlayers)
{
INT32 retaxis;
INT32 axisval;
boolean flp = false;
INT32 deviceID;
INT32 i, j;
INT32 deadzone = 0;
boolean trydefaults = true;
boolean tryingotherID = false;
INT32 *controltable = &(gamecontrol[p][gc][0]);
//find what axis to get
switch (axissel)
if (p >= MAXSPLITSCREENPLAYERS)
{
case AXISTURN:
axisval = cv_turnaxis[player-1].value;
break;
case AXISMOVE:
axisval = cv_moveaxis[player-1].value;
break;
case AXISBRAKE:
axisval = cv_brakeaxis[player-1].value;
break;
case AXISAIM:
axisval = cv_aimaxis[player-1].value;
break;
case AXISLOOK:
axisval = cv_lookaxis[player-1].value;
break;
case AXISFIRE:
axisval = cv_fireaxis[player-1].value;
break;
case AXISDRIFT:
axisval = cv_driftaxis[player-1].value;
break;
default:
return 0;
}
if (axisval < 0) //odd -axises
{
axisval = -axisval;
flp = true;
}
if (axisval > JOYAXISSET*2 || axisval == 0) //not there in array or None
#ifdef PARANOIA
CONS_Debug(DBG_GAMELOGIC, "G_PlayerInputAnalog: Invalid player ID %d\n", p);
#endif
return 0;
if (axisval%2)
{
axisval /= 2;
retaxis = joyxmove[player-1][axisval];
}
else
{
axisval--;
axisval /= 2;
retaxis = joyymove[player-1][axisval];
}
if (retaxis < (-JOYAXISRANGE))
retaxis = -JOYAXISRANGE;
if (retaxis > (+JOYAXISRANGE))
retaxis = +JOYAXISRANGE;
deadzone = (JOYAXISRANGE * cv_deadzone[p].value) / FRACUNIT;
if (!Joystick[player-1].bGamepadStyle && axissel >= AXISDIGITAL)
deviceID = cv_usejoystick[p].value;
retrygetcontrol:
for (i = 0; i < MAXINPUTMAPPING; i++)
{
const INT32 jdeadzone = ((JOYAXISRANGE-1) * cv_digitaldeadzone[player-1].value) >> FRACBITS;
if (-jdeadzone < retaxis && retaxis < jdeadzone)
return 0;
INT32 key = controltable[i];
INT32 menukey = KEY_NULL;
INT32 value = 0;
boolean processinput = true;
// for menus, keyboards have defaults!
if (deviceID == 0)
{
// In menus, check indexes 0 through 5 (everything besides gc_start)
// Outside of menus, only consider the hardcoded input for gc_start at index 6
INT32 maxj = menuactive ? KEYBOARDDEFAULTSSPLIT : KEYBOARDDEFAULTSSPLIT+1;
j = (!menuactive) ? KEYBOARDDEFAULTSSPLIT : 0;
for (; j < maxj; j++) // check keyboardMenuDefaults
{
// the gc we're looking for
if (gc == keyboardMenuDefaults[j][0])
{
menukey = keyboardMenuDefaults[j][1];
break;
}
// The key is mapped to *something else*...?
// Then don't process that as it would conflict with our hardcoded inputs.
else if (key == keyboardMenuDefaults[j][1])
{
processinput = false;
break;
}
}
}
// Invalid key number.
if (!G_KeyIsAvailable(key, deviceID) && !G_KeyIsAvailable(menukey, deviceID))
{
continue;
}
if (processinput)
{
// It's possible to access this control right now, so let's disable the default control backup for later.
trydefaults = false;
value = gamekeydown[deviceID][key];
if (menukey && gamekeydown[deviceID][menukey])
value = gamekeydown[deviceID][menukey];
if (value >= deadzone)
{
return value;
}
}
}
if (flp) retaxis = -retaxis; //flip it around
return retaxis;
// If you're on controller, try your keyboard-based binds as an immediate backup.
// Do not do this if there are more than 1 local player.
if (p == 0 && deviceID > 0 && !tryingotherID && menuPlayers < 2 && !splitscreen)
{
deviceID = 0;
goto retrygetcontrol;
}
if (menuPlayers == 0)
{
return 0;
}
// We don't want menus to become unnavigable if people unbind
// all of their controls, so we do several things in this scenario.
// First: try other controllers.
if (!tryingotherID)
{
deviceID = MAXDEVICES;
tryingotherID = true;
}
loweringid:
deviceID--;
if (deviceID > 0)
{
for (i = 0; i < menuPlayers; i++)
{
if (deviceID != cv_usejoystick[i].value)
continue;
// Controller taken? Try again...
goto loweringid;
}
goto retrygetcontrol;
}
if (trydefaults && G_KeyBindIsNecessary(gc))
{
// If we still haven't found anything and the keybind is necessary,
// try it all again but with default binds.
trydefaults = false;
controltable = &(gamecontroldefault[gc][0]);
tryingotherID = false;
deviceID = cv_usejoystick[p].value;
goto retrygetcontrol;
}
return 0;
}
#undef KEYBOARDDEFAULTSSPLIT
boolean G_PlayerInputDown(UINT8 p, INT32 gc, UINT8 menuPlayers)
{
return (G_PlayerInputAnalog(p, gc, menuPlayers) != 0);
}
// Take a magnitude of two axes, and adjust it to take out the deadzone
@ -950,27 +966,15 @@ static void G_DoAnglePrediction(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer, p
void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer)
{
const UINT8 forplayer = ssplayer-1;
const INT32 lookaxis = cv_lookaxis[forplayer].value;
const boolean invertmouse = cv_invertmouse.value;
const boolean analogjoystickmove = cv_usejoystick[forplayer].value && !Joystick[forplayer].bGamepadStyle;
const boolean gamepadjoystickmove = cv_usejoystick[forplayer].value && Joystick[forplayer].bGamepadStyle;
const boolean usejoystick = (analogjoystickmove || gamepadjoystickmove);
static boolean keyboard_look[MAXSPLITSCREENPLAYERS]; // true if lookup/down using keyboard
static boolean resetdown[MAXSPLITSCREENPLAYERS]; // don't cam reset every frame
INT32 forward, axis;
INT32 forward;
joystickvector2_t joystickvector;
boolean turnleft, turnright;
player_t *player = &players[g_localplayers[forplayer]];
camera_t *thiscam = &camera[forplayer];
boolean *kbl = &keyboard_look[forplayer];
boolean *rd = &resetdown[forplayer];
const boolean mouseaiming = player->spectator;
//camera_t *thiscam = &camera[forplayer];
//boolean *kbl = &keyboard_look[forplayer];
//boolean *rd = &resetdown[forplayer];
//const boolean mouseaiming = player->spectator;
if (demo.playback) return;
@ -999,16 +1003,27 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer)
return;
}
cmd->flags = 0;
if (menuactive || chat_on || CON_Ready())
{
cmd->flags |= TICCMD_TYPING;
if (hu_keystrokes)
{
cmd->flags |= TICCMD_KEYSTROKE;
}
goto aftercmdinput;
}
if (K_PlayerUsesBotMovement(player))
{
// Bot ticcmd is generated by K_BuildBotTiccmd
return;
}
turnright = PlayerInputDown(ssplayer, gc_turnright);
turnleft = PlayerInputDown(ssplayer, gc_turnleft);
joystickvector.xaxis = PlayerJoyAxis(ssplayer, AXISTURN);
joystickvector.xaxis = G_PlayerInputAnalog(forplayer, gc_right, 0) - G_PlayerInputAnalog(forplayer, gc_left, 0);
joystickvector.yaxis = 0;
G_HandleAxisDeadZone(forplayer, &joystickvector);
@ -1016,143 +1031,99 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer)
// use it for aiming to throw items forward/backward and the vote screen
// This mean that the turn axis will still be gradient but up/down will be 0
// until the stick is pushed far enough
joystickvector.yaxis = PlayerJoyAxis(ssplayer, AXISAIM);
joystickvector.yaxis = G_PlayerInputAnalog(forplayer, gc_down, 0) - G_PlayerInputAnalog(forplayer, gc_up, 0);
if (encoremode)
{
turnright ^= turnleft; // swap these using three XORs
turnleft ^= turnright;
turnright ^= turnleft;
joystickvector.xaxis = -joystickvector.xaxis;
}
if (gamepadjoystickmove && joystickvector.xaxis != 0)
{
turnright = turnright || (joystickvector.xaxis > 0);
turnleft = turnleft || (joystickvector.xaxis < 0);
}
forward = 0;
cmd->turning = 0;
// let movement keys cancel each other out
if (turnright && !(turnleft))
{
cmd->turning -= KART_FULLTURN;
}
else if (turnleft && !(turnright))
{
cmd->turning += KART_FULLTURN;
}
if (analogjoystickmove && joystickvector.xaxis != 0)
if (joystickvector.xaxis != 0)
{
cmd->turning -= (joystickvector.xaxis * KART_FULLTURN) >> 10;
}
// Specator mouse turning
if (player->spectator)
{
cmd->turning -= (mousex * 8) * (encoremode ? -1 : 1);
}
if (player->spectator || objectplacing) // SRB2Kart: spectators need special controls
{
axis = PlayerJoyAxis(ssplayer, AXISMOVE);
if (PlayerInputDown(ssplayer, gc_accelerate) || (usejoystick && axis > 0))
if (G_PlayerInputDown(forplayer, gc_accel, 0))
{
cmd->buttons |= BT_ACCELERATE;
axis = PlayerJoyAxis(ssplayer, AXISBRAKE);
if (PlayerInputDown(ssplayer, gc_brake) || (usejoystick && axis > 0))
}
if (G_PlayerInputDown(forplayer, gc_brake, 0))
{
cmd->buttons |= BT_BRAKE;
axis = PlayerJoyAxis(ssplayer, AXISAIM);
if (PlayerInputDown(ssplayer, gc_aimforward) || (usejoystick && axis < 0))
}
if (joystickvector.yaxis < 0)
{
forward += MAXPLMOVE;
if (PlayerInputDown(ssplayer, gc_aimbackward) || (usejoystick && axis > 0))
}
if (joystickvector.yaxis > 0)
{
forward -= MAXPLMOVE;
}
}
else
{
// forward with key or button // SRB2kart - we use an accel/brake instead of forward/backward.
axis = PlayerJoyAxis(ssplayer, AXISMOVE);
if (PlayerInputDown(ssplayer, gc_accelerate) || (gamepadjoystickmove && axis > 0))
INT32 value = G_PlayerInputAnalog(forplayer, gc_accel, 0);
if (value != 0)
{
cmd->buttons |= BT_ACCELERATE;
forward = MAXPLMOVE; // 50
}
else if (analogjoystickmove && axis > 0)
{
cmd->buttons |= BT_ACCELERATE;
// JOYAXISRANGE is supposed to be 1023 (divide by 1024)
forward += ((axis * MAXPLMOVE) >> 10);
forward += ((value * MAXPLMOVE) >> 10);
}
axis = PlayerJoyAxis(ssplayer, AXISBRAKE);
if (PlayerInputDown(ssplayer, gc_brake) || (gamepadjoystickmove && axis > 0))
value = G_PlayerInputAnalog(forplayer, gc_brake, 0);
if (value != 0)
{
cmd->buttons |= BT_BRAKE;
if (cmd->buttons & BT_ACCELERATE || cmd->forwardmove <= 0)
forward -= MAXPLMOVE;
}
else if (analogjoystickmove && axis > 0)
{
cmd->buttons |= BT_BRAKE;
// JOYAXISRANGE is supposed to be 1023 (divide by 1024)
if (cmd->buttons & BT_ACCELERATE || cmd->forwardmove <= 0)
forward -= ((axis * MAXPLMOVE) >> 10);
forward -= ((value * MAXPLMOVE) >> 10);
}
// But forward/backward IS used for aiming.
if (PlayerInputDown(ssplayer, gc_aimforward))
cmd->throwdir += KART_FULLTURN;
if (PlayerInputDown(ssplayer, gc_aimbackward))
cmd->throwdir -= KART_FULLTURN;
if (analogjoystickmove && joystickvector.yaxis != 0)
if (joystickvector.yaxis != 0)
{
cmd->throwdir -= (joystickvector.yaxis * KART_FULLTURN) >> 10;
}
}
// fire with any button/key
axis = PlayerJoyAxis(ssplayer, AXISFIRE);
if (PlayerInputDown(ssplayer, gc_fire) || (usejoystick && axis > 0))
cmd->buttons |= BT_ATTACK;
// drift with any button/key
axis = PlayerJoyAxis(ssplayer, AXISDRIFT);
if (PlayerInputDown(ssplayer, gc_drift) || (usejoystick && axis > 0))
cmd->buttons |= BT_DRIFT;
// Spindash with any button/key
// Simply holds all of the inputs for you.
axis = PlayerJoyAxis(ssplayer, AXISSPINDASH);
if (PlayerInputDown(ssplayer, gc_spindash) || (usejoystick && axis > 0))
cmd->buttons |= (BT_ACCELERATE|BT_BRAKE|BT_DRIFT);
// rear view with any button/key
axis = PlayerJoyAxis(ssplayer, AXISLOOKBACK);
if (PlayerInputDown(ssplayer, gc_lookback) || (usejoystick && axis > 0))
cmd->buttons |= BT_LOOKBACK;
// Lua scriptable buttons
if (PlayerInputDown(ssplayer, gc_custom1))
cmd->buttons |= BT_CUSTOM1;
if (PlayerInputDown(ssplayer, gc_custom2))
cmd->buttons |= BT_CUSTOM2;
if (PlayerInputDown(ssplayer, gc_custom3))
cmd->buttons |= BT_CUSTOM3;
// Reset camera
if (PlayerInputDown(ssplayer, gc_camreset))
// drift
if (G_PlayerInputDown(forplayer, gc_drift, 0))
{
if (thiscam->chase && *rd == false)
P_ResetCamera(player, thiscam);
*rd = true;
cmd->buttons |= BT_DRIFT;
}
else
*rd = false;
// C
if (G_PlayerInputDown(forplayer, gc_spindash, 0))
{
forward = 0;
cmd->buttons |= BT_SPINDASHMASK;
}
// fire
if (G_PlayerInputDown(forplayer, gc_item, 0))
{
cmd->buttons |= BT_ATTACK;
}
// rear view
if (G_PlayerInputDown(forplayer, gc_lookback, 0))
{
cmd->buttons |= BT_LOOKBACK;
}
// lua buttons a thru c
if (G_PlayerInputDown(forplayer, gc_luaa, 0)) { cmd->buttons |= BT_LUAA; }
if (G_PlayerInputDown(forplayer, gc_luab, 0)) { cmd->buttons |= BT_LUAB; }
if (G_PlayerInputDown(forplayer, gc_luac, 0)) { cmd->buttons |= BT_LUAC; }
// spectator aiming shit, ahhhh...
/*
{
INT32 player_invert = invertmouse ? -1 : 1;
INT32 screen_invert =
@ -1160,15 +1131,6 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer)
&& (!thiscam->chase)) //because chasecam's not inverted
? -1 : 1; // set to -1 or 1 to multiply
// mouse look stuff (mouse look is not the same as mouse aim)
if (mouseaiming && player->spectator)
{
*kbl = false;
// looking up/down
cmd->aiming += (mlooky<<19)*player_invert*screen_invert;
}
axis = PlayerJoyAxis(ssplayer, AXISLOOK);
if (analogjoystickmove && axis != 0 && lookaxis && player->spectator)
cmd->aiming += (axis<<16) * screen_invert;
@ -1194,22 +1156,11 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer)
if (PlayerInputDown(ssplayer, gc_centerview)) // No need to put a spectator limit on this one though :V
cmd->aiming = 0;
}
mousex = mousey = mlooky = 0;
*/
cmd->forwardmove += (SINT8)forward;
cmd->flags = 0;
if (chat_on || CON_Ready())
{
cmd->flags |= TICCMD_TYPING;
if (hu_keystrokes)
{
cmd->flags |= TICCMD_KEYSTROKE;
}
}
aftercmdinput:
/* Lua: Allow this hook to overwrite ticcmd.
We check if we're actually in a level because for some reason this Hook would run in menus and on the titlescreen otherwise.
@ -1304,7 +1255,7 @@ static void weaponPrefChange4(void)
//
void G_DoLoadLevel(boolean resetplayer)
{
INT32 i, j;
INT32 i;
// Make sure objectplace is OFF when you first start the level!
OP_ResetObjectplace();
@ -1314,6 +1265,8 @@ void G_DoLoadLevel(boolean resetplayer)
if (wipegamestate == GS_LEVEL)
wipegamestate = -1; // force a wipe
if (cv_currprofile.value == -1)
PR_ApplyProfilePretend(cv_ttlprofilen.value, 0);
if (gamestate == GS_INTERMISSION)
Y_EndIntermission();
if (gamestate == GS_VOTING)
@ -1335,6 +1288,8 @@ void G_DoLoadLevel(boolean resetplayer)
titlemapinaction = TITLEMAP_OFF;
G_SetGamestate(GS_LEVEL);
if (wipegamestate == GS_MENU)
M_ClearMenus(true);
I_UpdateMouseGrab();
for (i = 0; i < MAXPLAYERS; i++)
@ -1364,12 +1319,7 @@ void G_DoLoadLevel(boolean resetplayer)
// clear cmd building stuff
memset(gamekeydown, 0, sizeof (gamekeydown));
for (i = 0;i < JOYAXISSET; i++)
{
for (j = 0; j < MAXSPLITSCREENPLAYERS; j++)
joyxmove[j][i] = joyymove[j][i] = 0;
}
mousex = mousey = 0;
memset(deviceResponding, false, sizeof (deviceResponding));
// clear hud messages remains (usually from game startup)
CON_ClearHUD();
@ -1468,7 +1418,7 @@ static INT32 camtoggledelay[MAXSPLITSCREENPLAYERS];
//
boolean G_Responder(event_t *ev)
{
UINT8 i;
//INT32 i;
// any other key pops up menu if in demos
if (gameaction == ga_nothing && !demo.quitafterplaying &&
@ -1563,7 +1513,7 @@ boolean G_Responder(event_t *ev)
// allow spy mode changes even during the demo
if (gamestate == GS_LEVEL && ev->type == ev_keydown
&& (ev->data1 == KEY_F12 || ev->data1 == gamecontrol[0][gc_viewpoint][0] || ev->data1 == gamecontrol[0][gc_viewpoint][1]))
&& (ev->data1 == KEY_F12 /*|| ev->data1 == gamecontrol[0][gc_viewpoint][0] || ev->data1 == gamecontrol[0][gc_viewpoint][1]*/))
{
if (!demo.playback && (r_splitscreen || !netgame))
g_localplayers[0] = consoleplayer;
@ -1581,6 +1531,7 @@ boolean G_Responder(event_t *ev)
if (gamestate == GS_LEVEL && ev->type == ev_keydown && multiplayer && demo.playback && !demo.freecam)
{
/*
if (ev->data1 == gamecontrol[1][gc_viewpoint][0] || ev->data1 == gamecontrol[1][gc_viewpoint][1])
{
G_AdjustView(2, 1, true);
@ -1596,12 +1547,13 @@ boolean G_Responder(event_t *ev)
G_AdjustView(4, 1, true);
return true;
}
*/
// Allow pausing
if (
ev->data1 == gamecontrol[0][gc_pause][0]
|| ev->data1 == gamecontrol[0][gc_pause][1]
|| ev->data1 == KEY_PAUSE
//ev->data1 == gamecontrol[0][gc_pause][0]
//|| ev->data1 == gamecontrol[0][gc_pause][1]
ev->data1 == KEY_PAUSE
)
{
paused = !paused;
@ -1635,9 +1587,9 @@ boolean G_Responder(event_t *ev)
switch (ev->type)
{
case ev_keydown:
if (ev->data1 == gamecontrol[0][gc_pause][0]
|| ev->data1 == gamecontrol[0][gc_pause][1]
|| ev->data1 == KEY_PAUSE)
if (//ev->data1 == gamecontrol[0][gc_pause][0]
//|| ev->data1 == gamecontrol[0][gc_pause][1]
ev->data1 == KEY_PAUSE)
{
if (modeattacking && !demo.playback && (gamestate == GS_LEVEL))
{
@ -1667,6 +1619,7 @@ boolean G_Responder(event_t *ev)
}
}
/*
for (i = 0; i < MAXSPLITSCREENPLAYERS; i++)
{
if (ev->data1 == gamecontrol[i][gc_camtoggle][0]
@ -1679,6 +1632,7 @@ boolean G_Responder(event_t *ev)
}
}
}
*/
return true;
@ -1691,15 +1645,6 @@ boolean G_Responder(event_t *ev)
case ev_joystick:
return true; // eat events
case ev_joystick2:
return true; // eat events
case ev_joystick3:
return true; // eat events
case ev_joystick4:
return true; // eat events
default:
break;
}
@ -2044,8 +1989,7 @@ void G_Ticker(boolean run)
HU_Ticker();
break;
case GS_TIMEATTACK:
F_MenuPresTicker(run);
case GS_MENU:
break;
case GS_INTRO:
@ -3323,12 +3267,11 @@ INT16 G_SometimesGetDifferentGametype(void)
// G_GetGametypeColor
//
// Pretty and consistent ^u^
// See also M_GetGametypeColor.
// See also M_GetGametypeColor (if that still exists).
//
UINT8 G_GetGametypeColor(INT16 gt)
{
if (modeattacking // == ATTACKING_TIME
|| gamestate == GS_TIMEATTACK)
if (modeattacking) // == ATTACKING_RECORD
return orangemap[0];
if (gt == GT_BATTLE)
@ -3802,8 +3745,6 @@ demointermission:
// See also F_EndCutscene, the only other place which handles intra-map/ending transitions
void G_AfterIntermission(void)
{
Y_CleanupScreenBuffer();
if (modeattacking)
{
M_EndModeAttackRun();
@ -3820,9 +3761,11 @@ void G_AfterIntermission(void)
{
G_StopDemo();
#if 0
if (demo.inreplayhut)
M_ReplayHut(0);
else
#endif
D_StartTitle();
return;
@ -4044,9 +3987,6 @@ void G_LoadGameData(void)
totalplaytime = 0; // total play time (separate from all)
matchesplayed = 0; // SRB2Kart: matches played & finished
for (i = 0; i < PWRLV_NUMTYPES; i++) // SRB2Kart: online rank system
vspowerlevel[i] = PWRLVRECORD_START;
if (M_CheckParm("-nodata"))
return; // Don't load.
@ -4076,19 +4016,12 @@ void G_LoadGameData(void)
Z_Free(savebuffer);
save_p = NULL;
I_Error("Game data is from another version of SRB2.\nDelete %s(maybe in %s) and try again.", gamedatafilename, gdfolder);
I_Error("Game data is from another version of SRB2.\nDelete %s (maybe in %s) and try again.", gamedatafilename, gdfolder);
}
totalplaytime = READUINT32(save_p);
matchesplayed = READUINT32(save_p);
for (i = 0; i < PWRLV_NUMTYPES; i++)
{
vspowerlevel[i] = READUINT16(save_p);
if (vspowerlevel[i] < PWRLVRECORD_MIN || vspowerlevel[i] > PWRLVRECORD_MAX)
goto datacorrupt;
}
modded = READUINT8(save_p);
// Aha! Someone's been screwing with the save file!
@ -4205,9 +4138,6 @@ void G_SaveGameData(void)
WRITEUINT32(save_p, totalplaytime);
WRITEUINT32(save_p, matchesplayed);
for (i = 0; i < PWRLV_NUMTYPES; i++)
WRITEUINT16(save_p, vspowerlevel[i]);
WRITEUINT8(save_p, (UINT8)savemoddata);
// TODO put another cipher on these things? meh, I don't care...
@ -4271,6 +4201,9 @@ void G_SaveGameData(void)
FIL_WriteFile(va(pandf, srb2home, gamedatafilename), savebuffer, length);
free(savebuffer);
save_p = savebuffer = NULL;
// Also save profiles here.
PR_SaveProfiles();
}
#define VERSIONSIZE 16
@ -4589,8 +4522,6 @@ void G_InitNew(UINT8 pencoremode, const char *mapname, boolean resetplayer, bool
(void)FLS;
Y_CleanupScreenBuffer();
if (paused)
{
paused = false;

View file

@ -65,7 +65,6 @@ extern consvar_t cv_lookaxis[MAXSPLITSCREENPLAYERS];
extern consvar_t cv_fireaxis[MAXSPLITSCREENPLAYERS];
extern consvar_t cv_driftaxis[MAXSPLITSCREENPLAYERS];
extern consvar_t cv_deadzone[MAXSPLITSCREENPLAYERS];
extern consvar_t cv_digitaldeadzone[MAXSPLITSCREENPLAYERS];
extern consvar_t cv_ghost_besttime, cv_ghost_bestlap, cv_ghost_last, cv_ghost_guest, cv_ghost_staff;
@ -96,26 +95,6 @@ ticcmd_t *G_MoveTiccmd(ticcmd_t* dest, const ticcmd_t* src, const size_t n);
INT32 G_ClipAimingPitch(INT32 *aiming);
INT16 G_SoftwareClipAimingPitch(INT32 *aiming);
typedef enum
{
AXISNONE = 0,
AXISTURN,
AXISMOVE,
AXISBRAKE,
AXISLOOK,
AXISDIGITAL, // axes below this use digital deadzone
AXISFIRE = AXISDIGITAL,
AXISDRIFT,
AXISSPINDASH,
AXISLOOKBACK,
AXISAIM,
} axis_input_e;
INT32 PlayerJoyAxis(UINT8 player, axis_input_e axissel);
extern angle_t localangle[MAXSPLITSCREENPLAYERS];
extern INT32 localaiming[MAXSPLITSCREENPLAYERS]; // should be an angle_t but signed
extern INT32 localsteering[MAXSPLITSCREENPLAYERS];
@ -123,6 +102,9 @@ extern INT32 localdelta[MAXSPLITSCREENPLAYERS];
extern INT32 localstoredeltas[MAXSPLITSCREENPLAYERS][TICCMD_LATENCYMASK + 1];
extern UINT8 localtic;
INT32 G_PlayerInputAnalog(UINT8 p, INT32 gc, UINT8 menuPlayers);
boolean G_PlayerInputDown(UINT8 p, INT32 gc, UINT8 menuPlayers);
//
// GAME
//

File diff suppressed because it is too large Load diff

View file

@ -23,110 +23,93 @@
#define NUMKEYS 256
#define MOUSEBUTTONS 8
#define JOYBUTTONS 32 // 32 buttons
#define JOYHATS 4 // 4 hats
#define JOYAXISSET 4 // 4 Sets of 2 axises
#define JOYBUTTONS 21 // 21 buttons, to match SDL_GameControllerButton
#define JOYANALOGS 2 // 2 sets of analog stick axes, with positive and negative each
#define JOYTRIGGERS 1 // 1 set of trigger axes, positive only
#define JOYAXISSETS (JOYANALOGS + JOYTRIGGERS)
#define JOYAXES ((4 * JOYANALOGS) + (2 * JOYTRIGGERS))
#define MAXINPUTMAPPING 4
//
// mouse and joystick buttons are handled as 'virtual' keys
//
typedef enum
{
KEY_MOUSE1 = NUMKEYS,
KEY_JOY1 = KEY_MOUSE1 + MOUSEBUTTONS,
KEY_HAT1 = KEY_JOY1 + JOYBUTTONS,
KEY_JOY1 = NUMKEYS,
KEY_HAT1 = KEY_JOY1 + 11, // macro for SDL_CONTROLLER_BUTTON_DPAD_UP
KEY_AXIS1 = KEY_JOY1 + JOYBUTTONS,
JOYINPUTEND = KEY_AXIS1 + JOYAXES,
KEY_DBLMOUSE1 =KEY_HAT1 + JOYHATS*4, // double clicks
KEY_DBLJOY1 = KEY_DBLMOUSE1 + MOUSEBUTTONS,
KEY_DBLHAT1 = KEY_DBLJOY1 + JOYBUTTONS,
KEY_2MOUSE1 = KEY_DBLHAT1 + JOYHATS*4,
KEY_2JOY1 = KEY_2MOUSE1 + MOUSEBUTTONS,
KEY_2HAT1 = KEY_2JOY1 + JOYBUTTONS,
KEY_DBL2MOUSE1 = KEY_2HAT1 + JOYHATS*4,
KEY_DBL2JOY1 = KEY_DBL2MOUSE1 + MOUSEBUTTONS,
KEY_DBL2HAT1 = KEY_DBL2JOY1 + JOYBUTTONS,
KEY_3JOY1 = KEY_DBL2HAT1 + JOYHATS*4,
KEY_3HAT1 = KEY_3JOY1 + JOYBUTTONS,
KEY_DBL3JOY1 = KEY_3HAT1 + JOYHATS*4,
KEY_DBL3HAT1 = KEY_DBL3JOY1 + JOYBUTTONS,
KEY_4JOY1 = KEY_DBL3HAT1 + JOYHATS*4,
KEY_4HAT1 = KEY_4JOY1 + JOYBUTTONS,
KEY_DBL4JOY1 = KEY_4HAT1 + JOYHATS*4,
KEY_DBL4HAT1 = KEY_DBL4JOY1 + JOYBUTTONS,
KEY_MOUSEWHEELUP = KEY_DBL4HAT1 + JOYHATS*4,
KEY_MOUSE1 = JOYINPUTEND,
KEY_MOUSEMOVE = KEY_MOUSE1 + MOUSEBUTTONS,
KEY_MOUSEWHEELUP = KEY_MOUSEMOVE + 4,
KEY_MOUSEWHEELDOWN = KEY_MOUSEWHEELUP + 1,
KEY_2MOUSEWHEELUP = KEY_MOUSEWHEELDOWN + 1,
KEY_2MOUSEWHEELDOWN = KEY_2MOUSEWHEELUP + 1,
MOUSEINPUTEND = KEY_MOUSEWHEELDOWN + 1,
NUMINPUTS = KEY_2MOUSEWHEELDOWN + 1,
NUMINPUTS = MOUSEINPUTEND,
} key_input_e;
typedef enum
{
gc_null = 0, // a key/button mapped to gc_null has no effect
gc_aimforward,
gc_aimbackward,
gc_turnleft,
gc_turnright,
gc_accelerate,
gc_drift,
gc_brake,
gc_spindash,
gc_fire,
gc_lookback,
gc_camreset,
gc_camtoggle,
gc_spectate,
gc_lookup,
gc_lookdown,
gc_centerview,
gc_talkkey,
gc_teamkey,
gc_scores,
// The actual gamepad
gc_up,
gc_down,
gc_left,
gc_right,
gc_a,
gc_b,
gc_c,
gc_x,
gc_y,
gc_z,
gc_l,
gc_r,
gc_start,
// special keys
gc_abc,
gc_luaa,
gc_luab,
gc_luac,
gc_console,
gc_pause,
gc_systemmenu,
gc_talk,
gc_teamtalk,
gc_screenshot,
gc_recordgif,
gc_viewpoint,
gc_custom1, // Lua scriptable
gc_custom2, // Lua scriptable
gc_custom3, // Lua scriptable
num_gamecontrols
} gamecontrols_e;
typedef enum
{
gcs_custom,
gcs_kart, // Kart doesn't really need this code, like, at all? But I don't feel like removing it.
num_gamecontrolschemes
} gamecontrolschemes_e;
num_gamecontrols,
// alias gameplay controls
gc_accel = gc_a,
gc_brake = gc_x,
gc_drift = gc_r,
gc_item = gc_l,
gc_spindash = gc_c,
gc_lookback = gc_b,
} gamecontrols_e;
// mouse values are used once
extern consvar_t cv_mousesens, cv_mouseysens;
extern consvar_t cv_mousesens2, cv_mouseysens2;
extern consvar_t cv_controlperkey;
extern INT32 mousex, mousey;
extern INT32 mlooky; //mousey with mlookSensitivity
// current state of the keys: JOYAXISRANGE or 0 when boolean.
// Or anything inbetween for analog values
#define MAXDEVICES (MAXGAMEPADS + 1) // Gamepads + keyboard & mouse
extern INT32 gamekeydown[MAXDEVICES][NUMINPUTS];
extern boolean deviceResponding[MAXDEVICES];
extern INT32 joyxmove[MAXSPLITSCREENPLAYERS][JOYAXISSET], joyymove[MAXSPLITSCREENPLAYERS][JOYAXISSET];
// current state of the keys: true if pushed
extern UINT8 gamekeydown[NUMINPUTS];
// two key codes (or virtual key) per game control
extern INT32 gamecontrol[MAXSPLITSCREENPLAYERS][num_gamecontrols][2];
extern INT32 gamecontroldefault[MAXSPLITSCREENPLAYERS][num_gamecontrolschemes][num_gamecontrols][2]; // default control storage, use 0 (gcs_custom) for memory retention
#define PlayerInputDown(p, gc) (gamekeydown[gamecontrol[p-1][gc][0]] || gamekeydown[gamecontrol[p-1][gc][1]])
// several key codes (or virtual key) per game control
extern INT32 gamecontrol[MAXSPLITSCREENPLAYERS][num_gamecontrols][MAXINPUTMAPPING];
extern INT32 gamecontroldefault[num_gamecontrols][MAXINPUTMAPPING]; // default control storage
/*
#define num_gcl_accelerate 1
#define num_gcl_brake 1
#define num_gcl_drift 1
@ -142,10 +125,13 @@ extern const INT32 gcl_spindash[num_gcl_spindash];
extern const INT32 gcl_movement[num_gcl_movement];
extern const INT32 gcl_item[num_gcl_item];
extern const INT32 gcl_full[num_gcl_full];
*/
// peace to my little coder fingers!
// check a gamecontrol being active or not
INT32 G_GetDevicePlayer(INT32 deviceID);
// remaps the input event to a game control.
void G_MapEventsToControls(event_t *ev);
@ -153,17 +139,20 @@ void G_MapEventsToControls(event_t *ev);
const char *G_KeynumToString(INT32 keynum);
INT32 G_KeyStringtoNum(const char *keystr);
boolean G_KeyBindIsNecessary(INT32 gc);
boolean G_KeyIsAvailable(INT32 key, INT32 deviceID);
// detach any keys associated to the given game control
void G_ClearControlKeys(INT32 (*setupcontrols)[2], INT32 control);
void G_ClearControlKeys(INT32 (*setupcontrols)[MAXINPUTMAPPING], INT32 control);
void G_ClearAllControlKeys(void);
void Command_Setcontrol_f(void);
void Command_Setcontrol2_f(void);
void Command_Setcontrol3_f(void);
void Command_Setcontrol4_f(void);
void G_DefineDefaultControls(void);
INT32 G_GetControlScheme(INT32 (*fromcontrols)[2], const INT32 *gclist, INT32 gclen);
void G_CopyControls(INT32 (*setupcontrols)[2], INT32 (*fromcontrols)[2], const INT32 *gclist, INT32 gclen);
void G_SaveKeySetting(FILE *f, INT32 (*fromcontrolsa)[2], INT32 (*fromcontrolsb)[2], INT32 (*fromcontrolsc)[2], INT32 (*fromcontrolsd)[2]);
INT32 G_CheckDoubleUsage(INT32 keynum, boolean modify);
INT32 G_GetControlScheme(INT32 (*fromcontrols)[MAXINPUTMAPPING], const INT32 *gclist, INT32 gclen);
void G_CopyControls(INT32 (*setupcontrols)[MAXINPUTMAPPING], INT32 (*fromcontrols)[MAXINPUTMAPPING], const INT32 *gclist, INT32 gclen);
void G_SaveKeySetting(FILE *f, INT32 (*fromcontrolsa)[MAXINPUTMAPPING], INT32 (*fromcontrolsb)[MAXINPUTMAPPING], INT32 (*fromcontrolsc)[MAXINPUTMAPPING], INT32 (*fromcontrolsd)[MAXINPUTMAPPING]);
INT32 G_CheckDoubleUsage(INT32 keynum, INT32 playernum, boolean modify);
#endif

View file

@ -27,7 +27,7 @@ typedef enum
GS_CONTINUING, // continue screen
GS_TITLESCREEN, // title screen
GS_TIMEATTACK, // time attack menu
GS_MENU, // SRB2Kart: menu-only (previously was GS_TIMEATTACK)
GS_CREDITS, // credit sequence
GS_EVALUATION, // Evaluation at the end of a game.

View file

@ -17,7 +17,7 @@
#include "../z_zone.h"
#include "../console.h"
#include "../v_video.h"
#include "../m_menu.h"
#include "../k_menu.h"
#include "../i_system.h"
#include "../m_argv.h"
#include "../i_video.h"

View file

@ -6603,6 +6603,7 @@ void HWR_AddCommands(void)
CV_RegisterVar(&cv_glshearing);
CV_RegisterVar(&cv_glshaders);
CV_RegisterVar(&cv_glallowshaders);
CV_RegisterVar(&cv_glanisotropicmode);
CV_RegisterVar(&cv_glfiltermode);
CV_RegisterVar(&cv_glsolvetjoin);
@ -6618,7 +6619,7 @@ void HWR_AddSessionCommands(void)
{
if (gl_sessioncommandsadded)
return;
CV_RegisterVar(&cv_glanisotropicmode);
// Kept in case we ever need this again.
gl_sessioncommandsadded = true;
}

View file

@ -23,7 +23,7 @@ Documentation available here.
#include "command.h"
#include "console.h"
#include "m_argv.h"
#include "m_menu.h"
#include "k_menu.h"
#include "mserv.h"
#include "i_tcp.h"/* for current_port */
#include "i_threads.h"

View file

@ -16,7 +16,7 @@
#include "hu_stuff.h"
#include "font.h"
#include "m_menu.h" // gametype_cons_t
#include "k_menu.h" // gametype_cons_t
#include "m_cond.h" // emblems
#include "m_misc.h" // word jumping
@ -237,15 +237,13 @@ void HU_Init(void)
DIG (3);
ADIM (HU);
PR ("STCFN");
REG;
PR ("TNYFN");
REG;
ADIM (KART);
PR ("MKFNT");
PR ("FILEF");
REG;
ADIM (LT);
@ -279,6 +277,26 @@ void HU_Init(void)
PR ("PINGN");
REG;
PR ("PRFN");
REG;
DIG (3);
ADIM (KART);
PR ("MKFNT");
REG;
ADIM (LT);
PR ("GAMEM");
REG;
ADIM (LT);
PR ("THIFN");
REG;
PR ("TLWFN");
REG;
#undef REG
#undef DIG
#undef PR
@ -976,10 +994,12 @@ void HU_Ticker(void)
hu_tick++;
hu_tick &= 7; // currently only to blink chat input cursor
/*
if (PlayerInputDown(1, gc_scores))
hu_showscores = !chat_on;
else
hu_showscores = false;
*/
hu_keystrokes = false;
@ -1195,16 +1215,24 @@ boolean HU_Responder(event_t *ev)
// (Unless if you're sharing a keyboard, since you probably establish when you start chatting that you have dibs on it...)
// (Ahhh, the good ol days when I was a kid who couldn't afford an extra USB controller...)
if (ev->data1 >= KEY_MOUSE1)
if (ev->data1 >= NUMKEYS)
{
INT32 i;
INT32 i, j;
for (i = 0; i < num_gamecontrols; i++)
{
if (gamecontrol[0][i][0] == ev->data1 || gamecontrol[0][i][1] == ev->data1)
for (j = 0; j < MAXINPUTMAPPING; j++)
{
if (gamecontrol[0][i][j] == ev->data1)
break;
}
if (j < MAXINPUTMAPPING)
{
break;
}
}
if (i == num_gamecontrols)
if (i == num_gamecontrols && j == MAXINPUTMAPPING)
return false;
}
@ -1212,7 +1240,7 @@ boolean HU_Responder(event_t *ev)
if (!chat_on)
{
// enter chat mode
if ((ev->data1 == gamecontrol[0][gc_talkkey][0] || ev->data1 == gamecontrol[0][gc_talkkey][1])
if ((ev->data1 == gamecontrol[0][gc_talk][0] || ev->data1 == gamecontrol[0][gc_talk][1])
&& netgame && !OLD_MUTE) // check for old chat mute, still let the players open the chat incase they want to scroll otherwise.
{
chat_on = true;
@ -1222,7 +1250,7 @@ boolean HU_Responder(event_t *ev)
typelines = 1;
return true;
}
if ((ev->data1 == gamecontrol[0][gc_teamkey][0] || ev->data1 == gamecontrol[0][gc_teamkey][1])
if ((ev->data1 == gamecontrol[0][gc_teamtalk][0] || ev->data1 == gamecontrol[0][gc_teamtalk][1])
&& netgame && !OLD_MUTE)
{
chat_on = true;
@ -1246,9 +1274,9 @@ boolean HU_Responder(event_t *ev)
return true;
// Ignore non-keyboard keys, except when the talk key is bound
if (ev->data1 >= KEY_MOUSE1
&& (ev->data1 != gamecontrol[0][gc_talkkey][0]
&& ev->data1 != gamecontrol[0][gc_talkkey][1]))
if (ev->data1 >= NUMKEYS
/*&& (ev->data1 != gamecontrol[0][gc_talkkey][0]
&& ev->data1 != gamecontrol[0][gc_talkkey][1])*/)
return false;
c = CON_ShiftChar(c);
@ -1310,9 +1338,9 @@ boolean HU_Responder(event_t *ev)
I_UpdateMouseGrab();
}
else if (c == KEY_ESCAPE
|| ((c == gamecontrol[0][gc_talkkey][0] || c == gamecontrol[0][gc_talkkey][1]
/*|| ((c == gamecontrol[0][gc_talkkey][0] || c == gamecontrol[0][gc_talkkey][1]
|| c == gamecontrol[0][gc_teamkey][0] || c == gamecontrol[0][gc_teamkey][1])
&& c >= KEY_MOUSE1)) // If it's not a keyboard key, then the chat button is used as a toggle.
&& c >= NUMKEYS)*/) // If it's not a keyboard key, then the chat button is used as a toggle.
{
chat_on = false;
c_input = 0; // reset input cursor
@ -1579,7 +1607,7 @@ static void HU_drawChatLog(INT32 offset)
INT32 x = chatx+2, y, dx = 0, dy = 0;
UINT32 i = 0;
INT32 chat_topy, chat_bottomy;
INT32 highlight = HU_GetHighlightColor();
INT32 highlight = V_YELLOWMAP;
boolean atbottom = false;
// make sure that our scroll position isn't "illegal";
@ -2374,9 +2402,7 @@ static void HU_DrawRankings(void)
V_DrawFadeScreen(0xFF00, 16); // A little more readable, and prevents cheating the fades under other circumstances.
if (cons_menuhighlight.value)
hilicol = cons_menuhighlight.value;
else if (modeattacking)
if (modeattacking)
hilicol = V_ORANGEMAP;
else
hilicol = ((gametype == GT_RACE) ? V_SKYMAP : V_REDMAP);
@ -2385,7 +2411,7 @@ static void HU_DrawRankings(void)
if (modeattacking)
V_DrawString(4, 188, hilicol|V_SNAPTOBOTTOM|V_SNAPTOLEFT, "Record Attack");
else
V_DrawString(4, 188, hilicol|V_SNAPTOBOTTOM|V_SNAPTOLEFT, gametype_cons_t[gametype].strvalue);
V_DrawString(4, 188, hilicol|V_SNAPTOBOTTOM|V_SNAPTOLEFT, Gametype_Names[gametype]);
if ((gametyperules & (GTR_TIMELIMIT|GTR_POINTLIMIT)) && !bossinfo.boss)
{

View file

@ -32,6 +32,11 @@
#define KART_FONTEND 'Z'
#define KART_FONTSIZE (KART_FONTEND - KART_FONTSTART + 1)
#define AZ_FONTSTART 'A' // the first font character
#define AZ_FONTEND 'Z'
#define AZ_FONTSIZE (AZ_FONTEND - AZ_FONTSTART + 1)
//
// Level title font
@ -49,7 +54,7 @@ enum
{
X (HU),
X (TINY),
X (KART),
X (FILE),
X (LT),
X (CRED),
@ -60,6 +65,12 @@ enum
X (TALLNUM),
X (NIGHTSNUM),
X (PINGNUM),
X (PROFNUM),
X (KART),
X (GM),
X (LSHI),
X (LSLOW),
};
#undef X

View file

@ -110,7 +110,7 @@ boolean K_AddBot(UINT8 skin, UINT8 difficulty, UINT8 *p)
void K_UpdateMatchRaceBots(void)
{
const UINT8 difficulty = cv_kartbot.value;
UINT8 pmax = min((dedicated ? MAXPLAYERS-1 : MAXPLAYERS), cv_maxplayers.value);
UINT8 pmax = min((dedicated ? MAXPLAYERS-1 : MAXPLAYERS), cv_maxconnections.value);
UINT8 numplayers = 0;
UINT8 numbots = 0;
UINT8 numwaiting = 0;
@ -136,9 +136,9 @@ void K_UpdateMatchRaceBots(void)
}
}
if (cv_ingamecap.value > 0)
if (cv_maxplayers.value > 0)
{
pmax = min(pmax, cv_ingamecap.value);
pmax = min(pmax, cv_maxplayers.value);
}
for (i = 0; i < MAXPLAYERS; i++)

View file

@ -44,7 +44,7 @@ boolean K_OrbinautJawzCollide(mobj_t *t1, mobj_t *t2)
if ((t1->threshold > 0 && t2->hitlag > 0) || (t2->threshold > 0 && t1->hitlag > 0))
return true;
if (((t1->target == t2) || (!(t2->flags & (MF_ENEMY|MF_BOSS)) && (t1->target == t2->target))) && (t1->threshold > 0 || (t2->type != MT_PLAYER && t2->threshold > 0)))
if (((t1->target == t2) || (!(t2->flags & (MF_ENEMY|MF_BOSS)) && (t1->target == t2->target))) && ((t1->threshold > 0 && t2->type == MT_PLAYER) || (t2->type != MT_PLAYER && t2->threshold > 0)))
return true;
if (t1->health <= 0 || t2->health <= 0)

View file

@ -175,6 +175,23 @@ static void K_SetFollowerState(mobj_t *f, statenum_t state)
}
}
/*--------------------------------------------------
UINT16 K_GetEffectiveFollowerColor(UINT16 followercolor, UINT16 playercolor)
See header file for description.
--------------------------------------------------*/
UINT16 K_GetEffectiveFollowerColor(UINT16 followercolor, UINT16 playercolor)
{
if (followercolor < numskincolors) // bog standard
return followercolor;
if (followercolor == FOLLOWERCOLOR_OPPOSITE) // "Opposite"
return skincolors[playercolor].invcolor;
//if (followercolor == FOLLOWERCOLOR_MATCH) -- "Match"
return playercolor;
}
/*--------------------------------------------------
static void K_UpdateFollowerState(mobj_t *f, statenum_t state, followerstate_t type)
@ -302,24 +319,7 @@ void K_HandleFollower(player_t *player)
}
// Set follower colour
switch (player->followercolor)
{
case FOLLOWERCOLOR_MATCH: // "Match"
color = player->skincolor;
break;
case FOLLOWERCOLOR_OPPOSITE: // "Opposite"
color = skincolors[player->skincolor].invcolor;
break;
default:
color = player->followercolor;
if (color == 0 || color > MAXSKINCOLORS+2) // Make sure this isn't garbage
{
color = player->skincolor; // "Match" as fallback.
}
break;
}
color = K_GetEffectiveFollowerColor(player->followercolor, player->skincolor);
if (player->follower == NULL) // follower doesn't exist / isn't valid
{

View file

@ -15,7 +15,6 @@
#include "doomdef.h"
#include "doomstat.h"
#include "r_skins.h"
#define FOLLOWERCOLOR_MATCH UINT16_MAX
#define FOLLOWERCOLOR_OPPOSITE (UINT16_MAX-1)
@ -48,6 +47,7 @@ typedef struct follower_s
{
char skinname[SKINNAMESIZE+1]; // Skin Name. This is what to refer to when asking the commands anything.
char name[SKINNAMESIZE+1]; // Name. This is used for the menus. We'll just follow the same rules as skins for this.
char icon[8+1]; // Lump names are only 8 characters. (+1 for \0)
skincolornum_t defaultcolor; // default color for menus.
followermode_t mode; // Follower behavior modifier.
@ -136,6 +136,23 @@ boolean K_SetFollowerByName(INT32 playernum, const char *skinname);
void K_SetFollowerByNum(INT32 playernum, INT32 skinnum);
/*--------------------------------------------------
UINT16 K_GetEffectiveFollowerColor(UINT16 followercolor, UINT16 playercolor)
Updates a player's follower pointer, and does
its positioning and animations.
Input Arguments:-
followercolor - The raw color setting for the follower
playercolor - The player's associated colour, for reference
Return:-
The resultant skincolor enum for the follower
--------------------------------------------------*/
UINT16 K_GetEffectiveFollowerColor(UINT16 followercolor, UINT16 playercolor);
/*--------------------------------------------------
void K_HandleFollower(player_t *player)

View file

@ -662,6 +662,8 @@ const char *K_GetItemPatch(UINT8 item, boolean tiny)
return (tiny ? "K_ISMINE" : "K_ITMINE");
case KITEM_LANDMINE:
return (tiny ? "K_ISLNDM" : "K_ITLNDM");
case KITEM_DROPTARGET:
return (tiny ? "K_ISDTRG" : "K_ITDTRG");
case KITEM_BALLHOG:
return (tiny ? "K_ISBHOG" : "K_ITBHOG");
case KITEM_SPB:
@ -4469,7 +4471,7 @@ void K_drawKartFreePlay(void)
if (((leveltime-lt_endtime) % TICRATE) < TICRATE/2)
return;
V_DrawKartString((BASEVIDWIDTH - (LAPS_X+1)) - (12*9), // mirror the laps thingy
V_DrawKartString((BASEVIDWIDTH - (LAPS_X+1)) - 72, // mirror the laps thingy
LAPS_Y+3, V_HUDTRANS|V_SLIDEIN|V_SNAPTOBOTTOM|V_SNAPTORIGHT, "FREE PLAY");
}

View file

@ -2824,91 +2824,107 @@ void K_PlayOvertakeSound(mobj_t *source)
K_RegularVoiceTimers(source->player);
}
void K_PlayPainSound(mobj_t *source)
void K_PlayPainSound(mobj_t *source, mobj_t *other)
{
sfxenum_t pick = P_RandomKey(2); // Gotta roll the RNG every time this is called for sync reasons
sfxenum_t sfx_id = ((skin_t *)source->skin)->soundsid[S_sfx[sfx_khurt1 + pick].skinsound];
boolean alwaysHear = false;
if (other != NULL && P_MobjWasRemoved(other) == false && other->player != NULL)
{
alwaysHear = P_IsDisplayPlayer(other->player);
}
if (cv_kartvoices.value)
S_StartSound(source, sfx_khurt1 + pick);
{
S_StartSound(alwaysHear ? NULL : source, sfx_id);
}
K_RegularVoiceTimers(source->player);
}
void K_PlayHitEmSound(mobj_t *source, mobj_t *victim)
void K_PlayHitEmSound(mobj_t *source, mobj_t *other)
{
const boolean victimIsLocal = (victim != NULL && P_IsDisplayPlayer(victim->player) == true);
sfxenum_t sfx_id = ((skin_t *)source->skin)->soundsid[S_sfx[sfx_khitem].skinsound];
boolean alwaysHear = false;
if (source->player->follower)
if (other != NULL && P_MobjWasRemoved(other) == false && other->player != NULL)
{
follower_t fl = followers[source->player->followerskin];
source->player->follower->movecount = fl.hitconfirmtime; // movecount is used to play the hitconfirm animation for followers.
alwaysHear = P_IsDisplayPlayer(other->player);
}
if (cv_kartvoices.value)
{
if (victimIsLocal == false)
{
S_StartSound(source, sfx_khitem);
}
}
else
{
S_StartSound(source, sfx_s1c9); // The only lost gameplay functionality with voices disabled
S_StartSound(alwaysHear ? NULL : source, sfx_id);
}
K_RegularVoiceTimers(source->player);
}
if (victim != NULL && victim->player != NULL)
void K_TryHurtSoundExchange(mobj_t *victim, mobj_t *attacker)
{
if (victim == NULL || P_MobjWasRemoved(victim) == true || victim->player == NULL)
{
victim->player->confirmInflictor = source->player - players;
victim->player->confirmInflictorDelay = TICRATE/2;
return;
}
// In a perfect world we could move this here, but there's
// a few niche situations where we want a pain sound from
// the victim, but no confirm sound from the attacker.
// (ex: DMG_STING)
//K_PlayPainSound(victim, attacker);
if (attacker == NULL || P_MobjWasRemoved(attacker) == true || attacker->player == NULL)
{
return;
}
attacker->player->confirmVictim = (victim->player - players);
attacker->player->confirmVictimDelay = TICRATE/2;
if (attacker->player->follower != NULL)
{
const follower_t *fl = &followers[attacker->player->followerskin];
attacker->player->follower->movecount = fl->hitconfirmtime; // movecount is used to play the hitconfirm animation for followers.
}
}
void K_PlayPowerGloatSound(mobj_t *source)
{
if (cv_kartvoices.value)
{
S_StartSound(source, sfx_kgloat);
}
K_RegularVoiceTimers(source->player);
}
static void K_HandleDelayedHitByEm(player_t *player)
{
if (player->confirmInflictorDelay == 0)
if (player->confirmVictimDelay == 0)
{
return;
}
player->confirmInflictorDelay--;
player->confirmVictimDelay--;
if (player->confirmInflictorDelay == 0
&& P_IsDisplayPlayer(player) == true
&& cv_kartvoices.value)
if (player->confirmVictimDelay == 0)
{
player_t *inflictor = NULL;
mobj_t *victim = NULL;
if (player->confirmInflictor >= MAXPLAYERS)
if (player->confirmVictim < MAXPLAYERS && playeringame[player->confirmVictim])
{
return;
player_t *victimPlayer = &players[player->confirmVictim];
if (victimPlayer != NULL && victimPlayer->spectator == false)
{
victim = victimPlayer->mo;
}
}
if (!playeringame[player->confirmInflictor])
{
return;
}
inflictor = &players[player->confirmInflictor];
if (inflictor == NULL || inflictor->spectator)
{
return;
}
if (inflictor->mo != NULL && P_MobjWasRemoved(inflictor->mo) == false)
{
sfxenum_t sfx_id = ((skin_t *)inflictor->mo->skin)->soundsid[S_sfx[sfx_khitem].skinsound];
S_StartSound(NULL, sfx_id);
}
K_PlayHitEmSound(player->mo, victim);
}
}
@ -4281,8 +4297,8 @@ UINT16 K_DriftSparkColor(player_t *player, INT32 charge)
if (charge < 0)
{
// Stage 0: Yellow
color = SKINCOLOR_GOLD;
// Stage 0: Grey
color = SKINCOLOR_SILVER;
}
else if (charge >= dsfour)
{
@ -4299,7 +4315,7 @@ UINT16 K_DriftSparkColor(player_t *player, INT32 charge)
}
else if (charge >= dsthree)
{
// Stage 3: Purple
// Stage 3: Blue
if (charge <= dsthree+(16*3))
{
// transition 1
@ -4308,19 +4324,6 @@ UINT16 K_DriftSparkColor(player_t *player, INT32 charge)
else if (charge <= dsthree+(32*3))
{
// transition 2
color = SKINCOLOR_MOONSET;
}
else
{
color = SKINCOLOR_PURPLE;
}
}
else if (charge >= dstwo)
{
// Stage 2: Blue
if (charge <= dstwo+(32*3))
{
// transition
color = SKINCOLOR_NOVA;
}
else
@ -4328,10 +4331,10 @@ UINT16 K_DriftSparkColor(player_t *player, INT32 charge)
color = SKINCOLOR_SAPPHIRE;
}
}
else if (charge >= dsone)
else if (charge >= dstwo)
{
// Stage 1: Red
if (charge <= dsone+(32*3))
// Stage 2: Red
if (charge <= dstwo+(32*3))
{
// transition
color = SKINCOLOR_TANGERINE;
@ -4341,6 +4344,19 @@ UINT16 K_DriftSparkColor(player_t *player, INT32 charge)
color = SKINCOLOR_KETCHUP;
}
}
else if (charge >= dsone)
{
// Stage 1: Yellow
if (charge <= dsone+(32*3))
{
// transition
color = SKINCOLOR_TAN;
}
else
{
color = SKINCOLOR_GOLD;
}
}
return color;
}
@ -8527,9 +8543,9 @@ INT32 K_GetKartDriftSparkValueForStage(player_t *player, UINT8 stage)
}
/*
Stage 1: red sparks
Stage 2: blue sparks
Stage 3: purple sparks
Stage 1: yellow sparks
Stage 2: red sparks
Stage 3: blue sparks
Stage 4: big large rainbow sparks
Stage 0: air failsafe
*/
@ -8545,26 +8561,22 @@ void K_SpawnDriftBoostExplosion(player_t *player, int stage)
switch (stage)
{
case 1:
overlay->color = SKINCOLOR_KETCHUP;
overlay->fuse = 16;
break;
case 2:
overlay->color = SKINCOLOR_SAPPHIRE;
overlay->fuse = 32;
S_StartSound(player->mo, sfx_kc5b);
break;
case 3:
overlay->color = SKINCOLOR_PURPLE;
overlay->fuse = 48;
S_StartSound(player->mo, sfx_kc5b);
break;
case 4:
overlay->color = SKINCOLOR_SILVER;
overlay->fuse = 120;
S_StartSound(player->mo, sfx_kc5b);
@ -8572,7 +8584,6 @@ void K_SpawnDriftBoostExplosion(player_t *player, int stage)
break;
case 0:
overlay->color = SKINCOLOR_SILVER;
overlay->fuse = 16;
break;
}
@ -8607,7 +8618,7 @@ static void K_KartDrift(player_t *player, boolean onground)
if (player->driftcharge < 0)
{
// Stage 0: Yellow sparks
// Stage 0: Grey sparks
if (!onground)
P_Thrust(player->mo, pushdir, player->speed / 8);
@ -8616,7 +8627,7 @@ static void K_KartDrift(player_t *player, boolean onground)
}
else if (player->driftcharge >= dsone && player->driftcharge < dstwo)
{
// Stage 1: Red sparks
// Stage 1: Yellow sparks
if (!onground)
P_Thrust(player->mo, pushdir, player->speed / 4);
@ -8627,7 +8638,7 @@ static void K_KartDrift(player_t *player, boolean onground)
}
else if (player->driftcharge < dsthree)
{
// Stage 2: Blue sparks
// Stage 2: Red sparks
if (!onground)
P_Thrust(player->mo, pushdir, player->speed / 3);
@ -8638,7 +8649,7 @@ static void K_KartDrift(player_t *player, boolean onground)
}
else if (player->driftcharge < dsfour)
{
// Stage 3: Purple sparks
// Stage 3: Blue sparks
if (!onground)
P_Thrust(player->mo, pushdir, ( 5 * player->speed ) / 12);
@ -9025,13 +9036,17 @@ static INT32 K_FlameShieldMax(player_t *player)
boolean K_PlayerEBrake(player_t *player)
{
if (player->fastfall != 0)
{
return true;
}
return (K_GetKartButtons(player) & BT_EBRAKEMASK) == BT_EBRAKEMASK
&& P_IsObjectOnGround(player->mo) == true
&& player->drift == 0
&& player->spinouttimer == 0
&& player->justbumped == 0
&& player->spindashboost == 0
&& player->nocontrol == 0;
&& player->drift == 0
&& P_PlayerInPain(player) == false
&& player->justbumped == 0
&& player->spindashboost == 0
&& player->nocontrol == 0;
}
SINT8 K_Sliptiding(player_t *player)
@ -9053,9 +9068,8 @@ void K_KartEbrakeVisuals(player_t *p)
mobj_t *spdl;
fixed_t sx, sy;
if (K_PlayerEBrake(p))
if (K_PlayerEBrake(p) == true)
{
if (p->ebrakefor % 20 == 0)
{
wave = P_SpawnMobj(p->mo->x, p->mo->y, p->mo->z, MT_SOFTLANDING);
@ -9092,7 +9106,6 @@ void K_KartEbrakeVisuals(player_t *p)
K_FlipFromObject(p->mo->hprev, p->mo);
}
if (!p->spindash)
{
// Spawn downwards fastline
@ -9233,6 +9246,7 @@ static void K_KartSpindashWind(mobj_t *parent)
static void K_KartSpindash(player_t *player)
{
const boolean onGround = P_IsObjectOnGround(player->mo);
const INT16 MAXCHARGETIME = K_GetSpindashChargeTime(player);
UINT16 buttons = K_GetKartButtons(player);
boolean spawnWind = (leveltime % 2 == 0);
@ -9296,6 +9310,44 @@ static void K_KartSpindash(player_t *player)
return;
}
// Handle fast falling behaviors first.
if (onGround == false)
{
// Update fastfall.
player->fastfall = player->mo->momz;
player->spindash = 0;
return;
}
else if (player->fastfall != 0)
{
// Handle fastfall bounce.
const fixed_t maxBounce = player->mo->scale * 10;
const fixed_t minBounce = player->mo->scale;
fixed_t bounce = 2 * abs(player->fastfall) / 3;
if (bounce > maxBounce)
{
bounce = maxBounce;
}
else
{
// Lose speed on bad bounce.
player->mo->momx /= 2;
player->mo->momy /= 2;
if (bounce < minBounce)
{
bounce = minBounce;
}
}
S_StartSound(player->mo, sfx_ffbonc);
player->mo->momz = bounce * P_MobjFlip(player->mo);
player->fastfall = 0;
return;
}
if (player->speed == 0 && player->steering != 0 && leveltime % 8 == 0)
{
// Rubber burn turn sfx
@ -10477,7 +10529,7 @@ void K_CheckSpectateStatus(void)
if (!players[i].spectator)
{
numingame++;
if (cv_ingamecap.value && numingame >= cv_ingamecap.value) // DON'T allow if you've hit the in-game player cap
if (cv_maxplayers.value && numingame >= cv_maxplayers.value) // DON'T allow if you've hit the in-game player cap
return;
if (gamestate != GS_LEVEL) // Allow if you're not in a level
continue;
@ -10502,7 +10554,7 @@ void K_CheckSpectateStatus(void)
return;
// Organize by spectate wait timer
if (cv_ingamecap.value)
if (cv_maxplayers.value)
{
UINT8 oldrespawnlist[MAXPLAYERS];
memcpy(oldrespawnlist, respawnlist, numjoiners);
@ -10529,7 +10581,7 @@ void K_CheckSpectateStatus(void)
// Finally, we can de-spectate everyone!
for (i = 0; i < numjoiners; i++)
{
if (cv_ingamecap.value && numingame+i >= cv_ingamecap.value) // Hit the in-game player cap while adding people?
if (cv_maxplayers.value && numingame+i >= cv_maxplayers.value) // Hit the in-game player cap while adding people?
break;
//CONS_Printf("player %s is joining on tic %d\n", player_names[respawnlist[i]], leveltime);
P_SpectatorJoinGame(&players[respawnlist[i]]);

View file

@ -154,8 +154,9 @@ void K_HandleDirectionalInfluence(player_t *player);
void K_PlayAttackTaunt(mobj_t *source);
void K_PlayBoostTaunt(mobj_t *source);
void K_PlayOvertakeSound(mobj_t *source);
void K_PlayPainSound(mobj_t *source);
void K_PlayHitEmSound(mobj_t *source, mobj_t *victim);
void K_PlayPainSound(mobj_t *source, mobj_t *other);
void K_PlayHitEmSound(mobj_t *source, mobj_t *other);
void K_TryHurtSoundExchange(mobj_t *victim, mobj_t *attacker);
void K_PlayPowerGloatSound(mobj_t *source);
fixed_t K_ItemScaleForPlayer(player_t *player);

1113
src/k_menu.h Normal file

File diff suppressed because it is too large Load diff

1747
src/k_menudef.c Normal file

File diff suppressed because it is too large Load diff

4377
src/k_menudraw.c Normal file

File diff suppressed because it is too large Load diff

6594
src/k_menufunc.c Normal file

File diff suppressed because it is too large Load diff

539
src/k_profiles.c Normal file
View file

@ -0,0 +1,539 @@
// SONIC ROBO BLAST 2
//-----------------------------------------------------------------------------
// Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2020 by Sonic Team Junior.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
// See the 'LICENSE' file for more details.
//-----------------------------------------------------------------------------
/// \file k_profiles.c
/// \brief implements methods for profiles etc.
#include "d_main.h" // pandf
#include "byteptr.h" // READ/WRITE macros
#include "p_saveg.h" // save_p
#include "m_misc.h" //FIL_WriteFile()
#include "k_profiles.h"
#include "z_zone.h"
#include "r_skins.h"
// List of all the profiles.
static profile_t *profilesList[MAXPROFILES+1]; // +1 because we're gonna add a default "GUEST' profile.
static UINT8 numprofiles = 0; // # of loaded profiles
INT32 PR_GetNumProfiles(void)
{
return numprofiles;
}
profile_t* PR_MakeProfile(
const char *prname,
const char *pname,
const char *sname, const UINT16 col,
const char *fname, const UINT16 fcol,
INT32 controlarray[num_gamecontrols][MAXINPUTMAPPING],
boolean guest)
{
profile_t *new = Z_Malloc(sizeof(profile_t), PU_STATIC, NULL);
UINT8 i;
new->version = PROFILEVER;
strcpy(new->profilename, prname);
new->profilename[sizeof new->profilename - 1] = '\0';
strcpy(new->skinname, sname);
strcpy(new->playername, pname);
new->color = col;
strcpy(new->follower, fname);
new->followercolor = fcol;
new->kickstartaccel = false;
// Copy from gamecontrol directly as we'll be setting controls up directly in the profile.
memcpy(new->controls, controlarray, sizeof(new->controls));
// Init both power levels
for (i = 0; i < PWRLV_NUMTYPES; i++)
{
new->powerlevels[i] = (guest ? 0 : PWRLVRECORD_START);
}
return new;
}
profile_t* PR_MakeProfileFromPlayer(const char *prname, const char *pname, const char *sname, const UINT16 col, const char *fname, UINT16 fcol, UINT8 pnum)
{
// Generate profile using the player's gamecontrol, as we set them directly when making profiles from menus.
profile_t *new = PR_MakeProfile(prname, pname, sname, col, fname, fcol, gamecontrol[pnum], false);
// Player bound cvars:
new->kickstartaccel = cv_kickstartaccel[pnum].value;
return new;
}
boolean PR_AddProfile(profile_t *p)
{
if (numprofiles < MAXPROFILES+1)
{
profilesList[numprofiles] = p;
numprofiles++;
CONS_Printf("Profile '%s' added\n", p->profilename);
return true;
}
else
return false;
}
profile_t* PR_GetProfile(INT32 num)
{
if (num < numprofiles)
return profilesList[num];
else
return NULL;
}
boolean PR_DeleteProfile(INT32 num)
{
UINT8 i;
profile_t* sacrifice;
if (num <= 0 || num > numprofiles)
{
return false;
}
sacrifice = profilesList[num];
// If we're deleting inbetween profiles, move everything.
if (num < numprofiles)
{
for (i = num; i < numprofiles-1; i++)
{
profilesList[i] = profilesList[i+1];
}
// Make sure to move cv_lastprofile (and title/current profile) values as well!
for (i = 0; i < MAXSPLITSCREENPLAYERS+2; i++)
{
consvar_t *cv;
if (i < MAXSPLITSCREENPLAYERS)
cv = &cv_lastprofile[i];
else if (i == MAXSPLITSCREENPLAYERS)
cv = &cv_ttlprofilen;
else
cv = &cv_currprofile;
if (cv->value < num)
{
// Not affected.
continue;
}
if (cv->value > num)
{
// Shift our lastprofile number down to match the new order.
CV_StealthSetValue(cv, cv->value-1);
continue;
}
if (cv != &cv_currprofile)
{
// There's no hope for it. If we were on the deleted profile, default back to guest.
CV_StealthSetValue(cv, PROFILE_GUEST);
continue;
}
// Oh boy, now we're really in for it.
CV_StealthSetValue(cv, -1);
}
}
// In any case, delete the last profile as well.
profilesList[numprofiles] = NULL;
numprofiles--;
PR_SaveProfiles();
// Finally, clear up our memory!
Z_Free(sacrifice);
return true;
}
void PR_InitNewProfile(void)
{
char pname[PROFILENAMELEN+1] = "PRF";
profile_t *dprofile;
UINT8 usenum = numprofiles-1;
UINT8 i;
boolean nameok = false;
pname[4] = '\0';
// When deleting profile, it's possible to do some pretty wacko stuff that would lead a new fresh profile to share the same name as another profile we have never changed the name of.
// This could become an infinite loop if MAXPROFILES >= 26.
while (!nameok)
{
pname[3] = 'A'+usenum;
for (i = 0; i < numprofiles; i++)
{
profile_t *pr = PR_GetProfile(i);
if (!strcmp(pr->profilename, pname))
{
usenum++;
if (pname[3] == 'Z')
usenum = 0;
break;
}
// if we got here, then it means the name is okay!
if (i == numprofiles-1)
nameok = true;
}
}
dprofile = PR_MakeProfile(
pname,
PROFILEDEFAULTPNAME,
PROFILEDEFAULTSKIN, PROFILEDEFAULTCOLOR,
PROFILEDEFAULTFOLLOWER, PROFILEDEFAULTFOLLOWERCOLOR,
gamecontroldefault,
false
);
PR_AddProfile(dprofile);
}
static UINT8 *savebuffer;
void PR_SaveProfiles(void)
{
size_t length = 0;
const size_t headerlen = strlen(PROFILEHEADER);
UINT8 i, j, k;
save_p = savebuffer = (UINT8 *)malloc(sizeof(UINT32) + (numprofiles * sizeof(profile_t)));
if (!save_p)
{
I_Error("No more free memory for saving profiles\n");
return;
}
// Add header.
WRITESTRINGN(save_p, PROFILEHEADER, headerlen);
WRITEUINT8(save_p, PROFILEVER);
WRITEUINT8(save_p, numprofiles);
for (i = 1; i < numprofiles; i++)
{
// Names.
WRITESTRINGN(save_p, profilesList[i]->profilename, PROFILENAMELEN);
WRITESTRINGN(save_p, profilesList[i]->playername, MAXPLAYERNAME);
// Character and colour.
WRITESTRINGN(save_p, profilesList[i]->skinname, SKINNAMESIZE);
WRITEUINT16(save_p, profilesList[i]->color);
// Follower and colour.
WRITESTRINGN(save_p, profilesList[i]->follower, SKINNAMESIZE);
WRITEUINT16(save_p, profilesList[i]->followercolor);
// PWR.
for (j = 0; j < PWRLV_NUMTYPES; j++)
{
WRITEUINT16(save_p, profilesList[i]->powerlevels[j]);
}
// Consvars.
WRITEUINT8(save_p, profilesList[i]->kickstartaccel);
// Controls.
for (j = 0; j < num_gamecontrols; j++)
{
for (k = 0; k < MAXINPUTMAPPING; k++)
{
WRITEINT32(save_p, profilesList[i]->controls[j][k]);
}
}
}
length = save_p - savebuffer;
if (!FIL_WriteFile(va(pandf, srb2home, PROFILESFILE), savebuffer, length))
{
free(savebuffer);
I_Error("Couldn't save profiles. Are you out of Disk space / playing in a protected folder?");
}
free(savebuffer);
save_p = savebuffer = NULL;
}
void PR_LoadProfiles(void)
{
size_t length = 0;
const size_t headerlen = strlen(PROFILEHEADER);
UINT8 i, j, k, version;
profile_t *dprofile = PR_MakeProfile(
PROFILEDEFAULTNAME,
PROFILEDEFAULTPNAME,
PROFILEDEFAULTSKIN, PROFILEDEFAULTCOLOR,
PROFILEDEFAULTFOLLOWER, PROFILEDEFAULTFOLLOWERCOLOR,
gamecontroldefault,
true
);
length = FIL_ReadFile(va(pandf, srb2home, PROFILESFILE), &savebuffer);
if (!length)
{
// No profiles. Add the default one.
PR_AddProfile(dprofile);
return;
}
save_p = savebuffer;
if (strncmp(PROFILEHEADER, (const char *)savebuffer, headerlen))
{
const char *gdfolder = "the Ring Racers folder";
if (strcmp(srb2home,"."))
gdfolder = srb2home;
Z_Free(savebuffer);
save_p = NULL;
I_Error("Not a valid Profile file.\nDelete %s (maybe in %s) and try again.", PROFILESFILE, gdfolder);
}
save_p += headerlen;
version = READUINT8(save_p);
if (version > PROFILEVER)
{
Z_Free(savebuffer);
save_p = NULL;
I_Error("Existing %s is from the future! (expected %d, got %d)", PROFILESFILE, PROFILEVER, version);
}
numprofiles = READUINT8(save_p);
if (numprofiles > MAXPROFILES)
numprofiles = MAXPROFILES;
for (i = 1; i < numprofiles; i++)
{
profilesList[i] = Z_Malloc(sizeof(profile_t), PU_STATIC, NULL);
// Version.
profilesList[i]->version = version;
// Names.
READSTRINGN(save_p, profilesList[i]->profilename, PROFILENAMELEN);
READSTRINGN(save_p, profilesList[i]->playername, MAXPLAYERNAME);
// Character and colour.
READSTRINGN(save_p, profilesList[i]->skinname, SKINNAMESIZE);
profilesList[i]->color = READUINT16(save_p);
if (profilesList[i]->color == SKINCOLOR_NONE)
{
; // Valid, even outside the bounds
}
else if (profilesList[i]->color >= numskincolors
|| skincolors[profilesList[i]->color].accessible == false)
{
profilesList[i]->color = PROFILEDEFAULTCOLOR;
}
// Follower and colour.
READSTRINGN(save_p, profilesList[i]->follower, SKINNAMESIZE);
profilesList[i]->followercolor = READUINT16(save_p);
if (profilesList[i]->followercolor == FOLLOWERCOLOR_MATCH
|| profilesList[i]->followercolor == FOLLOWERCOLOR_OPPOSITE)
{
; // Valid, even outside the bounds
}
else if (profilesList[i]->followercolor >= numskincolors
|| profilesList[i]->followercolor == SKINCOLOR_NONE
|| skincolors[profilesList[i]->followercolor].accessible == false)
{
profilesList[i]->followercolor = PROFILEDEFAULTFOLLOWERCOLOR;
}
// PWR.
for (j = 0; j < PWRLV_NUMTYPES; j++)
{
profilesList[i]->powerlevels[j] = READUINT16(save_p);
if (profilesList[i]->powerlevels[j] < PWRLVRECORD_MIN
|| profilesList[i]->powerlevels[j] > PWRLVRECORD_MAX)
{
// invalid, reset
profilesList[i]->powerlevels[j] = PWRLVRECORD_START;
}
}
// Consvars.
profilesList[i]->kickstartaccel = (boolean)READUINT8(save_p);
// Controls.
for (j = 0; j < num_gamecontrols; j++)
{
for (k = 0; k < MAXINPUTMAPPING; k++)
{
profilesList[i]->controls[j][k] = READINT32(save_p);
}
}
}
// Add the the default profile directly to avoid letting anyone tamper with it.
profilesList[PROFILE_GUEST] = dprofile;
}
skincolornum_t PR_GetProfileColor(profile_t *p)
{
if (p->color == SKINCOLOR_NONE)
{
// Get skin's prefcolor.
INT32 foundskin = R_SkinAvailable(p->skinname);
if (foundskin == -1)
{
// Return random default value
return SKINCOLOR_RED;
}
return skins[foundskin].prefcolor;
}
// Get exact color.
return p->color;
}
static void PR_ApplyProfile_Appearance(profile_t *p, UINT8 playernum)
{
CV_StealthSet(&cv_skin[playernum], p->skinname);
CV_StealthSetValue(&cv_playercolor[playernum], PR_GetProfileColor(p));
CV_StealthSet(&cv_playername[playernum], p->playername);
// Followers
CV_StealthSet(&cv_follower[playernum], p->follower);
CV_StealthSetValue(&cv_followercolor[playernum], p->followercolor);
}
static void PR_ApplyProfile_Settings(profile_t *p, UINT8 playernum)
{
// toggles
CV_StealthSetValue(&cv_kickstartaccel[playernum], p->kickstartaccel);
// set controls...
memcpy(&gamecontrol[playernum], p->controls, sizeof(gamecontroldefault));
}
static void PR_ApplyProfile_Memory(UINT8 profilenum, UINT8 playernum)
{
// set memory cvar
CV_StealthSetValue(&cv_lastprofile[playernum], profilenum);
// If we're doing this on P1, also change current profile.
if (playernum == 0)
{
CV_StealthSetValue(&cv_currprofile, profilenum);
}
}
void PR_ApplyProfile(UINT8 profilenum, UINT8 playernum)
{
profile_t *p = PR_GetProfile(profilenum);
// this CAN happen!!
if (p == NULL)
{
CONS_Printf("Profile '%d' could not be loaded as it does not exist. Guest Profile will be loaded instead.\n", profilenum);
profilenum = 0; // make sure to set this so that the cvar is set properly.
p = PR_GetProfile(profilenum);
}
PR_ApplyProfile_Appearance(p, playernum);
PR_ApplyProfile_Settings(p, playernum);
PR_ApplyProfile_Memory(profilenum, playernum);
}
void PR_ApplyProfileLight(UINT8 profilenum, UINT8 playernum)
{
profile_t *p = PR_GetProfile(profilenum);
// this CAN happen!!
if (p == NULL)
{
// no need to be as loud...
profilenum = 0; // make sure to set this so that the cvar is set properly.
p = PR_GetProfile(profilenum);
}
PR_ApplyProfile_Appearance(p, playernum);
}
void PR_ApplyProfilePretend(UINT8 profilenum, UINT8 playernum)
{
profile_t *p = PR_GetProfile(profilenum);
// this CAN happen!!
if (p == NULL)
{
CONS_Printf("Profile '%d' could not be loaded as it does not exist. Guest Profile will be loaded instead.\n", profilenum);
profilenum = 0; // make sure to set this so that the cvar is set properly.
p = PR_GetProfile(profilenum);
}
PR_ApplyProfile_Memory(profilenum, playernum);
}
UINT8 PR_GetProfileNum(profile_t *p)
{
UINT8 i;
for (i = 0; i < MAXPROFILES+1; i++)
{
profile_t *comp = PR_GetProfile(i);
if (comp == p)
return i;
}
return 0;
}
SINT8 PR_ProfileUsedBy(profile_t *p)
{
UINT8 i;
UINT8 prn = PR_GetProfileNum(p);
for (i = 0; i < MAXSPLITSCREENPLAYERS; i++)
{
if (prn == cv_lastprofile[i].value)
return i;
}
return -1;
}
profile_t *PR_GetPlayerProfile(player_t *player)
{
const UINT8 playerNum = (player - players);
UINT8 i;
if (demo.playback)
{
return NULL;
}
for (i = 0; i <= splitscreen; i++)
{
if (playerNum == g_localplayers[i])
{
return PR_GetProfile(cv_lastprofile[i].value);
}
}
return NULL;
}

155
src/k_profiles.h Normal file
View file

@ -0,0 +1,155 @@
// SONIC ROBO BLAST 2
//-----------------------------------------------------------------------------
// Copyright (C) 1993-1996 by id Software, Inc.
// Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 2011-2016 by Matthew "Inuyasha" Walsh.
// Copyright (C) 1999-2018 by Sonic Team Junior.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
// See the 'LICENSE' file for more details.
//-----------------------------------------------------------------------------
/// \file k_profiles.h
/// \brief Control profiles definition
#ifndef __PROFILES_H__
#define __PROFILES_H__
#include "doomdef.h" // MAXPLAYERNAME
//#include "r_skins.h" // SKINNAMESIZE // This cuases stupid issues.
#include "g_input.h" // Input related stuff
#include "string.h" // strcpy etc
#include "g_game.h" // game CVs
#include "k_follower.h" // followers
// We have to redefine this because somehow including r_skins.h causes a redefinition of node_t since that's used for both net nodes and BSP nodes too......
// And honestly I don't wanna refactor that.
#define SKINNAMESIZE 16
#define PROFILENAMELEN 6
#define PROFILEVER 1
#define MAXPROFILES 16
#define PROFILESFILE "ringprofiles.prf"
#define PROFILE_GUEST 0
#define PROFILEDEFAULTNAME "GUEST"
#define PROFILEDEFAULTPNAME "Guest"
#define PROFILEDEFAULTSKIN "eggman"
#define PROFILEDEFAULTCOLOR SKINCOLOR_NONE
#define PROFILEDEFAULTFOLLOWER "none"
#define PROFILEDEFAULTFOLLOWERCOLOR FOLLOWERCOLOR_MATCH
#define PROFILEHEADER "Doctor Robotnik's Ring Racers Profiles"
// Man I wish I had more than 16 friends!!
// profile_t definition (WIP)
// If you edit, see PR_SaveProfiles and PR_LoadProfiles
typedef struct profile_s
{
// Versionning
UINT8 version; // Version of the profile, this can be useful for backwards compatibility reading if we ever update the profile structure/format after release.
// A version of 0 can easily be checked to identify an unitialized profile.
// Profile header
char profilename[PROFILENAMELEN+1]; // Profile name (not to be confused with player name)
// Player data
char playername[MAXPLAYERNAME+1]; // Player name
char skinname[SKINNAMESIZE+1]; // Default Skin
UINT16 color; // Default player coloUr. ...But for consistency we'll name it color.
char follower[SKINNAMESIZE+1]; // Follower
UINT16 followercolor; // Follower color
UINT16 powerlevels[PWRLV_NUMTYPES]; // PWRLV for each gametype.
// Player-specific consvars.
// @TODO: List all of those
boolean kickstartaccel; // cv_kickstartaccel
// Finally, control data itself
INT32 controls[num_gamecontrols][MAXINPUTMAPPING]; // Lists of all the controls, defined the same way as default inputs in g_input.c
} profile_t;
// Functions
// returns how many profiles there are
INT32 PR_GetNumProfiles(void);
// PR_MakeProfile
// Makes a profile from the supplied profile name, player name, colour, follower, followercolour and controls.
// The consvar values are left untouched.
profile_t* PR_MakeProfile(
const char *prname,
const char *pname,
const char *sname, const UINT16 col,
const char *fname, const UINT16 fcol,
INT32 controlarray[num_gamecontrols][MAXINPUTMAPPING],
boolean guest
);
// PR_MakeProfileFromPlayer
// Makes a profile_t from the supplied profile name, player name, colour, follower and followercolour.
// The last argument is a player number to read cvars from; as for convenience, cvars will be set directly when making a profile (since loading another one will overwrite them, this will be inconsequential)
profile_t* PR_MakeProfileFromPlayer(const char *prname, const char *pname, const char *sname, const UINT16 col, const char *fname, UINT16 fcol, UINT8 pnum);
// PR_AddProfile(profile_t p)
// Adds a profile to profilesList and increments numprofiles.
// Returns true if succesful, false if not.
boolean PR_AddProfile(profile_t *p);
// PR_GetProfile(INT32 num)
// Returns a pointer to the profile you're asking for or NULL if the profile is uninitialized.
profile_t* PR_GetProfile(INT32 num);
// PR_DeleteProfile(INT32 n)
// Deletes the specified profile. n cannot be 0. Returns false if the profile couldn't be deleted, true otherwise.
// This will also move every profile back accordingly to ensure the table has no empty profiles inbetween two valid profiles.
boolean PR_DeleteProfile(INT32 n);
// PR_InitNewProfile(void)
// Initializes the first new profile
void PR_InitNewProfile(void);
// PR_SaveProfiles(void)
// Saves all the profiles in profiles.cfg
// This does not save profilesList[0] since that's always going to be the default profile.
void PR_SaveProfiles(void);
// PR_LoadProfiles(void)
// Loads all the profiles saved in profiles.cfg.
// This also loads
void PR_LoadProfiles(void);
// PR_GetProfileColor(profile_t *p)
// Returns the profile's color, or the skin's prefcolor if set to none.
skincolornum_t PR_GetProfileColor(profile_t *p);
// PR_ApplyProfile(UINT8 profilenum, UINT8 playernum)
// Applies the given profile's settings to the given player.
void PR_ApplyProfile(UINT8 profilenum, UINT8 playernum);
// PR_ApplyProfileLight(UINT8 profilenum, UINT8 playernum)
// Similar to PR_ApplyProfile but only applies skin and follower values.
// Controls, kickstartaccel and "current profile" data is *not* modified.
void PR_ApplyProfileLight(UINT8 profilenum, UINT8 playernum);
// PR_ApplyProfilePretend(UINT8 profilenum, UINT8 playernum)
// ONLY modifies "current profile" data.
// Exists because any other option inteferes with rapid testing.
void PR_ApplyProfilePretend(UINT8 profilenum, UINT8 playernum);
// PR_GetProfileNum(profile_t *p)
// Gets the profile's index # in profilesList
UINT8 PR_GetProfileNum(profile_t *p);
// PR_ProfileUsedBy(profile_t *p)
// Returns the player # this profile is used by (if any)
// If the profile belongs to no player, then this returns -1
SINT8 PR_ProfileUsedBy(profile_t *p);
profile_t *PR_GetPlayerProfile(player_t *player);
#endif

View file

@ -17,10 +17,7 @@
#include "p_tick.h" // leveltime
#include "k_grandprix.h"
#include "k_boss.h"
// Online rankings for the main gametypes.
// This array is saved to the gamedata.
UINT16 vspowerlevel[PWRLV_NUMTYPES];
#include "k_profiles.h"
// Client-sided calculations done for Power Levels.
// This is done so that clients will never be able to hack someone else's score over the server.
@ -370,6 +367,7 @@ INT16 K_FinalPowerIncrement(player_t *player, INT16 yourPower, INT16 baseInc)
// Get at least one point.
inc = 1;
}
#if 0
else
{
// You trade points in 1v1s,
@ -388,6 +386,7 @@ INT16 K_FinalPowerIncrement(player_t *player, INT16 yourPower, INT16 baseInc)
}
}
}
#endif
}
if (yourPower + inc > PWRLVRECORD_MAX)
@ -416,14 +415,16 @@ void K_CashInPowerLevels(void)
{
if (playeringame[i] == true && powerType != PWRLV_DISABLED)
{
profile_t *pr = PR_GetPlayerProfile(&players[i]);
INT16 inc = K_FinalPowerIncrement(&players[i], clientpowerlevels[i][powerType], clientPowerAdd[i]);
clientpowerlevels[i][powerType] += inc;
//CONS_Printf("%s: %d -> %d (%d)\n", player_names[i], clientpowerlevels[i][powerType] - inc, clientpowerlevels[i][powerType], inc);
if (!demo.playback && i == consoleplayer && inc != 0)
if (pr != NULL && inc != 0)
{
vspowerlevel[powerType] = clientpowerlevels[i][powerType];
pr->powerlevels[powerType] = clientpowerlevels[i][powerType];
if (M_UpdateUnlockablesAndExtraEmblems())
{
@ -567,6 +568,7 @@ void K_SetPowerLevelScrambles(SINT8 powertype)
void K_PlayerForfeit(UINT8 playerNum, boolean pointLoss)
{
profile_t *pr;
UINT8 p = 0;
SINT8 powerType = PWRLV_DISABLED;
@ -631,17 +633,22 @@ void K_PlayerForfeit(UINT8 playerNum, boolean pointLoss)
K_UpdatePowerLevelsOnFailure(&players[playerNum]);
inc = K_FinalPowerIncrement(&players[playerNum], yourPower, clientPowerAdd[playerNum]);
if (inc >= 0)
if (inc == 0)
{
// Don't record no change or increases.
// No change
return;
}
// pointLoss isn't set for stuff like sync-outs,
// which shouldn't be so harsh on the victim!
if (!demo.playback && pointLoss == true && playerNum == consoleplayer)
if (inc < 0 && pointLoss == false)
{
vspowerlevel[powerType] = yourPower + inc;
// Don't record point losses for sync-out / crashes.
return;
}
pr = PR_GetPlayerProfile(&players[playerNum]);
if (pr != NULL)
{
pr->powerlevels[powerType] = yourPower + inc;
if (M_UpdateUnlockablesAndExtraEmblems())
{

View file

@ -31,7 +31,6 @@ typedef enum
extern SINT8 speedscramble;
extern SINT8 encorescramble;
extern UINT16 vspowerlevel[PWRLV_NUMTYPES];
extern UINT16 clientpowerlevels[MAXPLAYERS][PWRLV_NUMTYPES];
extern INT16 clientPowerAdd[MAXPLAYERS];
extern UINT8 spectateGriefed;

View file

@ -22,7 +22,6 @@
#include "m_random.h"
#include "s_sound.h"
#include "g_game.h"
#include "m_menu.h"
#include "y_inter.h"
#include "hu_stuff.h" // HU_AddChatText
#include "console.h"
@ -33,7 +32,7 @@
#include "k_color.h"
#include "k_hud.h"
#include "d_netcmd.h" // IsPlayerAdmin
#include "m_menu.h" // Player Setup menu color stuff
#include "k_menu.h" // Player Setup menu color stuff
#include "m_misc.h" // M_MapNumber
#include "p_spec.h" // P_StartQuake
#include "i_system.h" // I_GetPreciseTime, I_GetPrecisePrecision
@ -356,14 +355,26 @@ static int lib_pMoveColorAfter(lua_State *L)
static int lib_pGetColorBefore(lua_State *L)
{
UINT16 color = (UINT16)luaL_checkinteger(L, 1);
lua_pushinteger(L, M_GetColorBefore(color));
UINT16 amount = (UINT16)luaL_checkinteger(L, 2);
boolean follower = lua_optboolean(L, 3);
lua_pushinteger(L, M_GetColorBefore(color, amount, follower));
return 1;
}
static int lib_pGetColorAfter(lua_State *L)
{
UINT16 color = (UINT16)luaL_checkinteger(L, 1);
lua_pushinteger(L, M_GetColorAfter(color));
UINT16 amount = (UINT16)luaL_checkinteger(L, 2);
boolean follower = lua_optboolean(L, 3);
lua_pushinteger(L, M_GetColorAfter(color, amount, follower));
return 1;
}
static int lib_pGetEffectiveFollowerColor(lua_State *L)
{
UINT16 followercolor = (UINT16)luaL_checkinteger(L, 1);
UINT16 playercolor = (UINT16)luaL_checkinteger(L, 2);
lua_pushinteger(L, K_GetEffectiveFollowerColor(followercolor, playercolor));
return 1;
}
@ -3339,23 +3350,37 @@ static int lib_kOvertakeSound(lua_State *L)
static int lib_kPainSound(lua_State *L)
{
mobj_t *mobj = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
mobj_t *other = NULL;
NOHUD
if (!mobj->player)
return luaL_error(L, "K_PlayPainSound: mobj_t isn't a player object."); //Nothing bad would happen if we let it run the func, but telling why it ain't doing anything is helpful.
K_PlayPainSound(mobj);
if (!lua_isnone(L, 2) && lua_isuserdata(L, 2))
other = *((mobj_t **)luaL_checkudata(L, 2, META_MOBJ));
K_PlayPainSound(mobj, other);
return 0;
}
static int lib_kHitEmSound(lua_State *L)
{
mobj_t *mobj = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
mobj_t *victim = NULL;
mobj_t *other = NULL;
NOHUD
if (!mobj->player)
return luaL_error(L, "K_PlayHitEmSound: mobj_t isn't a player object."); //Nothing bad would happen if we let it run the func, but telling why it ain't doing anything is helpful.
if (!lua_isnone(L, 2) && lua_isuserdata(L, 2))
victim = *((mobj_t **)luaL_checkudata(L, 2, META_MOBJ));
K_PlayHitEmSound(mobj, victim);
other = *((mobj_t **)luaL_checkudata(L, 2, META_MOBJ));
K_PlayHitEmSound(mobj, other);
return 0;
}
static int lib_kTryHurtSoundExchange(lua_State *L)
{
mobj_t *victim = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
mobj_t *attacker = *((mobj_t **)luaL_checkudata(L, 2, META_MOBJ));
NOHUD
if (!victim->player)
return luaL_error(L, "K_TryHurtSoundExchange: mobj_t isn't a player object."); //Nothing bad would happen if we let it run the func, but telling why it ain't doing anything is helpful.
K_TryHurtSoundExchange(victim, attacker);
return 0;
}
@ -3896,6 +3921,7 @@ static luaL_Reg lib[] = {
{"P_ReturnThrustX",lib_pReturnThrustX},
{"P_ReturnThrustY",lib_pReturnThrustY},
{"P_NukeEnemies",lib_pNukeEnemies},
{"K_GetEffectiveFollowerColor",lib_pGetEffectiveFollowerColor},
// p_map
{"P_CheckPosition",lib_pCheckPosition},
@ -4037,6 +4063,7 @@ static luaL_Reg lib[] = {
{"K_PlayLossSound", lib_kLossSound},
{"K_PlayPainSound", lib_kPainSound},
{"K_PlayHitEmSound", lib_kHitEmSound},
{"K_TryHurtSoundExchange", lib_kTryHurtSoundExchange},
{"K_IsPlayerLosing",lib_kIsPlayerLosing},
{"K_IsPlayerWanted",lib_kIsPlayerWanted},
{"K_KartBouncing",lib_kKartBouncing},

View file

@ -274,6 +274,8 @@ static int player_get(lua_State *L)
lua_pushinteger(L, plr->spindashspeed);
else if (fastcmp(field,"spindashboost"))
lua_pushinteger(L, plr->spindashboost);
else if (fastcmp(field,"fastfall"))
lua_pushfixed(L, plr->fastfall);
else if (fastcmp(field,"numboosts"))
lua_pushinteger(L, plr->numboosts);
else if (fastcmp(field,"boostpower"))
@ -360,10 +362,10 @@ static int player_get(lua_State *L)
lua_pushinteger(L, plr->lastjawztarget);
else if (fastcmp(field,"jawztargetdelay"))
lua_pushinteger(L, plr->jawztargetdelay);
else if (fastcmp(field,"confirmInflictor"))
lua_pushinteger(L, plr->confirmInflictor);
else if (fastcmp(field,"confirmInflictorDelay"))
lua_pushinteger(L, plr->confirmInflictorDelay);
else if (fastcmp(field,"confirmVictim"))
lua_pushinteger(L, plr->confirmVictim);
else if (fastcmp(field,"confirmVictimDelay"))
lua_pushinteger(L, plr->confirmVictimDelay);
else if (fastcmp(field,"glanceDir"))
lua_pushinteger(L, plr->glanceDir);
else if (fastcmp(field,"trickpanel"))
@ -632,6 +634,8 @@ static int player_set(lua_State *L)
plr->spindashspeed = luaL_checkinteger(L, 3);
else if (fastcmp(field,"spindashboost"))
plr->spindashboost = luaL_checkinteger(L, 3);
else if (fastcmp(field,"fastfall"))
plr->fastfall = luaL_checkfixed(L, 3);
else if (fastcmp(field,"numboosts"))
plr->numboosts = luaL_checkinteger(L, 3);
else if (fastcmp(field,"boostpower"))
@ -718,10 +722,10 @@ static int player_set(lua_State *L)
plr->lastjawztarget = luaL_checkinteger(L, 3);
else if (fastcmp(field,"jawztargetdelay"))
plr->jawztargetdelay = luaL_checkinteger(L, 3);
else if (fastcmp(field,"confirmInflictor"))
plr->confirmInflictor = luaL_checkinteger(L, 3);
else if (fastcmp(field,"confirmInflictorDelay"))
plr->confirmInflictorDelay = luaL_checkinteger(L, 3);
else if (fastcmp(field,"confirmVictim"))
plr->confirmVictim = luaL_checkinteger(L, 3);
else if (fastcmp(field,"confirmVictimDelay"))
plr->confirmVictimDelay = luaL_checkinteger(L, 3);
else if (fastcmp(field,"glanceDir"))
plr->glanceDir = luaL_checkinteger(L, 3);
else if (fastcmp(field,"trickpanel"))

View file

@ -22,7 +22,7 @@
#include "d_net.h"
#include "m_cheat.h"
#include "m_menu.h"
#include "k_menu.h"
#include "m_random.h"
#include "m_misc.h"
@ -58,20 +58,6 @@ typedef struct
// ==========================================================================
// Cheat responders
/*static UINT8 cheatf_ultimate(void)
{
if (menuactive && (currentMenu != &MainDef && currentMenu != &SP_LoadDef))
return 0; // Only on the main menu, or the save select!
BwehHehHe();
ultimate_selectable = (!ultimate_selectable);
// If on the save select, move to what is now Ultimate Mode!
if (currentMenu == &SP_LoadDef)
M_ForceSaveSlotSelected(NOSAVESLOT);
return 1;
}*/
static UINT8 cheatf_warp(void)
{
UINT8 i;
@ -83,7 +69,7 @@ static UINT8 cheatf_warp(void)
if (menuactive && currentMenu != &MainDef)
return 0; // Only on the main menu!
// Temporarily unlock EVERYTHING.
// Unlock EVERYTHING.
for (i = 0; i < MAXUNLOCKABLES; i++)
{
if (!unlockables[i].conditionset)
@ -134,18 +120,6 @@ static UINT8 cheatf_devmode(void)
}
#endif
/*static cheatseq_t cheat_ultimate = {
0, cheatf_ultimate,
{ SCRAMBLE('u'), SCRAMBLE('l'), SCRAMBLE('t'), SCRAMBLE('i'), SCRAMBLE('m'), SCRAMBLE('a'), SCRAMBLE('t'), SCRAMBLE('e'), 0xff }
};*/
/*static cheatseq_t cheat_ultimate_joy = {
0, cheatf_ultimate,
{ SCRAMBLE(KEY_UPARROW), SCRAMBLE(KEY_UPARROW), SCRAMBLE(KEY_DOWNARROW), SCRAMBLE(KEY_DOWNARROW),
SCRAMBLE(KEY_LEFTARROW), SCRAMBLE(KEY_RIGHTARROW), SCRAMBLE(KEY_LEFTARROW), SCRAMBLE(KEY_RIGHTARROW),
SCRAMBLE(KEY_ENTER), 0xff }
};*/
static cheatseq_t cheat_warp = {
0, cheatf_warp,
//{ SCRAMBLE('r'), SCRAMBLE('e'), SCRAMBLE('d'), SCRAMBLE('x'), SCRAMBLE('v'), SCRAMBLE('i'), 0xff }
@ -253,8 +227,6 @@ boolean cht_Responder(event_t *ev)
else
ch = (UINT8)ev->data1;
//ret += cht_CheckCheat(&cheat_ultimate, (char)ch);
//ret += cht_CheckCheat(&cheat_ultimate_joy, (char)ch);
ret += cht_CheckCheat(&cheat_warp, (char)ch);
ret += cht_CheckCheat(&cheat_warp_joy, (char)ch);
#ifdef DEVELOP

View file

@ -20,7 +20,9 @@
#include "g_game.h" // record info
#include "r_skins.h" // numskins
#include "r_draw.h" // R_GetColorByName
#include "k_pwrlv.h"
#include "k_profiles.h"
// Map triggers for linedef executors
// 32 triggers, one bit each
@ -108,7 +110,20 @@ UINT8 M_CheckCondition(condition_t *cn)
case UC_MATCHESPLAYED: // Requires any level completed >= x times
return (matchesplayed >= (unsigned)cn->requirement);
case UC_POWERLEVEL: // Requires power level >= x on a certain gametype
return (vspowerlevel[cn->extrainfo1] >= (unsigned)cn->requirement);
{
UINT8 i;
for (i = PROFILE_GUEST; i < PR_GetNumProfiles(); i++)
{
profile_t *p = PR_GetProfile(i);
if (p->powerlevels[cn->extrainfo1] >= (unsigned)cn->requirement)
{
return true;
}
}
return false;
}
case UC_GAMECLEAR: // Requires game beaten >= x times
return (timesBeaten >= (unsigned)cn->requirement);
case UC_OVERALLTIME: // Requires overall time <= x
@ -359,10 +374,14 @@ UINT8 M_SecretUnlocked(INT32 type)
{
INT32 i;
#if 1
if (dedicated)
return true;
#endif
#if 0
(void)type;
(void)i;
return false; // for quick testing
#else
#ifdef DEVELOP
#define CHADYES true
@ -378,6 +397,7 @@ UINT8 M_SecretUnlocked(INT32 type)
return CHADYES;
#undef CHADYES
#endif //if 0
}
UINT8 M_MapLocked(INT32 mapnum)

11586
src/m_menu.c

File diff suppressed because it is too large Load diff

View file

@ -1,590 +0,0 @@
// SONIC ROBO BLAST 2
//-----------------------------------------------------------------------------
// Copyright (C) 1993-1996 by id Software, Inc.
// Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 2011-2016 by Matthew "Kaito Sinclaire" Walsh.
// Copyright (C) 1999-2020 by Sonic Team Junior.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
// See the 'LICENSE' file for more details.
//-----------------------------------------------------------------------------
/// \file m_menu.h
/// \brief Menu widget stuff, selection and such
#ifndef __X_MENU__
#define __X_MENU__
#include "doomstat.h" // for NUMGAMETYPES
#include "d_event.h"
#include "command.h"
#include "f_finale.h" // for ttmode_enum
#include "i_threads.h"
#include "mserv.h"
#include "r_skins.h" // for SKINNAMESIZE
// Compatibility with old-style named NiGHTS replay files.
#define OLDNREPLAYNAME
//
// MENUS
//
// If menu hierarchies go deeper, change this up to 5.
// Zero-based, inclusive.
#define NUMMENULEVELS 3
#define MENUBITS 6
// Menu IDs sectioned by numeric places to signify hierarchy
/**
* IF YOU MODIFY THIS, MODIFY MENUTYPES_LIST[] IN dehacked.c TO MATCH.
*/
typedef enum
{
MN_NONE,
MN_MAIN,
// Single Player
MN_SP_MAIN,
MN_SP_LOAD,
MN_SP_PLAYER,
MN_SP_LEVELSELECT,
MN_SP_LEVELSTATS,
MN_SP_TIMEATTACK,
MN_SP_TIMEATTACK_LEVELSELECT,
MN_SP_GUESTREPLAY,
MN_SP_REPLAY,
MN_SP_GHOST,
MN_SP_NIGHTSATTACK,
MN_SP_NIGHTS_LEVELSELECT,
MN_SP_NIGHTS_GUESTREPLAY,
MN_SP_NIGHTS_REPLAY,
MN_SP_NIGHTS_GHOST,
MN_SP_MARATHON,
// Multiplayer
MN_MP_MAIN,
MN_MP_SPLITSCREEN, // SplitServer
MN_MP_SERVER,
MN_MP_CONNECT,
MN_MP_ROOM,
MN_MP_PLAYERSETUP, // MP_PlayerSetupDef shared with SPLITSCREEN if #defined NONET
MN_MP_SERVER_OPTIONS,
// Options
MN_OP_MAIN,
MN_OP_P1CONTROLS,
MN_OP_CHANGECONTROLS, // OP_ChangeControlsDef shared with P2
MN_OP_P1MOUSE,
MN_OP_P1JOYSTICK,
MN_OP_JOYSTICKSET, // OP_JoystickSetDef shared with P2
MN_OP_P1CAMERA,
MN_OP_P2CONTROLS,
MN_OP_P2MOUSE,
MN_OP_P2JOYSTICK,
MN_OP_P2CAMERA,
MN_OP_PLAYSTYLE,
MN_OP_VIDEO,
MN_OP_VIDEOMODE,
MN_OP_COLOR,
MN_OP_OPENGL,
MN_OP_OPENGL_LIGHTING,
MN_OP_SOUND,
MN_OP_SERVER,
MN_OP_MONITORTOGGLE,
MN_OP_DATA,
MN_OP_ADDONS,
MN_OP_SCREENSHOTS,
MN_OP_ERASEDATA,
// Extras
MN_SR_MAIN,
MN_SR_PANDORA,
MN_SR_LEVELSELECT,
MN_SR_UNLOCKCHECKLIST,
MN_SR_EMBLEMHINT,
MN_SR_PLAYER,
MN_SR_SOUNDTEST,
// Addons (Part of MISC, but let's make it our own)
MN_AD_MAIN,
// MISC
// MN_MESSAGE,
// MN_SPAUSE,
// MN_MPAUSE,
// MN_SCRAMBLETEAM,
// MN_CHANGETEAM,
// MN_CHANGELEVEL,
// MN_MAPAUSE,
// MN_HELP,
MN_SPECIAL,
NUMMENUTYPES,
} menutype_t; // up to 63; MN_SPECIAL = 53
#define MTREE2(a,b) (a | (b<<MENUBITS))
#define MTREE3(a,b,c) MTREE2(a, MTREE2(b,c))
#define MTREE4(a,b,c,d) MTREE2(a, MTREE3(b,c,d))
typedef struct
{
char bgname[8]; // name for background gfx lump; lays over titlemap if this is set
SINT8 fadestrength; // darken background when displaying this menu, strength 0-31 or -1 for undefined
INT32 bgcolor; // fill color, overrides bg name. -1 means follow bg name rules.
INT32 titlescrollxspeed; // background gfx scroll per menu; inherits global setting
INT32 titlescrollyspeed; // y scroll
boolean bghide; // for titlemaps, hide the background.
SINT8 hidetitlepics; // hide title gfx per menu; -1 means undefined, inherits global setting
ttmode_enum ttmode; // title wing animation mode; default TTMODE_OLD
UINT8 ttscale; // scale of title wing gfx (FRACUNIT / ttscale); -1 means undefined, inherits global setting
char ttname[9]; // lump name of title wing gfx. If name length is <= 6, engine will attempt to load numbered frames (TTNAMExx)
INT16 ttx; // X position of title wing
INT16 tty; // Y position of title wing
INT16 ttloop; // # frame to loop; -1 means dont loop
UINT16 tttics; // # of tics per frame
char musname[7]; ///< Music track to play. "" for no music.
UINT16 mustrack; ///< Subsong to play. Only really relevant for music modules and specific formats supported by GME. 0 to ignore.
boolean muslooping; ///< Loop the music
boolean musstop; ///< Don't play any music
boolean musignore; ///< Let the current music keep playing
boolean enterbubble; // run all entrance line execs after common ancestor and up to child. If false, only run the child's exec
boolean exitbubble; // run all exit line execs from child and up to before common ancestor. If false, only run the child's exec
INT32 entertag; // line exec to run on menu enter, if titlemap
INT32 exittag; // line exec to run on menu exit, if titlemap
INT16 enterwipe; // wipe type to run on menu enter, -1 means default
INT16 exitwipe; // wipe type to run on menu exit, -1 means default
} menupres_t;
extern menupres_t menupres[NUMMENUTYPES];
extern UINT32 prevMenuId;
extern UINT32 activeMenuId;
void M_InitMenuPresTables(void);
//UINT8 M_GetYoungestChildMenu(void);
//void M_ChangeMenuMusic(const char *defaultmusname, boolean defaultmuslooping);
//void M_SetMenuCurBackground(const char *defaultname);
//void M_SetMenuCurFadeValue(UINT8 defaultvalue);
//void M_SetMenuCurTitlePics(void);
// Called by main loop,
// saves config file and calls I_Quit when user exits.
// Even when the menu is not displayed,
// this can resize the view and change game parameters.
// Does all the real work of the menu interaction.
boolean M_Responder(event_t *ev);
// Called by main loop, runs for demo playback. If this returns true, nullify any further user input.
boolean M_DemoResponder(event_t *ev);
// Called by main loop, only used for menu (skull cursor) animation.
void M_Ticker(void);
// Called by main loop, draws the menus directly into the screen buffer.
void M_Drawer(void);
// Called by D_SRB2Main, loads the config file.
void M_Init(void);
// Called by D_SRB2Main also, sets up the playermenu and description tables.
void M_InitCharacterTables(void);
// Called by intro code to force menu up upon a keypress,
// does nothing if menu is already up.
void M_StartControlPanel(void);
// Called upon end of a mode attack run
void M_EndModeAttackRun(void);
// Called on new server add, or other reasons
void M_SortServerList(void);
// Draws a box with a texture inside as background for messages
void M_DrawTextBox(INT32 x, INT32 y, INT32 width, INT32 boxlines);
// Used in d_netcmd to restart time attack
void M_ModeAttackRetry(INT32 choice);
// the function to show a message box typing with the string inside
// string must be static (not in the stack)
// routine is a function taking a INT32 in parameter
typedef enum
{
MM_NOTHING = 0, // is just displayed until the user do someting
MM_YESNO, // routine is called with only 'y' or 'n' in param
MM_EVENTHANDLER // the same of above but without 'y' or 'n' restriction
// and routine is void routine(event_t *) (ex: set control)
} menumessagetype_t;
void M_StartMessage(const char *string, void *routine, menumessagetype_t itemtype);
typedef enum
{
M_NOT_WAITING,
M_WAITING_VERSION,
M_WAITING_SERVERS,
}
M_waiting_mode_t;
extern M_waiting_mode_t m_waiting_mode;
// Called by linux_x/i_video_xshm.c
void M_QuitResponse(INT32 ch);
// Determines whether to show a level in the list (platter version does not need to be exposed)
boolean M_CanShowLevelInList(INT32 mapnum, INT32 gt);
// flags for items in the menu
// menu handle (what we do when key is pressed
#define IT_TYPE 15 // (1+2+4+8)
#define IT_CALL 0 // call the function
#define IT_SPACE 1 // no handling
#define IT_ARROWS 2 // call function with 0 for left arrow and 1 for right arrow in param
#define IT_KEYHANDLER 4 // call with the key in param
#define IT_SUBMENU 6 // go to sub menu
#define IT_CVAR 8 // handle as a cvar
#define IT_PAIR 11 // no handling, define both sides of text
#define IT_MSGHANDLER 12 // same as key but with event and sometime can handle y/n key (special for message)
#define IT_DISPLAY (48+64+128) // 16+32+64+128
#define IT_NOTHING 0 // space
#define IT_PATCH 16 // a patch or a string with big font
#define IT_STRING 32 // little string (spaced with 10)
#define IT_WHITESTRING 48 // little string in white
#define IT_DYBIGSPACE 64 // same as noting
#define IT_DYLITLSPACE (16+64) // little space
#define IT_STRING2 (32+64) // a simple string
#define IT_GRAYPATCH (16+32+64) // grayed patch or big font string
#define IT_BIGSLIDER 128 // volume sound use this
#define IT_TRANSTEXT (16+128) // Transparent text
#define IT_TRANSTEXT2 (32+128) // used for control names
#define IT_HEADERTEXT (48+128) // Non-selectable header option, displays in yellow offset to the left a little
#define IT_QUESTIONMARKS (64+128) // Displays as question marks, used for secrets
#define IT_CENTER 256 // if IT_PATCH, center it on screen
//consvar specific
#define IT_CVARTYPE (512+1024+2048)
#define IT_CV_NORMAL 0
#define IT_CV_SLIDER 512
#define IT_CV_STRING 1024
#define IT_CV_NOPRINT 1536
#define IT_CV_NOMOD 2048
#define IT_CV_INVISSLIDER 2560
#define IT_CV_INTEGERSTEP 4096 // if IT_CV_NORMAL and cvar is CV_FLOAT, modify it by 1 instead of 0.0625
#define IT_CV_FLOATSLIDER 4608 // IT_CV_SLIDER, value modified by 0.0625 instead of 1 (for CV_FLOAT cvars)
//call/submenu specific
// There used to be a lot more here but ...
// A lot of them became redundant with the advent of the Pause menu, so they were removed
#define IT_CALLTYPE (512+1024)
#define IT_CALL_NORMAL 0
#define IT_CALL_NOTMODIFIED 512
// in INT16 for some common use
#define IT_BIGSPACE (IT_SPACE +IT_DYBIGSPACE)
#define IT_LITLSPACE (IT_SPACE +IT_DYLITLSPACE)
#define IT_CONTROL (IT_STRING2+IT_CALL)
#define IT_CVARMAX (IT_CVAR +IT_CV_NOMOD)
#define IT_DISABLED (IT_SPACE +IT_GRAYPATCH)
#define IT_GRAYEDOUT (IT_SPACE +IT_TRANSTEXT)
#define IT_GRAYEDOUT2 (IT_SPACE +IT_TRANSTEXT2)
#define IT_HEADER (IT_SPACE +IT_HEADERTEXT)
#define IT_SECRET (IT_SPACE +IT_QUESTIONMARKS)
#define MAXSTRINGLENGTH 32
typedef union
{
struct menu_s *submenu; // IT_SUBMENU
consvar_t *cvar; // IT_CVAR
void (*routine)(INT32 choice); // IT_CALL, IT_KEYHANDLER, IT_ARROWS
void (*eventhandler)(event_t *ev); // MM_EVENTHANDLER
} itemaction_t;
//
// MENU TYPEDEFS
//
typedef struct menuitem_s
{
// show IT_xxx
UINT16 status;
const char *patch;
const char *text; // used when FONTBxx lump is found
itemaction_t itemaction;
// hotkey in menu or y of the item
UINT16 alphaKey;
} menuitem_t;
typedef struct menu_s
{
UINT32 menuid; // ID to encode menu type and hierarchy
const char *menutitlepic;
INT16 numitems; // # of menu items
struct menu_s *prevMenu; // previous menu
menuitem_t *menuitems; // menu items
void (*drawroutine)(void); // draw routine
INT16 x, y; // x, y of menu
INT16 lastOn; // last item user was on in menu
boolean (*quitroutine)(void); // called before quit a menu return true if we can
} menu_t;
void M_SetupNextMenu(menu_t *menudef);
void M_ClearMenus(boolean callexitmenufunc);
// Maybe this goes here????? Who knows.
boolean M_MouseNeeded(void);
#ifdef HAVE_THREADS
extern I_mutex m_menu_mutex;
#endif
extern menu_t *currentMenu;
extern menu_t MainDef;
extern menu_t SP_LoadDef;
// Call upon joystick hotplug
void M_SetupJoystickMenu(INT32 choice);
extern menu_t OP_JoystickSetDef;
// Stuff for customizing the player select screen
typedef struct
{
boolean used;
char notes[441];
char picname[8];
char skinname[SKINNAMESIZE*2+2]; // skin&skin\0
patch_t *charpic;
UINT8 prev;
UINT8 next;
// new character select
char displayname[SKINNAMESIZE+1];
SINT8 skinnum[2];
UINT16 oppositecolor;
char nametag[8];
patch_t *namepic;
UINT16 tagtextcolor;
UINT16 tagoutlinecolor;
} description_t;
// level select platter
typedef struct
{
char header[22+5]; // mapheader_t lvltttl max length + " ZONE"
INT32 maplist[3];
char mapnames[3][17+1];
boolean mapavailable[4]; // mapavailable[3] == wide or not
} levelselectrow_t;
typedef struct
{
UINT8 numrows;
levelselectrow_t *rows;
} levelselect_t;
// experimental level select end
// descriptions for gametype select screen
/*typedef struct
{
UINT8 col[2];
char notes[441];
} gtdesc_t;
extern gtdesc_t gametypedesc[NUMGAMETYPES];*/
// mode descriptions for video mode menu
typedef struct
{
INT32 modenum; // video mode number in the vidmodes list
const char *desc; // XXXxYYY
UINT8 goodratio; // aspect correct if 1
} modedesc_t;
// savegame struct for save game menu
typedef struct
{
char levelname[32];
UINT8 skinnum;
UINT8 numemeralds;
UINT8 numgameovers;
INT32 lives;
INT32 continuescore;
INT32 gamemap;
} saveinfo_t;
extern description_t description[MAXSKINS];
extern consvar_t cv_showfocuslost;
extern consvar_t cv_newgametype, cv_nextmap, cv_chooseskin, cv_serversort;
extern CV_PossibleValue_t gametype_cons_t[];
extern char dummystaffname[22];
extern INT16 startmap;
extern INT32 ultimate_selectable;
extern INT16 char_on, startchar;
#define MAXSAVEGAMES 31
#define NOSAVESLOT 0 //slot where Play Without Saving appears
#define MARATHONSLOT 420 // just has to be nonzero, but let's use one that'll show up as an obvious error if something goes wrong while not using our existing saves
#define BwehHehHe() S_StartSound(NULL, sfx_bewar1+M_RandomKey(4)) // Bweh heh he
//void M_TutorialSaveControlResponse(INT32 ch);
void M_ForceSaveSlotSelected(INT32 sslot);
void M_CheatActivationResponder(INT32 ch);
void M_ModeAttackRetry(INT32 choice);
// Level select updating
void Nextmap_OnChange(void);
// Screenshot menu updating
void Moviemode_mode_Onchange(void);
void Screenshot_option_Onchange(void);
// Addons menu updating
void Addons_option_Onchange(void);
void M_ReplayHut(INT32 choice);
void M_SetPlaybackMenuPointer(void);
void M_RefreshPauseMenu(void);
INT32 HU_GetHighlightColor(void);
// Moviemode menu updating
void Moviemode_option_Onchange(void);
// Player Setup menu colors linked list
typedef struct menucolor_s {
struct menucolor_s *next;
struct menucolor_s *prev;
UINT16 color;
} menucolor_t;
extern menucolor_t *menucolorhead, *menucolortail;
void M_AddMenuColor(UINT16 color);
void M_MoveColorBefore(UINT16 color, UINT16 targ);
void M_MoveColorAfter(UINT16 color, UINT16 targ);
UINT16 M_GetColorBefore(UINT16 color);
UINT16 M_GetColorAfter(UINT16 color);
void M_InitPlayerSetupColors(void);
void M_FreePlayerSetupColors(void);
// These defines make it a little easier to make menus
#define DEFAULTMENUSTYLE(id, header, source, prev, x, y)\
{\
id,\
header,\
sizeof(source)/sizeof(menuitem_t),\
prev,\
source,\
M_DrawGenericMenu,\
x, y,\
0,\
NULL\
}
#define DEFAULTSCROLLMENUSTYLE(id, header, source, prev, x, y)\
{\
id,\
header,\
sizeof(source)/sizeof(menuitem_t),\
prev,\
source,\
M_DrawGenericScrollMenu,\
x, y,\
0,\
NULL\
}
#define PAUSEMENUSTYLE(source, x, y)\
{\
MN_SPECIAL,\
NULL,\
sizeof(source)/sizeof(menuitem_t),\
NULL,\
source,\
M_DrawPauseMenu,\
x, y,\
0,\
NULL\
}
#define CENTERMENUSTYLE(id, header, source, prev, y)\
{\
id,\
header,\
sizeof(source)/sizeof(menuitem_t),\
prev,\
source,\
M_DrawCenteredMenu,\
BASEVIDWIDTH/2, y,\
0,\
NULL\
}
#define MAPICONMENUSTYLE(header, source, prev)\
{\
MN_NONE,\
header,\
sizeof (source)/sizeof (menuitem_t),\
prev,\
source,\
M_DrawServerMenu,\
24,40,\
0,\
NULL\
}
#define CONTROLMENUSTYLE(id, source, prev)\
{\
id,\
"M_CONTRO",\
sizeof (source)/sizeof (menuitem_t),\
prev,\
source,\
M_DrawControl,\
26, 40,\
0,\
NULL\
}
#define IMAGEDEF(source)\
{\
MN_SPECIAL,\
NULL,\
sizeof (source)/sizeof (menuitem_t),\
NULL,\
source,\
M_DrawImageDef,\
0, 0,\
0,\
NULL\
}
#endif //__X_MENU__

View file

@ -46,7 +46,7 @@
#include "m_anigif.h"
// So that the screenshot menu auto-updates...
#include "m_menu.h"
#include "k_menu.h"
#ifdef HWRENDER
#include "hardware/hw_main.h"
@ -181,6 +181,51 @@ boolean takescreenshot = false; // Take a screenshot this tic
moviemode_t moviemode = MM_OFF;
char joinedIPlist[NUMLOGIP][2][255];
char joinedIP[255];
// This initializes the above array to have NULL evrywhere it should.
void M_InitJoinedIPArray(void)
{
UINT8 i;
for (i=0; i < NUMLOGIP; i++)
{
strcpy(joinedIPlist[i][0], "");
strcpy(joinedIPlist[i][1], "");
}
}
// This adds an entry to the above array
void M_AddToJoinedIPs(char *address, char *servname)
{
UINT8 i = 0;
UINT8 dupeindex = 0;
// Check for dupes...
for (; i < NUMLOGIP && !dupeindex; i++)
{
// I don't care about the server name (this is broken anyway...) but definitely check the addresses
if (strcmp(joinedIPlist[i][0], address) == 0)
dupeindex = i;
}
CONS_Printf("Adding %s (%s) to list of manually joined IPs\n", servname, address);
// Start by moving every IP up 1 slot (dropping the last IP in the table)
// If we found duplicates, start here instead and pull the rest up.
i = dupeindex ? dupeindex : NUMLOGIP;
for (; i; i--)
{
strcpy(joinedIPlist[i][0], joinedIPlist[i-1][0]);
strcpy(joinedIPlist[i][1], joinedIPlist[i-1][1]);
}
// and add the new IP at the start of the table!
strcpy(joinedIPlist[0][0], address);
strcpy(joinedIPlist[0][1], servname);
}
/** Returns the map number for a map identified by the last two characters in
* its name.
*
@ -449,6 +494,87 @@ boolean FIL_CheckExtension(const char *in)
return false;
}
// LAST IPs JOINED LOG FILE!
// ...It won't be as overly engineered as the config file because let's be real there's 0 need to...
// Save the file:
void M_SaveJoinedIPs(void)
{
FILE *f = NULL;
UINT8 i;
char *filepath;
if (!strlen(joinedIPlist[0][0]))
return; // Don't bother, there's nothing to save.
// append srb2home to beginning of filename
// but check if srb2home isn't already there, first
if (!strstr(IPLOGFILE, srb2home))
filepath = va(pandf,srb2home, IPLOGFILE);
else
filepath = Z_StrDup(IPLOGFILE);
f = fopen(filepath, "w");
if (f == NULL)
return; // Uh I guess you don't have disk space?????????
for (i=0; i < NUMLOGIP; i++)
{
if (strlen(joinedIPlist[i][0]))
{
char savestring[MAXSTRINGLENGTH];
strcpy(savestring, joinedIPlist[i][0]);
strcat(savestring, IPLOGFILESEP);
strcat(savestring, joinedIPlist[i][1]);
fputs(savestring, f);
fputs("\n", f); // Because this won't do it automatically now will it...
}
}
fclose(f);
}
// Load the file:
void M_LoadJoinedIPs(void)
{
FILE *f = NULL;
UINT8 i = 0;
char *filepath;
char *s;
char content[255]; // 255 is more than long enough!
filepath = va("%s"PATHSEP"%s", srb2home, IPLOGFILE);
f = fopen(filepath, "r");
if (f == NULL)
return; // File doesn't exist? sure, just do nothing then.
while (fgets(content, 255, f) && i < NUMLOGIP && content[0] && content[0] != '\n') // Don't let us write more than we can chew!
{
// Now we have garbage under the form of "address;string"
// Now you might ask yourself, but what do we do if the player fucked with their file and now there's a bunch of garbage?
// ...Well that's not my problem lol.
s = strtok(content, IPLOGFILESEP); // We got the address
strcpy(joinedIPlist[i][0], s);
s = strtok(NULL, IPLOGFILESEP); // Let's get rid of this awful \n while we're here!
if (strlen(s))
s[strlen(s)-1] = '\0'; // Remove the \n
strcpy(joinedIPlist[i][1], s);
i++;
}
fclose(f); // We're done here
}
// ==========================================================================
// CONFIGURATION FILE
// ==========================================================================
@ -507,7 +633,7 @@ void Command_LoadConfig_f(void)
for (i = 0; i < MAXSPLITSCREENPLAYERS; i++)
{
G_CopyControls(gamecontrol[i], gamecontroldefault[i][gcs_kart], NULL, 0);
G_CopyControls(gamecontrol[i], gamecontroldefault, NULL, 0);
}
// temporarily reset execversion to default
@ -561,7 +687,7 @@ void M_FirstLoadConfig(void)
for (i = 0; i < MAXSPLITSCREENPLAYERS; i++)
{
G_CopyControls(gamecontrol[i], gamecontroldefault[i][gcs_kart], NULL, 0);
G_CopyControls(gamecontrol[i], gamecontroldefault, NULL, 0);
}
// register execversion here before we load any configs
@ -663,15 +789,7 @@ void M_SaveConfig(const char *filename)
if (!dedicated)
{
if (tutorialmode && tutorialgcs)
{
// using gcs_custom as temp storage
G_SaveKeySetting(f, gamecontroldefault[0][gcs_custom], gamecontrol[1], gamecontrol[2], gamecontrol[3]);
}
else
{
G_SaveKeySetting(f, gamecontrol[0], gamecontrol[1], gamecontrol[2], gamecontrol[3]);
}
G_SaveKeySetting(f, gamecontrol[0], gamecontrol[1], gamecontrol[2], gamecontrol[3]);
}
fclose(f);
@ -1651,12 +1769,12 @@ boolean M_ScreenshotResponder(event_t *ev)
ch = ev->data1;
if (ch >= KEY_MOUSE1 && menuactive) // If it's not a keyboard key, then don't allow it in the menus!
if (ch >= NUMKEYS && menuactive) // If it's not a keyboard key, then don't allow it in the menus!
return false;
if (ch == KEY_F8 || ch == gamecontrol[0][gc_screenshot][0] || ch == gamecontrol[0][gc_screenshot][1]) // remappable F8
if (ch == KEY_F8 /*|| ch == gamecontrol[0][gc_screenshot][0] || ch == gamecontrol[0][gc_screenshot][1]*/) // remappable F8
M_ScreenShot();
else if (ch == KEY_F9 || ch == gamecontrol[0][gc_recordgif][0] || ch == gamecontrol[0][gc_recordgif][1]) // remappable F9
else if (ch == KEY_F9 /*|| ch == gamecontrol[0][gc_recordgif][0] || ch == gamecontrol[0][gc_recordgif][1]*/) // remappable F9
((moviemode) ? M_StopMovie : M_StartMovie)();
else
return false;

View file

@ -40,7 +40,26 @@ void M_SaveFrame(void);
void M_StopMovie(void);
// the file where game vars and settings are saved
#define CONFIGFILENAME "kartconfig.cfg"
#define CONFIGFILENAME "ringconfig.cfg"
// The file where we'll save the last IPs we joined
#define IPLOGFILE "ringsavedips.txt"
#define IPLOGFILESEP ";"
#define NUMLOGIP 3
// Array where we'll store addresses to display for last servers joined
// {address, servame}
// 255 is long enough to store the text
extern char joinedIPlist[NUMLOGIP][2][255];
// Keep the address we're joining in mind until we've finished joining.
// Since we don't wanna add an IP address we aren't even sure worked out.
extern char joinedIP[255];
void M_InitJoinedIPArray(void);
void M_AddToJoinedIPs(char *address, char *servname);
void M_SaveJoinedIPs(void);
void M_LoadJoinedIPs(void);
INT32 M_MapNumber(char first, char second);

View file

@ -20,9 +20,11 @@
#include "command.h"
#include "i_threads.h"
#include "mserv.h"
#include "m_menu.h"
#include "z_zone.h"
// SRB2Kart
#include "k_menu.h"
#ifdef HAVE_DISCORDRPC
#include "discord.h"
#endif
@ -117,11 +119,11 @@ void AddMServCommands(void)
static void WarnGUI (void)
{
#ifdef HAVE_THREADS
I_lock_mutex(&m_menu_mutex);
I_lock_mutex(&k_menu_mutex);
#endif
M_StartMessage(M_GetText("There was a problem connecting to\nthe Master Server\n\nCheck the console for details.\n"), NULL, MM_NOTHING);
#ifdef HAVE_THREADS
I_unlock_mutex(m_menu_mutex);
I_unlock_mutex(k_menu_mutex);
#endif
}

View file

@ -786,73 +786,76 @@ void P_CheckPointLimit(void)
// Checks whether or not to end a race netgame.
boolean P_CheckRacers(void)
{
UINT8 i;
UINT8 numplayersingame = 0;
UINT8 numexiting = 0;
boolean eliminatelast = cv_karteliminatelast.value;
boolean everyonedone = true;
boolean eliminatebots = false;
const boolean griefed = (spectateGriefed > 0);
boolean eliminateLast = cv_karteliminatelast.value;
boolean allHumansDone = true;
//boolean allBotsDone = true;
UINT8 numPlaying = 0;
UINT8 numExiting = 0;
UINT8 numHumans = 0;
UINT8 numBots = 0;
UINT8 i;
// Check if all the players in the race have finished. If so, end the level.
for (i = 0; i < MAXPLAYERS; i++)
{
if (!playeringame[i] || players[i].spectator || players[i].lives <= 0) // Not playing
if (!playeringame[i] || players[i].spectator || players[i].lives <= 0)
{
// Y'all aren't even playing
continue;
}
numplayersingame++;
numPlaying++;
if (players[i].bot)
{
numBots++;
}
else
{
numHumans++;
}
if (players[i].exiting || (players[i].pflags & PF_NOCONTEST))
{
numexiting++;
numExiting++;
}
else
{
if (players[i].bot)
{
// Isn't a human, thus doesn't matter. (Sorry, robots.)
// Set this so that we can check for bots that need to get eliminated, though!
eliminatebots = true;
continue;
//allBotsDone = false;
}
else
{
allHumansDone = false;
}
everyonedone = false;
}
}
// If we returned here with bots left, then the last place bot may have a chance to finish the map and NOT get time over.
// Not that it affects anything, they didn't make the map take longer or even get any points from it. But... it's a bit inconsistent!
// So if there's any bots, we'll let the game skip this, continue onto calculating eliminatelast, THEN we return true anyway.
if (everyonedone && !eliminatebots)
{
// Everyone's finished, we're done here!
racecountdown = exitcountdown = 0;
return true;
}
if (numplayersingame <= 1)
if (numPlaying <= 1)
{
// Never do this without enough players.
eliminatelast = false;
eliminateLast = false;
}
else
{
if (grandprixinfo.gp == true)
{
// Always do this in GP
eliminatelast = true;
}
else if (griefed)
if (griefed == true)
{
// Don't do this if someone spectated
eliminatelast = false;
eliminateLast = false;
}
else if (grandprixinfo.gp == true)
{
// Always do this in GP
eliminateLast = true;
}
}
if (eliminatelast == true && (numexiting >= numplayersingame-1))
if (eliminateLast == true && (numExiting >= numPlaying-1))
{
// Everyone's done playing but one guy apparently.
// Just kill everyone who is still playing.
@ -879,9 +882,10 @@ boolean P_CheckRacers(void)
return true;
}
if (everyonedone)
if (numHumans > 0 && allHumansDone == true)
{
// See above: there might be bots that are still going, but all players are done, so we can exit now.
// There might be bots that are still going,
// but all of the humans are done, so we can exit now.
racecountdown = exitcountdown = 0;
return true;
}
@ -889,22 +893,21 @@ boolean P_CheckRacers(void)
// SO, we're not done playing.
// Let's see if it's time to start the death counter!
if (!racecountdown)
if (racecountdown == 0)
{
// If the winners are all done, then start the death timer.
UINT8 winningpos = 1;
UINT8 winningPos = max(1, numPlaying / 2);
winningpos = max(1, numplayersingame/2);
if (numplayersingame % 2) // any remainder?
if (numPlaying % 2) // Any remainder? Then round up.
{
winningpos++;
winningPos++;
}
if (numexiting >= winningpos)
if (numExiting >= winningPos)
{
tic_t countdown = 30*TICRATE; // 30 seconds left to finish, get going!
if (netgame)
if (K_CanChangeRules() == true)
{
// Custom timer
countdown = cv_countdowntime.value * TICRATE;
@ -914,13 +917,14 @@ boolean P_CheckRacers(void)
}
}
// We're still playing, but no one else is, so we need to reset spectator griefing.
if (numplayersingame <= 1)
// We're still playing, but no one else is,
// so we need to reset spectator griefing.
if (numPlaying <= 1)
{
spectateGriefed = 0;
}
// Turns out we're still having a good time & playing the game, we didn't have to do anything :)
// We are still having fun and playing the game :)
return false;
}
@ -2012,7 +2016,7 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
source->player->invincibilitytimer += kinvextend;
}
K_PlayHitEmSound(source, target);
K_TryHurtSoundExchange(target, source);
K_BattleAwardHit(source->player, player, inflictor, takeBumpers);
K_TakeBumpersFromPlayer(source->player, player, takeBumpers);
@ -2085,14 +2089,14 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
player->flashing = K_GetKartFlashing(player);
}
P_PlayRinglossSound(player->mo);
P_PlayRinglossSound(target);
if (ringburst > 0)
{
P_PlayerRingBurst(player, ringburst);
}
K_PlayPainSound(player->mo);
K_PlayPainSound(target, source);
if ((hardhit == true) || (cv_kartdebughuddrop.value && !modeattacking))
{

View file

@ -2463,12 +2463,6 @@ fixed_t P_GetThingStepUp(mobj_t *thing)
const fixed_t maxstepmove = P_BaseStepUp();
fixed_t maxstep = maxstepmove;
if (thing->type == MT_SKIM)
{
// Skim special (not needed for kart?)
return 0;
}
if (P_WaterStepUp(thing) == true)
{
// Add some extra stepmove when waterskipping
@ -2525,16 +2519,20 @@ boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff)
#endif
do {
if (thing->flags & MF_NOCLIP) {
if (thing->flags & MF_NOCLIP)
{
tryx = x;
tryy = y;
} else {
}
else
{
if (x-tryx > radius)
tryx += radius;
else if (x-tryx < -radius)
tryx -= radius;
else
tryx = x;
if (y-tryy > radius)
tryy += radius;
else if (y-tryy < -radius)
@ -2603,7 +2601,8 @@ boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff)
return false; // mobj must lower itself to fit
}
}
else if (!(P_MobjTouchingSectorSpecial(thing, 1, 14, false))) // Step down
else if (thing->momz * P_MobjFlip(thing) <= 0 // Step down requires moving down.
&& !(P_MobjTouchingSectorSpecial(thing, 1, 14, false)))
{
// If the floor difference is MAXSTEPMOVE or less, and the sector isn't Section1:14, ALWAYS
// step down! Formerly required a Section1:13 sector for the full MAXSTEPMOVE, but no more.

View file

@ -1132,6 +1132,12 @@ fixed_t P_GetMobjGravity(mobj_t *mo)
{
gravityadd = FixedMul(TUMBLEGRAVITY, gravityadd);
}
if (mo->player->fastfall != 0)
{
// Fast falling
gravityadd *= 4;
}
}
else
{
@ -1761,7 +1767,9 @@ void P_XYMovement(mobj_t *mo)
if (moved && oldslope && !(mo->flags & MF_NOCLIPHEIGHT)) { // Check to see if we ran off
if (oldslope != mo->standingslope) { // First, compare different slopes
if (oldslope != mo->standingslope)
{
// First, compare different slopes
angle_t oldangle, newangle;
angle_t moveangle = K_MomentumAngle(mo);
@ -1773,7 +1781,9 @@ void P_XYMovement(mobj_t *mo)
newangle = 0;
// Now compare the Zs of the different quantizations
if (oldangle-newangle > ANG30 && oldangle-newangle < ANGLE_180) { // Allow for a bit of sticking - this value can be adjusted later
if (oldangle-newangle > ANG30 && oldangle-newangle < ANGLE_180)
{
// Allow for a bit of sticking - this value can be adjusted later
mo->standingslope = oldslope;
P_SetPitchRollFromSlope(mo, mo->standingslope);
P_SlopeLaunch(mo);
@ -1781,26 +1791,36 @@ void P_XYMovement(mobj_t *mo)
//CONS_Printf("launched off of slope - ");
}
/*CONS_Printf("old angle %f - new angle %f = %f\n",
FIXED_TO_FLOAT(AngleFixed(oldangle)),
FIXED_TO_FLOAT(AngleFixed(newangle)),
FIXED_TO_FLOAT(AngleFixed(oldangle-newangle))
);*/
// Sryder 2018-11-26: Don't launch here if it's a slope without physics, we stick to those like glue anyway
} else if (predictedz-mo->z > abs(slopemom.z/2)
&& !(mo->standingslope->flags & SL_NOPHYSICS)) { // Now check if we were supposed to stick to this slope
/*
CONS_Printf("old angle %f - new angle %f = %f\n",
FIXED_TO_FLOAT(AngleFixed(oldangle)),
FIXED_TO_FLOAT(AngleFixed(newangle)),
FIXED_TO_FLOAT(AngleFixed(oldangle-newangle))
);
*/
}
else if (predictedz - mo->z > abs(slopemom.z / 2))
{
// Now check if we were supposed to stick to this slope
//CONS_Printf("%d-%d > %d\n", (predictedz), (mo->z), (slopemom.z/2));
P_SlopeLaunch(mo);
}
} else if (moved && mo->standingslope && predictedz) {
}
else if (moved && mo->standingslope && predictedz)
{
angle_t moveangle = K_MomentumAngle(mo);
angle_t newangle = FixedMul((signed)mo->standingslope->zangle, FINECOSINE((moveangle - mo->standingslope->xydirection) >> ANGLETOFINESHIFT));
/*CONS_Printf("flat to angle %f - predicted z of %f\n",
FIXED_TO_FLOAT(AngleFixed(ANGLE_MAX-newangle)),
FIXED_TO_FLOAT(predictedz)
);*/
if (ANGLE_MAX-newangle > ANG30 && newangle > ANGLE_180) {
/*
CONS_Printf("flat to angle %f - predicted z of %f\n",
FIXED_TO_FLOAT(AngleFixed(ANGLE_MAX-newangle)),
FIXED_TO_FLOAT(predictedz)
);
*/
if (ANGLE_MAX-newangle > ANG30 && newangle > ANGLE_180)
{
mo->momz = P_MobjFlip(mo)*FRACUNIT/2;
mo->z = predictedz + P_MobjFlip(mo);
mo->standingslope = NULL;
@ -3120,12 +3140,6 @@ void P_MobjCheckWater(mobj_t *mobj)
}
}
if (mobj->watertop > top2)
mobj->watertop = top2;
if (mobj->waterbottom < bot2)
mobj->waterbottom = bot2;
// Spectators and dead players don't get to do any of the things after this.
if (p && (p->spectator || p->playerstate != PST_LIVE))
{
@ -3133,8 +3147,10 @@ void P_MobjCheckWater(mobj_t *mobj)
}
// The rest of this code only executes on a water state change.
if (!!(mobj->eflags & MFE_UNDERWATER) == wasinwater)
if (waterwasnotset || !!(mobj->eflags & MFE_UNDERWATER) == wasinwater)
{
return;
}
if (p && !p->waterskip &&
p->curshield != KSHIELD_BUBBLE && wasinwater)
@ -3171,62 +3187,6 @@ void P_MobjCheckWater(mobj_t *mobj)
diff = -diff;
}
// Time to spawn the bubbles!
{
INT32 i;
INT32 bubblecount;
UINT8 prandom[4];
mobj_t *bubble;
mobjtype_t bubbletype;
if (mobj->eflags & MFE_GOOWATER || wasingoo)
S_StartSound(mobj, sfx_ghit);
else if (mobj->eflags & MFE_TOUCHLAVA)
S_StartSound(mobj, sfx_splash);
else
S_StartSound(mobj, sfx_splish); // And make a sound!
bubblecount = FixedDiv(abs(mobj->momz), mobj->scale)>>(FRACBITS-1);
// Max bubble count
if (bubblecount > 128)
bubblecount = 128;
// Create tons of bubbles
for (i = 0; i < bubblecount; i++)
{
// P_RandomByte()s are called individually to allow consistency
// across various compilers, since the order of function calls
// in C is not part of the ANSI specification.
prandom[0] = P_RandomByte();
prandom[1] = P_RandomByte();
prandom[2] = P_RandomByte();
prandom[3] = P_RandomByte();
bubbletype = MT_SMALLBUBBLE;
if (!(prandom[0] & 0x3)) // medium bubble chance up to 64 from 32
bubbletype = MT_MEDIUMBUBBLE;
bubble = P_SpawnMobj(
mobj->x + FixedMul((prandom[1]<<(FRACBITS-3)) * (prandom[0]&0x80 ? 1 : -1), mobj->scale),
mobj->y + FixedMul((prandom[2]<<(FRACBITS-3)) * (prandom[0]&0x40 ? 1 : -1), mobj->scale),
mobj->z + FixedMul((prandom[3]<<(FRACBITS-2)), mobj->scale), bubbletype);
if (bubble)
{
if (P_MobjFlip(mobj)*mobj->momz < 0)
bubble->momz = mobj->momz >> 4;
else
bubble->momz = 0;
bubble->destscale = mobj->scale;
P_SetScale(bubble, mobj->scale);
}
}
}
if (waterwasnotset)
return;
// Check to make sure you didn't just cross into a sector to jump out of
// that has shallower water than the block you were originally in.
if (diff <= (height >> 1))
@ -3328,6 +3288,59 @@ void P_MobjCheckWater(mobj_t *mobj)
P_SetScale(splish, mobj->scale);
}
}
// Time to spawn the bubbles!
{
INT32 i;
INT32 bubblecount;
UINT8 prandom[4];
mobj_t *bubble;
mobjtype_t bubbletype;
if (mobj->eflags & MFE_GOOWATER || wasingoo)
S_StartSound(mobj, sfx_ghit);
else if (mobj->eflags & MFE_TOUCHLAVA)
S_StartSound(mobj, sfx_splash);
else
S_StartSound(mobj, sfx_splish); // And make a sound!
bubblecount = FixedDiv(abs(mobj->momz), mobj->scale) >> (FRACBITS-1);
// Max bubble count
if (bubblecount > 128)
bubblecount = 128;
// Create tons of bubbles
for (i = 0; i < bubblecount; i++)
{
// P_RandomByte()s are called individually to allow consistency
// across various compilers, since the order of function calls
// in C is not part of the ANSI specification.
prandom[0] = P_RandomByte();
prandom[1] = P_RandomByte();
prandom[2] = P_RandomByte();
prandom[3] = P_RandomByte();
bubbletype = MT_SMALLBUBBLE;
if (!(prandom[0] & 0x3)) // medium bubble chance up to 64 from 32
bubbletype = MT_MEDIUMBUBBLE;
bubble = P_SpawnMobj(
mobj->x + FixedMul((prandom[1]<<(FRACBITS-3)) * (prandom[0]&0x80 ? 1 : -1), mobj->scale),
mobj->y + FixedMul((prandom[2]<<(FRACBITS-3)) * (prandom[0]&0x40 ? 1 : -1), mobj->scale),
mobj->z + FixedMul((prandom[3]<<(FRACBITS-2)), mobj->scale), bubbletype);
if (bubble)
{
if (P_MobjFlip(mobj)*mobj->momz < 0)
bubble->momz = mobj->momz >> 4;
else
bubble->momz = 0;
bubble->destscale = mobj->scale;
P_SetScale(bubble, mobj->scale);
}
}
}
}
}
@ -7104,17 +7117,17 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
if (mobj->fuse <= 16)
{
mobj->color = SKINCOLOR_KETCHUP;
mobj->color = SKINCOLOR_GOLD;
/* don't draw papersprite frames after blue boost */
mobj->renderflags ^= RF_DONTDRAW;
}
else if (mobj->fuse <= 32)
mobj->color = SKINCOLOR_SAPPHIRE;
mobj->color = SKINCOLOR_KETCHUP;
else if (mobj->fuse <= 48)
mobj->color = SKINCOLOR_PURPLE;
mobj->color = SKINCOLOR_SAPPHIRE;
else if (mobj->fuse > 48)
mobj->color = K_RainbowColor(
(SKINCOLOR_PURPLE - SKINCOLOR_PINK) // Smoothly transition into the other state
(SKINCOLOR_SAPPHIRE - SKINCOLOR_PINK) // Smoothly transition into the other state
+ ((mobj->fuse - 32) * 2) // Make the color flashing slow down while it runs out
);
@ -7129,14 +7142,14 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
}
break;
case 3:/* purple boost */
if ((mobj->fuse == 32)/* to blue*/
|| (mobj->fuse == 16))/* to red*/
case 3:/* blue boost */
if ((mobj->fuse == 32)/* to red*/
|| (mobj->fuse == 16))/* to yellow*/
K_SpawnDriftBoostClip(mobj->target->player);
break;
case 2:/* blue boost */
if (mobj->fuse == 16)/* to red*/
case 2:/* red boost */
if (mobj->fuse == 16)/* to yellow*/
K_SpawnDriftBoostClip(mobj->target->player);
break;

View file

@ -280,6 +280,8 @@ static void P_NetArchivePlayers(void)
WRITEFIXED(save_p, players[i].spindashspeed);
WRITEUINT8(save_p, players[i].spindashboost);
WRITEFIXED(save_p, players[i].fastfall);
WRITEUINT8(save_p, players[i].numboosts);
WRITEFIXED(save_p, players[i].boostpower);
WRITEFIXED(save_p, players[i].speedboost);
@ -337,8 +339,8 @@ static void P_NetArchivePlayers(void)
WRITESINT8(save_p, players[i].lastjawztarget);
WRITEUINT8(save_p, players[i].jawztargetdelay);
WRITEUINT8(save_p, players[i].confirmInflictor);
WRITEUINT8(save_p, players[i].confirmInflictorDelay);
WRITEUINT8(save_p, players[i].confirmVictim);
WRITEUINT8(save_p, players[i].confirmVictimDelay);
WRITEUINT8(save_p, players[i].trickpanel);
WRITEUINT8(save_p, players[i].tricktime);
@ -565,6 +567,8 @@ static void P_NetUnArchivePlayers(void)
players[i].spindashspeed = READFIXED(save_p);
players[i].spindashboost = READUINT8(save_p);
players[i].fastfall = READFIXED(save_p);
players[i].numboosts = READUINT8(save_p);
players[i].boostpower = READFIXED(save_p);
players[i].speedboost = READFIXED(save_p);
@ -622,8 +626,8 @@ static void P_NetUnArchivePlayers(void)
players[i].lastjawztarget = READSINT8(save_p);
players[i].jawztargetdelay = READUINT8(save_p);
players[i].confirmInflictor = READUINT8(save_p);
players[i].confirmInflictorDelay = READUINT8(save_p);
players[i].confirmVictim = READUINT8(save_p);
players[i].confirmVictimDelay = READUINT8(save_p);
players[i].trickpanel = READUINT8(save_p);
players[i].tricktime = READUINT8(save_p);

View file

@ -96,6 +96,7 @@
#include "k_boss.h"
#include "k_terrain.h" // TRF_TRIPWIRE
#include "k_brightmap.h"
#include "k_terrain.h" // TRF_TRIPWIRE
#include "k_director.h" // K_InitDirector
// Replay names have time
@ -3882,7 +3883,7 @@ static void P_ResetSpawnpoints(void)
static void P_LoadRecordGhosts(void)
{
// see also m_menu.c's Nextmap_OnChange
// see also k_menu.c's Nextmap_OnChange
const size_t glen = strlen(srb2home)+1+strlen("media")+1+strlen("replay")+1+strlen(timeattackfolder)+1+strlen("MAPXX")+1;
char *gpath = malloc(glen);
INT32 i;

View file

@ -894,6 +894,61 @@ fixed_t P_GetLightZAt(const lightlist_t *light, fixed_t x, fixed_t y)
return light->slope ? P_GetSlopeZAt(light->slope, x, y) : light->height;
}
// Returns true if we should run slope physics code on an object.
boolean P_CanApplySlopePhysics(mobj_t *mo, pslope_t *slope)
{
if (slope == NULL || mo == NULL || P_MobjWasRemoved(mo) == true)
{
// Invalid input.
return false;
}
if (slope->flags & SL_NOPHYSICS)
{
// Physics are turned off.
return false;
}
if (slope->normal.x == 0 && slope->normal.y == 0)
{
// Flat slope? No such thing, man. No such thing.
return false;
}
if (mo->player != NULL)
{
if (K_PlayerEBrake(mo->player) == true)
{
// Spindash negates slopes.
return false;
}
}
// We can do slope physics.
return true;
}
// Returns true if we should run slope launch code on an object.
boolean P_CanApplySlopeLaunch(mobj_t *mo, pslope_t *slope)
{
if (slope == NULL || mo == NULL || P_MobjWasRemoved(mo) == true)
{
// Invalid input.
return false;
}
// No physics slopes are fine to launch off of.
if (slope->normal.x == 0 && slope->normal.y == 0)
{
// Flat slope? No such thing, man. No such thing.
return false;
}
// We can do slope launching.
return true;
}
//
// P_QuantizeMomentumToSlope
//
@ -923,42 +978,23 @@ void P_ReverseQuantizeMomentumToSlope(vector3_t *momentum, pslope_t *slope)
slope->zangle = InvAngle(slope->zangle);
}
// SRB2Kart: This fixes all slope-based jumps for different scales in Kart automatically without map tweaking.
// However, they will always feel off every single time... see for yourself: https://cdn.discordapp.com/attachments/270211093761097728/484924392128774165/kart0181.gif
//#define GROWNEVERMISSES
//
// P_SlopeLaunch
//
// Handles slope ejection for objects
void P_SlopeLaunch(mobj_t *mo)
{
if (!(mo->standingslope->flags & SL_NOPHYSICS) // If there's physics, time for launching.
&& (mo->standingslope->normal.x != 0
|| mo->standingslope->normal.y != 0))
if (P_CanApplySlopeLaunch(mo, mo->standingslope) == true) // If there's physics, time for launching.
{
// Double the pre-rotation Z, then halve the post-rotation Z. This reduces the
// vertical launch given from slopes while increasing the horizontal launch
// given. Good for SRB2's gravity and horizontal speeds.
vector3_t slopemom;
slopemom.x = mo->momx;
slopemom.y = mo->momy;
slopemom.z = mo->momz;
P_QuantizeMomentumToSlope(&slopemom, mo->standingslope);
#ifdef GROWNEVERMISSES
{
const fixed_t xyscale = mapobjectscale + (mapobjectscale - mo->scale);
const fixed_t zscale = mapobjectscale + (mapobjectscale - mo->scale);
mo->momx = FixedMul(slopemom.x, xyscale);
mo->momy = FixedMul(slopemom.y, xyscale);
mo->momz = FixedMul(slopemom.z, zscale);
}
#else
mo->momx = slopemom.x;
mo->momy = slopemom.y;
mo->momz = slopemom.z;
#endif
mo->eflags |= MFE_SLOPELAUNCHED;
}
@ -984,14 +1020,19 @@ fixed_t P_GetWallTransferMomZ(mobj_t *mo, pslope_t *slope)
vector3_t slopemom, axis;
angle_t ang;
if (mo->standingslope->flags & SL_NOPHYSICS)
return 0;
if (P_CanApplySlopeLaunch(mo, mo->standingslope) == false)
{
return false;
}
// If there's physics, time for launching.
// Doesn't kill the vertical momentum as much as P_SlopeLaunch does.
ang = slope->zangle + ANG15*((slope->zangle > 0) ? 1 : -1);
if (ang > ANGLE_90 && ang < ANGLE_180)
ang = ((slope->zangle > 0) ? ANGLE_90 : InvAngle(ANGLE_90)); // hard cap of directly upwards
{
// hard cap of directly upwards
ang = ((slope->zangle > 0) ? ANGLE_90 : InvAngle(ANGLE_90));
}
slopemom.x = mo->momx;
slopemom.y = mo->momy;
@ -1010,13 +1051,16 @@ fixed_t P_GetWallTransferMomZ(mobj_t *mo, pslope_t *slope)
void P_HandleSlopeLanding(mobj_t *thing, pslope_t *slope)
{
vector3_t mom; // Ditto.
if (slope->flags & SL_NOPHYSICS || (slope->normal.x == 0 && slope->normal.y == 0)) { // No physics, no need to make anything complicated.
if (P_CanApplySlopePhysics(thing, slope) == false) // No physics, no need to make anything complicated.
{
if (P_MobjFlip(thing)*(thing->momz) < 0) // falling, land on slope
{
thing->standingslope = slope;
P_SetPitchRollFromSlope(thing, slope);
thing->momz = -P_MobjFlip(thing);
}
return;
}
@ -1026,7 +1070,9 @@ void P_HandleSlopeLanding(mobj_t *thing, pslope_t *slope)
P_ReverseQuantizeMomentumToSlope(&mom, slope);
if (P_MobjFlip(thing)*mom.z < 0) { // falling, land on slope
if (P_MobjFlip(thing)*mom.z < 0)
{
// falling, land on slope
thing->momx = mom.x;
thing->momy = mom.y;
thing->standingslope = slope;
@ -1041,27 +1087,29 @@ void P_ButteredSlope(mobj_t *mo)
{
fixed_t thrust;
if (!mo->standingslope)
return;
if (mo->standingslope->flags & SL_NOPHYSICS)
return; // No physics, no butter.
if (mo->flags & (MF_NOCLIPHEIGHT|MF_NOGRAVITY))
return; // don't slide down slopes if you can't touch them or you're not affected by gravity
if (mo->player) {
// SRB2Kart - spindash negates slopes
if (K_PlayerEBrake(mo->player))
return;
if (P_CanApplySlopePhysics(mo, mo->standingslope) == false)
return; // No physics, no butter.
// Changed in kart to only not apply physics on very slight slopes (I think about 4 degree angles)
if (mo->player != NULL)
{
if (abs(mo->standingslope->zdelta) < FRACUNIT/21)
return; // Don't slide on non-steep slopes
{
// Don't slide on non-steep slopes.
// Changed in Ring Racers to only not apply physics on very slight slopes.
// (I think about 4 degree angles.)
return;
}
// This only means you can be stopped on slopes that aren't steeper than 45 degrees
if (abs(mo->standingslope->zdelta) < FRACUNIT/2 && !(mo->player->rmomx || mo->player->rmomy))
return; // Allow the player to stand still on slopes below a certain steepness
if (abs(mo->standingslope->zdelta) < FRACUNIT/2
&& !(mo->player->rmomx || mo->player->rmomy))
{
// Allow the player to stand still on slopes below a certain steepness.
// 45 degree angle steep, to be exact.
return;
}
}
thrust = FINESINE(mo->standingslope->zangle>>ANGLETOFINESHIFT) * 5 / 4 * (mo->eflags & MFE_VERTICALFLIP ? 1 : -1);

View file

@ -82,6 +82,8 @@ fixed_t P_GetFFloorBottomZAt(const ffloor_t *ffloor, fixed_t x, fixed_t y);
fixed_t P_GetLightZAt(const lightlist_t *light, fixed_t x, fixed_t y);
// Lots of physics-based bullshit
boolean P_CanApplySlopePhysics(mobj_t *mo, pslope_t *slope);
boolean P_CanApplySlopeLaunch(mobj_t *mo, pslope_t *slope);
void P_QuantizeMomentumToSlope(vector3_t *momentum, pslope_t *slope);
void P_ReverseQuantizeMomentumToSlope(vector3_t *momentum, pslope_t *slope);
void P_SlopeLaunch(mobj_t *mo);

View file

@ -721,7 +721,7 @@ void P_Ticker(boolean run)
G_WriteAllGhostTics();
if (cv_recordmultiplayerdemos.value && (demo.savemode == DSM_NOTSAVING || demo.savemode == DSM_WILLAUTOSAVE))
if (demo.savebutton && demo.savebutton + 3*TICRATE < leveltime && PlayerInputDown(1, gc_lookback))
if (demo.savebutton && demo.savebutton + 3*TICRATE < leveltime && G_PlayerInputDown(0, gc_y, 0))
demo.savemode = DSM_TITLEENTRY;
}
else if (demo.playback) // Use Ghost data for consistency checks.

View file

@ -183,7 +183,7 @@ fixed_t P_ReturnThrustY(mobj_t *mo, angle_t angle, fixed_t move)
boolean P_AutoPause(void)
{
// Don't pause even on menu-up or focus-lost in netgames or record attack
if (netgame || modeattacking || gamestate == GS_TITLESCREEN)
if (netgame || modeattacking || gamestate == GS_TITLESCREEN || gamestate == GS_MENU || con_startup)
return false;
return ((menuactive && !demo.playback) || ( window_notinfocus && cv_pauseifunfocused.value ));
@ -473,6 +473,7 @@ void P_ResetPlayer(player_t *player)
//player->drift = player->driftcharge = 0;
player->trickpanel = 0;
player->glanceDir = 0;
player->fastfall = 0;
}
//
@ -1099,7 +1100,7 @@ boolean P_IsMachineLocalPlayer(player_t *player)
return false;
}
for (i = 0; i <= r_splitscreen; i++)
for (i = 0; i <= splitscreen; i++)
{
if (player == &players[g_localplayers[i]])
return true;
@ -1905,17 +1906,27 @@ static void P_3dMovement(player_t *player)
}
if ((totalthrust.x || totalthrust.y)
&& player->mo->standingslope && (!(player->mo->standingslope->flags & SL_NOPHYSICS)) && abs(player->mo->standingslope->zdelta) > FRACUNIT/2) {
&& player->mo->standingslope != NULL
&& (!(player->mo->standingslope->flags & SL_NOPHYSICS))
&& abs(player->mo->standingslope->zdelta) > FRACUNIT/2)
{
// Factor thrust to slope, but only for the part pushing up it!
// The rest is unaffected.
angle_t thrustangle = R_PointToAngle2(0, 0, totalthrust.x, totalthrust.y)-player->mo->standingslope->xydirection;
angle_t thrustangle = R_PointToAngle2(0, 0, totalthrust.x, totalthrust.y) - player->mo->standingslope->xydirection;
if (player->mo->standingslope->zdelta < 0) { // Direction goes down, so thrustangle needs to face toward
if (thrustangle < ANGLE_90 || thrustangle > ANGLE_270) {
if (player->mo->standingslope->zdelta < 0)
{
// Direction goes down, so thrustangle needs to face toward
if (thrustangle < ANGLE_90 || thrustangle > ANGLE_270)
{
P_QuantizeMomentumToSlope(&totalthrust, player->mo->standingslope);
}
} else { // Direction goes up, so thrustangle needs to face away
if (thrustangle > ANGLE_90 && thrustangle < ANGLE_270) {
}
else
{
// Direction goes up, so thrustangle needs to face away
if (thrustangle > ANGLE_90 && thrustangle < ANGLE_270)
{
P_QuantizeMomentumToSlope(&totalthrust, player->mo->standingslope);
}
}
@ -2786,12 +2797,14 @@ void P_InitCameraCmd(void)
static ticcmd_t *P_CameraCmd(camera_t *cam)
{
/*
INT32 forward, axis; //i
// these ones used for multiple conditions
boolean turnleft, turnright, mouseaiming;
boolean invertmouse, lookaxis, usejoystick, kbl;
INT32 player_invert;
INT32 screen_invert;
*/
ticcmd_t *cmd = &cameracmd;
(void)cam;
@ -2799,6 +2812,7 @@ static ticcmd_t *P_CameraCmd(camera_t *cam)
if (!demo.playback)
return cmd; // empty cmd, no.
/*
kbl = democam.keyboardlook;
G_CopyTiccmd(cmd, I_BaseTiccmd(), 1); // empty, or external driver
@ -2843,7 +2857,7 @@ static ticcmd_t *P_CameraCmd(camera_t *cam)
cmd->turning -= (mousex * 8) * (encoremode ? -1 : 1);
axis = PlayerJoyAxis(1, AXISMOVE);
if (PlayerInputDown(1, gc_accelerate) || (usejoystick && axis > 0))
if (PlayerInputDown(1, gc_a) || (usejoystick && axis > 0))
cmd->buttons |= BT_ACCELERATE;
axis = PlayerJoyAxis(1, AXISBRAKE);
if (PlayerInputDown(1, gc_brake) || (usejoystick && axis > 0))
@ -2889,8 +2903,6 @@ static ticcmd_t *P_CameraCmd(camera_t *cam)
if (PlayerInputDown(1, gc_centerview)) // No need to put a spectator limit on this one though :V
cmd->aiming = 0;
mousex = mousey = mlooky = 0;
cmd->forwardmove += (SINT8)forward;
if (cmd->forwardmove > MAXPLMOVE)
@ -2904,6 +2916,7 @@ static ticcmd_t *P_CameraCmd(camera_t *cam)
cmd->turning = -KART_FULLTURN;
democam.keyboardlook = kbl;
*/
return cmd;
}

View file

@ -709,7 +709,7 @@ void R_RemoveMobjInterpolator(mobj_t *mobj)
if (interpolated_mobjs_len == 0) return;
for (i = 0; i < interpolated_mobjs_len - 1; i++)
for (i = 0; i < interpolated_mobjs_len; i++)
{
if (interpolated_mobjs[i] == mobj)
{

View file

@ -24,7 +24,7 @@
#include "p_local.h"
#include "keys.h"
#include "i_video.h"
#include "m_menu.h"
#include "k_menu.h"
#include "am_map.h"
#include "d_main.h"
#include "v_video.h"

View file

@ -22,7 +22,6 @@
#include "r_defs.h" // spritedef_t
/// Defaults
#define SKINNAMESIZE 16
#define SKINRIVALS 3
// should be all lowercase!! S_SKIN processing does a strlwr
#define DEFAULTSKIN "eggman"

View file

@ -18,7 +18,7 @@
#include "st_stuff.h"
#include "w_wad.h"
#include "z_zone.h"
#include "m_menu.h" // character select
#include "k_menu.h" // character select
#include "m_misc.h"
#include "info.h" // spr2names
#include "i_video.h" // rendermode

View file

@ -2505,9 +2505,9 @@ void GameDigiMusic_OnChange(void)
{
P_RestoreMusic(&players[consoleplayer]);
}
else if (S_MusicExists("_title"))
else if (S_MusicExists("menu"))
{
S_ChangeMusicInternal("_title", looptitle);
S_ChangeMusicInternal("menu", looptitle);
}
}
else

View file

@ -405,12 +405,6 @@ void SCR_Recalc(void)
// vid.recalc lasts only for the next refresh...
con_recalc = true;
am_recalc = true;
#ifdef HWRENDER
// Shoot! The screen texture was flushed!
if ((rendermode == render_opengl) && (gamestate == GS_INTERMISSION))
usebuffer = false;
#endif
}
// Check for screen cmd-line parms: to force a resolution.

View file

@ -186,6 +186,8 @@ static char returnWadPath[256];
#include "../r_main.h" // Frame interpolation/uncapped
#include "../r_fps.h"
#include "../k_menu.h"
#ifdef MAC_ALERT
#include "macosx/mac_alert.h"
#endif
@ -198,6 +200,48 @@ static char returnWadPath[256];
#include "../byteptr.h"
#endif
void I_StoreExJoystick(SDL_GameController *dev)
{
// ExJoystick is a massive hack to avoid needing to completely
// rewrite pretty much all of the controller support from scratch...
// Used in favor of most instances of SDL_GameControllerClose.
// If a joystick would've been discarded, then save it in an array,
// because we want it have it for the joystick input screen.
int index = 0;
if (dev == NULL)
{
// No joystick?
return;
}
index = SDL_JoystickInstanceID(SDL_GameControllerGetJoystick(dev));
if (index >= MAXGAMEPADS || index < 0)
{
// Not enough space to save this joystick, completely discard.
SDL_GameControllerClose(dev);
return;
}
if (ExJoystick[index] == dev)
{
// No need to do anything else.
return;
}
if (ExJoystick[index] != NULL)
{
// Discard joystick in the old slot.
SDL_GameControllerClose(ExJoystick[index]);
}
// Keep for safe-keeping.
ExJoystick[index] = dev;
}
/** \brief The JoyReset function
\param JoySet Joystick info to reset
@ -208,7 +252,7 @@ static void JoyReset(SDLJoyInfo_t *JoySet)
{
if (JoySet->dev)
{
SDL_JoystickClose(JoySet->dev);
I_StoreExJoystick(JoySet->dev);
}
JoySet->dev = NULL;
JoySet->oldjoy = -1;
@ -223,6 +267,7 @@ static INT32 joystick_started[MAXSPLITSCREENPLAYERS] = {0,0,0,0};
/** \brief SDL info about joystick 1
*/
SDLJoyInfo_t JoyInfo[MAXSPLITSCREENPLAYERS];
SDL_GameController *ExJoystick[MAXGAMEPADS];
SDL_bool consolevent = SDL_FALSE;
SDL_bool framebuffer = SDL_FALSE;
@ -536,7 +581,7 @@ static void I_StartupConsole(void)
void I_GetConsoleEvents(void)
{
// we use this when sending back commands
event_t ev = {0,0,0,0};
event_t ev = {0};
char key = 0;
ssize_t d;
@ -944,29 +989,16 @@ void I_JoyScale4(void)
JoyInfo[3].scale = Joystick[3].bGamepadStyle?1:cv_joyscale[1].value;
}
// Cheat to get the device index for a joystick handle
INT32 I_GetJoystickDeviceIndex(SDL_Joystick *dev)
// Cheat to get the device index for a game controller handle
INT32 I_GetJoystickDeviceIndex(SDL_GameController *dev)
{
INT32 i, count = SDL_NumJoysticks();
SDL_Joystick *joystick = NULL;
for (i = 0; dev && i < count; i++)
joystick = SDL_GameControllerGetJoystick(dev);
if (joystick)
{
SDL_Joystick *test = SDL_JoystickOpen(i);
if (test && test == dev)
return i;
else
{
UINT8 j;
for (j = 0; j < MAXSPLITSCREENPLAYERS; j++)
{
if (JoyInfo[j].dev == test)
break;
}
if (j == MAXSPLITSCREENPLAYERS)
SDL_JoystickClose(test);
}
return SDL_JoystickInstanceID(joystick);
}
return -1;
@ -981,6 +1013,7 @@ void I_UpdateJoystickDeviceIndex(UINT8 player)
if (JoyInfo[player].dev)
{
cv_usejoystick[player].value = I_GetJoystickDeviceIndex(JoyInfo[player].dev) + 1;
CONS_Printf("I_UpdateJoystickDeviceIndex: Device for %d set to %d\n", player, cv_usejoystick[player].value);
}
else
{
@ -1004,6 +1037,7 @@ void I_UpdateJoystickDeviceIndex(UINT8 player)
{
// We DID make it through the whole loop, so we can use this one!
cv_usejoystick[player].value = value;
CONS_Printf("I_UpdateJoystickDeviceIndex: Device for %d set to %d\n", player, cv_usejoystick[player].value);
break;
}
}
@ -1013,6 +1047,7 @@ void I_UpdateJoystickDeviceIndex(UINT8 player)
// We DID NOT make it through the whole loop, so we can't assign this joystick to anything.
// When you try your best, but you don't succeed...
cv_usejoystick[player].value = 0;
CONS_Printf("I_UpdateJoystickDeviceIndex: Device for %d set to %d\n", player, 0);
}
}
}
@ -1032,14 +1067,6 @@ void I_UpdateJoystickDeviceIndices(UINT8 excludePlayer)
}
}
/** \brief Joystick buttons states
*/
static UINT64 lastjoybuttons[MAXSPLITSCREENPLAYERS] = {0,0,0,0};
/** \brief Joystick hats state
*/
static UINT64 lastjoyhats[MAXSPLITSCREENPLAYERS] = {0,0,0,0};
/** \brief Shuts down joystick
\return void
*/
@ -1047,29 +1074,22 @@ void I_ShutdownJoystick(UINT8 index)
{
INT32 i;
event_t event;
event.type=ev_keyup;
event.device = I_GetJoystickDeviceIndex(JoyInfo[index].dev);
event.type = ev_keyup;
event.data2 = 0;
event.data3 = 0;
lastjoybuttons[index] = lastjoyhats[index] = 0;
// emulate the up of all joystick buttons
for (i=0;i<JOYBUTTONS;i++)
for (i = 0; i < JOYBUTTONS; i++)
{
event.data1=KEY_JOY1+i;
D_PostEvent(&event);
}
// emulate the up of all joystick hats
for (i=0;i<JOYHATS*4;i++)
{
event.data1=KEY_HAT1+i;
event.data1 = KEY_JOY1+i;
D_PostEvent(&event);
}
// reset joystick position
event.type = ev_joystick;
for (i=0;i<JOYAXISSET; i++)
for (i = 0; i < JOYAXES; i++)
{
event.data1 = i;
D_PostEvent(&event);
@ -1081,136 +1101,6 @@ void I_ShutdownJoystick(UINT8 index)
// don't shut down the subsystem here, because hotplugging
}
void I_GetJoystickEvents(UINT8 index)
{
static event_t event = {0,0,0,0};
INT32 i = 0;
UINT64 joyhats = 0;
#if 0
UINT64 joybuttons = 0;
Sint16 axisx, axisy;
#endif
if (!joystick_started[index]) return;
if (!JoyInfo[index].dev) //I_ShutdownJoystick(index);
return;
#if 0
//faB: look for as much buttons as g_input code supports,
// we don't use the others
for (i = JoyInfo[index].buttons - 1; i >= 0; i--)
{
joybuttons <<= 1;
if (SDL_JoystickGetButton(JoyInfo[index].dev,i))
joybuttons |= 1;
}
if (joybuttons != lastjoybuttons[index])
{
INT64 j = 1; // keep only bits that changed since last time
INT64 newbuttons = joybuttons ^ lastjoybuttons[index];
lastjoybuttons[index] = joybuttons;
for (i = 0; i < JOYBUTTONS; i++, j <<= 1)
{
if (newbuttons & j) // button changed state?
{
if (joybuttons & j)
event.type = ev_keydown;
else
event.type = ev_keyup;
event.data1 = KEY_JOY1 + i;
D_PostEvent(&event);
}
}
}
#endif
for (i = JoyInfo[index].hats - 1; i >= 0; i--)
{
Uint8 hat = SDL_JoystickGetHat(JoyInfo[index].dev, i);
if (hat & SDL_HAT_UP ) joyhats|=(UINT64)0x1<<(0 + 4*i);
if (hat & SDL_HAT_DOWN ) joyhats|=(UINT64)0x1<<(1 + 4*i);
if (hat & SDL_HAT_LEFT ) joyhats|=(UINT64)0x1<<(2 + 4*i);
if (hat & SDL_HAT_RIGHT) joyhats|=(UINT64)0x1<<(3 + 4*i);
}
if (joyhats != lastjoyhats[index])
{
INT64 j = 1; // keep only bits that changed since last time
INT64 newhats = joyhats ^ lastjoyhats[index];
lastjoyhats[index] = joyhats;
for (i = 0; i < JOYHATS*4; i++, j <<= 1)
{
if (newhats & j) // hat changed state?
{
if (joyhats & j)
event.type = ev_keydown;
else
event.type = ev_keyup;
event.data1 = KEY_HAT1 + i;
D_PostEvent(&event);
}
}
}
#if 0
// send joystick axis positions
event.type = ev_joystick;
for (i = JOYAXISSET - 1; i >= 0; i--)
{
event.data1 = i;
if (i*2 + 1 <= JoyInfo[index].axises)
axisx = SDL_JoystickGetAxis(JoyInfo[index].dev, i*2 + 0);
else axisx = 0;
if (i*2 + 2 <= JoyInfo[index].axises)
axisy = SDL_JoystickGetAxis(JoyInfo[index].dev, i*2 + 1);
else axisy = 0;
// -32768 to 32767
axisx = axisx/32;
axisy = axisy/32;
if (Joystick[index].bGamepadStyle)
{
// gamepad control type, on or off, live or die
if (axisx < -(JOYAXISRANGE/2))
event.data2 = -1;
else if (axisx > (JOYAXISRANGE/2))
event.data2 = 1;
else event.data2 = 0;
if (axisy < -(JOYAXISRANGE/2))
event.data3 = -1;
else if (axisy > (JOYAXISRANGE/2))
event.data3 = 1;
else event.data3 = 0;
}
else
{
axisx = JoyInfo[index].scale?((axisx/JoyInfo[index].scale)*JoyInfo[index].scale):axisx;
axisy = JoyInfo[index].scale?((axisy/JoyInfo[index].scale)*JoyInfo[index].scale):axisy;
#ifdef SDL_JDEADZONE
if (-SDL_JDEADZONE <= axisx && axisx <= SDL_JDEADZONE) axisx = 0;
if (-SDL_JDEADZONE <= axisy && axisy <= SDL_JDEADZONE) axisy = 0;
#endif
// analog control style , just send the raw data
event.data2 = axisx; // x axis
event.data3 = axisy; // y axis
}
D_PostEvent(&event);
}
#endif
}
/** \brief Open joystick handle
\param fname name of joystick
@ -1221,7 +1111,7 @@ void I_GetJoystickEvents(UINT8 index)
*/
static int joy_open(int playerIndex, int joyIndex)
{
SDL_Joystick *newdev = NULL;
SDL_GameController *newdev = NULL;
int num_joy = 0;
if (SDL_WasInit(SDL_INIT_JOYSTICK) == 0)
@ -1230,6 +1120,12 @@ static int joy_open(int playerIndex, int joyIndex)
return -1;
}
if (SDL_WasInit(SDL_INIT_GAMECONTROLLER) == 0)
{
CONS_Printf(M_GetText("Game Controller subsystem not started\n"));
return -1;
}
if (joyIndex <= 0)
return -1;
@ -1241,7 +1137,7 @@ static int joy_open(int playerIndex, int joyIndex)
return -1;
}
newdev = SDL_JoystickOpen(joyIndex-1);
newdev = SDL_GameControllerOpen(joyIndex-1);
// Handle the edge case where the device <-> joystick index assignment can change due to hotplugging
// This indexing is SDL's responsibility and there's not much we can do about it.
@ -1256,9 +1152,9 @@ static int joy_open(int playerIndex, int joyIndex)
if (JoyInfo[playerIndex].dev)
{
if (JoyInfo[playerIndex].dev == newdev // same device, nothing to do
|| (newdev == NULL && SDL_JoystickGetAttached(JoyInfo[playerIndex].dev))) // we failed, but already have a working device
|| (newdev == NULL && SDL_GameControllerGetAttached(JoyInfo[playerIndex].dev))) // we failed, but already have a working device
{
return JoyInfo[playerIndex].axises;
return SDL_CONTROLLER_AXIS_MAX;
}
// Else, we're changing devices, so send neutral joy events
@ -1275,29 +1171,12 @@ static int joy_open(int playerIndex, int joyIndex)
}
else
{
CONS_Debug(DBG_GAMELOGIC, M_GetText("Joystick%d: %s\n"), playerIndex+1, SDL_JoystickName(JoyInfo[playerIndex].dev));
CONS_Debug(DBG_GAMELOGIC, M_GetText("Joystick%d: %s\n"), playerIndex+1, SDL_GameControllerName(JoyInfo[playerIndex].dev));
JoyInfo[playerIndex].axises = SDL_JoystickNumAxes(JoyInfo[playerIndex].dev);
if (JoyInfo[playerIndex].axises > JOYAXISSET*2)
JoyInfo[playerIndex].axises = JOYAXISSET*2;
/*
if (joyaxes<2)
{
I_OutputMsg("Not enought axes?\n");
return 0;
}
*/
JoyInfo[playerIndex].buttons = SDL_JoystickNumButtons(JoyInfo[playerIndex].dev);
if (JoyInfo[playerIndex].buttons > JOYBUTTONS)
JoyInfo[playerIndex].buttons = JOYBUTTONS;
JoyInfo[playerIndex].hats = SDL_JoystickNumHats(JoyInfo[playerIndex].dev);
if (JoyInfo[playerIndex].hats > JOYHATS)
JoyInfo[playerIndex].hats = JOYHATS;
JoyInfo[playerIndex].balls = SDL_JoystickNumBalls(JoyInfo[playerIndex].dev);
JoyInfo[playerIndex].axises = SDL_CONTROLLER_AXIS_MAX;
JoyInfo[playerIndex].buttons = SDL_CONTROLLER_BUTTON_MAX;
JoyInfo[playerIndex].hats = 1;
JoyInfo[playerIndex].balls = 0;
//JoyInfo[playerIndex].bGamepadStyle = !stricmp(SDL_JoystickName(JoyInfo[playerIndex].dev), "pad");
@ -1310,7 +1189,7 @@ static int joy_open(int playerIndex, int joyIndex)
//
void I_InitJoystick(UINT8 index)
{
SDL_Joystick *newjoy = NULL;
SDL_GameController *newcontroller = NULL;
UINT8 i;
//I_ShutdownJoystick();
@ -1335,23 +1214,33 @@ void I_InitJoystick(UINT8 index)
}
}
if (SDL_WasInit(SDL_INIT_GAMECONTROLLER) == 0)
{
if (SDL_InitSubSystem(SDL_INIT_GAMECONTROLLER) == -1)
{
CONS_Printf(M_GetText("Couldn't initialize gamepads: %s\n"), SDL_GetError());
return;
}
}
if (cv_usejoystick[index].value)
newjoy = SDL_JoystickOpen(cv_usejoystick[index].value-1);
newcontroller = SDL_GameControllerOpen(cv_usejoystick[index].value-1);
for (i = 0; i < MAXSPLITSCREENPLAYERS; i++)
{
if (i == index)
continue;
if (JoyInfo[i].dev == newjoy)
if (JoyInfo[i].dev == newcontroller)
break;
}
if (newjoy && i < MAXSPLITSCREENPLAYERS) // don't override an active device
if (newcontroller && i < MAXSPLITSCREENPLAYERS) // don't override an active device
{
cv_usejoystick[index].value = I_GetJoystickDeviceIndex(JoyInfo[index].dev) + 1;
CONS_Printf("I_InitJoystick: Device for %d set to %d\n", index, cv_usejoystick[index].value);
}
else if (newjoy && joy_open(index, cv_usejoystick[index].value) != -1)
else if (newcontroller && joy_open(index, cv_usejoystick[index].value) != -1)
{
// SDL's device indexes are unstable, so cv_usejoystick may not match
// the actual device index. So let's cheat a bit and find the device's current index.
@ -1363,19 +1252,20 @@ void I_InitJoystick(UINT8 index)
if (JoyInfo[index].oldjoy)
I_ShutdownJoystick(index);
cv_usejoystick[index].value = 0;
CONS_Printf("I_InitJoystick: Device for %d set to %d\n", index, cv_usejoystick[index].value);
joystick_started[index] = 0;
}
for (i = 0; i < MAXSPLITSCREENPLAYERS; i++)
{
if (JoyInfo[i].dev == newjoy)
if (JoyInfo[i].dev == newcontroller)
break;
}
if (i == MAXSPLITSCREENPLAYERS)
{
// Joystick didn't end up being used
SDL_JoystickClose(newjoy);
I_StoreExJoystick(newcontroller);
}
}
@ -1410,6 +1300,13 @@ static void I_ShutdownInput(void)
for (i = 0; i < MAXSPLITSCREENPLAYERS; i++)
I_ShutdownJoystick(i);
if (SDL_WasInit(SDL_INIT_GAMECONTROLLER) == SDL_INIT_GAMECONTROLLER)
{
CONS_Printf("Shutting down gamecontroller system\n");
SDL_QuitSubSystem(SDL_INIT_GAMECONTROLLER);
I_OutputMsg("I_Joystick: SDL's Game Controller system has been shutdown\n");
}
if (SDL_WasInit(SDL_INIT_JOYSTICK) == SDL_INIT_JOYSTICK)
{
CONS_Printf("Shutting down joy system\n");
@ -1838,6 +1735,7 @@ void I_Quit(void)
M_SaveConfig(NULL); //save game config, cvars..
#ifndef NONET
D_SaveBan(); // save the ban list
M_SaveJoinedIPs();
#endif
// Make sure you lose points for ALT-F4

View file

@ -63,7 +63,7 @@
#include "../i_system.h"
#include "../v_video.h"
#include "../m_argv.h"
#include "../m_menu.h"
#include "../k_menu.h"
#include "../d_main.h"
#include "../s_sound.h"
#include "../i_sound.h" // midi pause/unpause
@ -372,7 +372,7 @@ static boolean IgnoreMouse(void)
if (cv_alwaysgrabmouse.value)
return false;
if (menuactive)
return !M_MouseNeeded();
return false; // return !M_MouseNeeded();
if (paused || con_destlines || chat_on)
return true;
if (gamestate != GS_LEVEL && gamestate != GS_INTERMISSION &&
@ -526,95 +526,31 @@ static inline void SDLJoyRemap(event_t *event)
(void)event;
}
static INT32 SDLJoyAxis(const Sint16 axis, evtype_t which)
static INT32 SDLJoyAxis(const Sint16 axis, UINT8 pid)
{
// -32768 to 32767
INT32 raxis = axis/32;
if (which == ev_joystick)
INT32 raxis = axis / 32;
if (Joystick[pid].bGamepadStyle)
{
if (Joystick[0].bGamepadStyle)
{
// gamepad control type, on or off, live or die
if (raxis < -(JOYAXISRANGE/2))
raxis = -1;
else if (raxis > (JOYAXISRANGE/2))
raxis = 1;
else
raxis = 0;
}
// gamepad control type, on or off, live or die
if (raxis < -(JOYAXISRANGE/2))
raxis = -1;
else if (raxis > (JOYAXISRANGE/2))
raxis = 1;
else
{
raxis = JoyInfo[0].scale!=1?((raxis/JoyInfo[0].scale)*JoyInfo[0].scale):raxis;
raxis = 0;
}
else
{
raxis = (abs(JoyInfo[pid].scale) > 1) ? ((raxis / JoyInfo[pid].scale) * JoyInfo[pid].scale) : raxis;
#ifdef SDL_JDEADZONE
if (-SDL_JDEADZONE <= raxis && raxis <= SDL_JDEADZONE)
raxis = 0;
if (-SDL_JDEADZONE <= raxis && raxis <= SDL_JDEADZONE)
raxis = 0;
#endif
}
}
else if (which == ev_joystick2)
{
if (Joystick[1].bGamepadStyle)
{
// gamepad control type, on or off, live or die
if (raxis < -(JOYAXISRANGE/2))
raxis = -1;
else if (raxis > (JOYAXISRANGE/2))
raxis = 1;
else raxis = 0;
}
else
{
raxis = JoyInfo[1].scale!=1?((raxis/JoyInfo[1].scale)*JoyInfo[1].scale):raxis;
#ifdef SDL_JDEADZONE
if (-SDL_JDEADZONE <= raxis && raxis <= SDL_JDEADZONE)
raxis = 0;
#endif
}
}
else if (which == ev_joystick3)
{
if (Joystick[2].bGamepadStyle)
{
// gamepad control type, on or off, live or die
if (raxis < -(JOYAXISRANGE/2))
raxis = -1;
else if (raxis > (JOYAXISRANGE/2))
raxis = 1;
else raxis = 0;
}
else
{
raxis = JoyInfo[2].scale!=1?((raxis/JoyInfo[2].scale)*JoyInfo[2].scale):raxis;
#ifdef SDL_JDEADZONE
if (-SDL_JDEADZONE <= raxis && raxis <= SDL_JDEADZONE)
raxis = 0;
#endif
}
}
else if (which == ev_joystick4)
{
if (Joystick[3].bGamepadStyle)
{
// gamepad control type, on or off, live or die
if (raxis < -(JOYAXISRANGE/2))
raxis = -1;
else if (raxis > (JOYAXISRANGE/2))
raxis = 1;
else raxis = 0;
}
else
{
raxis = JoyInfo[3].scale!=1?((raxis/JoyInfo[3].scale)*JoyInfo[3].scale):raxis;
#ifdef SDL_JDEADZONE
if (-SDL_JDEADZONE <= raxis && raxis <= SDL_JDEADZONE)
raxis = 0;
#endif
}
}
return raxis;
}
@ -679,7 +615,8 @@ static void Impl_HandleWindowEvent(SDL_WindowEvent evt)
{
SDLforceUngrabMouse();
}
memset(gamekeydown, 0, NUMKEYS); // TODO this is a scary memset
memset(gamekeydown, 0, sizeof(gamekeydown)); // TODO this is a scary memset
memset(deviceResponding, false, sizeof (deviceResponding));
if (MOUSE_MENU)
{
@ -692,6 +629,9 @@ static void Impl_HandleWindowEvent(SDL_WindowEvent evt)
static void Impl_HandleKeyboardEvent(SDL_KeyboardEvent evt, Uint32 type)
{
event_t event;
event.device = 0;
if (type == SDL_KEYUP)
{
event.type = ev_keyup;
@ -773,6 +713,8 @@ static void Impl_HandleMouseButtonEvent(SDL_MouseButtonEvent evt, Uint32 type)
/// \todo inputEvent.button.which
if (USE_MOUSEINPUT)
{
event.device = 0;
if (type == SDL_MOUSEBUTTONUP)
{
event.type = ev_keyup;
@ -805,6 +747,8 @@ static void Impl_HandleMouseWheelEvent(SDL_MouseWheelEvent evt)
SDL_memset(&event, 0, sizeof(event_t));
event.device = 0;
if (evt.y > 0)
{
event.data1 = KEY_MOUSEWHEELUP;
@ -826,138 +770,87 @@ static void Impl_HandleMouseWheelEvent(SDL_MouseWheelEvent evt)
}
}
static void Impl_HandleJoystickAxisEvent(SDL_JoyAxisEvent evt)
static void Impl_HandleControllerAxisEvent(SDL_ControllerAxisEvent evt)
{
event_t event;
SDL_JoystickID joyid[MAXSPLITSCREENPLAYERS];
UINT8 i;
INT32 value;
// Determine the Joystick IDs for each current open joystick
for (i = 0; i < MAXSPLITSCREENPLAYERS; i++)
joyid[i] = SDL_JoystickInstanceID(JoyInfo[i].dev);
event.type = ev_joystick;
event.device = 1 + evt.which;
if (event.device == INT32_MAX)
{
return;
}
evt.axis++;
event.data1 = event.data2 = event.data3 = INT32_MAX;
if (evt.which == joyid[0])
{
event.type = ev_joystick;
}
else if (evt.which == joyid[1])
{
event.type = ev_joystick2;
}
else if (evt.which == joyid[2])
{
event.type = ev_joystick3;
}
else if (evt.which == joyid[3])
{
event.type = ev_joystick4;
}
else return;
//axis
if (evt.axis > JOYAXISSET*2)
return;
//vaule
if (evt.axis%2)
if (evt.axis > 2 * JOYAXISSETS)
{
event.data1 = evt.axis / 2;
event.data2 = SDLJoyAxis(evt.value, event.type);
return;
}
//vaule[sic]
value = SDLJoyAxis(evt.value, evt.which);
if (evt.axis & 1)
{
event.data3 = value;
}
else
{
evt.axis--;
event.data1 = evt.axis / 2;
event.data3 = SDLJoyAxis(evt.value, event.type);
event.data2 = value;
}
event.data1 = evt.axis / 2;
D_PostEvent(&event);
}
#if 0
static void Impl_HandleJoystickHatEvent(SDL_JoyHatEvent evt)
static void Impl_HandleControllerButtonEvent(SDL_ControllerButtonEvent evt, Uint32 type)
{
event_t event;
SDL_JoystickID joyid[MAXSPLITSCREENPLAYERS];
UINT8 i;
// Determine the Joystick IDs for each current open joystick
for (i = 0; i < MAXSPLITSCREENPLAYERS; i++)
joyid[i] = SDL_JoystickInstanceID(JoyInfo[i].dev);
event.device = 1 + evt.which;
if (evt.hat >= JOYHATS)
return; // ignore hats with too high an index
if (event.device == INT32_MAX)
{
return;
}
if (evt.which == joyid[0])
{
event.data1 = KEY_HAT1 + (evt.hat*4);
}
else if (evt.which == joyid[1])
{
event.data1 = KEY_2HAT1 + (evt.hat*4);
}
else if (evt.which == joyid[2])
{
event.data1 = KEY_3HAT1 + (evt.hat*4);
}
else if (evt.which == joyid[3])
{
event.data1 = KEY_4HAT1 + (evt.hat*4);
}
else return;
event.data1 = KEY_JOY1;
// NOTE: UNFINISHED
}
#endif
static void Impl_HandleJoystickButtonEvent(SDL_JoyButtonEvent evt, Uint32 type)
{
event_t event;
SDL_JoystickID joyid[MAXSPLITSCREENPLAYERS];
UINT8 i;
// Determine the Joystick IDs for each current open joystick
for (i = 0; i < MAXSPLITSCREENPLAYERS; i++)
joyid[i] = SDL_JoystickInstanceID(JoyInfo[i].dev);
if (evt.which == joyid[0])
{
event.data1 = KEY_JOY1;
}
else if (evt.which == joyid[1])
{
event.data1 = KEY_2JOY1;
}
else if (evt.which == joyid[2])
{
event.data1 = KEY_3JOY1;
}
else if (evt.which == joyid[3])
{
event.data1 = KEY_4JOY1;
}
else return;
if (type == SDL_JOYBUTTONUP)
if (type == SDL_CONTROLLERBUTTONUP)
{
event.type = ev_keyup;
}
else if (type == SDL_JOYBUTTONDOWN)
else if (type == SDL_CONTROLLERBUTTONDOWN)
{
event.type = ev_keydown;
}
else return;
else
{
return;
}
if (evt.button < JOYBUTTONS)
{
event.data1 += evt.button;
}
else return;
else
{
return;
}
SDLJoyRemap(&event);
if (event.type != ev_console) D_PostEvent(&event);
if (event.type != ev_console)
{
D_PostEvent(&event);
}
}
void I_GetEvent(void)
{
SDL_Event evt;
@ -998,28 +891,23 @@ void I_GetEvent(void)
case SDL_MOUSEWHEEL:
Impl_HandleMouseWheelEvent(evt.wheel);
break;
case SDL_JOYAXISMOTION:
Impl_HandleJoystickAxisEvent(evt.jaxis);
case SDL_CONTROLLERAXISMOTION:
Impl_HandleControllerAxisEvent(evt.caxis);
break;
#if 0
case SDL_JOYHATMOTION:
Impl_HandleJoystickHatEvent(evt.jhat)
break;
#endif
case SDL_JOYBUTTONUP:
case SDL_JOYBUTTONDOWN:
Impl_HandleJoystickButtonEvent(evt.jbutton, evt.type);
case SDL_CONTROLLERBUTTONUP:
case SDL_CONTROLLERBUTTONDOWN:
Impl_HandleControllerButtonEvent(evt.cbutton, evt.type);
break;
////////////////////////////////////////////////////////////
case SDL_JOYDEVICEADDED:
case SDL_CONTROLLERDEVICEADDED:
{
// OH BOY are you in for a good time! #abominationstation
SDL_Joystick *newjoy = SDL_JoystickOpen(evt.jdevice.which);
SDL_GameController *newcontroller = SDL_GameControllerOpen(evt.cdevice.which);
CONS_Debug(DBG_GAMELOGIC, "Joystick device index %d added\n", evt.jdevice.which + 1);
CONS_Debug(DBG_GAMELOGIC, "Controller device index %d added\n", evt.cdevice.which + 1);
////////////////////////////////////////////////////////////
// Because SDL's device index is unstable, we're going to cheat here a bit:
@ -1034,7 +922,7 @@ void I_GetEvent(void)
for (i = 0; i < MAXSPLITSCREENPLAYERS; i++)
{
if (newjoy && (!JoyInfo[i].dev || !SDL_JoystickGetAttached(JoyInfo[i].dev)))
if (newcontroller && (!JoyInfo[i].dev || !SDL_GameControllerGetAttached(JoyInfo[i].dev)))
{
UINT8 j;
@ -1043,14 +931,14 @@ void I_GetEvent(void)
if (i == j)
continue;
if (JoyInfo[j].dev == newjoy)
if (JoyInfo[j].dev == newcontroller)
break;
}
if (j == MAXSPLITSCREENPLAYERS)
{
// ensures we aren't overriding a currently active device
cv_usejoystick[i].value = evt.jdevice.which + 1;
cv_usejoystick[i].value = evt.cdevice.which + 1;
I_UpdateJoystickDeviceIndices(0);
}
}
@ -1084,27 +972,29 @@ void I_GetEvent(void)
for (i = 0; i < MAXSPLITSCREENPLAYERS; i++)
CONS_Debug(DBG_GAMELOGIC, "Joystick%d device index: %d\n", i+1, JoyInfo[i].oldjoy);
#if 0
// update the menu
if (currentMenu == &OP_JoystickSetDef)
M_SetupJoystickMenu(0);
#endif
for (i = 0; i < MAXSPLITSCREENPLAYERS; i++)
{
if (JoyInfo[i].dev == newjoy)
if (JoyInfo[i].dev == newcontroller)
break;
}
if (i == MAXSPLITSCREENPLAYERS)
SDL_JoystickClose(newjoy);
I_StoreExJoystick(newcontroller);
}
break;
////////////////////////////////////////////////////////////
case SDL_JOYDEVICEREMOVED:
case SDL_CONTROLLERDEVICEREMOVED:
for (i = 0; i < MAXSPLITSCREENPLAYERS; i++)
{
if (JoyInfo[i].dev && !SDL_JoystickGetAttached(JoyInfo[i].dev))
if (JoyInfo[i].dev && !SDL_GameControllerGetAttached(JoyInfo[i].dev))
{
CONS_Debug(DBG_GAMELOGIC, "Joystick%d removed, device index: %d\n", i+1, JoyInfo[i].oldjoy);
I_ShutdownJoystick(i);
@ -1144,9 +1034,11 @@ void I_GetEvent(void)
for (i = 0; i < MAXSPLITSCREENPLAYERS; i++)
CONS_Debug(DBG_GAMELOGIC, "Joystick%d device index: %d\n", i+1, JoyInfo[i].oldjoy);
#if 0
// update the menu
if (currentMenu == &OP_JoystickSetDef)
M_SetupJoystickMenu(0);
#endif
break;
case SDL_QUIT:
LUAh_GameQuit(true);
@ -1171,7 +1063,10 @@ void I_GetEvent(void)
// In order to make wheels act like buttons, we have to set their state to Up.
// This is because wheel messages don't have an up/down state.
gamekeydown[KEY_MOUSEWHEELDOWN] = gamekeydown[KEY_MOUSEWHEELUP] = 0;
for (i = 0; i < MAXSPLITSCREENPLAYERS; i++)
{
gamekeydown[i][KEY_MOUSEWHEELDOWN] = gamekeydown[i][KEY_MOUSEWHEELUP] = 0;
}
}
void I_StartupMouse(void)
@ -1199,16 +1094,12 @@ void I_StartupMouse(void)
void I_OsPolling(void)
{
SDL_Keymod mod;
UINT8 i;
if (consolevent)
I_GetConsoleEvents();
if (SDL_WasInit(SDL_INIT_JOYSTICK) == SDL_INIT_JOYSTICK)
{
SDL_JoystickUpdate();
for (i = 0; i < MAXSPLITSCREENPLAYERS; i++)
I_GetJoystickEvents(i);
}
if (SDL_WasInit(SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER) == (SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER))
SDL_GameControllerUpdate();
I_GetEvent();
@ -1583,15 +1474,22 @@ static SDL_bool Impl_CreateContext(void)
int flags = 0; // Use this to set SDL_RENDERER_* flags now
if (usesdl2soft)
flags |= SDL_RENDERER_SOFTWARE;
#if 0
// This shit is BROKEN.
// - The version of SDL we're using cannot toggle VSync at runtime. We'll need a new SDL version implemented to have this work properly.
// - cv_vidwait is initialized before config is loaded, so it's forced to default value at runtime, and forced off when switching. The config loading code would need restructured.
// - With both this & frame interpolation on, I_FinishUpdate takes x10 longer. At this point, it is simpler to use a standard FPS cap.
// So you can probably guess why I'm kinda over this, I'm just disabling it.
else if (cv_vidwait.value)
flags |= SDL_RENDERER_PRESENTVSYNC;
#endif
// 3 August 2022
// Possibly a Windows 11 issue; the default
// "direct3d" driver (D3D9) causes Drmingw exchndl
// to not write RPT files. Every other driver
// seems fine.
SDL_SetHint(SDL_HINT_RENDER_DRIVER, "direct3d11");
SDL_SetHint(SDL_HINT_RENDER_DRIVER, "opengl");
if (!renderer)
renderer = SDL_CreateRenderer(window, -1, flags);

View file

@ -41,8 +41,8 @@ extern SDL_bool framebuffer;
*/
typedef struct SDLJoyInfo_s
{
/// Joystick handle
SDL_Joystick *dev;
/// Controller handle
SDL_GameController *dev;
/// number of old joystick
int oldjoy;
/// number of axies
@ -58,9 +58,12 @@ typedef struct SDLJoyInfo_s
} SDLJoyInfo_t;
/** \brief SDL info about joysticks
/** \brief SDL info about controllers
*/
extern SDLJoyInfo_t JoyInfo[MAXSPLITSCREENPLAYERS];
extern SDL_GameController *ExJoystick[MAXGAMEPADS];
void I_StoreExJoystick(SDL_GameController *dev);
/** \brief joystick axis deadzone
*/
@ -72,8 +75,8 @@ void I_GetConsoleEvents(void);
// So we can call this from i_video event loop
void I_ShutdownJoystick(UINT8 index);
// Cheat to get the device index for a joystick handle
INT32 I_GetJoystickDeviceIndex(SDL_Joystick *dev);
// Cheat to get the device index for a game controller handle
INT32 I_GetJoystickDeviceIndex(SDL_GameController *dev);
// Quick thing to make SDL_JOYDEVICEADDED events less of an abomination
void I_UpdateJoystickDeviceIndex(UINT8 player);

View file

@ -1110,7 +1110,9 @@ sfxinfo_t S_sfx[NUMSFX] =
{"kdtrg3", false, 64, 80, -1, NULL, 0, -1, -1, LUMPERROR, ""}, // High energy, SF_X2AWAYSOUND|SF_X8AWAYSOUND
// SRB2kart - Grow/invinc clash
{"parry", false, 64, 16, -1, NULL, 0, -1, -1, LUMPERROR, ""}, // SF_X8AWAYSOUND
{"parry", false, 64, 16, -1, NULL, 0, -1, -1, LUMPERROR, ""}, // SF_X8AWAYSOUND
{"ffbonc", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""},
// SRB2Kart - Engine sounds
// Engine class A

View file

@ -1176,6 +1176,9 @@ typedef enum
// SRB2Kart - Powerup clash SFX
sfx_parry,
// Fast fall bounce
sfx_ffbonc,
// Next up: UNIQUE ENGINE SOUNDS! Hoooooo boy...
// Engine class A - Low Speed, Low Weight
sfx_krta00,

View file

@ -26,7 +26,7 @@
#include "console.h"
#include "s_sound.h"
#include "i_system.h"
#include "m_menu.h"
#include "k_menu.h"
#include "m_cheat.h"
#include "m_misc.h" // moviemode
#include "m_anigif.h" // cv_gif_downscale
@ -1057,7 +1057,7 @@ static void ST_overlayDrawer(void)
else if (G_GametypeHasTeams())
itemtxt = M_GetText("Item - Join Team");
if (cv_ingamecap.value)
if (cv_maxplayers.value)
{
UINT8 numingame = 0;
UINT8 i;
@ -1066,7 +1066,7 @@ static void ST_overlayDrawer(void)
if (playeringame[i] && !players[i].spectator)
numingame++;
itemtxt = va("%s (%s: %d)", itemtxt, M_GetText("Slots left"), max(0, cv_ingamecap.value - numingame));
itemtxt = va("%s (%s: %d)", itemtxt, M_GetText("Slots left"), max(0, cv_maxplayers.value - numingame));
}
// SRB2kart: changed positions & text
@ -1088,11 +1088,11 @@ static void ST_overlayDrawer(void)
void ST_DrawDemoTitleEntry(void)
{
static UINT8 skullAnimCounter = 0;
static UINT8 anim = 0;
char *nametodraw;
skullAnimCounter++;
skullAnimCounter %= 8;
anim++;
anim %= 8;
nametodraw = demo.titlename;
while (V_StringWidth(nametodraw, 0) > MAXSTRINGLENGTH*8 - 8)
@ -1102,7 +1102,7 @@ void ST_DrawDemoTitleEntry(void)
#define y (BASEVIDHEIGHT/2)
M_DrawTextBox(x, y + 4, MAXSTRINGLENGTH, 1);
V_DrawString(x + 8, y + 12, V_ALLOWLOWERCASE, nametodraw);
if (skullAnimCounter < 4)
if (anim < 4)
V_DrawCharacter(x + 8 + V_StringWidth(nametodraw, 0), y + 12,
'_' | 0x80, false);

View file

@ -1966,6 +1966,48 @@ static inline fixed_t BunchedCharacterDim(
return 0;
}
static inline fixed_t GamemodeCharacterDim(
fixed_t scale,
fixed_t chw,
INT32 hchw,
INT32 dupx,
fixed_t * cwp)
{
(void)chw;
(void)hchw;
(void)dupx;
(*cwp) = FixedMul (max (1, (*cwp) - 2) << FRACBITS, scale);
return 0;
}
static inline fixed_t FileCharacterDim(
fixed_t scale,
fixed_t chw,
INT32 hchw,
INT32 dupx,
fixed_t * cwp)
{
(void)chw;
(void)hchw;
(void)dupx;
(*cwp) = FixedMul (max (1, (*cwp) - 3) << FRACBITS, scale);
return 0;
}
static inline fixed_t LSTitleCharacterDim(
fixed_t scale,
fixed_t chw,
INT32 hchw,
INT32 dupx,
fixed_t * cwp)
{
(void)chw;
(void)hchw;
(void)dupx;
(*cwp) = FixedMul (max (1, (*cwp) - 4) << FRACBITS, scale);
return 0;
}
void V_DrawStringScaled(
fixed_t x,
fixed_t y,
@ -1973,6 +2015,7 @@ void V_DrawStringScaled(
fixed_t spacescale,
fixed_t lfscale,
INT32 flags,
const UINT8 *colormap,
int fontno,
const char *s)
{
@ -1993,8 +2036,6 @@ void V_DrawStringScaled(
boolean uppercase;
boolean notcolored;
const UINT8 *colormap;
fixed_t cx, cy;
fixed_t cxoff;
@ -2006,9 +2047,13 @@ void V_DrawStringScaled(
int c;
uppercase = !( flags & V_ALLOWLOWERCASE );
flags &= ~(V_FLIP);/* These two (V_ALLOWLOWERCASE) share a bit. */
flags &= ~(V_FLIP);/* These two (V_ALLOWLOWERCASE) share a bit. */
if (colormap == NULL)
{
colormap = V_GetStringColormap(( flags & V_CHARCOLORMASK ));
}
colormap = V_GetStringColormap(( flags & V_CHARCOLORMASK ));
notcolored = !colormap;
font = &fontv[fontno];
@ -2053,6 +2098,12 @@ void V_DrawStringScaled(
spacewidth = 3;*/
}
break;
case LT_FONT:
spacew = 12;
break;
case CRED_FONT:
spacew = 16;
break;
case KART_FONT:
spacew = 12;
switch (spacing)
@ -2067,13 +2118,18 @@ void V_DrawStringScaled(
spacew = 6;
}
break;
case LT_FONT:
spacew = 12;
case GM_FONT:
spacew = 6;
break;
case CRED_FONT:
case FILE_FONT:
spacew = 0;
break;
case LSHI_FONT:
case LSLOW_FONT:
spacew = 16;
break;
}
switch (fontno)
{
default:
@ -2084,8 +2140,18 @@ void V_DrawStringScaled(
break;
case LT_FONT:
case CRED_FONT:
case FILE_FONT:
lfh = 12;
break;
case GM_FONT:
lfh = 32;
break;
case LSHI_FONT:
lfh = 56;
break;
case LSLOW_FONT:
lfh = 38;
break;
}
hchw = chw >> 1;
@ -2130,25 +2196,45 @@ void V_DrawStringScaled(
right <<= FRACBITS;
bot = vid.height << FRACBITS;
if (fontno == TINY_FONT)
switch (fontno)
{
if (chw)
dim_fn = FixedCharacterDim;
else
{
/* Reuse this flag for the alternate bunched-up spacing. */
if (( flags & V_6WIDTHSPACE ))
dim_fn = BunchedCharacterDim;
default:
if (chw)
dim_fn = CenteredCharacterDim;
else
dim_fn = VariableCharacterDim;
}
}
else
{
if (chw)
dim_fn = CenteredCharacterDim;
else
dim_fn = VariableCharacterDim;
break;
case TINY_FONT:
if (chw)
dim_fn = FixedCharacterDim;
else
{
/* Reuse this flag for the alternate bunched-up spacing. */
if (( flags & V_6WIDTHSPACE ))
dim_fn = BunchedCharacterDim;
else
dim_fn = VariableCharacterDim;
}
break;
case GM_FONT:
if (chw)
dim_fn = FixedCharacterDim;
else
dim_fn = GamemodeCharacterDim;
break;
case FILE_FONT:
if (chw)
dim_fn = FixedCharacterDim;
else
dim_fn = FileCharacterDim;
break;
case LSHI_FONT:
case LSLOW_FONT:
if (chw)
dim_fn = FixedCharacterDim;
else
dim_fn = LSTitleCharacterDim;
break;
}
cx = x;
@ -2194,7 +2280,237 @@ void V_DrawStringScaled(
}
}
}
//
fixed_t V_StringScaledWidth(
fixed_t scale,
fixed_t spacescale,
fixed_t lfscale,
INT32 flags,
int fontno,
const char *s)
{
fixed_t chw;
INT32 hchw;/* half-width for centering */
fixed_t spacew;
fixed_t lfh;
INT32 dupx;
fixed_t (*dim_fn)(fixed_t,fixed_t,INT32,INT32,fixed_t *);
font_t *font;
boolean uppercase;
fixed_t cx, cy;
fixed_t cw;
INT32 spacing;
int c;
fixed_t fullwidth = 0;
uppercase = !( flags & V_ALLOWLOWERCASE );
flags &= ~(V_FLIP);/* These two (V_ALLOWLOWERCASE) share a bit. */
font = &fontv[fontno];
chw = 0;
spacing = ( flags & V_SPACINGMASK );
/*
Hardcoded until a better system can be implemented
for determining how fonts space.
*/
switch (fontno)
{
default:
case HU_FONT:
spacew = 4;
switch (spacing)
{
case V_MONOSPACE:
spacew = 8;
/* FALLTHRU */
case V_OLDSPACING:
chw = 8;
break;
case V_6WIDTHSPACE:
spacew = 6;
}
break;
case TINY_FONT:
spacew = 2;
switch (spacing)
{
case V_MONOSPACE:
spacew = 5;
/* FALLTHRU */
case V_OLDSPACING:
chw = 5;
break;
// Out of video flags, so we're reusing this for alternate charwidth instead
/*case V_6WIDTHSPACE:
spacewidth = 3;*/
}
break;
case LT_FONT:
spacew = 12;
break;
case CRED_FONT:
spacew = 16;
break;
case KART_FONT:
spacew = 12;
switch (spacing)
{
case V_MONOSPACE:
spacew = 12;
/* FALLTHRU */
case V_OLDSPACING:
chw = 12;
break;
case V_6WIDTHSPACE:
spacew = 6;
}
break;
case GM_FONT:
case FILE_FONT:
spacew = 0;
break;
case LSHI_FONT:
case LSLOW_FONT:
spacew = 16;
break;
}
switch (fontno)
{
default:
case HU_FONT:
case TINY_FONT:
case KART_FONT:
lfh = 12;
break;
case LT_FONT:
case CRED_FONT:
case FILE_FONT:
lfh = 12;
break;
case GM_FONT:
lfh = 32;
break;
case LSHI_FONT:
lfh = 56;
break;
case LSLOW_FONT:
lfh = 38;
break;
}
hchw = chw >> 1;
chw <<= FRACBITS;
spacew <<= FRACBITS;
#define Mul( id, scale ) ( id = FixedMul (scale, id) )
Mul (chw, scale);
Mul (spacew, scale);
Mul (lfh, scale);
Mul (spacew, spacescale);
Mul (lfh, lfscale);
#undef Mul
if (( flags & V_NOSCALESTART ))
{
dupx = vid.dupx;
hchw *= dupx;
chw *= dupx;
spacew *= dupx;
lfh *= vid.dupy;
}
else
{
dupx = 1;
}
switch (fontno)
{
default:
if (chw)
dim_fn = CenteredCharacterDim;
else
dim_fn = VariableCharacterDim;
break;
case TINY_FONT:
if (chw)
dim_fn = FixedCharacterDim;
else
{
/* Reuse this flag for the alternate bunched-up spacing. */
if (( flags & V_6WIDTHSPACE ))
dim_fn = BunchedCharacterDim;
else
dim_fn = VariableCharacterDim;
}
break;
case GM_FONT:
if (chw)
dim_fn = FixedCharacterDim;
else
dim_fn = GamemodeCharacterDim;
break;
case FILE_FONT:
if (chw)
dim_fn = FixedCharacterDim;
else
dim_fn = FileCharacterDim;
break;
case LSHI_FONT:
case LSLOW_FONT:
if (chw)
dim_fn = FixedCharacterDim;
else
dim_fn = LSTitleCharacterDim;
break;
}
cx = cy = 0;
for (; ( c = *s ); ++s)
{
switch (c)
{
case '\n':
cy += lfh;
cx = 0;
break;
default:
if (uppercase)
c = toupper(c);
c -= font->start;
if (c >= 0 && c < font->size && font->font[c])
{
cw = SHORT (font->font[c]->width) * dupx;
(*dim_fn)(scale, chw, hchw, dupx, &cw);
cx += cw;
}
else
cx += spacew;
}
fullwidth = max(cx, fullwidth);
}
return fullwidth;
}
void V_DrawCenteredString(INT32 x, INT32 y, INT32 option, const char *string)
{
@ -2244,49 +2560,64 @@ void V_DrawRightAlignedThinStringAtFixed(fixed_t x, fixed_t y, INT32 option, con
V_DrawThinStringAtFixed(x, y, option, string);
}
// Draws a number using the PING font thingy.
// TODO: Merge number drawing functions into one with "font name" selection.
void V_DrawPingNum(INT32 x, INT32 y, INT32 flags, INT32 num, const UINT8 *colormap)
void V_DrawCenteredKartString(INT32 x, INT32 y, INT32 option, const char *string)
{
INT32 w = SHORT(fontv[PINGNUM_FONT].font[0]->width); // this SHOULD always be 5 but I guess custom graphics exist.
if (flags & V_NOSCALESTART)
w *= vid.dupx;
if (num < 0)
num = -num;
// draw the number
do
{
x -= (w-1); // Oni wanted their outline to intersect.
V_DrawFixedPatch(x<<FRACBITS, y<<FRACBITS, FRACUNIT, flags, fontv[PINGNUM_FONT].font[num%10], colormap);
num /= 10;
} while (num);
x -= V_KartStringWidth(string, option)/2;
V_DrawKartString(x, y, option, string);
}
// Find string width from cred_font chars
//
INT32 V_CreditStringWidth(const char *string)
void V_DrawRightAlignedKartString(INT32 x, INT32 y, INT32 option, const char *string)
{
INT32 c, w = 0;
size_t i;
x -= V_KartStringWidth(string, option);
V_DrawKartString(x, y, option, string);
}
// It's possible for string to be a null pointer
if (!string)
return 0;
void V_DrawCenteredGamemodeString(INT32 x, INT32 y, INT32 option, const UINT8 *colormap, const char *string)
{
x -= V_GamemodeStringWidth(string, option)/2;
V_DrawGamemodeString(x, y, option, colormap, string);
}
for (i = 0; i < strlen(string); i++)
{
c = toupper(string[i]) - CRED_FONTSTART;
if (c < 0 || c >= CRED_FONTSIZE)
w += 16;
else
w += fontv[CRED_FONT].font[c]->width;
}
void V_DrawRightAlignedGamemodeString(INT32 x, INT32 y, INT32 option, const UINT8 *colormap, const char *string)
{
x -= V_GamemodeStringWidth(string, option);
V_DrawGamemodeString(x, y, option, colormap, string);
}
return w;
void V_DrawCenteredFileString(INT32 x, INT32 y, INT32 option, const char *string)
{
x -= V_FileStringWidth(string, option)/2;
V_DrawFileString(x, y, option, string);
}
void V_DrawRightAlignedFileString(INT32 x, INT32 y, INT32 option, const char *string)
{
x -= V_FileStringWidth(string, option);
V_DrawFileString(x, y, option, string);
}
void V_DrawCenteredLSTitleHighString(INT32 x, INT32 y, INT32 option, const char *string)
{
x -= V_LSTitleHighStringWidth(string, option)/2;
V_DrawLSTitleHighString(x, y, option, string);
}
void V_DrawRightAlignedLSTitleHighString(INT32 x, INT32 y, INT32 option, const char *string)
{
x -= V_LSTitleHighStringWidth(string, option);
V_DrawLSTitleHighString(x, y, option, string);
}
void V_DrawCenteredLSTitleLowString(INT32 x, INT32 y, INT32 option, const char *string)
{
x -= V_LSTitleLowStringWidth(string, option)/2;
V_DrawLSTitleLowString(x, y, option, string);
}
void V_DrawRightAlignedLSTitleLowString(INT32 x, INT32 y, INT32 option, const char *string)
{
x -= V_LSTitleLowStringWidth(string, option);
V_DrawLSTitleLowString(x, y, option, string);
}
// Draws a tallnum. Replaces two functions in y_inter and st_stuff
@ -2335,25 +2666,43 @@ void V_DrawPaddedTallNum(INT32 x, INT32 y, INT32 flags, INT32 num, INT32 digits)
} while (--digits);
}
// Find string width from lt_font chars
//
INT32 V_LevelNameWidth(const char *string)
void V_DrawProfileNum(INT32 x, INT32 y, INT32 flags, UINT8 num)
{
INT32 c, w = 0;
size_t i;
UINT8 digits = 3;
INT32 w = fontv[PROFNUM_FONT].font[0]->width;
for (i = 0; i < strlen(string); i++)
if (flags & V_NOSCALESTART)
w *= vid.dupx;
// draw the number
do
{
if (string[i] & 0x80)
continue;
c = string[i] - LT_FONTSTART;
if (c < 0 || c >= LT_FONTSIZE || !fontv[LT_FONT].font[c])
w += 12;
else
w += fontv[LT_FONT].font[c]->width;
}
x -= (w-1);
V_DrawScaledPatch(x, y, flags, fontv[PROFNUM_FONT].font[num % 10]);
num /= 10;
} while (--digits);
}
return w;
// Draws a number using the PING font thingy.
// TODO: Merge number drawing functions into one with "font name" selection.
void V_DrawPingNum(INT32 x, INT32 y, INT32 flags, INT32 num, const UINT8 *colormap)
{
INT32 w = SHORT(fontv[PINGNUM_FONT].font[0]->width); // this SHOULD always be 5 but I guess custom graphics exist.
if (flags & V_NOSCALESTART)
w *= vid.dupx;
if (num < 0)
num = -num;
// draw the number
do
{
x -= (w-1); // Oni wanted their outline to intersect.
V_DrawFixedPatch(x<<FRACBITS, y<<FRACBITS, FRACUNIT, flags, fontv[PINGNUM_FONT].font[num%10], colormap);
num /= 10;
} while (num);
}
// Find max height of the string
@ -2376,145 +2725,6 @@ INT32 V_LevelNameHeight(const char *string)
return w;
}
//
// Find string width from hu_font chars
//
INT32 V_StringWidth(const char *string, INT32 option)
{
INT32 c, w = 0;
INT32 spacewidth = 4, charwidth = 0;
size_t i;
switch (option & V_SPACINGMASK)
{
case V_MONOSPACE:
spacewidth = 8;
/* FALLTHRU */
case V_OLDSPACING:
charwidth = 8;
break;
case V_6WIDTHSPACE:
spacewidth = 6;
default:
break;
}
for (i = 0; i < strlen(string); i++)
{
c = string[i];
if ((UINT8)c & 0x80) //color parsing! -Inuyasha 2.16.09
continue;
c = toupper(c) - HU_FONTSTART;
if (c < 0 || c >= HU_FONTSIZE || !fontv[HU_FONT].font[c])
w += spacewidth;
else
w += (charwidth ? charwidth : fontv[HU_FONT].font[c]->width);
}
if (option & (V_NOSCALESTART|V_NOSCALEPATCH))
w *= vid.dupx;
return w;
}
//
// Find string width from hu_font chars, 0.5x scale
//
INT32 V_SmallStringWidth(const char *string, INT32 option)
{
INT32 c, w = 0;
INT32 spacewidth = 2, charwidth = 0;
size_t i;
switch (option & V_SPACINGMASK)
{
case V_MONOSPACE:
spacewidth = 4;
/* FALLTHRU */
case V_OLDSPACING:
charwidth = 4;
break;
case V_6WIDTHSPACE:
spacewidth = 3;
default:
break;
}
for (i = 0; i < strlen(string); i++)
{
c = string[i];
if ((UINT8)c & 0x80) //color parsing! -Inuyasha 2.16.09
continue;
c = toupper(c) - HU_FONTSTART;
if (c < 0 || c >= HU_FONTSIZE || !fontv[HU_FONT].font[c])
w += spacewidth;
else
w += (charwidth ? charwidth : fontv[HU_FONT].font[c]->width / 2);
}
return w;
}
//
// Find string width from tny_font chars
//
INT32 V_ThinStringWidth(const char *string, INT32 option)
{
INT32 c, w = 0;
INT32 spacewidth = 2, charwidth = 0;
boolean lowercase = (option & V_ALLOWLOWERCASE);
size_t i;
switch (option & V_SPACINGMASK)
{
case V_MONOSPACE:
spacewidth = 5;
/* FALLTHRU */
case V_OLDSPACING:
charwidth = 5;
break;
// Out of video flags, so we're reusing this for alternate charwidth instead
/*case V_6WIDTHSPACE:
spacewidth = 3;*/
default:
break;
}
for (i = 0; i < strlen(string); i++)
{
c = string[i];
if ((UINT8)c & 0x80) //color parsing! -Inuyasha 2.16.09
continue;
if (!lowercase || !fontv[TINY_FONT].font[c-HU_FONTSTART])
c = toupper(c);
c -= HU_FONTSTART;
if (c < 0 || c >= HU_FONTSIZE || !fontv[TINY_FONT].font[c])
w += spacewidth;
else
{
w += (charwidth ? charwidth
: ((option & V_6WIDTHSPACE && i < strlen(string)-1) ? max(1, fontv[TINY_FONT].font[c]->width-1) // Reuse this flag for the alternate bunched-up spacing
: fontv[TINY_FONT].font[c]->width));
}
}
return w;
}
//
// Find string width from tny_font chars, 0.5x scale
//
INT32 V_SmallThinStringWidth(const char *string, INT32 option)
{
INT32 w = V_ThinStringWidth(string, option)<<FRACBITS;
return w/2 + FRACUNIT; // +FRACUNIT because otherwise it's offset wrong.
}
boolean *heatshifter = NULL;
INT32 lastheight = 0;
INT32 heatindex[MAXSPLITSCREENPLAYERS] = {0, 0, 0, 0};

View file

@ -207,10 +207,15 @@ void V_EncoreInvertScreen(void);
void V_DrawPromptBack(INT32 boxheight, INT32 color);
/* Convenience macros for leagacy string function macros. */
#define V__DrawOneScaleString( x,y,scale,option,font,string ) \
V_DrawStringScaled(x,y,scale,FRACUNIT,FRACUNIT,option,font,string)
#define V__DrawDupxString( x,y,scale,option,font,string )\
V__DrawOneScaleString ((x)<<FRACBITS,(y)<<FRACBITS,scale,option,font,string)
#define V__DrawOneScaleString( x,y,scale,option,cm,font,string ) \
V_DrawStringScaled(x,y,scale,FRACUNIT,FRACUNIT,option,cm,font,string)
#define V__DrawDupxString( x,y,scale,option,cm,font,string )\
V__DrawOneScaleString ((x)<<FRACBITS,(y)<<FRACBITS,scale,option,cm,font,string)
#define V__OneScaleStringWidth( scale,option,font,string ) \
V_StringScaledWidth(scale,FRACUNIT,FRACUNIT,option,font,string)
#define V__IntegerStringWidth( scale,option,font,string ) \
(V_StringScaledWidth(scale,FRACUNIT,FRACUNIT,option,font,string) / FRACUNIT)
// draw a single character
void V_DrawCharacter(INT32 x, INT32 y, INT32 c, boolean lowercaseallowed);
@ -220,7 +225,13 @@ void V_DrawChatCharacter(INT32 x, INT32 y, INT32 c, boolean lowercaseallowed, UI
UINT8 *V_GetStringColormap(INT32 colorflags);
#define V_DrawLevelTitle( x,y,option,string ) \
V__DrawDupxString (x,y,FRACUNIT,option,LT_FONT,string)
V__DrawDupxString (x,y,FRACUNIT,option,NULL,LT_FONT,string)
// Find string width from lt_font chars
#define V_LevelNameWidth( string ) \
V__IntegerStringWidth ( FRACUNIT,0,LT_FONT,string )
INT32 V_LevelNameHeight(const char *string);
// wordwrap a string using the hu_font
char *V_WordWrap(INT32 x, INT32 w, INT32 option, const char *string);
@ -233,34 +244,57 @@ void V_DrawStringScaled(
fixed_t space_scale,
fixed_t linefeed_scale,
INT32 flags,
const UINT8 *colormap,
int font,
const char *text);
fixed_t V_StringScaledWidth(
fixed_t scale,
fixed_t spacescale,
fixed_t lfscale,
INT32 flags,
int fontno,
const char *s);
// draw a string using the hu_font
#define V_DrawString( x,y,option,string ) \
V__DrawDupxString (x,y,FRACUNIT,option,HU_FONT,string)
#define V_DrawKartString( x,y,option,string ) \
V__DrawDupxString (x,y,FRACUNIT,option,KART_FONT,string)
V__DrawDupxString (x,y,FRACUNIT,option,NULL,HU_FONT,string)
#define V_StringWidth( string,option ) \
V__IntegerStringWidth ( FRACUNIT,option,HU_FONT,string )
void V_DrawCenteredString(INT32 x, INT32 y, INT32 option, const char *string);
void V_DrawRightAlignedString(INT32 x, INT32 y, INT32 option, const char *string);
// draw a string using the hu_font, 0.5x scale
#define V_DrawSmallString( x,y,option,string ) \
V__DrawDupxString (x,y,FRACUNIT>>1,option,HU_FONT,string)
V__DrawDupxString (x,y,FRACUNIT>>1,option,NULL,HU_FONT,string)
#define V_SmallStringWidth( string,option ) \
V__IntegerStringWidth ( FRACUNIT>>1,option,HU_FONT,string )
void V_DrawCenteredSmallString(INT32 x, INT32 y, INT32 option, const char *string);
void V_DrawRightAlignedSmallString(INT32 x, INT32 y, INT32 option, const char *string);
// draw a string using the tny_font
#define V_DrawThinString( x,y,option,string ) \
V__DrawDupxString (x,y,FRACUNIT,option,TINY_FONT,string)
V__DrawDupxString (x,y,FRACUNIT,option,NULL,TINY_FONT,string)
#define V_ThinStringWidth( string,option ) \
V__IntegerStringWidth ( FRACUNIT,option,TINY_FONT,string )
void V_DrawCenteredThinString(INT32 x, INT32 y, INT32 option, const char *string);
void V_DrawRightAlignedThinString(INT32 x, INT32 y, INT32 option, const char *string);
#define V_DrawStringAtFixed( x,y,option,string ) \
V__DrawOneScaleString (x,y,FRACUNIT,option,HU_FONT,string)
V__DrawOneScaleString (x,y,FRACUNIT,option,NULL,HU_FONT,string)
#define V_DrawThinStringAtFixed( x,y,option,string ) \
V__DrawOneScaleString (x,y,FRACUNIT,option,TINY_FONT,string)
V__DrawOneScaleString (x,y,FRACUNIT,option,NULL,TINY_FONT,string)
void V_DrawCenteredThinStringAtFixed(fixed_t x, fixed_t y, INT32 option, const char *string);
void V_DrawRightAlignedThinStringAtFixed(fixed_t x, fixed_t y, INT32 option, const char *string);
void V_DrawCenteredThinStringAtFixed(fixed_t x, fixed_t y, INT32 option, const char *string);
void V_DrawRightAlignedThinStringAtFixed(fixed_t x, fixed_t y, INT32 option, const char *string);
@ -282,23 +316,59 @@ void V_DrawPaddedTallNum(INT32 x, INT32 y, INT32 flags, INT32 num, INT32 digits)
// This is a separate function because IMO lua should have access to it as well.
void V_DrawPingNum(INT32 x, INT32 y, INT32 flags, INT32 num, const UINT8 *colormap);
// Find string width from lt_font chars
INT32 V_LevelNameWidth(const char *string);
INT32 V_LevelNameHeight(const char *string);
INT16 V_LevelActNumWidth(UINT8 num); // act number width
void V_DrawProfileNum(INT32 x, INT32 y, INT32 flags, UINT8 num);
#define V_DrawCreditString( x,y,option,string ) \
V__DrawOneScaleString (x,y,FRACUNIT,option,CRED_FONT,string)
INT32 V_CreditStringWidth(const char *string);
V__DrawOneScaleString (x,y,FRACUNIT,option,NULL,CRED_FONT,string)
// Find string width from hu_font chars
INT32 V_StringWidth(const char *string, INT32 option);
// Find string width from hu_font chars, 0.5x scale
INT32 V_SmallStringWidth(const char *string, INT32 option);
// Find string width from tny_font chars
INT32 V_ThinStringWidth(const char *string, INT32 option);
// Find string width from tny_font chars, 0.5x scale
INT32 V_SmallThinStringWidth(const char *string, INT32 option);
#define V_CreditStringWidth( string ) \
V__IntegerStringWidth ( FRACUNIT,0,CRED_FONT,string )
// SRB2Kart
#define V_DrawKartString( x,y,option,string ) \
V__DrawDupxString (x,y,FRACUNIT,option,NULL,KART_FONT,string)
#define V_KartStringWidth( string,option ) \
V__IntegerStringWidth ( FRACUNIT,option,KART_FONT,string )
void V_DrawCenteredKartString(INT32 x, INT32 y, INT32 option, const char *string);
void V_DrawRightAlignedKartString(INT32 x, INT32 y, INT32 option, const char *string);
#define V_DrawGamemodeString( x,y,option,cm,string ) \
V__DrawDupxString (x,y,FRACUNIT,option,cm,GM_FONT,string)
#define V_GamemodeStringWidth( string,option ) \
V__IntegerStringWidth ( FRACUNIT,option,GM_FONT,string )
void V_DrawCenteredGamemodeString(INT32 x, INT32 y, INT32 option, const UINT8 *colormap, const char *string);
void V_DrawRightAlignedGamemodeString(INT32 x, INT32 y, INT32 option, const UINT8 *colormap, const char *string);
#define V_DrawFileString( x,y,option,string ) \
V__DrawDupxString (x,y,FRACUNIT,option,NULL,FILE_FONT,string)
#define V_FileStringWidth( string,option ) \
V__IntegerStringWidth ( FRACUNIT,option,FILE_FONT,string )
void V_DrawCenteredFileString(INT32 x, INT32 y, INT32 option, const char *string);
void V_DrawRightAlignedFileString(INT32 x, INT32 y, INT32 option, const char *string);
#define V_DrawLSTitleHighString( x,y,option,string ) \
V__DrawDupxString (x,y,FRACUNIT,option,NULL,LSHI_FONT,string)
#define V_LSTitleHighStringWidth( string,option ) \
V__IntegerStringWidth ( FRACUNIT,option,LSHI_FONT,string )
void V_DrawCenteredLSTitleHighString(INT32 x, INT32 y, INT32 option, const char *string);
void V_DrawRightAlignedLSTitleHighString(INT32 x, INT32 y, INT32 option, const char *string);
#define V_DrawLSTitleLowString( x,y,option,string ) \
V__DrawDupxString (x,y,FRACUNIT,option,NULL,LSLOW_FONT,string)
#define V_LSTitleLowStringWidth( string,option ) \
V__IntegerStringWidth ( FRACUNIT,option,LSLOW_FONT,string )
void V_DrawCenteredLSTitleLowString(INT32 x, INT32 y, INT32 option, const char *string);
void V_DrawRightAlignedLSTitleLowString(INT32 x, INT32 y, INT32 option, const char *string);
void V_DoPostProcessor(INT32 view, postimg_t type, INT32 param);

View file

@ -26,7 +26,7 @@
#include "w_wad.h"
#include "y_inter.h"
#include "z_zone.h"
#include "m_menu.h"
#include "k_menu.h"
#include "m_misc.h"
#include "i_system.h"
#include "p_setup.h"
@ -41,11 +41,10 @@
#include "lua_hudlib_drawlist.h"
#include "m_random.h" // M_RandomKey
#include "g_input.h" // PlayerInputDown
#include "g_input.h" // G_PlayerInputDown
#include "k_battle.h"
#include "k_boss.h"
#include "k_pwrlv.h"
#include "console.h" // cons_menuhighlight
#include "k_grandprix.h"
#ifdef HWRENDER
@ -88,24 +87,10 @@ static patch_t *bgpatch = NULL; // INTERSCR
static patch_t *widebgpatch = NULL;
static patch_t *bgtile = NULL; // SPECTILE/SRB2BACK
static patch_t *interpic = NULL; // custom picture defined in map header
static boolean usetile;
static INT32 timer;
typedef struct
{
INT32 source_width, source_height;
INT32 source_bpp, source_rowbytes;
UINT8 *source_picture;
INT32 target_width, target_height;
INT32 target_bpp, target_rowbytes;
UINT8 *target_picture;
} y_buffer_t;
boolean usebuffer = false;
static boolean useinterpic;
static INT32 timer;
static INT32 powertype = PWRLV_DISABLED;
static y_buffer_t *y_buffer;
static INT32 intertic;
static INT32 endtic = -1;
@ -117,8 +102,6 @@ intertype_t intermissiontypes[NUMGAMETYPES];
static huddrawlist_h luahuddrawlist_intermission;
static void Y_FollowIntermission(void);
static void Y_RescaleScreenBuffer(void);
static void Y_UnloadData(void);
// SRB2Kart: voting stuff
@ -344,91 +327,6 @@ static void Y_CalculateMatchData(UINT8 rankingsmode, void (*comparison)(INT32))
}
}
//
// Y_ConsiderScreenBuffer
//
// Can we copy the current screen to a buffer?
//
void Y_ConsiderScreenBuffer(void)
{
if (gameaction != ga_completed)
return;
if (y_buffer == NULL)
y_buffer = Z_Calloc(sizeof(y_buffer_t), PU_STATIC, NULL);
else
return;
y_buffer->source_width = vid.width;
y_buffer->source_height = vid.height;
y_buffer->source_bpp = vid.bpp;
y_buffer->source_rowbytes = vid.rowbytes;
y_buffer->source_picture = ZZ_Alloc(y_buffer->source_width*vid.bpp * y_buffer->source_height);
VID_BlitLinearScreen(screens[1], y_buffer->source_picture, vid.width*vid.bpp, vid.height, vid.width*vid.bpp, vid.rowbytes);
// Make the rescaled screen buffer
Y_RescaleScreenBuffer();
}
//
// Y_RescaleScreenBuffer
//
// Write the rescaled source picture, to the destination picture that has the current screen's resolutions.
//
static void Y_RescaleScreenBuffer(void)
{
INT32 sx, sy; // source
INT32 dx, dy; // dest
fixed_t scalefac, yscalefac;
fixed_t rowfrac, colfrac;
UINT8 *dest;
// Who knows?
if (y_buffer == NULL)
return;
if (y_buffer->target_picture)
Z_Free(y_buffer->target_picture);
y_buffer->target_width = vid.width;
y_buffer->target_height = vid.height;
y_buffer->target_rowbytes = vid.rowbytes;
y_buffer->target_bpp = vid.bpp;
y_buffer->target_picture = ZZ_Alloc(y_buffer->target_width*vid.bpp * y_buffer->target_height);
dest = y_buffer->target_picture;
scalefac = FixedDiv(y_buffer->target_width*FRACUNIT, y_buffer->source_width*FRACUNIT);
yscalefac = FixedDiv(y_buffer->target_height*FRACUNIT, y_buffer->source_height*FRACUNIT);
rowfrac = FixedDiv(FRACUNIT, yscalefac);
colfrac = FixedDiv(FRACUNIT, scalefac);
for (sy = 0, dy = 0; sy < (y_buffer->source_height << FRACBITS) && dy < y_buffer->target_height; sy += rowfrac, dy++)
for (sx = 0, dx = 0; sx < (y_buffer->source_width << FRACBITS) && dx < y_buffer->target_width; sx += colfrac, dx += y_buffer->target_bpp)
dest[(dy * y_buffer->target_rowbytes) + dx] = y_buffer->source_picture[((sy>>FRACBITS) * y_buffer->source_width) + (sx>>FRACBITS)];
}
//
// Y_CleanupScreenBuffer
//
// Free all related memory.
//
void Y_CleanupScreenBuffer(void)
{
// Who knows?
if (y_buffer == NULL)
return;
if (y_buffer->target_picture)
Z_Free(y_buffer->target_picture);
if (y_buffer->source_picture)
Z_Free(y_buffer->source_picture);
Z_Free(y_buffer);
y_buffer = NULL;
}
//
// Y_IntermissionDrawer
//
@ -442,38 +340,10 @@ void Y_IntermissionDrawer(void)
if (intertype == int_none || rendermode == render_none)
return;
if (useinterpic)
V_DrawScaledPatch(0, 0, 0, interpic);
else if (!usetile)
// the merge was kind of a mess, how does this work -- toast 171021
{
if (rendermode == render_soft && usebuffer)
{
// no y_buffer
if (y_buffer == NULL)
VID_BlitLinearScreen(screens[1], screens[0], vid.width*vid.bpp, vid.height, vid.width*vid.bpp, vid.rowbytes);
else
{
// Maybe the resolution changed?
if ((y_buffer->target_width != vid.width) || (y_buffer->target_height != vid.height))
Y_RescaleScreenBuffer();
// Blit the already-scaled screen buffer to the current screen
VID_BlitLinearScreen(y_buffer->target_picture, screens[0], vid.width*vid.bpp, vid.height, vid.width*vid.bpp, vid.rowbytes);
}
}
#ifdef HWRENDER
else if (rendermode != render_soft && usebuffer)
HWR_DrawIntermissionBG();
#endif
else if (bgpatch)
{
fixed_t hs = vid.width * FRACUNIT / BASEVIDWIDTH;
fixed_t vs = vid.height * FRACUNIT / BASEVIDHEIGHT;
V_DrawStretchyFixedPatch(0, 0, hs, vs, V_NOSCALEPATCH, bgpatch, NULL);
}
M_DrawMenuBackground();
}
else if (bgtile)
V_DrawPatchFill(bgtile);
if (renderisnewtic)
{
@ -485,15 +355,10 @@ void Y_IntermissionDrawer(void)
if (!LUA_HudEnabled(hud_intermissiontally))
goto skiptallydrawer;
if (usebuffer) // Fade everything out
V_DrawFadeScreen(0xFF00, 22);
if (!r_splitscreen)
whiteplayer = demo.playback ? displayplayers[0] : consoleplayer;
if (cons_menuhighlight.value)
hilicol = cons_menuhighlight.value;
else if (modeattacking)
if (modeattacking)
hilicol = V_ORANGEMAP;
else
hilicol = ((intertype == int_race) ? V_SKYMAP : V_REDMAP);
@ -639,7 +504,7 @@ void Y_IntermissionDrawer(void)
{
if (powertype != PWRLV_DISABLED && !clientpowerlevels[data.num[i]][powertype])
{
// No power level (splitscreen guests)
// No power level (guests)
STRBUFCPY(strtime, "----");
}
else
@ -710,7 +575,7 @@ skiptallydrawer:
if (!LUA_HudEnabled(hud_intermissionmessages))
return;
if (timer && grandprixinfo.gp == false && bossinfo.boss == false)
if (timer && grandprixinfo.gp == false && bossinfo.boss == false && !modeattacking)
{
char *string;
INT32 tickdown = (timer+1)/TICRATE;
@ -720,38 +585,40 @@ skiptallydrawer:
else
string = va("%s starts in %d", cv_advancemap.string, tickdown);
V_DrawCenteredString(BASEVIDWIDTH/2, 188, hilicol,
string);
}
V_DrawCenteredString(BASEVIDWIDTH/2, 188, hilicol, string);
if ((demo.recording || demo.savemode == DSM_SAVED) && !demo.playback)
switch (demo.savemode)
if ((demo.recording || demo.savemode == DSM_SAVED) && !demo.playback)
{
case DSM_NOTSAVING:
V_DrawRightAlignedThinString(BASEVIDWIDTH - 2, 2, V_SNAPTOTOP|V_SNAPTORIGHT|V_ALLOWLOWERCASE|hilicol, "Look Backward: Save replay");
break;
switch (demo.savemode)
{
case DSM_NOTSAVING:
V_DrawRightAlignedThinString(BASEVIDWIDTH - 2, 2, V_SNAPTOTOP|V_SNAPTORIGHT|V_ALLOWLOWERCASE|hilicol, "(B): Save replay");
break;
case DSM_SAVED:
V_DrawRightAlignedThinString(BASEVIDWIDTH - 2, 2, V_SNAPTOTOP|V_SNAPTORIGHT|V_ALLOWLOWERCASE|hilicol, "Replay saved!");
break;
case DSM_SAVED:
V_DrawRightAlignedThinString(BASEVIDWIDTH - 2, 2, V_SNAPTOTOP|V_SNAPTORIGHT|V_ALLOWLOWERCASE|hilicol, "Replay saved!");
break;
case DSM_TITLEENTRY:
ST_DrawDemoTitleEntry();
break;
case DSM_TITLEENTRY:
ST_DrawDemoTitleEntry();
break;
default: // Don't render any text here
break;
default: // Don't render any text here
break;
}
}
//if ((intertic/TICRATE) & 1) // Make it obvious that scrambling is happening next round. (OR NOT, I GUESS)
//{
/*if (cv_scrambleonchange.value && cv_teamscramble.value)
V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT/2, hilicol, M_GetText("Teams will be scrambled next round!"));*/
//if ((intertic/TICRATE) & 1) // Make it obvious that scrambling is happening next round. (OR NOT, I GUESS)
//{
if (speedscramble != -1 && speedscramble != gamespeed)
{
V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT-24, hilicol|V_ALLOWLOWERCASE|V_SNAPTOBOTTOM,
va(M_GetText("Next race will be %s Speed!"), kartspeed_cons_t[1+speedscramble].strvalue));
}
//}
}
if (speedscramble != -1 && speedscramble != gamespeed)
V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT-24, hilicol|V_ALLOWLOWERCASE|V_SNAPTOBOTTOM,
va(M_GetText("Next race will be %s Speed!"), kartspeed_cons_t[1+speedscramble].strvalue));
//}
M_DrawMenuForeground();
}
//
@ -766,7 +633,7 @@ void Y_Ticker(void)
if (demo.recording)
{
if (demo.savemode == DSM_NOTSAVING && PlayerInputDown(1, gc_lookback))
if (demo.savemode == DSM_NOTSAVING && G_PlayerInputDown(0, gc_y, 0))
demo.savemode = DSM_TITLEENTRY;
if (demo.savemode == DSM_WILLSAVE || demo.savemode == DSM_WILLAUTOSAVE)
@ -1017,12 +884,10 @@ void Y_StartIntermission(void)
K_CashInPowerLevels();
}
//if (intertype == int_race || intertype == int_battle)
{
//bgtile = W_CachePatchName("SRB2BACK", PU_STATIC);
usetile = useinterpic = false;
usebuffer = true;
}
bgpatch = W_CachePatchName("MENUBG", PU_STATIC);
widebgpatch = W_CachePatchName("WEIRDRES", PU_STATIC);
M_UpdateMenuBGImage(true);
}
// ======
@ -1038,7 +903,6 @@ void Y_EndIntermission(void)
endtic = -1;
sorttic = -1;
intertype = int_none;
usebuffer = false;
}
//
@ -1318,9 +1182,7 @@ void Y_VoteDrawer(void)
if (timer)
{
INT32 hilicol, tickdown = (timer+1)/TICRATE;
if (cons_menuhighlight.value)
hilicol = cons_menuhighlight.value;
else if (gametype == GT_RACE)
if (gametype == GT_RACE)
hilicol = V_SKYMAP;
else //if (gametype == GT_BATTLE)
hilicol = V_REDMAP;
@ -1503,15 +1365,15 @@ void Y_VoteTicker(void)
if ((playeringame[p] && !players[p].spectator)
&& !voteclient.playerinfo[i].delay
&& pickedvote == -1 && votes[p] == -1)
&& pickedvote == -1 && votes[p] == -1 && menuactive == false)
{
if (PlayerInputDown(i+1, gc_aimforward) || PlayerJoyAxis(i+1, AXISAIM) < 0)
if (G_PlayerInputDown(i, gc_up, 0))
{
voteclient.playerinfo[i].selection--;
pressed = true;
}
if ((PlayerInputDown(i+1, gc_aimbackward) || PlayerJoyAxis(i+1, AXISAIM) > 0) && !pressed)
if (G_PlayerInputDown(i, gc_down, 0) && pressed == false)
{
voteclient.playerinfo[i].selection++;
pressed = true;
@ -1522,7 +1384,7 @@ void Y_VoteTicker(void)
if (voteclient.playerinfo[i].selection > 3)
voteclient.playerinfo[i].selection = 0;
if ((PlayerInputDown(i+1, gc_accelerate) || PlayerJoyAxis(i+1, AXISMOVE) > 0) && !pressed)
if (G_PlayerInputDown(i, gc_a, 0) && pressed == false)
{
D_ModifyClientVote(consoleplayer, voteclient.playerinfo[i].selection, i);
pressed = true;
@ -1667,7 +1529,7 @@ void Y_StartVote(void)
// set up the gtc and gts
levelinfo[i].gtc = G_GetGametypeColor(votelevels[i][1]);
if (i == 2 && votelevels[i][1] != votelevels[0][1])
levelinfo[i].gts = gametype_cons_t[votelevels[i][1]].strvalue;
levelinfo[i].gts = Gametype_Names[votelevels[i][1]];
else
levelinfo[i].gts = NULL;

View file

@ -9,17 +9,12 @@
/// \file y_inter.h
/// \brief Tally screens, or "Intermissions" as they were formally called in Doom
extern boolean usebuffer;
void Y_IntermissionDrawer(void);
void Y_Ticker(void);
void Y_StartIntermission(void);
void Y_EndIntermission(void);
void Y_ConsiderScreenBuffer(void);
void Y_CleanupScreenBuffer(void);
void Y_DetermineIntermissionType(void);
void Y_VoteDrawer(void);