Merge branch 'master' into disable_gettext

This commit is contained in:
Alam Ed Arias 2017-03-29 16:56:44 -04:00
commit 108b0c2732
55 changed files with 1344 additions and 3400 deletions

63
.circleci/config.yml Normal file
View File

@ -0,0 +1,63 @@
version: 2
jobs:
build:
working_directory: /root/SRB2
docker:
- image: debian:jessie
environment:
CC: ccache gcc -m32
PKG_CONFIG_LIBDIR: /usr/lib/i386-linux-gnu/pkgconfig
LIBGME_CFLAGS: -I/usr/include
LIBGME_LDFLAGS: -lgme
CCACHE_COMPRESS: true
WFLAGS: -Wno-unsuffixed-float-constants
GCC49: true
#- image: ubuntu:trusty
# environment:
# CC: ccache gcc -m32
# PKG_CONFIG_LIBDIR: /usr/lib/i386-linux-gnu/pkgconfig
# LIBGME_CFLAGS: -I/usr/include
# LIBGME_LDFLAGS: -lgme
# CCACHE_COMPRESS: true
# WFLAGS: -Wno-unsuffixed-float-constants
# GCC48: true
steps:
- run:
name: Add i386 arch
command: dpkg --add-architecture i386
- run:
name: Update APT listing
command: apt-get -qq update
- run:
name: Support S3 upload
command: apt-get -qq -y install ca-certificates
- restore_cache:
keys:
- v1-SRB2-APT
- run:
name: Install SDK
command: apt-get -qq -y install git build-essential nasm libpng12-dev:i386 libsdl2-mixer-dev:i386 libgme-dev:i386 gettext ccache wget gcc-multilib upx
- save_cache:
key: v1-SRB2-APT
paths:
- /var/cache/apt/archives
- checkout
- run:
name: Clean build
command: make -C src LINUX=1 clean
- restore_cache:
keys:
- v1-SRB2-{{ .Branch }}-{{ checksum "objs/Linux/SDL/Release/depend.dep" }}
- run:
name: Compile
command: make -C src LINUX=1 ERRORMODE=1 -k
- store_artifacts:
path: /root/SRB2/bin/Linux/Release/
destination: bin
- save_cache:
key: v1-SRB2-{{ .Branch }}-{{ checksum "objs/Linux/SDL/Release/depend.dep" }}
paths:
- /root/.ccache

View File

@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.0) cmake_minimum_required(VERSION 3.0)
project(SRB2 project(SRB2
VERSION 2.1.14 VERSION 2.1.17
LANGUAGES C) LANGUAGES C)
if(${PROJECT_SOURCE_DIR} MATCHES ${PROJECT_BINARY_DIR}) if(${PROJECT_SOURCE_DIR} MATCHES ${PROJECT_BINARY_DIR})

View File

@ -2,6 +2,7 @@
[![Build status](https://ci.appveyor.com/api/projects/status/399d4hcw9yy7hg2y?svg=true)](https://ci.appveyor.com/project/STJr/srb2) [![Build status](https://ci.appveyor.com/api/projects/status/399d4hcw9yy7hg2y?svg=true)](https://ci.appveyor.com/project/STJr/srb2)
[![Build status](https://travis-ci.org/STJr/SRB2.svg?branch=master)](https://travis-ci.org/STJr/SRB2) [![Build status](https://travis-ci.org/STJr/SRB2.svg?branch=master)](https://travis-ci.org/STJr/SRB2)
[![CircleCI](https://circleci.com/gh/STJr/SRB2/tree/master.svg?style=svg)](https://circleci.com/gh/STJr/SRB2/tree/master)
[Sonic Robo Blast 2](https://srb2.org/) is a 3D Sonic the Hedgehog fangame based on a modified version of [Doom Legacy](http://doomlegacy.sourceforge.net/). [Sonic Robo Blast 2](https://srb2.org/) is a 3D Sonic the Hedgehog fangame based on a modified version of [Doom Legacy](http://doomlegacy.sourceforge.net/).

3002
SRB2.cbp

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,4 @@
version: 2.1.16.{branch}-{build} version: 2.1.17.{branch}-{build}
os: MinGW os: MinGW
environment: environment:
@ -47,7 +47,7 @@ before_build:
- upx -V - upx -V
- ccache -V - ccache -V
- ccache -s - ccache -s
- set SRB2_MFLAGS=-C src MINGW=1 WARNINGMODE=1 GCC53=1 CCACHE=1 - set SRB2_MFLAGS=-C src MINGW=1 WARNINGMODE=1 GCC63=1 CCACHE=1
build_script: build_script:
- cmd: mingw32-make.exe %SRB2_MFLAGS% %CONFIGURATION%=1 clean - cmd: mingw32-make.exe %SRB2_MFLAGS% %CONFIGURATION%=1 clean

View File

@ -390,18 +390,25 @@ if(${SRB2_CONFIG_HWRENDER} AND ${SRB2_CONFIG_STATIC_OPENGL})
endif() endif()
if(${SRB2_CONFIG_USEASM}) if(${SRB2_CONFIG_USEASM})
#SRB2_ASM_FLAGS can be used to pass flags to either nasm or yasm.
if(${CMAKE_SYSTEM} MATCHES "Linux")
set(SRB2_ASM_FLAGS "-DLINUX ${SRB2_ASM_FLAGS}")
endif()
if(${SRB2_CONFIG_YASM}) if(${SRB2_CONFIG_YASM})
set(CMAKE_ASM_YASM_SOURCE_FILE_EXTENSIONS ${CMAKE_ASM_YASM_SOURCE_FILE_EXTENSIONS} nas) set(CMAKE_ASM_YASM_SOURCE_FILE_EXTENSIONS ${CMAKE_ASM_YASM_SOURCE_FILE_EXTENSIONS} nas)
set(CMAKE_ASM_YASM_FLAGS "${SRB2_ASM_FLAGS}" CACHE STRING "Flags used by the assembler during all build types.")
enable_language(ASM_YASM) enable_language(ASM_YASM)
else() else()
set(CMAKE_ASM_NASM_SOURCE_FILE_EXTENSIONS ${CMAKE_ASM_NASM_SOURCE_FILE_EXTENSIONS} nas) set(CMAKE_ASM_NASM_SOURCE_FILE_EXTENSIONS ${CMAKE_ASM_NASM_SOURCE_FILE_EXTENSIONS} nas)
set(CMAKE_ASM_NASM_FLAGS "${SRB2_ASM_FLAGS}" CACHE STRING "Flags used by the assembler during all build types.")
enable_language(ASM_NASM) enable_language(ASM_NASM)
endif() endif()
set(SRB2_USEASM ON) set(SRB2_USEASM ON)
add_definitions(-DUSEASM) add_definitions(-DUSEASM)
else() else()
set(SRB2_USEASM OFF) set(SRB2_USEASM OFF)
add_definitions(-DNOASM -DNONX86) add_definitions(-DNONX86 -DNORUSEASM)
endif() endif()
# Targets # Targets

View File

@ -7,6 +7,23 @@
# and other things # and other things
# #
ifdef GCC63
GCC62=1
endif
ifdef GCC62
GCC61=1
endif
ifdef GCC61
GCC54=1
endif
ifdef GCC54
GCC53=1
endif
ifdef GCC53 ifdef GCC53
GCC52=1 GCC52=1
endif endif
@ -164,19 +181,29 @@ ifdef GCC45
WFLAGS+=-Wunsuffixed-float-constants WFLAGS+=-Wunsuffixed-float-constants
endif endif
endif endif
ifdef NOLDWARNING ifdef NOLDWARNING
LDFLAGS+=-Wl,--as-needed LDFLAGS+=-Wl,--as-needed
endif endif
ifdef ERRORMODE ifdef ERRORMODE
WFLAGS+=-Werror WFLAGS+=-Werror
endif endif
WFLAGS+=$(OLDWFLAGS)
ifdef GCC43 ifdef GCC43
#WFLAGS+=-Wno-error=clobbered #WFLAGS+=-Wno-error=clobbered
endif endif
ifdef GCC46 ifdef GCC46
WFLAGS+=-Wno-error=suggest-attribute=noreturn WFLAGS+=-Wno-error=suggest-attribute=noreturn
endif endif
WFLAGS+=$(OLDWFLAGS) ifdef GCC54
WFLAGS+=-Wno-logical-op -Wno-error=logical-op
endif
ifdef GCC61
WFLAGS+=-Wno-tautological-compare -Wno-error=tautological-compare
endif
#indicate platform and what interface use with #indicate platform and what interface use with

View File

@ -72,14 +72,21 @@
#define MAX_REASONLENGTH 30 #define MAX_REASONLENGTH 30
boolean server = true; // true or false but !server == client boolean server = true; // true or false but !server == client
#define client (!server)
boolean nodownload = false; boolean nodownload = false;
static boolean serverrunning = false; static boolean serverrunning = false;
INT32 serverplayer = 0; INT32 serverplayer = 0;
char motd[254], server_context[8]; // Message of the Day, Unique Context (even without Mumble support) char motd[254], server_context[8]; // Message of the Day, Unique Context (even without Mumble support)
// server specific vars // Server specific vars
UINT8 playernode[MAXPLAYERS]; UINT8 playernode[MAXPLAYERS];
// Minimum timeout for sending the savegame
// The actual timeout will be longer depending on the savegame length
tic_t jointimeout = (10*TICRATE);
static boolean sendingsavegame[MAXNETNODES]; // Are we sending the savegame?
static tic_t freezetimeout[MAXNETNODES]; // Until when can this node freeze the server before getting a timeout?
#ifdef NEWPING #ifdef NEWPING
UINT16 pingmeasurecount = 1; UINT16 pingmeasurecount = 1;
UINT32 realpingtable[MAXPLAYERS]; //the base table of ping where an average will be sent to everyone. UINT32 realpingtable[MAXPLAYERS]; //the base table of ping where an average will be sent to everyone.
@ -108,7 +115,7 @@ static UINT8 resynch_local_inprogress = false; // WE are desynched and getting p
static UINT8 player_joining = false; static UINT8 player_joining = false;
UINT8 hu_resynching = 0; UINT8 hu_resynching = 0;
// client specific // Client specific
static ticcmd_t localcmds; static ticcmd_t localcmds;
static ticcmd_t localcmds2; static ticcmd_t localcmds2;
static boolean cl_packetmissed; static boolean cl_packetmissed;
@ -404,7 +411,7 @@ static void ExtraDataTicker(void)
// If you are a client, you can safely forget the net commands for this tic // If you are a client, you can safely forget the net commands for this tic
// If you are the server, you need to remember them until every client has been aknowledged, // If you are the server, you need to remember them until every client has been aknowledged,
// because if you need to resend a PT_SERVERTICS packet, you need to put the commands in it // because if you need to resend a PT_SERVERTICS packet, you need to put the commands in it
if (!server) if (client)
D_FreeTextcmd(gametic); D_FreeTextcmd(gametic);
} }
@ -868,12 +875,13 @@ static inline void resynch_write_others(resynchend_pak *rst)
{ {
UINT8 i; UINT8 i;
rst->ingame = rst->ctfteam = 0; rst->ingame = 0;
for (i = 0; i < MAXPLAYERS; ++i) for (i = 0; i < MAXPLAYERS; ++i)
{ {
if (!playeringame[i]) if (!playeringame[i])
{ {
rst->ctfteam[i] = 0;
rst->score[i] = 0; rst->score[i] = 0;
rst->numboxes[i] = 0; rst->numboxes[i] = 0;
rst->totalring[i] = 0; rst->totalring[i] = 0;
@ -883,11 +891,8 @@ static inline void resynch_write_others(resynchend_pak *rst)
} }
if (!players[i].spectator) if (!players[i].spectator)
{
rst->ingame |= (1<<i); rst->ingame |= (1<<i);
if (players[i].ctfteam > 1) rst->ctfteam[i] = (INT32)LONG(players[i].ctfteam);
rst->ctfteam |= (1<<i);
}
rst->score[i] = (UINT32)LONG(players[i].score); rst->score[i] = (UINT32)LONG(players[i].score);
rst->numboxes[i] = SHORT(players[i].numboxes); rst->numboxes[i] = SHORT(players[i].numboxes);
rst->totalring[i] = SHORT(players[i].totalring); rst->totalring[i] = SHORT(players[i].totalring);
@ -897,28 +902,18 @@ static inline void resynch_write_others(resynchend_pak *rst)
// endian safeness // endian safeness
rst->ingame = (UINT32)LONG(rst->ingame); rst->ingame = (UINT32)LONG(rst->ingame);
rst->ctfteam = (UINT32)LONG(rst->ctfteam);
} }
static inline void resynch_read_others(resynchend_pak *p) static inline void resynch_read_others(resynchend_pak *p)
{ {
UINT8 i; UINT8 i;
UINT32 loc_ingame = (UINT32)LONG(p->ingame); UINT32 loc_ingame = (UINT32)LONG(p->ingame);
UINT32 loc_ctfteam = (UINT32)LONG(p->ctfteam);
for (i = 0; i < MAXPLAYERS; ++i) for (i = 0; i < MAXPLAYERS; ++i)
{ {
// We don't care if they're in the game or not, just write all the data. // We don't care if they're in the game or not, just write all the data.
if (loc_ingame & (1<<i)) players[i].spectator = !(loc_ingame & (1<<i));
{ players[i].ctfteam = (INT32)LONG(p->ctfteam[i]); // no, 0 does not mean spectator, at least not in Match
players[i].spectator = false;
players[i].ctfteam = (loc_ctfteam & (1<<i)) ? 2 : 1;
}
else
{
players[i].spectator = true;
players[i].ctfteam = 0;
}
players[i].score = (UINT32)LONG(p->score[i]); players[i].score = (UINT32)LONG(p->score[i]);
players[i].numboxes = SHORT(p->numboxes[i]); players[i].numboxes = SHORT(p->numboxes[i]);
players[i].totalring = SHORT(p->totalring[i]); players[i].totalring = SHORT(p->totalring[i]);
@ -1038,6 +1033,9 @@ static void SV_AcknowledgeResynchAck(INT32 node, UINT8 rsg)
resynch_status[node] &= ~(1<<rsg); resynch_status[node] &= ~(1<<rsg);
--resynch_score[node]; // unpenalize --resynch_score[node]; // unpenalize
} }
// Don't let resynch cause a timeout
freezetimeout[node] = I_GetTime() + connectiontimeout;
} }
// ----------------------------------------------------------------- // -----------------------------------------------------------------
// end resynch // end resynch
@ -1131,12 +1129,17 @@ static inline void CL_DrawConnectionStatus(void)
{ {
#ifdef JOININGAME #ifdef JOININGAME
case CL_DOWNLOADSAVEGAME: case CL_DOWNLOADSAVEGAME:
cltext = M_GetText("Downloading game state..."); if (lastfilenum != -1)
Net_GetNetStat(); {
V_DrawString(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-24, V_20TRANS|V_MONOSPACE, cltext = M_GetText("Downloading game state...");
va(" %4uK",fileneeded[lastfilenum].currentsize>>10)); Net_GetNetStat();
V_DrawRightAlignedString(BASEVIDWIDTH/2+128, BASEVIDHEIGHT-24, V_20TRANS|V_MONOSPACE, V_DrawString(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-24, V_20TRANS|V_MONOSPACE,
va("%3.1fK/s ", ((double)getbps)/1024)); va(" %4uK",fileneeded[lastfilenum].currentsize>>10));
V_DrawRightAlignedString(BASEVIDWIDTH/2+128, BASEVIDHEIGHT-24, V_20TRANS|V_MONOSPACE,
va("%3.1fK/s ", ((double)getbps)/1024));
}
else
cltext = M_GetText("Waiting to download game state...");
break; break;
#endif #endif
case CL_ASKJOIN: case CL_ASKJOIN:
@ -1151,25 +1154,31 @@ static inline void CL_DrawConnectionStatus(void)
} }
else else
{ {
INT32 dldlength; if (lastfilenum != -1)
static char tempname[32]; {
INT32 dldlength;
static char tempname[32];
Net_GetNetStat(); Net_GetNetStat();
dldlength = (INT32)((fileneeded[lastfilenum].currentsize/(double)fileneeded[lastfilenum].totalsize) * 256); dldlength = (INT32)((fileneeded[lastfilenum].currentsize/(double)fileneeded[lastfilenum].totalsize) * 256);
if (dldlength > 256) if (dldlength > 256)
dldlength = 256; dldlength = 256;
V_DrawFill(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-24, 256, 8, 175); V_DrawFill(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-24, 256, 8, 175);
V_DrawFill(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-24, dldlength, 8, 160); V_DrawFill(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-24, dldlength, 8, 160);
memset(tempname, 0, sizeof(tempname)); memset(tempname, 0, sizeof(tempname));
nameonly(strncpy(tempname, fileneeded[lastfilenum].filename, 31)); nameonly(strncpy(tempname, fileneeded[lastfilenum].filename, 31));
V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT-24-32, V_YELLOWMAP, V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT-24-32, V_YELLOWMAP,
va(M_GetText("Downloading \"%s\""), tempname)); va(M_GetText("Downloading \"%s\""), tempname));
V_DrawString(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-24, V_20TRANS|V_MONOSPACE, V_DrawString(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-24, V_20TRANS|V_MONOSPACE,
va(" %4uK/%4uK",fileneeded[lastfilenum].currentsize>>10,fileneeded[lastfilenum].totalsize>>10)); va(" %4uK/%4uK",fileneeded[lastfilenum].currentsize>>10,fileneeded[lastfilenum].totalsize>>10));
V_DrawRightAlignedString(BASEVIDWIDTH/2+128, BASEVIDHEIGHT-24, V_20TRANS|V_MONOSPACE, V_DrawRightAlignedString(BASEVIDWIDTH/2+128, BASEVIDHEIGHT-24, V_20TRANS|V_MONOSPACE,
va("%3.1fK/s ", ((double)getbps)/1024)); va("%3.1fK/s ", ((double)getbps)/1024));
}
else
V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT-24-32, V_YELLOWMAP,
M_GetText("Waiting to download files..."));
} }
} }
#endif #endif
@ -1458,6 +1467,10 @@ static void SV_SendSaveGame(INT32 node)
SV_SendRam(node, buffertosend, length, SF_RAM, 0); SV_SendRam(node, buffertosend, length, SF_RAM, 0);
save_p = NULL; save_p = NULL;
// Remember when we started sending the savegame so we can handle timeouts
sendingsavegame[node] = true;
freezetimeout[node] = I_GetTime() + jointimeout + length / 1024; // 1 extra tic for each kilobyte
} }
#ifdef DUMPCONSISTENCY #ifdef DUMPCONSISTENCY
@ -1750,7 +1763,7 @@ static boolean CL_ServerConnectionSearchTicker(boolean viams, tic_t *asksent)
return false; return false;
} }
if (!server) if (client)
{ {
D_ParseFileneeded(serverlist[i].info.fileneedednum, D_ParseFileneeded(serverlist[i].info.fileneedednum,
serverlist[i].info.fileneeded); serverlist[i].info.fileneeded);
@ -1924,7 +1937,7 @@ static boolean CL_ServerConnectionTicker(boolean viams, const char *tmpsave, tic
*oldtic = I_GetTime(); *oldtic = I_GetTime();
#ifdef CLIENT_LOADINGSCREEN #ifdef CLIENT_LOADINGSCREEN
if (!server && cl_mode != CL_CONNECTED && cl_mode != CL_ABORTED) if (client && cl_mode != CL_CONNECTED && cl_mode != CL_ABORTED)
{ {
F_TitleScreenTicker(true); F_TitleScreenTicker(true);
F_TitleScreenDrawer(); F_TitleScreenDrawer();
@ -1966,7 +1979,7 @@ static void CL_ConnectToServer(boolean viams)
cl_mode = CL_SEARCHING; cl_mode = CL_SEARCHING;
#ifdef CLIENT_LOADINGSCREEN #ifdef CLIENT_LOADINGSCREEN
lastfilenum = 0; lastfilenum = -1;
#endif #endif
#ifdef JOININGAME #ifdef JOININGAME
@ -2037,7 +2050,7 @@ static void CL_ConnectToServer(boolean viams)
pnumnodes++; pnumnodes++;
} }
} }
while (!(cl_mode == CL_CONNECTED && (!server || (server && nodewaited <= pnumnodes)))); while (!(cl_mode == CL_CONNECTED && (client || (server && nodewaited <= pnumnodes))));
DEBFILE(va("Synchronisation Finished\n")); DEBFILE(va("Synchronisation Finished\n"));
@ -2574,6 +2587,14 @@ static void Command_Kick(void)
WRITESINT8(p, pn); WRITESINT8(p, pn);
if (pn == -1 || pn == 0) if (pn == -1 || pn == 0)
return; return;
// Special case if we are trying to kick a player who is downloading the game state:
// trigger a timeout instead of kicking them, because a kick would only
// take effect after they have finished downloading
if (sendingsavegame[playernode[pn]])
{
Net_ConnectionTimeout(playernode[pn]);
return;
}
if (COM_Argc() == 2) if (COM_Argc() == 2)
{ {
WRITEUINT8(p, KICK_MSG_GO_AWAY); WRITEUINT8(p, KICK_MSG_GO_AWAY);
@ -2786,7 +2807,12 @@ consvar_t cv_blamecfail = {"blamecfail", "Off", 0, CV_OnOff, NULL, 0, NULL, NULL
// max file size to send to a player (in kilobytes) // max file size to send to a player (in kilobytes)
static CV_PossibleValue_t maxsend_cons_t[] = {{0, "MIN"}, {51200, "MAX"}, {0, NULL}}; static CV_PossibleValue_t maxsend_cons_t[] = {{0, "MIN"}, {51200, "MAX"}, {0, NULL}};
consvar_t cv_maxsend = {"maxsend", "1024", CV_SAVE, maxsend_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_maxsend = {"maxsend", "4096", CV_SAVE, maxsend_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_noticedownload = {"noticedownload", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
// Speed of file downloading (in packets per tic)
static CV_PossibleValue_t downloadspeed_cons_t[] = {{0, "MIN"}, {32, "MAX"}, {0, NULL}};
consvar_t cv_downloadspeed = {"downloadspeed", "16", CV_SAVE, downloadspeed_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
static void Got_AddPlayer(UINT8 **p, INT32 playernum); static void Got_AddPlayer(UINT8 **p, INT32 playernum);
@ -2809,6 +2835,9 @@ void D_ClientServerInit(void)
COM_AddCommand("drop", Command_Drop); COM_AddCommand("drop", Command_Drop);
COM_AddCommand("droprate", Command_Droprate); COM_AddCommand("droprate", Command_Droprate);
#endif #endif
#ifdef _DEBUG
COM_AddCommand("numnodes", Command_Numnodes);
#endif
#endif #endif
RegisterNetXCmd(XD_KICK, Got_KickCmd); RegisterNetXCmd(XD_KICK, Got_KickCmd);
@ -2844,6 +2873,7 @@ static void ResetNode(INT32 node)
supposedtics[node] = gametic; supposedtics[node] = gametic;
nodewaiting[node] = 0; nodewaiting[node] = 0;
playerpernode[node] = 0; playerpernode[node] = 0;
sendingsavegame[node] = false;
} }
void SV_ResetServer(void) void SV_ResetServer(void)
@ -3136,7 +3166,7 @@ void CL_RemoveSplitscreenPlayer(void)
// is there a game running // is there a game running
boolean Playing(void) boolean Playing(void)
{ {
return (server && serverrunning) || (!server && cl_mode == CL_CONNECTED); return (server && serverrunning) || (client && cl_mode == CL_CONNECTED);
} }
boolean SV_SpawnServer(void) boolean SV_SpawnServer(void)
@ -3399,12 +3429,19 @@ static void HandlePacketFromAwayNode(SINT8 node)
} }
if (cl_mode == CL_WAITJOINRESPONSE) if (cl_mode == CL_WAITJOINRESPONSE)
{ {
// Save the reason so it can be displayed after quitting the netgame
char *reason = strdup(netbuffer->u.serverrefuse.reason);
if (!reason)
I_Error("Out of memory!\n");
D_QuitNetGame(); D_QuitNetGame();
CL_Reset(); CL_Reset();
D_StartTitle(); D_StartTitle();
M_StartMessage(va(M_GetText("Server refuses connection\n\nReason:\n%s"), M_StartMessage(va(M_GetText("Server refuses connection\n\nReason:\n%s"),
netbuffer->u.serverrefuse.reason), NULL, MM_NOTHING); reason), NULL, MM_NOTHING);
free(reason);
// Will be reset by caller. Signals refusal. // Will be reset by caller. Signals refusal.
cl_mode = CL_ABORTED; cl_mode = CL_ABORTED;
@ -3425,7 +3462,7 @@ static void HandlePacketFromAwayNode(SINT8 node)
if (cl_mode != CL_WAITJOINRESPONSE) if (cl_mode != CL_WAITJOINRESPONSE)
break; break;
if (!server) if (client)
{ {
maketic = gametic = neededtic = (tic_t)LONG(netbuffer->u.servercfg.gametic); maketic = gametic = neededtic = (tic_t)LONG(netbuffer->u.servercfg.gametic);
gametype = netbuffer->u.servercfg.gametype; gametype = netbuffer->u.servercfg.gametype;
@ -3553,7 +3590,7 @@ FILESTAMP
case PT_CLIENT2MIS: case PT_CLIENT2MIS:
case PT_NODEKEEPALIVE: case PT_NODEKEEPALIVE:
case PT_NODEKEEPALIVEMIS: case PT_NODEKEEPALIVEMIS:
if (!server) if (client)
break; break;
// Ignore tics from those not synched // Ignore tics from those not synched
@ -3586,6 +3623,13 @@ FILESTAMP
|| netbuffer->packettype == PT_NODEKEEPALIVEMIS) || netbuffer->packettype == PT_NODEKEEPALIVEMIS)
break; break;
// If a client sends a ticcmd it should mean they are done receiving the savegame
sendingsavegame[node] = false;
// As long as clients send valid ticcmds, the server can keep running, so reset the timeout
/// \todo Use a separate cvar for that kind of timeout?
freezetimeout[node] = I_GetTime() + connectiontimeout;
// Copy ticcmd // Copy ticcmd
G_MoveTiccmd(&netcmds[maketic%BACKUPTICS][netconsole], &netbuffer->u.clientpak.cmd, 1); G_MoveTiccmd(&netcmds[maketic%BACKUPTICS][netconsole], &netbuffer->u.clientpak.cmd, 1);
@ -3652,7 +3696,7 @@ FILESTAMP
case PT_TEXTCMD2: // splitscreen special case PT_TEXTCMD2: // splitscreen special
netconsole = nodetoplayer2[node]; netconsole = nodetoplayer2[node];
case PT_TEXTCMD: case PT_TEXTCMD:
if (!server) if (client)
break; break;
if (netconsole < 0 || netconsole >= MAXPLAYERS) if (netconsole < 0 || netconsole >= MAXPLAYERS)
@ -3696,7 +3740,7 @@ FILESTAMP
break; break;
case PT_NODETIMEOUT: case PT_NODETIMEOUT:
case PT_CLIENTQUIT: case PT_CLIENTQUIT:
if (!server) if (client)
break; break;
// nodeingame will be put false in the execution of kick command // nodeingame will be put false in the execution of kick command
@ -3728,7 +3772,7 @@ FILESTAMP
// Only accept PT_RESYNCHEND from the server. // Only accept PT_RESYNCHEND from the server.
if (node != servernode) if (node != servernode)
{ {
CONS_Alert(CONS_WARNING, M_GetText("%s recieved from non-host %d\n"), "PT_RESYNCHEND", node); CONS_Alert(CONS_WARNING, M_GetText("%s received from non-host %d\n"), "PT_RESYNCHEND", node);
if (server) if (server)
{ {
@ -3806,13 +3850,20 @@ FILESTAMP
neededtic = realend; neededtic = realend;
} }
else else
{
DEBFILE(va("frame not in bound: %u\n", neededtic)); DEBFILE(va("frame not in bound: %u\n", neededtic));
/*if (realend < neededtic - 2 * TICRATE || neededtic + 2 * TICRATE < realstart)
I_Error("Received an out of order PT_SERVERTICS packet!\n"
"Got tics %d-%d, needed tic %d\n\n"
"Please report this crash on the Master Board,\n"
"IRC or Discord so it can be fixed.\n", (INT32)realstart, (INT32)realend, (INT32)neededtic);*/
}
break; break;
case PT_RESYNCHING: case PT_RESYNCHING:
// Only accept PT_RESYNCHING from the server. // Only accept PT_RESYNCHING from the server.
if (node != servernode) if (node != servernode)
{ {
CONS_Alert(CONS_WARNING, M_GetText("%s recieved from non-host %d\n"), "PT_RESYNCHING", node); CONS_Alert(CONS_WARNING, M_GetText("%s received from non-host %d\n"), "PT_RESYNCHING", node);
if (server) if (server)
{ {
@ -3832,7 +3883,7 @@ FILESTAMP
// Only accept PT_PING from the server. // Only accept PT_PING from the server.
if (node != servernode) if (node != servernode)
{ {
CONS_Alert(CONS_WARNING, M_GetText("%s recieved from non-host %d\n"), "PT_PING", node); CONS_Alert(CONS_WARNING, M_GetText("%s received from non-host %d\n"), "PT_PING", node);
if (server) if (server)
{ {
@ -3846,7 +3897,7 @@ FILESTAMP
} }
//Update client ping table from the server. //Update client ping table from the server.
if (!server) if (client)
{ {
INT32 i; INT32 i;
for (i = 0; i < MAXNETNODES; i++) for (i = 0; i < MAXNETNODES; i++)
@ -3859,7 +3910,7 @@ FILESTAMP
case PT_SERVERCFG: case PT_SERVERCFG:
break; break;
case PT_FILEFRAGMENT: case PT_FILEFRAGMENT:
if (!server) if (client)
Got_Filetxpak(); Got_Filetxpak();
break; break;
default: default:
@ -3889,17 +3940,18 @@ FILESTAMP
HandleConnect(node); HandleConnect(node);
continue; continue;
} }
if (netbuffer->packettype == PT_SERVERSHUTDOWN && node == servernode if (node == servernode && client && cl_mode != CL_SEARCHING)
&& !server && cl_mode != CL_SEARCHING)
{ {
HandleShutdown(node); if (netbuffer->packettype == PT_SERVERSHUTDOWN)
continue; {
} HandleShutdown(node);
if (netbuffer->packettype == PT_NODETIMEOUT && node == servernode continue;
&& !server && cl_mode != CL_SEARCHING) }
{ if (netbuffer->packettype == PT_NODETIMEOUT)
HandleTimeout(node); {
continue; HandleTimeout(node);
continue;
}
} }
#ifndef NONET #ifndef NONET
@ -3916,7 +3968,7 @@ FILESTAMP
// Packet received from someone already playing // Packet received from someone already playing
if (nodeingame[node]) if (nodeingame[node])
HandlePacketFromPlayer(node); HandlePacketFromPlayer(node);
// Packet received from someone trying to join // Packet received from someone not playing
else else
HandlePacketFromAwayNode(node); HandlePacketFromAwayNode(node);
} }
@ -4047,7 +4099,7 @@ static void CL_SendClientCmd(void)
if (gamestate == GS_WAITINGPLAYERS) if (gamestate == GS_WAITINGPLAYERS)
{ {
// send NODEKEEPALIVE packet // Send PT_NODEKEEPALIVE packet
netbuffer->packettype += 4; netbuffer->packettype += 4;
packetsize = sizeof (clientcmd_pak) - sizeof (ticcmd_t) - sizeof (INT16); packetsize = sizeof (clientcmd_pak) - sizeof (ticcmd_t) - sizeof (INT16);
HSendPacket(servernode, false, 0, packetsize); HSendPacket(servernode, false, 0, packetsize);
@ -4057,7 +4109,7 @@ static void CL_SendClientCmd(void)
G_MoveTiccmd(&netbuffer->u.clientpak.cmd, &localcmds, 1); G_MoveTiccmd(&netbuffer->u.clientpak.cmd, &localcmds, 1);
netbuffer->u.clientpak.consistancy = SHORT(consistancy[gametic%BACKUPTICS]); netbuffer->u.clientpak.consistancy = SHORT(consistancy[gametic%BACKUPTICS]);
// send a special packet with 2 cmd for splitscreen // Send a special packet with 2 cmd for splitscreen
if (splitscreen || botingame) if (splitscreen || botingame)
{ {
netbuffer->packettype += 2; netbuffer->packettype += 2;
@ -4072,23 +4124,23 @@ static void CL_SendClientCmd(void)
if (cl_mode == CL_CONNECTED || dedicated) if (cl_mode == CL_CONNECTED || dedicated)
{ {
// send extra data if needed // Send extra data if needed
if (localtextcmd[0]) if (localtextcmd[0])
{ {
netbuffer->packettype = PT_TEXTCMD; netbuffer->packettype = PT_TEXTCMD;
M_Memcpy(netbuffer->u.textcmd,localtextcmd, localtextcmd[0]+1); M_Memcpy(netbuffer->u.textcmd,localtextcmd, localtextcmd[0]+1);
// all extra data have been sended // All extra data have been sent
if (HSendPacket(servernode, true, 0, localtextcmd[0]+1)) // send can fail... if (HSendPacket(servernode, true, 0, localtextcmd[0]+1)) // Send can fail...
localtextcmd[0] = 0; localtextcmd[0] = 0;
} }
// send extra data if needed for player 2 (splitscreen) // Send extra data if needed for player 2 (splitscreen)
if (localtextcmd2[0]) if (localtextcmd2[0])
{ {
netbuffer->packettype = PT_TEXTCMD2; netbuffer->packettype = PT_TEXTCMD2;
M_Memcpy(netbuffer->u.textcmd, localtextcmd2, localtextcmd2[0]+1); M_Memcpy(netbuffer->u.textcmd, localtextcmd2, localtextcmd2[0]+1);
// all extra data have been sended // All extra data have been sent
if (HSendPacket(servernode, true, 0, localtextcmd2[0]+1)) // send can fail... if (HSendPacket(servernode, true, 0, localtextcmd2[0]+1)) // Send can fail...
localtextcmd2[0] = 0; localtextcmd2[0] = 0;
} }
} }
@ -4352,7 +4404,7 @@ static inline void PingUpdate(void)
//check for ping limit breakage. //check for ping limit breakage.
if (cv_maxping.value) if (cv_maxping.value)
{ {
for (i = 1; i < MAXNETNODES; i++) for (i = 1; i < MAXPLAYERS; i++)
{ {
if (playeringame[i] && (realpingtable[i] / pingmeasurecount > (unsigned)cv_maxping.value)) if (playeringame[i] && (realpingtable[i] / pingmeasurecount > (unsigned)cv_maxping.value))
{ {
@ -4366,7 +4418,7 @@ static inline void PingUpdate(void)
//in that case, it is probably the server's fault. //in that case, it is probably the server's fault.
if (numlaggers < D_NumPlayers() - 1) if (numlaggers < D_NumPlayers() - 1)
{ {
for (i = 1; i < MAXNETNODES; i++) for (i = 1; i < MAXPLAYERS; i++)
{ {
if (playeringame[i] && laggers[i]) if (playeringame[i] && laggers[i])
{ {
@ -4381,7 +4433,7 @@ static inline void PingUpdate(void)
} }
//make the ping packet and clear server data for next one //make the ping packet and clear server data for next one
for (i = 0; i < MAXNETNODES; i++) for (i = 0; i < MAXPLAYERS; i++)
{ {
netbuffer->u.pingtable[i] = realpingtable[i] / pingmeasurecount; netbuffer->u.pingtable[i] = realpingtable[i] / pingmeasurecount;
//server takes a snapshot of the real ping for display. //server takes a snapshot of the real ping for display.
@ -4391,7 +4443,7 @@ static inline void PingUpdate(void)
} }
//send out our ping packets //send out our ping packets
for (i = 0; i < MAXNETNODES; i++) for (i = 0; i < MAXPLAYERS; i++)
if (playeringame[i]) if (playeringame[i])
HSendPacket(i, true, 0, sizeof(INT32) * MAXPLAYERS); HSendPacket(i, true, 0, sizeof(INT32) * MAXPLAYERS);
@ -4440,7 +4492,7 @@ void NetUpdate(void)
} }
#endif #endif
if (!server) if (client)
maketic = neededtic; maketic = neededtic;
Local_Maketic(realtics); // make local tic, and call menu? Local_Maketic(realtics); // make local tic, and call menu?
@ -4455,7 +4507,7 @@ FILESTAMP
MasterClient_Ticker(); // Acking the Master Server MasterClient_Ticker(); // Acking the Master Server
if (!server) if (client)
{ {
if (!resynch_local_inprogress) if (!resynch_local_inprogress)
CL_SendClientCmd(); // Send tic cmd CL_SendClientCmd(); // Send tic cmd
@ -4505,6 +4557,11 @@ FILESTAMP
} }
} }
Net_AckTicker(); Net_AckTicker();
// Handle timeouts to prevent definitive freezes from happenning
if (server)
for (i = 1; i < MAXNETNODES; i++)
if (nodeingame[i] && freezetimeout[i] < I_GetTime())
Net_ConnectionTimeout(i);
nowtime /= NEWTICRATERATIO; nowtime /= NEWTICRATERATIO;
if (nowtime > resptime) if (nowtime > resptime)
{ {

View File

@ -80,6 +80,9 @@ typedef enum
void Command_Drop(void); void Command_Drop(void);
void Command_Droprate(void); void Command_Droprate(void);
#endif #endif
#ifdef _DEBUG
void Command_Numnodes(void);
#endif
#if defined(_MSC_VER) #if defined(_MSC_VER)
#pragma pack(1) #pragma pack(1)
@ -133,7 +136,7 @@ typedef struct
fixed_t flagz[2]; fixed_t flagz[2];
UINT32 ingame; // Spectator bit for each player UINT32 ingame; // Spectator bit for each player
UINT32 ctfteam; // If not spectator, then which team? INT32 ctfteam[MAXPLAYERS]; // Which team? (can't be 1 bit, since in regular Match there are no teams)
// Resynch game scores and the like all at once // Resynch game scores and the like all at once
UINT32 score[MAXPLAYERS]; // Everyone's score UINT32 score[MAXPLAYERS]; // Everyone's score
@ -442,6 +445,7 @@ extern consvar_t cv_playbackspeed;
#define KICK_MSG_CUSTOM_BAN 8 #define KICK_MSG_CUSTOM_BAN 8
extern boolean server; extern boolean server;
#define client (!server)
extern boolean dedicated; // For dedicated server extern boolean dedicated; // For dedicated server
extern UINT16 software_MAXPACKETLENGTH; extern UINT16 software_MAXPACKETLENGTH;
extern boolean acceptnewnode; extern boolean acceptnewnode;
@ -449,13 +453,14 @@ extern SINT8 servernode;
void Command_Ping_f(void); void Command_Ping_f(void);
extern tic_t connectiontimeout; extern tic_t connectiontimeout;
extern tic_t jointimeout;
#ifdef NEWPING #ifdef NEWPING
extern UINT16 pingmeasurecount; extern UINT16 pingmeasurecount;
extern UINT32 realpingtable[MAXPLAYERS]; extern UINT32 realpingtable[MAXPLAYERS];
extern UINT32 playerpingtable[MAXPLAYERS]; extern UINT32 playerpingtable[MAXPLAYERS];
#endif #endif
extern consvar_t cv_joinnextround, cv_allownewplayer, cv_maxplayers, cv_resynchattempts, cv_blamecfail, cv_maxsend; extern consvar_t cv_joinnextround, cv_allownewplayer, cv_maxplayers, cv_resynchattempts, cv_blamecfail, cv_maxsend, cv_noticedownload, cv_downloadspeed;
// Used in d_net, the only dependence // Used in d_net, the only dependence
tic_t ExpandTics(INT32 low); tic_t ExpandTics(INT32 low);

View File

@ -187,7 +187,7 @@ UINT8 altdown = 0; // 0x1 left, 0x2 right
// //
static inline void D_ModifierKeyResponder(event_t *ev) static inline void D_ModifierKeyResponder(event_t *ev)
{ {
if (ev->type == ev_keydown) switch (ev->data1) if (ev->type == ev_keydown || ev->type == ev_console) switch (ev->data1)
{ {
case KEY_LSHIFT: shiftdown |= 0x1; return; case KEY_LSHIFT: shiftdown |= 0x1; return;
case KEY_RSHIFT: shiftdown |= 0x2; return; case KEY_RSHIFT: shiftdown |= 0x2; return;

View File

@ -42,7 +42,7 @@
// Normally maketic >= gametic > 0 // Normally maketic >= gametic > 0
#define FORCECLOSE 0x8000 #define FORCECLOSE 0x8000
tic_t connectiontimeout = (15*TICRATE); tic_t connectiontimeout = (10*TICRATE);
/// \brief network packet /// \brief network packet
doomcom_t *doomcom = NULL; doomcom_t *doomcom = NULL;
@ -62,7 +62,7 @@ INT32 net_bandwidth;
/// \brief max length per packet /// \brief max length per packet
INT16 hardware_MAXPACKETLENGTH; INT16 hardware_MAXPACKETLENGTH;
void (*I_NetGet)(void) = NULL; boolean (*I_NetGet)(void) = NULL;
void (*I_NetSend)(void) = NULL; void (*I_NetSend)(void) = NULL;
boolean (*I_NetCanSend)(void) = NULL; boolean (*I_NetCanSend)(void) = NULL;
boolean (*I_NetCanGet)(void) = NULL; boolean (*I_NetCanGet)(void) = NULL;
@ -142,7 +142,7 @@ typedef struct
UINT8 destinationnode; // The node to send the ack to UINT8 destinationnode; // The node to send the ack to
tic_t senttime; // The time when the ack was sent tic_t senttime; // The time when the ack was sent
UINT16 length; // The packet size UINT16 length; // The packet size
UINT16 resentnum; // The number of UINT16 resentnum; // The number of times the ack has been resent
union { union {
SINT8 raw[MAXPACKETLENGTH]; SINT8 raw[MAXPACKETLENGTH];
doomdata_t data; doomdata_t data;
@ -152,11 +152,12 @@ typedef struct
typedef enum typedef enum
{ {
CLOSE = 1, // flag is set when connection is closing NF_CLOSE = 1, // Flag is set when connection is closing
NF_TIMEOUT = 2, // Flag is set when the node got a timeout
} node_flags_t; } node_flags_t;
#ifndef NONET #ifndef NONET
// table of packet that was not acknowleged can be resend (the sender window) // Table of packets that were not acknowleged can be resent (the sender window)
static ackpak_t ackpak[MAXACKPACKETS]; static ackpak_t ackpak[MAXACKPACKETS];
#endif #endif
@ -274,6 +275,38 @@ static boolean GetFreeAcknum(UINT8 *freeack, boolean lowtimer)
return false; return false;
} }
/** Counts how many acks are free
*
* \param urgent True if the type of the packet meant to
* use an ack is lower than PT_CANFAIL
* If for some reason you don't want use it
* for any packet type in particular,
* just set to false
* \return The number of free acks
*
*/
INT32 Net_GetFreeAcks(boolean urgent)
{
INT32 i, numfreeslot = 0;
INT32 n = 0; // Number of free acks found
for (i = 0; i < MAXACKPACKETS; i++)
if (!ackpak[i].acknum)
{
// For low priority packets, make sure to let freeslots so urgent packets can be sent
if (!urgent)
{
numfreeslot++;
if (numfreeslot <= URGENTFREESLOTNUM)
continue;
}
n++;
}
return n;
}
// Get a ack to send in the queue of this node // Get a ack to send in the queue of this node
static UINT8 GetAcktosend(INT32 node) static UINT8 GetAcktosend(INT32 node)
{ {
@ -298,7 +331,7 @@ static void RemoveAck(INT32 i)
DEBFILE(va("Remove ack %d\n",ackpak[i].acknum)); DEBFILE(va("Remove ack %d\n",ackpak[i].acknum));
#endif #endif
ackpak[i].acknum = 0; ackpak[i].acknum = 0;
if (nodes[node].flags & CLOSE) if (nodes[node].flags & NF_CLOSE)
Net_CloseConnection(node); Net_CloseConnection(node);
} }
@ -452,8 +485,13 @@ static void GotAcks(void)
} }
#endif #endif
static inline void Net_ConnectionTimeout(INT32 node) void Net_ConnectionTimeout(INT32 node)
{ {
// Don't timeout several times
if (nodes[node].flags & NF_TIMEOUT)
return;
nodes[node].flags |= NF_TIMEOUT;
// Send a very special packet to self (hack the reboundstore queue) // Send a very special packet to self (hack the reboundstore queue)
// Main code will handle it // Main code will handle it
reboundstore[rebound_head].packettype = PT_NODETIMEOUT; reboundstore[rebound_head].packettype = PT_NODETIMEOUT;
@ -484,7 +522,7 @@ void Net_AckTicker(void)
if (ackpak[i].acknum && ackpak[i].senttime + node->timeout < I_GetTime()) if (ackpak[i].acknum && ackpak[i].senttime + node->timeout < I_GetTime())
#endif #endif
{ {
if (ackpak[i].resentnum > 10 && (node->flags & CLOSE)) if (ackpak[i].resentnum > 10 && (node->flags & NF_CLOSE))
{ {
DEBFILE(va("ack %d sent 10 times so connection is supposed lost: node %d\n", DEBFILE(va("ack %d sent 10 times so connection is supposed lost: node %d\n",
i, nodei)); i, nodei));
@ -520,7 +558,7 @@ void Net_AckTicker(void)
if (nodes[i].lasttimeacktosend_sent + ACKTOSENDTIMEOUT < I_GetTime()) if (nodes[i].lasttimeacktosend_sent + ACKTOSENDTIMEOUT < I_GetTime())
Net_SendAcks(i); Net_SendAcks(i);
if (!(nodes[i].flags & CLOSE) if (!(nodes[i].flags & NF_CLOSE)
&& nodes[i].lasttimepacketreceived + connectiontimeout < I_GetTime()) && nodes[i].lasttimepacketreceived + connectiontimeout < I_GetTime())
{ {
Net_ConnectionTimeout(i); Net_ConnectionTimeout(i);
@ -678,7 +716,7 @@ void Net_CloseConnection(INT32 node)
if (!node) if (!node)
return; return;
nodes[node].flags |= CLOSE; nodes[node].flags |= NF_CLOSE;
// try to Send ack back (two army problem) // try to Send ack back (two army problem)
if (GetAcktosend(node)) if (GetAcktosend(node))
@ -813,18 +851,20 @@ static void DebugPrintpacket(const char *header)
case PT_SERVERTICS: case PT_SERVERTICS:
{ {
servertics_pak *serverpak = &netbuffer->u.serverpak; servertics_pak *serverpak = &netbuffer->u.serverpak;
ticcmd_t *cmd = &serverpak->cmds[serverpak->numslots * serverpak->numtics]; UINT8 *cmd = (UINT8 *)(&serverpak->cmds[serverpak->numslots * serverpak->numtics]);
size_t ntxtcmd = &((UINT8 *)netbuffer)[doomcom->datalength] - (UINT8 *)cmd; size_t ntxtcmd = &((UINT8 *)netbuffer)[doomcom->datalength] - cmd;
fprintf(debugfile, " firsttic %u ply %d tics %d ntxtcmd %s\n ", fprintf(debugfile, " firsttic %u ply %d tics %d ntxtcmd %s\n ",
(UINT32)ExpandTics(serverpak->starttic), serverpak->numslots, serverpak->numtics, sizeu1(ntxtcmd)); (UINT32)ExpandTics(serverpak->starttic), serverpak->numslots, serverpak->numtics, sizeu1(ntxtcmd));
fprintfstring((char *)cmd, 3); /// \todo Display more readable information about net commands
fprintfstringnewline((char *)cmd, ntxtcmd);
/*fprintfstring((char *)cmd, 3);
if (ntxtcmd > 4) if (ntxtcmd > 4)
{ {
fprintf(debugfile, "[%s]", netxcmdnames[*(((UINT8 *)cmd) + 3) - 1]); fprintf(debugfile, "[%s]", netxcmdnames[*((cmd) + 3) - 1]);
fprintfstring(((char *)cmd) + 4, ntxtcmd - 4); fprintfstring(((char *)cmd) + 4, ntxtcmd - 4);
} }
fprintf(debugfile, "\n"); fprintf(debugfile, "\n");*/
break; break;
} }
case PT_CLIENTCMD: case PT_CLIENTCMD:
@ -891,7 +931,7 @@ void Command_Drop(void)
if (COM_Argc() < 2) if (COM_Argc() < 2)
{ {
CONS_Printf("drop <packettype> [quantity]: drop packets\n" CONS_Printf("drop <packettype> [quantity]: drop packets\n"
"drop reset: cancel all packet drops"); "drop reset: cancel all packet drops\n");
return; return;
} }
@ -951,12 +991,14 @@ void Command_Droprate(void)
packetdroprate = droprate; packetdroprate = droprate;
} }
#ifndef NONET
static boolean ShouldDropPacket(void) static boolean ShouldDropPacket(void)
{ {
return (packetdropquantity[netbuffer->packettype]) return (packetdropquantity[netbuffer->packettype])
|| (packetdroprate != 0 && rand() < (RAND_MAX * (packetdroprate / 100.f))) || packetdroprate == 100; || (packetdroprate != 0 && rand() < (RAND_MAX * (packetdroprate / 100.f))) || packetdroprate == 100;
} }
#endif #endif
#endif
// //
// HSendPacket // HSendPacket
@ -1067,6 +1109,8 @@ boolean HSendPacket(INT32 node, boolean reliable, UINT8 acknum, size_t packetlen
// //
boolean HGetPacket(void) boolean HGetPacket(void)
{ {
//boolean nodejustjoined;
// Get a packet from self // Get a packet from self
if (rebound_tail != rebound_head) if (rebound_tail != rebound_head)
{ {
@ -1092,9 +1136,10 @@ boolean HGetPacket(void)
while(true) while(true)
{ {
//nodejustjoined = I_NetGet();
I_NetGet(); I_NetGet();
if (doomcom->remotenode == -1) if (doomcom->remotenode == -1) // No packet received
return false; return false;
getbytes += packetheaderlength + doomcom->datalength; // For stat getbytes += packetheaderlength + doomcom->datalength; // For stat
@ -1110,6 +1155,7 @@ boolean HGetPacket(void)
if (netbuffer->checksum != NetbufferChecksum()) if (netbuffer->checksum != NetbufferChecksum())
{ {
DEBFILE("Bad packet checksum\n"); DEBFILE("Bad packet checksum\n");
//Net_CloseConnection(nodejustjoined ? (doomcom->remotenode | FORCECLOSE) : doomcom->remotenode);
Net_CloseConnection(doomcom->remotenode); Net_CloseConnection(doomcom->remotenode);
continue; continue;
} }
@ -1119,11 +1165,26 @@ boolean HGetPacket(void)
DebugPrintpacket("GET"); DebugPrintpacket("GET");
#endif #endif
// proceed the ack and ackreturn field /*// If a new node sends an unexpected packet, just ignore it
if (nodejustjoined && server
&& !(netbuffer->packettype == PT_ASKINFO
|| netbuffer->packettype == PT_SERVERINFO
|| netbuffer->packettype == PT_PLAYERINFO
|| netbuffer->packettype == PT_REQUESTFILE
|| netbuffer->packettype == PT_ASKINFOVIAMS
|| netbuffer->packettype == PT_CLIENTJOIN))
{
DEBFILE(va("New node sent an unexpected %s packet\n", packettypename[netbuffer->packettype]));
//CONS_Alert(CONS_NOTICE, "New node sent an unexpected %s packet\n", packettypename[netbuffer->packettype]);
Net_CloseConnection(doomcom->remotenode | FORCECLOSE);
continue;
}*/
// Proceed the ack and ackreturn field
if (!Processackpak()) if (!Processackpak())
continue; // discarded (duplicated) continue; // discarded (duplicated)
// a packet with just ackreturn // A packet with just ackreturn
if (netbuffer->packettype == PT_NOTHING) if (netbuffer->packettype == PT_NOTHING)
{ {
GotAcks(); GotAcks();
@ -1136,9 +1197,10 @@ boolean HGetPacket(void)
return true; return true;
} }
static void Internal_Get(void) static boolean Internal_Get(void)
{ {
doomcom->remotenode = -1; doomcom->remotenode = -1;
return false;
} }
FUNCNORETURN static ATTRNORETURN void Internal_Send(void) FUNCNORETURN static ATTRNORETURN void Internal_Send(void)
@ -1223,7 +1285,7 @@ boolean D_CheckNetGame(void)
if (netgame) if (netgame)
ret = true; ret = true;
if (!server && netgame) if (client && netgame)
netgame = false; netgame = false;
server = true; // WTF? server always true??? server = true; // WTF? server always true???
// no! The deault mode is server. Client is set elsewhere // no! The deault mode is server. Client is set elsewhere

View File

@ -39,6 +39,7 @@ extern SINT8 nodetoplayer2[MAXNETNODES]; // Say the numplayer for this node if a
extern UINT8 playerpernode[MAXNETNODES]; // Used specially for splitscreen extern UINT8 playerpernode[MAXNETNODES]; // Used specially for splitscreen
extern boolean nodeingame[MAXNETNODES]; // Set false as nodes leave game extern boolean nodeingame[MAXNETNODES]; // Set false as nodes leave game
INT32 Net_GetFreeAcks(boolean urgent);
void Net_AckTicker(void); void Net_AckTicker(void);
// If reliable return true if packet sent, 0 else // If reliable return true if packet sent, 0 else
@ -53,6 +54,7 @@ boolean D_CheckNetGame(void);
void D_CloseConnection(void); void D_CloseConnection(void);
void Net_UnAcknowledgePacket(INT32 node); void Net_UnAcknowledgePacket(INT32 node);
void Net_CloseConnection(INT32 node); void Net_CloseConnection(INT32 node);
void Net_ConnectionTimeout(INT32 node);
void Net_AbortPacketType(UINT8 packettype); void Net_AbortPacketType(UINT8 packettype);
void Net_SendAcks(INT32 node); void Net_SendAcks(INT32 node);
void Net_WaitAllAckReceived(UINT32 timeout); void Net_WaitAllAckReceived(UINT32 timeout);

View File

@ -82,6 +82,7 @@ static void AutoBalance_OnChange(void);
static void TeamScramble_OnChange(void); static void TeamScramble_OnChange(void);
static void NetTimeout_OnChange(void); static void NetTimeout_OnChange(void);
static void JoinTimeout_OnChange(void);
static void Ringslinger_OnChange(void); static void Ringslinger_OnChange(void);
static void Gravity_OnChange(void); static void Gravity_OnChange(void);
@ -340,7 +341,9 @@ consvar_t cv_killingdead = {"killingdead", "Off", CV_NETVAR, CV_OnOff, NULL, 0,
consvar_t cv_netstat = {"netstat", "Off", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; // show bandwidth statistics consvar_t cv_netstat = {"netstat", "Off", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; // show bandwidth statistics
static CV_PossibleValue_t nettimeout_cons_t[] = {{TICRATE/7, "MIN"}, {60*TICRATE, "MAX"}, {0, NULL}}; static CV_PossibleValue_t nettimeout_cons_t[] = {{TICRATE/7, "MIN"}, {60*TICRATE, "MAX"}, {0, NULL}};
consvar_t cv_nettimeout = {"nettimeout", "525", CV_CALL|CV_SAVE, nettimeout_cons_t, NetTimeout_OnChange, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_nettimeout = {"nettimeout", "350", CV_CALL|CV_SAVE, nettimeout_cons_t, NetTimeout_OnChange, 0, NULL, NULL, 0, 0, NULL};
static CV_PossibleValue_t jointimeout_cons_t[] = {{5*TICRATE, "MIN"}, {60*TICRATE, "MAX"}, {0, NULL}};
consvar_t cv_jointimeout = {"jointimeout", "350", CV_CALL|CV_SAVE, jointimeout_cons_t, JoinTimeout_OnChange, 0, NULL, NULL, 0, 0, NULL};
#ifdef NEWPING #ifdef NEWPING
consvar_t cv_maxping = {"maxping", "0", CV_SAVE, CV_Unsigned, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_maxping = {"maxping", "0", CV_SAVE, CV_Unsigned, NULL, 0, NULL, NULL, 0, 0, NULL};
#endif #endif
@ -546,9 +549,12 @@ void D_RegisterServerCommands(void)
// d_clisrv // d_clisrv
CV_RegisterVar(&cv_maxplayers); CV_RegisterVar(&cv_maxplayers);
CV_RegisterVar(&cv_maxsend); CV_RegisterVar(&cv_maxsend);
CV_RegisterVar(&cv_noticedownload);
CV_RegisterVar(&cv_downloadspeed);
COM_AddCommand("ping", Command_Ping_f); COM_AddCommand("ping", Command_Ping_f);
CV_RegisterVar(&cv_nettimeout); CV_RegisterVar(&cv_nettimeout);
CV_RegisterVar(&cv_jointimeout);
CV_RegisterVar(&cv_skipmapcheck); CV_RegisterVar(&cv_skipmapcheck);
CV_RegisterVar(&cv_sleep); CV_RegisterVar(&cv_sleep);
@ -1005,7 +1011,7 @@ UINT8 CanChangeSkin(INT32 playernum)
return true; return true;
// Force skin in effect. // Force skin in effect.
if (!server && (cv_forceskin.value != -1) && !(adminplayer == playernum && serverplayer == -1)) if (client && (cv_forceskin.value != -1) && !(adminplayer == playernum && serverplayer == -1))
return false; return false;
// Can change skin in intermission and whatnot. // Can change skin in intermission and whatnot.
@ -1616,7 +1622,7 @@ static void Command_Map_f(void)
return; return;
} }
if (!server && !(adminplayer == consoleplayer)) if (client && !(adminplayer == consoleplayer))
{ {
CONS_Printf(M_GetText("Only the server or a remote admin can use this.\n")); CONS_Printf(M_GetText("Only the server or a remote admin can use this.\n"));
return; return;
@ -1943,7 +1949,7 @@ static void Got_Suicide(UINT8 **cp, INT32 playernum)
// You can't suicide someone else. Nice try, there. // You can't suicide someone else. Nice try, there.
if (suicideplayer != playernum || (!G_PlatformGametype())) if (suicideplayer != playernum || (!G_PlatformGametype()))
{ {
CONS_Alert(CONS_WARNING, M_GetText("Illegal suicide command recieved from %s\n"), player_names[playernum]); CONS_Alert(CONS_WARNING, M_GetText("Illegal suicide command received from %s\n"), player_names[playernum]);
if (server) if (server)
{ {
XBOXSTATIC UINT8 buf[2]; XBOXSTATIC UINT8 buf[2];
@ -2658,7 +2664,7 @@ static void Command_Changepassword_f(void)
// If we have no MD5 support then completely disable XD_LOGIN responses for security. // If we have no MD5 support then completely disable XD_LOGIN responses for security.
CONS_Alert(CONS_NOTICE, "Remote administration commands are not supported in this build.\n"); CONS_Alert(CONS_NOTICE, "Remote administration commands are not supported in this build.\n");
#else #else
if (!server) // cannot change remotely if (client) // cannot change remotely
{ {
CONS_Printf(M_GetText("Only the server can use this.\n")); CONS_Printf(M_GetText("Only the server can use this.\n"));
return; return;
@ -2717,7 +2723,7 @@ static void Got_Login(UINT8 **cp, INT32 playernum)
READMEM(*cp, sentmd5, 16); READMEM(*cp, sentmd5, 16);
if (!server) if (client)
return; return;
// Do the final pass to compare with the sent md5 // Do the final pass to compare with the sent md5
@ -2739,7 +2745,7 @@ static void Command_Verify_f(void)
char *temp; char *temp;
INT32 playernum; INT32 playernum;
if (!server) if (client)
{ {
CONS_Printf(M_GetText("Only the server can use this.\n")); CONS_Printf(M_GetText("Only the server can use this.\n"));
return; return;
@ -2823,7 +2829,7 @@ static void Command_MotD_f(void)
return; return;
} }
if ((netgame || multiplayer) && !server) if ((netgame || multiplayer) && client)
SendNetXCmd(XD_SETMOTD, mymotd, sizeof(motd)); SendNetXCmd(XD_SETMOTD, mymotd, sizeof(motd));
else else
{ {
@ -3080,7 +3086,7 @@ static void Got_RequestAddfilecmd(UINT8 **cp, INT32 playernum)
READMEM(*cp, md5sum, 16); READMEM(*cp, md5sum, 16);
// Only the server processes this message. // Only the server processes this message.
if (!server) if (client)
return; return;
// Disallow non-printing characters and semicolons. // Disallow non-printing characters and semicolons.
@ -3347,6 +3353,11 @@ static void NetTimeout_OnChange(void)
connectiontimeout = (tic_t)cv_nettimeout.value; connectiontimeout = (tic_t)cv_nettimeout.value;
} }
static void JoinTimeout_OnChange(void)
{
jointimeout = (tic_t)cv_jointimeout.value;
}
UINT32 timelimitintics = 0; UINT32 timelimitintics = 0;
/** Deals with a timelimit change by printing the change to the console. /** Deals with a timelimit change by printing the change to the console.
@ -3989,7 +4000,7 @@ static void Command_Archivetest_f(void)
} }
// assign mobjnum // assign mobjnum
i = 0; i = 1;
for (th = thinkercap.next; th != &thinkercap; th = th->next) for (th = thinkercap.next; th != &thinkercap; th = th->next)
if (th->function.acp1 == (actionf_p1)P_MobjThinker) if (th->function.acp1 == (actionf_p1)P_MobjThinker)
((mobj_t *)th)->mobjnum = i++; ((mobj_t *)th)->mobjnum = i++;
@ -4091,8 +4102,7 @@ static void Skin_OnChange(void)
if (!Playing()) if (!Playing())
return; // do whatever you want return; // do whatever you want
if (!(cv_debug || devparm) && !(multiplayer || netgame) // In single player. if (!(cv_debug || devparm) && !(multiplayer || netgame)) // In single player.
&& (gamestate == GS_LEVEL || gamestate == GS_INTERMISSION || gamestate == GS_CONTINUING))
{ {
CV_StealthSet(&cv_skin, skins[players[consoleplayer].skin].name); CV_StealthSet(&cv_skin, skins[players[consoleplayer].skin].name);
return; return;

View File

@ -97,7 +97,7 @@ char downloaddir[256] = "DOWNLOAD";
#ifdef CLIENT_LOADINGSCREEN #ifdef CLIENT_LOADINGSCREEN
// for cl loading screen // for cl loading screen
INT32 lastfilenum = 0; INT32 lastfilenum = -1;
#endif #endif
/** Fills a serverinfo packet with information about wad files loaded. /** Fills a serverinfo packet with information about wad files loaded.
@ -487,6 +487,9 @@ static void SV_SendFile(INT32 node, const char *filename, UINT8 fileid)
INT32 i; INT32 i;
char wadfilename[MAX_WADPATH]; char wadfilename[MAX_WADPATH];
if (cv_noticedownload.value)
CONS_Printf("Sending file \"%s\" to node %d\n", filename, node);
// Find the last file in the list and set a pointer to its "next" field // Find the last file in the list and set a pointer to its "next" field
q = &transfer[node].txlist; q = &transfer[node].txlist;
while (*q) while (*q)
@ -609,6 +612,8 @@ static void SV_EndFileSend(INT32 node)
switch (p->ram) switch (p->ram)
{ {
case SF_FILE: // It's a file, close it and free its filename 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) if (transfer[node].currentfile)
fclose(transfer[node].currentfile); fclose(transfer[node].currentfile);
free(p->id.filename); free(p->id.filename);
@ -636,6 +641,9 @@ static void SV_EndFileSend(INT32 node)
/** Handles file transmission /** Handles file transmission
* *
* \todo Use an acknowledging method more adapted to file transmission
* The current download speed suffers from lack of ack packets,
* especially when the one downloading has high latency
* *
*/ */
void SV_FileSendTicker(void) void SV_FileSendTicker(void)
@ -644,17 +652,38 @@ void SV_FileSendTicker(void)
filetx_pak *p; filetx_pak *p;
size_t size; size_t size;
filetx_t *f; filetx_t *f;
INT32 packetsent = PACKETPERTIC, ram, i; INT32 packetsent, ram, i, j;
INT32 maxpacketsent;
if (!filestosend) if (!filestosend) // No file to send
return; return;
if (!packetsent)
packetsent++; if (cv_downloadspeed.value) // New (and experimental) behavior
{
packetsent = cv_downloadspeed.value;
// Don't send more packets than we have free acks
#ifndef NONET
maxpacketsent = Net_GetFreeAcks(false) - 5; // Let 5 extra acks just in case
#else
maxpacketsent = 1;
#endif
if (packetsent > maxpacketsent && maxpacketsent > 0) // Send at least one packet
packetsent = maxpacketsent;
}
else // Old behavior
{
packetsent = PACKETPERTIC;
if (!packetsent)
packetsent = 1;
}
netbuffer->packettype = PT_FILEFRAGMENT;
// (((sendbytes-nowsentbyte)*TICRATE)/(I_GetTime()-starttime)<(UINT32)net_bandwidth) // (((sendbytes-nowsentbyte)*TICRATE)/(I_GetTime()-starttime)<(UINT32)net_bandwidth)
while (packetsent-- && filestosend != 0) while (packetsent-- && filestosend != 0)
{ {
for (i = currentnode, ram = 0; ram < MAXNETNODES; for (i = currentnode, j = 0; j < MAXNETNODES;
i = (i+1) % MAXNETNODES, ram++) i = (i+1) % MAXNETNODES, j++)
{ {
if (transfer[i].txlist) if (transfer[i].txlist)
goto found; goto found;
@ -713,7 +742,6 @@ void SV_FileSendTicker(void)
p->position |= LONG(0x80000000); p->position |= LONG(0x80000000);
p->fileid = f->fileid; p->fileid = f->fileid;
p->size = SHORT((UINT16)size); p->size = SHORT((UINT16)size);
netbuffer->packettype = PT_FILEFRAGMENT;
// Send the packet // Send the packet
if (HSendPacket(i, true, 0, FILETXHEADER + size)) // Reliable SEND if (HSendPacket(i, true, 0, FILETXHEADER + size)) // Reliable SEND
@ -735,27 +763,40 @@ void SV_FileSendTicker(void)
void Got_Filetxpak(void) void Got_Filetxpak(void)
{ {
INT32 filenum = netbuffer->u.filetxpak.fileid; INT32 filenum = netbuffer->u.filetxpak.fileid;
fileneeded_t *file = &fileneeded[filenum];
char *filename = file->filename;
static INT32 filetime = 0; static INT32 filetime = 0;
if (!(strcmp(filename, "srb2.srb")
&& strcmp(filename, "srb2.wad")
&& strcmp(filename, "zones.dta")
&& strcmp(filename, "player.dta")
&& strcmp(filename, "rings.dta")
&& strcmp(filename, "patch.dta")
&& strcmp(filename, "music.dta")
))
I_Error("Tried to download \"%s\"", filename);
if (filenum >= fileneedednum) if (filenum >= fileneedednum)
{ {
DEBFILE(va("fileframent not needed %d>%d\n", filenum, fileneedednum)); DEBFILE(va("fileframent not needed %d>%d\n", filenum, fileneedednum));
//I_Error("Received an unneeded file fragment (file id received: %d, file id needed: %d)\n", filenum, fileneedednum);
return; return;
} }
if (fileneeded[filenum].status == FS_REQUESTED) if (file->status == FS_REQUESTED)
{ {
if (fileneeded[filenum].file) if (file->file)
I_Error("Got_Filetxpak: already open file\n"); I_Error("Got_Filetxpak: already open file\n");
fileneeded[filenum].file = fopen(fileneeded[filenum].filename, "wb"); file->file = fopen(filename, "wb");
if (!fileneeded[filenum].file) if (!file->file)
I_Error("Can't create file %s: %s", fileneeded[filenum].filename, strerror(errno)); I_Error("Can't create file %s: %s", filename, strerror(errno));
CONS_Printf("\r%s...\n",fileneeded[filenum].filename); CONS_Printf("\r%s...\n",filename);
fileneeded[filenum].currentsize = 0; file->currentsize = 0;
fileneeded[filenum].status = FS_DOWNLOADING; file->status = FS_DOWNLOADING;
} }
if (fileneeded[filenum].status == FS_DOWNLOADING) if (file->status == FS_DOWNLOADING)
{ {
UINT32 pos = LONG(netbuffer->u.filetxpak.position); UINT32 pos = LONG(netbuffer->u.filetxpak.position);
UINT16 size = SHORT(netbuffer->u.filetxpak.size); UINT16 size = SHORT(netbuffer->u.filetxpak.size);
@ -764,27 +805,47 @@ void Got_Filetxpak(void)
if (pos & 0x80000000) if (pos & 0x80000000)
{ {
pos &= ~0x80000000; pos &= ~0x80000000;
fileneeded[filenum].totalsize = pos + size; file->totalsize = pos + size;
} }
// We can receive packet in the wrong order, anyway all os support gaped file // We can receive packet in the wrong order, anyway all os support gaped file
fseek(fileneeded[filenum].file, pos, SEEK_SET); fseek(file->file, pos, SEEK_SET);
if (fwrite(netbuffer->u.filetxpak.data,size,1,fileneeded[filenum].file) != 1) if (fwrite(netbuffer->u.filetxpak.data,size,1,file->file) != 1)
I_Error("Can't write to %s: %s\n",fileneeded[filenum].filename, strerror(ferror(fileneeded[filenum].file))); I_Error("Can't write to %s: %s\n",filename, strerror(ferror(file->file)));
fileneeded[filenum].currentsize += size; file->currentsize += size;
// Finished? // Finished?
if (fileneeded[filenum].currentsize == fileneeded[filenum].totalsize) if (file->currentsize == file->totalsize)
{ {
fclose(fileneeded[filenum].file); fclose(file->file);
fileneeded[filenum].file = NULL; file->file = NULL;
fileneeded[filenum].status = FS_FOUND; file->status = FS_FOUND;
CONS_Printf(M_GetText("Downloading %s...(done)\n"), CONS_Printf(M_GetText("Downloading %s...(done)\n"),
fileneeded[filenum].filename); filename);
} }
} }
else else
I_Error("Received a file not requested\n"); {
const char *s;
switch(file->status)
{
case FS_NOTFOUND:
s = "FS_NOTFOUND";
break;
case FS_FOUND:
s = "FS_FOUND";
break;
case FS_OPEN:
s = "FS_OPEN";
break;
case FS_MD5SUMBAD:
s = "FS_MD5SUMBAD";
break;
default:
s = "unknown";
break;
}
I_Error("Received a file not requested (file id: %d, file status: %s)\n", filenum, s);
}
// Send ack back quickly // Send ack back quickly
if (++filetime == 3) if (++filetime == 3)
{ {
@ -797,12 +858,23 @@ void Got_Filetxpak(void)
#endif #endif
} }
/** Cancels all file requests for a node /** \brief Checks if a node is downloading a file
* *
* \param node The destination * \param node The node to check for
* \sa SV_EndFileSend * \return True if the node is downloading a file
* *
*/ */
boolean SV_SendingFile(INT32 node)
{
return transfer[node].txlist != NULL;
}
/** Cancels all file requests for a node
*
* \param node The destination
* \sa SV_EndFileSend
*
*/
void SV_AbortSendFiles(INT32 node) void SV_AbortSendFiles(INT32 node)
{ {
while (transfer[node].txlist) while (transfer[node].txlist)

View File

@ -65,6 +65,7 @@ void SV_SendRam(INT32 node, void *data, size_t size, freemethod_t freemethod,
void SV_FileSendTicker(void); void SV_FileSendTicker(void);
void Got_Filetxpak(void); void Got_Filetxpak(void);
boolean SV_SendingFile(INT32 node);
boolean CL_CheckDownloadable(void); boolean CL_CheckDownloadable(void);
boolean CL_SendRequestFile(void); boolean CL_SendRequestFile(void);

View File

@ -150,9 +150,9 @@ extern FILE *logstream;
// we use comprevision and compbranch instead. // we use comprevision and compbranch instead.
#else #else
#define VERSION 201 // Game version #define VERSION 201 // Game version
#define SUBVERSION 16 // more precise version number #define SUBVERSION 17 // more precise version number
#define VERSIONSTRING "v2.1.16" #define VERSIONSTRING "v2.1.17"
#define VERSIONSTRINGW L"v2.1.16" #define VERSIONSTRINGW L"v2.1.17"
// Hey! If you change this, add 1 to the MODVERSION below! // Hey! If you change this, add 1 to the MODVERSION below!
// Otherwise we can't force updates! // Otherwise we can't force updates!
#endif #endif
@ -214,7 +214,7 @@ extern FILE *logstream;
// it's only for detection of the version the player is using so the MS can alert them of an update. // 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. // 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". // Note that we use this to help keep internal testing in check; this is why v2.1.0 is not version "1".
#define MODVERSION 21 #define MODVERSION 22
// ========================================================================= // =========================================================================

View File

@ -974,7 +974,7 @@ static const char *credits[] = {
"Scott \"Graue\" Feeney", "Scott \"Graue\" Feeney",
"Nathan \"Jazz\" Giroux", "Nathan \"Jazz\" Giroux",
"Thomas \"Shadow Hog\" Igoe", "Thomas \"Shadow Hog\" Igoe",
"\"Monster\" Iestyn Jealous", "Iestyn \"Monster Iestyn\" Jealous",
"Ronald \"Furyhunter\" Kinard", // The SDL2 port "Ronald \"Furyhunter\" Kinard", // The SDL2 port
"John \"JTE\" Muniz", "John \"JTE\" Muniz",
"Ehab \"Wolfy\" Saeed", "Ehab \"Wolfy\" Saeed",
@ -986,6 +986,7 @@ static const char *credits[] = {
"\"chi.miru\"", // Red's secret weapon, the REAL reason slopes exist (also helped port drawing code from ZDoom) "\"chi.miru\"", // Red's secret weapon, the REAL reason slopes exist (also helped port drawing code from ZDoom)
"Andrew \"orospakr\" Clunis", "Andrew \"orospakr\" Clunis",
"Gregor \"Oogaland\" Dick", "Gregor \"Oogaland\" Dick",
"Louis-Antoine \"LJSonic\" de Moulins", // for fixing 2.1's netcode (de Rochefort doesn't quite fit on the screen sorry lol)
"Vivian \"toaster\" Grannell", "Vivian \"toaster\" Grannell",
"Julio \"Chaos Zero 64\" Guir", "Julio \"Chaos Zero 64\" Guir",
"\"Kalaron\"", // Coded some of Sryder13's collection of OpenGL fixes, especially fog "\"Kalaron\"", // Coded some of Sryder13's collection of OpenGL fixes, especially fog
@ -1020,7 +1021,7 @@ static const char *credits[] = {
"Paul \"Boinciel\" Clempson", "Paul \"Boinciel\" Clempson",
"Cyan Helkaraxe", "Cyan Helkaraxe",
"Kepa \"Nev3r\" Iceta", "Kepa \"Nev3r\" Iceta",
"\"Monster\" Iestyn Jealous", "Iestyn \"Monster Iestyn\" Jealous",
"Jarel \"Arrow\" Jones", "Jarel \"Arrow\" Jones",
"Stefan \"Stuf\" Rimalia", "Stefan \"Stuf\" Rimalia",
"Shane Mychal Sexton", "Shane Mychal Sexton",

View File

@ -45,7 +45,7 @@
#include "hw_md2.h" #include "hw_md2.h"
#define R_FAKEFLOORS #define R_FAKEFLOORS
//#define HWPRECIP #define HWPRECIP
#define SORTING #define SORTING
//#define POLYSKY //#define POLYSKY
@ -1558,6 +1558,7 @@ static void HWR_StoreWallRange(double startfrac, double endfrac)
if (gr_backsector) if (gr_backsector)
{ {
INT32 gr_toptexture, gr_bottomtexture;
// two sided line // two sided line
if (gr_backsector->heightsec != -1) if (gr_backsector->heightsec != -1)
{ {
@ -1608,19 +1609,22 @@ static void HWR_StoreWallRange(double startfrac, double endfrac)
#endif #endif
} }
gr_toptexture = R_GetTextureNum(gr_sidedef->toptexture);
gr_bottomtexture = R_GetTextureNum(gr_sidedef->bottomtexture);
// check TOP TEXTURE // check TOP TEXTURE
if (( if ((
#ifdef ESLOPE #ifdef ESLOPE
worldhighslope < worldtopslope || worldhighslope < worldtopslope ||
#endif #endif
worldhigh < worldtop worldhigh < worldtop
) && texturetranslation[gr_sidedef->toptexture]) ) && gr_toptexture)
{ {
if (drawtextured) if (drawtextured)
{ {
fixed_t texturevpegtop; // top fixed_t texturevpegtop; // top
grTex = HWR_GetTexture(texturetranslation[gr_sidedef->toptexture]); grTex = HWR_GetTexture(gr_toptexture);
// PEGGING // PEGGING
if (gr_linedef->flags & ML_DONTPEGTOP) if (gr_linedef->flags & ML_DONTPEGTOP)
@ -1638,7 +1642,7 @@ static void HWR_StoreWallRange(double startfrac, double endfrac)
texturevpegtop += gr_sidedef->rowoffset; texturevpegtop += gr_sidedef->rowoffset;
// This is so that it doesn't overflow and screw up the wall, it doesn't need to go higher than the texture's height anyway // This is so that it doesn't overflow and screw up the wall, it doesn't need to go higher than the texture's height anyway
texturevpegtop %= SHORT(textures[texturetranslation[gr_sidedef->toptexture]]->height)<<FRACBITS; texturevpegtop %= SHORT(textures[gr_toptexture]->height)<<FRACBITS;
wallVerts[3].t = wallVerts[2].t = texturevpegtop * grTex->scaleY; wallVerts[3].t = wallVerts[2].t = texturevpegtop * grTex->scaleY;
wallVerts[0].t = wallVerts[1].t = (texturevpegtop + gr_frontsector->ceilingheight - gr_backsector->ceilingheight) * grTex->scaleY; wallVerts[0].t = wallVerts[1].t = (texturevpegtop + gr_frontsector->ceilingheight - gr_backsector->ceilingheight) * grTex->scaleY;
@ -1683,9 +1687,9 @@ static void HWR_StoreWallRange(double startfrac, double endfrac)
#endif #endif
if (gr_frontsector->numlights) if (gr_frontsector->numlights)
HWR_SplitWall(gr_frontsector, wallVerts, texturetranslation[gr_sidedef->toptexture], &Surf, FF_CUTSOLIDS); HWR_SplitWall(gr_frontsector, wallVerts, gr_toptexture, &Surf, FF_CUTSOLIDS);
else if (grTex->mipmap.flags & TF_TRANSPARENT) else if (grTex->mipmap.flags & TF_TRANSPARENT)
HWR_AddTransparentWall(wallVerts, &Surf, texturetranslation[gr_sidedef->toptexture], PF_Environment, false, lightnum, colormap); HWR_AddTransparentWall(wallVerts, &Surf, gr_toptexture, PF_Environment, false, lightnum, colormap);
else else
HWR_ProjectWall(wallVerts, &Surf, PF_Masked, lightnum, colormap); HWR_ProjectWall(wallVerts, &Surf, PF_Masked, lightnum, colormap);
} }
@ -1695,13 +1699,13 @@ static void HWR_StoreWallRange(double startfrac, double endfrac)
#ifdef ESLOPE #ifdef ESLOPE
worldlowslope > worldbottomslope || worldlowslope > worldbottomslope ||
#endif #endif
worldlow > worldbottom) && texturetranslation[gr_sidedef->bottomtexture]) //only if VISIBLE!!! worldlow > worldbottom) && gr_bottomtexture) //only if VISIBLE!!!
{ {
if (drawtextured) if (drawtextured)
{ {
fixed_t texturevpegbottom = 0; // bottom fixed_t texturevpegbottom = 0; // bottom
grTex = HWR_GetTexture(texturetranslation[gr_sidedef->bottomtexture]); grTex = HWR_GetTexture(gr_bottomtexture);
// PEGGING // PEGGING
#ifdef ESLOPE #ifdef ESLOPE
@ -1721,7 +1725,7 @@ static void HWR_StoreWallRange(double startfrac, double endfrac)
texturevpegbottom += gr_sidedef->rowoffset; texturevpegbottom += gr_sidedef->rowoffset;
// This is so that it doesn't overflow and screw up the wall, it doesn't need to go higher than the texture's height anyway // This is so that it doesn't overflow and screw up the wall, it doesn't need to go higher than the texture's height anyway
texturevpegbottom %= SHORT(textures[texturetranslation[gr_sidedef->bottomtexture]]->height)<<FRACBITS; texturevpegbottom %= SHORT(textures[gr_bottomtexture]->height)<<FRACBITS;
wallVerts[3].t = wallVerts[2].t = texturevpegbottom * grTex->scaleY; wallVerts[3].t = wallVerts[2].t = texturevpegbottom * grTex->scaleY;
wallVerts[0].t = wallVerts[1].t = (texturevpegbottom + gr_backsector->floorheight - gr_frontsector->floorheight) * grTex->scaleY; wallVerts[0].t = wallVerts[1].t = (texturevpegbottom + gr_backsector->floorheight - gr_frontsector->floorheight) * grTex->scaleY;
@ -1766,13 +1770,13 @@ static void HWR_StoreWallRange(double startfrac, double endfrac)
#endif #endif
if (gr_frontsector->numlights) if (gr_frontsector->numlights)
HWR_SplitWall(gr_frontsector, wallVerts, texturetranslation[gr_sidedef->bottomtexture], &Surf, FF_CUTSOLIDS); HWR_SplitWall(gr_frontsector, wallVerts, gr_bottomtexture, &Surf, FF_CUTSOLIDS);
else if (grTex->mipmap.flags & TF_TRANSPARENT) else if (grTex->mipmap.flags & TF_TRANSPARENT)
HWR_AddTransparentWall(wallVerts, &Surf, texturetranslation[gr_sidedef->bottomtexture], PF_Environment, false, lightnum, colormap); HWR_AddTransparentWall(wallVerts, &Surf, gr_bottomtexture, PF_Environment, false, lightnum, colormap);
else else
HWR_ProjectWall(wallVerts, &Surf, PF_Masked, lightnum, colormap); HWR_ProjectWall(wallVerts, &Surf, PF_Masked, lightnum, colormap);
} }
gr_midtexture = texturetranslation[gr_sidedef->midtexture]; gr_midtexture = R_GetTextureNum(gr_sidedef->midtexture);
if (gr_midtexture) if (gr_midtexture)
{ {
FBITFIELD blendmode; FBITFIELD blendmode;
@ -2134,7 +2138,7 @@ static void HWR_StoreWallRange(double startfrac, double endfrac)
else else
{ {
// Single sided line... Deal only with the middletexture (if one exists) // Single sided line... Deal only with the middletexture (if one exists)
gr_midtexture = texturetranslation[gr_sidedef->midtexture]; gr_midtexture = R_GetTextureNum(gr_sidedef->midtexture);
if (gr_midtexture) if (gr_midtexture)
{ {
if (drawtextured) if (drawtextured)
@ -2232,13 +2236,13 @@ static void HWR_StoreWallRange(double startfrac, double endfrac)
if (*rover->topheight < lowcut || *rover->bottomheight > highcut) if (*rover->topheight < lowcut || *rover->bottomheight > highcut)
continue; continue;
texnum = texturetranslation[sides[rover->master->sidenum[0]].midtexture]; texnum = R_GetTextureNum(sides[rover->master->sidenum[0]].midtexture);
if (rover->master->flags & ML_TFERLINE) if (rover->master->flags & ML_TFERLINE)
{ {
size_t linenum = gr_curline->linedef-gr_backsector->lines[0]; size_t linenum = gr_curline->linedef-gr_backsector->lines[0];
newline = rover->master->frontsector->lines[0] + linenum; newline = rover->master->frontsector->lines[0] + linenum;
texnum = texturetranslation[sides[newline->sidenum[0]].midtexture]; texnum = R_GetTextureNum(sides[newline->sidenum[0]].midtexture);
} }
#ifdef ESLOPE #ifdef ESLOPE
@ -2366,13 +2370,13 @@ static void HWR_StoreWallRange(double startfrac, double endfrac)
if (*rover->topheight < lowcut || *rover->bottomheight > highcut) if (*rover->topheight < lowcut || *rover->bottomheight > highcut)
continue; continue;
texnum = texturetranslation[sides[rover->master->sidenum[0]].midtexture]; texnum = R_GetTextureNum(sides[rover->master->sidenum[0]].midtexture);
if (rover->master->flags & ML_TFERLINE) if (rover->master->flags & ML_TFERLINE)
{ {
size_t linenum = gr_curline->linedef-gr_backsector->lines[0]; size_t linenum = gr_curline->linedef-gr_backsector->lines[0];
newline = rover->master->frontsector->lines[0] + linenum; newline = rover->master->frontsector->lines[0] + linenum;
texnum = texturetranslation[sides[newline->sidenum[0]].midtexture]; texnum = R_GetTextureNum(sides[newline->sidenum[0]].midtexture);
} }
#ifdef ESLOPE //backsides #ifdef ESLOPE //backsides
h = *rover->t_slope ? P_GetZAt(*rover->t_slope, v1x, v1y) : *rover->topheight; h = *rover->t_slope ? P_GetZAt(*rover->t_slope, v1x, v1y) : *rover->topheight;
@ -4401,7 +4405,6 @@ static inline void HWR_DrawPrecipitationSprite(gr_vissprite_t *spr)
FOutVector *wv; FOutVector *wv;
GLPatch_t *gpatch; // sprite patch converted to hardware GLPatch_t *gpatch; // sprite patch converted to hardware
FSurfaceInfo Surf; FSurfaceInfo Surf;
sector_t *sector;
if (!spr->mobj) if (!spr->mobj)
return; return;
@ -4455,19 +4458,38 @@ static inline void HWR_DrawPrecipitationSprite(gr_vissprite_t *spr)
//Hurdler: 25/04/2000: now support colormap in hardware mode //Hurdler: 25/04/2000: now support colormap in hardware mode
HWR_GetMappedPatch(gpatch, spr->colormap); HWR_GetMappedPatch(gpatch, spr->colormap);
sector = spr->mobj->subsector->sector; // colormap test
if (sector->ffloors)
{ {
ffloor_t *caster = sector->lightlist[R_GetPlaneLight(sector, spr->mobj->z, false)].caster; sector_t *sector = spr->mobj->subsector->sector;
sector = caster ? &sectors[caster->secnum] : sector; UINT8 lightlevel = 255;
} extracolormap_t *colormap = sector->extra_colormap;
// sprite lighting by modulating the RGB components if (sector->numlights)
if (sector->extra_colormap) {
Surf.FlatColor.rgba = HWR_Lighting(spr->sectorlight,sector->extra_colormap->rgba,sector->extra_colormap->fadergba, false, false); INT32 light;
light = R_GetPlaneLight(sector, spr->mobj->z + spr->mobj->height, false); // Always use the light at the top instead of whatever I was doing before
if (!(spr->mobj->frame & FF_FULLBRIGHT))
lightlevel = *sector->lightlist[light].lightlevel;
if (sector->lightlist[light].extra_colormap)
colormap = sector->lightlist[light].extra_colormap;
}
else else
Surf.FlatColor.rgba = HWR_Lighting(spr->sectorlight,NORMALFOG,FADEFOG, false, false); {
if (!(spr->mobj->frame & FF_FULLBRIGHT))
lightlevel = sector->lightlevel;
if (sector->extra_colormap)
colormap = sector->extra_colormap;
}
if (colormap)
Surf.FlatColor.rgba = HWR_Lighting(lightlevel, colormap->rgba, colormap->fadergba, false, false);
else
Surf.FlatColor.rgba = HWR_Lighting(lightlevel, NORMALFOG, FADEFOG, false, false);
}
if (spr->mobj->flags2 & MF2_SHADOW) if (spr->mobj->flags2 & MF2_SHADOW)
{ {
@ -4501,8 +4523,8 @@ static void HWR_SortVisSprites(void)
gr_vissprite_t *ds, *dsprev, *dsnext, *dsfirst; gr_vissprite_t *ds, *dsprev, *dsnext, *dsfirst;
gr_vissprite_t *best = NULL; gr_vissprite_t *best = NULL;
gr_vissprite_t unsorted; gr_vissprite_t unsorted;
float bestdist; float bestdist = 0.0f;
INT32 bestdispoffset; INT32 bestdispoffset = 0;
if (!gr_visspritecount) if (!gr_visspritecount)
return; return;
@ -5289,6 +5311,11 @@ static void HWR_ProjectPrecipitationSprite(precipmobj_t *thing)
// //
vis = HWR_NewVisSprite(); vis = HWR_NewVisSprite();
vis->x1 = x1; vis->x1 = x1;
#if 0
vis->x2 = x2;
#else
(void)x2;
#endif
vis->x2 = tx; vis->x2 = tx;
vis->tz = tz; vis->tz = tz;
vis->dispoffset = 0; // Monster Iestyn: 23/11/15: HARDWARE SUPPORT AT LAST vis->dispoffset = 0; // Monster Iestyn: 23/11/15: HARDWARE SUPPORT AT LAST
@ -5301,7 +5328,6 @@ static void HWR_ProjectPrecipitationSprite(precipmobj_t *thing)
// set top/bottom coords // set top/bottom coords
vis->ty = FIXED_TO_FLOAT(thing->z + spritecachedinfo[lumpoff].topoffset) - gr_viewz; vis->ty = FIXED_TO_FLOAT(thing->z + spritecachedinfo[lumpoff].topoffset) - gr_viewz;
vis->sectorlight = 0xff;
vis->precip = true; vis->precip = true;
} }
#endif #endif

View File

@ -1836,7 +1836,7 @@ EXPORT void HWRAPI(SetSpecialState) (hwdspecialstate_t IdState, INT32 Value)
} }
} }
static inline void DrawMD2Ex(INT32 *gl_cmd_buffer, md2_frame_t *frame, UINT32 duration, UINT32 tics, md2_frame_t *nextframe, FTransform *pos, float scale, UINT8 flipped, UINT8 *color) static void DrawMD2Ex(INT32 *gl_cmd_buffer, md2_frame_t *frame, UINT32 duration, UINT32 tics, md2_frame_t *nextframe, FTransform *pos, float scale, UINT8 flipped, UINT8 *color)
{ {
INT32 val, count, pindex; INT32 val, count, pindex;
GLfloat s, t; GLfloat s, t;

View File

@ -470,7 +470,7 @@ static void Got_Saycmd(UINT8 **p, INT32 playernum)
boolean action = false; boolean action = false;
char *ptr; char *ptr;
CONS_Debug(DBG_NETPLAY,"Recieved SAY cmd from Player %d (%s)\n", playernum+1, player_names[playernum]); CONS_Debug(DBG_NETPLAY,"Received SAY cmd from Player %d (%s)\n", playernum+1, player_names[playernum]);
target = READSINT8(*p); target = READSINT8(*p);
flags = READUINT8(*p); flags = READUINT8(*p);
@ -1102,7 +1102,19 @@ void HU_Drawer(void)
// draw desynch text // draw desynch text
if (hu_resynching) if (hu_resynching)
V_DrawCenteredString(BASEVIDWIDTH/2, 180, V_YELLOWMAP, "Resynching..."); {
static UINT32 resynch_ticker = 0;
char resynch_text[14];
UINT32 i;
// Animate the dots
resynch_ticker++;
strcpy(resynch_text, "Resynching");
for (i = 0; i < (resynch_ticker / 16) % 4; i++)
strcat(resynch_text, ".");
V_DrawCenteredString(BASEVIDWIDTH/2, 180, V_YELLOWMAP | V_ALLOWLOWERCASE, resynch_text);
}
} }
//====================================================================== //======================================================================

View File

@ -85,7 +85,7 @@ extern doomcom_t *doomcom;
/** \brief return packet in doomcom struct /** \brief return packet in doomcom struct
*/ */
extern void (*I_NetGet)(void); extern boolean (*I_NetGet)(void);
/** \brief ask to driver if there is data waiting /** \brief ask to driver if there is data waiting
*/ */

View File

@ -179,6 +179,7 @@ static UINT8 UPNP_support = TRUE;
#include "i_system.h" #include "i_system.h"
#include "i_net.h" #include "i_net.h"
#include "d_net.h" #include "d_net.h"
#include "d_netfil.h"
#include "i_tcp.h" #include "i_tcp.h"
#include "m_argv.h" #include "m_argv.h"
@ -482,21 +483,12 @@ static boolean SOCK_cmpaddr(mysockaddr_t *a, mysockaddr_t *b, UINT8 mask)
return false; return false;
} }
static SINT8 getfreenode(void)
{
SINT8 j;
for (j = 0; j < MAXNETNODES; j++)
if (!nodeconnected[j])
{
nodeconnected[j] = true;
return j;
}
return -1;
}
// This is a hack. For some reason, nodes aren't being freed properly. // This is a hack. For some reason, nodes aren't being freed properly.
// This goes through and cleans up what nodes were supposed to be freed. // This goes through and cleans up what nodes were supposed to be freed.
/** \warning This function causes the file downloading to stop if someone joins.
* How? Because it removes nodes that are connected but not in game,
* which is exactly what clients downloading a file are.
*/
static void cleanupnodes(void) static void cleanupnodes(void)
{ {
SINT8 j; SINT8 j;
@ -506,13 +498,81 @@ static void cleanupnodes(void)
// Why can't I start at zero? // Why can't I start at zero?
for (j = 1; j < MAXNETNODES; j++) for (j = 1; j < MAXNETNODES; j++)
//if (!(nodeingame[j] || SV_SendingFile(j)))
if (!nodeingame[j]) if (!nodeingame[j])
nodeconnected[j] = false; nodeconnected[j] = false;
} }
static SINT8 getfreenode(void)
{
SINT8 j;
cleanupnodes();
for (j = 0; j < MAXNETNODES; j++)
if (!nodeconnected[j])
{
nodeconnected[j] = true;
return j;
}
/** \warning No free node? Just in case a node might not have been freed properly,
* look if there are connected nodes that aren't in game, and forget them.
* It's dirty, and might result in a poor guy having to restart
* downloading a needed wad, but it's better than not letting anyone join...
*/
/*I_Error("No more free nodes!!1!11!11!!1111\n");
for (j = 1; j < MAXNETNODES; j++)
if (!nodeingame[j])
return j;*/
return -1;
}
#ifdef _DEBUG
void Command_Numnodes(void)
{
INT32 connected = 0;
INT32 ingame = 0;
INT32 i;
for (i = 1; i < MAXNETNODES; i++)
{
if (!(nodeconnected[i] || nodeingame[i]))
continue;
if (nodeconnected[i])
connected++;
if (nodeingame[i])
ingame++;
CONS_Printf("%2d - ", i);
if (nodetoplayer[i] != -1)
CONS_Printf("player %.2d", nodetoplayer[i]);
else
CONS_Printf(" ");
if (nodeconnected[i])
CONS_Printf(" - connected");
else
CONS_Printf(" - ");
if (nodeingame[i])
CONS_Printf(" - ingame");
else
CONS_Printf(" - ");
CONS_Printf(" - %s\n", I_GetNodeAddress(i));
}
CONS_Printf("\n"
"Connected: %d\n"
"Ingame: %d\n",
connected, ingame);
}
#endif
#endif #endif
#ifndef NONET #ifndef NONET
static void SOCK_Get(void) // Returns true if a packet was received from a new node, false in all other cases
static boolean SOCK_Get(void)
{ {
size_t i, n; size_t i, n;
int j; int j;
@ -535,13 +595,12 @@ static void SOCK_Get(void)
doomcom->remotenode = (INT16)j; // good packet from a game player doomcom->remotenode = (INT16)j; // good packet from a game player
doomcom->datalength = (INT16)c; doomcom->datalength = (INT16)c;
nodesocket[j] = mysockets[n]; nodesocket[j] = mysockets[n];
return; return false;
} }
} }
// not found // not found
// find a free slot // find a free slot
cleanupnodes();
j = getfreenode(); j = getfreenode();
if (j > 0) if (j > 0)
{ {
@ -564,14 +623,15 @@ static void SOCK_Get(void)
} }
if (i == numbans) if (i == numbans)
SOCK_bannednode[j] = false; SOCK_bannednode[j] = false;
return; return true;
} }
else else
DEBFILE("New node detected: No more free slots\n"); DEBFILE("New node detected: No more free slots\n");
} }
} }
doomcom->remotenode = -1; // no packet doomcom->remotenode = -1; // no packet
return false;
} }
#endif #endif
@ -1256,7 +1316,6 @@ static SINT8 SOCK_NetMakeNodewPort(const char *address, const char *port)
gaie = I_getaddrinfo(address, port, &hints, &ai); gaie = I_getaddrinfo(address, port, &hints, &ai);
if (gaie == 0) if (gaie == 0)
{ {
cleanupnodes();
newnode = getfreenode(); newnode = getfreenode();
} }
if (newnode == -1) if (newnode == -1)

View File

@ -369,6 +369,8 @@ static int libd_drawScaled(lua_State *L)
x = luaL_checkinteger(L, 1); x = luaL_checkinteger(L, 1);
y = luaL_checkinteger(L, 2); y = luaL_checkinteger(L, 2);
scale = luaL_checkinteger(L, 3); scale = luaL_checkinteger(L, 3);
if (scale < 0)
return luaL_error(L, "negative scale");
patch = *((patch_t **)luaL_checkudata(L, 4, META_PATCH)); patch = *((patch_t **)luaL_checkudata(L, 4, META_PATCH));
flags = luaL_optinteger(L, 5, 0); flags = luaL_optinteger(L, 5, 0);
if (!lua_isnoneornil(L, 6)) if (!lua_isnoneornil(L, 6))

View File

@ -348,22 +348,12 @@ static int sector_get(lua_State *L)
case sector_ceilingheight: case sector_ceilingheight:
lua_pushfixed(L, sector->ceilingheight); lua_pushfixed(L, sector->ceilingheight);
return 1; return 1;
case sector_floorpic: { // floorpic case sector_floorpic: // floorpic
levelflat_t *levelflat; lua_pushlstring(L, levelflats[sector->floorpic].name, 8);
INT16 i;
for (i = 0, levelflat = levelflats; i != sector->floorpic; i++, levelflat++)
;
lua_pushlstring(L, levelflat->name, 8);
return 1; return 1;
} case sector_ceilingpic: // ceilingpic
case sector_ceilingpic: { // ceilingpic lua_pushlstring(L, levelflats[sector->ceilingpic].name, 8);
levelflat_t *levelflat;
INT16 i;
for (i = 0, levelflat = levelflats; i != sector->ceilingpic; i++, levelflat++)
;
lua_pushlstring(L, levelflat->name, 8);
return 1; return 1;
}
case sector_lightlevel: case sector_lightlevel:
lua_pushinteger(L, sector->lightlevel); lua_pushinteger(L, sector->lightlevel);
return 1; return 1;
@ -400,46 +390,6 @@ static int sector_get(lua_State *L)
return 0; return 0;
} }
// help function for P_LoadSectors, find a flat in the active wad files,
// allocate an id for it, and set the levelflat (to speedup search)
//
static INT32 P_AddLevelFlatRuntime(const char *flatname)
{
size_t i;
levelflat_t *levelflat = levelflats;
//
// first scan through the already found flats
//
for (i = 0; i < numlevelflats; i++, levelflat++)
if (strnicmp(levelflat->name,flatname,8)==0)
break;
// that flat was already found in the level, return the id
if (i == numlevelflats)
{
// allocate new flat memory
levelflats = Z_Realloc(levelflats, (numlevelflats + 1) * sizeof(*levelflats), PU_LEVEL, NULL);
levelflat = levelflats+i;
// store the name
strlcpy(levelflat->name, flatname, sizeof (levelflat->name));
strupr(levelflat->name);
// store the flat lump number
levelflat->lumpnum = R_GetFlatNumForName(flatname);
#ifndef ZDEBUG
CONS_Debug(DBG_SETUP, "flat #%03d: %s\n", atoi(sizeu1(numlevelflats)), levelflat->name);
#endif
numlevelflats++;
}
// level flat id
return (INT32)i;
}
static int sector_set(lua_State *L) static int sector_set(lua_State *L)
{ {
sector_t *sector = *((sector_t **)luaL_checkudata(L, 1, META_SECTOR)); sector_t *sector = *((sector_t **)luaL_checkudata(L, 1, META_SECTOR));

View File

@ -28,4 +28,4 @@ void M_AATreeSet(aatree_t *aatree, INT32 key, void* value);
void *M_AATreeGet(aatree_t *aatree, INT32 key); void *M_AATreeGet(aatree_t *aatree, INT32 key);
void M_AATreeIterate(aatree_t *aatree, aatree_iter_t callback); void M_AATreeIterate(aatree_t *aatree, aatree_iter_t callback);
#endif #endif

View File

@ -452,7 +452,7 @@ void Command_RTeleport_f(void)
else else
inty = 0; inty = 0;
ss = R_PointInSubsector(p->mo->x + intx*FRACUNIT, p->mo->y + inty*FRACUNIT); ss = R_IsPointInSubsector(p->mo->x + intx*FRACUNIT, p->mo->y + inty*FRACUNIT);
if (!ss || ss->sector->ceilingheight - ss->sector->floorheight < p->mo->height) if (!ss || ss->sector->ceilingheight - ss->sector->floorheight < p->mo->height)
{ {
CONS_Alert(CONS_NOTICE, M_GetText("Not a valid location.\n")); CONS_Alert(CONS_NOTICE, M_GetText("Not a valid location.\n"));

View File

@ -248,9 +248,16 @@ FUNCMATH FUNCINLINE static ATTRINLINE fixed_t FixedFloor(fixed_t x)
{ {
const fixed_t a = abs(x); //absolute of x const fixed_t a = abs(x); //absolute of x
const fixed_t i = (a>>FRACBITS)<<FRACBITS; // cut out the fractional part const fixed_t i = (a>>FRACBITS)<<FRACBITS; // cut out the fractional part
const fixed_t f = i-a; // cut out the integral part const fixed_t f = a-i; // cut out the integral part
if (f == 0)
return x;
if (x != INT32_MIN) if (x != INT32_MIN)
return x-f; // return largest integral value not greater than argument { // return rounded down to nearest whole number
if (x > 0)
return x-f;
else
return x-(FRACUNIT-f);
}
return INT32_MIN; return INT32_MIN;
} }
@ -266,7 +273,7 @@ FUNCMATH FUNCINLINE static ATTRINLINE fixed_t FixedTrunc(fixed_t x)
{ {
const fixed_t a = abs(x); //absolute of x const fixed_t a = abs(x); //absolute of x
const fixed_t i = (a>>FRACBITS)<<FRACBITS; // cut out the fractional part const fixed_t i = (a>>FRACBITS)<<FRACBITS; // cut out the fractional part
const fixed_t f = i-a; // cut out the integral part const fixed_t f = a-i; // cut out the integral part
if (x != INT32_MIN) if (x != INT32_MIN)
{ // return rounded to nearest whole number, towards zero { // return rounded to nearest whole number, towards zero
if (x > 0) if (x > 0)
@ -289,11 +296,18 @@ FUNCMATH FUNCINLINE static ATTRINLINE fixed_t FixedCeil(fixed_t x)
{ {
const fixed_t a = abs(x); //absolute of x const fixed_t a = abs(x); //absolute of x
const fixed_t i = (a>>FRACBITS)<<FRACBITS; // cut out the fractional part const fixed_t i = (a>>FRACBITS)<<FRACBITS; // cut out the fractional part
const fixed_t f = i-a; // cut out the integral part const fixed_t f = a-i; // cut out the integral part
if (f == 0)
return x;
if (x == INT32_MIN) if (x == INT32_MIN)
return INT32_MIN; return INT32_MIN;
else if (x < FixedFloor(INT32_MAX)) else if (x < FixedFloor(INT32_MAX))
return x+(FRACUNIT-f); // return smallest integral value not less than argument { // return rounded up to nearest whole number
if (x > 0)
return x+(FRACUNIT-f);
else
return x+f;
}
return INT32_MAX; return INT32_MAX;
} }
@ -309,7 +323,9 @@ FUNCMATH FUNCINLINE static ATTRINLINE fixed_t FixedRound(fixed_t x)
{ {
const fixed_t a = abs(x); //absolute of x const fixed_t a = abs(x); //absolute of x
const fixed_t i = (a>>FRACBITS)<<FRACBITS; // cut out the fractional part const fixed_t i = (a>>FRACBITS)<<FRACBITS; // cut out the fractional part
const fixed_t f = i-a; // cut out the integral part const fixed_t f = a-i; // cut out the integral part
if (f == 0)
return x;
if (x == INT32_MIN) if (x == INT32_MIN)
return INT32_MIN; return INT32_MIN;
else if (x < FixedFloor(INT32_MAX)) else if (x < FixedFloor(INT32_MAX))

View File

@ -1675,6 +1675,7 @@ char *M_GetToken(const char *inputString)
|| stringToUse[startPos] == '\r' || stringToUse[startPos] == '\r'
|| stringToUse[startPos] == '\n' || stringToUse[startPos] == '\n'
|| stringToUse[startPos] == '\0' || stringToUse[startPos] == '\0'
|| stringToUse[startPos] == '"' // we're treating this as whitespace because SLADE likes adding it for no good reason
|| inComment != 0) || inComment != 0)
&& startPos < stringLength) && startPos < stringLength)
{ {
@ -1742,6 +1743,7 @@ char *M_GetToken(const char *inputString)
&& stringToUse[endPos] != ',' && stringToUse[endPos] != ','
&& stringToUse[endPos] != '{' && stringToUse[endPos] != '{'
&& stringToUse[endPos] != '}' && stringToUse[endPos] != '}'
&& stringToUse[endPos] != '"' // see above
&& inComment == 0) && inComment == 0)
&& endPos < stringLength) && endPos < stringLength)
{ {

View File

@ -7644,7 +7644,7 @@ void A_SetObjectFlags(mobj_t *actor)
else if (locvar2 == 1) else if (locvar2 == 1)
locvar1 = actor->flags & ~locvar1; locvar1 = actor->flags & ~locvar1;
if ((locvar1 & (MF_NOBLOCKMAP|MF_NOSECTOR)) != (actor->flags & (MF_NOBLOCKMAP|MF_NOSECTOR))) // Blockmap/sector status has changed, so reset the links if ((UINT32)(locvar1 & (MF_NOBLOCKMAP|MF_NOSECTOR)) != (actor->flags & (MF_NOBLOCKMAP|MF_NOSECTOR))) // Blockmap/sector status has changed, so reset the links
unlinkthings = true; unlinkthings = true;
if (unlinkthings) { if (unlinkthings) {

View File

@ -1684,7 +1684,7 @@ void P_CheckTimeLimit(void)
return; return;
//Tagmode round end but only on the tic before the //Tagmode round end but only on the tic before the
//XD_EXITLEVEL packet is recieved by all players. //XD_EXITLEVEL packet is received by all players.
if (G_TagGametype()) if (G_TagGametype())
{ {
if (leveltime == (timelimitintics + 1)) if (leveltime == (timelimitintics + 1))
@ -1695,7 +1695,7 @@ void P_CheckTimeLimit(void)
|| (players[i].pflags & PF_TAGGED) || (players[i].pflags & PF_TAGIT)) || (players[i].pflags & PF_TAGGED) || (players[i].pflags & PF_TAGIT))
continue; continue;
CONS_Printf(M_GetText("%s recieved double points for surviving the round.\n"), player_names[i]); CONS_Printf(M_GetText("%s received double points for surviving the round.\n"), player_names[i]);
P_AddPlayerScore(&players[i], players[i].score); P_AddPlayerScore(&players[i], players[i].score);
} }
} }

View File

@ -985,18 +985,24 @@ static boolean PIT_CheckThing(mobj_t *thing)
return true; return true;
} }
topz = thing->z - FixedMul(FRACUNIT, thing->scale); topz = thing->z - thing->scale; // FixedMul(FRACUNIT, thing->scale), but thing->scale == FRACUNIT in base scale anyways
// block only when jumping not high enough, // block only when jumping not high enough,
// (dont climb max. 24units while already in air) // (dont climb max. 24units while already in air)
// if not in air, let P_TryMove() decide if it's not too high // since return false doesn't handle momentum properly,
// we lie to P_TryMove() so it's always too high
if (tmthing->player && tmthing->z + tmthing->height > topz if (tmthing->player && tmthing->z + tmthing->height > topz
&& tmthing->z + tmthing->height < tmthing->ceilingz) && tmthing->z + tmthing->height < tmthing->ceilingz)
return false; // block while in air {
tmfloorz = tmceilingz = topz; // block while in air
if (thing->flags & MF_SPRING) #ifdef ESLOPE
tmceilingslope = NULL;
#endif
tmfloorthing = thing; // needed for side collision
}
else if (thing->flags & MF_SPRING)
; ;
else if (topz < tmceilingz && tmthing->z+tmthing->height <= thing->z+thing->height) else if (topz < tmceilingz && tmthing->z <= thing->z+thing->height)
{ {
tmceilingz = topz; tmceilingz = topz;
#ifdef ESLOPE #ifdef ESLOPE
@ -1022,17 +1028,24 @@ static boolean PIT_CheckThing(mobj_t *thing)
return true; return true;
} }
topz = thing->z + thing->height + FixedMul(FRACUNIT, thing->scale); topz = thing->z + thing->height + thing->scale; // FixedMul(FRACUNIT, thing->scale), but thing->scale == FRACUNIT in base scale anyways
// block only when jumping not high enough, // block only when jumping not high enough,
// (dont climb max. 24units while already in air) // (dont climb max. 24units while already in air)
// if not in air, let P_TryMove() decide if it's not too high // since return false doesn't handle momentum properly,
if (tmthing->player && tmthing->z < topz && tmthing->z > tmthing->floorz) // we lie to P_TryMove() so it's always too high
return false; // block while in air if (tmthing->player && tmthing->z < topz
&& tmthing->z > tmthing->floorz)
if (thing->flags & MF_SPRING) {
tmfloorz = tmceilingz = topz; // block while in air
#ifdef ESLOPE
tmfloorslope = NULL;
#endif
tmfloorthing = thing; // needed for side collision
}
else if (thing->flags & MF_SPRING)
; ;
else if (topz > tmfloorz && tmthing->z >= thing->z) else if (topz > tmfloorz && tmthing->z+tmthing->height >= thing->z)
{ {
tmfloorz = topz; tmfloorz = topz;
#ifdef ESLOPE #ifdef ESLOPE

View File

@ -572,51 +572,54 @@ void P_LineOpening(line_t *linedef, mobj_t *mobj)
side_t *side = &sides[linedef->sidenum[0]]; side_t *side = &sides[linedef->sidenum[0]];
fixed_t textop, texbottom, texheight; fixed_t textop, texbottom, texheight;
fixed_t texmid, delta1, delta2; fixed_t texmid, delta1, delta2;
INT32 texnum = R_GetTextureNum(side->midtexture); // make sure the texture is actually valid
// Get the midtexture's height if (texnum) {
texheight = textures[texturetranslation[side->midtexture]]->height << FRACBITS; // Get the midtexture's height
texheight = textures[texnum]->height << FRACBITS;
// Set texbottom and textop to the Z coordinates of the texture's boundaries // Set texbottom and textop to the Z coordinates of the texture's boundaries
#if 0 // #ifdef POLYOBJECTS #if 0 // #ifdef POLYOBJECTS
// don't remove this code unless solid midtextures // don't remove this code unless solid midtextures
// on non-solid polyobjects should NEVER happen in the future // on non-solid polyobjects should NEVER happen in the future
if (linedef->polyobj && (linedef->polyobj->flags & POF_TESTHEIGHT)) { if (linedef->polyobj && (linedef->polyobj->flags & POF_TESTHEIGHT)) {
if (linedef->flags & ML_EFFECT5 && !side->repeatcnt) { // "infinite" repeat if (linedef->flags & ML_EFFECT5 && !side->repeatcnt) { // "infinite" repeat
texbottom = back->floorheight + side->rowoffset; texbottom = back->floorheight + side->rowoffset;
textop = back->ceilingheight + side->rowoffset; textop = back->ceilingheight + side->rowoffset;
} else if (!!(linedef->flags & ML_DONTPEGBOTTOM) ^ !!(linedef->flags & ML_EFFECT3)) { } else if (!!(linedef->flags & ML_DONTPEGBOTTOM) ^ !!(linedef->flags & ML_EFFECT3)) {
texbottom = back->floorheight + side->rowoffset; texbottom = back->floorheight + side->rowoffset;
textop = texbottom + texheight*(side->repeatcnt+1); textop = texbottom + texheight*(side->repeatcnt+1);
} else { } else {
textop = back->ceilingheight + side->rowoffset; textop = back->ceilingheight + side->rowoffset;
texbottom = textop - texheight*(side->repeatcnt+1); texbottom = textop - texheight*(side->repeatcnt+1);
} }
} else } else
#endif #endif
{ {
if (linedef->flags & ML_EFFECT5 && !side->repeatcnt) { // "infinite" repeat if (linedef->flags & ML_EFFECT5 && !side->repeatcnt) { // "infinite" repeat
texbottom = openbottom + side->rowoffset; texbottom = openbottom + side->rowoffset;
textop = opentop + side->rowoffset; textop = opentop + side->rowoffset;
} else if (!!(linedef->flags & ML_DONTPEGBOTTOM) ^ !!(linedef->flags & ML_EFFECT3)) { } else if (!!(linedef->flags & ML_DONTPEGBOTTOM) ^ !!(linedef->flags & ML_EFFECT3)) {
texbottom = openbottom + side->rowoffset; texbottom = openbottom + side->rowoffset;
textop = texbottom + texheight*(side->repeatcnt+1); textop = texbottom + texheight*(side->repeatcnt+1);
} else { } else {
textop = opentop + side->rowoffset; textop = opentop + side->rowoffset;
texbottom = textop - texheight*(side->repeatcnt+1); texbottom = textop - texheight*(side->repeatcnt+1);
}
} }
}
texmid = texbottom+(textop-texbottom)/2; texmid = texbottom+(textop-texbottom)/2;
delta1 = abs(mobj->z - texmid); delta1 = abs(mobj->z - texmid);
delta2 = abs(thingtop - texmid); delta2 = abs(thingtop - texmid);
if (delta1 > delta2) { // Below if (delta1 > delta2) { // Below
if (opentop > texbottom) if (opentop > texbottom)
opentop = texbottom; opentop = texbottom;
} else { // Above } else { // Above
if (openbottom < textop) if (openbottom < textop)
openbottom = textop; openbottom = textop;
}
} }
} }

View File

@ -2017,13 +2017,13 @@ static void P_AdjustMobjFloorZ_FFloors(mobj_t *mo, sector_t *sector, UINT8 motyp
delta2 = thingtop - (bottomheight + ((topheight - bottomheight)/2)); delta2 = thingtop - (bottomheight + ((topheight - bottomheight)/2));
if (topheight > mo->floorz && abs(delta1) < abs(delta2) if (topheight > mo->floorz && abs(delta1) < abs(delta2)
&& !(rover->flags & FF_REVERSEPLATFORM) && !(rover->flags & FF_REVERSEPLATFORM)
&& ((P_MobjFlip(mo)*mo->momz > 0) || (!(rover->flags & FF_PLATFORM)))) // In reverse gravity, only clip for FOFs that are intangible from their bottom (the "top" you're falling through) if you're coming from above ("below" in your frame of reference) && ((P_MobjFlip(mo)*mo->momz >= 0) || (!(rover->flags & FF_PLATFORM)))) // In reverse gravity, only clip for FOFs that are intangible from their bottom (the "top" you're falling through) if you're coming from above ("below" in your frame of reference)
{ {
mo->floorz = topheight; mo->floorz = topheight;
} }
if (bottomheight < mo->ceilingz && abs(delta1) >= abs(delta2) if (bottomheight < mo->ceilingz && abs(delta1) >= abs(delta2)
&& !(rover->flags & FF_PLATFORM) && !(rover->flags & FF_PLATFORM)
&& ((P_MobjFlip(mo)*mo->momz > 0) || (!(rover->flags & FF_REVERSEPLATFORM)))) // In normal gravity, only clip for FOFs that are intangible from the top if you're coming from below && ((P_MobjFlip(mo)*mo->momz >= 0) || (!(rover->flags & FF_REVERSEPLATFORM)))) // In normal gravity, only clip for FOFs that are intangible from the top if you're coming from below
{ {
mo->ceilingz = bottomheight; mo->ceilingz = bottomheight;
} }
@ -4436,7 +4436,7 @@ static void P_Boss4MoveSpikeballs(mobj_t *mobj, angle_t angle, fixed_t fz)
{ {
INT32 s; INT32 s;
mobj_t *base = mobj, *seg; mobj_t *base = mobj, *seg;
fixed_t dist, bz = (mobj->spawnpoint->z+16)<<FRACBITS; fixed_t dist, bz = mobj->watertop+(16<<FRACBITS);
while ((base = base->tracer)) while ((base = base->tracer))
{ {
for (seg = base, dist = 172*FRACUNIT, s = 9; seg; seg = seg->hnext, dist += 124*FRACUNIT, --s) for (seg = base, dist = 172*FRACUNIT, s = 9; seg; seg = seg->hnext, dist += 124*FRACUNIT, --s)
@ -4450,7 +4450,7 @@ static void P_Boss4PinchSpikeballs(mobj_t *mobj, angle_t angle, fixed_t fz)
{ {
INT32 s; INT32 s;
mobj_t *base = mobj, *seg; mobj_t *base = mobj, *seg;
fixed_t dist, bz = (mobj->spawnpoint->z+16)<<FRACBITS; fixed_t dist, bz = mobj->watertop+(16<<FRACBITS);
while ((base = base->tracer)) while ((base = base->tracer))
{ {
for (seg = base, dist = 112*FRACUNIT, s = 9; seg; seg = seg->hnext, dist += 132*FRACUNIT, --s) for (seg = base, dist = 112*FRACUNIT, s = 9; seg; seg = seg->hnext, dist += 132*FRACUNIT, --s)
@ -4566,7 +4566,7 @@ static void P_Boss4Thinker(mobj_t *mobj)
INT32 i, arm; INT32 i, arm;
mobj_t *seg, *base = mobj; mobj_t *seg, *base = mobj;
// First frame init, spawn all the things. // First frame init, spawn all the things.
mobj->spawnpoint->z = mobj->z>>FRACBITS; mobj->watertop = mobj->z;
z = mobj->z + mobj->height/2 - mobjinfo[MT_EGGMOBILE4_MACE].height/2; z = mobj->z + mobj->height/2 - mobjinfo[MT_EGGMOBILE4_MACE].height/2;
for (arm = 0; arm <3 ; arm++) for (arm = 0; arm <3 ; arm++)
{ {
@ -4622,7 +4622,7 @@ static void P_Boss4Thinker(mobj_t *mobj)
case 3: case 3:
{ {
fixed_t z; fixed_t z;
if (mobj->z < (mobj->spawnpoint->z+512)<<FRACBITS) if (mobj->z < mobj->watertop+(512<<FRACBITS))
mobj->momz = 8*FRACUNIT; mobj->momz = 8*FRACUNIT;
else else
{ {
@ -4631,7 +4631,7 @@ static void P_Boss4Thinker(mobj_t *mobj)
} }
mobj->movecount += 400<<(FRACBITS>>1); mobj->movecount += 400<<(FRACBITS>>1);
mobj->movecount %= 360*FRACUNIT; mobj->movecount %= 360*FRACUNIT;
z = mobj->z - (mobj->spawnpoint->z<<FRACBITS) - mobjinfo[MT_EGGMOBILE4_MACE].height - mobj->height/2; z = mobj->z - mobj->watertop - mobjinfo[MT_EGGMOBILE4_MACE].height - mobj->height/2;
if (z < 0) // We haven't risen high enough to pull the spikeballs along yet if (z < 0) // We haven't risen high enough to pull the spikeballs along yet
P_Boss4MoveSpikeballs(mobj, FixedAngle(mobj->movecount), 0); // So don't pull the spikeballs along yet. P_Boss4MoveSpikeballs(mobj, FixedAngle(mobj->movecount), 0); // So don't pull the spikeballs along yet.
else else
@ -4641,13 +4641,13 @@ static void P_Boss4Thinker(mobj_t *mobj)
// Pinch phase! // Pinch phase!
case 4: case 4:
{ {
if (mobj->z < (mobj->spawnpoint->z+512+128*(mobj->info->damage-mobj->health))<<FRACBITS) if (mobj->z < (mobj->watertop + ((512+128*(mobj->info->damage-mobj->health))<<FRACBITS)))
mobj->momz = 8*FRACUNIT; mobj->momz = 8*FRACUNIT;
else else
mobj->momz = 0; mobj->momz = 0;
mobj->movecount += (800+800*(mobj->info->damage-mobj->health))<<(FRACBITS>>1); mobj->movecount += (800+800*(mobj->info->damage-mobj->health))<<(FRACBITS>>1);
mobj->movecount %= 360*FRACUNIT; mobj->movecount %= 360*FRACUNIT;
P_Boss4PinchSpikeballs(mobj, FixedAngle(mobj->movecount), mobj->z - (mobj->spawnpoint->z<<FRACBITS) - mobjinfo[MT_EGGMOBILE4_MACE].height - mobj->height/2); P_Boss4PinchSpikeballs(mobj, FixedAngle(mobj->movecount), mobj->z - mobj->watertop - mobjinfo[MT_EGGMOBILE4_MACE].height - mobj->height/2);
if (!mobj->target || !mobj->target->health) if (!mobj->target || !mobj->target->health)
P_SupermanLook4Players(mobj); P_SupermanLook4Players(mobj);
@ -6048,6 +6048,8 @@ void P_RunOverlays(void)
P_UnsetThingPosition(mo); P_UnsetThingPosition(mo);
mo->x = destx; mo->x = destx;
mo->y = desty; mo->y = desty;
mo->radius = mo->target->radius;
mo->height = mo->target->height;
if (mo->eflags & MFE_VERTICALFLIP) if (mo->eflags & MFE_VERTICALFLIP)
mo->z = (mo->target->z + mo->target->height - mo->height) - zoffs; mo->z = (mo->target->z + mo->target->height - mo->height) - zoffs;
else else
@ -7683,6 +7685,10 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type)
if (mobj->type == MT_UNIDUS) if (mobj->type == MT_UNIDUS)
mobj->z -= FixedMul(mobj->info->mass, mobj->scale); mobj->z -= FixedMul(mobj->info->mass, mobj->scale);
// defaults onground
if (mobj->z + mobj->height == mobj->ceilingz)
mobj->eflags |= MFE_ONGROUND;
} }
else else
mobj->z = z; mobj->z = z;

View File

@ -460,6 +460,7 @@ static void P_NetUnArchivePlayers(void)
#define SD_TAG 0x10 #define SD_TAG 0x10
#define SD_FLOORANG 0x20 #define SD_FLOORANG 0x20
#define SD_CEILANG 0x40 #define SD_CEILANG 0x40
#define SD_TAGLIST 0x80
#define LD_FLAG 0x01 #define LD_FLAG 0x01
#define LD_SPECIAL 0x02 #define LD_SPECIAL 0x02
@ -509,10 +510,9 @@ static void P_NetArchiveWorld(void)
// //
// flats // flats
// //
// P_AddLevelFlat should not add but just return the number if (ss->floorpic != P_CheckLevelFlat(ms->floorpic))
if (ss->floorpic != P_AddLevelFlat(ms->floorpic, levelflats))
diff |= SD_FLOORPIC; diff |= SD_FLOORPIC;
if (ss->ceilingpic != P_AddLevelFlat(ms->ceilingpic, levelflats)) if (ss->ceilingpic != P_CheckLevelFlat(ms->ceilingpic))
diff |= SD_CEILPIC; diff |= SD_CEILPIC;
if (ss->lightlevel != SHORT(ms->lightlevel)) if (ss->lightlevel != SHORT(ms->lightlevel))
@ -535,6 +535,8 @@ static void P_NetArchiveWorld(void)
if (ss->tag != SHORT(ms->tag)) if (ss->tag != SHORT(ms->tag))
diff2 |= SD_TAG; diff2 |= SD_TAG;
if (ss->nexttag != ss->spawn_nexttag || ss->firsttag != ss->spawn_firsttag)
diff2 |= SD_TAGLIST;
// Check if any of the sector's FOFs differ from how they spawned // Check if any of the sector's FOFs differ from how they spawned
if (ss->ffloors) if (ss->ffloors)
@ -582,16 +584,17 @@ static void P_NetArchiveWorld(void)
WRITEFIXED(put, ss->ceiling_xoffs); WRITEFIXED(put, ss->ceiling_xoffs);
if (diff2 & SD_CYOFFS) if (diff2 & SD_CYOFFS)
WRITEFIXED(put, ss->ceiling_yoffs); WRITEFIXED(put, ss->ceiling_yoffs);
if (diff2 & SD_TAG) if (diff2 & SD_TAG) // save only the tag
{
WRITEINT16(put, ss->tag); WRITEINT16(put, ss->tag);
WRITEINT32(put, ss->firsttag);
WRITEINT32(put, ss->nexttag);
}
if (diff2 & SD_FLOORANG) if (diff2 & SD_FLOORANG)
WRITEANGLE(put, ss->floorpic_angle); WRITEANGLE(put, ss->floorpic_angle);
if (diff2 & SD_CEILANG) if (diff2 & SD_CEILANG)
WRITEANGLE(put, ss->ceilingpic_angle); WRITEANGLE(put, ss->ceilingpic_angle);
if (diff2 & SD_TAGLIST) // save both firsttag and nexttag
{ // either of these could be changed even if tag isn't
WRITEINT32(put, ss->firsttag);
WRITEINT32(put, ss->nexttag);
}
// Special case: save the stats of all modified ffloors along with their ffloor "number"s // Special case: save the stats of all modified ffloors along with their ffloor "number"s
// we don't bother with ffloors that haven't changed, that would just add to savegame even more than is really needed // we don't bother with ffloors that haven't changed, that would just add to savegame even more than is really needed
@ -752,12 +755,12 @@ static void P_NetUnArchiveWorld(void)
sectors[i].ceilingheight = READFIXED(get); sectors[i].ceilingheight = READFIXED(get);
if (diff & SD_FLOORPIC) if (diff & SD_FLOORPIC)
{ {
sectors[i].floorpic = P_AddLevelFlat((char *)get, levelflats); sectors[i].floorpic = P_AddLevelFlatRuntime((char *)get);
get += 8; get += 8;
} }
if (diff & SD_CEILPIC) if (diff & SD_CEILPIC)
{ {
sectors[i].ceilingpic = P_AddLevelFlat((char *)get, levelflats); sectors[i].ceilingpic = P_AddLevelFlatRuntime((char *)get);
get += 8; get += 8;
} }
if (diff & SD_LIGHT) if (diff & SD_LIGHT)
@ -774,12 +777,11 @@ static void P_NetUnArchiveWorld(void)
if (diff2 & SD_CYOFFS) if (diff2 & SD_CYOFFS)
sectors[i].ceiling_yoffs = READFIXED(get); sectors[i].ceiling_yoffs = READFIXED(get);
if (diff2 & SD_TAG) if (diff2 & SD_TAG)
sectors[i].tag = READINT16(get); // DON'T use P_ChangeSectorTag
if (diff2 & SD_TAGLIST)
{ {
INT16 tag;
tag = READINT16(get);
sectors[i].firsttag = READINT32(get); sectors[i].firsttag = READINT32(get);
sectors[i].nexttag = READINT32(get); sectors[i].nexttag = READINT32(get);
P_ChangeSectorTag(i, tag);
} }
if (diff2 & SD_FLOORANG) if (diff2 & SD_FLOORANG)
sectors[i].floorpic_angle = READANGLE(get); sectors[i].floorpic_angle = READANGLE(get);
@ -2607,6 +2609,7 @@ static void P_NetUnArchiveThinkers(void)
thinker_t *next; thinker_t *next;
UINT8 tclass; UINT8 tclass;
UINT8 restoreNum = false; UINT8 restoreNum = false;
UINT32 i;
if (READUINT32(save_p) != ARCHIVEBLOCK_THINKERS) if (READUINT32(save_p) != ARCHIVEBLOCK_THINKERS)
I_Error("Bad $$$.sav at archive block Thinkers"); I_Error("Bad $$$.sav at archive block Thinkers");
@ -2627,6 +2630,12 @@ static void P_NetUnArchiveThinkers(void)
iquetail = iquehead = 0; iquetail = iquehead = 0;
P_InitThinkers(); P_InitThinkers();
// clear sector thinker pointers so they don't point to non-existant thinkers for all of eternity
for (i = 0; i < numsectors; i++)
{
sectors[i].floordata = sectors[i].ceilingdata = sectors[i].lightingdata = NULL;
}
// read in saved thinkers // read in saved thinkers
for (;;) for (;;)
{ {
@ -3285,7 +3294,7 @@ void P_SaveNetGame(void)
{ {
thinker_t *th; thinker_t *th;
mobj_t *mobj; mobj_t *mobj;
INT32 i = 0; INT32 i = 1; // don't start from 0, it'd be confused with a blank pointer otherwise
CV_SaveNetVars(&save_p); CV_SaveNetVars(&save_p);
P_NetArchiveMisc(); P_NetArchiveMisc();

View File

@ -574,6 +574,69 @@ INT32 P_AddLevelFlat(const char *flatname, levelflat_t *levelflat)
return (INT32)i; return (INT32)i;
} }
// help function for Lua and $$$.sav reading
// same as P_AddLevelFlat, except this is not setup so we must realloc levelflats to fit in the new flat
// no longer a static func in lua_maplib.c because p_saveg.c also needs it
//
INT32 P_AddLevelFlatRuntime(const char *flatname)
{
size_t i;
levelflat_t *levelflat = levelflats;
//
// first scan through the already found flats
//
for (i = 0; i < numlevelflats; i++, levelflat++)
if (strnicmp(levelflat->name,flatname,8)==0)
break;
// that flat was already found in the level, return the id
if (i == numlevelflats)
{
// allocate new flat memory
levelflats = Z_Realloc(levelflats, (numlevelflats + 1) * sizeof(*levelflats), PU_LEVEL, NULL);
levelflat = levelflats+i;
// store the name
strlcpy(levelflat->name, flatname, sizeof (levelflat->name));
strupr(levelflat->name);
// store the flat lump number
levelflat->lumpnum = R_GetFlatNumForName(flatname);
#ifndef ZDEBUG
CONS_Debug(DBG_SETUP, "flat #%03d: %s\n", atoi(sizeu1(numlevelflats)), levelflat->name);
#endif
numlevelflats++;
}
// level flat id
return (INT32)i;
}
// help function for $$$.sav checking
// this simply returns the flat # for the name given
//
INT32 P_CheckLevelFlat(const char *flatname)
{
size_t i;
levelflat_t *levelflat = levelflats;
//
// scan through the already found flats
//
for (i = 0; i < numlevelflats; i++, levelflat++)
if (strnicmp(levelflat->name,flatname,8)==0)
break;
if (i == numlevelflats)
return 0; // ??? flat was not found, this should not happen!
// level flat id
return (INT32)i;
}
static void P_LoadSectors(lumpnum_t lumpnum) static void P_LoadSectors(lumpnum_t lumpnum)
{ {
UINT8 *data; UINT8 *data;
@ -614,6 +677,7 @@ static void P_LoadSectors(lumpnum_t lumpnum)
ss->special = SHORT(ms->special); ss->special = SHORT(ms->special);
ss->tag = SHORT(ms->tag); ss->tag = SHORT(ms->tag);
ss->nexttag = ss->firsttag = -1; ss->nexttag = ss->firsttag = -1;
ss->spawn_nexttag = ss->spawn_firsttag = -1;
memset(&ss->soundorg, 0, sizeof(ss->soundorg)); memset(&ss->soundorg, 0, sizeof(ss->soundorg));
ss->validcount = 0; ss->validcount = 0;
@ -2587,10 +2651,6 @@ boolean P_SetupLevel(boolean skipprecip)
R_ReInitColormaps(mapheaderinfo[gamemap-1]->palette); R_ReInitColormaps(mapheaderinfo[gamemap-1]->palette);
CON_SetupBackColormap(); CON_SetupBackColormap();
// now part of level loading since in future each level may have
// its own anim texture sequences, switches etc.
P_InitPicAnims();
// SRB2 determines the sky texture to be used depending on the map header. // SRB2 determines the sky texture to be used depending on the map header.
P_SetupLevelSky(mapheaderinfo[gamemap-1]->skynum, true); P_SetupLevelSky(mapheaderinfo[gamemap-1]->skynum, true);
@ -3001,6 +3061,9 @@ boolean P_AddWadFile(const char *wadfilename, char **firstmapname)
else else
R_FlushTextureCache(); // just reload it from file R_FlushTextureCache(); // just reload it from file
// Reload ANIMATED / ANIMDEFS
P_InitPicAnims();
// Flush and reload HUD graphics // Flush and reload HUD graphics
ST_UnloadGraphics(); ST_UnloadGraphics();
HU_LoadGraphics(); HU_LoadGraphics();

View File

@ -47,6 +47,8 @@ typedef struct
extern size_t numlevelflats; extern size_t numlevelflats;
extern levelflat_t *levelflats; extern levelflat_t *levelflats;
INT32 P_AddLevelFlat(const char *flatname, levelflat_t *levelflat); INT32 P_AddLevelFlat(const char *flatname, levelflat_t *levelflat);
INT32 P_AddLevelFlatRuntime(const char *flatname);
INT32 P_CheckLevelFlat(const char *flatname);
extern size_t nummapthings; extern size_t nummapthings;
extern mapthing_t *mapthings; extern mapthing_t *mapthings;

View File

@ -221,8 +221,8 @@ static animdef_t harddefs[] =
static animdef_t *animdefs = NULL; static animdef_t *animdefs = NULL;
// A prototype; here instead of p_spec.h, so they're "private" // A prototype; here instead of p_spec.h, so they're "private"
void P_ParseANIMDEFSLump(INT32 wadNum, UINT16 lumpnum, INT32 *i); void P_ParseANIMDEFSLump(INT32 wadNum, UINT16 lumpnum);
void P_ParseAnimationDefintion(SINT8 istexture, INT32 *i); void P_ParseAnimationDefintion(SINT8 istexture);
/** Sets up texture and flat animations. /** Sets up texture and flat animations.
* *
@ -232,24 +232,21 @@ void P_ParseAnimationDefintion(SINT8 istexture, INT32 *i);
* Issues an error if any animation cycles are invalid. * Issues an error if any animation cycles are invalid.
* *
* \sa P_FindAnimatedFlat, P_SetupLevelFlatAnims * \sa P_FindAnimatedFlat, P_SetupLevelFlatAnims
* \author Steven McGranahan (original), Shadow Hog (had to rewrite it to handle multiple WADs) * \author Steven McGranahan (original), Shadow Hog (had to rewrite it to handle multiple WADs), JTE (had to rewrite it to handle multiple WADs _correctly_)
*/ */
void P_InitPicAnims(void) void P_InitPicAnims(void)
{ {
// Init animation // Init animation
INT32 i; // Position in the animdefs array
INT32 w; // WAD INT32 w; // WAD
UINT8 *wadAnimdefs; // not to be confused with animdefs, the combined total of every ANIMATED lump in every WAD, or ANIMDEFS, the ZDoom lump I intend to implement later UINT8 *animatedLump;
UINT8 *currentPos; UINT8 *currentPos;
size_t i;
I_Assert(animdefs == NULL);
if (W_CheckNumForName("ANIMATED") != LUMPERROR || W_CheckNumForName("ANIMDEFS") != LUMPERROR) if (W_CheckNumForName("ANIMATED") != LUMPERROR || W_CheckNumForName("ANIMDEFS") != LUMPERROR)
{ {
if (animdefs) for (w = numwadfiles-1, maxanims = 0; w >= 0; w--)
{
Z_Free(animdefs);
animdefs = NULL;
}
for (w = 0, i = 0, maxanims = 0; w < numwadfiles; w++)
{ {
UINT16 animatedLumpNum; UINT16 animatedLumpNum;
UINT16 animdefsLumpNum; UINT16 animdefsLumpNum;
@ -258,20 +255,20 @@ void P_InitPicAnims(void)
animatedLumpNum = W_CheckNumForNamePwad("ANIMATED", w, 0); animatedLumpNum = W_CheckNumForNamePwad("ANIMATED", w, 0);
if (animatedLumpNum != INT16_MAX) if (animatedLumpNum != INT16_MAX)
{ {
wadAnimdefs = (UINT8 *)W_CacheLumpNumPwad(w, animatedLumpNum, PU_STATIC); animatedLump = (UINT8 *)W_CacheLumpNumPwad(w, animatedLumpNum, PU_STATIC);
// Get the number of animations in the file // Get the number of animations in the file
for (currentPos = wadAnimdefs; *currentPos != UINT8_MAX; maxanims++, currentPos+=23); i = maxanims;
for (currentPos = animatedLump; *currentPos != UINT8_MAX; maxanims++, currentPos+=23);
// Resize animdefs (or if it hasn't been created, create it) // Resize animdefs (or if it hasn't been created, create it)
animdefs = (animdef_t *)Z_Realloc(animdefs, sizeof(animdef_t)*(maxanims + 1), PU_STATIC, NULL); animdefs = (animdef_t *)Z_Realloc(animdefs, sizeof(animdef_t)*(maxanims + 1), PU_STATIC, NULL);
// Sanity check it // Sanity check it
if (!animdefs) { if (!animdefs)
I_Error("Not enough free memory for ANIMATED data"); I_Error("Not enough free memory for ANIMATED data");
}
// Populate the new array // Populate the new array
for (currentPos = wadAnimdefs; *currentPos != UINT8_MAX; i++, currentPos+=23) for (currentPos = animatedLump; *currentPos != UINT8_MAX; i++, currentPos+=23)
{ {
M_Memcpy(&(animdefs[i].istexture), currentPos, 1); // istexture, 1 byte M_Memcpy(&(animdefs[i].istexture), currentPos, 1); // istexture, 1 byte
M_Memcpy(animdefs[i].endname, (currentPos + 1), 9); // endname, 9 bytes M_Memcpy(animdefs[i].endname, (currentPos + 1), 9); // endname, 9 bytes
@ -279,15 +276,13 @@ void P_InitPicAnims(void)
M_Memcpy(&(animdefs[i].speed), (currentPos + 19), 4); // speed, 4 bytes M_Memcpy(&(animdefs[i].speed), (currentPos + 19), 4); // speed, 4 bytes
} }
Z_Free(wadAnimdefs); Z_Free(animatedLump);
} }
// Now find ANIMDEFS // Now find ANIMDEFS
animdefsLumpNum = W_CheckNumForNamePwad("ANIMDEFS", w, 0); animdefsLumpNum = W_CheckNumForNamePwad("ANIMDEFS", w, 0);
if (animdefsLumpNum != INT16_MAX) if (animdefsLumpNum != INT16_MAX)
{ P_ParseANIMDEFSLump(w, animdefsLumpNum);
P_ParseANIMDEFSLump(w, animdefsLumpNum, &i);
}
} }
// Define the last one // Define the last one
animdefs[maxanims].istexture = -1; animdefs[maxanims].istexture = -1;
@ -347,16 +342,20 @@ void P_InitPicAnims(void)
lastanim->istexture = -1; lastanim->istexture = -1;
R_ClearTextureNumCache(false); R_ClearTextureNumCache(false);
// Clear animdefs now that we're done with it.
// We'll only be using anims from now on.
if (animdefs != harddefs) if (animdefs != harddefs)
Z_ChangeTag(animdefs, PU_CACHE); Z_Free(animdefs);
animdefs = NULL;
} }
void P_ParseANIMDEFSLump(INT32 wadNum, UINT16 lumpnum, INT32 *i) void P_ParseANIMDEFSLump(INT32 wadNum, UINT16 lumpnum)
{ {
char *animdefsLump; char *animdefsLump;
size_t animdefsLumpLength; size_t animdefsLumpLength;
char *animdefsText; char *animdefsText;
char *animdefsToken; char *animdefsToken;
char *p;
// Since lumps AREN'T \0-terminated like I'd assumed they should be, I'll // Since lumps AREN'T \0-terminated like I'd assumed they should be, I'll
// need to make a space of memory where I can ensure that it will terminate // need to make a space of memory where I can ensure that it will terminate
@ -376,18 +375,19 @@ void P_ParseANIMDEFSLump(INT32 wadNum, UINT16 lumpnum, INT32 *i)
Z_Free(animdefsLump); Z_Free(animdefsLump);
// Now, let's start parsing this thing // Now, let's start parsing this thing
animdefsToken = M_GetToken(animdefsText); p = animdefsText;
animdefsToken = M_GetToken(p);
while (animdefsToken != NULL) while (animdefsToken != NULL)
{ {
if (stricmp(animdefsToken, "TEXTURE") == 0) if (stricmp(animdefsToken, "TEXTURE") == 0)
{ {
Z_Free(animdefsToken); Z_Free(animdefsToken);
P_ParseAnimationDefintion(1, i); P_ParseAnimationDefintion(1);
} }
else if (stricmp(animdefsToken, "FLAT") == 0) else if (stricmp(animdefsToken, "FLAT") == 0)
{ {
Z_Free(animdefsToken); Z_Free(animdefsToken);
P_ParseAnimationDefintion(0, i); P_ParseAnimationDefintion(0);
} }
else if (stricmp(animdefsToken, "OSCILLATE") == 0) else if (stricmp(animdefsToken, "OSCILLATE") == 0)
{ {
@ -398,23 +398,22 @@ void P_ParseANIMDEFSLump(INT32 wadNum, UINT16 lumpnum, INT32 *i)
{ {
I_Error("Error parsing ANIMDEFS lump: Expected \"TEXTURE\" or \"FLAT\", got \"%s\"",animdefsToken); I_Error("Error parsing ANIMDEFS lump: Expected \"TEXTURE\" or \"FLAT\", got \"%s\"",animdefsToken);
} }
animdefsToken = M_GetToken(NULL); // parse next line
while (*p != '\0' && *p != '\n') ++p;
if (*p == '\n') ++p;
animdefsToken = M_GetToken(p);
} }
Z_Free(animdefsToken); Z_Free(animdefsToken);
Z_Free((void *)animdefsText); Z_Free((void *)animdefsText);
} }
void P_ParseAnimationDefintion(SINT8 istexture, INT32 *i) void P_ParseAnimationDefintion(SINT8 istexture)
{ {
char *animdefsToken; char *animdefsToken;
size_t animdefsTokenLength; size_t animdefsTokenLength;
char *endPos; char *endPos;
INT32 animSpeed; INT32 animSpeed;
size_t i;
// Increase the size to make room for the new animation definition
maxanims++;
animdefs = (animdef_t *)Z_Realloc(animdefs, sizeof(animdef_t)*(maxanims + 1), PU_STATIC, NULL);
animdefs[*i].istexture = istexture;
// Startname // Startname
animdefsToken = M_GetToken(NULL); animdefsToken = M_GetToken(NULL);
@ -448,14 +447,39 @@ void P_ParseAnimationDefintion(SINT8 istexture, INT32 *i)
{ {
I_Error("Error parsing ANIMDEFS lump: lump name \"%s\" exceeds 8 characters", animdefsToken); I_Error("Error parsing ANIMDEFS lump: lump name \"%s\" exceeds 8 characters", animdefsToken);
} }
strncpy(animdefs[*i].startname, animdefsToken, 9);
// Search for existing animdef
for (i = 0; i < maxanims; i++)
if (stricmp(animdefsToken, animdefs[i].startname) == 0)
{
//CONS_Alert(CONS_NOTICE, "Duplicate animation: %s\n", animdefsToken);
// If we weren't parsing in reverse order, we would `break` here and parse the new data into the existing slot we found.
// Instead, we're just going to skip parsing the rest of this line entirely.
Z_Free(animdefsToken);
return;
}
// Not found
if (i == maxanims)
{
// Increase the size to make room for the new animation definition
maxanims++;
animdefs = (animdef_t *)Z_Realloc(animdefs, sizeof(animdef_t)*(maxanims + 1), PU_STATIC, NULL);
strncpy(animdefs[i].startname, animdefsToken, 9);
}
// animdefs[i].startname is now set to animdefsToken either way.
Z_Free(animdefsToken); Z_Free(animdefsToken);
// set texture type
animdefs[i].istexture = istexture;
// "RANGE" // "RANGE"
animdefsToken = M_GetToken(NULL); animdefsToken = M_GetToken(NULL);
if (animdefsToken == NULL) if (animdefsToken == NULL)
{ {
I_Error("Error parsing ANIMDEFS lump: Unexpected end of file where \"RANGE\" after \"%s\"'s startname should be", animdefs[*i].startname); I_Error("Error parsing ANIMDEFS lump: Unexpected end of file where \"RANGE\" after \"%s\"'s startname should be", animdefs[i].startname);
} }
if (stricmp(animdefsToken, "ALLOWDECALS") == 0) if (stricmp(animdefsToken, "ALLOWDECALS") == 0)
{ {
@ -470,7 +494,7 @@ void P_ParseAnimationDefintion(SINT8 istexture, INT32 *i)
} }
if (stricmp(animdefsToken, "RANGE") != 0) if (stricmp(animdefsToken, "RANGE") != 0)
{ {
I_Error("Error parsing ANIMDEFS lump: Expected \"RANGE\" after \"%s\"'s startname, got \"%s\"", animdefs[*i].startname, animdefsToken); I_Error("Error parsing ANIMDEFS lump: Expected \"RANGE\" after \"%s\"'s startname, got \"%s\"", animdefs[i].startname, animdefsToken);
} }
Z_Free(animdefsToken); Z_Free(animdefsToken);
@ -478,21 +502,21 @@ void P_ParseAnimationDefintion(SINT8 istexture, INT32 *i)
animdefsToken = M_GetToken(NULL); animdefsToken = M_GetToken(NULL);
if (animdefsToken == NULL) if (animdefsToken == NULL)
{ {
I_Error("Error parsing ANIMDEFS lump: Unexpected end of file where \"%s\"'s end texture/flat name should be", animdefs[*i].startname); I_Error("Error parsing ANIMDEFS lump: Unexpected end of file where \"%s\"'s end texture/flat name should be", animdefs[i].startname);
} }
animdefsTokenLength = strlen(animdefsToken); animdefsTokenLength = strlen(animdefsToken);
if (animdefsTokenLength>8) if (animdefsTokenLength>8)
{ {
I_Error("Error parsing ANIMDEFS lump: lump name \"%s\" exceeds 8 characters", animdefsToken); I_Error("Error parsing ANIMDEFS lump: lump name \"%s\" exceeds 8 characters", animdefsToken);
} }
strncpy(animdefs[*i].endname, animdefsToken, 9); strncpy(animdefs[i].endname, animdefsToken, 9);
Z_Free(animdefsToken); Z_Free(animdefsToken);
// "TICS" // "TICS"
animdefsToken = M_GetToken(NULL); animdefsToken = M_GetToken(NULL);
if (animdefsToken == NULL) if (animdefsToken == NULL)
{ {
I_Error("Error parsing ANIMDEFS lump: Unexpected end of file where \"%s\"'s \"TICS\" should be", animdefs[*i].startname); I_Error("Error parsing ANIMDEFS lump: Unexpected end of file where \"%s\"'s \"TICS\" should be", animdefs[i].startname);
} }
if (stricmp(animdefsToken, "RAND") == 0) if (stricmp(animdefsToken, "RAND") == 0)
{ {
@ -501,7 +525,7 @@ void P_ParseAnimationDefintion(SINT8 istexture, INT32 *i)
} }
if (stricmp(animdefsToken, "TICS") != 0) if (stricmp(animdefsToken, "TICS") != 0)
{ {
I_Error("Error parsing ANIMDEFS lump: Expected \"TICS\" in animation definition for \"%s\", got \"%s\"", animdefs[*i].startname, animdefsToken); I_Error("Error parsing ANIMDEFS lump: Expected \"TICS\" in animation definition for \"%s\", got \"%s\"", animdefs[i].startname, animdefsToken);
} }
Z_Free(animdefsToken); Z_Free(animdefsToken);
@ -509,7 +533,7 @@ void P_ParseAnimationDefintion(SINT8 istexture, INT32 *i)
animdefsToken = M_GetToken(NULL); animdefsToken = M_GetToken(NULL);
if (animdefsToken == NULL) if (animdefsToken == NULL)
{ {
I_Error("Error parsing TEXTURES lump: Unexpected end of file where \"%s\"'s animation speed should be", animdefs[*i].startname); I_Error("Error parsing ANIMDEFS lump: Unexpected end of file where \"%s\"'s animation speed should be", animdefs[i].startname);
} }
endPos = NULL; endPos = NULL;
#ifndef AVOID_ERRNO #ifndef AVOID_ERRNO
@ -523,13 +547,10 @@ void P_ParseAnimationDefintion(SINT8 istexture, INT32 *i)
#endif #endif
|| animSpeed < 0) // Number is not positive || animSpeed < 0) // Number is not positive
{ {
I_Error("Error parsing TEXTURES lump: Expected a positive integer for \"%s\"'s animation speed, got \"%s\"", animdefs[*i].startname, animdefsToken); I_Error("Error parsing ANIMDEFS lump: Expected a positive integer for \"%s\"'s animation speed, got \"%s\"", animdefs[i].startname, animdefsToken);
} }
animdefs[*i].speed = animSpeed; animdefs[i].speed = animSpeed;
Z_Free(animdefsToken); Z_Free(animdefsToken);
// Increment i before we go, so this doesn't cause issues later
(*i)++;
} }
@ -1498,6 +1519,8 @@ static inline void P_InitTagLists(void)
size_t j = (unsigned)sectors[i].tag % numsectors; size_t j = (unsigned)sectors[i].tag % numsectors;
sectors[i].nexttag = sectors[j].firsttag; sectors[i].nexttag = sectors[j].firsttag;
sectors[j].firsttag = (INT32)i; sectors[j].firsttag = (INT32)i;
sectors[i].spawn_nexttag = sectors[i].nexttag;
sectors[j].spawn_firsttag = sectors[j].firsttag;
} }
for (i = numlines - 1; i != (size_t)-1; i--) for (i = numlines - 1; i != (size_t)-1; i--)
@ -5321,6 +5344,10 @@ void T_LaserFlash(laserthink_t *flash)
&& thing->flags & MF_BOSS) && thing->flags & MF_BOSS)
continue; // Don't hurt bosses continue; // Don't hurt bosses
// Don't endlessly kill egg guard shields (or anything else for that matter)
if (thing->health <= 0)
continue;
top = P_GetSpecialTopZ(thing, sourcesec, sector); top = P_GetSpecialTopZ(thing, sourcesec, sector);
bottom = P_GetSpecialBottomZ(thing, sourcesec, sector); bottom = P_GetSpecialBottomZ(thing, sourcesec, sector);
@ -7428,7 +7455,7 @@ void T_Pusher(pusher_t *p)
} }
else else
{ {
if (top < thing->z || referrer->floorheight > (thing->z + (thing->height >> 1))) if (top < thing->z || bottom > (thing->z + (thing->height >> 1)))
continue; continue;
if (thing->z + thing->height > top) if (thing->z + thing->height > top)
touching = true; touching = true;

View File

@ -2280,14 +2280,13 @@ static void P_DoClimbing(player_t *player)
fixed_t platy; fixed_t platy;
subsector_t *glidesector; subsector_t *glidesector;
boolean climb = true; boolean climb = true;
boolean onesided = ((player->lastsidehit != -1 && player->lastlinehit != -1) && !(lines[player->lastlinehit].backsector));
platx = P_ReturnThrustX(player->mo, player->mo->angle, player->mo->radius + FixedMul(8*FRACUNIT, player->mo->scale)); platx = P_ReturnThrustX(player->mo, player->mo->angle, player->mo->radius + FixedMul(8*FRACUNIT, player->mo->scale));
platy = P_ReturnThrustY(player->mo, player->mo->angle, player->mo->radius + FixedMul(8*FRACUNIT, player->mo->scale)); platy = P_ReturnThrustY(player->mo, player->mo->angle, player->mo->radius + FixedMul(8*FRACUNIT, player->mo->scale));
glidesector = R_PointInSubsector(player->mo->x + platx, player->mo->y + platy); glidesector = R_IsPointInSubsector(player->mo->x + platx, player->mo->y + platy);
if (onesided || glidesector->sector != player->mo->subsector->sector) if (!glidesector || glidesector->sector != player->mo->subsector->sector)
{ {
boolean floorclimb = false; boolean floorclimb = false;
boolean thrust = false; boolean thrust = false;
@ -2295,7 +2294,7 @@ static void P_DoClimbing(player_t *player)
boolean skyclimber = false; boolean skyclimber = false;
fixed_t floorheight, ceilingheight; // ESLOPE fixed_t floorheight, ceilingheight; // ESLOPE
if (onesided) if (!glidesector)
floorclimb = true; floorclimb = true;
else else
{ {
@ -7058,7 +7057,6 @@ static void P_DoZoomTube(player_t *player)
mobj_t *waypoint = NULL; mobj_t *waypoint = NULL;
fixed_t dist; fixed_t dist;
boolean reverse; boolean reverse;
fixed_t speedx,speedy,speedz;
player->mo->height = P_GetPlayerSpinHeight(player); player->mo->height = P_GetPlayerSpinHeight(player);
@ -7079,17 +7077,17 @@ static void P_DoZoomTube(player_t *player)
if (dist < 1) if (dist < 1)
dist = 1; dist = 1;
speedx = FixedMul(FixedDiv(player->mo->tracer->x - player->mo->x, dist), (speed)); player->mo->momx = FixedMul(FixedDiv(player->mo->tracer->x - player->mo->x, dist), (speed));
speedy = FixedMul(FixedDiv(player->mo->tracer->y - player->mo->y, dist), (speed)); player->mo->momy = FixedMul(FixedDiv(player->mo->tracer->y - player->mo->y, dist), (speed));
speedz = FixedMul(FixedDiv(player->mo->tracer->z - player->mo->z, dist), (speed)); player->mo->momz = FixedMul(FixedDiv(player->mo->tracer->z - player->mo->z, dist), (speed));
// Calculate the distance between the player and the waypoint // Calculate the distance between the player and the waypoint
// 'dist' already equals this. // 'dist' already equals this.
// Will the player be FURTHER away if the momx/momy/momz is added to // Will the player go past the waypoint?
// his current coordinates, or closer? (shift down to fracunits to avoid approximation errors) if (speed > dist)
if (dist>>FRACBITS <= P_AproxDistance(P_AproxDistance(player->mo->tracer->x - player->mo->x - speedx, player->mo->tracer->y - player->mo->y - speedy), player->mo->tracer->z - player->mo->z - speedz)>>FRACBITS)
{ {
speed -= dist;
// If further away, set XYZ of player to waypoint location // If further away, set XYZ of player to waypoint location
P_UnsetThingPosition(player->mo); P_UnsetThingPosition(player->mo);
player->mo->x = player->mo->tracer->x; player->mo->x = player->mo->tracer->x;
@ -7129,14 +7127,9 @@ static void P_DoZoomTube(player_t *player)
{ {
CONS_Debug(DBG_GAMELOGIC, "Found waypoint (sequence %d, number %d).\n", waypoint->threshold, waypoint->health); CONS_Debug(DBG_GAMELOGIC, "Found waypoint (sequence %d, number %d).\n", waypoint->threshold, waypoint->health);
// calculate MOMX/MOMY/MOMZ for next waypoint P_SetTarget(&player->mo->tracer, waypoint);
// change angle
player->mo->angle = R_PointToAngle2(player->mo->x, player->mo->y, player->mo->tracer->x, player->mo->tracer->y);
if (player == &players[consoleplayer]) // calculate MOMX/MOMY/MOMZ for next waypoint
localangle = player->mo->angle;
else if (player == &players[secondarydisplayplayer])
localangle2 = player->mo->angle;
// change slope // change slope
dist = P_AproxDistance(P_AproxDistance(player->mo->tracer->x - player->mo->x, player->mo->tracer->y - player->mo->y), player->mo->tracer->z - player->mo->z); dist = P_AproxDistance(P_AproxDistance(player->mo->tracer->x - player->mo->x, player->mo->tracer->y - player->mo->y), player->mo->tracer->z - player->mo->z);
@ -7147,22 +7140,14 @@ static void P_DoZoomTube(player_t *player)
player->mo->momx = FixedMul(FixedDiv(player->mo->tracer->x - player->mo->x, dist), (speed)); player->mo->momx = FixedMul(FixedDiv(player->mo->tracer->x - player->mo->x, dist), (speed));
player->mo->momy = FixedMul(FixedDiv(player->mo->tracer->y - player->mo->y, dist), (speed)); player->mo->momy = FixedMul(FixedDiv(player->mo->tracer->y - player->mo->y, dist), (speed));
player->mo->momz = FixedMul(FixedDiv(player->mo->tracer->z - player->mo->z, dist), (speed)); player->mo->momz = FixedMul(FixedDiv(player->mo->tracer->z - player->mo->z, dist), (speed));
P_SetTarget(&player->mo->tracer, waypoint);
} }
else else
{ {
P_SetTarget(&player->mo->tracer, NULL); // Else, we just let him fly. P_SetTarget(&player->mo->tracer, NULL); // Else, we just let them fly.
CONS_Debug(DBG_GAMELOGIC, "Next waypoint not found, releasing from track...\n"); CONS_Debug(DBG_GAMELOGIC, "Next waypoint not found, releasing from track...\n");
} }
} }
else
{
player->mo->momx = speedx;
player->mo->momy = speedy;
player->mo->momz = speedz;
}
// change angle // change angle
if (player->mo->tracer) if (player->mo->tracer)
@ -7190,24 +7175,10 @@ static void P_DoRopeHang(player_t *player)
mobj_t *mo2; mobj_t *mo2;
mobj_t *waypoint = NULL; mobj_t *waypoint = NULL;
fixed_t dist; fixed_t dist;
fixed_t speedx,speedy,speedz;
fixed_t playerz; fixed_t playerz;
player->mo->height = P_GetPlayerHeight(player); player->mo->height = P_GetPlayerHeight(player);
if (player->cmd.buttons & BT_USE && !(player->pflags & PF_STASIS)) // Drop off of the rope
{
P_SetTarget(&player->mo->tracer, NULL);
player->pflags |= PF_JUMPED;
player->pflags &= ~PF_ROPEHANG;
if (!(player->pflags & PF_SLIDING) && (player->pflags & PF_JUMPED)
&& !(player->panim == PA_ROLL) && player->charability2 == CA2_SPINDASH)
P_SetPlayerMobjState(player->mo, S_PLAY_ATK1);
return;
}
// Play the 'clink' sound only if the player is moving. // Play the 'clink' sound only if the player is moving.
if (!(leveltime & 7) && player->speed) if (!(leveltime & 7) && player->speed)
S_StartSound(player->mo, sfx_s3k55); S_StartSound(player->mo, sfx_s3k55);
@ -7224,9 +7195,22 @@ static void P_DoRopeHang(player_t *player)
if (dist < 1) if (dist < 1)
dist = 1; dist = 1;
speedx = FixedMul(FixedDiv(player->mo->tracer->x - player->mo->x, dist), (speed)); player->mo->momx = FixedMul(FixedDiv(player->mo->tracer->x - player->mo->x, dist), (speed));
speedy = FixedMul(FixedDiv(player->mo->tracer->y - player->mo->y, dist), (speed)); player->mo->momy = FixedMul(FixedDiv(player->mo->tracer->y - player->mo->y, dist), (speed));
speedz = FixedMul(FixedDiv(player->mo->tracer->z - playerz, dist), (speed)); player->mo->momz = FixedMul(FixedDiv(player->mo->tracer->z - playerz, dist), (speed));
if (player->cmd.buttons & BT_USE && !(player->pflags & PF_STASIS)) // Drop off of the rope
{
P_SetTarget(&player->mo->tracer, NULL);
player->pflags |= PF_JUMPED;
player->pflags &= ~PF_ROPEHANG;
if (!(player->pflags & PF_SLIDING) && (player->pflags & PF_JUMPED)
&& !(player->panim == PA_ROLL) && player->charability2 == CA2_SPINDASH)
P_SetPlayerMobjState(player->mo, S_PLAY_ATK1);
return;
}
// If not allowed to move, we're done here. // If not allowed to move, we're done here.
if (!speed) if (!speed)
@ -7235,15 +7219,16 @@ static void P_DoRopeHang(player_t *player)
// Calculate the distance between the player and the waypoint // Calculate the distance between the player and the waypoint
// 'dist' already equals this. // 'dist' already equals this.
// Will the player be FURTHER away if the momx/momy/momz is added to // Will the player go past the waypoint?
// his current coordinates, or closer? (shift down to fracunits to avoid approximation errors) if (speed > dist)
if (dist>>FRACBITS <= P_AproxDistance(P_AproxDistance(player->mo->tracer->x - player->mo->x - speedx, player->mo->tracer->y - player->mo->y - speedy), player->mo->tracer->z - playerz - speedz)>>FRACBITS)
{ {
speed -= dist;
// If further away, set XYZ of player to waypoint location // If further away, set XYZ of player to waypoint location
P_UnsetThingPosition(player->mo); P_UnsetThingPosition(player->mo);
player->mo->x = player->mo->tracer->x; player->mo->x = player->mo->tracer->x;
player->mo->y = player->mo->tracer->y; player->mo->y = player->mo->tracer->y;
player->mo->z = player->mo->tracer->z - player->mo->height; player->mo->z = player->mo->tracer->z - player->mo->height;
playerz = player->mo->tracer->z;
P_SetThingPosition(player->mo); P_SetThingPosition(player->mo);
CONS_Debug(DBG_GAMELOGIC, "Looking for next waypoint...\n"); CONS_Debug(DBG_GAMELOGIC, "Looking for next waypoint...\n");
@ -7299,6 +7284,8 @@ static void P_DoRopeHang(player_t *player)
{ {
CONS_Debug(DBG_GAMELOGIC, "Found waypoint (sequence %d, number %d).\n", waypoint->threshold, waypoint->health); CONS_Debug(DBG_GAMELOGIC, "Found waypoint (sequence %d, number %d).\n", waypoint->threshold, waypoint->health);
P_SetTarget(&player->mo->tracer, waypoint);
// calculate MOMX/MOMY/MOMZ for next waypoint // calculate MOMX/MOMY/MOMZ for next waypoint
// change slope // change slope
dist = P_AproxDistance(P_AproxDistance(player->mo->tracer->x - player->mo->x, player->mo->tracer->y - player->mo->y), player->mo->tracer->z - playerz); dist = P_AproxDistance(P_AproxDistance(player->mo->tracer->x - player->mo->x, player->mo->tracer->y - player->mo->y), player->mo->tracer->z - playerz);
@ -7309,8 +7296,6 @@ static void P_DoRopeHang(player_t *player)
player->mo->momx = FixedMul(FixedDiv(player->mo->tracer->x - player->mo->x, dist), (speed)); player->mo->momx = FixedMul(FixedDiv(player->mo->tracer->x - player->mo->x, dist), (speed));
player->mo->momy = FixedMul(FixedDiv(player->mo->tracer->y - player->mo->y, dist), (speed)); player->mo->momy = FixedMul(FixedDiv(player->mo->tracer->y - player->mo->y, dist), (speed));
player->mo->momz = FixedMul(FixedDiv(player->mo->tracer->z - playerz, dist), (speed)); player->mo->momz = FixedMul(FixedDiv(player->mo->tracer->z - playerz, dist), (speed));
P_SetTarget(&player->mo->tracer, waypoint);
} }
else else
{ {
@ -7329,12 +7314,6 @@ static void P_DoRopeHang(player_t *player)
CONS_Debug(DBG_GAMELOGIC, "Next waypoint not found!\n"); CONS_Debug(DBG_GAMELOGIC, "Next waypoint not found!\n");
} }
} }
else
{
player->mo->momx = speedx;
player->mo->momy = speedy;
player->mo->momz = speedz;
}
} }
#if 0 #if 0

View File

@ -210,7 +210,7 @@ void R_PortalClearClipSegs(INT32 start, INT32 end)
// //
// It assumes that Doom has already ruled out a door being closed because // It assumes that Doom has already ruled out a door being closed because
// of front-back closure (e.g. front floor is taller than back ceiling). // of front-back closure (e.g. front floor is taller than back ceiling).
static inline INT32 R_DoorClosed(void) static INT32 R_DoorClosed(void)
{ {
return return
@ -859,6 +859,7 @@ static void R_Subsector(size_t num)
static sector_t tempsec; // Deep water hack static sector_t tempsec; // Deep water hack
extracolormap_t *floorcolormap; extracolormap_t *floorcolormap;
extracolormap_t *ceilingcolormap; extracolormap_t *ceilingcolormap;
fixed_t floorcenterz, ceilingcenterz;
#ifdef RANGECHECK #ifdef RANGECHECK
if (num >= numsubsectors) if (num >= numsubsectors)
@ -879,6 +880,18 @@ static void R_Subsector(size_t num)
floorcolormap = ceilingcolormap = frontsector->extra_colormap; floorcolormap = ceilingcolormap = frontsector->extra_colormap;
floorcenterz =
#ifdef ESLOPE
frontsector->f_slope ? P_GetZAt(frontsector->f_slope, frontsector->soundorg.x, frontsector->soundorg.y) :
#endif
frontsector->floorheight;
ceilingcenterz =
#ifdef ESLOPE
frontsector->c_slope ? P_GetZAt(frontsector->c_slope, frontsector->soundorg.x, frontsector->soundorg.y) :
#endif
frontsector->ceilingheight;
// Check and prep all 3D floors. Set the sector floor/ceiling light levels and colormaps. // Check and prep all 3D floors. Set the sector floor/ceiling light levels and colormaps.
if (frontsector->ffloors) if (frontsector->ffloors)
{ {
@ -891,19 +904,11 @@ static void R_Subsector(size_t num)
sub->sector->moved = frontsector->moved = false; sub->sector->moved = frontsector->moved = false;
} }
light = R_GetPlaneLight(frontsector, light = R_GetPlaneLight(frontsector, floorcenterz, false);
#ifdef ESLOPE
frontsector->f_slope ? P_GetZAt(frontsector->f_slope, frontsector->soundorg.x, frontsector->soundorg.y) :
#endif
frontsector->floorheight, false);
if (frontsector->floorlightsec == -1) if (frontsector->floorlightsec == -1)
floorlightlevel = *frontsector->lightlist[light].lightlevel; floorlightlevel = *frontsector->lightlist[light].lightlevel;
floorcolormap = frontsector->lightlist[light].extra_colormap; floorcolormap = frontsector->lightlist[light].extra_colormap;
light = R_GetPlaneLight(frontsector, light = R_GetPlaneLight(frontsector, ceilingcenterz, false);
#ifdef ESLOPE
frontsector->c_slope ? P_GetZAt(frontsector->c_slope, frontsector->soundorg.x, frontsector->soundorg.y) :
#endif
frontsector->ceilingheight, false);
if (frontsector->ceilinglightsec == -1) if (frontsector->ceilinglightsec == -1)
ceilinglightlevel = *frontsector->lightlist[light].lightlevel; ceilinglightlevel = *frontsector->lightlist[light].lightlevel;
ceilingcolormap = frontsector->lightlist[light].extra_colormap; ceilingcolormap = frontsector->lightlist[light].extra_colormap;
@ -920,6 +925,9 @@ static void R_Subsector(size_t num)
{ {
floorplane = R_FindPlane(frontsector->floorheight, frontsector->floorpic, floorlightlevel, floorplane = R_FindPlane(frontsector->floorheight, frontsector->floorpic, floorlightlevel,
frontsector->floor_xoffs, frontsector->floor_yoffs, frontsector->floorpic_angle, floorcolormap, NULL frontsector->floor_xoffs, frontsector->floor_yoffs, frontsector->floorpic_angle, floorcolormap, NULL
#ifdef POLYOBJECTS_PLANES
, NULL
#endif
#ifdef ESLOPE #ifdef ESLOPE
, frontsector->f_slope , frontsector->f_slope
#endif #endif
@ -939,6 +947,9 @@ static void R_Subsector(size_t num)
ceilingplane = R_FindPlane(frontsector->ceilingheight, frontsector->ceilingpic, ceilingplane = R_FindPlane(frontsector->ceilingheight, frontsector->ceilingpic,
ceilinglightlevel, frontsector->ceiling_xoffs, frontsector->ceiling_yoffs, frontsector->ceilingpic_angle, ceilinglightlevel, frontsector->ceiling_xoffs, frontsector->ceiling_yoffs, frontsector->ceilingpic_angle,
ceilingcolormap, NULL ceilingcolormap, NULL
#ifdef POLYOBJECTS_PLANES
, NULL
#endif
#ifdef ESLOPE #ifdef ESLOPE
, frontsector->c_slope , frontsector->c_slope
#endif #endif
@ -956,7 +967,7 @@ static void R_Subsector(size_t num)
if (frontsector->ffloors) if (frontsector->ffloors)
{ {
ffloor_t *rover; ffloor_t *rover;
fixed_t heightcheck, planecenterz, floorcenterz, ceilingcenterz; fixed_t heightcheck, planecenterz;
for (rover = frontsector->ffloors; rover && numffloors < MAXFFLOORS; rover = rover->next) for (rover = frontsector->ffloors; rover && numffloors < MAXFFLOORS; rover = rover->next)
{ {
@ -975,18 +986,6 @@ static void R_Subsector(size_t num)
ffloor[numffloors].plane = NULL; ffloor[numffloors].plane = NULL;
ffloor[numffloors].polyobj = NULL; ffloor[numffloors].polyobj = NULL;
floorcenterz =
#ifdef ESLOPE
frontsector->f_slope ? P_GetZAt(frontsector->f_slope, frontsector->soundorg.x, frontsector->soundorg.y) :
#endif
frontsector->floorheight;
ceilingcenterz =
#ifdef ESLOPE
frontsector->c_slope ? P_GetZAt(frontsector->c_slope, frontsector->soundorg.x, frontsector->soundorg.y) :
#endif
frontsector->ceilingheight;
heightcheck = heightcheck =
#ifdef ESLOPE #ifdef ESLOPE
*rover->b_slope ? P_GetZAt(*rover->b_slope, viewx, viewy) : *rover->b_slope ? P_GetZAt(*rover->b_slope, viewx, viewy) :
@ -1009,6 +1008,9 @@ static void R_Subsector(size_t num)
ffloor[numffloors].plane = R_FindPlane(*rover->bottomheight, *rover->bottompic, ffloor[numffloors].plane = R_FindPlane(*rover->bottomheight, *rover->bottompic,
*frontsector->lightlist[light].lightlevel, *rover->bottomxoffs, *frontsector->lightlist[light].lightlevel, *rover->bottomxoffs,
*rover->bottomyoffs, *rover->bottomangle, frontsector->lightlist[light].extra_colormap, rover *rover->bottomyoffs, *rover->bottomangle, frontsector->lightlist[light].extra_colormap, rover
#ifdef POLYOBJECTS_PLANES
, NULL
#endif
#ifdef ESLOPE #ifdef ESLOPE
, *rover->b_slope , *rover->b_slope
#endif #endif
@ -1052,6 +1054,9 @@ static void R_Subsector(size_t num)
ffloor[numffloors].plane = R_FindPlane(*rover->topheight, *rover->toppic, ffloor[numffloors].plane = R_FindPlane(*rover->topheight, *rover->toppic,
*frontsector->lightlist[light].lightlevel, *rover->topxoffs, *rover->topyoffs, *rover->topangle, *frontsector->lightlist[light].lightlevel, *rover->topxoffs, *rover->topyoffs, *rover->topangle,
frontsector->lightlist[light].extra_colormap, rover frontsector->lightlist[light].extra_colormap, rover
#ifdef POLYOBJECTS_PLANES
, NULL
#endif
#ifdef ESLOPE #ifdef ESLOPE
, *rover->t_slope , *rover->t_slope
#endif #endif
@ -1093,8 +1098,8 @@ static void R_Subsector(size_t num)
polysec = po->lines[0]->backsector; polysec = po->lines[0]->backsector;
ffloor[numffloors].plane = NULL; ffloor[numffloors].plane = NULL;
if (polysec->floorheight <= frontsector->ceilingheight if (polysec->floorheight <= ceilingcenterz
&& polysec->floorheight >= frontsector->floorheight && polysec->floorheight >= floorcenterz
&& (viewz < polysec->floorheight)) && (viewz < polysec->floorheight))
{ {
fixed_t xoff, yoff; fixed_t xoff, yoff;
@ -1118,11 +1123,13 @@ static void R_Subsector(size_t num)
polysec->floorpic_angle-po->angle, polysec->floorpic_angle-po->angle,
NULL, NULL,
NULL NULL
#ifdef POLYOBJECTS_PLANES
, po
#endif
#ifdef ESLOPE #ifdef ESLOPE
, NULL // will ffloors be slopable eventually? , NULL // will ffloors be slopable eventually?
#endif #endif
); );
//ffloor[numffloors].plane->polyobj = po;
ffloor[numffloors].height = polysec->floorheight; ffloor[numffloors].height = polysec->floorheight;
ffloor[numffloors].polyobj = po; ffloor[numffloors].polyobj = po;
@ -1139,8 +1146,8 @@ static void R_Subsector(size_t num)
ffloor[numffloors].plane = NULL; ffloor[numffloors].plane = NULL;
if (polysec->ceilingheight >= frontsector->floorheight if (polysec->ceilingheight >= floorcenterz
&& polysec->ceilingheight <= frontsector->ceilingheight && polysec->ceilingheight <= ceilingcenterz
&& (viewz > polysec->ceilingheight)) && (viewz > polysec->ceilingheight))
{ {
fixed_t xoff, yoff; fixed_t xoff, yoff;
@ -1162,11 +1169,13 @@ static void R_Subsector(size_t num)
ffloor[numffloors].plane = R_FindPlane(polysec->ceilingheight, polysec->ceilingpic, ffloor[numffloors].plane = R_FindPlane(polysec->ceilingheight, polysec->ceilingpic,
polysec->lightlevel, xoff, yoff, polysec->ceilingpic_angle-po->angle, polysec->lightlevel, xoff, yoff, polysec->ceilingpic_angle-po->angle,
NULL, NULL NULL, NULL
#ifdef POLYOBJECTS_PLANES
, po
#endif
#ifdef ESLOPE #ifdef ESLOPE
, NULL // will ffloors be slopable eventually? , NULL // will ffloors be slopable eventually?
#endif #endif
); );
//ffloor[numffloors].plane->polyobj = po;
ffloor[numffloors].polyobj = po; ffloor[numffloors].polyobj = po;
ffloor[numffloors].height = polysec->ceilingheight; ffloor[numffloors].height = polysec->ceilingheight;

View File

@ -303,6 +303,32 @@ done:
return blocktex; return blocktex;
} }
//
// R_GetTextureNum
//
// Returns the actual texture id that we should use.
// This can either be texnum, the current frame for texnum's anim (if animated),
// or 0 if not valid.
//
INT32 R_GetTextureNum(INT32 texnum)
{
if (texnum < 0 || texnum >= numtextures)
return 0;
return texturetranslation[texnum];
}
//
// R_CheckTextureCache
//
// Use this if you need to make sure the texture is cached before R_GetColumn calls
// e.g.: midtextures and FOF walls
//
void R_CheckTextureCache(INT32 tex)
{
if (!texturecache[tex])
R_GenerateTexture(tex);
}
// //
// R_GetColumn // R_GetColumn
// //
@ -1499,6 +1525,9 @@ void R_InitData(void)
CONS_Printf("R_LoadTextures()...\n"); CONS_Printf("R_LoadTextures()...\n");
R_LoadTextures(); R_LoadTextures();
CONS_Printf("P_InitPicAnims()...\n");
P_InitPicAnims();
CONS_Printf("R_InitSprites()...\n"); CONS_Printf("R_InitSprites()...\n");
R_InitSpriteLumps(); R_InitSpriteLumps();
R_InitSprites(); R_InitSprites();

View File

@ -65,6 +65,9 @@ extern CV_PossibleValue_t Color_cons_t[];
void R_LoadTextures(void); void R_LoadTextures(void);
void R_FlushTextureCache(void); void R_FlushTextureCache(void);
INT32 R_GetTextureNum(INT32 texnum);
void R_CheckTextureCache(INT32 tex);
// Retrieve column data for span blitting. // Retrieve column data for span blitting.
UINT8 *R_GetColumn(fixed_t tex, INT32 col); UINT8 *R_GetColumn(fixed_t tex, INT32 col);

View File

@ -203,6 +203,7 @@ typedef struct r_lightlist_s
fixed_t heightstep; fixed_t heightstep;
fixed_t botheight; fixed_t botheight;
fixed_t botheightstep; fixed_t botheightstep;
fixed_t startheight; // for repeating midtextures
INT16 lightlevel; INT16 lightlevel;
extracolormap_t *extra_colormap; extracolormap_t *extra_colormap;
lighttable_t *rcolormap; lighttable_t *rcolormap;
@ -383,6 +384,7 @@ typedef struct sector_s
#endif #endif
// these are saved for netgames, so do not let Lua touch these! // these are saved for netgames, so do not let Lua touch these!
INT32 spawn_nexttag, spawn_firsttag; // the actual nexttag/firsttag values may differ if the sector's tag was changed
// offsets sector spawned with (via linedef type 7) // offsets sector spawned with (via linedef type 7)
fixed_t spawn_flr_xoffs, spawn_flr_yoffs; fixed_t spawn_flr_xoffs, spawn_flr_yoffs;

View File

@ -708,7 +708,7 @@ subsector_t *R_PointInSubsector(fixed_t x, fixed_t y)
} }
// //
// R_IsPointInSubsector, same as above but returns 0 if not in subsector - this does not work in opengl because of polyvertex_t // R_IsPointInSubsector, same as above but returns 0 if not in subsector
// //
subsector_t *R_IsPointInSubsector(fixed_t x, fixed_t y) subsector_t *R_IsPointInSubsector(fixed_t x, fixed_t y)
{ {
@ -732,7 +732,8 @@ subsector_t *R_IsPointInSubsector(fixed_t x, fixed_t y)
ret = &subsectors[nodenum & ~NF_SUBSECTOR]; ret = &subsectors[nodenum & ~NF_SUBSECTOR];
for (i = 0; i < ret->numlines; i++) for (i = 0; i < ret->numlines; i++)
if (R_PointOnSegSide(x, y, &segs[ret->firstline + i])) //if (R_PointOnSegSide(x, y, &segs[ret->firstline + i])) -- breaks in ogl because polyvertex_t cast over vertex pointers
if (P_PointOnLineSide(x, y, segs[ret->firstline + i].linedef) != segs[ret->firstline + i].side)
return 0; return 0;
return ret; return ret;

View File

@ -431,6 +431,9 @@ static visplane_t *new_visplane(unsigned hash)
visplane_t *R_FindPlane(fixed_t height, INT32 picnum, INT32 lightlevel, visplane_t *R_FindPlane(fixed_t height, INT32 picnum, INT32 lightlevel,
fixed_t xoff, fixed_t yoff, angle_t plangle, extracolormap_t *planecolormap, fixed_t xoff, fixed_t yoff, angle_t plangle, extracolormap_t *planecolormap,
ffloor_t *pfloor ffloor_t *pfloor
#ifdef POLYOBJECTS_PLANES
, polyobj_t *polyobj
#endif
#ifdef ESLOPE #ifdef ESLOPE
, pslope_t *slope , pslope_t *slope
#endif #endif
@ -470,6 +473,8 @@ visplane_t *R_FindPlane(fixed_t height, INT32 picnum, INT32 lightlevel,
#ifdef POLYOBJECTS_PLANES #ifdef POLYOBJECTS_PLANES
if (check->polyobj && pfloor) if (check->polyobj && pfloor)
continue; continue;
if (polyobj != check->polyobj)
continue;
#endif #endif
if (height == check->height && picnum == check->picnum if (height == check->height && picnum == check->picnum
&& lightlevel == check->lightlevel && lightlevel == check->lightlevel
@ -504,7 +509,7 @@ visplane_t *R_FindPlane(fixed_t height, INT32 picnum, INT32 lightlevel,
check->viewangle = viewangle; check->viewangle = viewangle;
check->plangle = plangle; check->plangle = plangle;
#ifdef POLYOBJECTS_PLANES #ifdef POLYOBJECTS_PLANES
check->polyobj = NULL; check->polyobj = polyobj;
#endif #endif
#ifdef ESLOPE #ifdef ESLOPE
check->slope = slope; check->slope = slope;
@ -719,7 +724,11 @@ void R_DrawPlanes(void)
continue; continue;
} }
if (pl->ffloor != NULL) if (pl->ffloor != NULL
#ifdef POLYOBJECTS_PLANES
|| pl->polyobj != NULL
#endif
)
continue; continue;
R_DrawSinglePlane(pl); R_DrawSinglePlane(pl);

View File

@ -97,6 +97,9 @@ void R_MakeSpans(INT32 x, INT32 t1, INT32 b1, INT32 t2, INT32 b2);
void R_DrawPlanes(void); void R_DrawPlanes(void);
visplane_t *R_FindPlane(fixed_t height, INT32 picnum, INT32 lightlevel, fixed_t xoff, fixed_t yoff, angle_t plangle, visplane_t *R_FindPlane(fixed_t height, INT32 picnum, INT32 lightlevel, fixed_t xoff, fixed_t yoff, angle_t plangle,
extracolormap_t *planecolormap, ffloor_t *ffloor extracolormap_t *planecolormap, ffloor_t *ffloor
#ifdef POLYOBJECTS_PLANES
, polyobj_t *polyobj
#endif
#ifdef ESLOPE #ifdef ESLOPE
, pslope_t *slope , pslope_t *slope
#endif #endif

View File

@ -300,7 +300,7 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2)
curline = ds->curline; curline = ds->curline;
frontsector = curline->frontsector; frontsector = curline->frontsector;
backsector = curline->backsector; backsector = curline->backsector;
texnum = texturetranslation[curline->sidedef->midtexture]; texnum = R_GetTextureNum(curline->sidedef->midtexture);
windowbottom = windowtop = sprbotscreen = INT32_MAX; windowbottom = windowtop = sprbotscreen = INT32_MAX;
// hack translucent linedef types (900-909 for transtables 1-9) // hack translucent linedef types (900-909 for transtables 1-9)
@ -344,6 +344,9 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2)
rw_scalestep = ds->scalestep; rw_scalestep = ds->scalestep;
spryscale = ds->scale1 + (x1 - ds->x1)*rw_scalestep; spryscale = ds->scale1 + (x1 - ds->x1)*rw_scalestep;
// Texture must be cached before setting colfunc_2s,
// otherwise texture[texnum]->holes may be false when it shouldn't be
R_CheckTextureCache(texnum);
// handle case where multipatch texture is drawn on a 2sided wall, multi-patch textures // handle case where multipatch texture is drawn on a 2sided wall, multi-patch textures
// are not stored per-column with post info in SRB2 // are not stored per-column with post info in SRB2
if (textures[texnum]->holes) if (textures[texnum]->holes)
@ -391,6 +394,7 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2)
rlight->height = (centeryfrac) - FixedMul((light->height - viewz), spryscale); rlight->height = (centeryfrac) - FixedMul((light->height - viewz), spryscale);
rlight->heightstep = -FixedMul(rw_scalestep, (light->height - viewz)); rlight->heightstep = -FixedMul(rw_scalestep, (light->height - viewz));
#endif #endif
rlight->startheight = rlight->height; // keep starting value here to reset for each repeat
rlight->lightlevel = *light->lightlevel; rlight->lightlevel = *light->lightlevel;
rlight->extra_colormap = light->extra_colormap; rlight->extra_colormap = light->extra_colormap;
rlight->flags = light->flags; rlight->flags = light->flags;
@ -484,6 +488,14 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2)
{ {
rw_scalestep = ds->scalestep; rw_scalestep = ds->scalestep;
spryscale = ds->scale1 + (x1 - ds->x1)*rw_scalestep; spryscale = ds->scale1 + (x1 - ds->x1)*rw_scalestep;
if (dc_numlights)
{ // reset all lights to their starting heights
for (i = 0; i < dc_numlights; i++)
{
rlight = &dc_lightlist[i];
rlight->height = rlight->startheight;
}
}
} }
#ifndef ESLOPE #ifndef ESLOPE
@ -694,10 +706,13 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2)
// Loop through R_DrawMaskedColumn calls // Loop through R_DrawMaskedColumn calls
static void R_DrawRepeatMaskedColumn(column_t *col) static void R_DrawRepeatMaskedColumn(column_t *col)
{ {
do { while (sprtopscreen < sprbotscreen) {
R_DrawMaskedColumn(col); R_DrawMaskedColumn(col);
sprtopscreen += dc_texheight*spryscale; if ((INT64)sprtopscreen + dc_texheight*spryscale > (INT64)INT32_MAX) // prevent overflow
} while (sprtopscreen < sprbotscreen); sprtopscreen = INT32_MAX;
else
sprtopscreen += dc_texheight*spryscale;
}
} }
// //
@ -740,7 +755,7 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
curline = ds->curline; curline = ds->curline;
backsector = pfloor->target; backsector = pfloor->target;
frontsector = curline->frontsector == pfloor->target ? curline->backsector : curline->frontsector; frontsector = curline->frontsector == pfloor->target ? curline->backsector : curline->frontsector;
texnum = texturetranslation[sides[pfloor->master->sidenum[0]].midtexture]; texnum = R_GetTextureNum(sides[pfloor->master->sidenum[0]].midtexture);
colfunc = wallcolfunc; colfunc = wallcolfunc;
@ -748,7 +763,7 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
{ {
size_t linenum = curline->linedef-backsector->lines[0]; size_t linenum = curline->linedef-backsector->lines[0];
newline = pfloor->master->frontsector->lines[0] + linenum; newline = pfloor->master->frontsector->lines[0] + linenum;
texnum = texturetranslation[sides[newline->sidenum[0]].midtexture]; texnum = R_GetTextureNum(sides[newline->sidenum[0]].midtexture);
} }
if (pfloor->flags & FF_TRANSLUCENT) if (pfloor->flags & FF_TRANSLUCENT)
@ -968,6 +983,9 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
dc_texturemid += offsetvalue; dc_texturemid += offsetvalue;
// Texture must be cached before setting colfunc_2s,
// otherwise texture[texnum]->holes may be false when it shouldn't be
R_CheckTextureCache(texnum);
//faB: handle case where multipatch texture is drawn on a 2sided wall, multi-patch textures //faB: handle case where multipatch texture is drawn on a 2sided wall, multi-patch textures
// are not stored per-column with post info anymore in Doom Legacy // are not stored per-column with post info anymore in Doom Legacy
if (textures[texnum]->holes) if (textures[texnum]->holes)
@ -1878,14 +1896,16 @@ void R_StoreWallRange(INT32 start, INT32 stop)
if (!backsector) if (!backsector)
{ {
fixed_t texheight;
// single sided line // single sided line
midtexture = texturetranslation[sidedef->midtexture]; midtexture = R_GetTextureNum(sidedef->midtexture);
texheight = textureheight[midtexture];
// a single sided line is terminal, so it must mark ends // a single sided line is terminal, so it must mark ends
markfloor = markceiling = true; markfloor = markceiling = true;
#ifdef ESLOPE #ifdef ESLOPE
if (linedef->flags & ML_EFFECT2) { if (linedef->flags & ML_EFFECT2) {
if (linedef->flags & ML_DONTPEGBOTTOM) if (linedef->flags & ML_DONTPEGBOTTOM)
rw_midtexturemid = frontsector->floorheight + textureheight[sidedef->midtexture] - viewz; rw_midtexturemid = frontsector->floorheight + texheight - viewz;
else else
rw_midtexturemid = frontsector->ceilingheight - viewz; rw_midtexturemid = frontsector->ceilingheight - viewz;
} }
@ -1894,10 +1914,10 @@ void R_StoreWallRange(INT32 start, INT32 stop)
if (linedef->flags & ML_DONTPEGBOTTOM) if (linedef->flags & ML_DONTPEGBOTTOM)
{ {
#ifdef ESLOPE #ifdef ESLOPE
rw_midtexturemid = worldbottom + textureheight[sidedef->midtexture]; rw_midtexturemid = worldbottom + texheight;
rw_midtextureslide = floorfrontslide; rw_midtextureslide = floorfrontslide;
#else #else
vtop = frontsector->floorheight + textureheight[sidedef->midtexture]; vtop = frontsector->floorheight + texheight;
// bottom of texture at bottom // bottom of texture at bottom
rw_midtexturemid = vtop - viewz; rw_midtexturemid = vtop - viewz;
#endif #endif
@ -2129,76 +2149,50 @@ void R_StoreWallRange(INT32 start, INT32 stop)
#endif #endif
) )
{ {
fixed_t texheight;
// top texture // top texture
if ((linedef->flags & (ML_DONTPEGTOP) && (linedef->flags & ML_DONTPEGBOTTOM)) if ((linedef->flags & (ML_DONTPEGTOP) && (linedef->flags & ML_DONTPEGBOTTOM))
&& linedef->sidenum[1] != 0xffff) && linedef->sidenum[1] != 0xffff)
{ {
// Special case... use offsets from 2nd side but only if it has a texture. // Special case... use offsets from 2nd side but only if it has a texture.
side_t *def = &sides[linedef->sidenum[1]]; side_t *def = &sides[linedef->sidenum[1]];
toptexture = texturetranslation[def->toptexture]; toptexture = R_GetTextureNum(def->toptexture);
if (!toptexture) //Second side has no texture, use the first side's instead. if (!toptexture) //Second side has no texture, use the first side's instead.
toptexture = texturetranslation[sidedef->toptexture]; toptexture = R_GetTextureNum(sidedef->toptexture);
texheight = textureheight[toptexture];
#ifdef ESLOPE
if (!(linedef->flags & ML_EFFECT1)) { // Ignore slopes for lower/upper textures unless flag is checked
if (linedef->flags & ML_DONTPEGTOP)
rw_toptexturemid = frontsector->ceilingheight - viewz;
else
rw_toptexturemid = backsector->ceilingheight - viewz;
} else
#endif
if (linedef->flags & ML_DONTPEGTOP)
{
// top of texture at top
rw_toptexturemid = worldtop;
#ifdef ESLOPE
rw_toptextureslide = ceilingfrontslide;
#endif
}
else
{
#ifdef ESLOPE
rw_toptexturemid = worldhigh + textureheight[def->toptexture];
rw_toptextureslide = ceilingbackslide;
#else
vtop = backsector->ceilingheight + textureheight[def->toptexture];
// bottom of texture
rw_toptexturemid = vtop - viewz;
#endif
}
} }
else else
{ {
toptexture = texturetranslation[sidedef->toptexture]; toptexture = R_GetTextureNum(sidedef->toptexture);
texheight = textureheight[toptexture];
}
#ifdef ESLOPE #ifdef ESLOPE
if (!(linedef->flags & ML_EFFECT1)) { // Ignore slopes for lower/upper textures unless flag is checked if (!(linedef->flags & ML_EFFECT1)) { // Ignore slopes for lower/upper textures unless flag is checked
if (linedef->flags & ML_DONTPEGTOP)
rw_toptexturemid = frontsector->ceilingheight - viewz;
else
rw_toptexturemid = backsector->ceilingheight - viewz;
} else
#endif
if (linedef->flags & ML_DONTPEGTOP) if (linedef->flags & ML_DONTPEGTOP)
{ rw_toptexturemid = frontsector->ceilingheight - viewz;
// top of texture at top
rw_toptexturemid = worldtop;
#ifdef ESLOPE
rw_toptextureslide = ceilingfrontslide;
#endif
}
else else
{ rw_toptexturemid = backsector->ceilingheight - viewz;
#ifdef ESLOPE } else
rw_toptexturemid = worldhigh + textureheight[sidedef->toptexture]; #endif
rw_toptextureslide = ceilingbackslide; if (linedef->flags & ML_DONTPEGTOP)
#else {
vtop = backsector->ceilingheight + textureheight[sidedef->toptexture]; // top of texture at top
// bottom of texture rw_toptexturemid = worldtop;
rw_toptexturemid = vtop - viewz; #ifdef ESLOPE
rw_toptextureslide = ceilingfrontslide;
#endif
}
else
{
#ifdef ESLOPE
rw_toptexturemid = worldhigh + texheight;
rw_toptextureslide = ceilingbackslide;
#else
vtop = backsector->ceilingheight + texheight;
// bottom of texture
rw_toptexturemid = vtop - viewz;
#endif #endif
}
} }
} }
// check BOTTOM TEXTURE // check BOTTOM TEXTURE
@ -2209,7 +2203,7 @@ void R_StoreWallRange(INT32 start, INT32 stop)
) //seulement si VISIBLE!!! ) //seulement si VISIBLE!!!
{ {
// bottom texture // bottom texture
bottomtexture = texturetranslation[sidedef->bottomtexture]; bottomtexture = R_GetTextureNum(sidedef->bottomtexture);
#ifdef ESLOPE #ifdef ESLOPE
if (!(linedef->flags & ML_EFFECT1)) { // Ignore slopes for lower/upper textures unless flag is checked if (!(linedef->flags & ML_EFFECT1)) { // Ignore slopes for lower/upper textures unless flag is checked
@ -2494,7 +2488,7 @@ void R_StoreWallRange(INT32 start, INT32 stop)
ds_p->numthicksides = numthicksides = i; ds_p->numthicksides = numthicksides = i;
} }
if (sidedef->midtexture) if (sidedef->midtexture > 0 && sidedef->midtexture < numtextures)
{ {
// masked midtexture // masked midtexture
if (!ds_p->thicksidecol) if (!ds_p->thicksidecol)
@ -3101,12 +3095,12 @@ void R_StoreWallRange(INT32 start, INT32 stop)
if (maskedtexture && !(ds_p->silhouette & SIL_TOP)) if (maskedtexture && !(ds_p->silhouette & SIL_TOP))
{ {
ds_p->silhouette |= SIL_TOP; ds_p->silhouette |= SIL_TOP;
ds_p->tsilheight = sidedef->midtexture ? INT32_MIN: INT32_MAX; ds_p->tsilheight = (sidedef->midtexture > 0 && sidedef->midtexture < numtextures) ? INT32_MIN: INT32_MAX;
} }
if (maskedtexture && !(ds_p->silhouette & SIL_BOTTOM)) if (maskedtexture && !(ds_p->silhouette & SIL_BOTTOM))
{ {
ds_p->silhouette |= SIL_BOTTOM; ds_p->silhouette |= SIL_BOTTOM;
ds_p->bsilheight = sidedef->midtexture ? INT32_MAX: INT32_MIN; ds_p->bsilheight = (sidedef->midtexture > 0 && sidedef->midtexture < numtextures) ? INT32_MAX: INT32_MIN;
} }
ds_p++; ds_p++;
} }

View File

@ -891,12 +891,18 @@ static void R_DrawPrecipitationVisSprite(vissprite_t *vis)
#endif #endif
fixed_t frac; fixed_t frac;
patch_t *patch; patch_t *patch;
INT64 overflow_test;
//Fab : R_InitSprites now sets a wad lump number //Fab : R_InitSprites now sets a wad lump number
patch = W_CacheLumpNum(vis->patch, PU_CACHE); patch = W_CacheLumpNum(vis->patch, PU_CACHE);
if (!patch) if (!patch)
return; return;
// Check for overflow
overflow_test = (INT64)centeryfrac - (((INT64)vis->texturemid*vis->scale)>>FRACBITS);
if (overflow_test < 0) overflow_test = -overflow_test;
if ((UINT64)overflow_test&0xFFFFFFFF80000000ULL) return; // fixed point mult would overflow
if (vis->transmap) if (vis->transmap)
{ {
colfunc = fuzzcolfunc; colfunc = fuzzcolfunc;
@ -1699,21 +1705,25 @@ static void R_CreateDrawNodes(void)
entry->ffloor = ds->thicksides[i]; entry->ffloor = ds->thicksides[i];
} }
} }
#ifdef POLYOBJECTS_PLANES
// Check for a polyobject plane, but only if this is a front line
if (ds->curline->polyseg && ds->curline->polyseg->visplane && !ds->curline->side) {
plane = ds->curline->polyseg->visplane;
R_PlaneBounds(plane);
if (plane->low < con_clipviewtop || plane->high > vid.height || plane->high > plane->low)
;
else {
// Put it in!
entry = R_CreateDrawNode(&nodehead);
entry->plane = plane;
entry->seg = ds;
}
ds->curline->polyseg->visplane = NULL;
}
#endif
if (ds->maskedtexturecol) if (ds->maskedtexturecol)
{ {
#ifdef POLYOBJECTS_PLANES
// Check for a polyobject plane, but only if this is a front line
if (ds->curline->polyseg && ds->curline->polyseg->visplane && !ds->curline->side) {
// Put it in!
entry = R_CreateDrawNode(&nodehead);
entry->plane = ds->curline->polyseg->visplane;
entry->seg = ds;
ds->curline->polyseg->visplane->polyobj = ds->curline->polyseg;
ds->curline->polyseg->visplane = NULL;
}
#endif
entry = R_CreateDrawNode(&nodehead); entry = R_CreateDrawNode(&nodehead);
entry->seg = ds; entry->seg = ds;
} }
@ -1756,6 +1766,29 @@ static void R_CreateDrawNodes(void)
} }
} }
#ifdef POLYOBJECTS_PLANES
// find all the remaining polyobject planes and add them on the end of the list
// probably this is a terrible idea if we wanted them to be sorted properly
// but it works getting them in for now
for (i = 0; i < numPolyObjects; i++)
{
if (!PolyObjects[i].visplane)
continue;
plane = PolyObjects[i].visplane;
R_PlaneBounds(plane);
if (plane->low < con_clipviewtop || plane->high > vid.height || plane->high > plane->low)
{
PolyObjects[i].visplane = NULL;
continue;
}
entry = R_CreateDrawNode(&nodehead);
entry->plane = plane;
// note: no seg is set, for what should be obvious reasons
PolyObjects[i].visplane = NULL;
}
#endif
if (visspritecount == 0) if (visspritecount == 0)
return; return;
@ -1812,13 +1845,16 @@ static void R_CreateDrawNodes(void)
if (x1 < r2->plane->minx) x1 = r2->plane->minx; if (x1 < r2->plane->minx) x1 = r2->plane->minx;
if (x2 > r2->plane->maxx) x2 = r2->plane->maxx; if (x2 > r2->plane->maxx) x2 = r2->plane->maxx;
for (i = x1; i <= x2; i++) if (r2->seg) // if no seg set, assume the whole thing is in front or something stupid
{ {
if (r2->seg->frontscale[i] > rover->scale) for (i = x1; i <= x2; i++)
break; {
if (r2->seg->frontscale[i] > rover->scale)
break;
}
if (i > x2)
continue;
} }
if (i > x2)
continue;
entry = R_CreateDrawNode(NULL); entry = R_CreateDrawNode(NULL);
(entry->prev = r2->prev)->next = entry; (entry->prev = r2->prev)->next = entry;

View File

@ -30,7 +30,7 @@
#include "f_finale.h" #include "f_finale.h"
#if defined (USEASM) //&& (!defined (_MSC_VER) || (_MSC_VER <= 1200)) #if defined (USEASM) && !defined (NORUSEASM)//&& (!defined (_MSC_VER) || (_MSC_VER <= 1200))
#define RUSEASM //MSC.NET can't patch itself #define RUSEASM //MSC.NET can't patch itself
#endif #endif

View File

@ -1214,7 +1214,7 @@
C01FCF4B08A954540054247B /* Debug */ = { C01FCF4B08A954540054247B /* Debug */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
CURRENT_PROJECT_VERSION = 2.1.14; CURRENT_PROJECT_VERSION = 2.1.17;
GCC_PREPROCESSOR_DEFINITIONS = ( GCC_PREPROCESSOR_DEFINITIONS = (
"$(inherited)", "$(inherited)",
NORMALSRB2, NORMALSRB2,
@ -1226,7 +1226,7 @@
C01FCF4C08A954540054247B /* Release */ = { C01FCF4C08A954540054247B /* Release */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
CURRENT_PROJECT_VERSION = 2.1.14; CURRENT_PROJECT_VERSION = 2.1.17;
GCC_ENABLE_FIX_AND_CONTINUE = NO; GCC_ENABLE_FIX_AND_CONTINUE = NO;
GCC_GENERATE_DEBUGGING_SYMBOLS = NO; GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
GCC_PREPROCESSOR_DEFINITIONS = ( GCC_PREPROCESSOR_DEFINITIONS = (

View File

@ -1214,7 +1214,7 @@
C01FCF4B08A954540054247B /* Debug */ = { C01FCF4B08A954540054247B /* Debug */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
CURRENT_PROJECT_VERSION = 2.1.14; CURRENT_PROJECT_VERSION = 2.1.17;
GCC_PREPROCESSOR_DEFINITIONS = ( GCC_PREPROCESSOR_DEFINITIONS = (
"$(inherited)", "$(inherited)",
NORMALSRB2, NORMALSRB2,
@ -1226,7 +1226,7 @@
C01FCF4C08A954540054247B /* Release */ = { C01FCF4C08A954540054247B /* Release */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
CURRENT_PROJECT_VERSION = 2.1.14; CURRENT_PROJECT_VERSION = 2.1.17;
GCC_ENABLE_FIX_AND_CONTINUE = NO; GCC_ENABLE_FIX_AND_CONTINUE = NO;
GCC_GENERATE_DEBUGGING_SYMBOLS = NO; GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
GCC_PREPROCESSOR_DEFINITIONS = ( GCC_PREPROCESSOR_DEFINITIONS = (

View File

@ -267,7 +267,7 @@ static void CV_Gammaxxx_ONChange(void)
#endif #endif
#if defined (__GNUC__) && defined (__i386__) && !defined (NOASM) && !defined (__APPLE__) #if defined (__GNUC__) && defined (__i386__) && !defined (NOASM) && !defined (__APPLE__) && !defined (NORUSEASM)
void VID_BlitLinearScreen_ASM(const UINT8 *srcptr, UINT8 *destptr, INT32 width, INT32 height, size_t srcrowbytes, void VID_BlitLinearScreen_ASM(const UINT8 *srcptr, UINT8 *destptr, INT32 width, INT32 height, size_t srcrowbytes,
size_t destrowbytes); size_t destrowbytes);
#define HAVE_VIDCOPY #define HAVE_VIDCOPY

View File

@ -1223,6 +1223,7 @@ int W_VerifyNMUSlumps(const char *filename)
{"COLORMAP", 8}, {"COLORMAP", 8},
{"PAL", 3}, {"PAL", 3},
{"CLM", 3}, {"CLM", 3},
{"TRANS", 5},
{NULL, 0}, {NULL, 0},
}; };
return W_VerifyFile(filename, NMUSlist, false); return W_VerifyFile(filename, NMUSlist, false);

View File

@ -20,7 +20,9 @@
#include <tchar.h> #include <tchar.h>
#ifndef HAVE_SDL
#include "win_main.h" #include "win_main.h"
#endif
#include "../doomdef.h" //just for VERSION #include "../doomdef.h" //just for VERSION
#include "win_dbg.h" #include "win_dbg.h"
#include "../m_argv.h" //print the parameter in the log #include "../m_argv.h" //print the parameter in the log

View File

@ -69,7 +69,7 @@ static HCURSOR windowCursor = NULL; // main window cursor
static LPCSTR wClassName = "SRB2WC"; static LPCSTR wClassName = "SRB2WC";
boolean appActive = false; // app window is active INT appActive = false; // app window is active
#ifdef LOGMESSAGES #ifdef LOGMESSAGES
FILE *logstream; FILE *logstream;

View File

@ -23,7 +23,7 @@
extern HWND hWndMain; extern HWND hWndMain;
extern boolean appActive; extern INT appActive;
VOID I_GetSysMouseEvents(INT mouse_state); VOID I_GetSysMouseEvents(INT mouse_state);
extern UINT MSHWheelMessage; extern UINT MSHWheelMessage;