diff --git a/assets/HISTORY.txt b/assets/HISTORY.txt index dfa06f2c7..5c7fe3b00 100644 --- a/assets/HISTORY.txt +++ b/assets/HISTORY.txt @@ -129,7 +129,7 @@ Oni: Sev, Sal, and toast were the most unexpected things to ever happen to this [Oni wiping sweat off his brow] Things only got more drastically revamped… very very rapidly. - The Mario aesthetic was entirely tossed out, as Sal was willing to work with me night and day on redoing most of everything about items… and then sounds. My power level for sprites massively jumped during TD development, so I decided to take it upon myself to do almost everything. They’re such friendly and cooperative coders that I can’t help but push a little harder than I used to (I was WAY lazier before they got here) to keep up. + The Mario aesthetic was entirely tossed out, as Sal was willing to work with me night and day on redoing most of everything about items… and then sounds. My power level for sprites massively jumped during TD development, so I decided to take it upon myself to do almost everything. They’re such friendly and cooperative coders that I can’t help but push a little harder than I used to (I was WAY lazier before they got here) to keep up. diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index faa860d44..e93777cbd 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -379,6 +379,12 @@ if(${SRB2_CONFIG_HAVE_PNG} AND ${SRB2_CONFIG_HAVE_ZLIB}) set(SRB2_HAVE_PNG ON) add_definitions(-DHAVE_PNG) add_definitions(-D_LARGEFILE64_SOURCE) + set(SRB2_PNG_SOURCES apng.c) + set(SRB2_PNG_HEADERS apng.h) + prepend_sources(SRB2_PNG_SOURCES) + prepend_sources(SRB2_PNG_HEADERS) + source_group("Main" FILES ${SRB2_CORE_SOURCES} ${SRB2_CORE_HEADERS} + ${SRB2_PNG_SOURCES} ${SRB2_PNG_HEADERS}) else() message(WARNING "You have specified that PNG is available but it was not found. SRB2Kart may not compile correctly.") endif() diff --git a/src/Makefile b/src/Makefile index 687cee404..7cfde5630 100644 --- a/src/Makefile +++ b/src/Makefile @@ -341,6 +341,8 @@ endif LIBS+=$(PNG_LDFLAGS) CFLAGS+=$(PNG_CFLAGS) + +OBJS+=$(OBJDIR)/apng.o endif ifdef HAVE_LIBGME diff --git a/src/apng.c b/src/apng.c new file mode 100644 index 000000000..694b3d1e8 --- /dev/null +++ b/src/apng.c @@ -0,0 +1,289 @@ +/* +Copyright 2019, James R. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include +#include + +#include "apng.h" + +#define APNG_INFO_acTL 0x20000U + +#define APNG_WROTE_acTL 0x10000U + +struct apng_info_def +{ + png_uint_32 mode; + png_uint_32 valid; + + png_uint_32 num_frames; + png_uint_32 num_plays; + + long start_acTL;/* acTL is written here */ + + png_flush_ptr output_flush_fn; + apng_seek_ptr output_seek_fn; + apng_tell_ptr output_tell_fn; + + apng_set_acTL_ptr set_acTL_fn; +}; + +/* PROTOS (FUCK COMPILER) */ +void apng_seek (png_structp, apng_const_infop, size_t); +size_t apng_tell (png_structp, apng_const_infop); +#ifdef PNG_WRITE_FLUSH_SUPPORTED +void apng_flush (png_structp, apng_infop); +#ifdef PNG_STDIO_SUPPORTED +void apng_default_flush (png_structp); +#endif/* PNG_STDIO_SUPPORTED */ +#endif/* PNG_WRITE_FLUSH_SUPPORTED */ +#ifdef PNG_STDIO_SUPPORTED +void apng_default_seek (png_structp, size_t); +size_t apng_default_tell (png_structp); +#endif/* PNG_STDIO_SUPPORTED */ +void apng_write_IEND (png_structp); +void apng_write_acTL (png_structp, png_uint_32, png_uint_32); +#ifndef PNG_WRITE_APNG_SUPPORTED +png_uint_32 apng_set_acTL_dummy (png_structp, png_infop, + png_uint_32, png_uint_32); +#endif/* PNG_WRITE_APNG_SUPPORTED */ + +apng_infop +apng_create_info_struct (png_structp pngp) +{ + apng_infop ainfop; + (void)pngp; + if (( ainfop = calloc(sizeof (apng_info),1) )) + { + apng_set_write_fn(pngp, ainfop, 0, 0, 0, 0, 0); + apng_set_set_acTL_fn(pngp, ainfop, 0); + } + return ainfop; +} + +void +apng_destroy_info_struct (png_structp pngp, apng_infopp ainfopp) +{ + (void)pngp; + if (!( pngp && ainfopp )) + return; + + free((*ainfopp)); +} + +void +apng_seek (png_structp pngp, apng_const_infop ainfop, size_t l) +{ + (*(ainfop->output_seek_fn))(pngp, l); +} + +size_t +apng_tell (png_structp pngp, apng_const_infop ainfop) +{ + return (*(ainfop->output_tell_fn))(pngp); +} + +#ifdef PNG_WRITE_FLUSH_SUPPORTED +void +apng_flush (png_structp pngp, apng_infop ainfop) +{ + if (ainfop->output_flush_fn) + (*(ainfop->output_flush_fn))(pngp); +} + +#ifdef PNG_STDIO_SUPPORTED +void +apng_default_flush (png_structp pngp) +{ + if (!( pngp )) + return; + + fflush((png_FILE_p)png_get_io_ptr); +} +#endif/* PNG_STDIO_SUPPORTED */ +#endif/* PNG_WRITE_FLUSH_SUPPORTED */ + +#ifdef PNG_STDIO_SUPPORTED +void +apng_default_seek (png_structp pngp, size_t l) +{ + if (!( pngp )) + return; + + if (fseek((png_FILE_p)png_get_io_ptr(pngp), (long)l, SEEK_SET) == -1) + png_error(pngp, "Seek Error"); +} + +size_t +apng_default_tell (png_structp pngp) +{ + long l; + + if (!( pngp )) + { + png_error(pngp, "Call to apng_default_tell with NULL pngp failed"); + } + + if (( l = ftell((png_FILE_p)png_get_io_ptr(pngp)) ) == -1) + png_error(pngp, "Tell Error"); + + return (size_t)l; +} +#endif/* PNG_STDIO_SUPPORTED */ + +void +apng_set_write_fn (png_structp pngp, apng_infop ainfop, png_voidp iop, + png_rw_ptr write_f, png_flush_ptr flush_f, + apng_seek_ptr seek_f, apng_tell_ptr tell_f) +{ + if (!( pngp && ainfop )) + return; + + png_set_write_fn(pngp, iop, write_f, flush_f); + +#ifdef PNG_WRITE_FLUSH_SUPPORTED +#ifdef PNG_STDIO_SUPPORTED + if (!flush_f) + ainfop->output_flush_fn = &apng_default_flush; + else +#endif/* PNG_STDIO_SUPPORTED */ + ainfop->output_flush_fn = flush_f; +#endif/* PNG_WRITE_FLUSH_SUPPORTED */ +#ifdef PNG_STDIO_SUPPORTED + if (!seek_f) + ainfop->output_seek_fn = &apng_default_seek; + else +#endif/* PNG_STDIO_SUPPORTED */ + ainfop->output_seek_fn = seek_f; +#ifdef PNG_STDIO_SUPPORTED + if (!seek_f) + ainfop->output_tell_fn = apng_default_tell; + else +#endif/* PNG_STDIO_SUPPORTED */ + ainfop->output_tell_fn = tell_f; +} + +void +apng_write_IEND (png_structp pngp) +{ + png_byte chunkc[] = "IEND"; + png_write_chunk(pngp, chunkc, 0, 0); +} + +void +apng_write_acTL (png_structp pngp, png_uint_32 frames, png_uint_32 plays) +{ + png_byte chunkc[] = "acTL"; + png_byte buf[8]; + png_save_uint_32(buf, frames); + png_save_uint_32(buf + 4, plays); + png_write_chunk(pngp, chunkc, buf, 8); +} + +png_uint_32 +apng_set_acTL (png_structp pngp, png_infop infop, apng_infop ainfop, + png_uint_32 frames, png_uint_32 plays) +{ + (void)pngp; + (void)infop; + if (!( pngp && infop && ainfop )) + return 0; + + ainfop->num_frames = frames; + ainfop->num_plays = plays; + + ainfop->valid |= APNG_INFO_acTL; + + return 1; +} + +void +apng_write_info_before_PLTE (png_structp pngp, png_infop infop, + apng_infop ainfop) +{ + if (!( pngp && infop && ainfop )) + return; + + png_write_info_before_PLTE(pngp, infop); + + if (( ainfop->valid & APNG_INFO_acTL )&&!( ainfop->mode & APNG_WROTE_acTL )) + { + ainfop->start_acTL = apng_tell(pngp, ainfop); + + apng_write_acTL(pngp, 0, 0); + /* modified for runtime dynamic linking */ + (*(ainfop->set_acTL_fn))(pngp, infop, PNG_UINT_31_MAX, 0); + + ainfop->mode |= APNG_WROTE_acTL; + } +} + +void +apng_write_info (png_structp pngp, png_infop infop, + apng_infop ainfop) +{ + apng_write_info_before_PLTE(pngp, infop, ainfop); + png_write_info(pngp, infop); +} + +void +apng_write_end (png_structp pngp, png_infop infop, apng_infop ainfop) +{ + (void)infop; + apng_write_IEND(pngp); + apng_seek(pngp, ainfop, ainfop->start_acTL); + apng_write_acTL(pngp, ainfop->num_frames, ainfop->num_plays); + +#ifdef PNG_WRITE_FLUSH_SUPPORTED +#ifdef PNG_WRITE_FLUSH_AFTER_IEND_SUPPORTED + apng_flush(pngp, infop); +#endif/* PNG_WRITE_FLUSH_SUPPORTED */ +#endif/* PNG_WRITE_FLUSH_AFTER_IEND_SUPPORTED */ +} + +#ifndef PNG_WRITE_APNG_SUPPORTED +png_uint_32 +apng_set_acTL_dummy (png_structp pngp, png_infop infop, + png_uint_32 frames, png_uint_32 plays) +{ + (void)pngp; + (void)infop; + (void)frames; + (void)plays; + return 0; +} +#endif/* PNG_WRITE_APNG_SUPPORTED */ + +/* Dynamic runtime linking capable! (Hopefully.) */ +void +apng_set_set_acTL_fn (png_structp pngp, apng_infop ainfop, + apng_set_acTL_ptr set_acTL_f) +{ + (void)pngp; + if (!ainfop->set_acTL_fn) +#ifndef PNG_WRITE_APNG_SUPPORTED + ainfop->set_acTL_fn = &apng_set_acTL_dummy; +#else + ainfop->set_acTL_fn = &png_set_acTL; +#endif/* PNG_WRITE_APNG_SUPPORTED */ + else + ainfop->set_acTL_fn = set_acTL_f; +} diff --git a/src/apng.h b/src/apng.h new file mode 100644 index 000000000..aa7fac3df --- /dev/null +++ b/src/apng.h @@ -0,0 +1,82 @@ +/* +Copyright 2019, James R. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef APNG_H +#define APNG_H + +#ifndef _MSC_VER +#ifndef _WII +#ifndef _LARGEFILE64_SOURCE +#define _LARGEFILE64_SOURCE +#endif +#endif +#endif + +#ifndef _LFS64_LARGEFILE +#define _LFS64_LARGEFILE +#endif + +#ifndef _FILE_OFFSET_BITS +#define _FILE_OFFSET_BITS 0 +#endif + +#include + +typedef struct apng_info_def apng_info; +typedef apng_info * apng_infop; +typedef const apng_info * apng_const_infop; +typedef apng_info * * apng_infopp; + +typedef void (*apng_seek_ptr)(png_structp, size_t); +typedef size_t (*apng_tell_ptr)(png_structp); + +typedef png_uint_32 (*apng_set_acTL_ptr)(png_structp, png_infop, + png_uint_32, png_uint_32); + +apng_infop apng_create_info_struct (png_structp png_ptr); + +void apng_destroy_info_struct (png_structp png_ptr, + apng_infopp info_ptr_ptr); + +/* Call the following functions in place of the libpng counterparts. */ + +png_uint_32 apng_set_acTL (png_structp png_ptr, png_infop info_ptr, + apng_infop ainfo_ptr, + png_uint_32 num_frames, png_uint_32 num_plays); + +void apng_write_info_before_PLTE (png_structp png_ptr, png_infop info_ptr, + apng_infop ainfo_ptr); +void apng_write_info (png_structp png_ptr, png_infop info_ptr, + apng_infop ainfo_ptr); + +void apng_write_end (png_structp png_ptr, png_infop info_ptr, + apng_infop ainfo_ptr); + +void apng_set_write_fn (png_structp png_ptr, apng_infop ainfo_ptr, + png_voidp io_ptr, + png_rw_ptr write_data_fn, png_flush_ptr output_flush_fn, + apng_seek_ptr output_seek_fn, apng_tell_ptr output_tell_fn); + +void apng_set_set_acTL_fn (png_structp png_ptr, apng_infop ainfo_ptr, + apng_set_acTL_ptr set_acTL_fn); + +#endif/* APNG_H */ diff --git a/src/config.h.in b/src/config.h.in index cb343d065..a1f5d0a6e 100644 --- a/src/config.h.in +++ b/src/config.h.in @@ -37,7 +37,7 @@ * Last updated 2015 / 05 / 03 - SRB2 v2.1.15 - srb2.srb * Last updated 2018 / 12 / 23 - SRB2 v2.1.22 - patch.dta * Last updated 2019 / 01 / 18 - Kart v1.0.2 - Main assets - * Last updated 2019 / 01 / 15 - Kart v1.0.2 - patch.kart + * Last updated 2019 / 02 / 04 - Kart v1.0.3 - patch.kart */ // Base SRB2 hashes @@ -52,7 +52,7 @@ #define ASSET_HASH_CHARS_KART "e2c428347dde52858a3dacd29fc5b964" #define ASSET_HASH_MAPS_KART "1335cd064656aedca359cfbb5233ac4a" #ifdef USE_PATCH_KART -#define ASSET_HASH_PATCH_KART "899aee1b63e731b7e2098406c85608b4" +#define ASSET_HASH_PATCH_KART "e06c1c90e5645c886026311964f8e1f5" #endif #endif diff --git a/src/d_clisrv.c b/src/d_clisrv.c index c84faa721..7516df2e0 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -2211,8 +2211,10 @@ static void CL_ConnectToServer(boolean viams) } while (!(cl_mode == CL_CONNECTED && (client || (server && nodewaited <= pnumnodes)))); +#ifndef NONET if (netgame) F_StartWaitingPlayers(); +#endif DEBFILE(va("Synchronisation Finished\n")); displayplayer = consoleplayer; @@ -4083,6 +4085,21 @@ FILESTAMP else if (resynch_score[node]) --resynch_score[node]; break; + case PT_BASICKEEPALIVE: + if (client) + break; + + // This should probably still timeout though, as the node should always have a player 1 number + if (netconsole == -1) + break; + + // If a client sends this it should mean they are done receiving the savegame + sendingsavegame[node] = false; + + // As long as clients send keep alives, the server can keep running, so reset the timeout + /// \todo Use a separate cvar for that kind of timeout? + freezetimeout[node] = I_GetTime() + connectiontimeout; + break; case PT_TEXTCMD: case PT_TEXTCMD2: case PT_TEXTCMD3: @@ -4586,6 +4603,15 @@ static INT16 Consistancy(void) return (INT16)(ret & 0xFFFF); } +// confusing, but this DOESN'T send PT_NODEKEEPALIVE, it sends PT_BASICKEEPALIVE +// used during wipes to tell the server that a node is still connected +static void CL_SendClientKeepAlive(void) +{ + netbuffer->packettype = PT_BASICKEEPALIVE; + + HSendPacket(servernode, false, 0, 0); +} + // send the client packet to the server static void CL_SendClientCmd(void) { @@ -5032,9 +5058,77 @@ static inline void PingUpdate(void) } #endif +static tic_t gametime = 0; + +#ifdef NEWPING +static void UpdatePingTable(void) +{ + INT32 i; + if (server) + { + if (netgame && !(gametime % 255)) + PingUpdate(); + // update node latency values so we can take an average later. + for (i = 0; i < MAXPLAYERS; i++) + if (playeringame[i]) + realpingtable[i] += G_TicsToMilliseconds(GetLag(playernode[i])); + pingmeasurecount++; + } +} +#endif + +// Handle timeouts to prevent definitive freezes from happenning +static void HandleNodeTimeouts(void) +{ + INT32 i; + if (server) + for (i = 1; i < MAXNETNODES; i++) + if (nodeingame[i] && freezetimeout[i] < I_GetTime()) + Net_ConnectionTimeout(i); +} + +// Keep the network alive while not advancing tics! +void NetKeepAlive(void) +{ + tic_t nowtime; + INT32 realtics; + + nowtime = I_GetTime(); + realtics = nowtime - gametime; + + // return if there's no time passed since the last call + if (realtics <= 0) // nothing new to update + return; + +#ifdef NEWPING + UpdatePingTable(); +#endif + + if (server) + CL_SendClientKeepAlive(); + +// Sryder: What is FILESTAMP??? +FILESTAMP + GetPackets(); +FILESTAMP + + MasterClient_Ticker(); + + if (client) + { + // send keep alive + CL_SendClientKeepAlive(); + // No need to check for resynch because we aren't running any tics + } + // No else because no tics are being run and we can't resynch during this + + Net_AckTicker(); + HandleNodeTimeouts(); + SV_FileSendTicker(); +} + void NetUpdate(void) { - static tic_t gametime = 0; static tic_t resptime = 0; tic_t nowtime; INT32 i; @@ -5056,16 +5150,7 @@ void NetUpdate(void) gametime = nowtime; #ifdef NEWPING - if (server) - { - if (netgame && !(gametime % 255)) - PingUpdate(); - // update node latency values so we can take an average later. - for (i = 0; i < MAXPLAYERS; i++) - if (playeringame[i]) - realpingtable[i] += G_TicsToMilliseconds(GetLag(playernode[i])); - pingmeasurecount++; - } + UpdatePingTable(); #endif if (client) @@ -5133,12 +5218,7 @@ FILESTAMP } } Net_AckTicker(); - // Handle timeouts to prevent definitive freezes from happenning - if (server) - for (i = 1; i < MAXNETNODES; i++) - if (nodeingame[i] && freezetimeout[i] < I_GetTime()) - Net_ConnectionTimeout(i); - nowtime /= NEWTICRATERATIO; + HandleNodeTimeouts(); if (nowtime > resptime) { resptime = nowtime; diff --git a/src/d_clisrv.h b/src/d_clisrv.h index 39cb8c4de..62bd8bc17 100644 --- a/src/d_clisrv.h +++ b/src/d_clisrv.h @@ -71,6 +71,7 @@ typedef enum PT_CLIENT3MIS, PT_CLIENT4CMD, // 4P PT_CLIENT4MIS, + PT_BASICKEEPALIVE,// Keep the network alive during wipes, as tics aren't advanced and NetUpdate isn't called PT_CANFAIL, // This is kind of a priority. Anything bigger than CANFAIL // allows HSendPacket(*, true, *, *) to return false. @@ -538,6 +539,7 @@ void SendNetXCmd3(netxcmd_t id, const void *param, size_t nparam); // splitsreen void SendNetXCmd4(netxcmd_t id, const void *param, size_t nparam); // splitsreen4 player // Create any new ticcmds and broadcast to other players. +void NetKeepAlive(void); void NetUpdate(void); void SV_StartSinglePlayerServer(void); diff --git a/src/d_main.c b/src/d_main.c index 29a916863..28f89f4f0 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -1162,7 +1162,7 @@ void D_SRB2Main(void) if (s) // Check for NULL? { if (!W_VerifyNMUSlumps(s)) - G_SetGameModified(true); + G_SetGameModified(true, false); D_AddFile(s); } } @@ -1189,7 +1189,7 @@ void D_SRB2Main(void) else { if (!M_CheckParm("-server")) - G_SetGameModified(true); + G_SetGameModified(true, true); autostart = true; } } @@ -1325,10 +1325,6 @@ void D_SRB2Main(void) midi_disabled = true; #endif } - else - { - CONS_Printf("S_InitSfxChannels(): Setting up sound channels.\n"); - } if (M_CheckParm("-nosound")) sound_disabled = true; if (M_CheckParm("-nomusic")) // combines -nomidimusic and -nodigmusic @@ -1347,10 +1343,18 @@ void D_SRB2Main(void) if (M_CheckParm("-nodigmusic")) digital_disabled = true; // WARNING: DOS version initmusic in I_StartupSound } - I_StartupSound(); - I_InitMusic(); - S_InitSfxChannels(cv_soundvolume.value); - S_InitMusicDefs(); + if (!( sound_disabled && digital_disabled +#ifndef NO_MIDI + && midi_disabled +#endif + )) + { + CONS_Printf("S_InitSfxChannels(): Setting up sound channels.\n"); + I_StartupSound(); + I_InitMusic(); + S_InitSfxChannels(cv_soundvolume.value); + S_InitMusicDefs(); + } CONS_Printf("ST_Init(): Init status bar.\n"); ST_Init(); diff --git a/src/d_net.c b/src/d_net.c index 62301dc11..6702a60a4 100644 --- a/src/d_net.c +++ b/src/d_net.c @@ -903,6 +903,9 @@ static void DebugPrintpacket(const char *header) (UINT32)ExpandTics(netbuffer->u.clientpak.client_tic), (UINT32)ExpandTics (netbuffer->u.clientpak.resendfrom)); break; + case PT_BASICKEEPALIVE: + fprintf(debugfile, " keep alive\n"); + break; case PT_TEXTCMD: case PT_TEXTCMD2: case PT_TEXTCMD3: diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 8b5e9063a..cea468cc6 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -214,7 +214,7 @@ static CV_PossibleValue_t autobalance_cons_t[] = {{0, "MIN"}, {4, "MAX"}, {0, NU static CV_PossibleValue_t teamscramble_cons_t[] = {{0, "Off"}, {1, "Random"}, {2, "Points"}, {0, NULL}}; static CV_PossibleValue_t startingliveslimit_cons_t[] = {{1, "MIN"}, {99, "MAX"}, {0, NULL}}; -static CV_PossibleValue_t sleeping_cons_t[] = {{-1, "MIN"}, {1000/TICRATE, "MAX"}, {0, NULL}}; +static CV_PossibleValue_t sleeping_cons_t[] = {{0, "MIN"}, {1000/TICRATE, "MAX"}, {0, NULL}}; static CV_PossibleValue_t competitionboxes_cons_t[] = {{0, "Normal"}, {1, "Random"}, {2, "Teleports"}, {3, "None"}, {0, NULL}}; @@ -236,6 +236,9 @@ static consvar_t cv_dummyconsvar = {"dummyconsvar", "Off", CV_CALL|CV_NOSHOWHELP consvar_t cv_restrictskinchange = {"restrictskinchange", "No", CV_NETVAR|CV_CHEAT, CV_YesNo, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_allowteamchange = {"allowteamchange", "Yes", CV_NETVAR, CV_YesNo, NULL, 0, NULL, NULL, 0, 0, NULL}; +static CV_PossibleValue_t ingamecap_cons_t[] = {{0, "MIN"}, {MAXPLAYERS-1, "MAX"}, {0, NULL}}; +consvar_t cv_ingamecap = {"ingamecap", "0", CV_NETVAR, ingamecap_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; + consvar_t cv_startinglives = {"startinglives", "3", CV_NETVAR|CV_CHEAT|CV_NOSHOWHELP, startingliveslimit_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; static CV_PossibleValue_t respawntime_cons_t[] = {{0, "MIN"}, {30, "MAX"}, {0, NULL}}; @@ -449,7 +452,7 @@ consvar_t cv_runscripts = {"runscripts", "Yes", 0, CV_YesNo, NULL, 0, NULL, NULL consvar_t cv_pause = {"pausepermission", "Server", CV_NETVAR, pause_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_mute = {"mute", "Off", CV_NETVAR|CV_CALL, CV_OnOff, Mute_OnChange, 0, NULL, NULL, 0, 0, NULL}; -consvar_t cv_sleep = {"cpusleep", "-1", CV_SAVE, sleeping_cons_t, NULL, -1, NULL, NULL, 0, 0, NULL}; +consvar_t cv_sleep = {"cpusleep", "1", CV_SAVE, sleeping_cons_t, NULL, -1, NULL, NULL, 0, 0, NULL}; INT16 gametype = GT_RACE; // SRB2kart boolean forceresetplayers = false; @@ -644,6 +647,7 @@ void D_RegisterServerCommands(void) CV_RegisterVar(&cv_allowexitlevel); CV_RegisterVar(&cv_restrictskinchange); CV_RegisterVar(&cv_allowteamchange); + CV_RegisterVar(&cv_ingamecap); CV_RegisterVar(&cv_respawntime); CV_RegisterVar(&cv_killingdead); @@ -2211,10 +2215,12 @@ static void Command_Map_f(void) return; } - if (!(netgame || multiplayer) && (!modifiedgame || savemoddata)) + if (!(netgame || multiplayer) && !majormods) { if (COM_CheckParm("-force")) - G_SetGameModified(false); + { + G_SetGameModified(false, true); + } else { CONS_Printf(M_GetText("Sorry, level change disabled in single player.\n")); @@ -3793,7 +3799,7 @@ static void Command_RunSOC(void) if (!P_RunSOC(fn)) CONS_Printf(M_GetText("Could not find SOC.\n")); else - G_SetGameModified(multiplayer); + G_SetGameModified(multiplayer, false); return; } @@ -3847,7 +3853,7 @@ static void Got_RunSOCcmd(UINT8 **cp, INT32 playernum) } P_RunSOC(filename); - G_SetGameModified(true); + G_SetGameModified(true, false); } /** Adds a pwad at runtime. @@ -3884,7 +3890,7 @@ static void Command_Addfile(void) CONS_Printf(M_GetText("Only the server or a remote admin can use this.\n")); return; } - G_SetGameModified(multiplayer); + G_SetGameModified(multiplayer, false); } // Add file on your client directly if it is trivial, or you aren't in a netgame. @@ -4130,7 +4136,7 @@ static void Got_Addfilecmd(UINT8 **cp, INT32 playernum) return; } - G_SetGameModified(true); + G_SetGameModified(true, false); } static void Command_ListWADS_f(void) @@ -4487,7 +4493,7 @@ static void Ringslinger_OnChange(void) } if (cv_ringslinger.value) // Only if it's been turned on - G_SetGameModified(multiplayer); + G_SetGameModified(multiplayer, true); } static void Gravity_OnChange(void) @@ -4508,7 +4514,7 @@ static void Gravity_OnChange(void) #endif if (!CV_IsSetToDefault(&cv_gravity)) - G_SetGameModified(multiplayer); + G_SetGameModified(multiplayer, true); gravity = cv_gravity.value; } @@ -4904,7 +4910,7 @@ static void Fishcake_OnChange(void) // so don't make modifiedgame always on! if (cv_debug) { - G_SetGameModified(multiplayer); + G_SetGameModified(multiplayer, true); } else if (cv_debug != cv_fishcake.value) @@ -4920,12 +4926,14 @@ static void Fishcake_OnChange(void) */ static void Command_Isgamemodified_f(void) { - if (savemoddata) - CONS_Printf(M_GetText("modifiedgame is true, but you can save medal and record data in this mod.\n")); + if (majormods) + CONS_Printf("The game has been modified with major add-ons, so you cannot play Record Attack.\n"); + else if (savemoddata) + CONS_Printf("The game has been modified with an add-on with its own save data, so you can play Record Attack and earn medals.\n"); else if (modifiedgame) - CONS_Printf(M_GetText("modifiedgame is true, extras will not be unlocked\n")); + CONS_Printf("The game has been modified with only minor add-ons. You can play Record Attack, earn medals and unlock extras.\n"); else - CONS_Printf(M_GetText("modifiedgame is false, you can unlock extras\n")); + CONS_Printf("The game has not been modified. You can play Record Attack, earn medals and unlock extras.\n"); } static void Command_Cheats_f(void) diff --git a/src/d_netcmd.h b/src/d_netcmd.h index f78ba3097..05be43a68 100644 --- a/src/d_netcmd.h +++ b/src/d_netcmd.h @@ -93,7 +93,7 @@ extern consvar_t cv_mute; extern consvar_t cv_killingdead; extern consvar_t cv_pause; -extern consvar_t cv_restrictskinchange, cv_allowteamchange, cv_respawntime; +extern consvar_t cv_restrictskinchange, cv_allowteamchange, cv_ingamecap, cv_respawntime; /*extern consvar_t cv_teleporters, cv_superring, cv_supersneakers, cv_invincibility; extern consvar_t cv_jumpshield, cv_watershield, cv_ringshield, cv_forceshield, cv_bombshield; diff --git a/src/d_netfil.c b/src/d_netfil.c index c7cfdbc11..99a058403 100644 --- a/src/d_netfil.c +++ b/src/d_netfil.c @@ -426,7 +426,7 @@ void CL_LoadServerFiles(void) else if (fileneeded[i].status == FS_FOUND) { P_AddWadFile(fileneeded[i].filename); - G_SetGameModified(true); + G_SetGameModified(true, false); fileneeded[i].status = FS_OPEN; } else if (fileneeded[i].status == FS_MD5SUMBAD) diff --git a/src/d_player.h b/src/d_player.h index 27fdef8dc..b430f20a4 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -348,10 +348,12 @@ typedef enum k_wanted, // Timer for determining WANTED status, lowers when hitting people, prevents the game turning into Camp Lazlo k_yougotem, // "You Got Em" gfx when hitting someone as a karma player via a method that gets you back in the game instantly - // v1.0.2 vars + // v1.0.2+ vars k_itemblink, // Item flashing after roulette, prevents Hyudoro stealing AND serves as a mashing indicator k_itemblinkmode, // Type of flashing: 0 = white (normal), 1 = red (mashing), 2 = rainbow (enhanced items) k_getsparks, // Disable drift sparks at low speed, JUST enough to give acceleration the actual headstart above speed + k_jawztargetdelay, // Delay for Jawz target switching, to make it less twitchy + k_spectatewait, // How long have you been waiting as a spectator NUMKARTSTUFF } kartstufftype_t; diff --git a/src/dehacked.c b/src/dehacked.c index b9e29bc47..11aed24d0 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -21,6 +21,7 @@ #include "w_wad.h" #include "m_menu.h" #include "m_misc.h" +#include "filesrch.h" // for refreshdirmenu #include "f_finale.h" #include "dehacked.h" #include "st_stuff.h" @@ -79,8 +80,6 @@ static powertype_t get_power(const char *word); boolean deh_loaded = false; static int dbg_line; -static boolean gamedataadded = false; - #ifdef DELFILE typedef struct undehacked_s { @@ -602,6 +601,14 @@ done: Z_Free(s); } +static int freeslotusage[2][2] = {{0, 0}, {0, 0}}; // [S_, MT_][max, previous .wad's max] + +void DEH_UpdateMaxFreeslots(void) +{ + freeslotusage[0][1] = freeslotusage[0][0]; + freeslotusage[1][1] = freeslotusage[1][0]; +} + // TODO: Figure out how to do undolines for this.... // TODO: Warnings for running out of freeslots static void readfreeslots(MYFILE *f) @@ -664,6 +671,7 @@ static void readfreeslots(MYFILE *f) if (!FREE_STATES[i]) { FREE_STATES[i] = Z_Malloc(strlen(word)+1, PU_STATIC, NULL); strcpy(FREE_STATES[i],word); + freeslotusage[0][0]++; break; } } @@ -673,6 +681,7 @@ static void readfreeslots(MYFILE *f) if (!FREE_MOBJS[i]) { FREE_MOBJS[i] = Z_Malloc(strlen(word)+1, PU_STATIC, NULL); strcpy(FREE_MOBJS[i],word); + freeslotusage[1][0]++; break; } } @@ -3139,6 +3148,7 @@ static void readmaincfg(MYFILE *f) strlcpy(gamedatafilename, word2, sizeof (gamedatafilename)); strlwr(gamedatafilename); savemoddata = true; + majormods = false; // Also save a time attack folder filenamelen = strlen(gamedatafilename)-4; // Strip off the extension @@ -3151,7 +3161,7 @@ static void readmaincfg(MYFILE *f) // can't use sprintf since there is %u in savegamename strcatbf(savegamename, srb2home, PATHSEP); - gamedataadded = true; + refreshdirmenu |= REFRESHDIR_GAMEDATA; } else if (fastcmp(word, "RESETDATA")) { @@ -3382,8 +3392,6 @@ static void DEH_LoadDehackedFile(MYFILE *f, UINT16 wad) for (i = 0; i < NUMSFX; i++) savesfxnames[i] = S_sfx[i].name; - gamedataadded = false; - // it doesn't test the version of SRB2 and version of dehacked file dbg_line = -1; // start at -1 so the first line is 0. while (!myfeof(f)) @@ -3417,10 +3425,12 @@ static void DEH_LoadDehackedFile(MYFILE *f, UINT16 wad) if (fastcmp(word, "FREESLOT")) { readfreeslots(f); + // This is not a major mod. continue; } else if (fastcmp(word, "MAINCFG")) { + G_SetGameModified(multiplayer, true); readmaincfg(f); DEH_WriteUndoline(word, "", UNDO_HEADER); continue; @@ -3429,6 +3439,7 @@ static void DEH_LoadDehackedFile(MYFILE *f, UINT16 wad) { readwipes(f); DEH_WriteUndoline(word, "", UNDO_HEADER); + // This is not a major mod. continue; } word2 = strtok(NULL, " "); @@ -3449,6 +3460,7 @@ static void DEH_LoadDehackedFile(MYFILE *f, UINT16 wad) ignorelines(f); } DEH_WriteUndoline(word, word2, UNDO_HEADER); + // This is not a major mod. continue; } if (word2) @@ -3462,19 +3474,25 @@ static void DEH_LoadDehackedFile(MYFILE *f, UINT16 wad) // Read texture from spec file. readtexture(f, word2); DEH_WriteUndoline(word, word2, UNDO_HEADER); + // This is not a major mod. } else if (fastcmp(word, "PATCH")) { // Read patch from spec file. readpatch(f, word2, wad); DEH_WriteUndoline(word, word2, UNDO_HEADER); + // This is not a major mod. } else 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 if (i < NUMMOBJTYPES && i >= 0) + { + if (i < (MT_FIRSTFREESLOT+freeslotusage[1][1])) + G_SetGameModified(multiplayer, true); // affecting something earlier than the first freeslot allocated in this .wad? DENIED readthing(f, i); + } else { deh_warning("Thing %d out of range (0 - %d)", i, NUMMOBJTYPES-1); @@ -3485,6 +3503,7 @@ static void DEH_LoadDehackedFile(MYFILE *f, UINT16 wad) /* else if (fastcmp(word, "ANIMTEX")) { readAnimTex(f, i); + // This is not a major mod. }*/ else if (fastcmp(word, "LIGHT")) { @@ -3498,6 +3517,7 @@ static void DEH_LoadDehackedFile(MYFILE *f, UINT16 wad) ignorelines(f); } DEH_WriteUndoline(word, word2, UNDO_HEADER); + // This is not a major mod. #endif } else if (fastcmp(word, "SPRITE")) @@ -3513,6 +3533,7 @@ static void DEH_LoadDehackedFile(MYFILE *f, UINT16 wad) ignorelines(f); } DEH_WriteUndoline(word, word2, UNDO_HEADER); + // This is not a major mod. #endif } else if (fastcmp(word, "LEVEL")) @@ -3525,7 +3546,11 @@ static void DEH_LoadDehackedFile(MYFILE *f, UINT16 wad) i = M_MapNumber(word2[0], word2[1]); if (i > 0 && i <= NUMMAPS) + { + if (mapheaderinfo[i]) + G_SetGameModified(multiplayer, true); // only mark as a major mod if it replaces an already-existing mapheaderinfo readlevelheader(f, i); + } else { deh_warning("Level number %d out of range (1 - %d)", i, NUMMAPS); @@ -3543,13 +3568,18 @@ static void DEH_LoadDehackedFile(MYFILE *f, UINT16 wad) ignorelines(f); } DEH_WriteUndoline(word, word2, UNDO_HEADER); + //G_SetGameModified(multiplayer, true); -- might have to reconsider in a future update } else if (fastcmp(word, "FRAME") || fastcmp(word, "STATE")) { if (i == 0 && word2[0] != '0') // If word2 isn't a number i = get_state(word2); // find a state by name if (i < NUMSTATES && i >= 0) + { + if (i < (S_FIRSTFREESLOT+freeslotusage[0][1])) + G_SetGameModified(multiplayer, true); // affecting something earlier than the first freeslot allocated in this .wad? DENIED readframe(f, i); + } else { deh_warning("Frame %d out of range (0 - %d)", i, NUMSTATES-1); @@ -3578,6 +3608,7 @@ static void DEH_LoadDehackedFile(MYFILE *f, UINT16 wad) } else deh_warning("pointer (Frame %d) : missing ')'", i); + G_SetGameModified(multiplayer, true); }*/ else if (fastcmp(word, "SOUND")) { @@ -3591,6 +3622,7 @@ static void DEH_LoadDehackedFile(MYFILE *f, UINT16 wad) ignorelines(f); } DEH_WriteUndoline(word, word2, UNDO_HEADER); + // This is not a major mod. } /* else if (fastcmp(word, "SPRITE")) { @@ -3611,6 +3643,7 @@ static void DEH_LoadDehackedFile(MYFILE *f, UINT16 wad) } else deh_warning("Sprite %d doesn't exist",i); + // This is not a major mod. }*/ else if (fastcmp(word, "HUDITEM")) { @@ -3624,10 +3657,11 @@ static void DEH_LoadDehackedFile(MYFILE *f, UINT16 wad) ignorelines(f); } DEH_WriteUndoline(word, word2, UNDO_HEADER); + // This is not a major mod. } else if (fastcmp(word, "EMBLEM")) { - if (!gamedataadded) + if (!(refreshdirmenu & REFRESHDIR_GAMEDATA)) { deh_warning("You must define a custom gamedata to use \"%s\"", word); ignorelines(f); @@ -3647,7 +3681,7 @@ static void DEH_LoadDehackedFile(MYFILE *f, UINT16 wad) } else if (fastcmp(word, "EXTRAEMBLEM")) { - if (!gamedataadded) + if (!(refreshdirmenu & REFRESHDIR_GAMEDATA)) { deh_warning("You must define a custom gamedata to use \"%s\"", word); ignorelines(f); @@ -3667,7 +3701,7 @@ static void DEH_LoadDehackedFile(MYFILE *f, UINT16 wad) } else if (fastcmp(word, "UNLOCKABLE")) { - if (!gamedataadded) + if (!(refreshdirmenu & REFRESHDIR_GAMEDATA)) { deh_warning("You must define a custom gamedata to use \"%s\"", word); ignorelines(f); @@ -3683,7 +3717,7 @@ static void DEH_LoadDehackedFile(MYFILE *f, UINT16 wad) } else if (fastcmp(word, "CONDITIONSET")) { - if (!gamedataadded) + if (!(refreshdirmenu & REFRESHDIR_GAMEDATA)) { deh_warning("You must define a custom gamedata to use \"%s\"", word); ignorelines(f); @@ -3718,7 +3752,7 @@ static void DEH_LoadDehackedFile(MYFILE *f, UINT16 wad) { boolean clearall = (fastcmp(word2, "ALL")); - if (!gamedataadded) + if (!(refreshdirmenu & REFRESHDIR_GAMEDATA)) { deh_warning("You must define a custom gamedata to use \"%s\"", word); continue; @@ -3755,8 +3789,8 @@ static void DEH_LoadDehackedFile(MYFILE *f, UINT16 wad) deh_warning("No word in this line: %s", s); } // end while - if (gamedataadded) - G_LoadGameData(); + /*if (gamedataadded) -- REFRESHDIR_GAMEDATA murdered this + G_LoadGameData();*/ dbg_line = -1; if (deh_num_warning) @@ -8299,7 +8333,9 @@ static const char *const KARTSTUFF_LIST[] = { "ITEMBLINK", "ITEMBLINKMODE", - "GETSPARKS" + "GETSPARKS", + "JAWZTARGETDELAY", + "SPECTATEWAIT" }; static const char *const HUDITEMS_LIST[] = { @@ -9356,6 +9392,7 @@ static inline int lib_freeslot(lua_State *L) CONS_Printf("State S_%s allocated.\n",word); FREE_STATES[i] = Z_Malloc(strlen(word)+1, PU_STATIC, NULL); strcpy(FREE_STATES[i],word); + freeslotusage[0][0]++; lua_pushinteger(L, i); r++; break; @@ -9371,6 +9408,7 @@ static inline int lib_freeslot(lua_State *L) CONS_Printf("MobjType MT_%s allocated.\n",word); FREE_MOBJS[i] = Z_Malloc(strlen(word)+1, PU_STATIC, NULL); strcpy(FREE_MOBJS[i],word); + freeslotusage[1][0]++; lua_pushinteger(L, i); r++; break; @@ -9740,6 +9778,9 @@ static inline int lib_getenum(lua_State *L) } else if (fastcmp(word,"modifiedgame")) { lua_pushboolean(L, modifiedgame && !savemoddata); return 1; + } else if (fastcmp(word,"majormods")) { + lua_pushboolean(L, majormods); + return 1; } else if (fastcmp(word,"menuactive")) { lua_pushboolean(L, menuactive); return 1; diff --git a/src/dehacked.h b/src/dehacked.h index 683fe7d94..0d6cc9022 100644 --- a/src/dehacked.h +++ b/src/dehacked.h @@ -37,6 +37,8 @@ void DEH_UnloadDehackedWad(UINT16 wad); void DEH_LoadDehackedLump(lumpnum_t lumpnum); void DEH_LoadDehackedLumpPwad(UINT16 wad, UINT16 lump); +void DEH_UpdateMaxFreeslots(void); + void DEH_Check(void); fixed_t get_number(const char *word); diff --git a/src/doomdef.h b/src/doomdef.h index 70e521b15..ab863c6f6 100644 --- a/src/doomdef.h +++ b/src/doomdef.h @@ -150,9 +150,9 @@ extern FILE *logstream; // we use comprevision and compbranch instead. #else #define VERSION 100 // Game version -#define SUBVERSION 2 // more precise version number -#define VERSIONSTRING "v1.0.2" -#define VERSIONSTRINGW L"v1.0.2" +#define SUBVERSION 3 // more precise version number +#define VERSIONSTRING "v1.0.3" +#define VERSIONSTRINGW L"v1.0.3" // Hey! If you change this, add 1 to the MODVERSION below! // Otherwise we can't force updates! #endif @@ -221,7 +221,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 2 +#define MODVERSION 3 // Filter consvars by version // To version config.cfg, MAJOREXECVERSION is set equal to MODVERSION automatically. diff --git a/src/doomstat.h b/src/doomstat.h index 6d710e28c..9ae2726d7 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -54,6 +54,7 @@ extern boolean gamecomplete; // Set if homebrew PWAD stuff has been added. extern boolean modifiedgame; +extern boolean majormods; extern UINT16 mainwads; extern boolean savemoddata; // This mod saves time/emblem data. extern boolean disableSpeedAdjust; // Don't alter the duration of player states if true @@ -280,6 +281,8 @@ typedef struct #define LF2_NIGHTSATTACK 8 ///< Show this map in NiGHTS mode menu #define LF2_NOVISITNEEDED 16 ///< Available in time attack/nights mode without visiting the level +#define LF2_EXISTSHACK 128 ///< Map lump exists; as noted, a single-bit hack that can be freely movable to other variables without concern. + // Save override #define SAVE_NEVER -1 #define SAVE_DEFAULT 0 diff --git a/src/f_finale.c b/src/f_finale.c index 0fe13a8c9..b863ea74b 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -181,7 +181,7 @@ static void F_SkyScroll(INT32 scrollspeed) { V_DrawFixedPatch(x*FRACUNIT, y*FRACUNIT, FRACUNIT, V_SNAPTOTOP|V_SNAPTOLEFT, pat, NULL); x += SHORT(pat->width); - } + } x = -anim2; y = BASEVIDHEIGHT - SHORT(pat2->height); diff --git a/src/f_wipe.c b/src/f_wipe.c index f7a5992ae..3c8713d18 100644 --- a/src/f_wipe.c +++ b/src/f_wipe.c @@ -26,6 +26,7 @@ #include "console.h" #include "d_main.h" #include "m_misc.h" // movie mode +#include "d_clisrv.h" // So the network state can be updated during the wipe #ifdef HWRENDER #include "hardware/hw_main.h" @@ -96,7 +97,7 @@ static fixed_t paldiv; * \return fademask_t for lump */ static fademask_t *F_GetFadeMask(UINT8 masknum, UINT8 scrnnum) { - static char lumpname[10] = "FADEmmss"; + static char lumpname[9] = "FADEmmss"; static fademask_t fm = {NULL,0,0,0,0,0}; lumpnum_t lumpnum; UINT8 *lump, *mask; @@ -106,7 +107,14 @@ static fademask_t *F_GetFadeMask(UINT8 masknum, UINT8 scrnnum) { if (masknum > 99 || scrnnum > 99) goto freemask; - sprintf(&lumpname[4], "%.2hu%.2hu", (UINT16)masknum, (UINT16)scrnnum); + // SRB2Kart: This suddenly triggers ERRORMODE now + //sprintf(&lumpname[4], "%.2hu%.2hu", (UINT16)masknum, (UINT16)scrnnum); + + lumpname[4] = '0'+(masknum/10); + lumpname[5] = '0'+(masknum%10); + + lumpname[6] = '0'+(scrnnum/10); + lumpname[7] = '0'+(scrnnum%10); lumpnum = W_CheckNumForName(lumpname); if (lumpnum == LUMPERROR) @@ -375,6 +383,8 @@ void F_RunWipe(UINT8 wipetype, boolean drawMenu) if (moviemode) M_SaveFrame(); + + NetKeepAlive(); // Update the network so we don't cause timeouts } WipeInAction = false; #endif diff --git a/src/filesrch.h b/src/filesrch.h index 4186271b0..01a528482 100644 --- a/src/filesrch.h +++ b/src/filesrch.h @@ -88,7 +88,8 @@ typedef enum REFRESHDIR_WARNING = 4, REFRESHDIR_ERROR = 8, REFRESHDIR_NOTLOADED = 16, - REFRESHDIR_MAX = 32 + REFRESHDIR_MAX = 32, + REFRESHDIR_GAMEDATA = 64 } refreshdir_enum; void closefilemenu(boolean validsize); diff --git a/src/g_game.c b/src/g_game.c index ee004b64b..3944c02aa 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -16,6 +16,7 @@ #include "d_main.h" #include "d_player.h" #include "f_finale.h" +#include "filesrch.h" // for refreshdirmenu #include "p_setup.h" #include "p_saveg.h" #include "i_system.h" @@ -86,7 +87,8 @@ INT16 lastmapsaved = 0; // Last map we auto-saved at boolean gamecomplete = false; UINT16 mainwads = 0; -boolean modifiedgame; // Set if homebrew PWAD stuff has been added. +boolean modifiedgame = false; // Set if homebrew PWAD stuff has been added. +boolean majormods = false; // Set if Lua/Gameplay SOC/replacement map has been added. boolean savemoddata = false; UINT8 paused; UINT8 modeattacking = ATTACKING_NONE; @@ -752,16 +754,21 @@ void G_SetNightsRecords(void) }*/ // for consistency among messages: this modifies the game and removes savemoddata. -void G_SetGameModified(boolean silent) +void G_SetGameModified(boolean silent, boolean major) { - if (modifiedgame && !savemoddata) + if ((majormods && modifiedgame) || !mainwads || (refreshdirmenu & REFRESHDIR_GAMEDATA)) // new gamedata amnesty? return; modifiedgame = true; - savemoddata = false; + + if (!major) + return; + + //savemoddata = false; -- there is literally no reason to do this anymore. + majormods = true; if (!silent) - CONS_Alert(CONS_NOTICE, M_GetText("Game must be restarted to record statistics.\n")); + CONS_Alert(CONS_NOTICE, M_GetText("Game must be restarted to play record attack.\n")); // If in record attack recording, cancel it. if (modeattacking) @@ -2155,7 +2162,7 @@ void G_Ticker(boolean run) G_CopyTiccmd(cmd, &netcmds[buf][i], 1); // Use the leveltime sent in the player's ticcmd to determine control lag - cmd->latency = modeattacking ? 0 : min((leveltime & 0xFF) - cmd->latency, MAXPREDICTTICS-1); //@TODO add a cvar to allow setting this max + cmd->latency = modeattacking ? 0 : min(((leveltime & 0xFF) - cmd->latency) & 0xFF, MAXPREDICTTICS-1); //@TODO add a cvar to allow setting this max } } @@ -3942,7 +3949,6 @@ void G_LoadGameData(void) // Saves the main data file, which stores information such as emblems found, etc. void G_SaveGameData(boolean force) { - const boolean wasmodified = modifiedgame; size_t length; INT32 i, j; UINT8 btemp; @@ -3959,9 +3965,7 @@ void G_SaveGameData(boolean force) return; } - if (force) // SRB2Kart: for enabling unlocks online, even if the game is modified - modifiedgame = savemoddata; // L-let's just sort of... hack around the cheat protection, because I'm too worried about just removing it @@; - else if (modifiedgame && !savemoddata) + if (majormods && !force) { free(savebuffer); save_p = savebuffer = NULL; @@ -3974,7 +3978,7 @@ void G_SaveGameData(boolean force) WRITEUINT32(save_p, totalplaytime); WRITEUINT32(save_p, matchesplayed); - btemp = (UINT8)(savemoddata || modifiedgame); + btemp = (UINT8)(savemoddata); // what used to be here was profoundly dunderheaded WRITEUINT8(save_p, btemp); // TODO put another cipher on these things? meh, I don't care... @@ -4060,9 +4064,6 @@ void G_SaveGameData(boolean force) FIL_WriteFile(va(pandf, srb2home, gamedatafilename), savebuffer, length); free(savebuffer); save_p = savebuffer = NULL; - - if (force) // Eeeek, I'm sorry for my sins! - modifiedgame = wasmodified; } #define VERSIONSIZE 16 @@ -5150,22 +5151,20 @@ void G_GhostTicker(void) if (ziptic & EZT_HIT) { // Spawn hit poofs for killing things! UINT16 i, count = READUINT16(g->p), health; - UINT32 type; + //UINT32 type; fixed_t x,y,z; angle_t angle; mobj_t *poof; for (i = 0; i < count; i++) { g->p += 4; // reserved - type = READUINT32(g->p); + g->p += 4; // backwards compat., type used to be here health = READUINT16(g->p); x = READFIXED(g->p); y = READFIXED(g->p); z = READFIXED(g->p); angle = READANGLE(g->p); - if (!(mobjinfo[type].flags & MF_SHOOTABLE) - || !(mobjinfo[type].flags & (MF_ENEMY|MF_MONITOR)) - || health != 0 || i >= 4) // only spawn for the first 4 hits per frame, to prevent ghosts from splode-spamming too bad. + if (health != 0 || i >= 4) // only spawn for the first 4 hits per frame, to prevent ghosts from splode-spamming too bad. continue; poof = P_SpawnMobj(x, y, z, MT_GHOST); poof->angle = angle; @@ -5921,6 +5920,32 @@ void G_DoPlayDemo(char *defdemoname) return; } + // Skin not loaded? + if (!SetPlayerSkin(0, skin)) + { + snprintf(msg, 1024, M_GetText("%s features a character that is not currently loaded.\n"), pdemoname); + CONS_Alert(CONS_ERROR, "%s", msg); + M_StartMessage(msg, NULL, MM_NOTHING); + Z_Free(pdemoname); + Z_Free(demobuffer); + demoplayback = false; + titledemo = false; + return; + } + + // ...*map* not loaded? + if (!gamemap || (gamemap > NUMMAPS) || !mapheaderinfo[gamemap-1] || !(mapheaderinfo[gamemap-1]->menuflags & LF2_EXISTSHACK)) + { + snprintf(msg, 1024, M_GetText("%s features a course that is not currently loaded.\n"), pdemoname); + CONS_Alert(CONS_ERROR, "%s", msg); + M_StartMessage(msg, NULL, MM_NOTHING); + Z_Free(pdemoname); + Z_Free(demobuffer); + demoplayback = false; + titledemo = false; + return; + } + Z_Free(pdemoname); memset(&oldcmd,0,sizeof(oldcmd)); @@ -5952,9 +5977,6 @@ void G_DoPlayDemo(char *defdemoname) P_SetRandSeed(randseed); G_InitNew(false, G_BuildMapName(gamemap), true, true); // Doesn't matter whether you reset or not here, given changes to resetplayer. - // Set skin - SetPlayerSkin(0, skin); - // Set color for (i = 0; i < MAXSKINCOLORS; i++) if (!stricmp(KartColor_Names[i],color)) // SRB2kart @@ -6004,6 +6026,7 @@ void G_AddGhost(char *defdemoname) UINT8 *buffer,*p; mapthing_t *mthing; UINT16 count, ghostversion; + skin_t *ghskin = &skins[0]; name[16] = '\0'; skin[16] = '\0'; @@ -6149,6 +6172,21 @@ void G_AddGhost(char *defdemoname) return; } + for (i = 0; i < numskins; i++) + if (!stricmp(skins[i].name,skin)) + { + ghskin = &skins[i]; + break; + } + + if (i == numskins) + { + CONS_Alert(CONS_NOTICE, M_GetText("Failed to add ghost %s: Invalid character.\n"), pdemoname); + Z_Free(pdemoname); + Z_Free(buffer); + return; + } + gh = Z_Calloc(sizeof(demoghost), PU_LEVEL, NULL); gh->next = ghosts; gh->buffer = buffer; @@ -6194,14 +6232,7 @@ void G_AddGhost(char *defdemoname) gh->oldmo.z = gh->mo->z; // Set skin - gh->mo->skin = &skins[0]; - for (i = 0; i < numskins; i++) - if (!stricmp(skins[i].name,skin)) - { - gh->mo->skin = &skins[i]; - break; - } - gh->oldmo.skin = gh->mo->skin; + gh->mo->skin = gh->oldmo.skin = ghskin; // Set color gh->mo->color = ((skin_t*)gh->mo->skin)->prefcolor; diff --git a/src/g_game.h b/src/g_game.h index 6d11a4a02..fc7a4a4f5 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -226,7 +226,7 @@ boolean G_GetRetryFlag(void); void G_LoadGameData(void); void G_LoadGameSettings(void); -void G_SetGameModified(boolean silent); +void G_SetGameModified(boolean silent, boolean major); void G_SetGamestate(gamestate_t newstate); diff --git a/src/g_input.c b/src/g_input.c index 871c1e604..cab358303 100644 --- a/src/g_input.c +++ b/src/g_input.c @@ -37,7 +37,7 @@ INT32 mlooky; // like mousey but with a custom sensitivity for mlook INT32 mouse2x, mouse2y, mlook2y; // joystick values are repeated -INT32 joyxmove[JOYAXISSET], joyymove[JOYAXISSET], joy2xmove[JOYAXISSET], joy2ymove[JOYAXISSET], +INT32 joyxmove[JOYAXISSET], joyymove[JOYAXISSET], joy2xmove[JOYAXISSET], joy2ymove[JOYAXISSET], joy3xmove[JOYAXISSET], joy3ymove[JOYAXISSET], joy4xmove[JOYAXISSET], joy4ymove[JOYAXISSET]; // current state of the keys: true if pushed @@ -1308,7 +1308,7 @@ void G_Controldefault(UINT8 player) gamecontrol[gc_brake ][1] = KEY_JOY1+1; // B gamecontrol[gc_fire ][1] = KEY_JOY1+4; // LB gamecontrol[gc_drift ][1] = KEY_JOY1+5; // RB - + // Extra controls gamecontrol[gc_pause ][0] = KEY_PAUSE; gamecontrol[gc_console ][0] = KEY_CONSOLE; diff --git a/src/hu_stuff.c b/src/hu_stuff.c index a308dfc2b..3d8f2383b 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -1185,8 +1185,8 @@ boolean HU_Responder(event_t *ev) return true; // Ignore non-keyboard keys, except when the talk key is bound - if (ev->data1 >= KEY_MOUSE1 - && (ev->data1 != gamecontrol[gc_talkkey][0] + if (ev->data1 >= KEY_MOUSE1 + && (ev->data1 != gamecontrol[gc_talkkey][0] && ev->data1 != gamecontrol[gc_talkkey][1])) return false; diff --git a/src/info.c b/src/info.c index f111fa950..3f90f5e48 100644 --- a/src/info.c +++ b/src/info.c @@ -15449,7 +15449,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_ORBINAUT_SHIELDDEAD, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound - 10*FRACUNIT, // speed + 4*FRACUNIT, // speed 16*FRACUNIT, // radius 32*FRACUNIT, // height 0, // display offset @@ -15530,7 +15530,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_JAWZ_DEAD1, // deathstate S_JAWZ_DEAD2, // xdeathstate sfx_None, // deathsound - 10*FRACUNIT, // speed + 4*FRACUNIT, // speed 16*FRACUNIT, // radius 32*FRACUNIT, // height 0, // display offset diff --git a/src/info.h b/src/info.h index 2ebd11fe8..157c72e1b 100644 --- a/src/info.h +++ b/src/info.h @@ -608,7 +608,7 @@ typedef enum sprite // Kart Items SPR_RSHE, // Rocket sneaker SPR_FITM, // Eggman Monitor - SPR_BANA, // Banana Peel + SPR_BANA, // Banana Peel SPR_ORBN, // Orbinaut SPR_JAWZ, // Jawz SPR_SSMN, // SS Mine @@ -3871,7 +3871,7 @@ typedef enum state S_GARU1, S_GARU2, S_GARU3, - S_TGARU0, + S_TGARU0, S_TGARU1, S_TGARU2, S_TGARU3, // Wind attack used by Roaming Shadows on Players. @@ -4612,14 +4612,14 @@ typedef enum mobj_type MT_EGGMANITEM_SHIELD, MT_BANANA, // Banana Stuff - MT_BANANA_SHIELD, + MT_BANANA_SHIELD, MT_ORBINAUT, // Orbinaut stuff MT_ORBINAUT_SHIELD, MT_JAWZ, // Jawz stuff MT_JAWZ_DUD, - MT_JAWZ_SHIELD, + MT_JAWZ_SHIELD, MT_PLAYERRETICULE, // Jawz reticule diff --git a/src/k_kart.c b/src/k_kart.c index 1167b22a6..ac077164b 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -500,9 +500,9 @@ static INT32 K_KartItemOddsRace[NUMKARTRESULTS][10] = /*Sneaker*/ {20, 0, 0, 4, 6, 6, 0, 0, 0, 0 }, // Sneaker /*Rocket Sneaker*/ { 0, 0, 0, 0, 0, 1, 3, 5, 3, 0 }, // Rocket Sneaker /*Invincibility*/ { 0, 0, 0, 0, 0, 1, 4, 6,14, 0 }, // Invincibility - /*Banana*/ { 0, 9, 4, 2, 1, 0, 0, 0, 0, 0 }, // Banana - /*Eggman Monitor*/ { 0, 4, 3, 2, 0, 0, 0, 0, 0, 0 }, // Eggman Monitor - /*Orbinaut*/ { 0, 6, 5, 3, 2, 0, 0, 0, 0, 0 }, // Orbinaut + /*Banana*/ { 0,10, 4, 2, 1, 0, 0, 0, 0, 0 }, // Banana + /*Eggman Monitor*/ { 0, 3, 2, 1, 0, 0, 0, 0, 0, 0 }, // Eggman Monitor + /*Orbinaut*/ { 0, 8, 6, 4, 2, 0, 0, 0, 0, 0 }, // Orbinaut /*Jawz*/ { 0, 0, 3, 2, 1, 1, 0, 0, 0, 0 }, // Jawz /*Mine*/ { 0, 0, 2, 2, 1, 0, 0, 0, 0, 0 }, // Mine /*Ballhog*/ { 0, 0, 0, 2, 1, 0, 0, 0, 0, 0 }, // Ballhog @@ -617,6 +617,35 @@ static INT32 K_KartGetItemOdds(UINT8 pos, SINT8 item, fixed_t mashed) UINT8 pingame = 0, pexiting = 0, pinvin = 0; SINT8 first = -1, second = -1; INT32 secondist = 0; + boolean itemenabled[NUMKARTRESULTS-1] = { + cv_sneaker.value, + cv_rocketsneaker.value, + cv_invincibility.value, + cv_banana.value, + cv_eggmanmonitor.value, + cv_orbinaut.value, + cv_jawz.value, + cv_mine.value, + cv_ballhog.value, + cv_selfpropelledbomb.value, + cv_grow.value, + cv_shrink.value, + cv_thundershield.value, + cv_hyudoro.value, + cv_pogospring.value, + cv_kitchensink.value, + cv_triplesneaker.value, + cv_triplebanana.value, + cv_decabanana.value, + cv_tripleorbinaut.value, + cv_quadorbinaut.value, + cv_dualjawz.value + }; + + I_Assert(item > KITEM_NONE); // too many off by one scenarioes. + + if (!itemenabled[item-1] && !modeattacking) + return 0; if (G_BattleGametype()) newodds = K_KartItemOddsBattle[item-1][pos]; @@ -627,21 +656,24 @@ static INT32 K_KartGetItemOdds(UINT8 pos, SINT8 item, fixed_t mashed) { if (!playeringame[i] || players[i].spectator) continue; - - pingame++; + if (!G_BattleGametype() || players[i].kartstuff[k_bumper]) + pingame++; if (players[i].exiting) pexiting++; if (players[i].mo) { - if (players[i].kartstuff[k_position] == 1 && first == -1) - first = i; - if (players[i].kartstuff[k_position] == 2 && second == -1) - second = i; if (players[i].kartstuff[k_itemtype] == KITEM_INVINCIBILITY || players[i].kartstuff[k_itemtype] == KITEM_GROW || players[i].kartstuff[k_invincibilitytimer] || players[i].kartstuff[k_growshrinktimer] > 0) pinvin++; + if (!G_BattleGametype()) + { + if (players[i].kartstuff[k_position] == 1 && first == -1) + first = i; + if (players[i].kartstuff[k_position] == 2 && second == -1) + second = i; + } } } @@ -651,120 +683,61 @@ static INT32 K_KartGetItemOdds(UINT8 pos, SINT8 item, fixed_t mashed) players[first].mo->y - players[second].mo->y), players[first].mo->z - players[second].mo->z) / mapobjectscale; if (franticitems) - secondist = (15*secondist/14); - if (pingame < 8 && !G_BattleGametype()) - secondist = ((28+(8-pingame))*secondist/28); + secondist = (15 * secondist) / 14; + secondist = ((28 + (8-pingame)) * secondist) / 28; } // POWERITEMODDS handles all of the "frantic item" related functionality, for all of our powerful items. // First, it multiplies it by 2 if franticitems is true; easy-peasy. // Next, it multiplies it again if it's in SPB mode and 2nd needs to apply pressure to 1st. - // Then, it multiplies it further if there's less than 8 players in game. - // This is done to make low player count races more fair & interesting. (1v1s are basically the same as franticitems false in a normal race) + // Then, it multiplies it further if there's less than 5 players in game. + // This is done to make low player count races more fair & interesting. (2P normal would be about halfway between 8P normal and 8P frantic) // Lastly, it *divides* it by your mashed value, which was determined in K_KartItemRoulette, to punish those who are impatient. - // The last two are very fractional and complicated, very sorry! #define POWERITEMODDS(odds) \ if (franticitems) \ - odds *= 2; \ - if (pingame < 8 && !G_BattleGametype()) \ - odds = FixedMul(odds*FRACUNIT, FRACUNIT+min((8-pingame)*(FRACUNIT/25), FRACUNIT))/FRACUNIT; \ + odds <<= 1; \ + odds = FixedMul(odds<> FRACBITS; \ if (mashed > 0) \ - odds = FixedDiv(odds*FRACUNIT, mashed+FRACUNIT)/FRACUNIT \ + odds = FixedDiv(odds<> FRACBITS \ switch (item) { - case KITEM_SNEAKER: - if ((!cv_sneaker.value) && (!modeattacking)) newodds = 0; - break; - case KITEM_ROCKETSNEAKER: - POWERITEMODDS(newodds); - if (!cv_rocketsneaker.value) newodds = 0; - break; case KITEM_INVINCIBILITY: - POWERITEMODDS(newodds); - if ((!cv_invincibility.value) || (pinvin >= 2)) newodds = 0; - break; - case KITEM_BANANA: - if (!cv_banana.value) newodds = 0; - break; - case KITEM_EGGMAN: - if (!cv_eggmanmonitor.value) newodds = 0; - break; - case KITEM_ORBINAUT: - if (!cv_orbinaut.value) newodds = 0; - break; + case KITEM_GROW: + if (pinvin >= max(1, (pingame+2) / 4)) + newodds = 0; + else + /* FALLTHRU */ + case KITEM_ROCKETSNEAKER: case KITEM_JAWZ: - POWERITEMODDS(newodds); - if (!cv_jawz.value) newodds = 0; - break; case KITEM_MINE: - POWERITEMODDS(newodds); - if (!cv_mine.value) newodds = 0; - break; case KITEM_BALLHOG: + case KITEM_THUNDERSHIELD: + case KRITEM_TRIPLESNEAKER: + case KRITEM_TRIPLEBANANA: + case KRITEM_TENFOLDBANANA: + case KRITEM_TRIPLEORBINAUT: + case KRITEM_QUADORBINAUT: + case KRITEM_DUALJAWZ: POWERITEMODDS(newodds); - if (!cv_ballhog.value) newodds = 0; break; case KITEM_SPB: //POWERITEMODDS(newodds); - if (((!cv_selfpropelledbomb.value) - || (indirectitemcooldown > 0) - || (pexiting > 0) - || (secondist/distvar < 3)) + if (((indirectitemcooldown > 0) || (pexiting > 0) || (secondist/distvar < 3)) && (pos != 9)) // Force SPB newodds = 0; - newodds *= min((secondist/distvar)-4, 3); - break; - case KITEM_GROW: - POWERITEMODDS(newodds); - if ((!cv_grow.value) || (pinvin >= 2)) newodds = 0; + else + newodds *= min((secondist/distvar)-4, 3); break; case KITEM_SHRINK: POWERITEMODDS(newodds); - if ((!cv_shrink.value) - || (indirectitemcooldown > 0) - || (pingame-1 <= pexiting)) newodds = 0; - break; - case KITEM_THUNDERSHIELD: - POWERITEMODDS(newodds); - if (!cv_thundershield.value) newodds = 0; - break; - case KITEM_HYUDORO: - if (!cv_hyudoro.value) newodds = 0; - break; - case KITEM_POGOSPRING: - if (!cv_pogospring.value) newodds = 0; - break; - case KITEM_KITCHENSINK: - newodds = 0; // Not obtained via normal means. - break; - case KRITEM_TRIPLESNEAKER: - POWERITEMODDS(newodds); - if (!cv_triplesneaker.value) newodds = 0; - break; - case KRITEM_TRIPLEBANANA: - POWERITEMODDS(newodds); - if (!cv_triplebanana.value) newodds = 0; - break; - case KRITEM_TENFOLDBANANA: - POWERITEMODDS(newodds); - if (!cv_decabanana.value) newodds = 0; - break; - case KRITEM_TRIPLEORBINAUT: - POWERITEMODDS(newodds); - if (!cv_tripleorbinaut.value) newodds = 0; - break; - case KRITEM_QUADORBINAUT: - POWERITEMODDS(newodds); - if (!cv_quadorbinaut.value) newodds = 0; - break; - case KRITEM_DUALJAWZ: - POWERITEMODDS(newodds); - if (!cv_dualjawz.value) newodds = 0; + if ((indirectitemcooldown > 0) || (pingame-1 <= pexiting)) + newodds = 0; break; default: break; } + #undef POWERITEMODDS return newodds; @@ -792,7 +765,7 @@ static INT32 K_FindUseodds(player_t *player, fixed_t mashed, INT32 pingame, INT3 break; } - for (j = 0; j < NUMKARTRESULTS; j++) + for (j = 1; j < NUMKARTRESULTS; j++) { if (K_KartGetItemOdds(i, j, mashed) > 0) { @@ -852,11 +825,12 @@ static INT32 K_FindUseodds(player_t *player, fixed_t mashed, INT32 pingame, INT3 if (oddsvalid[8]) SETUPDISTTABLE(8,1); if (franticitems) // Frantic items make the distances between everyone artifically higher, for crazier items - pdis = (15*pdis)/14; + pdis = (15 * pdis) / 14; + if (spbrush) // SPB Rush Mode: It's 2nd place's job to catch-up items and make 1st place's job hell - pdis = (3*pdis)/2; - if (pingame < 8) - pdis = ((28+(8-pingame))*pdis)/28; + pdis = (3 * pdis) / 2; + + pdis = ((28 + (8-pingame)) * pdis) / 28; if (pingame == 1 && oddsvalid[0]) // Record Attack, or just alone useodds = 0; @@ -1083,7 +1057,7 @@ void K_KartBouncing(mobj_t *mobj1, mobj_t *mobj2, boolean bounce, boolean solid) mobj_t *fx; fixed_t momdifx, momdify; fixed_t distx, disty; - fixed_t dot, p; + fixed_t dot, force; fixed_t mass1, mass2; if (!mobj1 || !mobj2) @@ -1098,6 +1072,26 @@ void K_KartBouncing(mobj_t *mobj1, mobj_t *mobj2, boolean bounce, boolean solid) || (mobj2->player && mobj2->player->kartstuff[k_respawn])) return; + { // Don't bump if you're flashing + INT32 flash; + + flash = K_GetKartFlashing(mobj1->player); + if (mobj1->player && mobj1->player->powers[pw_flashing] > 0 && mobj1->player->powers[pw_flashing] < flash) + { + if (mobj1->player->powers[pw_flashing] < flash-1) + mobj1->player->powers[pw_flashing]++; + return; + } + + flash = K_GetKartFlashing(mobj2->player); + if (mobj2->player && mobj2->player->powers[pw_flashing] > 0 && mobj2->player->powers[pw_flashing] < flash) + { + if (mobj2->player->powers[pw_flashing] < flash-1) + mobj2->player->powers[pw_flashing]++; + return; + } + } + // Don't bump if you've recently bumped if (mobj1->player && mobj1->player->kartstuff[k_justbumped]) { @@ -1121,6 +1115,30 @@ void K_KartBouncing(mobj_t *mobj1, mobj_t *mobj2, boolean bounce, boolean solid) momdifx = mobj1->momx - mobj2->momx; momdify = mobj1->momy - mobj2->momy; + // Adds the OTHER player's momentum times a bunch, for the best chance of getting the correct direction + distx = (mobj1->x + mobj2->momx*3) - (mobj2->x + mobj1->momx*3); + disty = (mobj1->y + mobj2->momy*3) - (mobj2->y + mobj1->momy*3); + + if (distx == 0 && disty == 0) + // if there's no distance between the 2, they're directly on top of each other, don't run this + return; + + { // Normalize distance to the sum of the two objects' radii, since in a perfect world that would be the distance at the point of collision... + fixed_t dist = P_AproxDistance(distx, disty) ?: 1; + fixed_t nx = FixedDiv(distx, dist); + fixed_t ny = FixedDiv(disty, dist); + + distx = FixedMul(mobj1->radius+mobj2->radius, nx); + disty = FixedMul(mobj1->radius+mobj2->radius, ny); + + if (momdifx == 0 && momdify == 0) + { + // If there's no momentum difference, they're moving at exactly the same rate. Pretend they moved into each other. + momdifx = -nx; + momdify = -ny; + } + } + // if the speed difference is less than this let's assume they're going proportionately faster from each other if (P_AproxDistance(momdifx, momdify) < (25*mapobjectscale)) { @@ -1131,34 +1149,6 @@ void K_KartBouncing(mobj_t *mobj1, mobj_t *mobj2, boolean bounce, boolean solid) momdify = FixedMul((25*mapobjectscale), normalisedy); } - // Adds the OTHER player's momentum, so that it reduces the chance of you being "inside" the other object - distx = (mobj1->x + mobj2->momx) - (mobj2->x + mobj1->momx); - disty = (mobj1->y + mobj2->momy) - (mobj2->y + mobj1->momy); - - { // Don't allow dist to get WAY too low, that it pushes you stupidly huge amounts, or backwards... - fixed_t dist = P_AproxDistance(distx, disty); - fixed_t nx = FixedDiv(distx, dist); - fixed_t ny = FixedDiv(disty, dist); - - if (P_AproxDistance(distx, disty) < (3*mobj1->radius)/4) - { - distx = FixedMul((3*mobj1->radius)/4, nx); - disty = FixedMul((3*mobj1->radius)/4, ny); - } - - if (P_AproxDistance(distx, disty) < (3*mobj2->radius)/4) - { - distx = FixedMul((3*mobj2->radius)/4, nx); - disty = FixedMul((3*mobj2->radius)/4, ny); - } - } - - if (distx == 0 && disty == 0) - { - // if there's no distance between the 2, they're directly on top of each other, don't run this - return; - } - dot = FixedMul(momdifx, distx) + FixedMul(momdify, disty); if (dot >= 0) @@ -1167,7 +1157,7 @@ void K_KartBouncing(mobj_t *mobj1, mobj_t *mobj2, boolean bounce, boolean solid) return; } - p = FixedDiv(dot, FixedMul(distx, distx)+FixedMul(disty, disty)); + force = FixedDiv(dot, FixedMul(distx, distx)+FixedMul(disty, disty)); if (bounce == true && mass2 > 0) // Perform a Goomba Bounce. mobj1->momz = -mobj1->momz; @@ -1182,14 +1172,14 @@ void K_KartBouncing(mobj_t *mobj1, mobj_t *mobj2, boolean bounce, boolean solid) if (mass2 > 0) { - mobj1->momx = mobj1->momx - FixedMul(FixedMul(FixedDiv(2*mass2, mass1 + mass2), p), distx); - mobj1->momy = mobj1->momy - FixedMul(FixedMul(FixedDiv(2*mass2, mass1 + mass2), p), disty); + mobj1->momx = mobj1->momx - FixedMul(FixedMul(FixedDiv(2*mass2, mass1 + mass2), force), distx); + mobj1->momy = mobj1->momy - FixedMul(FixedMul(FixedDiv(2*mass2, mass1 + mass2), force), disty); } if (mass1 > 0 && solid == false) { - mobj2->momx = mobj2->momx - FixedMul(FixedMul(FixedDiv(2*mass1, mass1 + mass2), p), -distx); - mobj2->momy = mobj2->momy - FixedMul(FixedMul(FixedDiv(2*mass1, mass1 + mass2), p), -disty); + mobj2->momx = mobj2->momx - FixedMul(FixedMul(FixedDiv(2*mass1, mass1 + mass2), force), -distx); + mobj2->momy = mobj2->momy - FixedMul(FixedMul(FixedDiv(2*mass1, mass1 + mass2), force), -disty); } // Do the bump fx when we've CONFIRMED we can bump. @@ -1212,8 +1202,8 @@ void K_KartBouncing(mobj_t *mobj1, mobj_t *mobj2, boolean bounce, boolean solid) mobj1->player->kartstuff[k_justbumped] = bumptime; if (mobj1->player->kartstuff[k_spinouttimer]) { - mobj1->player->kartstuff[k_wipeoutslow] += wipeoutslowtime+1; - mobj1->player->kartstuff[k_spinouttimer] += wipeoutslowtime+1; + mobj1->player->kartstuff[k_wipeoutslow] = wipeoutslowtime+1; + mobj1->player->kartstuff[k_spinouttimer] = max(wipeoutslowtime+1, mobj1->player->kartstuff[k_spinouttimer]); } } @@ -1224,8 +1214,8 @@ void K_KartBouncing(mobj_t *mobj1, mobj_t *mobj2, boolean bounce, boolean solid) mobj2->player->kartstuff[k_justbumped] = bumptime; if (mobj2->player->kartstuff[k_spinouttimer]) { - mobj2->player->kartstuff[k_wipeoutslow] += wipeoutslowtime+1; - mobj2->player->kartstuff[k_spinouttimer] += wipeoutslowtime+1; + mobj2->player->kartstuff[k_wipeoutslow] = wipeoutslowtime+1; + mobj2->player->kartstuff[k_spinouttimer] = max(wipeoutslowtime+1, mobj2->player->kartstuff[k_spinouttimer]); } } } @@ -1249,9 +1239,8 @@ static UINT8 K_CheckOffroadCollide(mobj_t *mo, sector_t *sec) for (i = 2; i < 5; i++) { if ((sec2 && GETSECSPECIAL(sec2->special, 1) == i) - || (P_IsObjectOnRealGround(mo, sec) - && GETSECSPECIAL(sec->special, 1) == i)) - return i; + || (P_IsObjectOnRealGround(mo, sec) && GETSECSPECIAL(sec->special, 1) == i)) + return i-1; } return 0; @@ -1265,33 +1254,20 @@ static UINT8 K_CheckOffroadCollide(mobj_t *mo, sector_t *sec) */ static void K_UpdateOffroad(player_t *player) { - fixed_t kartweight = player->kartweight; fixed_t offroad; sector_t *nextsector = R_PointInSubsector( player->mo->x + player->mo->momx*2, player->mo->y + player->mo->momy*2)->sector; + UINT8 offroadstrength = K_CheckOffroadCollide(player->mo, nextsector); - fixed_t offroadstrength = 0; - - if (K_CheckOffroadCollide(player->mo, nextsector) == 2) // Weak Offroad - offroadstrength = 1; - else if (K_CheckOffroadCollide(player->mo, nextsector) == 3) // Mid Offroad - offroadstrength = 2; - else if (K_CheckOffroadCollide(player->mo, nextsector) == 4) // Strong Offroad - offroadstrength = 3; - - // If you are offroad, a timer starts. Depending on your weight value, the timer increments differently. - //if ((nextsector->special & 256) && nextsector->special != 768 - // && nextsector->special != 1024 && nextsector->special != 4864) + // If you are in offroad, a timer starts. if (offroadstrength) { if (K_CheckOffroadCollide(player->mo, player->mo->subsector->sector) && player->kartstuff[k_offroad] == 0) - player->kartstuff[k_offroad] = 16; + player->kartstuff[k_offroad] = (TICRATE/2); if (player->kartstuff[k_offroad] > 0) { - // 1872 is the magic number - 35 frames adds up to approximately 65536. 1872/4 = 468/3 = 156 - // A higher kart weight means you can stay offroad for longer without losing speed - offroad = (1872 + 5*156 - kartweight*156)*offroadstrength; + offroad = (offroadstrength << FRACBITS) / (TICRATE/2); //if (player->kartstuff[k_growshrinktimer] > 1) // grow slows down half as fast // offroad /= 2; @@ -1299,8 +1275,8 @@ static void K_UpdateOffroad(player_t *player) player->kartstuff[k_offroad] += offroad; } - if (player->kartstuff[k_offroad] > FRACUNIT*offroadstrength) - player->kartstuff[k_offroad] = FRACUNIT*offroadstrength; + if (player->kartstuff[k_offroad] > (offroadstrength << FRACBITS)) + player->kartstuff[k_offroad] = (offroadstrength << FRACBITS); } else player->kartstuff[k_offroad] = 0; @@ -1650,10 +1626,8 @@ static void K_GetKartBoostPower(player_t *player) && player->kartstuff[k_offroad] >= 0) boostpower = FixedDiv(boostpower, player->kartstuff[k_offroad] + FRACUNIT); - if (player->kartstuff[k_itemtype] == KITEM_KITCHENSINK) - boostpower = max((TICRATE/2), (5*TICRATE)-(player->kartstuff[k_bananadrag]/2))*boostpower/(5*TICRATE); - else if (player->kartstuff[k_bananadrag] > TICRATE) - boostpower = 4*boostpower/5; + if (player->kartstuff[k_bananadrag] > TICRATE) + boostpower = (4*boostpower)/5; // Banana drag/offroad dust if (boostpower < FRACUNIT @@ -1772,11 +1746,17 @@ fixed_t K_GetKartAccel(player_t *player) UINT16 K_GetKartFlashing(player_t *player) { - UINT16 tics = flashingtics; - if (G_BattleGametype()) - tics *= 2; - tics += (flashingtics/8) * (player->kartspeed); - return tics; + UINT16 tics = flashingtics; + + if (!player) + return tics; + + if (G_BattleGametype()) + tics *= 2; + + tics += (flashingtics/8) * (player->kartspeed); + + return tics; } fixed_t K_3dKartMovement(player_t *player, boolean onground, fixed_t forwardmove) @@ -1911,8 +1891,10 @@ void K_SpinPlayer(player_t *player, mobj_t *source, INT32 type, mobj_t *inflicto } } +#ifdef HAVE_BLUA if (LUAh_PlayerSpin(player, inflictor, source)) // Let Lua do its thing or overwrite if it wants to. Make sure to let any possible instashield happen because we didn't get "damaged" in this case. return; +#endif if (source && source != player->mo && source->player) K_PlayHitEmSound(source); @@ -1993,12 +1975,16 @@ void K_SpinPlayer(player_t *player, mobj_t *source, INT32 type, mobj_t *inflicto static void K_RemoveGrowShrink(player_t *player) { player->kartstuff[k_growshrinktimer] = 0; - if (player->kartstuff[k_invincibilitytimer] == 0) - player->mo->color = player->skincolor; - player->mo->scalespeed = mapobjectscale/TICRATE; - player->mo->destscale = mapobjectscale; - if (cv_kartdebugshrink.value && !modeattacking && !player->bot) - player->mo->destscale = (6*player->mo->destscale)/8; + + if (player->mo && !P_MobjWasRemoved(player->mo)) + { + if (player->kartstuff[k_invincibilitytimer] == 0) + player->mo->color = player->skincolor; + player->mo->scalespeed = mapobjectscale/TICRATE; + player->mo->destscale = mapobjectscale; + if (cv_kartdebugshrink.value && !modeattacking && !player->bot) + player->mo->destscale = (6*player->mo->destscale)/8; + } P_RestoreMusic(player); } @@ -2042,8 +2028,10 @@ void K_SquishPlayer(player_t *player, mobj_t *source, mobj_t *inflictor) } } +#ifdef HAVE_BLUA if (LUAh_PlayerSquish(player, inflictor, source)) // Let Lua do its thing or overwrite if it wants to. Make sure to let any possible instashield happen because we didn't get "damaged" in this case. return; +#endif player->kartstuff[k_sneakertimer] = 0; player->kartstuff[k_driftboost] = 0; @@ -2156,8 +2144,10 @@ void K_ExplodePlayer(player_t *player, mobj_t *source, mobj_t *inflictor) // A b } } +#ifdef HAVE_BLUA if (LUAh_PlayerExplode(player, inflictor, source)) // Same thing. Also make sure to let Instashield happen blah blah return; +#endif if (source && source != player->mo && source->player) K_PlayHitEmSound(source); @@ -2535,7 +2525,17 @@ static mobj_t *K_SpawnKartMissile(mobj_t *source, mobjtype_t type, angle_t an, I break; case MT_JAWZ: if (source && source->player) + { + INT32 lasttarg = source->player->kartstuff[k_lastjawztarget]; th->cvmem = source->player->skincolor; + if ((lasttarg >= 0 && lasttarg < MAXPLAYERS) + && playeringame[lasttarg] + && !players[lasttarg].spectator + && players[lasttarg].mo) + { + P_SetTarget(&th->tracer, players[lasttarg].mo); + } + } else th->cvmem = SKINCOLOR_KETCHUP; /* FALLTHRU */ @@ -3037,7 +3037,7 @@ static mobj_t *K_ThrowKartItem(player_t *player, boolean missile, mobjtype_t map newz = player->mo->z; } - mo = P_SpawnMobj(newx, newy, newz, mapthing); + mo = P_SpawnMobj(newx, newy, newz, mapthing); // this will never return null because collision isn't processed here if (P_MobjFlip(player->mo) < 0) mo->z = player->mo->z + player->mo->height - mo->height; @@ -3049,7 +3049,9 @@ static mobj_t *K_ThrowKartItem(player_t *player, boolean missile, mobjtype_t map { // floorz and ceilingz aren't properly set to account for FOFs and Polyobjects on spawn // This should set it for FOFs - P_TeleportMove(mo, mo->x, mo->y, mo->z); + P_TeleportMove(mo, mo->x, mo->y, mo->z); // however, THIS can fuck up your day. just absolutely ruin you. + if (P_MobjWasRemoved(mo)) + return NULL; if (P_MobjFlip(mo) > 0) { @@ -3067,11 +3069,8 @@ static mobj_t *K_ThrowKartItem(player_t *player, boolean missile, mobjtype_t map } } - if (mo) - { - if (player->mo->eflags & MFE_VERTICALFLIP) - mo->eflags |= MFE_VERTICALFLIP; - } + if (player->mo->eflags & MFE_VERTICALFLIP) + mo->eflags |= MFE_VERTICALFLIP; } } @@ -3266,6 +3265,7 @@ void K_DoSneaker(player_t *player, INT32 type) { player->pflags |= PF_ATTACKDOWN; K_PlayBoostTaunt(player->mo); + player->powers[pw_flashing] = 0; // Stop flashing after boosting } } @@ -3291,11 +3291,15 @@ static void K_DoShrink(player_t *user) { // Start shrinking! K_DropItems(&players[i]); - players[i].mo->scalespeed = mapobjectscale/TICRATE; - players[i].mo->destscale = (6*mapobjectscale)/8; - if (cv_kartdebugshrink.value && !modeattacking && !players[i].bot) - players[i].mo->destscale = (6*players[i].mo->destscale)/8; - players[i].kartstuff[k_growshrinktimer] = -(200+(40*(MAXPLAYERS-players[i].kartstuff[k_position]))); + + if (!P_MobjWasRemoved(players[i].mo)) + { + players[i].mo->scalespeed = mapobjectscale/TICRATE; + players[i].mo->destscale = (6*mapobjectscale)/8; + if (cv_kartdebugshrink.value && !modeattacking && !players[i].bot) + players[i].mo->destscale = (6*players[i].mo->destscale)/8; + players[i].kartstuff[k_growshrinktimer] = -(200+(40*(MAXPLAYERS-players[i].kartstuff[k_position]))); + } } // Grow should get taken away. @@ -3420,7 +3424,7 @@ void K_DropHnextList(player_t *player) mobjtype_t type; boolean orbit, ponground, dropall = true; - if (!work) + if (!work || P_MobjWasRemoved(work)) return; flip = P_MobjFlip(player->mo); @@ -3557,7 +3561,7 @@ void K_DropItems(player_t *player) K_DropHnextList(player); - if (player->mo && player->kartstuff[k_itemamount]) + if (player->mo && !P_MobjWasRemoved(player->mo) && player->kartstuff[k_itemamount]) { mobj_t *drop = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z + player->mo->height/2, MT_FLOATINGITEM); P_SetScale(drop, drop->scale>>4); @@ -3659,6 +3663,7 @@ static void K_MoveHeldObjects(player_t *player) case MT_JAWZ_SHIELD: { mobj_t *cur = player->mo->hnext; + fixed_t speed = ((8 - min(4, player->kartstuff[k_itemamount])) * cur->info->speed) / 7; player->kartstuff[k_bananadrag] = 0; // Just to make sure @@ -3676,10 +3681,10 @@ static void K_MoveHeldObjects(player_t *player) cur->color = player->skincolor; cur->angle -= ANGLE_90; - cur->angle += FixedAngle(cur->info->speed); + cur->angle += FixedAngle(speed); if (cur->extravalue1 < radius) - cur->extravalue1 += FixedMul(P_AproxDistance(cur->extravalue1, radius), FRACUNIT/12); + cur->extravalue1 += P_AproxDistance(cur->extravalue1, radius) / 12; if (cur->extravalue1 > radius) cur->extravalue1 = radius; @@ -3939,13 +3944,14 @@ player_t *K_FindJawzTarget(mobj_t *actor, player_t *source) if (thisang > ANGLE_180) thisang = InvAngle(thisang); - if (thisang > ANGLE_45) // Don't go for people who are behind you - continue; - // Jawz only go after the person directly ahead of you in race... sort of literally now! if (G_RaceGametype()) { - if (player->kartstuff[k_position] >= source->kartstuff[k_position]) // Don't pay attention to people behind you + // Don't go for people who are behind you + if (thisang > ANGLE_67h) + continue; + // Don't pay attention to people who aren't above your position + if (player->kartstuff[k_position] >= source->kartstuff[k_position]) continue; if ((best == -1) || (player->kartstuff[k_position] > best)) { @@ -3958,6 +3964,11 @@ player_t *K_FindJawzTarget(mobj_t *actor, player_t *source) fixed_t thisdist; fixed_t thisavg; + // Don't go for people who are behind you + if (thisang > ANGLE_45) + continue; + + // Don't pay attention to dead players if (player->kartstuff[k_bumper] <= 0) continue; @@ -4471,12 +4482,22 @@ void K_KartPlayerAfterThink(player_t *player) // Jawz reticule (seeking) if (player->kartstuff[k_itemtype] == KITEM_JAWZ && player->kartstuff[k_itemheld]) { - player_t *targ = K_FindJawzTarget(player->mo, player); + INT32 lasttarg = player->kartstuff[k_lastjawztarget]; + player_t *targ; mobj_t *ret; - if (!targ) + if (player->kartstuff[k_jawztargetdelay] && playeringame[lasttarg] && !players[lasttarg].spectator) + { + targ = &players[lasttarg]; + player->kartstuff[k_jawztargetdelay]--; + } + else + targ = K_FindJawzTarget(player->mo, player); + + if (!targ || !targ->mo || P_MobjWasRemoved(targ->mo)) { player->kartstuff[k_lastjawztarget] = -1; + player->kartstuff[k_jawztargetdelay] = 0; return; } @@ -4486,7 +4507,7 @@ void K_KartPlayerAfterThink(player_t *player) ret->tics = 1; ret->color = player->skincolor; - if (targ-players != player->kartstuff[k_lastjawztarget]) + if (targ-players != lasttarg) { if (P_IsLocalPlayer(player) || P_IsLocalPlayer(targ)) S_StartSound(NULL, sfx_s3k89); @@ -4494,11 +4515,13 @@ void K_KartPlayerAfterThink(player_t *player) S_StartSound(targ->mo, sfx_s3k89); player->kartstuff[k_lastjawztarget] = targ-players; + player->kartstuff[k_jawztargetdelay] = 5; } } else { player->kartstuff[k_lastjawztarget] = -1; + player->kartstuff[k_jawztargetdelay] = 0; } } @@ -4671,8 +4694,6 @@ static void K_KartDrift(player_t *player, boolean onground) player->kartstuff[k_driftend] = 0; } - - // Incease/decrease the drift value to continue drifting in that direction if (player->kartstuff[k_spinouttimer] == 0 && player->kartstuff[k_jmp] == 1 && onground && player->kartstuff[k_drift] != 0) { @@ -4702,7 +4723,7 @@ static void K_KartDrift(player_t *player, boolean onground) } // Disable drift-sparks until you're going fast enough - if (player->kartstuff[k_getsparks] == 0) + if (player->kartstuff[k_getsparks] == 0 || (player->kartstuff[k_offroad] && !player->kartstuff[k_invincibilitytimer] && !player->kartstuff[k_hyudorotimer] && !player->kartstuff[k_sneakertimer])) driftadditive = 0; if (player->speed > minspeed*2) player->kartstuff[k_getsparks] = 1; @@ -5146,7 +5167,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground) for (moloop = 0; moloop < player->kartstuff[k_itemamount]; moloop++) { - newangle = FixedAngle(((360/player->kartstuff[k_itemamount])*moloop)*FRACUNIT) + ANGLE_90; + newangle = (player->mo->angle + ANGLE_157h) + FixedAngle(((360 / player->kartstuff[k_itemamount]) * moloop) << FRACBITS) + ANGLE_90; mo = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_ORBINAUT_SHIELD); if (!mo) { @@ -5187,7 +5208,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground) for (moloop = 0; moloop < player->kartstuff[k_itemamount]; moloop++) { - newangle = FixedAngle(((360/player->kartstuff[k_itemamount])*moloop)*FRACUNIT) + ANGLE_90; + newangle = (player->mo->angle + ANGLE_157h) + FixedAngle(((360 / player->kartstuff[k_itemamount]) * moloop) << FRACBITS) + ANGLE_90; mo = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_JAWZ_SHIELD); if (!mo) { @@ -5430,35 +5451,46 @@ void K_MoveKartPlayer(player_t *player, boolean onground) } } - // Friction - if (player->speed > 0 && cmd->forwardmove == 0 && player->mo->friction == 59392) - player->mo->friction += 4608; - if (player->speed > 0 && cmd->forwardmove < 0 && player->mo->friction == 59392) - player->mo->friction += 1608; - if (G_BattleGametype() && player->kartstuff[k_bumper] <= 0) + if (onground) { - player->mo->friction += 1228; + // Friction + if (!player->kartstuff[k_offroad]) + { + if (player->speed > 0 && cmd->forwardmove == 0 && player->mo->friction == 59392) + player->mo->friction += 4608; + if (player->speed > 0 && cmd->forwardmove < 0 && player->mo->friction == 59392) + player->mo->friction += 1608; + } - if (player->mo->friction > FRACUNIT) - player->mo->friction = FRACUNIT; - if (player->mo->friction < 0) - player->mo->friction = 0; + // Karma ice physics + if (G_BattleGametype() && player->kartstuff[k_bumper] <= 0) + { + player->mo->friction += 1228; - player->mo->movefactor = FixedDiv(ORIG_FRICTION, player->mo->friction); + if (player->mo->friction > FRACUNIT) + player->mo->friction = FRACUNIT; + if (player->mo->friction < 0) + player->mo->friction = 0; - if (player->mo->movefactor < FRACUNIT) - player->mo->movefactor = 19*player->mo->movefactor - 18*FRACUNIT; - else - player->mo->movefactor = FRACUNIT; //player->mo->movefactor = ((player->mo->friction - 0xDB34)*(0xA))/0x80; + player->mo->movefactor = FixedDiv(ORIG_FRICTION, player->mo->friction); - if (player->mo->movefactor < 32) - player->mo->movefactor = 32; - } - if (player->kartstuff[k_spinouttimer] && player->kartstuff[k_wipeoutslow]) - { - player->mo->friction -= FixedMul(1228, player->kartstuff[k_offroad]); - if (player->kartstuff[k_wipeoutslow] == 1) - player->mo->friction -= 4912; + if (player->mo->movefactor < FRACUNIT) + player->mo->movefactor = 19*player->mo->movefactor - 18*FRACUNIT; + else + player->mo->movefactor = FRACUNIT; //player->mo->movefactor = ((player->mo->friction - 0xDB34)*(0xA))/0x80; + + if (player->mo->movefactor < 32) + player->mo->movefactor = 32; + } + + // Wipeout slowdown + if (player->kartstuff[k_spinouttimer] && player->kartstuff[k_wipeoutslow]) + { + if (player->kartstuff[k_offroad]) + player->mo->friction -= 4912; + if (player->kartstuff[k_wipeoutslow] == 1) + player->mo->friction -= 9824; + } } K_KartDrift(player, onground); @@ -5747,9 +5779,22 @@ void K_CheckBumpers(void) void K_CheckSpectateStatus(void) { UINT8 respawnlist[MAXPLAYERS]; - UINT8 i, numingame = 0, numjoiners = 0; + UINT8 i, j, numingame = 0, numjoiners = 0; - if (!cv_allowteamchange.value) return; + // Maintain spectate wait timer + for (i = 0; i < MAXPLAYERS; i++) + { + if (!playeringame[i]) + continue; + if (players[i].spectator && (players[i].pflags & PF_WANTSTOJOIN)) + players[i].kartstuff[k_spectatewait]++; + else + players[i].kartstuff[k_spectatewait] = 0; + } + + // No one's allowed to join + if (!cv_allowteamchange.value) + return; // Get the number of players in game, and the players to be de-spectated. for (i = 0; i < MAXPLAYERS; i++) @@ -5760,16 +5805,18 @@ void K_CheckSpectateStatus(void) if (!players[i].spectator) { numingame++; + if (cv_ingamecap.value && numingame >= cv_ingamecap.value) // DON'T allow if you've hit the in-game player cap + return; if (gamestate != GS_LEVEL) // Allow if you're not in a level - continue; + continue; if (players[i].exiting) // DON'T allow if anyone's exiting return; if (numingame < 2 || leveltime < starttime || mapreset) // Allow if the match hasn't started yet - continue; + continue; if (leveltime > (starttime + 20*TICRATE)) // DON'T allow if the match is 20 seconds in - return; - if (G_RaceGametype() && players[i].laps) // DON'T allow if the race is at 2 laps - return; + return; + if (G_RaceGametype() && players[i].laps) // DON'T allow if the race is at 2 laps + return; continue; } else if (!(players[i].pflags & PF_WANTSTOJOIN)) @@ -5782,16 +5829,45 @@ void K_CheckSpectateStatus(void) if (!numjoiners) return; - // Reset the match if you're in an empty server - if (!mapreset && gamestate == GS_LEVEL && leveltime >= starttime && (numingame < 2 && numingame+numjoiners >= 2)) + // Organize by spectate wait timer + if (cv_ingamecap.value) { - S_ChangeMusicInternal("chalng", false); // COME ON - mapreset = 3*TICRATE; // Even though only the server uses this for game logic, set for everyone for HUD in the future + UINT8 oldrespawnlist[MAXPLAYERS]; + memcpy(oldrespawnlist, respawnlist, numjoiners); + for (i = 0; i < numjoiners; i++) + { + UINT8 pos = 0; + INT32 ispecwait = players[oldrespawnlist[i]].kartstuff[k_spectatewait]; + + for (j = 0; j < numjoiners; j++) + { + INT32 jspecwait = players[oldrespawnlist[j]].kartstuff[k_spectatewait]; + if (j == i) + continue; + if (jspecwait > ispecwait) + pos++; + else if (jspecwait == ispecwait && j < i) + pos++; + } + + respawnlist[pos] = oldrespawnlist[i]; + } } // Finally, we can de-spectate everyone! for (i = 0; i < numjoiners; i++) + { + if (cv_ingamecap.value && numingame+i >= cv_ingamecap.value) // Hit the in-game player cap while adding people? + break; P_SpectatorJoinGame(&players[respawnlist[i]]); + } + + // Reset the match if you're in an empty server + if (!mapreset && gamestate == GS_LEVEL && leveltime >= starttime && (numingame < 2 && numingame+i >= 2)) // use previous i value + { + S_ChangeMusicInternal("chalng", false); // COME ON + mapreset = 3*TICRATE; // Even though only the server uses this for game logic, set for everyone for HUD + } } //} @@ -7108,19 +7184,15 @@ void HU_DrawTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scorelines, I continue; //ignore them. if (netgame // don't draw it offline - && tab[i].num != serverplayer) + && tab[i].num != serverplayer) HU_drawPing(x + ((i < 8) ? -19 : rightoffset + 13), y+2, playerpingtable[tab[i].num], false); - if (scorelines > 8) - strlcpy(strtime, tab[i].name, 6); - else - STRBUFCPY(strtime, tab[i].name); + STRBUFCPY(strtime, tab[i].name); - V_DrawString(x + 20, y, - ((tab[i].num == whiteplayer) - ? hilicol|V_ALLOWLOWERCASE - : V_ALLOWLOWERCASE), - strtime); + if (scorelines > 8) + V_DrawThinString(x + 20, y, ((tab[i].num == whiteplayer) ? hilicol : 0)|V_ALLOWLOWERCASE|V_6WIDTHSPACE, strtime); + else + V_DrawString(x + 20, y, ((tab[i].num == whiteplayer) ? hilicol : 0)|V_ALLOWLOWERCASE, strtime); if (players[tab[i].num].mo->color) { @@ -7160,12 +7232,24 @@ void HU_DrawTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scorelines, I if (G_RaceGametype()) { #define timestring(time) va("%i'%02i\"%02i", G_TicsToMinutes(time, true), G_TicsToSeconds(time), G_TicsToCentiseconds(time)) - if (players[tab[i].num].exiting) - V_DrawRightAlignedString(x+rightoffset, y, hilicol, timestring(players[tab[i].num].realtime)); - else if (players[tab[i].num].pflags & PF_TIMEOVER) - V_DrawRightAlignedThinString(x+rightoffset, y-1, 0, "NO CONTEST."); - else if (circuitmap) - V_DrawRightAlignedString(x+rightoffset, y, 0, va("Lap %d", tab[i].count)); + if (scorelines > 8) + { + if (players[tab[i].num].exiting) + V_DrawRightAlignedThinString(x+rightoffset, y-1, hilicol|V_6WIDTHSPACE, timestring(players[tab[i].num].realtime)); + else if (players[tab[i].num].pflags & PF_TIMEOVER) + V_DrawRightAlignedThinString(x+rightoffset, y-1, V_6WIDTHSPACE, "NO CONTEST."); + else if (circuitmap) + V_DrawRightAlignedThinString(x+rightoffset, y-1, V_6WIDTHSPACE, va("Lap %d", tab[i].count)); + } + else + { + if (players[tab[i].num].exiting) + V_DrawRightAlignedString(x+rightoffset, y, hilicol, timestring(players[tab[i].num].realtime)); + else if (players[tab[i].num].pflags & PF_TIMEOVER) + V_DrawRightAlignedThinString(x+rightoffset, y-1, 0, "NO CONTEST."); + else if (circuitmap) + V_DrawRightAlignedString(x+rightoffset, y, 0, va("Lap %d", tab[i].count)); + } #undef timestring } else @@ -8322,6 +8406,7 @@ static void K_drawCheckpointDebugger(void) void K_drawKartHUD(void) { boolean isfreeplay = false; + boolean battlefullscreen = false; // Define the X and Y for each drawn object // This is handled by console/menu values @@ -8334,14 +8419,6 @@ void K_drawKartHUD(void) || ((splitscreen > 2 && stplyr == &players[fourthdisplayplayer]) && !camera4.chase)) K_drawKartFirstPerson(); -/* if (splitscreen == 2) // Player 4 in 3P is the minimap :p - { -#ifdef HAVE_BLUA - if (LUA_HudEnabled(hud_minimap)) -#endif - K_drawKartMinimap(); - }*/ - // Draw full screen stuff that turns off the rest of the HUD if (mapreset && stplyr == &players[displayplayer]) { @@ -8349,39 +8426,43 @@ void K_drawKartHUD(void) return; } - if ((G_BattleGametype()) + battlefullscreen = ((G_BattleGametype()) && (stplyr->exiting || (stplyr->kartstuff[k_bumper] <= 0 && stplyr->kartstuff[k_comebacktimer] && comeback - && stplyr->playerstate == PST_LIVE))) + && stplyr->playerstate == PST_LIVE))); + + if (!battlefullscreen || splitscreen) + { + // Draw the CHECK indicator before the other items, so it's overlapped by everything else + if (cv_kartcheck.value && !splitscreen && !players[displayplayer].exiting) + K_drawKartPlayerCheck(); + + // Draw WANTED status + if (G_BattleGametype()) + { +#ifdef HAVE_BLUA + if (LUA_HudEnabled(hud_wanted)) +#endif + K_drawKartWanted(); + } + + if (cv_kartminimap.value && !titledemo) + { +#ifdef HAVE_BLUA + if (LUA_HudEnabled(hud_minimap)) +#endif + K_drawKartMinimap(); + } + } + + if (battlefullscreen) { K_drawBattleFullscreen(); return; } - // Draw the CHECK indicator before the other items, so it's overlapped by everything else - if (cv_kartcheck.value && !splitscreen && !players[displayplayer].exiting) - K_drawKartPlayerCheck(); - - // Draw WANTED status - if (G_BattleGametype()) - { -#ifdef HAVE_BLUA - if (LUA_HudEnabled(hud_wanted)) -#endif - K_drawKartWanted(); - } - - if (cv_kartminimap.value && !titledemo) - { -#ifdef HAVE_BLUA - if (LUA_HudEnabled(hud_minimap)) -#endif - K_drawKartMinimap(); // 3P splitscreen is handled above - - } - // Draw the item window #ifdef HAVE_BLUA if (LUA_HudEnabled(hud_item)) diff --git a/src/k_kart.h b/src/k_kart.h index 17652b9de..dc37956af 100644 --- a/src/k_kart.h +++ b/src/k_kart.h @@ -1,83 +1,83 @@ -// SONIC ROBO BLAST 2 KART ~ ZarroTsu -//----------------------------------------------------------------------------- -/// \file k_kart.h -/// \brief SRB2kart stuff. - -#ifndef __K_KART__ -#define __K_KART__ - -#include "doomdef.h" -#include "d_player.h" // Need for player_t - -#define KART_FULLTURN 800 - -UINT8 colortranslations[MAXSKINCOLORS][16]; -extern const char *KartColor_Names[MAXSKINCOLORS]; -extern const UINT8 KartColor_Opposite[MAXSKINCOLORS*2]; -void K_RainbowColormap(UINT8 *dest_colormap, UINT8 skincolor); -void K_GenerateKartColormap(UINT8 *dest_colormap, INT32 skinnum, UINT8 color); -UINT8 K_GetKartColorByName(const char *name); - -void K_RegisterKartStuff(void); - -boolean K_IsPlayerLosing(player_t *player); -boolean K_IsPlayerWanted(player_t *player); -void K_KartBouncing(mobj_t *mobj1, mobj_t *mobj2, boolean bounce, boolean solid); -void K_MatchGenericExtraFlags(mobj_t *mo, mobj_t *master); -void K_RespawnChecker(player_t *player); -void K_KartMoveAnimation(player_t *player); -void K_KartPlayerHUDUpdate(player_t *player); -void K_KartPlayerThink(player_t *player, ticcmd_t *cmd); -void K_KartPlayerAfterThink(player_t *player); -void K_DoInstashield(player_t *player); -void K_SpawnBattlePoints(player_t *source, player_t *victim, UINT8 amount); -void K_SpinPlayer(player_t *player, mobj_t *source, INT32 type, mobj_t *inflictor, boolean trapitem); -void K_SquishPlayer(player_t *player, mobj_t *source, mobj_t *inflictor); -void K_ExplodePlayer(player_t *player, mobj_t *source, mobj_t *inflictor); -void K_StealBumper(player_t *player, player_t *victim, boolean force); -void K_SpawnKartExplosion(fixed_t x, fixed_t y, fixed_t z, fixed_t radius, INT32 number, mobjtype_t type, angle_t rotangle, boolean spawncenter, boolean ghostit, mobj_t *source); -void K_SpawnMineExplosion(mobj_t *source, UINT8 color); -void K_SpawnBoostTrail(player_t *player); -void K_SpawnSparkleTrail(mobj_t *mo); -void K_SpawnWipeoutTrail(mobj_t *mo, boolean translucent); -void K_DriftDustHandling(mobj_t *spawner); -void K_DoSneaker(player_t *player, INT32 type); -void K_DoPogoSpring(mobj_t *mo, fixed_t vertispeed, UINT8 sound); -void K_KillBananaChain(mobj_t *banana, mobj_t *inflictor, mobj_t *source); -void K_UpdateHnextList(player_t *player, boolean clean); -void K_DropHnextList(player_t *player); -void K_RepairOrbitChain(mobj_t *orbit); -player_t *K_FindJawzTarget(mobj_t *actor, player_t *source); -boolean K_CheckPlayersRespawnColliding(INT32 playernum, fixed_t x, fixed_t y); -INT16 K_GetKartTurnValue(player_t *player, INT16 turnvalue); -INT32 K_GetKartDriftSparkValue(player_t *player); -void K_KartUpdatePosition(player_t *player); -void K_DropItems(player_t *player); -void K_StripItems(player_t *player); -void K_StripOther(player_t *player); -void K_MomentumToFacing(player_t *player); -fixed_t K_GetKartSpeed(player_t *player, boolean doboostpower); -fixed_t K_GetKartAccel(player_t *player); -UINT16 K_GetKartFlashing(player_t *player); -fixed_t K_3dKartMovement(player_t *player, boolean onground, fixed_t forwardmove); -void K_MoveKartPlayer(player_t *player, boolean onground); -void K_CalculateBattleWanted(void); -void K_CheckBumpers(void); -void K_CheckSpectateStatus(void); - -// sound stuff for lua -void K_PlayAttackTaunt(mobj_t *source); -void K_PlayBoostTaunt(mobj_t *source); -void K_PlayOvertakeSound(mobj_t *source); -void K_PlayHitEmSound(mobj_t *source); -void K_PlayPowerGloatSound(mobj_t *source); - -const char *K_GetItemPatch(UINT8 item, boolean tiny); -INT32 K_calcSplitFlags(INT32 snapflags); -void K_LoadKartHUDGraphics(void); -void K_drawKartHUD(void); -void K_drawKartFreePlay(UINT32 flashtime); -void K_drawKartTimestamp(tic_t drawtime, INT32 TX, INT32 TY, INT16 emblemmap, UINT8 mode); - -// ========================================================================= -#endif // __K_KART__ +// SONIC ROBO BLAST 2 KART ~ ZarroTsu +//----------------------------------------------------------------------------- +/// \file k_kart.h +/// \brief SRB2kart stuff. + +#ifndef __K_KART__ +#define __K_KART__ + +#include "doomdef.h" +#include "d_player.h" // Need for player_t + +#define KART_FULLTURN 800 + +UINT8 colortranslations[MAXSKINCOLORS][16]; +extern const char *KartColor_Names[MAXSKINCOLORS]; +extern const UINT8 KartColor_Opposite[MAXSKINCOLORS*2]; +void K_RainbowColormap(UINT8 *dest_colormap, UINT8 skincolor); +void K_GenerateKartColormap(UINT8 *dest_colormap, INT32 skinnum, UINT8 color); +UINT8 K_GetKartColorByName(const char *name); + +void K_RegisterKartStuff(void); + +boolean K_IsPlayerLosing(player_t *player); +boolean K_IsPlayerWanted(player_t *player); +void K_KartBouncing(mobj_t *mobj1, mobj_t *mobj2, boolean bounce, boolean solid); +void K_MatchGenericExtraFlags(mobj_t *mo, mobj_t *master); +void K_RespawnChecker(player_t *player); +void K_KartMoveAnimation(player_t *player); +void K_KartPlayerHUDUpdate(player_t *player); +void K_KartPlayerThink(player_t *player, ticcmd_t *cmd); +void K_KartPlayerAfterThink(player_t *player); +void K_DoInstashield(player_t *player); +void K_SpawnBattlePoints(player_t *source, player_t *victim, UINT8 amount); +void K_SpinPlayer(player_t *player, mobj_t *source, INT32 type, mobj_t *inflictor, boolean trapitem); +void K_SquishPlayer(player_t *player, mobj_t *source, mobj_t *inflictor); +void K_ExplodePlayer(player_t *player, mobj_t *source, mobj_t *inflictor); +void K_StealBumper(player_t *player, player_t *victim, boolean force); +void K_SpawnKartExplosion(fixed_t x, fixed_t y, fixed_t z, fixed_t radius, INT32 number, mobjtype_t type, angle_t rotangle, boolean spawncenter, boolean ghostit, mobj_t *source); +void K_SpawnMineExplosion(mobj_t *source, UINT8 color); +void K_SpawnBoostTrail(player_t *player); +void K_SpawnSparkleTrail(mobj_t *mo); +void K_SpawnWipeoutTrail(mobj_t *mo, boolean translucent); +void K_DriftDustHandling(mobj_t *spawner); +void K_DoSneaker(player_t *player, INT32 type); +void K_DoPogoSpring(mobj_t *mo, fixed_t vertispeed, UINT8 sound); +void K_KillBananaChain(mobj_t *banana, mobj_t *inflictor, mobj_t *source); +void K_UpdateHnextList(player_t *player, boolean clean); +void K_DropHnextList(player_t *player); +void K_RepairOrbitChain(mobj_t *orbit); +player_t *K_FindJawzTarget(mobj_t *actor, player_t *source); +boolean K_CheckPlayersRespawnColliding(INT32 playernum, fixed_t x, fixed_t y); +INT16 K_GetKartTurnValue(player_t *player, INT16 turnvalue); +INT32 K_GetKartDriftSparkValue(player_t *player); +void K_KartUpdatePosition(player_t *player); +void K_DropItems(player_t *player); +void K_StripItems(player_t *player); +void K_StripOther(player_t *player); +void K_MomentumToFacing(player_t *player); +fixed_t K_GetKartSpeed(player_t *player, boolean doboostpower); +fixed_t K_GetKartAccel(player_t *player); +UINT16 K_GetKartFlashing(player_t *player); +fixed_t K_3dKartMovement(player_t *player, boolean onground, fixed_t forwardmove); +void K_MoveKartPlayer(player_t *player, boolean onground); +void K_CalculateBattleWanted(void); +void K_CheckBumpers(void); +void K_CheckSpectateStatus(void); + +// sound stuff for lua +void K_PlayAttackTaunt(mobj_t *source); +void K_PlayBoostTaunt(mobj_t *source); +void K_PlayOvertakeSound(mobj_t *source); +void K_PlayHitEmSound(mobj_t *source); +void K_PlayPowerGloatSound(mobj_t *source); + +const char *K_GetItemPatch(UINT8 item, boolean tiny); +INT32 K_calcSplitFlags(INT32 snapflags); +void K_LoadKartHUDGraphics(void); +void K_drawKartHUD(void); +void K_drawKartFreePlay(UINT32 flashtime); +void K_drawKartTimestamp(tic_t drawtime, INT32 TX, INT32 TY, INT16 emblemmap, UINT8 mode); + +// ========================================================================= +#endif // __K_KART__ diff --git a/src/lua_hudlib.c b/src/lua_hudlib.c index ca952a009..cd8e03923 100644 --- a/src/lua_hudlib.c +++ b/src/lua_hudlib.c @@ -34,6 +34,8 @@ static UINT8 hud_enabled[(hud_MAX/8)+1]; static UINT8 hudAvailable; // hud hooks field +static UINT8 camnum = 1; + // must match enum hud in lua_hud.h static const char *const hud_disable_options[] = { "stagetitle", @@ -134,7 +136,8 @@ enum cameraf { camera_height, camera_momx, camera_momy, - camera_momz + camera_momz, + camera_pnum }; @@ -153,6 +156,7 @@ static const char *const camera_opt[] = { "momx", "momy", "momz", + "pnum", NULL}; static int lib_getHudInfo(lua_State *L) @@ -308,6 +312,9 @@ static int camera_get(lua_State *L) case camera_momz: lua_pushinteger(L, cam->momz); break; + case camera_pnum: + lua_pushinteger(L, camnum); + break; } return 1; } @@ -772,13 +779,25 @@ void LUAh_GameHUD(player_t *stplayr) LUA_PushUserdata(gL, stplayr, META_PLAYER); if (splitscreen > 2 && stplayr == &players[fourthdisplayplayer]) + { LUA_PushUserdata(gL, &camera4, META_CAMERA); + camnum = 4; + } else if (splitscreen > 1 && stplayr == &players[thirddisplayplayer]) + { LUA_PushUserdata(gL, &camera3, META_CAMERA); + camnum = 3; + } else if (splitscreen && stplayr == &players[secondarydisplayplayer]) + { LUA_PushUserdata(gL, &camera2, META_CAMERA); + camnum = 2; + } else + { LUA_PushUserdata(gL, &camera, META_CAMERA); + camnum = 1; + } lua_pushnil(gL); while (lua_next(gL, -5) != 0) { diff --git a/src/lua_script.c b/src/lua_script.c index 34a260527..28f02ca37 100644 --- a/src/lua_script.c +++ b/src/lua_script.c @@ -212,6 +212,9 @@ void LUA_LoadLump(UINT16 wad, UINT16 lump) LUA_LoadFile(&f, name); // actually load file! + // Okay, we've modified the game beyond the point of no return. + G_SetGameModified(multiplayer, true); + free(name); Z_Free(f.data); } @@ -1017,7 +1020,7 @@ void LUA_Archive(void) for (i = 0; i < MAXPLAYERS; i++) { - if (!playeringame[i]) + if (!playeringame[i] && i > 0) // NEVER skip player 0, this is for dedi servs. continue; // all players in game will be archived, even if they just add a 0. ArchiveExtVars(&players[i], "player"); @@ -1053,7 +1056,7 @@ void LUA_UnArchive(void) for (i = 0; i < MAXPLAYERS; i++) { - if (!playeringame[i]) + if (!playeringame[i] && i > 0) // same here, this is to synch dediservs properly. continue; UnArchiveExtVars(&players[i]); } diff --git a/src/m_cheat.c b/src/m_cheat.c index 38d8cc7a9..2fc2e85c9 100644 --- a/src/m_cheat.c +++ b/src/m_cheat.c @@ -121,7 +121,7 @@ static UINT8 cheatf_devmode(void) S_StartSound(0, sfx_itemup); // Just unlock all the things and turn on -debug and console devmode. - G_SetGameModified(false); + G_SetGameModified(false, false); // might need to revist the latter later for (i = 0; i < MAXUNLOCKABLES; i++) unlockables[i].unlocked = true; devparm = true; @@ -295,7 +295,7 @@ void Command_CheatNoClip_f(void) plyr->pflags ^= PF_NOCLIP; CONS_Printf(M_GetText("No Clipping %s\n"), plyr->pflags & PF_NOCLIP ? M_GetText("On") : M_GetText("Off")); - G_SetGameModified(multiplayer); + G_SetGameModified(multiplayer, true); } void Command_CheatGod_f(void) @@ -310,7 +310,7 @@ void Command_CheatGod_f(void) plyr->pflags ^= PF_GODMODE; CONS_Printf(M_GetText("Sissy Mode %s\n"), plyr->pflags & PF_GODMODE ? M_GetText("On") : M_GetText("Off")); - G_SetGameModified(multiplayer); + G_SetGameModified(multiplayer, true); } void Command_CheatNoTarget_f(void) @@ -325,7 +325,7 @@ void Command_CheatNoTarget_f(void) plyr->pflags ^= PF_INVIS; CONS_Printf(M_GetText("SEP Field %s\n"), plyr->pflags & PF_INVIS ? M_GetText("On") : M_GetText("Off")); - G_SetGameModified(multiplayer); + G_SetGameModified(multiplayer, true); } void Command_Scale_f(void) @@ -727,7 +727,7 @@ void Command_Devmode_f(void) return; } - G_SetGameModified(multiplayer); + G_SetGameModified(multiplayer, true); } /*void Command_Setrings_f(void) @@ -1267,7 +1267,7 @@ void Command_ObjectPlace_f(void) REQUIRE_SINGLEPLAYER; REQUIRE_NOULTIMATE; - G_SetGameModified(multiplayer); + G_SetGameModified(multiplayer, true); // Entering objectplace? if (!objectplacing) diff --git a/src/m_cond.c b/src/m_cond.c index 35eccd1c4..b777e7d22 100644 --- a/src/m_cond.c +++ b/src/m_cond.c @@ -385,8 +385,7 @@ UINT8 M_UpdateUnlockablesAndExtraEmblems(boolean force) char cechoText[992] = ""; UINT8 cechoLines = 0; - if (modifiedgame && !savemoddata - && !force) // SRB2Kart: for enabling unlocks online in modified servers + if (majormods && !force) // SRB2Kart: for enabling unlocks online in modified servers return false; M_CheckUnlockConditions(); diff --git a/src/m_menu.c b/src/m_menu.c index f0831a172..615b8c893 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -274,14 +274,13 @@ static menu_t SP_TimeAttackDef, SP_ReplayDef, SP_GuestReplayDef, SP_GhostDef; #ifndef NONET static void M_StartServerMenu(INT32 choice); static void M_ConnectMenu(INT32 choice); -#endif -static void M_StartOfflineServerMenu(INT32 choice); -static void M_StartServer(INT32 choice); -#ifndef NONET +static void M_ConnectMenuModChecks(INT32 choice); static void M_Refresh(INT32 choice); static void M_Connect(INT32 choice); static void M_ChooseRoom(INT32 choice); #endif +static void M_StartOfflineServerMenu(INT32 choice); +static void M_StartServer(INT32 choice); static void M_SetupMultiPlayer(INT32 choice); static void M_SetupMultiPlayer2(INT32 choice); static void M_SetupMultiPlayer3(INT32 choice); @@ -439,11 +438,11 @@ static CV_PossibleValue_t serversort_cons_t[] = { {1,"Modified State"}, {2,"Most Players"}, {3,"Least Players"}, - {4,"Max Players"}, + {4,"Max Player Slots"}, {5,"Gametype"}, {0,NULL} }; -consvar_t cv_serversort = {"serversort", "Ping", CV_HIDEN | CV_CALL, serversort_cons_t, M_SortServerList, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_serversort = {"serversort", "Ping", CV_CALL, serversort_cons_t, M_SortServerList, 0, NULL, NULL, 0, 0, NULL}; // autorecord demos for time attack static consvar_t cv_autorecord = {"autorecord", "Yes", 0, CV_YesNo, NULL, 0, NULL, NULL, 0, 0, NULL}; @@ -935,11 +934,11 @@ static menuitem_t MP_MainMenu[] = {IT_HEADER, NULL, "Join a game", NULL, 132-24}, #ifndef NONET - {IT_STRING|IT_CALL, NULL, "Internet server browser...",M_ConnectMenu, 142-24}, + {IT_STRING|IT_CALL, NULL, "Internet server browser...",M_ConnectMenuModChecks, 142-24}, {IT_STRING|IT_KEYHANDLER, NULL, "Specify IPv4 address:", M_HandleConnectIP, 150-24}, #else - {IT_GRAYEDOUT, NULL, "Internet server browser...",M_ConnectMenu, 142-24}, - {IT_GRAYEDOUT, NULL, "Specify IPv4 address:", M_HandleConnectIP, 150-24}, + {IT_GRAYEDOUT, NULL, "Internet server browser...",NULL, 142-24}, + {IT_GRAYEDOUT, NULL, "Specify IPv4 address:", NULL, 150-24}, #endif //{IT_HEADER, NULL, "Player setup", NULL, 80}, //{IT_STRING|IT_CALL, NULL, "Name, character, color...", M_SetupMultiPlayer, 90}, @@ -1831,7 +1830,6 @@ static menu_t SP_NightsGhostDef = NULL };*/ -#ifndef NONET // Multiplayer menu_t MP_MainDef = { @@ -1842,12 +1840,18 @@ menu_t MP_MainDef = M_DrawMPMainMenu, 42, 30, 0, - M_CancelConnect -}; -menu_t MP_ServerDef = MAPICONMENUSTYLE("M_MULTI", MP_ServerMenu, &MP_MainDef); -#endif -menu_t MP_OfflineServerDef = MAPICONMENUSTYLE("M_MULTI", MP_OfflineServerMenu, &MP_MainDef); #ifndef NONET + M_CancelConnect +#else + NULL +#endif +}; + +menu_t MP_OfflineServerDef = MAPICONMENUSTYLE("M_MULTI", MP_OfflineServerMenu, &MP_MainDef); + +#ifndef NONET +menu_t MP_ServerDef = MAPICONMENUSTYLE("M_MULTI", MP_ServerMenu, &MP_MainDef); + menu_t MP_ConnectDef = { "M_MULTI", @@ -2739,10 +2743,10 @@ boolean M_Responder(event_t *ev) || (currentMenu->menuitems[itemOn].status & IT_TYPE)==IT_SUBMENU) && (currentMenu->menuitems[itemOn].status & IT_CALLTYPE)) { - if (((currentMenu->menuitems[itemOn].status & IT_CALLTYPE) & IT_CALL_NOTMODIFIED) && modifiedgame && !savemoddata) + if (((currentMenu->menuitems[itemOn].status & IT_CALLTYPE) & IT_CALL_NOTMODIFIED) && majormods) { S_StartSound(NULL, sfx_menu1); - M_StartMessage(M_GetText("This cannot be done with add-ons\nor in a cheated game.\n\n(Press a key)\n"), NULL, MM_NOTHING); + M_StartMessage(M_GetText("This cannot be done with complex add-ons\nor in a cheated game.\n\n(Press a key)\n"), NULL, MM_NOTHING); return true; } } @@ -4527,9 +4531,14 @@ static char *M_AddonsHeaderPath(void) #define CLEARNAME Z_Free(refreshdirname);\ refreshdirname = NULL +static boolean prevmajormods = false; + static void M_AddonsClearName(INT32 choice) { - CLEARNAME; + if (!majormods || prevmajormods) + { + CLEARNAME; + } M_StopMessage(choice); } @@ -4539,10 +4548,17 @@ static boolean M_AddonsRefresh(void) if ((refreshdirmenu & REFRESHDIR_NORMAL) && !preparefilemenu(true)) { UNEXIST; + if (refreshdirname) + { + CLEARNAME; + } return true; } - if (refreshdirmenu & REFRESHDIR_ADDFILE) + if (!majormods && prevmajormods) + prevmajormods = false; + + if ((refreshdirmenu & REFRESHDIR_ADDFILE) || (majormods && !prevmajormods)) { char *message = NULL; @@ -4550,7 +4566,7 @@ static boolean M_AddonsRefresh(void) { S_StartSound(NULL, sfx_s26d); if (refreshdirmenu & REFRESHDIR_MAX) - message = va("%c%s\x80\nMaximum number of add-ons reached.\nA file could not be loaded.\nIf you want to play with this add-on, restart the game to clear existing ones.\n\n(Press a key)\n", ('\x80' + (highlightflags>>V_CHARCOLORSHIFT)), refreshdirname); + message = va("%c%s\x80\nMaximum number of add-ons reached.\nA file could not be loaded.\nIf you wish to play with this add-on, restart the game to clear existing ones.\n\n(Press a key)\n", ('\x80' + (highlightflags>>V_CHARCOLORSHIFT)), refreshdirname); else message = va("%c%s\x80\nA file was not loaded.\nCheck the console log for more information.\n\n(Press a key)\n", ('\x80' + (highlightflags>>V_CHARCOLORSHIFT)), refreshdirname); } @@ -4559,6 +4575,12 @@ static boolean M_AddonsRefresh(void) S_StartSound(NULL, sfx_s224); message = va("%c%s\x80\nA file was loaded with %s.\nCheck the console log for more information.\n\n(Press a key)\n", ('\x80' + (highlightflags>>V_CHARCOLORSHIFT)), refreshdirname, ((refreshdirmenu & REFRESHDIR_ERROR) ? "errors" : "warnings")); } + else if (majormods && !prevmajormods) + { + S_StartSound(NULL, sfx_s221); + message = va("%c%s\x80\nGameplay has now been modified.\nIf you wish to play Record Attack mode, restart the game to clear existing add-ons.\n\n(Press a key)\n", ('\x80' + (highlightflags>>V_CHARCOLORSHIFT)), refreshdirname); + prevmajormods = majormods; + } if (message) { @@ -4709,7 +4731,7 @@ static void M_DrawAddons(void) V_DrawSmallScaledPatch(x, y + 4, (menusearch[0] ? 0 : V_TRANSLUCENT), addonsp[NUM_EXT+3]); x = BASEVIDWIDTH - x - 16; - V_DrawSmallScaledPatch(x, y + 4, ((!modifiedgame || savemoddata) ? 0 : V_TRANSLUCENT), addonsp[NUM_EXT+4]); + V_DrawSmallScaledPatch(x, y + 4, ((!majormods) ? 0 : V_TRANSLUCENT), addonsp[NUM_EXT+4]); if (modifiedgame) V_DrawSmallScaledPatch(x, y + 4, 0, addonsp[NUM_EXT+2]); @@ -5106,7 +5128,7 @@ static void M_GetAllEmeralds(INT32 choice) emeralds = ((EMERALD7)*2)-1; M_StartMessage(M_GetText("You now have all 7 emeralds.\nUse them wisely.\nWith great power comes great ring drain.\n"),NULL,MM_NOTHING); - G_SetGameModified(multiplayer); + G_SetGameModified(multiplayer, true); } static void M_DestroyRobotsResponse(INT32 ch) @@ -5117,7 +5139,7 @@ static void M_DestroyRobotsResponse(INT32 ch) // Destroy all robots P_DestroyRobots(); - G_SetGameModified(multiplayer); + G_SetGameModified(multiplayer, true); } static void M_DestroyRobots(INT32 choice) @@ -7384,6 +7406,20 @@ static void M_ConnectMenu(INT32 choice) M_Refresh(0); } +static void M_ConnectMenuModChecks(INT32 choice) +{ + (void)choice; + // okay never mind we want to COMMUNICATE to the player pre-emptively instead of letting them try and then get confused when it doesn't work + + if (modifiedgame) + { + M_StartMessage(M_GetText("Add-ons are currently loaded.\n\nYou will only be able to join a server if\nit has the same ones loaded in the same order, which may be unlikely.\n\nIf you wish to play on other servers,\nrestart the game to clear existing add-ons.\n\n(Press a key)\n"),M_ConnectMenu,MM_EVENTHANDLER); + return; + } + + M_ConnectMenu(-1); +} + static UINT32 roomIds[NUM_LIST_ROOMS]; static void M_RoomMenu(INT32 choice) diff --git a/src/m_misc.c b/src/m_misc.c index 53b63e75f..c95aa392c 100644 --- a/src/m_misc.c +++ b/src/m_misc.c @@ -93,9 +93,8 @@ typedef off_t off64_t; #ifdef PNG_WRITE_SUPPORTED #define USE_PNG // Only actually use PNG if write is supported. #if defined (PNG_WRITE_APNG_SUPPORTED) //|| !defined(PNG_STATIC) - #if (PNG_LIBPNG_VER_MAJOR) == 1 && (PNG_LIBPNG_VER_MINOR <= 4) // Supposedly, the current APNG code can't work on newer versions as is + #include "apng.h" #define USE_APNG - #endif #endif // See hardware/hw_draw.c for a similar check to this one. #endif @@ -795,13 +794,13 @@ static inline void M_PNGImage(png_structp png_ptr, png_infop png_info_ptr, PNG_C #ifdef USE_APNG static png_structp apng_ptr = NULL; static png_infop apng_info_ptr = NULL; +static apng_infop apng_ainfo_ptr = NULL; static png_FILE_p apng_FILE = NULL; static png_uint_32 apng_frames = 0; -static png_byte acTL_cn[5] = { 97, 99, 84, 76, '\0'}; #ifdef PNG_STATIC // Win32 build have static libpng -#define apng_set_acTL png_set_acTL -#define apng_write_frame_head png_write_frame_head -#define apng_write_frame_tail png_write_frame_tail +#define aPNG_set_acTL png_set_acTL +#define aPNG_write_frame_head png_write_frame_head +#define aPNG_write_frame_tail png_write_frame_tail #else // outside libpng may not have apng support #ifndef PNG_WRITE_APNG_SUPPORTED // libpng header may not have apng patch @@ -838,20 +837,20 @@ static png_byte acTL_cn[5] = { 97, 99, 84, 76, '\0'}; #endif #endif -typedef PNG_EXPORT(png_uint_32, (*P_png_set_acTL)) PNGARG((png_structp png_ptr, - png_infop info_ptr, png_uint_32 num_frames, png_uint_32 num_plays)); -typedef PNG_EXPORT (void, (*P_png_write_frame_head)) PNGARG((png_structp png_ptr, +typedef png_uint_32 (*P_png_set_acTL) (png_structp png_ptr, + png_infop info_ptr, png_uint_32 num_frames, png_uint_32 num_plays); +typedef void (*P_png_write_frame_head) (png_structp png_ptr, png_infop info_ptr, png_bytepp row_pointers, png_uint_32 width, png_uint_32 height, png_uint_32 x_offset, png_uint_32 y_offset, png_uint_16 delay_num, png_uint_16 delay_den, png_byte dispose_op, - png_byte blend_op)); + png_byte blend_op); -typedef PNG_EXPORT (void, (*P_png_write_frame_tail)) PNGARG((png_structp png_ptr, - png_infop info_ptr)); -static P_png_set_acTL apng_set_acTL = NULL; -static P_png_write_frame_head apng_write_frame_head = NULL; -static P_png_write_frame_tail apng_write_frame_tail = NULL; +typedef void (*P_png_write_frame_tail) (png_structp png_ptr, + png_infop info_ptr); +static P_png_set_acTL aPNG_set_acTL = NULL; +static P_png_write_frame_head aPNG_write_frame_head = NULL; +static P_png_write_frame_tail aPNG_write_frame_tail = NULL; #endif static inline boolean M_PNGLib(void) @@ -860,7 +859,7 @@ static inline boolean M_PNGLib(void) return true; #else static void *pnglib = NULL; - if (apng_set_acTL && apng_write_frame_head && apng_write_frame_tail) + if (aPNG_set_acTL && aPNG_write_frame_head && aPNG_write_frame_tail) return true; if (pnglib) return false; @@ -880,16 +879,16 @@ static inline boolean M_PNGLib(void) if (!pnglib) return false; #ifdef HAVE_SDL - apng_set_acTL = hwSym("png_set_acTL", pnglib); - apng_write_frame_head = hwSym("png_write_frame_head", pnglib); - apng_write_frame_tail = hwSym("png_write_frame_tail", pnglib); + aPNG_set_acTL = hwSym("png_set_acTL", pnglib); + aPNG_write_frame_head = hwSym("png_write_frame_head", pnglib); + aPNG_write_frame_tail = hwSym("png_write_frame_tail", pnglib); #endif #ifdef _WIN32 - apng_set_acTL = GetProcAddress("png_set_acTL", pnglib); - apng_write_frame_head = GetProcAddress("png_write_frame_head", pnglib); - apng_write_frame_tail = GetProcAddress("png_write_frame_tail", pnglib); + aPNG_set_acTL = GetProcAddress("png_set_acTL", pnglib); + aPNG_write_frame_head = GetProcAddress("png_write_frame_head", pnglib); + aPNG_write_frame_tail = GetProcAddress("png_write_frame_tail", pnglib); #endif - return (apng_set_acTL && apng_write_frame_head && apng_write_frame_tail); + return (aPNG_set_acTL && aPNG_write_frame_head && aPNG_write_frame_tail); #endif } @@ -903,11 +902,6 @@ static void M_PNGFrame(png_structp png_ptr, png_infop png_info_ptr, png_bytep pn apng_frames++; -#ifndef PNG_STATIC - if (apng_set_acTL) -#endif - apng_set_acTL(apng_ptr, apng_info_ptr, apng_frames, 0); - for (y = 0; y < height; y++) { row_pointers[y] = png_buf; @@ -915,9 +909,9 @@ static void M_PNGFrame(png_structp png_ptr, png_infop png_info_ptr, png_bytep pn } #ifndef PNG_STATIC - if (apng_write_frame_head) + if (aPNG_write_frame_head) #endif - apng_write_frame_head(apng_ptr, apng_info_ptr, row_pointers, + aPNG_write_frame_head(apng_ptr, apng_info_ptr, row_pointers, vid.width, /* width */ height, /* height */ 0, /* x offset */ @@ -930,57 +924,21 @@ static void M_PNGFrame(png_structp png_ptr, png_infop png_info_ptr, png_bytep pn png_write_image(png_ptr, row_pointers); #ifndef PNG_STATIC - if (apng_write_frame_tail) + if (aPNG_write_frame_tail) #endif - apng_write_frame_tail(apng_ptr, apng_info_ptr); + aPNG_write_frame_tail(apng_ptr, apng_info_ptr); png_free(png_ptr, (png_voidp)row_pointers); } -static inline boolean M_PNGfind_acTL(void) +static void M_PNGfix_acTL(png_structp png_ptr, png_infop png_info_ptr, + apng_infop png_ainfo_ptr) { - png_byte cn[8]; // 4 bytes for len then 4 byes for name - long endpos = ftell(apng_FILE); // not the real end of file, just what of libpng wrote - for (fseek(apng_FILE, 0, SEEK_SET); // let go to the start of the file - ftell(apng_FILE)+12 < endpos; // let not go over the file bound - fseek(apng_FILE, 1, SEEK_CUR) // we went 8 steps back and now we go 1 step forward - ) - { - if (fread(cn, sizeof(cn), 1, apng_FILE) != 1) // read 8 bytes - return false; // failed to read data - if (fseek(apng_FILE, -8, SEEK_CUR) != 0) //rewind 8 bytes - return false; // failed to rewird - if (!png_memcmp(cn+4, acTL_cn, 4)) //cmp for chuck header - return true; // found it - } - return false; // acTL chuck not found -} - -static void M_PNGfix_acTL(png_structp png_ptr, png_infop png_info_ptr) -{ - png_byte data[16]; - long oldpos; - -#ifndef PNG_STATIC - if (apng_set_acTL) -#endif - apng_set_acTL(png_ptr, png_info_ptr, apng_frames, 0); + apng_set_acTL(png_ptr, png_info_ptr, png_ainfo_ptr, apng_frames, 0); #ifndef NO_PNG_DEBUG png_debug(1, "in png_write_acTL\n"); #endif - - png_ptr->num_frames_to_write = apng_frames; - - png_save_uint_32(data, apng_frames); - png_save_uint_32(data + 4, 0); - - oldpos = ftell(apng_FILE); - - if (M_PNGfind_acTL()) - png_write_chunk(png_ptr, (png_bytep)acTL_cn, data, (png_size_t)8); - - fseek(apng_FILE, oldpos, SEEK_SET); } static boolean M_SetupaPNG(png_const_charp filename, png_bytep pal) @@ -1012,6 +970,16 @@ static boolean M_SetupaPNG(png_const_charp filename, png_bytep pal) return false; } + apng_ainfo_ptr = apng_create_info_struct(apng_ptr); + if (!apng_ainfo_ptr) + { + CONS_Debug(DBG_RENDER, "M_StartMovie: Error on allocate for apng\n"); + png_destroy_write_struct(&apng_ptr, &apng_info_ptr); + fclose(apng_FILE); + remove(filename); + return false; + } + png_init_io(apng_ptr, apng_FILE); #ifdef PNG_SET_USER_LIMITS_SUPPORTED @@ -1029,12 +997,11 @@ static boolean M_SetupaPNG(png_const_charp filename, png_bytep pal) M_PNGText(apng_ptr, apng_info_ptr, true); -#ifndef PNG_STATIC - if (apng_set_acTL) -#endif - apng_set_acTL(apng_ptr, apng_info_ptr, PNG_UINT_31_MAX, 0); + apng_set_set_acTL_fn(apng_ptr, apng_ainfo_ptr, aPNG_set_acTL); - png_write_info(apng_ptr, apng_info_ptr); + apng_set_acTL(apng_ptr, apng_info_ptr, apng_ainfo_ptr, PNG_UINT_31_MAX, 0); + + apng_write_info(apng_ptr, apng_info_ptr, apng_ainfo_ptr); apng_frames = 0; @@ -1237,8 +1204,8 @@ void M_StopMovie(void) if (apng_frames) { - M_PNGfix_acTL(apng_ptr, apng_info_ptr); - png_write_end(apng_ptr, apng_info_ptr); + M_PNGfix_acTL(apng_ptr, apng_info_ptr, apng_ainfo_ptr); + apng_write_end(apng_ptr, apng_info_ptr, apng_ainfo_ptr); } png_destroy_write_struct(&apng_ptr, &apng_info_ptr); diff --git a/src/p_enemy.c b/src/p_enemy.c index 8a6d7597f..9d3aa9519 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -8264,8 +8264,8 @@ void A_JawzChase(mobj_t *actor) if (actor->tracer) { - if (G_RaceGametype()) // Stop looking after first target in race - actor->extravalue1 = 1; + /*if (G_RaceGametype()) // Stop looking after first target in race + actor->extravalue1 = 1;*/ if (actor->tracer->health) { diff --git a/src/p_map.c b/src/p_map.c index c307e5721..41e5a455d 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -752,9 +752,7 @@ static boolean PIT_CheckThing(mobj_t *thing) // Player Damage P_DamageMobj(thing, tmthing, tmthing->target, 1); K_KartBouncing(thing, tmthing, false, false); - - if (tmthing->type == MT_ORBINAUT || tmthing->type == MT_JAWZ || tmthing->type == MT_JAWZ_DUD) - S_StartSound(thing, sfx_s3k7b); + S_StartSound(thing, sfx_s3k7b); // This Item Damage if (tmthing->eflags & MFE_VERTICALFLIP) @@ -1035,9 +1033,7 @@ static boolean PIT_CheckThing(mobj_t *thing) // Player Damage P_DamageMobj(tmthing, thing, thing->target, 1); K_KartBouncing(tmthing, thing, false, false); - - if (thing->type == MT_ORBINAUT || thing->type == MT_JAWZ || thing->type == MT_JAWZ_DUD) - S_StartSound(tmthing, sfx_s3k7b); + S_StartSound(tmthing, sfx_s3k7b); // Other Item Damage if (thing->eflags & MFE_VERTICALFLIP) @@ -3231,129 +3227,6 @@ isblocking: return false; // stop } -// -// P_IsClimbingValid -// -// Unlike P_DoClimbing, don't use when up against a one-sided linedef. -// -static boolean P_IsClimbingValid(player_t *player, angle_t angle) -{ - fixed_t platx, platy; - subsector_t *glidesector; - fixed_t floorz, ceilingz; - - platx = P_ReturnThrustX(player->mo, angle, player->mo->radius + FixedMul(8*FRACUNIT, player->mo->scale)); - platy = P_ReturnThrustY(player->mo, angle, player->mo->radius + FixedMul(8*FRACUNIT, player->mo->scale)); - - glidesector = R_PointInSubsector(player->mo->x + platx, player->mo->y + platy); - -#ifdef ESLOPE - floorz = glidesector->sector->f_slope ? P_GetZAt(glidesector->sector->f_slope, player->mo->x, player->mo->y) : glidesector->sector->floorheight; - ceilingz = glidesector->sector->c_slope ? P_GetZAt(glidesector->sector->c_slope, player->mo->x, player->mo->y) : glidesector->sector->ceilingheight; -#else - floorz = glidesector->sector->floorheight; - ceilingz = glidesector->sector->ceilingheight; -#endif - - if (glidesector->sector != player->mo->subsector->sector) - { - boolean floorclimb = false; - fixed_t topheight, bottomheight; - - if (glidesector->sector->ffloors) - { - ffloor_t *rover; - for (rover = glidesector->sector->ffloors; rover; rover = rover->next) - { - if (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_BLOCKPLAYER)) - continue; - - 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 - - floorclimb = true; - - if (player->mo->eflags & MFE_VERTICALFLIP) - { - if ((topheight < player->mo->z + player->mo->height) && ((player->mo->z + player->mo->height + player->mo->momz) < topheight)) - { - floorclimb = true; - } - if (topheight < player->mo->z) // Waaaay below the ledge. - { - floorclimb = false; - } - if (bottomheight > player->mo->z + player->mo->height - FixedMul(16*FRACUNIT,player->mo->scale)) - { - floorclimb = false; - } - } - else - { - if ((bottomheight > player->mo->z) && ((player->mo->z - player->mo->momz) > bottomheight)) - { - floorclimb = true; - } - if (bottomheight > player->mo->z + player->mo->height) // Waaaay below the ledge. - { - floorclimb = false; - } - if (topheight < player->mo->z + FixedMul(16*FRACUNIT,player->mo->scale)) - { - floorclimb = false; - } - } - - if (floorclimb) - break; - } - } - - if (player->mo->eflags & MFE_VERTICALFLIP) - { - if ((floorz <= player->mo->z + player->mo->height) - && ((player->mo->z + player->mo->height - player->mo->momz) <= floorz)) - floorclimb = true; - - if ((floorz > player->mo->z) - && glidesector->sector->floorpic == skyflatnum) - return false; - - if ((player->mo->z + player->mo->height - FixedMul(16*FRACUNIT,player->mo->scale) > ceilingz) - || (player->mo->z + player->mo->height <= floorz)) - floorclimb = true; - } - else - { - if ((ceilingz >= player->mo->z) - && ((player->mo->z - player->mo->momz) >= ceilingz)) - floorclimb = true; - - if ((ceilingz < player->mo->z+player->mo->height) - && glidesector->sector->ceilingpic == skyflatnum) - return false; - - if ((player->mo->z + FixedMul(16*FRACUNIT,player->mo->scale) < ceilingz) - || (player->mo->z >= ceilingz)) - floorclimb = true; - } - - if (!floorclimb) - return false; - - return true; - } - - return false; -} - // // PTR_SlideTraverse // @@ -3407,117 +3280,7 @@ isblocking: P_ProcessSpecialSector(slidemo->player, slidemo->subsector->sector, li->polyobj->lines[0]->backsector); } - if (slidemo->player && (slidemo->player->pflags & PF_GLIDING || slidemo->player->climbing) - && slidemo->player->charability == CA_GLIDEANDCLIMB) - { - line_t *checkline = li; - sector_t *checksector; - ffloor_t *rover; - fixed_t topheight, bottomheight; - boolean fofline = false; - INT32 side = P_PointOnLineSide(slidemo->x, slidemo->y, li); - - if (!side && li->backsector) - checksector = li->backsector; - else - checksector = li->frontsector; - - if (checksector->ffloors) - { - for (rover = checksector->ffloors; rover; rover = rover->next) - { - if (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_BLOCKPLAYER) || (rover->flags & FF_BUSTUP)) - continue; - - topheight = *rover->topheight; - bottomheight = *rover->bottomheight; - -#ifdef ESLOPE - if (*rover->t_slope) - topheight = P_GetZAt(*rover->t_slope, slidemo->x, slidemo->y); - if (*rover->b_slope) - bottomheight = P_GetZAt(*rover->b_slope, slidemo->x, slidemo->y); -#endif - - if (topheight < slidemo->z) - continue; - - if (bottomheight > slidemo->z + slidemo->height) - continue; - - // Got this far, so I guess it's climbable. // TODO: Climbing check, also, better method to do this? - if (rover->master->flags & ML_TFERLINE) - { - size_t linenum = li-checksector->lines[0]; - checkline = rover->master->frontsector->lines[0] + linenum; - fofline = true; - } - - break; - } - } - - // see about climbing on the wall - if (!(checkline->flags & ML_NOCLIMB)) - { - boolean canclimb; - angle_t climbangle, climbline; - INT32 whichside = P_PointOnLineSide(slidemo->x, slidemo->y, li); - - climbangle = climbline = R_PointToAngle2(li->v1->x, li->v1->y, li->v2->x, li->v2->y); - - if (whichside) // on second side? - climbline += ANGLE_180; - - climbangle += (ANGLE_90 * (whichside ? -1 : 1)); - - canclimb = (li->backsector ? P_IsClimbingValid(slidemo->player, climbangle) : true); - - if (((!slidemo->player->climbing && abs((signed)(slidemo->angle - ANGLE_90 - climbline)) < ANGLE_45) - || (slidemo->player->climbing == 1 && abs((signed)(slidemo->angle - climbline)) < ANGLE_135)) - && canclimb) - { - slidemo->angle = climbangle; - if (!demoplayback || P_AnalogMove(slidemo->player)) - { - if (slidemo->player == &players[consoleplayer]) - localangle = slidemo->angle; - else if (slidemo->player == &players[secondarydisplayplayer]) - localangle2 = slidemo->angle; - else if (slidemo->player == &players[thirddisplayplayer]) - localangle3 = slidemo->angle; - else if (slidemo->player == &players[fourthdisplayplayer]) - localangle4 = slidemo->angle; - } - - if (!slidemo->player->climbing) - { - S_StartSound(slidemo->player->mo, sfx_s3k4a); - slidemo->player->climbing = 5; - } - - slidemo->player->pflags &= ~(PF_GLIDING|PF_SPINNING|PF_JUMPED|PF_THOKKED); - slidemo->player->glidetime = 0; - slidemo->player->secondjump = 0; - - if (slidemo->player->climbing > 1) - slidemo->momz = slidemo->momx = slidemo->momy = 0; - - if (fofline) - whichside = 0; - - if (!whichside) - { - slidemo->player->lastsidehit = checkline->sidenum[whichside]; - slidemo->player->lastlinehit = (INT16)(checkline - lines); - } - - P_Thrust(slidemo, slidemo->angle, FixedMul(5*FRACUNIT, slidemo->scale)); - } - } - } - - if (in->frac < bestslidefrac && (!slidemo->player || !slidemo->player->climbing)) + if (in->frac < bestslidefrac) { secondslidefrac = bestslidefrac; secondslideline = bestslideline; diff --git a/src/p_mobj.c b/src/p_mobj.c index a0ad0d716..3cf27604e 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -1354,7 +1354,7 @@ fixed_t P_GetMobjGravity(mobj_t *mo) if (wasflip == !(mo->eflags & MFE_VERTICALFLIP)) // note!! == ! is not equivalent to != here - turns numeric into bool this way P_PlayerFlip(mo); if (mo->player->kartstuff[k_pogospring]) - gravityadd = FixedMul(gravityadd, 5*FRACUNIT/2); + gravityadd = (5*gravityadd)/2; } else { @@ -1404,11 +1404,12 @@ fixed_t P_GetMobjGravity(mobj_t *mo) break; case MT_BANANA: case MT_EGGMANITEM: + case MT_ORBINAUT: + case MT_JAWZ: + case MT_JAWZ_DUD: case MT_SSMINE: - gravityadd = FixedMul(gravityadd, 5*FRACUNIT/2); - break; case MT_SINK: - gravityadd = FixedMul(gravityadd, 5*FRACUNIT); // Double gravity + gravityadd = (5*gravityadd)/2; break; case MT_SIGN: gravityadd /= 8; @@ -3233,8 +3234,7 @@ boolean P_CanRunOnWater(player_t *player, ffloor_t *rover) #endif *rover->topheight; - if (!(player->pflags & PF_NIGHTSMODE) && !player->homing - && (((player->charability == CA_SWIM) || player->powers[pw_super] || player->charflags & SF_RUNONWATER) && player->mo->ceilingz-topheight >= player->mo->height) + if (((player->charflags & SF_RUNONWATER) && 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 - topheight) < FixedMul(30*FRACUNIT, player->mo->scale)) diff --git a/src/p_setup.c b/src/p_setup.c index 3cc4b874b..9ea8f0344 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -235,7 +235,7 @@ static void P_ClearSingleMapHeaderInfo(INT16 i) DEH_WriteUndoline("LEVELFLAGS", va("%d", mapheaderinfo[num]->levelflags), UNDO_NONE); mapheaderinfo[num]->levelflags = 0; DEH_WriteUndoline("MENUFLAGS", va("%d", mapheaderinfo[num]->menuflags), UNDO_NONE); - mapheaderinfo[num]->menuflags = 0; + mapheaderinfo[num]->menuflags = (mainwads ? 0 : LF2_EXISTSHACK); // see p_setup.c - prevents replacing maps in addons with easier versions // TODO grades support for delfile (pfft yeah right) P_DeleteGrades(num); // SRB2Kart @@ -1121,7 +1121,7 @@ static inline void P_SpawnEmblems(void) static void P_SpawnSecretItems(boolean loademblems) { // Now let's spawn those funky emblem things! Tails 12-08-2002 - if (netgame || multiplayer || (modifiedgame && !savemoddata)) // No cheating!! + if (netgame || multiplayer || majormods) // No cheating!! return; if (loademblems) @@ -2858,6 +2858,9 @@ boolean P_SetupLevel(boolean skipprecip) lastwipetic = nowtime; if (moviemode) // make sure we save frames for the white hold too M_SaveFrame(); + + // Keep the network alive + NetKeepAlive(); } ranspecialwipe = 1; @@ -3284,7 +3287,7 @@ boolean P_SetupLevel(boolean skipprecip) nextmapoverride = 0; skipstats = false; - if (!(netgame || multiplayer) && (!modifiedgame || savemoddata)) + if (!(netgame || multiplayer) && !majormods) mapvisited[gamemap-1] |= MV_VISITED; levelloading = false; @@ -3467,6 +3470,14 @@ boolean P_AddWadFile(const char *wadfilename) continue; num = (INT16)M_MapNumber(name[3], name[4]); + // we want to record whether this map exists. if it doesn't have a header, we can assume it's not relephant + if (num <= NUMMAPS && mapheaderinfo[num-1]) + { + if (mapheaderinfo[num-1]->menuflags & LF2_EXISTSHACK) + G_SetGameModified(multiplayer, true); // oops, double-defined - no record attack privileges for you + mapheaderinfo[num-1]->menuflags |= LF2_EXISTSHACK; + } + //If you replaced the map you're on, end the level when done. if (num == gamemap) replacedcurrentmap = true; @@ -3493,6 +3504,8 @@ boolean P_AddWadFile(const char *wadfilename) SendNetXCmd(XD_EXITLEVEL, NULL, 0); } + refreshdirmenu &= ~REFRESHDIR_GAMEDATA; // Under usual circumstances we'd wait for REFRESHDIR_GAMEDATA to disappear the next frame, but it's a bit too dangerous for that... + return true; } diff --git a/src/p_spec.c b/src/p_spec.c index 8a6241ba1..4077ea692 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -1758,12 +1758,12 @@ boolean P_RunTriggerLinedef(line_t *triggerline, mobj_t *actor, sector_t *caller switch (specialtype) { - case 305: // continuous + /*case 305: // continuous case 306: // each time case 307: // once if (!(actor && actor->player && actor->player->charability == dist/10)) return false; - break; + break;*/ case 309: // continuous case 310: // each time // Only red team members can activate this. @@ -3864,14 +3864,6 @@ DoneSection2: P_InstaThrust(player->mo, player->mo->angle, linespeed); - /*if (GETSECSPECIAL(sector->special, 3) == 6 && (player->charability2 == CA2_SPINDASH)) // SRB2kart - { - if (!(player->pflags & PF_SPINNING)) - player->pflags |= PF_SPINNING; - - //P_SetPlayerMobjState(player->mo, S_PLAY_ATK1); - }*/ - player->kartstuff[k_dashpadcooldown] = TICRATE/3; player->kartstuff[k_drift] = 0; player->kartstuff[k_driftcharge] = 0; @@ -5781,7 +5773,7 @@ void P_SpawnSpecials(INT32 fromnetsave) lines[i].special = 0; continue; } - /*else -- commented out because irrelevant to kart + /*else -- commented out because irrelevant to kart. keeping here because we can use these flags for something else now { if ((players[consoleplayer].charability == CA_THOK && (lines[i].flags & ML_NOSONIC)) || (players[consoleplayer].charability == CA_FLY && (lines[i].flags & ML_NOTAILS)) @@ -7999,12 +7991,13 @@ static void P_SearchForDisableLinedefs(void) } else if ((lines[i].flags & ML_NETONLY) == ML_NETONLY) continue; // Net-only never triggers in single player - else if (players[consoleplayer].charability == CA_THOK && (lines[i].flags & ML_NOSONIC)) + // commented out because irrelevant to kart. keeping here because we can use these flags for something else now + /*else if (players[consoleplayer].charability == CA_THOK && (lines[i].flags & ML_NOSONIC)) continue; else if (players[consoleplayer].charability == CA_FLY && (lines[i].flags & ML_NOTAILS)) continue; else if (players[consoleplayer].charability == CA_GLIDEANDCLIMB && (lines[i].flags & ML_NOKNUX)) - continue; + continue;*/ // Disable any linedef specials with our tag. for (j = -1; (j = P_FindLineFromLineTag(&lines[i], j)) >= 0;) diff --git a/src/p_user.c b/src/p_user.c index d7423d803..76f57a9ba 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -7323,74 +7323,6 @@ static void P_MovePlayer(player_t *player) if (CheckForBustableBlocks) P_CheckBustableBlocks(player); - // Special handling for - // gliding in 2D mode - if ((twodlevel || player->mo->flags2 & MF2_TWOD) && player->pflags & PF_GLIDING && player->charability == CA_GLIDEANDCLIMB - && !(player->mo->flags & MF_NOCLIP)) - { - msecnode_t *node; // only place it's being used in P_MovePlayer now - fixed_t oldx; - fixed_t oldy; - fixed_t floorz, ceilingz; - - oldx = player->mo->x; - oldy = player->mo->y; - - P_UnsetThingPosition(player->mo); - player->mo->x += player->mo->momx; - player->mo->y += player->mo->momy; - P_SetThingPosition(player->mo); - - for (node = player->mo->touching_sectorlist; node; node = node->m_sectorlist_next) - { - if (!node->m_sector) - break; - - if (node->m_sector->ffloors) - { - ffloor_t *rover; - fixed_t topheight, bottomheight; - - for (rover = node->m_sector->ffloors; rover; rover = rover->next) - { - if (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_BLOCKPLAYER)) - continue; - - topheight = P_GetFOFTopZ(player->mo, node->m_sector, rover, player->mo->x, player->mo->y, NULL); - bottomheight = P_GetFOFBottomZ(player->mo, node->m_sector, rover, player->mo->x, player->mo->y, NULL); - if (topheight > player->mo->z && bottomheight < player->mo->z) - { - P_ResetPlayer(player); - S_StartSound(player->mo, sfx_s3k4a); - player->climbing = 5; - player->mo->momx = player->mo->momy = player->mo->momz = 0; - break; - } - } - } - - floorz = P_GetFloorZ(player->mo, node->m_sector, player->mo->x, player->mo->y, NULL); - ceilingz = P_GetCeilingZ(player->mo, node->m_sector, player->mo->x, player->mo->y, NULL); - - if (player->mo->z+player->mo->height > ceilingz - && node->m_sector->ceilingpic == skyflatnum) - continue; - - if (floorz > player->mo->z || ceilingz < player->mo->z) - { - P_ResetPlayer(player); - S_StartSound(player->mo, sfx_s3k4a); - player->climbing = 5; - player->mo->momx = player->mo->momy = player->mo->momz = 0; - break; - } - } - P_UnsetThingPosition(player->mo); - player->mo->x = oldx; - player->mo->y = oldy; - P_SetThingPosition(player->mo); - } - // Check for a BOUNCY sector! if (CheckForBouncySector) P_CheckBouncySectors(player); @@ -8165,6 +8097,8 @@ void P_ResetCamera(player_t *player, camera_t *thiscam) boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcalled) { + static UINT8 lookbackdelay[4] = {0,0,0,0}; + UINT8 num; angle_t angle = 0, focusangle = 0, focusaiming = 0; fixed_t x, y, z, dist, height, viewpointx, viewpointy, camspeed, camdist, camheight, pviewheight; fixed_t pan, xpan, ypan; @@ -8293,6 +8227,7 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall if (thiscam == &camera) { + num = 0; camspeed = cv_cam_speed.value; camstill = cv_cam_still.value; camrotate = cv_cam_rotate.value; @@ -8302,6 +8237,7 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall } else if (thiscam == &camera2) // Camera 2 { + num = 1; camspeed = cv_cam2_speed.value; camstill = cv_cam2_still.value; camrotate = cv_cam2_rotate.value; @@ -8311,6 +8247,7 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall } else if (thiscam == &camera3) // Camera 3 { + num = 2; camspeed = cv_cam3_speed.value; camstill = cv_cam3_still.value; camrotate = cv_cam3_rotate.value; @@ -8320,6 +8257,7 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall } else // Camera 4 { + num = 3; camspeed = cv_cam4_speed.value; camstill = cv_cam4_still.value; camrotate = cv_cam4_rotate.value; @@ -8342,12 +8280,16 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall } else if (player->exiting) // SRB2Kart: Leave the camera behind while exiting, for dramatic effect! camstill = true; - else if (lookback) // SRB2kart - Camera flipper + else if (lookback || lookbackdelay[num]) // SRB2kart - Camera flipper { - camrotate += 180; - camspeed *= 2; - if (camspeed > FRACUNIT) - camspeed = FRACUNIT; + camspeed = FRACUNIT; + if (lookback) + { + camrotate += 180; + lookbackdelay[num] = 2; + } + else + lookbackdelay[num]--; } if (mo->eflags & MFE_VERTICALFLIP) @@ -8356,6 +8298,9 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall if (splitscreen == 1) camspeed = (3*camspeed)/4; + if (camspeed > FRACUNIT) + camspeed = FRACUNIT; + if (timeover) angle = mo->angle + FixedAngle(camrotate*FRACUNIT); else if (leveltime < starttime) @@ -8364,16 +8309,21 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall angle = thiscam->angle; else { - angle_t input = focusangle + FixedAngle(camrotate<angle; - boolean invert = (input > ANGLE_180); - if (invert) - input = InvAngle(input); + if (camspeed == FRACUNIT) + angle = focusangle + FixedAngle(camrotate<angle; + boolean invert = (input > ANGLE_180); + if (invert) + input = InvAngle(input); - input = FixedAngle(FixedMul(AngleFixed(input), camspeed)); - if (invert) - input = InvAngle(input); + input = FixedAngle(FixedMul(AngleFixed(input), camspeed)); + if (invert) + input = InvAngle(input); - angle = thiscam->angle + input; + angle = thiscam->angle + input; + } } if (!resetcalled && (leveltime > starttime && timeover != 2) @@ -8697,8 +8647,25 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall if (twodlevel || (mo->flags2 & MF2_TWOD) || (!camstill && !timeover)) // Keep the view still... { G_ClipAimingPitch((INT32 *)&angle); - dist = thiscam->aiming - angle; - thiscam->aiming -= (dist>>3); + + if (camspeed == FRACUNIT) + thiscam->aiming = angle; + else + { + angle_t input; + boolean invert; + + input = thiscam->aiming - angle; + invert = (input > ANGLE_180); + if (invert) + input = InvAngle(input); + + input = FixedAngle(FixedMul(AngleFixed(input), (5*camspeed)/16)); + if (invert) + input = InvAngle(input); + + thiscam->aiming -= input; + } } if (!resetcalled && (player->playerstate == PST_DEAD || player->playerstate == PST_REBORN)) @@ -8763,6 +8730,7 @@ boolean P_SpectatorJoinGame(player_t *player) } player->spectator = false; player->pflags &= ~PF_WANTSTOJOIN; + player->kartstuff[k_spectatewait] = 0; player->ctfteam = changeto; player->playerstate = PST_REBORN; @@ -8787,6 +8755,7 @@ boolean P_SpectatorJoinGame(player_t *player) } player->spectator = false; player->pflags &= ~PF_WANTSTOJOIN; + player->kartstuff[k_spectatewait] = 0; player->playerstate = PST_REBORN; //Reset away view @@ -9876,4 +9845,3 @@ void P_PlayerAfterThink(player_t *player) K_KartPlayerAfterThink(player); } - diff --git a/src/r_things.c b/src/r_things.c index d6234d4b3..135ae6a29 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -2635,7 +2635,7 @@ INT32 R_SkinAvailable(const char *name) } // network code calls this when a 'skin change' is received -void SetPlayerSkin(INT32 playernum, const char *skinname) +boolean SetPlayerSkin(INT32 playernum, const char *skinname) { INT32 i; player_t *player = &players[playernum]; @@ -2646,7 +2646,7 @@ void SetPlayerSkin(INT32 playernum, const char *skinname) if (stricmp(skins[i].name, skinname) == 0) { SetPlayerSkinByNum(playernum, i); - return; + return true; } } @@ -2656,6 +2656,7 @@ void SetPlayerSkin(INT32 playernum, const char *skinname) CONS_Alert(CONS_WARNING, M_GetText("Player %d (%s) skin '%s' not found\n"), playernum, player_names[playernum], skinname); SetPlayerSkinByNum(playernum, 0); + return false; } // Same as SetPlayerSkin, but uses the skin #. @@ -2894,27 +2895,27 @@ void R_AddSkins(UINT16 wadnum) #define FULLPROCESS(field) else if (!stricmp(stoken, #field)) skin->field = get_number(value); // character type identification FULLPROCESS(flags) - FULLPROCESS(ability) - FULLPROCESS(ability2) + //FULLPROCESS(ability) + //FULLPROCESS(ability2) - FULLPROCESS(thokitem) - FULLPROCESS(spinitem) - FULLPROCESS(revitem) + //FULLPROCESS(thokitem) + //FULLPROCESS(spinitem) + //FULLPROCESS(revitem) #undef FULLPROCESS #define GETSPEED(field) else if (!stricmp(stoken, #field)) skin->field = atoi(value)<field = atoi(value); +/*#define GETINT(field) else if (!stricmp(stoken, #field)) skin->field = atoi(value); GETINT(thrustfactor) GETINT(accelstart) GETINT(acceleration) -#undef GETINT +#undef GETINT*/ #define GETKARTSTAT(field) \ else if (!stricmp(stoken, #field)) \ @@ -2933,8 +2934,8 @@ void R_AddSkins(UINT16 wadnum) else if (!stricmp(stoken, "prefcolor")) skin->prefcolor = K_GetKartColorByName(value); - else if (!stricmp(stoken, "jumpfactor")) - skin->jumpfactor = FLOAT_TO_FIXED(atof(value)); + //else if (!stricmp(stoken, "jumpfactor")) + //skin->jumpfactor = FLOAT_TO_FIXED(atof(value)); else if (!stricmp(stoken, "highresscale")) skin->highresscale = FLOAT_TO_FIXED(atof(value)); else @@ -3044,6 +3045,9 @@ next_token: HWR_AddPlayerMD2(numskins); #endif + if (skin->flags & SF_RUNONWATER) // this is literally the only way a skin can be a major mod... this might be a bit heavy handed + G_SetGameModified(multiplayer, true); + numskins++; } return; diff --git a/src/r_things.h b/src/r_things.h index 53784415f..01d8fc071 100644 --- a/src/r_things.h +++ b/src/r_things.h @@ -194,7 +194,7 @@ typedef struct drawnode_s extern INT32 numskins; extern skin_t skins[MAXSKINS]; -void SetPlayerSkin(INT32 playernum,const char *skinname); +boolean SetPlayerSkin(INT32 playernum,const char *skinname); void SetPlayerSkinByNum(INT32 playernum,INT32 skinnum); // Tails 03-16-2002 INT32 R_SkinAvailable(const char *name); void R_AddSkins(UINT16 wadnum); diff --git a/src/sdl/CMakeLists.txt b/src/sdl/CMakeLists.txt index ec5d63ac7..de2157055 100644 --- a/src/sdl/CMakeLists.txt +++ b/src/sdl/CMakeLists.txt @@ -70,6 +70,8 @@ if(${SDL2_FOUND}) set(SRB2_SDL2_TOTAL_SOURCES ${SRB2_CORE_SOURCES} ${SRB2_CORE_HEADERS} + ${SRB2_PNG_SOURCES} + ${SRB2_PNG_HEADERS} ${SRB2_CORE_RENDER_SOURCES} ${SRB2_CORE_GAME_SOURCES} ${SRB2_LUA_SOURCES} @@ -80,7 +82,8 @@ if(${SDL2_FOUND}) ${SRB2_SDL2_HEADERS} ) - source_group("Main" FILES ${SRB2_CORE_SOURCES} ${SRB2_CORE_HEADERS}) + source_group("Main" FILES ${SRB2_CORE_SOURCES} ${SRB2_CORE_HEADERS} + ${SRB2_PNG_SOURCES} ${SRB2_PNG_HEADERS}) source_group("Renderer" FILES ${SRB2_CORE_RENDER_SOURCES}) source_group("Game" FILES ${SRB2_CORE_GAME_SOURCES}) source_group("Assembly" FILES ${SRB2_ASM_SOURCES} ${SRB2_NASM_SOURCES}) diff --git a/src/sdl/Srb2SDL-vc10.vcxproj b/src/sdl/Srb2SDL-vc10.vcxproj index bd964259b..d2466bd5b 100644 --- a/src/sdl/Srb2SDL-vc10.vcxproj +++ b/src/sdl/Srb2SDL-vc10.vcxproj @@ -164,6 +164,7 @@ + @@ -317,6 +318,7 @@ + diff --git a/src/sdl/Srb2SDL-vc10.vcxproj.filters b/src/sdl/Srb2SDL-vc10.vcxproj.filters index 09287436d..daa13189f 100644 --- a/src/sdl/Srb2SDL-vc10.vcxproj.filters +++ b/src/sdl/Srb2SDL-vc10.vcxproj.filters @@ -294,6 +294,9 @@ LUA + + M_Misc + M_Misc diff --git a/src/sdl/Srb2SDL-vc9.vcproj b/src/sdl/Srb2SDL-vc9.vcproj index d2a268f8d..3898aeba4 100644 --- a/src/sdl/Srb2SDL-vc9.vcproj +++ b/src/sdl/Srb2SDL-vc9.vcproj @@ -2834,6 +2834,50 @@ RelativePath="..\m_argv.h" > + + + + + + + + + + + + + + + + diff --git a/src/sdl/i_system.c b/src/sdl/i_system.c index 2154a070b..f360072a0 100644 --- a/src/sdl/i_system.c +++ b/src/sdl/i_system.c @@ -3018,7 +3018,7 @@ void I_StartupTimer(void) void I_Sleep(void) { - if (cv_sleep.value != -1) + if (cv_sleep.value > 0) SDL_Delay(cv_sleep.value); } diff --git a/src/sdl/i_video.c b/src/sdl/i_video.c index f63e98476..2a77604d2 100644 --- a/src/sdl/i_video.c +++ b/src/sdl/i_video.c @@ -1229,7 +1229,7 @@ void I_GetEvent(void) // update the menu if (currentMenu == &OP_JoystickSetDef) M_SetupJoystickMenu(0); - break; + break; case SDL_QUIT: I_Quit(); M_QuitResponse('y'); diff --git a/src/sdl/macosx/Srb2mac.xcodeproj/project.pbxproj b/src/sdl/macosx/Srb2mac.xcodeproj/project.pbxproj index 94a3fbb63..a8ecbf7f8 100644 --- a/src/sdl/macosx/Srb2mac.xcodeproj/project.pbxproj +++ b/src/sdl/macosx/Srb2mac.xcodeproj/project.pbxproj @@ -43,6 +43,7 @@ 1E44AF0D0B67CDE900BAD059 /* m_fixed.c in Sources */ = {isa = PBXBuildFile; fileRef = 1E44AEFE0B67CDE900BAD059 /* m_fixed.c */; }; 1E44AF0F0B67CDE900BAD059 /* m_menu.c in Sources */ = {isa = PBXBuildFile; fileRef = 1E44AF000B67CDE900BAD059 /* m_menu.c */; }; 1E44AF110B67CDE900BAD059 /* m_misc.c in Sources */ = {isa = PBXBuildFile; fileRef = 1E44AF020B67CDE900BAD059 /* m_misc.c */; }; + 1E44AF110B67CDE900BAD059 /* apng.c in Sources */ = {isa = PBXBuildFile; fileRef = 1E44AF020B67CDE900BAD059 /* apng.c */; }; 1E44AF130B67CDE900BAD059 /* m_random.c in Sources */ = {isa = PBXBuildFile; fileRef = 1E44AF040B67CDE900BAD059 /* m_random.c */; }; 1E44AF1A0B67CE2A00BAD059 /* info.c in Sources */ = {isa = PBXBuildFile; fileRef = 1E44AF180B67CE2A00BAD059 /* info.c */; }; 1E44AF1E0B67CE3600BAD059 /* md5.c in Sources */ = {isa = PBXBuildFile; fileRef = 1E44AF1C0B67CE3600BAD059 /* md5.c */; }; @@ -253,7 +254,9 @@ 1E44AF000B67CDE900BAD059 /* m_menu.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = m_menu.c; path = ../../m_menu.c; sourceTree = SOURCE_ROOT; }; 1E44AF010B67CDE900BAD059 /* m_menu.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = m_menu.h; path = ../../m_menu.h; sourceTree = SOURCE_ROOT; }; 1E44AF020B67CDE900BAD059 /* m_misc.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = m_misc.c; path = ../../m_misc.c; sourceTree = SOURCE_ROOT; }; + 1E44AF020B67CDE900BAD059 /* apng.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = apng.c; path = ../../m_misc.c; sourceTree = SOURCE_ROOT; }; 1E44AF030B67CDE900BAD059 /* m_misc.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = m_misc.h; path = ../../m_misc.h; sourceTree = SOURCE_ROOT; }; + 1E44AF020B67CDE900BAD059 /* apng.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = apng.h; path = ../../m_misc.c; sourceTree = SOURCE_ROOT; }; 1E44AF040B67CDE900BAD059 /* m_random.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = m_random.c; path = ../../m_random.c; sourceTree = SOURCE_ROOT; }; 1E44AF050B67CDE900BAD059 /* m_random.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = m_random.h; path = ../../m_random.h; sourceTree = SOURCE_ROOT; }; 1E44AF060B67CDE900BAD059 /* m_swap.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = m_swap.h; path = ../../m_swap.h; sourceTree = SOURCE_ROOT; }; @@ -679,6 +682,8 @@ 1E44AEFF0B67CDE900BAD059 /* m_fixed.h */, 1E44AF020B67CDE900BAD059 /* m_misc.c */, 1E44AF030B67CDE900BAD059 /* m_misc.h */, + 1E44AF020B67CDE900BAD059 /* apng.c */, + 1E44AF030B67CDE900BAD059 /* apng.h */, 676BB51C0E0DE06100C95963 /* m_queue.c */, 676BB51D0E0DE06100C95963 /* m_queue.h */, 1E44AF040B67CDE900BAD059 /* m_random.c */, diff --git a/src/sdl12/Srb2SDL-vc10.vcxproj b/src/sdl12/Srb2SDL-vc10.vcxproj index 958cd7d02..99916f58d 100644 --- a/src/sdl12/Srb2SDL-vc10.vcxproj +++ b/src/sdl12/Srb2SDL-vc10.vcxproj @@ -835,6 +835,16 @@ %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) @@ -1293,6 +1303,7 @@ + diff --git a/src/sdl12/Srb2SDL-vc9.vcproj b/src/sdl12/Srb2SDL-vc9.vcproj index d2a268f8d..fa386e381 100644 --- a/src/sdl12/Srb2SDL-vc9.vcproj +++ b/src/sdl12/Srb2SDL-vc9.vcproj @@ -2790,6 +2790,50 @@ + + + + + + + + + + + + + + + + diff --git a/src/sdl12/i_system.c b/src/sdl12/i_system.c index 0e5adbb40..d055a4ca5 100644 --- a/src/sdl12/i_system.c +++ b/src/sdl12/i_system.c @@ -2914,7 +2914,7 @@ void I_StartupTimer(void) void I_Sleep(void) { #if !(defined (_arch_dreamcast) || defined (_XBOX)) - if (cv_sleep.value != -1) + if (cv_sleep.value > 0) SDL_Delay(cv_sleep.value); #endif } diff --git a/src/sdl12/macosx/Srb2mac.pbproj/project.pbxproj b/src/sdl12/macosx/Srb2mac.pbproj/project.pbxproj index de12201f5..1f8e3276a 100644 --- a/src/sdl12/macosx/Srb2mac.pbproj/project.pbxproj +++ b/src/sdl12/macosx/Srb2mac.pbproj/project.pbxproj @@ -1365,6 +1365,20 @@ path = ../../m_misc.h; refType = 2; }; + 84177764085A10EB000C01D8 = { + fileEncoding = 30; + isa = PBXFileReference; + name = apng.c; + path = ../../apng.c; + refType = 2; + }; + 84177765085A10EB000C01D8 = { + fileEncoding = 30; + isa = PBXFileReference; + name = m_misc.h; + path = ../../apng.h; + refType = 2; + }; 84177766085A10EB000C01D8 = { fileEncoding = 30; isa = PBXFileReference; diff --git a/src/sdl12/macosx/Srb2mac.xcodeproj/project.pbxproj b/src/sdl12/macosx/Srb2mac.xcodeproj/project.pbxproj index 0ab40c45e..69c544c56 100644 --- a/src/sdl12/macosx/Srb2mac.xcodeproj/project.pbxproj +++ b/src/sdl12/macosx/Srb2mac.xcodeproj/project.pbxproj @@ -43,6 +43,7 @@ 1E44AF0D0B67CDE900BAD059 /* m_fixed.c in Sources */ = {isa = PBXBuildFile; fileRef = 1E44AEFE0B67CDE900BAD059 /* m_fixed.c */; }; 1E44AF0F0B67CDE900BAD059 /* m_menu.c in Sources */ = {isa = PBXBuildFile; fileRef = 1E44AF000B67CDE900BAD059 /* m_menu.c */; }; 1E44AF110B67CDE900BAD059 /* m_misc.c in Sources */ = {isa = PBXBuildFile; fileRef = 1E44AF020B67CDE900BAD059 /* m_misc.c */; }; + 1E44AF110B67CDE900BAD059 /* apng.c in Sources */ = {isa = PBXBuildFile; fileRef = 1E44AF020B67CDE900BAD059 /* apng.c */; }; 1E44AF130B67CDE900BAD059 /* m_random.c in Sources */ = {isa = PBXBuildFile; fileRef = 1E44AF040B67CDE900BAD059 /* m_random.c */; }; 1E44AF1A0B67CE2A00BAD059 /* info.c in Sources */ = {isa = PBXBuildFile; fileRef = 1E44AF180B67CE2A00BAD059 /* info.c */; }; 1E44AF1E0B67CE3600BAD059 /* md5.c in Sources */ = {isa = PBXBuildFile; fileRef = 1E44AF1C0B67CE3600BAD059 /* md5.c */; }; @@ -254,6 +255,8 @@ 1E44AF010B67CDE900BAD059 /* m_menu.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = m_menu.h; path = ../../m_menu.h; sourceTree = SOURCE_ROOT; }; 1E44AF020B67CDE900BAD059 /* m_misc.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = m_misc.c; path = ../../m_misc.c; sourceTree = SOURCE_ROOT; }; 1E44AF030B67CDE900BAD059 /* m_misc.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = m_misc.h; path = ../../m_misc.h; sourceTree = SOURCE_ROOT; }; + 1E44AF020B67CDE900BAD059 /* apng.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = apng.c; path = ../../m_misc.c; sourceTree = SOURCE_ROOT; }; + 1E44AF030B67CDE900BAD059 /* apng.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = apng.h; path = ../../m_misc.h; sourceTree = SOURCE_ROOT; }; 1E44AF040B67CDE900BAD059 /* m_random.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = m_random.c; path = ../../m_random.c; sourceTree = SOURCE_ROOT; }; 1E44AF050B67CDE900BAD059 /* m_random.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = m_random.h; path = ../../m_random.h; sourceTree = SOURCE_ROOT; }; 1E44AF060B67CDE900BAD059 /* m_swap.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = m_swap.h; path = ../../m_swap.h; sourceTree = SOURCE_ROOT; }; @@ -679,6 +682,8 @@ 1E44AEFF0B67CDE900BAD059 /* m_fixed.h */, 1E44AF020B67CDE900BAD059 /* m_misc.c */, 1E44AF030B67CDE900BAD059 /* m_misc.h */, + 1E44AF020B67CDE900BAD059 /* apng.c */, + 1E44AF030B67CDE900BAD059 /* apng.h */, 676BB51C0E0DE06100C95963 /* m_queue.c */, 676BB51D0E0DE06100C95963 /* m_queue.h */, 1E44AF040B67CDE900BAD059 /* m_random.c */, diff --git a/src/st_stuff.c b/src/st_stuff.c index 8ebd21321..36a658aec 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -1952,31 +1952,38 @@ static void ST_overlayDrawer(void) #endif ) { + const char *itemtxt = M_GetText("Item - Join Game"); + + if (stplyr->powers[pw_flashing]) + itemtxt = M_GetText("Item - . . ."); + else if (stplyr->pflags & PF_WANTSTOJOIN) + itemtxt = M_GetText("Item - Cancel Join"); + else if (G_GametypeHasTeams()) + itemtxt = M_GetText("Item - Join Team"); + + if (cv_ingamecap.value) + { + UINT8 numingame = 0; + UINT8 i; + + for (i = 0; i < MAXPLAYERS; i++) + if (playeringame[i] && !players[i].spectator) + numingame++; + + itemtxt = va("%s (%s: %d)", itemtxt, M_GetText("Slots left"), max(0, cv_ingamecap.value - numingame)); + } + // SRB2kart: changed positions & text if (splitscreen) { INT32 splitflags = K_calcSplitFlags(0); V_DrawThinString(2, (BASEVIDHEIGHT/2)-20, V_YELLOWMAP|V_HUDTRANSHALF|splitflags, M_GetText("- SPECTATING -")); - if (stplyr->powers[pw_flashing]) - V_DrawThinString(2, (BASEVIDHEIGHT/2)-10, V_HUDTRANSHALF|splitflags, M_GetText("Item - . . .")); - else if (stplyr->pflags & PF_WANTSTOJOIN) - V_DrawThinString(2, (BASEVIDHEIGHT/2)-10, V_HUDTRANSHALF|splitflags, M_GetText("Item - Cancel Join")); - /*else if (G_GametypeHasTeams()) - V_DrawThinString(2, (BASEVIDHEIGHT/2)-10, V_HUDTRANSHALF|splitflags, M_GetText("Item - Join Team"));*/ - else - V_DrawThinString(2, (BASEVIDHEIGHT/2)-10, V_HUDTRANSHALF|splitflags, M_GetText("Item - Join Game")); + V_DrawThinString(2, (BASEVIDHEIGHT/2)-10, V_HUDTRANSHALF|splitflags, itemtxt); } else { V_DrawString(2, BASEVIDHEIGHT-40, V_HUDTRANSHALF|V_YELLOWMAP, M_GetText("- SPECTATING -")); - if (stplyr->powers[pw_flashing]) - V_DrawString(2, BASEVIDHEIGHT-30, V_HUDTRANSHALF, M_GetText("Item - . . .")); - else if (stplyr->pflags & PF_WANTSTOJOIN) - V_DrawString(2, BASEVIDHEIGHT-30, V_HUDTRANSHALF, M_GetText("Item - Cancel Join")); - /*else if (G_GametypeHasTeams()) - V_DrawString(2, BASEVIDHEIGHT-30, V_HUDTRANSHALF, M_GetText("Item - Join Team"));*/ - else - V_DrawString(2, BASEVIDHEIGHT-30, V_HUDTRANSHALF, M_GetText("Item - Join Game")); + V_DrawString(2, BASEVIDHEIGHT-30, V_HUDTRANSHALF, itemtxt); V_DrawString(2, BASEVIDHEIGHT-20, V_HUDTRANSHALF, M_GetText("Accelerate - Float")); V_DrawString(2, BASEVIDHEIGHT-10, V_HUDTRANSHALF, M_GetText("Brake - Sink")); } diff --git a/src/v_video.c b/src/v_video.c index dd95efe3d..115e081e0 100644 --- a/src/v_video.c +++ b/src/v_video.c @@ -2305,7 +2305,7 @@ INT32 V_ThinStringWidth(const char *string, INT32 option) } } - + return w; } diff --git a/src/w_wad.c b/src/w_wad.c index 63bee97de..29e1ba223 100644 --- a/src/w_wad.c +++ b/src/w_wad.c @@ -34,6 +34,7 @@ #include "z_zone.h" #include "fastcmp.h" +#include "g_game.h" // G_LoadGameData #include "filesrch.h" #include "i_video.h" // rendermode @@ -190,8 +191,10 @@ static inline void W_LoadDehackedLumpsPK3(UINT16 wadnum) { posEnd = W_CheckNumForFolderEndPK3("Lua/", wadnum, posStart); posStart++; +#ifdef HAVE_BLUA for (; posStart < posEnd; posStart++) LUA_LoadLump(wadnum, posStart); +#endif } posStart = W_CheckNumForFolderStartPK3("SOC/", wadnum, 0); if (posStart != INT16_MAX) @@ -793,12 +796,18 @@ UINT16 W_InitFile(const char *filename) DEH_LoadDehackedLumpPwad(numwadfiles - 1, 0); break; case RET_LUA: +#ifdef HAVE_BLUA LUA_LoadLump(numwadfiles - 1, 0); +#endif break; default: break; } + if (refreshdirmenu & REFRESHDIR_GAMEDATA) + G_LoadGameData(); + DEH_UpdateMaxFreeslots(); + W_InvalidateLumpnumCache(); return wadfile->numlumps; } diff --git a/src/win32/Srb2win-vc10.vcxproj b/src/win32/Srb2win-vc10.vcxproj index ca73b1293..774ce5cbe 100644 --- a/src/win32/Srb2win-vc10.vcxproj +++ b/src/win32/Srb2win-vc10.vcxproj @@ -182,6 +182,7 @@ + @@ -330,6 +331,7 @@ + diff --git a/src/win32/Srb2win-vc9.vcproj b/src/win32/Srb2win-vc9.vcproj index 24235bc7b..a64b8638c 100644 --- a/src/win32/Srb2win-vc9.vcproj +++ b/src/win32/Srb2win-vc9.vcproj @@ -2851,6 +2851,50 @@ RelativePath="..\m_misc.h" > + + + + + + + + + + + + + + + + diff --git a/src/win32/win_sys.c b/src/win32/win_sys.c index 75aca68df..fa9d6d644 100644 --- a/src/win32/win_sys.c +++ b/src/win32/win_sys.c @@ -261,7 +261,7 @@ tic_t I_GetTime(void) void I_Sleep(void) { - if (cv_sleep.value != -1) + if (cv_sleep.value > 0) Sleep(cv_sleep.value); } diff --git a/src/win32ce/win_sys.c b/src/win32ce/win_sys.c index 3b6a47258..091171b52 100644 --- a/src/win32ce/win_sys.c +++ b/src/win32ce/win_sys.c @@ -265,7 +265,7 @@ tic_t I_GetTime(void) void I_Sleep(void) { - if (cv_sleep.value != -1) + if (cv_sleep.value > 0) Sleep(cv_sleep.value); } diff --git a/src/y_inter.c b/src/y_inter.c index 021519e3b..095b4ad36 100644 --- a/src/y_inter.c +++ b/src/y_inter.c @@ -432,7 +432,7 @@ void Y_IntermissionDrawer(void) if (data.match.encore) V_DrawCenteredString(-4 + x + BASEVIDWIDTH/2, 12-8, hilicol, "ENCORE MODE"); - if (!gutter) + if (data.match.numplayers > NUMFORNEWCOLUMN) { V_DrawFill(x+156, 24, 1, 158, 0); V_DrawFill((x-3) - duptweak, 182, dupadjust-2, 1, 0); @@ -474,16 +474,12 @@ void Y_IntermissionDrawer(void) V_DrawScaledPatch(x+16, y-4, 0, W_CachePatchName(va("K_CHILI%d", cursorframe+1), PU_CACHE)); } - if (!gutter) - strlcpy(strtime, data.match.name[i], 6); - else - STRBUFCPY(strtime, data.match.name[i]); + STRBUFCPY(strtime, data.match.name[i]); - V_DrawString(x+36, y, - ((data.match.num[i] == whiteplayer) - ? hilicol|V_ALLOWLOWERCASE - : V_ALLOWLOWERCASE), - strtime); + if (data.match.numplayers > NUMFORNEWCOLUMN) + V_DrawThinString(x+36, y-1, ((data.match.num[i] == whiteplayer) ? hilicol : 0)|V_ALLOWLOWERCASE|V_6WIDTHSPACE, strtime); + else + V_DrawString(x+36, y, ((data.match.num[i] == whiteplayer) ? hilicol : 0)|V_ALLOWLOWERCASE, strtime); if (data.match.rankingsmode) { @@ -494,17 +490,23 @@ void Y_IntermissionDrawer(void) else snprintf(strtime, sizeof strtime, "(+ %d)", data.match.increase[data.match.num[i]]); - V_DrawRightAlignedString(x+120+gutter, y, 0, strtime); + if (data.match.numplayers > NUMFORNEWCOLUMN) + V_DrawRightAlignedThinString(x+135+gutter, y-1, V_6WIDTHSPACE, strtime); + else + V_DrawRightAlignedString(x+120+gutter, y, 0, strtime); } snprintf(strtime, sizeof strtime, "%d", data.match.val[i]); - V_DrawRightAlignedString(x+152+gutter, y, 0, strtime); + if (data.match.numplayers > NUMFORNEWCOLUMN) + V_DrawRightAlignedThinString(x+152+gutter, y-1, V_6WIDTHSPACE, strtime); + else + V_DrawRightAlignedString(x+152+gutter, y, 0, strtime); } else { if (data.match.val[i] == (UINT32_MAX-1)) - V_DrawRightAlignedThinString(x+152+gutter, y-1, 0, "NO CONTEST."); + V_DrawRightAlignedThinString(x+152+gutter, y-1, (data.match.numplayers > NUMFORNEWCOLUMN ? V_6WIDTHSPACE : 0), "NO CONTEST."); else { if (intertype == int_race) @@ -513,10 +515,18 @@ void Y_IntermissionDrawer(void) G_TicsToSeconds(data.match.val[i]), G_TicsToCentiseconds(data.match.val[i])); strtime[sizeof strtime - 1] = '\0'; - V_DrawRightAlignedString(x+152+gutter, y, 0, strtime); + if (data.match.numplayers > NUMFORNEWCOLUMN) + V_DrawRightAlignedThinString(x+152+gutter, y-1, V_6WIDTHSPACE, strtime); + else + V_DrawRightAlignedString(x+152+gutter, y, 0, strtime); } else - V_DrawRightAlignedString(x+152+gutter, y, 0, va("%i", data.match.val[i])); + { + if (data.match.numplayers > NUMFORNEWCOLUMN) + V_DrawRightAlignedThinString(x+152+gutter, y-1, V_6WIDTHSPACE, va("%i", data.match.val[i])); + else + V_DrawRightAlignedString(x+152+gutter, y, 0, va("%i", data.match.val[i])); + } } } @@ -786,7 +796,7 @@ void Y_StartIntermission(void) } case int_race: // (time-only race) { - if ((!modifiedgame || savemoddata) && !multiplayer && !demoplayback) // remove this once we have a proper time attack screen + if (!majormods && !multiplayer && !demoplayback) // remove this once we have a proper time attack screen { // Update visitation flags mapvisited[gamemap-1] |= MV_BEATEN;