diff --git a/CMakeLists.txt b/CMakeLists.txt index 23b768a70..f9364fdd2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.0) project(SRB2 - VERSION 2.1.18 + VERSION 2.1.19 LANGUAGES C) if(${PROJECT_SOURCE_DIR} MATCHES ${PROJECT_BINARY_DIR}) diff --git a/appveyor.yml b/appveyor.yml index c1f6894ef..23b9b6281 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,4 +1,4 @@ -version: 2.1.18.{branch}-{build} +version: 2.1.19.{branch}-{build} os: MinGW environment: @@ -47,7 +47,7 @@ before_build: - upx -V - ccache -V - 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: - cmd: mingw32-make.exe %SRB2_MFLAGS% %CONFIGURATION%=1 clean diff --git a/src/Makefile b/src/Makefile index 76f013c52..426dc2289 100644 --- a/src/Makefile +++ b/src/Makefile @@ -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. # (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 -ifndef NOGETTEXT ifdef GETTEXT POS:=$(BIN)/en.mo OPTS+=-DGETTEXT endif -endif ifdef DJGPPDOS all: pre-build $(BIN)/$(EXENAME) diff --git a/src/Makefile.cfg b/src/Makefile.cfg index 80d018c4b..5bf7f247d 100644 --- a/src/Makefile.cfg +++ b/src/Makefile.cfg @@ -283,9 +283,6 @@ else ifdef LINUX NASMFORMAT=elf -DLINUX SDL=1 -ifndef NOGETTEXT - GETTEXT=1 -endif ifdef LINUX64 OBJDIR:=$(OBJDIR)/Linux64 BIN:=$(BIN)/Linux64 @@ -321,9 +318,6 @@ else ifdef MINGW64 INTERFACE=win32 #NASMFORMAT=win64 -ifndef NOGETTEXT - #GETTEXT=1 -endif OBJDIR:=$(OBJDIR)/Mingw64 BIN:=$(BIN)/Mingw64 else @@ -354,9 +348,6 @@ else ifdef MINGW INTERFACE=win32 NASMFORMAT=win32 -ifndef NOGETTEXT - GETTEXT=1 -endif OBJDIR:=$(OBJDIR)/Mingw BIN:=$(BIN)/Mingw else diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 187d6f857..6705e6dcd 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -1748,9 +1748,7 @@ static boolean CL_ServerConnectionSearchTicker(boolean viams, tic_t *asksent) { #ifndef NONET INT32 i; -#endif -#ifndef NONET // serverlist is updated by GetPacket function if (serverlistcount > 0) { @@ -1784,7 +1782,20 @@ static boolean CL_ServerConnectionSearchTicker(boolean viams, tic_t *asksent) serverlist[i].info.fileneeded); CONS_Printf(M_GetText("Checking files...\n")); 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(); CL_Reset(); @@ -3412,17 +3423,42 @@ static void HandlePacketFromAwayNode(SINT8 node) if (node != servernode) 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) { case PT_ASKINFOVIAMS: +#if 0 if (server && serverrunning) { - INT32 clientnode = I_NetMakeNode(netbuffer->u.msaskinfo.clientaddr); - SV_SendServerInfo(clientnode, (tic_t)LONG(netbuffer->u.msaskinfo.time)); - SV_SendPlayerInfo(clientnode); // Send extra info - Net_CloseConnection(clientnode); - // Don't close connection to MS. + 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_SendPlayerInfo(clientnode); // Send extra info + Net_CloseConnection(clientnode); + // 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; case PT_ASKINFO: @@ -3430,8 +3466,8 @@ static void HandlePacketFromAwayNode(SINT8 node) { SV_SendServerInfo(node, (tic_t)LONG(netbuffer->u.askinfo.time)); SV_SendPlayerInfo(node); // Send extra info - Net_CloseConnection(node); } + Net_CloseConnection(node); break; case PT_SERVERREFUSE: // Negative response of client join request @@ -3440,6 +3476,7 @@ static void HandlePacketFromAwayNode(SINT8 node) Net_CloseConnection(node); break; } + SERVERONLY if (cl_mode == CL_WAITJOINRESPONSE) { // Save the reason so it can be displayed after quitting the netgame @@ -3471,6 +3508,7 @@ static void HandlePacketFromAwayNode(SINT8 node) Net_CloseConnection(node); break; } + SERVERONLY /// \note how would this happen? and is it doing the right thing if it does? if (cl_mode != CL_WAITJOINRESPONSE) break; @@ -3536,13 +3574,18 @@ static void HandlePacketFromAwayNode(SINT8 node) Net_CloseConnection(node); break; } - else - Got_Filetxpak(); + SERVERONLY + Got_Filetxpak(); break; case PT_REQUESTFILE: 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; case PT_NODETIMEOUT: @@ -3565,6 +3608,7 @@ static void HandlePacketFromAwayNode(SINT8 node) break; // Ignore it } +#undef SERVERONLY } /** Handles a packet received from a node that is in game @@ -3597,6 +3641,8 @@ FILESTAMP { // -------------------------------------------- SERVER RECEIVE ---------- case PT_RESYNCHGET: + if (client) + break; SV_AcknowledgeResynchAck(netconsole, netbuffer->u.resynchgot); break; case PT_CLIENTCMD: @@ -3663,7 +3709,8 @@ FILESTAMP } // 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]], &netbuffer->u.client2pak.cmd2, 1); @@ -3722,6 +3769,27 @@ FILESTAMP tic_t tic = maketic; 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 :( // doomcom->numslots+1 "+1" since doomcom->numslots can change within this time and sent time j = software_MAXPACKETLENGTH @@ -3915,7 +3983,7 @@ FILESTAMP if (client) { INT32 i; - for (i = 0; i < MAXNETNODES; i++) + for (i = 0; i < MAXPLAYERS; i++) if (playeringame[i]) playerpingtable[i] = (tic_t)netbuffer->u.pingtable[i]; } @@ -3925,6 +3993,21 @@ FILESTAMP case PT_SERVERCFG: break; 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) Got_Filetxpak(); break; @@ -4458,8 +4541,8 @@ static inline void PingUpdate(void) } //send out our ping packets - for (i = 0; i < MAXPLAYERS; i++) - if (playeringame[i]) + for (i = 0; i < MAXNETNODES; i++) + if (nodeingame[i]) HSendPacket(i, true, 0, sizeof(INT32) * MAXPLAYERS); pingmeasurecount = 1; //Reset count @@ -4489,20 +4572,15 @@ void NetUpdate(void) gametime = nowtime; - if (!(gametime % 255) && netgame && server) - { -#ifdef NEWPING - PingUpdate(); -#endif - } - #ifdef NEWPING if (server) { + if (netgame && !(gametime % 255)) + PingUpdate(); // 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]) - realpingtable[i] += G_TicsToMilliseconds(GetLag(i)); + realpingtable[i] += G_TicsToMilliseconds(GetLag(playernode[i])); pingmeasurecount++; } #endif diff --git a/src/d_main.c b/src/d_main.c index 0bba9dc06..1a58ee89a 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -107,8 +107,6 @@ UINT8 window_notinfocus = false; // // DEMO LOOP // -//static INT32 demosequence; -static const char *pagename = "MAP1PIC"; static char *startupwadfiles[MAX_WADFILES]; boolean devparm = false; // started game with -devparm @@ -721,7 +719,6 @@ void D_StartTitle(void) gameaction = ga_nothing; displayplayer = consoleplayer = 0; - //demosequence = -1; gametype = GT_COOP; paused = false; advancedemo = false; @@ -886,27 +883,10 @@ static void IdentifyVersion(void) #endif } -/* ======================================================================== */ -// Just print the nice red titlebar like the original SRB2 for DOS. -/* ======================================================================== */ #ifdef PC_DOS -static inline void D_Titlebar(char *title1, char *title2) -{ - // 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 +/* ======================================================================== */ +// Code for printing SRB2's title bar in DOS +/* ======================================================================== */ // // 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); } +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 @@ -942,8 +947,6 @@ static inline void D_MakeTitleString(char *s) void D_SRB2Main(void) { INT32 p; - char srb2[82]; // srb2 title banner - char title[82]; INT32 pstartmap = 1; boolean autostart = false; @@ -986,20 +989,8 @@ void D_SRB2Main(void) dedicated = M_CheckParm("-dedicated") != 0; #endif - strcpy(title, "Sonic Robo Blast 2"); - strcpy(srb2, "Sonic Robo Blast 2"); - D_MakeTitleString(srb2); - #ifdef PC_DOS - D_Titlebar(srb2, title); -#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'; + D_Titlebar(); #endif if (devparm) @@ -1399,7 +1390,6 @@ void D_SRB2Main(void) if (dedicated && server) { - pagename = "TITLESKY"; levelstarttic = gametic; G_SetGamestate(GS_LEVEL); if (!P_SetupLevel(false)) diff --git a/src/d_net.c b/src/d_net.c index 60a423ffa..48c1d60ea 100644 --- a/src/d_net.c +++ b/src/d_net.c @@ -713,6 +713,13 @@ void Net_CloseConnection(INT32 node) #else INT32 i; boolean forceclose = (node & FORCECLOSE) != 0; + + if (node == -1) + { + DEBFILE(M_GetText("Net_CloseConnection: node -1 detected!\n")); + return; // nope, just ignore it + } + node &= ~FORCECLOSE; if (!node) @@ -720,7 +727,7 @@ void Net_CloseConnection(INT32 node) 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; } diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 8ddc1e142..692f6b714 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -1621,8 +1621,13 @@ void D_MapChange(INT32 mapnum, INT32 newgametype, boolean pultmode, boolean rese mapchangepending = 0; // spawn the server if needed // reset players if there is a new one - if (!(adminplayer == consoleplayer) && SV_SpawnServer()) - buf[0] &= ~(1<<1); + if (!(adminplayer == consoleplayer)) + { + if (SV_SpawnServer()) + buf[0] &= ~(1<<1); + if (!Playing()) // you failed to start a server somehow, so cancel the map change + return; + } // Kick bot from special stages if (botskin) @@ -3128,7 +3133,13 @@ static void Got_RequestAddfilecmd(UINT8 **cp, INT32 playernum) filestatus_t ncs = FS_NOTFOUND; UINT8 md5sum[16]; boolean kick = false; + boolean toomany = false; INT32 i; + size_t packetsize = 0; + serverinfo_pak *dummycheck = NULL; + + // Shut the compiler up. + (void)dummycheck; READSTRINGN(*cp, filename, 240); READMEM(*cp, md5sum, 16); @@ -3154,13 +3165,25 @@ static void Got_RequestAddfilecmd(UINT8 **cp, INT32 playernum) return; } - ncs = findfile(filename,md5sum,true); + // See W_LoadWadFile in w_wad.c + for (i = 0; i < numwadfiles; i++) + packetsize += nameonlylength(wadfiles[i]->filename) + 22; - if (ncs != FS_FOUND) + packetsize += nameonlylength(filename) + 22; + + if ((numwadfiles >= MAX_WADFILES) + || (packetsize > sizeof(dummycheck->fileneeded))) + toomany = true; + else + ncs = findfile(filename,md5sum,true); + + if (ncs != FS_FOUND || toomany) { 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); else if (ncs == FS_MD5SUMBAD) sprintf(message, M_GetText("Checksum mismatch on %s\n"), filename); @@ -3230,10 +3253,15 @@ static void Got_Addfilecmd(UINT8 **cp, INT32 playernum) ncs = findfile(filename,md5sum,true); - if (ncs != FS_FOUND) + if (ncs != FS_FOUND || !P_AddWadFile(filename, NULL)) { 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); M_StartMessage(va("The server added a file \n(%s)\nthat you do not have.\n\nPress ESC\n",filename), NULL, MM_NOTHING); @@ -3251,7 +3279,6 @@ static void Got_Addfilecmd(UINT8 **cp, INT32 playernum) return; } - P_AddWadFile(filename, NULL); G_SetGameModified(true); } diff --git a/src/d_netfil.c b/src/d_netfil.c index bf4e59878..172624ad2 100644 --- a/src/d_netfil.c +++ b/src/d_netfil.c @@ -62,7 +62,8 @@ #include -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 typedef struct filetx_s @@ -303,7 +304,8 @@ boolean CL_SendRequestFile(void) } // 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]; UINT8 *p = netbuffer->u.textcmd; @@ -314,8 +316,13 @@ void Got_RequestFilePak(INT32 node) if (id == 0xFF) break; 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 @@ -330,6 +337,12 @@ INT32 CL_CheckFiles(void) INT32 i, j; char wadfilename[MAX_WADPATH]; 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")) // return 1; @@ -378,6 +391,10 @@ INT32 CL_CheckFiles(void) 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++) { 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) 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); CONS_Debug(DBG_NETPLAY, "found %d\n", fileneeded[i].status); if (fileneeded[i].status != FS_FOUND) @@ -480,7 +505,7 @@ static INT32 filestosend = 0; * \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 *p; // The new file request @@ -488,7 +513,7 @@ static void SV_SendFile(INT32 node, const char *filename, UINT8 fileid) char wadfilename[MAX_WADPATH]; if (cv_noticedownload.value) - CONS_Printf("Sending file \"%s\" to node %d\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 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); *q = NULL; - return; + return false; // cancel the rest of the requests } // 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); *q = NULL; - return; + return false; // cancel the rest of the requests } 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->next = NULL; // End of list filestosend++; + return true; } /** Adds a memory block to the file list for a node diff --git a/src/d_netfil.h b/src/d_netfil.h index c9085a5b0..b9b7b2f2e 100644 --- a/src/d_netfil.h +++ b/src/d_netfil.h @@ -69,7 +69,7 @@ boolean SV_SendingFile(INT32 node); boolean CL_CheckDownloadable(void); boolean CL_SendRequestFile(void); -void Got_RequestFilePak(INT32 node); +boolean Got_RequestFilePak(INT32 node); void SV_AbortSendFiles(INT32 node); void CloseNetFile(void); diff --git a/src/dehacked.c b/src/dehacked.c index aa6f4f7f9..9c8d25213 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -382,56 +382,6 @@ static void clear_levels(void) 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) { // Send the character select entry to a free slot. @@ -2106,7 +2056,7 @@ static void readframe(MYFILE *f, INT32 num) 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 *word; @@ -2142,21 +2092,7 @@ static void readsound(MYFILE *f, INT32 num, const char *savesfxnames[]) continue; } -/* if (fastcmp(word, "OFFSET")) - { - 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")) + if (fastcmp(word, "SINGULAR")) { DEH_WriteUndoline(word, va("%d", S_sfx[num].singularity), UNDO_NONE); S_sfx[num].singularity = value; @@ -2182,8 +2118,6 @@ static void readsound(MYFILE *f, INT32 num, const char *savesfxnames[]) } while (!myfeof(f)); Z_Free(s); - - (void)savesfxnames; } /** 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); } -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) { char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL); @@ -3405,30 +3155,17 @@ static void ignorelines(MYFILE *f) 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 *word; char *word2; 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) initfreeslots(); 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; @@ -3505,19 +3242,7 @@ static void DEH_LoadDehackedFile(MYFILE *f, UINT16 wad) if (word2[strlen(word2)-1] == '\n') word2[strlen(word2)-1] = '\0'; i = atoi(word2); - if (fastcmp(word, "TEXTURE")) - { - // Read texture from spec file. - readtexture(f, word2); - DEH_WriteUndoline(word, word2, UNDO_HEADER); - } - 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 (fastcmp(word, "THING") || fastcmp(word, "MOBJ") || fastcmp(word, "OBJECT")) { if (i == 0 && word2[0] != '0') // If word2 isn't a number 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); } -/* else if (fastcmp(word, "ANIMTEX")) - { - readAnimTex(f, i); - }*/ else if (fastcmp(word, "LIGHT")) { #ifdef HWRENDER @@ -3605,34 +3326,12 @@ static void DEH_LoadDehackedFile(MYFILE *f, UINT16 wad) } DEH_WriteUndoline(word, word2, UNDO_HEADER); } - // 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")) { if (i == 0 && word2[0] != '0') // If word2 isn't a number i = get_sfx(word2); // find a sound by name if (i < NUMSFX && i > 0) - readsound(f, i, savesfxnames); + readsound(f, i); else { 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); } -/* 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")) { 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 //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")); if (ver != PATCHVERSION) @@ -3757,6 +3439,7 @@ static void DEH_LoadDehackedFile(MYFILE *f, UINT16 wad) // Unless you REALLY want to piss people off, // define a custom gamedata /before/ doing this!! // (then again, modifiedgame will prevent game data saving anyway) +*/ else if (fastcmp(word, "CLEAR")) { boolean clearall = (fastcmp(word2, "ALL")); @@ -3830,7 +3513,7 @@ void DEH_LoadDehackedLumpPwad(UINT16 wad, UINT16 lump) W_ReadLumpPwad(wad, lump, f.data); f.curpos = f.data; 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); Z_Free(f.data); } diff --git a/src/doomdef.h b/src/doomdef.h index ffd799d55..16d7fa218 100644 --- a/src/doomdef.h +++ b/src/doomdef.h @@ -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. // Only set it higher, not lower, obviously. // Note that we use this to help keep internal testing in check; this is why v2.1.0 is not version "1". -#define MODVERSION 23 +#define MODVERSION 24 // ========================================================================= @@ -546,4 +546,8 @@ extern const char *compdate, *comptime, *comprevision, *compbranch; /// Hudname padding. #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__ diff --git a/src/g_game.c b/src/g_game.c index f574094b8..ec41449d8 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -2309,6 +2309,9 @@ void G_SpawnPlayer(INT32 playernum, boolean starpost) if (starpost) //Don't even bother with looking for a place to spawn. { P_MovePlayerToStarpost(playernum); +#ifdef HAVE_BLUA + LUAh_PlayerSpawn(&players[playernum]); // Lua hook for player spawning :) +#endif return; } @@ -4079,7 +4082,7 @@ void G_GhostAddColor(ghostcolor_t color) ghostext.color = (UINT8)color; } -void G_GhostAddScale(UINT16 scale) +void G_GhostAddScale(fixed_t scale) { if (!demorecording || !(demoflags & DF_GHOST)) return; diff --git a/src/g_game.h b/src/g_game.h index 145c3ec93..72a6f3d6e 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -142,7 +142,7 @@ void G_GhostAddSpin(void); void G_GhostAddRev(void); void G_GhostAddColor(ghostcolor_t color); void G_GhostAddFlip(void); -void G_GhostAddScale(UINT16 scale); +void G_GhostAddScale(fixed_t scale); void G_GhostAddHit(mobj_t *victim); void G_WriteGhostTic(mobj_t *ghost); void G_ConsGhostTic(void); diff --git a/src/hardware/hw_glob.h b/src/hardware/hw_glob.h index 94eef1d3e..5d1a81d4f 100644 --- a/src/hardware/hw_glob.h +++ b/src/hardware/hw_glob.h @@ -78,6 +78,7 @@ typedef struct gr_vissprite_s //Hurdler: 25/04/2000: now support colormap in hardware mode UINT8 *colormap; INT32 dispoffset; // copy of info->dispoffset, affects ordering but not drawing + float z1, z2; } gr_vissprite_t; // -------- diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index e15713e27..92c363943 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -1084,9 +1084,9 @@ static void HWR_SplitWall(sector_t *sector, wallVert3D *wallVerts, INT32 texnum, float endheight = 0.0f, endbheight = 0.0f; 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 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 // use this as a temp var to store P_GetZAt's return value each time fixed_t temp; @@ -3721,6 +3721,9 @@ static void HWR_Subsector(size_t num) while (count--) { +#ifdef POLYOBJECTS + if (!line->polyseg) // ignore segs that belong to polyobjects +#endif HWR_AddLine(line); line++; } @@ -4226,6 +4229,7 @@ static void HWR_DrawSprite(gr_vissprite_t *spr) GLPatch_t *gpatch; // sprite patch converted to hardware FSurfaceInfo Surf; 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) this_scale = FIXED_TO_FLOAT(spr->mobj->scale); 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, // 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 wv = wallVerts; @@ -5065,6 +5070,10 @@ static void HWR_ProjectSprite(mobj_t *thing) angle_t ang; 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) return; @@ -5079,7 +5088,7 @@ static void HWR_ProjectSprite(mobj_t *thing) tz = (tr_x * gr_viewcos) + (tr_y * gr_viewsin); // 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; 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); #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) { // use single rotation for all views @@ -5127,8 +5157,6 @@ static void HWR_ProjectSprite(mobj_t *thing) else { // 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 rot = 6; // F7 slot 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 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 - 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 x1 = gr_windowcenterx + (tx * gr_centerx / tz); @@ -5159,7 +5190,14 @@ static void HWR_ProjectSprite(mobj_t *thing) 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); if (vflip) @@ -5208,6 +5246,8 @@ static void HWR_ProjectSprite(mobj_t *thing) vis->patchlumpnum = sprframe->lumppat[rot]; vis->flip = flip; vis->mobj = thing; + vis->z1 = z1; + vis->z2 = z2; //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" diff --git a/src/hardware/r_opengl/r_opengl.c b/src/hardware/r_opengl/r_opengl.c index 3a0bf7054..e6ff83e89 100644 --- a/src/hardware/r_opengl/r_opengl.c +++ b/src/hardware/r_opengl/r_opengl.c @@ -244,6 +244,7 @@ FUNCPRINTF void DBG_Printf(const char *lpFmt, ...) #define pglMaterialfv glMaterialfv /* Raster functions */ +#define pglPixelStorei glPixelStorei #define pglReadPixels glReadPixels /* Texture mapping */ @@ -262,15 +263,8 @@ FUNCPRINTF void DBG_Printf(const char *lpFmt, ...) /* texture mapping */ //GL_EXT_copy_texture #ifndef KOS_GL_COMPATIBILITY #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 /* 1.0 functions */ @@ -365,6 +359,8 @@ typedef void (APIENTRY * PFNglMaterialfv) (GLint face, GLenum pname, GLfloat *pa static PFNglMaterialfv pglMaterialfv; /* 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); static PFNglReadPixels pglReadPixels; @@ -391,7 +387,7 @@ static PFNglBindTexture pglBindTexture; /* 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); static PFNglCopyTexImage2D pglCopyTexImage2D; - +#endif /* GLU functions */ typedef GLint (APIENTRY * PFNgluBuild2DMipmaps) (GLenum target, GLint internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *data); static PFNgluBuild2DMipmaps pgluBuild2DMipmaps; @@ -403,7 +399,6 @@ static PFNglActiveTexture pglActiveTexture; typedef void (APIENTRY *PFNglMultiTexCoord2f) (GLenum, GLfloat, GLfloat); static PFNglMultiTexCoord2f pglMultiTexCoord2f; #endif -#endif #ifndef MINI_GL_COMPATIBILITY /* 1.2 Parms */ @@ -494,6 +489,7 @@ boolean SetupGLfunc(void) GETOPENGLFUNC(pglLightModelfv , glLightModelfv) GETOPENGLFUNC(pglMaterialfv , glMaterialfv) + GETOPENGLFUNC(pglPixelStorei , glPixelStorei) GETOPENGLFUNC(pglReadPixels , glReadPixels) 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 boolean SetupGLFunc13(void) { +#ifdef MINI_GL_COMPATIBILITY + return false; +#else const GLubyte *version = pglGetString(GL_VERSION); int glmajor, glminor; gl13 = false; -#ifdef MINI_GL_COMPATIBILITY - return false; -#else -#ifdef STATIC_OPENGL - gl13 = true; -#else - // Parse the GL version if (version != NULL) { if (sscanf((const char*)version, "%d.%d", &glmajor, &glminor) == 2) { // Look, we gotta prepare for the inevitable arrival of GL 2.0 code... - switch (glmajor) - { - case 1: - if (glminor == 3) gl13 = true; - break; - case 2: - case 3: - case 4: - gl13 = true; - default: - break; - } + if (glmajor == 1 && glminor >= 3) + gl13 = true; + else if (glmajor > 1) + gl13 = true; } } @@ -568,9 +552,6 @@ boolean SetupGLFunc13(void) } else DBG_Printf("GL_ARB_multitexture support: disabled\n"); -#undef GETOPENGLFUNC - -#endif return true; #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 *row = malloc(dst_stride); if (!row) return; + pglPixelStorei(GL_PACK_ALIGNMENT, 1); pglReadPixels(x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, dst_data); + pglPixelStorei(GL_UNPACK_ALIGNMENT, 1); for(i = 0; i < height/2; i++) { memcpy(row, top, dst_stride); @@ -913,7 +896,9 @@ EXPORT void HWRAPI(ReadRect) (INT32 x, INT32 y, INT32 width, INT32 height, INT32 j; GLubyte *image = malloc(width*height*3*sizeof (*image)); if (!image) return; + pglPixelStorei(GL_PACK_ALIGNMENT, 1); pglReadPixels(x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, image); + pglPixelStorei(GL_UNPACK_ALIGNMENT, 1); for (i = height-1; i >= 0; i--) { for (j = 0; j < width; j++) @@ -1815,13 +1800,11 @@ EXPORT void HWRAPI(SetSpecialState) (hwdspecialstate_t IdState, INT32 Value) min_filter = GL_NEAREST; #endif } -#ifndef STATIC_OPENGL if (!pgluBuild2DMipmaps) { MipMap = GL_FALSE; min_filter = GL_LINEAR; } -#endif Flush(); //??? if we want to change filter mode by texture, remove this break; diff --git a/src/lua_hook.h b/src/lua_hook.h index 88867db2b..fe5706f56 100644 --- a/src/lua_hook.h +++ b/src/lua_hook.h @@ -46,6 +46,7 @@ enum hook { hook_ShieldSpawn, hook_ShieldSpecial, hook_MobjMoveBlocked, + hook_MapThingSpawn, 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_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) +boolean LUAh_MapThingSpawn(mobj_t *mo, mapthing_t *mthing); // Hook for P_SpawnMapThing by mobj type #endif diff --git a/src/lua_hooklib.c b/src/lua_hooklib.c index dadc1861a..04efac070 100644 --- a/src/lua_hooklib.c +++ b/src/lua_hooklib.c @@ -57,6 +57,7 @@ const char *const hookNames[hook_MAX+1] = { "ShieldSpawn", "ShieldSpecial", "MobjMoveBlocked", + "MapThingSpawn", NULL }; @@ -128,6 +129,7 @@ static int lib_addHook(lua_State *L) case hook_MobjRemoved: case hook_HurtMsg: case hook_MobjMoveBlocked: + case hook_MapThingSpawn: hook.s.mt = MT_NULL; if (lua_isnumber(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_MobjRemoved: case hook_MobjMoveBlocked: + case hook_MapThingSpawn: lastp = &mobjhooks[hook.s.mt]; break; case hook_JumpSpecial: @@ -1073,4 +1076,66 @@ void LUAh_NetArchiveHook(lua_CFunction archFunc) // 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 diff --git a/src/lua_thinkerlib.c b/src/lua_thinkerlib.c index b8cf1baec..a661aaf04 100644 --- a/src/lua_thinkerlib.c +++ b/src/lua_thinkerlib.c @@ -16,89 +16,127 @@ #include "lua_script.h" #include "lua_libs.h" +#define META_ITERATIONSTATE "iteration state" + static const char *const iter_opt[] = { "all", "mobj", 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) { - int state = luaL_checkoption(L, 1, "mobj", iter_opt); - - thinker_t *th = NULL; - actionf_p1 searchFunc; - const char *searchMeta; + thinker_t *th = NULL, *next = NULL; + struct iterationState *it; if (gamestate != GS_LEVEL) return luaL_error(L, "This function can only be used in a level!"); - lua_settop(L, 2); - lua_remove(L, 1); // remove state now. + it = luaL_checkudata(L, 1, META_ITERATIONSTATE); - switch(state) + lua_settop(L, 2); + + if (lua_isnil(L, 2)) + th = &thinkercap; + else if (lua_isuserdata(L, 2)) { - case 0: - searchFunc = NULL; - searchMeta = NULL; - break; - case 1: - default: - searchFunc = (actionf_p1)P_MobjThinker; - searchMeta = META_MOBJ; - break; + if (lua_islightuserdata(L, 2)) + th = lua_touserdata(L, 2); + else + { + th = *(thinker_t **)lua_touserdata(L, -1); + if (!th) + { + if (it->next == LUA_REFNIL) + return 0; + + 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); + } + } } - 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; + luaL_unref(L, LUA_REGISTRYINDEX, it->next); + it->next = LUA_REFNIL; - if (!th) // something got our userdata invalidated! - return 0; + if (th && !next) + next = th->next; + if (!next) + return luaL_error(L, "next thinker invalidated during iteration"); - if (searchFunc == NULL) - { - if ((th = th->next) != &thinkercap) + for (; next != &thinkercap; next = next->next) + if (!it->filter || next->function.acp1 == it->filter) { - if (th->function.acp1 == (actionf_p1)P_MobjThinker) - LUA_PushUserdata(L, th, META_MOBJ); - else - lua_pushlightuserdata(L, th); + push_thinker(next); + if (next->next != &thinkercap) + { + push_thinker(next->next); + it->next = luaL_ref(L, LUA_REGISTRYINDEX); + } return 1; } - return 0; - } - - for (th = th->next; th != &thinkercap; th = th->next) - { - if (th->function.acp1 != searchFunc) - continue; - - LUA_PushUserdata(L, th, searchMeta); - return 1; - } return 0; } static int lib_startIterate(lua_State *L) { + struct iterationState *it; + if (gamestate != GS_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, 1); + + lua_pushvalue(L, lua_upvalueindex(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; } +#undef push_thinker + 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_pushcfunction(L, lib_startIterate); + lua_pushcfunction(L, lib_iterateThinkers); + lua_pushcclosure(L, lib_startIterate, 1); lua_setfield(L, -2, "iterate"); lua_setglobal(L, "thinkers"); return 0; diff --git a/src/p_floor.c b/src/p_floor.c index 68c3d55b8..1ed1d1565 100644 --- a/src/p_floor.c +++ b/src/p_floor.c @@ -2113,6 +2113,7 @@ void T_EachTimeThinker(levelspecthink_t *eachtime) boolean inAndOut = false; boolean floortouch = false; fixed_t bottomheight, topheight; + msecnode_t *node; for (i = 0; i < MAXPLAYERS; i++) { @@ -2174,7 +2175,23 @@ void T_EachTimeThinker(levelspecthink_t *eachtime) if ((netgame || multiplayer) && players[j].spectator) 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; topheight = P_GetSpecialTopZ(players[j].mo, sec, targetsec); @@ -2224,7 +2241,27 @@ void T_EachTimeThinker(levelspecthink_t *eachtime) if ((netgame || multiplayer) && players[i].spectator) 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; if (floortouch == true && P_IsObjectOnGroundIn(players[i].mo, sec)) diff --git a/src/p_mobj.c b/src/p_mobj.c index f93bafe7e..3e698990f 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -2560,10 +2560,18 @@ boolean P_CheckSolidLava(mobj_t *mo, ffloor_t *rover) I_Assert(mo != NULL); I_Assert(!P_MobjWasRemoved(mo)); - if (rover->flags & FF_SWIMMABLE && GETSECSPECIAL(rover->master->frontsector->special, 1) == 3 - && !(rover->master->flags & ML_BLOCKMONSTERS) - && ((rover->master->flags & ML_EFFECT3) || mo->z-mo->momz > *rover->topheight - FixedMul(16*FRACUNIT, mo->scale))) - return true; + { + 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 + && !(rover->master->flags & ML_BLOCKMONSTERS) + && ((rover->master->flags & ML_EFFECT3) || mo->z-mo->momz > topheight - FixedMul(16*FRACUNIT, mo->scale))) + return true; + } return false; } @@ -2802,7 +2810,7 @@ static boolean P_ZMovement(mobj_t *mo) mo->z = mo->floorz; #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; return true; @@ -3578,11 +3586,17 @@ static boolean P_SceneryZMovement(mobj_t *mo) // 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 - && ((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) && !(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 false; @@ -8515,6 +8529,7 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) break; case MT_EGGCAPSULE: mobj->extravalue1 = -1; // timer for how long a player has been at the capsule + break; case MT_REDTEAMRING: mobj->color = skincolor_redteam; break; @@ -9719,6 +9734,16 @@ void P_SpawnMapThing(mapthing_t *mthing) mobj = P_SpawnMobj(x, y, z, i); 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) { case MT_SKYBOX: diff --git a/src/p_spec.c b/src/p_spec.c index 5dfa515f0..3bf836a9c 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -456,7 +456,8 @@ void P_ParseAnimationDefintion(SINT8 istexture) // Search for existing animdef 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); @@ -2444,73 +2445,81 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) case 414: // Play SFX { - fixed_t sfxnum; + INT32 sfxnum; 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) { - sector_t *sec; - - while ((secnum = P_FindSectorFromLineTag(line, secnum)) >= 0) + 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 { - sec = §ors[secnum]; - S_StartSound(&sec->soundorg, sfxnum); + // Additionally play the sound from tagged sectors' soundorgs + sector_t *sec; + + while ((secnum = P_FindSectorFromLineTag(line, secnum)) >= 0) + { + sec = §ors[secnum]; + S_StartSound(&sec->soundorg, sfxnum); + } + } + else if (mo) // A mobj must have triggered the executor + { + // Only trigger if mobj is touching the tag + ffloor_t *rover; + boolean foundit = false; + + for(rover = mo->subsector->sector->ffloors; rover; rover = rover->next) + { + if (rover->master->frontsector->tag != line->tag) + continue; + + if (mo->z > P_GetSpecialTopZ(mo, sectors + rover->secnum, mo->subsector->sector)) + continue; + + if (mo->z + mo->height < P_GetSpecialBottomZ(mo, sectors + rover->secnum, mo->subsector->sector)) + continue; + + foundit = true; + } + + if (mo->subsector->sector->tag == line->tag) + foundit = true; + + if (!foundit) + return; } } - else if (line->tag != 0 && mo) + + if (line->flags & ML_NOCLIMB) { - // Only trigger if mobj is touching the tag - ffloor_t *rover; - boolean foundit = false; - - for(rover = mo->subsector->sector->ffloors; rover; rover = rover->next) - { - if (rover->master->frontsector->tag != line->tag) - continue; - - if (mo->z > P_GetSpecialTopZ(mo, sectors + rover->secnum, mo->subsector->sector)) - continue; - - if (mo->z + mo->height < P_GetSpecialBottomZ(mo, sectors + rover->secnum, mo->subsector->sector)) - continue; - - foundit = true; - } - - if (mo->subsector->sector->tag == line->tag) - foundit = true; - - if (!foundit) - return; - } - - if (sfxnum < NUMSFX && sfxnum > sfx_None) - { - if (line->flags & ML_NOCLIMB) - { - // play the sound from nowhere, but only if display player triggered it - if (mo && mo->player && (mo->player == &players[displayplayer] || mo->player == &players[secondarydisplayplayer])) - S_StartSound(NULL, sfxnum); - } - else if (line->flags & ML_EFFECT4) - { - // play the sound from nowhere + // play the sound from nowhere, but only if display player triggered it + if (mo && mo->player && (mo->player == &players[displayplayer] || mo->player == &players[secondarydisplayplayer])) S_StartSound(NULL, sfxnum); - } - else if (line->flags & ML_BLOCKMONSTERS) - { - // play the sound from calling sector's soundorg - if (callsec) - S_StartSound(&callsec->soundorg, sfxnum); - else if (mo) - S_StartSound(&mo->subsector->sector->soundorg, sfxnum); - } + } + else if (line->flags & ML_EFFECT4) + { + // play the sound from nowhere + S_StartSound(NULL, sfxnum); + } + else if (line->flags & ML_BLOCKMONSTERS) + { + // play the sound from calling sector's soundorg + if (callsec) + S_StartSound(&callsec->soundorg, sfxnum); else if (mo) - { - // play the sound from mobj that triggered it - S_StartSound(mo, sfxnum); - } + S_StartSound(&mo->subsector->sector->soundorg, sfxnum); + } + else if (mo) + { + // play the sound from mobj that triggered it + S_StartSound(mo, sfxnum); } } break; @@ -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"? // -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) 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 (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; + } + else goto DoneSection2; + if (!P_ThingIsOnThe3DFloor(players[i].mo, sector, roversector)) goto DoneSection2; } 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; if (special == 3 && !P_MobjReadyToTrigger(players[i].mo, sector)) @@ -4490,6 +4534,7 @@ sector_t *P_ThingOnSpecial3DFloor(mobj_t *mo) { sector_t *sector; ffloor_t *rover; + fixed_t topheight, bottomheight; sector = mo->subsector->sector; if (!sector->ffloors) @@ -4497,8 +4542,6 @@ sector_t *P_ThingOnSpecial3DFloor(mobj_t *mo) for (rover = sector->ffloors; rover; rover = rover->next) { - fixed_t topheight, bottomheight; - if (!rover->master->frontsector->special) continue; @@ -4546,6 +4589,8 @@ sector_t *P_ThingOnSpecial3DFloor(mobj_t *mo) 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 * applies any specials. * @@ -4554,12 +4599,12 @@ sector_t *P_ThingOnSpecial3DFloor(mobj_t *mo) */ static void P_PlayerOnSpecial3DFloor(player_t *player, sector_t *sector) { + sector_t *originalsector = player->mo->subsector->sector; ffloor_t *rover; + fixed_t topheight, bottomheight; for (rover = sector->ffloors; rover; rover = rover->next) { - fixed_t topheight, bottomheight; - if (!rover->master->frontsector->special) 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? if (sector == player->mo->subsector->sector || (rover->master->frontsector->flags & SF_TRIGGERSPECIAL_TOUCH)) + { P_ProcessSpecialSector(player, rover->master->frontsector, sector); + if TELEPORTED return; + } } // Allow sector specials to be applied to polyobjects! @@ -4614,7 +4662,7 @@ static void P_PlayerOnSpecial3DFloor(player_t *player, sector_t *sector) boolean touching = false; boolean inside = false; - while(po) + while (po) { if (po->flags & POF_NOSPECIALS) { @@ -4690,6 +4738,7 @@ static void P_PlayerOnSpecial3DFloor(player_t *player, sector_t *sector) } P_ProcessSpecialSector(player, polysec, sector); + if TELEPORTED return; 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) { - sector_t *sector; + sector_t *originalsector; + sector_t *loopsector; msecnode_t *node; if (!player->mo) return; - // Do your ->subsector->sector first - 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); + originalsector = player->mo->subsector->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) { - sector = node->m_sector; + loopsector = node->m_sector; - if (sector == player->mo->subsector->sector) // Don't duplicate + if (loopsector == originalsector) // Don't duplicate continue; // Check 3D floors... - P_PlayerOnSpecial3DFloor(player, sector); + P_PlayerOnSpecial3DFloor(player, loopsector); + if TELEPORTED return; - if (!(sector->flags & SF_TRIGGERSPECIAL_TOUCH)) - return; - // 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); + if (!(loopsector->flags & SF_TRIGGERSPECIAL_TOUCH)) + continue; + + P_RunSpecialSectorCheck(player, loopsector); + if TELEPORTED return; } } +#undef TELEPORTED + /** Animate planes, scroll walls, etc. and keeps track of level timelimit and exits if time is up. * * \sa P_CheckTimeLimit, P_CheckPointLimit diff --git a/src/p_user.c b/src/p_user.c index 7ea6c9269..736e514dd 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -1729,9 +1729,8 @@ void P_DoPlayerExit(player_t *player) #define SPACESPECIAL 12 boolean P_InSpaceSector(mobj_t *mo) // Returns true if you are in space { - sector_t *sector; - - sector = mo->subsector->sector; + sector_t *sector = mo->subsector->sector; + fixed_t topheight, bottomheight; if (GETSECSPECIAL(sector->special, 1) == SPACESPECIAL) return true; @@ -1744,11 +1743,18 @@ boolean P_InSpaceSector(mobj_t *mo) // Returns true if you are in space { if (GETSECSPECIAL(rover->master->frontsector->special, 1) != SPACESPECIAL) 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; - if (mo->z + (mo->height/2) < *rover->bottomheight) + if (mo->z + (mo->height/2) < bottomheight) continue; return true; @@ -1760,9 +1766,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 { - 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) { @@ -1776,10 +1783,18 @@ boolean P_InQuicksand(mobj_t *mo) // Returns true if you are in quicksand if (!(rover->flags & FF_QUICKSAND)) 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; - if (mo->z + (mo->height/2) < *rover->bottomheight) + if (mo->z + (mo->height/2) + flipoffset < bottomheight) continue; return true; @@ -2090,6 +2105,7 @@ static void P_CheckQuicksand(player_t *player) { ffloor_t *rover; fixed_t sinkspeed, friction; + fixed_t topheight, bottomheight; if (!(player->mo->subsector->sector->ffloors && player->mo->momz <= 0)) return; @@ -2101,16 +2117,38 @@ static void P_CheckQuicksand(player_t *player) if (!(rover->flags & FF_QUICKSAND)) 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 = FixedDiv(sinkspeed,TICRATE*FRACUNIT); - player->mo->z -= sinkspeed; + if (player->mo->eflags & MFE_VERTICALFLIP) + { + fixed_t ceilingheight = P_GetCeilingZ(player->mo, player->mo->subsector->sector, player->mo->x, player->mo->y, NULL); - if (player->mo->z <= player->mo->subsector->sector->floorheight) - player->mo->z = player->mo->subsector->sector->floorheight; + 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; + + if (player->mo->z <= floorheight) + player->mo->z = floorheight; + } friction = abs(rover->master->v1->y - rover->master->v2->y)>>6; @@ -2460,11 +2498,11 @@ static void P_DoClimbing(player_t *player) floorclimb = true; #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; + bottomheight = *rover->b_slope ? P_GetZAt(*rover->b_slope, player->mo->x, player->mo->y) : *rover->bottomheight; #else - bottomheight = *rover->bottomheight; topheight = *rover->topheight; + bottomheight = *rover->bottomheight; #endif // Only supports rovers that are moving like an 'elevator', not just the top or bottom. @@ -2653,13 +2691,20 @@ static void P_DoClimbing(player_t *player) // Is there a FOF directly below that we can move onto? if (glidesector->sector->ffloors) { + fixed_t topheight; ffloor_t *rover; for (rover = glidesector->sector->ffloors; rover; rover = rover->next) { if (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_BLOCKPLAYER) || (rover->flags & FF_BUSTUP)) 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; break; @@ -3037,14 +3082,12 @@ static void P_DoTeeter(player_t *player) { 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; 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 if (P_CheckSolidLava(player->mo, rover)) @@ -9125,13 +9168,23 @@ static void P_CalcPostImg(player_t *player) else if (sector->ffloors) { ffloor_t *rover; + fixed_t topheight; + fixed_t bottomheight; for (rover = sector->ffloors; rover; rover = rover->next) { if (!(rover->flags & FF_EXISTS)) 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; if (P_FindSpecialLineFromTag(13, rover->master->frontsector->tag, -1) != -1) @@ -9143,13 +9196,23 @@ static void P_CalcPostImg(player_t *player) if (sector->ffloors) { ffloor_t *rover; + fixed_t topheight; + fixed_t bottomheight; for (rover = sector->ffloors; rover; rover = rover->next) { if (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_SWIMMABLE) || rover->flags & FF_BLOCKPLAYER) 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; *type = postimg_water; @@ -9381,6 +9444,7 @@ void P_PlayerThink(player_t *player) // check water content, set stuff in mobj P_MobjCheckWater(player->mo); +#ifndef SECTORSPECIALSAFTERTHINK #ifdef POLYOBJECTS if (player->onconveyor != 1 || !P_IsObjectOnGround(player->mo)) #endif @@ -9389,7 +9453,11 @@ void P_PlayerThink(player_t *player) if (!player->spectator) P_PlayerInSpecialSector(player); - else if (gametype == GT_COOP && (netgame || multiplayer) && cv_coopstarposts.value == 2) + else if ( +#else + if (player->spectator && +#endif + gametype == GT_COOP && (netgame || multiplayer) && cv_coopstarposts.value == 2) P_ConsiderAllGone(); if (player->playerstate == PST_DEAD) @@ -9782,6 +9850,17 @@ void P_PlayerAfterThink(player_t *player) 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]) thiscam = &camera2; else if (player == &players[displayplayer]) diff --git a/src/r_bsp.c b/src/r_bsp.c index 44cb991a7..abb11204a 100644 --- a/src/r_bsp.c +++ b/src/r_bsp.c @@ -1222,6 +1222,9 @@ static void R_Subsector(size_t num) while (count--) { // 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); 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 */ diff --git a/src/sdl/i_video.c b/src/sdl/i_video.c index ad60f9c53..f4ebb6df9 100644 --- a/src/sdl/i_video.c +++ b/src/sdl/i_video.c @@ -158,7 +158,7 @@ static INT32 windowedModes[MAXWINMODES][2] = static void Impl_VideoSetupSDLBuffer(void); static void Impl_VideoSetupBuffer(void); 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 SDLSetMode(INT32 width, INT32 height, SDL_bool fullscreen) @@ -1188,7 +1188,7 @@ INT32 VID_SetMode(INT32 modeNum) } vid.modenum = -1; } - Impl_SetWindowName("SRB2 "VERSIONSTRING); + //Impl_SetWindowName("SRB2 "VERSIONSTRING); SDLSetMode(vid.width, vid.height, USE_FULLSCREEN); @@ -1271,14 +1271,16 @@ static SDL_bool Impl_CreateWindow(SDL_bool fullscreen) return SDL_TRUE; } +/* static void Impl_SetWindowName(const char *title) { - if (window != NULL) + if (window == NULL) { return; } SDL_SetWindowTitle(window, title); } +*/ static void Impl_SetWindowIcon(void) { diff --git a/src/sdl/macosx/Srb2mac.xcodeproj/project.pbxproj b/src/sdl/macosx/Srb2mac.xcodeproj/project.pbxproj index fbf9bacb2..68391f99c 100644 --- a/src/sdl/macosx/Srb2mac.xcodeproj/project.pbxproj +++ b/src/sdl/macosx/Srb2mac.xcodeproj/project.pbxproj @@ -1214,7 +1214,7 @@ C01FCF4B08A954540054247B /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - CURRENT_PROJECT_VERSION = 2.1.18; + CURRENT_PROJECT_VERSION = 2.1.19; GCC_PREPROCESSOR_DEFINITIONS = ( "$(inherited)", NORMALSRB2, @@ -1226,7 +1226,7 @@ C01FCF4C08A954540054247B /* Release */ = { isa = XCBuildConfiguration; buildSettings = { - CURRENT_PROJECT_VERSION = 2.1.18; + CURRENT_PROJECT_VERSION = 2.1.19; GCC_ENABLE_FIX_AND_CONTINUE = NO; GCC_GENERATE_DEBUGGING_SYMBOLS = NO; GCC_PREPROCESSOR_DEFINITIONS = ( diff --git a/src/sdl/ogl_sdl.c b/src/sdl/ogl_sdl.c index 21afd831d..cd7ced7ca 100644 --- a/src/sdl/ogl_sdl.c +++ b/src/sdl/ogl_sdl.c @@ -71,7 +71,6 @@ INT32 oglflags = 0; void *GLUhandle = NULL; SDL_GLContext sdlglcontext = 0; -#ifndef STATIC_OPENGL void *GetGLFunc(const char *proc) { if (strncmp(proc, "glu", 3) == 0) @@ -83,7 +82,6 @@ void *GetGLFunc(const char *proc) } return SDL_GL_GetProcAddress(proc); } -#endif boolean LoadGL(void) { diff --git a/src/sdl12/macosx/Srb2mac.xcodeproj/project.pbxproj b/src/sdl12/macosx/Srb2mac.xcodeproj/project.pbxproj index 98a760c7b..fada7849c 100644 --- a/src/sdl12/macosx/Srb2mac.xcodeproj/project.pbxproj +++ b/src/sdl12/macosx/Srb2mac.xcodeproj/project.pbxproj @@ -1214,7 +1214,7 @@ C01FCF4B08A954540054247B /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - CURRENT_PROJECT_VERSION = 2.1.18; + CURRENT_PROJECT_VERSION = 2.1.19; GCC_PREPROCESSOR_DEFINITIONS = ( "$(inherited)", NORMALSRB2, @@ -1226,7 +1226,7 @@ C01FCF4C08A954540054247B /* Release */ = { isa = XCBuildConfiguration; buildSettings = { - CURRENT_PROJECT_VERSION = 2.1.18; + CURRENT_PROJECT_VERSION = 2.1.19; GCC_ENABLE_FIX_AND_CONTINUE = NO; GCC_GENERATE_DEBUGGING_SYMBOLS = NO; GCC_PREPROCESSOR_DEFINITIONS = ( diff --git a/src/win32/win_cd.c b/src/win32/win_cd.c index d73b95523..ae13d3e57 100644 --- a/src/win32/win_cd.c +++ b/src/win32/win_cd.c @@ -180,9 +180,9 @@ static LPSTR hms(UINT seconds) hours = minutes / 60; minutes %= 60; 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 - sprintf (s, "%2lu:%02lu", minutes, seconds); + sprintf (s, "%2lu:%02lu", (long unsigned int)minutes, (long unsigned int)seconds); return s; } diff --git a/src/win32/win_main.c b/src/win32/win_main.c index d84c86232..4ac05f94f 100644 --- a/src/win32/win_main.c +++ b/src/win32/win_main.c @@ -470,7 +470,7 @@ static inline BOOL tlErrorMessage(const TCHAR *err) // // warn user if there is one // - printf("Error %Ts..\n", err); + printf("Error %s..\n", err); fflush(stdout); MessageBox(hWndMain, err, TEXT("ERROR"), MB_OK); diff --git a/src/y_inter.c b/src/y_inter.c index b92b0a5ca..9660f9287 100644 --- a/src/y_inter.c +++ b/src/y_inter.c @@ -1008,7 +1008,8 @@ void Y_StartIntermission(void) } // 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... if(!mapheaderinfo[prevmap])