diff --git a/SRB2.cbp b/SRB2.cbp
index 2a1eb87b8..acdc61c7f 100644
--- a/SRB2.cbp
+++ b/SRB2.cbp
@@ -1545,6 +1545,10 @@ HW3SOUND for 3D hardware sound support
+
+
+
+
diff --git a/src/config.h.in b/src/config.h.in
index dd86966e1..cb343d065 100644
--- a/src/config.h.in
+++ b/src/config.h.in
@@ -36,8 +36,8 @@
/* Manually defined asset hashes for non-CMake builds
* Last updated 2015 / 05 / 03 - SRB2 v2.1.15 - srb2.srb
* Last updated 2018 / 12 / 23 - SRB2 v2.1.22 - patch.dta
- * Last updated 2018 / 11 / 16 - Kart v1.0.0 - Main assets
- * Last updated 2018 / 12 / 13 - Kart v1.0.2 - patch.kart
+ * Last updated 2019 / 01 / 18 - Kart v1.0.2 - Main assets
+ * Last updated 2019 / 01 / 15 - Kart v1.0.2 - patch.kart
*/
// Base SRB2 hashes
@@ -49,10 +49,10 @@
// SRB2Kart-specific hashes
#define ASSET_HASH_GFX_KART "99c39f223d84ebc78e67ab68f3bead95"
#define ASSET_HASH_TEXTURES_KART "ec8e9b7535cf585afe72ef277b08f490"
-#define ASSET_HASH_CHARS_KART "784ee9177b01c8cb26edff43eaf93d87"
-#define ASSET_HASH_MAPS_KART "84018d9b35d181ca9fcc2be5a9d43a45"
+#define ASSET_HASH_CHARS_KART "e2c428347dde52858a3dacd29fc5b964"
+#define ASSET_HASH_MAPS_KART "1335cd064656aedca359cfbb5233ac4a"
#ifdef USE_PATCH_KART
-#define ASSET_HASH_PATCH_KART "843a13a73935dc4df721427a8948fb89"
+#define ASSET_HASH_PATCH_KART "899aee1b63e731b7e2098406c85608b4"
#endif
#endif
diff --git a/src/d_clisrv.c b/src/d_clisrv.c
index 9f65fdf8b..c84faa721 100644
--- a/src/d_clisrv.c
+++ b/src/d_clisrv.c
@@ -2076,8 +2076,8 @@ static boolean CL_ServerConnectionTicker(boolean viams, const char *tmpsave, tic
I_OsPolling();
key = I_GetKey();
- // Any key can be used to abort network connection
- if (key != KEY_NULL)
+ // Only ESC and non-keyboard keys abort connection
+ if (key == KEY_ESCAPE || key >= KEY_MOUSE1)
{
CONS_Printf(M_GetText("Network game synchronization aborted.\n"));
// M_StartMessage(M_GetText("Network game synchronization aborted.\n\nPress ESC\n"), NULL, MM_NOTHING);
@@ -3025,6 +3025,9 @@ static void Got_KickCmd(UINT8 **p, INT32 playernum)
}
}
+static CV_PossibleValue_t netticbuffer_cons_t[] = {{0, "MIN"}, {3, "MAX"}, {0, NULL}};
+consvar_t cv_netticbuffer = {"netticbuffer", "1", CV_SAVE, netticbuffer_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
+
consvar_t cv_allownewplayer = {"allowjoin", "On", CV_NETVAR, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL };
#ifdef VANILLAJOINNEXTROUND
consvar_t cv_joinnextround = {"joinnextround", "Off", CV_NETVAR, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; /// \todo not done
@@ -3080,7 +3083,6 @@ void D_ClientServerInit(void)
CV_RegisterVar(&cv_joinnextround);
#endif
CV_RegisterVar(&cv_showjoinaddress);
- CV_RegisterVar(&cv_resynchattempts);
CV_RegisterVar(&cv_blamecfail);
#ifdef DUMPCONSISTENCY
CV_RegisterVar(&cv_dumpconsistency);
@@ -3883,6 +3885,32 @@ static void HandlePacketFromAwayNode(SINT8 node)
#undef SERVERONLY
}
+/** Checks ticcmd for "speed hacks"
+ *
+ * \param p Which player
+ * \return True if player is hacking
+ * \sa HandlePacketFromPlayer
+ *
+ */
+static boolean CheckForSpeedHacks(UINT8 p)
+{
+ if (netcmds[maketic%BACKUPTICS][p].forwardmove > MAXPLMOVE || netcmds[maketic%BACKUPTICS][p].forwardmove < -MAXPLMOVE
+ || netcmds[maketic%BACKUPTICS][p].sidemove > MAXPLMOVE || netcmds[maketic%BACKUPTICS][p].sidemove < -MAXPLMOVE
+ || netcmds[maketic%BACKUPTICS][p].driftturn > KART_FULLTURN || netcmds[maketic%BACKUPTICS][p].driftturn < -KART_FULLTURN)
+ {
+ XBOXSTATIC char buf[2];
+ CONS_Alert(CONS_WARNING, M_GetText("Illegal movement value received from node %d\n"), playernode[p]);
+ //D_Clearticcmd(k);
+
+ buf[0] = (char)p;
+ buf[1] = KICK_MSG_CON_FAIL;
+ SendNetXCmd(XD_KICK, &buf, 2);
+ return true;
+ }
+
+ return false;
+}
+
/** Handles a packet received from a node that is in game
*
* \param node The packet sender
@@ -3977,18 +4005,8 @@ FILESTAMP
G_MoveTiccmd(&netcmds[maketic%BACKUPTICS][netconsole], &netbuffer->u.clientpak.cmd, 1);
// Check ticcmd for "speed hacks"
- if (netcmds[maketic%BACKUPTICS][netconsole].forwardmove > MAXPLMOVE || netcmds[maketic%BACKUPTICS][netconsole].forwardmove < -MAXPLMOVE
- || netcmds[maketic%BACKUPTICS][netconsole].sidemove > MAXPLMOVE || netcmds[maketic%BACKUPTICS][netconsole].sidemove < -MAXPLMOVE)
- {
- XBOXSTATIC char buf[2];
- CONS_Alert(CONS_WARNING, M_GetText("Illegal movement value received from node %d\n"), netconsole);
- //D_Clearticcmd(k);
-
- buf[0] = (char)netconsole;
- buf[1] = KICK_MSG_CON_FAIL;
- SendNetXCmd(XD_KICK, &buf, 2);
+ if (CheckForSpeedHacks((UINT8)netconsole))
break;
- }
// Splitscreen cmd
if (((netbuffer->packettype == PT_CLIENT2CMD || netbuffer->packettype == PT_CLIENT2MIS)
@@ -3998,6 +4016,9 @@ FILESTAMP
{
G_MoveTiccmd(&netcmds[maketic%BACKUPTICS][(UINT8)nodetoplayer2[node]],
&netbuffer->u.client2pak.cmd2, 1);
+
+ if (CheckForSpeedHacks((UINT8)nodetoplayer2[node]))
+ break;
}
if (((netbuffer->packettype == PT_CLIENT3CMD || netbuffer->packettype == PT_CLIENT3MIS)
@@ -4006,6 +4027,9 @@ FILESTAMP
{
G_MoveTiccmd(&netcmds[maketic%BACKUPTICS][(UINT8)nodetoplayer3[node]],
&netbuffer->u.client3pak.cmd3, 1);
+
+ if (CheckForSpeedHacks((UINT8)nodetoplayer3[node]))
+ break;
}
if ((netbuffer->packettype == PT_CLIENT4CMD || netbuffer->packettype == PT_CLIENT4MIS)
@@ -4013,6 +4037,9 @@ FILESTAMP
{
G_MoveTiccmd(&netcmds[maketic%BACKUPTICS][(UINT8)nodetoplayer4[node]],
&netbuffer->u.client4pak.cmd4, 1);
+
+ if (CheckForSpeedHacks((UINT8)nodetoplayer4[node]))
+ break;
}
// A delay before we check resynching
@@ -4933,6 +4960,10 @@ void TryRunTics(tic_t realtics)
ExtraDataTicker();
gametic++;
consistancy[gametic%BACKUPTICS] = 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;
}
}
else
diff --git a/src/d_clisrv.h b/src/d_clisrv.h
index f1abffaf2..39cb8c4de 100644
--- a/src/d_clisrv.h
+++ b/src/d_clisrv.h
@@ -433,10 +433,10 @@ typedef struct
UINT8 reserved; // Padding
union
{
- clientcmd_pak clientpak; // 144 bytes
- client2cmd_pak client2pak; // 200 bytes
- client3cmd_pak client3pak; // 256 bytes(?)
- client4cmd_pak client4pak; // 312 bytes(?)
+ clientcmd_pak clientpak; // 145 bytes
+ client2cmd_pak client2pak; // 202 bytes
+ client3cmd_pak client3pak; // 258 bytes(?)
+ client4cmd_pak client4pak; // 316 bytes(?)
servertics_pak serverpak; // 132495 bytes (more around 360, no?)
serverconfig_pak servercfg; // 773 bytes
resynchend_pak resynchend; //
@@ -524,7 +524,7 @@ extern consvar_t
#ifdef VANILLAJOINNEXTROUND
cv_joinnextround,
#endif
- cv_allownewplayer, cv_maxplayers, cv_resynchattempts, cv_blamecfail, cv_maxsend, cv_noticedownload, cv_downloadspeed;
+ cv_netticbuffer, cv_allownewplayer, cv_maxplayers, cv_resynchattempts, cv_blamecfail, cv_maxsend, cv_noticedownload, cv_downloadspeed;
// Used in d_net, the only dependence
tic_t ExpandTics(INT32 low);
diff --git a/src/d_netcmd.c b/src/d_netcmd.c
index 617ff78f3..1da2c5234 100644
--- a/src/d_netcmd.c
+++ b/src/d_netcmd.c
@@ -357,7 +357,7 @@ consvar_t cv_kartfrantic = {"kartfrantic", "Off", CV_NETVAR|CV_CHEAT|CV_CALL|CV_
consvar_t cv_kartcomeback = {"kartcomeback", "On", CV_NETVAR|CV_CHEAT|CV_CALL|CV_NOINIT, CV_OnOff, KartComeback_OnChange, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_kartencore = {"kartencore", "Off", CV_NETVAR|CV_CALL|CV_NOINIT, CV_OnOff, KartEncore_OnChange, 0, NULL, NULL, 0, 0, NULL};
static CV_PossibleValue_t kartvoterulechanges_cons_t[] = {{0, "Never"}, {1, "Sometimes"}, {2, "Frequent"}, {3, "Always"}, {0, NULL}};
-consvar_t cv_kartvoterulechanges = {"kartvoterulechanges", "Sometimes", CV_NETVAR, kartvoterulechanges_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_kartvoterulechanges = {"kartvoterulechanges", "Frequent", CV_NETVAR, kartvoterulechanges_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
static CV_PossibleValue_t kartspeedometer_cons_t[] = {{0, "Off"}, {1, "Kilometers"}, {2, "Miles"}, {3, "Fracunits"}, {0, NULL}};
consvar_t cv_kartspeedometer = {"kartdisplayspeed", "Off", CV_SAVE, kartspeedometer_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; // use tics in display
static CV_PossibleValue_t kartvoices_cons_t[] = {{0, "Never"}, {1, "Tasteful"}, {2, "Meme"}, {0, NULL}};
@@ -483,6 +483,7 @@ const char *netxcmdnames[MAXNETXCMD - 1] =
"SETUPVOTE",
"MODIFYVOTE",
"PICKVOTE",
+ "REMOVEPLAYER",
#ifdef HAVE_BLUA
"LUACMD",
"LUAVAR"
@@ -646,6 +647,7 @@ void D_RegisterServerCommands(void)
// d_clisrv
CV_RegisterVar(&cv_maxplayers);
+ CV_RegisterVar(&cv_resynchattempts);
CV_RegisterVar(&cv_maxsend);
CV_RegisterVar(&cv_noticedownload);
CV_RegisterVar(&cv_downloadspeed);
@@ -761,6 +763,7 @@ void D_RegisterClientCommands(void)
#endif
CV_RegisterVar(&cv_rollingdemos);
CV_RegisterVar(&cv_netstat);
+ CV_RegisterVar(&cv_netticbuffer);
#ifdef NETGAME_DEVMODE
CV_RegisterVar(&cv_fishcake);
@@ -839,14 +842,6 @@ void D_RegisterClientCommands(void)
CV_RegisterVar(&cv_addons_search_type);
CV_RegisterVar(&cv_addons_search_case);
- // filesrch.c
- CV_RegisterVar(&cv_addons_option);
- CV_RegisterVar(&cv_addons_folder);
- CV_RegisterVar(&cv_addons_md5);
- CV_RegisterVar(&cv_addons_showall);
- CV_RegisterVar(&cv_addons_search_type);
- CV_RegisterVar(&cv_addons_search_case);
-
// WARNING: the order is important when initialising mouse2
// we need the mouse2port
CV_RegisterVar(&cv_mouse2port);
diff --git a/src/d_netcmd.h b/src/d_netcmd.h
index 7927aea00..2269996fb 100644
--- a/src/d_netcmd.h
+++ b/src/d_netcmd.h
@@ -33,6 +33,8 @@ extern consvar_t cv_skin3;
extern consvar_t cv_playername4;
extern consvar_t cv_playercolor4;
extern consvar_t cv_skin4;
+// preferred number of players
+extern consvar_t cv_splitplayers;
#ifdef SEENAMES
extern consvar_t cv_seenames, cv_allowseenames;
diff --git a/src/d_player.h b/src/d_player.h
index 2d9ed5c82..27fdef8dc 100644
--- a/src/d_player.h
+++ b/src/d_player.h
@@ -416,6 +416,8 @@ typedef struct player_s
// SRB2kart stuff
INT32 kartstuff[NUMKARTSTUFF];
angle_t frameangle; // for the player add the ability to have the sprite only face other angles
+ INT16 lturn_max[MAXPREDICTTICS]; // What's the expected turn value for full-left for a number of frames back (to account for netgame latency)?
+ INT16 rturn_max[MAXPREDICTTICS]; // Ditto but for full-right
// Bit flags.
// See pflags_t, above.
diff --git a/src/d_ticcmd.h b/src/d_ticcmd.h
index 7df2d4122..dab758f8d 100644
--- a/src/d_ticcmd.h
+++ b/src/d_ticcmd.h
@@ -21,6 +21,8 @@
#pragma interface
#endif
+#define MAXPREDICTTICS 12
+
// Button/action code definitions.
typedef enum
{
@@ -60,6 +62,7 @@ typedef struct
INT16 aiming; // vertical aiming, see G_BuildTicCmd
UINT16 buttons;
INT16 driftturn; // SRB2Kart: Used for getting drift turn speed
+ UINT8 latency; // Netgames: how many tics ago was this ticcmd generated from this player's end?
} ATTRPACK ticcmd_t;
#if defined(_MSC_VER)
diff --git a/src/dehacked.c b/src/dehacked.c
index 8bb2d5676..835502820 100644
--- a/src/dehacked.c
+++ b/src/dehacked.c
@@ -435,11 +435,11 @@ static void readAnimTex(MYFILE *f, INT32 num)
static boolean findFreeSlot(INT32 *num)
{
// Send the character select entry to a free slot.
- while (*num < 32 && PlayerMenu[*num].status != IT_DISABLED)
+ while (*num < MAXSKINS && PlayerMenu[*num].status != IT_DISABLED)
*num = *num+1;
// No more free slots. :(
- if (*num >= 32)
+ if (*num >= MAXSKINS)
return false;
// Found one! ^_^
@@ -3741,7 +3741,8 @@ static void DEH_LoadDehackedFile(MYFILE *f, UINT16 wad)
}
else if (fastcmp(word, "SRB2"))
{
- deh_warning("Patch is only compatible with base SRB2.");
+ if (mainwads) // srb2.srb triggers this warning otherwise
+ deh_warning("Patch is only compatible with base SRB2.");
}
// Clear all data in certain locations (mostly for unlocks)
// Unless you REALLY want to piss people off,
diff --git a/src/doomdef.h b/src/doomdef.h
index c44e70c00..70e521b15 100644
--- a/src/doomdef.h
+++ b/src/doomdef.h
@@ -244,7 +244,7 @@ extern FILE *logstream;
// NOTE: it needs more than this to increase the number of players...
#define MAXPLAYERS 16
-#define MAXSKINS 32
+#define MAXSKINS 64
#define PLAYERSMASK (MAXPLAYERS-1)
#define MAXPLAYERNAME 21
diff --git a/src/f_finale.c b/src/f_finale.c
index b398c0ef2..0fe13a8c9 100644
--- a/src/f_finale.c
+++ b/src/f_finale.c
@@ -438,7 +438,7 @@ static const char *credits[] = {
"\"ZarroTsu\"",
"",
"\1Support Programming",
- "\"fickle\"",
+ "Colette \"fickleheart\" Bordelon",
"\"Lat\'\"",
"\"Monster Iestyn\"",
"\"Shuffle\"",
diff --git a/src/g_game.c b/src/g_game.c
index 60fd56cbe..e347cf7c5 100644
--- a/src/g_game.c
+++ b/src/g_game.c
@@ -1216,7 +1216,7 @@ boolean camspin, camspin2, camspin3, camspin4;
static fixed_t forwardmove[2] = {25<>16, 50<>16};
static fixed_t sidemove[2] = {2<>16, 4<>16};
-static fixed_t angleturn[3] = {400, 800, 200}; // + slow turn
+static fixed_t angleturn[3] = {KART_FULLTURN/2, KART_FULLTURN, KART_FULLTURN/4}; // + slow turn
void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer)
{
@@ -1359,41 +1359,30 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer)
// let movement keys cancel each other out
if (turnright && !(turnleft))
{
- cmd->angleturn = (INT16)(cmd->angleturn - (angleturn[tspeed] * realtics));
- cmd->driftturn = (INT16)(cmd->driftturn - (angleturn[tspeed] * realtics));
+ cmd->angleturn = (INT16)(cmd->angleturn - (angleturn[tspeed]));
+ cmd->driftturn = (INT16)(cmd->driftturn - (angleturn[tspeed]));
+ side += sidemove[1];
}
else if (turnleft && !(turnright))
{
- cmd->angleturn = (INT16)(cmd->angleturn + (angleturn[tspeed] * realtics));
- cmd->driftturn = (INT16)(cmd->driftturn + (angleturn[tspeed] * realtics));
+ cmd->angleturn = (INT16)(cmd->angleturn + (angleturn[tspeed]));
+ cmd->driftturn = (INT16)(cmd->driftturn + (angleturn[tspeed]));
+ side -= sidemove[1];
}
if (analogjoystickmove && axis != 0)
{
// JOYAXISRANGE should be 1023 (divide by 1024)
- cmd->angleturn = (INT16)(cmd->angleturn - (((axis * angleturn[1]) >> 10) * realtics)); // ANALOG!
- cmd->driftturn = (INT16)(cmd->driftturn - (((axis * angleturn[1]) >> 10) * realtics));
+ cmd->angleturn = (INT16)(cmd->angleturn - (((axis * angleturn[1]) >> 10))); // ANALOG!
+ cmd->driftturn = (INT16)(cmd->driftturn - (((axis * angleturn[1]) >> 10)));
+ side += ((axis * sidemove[0]) >> 10);
}
// Specator mouse turning
if (player->spectator)
{
- cmd->angleturn = (INT16)(cmd->angleturn - ((mousex*(encoremode ? -1 : 1)*8) * realtics));
- cmd->driftturn = (INT16)(cmd->driftturn - ((mousex*(encoremode ? -1 : 1)*8) * realtics));
- }
-
- // Speed bump strafing
- if (!demoplayback && ((player->pflags & PF_FORCESTRAFE) || (player->kartstuff[k_pogospring])))
- {
- if (turnright)
- side += sidemove[1];
- if (turnleft)
- side -= sidemove[1];
- if (analogjoystickmove && axis != 0)
- {
- // JOYAXISRANGE is supposed to be 1023 (divide by 1024)
- side += ((axis * sidemove[0]) >> 10);
- }
+ cmd->angleturn = (INT16)(cmd->angleturn - ((mousex*(encoremode ? -1 : 1)*8)));
+ cmd->driftturn = (INT16)(cmd->driftturn - ((mousex*(encoremode ? -1 : 1)*8)));
}
if (player->spectator || objectplacing) // SRB2Kart: spectators need special controls
@@ -1538,15 +1527,6 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer)
else if (side < -MAXPLMOVE)
side = -MAXPLMOVE;
- // No additional acceleration when moving forward/backward and strafing simultaneously.
- // do this AFTER we cap to MAXPLMOVE so people can't find ways to cheese around this.
- // SRB2Kart: We don't need this; we WANT bounce strafing to plain stack on top of normal movement.
- /*if (!bouncestrafe && forward && side)
- {
- forward = FixedMul(forward, 3*FRACUNIT/4);
- side = FixedMul(side, 3*FRACUNIT/4);
- }*/
-
if (forward || side)
{
cmd->forwardmove = (SINT8)(cmd->forwardmove + forward);
@@ -1556,19 +1536,21 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer)
//{ SRB2kart - Drift support
// Not grouped with the rest of turn stuff because it needs to know what buttons you're pressing for rubber-burn turn
// limit turning to angleturn[1] to stop mouselook letting you look too fast
- if (cmd->angleturn > (angleturn[1] * realtics))
- cmd->angleturn = (angleturn[1] * realtics);
- else if (cmd->angleturn < (-angleturn[1] * realtics))
- cmd->angleturn = (-angleturn[1] * realtics);
+ if (cmd->angleturn > (angleturn[1]))
+ cmd->angleturn = (angleturn[1]);
+ else if (cmd->angleturn < (-angleturn[1]))
+ cmd->angleturn = (-angleturn[1]);
- if (cmd->driftturn > (angleturn[1] * realtics))
- cmd->driftturn = (angleturn[1] * realtics);
- else if (cmd->driftturn < (-angleturn[1] * realtics))
- cmd->driftturn = (-angleturn[1] * realtics);
+ if (cmd->driftturn > (angleturn[1]))
+ cmd->driftturn = (angleturn[1]);
+ else if (cmd->driftturn < (-angleturn[1]))
+ cmd->driftturn = (-angleturn[1]);
if (player->mo)
cmd->angleturn = K_GetKartTurnValue(player, cmd->angleturn);
+ cmd->angleturn *= realtics;
+
// SRB2kart - no additional angle if not moving
if (((player->mo && player->speed > 0) // Moving
|| (leveltime > starttime && (cmd->buttons & BT_ACCELERATE && cmd->buttons & BT_BRAKE)) // Rubber-burn turn
@@ -1578,6 +1560,7 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer)
lang += (cmd->angleturn<<16);
cmd->angleturn = (INT16)(lang >> 16);
+ cmd->latency = modeattacking ? 0 : (leveltime & 0xFF); // Send leveltime when this tic was generated to the server for control lag calculations
if (!hu_stopped)
{
@@ -2161,6 +2144,9 @@ void G_Ticker(boolean run)
players[i].kartstuff[k_throwdir] = 0;
G_CopyTiccmd(cmd, &netcmds[buf][i], 1);
+
+ // Use the leveltime sent in the player's ticcmd to determine control lag
+ cmd->latency = modeattacking ? 0 : min((leveltime & 0xFF) - cmd->latency, MAXPREDICTTICS-1); //@TODO add a cvar to allow setting this max
}
}
@@ -3180,7 +3166,7 @@ INT16 G_SometimesGetDifferentGametype(void)
break;
case 1: // sometimes
default:
- encorepossible = M_RandomChance(FRACUNIT>>3);
+ encorepossible = M_RandomChance(FRACUNIT>>2);
break;
}
if (encorepossible != (boolean)cv_kartencore.value)
@@ -3195,12 +3181,12 @@ INT16 G_SometimesGetDifferentGametype(void)
randmapbuffer[NUMMAPS] = 1; // every other vote (or always if !encorepossible)
break;
case 1: // sometimes
- randmapbuffer[NUMMAPS] = 10; // ...every two cups?
+ randmapbuffer[NUMMAPS] = 5; // per "cup"
break;
default:
// fallthrough - happens when clearing buffer, but needs a reasonable countdown if cvar is modified
case 2: // frequent
- randmapbuffer[NUMMAPS] = 5; // per "cup"
+ randmapbuffer[NUMMAPS] = 2; // ...every 1/2th-ish cup?
break;
}
@@ -4568,6 +4554,7 @@ ticcmd_t *G_MoveTiccmd(ticcmd_t* dest, const ticcmd_t* src, const size_t n)
dest[i].aiming = (INT16)SHORT(src[i].aiming);
dest[i].buttons = (UINT16)SHORT(src[i].buttons);
dest[i].driftturn = (INT16)SHORT(src[i].driftturn);
+ dest[i].latency = (INT16)SHORT(src[i].latency);
}
return dest;
}
diff --git a/src/g_game.h b/src/g_game.h
index 793cfe956..fc7a4a4f5 100644
--- a/src/g_game.h
+++ b/src/g_game.h
@@ -66,7 +66,6 @@ extern consvar_t cv_turnaxis2,cv_moveaxis2,cv_brakeaxis2,cv_aimaxis2,cv_lookaxis
extern consvar_t cv_turnaxis3,cv_moveaxis3,cv_brakeaxis3,cv_aimaxis3,cv_lookaxis3,cv_fireaxis3,cv_driftaxis3;
extern consvar_t cv_turnaxis4,cv_moveaxis4,cv_brakeaxis4,cv_aimaxis4,cv_lookaxis4,cv_fireaxis4,cv_driftaxis4;
extern consvar_t cv_ghost_besttime, cv_ghost_bestlap, cv_ghost_last, cv_ghost_guest, cv_ghost_staff;
-extern consvar_t cv_splitplayers;
typedef enum
{
diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c
index 754c8d872..4c19b0956 100644
--- a/src/hardware/hw_md2.c
+++ b/src/hardware/hw_md2.c
@@ -496,7 +496,7 @@ static GrTextureFormat_t PNG_Load(const char *filename, int *w, int *h, GLPatch_
jmp_buf jmpbuf;
#endif
#endif
- png_FILE_p png_FILE;
+ volatile png_FILE_p png_FILE;
//Filename checking fixed ~Monster Iestyn and Golden
char *pngfilename = va("%s"PATHSEP"md2"PATHSEP"%s", srb2home, filename);
diff --git a/src/k_kart.c b/src/k_kart.c
index 89a974cf2..ee50cfdd2 100644
--- a/src/k_kart.c
+++ b/src/k_kart.c
@@ -5499,7 +5499,12 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
if (leveltime >= starttime-(2*TICRATE) && leveltime <= starttime)
{
if (cmd->buttons & BT_ACCELERATE)
+ {
+ if (player->kartstuff[k_boostcharge] == 0)
+ player->kartstuff[k_boostcharge] = cmd->latency;
+
player->kartstuff[k_boostcharge]++;
+ }
else
player->kartstuff[k_boostcharge] = 0;
}
@@ -6836,7 +6841,13 @@ static void K_DrawKartPositionNum(INT32 num)
W = FixedMul(W<>FRACBITS;
// pain and suffering defined below
- if (splitscreen < 2) // for this splitscreen, we'll use case by case because it's a bit different.
+ if (!splitscreen)
+ {
+ fx = POSI_X;
+ fy = BASEVIDHEIGHT - 8;
+ fflags = V_SNAPTOBOTTOM|V_SNAPTORIGHT;
+ }
+ else if (splitscreen == 1) // for this splitscreen, we'll use case by case because it's a bit different.
{
fx = POSI_X;
if (stplyr == &players[displayplayer]) // for player 1: display this at the top right, above the minimap.
@@ -6916,7 +6927,7 @@ static void K_DrawKartPositionNum(INT32 num)
else
localpatch = kp_positionnum[num % 10][0];
- V_DrawFixedPatch((fx<width*scale/2) : 0), (fy<height*scale/2) : 0), scale, V_HUDTRANSHALF|fflags, localpatch, NULL);
+ V_DrawFixedPatch((fx<width)*scale/2) : 0), (fy<height)*scale/2) : 0), scale, V_HUDTRANSHALF|fflags, localpatch, NULL);
// ^ if we overtake as p1 or p3 in splitscren, we shift it so that it doesn't go off screen.
// ^ if we overtake as p1 in 2p splits, shift vertically so that this doesn't happen either.
@@ -7372,7 +7383,7 @@ static void K_drawKartWanted(void)
}
else if (splitscreen == 3) // 4P splitscreen...
{
- basex = BASEVIDWIDTH/2 - (SHORT)(kp_wantedsplit->width/2); // center on screen
+ basex = BASEVIDWIDTH/2 - (SHORT(kp_wantedsplit->width)/2); // center on screen
basey = BASEVIDHEIGHT - 55;
//basey2 = 4;
}
@@ -7560,7 +7571,8 @@ static void K_drawKartMinimap(void)
INT32 i = 0;
INT32 x, y;
INT32 minimaptrans, splitflags = (splitscreen == 3 ? 0 : V_SNAPTORIGHT); // flags should only be 0 when it's centered (4p split)
- boolean dop1later = false;
+ SINT8 localplayers[4];
+ SINT8 numlocalplayers = 0;
// Draw the HUD only when playing in a level.
// hu_stuff needs this, unlike st_stuff.
@@ -7612,6 +7624,10 @@ static void K_drawKartMinimap(void)
x -= SHORT(AutomapPic->leftoffset);
y -= SHORT(AutomapPic->topoffset);
+ // initialize
+ for (i = 0; i < 4; i++)
+ localplayers[i] = -1;
+
// Player's tiny icons on the Automap. (drawn opposite direction so player 1 is drawn last in splitscreen)
if (ghosts)
{
@@ -7621,9 +7637,12 @@ static void K_drawKartMinimap(void)
K_drawKartMinimapHead(g->mo, x, y, splitflags, AutomapPic);
g = g->next;
}
+
if (!stplyr->mo || stplyr->spectator) // do we need the latter..?
return;
- dop1later = true;
+
+ localplayers[numlocalplayers] = stplyr-players;
+ numlocalplayers++;
}
else
{
@@ -7634,53 +7653,41 @@ static void K_drawKartMinimap(void)
if (!players[i].mo || players[i].spectator)
continue;
- if (i == displayplayer || i == secondarydisplayplayer || i == thirddisplayplayer || i == fourthdisplayplayer) // don't draw our local players.
+ if (i != displayplayer || splitscreen)
{
- dop1later = true; // Do displayplayer later
- continue;
+ if (G_BattleGametype() && players[i].kartstuff[k_bumper] <= 0)
+ continue;
+
+ if (players[i].kartstuff[k_hyudorotimer] > 0)
+ {
+ if (!((players[i].kartstuff[k_hyudorotimer] < 1*TICRATE/2
+ || players[i].kartstuff[k_hyudorotimer] > hyudorotime-(1*TICRATE/2))
+ && !(leveltime & 1)))
+ continue;
+ }
}
- if (G_BattleGametype() && players[i].kartstuff[k_bumper] <= 0)
- continue;
- if (players[i].kartstuff[k_hyudorotimer] > 0)
+ if (i == displayplayer || i == secondarydisplayplayer || i == thirddisplayplayer || i == fourthdisplayplayer)
{
- if (!((players[i].kartstuff[k_hyudorotimer] < 1*TICRATE/2
- || players[i].kartstuff[k_hyudorotimer] > hyudorotime-(1*TICRATE/2))
- && !(leveltime & 1)))
- continue;
+ // Draw display players on top of everything else
+ localplayers[numlocalplayers] = i;
+ numlocalplayers++;
+ continue;
}
K_drawKartMinimapHead(players[i].mo, x, y, splitflags, AutomapPic);
}
}
- if (!dop1later)
- return; // Don't need this
-
// draw our local players here, opaque.
splitflags &= ~V_HUDTRANSHALF;
splitflags |= V_HUDTRANS;
- for (i = MAXPLAYERS-1; i >= 0; i--)
+
+ for (i = 0; i < numlocalplayers; i++)
{
- if (!(i == displayplayer || i == secondarydisplayplayer || i == thirddisplayplayer || i == fourthdisplayplayer))
- continue; // this doesn't interrest us
-
- if (splitscreen > 1) // this only applies to splitscreen. When we play alone, we should always get drawn reguardless of what we're doing.
- {
- if (G_BattleGametype() && players[i].kartstuff[k_bumper] <= 0)
- continue;
- if (players[i].kartstuff[k_hyudorotimer] > 0)
- {
- if (!((players[i].kartstuff[k_hyudorotimer] < 1*TICRATE/2
- || players[i].kartstuff[k_hyudorotimer] > hyudorotime-(1*TICRATE/2))
- && !(leveltime & 1)))
- continue;
- }
-
- K_drawKartMinimapHead(players[i].mo, x, y, splitflags, AutomapPic);
- }
- else
- K_drawKartMinimapHead(players[i].mo, x, y, splitflags, AutomapPic);
+ if (i == -1)
+ continue; // this doesn't interest us
+ K_drawKartMinimapHead(players[localplayers[i]].mo, x, y, splitflags, AutomapPic);
}
}
@@ -7787,7 +7794,7 @@ static void K_drawBattleFullscreen(void)
{
if (stplyr == &players[displayplayer])
V_DrawFadeScreen(0xFF00, 16);
- if (stplyr->exiting < 6*TICRATE)
+ if (stplyr->exiting < 6*TICRATE && !stplyr->spectator)
{
if (stplyr->kartstuff[k_position] == 1)
V_DrawFixedPatch(x<mo, player->mo->x+player->mo->momx, player->mo->y+player->mo->momy, player->mo->z);
player->mo->momx = player->mo->momy = 0;
}
- if (cmd->sidemove != 0)
+ /*if (cmd->sidemove != 0) -- was disabled in practice anyways, since sidemove was suppressed
{
P_Thrust(player->mo, player->mo->angle-ANGLE_90, (cmd->sidemove*FRACUNIT/MAXPLMOVE)*cv_speed.value);
P_TeleportMove(player->mo, player->mo->x+player->mo->momx, player->mo->y+player->mo->momy, player->mo->z);
player->mo->momx = player->mo->momy = 0;
- }
+ }*/
if (player->mo->z > player->mo->ceilingz - player->mo->height)
player->mo->z = player->mo->ceilingz - player->mo->height;
diff --git a/src/m_menu.c b/src/m_menu.c
index 9534a456d..1edb1cdff 100644
--- a/src/m_menu.c
+++ b/src/m_menu.c
@@ -910,41 +910,7 @@ static menuitem_t SP_LevelStatsMenu[] =
// External files modify this menu, so we can't call it static.
// And I'm too lazy to go through and rename it everywhere. ARRGH!
#define M_ChoosePlayer NULL
-menuitem_t PlayerMenu[32] =
-{
- {IT_CALL, NULL, NULL, M_ChoosePlayer, 0},
- {IT_DISABLED, NULL, NULL, M_ChoosePlayer, 0},
- {IT_DISABLED, NULL, NULL, M_ChoosePlayer, 0},
- {IT_DISABLED, NULL, NULL, M_ChoosePlayer, 0},
- {IT_DISABLED, NULL, NULL, M_ChoosePlayer, 0},
- {IT_DISABLED, NULL, NULL, M_ChoosePlayer, 0},
- {IT_DISABLED, NULL, NULL, M_ChoosePlayer, 0},
- {IT_DISABLED, NULL, NULL, M_ChoosePlayer, 0},
- {IT_DISABLED, NULL, NULL, M_ChoosePlayer, 0},
- {IT_DISABLED, NULL, NULL, M_ChoosePlayer, 0},
- {IT_DISABLED, NULL, NULL, M_ChoosePlayer, 0},
- {IT_DISABLED, NULL, NULL, M_ChoosePlayer, 0},
- {IT_DISABLED, NULL, NULL, M_ChoosePlayer, 0},
- {IT_DISABLED, NULL, NULL, M_ChoosePlayer, 0},
- {IT_DISABLED, NULL, NULL, M_ChoosePlayer, 0},
- {IT_DISABLED, NULL, NULL, M_ChoosePlayer, 0},
- {IT_DISABLED, NULL, NULL, M_ChoosePlayer, 0},
- {IT_DISABLED, NULL, NULL, M_ChoosePlayer, 0},
- {IT_DISABLED, NULL, NULL, M_ChoosePlayer, 0},
- {IT_DISABLED, NULL, NULL, M_ChoosePlayer, 0},
- {IT_DISABLED, NULL, NULL, M_ChoosePlayer, 0},
- {IT_DISABLED, NULL, NULL, M_ChoosePlayer, 0},
- {IT_DISABLED, NULL, NULL, M_ChoosePlayer, 0},
- {IT_DISABLED, NULL, NULL, M_ChoosePlayer, 0},
- {IT_DISABLED, NULL, NULL, M_ChoosePlayer, 0},
- {IT_DISABLED, NULL, NULL, M_ChoosePlayer, 0},
- {IT_DISABLED, NULL, NULL, M_ChoosePlayer, 0},
- {IT_DISABLED, NULL, NULL, M_ChoosePlayer, 0},
- {IT_DISABLED, NULL, NULL, M_ChoosePlayer, 0},
- {IT_DISABLED, NULL, NULL, M_ChoosePlayer, 0},
- {IT_DISABLED, NULL, NULL, M_ChoosePlayer, 0},
- {IT_DISABLED, NULL, NULL, M_ChoosePlayer, 0}
-};
+menuitem_t PlayerMenu[MAXSKINS];
// -----------------------------------
// Multiplayer and all of its submenus
@@ -3187,6 +3153,8 @@ void M_Ticker(void)
//
void M_Init(void)
{
+ UINT8 i;
+
COM_AddCommand("manual", Command_Manual_f);
CV_RegisterVar(&cv_nextmap);
@@ -3198,7 +3166,6 @@ void M_Init(void)
return;
// Menu hacks
- CV_RegisterVar(&cv_splitplayers);
CV_RegisterVar(&cv_dummymenuplayer);
CV_RegisterVar(&cv_dummyteam);
CV_RegisterVar(&cv_dummyspectate);
@@ -3234,6 +3201,15 @@ void M_Init(void)
quitmsg[QUIT3MSG5] = M_GetText("You'll be back to play soon, though...\n...right?\n\n(Press 'Y' to quit)");
quitmsg[QUIT3MSG6] = M_GetText("Aww, is Eggman's Nightclub too\ndifficult for you?\n\n(Press 'Y' to quit)");
+ // Setup PlayerMenu table
+ for (i = 0; i < MAXSKINS; i++)
+ {
+ PlayerMenu[i].status = (i == 0 ? IT_CALL : IT_DISABLED);
+ PlayerMenu[i].patch = PlayerMenu[i].text = NULL;
+ PlayerMenu[i].itemaction = M_ChoosePlayer;
+ PlayerMenu[i].alphaKey = 0;
+ }
+
#ifdef HWRENDER
// Permanently hide some options based on render mode
if (rendermode == render_soft)
diff --git a/src/m_menu.h b/src/m_menu.h
index 9509004b4..864f4cacc 100644
--- a/src/m_menu.h
+++ b/src/m_menu.h
@@ -150,7 +150,7 @@ typedef struct menuitem_s
UINT8 alphaKey;
} menuitem_t;
-extern menuitem_t PlayerMenu[32];
+extern menuitem_t PlayerMenu[MAXSKINS];
typedef struct menu_s
{
diff --git a/src/m_misc.c b/src/m_misc.c
index 0586f6e52..53b63e75f 100644
--- a/src/m_misc.c
+++ b/src/m_misc.c
@@ -93,7 +93,9 @@ typedef off_t off64_t;
#ifdef PNG_WRITE_SUPPORTED
#define USE_PNG // Only actually use PNG if write is supported.
#if defined (PNG_WRITE_APNG_SUPPORTED) //|| !defined(PNG_STATIC)
- #define USE_APNG
+ #if (PNG_LIBPNG_VER_MAJOR) == 1 && (PNG_LIBPNG_VER_MINOR <= 4) // Supposedly, the current APNG code can't work on newer versions as is
+ #define USE_APNG
+ #endif
#endif
// See hardware/hw_draw.c for a similar check to this one.
#endif
diff --git a/src/p_local.h b/src/p_local.h
index 0b64307dc..cf1387fee 100644
--- a/src/p_local.h
+++ b/src/p_local.h
@@ -128,7 +128,6 @@ extern fixed_t t_cam4_dist, t_cam4_height, t_cam4_rotate;
fixed_t P_GetPlayerHeight(player_t *player);
fixed_t P_GetPlayerSpinHeight(player_t *player);
-INT32 P_GetPlayerControlDirection(player_t *player);
void P_AddPlayerScore(player_t *player, UINT32 amount);
void P_ResetCamera(player_t *player, camera_t *thiscam);
boolean P_TryCameraMove(fixed_t x, fixed_t y, camera_t *thiscam);
diff --git a/src/p_saveg.c b/src/p_saveg.c
index 555a26140..975a4a5d2 100644
--- a/src/p_saveg.c
+++ b/src/p_saveg.c
@@ -282,6 +282,12 @@ static void P_NetArchivePlayers(void)
WRITEUINT8(save_p, players[i].accelstart);
WRITEUINT8(save_p, players[i].acceleration);
WRITEFIXED(save_p, players[i].jumpfactor);
+
+ for (j = 0; j < MAXPREDICTTICS; j++)
+ {
+ WRITEINT16(save_p, players[i].lturn_max[j]);
+ WRITEINT16(save_p, players[i].rturn_max[j]);
+ }
}
}
@@ -456,6 +462,12 @@ static void P_NetUnArchivePlayers(void)
players[i].accelstart = READUINT8(save_p);
players[i].acceleration = READUINT8(save_p);
players[i].jumpfactor = READFIXED(save_p);
+
+ for (j = 0; j < MAXPREDICTTICS; j++)
+ {
+ players[i].lturn_max[j] = READINT16(save_p);
+ players[i].rturn_max[j] = READINT16(save_p);
+ }
}
}
diff --git a/src/p_user.c b/src/p_user.c
index ab6c61dc1..d7423d803 100644
--- a/src/p_user.c
+++ b/src/p_user.c
@@ -4509,7 +4509,7 @@ boolean P_AnalogMove(player_t *player)
// 1 = pressing in the direction of movement
// 2 = pressing in the opposite direction of movement
//
-INT32 P_GetPlayerControlDirection(player_t *player)
+/*INT32 P_GetPlayerControlDirection(player_t *player)
{
ticcmd_t *cmd = &player->cmd;
angle_t controllerdirection, controlplayerdirection;
@@ -4584,7 +4584,7 @@ INT32 P_GetPlayerControlDirection(player_t *player)
}
// Control scheme for 2d levels.
-/*static void P_2dMovement(player_t *player)
+static void P_2dMovement(player_t *player)
{
ticcmd_t *cmd;
INT32 topspeed, acceleration, thrustfactor;
@@ -4794,24 +4794,11 @@ static void P_3dMovement(player_t *player)
cmd->forwardmove = cmd->sidemove = 0;
if (player->kartstuff[k_sneakertimer])
cmd->forwardmove = 50;
- if (player->pflags & PF_GLIDING)
- {
- if (!player->skidtime)
- player->pflags &= ~PF_GLIDING;
- else if (player->exiting || mapreset)
- {
- player->pflags &= ~PF_GLIDING;
- P_SetPlayerMobjState(player->mo, S_KART_WALK1); // SRB2kart - was S_PLAY_RUN1
- player->skidtime = 0;
- }
- }
- if (player->pflags & PF_SPINNING && !(player->exiting || mapreset))
- {
- player->pflags &= ~PF_SPINNING;
- P_SetPlayerMobjState(player->mo, S_KART_STND1); // SRB2kart - was S_PLAY_STND
- }
}
+ if (!(player->pflags & PF_FORCESTRAFE) && !player->kartstuff[k_pogospring])
+ cmd->sidemove = 0;
+
if (analogmove)
{
movepushangle = (cmd->angleturn<<16 /* not FRACBITS */);
@@ -4819,9 +4806,7 @@ static void P_3dMovement(player_t *player)
else
{
if (player->kartstuff[k_drift] != 0)
- {
movepushangle = player->mo->angle-(ANGLE_45/5)*player->kartstuff[k_drift];
- }
else
movepushangle = player->mo->angle;
}
@@ -5039,10 +5024,10 @@ static void P_SpectatorMovement(player_t *player)
// Quake-style flying spectators :D
player->mo->momz += FixedMul(cmd->forwardmove*mapobjectscale, AIMINGTOSLOPE(player->aiming));
}
- if (cmd->sidemove != 0)
+ /*if (cmd->sidemove != 0) -- was disabled in practice anyways, since sidemove was suppressed
{
P_Thrust(player->mo, player->mo->angle-ANGLE_90, cmd->sidemove*mapobjectscale);
- }
+ }*/
}
//
@@ -6633,8 +6618,53 @@ static void P_MovePlayer(player_t *player)
P_2dMovement(player);
else*/
{
- if (!player->climbing && (!P_AnalogMove(player)))
- player->mo->angle = (cmd->angleturn<<16 /* not FRACBITS */);
+ INT16 angle_diff, max_left_turn, max_right_turn;
+ boolean add_delta = true;
+
+ // Kart: store the current turn range for later use
+ if (((player->mo && player->speed > 0) // Moving
+ || (leveltime > starttime && (cmd->buttons & BT_ACCELERATE && cmd->buttons & BT_BRAKE)) // Rubber-burn turn
+ || (player->kartstuff[k_respawn]) // Respawning
+ || (player->spectator || objectplacing)) // Not a physical player
+ && !(player->kartstuff[k_spinouttimer] && player->kartstuff[k_sneakertimer])) // Spinning and boosting cancels out turning
+ {
+ player->lturn_max[leveltime%MAXPREDICTTICS] = K_GetKartTurnValue(player, KART_FULLTURN)+1;
+ player->rturn_max[leveltime%MAXPREDICTTICS] = K_GetKartTurnValue(player, -KART_FULLTURN)-1;
+ } else {
+ player->lturn_max[leveltime%MAXPREDICTTICS] = player->rturn_max[leveltime%MAXPREDICTTICS] = 0;
+ }
+
+ if (leveltime >= starttime)
+ {
+ // KART: Don't directly apply angleturn! It may have been either A) forged by a malicious client, or B) not be a smooth turn due to a player dropping frames.
+ // Instead, turn the player only up to the amount they're supposed to turn accounting for latency. Allow exactly 1 extra turn unit to try to keep old replays synced.
+ angle_diff = cmd->angleturn - (player->mo->angle>>16);
+ max_left_turn = player->lturn_max[(leveltime + MAXPREDICTTICS - cmd->latency) % MAXPREDICTTICS];
+ max_right_turn = player->rturn_max[(leveltime + MAXPREDICTTICS - cmd->latency) % MAXPREDICTTICS];
+
+ //CONS_Printf("----------------\nangle diff: %d - turning options: %d to %d - ", angle_diff, max_left_turn, max_right_turn);
+
+ if (angle_diff > max_left_turn)
+ angle_diff = max_left_turn;
+ else if (angle_diff < max_right_turn)
+ angle_diff = max_right_turn;
+ else
+ {
+ // Try to keep normal turning as accurate to 1.0.1 as possible to reduce replay desyncs.
+ player->mo->angle = cmd->angleturn<<16;
+ add_delta = false;
+ }
+ //CONS_Printf("applied turn: %d\n", angle_diff);
+
+ if (add_delta) {
+ player->mo->angle += angle_diff<<16;
+ player->mo->angle &= ~0xFFFF; // Try to keep the turning somewhat similar to how it was before?
+ //CONS_Printf("leftover turn (%s): %5d or %4d%%\n",
+ // player_names[player-players],
+ // (INT16) (cmd->angleturn - (player->mo->angle>>16)),
+ // (INT16) (cmd->angleturn - (player->mo->angle>>16)) * 100 / (angle_diff ?: 1));
+ }
+ }
ticruned++;
if ((cmd->angleturn & TICCMD_RECEIVED) == 0)
@@ -7032,6 +7062,7 @@ static void P_MovePlayer(player_t *player)
//ANALOG CONTROL//
//////////////////
+#if 0
// This really looks like it should be moved to P_3dMovement. -Red
if (P_AnalogMove(player)
&& (cmd->forwardmove != 0 || cmd->sidemove != 0) && !player->climbing && !twodlevel && !(player->mo->flags2 & MF2_TWOD))
@@ -7088,6 +7119,7 @@ static void P_MovePlayer(player_t *player)
else if (player == &players[fourthdisplayplayer])
localangle4 = player->mo->angle;
}
+#endif
///////////////////////////
//BOMB SHIELD ACTIVATION,//
diff --git a/src/r_things.c b/src/r_things.c
index a47200634..c0a71b024 100644
--- a/src/r_things.c
+++ b/src/r_things.c
@@ -2500,7 +2500,7 @@ void R_DrawMasked(void)
// ==========================================================================
INT32 numskins = 0;
-skin_t skins[MAXSKINS+1];
+skin_t skins[MAXSKINS];
// FIXTHIS: don't work because it must be inistilised before the config load
//#define SKINVALUES
#ifdef SKINVALUES
@@ -2772,7 +2772,7 @@ void R_AddSkins(UINT16 wadnum)
// advance by default
lastlump = lump + 1;
- if (numskins > MAXSKINS)
+ if (numskins >= MAXSKINS)
{
CONS_Debug(DBG_RENDER, "ignored skin (%d skins maximum)\n", MAXSKINS);
continue; // so we know how many skins couldn't be added
diff --git a/src/r_things.h b/src/r_things.h
index bc51f7111..01d8fc071 100644
--- a/src/r_things.h
+++ b/src/r_things.h
@@ -192,7 +192,7 @@ typedef struct drawnode_s
} drawnode_t;
extern INT32 numskins;
-extern skin_t skins[MAXSKINS + 1];
+extern skin_t skins[MAXSKINS];
boolean SetPlayerSkin(INT32 playernum,const char *skinname);
void SetPlayerSkinByNum(INT32 playernum,INT32 skinnum); // Tails 03-16-2002