diff --git a/CMakeLists.txt b/CMakeLists.txt index 1e46f5dc3..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.4 + VERSION 2.2.6 LANGUAGES C) if(${PROJECT_SOURCE_DIR} MATCHES ${PROJECT_BINARY_DIR}) diff --git a/appveyor.yml b/appveyor.yml index 5d599a516..820c77e8b 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,4 +1,4 @@ -version: 2.2.4.{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/CMakeLists.txt b/src/CMakeLists.txt index fa7f235a1..520fc8929 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -429,7 +429,6 @@ if(${SRB2_CONFIG_HWRENDER}) ${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_md2load.c ${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_md3load.c ${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_model.c - ${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_trick.c ${CMAKE_CURRENT_SOURCE_DIR}/hardware/u_list.c ) diff --git a/src/Makefile b/src/Makefile index 4bf158d78..9ea1ea239 100644 --- a/src/Makefile +++ b/src/Makefile @@ -224,7 +224,7 @@ ifdef NOHW else OPTS+=-DHWRENDER OBJS+=$(OBJDIR)/hw_bsp.o $(OBJDIR)/hw_draw.o $(OBJDIR)/hw_light.o \ - $(OBJDIR)/hw_main.o $(OBJDIR)/hw_clip.o $(OBJDIR)/hw_md2.o $(OBJDIR)/hw_cache.o $(OBJDIR)/hw_trick.o \ + $(OBJDIR)/hw_main.o $(OBJDIR)/hw_clip.o $(OBJDIR)/hw_md2.o $(OBJDIR)/hw_cache.o \ $(OBJDIR)/hw_md2load.o $(OBJDIR)/hw_md3load.o $(OBJDIR)/hw_model.o $(OBJDIR)/u_list.o $(OBJDIR)/hw_batching.o endif 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 fdfc95c6d..4973812e7 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) @@ -1574,7 +1751,7 @@ static void CV_SetCVar(consvar_t *var, const char *value, boolean stealth) // send the value of the variable UINT8 buf[128]; UINT8 *p = buf; - if (!(server || (IsPlayerAdmin(consoleplayer)))) + if (!(server || (addedtogame && IsPlayerAdmin(consoleplayer)))) { CONS_Printf(M_GetText("Only the server or admin can change: %s %s\n"), var->name, var->string); return; 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 3b2579965..595bea7b3 100644 --- a/src/config.h.in +++ b/src/config.h.in @@ -30,12 +30,14 @@ * Last updated 2020 / 02 / 22 - v2.2.2 - patch.pk3 * 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 "8a4507ddf9bc0682c09174400f26ad65" +#define ASSET_HASH_PLAYER_DTA "49dad7b24634c89728cc3e0b689e12bb" #ifdef USE_PATCH_DTA -#define ASSET_HASH_PATCH_PK3 "bbbf6af3b20349612ee06e0b55979a76" +#define ASSET_HASH_PATCH_PK3 "ecf00060f03c76b3e49c6ae3925b627f" #endif #endif diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 78d4555bd..c7c5470ae 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -5159,7 +5159,7 @@ static void SV_SendTics(void) { // assert supposedtics[n]>=nettics[n] realfirsttic = supposedtics[n]; - lasttictosend = min(maketic, realfirsttic + CLIENTBACKUPTICS); + lasttictosend = min(maketic, nettics[n] + CLIENTBACKUPTICS); if (realfirsttic >= lasttictosend) { @@ -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/dehacked.c b/src/dehacked.c index 258cc1f46..99d4883f6 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -3082,6 +3082,7 @@ static actionpointer_t actionpointers[] = {{A_NapalmScatter}, "A_NAPALMSCATTER"}, {{A_SpawnFreshCopy}, "A_SPAWNFRESHCOPY"}, {{A_FlickySpawn}, "A_FLICKYSPAWN"}, + {{A_FlickyCenter}, "A_FLICKYCENTER"}, {{A_FlickyAim}, "A_FLICKYAIM"}, {{A_FlickyFly}, "A_FLICKYFLY"}, {{A_FlickySoar}, "A_FLICKYSOAR"}, diff --git a/src/doomdef.h b/src/doomdef.h index 1f90a6f7f..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 4 // more precise version number -#define VERSIONSTRING "v2.2.4" -#define VERSIONSTRINGW L"v2.2.4" +#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 @@ -204,7 +204,7 @@ extern char logfilename[1024]; // Will always resemble the versionstring, 205 = 2.0.5, 210 = 2.1, etc. #define CODEBASE 220 -// The Modification ID; must be obtained from Rob ( https://mb.srb2.org/private.php?do=newpm&u=546 ). +// The Modification ID; must be obtained from a Master Server Admin ( https://mb.srb2.org/showgroups.php ). // DO NOT try to set this otherwise, or your modification will be unplayable through the Master Server. // "18" is the default mod ID for version 2.2 #define MODID 18 @@ -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 44 +#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..8d39a7533 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, V_SNAPTOBOTTOM|(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..cce4ac822 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)) + writetime += 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_cache.c b/src/hardware/hw_cache.c index 79610cbd0..ed3b6afee 100644 --- a/src/hardware/hw_cache.c +++ b/src/hardware/hw_cache.c @@ -117,7 +117,7 @@ static void HWR_DrawColumnInCache(const column_t *patchcol, UINT8 *block, GLMipm { case 2 : // uhhhhhhhh.......... if ((originPatch != NULL) && (originPatch->style != AST_COPY)) - texel = ASTBlendPixel_8bpp(*(dest+1), texel, originPatch->style, originPatch->alpha); + texel = ASTBlendPaletteIndexes(*(dest+1), texel, originPatch->style, originPatch->alpha); texelu16 = (UINT16)((alpha<<8) | texel); memcpy(dest, &texelu16, sizeof(UINT16)); break; @@ -126,7 +126,7 @@ static void HWR_DrawColumnInCache(const column_t *patchcol, UINT8 *block, GLMipm { RGBA_t rgbatexel; rgbatexel.rgba = *(UINT32 *)dest; - colortemp.rgba = ASTBlendPixel(rgbatexel, colortemp, originPatch->style, originPatch->alpha); + colortemp.rgba = ASTBlendTexturePixel(rgbatexel, colortemp, originPatch->style, originPatch->alpha); } memcpy(dest, &colortemp, sizeof(RGBA_t)-sizeof(UINT8)); break; @@ -136,14 +136,14 @@ static void HWR_DrawColumnInCache(const column_t *patchcol, UINT8 *block, GLMipm { RGBA_t rgbatexel; rgbatexel.rgba = *(UINT32 *)dest; - colortemp.rgba = ASTBlendPixel(rgbatexel, colortemp, originPatch->style, originPatch->alpha); + colortemp.rgba = ASTBlendTexturePixel(rgbatexel, colortemp, originPatch->style, originPatch->alpha); } memcpy(dest, &colortemp, sizeof(RGBA_t)); break; // default is 1 default: if ((originPatch != NULL) && (originPatch->style != AST_COPY)) - *dest = ASTBlendPixel_8bpp(*dest, texel, originPatch->style, originPatch->alpha); + *dest = ASTBlendPaletteIndexes(*dest, texel, originPatch->style, originPatch->alpha); else *dest = texel; break; @@ -229,7 +229,7 @@ static void HWR_DrawFlippedColumnInCache(const column_t *patchcol, UINT8 *block, { case 2 : // uhhhhhhhh.......... if ((originPatch != NULL) && (originPatch->style != AST_COPY)) - texel = ASTBlendPixel_8bpp(*(dest+1), texel, originPatch->style, originPatch->alpha); + texel = ASTBlendPaletteIndexes(*(dest+1), texel, originPatch->style, originPatch->alpha); texelu16 = (UINT16)((alpha<<8) | texel); memcpy(dest, &texelu16, sizeof(UINT16)); break; @@ -238,7 +238,7 @@ static void HWR_DrawFlippedColumnInCache(const column_t *patchcol, UINT8 *block, { RGBA_t rgbatexel; rgbatexel.rgba = *(UINT32 *)dest; - colortemp.rgba = ASTBlendPixel(rgbatexel, colortemp, originPatch->style, originPatch->alpha); + colortemp.rgba = ASTBlendTexturePixel(rgbatexel, colortemp, originPatch->style, originPatch->alpha); } memcpy(dest, &colortemp, sizeof(RGBA_t)-sizeof(UINT8)); break; @@ -248,14 +248,14 @@ static void HWR_DrawFlippedColumnInCache(const column_t *patchcol, UINT8 *block, { RGBA_t rgbatexel; rgbatexel.rgba = *(UINT32 *)dest; - colortemp.rgba = ASTBlendPixel(rgbatexel, colortemp, originPatch->style, originPatch->alpha); + colortemp.rgba = ASTBlendTexturePixel(rgbatexel, colortemp, originPatch->style, originPatch->alpha); } memcpy(dest, &colortemp, sizeof(RGBA_t)); break; // default is 1 default: if ((originPatch != NULL) && (originPatch->style != AST_COPY)) - *dest = ASTBlendPixel_8bpp(*dest, texel, originPatch->style, originPatch->alpha); + *dest = ASTBlendPaletteIndexes(*dest, texel, originPatch->style, originPatch->alpha); else *dest = texel; break; diff --git a/src/hardware/hw_glob.h b/src/hardware/hw_glob.h index 57f3c54d9..6ede8448b 100644 --- a/src/hardware/hw_glob.h +++ b/src/hardware/hw_glob.h @@ -63,11 +63,12 @@ typedef struct gl_vissprite_s { float x1, x2; float tz, ty; + float tracertz; // for MF2_LINKDRAW sprites, this contains tracer's tz for use in sorting //lumpnum_t patchlumpnum; GLPatch_t *gpatch; boolean flip; UINT8 translucency; //alpha level 0-255 - mobj_t *mobj; + mobj_t *mobj; // NOTE: This is a precipmobj_t if precip is true !!! Watch out. boolean precip; // Tails 08-25-2002 boolean vflip; //Hurdler: 25/04/2000: now support colormap in hardware mode diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index db9dfdda7..85d8d454e 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -2990,34 +2990,11 @@ static void HWR_Subsector(size_t num) //gl_cursectorlight.blue = light; //gl_cursectorlight.alpha = light; -// ----- for special tricks with HW renderer ----- - if (gl_frontsector->pseudoSector) - { - cullFloorHeight = locFloorHeight = gl_frontsector->virtualFloorheight; - cullCeilingHeight = locCeilingHeight = gl_frontsector->virtualCeilingheight; - } - else if (gl_frontsector->virtualFloor) - { - ///@TODO Is this whole virtualFloor mess even useful? I don't think it even triggers ever. - cullFloorHeight = locFloorHeight = gl_frontsector->virtualFloorheight; - if (gl_frontsector->virtualCeiling) - cullCeilingHeight = locCeilingHeight = gl_frontsector->virtualCeilingheight; - else - cullCeilingHeight = locCeilingHeight = gl_frontsector->ceilingheight; - } - else if (gl_frontsector->virtualCeiling) - { - cullCeilingHeight = locCeilingHeight = gl_frontsector->virtualCeilingheight; - cullFloorHeight = locFloorHeight = gl_frontsector->floorheight; - } - else - { - cullFloorHeight = P_GetSectorFloorZAt (gl_frontsector, viewx, viewy); - cullCeilingHeight = P_GetSectorCeilingZAt(gl_frontsector, viewx, viewy); - locFloorHeight = P_GetSectorFloorZAt (gl_frontsector, gl_frontsector->soundorg.x, gl_frontsector->soundorg.y); - locCeilingHeight = P_GetSectorCeilingZAt(gl_frontsector, gl_frontsector->soundorg.x, gl_frontsector->soundorg.y); - } // ----- end special tricks ----- + cullFloorHeight = P_GetSectorFloorZAt (gl_frontsector, viewx, viewy); + cullCeilingHeight = P_GetSectorCeilingZAt(gl_frontsector, viewx, viewy); + locFloorHeight = P_GetSectorFloorZAt (gl_frontsector, gl_frontsector->soundorg.x, gl_frontsector->soundorg.y); + locCeilingHeight = P_GetSectorCeilingZAt(gl_frontsector, gl_frontsector->soundorg.x, gl_frontsector->soundorg.y); if (gl_frontsector->ffloors) { @@ -3501,6 +3478,54 @@ static gl_vissprite_t *HWR_NewVisSprite(void) return HWR_GetVisSprite(gl_visspritecount++); } +// A hack solution for transparent surfaces appearing on top of linkdraw sprites. +// Keep a list of linkdraw sprites and draw their shapes to the z-buffer after all other +// sprite drawing is done. (effectively the z-buffer drawing of linkdraw sprites is delayed) +// NOTE: This will no longer be necessary once full translucent sorting is implemented, where +// translucent sprites and surfaces are sorted together. + +typedef struct +{ + FOutVector verts[4]; + gr_vissprite_t *spr; +} zbuffersprite_t; + +// this list is used to store data about linkdraw sprites +zbuffersprite_t linkdrawlist[MAXVISSPRITES]; +UINT32 linkdrawcount = 0; + +// add the necessary data to the list for delayed z-buffer drawing +static void HWR_LinkDrawHackAdd(FOutVector *verts, gr_vissprite_t *spr) +{ + if (linkdrawcount < MAXVISSPRITES) + { + memcpy(linkdrawlist[linkdrawcount].verts, verts, sizeof(FOutVector) * 4); + linkdrawlist[linkdrawcount].spr = spr; + linkdrawcount++; + } +} + +// process and clear the list of sprites for delayed z-buffer drawing +static void HWR_LinkDrawHackFinish(void) +{ + UINT32 i; + FSurfaceInfo surf; + surf.PolyColor.rgba = 0xFFFFFFFF; + surf.TintColor.rgba = 0xFFFFFFFF; + surf.FadeColor.rgba = 0xFFFFFFFF; + surf.LightInfo.light_level = 0; + surf.LightInfo.fade_start = 0; + surf.LightInfo.fade_end = 31; + for (i = 0; i < linkdrawcount; i++) + { + // draw sprite shape, only to z-buffer + HWR_GetPatch(linkdrawlist[i].spr->gpatch); + HWR_ProcessPolygon(&surf, linkdrawlist[i].verts, 4, PF_Translucent|PF_Occlude|PF_Invisible|PF_Clip, 0, false); + } + // reset list + linkdrawcount = 0; +} + // // HWR_DoCulling // Hardware version of R_DoCulling @@ -3687,6 +3712,8 @@ static void HWR_SplitSprite(gl_vissprite_t *spr) extracolormap_t *colormap; FUINT lightlevel; FBITFIELD blend = 0; + FBITFIELD occlusion; + boolean use_linkdraw_hack = false; UINT8 alpha; INT32 i; @@ -3780,10 +3807,18 @@ static void HWR_SplitSprite(gl_vissprite_t *spr) // co-ordinates memcpy(wallVerts, baseWallVerts, sizeof(baseWallVerts)); + // if sprite has linkdraw, then dont write to z-buffer (by not using PF_Occlude) + // this will result in sprites drawn afterwards to be drawn on top like intended when using linkdraw. + if ((spr->mobj->flags2 & MF2_LINKDRAW) && spr->mobj->tracer) + occlusion = 0; + else + occlusion = PF_Occlude; + if (!cv_translucency.value) // translucency disabled { Surf.PolyColor.s.alpha = 0xFF; - blend = PF_Translucent|PF_Occlude; + blend = PF_Translucent|occlusion; + if (!occlusion) use_linkdraw_hack = true; } else if (spr->mobj->flags2 & MF2_SHADOW) { @@ -3799,7 +3834,8 @@ static void HWR_SplitSprite(gl_vissprite_t *spr) // Hurdler: PF_Environement would be cool, but we need to fix // the issue with the fog before Surf.PolyColor.s.alpha = 0xFF; - blend = PF_Translucent|PF_Occlude; + blend = PF_Translucent|occlusion; + if (!occlusion) use_linkdraw_hack = true; } alpha = Surf.PolyColor.s.alpha; @@ -3904,6 +3940,9 @@ static void HWR_SplitSprite(gl_vissprite_t *spr) HWR_ProcessPolygon(&Surf, wallVerts, 4, blend|PF_Modulated|PF_Clip, 3, false); // sprite shader + if (use_linkdraw_hack) + HWR_LinkDrawHackAdd(wallVerts, spr); + top = bot; endtop = endbot; } @@ -3929,6 +3968,9 @@ static void HWR_SplitSprite(gl_vissprite_t *spr) Surf.PolyColor.s.alpha = alpha; HWR_ProcessPolygon(&Surf, wallVerts, 4, blend|PF_Modulated|PF_Clip, 3, false); // sprite shader + + if (use_linkdraw_hack) + HWR_LinkDrawHackAdd(wallVerts, spr); } // -----------------+ @@ -4051,10 +4093,21 @@ static void HWR_DrawSprite(gl_vissprite_t *spr) { FBITFIELD blend = 0; + FBITFIELD occlusion; + boolean use_linkdraw_hack = false; + + // if sprite has linkdraw, then dont write to z-buffer (by not using PF_Occlude) + // this will result in sprites drawn afterwards to be drawn on top like intended when using linkdraw. + if ((spr->mobj->flags2 & MF2_LINKDRAW) && spr->mobj->tracer) + occlusion = 0; + else + occlusion = PF_Occlude; + if (!cv_translucency.value) // translucency disabled { Surf.PolyColor.s.alpha = 0xFF; - blend = PF_Translucent|PF_Occlude; + blend = PF_Translucent|occlusion; + if (!occlusion) use_linkdraw_hack = true; } else if (spr->mobj->flags2 & MF2_SHADOW) { @@ -4070,10 +4123,14 @@ static void HWR_DrawSprite(gl_vissprite_t *spr) // Hurdler: PF_Environement would be cool, but we need to fix // the issue with the fog before Surf.PolyColor.s.alpha = 0xFF; - blend = PF_Translucent|PF_Occlude; + blend = PF_Translucent|occlusion; + if (!occlusion) use_linkdraw_hack = true; } HWR_ProcessPolygon(&Surf, wallVerts, 4, blend|PF_Modulated|PF_Clip, 3, false); // sprite shader + + if (use_linkdraw_hack) + HWR_LinkDrawHackAdd(wallVerts, spr); } } @@ -4189,6 +4246,7 @@ static int CompareVisSprites(const void *p1, const void *p2) gl_vissprite_t* spr2 = *(gl_vissprite_t*const*)p2; int idiff; float fdiff; + float tz1, tz2; // Make transparent sprites last. Comment from the previous sort implementation: // Sryder: Oh boy, while it's nice having ALL the sprites sorted properly, it fails when we bring MD2's into the @@ -4196,12 +4254,53 @@ static int CompareVisSprites(const void *p1, const void *p2) // everything else, but still ordered of course, the depth buffer can handle the opaque ones plenty fine. // We just need to move all translucent ones to the end in order // TODO: Fully sort all sprites and MD2s with walls and floors, this part will be unnecessary after that - int transparency1 = (spr1->mobj->flags2 & MF2_SHADOW) || (spr1->mobj->frame & FF_TRANSMASK); - int transparency2 = (spr2->mobj->flags2 & MF2_SHADOW) || (spr2->mobj->frame & FF_TRANSMASK); + int transparency1; + int transparency2; + + // check for precip first, because then sprX->mobj is actually a precipmobj_t and does not have flags2 or tracer + int linkdraw1 = !spr1->precip && (spr1->mobj->flags2 & MF2_LINKDRAW) && spr1->mobj->tracer; + int linkdraw2 = !spr2->precip && (spr2->mobj->flags2 & MF2_LINKDRAW) && spr2->mobj->tracer; + + // ^ is the XOR operation + // if comparing a linkdraw and non-linkdraw sprite or 2 linkdraw sprites with different tracers, then use + // the tracer's properties instead of the main sprite's. + if ((linkdraw1 && linkdraw2 && spr1->mobj->tracer != spr2->mobj->tracer) || (linkdraw1 ^ linkdraw2)) + { + if (linkdraw1) + { + tz1 = spr1->tracertz; + transparency1 = (spr1->mobj->tracer->flags2 & MF2_SHADOW) || (spr1->mobj->tracer->frame & FF_TRANSMASK); + } + else + { + tz1 = spr1->tz; + transparency1 = (!spr1->precip && (spr1->mobj->flags2 & MF2_SHADOW)) || (spr1->mobj->frame & FF_TRANSMASK); + } + if (linkdraw2) + { + tz2 = spr2->tracertz; + transparency2 = (spr2->mobj->tracer->flags2 & MF2_SHADOW) || (spr2->mobj->tracer->frame & FF_TRANSMASK); + } + else + { + tz2 = spr2->tz; + transparency2 = (!spr2->precip && (spr2->mobj->flags2 & MF2_SHADOW)) || (spr2->mobj->frame & FF_TRANSMASK); + } + } + else + { + tz1 = spr1->tz; + transparency1 = (!spr1->precip && (spr1->mobj->flags2 & MF2_SHADOW)) || (spr1->mobj->frame & FF_TRANSMASK); + tz2 = spr2->tz; + transparency2 = (!spr2->precip && (spr2->mobj->flags2 & MF2_SHADOW)) || (spr2->mobj->frame & FF_TRANSMASK); + } + + // first compare transparency flags, then compare tz, then compare dispoffset + idiff = transparency1 - transparency2; if (idiff != 0) return idiff; - fdiff = spr2->tz - spr1->tz; // this order seems correct when checking with apitrace. Back to front. + fdiff = tz2 - tz1; // this order seems correct when checking with apitrace. Back to front. if (fabsf(fdiff) < 1.0E-36f) return spr1->dispoffset - spr2->dispoffset; // smallest dispoffset first if sprites are at (almost) same location. else if (fdiff > 0) @@ -4525,6 +4624,7 @@ static void HWR_CreateDrawNodes(void) static void HWR_DrawSprites(void) { UINT32 i; + boolean skipshadow = false; // skip shadow if it was drawn already for a linkdraw sprite encountered earlier in the list HWD.pfnSetSpecialState(HWD_SET_MODEL_LIGHTING, cv_glmodellighting.value); for (i = 0; i < gl_visspritecount; i++) { @@ -4535,11 +4635,32 @@ static void HWR_DrawSprites(void) else #endif { - if (spr->mobj && spr->mobj->shadowscale && cv_shadow.value) + if (spr->mobj && spr->mobj->shadowscale && cv_shadow.value && !skipshadow) { HWR_DrawDropShadow(spr->mobj, spr->mobj->shadowscale); } + if ((spr->mobj->flags2 & MF2_LINKDRAW) && spr->mobj->tracer) + { + // If this linkdraw sprite is behind a sprite that has a shadow, + // then that shadow has to be drawn first, otherwise the shadow ends up on top of + // the linkdraw sprite because the linkdraw sprite does not modify the z-buffer. + // The !skipshadow check is there in case there are multiple linkdraw sprites connected + // to the same tracer, so the tracer's shadow only gets drawn once. + if (cv_shadow.value && !skipshadow && spr->dispoffset < 0 && spr->mobj->tracer->shadowscale) + { + HWR_DrawDropShadow(spr->mobj->tracer, spr->mobj->tracer->shadowscale); + skipshadow = true; + // The next sprite in this loop should be either another linkdraw sprite or the tracer. + // When the tracer is inevitably encountered, skipshadow will cause it's shadow + // to get skipped and skipshadow will get set to false by the 'else' clause below. + } + } + else + { + skipshadow = false; + } + if (spr->mobj && spr->mobj->skin && spr->mobj->sprite == SPR_PLAY) { if (!cv_glmodels.value || md2_playermodels[(skin_t*)spr->mobj->skin-skins].notfound || md2_playermodels[(skin_t*)spr->mobj->skin-skins].scale < 0.0f) @@ -4563,6 +4684,16 @@ static void HWR_DrawSprites(void) } } HWD.pfnSetSpecialState(HWD_SET_MODEL_LIGHTING, 0); + + // At the end of sprite drawing, draw shapes of linkdraw sprites to z-buffer, so they + // don't get drawn over by transparent surfaces. + HWR_LinkDrawHackFinish(); + // Work around a r_opengl.c bug with PF_Invisible by making this SetBlend call + // where PF_Invisible is off and PF_Masked is on. + // (Other states probably don't matter. Here I left them same as in LinkDrawHackFinish) + // Without this workaround the rest of the draw calls in this frame (including UI, screen texture) + // can get drawn using an incorrect glBlendFunc, resulting in a occasional black screen. + HWD.pfnSetBlend(PF_Translucent|PF_Occlude|PF_Clip|PF_Masked); } // -------------------------------------------------------------------------- @@ -4624,6 +4755,7 @@ static void HWR_ProjectSprite(mobj_t *thing) gl_vissprite_t *vis; float tr_x, tr_y; float tz; + float tracertz = 0.0f; float x1, x2; float rightsin, rightcos; float this_scale; @@ -4638,6 +4770,7 @@ static void HWR_ProjectSprite(mobj_t *thing) boolean vflip = (!(thing->eflags & MFE_VERTICALFLIP) != !(thing->frame & FF_VERTICALFLIP)); boolean mirrored = thing->mirrored; boolean hflip = (!(thing->frame & FF_HORIZONTALFLIP) != !mirrored); + INT32 dispoffset; angle_t ang; INT32 heightsec, phs; @@ -4655,6 +4788,8 @@ static void HWR_ProjectSprite(mobj_t *thing) if (!thing) return; + dispoffset = thing->info->dispoffset; + this_scale = FIXED_TO_FLOAT(thing->scale); // transform the origin point @@ -4867,9 +5002,28 @@ static void HWR_ProjectSprite(mobj_t *thing) if ((thing->flags2 & MF2_LINKDRAW) && thing->tracer) { - // bodge support - not nearly as comprehensive as r_things.c, but better than nothing if (! R_ThingVisible(thing->tracer)) return; + + // calculate tz for tracer, same way it is calculated for this sprite + // transform the origin point + tr_x = FIXED_TO_FLOAT(thing->tracer->x) - gr_viewx; + tr_y = FIXED_TO_FLOAT(thing->tracer->y) - gr_viewy; + + // rotation around vertical axis + tracertz = (tr_x * gr_viewcos) + (tr_y * gr_viewsin); + + // Software does not render the linkdraw sprite if the tracer is behind the view plane, + // so do the same check here. + // NOTE: This check has the same flaw as the view plane check at the beginning of HWR_ProjectSprite: + // the view aiming angle is not taken into account, leading to sprites disappearing too early when they + // can still be seen when looking down/up at steep angles. + if (tracertz < ZCLIP_PLANE) + return; + + // if the sprite is behind the tracer, invert dispoffset, putting the sprite behind the tracer + if (tz > tracertz) + dispoffset *= -1; } // store information in a vissprite @@ -4877,7 +5031,8 @@ static void HWR_ProjectSprite(mobj_t *thing) vis->x1 = x1; vis->x2 = x2; vis->tz = tz; // Keep tz for the simple sprite sorting that happens - vis->dispoffset = thing->info->dispoffset; // Monster Iestyn: 23/11/15: HARDWARE SUPPORT AT LAST + vis->tracertz = tracertz; + vis->dispoffset = dispoffset; // Monster Iestyn: 23/11/15: HARDWARE SUPPORT AT LAST //vis->patchlumpnum = sprframe->lumppat[rot]; #ifdef ROTSPRITE if (rotsprite) @@ -5688,7 +5843,7 @@ static CV_PossibleValue_t grshearing_cons_t[] = {{0, "Off"}, {1, "On"}, {2, "Thi static void CV_glfiltermode_OnChange(void); static void CV_glanisotropic_OnChange(void); -static CV_PossibleValue_t grfiltermode_cons_t[]= {{HWD_SET_TEXTUREFILTER_POINTSAMPLED, "Nearest"}, +static CV_PossibleValue_t glfiltermode_cons_t[]= {{HWD_SET_TEXTUREFILTER_POINTSAMPLED, "Nearest"}, {HWD_SET_TEXTUREFILTER_BILINEAR, "Bilinear"}, {HWD_SET_TEXTUREFILTER_TRILINEAR, "Trilinear"}, {HWD_SET_TEXTUREFILTER_MIXED1, "Linear_Nearest"}, {HWD_SET_TEXTUREFILTER_MIXED2, "Nearest_Linear"}, @@ -5716,12 +5871,11 @@ consvar_t cv_glskydome = {"gr_skydome", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, consvar_t cv_glfakecontrast = {"gr_fakecontrast", "Smooth", CV_SAVE, grfakecontrast_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_glslopecontrast = {"gr_slopecontrast", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; -consvar_t cv_glfiltermode = {"gr_filtermode", "Nearest", CV_SAVE|CV_CALL, grfiltermode_cons_t, +consvar_t cv_glfiltermode = {"gr_filtermode", "Nearest", CV_SAVE|CV_CALL, glfiltermode_cons_t, CV_glfiltermode_OnChange, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_glanisotropicmode = {"gr_anisotropicmode", "1", CV_CALL, granisotropicmode_cons_t, CV_glanisotropic_OnChange, 0, NULL, NULL, 0, 0, NULL}; -consvar_t cv_glcorrecttricks = {"gr_correcttricks", "Off", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_glsolvetjoin = {"gr_solvetjoin", "On", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_glbatching = {"gr_batching", "On", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; @@ -5761,7 +5915,6 @@ void HWR_AddCommands(void) CV_RegisterVar(&cv_glshaders); CV_RegisterVar(&cv_glfiltermode); - CV_RegisterVar(&cv_glcorrecttricks); CV_RegisterVar(&cv_glsolvetjoin); CV_RegisterVar(&cv_renderstats); diff --git a/src/hardware/hw_main.h b/src/hardware/hw_main.h index f404d8c5e..ddb3696b6 100644 --- a/src/hardware/hw_main.h +++ b/src/hardware/hw_main.h @@ -52,7 +52,6 @@ boolean HWR_Screenshot(const char *pathname); void HWR_AddCommands(void); void HWR_AddSessionCommands(void); -void HWR_CorrectSWTricks(void); void transform(float *cx, float *cy, float *cz); FBITFIELD HWR_TranstableToAlpha(INT32 transtablenum, FSurfaceInfo *pSurf); INT32 HWR_GetTextureUsed(void); @@ -87,7 +86,6 @@ extern consvar_t cv_glmodelinterpolation; extern consvar_t cv_glmodellighting; extern consvar_t cv_glfiltermode; extern consvar_t cv_glanisotropicmode; -extern consvar_t cv_glcorrecttricks; extern consvar_t cv_fovchange; extern consvar_t cv_glsolvetjoin; extern consvar_t cv_glshearing; diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c index c311d6462..b23b3600c 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(gl_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(gl_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(gl_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->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->format) // don't load the blend texture if the base texture isn't available - && (!md2->blendgrpatch - || ((!((GLPatch_t *)md2->blendgrpatch)->mipmap->format || !((GLPatch_t *)md2->blendgrpatch)->mipmap->downloaded) - && !md2->noblendfile))) - md2_loadBlendTexture(md2); if (gpatch && gpatch->mipmap->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/hw_trick.c b/src/hardware/hw_trick.c deleted file mode 100644 index 312be66d4..000000000 --- a/src/hardware/hw_trick.c +++ /dev/null @@ -1,914 +0,0 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- -// -// Copyright (C) 1998-2001 by DooM Legacy Team. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -//----------------------------------------------------------------------------- -/// \file -/// \brief special trick routines to make some SW tricks look OK with -/// HW rendering. This includes: -/// - deepwatereffect (e.g. tnt/map02) -/// - invisible staircase (e.g. eternal/map02) -/// - floating ceilings (e.g. eternal/map03) -/// -/// It is not guaranteed that it looks identical to the SW mode, -/// but it looks in most of the cases far better than having -/// holes in the architecture, HOM, etc. -/// -/// It fixes as well missing textures, which are replaced by either -/// a default texture or the midtexture. -/// -/// words of notice: -/// pseudosectors, as mentioned in this file, are sectors where both -/// sidedefs point to the same sector. This expression is also used -/// for sectors which are enclosed by another sector but have no -/// correct sidedefs at all -/// -/// if a vertex is inside a poly is determined by the angles between -/// this vertex and all angles on the linedefs (imagine walking along -/// a circle always facing a certain point inside/outside the circle; -/// if inside, angle have taken all values [0..pi), otherwise the -/// range was < pi/2 - -#include -#include "../doomdef.h" -#include "../doomstat.h" - -#ifdef HWRENDER -#include "hw_glob.h" -#include "hw_dll.h" -#include "../r_local.h" -#include "../i_system.h" - -// -// add a line to a sectors list of lines -// -static void addLineToChain(sector_t *sector, line_t *line) -{ - linechain_t *thisElem = NULL, *nextElem; - - if (!sector) - return; - - nextElem = sector->sectorLines; - - while (nextElem) // walk through chain - { - thisElem = nextElem; - nextElem = thisElem->next; - } - - // add a new element into the chain - if (thisElem) - { - thisElem->next = malloc(sizeof (linechain_t)); - if (thisElem->next) - { - thisElem->next->line = line; - thisElem->next->next = NULL; - } - else - { - I_Error("Out of memory in addLineToChain(.)\n"); - } - } - else // first element in chain - { - sector->sectorLines = malloc(sizeof (linechain_t)); - if (sector->sectorLines) - { - sector->sectorLines->line = line; - sector->sectorLines->next = NULL; - } - else - { - I_Error("Out of memory in addLineToChain(.)\n"); - } - } -} - -// -// We dont want a memory hole, do we?;-) -// -static void releaseLineChains(void) -{ - linechain_t *thisElem, *nextElem; - sector_t *sector; - size_t i; - - for (i = 0; i < numsectors; i++) - { - sector = §ors[i]; - nextElem = sector->sectorLines; - - while (nextElem) - { - thisElem = nextElem; - nextElem = thisElem->next; - free(thisElem); - } - - sector->sectorLines = NULL; - } -} - -// -// check if a pseudo sector is valid by checking all its linedefs -// -static boolean isPSectorValid(sector_t *sector) -{ - linechain_t *thisElem, *nextElem; - - if (!sector->pseudoSector) // check only pseudosectors, others dont care - { -#ifdef PARANOIA - CONS_Debug(DBG_RENDER, "Alert! non-pseudosector fed to isPSectorClosed()\n"); -#endif - return false; - } - - nextElem = sector->sectorLines; - - while (nextElem) - { - thisElem = nextElem; - nextElem = thisElem->next; - if (thisElem->line->frontsector != thisElem->line->backsector) - return false; - } - return true; -} - -// -// angles are always phiMax-phiMin [0...2\pi) -// -FUNCMATH static double phiDiff(double phiMin, double phiMax) -{ - double result; - - result = phiMax-phiMin; - - if (result < 0.0l) - result += 2.0l*M_PIl; - - return result; -} - -// -// sort phi's so that enclosed angle < \pi -// -static void sortPhi(double phi1, double phi2, double *phiMin, double *phiMax) -{ - if (phiDiff(phi1, phi2) < M_PIl) - { - *phiMin = phi1; - *phiMax = phi2; - } - else - { - *phiMin = phi2; - *phiMax = phi1; - } -} - -// -// return if angle(phi1, phi2) is bigger than \pi -// if so, the vertex lies inside the poly -// -FUNCMATH static boolean biggerThanPi(double phi1, double phi2) -{ - if (phiDiff(phi1, phi2) > M_PIl) - return true; - - return false; -} - -#define DELTAPHI (M_PIl/100.0l) // some small phi << \pi - -// -// calculate bounds for minimum angle -// -static void phiBounds(double phi1, double phi2, double *phiMin, double *phiMax) -{ - double phi1Tmp, phi2Tmp; - double psi1, psi2, psi3, psi4, psi5, psi6, psi7; // for optimization - - sortPhi(phi1, phi2, &phi1Tmp, &phi2Tmp); - phi1 = phi1Tmp; - phi2 = phi2Tmp; - - // check start condition - if (*phiMin > M_PIl || *phiMax > M_PIl) - { - *phiMin = phi1; - *phiMax = phi2; - return; - } - - // 6 cases: - // new angles inbetween phiMin, phiMax -> forget it - // new angles enclose phiMin -> set phiMin - // new angles enclose phiMax -> set phiMax - // new angles completely outside phiMin, phiMax -> leave largest area free - // new angles close the range completely! - // new angles enlarges range on both sides - - psi1 = phiDiff(*phiMin, phi1); - psi2 = phiDiff(*phiMin, phi2); - psi3 = phiDiff(*phiMax, phi1); - psi4 = phiDiff(*phiMax, phi2); - psi5 = phiDiff(*phiMin, *phiMax); - psi6 = (double)(2.0l*M_PIl - psi5); // phiDiff(*phiMax, *phiMin); - psi7 = (double)(2.0l*M_PIl - psi2); // phiDiff(phi2, *phiMin); - - // case 1 & 5! - if ((psi1 <= psi5) && (psi2 <= psi5)) - { - if (psi1 <= psi2) // case 1 - { - return; - } - else // case 5 - { - // create some artificial interval here not to get into numerical trouble - // in fact we know now the sector is completely enclosed -> base for computational optimization - *phiMax = 0.0l; - *phiMin = DELTAPHI; - return; - } - } - - // case 2 - if ((psi1 >= psi5) && (psi2 <= psi5)) - { - *phiMin = phi1; - return; - } - - // case 3 - if ((psi3 >= psi6) && (psi4 <= psi6)) - { - *phiMax = phi2; - return; - } - - // case 4 & 6 -#ifdef PARANOIA - if ((psi3 <= psi6) && (psi4 <= psi6)) // FIXME: isn't this case implicitly true anyway?? -#endif - { - if (psi3 <= psi4) //case 4 - { - if (psi3 >= psi7) - { - *phiMin = phi1; - return; - } - else - { - *phiMax = phi2; - return; - } - } - else // case 6 - { - *phiMin = phi1; - *phiMax = phi2; - return; - } - } - -#ifdef PARANOIA - CONS_Debug(DBG_RENDER, "phiMin = %f, phiMax = %f, phi1 = %f, phi2 = %f\n", *phiMin, *phiMax, phi1, phi2); - I_Error("phiBounds() out of range!\n"); -#endif -} - -// -// Check if a vertex lies inside a sector -// This works for "well-behaved" convex polygons -// If we need it mathematically correct, we need to sort the -// linedefs first so we have them in a row, then walk along the linedefs, -// but this is a bit overdone -// -static inline boolean isVertexInside(vertex_t *vertex, sector_t *sector) -{ - double xa, ya, xe, ye; - linechain_t *chain; - double phiMin, phiMax; - double phi1, phi2; - - chain = sector->sectorLines; - phiMin = phiMax = 10.0l*M_PIl; // some value > \pi - - while (chain) - { - // start and end vertex - xa = (double)chain->line->v1->x - (double)vertex->x; - ya = (double)chain->line->v1->y - (double)vertex->y; - xe = (double)chain->line->v2->x - (double)vertex->x; - ye = (double)chain->line->v2->y - (double)vertex->y; - - // angle phi of connection between the vertices and the x-axis - phi1 = atan2(ya, xa); - phi2 = atan2(ye, xe); - - // if we have just started, we can have to create start bounds for phi - - phiBounds(phi1, phi2, &phiMin, &phiMax); - chain = chain->next; - } - - return biggerThanPi(phiMin, phiMax); -} - - -#define MAXSTACK 256 // Not more than 256 polys in each other? -// -// generate a list of sectors which enclose the given sector -// -static void generateStacklist(sector_t *thisSector) -{ - size_t i, stackCnt = 0; - sector_t *locStacklist[MAXSTACK]; - sector_t *checkSector; - - for (i = 0; i < numsectors; i++) - { - checkSector = §ors[i]; - - if (checkSector == thisSector) // dont check self - continue; - - // buggy sector? - if (!thisSector->sectorLines) - continue; - - // check if an arbitrary vertex of thisSector lies inside the checkSector - if (isVertexInside(thisSector->sectorLines->line->v1, checkSector)) - { - // if so, the thisSector lies inside the checkSector - locStacklist[stackCnt] = checkSector; - stackCnt++; - - if (MAXSTACK-1 == stackCnt) // beware of the SIGSEGV! and consider terminating NULL! - break; - } - } - - thisSector->stackList = malloc(sizeof (sector_t *) * (stackCnt+1)); - if (NULL == thisSector->stackList) - { - I_Error("Out of memory error in generateStacklist()"); - } - - locStacklist[stackCnt] = NULL; // terminating NULL - - memcpy(thisSector->stackList, locStacklist, sizeof (sector_t *) * (stackCnt+1)); -} - -// -// Bubble sort the stacklist with rising lineoutlengths -// -static void sortStacklist(sector_t *sector) -{ - sector_t **list; - sector_t *sec1, *sec2; - boolean finished; - size_t i; - - list = sector->stackList; - finished = false; - - if (!*list) - return; // nothing to sort - - while (!finished) - { - i = 0; - finished = true; - - while (*(list+i+1)) - { - sec1 = *(list+i); - sec2 = *(list+i+1); - - if (sec1->lineoutLength > sec2->lineoutLength) - { - *(list+i) = sec2; - *(list+i+1) = sec1; - finished = false; - } - i++; - } - } -} - -// -// length of a line in euclidian sense -// -static double lineLength(line_t *line) -{ - double dx, dy, length; - - dx = (double) line->v1->x - (double) line->v2->x; - dy = (double) line->v1->y - (double) line->v2->y; - - length = hypot(dx, dy); - - return length; -} - - -// -// length of the sector lineout -// -static double calcLineoutLength(sector_t *sector) -{ - linechain_t *chain; - double length = 0.0L; - chain = sector->sectorLines; - - while (chain) // sum up lengths of all lines - { - length += lineLength(chain->line); - chain = chain->next; - } - return length; -} - -// -// Calculate length of the sectors lineout -// -static void calcLineouts(sector_t *sector) -{ - size_t secCount = 0; - sector_t *encSector = *(sector->stackList); - - while (encSector) - { - if (encSector->lineoutLength < 0.0L) // if length has not yet been calculated - { - encSector->lineoutLength = calcLineoutLength(encSector); - } - - secCount++; - encSector = *((sector->stackList) + secCount); - } -} - -// -// Free Stacklists of all sectors -// -static void freeStacklists(void) -{ - size_t i; - - for (i = 0; i < numsectors; i++) - { - if (sectors[i].stackList) - { - free(sectors[i].stackList); - sectors[i].stackList = NULL; - } - } -} - -// -// if more than half of the toptextures are missing -// -static boolean areToptexturesMissing(sector_t *thisSector) -{ - linechain_t *thisElem, *nextElem = thisSector->sectorLines; - sector_t *frontSector, *backSector; - size_t nomiss = 0; - side_t *sidel, *sider; - - while (nextElem) // walk through chain - { - thisElem = nextElem; - nextElem = thisElem->next; - - frontSector = thisElem->line->frontsector; - backSector = thisElem->line->backsector; - - if (frontSector == backSector) // skip damn renderer tricks here - continue; - - if (!frontSector || !backSector) - continue; - - sider = &sides[thisElem->line->sidenum[0]]; - sidel = &sides[thisElem->line->sidenum[1]]; - - if (backSector->ceilingheight < frontSector->ceilingheight) - { - if (sider->toptexture != 0) - { - nomiss++; - break; // we can stop here if decision criterium is ==0 - } - } - else if (backSector->ceilingheight > frontSector->ceilingheight) - { - if (sidel->toptexture != 0) - { - nomiss++; - break; // we can stop here if decision criterium is ==0 - } - } - } - - return nomiss == 0; -} - -// -// are more textures missing than present? -// -static boolean areBottomtexturesMissing(sector_t *thisSector) -{ - linechain_t *thisElem, *nextElem = thisSector->sectorLines; - sector_t *frontSector, *backSector; - size_t nomiss = 0; - side_t *sidel, *sider; - - while (nextElem) // walk through chain - { - thisElem = nextElem; - nextElem = thisElem->next; - - frontSector = thisElem->line->frontsector; - backSector = thisElem->line->backsector; - - if (frontSector == backSector) // skip damn renderer tricks here - continue; - - if (!frontSector || !backSector) - continue; - - sider = &sides[thisElem->line->sidenum[0]]; - sidel = &sides[thisElem->line->sidenum[1]]; - - if (backSector->floorheight > frontSector->floorheight) - { - if (sider->bottomtexture != 0) - { - nomiss++; - break; // we can stop here if decision criterium is ==0 - } - } - - else if (backSector->floorheight < frontSector->floorheight) - { - if (sidel->bottomtexture != 0) - { - nomiss++; - break; // we can stop here if decision criterium is ==0 - } - } - } - - // return missing >= nomiss; - return nomiss == 0; -} - -// -// check if no adjacent sector has same ceiling height -// -static boolean isCeilingFloating(sector_t *thisSector) -{ - sector_t *adjSector, *refSector = NULL, *frontSector, *backSector; - linechain_t *thisElem, *nextElem; - - if (!thisSector) - return false; - - nextElem = thisSector->sectorLines; - - while (nextElem) // walk through chain - { - thisElem = nextElem; - nextElem = thisElem->next; - - frontSector = thisElem->line->frontsector; - backSector = thisElem->line->backsector; - - if (frontSector == thisSector) - adjSector = backSector; - else - adjSector = frontSector; - - if (!adjSector) // assume floating sectors have surrounding sectors - return false; - - if (adjSector->c_slope) // Don't bother with slopes - return false; - - if (!refSector) - { - refSector = adjSector; - continue; - } - - // if adjacent sector has same height or more than one adjacent sector exists -> stop - if (thisSector->ceilingheight == adjSector->ceilingheight || refSector != adjSector) - return false; - } - - // now check for walltextures - if (!areToptexturesMissing(thisSector)) - return false; - - return true; -} - -// -// check if no adjacent sector has same ceiling height -// FIXME: throw that together with isCeilingFloating?? -// -static boolean isFloorFloating(sector_t *thisSector) -{ - sector_t *adjSector, *refSector = NULL, *frontSector, *backSector; - linechain_t *thisElem, *nextElem; - - if (!thisSector) - return false; - - nextElem = thisSector->sectorLines; - - while (nextElem) // walk through chain - { - thisElem = nextElem; - nextElem = thisElem->next; - - frontSector = thisElem->line->frontsector; - backSector = thisElem->line->backsector; - - if (frontSector == thisSector) - adjSector = backSector; - else - adjSector = frontSector; - - if (!adjSector) // assume floating sectors have surrounding sectors - return false; - - if (adjSector->f_slope) // Don't bother with slopes - return false; - - if (!refSector) - { - refSector = adjSector; - continue; - } - - // if adjacent sector has same height or more than one adjacent sector exists -> stop - if (thisSector->floorheight == adjSector->floorheight || refSector != adjSector) - return false; - } - - // now check for walltextures - if (!areBottomtexturesMissing(thisSector)) - return false; - - return true; -} - -// -// estimate ceilingheight according to height of adjacent sector -// -static fixed_t estimateCeilHeight(sector_t *thisSector) -{ - sector_t *adjSector; - - if (!thisSector || !thisSector->sectorLines || !thisSector->sectorLines->line) - return 0; - - adjSector = thisSector->sectorLines->line->frontsector; - if (adjSector == thisSector) - adjSector = thisSector->sectorLines->line->backsector; - - if (!adjSector) - return 0; - - return adjSector->ceilingheight; -} - -// -// estimate ceilingheight according to height of adjacent sector -// -static fixed_t estimateFloorHeight(sector_t *thisSector) -{ - sector_t *adjSector; - - if (!thisSector || !thisSector->sectorLines || !thisSector->sectorLines->line) - return 0; - - adjSector = thisSector->sectorLines->line->frontsector; - if (adjSector == thisSector) - adjSector = thisSector->sectorLines->line->backsector; - - if (!adjSector) - return 0; - - return adjSector->floorheight; -} - -#define CORRECT_FLOAT_EXPERIMENTAL - -// -------------------------------------------------------------------------- -// Some levels have missing sidedefs, which produces HOM, so lets try to compensate for that -// and some levels have deep water trick, invisible staircases etc. -// -------------------------------------------------------------------------- -// FIXME: put some nice default texture in legacy.dat and use it -void HWR_CorrectSWTricks(void) -{ - size_t i; - size_t k; - line_t *ld; - side_t *sidel = NULL, *sider; - sector_t *secl, *secr; - sector_t **sectorList; - sector_t *outSector; - - if ((0 == cv_glcorrecttricks.value)) - return; - - // determine lines for sectors - for (i = 0; i < numlines; i++) - { - ld = &lines[i]; - secr = ld->frontsector; - secl = ld->backsector; - - if (secr == secl) - { - secr->pseudoSector = true; // special renderer trick? - addLineToChain(secr, ld); - } - else - { - addLineToChain(secr, ld); - addLineToChain(secl, ld); - } - } - - // preprocessing - for (i = 0; i < numsectors; i++) - { - sector_t *checkSector; - - checkSector = §ors[i]; - - // identify real pseudosectors first - if (checkSector->pseudoSector) - { - if (!isPSectorValid(checkSector)) // drop invalid pseudo sectors - { - checkSector->pseudoSector = false; - } - } - - // determine enclosing sectors for pseudosectors ... used later - if (checkSector->pseudoSector) - { - generateStacklist(checkSector); - calcLineouts(checkSector); - sortStacklist(checkSector); - } - } - - // set virtual floor heights for pseudo sectors - // required for deep water effect e.g. - for (i = 0; i < numsectors; i++) - { - if (sectors[i].pseudoSector) - { - sectorList = sectors[i].stackList; - k = 0; - while (*(sectorList+k)) - { - outSector = *(sectorList+k); - if (!outSector->pseudoSector) - { - sectors[i].virtualFloorheight = outSector->floorheight; - sectors[i].virtualCeilingheight = outSector->ceilingheight; - break; - } - k++; - } - if (*(sectorList+k) == NULL) // sorry, did not work :( - { - sectors[i].virtualFloorheight = sectors[i].floorheight; - sectors[i].virtualCeilingheight = sectors[i].ceilingheight; - } - } - } -#ifdef CORRECT_FLOAT_EXPERIMENTAL - // correct ceiling/floor heights of totally floating sectors - for (i = 0; i < numsectors; i++) - { - sector_t *floatSector; - - floatSector = §ors[i]; - - // correct height of floating sectors - if (isCeilingFloating(floatSector)) - { - floatSector->virtualCeilingheight = estimateCeilHeight(floatSector); - floatSector->virtualCeiling = true; - } - if (isFloorFloating(floatSector)) - { - floatSector->virtualFloorheight = estimateFloorHeight(floatSector); - floatSector->virtualFloor = true; - } - } -#endif - - // now for the missing textures - for (i = 0; i < numlines; i++) - { - ld = &lines[i]; - sider = &sides[ld->sidenum[0]]; - if (ld->sidenum[1] != 0xffff) - sidel = &sides[ld->sidenum[1]]; - - secr = ld->frontsector; - secl = ld->backsector; - - if (secr == secl) // special renderer trick - continue; // we cant correct missing textures here - - if (secl) // only if there is a backsector - { - if (secr->pseudoSector || secl->pseudoSector) - continue; - if (!secr->virtualFloor && !secl->virtualFloor) - { - if (secl->floorheight > secr->floorheight) - { - // now check if r-sidedef is correct - if (sider->bottomtexture == 0) - { - if (sider->midtexture == 0) - sider->bottomtexture = 0; // Tails // More redwall sky shenanigans - else - sider->bottomtexture = sider->midtexture; - } - } - else if (secl->floorheight < secr->floorheight) - { - // now check if l-sidedef is correct - if (sidel->bottomtexture == 0) - { - if (sidel->midtexture == 0) - sidel->bottomtexture = 0; // Tails // More redwall sky shenanigans - else - sidel->bottomtexture = sidel->midtexture; - } - } - } - - if (!secr->virtualCeiling && !secl->virtualCeiling) - { - if (secl->ceilingheight < secr->ceilingheight) - { - // now check if r-sidedef is correct - if (sider->toptexture == 0) - { - if (sider->midtexture == 0) - sider->toptexture = 0; // Tails // When this was REDWALL it was causing issues in the sky sometimes - else - sider->toptexture = sider->midtexture; - } - } - else if (secl->ceilingheight > secr->ceilingheight) - { - // now check if l-sidedef is correct - if (sidel->toptexture == 0) - { - if (sidel->midtexture == 0) - sidel->toptexture = 0; // Tails // When this was REDWALL it was causing issues in the sky sometimes - else - sidel->toptexture = sidel->midtexture; - } - } - } - } // if (NULL != secl) - } // for (i = 0; i < numlines; i++) - - // release all linechains - releaseLineChains(); - freeStacklists(); -} - -#endif // HWRENDER diff --git a/src/hardware/r_opengl/r_opengl.c b/src/hardware/r_opengl/r_opengl.c index 8b48a0438..08d688e1d 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/info.c b/src/info.c index 36806eca3..778f1f741 100644 --- a/src/info.c +++ b/src/info.c @@ -21803,11 +21803,11 @@ skincolor_t skincolors[MAXSKINCOLORS] = { {"Super Orange 4", {0x00, 0xd0, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x44, 0x45, 0x46}, SKINCOLOR_SAPPHIRE, 4, V_ORANGEMAP, false}, // SKINCOLOR_SUPERORANGE4 {"Super Orange 5", {0xd0, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x44, 0x45, 0x46, 0x47}, SKINCOLOR_SAPPHIRE, 3, V_ORANGEMAP, false}, // SKINCOLOR_SUPERORANGE5 - {"Super Gold 1", {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x50, 0x51, 0x52, 0x53, 0x48}, SKINCOLOR_CORNFLOWER, 15, 0, false}, // SKINCOLOR_SUPERGOLD1 - {"Super Gold 2", {0x00, 0x50, 0x51, 0x52, 0x53, 0x53, 0x48, 0x48, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x40, 0x41}, SKINCOLOR_CORNFLOWER, 9, V_YELLOWMAP, false}, // SKINCOLOR_SUPERGOLD2 - {"Super Gold 3", {0x51, 0x52, 0x53, 0x53, 0x48, 0x48, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x40, 0x41, 0x42, 0x43}, SKINCOLOR_CORNFLOWER, 8, V_YELLOWMAP, false}, // SKINCOLOR_SUPERGOLD3 - {"Super Gold 4", {0x53, 0x48, 0x48, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46}, SKINCOLOR_CORNFLOWER, 8, V_YELLOWMAP, false}, // SKINCOLOR_SUPERGOLD4 - {"Super Gold 5", {0x48, 0x48, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47}, SKINCOLOR_CORNFLOWER, 8, V_YELLOWMAP, false}, // SKINCOLOR_SUPERGOLD5 + {"Super Gold 1", {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x50, 0x51, 0x52, 0x53, 0x48, 0x48, 0x48}, SKINCOLOR_CORNFLOWER, 15, 0, false}, // SKINCOLOR_SUPERGOLD1 + {"Super Gold 2", {0x00, 0x50, 0x51, 0x52, 0x53, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x40, 0x41, 0x41, 0x41}, SKINCOLOR_CORNFLOWER, 9, V_YELLOWMAP, false}, // SKINCOLOR_SUPERGOLD2 + {"Super Gold 3", {0x51, 0x52, 0x53, 0x53, 0x48, 0x49, 0x49, 0x49, 0x49, 0x49, 0x40, 0x41, 0x42, 0x43, 0x43, 0x43}, SKINCOLOR_CORNFLOWER, 8, V_YELLOWMAP, false}, // SKINCOLOR_SUPERGOLD3 + {"Super Gold 4", {0x53, 0x48, 0x48, 0x49, 0x49, 0x49, 0x49, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x46, 0x46}, SKINCOLOR_CORNFLOWER, 8, V_YELLOWMAP, false}, // SKINCOLOR_SUPERGOLD4 + {"Super Gold 5", {0x48, 0x48, 0x49, 0x49, 0x49, 0x40, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x47, 0x47}, SKINCOLOR_CORNFLOWER, 8, V_YELLOWMAP, false}, // SKINCOLOR_SUPERGOLD5 {"Super Peridot 1", {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x58, 0x58, 0x58, 0xbc, 0xbc, 0xbc}, SKINCOLOR_COBALT, 15, 0, false}, // SKINCOLOR_SUPERPERIDOT1 {"Super Peridot 2", {0x00, 0x58, 0x58, 0x58, 0xbc, 0xbc, 0xbc, 0xbc, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbe, 0xbe}, SKINCOLOR_COBALT, 4, V_PERIDOTMAP, false}, // SKINCOLOR_SUPERPERIDOT2 diff --git a/src/lua_baselib.c b/src/lua_baselib.c index 775d9ec02..2e05008ca 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -902,6 +902,17 @@ static int lib_pMaceRotate(lua_State *L) return 0; } +static int lib_pRailThinker(lua_State *L) +{ + mobj_t *mobj = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ)); + NOHUD + INLEVEL + if (!mobj) + return LUA_ErrInvalid(L, "mobj_t"); + lua_pushboolean(L, P_RailThinker(mobj)); + return 1; +} + // P_USER //////////// @@ -3259,6 +3270,7 @@ static luaL_Reg lib[] = { {"P_CheckSolidLava",lib_pCheckSolidLava}, {"P_CanRunOnWater",lib_pCanRunOnWater}, {"P_MaceRotate",lib_pMaceRotate}, + {"P_RailThinker",lib_pRailThinker}, // p_user {"P_GetPlayerHeight",lib_pGetPlayerHeight}, diff --git a/src/m_menu.c b/src/m_menu.c index 338d9b1be..ddadec799 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. @@ -1942,7 +1942,7 @@ static menu_t SP_NightsGhostDef = static menu_t SP_MarathonDef = { MTREE2(MN_SP_MAIN, MN_SP_MARATHON), - "M_ATTACK", // temporary + "M_RATHON", sizeof(SP_MarathonMenu)/sizeof(menuitem_t), &MainDef, // Doesn't matter. SP_MarathonMenu, @@ -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) @@ -10709,7 +10708,7 @@ void M_DrawMarathon(void) recatkdrawtimer -= (10*TICRATE); } - //M_DrawMenuTitle(); + M_DrawMenuTitle(); // draw menu (everything else goes on top of it) // Sadly we can't just use generic mode menus because we need some extra hacks diff --git a/src/m_misc.c b/src/m_misc.c index c527d2296..216fde056 100644 --- a/src/m_misc.c +++ b/src/m_misc.c @@ -162,7 +162,7 @@ consvar_t cv_zlib_memorya = {"apng_memory_level", "(Max Memory) 9", CV_SAVE, zli consvar_t cv_zlib_levela = {"apng_compress_level", "4", CV_SAVE, zlib_level_t, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_zlib_strategya = {"apng_strategy", "RLE", CV_SAVE, zlib_strategy_t, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_zlib_window_bitsa = {"apng_window_size", "32k", CV_SAVE, zlib_window_bits_t, NULL, 0, NULL, NULL, 0, 0, NULL}; -consvar_t cv_apng_delay = {"apng_speed", "1/2x", CV_SAVE, apng_delay_t, NULL, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_apng_delay = {"apng_speed", "1x", CV_SAVE, apng_delay_t, NULL, 0, NULL, NULL, 0, 0, NULL}; boolean takescreenshot = false; // Take a screenshot this tic diff --git a/src/p_enemy.c b/src/p_enemy.c index 9571b0b4a..fd30f8e38 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -5214,7 +5214,7 @@ void A_SignPlayer(mobj_t *actor) actor->tracer->color = signcolor; if (signcolor && signcolor < numskincolors) - signframe += (15 - skincolors[facecolor].invshade); + signframe += (15 - skincolors[skincolors[signcolor].invcolor].invshade); actor->tracer->frame = signframe; } 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_mobj.c b/src/p_mobj.c index 62bcad500..c26308a59 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -442,7 +442,7 @@ boolean P_SetPlayerMobjState(mobj_t *mobj, statenum_t state) mobj->sprite2 = spr2; mobj->frame = frame|(st->frame&~FF_FRAMEMASK); - if (mobj->color >= FIRSTSUPERCOLOR && mobj->color < numskincolors) // Super colours? Super bright! + if (player->powers[pw_super] || (player->powers[pw_carry] == CR_NIGHTSMODE && (player->charflags & (SF_SUPER|SF_NONIGHTSSUPER)) == SF_SUPER)) // Super colours? Super bright! mobj->frame |= FF_FULLBRIGHT; } // Regular sprites diff --git a/src/p_setup.c b/src/p_setup.c index 942deecf8..2fd7ba5b0 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -995,17 +995,6 @@ static void P_InitializeSector(sector_t *ss) ss->extra_colormap = NULL; -#ifdef HWRENDER // ----- for special tricks with HW renderer ----- - ss->pseudoSector = false; - ss->virtualFloor = false; - ss->virtualFloorheight = 0; - ss->virtualCeiling = false; - ss->virtualCeilingheight = 0; - ss->sectorLines = NULL; - ss->stackList = NULL; - ss->lineoutLength = -1.0l; -#endif // ----- end special tricks ----- - ss->gravity = NULL; ss->verticalflip = false; ss->flags = SF_FLIPSPECIAL_FLOOR; @@ -3767,7 +3756,7 @@ boolean P_LoadLevel(boolean fromnetsave) if (!lastmaploaded) // Start a new game? { // I'd love to do this in the menu code instead of here, but everything's a mess and I can't guarantee saving proper player struct info before the first act's started. You could probably refactor it, but it'd be a lot of effort. Easier to just work off known good code. ~toast 22/06/2020 - if (!(ultimatemode || netgame || multiplayer || demoplayback || demorecording || metalrecording || modeattacking) + if (!(ultimatemode || netgame || multiplayer || demoplayback || demorecording || metalrecording || modeattacking || marathonmode) && (!modifiedgame || savemoddata) && cursaveslot > 0) G_SaveGame((UINT32)cursaveslot, gamemap); // If you're looking for saving sp file progression (distinct from G_SaveGameOver), check G_DoCompleted. @@ -3825,8 +3814,6 @@ void HWR_SetupLevel(void) HWR_ResetLights(); #endif - // Correct missing sidedefs & deep water trick - HWR_CorrectSWTricks(); HWR_CreatePlanePolygons((INT32)numnodes - 1); } #endif diff --git a/src/p_user.c b/src/p_user.c index df037504e..c62606970 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/r_data.c b/src/r_data.c index b72214996..d10919d81 100644 --- a/src/r_data.c +++ b/src/r_data.c @@ -227,6 +227,8 @@ static inline void R_DrawFlippedColumnInCache(column_t *patch, UINT8 *cache, tex } } +// Blends two pixels together, using the equation +// that matches the specified alpha style. UINT32 ASTBlendPixel(RGBA_t background, RGBA_t foreground, int style, UINT8 alpha) { RGBA_t output; @@ -245,7 +247,13 @@ UINT32 ASTBlendPixel(RGBA_t background, RGBA_t foreground, int style, UINT8 alph // if the background pixel is empty, // match software and don't blend anything if (!background.s.alpha) - output.s.alpha = 0; + { + // ...unless the foreground pixel ISN'T actually translucent. + if (alpha == 0xFF) + output.rgba = foreground.rgba; + else + output.rgba = 0; + } else { UINT8 beta = (0xFF - alpha); @@ -302,18 +310,46 @@ UINT32 ASTBlendPixel(RGBA_t background, RGBA_t foreground, int style, UINT8 alph return 0; } -UINT8 ASTBlendPixel_8bpp(UINT8 background, UINT8 foreground, int style, UINT8 alpha) +INT32 ASTTextureBlendingThreshold[2] = {255/11, (10*255/11)}; + +// Blends a pixel for a texture patch. +UINT32 ASTBlendTexturePixel(RGBA_t background, RGBA_t foreground, int style, UINT8 alpha) { // Alpha style set to translucent? if (style == AST_TRANSLUCENT) { // Is the alpha small enough for translucency? - if (alpha <= (10*255/11)) + if (alpha <= ASTTextureBlendingThreshold[1]) + { + // Is the patch way too translucent? Don't blend then. + if (alpha < ASTTextureBlendingThreshold[0]) + return background.rgba; + + return ASTBlendPixel(background, foreground, style, alpha); + } + else // just copy the pixel + return foreground.rgba; + } + else + return ASTBlendPixel(background, foreground, style, alpha); +} + +// Blends two palette indexes for a texture patch, then +// finds the nearest palette index from the blended output. +UINT8 ASTBlendPaletteIndexes(UINT8 background, UINT8 foreground, int style, UINT8 alpha) +{ + // Alpha style set to translucent? + if (style == AST_TRANSLUCENT) + { + // Is the alpha small enough for translucency? + if (alpha <= ASTTextureBlendingThreshold[1]) { UINT8 *mytransmap; + // Is the patch way too translucent? Don't blend then. - if (alpha < 255/11) + if (alpha < ASTTextureBlendingThreshold[0]) return background; + // The equation's not exact but it works as intended. I'll call it a day for now. mytransmap = transtables + ((8*(alpha) + 255/8)/(255 - 255/11) << FF_TRANSSHIFT); if (background != 0xFF) @@ -378,7 +414,7 @@ static inline void R_DrawBlendColumnInCache(column_t *patch, UINT8 *cache, texpa { for (; dest < cache + position + count; source++, dest++) if (*source != 0xFF) - *dest = ASTBlendPixel_8bpp(*dest, *source, originPatch->style, originPatch->alpha); + *dest = ASTBlendPaletteIndexes(*dest, *source, originPatch->style, originPatch->alpha); } patch = (column_t *)((UINT8 *)patch + patch->length + 4); @@ -422,7 +458,7 @@ static inline void R_DrawBlendFlippedColumnInCache(column_t *patch, UINT8 *cache { for (; dest < cache + position + count; --source, dest++) if (*source != 0xFF) - *dest = ASTBlendPixel_8bpp(*dest, *source, originPatch->style, originPatch->alpha); + *dest = ASTBlendPaletteIndexes(*dest, *source, originPatch->style, originPatch->alpha); } patch = (column_t *)((UINT8 *)patch + patch->length + 4); diff --git a/src/r_data.h b/src/r_data.h index 78ce35a41..8b8d08c52 100644 --- a/src/r_data.h +++ b/src/r_data.h @@ -26,7 +26,10 @@ enum patchalphastyle {AST_COPY, AST_TRANSLUCENT, AST_ADD, AST_SUBTRACT, AST_REVERSESUBTRACT, AST_MODULATE, AST_OVERLAY}; UINT32 ASTBlendPixel(RGBA_t background, RGBA_t foreground, int style, UINT8 alpha); -UINT8 ASTBlendPixel_8bpp(UINT8 background, UINT8 foreground, int style, UINT8 alpha); +UINT32 ASTBlendTexturePixel(RGBA_t background, RGBA_t foreground, int style, UINT8 alpha); +UINT8 ASTBlendPaletteIndexes(UINT8 background, UINT8 foreground, int style, UINT8 alpha); + +extern INT32 ASTTextureBlendingThreshold[2]; UINT8 NearestColor(UINT8 r, UINT8 g, UINT8 b); diff --git a/src/r_defs.h b/src/r_defs.h index a36568192..fd868ee97 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -221,20 +221,6 @@ typedef struct r_lightlist_s INT32 lightnum; } r_lightlist_t; -// ----- for special tricks with HW renderer ----- - -// -// For creating a chain with the lines around a sector -// -typedef struct linechain_s -{ - struct line_s *line; - struct linechain_s *next; -} linechain_t; -// ----- end special tricks ----- - - - // Slopes typedef enum { SL_NOPHYSICS = 1, /// This plane will have no physics applied besides the positioning. @@ -348,17 +334,6 @@ typedef struct sector_s // per-sector colormaps! extracolormap_t *extra_colormap; -#ifdef HWRENDER // ----- for special tricks with HW renderer ----- - boolean pseudoSector; - boolean virtualFloor; - fixed_t virtualFloorheight; - boolean virtualCeiling; - fixed_t virtualCeilingheight; - linechain_t *sectorLines; - struct sector_s **stackList; - double lineoutLength; -#endif // ----- end special tricks ----- - // This points to the master's floorheight, so it can be changed in realtime! fixed_t *gravity; // per-sector gravity boolean verticalflip; // If gravity < 0, then allow flipped physics diff --git a/src/sdl/Srb2SDL-vc10.vcxproj b/src/sdl/Srb2SDL-vc10.vcxproj index beaed6a3b..5592de86b 100644 --- a/src/sdl/Srb2SDL-vc10.vcxproj +++ b/src/sdl/Srb2SDL-vc10.vcxproj @@ -381,7 +381,6 @@ - diff --git a/src/sdl/Srb2SDL-vc10.vcxproj.filters b/src/sdl/Srb2SDL-vc10.vcxproj.filters index 80af94b65..db1aa123f 100644 --- a/src/sdl/Srb2SDL-vc10.vcxproj.filters +++ b/src/sdl/Srb2SDL-vc10.vcxproj.filters @@ -669,9 +669,6 @@ Hw_Hardware - - Hw_Hardware - Hw_Hardware diff --git a/src/sdl/Srb2SDL-vc9.vcproj b/src/sdl/Srb2SDL-vc9.vcproj index d407b2884..cfa49ea50 100644 --- a/src/sdl/Srb2SDL-vc9.vcproj +++ b/src/sdl/Srb2SDL-vc9.vcproj @@ -2546,46 +2546,6 @@ RelativePath="..\hardware\hw_md2.h" > - - - - - - - - - - - - - - diff --git a/src/sdl/Srb2SDL.dsp b/src/sdl/Srb2SDL.dsp index ce35e2e23..9f6dd7b33 100644 --- a/src/sdl/Srb2SDL.dsp +++ b/src/sdl/Srb2SDL.dsp @@ -604,10 +604,6 @@ SOURCE=..\hardware\hw_md2.h # End Source File # Begin Source File -SOURCE=..\hardware\hw_trick.c -# End Source File -# Begin Source File - SOURCE=..\hardware\hws_data.h # End Source File # End Group diff --git a/src/sdl/i_system.c b/src/sdl/i_system.c index 27e015ef7..b24ae2814 100644 --- a/src/sdl/i_system.c +++ b/src/sdl/i_system.c @@ -108,7 +108,7 @@ int TimeFunction(int requested_frequency); #endif #endif -#if (defined (__unix__) && !defined (_MSDOS)) || defined (UNIXCOMMON) +#if (defined (__unix__) && !defined (_MSDOS)) || (defined (UNIXCOMMON) && !defined(__APPLE__)) #include #include #define NEWSIGNALHANDLER diff --git a/src/sdl/macosx/Srb2mac.pbproj/project.pbxproj b/src/sdl/macosx/Srb2mac.pbproj/project.pbxproj index ee0bf4697..909bb2ced 100644 --- a/src/sdl/macosx/Srb2mac.pbproj/project.pbxproj +++ b/src/sdl/macosx/Srb2mac.pbproj/project.pbxproj @@ -1113,13 +1113,6 @@ path = ../../hardware/hw_md2.h; refType = 2; }; - 84177743085A106C000C01D8 = { - fileEncoding = 30; - isa = PBXFileReference; - name = hw_trick.c; - path = ../../hardware/hw_trick.c; - refType = 2; - }; 84177744085A106C000C01D8 = { fileEncoding = 30; isa = PBXFileReference; diff --git a/src/sdl/macosx/Srb2mac.xcodeproj/project.pbxproj b/src/sdl/macosx/Srb2mac.xcodeproj/project.pbxproj index f4d7fdd86..04f8ecc0a 100644 --- a/src/sdl/macosx/Srb2mac.xcodeproj/project.pbxproj +++ b/src/sdl/macosx/Srb2mac.xcodeproj/project.pbxproj @@ -19,7 +19,6 @@ 1E44AE800B67CC2B00BAD059 /* hw_draw.c in Sources */ = {isa = PBXBuildFile; fileRef = 1E44AE6C0B67CC2B00BAD059 /* hw_draw.c */; }; 1E44AE820B67CC2B00BAD059 /* hw_main.c in Sources */ = {isa = PBXBuildFile; fileRef = 1E44AE6E0B67CC2B00BAD059 /* hw_main.c */; }; 1E44AE840B67CC2B00BAD059 /* hw_md2.c in Sources */ = {isa = PBXBuildFile; fileRef = 1E44AE700B67CC2B00BAD059 /* hw_md2.c */; }; - 1E44AE860B67CC2B00BAD059 /* hw_trick.c in Sources */ = {isa = PBXBuildFile; fileRef = 1E44AE720B67CC2B00BAD059 /* hw_trick.c */; }; 1E44AEA40B67CC8500BAD059 /* d_clisrv.c in Sources */ = {isa = PBXBuildFile; fileRef = 1E44AE8D0B67CC8400BAD059 /* d_clisrv.c */; }; 1E44AEA70B67CC8500BAD059 /* d_main.c in Sources */ = {isa = PBXBuildFile; fileRef = 1E44AE900B67CC8400BAD059 /* d_main.c */; }; 1E44AEA80B67CC8500BAD059 /* d_net.c in Sources */ = {isa = PBXBuildFile; fileRef = 1E44AE910B67CC8500BAD059 /* d_net.c */; }; @@ -191,7 +190,6 @@ 1E44AE6F0B67CC2B00BAD059 /* hw_main.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = hw_main.h; path = ../../hardware/hw_main.h; sourceTree = SOURCE_ROOT; }; 1E44AE700B67CC2B00BAD059 /* hw_md2.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = hw_md2.c; path = ../../hardware/hw_md2.c; sourceTree = SOURCE_ROOT; }; 1E44AE710B67CC2B00BAD059 /* hw_md2.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = hw_md2.h; path = ../../hardware/hw_md2.h; sourceTree = SOURCE_ROOT; }; - 1E44AE720B67CC2B00BAD059 /* hw_trick.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = hw_trick.c; path = ../../hardware/hw_trick.c; sourceTree = SOURCE_ROOT; }; 1E44AE730B67CC2B00BAD059 /* hws_data.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = hws_data.h; path = ../../hardware/hws_data.h; sourceTree = SOURCE_ROOT; }; 1E44AE8A0B67CC6000BAD059 /* asm_defs.inc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.pascal; name = asm_defs.inc; path = ../../asm_defs.inc; sourceTree = SOURCE_ROOT; }; 1E44AE8D0B67CC8400BAD059 /* d_clisrv.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = d_clisrv.c; path = ../../d_clisrv.c; sourceTree = SOURCE_ROOT; }; @@ -544,7 +542,6 @@ 1E44AE6F0B67CC2B00BAD059 /* hw_main.h */, 1E44AE700B67CC2B00BAD059 /* hw_md2.c */, 1E44AE710B67CC2B00BAD059 /* hw_md2.h */, - 1E44AE720B67CC2B00BAD059 /* hw_trick.c */, 1E44AE730B67CC2B00BAD059 /* hws_data.h */, ); name = Hw_Hardware; @@ -1078,7 +1075,6 @@ 1E44AE800B67CC2B00BAD059 /* hw_draw.c in Sources */, 1E44AE820B67CC2B00BAD059 /* hw_main.c in Sources */, 1E44AE840B67CC2B00BAD059 /* hw_md2.c in Sources */, - 1E44AE860B67CC2B00BAD059 /* hw_trick.c in Sources */, 1E44AEA40B67CC8500BAD059 /* d_clisrv.c in Sources */, 1E44AEA70B67CC8500BAD059 /* d_main.c in Sources */, 1E44AEA80B67CC8500BAD059 /* d_net.c in Sources */, @@ -1217,7 +1213,7 @@ C01FCF4B08A954540054247B /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - CURRENT_PROJECT_VERSION = 2.2.4; + CURRENT_PROJECT_VERSION = 2.2.6; GCC_PREPROCESSOR_DEFINITIONS = ( "$(inherited)", NORMALSRB2, @@ -1229,7 +1225,7 @@ C01FCF4C08A954540054247B /* Release */ = { isa = XCBuildConfiguration; buildSettings = { - CURRENT_PROJECT_VERSION = 2.2.4; + CURRENT_PROJECT_VERSION = 2.2.6; GCC_ENABLE_FIX_AND_CONTINUE = NO; GCC_GENERATE_DEBUGGING_SYMBOLS = NO; GCC_PREPROCESSOR_DEFINITIONS = ( diff --git a/src/st_stuff.c b/src/st_stuff.c index 53d988913..d5aa5fbac 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -240,8 +240,8 @@ void ST_LoadGraphics(void) int i; // SRB2 border patch - st_borderpatchnum = W_GetNumForName("GFZFLR01"); - scr_borderpatch = W_CacheLumpNum(st_borderpatchnum, PU_HUDGFX); + // st_borderpatchnum = W_GetNumForName("GFZFLR01"); + // scr_borderpatch = W_CacheLumpNum(st_borderpatchnum, PU_HUDGFX); // the original Doom uses 'STF' as base name for all face graphics // Graue 04-08-2004: face/name graphics are now indexed by skins diff --git a/src/win32/Srb2win-vc10.vcxproj b/src/win32/Srb2win-vc10.vcxproj index 72636d60d..6855a4135 100644 --- a/src/win32/Srb2win-vc10.vcxproj +++ b/src/win32/Srb2win-vc10.vcxproj @@ -234,7 +234,6 @@ - diff --git a/src/win32/Srb2win-vc10.vcxproj.filters b/src/win32/Srb2win-vc10.vcxproj.filters index a46eb1e2e..4a980c6bd 100644 --- a/src/win32/Srb2win-vc10.vcxproj.filters +++ b/src/win32/Srb2win-vc10.vcxproj.filters @@ -108,9 +108,6 @@ Hw_Hardware - - Hw_Hardware - Hw_Hardware diff --git a/src/win32/Srb2win-vc9.vcproj b/src/win32/Srb2win-vc9.vcproj index e216212f8..c1c6b5bc4 100644 --- a/src/win32/Srb2win-vc9.vcproj +++ b/src/win32/Srb2win-vc9.vcproj @@ -2287,46 +2287,6 @@ RelativePath="..\hardware\hw_md2.h" > - - - - - - - - - - - - - - diff --git a/src/win32/Srb2win.dsp b/src/win32/Srb2win.dsp index c52873f7b..661f3eaf9 100644 --- a/src/win32/Srb2win.dsp +++ b/src/win32/Srb2win.dsp @@ -563,10 +563,6 @@ SOURCE=..\hardware\hw_md2.h # End Source File # Begin Source File -SOURCE=..\hardware\hw_trick.c -# End Source File -# Begin Source File - SOURCE=..\hardware\hws_data.h # End Source File # End Group diff --git a/src/win32/Srb2win.rc b/src/win32/Srb2win.rc index d7e3383b0..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,0,0 - PRODUCTVERSION 2,2,0,0 + FILEVERSION 2,2,6,0 + PRODUCTVERSION 2,2,6,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L