Merge branch 'master' into lua-spritedefs

This commit is contained in:
Monster Iestyn 2017-07-09 15:05:18 +01:00
commit 3d2fd5d5a4
38 changed files with 991 additions and 829 deletions

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.18 VERSION 2.1.19
LANGUAGES C) LANGUAGES C)
if(${PROJECT_SOURCE_DIR} MATCHES ${PROJECT_BINARY_DIR}) if(${PROJECT_SOURCE_DIR} MATCHES ${PROJECT_BINARY_DIR})

View file

@ -1,4 +1,4 @@
version: 2.1.18.{branch}-{build} version: 2.1.19.{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 GCC63=1 CCACHE=1 - set SRB2_MFLAGS=-C src MINGW=1 WARNINGMODE=1 GCC63=1 CCACHE=1 NOOBJDUMP=1
build_script: build_script:
- cmd: mingw32-make.exe %SRB2_MFLAGS% %CONFIGURATION%=1 clean - cmd: mingw32-make.exe %SRB2_MFLAGS% %CONFIGURATION%=1 clean
@ -58,26 +58,29 @@ after_build:
- cmd: git rev-parse --short %APPVEYOR_REPO_COMMIT%>%TMP%/gitshort.txt - cmd: git rev-parse --short %APPVEYOR_REPO_COMMIT%>%TMP%/gitshort.txt
- cmd: set /P GITSHORT=<%TMP%/gitshort.txt - cmd: set /P GITSHORT=<%TMP%/gitshort.txt
- set BUILD_ARCHIVE=%APPVEYOR_REPO_BRANCH%-%GITSHORT%-%CONFIGURATION%.7z - set BUILD_ARCHIVE=%APPVEYOR_REPO_BRANCH%-%GITSHORT%-%CONFIGURATION%.7z
- set BUILDSARCHIVE=%APPVEYOR_REPO_BRANCH%-%CONFIGURATION%.7z
- cmd: 7z a %BUILD_ARCHIVE% bin\Mingw\Release -xr!.gitignore - cmd: 7z a %BUILD_ARCHIVE% bin\Mingw\Release -xr!.gitignore
- appveyor PushArtifact %BUILD_ARCHIVE% - appveyor PushArtifact %BUILD_ARCHIVE%
- cmd: copy %BUILD_ARCHIVE% %BUILDSARCHIVE%
- appveyor PushArtifact %BUILDSARCHIVE%
test: off test: off
deploy: #deploy:
- provider: FTP # - provider: FTP
protocol: ftps # protocol: ftps
host: # host:
secure: NsLJEPIBvmwCOj8Tg8RoRQ== # secure: NsLJEPIBvmwCOj8Tg8RoRQ==
username: # username:
secure: ejxi5mvk7oLYu7QtbYojajEPigMy0mokaKhuEVuDZcA= # secure: ejxi5mvk7oLYu7QtbYojajEPigMy0mokaKhuEVuDZcA=
password: # password:
secure: Hbn6Uy3lT0YZ88yFJ3aW4w== # secure: Hbn6Uy3lT0YZ88yFJ3aW4w==
folder: appveyor # folder: appveyor
application: # application:
active_mode: false # active_mode: false
on: # on:
branch: master # branch: master
appveyor_repo_tag: true # appveyor_repo_tag: true
on_finish: on_finish:

View file

@ -511,13 +511,11 @@ OBJS:=$(i_main_o) \
# For reference, this is the command I use to build a srb2.pot file from the source code. # For reference, this is the command I use to build a srb2.pot file from the source code.
# (The listed source files are the ones containing translated strings). # (The listed source files are the ones containing translated strings).
# FILES=""; for file in `find ./ | grep "\.c" | grep -v svn`; do [ "`grep "M_GetText(" $file`" ] && FILES="$FILES $file"; done; xgettext -d srb2 -o locale/srb2.pot -kM_GetText -F --no-wrap $FILES # FILES=""; for file in `find ./ | grep "\.c" | grep -v svn`; do [ "`grep "M_GetText(" $file`" ] && FILES="$FILES $file"; done; xgettext -d srb2 -o locale/srb2.pot -kM_GetText -F --no-wrap $FILES
ifndef NOGETTEXT
ifdef GETTEXT ifdef GETTEXT
POS:=$(BIN)/en.mo POS:=$(BIN)/en.mo
OPTS+=-DGETTEXT OPTS+=-DGETTEXT
endif endif
endif
ifdef DJGPPDOS ifdef DJGPPDOS
all: pre-build $(BIN)/$(EXENAME) all: pre-build $(BIN)/$(EXENAME)

View file

@ -283,9 +283,6 @@ else
ifdef LINUX ifdef LINUX
NASMFORMAT=elf -DLINUX NASMFORMAT=elf -DLINUX
SDL=1 SDL=1
ifndef NOGETTEXT
GETTEXT=1
endif
ifdef LINUX64 ifdef LINUX64
OBJDIR:=$(OBJDIR)/Linux64 OBJDIR:=$(OBJDIR)/Linux64
BIN:=$(BIN)/Linux64 BIN:=$(BIN)/Linux64
@ -321,9 +318,6 @@ else
ifdef MINGW64 ifdef MINGW64
INTERFACE=win32 INTERFACE=win32
#NASMFORMAT=win64 #NASMFORMAT=win64
ifndef NOGETTEXT
#GETTEXT=1
endif
OBJDIR:=$(OBJDIR)/Mingw64 OBJDIR:=$(OBJDIR)/Mingw64
BIN:=$(BIN)/Mingw64 BIN:=$(BIN)/Mingw64
else else
@ -354,9 +348,6 @@ else
ifdef MINGW ifdef MINGW
INTERFACE=win32 INTERFACE=win32
NASMFORMAT=win32 NASMFORMAT=win32
ifndef NOGETTEXT
GETTEXT=1
endif
OBJDIR:=$(OBJDIR)/Mingw OBJDIR:=$(OBJDIR)/Mingw
BIN:=$(BIN)/Mingw BIN:=$(BIN)/Mingw
else else

View file

@ -1740,9 +1740,7 @@ static boolean CL_ServerConnectionSearchTicker(boolean viams, tic_t *asksent)
{ {
#ifndef NONET #ifndef NONET
INT32 i; INT32 i;
#endif
#ifndef NONET
// serverlist is updated by GetPacket function // serverlist is updated by GetPacket function
if (serverlistcount > 0) if (serverlistcount > 0)
{ {
@ -1776,7 +1774,20 @@ static boolean CL_ServerConnectionSearchTicker(boolean viams, tic_t *asksent)
serverlist[i].info.fileneeded); serverlist[i].info.fileneeded);
CONS_Printf(M_GetText("Checking files...\n")); CONS_Printf(M_GetText("Checking files...\n"));
i = CL_CheckFiles(); i = CL_CheckFiles();
if (i == 2) // cannot join for some reason if (i == 3) // too many files
{
D_QuitNetGame();
CL_Reset();
D_StartTitle();
M_StartMessage(M_GetText(
"You have too many WAD files loaded\n"
"to add ones the server is using.\n"
"Please restart SRB2 before connecting.\n\n"
"Press ESC\n"
), NULL, MM_NOTHING);
return false;
}
else if (i == 2) // cannot join for some reason
{ {
D_QuitNetGame(); D_QuitNetGame();
CL_Reset(); CL_Reset();
@ -2516,12 +2527,18 @@ static void Command_Nodes(void)
static void Command_Ban(void) static void Command_Ban(void)
{ {
if (COM_Argc() == 1) if (COM_Argc() < 2)
{ {
CONS_Printf(M_GetText("Ban <playername/playernum> <reason>: ban and kick a player\n")); CONS_Printf(M_GetText("Ban <playername/playernum> <reason>: ban and kick a player\n"));
return; return;
} }
if (!netgame) // Don't kick Tails in splitscreen!
{
CONS_Printf(M_GetText("This only works in a netgame.\n"));
return;
}
if (server || adminplayer == consoleplayer) if (server || adminplayer == consoleplayer)
{ {
XBOXSTATIC UINT8 buf[3 + MAX_REASONLENGTH]; XBOXSTATIC UINT8 buf[3 + MAX_REASONLENGTH];
@ -2531,8 +2548,9 @@ static void Command_Ban(void)
if (pn == -1 || pn == 0) if (pn == -1 || pn == 0)
return; return;
else
WRITEUINT8(p, pn); WRITEUINT8(p, pn);
if (server && I_Ban && !I_Ban(node)) // only the server is allowed to do this right now if (server && I_Ban && !I_Ban(node)) // only the server is allowed to do this right now
{ {
CONS_Alert(CONS_WARNING, M_GetText("Too many bans! Geez, that's a lot of people you're excluding...\n")); CONS_Alert(CONS_WARNING, M_GetText("Too many bans! Geez, that's a lot of people you're excluding...\n"));
@ -2575,21 +2593,27 @@ static void Command_Ban(void)
static void Command_Kick(void) static void Command_Kick(void)
{ {
XBOXSTATIC UINT8 buf[3 + MAX_REASONLENGTH]; if (COM_Argc() < 2)
UINT8 *p = buf;
if (COM_Argc() == 1)
{ {
CONS_Printf(M_GetText("kick <playername/playernum> <reason>: kick a player\n")); CONS_Printf(M_GetText("kick <playername/playernum> <reason>: kick a player\n"));
return; return;
} }
if (!netgame) // Don't kick Tails in splitscreen!
{
CONS_Printf(M_GetText("This only works in a netgame.\n"));
return;
}
if (server || adminplayer == consoleplayer) if (server || adminplayer == consoleplayer)
{ {
XBOXSTATIC UINT8 buf[3 + MAX_REASONLENGTH];
UINT8 *p = buf;
const SINT8 pn = nametonum(COM_Argv(1)); const SINT8 pn = nametonum(COM_Argv(1));
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: // 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 // trigger a timeout instead of kicking them, because a kick would only
// take effect after they have finished downloading // take effect after they have finished downloading
@ -2598,6 +2622,9 @@ static void Command_Kick(void)
Net_ConnectionTimeout(playernode[pn]); Net_ConnectionTimeout(playernode[pn]);
return; return;
} }
WRITESINT8(p, pn);
if (COM_Argc() == 2) if (COM_Argc() == 2)
{ {
WRITEUINT8(p, KICK_MSG_GO_AWAY); WRITEUINT8(p, KICK_MSG_GO_AWAY);
@ -3404,17 +3431,42 @@ static void HandlePacketFromAwayNode(SINT8 node)
if (node != servernode) if (node != servernode)
DEBFILE(va("Received packet from unknown host %d\n", node)); DEBFILE(va("Received packet from unknown host %d\n", node));
// macro for packets that should only be sent by the server
// if it is NOT from the server, bail out and close the connection!
#define SERVERONLY \
if (node != servernode) \
{ \
Net_CloseConnection(node); \
break; \
}
switch (netbuffer->packettype) switch (netbuffer->packettype)
{ {
case PT_ASKINFOVIAMS: case PT_ASKINFOVIAMS:
#if 0
if (server && serverrunning) if (server && serverrunning)
{ {
INT32 clientnode = I_NetMakeNode(netbuffer->u.msaskinfo.clientaddr); INT32 clientnode;
if (ms_RoomId < 0) // ignore if we're not actually on the MS right now
{
Net_CloseConnection(node); // and yes, close connection
return;
}
clientnode = I_NetMakeNode(netbuffer->u.msaskinfo.clientaddr);
if (clientnode != -1)
{
SV_SendServerInfo(clientnode, (tic_t)LONG(netbuffer->u.msaskinfo.time)); SV_SendServerInfo(clientnode, (tic_t)LONG(netbuffer->u.msaskinfo.time));
SV_SendPlayerInfo(clientnode); // Send extra info SV_SendPlayerInfo(clientnode); // Send extra info
Net_CloseConnection(clientnode); Net_CloseConnection(clientnode);
// Don't close connection to MS. // Don't close connection to MS...
} }
else
Net_CloseConnection(node); // ...unless the IP address is not valid
}
else
Net_CloseConnection(node); // you're not supposed to get it, so ignore it
#else
Net_CloseConnection(node);
#endif
break; break;
case PT_ASKINFO: case PT_ASKINFO:
@ -3422,8 +3474,8 @@ static void HandlePacketFromAwayNode(SINT8 node)
{ {
SV_SendServerInfo(node, (tic_t)LONG(netbuffer->u.askinfo.time)); SV_SendServerInfo(node, (tic_t)LONG(netbuffer->u.askinfo.time));
SV_SendPlayerInfo(node); // Send extra info SV_SendPlayerInfo(node); // Send extra info
Net_CloseConnection(node);
} }
Net_CloseConnection(node);
break; break;
case PT_SERVERREFUSE: // Negative response of client join request case PT_SERVERREFUSE: // Negative response of client join request
@ -3432,6 +3484,7 @@ static void HandlePacketFromAwayNode(SINT8 node)
Net_CloseConnection(node); Net_CloseConnection(node);
break; break;
} }
SERVERONLY
if (cl_mode == CL_WAITJOINRESPONSE) if (cl_mode == CL_WAITJOINRESPONSE)
{ {
// Save the reason so it can be displayed after quitting the netgame // Save the reason so it can be displayed after quitting the netgame
@ -3463,6 +3516,7 @@ static void HandlePacketFromAwayNode(SINT8 node)
Net_CloseConnection(node); Net_CloseConnection(node);
break; break;
} }
SERVERONLY
/// \note how would this happen? and is it doing the right thing if it does? /// \note how would this happen? and is it doing the right thing if it does?
if (cl_mode != CL_WAITJOINRESPONSE) if (cl_mode != CL_WAITJOINRESPONSE)
break; break;
@ -3528,13 +3582,18 @@ static void HandlePacketFromAwayNode(SINT8 node)
Net_CloseConnection(node); Net_CloseConnection(node);
break; break;
} }
else SERVERONLY
Got_Filetxpak(); Got_Filetxpak();
break; break;
case PT_REQUESTFILE: case PT_REQUESTFILE:
if (server) if (server)
Got_RequestFilePak(node); {
if (!cv_downloading.value || !Got_RequestFilePak(node))
Net_CloseConnection(node); // close connection if one of the requested files could not be sent, or you disabled downloading anyway
}
else
Net_CloseConnection(node); // nope
break; break;
case PT_NODETIMEOUT: case PT_NODETIMEOUT:
@ -3557,6 +3616,7 @@ static void HandlePacketFromAwayNode(SINT8 node)
break; // Ignore it break; // Ignore it
} }
#undef SERVERONLY
} }
/** Handles a packet received from a node that is in game /** Handles a packet received from a node that is in game
@ -3589,6 +3649,8 @@ FILESTAMP
{ {
// -------------------------------------------- SERVER RECEIVE ---------- // -------------------------------------------- SERVER RECEIVE ----------
case PT_RESYNCHGET: case PT_RESYNCHGET:
if (client)
break;
SV_AcknowledgeResynchAck(netconsole, netbuffer->u.resynchgot); SV_AcknowledgeResynchAck(netconsole, netbuffer->u.resynchgot);
break; break;
case PT_CLIENTCMD: case PT_CLIENTCMD:
@ -3655,7 +3717,8 @@ FILESTAMP
} }
// Splitscreen cmd // Splitscreen cmd
if (netbuffer->packettype == PT_CLIENT2CMD && nodetoplayer2[node] >= 0) if ((netbuffer->packettype == PT_CLIENT2CMD || netbuffer->packettype == PT_CLIENT2MIS)
&& nodetoplayer2[node] >= 0)
G_MoveTiccmd(&netcmds[maketic%BACKUPTICS][(UINT8)nodetoplayer2[node]], G_MoveTiccmd(&netcmds[maketic%BACKUPTICS][(UINT8)nodetoplayer2[node]],
&netbuffer->u.client2pak.cmd2, 1); &netbuffer->u.client2pak.cmd2, 1);
@ -3714,6 +3777,27 @@ FILESTAMP
tic_t tic = maketic; tic_t tic = maketic;
UINT8 *textcmd; UINT8 *textcmd;
// ignore if the textcmd has a reported size of zero
// this shouldn't be sent at all
if (!netbuffer->u.textcmd[0])
{
DEBFILE(va("GetPacket: Textcmd with size 0 detected! (node %u, player %d)\n",
node, netconsole));
Net_UnAcknowledgePacket(node);
break;
}
// ignore if the textcmd size var is actually larger than it should be
// BASEPACKETSIZE + 1 (for size) + textcmd[0] should == datalength
if (netbuffer->u.textcmd[0] > (size_t)doomcom->datalength-BASEPACKETSIZE-1)
{
DEBFILE(va("GetPacket: Bad Textcmd packet size! (expected %d, actual %s, node %u, player %d)\n",
netbuffer->u.textcmd[0], sizeu1((size_t)doomcom->datalength-BASEPACKETSIZE-1),
node, netconsole));
Net_UnAcknowledgePacket(node);
break;
}
// check if tic that we are making isn't too large else we cannot send it :( // check if tic that we are making isn't too large else we cannot send it :(
// doomcom->numslots+1 "+1" since doomcom->numslots can change within this time and sent time // doomcom->numslots+1 "+1" since doomcom->numslots can change within this time and sent time
j = software_MAXPACKETLENGTH j = software_MAXPACKETLENGTH
@ -3907,7 +3991,7 @@ FILESTAMP
if (client) if (client)
{ {
INT32 i; INT32 i;
for (i = 0; i < MAXNETNODES; i++) for (i = 0; i < MAXPLAYERS; i++)
if (playeringame[i]) if (playeringame[i])
playerpingtable[i] = (tic_t)netbuffer->u.pingtable[i]; playerpingtable[i] = (tic_t)netbuffer->u.pingtable[i];
} }
@ -3917,6 +4001,21 @@ FILESTAMP
case PT_SERVERCFG: case PT_SERVERCFG:
break; break;
case PT_FILEFRAGMENT: case PT_FILEFRAGMENT:
// Only accept PT_FILEFRAGMENT from the server.
if (node != servernode)
{
CONS_Alert(CONS_WARNING, M_GetText("%s received from non-host %d\n"), "PT_FILEFRAGMENT", node);
if (server)
{
XBOXSTATIC UINT8 buf[2];
buf[0] = (UINT8)node;
buf[1] = KICK_MSG_CON_FAIL;
SendNetXCmd(XD_KICK, &buf, 2);
}
break;
}
if (client) if (client)
Got_Filetxpak(); Got_Filetxpak();
break; break;
@ -4450,8 +4549,8 @@ static inline void PingUpdate(void)
} }
//send out our ping packets //send out our ping packets
for (i = 0; i < MAXPLAYERS; i++) for (i = 0; i < MAXNETNODES; i++)
if (playeringame[i]) if (nodeingame[i])
HSendPacket(i, true, 0, sizeof(INT32) * MAXPLAYERS); HSendPacket(i, true, 0, sizeof(INT32) * MAXPLAYERS);
pingmeasurecount = 1; //Reset count pingmeasurecount = 1; //Reset count
@ -4481,20 +4580,15 @@ void NetUpdate(void)
gametime = nowtime; gametime = nowtime;
if (!(gametime % 255) && netgame && server)
{
#ifdef NEWPING
PingUpdate();
#endif
}
#ifdef NEWPING #ifdef NEWPING
if (server) if (server)
{ {
if (netgame && !(gametime % 255))
PingUpdate();
// update node latency values so we can take an average later. // update node latency values so we can take an average later.
for (i = 0; i < MAXNETNODES; i++) for (i = 0; i < MAXPLAYERS; i++)
if (playeringame[i]) if (playeringame[i])
realpingtable[i] += G_TicsToMilliseconds(GetLag(i)); realpingtable[i] += G_TicsToMilliseconds(GetLag(playernode[i]));
pingmeasurecount++; pingmeasurecount++;
} }
#endif #endif

View file

@ -107,8 +107,6 @@ UINT8 window_notinfocus = false;
// //
// DEMO LOOP // DEMO LOOP
// //
//static INT32 demosequence;
static const char *pagename = "MAP1PIC";
static char *startupwadfiles[MAX_WADFILES]; static char *startupwadfiles[MAX_WADFILES];
boolean devparm = false; // started game with -devparm boolean devparm = false; // started game with -devparm
@ -721,7 +719,6 @@ void D_StartTitle(void)
gameaction = ga_nothing; gameaction = ga_nothing;
displayplayer = consoleplayer = 0; displayplayer = consoleplayer = 0;
//demosequence = -1;
gametype = GT_COOP; gametype = GT_COOP;
paused = false; paused = false;
advancedemo = false; advancedemo = false;
@ -886,27 +883,10 @@ static void IdentifyVersion(void)
#endif #endif
} }
/* ======================================================================== */
// Just print the nice red titlebar like the original SRB2 for DOS.
/* ======================================================================== */
#ifdef PC_DOS #ifdef PC_DOS
static inline void D_Titlebar(char *title1, char *title2) /* ======================================================================== */
{ // Code for printing SRB2's title bar in DOS
// SRB2 banner /* ======================================================================== */
clrscr();
textattr((BLUE<<4)+WHITE);
clreol();
cputs(title1);
// standard srb2 banner
textattr((RED<<4)+WHITE);
clreol();
gotoxy((80-strlen(title2))/2, 2);
cputs(title2);
normvideo();
gotoxy(1,3);
}
#endif
// //
// Center the title string, then add the date and time of compilation. // Center the title string, then add the date and time of compilation.
@ -935,6 +915,31 @@ static inline void D_MakeTitleString(char *s)
strcpy(s, temp); strcpy(s, temp);
} }
static inline void D_Titlebar(void)
{
char title1[82]; // srb2 title banner
char title2[82];
strcpy(title1, "Sonic Robo Blast 2");
strcpy(title2, "Sonic Robo Blast 2");
D_MakeTitleString(title1);
// SRB2 banner
clrscr();
textattr((BLUE<<4)+WHITE);
clreol();
cputs(title1);
// standard srb2 banner
textattr((RED<<4)+WHITE);
clreol();
gotoxy((80-strlen(title2))/2, 2);
cputs(title2);
normvideo();
gotoxy(1,3);
}
#endif
// //
// D_SRB2Main // D_SRB2Main
@ -942,8 +947,6 @@ static inline void D_MakeTitleString(char *s)
void D_SRB2Main(void) void D_SRB2Main(void)
{ {
INT32 p; INT32 p;
char srb2[82]; // srb2 title banner
char title[82];
INT32 pstartmap = 1; INT32 pstartmap = 1;
boolean autostart = false; boolean autostart = false;
@ -986,20 +989,8 @@ void D_SRB2Main(void)
dedicated = M_CheckParm("-dedicated") != 0; dedicated = M_CheckParm("-dedicated") != 0;
#endif #endif
strcpy(title, "Sonic Robo Blast 2");
strcpy(srb2, "Sonic Robo Blast 2");
D_MakeTitleString(srb2);
#ifdef PC_DOS #ifdef PC_DOS
D_Titlebar(srb2, title); D_Titlebar();
#endif
#if defined (__OS2__) && !defined (HAVE_SDL)
// set PM window title
snprintf(pmData->title, sizeof (pmData->title),
"Sonic Robo Blast 2" VERSIONSTRING ": %s",
title);
pmData->title[sizeof (pmData->title) - 1] = '\0';
#endif #endif
if (devparm) if (devparm)
@ -1399,7 +1390,6 @@ void D_SRB2Main(void)
if (dedicated && server) if (dedicated && server)
{ {
pagename = "TITLESKY";
levelstarttic = gametic; levelstarttic = gametic;
G_SetGamestate(GS_LEVEL); G_SetGamestate(GS_LEVEL);
if (!P_SetupLevel(false)) if (!P_SetupLevel(false))

View file

@ -713,6 +713,13 @@ void Net_CloseConnection(INT32 node)
#else #else
INT32 i; INT32 i;
boolean forceclose = (node & FORCECLOSE) != 0; boolean forceclose = (node & FORCECLOSE) != 0;
if (node == -1)
{
DEBFILE(M_GetText("Net_CloseConnection: node -1 detected!\n"));
return; // nope, just ignore it
}
node &= ~FORCECLOSE; node &= ~FORCECLOSE;
if (!node) if (!node)
@ -720,7 +727,7 @@ void Net_CloseConnection(INT32 node)
if (node < 0 || node >= MAXNETNODES) // prevent invalid nodes from crashing the game if (node < 0 || node >= MAXNETNODES) // prevent invalid nodes from crashing the game
{ {
CONS_Alert(CONS_WARNING, M_GetText("Net_CloseConnection: invalid node %d detected!\n"), node); DEBFILE(va(M_GetText("Net_CloseConnection: invalid node %d detected!\n"), node));
return; return;
} }

View file

@ -1609,8 +1609,13 @@ void D_MapChange(INT32 mapnum, INT32 newgametype, boolean pultmode, boolean rese
mapchangepending = 0; mapchangepending = 0;
// spawn the server if needed // spawn the server if needed
// reset players if there is a new one // reset players if there is a new one
if (!(adminplayer == consoleplayer) && SV_SpawnServer()) if (!(adminplayer == consoleplayer))
{
if (SV_SpawnServer())
buf[0] &= ~(1<<1); buf[0] &= ~(1<<1);
if (!Playing()) // you failed to start a server somehow, so cancel the map change
return;
}
// Kick bot from special stages // Kick bot from special stages
if (botskin) if (botskin)
@ -3116,7 +3121,13 @@ static void Got_RequestAddfilecmd(UINT8 **cp, INT32 playernum)
filestatus_t ncs = FS_NOTFOUND; filestatus_t ncs = FS_NOTFOUND;
UINT8 md5sum[16]; UINT8 md5sum[16];
boolean kick = false; boolean kick = false;
boolean toomany = false;
INT32 i; INT32 i;
size_t packetsize = 0;
serverinfo_pak *dummycheck = NULL;
// Shut the compiler up.
(void)dummycheck;
READSTRINGN(*cp, filename, 240); READSTRINGN(*cp, filename, 240);
READMEM(*cp, md5sum, 16); READMEM(*cp, md5sum, 16);
@ -3142,13 +3153,25 @@ static void Got_RequestAddfilecmd(UINT8 **cp, INT32 playernum)
return; return;
} }
// See W_LoadWadFile in w_wad.c
for (i = 0; i < numwadfiles; i++)
packetsize += nameonlylength(wadfiles[i]->filename) + 22;
packetsize += nameonlylength(filename) + 22;
if ((numwadfiles >= MAX_WADFILES)
|| (packetsize > sizeof(dummycheck->fileneeded)))
toomany = true;
else
ncs = findfile(filename,md5sum,true); ncs = findfile(filename,md5sum,true);
if (ncs != FS_FOUND) if (ncs != FS_FOUND || toomany)
{ {
char message[256]; char message[256];
if (ncs == FS_NOTFOUND) if (toomany)
sprintf(message, M_GetText("Too many files loaded to add %s\n"), filename);
else if (ncs == FS_NOTFOUND)
sprintf(message, M_GetText("The server doesn't have %s\n"), filename); sprintf(message, M_GetText("The server doesn't have %s\n"), filename);
else if (ncs == FS_MD5SUMBAD) else if (ncs == FS_MD5SUMBAD)
sprintf(message, M_GetText("Checksum mismatch on %s\n"), filename); sprintf(message, M_GetText("Checksum mismatch on %s\n"), filename);
@ -3218,10 +3241,15 @@ static void Got_Addfilecmd(UINT8 **cp, INT32 playernum)
ncs = findfile(filename,md5sum,true); ncs = findfile(filename,md5sum,true);
if (ncs != FS_FOUND) if (ncs != FS_FOUND || !P_AddWadFile(filename, NULL))
{ {
Command_ExitGame_f(); Command_ExitGame_f();
if (ncs == FS_NOTFOUND) if (ncs == FS_FOUND)
{
CONS_Printf(M_GetText("The server tried to add %s,\nbut you have too many files added.\nRestart the game to clear loaded files\nand play on this server."), filename);
M_StartMessage(va("The server added a file \n(%s)\nbut you have too many files added.\nRestart the game to clear loaded files.\n\nPress ESC\n",filename), NULL, MM_NOTHING);
}
else if (ncs == FS_NOTFOUND)
{ {
CONS_Printf(M_GetText("The server tried to add %s,\nbut you don't have this file.\nYou need to find it in order\nto play on this server."), filename); CONS_Printf(M_GetText("The server tried to add %s,\nbut you don't have this file.\nYou need to find it in order\nto play on this server."), filename);
M_StartMessage(va("The server added a file \n(%s)\nthat you do not have.\n\nPress ESC\n",filename), NULL, MM_NOTHING); M_StartMessage(va("The server added a file \n(%s)\nthat you do not have.\n\nPress ESC\n",filename), NULL, MM_NOTHING);
@ -3239,7 +3267,6 @@ static void Got_Addfilecmd(UINT8 **cp, INT32 playernum)
return; return;
} }
P_AddWadFile(filename, NULL);
G_SetGameModified(true); G_SetGameModified(true);
} }

View file

@ -62,7 +62,8 @@
#include <errno.h> #include <errno.h>
static void SV_SendFile(INT32 node, const char *filename, UINT8 fileid); // Prototypes
static boolean SV_SendFile(INT32 node, const char *filename, UINT8 fileid);
// Sender structure // Sender structure
typedef struct filetx_s typedef struct filetx_s
@ -303,7 +304,8 @@ boolean CL_SendRequestFile(void)
} }
// get request filepak and put it on the send queue // get request filepak and put it on the send queue
void Got_RequestFilePak(INT32 node) // returns false if a requested file was not found or cannot be sent
boolean Got_RequestFilePak(INT32 node)
{ {
char wad[MAX_WADPATH+1]; char wad[MAX_WADPATH+1];
UINT8 *p = netbuffer->u.textcmd; UINT8 *p = netbuffer->u.textcmd;
@ -314,9 +316,14 @@ void Got_RequestFilePak(INT32 node)
if (id == 0xFF) if (id == 0xFF)
break; break;
READSTRINGN(p, wad, MAX_WADPATH); READSTRINGN(p, wad, MAX_WADPATH);
SV_SendFile(node, wad, id); if (!SV_SendFile(node, wad, id))
{
SV_AbortSendFiles(node);
return false; // don't read the rest of the files
} }
} }
return true; // no problems with any files
}
/** Checks if the files needed aren't already loaded or on the disk /** Checks if the files needed aren't already loaded or on the disk
* *
@ -330,6 +337,12 @@ INT32 CL_CheckFiles(void)
INT32 i, j; INT32 i, j;
char wadfilename[MAX_WADPATH]; char wadfilename[MAX_WADPATH];
INT32 ret = 1; INT32 ret = 1;
size_t packetsize = 0;
size_t filestoget = 0;
serverinfo_pak *dummycheck = NULL;
// Shut the compiler up.
(void)dummycheck;
// if (M_CheckParm("-nofiles")) // if (M_CheckParm("-nofiles"))
// return 1; // return 1;
@ -378,6 +391,10 @@ INT32 CL_CheckFiles(void)
return 1; return 1;
} }
// See W_LoadWadFile in w_wad.c
for (i = 0; i < numwadfiles; i++)
packetsize += nameonlylength(wadfiles[i]->filename) + 22;
for (i = 1; i < fileneedednum; i++) for (i = 1; i < fileneedednum; i++)
{ {
CONS_Debug(DBG_NETPLAY, "searching for '%s' ", fileneeded[i].filename); CONS_Debug(DBG_NETPLAY, "searching for '%s' ", fileneeded[i].filename);
@ -397,6 +414,14 @@ INT32 CL_CheckFiles(void)
if (fileneeded[i].status != FS_NOTFOUND || !fileneeded[i].important) if (fileneeded[i].status != FS_NOTFOUND || !fileneeded[i].important)
continue; continue;
packetsize += nameonlylength(fileneeded[i].filename) + 22;
if ((numwadfiles+filestoget >= MAX_WADFILES)
|| (packetsize > sizeof(dummycheck->fileneeded)))
return 3;
filestoget++;
fileneeded[i].status = findfile(fileneeded[i].filename, fileneeded[i].md5sum, true); fileneeded[i].status = findfile(fileneeded[i].filename, fileneeded[i].md5sum, true);
CONS_Debug(DBG_NETPLAY, "found %d\n", fileneeded[i].status); CONS_Debug(DBG_NETPLAY, "found %d\n", fileneeded[i].status);
if (fileneeded[i].status != FS_FOUND) if (fileneeded[i].status != FS_FOUND)
@ -480,7 +505,7 @@ static INT32 filestosend = 0;
* \sa SV_SendRam * \sa SV_SendRam
* *
*/ */
static void SV_SendFile(INT32 node, const char *filename, UINT8 fileid) static boolean SV_SendFile(INT32 node, const char *filename, UINT8 fileid)
{ {
filetx_t **q; // A pointer to the "next" field of the last file in the list filetx_t **q; // A pointer to the "next" field of the last file in the list
filetx_t *p; // The new file request filetx_t *p; // The new file request
@ -488,7 +513,7 @@ static void SV_SendFile(INT32 node, const char *filename, UINT8 fileid)
char wadfilename[MAX_WADPATH]; char wadfilename[MAX_WADPATH];
if (cv_noticedownload.value) if (cv_noticedownload.value)
CONS_Printf("Sending file \"%s\" to node %d\n", filename, node); CONS_Printf("Sending file \"%s\" to node %d (%s)\n", filename, node, I_GetNodeAddress(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;
@ -537,7 +562,7 @@ static void SV_SendFile(INT32 node, const char *filename, UINT8 fileid)
free(p->id.filename); free(p->id.filename);
free(p); free(p);
*q = NULL; *q = NULL;
return; return false; // cancel the rest of the requests
} }
// Handle huge file requests (i.e. bigger than cv_maxsend.value KB) // Handle huge file requests (i.e. bigger than cv_maxsend.value KB)
@ -549,7 +574,7 @@ static void SV_SendFile(INT32 node, const char *filename, UINT8 fileid)
free(p->id.filename); free(p->id.filename);
free(p); free(p);
*q = NULL; *q = NULL;
return; return false; // cancel the rest of the requests
} }
DEBFILE(va("Sending file %s (id=%d) to %d\n", filename, fileid, node)); DEBFILE(va("Sending file %s (id=%d) to %d\n", filename, fileid, node));
@ -557,6 +582,7 @@ static void SV_SendFile(INT32 node, const char *filename, UINT8 fileid)
p->fileid = fileid; p->fileid = fileid;
p->next = NULL; // End of list p->next = NULL; // End of list
filestosend++; filestosend++;
return true;
} }
/** Adds a memory block to the file list for a node /** Adds a memory block to the file list for a node

View file

@ -69,7 +69,7 @@ boolean SV_SendingFile(INT32 node);
boolean CL_CheckDownloadable(void); boolean CL_CheckDownloadable(void);
boolean CL_SendRequestFile(void); boolean CL_SendRequestFile(void);
void Got_RequestFilePak(INT32 node); boolean Got_RequestFilePak(INT32 node);
void SV_AbortSendFiles(INT32 node); void SV_AbortSendFiles(INT32 node);
void CloseNetFile(void); void CloseNetFile(void);

View file

@ -382,56 +382,6 @@ static void clear_levels(void)
P_AllocMapHeader(gamemap-1); P_AllocMapHeader(gamemap-1);
} }
/*
// Edits an animated texture slot on the array
// Tails 12-27-2003
static void readAnimTex(MYFILE *f, INT32 num)
{
char s[MAXLINELEN];
char *word;
char *word2;
INT32 i;
do {
if (myfgets(s, sizeof s, f) != NULL)
{
if (s[0] == '\n') break;
tmp = strchr(s, '#');
if (tmp)
*tmp = '\0';
// set the value in the appropriate field
word = strtok(s, " ");
if (word)
strupr(word);
else
break;
word2 = strtok(NULL, " = ");
if (word2)
strupr(word2);
else
break;
if (word2[strlen(word2)-1] == '\n')
word2[strlen(word2)-1] = '\0';
i = atoi(word2);
if (fastcmp(word, "START"))
strncpy(harddefs[num].startname, word2, 8);
if (fastcmp(word, "END"))
strncpy(harddefs[num].endname, word2, 8);
else if (fastcmp(word, "SPEED")) harddefs[num].speed = i;
else if (fastcmp(word, "ISTEXTURE")) harddefs[num].istexture = i;
else deh_warning("readAnimTex %d: unknown word '%s'", num, word);
}
} while (s[0] != '\n' && !myfeof(f)); //finish when the line is empty
}
*/
static boolean findFreeSlot(INT32 *num) static boolean findFreeSlot(INT32 *num)
{ {
// Send the character select entry to a free slot. // Send the character select entry to a free slot.
@ -2106,7 +2056,7 @@ static void readframe(MYFILE *f, INT32 num)
Z_Free(s); Z_Free(s);
} }
static void readsound(MYFILE *f, INT32 num, const char *savesfxnames[]) static void readsound(MYFILE *f, INT32 num)
{ {
char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL); char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL);
char *word; char *word;
@ -2142,21 +2092,7 @@ static void readsound(MYFILE *f, INT32 num, const char *savesfxnames[])
continue; continue;
} }
/* if (fastcmp(word, "OFFSET")) if (fastcmp(word, "SINGULAR"))
{
value -= 150360;
if (value <= 64)
value /= 8;
else if (value <= 260)
value = (value+4)/8;
else
value = (value+8)/8;
if (value >= -1 && value < sfx_freeslot0 - 1)
S_sfx[num].name = savesfxnames[value+1];
else
deh_warning("Sound %d: offset out of bounds", num);
}
else */if (fastcmp(word, "SINGULAR"))
{ {
DEH_WriteUndoline(word, va("%d", S_sfx[num].singularity), UNDO_NONE); DEH_WriteUndoline(word, va("%d", S_sfx[num].singularity), UNDO_NONE);
S_sfx[num].singularity = value; S_sfx[num].singularity = value;
@ -2182,8 +2118,6 @@ static void readsound(MYFILE *f, INT32 num, const char *savesfxnames[])
} while (!myfeof(f)); } while (!myfeof(f));
Z_Free(s); Z_Free(s);
(void)savesfxnames;
} }
/** Checks if a game data file name for a mod is good. /** Checks if a game data file name for a mod is good.
@ -2811,190 +2745,6 @@ static void readconditionset(MYFILE *f, UINT8 setnum)
Z_Free(s); Z_Free(s);
} }
static void readtexture(MYFILE *f, const char *name)
{
char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL);
char *word;
char *word2;
char *tmp;
INT32 i, j, value;
UINT16 width = 0, height = 0;
INT16 patchcount = 0;
texture_t *texture;
do
{
if (myfgets(s, MAXLINELEN, f))
{
if (s[0] == '\n')
break;
tmp = strchr(s, '#');
if (tmp)
*tmp = '\0';
value = searchvalue(s);
word = strtok(s, " ");
if (word)
strupr(word);
else
break;
word2 = strtok(NULL, " ");
if (word2)
strupr(word2);
else
break;
// Width of the texture.
if (fastcmp(word, "WIDTH"))
{
DEH_WriteUndoline(word, va("%d", width), UNDO_NONE);
width = SHORT((UINT16)value);
}
// Height of the texture.
else if (fastcmp(word, "HEIGHT"))
{
DEH_WriteUndoline(word, va("%d", height), UNDO_NONE);
height = SHORT((UINT16)value);
}
// Number of patches the texture has.
else if (fastcmp(word, "NUMPATCHES"))
{
DEH_WriteUndoline(word, va("%d", patchcount), UNDO_NONE);
patchcount = SHORT((UINT16)value);
}
else
deh_warning("readtexture: unknown word '%s'", word);
}
} while (!myfeof(f));
// Error checking.
if (!width)
I_Error("Texture %s has no width!\n", name);
if (!height)
I_Error("Texture %s has no height!\n", name);
if (!patchcount)
I_Error("Texture %s has no patches!\n", name);
// Allocate memory for the texture, and fill in information.
texture = Z_Calloc(sizeof(texture_t) + (sizeof(texpatch_t) * SHORT(patchcount)), PU_STATIC, NULL);
M_Memcpy(texture->name, name, sizeof(texture->name));
texture->width = width;
texture->height = height;
texture->patchcount = patchcount;
texture->holes = false;
// Fill out the texture patches, to allow them to be detected
// accurately by readpatch.
for (i = 0; i < patchcount; i++)
{
texture->patches[i].originx = 0;
texture->patches[i].originy = 0;
texture->patches[i].wad = UINT16_MAX;
texture->patches[i].lump = UINT16_MAX;
}
// Jump to the next empty texture entry.
i = 0;
while (textures[i])
i++;
// Fill the global texture buffer entries.
j = 1;
while (j << 1 <= texture->width)
j <<= 1;
textures[i] = texture;
texturewidthmask[i] = j - 1;
textureheight[i] = texture->height << FRACBITS;
// Clean up.
Z_Free(s);
}
static void readpatch(MYFILE *f, const char *name, UINT16 wad)
{
char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL);
char *word;
char *word2;
char *tmp;
INT32 i = 0, j = 0, value;
texpatch_t patch = {0, 0, UINT16_MAX, UINT16_MAX, 0, 255, AST_COPY};
// Jump to the texture this patch belongs to, which,
// coincidentally, is always the last one on the buffer cache.
while (textures[i+1])
i++;
// Jump to the next empty patch entry.
while (memcmp(&(textures[i]->patches[j]), &patch, sizeof(patch)))
j++;
patch.wad = wad;
// Set the texture number, but only if the lump exists.
if ((patch.lump = W_CheckNumForNamePwad(name, wad, 0)) == INT16_MAX)
I_Error("readpatch: Missing patch in texture %s", textures[i]->name);
// note: undoing this patch will be done by other means
do
{
if (myfgets(s, MAXLINELEN, f))
{
if (s[0] == '\n')
break;
tmp = strchr(s, '#');
if (tmp)
*tmp = '\0';
value = searchvalue(s);
word = strtok(s, " ");
if (word)
strupr(word);
else
break;
word2 = strtok(NULL, " ");
if (word2)
strupr(word2);
else
break;
// X position of the patch in the texture.
if (fastcmp(word, "X"))
{
//DEH_WriteUndoline(word, va("%d", patch->originx), UNDO_NONE);
patch.originx = (INT16)value;
}
// Y position of the patch in the texture.
else if (fastcmp(word, "Y"))
{
//DEH_WriteUndoline(word, va("%d", patch->originy), UNDO_NONE);
patch.originy = (INT16)value;
}
else
deh_warning("readpatch: unknown word '%s'", word);
}
} while (!myfeof(f));
// Error checking.
/* // Irrelevant. Origins cannot be unsigned.
if (patch.originx == UINT16_MAX)
I_Error("Patch %s on texture %s has no X position!\n", name, textures[i]->name);
if (patch.originy == UINT16_MAX)
I_Error("Patch %s on texture %s has no Y position!\n", name, textures[i]->name);
*/
// Set the patch as that patch number.
textures[i]->patches[j] = patch;
// Clean up.
Z_Free(s);
}
static void readmaincfg(MYFILE *f) static void readmaincfg(MYFILE *f)
{ {
char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL); char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL);
@ -3405,30 +3155,17 @@ static void ignorelines(MYFILE *f)
Z_Free(s); Z_Free(s);
} }
static void DEH_LoadDehackedFile(MYFILE *f, UINT16 wad) static void DEH_LoadDehackedFile(MYFILE *f)
{ {
char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL); char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL);
char *word; char *word;
char *word2; char *word2;
INT32 i; INT32 i;
// do a copy of this for cross references probleme
//XBOXSTATIC actionf_t saveactions[NUMSTATES];
//XBOXSTATIC const char *savesprnames[NUMSPRITES];
XBOXSTATIC const char *savesfxnames[NUMSFX];
if (!deh_loaded) if (!deh_loaded)
initfreeslots(); initfreeslots();
deh_num_warning = 0; deh_num_warning = 0;
// save values for cross reference
/*
for (i = 0; i < NUMSTATES; i++)
saveactions[i] = states[i].action;
for (i = 0; i < NUMSPRITES; i++)
savesprnames[i] = sprnames[i];
*/
for (i = 0; i < NUMSFX; i++)
savesfxnames[i] = S_sfx[i].name;
gamedataadded = false; gamedataadded = false;
@ -3505,19 +3242,7 @@ static void DEH_LoadDehackedFile(MYFILE *f, UINT16 wad)
if (word2[strlen(word2)-1] == '\n') if (word2[strlen(word2)-1] == '\n')
word2[strlen(word2)-1] = '\0'; word2[strlen(word2)-1] = '\0';
i = atoi(word2); i = atoi(word2);
if (fastcmp(word, "TEXTURE")) if (fastcmp(word, "THING") || fastcmp(word, "MOBJ") || fastcmp(word, "OBJECT"))
{
// Read texture from spec file.
readtexture(f, word2);
DEH_WriteUndoline(word, word2, UNDO_HEADER);
}
else if (fastcmp(word, "PATCH"))
{
// Read patch from spec file.
readpatch(f, word2, wad);
DEH_WriteUndoline(word, word2, UNDO_HEADER);
}
else if (fastcmp(word, "THING") || fastcmp(word, "MOBJ") || fastcmp(word, "OBJECT"))
{ {
if (i == 0 && word2[0] != '0') // If word2 isn't a number if (i == 0 && word2[0] != '0') // If word2 isn't a number
i = get_mobjtype(word2); // find a thing by name i = get_mobjtype(word2); // find a thing by name
@ -3530,10 +3255,6 @@ static void DEH_LoadDehackedFile(MYFILE *f, UINT16 wad)
} }
DEH_WriteUndoline(word, word2, UNDO_HEADER); DEH_WriteUndoline(word, word2, UNDO_HEADER);
} }
/* else if (fastcmp(word, "ANIMTEX"))
{
readAnimTex(f, i);
}*/
else if (fastcmp(word, "LIGHT")) else if (fastcmp(word, "LIGHT"))
{ {
#ifdef HWRENDER #ifdef HWRENDER
@ -3605,34 +3326,12 @@ static void DEH_LoadDehackedFile(MYFILE *f, UINT16 wad)
} }
DEH_WriteUndoline(word, word2, UNDO_HEADER); DEH_WriteUndoline(word, word2, UNDO_HEADER);
} }
// <Callum> Added translations to this just in case its re-enabled
/* else if (fastcmp(word, "POINTER"))
{
word = strtok(NULL, " "); // get frame
word = strtok(NULL, ")");
if (word)
{
i = atoi(word);
if (i < NUMSTATES && i >= 0)
{
if (myfgets(s, MAXLINELEN, f))
states[i].action = saveactions[searchvalue(s)];
}
else
{
deh_warning("Pointer: Frame %d doesn't exist", i);
ignorelines(f);
}
}
else
deh_warning("pointer (Frame %d) : missing ')'", i);
}*/
else if (fastcmp(word, "SOUND")) else if (fastcmp(word, "SOUND"))
{ {
if (i == 0 && word2[0] != '0') // If word2 isn't a number if (i == 0 && word2[0] != '0') // If word2 isn't a number
i = get_sfx(word2); // find a sound by name i = get_sfx(word2); // find a sound by name
if (i < NUMSFX && i > 0) if (i < NUMSFX && i > 0)
readsound(f, i, savesfxnames); readsound(f, i);
else else
{ {
deh_warning("Sound %d out of range (1 - %d)", i, NUMSFX-1); deh_warning("Sound %d out of range (1 - %d)", i, NUMSFX-1);
@ -3640,26 +3339,6 @@ static void DEH_LoadDehackedFile(MYFILE *f, UINT16 wad)
} }
DEH_WriteUndoline(word, word2, UNDO_HEADER); DEH_WriteUndoline(word, word2, UNDO_HEADER);
} }
/* else if (fastcmp(word, "SPRITE"))
{
if (i < NUMSPRITES && i >= 0)
{
if (myfgets(s, MAXLINELEN, f))
{
INT32 k;
k = (searchvalue(s) - 151328)/8;
if (k >= 0 && k < NUMSPRITES)
sprnames[i] = savesprnames[k];
else
{
deh_warning("Sprite %d: offset out of bounds", i);
ignorelines(f);
}
}
}
else
deh_warning("Sprite %d doesn't exist",i);
}*/
else if (fastcmp(word, "HUDITEM")) else if (fastcmp(word, "HUDITEM"))
{ {
if (i == 0 && word2[0] != '0') // If word2 isn't a number if (i == 0 && word2[0] != '0') // If word2 isn't a number
@ -3746,7 +3425,10 @@ static void DEH_LoadDehackedFile(MYFILE *f, UINT16 wad)
// no undo support for this insanity yet // no undo support for this insanity yet
//DEH_WriteUndoline(word, word2, UNDO_HEADER); //DEH_WriteUndoline(word, word2, UNDO_HEADER);
} }
else if (fastcmp(word, "SRB2")) // Last I heard this crashes the game if you try to use it
// so this is disabled for now
// -- Monster Iestyn
/* else if (fastcmp(word, "SRB2"))
{ {
INT32 ver = searchvalue(strtok(NULL, "\n")); INT32 ver = searchvalue(strtok(NULL, "\n"));
if (ver != PATCHVERSION) if (ver != PATCHVERSION)
@ -3757,6 +3439,7 @@ static void DEH_LoadDehackedFile(MYFILE *f, UINT16 wad)
// Unless you REALLY want to piss people off, // Unless you REALLY want to piss people off,
// define a custom gamedata /before/ doing this!! // define a custom gamedata /before/ doing this!!
// (then again, modifiedgame will prevent game data saving anyway) // (then again, modifiedgame will prevent game data saving anyway)
*/
else if (fastcmp(word, "CLEAR")) else if (fastcmp(word, "CLEAR"))
{ {
boolean clearall = (fastcmp(word2, "ALL")); boolean clearall = (fastcmp(word2, "ALL"));
@ -3830,7 +3513,7 @@ void DEH_LoadDehackedLumpPwad(UINT16 wad, UINT16 lump)
W_ReadLumpPwad(wad, lump, f.data); W_ReadLumpPwad(wad, lump, f.data);
f.curpos = f.data; f.curpos = f.data;
f.data[f.size] = 0; f.data[f.size] = 0;
DEH_LoadDehackedFile(&f, wad); DEH_LoadDehackedFile(&f);
DEH_WriteUndoline(va("# uload for wad: %u, lump: %u", wad, lump), NULL, UNDO_DONE); DEH_WriteUndoline(va("# uload for wad: %u, lump: %u", wad, lump), NULL, UNDO_DONE);
Z_Free(f.data); Z_Free(f.data);
} }

View file

@ -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 23 #define MODVERSION 24
// ========================================================================= // =========================================================================
@ -546,4 +546,8 @@ extern const char *compdate, *comptime, *comprevision, *compbranch;
/// Hudname padding. /// Hudname padding.
#define SKINNAMEPADDING #define SKINNAMEPADDING
/// Handle touching sector specials in P_PlayerAfterThink instead of P_PlayerThink.
/// \note Required for proper collision with moving sloped surfaces that have sector specials on them.
//#define SECTORSPECIALSAFTERTHINK
#endif // __DOOMDEF__ #endif // __DOOMDEF__

View file

@ -1723,7 +1723,7 @@ static void F_AdvanceToNextScene(void)
void F_EndCutScene(void) void F_EndCutScene(void)
{ {
cutsceneover = true; // do this first, just in case Y_EndGame or something wants to turn it back false later cutsceneover = true; // do this first, just in case G_EndGame or something wants to turn it back false later
if (runningprecutscene) if (runningprecutscene)
{ {
if (server) if (server)
@ -1738,7 +1738,7 @@ void F_EndCutScene(void)
else if (nextmap < 1100-1) else if (nextmap < 1100-1)
G_NextLevel(); G_NextLevel();
else else
Y_EndGame(); G_EndGame();
} }
} }

View file

@ -2309,6 +2309,9 @@ void G_SpawnPlayer(INT32 playernum, boolean starpost)
if (starpost) //Don't even bother with looking for a place to spawn. if (starpost) //Don't even bother with looking for a place to spawn.
{ {
P_MovePlayerToStarpost(playernum); P_MovePlayerToStarpost(playernum);
#ifdef HAVE_BLUA
LUAh_PlayerSpawn(&players[playernum]); // Lua hook for player spawning :)
#endif
return; return;
} }
@ -2633,7 +2636,7 @@ void G_ExitLevel(void)
CONS_Printf(M_GetText("The round has ended.\n")); CONS_Printf(M_GetText("The round has ended.\n"));
// Remove CEcho text on round end. // Remove CEcho text on round end.
HU_DoCEcho(""); HU_ClearCEcho();
} }
} }
@ -2927,7 +2930,7 @@ void G_AfterIntermission(void)
if (nextmap < 1100-1) if (nextmap < 1100-1)
G_NextLevel(); G_NextLevel();
else else
Y_EndGame(); G_EndGame();
} }
} }
@ -3013,6 +3016,38 @@ static void G_DoContinued(void)
gameaction = ga_nothing; gameaction = ga_nothing;
} }
//
// G_EndGame (formerly Y_EndGame)
// Frankly this function fits better in g_game.c than it does in y_inter.c
//
// ...Gee, (why) end the game?
// Because G_AfterIntermission and F_EndCutscene would
// both do this exact same thing *in different ways* otherwise,
// which made it so that you could only unlock Ultimate mode
// if you had a cutscene after the final level and crap like that.
// This function simplifies it so only one place has to be updated
// when something new is added.
void G_EndGame(void)
{
// Only do evaluation and credits in coop games.
if (gametype == GT_COOP)
{
if (nextmap == 1102-1) // end game with credits
{
F_StartCredits();
return;
}
if (nextmap == 1101-1) // end game with evaluation
{
F_StartGameEvaluation();
return;
}
}
// 1100 or competitive multiplayer, so go back to title screen.
D_StartTitle();
}
// //
// G_LoadGameSettings // G_LoadGameSettings
// //
@ -3898,7 +3933,7 @@ void G_GhostAddColor(ghostcolor_t color)
ghostext.color = (UINT8)color; ghostext.color = (UINT8)color;
} }
void G_GhostAddScale(UINT16 scale) void G_GhostAddScale(fixed_t scale)
{ {
if (!demorecording || !(demoflags & DF_GHOST)) if (!demorecording || !(demoflags & DF_GHOST))
return; return;

View file

@ -142,7 +142,7 @@ void G_GhostAddSpin(void);
void G_GhostAddRev(void); void G_GhostAddRev(void);
void G_GhostAddColor(ghostcolor_t color); void G_GhostAddColor(ghostcolor_t color);
void G_GhostAddFlip(void); void G_GhostAddFlip(void);
void G_GhostAddScale(UINT16 scale); void G_GhostAddScale(fixed_t scale);
void G_GhostAddHit(mobj_t *victim); void G_GhostAddHit(mobj_t *victim);
void G_WriteGhostTic(mobj_t *ghost); void G_WriteGhostTic(mobj_t *ghost);
void G_ConsGhostTic(void); void G_ConsGhostTic(void);
@ -174,6 +174,7 @@ void G_NextLevel(void);
void G_Continue(void); void G_Continue(void);
void G_UseContinue(void); void G_UseContinue(void);
void G_AfterIntermission(void); void G_AfterIntermission(void);
void G_EndGame(void); // moved from y_inter.c/h and renamed
void G_Ticker(boolean run); void G_Ticker(boolean run);
boolean G_Responder(event_t *ev); boolean G_Responder(event_t *ev);

View file

@ -78,6 +78,7 @@ typedef struct gr_vissprite_s
//Hurdler: 25/04/2000: now support colormap in hardware mode //Hurdler: 25/04/2000: now support colormap in hardware mode
UINT8 *colormap; UINT8 *colormap;
INT32 dispoffset; // copy of info->dispoffset, affects ordering but not drawing INT32 dispoffset; // copy of info->dispoffset, affects ordering but not drawing
float z1, z2;
} gr_vissprite_t; } gr_vissprite_t;
// -------- // --------

View file

@ -1084,9 +1084,9 @@ static void HWR_SplitWall(sector_t *sector, wallVert3D *wallVerts, INT32 texnum,
float endheight = 0.0f, endbheight = 0.0f; float endheight = 0.0f, endbheight = 0.0f;
fixed_t v1x = FLOAT_TO_FIXED(wallVerts[0].x); fixed_t v1x = FLOAT_TO_FIXED(wallVerts[0].x);
fixed_t v1y = FLOAT_TO_FIXED(wallVerts[0].y); fixed_t v1y = FLOAT_TO_FIXED(wallVerts[0].z); // not a typo
fixed_t v2x = FLOAT_TO_FIXED(wallVerts[1].x); fixed_t v2x = FLOAT_TO_FIXED(wallVerts[1].x);
fixed_t v2y = FLOAT_TO_FIXED(wallVerts[1].y); fixed_t v2y = FLOAT_TO_FIXED(wallVerts[1].z); // not a typo
// compiler complains when P_GetZAt is used in FLOAT_TO_FIXED directly // compiler complains when P_GetZAt is used in FLOAT_TO_FIXED directly
// use this as a temp var to store P_GetZAt's return value each time // use this as a temp var to store P_GetZAt's return value each time
fixed_t temp; fixed_t temp;
@ -3721,6 +3721,9 @@ static void HWR_Subsector(size_t num)
while (count--) while (count--)
{ {
#ifdef POLYOBJECTS
if (!line->polyseg) // ignore segs that belong to polyobjects
#endif
HWR_AddLine(line); HWR_AddLine(line);
line++; line++;
} }
@ -4226,6 +4229,7 @@ static void HWR_DrawSprite(gr_vissprite_t *spr)
GLPatch_t *gpatch; // sprite patch converted to hardware GLPatch_t *gpatch; // sprite patch converted to hardware
FSurfaceInfo Surf; FSurfaceInfo Surf;
const boolean hires = (spr->mobj && spr->mobj->skin && ((skin_t *)spr->mobj->skin)->flags & SF_HIRES); const boolean hires = (spr->mobj && spr->mobj->skin && ((skin_t *)spr->mobj->skin)->flags & SF_HIRES);
//const boolean papersprite = (spr->mobj && (spr->mobj->frame & FF_PAPERSPRITE));
if (spr->mobj) if (spr->mobj)
this_scale = FIXED_TO_FLOAT(spr->mobj->scale); this_scale = FIXED_TO_FLOAT(spr->mobj->scale);
if (hires) if (hires)
@ -4269,7 +4273,8 @@ static void HWR_DrawSprite(gr_vissprite_t *spr)
// make a wall polygon (with 2 triangles), using the floor/ceiling heights, // make a wall polygon (with 2 triangles), using the floor/ceiling heights,
// and the 2d map coords of start/end vertices // and the 2d map coords of start/end vertices
wallVerts[0].z = wallVerts[1].z = wallVerts[2].z = wallVerts[3].z = spr->tz; wallVerts[0].z = wallVerts[3].z = spr->z1;
wallVerts[2].z = wallVerts[1].z = spr->z2;
// transform // transform
wv = wallVerts; wv = wallVerts;
@ -5065,6 +5070,10 @@ static void HWR_ProjectSprite(mobj_t *thing)
angle_t ang; angle_t ang;
INT32 heightsec, phs; INT32 heightsec, phs;
const boolean papersprite = (thing->frame & FF_PAPERSPRITE);
float offset;
float ang_scale = 1.0f, ang_scalez = 0.0f;
float z1, z2;
if (!thing) if (!thing)
return; return;
@ -5079,7 +5088,7 @@ static void HWR_ProjectSprite(mobj_t *thing)
tz = (tr_x * gr_viewcos) + (tr_y * gr_viewsin); tz = (tr_x * gr_viewcos) + (tr_y * gr_viewsin);
// thing is behind view plane? // thing is behind view plane?
if (tz < ZCLIP_PLANE && (!cv_grmd2.value || md2_models[thing->sprite].notfound == true)) //Yellow: Only MD2's dont disappear if (tz < ZCLIP_PLANE && !papersprite && (!cv_grmd2.value || md2_models[thing->sprite].notfound == true)) //Yellow: Only MD2's dont disappear
return; return;
tx = (tr_x * gr_viewsin) - (tr_y * gr_viewcos); tx = (tr_x * gr_viewsin) - (tr_y * gr_viewcos);
@ -5117,6 +5126,27 @@ static void HWR_ProjectSprite(mobj_t *thing)
I_Error("sprframes NULL for sprite %d\n", thing->sprite); I_Error("sprframes NULL for sprite %d\n", thing->sprite);
#endif #endif
if (papersprite)
{
// Use the actual view angle, rather than the angle formed
// between the view point and the thing
// this makes sure paper sprites always appear at the right angle!
// Note: DO NOT do this in software mode version, it actually
// makes papersprites look WORSE there (I know, I've tried)
// Monster Iestyn - 13/05/17
ang = dup_viewangle - thing->angle;
ang_scale = FIXED_TO_FLOAT(FINESINE(ang>>ANGLETOFINESHIFT));
ang_scalez = FIXED_TO_FLOAT(FINECOSINE(ang>>ANGLETOFINESHIFT));
if (ang_scale < 0)
{
ang_scale = -ang_scale;
ang_scalez = -ang_scalez;
}
}
else if (sprframe->rotate != SRF_SINGLE)
ang = R_PointToAngle (thing->x, thing->y) - thing->angle;
if (sprframe->rotate == SRF_SINGLE) if (sprframe->rotate == SRF_SINGLE)
{ {
// use single rotation for all views // use single rotation for all views
@ -5127,8 +5157,6 @@ static void HWR_ProjectSprite(mobj_t *thing)
else else
{ {
// choose a different rotation based on player view // choose a different rotation based on player view
ang = R_PointToAngle (thing->x, thing->y) - thing->angle;
if ((sprframe->rotate & SRF_RIGHT) && (ang < ANGLE_180)) // See from right if ((sprframe->rotate & SRF_RIGHT) && (ang < ANGLE_180)) // See from right
rot = 6; // F7 slot rot = 6; // F7 slot
else if ((sprframe->rotate & SRF_LEFT) && (ang >= ANGLE_180)) // See from left else if ((sprframe->rotate & SRF_LEFT) && (ang >= ANGLE_180)) // See from left
@ -5146,9 +5174,12 @@ static void HWR_ProjectSprite(mobj_t *thing)
// calculate edges of the shape // calculate edges of the shape
if (flip) if (flip)
tx -= FIXED_TO_FLOAT(spritecachedinfo[lumpoff].width - spritecachedinfo[lumpoff].offset) * this_scale; offset = FIXED_TO_FLOAT(spritecachedinfo[lumpoff].width - spritecachedinfo[lumpoff].offset) * this_scale;
else else
tx -= FIXED_TO_FLOAT(spritecachedinfo[lumpoff].offset) * this_scale; offset = FIXED_TO_FLOAT(spritecachedinfo[lumpoff].offset) * this_scale;
z1 = tz - (offset * ang_scalez);
tx -= offset * ang_scale;
// project x // project x
x1 = gr_windowcenterx + (tx * gr_centerx / tz); x1 = gr_windowcenterx + (tx * gr_centerx / tz);
@ -5159,7 +5190,14 @@ static void HWR_ProjectSprite(mobj_t *thing)
x1 = tx; x1 = tx;
tx += FIXED_TO_FLOAT(spritecachedinfo[lumpoff].width) * this_scale; offset = FIXED_TO_FLOAT(spritecachedinfo[lumpoff].width) * this_scale;
z2 = z1 + (offset * ang_scalez);
tx += offset * ang_scale;
if (papersprite && max(z1, z2) < ZCLIP_PLANE)
return;
x2 = gr_windowcenterx + (tx * gr_centerx / tz); x2 = gr_windowcenterx + (tx * gr_centerx / tz);
if (vflip) if (vflip)
@ -5208,6 +5246,8 @@ static void HWR_ProjectSprite(mobj_t *thing)
vis->patchlumpnum = sprframe->lumppat[rot]; vis->patchlumpnum = sprframe->lumppat[rot];
vis->flip = flip; vis->flip = flip;
vis->mobj = thing; vis->mobj = thing;
vis->z1 = z1;
vis->z2 = z2;
//Hurdler: 25/04/2000: now support colormap in hardware mode //Hurdler: 25/04/2000: now support colormap in hardware mode
if ((vis->mobj->flags & MF_BOSS) && (vis->mobj->flags2 & MF2_FRET) && (leveltime & 1)) // Bosses "flash" if ((vis->mobj->flags & MF_BOSS) && (vis->mobj->flags2 & MF2_FRET) && (leveltime & 1)) // Bosses "flash"

View file

@ -244,6 +244,7 @@ FUNCPRINTF void DBG_Printf(const char *lpFmt, ...)
#define pglMaterialfv glMaterialfv #define pglMaterialfv glMaterialfv
/* Raster functions */ /* Raster functions */
#define pglPixelStorei glPixelStorei
#define pglReadPixels glReadPixels #define pglReadPixels glReadPixels
/* Texture mapping */ /* Texture mapping */
@ -262,15 +263,8 @@ FUNCPRINTF void DBG_Printf(const char *lpFmt, ...)
/* texture mapping */ //GL_EXT_copy_texture /* texture mapping */ //GL_EXT_copy_texture
#ifndef KOS_GL_COMPATIBILITY #ifndef KOS_GL_COMPATIBILITY
#define pglCopyTexImage2D glCopyTexImage2D #define pglCopyTexImage2D glCopyTexImage2D
#endif
/* GLU functions */
#define pgluBuild2DMipmaps gluBuild2DMipmaps
#endif
#ifndef MINI_GL_COMPATIBILITY
/* 1.3 functions for multitexturing */
#define pglActiveTexture glActiveTexture
#define pglMultiTexCoord2f glMultiTexCoord2f
#endif
#else //!STATIC_OPENGL #else //!STATIC_OPENGL
/* 1.0 functions */ /* 1.0 functions */
@ -365,6 +359,8 @@ typedef void (APIENTRY * PFNglMaterialfv) (GLint face, GLenum pname, GLfloat *pa
static PFNglMaterialfv pglMaterialfv; static PFNglMaterialfv pglMaterialfv;
/* Raster functions */ /* Raster functions */
typedef void (APIENTRY * PFNglPixelStorei) (GLenum pname, GLint param);
static PFNglPixelStorei pglPixelStorei;
typedef void (APIENTRY * PFNglReadPixels) (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels); typedef void (APIENTRY * PFNglReadPixels) (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels);
static PFNglReadPixels pglReadPixels; static PFNglReadPixels pglReadPixels;
@ -391,7 +387,7 @@ static PFNglBindTexture pglBindTexture;
/* texture mapping */ //GL_EXT_copy_texture /* texture mapping */ //GL_EXT_copy_texture
typedef void (APIENTRY * PFNglCopyTexImage2D) (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); typedef void (APIENTRY * PFNglCopyTexImage2D) (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border);
static PFNglCopyTexImage2D pglCopyTexImage2D; static PFNglCopyTexImage2D pglCopyTexImage2D;
#endif
/* GLU functions */ /* GLU functions */
typedef GLint (APIENTRY * PFNgluBuild2DMipmaps) (GLenum target, GLint internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *data); typedef GLint (APIENTRY * PFNgluBuild2DMipmaps) (GLenum target, GLint internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *data);
static PFNgluBuild2DMipmaps pgluBuild2DMipmaps; static PFNgluBuild2DMipmaps pgluBuild2DMipmaps;
@ -403,7 +399,6 @@ static PFNglActiveTexture pglActiveTexture;
typedef void (APIENTRY *PFNglMultiTexCoord2f) (GLenum, GLfloat, GLfloat); typedef void (APIENTRY *PFNglMultiTexCoord2f) (GLenum, GLfloat, GLfloat);
static PFNglMultiTexCoord2f pglMultiTexCoord2f; static PFNglMultiTexCoord2f pglMultiTexCoord2f;
#endif #endif
#endif
#ifndef MINI_GL_COMPATIBILITY #ifndef MINI_GL_COMPATIBILITY
/* 1.2 Parms */ /* 1.2 Parms */
@ -494,6 +489,7 @@ boolean SetupGLfunc(void)
GETOPENGLFUNC(pglLightModelfv , glLightModelfv) GETOPENGLFUNC(pglLightModelfv , glLightModelfv)
GETOPENGLFUNC(pglMaterialfv , glMaterialfv) GETOPENGLFUNC(pglMaterialfv , glMaterialfv)
GETOPENGLFUNC(pglPixelStorei , glPixelStorei)
GETOPENGLFUNC(pglReadPixels , glReadPixels) GETOPENGLFUNC(pglReadPixels , glReadPixels)
GETOPENGLFUNC(pglTexEnvi , glTexEnvi) GETOPENGLFUNC(pglTexEnvi , glTexEnvi)
@ -519,35 +515,23 @@ boolean SetupGLfunc(void)
// This has to be done after the context is created so the version number can be obtained // This has to be done after the context is created so the version number can be obtained
boolean SetupGLFunc13(void) boolean SetupGLFunc13(void)
{ {
#ifdef MINI_GL_COMPATIBILITY
return false;
#else
const GLubyte *version = pglGetString(GL_VERSION); const GLubyte *version = pglGetString(GL_VERSION);
int glmajor, glminor; int glmajor, glminor;
gl13 = false; gl13 = false;
#ifdef MINI_GL_COMPATIBILITY
return false;
#else
#ifdef STATIC_OPENGL
gl13 = true;
#else
// Parse the GL version // Parse the GL version
if (version != NULL) if (version != NULL)
{ {
if (sscanf((const char*)version, "%d.%d", &glmajor, &glminor) == 2) if (sscanf((const char*)version, "%d.%d", &glmajor, &glminor) == 2)
{ {
// Look, we gotta prepare for the inevitable arrival of GL 2.0 code... // Look, we gotta prepare for the inevitable arrival of GL 2.0 code...
switch (glmajor) if (glmajor == 1 && glminor >= 3)
{ gl13 = true;
case 1: else if (glmajor > 1)
if (glminor == 3) gl13 = true;
break;
case 2:
case 3:
case 4:
gl13 = true; gl13 = true;
default:
break;
}
} }
} }
@ -568,9 +552,6 @@ boolean SetupGLFunc13(void)
} }
else else
DBG_Printf("GL_ARB_multitexture support: disabled\n"); DBG_Printf("GL_ARB_multitexture support: disabled\n");
#undef GETOPENGLFUNC
#endif
return true; return true;
#endif #endif
} }
@ -897,7 +878,9 @@ EXPORT void HWRAPI(ReadRect) (INT32 x, INT32 y, INT32 width, INT32 height,
GLubyte*top = (GLvoid*)dst_data, *bottom = top + dst_stride * (height - 1); GLubyte*top = (GLvoid*)dst_data, *bottom = top + dst_stride * (height - 1);
GLubyte *row = malloc(dst_stride); GLubyte *row = malloc(dst_stride);
if (!row) return; if (!row) return;
pglPixelStorei(GL_PACK_ALIGNMENT, 1);
pglReadPixels(x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, dst_data); pglReadPixels(x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, dst_data);
pglPixelStorei(GL_UNPACK_ALIGNMENT, 1);
for(i = 0; i < height/2; i++) for(i = 0; i < height/2; i++)
{ {
memcpy(row, top, dst_stride); memcpy(row, top, dst_stride);
@ -913,7 +896,9 @@ EXPORT void HWRAPI(ReadRect) (INT32 x, INT32 y, INT32 width, INT32 height,
INT32 j; INT32 j;
GLubyte *image = malloc(width*height*3*sizeof (*image)); GLubyte *image = malloc(width*height*3*sizeof (*image));
if (!image) return; if (!image) return;
pglPixelStorei(GL_PACK_ALIGNMENT, 1);
pglReadPixels(x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, image); pglReadPixels(x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, image);
pglPixelStorei(GL_UNPACK_ALIGNMENT, 1);
for (i = height-1; i >= 0; i--) for (i = height-1; i >= 0; i--)
{ {
for (j = 0; j < width; j++) for (j = 0; j < width; j++)
@ -1815,13 +1800,11 @@ EXPORT void HWRAPI(SetSpecialState) (hwdspecialstate_t IdState, INT32 Value)
min_filter = GL_NEAREST; min_filter = GL_NEAREST;
#endif #endif
} }
#ifndef STATIC_OPENGL
if (!pgluBuild2DMipmaps) if (!pgluBuild2DMipmaps)
{ {
MipMap = GL_FALSE; MipMap = GL_FALSE;
min_filter = GL_LINEAR; min_filter = GL_LINEAR;
} }
#endif
Flush(); //??? if we want to change filter mode by texture, remove this Flush(); //??? if we want to change filter mode by texture, remove this
break; break;

View file

@ -46,6 +46,7 @@ enum hook {
hook_ShieldSpawn, hook_ShieldSpawn,
hook_ShieldSpecial, hook_ShieldSpecial,
hook_MobjMoveBlocked, hook_MobjMoveBlocked,
hook_MapThingSpawn,
hook_MAX // last hook hook_MAX // last hook
}; };
@ -83,5 +84,6 @@ boolean LUAh_HurtMsg(player_t *player, mobj_t *inflictor, mobj_t *source, UINT8
#define LUAh_ShieldSpawn(player) LUAh_PlayerHook(player, hook_ShieldSpawn) // Hook for P_SpawnShieldOrb #define LUAh_ShieldSpawn(player) LUAh_PlayerHook(player, hook_ShieldSpawn) // Hook for P_SpawnShieldOrb
#define LUAh_ShieldSpecial(player) LUAh_PlayerHook(player, hook_ShieldSpecial) // Hook for shield abilities #define LUAh_ShieldSpecial(player) LUAh_PlayerHook(player, hook_ShieldSpecial) // Hook for shield abilities
#define LUAh_MobjMoveBlocked(mo) LUAh_MobjHook(mo, hook_MobjMoveBlocked) // Hook for P_XYMovement (when movement is blocked) #define LUAh_MobjMoveBlocked(mo) LUAh_MobjHook(mo, hook_MobjMoveBlocked) // Hook for P_XYMovement (when movement is blocked)
boolean LUAh_MapThingSpawn(mobj_t *mo, mapthing_t *mthing); // Hook for P_SpawnMapThing by mobj type
#endif #endif

View file

@ -57,6 +57,7 @@ const char *const hookNames[hook_MAX+1] = {
"ShieldSpawn", "ShieldSpawn",
"ShieldSpecial", "ShieldSpecial",
"MobjMoveBlocked", "MobjMoveBlocked",
"MapThingSpawn",
NULL NULL
}; };
@ -128,6 +129,7 @@ static int lib_addHook(lua_State *L)
case hook_MobjRemoved: case hook_MobjRemoved:
case hook_HurtMsg: case hook_HurtMsg:
case hook_MobjMoveBlocked: case hook_MobjMoveBlocked:
case hook_MapThingSpawn:
hook.s.mt = MT_NULL; hook.s.mt = MT_NULL;
if (lua_isnumber(L, 2)) if (lua_isnumber(L, 2))
hook.s.mt = lua_tonumber(L, 2); hook.s.mt = lua_tonumber(L, 2);
@ -187,6 +189,7 @@ static int lib_addHook(lua_State *L)
case hook_BossDeath: case hook_BossDeath:
case hook_MobjRemoved: case hook_MobjRemoved:
case hook_MobjMoveBlocked: case hook_MobjMoveBlocked:
case hook_MapThingSpawn:
lastp = &mobjhooks[hook.s.mt]; lastp = &mobjhooks[hook.s.mt];
break; break;
case hook_JumpSpecial: case hook_JumpSpecial:
@ -1073,4 +1076,66 @@ void LUAh_NetArchiveHook(lua_CFunction archFunc)
// stack: tables // stack: tables
} }
boolean LUAh_MapThingSpawn(mobj_t *mo, mapthing_t *mthing)
{
hook_p hookp;
boolean hooked = false;
if (!gL || !(hooksAvailable[hook_MapThingSpawn/8] & (1<<(hook_MapThingSpawn%8))))
return false;
lua_settop(gL, 0);
// Look for all generic mobj map thing spawn hooks
for (hookp = mobjhooks[MT_NULL]; hookp; hookp = hookp->next)
if (hookp->type == hook_MapThingSpawn)
{
if (lua_gettop(gL) == 0)
{
LUA_PushUserdata(gL, mo, META_MOBJ);
LUA_PushUserdata(gL, mthing, META_MAPTHING);
}
lua_pushfstring(gL, FMT_HOOKID, hookp->id);
lua_gettable(gL, LUA_REGISTRYINDEX);
lua_pushvalue(gL, -3);
lua_pushvalue(gL, -3);
if (lua_pcall(gL, 2, 1, 0)) {
if (!hookp->error || cv_debug & DBG_LUA)
CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1));
lua_pop(gL, 1);
hookp->error = true;
continue;
}
if (lua_toboolean(gL, -1))
hooked = true;
lua_pop(gL, 1);
}
for (hookp = mobjhooks[mo->type]; hookp; hookp = hookp->next)
if (hookp->type == hook_MapThingSpawn)
{
if (lua_gettop(gL) == 0)
{
LUA_PushUserdata(gL, mo, META_MOBJ);
LUA_PushUserdata(gL, mthing, META_MAPTHING);
}
lua_pushfstring(gL, FMT_HOOKID, hookp->id);
lua_gettable(gL, LUA_REGISTRYINDEX);
lua_pushvalue(gL, -3);
lua_pushvalue(gL, -3);
if (lua_pcall(gL, 2, 1, 0)) {
if (!hookp->error || cv_debug & DBG_LUA)
CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1));
lua_pop(gL, 1);
hookp->error = true;
continue;
}
if (lua_toboolean(gL, -1))
hooked = true;
lua_pop(gL, 1);
}
lua_settop(gL, 0);
return hooked;
}
#endif #endif

View file

@ -596,14 +596,14 @@ static UINT8 ArchiveValue(int TABLESINDEX, int myindex)
{ {
mobjinfo_t *info = *((mobjinfo_t **)lua_touserdata(gL, myindex)); mobjinfo_t *info = *((mobjinfo_t **)lua_touserdata(gL, myindex));
WRITEUINT8(save_p, ARCH_MOBJINFO); WRITEUINT8(save_p, ARCH_MOBJINFO);
WRITEUINT8(save_p, info - mobjinfo); WRITEUINT16(save_p, info - mobjinfo);
break; break;
} }
case ARCH_STATE: case ARCH_STATE:
{ {
state_t *state = *((state_t **)lua_touserdata(gL, myindex)); state_t *state = *((state_t **)lua_touserdata(gL, myindex));
WRITEUINT8(save_p, ARCH_STATE); WRITEUINT8(save_p, ARCH_STATE);
WRITEUINT8(save_p, state - states); WRITEUINT16(save_p, state - states);
break; break;
} }
case ARCH_MOBJ: case ARCH_MOBJ:

View file

@ -16,70 +16,93 @@
#include "lua_script.h" #include "lua_script.h"
#include "lua_libs.h" #include "lua_libs.h"
#define META_ITERATIONSTATE "iteration state"
static const char *const iter_opt[] = { static const char *const iter_opt[] = {
"all", "all",
"mobj", "mobj",
NULL}; NULL};
static const actionf_p1 iter_funcs[] = {
NULL,
(actionf_p1)P_MobjThinker
};
struct iterationState {
actionf_p1 filter;
int next;
};
static int iterationState_gc(lua_State *L)
{
struct iterationState *it = luaL_checkudata(L, -1, META_ITERATIONSTATE);
if (it->next != LUA_REFNIL)
{
luaL_unref(L, LUA_REGISTRYINDEX, it->next);
it->next = LUA_REFNIL;
}
return 0;
}
#define push_thinker(th) {\
if ((th)->function.acp1 == (actionf_p1)P_MobjThinker) \
LUA_PushUserdata(L, (th), META_MOBJ); \
else \
lua_pushlightuserdata(L, (th)); \
}
static int lib_iterateThinkers(lua_State *L) static int lib_iterateThinkers(lua_State *L)
{ {
int state = luaL_checkoption(L, 1, "mobj", iter_opt); thinker_t *th = NULL, *next = NULL;
struct iterationState *it;
thinker_t *th = NULL;
actionf_p1 searchFunc;
const char *searchMeta;
if (gamestate != GS_LEVEL) if (gamestate != GS_LEVEL)
return luaL_error(L, "This function can only be used in a level!"); return luaL_error(L, "This function can only be used in a level!");
it = luaL_checkudata(L, 1, META_ITERATIONSTATE);
lua_settop(L, 2); lua_settop(L, 2);
lua_remove(L, 1); // remove state now.
switch(state) if (lua_isnil(L, 2))
{
case 0:
searchFunc = NULL;
searchMeta = NULL;
break;
case 1:
default:
searchFunc = (actionf_p1)P_MobjThinker;
searchMeta = META_MOBJ;
break;
}
if (!lua_isnil(L, 1)) {
if (lua_islightuserdata(L, 1))
th = (thinker_t *)lua_touserdata(L, 1);
else if (searchMeta)
th = *((thinker_t **)luaL_checkudata(L, 1, searchMeta));
else
th = *((thinker_t **)lua_touserdata(L, 1));
} else
th = &thinkercap; th = &thinkercap;
else if (lua_isuserdata(L, 2))
if (!th) // something got our userdata invalidated!
return 0;
if (searchFunc == NULL)
{ {
if ((th = th->next) != &thinkercap) if (lua_islightuserdata(L, 2))
{ th = lua_touserdata(L, 2);
if (th->function.acp1 == (actionf_p1)P_MobjThinker)
LUA_PushUserdata(L, th, META_MOBJ);
else else
lua_pushlightuserdata(L, th);
return 1;
}
return 0;
}
for (th = th->next; th != &thinkercap; th = th->next)
{ {
if (th->function.acp1 != searchFunc) th = *(thinker_t **)lua_touserdata(L, -1);
continue; if (!th)
{
if (it->next == LUA_REFNIL)
return 0;
LUA_PushUserdata(L, th, searchMeta); lua_rawgeti(L, LUA_REGISTRYINDEX, it->next);
if (lua_islightuserdata(L, -1))
next = lua_touserdata(L, -1);
else
next = *(thinker_t **)lua_touserdata(L, -1);
}
}
}
luaL_unref(L, LUA_REGISTRYINDEX, it->next);
it->next = LUA_REFNIL;
if (th && !next)
next = th->next;
if (!next)
return luaL_error(L, "next thinker invalidated during iteration");
for (; next != &thinkercap; next = next->next)
if (!it->filter || next->function.acp1 == it->filter)
{
push_thinker(next);
if (next->next != &thinkercap)
{
push_thinker(next->next);
it->next = luaL_ref(L, LUA_REGISTRYINDEX);
}
return 1; return 1;
} }
return 0; return 0;
@ -87,18 +110,33 @@ static int lib_iterateThinkers(lua_State *L)
static int lib_startIterate(lua_State *L) static int lib_startIterate(lua_State *L)
{ {
struct iterationState *it;
if (gamestate != GS_LEVEL) if (gamestate != GS_LEVEL)
return luaL_error(L, "This function can only be used in a level!"); return luaL_error(L, "This function can only be used in a level!");
luaL_checkoption(L, 1, iter_opt[0], iter_opt);
lua_pushcfunction(L, lib_iterateThinkers); lua_pushvalue(L, lua_upvalueindex(1));
lua_pushvalue(L, 1); it = lua_newuserdata(L, sizeof(struct iterationState));
luaL_getmetatable(L, META_ITERATIONSTATE);
lua_setmetatable(L, -2);
it->filter = iter_funcs[luaL_checkoption(L, 1, "mobj", iter_opt)];
it->next = LUA_REFNIL;
return 2; return 2;
} }
#undef push_thinker
int LUA_ThinkerLib(lua_State *L) int LUA_ThinkerLib(lua_State *L)
{ {
luaL_newmetatable(L, META_ITERATIONSTATE);
lua_pushcfunction(L, iterationState_gc);
lua_setfield(L, -2, "__gc");
lua_pop(L, 1);
lua_createtable(L, 0, 1); lua_createtable(L, 0, 1);
lua_pushcfunction(L, lib_startIterate); lua_pushcfunction(L, lib_iterateThinkers);
lua_pushcclosure(L, lib_startIterate, 1);
lua_setfield(L, -2, "iterate"); lua_setfield(L, -2, "iterate");
lua_setglobal(L, "thinkers"); lua_setglobal(L, "thinkers");
return 0; return 0;

View file

@ -2113,6 +2113,7 @@ void T_EachTimeThinker(levelspecthink_t *eachtime)
boolean inAndOut = false; boolean inAndOut = false;
boolean floortouch = false; boolean floortouch = false;
fixed_t bottomheight, topheight; fixed_t bottomheight, topheight;
msecnode_t *node;
for (i = 0; i < MAXPLAYERS; i++) for (i = 0; i < MAXPLAYERS; i++)
{ {
@ -2174,7 +2175,23 @@ void T_EachTimeThinker(levelspecthink_t *eachtime)
if ((netgame || multiplayer) && players[j].spectator) if ((netgame || multiplayer) && players[j].spectator)
continue; continue;
if (players[j].mo->subsector->sector != targetsec) if (players[j].mo->subsector->sector == targetsec)
;
else if (sec->flags & SF_TRIGGERSPECIAL_TOUCH)
{
boolean insector = false;
for (node = players[j].mo->touching_sectorlist; node; node = node->m_sectorlist_next)
{
if (node->m_sector == targetsec)
{
insector = true;
break;
}
}
if (!insector)
continue;
}
else
continue; continue;
topheight = P_GetSpecialTopZ(players[j].mo, sec, targetsec); topheight = P_GetSpecialTopZ(players[j].mo, sec, targetsec);
@ -2224,7 +2241,27 @@ void T_EachTimeThinker(levelspecthink_t *eachtime)
if ((netgame || multiplayer) && players[i].spectator) if ((netgame || multiplayer) && players[i].spectator)
continue; continue;
if (players[i].mo->subsector->sector != sec) if (players[i].mo->subsector->sector == sec)
;
else if (sec->flags & SF_TRIGGERSPECIAL_TOUCH)
{
boolean insector = false;
for (node = players[i].mo->touching_sectorlist; node; node = node->m_sectorlist_next)
{
if (node->m_sector == sec)
{
insector = true;
break;
}
}
if (!insector)
continue;
}
else
continue;
if (!(players[i].mo->subsector->sector == sec
|| P_PlayerTouchingSectorSpecial(&players[i], 2, (GETSECSPECIAL(sec->special, 2))) == sec))
continue; continue;
if (floortouch == true && P_IsObjectOnGroundIn(players[i].mo, sec)) if (floortouch == true && P_IsObjectOnGroundIn(players[i].mo, sec))

View file

@ -1117,6 +1117,8 @@ static boolean PIT_CheckThing(mobj_t *thing)
if (iwassprung) // this spring caused you to gain MFE_SPRUNG just now... if (iwassprung) // this spring caused you to gain MFE_SPRUNG just now...
return false; // "cancel" P_TryMove via blocking so you keep your current position return false; // "cancel" P_TryMove via blocking so you keep your current position
} }
else if (tmthing->flags & MF_SPRING && (thing->player || thing->flags & MF_PUSHABLE))
; // Fix a few nasty spring-jumping bugs that happen sometimes.
// Monitors are not treated as solid to players who are jumping, spinning or gliding, // Monitors are not treated as solid to players who are jumping, spinning or gliding,
// unless it's a CTF team monitor and you're on the wrong team // unless it's a CTF team monitor and you're on the wrong team
else if (thing->flags & MF_MONITOR && tmthing->player else if (thing->flags & MF_MONITOR && tmthing->player
@ -1155,11 +1157,13 @@ static boolean PIT_CheckThing(mobj_t *thing)
topz = thing->z - thing->scale; // FixedMul(FRACUNIT, thing->scale), but thing->scale == FRACUNIT in base scale anyways topz = thing->z - thing->scale; // FixedMul(FRACUNIT, thing->scale), but thing->scale == FRACUNIT in base scale anyways
if (thing->flags & MF_SPRING)
;
// 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)
// since return false doesn't handle momentum properly, // since return false doesn't handle momentum properly,
// we lie to P_TryMove() so it's always too high // we lie to P_TryMove() so it's always too high
if (tmthing->player && tmthing->z + tmthing->height > topz else if (tmthing->player && tmthing->z + tmthing->height > topz
&& tmthing->z + tmthing->height < tmthing->ceilingz) && tmthing->z + tmthing->height < tmthing->ceilingz)
{ {
if (thing->flags & MF_GRENADEBOUNCE && (thing->flags & MF_MONITOR || thing->flags2 & MF2_STANDONME)) // Gold monitor hack... if (thing->flags & MF_GRENADEBOUNCE && (thing->flags & MF_MONITOR || thing->flags2 & MF2_STANDONME)) // Gold monitor hack...
@ -1171,8 +1175,6 @@ static boolean PIT_CheckThing(mobj_t *thing)
#endif #endif
tmfloorthing = thing; // needed for side collision tmfloorthing = thing; // needed for side collision
} }
else if (thing->flags & MF_SPRING)
;
else if (topz < tmceilingz && tmthing->z <= thing->z+thing->height) else if (topz < tmceilingz && tmthing->z <= thing->z+thing->height)
{ {
tmceilingz = topz; tmceilingz = topz;
@ -1201,11 +1203,13 @@ static boolean PIT_CheckThing(mobj_t *thing)
topz = thing->z + thing->height + thing->scale; // FixedMul(FRACUNIT, thing->scale), but thing->scale == FRACUNIT in base scale anyways topz = thing->z + thing->height + thing->scale; // FixedMul(FRACUNIT, thing->scale), but thing->scale == FRACUNIT in base scale anyways
if (thing->flags & MF_SPRING)
;
// 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)
// since return false doesn't handle momentum properly, // since return false doesn't handle momentum properly,
// we lie to P_TryMove() so it's always too high // we lie to P_TryMove() so it's always too high
if (tmthing->player && tmthing->z < topz else if (tmthing->player && tmthing->z < topz
&& tmthing->z > tmthing->floorz) && tmthing->z > tmthing->floorz)
{ {
if (thing->flags & MF_GRENADEBOUNCE && (thing->flags & MF_MONITOR || thing->flags2 & MF2_STANDONME)) // Gold monitor hack... if (thing->flags & MF_GRENADEBOUNCE && (thing->flags & MF_MONITOR || thing->flags2 & MF2_STANDONME)) // Gold monitor hack...
@ -1217,8 +1221,6 @@ static boolean PIT_CheckThing(mobj_t *thing)
#endif #endif
tmfloorthing = thing; // needed for side collision tmfloorthing = thing; // needed for side collision
} }
else if (thing->flags & MF_SPRING)
;
else if (topz > tmfloorz && tmthing->z+tmthing->height >= thing->z) else if (topz > tmfloorz && tmthing->z+tmthing->height >= thing->z)
{ {
tmfloorz = topz; tmfloorz = topz;

View file

@ -2560,10 +2560,18 @@ boolean P_CheckSolidLava(mobj_t *mo, ffloor_t *rover)
I_Assert(mo != NULL); I_Assert(mo != NULL);
I_Assert(!P_MobjWasRemoved(mo)); I_Assert(!P_MobjWasRemoved(mo));
{
fixed_t topheight =
#ifdef ESLOPE
*rover->t_slope ? P_GetZAt(*rover->t_slope, mo->x, mo->y) :
#endif
*rover->topheight;
if (rover->flags & FF_SWIMMABLE && GETSECSPECIAL(rover->master->frontsector->special, 1) == 3 if (rover->flags & FF_SWIMMABLE && GETSECSPECIAL(rover->master->frontsector->special, 1) == 3
&& !(rover->master->flags & ML_BLOCKMONSTERS) && !(rover->master->flags & ML_BLOCKMONSTERS)
&& ((rover->master->flags & ML_EFFECT3) || mo->z-mo->momz > *rover->topheight - FixedMul(16*FRACUNIT, mo->scale))) && ((rover->master->flags & ML_EFFECT3) || mo->z-mo->momz > topheight - FixedMul(16*FRACUNIT, mo->scale)))
return true; return true;
}
return false; return false;
} }
@ -2802,7 +2810,7 @@ static boolean P_ZMovement(mobj_t *mo)
mo->z = mo->floorz; mo->z = mo->floorz;
#ifdef ESLOPE #ifdef ESLOPE
if (mo->standingslope) // You're still on the ground; why are we here? if (!(mo->flags & MF_MISSILE) && mo->standingslope) // You're still on the ground; why are we here?
{ {
mo->momz = 0; mo->momz = 0;
return true; return true;
@ -3578,11 +3586,17 @@ static boolean P_SceneryZMovement(mobj_t *mo)
// //
boolean P_CanRunOnWater(player_t *player, ffloor_t *rover) boolean P_CanRunOnWater(player_t *player, ffloor_t *rover)
{ {
fixed_t topheight =
#ifdef ESLOPE
*rover->t_slope ? P_GetZAt(*rover->t_slope, player->mo->x, player->mo->y) :
#endif
*rover->topheight;
if (!player->powers[pw_carry] && !player->homing if (!player->powers[pw_carry] && !player->homing
&& ((player->powers[pw_super] || player->charflags & SF_RUNONWATER || player->dashmode >= 3*TICRATE) && player->mo->ceilingz-*rover->topheight >= player->mo->height) && ((player->powers[pw_super] || player->charflags & SF_RUNONWATER || player->dashmode >= 3*TICRATE) && player->mo->ceilingz-topheight >= player->mo->height)
&& (rover->flags & FF_SWIMMABLE) && !(player->pflags & PF_SPINNING) && player->speed > FixedMul(player->runspeed, player->mo->scale) && (rover->flags & FF_SWIMMABLE) && !(player->pflags & PF_SPINNING) && player->speed > FixedMul(player->runspeed, player->mo->scale)
&& !(player->pflags & PF_SLIDING) && !(player->pflags & PF_SLIDING)
&& abs(player->mo->z - *rover->topheight) < FixedMul(30*FRACUNIT, player->mo->scale)) && abs(player->mo->z - topheight) < FixedMul(30*FRACUNIT, player->mo->scale))
return true; return true;
return false; return false;
@ -8515,6 +8529,7 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type)
break; break;
case MT_EGGCAPSULE: case MT_EGGCAPSULE:
mobj->extravalue1 = -1; // timer for how long a player has been at the capsule mobj->extravalue1 = -1; // timer for how long a player has been at the capsule
break;
case MT_REDTEAMRING: case MT_REDTEAMRING:
mobj->color = skincolor_redteam; mobj->color = skincolor_redteam;
break; break;
@ -9714,6 +9729,16 @@ void P_SpawnMapThing(mapthing_t *mthing)
mobj = P_SpawnMobj(x, y, z, i); mobj = P_SpawnMobj(x, y, z, i);
mobj->spawnpoint = mthing; mobj->spawnpoint = mthing;
#ifdef HAVE_BLUA
if (LUAh_MapThingSpawn(mobj, mthing))
{
if (P_MobjWasRemoved(mobj))
return;
}
else if (P_MobjWasRemoved(mobj))
return;
else
#endif
switch(mobj->type) switch(mobj->type)
{ {
case MT_SKYBOX: case MT_SKYBOX:

View file

@ -456,7 +456,8 @@ void P_ParseAnimationDefintion(SINT8 istexture)
// Search for existing animdef // Search for existing animdef
for (i = 0; i < maxanims; i++) for (i = 0; i < maxanims; i++)
if (stricmp(animdefsToken, animdefs[i].startname) == 0) if (animdefs[i].istexture == istexture // Check if it's the same type!
&& stricmp(animdefsToken, animdefs[i].startname) == 0)
{ {
//CONS_Alert(CONS_NOTICE, "Duplicate animation: %s\n", animdefsToken); //CONS_Alert(CONS_NOTICE, "Duplicate animation: %s\n", animdefsToken);
@ -2444,12 +2445,22 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec)
case 414: // Play SFX case 414: // Play SFX
{ {
fixed_t sfxnum; INT32 sfxnum;
sfxnum = sides[line->sidenum[0]].toptexture; sfxnum = sides[line->sidenum[0]].toptexture;
if (line->tag != 0 && line->flags & ML_EFFECT5) if (sfxnum == sfx_None)
return; // Do nothing!
if (sfxnum < sfx_None || sfxnum >= NUMSFX)
{ {
CONS_Debug(DBG_GAMELOGIC, "Line type 414 Executor: sfx number %d is invalid!\n", sfxnum);
return;
}
if (line->tag != 0) // Do special stuff only if a non-zero linedef tag is set
{
if (line->flags & ML_EFFECT5) // Repeat Midtexture
{
// Additionally play the sound from tagged sectors' soundorgs
sector_t *sec; sector_t *sec;
while ((secnum = P_FindSectorFromLineTag(line, secnum)) >= 0) while ((secnum = P_FindSectorFromLineTag(line, secnum)) >= 0)
@ -2458,7 +2469,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec)
S_StartSound(&sec->soundorg, sfxnum); S_StartSound(&sec->soundorg, sfxnum);
} }
} }
else if (line->tag != 0 && mo) else if (mo) // A mobj must have triggered the executor
{ {
// Only trigger if mobj is touching the tag // Only trigger if mobj is touching the tag
ffloor_t *rover; ffloor_t *rover;
@ -2484,9 +2495,8 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec)
if (!foundit) if (!foundit)
return; return;
} }
}
if (sfxnum < NUMSFX && sfxnum > sfx_None)
{
if (line->flags & ML_NOCLIMB) if (line->flags & ML_NOCLIMB)
{ {
// play the sound from nowhere, but only if display player triggered it // play the sound from nowhere, but only if display player triggered it
@ -2512,7 +2522,6 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec)
S_StartSound(mo, sfxnum); S_StartSound(mo, sfxnum);
} }
} }
}
break; break;
case 415: // Run a script case 415: // Run a script
@ -3569,7 +3578,7 @@ static boolean P_ThingIsOnThe3DFloor(mobj_t *mo, sector_t *sector, sector_t *tar
// //
// Is player standing on the sector's "ground"? // Is player standing on the sector's "ground"?
// //
static inline boolean P_MobjReadyToTrigger(mobj_t *mo, sector_t *sec) static boolean P_MobjReadyToTrigger(mobj_t *mo, sector_t *sec)
{ {
if (mo->eflags & MFE_VERTICALFLIP) if (mo->eflags & MFE_VERTICALFLIP)
return (mo->z+mo->height == P_GetSpecialTopZ(mo, sec, sec) && sec->flags & SF_FLIPSPECIAL_CEILING); return (mo->z+mo->height == P_GetSpecialTopZ(mo, sec, sec) && sec->flags & SF_FLIPSPECIAL_CEILING);
@ -3702,14 +3711,49 @@ void P_ProcessSpecialSector(player_t *player, sector_t *sector, sector_t *rovers
{ {
if (roversector) if (roversector)
{ {
if (players[i].mo->subsector->sector != roversector) if (players[i].mo->subsector->sector == roversector)
;
else if (sector->flags & SF_TRIGGERSPECIAL_TOUCH)
{
boolean insector = false;
msecnode_t *node;
for (node = players[i].mo->touching_sectorlist; node; node = node->m_sectorlist_next)
{
if (node->m_sector == roversector)
{
insector = true;
break;
}
}
if (!insector)
goto DoneSection2; goto DoneSection2;
}
else
goto DoneSection2;
if (!P_ThingIsOnThe3DFloor(players[i].mo, sector, roversector)) if (!P_ThingIsOnThe3DFloor(players[i].mo, sector, roversector))
goto DoneSection2; goto DoneSection2;
} }
else else
{ {
if (players[i].mo->subsector->sector != sector) if (players[i].mo->subsector->sector == sector)
;
else if (sector->flags & SF_TRIGGERSPECIAL_TOUCH)
{
boolean insector = false;
msecnode_t *node;
for (node = players[i].mo->touching_sectorlist; node; node = node->m_sectorlist_next)
{
if (node->m_sector == sector)
{
insector = true;
break;
}
}
if (!insector)
goto DoneSection2;
}
else
goto DoneSection2; goto DoneSection2;
if (special == 3 && !P_MobjReadyToTrigger(players[i].mo, sector)) if (special == 3 && !P_MobjReadyToTrigger(players[i].mo, sector))
@ -4490,6 +4534,7 @@ sector_t *P_ThingOnSpecial3DFloor(mobj_t *mo)
{ {
sector_t *sector; sector_t *sector;
ffloor_t *rover; ffloor_t *rover;
fixed_t topheight, bottomheight;
sector = mo->subsector->sector; sector = mo->subsector->sector;
if (!sector->ffloors) if (!sector->ffloors)
@ -4497,8 +4542,6 @@ sector_t *P_ThingOnSpecial3DFloor(mobj_t *mo)
for (rover = sector->ffloors; rover; rover = rover->next) for (rover = sector->ffloors; rover; rover = rover->next)
{ {
fixed_t topheight, bottomheight;
if (!rover->master->frontsector->special) if (!rover->master->frontsector->special)
continue; continue;
@ -4546,6 +4589,8 @@ sector_t *P_ThingOnSpecial3DFloor(mobj_t *mo)
return NULL; return NULL;
} }
#define TELEPORTED (player->mo->subsector->sector != originalsector)
/** Checks if a player is standing on or is inside a 3D floor (e.g. water) and /** Checks if a player is standing on or is inside a 3D floor (e.g. water) and
* applies any specials. * applies any specials.
* *
@ -4554,12 +4599,12 @@ sector_t *P_ThingOnSpecial3DFloor(mobj_t *mo)
*/ */
static void P_PlayerOnSpecial3DFloor(player_t *player, sector_t *sector) static void P_PlayerOnSpecial3DFloor(player_t *player, sector_t *sector)
{ {
sector_t *originalsector = player->mo->subsector->sector;
ffloor_t *rover; ffloor_t *rover;
fixed_t topheight, bottomheight;
for (rover = sector->ffloors; rover; rover = rover->next) for (rover = sector->ffloors; rover; rover = rover->next)
{ {
fixed_t topheight, bottomheight;
if (!rover->master->frontsector->special) if (!rover->master->frontsector->special)
continue; continue;
@ -4603,7 +4648,10 @@ static void P_PlayerOnSpecial3DFloor(player_t *player, sector_t *sector)
// This FOF has the special we're looking for, but are we allowed to touch it? // This FOF has the special we're looking for, but are we allowed to touch it?
if (sector == player->mo->subsector->sector if (sector == player->mo->subsector->sector
|| (rover->master->frontsector->flags & SF_TRIGGERSPECIAL_TOUCH)) || (rover->master->frontsector->flags & SF_TRIGGERSPECIAL_TOUCH))
{
P_ProcessSpecialSector(player, rover->master->frontsector, sector); P_ProcessSpecialSector(player, rover->master->frontsector, sector);
if TELEPORTED return;
}
} }
// Allow sector specials to be applied to polyobjects! // Allow sector specials to be applied to polyobjects!
@ -4690,6 +4738,7 @@ static void P_PlayerOnSpecial3DFloor(player_t *player, sector_t *sector)
} }
P_ProcessSpecialSector(player, polysec, sector); P_ProcessSpecialSector(player, polysec, sector);
if TELEPORTED return;
po = (polyobj_t *)(po->link.next); po = (polyobj_t *)(po->link.next);
} }
@ -4794,40 +4843,43 @@ static void P_RunSpecialSectorCheck(player_t *player, sector_t *sector)
*/ */
void P_PlayerInSpecialSector(player_t *player) void P_PlayerInSpecialSector(player_t *player)
{ {
sector_t *sector; sector_t *originalsector;
sector_t *loopsector;
msecnode_t *node; msecnode_t *node;
if (!player->mo) if (!player->mo)
return; return;
// Do your ->subsector->sector first originalsector = player->mo->subsector->sector;
sector = player->mo->subsector->sector;
P_PlayerOnSpecial3DFloor(player, sector);
// After P_PlayerOnSpecial3DFloor, recheck if the player is in that sector,
// because the player can be teleported in between these times.
if (sector == player->mo->subsector->sector)
P_RunSpecialSectorCheck(player, sector);
// Iterate through touching_sectorlist P_PlayerOnSpecial3DFloor(player, originalsector); // Handle FOFs first.
if TELEPORTED return;
P_RunSpecialSectorCheck(player, originalsector);
if TELEPORTED return;
// Iterate through touching_sectorlist for SF_TRIGGERSPECIAL_TOUCH
for (node = player->mo->touching_sectorlist; node; node = node->m_sectorlist_next) for (node = player->mo->touching_sectorlist; node; node = node->m_sectorlist_next)
{ {
sector = node->m_sector; loopsector = node->m_sector;
if (sector == player->mo->subsector->sector) // Don't duplicate if (loopsector == originalsector) // Don't duplicate
continue; continue;
// Check 3D floors... // Check 3D floors...
P_PlayerOnSpecial3DFloor(player, sector); P_PlayerOnSpecial3DFloor(player, loopsector);
if TELEPORTED return;
if (!(sector->flags & SF_TRIGGERSPECIAL_TOUCH)) if (!(loopsector->flags & SF_TRIGGERSPECIAL_TOUCH))
return; continue;
// After P_PlayerOnSpecial3DFloor, recheck if the player is in that sector,
// because the player can be teleported in between these times. P_RunSpecialSectorCheck(player, loopsector);
if (sector == player->mo->subsector->sector) if TELEPORTED return;
P_RunSpecialSectorCheck(player, sector);
} }
} }
#undef TELEPORTED
/** Animate planes, scroll walls, etc. and keeps track of level timelimit and exits if time is up. /** Animate planes, scroll walls, etc. and keeps track of level timelimit and exits if time is up.
* *
* \sa P_CheckTimeLimit, P_CheckPointLimit * \sa P_CheckTimeLimit, P_CheckPointLimit

View file

@ -1706,9 +1706,8 @@ void P_DoPlayerExit(player_t *player)
#define SPACESPECIAL 12 #define SPACESPECIAL 12
boolean P_InSpaceSector(mobj_t *mo) // Returns true if you are in space boolean P_InSpaceSector(mobj_t *mo) // Returns true if you are in space
{ {
sector_t *sector; sector_t *sector = mo->subsector->sector;
fixed_t topheight, bottomheight;
sector = mo->subsector->sector;
if (GETSECSPECIAL(sector->special, 1) == SPACESPECIAL) if (GETSECSPECIAL(sector->special, 1) == SPACESPECIAL)
return true; return true;
@ -1721,11 +1720,18 @@ boolean P_InSpaceSector(mobj_t *mo) // Returns true if you are in space
{ {
if (GETSECSPECIAL(rover->master->frontsector->special, 1) != SPACESPECIAL) if (GETSECSPECIAL(rover->master->frontsector->special, 1) != SPACESPECIAL)
continue; continue;
#ifdef ESLOPE
topheight = *rover->t_slope ? P_GetZAt(*rover->t_slope, mo->x, mo->y) : *rover->topheight;
bottomheight = *rover->b_slope ? P_GetZAt(*rover->b_slope, mo->x, mo->y) : *rover->bottomheight;
#else
topheight = *rover->topheight;
bottomheight = *rover->bottomheight;
#endif
if (mo->z > *rover->topheight) if (mo->z + (mo->height/2) > topheight)
continue; continue;
if (mo->z + (mo->height/2) < *rover->bottomheight) if (mo->z + (mo->height/2) < bottomheight)
continue; continue;
return true; return true;
@ -1737,9 +1743,10 @@ boolean P_InSpaceSector(mobj_t *mo) // Returns true if you are in space
boolean P_InQuicksand(mobj_t *mo) // Returns true if you are in quicksand boolean P_InQuicksand(mobj_t *mo) // Returns true if you are in quicksand
{ {
sector_t *sector; sector_t *sector = mo->subsector->sector;
fixed_t topheight, bottomheight;
sector = mo->subsector->sector; fixed_t flipoffset = ((mo->eflags & MFE_VERTICALFLIP) ? (mo->height/2) : 0);
if (sector->ffloors) if (sector->ffloors)
{ {
@ -1753,10 +1760,18 @@ boolean P_InQuicksand(mobj_t *mo) // Returns true if you are in quicksand
if (!(rover->flags & FF_QUICKSAND)) if (!(rover->flags & FF_QUICKSAND))
continue; continue;
if (mo->z > *rover->topheight) #ifdef ESLOPE
topheight = *rover->t_slope ? P_GetZAt(*rover->t_slope, mo->x, mo->y) : *rover->topheight;
bottomheight = *rover->b_slope ? P_GetZAt(*rover->b_slope, mo->x, mo->y) : *rover->bottomheight;
#else
topheight = *rover->topheight;
bottomheight = *rover->bottomheight;
#endif
if (mo->z + flipoffset > topheight)
continue; continue;
if (mo->z + (mo->height/2) < *rover->bottomheight) if (mo->z + (mo->height/2) + flipoffset < bottomheight)
continue; continue;
return true; return true;
@ -2067,6 +2082,7 @@ static void P_CheckQuicksand(player_t *player)
{ {
ffloor_t *rover; ffloor_t *rover;
fixed_t sinkspeed, friction; fixed_t sinkspeed, friction;
fixed_t topheight, bottomheight;
if (!(player->mo->subsector->sector->ffloors && player->mo->momz <= 0)) if (!(player->mo->subsector->sector->ffloors && player->mo->momz <= 0))
return; return;
@ -2078,16 +2094,38 @@ static void P_CheckQuicksand(player_t *player)
if (!(rover->flags & FF_QUICKSAND)) if (!(rover->flags & FF_QUICKSAND))
continue; continue;
if (*rover->topheight >= player->mo->z && *rover->bottomheight < player->mo->z + player->mo->height) #ifdef ESLOPE
topheight = *rover->t_slope ? P_GetZAt(*rover->t_slope, player->mo->x, player->mo->y) : *rover->topheight;
bottomheight = *rover->b_slope ? P_GetZAt(*rover->b_slope, player->mo->x, player->mo->y) : *rover->bottomheight;
#else
topheight = *rover->topheight;
bottomheight = *rover->bottomheight;
#endif
if (topheight >= player->mo->z && bottomheight < player->mo->z + player->mo->height)
{ {
sinkspeed = abs(rover->master->v1->x - rover->master->v2->x)>>1; sinkspeed = abs(rover->master->v1->x - rover->master->v2->x)>>1;
sinkspeed = FixedDiv(sinkspeed,TICRATE*FRACUNIT); sinkspeed = FixedDiv(sinkspeed,TICRATE*FRACUNIT);
if (player->mo->eflags & MFE_VERTICALFLIP)
{
fixed_t ceilingheight = P_GetCeilingZ(player->mo, player->mo->subsector->sector, player->mo->x, player->mo->y, NULL);
player->mo->z += sinkspeed;
if (player->mo->z + player->mo->height >= ceilingheight)
player->mo->z = ceilingheight - player->mo->height;
}
else
{
fixed_t floorheight = P_GetFloorZ(player->mo, player->mo->subsector->sector, player->mo->x, player->mo->y, NULL);
player->mo->z -= sinkspeed; player->mo->z -= sinkspeed;
if (player->mo->z <= player->mo->subsector->sector->floorheight) if (player->mo->z <= floorheight)
player->mo->z = player->mo->subsector->sector->floorheight; player->mo->z = floorheight;
}
friction = abs(rover->master->v1->y - rover->master->v2->y)>>6; friction = abs(rover->master->v1->y - rover->master->v2->y)>>6;
@ -2437,11 +2475,11 @@ static void P_DoClimbing(player_t *player)
floorclimb = true; floorclimb = true;
#ifdef ESLOPE #ifdef ESLOPE
bottomheight = *rover->b_slope ? P_GetZAt(*rover->b_slope, player->mo->x, player->mo->y) : *rover->bottomheight;
topheight = *rover->t_slope ? P_GetZAt(*rover->t_slope, player->mo->x, player->mo->y) : *rover->topheight; topheight = *rover->t_slope ? P_GetZAt(*rover->t_slope, player->mo->x, player->mo->y) : *rover->topheight;
bottomheight = *rover->b_slope ? P_GetZAt(*rover->b_slope, player->mo->x, player->mo->y) : *rover->bottomheight;
#else #else
bottomheight = *rover->bottomheight;
topheight = *rover->topheight; topheight = *rover->topheight;
bottomheight = *rover->bottomheight;
#endif #endif
// Only supports rovers that are moving like an 'elevator', not just the top or bottom. // Only supports rovers that are moving like an 'elevator', not just the top or bottom.
@ -2630,13 +2668,20 @@ static void P_DoClimbing(player_t *player)
// Is there a FOF directly below that we can move onto? // Is there a FOF directly below that we can move onto?
if (glidesector->sector->ffloors) if (glidesector->sector->ffloors)
{ {
fixed_t topheight;
ffloor_t *rover; ffloor_t *rover;
for (rover = glidesector->sector->ffloors; rover; rover = rover->next) for (rover = glidesector->sector->ffloors; rover; rover = rover->next)
{ {
if (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_BLOCKPLAYER) || (rover->flags & FF_BUSTUP)) if (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_BLOCKPLAYER) || (rover->flags & FF_BUSTUP))
continue; continue;
if (*rover->topheight > ceilingheight - FixedMul(16*FRACUNIT, player->mo->scale)) #ifdef ESLOPE
topheight = *rover->t_slope ? P_GetZAt(*rover->t_slope, player->mo->x, player->mo->y) : *rover->topheight;
#else
topheight = *rover->topheight;
#endif
if (topheight > ceilingheight - FixedMul(16*FRACUNIT, player->mo->scale))
{ {
foundfof = true; foundfof = true;
break; break;
@ -3014,14 +3059,12 @@ static void P_DoTeeter(player_t *player)
{ {
if (!(rover->flags & FF_EXISTS)) continue; if (!(rover->flags & FF_EXISTS)) continue;
#ifdef ESLOPE
topheight = *rover->t_slope ? P_GetZAt(*rover->t_slope, player->mo->x, player->mo->y) : *rover->topheight;
bottomheight = *rover->b_slope ? P_GetZAt(*rover->b_slope, player->mo->x, player->mo->y) : *rover->bottomheight;
#else
topheight = *rover->topheight; topheight = *rover->topheight;
bottomheight = *rover->bottomheight; bottomheight = *rover->bottomheight;
#ifdef ESLOPE
if (*rover->t_slope)
topheight = P_GetZAt(*rover->t_slope, player->mo->x, player->mo->y);
if (*rover->b_slope)
bottomheight = P_GetZAt(*rover->b_slope, player->mo->x, player->mo->y);
#endif #endif
if (P_CheckSolidLava(player->mo, rover)) if (P_CheckSolidLava(player->mo, rover))
@ -9007,13 +9050,23 @@ static void P_CalcPostImg(player_t *player)
else if (sector->ffloors) else if (sector->ffloors)
{ {
ffloor_t *rover; ffloor_t *rover;
fixed_t topheight;
fixed_t bottomheight;
for (rover = sector->ffloors; rover; rover = rover->next) for (rover = sector->ffloors; rover; rover = rover->next)
{ {
if (!(rover->flags & FF_EXISTS)) if (!(rover->flags & FF_EXISTS))
continue; continue;
if (pviewheight >= *rover->topheight || pviewheight <= *rover->bottomheight) #ifdef ESLOPE
topheight = *rover->t_slope ? P_GetZAt(*rover->t_slope, player->mo->x, player->mo->y) : *rover->topheight;
bottomheight = *rover->b_slope ? P_GetZAt(*rover->b_slope, player->mo->x, player->mo->y) : *rover->bottomheight;
#else
topheight = *rover->topheight;
bottomheight = *rover->bottomheight;
#endif
if (pviewheight >= topheight || pviewheight <= bottomheight)
continue; continue;
if (P_FindSpecialLineFromTag(13, rover->master->frontsector->tag, -1) != -1) if (P_FindSpecialLineFromTag(13, rover->master->frontsector->tag, -1) != -1)
@ -9025,13 +9078,23 @@ static void P_CalcPostImg(player_t *player)
if (sector->ffloors) if (sector->ffloors)
{ {
ffloor_t *rover; ffloor_t *rover;
fixed_t topheight;
fixed_t bottomheight;
for (rover = sector->ffloors; rover; rover = rover->next) for (rover = sector->ffloors; rover; rover = rover->next)
{ {
if (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_SWIMMABLE) || rover->flags & FF_BLOCKPLAYER) if (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_SWIMMABLE) || rover->flags & FF_BLOCKPLAYER)
continue; continue;
if (pviewheight >= *rover->topheight || pviewheight <= *rover->bottomheight) #ifdef ESLOPE
topheight = *rover->t_slope ? P_GetZAt(*rover->t_slope, player->mo->x, player->mo->y) : *rover->topheight;
bottomheight = *rover->b_slope ? P_GetZAt(*rover->b_slope, player->mo->x, player->mo->y) : *rover->bottomheight;
#else
topheight = *rover->topheight;
bottomheight = *rover->bottomheight;
#endif
if (pviewheight >= topheight || pviewheight <= bottomheight)
continue; continue;
*type = postimg_water; *type = postimg_water;
@ -9137,8 +9200,9 @@ void P_PlayerThink(player_t *player)
if (player->panim != PA_ABILITY) if (player->panim != PA_ABILITY)
P_SetPlayerMobjState(player->mo, S_PLAY_GLIDE); P_SetPlayerMobjState(player->mo, S_PLAY_GLIDE);
} }
else if ((player->pflags & PF_JUMPED && !(player->pflags & PF_NOJUMPDAMAGE)) else if ((player->pflags & PF_JUMPED && !(player->pflags & PF_NOJUMPDAMAGE)
&& ((player->charflags & SF_NOJUMPSPIN && player->panim != PA_ROLL) && (player->mo->state-states != S_PLAY_FLOAT && player->mo->state-states != S_PLAY_FLOAT_RUN))
&& ((((player->charflags & (SF_NOJUMPSPIN|SF_NOJUMPDAMAGE)) == (SF_NOJUMPSPIN|SF_NOJUMPDAMAGE)) && player->panim != PA_ROLL)
|| (!(player->charflags & SF_NOJUMPSPIN) && player->panim != PA_JUMP))) || (!(player->charflags & SF_NOJUMPSPIN) && player->panim != PA_JUMP)))
{ {
if (!(player->charflags & SF_NOJUMPSPIN)) if (!(player->charflags & SF_NOJUMPSPIN))
@ -9262,6 +9326,7 @@ void P_PlayerThink(player_t *player)
// check water content, set stuff in mobj // check water content, set stuff in mobj
P_MobjCheckWater(player->mo); P_MobjCheckWater(player->mo);
#ifndef SECTORSPECIALSAFTERTHINK
#ifdef POLYOBJECTS #ifdef POLYOBJECTS
if (player->onconveyor != 1 || !P_IsObjectOnGround(player->mo)) if (player->onconveyor != 1 || !P_IsObjectOnGround(player->mo))
#endif #endif
@ -9270,6 +9335,7 @@ void P_PlayerThink(player_t *player)
if (!player->spectator) if (!player->spectator)
P_PlayerInSpecialSector(player); P_PlayerInSpecialSector(player);
#endif
if (player->playerstate == PST_DEAD) if (player->playerstate == PST_DEAD)
{ {
@ -9661,6 +9727,17 @@ void P_PlayerAfterThink(player_t *player)
cmd = &player->cmd; cmd = &player->cmd;
#ifdef SECTORSPECIALSAFTERTHINK
#ifdef POLYOBJECTS
if (player->onconveyor != 1 || !P_IsObjectOnGround(player->mo))
#endif
player->onconveyor = 0;
// check special sectors : damage & secrets
if (!player->spectator)
P_PlayerInSpecialSector(player);
#endif
if (splitscreen && player == &players[secondarydisplayplayer]) if (splitscreen && player == &players[secondarydisplayplayer])
thiscam = &camera2; thiscam = &camera2;
else if (player == &players[displayplayer]) else if (player == &players[displayplayer])

View file

@ -1222,6 +1222,9 @@ static void R_Subsector(size_t num)
while (count--) while (count--)
{ {
// CONS_Debug(DBG_GAMELOGIC, "Adding normal line %d...(%d)\n", line->linedef-lines, leveltime); // CONS_Debug(DBG_GAMELOGIC, "Adding normal line %d...(%d)\n", line->linedef-lines, leveltime);
#ifdef POLYOBJECTS
if (!line->polyseg) // ignore segs that belong to polyobjects
#endif
R_AddLine(line); R_AddLine(line);
line++; line++;
curline = NULL; /* cph 2001/11/18 - must clear curline now we're done with it, so stuff doesn't try using it for other things */ curline = NULL; /* cph 2001/11/18 - must clear curline now we're done with it, so stuff doesn't try using it for other things */

View file

@ -1151,23 +1151,24 @@ static void R_InitExtraColormaps(void)
for (cfile = clump = 0; cfile < numwadfiles; cfile++, clump = 0) for (cfile = clump = 0; cfile < numwadfiles; cfile++, clump = 0)
{ {
startnum = W_CheckNumForNamePwad("C_START", cfile, clump); startnum = W_CheckNumForNamePwad("C_START", cfile, clump);
if (startnum == LUMPERROR) if (startnum == INT16_MAX)
continue; continue;
endnum = W_CheckNumForNamePwad("C_END", cfile, clump); endnum = W_CheckNumForNamePwad("C_END", cfile, clump);
if (endnum == LUMPERROR) if (endnum == INT16_MAX)
I_Error("R_InitExtraColormaps: C_START without C_END\n"); I_Error("R_InitExtraColormaps: C_START without C_END\n");
if (WADFILENUM(startnum) != WADFILENUM(endnum)) // This shouldn't be possible when you use the Pwad function, silly
I_Error("R_InitExtraColormaps: C_START and C_END in different wad files!\n"); //if (WADFILENUM(startnum) != WADFILENUM(endnum))
//I_Error("R_InitExtraColormaps: C_START and C_END in different wad files!\n");
if (numcolormaplumps >= maxcolormaplumps) if (numcolormaplumps >= maxcolormaplumps)
maxcolormaplumps *= 2; maxcolormaplumps *= 2;
colormaplumps = Z_Realloc(colormaplumps, colormaplumps = Z_Realloc(colormaplumps,
sizeof (*colormaplumps) * maxcolormaplumps, PU_STATIC, NULL); sizeof (*colormaplumps) * maxcolormaplumps, PU_STATIC, NULL);
colormaplumps[numcolormaplumps].wadfile = WADFILENUM(startnum); colormaplumps[numcolormaplumps].wadfile = cfile;
colormaplumps[numcolormaplumps].firstlump = LUMPNUM(startnum+1); colormaplumps[numcolormaplumps].firstlump = startnum+1;
colormaplumps[numcolormaplumps].numlumps = endnum - (startnum + 1); colormaplumps[numcolormaplumps].numlumps = endnum - (startnum + 1);
numcolormaplumps++; numcolormaplumps++;
} }

View file

@ -590,51 +590,44 @@ static BOOL I_ReadyConsole(HANDLE ci)
static boolean entering_con_command = false; static boolean entering_con_command = false;
void I_GetConsoleEvents(void) static void Impl_HandleKeyboardConsoleEvent(KEY_EVENT_RECORD evt, HANDLE co)
{ {
event_t ev = {0,0,0,0}; event_t event;
HANDLE ci = GetStdHandle(STD_INPUT_HANDLE);
HANDLE co = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_SCREEN_BUFFER_INFO CSBI; CONSOLE_SCREEN_BUFFER_INFO CSBI;
INPUT_RECORD input;
DWORD t; DWORD t;
while (I_ReadyConsole(ci) && ReadConsoleInput(ci, &input, 1, &t) && t) memset(&event,0x00,sizeof (event));
if (evt.bKeyDown)
{ {
memset(&ev,0x00,sizeof (ev)); event.type = ev_console;
switch (input.EventType)
{
case KEY_EVENT:
if (input.Event.KeyEvent.bKeyDown)
{
ev.type = ev_console;
entering_con_command = true; entering_con_command = true;
switch (input.Event.KeyEvent.wVirtualKeyCode) switch (evt.wVirtualKeyCode)
{ {
case VK_ESCAPE: case VK_ESCAPE:
case VK_TAB: case VK_TAB:
ev.data1 = KEY_NULL; event.data1 = KEY_NULL;
break; break;
case VK_SHIFT: case VK_SHIFT:
ev.data1 = KEY_LSHIFT; event.data1 = KEY_LSHIFT;
break; break;
case VK_RETURN: case VK_RETURN:
entering_con_command = false; entering_con_command = false;
// Fall through. // Fall through.
default: default:
ev.data1 = MapVirtualKey(input.Event.KeyEvent.wVirtualKeyCode,2); // convert in to char event.data1 = MapVirtualKey(evt.wVirtualKeyCode,2); // convert in to char
} }
if (co != INVALID_HANDLE_VALUE && GetFileType(co) == FILE_TYPE_CHAR && GetConsoleMode(co, &t)) if (co != INVALID_HANDLE_VALUE && GetFileType(co) == FILE_TYPE_CHAR && GetConsoleMode(co, &t))
{ {
if (ev.data1 && ev.data1 != KEY_LSHIFT && ev.data1 != KEY_RSHIFT) if (event.data1 && event.data1 != KEY_LSHIFT && event.data1 != KEY_RSHIFT)
{ {
#ifdef _UNICODE #ifdef _UNICODE
WriteConsole(co, &input.Event.KeyEvent.uChar.UnicodeChar, 1, &t, NULL); WriteConsole(co, &evt.uChar.UnicodeChar, 1, &t, NULL);
#else #else
WriteConsole(co, &input.Event.KeyEvent.uChar.AsciiChar, 1 , &t, NULL); WriteConsole(co, &evt.uChar.AsciiChar, 1 , &t, NULL);
#endif #endif
} }
if (input.Event.KeyEvent.wVirtualKeyCode == VK_BACK if (evt.wVirtualKeyCode == VK_BACK
&& GetConsoleScreenBufferInfo(co,&CSBI)) && GetConsoleScreenBufferInfo(co,&CSBI))
{ {
WriteConsoleOutputCharacterA(co, " ",1, CSBI.dwCursorPosition, &t); WriteConsoleOutputCharacterA(co, " ",1, CSBI.dwCursorPosition, &t);
@ -643,17 +636,32 @@ void I_GetConsoleEvents(void)
} }
else else
{ {
ev.type = ev_keyup; event.type = ev_keyup;
switch (input.Event.KeyEvent.wVirtualKeyCode) switch (evt.wVirtualKeyCode)
{ {
case VK_SHIFT: case VK_SHIFT:
ev.data1 = KEY_LSHIFT; event.data1 = KEY_LSHIFT;
break; break;
default: default:
break; break;
} }
} }
if (ev.data1) D_PostEvent(&ev); if (event.data1) D_PostEvent(&event);
}
void I_GetConsoleEvents(void)
{
HANDLE ci = GetStdHandle(STD_INPUT_HANDLE);
HANDLE co = GetStdHandle(STD_OUTPUT_HANDLE);
INPUT_RECORD input;
DWORD t;
while (I_ReadyConsole(ci) && ReadConsoleInput(ci, &input, 1, &t) && t)
{
switch (input.EventType)
{
case KEY_EVENT:
Impl_HandleKeyboardConsoleEvent(input.Event.KeyEvent, co);
break; break;
case MOUSE_EVENT: case MOUSE_EVENT:
case WINDOW_BUFFER_SIZE_EVENT: case WINDOW_BUFFER_SIZE_EVENT:

View file

@ -158,7 +158,7 @@ static INT32 windowedModes[MAXWINMODES][2] =
static void Impl_VideoSetupSDLBuffer(void); static void Impl_VideoSetupSDLBuffer(void);
static void Impl_VideoSetupBuffer(void); static void Impl_VideoSetupBuffer(void);
static SDL_bool Impl_CreateWindow(SDL_bool fullscreen); static SDL_bool Impl_CreateWindow(SDL_bool fullscreen);
static void Impl_SetWindowName(const char *title); //static void Impl_SetWindowName(const char *title);
static void Impl_SetWindowIcon(void); static void Impl_SetWindowIcon(void);
static void SDLSetMode(INT32 width, INT32 height, SDL_bool fullscreen) static void SDLSetMode(INT32 width, INT32 height, SDL_bool fullscreen)
@ -181,15 +181,13 @@ static void SDLSetMode(INT32 width, INT32 height, SDL_bool fullscreen)
wasfullscreen = SDL_TRUE; wasfullscreen = SDL_TRUE;
SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN_DESKTOP); SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN_DESKTOP);
} }
else if (wasfullscreen) else // windowed mode
{
if (wasfullscreen)
{ {
wasfullscreen = SDL_FALSE; wasfullscreen = SDL_FALSE;
SDL_SetWindowFullscreen(window, 0); SDL_SetWindowFullscreen(window, 0);
SDL_SetWindowSize(window, width, height);
SDL_SetWindowPosition(window, SDL_WINDOWPOS_CENTERED_DISPLAY(1), SDL_WINDOWPOS_CENTERED_DISPLAY(1));
} }
else
{
// Reposition window only in windowed mode // Reposition window only in windowed mode
SDL_SetWindowSize(window, width, height); SDL_SetWindowSize(window, width, height);
SDL_SetWindowPosition(window, SDL_WINDOWPOS_CENTERED_DISPLAY(1), SDL_WINDOWPOS_CENTERED_DISPLAY(1)); SDL_SetWindowPosition(window, SDL_WINDOWPOS_CENTERED_DISPLAY(1), SDL_WINDOWPOS_CENTERED_DISPLAY(1));
@ -899,7 +897,7 @@ static inline boolean I_SkipFrame(void)
{ {
static boolean skip = false; static boolean skip = false;
if (render_soft != rendermode) if (rendermode != render_soft)
return false; return false;
skip = !skip; skip = !skip;
@ -935,7 +933,7 @@ void I_FinishUpdate(void)
if (cv_ticrate.value) if (cv_ticrate.value)
SCR_DisplayTicRate(); SCR_DisplayTicRate();
if (render_soft == rendermode && screens[0]) if (rendermode == render_soft && screens[0])
{ {
SDL_Rect rect; SDL_Rect rect;
@ -962,7 +960,7 @@ void I_FinishUpdate(void)
} }
#ifdef HWRENDER #ifdef HWRENDER
else else if (rendermode == render_opengl)
{ {
OglSdlFinishUpdate(cv_vidwait.value); OglSdlFinishUpdate(cv_vidwait.value);
} }
@ -1190,11 +1188,11 @@ INT32 VID_SetMode(INT32 modeNum)
} }
vid.modenum = -1; vid.modenum = -1;
} }
Impl_SetWindowName("SRB2 "VERSIONSTRING); //Impl_SetWindowName("SRB2 "VERSIONSTRING);
SDLSetMode(windowedModes[modeNum][0], windowedModes[modeNum][1], USE_FULLSCREEN); SDLSetMode(vid.width, vid.height, USE_FULLSCREEN);
if (render_soft == rendermode) if (rendermode == render_soft)
{ {
if (bufSurface) if (bufSurface)
{ {
@ -1213,30 +1211,20 @@ static SDL_bool Impl_CreateWindow(SDL_bool fullscreen)
int flags = 0; int flags = 0;
if (rendermode == render_none) // dedicated if (rendermode == render_none) // dedicated
{
return SDL_TRUE; // Monster Iestyn -- not sure if it really matters what we return here tbh return SDL_TRUE; // Monster Iestyn -- not sure if it really matters what we return here tbh
}
if (window != NULL) if (window != NULL)
{
return SDL_FALSE; return SDL_FALSE;
}
if (fullscreen) if (fullscreen)
{
flags |= SDL_WINDOW_FULLSCREEN_DESKTOP; flags |= SDL_WINDOW_FULLSCREEN_DESKTOP;
}
if (borderlesswindow) if (borderlesswindow)
{
flags |= SDL_WINDOW_BORDERLESS; flags |= SDL_WINDOW_BORDERLESS;
}
#ifdef HWRENDER #ifdef HWRENDER
if (rendermode == render_opengl) if (rendermode == render_opengl)
{
flags |= SDL_WINDOW_OPENGL; flags |= SDL_WINDOW_OPENGL;
}
#endif #endif
// Create a window // Create a window
@ -1265,7 +1253,13 @@ static SDL_bool Impl_CreateWindow(SDL_bool fullscreen)
#endif #endif
if (rendermode == render_soft) if (rendermode == render_soft)
{ {
renderer = SDL_CreateRenderer(window, -1, (usesdl2soft ? SDL_RENDERER_SOFTWARE : 0) | (cv_vidwait.value && !usesdl2soft ? SDL_RENDERER_PRESENTVSYNC : 0)); flags = 0; // Use this to set SDL_RENDERER_* flags now
if (usesdl2soft)
flags |= SDL_RENDERER_SOFTWARE;
else if (cv_vidwait.value)
flags |= SDL_RENDERER_PRESENTVSYNC;
renderer = SDL_CreateRenderer(window, -1, flags);
if (renderer == NULL) if (renderer == NULL)
{ {
CONS_Printf(M_GetText("Couldn't create rendering context: %s\n"), SDL_GetError()); CONS_Printf(M_GetText("Couldn't create rendering context: %s\n"), SDL_GetError());
@ -1277,14 +1271,16 @@ static SDL_bool Impl_CreateWindow(SDL_bool fullscreen)
return SDL_TRUE; return SDL_TRUE;
} }
/*
static void Impl_SetWindowName(const char *title) static void Impl_SetWindowName(const char *title)
{ {
if (window != NULL) if (window == NULL)
{ {
return; return;
} }
SDL_SetWindowTitle(window, title); SDL_SetWindowTitle(window, title);
} }
*/
static void Impl_SetWindowIcon(void) static void Impl_SetWindowIcon(void)
{ {
@ -1487,7 +1483,7 @@ void I_ShutdownGraphics(void)
rendermode = render_none; rendermode = render_none;
if (icoSurface) SDL_FreeSurface(icoSurface); if (icoSurface) SDL_FreeSurface(icoSurface);
icoSurface = NULL; icoSurface = NULL;
if (render_soft == oldrendermode) if (oldrendermode == render_soft)
{ {
if (vidSurface) SDL_FreeSurface(vidSurface); if (vidSurface) SDL_FreeSurface(vidSurface);
vidSurface = NULL; vidSurface = NULL;

View file

@ -1214,7 +1214,7 @@
C01FCF4B08A954540054247B /* Debug */ = { C01FCF4B08A954540054247B /* Debug */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
CURRENT_PROJECT_VERSION = 2.1.18; CURRENT_PROJECT_VERSION = 2.1.19;
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.18; CURRENT_PROJECT_VERSION = 2.1.19;
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

@ -71,7 +71,6 @@ INT32 oglflags = 0;
void *GLUhandle = NULL; void *GLUhandle = NULL;
SDL_GLContext sdlglcontext = 0; SDL_GLContext sdlglcontext = 0;
#ifndef STATIC_OPENGL
void *GetGLFunc(const char *proc) void *GetGLFunc(const char *proc)
{ {
if (strncmp(proc, "glu", 3) == 0) if (strncmp(proc, "glu", 3) == 0)
@ -83,7 +82,6 @@ void *GetGLFunc(const char *proc)
} }
return SDL_GL_GetProcAddress(proc); return SDL_GL_GetProcAddress(proc);
} }
#endif
boolean LoadGL(void) boolean LoadGL(void)
{ {

View file

@ -1214,7 +1214,7 @@
C01FCF4B08A954540054247B /* Debug */ = { C01FCF4B08A954540054247B /* Debug */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
CURRENT_PROJECT_VERSION = 2.1.18; CURRENT_PROJECT_VERSION = 2.1.19;
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.18; CURRENT_PROJECT_VERSION = 2.1.19;
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

@ -180,9 +180,9 @@ static LPSTR hms(UINT seconds)
hours = minutes / 60; hours = minutes / 60;
minutes %= 60; minutes %= 60;
if (hours > 0) if (hours > 0)
sprintf (s, "%lu:%02lu:%02lu", hours, minutes, seconds); sprintf (s, "%lu:%02lu:%02lu", (long unsigned int)hours, (long unsigned int)minutes, (long unsigned int)seconds);
else else
sprintf (s, "%2lu:%02lu", minutes, seconds); sprintf (s, "%2lu:%02lu", (long unsigned int)minutes, (long unsigned int)seconds);
return s; return s;
} }

View file

@ -470,7 +470,7 @@ static inline BOOL tlErrorMessage(const TCHAR *err)
// //
// warn user if there is one // warn user if there is one
// //
printf("Error %Ts..\n", err); printf("Error %s..\n", err);
fflush(stdout); fflush(stdout);
MessageBox(hWndMain, err, TEXT("ERROR"), MB_OK); MessageBox(hWndMain, err, TEXT("ERROR"), MB_OK);

View file

@ -160,6 +160,20 @@ static void Y_CalculateMatchWinners(void);
static void Y_FollowIntermission(void); static void Y_FollowIntermission(void);
static void Y_UnloadData(void); static void Y_UnloadData(void);
// Stuff copy+pasted from st_stuff.c
static INT32 SCX(INT32 x)
{
return FixedInt(FixedMul(x<<FRACBITS, vid.fdupx));
}
static INT32 SCY(INT32 z)
{
return FixedInt(FixedMul(z<<FRACBITS, vid.fdupy));
}
#define ST_DrawNumFromHud(h,n) V_DrawTallNum(SCX(hudinfo[h].x), SCY(hudinfo[h].y), V_NOSCALESTART, n)
#define ST_DrawPadNumFromHud(h,n,q) V_DrawPaddedTallNum(SCX(hudinfo[h].x), SCY(hudinfo[h].y), V_NOSCALESTART, n, q)
#define ST_DrawPatchFromHud(h,p) V_DrawScaledPatch(SCX(hudinfo[h].x), SCY(hudinfo[h].y), V_NOSCALESTART, p)
static void Y_IntermissionTokenDrawer(void) static void Y_IntermissionTokenDrawer(void)
{ {
INT32 y; INT32 y;
@ -242,28 +256,31 @@ void Y_IntermissionDrawer(void)
Y_IntermissionTokenDrawer(); Y_IntermissionTokenDrawer();
// draw score // draw score
V_DrawScaledPatch(hudinfo[HUD_SCORE].x, hudinfo[HUD_SCORE].y, V_SNAPTOLEFT, sboscore); ST_DrawPatchFromHud(HUD_SCORE, sboscore);
V_DrawTallNum(hudinfo[HUD_SCORENUM].x, hudinfo[HUD_SCORENUM].y, V_SNAPTOLEFT, data.coop.score); ST_DrawNumFromHud(HUD_SCORENUM, data.coop.score);
// draw time // draw time
V_DrawScaledPatch(hudinfo[HUD_TIME].x, hudinfo[HUD_TIME].y, V_SNAPTOLEFT, sbotime); ST_DrawPatchFromHud(HUD_TIME, sbotime);
if (cv_timetic.value == 1) if (cv_timetic.value == 1)
V_DrawTallNum(hudinfo[HUD_SECONDS].x, hudinfo[HUD_SECONDS].y, V_SNAPTOLEFT, data.coop.tics); ST_DrawNumFromHud(HUD_SECONDS, data.coop.tics);
else else
{ {
INT32 seconds, minutes, tictrn;
seconds = G_TicsToSeconds(data.coop.tics);
minutes = G_TicsToMinutes(data.coop.tics, true);
tictrn = G_TicsToCentiseconds(data.coop.tics);
ST_DrawNumFromHud(HUD_MINUTES, minutes); // Minutes
ST_DrawPatchFromHud(HUD_TIMECOLON, sbocolon); // Colon
ST_DrawPadNumFromHud(HUD_SECONDS, seconds, 2); // Seconds
// we should show centiseconds on the intermission screen too, if the conditions are right. // we should show centiseconds on the intermission screen too, if the conditions are right.
if (modeattacking || cv_timetic.value == 2) if (modeattacking || cv_timetic.value == 2)
{ {
V_DrawPaddedTallNum(hudinfo[HUD_TICS].x, hudinfo[HUD_TICS].y, V_SNAPTOLEFT, ST_DrawPatchFromHud(HUD_TIMETICCOLON, sboperiod); // Period
G_TicsToCentiseconds(data.coop.tics), 2); ST_DrawPadNumFromHud(HUD_TICS, tictrn, 2); // Tics
V_DrawScaledPatch(hudinfo[HUD_TIMETICCOLON].x, hudinfo[HUD_TIMETICCOLON].y, V_SNAPTOLEFT, sboperiod);
} }
V_DrawPaddedTallNum(hudinfo[HUD_SECONDS].x, hudinfo[HUD_SECONDS].y, V_SNAPTOLEFT,
G_TicsToSeconds(data.coop.tics), 2);
V_DrawScaledPatch(hudinfo[HUD_TIMECOLON].x, hudinfo[HUD_TIMECOLON].y, V_SNAPTOLEFT, sbocolon);
V_DrawTallNum(hudinfo[HUD_MINUTES].x, hudinfo[HUD_MINUTES].y, V_SNAPTOLEFT,
G_TicsToMinutes(data.coop.tics, false));
} }
// draw the "got through act" lines and act number // draw the "got through act" lines and act number
@ -1008,7 +1025,8 @@ void Y_StartIntermission(void)
} }
// We couldn't display the intermission even if we wanted to. // We couldn't display the intermission even if we wanted to.
if (dedicated) return; // But we still need to give the players their score bonuses, dummy.
//if (dedicated) return;
// This should always exist, but just in case... // This should always exist, but just in case...
if(!mapheaderinfo[prevmap]) if(!mapheaderinfo[prevmap])
@ -1823,37 +1841,6 @@ void Y_EndIntermission(void)
usebuffer = false; usebuffer = false;
} }
//
// Y_EndGame
//
// Why end the game?
// Because Y_FollowIntermission and F_EndCutscene would
// both do this exact same thing *in different ways* otherwise,
// which made it so that you could only unlock Ultimate mode
// if you had a cutscene after the final level and crap like that.
// This function simplifies it so only one place has to be updated
// when something new is added.
void Y_EndGame(void)
{
// Only do evaluation and credits in coop games.
if (gametype == GT_COOP)
{
if (nextmap == 1102-1) // end game with credits
{
F_StartCredits();
return;
}
if (nextmap == 1101-1) // end game with evaluation
{
F_StartGameEvaluation();
return;
}
}
// 1100 or competitive multiplayer, so go back to title screen.
D_StartTitle();
}
// //
// Y_FollowIntermission // Y_FollowIntermission
// //
@ -1865,21 +1852,10 @@ static void Y_FollowIntermission(void)
return; return;
} }
if (nextmap < 1100-1) // This handles whether to play a post-level cutscene, end the game,
{ // or simply go to the next level.
// normal level // No need to duplicate the code here!
G_AfterIntermission(); G_AfterIntermission();
return;
}
// Start a custom cutscene if there is one.
if (mapheaderinfo[gamemap-1]->cutscenenum && !modeattacking)
{
F_StartCustomCutscene(mapheaderinfo[gamemap-1]->cutscenenum-1, false, false);
return;
}
Y_EndGame();
} }
#define UNLOAD(x) Z_ChangeTag(x, PU_CACHE); x = NULL #define UNLOAD(x) Z_ChangeTag(x, PU_CACHE); x = NULL

View file

@ -15,7 +15,6 @@ void Y_IntermissionDrawer(void);
void Y_Ticker(void); void Y_Ticker(void);
void Y_StartIntermission(void); void Y_StartIntermission(void);
void Y_EndIntermission(void); void Y_EndIntermission(void);
void Y_EndGame(void);
typedef enum typedef enum
{ {