Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • KartKrew/Kart-Public
  • SteelT/Kart-Public
  • SSNTails/Kart-Public
  • mazmazz_/Kart-Public
  • james/Kart-Public
  • Latius/Kart-Public
  • alphaRexJames/Kart-Public
  • heyjoeway/Kart-Public
  • Namolos/Kart-Public
  • SinnamonLat/Kart-Public
  • filpAM/Kart-Public
  • wolfy852/Kart-Public
  • bird/Kart-Public
  • TehRealSalt/Kart-Public
  • Snu/Kart-Public
  • Tyron/Kart-Public
  • kimmy/Kart-Public
  • Spice/Kart-Public
  • Callmore/Kart-Public
  • JugadorXEI/Kart-Public
  • Fafabis/Kart-Public
  • cspotcode/Kart-Public
  • Lonsfor_/Kart-Public
  • brokenspleentec/Kart-Public
  • minenice/Kart-Public
  • Lighto97/Kart-Public
  • X.organic/Kart-Public
  • Superjustinbros/srb2kart-custom-color-expansion
  • Galactice/Kart-Public
  • haya_/Kart-Public
  • QuantumToasted/Kart-Public
  • Indev/Kart-Public
  • chreas/kart-public-vr
  • alufolie91/Kart-Public2
  • Alam/Kart-Public
  • koi/Kart-Public
  • Alam/kart-public-vr
  • Hanicef/Kart-Public
  • hero0fnin/kart-public-batocera-edit
  • NepDisk/Kart-Public
  • Nep2Disk/Kart-Public
41 results
Show changes
Commits on Source (206)
......@@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.0)
# DO NOT CHANGE THIS SRB2 STRING! Some variable names depend on this string.
# Version change is fine.
project(SRB2
VERSION 1.4
VERSION 1.6
LANGUAGES C)
if(${PROJECT_SOURCE_DIR} MATCHES ${PROJECT_BINARY_DIR})
......
......@@ -353,6 +353,40 @@ size_t COM_CheckParm(const char *check)
return 0;
}
/** \brief COM_CheckParm, but checks only the start of each argument.
* E.g. checking for "-no" would match "-noerror" too.
*/
size_t COM_CheckPartialParm(const char *check)
{
int len;
size_t i;
len = strlen(check);
for (i = 1; i < com_argc; i++)
{
if (strncasecmp(check, com_argv[i], len) == 0)
return i;
}
return 0;
}
/** Find the first argument that starts with a hyphen (-).
* \return The index of the argument, or 0
* if there are no such arguments.
*/
size_t COM_FirstOption(void)
{
size_t i;
for (i = 1; i < com_argc; i++)
{
if (com_argv[i][0] == '-')/* options start with a hyphen */
return i;
}
return 0;
}
/** Parses a string into command-line tokens.
*
* \param ptext A null-terminated string. Does not need to be
......@@ -1875,6 +1909,45 @@ static boolean CV_FilterJoyAxisVars(consvar_t *v, const char *valstr)
return true;
}
// Block the Xbox DInput default axes and reset to the current defaults
static boolean CV_FilterJoyAxisVars2(consvar_t *v, const char *valstr)
{
if (!stricmp(v->name, "joyaxis_turn") && !stricmp(valstr, "X-Axis"))
return false;
if (!stricmp(v->name, "joyaxis2_turn") && !stricmp(valstr, "X-Axis"))
return false;
if (!stricmp(v->name, "joyaxis3_turn") && !stricmp(valstr, "X-Axis"))
return false;
if (!stricmp(v->name, "joyaxis4_turn") && !stricmp(valstr, "X-Axis"))
return false;
if (!stricmp(v->name, "joyaxis_aim") && !stricmp(valstr, "Y-Axis"))
return false;
if (!stricmp(v->name, "joyaxis2_aim") && !stricmp(valstr, "Y-Axis"))
return false;
if (!stricmp(v->name, "joyaxis3_aim") && !stricmp(valstr, "Y-Axis"))
return false;
if (!stricmp(v->name, "joyaxis4_aim") && !stricmp(valstr, "Y-Axis"))
return false;
if (!stricmp(v->name, "joyaxis_fire") && !stricmp(valstr, "None"))
return false;
if (!stricmp(v->name, "joyaxis2_fire") && !stricmp(valstr, "None"))
return false;
if (!stricmp(v->name, "joyaxis3_fire") && !stricmp(valstr, "None"))
return false;
if (!stricmp(v->name, "joyaxis4_fire") && !stricmp(valstr, "None"))
return false;
if (!stricmp(v->name, "joyaxis_drift") && !stricmp(valstr, "None"))
return false;
if (!stricmp(v->name, "joyaxis2_drift") && !stricmp(valstr, "None"))
return false;
if (!stricmp(v->name, "joyaxis3_drift") && !stricmp(valstr, "None"))
return false;
if (!stricmp(v->name, "joyaxis4_drift") && !stricmp(valstr, "None"))
return false;
return true;
}
static boolean CV_FilterVarByVersion(consvar_t *v, const char *valstr)
{
// True means allow the CV change, False means block it
......@@ -1908,6 +1981,13 @@ static boolean CV_FilterVarByVersion(consvar_t *v, const char *valstr)
return false;
}
if (GETMAJOREXECVERSION(cv_execversion.value) < 10) // 10 = 1.6
{
// axis defaults changed again to SDL game controllers
if (!CV_FilterJoyAxisVars2(v, valstr))
return false;
}
return true;
}
......
......@@ -37,6 +37,8 @@ size_t COM_Argc(void);
const char *COM_Argv(size_t arg); // if argv > argc, returns empty string
char *COM_Args(void);
size_t COM_CheckParm(const char *check); // like M_CheckParm :)
size_t COM_CheckPartialParm(const char *check);
size_t COM_FirstOption(void);
// match existing command or NULL
const char *COM_CompleteCommand(const char *partial, INT32 skips);
......
......@@ -40,6 +40,7 @@
* Last updated 2020 / 08 / 30 - Kart v1.3 - patch.kart
* Last updated 2022 / 08 / 16 - Kart v1.4 - Main assets
* Last updated 2022 / 08 / 19 - Kart v1.5 - gfx.kart
* Last updated 2022 / 11 / 01 - Kart v1.6 - gfx.kart, maps.kart
*/
// Base SRB2 hashes
......@@ -49,10 +50,10 @@
#endif
// SRB2Kart-specific hashes
#define ASSET_HASH_GFX_KART "30b2d9fb5009f1b3a3d7216a0fe28e51"
#define ASSET_HASH_GFX_KART "06f86ee16136eb8a7043b15001797034"
#define ASSET_HASH_TEXTURES_KART "abb53d56aba47c3a8cb0f764da1c8b80"
#define ASSET_HASH_CHARS_KART "e2c428347dde52858a3dacd29fc5b964"
#define ASSET_HASH_MAPS_KART "13e273292576b71af0cdb3a98ca066eb"
#define ASSET_HASH_MAPS_KART "d051e55141ba736582228c456953cd98"
#ifdef USE_PATCH_KART
#define ASSET_HASH_PATCH_KART "00000000000000000000000000000000"
#endif
......
......@@ -1117,6 +1117,7 @@ typedef enum
CL_DOWNLOADFILES,
CL_ASKJOIN,
CL_LOADFILES,
CL_SETUPFILES,
CL_WAITJOINRESPONSE,
#ifdef JOININGAME
CL_DOWNLOADSAVEGAME,
......@@ -1129,6 +1130,7 @@ typedef enum
CL_PREPAREHTTPFILES,
CL_DOWNLOADHTTPFILES,
#endif
CL_LEGACYREQUESTFAILED,
} cl_mode_t;
static void GetPackets(void);
......@@ -1226,8 +1228,12 @@ static inline void CL_DrawConnectionStatus(void)
#endif
case CL_ASKFULLFILELIST:
case CL_CONFIRMCONNECT:
case CL_LEGACYREQUESTFAILED:
cltext = "";
break;
case CL_SETUPFILES:
cltext = M_GetText("Configuring addons...");
break;
case CL_ASKJOIN:
case CL_WAITJOINRESPONSE:
if (serverisfull)
......@@ -1329,8 +1335,10 @@ static inline void CL_DrawConnectionStatus(void)
strncpy(tempname, filename, sizeof(tempname)-1);
}
V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT-58-30, 0,
va(M_GetText("%s downloading"), ((cl_mode == CL_DOWNLOADHTTPFILES) ? "\x82""HTTP" : "\x85""Direct")));
V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT-58-22, V_YELLOWMAP,
va(M_GetText("Downloading \"%s\""), tempname));
va(M_GetText("\"%s\""), tempname));
V_DrawString(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-58, V_20TRANS|V_MONOSPACE,
va(" %4uK/%4uK",fileneeded[lastfilenum].currentsize>>10,file->totalsize>>10));
V_DrawRightAlignedString(BASEVIDWIDTH/2+128, BASEVIDHEIGHT-58, V_20TRANS|V_MONOSPACE,
......@@ -1933,7 +1941,15 @@ static void CL_LoadReceivedSavegame(void)
#ifndef NONET
static void SendAskInfo(INT32 node)
{
const tic_t asktime = I_GetTime();
tic_t asktime;
if (node != 0 && node != BROADCASTADDR &&
cv_rendezvousserver.string[0])
{
I_NetRequestHolePunch(node);
}
asktime = I_GetTime();
netbuffer->packettype = PT_ASKINFO;
netbuffer->u.askinfo.version = VERSION;
......@@ -1943,16 +1959,14 @@ static void SendAskInfo(INT32 node)
// now allowed traffic from the host to us in, so once the MS relays
// our address to the host, it'll be able to speak to us.
HSendPacket(node, false, 0, sizeof (askinfo_pak));
if (node != 0 && node != BROADCASTADDR &&
cv_rendezvousserver.string[0])
{
I_NetRequestHolePunch(node);
}
}
serverelem_t serverlist[MAXSERVERLIST];
UINT32 serverlistcount = 0;
UINT32 serverlistultimatecount = 0;
static boolean resendserverlistnode[MAXNETNODES];
static tic_t serverlistepoch;
static void SL_ClearServerList(INT32 connectedserver)
{
......@@ -1965,6 +1979,8 @@ static void SL_ClearServerList(INT32 connectedserver)
serverlist[i].node = 0;
}
serverlistcount = 0;
memset(resendserverlistnode, 0, sizeof resendserverlistnode);
}
static UINT32 SL_SearchServer(INT32 node)
......@@ -1981,6 +1997,8 @@ static void SL_InsertServer(serverinfo_pak* info, SINT8 node)
{
UINT32 i;
resendserverlistnode[node] = false;
// search if not already on it
i = SL_SearchServer(node);
if (i == UINT32_MAX)
......@@ -2038,6 +2056,8 @@ void CL_QueryServerList (msg_server_t *server_list)
CL_UpdateServerList();
serverlistepoch = I_GetTime();
for (i = 0; server_list[i].header.buffer[0]; i++)
{
// Make sure MS version matches our own, to
......@@ -2050,19 +2070,42 @@ void CL_QueryServerList (msg_server_t *server_list)
if (node == -1)
break; // no more node free
SendAskInfo(node);
// Force close the connection so that servers can't eat
// up nodes forever if we never get a reply back from them
// (usually when they've not forwarded their ports).
//
// Don't worry, we'll get in contact with the working
// servers again when they send SERVERINFO to us later!
//
// (Note: as a side effect this probably means every
// server in the list will probably be using the same node (e.g. node 1),
// not that it matters which nodes they use when
// the connections are closed afterwards anyway)
// -- Monster Iestyn 12/11/18
Net_CloseConnection(node|FORCECLOSE);
resendserverlistnode[node] = true;
// Leave this node open. It'll be closed if the
// request times out (CL_TimeoutServerList).
}
}
serverlistultimatecount = i;
}
#define SERVERLISTRESENDRATE NEWTICRATE
void CL_TimeoutServerList(void)
{
if (netgame && serverlistultimatecount > serverlistcount)
{
const tic_t timediff = I_GetTime() - serverlistepoch;
const tic_t timetoresend = timediff % SERVERLISTRESENDRATE;
const boolean timedout = timediff > connectiontimeout;
if (timedout || (timediff > 0 && timetoresend == 0))
{
INT32 node;
for (node = 1; node < MAXNETNODES; ++node)
{
if (resendserverlistnode[node])
{
if (timedout)
Net_CloseConnection(node|FORCECLOSE);
else
SendAskInfo(node);
}
}
if (timedout)
serverlistultimatecount = serverlistcount;
}
}
}
......@@ -2085,6 +2128,10 @@ static void M_ConfirmConnect(event_t *ev)
{
cl_mode = CL_DOWNLOADFILES;
}
else
{
cl_mode = CL_LEGACYREQUESTFAILED;
}
}
#ifdef HAVE_CURL
else
......@@ -2240,6 +2287,10 @@ static boolean CL_FinishedFileList(void)
{
cl_mode = CL_DOWNLOADFILES;
}
else
{
cl_mode = CL_LEGACYREQUESTFAILED;
}
}
#endif
}
......@@ -2426,8 +2477,28 @@ static boolean CL_ServerConnectionTicker(const char *tmpsave, tic_t *oldtic, tic
cl_mode = CL_LOADFILES;
break;
case CL_LEGACYREQUESTFAILED:
{
CONS_Printf(M_GetText("Legacy downloader request packet failed.\n"));
CONS_Printf(M_GetText("Network game synchronization aborted.\n"));
D_QuitNetGame();
CL_Reset();
D_StartTitle();
M_StartMessage(M_GetText(
"The direct download encountered an error.\n"
"See the logfile for more info.\n"
"\n"
"Press ESC\n"
), NULL, MM_NOTHING);
return false;
}
case CL_LOADFILES:
if (CL_LoadServerFiles())
if (CL_LoadServerFiles())
cl_mode = CL_SETUPFILES;
break;
case CL_SETUPFILES:
if (P_PartialAddGetStage() < 0 || P_MultiSetupWadFiles(false))
{
*asksent = 0; //This ensure the first join ask is right away
firstconnectattempttime = I_GetTime();
......@@ -2633,7 +2704,11 @@ static void CL_ConnectToServer(void)
#else
if (!CL_ServerConnectionTicker((char*)NULL, &oldtic, (tic_t *)NULL))
#endif
{
if (P_PartialAddGetStage() >= 0)
P_MultiSetupWadFiles(true); // in case any partial adds were done
return;
}
if (server)
{
......@@ -2830,6 +2905,12 @@ void D_LoadBan(boolean warning)
address = strtok(buffer, " /\t\r\n");
mask = strtok(NULL, " \t\r\n");
if (!address)
{
malformed = true;
continue;
}
if (i == 0 && !strncmp(address, "BANFORMAT", 9))
{
if (mask)
......@@ -5897,23 +5978,20 @@ boolean TryRunTics(tic_t realtics)
if (ticking)
{
if (advancedemo)
D_StartTitle();
else
// run the count * tics
while (neededtic > gametic)
{
DEBFILE(va("============ Running tic %d (local %d)\n", gametic, localgametic));
// run the count * tics
while (neededtic > gametic)
{
DEBFILE(va("============ Running tic %d (local %d)\n", gametic, localgametic));
G_Ticker((gametic % NEWTICRATERATIO) == 0);
ExtraDataTicker();
gametic++;
consistancy[gametic%TICQUEUE] = Consistancy();
G_Ticker((gametic % NEWTICRATERATIO) == 0);
ExtraDataTicker();
gametic++;
consistancy[gametic%TICQUEUE] = Consistancy();
// Leave a certain amount of tics present in the net buffer as long as we've ran at least one tic this frame.
if (client && gamestate == GS_LEVEL && leveltime > 3 && neededtic <= gametic + cv_netticbuffer.value)
break;
}
// Leave a certain amount of tics present in the net buffer as long as we've ran at least one tic this frame.
if (client && gamestate == GS_LEVEL && leveltime > 3 && neededtic <= gametic + cv_netticbuffer.value)
break;
}
}
else
{
......@@ -5935,53 +6013,77 @@ boolean TryRunTics(tic_t realtics)
static INT32 pingtimeout[MAXPLAYERS];
#define PINGKICK_TICQUEUE 2
#define PINGKICK_LIMIT 1
static inline void PingUpdate(void)
{
INT32 i;
boolean laggers[MAXPLAYERS];
UINT8 numlaggers = 0;
memset(laggers, 0, sizeof(boolean) * MAXPLAYERS);
UINT8 pingkick[MAXPLAYERS];
UINT8 nonlaggers = 0;
memset(pingkick, 0, sizeof(pingkick));
netbuffer->packettype = PT_PING;
//check for ping limit breakage.
if (cv_maxping.value)
//if (cv_maxping.value) -- always check for TICQUEUE overrun
{
for (i = 1; i < MAXPLAYERS; i++)
for (i = 0; i < MAXPLAYERS; i++)
{
if (playeringame[i] && (realpingtable[i] / pingmeasurecount > (unsigned)cv_maxping.value))
if (!playeringame[i] || P_IsLocalPlayer(&players[i])) // should be P_IsMachineLocalPlayer for DRRR
{
if (players[i].jointime > 30 * TICRATE)
laggers[i] = true;
numlaggers++;
pingtimeout[i] = 0;
continue;
}
if ((maketic + 5) >= nettics[playernode[i]] + (TICQUEUE-(2*TICRATE)))
{
// Anyone who's gobbled most of the TICQUEUE and is likely to halt the server the next few times this runs has to die *right now*. (See also NetUpdate)
pingkick[i] = PINGKICK_TICQUEUE;
}
else if ((cv_maxping.value)
&& (realpingtable[i] / pingmeasurecount > (unsigned)cv_maxping.value))
{
if (players[i].jointime > 10 * TICRATE)
{
pingkick[i] = PINGKICK_LIMIT;
}
}
else
pingtimeout[i] = 0;
{
nonlaggers++;
// you aren't lagging, but you aren't free yet. In case you'll keep spiking, we just make the timer go back down. (Very unstable net must still get kicked).
if (pingtimeout[i] > 0)
pingtimeout[i]--;
}
}
//kick lagging players... unless everyone but the server's ping sucks.
//in that case, it is probably the server's fault.
if (numlaggers < D_NumPlayers() - 1)
// Always kick TICQUEUE-overrunners, too.
{
for (i = 1; i < MAXPLAYERS; i++)
UINT8 minimumkicklevel = (nonlaggers > 0) ? PINGKICK_LIMIT : PINGKICK_TICQUEUE;
for (i = 0; i < MAXPLAYERS; i++)
{
if (playeringame[i] && laggers[i])
{
pingtimeout[i]++;
if (pingtimeout[i] > cv_pingtimeout.value) // ok your net has been bad for too long, you deserve to die.
{
XBOXSTATIC char buf[2];
XBOXSTATIC char buf[2];
pingtimeout[i] = 0;
if (!playeringame[i] || pingkick[i] < minimumkicklevel)
continue;
buf[0] = (char)i;
buf[1] = KICK_MSG_PING_HIGH;
SendNetXCmd(XD_KICK, &buf, 2);
}
if (pingkick[i] == PINGKICK_LIMIT)
{
// Don't kick on ping alone if we haven't reached our threshold yet.
if (++pingtimeout[i] < cv_pingtimeout.value)
continue;
}
else // you aren't lagging, but you aren't free yet. In case you'll keep spiking, we just make the timer go back down. (Very unstable net must still get kicked).
pingtimeout[i] = (pingtimeout[i] == 0 ? 0 : pingtimeout[i]-1);
pingtimeout[i] = 0;
buf[0] = (char)i;
buf[1] = KICK_MSG_PING_HIGH;
SendNetXCmd(XD_KICK, &buf, 2);
}
}
}
......@@ -6006,9 +6108,12 @@ static inline void PingUpdate(void)
if (nodeingame[i])
HSendPacket(i, true, 0, sizeof(INT32) * (MAXPLAYERS+1));
pingmeasurecount = 1; //Reset count
pingmeasurecount = 0; //Reset count
}
#undef PINGKICK_DANGER
#undef PINGKICK_LIMIT
static tic_t gametime = 0;
static void UpdatePingTable(void)
......@@ -6099,6 +6204,9 @@ FILESTAMP
SV_FileSendTicker();
}
// If a tree falls in the forest but nobody is around to hear it, does it make a tic?
#define DEDICATEDIDLETIME (10*TICRATE)
void NetUpdate(void)
{
static tic_t resptime = 0;
......@@ -6111,6 +6219,55 @@ void NetUpdate(void)
if (realtics <= 0) // nothing new to update
return;
#ifdef DEDICATEDIDLETIME
if (server && dedicated && gamestate == GS_LEVEL)
{
static tic_t dedicatedidle = 0;
for (i = 1; i < MAXNETNODES; ++i)
if (nodeingame[i])
{
if (dedicatedidle == DEDICATEDIDLETIME)
{
CONS_Printf("DEDICATED: Awakening from idle (Node %d detected...)\n", i);
dedicatedidle = 0;
}
break;
}
if (i == MAXNETNODES)
{
if (leveltime == 2)
{
// On next tick...
dedicatedidle = DEDICATEDIDLETIME-1;
}
else if (dedicatedidle == DEDICATEDIDLETIME)
{
if (D_GetExistingTextcmd(gametic, 0) || D_GetExistingTextcmd(gametic+1, 0))
{
CONS_Printf("DEDICATED: Awakening from idle (Netxcmd detected...)\n");
dedicatedidle = 0;
}
else
{
realtics = 0;
}
}
else if (++dedicatedidle == DEDICATEDIDLETIME)
{
const char *idlereason = "at round start";
if (leveltime > 3)
idlereason = va("for %d seconds", dedicatedidle/TICRATE);
CONS_Printf("DEDICATED: No nodes %s, idling...\n", idlereason);
realtics = 0;
}
}
}
#endif
if (realtics > 5)
{
if (server)
......@@ -6153,7 +6310,7 @@ FILESTAMP
}
else
{
if (!demo.playback)
if (!demo.playback && realtics > 0)
{
INT32 counts;
......@@ -6177,6 +6334,7 @@ FILESTAMP
// Do not make tics while resynching
if (counts != -666)
{
// See also PingUpdate
if (maketic + counts >= firstticstosend + TICQUEUE)
counts = firstticstosend+TICQUEUE-maketic-1;
......@@ -6227,6 +6385,9 @@ INT32 D_NumPlayers(void)
tic_t GetLag(INT32 node)
{
// If the client has caught up to the server -- say, during a wipe -- lag is meaningless.
if (nettics[node] > gametic)
return 0;
return gametic - nettics[node];
}
......
......@@ -502,6 +502,7 @@ typedef struct
extern serverelem_t serverlist[MAXSERVERLIST];
extern UINT32 serverlistcount;
extern UINT32 serverlistultimatecount;
extern INT32 mapchangepending;
// Points inside doomcom
......@@ -594,6 +595,7 @@ void CL_ClearPlayer(INT32 playernum);
void CL_RemovePlayer(INT32 playernum, INT32 reason);
void CL_QueryServerList(msg_server_t *list);
void CL_UpdateServerList(void);
void CL_TimeoutServerList(void);
// Is there a game running
boolean Playing(void);
......
......@@ -144,7 +144,6 @@ boolean sound_disabled = false;
boolean digital_disabled = false;
#endif
boolean advancedemo;
#ifdef DEBUGFILE
INT32 debugload = 0;
#endif
......@@ -815,15 +814,6 @@ void D_SRB2Loop(void)
}
}
//
// D_AdvanceDemo
// Called after each demo or intro demosequence finishes
//
void D_AdvanceDemo(void)
{
advancedemo = true;
}
// =========================================================================
// D_SRB2Main
// =========================================================================
......@@ -883,7 +873,6 @@ void D_StartTitle(void)
//demosequence = -1;
gametype = GT_RACE; // SRB2kart
paused = false;
advancedemo = false;
F_StartTitleScreen();
// Reset the palette -- SRB2Kart: actually never mind let's do this in the middle of every fade
......@@ -1154,6 +1143,8 @@ void D_SRB2Main(void)
{
const char *userhome = D_Home(); //Alam: path to home
FILE *tmpfile;
char testfile[MAX_WADPATH];
if (!userhome)
{
......@@ -1203,9 +1194,6 @@ void D_SRB2Main(void)
// If config isn't writable, tons of behavior will be broken.
// Fail loudly before things get confusing!
FILE *tmpfile;
char testfile[MAX_WADPATH];
snprintf(testfile, sizeof testfile, "%s" PATHSEP "file.tmp", srb2home);
testfile[sizeof testfile - 1] = '\0';
......@@ -1258,26 +1246,6 @@ void D_SRB2Main(void)
if (M_CheckParm("-server") || dedicated)
netgame = server = true;
if (M_CheckParm("-warp") && M_IsNextParm())
{
const char *word = M_GetNextParm();
char ch; // use this with sscanf to catch non-digits with
if (fastncmp(word, "MAP", 3)) // MAPxx name
pstartmap = M_MapNumber(word[3], word[4]);
else if (sscanf(word, "%d%c", &pstartmap, &ch) != 1) // a plain number
I_Error("Cannot warp to map %s (invalid map name)\n", word);
// Don't check if lump exists just yet because the wads haven't been loaded!
// Just do a basic range check here.
if (pstartmap < 1 || pstartmap > NUMMAPS)
I_Error("Cannot warp to map %d (out of range)\n", pstartmap);
else
{
if (!M_CheckParm("-server"))
G_SetGameModified(true, true);
autostart = true;
}
}
CONS_Printf("Z_Init(): Init zone memory allocation daemon. \n");
Z_Init();
......@@ -1343,7 +1311,7 @@ void D_SRB2Main(void)
//
// search for maps
//
for (wadnum = 4; wadnum < 6; wadnum++) // fucking arbitrary numbers
for (wadnum = 0; wadnum < mainwads; wadnum++)
{
lumpinfo = wadfiles[wadnum]->lumpinfo;
for (i = 0; i < wadfiles[wadnum]->numlumps; i++, lumpinfo++)
......@@ -1457,6 +1425,23 @@ void D_SRB2Main(void)
//------------------------------------------------ COMMAND LINE PARAMS
// this must be done after loading gamedata,
// to avoid setting off the corrupted gamedata code in G_LoadGameData if a SOC with custom gamedata is added
// -- Monster Iestyn 20/02/20
if (M_CheckParm("-warp") && M_IsNextParm())
{
const char *word = M_GetNextParm();
pstartmap = G_FindMapByNameOrCode(word, 0);
if (! pstartmap)
I_Error("Cannot find a map remotely named '%s'\n", word);
else
{
if (!M_CheckParm("-server"))
G_SetGameModified(true, true);
autostart = true;
}
}
// Initialize CD-Audio
if (M_CheckParm("-usecd") && !dedicated)
I_InitCD();
......
......@@ -17,8 +17,6 @@
#include "d_event.h"
#include "w_wad.h" // for MAX_WADFILES
extern boolean advancedemo;
// make sure not to write back the config until it's been correctly loaded
extern tic_t rendergametic;
......@@ -34,7 +32,6 @@ void D_SRB2Loop(void) FUNCNORETURN;
// D_SRB2Main()
// Not a globally visible function, just included for source reference,
// calls all startup code, parses command line options.
// If not overrided by user input, calls D_AdvanceDemo.
//
void D_SRB2Main(void);
......@@ -51,7 +48,6 @@ const char *D_Home(void);
//
// BASE LEVEL
//
void D_AdvanceDemo(void);
void D_StartTitle(void);
#endif //__D_MAIN__
......@@ -1464,7 +1464,7 @@ void Command_Ping_f(void)
if (!server && playeringame[consoleplayer])
{
CONS_Printf("\nYour ping is %d frames (%d ms)\n", playerpingtable[consoleplayer], (INT32)(playerpingtable[i] * (1000.00f / TICRATE)));
CONS_Printf("\nYour ping is %d frames (%d ms)\n", playerpingtable[consoleplayer], (INT32)(playerpingtable[consoleplayer] * (1000.00f / TICRATE)));
}
}
......
......@@ -251,7 +251,7 @@ consvar_t cv_ingamecap = {"ingamecap", "0", CV_NETVAR, ingamecap_cons_t, NULL, 0
static CV_PossibleValue_t spectatorreentry_cons_t[] = {{0, "MIN"}, {10*60, "MAX"}, {0, NULL}};
consvar_t cv_spectatorreentry = {"spectatorreentry", "30", CV_NETVAR, spectatorreentry_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
static CV_PossibleValue_t antigrief_cons_t[] = {{20, "MIN"}, {60, "MAX"}, {0, "Off"}, {0, NULL}};
static CV_PossibleValue_t antigrief_cons_t[] = {{20, "MIN"}, {180, "MAX"}, {0, "Off"}, {0, NULL}};
consvar_t cv_antigrief = {"antigrief", "30", CV_NETVAR, antigrief_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_startinglives = {"startinglives", "3", CV_NETVAR|CV_CHEAT|CV_NOSHOWHELP, startingliveslimit_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
......@@ -912,6 +912,10 @@ void D_RegisterClientCommands(void)
CV_RegisterVar(&cv_driftaxis2);
CV_RegisterVar(&cv_driftaxis3);
CV_RegisterVar(&cv_driftaxis4);
CV_RegisterVar(&cv_lookbackaxis);
CV_RegisterVar(&cv_lookbackaxis2);
CV_RegisterVar(&cv_lookbackaxis3);
CV_RegisterVar(&cv_lookbackaxis4);
CV_RegisterVar(&cv_xdeadzone);
CV_RegisterVar(&cv_ydeadzone);
CV_RegisterVar(&cv_xdeadzone2);
......@@ -2515,127 +2519,197 @@ void D_PickVote(void)
SendNetXCmd(XD_PICKVOTE, &buf, 2);
}
static char *
ConcatCommandArgv (int start, int end)
{
char *final;
size_t size;
int i;
char *p;
size = 0;
for (i = start; i < end; ++i)
{
/*
one space after each argument, but terminating
character on final argument
*/
size += strlen(COM_Argv(i)) + 1;
}
final = ZZ_Alloc(size);
p = final;
--end;/* handle the final argument separately */
for (i = start; i < end; ++i)
{
p += sprintf(p, "%s ", COM_Argv(i));
}
/* at this point "end" is actually the last argument's position */
strcpy(p, COM_Argv(end));
return final;
}
//
// Warp to map code.
// Called either from map <mapname> console command, or idclev cheat.
//
// Largely rewritten by James.
//
static void Command_Map_f(void)
{
const char *mapname;
size_t i;
size_t first_option;
size_t option_force;
size_t option_gametype;
size_t option_encore;
const char *gametypename;
boolean newresetplayers;
boolean mustmodifygame;
INT32 newmapnum;
boolean newresetplayers, newencoremode;
INT32 newgametype = gametype;
// max length of command: map map03 -gametype race -noresetplayers -force -encore
// 1 2 3 4 5 6 7
// = 8 arg max
// i don't know whether this is intrinsic to the system or just someone being weird but
// "noresetplayers" is pretty useless for kart if it turns out this is too close to the limit
if (COM_Argc() < 2 || COM_Argc() > 8)
char * mapname;
char *realmapname = NULL;
INT32 newgametype = gametype;
boolean newencoremode = cv_kartencore.value;
INT32 d;
if (client && !IsPlayerAdmin(consoleplayer))
{
CONS_Printf(M_GetText("map <mapname> [-gametype <type> [-force]: warp to map\n"));
CONS_Printf(M_GetText("Only the server or a remote admin can use this.\n"));
return;
}
if (client && !IsPlayerAdmin(consoleplayer))
option_force = COM_CheckPartialParm("-f");
option_gametype = COM_CheckPartialParm("-g");
option_encore = COM_CheckPartialParm("-e");
newresetplayers = ! COM_CheckParm("-noresetplayers");
mustmodifygame = !( netgame || multiplayer || majormods );
if (mustmodifygame && !option_force)
{
CONS_Printf(M_GetText("Only the server or a remote admin can use this.\n"));
/* May want to be more descriptive? */
CONS_Printf(M_GetText("Sorry, level change disabled in single player.\n"));
return;
}
// internal wad lump always: map command doesn't support external files as in doom legacy
if (W_CheckNumForName(COM_Argv(1)) == LUMPERROR)
if (!newresetplayers && !cv_debug)
{
CONS_Alert(CONS_ERROR, M_GetText("Internal game level '%s' not found\n"), COM_Argv(1));
CONS_Printf(M_GetText("DEVMODE must be enabled.\n"));
return;
}
if (!(netgame || multiplayer) && !majormods)
if (option_gametype)
{
if (COM_CheckParm("-force"))
if (!multiplayer)
{
G_SetGameModified(false, true);
CONS_Printf(M_GetText(
"You can't switch gametypes in single player!\n"));
return;
}
else
else if (COM_Argc() < option_gametype + 2)/* no argument after? */
{
CONS_Printf(M_GetText("Sorry, level change disabled in single player.\n"));
CONS_Alert(CONS_ERROR,
"No gametype name follows parameter '%s'.\n",
COM_Argv(option_gametype));
return;
}
}
newresetplayers = !COM_CheckParm("-noresetplayers");
if (!( first_option = COM_FirstOption() ))
first_option = COM_Argc();
if (!newresetplayers && !cv_debug)
if (first_option < 2)
{
CONS_Printf(M_GetText("DEVMODE must be enabled.\n"));
/* I'm going over the fucking lines and I DON'T CAREEEEE */
CONS_Printf("map <name / [MAP]code / number> [-gametype <type>] [-encore] [-force]:\n");
CONS_Printf(M_GetText(
"Warp to a map, by its name, two character code, with optional \"MAP\" prefix, or by its number (though why would you).\n"
"All parameters are case-insensitive and may be abbreviated.\n"));
return;
}
mapname = COM_Argv(1);
if (strlen(mapname) != 5
|| (newmapnum = M_MapNumber(mapname[3], mapname[4])) == 0)
mapname = ConcatCommandArgv(1, first_option);
newmapnum = G_FindMapByNameOrCode(mapname, &realmapname);
if (newmapnum == 0)
{
CONS_Alert(CONS_ERROR, M_GetText("Invalid level name %s\n"), mapname);
CONS_Alert(CONS_ERROR, M_GetText("Could not find any map described as '%s'.\n"), mapname);
Z_Free(mapname);
return;
}
// new gametype value
// use current one by default
i = COM_CheckParm("-gametype");
if (i)
if (mustmodifygame && option_force)
{
if (!multiplayer)
{
CONS_Printf(M_GetText("You can't switch gametypes in single player!\n"));
return;
}
newgametype = G_GetGametypeByName(COM_Argv(i+1));
if (newgametype == -1) // reached end of the list with no match
{
INT32 j = atoi(COM_Argv(i+1)); // assume they gave us a gametype number, which is okay too
if (j >= 0 && j < NUMGAMETYPES)
newgametype = (INT16)j;
}
G_SetGameModified(false, true);
}
// new encoremode value
// use cvar by default
// new gametype value
// use current one by default
if (option_gametype)
{
gametypename = COM_Argv(option_gametype + 1);
newencoremode = (boolean)cv_kartencore.value;
newgametype = G_GetGametypeByName(gametypename);
if (COM_CheckParm("-encore"))
{
if (!M_SecretUnlocked(SECRET_ENCORE) && !newencoremode)
if (newgametype == -1) // reached end of the list with no match
{
CONS_Alert(CONS_NOTICE, M_GetText("You haven't unlocked Encore Mode yet!\n"));
return;
/* Did they give us a gametype number? That's okay too! */
if (isdigit(gametypename[0]))
{
d = atoi(gametypename);
if (d >= 0 && d < NUMGAMETYPES)
newgametype = d;
else
{
CONS_Alert(CONS_ERROR,
"Gametype number %d is out of range. Use a number between"
" 0 and %d inclusive. ...Or just use the name. :v\n",
d,
NUMGAMETYPES-1);
Z_Free(realmapname);
Z_Free(mapname);
return;
}
}
else
{
CONS_Alert(CONS_ERROR,
"'%s' is not a gametype.\n",
gametypename);
Z_Free(realmapname);
Z_Free(mapname);
return;
}
}
newencoremode = !newencoremode;
}
if (!(i = COM_CheckParm("-force")) && newgametype == gametype) // SRB2Kart
if (!option_force && newgametype == gametype) // SRB2Kart
newresetplayers = false; // if not forcing and gametypes is the same
// don't use a gametype the map doesn't support
if (cv_debug || i || cv_skipmapcheck.value)
; // The player wants us to trek on anyway. Do so.
if (cv_debug || option_force || cv_skipmapcheck.value)
fromlevelselect = false; // The player wants us to trek on anyway. Do so.
// G_TOLFlag handles both multiplayer gametype and ignores it for !multiplayer
// Alternatively, bail if the map header is completely missing anyway.
else if (!mapheaderinfo[newmapnum-1]
|| !(mapheaderinfo[newmapnum-1]->typeoflevel & G_TOLFlag(newgametype)))
else
{
char gametypestring[32] = "Single Player";
if (multiplayer)
if (!(mapheaderinfo[newmapnum-1]->typeoflevel & G_TOLFlag(newgametype)))
{
if (newgametype >= 0 && newgametype < NUMGAMETYPES
&& Gametype_Names[newgametype])
strcpy(gametypestring, Gametype_Names[newgametype]);
CONS_Alert(CONS_WARNING, M_GetText("Course %s (%s) doesn't support %s mode!\n(Use -force to override)\n"), realmapname, G_BuildMapName(newmapnum),
(multiplayer ? gametype_cons_t[newgametype].strvalue : "Single Player"));
Z_Free(realmapname);
Z_Free(mapname);
return;
}
CONS_Alert(CONS_WARNING, M_GetText("%s doesn't support %s mode!\n(Use -force to override)\n"), mapname, gametypestring);
return;
}
// Prevent warping to locked levels
......@@ -2645,11 +2719,25 @@ static void Command_Map_f(void)
if (!dedicated && M_MapLocked(newmapnum))
{
CONS_Alert(CONS_NOTICE, M_GetText("You need to unlock this level before you can warp to it!\n"));
Z_Free(realmapname);
Z_Free(mapname);
return;
}
if (option_encore)
{
newencoremode = ! newencoremode;
if (! M_SecretUnlocked(SECRET_ENCORE) && newencoremode)
{
CONS_Alert(CONS_NOTICE, M_GetText("You haven't unlocked Encore Mode yet!\n"));
return;
}
}
fromlevelselect = false;
D_MapChange(newmapnum, newgametype, newencoremode, newresetplayers, 0, false, false);
Z_Free(realmapname);
}
/** Receives a map command and changes the map.
......@@ -2698,7 +2786,9 @@ static void Got_Mapcmd(UINT8 **cp, INT32 playernum)
lastgametype = gametype;
gametype = READUINT8(*cp);
if (gametype != lastgametype)
if (gametype < 0 || gametype >= NUMGAMETYPES)
gametype = lastgametype;
else if (gametype != lastgametype)
D_GameTypeChanged(lastgametype); // emulate consvar_t behavior for gametype
if (!G_RaceGametype())
......
......@@ -94,10 +94,20 @@ typedef struct filetran_s
{
filetx_t *txlist; // Linked list of all files for the node
UINT32 position; // The current position in the file
FILE *currentfile; // The file currently being sent/received
boolean init; // false if we want to reset position / open a new file
} filetran_t;
static filetran_t transfer[MAXNETNODES];
// The files currently being sent/received
typedef struct fileused_s
{
FILE *file;
UINT8 count;
UINT32 position;
} fileused_t;
static fileused_t transferFiles[UINT8_MAX + 1];
// Read time of file: stat _stmtime
// Write time of file: utime
......@@ -299,6 +309,9 @@ boolean CL_CheckDownloadable(void)
return false;
}
// The following was written and, against all odds, works.
#define MORELEGACYDOWNLOADER
/** Sends requests for files in the ::fileneeded table with a status of
* ::FS_NOTFOUND.
*
......@@ -311,42 +324,132 @@ boolean CL_SendRequestFile(void)
char *p;
INT32 i;
INT64 totalfreespaceneeded = 0, availablefreespace;
INT32 skippedafile = -1;
#ifdef MORELEGACYDOWNLOADER
boolean firstloop = true;
#endif
#ifdef PARANOIA
if (M_CheckParm("-nodownload"))
I_Error("Attempted to download files in -nodownload mode");
{
CONS_Printf("Direct download - Attempted to download files in -nodownload mode");
return false;
}
#endif
for (i = 0; i < fileneedednum; i++)
{
if (fileneeded[i].status != FS_FOUND && fileneeded[i].status != FS_OPEN
&& (fileneeded[i].willsend == 0 || fileneeded[i].willsend == 2))
{
I_Error("Attempted to download files that were not sendable");
CONS_Printf("Direct download - attempted to download files that were not sendable\n");
return false;
}
if ((fileneeded[i].status == FS_NOTFOUND || fileneeded[i].status == FS_MD5SUMBAD || fileneeded[i].status == FS_FALLBACK))
{
// Error check for the first time around.
totalfreespaceneeded += fileneeded[i].totalsize;
}
}
I_GetDiskFreeSpace(&availablefreespace);
if (totalfreespaceneeded > availablefreespace)
{
CONS_Printf("Direct download -\n"
" To play on this server you must download %s KB,\n"
" but you have only %s KB free space on this drive\n",
sizeu1((size_t)(totalfreespaceneeded>>10)), sizeu2((size_t)(availablefreespace>>10)));
return false;
}
#ifdef MORELEGACYDOWNLOADER
tryagain:
skippedafile = -1;
#endif
#ifdef VERBOSEREQUESTFILE
CONS_Printf("Preparing packet\n");
#endif
netbuffer->packettype = PT_REQUESTFILE;
p = (char *)netbuffer->u.textcmd;
for (i = 0; i < fileneedednum; i++)
{
if ((fileneeded[i].status == FS_NOTFOUND || fileneeded[i].status == FS_MD5SUMBAD || fileneeded[i].status == FS_FALLBACK))
{
totalfreespaceneeded += fileneeded[i].totalsize;
// Pre-prepare.
size_t checklen;
nameonly(fileneeded[i].filename);
// Figure out if we'd overrun our buffer.
checklen = strlen(fileneeded[i].filename)+2; // plus the fileid (and terminator, in case this is last)
if ((UINT8 *)(p + checklen) >= netbuffer->u.textcmd + MAXTEXTCMD)
{
skippedafile = i;
// we might have a shorter file that can fit in the remaining space, and file ID permits out-of-order data
continue;
}
// Now write.
WRITEUINT8(p, i); // fileid
WRITESTRINGN(p, fileneeded[i].filename, MAX_WADPATH);
#ifdef VERBOSEREQUESTFILE
CONS_Printf(" file \"%s\" (id %d)\n", i, fileneeded[i].filename);
#endif
// put it in download dir
strcatbf(fileneeded[i].filename, downloaddir, "/");
fileneeded[i].status = FS_REQUESTED;
}
WRITEUINT8(p, 0xFF);
I_GetDiskFreeSpace(&availablefreespace);
if (totalfreespaceneeded > availablefreespace)
I_Error("To play on this server you must download %s KB,\n"
"but you have only %s KB free space on this drive\n",
sizeu1((size_t)(totalfreespaceneeded>>10)), sizeu2((size_t)(availablefreespace>>10)));
}
#ifdef MORELEGACYDOWNLOADER
if (firstloop)
#else
// If we're not trying extralong legacy download requests, gotta bail.
if (skippedafile != -1)
{
CONS_Printf("Direct download - missing files are as follows:\n");
for (i = 0; i < fileneedednum; i++)
{
if ((fileneeded[i].status == FS_NOTFOUND || fileneeded[i].status == FS_MD5SUMBAD || fileneeded[i].status == FS_FALLBACK || fileneeded[i].status == FS_REQUESTED)) // FS_REQUESTED added
CONS_Printf(" %s\n", fileneeded[i].filename);
}
return false;
}
#endif
I_mkdir(downloaddir, 0755);
// Couldn't fit a single one in?
if (p == (char *)netbuffer->u.textcmd)
{
CONS_Printf("Direct download - fileneeded name for %s (fileneeded[%d]) too long??\n", (skippedafile != -1 ? fileneeded[skippedafile].filename : NULL), skippedafile);
return false;
}
WRITEUINT8(p, 0xFF); // terminator
if (!HSendPacket(servernode, true, 0, p - (char *)netbuffer->u.textcmd))
{
CONS_Printf("Direct download - unable to send packet.\n");
return false;
}
// prepare to download
I_mkdir(downloaddir, 0755);
return HSendPacket(servernode, true, 0, p - (char *)netbuffer->u.textcmd);
#ifdef MORELEGACYDOWNLOADER
if (skippedafile != -1)
{
firstloop = false;
goto tryagain;
}
#endif
#ifdef VERBOSEREQUESTFILE
CONS_Printf("Returning true\n");
#endif
return true;
}
// get request filepak and put it on the send queue
......@@ -356,16 +459,18 @@ boolean Got_RequestFilePak(INT32 node)
char wad[MAX_WADPATH+1];
UINT8 *p = netbuffer->u.textcmd;
UINT8 id;
while (p < netbuffer->u.textcmd + MAXTEXTCMD-1) // Don't allow hacked client to overflow
while (p < netbuffer->u.textcmd + MAXTEXTCMD) // Don't allow hacked client to overflow
{
id = READUINT8(p);
if (id == 0xFF)
break;
READSTRINGN(p, wad, MAX_WADPATH);
if (!SV_SendFile(node, wad, id))
if (p >= netbuffer->u.textcmd + MAXTEXTCMD || !SV_SendFile(node, wad, id))
{
if (cv_noticedownload.value)
CONS_Printf("Bad PT_REQUESTFILE from node %d!\n", node);
SV_AbortSendFiles(node);
return false; // don't read the rest of the files
return false; // don't read any more
}
}
return true; // no problems with any files
......@@ -486,7 +591,7 @@ boolean CL_LoadServerFiles(void)
continue; // Already loaded
else if (fileneeded[i].status == FS_FOUND)
{
P_AddWadFile(fileneeded[i].filename);
P_PartialAddWadFile(fileneeded[i].filename);
G_SetGameModified(true, false);
fileneeded[i].status = FS_OPEN;
return false;
......@@ -538,7 +643,7 @@ static boolean SV_SendFile(INT32 node, const char *filename, UINT8 fileid)
char wadfilename[MAX_WADPATH];
if (cv_noticedownload.value)
CONS_Printf("Sending file \"%s\" to node %d (%s)\n", filename, node, I_GetNodeAddress(node));
CONS_Printf("Sending file \"%s\" (id %d) to node %d (%s)\n", filename, fileid, node, I_GetNodeAddress(node));
// Find the last file in the list and set a pointer to its "next" field
q = &transfer[node].txlist;
......@@ -664,9 +769,20 @@ static void SV_EndFileSend(INT32 node)
{
case SF_FILE: // It's a file, close it and free its filename
if (cv_noticedownload.value)
CONS_Printf("Ending file transfer for node %d\n", node);
if (transfer[node].currentfile)
fclose(transfer[node].currentfile);
CONS_Printf("Ending file transfer (id %d) for node %d\n", p->fileid, node);
if (transferFiles[p->fileid].file)
{
if (transferFiles[p->fileid].count > 0)
{
transferFiles[p->fileid].count--;
}
if (transferFiles[p->fileid].count == 0)
{
fclose(transferFiles[p->fileid].file);
transferFiles[p->fileid].file = NULL;
}
}
free(p->id.filename);
break;
case SF_Z_RAM: // It's a memory block allocated with Z_Alloc or the likes, use Z_Free
......@@ -683,7 +799,7 @@ static void SV_EndFileSend(INT32 node)
free(p);
// Indicate that the transmission is over
transfer[node].currentfile = NULL;
transfer[node].init = false;
filestosend--;
}
......@@ -747,21 +863,31 @@ void SV_FileSendTicker(void)
ram = f->ram;
// Open the file if it isn't open yet, or
if (!transfer[i].currentfile)
if (transfer[i].init == false)
{
if (!ram) // Sending a file
{
long filesize;
transfer[i].currentfile =
fopen(f->id.filename, "rb");
if (transferFiles[f->fileid].count == 0)
{
// It needs opened.
transferFiles[f->fileid].file =
fopen(f->id.filename, "rb");
if (!transferFiles[f->fileid].file)
{
I_Error("Can't open file %s: %s",
f->id.filename, strerror(errno));
}
}
if (!transfer[i].currentfile)
I_Error("File %s does not exist",
f->id.filename);
// Increment number of nodes using this file.
I_Assert(transferFiles[f->fileid].count < UINT8_MAX);
transferFiles[f->fileid].count++;
fseek(transfer[i].currentfile, 0, SEEK_END);
filesize = ftell(transfer[i].currentfile);
fseek(transferFiles[f->fileid].file, 0, SEEK_END);
filesize = ftell(transferFiles[f->fileid].file);
// Nobody wants to transfer a file bigger
// than 4GB!
......@@ -770,23 +896,43 @@ void SV_FileSendTicker(void)
if (filesize == -1)
I_Error("Error getting filesize of %s", f->id.filename);
f->size = (UINT32)filesize;
fseek(transfer[i].currentfile, 0, SEEK_SET);
f->size = transferFiles[f->fileid].position = (UINT32)filesize;
}
else // Sending RAM
transfer[i].currentfile = (FILE *)1; // Set currentfile to a non-null value to indicate that it is open
transfer[i].position = 0;
transfer[i].init = true; // Indicate that it is open
}
if (!ram)
{
// Seek to the right position if we aren't already there.
if (transferFiles[f->fileid].position != transfer[i].position)
{
fseek(transferFiles[f->fileid].file, transfer[i].position, SEEK_SET);
}
}
// Build a packet containing a file fragment
p = &netbuffer->u.filetxpak;
size = software_MAXPACKETLENGTH - (FILETXHEADER + BASEPACKETSIZE);
if (f->size-transfer[i].position < size)
size = f->size-transfer[i].position;
if (f->size - transfer[i].position < size)
{
size = f->size - transfer[i].position;
}
if (ram)
{
M_Memcpy(p->data, &f->id.ram[transfer[i].position], size);
else if (fread(p->data, 1, size, transfer[i].currentfile) != size)
I_Error("SV_FileSendTicker: can't read %s byte on %s at %d because %s", sizeu1(size), f->id.filename, transfer[i].position, M_FileError(transfer[i].currentfile));
}
else if (fread(p->data, 1, size, transferFiles[f->fileid].file) != size)
{
I_Error("SV_FileSendTicker: can't read %s byte on %s at %d because %s",
sizeu1(size), f->id.filename, transfer[i].position, M_FileError(transferFiles[f->fileid].file));
transferFiles[f->fileid].position = (UINT32)(transferFiles[f->fileid].position + size);
}
p->position = LONG(transfer[i].position);
// Put flag so receiver knows the total size
if (transfer[i].position + size == f->size)
......@@ -796,15 +942,18 @@ void SV_FileSendTicker(void)
// Send the packet
if (HSendPacket(i, true, 0, FILETXHEADER + size)) // Reliable SEND
{ // Success
{
// Success
transfer[i].position = (UINT32)(transfer[i].position + size);
if (transfer[i].position == f->size) // Finish?
{
SV_EndFileSend(i);
}
}
else
{ // Not sent for some odd reason, retry at next call
if (!ram)
fseek(transfer[i].currentfile,transfer[i].position, SEEK_SET);
{
// Not sent for some odd reason, retry at next call
// Exit the while (can't send this one so why should i send the next?)
break;
}
......@@ -1156,6 +1305,7 @@ void CURLGetFile(void)
int msgs_left; /* how many messages are left */
const char *easy_handle_error;
long response_code = 0;
static char *filename;
if (curl_runninghandles)
{
......@@ -1180,6 +1330,8 @@ void CURLGetFile(void)
{
e = m->easy_handle;
easyres = m->data.result;
filename = Z_StrDup(curl_realname);
nameonly(filename);
if (easyres != CURLE_OK)
{
if (easyres == CURLE_HTTP_RETURNED_ERROR)
......@@ -1192,21 +1344,30 @@ void CURLGetFile(void)
curl_failedwebdownload = true;
fclose(curl_curfile->file);
remove(curl_curfile->filename);
curl_curfile->file = NULL;
//nameonly(curl_curfile->filename);
nameonly(curl_realname);
CONS_Printf(M_GetText("Failed to download %s (%s)\n"), curl_realname, easy_handle_error);
CONS_Printf(M_GetText("Failed to download %s (%s)\n"), filename, easy_handle_error);
}
else
{
nameonly(curl_realname);
CONS_Printf(M_GetText("Finished downloading %s\n"), curl_realname);
downloadcompletednum++;
downloadcompletedsize += curl_curfile->totalsize;
curl_curfile->status = FS_FOUND;
fclose(curl_curfile->file);
if (checkfilemd5(curl_curfile->filename, curl_curfile->md5sum) == FS_MD5SUMBAD)
{
CONS_Alert(CONS_ERROR, M_GetText("HTTP Download of %s finished but is corrupt or has been modified\n"), filename);
curl_curfile->status = FS_FALLBACK;
curl_failedwebdownload = true;
}
else
{
CONS_Printf(M_GetText("Finished HTTP download of %s\n"), filename);
downloadcompletednum++;
downloadcompletedsize += curl_curfile->totalsize;
curl_curfile->status = FS_FOUND;
}
}
Z_Free(filename);
curl_curfile->file = NULL;
curl_running = false;
curl_transfers--;
curl_multi_remove_handle(multi_handle, e);
......
......@@ -2641,109 +2641,6 @@ static void readconditionset(MYFILE *f, UINT8 setnum)
Z_Free(s);
}
static void readtexture(MYFILE *f, const char *name)
{
char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL);
char *word;
char *word2;
char *tmp;
INT32 i, j, value;
UINT16 width = 0, height = 0;
INT16 patchcount = 0;
texture_t *texture;
do
{
if (myfgets(s, MAXLINELEN, f))
{
if (s[0] == '\n')
break;
tmp = strchr(s, '#');
if (tmp)
*tmp = '\0';
value = searchvalue(s);
word = strtok(s, " ");
if (word)
strupr(word);
else
break;
word2 = strtok(NULL, " ");
if (word2)
strupr(word2);
else
break;
// Width of the texture.
if (fastcmp(word, "WIDTH"))
{
DEH_WriteUndoline(word, va("%d", width), UNDO_NONE);
width = SHORT((UINT16)value);
}
// Height of the texture.
else if (fastcmp(word, "HEIGHT"))
{
DEH_WriteUndoline(word, va("%d", height), UNDO_NONE);
height = SHORT((UINT16)value);
}
// Number of patches the texture has.
else if (fastcmp(word, "NUMPATCHES"))
{
DEH_WriteUndoline(word, va("%d", patchcount), UNDO_NONE);
patchcount = SHORT((UINT16)value);
}
else
deh_warning("readtexture: unknown word '%s'", word);
}
} while (!myfeof(f));
// Error checking.
if (!width)
I_Error("Texture %s has no width!\n", name);
if (!height)
I_Error("Texture %s has no height!\n", name);
if (!patchcount)
I_Error("Texture %s has no patches!\n", name);
// Allocate memory for the texture, and fill in information.
texture = Z_Calloc(sizeof(texture_t) + (sizeof(texpatch_t) * SHORT(patchcount)), PU_STATIC, NULL);
M_Memcpy(texture->name, name, sizeof(texture->name));
texture->width = width;
texture->height = height;
texture->patchcount = patchcount;
texture->holes = false;
// Fill out the texture patches, to allow them to be detected
// accurately by readpatch.
for (i = 0; i < patchcount; i++)
{
texture->patches[i].originx = 0;
texture->patches[i].originy = 0;
texture->patches[i].wad = UINT16_MAX;
texture->patches[i].lump = UINT16_MAX;
}
// Jump to the next empty texture entry.
i = 0;
while (textures[i])
i++;
// Fill the global texture buffer entries.
j = 1;
while (j << 1 <= texture->width)
j <<= 1;
textures[i] = texture;
texturewidthmask[i] = j - 1;
textureheight[i] = texture->height << FRACBITS;
// Clean up.
Z_Free(s);
}
static void readpatch(MYFILE *f, const char *name, UINT16 wad)
{
char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL);
......@@ -3350,14 +3247,7 @@ static void DEH_LoadDehackedFile(MYFILE *f, UINT16 wad)
if (word2[strlen(word2)-1] == '\n')
word2[strlen(word2)-1] = '\0';
i = atoi(word2);
if (fastcmp(word, "TEXTURE"))
{
// Read texture from spec file.
readtexture(f, word2);
DEH_WriteUndoline(word, word2, UNDO_HEADER);
// This is not a major mod.
}
else if (fastcmp(word, "PATCH"))
if (fastcmp(word, "PATCH"))
{
// Read patch from spec file.
readpatch(f, word2, wad);
......
......@@ -529,8 +529,10 @@ void DRPC_UpdatePresence(void)
else
{
// Map name on tool tip
snprintf(mapname, 48, "Map: %s", G_BuildMapTitle(gamemap));
char *title = G_BuildMapTitle(gamemap);
snprintf(mapname, 48, "Map: %s", title);
discordPresence.largeImageText = mapname;
Z_Free(title);
}
if (gamestate == GS_LEVEL && Playing())
......
......@@ -148,9 +148,9 @@ extern char logfilename[1024];
// we use comprevision and compbranch instead.
#else
#define VERSION 1 // Game version
#define SUBVERSION 4 // more precise version number
#define VERSIONSTRING "v1.5"
#define VERSIONSTRINGW L"v1.5"
#define SUBVERSION 6 // more precise version number
#define VERSIONSTRING "v1.6"
#define VERSIONSTRINGW L"v1.6"
// Hey! If you change this, add 1 to the MODVERSION below! Otherwise we can't force updates!
// And change CMakeLists.txt (not src/, but in root), for CMake users!
// AND appveyor.yml, for the build bots!
......@@ -204,7 +204,7 @@ extern char logfilename[1024];
// it's only for detection of the version the player is using so the MS can alert them of an update.
// Only set it higher, not lower, obviously.
// Note that we use this to help keep internal testing in check; this is why v2.1.0 is not version "1".
#define MODVERSION 9
#define MODVERSION 10
// Filter consvars by version
// To version config.cfg, MAJOREXECVERSION is set equal to MODVERSION automatically.
......@@ -227,7 +227,7 @@ extern char logfilename[1024];
// NOTE: it needs more than this to increase the number of players...
#define MAXPLAYERS 16
#define MAXSKINS 128
#define MAXSKINS 255
#define PLAYERSMASK (MAXPLAYERS-1)
#define MAXPLAYERNAME 21
......@@ -532,6 +532,7 @@ extern boolean capslock;
// if we ever make our alloc stuff...
#define ZZ_Alloc(x) Z_Malloc(x, PU_STATIC, NULL)
#define ZZ_Calloc(x) Z_Calloc(x, PU_STATIC, NULL)
// i_system.c, replace getchar() once the keyboard has been appropriated
INT32 I_GetKey(void);
......
......@@ -139,6 +139,9 @@ typedef long ssize_t;
#define strlwr _strlwr
#endif
char *strcasestr(const char *in, const char *what);
#define stristr strcasestr
#if defined (macintosh) //|| defined (__APPLE__) //skip all boolean/Boolean crap
#define true 1
#define false 0
......@@ -161,6 +164,15 @@ typedef long ssize_t;
#define HAVE_DOSSTR_FUNCS
#endif
#if defined (__APPLE__)
#define SRB2_HAVE_STRLCPY
#elif defined (__GLIBC_PREREQ)
// glibc 2.38: added strlcpy and strlcat to _DEFAULT_SOURCE
#if __GLIBC_PREREQ(2, 38)
#define SRB2_HAVE_STRLCPY
#endif
#endif
#ifndef HAVE_DOSSTR_FUNCS
int strupr(char *n); // from dosstr.c
int strlwr(char *n); // from dosstr.c
......@@ -168,7 +180,7 @@ int strlwr(char *n); // from dosstr.c
#include <stddef.h> // for size_t
#ifndef __APPLE__
#ifndef SRB2_HAVE_STRLCPY
size_t strlcat(char *dst, const char *src, size_t siz);
size_t strlcpy(char *dst, const char *src, size_t siz);
#endif
......
......@@ -431,10 +431,12 @@ static const char *credits[] = {
"\"JugadorXEI\"",
"\"Kimberly\"",
"\"Lighto97\"",
"\"Lonsfor\"",
"\"mazmazz\"",
"\"minenice\"",
"\"Shuffle\"",
"\"Snu\"",
"\"X.organic\"",
"",
"\1Lead Artists",
"Desmond \"Blade\" DesJardins",
......@@ -512,6 +514,7 @@ static const char *credits[] = {
"",
"\1Testing",
"RKH License holders",
"The KCS",
"\"CyberIF\"",
"\"Dani\"",
"Karol \"Fooruman\" D""\x1E""browski", // Dąbrowski, <Sryder> accents in srb2 :ytho:
......@@ -559,7 +562,7 @@ static struct {
// This Tyler52 gag is troublesome
// Alignment should be ((spaces+1 * 100) + (headers+1 * 38) + (lines * 15))
// Current max image spacing: (216*17)
{112, (16*100)+(19*38)+(100*15), "TYLER52", SKINCOLOR_NONE},
{112, (16*100)+(19*38)+(103*15), "TYLER52", SKINCOLOR_NONE},
{0, 0, NULL, SKINCOLOR_NONE}
};
......
......@@ -391,7 +391,7 @@ static CV_PossibleValue_t joyaxis_cons_t[] = {{0, "None"},
{7, "LAnalog"}, {8, "RAnalog"}, {-7, "LAnalog-"}, {-8, "RAnalog-"},
#endif
#else
{1, "X-Axis"}, {2, "Y-Axis"}, {-1, "X-Axis-"}, {-2, "Y-Axis-"},
{1, "Left X"}, {2, "Left Y"}, {-1, "Left X-"}, {-2, "Left Y-"},
#ifdef _arch_dreamcast
{3, "R-Trig"}, {4, "L-Trig"}, {-3, "R-Trig-"}, {-4, "L-Trig-"},
{5, "Alt X-Axis"}, {6, "Alt Y-Axis"}, {-5, "Alt X-Axis-"}, {-6, "Alt Y-Axis-"},
......@@ -400,10 +400,10 @@ static CV_PossibleValue_t joyaxis_cons_t[] = {{0, "None"},
{3, "Alt X-Axis"}, {4, "Alt Y-Axis"}, {-3, "Alt X-Axis-"}, {-4, "Alt Y-Axis-"},
#else
#if JOYAXISSET > 1
{3, "Z-Axis"}, {4, "X-Rudder"}, {-3, "Z-Axis-"}, {-4, "X-Rudder-"},
{3, "Right X"}, {4, "Right Y"}, {-3, "Right X-"}, {-4, "Right Y-"},
#endif
#if JOYAXISSET > 2
{5, "Y-Rudder"}, {6, "Z-Rudder"}, {-5, "Y-Rudder-"}, {-6, "Z-Rudder-"},
{5, "L Trigger"}, {6, "R Trigger"}, {-5, "L Trigger-"}, {-6, "R Trigger-"},
#endif
#if JOYAXISSET > 3
{7, "U-Axis"}, {8, "V-Axis"}, {-7, "U-Axis-"}, {-8, "V-Axis-"},
......@@ -486,43 +486,47 @@ consvar_t cv_useranalog3 = {"useranalog3", "Off", CV_SAVE|CV_CALL, CV_OnOff, Use
consvar_t cv_useranalog4 = {"useranalog4", "Off", CV_SAVE|CV_CALL, CV_OnOff, UserAnalog4_OnChange, 0, NULL, NULL, 0, 0, NULL};
#endif
consvar_t cv_turnaxis = {"joyaxis_turn", "X-Axis", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_turnaxis = {"joyaxis_turn", "Left X", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_moveaxis = {"joyaxis_move", "None", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_brakeaxis = {"joyaxis_brake", "None", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_aimaxis = {"joyaxis_aim", "Y-Axis", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_aimaxis = {"joyaxis_aim", "Left Y", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_lookaxis = {"joyaxis_look", "None", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_fireaxis = {"joyaxis_fire", "None", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_driftaxis = {"joyaxis_drift", "None", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_fireaxis = {"joyaxis_fire", "L Trigger", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_driftaxis = {"joyaxis_drift", "R Trigger", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_lookbackaxis = {"joyaxis_lookback", "None", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_xdeadzone = {"joy_xdeadzone", "0.3", CV_FLOAT|CV_SAVE, deadzone_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_ydeadzone = {"joy_ydeadzone", "0.5", CV_FLOAT|CV_SAVE, deadzone_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_turnaxis2 = {"joyaxis2_turn", "X-Axis", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_turnaxis2 = {"joyaxis2_turn", "Left X", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_moveaxis2 = {"joyaxis2_move", "None", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_brakeaxis2 = {"joyaxis2_brake", "None", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_aimaxis2 = {"joyaxis2_aim", "Y-Axis", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_aimaxis2 = {"joyaxis2_aim", "Left Y", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_lookaxis2 = {"joyaxis2_look", "None", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_fireaxis2 = {"joyaxis2_fire", "None", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_driftaxis2 = {"joyaxis2_drift", "None", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_fireaxis2 = {"joyaxis2_fire", "L Trigger", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_driftaxis2 = {"joyaxis2_drift", "R Trigger", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_lookbackaxis2 = {"joyaxis2_lookback", "None", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_xdeadzone2 = {"joy2_xdeadzone", "0.3", CV_FLOAT|CV_SAVE, deadzone_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_ydeadzone2 = {"joy2_ydeadzone", "0.5", CV_FLOAT|CV_SAVE, deadzone_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_turnaxis3 = {"joyaxis3_turn", "X-Axis", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_turnaxis3 = {"joyaxis3_turn", "Left X", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_moveaxis3 = {"joyaxis3_move", "None", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_brakeaxis3 = {"joyaxis3_brake", "None", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_aimaxis3 = {"joyaxis3_aim", "Y-Axis", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_aimaxis3 = {"joyaxis3_aim", "Left Y", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_lookaxis3 = {"joyaxis3_look", "None", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_fireaxis3 = {"joyaxis3_fire", "None", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_driftaxis3 = {"joyaxis3_drift", "None", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_fireaxis3 = {"joyaxis3_fire", "L Trigger", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_driftaxis3 = {"joyaxis3_drift", "R Trigger", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_lookbackaxis3 = {"joyaxis3_lookback", "None", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_xdeadzone3 = {"joy3_xdeadzone", "0.3", CV_FLOAT|CV_SAVE, deadzone_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_ydeadzone3 = {"joy3_ydeadzone", "0.5", CV_FLOAT|CV_SAVE, deadzone_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_turnaxis4 = {"joyaxis4_turn", "X-Axis", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_turnaxis4 = {"joyaxis4_turn", "Left X", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_moveaxis4 = {"joyaxis4_move", "None", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_brakeaxis4 = {"joyaxis4_brake", "None", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_aimaxis4 = {"joyaxis4_aim", "Y-Axis", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_aimaxis4 = {"joyaxis4_aim", "Left Y", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_lookaxis4 = {"joyaxis4_look", "None", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_fireaxis4 = {"joyaxis4_fire", "None", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_driftaxis4 = {"joyaxis4_drift", "None", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_fireaxis4 = {"joyaxis4_fire", "L Trigger", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_driftaxis4 = {"joyaxis4_drift", "R Trigger", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_lookbackaxis4 = {"joyaxis4_lookback", "None", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_xdeadzone4 = {"joy4_xdeadzone", "0.3", CV_FLOAT|CV_SAVE, deadzone_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_ydeadzone4 = {"joy4_ydeadzone", "0.5", CV_FLOAT|CV_SAVE, deadzone_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
......@@ -910,6 +914,9 @@ static INT32 Joy1Axis(axis_input_e axissel)
case AXISDRIFT:
axisval = cv_driftaxis.value;
break;
case AXISLOOKBACK:
axisval = cv_lookbackaxis.value;
break;
default:
return 0;
}
......@@ -1003,11 +1010,13 @@ static INT32 Joy2Axis(axis_input_e axissel)
case AXISDRIFT:
axisval = cv_driftaxis2.value;
break;
case AXISLOOKBACK:
axisval = cv_lookbackaxis2.value;
break;
default:
return 0;
}
if (axisval < 0) //odd -axises
{
axisval = -axisval;
......@@ -1099,11 +1108,13 @@ static INT32 Joy3Axis(axis_input_e axissel)
case AXISDRIFT:
axisval = cv_driftaxis3.value;
break;
case AXISLOOKBACK:
axisval = cv_lookbackaxis3.value;
break;
default:
return 0;
}
if (axisval < 0) //odd -axises
{
axisval = -axisval;
......@@ -1195,6 +1206,9 @@ static INT32 Joy4Axis(axis_input_e axissel)
case AXISDRIFT:
axisval = cv_driftaxis4.value;
break;
case AXISLOOKBACK:
axisval = cv_lookbackaxis4.value;
break;
default:
return 0;
}
......@@ -1489,22 +1503,20 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer)
{
cmd->buttons |= BT_ACCELERATE;
// JOYAXISRANGE is supposed to be 1023 (divide by 1024)
forward += ((axis * forwardmove[1]) >> 10)*2;
forward += ((axis * forwardmove[1]) / (JOYAXISRANGE-1));
}
axis = JoyAxis(AXISBRAKE, ssplayer);
if (InputDown(gc_brake, ssplayer) || (gamepadjoystickmove && axis > 0))
{
cmd->buttons |= BT_BRAKE;
if (cmd->buttons & BT_ACCELERATE || cmd->forwardmove <= 0)
forward -= forwardmove[0]; // 25 - Halved value so clutching is possible
forward -= forwardmove[0]; // 25 - Halved value so clutching is possible
}
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 * forwardmove[0]) >> 10);
forward -= ((axis * forwardmove[0]) / (JOYAXISRANGE-1));
}
// But forward/backward IS used for aiming.
......@@ -1645,7 +1657,8 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer)
keyboard_look[ssplayer-1] = kbl;
turnheld[ssplayer-1] = th;
resetdown[ssplayer-1] = rd;
camspin[ssplayer-1] = InputDown(gc_lookback, ssplayer);
axis = JoyAxis(AXISLOOKBACK, ssplayer);
camspin[ssplayer-1] = (InputDown(gc_lookback, ssplayer) || (usejoystick && axis > 0));
}
/* Lua: Allow this hook to overwrite ticcmd.
......@@ -3324,7 +3337,9 @@ void G_DoReborn(INT32 playernum)
// respawn at the start
mobj_t *oldmo = NULL;
if (player->starpostnum || ((mapheaderinfo[gamemap - 1]->levelflags & LF_SECTIONRACE) && player->laps)) // SRB2kart
if (player->spectator)
;
else if (player->starpostnum || ((mapheaderinfo[gamemap - 1]->levelflags & LF_SECTIONRACE) && player->laps)) // SRB2kart
starpost = true;
// first dissasociate the corpse
......@@ -3519,21 +3534,14 @@ UINT8 G_SometimesGetDifferentGametype(UINT8 prefgametype)
if (!cv_kartvoterulechanges.value) // never
return (gametype|encoremodifier);
if (randmapbuffer[NUMMAPS] > 0 && (encorepossible || cv_kartvoterulechanges.value != 3))
if (randmapbuffer[NUMMAPS] > 0 && (cv_kartvoterulechanges.value != 3)) // used to be (encorepossible || rule changes != 3)
{
randmapbuffer[NUMMAPS]--;
if (cv_kartvoterulechanges.value == 3) // always
{
randmapbuffer[NUMMAPS] = 0; // gotta prep this in case it isn't already set
}
return (gametype|encoremodifier);
}
switch (cv_kartvoterulechanges.value) // okay, we're having a gametype change! when's the next one, luv?
{
case 3: // always
randmapbuffer[NUMMAPS] = 1; // every other vote (or always if !encorepossible)
break;
case 1: // sometimes
randmapbuffer[NUMMAPS] = 5; // per "cup"
break;
......@@ -3545,10 +3553,15 @@ UINT8 G_SometimesGetDifferentGametype(UINT8 prefgametype)
}
// Only this response is prefgametype-based.
// Also intentionally does not use encoremodifier!
if (prefgametype == GT_MATCH)
{
// Intentionally does not use encoremodifier!
if (cv_kartencore.value)
return (GT_RACE|0x80);
return (GT_RACE);
return (GT_MATCH);
}
// This might appear wrong HERE, but the game will display the Encore possibility on the second voting choice instead.
return (GT_MATCH|encoremodifier);
}
//
......@@ -4851,6 +4864,242 @@ char *G_BuildMapTitle(INT32 mapnum)
return title;
}
static void measurekeywords(mapsearchfreq_t *fr,
struct searchdim **dimp, UINT8 *cuntp,
const char *s, const char *q, boolean wanttable)
{
char *qp;
char *sp;
if (wanttable)
(*dimp) = Z_Realloc((*dimp), 255 * sizeof (struct searchdim),
PU_STATIC, NULL);
for (qp = strtok(va("%s", q), " ");
qp && fr->total < 255;
qp = strtok(0, " "))
{
if (( sp = strcasestr(s, qp) ))
{
if (wanttable)
{
(*dimp)[(*cuntp)].pos = sp - s;
(*dimp)[(*cuntp)].siz = strlen(qp);
}
(*cuntp)++;
fr->total++;
}
}
if (wanttable)
(*dimp) = Z_Realloc((*dimp), (*cuntp) * sizeof (struct searchdim),
PU_STATIC, NULL);
}
static void writesimplefreq(mapsearchfreq_t *fr, INT32 *frc,
INT32 mapnum, UINT8 pos, UINT8 siz)
{
fr[(*frc)].mapnum = mapnum;
fr[(*frc)].matchd = ZZ_Alloc(sizeof (struct searchdim));
fr[(*frc)].matchd[0].pos = pos;
fr[(*frc)].matchd[0].siz = siz;
fr[(*frc)].matchc = 1;
fr[(*frc)].total = 1;
(*frc)++;
}
INT32 G_FindMap(const char *mapname, char **foundmapnamep,
mapsearchfreq_t **freqp, INT32 *freqcp)
{
INT32 newmapnum = 0;
INT32 mapnum;
INT32 apromapnum = 0;
size_t mapnamelen;
char *realmapname = NULL;
char *newmapname = NULL;
char *apromapname = NULL;
char *aprop = NULL;
mapsearchfreq_t *freq;
boolean wanttable;
INT32 freqc;
UINT8 frequ;
INT32 i;
mapnamelen = strlen(mapname);
/* Count available maps; how ugly. */
for (i = 0, freqc = 0; i < NUMMAPS; ++i)
{
if (mapheaderinfo[i])
freqc++;
}
freq = ZZ_Calloc(freqc * sizeof (mapsearchfreq_t));
wanttable = !!( freqp );
freqc = 0;
for (i = 0, mapnum = 1; i < NUMMAPS; ++i, ++mapnum)
if (mapheaderinfo[i])
{
if (!( realmapname = G_BuildMapTitle(mapnum) ))
continue;
aprop = realmapname;
/* Now that we found a perfect match no need to fucking guess. */
if (strnicmp(realmapname, mapname, mapnamelen) == 0)
{
if (wanttable)
{
writesimplefreq(freq, &freqc, mapnum, 0, mapnamelen);
}
if (newmapnum == 0)
{
newmapnum = mapnum;
newmapname = realmapname;
realmapname = 0;
Z_Free(apromapname);
if (!wanttable)
break;
}
}
else
if (apromapnum == 0 || wanttable)
{
/* LEVEL 1--match keywords verbatim */
if (( aprop = strcasestr(realmapname, mapname) ))
{
if (wanttable)
{
writesimplefreq(freq, &freqc,
mapnum, aprop - realmapname, mapnamelen);
}
if (apromapnum == 0)
{
apromapnum = mapnum;
apromapname = realmapname;
realmapname = 0;
}
}
else/* ...match individual keywords */
{
freq[freqc].mapnum = mapnum;
measurekeywords(&freq[freqc],
&freq[freqc].matchd, &freq[freqc].matchc,
realmapname, mapname, wanttable);
if (freq[freqc].total)
freqc++;
}
}
Z_Free(realmapname);/* leftover old name */
}
if (newmapnum == 0)/* no perfect match--try a substring */
{
newmapnum = apromapnum;
newmapname = apromapname;
}
if (newmapnum == 0)/* calculate most queries met! */
{
frequ = 0;
for (i = 0; i < freqc; ++i)
{
if (freq[i].total > frequ)
{
frequ = freq[i].total;
newmapnum = freq[i].mapnum;
}
}
if (newmapnum)
{
newmapname = G_BuildMapTitle(newmapnum);
}
}
if (freqp)
(*freqp) = freq;
else
Z_Free(freq);
if (freqcp)
(*freqcp) = freqc;
if (foundmapnamep)
(*foundmapnamep) = newmapname;
else
Z_Free(newmapname);
return newmapnum;
}
void G_FreeMapSearch(mapsearchfreq_t *freq, INT32 freqc)
{
INT32 i;
for (i = 0; i < freqc; ++i)
{
Z_Free(freq[i].matchd);
}
Z_Free(freq);
}
INT32 G_FindMapByNameOrCode(const char *mapname, char **realmapnamep)
{
boolean usemapcode = false;
INT32 newmapnum;
size_t mapnamelen;
char *p;
mapnamelen = strlen(mapname);
if (mapnamelen == 2)/* maybe two digit code */
{
if (( newmapnum = M_MapNumber(mapname[0], mapname[1]) ))
usemapcode = true;
}
else if (mapnamelen == 5 && strnicmp(mapname, "MAP", 3) == 0)
{
if (( newmapnum = M_MapNumber(mapname[3], mapname[4]) ))
usemapcode = true;
}
if (!usemapcode)
{
/* Now detect map number in base 10, which no one asked for. */
newmapnum = strtol(mapname, &p, 10);
if (*p == '\0')/* we got it */
{
if (newmapnum < 1 || newmapnum > NUMMAPS)
{
CONS_Alert(CONS_ERROR, M_GetText("Invalid map number %d.\n"), newmapnum);
return 0;
}
usemapcode = true;
}
else
{
newmapnum = G_FindMap(mapname, realmapnamep, NULL, NULL);
}
}
if (usemapcode)
{
/* we can't check mapheaderinfo for this hahahaha */
if (W_CheckNumForName(G_BuildMapName(newmapnum)) == LUMPERROR)
return 0;
if (realmapnamep)
(*realmapnamep) = G_BuildMapTitle(newmapnum);
}
return newmapnum;
}
//
// DEMO RECORDING
//
......@@ -6483,7 +6732,7 @@ void G_BeginRecording(void)
demoflags |= DF_ENCORE;
#ifdef HAVE_BLUA
if (!modeattacking) // Ghosts don't read luavars, and you shouldn't ever need to save Lua in replays, you doof!
if (!modeattacking && gL) // Ghosts don't read luavars, and you shouldn't ever need to save Lua in replays, you doof!
// SERIOUSLY THOUGH WHY WOULD YOU LOAD HOSTMOD AND RECORD A GHOST WITH IT !????
demoflags |= DF_LUAVARS;
#endif
......@@ -6496,7 +6745,11 @@ void G_BeginRecording(void)
// Full replay title
demo_p += 64;
snprintf(demo.titlename, 64, "%s - %s", G_BuildMapTitle(gamemap), modeattacking ? "Time Attack" : connectedservername);
{
char *title = G_BuildMapTitle(gamemap);
snprintf(demo.titlename, 64, "%s - %s", title, modeattacking ? "Time Attack" : connectedservername);
Z_Free(title);
}
// demo checksum
demo_p += 16;
......@@ -6518,7 +6771,7 @@ void G_BeginRecording(void)
if (wadfiles[i]->important)
{
nameonly(( filename = va("%s", wadfiles[i]->filename) ));
WRITESTRINGN(demo_p, filename, 64);
WRITESTRINGL(demo_p, filename, MAX_WADPATH);
WRITEMEM(demo_p, wadfiles[i]->md5sum, 16);
totalfiles++;
......@@ -6592,7 +6845,7 @@ void G_BeginRecording(void)
#ifdef HAVE_BLUA
// player lua vars, always saved even if empty... Unless it's record attack.
if (!modeattacking)
if (demoflags & DF_LUAVARS)
LUA_ArchiveDemo();
#endif
......@@ -6763,10 +7016,13 @@ static void G_LoadDemoExtraFiles(UINT8 **pp)
}
else
{
P_AddWadFile(filename);
P_PartialAddWadFile(filename);
}
}
}
if (P_PartialAddGetStage() >= 0)
P_MultiSetupWadFiles(true); // in case any partial adds were done
}
static void G_SkipDemoExtraFiles(UINT8 **pp)
......@@ -8345,7 +8601,7 @@ boolean G_CheckDemoStatus(void)
CONS_Printf(M_GetText("timed %u gametics in %d realtics\n%f seconds, %f avg fps\n"), leveltime,demotime,f1/TICRATE,f2/f1);
if (restorecv_vidwait != cv_vidwait.value)
CV_SetValue(&cv_vidwait, restorecv_vidwait);
D_AdvanceDemo();
D_StartTitle();
return true;
}
......@@ -8363,7 +8619,7 @@ boolean G_CheckDemoStatus(void)
if (modeattacking)
M_EndModeAttackRun();
else
D_AdvanceDemo();
D_StartTitle();
}
return true;
......
......@@ -118,10 +118,10 @@ extern consvar_t cv_invertmouse/*, cv_alwaysfreelook, cv_chasefreelook, cv_mouse
extern consvar_t cv_invertmouse2/*, cv_alwaysfreelook2, cv_chasefreelook2, cv_mousemove2*/;
extern consvar_t cv_useranalog, cv_useranalog2, cv_useranalog3, cv_useranalog4;
extern consvar_t cv_analog, cv_analog2, cv_analog3, cv_analog4;
extern consvar_t cv_turnaxis,cv_moveaxis,cv_brakeaxis,cv_aimaxis,cv_lookaxis,cv_fireaxis,cv_driftaxis,cv_xdeadzone,cv_ydeadzone;
extern consvar_t cv_turnaxis2,cv_moveaxis2,cv_brakeaxis2,cv_aimaxis2,cv_lookaxis2,cv_fireaxis2,cv_driftaxis2,cv_xdeadzone2,cv_ydeadzone2;
extern consvar_t cv_turnaxis3,cv_moveaxis3,cv_brakeaxis3,cv_aimaxis3,cv_lookaxis3,cv_fireaxis3,cv_driftaxis3,cv_xdeadzone3,cv_ydeadzone3;
extern consvar_t cv_turnaxis4,cv_moveaxis4,cv_brakeaxis4,cv_aimaxis4,cv_lookaxis4,cv_fireaxis4,cv_driftaxis4,cv_xdeadzone4,cv_ydeadzone4;
extern consvar_t cv_turnaxis,cv_moveaxis,cv_brakeaxis,cv_aimaxis,cv_lookaxis,cv_fireaxis,cv_driftaxis,cv_lookbackaxis,cv_xdeadzone,cv_ydeadzone;
extern consvar_t cv_turnaxis2,cv_moveaxis2,cv_brakeaxis2,cv_aimaxis2,cv_lookaxis2,cv_fireaxis2,cv_driftaxis2,cv_lookbackaxis2,cv_xdeadzone2,cv_ydeadzone2;
extern consvar_t cv_turnaxis3,cv_moveaxis3,cv_brakeaxis3,cv_aimaxis3,cv_lookaxis3,cv_fireaxis3,cv_driftaxis3,cv_lookbackaxis3,cv_xdeadzone3,cv_ydeadzone3;
extern consvar_t cv_turnaxis4,cv_moveaxis4,cv_brakeaxis4,cv_aimaxis4,cv_lookaxis4,cv_fireaxis4,cv_driftaxis4,cv_lookbackaxis4,cv_xdeadzone4,cv_ydeadzone4;
extern consvar_t cv_ghost_besttime, cv_ghost_bestlap, cv_ghost_last, cv_ghost_guest, cv_ghost_staff;
typedef enum
......@@ -135,6 +135,7 @@ typedef enum
AXISDEAD, //Axises that don't want deadzones
AXISFIRE,
AXISDRIFT,
AXISLOOKBACK,
} axis_input_e;
// mouseaiming (looking up/down with the mouse or keyboard)
......@@ -172,6 +173,30 @@ void G_InitNew(UINT8 pencoremode, const char *mapname, boolean resetplayer,
boolean skipprecutscene);
char *G_BuildMapTitle(INT32 mapnum);
struct searchdim
{
UINT8 pos;
UINT8 siz;
};
typedef struct
{
INT16 mapnum;
UINT8 matchc;
struct searchdim *matchd;/* offset that a pattern was matched */
UINT8 keywhc;
struct searchdim *keywhd;/* ...in KEYWORD */
UINT8 total;/* total hits */
}
mapsearchfreq_t;
INT32 G_FindMap(const char *query, char **foundmapnamep,
mapsearchfreq_t **freqp, INT32 *freqc);
void G_FreeMapSearch(mapsearchfreq_t *freq, INT32 freqc);
/* Match map name by search + 2 digit map code or map number. */
INT32 G_FindMapByNameOrCode(const char *query, char **foundmapnamep);
// XMOD spawning
mapthing_t *G_FindCTFStart(INT32 playernum);
mapthing_t *G_FindMatchStart(INT32 playernum);
......
......@@ -1311,8 +1311,8 @@ void G_Controldefault(UINT8 player)
gamecontrol[gc_accelerate ][1] = KEY_JOY1+0; // A
gamecontrol[gc_lookback ][1] = KEY_JOY1+2; // X
gamecontrol[gc_brake ][1] = KEY_JOY1+1; // B
gamecontrol[gc_fire ][1] = KEY_JOY1+4; // LB
gamecontrol[gc_drift ][1] = KEY_JOY1+5; // RB
gamecontrol[gc_fire ][1] = KEY_JOY1+9; // LB
gamecontrol[gc_drift ][1] = KEY_JOY1+10; // RB
// Extra controls
gamecontrol[gc_pause ][0] = KEY_PAUSE;
......@@ -1331,8 +1331,8 @@ void G_Controldefault(UINT8 player)
gamecontrol[gc_camtoggle ][0] = KEY_BACKSPACE;
gamecontrol[gc_viewpoint ][1] = KEY_JOY1+3; // Y
gamecontrol[gc_pause ][1] = KEY_JOY1+6; // Back
gamecontrol[gc_systemmenu ][0] = KEY_JOY1+7; // Start
gamecontrol[gc_pause ][1] = KEY_JOY1+4; // Back
gamecontrol[gc_systemmenu ][0] = KEY_JOY1+6; // Start
//gamecontrol[gc_camtoggle ][1] = KEY_HAT1+0; // D-Pad Up
//gamecontrol[gc_screenshot ][1] = KEY_HAT1+1; // D-Pad Down // absolutely fucking NOT
gamecontrol[gc_talkkey ][1] = KEY_HAT1+1; // D-Pad Down
......@@ -1345,8 +1345,8 @@ void G_Controldefault(UINT8 player)
gamecontrolbis[gc_accelerate ][0] = KEY_2JOY1+0; // A
gamecontrolbis[gc_lookback ][0] = KEY_2JOY1+2; // X
gamecontrolbis[gc_brake ][0] = KEY_2JOY1+1; // B
gamecontrolbis[gc_fire ][0] = KEY_2JOY1+4; // LB
gamecontrolbis[gc_drift ][0] = KEY_2JOY1+5; // RB
gamecontrolbis[gc_fire ][0] = KEY_2JOY1+9; // LB
gamecontrolbis[gc_drift ][0] = KEY_2JOY1+10; // RB
}
if (player == 0 || player == 3)
......@@ -1355,8 +1355,8 @@ void G_Controldefault(UINT8 player)
gamecontrol3[gc_accelerate ][0] = KEY_3JOY1+0; // A
gamecontrol3[gc_lookback ][0] = KEY_3JOY1+2; // X
gamecontrol3[gc_brake ][0] = KEY_3JOY1+1; // B
gamecontrol3[gc_fire ][0] = KEY_3JOY1+4; // LB
gamecontrol3[gc_drift ][0] = KEY_3JOY1+5; // RB
gamecontrol3[gc_fire ][0] = KEY_3JOY1+9; // LB
gamecontrol3[gc_drift ][0] = KEY_3JOY1+10; // RB
}
if (player == 0 || player == 4)
......@@ -1365,8 +1365,8 @@ void G_Controldefault(UINT8 player)
gamecontrol4[gc_accelerate ][0] = KEY_4JOY1+0; // A
gamecontrol4[gc_lookback ][0] = KEY_4JOY1+2; // X
gamecontrol4[gc_brake ][0] = KEY_4JOY1+1; // B
gamecontrol4[gc_fire ][0] = KEY_4JOY1+4; // LB
gamecontrol4[gc_drift ][0] = KEY_4JOY1+5; // RB
gamecontrol4[gc_fire ][0] = KEY_4JOY1+9; // LB
gamecontrol4[gc_drift ][0] = KEY_4JOY1+10; // RB
}
}
......@@ -1455,25 +1455,51 @@ INT32 G_CheckDoubleUsage(INT32 keynum, boolean modify)
static INT32 G_FilterKeyByVersion(INT32 numctrl, INT32 keyidx, INT32 player, INT32 *keynum1, INT32 *keynum2, boolean *nestedoverride)
{
// Special case: ignore KEY_PAUSE because it's hardcoded
if (keyidx == 0 && *keynum1 == KEY_PAUSE)
#if 1 // SRB2Kart filters/migrations
(void)nestedoverride;
// Migration: 1.6 (majorexec 10) Joystick Defaults changed to use SDL Game Controllers
if (GETMAJOREXECVERSION(cv_execversion.value) < 10)
{
if (*keynum2 != KEY_PAUSE)
INT32 joybuttonbase = KEY_JOY1;
switch (player)
{
*keynum1 = *keynum2; // shift down keynum2 and continue
*keynum2 = 0;
case 0:
joybuttonbase = KEY_JOY1;
break;
case 1:
joybuttonbase = KEY_2JOY1;
break;
case 2:
joybuttonbase = KEY_3JOY1;
break;
case 3:
joybuttonbase = KEY_4JOY1;
break;
}
else
return -1; // skip setting control
}
else if (keyidx == 1 && *keynum2 == KEY_PAUSE)
return -1; // skip setting control
#if 1
// We don't have changed control defaults yet
(void)numctrl;
(void)player;
(void)nestedoverride;
// The face buttons match, so we don't need to rebind those.
if (keyidx == 1 && numctrl == gc_fire && *keynum2 == joybuttonbase + 4) // Xbox DInput LB
{
*keynum2 = joybuttonbase + 9; // SDL LEFTSHOULDER
}
if (keyidx == 1 && numctrl == gc_drift && *keynum2 == joybuttonbase + 5) // Xbox DInput RB
{
*keynum2 = joybuttonbase + 10; // SDL RIGHTSHOULDER
}
// Pause and Systemmenu are only bound for P1
if (keyidx == 1 && player == 0 && numctrl == gc_pause && *keynum2 == joybuttonbase + 6) // Xbox DInput Back
{
*keynum2 = joybuttonbase + 4; // SDL BACK
}
if (keyidx == 0 && player == 0 && numctrl == gc_systemmenu && *keynum1 == joybuttonbase + 7) // Xbox DInput Start
{
*keynum1 = joybuttonbase + 6; // SDL START
}
}
#else
#if !defined (DC) && !defined (_PSP) && !defined (GP2X) && !defined (_NDS) && !defined(WMINPUT) && !defined(_WII)
if (GETMAJOREXECVERSION(cv_execversion.value) < 27 && ( // v2.1.22
......
......@@ -479,14 +479,43 @@ void HWR_InitTextureCache(void)
// Callback function for HWR_FreeTextureCache.
static void FreeMipmapColormap(INT32 patchnum, void *patch)
{
GLPatch_t* const grpatch = patch;
GLPatch_t* const pat = patch;
(void)patchnum; //unused
while (grpatch->mipmap->nextcolormap)
// The patch must be valid, obviously
if (!pat)
return;
// The mipmap must be valid, obviously
while (pat->mipmap)
{
GLMipmap_t *grmip = grpatch->mipmap->nextcolormap;
grpatch->mipmap->nextcolormap = grmip->nextcolormap;
if (grmip->grInfo.data) Z_Free(grmip->grInfo.data);
free(grmip);
// Confusing at first, but pat->mipmap->nextcolormap
// at the beginning of the loop is the first colormap
// from the linked list of colormaps.
GLMipmap_t *next = NULL;
// No mipmap in this patch, break out of the loop.
if (!pat->mipmap)
break;
// No colormap mipmaps either.
if (!pat->mipmap->nextcolormap)
break;
// Set the first colormap to the one that comes after it.
next = pat->mipmap->nextcolormap;
if (!next)
break;
pat->mipmap->nextcolormap = next->nextcolormap;
// Free image data from memory.
if (next->grInfo.data)
Z_Free(next->grInfo.data);
next->grInfo.data = NULL;
// Free the old colormap mipmap from memory.
free(next);
}
}
......@@ -503,7 +532,7 @@ void HWR_FreeTextureCache(void)
// Alam: free the Z_Blocks before freeing it's users
// free all skin after each level: must be done after pfnClearMipMapCache!
// free all patch colormaps after each level: must be done after ClearMipMapCache!
for (i = 0; i < numwadfiles; i++)
M_AATreeIterate(wadfiles[i]->hwrcache, FreeMipmapColormap);
......