diff --git a/CMakeLists.txt b/CMakeLists.txt index 34cc12f3c..e12b0d345 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.0) # DO NOT CHANGE THIS SRB2 STRING! Some variable names depend on this string. # Version change is fine. project(SRB2 - VERSION 2.2.5 + VERSION 2.2.6 LANGUAGES C) if(${PROJECT_SOURCE_DIR} MATCHES ${PROJECT_BINARY_DIR}) diff --git a/appveyor.yml b/appveyor.yml index 4a389dca7..820c77e8b 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,4 +1,4 @@ -version: 2.2.5.{branch}-{build} +version: 2.2.6.{branch}-{build} os: MinGW environment: @@ -110,8 +110,8 @@ after_build: - set BUILDSARCHIVE=%REPO%-%CONFIGURATION%.7z - cmd: 7z a %BUILD_ARCHIVE% %BUILD_PATH% -xr!.gitignore - appveyor PushArtifact %BUILD_ARCHIVE% -- cmd: copy %BUILD_ARCHIVE% %BUILDSARCHIVE% -- appveyor PushArtifact %BUILDSARCHIVE% +#- cmd: copy %BUILD_ARCHIVE% %BUILDSARCHIVE% +#- appveyor PushArtifact %BUILDSARCHIVE% ############################## # DEPLOYER SCRIPT ############################## diff --git a/src/Makefile.cfg b/src/Makefile.cfg index 409cc4f22..23e602798 100644 --- a/src/Makefile.cfg +++ b/src/Makefile.cfg @@ -1,3 +1,4 @@ +# vim: ft=make # # Makefile.cfg for SRB2 # @@ -7,6 +8,66 @@ # and other things # +# See the following variable don't start with 'GCC'. This is +# to avoid a false positive with the version detection... + +SUPPORTED_GCC_VERSIONS:=\ + 91\ + 81 82 83\ + 71 72\ + 61 62 63 64\ + 51 52 53 54\ + 40 41 42 43 44 45 46 47 48 49 + +LATEST_GCC_VERSION=9.1 + +# gcc or g++ +ifdef PREFIX + CC=$(PREFIX)-gcc + CXX=$(PREFIX)-g++ + OBJCOPY=$(PREFIX)-objcopy + OBJDUMP=$(PREFIX)-objdump + STRIP=$(PREFIX)-strip + WINDRES=$(PREFIX)-windres +else + OBJCOPY=objcopy + OBJDUMP=objdump + STRIP=strip + WINDRES=windres +endif + +# because Apple screws with us on this +# need to get bintools from homebrew +ifdef MACOSX + CC=clang + CXX=clang + OBJCOPY=gobjcopy + OBJDUMP=gobjdump +endif + +# Automatically set version flag, but not if one was manually set +ifeq (,$(filter GCC%,$(.VARIABLES))) + ifneq (,$(findstring GCC,$(shell $(CC) --version))) # if it's GCC + version:=$(shell $(CC) -dumpversion) + + # Turn version into words of major, minor + v:=$(subst ., ,$(version)) + # concat. major minor + v:=$(word 1,$(v))$(word 2,$(v)) + + # If this version is not in the list, default to the latest supported + ifeq (,$(filter $(v),$(SUPPORTED_GCC_VERSIONS))) + $(info\ + Your compiler version, GCC $(version), is not supported by the Makefile.\ + The Makefile will assume GCC $(LATEST_GCC_VERSION).) + GCC$(subst .,,$(LATEST_GCC_VERSION))=1 + else + $(info Detected GCC $(version) (GCC$(v))) + GCC$(v)=1 + endif + endif +endif + ifdef GCC91 GCC83=1 endif @@ -358,30 +419,6 @@ ifdef ARCHNAME BIN:=$(BIN)/$(ARCHNAME) endif -# gcc or g++ -ifdef PREFIX - CC=$(PREFIX)-gcc - CXX=$(PREFIX)-g++ - OBJCOPY=$(PREFIX)-objcopy - OBJDUMP=$(PREFIX)-objdump - STRIP=$(PREFIX)-strip - WINDRES=$(PREFIX)-windres -else - OBJCOPY=objcopy - OBJDUMP=objdump - STRIP=strip - WINDRES=windres -endif - -# because Apple screws with us on this -# need to get bintools from homebrew -ifdef MACOSX - CC=clang - CXX=clang - OBJCOPY=gobjcopy - OBJDUMP=gobjdump -endif - OBJDUMP_OPTS?=--wide --source --line-numbers LD=$(CC) diff --git a/src/byteptr.h b/src/byteptr.h index 933c2af34..01a6293b4 100644 --- a/src/byteptr.h +++ b/src/byteptr.h @@ -150,15 +150,15 @@ FUNCINLINE static ATTRINLINE UINT32 readulong(void *ptr) #undef DEALIGNED -#define WRITESTRINGN(p,s,n) { size_t tmp_i = 0; for (; tmp_i < n && s[tmp_i] != '\0'; tmp_i++) WRITECHAR(p, s[tmp_i]); if (tmp_i < n) WRITECHAR(p, '\0');} -#define WRITESTRING(p,s) { size_t tmp_i = 0; for (; s[tmp_i] != '\0'; tmp_i++) WRITECHAR(p, s[tmp_i]); WRITECHAR(p, '\0');} -#define WRITEMEM(p,s,n) { memcpy(p, s, n); p += n; } +#define WRITESTRINGN(p,s,n) do { size_t tmp_i = 0; for (; tmp_i < n && s[tmp_i] != '\0'; tmp_i++) WRITECHAR(p, s[tmp_i]); if (tmp_i < n) WRITECHAR(p, '\0');} while (0) +#define WRITESTRING(p,s) do { size_t tmp_i = 0; for (; s[tmp_i] != '\0'; tmp_i++) WRITECHAR(p, s[tmp_i]); WRITECHAR(p, '\0');} while (0) +#define WRITEMEM(p,s,n) do { memcpy(p, s, n); p += n; } while (0) #define SKIPSTRING(p) while (READCHAR(p) != '\0') -#define READSTRINGN(p,s,n) { size_t tmp_i = 0; for (; tmp_i < n && (s[tmp_i] = READCHAR(p)) != '\0'; tmp_i++); s[tmp_i] = '\0';} -#define READSTRING(p,s) { size_t tmp_i = 0; for (; (s[tmp_i] = READCHAR(p)) != '\0'; tmp_i++); s[tmp_i] = '\0';} -#define READMEM(p,s,n) { memcpy(s, p, n); p += n; } +#define READSTRINGN(p,s,n) ({ size_t tmp_i = 0; for (; tmp_i < n && (s[tmp_i] = READCHAR(p)) != '\0'; tmp_i++); s[tmp_i] = '\0';}) +#define READSTRING(p,s) ({ size_t tmp_i = 0; for (; (s[tmp_i] = READCHAR(p)) != '\0'; tmp_i++); s[tmp_i] = '\0';}) +#define READMEM(p,s,n) ({ memcpy(s, p, n); p += n; }) #if 0 // old names #define WRITEBYTE(p,b) WRITEUINT8(p,b) diff --git a/src/command.c b/src/command.c index 091dbd8f1..6fd8c11f9 100644 --- a/src/command.c +++ b/src/command.c @@ -56,7 +56,13 @@ static boolean CV_FilterVarByVersion(consvar_t *v, const char *valstr); static boolean CV_Command(void); consvar_t *CV_FindVar(const char *name); static const char *CV_StringValue(const char *var_name); + static consvar_t *consvar_vars; // list of registered console variables +static UINT16 consvar_number_of_netids = 0; + +#ifdef OLD22DEMOCOMPAT +static old_demo_var_t *consvar_old_demo_vars; +#endif static char com_token[1024]; static char *COM_Parse(char *data); @@ -1121,14 +1127,16 @@ consvar_t *CV_FindVar(const char *name) return NULL; } -/** Builds a unique Net Variable identifier number, which is used - * in network packets instead of the full name. +#ifdef OLD22DEMOCOMPAT +/** Builds a unique Net Variable identifier number, which was used + * in network packets and demos instead of the full name. + * + * This function only still exists to keep compatibility with old demos. * * \param s Name of the variable. * \return A new unique identifier. - * \sa CV_FindNetVar */ -static inline UINT16 CV_ComputeNetid(const char *s) +static inline UINT16 CV_ComputeOldDemoID(const char *s) { UINT16 ret = 0, i = 0; static UINT16 premiers[16] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53}; @@ -1142,16 +1150,47 @@ static inline UINT16 CV_ComputeNetid(const char *s) return ret; } +/** Finds a net variable based on its old style hash. If a hash collides, a + * warning is printed and this function returns NULL. + * + * \param chk The variable's old style hash. + * \return A pointer to the variable itself if found, or NULL. + */ +static old_demo_var_t *CV_FindOldDemoVar(UINT16 chk) +{ + old_demo_var_t *demovar; + + for (demovar = consvar_old_demo_vars; demovar; demovar = demovar->next) + { + if (demovar->checksum == chk) + { + if (demovar->collides) + { + CONS_Alert(CONS_WARNING, + "Old demo netvar id %hu is a collision\n", chk); + return NULL; + } + + return demovar; + } + } + + return NULL; +} +#endif/*OLD22DEMOCOMPAT*/ + /** Finds a net variable based on its identifier number. * * \param netid The variable's identifier number. * \return A pointer to the variable itself if found, or NULL. - * \sa CV_ComputeNetid */ static consvar_t *CV_FindNetVar(UINT16 netid) { consvar_t *cvar; + if (netid >= consvar_number_of_netids) + return NULL; + for (cvar = consvar_vars; cvar; cvar = cvar->next) if (cvar->netid == netid) return cvar; @@ -1161,6 +1200,32 @@ static consvar_t *CV_FindNetVar(UINT16 netid) static void Setvalue(consvar_t *var, const char *valstr, boolean stealth); +#ifdef OLD22DEMOCOMPAT +/* Sets up a netvar for compatibility with old demos. */ +static void CV_RegisterOldDemoVar(consvar_t *variable) +{ + old_demo_var_t *demovar; + UINT16 old_demo_id; + + old_demo_id = CV_ComputeOldDemoID(variable->name); + + demovar = CV_FindOldDemoVar(old_demo_id); + + if (demovar) + demovar->collides = true; + else + { + demovar = ZZ_Calloc(sizeof *demovar); + + demovar->checksum = old_demo_id; + demovar->cvar = variable; + + demovar->next = consvar_old_demo_vars; + consvar_old_demo_vars = demovar; + } +} +#endif + /** Registers a variable for later use from the console. * * \param variable The variable to register. @@ -1184,11 +1249,15 @@ void CV_RegisterVar(consvar_t *variable) // check net variables if (variable->flags & CV_NETVAR) { - const consvar_t *netvar; - variable->netid = CV_ComputeNetid(variable->name); - netvar = CV_FindNetVar(variable->netid); - if (netvar) - I_Error("Variables %s and %s have same netid\n", variable->name, netvar->name); + variable->netid = consvar_number_of_netids++; + + /* in case of overflow... */ + if (variable->netid > consvar_number_of_netids) + I_Error("Way too many netvars"); + +#ifdef OLD22DEMOCOMPAT + CV_RegisterOldDemoVar(variable); +#endif } // link the variable in @@ -1448,12 +1517,100 @@ badinput: static boolean serverloading = false; +static consvar_t * +ReadNetVar (UINT8 **p, char **return_value, boolean *return_stealth) +{ + UINT16 netid; + char *val; + boolean stealth; + + consvar_t *cvar; + + netid = READUINT16 (*p); + val = (char *)*p; + SKIPSTRING (*p); + stealth = READUINT8 (*p); + + cvar = CV_FindNetVar(netid); + + if (cvar) + { + (*return_value) = val; + (*return_stealth) = stealth; + + DEBFILE(va("Netvar received: %s [netid=%d] value %s\n", cvar->name, netid, val)); + } + else + CONS_Alert(CONS_WARNING, "Netvar not found with netid %hu\n", netid); + + return cvar; +} + +#ifdef OLD22DEMOCOMPAT +static consvar_t * +ReadOldDemoVar (UINT8 **p, char **return_value, boolean *return_stealth) +{ + UINT16 id; + char *val; + boolean stealth; + + old_demo_var_t *demovar; + + id = READUINT16 (*p); + val = (char *)*p; + SKIPSTRING (*p); + stealth = READUINT8 (*p); + + demovar = CV_FindOldDemoVar(id); + + if (demovar) + { + (*return_value) = val; + (*return_stealth) = stealth; + + return demovar->cvar; + } + else + { + CONS_Alert(CONS_WARNING, "Netvar not found with old demo id %hu\n", id); + return NULL; + } +} +#endif/*OLD22DEMOCOMPAT*/ + +static consvar_t * +ReadDemoVar (UINT8 **p, char **return_value, boolean *return_stealth) +{ + char *name; + char *val; + boolean stealth; + + consvar_t *cvar; + + name = (char *)*p; + SKIPSTRING (*p); + val = (char *)*p; + SKIPSTRING (*p); + stealth = READUINT8 (*p); + + cvar = CV_FindVar(name); + + if (cvar) + { + (*return_value) = val; + (*return_stealth) = stealth; + } + else + CONS_Alert(CONS_WARNING, "Netvar not found with name %s\n", name); + + return cvar; +} + static void Got_NetVar(UINT8 **p, INT32 playernum) { consvar_t *cvar; - UINT16 netid; char *svalue; - UINT8 stealth = false; + boolean stealth; if (playernum != serverplayer && !IsPlayerAdmin(playernum) && !serverloading) { @@ -1463,23 +1620,14 @@ static void Got_NetVar(UINT8 **p, INT32 playernum) SendKick(playernum, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY); return; } - netid = READUINT16(*p); - cvar = CV_FindNetVar(netid); - svalue = (char *)*p; - SKIPSTRING(*p); - stealth = READUINT8(*p); - if (!cvar) - { - CONS_Alert(CONS_WARNING, "Netvar not found with netid %hu\n", netid); - return; - } - DEBFILE(va("Netvar received: %s [netid=%d] value %s\n", cvar->name, netid, svalue)); + cvar = ReadNetVar(p, &svalue, &stealth); - Setvalue(cvar, svalue, stealth); + if (cvar) + Setvalue(cvar, svalue, stealth); } -void CV_SaveNetVars(UINT8 **p) +void CV_SaveVars(UINT8 **p, boolean in_demo) { consvar_t *cvar; UINT8 *count_p = *p; @@ -1491,7 +1639,10 @@ void CV_SaveNetVars(UINT8 **p) for (cvar = consvar_vars; cvar; cvar = cvar->next) if ((cvar->flags & CV_NETVAR) && !CV_IsSetToDefault(cvar)) { - WRITEUINT16(*p, cvar->netid); + if (in_demo) + WRITESTRING(*p, cvar->name); + else + WRITEUINT16(*p, cvar->netid); WRITESTRING(*p, cvar->string); WRITEUINT8(*p, false); ++count; @@ -1499,11 +1650,15 @@ void CV_SaveNetVars(UINT8 **p) WRITEUINT16(count_p, count); } -void CV_LoadNetVars(UINT8 **p) +static void CV_LoadVars(UINT8 **p, + consvar_t *(*got)(UINT8 **p, char **ret_value, boolean *ret_stealth)) { consvar_t *cvar; UINT16 count; + char *val; + boolean stealth; + // prevent "invalid command received" serverloading = true; @@ -1513,11 +1668,33 @@ void CV_LoadNetVars(UINT8 **p) count = READUINT16(*p); while (count--) - Got_NetVar(p, 0); + { + cvar = (*got)(p, &val, &stealth); + + if (cvar) + Setvalue(cvar, val, stealth); + } serverloading = false; } +void CV_LoadNetVars(UINT8 **p) +{ + CV_LoadVars(p, ReadNetVar); +} + +#ifdef OLD22DEMOCOMPAT +void CV_LoadOldDemoVars(UINT8 **p) +{ + CV_LoadVars(p, ReadOldDemoVar); +} +#endif + +void CV_LoadDemoVars(UINT8 **p) +{ + CV_LoadVars(p, ReadDemoVar); +} + static void CV_SetCVar(consvar_t *var, const char *value, boolean stealth); void CV_ResetCheatNetVars(void) diff --git a/src/command.h b/src/command.h index 404052ce4..b39153a65 100644 --- a/src/command.h +++ b/src/command.h @@ -144,6 +144,19 @@ typedef struct consvar_s //NULL, NULL, 0, NULL, NULL |, 0, NULL, NULL, 0, 0, NUL struct consvar_s *next; } consvar_t; +#ifdef OLD22DEMOCOMPAT +typedef struct old_demo_var old_demo_var_t; + +struct old_demo_var +{ + UINT16 checksum; + boolean collides;/* this var is a collision of multiple hashes */ + + consvar_t *cvar; + old_demo_var_t *next; +}; +#endif/*OLD22DEMOCOMPAT*/ + extern CV_PossibleValue_t CV_OnOff[]; extern CV_PossibleValue_t CV_YesNo[]; extern CV_PossibleValue_t CV_Unsigned[]; @@ -184,9 +197,18 @@ void CV_AddValue(consvar_t *var, INT32 increment); void CV_SaveVariables(FILE *f); // load/save gamesate (load and save option and for network join in game) -void CV_SaveNetVars(UINT8 **p); +void CV_SaveVars(UINT8 **p, boolean in_demo); + +#define CV_SaveNetVars(p) CV_SaveVars(p, false) void CV_LoadNetVars(UINT8 **p); +#define CV_SaveDemoVars(p) CV_SaveVars(p, true) +void CV_LoadDemoVars(UINT8 **p); + +#ifdef OLD22DEMOCOMPAT +void CV_LoadOldDemoVars(UINT8 **p); +#endif + // reset cheat netvars after cheats is deactivated void CV_ResetCheatNetVars(void); diff --git a/src/config.h.in b/src/config.h.in index def5d67ce..595bea7b3 100644 --- a/src/config.h.in +++ b/src/config.h.in @@ -31,12 +31,13 @@ * Last updated 2020 / 05 / 10 - v2.2.3 - player.dta & patch.pk3 * Last updated 2020 / 05 / 11 - v2.2.4 - patch.pk3 * Last updated 2020 / 07 / 07 - v2.2.5 - player.dta & patch.pk3 + * Last updated 2020 / 07 / 10 - v2.2.6 - player.dta & patch.pk3 */ #define ASSET_HASH_SRB2_PK3 "0277c9416756627004e83cbb5b2e3e28" #define ASSET_HASH_ZONES_PK3 "f7e88afb6af7996a834c7d663144bead" -#define ASSET_HASH_PLAYER_DTA "3a48810db46c7790bd373d7e05af5221" +#define ASSET_HASH_PLAYER_DTA "49dad7b24634c89728cc3e0b689e12bb" #ifdef USE_PATCH_DTA -#define ASSET_HASH_PATCH_PK3 "57af2ba105dc4eb1e5b8e39e6aafaa4d" +#define ASSET_HASH_PATCH_PK3 "ecf00060f03c76b3e49c6ae3925b627f" #endif #endif diff --git a/src/d_clisrv.c b/src/d_clisrv.c index a1e3976bc..c7c5470ae 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -5496,7 +5496,7 @@ void NetUpdate(void) // update node latency values so we can take an average later. for (i = 0; i < MAXPLAYERS; i++) if (playeringame[i] && playernode[i] != UINT8_MAX) - realpingtable[i] += GetLag(playernode[i]) * (1000.00f / TICRATE); + realpingtable[i] += G_TicsToMilliseconds(GetLag(playernode[i])); pingmeasurecount++; } diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 4f5c17c95..592734067 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -3475,7 +3475,7 @@ static void Command_Version_f(void) #ifdef DEVELOP CONS_Printf("Sonic Robo Blast 2 %s-%s (%s %s) ", compbranch, comprevision, compdate, comptime); #else - CONS_Printf("Sonic Robo Blast 2 %s (%s %s %s) ", VERSIONSTRING, compdate, comptime, comprevision); + CONS_Printf("Sonic Robo Blast 2 %s (%s %s %s %s) ", VERSIONSTRING, compdate, comptime, comprevision, compbranch); #endif // Base library diff --git a/src/doomdef.h b/src/doomdef.h index a994d5990..8853b4aae 100644 --- a/src/doomdef.h +++ b/src/doomdef.h @@ -143,9 +143,9 @@ extern char logfilename[1024]; // we use comprevision and compbranch instead. #else #define VERSION 202 // Game version -#define SUBVERSION 5 // more precise version number -#define VERSIONSTRING "v2.2.5" -#define VERSIONSTRINGW L"v2.2.5" +#define SUBVERSION 6 // more precise version number +#define VERSIONSTRING "v2.2.6" +#define VERSIONSTRINGW L"v2.2.6" // Hey! If you change this, add 1 to the MODVERSION below! // Otherwise we can't force updates! #endif @@ -213,7 +213,7 @@ extern char logfilename[1024]; // 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.2.0 is not version "1". -#define MODVERSION 45 +#define MODVERSION 47 // To version config.cfg, MAJOREXECVERSION is set equal to MODVERSION automatically. // Increment MINOREXECVERSION whenever a config change is needed that does not correspond @@ -657,4 +657,7 @@ extern const char *compdate, *comptime, *comprevision, *compbranch; /// Render flats on walls #define WALLFLATS +/// Maintain compatibility with older 2.2 demos +#define OLD22DEMOCOMPAT + #endif // __DOOMDEF__ diff --git a/src/f_finale.c b/src/f_finale.c index eb6e283ad..f47c6c1a7 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -1674,6 +1674,18 @@ void F_GameEvaluationDrawer(void) V_DrawString(8, 96, V_YELLOWMAP, "Modified games\ncan't unlock\nextras!"); } #endif + + if (marathonmode) + { + const char *rtatext, *cuttext; + rtatext = (marathonmode & MA_INGAME) ? "In-game timer" : "RTA timer"; + cuttext = (marathonmode & MA_NOCUTSCENES) ? "" : " w/ cutscenes"; + if (botskin) + endingtext = va("%s & %s, %s%s", skins[players[consoleplayer].skin].realname, skins[botskin-1].realname, rtatext, cuttext); + else + endingtext = va("%s, %s%s", skins[players[consoleplayer].skin].realname, rtatext, cuttext); + V_DrawCenteredString(BASEVIDWIDTH/2, 182, (ultimatemode ? V_REDMAP : V_YELLOWMAP), endingtext); + } } void F_GameEvaluationTicker(void) diff --git a/src/g_demo.c b/src/g_demo.c index 4dad85a3c..6c58f12fb 100644 --- a/src/g_demo.c +++ b/src/g_demo.c @@ -1525,7 +1525,7 @@ void G_BeginRecording(void) } // Save netvar data - CV_SaveNetVars(&demo_p); + CV_SaveDemoVars(&demo_p); memset(&oldcmd,0,sizeof(oldcmd)); memset(&oldghost,0,sizeof(oldghost)); @@ -1756,6 +1756,9 @@ void G_DoPlayDemo(char *defdemoname) UINT32 randseed, followitem; fixed_t camerascale,shieldscale,actionspd,mindash,maxdash,normalspeed,runspeed,jumpfactor,height,spinheight; char msg[1024]; +#ifdef OLD22DEMOCOMPAT + boolean use_old_demo_vars = false; +#endif skin[16] = '\0'; color[MAXCOLORNAME] = '\0'; @@ -1818,10 +1821,13 @@ void G_DoPlayDemo(char *defdemoname) case DEMOVERSION: // latest always supported cnamelen = MAXCOLORNAME; break; +#ifdef OLD22DEMOCOMPAT // all that changed between then and now was longer color name case 0x000c: cnamelen = 16; + use_old_demo_vars = true; break; +#endif // too old, cannot support. default: snprintf(msg, 1024, M_GetText("%s is an incompatible replay format and cannot be played.\n"), pdemoname); @@ -1923,7 +1929,13 @@ void G_DoPlayDemo(char *defdemoname) } // net var data - CV_LoadNetVars(&demo_p); +#ifdef OLD22DEMOCOMPAT + if (use_old_demo_vars) + CV_LoadOldDemoVars(&demo_p); + else +#else + CV_LoadDemoVars(&demo_p); +#endif // Sigh ... it's an empty demo. if (*demo_p == DEMOMARKER) diff --git a/src/g_game.c b/src/g_game.c index b20157156..69aac5065 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -3729,6 +3729,32 @@ static boolean CanSaveLevel(INT32 mapnum) return (mapheaderinfo[mapnum-1] && (mapheaderinfo[mapnum-1]->levelflags & LF_SAVEGAME)); } +static void G_HandleSaveLevel(void) +{ + // do this before running the intermission or custom cutscene, mostly for the sake of marathon mode but it also massively reduces redundant file save events in f_finale.c + if (nextmap >= 1100-1) + { + if (!gamecomplete) + gamecomplete = 2; // special temporary mode to prevent using SP level select in pause menu until the intermission is over without restricting it in every intermission + if (cursaveslot > 0) + { + if (marathonmode) + { + // don't keep a backup around when the run is done! + if (FIL_FileExists(liveeventbackup)) + remove(liveeventbackup); + cursaveslot = 0; + } + else if ((!modifiedgame || savemoddata) && !(netgame || multiplayer || ultimatemode || demorecording || metalrecording || modeattacking)) + G_SaveGame((UINT32)cursaveslot, spstage_start); + } + } + // and doing THIS here means you don't lose your progress if you close the game mid-intermission + else if (!(ultimatemode || netgame || multiplayer || demoplayback || demorecording || metalrecording || modeattacking) + && (!modifiedgame || savemoddata) && cursaveslot > 0 && CanSaveLevel(lastmap+1)) + G_SaveGame((UINT32)cursaveslot, lastmap+1); // not nextmap+1 to route around special stages +} + // // G_DoCompleted // @@ -3875,6 +3901,7 @@ static void G_DoCompleted(void) if ((skipstats && !modeattacking) || (spec && modeattacking && stagefailed) || (intertype == int_none)) { G_UpdateVisited(); + G_HandleSaveLevel(); G_AfterIntermission(); } else @@ -3882,30 +3909,8 @@ static void G_DoCompleted(void) G_SetGamestate(GS_INTERMISSION); Y_StartIntermission(); G_UpdateVisited(); + G_HandleSaveLevel(); } - - // do this before running the intermission or custom cutscene, mostly for the sake of marathon mode but it also massively reduces redundant file save events in f_finale.c - if (nextmap >= 1100-1) - { - if (!gamecomplete) - gamecomplete = 2; // special temporary mode to prevent using SP level select in pause menu until the intermission is over without restricting it in every intermission - if (cursaveslot > 0) - { - if (marathonmode) - { - // don't keep a backup around when the run is done! - if (FIL_FileExists(liveeventbackup)) - remove(liveeventbackup); - cursaveslot = 0; - } - else if ((!modifiedgame || savemoddata) && !(netgame || multiplayer || ultimatemode || demorecording || metalrecording || modeattacking)) - G_SaveGame((UINT32)cursaveslot, spstage_start); - } - } - // and doing THIS here means you don't lose your progress if you close the game mid-intermission - else if (!(ultimatemode || netgame || multiplayer || demoplayback || demorecording || metalrecording || modeattacking) - && (!modifiedgame || savemoddata) && cursaveslot > 0 && CanSaveLevel(lastmap+1)) - G_SaveGame((UINT32)cursaveslot, lastmap+1); // not nextmap+1 to route around special stages } // See also F_EndCutscene, the only other place which handles intra-map/ending transitions @@ -4498,7 +4503,10 @@ void G_SaveGame(UINT32 slot, INT16 mapnum) P_SaveGame(mapnum); if (marathonmode) { - WRITEUINT32(save_p, marathontime); + UINT32 writetime = marathontime; + if (!(marathonmode & MA_INGAME)) + marathontime += TICRATE*5; // live event backup penalty because we don't know how long it takes to get to the next map + WRITEUINT32(save_p, writetime); WRITEUINT8(save_p, (marathonmode & ~MA_INIT)); } diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c index f5df49bcd..80c01f98c 100644 --- a/src/hardware/hw_md2.c +++ b/src/hardware/hw_md2.c @@ -1177,6 +1177,34 @@ static UINT8 HWR_GetModelSprite2(md2_t *md2, skin_t *skin, UINT8 spr2, player_t return spr2; } +static void adjustTextureCoords(model_t *model, GLPatch_t *gpatch) +{ + int i; + for (i = 0; i < model->numMeshes; i++) + { + int j; + mesh_t *mesh = &model->meshes[i]; + int numVertices; + float *uvPtr = mesh->uvs; + + // i dont know if this is actually possible, just logical conclusion of structure in CreateModelVBOs + if (!mesh->frames && !mesh->tinyframes) return; + + if (mesh->frames) // again CreateModelVBO and CreateModelVBOTiny iterate like this so I'm gonna do that too + numVertices = mesh->numTriangles * 3; + else + numVertices = mesh->numVertices; + + // fix uvs (texture coordinates) to take into account that the actual texture + // has empty space added until the next power of two + for (j = 0; j < numVertices; j++) + { + *uvPtr++ *= gpatch->max_s; + *uvPtr++ *= gpatch->max_t; + } + } +} + // // HWR_DrawModel // @@ -1278,6 +1306,19 @@ boolean HWR_DrawModel(gr_vissprite_t *spr) sprinfo = &spriteinfo[spr->mobj->sprite]; } + // texture loading before model init, so it knows if sprite graphics are used, which + // means that texture coordinates have to be adjusted + gpatch = md2->grpatch; + if (!gpatch || ((!gpatch->mipmap->grInfo.format || !gpatch->mipmap->downloaded) && !md2->notexturefile)) + md2_loadTexture(md2); + gpatch = md2->grpatch; // Load it again, because it isn't being loaded into gpatch after md2_loadtexture... + + if ((gpatch && gpatch->mipmap->grInfo.format) // don't load the blend texture if the base texture isn't available + && (!md2->blendgrpatch + || ((!((GLPatch_t *)md2->blendgrpatch)->mipmap->grInfo.format || !((GLPatch_t *)md2->blendgrpatch)->mipmap->downloaded) + && !md2->noblendfile))) + md2_loadBlendTexture(md2); + if (md2->error) return false; // we already failed loading this before :( if (!md2->model) @@ -1289,6 +1330,10 @@ boolean HWR_DrawModel(gr_vissprite_t *spr) if (md2->model) { md2_printModelInfo(md2->model); + // if model uses sprite patch as texture, then + // adjust texture coordinates to take power of two textures into account + if (!gpatch || !gpatch->mipmap->grInfo.format) + adjustTextureCoords(md2->model, spr->gpatch); HWD.pfnCreateModelVBOs(md2->model); } else @@ -1306,16 +1351,6 @@ boolean HWR_DrawModel(gr_vissprite_t *spr) //HWD.pfnSetBlend(blend); // This seems to actually break translucency? finalscale = md2->scale; //Hurdler: arf, I don't like that implementation at all... too much crappy - gpatch = md2->grpatch; - if (!gpatch || ((!gpatch->mipmap->grInfo.format || !gpatch->mipmap->downloaded) && !md2->notexturefile)) - md2_loadTexture(md2); - gpatch = md2->grpatch; // Load it again, because it isn't being loaded into gpatch after md2_loadtexture... - - if ((gpatch && gpatch->mipmap->grInfo.format) // don't load the blend texture if the base texture isn't available - && (!md2->blendgrpatch - || ((!((GLPatch_t *)md2->blendgrpatch)->mipmap->grInfo.format || !((GLPatch_t *)md2->blendgrpatch)->mipmap->downloaded) - && !md2->noblendfile))) - md2_loadBlendTexture(md2); if (gpatch && gpatch->mipmap->grInfo.format) // else if meant that if a texture couldn't be loaded, it would just end up using something else's texture { diff --git a/src/hardware/r_opengl/r_opengl.c b/src/hardware/r_opengl/r_opengl.c index e5f6ff3cf..b7baa4eb0 100644 --- a/src/hardware/r_opengl/r_opengl.c +++ b/src/hardware/r_opengl/r_opengl.c @@ -2939,6 +2939,8 @@ EXPORT void HWRAPI(SetTransform) (FTransform *stransform) if (shearing) { float fdy = stransform->viewaiming * 2; + if (stransform->flip) + fdy *= -1.0f; pglTranslatef(0.0f, -fdy/BASEVIDHEIGHT, 0.0f); } diff --git a/src/m_menu.c b/src/m_menu.c index dba792e90..131f72c76 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -487,7 +487,7 @@ CV_PossibleValue_t loadless_cons_t[] = {{0, "Realtime"}, {1, "In-game"}, {0, NUL consvar_t cv_dummymarathon = {"dummymarathon", "Standard", CV_HIDEN, marathon_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_dummycutscenes = {"dummycutscenes", "Off", CV_HIDEN, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; -consvar_t cv_dummyloadless = {"dummyloadless", "Realtime", CV_HIDEN, loadless_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_dummyloadless = {"dummyloadless", "In-game", CV_HIDEN, loadless_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; // ========================================================================== // ORGANIZATION START. @@ -10563,8 +10563,7 @@ static void M_StartMarathon(INT32 choice) (void)choice; marathontime = 0; marathonmode = MA_RUNNING|MA_INIT; - if (cv_dummymarathon.value == 1) - cursaveslot = MARATHONSLOT; + cursaveslot = (cv_dummymarathon.value == 1) ? MARATHONSLOT : 0; if (!cv_dummycutscenes.value) marathonmode |= MA_NOCUTSCENES; if (cv_dummyloadless.value) diff --git a/src/p_inter.c b/src/p_inter.c index 9caed927d..bd044f32a 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -467,10 +467,22 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) if ((P_MobjFlip(toucher)*toucher->momz < 0) && (elementalpierce != 1)) { - if (elementalpierce == 2) - P_DoBubbleBounce(player); - else if (!(player->charability2 == CA2_MELEE && player->panim == PA_ABILITY2)) - toucher->momz = -toucher->momz; + if (!(player->charability2 == CA2_MELEE && player->panim == PA_ABILITY2)) + { + fixed_t setmomz = -toucher->momz; // Store this, momz get changed by P_DoJump within P_DoBubbleBounce + + if (elementalpierce == 2) // Reset bubblewrap, part 1 + P_DoBubbleBounce(player); + toucher->momz = setmomz; + if (elementalpierce == 2) // Reset bubblewrap, part 2 + { + boolean underwater = toucher->eflags & MFE_UNDERWATER; + + if (underwater) + toucher->momz /= 2; + toucher->momz -= (toucher->momz/(underwater ? 8 : 4)); // Cap the height! + } + } } if (player->pflags & PF_BOUNCING) P_DoAbilityBounce(player, false); diff --git a/src/p_map.c b/src/p_map.c index b7ad14808..f7db52f6a 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -1678,13 +1678,23 @@ static boolean PIT_CheckThing(mobj_t *thing) && (flipval*(*momz) < 0) // monitor is on the floor and you're going down, or on the ceiling and you're going up && (elementalpierce != 1)) // you're not piercing through the monitor... { - if (elementalpierce == 2) - P_DoBubbleBounce(player); - else if (!(player->charability2 == CA2_MELEE && player->panim == PA_ABILITY2)) + if (!(player->charability2 == CA2_MELEE && player->panim == PA_ABILITY2)) { - *momz = -*momz; // Therefore, you should be thrust in the opposite direction, vertically. + fixed_t setmomz = -*momz; // Store this, momz get changed by P_DoJump within P_DoBubbleBounce + + if (elementalpierce == 2) // Reset bubblewrap, part 1 + P_DoBubbleBounce(player); + *momz = setmomz; // Therefore, you should be thrust in the opposite direction, vertically. if (player->charability == CA_TWINSPIN && player->panim == PA_ABILITY) P_TwinSpinRejuvenate(player, player->thokitem); + if (elementalpierce == 2) // Reset bubblewrap, part 2 + { + boolean underwater = tmthing->eflags & MFE_UNDERWATER; + + if (underwater) + *momz /= 2; + *momz -= (*momz/(underwater ? 8 : 4)); // Cap the height! + } } } if (!(elementalpierce == 1 && thing->flags & MF_GRENADEBOUNCE)) // prevent gold monitor clipthrough. diff --git a/src/p_user.c b/src/p_user.c index 261e4b28c..d426277ff 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -4863,7 +4863,7 @@ void P_DoBubbleBounce(player_t *player) player->pflags |= PF_THOKKED; player->pflags &= ~PF_STARTJUMP; player->secondjump = UINT8_MAX; - player->mo->momz = FixedMul(player->mo->momz, 5*FRACUNIT/4); + player->mo->momz = FixedMul(player->mo->momz, 11*FRACUNIT/8); } // @@ -5112,15 +5112,19 @@ static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd) boolean elem = ((player->powers[pw_shield] & SH_NOSTACK) == SH_ELEMENTAL); player->pflags |= PF_THOKKED|PF_SHIELDABILITY; if (elem) + { + player->mo->momx = player->mo->momy = 0; S_StartSound(player->mo, sfx_s3k43); + } else { + player->mo->momx -= (player->mo->momx/3); + player->mo->momy -= (player->mo->momy/3); player->pflags &= ~PF_NOJUMPDAMAGE; P_SetPlayerMobjState(player->mo, S_PLAY_ROLL); S_StartSound(player->mo, sfx_s3k44); } player->secondjump = 0; - player->mo->momx = player->mo->momy = 0; P_SetObjectMomZ(player->mo, -24*FRACUNIT, false); break; } diff --git a/src/sdl/macosx/Srb2mac.xcodeproj/project.pbxproj b/src/sdl/macosx/Srb2mac.xcodeproj/project.pbxproj index a7d9022f1..eeae1c2de 100644 --- a/src/sdl/macosx/Srb2mac.xcodeproj/project.pbxproj +++ b/src/sdl/macosx/Srb2mac.xcodeproj/project.pbxproj @@ -1215,7 +1215,7 @@ C01FCF4B08A954540054247B /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - CURRENT_PROJECT_VERSION = 2.2.5; + CURRENT_PROJECT_VERSION = 2.2.6; GCC_PREPROCESSOR_DEFINITIONS = ( "$(inherited)", NORMALSRB2, @@ -1227,7 +1227,7 @@ C01FCF4C08A954540054247B /* Release */ = { isa = XCBuildConfiguration; buildSettings = { - CURRENT_PROJECT_VERSION = 2.2.5; + CURRENT_PROJECT_VERSION = 2.2.6; GCC_ENABLE_FIX_AND_CONTINUE = NO; GCC_GENERATE_DEBUGGING_SYMBOLS = NO; GCC_PREPROCESSOR_DEFINITIONS = ( diff --git a/src/win32/Srb2win.rc b/src/win32/Srb2win.rc index c6ec8dff3..b90947a9e 100644 --- a/src/win32/Srb2win.rc +++ b/src/win32/Srb2win.rc @@ -66,8 +66,8 @@ END #include "../doomdef.h" // Needed for version string VS_VERSION_INFO VERSIONINFO - FILEVERSION 2,2,5,0 - PRODUCTVERSION 2,2,5,0 + FILEVERSION 2,2,6,0 + PRODUCTVERSION 2,2,6,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L