mirror of
https://github.com/ZDoom/qzdoom-gpl.git
synced 2024-11-16 01:02:03 +00:00
Merge pull request #1 from rheit/master
Merge rheit: master into MajorCooke: master
This commit is contained in:
commit
c5db63fbbb
20 changed files with 567 additions and 65 deletions
|
@ -756,9 +756,9 @@ void D_Display ()
|
|||
}
|
||||
screen->SetBlendingRect(viewwindowx, viewwindowy,
|
||||
viewwindowx + viewwidth, viewwindowy + viewheight);
|
||||
P_PredictPlayer(&players[consoleplayer]);
|
||||
|
||||
Renderer->RenderView(&players[consoleplayer]);
|
||||
P_UnPredictPlayer();
|
||||
|
||||
if ((hw2d = screen->Begin2D(viewactive)))
|
||||
{
|
||||
// Redraw everything every frame when using 2D accel
|
||||
|
|
192
src/d_net.cpp
192
src/d_net.cpp
|
@ -110,6 +110,8 @@ unsigned int lastrecvtime[MAXPLAYERS]; // [RH] Used for pings
|
|||
unsigned int currrecvtime[MAXPLAYERS];
|
||||
unsigned int lastglobalrecvtime; // Identify the last time a packet was recieved.
|
||||
bool hadlate;
|
||||
int netdelay[MAXNETNODES][BACKUPTICS]; // Used for storing network delay times.
|
||||
int lastaverage;
|
||||
|
||||
int nodeforplayer[MAXPLAYERS];
|
||||
int playerfornode[MAXNETNODES];
|
||||
|
@ -151,6 +153,32 @@ CUSTOM_CVAR (Bool, cl_capfps, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
|||
}
|
||||
}
|
||||
|
||||
CVAR(Bool, net_ticbalance, false, CVAR_SERVERINFO | CVAR_NOSAVE)
|
||||
CUSTOM_CVAR(Int, net_extratic, 0, CVAR_SERVERINFO | CVAR_NOSAVE)
|
||||
{
|
||||
if (self < 0)
|
||||
{
|
||||
self = 0;
|
||||
}
|
||||
else if (self > 2)
|
||||
{
|
||||
self = 2;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef _DEBUG
|
||||
CVAR(Int, net_fakelatency, 0, 0);
|
||||
|
||||
struct PacketStore
|
||||
{
|
||||
int timer;
|
||||
doomcom_t message;
|
||||
};
|
||||
|
||||
static TArray<PacketStore> InBuffer;
|
||||
static TArray<PacketStore> OutBuffer;
|
||||
#endif
|
||||
|
||||
// [RH] Special "ticcmds" get stored in here
|
||||
static struct TicSpecial
|
||||
{
|
||||
|
@ -347,6 +375,9 @@ int NetbufferSize ()
|
|||
k += netbuffer[k] + 1;
|
||||
}
|
||||
|
||||
// Network delay byte
|
||||
k++;
|
||||
|
||||
if (netbuffer[0] & NCMD_MULTI)
|
||||
{
|
||||
count = netbuffer[k];
|
||||
|
@ -487,7 +518,30 @@ void HSendPacket (int node, int len)
|
|||
doomcom.remotenode = node;
|
||||
doomcom.datalength = len;
|
||||
|
||||
I_NetCmd ();
|
||||
#ifdef _DEBUG
|
||||
if (net_fakelatency / 2 > 0)
|
||||
{
|
||||
PacketStore store;
|
||||
store.message = doomcom;
|
||||
store.timer = I_GetTime(false) + ((net_fakelatency / 2) / (1000 / TICRATE));
|
||||
OutBuffer.Push(store);
|
||||
}
|
||||
else
|
||||
I_NetCmd();
|
||||
|
||||
for (unsigned int i = 0; i < OutBuffer.Size(); i++)
|
||||
{
|
||||
if (OutBuffer[i].timer <= I_GetTime(false))
|
||||
{
|
||||
doomcom = OutBuffer[i].message;
|
||||
I_NetCmd();
|
||||
OutBuffer.Delete(i);
|
||||
i = -1;
|
||||
}
|
||||
}
|
||||
#else
|
||||
I_NetCmd();
|
||||
#endif
|
||||
}
|
||||
|
||||
//
|
||||
|
@ -513,8 +567,38 @@ bool HGetPacket (void)
|
|||
doomcom.command = CMD_GET;
|
||||
I_NetCmd ();
|
||||
|
||||
#ifdef _DEBUG
|
||||
if (net_fakelatency / 2 > 0 && doomcom.remotenode != -1)
|
||||
{
|
||||
PacketStore store;
|
||||
store.message = doomcom;
|
||||
store.timer = I_GetTime(false) + ((net_fakelatency / 2) / (1000 / TICRATE));
|
||||
InBuffer.Push(store);
|
||||
doomcom.remotenode = -1;
|
||||
}
|
||||
|
||||
if (doomcom.remotenode == -1)
|
||||
{
|
||||
bool gotmessage = false;
|
||||
for (unsigned int i = 0; i < InBuffer.Size(); i++)
|
||||
{
|
||||
if (InBuffer[i].timer <= I_GetTime(false))
|
||||
{
|
||||
doomcom = InBuffer[i].message;
|
||||
InBuffer.Delete(i);
|
||||
gotmessage = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!gotmessage)
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
if (doomcom.remotenode == -1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (debugfile)
|
||||
{
|
||||
|
@ -570,6 +654,9 @@ bool HGetPacket (void)
|
|||
|
||||
if (doomcom.datalength != NetbufferSize ())
|
||||
{
|
||||
Printf("Bad packet length %i (calculated %i)\n",
|
||||
doomcom.datalength, NetbufferSize());
|
||||
|
||||
if (debugfile)
|
||||
fprintf (debugfile,"---bad packet length %i (calculated %i)\n",
|
||||
doomcom.datalength, NetbufferSize());
|
||||
|
@ -782,6 +869,9 @@ void GetPackets (void)
|
|||
}
|
||||
}
|
||||
|
||||
// Pull current network delay from node
|
||||
netdelay[netnode][(nettics[netnode]+1) % BACKUPTICS] = netbuffer[k++];
|
||||
|
||||
playerbytes[0] = netconsole;
|
||||
if (netbuffer[0] & NCMD_MULTI)
|
||||
{
|
||||
|
@ -1150,11 +1240,18 @@ void NetUpdate (void)
|
|||
netbuffer[k++] = lowtic;
|
||||
}
|
||||
|
||||
numtics = lowtic - realstart;
|
||||
numtics = MAX(0, lowtic - realstart);
|
||||
if (numtics > BACKUPTICS)
|
||||
I_Error ("NetUpdate: Node %d missed too many tics", i);
|
||||
|
||||
resendto[i] = MAX (0, lowtic - doomcom.extratics);
|
||||
switch (net_extratic)
|
||||
{
|
||||
case 0:
|
||||
default:
|
||||
resendto[i] = lowtic; break;
|
||||
case 1: resendto[i] = MAX(0, lowtic - 1); break;
|
||||
case 2: resendto[i] = nettics[i]; break;
|
||||
}
|
||||
|
||||
if (numtics == 0 && resendOnly && !remoteresend[i] && nettics[i])
|
||||
{
|
||||
|
@ -1190,6 +1287,10 @@ void NetUpdate (void)
|
|||
}
|
||||
}
|
||||
|
||||
// Send current network delay
|
||||
// The number of tics we just made should be removed from the count.
|
||||
netbuffer[k++] = ((maketic - newtics - gametic) / ticdup);
|
||||
|
||||
if (numtics > 0)
|
||||
{
|
||||
int l;
|
||||
|
@ -1299,9 +1400,37 @@ void NetUpdate (void)
|
|||
// that it won't adapt. Fortunately, player prediction helps
|
||||
// alleviate the lag somewhat.
|
||||
|
||||
if (NetMode != NET_PacketServer)
|
||||
if (NetMode == NET_PeerToPeer)
|
||||
{
|
||||
mastertics = nettics[nodeforplayer[Net_Arbitrator]];
|
||||
int totalavg = 0;
|
||||
if (net_ticbalance)
|
||||
{
|
||||
// Try to guess ahead the time it takes to send responses to the slowest node
|
||||
int nodeavg = 0, arbavg = 0;
|
||||
|
||||
for (j = 0; j < BACKUPTICS; j++)
|
||||
{
|
||||
arbavg += netdelay[nodeforplayer[Net_Arbitrator]][j];
|
||||
nodeavg += netdelay[0][j];
|
||||
}
|
||||
arbavg /= BACKUPTICS;
|
||||
nodeavg /= BACKUPTICS;
|
||||
|
||||
// We shouldn't adapt if we are already the arbitrator isn't what we are waiting for, otherwise it just adds more latency
|
||||
if (arbavg > nodeavg)
|
||||
{
|
||||
lastaverage = totalavg = ((arbavg + nodeavg) / 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Allow room to guess two tics ahead
|
||||
if (nodeavg > (arbavg + 2) && lastaverage > 0)
|
||||
lastaverage--;
|
||||
totalavg = lastaverage;
|
||||
}
|
||||
}
|
||||
|
||||
mastertics = nettics[nodeforplayer[Net_Arbitrator]] + totalavg;
|
||||
}
|
||||
if (nettics[0] <= mastertics)
|
||||
{
|
||||
|
@ -1346,9 +1475,8 @@ void NetUpdate (void)
|
|||
//
|
||||
// 0 One byte set to NCMD_SETUP+2
|
||||
// 1 One byte for ticdup setting
|
||||
// 2 One byte for extratics setting
|
||||
// 3 One byte for NetMode setting
|
||||
// 4 String with starting map's name
|
||||
// 2 One byte for NetMode setting
|
||||
// 3 String with starting map's name
|
||||
// . Four bytes for the RNG seed
|
||||
// . Stream containing remaining game info
|
||||
//
|
||||
|
@ -1429,10 +1557,9 @@ bool DoArbitrate (void *userdata)
|
|||
data->gotsetup[0] = 0x80;
|
||||
|
||||
ticdup = doomcom.ticdup = netbuffer[1];
|
||||
doomcom.extratics = netbuffer[2];
|
||||
NetMode = netbuffer[3];
|
||||
NetMode = netbuffer[2];
|
||||
|
||||
stream = &netbuffer[4];
|
||||
stream = &netbuffer[3];
|
||||
s = ReadString (&stream);
|
||||
startmap = s;
|
||||
delete[] s;
|
||||
|
@ -1497,9 +1624,8 @@ bool DoArbitrate (void *userdata)
|
|||
{
|
||||
netbuffer[0] = NCMD_SETUP+2;
|
||||
netbuffer[1] = (BYTE)doomcom.ticdup;
|
||||
netbuffer[2] = (BYTE)doomcom.extratics;
|
||||
netbuffer[3] = NetMode;
|
||||
stream = &netbuffer[4];
|
||||
netbuffer[2] = NetMode;
|
||||
stream = &netbuffer[3];
|
||||
WriteString (startmap, &stream);
|
||||
WriteLong (rngseed, &stream);
|
||||
C_WriteCVars (&stream, CVAR_SERVERINFO, true);
|
||||
|
@ -1647,15 +1773,23 @@ void D_CheckNetGame (void)
|
|||
|
||||
consoleplayer = doomcom.consoleplayer;
|
||||
|
||||
v = Args->CheckValue ("-netmode");
|
||||
if (v != NULL)
|
||||
if (consoleplayer == Net_Arbitrator)
|
||||
{
|
||||
NetMode = atoi (v) != 0 ? NET_PacketServer : NET_PeerToPeer;
|
||||
}
|
||||
if (doomcom.numnodes > 1)
|
||||
{
|
||||
Printf ("Selected " TEXTCOLOR_BLUE "%s" TEXTCOLOR_NORMAL " networking mode. (%s)\n", NetMode == NET_PeerToPeer ? "peer to peer" : "packet server",
|
||||
v != NULL ? "forced" : "auto");
|
||||
v = Args->CheckValue("-netmode");
|
||||
if (v != NULL)
|
||||
{
|
||||
NetMode = atoi(v) != 0 ? NET_PacketServer : NET_PeerToPeer;
|
||||
}
|
||||
if (doomcom.numnodes > 1)
|
||||
{
|
||||
Printf("Selected " TEXTCOLOR_BLUE "%s" TEXTCOLOR_NORMAL " networking mode. (%s)\n", NetMode == NET_PeerToPeer ? "peer to peer" : "packet server",
|
||||
v != NULL ? "forced" : "auto");
|
||||
}
|
||||
|
||||
if (Args->CheckParm("-extratic"))
|
||||
{
|
||||
net_extratic = 1;
|
||||
}
|
||||
}
|
||||
|
||||
// [RH] Setup user info
|
||||
|
@ -1683,6 +1817,11 @@ void D_CheckNetGame (void)
|
|||
for (i = 0; i < doomcom.numnodes; i++)
|
||||
nodeingame[i] = true;
|
||||
|
||||
if (consoleplayer != Net_Arbitrator && doomcom.numnodes > 1)
|
||||
{
|
||||
Printf("Arbitrator selected " TEXTCOLOR_BLUE "%s" TEXTCOLOR_NORMAL " networking mode.\n", NetMode == NET_PeerToPeer ? "peer to peer" : "packet server");
|
||||
}
|
||||
|
||||
Printf ("player %i of %i (%i nodes)\n",
|
||||
consoleplayer+1, doomcom.numplayers, doomcom.numnodes);
|
||||
}
|
||||
|
@ -1809,6 +1948,9 @@ void TryRunTics (void)
|
|||
{
|
||||
C_Ticker();
|
||||
M_Ticker();
|
||||
// Repredict the player for new buffered movement
|
||||
P_UnPredictPlayer();
|
||||
P_PredictPlayer(&players[consoleplayer]);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -1844,6 +1986,9 @@ void TryRunTics (void)
|
|||
{
|
||||
C_Ticker ();
|
||||
M_Ticker ();
|
||||
// Repredict the player for new buffered movement
|
||||
P_UnPredictPlayer();
|
||||
P_PredictPlayer(&players[consoleplayer]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -1857,6 +2002,7 @@ void TryRunTics (void)
|
|||
// run the count tics
|
||||
if (counts > 0)
|
||||
{
|
||||
P_UnPredictPlayer();
|
||||
while (counts--)
|
||||
{
|
||||
if (gametic > lowtic)
|
||||
|
@ -1876,6 +2022,7 @@ void TryRunTics (void)
|
|||
|
||||
NetUpdate (); // check for new console commands
|
||||
}
|
||||
P_PredictPlayer(&players[consoleplayer]);
|
||||
S_UpdateSounds (players[consoleplayer].camera); // move positional sounds
|
||||
}
|
||||
}
|
||||
|
@ -2713,7 +2860,6 @@ void Net_SkipCommand (int type, BYTE **stream)
|
|||
CCMD (pings)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
if (playeringame[i])
|
||||
Printf ("% 4d %s\n", currrecvtime[i] - lastrecvtime[i],
|
||||
|
|
|
@ -70,7 +70,6 @@ struct doomcom_t
|
|||
// info common to all nodes
|
||||
SWORD numnodes; // console is always node 0.
|
||||
SWORD ticdup; // 1 = no duplication, 2-5 = dup for slow nets
|
||||
SWORD extratics; // 1 = send a backup tic in every packet
|
||||
#ifdef DJGPP
|
||||
SWORD pad[5]; // keep things aligned for DOS drivers
|
||||
#endif
|
||||
|
@ -143,6 +142,8 @@ extern struct ticcmd_t localcmds[LOCALCMDTICS];
|
|||
|
||||
extern int maketic;
|
||||
extern int nettics[MAXNETNODES];
|
||||
extern int netdelay[MAXNETNODES][BACKUPTICS];
|
||||
extern int nodeforplayer[MAXPLAYERS];
|
||||
|
||||
extern ticcmd_t netcmds[MAXPLAYERS][BACKUPTICS];
|
||||
extern int ticdup;
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
// copy would be.
|
||||
|
||||
#include "doomtype.h"
|
||||
#include "doomdef.h"
|
||||
#include "v_video.h"
|
||||
#include "gi.h"
|
||||
#include "c_cvars.h"
|
||||
|
@ -48,6 +49,7 @@
|
|||
#include "p_local.h"
|
||||
#include "doomstat.h"
|
||||
#include "g_level.h"
|
||||
#include "d_net.h"
|
||||
|
||||
#include <time.h>
|
||||
|
||||
|
@ -73,6 +75,7 @@ CVAR (Bool, hud_showscore, false, CVAR_ARCHIVE); // for user maintained score
|
|||
CVAR (Bool, hud_showweapons, true, CVAR_ARCHIVE); // Show weapons collected
|
||||
CVAR (Int , hud_showtime, 0, CVAR_ARCHIVE); // Show time on HUD
|
||||
CVAR (Int , hud_timecolor, CR_GOLD,CVAR_ARCHIVE); // Color of in-game time on HUD
|
||||
CVAR (Int , hud_showlag, 0, CVAR_ARCHIVE); // Show input latency (maketic - gametic difference)
|
||||
|
||||
CVAR (Int, hud_ammo_red, 25, CVAR_ARCHIVE) // ammo percent less than which status is red
|
||||
CVAR (Int, hud_ammo_yellow, 50, CVAR_ARCHIVE) // ammo percent less is yellow more green
|
||||
|
@ -917,6 +920,51 @@ static void DrawTime()
|
|||
DrawHudText(SmallFont, hud_timecolor, timeString, hudwidth - width, height, FRACUNIT);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// Draw in-game latency
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
static void DrawLatency()
|
||||
{
|
||||
if (hud_showlag <= 0 ||
|
||||
(hud_showlag == 1 && !netgame) ||
|
||||
hud_showlag > 2)
|
||||
{
|
||||
return;
|
||||
}
|
||||
int i, localdelay = 0, arbitratordelay = 0;
|
||||
for (i = 0; i < BACKUPTICS; i++) localdelay += netdelay[0][i];
|
||||
for (i = 0; i < BACKUPTICS; i++) arbitratordelay += netdelay[nodeforplayer[Net_Arbitrator]][i];
|
||||
localdelay = ((localdelay / BACKUPTICS) * ticdup) * (1000 / TICRATE);
|
||||
arbitratordelay = ((arbitratordelay / BACKUPTICS) * ticdup) * (1000 / TICRATE);
|
||||
int color = CR_GREEN;
|
||||
if (MAX(localdelay, arbitratordelay) > 200)
|
||||
{
|
||||
color = CR_YELLOW;
|
||||
}
|
||||
if (MAX(localdelay, arbitratordelay) > 400)
|
||||
{
|
||||
color = CR_ORANGE;
|
||||
}
|
||||
if (MAX(localdelay, arbitratordelay) >= ((BACKUPTICS / 2 - 1) * ticdup) * (1000 / TICRATE))
|
||||
{
|
||||
color = CR_RED;
|
||||
}
|
||||
|
||||
char tempstr[32];
|
||||
|
||||
const int millis = (level.time % TICRATE) * (1000 / TICRATE);
|
||||
mysnprintf(tempstr, sizeof(tempstr), "a:%dms - l:%dms", arbitratordelay, localdelay);
|
||||
|
||||
const int characterCount = strlen(tempstr);
|
||||
const int width = SmallFont->GetCharWidth('0') * characterCount + 2; // small offset from screen's border
|
||||
const int height = SmallFont->GetHeight() * 2;
|
||||
|
||||
DrawHudText(SmallFont, color, tempstr, hudwidth - width, height, FRACUNIT);
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
|
@ -982,6 +1030,7 @@ void DrawHUD()
|
|||
if (idmypos) DrawCoordinates(CPlayer);
|
||||
|
||||
DrawTime();
|
||||
DrawLatency();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -48,6 +48,7 @@
|
|||
#include "d_player.h"
|
||||
#include "hu_stuff.h"
|
||||
#include "gstrings.h"
|
||||
#include "d_net.h"
|
||||
|
||||
// MACROS ------------------------------------------------------------------
|
||||
|
||||
|
@ -61,7 +62,7 @@
|
|||
|
||||
static void HU_DoDrawScores (player_t *, player_t *[MAXPLAYERS]);
|
||||
static void HU_DrawTimeRemaining (int y);
|
||||
static void HU_DrawPlayer (player_t *, bool, int, int, int, int, int, int, int, int);
|
||||
static void HU_DrawPlayer(player_t *, bool, int, int, int, int, int, int, int, int, int);
|
||||
|
||||
// EXTERNAL DATA DECLARATIONS ----------------------------------------------
|
||||
|
||||
|
@ -228,7 +229,7 @@ static void HU_DoDrawScores (player_t *player, player_t *sortedplayers[MAXPLAYER
|
|||
int maxnamewidth, maxscorewidth, maxiconheight;
|
||||
int numTeams = 0;
|
||||
int x, y, ypadding, bottom;
|
||||
int col2, col3, col4;
|
||||
int col2, col3, col4, col5;
|
||||
|
||||
if (deathmatch)
|
||||
{
|
||||
|
@ -309,12 +310,14 @@ static void HU_DoDrawScores (player_t *player, player_t *sortedplayers[MAXPLAYER
|
|||
|
||||
const char *text_color = GStrings("SCORE_COLOR"),
|
||||
*text_frags = GStrings(deathmatch ? "SCORE_FRAGS" : "SCORE_KILLS"),
|
||||
*text_name = GStrings("SCORE_NAME");
|
||||
*text_name = GStrings("SCORE_NAME"),
|
||||
*text_delay = GStrings("SCORE_DELAY");
|
||||
|
||||
col2 = (SmallFont->StringWidth(text_color) + 8) * CleanXfac;
|
||||
col3 = col2 + (SmallFont->StringWidth(text_frags) + 8) * CleanXfac;
|
||||
col4 = col3 + maxscorewidth * CleanXfac;
|
||||
x = (SCREENWIDTH >> 1) - ((maxnamewidth * CleanXfac + col4) >> 1);
|
||||
col5 = col4 + (maxnamewidth + 8) * CleanXfac;
|
||||
x = (SCREENWIDTH >> 1) - (((SmallFont->StringWidth(text_delay) * CleanXfac) + col5) >> 1);
|
||||
|
||||
screen->DrawText (SmallFont, color, x, y, text_color,
|
||||
DTA_CleanNoMove, true, TAG_DONE);
|
||||
|
@ -325,6 +328,9 @@ static void HU_DoDrawScores (player_t *player, player_t *sortedplayers[MAXPLAYER
|
|||
screen->DrawText (SmallFont, color, x + col4, y, text_name,
|
||||
DTA_CleanNoMove, true, TAG_DONE);
|
||||
|
||||
screen->DrawText(SmallFont, color, x + col5, y, text_delay,
|
||||
DTA_CleanNoMove, true, TAG_DONE);
|
||||
|
||||
y += height + 6 * CleanYfac;
|
||||
bottom -= height;
|
||||
|
||||
|
@ -332,7 +338,7 @@ static void HU_DoDrawScores (player_t *player, player_t *sortedplayers[MAXPLAYER
|
|||
{
|
||||
if (playeringame[sortedplayers[i] - players])
|
||||
{
|
||||
HU_DrawPlayer (sortedplayers[i], player==sortedplayers[i], x, col2, col3, col4, maxnamewidth, y, ypadding, lineheight);
|
||||
HU_DrawPlayer(sortedplayers[i], player == sortedplayers[i], x, col2, col3, col4, col5, maxnamewidth, y, ypadding, lineheight);
|
||||
y += lineheight + CleanYfac;
|
||||
}
|
||||
}
|
||||
|
@ -377,7 +383,7 @@ static void HU_DrawTimeRemaining (int y)
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
static void HU_DrawPlayer (player_t *player, bool highlight, int col1, int col2, int col3, int col4, int maxnamewidth, int y, int ypadding, int height)
|
||||
static void HU_DrawPlayer (player_t *player, bool highlight, int col1, int col2, int col3, int col4, int col5, int maxnamewidth, int y, int ypadding, int height)
|
||||
{
|
||||
int color;
|
||||
char str[80];
|
||||
|
@ -387,12 +393,13 @@ static void HU_DrawPlayer (player_t *player, bool highlight, int col1, int col2,
|
|||
// The teamplay mode uses colors to show teams, so we need some
|
||||
// other way to do highlighting. And it may as well be used for
|
||||
// all modes for the sake of consistancy.
|
||||
screen->Dim(MAKERGB(200,245,255), 0.125f, col1 - 12*CleanXfac, y - 1, col4 + (maxnamewidth + 24)*CleanXfac, height + 2);
|
||||
screen->Dim(MAKERGB(200,245,255), 0.125f, col1 - 12*CleanXfac, y - 1, col5 + (maxnamewidth + 24)*CleanXfac, height + 2);
|
||||
}
|
||||
|
||||
col2 += col1;
|
||||
col3 += col1;
|
||||
col4 += col1;
|
||||
col5 += col1;
|
||||
|
||||
color = HU_GetRowColor(player, highlight);
|
||||
HU_DrawColorBar(col1, y, height, (int)(player - players));
|
||||
|
@ -412,6 +419,18 @@ static void HU_DrawPlayer (player_t *player, bool highlight, int col1, int col2,
|
|||
screen->DrawText (SmallFont, color, col4, y + ypadding, player->userinfo.GetName(),
|
||||
DTA_CleanNoMove, true, TAG_DONE);
|
||||
|
||||
int avgdelay = 0;
|
||||
for (int i = 0; i < BACKUPTICS; i++)
|
||||
{
|
||||
avgdelay += netdelay[nodeforplayer[(int)(player - players)]][i];
|
||||
}
|
||||
avgdelay /= BACKUPTICS;
|
||||
|
||||
mysnprintf(str, countof(str), "%d", (avgdelay * ticdup) * (1000 / TICRATE));
|
||||
|
||||
screen->DrawText(SmallFont, color, col5, y + ypadding, str,
|
||||
DTA_CleanNoMove, true, TAG_DONE);
|
||||
|
||||
if (teamplay && Teams[player->userinfo.GetTeam()].GetLogo().IsNotEmpty ())
|
||||
{
|
||||
FTexture *pic = TexMan[Teams[player->userinfo.GetTeam()].GetLogo().GetChars ()];
|
||||
|
|
|
@ -208,11 +208,11 @@ void PacketSend (void)
|
|||
{
|
||||
I_FatalError("Netbuffer overflow!");
|
||||
}
|
||||
assert(!(doomcom.data[0] & NCMD_COMPRESSED));
|
||||
|
||||
uLong size = TRANSMIT_SIZE - 1;
|
||||
if (doomcom.datalength >= 10)
|
||||
{
|
||||
assert(!(doomcom.data[0] & NCMD_COMPRESSED));
|
||||
TransmitBuffer[0] = doomcom.data[0] | NCMD_COMPRESSED;
|
||||
c = compress2(TransmitBuffer + 1, &size, doomcom.data + 1, doomcom.datalength - 1, 9);
|
||||
size += 1;
|
||||
|
@ -938,11 +938,6 @@ bool I_InitNetwork (void)
|
|||
doomcom.ticdup = 1;
|
||||
}
|
||||
|
||||
if (Args->CheckParm ("-extratic"))
|
||||
doomcom.extratics = 1;
|
||||
else
|
||||
doomcom.extratics = 0;
|
||||
|
||||
v = Args->CheckValue ("-port");
|
||||
if (v)
|
||||
{
|
||||
|
|
|
@ -298,6 +298,7 @@ xx(Abs)
|
|||
xx(ACS_NamedExecuteWithResult)
|
||||
xx(CallACS)
|
||||
xx(Sqrt)
|
||||
xx(CheckClass)
|
||||
|
||||
// Various actor names which are used internally
|
||||
xx(MapSpot)
|
||||
|
|
|
@ -380,7 +380,9 @@ bool P_TeleportMove(AActor *thing, fixed_t x, fixed_t y, fixed_t z, bool telefra
|
|||
// ... and some items can never be telefragged while others will be telefragged by everything that teleports upon them.
|
||||
if ((StompAlwaysFrags && !(th->flags6 & MF6_NOTELEFRAG)) || (th->flags7 & MF7_ALWAYSTELEFRAG))
|
||||
{
|
||||
P_DamageMobj(th, thing, thing, TELEFRAG_DAMAGE, NAME_Telefrag, DMG_THRUSTLESS);
|
||||
// Don't actually damage if predicting a teleport
|
||||
if (thing->player == NULL || !(thing->player->cheats & CF_PREDICTING))
|
||||
P_DamageMobj(th, thing, thing, TELEFRAG_DAMAGE, NAME_Telefrag, DMG_THRUSTLESS);
|
||||
continue;
|
||||
}
|
||||
return false;
|
||||
|
@ -1981,13 +1983,6 @@ bool P_TryMove(AActor *thing, fixed_t x, fixed_t y,
|
|||
thing->AdjustFloorClip();
|
||||
}
|
||||
|
||||
// [RH] Don't activate anything if just predicting
|
||||
if (thing->player && (thing->player->cheats & CF_PREDICTING))
|
||||
{
|
||||
thing->flags6 &= ~MF6_INTRYMOVE;
|
||||
return true;
|
||||
}
|
||||
|
||||
// if any special lines were hit, do the effect
|
||||
if (!(thing->flags & (MF_TELEPORT | MF_NOCLIP)))
|
||||
{
|
||||
|
@ -1998,7 +1993,11 @@ bool P_TryMove(AActor *thing, fixed_t x, fixed_t y,
|
|||
oldside = P_PointOnLineSide(oldx, oldy, ld);
|
||||
if (side != oldside && ld->special && !(thing->flags6 & MF6_NOTRIGGER))
|
||||
{
|
||||
if (thing->player)
|
||||
if (thing->player && (thing->player->cheats & CF_PREDICTING))
|
||||
{
|
||||
P_PredictLine(ld, thing, oldside, SPAC_Cross);
|
||||
}
|
||||
else if (thing->player)
|
||||
{
|
||||
P_ActivateLine(ld, thing, oldside, SPAC_Cross);
|
||||
}
|
||||
|
@ -2024,6 +2023,13 @@ bool P_TryMove(AActor *thing, fixed_t x, fixed_t y,
|
|||
}
|
||||
}
|
||||
|
||||
// [RH] Don't activate anything if just predicting
|
||||
if (thing->player && (thing->player->cheats & CF_PREDICTING))
|
||||
{
|
||||
thing->flags6 &= ~MF6_INTRYMOVE;
|
||||
return true;
|
||||
}
|
||||
|
||||
// [RH] Check for crossing fake floor/ceiling
|
||||
newsec = thing->Sector;
|
||||
if (newsec->heightsec && oldsec->heightsec && newsec->SecActTarget)
|
||||
|
|
|
@ -73,6 +73,7 @@
|
|||
static FRandom pr_playerinspecialsector ("PlayerInSpecialSector");
|
||||
void P_SetupPortals();
|
||||
|
||||
EXTERN_CVAR(Bool, cl_predict_specials)
|
||||
|
||||
IMPLEMENT_POINTY_CLASS (DScroller)
|
||||
DECLARE_POINTER (m_Interpolations[0])
|
||||
|
@ -408,6 +409,48 @@ bool P_TestActivateLine (line_t *line, AActor *mo, int side, int activationType)
|
|||
return true;
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
//
|
||||
// P_PredictLine
|
||||
//
|
||||
//============================================================================
|
||||
|
||||
bool P_PredictLine(line_t *line, AActor *mo, int side, int activationType)
|
||||
{
|
||||
int lineActivation;
|
||||
INTBOOL buttonSuccess;
|
||||
BYTE special;
|
||||
|
||||
// Only predict a very specifc section of specials
|
||||
if (line->special != Teleport_Line &&
|
||||
line->special != Teleport)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!P_TestActivateLine(line, mo, side, activationType) || !cl_predict_specials)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (line->locknumber > 0) return false;
|
||||
lineActivation = line->activation;
|
||||
buttonSuccess = false;
|
||||
buttonSuccess = P_ExecuteSpecial(line->special,
|
||||
line, mo, side == 1, line->args[0],
|
||||
line->args[1], line->args[2],
|
||||
line->args[3], line->args[4]);
|
||||
|
||||
special = line->special;
|
||||
|
||||
// end of changed code
|
||||
if (developer && buttonSuccess)
|
||||
{
|
||||
Printf("Line special %d predicted on line %i\n", special, int(line - lines));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//
|
||||
// P_PlayerInSpecialSector
|
||||
// Called every tic frame
|
||||
|
|
|
@ -166,6 +166,7 @@ void P_UpdateSpecials (void);
|
|||
// when needed
|
||||
bool P_ActivateLine (line_t *ld, AActor *mo, int side, int activationType);
|
||||
bool P_TestActivateLine (line_t *ld, AActor *mo, int side, int activationType);
|
||||
bool P_PredictLine (line_t *ld, AActor *mo, int side, int activationType);
|
||||
|
||||
void P_PlayerInSpecialSector (player_t *player, sector_t * sector=NULL);
|
||||
void P_PlayerOnSpecialFlat (player_t *player, int floorType);
|
||||
|
|
|
@ -96,6 +96,8 @@ void P_SpawnTeleportFog(fixed_t x, fixed_t y, fixed_t z, int spawnid)
|
|||
bool P_Teleport (AActor *thing, fixed_t x, fixed_t y, fixed_t z, angle_t angle,
|
||||
bool useFog, bool sourceFog, bool keepOrientation, bool bHaltVelocity, bool keepHeight)
|
||||
{
|
||||
bool predicting = (thing->player && (thing->player->cheats & CF_PREDICTING));
|
||||
|
||||
fixed_t oldx;
|
||||
fixed_t oldy;
|
||||
fixed_t oldz;
|
||||
|
@ -181,7 +183,7 @@ bool P_Teleport (AActor *thing, fixed_t x, fixed_t y, fixed_t z, angle_t angle,
|
|||
angle = thing->angle;
|
||||
}
|
||||
// Spawn teleport fog at source and destination
|
||||
if (sourceFog)
|
||||
if (sourceFog && !predicting)
|
||||
{
|
||||
fixed_t fogDelta = thing->flags & MF_MISSILE ? 0 : TELEFOGHEIGHT;
|
||||
AActor *fog = Spawn<ATeleportFog> (oldx, oldy, oldz + fogDelta, ALLOW_REPLACE);
|
||||
|
@ -189,11 +191,14 @@ bool P_Teleport (AActor *thing, fixed_t x, fixed_t y, fixed_t z, angle_t angle,
|
|||
}
|
||||
if (useFog)
|
||||
{
|
||||
fixed_t fogDelta = thing->flags & MF_MISSILE ? 0 : TELEFOGHEIGHT;
|
||||
an = angle >> ANGLETOFINESHIFT;
|
||||
AActor *fog = Spawn<ATeleportFog> (x + 20*finecosine[an],
|
||||
y + 20*finesine[an], thing->z + fogDelta, ALLOW_REPLACE);
|
||||
fog->target = thing;
|
||||
if (!predicting)
|
||||
{
|
||||
fixed_t fogDelta = thing->flags & MF_MISSILE ? 0 : TELEFOGHEIGHT;
|
||||
an = angle >> ANGLETOFINESHIFT;
|
||||
AActor *fog = Spawn<ATeleportFog>(x + 20 * finecosine[an],
|
||||
y + 20 * finesine[an], thing->z + fogDelta, ALLOW_REPLACE);
|
||||
fog->target = thing;
|
||||
}
|
||||
if (thing->player)
|
||||
{
|
||||
// [RH] Zoom player's field of vision
|
||||
|
@ -226,7 +231,7 @@ bool P_Teleport (AActor *thing, fixed_t x, fixed_t y, fixed_t z, angle_t angle,
|
|||
return true;
|
||||
}
|
||||
|
||||
static AActor *SelectTeleDest (int tid, int tag)
|
||||
static AActor *SelectTeleDest (int tid, int tag, bool norandom)
|
||||
{
|
||||
AActor *searcher;
|
||||
|
||||
|
@ -276,7 +281,7 @@ static AActor *SelectTeleDest (int tid, int tag)
|
|||
}
|
||||
else
|
||||
{
|
||||
if (count != 1)
|
||||
if (count != 1 && !norandom)
|
||||
{
|
||||
count = 1 + (pr_teleport() % count);
|
||||
}
|
||||
|
@ -323,6 +328,8 @@ static AActor *SelectTeleDest (int tid, int tag)
|
|||
bool EV_Teleport (int tid, int tag, line_t *line, int side, AActor *thing, bool fog,
|
||||
bool sourceFog, bool keepOrientation, bool haltVelocity, bool keepHeight)
|
||||
{
|
||||
bool predicting = (thing->player && (thing->player->cheats & CF_PREDICTING));
|
||||
|
||||
AActor *searcher;
|
||||
fixed_t z;
|
||||
angle_t angle = 0;
|
||||
|
@ -342,7 +349,7 @@ bool EV_Teleport (int tid, int tag, line_t *line, int side, AActor *thing, bool
|
|||
{ // Don't teleport if hit back of line, so you can get out of teleporter.
|
||||
return 0;
|
||||
}
|
||||
searcher = SelectTeleDest (tid, tag);
|
||||
searcher = SelectTeleDest(tid, tag, predicting);
|
||||
if (searcher == NULL)
|
||||
{
|
||||
return false;
|
||||
|
@ -390,7 +397,7 @@ bool EV_Teleport (int tid, int tag, line_t *line, int side, AActor *thing, bool
|
|||
thing->velx = FixedMul(velx, c) - FixedMul(vely, s);
|
||||
thing->vely = FixedMul(vely, c) + FixedMul(velx, s);
|
||||
}
|
||||
if ((velx | vely) == 0 && thing->player != NULL && thing->player->mo == thing)
|
||||
if ((velx | vely) == 0 && thing->player != NULL && thing->player->mo == thing && !predicting)
|
||||
{
|
||||
thing->player->mo->PlayIdle ();
|
||||
}
|
||||
|
|
|
@ -62,6 +62,7 @@ static FRandom pr_skullpop ("SkullPop");
|
|||
|
||||
// Variables for prediction
|
||||
CVAR (Bool, cl_noprediction, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||
CVAR(Bool, cl_predict_specials, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
static player_t PredictionPlayerBackup;
|
||||
static BYTE PredictionActorBackup[sizeof(AActor)];
|
||||
static TArray<sector_t *> PredictionTouchingSectorsBackup;
|
||||
|
@ -2722,8 +2723,12 @@ void P_PredictPlayer (player_t *player)
|
|||
}
|
||||
act->BlockNode = NULL;
|
||||
|
||||
bool NoInterpolateOld = R_GetViewInterpolationStatus();
|
||||
for (int i = gametic; i < maxtic; ++i)
|
||||
{
|
||||
if (!NoInterpolateOld)
|
||||
R_RebuildViewInterpolation(player);
|
||||
|
||||
player->cmd = localcmds[i % LOCALCMDTICS];
|
||||
P_PlayerThink (player);
|
||||
player->mo->Tick ();
|
||||
|
|
|
@ -729,6 +729,42 @@ void R_ClearPastViewer (AActor *actor)
|
|||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// R_RebuildViewInterpolation
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void R_RebuildViewInterpolation(player_t *player)
|
||||
{
|
||||
if (player == NULL || player->camera == NULL)
|
||||
return;
|
||||
|
||||
if (!NoInterpolateView)
|
||||
return;
|
||||
NoInterpolateView = false;
|
||||
|
||||
InterpolationViewer *iview = FindPastViewer(player->camera);
|
||||
|
||||
iview->oviewx = iview->nviewx;
|
||||
iview->oviewy = iview->nviewy;
|
||||
iview->oviewz = iview->nviewz;
|
||||
iview->oviewpitch = iview->nviewpitch;
|
||||
iview->oviewangle = iview->nviewangle;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// R_GetViewInterpolationStatus
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
bool R_GetViewInterpolationStatus()
|
||||
{
|
||||
return NoInterpolateView;
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// R_SetupFrame
|
||||
|
|
|
@ -61,6 +61,8 @@ inline angle_t R_PointToAngle (fixed_t x, fixed_t y) { return R_PointToAngle2 (v
|
|||
subsector_t *R_PointInSubsector (fixed_t x, fixed_t y);
|
||||
fixed_t R_PointToDist2 (fixed_t dx, fixed_t dy);
|
||||
void R_ResetViewInterpolation ();
|
||||
void R_RebuildViewInterpolation(player_t *player);
|
||||
bool R_GetViewInterpolationStatus();
|
||||
void R_SetViewSize (int blocks);
|
||||
void R_SetFOV (float fov);
|
||||
float R_GetFOV ();
|
||||
|
|
|
@ -3532,7 +3532,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfInTargetLOS)
|
|||
|
||||
//===========================================================================
|
||||
//
|
||||
// A_DamageMaster (int amount)
|
||||
// A_DamageMaster (int amount, str damagetype)
|
||||
// Damages the master of this child by the specified amount. Negative values heal.
|
||||
//
|
||||
//===========================================================================
|
||||
|
@ -3558,7 +3558,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_DamageMaster)
|
|||
|
||||
//===========================================================================
|
||||
//
|
||||
// A_DamageChildren (amount)
|
||||
// A_DamageChildren (amount, str damagetype)
|
||||
// Damages the children of this master by the specified amount. Negative values heal.
|
||||
//
|
||||
//===========================================================================
|
||||
|
@ -3592,7 +3592,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_DamageChildren)
|
|||
|
||||
//===========================================================================
|
||||
//
|
||||
// A_DamageSiblings (amount)
|
||||
// A_DamageSiblings (int amount, str damagetype)
|
||||
// Damages the siblings of this master by the specified amount. Negative values heal.
|
||||
//
|
||||
//===========================================================================
|
||||
|
@ -4994,3 +4994,80 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetSpeed)
|
|||
|
||||
self->Speed = speed;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// A_DamageSelf (int amount, str damagetype)
|
||||
// Damages the calling actor by the specified amount. Negative values heal.
|
||||
//
|
||||
//===========================================================================
|
||||
DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_DamageSelf)
|
||||
{
|
||||
ACTION_PARAM_START(2);
|
||||
ACTION_PARAM_INT(amount, 0);
|
||||
ACTION_PARAM_NAME(DamageType, 1);
|
||||
|
||||
if (amount > 0)
|
||||
{
|
||||
P_DamageMobj(self, self, self, amount, DamageType, DMG_NO_ARMOR);
|
||||
}
|
||||
else if (amount < 0)
|
||||
{
|
||||
amount = -amount;
|
||||
P_GiveBody(self, amount);
|
||||
}
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// A_DamageTarget (int amount, str damagetype)
|
||||
// Damages the target of the actor by the specified amount. Negative values heal.
|
||||
//
|
||||
//===========================================================================
|
||||
DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_DamageTarget)
|
||||
{
|
||||
ACTION_PARAM_START(2);
|
||||
ACTION_PARAM_INT(amount, 0);
|
||||
ACTION_PARAM_NAME(DamageType, 1);
|
||||
|
||||
if (self->target != NULL)
|
||||
{
|
||||
|
||||
if (amount > 0)
|
||||
{
|
||||
P_DamageMobj(self->target, self, self, amount, DamageType, DMG_NO_ARMOR);
|
||||
}
|
||||
else if (amount < 0)
|
||||
{
|
||||
amount = -amount;
|
||||
P_GiveBody(self->target, amount);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// A_DamageTracer (int amount, str damagetype)
|
||||
// Damages the tracer of the actor by the specified amount. Negative values heal.
|
||||
//
|
||||
//===========================================================================
|
||||
DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_DamageTracer)
|
||||
{
|
||||
ACTION_PARAM_START(2);
|
||||
ACTION_PARAM_INT(amount, 0);
|
||||
ACTION_PARAM_NAME(DamageType, 1);
|
||||
|
||||
if (self->target != NULL)
|
||||
{
|
||||
|
||||
if (amount > 0)
|
||||
{
|
||||
P_DamageMobj(self->tracer, self, self, amount, DamageType, DMG_NO_ARMOR);
|
||||
}
|
||||
else if (amount < 0)
|
||||
{
|
||||
amount = -amount;
|
||||
P_GiveBody(self->tracer, amount);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -43,6 +43,8 @@
|
|||
#include "tarray.h"
|
||||
#include "thingdef.h"
|
||||
#include "thingdef_exp.h"
|
||||
#include "actor.h"
|
||||
#include "actorptrselect.h"
|
||||
|
||||
static TMap<FName, FxGlobalFunctionCall::Creator> CreatorMap;
|
||||
|
||||
|
@ -185,3 +187,77 @@ public:
|
|||
|
||||
GLOBALFUNCTION_ADDER(Sqrt);
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Function: checkclass
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
class FxGlobalFunctionCall_CheckClass : public FxGlobalFunctionCall
|
||||
{
|
||||
public:
|
||||
GLOBALFUNCTION_DEFINE(CheckClass);
|
||||
|
||||
FxExpression *Resolve(FCompileContext& ctx)
|
||||
{
|
||||
CHECKRESOLVED();
|
||||
|
||||
if (!ResolveArgs(ctx, 1, 3, false))
|
||||
return NULL;
|
||||
|
||||
for (int i = ArgList->Size(); i > 1;)
|
||||
{
|
||||
if (!(*ArgList)[--i]->ValueType.isNumeric())
|
||||
{
|
||||
ScriptPosition.Message(MSG_ERROR, "numeric value expected for parameter");
|
||||
delete this;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
switch ((*ArgList)[0]->ValueType.Type)
|
||||
{
|
||||
case VAL_Class: case VAL_Name:break;
|
||||
default:
|
||||
ScriptPosition.Message(MSG_ERROR, "actor class expected for parameter");
|
||||
delete this;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ValueType = VAL_Float;
|
||||
return this;
|
||||
}
|
||||
|
||||
ExpVal EvalExpression(AActor *self)
|
||||
{
|
||||
ExpVal ret;
|
||||
ret.Type = VAL_Int;
|
||||
|
||||
const PClass * checkclass;
|
||||
{
|
||||
ExpVal v = (*ArgList)[0]->EvalExpression(self);
|
||||
checkclass = v.GetClass();
|
||||
if (!checkclass)
|
||||
{
|
||||
checkclass = PClass::FindClass(v.GetName());
|
||||
if (!checkclass) { ret.Int = 0; return ret; }
|
||||
}
|
||||
}
|
||||
|
||||
bool match_superclass = false;
|
||||
int pick_pointer = AAPTR_DEFAULT;
|
||||
|
||||
switch (ArgList->Size())
|
||||
{
|
||||
case 3: match_superclass = (*ArgList)[2]->EvalExpression(self).GetBool();
|
||||
case 2: pick_pointer = (*ArgList)[1]->EvalExpression(self).GetInt();
|
||||
}
|
||||
|
||||
self = COPY_AAPTR(self, pick_pointer);
|
||||
if (!self){ ret.Int = 0; return ret; }
|
||||
ret.Int = match_superclass ? checkclass->IsAncestorOf(self->GetClass()) : checkclass == self->GetClass();
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
||||
GLOBALFUNCTION_ADDER(CheckClass);
|
|
@ -51,7 +51,7 @@ const char *GetVersionString();
|
|||
// Version identifier for network games.
|
||||
// Bump it every time you do a release unless you're certain you
|
||||
// didn't change anything that will affect sync.
|
||||
#define NETGAMEVERSION 230
|
||||
#define NETGAMEVERSION 231
|
||||
|
||||
// Version stored in the ini's [LastRun] section.
|
||||
// Bump it if you made some configuration change that you want to
|
||||
|
|
|
@ -304,6 +304,9 @@ ACTOR Actor native //: Thinker
|
|||
action native A_SetDamageType(name damagetype);
|
||||
action native A_DropItem(class<Actor> item, int dropamount = -1, int chance = 256);
|
||||
action native A_SetSpeed(float speed);
|
||||
action native A_DamageSelf(int amount, name damagetype = "none");
|
||||
action native A_DamageTarget(int amount, name damagetype = "none");
|
||||
action native A_DamageTracer(int amount, name damagetype = "none");
|
||||
|
||||
action native A_CheckSightOrRange(float distance, state label);
|
||||
action native A_CheckRange(float distance, state label);
|
||||
|
|
|
@ -836,6 +836,7 @@ SCORE_BONUS = "BONUS";
|
|||
SCORE_COLOR = "COLOR";
|
||||
SCORE_SECRET = "SECRET";
|
||||
SCORE_NAME = "NAME";
|
||||
SCORE_DELAY = "DELAY(ms)";
|
||||
SCORE_KILLS = "KILLS";
|
||||
SCORE_FRAGS = "FRAGS";
|
||||
SCORE_DEATHS = "DEATHS";
|
||||
|
|
|
@ -341,6 +341,7 @@ OptionMenu "OptionsMenu"
|
|||
Submenu "Automap Options", "AutomapOptions"
|
||||
Submenu "HUD Options", "HUDOptions"
|
||||
Submenu "Miscellaneous Options", "MiscOptions"
|
||||
Submenu "Network Options", "NetworkOptions"
|
||||
Submenu "Sound Options", "SoundOptions"
|
||||
Submenu "Display Options", "VideoOptions"
|
||||
Submenu "Set video mode", "VideoModeMenu"
|
||||
|
@ -805,6 +806,13 @@ OptionValue "AltHUDTime"
|
|||
9, "System"
|
||||
}
|
||||
|
||||
OptionValue "AltHUDLag"
|
||||
{
|
||||
0, "Off"
|
||||
1, "Netgames only"
|
||||
2, "Always"
|
||||
}
|
||||
|
||||
OptionMenu "AltHUDOptions"
|
||||
{
|
||||
Title "Alternative HUD"
|
||||
|
@ -819,6 +827,7 @@ OptionMenu "AltHUDOptions"
|
|||
Option "Show weapons", "hud_showweapons", "OnOff"
|
||||
Option "Show time", "hud_showtime", "AltHUDTime"
|
||||
Option "Time color", "hud_timecolor", "TextColors"
|
||||
Option "Show network latency", "hud_showlag", "AltHUDLag"
|
||||
Slider "Red ammo display below %", "hud_ammo_red", 0, 100, 1, 0
|
||||
Slider "Yellow ammo display below %", "hud_ammo_yellow", 0, 100, 1, 0
|
||||
Slider "Red health display below", "hud_health_red", 0, 100, 1, 0
|
||||
|
@ -1591,3 +1600,28 @@ OptionMenu VideoModeMenu
|
|||
class VideoModeMenu
|
||||
}
|
||||
|
||||
/*=======================================
|
||||
*
|
||||
* Network options menu
|
||||
*
|
||||
*=======================================*/
|
||||
|
||||
OptionMenu NetworkOptions
|
||||
{
|
||||
Title "NETWORK OPTIONS"
|
||||
StaticText "Local options", 1
|
||||
Option "Movement prediction", "cl_noprediction", "OffOn"
|
||||
Option "Predict line actions", "cl_predict_specials", "OnOff"
|
||||
StaticText " "
|
||||
StaticText "Host options", 1
|
||||
Option "Extra Tics", "net_extratic", "ExtraTicMode"
|
||||
Option "Latency balancing", "net_ticbalance", "OnOff"
|
||||
|
||||
}
|
||||
|
||||
OptionValue ExtraTicMode
|
||||
{
|
||||
0, "None"
|
||||
1, "1"
|
||||
2, "All unacknowledged"
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue