diff --git a/AppImage_build.sh b/AppImage_build.sh new file mode 100755 index 000000000..2822d00d3 --- /dev/null +++ b/AppImage_build.sh @@ -0,0 +1,346 @@ +#!/bin/bash +set -e # Enable auto-exit for debugging :)) + +# Make Linux AppImage program data +# https://docs.appimage.org/reference/appdir.html + +# PWD: {repo_root}/build +# See deployer.sh for usage + +# Terminal stuff +RESET="$(tput sgr0)" #"\e[0m" # Resets terminal colors + +# Colors for various information types +FAILURE="$(tput setaf 1)" #"\e[91m" +SUCCESS="$(tput setaf 2)" #"\e[92m" +NOTICE="$(tput setaf 3)" #"\e[93m" +VERBOSE="$(tput setaf 4)" #"\e[94m" + +verbosity=0 # By default don't print anything unless it's *ultra* important. +quiet=0 # Also don't print anything if they supplied the quiet argument + +# URL from which to download appimagetool if there isn't one available in your $PATH +# at time of writing only aarch64, armhf, i686, and x86_64 versions are available via this method +# in those cases, and honestly even outside of those cases, it's better to just put a working one in your $PATH yourself.. +url="https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-$(uname -m).AppImage" + +# A whitelist of libraries to include into SRB2's AppImage if SRB2 is dynamically linked. +# please don't add a newline at the end of this or i will cry :( +libraryWhitelist=" +libbacktrace +libnsl +libSDL2 +libSDL2_mixer +libgme +libopenmpt +libpng +libfluidsynth +libpulse +libmodplug +libvorbisfile +libopusfile +libFLAC +libmad +libmpg123 +libvorbis +libpulsecommon +libsndfile +libsndio +libogg +libvorbisenc +libjson +libreadline +libwrap +libtinfo +libtirpc +libpng16" + +# these kinda look like macros don't they +function print { (( "$quiet" == 0 )) && echo "$@" || :; } # echo if not quiet +function coloredText { printf "$1"; print "${@:2}"; printf "$RESET"; } # use print to inherit quiet +function success { coloredText "$SUCCESS" "$@"; } # use coloredText to inherit quiet +function important { coloredText "$NOTICE" "$@"; } # use coloredText to inherit quiet +function verboseOnly { (( "$verbosity" >= $1 )) && (coloredText "$VERBOSE" "${@:2}") || :; } # use coloredText to inherit quiet + +# Parses an argument with a single dash +function parseSingleDashArg() { + while read -n 1 char; do + if [[ "$char" == '-' || "$char" == '' ]]; then + : + elif [[ "$char" == 'h' ]]; then + helppassed=1 + elif [[ "$char" == 'q' ]]; then + quiet=1 + elif [[ "$char" == 'v' ]]; then + verbosity="$((verbosity + 1))" + elif [[ "$char" == 'd' ]]; then + dry=1 + elif [[ "$char" == 's' ]]; then + small=1 + else + echo "$0: invalid option -- '$1'" + echo "Try '$0 --help' for more information." + return 1 + fi + done <<<"$1" +} + +# Simple help argument checker. +currentarg=1; # Which argument is --help... + +# For $arg in the argument array... +for arg in "$@"; do + # Is it a help argument? + if [[ "$arg" == "--help" ]]; then + helppassed=1; # Help is passed, set $helppassed! + set -- "${@:1:$currentarg-1}" "${@:$currentarg+1}" # Remove argument from list + elif [[ "$arg" == "--quiet" ]]; then + quiet=1 + set -- "${@:1:$currentarg-1}" "${@:$currentarg+1}" + elif [[ "$arg" == "--verbose" ]]; then + verbosity="$((verbosity + 1))" # Increase verbosity! + set -- "${@:1:$currentarg-1}" "${@:$currentarg+1}" + elif [[ "$arg" == "--dry" ]]; then + dry=1; # Show parameters instead of using them. + set -- "${@:1:$currentarg-1}" "${@:$currentarg+1}" + elif [[ "$arg" == "--small" ]]; then + small=1; # Don't copy assets to save on bandwidth. + set -- "${@:1:$currentarg-1}" "${@:$currentarg+1}" + elif [[ ! "$arg" == *'--'* && "$arg" == *'-'* ]]; then + parseSingleDashArg "$arg" + + if [[ "$?" == 0 ]]; then + set -- "${@:1:$currentarg-1}" "${@:$currentarg+1}" # Remove argument from list + fi + elif [[ $arg == *'--'* ]]; then + print "$0: invalid option -- '$1'" + print "Try '$0 --help' for more information." + return 1 + else + currentarg="$((currentarg+1))" # Increment current argument number otherwise... + fi +done + +important "SRB2Kart AppImage Packager v1.0 modified for kart by NepDisk." +important "Orignal for SRB2 my mazmazz and Golden." + +# Get root directory from the full path of this script. +__ROOT_DIR="$3" + +if [[ -z "$3" ]]; then + # finds out where this script is and goes to that directory and goes up one for the root + + scriptdir="$(dirname "${BASH_SOURCE[0]}")" + scriptbase="$(basename "${BASH_SOURCE[0]}")" + + __ROOT_DIR="$(cd "$scriptdir" && pwd -P)" +fi + +# If it starts with '.', put the current working directory behind it so things work. +if [[ "$__ROOT_DIR" == '.' || "$__ROOT_DIR" == '..' ]]; then + __ROOT_DIR="$PWD/$__ROOT_DIR" +fi + +# Set up defaults +__PROGRAM_NAME="${PROGRAM_NAME:-"SRB2Kart Saturn"}" +__PROGRAM_DESCRIPTION="${PROGRAM_DESCRIPTION:-"Modded version of SRB2kart with more features."}" +__PROGRAM_FILENAME="${PROGRAM_FILENAME:-"lsdl2srb2kart"}" +__PROGRAM_ASSETS="${PROGRAM_ASSETS:-"$__ROOT_DIR/assets/installer"}" + +__BUILD_DIR="${1:-"$__ROOT_DIR/bin"}" +__OUTPUT_FILENAME="${2:-"$__PROGRAM_FILENAME.AppImage"}" + +__APPIMAGETOOL="${4:-"appimagetool"}" + +if (! command -v "$__APPIMAGETOOL" &> /dev/null); then + __APPIMAGETOOL= +fi + +# Stuff that prints and exits. + +# Prints setup text using method given by arguments. +# Example: printSetup "print" # print "Setup for AppImage... +function printSetup { + $@ "Setup for AppImage in BUILD_DIR: '$__BUILD_DIR'..." + $@ "With the OUTPUT_FILENAME: '$__OUTPUT_FILENAME'" + $@ "And SRB2 Repository Root ROOT_DIR: '$__ROOT_DIR'" + $@ "Using APPIMAGETOOL: '$([ -z "$__APPIMAGETOOL" ] && echo '(download)' || echo $__APPIMAGETOOL)'" + $@ "" + $@ "This should be run from a Makefile or from the directory of the build. If it is not, then change to that directory or specify that directory as an argument." + $@ "If ROOT_DIR isn't SRB2's repository root, specify that as an argument too." + $@ "Make must have built the program before you run this script." + $@ "" + $@ "Make sure these Environment Variables are correct." + $@ "If not, then enter: export PROGRAM_VARIABLE=value" + $@ "PROGRAM_NAME: $__PROGRAM_NAME" + $@ "PROGRAM_DESCRIPTION: $__PROGRAM_DESCRIPTION" + $@ "PROGRAM_FILENAME: $__PROGRAM_FILENAME" + $@ "PROGRAM_ASSETS: $__PROGRAM_ASSETS" +} + +if [[ "$helppassed" ]]; then + print "Usage: $(basename "$0") [OPTION]... [BUILD_DIR] [OUTPUT_NAME] [ROOT_DIR] [APPIMAGETOOL]" + print "Packages a SRB2 binary into an AppImage." + print "OPTIONs may be included anywhere within the arguments." + print "" + print "Arguments:" + print " -h, --help display this help and exit." + print " -q, --quiet don't display any text." + print " -v, --verbose make commands more verbose, will always print." + print " -s, --small don't copy SRB2 assets to save on bandwidth." + print " parameters regardless of --dry." + print " -d, --dry print parameters and exit." + print "" + if (( "$verbosity" > 0 )) || [[ "$dry" ]]; then + printSetup "print" + else + print "This should be run from a Makefile or from the directory of the build." + print "Make must have built the program before you run this script." + fi + exit; +fi + +if (( "$verbosity" > 0 )) || [[ "$dry" ]]; then + printSetup "verboseOnly" "0" + verboseOnly 0 "" + + if [[ "$dry" ]]; then + set -n # Enable debug mode and verbose for dry run. + fi +fi + +# End stuff that prints and exits. + +if (( "$verbosity" >= 4 )); then + set -v # Really verbose? Print *everything*! +fi + +# Define AppDir structure +mkdir -p "$__BUILD_DIR/AppDir/usr/bin" +mkdir -p "$__BUILD_DIR/AppDir/lib" +mkdir -p "$__BUILD_DIR/AppDir/usr/share/applications" +mkdir -p "$__BUILD_DIR/AppDir/usr/share/icons/hicolor/256x256/apps" + +# Copy program data +if [[ ! $small ]]; then + verboseOnly 1 "Packaging program assets..." + cp -r "$__PROGRAM_ASSETS"/* "$__BUILD_DIR/AppDir/usr/bin/" + cp -r "$__BUILD_DIR/$__PROGRAM_FILENAME" "$__BUILD_DIR/AppDir/usr/bin" +else + verboseOnly 1 "Skipping program asset packing, --small or -s passed..." +fi + +verboseOnly 1 "Packaging SRB2..." +verboseOnly 1 "Assuming executable name $__PROGRAM_FILENAME" +cp -r "$__BUILD_DIR/$__PROGRAM_FILENAME" "$__BUILD_DIR/AppDir/usr/bin" + +# Copy required dependencies, but only if the program is dynamically linked. +verboseOnly 1 "Testing if this build is dynamically linked..." + +set +e # Disable auto-exit for ldd. + +srb2Libraries="$(ldd "$__BUILD_DIR/$__PROGRAM_FILENAME")" +exitcode="$?" + +set -e # Enable it again! + +if (( $exitcode == 0 )); then + verboseOnly 1 "This build *is* dynamically linked! Packaging dependencies." + + # read the dynamic libraries of srb2, trim off beginning whitespace, and get the third field seperated by spaces + # this gives us a newline-seperated list of libraries with their full paths. + srb2Libraries="$(echo "$srb2Libraries" | cut -f 2 | cut -d ' ' -f 3)" + + # remove any extraneous newlines around the string + libraryWhitelist="$(echo $libraryWhitelist | head -c -1 | tr ' ' '\n')" + + # replace e.g. 'abc' with '(/abc\b)', and replace newlines with '|'. + # this converts it into a grep regular expression to check for any whitelisted library names. + libraryWhitelist="$(printf "%s" "$libraryWhitelist" | sed 's|.*|(/\0\\b)|' | tr '\n' '|')" + + # grab only the entries that match the regex + __LDD_LIST="$(printf "%s" "$srb2Libraries" | grep -E "$libraryWhitelist")" + + # use echo to convert the newline-seperated list into an argument list + __LDD_LIST="$(echo $__LDD_LIST)" + + # read into an array because i can't be bothered iterating the lines of a string today + # there's so many other things in this file that'd need to be adjusted to be POSIX-compliant anyway + IFS=' ' read -r -a paths <<< "$__LDD_LIST" + + for path in "${paths[@]}"; do + if [ -f "$path" ]; then + verboseOnly 2 "Packaging dependency $(basename "$path")..." + cp "$path" $__BUILD_DIR/AppDir/lib/ + else + verboseOnly 2 "Dependency $(basename "$path") not found" + fi + done +else + verboseOnly 1 "This SRB2 build is statically linked, skipping dependency packing." +fi + +cd "$__BUILD_DIR/AppDir" + +# Copy icons +verboseOnly 1 "Packaging resources..." +cp "$__ROOT_DIR/srb2.png" "./usr/share/icons/hicolor/256x256/apps/$__PROGRAM_FILENAME.png" +ln -sf "./usr/share/icons/hicolor/256x256/apps/$__PROGRAM_FILENAME.png" "./.DirIcon" +ln -sf "./usr/share/icons/hicolor/256x256/apps/$__PROGRAM_FILENAME.png" "./$__PROGRAM_FILENAME.png" + +# Make desktop descriptor +cat > "./usr/share/applications/$__PROGRAM_FILENAME.desktop" < ./AppRun +echo -e 'HERE="$(dirname "$(readlink -f "${0}")")"' >> ./AppRun +echo -e 'SRB2WADDIR=$HERE/usr/bin LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$HERE/lib exec $HERE/usr/bin/'"$__PROGRAM_FILENAME"' "$@"' >> ./AppRun +chmod +x ./AppRun + +cd .. # now in $__BUILD_DIR + +# Package AppImage +if [ -z "$__APPIMAGETOOL" ]; then + verboseOnly 1 "No valid appimagetool path given or detected, downloading appimagetool..." + + # Print notice for internet connection. + important "If the command hangs here, check your internet connection, or download appimagetool and add it to your \$PATH and try compiling again." + + (( "$verbosity" >= 3 )) && wget "$url" || wget -q "$url" + + APPIMAGETOOL="./$(basename "$url")" + chmod a+x "$APPIMAGETOOL" +else + verboseOnly 1 "appimagetool path given or detected, no download required." + APPIMAGETOOL="$__APPIMAGETOOL" +fi + +verboseOnly 1 "Packing AppImage $__OUTPUT_FILENAME" + +if (( verbosity >= 3 )); then + "$APPIMAGETOOL" ./AppDir "$__OUTPUT_FILENAME" +elif (( verbosity >= 2 )); then + "$APPIMAGETOOL" ./AppDir "$__OUTPUT_FILENAME" >/dev/null +else + "$APPIMAGETOOL" ./AppDir "$__OUTPUT_FILENAME" >/dev/null 2>&1 +fi + +success "AppImage ready!" +verboseOnly 1 "Cleaning up files..." +rm -r ./AppDir + +if [ -z "$__APPIMAGETOOL" ]; then + rm "$APPIMAGETOOL" +fi + +cd "$__ROOT_DIR" # snap back to reality diff --git a/LUASTUFF.md b/LUASTUFF.md index 05ca33bd0..d753723f1 100644 --- a/LUASTUFF.md +++ b/LUASTUFF.md @@ -52,6 +52,70 @@ Returns the displayplayer's HUD color. Returns true if colorization is enabled, false otherwise. +## v.interpolate(true) + +Enables HUD interpolation. Each call to a drawing function will have its coordinates interpolated +by assigning an unique ID to every call. +For example, three successive calls to `v.draw` will each have their own ID and interpolation offsets. +Pass `true` to enable interpolation, `false` to disable. + +Alternatively, pass a number to enable interpolation with the specified tag. +Tags allow HUD items drawn by the same call to a drawing function to be differentiated. +Valid tags range from 0-255. +For example, when iterating players, use a unique tag for each player to avoid artifacting: +```lua +for p in players.iterate do + -- enable interpolation, using player numbers as the tag + -- every draw will have different interp offsets per player + v.interpolate(#p) + + -- doesn't matter for unconditional draws like this one... + v.draw(...) + + -- but it does matter if there's a condition! + -- without tags, this patch would warp between players + -- whenever their `someVar` changes + if p.someVar then v.draw(...) end +end + +-- don't want interpolation anymore? then disable it +v.interpolate(false) +``` +NOTE: The default tag for `true` is 0. + +## v.interpLatch(true) + +Enables interpolation offset latching. The next call to a drawing function will have its lerp offsets +saved and reused for all following draw calls. Disable with `false` when done. +Interpolation cannot easily "snap" between two points; latching can help overcome this by manually +setting the lerp offsets. +```lua +v.interpolate(true) + +-- X coordinate for the HUD item +-- every so often, this will wrap around to zero +local x = (leveltime*4) % 256 + +-- draw an interpolated patch, but... when X rolls back to zero, +-- the patch will slide all the way across the screen! +v.draw(x, 100, ...) + +-- this is where interpLatch comes into play +-- enable latching, then draw an invisible patch, +-- moving at the same speed as the visible patch +-- the exact coordinates don't matter, it just has to move at the right speed +v.interpLatch(true) +v.draw(leveltime*4, 0, v.cachePatch("K_TRNULL")) + +-- now we can draw the patch again, and when X becomes zero, +-- it'll snap right back without sliding across the screen +v.draw(x, 150, ...) + +-- don't forget to turn off latching! +v.interpLatch(false) +``` +When using a custom string drawer, enable this mode to avoid interpolation artifacting when the string changes. + ## mobj.spritexscale, mobj.spriteyscale, mobj.spritexoffset, mobj.spriteyoffset, mobj.rollangle, mobj.sloperoll, mobj.rollmodel fields Same fields as in SRB2 2.2 @@ -66,3 +130,36 @@ if rawget(_G, "S_StopSoundByNum") ~= nil then ... -- Can use it end ``` +## addHook("ServerJoin", function()) + +ServerJoin hook called when client joins server (starting a listen server also calls it for host). +Generally it was made to make loading custom config files less hacky, but can be used for anything else too. + +## player.viewrollangle field + +Returns player's current view roll angle for the Screen Tilting feature, useful for HUD elements. + +## G_SetPlayerGamepadIndicatorColor(player, skincolor) + +Set a custom color for Supported Gamepads with RGB LED functionality. +To be used with Displayplayers. +Only takes Skincolors. +Best to be used in a Loop to ensure the color wont get overwritten by the game. + +## G_PlayerDeviceRumble(player, low_strength, high_strength, -optional- duration) + +Add Gamepad Rumble support for things. +To be used with Displayplayers. +Duration is in milliseconds and is optional to set, default value is 84ms. + +# Other changes + +## P_PlayRinglossSound(source, damager) + +Add optional `damager` argument (should be `mobj_t`), which causes hurt sound also play for damager +if `karthitemdialog` option is enabled + +## K_PlayHitEmSound(mobj, victim) + +Add optional `victim` argument (should be a player's `mobj_t`), which causes "hit em" sound to be +delayed and played for victim too if `karthitemdialog` option is enabled diff --git a/bin/Linux64/Release/.gitignore b/bin/Linux64/Release/.gitignore index 56dee6f95..c63fd53bc 100644 --- a/bin/Linux64/Release/.gitignore +++ b/bin/Linux64/Release/.gitignore @@ -1 +1 @@ -/lsdlsrb2 +/lsdl2srb2kart diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index b4bb035af..258ff882c 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -167,6 +167,7 @@ set(SRB2_CORE_GAME_SOURCES p_telept.c p_tick.c p_user.c + k_director.c k_kart.c i_time.c @@ -180,6 +181,7 @@ set(SRB2_CORE_GAME_SOURCES p_slopes.h p_spec.h p_tick.h + k_director.h k_kart.h ) @@ -465,7 +467,6 @@ if(${SRB2_CONFIG_HWRENDER}) ${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_cache.c ${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_clip.c ${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_draw.c - ${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_light.c ${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_main.c ${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_md2.c ${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_md2load.c @@ -483,7 +484,6 @@ if(${SRB2_CONFIG_HWRENDER}) ${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_dll.h ${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_drv.h ${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_glob.h - ${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_light.h ${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_main.h ${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_md2.h ${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_md2load.h diff --git a/src/Makefile b/src/Makefile index 20f33a471..4668518b9 100644 --- a/src/Makefile +++ b/src/Makefile @@ -106,6 +106,8 @@ ifeq ($(OS),Windows_NT) # all windows are Windows_NT... else # if you on the *nix + NOUPX=1 + system:=$(shell uname -s) ifeq ($(system),Linux) @@ -205,6 +207,18 @@ USE_FBO_OGL=1 endif endif +ifndef NONET +ifndef NOSATURNSYNCH +DOSATURNSYNCH=1 +ifndef NOSATURNJOIN +DOSATURNJOIN=1 +endif +#ifndef NOSATURNPAK +#DOSATURNPAK=1 +#endif +endif +endif + ifdef MINGW include win32/Makefile.cfg endif #ifdef MINGW @@ -278,12 +292,12 @@ ifdef NOHW OPTS+=-DNOHW else OPTS+=-DHWRENDER - OBJS+=$(OBJDIR)/hw_bsp.o $(OBJDIR)/hw_draw.o $(OBJDIR)/hw_light.o \ + OBJS+=$(OBJDIR)/hw_bsp.o $(OBJDIR)/hw_draw.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 $(OBJDIR)/hw_shaders.o endif -OPTS += -DCOMPVERSION +OPTS += -DCOMPVERSION -fwrapv ifndef NONX86 ifndef GCC29 @@ -384,6 +398,18 @@ OPTS+=-DUSE_FBO_OGL endif endif +ifndef NONET +ifndef NOSATURNSYNCH +OPTS+=-DDOSATURNSYNCH +ifndef NOSATURNJOIN +OPTS+=-DDOSATURNJOIN +endif +#ifndef NOSATURNPAK +#OPTS+=-DDOSATURNPAK +#endif +endif +endif + ifdef HAVE_MINIUPNPC ifdef NONET HAVE_MINIUPNPC='' @@ -492,6 +518,7 @@ OBJS:=$(i_main_o) \ $(OBJDIR)/hu_stuff.o \ $(OBJDIR)/y_inter.o \ $(OBJDIR)/st_stuff.o \ + $(OBJDIR)/k_director.o \ $(OBJDIR)/k_kart.o \ $(OBJDIR)/m_aatree.o \ $(OBJDIR)/m_anigif.o \ @@ -630,6 +657,17 @@ ifndef NOUPX -$(UPX) $(UPX_OPTS) $(BIN)/$(EXENAME) endif endif + +ifdef APPIMAGE + @echo Building AppImage... +ifdef APPIMAGE_NOASSETS + $(.)../AppImage_build.sh --small --quiet $(BIN)/ +else + $(.)../AppImage_build.sh -q $(BIN)/ +endif + @echo AppImage build complete, please look for $(EXENAME).AppImage in $(BIN) +endif + @echo Build is done, please look for $(EXENAME) in $(BIN), \(checking for post steps\) reobjdump: diff --git a/src/Makefile.cfg b/src/Makefile.cfg index 77779f7d5..cba731b9c 100644 --- a/src/Makefile.cfg +++ b/src/Makefile.cfg @@ -12,7 +12,7 @@ # to avoid a false positive with the version detection... SUPPORTED_GCC_VERSIONS:=\ - 141 14\ + 142 141 140 14\ 132 131 130 13\ 123 122 121 120 12\ 114 113 112 111 110 11\ @@ -24,7 +24,7 @@ SUPPORTED_GCC_VERSIONS:=\ 55 54 53 52 51 50\ 49 48 47 46 45 44 43 42 41 40 -LATEST_GCC_VERSION=14.1 +LATEST_GCC_VERSION=14.2.1 # gcc or g++ ifdef PREFIX @@ -78,12 +78,20 @@ ifeq (,$(filter GCC%,$(.VARIABLES))) endif endif -ifdef GCC141 +ifdef GCC142 GCC141=1 endif +ifdef GCC141 +GCC140=1 +endif + ifdef GCC14 -GCC14=1 +GCC140=1 +endif + +ifdef GCC140 +GCC132=1 endif ifdef GCC132 @@ -437,9 +445,6 @@ endif ifdef GCC44 WFLAGS+=-Wno-error=array-bounds endif -ifdef GCC45 -opts+=-fwrapv -endif ifdef GCC46 WFLAGS+=-Wno-error=suggest-attribute=noreturn endif diff --git a/src/am_map.c b/src/am_map.c index 666113ddb..d94ec7262 100644 --- a/src/am_map.c +++ b/src/am_map.c @@ -1015,6 +1015,9 @@ static inline void AM_drawPlayers(void) { if (!playeringame[i] || players[i].spectator) continue; + + if (!players[i].mo) + continue; p = &players[i]; if (p->skincolor > 0) diff --git a/src/console.c b/src/console.c index 90212469e..5c2e04eb3 100644 --- a/src/console.c +++ b/src/console.c @@ -43,8 +43,12 @@ #ifdef HAVE_THREADS I_mutex con_mutex; -# define Lock_state() I_lock_mutex(&con_mutex) -# define Unlock_state() I_unlock_mutex(con_mutex) +// g_in_exiting_signal_handler is an evil hack +// to avoid infinite SIGABRT recursion in the signal handler +// due to poisoned locks or mach-o kernel not supporting locks in signals +// or something like that. idk +# define Lock_state() if (!g_in_exiting_signal_handler) { I_lock_mutex(&con_mutex); } +# define Unlock_state() if (!g_in_exiting_signal_handler) { I_unlock_mutex(con_mutex); } #else/*HAVE_THREADS*/ # define Lock_state() # define Unlock_state() @@ -846,9 +850,36 @@ static void CON_InputAddString(const char *c) Unlock_state(); } +static void CON_InputDel(size_t start, size_t end) +{ + size_t len; + + Lock_state(); + + len = (end - start); + + if (end != input_len) + memmove(&inputlines[inputline][start], &inputlines[inputline][end], input_len-end); + memset(&inputlines[inputline][input_len - len], 0, len); + + input_len -= len; + + if (input_sel >= end) + input_sel -= len; + else if (input_sel > start) + input_sel = start; + + if (input_cur >= end) + input_cur -= len; + else if (input_cur > start) + input_cur = start; + + Unlock_state(); +} + static void CON_InputDelSelection(void) { - size_t start, end, len; + size_t start, end; Lock_state(); @@ -862,18 +893,56 @@ static void CON_InputDelSelection(void) start = input_cur; end = input_sel; } - len = (end - start); - if (end != input_len) - memmove(&inputlines[inputline][start], &inputlines[inputline][end], input_len-end); - memset(&inputlines[inputline][input_len - len], 0, len); + CON_InputDel(start, end); - input_len -= len; input_sel = input_cur = start; Unlock_state(); } +static void CON_ToWordEnd(boolean move_sel) +{ + Lock_state(); + + // Skip spaces + while (input_cur < input_len && isspace(inputlines[inputline][input_cur])) + ++input_cur; + + // Skip word + while (input_cur < input_len && !isspace(inputlines[inputline][input_cur])) + ++input_cur; + + if (move_sel) input_sel = input_cur; + + Unlock_state(); +} + +static void CON_ToWordBegin(boolean move_sel) +{ + Lock_state(); + + // Hack, always move back 1 character if possible so if we press ctrl-left at a word beginning + // we move to previous word + if (input_cur) --input_cur; + + // Skip spaces + while (input_cur && isspace(inputlines[inputline][input_cur])) + --input_cur; + + // Skip word + while (input_cur && !isspace(inputlines[inputline][input_cur])) + --input_cur; + + // Unless we reached beginning of line, we're pointing at a space before word, so move cursor + // forward to fix that + if (input_cur) ++input_cur; + + if (move_sel) input_sel = input_cur; + + Unlock_state(); +} + static void CON_InputAddChar(char c) { if (input_len >= CON_MAXPROMPTCHARS-1) @@ -1051,6 +1120,38 @@ boolean CON_Responder(event_t *ev) completion[0] = 0; return true; } + else if (key == 'w' || key == 'W') + { + size_t word_start, word_end, i; + word_end = i = input_cur; + + // Unless we're pointing at the beginning of line, decrement i so we only start + // removing symbols that come before the cursor + if (i) --i; + + // We might be pointing to spaces, skip them first + while (i && isspace(inputlines[inputline][i])) + --i; + + // Now skip the "word" + while (i && !isspace(inputlines[inputline][i])) + --i; + + // Unless we reached beginning of line, i is pointing at first space that was found + // before word start, and we don't want to remove it + if (i) ++i; + + word_start = i; + + if (word_start != word_end) + CON_InputDel(word_start, word_end); + + return true; + } + else if (key == KEY_RIGHTARROW) + CON_ToWordEnd(!shiftdown); + else if (key == KEY_LEFTARROW) + CON_ToWordBegin(!shiftdown); // Select all if (key == 'a' || key == 'A') diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 471d329a4..b6eb9930b 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -10,6 +10,7 @@ /// \file d_clisrv.c /// \brief SRB2 Network game communication and protocol, all OS independent parts. +#include "doomdef.h" #include #ifdef __GNUC__ #include //for unlink @@ -23,6 +24,7 @@ #include "d_netfil.h" // fileneedednum #include "d_main.h" #include "g_game.h" +#include "m_menu.h" // M_ClearMenus #include "hu_stuff.h" #include "keys.h" #include "g_input.h" // JOY1 @@ -75,6 +77,8 @@ #define MAX_REASONLENGTH 30 #define FORCECLOSE 0x8000 +static long long unsigned packetstat[NUMPACKETTYPE+1] = {0}; + boolean server = true; // true or false but !server == client #define client (!server) boolean nodownload = false; @@ -89,6 +93,10 @@ UINT8 playernode[MAXPLAYERS]; // The actual timeout will be longer depending on the savegame length tic_t jointimeout = (3*TICRATE); static boolean sendingsavegame[MAXNETNODES]; // Are we sending the savegame? +#ifdef SATURNSYNCH +static boolean resendingsavegame[MAXNETNODES]; // Are we resending the savegame? +static tic_t savegameresendcooldown[MAXNETNODES]; // How long before we can resend again? +#endif static tic_t freezetimeout[MAXNETNODES]; // Until when can this node freeze the server before getting a timeout? UINT16 pingmeasurecount = 1; @@ -121,6 +129,12 @@ static UINT8 resynch_local_inprogress = false; // WE are desynched and getting p static UINT8 player_joining = false; UINT8 hu_resynching = 0; +#ifdef SATURNSYNCH +UINT8 hu_redownloadinggamestate = 0; +static boolean can_receive_gamestate[MAXNETNODES]; +static UINT8 gamestate_resend_counter[MAXNETNODES]; +#endif + // kart, true when a player is connecting or disconnecting so that the gameplay has stopped in its tracks UINT8 hu_stopped = 0; @@ -133,6 +147,18 @@ static boolean cl_packetmissed; // here it is for the secondary local player (splitscreen) static UINT8 mynode; // my address pointofview server +#ifdef SATURNSYNCH +static boolean cl_redownloadinggamestate = false; +#endif + +#ifdef SATURNPAK +boolean is_client_saturn[MAXNETNODES]; +#endif + +#ifdef SATURNJOIN +#define ISSATURN 69 +#endif + static UINT8 localtextcmd[MAXTEXTCMD]; static UINT8 localtextcmd2[MAXTEXTCMD]; // splitscreen static UINT8 localtextcmd3[MAXTEXTCMD]; // splitscreen == 2 @@ -169,7 +195,6 @@ typedef struct textcmdtic_s ticcmd_t netcmds[TICQUEUE][MAXPLAYERS]; static textcmdtic_t *textcmds[TEXTCMD_HASH_SIZE] = {NULL}; - consvar_t cv_showjoinaddress = {"showjoinaddress", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_shownodeip = {"showipinnodelist", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; @@ -220,7 +245,7 @@ UINT16 software_MAXPACKETLENGTH; * \return The full tic value * */ -tic_t ExpandTics(INT32 low, tic_t basetic) +static inline tic_t ExpandTics(INT32 low, tic_t basetic) { INT32 delta; @@ -1333,9 +1358,13 @@ static inline void CL_DrawConnectionStatus(void) { strncpy(tempname, filename, sizeof(tempname)-1); } - +#ifdef HAVE_CURL V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT-58-30, 0, va(M_GetText("%s downloading"), ((cl_mode == CL_DOWNLOADHTTPFILES) ? "\x82""HTTP" : "\x85""Direct"))); +#else + V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT-58-30, 0, + va(M_GetText("%s downloading"),("\x85""Direct"))); +#endif V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT-58-22, V_YELLOWMAP, va(M_GetText("\"%s\""), tempname)); V_DrawString(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-58, V_20TRANS|V_MONOSPACE, @@ -1423,6 +1452,9 @@ static boolean CL_SendJoin(void) netbuffer->u.clientcfg.subversion = SUBVERSION; strncpy(netbuffer->u.clientcfg.application, SRB2APPLICATION, sizeof netbuffer->u.clientcfg.application); +#ifdef SATURNJOIN + netbuffer->u.clientcfg.issaturn = ISSATURN; +#endif return HSendPacket(servernode, false, 0, sizeof (clientconfig_pak)); } @@ -1720,23 +1752,23 @@ static boolean SV_SendServerConfig(INT32 node) netbuffer->u.servercfg.discordinvites = (boolean)cv_discordinvites.value; memcpy(netbuffer->u.servercfg.server_context, server_context, 8); + op = p = netbuffer->u.servercfg.varlengthinputs; CV_SavePlayerNames(&p); CV_SaveNetVars(&p, false); - { - const size_t len = sizeof (serverconfig_pak) + (size_t)(p - op); + + const size_t len = sizeof (serverconfig_pak) + (size_t)(p - op); #ifdef DEBUGFILE - if (debugfile) - { - fprintf(debugfile, "ServerConfig Packet about to be sent, size of packet:%s to node:%d\n", - sizeu1(len), node); - } + if (debugfile) + { + fprintf(debugfile, "ServerConfig Packet about to be sent, size of packet:%s to node:%d\n", + sizeu1(len), node); + } #endif - waspacketsent = HSendPacket(node, true, 0, len); - } + waspacketsent = HSendPacket(node, true, 0, len); #ifdef DEBUGFILE if (debugfile) @@ -1758,7 +1790,7 @@ static boolean SV_SendServerConfig(INT32 node) #ifdef JOININGAME #define SAVEGAMESIZE (768*1024) -static void SV_SendSaveGame(INT32 node) +static void SV_SendSaveGame(INT32 node, boolean resending) { size_t length, compressedlen; UINT8 *savebuffer; @@ -1776,7 +1808,7 @@ static void SV_SendSaveGame(INT32 node) // Leave room for the uncompressed length. save_p = savebuffer + sizeof(UINT32); - P_SaveNetGame(); + P_SaveNetGame(resending); length = save_p - savebuffer; if (length > SAVEGAMESIZE) @@ -1849,7 +1881,7 @@ static void SV_SavedGame(void) return; } - P_SaveNetGame(); + P_SaveNetGame(false); length = save_p - savebuffer; if (length > SAVEGAMESIZE) @@ -1871,8 +1903,7 @@ static void SV_SavedGame(void) #endif #define TMPSAVENAME "$$$.sav" - -static void CL_LoadReceivedSavegame(void) +static void CL_LoadReceivedSavegame(boolean reloading) { UINT8 *savebuffer = NULL; size_t length, decompressedlen; @@ -1906,39 +1937,24 @@ static void CL_LoadReceivedSavegame(void) demo.title = false; automapactive = false; - if (!postautoloaded) - { - CONS_Printf("D_AutoloadFile(): Loading autoloaded addons...\n"); - if (W_AddAutoloadedLocalFiles(autoloadwadfilespost) == 0) - CONS_Printf("D_AutoloadFile(): Are you sure you put in valid files or what?\n"); - D_CleanFile(autoloadwadfilespost); - postautoloaded = true; - } - // load a base level - if (P_LoadNetGame()) + if (P_LoadNetGame(reloading)) { - CON_LogMessage(va(M_GetText("Map is now \"%s"), G_BuildMapName(gamemap))); - if (strlen(mapheaderinfo[gamemap-1]->lvlttl) > 0) + if (!reloading) { - CON_LogMessage(va(": %s", mapheaderinfo[gamemap-1]->lvlttl)); - if (strlen(mapheaderinfo[gamemap-1]->zonttl) > 0) - CON_LogMessage(va(" %s", mapheaderinfo[gamemap-1]->zonttl)); - else if (!(mapheaderinfo[gamemap-1]->levelflags & LF_NOZONE)) - CON_LogMessage(M_GetText(" Zone")); - if (strlen(mapheaderinfo[gamemap-1]->actnum) > 0) - CON_LogMessage(va(" %s", mapheaderinfo[gamemap-1]->actnum)); + CON_LogMessage(va(M_GetText("Map is now \"%s"), G_BuildMapName(gamemap))); + if (strlen(mapheaderinfo[gamemap-1]->lvlttl) > 0) + { + CON_LogMessage(va(": %s", mapheaderinfo[gamemap-1]->lvlttl)); + if (strlen(mapheaderinfo[gamemap-1]->zonttl) > 0) + CON_LogMessage(va(" %s", mapheaderinfo[gamemap-1]->zonttl)); + else if (!(mapheaderinfo[gamemap-1]->levelflags & LF_NOZONE)) + CON_LogMessage(M_GetText(" Zone")); + if (strlen(mapheaderinfo[gamemap-1]->actnum) > 0) + CON_LogMessage(va(" %s", mapheaderinfo[gamemap-1]->actnum)); + } + CON_LogMessage("\"\n"); } - CON_LogMessage("\"\n"); - } - else - { - CONS_Alert(CONS_ERROR, M_GetText("Can't load the level!\n")); - Z_Free(savebuffer); - save_p = NULL; - if (unlink(tmpsave) == -1) - CONS_Alert(CONS_ERROR, M_GetText("Can't delete %s\n"), tmpsave); - return; } // done @@ -1948,20 +1964,61 @@ static void CL_LoadReceivedSavegame(void) CONS_Alert(CONS_ERROR, M_GetText("Can't delete %s\n"), tmpsave); consistancy[gametic%TICQUEUE] = Consistancy(); CON_ToggleOff(); + +#ifdef SATURNSYNCH + // Tell the server we have received and reloaded the gamestate + // so they know they can resume the game + if (reloading) + { + netbuffer->packettype = PT_RECEIVEDGAMESTATE; + HSendPacket(servernode, true, 0, 0); + } +#endif } + +#ifdef SATURNSYNCH +static void CL_ReloadReceivedSavegame(void) +{ + INT32 i; + + for (i = 0; i < MAXPLAYERS; i++) + { + LUA_InvalidatePlayer(&players[i]); + sprintf(player_names[i], "Player %d", i + 1); + } + + CL_LoadReceivedSavegame(true); + + if (neededtic < gametic) + neededtic = gametic; + maketic = neededtic; + + // set camera angle to somewhat match where your player is turning + for (i = 0; i <= splitscreen; i++) + { + localangle[i] = players[displayplayers[i]].cmd.angleturn<<16; + } + + camera->subsector = R_PointInSubsector(camera->x, camera->y); + + cl_redownloadinggamestate = false; + + CONS_Printf(M_GetText("Game state reloaded\n")); +} +#endif #endif #ifndef NONET static void SendAskInfo(INT32 node) { tic_t asktime; - #ifdef HOLEPUNCH +#ifdef HOLEPUNCH if (node != 0 && node != BROADCASTADDR && cv_rendezvousserver.string[0]) { I_NetRequestHolePunch(node); } - #endif +#endif asktime = I_GetTime(); @@ -2170,7 +2227,9 @@ static void M_ConfirmConnect(event_t *ev) static void AbortConnection(void) { +#ifdef HAVE_CURL CURLAbortFile(); +#endif D_QuitNetGame(); CL_Reset(); D_StartTitle(); @@ -2559,7 +2618,7 @@ static boolean CL_ServerConnectionTicker(const char *tmpsave, tic_t *oldtic, tic if (fileneeded[0].status == FS_FOUND) { // Gamestate is now handled within CL_LoadReceivedSavegame() - CL_LoadReceivedSavegame(); + CL_LoadReceivedSavegame(false); cl_mode = CL_CONNECTED; break; } // don't break case continue to CL_CONNECTED @@ -2584,7 +2643,6 @@ static boolean CL_ServerConnectionTicker(const char *tmpsave, tic_t *oldtic, tic // Call it only once by tic if (*oldtic != I_GetTime()) { - INT32 key; I_OsPolling(); @@ -3040,8 +3098,17 @@ static void Command_connect(void) if (Playing() || demo.title) { - CONS_Printf(M_GetText("You cannot connect while in a game. End this game first.\n")); - return; + M_ClearMenus(true); + if (demo.title) + G_CheckDemoStatus(); + + if (netgame) + { + D_QuitNetGame(); + CL_Reset(); + } + + D_StartTitle(); } // modified game check: no longer handled @@ -3100,6 +3167,17 @@ static void Command_connect(void) botskin = 0; CL_ConnectToServer(); } + +static void Command_Packetstat(void) +{ + CONS_Printf("Number of packets handled:\n"); + + for (UINT8 i = 0; i <= NUMPACKETTYPE; ++i) + { + CONS_Printf("%16s: %llu%s", Net_GetPacketName(i), packetstat[i], (i % 2 == 1) ? "\n" : "\t|\t"); + } +} + #endif static void ResetNode(INT32 node); @@ -3142,10 +3220,15 @@ void CL_RemovePlayer(INT32 playernum, INT32 reason) playerpernode[node]--; if (playerpernode[node] <= 0) { - // If a resynch was in progress, well, it no longer needs to be. - SV_InitResynchVars(node); + SV_InitResynchVars(node); // If a resynch was in progress, well, it no longer needs to be. nodeingame[node] = false; +#ifdef SATURNPAK + is_client_saturn[node] = false; +#endif +#ifdef SATURNSYNCH + can_receive_gamestate[node] = false; +#endif Net_CloseConnection(node); ResetNode(node); } @@ -3251,6 +3334,9 @@ void CL_Reset(void) if (servernode > 0 && servernode < MAXNETNODES) { nodeingame[(UINT8)servernode] = false; +#ifdef SATURNPAK + is_client_saturn[(UINT8)servernode] = false; +#endif Net_CloseConnection(servernode); } D_CloseConnection(); // netgame = false @@ -3265,6 +3351,7 @@ void CL_Reset(void) // make sure we don't leave any fileneeded gunk over from a failed join fileneedednum = 0; memset(fileneeded, 0, sizeof(fileneeded)); + memset(packetstat, 0, sizeof(packetstat)); #ifndef NONET totalfilesrequestednum = 0; @@ -3945,6 +4032,36 @@ static void Command_list_http_logins (void) } #endif/*HAVE_CURL*/ +#ifdef SATURNSYNCH +static void Command_ResendGamestate(void) +{ + SINT8 playernum; + + if (COM_Argc() == 1) + { + CONS_Printf(M_GetText("resendgamestate : resend the game state to a player\n")); + return; + } + else if (client) + { + CONS_Printf(M_GetText("Only the server can use this.\n")); + return; + } + + playernum = nametonum(COM_Argv(1)); + if (playernum == -1 || playernum == 0) + return; + + // Send a PT_WILLRESENDGAMESTATE packet to the client so they know what's going on + netbuffer->packettype = PT_WILLRESENDGAMESTATE; + if (!HSendPacket(playernode[playernum], true, 0, 0)) + { + CONS_Alert(CONS_ERROR, M_GetText("A problem occured, please try again.\n")); + return; + } +} +#endif + static CV_PossibleValue_t netticbuffer_cons_t[] = {{0, "MIN"}, {3, "MAX"}, {0, NULL}}; consvar_t cv_netticbuffer = {"netticbuffer", "1", CV_SAVE, netticbuffer_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; @@ -3954,6 +4071,10 @@ consvar_t cv_joinrefusemessage = {"joinrefusemessage", "The server is not accept consvar_t cv_allownewplayer = {"allowjoin", "On", CV_SAVE|CV_CALL, CV_OnOff, Joinable_OnChange, 0, NULL, NULL, 0, 0, NULL}; +#ifdef SATURNJOIN +consvar_t cv_allownewsaturnplayer = {"allowsaturnjoin", "On", CV_HIDEN, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; +#endif + #ifdef VANILLAJOINNEXTROUND consvar_t cv_joinnextround = {"joinnextround", "Off", CV_SAVE|CV_NETVAR, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; /// \todo not done #endif @@ -3966,7 +4087,16 @@ static CV_PossibleValue_t discordinvites_cons_t[] = {{0, "Admins Only"}, {1, "Ev consvar_t cv_discordinvites = {"discordinvites", "Everyone", CV_SAVE|CV_CALL, discordinvites_cons_t, Joinable_OnChange, 0, NULL, NULL, 0, 0, NULL}; static CV_PossibleValue_t resynchattempts_cons_t[] = {{0, "MIN"}, {20, "MAX"}, {0, NULL}}; -consvar_t cv_resynchattempts = {"resynchattempts", "2", CV_SAVE, resynchattempts_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL }; +consvar_t cv_resynchattempts = {"resynchattempts", "2", CV_SAVE, resynchattempts_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; + +#ifdef SATURNSYNCH +static CV_PossibleValue_t gamestateattempts_cons_t[] = {{0, "MIN"}, {30, "MAX"}, {0, NULL}}; +consvar_t cv_gamestateattempts = {"gamestateresendattempts", "10", CV_SAVE, gamestateattempts_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; + +static CV_PossibleValue_t resynchcooldown_cons_t[] = {{0, "MIN"}, {20, "MAX"}, {0, NULL}}; +consvar_t cv_resynchcooldown = {"gamestatecooldown", "5", CV_SAVE, resynchcooldown_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL }; +#endif + consvar_t cv_blamecfail = {"blamecfail", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL }; // max file size to send to a player (in kilobytes) @@ -3993,6 +4123,11 @@ static void Joinable_OnChange(void) if (!server) return; +#ifdef SATURNJOIN + // disabling joins should also disable saturn joins unless its called with CV_StealthSet and vice versa to make life a bit easier + CV_SetValue(&cv_allownewsaturnplayer, cv_allownewplayer.value); +#endif + maxplayer = (UINT8)(min((dedicated ? MAXPLAYERS-1 : MAXPLAYERS), cv_maxplayers.value)); WRITEUINT8(p, maxplayer); @@ -4018,7 +4153,11 @@ void D_ClientServerInit(void) COM_AddCommand("reloadbans", Command_ReloadBan); COM_AddCommand("connect", Command_connect); COM_AddCommand("nodes", Command_Nodes); +#ifdef SATURNSYNCH + COM_AddCommand("resendgamestate", Command_ResendGamestate); +#endif COM_AddCommand("listplayers", Command_Listplayers); + COM_AddCommand("packetstat", Command_Packetstat); #ifdef HAVE_CURL COM_AddCommand("set_http_login", Command_set_http_login); COM_AddCommand("list_http_logins", Command_list_http_logins); @@ -4055,17 +4194,33 @@ void D_ClientServerInit(void) static void ResetNode(INT32 node) { nodeingame[node] = false; + nodewaiting[node] = 0; + nodetoplayer[node] = -1; nodetoplayer2[node] = -1; nodetoplayer3[node] = -1; nodetoplayer4[node] = -1; + playerpernode[node] = 0; + nettics[node] = gametic; supposedtics[node] = gametic; - nodewaiting[node] = 0; - playerpernode[node] = 0; + sendingsavegame[node] = false; + bannednode[node].banid = SIZE_MAX; bannednode[node].timeleft = NO_BAN_TIME; + + // SATURN +#ifdef SATURNPAK + is_client_saturn[node] = false; +#endif + +#ifdef SATURNSYNCH + resendingsavegame[node] = false; + can_receive_gamestate[node] = false; + savegameresendcooldown[node] = 0; +#endif + // } void SV_ResetServer(void) @@ -4101,6 +4256,9 @@ void SV_ResetServer(void) mynode = 0; cl_packetmissed = false; +#ifdef SATURNSYNCH + cl_redownloadinggamestate = false; +#endif if (dedicated) { @@ -4117,6 +4275,7 @@ void SV_ResetServer(void) // clear server_context memset(server_context, '-', 8); + memset(packetstat, 0, sizeof(packetstat)); DEBFILE("\n-=-=-=-=-=-=-= Server Reset =-=-=-=-=-=-=-\n\n"); } @@ -4276,8 +4435,13 @@ static void Got_AddPlayer(UINT8 **p, INT32 playernum) if (server && multiplayer && motd[0] != '\0') COM_BufAddText(va("sayto %d %s\n", newplayernum, motd)); + D_AddAutoloadFiles(); + LUAh_PlayerJoin(newplayernum); + if (newplayernum == consoleplayer) + LUAh_ServerJoin(); + #ifdef HAVE_DISCORDRPC DRPC_UpdatePresence(); #endif @@ -4309,7 +4473,6 @@ static void Got_RemovePlayer(UINT8 **p, INT32 playernum) if (pnum == serverplayer) { CONS_Alert(CONS_WARNING, "Attempt to remove server player\n"); - return; } @@ -4388,6 +4551,14 @@ static boolean SV_AddWaitingPlayers(void) return newplayer; } +#ifdef SATURNPAK +static inline void SendSaturnInfo(INT32 node) +{ + netbuffer->packettype = PT_ISSATURN; + HSendPacket(node, true, 0, 0); +} +#endif + void CL_AddSplitscreenPlayer(void) { if (cl_mode == CL_CONNECTED) @@ -4573,7 +4744,11 @@ static void HandleConnect(SINT8 node) { SV_SendRefuse(node, va(M_GetText("Different SRB2Kart versions cannot\nplay a netgame!\n(server version %d.%d)"), VERSION, SUBVERSION)); } +#ifdef SATURNJOIN + else if ((!cv_allownewplayer.value && node && netbuffer->u.clientcfg.issaturn != ISSATURN) || (!cv_allownewsaturnplayer.value && node && netbuffer->u.clientcfg.issaturn == ISSATURN)) +#else else if (!cv_allownewplayer.value && node) +#endif { SV_SendRefuse(node, M_GetText(cv_joinrefusemessage.string)); } @@ -4629,6 +4804,7 @@ static void HandleConnect(SINT8 node) /// \todo fix this !!! return; // restart the while } + SV_SendServerInfo(node, 0); // Dunno if 0 time is good idea //if (gamestate != GS_LEVEL) // GS_INTERMISSION, etc? // SV_SendPlayerConfigs(node); // send bare minimum player info G_SetGamestate(backupstate); @@ -4639,7 +4815,7 @@ static void HandleConnect(SINT8 node) { if (node && newnode) { - SV_SendSaveGame(node); // send a complete game state + SV_SendSaveGame(node, false); // send a complete game state DEBFILE("send savegame\n"); } SV_AddWaitingPlayers(); @@ -4705,6 +4881,47 @@ static void HandleServerInfo(SINT8 node) netbuffer->u.serverinfo.gametype = (UINT8)((netbuffer->u.serverinfo.gametype == VANILLA_GT_MATCH) ? GT_MATCH : GT_RACE); SL_InsertServer(&netbuffer->u.serverinfo, node); + + if (client && cl_mode > CL_SEARCHING && node == servernode) + memcpy(connectedservername, netbuffer->u.serverinfo.servername, MAXSERVERNAME); +} +#endif + +#ifdef SATURNSYNCH +static void PT_WillResendGamestate(void) +{ + char tmpsave[264]; + + if (server || cl_redownloadinggamestate) + return; + + // Send back a PT_CANRECEIVEGAMESTATE packet to the server + // so they know they can start sending the game state + netbuffer->packettype = PT_CANRECEIVEGAMESTATE; + if (!HSendPacket(servernode, true, 0, 0)) + return; + + CONS_Printf(M_GetText("Reloading game state...\n")); + + sprintf(tmpsave, "%s" PATHSEP TMPSAVENAME, srb2home); + + // Don't get a corrupt savegame error because tmpsave already exists + if (FIL_FileExists(tmpsave) && unlink(tmpsave) == -1) + I_Error("Can't delete %s\n", tmpsave); + + CL_PrepareDownloadSaveGame(tmpsave); + cl_redownloadinggamestate = true; +} + +static void PT_CanReceiveGamestate(SINT8 node) +{ + if (client || sendingsavegame[node]) + return; + + CONS_Printf(M_GetText("Resending game state to %s...\n"), player_names[nodetoplayer[node]]); + + SV_SendSaveGame(node, true); // Resend a complete game state + resendingsavegame[node] = true; } #endif @@ -4896,6 +5113,9 @@ static void HandlePacketFromAwayNode(SINT8 node) #endif DEBFILE(va("Server accept join gametic=%u mynode=%d\n", gametic, mynode)); +#ifdef SATURNPAK + SendSaturnInfo(node); +#endif memset(playeringame, 0, sizeof(playeringame)); for (j = 0; j < MAXPLAYERS; j++) { @@ -5009,7 +5229,6 @@ static void HandlePacketFromPlayer(SINT8 node) tic_t realend, realstart; UINT8 *pak, *txtpak, numtxtpak; - txtpak = NULL; if (dedicated && node == 0) @@ -5133,11 +5352,69 @@ static void HandlePacketFromPlayer(SINT8 node) --resynch_delay[node]; break; } + +#ifdef SATURNSYNCH + if ((gamestate_resend_counter[node] != 0) && (I_GetTime() % ((max(cv_resynchcooldown.value, 1) * TICRATE) *2) == 0)) + gamestate_resend_counter[node]--; + + // Check player consistancy during the level + if (((!can_receive_gamestate[node]) && realstart <= gametic && realstart > gametic - TICQUEUE+1 && gamestate == GS_LEVEL + && consistancy[realstart%TICQUEUE] != SHORT(netbuffer->u.clientpak.consistancy)) || (can_receive_gamestate[node] && realstart <= gametic && realstart + TICQUEUE - 1 > gametic && gamestate == GS_LEVEL + && consistancy[realstart%TICQUEUE] != SHORT(netbuffer->u.clientpak.consistancy) + && !resendingsavegame[node] && savegameresendcooldown[node] <= I_GetTime())) + { + // we need to send this so the client can tell us if it can receive the savegame + netbuffer->packettype = PT_WILLRESENDGAMESTATE; + HSendPacket(node, true, 0, 0); + + if (can_receive_gamestate[node]) + resendingsavegame[node] = true; + else + { + SV_RequireResynch(node); + resendingsavegame[node] = false; + } + + if ((!can_receive_gamestate[node] && cv_resynchattempts.value && resynch_score[node] <= (unsigned)cv_resynchattempts.value*250) || (can_receive_gamestate[node] && (gamestate_resend_counter[node] < cv_gamestateattempts.value))) + { + if (can_receive_gamestate[node] && resendingsavegame[node]) + { + gamestate_resend_counter[node]++; + DEBFILE(va("gamestate counter %d for player %d\n", gamestate_resend_counter[node], netconsole)); + } + + if (cv_blamecfail.value) + CONS_Printf(M_GetText("Synch failure for player %d (%s); expected %hd, got %hd\n"), + netconsole+1, player_names[netconsole], + consistancy[realstart%TICQUEUE], + SHORT(netbuffer->u.clientpak.consistancy)); + DEBFILE(va("Restoring player %d (synch failure) [%update] %d!=%d\n", + netconsole, realstart, consistancy[realstart%TICQUEUE], + SHORT(netbuffer->u.clientpak.consistancy))); + break; + } + else + { + UINT8 buf[3]; + + buf[0] = (UINT8)netconsole; + buf[1] = KICK_MSG_CON_FAIL; + SendNetXCmd(XD_KICK, &buf, 2); + DEBFILE(va("player %d kicked (synch failure) [%u] %d!=%d\n", + netconsole, realstart, consistancy[realstart%TICQUEUE], + SHORT(netbuffer->u.clientpak.consistancy))); + break; + } + } + else if (resynch_score[node]) + --resynch_score[node]; + break; +#else // Check player consistancy during the level if (realstart <= gametic && realstart > gametic - TICQUEUE+1 && gamestate == GS_LEVEL && consistancy[realstart%TICQUEUE] != SHORT(netbuffer->u.clientpak.consistancy)) { - SV_RequireResynch(node); + SV_RequireResynch(node); if (cv_resynchattempts.value && resynch_score[node] <= (unsigned)cv_resynchattempts.value*250) { @@ -5167,6 +5444,8 @@ static void HandlePacketFromPlayer(SINT8 node) else if (resynch_score[node]) --resynch_score[node]; break; +#endif + case PT_BASICKEEPALIVE: if (client) break; @@ -5301,6 +5580,12 @@ static void HandlePacketFromPlayer(SINT8 node) } Net_CloseConnection(node); nodeingame[node] = false; +#ifdef SATURNPAK + is_client_saturn[node] = false; +#endif +#ifdef SATURNSYNCH + can_receive_gamestate[node] = false; +#endif break; // -------------------------------------------- CLIENT RECEIVE ---------- case PT_RESYNCHEND: @@ -5464,6 +5749,26 @@ static void HandlePacketFromPlayer(SINT8 node) if (client) Got_Filetxpak(); break; +#ifdef SATURNSYNCH + case PT_CANRECEIVEGAMESTATE: + can_receive_gamestate[node] = true; + PT_CanReceiveGamestate(node); + break; + case PT_RECEIVEDGAMESTATE: + sendingsavegame[node] = false; + resendingsavegame[node] = false; + savegameresendcooldown[node] = I_GetTime() + cv_resynchcooldown.value * TICRATE; // I_GetTime() + 5 * TICRATE; + break; + case PT_WILLRESENDGAMESTATE: + PT_WillResendGamestate(); + break; +#endif +#ifdef SATURNPAK + case PT_ISSATURN: + //CONS_Printf("hi im on saturn%d\n", node); + is_client_saturn[node] = true; + break; +#endif default: DEBFILE(va("UNKNOWN PACKET TYPE RECEIVED %d from host %d\n", netbuffer->packettype, node)); @@ -5479,7 +5784,6 @@ static void GetPackets(void) { SINT8 node; // The packet sender - player_joining = false; while (HGetPacket()) @@ -5516,6 +5820,10 @@ static void GetPackets(void) if (netbuffer->packettype == PT_PLAYERINFO) continue; // We do nothing with PLAYERINFO, that's for the MS browser. + // We also count unknown packets, hence "<=" + if (netbuffer->packettype <= NUMPACKETTYPE) + ++packetstat[netbuffer->packettype]; + // Packet received from someone already playing if (nodeingame[node]) HandlePacketFromPlayer(node); @@ -6292,13 +6600,12 @@ void NetKeepAlive(void) MasterClient_Ticker(); #endif - #ifdef HOLEPUNCH +#ifdef HOLEPUNCH if (netgame && serverrunning) { RenewHolePunch(); } - #endif - +#endif if (client) { @@ -6411,18 +6718,27 @@ void NetUpdate(void) MasterClient_Ticker(); // Acking the Master Server #endif - #ifdef HOLEPUNCH +#ifdef HOLEPUNCH if (netgame && serverrunning) { RenewHolePunch(); } - #endif +#endif if (client) { +#ifdef SATURNSYNCH + // If the client just finished redownloading the game state, load it + if (cl_redownloadinggamestate && fileneeded[0].status == FS_FOUND) + CL_ReloadReceivedSavegame(); +#endif if (!resynch_local_inprogress) CL_SendClientCmd(); // Send tic cmd + hu_resynching = resynch_local_inprogress; +#ifdef SATURNSYNCH + hu_redownloadinggamestate = cl_redownloadinggamestate; +#endif } else { @@ -6431,6 +6747,9 @@ void NetUpdate(void) INT32 counts; hu_resynching = false; +#ifdef SATURNSYNCH + hu_redownloadinggamestate = false; +#endif firstticstosend = gametic; for (i = 0; i < MAXNETNODES; i++) @@ -6532,7 +6851,7 @@ rewind_t *CL_SaveRewindPoint(size_t demopos) return NULL; save_p = rewind->savebuffer; - P_SaveNetGame(); + P_SaveNetGame(false); rewind->leveltime = leveltime; rewind->next = rewindhead; rewind->demopos = demopos; @@ -6556,7 +6875,7 @@ rewind_t *CL_RewindToTime(tic_t time) return NULL; save_p = rewindhead->savebuffer; - P_LoadNetGame(); + P_LoadNetGame(false); wipegamestate = gamestate; // No fading back in! timeinmap = leveltime; diff --git a/src/d_clisrv.h b/src/d_clisrv.h index 13c2bc353..cc123b1d2 100644 --- a/src/d_clisrv.h +++ b/src/d_clisrv.h @@ -98,6 +98,16 @@ typedef enum PT_MOREFILESNEEDED, // Server, to client: "you need these (+ more on top of those)" PT_PING, // Packet sent to tell clients the other client's latency to server. + +#ifdef SATURNSYNCH + PT_WILLRESENDGAMESTATE, // Hey Client, I am about to resend you the gamestate! + PT_CANRECEIVEGAMESTATE, // Okay Server, I'm ready to receive it, you can go ahead. + PT_RECEIVEDGAMESTATE, // Thank you Server, I am ready to play again! + + // we will reserve this for now even if unused, so order wont get mangled + PT_ISSATURN, // Saturn specific identifier packet +#endif + NUMPACKETTYPE } packettype_t; @@ -363,6 +373,9 @@ typedef struct UINT8 subversion; // Contains build version UINT8 localplayers; // number of splitscreen players UINT8 mode; +#ifdef SATURNJOIN + UINT8 issaturn; +#endif } ATTRPACK clientconfig_pak; #define SV_SPEEDMASK 0x03 // used to send kartspeed @@ -567,14 +580,22 @@ extern consvar_t #ifdef VANILLAJOINNEXTROUND cv_joinnextround, #endif - cv_netticbuffer, cv_allownewplayer, cv_joinrefusemessage, cv_maxplayers, cv_resynchattempts, cv_blamecfail, cv_maxsend, cv_noticedownload, cv_downloadspeed; + cv_netticbuffer, cv_allownewplayer, +#ifdef SATURNJOIN + cv_allownewsaturnplayer, +#endif + cv_joinrefusemessage, cv_maxplayers, cv_resynchattempts, +#ifdef SATURNSYNCH + cv_resynchcooldown, cv_gamestateattempts, +#endif + cv_blamecfail, cv_maxsend, cv_noticedownload, cv_downloadspeed; extern consvar_t cv_connectawaittime; extern consvar_t cv_discordinvites; // Used in d_net, the only dependence -tic_t ExpandTics(INT32 low, tic_t basetic); +//tic_t ExpandTics(INT32 low, tic_t basetic); void D_ClientServerInit(void); // Initialise the other field @@ -632,6 +653,9 @@ tic_t GetLag(INT32 node); UINT8 GetFreeXCmdSize(void); extern UINT8 hu_resynching; +#ifdef SATURNSYNCH +extern UINT8 hu_redownloadinggamestate; +#endif extern UINT8 hu_stopped; // kart, true when the game is stopped for players due to a disconnecting or connecting player typedef struct rewind_s { diff --git a/src/d_main.c b/src/d_main.c index 17325e904..c437a9dcf 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -37,6 +37,7 @@ #include "d_net.h" #include "f_finale.h" #include "g_game.h" +#include "g_input.h" #include "hu_stuff.h" #include "i_sound.h" #include "i_system.h" @@ -103,11 +104,12 @@ static char *startupwadfiles[MAX_WADFILES]; static char *startuppwads[MAX_WADFILES]; // autoloading -static char *autoloadwadfiles[MAX_WADFILES]; +char *autoloadwadfiles[MAX_WADFILES]; char *autoloadwadfilespost[MAX_WADFILES]; boolean autoloading; boolean autoloaded; -boolean postautoloaded; +boolean postautoloaded = false; +boolean wasautoloaded = false; boolean devparm = false; // started game with -devparm @@ -149,6 +151,8 @@ INT32 eventhead, eventtail; boolean dedicated = false; +boolean loaded_config = false; + // // D_PostEvent // Called by the I/O functions when input is detected @@ -166,6 +170,32 @@ UINT8 ctrldown = 0; // 0x1 left, 0x2 right UINT8 altdown = 0; // 0x1 left, 0x2 right boolean capslock = 0; // gee i wonder what this does. +static inline void D_DeviceLEDTick(void) +{ + UINT8 i; + UINT16 color[MAXSPLITSCREENPLAYERS]; + UINT16 curcolor[MAXSPLITSCREENPLAYERS]; + + if (I_NumJoys() == 0 || (cv_gamepadled[0].value == 0 && cv_gamepadled[1].value == 0 && cv_gamepadled[2].value == 0 && cv_gamepadled[3].value == 0)) + { + return; + } + + for (i = 0; i <= splitscreen; i++) + { + if (G_GetDeviceForPlayer(i) == 0) + continue; + + color[i] = G_GetSkinColor(i); + + if (curcolor[i] == color[i]) // dont update if same colour + continue; + + G_SetPlayerGamepadIndicatorColor(i, color[i]); + curcolor[i] = color[i]; + } +} + // // D_ProcessEvents // Send all the events of the given timestamp down the responder chain @@ -242,8 +272,9 @@ void D_ProcessEvents(void) // added comment : there is a wipe eatch change of the gamestate gamestate_t wipegamestate = GS_LEVEL; -static void D_Display(void) +static boolean D_Display(void) { + boolean ranwipe = false; boolean forcerefresh = false; static boolean wipe = false; INT32 wipedefindex = 0; @@ -252,7 +283,7 @@ static void D_Display(void) if (!dedicated) { if (nodrawers) - return; // for comparative timing/profiling + return false; // for comparative timing/profiling // check for change of screen size (video mode) if (setmodeneeded && !wipe) @@ -262,7 +293,10 @@ static void D_Display(void) SCR_Recalc(); // NOTE! setsizeneeded is set by SCR_Recalc() if (rendermode == render_soft && !splitscreen) + { + R_InterpolateViewRollAngle(rendertimefrac); R_CheckViewMorph(); + } // change the view size if needed if (setsizeneeded) @@ -302,6 +336,7 @@ static void D_Display(void) V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 31); F_WipeEndScreen(); F_RunWipe(wipedefs[wipedefindex], gamestate != GS_TIMEATTACK); + ranwipe = true; } if (gamestate != GS_LEVEL && rendermode != render_none) @@ -315,12 +350,13 @@ static void D_Display(void) else //dedicated servers { F_RunWipe(wipedefs[wipedefindex], gamestate != GS_TIMEATTACK); + ranwipe = true; wipegamestate = gamestate; } } if (dedicated) //bail out after wipe logic - return; + return false; // do buffered drawing switch (gamestate) @@ -427,7 +463,7 @@ static void D_Display(void) viewssnum = i; #ifdef HWRENDER - if (rendermode != render_soft) + if (rendermode == render_opengl) HWR_RenderPlayerView(i, &players[displayplayers[i]]); else #endif @@ -482,8 +518,10 @@ static void D_Display(void) for (i = 0; i <= splitscreen; i++) { - if (postimgtype[i]) - V_DoPostProcessor(i, postimgtype[i], postimgparam[i]); + if (!postimgtype[i]) + continue; + + V_DoPostProcessor(i, postimgtype[i], postimgparam[i]); } } @@ -497,7 +535,6 @@ static void D_Display(void) if (rendermode == render_soft) { VID_BlitLinearScreen(screens[0], screens[1], vid.width*vid.bpp, vid.height, vid.width*vid.bpp, vid.rowbytes); - usebuffer = true; } lastdraw = false; } @@ -561,11 +598,10 @@ static void D_Display(void) { F_WipeEndScreen(); F_RunWipe(wipedefs[wipedefindex], gamestate != GS_TIMEATTACK); + ranwipe = true; } } - NetUpdate(); // send out any new accumulation - // It's safe to end the game now. if (G_GetExitGameFlag()) { @@ -610,6 +646,7 @@ static void D_Display(void) PS_STOP_TIMING(ps_swaptime); } + return ranwipe; } // ========================================================================= @@ -617,6 +654,7 @@ static void D_Display(void) // ========================================================================= tic_t rendergametic; +static int menuInputDelayTimer = 0; void D_SRB2Loop(void) { @@ -626,6 +664,7 @@ void D_SRB2Loop(void) boolean interp = false; boolean doDisplay = false; + int frameskip = 0; if (dedicated) server = true; @@ -670,6 +709,8 @@ void D_SRB2Loop(void) capbudget = (precise_t) budget; } + boolean ranwipe = false; + I_UpdateTime(cv_timescale.value); if (lastwipetic) @@ -702,9 +743,11 @@ void D_SRB2Loop(void) HW3S_BeginFrameUpdate(); #endif + renderisnewtic = (realtics > 0 || singletics); + refreshdirmenu = 0; // not sure where to put this, here as good as any? - if (realtics > 0 || singletics) + if (renderisnewtic) { // don't skip more than 10 frames at a time // (fadein / fadeout cause massive frame skip!) @@ -723,14 +766,20 @@ void D_SRB2Loop(void) } else if (rendertimeout < entertic) // in case the server hang or netsplit { + // Lagless camera! Yay! + if (cv_laglesscam.value && gamestate == GS_LEVEL && netgame) + { + // Evaluate the chase cam once for every local realtic + // This might actually be better suited inside G_Ticker or TryRunTics + for (tic_t chasecamtics = 0; chasecamtics < realtics; chasecamtics++) + { + P_RunChaseCameras(); + } + R_UpdateViewInterpolation(); + } + doDisplay = true; } - - renderisnewtic = true; - } - else - { - renderisnewtic = false; } if (interp) @@ -752,9 +801,9 @@ void D_SRB2Loop(void) rendertimefrac = FRACUNIT; } - if (interp || doDisplay) + if ((interp || doDisplay) && !frameskip) { - D_Display(); + ranwipe = D_Display(); } // Only take screenshots after drawing. @@ -779,8 +828,72 @@ void D_SRB2Loop(void) } #endif + // this is absolutely awful and i hate it lmao + if (menuactive && (DPADUPSCROLL || DPADDOWNSCROLL || DPADLEFTSCROLL || DPADRIGHTSCROLL)) + { + event_t myev; + myev.type = ev_keydown; + + if (renderisnewtic) + { + menuInputDelayTimer++; + + if (menuInputDelayTimer >= 19) // TICRATE * ( (k+2) (1 - [wz + h + j - q]^2 - [(gk + 2g + k + 1)(h + j) + h - z]^2 - [16(k + 1)^3(k + 2)(n + 1)^2 + 1 - f^2]^2 calculated by my butt + { + if (DPADUPSCROLL) + { + myev.data1 = KEY_UPARROW; + M_Responder(&myev); + } + else if (DPADDOWNSCROLL) + { + myev.data1 = KEY_DOWNARROW; + M_Responder(&myev); + } + else if (DPADLEFTSCROLL) + { + myev.data1 = KEY_LEFTARROW; + M_Responder(&myev); + } + else if (DPADRIGHTSCROLL) + { + myev.data1 = KEY_RIGHTARROW; + M_Responder(&myev); + } + } + } + } + else + menuInputDelayTimer = 0; + + if (!dedicated && renderisnewtic) // idk does this need dedi check?? + D_DeviceLEDTick(); + // Fully completed frame made. finishprecise = I_GetPreciseTime(); + + // Use the time before sleep for frameskip calculations: + // post-sleep time is literally being intentionally wasted + deltasecs = (double)((INT64)(finishprecise - enterprecise)) / I_GetPrecisePrecision(); + deltatics = deltasecs * NEWTICRATE; + + // If time spent this game loop exceeds a single tic, + // it's probably because of rendering. + // + // Skip rendering the next frame, up to a limit of 3 + // frames before a frame is rendered no matter what. + // + // Wipes run an inner loop and artificially increase + // the measured time. + if (!ranwipe && frameskip < 3 && deltatics > 1.0) + { + frameskip++; + } + else + { + frameskip = 0; + } + if (!singletics) { INT64 elapsed = (INT64)(finishprecise - enterprecise); @@ -906,7 +1019,7 @@ static INT32 D_DetectFileType(const char* filename) return 5; else if (!stricmp(&filename[strlen(filename) - 4], ".soc")) return 6; - + else if (!stricmp(&filename[strlen(filename) - 4], ".cfg")) return 7; else if (!stricmp(&filename[strlen(filename) - 4], ".txt")) @@ -930,12 +1043,12 @@ static void D_AutoloadFile(const char *file, char **filearray) if (!newfile) I_Error("No more free memory to AutoloadFile %s",file); - if (!fileType) + if (!fileType) { CONS_Printf("D_AutoloadFile: File %s is unknown or invalid\n", file); return; } - + strcpy(newfile, file); if (fileType <= 6) @@ -975,7 +1088,10 @@ static void D_FindAddonsToAutoload(void) // If the file is found, run our shit if (!autoloadconfigfile) // nope outta here + { + wasautoloaded = postautoloaded = true; // so D_AddAutoloadFiles can skip everything since nothings there to autoload return; + } while (fgets(wadsToAutoload, sizeof wadsToAutoload, autoloadconfigfile) != NULL) { @@ -1042,6 +1158,32 @@ static void D_FindAddonsToAutoload(void) fclose(autoloadconfigfile); } +void D_AddAutoloadFiles(void) +{ + if (wasautoloaded && postautoloaded) + return; + + if (!wasautoloaded && !modeattacking) + { + CONS_Printf("D_AutoloadFile(): Loading autoloaded addons...\n"); + if (W_AddAutoloadedLocalFiles(autoloadwadfiles) == 0) + CONS_Printf("D_AutoloadFile(): Are you sure you put in valid files or what?\n"); + D_CleanFile(autoloadwadfiles); + + wasautoloaded = true; + } + + if ((!postautoloaded) && netgame) + { + CONS_Printf("D_AutoloadFile(): Loading postloaded addons...\n"); + if (W_AddAutoloadedLocalFiles(autoloadwadfilespost) == 0) + CONS_Printf("D_AutoloadFile(): Are you sure you put in valid files or what?\n"); + D_CleanFile(autoloadwadfilespost); + + postautoloaded = true; + } +} + void D_CleanFile(char **filearray) { size_t pnumwadfiles; @@ -1147,13 +1289,13 @@ static void IdentifyVersion(void) D_AddFile(va(pandf,srb2waddir,"extra.kart"), startupwadfiles); found_extra_kart = true; } - + // completely optional 2: Back with a vengence if (FIL_ReadFileOK(va(pandf,srb2waddir,"extra2.kart"))) { D_AddFile(va(pandf,srb2waddir,"extra2.kart"), startupwadfiles); found_extra2_kart = true; } - + if (FIL_ReadFileOK(va(pandf,srb2waddir,"extra3.kart"))) { D_AddFile(va(pandf,srb2waddir,"extra3.kart"), startupwadfiles); found_extra3_kart = true; @@ -1456,7 +1598,7 @@ void D_SRB2Main(void) if (found_extra_kart || found_extra2_kart || found_extra3_kart) // found the funny, add it in! { // HAYA: These are seperated for a reason lmao - if (found_extra_kart) + if (found_extra_kart) mainwads++; if (found_extra2_kart) mainwads++; @@ -1484,7 +1626,7 @@ void D_SRB2Main(void) achi_speedo_clr = true; // check for bigger lap count - if (W_CheckMultipleLumps("K_STLAPB", "K_STLA2B", NULL)) + if (W_CheckMultipleLumps("K_STLAPB", "K_STLA2B", NULL)) big_lap = true; // now check for colour hud stuff @@ -1493,7 +1635,7 @@ void D_SRB2Main(void) clr_hud = true; // check for bigger lap count but color** its color bitch - if (W_CheckMultipleLumps("K_SCLAPB", "K_SCLA2B", NULL)) + if (W_CheckMultipleLumps("K_SCLAPB", "K_SCLA2B", NULL)) big_lap_color = true; // kartzspeedo @@ -1508,16 +1650,16 @@ void D_SRB2Main(void) // stat display for extended player setup if (W_CheckMultipleLumps("K_STATNB", "K_STATN1", "K_STATN2", "K_STATN3", "K_STATN4", \ - "K_STATN5", "K_STATN6", NULL)) + "K_STATN5", "K_STATN6", NULL)) statdp = true; // Nametag stuffs - if (W_CheckMultipleLumps("NTLINE", "NTLINEV", "NTSP", "NTWH", NULL)) + if (W_CheckMultipleLumps("NTLINE", "NTLINEV", "NTSP", "NTWH", NULL)) nametaggfx = true; - if (W_CheckMultipleLumps("K_DGAU","K_DCAU","K_DGSU","K_DCSU", NULL)) + if (W_CheckMultipleLumps("K_DGAU","K_DCAU","K_DGSU","K_DCSU", NULL)) driftgaugegfx = true; - + if (found_extra3_kart) { // 80x11 speedometer crap @@ -1530,7 +1672,7 @@ void D_SRB2Main(void) if (W_LumpExists("SC_SM3TC")) xtra_speedo_clr3 = true; } - } + } #undef PUSHSPEEDO memcpy(speedo_cons_t, speedo_cons_temp, sizeof(speedo_cons_t)); @@ -1644,6 +1786,8 @@ void D_SRB2Main(void) savedata.lives = 0; // flag this as not-used + loaded_config = true; // so pallettechange doesent get called 500 times at startup lol + //------------------------------------------------ COMMAND LINE PARAMS // this must be done after loading gamedata, @@ -1728,11 +1872,6 @@ void D_SRB2Main(void) CONS_Printf("ST_Init(): Init status bar.\n"); ST_Init(); - CONS_Printf("D_AutoloadFile(): Loading autoloaded addons...\n"); - if (W_AddAutoloadedLocalFiles(autoloadwadfiles) == 0) - CONS_Printf("D_AutoloadFile(): Are you sure you put in valid files or what?\n"); - D_CleanFile(autoloadwadfiles); - // Set up splitscreen players before joining! if (!dedicated && (M_CheckParm("-splitscreen") && M_IsNextParm())) { @@ -1937,7 +2076,7 @@ void D_SRB2Main(void) pagename = "TITLESKY"; levelstarttic = gametic; G_SetGamestate(GS_LEVEL); - if (!P_SetupLevel(false)) + if (!P_SetupLevel(false, false)) I_Quit(); // fail so reset game stuff } diff --git a/src/d_main.h b/src/d_main.h index 23fb31619..851eaa8b5 100644 --- a/src/d_main.h +++ b/src/d_main.h @@ -20,6 +20,8 @@ // make sure not to write back the config until it's been correctly loaded extern tic_t rendergametic; +extern boolean loaded_config; + extern char srb2home[256]; //Alam: My Home extern boolean usehome; //Alam: which path? extern const char *pandf; //Alam: how to path? @@ -43,12 +45,15 @@ extern boolean statdp; // stat display for extended player setup extern boolean nametaggfx; // Nametag stuffs extern boolean driftgaugegfx; +void D_AddAutoloadFiles(void); extern boolean autoloading; extern boolean autoloaded; extern boolean postautoloaded; +extern boolean wasautoloaded; extern char *autoloadwadfilespost[MAX_WADFILES]; +extern char *autoloadwadfiles[MAX_WADFILES]; // the infinite loop of D_SRB2Loop() called from win_main for windows version void D_SRB2Loop(void) FUNCNORETURN; diff --git a/src/d_net.c b/src/d_net.c index 6b45e009d..ad031a76b 100644 --- a/src/d_net.c +++ b/src/d_net.c @@ -64,9 +64,6 @@ static doomdata_t reboundstore[MAXREBOUND]; static INT16 reboundsize[MAXREBOUND]; static INT32 rebound_head, rebound_tail; -/// \brief bandwith of netgame -INT32 net_bandwidth; - /// \brief max length per packet INT16 hardware_MAXPACKETLENGTH; @@ -793,7 +790,7 @@ static void fprintfstringnewline(char *s, size_t len) } /// \warning Keep this up-to-date if you add/remove/rename packet types -static const char *packettypename[NUMPACKETTYPE] = +const char *packettypename[NUMPACKETTYPE] = { "NOTHING", "SERVERCFG", @@ -836,13 +833,31 @@ static const char *packettypename[NUMPACKETTYPE] = "MOREFILESNEEDED", "PING" +#ifdef SATURNSYNCH + , + + "WILLRESENDGAMESTATE", + "CANRECEIVEGAMESTATE", + "RECEIVEDGAMESTATE", + + // we will reserve this for now even if unused, so order wont get mangled + "ISSATURN" +#endif }; +const char *Net_GetPacketName(UINT8 packettype) +{ + if (packettype >= NUMPACKETTYPE) + return "UNKNOWN"; + + return packettypename[packettype]; +} + static void DebugPrintpacket(const char *header) { fprintf(debugfile, "%-12s (node %d,ack %d,ackret %d,size %d) type(%d) : %s\n", header, doomcom->remotenode, netbuffer->ack, netbuffer->ackreturn, doomcom->datalength, - netbuffer->packettype, packettypename[netbuffer->packettype]); + netbuffer->packettype, Net_GetPacketName(netbuffer->packettype)); switch (netbuffer->packettype) { @@ -1208,7 +1223,7 @@ boolean HGetPacket(void) } break; } -#endif // ndef NONET +#endif // ifndef NONET return true; } @@ -1258,10 +1273,7 @@ void D_SetDoomcom(void) { if (doomcom) return; doomcom = Z_Calloc(sizeof (doomcom_t), PU_STATIC, NULL); - doomcom->id = DOOMCOM_ID; doomcom->numslots = doomcom->numnodes = 1; - doomcom->gametype = 0; - doomcom->consoleplayer = 0; doomcom->extratics = 0; } @@ -1286,7 +1298,6 @@ boolean D_CheckNetGame(void) I_NetMakeNodewPort = NULL; hardware_MAXPACKETLENGTH = MAXPACKETLENGTH; - net_bandwidth = 30000; // I_InitNetwork sets doomcom and netgame // check and initialize the network driver multiplayer = false; @@ -1306,7 +1317,6 @@ boolean D_CheckNetGame(void) server = true; // WTF? server always true??? // no! The deault mode is server. Client is set elsewhere // when the client executes connect command. - doomcom->ticdup = 1; if (M_CheckParm("-extratic")) { @@ -1317,21 +1327,6 @@ boolean D_CheckNetGame(void) CONS_Printf(M_GetText("Set extratics to %d\n"), doomcom->extratics); } - if (M_CheckParm("-bandwidth")) - { - if (M_IsNextParm()) - { - net_bandwidth = atoi(M_GetNextParm()); - if (net_bandwidth < 1000) - net_bandwidth = 1000; - if (net_bandwidth > 100000) - hardware_MAXPACKETLENGTH = MAXPACKETLENGTH; - CONS_Printf(M_GetText("Network bandwidth set to %d\n"), net_bandwidth); - } - else - I_Error("usage: -bandwidth "); - } - software_MAXPACKETLENGTH = hardware_MAXPACKETLENGTH; if (M_CheckParm("-packetsize")) { @@ -1351,8 +1346,6 @@ boolean D_CheckNetGame(void) if (netgame) multiplayer = true; - if (doomcom->id != DOOMCOM_ID) - I_Error("Doomcom buffer invalid!"); if (doomcom->numnodes > MAXNETNODES) I_Error("Too many nodes (%d), max:%d", doomcom->numnodes, MAXNETNODES); @@ -1365,7 +1358,7 @@ boolean D_CheckNetGame(void) if (M_CheckParm("-debugfile")) { char filename[21]; - INT32 k = doomcom->consoleplayer - 1; + INT32 k = consoleplayer - 1; if (M_IsNextParm()) k = atoi(M_GetNextParm()) - 1; while (!debugfile && k < MAXPLAYERS) diff --git a/src/d_net.h b/src/d_net.h index e267f5268..471881847 100644 --- a/src/d_net.h +++ b/src/d_net.h @@ -65,5 +65,6 @@ void Net_ConnectionTimeout(INT32 node); void Net_AbortPacketType(UINT8 packettype); void Net_SendAcks(INT32 node); void Net_WaitAllAckReceived(UINT32 timeout); +const char *Net_GetPacketName(UINT8 packettype); #endif diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 1e46da57f..3cd815dee 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -299,6 +299,9 @@ consvar_t cv_usemouse2 = {"use_mouse2", "Off", CV_SAVE|CV_CALL,usemouse_cons_t, //WTF consvar_t cv_mouseturn = {"mouseturn", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; +// Lagless camera! Yay! +consvar_t cv_laglesscam = {"laglesscamera", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; + #if defined(HAVE_SDL) || defined(_WINDOWS) //joystick 1 and 2 consvar_t cv_usejoystick = {"use_joystick", "1", CV_SAVE|CV_CALL, usejoystick_cons_t, I_InitJoystick, 0, NULL, NULL, 0, 0, NULL}; @@ -394,6 +397,7 @@ static CV_PossibleValue_t kartspeedometer_cons_t[] = {{0, "Off"}, {1, "Kilometer consvar_t cv_kartspeedometer = {"kartdisplayspeed", "Off", CV_SAVE, kartspeedometer_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; // use tics in display static CV_PossibleValue_t kartvoices_cons_t[] = {{0, "Never"}, {1, "Tasteful"}, {2, "Meme"}, {0, NULL}}; consvar_t cv_kartvoices = {"kartvoices", "Tasteful", CV_SAVE, kartvoices_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_karthitemdialog = {"karthitemdialog", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_karteliminatelast = {"karteliminatelast", "Yes", CV_NETVAR|CV_CHEAT|CV_CALL|CV_NOSHOWHELP, CV_YesNo, KartEliminateLast_OnChange, 0, NULL, NULL, 0, 0, NULL}; @@ -561,6 +565,10 @@ static CV_PossibleValue_t ps_descriptor_cons_t[] = { {1, "Average"}, {2, "SD"}, {3, "Minimum"}, {4, "Maximum"}, {0, NULL}}; consvar_t cv_ps_descriptor = {"ps_descriptor", "Average", 0, ps_descriptor_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_director = {"director", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_kartdebugdirector = {"debugdirector", "Off", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_showdirectorhud = {"showdirectorhud", "On", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; + consvar_t cv_showtrackaddon = {"showtrackaddon", "Yes", CV_SAVE, CV_YesNo, NULL, 0, NULL, NULL, 0, 0, NULL}; static CV_PossibleValue_t skinselectmenu_t[] = {{SKINMENUTYPE_SCROLL, "Scroll"}, {SKINMENUTYPE_2D, "2d"}, {SKINMENUTYPE_GRID, "Grid"}, {SKINMENUTYPE_EXTENDED, "Extended"}, {0, NULL}}; @@ -577,6 +585,9 @@ static CV_PossibleValue_t skinselectgridsort_t[] ={ }; consvar_t cv_skinselectgridsort ={ "skinselectgridsort", "Real name", CV_SAVE|CV_CALL|CV_NOINIT, skinselectgridsort_t, sortSkinGrid, 0, NULL, NULL, 0, 0, NULL }; +static CV_PossibleValue_t betainterscreen_t[] = {{0, "Off"}, {1, "On"}, {2, "NoBG"}, {0, NULL}}; +consvar_t cv_betainterscreen = {"betaintermissionscreen", "Off", CV_SAVE, betainterscreen_t, NULL, 0, NULL, NULL, 0, 0, NULL}; + INT16 gametype = GT_RACE; // SRB2kart boolean forceresetplayers = false; boolean deferencoremode = false; @@ -777,6 +788,10 @@ void D_RegisterServerCommands(void) // d_clisrv CV_RegisterVar(&cv_maxplayers); CV_RegisterVar(&cv_resynchattempts); +#ifdef SATURNSYNCH + CV_RegisterVar(&cv_gamestateattempts); + CV_RegisterVar(&cv_resynchcooldown); +#endif CV_RegisterVar(&cv_maxsend); CV_RegisterVar(&cv_noticedownload); CV_RegisterVar(&cv_downloadspeed); @@ -784,6 +799,9 @@ void D_RegisterServerCommands(void) CV_RegisterVar(&cv_httpsource); #ifndef NONET CV_RegisterVar(&cv_allownewplayer); +#ifdef SATURNJOIN + CV_RegisterVar(&cv_allownewsaturnplayer); +#endif CV_RegisterVar(&cv_joinrefusemessage); CV_RegisterVar(&cv_chatlogsize); #ifdef VANILLAJOINNEXTROUND @@ -821,6 +839,8 @@ void D_RegisterServerCommands(void) CV_RegisterVar(&cv_recordmultiplayerdemos); CV_RegisterVar(&cv_netdemosyncquality); CV_RegisterVar(&cv_maxdemosize); + CV_RegisterVar(&cv_demochangemap); + CV_RegisterVar(&cv_keyboardlayout); } @@ -975,6 +995,10 @@ void D_RegisterClientCommands(void) CV_RegisterVar(&cv_showtrackaddon); CV_RegisterVar(&cv_showviewpointtext); + CV_RegisterVar(&cv_director); + CV_RegisterVar(&cv_kartdebugdirector); + CV_RegisterVar(&cv_showdirectorhud); + CV_RegisterVar(&cv_luaimmersion); CV_RegisterVar(&cv_fakelocalskin); @@ -988,6 +1012,7 @@ void D_RegisterClientCommands(void) //CV_RegisterVar(&cv_alwaysfreelook2); //CV_RegisterVar(&cv_chasefreelook); //CV_RegisterVar(&cv_chasefreelook2); + CV_RegisterVar(&cv_replaysearchrate); CV_RegisterVar(&cv_showfocuslost); CV_RegisterVar(&cv_pauseifunfocused); @@ -1062,6 +1087,21 @@ void D_RegisterClientCommands(void) CV_RegisterVar(&cv_controlperkey); CV_RegisterVar(&cv_turnsmooth); + CV_RegisterVar(&cv_rumble[0]); + CV_RegisterVar(&cv_rumble[1]); + CV_RegisterVar(&cv_rumble[2]); + CV_RegisterVar(&cv_rumble[3]); + + CV_RegisterVar(&cv_gamepadled[0]); + CV_RegisterVar(&cv_gamepadled[1]); + CV_RegisterVar(&cv_gamepadled[2]); + CV_RegisterVar(&cv_gamepadled[3]); + + CV_RegisterVar(&cv_ledpowerup[0]); + CV_RegisterVar(&cv_ledpowerup[1]); + CV_RegisterVar(&cv_ledpowerup[2]); + CV_RegisterVar(&cv_ledpowerup[3]); + CV_RegisterVar(&cv_usemouse); CV_RegisterVar(&cv_usemouse2); CV_RegisterVar(&cv_invertmouse); @@ -1154,6 +1194,10 @@ void D_RegisterClientCommands(void) CV_RegisterVar(&cv_showmusicfilename); + CV_RegisterVar(&cv_betainterscreen); + + CV_RegisterVar(&cv_laglesscam); + // ingame object placing COM_AddCommand("objectplace", Command_ObjectPlace_f); COM_AddCommand("writethings", Command_Writethings_f); @@ -1650,8 +1694,9 @@ static void SendNameAndColor(void) cv_skin.value = R_SkinAvailable(cv_skin.string); if (cv_skin.value < 0) { - CV_StealthSet(&cv_skin, DEFAULTSKIN); - cv_skin.value = 0; + INT32 skinnum = players[consoleplayer].skin; + CV_StealthSet(&cv_skin, skins[skinnum].name); + cv_skin.value = skinnum; } // Finally write out the complete packet and send it off. @@ -1779,8 +1824,9 @@ static void SendNameAndColor2(void) cv_skin2.value = R_SkinAvailable(cv_skin2.string); if (cv_skin2.value < 0) { - CV_StealthSet(&cv_skin2, DEFAULTSKIN); - cv_skin2.value = 0; + INT32 skinnum = players[displayplayers[1]].skin; + CV_StealthSet(&cv_skin2, skins[skinnum].name); + cv_skin2.value = skinnum; } // Finally write out the complete packet and send it off. @@ -1899,8 +1945,9 @@ static void SendNameAndColor3(void) cv_skin3.value = R_SkinAvailable(cv_skin3.string); if (cv_skin3.value < 0) { - CV_StealthSet(&cv_skin3, DEFAULTSKIN); - cv_skin3.value = 0; + INT32 skinnum = players[displayplayers[2]].skin; + CV_StealthSet(&cv_skin3, skins[skinnum].name); + cv_skin3.value = skinnum; } // Finally write out the complete packet and send it off. @@ -2027,8 +2074,9 @@ static void SendNameAndColor4(void) cv_skin4.value = R_SkinAvailable(cv_skin4.string); if (cv_skin4.value < 0) { - CV_StealthSet(&cv_skin4, DEFAULTSKIN); - cv_skin4.value = 0; + INT32 skinnum = players[displayplayers[3]].skin; + CV_StealthSet(&cv_skin4, skins[skinnum].name); + cv_skin4.value = skinnum; } // Finally write out the complete packet and send it off. @@ -2933,6 +2981,10 @@ static void Command_Map_f(void) } } + // spend atleast 35 seconds in one map + if (cv_demochangemap.value && demo.recording && demo.savemode != DSM_NOTSAVING && (timeinmap > 1463) && ((cv_demochangemap.value == 2 && newmapnum == gamemap) || newmapnum != gamemap)) + G_SaveDemo(); + fromlevelselect = false; D_MapChange(newmapnum, newgametype, newencoremode, newresetplayers, 0, false, false); @@ -5661,6 +5713,12 @@ void Command_ExitGame_f(void) { INT32 i; + if (dedicated) + { + CONS_Printf("This command cannot be used on dedicated server\n"); + return; + } + D_QuitNetGame(); CL_Reset(); CV_ClearChangedFlags(); diff --git a/src/d_netcmd.h b/src/d_netcmd.h index e9934e237..f4ca00214 100644 --- a/src/d_netcmd.h +++ b/src/d_netcmd.h @@ -128,6 +128,7 @@ extern consvar_t cv_kartvoterulechanges; extern consvar_t cv_kartgametypepreference; extern consvar_t cv_kartspeedometer; extern consvar_t cv_kartvoices; +extern consvar_t cv_karthitemdialog; extern consvar_t cv_karteliminatelast; @@ -201,10 +202,16 @@ extern consvar_t cv_ps_thinkframe_page; extern consvar_t cv_ps_samplesize; extern consvar_t cv_ps_descriptor; +extern consvar_t cv_director, cv_kartdebugdirector, cv_showdirectorhud; + extern consvar_t cv_showtrackaddon; extern consvar_t cv_showspecstuff; +extern consvar_t cv_betainterscreen; + +extern consvar_t cv_laglesscam; + typedef enum { SKINMENUTYPE_SCROLL = 0, diff --git a/src/d_netfil.c b/src/d_netfil.c index 9c32a41f4..7bf862f90 100644 --- a/src/d_netfil.c +++ b/src/d_netfil.c @@ -833,7 +833,6 @@ void SV_FileSendTicker(void) netbuffer->packettype = PT_FILEFRAGMENT; - // (((sendbytes-nowsentbyte)*TICRATE)/(I_GetTime()-starttime)<(UINT32)net_bandwidth) while (packetsent-- && filestosend != 0) { for (i = currentnode, j = 0; j < MAXNETNODES; @@ -1300,8 +1299,9 @@ void CURLPrepareFile(const char* url, int dfilenum) curl_starttime = time(NULL); curl_running = true; - +#ifdef HAVE_THREADS I_spawn_thread("http-download", (I_thread_fn)CURLGetFile, NULL); +#endif } } diff --git a/src/d_player.h b/src/d_player.h index 4d61474fb..c2a5d32ce 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -347,6 +347,14 @@ typedef enum RW_RAIL = 32 } ringweapons_t; +// enum for saved lap times +typedef enum +{ + LAP_CUR, + LAP_LAST, + LAP__MAX +} laptime_e; + // ======================================================================== // PLAYER STRUCTURE // ======================================================================== @@ -465,6 +473,7 @@ typedef struct player_s INT16 numboxes; // Number of item boxes obtained for Race Mode INT16 totalring; // Total number of rings obtained for Race Mode tic_t realtime; // integer replacement for leveltime + tic_t laptime[LAP__MAX]; UINT8 laps; // Number of laps (optional) //////////////////// @@ -537,15 +546,13 @@ typedef struct player_s tic_t grieftime; UINT8 griefstrikes; + tic_t hitemtimer; + UINT8 hitemvictim; + UINT8 splitscreenindex; #ifdef HWRENDER fixed_t fovadd; // adjust FOV for hw rendering #endif - - struct { - angle_t aiming, awayviewaiming, frameangle; - angle_t viewrollangle; - } lerp; } player_t; #endif diff --git a/src/dehacked.c b/src/dehacked.c index 8b181a563..80a8e0ec1 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -291,8 +291,6 @@ static void readPlayer(MYFILE *f, INT32 num) INT32 i; boolean slotfound = false; - DEH_WriteUndoline("PLAYERTEXT", description[num].notes, UNDO_ENDTEXT); - do { if (myfgets(s, MAXLINELEN, f)) @@ -362,7 +360,6 @@ static void readPlayer(MYFILE *f, INT32 num) { if (!slotfound && (slotfound = findFreeSlot(&num)) == false) goto done; - DEH_WriteUndoline(word, &description[num].picname[0], UNDO_NONE); PlayerMenu[num].status = IT_CALL; strncpy(description[num].picname, word2, 8); } @@ -386,7 +383,6 @@ static void readPlayer(MYFILE *f, INT32 num) */ if (i != IT_DISABLED && !slotfound && (slotfound = findFreeSlot(&num)) == false) goto done; - DEH_WriteUndoline(word, va("%d", PlayerMenu[num].status), UNDO_NONE); PlayerMenu[num].status = (INT16)i; } else if (fastcmp(word, "SKINNAME")) @@ -394,7 +390,6 @@ static void readPlayer(MYFILE *f, INT32 num) // Send to free slot. if (!slotfound && (slotfound = findFreeSlot(&num)) == false) goto done; - DEH_WriteUndoline(word, description[num].skinname, UNDO_NONE); PlayerMenu[num].status = IT_CALL; strlcpy(description[num].skinname, word2, sizeof description[num].skinname); @@ -557,122 +552,98 @@ static void readthing(MYFILE *f, INT32 num) if (fastcmp(word, "MAPTHINGNUM") || fastcmp(word, "DOOMEDNUM")) { - DEH_WriteUndoline(word, va("%d", mobjinfo[num].doomednum), UNDO_NONE); mobjinfo[num].doomednum = (INT32)atoi(word2); } else if (fastcmp(word, "SPAWNSTATE")) { - DEH_WriteUndoline(word, va("%d", mobjinfo[num].spawnstate), UNDO_NONE); mobjinfo[num].spawnstate = get_number(word2); } else if (fastcmp(word, "SPAWNHEALTH")) { - DEH_WriteUndoline(word, va("%d", mobjinfo[num].spawnhealth), UNDO_NONE); mobjinfo[num].spawnhealth = (INT32)get_number(word2); } else if (fastcmp(word, "SEESTATE")) { - DEH_WriteUndoline(word, va("%d", mobjinfo[num].seestate), UNDO_NONE); mobjinfo[num].seestate = get_number(word2); } else if (fastcmp(word, "SEESOUND")) { - DEH_WriteUndoline(word, va("%d", mobjinfo[num].seesound), UNDO_NONE); mobjinfo[num].seesound = get_number(word2); } else if (fastcmp(word, "REACTIONTIME")) { - DEH_WriteUndoline(word, va("%d", mobjinfo[num].reactiontime), UNDO_NONE); mobjinfo[num].reactiontime = (INT32)get_number(word2); } else if (fastcmp(word, "ATTACKSOUND")) { - DEH_WriteUndoline(word, va("%d", mobjinfo[num].attacksound), UNDO_NONE); mobjinfo[num].attacksound = get_number(word2); } else if (fastcmp(word, "PAINSTATE")) { - DEH_WriteUndoline(word, va("%d", mobjinfo[num].painstate), UNDO_NONE); mobjinfo[num].painstate = get_number(word2); } else if (fastcmp(word, "PAINCHANCE")) { - DEH_WriteUndoline(word, va("%d", mobjinfo[num].painchance), UNDO_NONE); mobjinfo[num].painchance = (INT32)get_number(word2); } else if (fastcmp(word, "PAINSOUND")) { - DEH_WriteUndoline(word, va("%d", mobjinfo[num].painsound), UNDO_NONE); mobjinfo[num].painsound = get_number(word2); } else if (fastcmp(word, "MELEESTATE")) { - DEH_WriteUndoline(word, va("%d", mobjinfo[num].meleestate), UNDO_NONE); mobjinfo[num].meleestate = get_number(word2); } else if (fastcmp(word, "MISSILESTATE")) { - DEH_WriteUndoline(word, va("%d", mobjinfo[num].missilestate), UNDO_NONE); mobjinfo[num].missilestate = get_number(word2); } else if (fastcmp(word, "DEATHSTATE")) { - DEH_WriteUndoline(word, va("%d", mobjinfo[num].deathstate), UNDO_NONE); mobjinfo[num].deathstate = get_number(word2); } else if (fastcmp(word, "DEATHSOUND")) { - DEH_WriteUndoline(word, va("%d", mobjinfo[num].deathsound), UNDO_NONE); mobjinfo[num].deathsound = get_number(word2); } else if (fastcmp(word, "XDEATHSTATE")) { - DEH_WriteUndoline(word, va("%d", mobjinfo[num].xdeathstate), UNDO_NONE); mobjinfo[num].xdeathstate = get_number(word2); } else if (fastcmp(word, "SPEED")) { - DEH_WriteUndoline(word, va("%d", mobjinfo[num].speed), UNDO_NONE); mobjinfo[num].speed = get_number(word2); } else if (fastcmp(word, "RADIUS")) { - DEH_WriteUndoline(word, va("%d", mobjinfo[num].radius), UNDO_NONE); mobjinfo[num].radius = get_number(word2); } else if (fastcmp(word, "HEIGHT")) { - DEH_WriteUndoline(word, va("%d", mobjinfo[num].height), UNDO_NONE); mobjinfo[num].height = get_number(word2); } else if (fastcmp(word, "DISPOFFSET")) { - DEH_WriteUndoline(word, va("%d", mobjinfo[num].dispoffset), UNDO_NONE); mobjinfo[num].dispoffset = get_number(word2); } else if (fastcmp(word, "MASS")) { - DEH_WriteUndoline(word, va("%d", mobjinfo[num].mass), UNDO_NONE); mobjinfo[num].mass = (INT32)get_number(word2); } else if (fastcmp(word, "DAMAGE")) { - DEH_WriteUndoline(word, va("%d", mobjinfo[num].damage), UNDO_NONE); mobjinfo[num].damage = (INT32)get_number(word2); } else if (fastcmp(word, "ACTIVESOUND")) { - DEH_WriteUndoline(word, va("%d", mobjinfo[num].activesound), UNDO_NONE); mobjinfo[num].activesound = get_number(word2); } else if (fastcmp(word, "FLAGS")) { - DEH_WriteUndoline(word, va("%d", mobjinfo[num].flags), UNDO_NONE); mobjinfo[num].flags = (INT32)get_number(word2); } else if (fastcmp(word, "RAISESTATE")) { - DEH_WriteUndoline(word, va("%d", mobjinfo[num].raisestate), UNDO_NONE); mobjinfo[num].raisestate = get_number(word2); } else @@ -1110,8 +1081,6 @@ static void readcutscenescene(MYFILE *f, INT32 num, INT32 scenenum) UINT16 usi; UINT8 picid; - DEH_WriteUndoline("SCENETEXT", cutscenes[num]->scene[scenenum].text, UNDO_ENDTEXT); - do { if (myfgets(s, MAXLINELEN, f)) @@ -1188,7 +1157,6 @@ static void readcutscenescene(MYFILE *f, INT32 num, INT32 scenenum) if (fastcmp(word, "NUMBEROFPICS")) { - DEH_WriteUndoline(word, va("%d", cutscenes[num]->scene[scenenum].numpics), UNDO_NONE); cutscenes[num]->scene[scenenum].numpics = (UINT8)i; } else if (fastncmp(word, "PIC", 3)) @@ -1203,27 +1171,22 @@ static void readcutscenescene(MYFILE *f, INT32 num, INT32 scenenum) if (fastcmp(word+4, "NAME")) { - DEH_WriteUndoline(word, cutscenes[num]->scene[scenenum].picname[picid], UNDO_NONE); strncpy(cutscenes[num]->scene[scenenum].picname[picid], word2, 8); } else if (fastcmp(word+4, "HIRES")) { - DEH_WriteUndoline(word, va("%d", cutscenes[num]->scene[scenenum].pichires[picid]), UNDO_NONE); cutscenes[num]->scene[scenenum].pichires[picid] = (UINT8)(i || word2[0] == 'T' || word2[0] == 'Y'); } else if (fastcmp(word+4, "DURATION")) { - DEH_WriteUndoline(word, va("%u", cutscenes[num]->scene[scenenum].picduration[picid]), UNDO_NONE); cutscenes[num]->scene[scenenum].picduration[picid] = usi; } else if (fastcmp(word+4, "XCOORD")) { - DEH_WriteUndoline(word, va("%u", cutscenes[num]->scene[scenenum].xcoord[picid]), UNDO_NONE); cutscenes[num]->scene[scenenum].xcoord[picid] = usi; } else if (fastcmp(word+4, "YCOORD")) { - DEH_WriteUndoline(word, va("%u", cutscenes[num]->scene[scenenum].ycoord[picid]), UNDO_NONE); cutscenes[num]->scene[scenenum].ycoord[picid] = usi; } else @@ -1231,14 +1194,12 @@ static void readcutscenescene(MYFILE *f, INT32 num, INT32 scenenum) } else if (fastcmp(word, "MUSIC")) { - DEH_WriteUndoline(word, cutscenes[num]->scene[scenenum].musswitch, UNDO_NONE); strncpy(cutscenes[num]->scene[scenenum].musswitch, word2, 7); cutscenes[num]->scene[scenenum].musswitch[6] = 0; } #ifdef MUSICSLOT_COMPATIBILITY else if (fastcmp(word, "MUSICSLOT")) { - DEH_WriteUndoline(word, cutscenes[num]->scene[scenenum].musswitch, UNDO_NONE); i = get_mus(word2, true); if (i && i <= 1035) snprintf(cutscenes[num]->scene[scenenum].musswitch, 7, "%sM", G_BuildMapName(i)); @@ -1251,42 +1212,34 @@ static void readcutscenescene(MYFILE *f, INT32 num, INT32 scenenum) #endif else if (fastcmp(word, "MUSICTRACK")) { - DEH_WriteUndoline(word, va("%u", cutscenes[num]->scene[scenenum].musswitchflags), UNDO_NONE); cutscenes[num]->scene[scenenum].musswitchflags = ((UINT16)i) & MUSIC_TRACKMASK; } else if (fastcmp(word, "MUSICPOS")) { - DEH_WriteUndoline(word, va("%u", cutscenes[num]->scene[scenenum].musswitchposition), UNDO_NONE); cutscenes[num]->scene[scenenum].musswitchposition = (UINT32)get_number(word2); } else if (fastcmp(word, "MUSICLOOP")) { - DEH_WriteUndoline(word, va("%u", cutscenes[num]->scene[scenenum].musicloop), UNDO_NONE); cutscenes[num]->scene[scenenum].musicloop = (UINT8)(i || word2[0] == 'T' || word2[0] == 'Y'); } else if (fastcmp(word, "TEXTXPOS")) { - DEH_WriteUndoline(word, va("%u", cutscenes[num]->scene[scenenum].textxpos), UNDO_NONE); cutscenes[num]->scene[scenenum].textxpos = usi; } else if (fastcmp(word, "TEXTYPOS")) { - DEH_WriteUndoline(word, va("%u", cutscenes[num]->scene[scenenum].textypos), UNDO_NONE); cutscenes[num]->scene[scenenum].textypos = usi; } else if (fastcmp(word, "FADEINID")) { - DEH_WriteUndoline(word, va("%u", cutscenes[num]->scene[scenenum].fadenum), UNDO_NONE); cutscenes[num]->scene[scenenum].fadeinid = (UINT8)i; } else if (fastcmp(word, "FADEOUTID")) { - DEH_WriteUndoline(word, va("%u", cutscenes[num]->scene[scenenum].fadenum), UNDO_NONE); cutscenes[num]->scene[scenenum].fadeoutid = (UINT8)i; } else if (fastcmp(word, "FADECOLOR")) { - DEH_WriteUndoline(word, va("%u", cutscenes[num]->scene[scenenum].fadenum), UNDO_NONE); cutscenes[num]->scene[scenenum].fadecolor = (UINT8)i; } else @@ -1346,8 +1299,6 @@ static void readcutscene(MYFILE *f, INT32 num) if (1 <= value && value <= 128) { readcutscenescene(f, num, value - 1); - DEH_WriteUndoline(word, word2, UNDO_SPACE|UNDO_CUTLINE); - DEH_WriteUndoline("NUMSCENES", va("%d", oldnumscenes), UNDO_SPACE); } else deh_warning("Scene number %d out of range (1 - 128)", value); @@ -1403,12 +1354,10 @@ static void readhuditem(MYFILE *f, INT32 num) if (fastcmp(word, "X")) { - DEH_WriteUndoline(word, va("%d", hudinfo[num].x), UNDO_NONE); hudinfo[num].x = i; } else if (fastcmp(word, "Y")) { - DEH_WriteUndoline(word, va("%d", hudinfo[num].y), UNDO_NONE); hudinfo[num].y = i; } else @@ -1419,25 +1368,10 @@ static void readhuditem(MYFILE *f, INT32 num) Z_Free(s); } -/* -Sprite number = 10 -Sprite subnumber = 32968 -Duration = 200 -Next frame = 200 -*/ -/** Action pointer for reading actions from Dehacked lumps. - */ -typedef struct -{ - actionf_t action; ///< Function pointer corresponding to the actual action. - const char *name; ///< Name of the action in ALL CAPS. -} actionpointer_t; - -/** Array mapping action names to action functions. - * Names must be in ALL CAPS for case insensitive comparisons. - */ -static actionpointer_t actionpointers[] = +// IMPORTANT! +// DO NOT FORGET TO SYNC THIS LIST WITH THE ACTIONNUM ENUM IN INFO.H +actionpointer_t actionpointers[] = { {{A_Explode}, "A_EXPLODE"}, {{A_Pain}, "A_PAIN"}, @@ -1592,6 +1526,7 @@ static actionpointer_t actionpointers[] = {{A_FZBoomSmoke}, "A_FZBOOMSMOKE"}, //SRB2kart {{A_RandomShadowFrame}, "A_RANDOMSHADOWFRAME"}, //SRB2kart {{A_RoamingShadowThinker}, "A_ROAMINGSHADOWTHINKER"}, //SRB2kart + {{A_MayonakaArrow}, "A_MAYONAKAARROW"}, //SRB2kart {{A_ReaperThinker}, "A_REAPERTHINKER"}, //SRB2kart {{A_MementosTPParticles}, "A_MEMENTOSTPPARTICLES"}, //SRB2kart {{A_FlameParticle}, "A_FLAMEPARTICLE"}, // SRB2kart @@ -1684,32 +1619,26 @@ static void readframe(MYFILE *f, INT32 num) if (fastcmp(word1, "SPRITENUMBER") || fastcmp(word1, "SPRITENAME")) { - DEH_WriteUndoline(word1, va("%u", states[num].sprite), UNDO_NONE); states[num].sprite = get_sprite(word2); } else if (fastcmp(word1, "SPRITESUBNUMBER") || fastcmp(word1, "SPRITEFRAME")) { - DEH_WriteUndoline(word1, va("%d", states[num].frame), UNDO_NONE); states[num].frame = (INT32)get_number(word2); // So the FF_ flags get calculated } else if (fastcmp(word1, "DURATION")) { - DEH_WriteUndoline(word1, va("%u", states[num].tics), UNDO_NONE); states[num].tics = (INT32)get_number(word2); // So TICRATE can be used } else if (fastcmp(word1, "NEXT")) { - DEH_WriteUndoline(word1, va("%d", states[num].nextstate), UNDO_NONE); states[num].nextstate = get_state(word2); } else if (fastcmp(word1, "VAR1")) { - DEH_WriteUndoline(word1, va("%d", states[num].var1), UNDO_NONE); states[num].var1 = (INT32)get_number(word2); } else if (fastcmp(word1, "VAR2")) { - DEH_WriteUndoline(word1, va("%d", states[num].var2), UNDO_NONE); states[num].var2 = (INT32)get_number(word2); } else if (fastcmp(word1, "ACTION")) @@ -1735,7 +1664,6 @@ static void readframe(MYFILE *f, INT32 num) { if (actionpointers[z].action.acv == states[num].action.acv) { - DEH_WriteUndoline(word1, actionpointers[z].name, UNDO_NONE); break; } } @@ -1795,17 +1723,14 @@ static void readsound(MYFILE *f, INT32 num, const char *savesfxnames[]) if (fastcmp(word, "SINGULAR")) { - DEH_WriteUndoline(word, va("%d", S_sfx[num].singularity), UNDO_NONE); S_sfx[num].singularity = value; } else if (fastcmp(word, "PRIORITY")) { - DEH_WriteUndoline(word, va("%d", S_sfx[num].priority), UNDO_NONE); S_sfx[num].priority = value; } else if (fastcmp(word, "FLAGS")) { - DEH_WriteUndoline(word, va("%d", S_sfx[num].pitch), UNDO_NONE); S_sfx[num].pitch = value; } else @@ -1865,16 +1790,6 @@ static void reademblemdata(MYFILE *f, INT32 num) INT32 value; // Reset all data initially - DEH_WriteUndoline("TYPE", va("%d", emblemlocations[num-1].type), UNDO_NONE); - DEH_WriteUndoline("X", va("%d", emblemlocations[num-1].x), UNDO_NONE); - DEH_WriteUndoline("Y", va("%d", emblemlocations[num-1].y), UNDO_NONE); - DEH_WriteUndoline("Z", va("%d", emblemlocations[num-1].z), UNDO_NONE); - DEH_WriteUndoline("MAPNUM", va("%d", emblemlocations[num-1].level), UNDO_NONE); - DEH_WriteUndoline("VAR", va("%d", emblemlocations[num-1].var), UNDO_NONE); - DEH_WriteUndoline("SPRITE", va("%d", emblemlocations[num-1].sprite), UNDO_NONE); - DEH_WriteUndoline("COLOR", va("%d", emblemlocations[num-1].color), UNDO_NONE); - DEH_WriteUndoline("HINT", extraemblems[num-1].hint, UNDO_NONE); - memset(&emblemlocations[num-1], 0, sizeof(emblem_t)); do @@ -2002,12 +1917,6 @@ static void readextraemblemdata(MYFILE *f, INT32 num) INT32 value; // Reset all data initially - DEH_WriteUndoline("NAME", extraemblems[num-1].name, UNDO_NONE); - DEH_WriteUndoline("OBJECTIVE", extraemblems[num-1].description, UNDO_NONE); - DEH_WriteUndoline("CONDITIONSET", va("%d", extraemblems[num-1].conditionset), UNDO_NONE); - DEH_WriteUndoline("SPRITE", va("%d", extraemblems[num-1].sprite), UNDO_NONE); - DEH_WriteUndoline("COLOR", va("%d", extraemblems[num-1].color), UNDO_NONE); - memset(&extraemblems[num-1], 0, sizeof(extraemblem_t)); do @@ -2086,15 +1995,6 @@ static void readunlockable(MYFILE *f, INT32 num) INT32 i; // Same deal with unlockables, clear all first - DEH_WriteUndoline("NAME", unlockables[num].name, UNDO_NONE); - DEH_WriteUndoline("OBJECTIVE", unlockables[num].objective, UNDO_NONE); - DEH_WriteUndoline("HEIGHT", va("%d", unlockables[num].height), UNDO_NONE); - DEH_WriteUndoline("CONDITIONSET", va("%d", unlockables[num].conditionset), UNDO_NONE); - DEH_WriteUndoline("TYPE", va("%d", unlockables[num].type), UNDO_NONE); - DEH_WriteUndoline("NOCECHO", va("%d", unlockables[num].nocecho), UNDO_NONE); - DEH_WriteUndoline("NOCHECKLIST", va("%d", unlockables[num].nochecklist), UNDO_NONE); - DEH_WriteUndoline("VAR", va("%d", unlockables[num].variable), UNDO_NONE); - memset(&unlockables[num], 0, sizeof(unlockable_t)); do @@ -2473,13 +2373,11 @@ static void readpatch(MYFILE *f, const char *name, UINT16 wad) // X position of the patch in the texture. if (fastcmp(word, "X")) { - //DEH_WriteUndoline(word, va("%d", patch->originx), UNDO_NONE); patch.originx = (INT16)value; } // Y position of the patch in the texture. else if (fastcmp(word, "Y")) { - //DEH_WriteUndoline(word, va("%d", patch->originy), UNDO_NONE); patch.originy = (INT16)value; } else @@ -2548,7 +2446,6 @@ static void readmaincfg(MYFILE *f) else value = get_number(word2); - DEH_WriteUndoline(word, va("%d", spstage_start), UNDO_NONE); spstage_start = (INT16)value; } else if (fastcmp(word, "SSTAGE_START")) @@ -2562,79 +2459,64 @@ static void readmaincfg(MYFILE *f) else value = get_number(word2); - DEH_WriteUndoline(word, va("%d", sstage_start), UNDO_NONE); sstage_start = (INT16)value; sstage_end = (INT16)(sstage_start+6); // 7 special stages total } else if (fastcmp(word, "USENIGHTSSS")) { - DEH_WriteUndoline(word, va("%d", useNightsSS), UNDO_NONE); useNightsSS = (value || word2[0] == 'T' || word2[0] == 'Y'); } else if (fastcmp(word, "REDTEAM")) { - DEH_WriteUndoline(word, va("%d", skincolor_redteam), UNDO_NONE); skincolor_redteam = (UINT8)get_number(word2); } else if (fastcmp(word, "BLUETEAM")) { - DEH_WriteUndoline(word, va("%d", skincolor_blueteam), UNDO_NONE); skincolor_blueteam = (UINT8)get_number(word2); } else if (fastcmp(word, "REDRING")) { - DEH_WriteUndoline(word, va("%d", skincolor_redring), UNDO_NONE); skincolor_redring = (UINT8)get_number(word2); } else if (fastcmp(word, "BLUERING")) { - DEH_WriteUndoline(word, va("%d", skincolor_bluering), UNDO_NONE); skincolor_bluering = (UINT8)get_number(word2); } else if (fastcmp(word, "INVULNTICS")) { - DEH_WriteUndoline(word, va("%u", invulntics), UNDO_NONE); invulntics = (UINT16)get_number(word2); } else if (fastcmp(word, "SNEAKERTICS")) { - DEH_WriteUndoline(word, va("%u", sneakertics), UNDO_NONE); sneakertics = (UINT16)get_number(word2); } else if (fastcmp(word, "FLASHINGTICS")) { - DEH_WriteUndoline(word, va("%u", flashingtics), UNDO_NONE); flashingtics = (UINT16)get_number(word2); } else if (fastcmp(word, "TAILSFLYTICS")) { - DEH_WriteUndoline(word, va("%u", tailsflytics), UNDO_NONE); tailsflytics = (UINT16)get_number(word2); } else if (fastcmp(word, "UNDERWATERTICS")) { - DEH_WriteUndoline(word, va("%u", underwatertics), UNDO_NONE); underwatertics = (UINT16)get_number(word2); } else if (fastcmp(word, "SPACETIMETICS")) { - DEH_WriteUndoline(word, va("%u", spacetimetics), UNDO_NONE); spacetimetics = (UINT16)get_number(word2); } else if (fastcmp(word, "EXTRALIFETICS")) { - DEH_WriteUndoline(word, va("%u", extralifetics), UNDO_NONE); extralifetics = (UINT16)get_number(word2); } else if (fastcmp(word, "GAMEOVERTICS")) { - DEH_WriteUndoline(word, va("%u", gameovertics), UNDO_NONE); gameovertics = get_number(word2); } else if (fastcmp(word, "INTROTOPLAY")) { - DEH_WriteUndoline(word, va("%d", introtoplay), UNDO_NONE); introtoplay = (UINT8)get_number(word2); // range check, you morons. if (introtoplay > 128) @@ -2642,17 +2524,14 @@ static void readmaincfg(MYFILE *f) } else if (fastcmp(word, "LOOPTITLE")) { - DEH_WriteUndoline(word, va("%d", looptitle), UNDO_NONE); looptitle = (value || word2[0] == 'T' || word2[0] == 'Y'); } else if (fastcmp(word, "TITLESCROLLSPEED")) { - DEH_WriteUndoline(word, va("%d", titlescrollspeed), UNDO_NONE); titlescrollspeed = get_number(word2); } else if (fastcmp(word, "CREDITSCUTSCENE")) { - DEH_WriteUndoline(word, va("%d", creditscutscene), UNDO_NONE); creditscutscene = (UINT8)get_number(word2); // range check, you morons. if (creditscutscene > 128) @@ -2660,27 +2539,22 @@ static void readmaincfg(MYFILE *f) } else if (fastcmp(word, "NUMDEMOS")) { - DEH_WriteUndoline(word, va("%d", numDemos), UNDO_NONE); numDemos = (UINT8)get_number(word2); } else if (fastcmp(word, "DEMODELAYTIME")) { - DEH_WriteUndoline(word, va("%d", demoDelayTime), UNDO_NONE); demoDelayTime = get_number(word2); } else if (fastcmp(word, "DEMOIDLETIME")) { - DEH_WriteUndoline(word, va("%d", demoIdleTime), UNDO_NONE); demoIdleTime = get_number(word2); } else if (fastcmp(word, "USE1UPSOUND")) { - DEH_WriteUndoline(word, va("%u", use1upSound), UNDO_NONE); use1upSound = (UINT8)(value || word2[0] == 'T' || word2[0] == 'Y'); } else if (fastcmp(word, "MAXXTRALIFE")) { - DEH_WriteUndoline(word, va("%u", maxXtraLife), UNDO_NONE); maxXtraLife = (UINT8)get_number(word2); } @@ -2694,7 +2568,6 @@ static void readmaincfg(MYFILE *f) I_Error("Maincfg: bad data file name '%s'\n", word2); G_SaveGameData(false); - DEH_WriteUndoline(word, gamedatafilename, UNDO_NONE); strlcpy(gamedatafilename, word2, sizeof (gamedatafilename)); strlwr(gamedatafilename); savemoddata = true; @@ -2715,12 +2588,10 @@ static void readmaincfg(MYFILE *f) } else if (fastcmp(word, "RESETDATA")) { - DEH_WriteUndoline(word, "0", UNDO_TODO); /// \todo P_ResetData(value); } else if (fastcmp(word, "CUSTOMVERSION")) { - DEH_WriteUndoline(word, customversionstring, UNDO_NONE); strlcpy(customversionstring, word2, sizeof (customversionstring)); } else @@ -2980,13 +2851,11 @@ static void DEH_LoadDehackedFile(MYFILE *f, UINT16 wad) { G_SetGameModified(multiplayer, true); readmaincfg(f); - DEH_WriteUndoline(word, "", UNDO_HEADER); continue; } else if (fastcmp(word, "WIPES")) { readwipes(f); - DEH_WriteUndoline(word, "", UNDO_HEADER); // This is not a major mod. continue; } @@ -3007,7 +2876,6 @@ static void DEH_LoadDehackedFile(MYFILE *f, UINT16 wad) deh_warning("Character %d out of range (0 - 31)", i); ignorelines(f); } - DEH_WriteUndoline(word, word2, UNDO_HEADER); // This is not a major mod. continue; } @@ -3021,7 +2889,6 @@ static void DEH_LoadDehackedFile(MYFILE *f, UINT16 wad) { // Read patch from spec file. readpatch(f, word2, wad); - DEH_WriteUndoline(word, word2, UNDO_HEADER); // This is not a major mod. } else if (fastcmp(word, "THING") || fastcmp(word, "MOBJ") || fastcmp(word, "OBJECT")) @@ -3039,13 +2906,7 @@ static void DEH_LoadDehackedFile(MYFILE *f, UINT16 wad) deh_warning("Thing %d out of range (0 - %d)", i, NUMMOBJTYPES-1); ignorelines(f); } - DEH_WriteUndoline(word, word2, UNDO_HEADER); } -/* else if (fastcmp(word, "ANIMTEX")) - { - readAnimTex(f, i); - // This is not a major mod. - }*/ else if (fastcmp(word, "LEVEL")) { // Support using the actual map name, @@ -3066,7 +2927,6 @@ static void DEH_LoadDehackedFile(MYFILE *f, UINT16 wad) deh_warning("Level number %d out of range (1 - %d)", i, NUMMAPS); ignorelines(f); } - DEH_WriteUndoline(word, word2, UNDO_HEADER); } else if (fastcmp(word, "CUTSCENE")) { @@ -3077,8 +2937,6 @@ static void DEH_LoadDehackedFile(MYFILE *f, UINT16 wad) deh_warning("Cutscene number %d out of range (1 - 128)", i); ignorelines(f); } - DEH_WriteUndoline(word, word2, UNDO_HEADER); - //G_SetGameModified(multiplayer, true); -- might have to reconsider in a future update } else if (fastcmp(word, "FRAME") || fastcmp(word, "STATE")) { @@ -3095,7 +2953,6 @@ static void DEH_LoadDehackedFile(MYFILE *f, UINT16 wad) deh_warning("Frame %d out of range (0 - %d)", i, NUMSTATES-1); ignorelines(f); } - DEH_WriteUndoline(word, word2, UNDO_HEADER); } else if (fastcmp(word, "SOUND")) { @@ -3108,7 +2965,6 @@ static void DEH_LoadDehackedFile(MYFILE *f, UINT16 wad) deh_warning("Sound %d out of range (0 - %d)", i, NUMSFX-1); ignorelines(f); } - DEH_WriteUndoline(word, word2, UNDO_HEADER); // This is not a major mod. } else if (fastcmp(word, "HUDITEM")) @@ -3122,7 +2978,6 @@ static void DEH_LoadDehackedFile(MYFILE *f, UINT16 wad) deh_warning("HUD item number %d out of range (0 - %d)", i, NUMHUDITEMS-1); ignorelines(f); } - DEH_WriteUndoline(word, word2, UNDO_HEADER); // This is not a major mod. } else if (fastcmp(word, "EMBLEM")) @@ -3143,7 +2998,6 @@ static void DEH_LoadDehackedFile(MYFILE *f, UINT16 wad) deh_warning("Emblem number %d out of range (1 - %d)", i, MAXEMBLEMS); ignorelines(f); } - DEH_WriteUndoline(word, word2, UNDO_HEADER); } else if (fastcmp(word, "EXTRAEMBLEM")) { @@ -3163,7 +3017,6 @@ static void DEH_LoadDehackedFile(MYFILE *f, UINT16 wad) deh_warning("Extra emblem number %d out of range (1 - %d)", i, MAXEXTRAEMBLEMS); ignorelines(f); } - DEH_WriteUndoline(word, word2, UNDO_HEADER); } else if (fastcmp(word, "UNLOCKABLE")) { @@ -3179,7 +3032,6 @@ static void DEH_LoadDehackedFile(MYFILE *f, UINT16 wad) deh_warning("Unlockable number %d out of range (1 - %d)", i, MAXUNLOCKABLES); ignorelines(f); } - DEH_WriteUndoline(word, word2, UNDO_HEADER); } else if (fastcmp(word, "CONDITIONSET")) { @@ -3195,15 +3047,12 @@ static void DEH_LoadDehackedFile(MYFILE *f, UINT16 wad) deh_warning("Condition set number %d out of range (1 - %d)", i, MAXCONDITIONSETS); ignorelines(f); } - // no undo support for this insanity yet - //DEH_WriteUndoline(word, word2, UNDO_HEADER); } else if (fastcmp(word, "SRB2KART")) { INT32 ver = searchvalue(strtok(NULL, "\n")); if (ver != PATCHVERSION) deh_warning("Patch is for SRB2Kart version %d,\nonly version %d is supported", ver, PATCHVERSION); - //DEH_WriteUndoline(word, va("%d", ver), UNDO_NONE); } else if (fastcmp(word, "SRB2")) { @@ -3282,7 +3131,6 @@ void DEH_LoadDehackedLumpPwad(UINT16 wad, UINT16 lump) f.curpos = f.data; f.data[f.size] = 0; DEH_LoadDehackedFile(&f, wad); - DEH_WriteUndoline(va("# uload for wad: %u, lump: %u", wad, lump), NULL, UNDO_DONE); Z_Free(f.data); } @@ -9130,12 +8978,15 @@ int LUA_EnumLib(lua_State *L) char *str = NULL; int size = 0; + // Sound enum tables preallocated for sfx_freeslot0 elements because using NUMSFX may be too + // much if number of skins increased a lot (because of skinsound freeslots) + /* SFX (SFX_) */ lua_pushcfunction(L, lua_glib_new_enum); - lua_createtable(L, 0, NUMSFX); + lua_createtable(L, 0, sfx_freeslot0); for (int i = 0; i < NUMSFX; i++) { - if (!S_sfx[i].name) continue; + if (!S_sfx[i].name || !S_sfx[i].priority) continue; if (lua_enumlib_sprintf_upper(&str, &size, "SFX_%s", S_sfx[i].name) == NULL) return luaL_error(L, "Ran out of memory."); @@ -9150,10 +9001,10 @@ int LUA_EnumLib(lua_State *L) /* SFX (DS) */ lua_pushcfunction(L, lua_glib_new_enum); - lua_createtable(L, 0, NUMSFX); + lua_createtable(L, 0, sfx_freeslot0); for (int i = 0; i < NUMSFX; i++) { - if (!S_sfx[i].name) continue; + if (!S_sfx[i].name || !S_sfx[i].priority) continue; if (lua_enumlib_sprintf_upper(&str, &size, "DS%s", S_sfx[i].name) == NULL) return luaL_error(L, "Ran out of memory."); @@ -9188,10 +9039,10 @@ int LUA_EnumLib(lua_State *L) { /* SFX (sfx_) */ lua_pushcfunction(L, lua_glib_new_enum); - lua_createtable(L, 0, NUMSFX); + lua_createtable(L, 0, sfx_freeslot0); for (int i = 0; i < NUMSFX; i++) { - if (!S_sfx[i].name) continue; + if (!S_sfx[i].name || !S_sfx[i].priority) continue; lua_pushfstring(L, "sfx_%s", S_sfx[i].name); lua_pushinteger(L, i); @@ -9422,4 +9273,13 @@ void LUA_SetActionByName(void *state, const char *actiontocompare) return; } } -} \ No newline at end of file +} + +enum actionnum LUA_GetActionNumByName(const char *actiontocompare) +{ + size_t z; + for (z = 0; actionpointers[z].name; z++) + if (fasticmp(actiontocompare, actionpointers[z].name)) + return z; + return z; +} diff --git a/src/dehacked.h b/src/dehacked.h index 51a838127..0d3778b28 100644 --- a/src/dehacked.h +++ b/src/dehacked.h @@ -15,20 +15,6 @@ #include "m_fixed.h" // for get_number -typedef enum -{ - UNDO_NONE = 0x00, - UNDO_NEWLINE = 0x01, - UNDO_SPACE = 0x02, - UNDO_CUTLINE = 0x04, - UNDO_HEADER = 0x07, - UNDO_ENDTEXT = 0x08, - UNDO_TODO = 0, - UNDO_DONE = 0, -} undotype_f; - -#define DEH_WriteUndoline(a,b,c) - void DEH_LoadDehackedLump(lumpnum_t lumpnum); void DEH_LoadDehackedLumpPwad(UINT16 wad, UINT16 lump); @@ -41,6 +27,7 @@ fixed_t get_number(const char *word); boolean LUA_SetLuaAction(void *state, const char *actiontocompare); const char *LUA_GetActionName(void *action); void LUA_SetActionByName(void *state, const char *actiontocompare); +enum actionnum LUA_GetActionNumByName(const char *actiontocompare); extern boolean deh_loaded; diff --git a/src/doomdef.h b/src/doomdef.h index 2b5f93b19..bdc82a0ca 100644 --- a/src/doomdef.h +++ b/src/doomdef.h @@ -128,11 +128,11 @@ extern char logfilename[1024]; #define VERSION 1 // Game version #define SUBVERSION 6 // more precise version number #ifndef USE_FBO_OGL -#define VERSIONSTRING "Saturn v6.2 " -#define VERSIONSTRINGW L"Saturn v6.2" +#define VERSIONSTRING "Saturn v7" +#define VERSIONSTRINGW L"Saturn v7" #else -#define VERSIONSTRING "Saturn v6.2 - FBO " -#define VERSIONSTRINGW L"Saturn v6.2 - FBO" +#define VERSIONSTRING "Saturn v7 - FBO " +#define VERSIONSTRINGW L"Saturn v7 - FBO" #endif // Hey! If you change this, add 1 to the MODVERSION below! Otherwise we can't force updates! // And change CMakeLists.txt (not src/, but in root), for CMake users! @@ -211,6 +211,7 @@ extern char logfilename[1024]; #define MAXPLAYERS 16 #define MAXSKINS 255 +#define MAXLOCALSKINS 32 #define PLAYERSMASK (MAXPLAYERS-1) #define MAXPLAYERNAME 21 @@ -528,6 +529,10 @@ INT32 I_GetKey(void); #define max(x, y) (((x) > (y)) ? (x) : (y)) #endif +#ifndef CLAMP +#define CLAMP(x, min_val, max_val) ((x) < (min_val) ? (min_val) : ((x) > (max_val) ? (max_val) : (x))) +#endif + #ifndef M_PIl #define M_PIl 3.1415926535897932384626433832795029L #endif @@ -563,6 +568,29 @@ extern const char *compdate, *comptime, *comprevision, *compbranch; // None of these that are disabled in the normal build are guaranteed to work perfectly // Compile them at your own risk! +#ifndef NONET +//-- SATURN __ +/// Enable gamestate resynching between Saturn servers and clients +/// Like SRB2 and RR does +/// Still highly experimental +#ifdef DOSATURNSYNCH +#define SATURNSYNCH + +/// Detect if a client is on Saturn in the clientconfig. +/// To seperately allow them to join or block joining from vanilla clients. +#ifdef DOSATURNJOIN +#define SATURNJOIN +#endif +#endif + +/// Server detection for if a connecting client is on Saturn. +/// For stuff like extra synching, etc. +//#ifdef DOSATURNPAK +//#define SATURNPAK +//#endif +//-- <( ̄︶ ̄)> __ +#endif + /// Undefine to use the new method of Gamma correction see colour cube in v_video.c #define BACKWARDSCOMPATCORRECTION diff --git a/src/doomstat.h b/src/doomstat.h index 3f90eb531..35ae67d1b 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -510,6 +510,18 @@ extern mapthing_t *playerstarts[MAXPLAYERS]; // Cooperative extern mapthing_t *bluectfstarts[MAXPLAYERS]; // CTF extern mapthing_t *redctfstarts[MAXPLAYERS]; // CTF +#define WAYPOINTSEQUENCESIZE 256 +#define NUMWAYPOINTSEQUENCES 256 +extern mobj_t *waypoints[NUMWAYPOINTSEQUENCES][WAYPOINTSEQUENCESIZE]; +extern UINT16 numwaypoints[NUMWAYPOINTSEQUENCES]; + +void P_AddWaypoint(UINT8 sequence, UINT8 id, mobj_t *waypoint); +mobj_t *P_GetFirstWaypoint(UINT8 sequence); +mobj_t *P_GetLastWaypoint(UINT8 sequence); +mobj_t *P_GetPreviousWaypoint(mobj_t *current, boolean wrap); +mobj_t *P_GetNextWaypoint(mobj_t *current, boolean wrap); +mobj_t *P_GetClosestWaypoint(UINT8 sequence, mobj_t *mo); + // ===================================== // Internal parameters, used for engine. // ===================================== diff --git a/src/doomtype.h b/src/doomtype.h index 3541e2cf6..1dcf47ea7 100644 --- a/src/doomtype.h +++ b/src/doomtype.h @@ -349,7 +349,8 @@ typedef enum postimg_motion, postimg_flip, postimg_heat, - postimg_mirror + postimg_mirror, + postimg_mirrorflip } postimg_t; typedef UINT32 lumpnum_t; // 16 : 16 unsigned long (wad num: lump num) diff --git a/src/filesrch.c b/src/filesrch.c index 55d40d811..3a3a576ce 100644 --- a/src/filesrch.c +++ b/src/filesrch.c @@ -37,7 +37,6 @@ #include #define SUFFIX "*" -#define SLASH "\\" #define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) #ifndef INVALID_FILE_ATTRIBUTES @@ -135,7 +134,7 @@ opendir (const CHAR *szPath) /* Allocate enough space to store DIR structure and the complete * directory path given. */ nd = (DIR *) malloc (sizeof (DIR) + (strlen(szFullPath) + strlen (SLASH) + - strlen(SUFFIX) + 1) * sizeof (CHAR)); + strlen(PATHSEP) + 1) * sizeof (CHAR)); if (!nd) { @@ -149,10 +148,9 @@ opendir (const CHAR *szPath) /* Add on a slash if the path does not end with one. */ if (nd->dd_name[0] != '\0' && - nd->dd_name[strlen (nd->dd_name) - 1] != '/' && - nd->dd_name[strlen (nd->dd_name) - 1] != '\\') + nd->dd_name[strlen (nd->dd_name) - 1] != PATHSEP[0]) { - strcat (nd->dd_name, SLASH); + strcat (nd->dd_name, PATHSEP); } /* Add on the search pattern */ @@ -382,9 +380,9 @@ filestatus_t filesearch(char *filename, const char *startpath, const UINT8 *want return FS_NOTFOUND; } - if (searchpath[searchpathindex[depthleft]-2] != '/') + if (searchpath[searchpathindex[depthleft]-2] != PATHSEP[0]) { - searchpath[searchpathindex[depthleft]-1] = '/'; + searchpath[searchpathindex[depthleft]-1] = PATHSEP[0]; searchpath[searchpathindex[depthleft]] = 0; } else @@ -392,7 +390,7 @@ filestatus_t filesearch(char *filename, const char *startpath, const UINT8 *want while ((!found) && (depthleft < maxsearchdepth)) { - searchpath[searchpathindex[depthleft]]=0; + searchpath[searchpathindex[depthleft]] = 0; dent = readdir(dirhandle[depthleft]); if (!dent) @@ -419,7 +417,7 @@ filestatus_t filesearch(char *filename, const char *startpath, const UINT8 *want if (S_ISDIR(fsstat.st_mode)) dent->d_type = DT_DIR; else if (S_ISLNK(fsstat.st_mode)) - dent->d_type = DT_LNK; + dent->d_type = DT_LNK; } // Symlinks aren't always directory symlinks. Dunno if this would resolve recursive @@ -447,8 +445,8 @@ filestatus_t filesearch(char *filename, const char *startpath, const UINT8 *want depthleft++; } - searchpath[searchpathindex[depthleft]-1]='/'; - searchpath[searchpathindex[depthleft]]=0; + searchpath[searchpathindex[depthleft]-1] = PATHSEP[0]; + searchpath[searchpathindex[depthleft]] = 0; } else if (!strcasecmp(searchname, dent->d_name)) { diff --git a/src/g_game.c b/src/g_game.c index 8352d0b98..27758119b 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -50,6 +50,7 @@ #include "b_bot.h" #include "m_cond.h" // condition sets #include "md5.h" // demo checksums +#include "k_director.h" // SRB2kart #include "k_kart.h" // SRB2kart #include "r_fps.h" // frame interpolation/uncapped @@ -335,6 +336,11 @@ boolean precache = true; // if true, load all graphics at start INT16 prevmap, nextmap; +// save if director is enabled +// so demos can disable it by default and restore it after +static int directorstate = 0; +tic_t directortoggletimer = 0; + static CV_PossibleValue_t recordmultiplayerdemos_cons_t[] = {{0, "Disabled"}, {1, "Manual Save"}, {2, "Auto Save"}, {0, NULL}}; consvar_t cv_recordmultiplayerdemos = {"netdemo_record", "Manual Save", CV_SAVE, recordmultiplayerdemos_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; @@ -345,6 +351,9 @@ consvar_t cv_netdemosyncquality = {"netdemo_syncquality", "1", CV_SAVE, netdemos static CV_PossibleValue_t maxdemosize_cons_t[] = {{10, "MIN"}, {100, "MAX"}, {0, NULL}}; consvar_t cv_maxdemosize = {"maxdemosize", "10", CV_SAVE, maxdemosize_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; +static CV_PossibleValue_t demochangemap_cons_t[] = {{0, "Disabled"}, {1, "Diff Map"}, {2, "Always"}, {0, NULL}}; +consvar_t cv_demochangemap = {"netdemo_savemapchange", "Disabled", CV_SAVE, demochangemap_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; + static UINT8 *savebuffer; // Analog Control @@ -417,8 +426,9 @@ consvar_t cv_songcredits = {"songcredits", "On", CV_SAVE, CV_OnOff, NULL, 0, NUL consvar_t cv_showfreeplay = { "showfreeplay", "Yes", CV_SAVE, CV_YesNo, NULL, 0, NULL, NULL, 0, 0, NULL}; // We can disable special tunes! -consvar_t cv_growmusic = {"growmusic", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; -consvar_t cv_supermusic = {"supermusic", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; +static CV_PossibleValue_t powermusic_cons_t[] = {{0, "Off"}, {1, "On"}, {2, "SFX"}, {0, NULL}}; +consvar_t cv_growmusic = {"growmusic", "On", CV_SAVE, powermusic_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_supermusic = {"supermusic", "On", CV_SAVE, powermusic_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; /*consvar_t cv_crosshair = {"crosshair", "Off", CV_SAVE, crosshair_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_crosshair2 = {"crosshair2", "Off", CV_SAVE, crosshair_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; @@ -1187,7 +1197,11 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer) // why build a ticcmd if we're paused? // Or, for that matter, if we're being reborn. // Kart, don't build a ticcmd if someone is resynching or the server is stopped too so we don't fly off course in bad conditions - if (paused || P_AutoPause() || (gamestate == GS_LEVEL && player->playerstate == PST_REBORN) || hu_resynching) + if (paused || P_AutoPause() || (gamestate == GS_LEVEL && player->playerstate == PST_REBORN) || hu_resynching +#ifdef SATURNSYNCH + || hu_redownloadinggamestate +#endif + ) { cmd->angleturn = (INT16)(lang >> 16); cmd->aiming = G_ClipAimingPitch(&laim); @@ -1637,7 +1651,7 @@ void G_DoLoadLevel(boolean resetplayer) } // Setup the level. - if (!P_SetupLevel(false)) + if (!P_SetupLevel(false,false)) { // fail so reset game stuff Command_ExitGame_f(); @@ -1934,6 +1948,12 @@ boolean G_Responder(event_t *ev) COM_ImmedExecute("changeteam4 spectator"); } } + if (ev->data1 == gamecontrol[gc_director][0] + || ev->data1 == gamecontrol[gc_director][1]) + { + K_ToggleDirector(); + directortoggletimer = 0; + } return true; @@ -2108,7 +2128,7 @@ void G_ResetView(UINT8 viewnum, INT32 playernum, boolean onlyactive) olddisplayplayer = (*displayplayerp); /* Check if anyone is available to view. */ - if (( playernum = G_FindView(playernum, viewnum, onlyactive, playernum < olddisplayplayer) ) == -1) + if ((playernum = G_FindView(playernum, viewnum, onlyactive, playernum < olddisplayplayer)) == -1) return; /* Focus our target view first so that we don't take its player. */ @@ -2118,6 +2138,8 @@ void G_ResetView(UINT8 viewnum, INT32 playernum, boolean onlyactive) camerap = &camera[viewnum-1]; P_ResetCamera(&players[(*displayplayerp)], camerap); + // Make sure the viewport doesn't interpolate at all into + // its new position -- just snap instantly into place. R_ResetViewInterpolation(viewnum); } @@ -2131,6 +2153,11 @@ void G_ResetView(UINT8 viewnum, INT32 playernum, boolean onlyactive) (*displayplayerp) = G_FindView(0, viewd, onlyactive, false); P_ResetCamera(&players[(*displayplayerp)], camerap); + + + // Make sure the viewport doesn't interpolate at all into + // its new position -- just snap instantly into place. + R_ResetViewInterpolation(viewd); } } @@ -2244,13 +2271,14 @@ void G_Ticker(boolean run) buf = gametic % TICQUEUE; if (!demo.playback) - // read/write demo and check turbo cheat - for (i = 0; i < MAXPLAYERS; i++) { - cmd = &players[i].cmd; - - if (playeringame[i]) + for (i = 0; i < MAXPLAYERS; i++) // read/write demo and check turbo cheat { + cmd = &players[i].cmd; + + if (!playeringame[i]) + continue; + //@TODO all this throwdir stuff shouldn't be here! But it stays for now to maintain 1.0.4 compat... // Remove for 1.1! @@ -2485,6 +2513,10 @@ void G_PlayerReborn(INT32 player) boolean fade; boolean playing; + tic_t laptime[LAP__MAX]; + + INT32 i; + score = players[player].score; marescore = players[player].marescore; lives = players[player].lives; @@ -2526,6 +2558,21 @@ void G_PlayerReborn(INT32 player) bot = players[player].bot; pity = players[player].pity; + if (leveltime <= starttime) // man i really hope this crap works kek but need to reset this somehow at mapstart + { + for (i = 0; i < LAP__MAX; i++) + { + laptime[i] = 0; + } + } + else + { + for (i = 0; i < LAP__MAX; i++) + { + laptime[i] = players[player].laptime[i]; + } + } + // SRB2kart if (leveltime <= starttime || spectator == true) { @@ -2617,6 +2664,11 @@ void G_PlayerReborn(INT32 player) p->laps = laps; p->totalring = totalring; + for (i = 0; i < LAP__MAX; i++) + { + p->laptime[i] = laptime[i]; + } + p->mare = mare; if (bot) p->bot = 1; // reset to AI-controlled @@ -2666,8 +2718,7 @@ void G_PlayerReborn(INT32 player) } /* I'm putting this here because lol */ - - fade = (cv_fading.value && cv_birdmusic.value && P_IsLocalPlayer(p)); + fade = (cv_birdmusic.value && cv_fading.value && P_IsLocalPlayer(p)); if (fade) { @@ -2677,7 +2728,7 @@ void G_PlayerReborn(INT32 player) Fade it in with the same call to avoid max volume for a few milliseconds (?). */ - if (! playing) + if (!playing) S_SetRestoreMusicFadeInCvar(&cv_respawnfademusicback); } @@ -3033,12 +3084,6 @@ void G_DoReborn(INT32 playernum) player_t *player = &players[playernum]; boolean starpost = false; - /*if (modeattacking) // Not needed for SRB2Kart. - { - M_EndModeAttackRun(); - return; - }*/ - // Make sure objectplace is OFF when you first start the level! OP_ResetObjectplace(); @@ -3058,68 +3103,6 @@ void G_DoReborn(INT32 playernum) if (oldmo) G_ChangePlayerReferences(oldmo, players[playernum].mo); } - /*else if (countdowntimeup || (!multiplayer && !modeattacking)) - { - // reload the level from scratch - if (countdowntimeup) - { - player->starpostangle = 0; - player->starposttime = 0; - player->starpostx = 0; - player->starposty = 0; - player->starpostz = 0; - player->starpostnum = 0; - } - if (!countdowntimeup && (mapheaderinfo[gamemap-1]->levelflags & LF_NORELOAD)) - { - INT32 i; - - player->playerstate = PST_REBORN; - - P_LoadThingsOnly(); - - // Do a wipe - wipegamestate = -1; - - if (player->starpostnum) // SRB2kart - starpost = true; - - for (i = 0; i <= splitscreen; i++) - { - if (camera[i].chase) - P_ResetCamera(&players[displayplayers[i]], &camera[i]); - } - - // clear cmd building stuff - memset(gamekeydown, 0, sizeof (gamekeydown)); - for (i = 0;i < JOYAXISSET; i++) - { - joyxmove[i] = joyymove[i] = 0; - joy2xmove[i] = joy2ymove[i] = 0; - joy3xmove[i] = joy3ymove[i] = 0; - joy4xmove[i] = joy4ymove[i] = 0; - } - mousex = mousey = 0; - mouse2x = mouse2y = 0; - - // clear hud messages remains (usually from game startup) - CON_ClearHUD(); - - // Starpost support - G_SpawnPlayer(playernum, starpost); - - if (botingame) - { // Bots respawn next to their master. - players[displayplayers[1]].playerstate = PST_REBORN; - G_SpawnPlayer(displayplayers[1], false); - } - } - else - { - LUAh_MapChange(gamemap); - G_DoLoadLevel(true); - } - }*/ else { // respawn at the start @@ -4446,6 +4429,11 @@ void G_InitNew(UINT8 pencoremode, const char *mapname, boolean resetplayer, bool players[i].starpostx = players[i].starposty = players[i].starpostz = 0; players[i].lives = 1; // SRB2Kart + // This should be cleared in P_SpawnPlayer but address sanitizer says "use-after-free" + // when reloading map sometimes + players[i].awayviewtics = 0; + players[i].awayviewmobj = NULL; + // The latter two should clear by themselves, but just in case players[i].pflags &= ~(PF_TAGIT|PF_TAGGED|PF_FULLSTASIS); @@ -7161,6 +7149,57 @@ void G_LoadDemoInfo(menudemo_t *pdemo) Z_Free(infobuffer); } +void G_LoadDemoTitle(menudemo_t *pdemo) +{ + UINT8 infobuffer[96], *info_p; + UINT16 pdemoversion; + size_t count; + + FILE *handle = fopen(pdemo->filepath, "rb"); + + if (!handle) + { + CONS_Alert(CONS_ERROR, M_GetText("Failed to read file '%s'.\n"), pdemo->filepath); + sprintf(pdemo->title, "INVALID REPLAY"); + return; + } + + count = fread(infobuffer, 1, 96, handle); + fclose(handle); + info_p = infobuffer; + + // First check isn't too accurate technically, but well, valid replays should be larger than that anyway + if (count < 96 || memcmp(info_p, DEMOHEADER, 12)) + { + CONS_Alert(CONS_ERROR, M_GetText("%s is not a SRB2Kart replay file.\n"), pdemo->filepath); + sprintf(pdemo->title, "INVALID REPLAY"); + return; + } + + info_p += 12; // DEMOHEADER + + READUINT8(info_p); + READUINT8(info_p); + pdemoversion = READUINT16(info_p); + + switch(pdemoversion) + { + case DEMOVERSION: // latest always supported + // demo title + M_Memcpy(pdemo->title, info_p, 64); + break; +#ifdef DEMO_COMPAT_100 + case 0x0001: + sprintf(pdemo->title, "Legacy Replay"); + break; +#endif + // too old, cannot support. + default: + CONS_Alert(CONS_ERROR, M_GetText("%s is an incompatible replay format and cannot be played.\n"), pdemo->filepath); + sprintf(pdemo->title, "INVALID REPLAY"); + } +} + // // G_PlayDemo // @@ -7690,6 +7729,9 @@ post_compat: players[i].kartweight = kartweight[i]; } + directorstate = cv_director.value; + CV_SetValue(&cv_director, 0); + demo.deferstart = true; } #undef SKIPERRORS @@ -8256,6 +8298,11 @@ void G_StopDemo(void) { Z_Free(demobuffer); demobuffer = NULL; + if (demo.playback) + { + CV_SetValue(&cv_director, directorstate); + directorstate = 0; + } demo.playback = false; if (demo.title) modeattacking = false; @@ -8493,6 +8540,7 @@ boolean G_DemoTitleResponder(event_t *ev) void G_SetGamestate(gamestate_t newstate) { gamestate = newstate; + #ifdef HAVE_DISCORDRPC DRPC_UpdatePresence(); #endif diff --git a/src/g_game.h b/src/g_game.h index bfc158583..14decd858 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -39,7 +39,7 @@ extern UINT8 *demo_p; // ====================================== // demoplaying back and demo recording -extern consvar_t cv_recordmultiplayerdemos, cv_netdemosyncquality, cv_maxdemosize; +extern consvar_t cv_recordmultiplayerdemos, cv_netdemosyncquality, cv_maxdemosize, cv_demochangemap; // Publicly-accessible demo vars struct demovars_s { @@ -218,6 +218,8 @@ extern angle_t localangle[MAXSPLITSCREENPLAYERS]; extern INT32 localaiming[MAXSPLITSCREENPLAYERS]; // should be an angle_t but signed extern boolean camspin[MAXSPLITSCREENPLAYERS]; // SRB2Kart +extern tic_t directortoggletimer; + // // GAME // @@ -265,6 +267,7 @@ void G_DeferedInitNew(boolean pencoremode, const char *mapname, INT32 pickedchar void G_DoLoadLevel(boolean resetplayer); void G_LoadDemoInfo(menudemo_t *pdemo); +void G_LoadDemoTitle(menudemo_t *pdemo); // For use in replay search feature void G_DeferedPlayDemo(const char *demo); // Can be called by the startup code or M_Responder, calls P_SetupLevel. diff --git a/src/g_input.c b/src/g_input.c index b6e631309..a4046350d 100644 --- a/src/g_input.c +++ b/src/g_input.c @@ -14,11 +14,17 @@ #include "doomdef.h" #include "doomstat.h" #include "g_input.h" +#include "g_game.h" #include "keys.h" #include "hu_stuff.h" // need HUFONT start & end #include "d_net.h" #include "console.h" +#include "i_system.h" +#include "i_video.h" +#include "r_draw.h" +#include "v_video.h" + #define MAXMOUSESENSITIVITY 100 // sensitivity steps static CV_PossibleValue_t mousesens_cons_t[] = {{1, "MIN"}, {MAXMOUSESENSITIVITY, "MAX"}, {0, NULL}}; @@ -33,6 +39,89 @@ consvar_t cv_mouseysens2 = {"mouseysens2", "20", CV_SAVE, mousesens_cons_t, NULL consvar_t cv_controlperkey = {"controlperkey", "One", CV_SAVE, onecontrolperkey_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_turnsmooth = {"turnsmoothing", "Slow", CV_SAVE, turnsmooth_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; +static void G_ResetPlayerDeviceRumble(INT32 player); +static void rumble_off_handle(void); +static void rumble_off_handle2(void); +static void rumble_off_handle3(void); +static void rumble_off_handle4(void); + +static void G_ResetPlayerGamepadIndicatorColor(INT32 player); +static void led_off_handle(void); +static void led_off_handle2(void); +static void led_off_handle3(void); +static void led_off_handle4(void); + +consvar_t cv_rumble[MAXSPLITSCREENPLAYERS] = { + {"rumble", "Off", CV_SAVE|CV_CALL|CV_NOINIT, CV_OnOff, rumble_off_handle, 0, NULL, NULL, 0, 0, NULL}, + {"rumble2", "Off", CV_SAVE|CV_CALL|CV_NOINIT, CV_OnOff, rumble_off_handle2, 0, NULL, NULL, 0, 0, NULL}, + {"rumble3", "Off", CV_SAVE|CV_CALL|CV_NOINIT, CV_OnOff, rumble_off_handle3, 0, NULL, NULL, 0, 0, NULL}, + {"rumble4", "Off", CV_SAVE|CV_CALL|CV_NOINIT, CV_OnOff, rumble_off_handle4, 0, NULL, NULL, 0, 0, NULL} +}; + +consvar_t cv_gamepadled[MAXSPLITSCREENPLAYERS] = { + {"gamepadled", "On", CV_SAVE|CV_CALL|CV_NOINIT, CV_OnOff, led_off_handle, 0, NULL, NULL, 0, 0, NULL}, + {"gamepadled2", "On", CV_SAVE|CV_CALL|CV_NOINIT, CV_OnOff, led_off_handle2, 0, NULL, NULL, 0, 0, NULL}, + {"gamepadled3", "On", CV_SAVE|CV_CALL|CV_NOINIT, CV_OnOff, led_off_handle3, 0, NULL, NULL, 0, 0, NULL}, + {"gamepadled4", "On", CV_SAVE|CV_CALL|CV_NOINIT, CV_OnOff, led_off_handle4, 0, NULL, NULL, 0, 0, NULL} +}; + +consvar_t cv_ledpowerup[MAXSPLITSCREENPLAYERS] = { + {"ledpowerup", "Off", CV_SAVE|CV_CALL|CV_NOINIT, CV_OnOff, led_off_handle, 0, NULL, NULL, 0, 0, NULL}, + {"ledpowerup2", "Off", CV_SAVE|CV_CALL|CV_NOINIT, CV_OnOff, led_off_handle2, 0, NULL, NULL, 0, 0, NULL}, + {"ledpowerup3", "Off", CV_SAVE|CV_CALL|CV_NOINIT, CV_OnOff, led_off_handle3, 0, NULL, NULL, 0, 0, NULL}, + {"ledpowerup4", "Off", CV_SAVE|CV_CALL|CV_NOINIT, CV_OnOff, led_off_handle4, 0, NULL, NULL, 0, 0, NULL} +}; + +static void rumble_off_handle(void) +{ + if (cv_rumble[0].value == 0) + G_ResetPlayerDeviceRumble(0); +} + + +static void rumble_off_handle2(void) +{ + if (cv_rumble[1].value == 0) + G_ResetPlayerDeviceRumble(1); +} + + +static void rumble_off_handle3(void) +{ + if (cv_rumble[2].value == 0) + G_ResetPlayerDeviceRumble(2); +} + + +static void rumble_off_handle4(void) +{ + if (cv_rumble[3].value == 0) + G_ResetPlayerDeviceRumble(3); +} + +static void led_off_handle(void) +{ + G_ResetPlayerGamepadIndicatorColor(0); +} + + +static void led_off_handle2(void) +{ + G_ResetPlayerGamepadIndicatorColor(1); +} + + +static void led_off_handle3(void) +{ + G_ResetPlayerGamepadIndicatorColor(2); +} + + +static void led_off_handle4(void) +{ + G_ResetPlayerGamepadIndicatorColor(3); +} + INT32 mousex, mousey; INT32 mlooky; // like mousey but with a custom sensitivity for mlook @@ -812,10 +901,137 @@ static const char *gamecontrolname[num_gamecontrols] = "custom1", "custom2", "custom3", + "director", }; #define NUMKEYNAMES (sizeof (keynames)/sizeof (keyname_t)) +#include "k_kart.h" + +INT32 G_GetDeviceForPlayer(INT32 player) +{ + switch (player) + { + case 0: + return cv_usejoystick.value; + break; + case 1: + return cv_usejoystick2.value; + break; + case 2: + return cv_usejoystick3.value; + break; + case 3: + return cv_usejoystick4.value; + break; + default: + return 0; + break; + } +} + +inline UINT16 G_GetSkinColor(INT32 player) +{ + // make rgb rainbow vomit when invul or flash blue when grow + if (cv_ledpowerup[player].value && gamestate == GS_LEVEL && players[displayplayers[player]].mo && (players[displayplayers[player]].kartstuff[k_invincibilitytimer] || players[displayplayers[player]].powers[pw_invulnerability] || players[displayplayers[player]].kartstuff[k_growshrinktimer])) + return players[displayplayers[player]].mo->color; + + // take actual player skincolour when ingame + if (gamestate == GS_LEVEL && players[displayplayers[player]].skincolor) + return players[displayplayers[player]].skincolor; + + // otherwise just fallback to whatever the cvar is + switch (player) + { + case 0: + return cv_playercolor.value; + break; + case 1: + return cv_playercolor2.value; + break; + case 2: + return cv_playercolor3.value; + break; + case 3: + return cv_playercolor4.value; + break; + default: + return 0; + break; + } +} + +void G_SetPlayerGamepadIndicatorColor(INT32 player, UINT16 color) +{ + INT32 device; + UINT16 skincolor; + byteColor_t byte_color; + + I_Assert(player >= 0 && player < MAXSPLITSCREENPLAYERS); + + if (cv_gamepadled[player].value == 0) + return; + + device = G_GetDeviceForPlayer(player); + + if (device <= 0) + { + return; + } + + skincolor = color ? color : G_GetSkinColor(player); + byte_color = V_GetColor(colortranslations[skincolor][8]).s; + + I_SetGamepadIndicatorColor(device, byte_color.red, byte_color.green, byte_color.blue); +} + +static void G_ResetPlayerGamepadIndicatorColor(INT32 player) +{ + if (cv_gamepadled[player].value == 0) + { + INT32 device = G_GetDeviceForPlayer(player); + if (device <= 0) + return; + + I_SetGamepadIndicatorColor(device, 0, 0, 255); + } + else + G_SetPlayerGamepadIndicatorColor(player, 0); +} + +static void G_ResetPlayerDeviceRumble(INT32 player) +{ + INT32 device_id; + + device_id = G_GetDeviceForPlayer(player); + + if (device_id < 1) + { + return; + } + + I_GamepadRumble(device_id, 0, 0, 0); +} + +void G_PlayerDeviceRumble(INT32 player, UINT16 low_strength, UINT16 high_strength, UINT32 duration) +{ + INT32 device_id; + + if (cv_rumble[player].value == 0) + { + return; + } + + device_id = G_GetDeviceForPlayer(player); + + if (device_id < 1) + { + return; + } + + I_GamepadRumble(device_id, low_strength, high_strength, duration); +} + // // Detach any keys associated to the given game control // - pass the pointer to the gamecontrol table for the player being edited diff --git a/src/g_input.h b/src/g_input.h index dac8a3e23..6799f6ca0 100644 --- a/src/g_input.h +++ b/src/g_input.h @@ -15,6 +15,7 @@ #define __G_INPUT__ #include "d_event.h" +#include "doomstat.h" #include "keys.h" #include "command.h" @@ -98,6 +99,7 @@ typedef enum gc_custom1, // Lua scriptable gc_custom2, // Lua scriptable gc_custom3, // Lua scriptable + gc_director, num_gamecontrols } gamecontrols_e; @@ -105,6 +107,9 @@ typedef enum extern consvar_t cv_mousesens, cv_mouseysens; extern consvar_t cv_mousesens2, cv_mouseysens2; extern consvar_t cv_controlperkey, cv_turnsmooth; +extern consvar_t cv_rumble[MAXSPLITSCREENPLAYERS]; +extern consvar_t cv_gamepadled[MAXSPLITSCREENPLAYERS]; +extern consvar_t cv_ledpowerup[MAXSPLITSCREENPLAYERS]; extern INT32 mousex, mousey; extern INT32 mlooky; //mousey with mlookSensitivity @@ -129,6 +134,11 @@ extern INT32 gamecontrol4[num_gamecontrols][2]; // peace to my little coder fingers! // check a gamecontrol being active or not +UINT16 G_GetSkinColor(INT32 player); +INT32 G_GetDeviceForPlayer(INT32 player); +void G_SetPlayerGamepadIndicatorColor(INT32 player, UINT16 color); +void G_PlayerDeviceRumble(INT32 player, UINT16 low_strength, UINT16 high_strength, UINT32 duration); + // remaps the input event to a game control. void G_MapEventsToControls(event_t *ev); diff --git a/src/hardware/hw_batching.c b/src/hardware/hw_batching.c index e0afb6054..a4984a905 100644 --- a/src/hardware/hw_batching.c +++ b/src/hardware/hw_batching.c @@ -35,7 +35,7 @@ int finalVertexArrayAllocSize = 65536; PolygonArrayEntry* polygonArray = NULL;// contains the polygon data from DrawPolygon, waiting to be processed int polygonArraySize = 0; -UINT32* polygonIndexArray = NULL;// contains sorting pointers for polygonArray +PolygonArrayEntry **polygonArraySorted = NULL;// contains sorted pointers to polygonArray int polygonArrayAllocSize = 65536; FOutVector* unsortedVertexArray = NULL;// contains unsorted vertices and texture coordinates from DrawPolygon @@ -47,7 +47,9 @@ int unsortedVertexArrayAllocSize = 65536; void HWR_StartBatching(void) { if (currently_batching) + { I_Error("Repeat call to HWR_StartBatching without HWR_RenderBatches"); + } // init arrays if that has not been done yet if (!finalVertexArray) @@ -55,7 +57,7 @@ void HWR_StartBatching(void) finalVertexArray = malloc(finalVertexArrayAllocSize * sizeof(FOutVector)); finalVertexIndexArray = malloc(finalVertexArrayAllocSize * 3 * sizeof(UINT32)); polygonArray = malloc(polygonArrayAllocSize * sizeof(PolygonArrayEntry)); - polygonIndexArray = malloc(polygonArrayAllocSize * sizeof(UINT32)); + polygonArraySorted = malloc(polygonArrayAllocSize * sizeof(PolygonArrayEntry *)); unsortedVertexArray = malloc(unsortedVertexArrayAllocSize * sizeof(FOutVector)); } @@ -96,8 +98,8 @@ void HWR_ProcessPolygon(FSurfaceInfo *pSurf, FOutVector *pOutVerts, FUINT iNumPt free(polygonArray); polygonArray = new_array; // also need to redo the index array, dont need to copy it though - free(polygonIndexArray); - polygonIndexArray = malloc(polygonArrayAllocSize * sizeof(UINT32)); + free(polygonArraySorted); + polygonArraySorted = malloc(polygonArrayAllocSize * sizeof(PolygonArrayEntry *)); } while (unsortedVertexArraySize + (int)iNumPts > unsortedVertexArrayAllocSize) @@ -134,10 +136,8 @@ void HWR_ProcessPolygon(FSurfaceInfo *pSurf, FOutVector *pOutVerts, FUINT iNumPt static int comparePolygons(const void *p1, const void *p2) { - unsigned int index1 = *(const unsigned int*)p1; - unsigned int index2 = *(const unsigned int*)p2; - PolygonArrayEntry* poly1 = &polygonArray[index1]; - PolygonArrayEntry* poly2 = &polygonArray[index2]; + PolygonArrayEntry *poly1 = *(PolygonArrayEntry *const *)p1; + PolygonArrayEntry *poly2 = *(PolygonArrayEntry *const *)p2; int diff; INT64 diff64; UINT32 downloaded1 = 0; @@ -155,7 +155,7 @@ static int comparePolygons(const void *p1, const void *p2) // skywalls and horizon lines must retain their order for horizon lines to work if (shader1 == -1 && shader2 == -1) - return index1 - index2; + return poly1 - poly2; if (poly1->texture) downloaded1 = poly1->texture->downloaded; // there should be a opengl texture name here, usable for comparisons @@ -184,10 +184,8 @@ static int comparePolygons(const void *p1, const void *p2) static int comparePolygonsNoShaders(const void *p1, const void *p2) { - unsigned int index1 = *(const unsigned int*)p1; - unsigned int index2 = *(const unsigned int*)p2; - PolygonArrayEntry* poly1 = &polygonArray[index1]; - PolygonArrayEntry* poly2 = &polygonArray[index2]; + PolygonArrayEntry *poly1 = *(PolygonArrayEntry *const *)p1; + PolygonArrayEntry *poly2 = *(PolygonArrayEntry *const *)p2; int diff; INT64 diff64; @@ -205,7 +203,7 @@ static int comparePolygonsNoShaders(const void *p1, const void *p2) downloaded2 = texture2->downloaded; // skywalls and horizon lines must retain their order for horizon lines to work if (!texture1 && !texture2) - return index1 - index2; + return poly1 - poly2; diff64 = downloaded1 - downloaded2; if (diff64 != 0) return diff64; @@ -225,7 +223,7 @@ void HWR_RenderBatches(void) int finalVertexWritePos = 0;// position in finalVertexArray int finalIndexWritePos = 0;// position in finalVertexIndexArray - int polygonReadPos = 0;// position in polygonIndexArray + int polygonReadPos = 0;// position in polygonArraySorted int currentShader; int nextShader = 0; @@ -258,18 +256,18 @@ void HWR_RenderBatches(void) ps_hw_numcalls.value.i = ps_hw_numverts.value.i = 0; ps_hw_numshaders.value.i = ps_hw_numtextures.value.i = ps_hw_numpolyflags.value.i = ps_hw_numcolors.value.i = 1; - // init polygonIndexArray + // init polygonArraySorted for (i = 0; i < polygonArraySize; i++) { - polygonIndexArray[i] = i; + polygonArraySorted[i] = &polygonArray[i]; } // sort polygons PS_START_TIMING(ps_hw_batchsorttime); if (cv_grshaders.value && gr_shadersavailable) - qs22j(polygonIndexArray, polygonArraySize, sizeof(unsigned int), comparePolygons); + qs22j(polygonArraySorted, polygonArraySize, sizeof(PolygonArrayEntry *), comparePolygons); else - qs22j(polygonIndexArray, polygonArraySize, sizeof(unsigned int), comparePolygonsNoShaders); + qs22j(polygonArraySorted, polygonArraySize, sizeof(PolygonArrayEntry *), comparePolygonsNoShaders); PS_STOP_TIMING(ps_hw_batchsorttime); // sort order // 1. shader @@ -280,10 +278,10 @@ void HWR_RenderBatches(void) PS_START_TIMING(ps_hw_batchdrawtime); - currentShader = polygonArray[polygonIndexArray[0]].shader; - currentTexture = polygonArray[polygonIndexArray[0]].texture; - currentPolyFlags = polygonArray[polygonIndexArray[0]].polyFlags; - currentSurfaceInfo = polygonArray[polygonIndexArray[0]].surf; + currentShader = polygonArraySorted[0]->shader; + currentTexture = polygonArraySorted[0]->texture; + currentPolyFlags = polygonArraySorted[0]->polyFlags; + currentSurfaceInfo = polygonArraySorted[0]->surf; // For now, will sort and track the colors. Vertex attributes could be used instead of uniforms // and a color array could replace the color calls. @@ -322,8 +320,8 @@ void HWR_RenderBatches(void) // reset write pos // repeat loop - int index = polygonIndexArray[polygonReadPos++]; - int numVerts = polygonArray[index].numVerts; + PolygonArrayEntry *entry = polygonArraySorted[polygonReadPos++]; + int numVerts = entry->numVerts; // before writing, check if there is enough room // using 'while' instead of 'if' here makes sure that there will *always* be enough room. // probably never will this loop run more than once though @@ -344,7 +342,7 @@ void HWR_RenderBatches(void) finalVertexIndexArray = new_index_array; } // write the vertices of the polygon - memcpy(&finalVertexArray[finalVertexWritePos], &unsortedVertexArray[polygonArray[index].vertsIndex], + memcpy(&finalVertexArray[finalVertexWritePos], &unsortedVertexArray[entry->vertsIndex], numVerts * sizeof(FOutVector)); // write the indexes, pointing to the fan vertexes but in triangles format firstIndex = finalVertexWritePos; @@ -364,11 +362,11 @@ void HWR_RenderBatches(void) else { // check if a state change is required, set the change bools and next vars - int nextIndex = polygonIndexArray[polygonReadPos]; - nextShader = polygonArray[nextIndex].shader; - nextTexture = polygonArray[nextIndex].texture; - nextPolyFlags = polygonArray[nextIndex].polyFlags; - nextSurfaceInfo = polygonArray[nextIndex].surf; + PolygonArrayEntry *nextEntry = polygonArraySorted[polygonReadPos]; + nextShader = nextEntry->shader; + nextTexture = nextEntry->texture; + nextPolyFlags = nextEntry->polyFlags; + nextSurfaceInfo = nextEntry->surf; if (nextPolyFlags & PF_NoTexture) nextTexture = 0; if (currentShader != nextShader && cv_grshaders.value && gr_shadersavailable) @@ -426,38 +424,40 @@ void HWR_RenderBatches(void) if (stopFlag) break; // change state according to change bools and next vars, update current vars and reset bools - if (changeShader) + if (changeState) { - HWD.pfnSetShader(nextShader); - currentShader = nextShader; - changeShader = false; + if (changeShader) + { + HWD.pfnSetShader(nextShader); + currentShader = nextShader; + changeShader = false; - ps_hw_numshaders.value.i++; - } - if (changeTexture) - { - // texture should be already ready for use from calls to SetTexture during batch collection - HWD.pfnSetTexture(nextTexture); - currentTexture = nextTexture; - changeTexture = false; + ps_hw_numshaders.value.i++; + } + if (changeTexture) + { + // texture should be already ready for use from calls to SetTexture during batch collection + HWD.pfnSetTexture(nextTexture); + currentTexture = nextTexture; + changeTexture = false; - ps_hw_numtextures.value.i++; - } - if (changePolyFlags) - { - currentPolyFlags = nextPolyFlags; - changePolyFlags = false; + ps_hw_numtextures.value.i++; + } + if (changePolyFlags) + { + currentPolyFlags = nextPolyFlags; + changePolyFlags = false; - ps_hw_numpolyflags.value.i++; - } - if (changeSurfaceInfo) - { - currentSurfaceInfo = nextSurfaceInfo; - changeSurfaceInfo = false; + ps_hw_numpolyflags.value.i++; + } + if (changeSurfaceInfo) + { + currentSurfaceInfo = nextSurfaceInfo; + changeSurfaceInfo = false; - ps_hw_numcolors.value.i++; + ps_hw_numcolors.value.i++; + } } - // and that should be it? } // reset the arrays (set sizes to 0) polygonArraySize = 0; diff --git a/src/hardware/hw_batching.h b/src/hardware/hw_batching.h index 7c108a4bd..22a4cc4c0 100644 --- a/src/hardware/hw_batching.h +++ b/src/hardware/hw_batching.h @@ -17,7 +17,7 @@ #include "hw_data.h" #include "hw_drv.h" -typedef struct +typedef struct { FSurfaceInfo surf;// surf also has its own polyflags for some reason, but it seems unused unsigned int vertsIndex;// location of verts in unsortedVertexArray diff --git a/src/hardware/hw_bsp.c b/src/hardware/hw_bsp.c index ebf18ed14..a5f76df06 100644 --- a/src/hardware/hw_bsp.c +++ b/src/hardware/hw_bsp.c @@ -667,9 +667,15 @@ static boolean PointInSeg(polyvertex_t *a,polyvertex_t *v1,polyvertex_t *v2) // v1 = origine ax= v2->x-v1->x; ay= v2->y-v1->y; - norm = (float)hypot(ax, ay); - ax /= norm; - ay /= norm; + norm = hypotf(ax, ay); +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wfloat-equal" + if (norm != 0) // yes, this can be exactly 0 +#pragma GCC diagnostic pop + { + ax /= norm; + ay /= norm; + } bx = a->x-v1->x; by = a->y-v1->y; //d = a.b @@ -772,9 +778,11 @@ static INT32 SolveTProblem(void) for (l = 0; l < addsubsector; l++) { p = extrasubsectors[l].planepoly; - if (p) - for (i = 0; i < p->numpts; i++) - SearchSegInBSP((INT32)numnodes-1, &p->pts[i], p); + if (!p) + continue; + + for (i = 0; i < p->numpts; i++) + SearchSegInBSP((INT32)numnodes-1, &p->pts[i], p); } //CONS_Debug(DBG_RENDER, "numsplitpoly %d\n", numsplitpoly); return numsplitpoly; @@ -802,8 +810,10 @@ static void AdjustSegs(void) count = subsectors[i].numlines; lseg = &segs[subsectors[i].firstline]; p = extrasubsectors[i].planepoly; - //if (!p) - //continue; + + if (!p) + continue; + for (; count--; lseg++) { float distv1,distv2,tmp; diff --git a/src/hardware/hw_cache.c b/src/hardware/hw_cache.c index 848f8243f..9f02007d4 100644 --- a/src/hardware/hw_cache.c +++ b/src/hardware/hw_cache.c @@ -26,6 +26,7 @@ #include "../z_zone.h" #include "../v_video.h" #include "../r_draw.h" +#include "../r_main.h" #include "../r_patch.h" // patch rotation INT32 patchformat = GL_TEXFMT_AP_88; // use alpha for holes @@ -344,7 +345,7 @@ static void HWR_GenerateTexture(INT32 texnum, GLMapTexture_t *grtex, boolean noe #ifdef GLENCORE if (encoremap && !noencore) - grtex->mipmap.colormap += (256*32); + grtex->mipmap.colormap += COLORMAP_REMAPOFFSET; #endif blockwidth = texture->width; @@ -378,18 +379,19 @@ static void HWR_GenerateTexture(INT32 texnum, GLMapTexture_t *grtex, boolean noe blockwidth, blockheight, texture, patch, realpatch); - Z_Unlock(realpatch); + Z_ChangeTag(realpatch, PU_HWRCACHE_UNLOCKED); } + //Hurdler: not efficient at all but I don't remember exactly how HWR_DrawPatchInCache works :( if (format2bpp(grtex->mipmap.format)==4) { for (i = 3; i < blocksize*4; i += 4) // blocksize*4 because blocksize doesn't include the bpp { - if (block[i] == 0) - { - grtex->mipmap.flags |= TF_TRANSPARENT; - break; - } + if (block[i] != 0) + continue; + + grtex->mipmap.flags |= TF_TRANSPARENT; + break; } } @@ -571,7 +573,6 @@ GLMapTexture_t *HWR_GetTexture(INT32 tex, boolean noencore) // If hardware does not have the texture, then call pfnSetTexture to upload it if (!grtex->mipmap.downloaded) HWD.pfnSetTexture(&grtex->mipmap); - HWR_SetCurrentTexture(&grtex->mipmap); // The system-memory data can be purged now. @@ -628,8 +629,12 @@ static void HWR_CacheFlat(GLMipmap_t *grMipmap, lumpnum_t flatlumpnum) #ifdef GLENCORE flat = grMipmap->data; for (steppy = 0; steppy < size; steppy++) - if (flat[steppy] != HWR_PATCHES_CHROMAKEY_COLORINDEX) - flat[steppy] = grMipmap->colormap[flat[steppy]]; + { + if (flat[steppy] == HWR_PATCHES_CHROMAKEY_COLORINDEX) + continue; + + flat[steppy] = grMipmap->colormap[flat[steppy]]; + } #endif } @@ -647,7 +652,7 @@ void HWR_GetFlat(lumpnum_t flatlumpnum, boolean noencoremap) #ifdef GLENCORE if (!noencoremap && encoremap) - grmip->colormap += (256*32); + grmip->colormap += COLORMAP_REMAPOFFSET; #endif if (!grmip->downloaded && !grmip->data) @@ -729,7 +734,8 @@ void HWR_GetMappedPatch(GLPatch_t *gpatch, const UINT8 *colormap) { GLMipmap_t *grmip, *newmip; - if (colormap == colormaps || colormap == NULL) + // Blatant hack for encore colormapping aside... + if (colormap == colormaps || colormap == NULL || colormap == (const UINT8*)(COLORMAP_REMAPOFFSET)) { // Load the default (green) color in doom cache (temporary?) AND hardware cache HWR_GetPatch(gpatch); @@ -741,11 +747,12 @@ void HWR_GetMappedPatch(GLPatch_t *gpatch, const UINT8 *colormap) for (grmip = gpatch->mipmap; grmip->nextcolormap; ) { grmip = grmip->nextcolormap; - if (grmip->colormap == colormap) - { - HWR_LoadMappedPatch(grmip, gpatch); - return; - } + + if (grmip->colormap != colormap) + continue; + + HWR_LoadMappedPatch(grmip, gpatch); + return; } // not found, create it! // If we are here, the sprite with the current colormap is not already in hardware memory diff --git a/src/hardware/hw_clip.c b/src/hardware/hw_clip.c index 623527549..2c6e1d52e 100644 --- a/src/hardware/hw_clip.c +++ b/src/hardware/hw_clip.c @@ -337,16 +337,16 @@ angle_t gld_FrustumAngle(angle_t tiltangle) floatangle = 2.0f + (45.0f + (tilt / 1.9f)) * clipfov / 90.0f; if (floatangle >= 180.0) return 0xffffffff; - a1 = ANG1 * (int)floatangle; + a1 = (angle_t)(ANG1 * (int)floatangle); return a1; } - // SRB2CB I don't think used any of this stuff, let's disable for now since SRB2 probably doesn't want it either // compiler complains about (p)glGetFloatv anyway, in case anyone wants this // only r_opengl.c can use the base gl funcs as it turns out, that's a problem for whoever wants sphere frustum checks // btw to renable define HAVE_SPHEREFRUSTRUM in hw_clip.h #ifdef HAVE_SPHEREFRUSTRUM + // // gld_FrustumSetup // diff --git a/src/hardware/hw_data.h b/src/hardware/hw_data.h index 569548137..b149493c5 100644 --- a/src/hardware/hw_data.h +++ b/src/hardware/hw_data.h @@ -44,7 +44,6 @@ struct GLMipmap_s UINT16 width, height; UINT32 downloaded; // tex_downloaded - struct GLMipmap_s *nextmipmap; struct GLMipmap_s *nextcolormap; const UINT8 *colormap; }; diff --git a/src/hardware/hw_defs.h b/src/hardware/hw_defs.h index b55c10bb9..7d2d17532 100644 --- a/src/hardware/hw_defs.h +++ b/src/hardware/hw_defs.h @@ -153,6 +153,7 @@ typedef struct FLOAT centerx, centery; #ifdef USE_FTRANSFORM_MIRROR boolean mirror; // SRB2Kart: Encore Mode + boolean mirrorflip; // Encore Mode with Flipcam #endif boolean shearing; // 14042019 angle_t viewaiming; // 17052019 @@ -172,9 +173,10 @@ enum { SHADER_NONE = -1, SHADER_FLOOR = 0, + SHADER_SHADOW, SHADER_WALL, - SHADER_MODEL, SHADER_SPRITE, + SHADER_MODEL, SHADER_WATER, SHADER_FOG, SHADER_SKY, diff --git a/src/hardware/hw_glob.h b/src/hardware/hw_glob.h index a5b66a429..4a8a5dd9c 100644 --- a/src/hardware/hw_glob.h +++ b/src/hardware/hw_glob.h @@ -28,13 +28,11 @@ typedef struct gr_vissprite_s float x1, x2; float z1, z2; float gz, gzt; - float tz, ty; + float tz; float scale; - //lumpnum_t patchlumpnum; float spritexscale, spriteyscale; float spritexoffset, spriteyoffset; UINT32 renderflags; - UINT8 rotateflags; GLPatch_t *gpatch; boolean flip; UINT8 translucency; //alpha level 0-255 diff --git a/src/hardware/hw_light.c b/src/hardware/hw_light.c deleted file mode 100644 index 079349c37..000000000 --- a/src/hardware/hw_light.c +++ /dev/null @@ -1,27 +0,0 @@ -// SONIC ROBO BLAST 2 -//----------------------------------------------------------------------------- -// Copyright (C) 1993-1996 by id Software, Inc. -// Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. -// -// This program is free software distributed under the -// terms of the GNU General Public License, version 2. -// See the 'LICENSE' file for more details. -//----------------------------------------------------------------------------- -/// \file - -#include "../doomdef.h" - -#ifdef HWRENDER -#include "hw_light.h" -#include "hw_drv.h" -#include "../i_video.h" -#include "../z_zone.h" -#include "../m_random.h" -#include "../m_bbox.h" -#include "../w_wad.h" -#include "../r_state.h" -#include "../r_main.h" -#include "../p_local.h" - -#endif // HWRENDER diff --git a/src/hardware/hw_light.h b/src/hardware/hw_light.h deleted file mode 100644 index fbc1d1f26..000000000 --- a/src/hardware/hw_light.h +++ /dev/null @@ -1,20 +0,0 @@ -// SONIC ROBO BLAST 2 -//----------------------------------------------------------------------------- -// Copyright (C) 1993-1996 by id Software, Inc. -// Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2019 by Sonic Team Junior. -// -// This program is free software distributed under the -// terms of the GNU General Public License, version 2. -// See the 'LICENSE' file for more details. -//----------------------------------------------------------------------------- -/// \file -/// \brief Dynamic lighting & coronas add on by Hurdler - -#ifndef _HW_LIGHTS_ -#define _HW_LIGHTS_ - -#include "hw_glob.h" -#include "hw_defs.h" - -#endif diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index 53f0e8786..ba11cd7c4 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -12,6 +12,7 @@ /// \brief hardware renderer, using the standard HardWareRender driver DLL for SRB2 #include +#include // qsort #include "../doomstat.h" @@ -24,7 +25,8 @@ #include "hw_batching.h" #include "hw_md2.h" #include "hw_clip.h" -#include "hw_light.h" + +#include "r_opengl/r_opengl.h" #include "../i_video.h" // for rendermode == render_glide #include "../v_video.h" @@ -48,8 +50,6 @@ #include "../m_argv.h" // parm functions for msaa #include "../p_slopes.h" -#include // qsort - #define ABS(x) ((x) < 0 ? -(x) : (x)) #define SOFTLIGHT(llevel) HWR_ShouldUsePaletteRendering() ? ((llevel) >> LIGHTSEGSHIFT) << LIGHTSEGSHIFT : (llevel) @@ -69,6 +69,8 @@ static boolean gr_palette_rendering_state = false; // Commands and console variables // ========================================================================== +static void HWR_RollTransform(FTransform *tr, angle_t roll); + #ifdef USE_FBO_OGL static void CV_grframebuffer_OnChange(void); #endif @@ -79,6 +81,8 @@ static void CV_grshaders_OnChange(void); static void CV_grpaletterendering_OnChange(void); static void CV_grpalettedepth_OnChange(void); +static void CV_grlightdithering_OnChange(void); + static CV_PossibleValue_t grfakecontrast_cons_t[] = {{0, "Off"}, {1, "Standard"}, {2, "Smooth"}, {0, NULL}}; static CV_PossibleValue_t grfiltermode_cons_t[]= {{HWD_SET_TEXTUREFILTER_POINTSAMPLED, "Nearest"}, @@ -103,14 +107,8 @@ consvar_t cv_grbatching = {"gr_batching", "On", 0, CV_OnOff, NULL, 0, NULL, NULL consvar_t cv_grframebuffer = {"gr_framebuffer", "Off", CV_SAVE|CV_CALL|CV_NOINIT, CV_OnOff, CV_grframebuffer_OnChange, 0, NULL, NULL, 0, 0, NULL}; #endif -consvar_t cv_grfofcut = {"gr_fofcut", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; - -consvar_t cv_fofzfightfix = {"fofzfightfix", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; - consvar_t cv_splitwallfix = {"splitwallfix", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; -consvar_t cv_slopepegfix = {"slopepegfix", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; - static CV_PossibleValue_t grrenderdistance_cons_t[] = { {0, "Max"}, {1, "1024"}, {2, "2048"}, {3, "4096"}, {4, "6144"}, {5, "8192"}, {6, "12288"}, {7, "16384"}, {0, NULL}}; @@ -118,11 +116,8 @@ consvar_t cv_grrenderdistance = {"gr_renderdistance", "Max", CV_SAVE, grrenderdi NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_grportals = {"gr_portals", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; -consvar_t cv_nostencil = {"nostencil", "Off", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; -consvar_t cv_portalline = {"portalline", "0", 0, CV_Unsigned, NULL, 0, NULL, NULL, 0, 0, NULL}; -consvar_t cv_portalonly = {"portalonly", "Off", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; -CV_PossibleValue_t secbright_cons_t[] = {{0, "MIN"}, {255, "MAX"}, {0, NULL}}; +CV_PossibleValue_t secbright_cons_t[] = {{0, "MIN"}, {255, "MAX"}, {0, NULL}}; consvar_t cv_secbright = {"secbright", "0", CV_SAVE, secbright_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; @@ -155,6 +150,8 @@ consvar_t cv_grpaletterendering = {"gr_paletteshader", "Off", CV_CALL|CV_SAVE, C static CV_PossibleValue_t glpalettedepth_cons_t[] = {{16, "16 bits"}, {24, "24 bits"}, {0, NULL}}; consvar_t cv_grpalettedepth = {"gr_palettedepth", "16 bits", CV_SAVE|CV_CALL, glpalettedepth_cons_t, CV_grpalettedepth_OnChange, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_lightdither = {"gr_lightdithering", "Off", CV_CALL|CV_SAVE, CV_OnOff, CV_grlightdithering_OnChange, 0, NULL, NULL, 0, 0, NULL}; + consvar_t cv_grflashpal = {"gr_flashpal", "On", CV_CALL|CV_SAVE, CV_OnOff, CV_grpaletterendering_OnChange, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_grmdls = {"gr_mdls", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; @@ -184,8 +181,13 @@ static void CV_anisotropic_ONChange(void) static void CV_screentextures_ONChange(void) { ONLY_IF_GL_LOADED - if (cv_grscreentextures.value != 3) + if (cv_grscreentextures.value != 2) + { +#ifdef USE_FBO_OGL + CV_Set(&cv_grframebuffer, "Off"); +#endif CV_Set(&cv_grpaletterendering, "Off"); + } HWD.pfnSetSpecialState(HWD_SET_SCREEN_TEXTURES, cv_grscreentextures.value); } @@ -203,6 +205,10 @@ static void CV_grshaders_OnChange(void) static void CV_grpaletterendering_OnChange(void) { ONLY_IF_GL_LOADED + + if (cv_grscreentextures.value != 2) // can't do palette rendering without screen textures + CV_Set(&cv_grpaletterendering, "Off"); + if (gr_shadersavailable) { HWR_CompileShaders(); @@ -210,6 +216,15 @@ static void CV_grpaletterendering_OnChange(void) } } +static void CV_grlightdithering_OnChange(void) +{ + ONLY_IF_GL_LOADED + if (gr_shadersavailable) + { + HWR_CompileShaders(); + } +} + static void CV_grpalettedepth_OnChange(void) { ONLY_IF_GL_LOADED @@ -221,6 +236,8 @@ static void CV_grpalettedepth_OnChange(void) static void CV_grframebuffer_OnChange(void) { ONLY_IF_GL_LOADED + if (cv_grscreentextures.value != 2) // screen FBO needs screen textures + CV_Set(&cv_grframebuffer, "Off"); HWD.pfnSetSpecialState(HWD_SET_FRAMEBUFFER, cv_grframebuffer.value); I_DownSample(); RefreshOGLSDLSurface(); @@ -283,6 +300,7 @@ ps_metric_t ps_hw_batchsorttime = {0}; ps_metric_t ps_hw_batchdrawtime = {0}; static void HWR_AddPrecipitationSprites(void); +static void HWR_ProjectPrecipitationSprite(precipmobj_t *thing); // ========================================================================== // View position @@ -301,6 +319,9 @@ static float gr_viewludsin, gr_viewludcos; // Visual portals (attr. Hannu Hanhi) // ========================================================================== +static boolean HWR_PortalCheckPointSide(fixed_t x, fixed_t y); +static boolean HWR_PortalCheckBBox(const fixed_t *bspcoord); + enum { GRPORTAL_OFF, @@ -339,25 +360,35 @@ typedef struct gl_portallist_s // new thing gl_portallist_t *currentportallist; -INT32 portalviewside; - -// Linked list for portals. -gl_portal_t *portal_base_gl, *portal_cap_gl; - -/* For now, these aren't used. -// maybe at some point these could be organized better -static void HWR_Portal_InitList (void) +// More precise version of R_PointToAngle2 using floats and atan2. +static angle_t R_PointToAngle2Precise(fixed_t pviewx, fixed_t pviewy, fixed_t x, fixed_t y) { - portalrender = 0; - portal_base_gl = portal_cap_gl = NULL; + fixed_t dx = x - pviewx; + fixed_t dy = y - pviewy; + float radians; + + if (!dx && !dy) + return 0; + + // no need for correct scale with FIXED_TO_FLOAT here + // since we're just calculating the angle + radians = atan2(dy, dx); + + return (angle_t)(radians / M_PI * ANGLE_180); } -static void HWR_Portal_Remove(gl_portal_t* portal) +// More precise version of R_PointToDist2 using floats and sqrt. +static fixed_t R_PointToDist2Precise(fixed_t px2, fixed_t py2, fixed_t px1, fixed_t py1) { - portal_base_gl = portal->next; - Z_Free(portal); + // float-fixed conversions can be omitted here + // because they cancel each other out in this case + + float dx = px1 - px2; + float dy = py1 - py2; + double result = sqrt(dx*dx + dy*dy); + + return (fixed_t)result; } -*/ static void HWR_Portal_Add2Lines(const INT32 line1, const INT32 line2, seg_t *seg) { @@ -395,20 +426,33 @@ static void HWR_Portal_Add2Lines(const INT32 line1, const INT32 line2, seg_t *se // Offset the portal view by the linedef centers start = &lines[line1]; dest = &lines[line2]; - dangle = R_PointToAngle2(0,0,dest->dx,dest->dy) - R_PointToAngle2(start->dx,start->dy,0,0); + + // Most fixed-point calculations and trigonometric function tables are replaced by + // floats and cmath library calls in this part to improve the precision of the + // location and angle of the new viewpoint. + // + // This reduces artefacts on the edges of portals, showing thin lines/pixels + // of the underlying graphics. (for example the sky texture) It's not 100% + // perfectly aligned and artefact-free, but looks noticeably + // better than the original code. I'm not even sure if it's this + // code or the nodebuilder or hw_map or something else causing the remaining issues.. + + dangle = R_PointToAngle2Precise(0,0,dest->dx,dest->dy) - R_PointToAngle2Precise(start->dx,start->dy,0,0); // looking glass center - start_c.x = (start->v1->x + start->v2->x) / 2; - start_c.y = (start->v1->y + start->v2->y) / 2; + start_c.x = start->v1->x/2 + start->v2->x/2; + start_c.y = start->v1->y/2 + start->v2->y/2; // other side center - dest_c.x = (dest->v1->x + dest->v2->x) / 2; - dest_c.y = (dest->v1->y + dest->v2->y) / 2; + dest_c.x = dest->v1->x/2 + dest->v2->x/2; + dest_c.y = dest->v1->y/2 + dest->v2->y/2; - disttopoint = R_PointToDist2(start_c.x, start_c.y, viewx, viewy); - angtopoint = R_PointToAngle2(start_c.x, start_c.y, viewx, viewy); + disttopoint = R_PointToDist2Precise(start_c.x, start_c.y, viewx, viewy); + angtopoint = R_PointToAngle2Precise(start_c.x, start_c.y, viewx, viewy); angtopoint += dangle; + float fang = ((float)angtopoint / 4294967296.0f) * 2.0f * M_PI; + if (dangle == 0) { portal->viewx = viewx + dest_c.x - start_c.x; @@ -416,8 +460,8 @@ static void HWR_Portal_Add2Lines(const INT32 line1, const INT32 line2, seg_t *se } else { - portal->viewx = dest_c.x + FixedMul(FINECOSINE(angtopoint>>ANGLETOFINESHIFT), disttopoint); - portal->viewy = dest_c.y + FixedMul(FINESINE(angtopoint>>ANGLETOFINESHIFT), disttopoint); + portal->viewx = dest_c.x + (fixed_t)(cos(fang) * disttopoint); + portal->viewy = dest_c.y + (fixed_t)(sin(fang) * disttopoint); } portal->viewz = viewz + dest->frontsector->floorheight - start->frontsector->floorheight; portal->viewangle = viewangle + dangle; @@ -441,7 +485,6 @@ static void HWR_PortalFrame(gl_portal_t* portal) portalclipline = &lines[portal->clipline]; portalcullsector = portalclipline->frontsector; viewsector = portalclipline->frontsector; - portalviewside = P_PointOnLineSide(viewx, viewy, portalclipline); } else { @@ -515,10 +558,8 @@ void HWR_Lighting(FSurfaceInfo *Surface, INT32 light_level, extracolormap_t *col poly_color.s.blue = (UINT8)blue; } - light_level = SOFTLIGHT(light_level); - // Clamp the light level, since it can sometimes go out of the 0-255 range from animations - light_level = min(max(light_level, cv_secbright.value), 255); + light_level = CLAMP(SOFTLIGHT(light_level), cv_secbright.value, 255); // in palette rendering mode, this is not needed since it properly takes the changes to the palette itself if (!HWR_ShouldUsePaletteRendering()) @@ -552,13 +593,8 @@ UINT8 HWR_FogBlockAlpha(INT32 light, extracolormap_t *colormap) // Let's see if } else { - light = light - (255 - light); - // Don't go out of bounds - if (light < 0) - light = 0; - else if (light > 255) - light = 255; + light = CLAMP(light - (255 - light), 0, 255); alpha = (realcolor.s.alpha*255)/25; @@ -569,83 +605,46 @@ UINT8 HWR_FogBlockAlpha(INT32 light, extracolormap_t *colormap) // Let's see if return surfcolor.s.alpha; } -static FUINT HWR_CalcWallLight(FUINT lightnum, fixed_t v1x, fixed_t v1y, fixed_t v2x, fixed_t v2y) +static FUINT HWR_CalcWallLight(FUINT lightnum, seg_t *seg) { INT16 finallight = lightnum; - if (cv_grfakecontrast.value != 0) + if (seg != NULL && cv_grfakecontrast.value != 0) { - const UINT8 contrast = 8; fixed_t extralight = 0; if (cv_grfakecontrast.value == 2) // Smooth setting - { - extralight = (-(contrast<> FRACBITS; - } + extralight += seg->hwLightOffset; else - { - if (v1y == v2y) - extralight = -contrast; - else if (v1x == v2x) - extralight = contrast; - } + extralight += seg->lightOffset * 8; if (extralight != 0) { finallight += extralight; - - if (finallight < 0) - finallight = 0; - if (finallight > 255) - finallight = 255; + finallight = CLAMP(finallight, 0 , 255); } } return (FUINT)finallight; } -static FUINT HWR_CalcSlopeLight(FUINT lightnum, angle_t dir, fixed_t delta) +static FUINT HWR_CalcSlopeLight(FUINT lightnum, pslope_t *slope) { INT16 finallight = lightnum; - if (cv_grfakecontrast.value != 0 && cv_grslopecontrast.value != 0) + if (slope != NULL && cv_grfakecontrast.value != 0 && cv_grslopecontrast.value != 0) { - const UINT8 contrast = 8; fixed_t extralight = 0; if (cv_grfakecontrast.value == 2) // Smooth setting - { - fixed_t dirmul = abs(FixedDiv(AngleFixed(dir) - (180<> FRACBITS; - } + extralight += slope->hwLightOffset; else - { - dir = ((dir + ANGLE_45) / ANGLE_90) * ANGLE_90; - - if (dir == ANGLE_180) - extralight = -contrast; - else if (dir == 0) - extralight = contrast; - - if (delta >= FRACUNIT/2) - extralight *= 2; - } + extralight += slope->lightOffset * 8; if (extralight != 0) { finallight += extralight; - - if (finallight < 0) - finallight = 0; - if (finallight > 255) - finallight = 255; + finallight = CLAMP(finallight, 0 , 255); } } @@ -660,31 +659,33 @@ static FUINT HWR_CalcSlopeLight(FUINT lightnum, angle_t dir, fixed_t delta) // Render a floor or ceiling convex polygon void HWR_RenderPlane(subsector_t *subsector, extrasubsector_t *xsub, boolean isceiling, fixed_t fixedheight, FBITFIELD PolyFlags, INT32 lightlevel, lumpnum_t lumpnum, sector_t *FOFsector, UINT8 alpha, extracolormap_t *planecolormap) { - polyvertex_t * pv; - float height; //constant y for all points on the convex flat polygon - FOutVector *v3d; - INT32 nrPlaneVerts; //verts original define of convex flat polygon - INT32 i; - float flatxref,flatyref; - float fflatsize; - INT32 flatflag; + FSurfaceInfo Surf; + FOutVector *v3d; + polyvertex_t *pv; + pslope_t *slope = NULL; + INT32 shader = SHADER_NONE; + + size_t nrPlaneVerts; + INT32 i; + + float height; // constant y for all points on the convex flat polygon + float flatxref, flatyref = 0.0f; + float fflatsize = 64.0f; + INT32 flatflag = 63; size_t len; + + float tempxsow, tempytow; float scrollx = 0.0f, scrolly = 0.0f; angle_t angle = 0; - FSurfaceInfo Surf; - fixed_t tempxsow, tempytow; - pslope_t *slope = NULL; static FOutVector *planeVerts = NULL; static UINT16 numAllocedPlaneVerts = 0; - - INT32 shader = SHADER_NONE; // no convex poly were generated for this subsector if (!xsub->planepoly) return; - pv = xsub->planepoly->pts; + pv = xsub->planepoly->pts; nrPlaneVerts = xsub->planepoly->numpts; if (nrPlaneVerts < 3) //not even a triangle ? @@ -793,12 +794,6 @@ void HWR_RenderPlane(subsector_t *subsector, extrasubsector_t *xsub, boolean isc { angle = InvAngle(angle)>>ANGLETOFINESHIFT; - // This needs to be done so that it scrolls in a different direction after rotation like software - /*tempxsow = FLOAT_TO_FIXED(scrollx); - tempytow = FLOAT_TO_FIXED(scrolly); - scrollx = (FIXED_TO_FLOAT(FixedMul(tempxsow, FINECOSINE(angle)) - FixedMul(tempytow, FINESINE(angle)))); - scrolly = (FIXED_TO_FLOAT(FixedMul(tempxsow, FINESINE(angle)) + FixedMul(tempytow, FINECOSINE(angle))));*/ - // This needs to be done so everything aligns after rotation // It would be done so that rotation is done, THEN the translation, but I couldn't get it to rotate AND scroll like software does tempxsow = FLOAT_TO_FIXED(flatxref); @@ -831,11 +826,11 @@ void HWR_RenderPlane(subsector_t *subsector, extrasubsector_t *xsub, boolean isc vert->y = FIXED_TO_FLOAT(fixedheight);\ }\ } - for (i = 0, v3d = planeVerts; i < nrPlaneVerts; i++,v3d++,pv++) + for (i = 0, v3d = planeVerts; i < (INT32)nrPlaneVerts; i++,v3d++,pv++) SETUP3DVERT(v3d, pv->x, pv->y); if (slope) - lightlevel = HWR_CalcSlopeLight(lightlevel, R_PointToAngle2(0, 0, slope->normal.x, slope->normal.y), abs(slope->zdelta)); + lightlevel = HWR_CalcSlopeLight(lightlevel, slope); HWR_Lighting(&Surf, lightlevel, planecolormap); @@ -850,11 +845,11 @@ void HWR_RenderPlane(subsector_t *subsector, extrasubsector_t *xsub, boolean isc if (HWR_UseShader()) { if (PolyFlags & PF_Fog) - shader = SHADER_FOG; // fog shader + shader = SHADER_FOG; else if (PolyFlags & PF_Ripple) - shader = SHADER_WATER; // water shader + shader = SHADER_WATER; else - shader = SHADER_FLOOR; // floor shader + shader = SHADER_FLOOR; PolyFlags |= PF_ColorMapped; } @@ -877,75 +872,75 @@ void HWR_RenderPlane(subsector_t *subsector, extrasubsector_t *xsub, boolean isc for (i = 0; i < subsector->numlines; i++, line++) { - if (line->linedef->special == HORIZONSPECIAL && R_PointOnSegSide(viewx, viewy, line) == 0) + if (!(line->linedef->special == HORIZONSPECIAL && R_PointOnSegSide(viewx, viewy, line) == 0)) + continue; + + P_ClosestPointOnLine(viewx, viewy, line->linedef, &v); + dist = FIXED_TO_FLOAT(R_PointToDist(v.x, v.y)); + + if (line->pv1) { - P_ClosestPointOnLine(viewx, viewy, line->linedef, &v); - dist = FIXED_TO_FLOAT(R_PointToDist(v.x, v.y)); - - if (line->pv1) - { - x1 = ((polyvertex_t *)line->pv1)->x; - y1 = ((polyvertex_t *)line->pv1)->y; - } - else - { - x1 = FIXED_TO_FLOAT(line->v1->x); - y1 = FIXED_TO_FLOAT(line->v1->x); - } - if (line->pv2) - { - xd = ((polyvertex_t *)line->pv2)->x - x1; - yd = ((polyvertex_t *)line->pv2)->y - y1; - } - else - { - xd = FIXED_TO_FLOAT(line->v2->x) - x1; - yd = FIXED_TO_FLOAT(line->v2->y) - y1; - } + x1 = ((polyvertex_t *)line->pv1)->x; + y1 = ((polyvertex_t *)line->pv1)->y; + } + else + { + x1 = FIXED_TO_FLOAT(line->v1->x); + y1 = FIXED_TO_FLOAT(line->v1->x); + } + if (line->pv2) + { + xd = ((polyvertex_t *)line->pv2)->x - x1; + yd = ((polyvertex_t *)line->pv2)->y - y1; + } + else + { + xd = FIXED_TO_FLOAT(line->v2->x) - x1; + yd = FIXED_TO_FLOAT(line->v2->y) - y1; + } - // Based on the seg length and the distance from the line, split horizon into multiple poly sets to reduce distortion - dist = sqrtf((xd*xd) + (yd*yd)) / dist / 16.0f; - if (dist > 100.0f) - numplanes = 100; - else - numplanes = (UINT8)dist + 1; + // Based on the seg length and the distance from the line, split horizon into multiple poly sets to reduce distortion + dist = sqrtf((xd*xd) + (yd*yd)) / dist / 16.0f; + if (dist > 100.0f) + numplanes = 100; + else + numplanes = (UINT8)dist + 1; - for (j = 0; j < numplanes; j++) - { - // Left side - vx = x1 + xd * j / numplanes; - vy = y1 + yd * j / numplanes; - SETUP3DVERT((&horizonpts[1]), vx, vy); + for (j = 0; j < numplanes; j++) + { + // Left side + vx = x1 + xd * j / numplanes; + vy = y1 + yd * j / numplanes; + SETUP3DVERT((&horizonpts[1]), vx, vy); - dist = sqrtf(powf(vx - gr_viewx, 2) + powf(vy - gr_viewy, 2)); - vx = (vx - gr_viewx) * renderdist / dist + gr_viewx; - vy = (vy - gr_viewy) * renderdist / dist + gr_viewy; - SETUP3DVERT((&horizonpts[0]), vx, vy); + dist = sqrtf(powf(vx - gr_viewx, 2) + powf(vy - gr_viewy, 2)); + vx = (vx - gr_viewx) * renderdist / dist + gr_viewx; + vy = (vy - gr_viewy) * renderdist / dist + gr_viewy; + SETUP3DVERT((&horizonpts[0]), vx, vy); - // Right side - vx = x1 + xd * (j+1) / numplanes; - vy = y1 + yd * (j+1) / numplanes; - SETUP3DVERT((&horizonpts[2]), vx, vy); + // Right side + vx = x1 + xd * (j+1) / numplanes; + vy = y1 + yd * (j+1) / numplanes; + SETUP3DVERT((&horizonpts[2]), vx, vy); - dist = sqrtf(powf(vx - gr_viewx, 2) + powf(vy - gr_viewy, 2)); - vx = (vx - gr_viewx) * renderdist / dist + gr_viewx; - vy = (vy - gr_viewy) * renderdist / dist + gr_viewy; - SETUP3DVERT((&horizonpts[3]), vx, vy); + dist = sqrtf(powf(vx - gr_viewx, 2) + powf(vy - gr_viewy, 2)); + vx = (vx - gr_viewx) * renderdist / dist + gr_viewx; + vy = (vy - gr_viewy) * renderdist / dist + gr_viewy; + SETUP3DVERT((&horizonpts[3]), vx, vy); - // Horizon fills - vx = (horizonpts[0].x - gr_viewx) * farrenderdist / renderdist + gr_viewx; - vy = (horizonpts[0].z - gr_viewy) * farrenderdist / renderdist + gr_viewy; - SETUP3DVERT((&horizonpts[5]), vx, vy); - horizonpts[5].y = gr_viewz; + // Horizon fills + vx = (horizonpts[0].x - gr_viewx) * farrenderdist / renderdist + gr_viewx; + vy = (horizonpts[0].z - gr_viewy) * farrenderdist / renderdist + gr_viewy; + SETUP3DVERT((&horizonpts[5]), vx, vy); + horizonpts[5].y = gr_viewz; - vx = (horizonpts[3].x - gr_viewx) * farrenderdist / renderdist + gr_viewx; - vy = (horizonpts[3].z - gr_viewy) * farrenderdist / renderdist + gr_viewy; - SETUP3DVERT((&horizonpts[4]), vx, vy); - horizonpts[4].y = gr_viewz; + vx = (horizonpts[3].x - gr_viewx) * farrenderdist / renderdist + gr_viewx; + vy = (horizonpts[3].z - gr_viewy) * farrenderdist / renderdist + gr_viewy; + SETUP3DVERT((&horizonpts[4]), vx, vy); + horizonpts[4].y = gr_viewz; - // Draw - HWR_ProcessPolygon(&Surf, horizonpts, 6, PolyFlags, shader, true); - } + // Draw + HWR_ProcessPolygon(&Surf, horizonpts, 6, PolyFlags, shader, true); } } } @@ -1014,7 +1009,7 @@ static void HWR_DrawSegsSplats(FSurfaceInfo * pSurf) } if (HWR_UseShader()) - shader = SHADER_WALL; // wall shader + shader = SHADER_WALL; HWR_ProcessPolygon(&pSurf, wallVerts, 4, i|PF_Modulated|PF_Decal, shader, false); } @@ -1093,7 +1088,7 @@ static void HWR_SplitWall(sector_t *sector, FOutVector *wallVerts, INT32 texnum, fixed_t v2y = FloatToFixed(wallVerts[1].z); const UINT8 alpha = Surf->PolyColor.s.alpha; - FUINT lightnum = HWR_CalcWallLight(sector->lightlevel, v1x, v1y, v2x, v2y); + FUINT lightnum = HWR_CalcWallLight(sector->lightlevel, gr_curline); extracolormap_t *colormap = NULL; realtop = top = wallVerts[3].y; @@ -1130,27 +1125,15 @@ static void HWR_SplitWall(sector_t *sector, FOutVector *wallVerts, INT32 texnum, { if (pfloor && (pfloor->flags & FF_FOG)) { - if (HWR_ShouldUsePaletteRendering()) - { - lightnum = pfloor->master->frontsector->lightlevel; - colormap = pfloor->master->frontsector->extra_colormap; - lightnum = colormap ? lightnum : HWR_CalcWallLight(lightnum, v1x, v1y, v2x, v2y); - }else{ - lightnum = HWR_CalcWallLight(pfloor->master->frontsector->lightlevel, v1x, v1y, v2x, v2y); - colormap = pfloor->master->frontsector->extra_colormap; - } + lightnum = pfloor->master->frontsector->lightlevel; + colormap = pfloor->master->frontsector->extra_colormap; + lightnum = (HWR_ShouldUsePaletteRendering() && colormap) ? lightnum : HWR_CalcWallLight(lightnum, gr_curline); } else { - if (HWR_ShouldUsePaletteRendering()) - { - lightnum = *list[i].lightlevel; - colormap = list[i].extra_colormap; - lightnum = colormap ? lightnum : HWR_CalcWallLight(lightnum, v1x, v1y, v2x, v2y); - }else{ - lightnum = HWR_CalcWallLight(*list[i].lightlevel, v1x, v1y, v2x, v2y); - colormap = list[i].extra_colormap; - } + lightnum = *list[i].lightlevel; + colormap = list[i].extra_colormap; + lightnum = (HWR_ShouldUsePaletteRendering() && colormap) ? lightnum : HWR_CalcWallLight(lightnum, gr_curline); } } @@ -1330,7 +1313,7 @@ static void HWR_DrawSkyWallList(void) // Draw walls into the depth buffer so that anything behind is culled properly void HWR_DrawSkyWall(FOutVector *wallVerts, FSurfaceInfo *Surf) { - //HWD.pfnSetTexture(NULL); + //HWR_SetCurrentTexture(NULL); // no texture wallVerts[3].t = wallVerts[2].t = 0; wallVerts[0].t = wallVerts[1].t = 0; @@ -1517,17 +1500,9 @@ void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom cliplow = (float)texturehpeg; cliphigh = (float)(texturehpeg + (gr_curline->flength*FRACUNIT)); - if (HWR_ShouldUsePaletteRendering()) - { - lightnum = gr_frontsector->lightlevel; - colormap = gr_frontsector->extra_colormap; - lightnum = colormap ? lightnum : HWR_CalcWallLight(lightnum, vs.x, vs.y, ve.x, ve.y); - } - else - { - lightnum = HWR_CalcWallLight(gr_frontsector->lightlevel, vs.x, vs.y, ve.x, ve.y); - colormap = gr_frontsector->extra_colormap; - } + lightnum = gr_frontsector->lightlevel; + colormap = gr_frontsector->extra_colormap; + lightnum = (HWR_ShouldUsePaletteRendering() && colormap) ? lightnum : HWR_CalcWallLight(lightnum, gr_curline); if (gr_linedef->flags & ML_TFERLINE) noencore = true; @@ -1540,7 +1515,7 @@ void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom // two sided line if (gr_backsector) { - INT32 gr_toptexture, gr_bottomtexture; + INT32 gr_toptexture = 0, gr_bottomtexture = 0; SLOPEPARAMS(gr_backsector->c_slope, worldhigh, worldhighslope, gr_backsector->ceilingheight) SLOPEPARAMS(gr_backsector->f_slope, worldlow, worldlowslope, gr_backsector->floorheight) @@ -1582,7 +1557,6 @@ void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom HWR_DrawSkyWall(wallVerts, &Surf); } - // Sky Floors wallVerts[0].y = wallVerts[1].y = FIXED_TO_FLOAT(INT32_MIN); @@ -1699,51 +1673,49 @@ void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom // check BOTTOM TEXTURE if ((worldlowslope > worldbottomslope || worldlow > worldbottom) && gr_bottomtexture) //only if VISIBLE!!! { + fixed_t texturevpegbottom = 0; // bottom + + grTex = HWR_GetTexture(gr_bottomtexture, gr_linedef->flags & ML_TFERLINE); + + // PEGGING + if (!(gr_linedef->flags & ML_DONTPEGBOTTOM)) + texturevpegbottom = 0; + else if (gr_linedef->flags & ML_EFFECT1) + texturevpegbottom = worldbottom - worldlow; + else + texturevpegbottom = gr_frontsector->floorheight - gr_backsector->floorheight; + + texturevpegbottom += gr_sidedef->rowoffset; + + // This is so that it doesn't overflow and screw up the wall, it doesn't need to go higher than the texture's height anyway + texturevpegbottom %= SHORT(textures[gr_bottomtexture]->height)<scaleY; + wallVerts[0].t = wallVerts[1].t = (texturevpegbottom + gr_backsector->floorheight - gr_frontsector->floorheight) * grTex->scaleY; + wallVerts[0].s = wallVerts[3].s = cliplow * grTex->scaleX; + wallVerts[2].s = wallVerts[1].s = cliphigh * grTex->scaleX; + + // Adjust t value for sloped walls + if (!(gr_linedef->flags & ML_EFFECT1)) { - fixed_t texturevpegbottom = 0; // bottom - - grTex = HWR_GetTexture(gr_bottomtexture, gr_linedef->flags & ML_TFERLINE); - - // PEGGING - if (!(gr_linedef->flags & ML_DONTPEGBOTTOM)) - texturevpegbottom = 0; - else if (gr_linedef->flags & ML_EFFECT1) - texturevpegbottom = worldbottom - worldlow; - else - texturevpegbottom = gr_frontsector->floorheight - gr_backsector->floorheight; - - texturevpegbottom += gr_sidedef->rowoffset; - - // This is so that it doesn't overflow and screw up the wall, it doesn't need to go higher than the texture's height anyway - texturevpegbottom %= SHORT(textures[gr_bottomtexture]->height)<scaleY; - wallVerts[0].t = wallVerts[1].t = (texturevpegbottom + gr_backsector->floorheight - gr_frontsector->floorheight) * grTex->scaleY; - wallVerts[0].s = wallVerts[3].s = cliplow * grTex->scaleX; - wallVerts[2].s = wallVerts[1].s = cliphigh * grTex->scaleX; - - // Adjust t value for sloped walls - if (!(gr_linedef->flags & ML_EFFECT1)) - { - // Unskewed - wallVerts[0].t -= (worldbottom - gr_frontsector->floorheight) * grTex->scaleY; - wallVerts[1].t -= (worldbottomslope - gr_frontsector->floorheight) * grTex->scaleY; - wallVerts[3].t -= (worldlow - gr_backsector->floorheight) * grTex->scaleY; - wallVerts[2].t -= (worldlowslope - gr_backsector->floorheight) * grTex->scaleY; - } - else if (gr_linedef->flags & ML_DONTPEGBOTTOM) - { - // Skewed by bottom - wallVerts[0].t = wallVerts[1].t = (texturevpegbottom + worldlow - worldbottom) * grTex->scaleY; - //wallVerts[3].t = wallVerts[0].t - (worldlow - worldbottom) * grTex->scaleY; // no need, [3] is already this - wallVerts[2].t = wallVerts[1].t - (worldlowslope - worldbottomslope) * grTex->scaleY; - } - else - { - // Skewed by top - wallVerts[0].t = (texturevpegbottom + worldlow - worldbottom) * grTex->scaleY; - wallVerts[1].t = (texturevpegbottom + worldlowslope - worldbottomslope) * grTex->scaleY; - } + // Unskewed + wallVerts[0].t -= (worldbottom - gr_frontsector->floorheight) * grTex->scaleY; + wallVerts[1].t -= (worldbottomslope - gr_frontsector->floorheight) * grTex->scaleY; + wallVerts[3].t -= (worldlow - gr_backsector->floorheight) * grTex->scaleY; + wallVerts[2].t -= (worldlowslope - gr_backsector->floorheight) * grTex->scaleY; + } + else if (gr_linedef->flags & ML_DONTPEGBOTTOM) + { + // Skewed by bottom + wallVerts[0].t = wallVerts[1].t = (texturevpegbottom + worldlow - worldbottom) * grTex->scaleY; + //wallVerts[3].t = wallVerts[0].t - (worldlow - worldbottom) * grTex->scaleY; // no need, [3] is already this + wallVerts[2].t = wallVerts[1].t - (worldlowslope - worldbottomslope) * grTex->scaleY; + } + else + { + // Skewed by top + wallVerts[0].t = (texturevpegbottom + worldlow - worldbottom) * grTex->scaleY; + wallVerts[1].t = (texturevpegbottom + worldlowslope - worldbottomslope) * grTex->scaleY; } // set top/bottom coords @@ -1888,112 +1860,41 @@ void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom grTex = HWR_GetTexture(gr_midtexture, gr_linedef->flags & ML_TFERLINE); - if (cv_slopepegfix.value) + if (!!(gr_linedef->flags & ML_DONTPEGBOTTOM) ^ !!(gr_linedef->flags & ML_EFFECT3)) { - if (!!(gr_linedef->flags & ML_DONTPEGBOTTOM) ^ !!(gr_linedef->flags & ML_EFFECT3)) - { - texturevpeg = midtexheight - h + polybottom; - texturevpegslope = midtexheight - hS + polybottomslope; - } - else - { - texturevpeg = polytop - h; - texturevpegslope = polytopslope - hS; - } - - wallVerts[3].t = texturevpeg * grTex->scaleY; - wallVerts[0].t = (h - l + texturevpeg) * grTex->scaleY; - wallVerts[2].t = texturevpegslope * grTex->scaleY; - wallVerts[1].t = (hS - lS + texturevpegslope) * grTex->scaleY; - wallVerts[0].s = wallVerts[3].s = cliplow * grTex->scaleX; - wallVerts[2].s = wallVerts[1].s = cliphigh * grTex->scaleX; - - // set top/bottom coords - // Take the texture peg into account, rather than changing the offsets past - // where the polygon might not be. - wallVerts[3].y = FIXED_TO_FLOAT(h); - wallVerts[0].y = FIXED_TO_FLOAT(l); - wallVerts[2].y = FIXED_TO_FLOAT(hS); - wallVerts[1].y = FIXED_TO_FLOAT(lS); + texturevpeg = midtexheight - h + polybottom; + texturevpegslope = midtexheight - hS + polybottomslope; } else { - // PEGGING - if (!!(gr_linedef->flags & ML_DONTPEGBOTTOM) ^ !!(gr_linedef->flags & ML_EFFECT3)) - texturevpeg = textureheight[gr_sidedef->midtexture]*repeats - h + polybottom; - else - texturevpeg = polytop - h; - - wallVerts[3].t = wallVerts[2].t = texturevpeg * grTex->scaleY; - wallVerts[0].t = wallVerts[1].t = (h - l + texturevpeg) * grTex->scaleY; - wallVerts[0].s = wallVerts[3].s = cliplow * grTex->scaleX; - wallVerts[2].s = wallVerts[1].s = cliphigh * grTex->scaleX; - - // set top/bottom coords - // Take the texture peg into account, rather than changing the offsets past - // where the polygon might not be. - wallVerts[2].y = wallVerts[3].y = FIXED_TO_FLOAT(h); - wallVerts[0].y = wallVerts[1].y = FIXED_TO_FLOAT(l); - - // Correct to account for slopes - { - fixed_t midtextureslant; - - if (gr_linedef->flags & ML_EFFECT2) - midtextureslant = 0; - else if (!!(gr_linedef->flags & ML_DONTPEGBOTTOM) ^ !!(gr_linedef->flags & ML_EFFECT3)) - midtextureslant = worldlow < worldbottom - ? worldbottomslope-worldbottom - : worldlowslope-worldlow; - else - midtextureslant = worldtop < worldhigh - ? worldtopslope-worldtop - : worldhighslope-worldhigh; - - polytop += midtextureslant; - polybottom += midtextureslant; - - highcut += worldtop < worldhigh - ? worldtopslope-worldtop - : worldhighslope-worldhigh; - lowcut += worldlow < worldbottom - ? worldbottomslope-worldbottom - : worldlowslope-worldlow; - - // Texture stuff - h = min(highcut, polytop); - l = max(polybottom, lowcut); - - { - // PEGGING - if (!!(gr_linedef->flags & ML_DONTPEGBOTTOM) ^ !!(gr_linedef->flags & ML_EFFECT3)) - texturevpeg = textureheight[gr_sidedef->midtexture]*repeats - h + polybottom; - else - texturevpeg = polytop - h; - wallVerts[2].t = texturevpeg * grTex->scaleY; - wallVerts[1].t = (h - l + texturevpeg) * grTex->scaleY; - } - - wallVerts[2].y = FIXED_TO_FLOAT(h); - wallVerts[1].y = FIXED_TO_FLOAT(l); - } + texturevpeg = polytop - h; + texturevpegslope = polytopslope - hS; } + wallVerts[3].t = texturevpeg * grTex->scaleY; + wallVerts[0].t = (h - l + texturevpeg) * grTex->scaleY; + wallVerts[2].t = texturevpegslope * grTex->scaleY; + wallVerts[1].t = (hS - lS + texturevpegslope) * grTex->scaleY; + wallVerts[0].s = wallVerts[3].s = cliplow * grTex->scaleX; + wallVerts[2].s = wallVerts[1].s = cliphigh * grTex->scaleX; + + // set top/bottom coords + // Take the texture peg into account, rather than changing the offsets past + // where the polygon might not be. + wallVerts[3].y = FIXED_TO_FLOAT(h); + wallVerts[0].y = FIXED_TO_FLOAT(l); + wallVerts[2].y = FIXED_TO_FLOAT(hS); + wallVerts[1].y = FIXED_TO_FLOAT(lS); + // TODO: Actually use the surface's flags so that I don't have to do this FUINT blendmode = Surf.PolyFlags; // Render midtextures on two-sided lines with a z-buffer offset. // This will cause the midtexture appear on top, if a FOF overlaps with it. - if (cv_fofzfightfix.value) - blendmode |= PF_Decal; + blendmode |= PF_Decal; if (!gl_drawing_stencil && gr_frontsector->numlights) - { - if (!(blendmode & PF_Masked)) - HWR_SplitWall(gr_frontsector, wallVerts, gr_midtexture, gr_linedef->flags & ML_TFERLINE, &Surf, FF_TRANSLUCENT, NULL, cv_fofzfightfix.value ? PF_Decal : 0); - else - HWR_SplitWall(gr_frontsector, wallVerts, gr_midtexture, gr_linedef->flags & ML_TFERLINE, &Surf, FF_CUTLEVEL, NULL, cv_fofzfightfix.value ? PF_Decal : 0); - } + HWR_SplitWall(gr_frontsector, wallVerts, gr_midtexture, gr_linedef->flags & ML_TFERLINE, &Surf, (!(blendmode & PF_Masked)) ? FF_TRANSLUCENT : FF_CUTLEVEL, NULL, PF_Decal); else if (!gl_drawing_stencil && !(blendmode & PF_Masked)) HWR_AddTransparentWall(wallVerts, &Surf, gr_midtexture, gr_linedef->flags & ML_TFERLINE, blendmode, false, lightnum, colormap); else @@ -2003,41 +1904,44 @@ void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom else { // Single sided line... Deal only with the middletexture (if one exists) - if (gr_midtexture && gr_linedef->special != HORIZONSPECIAL) // Ignore horizon line for OGL { + fixed_t texturevpeg; + + // PEGGING + if ((gr_linedef->flags & (ML_DONTPEGBOTTOM|ML_EFFECT2)) == (ML_DONTPEGBOTTOM|ML_EFFECT2)) + texturevpeg = gr_frontsector->floorheight + textureheight[gr_sidedef->midtexture] - gr_frontsector->ceilingheight + gr_sidedef->rowoffset; + else if (gr_linedef->flags & ML_DONTPEGBOTTOM) + texturevpeg = worldbottom + textureheight[gr_sidedef->midtexture] - worldtop + gr_sidedef->rowoffset; + else + texturevpeg = gr_sidedef->rowoffset; // top of texture at top + + grTex = HWR_GetTexture(gr_midtexture, gr_linedef->flags & ML_TFERLINE); + + wallVerts[3].t = wallVerts[2].t = texturevpeg * grTex->scaleY; + wallVerts[0].t = wallVerts[1].t = (texturevpeg + gr_frontsector->ceilingheight - gr_frontsector->floorheight) * grTex->scaleY; + wallVerts[0].s = wallVerts[3].s = cliplow * grTex->scaleX; + wallVerts[2].s = wallVerts[1].s = cliphigh * grTex->scaleX; + + // Texture correction for slopes + if (gr_linedef->flags & ML_EFFECT2) { - fixed_t texturevpeg; - // PEGGING - if ((gr_linedef->flags & (ML_DONTPEGBOTTOM|ML_EFFECT2)) == (ML_DONTPEGBOTTOM|ML_EFFECT2)) - texturevpeg = gr_frontsector->floorheight + textureheight[gr_sidedef->midtexture] - gr_frontsector->ceilingheight + gr_sidedef->rowoffset; - else if (gr_linedef->flags & ML_DONTPEGBOTTOM) - texturevpeg = worldbottom + textureheight[gr_sidedef->midtexture] - worldtop + gr_sidedef->rowoffset; - else - // top of texture at top - texturevpeg = gr_sidedef->rowoffset; - - grTex = HWR_GetTexture(gr_midtexture, gr_linedef->flags & ML_TFERLINE); - - wallVerts[3].t = wallVerts[2].t = texturevpeg * grTex->scaleY; - wallVerts[0].t = wallVerts[1].t = (texturevpeg + gr_frontsector->ceilingheight - gr_frontsector->floorheight) * grTex->scaleY; - wallVerts[0].s = wallVerts[3].s = cliplow * grTex->scaleX; - wallVerts[2].s = wallVerts[1].s = cliphigh * grTex->scaleX; - - // Texture correction for slopes - if (gr_linedef->flags & ML_EFFECT2) { - wallVerts[3].t += (gr_frontsector->ceilingheight - worldtop) * grTex->scaleY; - wallVerts[2].t += (gr_frontsector->ceilingheight - worldtopslope) * grTex->scaleY; - wallVerts[0].t += (gr_frontsector->floorheight - worldbottom) * grTex->scaleY; - wallVerts[1].t += (gr_frontsector->floorheight - worldbottomslope) * grTex->scaleY; - } else if (gr_linedef->flags & ML_DONTPEGBOTTOM) { - wallVerts[3].t = wallVerts[0].t + (worldbottom-worldtop) * grTex->scaleY; - wallVerts[2].t = wallVerts[1].t + (worldbottomslope-worldtopslope) * grTex->scaleY; - } else { - wallVerts[0].t = wallVerts[3].t - (worldbottom-worldtop) * grTex->scaleY; - wallVerts[1].t = wallVerts[2].t - (worldbottomslope-worldtopslope) * grTex->scaleY; - } + wallVerts[3].t += (gr_frontsector->ceilingheight - worldtop) * grTex->scaleY; + wallVerts[2].t += (gr_frontsector->ceilingheight - worldtopslope) * grTex->scaleY; + wallVerts[0].t += (gr_frontsector->floorheight - worldbottom) * grTex->scaleY; + wallVerts[1].t += (gr_frontsector->floorheight - worldbottomslope) * grTex->scaleY; } + else if (gr_linedef->flags & ML_DONTPEGBOTTOM) + { + wallVerts[3].t = wallVerts[0].t + (worldbottom-worldtop) * grTex->scaleY; + wallVerts[2].t = wallVerts[1].t + (worldbottomslope-worldtopslope) * grTex->scaleY; + } + else + { + wallVerts[0].t = wallVerts[3].t - (worldbottom-worldtop) * grTex->scaleY; + wallVerts[1].t = wallVerts[2].t - (worldbottomslope-worldtopslope) * grTex->scaleY; + } + //Set textures properly on single sided walls that are sloped wallVerts[3].y = FIXED_TO_FLOAT(worldtop); wallVerts[0].y = FIXED_TO_FLOAT(worldbottom); @@ -2046,8 +1950,7 @@ void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom if (gr_frontsector->numlights) HWR_SplitWall(gr_frontsector, wallVerts, gr_midtexture, gr_linedef->flags & ML_TFERLINE, &Surf, FF_CUTLEVEL, NULL, 0); - // I don't think that solid walls can use translucent linedef types... - else + else // I don't think that solid walls can use translucent linedef types... { if (grTex->mipmap.flags & TF_TRANSPARENT) HWR_AddTransparentWall(wallVerts, &Surf, gr_midtexture, gr_linedef->flags & ML_TFERLINE, PF_Environment, false, lightnum, colormap); @@ -2102,20 +2005,10 @@ void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom INT32 texnum; line_t * newline = NULL; // Multi-Property FOF - if (!cv_grfofcut.value) - { - ///TODO add slope support (fixing cutoffs, proper wall clipping) - maybe just disable highcut/lowcut if either sector or FOF has a slope - /// to allow fun plane intersecting in OGL? But then people would abuse that and make software look bad. :C - highcut = gr_frontsector->ceilingheight < gr_backsector->ceilingheight ? gr_frontsector->ceilingheight : gr_backsector->ceilingheight; - lowcut = gr_frontsector->floorheight > gr_backsector->floorheight ? gr_frontsector->floorheight : gr_backsector->floorheight; - } - else - { - lowcut = max(worldbottom, worldlow); - highcut = min(worldtop, worldhigh); - lowcutslope = max(worldbottomslope, worldlowslope); - highcutslope = min(worldtopslope, worldhighslope); - } + lowcut = max(worldbottom, worldlow); + highcut = min(worldtop, worldhigh); + lowcutslope = max(worldbottomslope, worldlowslope); + highcutslope = min(worldtopslope, worldhighslope); if (gr_backsector->ffloors) { @@ -2124,19 +2017,11 @@ void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom if (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_RENDERSIDES) || (rover->flags & FF_INVERTSIDES)) continue; - if (!cv_grfofcut.value) - { - if (*rover->topheight < lowcut || *rover->bottomheight > highcut) - continue; - } - else - { - SLOPEPARAMS(*rover->t_slope, high1, highslope1, *rover->topheight) - SLOPEPARAMS(*rover->b_slope, low1, lowslope1, *rover->bottomheight) + SLOPEPARAMS(*rover->t_slope, high1, highslope1, *rover->topheight) + SLOPEPARAMS(*rover->b_slope, low1, lowslope1, *rover->bottomheight) - if ((high1 < lowcut && highslope1 < lowcutslope) || (low1 > highcut && lowslope1 > highcutslope)) - continue; - } + if ((high1 < lowcut && highslope1 < lowcutslope) || (low1 > highcut && lowslope1 > highcutslope)) + continue; texnum = R_GetTextureNum(sides[rover->master->sidenum[0]].midtexture); @@ -2152,26 +2037,16 @@ void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom l = P_GetFFloorBottomZAt(rover, v1x, v1y); lS = P_GetFFloorBottomZAt(rover, v2x, v2y); - if (!cv_grfofcut.value) + // Adjust the heights so the FOF does not overlap with top and bottom textures. + if (h >= highcut && hS >= highcutslope) { - if (!(*rover->t_slope) && !gr_frontsector->c_slope && !gr_backsector->c_slope && h > highcut) - h = hS = highcut; - if (!(*rover->b_slope) && !gr_frontsector->f_slope && !gr_backsector->f_slope && l < lowcut) - l = lS = lowcut; + h = highcut; + hS = highcutslope; } - else + if (l <= lowcut && lS <= lowcutslope) { - // Adjust the heights so the FOF does not overlap with top and bottom textures. - if (h >= highcut && hS >= highcutslope) - { - h = highcut; - hS = highcutslope; - } - if (l <= lowcut && lS <= lowcutslope) - { - l = lowcut; - lS = lowcutslope; - } + l = lowcut; + lS = lowcutslope; } //Hurdler: HW code starts here @@ -2248,16 +2123,10 @@ void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom blendmode = PF_Fog|PF_NoTexture; - if (HWR_ShouldUsePaletteRendering()) - { - lightnum = rover->master->frontsector->lightlevel; - colormap = rover->master->frontsector->extra_colormap; - lightnum = colormap ? lightnum : HWR_CalcWallLight(lightnum, vs.x, vs.y, ve.x, ve.y); - }else{ - lightnum = HWR_CalcWallLight(rover->master->frontsector->lightlevel, vs.x, vs.y, ve.x, ve.y); - colormap = rover->master->frontsector->extra_colormap; - } - + lightnum = rover->master->frontsector->lightlevel; + colormap = rover->master->frontsector->extra_colormap; + lightnum = (HWR_ShouldUsePaletteRendering() && colormap) ? lightnum : HWR_CalcWallLight(lightnum, gr_curline); + Surf.PolyColor.s.alpha = HWR_FogBlockAlpha(rover->master->frontsector->lightlevel, rover->master->frontsector->extra_colormap); if (gr_frontsector->numlights) @@ -2272,7 +2141,7 @@ void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom if (rover->flags & FF_TRANSLUCENT && rover->alpha < 256) { blendmode = PF_Translucent; - Surf.PolyColor.s.alpha = max(0, min(rover->alpha, 255)); + Surf.PolyColor.s.alpha = CLAMP(rover->alpha, 0, 255); } if (gr_frontsector->numlights) @@ -2295,20 +2164,11 @@ void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom if (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_RENDERSIDES) || !(rover->flags & FF_ALLSIDES)) continue; - if (!cv_grfofcut.value) - { - if (*rover->topheight < lowcut || *rover->bottomheight > highcut) - continue; - } - else - { - SLOPEPARAMS(*rover->t_slope, high1, highslope1, *rover->topheight) - SLOPEPARAMS(*rover->b_slope, low1, lowslope1, *rover->bottomheight) - - if ((high1 < lowcut && highslope1 < lowcutslope) || (low1 > highcut && lowslope1 > highcutslope)) - continue; - } + SLOPEPARAMS(*rover->t_slope, high1, highslope1, *rover->topheight) + SLOPEPARAMS(*rover->b_slope, low1, lowslope1, *rover->bottomheight) + if ((high1 < lowcut && highslope1 < lowcutslope) || (low1 > highcut && lowslope1 > highcutslope)) + continue; texnum = R_GetTextureNum(sides[rover->master->sidenum[0]].midtexture); @@ -2324,26 +2184,16 @@ void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom l = P_GetFFloorBottomZAt(rover, v1x, v1y); lS = P_GetFFloorBottomZAt(rover, v2x, v2y); - if (!cv_grfofcut.value) + // Adjust the heights so the FOF does not overlap with top and bottom textures. + if (h >= highcut && hS >= highcutslope) { - if (!(*rover->t_slope) && !gr_frontsector->c_slope && !gr_backsector->c_slope && h > highcut) - h = hS = highcut; - if (!(*rover->b_slope) && !gr_frontsector->f_slope && !gr_backsector->f_slope && l < lowcut) - l = lS = lowcut; + h = highcut; + hS = highcutslope; } - else + if (l <= lowcut && lS <= lowcutslope) { - // Adjust the heights so the FOF does not overlap with top and bottom textures. - if (h >= highcut && hS >= highcutslope) - { - h = highcut; - hS = highcutslope; - } - if (l <= lowcut && lS <= lowcutslope) - { - l = lowcut; - lS = lowcutslope; - } + l = lowcut; + lS = lowcutslope; } //Hurdler: HW code starts here @@ -2387,15 +2237,9 @@ void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom blendmode = PF_Fog|PF_NoTexture; - if (HWR_ShouldUsePaletteRendering()) - { - lightnum = rover->master->frontsector->lightlevel; - colormap = rover->master->frontsector->extra_colormap; - lightnum = colormap ? lightnum : HWR_CalcWallLight(lightnum, vs.x, vs.y, ve.x, ve.y); - }else{ - lightnum = HWR_CalcWallLight(rover->master->frontsector->lightlevel, vs.x, vs.y, ve.x, ve.y); - colormap = rover->master->frontsector->extra_colormap; - } + lightnum = rover->master->frontsector->lightlevel; + colormap = rover->master->frontsector->extra_colormap; + lightnum = (HWR_ShouldUsePaletteRendering() && colormap) ? lightnum : HWR_CalcWallLight(lightnum, gr_curline); Surf.PolyColor.s.alpha = HWR_FogBlockAlpha(rover->master->frontsector->lightlevel, rover->master->frontsector->extra_colormap); @@ -2411,7 +2255,7 @@ void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom if (rover->flags & FF_TRANSLUCENT && rover->alpha < 256) { blendmode = PF_Translucent; - Surf.PolyColor.s.alpha = max(0, min(rover->alpha, 255)); + Surf.PolyColor.s.alpha = CLAMP(rover->alpha, 0, 255); } if (gr_backsector->numlights) @@ -2427,7 +2271,6 @@ void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom } } } - #undef SLOPEPARAMS //Hurdler: end of 3d-floors test } @@ -2567,8 +2410,7 @@ static boolean CheckClip(sector_t * afrontsector, sector_t * abacksector) // Window. // We know it's a window when the above isn't true and the back and front sectors don't match - if (backc1 != frontc1 || backc2 != frontc2 - || backf1 != frontf1 || backf2 != frontf2) + if (backc1 != frontc1 || backc2 != frontc2 || backf1 != frontf1 || backf2 != frontf2) { checkforemptylines = false; return false; @@ -2619,16 +2461,8 @@ static void HWR_AddLine(seg_t *line) } // OPTIMIZE: quickly reject orthogonal back sides. - if (cv_pointoangleexor64.value) - { - angle1 = R_PointToAngle64(v1x, v1y); - angle2 = R_PointToAngle64(v2x, v2y); - } - else - { - angle1 = R_PointToAngleEx(viewx, viewy, v1x, v1y); - angle2 = R_PointToAngleEx(viewx, viewy, v2x, v2y); - } + angle1 = R_PointToAngle64(v1x, v1y); + angle2 = R_PointToAngle64(v2x, v2y); // PrBoom: Back side, i.e. backface culling - read: endAngle >= startAngle! if (angle2 - angle1 < ANGLE_180 || !gr_curline->linedef) @@ -2642,37 +2476,17 @@ static void HWR_AddLine(seg_t *line) gr_backsector = line->backsector; - // do an extra culling check when rendering portals - // check if any line vertex is on the viewable side of the portal target line - // if not, the line can be culled. - if (portalclipline)// portalclipline should be NULL when we are not rendering portal contents + // do extra checks on the seg when rendering portals: + // don't render segs that are behind the portal destination line + if (portalclipline && + !HWR_PortalCheckPointSide(line->v1->x, line->v1->y) && + !HWR_PortalCheckPointSide(line->v2->x, line->v2->y)) { - vertex_t closest_point; - boolean pass = false; - - // similar idea than in PortalCheckBBox, but checking the line vertices instead - // TODO could make the check more efficient and not check anything if pass==true from earlier or something - P_ClosestPointOnLine(line->v1->x, line->v1->y, portalclipline, &closest_point); - if (closest_point.x != line->v1->x || closest_point.y != line->v1->y) - { - if (P_PointOnLineSide(line->v1->x, line->v1->y, portalclipline) != portalviewside) - pass = true; - } - P_ClosestPointOnLine(line->v2->x, line->v2->y, portalclipline, &closest_point); - if (closest_point.x != line->v2->x || closest_point.y != line->v2->y) - { - if (P_PointOnLineSide(line->v2->x, line->v2->y, portalclipline) != portalviewside) - pass = true; - } - if (!pass) - return; + return; } if (gr_portal == GRPORTAL_STENCIL || gr_portal == GRPORTAL_DEPTH) - { - gr_backsector = line->backsector; goto doaddline; - } if (line->linedef->special == 40) { @@ -2709,6 +2523,7 @@ doaddline: gld_clipper_SafeAddClipRange(angle2, angle1); checkforemptylines = false; } + // Reject empty lines used for triggers and special events. // Identical floor and ceiling on both sides, // identical light levels on both sides, @@ -2824,16 +2639,8 @@ static boolean HWR_CheckBBox(const fixed_t *bspcoord) if (mindist > current_bsp_culling_distance) return false; } - if (cv_pointoangleexor64.value) - { - angle1 = R_PointToAngle64(px1, py1); - angle2 = R_PointToAngle64(px2, py2); - } - else - { - angle1 = R_PointToAngleEx(viewx, viewy, px1, py1); - angle2 = R_PointToAngleEx(viewx, viewy, px2, py2); - } + angle1 = R_PointToAngle64(px1, py1); + angle2 = R_PointToAngle64(px2, py2); return gld_clipper_SafeCheckRange(angle2, angle1); } @@ -2846,12 +2653,9 @@ static boolean HWR_CheckBBox(const fixed_t *bspcoord) // Adds all segs in all polyobjects in the given subsector. // Modified for hardware rendering. // -void HWR_AddPolyObjectSegs(void) +static inline void HWR_AddPolyObjectSegs(void) { size_t i, j; - seg_t gr_fakeline; - polyvertex_t pv1; - polyvertex_t pv2; // Sort through all the polyobjects for (i = 0; i < numpolys; ++i) @@ -2859,19 +2663,7 @@ void HWR_AddPolyObjectSegs(void) // Render the polyobject's lines for (j = 0; j < po_ptrs[i]->segCount; ++j) { - // Copy the info of a polyobject's seg, then convert it to OpenGL floating point - M_Memcpy(&gr_fakeline, po_ptrs[i]->segs[j], sizeof(seg_t)); - - // Now convert the line to float and add it to be rendered - pv1.x = FIXED_TO_FLOAT(gr_fakeline.v1->x); - pv1.y = FIXED_TO_FLOAT(gr_fakeline.v1->y); - pv2.x = FIXED_TO_FLOAT(gr_fakeline.v2->x); - pv2.y = FIXED_TO_FLOAT(gr_fakeline.v2->y); - - gr_fakeline.pv1 = &pv1; - gr_fakeline.pv2 = &pv2; - - HWR_AddLine(&gr_fakeline); + HWR_AddLine(po_ptrs[i]->segs[j]); } } } @@ -3040,17 +2832,18 @@ void HWR_RenderPolyObjectPlane(polyobj_t *polysector, boolean isceiling, fixed_t if (HWR_UseShader()) { - shader = SHADER_FLOOR; // floor shader + shader = SHADER_FLOOR; blendmode |= PF_ColorMapped; } - HWR_ProcessPolygon(&Surf, planeVerts, nrPlaneVerts, blendmode, shader, false); // floor shader + HWR_ProcessPolygon(&Surf, planeVerts, nrPlaneVerts, blendmode, shader, false); } -void HWR_AddPolyObjectPlanes(void) +static void HWR_AddPolyObjectPlanes(void) { size_t i; sector_t *polyobjsector; + INT32 light = 0; // Polyobject Planes need their own function for drawing because they don't have extrasubsectors by themselves // It should be okay because polyobjects should always be convex anyway @@ -3069,19 +2862,22 @@ void HWR_AddPolyObjectPlanes(void) && polyobjsector->floorheight >= gr_frontsector->floorheight && (viewz < polyobjsector->floorheight)) { + light = R_GetPlaneLight(gr_frontsector, polyobjsector->floorheight, true); if (po_ptrs[i]->translucency > 0) { FSurfaceInfo Surf; - FBITFIELD blendmode = HWR_TranstableToAlpha(po_ptrs[i]->translucency, &Surf); + FBITFIELD blendmode; + memset(&Surf, 0x00, sizeof(Surf)); + blendmode = HWR_TranstableToAlpha(po_ptrs[i]->translucency, &Surf); HWR_AddTransparentPolyobjectFloor(levelflats[polyobjsector->floorpic].lumpnum, po_ptrs[i], false, polyobjsector->floorheight, - polyobjsector->lightlevel, Surf.PolyColor.s.alpha, polyobjsector, blendmode, NULL); + (light == -1 ? gr_frontsector->lightlevel : *gr_frontsector->lightlist[light].lightlevel), Surf.PolyColor.s.alpha, polyobjsector, blendmode, (light == -1 ? gr_frontsector->extra_colormap : gr_frontsector->lightlist[light].extra_colormap)); } else { HWR_GetFlat(levelflats[polyobjsector->floorpic].lumpnum, R_NoEncore(polyobjsector, false)); HWR_RenderPolyObjectPlane(po_ptrs[i], false, polyobjsector->floorheight, PF_Occlude, - polyobjsector->lightlevel, levelflats[polyobjsector->floorpic].lumpnum, - polyobjsector, 255, NULL); + (light == -1 ? gr_frontsector->lightlevel : *gr_frontsector->lightlist[light].lightlevel), levelflats[polyobjsector->floorpic].lumpnum, + polyobjsector, 255, (light == -1 ? gr_frontsector->extra_colormap : gr_frontsector->lightlist[light].extra_colormap)); } } @@ -3089,6 +2885,7 @@ void HWR_AddPolyObjectPlanes(void) && polyobjsector->ceilingheight <= gr_frontsector->ceilingheight && (viewz > polyobjsector->ceilingheight)) { + light = R_GetPlaneLight(gr_frontsector, polyobjsector->ceilingheight, true); if (po_ptrs[i]->translucency > 0) { FSurfaceInfo Surf; @@ -3096,14 +2893,14 @@ void HWR_AddPolyObjectPlanes(void) memset(&Surf, 0x00, sizeof(Surf)); blendmode = HWR_TranstableToAlpha(po_ptrs[i]->translucency, &Surf); HWR_AddTransparentPolyobjectFloor(levelflats[polyobjsector->ceilingpic].lumpnum, po_ptrs[i], true, polyobjsector->ceilingheight, - polyobjsector->lightlevel, Surf.PolyColor.s.alpha, polyobjsector, blendmode, NULL); + (light == -1 ? gr_frontsector->lightlevel : *gr_frontsector->lightlist[light].lightlevel), Surf.PolyColor.s.alpha, polyobjsector, blendmode, (light == -1 ? gr_frontsector->extra_colormap : gr_frontsector->lightlist[light].extra_colormap)); } else { HWR_GetFlat(levelflats[polyobjsector->ceilingpic].lumpnum, R_NoEncore(polyobjsector, true)); HWR_RenderPolyObjectPlane(po_ptrs[i], true, polyobjsector->ceilingheight, PF_Occlude, - polyobjsector->lightlevel, levelflats[polyobjsector->ceilingpic].lumpnum, - polyobjsector, 255, NULL); + (light == -1 ? gr_frontsector->lightlevel : *gr_frontsector->lightlist[light].lightlevel), levelflats[polyobjsector->ceilingpic].lumpnum, + polyobjsector, 255, (light == -1 ? gr_frontsector->extra_colormap : gr_frontsector->lightlist[light].extra_colormap)); } } } @@ -3200,7 +2997,6 @@ static void HWR_Subsector(size_t num) //SoM: 4/7/2000: Test to make Boom water work in Hardware mode. gr_frontsector = R_FakeFlat(gr_frontsector, &tempsec, &floorlightlevel, &ceilinglightlevel, false); - //FIXME: Use floorlightlevel and ceilinglightlevel insted of lightlevel. if (gr_portal == GRPORTAL_SEARCH) { @@ -3225,11 +3021,11 @@ static void HWR_Subsector(size_t num) { sector_t *controlSec = §ors[rover->secnum]; - if (controlSec->moved == true) - { - anyMoved = true; - break; - } + if (controlSec->moved != true) + continue; + + anyMoved = true; + break; } } @@ -3344,7 +3140,7 @@ static void HWR_Subsector(size_t num) false, *rover->bottomheight, *gr_frontsector->lightlist[light].lightlevel, - max(0, min(rover->alpha, 255)), rover->master->frontsector, (rover->flags & FF_RIPPLE ? PF_Ripple : 0)|PF_Translucent, + CLAMP(rover->alpha, 0 ,255), rover->master->frontsector, (rover->flags & FF_RIPPLE ? PF_Ripple : 0)|PF_Translucent, false, gr_frontsector->lightlist[light].extra_colormap); } else @@ -3384,11 +3180,11 @@ static void HWR_Subsector(size_t num) { light = R_GetPlaneLight(gr_frontsector, centerHeight, viewz < topCullHeight ? true : false); HWR_AddTransparentFloor(levelflats[*rover->toppic].lumpnum, - &extrasubsectors[num], + &extrasubsectors[num], true, *rover->topheight, *gr_frontsector->lightlist[light].lightlevel, - max(0, min(rover->alpha, 255)), rover->master->frontsector, (rover->flags & FF_RIPPLE ? PF_Ripple : 0)|PF_Translucent, + CLAMP(rover->alpha, 0 ,255), rover->master->frontsector, (rover->flags & FF_RIPPLE ? PF_Ripple : 0)|PF_Translucent, false, gr_frontsector->lightlist[light].extra_colormap); } else @@ -3470,7 +3266,6 @@ skip_stuff_for_portals: // if its zero (or very close?) then dont return true, instead continue to next side check // it helped with center pillars! but other parts still have issues, probably because some of bounding box is on correct side. - // idea for further clipping improvement: // have a separate xyz coordinate for portal view side checking: one that is derived by moving the viewxyz forward // the new coords would be at the intersection of line_a and line_b, where @@ -3483,40 +3278,36 @@ skip_stuff_for_portals: // use returned value as multiplier for the added values from p_thrust thing // P_InterceptVector needs divlines which need dx and dy, dx=x2-x1 dy=y2-y1 -static boolean HWR_PortalCheckBBox(const fixed_t *bspcoord) +// returns true if the point is on the correct (viewable) side of the +// portal destination line +static boolean HWR_PortalCheckPointSide(fixed_t x, fixed_t y) { - vertex_t closest_point; - if (!portalclipline) - return true; - - // we are looking for a bounding box corner that is on the viewable side of the portal exit. + // we are checking if the point is on the viewable side of the portal exit. // being exactly on the portal exit line is not enough to pass the test. // P_PointOnLineSide could behave differently from this expectation on this case, // so first check if the point is precisely on the line, and then if not, check the side. - P_ClosestPointOnLine(bspcoord[BOXLEFT], bspcoord[BOXTOP], portalclipline, &closest_point); - if (closest_point.x != bspcoord[BOXLEFT] || closest_point.y != bspcoord[BOXTOP]) + vertex_t closest_point; + P_ClosestPointOnLine(x, y, portalclipline, &closest_point); + if (closest_point.x != x || closest_point.y != y) { - if (P_PointOnLineSide(bspcoord[BOXLEFT], bspcoord[BOXTOP], portalclipline) != portalviewside) + if (P_PointOnLineSide(x, y, portalclipline) != 1) return true; } - P_ClosestPointOnLine(bspcoord[BOXLEFT], bspcoord[BOXBOTTOM], portalclipline, &closest_point); - if (closest_point.x != bspcoord[BOXLEFT] || closest_point.y != bspcoord[BOXBOTTOM]) + return false; +} + +static boolean HWR_PortalCheckBBox(const fixed_t *bspcoord) +{ + if (!portalclipline) + return true; + + if (HWR_PortalCheckPointSide(bspcoord[BOXLEFT], bspcoord[BOXTOP]) || + HWR_PortalCheckPointSide(bspcoord[BOXLEFT], bspcoord[BOXBOTTOM]) || + HWR_PortalCheckPointSide(bspcoord[BOXRIGHT], bspcoord[BOXTOP]) || + HWR_PortalCheckPointSide(bspcoord[BOXRIGHT], bspcoord[BOXBOTTOM])) { - if (P_PointOnLineSide(bspcoord[BOXLEFT], bspcoord[BOXBOTTOM], portalclipline) != portalviewside) - return true; - } - P_ClosestPointOnLine(bspcoord[BOXRIGHT], bspcoord[BOXTOP], portalclipline, &closest_point); - if (closest_point.x != bspcoord[BOXRIGHT] || closest_point.y != bspcoord[BOXTOP]) - { - if (P_PointOnLineSide(bspcoord[BOXRIGHT], bspcoord[BOXTOP], portalclipline) != portalviewside) - return true; - } - P_ClosestPointOnLine(bspcoord[BOXRIGHT], bspcoord[BOXBOTTOM], portalclipline, &closest_point); - if (closest_point.x != bspcoord[BOXRIGHT] || closest_point.y != bspcoord[BOXBOTTOM]) - { - if (P_PointOnLineSide(bspcoord[BOXRIGHT], bspcoord[BOXBOTTOM], portalclipline) != portalviewside) - return true; + return true; } // we did not find any reason to pass the check, so return failure @@ -3530,14 +3321,16 @@ static boolean HWR_PortalCheckBBox(const fixed_t *bspcoord) static void HWR_RenderBSPNode(INT32 bspnum) { + const node_t *bsp; + INT32 side; ps_numbspcalls.value.i++; while (!(bspnum & NF_SUBSECTOR)) // Found a subsector? { - const node_t *bsp = &nodes[bspnum]; + bsp = &nodes[bspnum]; // Decide which side the view point is on. - INT32 side = R_PointOnSide(viewx, viewy, bsp); + side = R_PointOnSide(viewx, viewy, bsp); // Recursively divide front space. if (HWR_PortalCheckBBox(bsp->bbox[side])) @@ -3555,8 +3348,10 @@ static void HWR_RenderBSPNode(INT32 bspnum) { if (portalcullsector != subsectors[bspnum & ~NF_SUBSECTOR].sector) return; - portalcullsector = NULL; + else + portalcullsector = NULL; } + // e6y: support for extended nodes HWR_Subsector(bspnum == -1 ? 0 : bspnum & ~NF_SUBSECTOR); } @@ -3627,24 +3422,36 @@ static fixed_t HWR_OpaqueFloorAtPos(fixed_t x, fixed_t y, fixed_t z, fixed_t hei delta1 = z - (*rover->bottomheight + ((*rover->topheight - *rover->bottomheight)/2)); delta2 = thingtop - (*rover->bottomheight + ((*rover->topheight - *rover->bottomheight)/2)); - if (*rover->topheight > floorz && abs(delta1) < abs(delta2)) - floorz = *rover->topheight; + + if (!(*rover->topheight > floorz && abs(delta1) < abs(delta2))) + continue; + + floorz = *rover->topheight; } } return floorz; } -static void HWR_DrawSpriteShadow(gr_vissprite_t *spr, GLPatch_t *gpatch, float this_scale) +static void HWR_DrawSpriteShadow(gr_vissprite_t *spr, GLPatch_t *gpatch) { + float this_scale = 1.0f; FOutVector swallVerts[4]; FSurfaceInfo sSurf; + FBITFIELD blendmode = 0; fixed_t floorheight, mobjfloor; pslope_t *floorslope; fixed_t slopez; float offset = 0; INT32 shader = SHADER_NONE; + + // technically this_scale gets multiplied and added to sprite y/x scale, but this thing needs it for some crap so ill just throw it in here again + const boolean hires = (spr->mobj && spr->mobj->skin && ((skin_t *)( (spr->mobj->localskin) ? spr->mobj->localskin : spr->mobj->skin ))->flags & SF_HIRES); + if (spr->mobj) + this_scale = FIXED_TO_FLOAT(spr->mobj->scale); + if (hires) + this_scale = this_scale * FIXED_TO_FLOAT(((skin_t *)( (spr->mobj->localskin) ? spr->mobj->localskin : spr->mobj->skin ))->highresscale); R_GetShadowZ(spr->mobj, &floorslope); @@ -3713,7 +3520,7 @@ static void HWR_DrawSpriteShadow(gr_vissprite_t *spr, GLPatch_t *gpatch, float t if (spr->mobj && fabsf(this_scale - 1.0f) > 1.0E-36f) { // Always a pixel above the floor, perfectly flat. - swallVerts[0].y = swallVerts[1].y = swallVerts[2].y = swallVerts[3].y = spr->ty - gpatch->topoffset * this_scale - (floorheight+3); + swallVerts[0].y = swallVerts[1].y = swallVerts[2].y = swallVerts[3].y = spr->gzt - gpatch->topoffset * this_scale - (floorheight+3); // Now transform the TOP vertices along the floor in the direction of the camera swallVerts[3].x = spr->x1 + ((gpatch->height * this_scale) + offset) * gr_viewcos; @@ -3724,7 +3531,7 @@ static void HWR_DrawSpriteShadow(gr_vissprite_t *spr, GLPatch_t *gpatch, float t else { // Always a pixel above the floor, perfectly flat. - swallVerts[0].y = swallVerts[1].y = swallVerts[2].y = swallVerts[3].y = spr->ty - gpatch->topoffset - (floorheight+3); + swallVerts[0].y = swallVerts[1].y = swallVerts[2].y = swallVerts[3].y = spr->gzt - gpatch->topoffset - (floorheight+3); // Now transform the TOP vertices along the floor in the direction of the camera swallVerts[3].x = spr->x1 + (gpatch->height + offset) * gr_viewcos; @@ -3794,13 +3601,14 @@ static void HWR_DrawSpriteShadow(gr_vissprite_t *spr, GLPatch_t *gpatch, float t if (sSurf.PolyColor.s.alpha > floorheight/4) { sSurf.PolyColor.s.alpha = (UINT8)(sSurf.PolyColor.s.alpha - floorheight/4); - + if (HWR_UseShader()) { - shader = SHADER_FLOOR; // floor shader + shader = SHADER_SHADOW; + blendmode |= PF_ColorMapped; } - HWR_ProcessPolygon(&sSurf, swallVerts, 4, PF_Translucent|PF_Modulated, shader, false); + HWR_ProcessPolygon(&sSurf, swallVerts, 4, blendmode|PF_Translucent|PF_Modulated, shader, false); } } @@ -3841,7 +3649,7 @@ static void HWR_RotateSpritePolyToAim(gr_vissprite_t *spr, FOutVector *wallVerts } } - if (P_MobjFlip(spr->mobj) == -1) + if (!precip && P_MobjFlip(spr->mobj) == -1) // precip doesn't have eflags so they can't flip { basey = FIXED_TO_FLOAT(interp.z + spr->mobj->height); } @@ -3874,12 +3682,10 @@ static void HWR_RotateSpritePolyToAim(gr_vissprite_t *spr, FOutVector *wallVerts static void HWR_SplitSprite(gr_vissprite_t *spr) { - float this_scale = 1.0f; FOutVector wallVerts[4]; FOutVector baseWallVerts[4]; // This is what the verts should end up as GLPatch_t *gpatch; FSurfaceInfo Surf; - const boolean hires = (spr->mobj && spr->mobj->skin && ((skin_t *)( (spr->mobj->localskin) ? spr->mobj->localskin : spr->mobj->skin ))->flags & SF_HIRES); extracolormap_t *colormap; FUINT lightlevel; FBITFIELD blend = 0; @@ -3899,11 +3705,6 @@ static void HWR_SplitSprite(gr_vissprite_t *spr) fixed_t v1x, v1y, v2x, v2y; INT32 shader = SHADER_NONE; - this_scale = FIXED_TO_FLOAT(spr->mobj->scale); - - if (hires) - this_scale = this_scale * FIXED_TO_FLOAT(((skin_t *)( (spr->mobj->localskin) ? spr->mobj->localskin : spr->mobj->skin ))->highresscale); - gpatch = spr->gpatch; //W_CachePatchNum(spr->patchlumpnum, PU_CACHE); // cache the patch in the graphics card memory @@ -3920,7 +3721,7 @@ static void HWR_SplitSprite(gr_vissprite_t *spr) //////////////////// // SHADOW SPRITE! // //////////////////// - HWR_DrawSpriteShadow(spr, gpatch, this_scale); + HWR_DrawSpriteShadow(spr, gpatch); } baseWallVerts[0].x = baseWallVerts[3].x = spr->x1; @@ -3964,7 +3765,7 @@ static void HWR_SplitSprite(gr_vissprite_t *spr) // push it toward the camera to mitigate floor-clipping sprites { - float sprdist = sqrtf((spr->x1 - gr_viewx)*(spr->x1 - gr_viewx) + (spr->z1 - gr_viewy)*(spr->z1 - gr_viewy) + (spr->ty - gr_viewz)*(spr->ty - gr_viewz)); + float sprdist = sqrtf((spr->x1 - gr_viewx)*(spr->x1 - gr_viewx) + (spr->z1 - gr_viewy)*(spr->z1 - gr_viewy) + (spr->gzt - gr_viewz)*(spr->gzt - gr_viewz)); float distfact = ((2.0f*spr->dispoffset) + 20.0f) / sprdist; for (i = 0; i < 4; i++) { @@ -4031,13 +3832,13 @@ static void HWR_SplitSprite(gr_vissprite_t *spr) for (i = 1; i < sector->numlights; i++) { fixed_t h = P_GetLightZAt(§or->lightlist[i], spr->mobj->x, spr->mobj->y); - if (h <= temp) - { - if (!(spr->mobj->frame & FF_FULLBRIGHT)) - lightlevel = *list[i-1].lightlevel > 255 ? 255 : *list[i-1].lightlevel; - colormap = list[i-1].extra_colormap; - break; - } + if (!(h <= temp)) + continue; + + if (!(spr->mobj->frame & FF_FULLBRIGHT)) + lightlevel = min(*list[i-1].lightlevel, 255); + colormap = list[i-1].extra_colormap; + break; } for (i = 0; i < sector->numlights; i++) @@ -4049,7 +3850,7 @@ static void HWR_SplitSprite(gr_vissprite_t *spr) if (!(list[i].flags & FF_NOSHADE) && (list[i].flags & FF_CUTSPRITES)) { if (!(spr->mobj->frame & FF_FULLBRIGHT)) - lightlevel = *list[i].lightlevel > 255 ? 255 : *list[i].lightlevel; + lightlevel = min(*list[i].lightlevel, 255); colormap = list[i].extra_colormap; } @@ -4153,7 +3954,6 @@ static void HWR_SplitSprite(gr_vissprite_t *spr) // -----------------+ static void HWR_DrawSprite(gr_vissprite_t *spr) { - float this_scale = 1.0f; FOutVector wallVerts[4]; GLPatch_t *gpatch; // sprite patch converted to hardware FSurfaceInfo Surf; @@ -4172,12 +3972,6 @@ static void HWR_DrawSprite(gr_vissprite_t *spr) return; } - const boolean hires = (spr->mobj && spr->mobj->skin && ((skin_t *)( (spr->mobj->localskin) ? spr->mobj->localskin : spr->mobj->skin ))->flags & SF_HIRES); - if (spr->mobj) - this_scale = FIXED_TO_FLOAT(spr->mobj->scale); - if (hires) - this_scale = this_scale * FIXED_TO_FLOAT(((skin_t *)( (spr->mobj->localskin) ? spr->mobj->localskin : spr->mobj->skin ))->highresscale); - // cache sprite graphics //12/12/99: Hurdler: // OK, I don't change anything for MD2 support because I want to be @@ -4237,7 +4031,7 @@ static void HWR_DrawSprite(gr_vissprite_t *spr) //////////////////// // SHADOW SPRITE! // //////////////////// - HWR_DrawSpriteShadow(spr, gpatch, this_scale); + HWR_DrawSpriteShadow(spr, gpatch); } // Let dispoffset work first since this adjust each vertex @@ -4246,7 +4040,7 @@ static void HWR_DrawSprite(gr_vissprite_t *spr) // push it toward the camera to mitigate floor-clipping sprites { - float sprdist = sqrtf((spr->x1 - gr_viewx)*(spr->x1 - gr_viewx) + (spr->z1 - gr_viewy)*(spr->z1 - gr_viewy) + (spr->ty - gr_viewz)*(spr->ty - gr_viewz)); + float sprdist = sqrtf((spr->x1 - gr_viewx)*(spr->x1 - gr_viewx) + (spr->z1 - gr_viewy)*(spr->z1 - gr_viewy) + (spr->gzt - gr_viewz)*(spr->gzt - gr_viewz)); float distfact = ((2.0f*spr->dispoffset) + 20.0f) / sprdist; size_t i; for (i = 0; i < 4; i++) @@ -4262,16 +4056,14 @@ static void HWR_DrawSprite(gr_vissprite_t *spr) /// \todo coloured // colormap test - { - sector_t *sector = spr->mobj->subsector->sector; - UINT8 lightlevel = 255; - extracolormap_t *colormap = sector->extra_colormap; + sector_t *sector = spr->mobj->subsector->sector; + UINT8 lightlevel = 255; + extracolormap_t *colormap = sector->extra_colormap; - if (!(spr->mobj->frame & FF_FULLBRIGHT)) - lightlevel = sector->lightlevel > 255 ? 255 : sector->lightlevel; + if (!(spr->mobj->frame & FF_FULLBRIGHT)) + lightlevel = min(sector->lightlevel, 255); - HWR_Lighting(&Surf, lightlevel, colormap); - } + HWR_Lighting(&Surf, lightlevel, colormap); { FBITFIELD blend = 0; @@ -4299,7 +4091,7 @@ static void HWR_DrawSprite(gr_vissprite_t *spr) if (HWR_UseShader()) { - shader = SHADER_SPRITE; // sprite shader + shader = SHADER_SPRITE; blend |= PF_ColorMapped; } @@ -4314,7 +4106,7 @@ static inline void HWR_DrawPrecipitationSprite(gr_vissprite_t *spr) FOutVector wallVerts[4]; GLPatch_t *gpatch; // sprite patch converted to hardware FSurfaceInfo Surf; - + INT32 shader = SHADER_NONE; if (!spr->mobj) @@ -4334,8 +4126,8 @@ static inline void HWR_DrawPrecipitationSprite(gr_vissprite_t *spr) // 0--1 wallVerts[0].x = wallVerts[3].x = spr->x1; wallVerts[2].x = wallVerts[1].x = spr->x2; - wallVerts[2].y = wallVerts[3].y = spr->ty; - wallVerts[0].y = wallVerts[1].y = spr->ty - gpatch->height; + wallVerts[2].y = wallVerts[3].y = spr->gzt; + wallVerts[0].y = wallVerts[1].y = spr->gz; // make a wall polygon (with 2 triangles), using the floor/ceiling heights, // and the 2d map coords of start/end vertices @@ -4357,34 +4149,32 @@ static inline void HWR_DrawPrecipitationSprite(gr_vissprite_t *spr) HWR_GetMappedPatch(gpatch, spr->colormap); // colormap test + sector_t *sector = spr->mobj->subsector->sector; + UINT8 lightlevel = 255; + extracolormap_t *colormap = sector->extra_colormap; + + if (sector->numlights) { - sector_t *sector = spr->mobj->subsector->sector; - UINT8 lightlevel = 255; - extracolormap_t *colormap = sector->extra_colormap; + INT32 light; - if (sector->numlights) - { - INT32 light; + light = R_GetPlaneLight(sector, spr->mobj->z + spr->mobj->height, false); // Always use the light at the top instead of whatever I was doing before - light = R_GetPlaneLight(sector, spr->mobj->z + spr->mobj->height, false); // Always use the light at the top instead of whatever I was doing before + if (!(spr->mobj->frame & FF_FULLBRIGHT)) + lightlevel = min(*sector->lightlist[light].lightlevel, 255); - if (!(spr->mobj->frame & FF_FULLBRIGHT)) - lightlevel = *sector->lightlist[light].lightlevel > 255 ? 255 : *sector->lightlist[light].lightlevel; - - if (sector->lightlist[light].extra_colormap) - colormap = sector->lightlist[light].extra_colormap; - } - else - { - if (!(spr->mobj->frame & FF_FULLBRIGHT)) - lightlevel = sector->lightlevel > 255 ? 255 : sector->lightlevel; - - if (sector->extra_colormap) - colormap = sector->extra_colormap; - } - - HWR_Lighting(&Surf, lightlevel, colormap); + if (sector->lightlist[light].extra_colormap) + colormap = sector->lightlist[light].extra_colormap; } + else + { + if (!(spr->mobj->frame & FF_FULLBRIGHT)) + lightlevel = min(sector->lightlevel, 255); + + if (sector->extra_colormap) + colormap = sector->extra_colormap; + } + + HWR_Lighting(&Surf, lightlevel, colormap); if (spr->mobj->frame & FF_TRANSMASK) blend = HWR_TranstableToAlpha((spr->mobj->frame & FF_TRANSMASK)>>FF_TRANSSHIFT, &Surf); @@ -4400,10 +4190,10 @@ static inline void HWR_DrawPrecipitationSprite(gr_vissprite_t *spr) if (HWR_UseShader()) { - shader = SHADER_SPRITE; // sprite shader + shader = SHADER_SPRITE; blend |= PF_ColorMapped; } - + HWR_ProcessPolygon(&Surf, wallVerts, 4, blend|PF_Modulated, shader, false); } @@ -4447,7 +4237,8 @@ static void HWR_SortVisSprites(void) { gr_vsprorder[i] = HWR_GetVisSprite(i); } - qs22j(gr_vsprorder, gr_visspritecount, sizeof(gr_vissprite_t*), CompareVisSprites); + + qsort(gr_vsprorder, gr_visspritecount, sizeof(gr_vissprite_t*), CompareVisSprites); } // A drawnode is something that points to a 3D floor, 3D side, or masked @@ -4567,10 +4358,7 @@ void HWR_AddTransparentFloor(lumpnum_t lumpnum, extrasubsector_t *xsub, boolean planeinfo->isceiling = isceiling; planeinfo->fixedheight = fixedheight; - if (HWR_ShouldUsePaletteRendering()) - planeinfo->lightlevel = (planecolormap && (planecolormap->fog & 1)) ? 255 : lightlevel; - else - planeinfo->lightlevel = lightlevel; + planeinfo->lightlevel = (HWR_ShouldUsePaletteRendering() && (planecolormap && (planecolormap->fog & 1))) ? 255 : lightlevel; planeinfo->lumpnum = lumpnum; planeinfo->xsub = xsub; @@ -4590,10 +4378,7 @@ void HWR_AddTransparentPolyobjectFloor(lumpnum_t lumpnum, polyobj_t *polysector, polyplaneinfo->isceiling = isceiling; polyplaneinfo->fixedheight = fixedheight; - if (HWR_ShouldUsePaletteRendering()) - polyplaneinfo->lightlevel = (planecolormap && (planecolormap->fog & 1)) ? 255 : lightlevel; - else - polyplaneinfo->lightlevel = lightlevel; + polyplaneinfo->lightlevel = (HWR_ShouldUsePaletteRendering() && (planecolormap && (planecolormap->fog & 1))) ? 255 : lightlevel; polyplaneinfo->lumpnum = lumpnum; polyplaneinfo->polysector = polysector; @@ -4729,35 +4514,39 @@ void HWR_DrawSprites(void) for (i = 0; i < gr_visspritecount; i++) { gr_vissprite_t *spr = gr_vsprorder[i]; - if (spr->precip) - HWR_DrawPrecipitationSprite(spr); - else - if (spr->mobj && spr->mobj->skin && spr->mobj->sprite == SPR_PLAY) - { - md2_t *md2; - if (spr->mobj->localskin) - { - if (spr->mobj->skinlocal) - md2 = &md2_localplayermodels[(skin_t *)spr->mobj->localskin - localskins]; - else - md2 = &md2_playermodels [(skin_t *)spr->mobj->localskin - skins]; - } - else - md2 = &md2_playermodels[(skin_t *)spr->mobj->skin - skins]; - // 8/1/19: Only don't display player models if no default SPR_PLAY is found. - if (!cv_grmdls.value || ((md2->notfound || md2->scale < 0.0f) && ((!cv_grfallbackplayermodel.value) || md2_models[SPR_PLAY].notfound || md2_models[SPR_PLAY].scale < 0.0f)) || spr->mobj->state == &states[S_PLAY_SIGN]) - HWR_DrawSprite(spr); + if (spr->precip) + { + HWR_DrawPrecipitationSprite(spr); + continue; + } + + if (spr->mobj && spr->mobj->skin && spr->mobj->sprite == SPR_PLAY) + { + md2_t *md2; + if (spr->mobj->localskin) + { + if (spr->mobj->skinlocal) + md2 = &md2_localplayermodels[(skin_t *)spr->mobj->localskin - localskins]; else - HWR_DrawMD2(spr); + md2 = &md2_playermodels [(skin_t *)spr->mobj->localskin - skins]; } else - { - if (!cv_grmdls.value || md2_models[spr->mobj->sprite].notfound || md2_models[spr->mobj->sprite].scale < 0.0f) - HWR_DrawSprite(spr); - else - HWR_DrawMD2(spr); - } + md2 = &md2_playermodels[(skin_t *)spr->mobj->skin - skins]; + + // 8/1/19: Only don't display player models if no default SPR_PLAY is found. + if (!cv_grmdls.value || ((md2->notfound || md2->scale < 0.0f) && ((!cv_grfallbackplayermodel.value) || md2_models[SPR_PLAY].notfound || md2_models[SPR_PLAY].scale < 0.0f)) || spr->mobj->state == &states[S_PLAY_SIGN]) + HWR_DrawSprite(spr); + else + HWR_DrawMD2(spr); + } + else + { + if (!cv_grmdls.value || md2_models[spr->mobj->sprite].notfound || md2_models[spr->mobj->sprite].scale < 0.0f) + HWR_DrawSprite(spr); + else + HWR_DrawMD2(spr); + } } } @@ -4768,14 +4557,11 @@ void HWR_DrawSprites(void) void HWR_AddSprites(sector_t *sec) { mobj_t *thing; - fixed_t approx_dist, limit_dist; - - INT32 splitflags; - boolean split_drawsprite; // drawing with splitscreen flags + fixed_t limit_dist; // BSP is traversed by subsector. // A sector might have been split into several - // subsectors during BSP building. + // subsectors during BSP building. // Thus we check whether its already added. if (sec->validcount == validcount) return; @@ -4787,96 +4573,23 @@ void HWR_AddSprites(sector_t *sec) { // Use the smaller setting if (cv_drawdist.value) - limit_dist = min(current_bsp_culling_distance, cv_drawdist.value << FRACBITS); + limit_dist = min((fixed_t)current_bsp_culling_distance, (fixed_t)(cv_drawdist.value) * mapobjectscale); else - limit_dist = current_bsp_culling_distance; + limit_dist = (fixed_t)current_bsp_culling_distance; } else - limit_dist = cv_drawdist.value << FRACBITS; + limit_dist = (fixed_t)(cv_drawdist.value) * mapobjectscale; // Handle all things in sector. - // If a limit exists, handle things a tiny bit different. - if (limit_dist) + for (thing = sec->thinglist; thing; thing = thing->snext) { - for (thing = sec->thinglist; thing; thing = thing->snext) - { - split_drawsprite = false; + if (!R_ThingWithinDist(thing, limit_dist)) + continue; - if (thing->sprite == SPR_NULL || thing->flags2 & MF2_DONTDRAW) - continue; + if (!R_ThingVisible(thing)) + continue; - splitflags = thing->eflags & (MFE_DRAWONLYFORP1|MFE_DRAWONLYFORP2|MFE_DRAWONLYFORP3|MFE_DRAWONLYFORP4); - - if (splitscreen && splitflags) - { - if (thing->eflags & MFE_DRAWONLYFORP1) - if (viewssnum == 0) - split_drawsprite = true; - - if (thing->eflags & MFE_DRAWONLYFORP2) - if (viewssnum == 1) - split_drawsprite = true; - - if (thing->eflags & MFE_DRAWONLYFORP3 && splitscreen > 1) - if (viewssnum == 2) - split_drawsprite = true; - - if (thing->eflags & MFE_DRAWONLYFORP4 && splitscreen > 2) - if (viewssnum == 3) - split_drawsprite = true; - } - else - split_drawsprite = true; - - if (!split_drawsprite) - continue; - - approx_dist = P_AproxDistance(viewx-thing->x, viewy-thing->y); - - if (approx_dist > limit_dist) - continue; - - HWR_ProjectSprite(thing); - } - } - else - { - // Draw everything in sector, no checks - for (thing = sec->thinglist; thing; thing = thing->snext) - { - split_drawsprite = false; - - if (thing->sprite == SPR_NULL || thing->flags2 & MF2_DONTDRAW) - continue; - - splitflags = thing->eflags & (MFE_DRAWONLYFORP1|MFE_DRAWONLYFORP2|MFE_DRAWONLYFORP3|MFE_DRAWONLYFORP4); - - if (splitscreen && splitflags) - { - if (thing->eflags & MFE_DRAWONLYFORP1) - if (viewssnum == 0) - split_drawsprite = true; - - if (thing->eflags & MFE_DRAWONLYFORP2) - if (viewssnum == 1) - split_drawsprite = true; - - if (thing->eflags & MFE_DRAWONLYFORP3 && splitscreen > 1) - if (viewssnum == 2) - split_drawsprite = true; - - if (thing->eflags & MFE_DRAWONLYFORP4 && splitscreen > 2) - if (viewssnum == 3) - split_drawsprite = true; - } - else - split_drawsprite = true; - - if (!split_drawsprite) - continue; - - HWR_ProjectSprite(thing); - } + HWR_ProjectSprite(thing); } } @@ -4890,14 +4603,15 @@ static void HWR_AddPrecipitationSprites(void) { //const fixed_t drawdist = cv_drawdist_precip.value * mapobjectscale; fixed_t drawdist; + fixed_t precipscale = cv_mobjscaleprecip.value ? mapobjectscale : FRACUNIT; INT32 xl, xh, yl, yh, bx, by; precipmobj_t *th; if (current_bsp_culling_distance) - drawdist = min(current_bsp_culling_distance, cv_drawdist_precip.value * mapobjectscale); + drawdist = min((fixed_t)current_bsp_culling_distance, (fixed_t)(cv_drawdist_precip.value) * precipscale); else - drawdist = cv_drawdist_precip.value * mapobjectscale; + drawdist = (fixed_t)(cv_drawdist_precip.value) * precipscale; // No to infinite precipitation draw distance. if (drawdist == 0) @@ -4935,7 +4649,7 @@ void HWR_ProjectSprite(mobj_t *thing) float x1, x2; float z1, z2; float rightsin, rightcos; - float this_scale, this_xscale, this_yscale; + float this_scale; float spritexscale, spriteyscale; float gz, gzt; spritedef_t *sprdef; @@ -4946,6 +4660,7 @@ void HWR_ProjectSprite(mobj_t *thing) size_t lumpoff; unsigned rot; UINT8 flip; + boolean vflip; boolean mirrored; boolean hflip; @@ -4969,6 +4684,7 @@ void HWR_ProjectSprite(mobj_t *thing) if (!thing) return; + vflip = (thing->eflags & MFE_VERTICALFLIP); mirrored = thing->mirrored; hflip = (!(thing->frame & FF_HORIZONTALFLIP) != !mirrored); papersprite = (thing->frame & FF_PAPERSPRITE); @@ -5067,12 +4783,7 @@ void HWR_ProjectSprite(mobj_t *thing) flip = sprframe->flip; // Will only be 0x00 or 0xFF if (papersprite && ang < ANGLE_180) - { - if (flip) - flip = 0; - else - flip = 255; - } + flip ^= 0xFFFF; } else { @@ -5089,16 +4800,11 @@ void HWR_ProjectSprite(mobj_t *thing) flip = sprframe->flip & (1<skin && ((skin_t *)( (thing->localskin) ? thing->localskin : thing->skin ))->flags & SF_HIRES) - this_scale = this_scale * FIXED_TO_FLOAT(((skin_t *)( (thing->localskin) ? thing->localskin : thing->skin ))->highresscale); + this_scale *= FIXED_TO_FLOAT(((skin_t *)( (thing->localskin) ? thing->localskin : thing->skin ))->highresscale); spr_width = spritecachedinfo[lumpoff].width; spr_height = spritecachedinfo[lumpoff].height; @@ -5169,20 +4875,20 @@ void HWR_ProjectSprite(mobj_t *thing) rightcos = FIXED_TO_FLOAT(FINECOSINE((viewangle + ANGLE_90)>>ANGLETOFINESHIFT)); } - this_xscale = spritexscale * this_scale; - this_yscale = spriteyscale * this_scale; + spritexscale *= this_scale; + spriteyscale *= this_scale; flip = !flip != !hflip; if (flip) { - x1 = (FIXED_TO_FLOAT(spr_width - spr_offset) * this_xscale); - x2 = (FIXED_TO_FLOAT(spr_offset) * this_xscale); + x1 = (FIXED_TO_FLOAT(spr_width - spr_offset) * spritexscale); + x2 = (FIXED_TO_FLOAT(spr_offset) * spritexscale); } else { - x1 = (FIXED_TO_FLOAT(spr_offset) * this_xscale); - x2 = (FIXED_TO_FLOAT(spr_width - spr_offset) * this_xscale); + x1 = (FIXED_TO_FLOAT(spr_offset) * spritexscale); + x2 = (FIXED_TO_FLOAT(spr_width - spr_offset) * spritexscale); } z1 = tr_y + x1 * rightsin; @@ -5190,16 +4896,15 @@ void HWR_ProjectSprite(mobj_t *thing) x1 = tr_x + x1 * rightcos; x2 = tr_x - x2 * rightcos; - - if (thing->eflags & MFE_VERTICALFLIP) + if (vflip) { - gz = FIXED_TO_FLOAT(interp.z + thing->height) - (FIXED_TO_FLOAT(spr_topoffset) * this_yscale); - gzt = gz + (FIXED_TO_FLOAT(spr_height) * this_yscale); + gz = FIXED_TO_FLOAT(interp.z + thing->height) - (FIXED_TO_FLOAT(spr_topoffset) * spriteyscale); + gzt = gz + (FIXED_TO_FLOAT(spr_height) * spriteyscale); } else { - gzt = FIXED_TO_FLOAT(interp.z) + (FIXED_TO_FLOAT(spr_topoffset) * this_yscale); - gz = gzt - (FIXED_TO_FLOAT(spr_height) * this_yscale); + gzt = FIXED_TO_FLOAT(interp.z) + (FIXED_TO_FLOAT(spr_topoffset) * spriteyscale); + gz = gzt - (FIXED_TO_FLOAT(spr_height) * spriteyscale); } if (thing->subsector->sector->cullheight) @@ -5209,7 +4914,7 @@ void HWR_ProjectSprite(mobj_t *thing) } heightsec = thing->subsector->sector->heightsec; - if (viewplayer->mo && viewplayer->mo->subsector) + if (viewplayer && viewplayer->mo && viewplayer->mo->subsector) phs = viewplayer->mo->subsector->sector->heightsec; else phs = -1; @@ -5251,7 +4956,6 @@ void HWR_ProjectSprite(mobj_t *thing) vis->mobj = thing; - //Hurdler: 25/04/2000: now support colormap in hardware mode if ((vis->mobj->flags & MF_BOSS) && (vis->mobj->flags2 & MF2_FRET) && (leveltime & 1)) // Bosses "flash" { @@ -5277,29 +4981,24 @@ void HWR_ProjectSprite(mobj_t *thing) vis->colormap = colormaps; #ifdef GLENCORE if (encoremap && !(thing->flags & MF_DONTENCOREMAP)) - vis->colormap += (256*32); + vis->colormap += COLORMAP_REMAPOFFSET; #endif } // set top/bottom coords - vis->ty = gzt; - vis->gzt = gzt; vis->gz = gz; //CONS_Debug(DBG_RENDER, "------------------\nH: sprite : %d\nH: frame : %x\nH: type : %d\nH: sname : %s\n\n", // thing->sprite, thing->frame, thing->type, sprnames[thing->sprite]); - if (thing->eflags & MFE_VERTICALFLIP) - vis->vflip = true; - else - vis->vflip = false; + vis->vflip = vflip; vis->precip = false; } // Precipitation projector for hardware mode -void HWR_ProjectPrecipitationSprite(precipmobj_t *thing) +static void HWR_ProjectPrecipitationSprite(precipmobj_t *thing) { gr_vissprite_t *vis; float tr_x, tr_y; @@ -5307,6 +5006,7 @@ void HWR_ProjectPrecipitationSprite(precipmobj_t *thing) float x1, x2; float z1, z2; float rightsin, rightcos; + float this_scale; spritedef_t *sprdef; spriteframe_t *sprframe; size_t lumpoff; @@ -5317,12 +5017,18 @@ void HWR_ProjectPrecipitationSprite(precipmobj_t *thing) if (!thing) return; - if (cv_grmaxinterpdist.value) - dist = R_QuickCamDist(thing->x, thing->y); - // uncapped/interpolation interpmobjstate_t interp = {0}; + // okay... this is a hack, but weather isn't networked, so it should be ok + if (!P_PrecipThinker(thing)) + { + return; + } + + if (cv_grmaxinterpdist.value) + dist = R_QuickCamDist(thing->x, thing->y); + // do interpolation if (R_UsingFrameInterpolation() && !paused && (!cv_grmaxinterpdist.value || dist < cv_grmaxinterpdist.value)) { @@ -5333,6 +5039,8 @@ void HWR_ProjectPrecipitationSprite(precipmobj_t *thing) R_InterpolatePrecipMobjState(thing, FRACUNIT, &interp); } + this_scale = FIXED_TO_FLOAT(interp.scale); + // transform the origin point tr_x = FIXED_TO_FLOAT(interp.x) - gr_viewx; tr_y = FIXED_TO_FLOAT(interp.y) - gr_viewy; @@ -5385,6 +5093,9 @@ void HWR_ProjectPrecipitationSprite(precipmobj_t *thing) x2 = FIXED_TO_FLOAT(spritecachedinfo[lumpoff].width - spritecachedinfo[lumpoff].offset); } + x1 *= this_scale; + x2 *= this_scale; + z1 = tr_y + x1 * rightsin; z2 = tr_y - x2 * rightsin; x1 = tr_x + x1 * rightcos; @@ -5408,26 +5119,14 @@ void HWR_ProjectPrecipitationSprite(precipmobj_t *thing) #ifdef GLENCORE if (encoremap && !(thing->flags & MF_DONTENCOREMAP)) - vis->colormap += (256*32); + vis->colormap += COLORMAP_REMAPOFFSET; #endif // set top/bottom coords - vis->ty = FIXED_TO_FLOAT(interp.z + spritecachedinfo[lumpoff].topoffset); - - vis->gzt = FIXED_TO_FLOAT(interp.z + spritecachedinfo[lumpoff].topoffset); - vis->gz = vis->gzt - FIXED_TO_FLOAT(spritecachedinfo[lumpoff].height); + vis->gzt = FIXED_TO_FLOAT(interp.z) + (FIXED_TO_FLOAT(spritecachedinfo[lumpoff].topoffset) * this_scale); + vis->gz = vis->gzt - (FIXED_TO_FLOAT(spritecachedinfo[lumpoff].height) * this_scale); vis->precip = true; - - // okay... this is a hack, but weather isn't networked, so it should be ok - if (!(thing->precipflags & PCF_THUNK)) - { - if (thing->precipflags & PCF_RAIN) - P_RainThinker(thing); - else - P_SnowThinker(thing); - thing->precipflags |= PCF_THUNK; - } } static boolean drewsky = false; @@ -5449,6 +5148,7 @@ void HWR_DrawSkyBackground(float fpov) dometransform.flip = atransform.flip; dometransform.mirror = atransform.mirror; + dometransform.mirrorflip = atransform.mirrorflip; dometransform.shearing = atransform.shearing; dometransform.viewaiming = atransform.viewaiming; @@ -5457,8 +5157,7 @@ void HWR_DrawSkyBackground(float fpov) dometransform.scalez = 1; dometransform.fovxangle = fpov; // Tails dometransform.fovyangle = fpov; // Tails - dometransform.rollangle = atransform.rollangle; - dometransform.roll = atransform.roll; + HWR_RollTransform(&dometransform, viewroll); dometransform.splitscreen = splitscreen; HWR_GetTexture(texturetranslation[skytexture], false); @@ -5478,7 +5177,7 @@ static inline void HWR_ClearView(void) (INT32)(gr_viewwindowx + gr_viewwidth), (INT32)(gr_viewwindowy + gr_viewheight), ZCLIP_PLANE, FAR_ZCLIP_DEFAULT); - HWD.pfnClearBuffer(false, true, true, 0); + HWD.pfnClearBuffer(false, true, true, NULL); } @@ -5553,18 +5252,15 @@ void HWR_SetTransform(float fpov, player_t *player) atransform.fovxangle = fpov; // Tails atransform.fovyangle = fpov; // Tails - if (player->viewrollangle != 0) - { - fixed_t rol = AngleFixed(player->viewrollangle); - atransform.rollangle = FIXED_TO_FLOAT(rol); - atransform.roll = true; - } + HWR_RollTransform(&atransform, viewroll); atransform.splitscreen = splitscreen; for (i = 0; i <= splitscreen; i++) { - if (player == &players[displayplayers[i]]) - postprocessor = &postimgtype[i]; + if (player != &players[displayplayers[i]]) + continue; + + postprocessor = &postimgtype[i]; } atransform.flip = false; @@ -5575,6 +5271,10 @@ void HWR_SetTransform(float fpov, player_t *player) if (*postprocessor == postimg_mirror) atransform.mirror = true; + atransform.mirrorflip = false; + if (*postprocessor == postimg_mirrorflip) + atransform.mirrorflip = true; + // Set transform. HWD.pfnSetTransform(&atransform); } @@ -5596,22 +5296,14 @@ static void HWR_PortalClipping(gl_portal_t *portal) line_t *line = &lines[portal->clipline]; - if (cv_pointoangleexor64.value) - { - angle1 = R_PointToAngle64(line->v1->x, line->v1->y); - angle2 = R_PointToAngle64(line->v2->x, line->v2->y); - } - else - { - angle1 = R_PointToAngleEx(viewx, viewy, line->v1->x, line->v1->y); - angle2 = R_PointToAngleEx(viewx, viewy, line->v2->x, line->v2->y); - } + angle1 = R_PointToAngle64(line->v1->x, line->v1->y); + angle2 = R_PointToAngle64(line->v2->x, line->v2->y); // clip things that are not inside the portal window from our viewpoint gld_clipper_SafeAddClipRange(angle2, angle1); } -enum +enum { HWR_STENCIL_NORMAL, HWR_STENCIL_BEGIN, @@ -5623,7 +5315,7 @@ enum // Changes the current stencil state. static void HWR_SetStencilState(int state, int level) { - if (!cv_nostencil.value && level > -1) + if (level > -1) HWD.pfnSetSpecialState(HWD_SET_STENCIL_LEVEL, level); HWD.pfnSetSpecialState(HWD_SET_PORTAL_MODE, state); } @@ -5673,7 +5365,7 @@ static void HWR_RenderPortal(gl_portal_t* portal, gl_portal_t* rootportal, const // remove portal seg from stencil buffer HWR_SetTransform(fpov, player); HWR_ClearClipper(); - + HWR_SetStencilState(HWR_STENCIL_REVERSE, stencil_level); HWR_RenderPortalSeg(portal, GRPORTAL_STENCIL); @@ -5691,8 +5383,9 @@ static void HWR_RenderViewpoint(gl_portal_t *rootportal, const float fpov, playe gl_portal_t *gl_portal_temp; portallist.base = portallist.cap = NULL; const boolean skybox = (skyboxmo[0] && cv_skybox.value); + boolean useportals = gr_maphasportals && cv_grportals.value && allow_portals; - if (gr_maphasportals && allow_portals && cv_grportals.value && stencil_level < cv_maxportals.value)// if recursion limit is not reached + if (useportals && stencil_level < cv_maxportals.value) // if recursion limit is not reached { // search for portals in current frame currentportallist = &portallist; @@ -5712,23 +5405,23 @@ static void HWR_RenderViewpoint(gl_portal_t *rootportal, const float fpov, playe // note: if necessary, could sort the portals here? for (portal = portallist.base; portal; portal = portal->next) { - if (cv_portalline.value && cv_portalline.value != portal->startline) - continue; HWR_RenderPortal(portal, rootportal, fpov, player, stencil_level); } gr_portal = GRPORTAL_INSIDE;// when portal walls are encountered in following bsp traversal, nothing should be drawn } else gr_portal = GRPORTAL_OFF;// there may be portals and they need to be drawn as regural walls + // draw normal things in current frame in current incremented stencil buffer area HWR_SetStencilState(HWR_STENCIL_NORMAL, stencil_level); - if (!cv_portalonly.value || rootportal) - { - HWR_SetTransform(fpov, player); - HWR_ClearClipper(); - HWR_ClearSprites(); + HWR_SetTransform(fpov, player); + HWR_ClearSprites(); + HWR_ClearClipper(); + + if (useportals) + { if (!rootportal) portalclipline = NULL; else @@ -5736,67 +5429,73 @@ static void HWR_RenderViewpoint(gl_portal_t *rootportal, const float fpov, playe HWR_PortalFrame(rootportal);// for portalclipsector, it could have gone null from search HWR_PortalClipping(rootportal); } + } + else + portalclipline = NULL; - // Set transform. - HWD.pfnSetTransform(&atransform); + // Set transform. + HWD.pfnSetTransform(&atransform); - validcount++; - - if (cv_grbatching.value) - HWR_StartBatching(); + validcount++; + ps_numbspcalls.value.i = 0; + ps_numpolyobjects.value.i = 0; + PS_START_TIMING(ps_bsptime); + + if (cv_grbatching.value) + HWR_StartBatching(); + + if (useportals && !rootportal && portallist.base && !skybox) // if portals have been drawn in the main view, then render skywalls differently + gr_collect_skywalls = true; + + // HAYA: Save the old portal state, and turn portals off while normally rendering the BSP tree. + // This fixes specific effects not working, such as horizon lines. + int oldgl_portal_state = gr_portal; + + if (gr_portal != GRPORTAL_OFF) // if we already haven't hit the recursion limit or we already ended our portal shenanigans + gr_portal = GRPORTAL_INSIDE; // TURN IT OFF + + // Recursively "render" the BSP tree. + HWR_RenderBSPNode((INT32)numnodes-1); + + // woo we back + gr_portal = oldgl_portal_state; + + if (allow_portals) // looks weird, but this is only true when its not skybox rendering skipping precip in skyboxes like software does HWR_AddPrecipitationSprites(); - ps_numbspcalls.value.i = 0; - ps_numpolyobjects.value.i = 0; - PS_START_TIMING(ps_bsptime); + PS_STOP_TIMING(ps_bsptime); - if (!rootportal && portallist.base && !skybox)// if portals have been drawn in the main view, then render skywalls differently - gr_collect_skywalls = true; + if (cv_grbatching.value) + HWR_RenderBatches(); - // HAYA: Save the old portal state, and turn portals off while normally rendering the BSP tree. - // This fixes specific effects not working, such as horizon lines. - int oldgl_portal_state = gr_portal; - - if (gr_portal != GRPORTAL_OFF) // if we already haven't hit the recursion limit or we already ended our portal shenanigans - gr_portal = GRPORTAL_INSIDE; // TURN IT OFF - // Recursively "render" the BSP tree. - HWR_RenderBSPNode((INT32)numnodes-1); - // woo we back - gr_portal = oldgl_portal_state; - - PS_STOP_TIMING(ps_bsptime); - - if (cv_grbatching.value) - HWR_RenderBatches(); - - if (skyWallVertexArraySize)// if there are skywalls to draw using the alternate method - { - HWR_SetStencilState(HWR_STENCIL_SKY, -1); - HWR_DrawSkyWallList(); - HWR_SkyWallList_Clear(); - HWR_SetStencilState(HWR_STENCIL_NORMAL, 1); - drewsky = false; - HWR_DrawSkyBackground(fpov); - HWR_SetStencilState(HWR_STENCIL_NORMAL, 0); - HWD.pfnClearBuffer(false, false, true, 0);// clear skywall markings from the stencil buffer - HWR_SetTransform(fpov, player);// restore transform - } - gr_collect_skywalls = false; - - ps_numsprites.value.i = gr_visspritecount; - PS_START_TIMING(ps_hw_spritesorttime); - HWR_SortVisSprites(); - PS_STOP_TIMING(ps_hw_spritesorttime); - PS_START_TIMING(ps_hw_spritedrawtime); - HWR_DrawSprites(); - PS_STOP_TIMING(ps_hw_spritedrawtime); - - ps_numdrawnodes.value.i = 0; - ps_hw_nodesorttime.value.p = 0; - ps_hw_nodedrawtime.value.p = 0; - HWR_RenderDrawNodes(); + if (skyWallVertexArraySize) // if there are skywalls to draw using the alternate method + { + HWR_SetStencilState(HWR_STENCIL_SKY, -1); + HWR_DrawSkyWallList(); + HWR_SkyWallList_Clear(); + HWR_SetStencilState(HWR_STENCIL_NORMAL, 1); + drewsky = false; + HWR_DrawSkyBackground(fpov); + HWR_SetStencilState(HWR_STENCIL_NORMAL, 0); + HWD.pfnClearBuffer(false, false, true, 0);// clear skywall markings from the stencil buffer + HWR_SetTransform(fpov, player);// restore transform } + gr_collect_skywalls = false; + + ps_numsprites.value.i = gr_visspritecount; + PS_START_TIMING(ps_hw_spritesorttime); + HWR_SortVisSprites(); + PS_STOP_TIMING(ps_hw_spritesorttime); + PS_START_TIMING(ps_hw_spritedrawtime); + HWR_DrawSprites(); + PS_STOP_TIMING(ps_hw_spritedrawtime); + + ps_numdrawnodes.value.i = 0; + ps_hw_nodesorttime.value.p = 0; + ps_hw_nodedrawtime.value.p = 0; + HWR_RenderDrawNodes(); + // free memory from portal list allocated by calls to Add2Lines gl_portal_temp = portallist.base; while (gl_portal_temp) @@ -5805,9 +5504,6 @@ static void HWR_RenderViewpoint(gl_portal_t *rootportal, const float fpov, playe Z_Free(gl_portal_temp); gl_portal_temp = nextportal; } - - // TODO: batching at some point - // TODO: is it okay if stencil test is on all the time even when its not needed? } @@ -5852,9 +5548,6 @@ void HWR_RenderFrame(INT32 viewnumber, player_t *player, boolean skybox) } } - // check for new console commands. - NetUpdate(); - // Clear view, set viewport (glViewport), set perspective... HWR_ClearView(); @@ -5888,9 +5581,6 @@ void HWR_RenderFrame(INT32 viewnumber, player_t *player, boolean skybox) if (!skybox) HWR_DoPostProcessor(player); - // Check for new console commands. - NetUpdate(); - // added by Hurdler for correct splitscreen // moved here by hurdler so it works with the new near clipping plane HWD.pfnGClipRect(0, 0, vid.width, vid.height, NZCLIP_PLANE, FAR_ZCLIP_DEFAULT); @@ -5899,21 +5589,30 @@ void HWR_RenderFrame(INT32 viewnumber, player_t *player, boolean skybox) // ========================================================================== // Render the player view. // ========================================================================== + +static void HWR_RollTransform(FTransform *tr, angle_t roll) +{ + if (roll != 0) + { + tr->rollangle = roll / (float)ANG1; + tr->roll = true; + } +} + void HWR_RenderPlayerView(INT32 viewnumber, player_t *player) { const boolean skybox = (skyboxmo[0] && cv_skybox.value); // True if there's a skybox object and skyboxes are on + FRGBAFloat ClearColor; + + ClearColor.red = 0.0f; + ClearColor.green = 0.0f; + ClearColor.blue = 0.0f; + ClearColor.alpha = 1.0f; + // Clear the color buffer, stops HOMs. Also seems to fix the skybox issue on Intel GPUs. if (viewnumber == 0) // Only do it if it's the first screen being rendered - { - FRGBAFloat ClearColor; - - ClearColor.red = 0.0f; - ClearColor.green = 0.0f; - ClearColor.blue = 0.0f; - ClearColor.alpha = 1.0f; HWD.pfnClearBuffer(true, false, false, &ClearColor); - } if (cv_grshaders.value) HWD.pfnSetShaderInfo(HWD_SHADERINFO_LEVELTIME, (INT32)leveltime); // The water surface shader needs the leveltime. @@ -5936,6 +5635,25 @@ void HWR_RenderPlayerView(INT32 viewnumber, player_t *player) HWR_RenderFrame(viewnumber, player, false); } +void HWR_LoadLevel(void) +{ + // Lactozilla (December 8, 2019) + // Level setup used to free EVERY mipmap from memory. + // Even mipmaps that aren't related to level textures. + // Presumably, the hardware render code used to store textures as level data. + // Meaning, they had memory allocated and marked with the PU_LEVEL tag. + // Level textures are only reloaded after R_LoadTextures, which is + // when the texture list is loaded. + + // Sal: Unfortunately, NOT freeing them causes the dreaded Color Bug. + HWR_FreeMipmapCache(); + + HWR_CreatePlanePolygons((INT32)numnodes - 1); + + if (HWR_ShouldUsePaletteRendering()) + HWR_SetMapPalette(); +} + // enable or disable palette rendering state depending on settings and availability // called when relevant settings change // shader recompilation is done in the cvar callback @@ -5982,48 +5700,46 @@ void HWR_TogglePaletteRendering(void) //added by Hurdler: console varibale that are saved void HWR_AddCommands(void) { -#ifdef USE_FBO_OGL - CV_RegisterVar(&cv_grframebuffer); -#endif CV_RegisterVar(&cv_grfiltermode); CV_RegisterVar(&cv_granisotropicmode); CV_RegisterVar(&cv_grsolvetjoin); - + CV_RegisterVar(&cv_grbatching); - CV_RegisterVar(&cv_grfofcut); - CV_RegisterVar(&cv_fofzfightfix); + CV_RegisterVar(&cv_splitwallfix); - CV_RegisterVar(&cv_slopepegfix); - - CV_RegisterVar(&cv_grscreentextures); - + CV_RegisterVar(&cv_grrenderdistance); CV_RegisterVar(&cv_grfakecontrast); CV_RegisterVar(&cv_grslopecontrast); CV_RegisterVar(&cv_grhorizonlines); - + CV_RegisterVar(&cv_grfovchange); - + CV_RegisterVar(&cv_grmdls); CV_RegisterVar(&cv_grfallbackplayermodel); - + CV_RegisterVar(&cv_grspritebillboarding); - + CV_RegisterVar(&cv_grshearing); - + CV_RegisterVar(&cv_grshaders); - + CV_RegisterVar(&cv_grportals); - CV_RegisterVar(&cv_nostencil); - CV_RegisterVar(&cv_portalline); - CV_RegisterVar(&cv_portalonly); - + CV_RegisterVar(&cv_secbright); - + CV_RegisterVar(&cv_grpaletterendering); CV_RegisterVar(&cv_grpalettedepth); CV_RegisterVar(&cv_grflashpal); + + CV_RegisterVar(&cv_lightdither); + +#ifdef USE_FBO_OGL + CV_RegisterVar(&cv_grframebuffer); +#endif + + CV_RegisterVar(&cv_grscreentextures); } // -------------------------------------------------------------------------- @@ -6048,17 +5764,12 @@ void HWR_Startup(void) HWR_TogglePaletteRendering(); -#ifdef USE_FBO_OGL +#ifdef USE_FBO_OGL HWD.pfnSetSpecialState(HWD_SET_FRAMEBUFFER, cv_grframebuffer.value); #endif if (msaa) - { - if (a2c) - HWD.pfnSetSpecialState(HWD_SET_MSAA, 2); - else - HWD.pfnSetSpecialState(HWD_SET_MSAA, 1); - } + HWD.pfnSetSpecialState(HWD_SET_MSAA, a2c ? 2 : 1); } startupdone = true; } @@ -6073,6 +5784,9 @@ void HWR_Shutdown(void) HWR_FreeMipmapCache(); HWR_FreeTextureCache(); HWD.pfnFlushScreenTextures(); +#ifdef USE_FBO_OGL + GLFramebuffer_Disable(); +#endif } void HWR_RenderWall(FOutVector *wallVerts, FSurfaceInfo *pSurf, FBITFIELD blend, boolean fogwall, INT32 lightlevel, extracolormap_t *wallcolormap) @@ -6126,11 +5840,11 @@ void HWR_DoPostProcessor(player_t *player) for (i = splitscreen; i > 0; i--) { - if (player == &players[displayplayers[i]]) - { - type = &postimgtype[i]; - break; - } + if (player != &players[displayplayers[i]]) + continue; + + type = &postimgtype[i]; + break; } // Armageddon Blast Flash! @@ -6158,7 +5872,7 @@ void HWR_DoPostProcessor(player_t *player) HWD.pfnDrawPolygon(&Surf, v, 4, PF_Modulated|PF_Translucent|PF_NoTexture|PF_NoDepthTest); } - if (!cv_grscreentextures.value) // screen textures are needed for the rest of the effects + if (cv_grscreentextures.value != 2) // screen textures are needed for the rest of the effects return; // Capture the screen for intermission and screen waving @@ -6206,7 +5920,7 @@ void HWR_DoPostProcessor(player_t *player) HWD.pfnPostImgRedraw(v); // Capture the screen again for screen waving on the intermission - if(gamestate != GS_INTERMISSION) + if (gamestate != GS_INTERMISSION) HWD.pfnMakeScreenTexture(HWD_SCREENTEXTURE_GENERIC1); } // Flipping of the screen isn't done here anymore @@ -6233,6 +5947,12 @@ void HWR_DoWipe(UINT8 wipenum, UINT8 scrnnum) lumpnum_t lumpnum; size_t lsize; + if (cv_grscreentextures.value == 0) + { + V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 31); // just draw a black screen instead of flashing and crap + return; + } + if (wipenum > 99 || scrnnum > 99) // not a valid wipe number return; // shouldn't end up here really, the loop should've stopped running beforehand @@ -6269,4 +5989,5 @@ void HWR_DrawScreenFinalTexture(INT32 width, INT32 height) { HWD.pfnDrawScreenFinalTexture(HWD_SCREENTEXTURE_GENERIC2, width, height); } + #endif // HWRENDER diff --git a/src/hardware/hw_main.h b/src/hardware/hw_main.h index 1c51e2981..bd6258ef4 100644 --- a/src/hardware/hw_main.h +++ b/src/hardware/hw_main.h @@ -120,7 +120,6 @@ void HWR_RenderPlane(subsector_t *subsector, extrasubsector_t *xsub, boolean isc void HWR_AddTransparentFloor(lumpnum_t lumpnum, extrasubsector_t *xsub, boolean isceiling, fixed_t fixedheight, INT32 lightlevel, INT32 alpha, sector_t *FOFSector, FBITFIELD blend, boolean fogplane, extracolormap_t *planecolormap); void HWR_RenderPolyObjectPlane(polyobj_t *polysector, boolean isceiling, fixed_t fixedheight, FBITFIELD blendmode, UINT8 lightlevel, lumpnum_t lumpnum, sector_t *FOFsector, UINT8 alpha, extracolormap_t *planecolormap); -void HWR_AddPolyObjectPlanes(void); void HWR_AddTransparentPolyobjectFloor(lumpnum_t lumpnum, polyobj_t *polysector, boolean isceiling, fixed_t fixedheight, INT32 lightlevel, INT32 alpha, sector_t *FOFSector, FBITFIELD blend, extracolormap_t *planecolormap); // hw_main.c: Segs @@ -132,12 +131,10 @@ void HWR_AddTransparentWall(FOutVector *wallVerts, FSurfaceInfo * pSurf, INT32 t void HWR_DrawSkyWall(FOutVector *wallVerts, FSurfaceInfo *Surf); void HWR_DrawSkyBackground(float fpov); -void HWR_AddPolyObjectSegs(void); - // hw_main.c: Sprites void HWR_AddSprites(sector_t *sec); void HWR_ProjectSprite(mobj_t *thing); -void HWR_ProjectPrecipitationSprite(precipmobj_t *thing); +//void HWR_ProjectPrecipitationSprite(precipmobj_t *thing); void HWR_DrawSprites(void); // hw_bsp.c @@ -155,10 +152,7 @@ extern consvar_t cv_grshaders; #ifdef USE_FBO_OGL extern consvar_t cv_grframebuffer; #endif -extern consvar_t cv_grfofcut; -extern consvar_t cv_fofzfightfix; extern consvar_t cv_splitwallfix; -extern consvar_t cv_slopepegfix; extern consvar_t cv_grshearing; extern consvar_t cv_grfov; extern consvar_t cv_grmdls; @@ -179,6 +173,7 @@ extern consvar_t cv_grrenderdistance; extern consvar_t cv_grpaletterendering; extern consvar_t cv_grpalettedepth; extern consvar_t cv_grflashpal; +extern consvar_t cv_lightdither; extern consvar_t cv_grscreentextures; extern consvar_t cv_grportals; extern consvar_t cv_nostencil; diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c index 5818f01b2..c71f47185 100644 --- a/src/hardware/hw_md2.c +++ b/src/hardware/hw_md2.c @@ -26,7 +26,6 @@ #ifdef HWRENDER #include "hw_drv.h" -#include "hw_light.h" #include "hw_md2.h" #include "../d_main.h" #include "../r_bsp.h" @@ -75,7 +74,7 @@ md2_t md2_models[NUMSPRITES]; md2_t md2_playermodels[MAXSKINS]; -md2_t md2_localplayermodels[MAXSKINS]; +md2_t md2_localplayermodels[MAXLOCALSKINS]; /* @@ -494,7 +493,9 @@ void HWR_InitMD2(void) md2_playermodels[s].skin = -1; md2_playermodels[s].notfound = true; md2_playermodels[s].error = false; - + } + for (s = 0; s < MAXLOCALSKINS; s++) + { md2_localplayermodels[s].scale = -1.0f; md2_localplayermodels[s].model = NULL; md2_localplayermodels[s].grpatch = NULL; diff --git a/src/hardware/hw_md2.h b/src/hardware/hw_md2.h index a6f06428e..7b58a6f97 100644 --- a/src/hardware/hw_md2.h +++ b/src/hardware/hw_md2.h @@ -37,7 +37,7 @@ typedef struct extern md2_t md2_models[NUMSPRITES]; extern md2_t md2_playermodels[MAXSKINS]; -extern md2_t md2_localplayermodels[MAXSKINS]; +extern md2_t md2_localplayermodels[MAXLOCALSKINS]; void HWR_InitMD2(void); void HWR_DrawMD2(gr_vissprite_t *spr); diff --git a/src/hardware/hw_shaders.c b/src/hardware/hw_shaders.c index 427bd1540..d7924a675 100644 --- a/src/hardware/hw_shaders.c +++ b/src/hardware/hw_shaders.c @@ -29,6 +29,9 @@ static struct { // Floor shader {GLSL_DEFAULT_VERTEX_SHADER, GLSL_FLOOR_FRAGMENT_SHADER}, + // Shadow shader + {GLSL_DEFAULT_VERTEX_SHADER, GLSL_SHADOW_FRAGMENT_SHADER}, + // Wall shader {GLSL_DEFAULT_VERTEX_SHADER, GLSL_WALL_FRAGMENT_SHADER}, @@ -79,6 +82,7 @@ static shadertarget_t gl_shadertargets[NUMSHADERTARGETS]; #define WHITESPACE_CHARS " \t" #define PALETTE_RENDERING_DEFINE "#define SRB2_PALETTE_RENDERING" +#define LIGHT_DITHERING_DEFINE "#define SRB2_LIGHT_DITHER" // Initialize shader variables and the backend's shader system. Load the base shaders. // Returns false if shaders cannot be used. @@ -279,6 +283,9 @@ static char *HWR_PreprocessShader(char *original) if (cv_grpaletterendering.value) ADD_TO_LEN(PALETTE_RENDERING_DEFINE) + if (cv_lightdither.value) + ADD_TO_LEN(LIGHT_DITHERING_DEFINE) + #undef ADD_TO_LEN #define VERSION_PART "#version " @@ -320,6 +327,9 @@ static char *HWR_PreprocessShader(char *original) if (cv_grpaletterendering.value) WRITE_DEFINE(PALETTE_RENDERING_DEFINE) + if (cv_lightdither.value) + WRITE_DEFINE(LIGHT_DITHERING_DEFINE) + #undef WRITE_DEFINE // Write a #line directive, so compiler errors will report line numbers from the @@ -422,6 +432,7 @@ static inline UINT16 HWR_FindShaderDefs(UINT16 wadnum) customshaderxlat_t shaderxlat[] = { {"Flat", SHADER_FLOOR}, + {"Shadow", SHADER_SHADOW}, {"WallTexture", SHADER_WALL}, {"Sprite", SHADER_SPRITE}, {"Model", SHADER_MODEL}, @@ -442,6 +453,106 @@ void HWR_LoadAllCustomShaders(void) HWR_LoadCustomShadersFromFile(i, W_FileHasFolders(wadfiles[i])); } +static const char version_directives[][14] = { + "#version 330\n", + "#version 150\n", + "#version 140\n", + "#version 130\n", + "#version 120\n", + "#version 110\n", +}; + +static boolean HWR_VersionDirectiveExists(const char* source) +{ + return strncmp(source, "#version", 8) == 0; +} + +static char* HWR_PrependVersionDirective(const char* source, UINT32 version_index) +{ + const UINT32 version_len = sizeof(version_directives[version_index]) - 1; + const UINT32 source_len = strlen(source); + + char* result = Z_Malloc(source_len + version_len + 1, PU_STATIC, NULL); + strcpy(result, version_directives[version_index]); + strcpy(result + version_len, source); + + return result; +} + +static void HWR_ReplaceVersionInplace(char* shader, UINT32 version_index) +{ + shader[9] = version_directives[version_index][9]; + shader[10] = version_directives[version_index][10]; + shader[11] = version_directives[version_index][11]; +} + +static boolean HWR_CheckVersionDirectives(const char* vert, const char* frag) +{ + return HWR_VersionDirectiveExists(vert) && HWR_VersionDirectiveExists(frag); +} + +static void HWR_TryToCompileShaderWithImplicitVersion(INT32 shader_index, INT32 shaderxlat_id) +{ + char* vert_shader = gl_shaders[shader_index].vertex; + char* frag_shader = gl_shaders[shader_index].fragment; + + boolean vert_shader_version_exists = HWR_VersionDirectiveExists(vert_shader); + boolean frag_shader_version_exists = HWR_VersionDirectiveExists(frag_shader); + + if (!vert_shader_version_exists) + CONS_Alert(CONS_WARNING, "HWR_LoadCustomShadersFromFile: vertex shader '%s' is missing a #version directive\n", HWR_GetShaderName(shaderxlat_id)); + + if (!frag_shader_version_exists) + CONS_Alert(CONS_WARNING, "HWR_LoadCustomShadersFromFile: fragment shader '%s' is missing a #version directive\n", HWR_GetShaderName(shaderxlat_id)); + + // try to compile as is + HWR_CompileShader(shader_index); + + if (gl_shaders[shader_index].compiled) + return; + + // try each version directive + for (UINT32 i = 0; i < sizeof(version_directives) / sizeof(version_directives[0]); ++i) + { + CONS_Alert(CONS_NOTICE, "HWR_TryToCompileShaderWithImplicitVersion: Trying %s\n", version_directives[i]); + + if (!vert_shader_version_exists) + { + // first time reallocation would have to be made + + if (i == 0) + { + void* old = (void*)gl_shaders[shader_index].vertex; + vert_shader = gl_shaders[shader_index].vertex = HWR_PrependVersionDirective(vert_shader, i); + Z_Free(old); + } + else + HWR_ReplaceVersionInplace(vert_shader, i); + } + + if (!frag_shader_version_exists) + { + if (i == 0) + { + void* old = (void*)gl_shaders[shader_index].fragment; + frag_shader = gl_shaders[shader_index].fragment = HWR_PrependVersionDirective(frag_shader, i); + Z_Free(old); + } + else + HWR_ReplaceVersionInplace(frag_shader, i); + } + + HWR_CompileShader(shader_index); + if (gl_shaders[shader_index].compiled) + { + CONS_Alert(CONS_NOTICE, "HWR_TryToCompileShaderWithImplicitVersion: Compiled with %s\n", + version_directives[i]); + CONS_Alert(CONS_WARNING, "Implicit GLSL version is used. Correct behavior is not guaranteed\n"); + return; + } + } +} + void HWR_LoadCustomShadersFromFile(UINT16 wadnum, boolean PK3) { UINT16 lump; @@ -598,13 +709,20 @@ skip_field: { int shader_index = i + NUMSHADERTARGETS; // index to gl_shaders gl_shadertargets[i].custom_shader = shader_index; + // if only one stage (vertex/fragment) is defined, the other one // is copied from the base shaders. if (!gl_shaders[shader_index].fragment) gl_shaders[shader_index].fragment = Z_StrDup(gl_shadersources[i].fragment); + if (!gl_shaders[shader_index].vertex) gl_shaders[shader_index].vertex = Z_StrDup(gl_shadersources[i].vertex); - HWR_CompileShader(shader_index); + + if (!HWR_CheckVersionDirectives(gl_shaders[shader_index].vertex, gl_shaders[shader_index].fragment)) + HWR_TryToCompileShaderWithImplicitVersion(shader_index, i); + else + HWR_CompileShader(shader_index); + if (!gl_shaders[shader_index].compiled) CONS_Alert(CONS_ERROR, "HWR_LoadCustomShadersFromFile: A compilation error occured for the %s shader in file %s. See the console messages above for more information.\n", shaderxlat[i].type, wadfiles[wadnum]->filename); } diff --git a/src/hardware/hw_shaders.h b/src/hardware/hw_shaders.h index eb705c34c..714b004b1 100644 --- a/src/hardware/hw_shaders.h +++ b/src/hardware/hw_shaders.h @@ -51,15 +51,53 @@ // // Include GLSL_FLOOR_FUDGES or GLSL_WALL_FUDGES or define the fudges in shaders that use this macro. +#define GLSL_DOOM_COLORMAP_DITHER \ + "float baseValue = max(startmap * STARTMAP_FUDGE - scale * 0.5 * SCALE_FUDGE, cap);\n" \ + "float endResolutionx = scr_resolution.x;\n" \ + "float endResolutiony = scr_resolution.y;\n" \ + "if (scr_resolution.x > 1280.0) {\n" \ + "endResolutionx = scr_resolution.x * 0.5;\n" \ + "}\n" \ + "if (scr_resolution.y > 720.0) {\n" \ + "endResolutiony = scr_resolution.y * 0.5;\n" \ + "}\n" \ + "float zFactor = clamp((z - 192.0) / (6144.0 - 192.0), 0.0, 1.0);\n" \ + "int scaleFactor = int(mix(1.0, 8.0, zFactor));\n" \ + "endResolutionx = endResolutionx * scaleFactor;\n" \ + "endResolutiony = endResolutiony * scaleFactor;\n" \ + "vec2 normalizedPosition = position * vec2(endResolutionx / scr_resolution.x, endResolutiony / scr_resolution.y);\n" \ + "int x = int(mod(normalizedPosition.x, 4.0));\n" \ + "int y = int(mod(normalizedPosition.y, 4.0));\n" \ + "float bayerMatrix[4*4] = float[4*4](\n" \ + "0.0, 8.0, 2.0, 10.0,\n" \ + "12.0, 4.0, 14.0, 6.0,\n" \ + "3.0, 11.0, 1.0, 9.0,\n" \ + "15.0, 7.0, 13.0, 5.0\n" \ + ");\n" \ + "#ifdef SRB2_PALETTE_RENDERING\n" \ + "float threshold = (1.0 - pow(zFactor, 2.0)) * (bayerMatrix[y*4 + x] / 11.0);\n" \ + "#else\n" \ + "float threshold = (1.0 - pow(zFactor, 2.0)) * (bayerMatrix[y*4 + x] / 16.0);\n" \ + "#endif\n" \ + "return mix(baseValue + threshold - 0.5 / 16.0, baseValue, zFactor);\n" + +#define GLSL_DOOM_COLORMAP_NODITHER \ + "return max(startmap * STARTMAP_FUDGE - scale * 0.5 * SCALE_FUDGE, cap);\n" \ + #define GLSL_DOOM_COLORMAP \ - "float R_DoomColormap(float light, float z)\n" \ + "uniform vec2 scr_resolution;\n" \ + "float R_DoomColormap(float light, float z, vec2 position)\n" \ "{\n" \ "float lightnum = clamp(light / 17.0, 0.0, 15.0);\n" \ "float lightz = clamp(z / 16.0, 0.0, 127.0);\n" \ "float startmap = (15.0 - lightnum) * 4.0;\n" \ "float scale = 160.0 / (lightz + 1.0);\n" \ "float cap = (155.0 - light) * 0.26;\n" \ - "return max(startmap * STARTMAP_FUDGE - scale * 0.5 * SCALE_FUDGE, cap);\n" \ + "#ifdef SRB2_LIGHT_DITHER\n" \ + GLSL_DOOM_COLORMAP_DITHER \ + "#else\n" \ + GLSL_DOOM_COLORMAP_NODITHER \ + "#endif\n" \ "}\n" // lighting cap adjustment: // first num (155.0), increase to make it start to go dark sooner @@ -69,7 +107,7 @@ "float R_DoomLightingEquation(float light)\n" \ "{\n" \ "float z = gl_FragCoord.z / gl_FragCoord.w;\n" \ - "float colormap = floor(R_DoomColormap(light, z)) + 0.5;\n" \ + "float colormap = floor(R_DoomColormap(light, z, gl_FragCoord.xy)) + 0.5;\n" \ "return clamp(colormap, 0.0, 31.0) / 32.0;\n" \ "}\n" @@ -95,7 +133,7 @@ #define GLSL_PALETTE_RENDERING \ "float tex_pal_idx = texture3D(palette_lookup_tex, vec3((texel * 63.0 + 0.5) / 64.0))[0] * 255.0;\n" \ "float z = gl_FragCoord.z / gl_FragCoord.w;\n" \ - "float light_y = clamp(floor(R_DoomColormap(lighting, z)), 0.0, 31.0);\n" \ + "float light_y = clamp(floor(R_DoomColormap(lighting, z, gl_FragCoord.xy)), 0.0, 31.0);\n" \ "vec2 lighttable_coord = vec2((tex_pal_idx + 0.5) / 256.0, (light_y + 0.5) / 32.0);\n" \ "vec4 final_color = texture2D(lighttable_tex, lighttable_coord);\n" \ "final_color.a = texel.a * poly_color.a;\n" \ @@ -133,13 +171,35 @@ "gl_FragColor = final_color;\n" \ "}\n" \ "#endif\0" + +#define GLSL_SOFTWARE_FRAGMENT_SHADER_NOPAL \ + "uniform sampler2D tex;\n" \ + "uniform vec4 poly_color;\n" \ + "uniform vec4 tint_color;\n" \ + "uniform vec4 fade_color;\n" \ + "uniform float lighting;\n" \ + "uniform float fade_start;\n" \ + "uniform float fade_end;\n" \ + GLSL_DOOM_COLORMAP \ + GLSL_DOOM_LIGHT_EQUATION \ + "void main(void) {\n" \ + "vec4 texel = texture2D(tex, gl_TexCoord[0].st);\n" \ + "vec4 base_color = texel * poly_color;\n" \ + "vec4 final_color = base_color;\n" \ + GLSL_SOFTWARE_TINT_EQUATION \ + GLSL_SOFTWARE_FADE_EQUATION \ + "final_color.a = texel.a * poly_color.a;\n" \ + "gl_FragColor = final_color;\n" \ + "}\n" \ // hand tuned adjustments for light level calculation #define GLSL_FLOOR_FUDGES \ + "#version 120\n" \ "#define STARTMAP_FUDGE 1.06\n" \ "#define SCALE_FUDGE 1.15\n" #define GLSL_WALL_FUDGES \ + "#version 120\n" \ "#define STARTMAP_FUDGE 1.05\n" \ "#define SCALE_FUDGE 2.2\n" @@ -150,6 +210,10 @@ #define GLSL_WALL_FRAGMENT_SHADER \ GLSL_WALL_FUDGES \ GLSL_SOFTWARE_FRAGMENT_SHADER + +#define GLSL_SHADOW_FRAGMENT_SHADER \ + GLSL_FLOOR_FUDGES \ + GLSL_SOFTWARE_FRAGMENT_SHADER_NOPAL // // Water surface shader diff --git a/src/hardware/r_opengl/r_opengl.c b/src/hardware/r_opengl/r_opengl.c index 0ea12a793..abfbfdd25 100644 --- a/src/hardware/r_opengl/r_opengl.c +++ b/src/hardware/r_opengl/r_opengl.c @@ -120,8 +120,6 @@ GLfloat projMatrix[16]; static GLint viewport[4]; #ifdef USE_FBO_OGL -static boolean GLFramebuffer_IsFuncAvailible(void); - GLuint FramebufferObject, FramebufferTexture, RenderbufferObject; GLboolean FrameBufferEnabled = GL_FALSE, RenderToFramebuffer = GL_FALSE; @@ -608,6 +606,7 @@ typedef void (APIENTRY *PFNglDeleteProgram) (GLuint); typedef void (APIENTRY *PFNglAttachShader) (GLuint, GLuint); typedef void (APIENTRY *PFNglLinkProgram) (GLuint); typedef void (APIENTRY *PFNglGetProgramiv) (GLuint, GLenum, GLint*); +typedef void (APIENTRY *PFNglGetProgramInfoLog) (GLuint, GLsizei, GLsizei*, GLchar*); typedef void (APIENTRY *PFNglUseProgram) (GLuint); typedef void (APIENTRY *PFNglUniform1i) (GLint, GLint); typedef void (APIENTRY *PFNglUniform1f) (GLint, GLfloat); @@ -630,6 +629,7 @@ static PFNglDeleteProgram pglDeleteProgram; static PFNglAttachShader pglAttachShader; static PFNglLinkProgram pglLinkProgram; static PFNglGetProgramiv pglGetProgramiv; +static PFNglGetProgramInfoLog pglGetProgramInfoLog; static PFNglUseProgram pglUseProgram; static PFNglUniform1i pglUniform1i; static PFNglUniform1f pglUniform1f; @@ -669,6 +669,8 @@ typedef enum // misc. gluniform_leveltime, + + gluniform_scr_resolution, gluniform_max, } gluniform_t; @@ -703,6 +705,9 @@ static void Shader_SetUniforms(FSurfaceInfo *Surface, GLRGBAFloat *poly, GLRGBAF static GLRGBAFloat shader_defaultcolor = {1.0f, 1.0f, 1.0f, 1.0f}; +#ifdef USE_FBO_OGL +static boolean GLFramebuffer_IsFuncAvailible(void); +#endif void SetupGLFunc4(void) { @@ -735,6 +740,7 @@ void SetupGLFunc4(void) pglAttachShader = GetGLFunc("glAttachShader"); pglLinkProgram = GetGLFunc("glLinkProgram"); pglGetProgramiv = GetGLFunc("glGetProgramiv"); + pglGetProgramInfoLog = GetGLFunc("glGetProgramInfoLog"); pglUseProgram = GetGLFunc("glUseProgram"); pglUniform1i = GetGLFunc("glUniform1i"); pglUniform1f = GetGLFunc("glUniform1f"); @@ -759,6 +765,8 @@ void SetupGLFunc4(void) pglDeleteRenderbuffers = GetGLFunc("glDeleteRenderbuffers"); pglRenderbufferStorage = GetGLFunc("glRenderbufferStorage"); pglFramebufferRenderbuffer = GetGLFunc("glFramebufferRenderbuffer"); + + supportFBO = true; } #endif } @@ -770,9 +778,7 @@ static boolean GLFramebuffer_IsFuncAvailible(void) if (majorGL < 3) return false; - return((isExtAvailable("GL_ARB_framebuffer_no_attachments",gl_extensions)) && - (isExtAvailable("GL_ARB_framebuffer_object",gl_extensions)) && - (isExtAvailable("GL_ARB_framebuffer_sRGB",gl_extensions))); + return (isExtAvailable("GL_ARB_framebuffer_no_attachments",gl_extensions) && isExtAvailable("GL_ARB_framebuffer_object",gl_extensions) && isExtAvailable("GL_ARB_framebuffer_sRGB",gl_extensions)); return false; } @@ -846,7 +852,7 @@ EXPORT void HWRAPI(SetShaderInfo) (hwdshaderinfo_t info, INT32 value) switch (info) { case HWD_SHADERINFO_LEVELTIME: - shader_leveltime = value; + shader_leveltime = (((float)(value-1)) + FIXED_TO_FLOAT(rendertimefrac)) / TICRATE; break; default: break; @@ -1038,37 +1044,9 @@ EXPORT void HWRAPI(DeleteTexture) (GLMipmap_t *pTexInfo) } #ifdef USE_FBO_OGL -void GLFramebuffer_Generate(void) +static void GLFramebuffer_GenerateAttachments(void) { - if (!GLFramebuffer_IsFuncAvailible()) - return; - - // Generate the framebuffer - if (FramebufferObject == 0) - pglGenFramebuffers(1, &FramebufferObject); - - if (pglCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE) - GLFramebuffer_GenerateAttachments(); -} - -void GLFramebuffer_Delete(void) -{ - if (!GLFramebuffer_IsFuncAvailible()) - return; - - // Unbind the framebuffer - pglBindFramebuffer(GL_FRAMEBUFFER, 0); - - if (FramebufferObject) - pglDeleteFramebuffers(1, &FramebufferObject); - - GLFramebuffer_DeleteAttachments(); - FramebufferObject = 0; -} - -void GLFramebuffer_GenerateAttachments(void) -{ - if (!GLFramebuffer_IsFuncAvailible()) + if (!supportFBO) return; // Bind the framebuffer @@ -1109,11 +1087,12 @@ void GLFramebuffer_GenerateAttachments(void) void GLFramebuffer_DeleteAttachments(void) { - if (!GLFramebuffer_IsFuncAvailible()) + if (!supportFBO) return; // Unbind the framebuffer pglBindFramebuffer(GL_FRAMEBUFFER, 0); + pglBindRenderbuffer(GL_RENDERBUFFER, 0); if (FramebufferTexture) pglDeleteTextures(1, &FramebufferTexture); @@ -1125,9 +1104,43 @@ void GLFramebuffer_DeleteAttachments(void) RenderbufferObject = 0; } -void GLFramebuffer_Enable(void) +static void GLFramebuffer_Generate(void) { - if (!GLFramebuffer_IsFuncAvailible()) + if (!supportFBO) + return; + + // Generate the framebuffer + if (FramebufferObject == 0) + pglGenFramebuffers(1, &FramebufferObject); + + if (pglCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE) + GLFramebuffer_GenerateAttachments(); +} + +static void GLFramebuffer_Delete(void) +{ + if (!supportFBO) + return; + + if (FramebufferObject) + pglDeleteFramebuffers(1, &FramebufferObject); + + GLFramebuffer_DeleteAttachments(); + FramebufferObject = 0; +} + +inline void GLFramebuffer_Unbind(void) +{ + if (!supportFBO) + return; + + pglBindFramebuffer(GL_FRAMEBUFFER, 0); + pglBindRenderbuffer(GL_RENDERBUFFER, 0); +} + +inline void GLFramebuffer_Enable(void) +{ + if (!supportFBO) return; if (FramebufferObject == 0) @@ -1141,11 +1154,13 @@ void GLFramebuffer_Enable(void) void GLFramebuffer_Disable(void) { - if (!GLFramebuffer_IsFuncAvailible()) + if (!supportFBO) return; pglBindFramebuffer(GL_FRAMEBUFFER, 0); pglBindRenderbuffer(GL_RENDERBUFFER, 0); + + GLFramebuffer_Delete(); } #endif @@ -1834,7 +1849,9 @@ static void Shader_SetUniforms(FSurfaceInfo *Surface, GLRGBAFloat *poly, GLRGBAF UNIFORM_1(shader->uniforms[gluniform_fade_end], (GLfloat)Surface->LightInfo.fade_end, pglUniform1f); } - UNIFORM_1(shader->uniforms[gluniform_leveltime], ((float)shader_leveltime) / TICRATE, pglUniform1f); + UNIFORM_1(shader->uniforms[gluniform_leveltime], shader_leveltime, pglUniform1f); + + UNIFORM_2(shader->uniforms[gluniform_scr_resolution], vid.width, vid.height, pglUniform2f); #undef UNIFORM_1 #undef UNIFORM_2 @@ -1850,6 +1867,7 @@ static boolean Shader_CompileProgram(gl_shader_t *shader, GLint i) GLint result; const GLchar *vert_shader = shader->vertex_shader; const GLchar *frag_shader = shader->fragment_shader; + GLchar info_log[512]; if (shader->program) pglDeleteProgram(shader->program); @@ -1879,7 +1897,10 @@ static boolean Shader_CompileProgram(gl_shader_t *shader, GLint i) pglGetShaderiv(gl_vertShader, GL_COMPILE_STATUS, &result); if (result == GL_FALSE) { - GL_MSG_Error("Error compiling vertex shader", gl_vertShader, i); + pglGetShaderInfoLog(gl_vertShader, 512, NULL, info_log); + + GL_MSG_Error("Error compiling vertex shader: %s\n", info_log); + pglDeleteShader(gl_vertShader); return false; } @@ -1906,7 +1927,9 @@ static boolean Shader_CompileProgram(gl_shader_t *shader, GLint i) pglGetShaderiv(gl_fragShader, GL_COMPILE_STATUS, &result); if (result == GL_FALSE) { - GL_MSG_Error("Error compiling fragment shader", gl_fragShader, i); + pglGetShaderInfoLog(gl_fragShader, 512, NULL, info_log); + + GL_MSG_Error("Error compiling fragment shader: %s\n", info_log); pglDeleteShader(gl_vertShader); pglDeleteShader(gl_fragShader); return false; @@ -1932,7 +1955,8 @@ static boolean Shader_CompileProgram(gl_shader_t *shader, GLint i) // couldn't link? if (result != GL_TRUE) { - GL_MSG_Error("Shader_CompileProgram: Error linking shader program %s\n", HWR_GetShaderName(i)); + pglGetProgramInfoLog(shader->program, 512, NULL, info_log); + GL_MSG_Error("Shader_CompileProgram: Error linking shader program %s: %s\n", HWR_GetShaderName(i), info_log); pglDeleteProgram(shader->program); return false; } @@ -1953,6 +1977,8 @@ static boolean Shader_CompileProgram(gl_shader_t *shader, GLint i) shader->uniforms[gluniform_palette_lookup_tex] = GETUNI("palette_lookup_tex"); shader->uniforms[gluniform_lighttable_tex] = GETUNI("lighttable_tex"); + shader->uniforms[gluniform_scr_resolution] = GETUNI("scr_resolution"); + // misc. shader->uniforms[gluniform_leveltime] = GETUNI("leveltime"); #undef GETUNI @@ -2327,7 +2353,6 @@ EXPORT void HWRAPI(SetSpecialState) (hwdspecialstate_t IdState, INT32 Value) #ifdef USE_FBO_OGL case HWD_SET_FRAMEBUFFER: FrameBufferEnabled = Value ? GL_TRUE : GL_FALSE; - supportFBO = GLFramebuffer_IsFuncAvailible(); if (!supportFBO) { @@ -2927,6 +2952,8 @@ EXPORT void HWRAPI(SetTransform) (FTransform *stransform) // mirroring from Kart if (stransform->mirror) pglScalef(-stransform->scalex, stransform->scaley, -stransform->scalez); + else if (stransform->mirrorflip) + pglScalef(-stransform->scalex, -stransform->scaley, -stransform->scalez); else #endif if (stransform->flip) @@ -2958,7 +2985,7 @@ EXPORT void HWRAPI(SetTransform) (FTransform *stransform) if (shearing) { float dy = FIXED_TO_FLOAT(AIMINGTODY((stransform->viewaiming)) * 2)* ((float)vid.width / vid.height) / ((float)BASEVIDWIDTH / BASEVIDHEIGHT); //screen_width/BASEVIDWIDTH; - if (stransform->flip) + if (stransform->flip || stransform->mirrorflip) dy *= -1.0f; pglTranslatef(0.0f, -dy/BASEVIDHEIGHT, 0.0f); } diff --git a/src/hardware/r_opengl/r_opengl.h b/src/hardware/r_opengl/r_opengl.h index 255969d5a..baab44637 100644 --- a/src/hardware/r_opengl/r_opengl.h +++ b/src/hardware/r_opengl/r_opengl.h @@ -105,12 +105,9 @@ static PFNglEnableClientState pglEnableClientState; #endif #ifdef USE_FBO_OGL -void GLFramebuffer_Generate(void); -void GLFramebuffer_Delete(void); - -void GLFramebuffer_GenerateAttachments(void); void GLFramebuffer_DeleteAttachments(void); +void GLFramebuffer_Unbind(void); void GLFramebuffer_Enable(void); void GLFramebuffer_Disable(void); diff --git a/src/http-mserv.c b/src/http-mserv.c index d1ef80ae4..9e32f9ea7 100644 --- a/src/http-mserv.c +++ b/src/http-mserv.c @@ -532,7 +532,9 @@ HMS_fetch_rules (char *buffer, size_t buffer_size) if (! hms) return NULL; - if (HMS_do(hms)) + boolean ok = HMS_do(hms); + + if (ok) { char *p = strstr(hms->buffer, "\n\n"); @@ -550,6 +552,9 @@ HMS_fetch_rules (char *buffer, size_t buffer_size) HMS_end(hms); + if (!ok) + return NULL; + return buffer; } diff --git a/src/hu_stuff.c b/src/hu_stuff.c index cd0f42a9c..0594d28cd 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -594,7 +594,10 @@ void HU_AddChatText(const char *text, boolean playsound) if (OLDCHAT) // if we're using oldchat, print directly in console CONS_Printf("%s\n", text); else // if we aren't, still save the message to log.txt - CON_LogMessage(va("%s\n", text)); + { + CON_LogMessage(text); + CON_LogMessage("\n"); // Add newline. Don't use va for that, since `text` might be refering to va's buffer itself + } #else (void)playsound; CONS_Printf("%s\n", text); @@ -1253,7 +1256,11 @@ void HU_Ticker(void) if (cechotimer > 0) --cechotimer; // Animate the desynch dots - if (hu_resynching) + if (hu_resynching +#ifdef SATURNSYNCH + || hu_redownloadinggamestate +#endif + ) resynch_ticker++; //tic tic tic tic tic HU_TickSongCredits(); @@ -2418,7 +2425,11 @@ void HU_Drawer(void) HU_DrawSongCredits(); // draw desynch text - if (hu_resynching) + if (hu_resynching +#ifdef SATURNSYNCH + || hu_redownloadinggamestate +#endif + ) { char resynch_text[14]; UINT32 i; diff --git a/src/i_net.h b/src/i_net.h index c3391a1ed..11dbc6341 100644 --- a/src/i_net.h +++ b/src/i_net.h @@ -34,7 +34,6 @@ #define NO_BAN_TIME (time_t)(-1) extern INT16 hardware_MAXPACKETLENGTH; -extern INT32 net_bandwidth; // in byte/s #if defined(_MSC_VER) #pragma pack(1) @@ -42,36 +41,17 @@ extern INT32 net_bandwidth; // in byte/s typedef struct { - /// Supposed to be DOOMCOM_ID - INT32 id; - - /// SRB2 executes an INT32 to execute commands. - INT16 intnum; - /// Communication between SRB2 and the driver. - /// Is CMD_SEND or CMD_GET. - INT16 command; /// Is dest for send, set by get (-1 = no packet). INT16 remotenode; - /// Number of bytes in doomdata to be sent INT16 datalength; /// Info common to all nodes. /// Console is always node 0. INT16 numnodes; - /// Flag: 1 = no duplication, 2-5 = dup for slow nets. - INT16 ticdup; /// Flag: 1 = send a backup tic in every packet. INT16 extratics; - /// kind of game - INT16 gametype; - /// Flag: -1 = new game, 0-5 = load savegame - INT16 savegame; - /// currect map - INT16 map; - /// Info specific to this node. - INT16 consoleplayer; /// Number of "slots": the highest player number in use plus one. INT16 numslots; diff --git a/src/i_sound.h b/src/i_sound.h index d0542cfb5..925be7596 100644 --- a/src/i_sound.h +++ b/src/i_sound.h @@ -159,7 +159,6 @@ boolean I_SetSongPosition(UINT32 position); UINT32 I_GetSongPosition(void); void I_UpdateSongLagThreshold (void); -void I_UpdateSongLagConditions (void); /// ------------------------ // MUSIC PLAYBACK diff --git a/src/i_system.h b/src/i_system.h index a78eb5c5e..f49bca4a1 100644 --- a/src/i_system.h +++ b/src/i_system.h @@ -34,6 +34,9 @@ extern UINT8 graphics_started; */ extern UINT8 keyboard_started; +/** \brief Set to true when inside a signal handler that will exit the program. */ +extern boolean g_in_exiting_signal_handler; + /** \brief The I_GetFreeMem function \param total total memory in the system @@ -227,6 +230,9 @@ INT32 I_NumJoys(void); */ const char *I_GetJoyName(INT32 joyindex); +void I_GamepadRumble(INT32 device_id, UINT16 low_strength, UINT16 high_strength, UINT32 duration); +void I_SetGamepadIndicatorColor(INT32 device_id, UINT8 red, UINT8 green, UINT8 blue); + #ifndef NOMUMBLE #include "p_mobj.h" // mobj_t #include "s_sound.h" // listener_t diff --git a/src/i_tcp.c b/src/i_tcp.c index 81c221d27..77f8aac0c 100644 --- a/src/i_tcp.c +++ b/src/i_tcp.c @@ -1692,8 +1692,6 @@ boolean I_InitTcpNetwork(void) // FIXME: for dedicated server, numnodes needs to be set to 0 upon start if (dedicated) doomcom->numnodes = 0; -/* else if (M_IsNextParm()) - doomcom->numnodes = (INT16)atoi(M_GetNextParm());*/ else doomcom->numnodes = 1; @@ -1707,7 +1705,6 @@ boolean I_InitTcpNetwork(void) // FIXME: // ??? and now ? // server on a big modem ??? 4*isdn - net_bandwidth = 16000; hardware_MAXPACKETLENGTH = INETPACKETLENGTH; ret = true; @@ -1738,7 +1735,6 @@ boolean I_InitTcpNetwork(void) // so we're on a LAN COM_BufAddText("connect any\n"); - net_bandwidth = 800000; hardware_MAXPACKETLENGTH = MAXPACKETLENGTH; } } @@ -1763,8 +1759,6 @@ boolean I_InitTcpNetwork(void) { // so we're on a LAN COM_BufAddText("connect any\n"); - - net_bandwidth = 800000; hardware_MAXPACKETLENGTH = MAXPACKETLENGTH; } } diff --git a/src/i_video.h b/src/i_video.h index 708fde03c..6a60f8036 100644 --- a/src/i_video.h +++ b/src/i_video.h @@ -140,6 +140,10 @@ UINT32 I_GetRefreshRate(void); boolean I_UseNativeKeyboard(void); #ifdef USE_FBO_OGL +#if defined (__unix__) +extern boolean xwaylandcrap; +#endif + void RefreshOGLSDLSurface(void); void I_DownSample(void); extern boolean downsample; diff --git a/src/info.c b/src/info.c index b417c1135..f8cb9a6f1 100644 --- a/src/info.c +++ b/src/info.c @@ -1822,7 +1822,7 @@ state_t states[NUMSTATES] = // Rain {SPR_RAIN, FF_TRANS50, -1, {NULL}, 0, 0, S_NULL}, // S_RAIN1 - {SPR_RAIN, FF_TRANS50, 1, {NULL}, 0, 0, S_RAIN1}, // S_RAINRETURN + {SPR_NULL, 0, -1, {NULL}, 0, 0, S_NULL}, // S_RAINRETURN // Snowflake {SPR_SNO1, 0, -1, {NULL}, 0, 0, S_NULL}, // S_SNOW1 @@ -1841,9 +1841,9 @@ state_t states[NUMSTATES] = {SPR_SPLH, FF_TRANS50|8, 2, {NULL}, 0, 0, S_NULL}, // S_SPLISH9 // Water Splash - {SPR_SPLA, FF_TRANS50 , 3, {NULL}, 0, 0, S_SPLASH2}, // S_SPLASH1 - {SPR_SPLA, FF_TRANS70|1, 3, {NULL}, 0, 0, S_SPLASH3}, // S_SPLASH2 - {SPR_SPLA, FF_TRANS90|2, 3, {NULL}, 0, 0, S_RAINRETURN}, // S_SPLASH3 + {SPR_SPLA, FF_TRANS50 , 3, {NULL}, 0, 0, S_SPLASH2}, // S_SPLASH1 + {SPR_SPLA, FF_TRANS70|1, 3, {NULL}, 0, 0, S_SPLASH3}, // S_SPLASH2 + {SPR_SPLA, FF_TRANS90|2, 3, {NULL}, 0, 0, S_NULL}, // S_SPLASH3 // Smoke {SPR_SMOK, FF_TRANS50 , 4, {NULL}, 0, 0, S_SMOKE2}, // S_SMOKE1 @@ -11198,22 +11198,22 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_RAIN1, // spawnstate 1000, // spawnhealth S_NULL, // seestate - sfx_None, // seesound - 8, // reactiontime + sfx_rainin, // seesound + 0, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate - S_NULL, // deathstate + S_SPLASH1, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound -72*FRACUNIT, // speed -- -24*FRACUNIT originally, srb2kart x3 (nya) 1*FRACUNIT, // radius 8*FRACUNIT, // height 0, // display offset - 4, // mass + 80, // mass 0, // damage sfx_None, // activesound MF_NOBLOCKMAP, // flags @@ -11226,7 +11226,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound - 8, // reactiontime + 0, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance @@ -11240,7 +11240,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 4*FRACUNIT, // radius 4*FRACUNIT, // height 0, // display offset - 4, // mass + 0, // mass 0, // damage sfx_None, // activesound MF_NOBLOCKMAP, // flags diff --git a/src/info.h b/src/info.h index 9b931ff65..aff87a663 100644 --- a/src/info.h +++ b/src/info.h @@ -22,211 +22,438 @@ // dehacked.c now has lists for the more named enums! PLEASE keep them up to date! // For great modding!! +/** Action pointer for reading actions from Dehacked lumps. + */ +typedef struct +{ + actionf_t action; ///< Function pointer corresponding to the actual action. + const char *name; ///< Name of the action in ALL CAPS. +} actionpointer_t; + +/** Array mapping action names to action functions. + * Names must be in ALL CAPS for case insensitive comparisons. + */ +extern actionpointer_t actionpointers[]; + +// IMPORTANT! +// DO NOT FORGET TO SYNC THIS LIST WITH THE ACTIONPOINTERS ARRAY IN DEHACKED.C +enum actionnum +{ + A_EXPLODE = 0, + A_PAIN, + A_FALL, + A_MONITORPOP, + A_LOOK, + A_CHASE, + A_FACESTABCHASE, + A_FACETARGET, + A_FACETRACER, + A_SCREAM, + A_BOSSDEATH, + A_CUSTOMPOWER, + A_GIVEWEAPON, + A_RINGSHIELD, + A_RINGBOX, + A_INVINCIBILITY, + A_SUPERSNEAKERS, + A_BUNNYHOP, + A_BUBBLESPAWN, + A_FANBUBBLESPAWN, + A_BUBBLERISE, + A_BUBBLECHECK, + A_AWARDSCORE, + A_EXTRALIFE, + A_BOMBSHIELD, + A_JUMPSHIELD, + A_WATERSHIELD, + A_FORCESHIELD, + A_PITYSHIELD, + A_GRAVITYBOX, + A_SCORERISE, + A_PARTICLESPAWN, + A_ATTRACTCHASE, + A_DROPMINE, + A_FISHJUMP, + A_THROWNRING, + A_GRENADERING, // SRB2kart + A_SETSOLIDSTEAM, + A_UNSETSOLIDSTEAM, + A_SIGNPLAYER, + A_OVERLAYTHINK, + A_JETCHASE, + A_JETBTHINK, + A_JETGTHINK, + A_JETGSHOOT, + A_SHOOTBULLET, + A_MINUSDIGGING, + A_MINUSPOPUP, + A_MINUSCHECK, + A_CHICKENCHECK, + A_MOUSETHINK, + A_DETONCHASE, + A_CAPECHASE, + A_ROTATESPIKEBALL, + A_SLINGAPPEAR, + A_MACEROTATE, + A_UNIDUSBALL, + A_ROCKSPAWN, + A_SETFUSE, + A_CRAWLACOMMANDERTHINK, + A_SMOKETRAILER, + A_RINGEXPLODE, + A_OLDRINGEXPLODE, + A_MIXUP, + A_RECYCLEPOWERS, + A_BOSS1CHASE, + A_FOCUSTARGET, + A_BOSS2CHASE, + A_BOSS2POGO, + A_BOSSZOOM, + A_BOSSSCREAM, + A_BOSS2TAKEDAMAGE, + A_BOSS7CHASE, + A_GOOPSPLAT, + A_BOSS2POGOSFX, + A_BOSS2POGOTARGET, + A_BOSSJETFUME, + A_EGGMANBOX, + A_TURRETFIRE, + A_SUPERTURRETFIRE, + A_TURRETSTOP, + A_JETJAWROAM, + A_JETJAWCHOMP, + A_POINTYTHINK, + A_CHECKBUDDY, + A_HOODTHINK, + A_ARROWCHECK, + A_SNAILERTHINK, + A_SHARPCHASE, + A_SHARPSPIN, + A_VULTUREVTOL, + A_VULTURECHECK, + A_SKIMCHASE, + A_1UPTHINKER, + A_SKULLATTACK, + A_LOBSHOT, + A_FIRESHOT, + A_SUPERFIRESHOT, + A_BOSSFIRESHOT, + A_BOSS7FIREMISSILES, + A_BOSS1LASER, + A_BOSS4REVERSE, + A_BOSS4SPEEDUP, + A_BOSS4RAISE, + A_SPARKFOLLOW, + A_BUZZFLY, + A_GUARDCHASE, + A_EGGSHIELD, + A_SETREACTIONTIME, + A_BOSS1SPIKEBALLS, + A_BOSS3TAKEDAMAGE, + A_BOSS3PATH, + A_LINEDEFEXECUTE, + A_PLAYSEESOUND, + A_PLAYATTACKSOUND, + A_PLAYACTIVESOUND, + A_SPAWNOBJECTABSOLUTE, + A_SPAWNOBJECTRELATIVE, + A_CHANGEANGLERELATIVE, + A_CHANGEANGLEABSOLUTE, + A_ROLLANGLE, + A_CHANGEROLLANGLERELATIVE, + A_CHANGEROLLANGLEABSOLUTE, + A_PLAYSOUND, + A_FINDTARGET, + A_FINDTRACER, + A_SETTICS, + A_SETRANDOMTICS, + A_CHANGECOLORRELATIVE, + A_CHANGECOLORABSOLUTE, + A_MOVERELATIVE, + A_MOVEABSOLUTE, + A_THRUST, + A_ZTHRUST, + A_SETTARGETSTARGET, + A_SETOBJECTFLAGS, + A_SETOBJECTFLAGS2, + A_RANDOMSTATE, + A_RANDOMSTATERANGE, + A_DUALACTION, + A_REMOTEACTION, + A_TOGGLEFLAMEJET, + A_ITEMPOP, // SRB2kart + A_JAWZCHASE, // SRB2kart + A_JAWZEXPLODE, // SRB2kart + A_SPBCHASE, // SRB2kart + A_MINEEXPLODE, // SRB2kart + A_BALLHOGEXPLODE, // SRB2kart + A_LIGHTNINGFOLLOWPLAYER, //SRB2kart + A_FZBOOMFLASH, //SRB2kart + A_FZBOOMSMOKE, //SRB2kart + A_RANDOMSHADOWFRAME, //SRB2kart + A_ROAMINGSHADOWTHINKER, //SRB2kart + A_MAYONAKAARROW, //SRB2kart + A_REAPERTHINKER, //SRB2kart + A_MEMENTOSTPPARTICLES, //SRB2kart + A_FLAMEPARTICLE, // SRB2kart + A_ORBITNIGHTS, + A_GHOSTME, + A_SETOBJECTSTATE, + A_SETOBJECTTYPESTATE, + A_KNOCKBACK, + A_PUSHAWAY, + A_RINGDRAIN, + A_SPLITSHOT, + A_MISSILESPLIT, + A_MULTISHOT, + A_INSTALOOP, + A_CUSTOM3DROTATE, + A_SEARCHFORPLAYERS, + A_CHECKRANDOM, + A_CHECKTARGETRINGS, + A_CHECKRINGS, + A_CHECKTOTALRINGS, + A_CHECKHEALTH, + A_CHECKRANGE, + A_CHECKHEIGHT, + A_CHECKTRUERANGE, + A_CHECKTHINGCOUNT, + A_CHECKAMBUSH, + A_CHECKCUSTOMVALUE, + A_CHECKCUSVALMEMO, + A_SETCUSTOMVALUE, + A_USECUSVALMEMO, + A_RELAYCUSTOMVALUE, + A_CUSVALACTION, + A_FORCESTOP, + A_FORCEWIN, + A_SPIKERETRACT, + A_INFOSTATE, + A_REPEAT, + A_SETSCALE, + A_REMOTEDAMAGE, + A_HOMINGCHASE, + A_TRAPSHOT, + A_VILETARGET, + A_VILEATTACK, + A_VILEFIRE, + A_BRAKCHASE, + A_BRAKFIRESHOT, + A_BRAKLOBSHOT, + A_NAPALMSCATTER, + A_SPAWNFRESHCOPY, + NUMACTIONS +}; + +struct mobj_s; + // IMPORTANT NOTE: If you add/remove from this list of action // functions, don't forget to update them in dehacked.c! -void A_Explode(); -void A_Pain(); -void A_Fall(); -void A_MonitorPop(); -void A_Look(); -void A_Chase(); -void A_FaceStabChase(); -void A_FaceTarget(); -void A_FaceTracer(); -void A_Scream(); -void A_BossDeath(); -void A_CustomPower(); // Use this for a custom power -void A_GiveWeapon(); // Gives the player weapon(s) -void A_JumpShield(); // Obtained Jump Shield -void A_RingShield(); // Obtained Ring Shield -void A_RingBox(); // Obtained Ring Box Tails -void A_Invincibility(); // Obtained Invincibility Box -void A_SuperSneakers(); // Obtained Super Sneakers Box -void A_BunnyHop(); // have bunny hop tails -void A_BubbleSpawn(); // Randomly spawn bubbles -void A_FanBubbleSpawn(); -void A_BubbleRise(); // Bubbles float to surface -void A_BubbleCheck(); // Don't draw if not underwater -void A_AwardScore(); -void A_ExtraLife(); // Extra Life -void A_BombShield(); // Obtained Bomb Shield -void A_WaterShield(); // Obtained Water Shield -void A_ForceShield(); // Obtained Force Shield -void A_PityShield(); // Obtained Pity Shield. We're... sorry. -void A_GravityBox(); -void A_ScoreRise(); // Rise the score logo -void A_ParticleSpawn(); -void A_AttractChase(); // Ring Chase -void A_DropMine(); // Drop Mine from Skim or Jetty-Syn Bomber -void A_FishJump(); // Fish Jump -void A_ThrownRing(); // Sparkle trail for red ring -void A_GrenadeRing(); // SRB2kart -void A_SetSolidSteam(); -void A_UnsetSolidSteam(); -void A_SignPlayer(); -void A_OverlayThink(); -void A_JetChase(); -void A_JetbThink(); // Jetty-Syn Bomber Thinker -void A_JetgThink(); // Jetty-Syn Gunner Thinker -void A_JetgShoot(); // Jetty-Syn Shoot Function -void A_ShootBullet(); // JetgShoot without reactiontime setting -void A_MinusDigging(); -void A_MinusPopup(); -void A_MinusCheck(); -void A_ChickenCheck(); -void A_MouseThink(); // Mouse Thinker -void A_DetonChase(); // Deton Chaser -void A_CapeChase(); // Fake little Super Sonic cape -void A_RotateSpikeBall(); // Spike ball rotation -void A_SlingAppear(); -void A_MaceRotate(); -void A_UnidusBall(); -void A_RockSpawn(); -void A_SetFuse(); -void A_CrawlaCommanderThink(); // Crawla Commander -void A_SmokeTrailer(); -void A_RingExplode(); -void A_OldRingExplode(); -void A_MixUp(); -void A_RecyclePowers(); -void A_BossScream(); -void A_Boss2TakeDamage(); -void A_GoopSplat(); -void A_Boss2PogoSFX(); -void A_Boss2PogoTarget(); -void A_EggmanBox(); -void A_TurretFire(); -void A_SuperTurretFire(); -void A_TurretStop(); -void A_JetJawRoam(); -void A_JetJawChomp(); -void A_PointyThink(); -void A_CheckBuddy(); -void A_HoodThink(); -void A_ArrowCheck(); -void A_SnailerThink(); -void A_SharpChase(); -void A_SharpSpin(); -void A_VultureVtol(); -void A_VultureCheck(); -void A_SkimChase(); -void A_SkullAttack(); -void A_LobShot(); -void A_FireShot(); -void A_SuperFireShot(); -void A_BossFireShot(); -void A_Boss7FireMissiles(); -void A_Boss1Laser(); -void A_FocusTarget(); -void A_Boss4Reverse(); -void A_Boss4SpeedUp(); -void A_Boss4Raise(); -void A_SparkFollow(); -void A_BuzzFly(); -void A_GuardChase(); -void A_EggShield(); -void A_SetReactionTime(); -void A_Boss1Spikeballs(); -void A_Boss3TakeDamage(); -void A_Boss3Path(); -void A_LinedefExecute(); -void A_PlaySeeSound(); -void A_PlayAttackSound(); -void A_PlayActiveSound(); -void A_1upThinker(); -void A_BossZoom(); //Unused -void A_Boss1Chase(); -void A_Boss2Chase(); -void A_Boss2Pogo(); -void A_Boss7Chase(); -void A_BossJetFume(); -void A_SpawnObjectAbsolute(); -void A_SpawnObjectRelative(); -void A_ChangeAngleRelative(); -void A_ChangeAngleAbsolute(); -void A_RollAngle(); -void A_ChangeRollAngleRelative(); -void A_ChangeRollAngleAbsolute(); -void A_PlaySound(); -void A_FindTarget(); -void A_FindTracer(); -void A_SetTics(); -void A_SetRandomTics(); -void A_ChangeColorRelative(); -void A_ChangeColorAbsolute(); -void A_MoveRelative(); -void A_MoveAbsolute(); -void A_Thrust(); -void A_ZThrust(); -void A_SetTargetsTarget(); -void A_SetObjectFlags(); -void A_SetObjectFlags2(); -void A_RandomState(); -void A_RandomStateRange(); -void A_DualAction(); -void A_RemoteAction(); -void A_ToggleFlameJet(); -void A_ItemPop(); // SRB2kart -void A_JawzChase(); // SRB2kart -void A_JawzExplode(); // SRB2kart -void A_SPBChase(); // SRB2kart -void A_MineExplode(); // SRB2kart -void A_BallhogExplode(); // SRB2kart -void A_LightningFollowPlayer(); // SRB2kart: Lightning shield effect player chasing -void A_FZBoomFlash(); // SRB2kart -void A_FZBoomSmoke(); // SRB2kart -void A_RandomShadowFrame(); //SRB2kart: Shadow spawner frame randomizer -void A_RoamingShadowThinker(); // SRB2kart: Roaming Shadow moving + attacking players. -void A_MayonakaArrow(); //SRB2kart: midnight channel arrow sign -void A_ReaperThinker(); //SRB2kart: mementos reaper -void A_MementosTPParticles(); //SRB2kart: mementos teleporter particles. Man that's a lot of actions for my shite. -void A_FlameParticle(); // SRB2kart -void A_OrbitNights(); -void A_GhostMe(); -void A_SetObjectState(); -void A_SetObjectTypeState(); -void A_KnockBack(); -void A_PushAway(); -void A_RingDrain(); -void A_SplitShot(); -void A_MissileSplit(); -void A_MultiShot(); -void A_InstaLoop(); -void A_Custom3DRotate(); -void A_SearchForPlayers(); -void A_CheckRandom(); -void A_CheckTargetRings(); -void A_CheckRings(); -void A_CheckTotalRings(); -void A_CheckHealth(); -void A_CheckRange(); -void A_CheckHeight(); -void A_CheckTrueRange(); -void A_CheckThingCount(); -void A_CheckAmbush(); -void A_CheckCustomValue(); -void A_CheckCusValMemo(); -void A_SetCustomValue(); -void A_UseCusValMemo(); -void A_RelayCustomValue(); -void A_CusValAction(); -void A_ForceStop(); -void A_ForceWin(); -void A_SpikeRetract(); -void A_InfoState(); -void A_Repeat(); -void A_SetScale(); -void A_RemoteDamage(); -void A_HomingChase(); -void A_TrapShot(); -void A_VileTarget(); -void A_VileAttack(); -void A_VileFire(); -void A_BrakChase(); -void A_BrakFireShot(); -void A_BrakLobShot(); -void A_NapalmScatter(); -void A_SpawnFreshCopy(); +void A_Explode(struct mobj_s *actor); +void A_Pain(struct mobj_s *actor); +void A_Fall(struct mobj_s *actor); +void A_MonitorPop(struct mobj_s *actor); +void A_Look(struct mobj_s *actor); +void A_Chase(struct mobj_s *actor); +void A_FaceStabChase(struct mobj_s *actor); +void A_FaceTarget(struct mobj_s *actor); +void A_FaceTracer(struct mobj_s *actor); +void A_Scream(struct mobj_s *actor); +void A_BossDeath(struct mobj_s *actor); +void A_CustomPower(struct mobj_s *actor); // Use this for a custom power +void A_GiveWeapon(struct mobj_s *actor); // Gives the player weapon(s) +void A_JumpShield(struct mobj_s *actor); // Obtained Jump Shield +void A_RingShield(struct mobj_s *actor); // Obtained Ring Shield +void A_RingBox(struct mobj_s *actor); // Obtained Ring Box Tails +void A_Invincibility(struct mobj_s *actor); // Obtained Invincibility Box +void A_SuperSneakers(struct mobj_s *actor); // Obtained Super Sneakers Box +void A_BunnyHop(struct mobj_s *actor); // have bunny hop tails +void A_BubbleSpawn(struct mobj_s *actor); // Randomly spawn bubbles +void A_FanBubbleSpawn(struct mobj_s *actor); +void A_BubbleRise(struct mobj_s *actor); // Bubbles float to surface +void A_BubbleCheck(struct mobj_s *actor); // Don't draw if not underwater +void A_AwardScore(struct mobj_s *actor); +void A_ExtraLife(struct mobj_s *actor); // Extra Life +void A_BombShield(struct mobj_s *actor); // Obtained Bomb Shield +void A_WaterShield(struct mobj_s *actor); // Obtained Water Shield +void A_ForceShield(struct mobj_s *actor); // Obtained Force Shield +void A_PityShield(struct mobj_s *actor); // Obtained Pity Shield. We're... sorry. +void A_GravityBox(struct mobj_s *actor); +void A_ScoreRise(struct mobj_s *actor); // Rise the score logo +void A_ParticleSpawn(struct mobj_s *actor); +void A_AttractChase(struct mobj_s *actor); // Ring Chase +void A_DropMine(struct mobj_s *actor); // Drop Mine from Skim or Jetty-Syn Bomber +void A_FishJump(struct mobj_s *actor); // Fish Jump +void A_ThrownRing(struct mobj_s *actor); // Sparkle trail for red ring +void A_GrenadeRing(struct mobj_s *actor); // SRB2kart +void A_SetSolidSteam(struct mobj_s *actor); +void A_UnsetSolidSteam(struct mobj_s *actor); +void A_SignPlayer(struct mobj_s *actor); +void A_OverlayThink(struct mobj_s *actor); +void A_JetChase(struct mobj_s *actor); +void A_JetbThink(struct mobj_s *actor); // Jetty-Syn Bomber Thinker +void A_JetgThink(struct mobj_s *actor); // Jetty-Syn Gunner Thinker +void A_JetgShoot(struct mobj_s *actor); // Jetty-Syn Shoot Function +void A_ShootBullet(struct mobj_s *actor); // JetgShoot without reactiontime setting +void A_MinusDigging(struct mobj_s *actor); +void A_MinusPopup(struct mobj_s *actor); +void A_MinusCheck(struct mobj_s *actor); +void A_ChickenCheck(struct mobj_s *actor); +void A_MouseThink(struct mobj_s *actor); // Mouse Thinker +void A_DetonChase(struct mobj_s *actor); // Deton Chaser +void A_CapeChase(struct mobj_s *actor); // Fake little Super Sonic cape +void A_RotateSpikeBall(struct mobj_s *actor); // Spike ball rotation +void A_SlingAppear(struct mobj_s *actor); +void A_MaceRotate(struct mobj_s *actor); +void A_UnidusBall(struct mobj_s *actor); +void A_RockSpawn(struct mobj_s *actor); +void A_SetFuse(struct mobj_s *actor); +void A_CrawlaCommanderThink(struct mobj_s *actor); // Crawla Commander +void A_SmokeTrailer(struct mobj_s *actor); +void A_RingExplode(struct mobj_s *actor); +void A_OldRingExplode(struct mobj_s *actor); +void A_MixUp(struct mobj_s *actor); +void A_RecyclePowers(struct mobj_s *actor); +void A_BossScream(struct mobj_s *actor); +void A_Boss2TakeDamage(struct mobj_s *actor); +void A_GoopSplat(struct mobj_s *actor); +void A_Boss2PogoSFX(struct mobj_s *actor); +void A_Boss2PogoTarget(struct mobj_s *actor); +void A_EggmanBox(struct mobj_s *actor); +void A_TurretFire(struct mobj_s *actor); +void A_SuperTurretFire(struct mobj_s *actor); +void A_TurretStop(struct mobj_s *actor); +void A_JetJawRoam(struct mobj_s *actor); +void A_JetJawChomp(struct mobj_s *actor); +void A_PointyThink(struct mobj_s *actor); +void A_CheckBuddy(struct mobj_s *actor); +void A_HoodThink(struct mobj_s *actor); +void A_ArrowCheck(struct mobj_s *actor); +void A_SnailerThink(struct mobj_s *actor); +void A_SharpChase(struct mobj_s *actor); +void A_SharpSpin(struct mobj_s *actor); +void A_VultureVtol(struct mobj_s *actor); +void A_VultureCheck(struct mobj_s *actor); +void A_SkimChase(struct mobj_s *actor); +void A_SkullAttack(struct mobj_s *actor); +void A_LobShot(struct mobj_s *actor); +void A_FireShot(struct mobj_s *actor); +void A_SuperFireShot(struct mobj_s *actor); +void A_BossFireShot(struct mobj_s *actor); +void A_Boss7FireMissiles(struct mobj_s *actor); +void A_Boss1Laser(struct mobj_s *actor); +void A_FocusTarget(struct mobj_s *actor); +void A_Boss4Reverse(struct mobj_s *actor); +void A_Boss4SpeedUp(struct mobj_s *actor); +void A_Boss4Raise(struct mobj_s *actor); +void A_SparkFollow(struct mobj_s *actor); +void A_BuzzFly(struct mobj_s *actor); +void A_GuardChase(struct mobj_s *actor); +void A_EggShield(struct mobj_s *actor); +void A_SetReactionTime(struct mobj_s *actor); +void A_Boss1Spikeballs(struct mobj_s *actor); +void A_Boss3TakeDamage(struct mobj_s *actor); +void A_Boss3Path(struct mobj_s *actor); +void A_LinedefExecute(struct mobj_s *actor); +void A_PlaySeeSound(struct mobj_s *actor); +void A_PlayAttackSound(struct mobj_s *actor); +void A_PlayActiveSound(struct mobj_s *actor); +void A_1upThinker(struct mobj_s *actor); +void A_BossZoom(struct mobj_s *actor); //Unused +void A_Boss1Chase(struct mobj_s *actor); +void A_Boss2Chase(struct mobj_s *actor); +void A_Boss2Pogo(struct mobj_s *actor); +void A_Boss7Chase(struct mobj_s *actor); +void A_BossJetFume(struct mobj_s *actor); +void A_SpawnObjectAbsolute(struct mobj_s *actor); +void A_SpawnObjectRelative(struct mobj_s *actor); +void A_ChangeAngleRelative(struct mobj_s *actor); +void A_ChangeAngleAbsolute(struct mobj_s *actor); +void A_RollAngle(struct mobj_s *actor); +void A_ChangeRollAngleRelative(struct mobj_s *actor); +void A_ChangeRollAngleAbsolute(struct mobj_s *actor); +void A_PlaySound(struct mobj_s *actor); +void A_FindTarget(struct mobj_s *actor); +void A_FindTracer(struct mobj_s *actor); +void A_SetTics(struct mobj_s *actor); +void A_SetRandomTics(struct mobj_s *actor); +void A_ChangeColorRelative(struct mobj_s *actor); +void A_ChangeColorAbsolute(struct mobj_s *actor); +void A_MoveRelative(struct mobj_s *actor); +void A_MoveAbsolute(struct mobj_s *actor); +void A_Thrust(struct mobj_s *actor); +void A_ZThrust(struct mobj_s *actor); +void A_SetTargetsTarget(struct mobj_s *actor); +void A_SetObjectFlags(struct mobj_s *actor); +void A_SetObjectFlags2(struct mobj_s *actor); +void A_RandomState(struct mobj_s *actor); +void A_RandomStateRange(struct mobj_s *actor); +void A_DualAction(struct mobj_s *actor); +void A_RemoteAction(struct mobj_s *actor); +void A_ToggleFlameJet(struct mobj_s *actor); +void A_ItemPop(struct mobj_s *actor); // SRB2kart +void A_JawzChase(struct mobj_s *actor); // SRB2kart +void A_JawzExplode(struct mobj_s *actor); // SRB2kart +void A_SPBChase(struct mobj_s *actor); // SRB2kart +void A_MineExplode(struct mobj_s *actor); // SRB2kart +void A_BallhogExplode(struct mobj_s *actor); // SRB2kart +void A_LightningFollowPlayer(struct mobj_s *actor); // SRB2kart: Lightning shield effect player chasing +void A_FZBoomFlash(struct mobj_s *actor); // SRB2kart +void A_FZBoomSmoke(struct mobj_s *actor); // SRB2kart +void A_RandomShadowFrame(struct mobj_s *actor); //SRB2kart: Shadow spawner frame randomizer +void A_RoamingShadowThinker(struct mobj_s *actor); // SRB2kart: Roaming Shadow moving + attacking players. +void A_MayonakaArrow(struct mobj_s *actor); //SRB2kart: midnight channel arrow sign +void A_ReaperThinker(struct mobj_s *actor); //SRB2kart: mementos reaper +void A_MementosTPParticles(struct mobj_s *actor); //SRB2kart: mementos teleporter particles. Man that's a lot of actions for my shite. +void A_FlameParticle(struct mobj_s *actor); // SRB2kart +void A_OrbitNights(struct mobj_s *actor); +void A_GhostMe(struct mobj_s *actor); +void A_SetObjectState(struct mobj_s *actor); +void A_SetObjectTypeState(struct mobj_s *actor); +void A_KnockBack(struct mobj_s *actor); +void A_PushAway(struct mobj_s *actor); +void A_RingDrain(struct mobj_s *actor); +void A_SplitShot(struct mobj_s *actor); +void A_MissileSplit(struct mobj_s *actor); +void A_MultiShot(struct mobj_s *actor); +void A_InstaLoop(struct mobj_s *actor); +void A_Custom3DRotate(struct mobj_s *actor); +void A_SearchForPlayers(struct mobj_s *actor); +void A_CheckRandom(struct mobj_s *actor); +void A_CheckTargetRings(struct mobj_s *actor); +void A_CheckRings(struct mobj_s *actor); +void A_CheckTotalRings(struct mobj_s *actor); +void A_CheckHealth(struct mobj_s *actor); +void A_CheckRange(struct mobj_s *actor); +void A_CheckHeight(struct mobj_s *actor); +void A_CheckTrueRange(struct mobj_s *actor); +void A_CheckThingCount(struct mobj_s *actor); +void A_CheckAmbush(struct mobj_s *actor); +void A_CheckCustomValue(struct mobj_s *actor); +void A_CheckCusValMemo(struct mobj_s *actor); +void A_SetCustomValue(struct mobj_s *actor); +void A_UseCusValMemo(struct mobj_s *actor); +void A_RelayCustomValue(struct mobj_s *actor); +void A_CusValAction(struct mobj_s *actor); +void A_ForceStop(struct mobj_s *actor); +void A_ForceWin(struct mobj_s *actor); +void A_SpikeRetract(struct mobj_s *actor); +void A_InfoState(struct mobj_s *actor); +void A_Repeat(struct mobj_s *actor); +void A_SetScale(struct mobj_s *actor); +void A_RemoteDamage(struct mobj_s *actor); +void A_HomingChase(struct mobj_s *actor); +void A_TrapShot(struct mobj_s *actor); +void A_VileTarget(struct mobj_s *actor); +void A_VileAttack(struct mobj_s *actor); +void A_VileFire(struct mobj_s *actor); +void A_BrakChase(struct mobj_s *actor); +void A_BrakFireShot(struct mobj_s *actor); +void A_BrakLobShot(struct mobj_s *actor); +void A_NapalmScatter(struct mobj_s *actor); +void A_SpawnFreshCopy(struct mobj_s *actor); + +extern boolean actionsoverridden[NUMACTIONS]; // ratio of states to sprites to mobj types is roughly 6 : 1 : 1 #define NUMMOBJFREESLOTS 1024 diff --git a/src/k_director.c b/src/k_director.c new file mode 100644 index 000000000..952adf8da --- /dev/null +++ b/src/k_director.c @@ -0,0 +1,403 @@ +// SONIC ROBO BLAST 2 KART +//----------------------------------------------------------------------------- +// Copyright (C) 2024 by AJ "Tyron" Martinez. +// Copyright (C) 2024 by James Robert Roman. +// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. +//----------------------------------------------------------------------------- +/// \file k_director.c +/// \brief SRB2kart automatic spectator camera. + +//#include "k_kart.h" +#include "doomdef.h" +#include "g_game.h" +#include "v_video.h" +#include "k_director.h" +#include "d_netcmd.h" +#include "p_local.h" + +#define SWITCHTIME TICRATE * 5 // cooldown between unforced switches +#define BOREDOMTIME 3 * TICRATE / 2 // how long until players considered far apart? +#define TRANSFERTIME TICRATE // how long to delay reaction shots? +#define BREAKAWAYDIST 2000 // how *far* until players considered far apart? +#define WALKBACKDIST 600 // how close should a trailing player be before we switch? +#define PINCHDIST 20000 // how close should the leader be to be considered "end of race"? + +struct directorinfo +{ + tic_t cooldown; // how long has it been since we last switched? + tic_t freeze; // when nonzero, fixed switch pending, freeze logic! + INT32 attacker; // who to switch to when freeze delay elapses + INT32 maxdist; // how far is the closest player from finishing? + + INT32 sortedplayers[MAXPLAYERS]; // position-1 goes in, player index comes out. + INT32 gap[MAXPLAYERS]; // gap between a given position and their closest pursuer + INT32 boredom[MAXPLAYERS]; // how long has a given position had no credible attackers? +} directorinfo; + +static inline boolean race_rules(void) +{ + return gametype == GT_RACE; +} + +static fixed_t ScaleFromMap(fixed_t n, fixed_t scale) +{ + return FixedMul(n, FixedDiv(scale, mapobjectscale)); +} + +static boolean K_DirectorIsEnabled(void) +{ + return cv_director.value && !splitscreen && (gamestate == GS_LEVEL && (!playeringame[consoleplayer] || players[consoleplayer].spectator || (demo.playback && (!demo.title || !modeattacking)))); +} + +void K_InitDirector(void) +{ + INT32 playernum; + + directorinfo.cooldown = SWITCHTIME; + directorinfo.freeze = 0; + directorinfo.attacker = 0; + directorinfo.maxdist = 0; + + for (playernum = 0; playernum < MAXPLAYERS; playernum++) + { + directorinfo.sortedplayers[playernum] = -1; + directorinfo.gap[playernum] = INT32_MAX; + directorinfo.boredom[playernum] = 0; + } +} + +static fixed_t K_GetDistanceToFinish(player_t player) +{ + mobj_t *mo; + fixed_t dist = 0; + INT16 maxMoveCount = -1; + INT16 maxAngle = -1; + + if (!(mapheaderinfo[gamemap - 1]->levelflags & LF_SECTIONRACE)) + { + for (mo = waypointcap; mo != NULL; mo = mo->tracer) + { + if (mo->spawnpoint->angle != 0) + continue; + + dist = P_AproxDistance(P_AproxDistance(mo->x - player.mo->x, + mo->y - player.mo->y), + mo->z - player.mo->z) / FRACUNIT; + + break; + } + } + else // crappy optimization weeeee + { + for (mo = waypointcap; mo != NULL; mo = mo->tracer) + { + if (mo->movecount > maxMoveCount) + maxMoveCount = mo->movecount; + if (mo->spawnpoint->angle > maxAngle) + maxAngle = mo->spawnpoint->angle; + + if (!(mo->movecount == maxMoveCount && mo->spawnpoint->angle == maxAngle)) // sprint maps finishline waypoint is the one with highest movecount AND angle + continue; + + dist = P_AproxDistance(P_AproxDistance(mo->x - player.mo->x, + mo->y - player.mo->y), + mo->z - player.mo->z) / FRACUNIT; + + break; + } + } + + return dist; +} + +static fixed_t K_GetFinishGap(INT32 leader, INT32 follower) +{ + fixed_t dista = K_GetDistanceToFinish(players[follower]); + fixed_t distb = K_GetDistanceToFinish(players[leader]); + + if (players[follower].kartstuff[k_position] < players[leader].kartstuff[k_position]) + { + return distb - dista; + } + else + { + return dista - distb; + } +} + +static void K_UpdateDirectorPositions(void) +{ + INT32 playernum; + INT32 position; + player_t* target; + + memset(directorinfo.sortedplayers, -1, sizeof(directorinfo.sortedplayers)); + + for (playernum = 0; playernum < MAXPLAYERS; playernum++) + { + target = &players[playernum]; + + if (playeringame[playernum] && !target->spectator && target->kartstuff[k_position] > 0) + { + directorinfo.sortedplayers[target->kartstuff[k_position] - 1] = playernum; + } + } + + for (position = 0; position < MAXPLAYERS - 1; position++) + { + directorinfo.gap[position] = INT32_MAX; + + if (directorinfo.sortedplayers[position] == -1 || directorinfo.sortedplayers[position + 1] == -1) + { + continue; + } + + directorinfo.gap[position] = ScaleFromMap(K_GetFinishGap(directorinfo.sortedplayers[position], directorinfo.sortedplayers[position + 1]), FRACUNIT); + + if (directorinfo.gap[position] >= BREAKAWAYDIST) + { + directorinfo.boredom[position] = (INT32)(min(BOREDOMTIME * 2, directorinfo.boredom[position] + 1)); + } + else if (directorinfo.boredom[position] > 0) + { + directorinfo.boredom[position]--; + } + } + + if (directorinfo.sortedplayers[0] == -1) + { + directorinfo.maxdist = -1; + return; + } + + directorinfo.maxdist = ScaleFromMap(K_GetDistanceToFinish(players[directorinfo.sortedplayers[0]]), FRACUNIT); +} + +static boolean K_CanSwitchDirector(void) +{ + if (directorinfo.cooldown > 0) + { + return false; + } + + return true; +} + +static void K_DirectorSwitch(INT32 player, boolean force) +{ + if (!K_DirectorIsEnabled()) + { + return; + } + + if (P_IsDisplayPlayer(&players[player])) + { + return; + } + + if (players[player].exiting) + { + return; + } + + if (!force && !K_CanSwitchDirector()) + { + return; + } + + G_ResetView(1, player, true); + directorinfo.cooldown = SWITCHTIME; +} + +static void K_DirectorForceSwitch(INT32 player, INT32 time) +{ + if (players[player].exiting) + { + return; + } + + directorinfo.attacker = player; + directorinfo.freeze = time; +} + +void K_DirectorFollowAttack(player_t *player, mobj_t *inflictor, mobj_t *source) +{ + if (!K_DirectorIsEnabled()) + { + return; + } + + if (!P_IsDisplayPlayer(player)) + { + return; + } + + if (inflictor && inflictor->player) + { + K_DirectorForceSwitch(inflictor->player - players, TRANSFERTIME); + } + else if (source && source->player) + { + K_DirectorForceSwitch(source->player - players, TRANSFERTIME); + } +} + +void K_DrawDirectorDebugger(void) +{ + INT32 position; + INT32 leader; + INT32 follower; + INT32 ytxt; + + if (!cv_kartdebugdirector.value) + { + return; + } + + V_DrawThinString(10, 0, V_70TRANS, va("PLACE")); + V_DrawThinString(40, 0, V_70TRANS, va("CONF?")); + V_DrawThinString(80, 0, V_70TRANS, va("GAP")); + V_DrawThinString(120, 0, V_70TRANS, va("BORED")); + V_DrawThinString(150, 0, V_70TRANS, va("COOLDOWN: %d", directorinfo.cooldown)); + V_DrawThinString(230, 0, V_70TRANS, va("MAXDIST: %d", directorinfo.maxdist)); + + for (position = 0; position < MAXPLAYERS - 1; position++) + { + ytxt = 10 * (position + 1); + leader = directorinfo.sortedplayers[position]; + follower = directorinfo.sortedplayers[position + 1]; + + if (leader == -1 || follower == -1) + break; + + V_DrawThinString(10, ytxt, V_70TRANS, va("%d", position)); + V_DrawThinString(20, ytxt, V_70TRANS, va("%d", position + 1)); + + if (players[leader].kartstuff[k_positiondelay]) + { + V_DrawThinString(40, ytxt, V_70TRANS, va("NG")); + } + + V_DrawThinString(80, ytxt, V_70TRANS, va("%d", directorinfo.gap[position])); + + if (directorinfo.boredom[position] >= BOREDOMTIME) + { + V_DrawThinString(120, ytxt, V_70TRANS, va("BORED")); + } + else + { + V_DrawThinString(120, ytxt, V_70TRANS, va("%d", directorinfo.boredom[position])); + } + + V_DrawThinString(150, ytxt, V_70TRANS, va("%s", player_names[leader])); + V_DrawThinString(230, ytxt, V_70TRANS, va("%s", player_names[follower])); + } +} + +void K_UpdateDirector(void) +{ + INT32 *displayplayerp = &displayplayers[0]; + INT32 targetposition; + + if (!K_DirectorIsEnabled()) + { + return; + } + + K_UpdateDirectorPositions(); + + if (directorinfo.cooldown > 0) { + directorinfo.cooldown--; + } + + // handle pending forced switches + if (directorinfo.freeze > 0) + { + if (!(--directorinfo.freeze)) + K_DirectorSwitch(directorinfo.attacker, true); + + return; + } + + // if there's only one player left in the list, just switch to that player + if (directorinfo.sortedplayers[0] != -1 && (directorinfo.sortedplayers[1] == -1 || + // TODO: Battle; I just threw this together quick. Focus on leader. + !race_rules())) + { + K_DirectorSwitch(directorinfo.sortedplayers[0], false); + return; + } + + // aaight, time to walk through the standings to find the first interesting pair + // NB: targetposition/sortedplayers is 0-indexed, aiming at the "back half" of a given pair by default. + // we adjust for this when comparing to player->position or when looking at the leading player, Don't Freak Out + for (targetposition = 1; targetposition < MAXPLAYERS; targetposition++) + { + INT32 target; + + // you are out of players, try again + if (directorinfo.sortedplayers[targetposition] == -1) + { + break; + } + + // pair too far apart? try the next one + if (directorinfo.boredom[targetposition - 1] >= BOREDOMTIME) + { + continue; + } + + // pair finished? try the next one + if (players[directorinfo.sortedplayers[targetposition]].exiting) + { + continue; + } + + // don't risk switching away from forward pairs at race end, might miss something! + if (directorinfo.maxdist > PINCHDIST) + { + // if the "next" player is close enough, they should be able to see everyone fine! + // walk back through the standings to find a vantage that gets everyone in frame. + // (also creates a pretty cool effect w/ overtakes at speed) + while (targetposition < MAXPLAYERS && directorinfo.gap[targetposition] < WALKBACKDIST) + { + targetposition++; + } + } + + target = directorinfo.sortedplayers[targetposition]; + + // stop here since we're already viewing this player + if (*displayplayerp == target) + { + break; + } + + // if we're certain the back half of the pair is actually in this position, try to switch + if (!players[target].kartstuff[k_positiondelay]) + { + K_DirectorSwitch(target, false); + } + + // even if we're not certain, if we're certain we're watching the WRONG player, try to switch + if (players[*displayplayerp].kartstuff[k_position] != targetposition+1 && !players[*displayplayerp].kartstuff[k_positiondelay]) + { + K_DirectorSwitch(target, false); + } + + break; + } +} + +void K_ToggleDirector(void) +{ + if (!K_DirectorIsEnabled()) + { + directorinfo.cooldown = 0; // switch immediately + } + + COM_ImmedExecute("add director 1"); +} diff --git a/src/k_director.h b/src/k_director.h new file mode 100644 index 000000000..3be71b675 --- /dev/null +++ b/src/k_director.h @@ -0,0 +1,17 @@ +// SONIC ROBO BLAST 2 KART +//----------------------------------------------------------------------------- +// Copyright (C) 2024 by AJ "Tyron" Martinez. +// Copyright (C) 2024 by James Robert Roman. +// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. +//----------------------------------------------------------------------------- +/// \file k_director.h +/// \brief SRB2kart automatic spectator camera. + +void K_InitDirector(void); +void K_UpdateDirector(void); +void K_DrawDirectorDebugger(void); +void K_DirectorFollowAttack(player_t *player, mobj_t *inflictor, mobj_t *source); +void K_ToggleDirector(void); diff --git a/src/k_kart.c b/src/k_kart.c index 2857eddf3..03efb24c9 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -16,6 +16,7 @@ #include "m_random.h" #include "m_menu.h" // ffdhidshfuisduifigergho9igj89dgodhfih AAAAAAAAAA #include "p_local.h" +#include "p_setup.h" #include "p_slopes.h" #include "r_defs.h" #include "r_draw.h" @@ -31,12 +32,14 @@ #include "z_zone.h" #include "m_misc.h" #include "m_cond.h" +#include "k_director.h" #include "k_kart.h" #include "f_finale.h" #include "lua_hud.h" // For Lua hud checks #include "lua_hook.h" // For MobjDamage and ShouldDamage #include "d_main.h" // found_extra_kart + #include "i_video.h" #ifdef HWRENDER @@ -74,6 +77,7 @@ IMPL_HUD_OFFSET(stat); // Stats //extra hud things consvar_t cv_showstats = {"showstats", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_showinput = {"showinput", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_showlaptimes = {"showlaptimes", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; CV_PossibleValue_t speedo_cons_t[NUMSPEEDOSTUFF]; consvar_t cv_newspeedometer = {"newspeedometer", "Default", CV_SAVE, speedo_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; @@ -84,7 +88,7 @@ consvar_t cv_saltyhopsfx = {"hardcodehopsfx", "On", CV_SAVE, CV_OnOff, NULL, 0, consvar_t cv_saltysquish = {"hardcodehopsquish", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; //Colourized HUD -consvar_t cv_colorizedhud = {"colorizedhud", "Off", CV_SAVE|CV_CALL, CV_OnOff, Saturn_menu_Onchange, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_colorizedhud = {"colorizedhud", "Off", CV_SAVE|CV_CALL, CV_OnOff, SaturnHud_menu_Onchange, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_colorizeditembox = {"colorizeditembox", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; static CV_PossibleValue_t HudColor_cons_t[MAXSKINCOLORS+1]; @@ -613,10 +617,8 @@ UINT8 K_GetKartColorByName(const char *name) UINT8 K_GetHudColor(void) { - if (cv_colorizedhud.value){ - if (cv_colorizedhudcolor.value) return cv_colorizedhudcolor.value; - } - if (stplyr && P_IsLocalPlayer(stplyr) && gamestate == GS_LEVEL) return stplyr->skincolor; + if (cv_colorizedhud.value && cv_colorizedhudcolor.value) return cv_colorizedhudcolor.value; + return ((stplyr && gamestate == GS_LEVEL) ? stplyr->skincolor : cv_playercolor.value); } @@ -678,6 +680,7 @@ void K_RegisterKartStuff(void) CV_RegisterVar(&cv_kartgametypepreference); CV_RegisterVar(&cv_kartspeedometer); CV_RegisterVar(&cv_kartvoices); + CV_RegisterVar(&cv_karthitemdialog); CV_RegisterVar(&cv_karteliminatelast); CV_RegisterVar(&cv_votetime); @@ -720,6 +723,7 @@ void K_RegisterKartStuff(void) CV_RegisterVar(&cv_showstats); CV_RegisterVar(&cv_showinput); + CV_RegisterVar(&cv_showlaptimes); CV_RegisterVar(&cv_newspeedometer); CV_RegisterVar(&cv_battlespeedo); @@ -1896,6 +1900,31 @@ static void K_RegularVoiceTimers(player_t *player) player->kartstuff[k_tauntvoices] = 4*TICRATE; } +static void K_PlayGenericCombatSound(mobj_t *source, mobj_t *other, sfxenum_t sfx_id) +{ + skin_t *skin = NULL; + + // I HATE LOCALSKINS! I HATE LOCALSKINS! :AAAAAAAAAA: + if (source->player) + { + INT32 skinnum = source->player->skinlocal ? (source->player->localskin - 1) : source->player->skin; + skin = &(source->player->skinlocal ? localskins : skins)[skinnum]; + } + + if (!skin) + return; + + boolean alwaysHear = false; + + if (other != NULL && P_MobjWasRemoved(other) == false && other->player != NULL) + alwaysHear = P_IsDisplayPlayer(other->player); + + if (cv_kartvoices.value) + S_StartSound(alwaysHear ? NULL : source, skin->soundsid[S_sfx[sfx_id].skinsound]); + + K_RegularVoiceTimers(source->player); +} + void K_PlayAttackTaunt(mobj_t *source) { sfxenum_t pick = P_RandomKey(2); // Gotta roll the RNG every time this is called for sync reasons @@ -1944,10 +1973,34 @@ void K_PlayOvertakeSound(mobj_t *source) K_RegularVoiceTimers(source->player); } -void K_PlayHitEmSound(mobj_t *source) +static boolean K_SetDelayedHitEm(player_t *player, player_t *victim) +{ + player_t *prevvictim = NULL; + + if (player->hitemtimer) + prevvictim = &players[player->hitemvictim]; + + // We prioritize local players to hear "hit em" sfx + if (prevvictim && P_IsDisplayPlayer(prevvictim) && !P_IsDisplayPlayer(victim)) + return false; + + player->hitemtimer = TICRATE/2; + player->hitemvictim = victim - players; + + return true; +} + +void K_PlayHitEmSound(mobj_t *source, mobj_t *victim) { if (cv_kartvoices.value) + { + if (cv_karthitemdialog.value + && source->player && victim && victim->player + && K_SetDelayedHitEm(source->player, victim->player)) + return; // Don't call K_RegularVoiceTimers yet, we didn't do any sound + S_StartSound(source, sfx_khitem); + } else S_StartSound(source, sfx_s1c9); // The only lost gameplay functionality with voices disabled @@ -1962,6 +2015,33 @@ void K_PlayPowerGloatSound(mobj_t *source) K_RegularVoiceTimers(source->player); } +static void K_HandleDelayedHitByEm(player_t *player) +{ + if (player->hitemtimer == 0) + { + return; + } + + player->hitemtimer--; + + if (player->hitemtimer == 0) + { + mobj_t *victim = NULL; + + if (player->hitemvictim < MAXPLAYERS && playeringame[player->hitemvictim]) + { + player_t *victimPlayer = &players[player->hitemvictim]; + + if (victimPlayer != NULL && victimPlayer->spectator == false) + { + victim = victimPlayer->mo; + } + } + + K_PlayGenericCombatSound(player->mo, victim, sfx_khitem); + } +} + void K_MomentumToFacing(player_t *player) { angle_t dangle = player->mo->angle - R_PointToAngle2(0, 0, player->mo->momx, player->mo->momy); @@ -2233,6 +2313,7 @@ void K_SpinPlayer(player_t *player, mobj_t *source, INT32 type, mobj_t *inflicto // PS: Inflictor is unused for all purposes here and is actually only ever relevant to Lua. It may be nil too. boolean force = false; // Used to check if Lua ShouldSpin should get us damaged reguardless of flashtics or heck knows what. UINT8 shouldForce = LUAh_ShouldSpin(player, inflictor, source); + if (P_MobjWasRemoved(player->mo)) return; // mobj was removed (in theory that shouldn't happen) if (shouldForce == 1) @@ -2240,6 +2321,8 @@ void K_SpinPlayer(player_t *player, mobj_t *source, INT32 type, mobj_t *inflicto else if (shouldForce == 2) return; + K_DirectorFollowAttack(player, inflictor, source); + if (!trapitem && G_BattleGametype()) { if (K_IsPlayerWanted(player)) @@ -2266,7 +2349,7 @@ void K_SpinPlayer(player_t *player, mobj_t *source, INT32 type, mobj_t *inflicto return; if (source && source != player->mo && source->player) - K_PlayHitEmSound(source); + K_PlayHitEmSound(source, player->mo); //player->kartstuff[k_sneakertimer] = 0; player->kartstuff[k_driftboost] = 0; @@ -2466,7 +2549,7 @@ void K_SquishPlayer(player_t *player, mobj_t *source, mobj_t *inflictor) if (player->mo->state != &states[S_KART_SQUISH]) // Squash P_SetPlayerMobjState(player->mo, S_KART_SQUISH); - P_PlayRinglossSound(player->mo); + P_PlayRinglossSound(player->mo, source); player->kartstuff[k_instashield] = 15; if (cv_kartdebughuddrop.value && !modeattacking) @@ -2490,6 +2573,8 @@ void K_ExplodePlayer(player_t *player, mobj_t *source, mobj_t *inflictor) // A b else if (shouldForce == 2) return; + K_DirectorFollowAttack(player, inflictor, source); + if (G_BattleGametype()) { if (K_IsPlayerWanted(player)) @@ -2516,7 +2601,7 @@ void K_ExplodePlayer(player_t *player, mobj_t *source, mobj_t *inflictor) // A b return; if (source && source != player->mo && source->player) - K_PlayHitEmSound(source); + K_PlayHitEmSound(source, player->mo); player->kartstuff[k_sneakertimer] = 0; player->kartstuff[k_driftboost] = 0; @@ -2597,7 +2682,7 @@ void K_ExplodePlayer(player_t *player, mobj_t *source, mobj_t *inflictor) // A b if (player->mo->state != &states[S_KART_SPIN]) P_SetPlayerMobjState(player->mo, S_KART_SPIN); - P_PlayRinglossSound(player->mo); + P_PlayRinglossSound(player->mo, source); if (P_IsLocalPlayer(player)) { @@ -4406,6 +4491,7 @@ static void K_MoveHeldObjects(player_t *player) if (!player->mo->hnext) { player->kartstuff[k_bananadrag] = 0; + if (player->kartstuff[k_eggmanheld]) player->kartstuff[k_eggmanheld] = 0; else if (player->kartstuff[k_itemheld]) @@ -4421,6 +4507,7 @@ static void K_MoveHeldObjects(player_t *player) // we need this here too because this is done in afterthink - pointers are cleaned up at the START of each tic... P_SetTarget(&player->mo->hnext, NULL); player->kartstuff[k_bananadrag] = 0; + if (player->kartstuff[k_eggmanheld]) player->kartstuff[k_eggmanheld] = 0; else if (player->kartstuff[k_itemheld]) @@ -4915,23 +5002,14 @@ static void K_UpdateEngineSounds(player_t *player, ticcmd_t *cmd) static void K_UpdateInvincibilitySounds(player_t *player) { INT32 sfxnum = sfx_None; + boolean localplayer = P_IsLocalPlayer(player); - if (player->mo->health > 0 && !P_IsLocalPlayer(player)) + if (player->mo->health > 0) { - if (cv_kartinvinsfx.value) - { - if (player->kartstuff[k_growshrinktimer] > 0) // Prioritize Grow - sfxnum = sfx_alarmg; - else if (player->kartstuff[k_invincibilitytimer] > 0) - sfxnum = sfx_alarmi; - } - else - { - if (player->kartstuff[k_growshrinktimer] > 0) - sfxnum = sfx_kgrow; - else if (player->kartstuff[k_invincibilitytimer] > 0) - sfxnum = sfx_kinvnc; - } + if (player->kartstuff[k_growshrinktimer] > 0 && (!localplayer || cv_growmusic.value == 2)) // Prioritize Grow + sfxnum = cv_kartinvinsfx.value ? sfx_alarmg : sfx_kgrow; + else if (player->kartstuff[k_invincibilitytimer] > 0 && (!localplayer || cv_supermusic.value == 2)) + sfxnum = cv_kartinvinsfx.value ? sfx_alarmi : sfx_kinvnc; } if (sfxnum != sfx_None && !S_SoundPlaying(player->mo, sfxnum)) @@ -5276,6 +5354,9 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) // Roulette Code K_KartItemRoulette(player, cmd); + // Used when karthitemdialog is On + K_HandleDelayedHitByEm(player); + // Handle invincibility sfx K_UpdateInvincibilitySounds(player); // Also thanks, VAda! @@ -5993,7 +6074,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground) P_SetScale(overlay, player->mo->scale); } player->kartstuff[k_invincibilitytimer] = itemtime+(2*TICRATE); // 10 seconds - if (P_IsLocalPlayer(player) && cv_supermusic.value && cv_birdmusic.value) + if (P_IsLocalPlayer(player) && cv_supermusic.value == 1 && cv_birdmusic.value) S_ChangeMusicSpecial("kinvnc"); else S_StartSound(player->mo, (cv_kartinvinsfx.value ? sfx_alarmi : sfx_kinvnc)); @@ -6198,7 +6279,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground) if (cv_kartdebugshrink.value && !modeattacking && !player->bot) player->mo->destscale = (6*player->mo->destscale)/8; player->kartstuff[k_growshrinktimer] = itemtime+(4*TICRATE); // 12 seconds - if (P_IsLocalPlayer(player) && cv_growmusic.value && cv_birdmusic.value ) + if (P_IsLocalPlayer(player) && cv_growmusic.value == 1 && cv_birdmusic.value ) S_ChangeMusicSpecial("kgrow"); else S_StartSound(player->mo, (cv_kartinvinsfx.value ? sfx_alarmg : sfx_kgrow)); @@ -7507,55 +7588,55 @@ static void K_initKartHUD(void) if (splitscreen) // Splitscreen { - ITEM_X = 5 + cv_item_xoffset.value; - ITEM_Y = 3 + cv_item_yoffset.value; + ITEM_X = 5; + ITEM_Y = 3; - LAPS_Y = (BASEVIDHEIGHT/2)-24 + cv_laps_yoffset.value; + LAPS_Y = (BASEVIDHEIGHT/2)-24; - POSI_Y = (BASEVIDHEIGHT/2)- 2 + cv_posi_yoffset.value; + POSI_Y = (BASEVIDHEIGHT/2)- 2; - STCD_Y = BASEVIDHEIGHT/4 + cv_stcd_yoffset.value; + STCD_Y = BASEVIDHEIGHT/4; - MINI_Y = (BASEVIDHEIGHT/2) + cv_mini_yoffset.value; + MINI_Y = (BASEVIDHEIGHT/2); if (splitscreen > 1) // 3P/4P Small Splitscreen { // 1P (top left) - ITEM_X = -9 + cv_item_xoffset.value; - ITEM_Y = -8 + cv_item_yoffset.value; + ITEM_X = -9; + ITEM_Y = -8; - LAPS_X = 3 + cv_laps_xoffset.value; - LAPS_Y = (BASEVIDHEIGHT/2)-13 + cv_laps_yoffset.value; + LAPS_X = 3; + LAPS_Y = (BASEVIDHEIGHT/2)-13; - POSI_X = 24 + cv_posi_xoffset.value; - POSI_Y = (BASEVIDHEIGHT/2)- 16 + cv_posi_yoffset.value; + POSI_X = 24; + POSI_Y = (BASEVIDHEIGHT/2)- 16; // 2P (top right) - ITEM2_X = BASEVIDWIDTH-39 + cv_item_xoffset.value; - ITEM2_Y = -8 + cv_item_yoffset.value; + ITEM2_X = BASEVIDWIDTH-39; + ITEM2_Y = -8; - LAPS2_X = BASEVIDWIDTH-3 + cv_laps_xoffset.value; - LAPS2_Y = (BASEVIDHEIGHT/2)-13 + cv_laps_yoffset.value; + LAPS2_X = BASEVIDWIDTH-3; + LAPS2_Y = (BASEVIDHEIGHT/2)-13; - POSI2_X = BASEVIDWIDTH -4 + cv_posi_xoffset.value; - POSI2_Y = (BASEVIDHEIGHT/2)- 16 + cv_posi_yoffset.value; + POSI2_X = BASEVIDWIDTH -4; + POSI2_Y = (BASEVIDHEIGHT/2)- 16; // Reminder that 3P and 4P are just 1P and 2P splitscreen'd to the bottom. - STCD_X = BASEVIDWIDTH/4 + cv_stcd_xoffset.value; + STCD_X = BASEVIDWIDTH/4; - MINI_X = (3*BASEVIDWIDTH/4) + cv_mini_xoffset.value; - MINI_Y = (3*BASEVIDHEIGHT/4) + cv_mini_yoffset.value; + MINI_X = (3*BASEVIDWIDTH/4); + MINI_Y = (3*BASEVIDHEIGHT/4); if (splitscreen > 2) // 4P-only { - MINI_X = (BASEVIDWIDTH/2) + cv_mini_xoffset.value; - MINI_Y = (BASEVIDHEIGHT/2) + cv_mini_yoffset.value; + MINI_X = (BASEVIDWIDTH/2); + MINI_Y = (BASEVIDHEIGHT/2); } } } - if (timeinmap > 113) + if (timeinmap > 113 || forceshowhud) hudtrans = cv_translucenthud.value; else if (timeinmap > 105) hudtrans = ((((INT32)timeinmap) - 105)*cv_translucenthud.value)/(113-105); @@ -7710,49 +7791,6 @@ static void K_drawKartStats(void) if (!LUA_HudEnabled(hud_statdisplay)) return; - - // I tried my best, but this is still mess :/ - if (splitscreen) - { - if (splitscreen == 1) - { - // If we are in 2-player splitscreen, for player 1 we move hud to up and remove snapping - // to bottom - if (splitnum == 0) - { - y /= 2; - flags = V_SNAPTOLEFT; - } - else - { - // Can move it down a bit - y += 20; - } - } - else - { - // In 4-player splitscreen... - flags = 0; - - // ...For players 2 and 4, which are at right side, we move x coordinate... - if (splitnum == 1 || splitnum == 3) - x += BASEVIDWIDTH/2; - // ...Else, for players on left side we can snap position to left... - else - flags |= V_SNAPTOLEFT; - - // ...For players 1 and 2, which are at top side, we move y coordinate... - if (splitnum == 0 || splitnum == 1) - y /= 2; - // ...Else, for players on bottom side we can snap position to bottom - else - { - flags |= V_SNAPTOBOTTOM; - // Can move it down a bit - y += 20; - } - } - } //Internal offset for speedometer if (cv_kartspeedometer.value) @@ -7764,10 +7802,49 @@ static void K_drawKartStats(void) } else spdoffset = 0; - + // Customizations c: - x += 18 + cv_stat_xoffset.value; - y += cv_stat_yoffset.value + (G_BattleGametype() ? (stplyr->kartstuff[k_bumper] ? -5 : -8) : 0) + spdoffset; + if (!splitscreen) + { + x += 18 + cv_stat_xoffset.value; + y += cv_stat_yoffset.value + (G_BattleGametype() ? (stplyr->kartstuff[k_bumper] ? -5 : -8) : 0) + spdoffset; + } + else if (splitscreen == 1) // I tried my best, but this is still mess :/ < :Blobcatpats: c: + { + x -= 10; + y -= 40; + y += (G_BattleGametype() ? (stplyr->kartstuff[k_bumper] ? -5 : -8) : 0); + + // If we are in 2-player splitscreen, for player 1 we move hud to up and remove snapping + // to bottom + if (splitnum == 0) + { + y /= 2; + flags = V_SNAPTOLEFT; + } + else + { + // Can move it down a bit + y += 45; + } + } + else + { + if (splitnum == 0 || splitnum == 2) // If we are P1 or P3... + { + // ye i just align it to position number lol + x = POSI_X + 19; + y = POSI_Y - 6; + flags = V_SNAPTOLEFT|((splitnum == 2) ? V_SPLITSCREEN|V_SNAPTOBOTTOM : 0); // flip P3 to the bottom. + } + else // else, that means we're P2 or P4. + { + x = POSI2_X - 75; + y = POSI2_Y - 6; + flags = V_SNAPTORIGHT|((splitnum == 3) ? V_SPLITSCREEN|V_SNAPTOBOTTOM : 0); // flip P4 to the bottom + } + } + flags |= V_HUDTRANS; skin_t *fakeskin; @@ -8111,8 +8188,6 @@ void K_drawKartTimestamp(tic_t drawtime, INT32 TX, INT32 TY, INT16 emblemmap, UI { // TIME_X = BASEVIDWIDTH-124; // 196 // TIME_Y = 6; // 6 - - tic_t worktime; INT32 splitflags = 0; if (!mode) @@ -8137,63 +8212,51 @@ void K_drawKartTimestamp(tic_t drawtime, INT32 TX, INT32 TY, INT16 emblemmap, UI TX += 33; - worktime = drawtime/(60*TICRATE); - - if (mode && !drawtime) - V_DrawKartString(TX, TY+3, splitflags, va("--'--\"--")); - else if (worktime < 100) // 99:99:99 only + if (drawtime == UINT32_MAX) + ; + else if (mode && !drawtime) { - if ((cv_timelimit.value && G_BattleGametype()) && (!players[consoleplayer].exiting && (leveltime > (timelimitintics + starttime + TICRATE/2)) && cv_overtime.value)) // i hate this so much - { - V_DrawKartString(TX, TY+3, splitflags, va("OVERTIME")); - return; - } - - // zero minute - if (worktime < 10) - { - V_DrawKartString(TX, TY+3, splitflags, va("0")); - // minutes time 0 __ __ - V_DrawKartString(TX+12, TY+3, splitflags, va("%d", worktime)); - } - // minutes time 0 __ __ - else - V_DrawKartString(TX, TY+3, splitflags, va("%d", worktime)); - // apostrophe location _'__ __ V_DrawKartString(TX+24, TY+3, splitflags, va("'")); - worktime = (drawtime/TICRATE % 60); - - // zero second _ 0_ __ - if (worktime < 10) - { - V_DrawKartString(TX+36, TY+3, splitflags, va("0")); - // seconds time _ _0 __ - V_DrawKartString(TX+48, TY+3, splitflags, va("%d", worktime)); - } - // zero second _ 00 __ - else - V_DrawKartString(TX+36, TY+3, splitflags, va("%d", worktime)); - // quotation mark location _ __"__ V_DrawKartString(TX+60, TY+3, splitflags, va("\"")); - - worktime = G_TicsToCentiseconds(drawtime); - - // zero tick _ __ 0_ - if (worktime < 10) - { - V_DrawKartString(TX+72, TY+3, splitflags, va("0")); - // tics _ __ _0 - V_DrawKartString(TX+84, TY+3, splitflags, va("%d", worktime)); - } - // zero tick _ __ 00 - else - V_DrawKartString(TX+72, TY+3, splitflags, va("%d", worktime)); } - else if ((drawtime/TICRATE) & 1) - V_DrawKartString(TX, TY+3, splitflags, va("99'59\"99")); + else + { + tic_t worktime = drawtime/(60*TICRATE); + + if ((G_BattleGametype() && cv_timelimit.value) && (!players[consoleplayer].exiting && (leveltime > (timelimitintics + starttime + TICRATE/2)) && cv_overtime.value)) // i hate this so much + { + V_DrawKartString(TX, TY+3, splitflags, va("OVERTIME")); + } + else if (worktime < 100) + { + // minutes time 00 __ __ + V_DrawKartString(TX, TY+3, splitflags, va("%d", worktime/10)); + V_DrawKartString(TX+12, TY+3, splitflags, va("%d", worktime%10)); + + // apostrophe location _'__ __ + V_DrawKartString(TX+24, TY+3, splitflags, va("'")); + + worktime = (drawtime/TICRATE % 60); + + // seconds time _ 00 __ + V_DrawKartString(TX+36, TY+3, splitflags, va("%d", worktime/10)); + V_DrawKartString(TX+48, TY+3, splitflags, va("%d", worktime%10)); + + // quotation mark location _ __"__ + V_DrawKartString(TX+60, TY+3, splitflags, va("\"")); + + worktime = G_TicsToCentiseconds(drawtime); + + // tics _ __ 00 + V_DrawKartString(TX+72, TY+3, splitflags, va("%d", worktime/10)); + V_DrawKartString(TX+84, TY+3, splitflags, va("%d", worktime%10)); + } + else if ((drawtime/TICRATE) & 1) + V_DrawKartString(TX, TY+3, splitflags, va("99'59\"99")); + } if (emblemmap && (modeattacking || (mode == 1)) && !demo.playback) // emblem time! { @@ -8707,7 +8770,7 @@ static void K_drawKartLaps(void) else V_DrawMappedPatch(fx, fy, V_HUDTRANS|splitflags, kp_lapstickerclr, colormap); } - + if (stplyr->exiting) V_DrawKartString(fx+33, fy+3, V_HUDTRANS|splitflags, "FIN"); else @@ -8722,7 +8785,7 @@ static void K_drawKartSpeedometer(void) return; fixed_t convSpeed = 0; - + //KartZ speedo fixed_t fuspeed = 0; INT32 spdpatch = 0; @@ -8860,6 +8923,14 @@ static void K_drawKartBumpersOrKarma(void) fy = info.y; fflags = info.flags; + if (cv_battlespeedo.value && !splitscreen) + { + if ((cv_newspeedometer.value == 2 && xtra_speedo) || (cv_newspeedometer.value == 3 && achi_speedo) || (cv_newspeedometer.value == 5 && xtra_speedo3)) + fy += 5; + else + fy += 7; + } + if (splitscreen > 1) { if (stplyr->kartstuff[k_bumper] <= 0) @@ -8996,11 +9067,11 @@ static boolean K_GetScreenCoords(vector2_t *vec, player_t *player, mobj_t *targe offset = FixedMul(FINETANGENT(((aimingangle+ANGLE_90)>>ANGLETOFINESHIFT) & 4095), xres); // this isn't fovtan... what am i even doing anymore if (splitscreen == 1) - offset = 17*offset/10; - // OpenGL with software perspective is miscentered on non-16:10 resolutions + offset = 17*offset/120; #ifdef HWRENDER - if (rendermode == render_opengl) - offset = FixedMul(offset, FixedDiv(104857, FixedDiv(xres, yres))); + // OpenGL with software perspective is miscentered on non-16:10 resolutions + //if (rendermode == render_opengl) + //offset = FixedMul(offset, FixedDiv(104857, FixedDiv(xres, yres))); #endif // thanks fickle offset = FixedDiv(offset, fovratio); @@ -9023,12 +9094,14 @@ static boolean K_GetScreenCoords(vector2_t *vec, player_t *player, mobj_t *targe int splitindex = stplyrnum; // adjust coords for splitscreen - if (splitscreen == 1){ // 2P + if (splitscreen == 1) // 2P + { y = y>>1; if (splitindex) y = y + yres; } - if (splitscreen >= 2) { // 3P or 4P + if (splitscreen >= 2) // 3P or 4P + { x = x>>1; y = y>>1; if (splitindex & 1) @@ -9297,9 +9370,17 @@ static void K_drawDriftGauge(void) 0, 31, 47, 63, 79, 95, 111, 119, 127, 143, 159, 175, 183, 191, 199, 207, 223, 247 }; - if (!stplyr->mo || !stplyr->kartstuff[k_drift] || (!splitscreen && !camera->chase)) + if (!stplyr->mo || (!splitscreen && !camera->chase)) return; + if (forceshowhud) + goto skipcrap; // i will skip the drift early return and you cant stop me! + + if (!stplyr->kartstuff[k_drift]) + return; + +skipcrap: + if (!K_GetScreenCoords(&pos, stplyr, stplyr->mo, FixedMul(cv_driftgaugeofs.value, cv_driftgaugeofs.value > 0 ? stplyr->mo->scale : mapobjectscale), false)) return; @@ -9352,9 +9433,7 @@ static void K_drawDriftGauge(void) { cmap = R_GetTranslationColormap(TC_RAINBOW, 1 + leveltime % (MAXSKINCOLORS-1),GTC_CACHE); for (i = 0; i < 4; i++) - { - V_DrawFill(barx, bary+dup*1+dup*i, BAR_WIDTH, dup, (driftrainbow[(leveltime % 18) + 1] + i*2) | V_NOSCALESTART|drifttrans); - } + V_DrawFill(barx, bary+dup*1+dup*i, BAR_WIDTH, dup, (driftrainbow[min((leveltime % 18) + 1, 18 - 1)] + i*2) | V_NOSCALESTART|drifttrans); } else // none/blue/red { @@ -9679,7 +9758,9 @@ static void K_drawKartMinimap(void) splitflags = info.flags; - if (timeinmap > 105) + if (forceshowhud) + minimaptrans = cv_kartminimap.value; + else if (timeinmap > 105) { minimaptrans = cv_kartminimap.value; if (timeinmap <= 113) @@ -10492,9 +10573,27 @@ void K_drawKartHUD(void) // If not splitscreen, draw... if (!splitscreen && !demo.title) { + tic_t realtime = stplyr->realtime; + + if (cv_showlaptimes.value + && stplyr->kartstuff[k_lapanimation] + && !stplyr->exiting + && stplyr->laptime[LAP_LAST] != 0 + && !midgamejoin) + { + if ((stplyr->kartstuff[k_lapanimation] / 5) & 1) + { + realtime = stplyr->laptime[LAP_LAST]; + } + else + { + realtime = UINT32_MAX; + } + } + // Draw the timestamp if (LUA_HudEnabled(hud_time)) - K_drawKartTimestamp(stplyr->realtime, TIME_X, TIME_Y, gamemap, 0); + K_drawKartTimestamp(realtime, TIME_X, TIME_Y, gamemap, 0); if (!modeattacking) { @@ -10521,6 +10620,7 @@ void K_drawKartHUD(void) if (demo.title) // Draw title logo instead in demo.titles { INT32 x = (BASEVIDWIDTH - 32)*FRACUNIT, y = 128*FRACUNIT, offs; + INT32 logoflags = V_SNAPTORIGHT|V_SNAPTOBOTTOM; if (splitscreen == 3) { @@ -10539,8 +10639,8 @@ void K_drawKartHUD(void) x += offs - frac; } - V_DrawSciencePatch(x - (54*FRACUNIT), y, 0, W_CachePatchName("TTKBANNR", PU_CACHE), FRACUNIT/4); - V_DrawSciencePatch(x - (54*FRACUNIT), y + (25*FRACUNIT), 0, W_CachePatchName("TTKART", PU_CACHE), FRACUNIT/4); + V_DrawSciencePatch(x - (54*FRACUNIT), y, logoflags, W_CachePatchName("TTKBANNR", PU_CACHE), FRACUNIT/4); + V_DrawSciencePatch(x - (54*FRACUNIT), y + (25*FRACUNIT), logoflags, W_CachePatchName("TTKART", PU_CACHE), FRACUNIT/4); } else if (G_RaceGametype()) // Race-only elements { @@ -10636,6 +10736,9 @@ void K_drawKartHUD(void) if (cv_kartdebugcheckpoint.value) K_drawCheckpointDebugger(); + if (cv_kartdebugdirector.value) + K_DrawDirectorDebugger(); + if (cv_kartdebugnodes.value) { UINT8 p; diff --git a/src/k_kart.h b/src/k_kart.h index 06195280d..647ae3bf0 100644 --- a/src/k_kart.h +++ b/src/k_kart.h @@ -31,6 +31,7 @@ extern consvar_t cv_highresportrait; extern consvar_t cv_stat_xoffset; extern consvar_t cv_stat_yoffset; extern consvar_t cv_showstats; +extern consvar_t cv_showlaptimes; extern consvar_t cv_battlespeedo; #define NUMSPEEDOSTUFF 6 @@ -91,7 +92,7 @@ void K_UpdateSpectateGrief(void); void K_PlayAttackTaunt(mobj_t *source); void K_PlayBoostTaunt(mobj_t *source); void K_PlayOvertakeSound(mobj_t *source); -void K_PlayHitEmSound(mobj_t *source); +void K_PlayHitEmSound(mobj_t *source, mobj_t *victim); void K_PlayPowerGloatSound(mobj_t *source); const char *K_GetItemPatch(UINT8 item, boolean tiny); diff --git a/src/lua_baselib.c b/src/lua_baselib.c index be561e7ba..3fbfd463d 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -20,6 +20,7 @@ #include "m_random.h" #include "s_sound.h" #include "g_game.h" +#include "g_input.h" #include "hu_stuff.h" // HU_AddChatText #include "console.h" #include "k_kart.h" // SRB2Kart @@ -1258,6 +1259,7 @@ static int lib_pPlayRinglossSound(lua_State *L) { mobj_t *source = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ)); player_t *player = NULL; + mobj_t *damager = NULL; NOHUD if (!source) return LUA_ErrInvalid(L, "mobj_t"); @@ -1267,8 +1269,15 @@ static int lib_pPlayRinglossSound(lua_State *L) if (!player) return LUA_ErrInvalid(L, "player_t"); } + if (!lua_isnoneornil(L, 3)) + { + damager = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ)); + + if (!damager) + return LUA_ErrInvalid(L, "mobj_t"); + } if (!player || P_IsLocalPlayer(player)) - P_PlayRinglossSound(source); + P_PlayRinglossSound(source, damager); return 0; } @@ -2556,10 +2565,22 @@ static int lib_kOvertakeSound(lua_State *L) static int lib_kHitEmSound(lua_State *L) { mobj_t *mobj = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ)); + mobj_t *victim = NULL; + + if (!lua_isnoneornil(L, 2)) + { + victim = *((mobj_t **)luaL_checkudata(L, 2, META_MOBJ)); + if (!victim) + return LUA_ErrInvalid(L, "mobj_t"); + } + NOHUD if (!mobj->player) return luaL_error(L, "K_PlayHitEmSound: mobj_t isn't a player object."); //Nothing bad would happen if we let it run the func, but telling why it ain't doing anything is helpful. - K_PlayHitEmSound(mobj); + if (victim && !victim->player) + return luaL_error(L, "K_PlayHitEmSound: mobj_t isn't a player object."); //Same as above + + K_PlayHitEmSound(mobj, victim); return 0; } @@ -3000,6 +3021,58 @@ static int lib_kSetHyuCountdown(lua_State *L) return 0; } +// G_INPUT +//////////// + +static int lib_gSetPlayerGamepadIndicatorColor(lua_State *L) +{ + INT32 player = -1; + player_t *plr = *((player_t **)luaL_checkudata(L, 1, META_PLAYER)); // retrieve player + UINT16 color = (UINT16)luaL_checkinteger(L, 2); // skincolor + + for (int i = 0; i < MAXSPLITSCREENPLAYERS; ++i) + { + if (plr - players == displayplayers[i]) + { + player = i; + break; + } + } + + // Not a local player + if (player == -1) return 0; + + // pls update with color 0 when youre done with changing led stuff so it can get player color again + G_SetPlayerGamepadIndicatorColor(player, color); + + return 0; +} + +static int lib_gPlayerDeviceRumble(lua_State *L) +{ + INT32 player = -1; + player_t *plr = *((player_t **)luaL_checkudata(L, 1, META_PLAYER)); // retrieve player + UINT16 low_strength = (UINT16)luaL_checkinteger(L, 2); // low frequency rumble motor strenght + UINT16 high_strength = (UINT16)luaL_checkinteger(L, 3); // high frequency rumble motor strenght + UINT32 duration = (UINT32)luaL_optinteger(L, 4, 84); // duration of rumble in ms + + for (int i = 0; i < MAXSPLITSCREENPLAYERS; ++i) + { + if (plr - players == displayplayers[i]) + { + player = i; + break; + } + } + + // Not a local player + if (player == -1) return 0; + + G_PlayerDeviceRumble(player, low_strength, high_strength, duration); + + return 0; +} + static luaL_Reg lib[] = { {"print", lib_print}, {"chatprint", lib_chatprint}, @@ -3247,6 +3320,10 @@ static luaL_Reg lib[] = { {"K_SetIndirectItemCooldown",lib_kSetIndirectItemCountdown}, {"K_SetHyudoroCooldown",lib_kSetHyuCountdown}, + //g_input + {"G_SetPlayerGamepadIndicatorColor",lib_gSetPlayerGamepadIndicatorColor}, + {"G_PlayerDeviceRumble",lib_gPlayerDeviceRumble}, + {NULL, NULL} }; @@ -3266,4 +3343,4 @@ int LUA_BaseLib(lua_State *L) lua_pushvalue(L, LUA_GLOBALSINDEX); luaL_register(L, NULL, lib); return 0; -} \ No newline at end of file +} diff --git a/src/lua_consolelib.c b/src/lua_consolelib.c index 7d9cd67ec..3e70ce008 100644 --- a/src/lua_consolelib.c +++ b/src/lua_consolelib.c @@ -453,9 +453,11 @@ static int lib_cvRegisterVar(lua_State *L) if (!(((cvar->flags & CV_HIDEN)) || (cvar->flags & CV_NOSHOWHELP)) && (cvar->PossibleValue || !(cvar->value == 0 && stricmp(cvar->string, "0")))) { + char *temp = NULL; + if (!category) { - char *temp = strdup(wadfiles[numwadfiles - 1]->filename); + temp = strdup(wadfiles[numwadfiles - 1]->filename); nameonly(temp); category = temp; @@ -465,6 +467,8 @@ static int lib_cvRegisterVar(lua_State *L) M_SlotCvarIntoModMenu(cvar, category, menu_name); else M_SlotCvarIntoModMenu(cvar, category, cvar->name); + + free (temp); } // return cvar userdata @@ -580,27 +584,59 @@ static luaL_Reg lib[] = { {NULL, NULL} }; +enum cvar_e +{ + cvar_name, + cvar_defaultvalue, + cvar_flags, + cvar_value, + cvar_string, + cvar_changed, +}; + +static const char *const cvar_opt[] = { + "name", + "defaultvalue", + "flags", + "value", + "string", + "changed", + NULL, +}; + +static int cvar_fields_ref = LUA_NOREF; + static int cvar_get(lua_State *L) { consvar_t *cvar = (consvar_t *)luaL_checkudata(L, 1, META_CVAR); - const char *field = luaL_checkstring(L, 2); + enum cvar_e field = Lua_optoption(L, 2, -1, cvar_fields_ref); - if(fastcmp(field,"name")) + switch (field) + { + case cvar_name: lua_pushstring(L, cvar->name); - else if(fastcmp(field,"defaultvalue")) + break; + case cvar_defaultvalue: lua_pushstring(L, cvar->defaultvalue); - else if(fastcmp(field,"flags")) + break; + case cvar_flags: lua_pushinteger(L, cvar->flags); - else if(fastcmp(field,"value")) + break; + case cvar_value: lua_pushinteger(L, cvar->value); - else if(fastcmp(field,"string")) + break; + case cvar_string: lua_pushstring(L, cvar->string); - else if(fastcmp(field,"changed")) + break; + case cvar_changed: lua_pushboolean(L, cvar->changed); - else if (devparm) - return luaL_error(L, LUA_QL("consvar_t") " has no field named " LUA_QS, field); - else - return 0; + break; + default: + if (devparm) + return luaL_error(L, LUA_QL("consvar_t") " has no field named " LUA_QS, field); + else + return 0; + } return 1; } @@ -612,6 +648,8 @@ int LUA_ConsoleLib(lua_State *L) lua_setfield(L, -2, "__index"); lua_pop(L,1); + cvar_fields_ref = Lua_CreateFieldTable(L, cvar_opt); + // Set empty registry tables lua_newtable(L); lua_setfield(L, LUA_REGISTRYINDEX, "COM_Command"); diff --git a/src/lua_hook.h b/src/lua_hook.h index 14270dea5..921336cd2 100644 --- a/src/lua_hook.h +++ b/src/lua_hook.h @@ -55,6 +55,7 @@ enum hook { hook_PlayerCmd, //SRB2KART hook_IntermissionThinker, //SRB2KART hook_VoteThinker, //SRB2KART + hook_ServerJoin, // SRB2KART - Saturn 32p hook_MAX // last hook }; @@ -106,8 +107,10 @@ boolean LUAh_PlayerSpin(player_t *player, mobj_t *inflictor, mobj_t *source); // boolean LUAh_PlayerExplode(player_t *player, mobj_t *inflictor, mobj_t *source); // SRB2KART: Hook for K_ExplodePlayer. Allows Lua to execute code and/or overwrite its behavior. boolean LUAh_PlayerSquish(player_t *player, mobj_t *inflictor, mobj_t *source); // SRB2KART: Hook for K_SquishPlayer. Allows Lua to execute code and/or overwrite its behavior. +void LUAh_ServerJoin(void); // SRB2KART - Saturn 32p: called by client when joining a server, allows lua to load any sort of config file + boolean LUAh_PlayerCmd(player_t *player, ticcmd_t *cmd); // Allows to write to player cmd before the game does anything with them. void LUAh_IntermissionThinker(void); // Hook for Y_Ticker void LUAh_VoteThinker(void); // Hook for Y_VoteTicker -#define LUAh_PlayerThink(player) LUAh_PlayerHook(player, hook_PlayerThink) // Hook for P_PlayerThink \ No newline at end of file +#define LUAh_PlayerThink(player) LUAh_PlayerHook(player, hook_PlayerThink) // Hook for P_PlayerThink diff --git a/src/lua_hooklib.c b/src/lua_hooklib.c index a1ea4fdaf..1aadea9a3 100644 --- a/src/lua_hooklib.c +++ b/src/lua_hooklib.c @@ -68,6 +68,7 @@ const char *const hookNames[hook_MAX+1] = { "PlayerCmd", "IntermissionThinker", "VoteThinker", + "ServerJoin", NULL }; @@ -86,8 +87,6 @@ struct hook_s }; typedef struct hook_s* hook_p; -#define FMT_HOOKID "hook_%d" - // For each mobj type, a linked list to its thinker and collision hooks. // That way, we don't have to iterate through all the hooks. // We could do that with all other mobj hooks, but it would probably just be @@ -221,6 +220,7 @@ static int lib_addHook(lua_State *L) case hook_PlayerSpin: case hook_PlayerExplode: case hook_PlayerSquish: + case hook_ServerJoin: default: lastp = &roothook; break; @@ -237,9 +237,9 @@ static int lib_addHook(lua_State *L) *lastp = hookp; // set the hook function in the registry. - lua_pushfstring(L, FMT_HOOKID, hook.id); + lua_getfield(L, LUA_REGISTRYINDEX, "hooks"); lua_pushvalue(L, 1); - lua_settable(L, LUA_REGISTRYINDEX); + lua_rawseti(L, -2, hook.id); return 0; } @@ -248,6 +248,10 @@ int LUA_HookLib(lua_State *L) memset(hooksAvailable,0,sizeof(UINT8[(hook_MAX/8)+1])); roothook = NULL; lua_register(L, "addHook", lib_addHook); + + lua_newtable(L); + lua_setfield(L, LUA_REGISTRYINDEX, "hooks"); + return 0; } @@ -255,59 +259,66 @@ boolean LUAh_MobjHook(mobj_t *mo, enum hook which) { hook_p hookp; boolean hooked = false; + int HOOKSINDEX; if (!gL || !(hooksAvailable[which/8] & (1<<(which%8)))) return false; I_Assert(mo->type < NUMMOBJTYPES); - + if (!(mobjhooks[MT_NULL] || mobjhooks[mo->type])) return false; lua_settop(gL, 0); lua_pushcfunction(gL, LUA_GetErrorMessage); + lua_getfield(gL, LUA_REGISTRYINDEX, "hooks"); + HOOKSINDEX = lua_gettop(gL); + I_Assert(lua_istable(L, HOOKSINDEX)); + // Look for all generic mobj hooks for (hookp = mobjhooks[MT_NULL]; hookp; hookp = hookp->next) - if (hookp->type == which) - { - ps_lua_mobjhooks.value.i++; - if (lua_gettop(gL) == 1) - LUA_PushUserdata(gL, mo, META_MOBJ); - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); - lua_pushvalue(gL, -2); - if (lua_pcall(gL, 1, 1, 1)) { - if (!hookp->error || cv_debug & DBG_LUA) - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); - lua_pop(gL, 1); - hookp->error = true; - continue; - } - if (lua_toboolean(gL, -1)) - hooked = true; + { + if (hookp->type != which) + continue; + + ps_lua_mobjhooks.value.i++; + if (lua_gettop(gL) == 2) + LUA_PushUserdata(gL, mo, META_MOBJ); + lua_rawgeti(gL, HOOKSINDEX, hookp->id); + lua_pushvalue(gL, -2); + if (lua_pcall(gL, 1, 1, 1)) { + if (!hookp->error || cv_debug & DBG_LUA) + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); lua_pop(gL, 1); + hookp->error = true; + continue; } + if (lua_toboolean(gL, -1)) + hooked = true; + lua_pop(gL, 1); + } for (hookp = mobjhooks[mo->type]; hookp; hookp = hookp->next) - if (hookp->type == which) - { - ps_lua_mobjhooks.value.i++; - if (lua_gettop(gL) == 1) - LUA_PushUserdata(gL, mo, META_MOBJ); - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); - lua_pushvalue(gL, -2); - if (lua_pcall(gL, 1, 1, 1)) { - if (!hookp->error || cv_debug & DBG_LUA) - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); - lua_pop(gL, 1); - hookp->error = true; - continue; - } - if (lua_toboolean(gL, -1)) - hooked = true; + { + if (hookp->type != which) + continue; + + ps_lua_mobjhooks.value.i++; + if (lua_gettop(gL) == 2) + LUA_PushUserdata(gL, mo, META_MOBJ); + lua_rawgeti(gL, HOOKSINDEX, hookp->id); + lua_pushvalue(gL, -2); + if (lua_pcall(gL, 1, 1, 1)) { + if (!hookp->error || cv_debug & DBG_LUA) + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); lua_pop(gL, 1); + hookp->error = true; + continue; } + if (lua_toboolean(gL, -1)) + hooked = true; + lua_pop(gL, 1); + } lua_settop(gL, 0); return hooked; @@ -317,32 +328,38 @@ boolean LUAh_PlayerHook(player_t *plr, enum hook which) { hook_p hookp; boolean hooked = false; + int HOOKSINDEX; if (!gL || !(hooksAvailable[which/8] & (1<<(which%8)))) return false; lua_settop(gL, 0); lua_pushcfunction(gL, LUA_GetErrorMessage); + lua_getfield(gL, LUA_REGISTRYINDEX, "hooks"); + HOOKSINDEX = lua_gettop(gL); + I_Assert(lua_istable(L, HOOKSINDEX)); + for (hookp = playerhooks; hookp; hookp = hookp->next) - if (hookp->type == which) - { - ps_lua_mobjhooks.value.i++; - if (lua_gettop(gL) == 1) - LUA_PushUserdata(gL, plr, META_PLAYER); - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); - lua_pushvalue(gL, -2); - if (lua_pcall(gL, 1, 1, 1)) { - if (!hookp->error || cv_debug & DBG_LUA) - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); - lua_pop(gL, 1); - hookp->error = true; - continue; - } - if (lua_toboolean(gL, -1)) - hooked = true; + { + if (hookp->type != which) + continue; + + ps_lua_mobjhooks.value.i++; + if (lua_gettop(gL) == 2) + LUA_PushUserdata(gL, plr, META_PLAYER); + lua_rawgeti(gL, HOOKSINDEX, hookp->id); + lua_pushvalue(gL, -2); + if (lua_pcall(gL, 1, 1, 1)) { + if (!hookp->error || cv_debug & DBG_LUA) + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); lua_pop(gL, 1); + hookp->error = true; + continue; } + if (lua_toboolean(gL, -1)) + hooked = true; + lua_pop(gL, 1); + } lua_settop(gL, 0); return hooked; @@ -352,25 +369,32 @@ boolean LUAh_PlayerHook(player_t *plr, enum hook which) void LUAh_MapChange(INT16 mapnumber) { hook_p hookp; + int HOOKSINDEX; if (!gL || !(hooksAvailable[hook_MapChange/8] & (1<<(hook_MapChange%8)))) return; lua_settop(gL, 0); lua_pushcfunction(gL, LUA_GetErrorMessage); + + lua_getfield(gL, LUA_REGISTRYINDEX, "hooks"); + HOOKSINDEX = lua_gettop(gL); + I_Assert(lua_istable(L, HOOKSINDEX)); + lua_pushinteger(gL, mapnumber); for (hookp = roothook; hookp; hookp = hookp->next) - if (hookp->type == hook_MapChange) - { - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); - lua_pushvalue(gL, -2); - if (lua_pcall(gL, 1, 0, 1)) { + { + if (hookp->type != hook_MapChange) + continue; + + lua_rawgeti(gL, HOOKSINDEX, hookp->id); + lua_pushvalue(gL, -2); + if (lua_pcall(gL, 1, 0, 1)) { CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); lua_pop(gL, 1); - } } - + } + lua_settop(gL, 0); } @@ -378,24 +402,32 @@ void LUAh_MapChange(INT16 mapnumber) void LUAh_MapLoad(void) { hook_p hookp; + int HOOKSINDEX; if (!gL || !(hooksAvailable[hook_MapLoad/8] & (1<<(hook_MapLoad%8)))) return; lua_settop(gL, 0); lua_pushcfunction(gL, LUA_GetErrorMessage); + + lua_getfield(gL, LUA_REGISTRYINDEX, "hooks"); + HOOKSINDEX = lua_gettop(gL); + I_Assert(lua_istable(L, HOOKSINDEX)); + lua_pushinteger(gL, gamemap); for (hookp = roothook; hookp; hookp = hookp->next) - if (hookp->type == hook_MapLoad) - { - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); - lua_pushvalue(gL, -2); - if (lua_pcall(gL, 1, 0, 1)) { + { + if (hookp->type != hook_MapLoad) + continue; + + lua_rawgeti(gL, HOOKSINDEX, hookp->id); + lua_pushvalue(gL, -2); + if (lua_pcall(gL, 1, 0, 1)) { CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); lua_pop(gL, 1); - } } + } + lua_settop(gL, 0); } @@ -403,25 +435,32 @@ void LUAh_MapLoad(void) void LUAh_PlayerJoin(int playernum) { hook_p hookp; + int HOOKSINDEX; if (!gL || !(hooksAvailable[hook_PlayerJoin/8] & (1<<(hook_PlayerJoin%8)))) return; lua_settop(gL, 0); lua_pushcfunction(gL, LUA_GetErrorMessage); + + lua_getfield(gL, LUA_REGISTRYINDEX, "hooks"); + HOOKSINDEX = lua_gettop(gL); + I_Assert(lua_istable(L, HOOKSINDEX)); + lua_pushinteger(gL, playernum); for (hookp = roothook; hookp; hookp = hookp->next) - if (hookp->type == hook_PlayerJoin) - { - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); - lua_pushvalue(gL, -2); - if (lua_pcall(gL, 1, 0, 1)) { + { + if (hookp->type != hook_PlayerJoin) + continue; + + lua_rawgeti(gL, HOOKSINDEX, hookp->id); + lua_pushvalue(gL, -2); + if (lua_pcall(gL, 1, 0, 1)) { CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); lua_pop(gL, 1); - } } - + } + lua_settop(gL, 0); } @@ -429,49 +468,53 @@ void LUAh_PlayerJoin(int playernum) void LUAh_PreThinkFrame(void) { hook_p hookp; + int HOOKSINDEX; // variables used by perf stats int hook_index = 0; precise_t time_taken = 0; if (!gL || !(hooksAvailable[hook_PreThinkFrame/8] & (1<<(hook_PreThinkFrame%8)))) return; - + lua_pushcfunction(gL, LUA_GetErrorMessage); + lua_getfield(gL, LUA_REGISTRYINDEX, "hooks"); + HOOKSINDEX = lua_gettop(gL); + I_Assert(lua_istable(L, HOOKSINDEX)); + for (hookp = roothook; hookp; hookp = hookp->next) { - if (hookp->type == hook_PreThinkFrame) - { - if (cv_perfstats.value == 4) - time_taken = I_GetPreciseTime(); - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); - if (lua_pcall(gL, 0, 0, 1)) { - if (!hookp->error || cv_debug & DBG_LUA) - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); - lua_pop(gL, 1); - hookp->error = true; - } - if (cv_perfstats.value == 4) - { - lua_Debug ar; - time_taken = I_GetPreciseTime() - time_taken; - // we need the function, let's just retrieve it again - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); - lua_getinfo(gL, ">S", &ar); - PS_SetPreThinkFrameHookInfo(hook_index, time_taken, ar.short_src); - hook_index++; - } + if (hookp->type != hook_PreThinkFrame) + continue; + + if (cv_perfstats.value == 4) + time_taken = I_GetPreciseTime(); + lua_rawgeti(gL, HOOKSINDEX, hookp->id); + if (lua_pcall(gL, 0, 0, 1)) { + if (!hookp->error || cv_debug & DBG_LUA) + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); + lua_pop(gL, 1); + hookp->error = true; + } + if (cv_perfstats.value == 4) + { + lua_Debug ar; + time_taken = I_GetPreciseTime() - time_taken; + // we need the function, let's just retrieve it again + lua_rawgeti(gL, HOOKSINDEX, hookp->id); + lua_getinfo(gL, ">S", &ar); + PS_SetPreThinkFrameHookInfo(hook_index, time_taken, ar.short_src); + hook_index++; } - } - lua_pop(gL, 1); // Pop error handler + + lua_pop(gL, 2); // Pop error handler and hooks table } // Hook for frame (after mobj and player thinkers) void LUAh_ThinkFrame(void) { hook_p hookp; + int HOOKSINDEX; // variables used by perf stats int hook_index = 0; precise_t time_taken = 0; @@ -481,41 +524,44 @@ void LUAh_ThinkFrame(void) lua_pushcfunction(gL, LUA_GetErrorMessage); + lua_getfield(gL, LUA_REGISTRYINDEX, "hooks"); + HOOKSINDEX = lua_gettop(gL); + I_Assert(lua_istable(L, HOOKSINDEX)); + for (hookp = roothook; hookp; hookp = hookp->next) { - if (hookp->type == hook_ThinkFrame) + if (hookp->type != hook_ThinkFrame) + continue; + + if (cv_perfstats.value == 3) + time_taken = I_GetPreciseTime(); + lua_rawgeti(gL, HOOKSINDEX, hookp->id); + if (lua_pcall(gL, 0, 0, 1)) { + if (!hookp->error || cv_debug & DBG_LUA) + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); + lua_pop(gL, 1); + hookp->error = true; + } + if (cv_perfstats.value == 3) { - if (cv_perfstats.value == 3) - time_taken = I_GetPreciseTime(); - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); - if (lua_pcall(gL, 0, 0, 1)) { - if (!hookp->error || cv_debug & DBG_LUA) - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); - lua_pop(gL, 1); - hookp->error = true; - } - if (cv_perfstats.value == 3) - { - lua_Debug ar; - time_taken = I_GetPreciseTime() - time_taken; - // we need the function, let's just retrieve it again - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); - lua_getinfo(gL, ">S", &ar); - PS_SetThinkFrameHookInfo(hook_index, time_taken, ar.short_src); - hook_index++; - } + lua_Debug ar; + time_taken = I_GetPreciseTime() - time_taken; + // we need the function, let's just retrieve it again + lua_rawgeti(gL, HOOKSINDEX, hookp->id); + lua_getinfo(gL, ">S", &ar); + PS_SetThinkFrameHookInfo(hook_index, time_taken, ar.short_src); + hook_index++; } } - lua_pop(gL, 1); // Pop error handler + lua_pop(gL, 2); // Pop error handler and hooks table } // Hook for frame (at end of tick, ie after overlays, precipitation, specials) void LUAh_PostThinkFrame(void) { hook_p hookp; + int HOOKSINDEX; // variables used by perf stats int hook_index = 0; precise_t time_taken = 0; @@ -524,91 +570,101 @@ void LUAh_PostThinkFrame(void) lua_pushcfunction(gL, LUA_GetErrorMessage); + lua_getfield(gL, LUA_REGISTRYINDEX, "hooks"); + HOOKSINDEX = lua_gettop(gL); + I_Assert(lua_istable(L, HOOKSINDEX)); + for (hookp = roothook; hookp; hookp = hookp->next) { - if (hookp->type == hook_PostThinkFrame) + if (hookp->type != hook_PostThinkFrame) + continue; + + if (cv_perfstats.value == 5) + time_taken = I_GetPreciseTime(); + lua_rawgeti(gL, HOOKSINDEX, hookp->id); + if (lua_pcall(gL, 0, 0, 1)) { + if (!hookp->error || cv_debug & DBG_LUA) + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); + lua_pop(gL, 1); + hookp->error = true; + } + if (cv_perfstats.value == 5) { - if (cv_perfstats.value == 5) - time_taken = I_GetPreciseTime(); - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); - if (lua_pcall(gL, 0, 0, 1)) { - if (!hookp->error || cv_debug & DBG_LUA) - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); - lua_pop(gL, 1); - hookp->error = true; - } - if (cv_perfstats.value == 5) - { - lua_Debug ar; - time_taken = I_GetPreciseTime() - time_taken; - // we need the function, let's just retrieve it again - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); - lua_getinfo(gL, ">S", &ar); - PS_SetPostThinkFrameHookInfo(hook_index, time_taken, ar.short_src); - hook_index++; - } + lua_Debug ar; + time_taken = I_GetPreciseTime() - time_taken; + // we need the function, let's just retrieve it again + lua_rawgeti(gL, HOOKSINDEX, hookp->id); + lua_getinfo(gL, ">S", &ar); + PS_SetPostThinkFrameHookInfo(hook_index, time_taken, ar.short_src); + hook_index++; } } - lua_pop(gL, 1); // Pop error handler + lua_pop(gL, 2); // Pop error handler and hooks table } // Hook for Y_Ticker void LUAh_IntermissionThinker(void) { hook_p hookp; + int HOOKSINDEX; if (!gL || !(hooksAvailable[hook_IntermissionThinker/8] & (1<<(hook_IntermissionThinker%8)))) return; - lua_pushcfunction(gL, LUA_GetErrorMessage); + lua_pushcfunction(gL, LUA_GetErrorMessage);; + + lua_getfield(gL, LUA_REGISTRYINDEX, "hooks"); + HOOKSINDEX = lua_gettop(gL); + I_Assert(lua_istable(L, HOOKSINDEX)); for (hookp = roothook; hookp; hookp = hookp->next) { - if (hookp->type == hook_IntermissionThinker) - { - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); - if (lua_pcall(gL, 0, 0, 1)) { - if (!hookp->error || cv_debug & DBG_LUA) - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); - lua_pop(gL, 1); - hookp->error = true; - } + if (hookp->type != hook_IntermissionThinker) + continue; + + lua_rawgeti(gL, HOOKSINDEX, hookp->id); + if (lua_pcall(gL, 0, 0, 1)) { + if (!hookp->error || cv_debug & DBG_LUA) + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); + lua_pop(gL, 1); + hookp->error = true; } } - lua_pop(gL, 1); // Pop error handler + lua_pop(gL, 2); // Pop error handler and hooks table } // Hook for Y_VoteTicker void LUAh_VoteThinker(void) { hook_p hookp; + int HOOKSINDEX; if (!gL || !(hooksAvailable[hook_VoteThinker/8] & (1<<(hook_VoteThinker%8)))) return; lua_pushcfunction(gL, LUA_GetErrorMessage); + lua_getfield(gL, LUA_REGISTRYINDEX, "hooks"); + HOOKSINDEX = lua_gettop(gL); + I_Assert(lua_istable(L, HOOKSINDEX)); + for (hookp = roothook; hookp; hookp = hookp->next) { - if (hookp->type == hook_VoteThinker) - { - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); - if (lua_pcall(gL, 0, 0, 1)) { - if (!hookp->error || cv_debug & DBG_LUA) - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); - lua_pop(gL, 1); - hookp->error = true; - } + if (hookp->type != hook_VoteThinker) + continue; + + lua_rawgeti(gL, HOOKSINDEX, hookp->id); + if (lua_pcall(gL, 0, 0, 1)) { + if (!hookp->error || cv_debug & DBG_LUA) + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); + lua_pop(gL, 1); + hookp->error = true; } } - lua_pop(gL, 1); // Pop error handler + lua_pop(gL, 2); // Pop error handler and hooks table } @@ -617,77 +673,84 @@ UINT8 LUAh_MobjCollideHook(mobj_t *thing1, mobj_t *thing2, enum hook which) { hook_p hookp; UINT8 shouldCollide = 0; // 0 = default, 1 = force yes, 2 = force no. + int HOOKSINDEX; if (!gL || !(hooksAvailable[which/8] & (1<<(which%8)))) return 0; I_Assert(thing1->type < NUMMOBJTYPES); - + if (!(mobjcollidehooks[MT_NULL] || mobjcollidehooks[thing1->type])) return 0; lua_settop(gL, 0); lua_pushcfunction(gL, LUA_GetErrorMessage); + lua_getfield(gL, LUA_REGISTRYINDEX, "hooks"); + HOOKSINDEX = lua_gettop(gL); + I_Assert(lua_istable(L, HOOKSINDEX)); + // Look for all generic mobj collision hooks for (hookp = mobjcollidehooks[MT_NULL]; hookp; hookp = hookp->next) - if (hookp->type == which) + { + if (hookp->type != which) + continue; + + ps_lua_mobjhooks.value.i++; + if (lua_gettop(gL) == 2) { - ps_lua_mobjhooks.value.i++; - if (lua_gettop(gL) == 1) - { - LUA_PushUserdata(gL, thing1, META_MOBJ); - LUA_PushUserdata(gL, thing2, META_MOBJ); - } - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); - lua_pushvalue(gL, -3); - lua_pushvalue(gL, -3); - if (lua_pcall(gL, 2, 1, 1)) { - if (!hookp->error || cv_debug & DBG_LUA) - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); - lua_pop(gL, 1); - hookp->error = true; - continue; - } - if (!lua_isnil(gL, -1)) - { // if nil, leave shouldCollide = 0. - if (lua_toboolean(gL, -1)) - shouldCollide = 1; // Force yes - else - shouldCollide = 2; // Force no - } - lua_pop(gL, 1); + LUA_PushUserdata(gL, thing1, META_MOBJ); + LUA_PushUserdata(gL, thing2, META_MOBJ); } + lua_rawgeti(gL, HOOKSINDEX, hookp->id); + lua_pushvalue(gL, -3); + lua_pushvalue(gL, -3); + if (lua_pcall(gL, 2, 1, 1)) { + if (!hookp->error || cv_debug & DBG_LUA) + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); + lua_pop(gL, 1); + hookp->error = true; + continue; + } + if (!lua_isnil(gL, -1)) + { // if nil, leave shouldCollide = 0. + if (lua_toboolean(gL, -1)) + shouldCollide = 1; // Force yes + else + shouldCollide = 2; // Force no + } + lua_pop(gL, 1); + } for (hookp = mobjcollidehooks[thing1->type]; hookp; hookp = hookp->next) - if (hookp->type == which) + { + if (hookp->type != which) + continue; + + ps_lua_mobjhooks.value.i++; + if (lua_gettop(gL) == 2) { - ps_lua_mobjhooks.value.i++; - if (lua_gettop(gL) == 1) - { - LUA_PushUserdata(gL, thing1, META_MOBJ); - LUA_PushUserdata(gL, thing2, META_MOBJ); - } - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); - lua_pushvalue(gL, -3); - lua_pushvalue(gL, -3); - if (lua_pcall(gL, 2, 1, 1)) { - if (!hookp->error || cv_debug & DBG_LUA) - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); - lua_pop(gL, 1); - hookp->error = true; - continue; - } - if (!lua_isnil(gL, -1)) - { // if nil, leave shouldCollide = 0. - if (lua_toboolean(gL, -1)) - shouldCollide = 1; // Force yes - else - shouldCollide = 2; // Force no - } - lua_pop(gL, 1); + LUA_PushUserdata(gL, thing1, META_MOBJ); + LUA_PushUserdata(gL, thing2, META_MOBJ); } + lua_rawgeti(gL, HOOKSINDEX, hookp->id); + lua_pushvalue(gL, -3); + lua_pushvalue(gL, -3); + if (lua_pcall(gL, 2, 1, 1)) { + if (!hookp->error || cv_debug & DBG_LUA) + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); + lua_pop(gL, 1); + hookp->error = true; + continue; + } + if (!lua_isnil(gL, -1)) + { // if nil, leave shouldCollide = 0. + if (lua_toboolean(gL, -1)) + shouldCollide = 1; // Force yes + else + shouldCollide = 2; // Force no + } + lua_pop(gL, 1); + } lua_settop(gL, 0); return shouldCollide; @@ -698,25 +761,29 @@ boolean LUAh_MobjThinker(mobj_t *mo) { hook_p hookp; boolean hooked = false; + int HOOKSINDEX; if (!gL || !(hooksAvailable[hook_MobjThinker/8] & (1<<(hook_MobjThinker%8)))) return false; I_Assert(mo->type < NUMMOBJTYPES); - + if (!(mobjthinkerhooks[MT_NULL] || mobjthinkerhooks[mo->type])) return false; lua_settop(gL, 0); lua_pushcfunction(gL, LUA_GetErrorMessage); + lua_getfield(gL, LUA_REGISTRYINDEX, "hooks"); + HOOKSINDEX = lua_gettop(gL); + I_Assert(lua_istable(L, HOOKSINDEX)); + // Look for all generic mobj thinker hooks for (hookp = mobjthinkerhooks[MT_NULL]; hookp; hookp = hookp->next) { ps_lua_mobjhooks.value.i++; - if (lua_gettop(gL) == 1) + if (lua_gettop(gL) == 2) LUA_PushUserdata(gL, mo, META_MOBJ); - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); + lua_rawgeti(gL, HOOKSINDEX, hookp->id); lua_pushvalue(gL, -2); if (lua_pcall(gL, 1, 1, 1)) { if (!hookp->error || cv_debug & DBG_LUA) @@ -733,10 +800,9 @@ boolean LUAh_MobjThinker(mobj_t *mo) for (hookp = mobjthinkerhooks[mo->type]; hookp; hookp = hookp->next) { ps_lua_mobjhooks.value.i++; - if (lua_gettop(gL) == 1) + if (lua_gettop(gL) == 2) LUA_PushUserdata(gL, mo, META_MOBJ); - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); + lua_rawgeti(gL, HOOKSINDEX, hookp->id); lua_pushvalue(gL, -2); if (lua_pcall(gL, 1, 1, 1)) { if (!hookp->error || cv_debug & DBG_LUA) @@ -759,67 +825,74 @@ boolean LUAh_TouchSpecial(mobj_t *special, mobj_t *toucher) { hook_p hookp; boolean hooked = false; + int HOOKSINDEX; if (!gL || !(hooksAvailable[hook_TouchSpecial/8] & (1<<(hook_TouchSpecial%8)))) return false; I_Assert(special->type < NUMMOBJTYPES); - - if (!(mobjhooks[MT_NULL] || mobjhooks[special->type])) + + if (!(mobjhooks[MT_NULL] || mobjhooks[special->type])) return false; lua_settop(gL, 0); lua_pushcfunction(gL, LUA_GetErrorMessage); + lua_getfield(gL, LUA_REGISTRYINDEX, "hooks"); + HOOKSINDEX = lua_gettop(gL); + I_Assert(lua_istable(L, HOOKSINDEX)); + // Look for all generic touch special hooks for (hookp = mobjhooks[MT_NULL]; hookp; hookp = hookp->next) - if (hookp->type == hook_TouchSpecial) + { + if (hookp->type != hook_TouchSpecial) + continue; + + ps_lua_mobjhooks.value.i++; + if (lua_gettop(gL) == 2) { - ps_lua_mobjhooks.value.i++; - if (lua_gettop(gL) == 1) - { - LUA_PushUserdata(gL, special, META_MOBJ); - LUA_PushUserdata(gL, toucher, META_MOBJ); - } - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); - lua_pushvalue(gL, -3); - lua_pushvalue(gL, -3); - if (lua_pcall(gL, 2, 1, 1)) { - if (!hookp->error || cv_debug & DBG_LUA) - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); - lua_pop(gL, 1); - hookp->error = true; - continue; - } - if (lua_toboolean(gL, -1)) - hooked = true; - lua_pop(gL, 1); + LUA_PushUserdata(gL, special, META_MOBJ); + LUA_PushUserdata(gL, toucher, META_MOBJ); } + lua_rawgeti(gL, HOOKSINDEX, hookp->id); + lua_pushvalue(gL, -3); + lua_pushvalue(gL, -3); + if (lua_pcall(gL, 2, 1, 1)) { + if (!hookp->error || cv_debug & DBG_LUA) + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); + lua_pop(gL, 1); + hookp->error = true; + continue; + } + if (lua_toboolean(gL, -1)) + hooked = true; + lua_pop(gL, 1); + } for (hookp = mobjhooks[special->type]; hookp; hookp = hookp->next) - if (hookp->type == hook_TouchSpecial) + { + if (hookp->type != hook_TouchSpecial) + continue; + + ps_lua_mobjhooks.value.i++; + if (lua_gettop(gL) == 2) { - ps_lua_mobjhooks.value.i++; - if (lua_gettop(gL) == 1) - { - LUA_PushUserdata(gL, special, META_MOBJ); - LUA_PushUserdata(gL, toucher, META_MOBJ); - } - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); - lua_pushvalue(gL, -3); - lua_pushvalue(gL, -3); - if (lua_pcall(gL, 2, 1, 1)) { - if (!hookp->error || cv_debug & DBG_LUA) - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); - lua_pop(gL, 1); - hookp->error = true; - continue; - } - if (lua_toboolean(gL, -1)) - hooked = true; - lua_pop(gL, 1); + LUA_PushUserdata(gL, special, META_MOBJ); + LUA_PushUserdata(gL, toucher, META_MOBJ); } + lua_rawgeti(gL, HOOKSINDEX, hookp->id); + lua_pushvalue(gL, -3); + lua_pushvalue(gL, -3); + if (lua_pcall(gL, 2, 1, 1)) { + if (!hookp->error || cv_debug & DBG_LUA) + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); + lua_pop(gL, 1); + hookp->error = true; + continue; + } + if (lua_toboolean(gL, -1)) + hooked = true; + lua_pop(gL, 1); + } lua_settop(gL, 0); return hooked; @@ -830,85 +903,92 @@ UINT8 LUAh_ShouldDamage(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 { hook_p hookp; UINT8 shouldDamage = 0; // 0 = default, 1 = force yes, 2 = force no. + int HOOKSINDEX; if (!gL || !(hooksAvailable[hook_ShouldDamage/8] & (1<<(hook_ShouldDamage%8)))) return 0; I_Assert(target->type < NUMMOBJTYPES); - + if (!(mobjhooks[MT_NULL] || mobjhooks[target->type])) return 0; lua_settop(gL, 0); lua_pushcfunction(gL, LUA_GetErrorMessage); + lua_getfield(gL, LUA_REGISTRYINDEX, "hooks"); + HOOKSINDEX = lua_gettop(gL); + I_Assert(lua_istable(L, HOOKSINDEX)); + // Look for all generic should damage hooks for (hookp = mobjhooks[MT_NULL]; hookp; hookp = hookp->next) - if (hookp->type == hook_ShouldDamage) + { + if (hookp->type != hook_ShouldDamage) + continue; + + ps_lua_mobjhooks.value.i++; + if (lua_gettop(gL) == 2) { - ps_lua_mobjhooks.value.i++; - if (lua_gettop(gL) == 1) - { - LUA_PushUserdata(gL, target, META_MOBJ); - LUA_PushUserdata(gL, inflictor, META_MOBJ); - LUA_PushUserdata(gL, source, META_MOBJ); - lua_pushinteger(gL, damage); - } - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); - lua_pushvalue(gL, -5); - lua_pushvalue(gL, -5); - lua_pushvalue(gL, -5); - lua_pushvalue(gL, -5); - if (lua_pcall(gL, 4, 1, 1)) { - if (!hookp->error || cv_debug & DBG_LUA) - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); - lua_pop(gL, 1); - hookp->error = true; - continue; - } - if (!lua_isnil(gL, -1)) - { - if (lua_toboolean(gL, -1)) - shouldDamage = 1; // Force yes - else - shouldDamage = 2; // Force no - } - lua_pop(gL, 1); + LUA_PushUserdata(gL, target, META_MOBJ); + LUA_PushUserdata(gL, inflictor, META_MOBJ); + LUA_PushUserdata(gL, source, META_MOBJ); + lua_pushinteger(gL, damage); } + lua_rawgeti(gL, HOOKSINDEX, hookp->id); + lua_pushvalue(gL, -5); + lua_pushvalue(gL, -5); + lua_pushvalue(gL, -5); + lua_pushvalue(gL, -5); + if (lua_pcall(gL, 4, 1, 1)) { + if (!hookp->error || cv_debug & DBG_LUA) + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); + lua_pop(gL, 1); + hookp->error = true; + continue; + } + if (!lua_isnil(gL, -1)) + { + if (lua_toboolean(gL, -1)) + shouldDamage = 1; // Force yes + else + shouldDamage = 2; // Force no + } + lua_pop(gL, 1); + } for (hookp = mobjhooks[target->type]; hookp; hookp = hookp->next) - if (hookp->type == hook_ShouldDamage) + { + if (hookp->type != hook_ShouldDamage) + continue; + + ps_lua_mobjhooks.value.i++; + if (lua_gettop(gL) == 2) { - ps_lua_mobjhooks.value.i++; - if (lua_gettop(gL) == 1) - { - LUA_PushUserdata(gL, target, META_MOBJ); - LUA_PushUserdata(gL, inflictor, META_MOBJ); - LUA_PushUserdata(gL, source, META_MOBJ); - lua_pushinteger(gL, damage); - } - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); - lua_pushvalue(gL, -5); - lua_pushvalue(gL, -5); - lua_pushvalue(gL, -5); - lua_pushvalue(gL, -5); - if (lua_pcall(gL, 4, 1, 1)) { - if (!hookp->error || cv_debug & DBG_LUA) - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); - lua_pop(gL, 1); - hookp->error = true; - continue; - } - if (!lua_isnil(gL, -1)) - { - if (lua_toboolean(gL, -1)) - shouldDamage = 1; // Force yes - else - shouldDamage = 2; // Force no - } - lua_pop(gL, 1); + LUA_PushUserdata(gL, target, META_MOBJ); + LUA_PushUserdata(gL, inflictor, META_MOBJ); + LUA_PushUserdata(gL, source, META_MOBJ); + lua_pushinteger(gL, damage); } + lua_rawgeti(gL, HOOKSINDEX, hookp->id); + lua_pushvalue(gL, -5); + lua_pushvalue(gL, -5); + lua_pushvalue(gL, -5); + lua_pushvalue(gL, -5); + if (lua_pcall(gL, 4, 1, 1)) { + if (!hookp->error || cv_debug & DBG_LUA) + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); + lua_pop(gL, 1); + hookp->error = true; + continue; + } + if (!lua_isnil(gL, -1)) + { + if (lua_toboolean(gL, -1)) + shouldDamage = 1; // Force yes + else + shouldDamage = 2; // Force no + } + lua_pop(gL, 1); + } lua_settop(gL, 0); return shouldDamage; @@ -919,75 +999,82 @@ boolean LUAh_MobjDamage(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 { hook_p hookp; boolean hooked = false; + int HOOKSINDEX; if (!gL || !(hooksAvailable[hook_MobjDamage/8] & (1<<(hook_MobjDamage%8)))) return false; I_Assert(target->type < NUMMOBJTYPES); - + if (!(mobjhooks[MT_NULL] || mobjhooks[target->type])) return false; lua_settop(gL, 0); lua_pushcfunction(gL, LUA_GetErrorMessage); + lua_getfield(gL, LUA_REGISTRYINDEX, "hooks"); + HOOKSINDEX = lua_gettop(gL); + I_Assert(lua_istable(L, HOOKSINDEX)); + // Look for all generic mobj damage hooks for (hookp = mobjhooks[MT_NULL]; hookp; hookp = hookp->next) - if (hookp->type == hook_MobjDamage) + { + if (hookp->type != hook_MobjDamage) + continue; + + ps_lua_mobjhooks.value.i++; + if (lua_gettop(gL) == 2) { - ps_lua_mobjhooks.value.i++; - if (lua_gettop(gL) == 1) - { - LUA_PushUserdata(gL, target, META_MOBJ); - LUA_PushUserdata(gL, inflictor, META_MOBJ); - LUA_PushUserdata(gL, source, META_MOBJ); - lua_pushinteger(gL, damage); - } - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); - lua_pushvalue(gL, -5); - lua_pushvalue(gL, -5); - lua_pushvalue(gL, -5); - lua_pushvalue(gL, -5); - if (lua_pcall(gL, 4, 1, 1)) { - if (!hookp->error || cv_debug & DBG_LUA) - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); - lua_pop(gL, 1); - hookp->error = true; - continue; - } - if (lua_toboolean(gL, -1)) - hooked = true; - lua_pop(gL, 1); + LUA_PushUserdata(gL, target, META_MOBJ); + LUA_PushUserdata(gL, inflictor, META_MOBJ); + LUA_PushUserdata(gL, source, META_MOBJ); + lua_pushinteger(gL, damage); } + lua_rawgeti(gL, HOOKSINDEX, hookp->id); + lua_pushvalue(gL, -5); + lua_pushvalue(gL, -5); + lua_pushvalue(gL, -5); + lua_pushvalue(gL, -5); + if (lua_pcall(gL, 4, 1, 1)) { + if (!hookp->error || cv_debug & DBG_LUA) + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); + lua_pop(gL, 1); + hookp->error = true; + continue; + } + if (lua_toboolean(gL, -1)) + hooked = true; + lua_pop(gL, 1); + } for (hookp = mobjhooks[target->type]; hookp; hookp = hookp->next) - if (hookp->type == hook_MobjDamage) + { + if (hookp->type != hook_MobjDamage) + continue; + + ps_lua_mobjhooks.value.i++; + if (lua_gettop(gL) == 2) { - ps_lua_mobjhooks.value.i++; - if (lua_gettop(gL) == 1) - { - LUA_PushUserdata(gL, target, META_MOBJ); - LUA_PushUserdata(gL, inflictor, META_MOBJ); - LUA_PushUserdata(gL, source, META_MOBJ); - lua_pushinteger(gL, damage); - } - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); - lua_pushvalue(gL, -5); - lua_pushvalue(gL, -5); - lua_pushvalue(gL, -5); - lua_pushvalue(gL, -5); - if (lua_pcall(gL, 4, 1, 1)) { - if (!hookp->error || cv_debug & DBG_LUA) - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); - lua_pop(gL, 1); - hookp->error = true; - continue; - } - if (lua_toboolean(gL, -1)) - hooked = true; - lua_pop(gL, 1); + LUA_PushUserdata(gL, target, META_MOBJ); + LUA_PushUserdata(gL, inflictor, META_MOBJ); + LUA_PushUserdata(gL, source, META_MOBJ); + lua_pushinteger(gL, damage); } + lua_rawgeti(gL, HOOKSINDEX, hookp->id); + lua_pushvalue(gL, -5); + lua_pushvalue(gL, -5); + lua_pushvalue(gL, -5); + lua_pushvalue(gL, -5); + if (lua_pcall(gL, 4, 1, 1)) { + if (!hookp->error || cv_debug & DBG_LUA) + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); + lua_pop(gL, 1); + hookp->error = true; + continue; + } + if (lua_toboolean(gL, -1)) + hooked = true; + lua_pop(gL, 1); + } lua_settop(gL, 0); return hooked; @@ -998,70 +1085,77 @@ boolean LUAh_MobjDeath(mobj_t *target, mobj_t *inflictor, mobj_t *source) { hook_p hookp; boolean hooked = false; + int HOOKSINDEX; if (!gL || !(hooksAvailable[hook_MobjDeath/8] & (1<<(hook_MobjDeath%8)))) return false; I_Assert(target->type < NUMMOBJTYPES); - + if (!(mobjhooks[MT_NULL] || mobjhooks[target->type])) return false; lua_settop(gL, 0); lua_pushcfunction(gL, LUA_GetErrorMessage); + lua_getfield(gL, LUA_REGISTRYINDEX, "hooks"); + HOOKSINDEX = lua_gettop(gL); + I_Assert(lua_istable(L, HOOKSINDEX)); + // Look for all generic mobj death hooks for (hookp = mobjhooks[MT_NULL]; hookp; hookp = hookp->next) - if (hookp->type == hook_MobjDeath) + { + if (hookp->type != hook_MobjDeath) + continue; + + if (lua_gettop(gL) == 2) { - if (lua_gettop(gL) == 1) - { - LUA_PushUserdata(gL, target, META_MOBJ); - LUA_PushUserdata(gL, inflictor, META_MOBJ); - LUA_PushUserdata(gL, source, META_MOBJ); - } - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); - lua_pushvalue(gL, -4); - lua_pushvalue(gL, -4); - lua_pushvalue(gL, -4); - if (lua_pcall(gL, 3, 1, 1)) { - if (!hookp->error || cv_debug & DBG_LUA) - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); - lua_pop(gL, 1); - hookp->error = true; - continue; - } - if (lua_toboolean(gL, -1)) - hooked = true; - lua_pop(gL, 1); + LUA_PushUserdata(gL, target, META_MOBJ); + LUA_PushUserdata(gL, inflictor, META_MOBJ); + LUA_PushUserdata(gL, source, META_MOBJ); } + lua_rawgeti(gL, HOOKSINDEX, hookp->id); + lua_pushvalue(gL, -4); + lua_pushvalue(gL, -4); + lua_pushvalue(gL, -4); + if (lua_pcall(gL, 3, 1, 1)) { + if (!hookp->error || cv_debug & DBG_LUA) + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); + lua_pop(gL, 1); + hookp->error = true; + continue; + } + if (lua_toboolean(gL, -1)) + hooked = true; + lua_pop(gL, 1); + } for (hookp = mobjhooks[target->type]; hookp; hookp = hookp->next) - if (hookp->type == hook_MobjDeath) + { + if (hookp->type != hook_MobjDeath) + continue; + + ps_lua_mobjhooks.value.i++; + if (lua_gettop(gL) == 2) { - ps_lua_mobjhooks.value.i++; - if (lua_gettop(gL) == 1) - { - LUA_PushUserdata(gL, target, META_MOBJ); - LUA_PushUserdata(gL, inflictor, META_MOBJ); - LUA_PushUserdata(gL, source, META_MOBJ); - } - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); - lua_pushvalue(gL, -4); - lua_pushvalue(gL, -4); - lua_pushvalue(gL, -4); - if (lua_pcall(gL, 3, 1, 1)) { - if (!hookp->error || cv_debug & DBG_LUA) - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); - lua_pop(gL, 1); - hookp->error = true; - continue; - } - if (lua_toboolean(gL, -1)) - hooked = true; - lua_pop(gL, 1); + LUA_PushUserdata(gL, target, META_MOBJ); + LUA_PushUserdata(gL, inflictor, META_MOBJ); + LUA_PushUserdata(gL, source, META_MOBJ); } + lua_rawgeti(gL, HOOKSINDEX, hookp->id); + lua_pushvalue(gL, -4); + lua_pushvalue(gL, -4); + lua_pushvalue(gL, -4); + if (lua_pcall(gL, 3, 1, 1)) { + if (!hookp->error || cv_debug & DBG_LUA) + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); + lua_pop(gL, 1); + hookp->error = true; + continue; + } + if (lua_toboolean(gL, -1)) + hooked = true; + lua_pop(gL, 1); + } lua_settop(gL, 0); return hooked; @@ -1072,35 +1166,41 @@ boolean LUAh_BotTiccmd(player_t *bot, ticcmd_t *cmd) { hook_p hookp; boolean hooked = false; + int HOOKSINDEX; if (!gL || !(hooksAvailable[hook_BotTiccmd/8] & (1<<(hook_BotTiccmd%8)))) return false; lua_settop(gL, 0); lua_pushcfunction(gL, LUA_GetErrorMessage); + lua_getfield(gL, LUA_REGISTRYINDEX, "hooks"); + HOOKSINDEX = lua_gettop(gL); + I_Assert(lua_istable(L, HOOKSINDEX)); + for (hookp = roothook; hookp; hookp = hookp->next) - if (hookp->type == hook_BotTiccmd) + { + if (hookp->type != hook_BotTiccmd) + continue; + + if (lua_gettop(gL) == 2) { - if (lua_gettop(gL) == 1) - { - LUA_PushUserdata(gL, bot, META_PLAYER); - LUA_PushUserdata(gL, cmd, META_TICCMD); - } - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); - lua_pushvalue(gL, -3); - lua_pushvalue(gL, -3); - if (lua_pcall(gL, 2, 1, 1)) { - if (!hookp->error || cv_debug & DBG_LUA) - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); - lua_pop(gL, 1); - hookp->error = true; - continue; - } - if (lua_toboolean(gL, -1)) - hooked = true; - lua_pop(gL, 1); + LUA_PushUserdata(gL, bot, META_PLAYER); + LUA_PushUserdata(gL, cmd, META_TICCMD); } + lua_rawgeti(gL, HOOKSINDEX, hookp->id); + lua_pushvalue(gL, -3); + lua_pushvalue(gL, -3); + if (lua_pcall(gL, 2, 1, 1)) { + if (!hookp->error || cv_debug & DBG_LUA) + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); + lua_pop(gL, 1); + hookp->error = true; + continue; + } + if (lua_toboolean(gL, -1)) + hooked = true; + lua_pop(gL, 1); + } lua_settop(gL, 0); return hooked; @@ -1112,36 +1212,42 @@ boolean LUAh_PlayerCmd(player_t *player, ticcmd_t *cmd) { hook_p hookp; boolean hooked = false; + int HOOKSINDEX; if (!gL || !(hooksAvailable[hook_PlayerCmd/8] & (1<<(hook_PlayerCmd%8)))) return false; lua_settop(gL, 0); lua_pushcfunction(gL, LUA_GetErrorMessage); + lua_getfield(gL, LUA_REGISTRYINDEX, "hooks"); + HOOKSINDEX = lua_gettop(gL); + I_Assert(lua_istable(L, HOOKSINDEX)); + hook_cmd_running = true; for (hookp = roothook; hookp; hookp = hookp->next) - if (hookp->type == hook_PlayerCmd) + { + if (hookp->type != hook_PlayerCmd) + continue; + + if (lua_gettop(gL) == 2) { - if (lua_gettop(gL) == 1) - { - LUA_PushUserdata(gL, player, META_PLAYER); - LUA_PushUserdata(gL, cmd, META_TICCMD); - } - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); - lua_pushvalue(gL, -3); - lua_pushvalue(gL, -3); - if (lua_pcall(gL, 2, 1, 1)) { - if (!hookp->error || cv_debug & DBG_LUA) - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); - lua_pop(gL, 1); - hookp->error = true; - continue; - } - if (lua_toboolean(gL, -1)) - hooked = true; - lua_pop(gL, 1); + LUA_PushUserdata(gL, player, META_PLAYER); + LUA_PushUserdata(gL, cmd, META_TICCMD); } + lua_rawgeti(gL, HOOKSINDEX, hookp->id); + lua_pushvalue(gL, -3); + lua_pushvalue(gL, -3); + if (lua_pcall(gL, 2, 1, 1)) { + if (!hookp->error || cv_debug & DBG_LUA) + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); + lua_pop(gL, 1); + hookp->error = true; + continue; + } + if (lua_toboolean(gL, -1)) + hooked = true; + lua_pop(gL, 1); + } hook_cmd_running = false; lua_settop(gL, 0); @@ -1153,58 +1259,64 @@ boolean LUAh_BotAI(mobj_t *sonic, mobj_t *tails, ticcmd_t *cmd) { hook_p hookp; boolean hooked = false; + int HOOKSINDEX; if (!gL || !(hooksAvailable[hook_BotAI/8] & (1<<(hook_BotAI%8)))) return false; lua_settop(gL, 0); lua_pushcfunction(gL, LUA_GetErrorMessage); + lua_getfield(gL, LUA_REGISTRYINDEX, "hooks"); + HOOKSINDEX = lua_gettop(gL); + I_Assert(lua_istable(L, HOOKSINDEX)); + for (hookp = roothook; hookp; hookp = hookp->next) - if (hookp->type == hook_BotAI - && (hookp->s.skinname == NULL || !strcmp(hookp->s.skinname, ((skin_t*)tails->skin)->name))) + { + if (hookp->type != hook_BotAI + || (hookp->s.skinname && strcmp(hookp->s.skinname, ((skin_t*)tails->skin)->name))) + continue; + + if (lua_gettop(gL) == 2) { - if (lua_gettop(gL) == 1) - { - LUA_PushUserdata(gL, sonic, META_MOBJ); - LUA_PushUserdata(gL, tails, META_MOBJ); - } - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); - lua_pushvalue(gL, -3); - lua_pushvalue(gL, -3); - if (lua_pcall(gL, 2, 8, 1)) { - if (!hookp->error || cv_debug & DBG_LUA) - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); - lua_pop(gL, 1); - hookp->error = true; - continue; - } - - // This turns forward, backward, left, right, jump, and spin into a proper ticcmd for tails. - if (lua_istable(gL, 2+1)) { - boolean forward=false, backward=false, left=false, right=false, strafeleft=false, straferight=false, jump=false, spin=false; -#define CHECKFIELD(field) \ - lua_getfield(gL, 2+1, #field);\ - if (lua_toboolean(gL, -1))\ - field = true;\ - lua_pop(gL, 1); - - CHECKFIELD(forward) - CHECKFIELD(backward) - CHECKFIELD(left) - CHECKFIELD(right) - CHECKFIELD(strafeleft) - CHECKFIELD(straferight) - CHECKFIELD(jump) - CHECKFIELD(spin) -#undef CHECKFIELD - B_KeysToTiccmd(tails, cmd, forward, backward, left, right, strafeleft, straferight, jump, spin); - } else - B_KeysToTiccmd(tails, cmd, lua_toboolean(gL, 2+1), lua_toboolean(gL, 2+2), lua_toboolean(gL, 2+3), lua_toboolean(gL, 2+4), lua_toboolean(gL, 2+5), lua_toboolean(gL, 2+6), lua_toboolean(gL, 2+7), lua_toboolean(gL, 2+8)); - - lua_pop(gL, 8); - hooked = true; + LUA_PushUserdata(gL, sonic, META_MOBJ); + LUA_PushUserdata(gL, tails, META_MOBJ); } + lua_rawgeti(gL, HOOKSINDEX, hookp->id); + lua_pushvalue(gL, -3); + lua_pushvalue(gL, -3); + if (lua_pcall(gL, 2, 8, 1)) { + if (!hookp->error || cv_debug & DBG_LUA) + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); + lua_pop(gL, 1); + hookp->error = true; + continue; + } + + // This turns forward, backward, left, right, jump, and spin into a proper ticcmd for tails. + if (lua_istable(gL, -8)) { + boolean forward=false, backward=false, left=false, right=false, strafeleft=false, straferight=false, jump=false, spin=false; +#define CHECKFIELD(field) \ + lua_getfield(gL, -8, #field);\ + if (lua_toboolean(gL, -1))\ + field = true;\ + lua_pop(gL, 1); + + CHECKFIELD(forward) + CHECKFIELD(backward) + CHECKFIELD(left) + CHECKFIELD(right) + CHECKFIELD(strafeleft) + CHECKFIELD(straferight) + CHECKFIELD(jump) + CHECKFIELD(spin) +#undef CHECKFIELD + B_KeysToTiccmd(tails, cmd, forward, backward, left, right, strafeleft, straferight, jump, spin); + } else + B_KeysToTiccmd(tails, cmd, lua_toboolean(gL, -8), lua_toboolean(gL, -7), lua_toboolean(gL, -6), lua_toboolean(gL, -5), lua_toboolean(gL, -4), lua_toboolean(gL, -3), lua_toboolean(gL, -2), lua_toboolean(gL, -1)); + + lua_pop(gL, 8); + hooked = true; + } lua_settop(gL, 0); return hooked; @@ -1215,33 +1327,39 @@ boolean LUAh_LinedefExecute(line_t *line, mobj_t *mo, sector_t *sector) { hook_p hookp; boolean hooked = false; + int HOOKSINDEX; if (!gL || !(hooksAvailable[hook_LinedefExecute/8] & (1<<(hook_LinedefExecute%8)))) return 0; lua_settop(gL, 0); lua_pushcfunction(gL, LUA_GetErrorMessage); + lua_getfield(gL, LUA_REGISTRYINDEX, "hooks"); + HOOKSINDEX = lua_gettop(gL); + I_Assert(lua_istable(L, HOOKSINDEX)); + for (hookp = linedefexecutorhooks; hookp; hookp = hookp->next) - if (!strcmp(hookp->s.funcname, line->text)) + { + if (strcmp(hookp->s.funcname, line->text)) + continue; + + ps_lua_mobjhooks.value.i++; + if (lua_gettop(gL) == 2) { - ps_lua_mobjhooks.value.i++; - if (lua_gettop(gL) == 1) - { - LUA_PushUserdata(gL, line, META_LINE); - LUA_PushUserdata(gL, mo, META_MOBJ); - LUA_PushUserdata(gL, sector, META_SECTOR); - } - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); - lua_pushvalue(gL, -4); - lua_pushvalue(gL, -4); - lua_pushvalue(gL, -4); - if (lua_pcall(gL, 3, 0, 1)) { + LUA_PushUserdata(gL, line, META_LINE); + LUA_PushUserdata(gL, mo, META_MOBJ); + LUA_PushUserdata(gL, sector, META_SECTOR); + } + lua_rawgeti(gL, HOOKSINDEX, hookp->id); + lua_pushvalue(gL, -4); + lua_pushvalue(gL, -4); + lua_pushvalue(gL, -4); + if (lua_pcall(gL, 3, 0, 1)) { CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); lua_pop(gL, 1); - } - hooked = true; } + hooked = true; + } lua_settop(gL, 0); return hooked; @@ -1254,55 +1372,61 @@ boolean LUAh_PlayerMsg(int source, int target, int flags, char *msg, int mute) { hook_p hookp; boolean hooked = false; + int HOOKSINDEX; if (!gL || !(hooksAvailable[hook_PlayerMsg/8] & (1<<(hook_PlayerMsg%8)))) return false; lua_settop(gL, 0); lua_pushcfunction(gL, LUA_GetErrorMessage); + lua_getfield(gL, LUA_REGISTRYINDEX, "hooks"); + HOOKSINDEX = lua_gettop(gL); + I_Assert(lua_istable(L, HOOKSINDEX)); + for (hookp = roothook; hookp; hookp = hookp->next) - if (hookp->type == hook_PlayerMsg) + { + if (hookp->type != hook_PlayerMsg) + continue; + + if (lua_gettop(gL) == 2) { - if (lua_gettop(gL) == 1) - { - LUA_PushUserdata(gL, &players[source], META_PLAYER); // Source player - if (flags & 2 /*HU_CSAY*/) { // csay TODO: make HU_CSAY accessible outside hu_stuff.c - lua_pushinteger(gL, 3); // type - lua_pushnil(gL); // target - } else if (target == -1) { // sayteam - lua_pushinteger(gL, 1); // type - lua_pushnil(gL); // target - } else if (target == 0) { // say - lua_pushinteger(gL, 0); // type - lua_pushnil(gL); // target - } else { // sayto - lua_pushinteger(gL, 2); // type - LUA_PushUserdata(gL, &players[target-1], META_PLAYER); // target - } - lua_pushstring(gL, msg); // msg - if (mute) - lua_pushboolean(gL, true); // the message was supposed to be eaten by spamprotecc. - else - lua_pushboolean(gL, false); + LUA_PushUserdata(gL, &players[source], META_PLAYER); // Source player + if (flags & 2 /*HU_CSAY*/) { // csay TODO: make HU_CSAY accessible outside hu_stuff.c + lua_pushinteger(gL, 3); // type + lua_pushnil(gL); // target + } else if (target == -1) { // sayteam + lua_pushinteger(gL, 1); // type + lua_pushnil(gL); // target + } else if (target == 0) { // say + lua_pushinteger(gL, 0); // type + lua_pushnil(gL); // target + } else { // sayto + lua_pushinteger(gL, 2); // type + LUA_PushUserdata(gL, &players[target-1], META_PLAYER); // target } - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); - lua_pushvalue(gL, -6); - lua_pushvalue(gL, -6); - lua_pushvalue(gL, -6); - lua_pushvalue(gL, -6); - lua_pushvalue(gL, -6); - if (lua_pcall(gL, 5, 1, 1)) { - if (!hookp->error || cv_debug & DBG_LUA) - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); - lua_pop(gL, 1); - hookp->error = true; - continue; - } - if (lua_toboolean(gL, -1)) - hooked = true; - lua_pop(gL, 1); + lua_pushstring(gL, msg); // msg + if (mute) + lua_pushboolean(gL, true); // the message was supposed to be eaten by spamprotecc. + else + lua_pushboolean(gL, false); } + lua_rawgeti(gL, HOOKSINDEX, hookp->id); + lua_pushvalue(gL, -6); + lua_pushvalue(gL, -6); + lua_pushvalue(gL, -6); + lua_pushvalue(gL, -6); + lua_pushvalue(gL, -6); + if (lua_pcall(gL, 5, 1, 1)) { + if (!hookp->error || cv_debug & DBG_LUA) + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); + lua_pop(gL, 1); + hookp->error = true; + continue; + } + if (lua_toboolean(gL, -1)) + hooked = true; + lua_pop(gL, 1); + } lua_settop(gL, 0); return hooked; @@ -1313,38 +1437,44 @@ boolean LUAh_HurtMsg(player_t *player, mobj_t *inflictor, mobj_t *source) { hook_p hookp; boolean hooked = false; + int HOOKSINDEX; if (!gL || !(hooksAvailable[hook_HurtMsg/8] & (1<<(hook_HurtMsg%8)))) return false; lua_settop(gL, 0); lua_pushcfunction(gL, LUA_GetErrorMessage); + lua_getfield(gL, LUA_REGISTRYINDEX, "hooks"); + HOOKSINDEX = lua_gettop(gL); + I_Assert(lua_istable(L, HOOKSINDEX)); + for (hookp = roothook; hookp; hookp = hookp->next) - if (hookp->type == hook_HurtMsg - && (hookp->s.mt == MT_NULL || (inflictor && hookp->s.mt == inflictor->type))) + { + if (hookp->type != hook_HurtMsg + || (hookp->s.mt && !(inflictor && hookp->s.mt == inflictor->type))) + continue; + + if (lua_gettop(gL) == 2) { - if (lua_gettop(gL) == 1) - { - LUA_PushUserdata(gL, player, META_PLAYER); - LUA_PushUserdata(gL, inflictor, META_MOBJ); - LUA_PushUserdata(gL, source, META_MOBJ); - } - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); - lua_pushvalue(gL, -4); - lua_pushvalue(gL, -4); - lua_pushvalue(gL, -4); - if (lua_pcall(gL, 3, 1, 1)) { - if (!hookp->error || cv_debug & DBG_LUA) - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); - lua_pop(gL, 1); - hookp->error = true; - continue; - } - if (lua_toboolean(gL, -1)) - hooked = true; - lua_pop(gL, 1); + LUA_PushUserdata(gL, player, META_PLAYER); + LUA_PushUserdata(gL, inflictor, META_MOBJ); + LUA_PushUserdata(gL, source, META_MOBJ); } + lua_rawgeti(gL, HOOKSINDEX, hookp->id); + lua_pushvalue(gL, -4); + lua_pushvalue(gL, -4); + lua_pushvalue(gL, -4); + if (lua_pcall(gL, 3, 1, 1)) { + if (!hookp->error || cv_debug & DBG_LUA) + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); + lua_pop(gL, 1); + hookp->error = true; + continue; + } + if (lua_toboolean(gL, -1)) + hooked = true; + lua_pop(gL, 1); + } lua_settop(gL, 0); return hooked; @@ -1354,63 +1484,75 @@ void LUAh_NetArchiveHook(lua_CFunction archFunc) { hook_p hookp; int errorhandlerindex; + int HOOKSINDEX; if (!gL || !(hooksAvailable[hook_NetVars/8] & (1<<(hook_NetVars%8)))) return; // stack: tables I_Assert(lua_gettop(gL) > 0); I_Assert(lua_istable(gL, -1)); - + lua_pushcfunction(gL, LUA_GetErrorMessage); errorhandlerindex = lua_gettop(gL); + lua_getfield(gL, LUA_REGISTRYINDEX, "hooks"); + HOOKSINDEX = lua_gettop(gL); + I_Assert(lua_istable(L, HOOKSINDEX)); + // tables becomes an upvalue of archFunc - lua_pushvalue(gL, -2); + lua_pushvalue(gL, -3); lua_pushcclosure(gL, archFunc, 1); // stack: tables, archFunc for (hookp = roothook; hookp; hookp = hookp->next) - if (hookp->type == hook_NetVars) - { - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); - lua_pushvalue(gL, -2); // archFunc - if (lua_pcall(gL, 1, 0, errorhandlerindex)) { + { + if (hookp->type != hook_NetVars) + continue; + + lua_rawgeti(gL, HOOKSINDEX, hookp->id); + lua_pushvalue(gL, -2); // archFunc + if (lua_pcall(gL, 1, 0, errorhandlerindex)) { CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); lua_pop(gL, 1); - } } + } - lua_pop(gL, 2); // Pop archFunc and error handler + lua_pop(gL, 3); // Pop archFunc, error handler and hooks table // stack: tables } void LUAh_PlayerQuit(player_t *plr, int reason) { hook_p hookp; + int HOOKSINDEX; if (!gL || !(hooksAvailable[hook_PlayerQuit/8] & (1<<(hook_PlayerQuit%8)))) return; lua_settop(gL, 0); lua_pushcfunction(gL, LUA_GetErrorMessage); + lua_getfield(gL, LUA_REGISTRYINDEX, "hooks"); + HOOKSINDEX = lua_gettop(gL); + I_Assert(lua_istable(L, HOOKSINDEX)); + for (hookp = roothook; hookp; hookp = hookp->next) - if (hookp->type == hook_PlayerQuit) + { + if (hookp->type != hook_PlayerQuit) + continue; + + if (lua_gettop(gL) == 2) { - if (lua_gettop(gL) == 1) - { - LUA_PushUserdata(gL, plr, META_PLAYER); // Player that quit - lua_pushinteger(gL, reason); // Reason for quitting - } - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); - lua_pushvalue(gL, -3); - lua_pushvalue(gL, -3); - if (lua_pcall(gL, 2, 0, 1)) { + LUA_PushUserdata(gL, plr, META_PLAYER); // Player that quit + lua_pushinteger(gL, reason); // Reason for quitting + } + lua_rawgeti(gL, HOOKSINDEX, hookp->id); + lua_pushvalue(gL, -3); + lua_pushvalue(gL, -3); + if (lua_pcall(gL, 2, 0, 1)) { CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); lua_pop(gL, 1); - } } + } lua_settop(gL, 0); } @@ -1421,6 +1563,7 @@ boolean LUAh_MusicChange(const char *oldname, char *newname, UINT16 *mflags, boo { hook_p hookp; boolean hooked = false; + int HOOKSINDEX; if (!gL || !(hooksAvailable[hook_MusicChange/8] & (1<<(hook_MusicChange%8)))) return false; @@ -1428,48 +1571,53 @@ boolean LUAh_MusicChange(const char *oldname, char *newname, UINT16 *mflags, boo lua_settop(gL, 0); lua_pushcfunction(gL, LUA_GetErrorMessage); + lua_getfield(gL, LUA_REGISTRYINDEX, "hooks"); + HOOKSINDEX = lua_gettop(gL); + I_Assert(lua_istable(L, HOOKSINDEX)); + for (hookp = roothook; hookp; hookp = hookp->next) - if (hookp->type == hook_MusicChange) - { - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); - lua_pushstring(gL, oldname); - lua_pushstring(gL, newname); - lua_pushinteger(gL, *mflags); - lua_pushboolean(gL, *looping); - lua_pushinteger(gL, *position); - lua_pushinteger(gL, *prefadems); - lua_pushinteger(gL, *fadeinms); - if (lua_pcall(gL, 7, 6, 1)) { - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL,-1)); - lua_pop(gL, 1); - continue; - } + { + if (hookp->type != hook_MusicChange) + continue; - // output 1: true, false, or string musicname override - if (lua_isboolean(gL, -6) && lua_toboolean(gL, -6)) - hooked = true; - else if (lua_isstring(gL, -6)) - strncpy(newname, lua_tostring(gL, -6), 7); - // output 2: mflags override - if (lua_isnumber(gL, -5)) - *mflags = lua_tonumber(gL, -5); - // output 3: looping override - if (lua_isboolean(gL, -4)) - *looping = lua_toboolean(gL, -4); - // output 4: position override - if (lua_isnumber(gL, -3)) - *position = lua_tonumber(gL, -3); - // output 5: prefadems override - if (lua_isnumber(gL, -2)) - *prefadems = lua_tonumber(gL, -2); - // output 6: fadeinms override - if (lua_isnumber(gL, -1)) - *fadeinms = lua_tonumber(gL, -1); - - lua_pop(gL, 6); + lua_rawgeti(gL, HOOKSINDEX, hookp->id); + lua_pushstring(gL, oldname); + lua_pushstring(gL, newname); + lua_pushinteger(gL, *mflags); + lua_pushboolean(gL, *looping); + lua_pushinteger(gL, *position); + lua_pushinteger(gL, *prefadems); + lua_pushinteger(gL, *fadeinms); + if (lua_pcall(gL, 7, 6, 1)) { + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL,-1)); + lua_pop(gL, 1); + continue; } + // output 1: true, false, or string musicname override + if (lua_isboolean(gL, -6) && lua_toboolean(gL, -6)) + hooked = true; + else if (lua_isstring(gL, -6)) + strncpy(newname, lua_tostring(gL, -6), 7); + // output 2: mflags override + if (lua_isnumber(gL, -5)) + *mflags = lua_tonumber(gL, -5); + // output 3: looping override + if (lua_isboolean(gL, -4)) + *looping = lua_toboolean(gL, -4); + // output 4: position override + if (lua_isnumber(gL, -3)) + *position = lua_tonumber(gL, -3); + // output 5: prefadems override + if (lua_isnumber(gL, -2)) + *prefadems = lua_tonumber(gL, -2); + // output 6: fadeinms override + if (lua_isnumber(gL, -1)) + *fadeinms = lua_tonumber(gL, -1); + + lua_pop(gL, 6); + } + lua_settop(gL, 0); newname[6] = 0; return hooked; @@ -1480,45 +1628,51 @@ UINT8 LUAh_ShouldSpin(player_t *player, mobj_t *inflictor, mobj_t *source) { hook_p hookp; UINT8 shouldDamage = 0; // 0 = default, 1 = force yes, 2 = force no. + int HOOKSINDEX; if (!gL || !(hooksAvailable[hook_ShouldSpin/8] & (1<<(hook_ShouldSpin%8)))) return 0; lua_settop(gL, 0); lua_pushcfunction(gL, LUA_GetErrorMessage); + lua_getfield(gL, LUA_REGISTRYINDEX, "hooks"); + HOOKSINDEX = lua_gettop(gL); + I_Assert(lua_istable(L, HOOKSINDEX)); + // We can afford not to check for mobj type because it will always be MT_PLAYER in this case. for (hookp = roothook; hookp; hookp = hookp->next) - if (hookp->type == hook_ShouldSpin) + { + if (hookp->type != hook_ShouldSpin) + continue; + + ps_lua_mobjhooks.value.i++; + if (lua_gettop(gL) == 2) { - ps_lua_mobjhooks.value.i++; - if (lua_gettop(gL) == 1) - { - LUA_PushUserdata(gL, player, META_PLAYER); - LUA_PushUserdata(gL, inflictor, META_MOBJ); - LUA_PushUserdata(gL, source, META_MOBJ); - } - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); - lua_pushvalue(gL, -4); - lua_pushvalue(gL, -4); - lua_pushvalue(gL, -4); - if (lua_pcall(gL, 3, 1, 1)) { - if (!hookp->error || cv_debug & DBG_LUA) - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); - lua_pop(gL, 1); - hookp->error = true; - continue; - } - if (!lua_isnil(gL, -1)) - { - if (lua_toboolean(gL, -1)) - shouldDamage = 1; // Force yes - else - shouldDamage = 2; // Force no - } - lua_pop(gL, 1); + LUA_PushUserdata(gL, player, META_PLAYER); + LUA_PushUserdata(gL, inflictor, META_MOBJ); + LUA_PushUserdata(gL, source, META_MOBJ); } + lua_rawgeti(gL, HOOKSINDEX, hookp->id); + lua_pushvalue(gL, -4); + lua_pushvalue(gL, -4); + lua_pushvalue(gL, -4); + if (lua_pcall(gL, 3, 1, 1)) { + if (!hookp->error || cv_debug & DBG_LUA) + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); + lua_pop(gL, 1); + hookp->error = true; + continue; + } + if (!lua_isnil(gL, -1)) + { + if (lua_toboolean(gL, -1)) + shouldDamage = 1; // Force yes + else + shouldDamage = 2; // Force no + } + lua_pop(gL, 1); + } lua_settop(gL, 0); return shouldDamage; @@ -1529,45 +1683,51 @@ UINT8 LUAh_ShouldExplode(player_t *player, mobj_t *inflictor, mobj_t *source) { hook_p hookp; UINT8 shouldDamage = 0; // 0 = default, 1 = force yes, 2 = force no. + int HOOKSINDEX; if (!gL || !(hooksAvailable[hook_ShouldExplode/8] & (1<<(hook_ShouldExplode%8)))) return 0; lua_settop(gL, 0); lua_pushcfunction(gL, LUA_GetErrorMessage); + lua_getfield(gL, LUA_REGISTRYINDEX, "hooks"); + HOOKSINDEX = lua_gettop(gL); + I_Assert(lua_istable(L, HOOKSINDEX)); + // We can afford not to check for mobj type because it will always be MT_PLAYER in this case. for (hookp = roothook; hookp; hookp = hookp->next) - if (hookp->type == hook_ShouldExplode) + { + if (hookp->type != hook_ShouldExplode) + continue; + + ps_lua_mobjhooks.value.i++; + if (lua_gettop(gL) == 2) { - ps_lua_mobjhooks.value.i++; - if (lua_gettop(gL) == 1) - { - LUA_PushUserdata(gL, player, META_PLAYER); - LUA_PushUserdata(gL, inflictor, META_MOBJ); - LUA_PushUserdata(gL, source, META_MOBJ); - } - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); - lua_pushvalue(gL, -4); - lua_pushvalue(gL, -4); - lua_pushvalue(gL, -4); - if (lua_pcall(gL, 3, 1, 1)) { - if (!hookp->error || cv_debug & DBG_LUA) - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); - lua_pop(gL, 1); - hookp->error = true; - continue; - } - if (!lua_isnil(gL, -1)) - { - if (lua_toboolean(gL, -1)) - shouldDamage = 1; // Force yes - else - shouldDamage = 2; // Force no - } - lua_pop(gL, 1); + LUA_PushUserdata(gL, player, META_PLAYER); + LUA_PushUserdata(gL, inflictor, META_MOBJ); + LUA_PushUserdata(gL, source, META_MOBJ); } + lua_rawgeti(gL, HOOKSINDEX, hookp->id); + lua_pushvalue(gL, -4); + lua_pushvalue(gL, -4); + lua_pushvalue(gL, -4); + if (lua_pcall(gL, 3, 1, 1)) { + if (!hookp->error || cv_debug & DBG_LUA) + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); + lua_pop(gL, 1); + hookp->error = true; + continue; + } + if (!lua_isnil(gL, -1)) + { + if (lua_toboolean(gL, -1)) + shouldDamage = 1; // Force yes + else + shouldDamage = 2; // Force no + } + lua_pop(gL, 1); + } lua_settop(gL, 0); return shouldDamage; @@ -1578,45 +1738,51 @@ UINT8 LUAh_ShouldSquish(player_t *player, mobj_t *inflictor, mobj_t *source) { hook_p hookp; UINT8 shouldDamage = 0; // 0 = default, 1 = force yes, 2 = force no. + int HOOKSINDEX; if (!gL || !(hooksAvailable[hook_ShouldSquish/8] & (1<<(hook_ShouldSquish%8)))) return 0; lua_settop(gL, 0); lua_pushcfunction(gL, LUA_GetErrorMessage); + lua_getfield(gL, LUA_REGISTRYINDEX, "hooks"); + HOOKSINDEX = lua_gettop(gL); + I_Assert(lua_istable(L, HOOKSINDEX)); + // We can afford not to check for mobj type because it will always be MT_PLAYER in this case. for (hookp = roothook; hookp; hookp = hookp->next) - if (hookp->type == hook_ShouldSquish) + { + if (hookp->type != hook_ShouldSquish) + continue; + + ps_lua_mobjhooks.value.i++; + if (lua_gettop(gL) == 2) { - ps_lua_mobjhooks.value.i++; - if (lua_gettop(gL) == 1) - { - LUA_PushUserdata(gL, player, META_PLAYER); - LUA_PushUserdata(gL, inflictor, META_MOBJ); - LUA_PushUserdata(gL, source, META_MOBJ); - } - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); - lua_pushvalue(gL, -4); - lua_pushvalue(gL, -4); - lua_pushvalue(gL, -4); - if (lua_pcall(gL, 3, 1, 1)) { - if (!hookp->error || cv_debug & DBG_LUA) - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); - lua_pop(gL, 1); - hookp->error = true; - continue; - } - if (!lua_isnil(gL, -1)) - { - if (lua_toboolean(gL, -1)) - shouldDamage = 1; // Force yes - else - shouldDamage = 2; // Force no - } - lua_pop(gL, 1); + LUA_PushUserdata(gL, player, META_PLAYER); + LUA_PushUserdata(gL, inflictor, META_MOBJ); + LUA_PushUserdata(gL, source, META_MOBJ); } + lua_rawgeti(gL, HOOKSINDEX, hookp->id); + lua_pushvalue(gL, -4); + lua_pushvalue(gL, -4); + lua_pushvalue(gL, -4); + if (lua_pcall(gL, 3, 1, 1)) { + if (!hookp->error || cv_debug & DBG_LUA) + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); + lua_pop(gL, 1); + hookp->error = true; + continue; + } + if (!lua_isnil(gL, -1)) + { + if (lua_toboolean(gL, -1)) + shouldDamage = 1; // Force yes + else + shouldDamage = 2; // Force no + } + lua_pop(gL, 1); + } lua_settop(gL, 0); return shouldDamage; @@ -1627,40 +1793,47 @@ boolean LUAh_PlayerSpin(player_t *player, mobj_t *inflictor, mobj_t *source) { hook_p hookp; boolean hooked = false; + int HOOKSINDEX; if (!gL || !(hooksAvailable[hook_PlayerSpin/8] & (1<<(hook_PlayerSpin%8)))) return 0; lua_settop(gL, 0); lua_pushcfunction(gL, LUA_GetErrorMessage); + lua_getfield(gL, LUA_REGISTRYINDEX, "hooks"); + HOOKSINDEX = lua_gettop(gL); + I_Assert(lua_istable(L, HOOKSINDEX)); + // We can afford not to look for target->type because it will always be MT_PLAYER. for (hookp = roothook; hookp; hookp = hookp->next) - if (hookp->type == hook_PlayerSpin) + { + if (hookp->type != hook_PlayerSpin) + continue; + + ps_lua_mobjhooks.value.i++; + if (lua_gettop(gL) == 2) { - ps_lua_mobjhooks.value.i++; - if (lua_gettop(gL) == 1) - { - LUA_PushUserdata(gL, player, META_PLAYER); - LUA_PushUserdata(gL, inflictor, META_MOBJ); - LUA_PushUserdata(gL, source, META_MOBJ); - } - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); - lua_pushvalue(gL, -4); - lua_pushvalue(gL, -4); - lua_pushvalue(gL, -4); - if (lua_pcall(gL, 3, 1, 1)) { - if (!hookp->error || cv_debug & DBG_LUA) - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); - lua_pop(gL, 1); - hookp->error = true; - continue; - } - if (lua_toboolean(gL, -1)) - hooked = true; - lua_pop(gL, 1); + LUA_PushUserdata(gL, player, META_PLAYER); + LUA_PushUserdata(gL, inflictor, META_MOBJ); + LUA_PushUserdata(gL, source, META_MOBJ); } + lua_rawgeti(gL, HOOKSINDEX, hookp->id); + lua_pushvalue(gL, -4); + lua_pushvalue(gL, -4); + lua_pushvalue(gL, -4); + if (lua_pcall(gL, 3, 1, 1)) { + if (!hookp->error || cv_debug & DBG_LUA) + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); + lua_pop(gL, 1); + hookp->error = true; + continue; + } + if (lua_toboolean(gL, -1)) + hooked = true; + lua_pop(gL, 1); + } + lua_settop(gL, 0); return hooked; } @@ -1670,40 +1843,47 @@ boolean LUAh_PlayerSquish(player_t *player, mobj_t *inflictor, mobj_t *source) { hook_p hookp; boolean hooked = false; + int HOOKSINDEX; if (!gL || !(hooksAvailable[hook_PlayerSquish/8] & (1<<(hook_PlayerSquish%8)))) return 0; lua_settop(gL, 0); lua_pushcfunction(gL, LUA_GetErrorMessage); + lua_getfield(gL, LUA_REGISTRYINDEX, "hooks"); + HOOKSINDEX = lua_gettop(gL); + I_Assert(lua_istable(L, HOOKSINDEX)); + // We can afford not to look for target->type because it will always be MT_PLAYER. for (hookp = roothook; hookp; hookp = hookp->next) - if (hookp->type == hook_PlayerSquish) + { + if (hookp->type != hook_PlayerSquish) + continue; + + ps_lua_mobjhooks.value.i++; + if (lua_gettop(gL) == 2) { - ps_lua_mobjhooks.value.i++; - if (lua_gettop(gL) == 1) - { - LUA_PushUserdata(gL, player, META_PLAYER); - LUA_PushUserdata(gL, inflictor, META_MOBJ); - LUA_PushUserdata(gL, source, META_MOBJ); - } - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); - lua_pushvalue(gL, -4); - lua_pushvalue(gL, -4); - lua_pushvalue(gL, -4); - if (lua_pcall(gL, 3, 1, 1)) { - if (!hookp->error || cv_debug & DBG_LUA) - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); - lua_pop(gL, 1); - hookp->error = true; - continue; - } - if (lua_toboolean(gL, -1)) - hooked = true; - lua_pop(gL, 1); + LUA_PushUserdata(gL, player, META_PLAYER); + LUA_PushUserdata(gL, inflictor, META_MOBJ); + LUA_PushUserdata(gL, source, META_MOBJ); } + lua_rawgeti(gL, HOOKSINDEX, hookp->id); + lua_pushvalue(gL, -4); + lua_pushvalue(gL, -4); + lua_pushvalue(gL, -4); + if (lua_pcall(gL, 3, 1, 1)) { + if (!hookp->error || cv_debug & DBG_LUA) + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); + lua_pop(gL, 1); + hookp->error = true; + continue; + } + if (lua_toboolean(gL, -1)) + hooked = true; + lua_pop(gL, 1); + } + lua_settop(gL, 0); return hooked; } @@ -1713,40 +1893,81 @@ boolean LUAh_PlayerExplode(player_t *player, mobj_t *inflictor, mobj_t *source) { hook_p hookp; boolean hooked = false; + int HOOKSINDEX; if (!gL || !(hooksAvailable[hook_PlayerExplode/8] & (1<<(hook_PlayerExplode%8)))) return 0; lua_settop(gL, 0); lua_pushcfunction(gL, LUA_GetErrorMessage); + lua_getfield(gL, LUA_REGISTRYINDEX, "hooks"); + HOOKSINDEX = lua_gettop(gL); + I_Assert(lua_istable(L, HOOKSINDEX)); + // We can afford not to look for target->type because it will always be MT_PLAYER. for (hookp = roothook; hookp; hookp = hookp->next) - if (hookp->type == hook_PlayerExplode) + { + if (hookp->type != hook_PlayerExplode) + continue; + + ps_lua_mobjhooks.value.i++; + if (lua_gettop(gL) == 2) { - ps_lua_mobjhooks.value.i++; - if (lua_gettop(gL) == 1) - { - LUA_PushUserdata(gL, player, META_PLAYER); - LUA_PushUserdata(gL, inflictor, META_MOBJ); - LUA_PushUserdata(gL, source, META_MOBJ); - } - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); - lua_pushvalue(gL, -4); - lua_pushvalue(gL, -4); - lua_pushvalue(gL, -4); - if (lua_pcall(gL, 3, 1, 1)) { - if (!hookp->error || cv_debug & DBG_LUA) - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); - lua_pop(gL, 1); - hookp->error = true; - continue; - } - if (lua_toboolean(gL, -1)) - hooked = true; - lua_pop(gL, 1); + LUA_PushUserdata(gL, player, META_PLAYER); + LUA_PushUserdata(gL, inflictor, META_MOBJ); + LUA_PushUserdata(gL, source, META_MOBJ); } + lua_rawgeti(gL, HOOKSINDEX, hookp->id); + lua_pushvalue(gL, -4); + lua_pushvalue(gL, -4); + lua_pushvalue(gL, -4); + if (lua_pcall(gL, 3, 1, 1)) { + if (!hookp->error || cv_debug & DBG_LUA) + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); + lua_pop(gL, 1); + hookp->error = true; + continue; + } + if (lua_toboolean(gL, -1)) + hooked = true; + lua_pop(gL, 1); + } + lua_settop(gL, 0); return hooked; -} \ No newline at end of file +} + +void LUAh_ServerJoin(void) +{ + hook_p hookp; + int HOOKSINDEX; + if (!gL || !(hooksAvailable[hook_ServerJoin/8] & (1<<(hook_ServerJoin%8)))) + return; + + lua_settop(gL, 0); + lua_pushcfunction(gL, LUA_GetErrorMessage); + + lua_getfield(gL, LUA_REGISTRYINDEX, "hooks"); + HOOKSINDEX = lua_gettop(gL); + I_Assert(lua_istable(L, HOOKSINDEX)); + + // We can afford not to look for target->type because it will always be MT_PLAYER. + + for (hookp = roothook; hookp; hookp = hookp->next) + { + if (hookp->type != hook_ServerJoin) + continue; + + lua_rawgeti(gL, HOOKSINDEX, hookp->id); + if (lua_pcall(gL, 0, 0, 1)) { + if (!hookp->error || cv_debug & DBG_LUA) + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); + lua_pop(gL, 1); + hookp->error = true; + continue; + } + } + + lua_settop(gL, 0); +} diff --git a/src/lua_hud.h b/src/lua_hud.h index d0fec7f1e..5d1f41c83 100644 --- a/src/lua_hud.h +++ b/src/lua_hud.h @@ -42,9 +42,15 @@ enum hud { extern boolean hud_running; +extern boolean hud_interpolate; // interpolation enabled +extern UINT8 hud_interptag; // current tag +extern UINT32 hud_interpcounter; // number of HUD hooks ran +extern boolean hud_interpstring; // string mode +extern boolean hud_interplatch; // string mode was toggled + boolean LUA_HudEnabled(enum hud option); -void LUAh_GameHUD(player_t *stplyr, huddrawlist_h list); +void LUAh_GameHUD(huddrawlist_h list); void LUAh_ScoresHUD(huddrawlist_h list); void LUAh_IntermissionHUD(huddrawlist_h list); void LUAh_VoteHUD(huddrawlist_h list); diff --git a/src/lua_hudlib.c b/src/lua_hudlib.c index 2f81d98bf..0af7f2c36 100644 --- a/src/lua_hudlib.c +++ b/src/lua_hudlib.c @@ -32,6 +32,12 @@ #define HUDONLY if (!hud_running) return luaL_error(L, "HUD rendering code should not be called outside of rendering hooks!"); boolean hud_running = false; + +boolean hud_interpolate = false; +UINT8 hud_interptag = 0; +UINT32 hud_interpcounter = 0; +boolean hud_interpstring = false; +boolean hud_interplatch = false; static UINT8 hud_enabled[(hud_MAX/8)+1]; static UINT8 hudAvailable; // hud hooks field @@ -100,6 +106,8 @@ static const char *const hudhook_opt[] = { "vote", NULL}; +static int patch_fields_ref = LUA_NOREF; + // alignment types for v.drawString enum align { align_left = 0, @@ -223,6 +231,8 @@ static const char *const hud_drawinfo_options[] = { "minimap", NULL}; +static int camera_fields_ref = LUA_NOREF; + static int lib_getHudInfo(lua_State *L) { UINT32 i; @@ -292,7 +302,7 @@ static int colormap_get(lua_State *L) static int patch_get(lua_State *L) { patch_t *patch = *((patch_t **)luaL_checkudata(L, 1, META_PATCH)); - enum patch field = luaL_checkoption(L, 2, NULL, patch_opt); + enum patch field = Lua_optoption(L, 2, -1, patch_fields_ref); // patches are CURRENTLY always valid, expected to be cached with PU_STATIC // this may change in the future, so patch.valid still exists @@ -327,7 +337,7 @@ static int patch_set(lua_State *L) static int camera_get(lua_State *L) { camera_t *cam = *((camera_t **)luaL_checkudata(L, 1, META_CAMERA)); - enum cameraf field = luaL_checkoption(L, 2, NULL, camera_opt); + enum cameraf field = Lua_optoption(L, 2, -1, camera_fields_ref); // cameras should always be valid unless I'm a nutter I_Assert(cam != NULL); @@ -1178,6 +1188,41 @@ static int libd_getDrawInfo(lua_State *L) return 3; } +static int libd_interpolate(lua_State *L) +{ + HUDONLY + + // do type checking even if interpolation is disabled + boolean newinterpolate; + UINT8 newtag; + + if (lua_isnumber(L, 1)) + { + newinterpolate = true; + newtag = luaL_checkinteger(L, 1); + } + else + { + newinterpolate = luaL_checkboolean(L, 1); + newtag = 0; + } + + if (!cv_uncappedhud.value) + return 0; + + hud_interpolate = newinterpolate; + hud_interptag = newtag; + + return 0; +} + +static int libd_interpLatch(lua_State *L) +{ + HUDONLY + hud_interpstring = hud_interplatch = luaL_checkboolean(L, 1); + return 0; +} + static luaL_Reg lib_draw[] = { {"patchExists", libd_patchExists}, {"cachePatch", libd_cachePatch}, @@ -1205,6 +1250,8 @@ static luaL_Reg lib_draw[] = { {"getDrawInfo", libd_getDrawInfo}, {"getHudColor", libd_getHudColor}, {"useColorHud", libd_useColorHud}, + {"interpolate", libd_interpolate}, + {"interpLatch", libd_interpLatch}, {NULL, NULL} }; @@ -1396,11 +1443,15 @@ int LUA_HudLib(lua_State *L) lua_setfield(L, -2, "__newindex"); lua_pop(L,1); + patch_fields_ref = Lua_CreateFieldTable(L, patch_opt); + luaL_newmetatable(L, META_CAMERA); lua_pushcfunction(L, camera_get); lua_setfield(L, -2, "__index"); lua_pop(L,1); + camera_fields_ref = Lua_CreateFieldTable(L, camera_opt); + luaL_register(L, "hud", lib_hud); return 0; } @@ -1413,7 +1464,7 @@ boolean LUA_HudEnabled(enum hud option) } // Hook for HUD rendering -void LUAh_GameHUD(player_t *stplayr, huddrawlist_h list) +void LUAh_GameHUD(huddrawlist_h list) { if (!gL || !(hudAvailable & (1< 2 && stplayr == &players[displayplayers[3]]) - { - LUA_PushUserdata(gL, &camera[3], META_CAMERA); - camnum = 4; - } - else if (splitscreen > 1 && stplayr == &players[displayplayers[2]]) - { - LUA_PushUserdata(gL, &camera[2], META_CAMERA); - camnum = 3; - } - else if (splitscreen && stplayr == &players[displayplayers[1]]) - { - LUA_PushUserdata(gL, &camera[1], META_CAMERA); - camnum = 2; - } - else - { - LUA_PushUserdata(gL, &camera[0], META_CAMERA); - camnum = 1; - } + LUA_PushUserdata(gL, stplyr, META_PLAYER); + LUA_PushUserdata(gL, &camera[stplyrnum], META_CAMERA); + camnum = stplyrnum + 1; + hud_interpcounter = 0; lua_pushnil(gL); while (lua_next(gL, -5) != 0) { + hud_interpolate = hud_interpstring = hud_interplatch = false; + hud_interpcounter++; lua_pushvalue(gL, -5); // graphics library (HUD[1]) - lua_pushvalue(gL, -5); // stplayr + lua_pushvalue(gL, -5); // stplyr lua_pushvalue(gL, -5); // camera LUA_Call(gL, 3, 0, 1); } @@ -1493,7 +1528,10 @@ void LUAh_ScoresHUD(huddrawlist_h list) I_Assert(lua_istable(gL, -1)); lua_remove(gL, -3); // pop HUD lua_pushnil(gL); + hud_interpcounter = 0; while (lua_next(gL, -3) != 0) { + hud_interpolate = hud_interpstring = hud_interplatch = false; + hud_interpcounter++; lua_pushvalue(gL, -3); // graphics library (HUD[1]) LUA_Call(gL, 1, 0, 1); } @@ -1526,7 +1564,10 @@ void LUAh_IntermissionHUD(huddrawlist_h list) I_Assert(lua_istable(gL, -1)); lua_remove(gL, -3); // pop HUD lua_pushnil(gL); + hud_interpcounter = 0; while (lua_next(gL, -3) != 0) { + hud_interpolate = hud_interpstring = hud_interplatch = false; + hud_interpcounter++; lua_pushvalue(gL, -3); // graphics library (HUD[1]) LUA_Call(gL, 1, 0, 1); } @@ -1559,7 +1600,10 @@ void LUAh_VoteHUD(huddrawlist_h list) I_Assert(lua_istable(gL, -1)); lua_remove(gL, -3); // pop HUD lua_pushnil(gL); + hud_interpcounter = 0; while (lua_next(gL, -3) != 0) { + hud_interpolate = hud_interpstring = hud_interplatch = false; + hud_interpcounter++; lua_pushvalue(gL, -3); // graphics library (HUD[1]) LUA_Call(gL, 1, 0, 1); } diff --git a/src/lua_hudlib_drawlist.c b/src/lua_hudlib_drawlist.c index de1f234c3..2ee9b8156 100644 --- a/src/lua_hudlib_drawlist.c +++ b/src/lua_hudlib_drawlist.c @@ -11,11 +11,16 @@ /// \brief a data structure for managing cached drawlists for the Lua hud lib #include "lua_hudlib_drawlist.h" +#include "lua_hud.h" +#include "blua/lstate.h" // shhhhhh +#include "lua_libs.h" #include #include "v_video.h" #include "z_zone.h" +#include "r_main.h" +#include "r_fps.h" enum drawitem_e { DI_Draw = 0, @@ -34,37 +39,45 @@ enum drawitem_e { // A single draw item with all possible arguments needed for a draw call. typedef struct drawitem_s { + UINT64 id; enum drawitem_e type; fixed_t x; fixed_t y; - fixed_t w; - fixed_t h; - INT32 c; - fixed_t scale; - fixed_t hscale; - fixed_t vscale; - patch_t *patch; - INT32 flags; - UINT16 basecolor; - UINT16 outlinecolor; + union { + INT32 flags; + INT32 c; + }; + + union { + fixed_t scale; // drawScaled + fixed_t hscale; // drawStretched + fixed_t w; // drawFill + INT32 align; // drawString + INT32 num; // drawNum, drawPaddedNum, drawPingNum + UINT16 color; // fadeScreen + }; + union { + fixed_t vscale; // drawStretched + fixed_t h; // drawFill + INT32 digits; // drawPaddedNum + UINT8 strength; // fadeScreen + }; + + // pointers (and size_t's) last, for potentially better packing + union { + patch_t *patch; + size_t stroffset; // offset into strbuf to get str + }; const UINT8 *colormap; - UINT8 *basecolormap; - UINT8 *outlinecolormap; - fixed_t sx; - fixed_t sy; - INT32 num; - INT32 digits; - size_t stroffset; // offset into strbuf to get str - UINT16 color; - UINT8 strength; - INT32 align; } drawitem_t; // The internal structure of a drawlist. struct huddrawlist_s { drawitem_t *items; - size_t items_capacity; size_t items_len; + drawitem_t *olditems; + size_t olditems_len; + size_t capacity; char *strbuf; size_t strbuf_capacity; size_t strbuf_len; @@ -88,8 +101,10 @@ huddrawlist_h LUA_HUD_CreateDrawList(void) drawlist = (huddrawlist_h) Z_Calloc(sizeof(struct huddrawlist_s), PU_STATIC, NULL); drawlist->items = NULL; - drawlist->items_capacity = 0; drawlist->items_len = 0; + drawlist->olditems = NULL; + drawlist->olditems_len = 0; + drawlist->capacity = 0; drawlist->strbuf = NULL; drawlist->strbuf_capacity = 0; drawlist->strbuf_len = 0; @@ -99,15 +114,14 @@ huddrawlist_h LUA_HUD_CreateDrawList(void) void LUA_HUD_ClearDrawList(huddrawlist_h list) { + // swap the old and new lists + void *tmp = list->olditems; + list->olditems = list->items; + list->items = tmp; + // rather than deallocate, we'll just save the existing allocation and empty // it out for reuse - - // this memset probably isn't necessary - if (list->items) - { - memset(list->items, 0, sizeof(drawitem_t) * list->items_capacity); - } - + list->olditems_len = list->items_len; list->items_len = 0; if (list->strbuf) @@ -125,6 +139,10 @@ void LUA_HUD_DestroyDrawList(huddrawlist_h list) { Z_Free(list->items); } + if (list->olditems) + { + Z_Free(list->olditems); + } if (list->strbuf) { Z_Free(list->strbuf); @@ -143,11 +161,11 @@ boolean LUA_HUD_IsDrawListValid(huddrawlist_h list) static size_t AllocateDrawItem(huddrawlist_h list) { if (!list) I_Error("can't allocate draw item: invalid list"); - if (list->items_capacity <= list->items_len + 1) + if (list->capacity <= list->items_len) { - if (list->items_capacity == 0) list->items_capacity = 128; - else list->items_capacity *= 2; - list->items = (drawitem_t *) Z_Realloc(list->items, sizeof(struct drawitem_s) * list->items_capacity, PU_STATIC, NULL); + list->capacity = list->capacity == 0 ? 128 : list->capacity * 2; + list->items = Z_Realloc(list->items, sizeof(struct drawitem_s) * list->capacity, PU_STATIC, NULL); + list->olditems = Z_Realloc(list->olditems, sizeof(struct drawitem_s) * list->capacity, PU_STATIC, NULL); } return list->items_len++; @@ -178,6 +196,149 @@ static size_t CopyString(huddrawlist_h list, const char* str) } } +static void CalcStringCoords(drawitem_t *item, const char *string) +{ + if (!(item->flags & V_NOSCALESTART) && cv_uncappedhud.value) + { + INT32 dupx = vid.dupx; + INT32 dupy = vid.dupy; + + item->flags |= V_NOSCALESTART; + + if (item->flags & V_SCALEPATCHMASK) switch ((item->flags & V_SCALEPATCHMASK) >> V_SCALEPATCHSHIFT) + { + case 1: // V_NOSCALEPATCH + dupx = dupy = 1; + break; + case 2: // V_SMALLSCALEPATCH + dupx = vid.smalldupx; + dupy = vid.smalldupy; + break; + case 3: // V_MEDSCALEPATCH + dupx = vid.meddupx; + dupy = vid.meddupy; + break; + default: + break; + } + + // only use one dup, to avoid stretching (har har) + dupx = dupy = (dupx < dupy ? dupx : dupy); + + INT32 x = item->x * dupx; + INT32 y = item->y * dupy; + + if (item->flags & V_SPLITSCREEN) + y += (BASEVIDHEIGHT * (dupy - 1))/2; + + if (item->flags & V_HORZSCREEN) + x += (BASEVIDWIDTH * (dupx - 1))/2; + + if (vid.width != BASEVIDWIDTH * dupx) + { + // dupx adjustments pretend that screen width is BASEVIDWIDTH * dupx, + // so center this imaginary screen + if ((item->flags & (V_HORZSCREEN|V_SNAPTOLEFT)) == (V_HORZSCREEN|V_SNAPTOLEFT)) + x += (vid.width/2 - (BASEVIDWIDTH/2 * dupx)); + else if (item->flags & V_SNAPTORIGHT) + x += (vid.width - (BASEVIDWIDTH * dupx)); + else if (!(item->flags & V_SNAPTOLEFT)) + x += (vid.width - (BASEVIDWIDTH * dupx)) / 2; + } + if (vid.height != BASEVIDHEIGHT * dupy) + { + // same thing here + if ((item->flags & (V_SPLITSCREEN|V_SNAPTOTOP)) == (V_SPLITSCREEN|V_SNAPTOTOP)) + y += (vid.height/2 - (BASEVIDHEIGHT/2 * dupy)); + else if (item->flags & V_SNAPTOBOTTOM) + y += (vid.height - (BASEVIDHEIGHT * dupy)); + else if (!(item->flags & V_SNAPTOTOP)) + y += (vid.height - (BASEVIDHEIGHT * dupy)) / 2; + } + + // need to compensate for dup here + if (item->type == DI_DrawString) + { + if (item->align == align_center) + x -= (V_StringWidth(string, item->flags) * (dupx - 1))/2; + if (item->align == align_right) + x -= V_StringWidth(string, item->flags) * (dupx - 1); + if (item->align == align_smallright) + x -= V_SmallStringWidth(string, item->flags) * (dupx - 1); + if (item->align == align_thinright) + x -= V_ThinStringWidth(string, item->flags) * (dupx - 1); + } + + item->x = x; + item->y = y; + } +} + +static void CalcFillCoords(drawitem_t *item) +{ + if (!(item->flags & V_NOSCALESTART) && cv_uncappedhud.value) + { + INT32 dupx = vid.dupx; + INT32 dupy = vid.dupy; + INT32 x = item->x * dupx; + INT32 y = item->y * dupy; + INT32 c = item->c; + + item->flags |= V_NOSCALESTART; + item->w *= dupx; + item->h *= dupy; + + // Center it if necessary + if (vid.width != BASEVIDWIDTH * dupx) + { + // dupx adjustments pretend that screen width is BASEVIDWIDTH * dupx, + // so center this imaginary screen + if (c & V_SNAPTORIGHT) + x += (vid.width - (BASEVIDWIDTH * dupx)); + else if (!(c & V_SNAPTOLEFT)) + x += (vid.width - (BASEVIDWIDTH * dupx)) / 2; + } + if (vid.height != BASEVIDHEIGHT * dupy) + { + // same thing here + if (c & V_SNAPTOBOTTOM) + y += (vid.height - (BASEVIDHEIGHT * dupy)); + else if (!(c & V_SNAPTOTOP)) + y += (vid.height - (BASEVIDHEIGHT * dupy)) / 2; + } + if (c & V_SPLITSCREEN) + y += (BASEVIDHEIGHT * dupy)/2; + if (c & V_HORZSCREEN) + x += (BASEVIDWIDTH * dupx)/2; + + item->x = x; + item->y = y; + } +} + +#define INTERP_LATCH 1 +#define INTERP_STRING 2 +#define INTERP_FLAGMASK 0x3 + +static UINT64 GetItemId(void) +{ + if (!hud_interpolate) + return 0; + + // leave bits 0 and 1 free for the string mode + UINT64 id = ((UINT64)(uintptr_t)gL->savedpc << 32) | (hud_interpcounter << 10) | (hud_interptag << 2); + + if (hud_interplatch) + { + id |= INTERP_LATCH; + hud_interplatch = false; + } + if (hud_interpstring) + id |= INTERP_STRING; + + return id; +} + void LUA_HUD_AddDraw( huddrawlist_h list, INT32 x, @@ -189,9 +350,10 @@ void LUA_HUD_AddDraw( { size_t i = AllocateDrawItem(list); drawitem_t *item = &list->items[i]; + item->id = GetItemId(); item->type = DI_Draw; - item->x = x; - item->y = y; + item->x = x << FRACBITS; + item->y = y << FRACBITS; item->patch = patch; item->flags = flags; item->colormap = colormap; @@ -209,6 +371,7 @@ void LUA_HUD_AddDrawScaled( { size_t i = AllocateDrawItem(list); drawitem_t *item = &list->items[i]; + item->id = GetItemId(); item->type = DI_DrawScaled; item->x = x; item->y = y; @@ -231,6 +394,7 @@ void LUA_HUD_AddDrawStretched( { size_t i = AllocateDrawItem(list); drawitem_t *item = &list->items[i]; + item->id = GetItemId(); item->type = DI_DrawStretched; item->x = x; item->y = y; @@ -251,11 +415,13 @@ void LUA_HUD_AddDrawNum( { size_t i = AllocateDrawItem(list); drawitem_t *item = &list->items[i]; + item->id = GetItemId(); item->type = DI_DrawNum; item->x = x; item->y = y; item->num = num; item->flags = flags; + CalcStringCoords(item, NULL); } void LUA_HUD_AddDrawPaddedNum( @@ -269,12 +435,14 @@ void LUA_HUD_AddDrawPaddedNum( { size_t i = AllocateDrawItem(list); drawitem_t *item = &list->items[i]; + item->id = GetItemId(); item->type = DI_DrawPaddedNum; item->x = x; item->y = y; item->num = num; item->digits = digits; item->flags = flags; + CalcStringCoords(item, NULL); } void LUA_HUD_AddDrawPingNum( @@ -288,12 +456,14 @@ void LUA_HUD_AddDrawPingNum( { size_t i = AllocateDrawItem(list); drawitem_t *item = &list->items[i]; + item->id = GetItemId(); item->type = DI_DrawPingNum; item->x = x; item->y = y; item->num = num; item->flags = flags; item->colormap = colormap; + CalcStringCoords(item, NULL); } void LUA_HUD_AddDrawFill( @@ -307,12 +477,14 @@ void LUA_HUD_AddDrawFill( { size_t i = AllocateDrawItem(list); drawitem_t *item = &list->items[i]; + item->id = GetItemId(); item->type = DI_DrawFill; item->x = x; item->y = y; item->w = w; item->h = h; item->c = c; + CalcFillCoords(item); } void LUA_HUD_AddDrawString( @@ -326,12 +498,15 @@ void LUA_HUD_AddDrawString( { size_t i = AllocateDrawItem(list); drawitem_t *item = &list->items[i]; + item->id = GetItemId(); item->type = DI_DrawString; item->x = x; item->y = y; item->stroffset = CopyString(list, str); item->flags = flags; item->align = align; + if (item->align != align_fixed) + CalcStringCoords(item, str); } void LUA_HUD_AddDrawKartString( @@ -344,11 +519,13 @@ void LUA_HUD_AddDrawKartString( { size_t i = AllocateDrawItem(list); drawitem_t *item = &list->items[i]; + item->id = GetItemId(); item->type = DI_DrawKartString; item->x = x; item->y = y; item->stroffset = CopyString(list, str); item->flags = flags; + CalcStringCoords(item, str); } void LUA_HUD_AddDrawLevelTitle( @@ -361,11 +538,13 @@ void LUA_HUD_AddDrawLevelTitle( { size_t i = AllocateDrawItem(list); drawitem_t *item = &list->items[i]; + item->id = GetItemId(); item->type = DI_DrawLevelTitle; item->x = x; item->y = y; item->stroffset = CopyString(list, str); item->flags = flags; + CalcStringCoords(item, str); } void LUA_HUD_AddFadeScreen( @@ -376,6 +555,8 @@ void LUA_HUD_AddFadeScreen( { size_t i = AllocateDrawItem(list); drawitem_t *item = &list->items[i]; + // nothing to interpolate here + item->id = 0; item->type = DI_FadeScreen; item->color = color; item->strength = strength; @@ -384,6 +565,11 @@ void LUA_HUD_AddFadeScreen( void LUA_HUD_DrawList(huddrawlist_h list) { size_t i; + size_t j = 0; + fixed_t frac = R_UsingFrameInterpolation() ? rendertimefrac : FRACUNIT; + fixed_t lerpx = 0, lerpy = 0; + drawitem_t *latchitem = NULL; + drawitem_t *oldlatchitem = NULL; if (!list) I_Error("HUD drawlist invalid"); if (list->items_len <= 0) return; @@ -392,68 +578,117 @@ void LUA_HUD_DrawList(huddrawlist_h list) for (i = 0; i < list->items_len; i++) { drawitem_t *item = &list->items[i]; + drawitem_t *olditem = NULL; const char *itemstr = &list->strbuf[item->stroffset]; + if (item->id) + { + // find the old one too + // this is kinda cursed... we need to check every item + // but stop when the first-checked item is reached again + size_t stop = j; + do + { + if (j == list->olditems_len) + { + j = 0; + continue; + } + drawitem_t *old = &list->olditems[j++]; + if ((old->id & ~INTERP_FLAGMASK) == (item->id & ~INTERP_FLAGMASK)) + { + // gotcha! + olditem = old; + if (item->id & INTERP_LATCH) + { + lerpx = FixedMul(frac, item->x - olditem->x); + lerpy = FixedMul(frac, item->y - olditem->y); + latchitem = item; + oldlatchitem = olditem; + } + else if (!(item->id & INTERP_STRING)) + { + lerpx = FixedMul(frac, item->x - olditem->x); + lerpy = FixedMul(frac, item->y - olditem->y); + latchitem = NULL; + } + break; + } + } + while (j != stop); + } + else + { + lerpx = lerpy = 0; + latchitem = NULL; + } + + #define LERP(it) (olditem ? olditem->it + FixedMul(frac, item->it - olditem->it) : item->it) + + // half of this could be done when the coordinates are latched... zzzzzz + #define LERPS(it) (latchitem ? ((latchitem->it + (item->it - latchitem->it)) - (latchitem->it - oldlatchitem->it)) + lerp##it : (olditem ? olditem->it + lerp##it : item->it)) + //define LERPS(it) (olditem ? (latchitem ? (latchitem->it + (item->it - latchitem->it)) - (latchitem->it - oldlatchitem->it) : olditem->it) + lerp##it : item->it) + switch (item->type) { case DI_Draw: - V_DrawFixedPatch(item->x<y<flags, item->patch, item->colormap); + V_DrawFixedPatch(LERPS(x), LERPS(y), FRACUNIT, item->flags, item->patch, item->colormap); break; case DI_DrawScaled: - V_DrawFixedPatch(item->x, item->y, item->scale, item->flags, item->patch, item->colormap); + V_DrawFixedPatch(LERPS(x), LERPS(y), LERP(scale), item->flags, item->patch, item->colormap); break; case DI_DrawStretched: - V_DrawStretchyFixedPatch(item->x, item->y, item->hscale, item->vscale, item->flags, item->patch, item->colormap); + V_DrawStretchyFixedPatch(LERPS(x), LERPS(y), LERP(hscale), LERP(vscale), item->flags, item->patch, item->colormap); break; case DI_DrawNum: - V_DrawTallNum(item->x, item->y, item->flags, item->num); + V_DrawTallNum(LERPS(x), LERPS(y), item->flags, item->num); break; case DI_DrawPaddedNum: - V_DrawPaddedTallNum(item->x, item->y, item->flags, item->num, item->digits); + V_DrawPaddedTallNum(LERPS(x), LERPS(y), item->flags, item->num, item->digits); break; case DI_DrawPingNum: - V_DrawPingNum(item->x, item->y, item->flags, item->num, item->colormap); + V_DrawPingNum(LERPS(x), LERPS(y), item->flags, item->num, item->colormap); break; case DI_DrawFill: - V_DrawFill(item->x, item->y, item->w, item->h, item->c); + V_DrawFill(LERPS(x), LERPS(y), LERP(w), LERP(h), item->c); break; case DI_DrawString: switch(item->align) { // hu_font case align_left: - V_DrawString(item->x, item->y, item->flags, itemstr); + V_DrawString(LERPS(x), LERPS(y), item->flags, itemstr); break; case align_center: - V_DrawCenteredString(item->x, item->y, item->flags, itemstr); + V_DrawCenteredString(LERPS(x), LERPS(y), item->flags, itemstr); break; case align_right: - V_DrawRightAlignedString(item->x, item->y, item->flags, itemstr); + V_DrawRightAlignedString(LERPS(x), LERPS(y), item->flags, itemstr); break; case align_fixed: - V_DrawStringAtFixed(item->x, item->y, item->flags, itemstr); + V_DrawStringAtFixed(LERPS(x), LERPS(y), item->flags, itemstr); break; // hu_font, 0.5x scale case align_small: - V_DrawSmallString(item->x, item->y, item->flags, itemstr); + V_DrawSmallString(LERPS(x), LERPS(y), item->flags, itemstr); break; case align_smallright: - V_DrawRightAlignedSmallString(item->x, item->y, item->flags, itemstr); + V_DrawRightAlignedSmallString(LERPS(x), LERPS(y), item->flags, itemstr); break; // tny_font case align_thin: - V_DrawThinString(item->x, item->y, item->flags, itemstr); + V_DrawThinString(LERPS(x), LERPS(y), item->flags, itemstr); break; case align_thinright: - V_DrawRightAlignedThinString(item->x, item->y, item->flags, itemstr); + V_DrawRightAlignedThinString(LERPS(x), LERPS(y), item->flags, itemstr); break; } break; case DI_DrawKartString: - V_DrawKartString(item->x, item->y, item->flags, itemstr); + V_DrawKartString(LERPS(x), LERPS(y), item->flags, itemstr); break; case DI_DrawLevelTitle: - V_DrawLevelTitle(item->x, item->y, item->flags, itemstr); + V_DrawLevelTitle(LERPS(x), LERPS(y), item->flags, itemstr); break; case DI_FadeScreen: V_DrawFadeScreen(item->color, item->strength); diff --git a/src/lua_infolib.c b/src/lua_infolib.c index c94b42b5b..8754176ed 100644 --- a/src/lua_infolib.c +++ b/src/lua_infolib.c @@ -23,34 +23,10 @@ #include "lua_hud.h" // hud_running errors #include "lua_hook.h" // cmd errors -boolean LUA_CallAction(const char *action, mobj_t *actor); +boolean LUA_CallAction(enum actionnum actionnum, mobj_t *actor); state_t *astate; -enum sfxinfo_read { - sfxinfor_name = 0, - sfxinfor_singular, - sfxinfor_priority, - sfxinfor_flags, // "pitch" - sfxinfor_skinsound -}; -const char *const sfxinfo_ropt[] = { - "name", - "singular", - "priority", - "flags", - "skinsound", - NULL}; - -enum sfxinfo_write { - sfxinfow_singular = 0, - sfxinfow_priority, - sfxinfow_flags // "pitch" -}; -const char *const sfxinfo_wopt[] = { - "singular", - "priority", - "flags", - NULL}; +boolean actionsoverridden[NUMACTIONS] = {false}; // // Sprite Names @@ -101,7 +77,7 @@ static void A_Lua(mobj_t *actor) { boolean found = false; I_Assert(actor != NULL); - + lua_settop(gL, 0); // Just in case... lua_pushcfunction(gL, LUA_GetErrorMessage); @@ -276,27 +252,21 @@ boolean LUA_SetLuaAction(void *stv, const char *action) return true; // action successfully set. } -boolean LUA_CallAction(const char *csaction, mobj_t *actor) +boolean LUA_CallAction(enum actionnum actionnum, mobj_t *actor) { - I_Assert(csaction != NULL); I_Assert(actor != NULL); - if (!gL) // Lua isn't loaded, + if (!actionsoverridden[actionnum]) // The action is not overriden, return false; // action not called. - if (superstack && fasticmp(csaction, superactions[superstack-1])) // the action is calling itself, - return false; // let it call the hardcoded function instead. + if (superstack && fasticmp(actionpointers[actionnum].name, superactions[superstack-1])) // the action is calling itself, + return false; // let it call the hardcoded function lua_pushcfunction(gL, LUA_GetErrorMessage); // grab function by uppercase name. lua_getfield(gL, LUA_REGISTRYINDEX, LREG_ACTIONS); - { - char *action = Z_StrDup(csaction); - strupr(action); - lua_getfield(gL, -1, action); - Z_Free(action); - } + lua_getfield(gL, -1, actionpointers[actionnum].name); lua_remove(gL, -2); // pop LREG_ACTIONS if (lua_isnil(gL, -1)) // no match @@ -319,7 +289,7 @@ boolean LUA_CallAction(const char *csaction, mobj_t *actor) lua_pushinteger(gL, var1); lua_pushinteger(gL, var2); - superactions[superstack] = csaction; + superactions[superstack] = actionpointers[actionnum].name; ++superstack; LUA_Call(gL, 3, 0, -(2 + 3)); @@ -330,49 +300,93 @@ boolean LUA_CallAction(const char *csaction, mobj_t *actor) return true; // action successfully called. } +enum state_e { + state_sprite = 0, + state_frame, + state_tics, + state_action, + state_var1, + state_var2, + state_nextstate, +}; + +const char *const state_opt[] = { + "sprite", + "frame", + "tics", + "action", + "var1", + "var2", + "nextstate", + NULL +}; + +static int state_fields_ref = LUA_NOREF; + // state_t *, field -> number static int state_get(lua_State *L) { state_t *st = *((state_t **)luaL_checkudata(L, 1, META_STATE)); - const char *field = luaL_checkstring(L, 2); + enum state_e field = Lua_optoption(L, 2, -1, state_fields_ref); lua_Integer number; - if (fastcmp(field,"sprite")) - number = st->sprite; - else if (fastcmp(field,"frame")) - number = st->frame; - else if (fastcmp(field,"tics")) - number = st->tics; - else if (fastcmp(field,"action")) { - const char *name; - if (!st->action.acp1) // Action is NULL. - return 0; // return nil. - if (st->action.acp1 == (actionf_p1)A_Lua) { // This is a Lua function? - lua_getfield(L, LUA_REGISTRYINDEX, LREG_STATEACTION); - I_Assert(lua_istable(L, -1)); - lua_pushlightuserdata(L, st); // Push the state pointer and - lua_rawget(L, -2); // use it to get the actual Lua function. - lua_remove(L, -2); // pop LREG_STATEACTION - return 1; // Return the Lua function. + switch (field) + { + case state_sprite: + number = st->sprite; + break; + + case state_frame: + number = st->frame; + break; + + case state_tics: + number = st->tics; + break; + + case state_action: + { + const char *name; + if (!st->action.acp1) // Action is NULL. + return 0; // return nil. + if (st->action.acp1 == (actionf_p1)A_Lua) { // This is a Lua function? + lua_getfield(L, LUA_REGISTRYINDEX, LREG_STATEACTION); + I_Assert(lua_istable(L, -1)); + lua_pushlightuserdata(L, st); // Push the state pointer and + lua_rawget(L, -2); // use it to get the actual Lua function. + lua_remove(L, -2); // pop LREG_STATEACTION + return 1; // Return the Lua function. + } + name = LUA_GetActionName(&st->action); // find a hardcoded function name + if (!name) // If it's not a hardcoded function and it's not a Lua function... + return 0; // Just what is this?? + // get the function from the global + // because the metatable will trigger. + lua_getglobal(L, name); // actually gets from LREG_ACTIONS if applicable, and pushes a new C closure if not. + lua_pushstring(L, name); // push the name we found. + return 2; // return both the function and its name, in case somebody wanted to do a comparison by name or something? } - name = LUA_GetActionName(&st->action); // find a hardcoded function name - if (!name) // If it's not a hardcoded function and it's not a Lua function... - return 0; // Just what is this?? - // get the function from the global - // because the metatable will trigger. - lua_getglobal(L, name); // actually gets from LREG_ACTIONS if applicable, and pushes a new C closure if not. - lua_pushstring(L, name); // push the name we found. - return 2; // return both the function and its name, in case somebody wanted to do a comparison by name or something? - } else if (fastcmp(field,"var1")) - number = st->var1; - else if (fastcmp(field,"var2")) - number = st->var2; - else if (fastcmp(field,"nextstate")) - number = st->nextstate; - else if (devparm) - return luaL_error(L, LUA_QL("state_t") " has no field named " LUA_QS, field); - else - return 0; + break; + + case state_var1: + number = st->var1; + break; + + case state_var2: + number = st->var2; + break; + + case state_nextstate: + number = st->nextstate; + break; + + default: + { + if (devparm) + return luaL_error(L, LUA_QL("state_t") " has no field named " LUA_QS, field); + return 0; + } + } lua_pushinteger(L, number); return 1; @@ -382,7 +396,7 @@ static int state_get(lua_State *L) static int state_set(lua_State *L) { state_t *st = *((state_t **)luaL_checkudata(L, 1, META_STATE)); - const char *field = luaL_checkstring(L, 2); + enum state_e field = Lua_optoption(L, 2, -1, state_fields_ref); lua_Integer value; if (hud_running) @@ -390,16 +404,24 @@ static int state_set(lua_State *L) if (hook_cmd_running) return luaL_error(L, "Do not alter states in BuildCMD code!"); - if (fastcmp(field,"sprite")) { + switch (field) + { + case state_sprite: value = luaL_checknumber(L, 3); if (value < SPR_NULL || value >= NUMSPRITES) return luaL_error(L, "sprite number %d is invalid.", value); st->sprite = (spritenum_t)value; - } else if (fastcmp(field,"frame")) + break; + + case state_frame: st->frame = (UINT32)luaL_checknumber(L, 3); - else if (fastcmp(field,"tics")) + break; + + case state_tics: st->tics = (INT32)luaL_checknumber(L, 3); - else if (fastcmp(field,"action")) { + break; + + case state_action: switch(lua_type(L, 3)) { case LUA_TNIL: // Null? Set the action to nothing, then. @@ -420,17 +442,26 @@ static int state_set(lua_State *L) default: // ?! return luaL_typerror(L, 3, "function"); } - } else if (fastcmp(field,"var1")) + break; + + case state_var1: st->var1 = (INT32)luaL_checknumber(L, 3); - else if (fastcmp(field,"var2")) + break; + + case state_var2: st->var2 = (INT32)luaL_checknumber(L, 3); - else if (fastcmp(field,"nextstate")) { + break; + + case state_nextstate: value = luaL_checkinteger(L, 3); if (value < S_NULL || value >= NUMSTATES) return luaL_error(L, "nextstate number %d is invalid.", value); st->nextstate = (statenum_t)value; - } else + break; + + default: return luaL_error(L, LUA_QL("state_t") " has no field named " LUA_QS, field); + } return 0; } @@ -565,75 +596,161 @@ static int lib_mobjinfolen(lua_State *L) return 1; } +enum mobjinfo_e +{ + mobjinfo_doomednum, + mobjinfo_spawnstate, + mobjinfo_spawnhealth, + mobjinfo_seestate, + mobjinfo_seesound, + mobjinfo_reactiontime, + mobjinfo_attacksound, + mobjinfo_painstate, + mobjinfo_painchance, + mobjinfo_painsound, + mobjinfo_meleestate, + mobjinfo_missilestate, + mobjinfo_deathstate, + mobjinfo_xdeathstate, + mobjinfo_deathsound, + mobjinfo_speed, + mobjinfo_radius, + mobjinfo_height, + mobjinfo_dispoffset, + mobjinfo_mass, + mobjinfo_damage, + mobjinfo_activesound, + mobjinfo_flags, + mobjinfo_raisestate, +}; + +const char *const mobjinfo_opt[] = { + "doomednum", + "spawnstate", + "spawnhealth", + "seestate", + "seesound", + "reactiontime", + "attacksound", + "painstate", + "painchance", + "painsound", + "meleestate", + "missilestate", + "deathstate", + "xdeathstate", + "deathsound", + "speed", + "radius", + "height", + "dispoffset", + "mass", + "damage", + "activesound", + "flags", + "raisestate", + NULL, +}; + +static int mobjinfo_fields_ref = LUA_NOREF; + // mobjinfo_t *, field -> number static int mobjinfo_get(lua_State *L) { mobjinfo_t *info = *((mobjinfo_t **)luaL_checkudata(L, 1, META_MOBJINFO)); - const char *field = luaL_checkstring(L, 2); + enum mobjinfo_e field = Lua_optoption(L, 2, -1, mobjinfo_fields_ref); I_Assert(info != NULL); I_Assert(info >= mobjinfo); - if (fastcmp(field,"doomednum")) + switch (field) + { + case mobjinfo_doomednum: lua_pushinteger(L, info->doomednum); - else if (fastcmp(field,"spawnstate")) + break; + case mobjinfo_spawnstate: lua_pushinteger(L, info->spawnstate); - else if (fastcmp(field,"spawnhealth")) + break; + case mobjinfo_spawnhealth: lua_pushinteger(L, info->spawnhealth); - else if (fastcmp(field,"seestate")) + break; + case mobjinfo_seestate: lua_pushinteger(L, info->seestate); - else if (fastcmp(field,"seesound")) + break; + case mobjinfo_seesound: lua_pushinteger(L, info->seesound); - else if (fastcmp(field,"reactiontime")) + break; + case mobjinfo_reactiontime: lua_pushinteger(L, info->reactiontime); - else if (fastcmp(field,"attacksound")) + break; + case mobjinfo_attacksound: lua_pushinteger(L, info->attacksound); - else if (fastcmp(field,"painstate")) + break; + case mobjinfo_painstate: lua_pushinteger(L, info->painstate); - else if (fastcmp(field,"painchance")) + break; + case mobjinfo_painchance: lua_pushinteger(L, info->painchance); - else if (fastcmp(field,"painsound")) + break; + case mobjinfo_painsound: lua_pushinteger(L, info->painsound); - else if (fastcmp(field,"meleestate")) + break; + case mobjinfo_meleestate: lua_pushinteger(L, info->meleestate); - else if (fastcmp(field,"missilestate")) + break; + case mobjinfo_missilestate: lua_pushinteger(L, info->missilestate); - else if (fastcmp(field,"deathstate")) + break; + case mobjinfo_deathstate: lua_pushinteger(L, info->deathstate); - else if (fastcmp(field,"xdeathstate")) + break; + case mobjinfo_xdeathstate: lua_pushinteger(L, info->xdeathstate); - else if (fastcmp(field,"deathsound")) + break; + case mobjinfo_deathsound: lua_pushinteger(L, info->deathsound); - else if (fastcmp(field,"speed")) + break; + case mobjinfo_speed: lua_pushinteger(L, info->speed); // sometimes it's fixed_t, sometimes it's not... - else if (fastcmp(field,"radius")) + break; + case mobjinfo_radius: lua_pushfixed(L, info->radius); - else if (fastcmp(field,"height")) + break; + case mobjinfo_height: lua_pushfixed(L, info->height); - else if (fastcmp(field,"dispoffset")) + break; + case mobjinfo_dispoffset: lua_pushinteger(L, info->dispoffset); - else if (fastcmp(field,"mass")) + break; + case mobjinfo_mass: lua_pushinteger(L, info->mass); - else if (fastcmp(field,"damage")) + break; + case mobjinfo_damage: lua_pushinteger(L, info->damage); - else if (fastcmp(field,"activesound")) + break; + case mobjinfo_activesound: lua_pushinteger(L, info->activesound); - else if (fastcmp(field,"flags")) + break; + case mobjinfo_flags: lua_pushinteger(L, info->flags); - else if (fastcmp(field,"raisestate")) + break; + case mobjinfo_raisestate: lua_pushinteger(L, info->raisestate); - else { + break; + default: lua_getfield(L, LUA_REGISTRYINDEX, LREG_EXTVARS); I_Assert(lua_istable(L, -1)); lua_pushlightuserdata(L, info); lua_rawget(L, -2); if (!lua_istable(L, -1)) { // no extra values table - CONS_Debug(DBG_LUA, M_GetText("'%s' has no field named '%s'; returning nil.\n"), "mobjinfo_t", field); + CONS_Debug(DBG_LUA, M_GetText("'%s' has no field named '%s'; returning nil.\n"), "mobjinfo_t", lua_tostring(L, 2)); return 0; } - lua_getfield(L, -1, field); + lua_pushvalue(L, 2); // field name + lua_gettable(L, -2); if (lua_isnil(L, -1)) // no value for this field - CONS_Debug(DBG_LUA, M_GetText("'%s' has no field named '%s'; returning nil.\n"), "mobjinfo_t", field); + CONS_Debug(DBG_LUA, M_GetText("'%s' has no field named '%s'; returning nil.\n"), "mobjinfo_t", lua_tostring(L, 2)); + break; } return 1; } @@ -642,7 +759,7 @@ static int mobjinfo_get(lua_State *L) static int mobjinfo_set(lua_State *L) { mobjinfo_t *info = *((mobjinfo_t **)luaL_checkudata(L, 1, META_MOBJINFO)); - const char *field = luaL_checkstring(L, 2); + enum mobjinfo_e field = Lua_optoption(L, 2, -1, mobjinfo_fields_ref); if (hud_running) return luaL_error(L, "Do not alter mobjinfo in HUD rendering code!"); @@ -652,55 +769,81 @@ static int mobjinfo_set(lua_State *L) I_Assert(info != NULL); I_Assert(info >= mobjinfo); - if (fastcmp(field,"doomednum")) + switch (field) + { + case mobjinfo_doomednum: info->doomednum = (INT32)luaL_checkinteger(L, 3); - else if (fastcmp(field,"spawnstate")) + break; + case mobjinfo_spawnstate: info->spawnstate = luaL_checkinteger(L, 3); - else if (fastcmp(field,"spawnhealth")) + break; + case mobjinfo_spawnhealth: info->spawnhealth = (INT32)luaL_checkinteger(L, 3); - else if (fastcmp(field,"seestate")) + break; + case mobjinfo_seestate: info->seestate = luaL_checkinteger(L, 3); - else if (fastcmp(field,"seesound")) + break; + case mobjinfo_seesound: info->seesound = luaL_checkinteger(L, 3); - else if (fastcmp(field,"reactiontime")) + break; + case mobjinfo_reactiontime: info->reactiontime = (INT32)luaL_checkinteger(L, 3); - else if (fastcmp(field,"attacksound")) + break; + case mobjinfo_attacksound: info->attacksound = luaL_checkinteger(L, 3); - else if (fastcmp(field,"painstate")) + break; + case mobjinfo_painstate: info->painstate = luaL_checkinteger(L, 3); - else if (fastcmp(field,"painchance")) + break; + case mobjinfo_painchance: info->painchance = (INT32)luaL_checkinteger(L, 3); - else if (fastcmp(field,"painsound")) + break; + case mobjinfo_painsound: info->painsound = luaL_checkinteger(L, 3); - else if (fastcmp(field,"meleestate")) + break; + case mobjinfo_meleestate: info->meleestate = luaL_checkinteger(L, 3); - else if (fastcmp(field,"missilestate")) + break; + case mobjinfo_missilestate: info->missilestate = luaL_checkinteger(L, 3); - else if (fastcmp(field,"deathstate")) + break; + case mobjinfo_deathstate: info->deathstate = luaL_checkinteger(L, 3); - else if (fastcmp(field,"xdeathstate")) + break; + case mobjinfo_xdeathstate: info->xdeathstate = luaL_checkinteger(L, 3); - else if (fastcmp(field,"deathsound")) + break; + case mobjinfo_deathsound: info->deathsound = luaL_checkinteger(L, 3); - else if (fastcmp(field,"speed")) + break; + case mobjinfo_speed: info->speed = luaL_checkfixed(L, 3); - else if (fastcmp(field,"radius")) + break; + case mobjinfo_radius: info->radius = luaL_checkfixed(L, 3); - else if (fastcmp(field,"height")) + break; + case mobjinfo_height: info->height = luaL_checkfixed(L, 3); - else if (fastcmp(field,"dispoffset")) + break; + case mobjinfo_dispoffset: info->dispoffset = (INT32)luaL_checkinteger(L, 3); - else if (fastcmp(field,"mass")) + break; + case mobjinfo_mass: info->mass = (INT32)luaL_checkinteger(L, 3); - else if (fastcmp(field,"damage")) + break; + case mobjinfo_damage: info->damage = (INT32)luaL_checkinteger(L, 3); - else if (fastcmp(field,"activesound")) + break; + case mobjinfo_activesound: info->activesound = luaL_checkinteger(L, 3); - else if (fastcmp(field,"flags")) + break; + case mobjinfo_flags: info->flags = (INT32)luaL_checkinteger(L, 3); - else if (fastcmp(field,"raisestate")) + break; + case mobjinfo_raisestate: info->raisestate = luaL_checkinteger(L, 3); - else { + break; + default: lua_getfield(L, LUA_REGISTRYINDEX, LREG_EXTVARS); I_Assert(lua_istable(L, -1)); lua_pushlightuserdata(L, info); @@ -708,18 +851,17 @@ static int mobjinfo_set(lua_State *L) if (lua_isnil(L, -1)) { // This index doesn't have a table for extra values yet, let's make one. lua_pop(L, 1); - CONS_Debug(DBG_LUA, M_GetText("'%s' has no field named '%s'; adding it as Lua data.\n"), "mobjinfo_t", field); + CONS_Debug(DBG_LUA, M_GetText("'%s' has no field named '%s'; adding it as Lua data.\n"), "mobjinfo_t", lua_tostring(L, 2)); lua_newtable(L); lua_pushlightuserdata(L, info); lua_pushvalue(L, -2); // ext value table lua_rawset(L, -4); // LREG_EXTVARS table } + lua_pushvalue(L, 2); // key lua_pushvalue(L, 3); // value to store - lua_setfield(L, -2, field); + lua_settable(L, -3); lua_pop(L, 2); } - //else - //return luaL_error(L, LUA_QL("mobjinfo_t") " has no field named " LUA_QS, field); return 0; } @@ -752,6 +894,25 @@ static int lib_getSfxInfo(lua_State *L) return 1; } +enum sfxinfo_e { + sfxinfo_name = 0, + sfxinfo_singular, + sfxinfo_priority, + sfxinfo_flags, // "pitch" + sfxinfo_skinsound +}; + +const char *const sfxinfo_opt[] = { + "name", + "singular", + "priority", + "flags", + "skinsound", + NULL +}; + +static int sfxinfo_fields_ref = LUA_NOREF; + // stack: dummy, S_sfx[] table index, table of values to set. static int lib_setSfxInfo(lua_State *L) { @@ -775,22 +936,44 @@ static int lib_setSfxInfo(lua_State *L) lua_pushnil(L); while (lua_next(L, 1)) { - enum sfxinfo_write i; + enum sfxinfo_e i; if (lua_isnumber(L, 2)) - i = lua_tointeger(L, 2) - 1; // lua is one based, this enum is zero based. + { + int j = lua_tointeger(L, 2) - 1; + + // Read and Write enums were combined, need to do this switch now + switch (j) + { + case 1: + i = sfxinfo_singular; + break; + + case 2: + i = sfxinfo_priority; + break; + + case 3: + i = sfxinfo_flags; + break; + + default: + i = -1; + break; + } + } else - i = luaL_checkoption(L, 2, NULL, sfxinfo_wopt); + i = Lua_optoption(L, 2, -1, sfxinfo_fields_ref); switch(i) { - case sfxinfow_singular: + case sfxinfo_singular: info->singularity = luaL_checkboolean(L, 3); break; - case sfxinfow_priority: + case sfxinfo_priority: info->priority = (INT32)luaL_checkinteger(L, 3); break; - case sfxinfow_flags: + case sfxinfo_flags: info->pitch = (INT32)luaL_checkinteger(L, 3); break; default: @@ -812,29 +995,29 @@ static int lib_sfxlen(lua_State *L) static int sfxinfo_get(lua_State *L) { sfxinfo_t *sfx = *((sfxinfo_t **)luaL_checkudata(L, 1, META_SFXINFO)); - enum sfxinfo_read field = luaL_checkoption(L, 2, NULL, sfxinfo_ropt); + enum sfxinfo_e field = Lua_optoption(L, 2, -1, sfxinfo_fields_ref); I_Assert(sfx != NULL); switch (field) { - case sfxinfor_name: + case sfxinfo_name: lua_pushstring(L, sfx->name); return 1; - case sfxinfor_singular: + case sfxinfo_singular: lua_pushboolean(L, sfx->singularity); return 1; - case sfxinfor_priority: + case sfxinfo_priority: lua_pushinteger(L, sfx->priority); return 1; - case sfxinfor_flags: + case sfxinfo_flags: lua_pushinteger(L, sfx->pitch); return 1; - case sfxinfor_skinsound: + case sfxinfo_skinsound: lua_pushinteger(L, sfx->skinsound); return 1; default: - return luaL_error(L, "impossible error"); + return luaL_error(L, LUA_QL("sfxinfo_t") " has no field named " LUA_QS, lua_tostring(L, 2)); } return 0; } @@ -843,7 +1026,7 @@ static int sfxinfo_get(lua_State *L) static int sfxinfo_set(lua_State *L) { sfxinfo_t *sfx = *((sfxinfo_t **)luaL_checkudata(L, 1, META_SFXINFO)); - enum sfxinfo_write field = luaL_checkoption(L, 2, NULL, sfxinfo_wopt); + int field = Lua_optoption(L, 2, -1, sfxinfo_fields_ref); if (hud_running) return luaL_error(L, "Do not alter S_sfx in HUD rendering code!"); @@ -858,17 +1041,20 @@ static int sfxinfo_set(lua_State *L) switch (field) { - case sfxinfow_singular: + case sfxinfo_singular: sfx->singularity = luaL_checkboolean(L, 1); break; - case sfxinfow_priority: + case sfxinfo_priority: sfx->priority = luaL_checkinteger(L, 1); break; - case sfxinfow_flags: + case sfxinfo_flags: sfx->pitch = luaL_checkinteger(L, 1); break; default: - return luaL_error(L, "impossible error"); + if (field == -1) + return luaL_error(L, LUA_QL("sfxinfo_t") " has no field named " LUA_QS, lua_tostring(L, 2)); + else + return luaL_error(L, LUA_QL("sfxinfo_t") " field " LUA_QS " is read-only", lua_tostring(L, 2)); } return 0; } @@ -910,6 +1096,8 @@ int LUA_InfoLib(lua_State *L) lua_setfield(L, -2, "__len"); lua_pop(L, 1); + state_fields_ref = Lua_CreateFieldTable(L, state_opt); + luaL_newmetatable(L, META_MOBJINFO); lua_pushcfunction(L, mobjinfo_get); lua_setfield(L, -2, "__index"); @@ -921,6 +1109,8 @@ int LUA_InfoLib(lua_State *L) lua_setfield(L, -2, "__len"); lua_pop(L, 1); + mobjinfo_fields_ref = Lua_CreateFieldTable(L, mobjinfo_opt); + luaL_newmetatable(L, META_SFXINFO); lua_pushcfunction(L, sfxinfo_get); lua_setfield(L, -2, "__index"); @@ -932,6 +1122,8 @@ int LUA_InfoLib(lua_State *L) lua_setfield(L, -2, "__len"); lua_pop(L, 1); + sfxinfo_fields_ref = Lua_CreateFieldTable(L, sfxinfo_opt); + lua_newuserdata(L, 0); lua_createtable(L, 0, 2); lua_pushcfunction(L, lib_getSprname); @@ -983,4 +1175,4 @@ int LUA_InfoLib(lua_State *L) lua_setglobal(L, "S_sfx"); lua_setglobal(L, "sfxinfo"); return 0; -} \ No newline at end of file +} diff --git a/src/lua_maplib.c b/src/lua_maplib.c index 96222ba0a..d92cd1f8b 100644 --- a/src/lua_maplib.c +++ b/src/lua_maplib.c @@ -71,6 +71,8 @@ enum subsector_e { subsector_firstline, }; +static int sector_fields_ref = LUA_NOREF; + static const char *const subsector_opt[] = { "valid", "sector", @@ -78,6 +80,8 @@ static const char *const subsector_opt[] = { "firstline", NULL}; +static int subsector_fields_ref = LUA_NOREF; + enum line_e { line_valid = 0, line_v1, @@ -120,6 +124,8 @@ static const char *const line_opt[] = { "callcount", NULL}; +static int line_fields_ref = LUA_NOREF; + enum side_e { side_valid = 0, side_textureoffset, @@ -146,6 +152,8 @@ static const char *const side_opt[] = { "text", NULL}; +static int side_fields_ref = LUA_NOREF; + enum vertex_e { vertex_valid = 0, vertex_x, @@ -160,6 +168,8 @@ static const char *const vertex_opt[] = { "z", NULL}; +static int vertex_fields_ref = LUA_NOREF; + enum ffloor_e { ffloor_valid = 0, ffloor_topheight, @@ -196,6 +206,8 @@ static const char *const ffloor_opt[] = { "alpha", NULL}; +static int ffloor_fields_ref = LUA_NOREF; + enum slope_e { slope_valid = 0, slope_o, @@ -222,6 +234,8 @@ static const char *const slope_opt[] = { "flags", NULL}; +static int slope_fields_ref = LUA_NOREF; + // shared by both vector2_t and vector3_t enum vector_e { vector_x = 0, @@ -387,7 +401,7 @@ static int sectorlines_num(lua_State *L) static int sector_get(lua_State *L) { sector_t *sector = *((sector_t **)luaL_checkudata(L, 1, META_SECTOR)); - enum sector_e field = luaL_checkoption(L, 2, sector_opt[0], sector_opt); + enum sector_e field = Lua_optoption(L, 2, sector_valid, sector_fields_ref); INT16 i; if (!sector) @@ -473,7 +487,7 @@ static int sector_get(lua_State *L) static int sector_set(lua_State *L) { sector_t *sector = *((sector_t **)luaL_checkudata(L, 1, META_SECTOR)); - enum sector_e field = luaL_checkoption(L, 2, sector_opt[0], sector_opt); + enum sector_e field = Lua_optoption(L, 2, sector_valid, sector_fields_ref); if (!sector) return luaL_error(L, "accessed sector_t doesn't exist anymore."); @@ -551,7 +565,7 @@ static int sector_num(lua_State *L) static int subsector_get(lua_State *L) { subsector_t *subsector = *((subsector_t **)luaL_checkudata(L, 1, META_SUBSECTOR)); - enum subsector_e field = luaL_checkoption(L, 2, subsector_opt[0], subsector_opt); + enum subsector_e field = Lua_optoption(L, 2, subsector_valid, subsector_fields_ref); if (!subsector) { @@ -590,7 +604,7 @@ static int subsector_num(lua_State *L) static int line_get(lua_State *L) { line_t *line = *((line_t **)luaL_checkudata(L, 1, META_LINE)); - enum line_e field = luaL_checkoption(L, 2, line_opt[0], line_opt); + enum line_e field = Lua_optoption(L, 2, line_valid, line_fields_ref); if (!line) { @@ -715,7 +729,7 @@ static int sidenum_get(lua_State *L) static int side_get(lua_State *L) { side_t *side = *((side_t **)luaL_checkudata(L, 1, META_SIDE)); - enum side_e field = luaL_checkoption(L, 2, side_opt[0], side_opt); + enum side_e field = Lua_optoption(L, 2, side_valid, side_fields_ref); if (!side) { @@ -765,7 +779,7 @@ static int side_get(lua_State *L) static int side_set(lua_State *L) { side_t *side = *((side_t **)luaL_checkudata(L, 1, META_SIDE)); - enum side_e field = luaL_checkoption(L, 2, side_opt[0], side_opt); + enum side_e field = Lua_optoption(L, 2, side_valid, side_fields_ref); if (!side) { @@ -816,7 +830,7 @@ static int side_num(lua_State *L) static int vertex_get(lua_State *L) { vertex_t *vertex = *((vertex_t **)luaL_checkudata(L, 1, META_VERTEX)); - enum vertex_e field = luaL_checkoption(L, 2, vertex_opt[0], vertex_opt); + enum vertex_e field = Lua_optoption(L, 2, vertex_valid, vertex_fields_ref); if (!vertex) { @@ -1085,7 +1099,7 @@ static int lib_numvertexes(lua_State *L) static int ffloor_get(lua_State *L) { ffloor_t *ffloor = *((ffloor_t **)luaL_checkudata(L, 1, META_FFLOOR)); - enum ffloor_e field = luaL_checkoption(L, 2, ffloor_opt[0], ffloor_opt); + enum ffloor_e field = Lua_optoption(L, 2, ffloor_valid, ffloor_fields_ref); INT16 i; if (!ffloor) @@ -1161,7 +1175,7 @@ static int ffloor_get(lua_State *L) static int ffloor_set(lua_State *L) { ffloor_t *ffloor = *((ffloor_t **)luaL_checkudata(L, 1, META_FFLOOR)); - enum ffloor_e field = luaL_checkoption(L, 2, ffloor_opt[0], ffloor_opt); + enum ffloor_e field = Lua_optoption(L, 2, ffloor_valid, ffloor_fields_ref); if (!ffloor) return luaL_error(L, "accessed ffloor_t doesn't exist anymore."); @@ -1239,7 +1253,7 @@ static int ffloor_set(lua_State *L) static int slope_get(lua_State *L) { pslope_t *slope = *((pslope_t **)luaL_checkudata(L, 1, META_SLOPE)); - enum slope_e field = luaL_checkoption(L, 2, slope_opt[0], slope_opt); + enum slope_e field = Lua_optoption(L, 2, slope_valid, slope_fields_ref); if (!slope) { @@ -1289,7 +1303,7 @@ static int slope_get(lua_State *L) static int slope_set(lua_State *L) { pslope_t *slope = *((pslope_t **)luaL_checkudata(L, 1, META_SLOPE)); - enum slope_e field = luaL_checkoption(L, 2, slope_opt[0], slope_opt); + enum slope_e field = Lua_optoption(L, 2, slope_valid, slope_fields_ref); if (!slope) return luaL_error(L, "accessed pslope_t doesn't exist anymore."); @@ -1446,93 +1460,207 @@ static int lib_nummapheaders(lua_State *L) return 1; } +enum mapheaderinfo_e +{ + mapheaderinfo_lvlttl, + mapheaderinfo_subttl, + mapheaderinfo_zonttl, + mapheaderinfo_actnum, + mapheaderinfo_typeoflevel, + mapheaderinfo_nextlevel, + mapheaderinfo_musname, + mapheaderinfo_mustrack, + mapheaderinfo_muspos, + mapheaderinfo_musinterfadeout, + mapheaderinfo_musintername, + mapheaderinfo_forcecharacter, + mapheaderinfo_weather, + mapheaderinfo_skynum, + mapheaderinfo_skybox_scalex, + mapheaderinfo_skybox_scaley, + mapheaderinfo_skybox_scalez, + mapheaderinfo_interscreen, + mapheaderinfo_runsoc, + mapheaderinfo_scriptname, + mapheaderinfo_precutscenenum, + mapheaderinfo_cutscenenum, + mapheaderinfo_countdown, + mapheaderinfo_palette, + mapheaderinfo_numlaps, + mapheaderinfo_unlockrequired, + mapheaderinfo_levelselect, + mapheaderinfo_bonustype, + mapheaderinfo_saveoverride, + mapheaderinfo_levelflags, + mapheaderinfo_menuflags, + //mapheaderinfo_automap, + mapheaderinfo_mobj_scale, +}; + +static const char *const mapheaderinfo_opt[] = { + "lvlttl", + "subttl", + "zonttl", + "actnum", + "typeoflevel", + "nextlevel", + "musname", + "mustrack", + "muspos", + "musinterfadeout", + "musintername", + "forcecharacter", + "weather", + "skynum", + "skybox_scalex", + "skybox_scaley", + "skybox_scalez", + "interscreen", + "runsoc", + "scriptname", + "precutscenenum", + "cutscenenum", + "countdown", + "palette", + "numlaps", + "unlockrequired", + "levelselect", + "bonustype", + "saveoverride", + "levelflags", + "menuflags", + //"automap", + "mobj_scale", + NULL, +}; + +static int mapheaderinfo_fields_ref = LUA_NOREF; + static int mapheaderinfo_get(lua_State *L) { mapheader_t *header = *((mapheader_t **)luaL_checkudata(L, 1, META_MAPHEADER)); - const char *field = luaL_checkstring(L, 2); + enum mapheaderinfo_e field = Lua_optoption(L, 2, -1, mapheaderinfo_fields_ref); INT16 i; - if (fastcmp(field,"lvlttl")) + switch (field) + { + case mapheaderinfo_lvlttl: lua_pushstring(L, header->lvlttl); - else if (fastcmp(field,"subttl")) + break; + case mapheaderinfo_subttl: lua_pushstring(L, header->subttl); - else if (fastcmp(field,"zonttl")) + break; + case mapheaderinfo_zonttl: lua_pushstring(L, header->zonttl); - else if (fastcmp(field,"actnum")) + break; + case mapheaderinfo_actnum: lua_pushstring(L, header->actnum); - else if (fastcmp(field,"typeoflevel")) + break; + case mapheaderinfo_typeoflevel: lua_pushinteger(L, header->typeoflevel); - else if (fastcmp(field,"nextlevel")) + break; + case mapheaderinfo_nextlevel: lua_pushinteger(L, header->nextlevel); - else if (fastcmp(field,"musname")) + break; + case mapheaderinfo_musname: lua_pushstring(L, header->musname); - else if (fastcmp(field,"mustrack")) + break; + case mapheaderinfo_mustrack: lua_pushinteger(L, header->mustrack); - else if (fastcmp(field,"muspos")) + break; + case mapheaderinfo_muspos: lua_pushinteger(L, header->muspos); - else if (fastcmp(field,"musinterfadeout")) + break; + case mapheaderinfo_musinterfadeout: lua_pushinteger(L, header->musinterfadeout); - else if (fastcmp(field,"musintername")) + break; + case mapheaderinfo_musintername: lua_pushstring(L, header->musintername); - else if (fastcmp(field,"forcecharacter")) + break; + case mapheaderinfo_forcecharacter: lua_pushstring(L, header->forcecharacter); - else if (fastcmp(field,"weather")) + break; + case mapheaderinfo_weather: lua_pushinteger(L, header->weather); - else if (fastcmp(field,"skynum")) + break; + case mapheaderinfo_skynum: lua_pushinteger(L, header->skynum); - else if (fastcmp(field,"skybox_scalex")) + break; + case mapheaderinfo_skybox_scalex: lua_pushinteger(L, header->skybox_scalex); - else if (fastcmp(field,"skybox_scaley")) + break; + case mapheaderinfo_skybox_scaley: lua_pushinteger(L, header->skybox_scaley); - else if (fastcmp(field,"skybox_scalez")) + break; + case mapheaderinfo_skybox_scalez: lua_pushinteger(L, header->skybox_scalez); - else if (fastcmp(field,"interscreen")) { + break; + case mapheaderinfo_interscreen: for (i = 0; i < 8; i++) if (!header->interscreen[i]) break; lua_pushlstring(L, header->interscreen, i); - } else if (fastcmp(field,"runsoc")) + break; + case mapheaderinfo_runsoc: lua_pushstring(L, header->runsoc); - else if (fastcmp(field,"scriptname")) + break; + case mapheaderinfo_scriptname: lua_pushstring(L, header->scriptname); - else if (fastcmp(field,"precutscenenum")) + break; + case mapheaderinfo_precutscenenum: lua_pushinteger(L, header->precutscenenum); - else if (fastcmp(field,"cutscenenum")) + break; + case mapheaderinfo_cutscenenum: lua_pushinteger(L, header->cutscenenum); - else if (fastcmp(field,"countdown")) + break; + case mapheaderinfo_countdown: lua_pushinteger(L, header->countdown); - else if (fastcmp(field,"palette")) + break; + case mapheaderinfo_palette: lua_pushinteger(L, header->palette); - else if (fastcmp(field,"numlaps")) + break; + case mapheaderinfo_numlaps: lua_pushinteger(L, header->numlaps); - else if (fastcmp(field,"unlockrequired")) + break; + case mapheaderinfo_unlockrequired: lua_pushinteger(L, header->unlockrequired); - else if (fastcmp(field,"levelselect")) + break; + case mapheaderinfo_levelselect: lua_pushinteger(L, header->levelselect); - else if (fastcmp(field,"bonustype")) + break; + case mapheaderinfo_bonustype: lua_pushinteger(L, header->bonustype); - else if (fastcmp(field,"saveoverride")) + break; + case mapheaderinfo_saveoverride: lua_pushinteger(L, header->saveoverride); - else if (fastcmp(field,"levelflags")) + break; + case mapheaderinfo_levelflags: lua_pushinteger(L, header->levelflags); - else if (fastcmp(field,"menuflags")) + break; + case mapheaderinfo_menuflags: lua_pushinteger(L, header->menuflags); - /*else if (fastcmp(field,"automap")) - lua_pushboolean(L, header->automap);*/ - else if (fastcmp(field,"mobj_scale")) + break; + /*case mapheaderinfo_automap: + lua_pushstring(L, header->selectheading); + break;*/ + case mapheaderinfo_mobj_scale: lua_pushfixed(L, header->mobj_scale); + break; // TODO add support for reading numGradedMares and grades - else { + default: + { // Read custom vars now // (note: don't include the "LUA." in your lua scripts!) UINT8 j = 0; - for (;j < header->numCustomOptions && !fastcmp(field, header->customopts[j].option); ++j); + for (;j < header->numCustomOptions && !fastcmp(lua_tostring(L, 2), header->customopts[j].option); ++j); if(j < header->numCustomOptions) lua_pushstring(L, header->customopts[j].value); else lua_pushnil(L); } + } return 1; + } int LUA_MapLib(lua_State *L) @@ -1556,6 +1684,8 @@ int LUA_MapLib(lua_State *L) lua_setfield(L, -2, "__len"); lua_pop(L, 1); + sector_fields_ref = Lua_CreateFieldTable(L, sector_opt); + luaL_newmetatable(L, META_SUBSECTOR); lua_pushcfunction(L, subsector_get); lua_setfield(L, -2, "__index"); @@ -1564,6 +1694,8 @@ int LUA_MapLib(lua_State *L) lua_setfield(L, -2, "__len"); lua_pop(L, 1); + subsector_fields_ref = Lua_CreateFieldTable(L, subsector_opt); + luaL_newmetatable(L, META_LINE); lua_pushcfunction(L, line_get); lua_setfield(L, -2, "__index"); @@ -1572,6 +1704,8 @@ int LUA_MapLib(lua_State *L) lua_setfield(L, -2, "__len"); lua_pop(L, 1); + line_fields_ref = Lua_CreateFieldTable(L, line_opt); + luaL_newmetatable(L, META_SIDENUM); lua_pushcfunction(L, sidenum_get); lua_setfield(L, -2, "__index"); @@ -1588,6 +1722,8 @@ int LUA_MapLib(lua_State *L) lua_setfield(L, -2, "__len"); lua_pop(L, 1); + side_fields_ref = Lua_CreateFieldTable(L, side_opt); + luaL_newmetatable(L, META_VERTEX); lua_pushcfunction(L, vertex_get); lua_setfield(L, -2, "__index"); @@ -1596,6 +1732,8 @@ int LUA_MapLib(lua_State *L) lua_setfield(L, -2, "__len"); lua_pop(L, 1); + vertex_fields_ref = Lua_CreateFieldTable(L, vertex_opt); + luaL_newmetatable(L, META_FFLOOR); lua_pushcfunction(L, ffloor_get); lua_setfield(L, -2, "__index"); @@ -1604,6 +1742,8 @@ int LUA_MapLib(lua_State *L) lua_setfield(L, -2, "__newindex"); lua_pop(L, 1); + ffloor_fields_ref = Lua_CreateFieldTable(L, ffloor_opt); + luaL_newmetatable(L, META_SLOPE); lua_pushcfunction(L, slope_get); lua_setfield(L, -2, "__index"); @@ -1612,6 +1752,8 @@ int LUA_MapLib(lua_State *L) lua_setfield(L, -2, "__newindex"); lua_pop(L, 1); + slope_fields_ref = Lua_CreateFieldTable(L, slope_opt); + luaL_newmetatable(L, META_VECTOR2); lua_pushcfunction(L, vector2_get); lua_setfield(L, -2, "__index"); @@ -1630,6 +1772,8 @@ int LUA_MapLib(lua_State *L) //lua_setfield(L, -2, "__len"); lua_pop(L, 1); + mapheaderinfo_fields_ref = Lua_CreateFieldTable(L, mapheaderinfo_opt); + lua_newuserdata(L, 0); lua_createtable(L, 0, 2); lua_pushcfunction(L, lib_getSector); @@ -1690,4 +1834,4 @@ int LUA_MapLib(lua_State *L) lua_setmetatable(L, -2); lua_setglobal(L, "mapheaderinfo"); return 0; -} \ No newline at end of file +} diff --git a/src/lua_mobjlib.c b/src/lua_mobjlib.c index 7b1db5327..7385cccf6 100644 --- a/src/lua_mobjlib.c +++ b/src/lua_mobjlib.c @@ -147,7 +147,7 @@ static const udata_field_t mobj_fields[] = { FIELD(mobj_t, colorized, udatalib_getter_boolean, udatalib_setter_boolean), FIELD(mobj_t, mirrored, udatalib_getter_boolean, udatalib_setter_boolean), FIELD(mobj_t, rollmodel, udatalib_getter_boolean, udatalib_setter_boolean), - { NULL }, + { NULL, 0, NULL, NULL }, }; #undef FIELD @@ -769,14 +769,41 @@ static int mobj_set(lua_State *L) #undef NOSETPOS #undef NOFIELD +enum mapthing_e { + mapthing_valid = 0, + mapthing_x, + mapthing_y, + mapthing_angle, + mapthing_type, + mapthing_options, + mapthing_z, + mapthing_extrainfo, + mapthing_mobj, +}; + +const char *const mapthing_opt[] = { + "valid", + "x", + "y", + "angle", + "type", + "options", + "z", + "extrainfo", + "mobj", + NULL, +}; + +static int mapthing_fields_ref = LUA_NOREF; + static int mapthing_get(lua_State *L) { mapthing_t *mt = *((mapthing_t **)luaL_checkudata(L, 1, META_MAPTHING)); - const char *field = luaL_checkstring(L, 2); - lua_Integer number; + enum mapthing_e field = Lua_optoption(L, 2, -1, mapthing_fields_ref); + lua_settop(L, 2); if (!mt) { - if (fastcmp(field,"valid")) { + if (field == mapthing_valid) { lua_pushboolean(L, false); return 1; } @@ -785,39 +812,50 @@ static int mapthing_get(lua_State *L) return 0; } - if (fastcmp(field,"valid")) { - lua_pushboolean(L, true); - return 1; - } else if(fastcmp(field,"x")) - number = mt->x; - else if(fastcmp(field,"y")) - number = mt->y; - else if(fastcmp(field,"angle")) - number = mt->angle; - else if(fastcmp(field,"type")) - number = mt->type; - else if(fastcmp(field,"options")) - number = mt->options; - else if(fastcmp(field,"z")) - number = mt->z; - else if(fastcmp(field,"extrainfo")) - number = mt->extrainfo; - else if(fastcmp(field,"mobj")) { - LUA_PushUserdata(L, mt->mobj, META_MOBJ); - return 1; - } else if (devparm) - return luaL_error(L, LUA_QL("mapthing_t") " has no field named " LUA_QS, field); - else - return 0; + switch (field) + { + case mapthing_valid: + lua_pushboolean(L, true); + break; + case mapthing_x: + lua_pushinteger(L, mt->x); + break; + case mapthing_y: + lua_pushinteger(L, mt->y); + break; + case mapthing_angle: + lua_pushinteger(L, mt->angle); + break; + case mapthing_type: + lua_pushinteger(L, mt->type); + break; + case mapthing_options: + lua_pushinteger(L, mt->options); + break; + case mapthing_z: + lua_pushinteger(L, mt->z); + break; + case mapthing_extrainfo: + lua_pushinteger(L, mt->extrainfo); + break; + case mapthing_mobj: + LUA_PushUserdata(L, mt->mobj, META_MOBJ); + break; + default: + if (devparm) + return luaL_error(L, LUA_QL("mapthing_t") " has no field named " LUA_QS, field); + else + return 0; + } - lua_pushinteger(L, number); return 1; } static int mapthing_set(lua_State *L) { mapthing_t *mt = *((mapthing_t **)luaL_checkudata(L, 1, META_MAPTHING)); - const char *field = luaL_checkstring(L, 2); + enum mapthing_e field = Lua_optoption(L, 2, -1, mapthing_fields_ref); + lua_settop(L, 3); if (!mt) return luaL_error(L, "accessed mapthing_t doesn't exist anymore."); @@ -827,24 +865,40 @@ static int mapthing_set(lua_State *L) if (hook_cmd_running) return luaL_error(L, "Do not alter mapthing_t in BuildCMD code!"); - if(fastcmp(field,"x")) - mt->x = (INT16)luaL_checkinteger(L, 3); - else if(fastcmp(field,"y")) - mt->y = (INT16)luaL_checkinteger(L, 3); - else if(fastcmp(field,"angle")) - mt->angle = (INT16)luaL_checkinteger(L, 3); - else if(fastcmp(field,"type")) - mt->type = (UINT16)luaL_checkinteger(L, 3); - else if(fastcmp(field,"options")) - mt->options = (UINT16)luaL_checkinteger(L, 3); - else if(fastcmp(field,"z")) - mt->z = (INT16)luaL_checkinteger(L, 3); - else if(fastcmp(field,"extrainfo")) - mt->extrainfo = (UINT8)luaL_checkinteger(L, 3); - else if(fastcmp(field,"mobj")) - mt->mobj = *((mobj_t **)luaL_checkudata(L, 3, META_MOBJ)); - else - return luaL_error(L, LUA_QL("mapthing_t") " has no field named " LUA_QS, field); + switch (field) + { + case mapthing_x: + mt->x = (INT16)luaL_checkinteger(L, 3); + break; + case mapthing_y: + mt->y = (INT16)luaL_checkinteger(L, 3); + break; + case mapthing_angle: + mt->angle = (INT16)luaL_checkinteger(L, 3); + break; + case mapthing_type: + mt->type = (UINT16)luaL_checkinteger(L, 3); + break; + case mapthing_options: + mt->options = (UINT16)luaL_checkinteger(L, 3); + break; + case mapthing_z: + mt->z = (INT16)luaL_checkinteger(L, 3); + break; + case mapthing_extrainfo: + { + INT32 extrainfo = luaL_checkinteger(L, 3); + if (extrainfo & ~15) + return luaL_error(L, "mapthing_t extrainfo set %d out of range (%d - %d)", extrainfo, 0, 15); + mt->extrainfo = (UINT8)extrainfo; + break; + } + case mapthing_mobj: + mt->mobj = *((mobj_t **)luaL_checkudata(L, 3, META_MOBJ)); + break; + default: + return luaL_error(L, LUA_QL("mapthing_t") " has no field named " LUA_QS, field); + } return 0; } @@ -915,6 +969,8 @@ int LUA_MobjLib(lua_State *L) lua_setfield(L, -2, "__newindex"); lua_pop(L,1); + mapthing_fields_ref = Lua_CreateFieldTable(L, mapthing_opt); + lua_newuserdata(L, 0); lua_createtable(L, 0, 2); lua_pushcfunction(L, lib_getMapthing); @@ -925,4 +981,4 @@ int LUA_MobjLib(lua_State *L) lua_setmetatable(L, -2); lua_setglobal(L, "mapthings"); return 0; -} \ No newline at end of file +} diff --git a/src/lua_playerlib.c b/src/lua_playerlib.c index 70324fa02..dd4cf7b03 100644 --- a/src/lua_playerlib.c +++ b/src/lua_playerlib.c @@ -51,6 +51,9 @@ int player_localskin_setter(lua_State *L); int player_sliproll_getter(lua_State *L); int player_sliproll_noset(lua_State *L); +int player_viewrollangle_getter(lua_State *L); +int player_viewrollangle_noset(lua_State *L); + #define FIELD(type, field_name, getter, setter) { #field_name, offsetof(type, field_name), getter, setter } static const udata_field_t player_fields[] = { // Player doesn't actually have field "name" so macro fails. Need to declare field manually. @@ -159,8 +162,9 @@ static const udata_field_t player_fields[] = { #endif // Same as player.name { "sliproll", 0, player_sliproll_getter, player_sliproll_noset }, + { "viewrollangle", 0, player_viewrollangle_getter, player_viewrollangle_noset }, { "ping", 0, player_ping_getter, player_ping_noset }, // Hmm originally setter doesn't exist so data is written as unreachable custom field... - { NULL }, + { NULL, 0, NULL, NULL }, }; #undef FIELD @@ -217,6 +221,7 @@ NOSET(bot) NOSET(splitscreenindex) NOSET(ping) NOSET(sliproll) +NOSET(viewrollangle) #undef NOSET @@ -372,6 +377,15 @@ int player_sliproll_getter(lua_State *L) return 1; } +int player_viewrollangle_getter(lua_State *L) +{ + player_t *plr = GETPLAYER(); + + lua_pushangle(L, R_ViewRollAngle(plr)); + + return 1; +} + static int lib_iteratePlayers(lua_State *L) { INT32 i = -1; @@ -694,30 +708,65 @@ static int kartstuff_len(lua_State *L) } #define NOFIELD luaL_error(L, LUA_QL("ticcmd_t") " has no field named " LUA_QS, field) +#define NOSET luaL_error(L, LUA_QL("ticcmd_t") " field " LUA_QS " should not be set directly.", field) + +enum ticcmd_e +{ + ticcmd_forwardmove, + ticcmd_sidemove, + ticcmd_angleturn, + ticcmd_aiming, + ticcmd_buttons, + ticcmd_driftturn, + ticcmd_latency, +}; + +static const char *const ticcmd_opt[] = { + "forwardmove", + "sidemove", + "angleturn", + "aiming", + "buttons", + "driftturn", + "latency", + NULL, +}; + +static int ticcmd_fields_ref = LUA_NOREF; static int ticcmd_get(lua_State *L) { ticcmd_t *cmd = *((ticcmd_t **)luaL_checkudata(L, 1, META_TICCMD)); - const char *field = luaL_checkstring(L, 2); + enum ticcmd_e field = Lua_optoption(L, 2, -1, ticcmd_fields_ref); if (!cmd) return LUA_ErrInvalid(L, "player_t"); - if (fastcmp(field,"forwardmove")) + switch (field) + { + case ticcmd_forwardmove: lua_pushinteger(L, cmd->forwardmove); - else if (fastcmp(field,"sidemove")) + break; + case ticcmd_sidemove: lua_pushinteger(L, cmd->sidemove); - else if (fastcmp(field,"angleturn")) + break; + case ticcmd_angleturn: lua_pushinteger(L, cmd->angleturn); - else if (fastcmp(field,"aiming")) + break; + case ticcmd_aiming: lua_pushinteger(L, cmd->aiming); - else if (fastcmp(field,"buttons")) + break; + case ticcmd_buttons: lua_pushinteger(L, cmd->buttons); - else if (fastcmp(field,"driftturn")) + break; + case ticcmd_driftturn: lua_pushinteger(L, cmd->driftturn); - else if (fastcmp(field,"latency")) + break; + case ticcmd_latency: lua_pushinteger(L, cmd->latency); - else + break; + default: return NOFIELD; + } return 1; } @@ -725,32 +774,44 @@ static int ticcmd_get(lua_State *L) static int ticcmd_set(lua_State *L) { ticcmd_t *cmd = *((ticcmd_t **)luaL_checkudata(L, 1, META_TICCMD)); - const char *field = luaL_checkstring(L, 2); + enum ticcmd_e field = Lua_optoption(L, 2, -1, ticcmd_fields_ref); if (!cmd) return LUA_ErrInvalid(L, "ticcmd_t"); if (hud_running) return luaL_error(L, "Do not alter player_t in HUD rendering code!"); - if (fastcmp(field,"forwardmove")) + switch (field) + { + case ticcmd_forwardmove: cmd->forwardmove = (SINT8)luaL_checkinteger(L, 3); - else if (fastcmp(field,"sidemove")) + break; + case ticcmd_sidemove: cmd->sidemove = (SINT8)luaL_checkinteger(L, 3); - else if (fastcmp(field,"angleturn")) + break; + case ticcmd_angleturn: cmd->angleturn = (INT16)luaL_checkinteger(L, 3); - else if (fastcmp(field,"aiming")) + break; + case ticcmd_aiming: cmd->aiming = (INT16)luaL_checkinteger(L, 3); - else if (fastcmp(field,"buttons")) + break; + case ticcmd_buttons: cmd->buttons = (UINT16)luaL_checkinteger(L, 3); - else if (fastcmp(field,"driftturn")) + break; + case ticcmd_driftturn: cmd->driftturn = (INT16)luaL_checkinteger(L, 3); - else + break; + case ticcmd_latency: + return NOSET; + default: return NOFIELD; + } return 0; } #undef NOFIELD +#undef NOSET int LUA_PlayerLib(lua_State *L) { @@ -797,6 +858,8 @@ int LUA_PlayerLib(lua_State *L) lua_setfield(L, -2, "__newindex"); lua_pop(L,1); + ticcmd_fields_ref = Lua_CreateFieldTable(L, ticcmd_opt); + lua_newuserdata(L, 0); lua_createtable(L, 0, 2); lua_pushcfunction(L, lib_getPlayer); diff --git a/src/lua_script.c b/src/lua_script.c index 3af655efe..9d5bef4a7 100644 --- a/src/lua_script.c +++ b/src/lua_script.c @@ -152,6 +152,7 @@ static int noglobals(lua_State *L) { const char *csname; char *name; + enum actionnum actionnum; lua_remove(L, 1); // we're not gonna be using _G csname = lua_tostring(L, 1); @@ -170,6 +171,10 @@ static int noglobals(lua_State *L) lua_rawset(L, -3); // rawset doesn't trigger this metatable again. // otherwise we would've used setfield, obviously. + actionnum = LUA_GetActionNumByName(name); + if (actionnum < NUMACTIONS) + actionsoverridden[actionnum] = true; + Z_Free(name); return 0; } @@ -394,8 +399,14 @@ fixed_t LUA_EvalMath(const char *word) if (luaL_dostring(mL, buf)) { p = lua_tostring(mL, -1); - while (*p++ != ':' && *p) ; - p += 3; // "1: " + + // If there is [string "..."]:1: text, skip it + if (strstr(p, ":") != NULL) + { + while (*p++ != ':' && *p); + + p += 3; // "1: " + } CONS_Alert(CONS_WARNING, "%s\n", p); } else @@ -659,8 +670,17 @@ static UINT8 ArchiveValue(int TABLESINDEX, int myindex) lua_pop(gL, 1); } if (!found) + { t++; + if (t == 0) + { + CONS_Alert(CONS_ERROR, "Too many tables to archive!\n"); + WRITEUINT8(save_p, ARCH_NULL); + return 0; + } + } + WRITEUINT8(save_p, ARCH_TABLE); WRITEUINT16(save_p, t); @@ -1427,7 +1447,12 @@ static void UnArchiveExtVars(void *pointer) if (field_count == 0) return; - I_Assert(gL != NULL); + + // Technically possible new, since server may have local lua scripts but no "public" ones, so + // field_count would be non zero (there is no way to tell local field from non-local, so + // everything gets archived) + if (!gL) + return; TABLESINDEX = lua_gettop(gL); lua_createtable(gL, 0, field_count); // pointer's ext vars subtable @@ -1587,12 +1612,14 @@ void LUA_Archive(void) if (gamestate == GS_LEVEL) { for (th = thinkercap.next; th != &thinkercap; th = th->next) - if (th->function.acp1 == (actionf_p1)P_MobjThinker) - { - // archive function will determine when to skip mobjs, - // and write mobjnum in otherwise. - ArchiveExtVars(th, "mobj"); - } + { + if (th->function.acp1 != (actionf_p1)P_MobjThinker) + continue; + + // archive function will determine when to skip mobjs, + // and write mobjnum in otherwise. + ArchiveExtVars(th, "mobj"); + } } WRITEUINT32(save_p, UINT32_MAX); // end of mobjs marker, replaces mobjnum. @@ -1620,11 +1647,15 @@ void LUA_UnArchive(void) } do { - mobjnum = READUINT32(save_p); // read a mobjnum + mobjnum = READUINT32(save_p); // read a mobjnum for (th = thinkercap.next; th != &thinkercap; th = th->next) - if (th->function.acp1 == (actionf_p1)P_MobjThinker - && ((mobj_t *)th)->mobjnum == mobjnum) // find matching mobj - UnArchiveExtVars(th); // apply variables + { + if (th->function.acp1 != (actionf_p1)P_MobjThinker) + continue; + if (((mobj_t *)th)->mobjnum != mobjnum) // find matching mobj + continue; + UnArchiveExtVars(th); // apply variables + } } while(mobjnum != UINT32_MAX); // repeat until end of mobjs marker. LUAh_NetArchiveHook(NetUnArchive); // call the NetArchive hook in unarchive mode @@ -1678,13 +1709,41 @@ void LUA_UnArchiveDemo(void) } // For mobj_t, player_t, etc. to take custom variables. -int Lua_optoption(lua_State *L, int narg, - const char *def, const char *const lst[]) +int Lua_optoption(lua_State *L, int narg, int def, int list_ref) +{ + int result = -1; + + if (lua_isnoneornil(L, narg)) + return def; + + I_Assert(lua_checkstack(L, 2)); + luaL_checkstring(L, narg); + + lua_rawgeti(L, LUA_REGISTRYINDEX, list_ref); + I_Assert(lua_istable(L, -1)); + lua_pushvalue(L, narg); + lua_rawget(L, -2); + + if (lua_isnumber(L, -1)) + result = lua_tointeger(L, -1); + + lua_pop(L, 2); // Pop result and fields table + + return result; +} + + +int Lua_CreateFieldTable(lua_State *L, const char *const lst[]) { - const char *name = (def) ? luaL_optstring(L, narg, def) : luaL_checkstring(L, narg); int i; - for (i=0; lst[i]; i++) - if (fastcmp(lst[i], name)) - return i; - return -1; -} \ No newline at end of file + + lua_newtable(L); + for (i = 0; lst[i] != NULL; i++) + { + lua_pushstring(L, lst[i]); + lua_pushinteger(L, i); + lua_settable(L, -3); + } + + return luaL_ref(L, LUA_REGISTRYINDEX); +} diff --git a/src/lua_script.h b/src/lua_script.h index a22e47c12..9903315c2 100644 --- a/src/lua_script.h +++ b/src/lua_script.h @@ -63,8 +63,8 @@ void LUA_UnArchiveDemo(void); void Got_Luacmd(UINT8 **cp, INT32 playernum); // lua_consolelib.c void LUA_CVarChanged(const char *name); // lua_consolelib.c -int Lua_optoption(lua_State *L, int narg, - const char *def, const char *const lst[]); +int Lua_optoption(lua_State *L, int narg, int def, int list_ref); +int Lua_CreateFieldTable(lua_State *L, const char *const lst[]); void LUAh_NetArchiveHook(lua_CFunction archFunc); // Console wrapper diff --git a/src/lua_skinlib.c b/src/lua_skinlib.c index 286e983c1..403ac834e 100644 --- a/src/lua_skinlib.c +++ b/src/lua_skinlib.c @@ -38,6 +38,7 @@ enum skin { skin_highresscale, skin_soundsid }; + static const char *const skin_opt[] = { "valid", "name", @@ -61,10 +62,12 @@ static const char *const skin_opt[] = { #define UNIMPLEMENTED luaL_error(L, LUA_QL("skin_t") " field " LUA_QS " is not implemented for Lua and cannot be accessed.", skin_opt[field]) +static int skin_fields_ref = LUA_NOREF; + static int skin_get(lua_State *L) { skin_t *skin = *((skin_t **)luaL_checkudata(L, 1, META_SKIN)); - enum skin field = luaL_checkoption(L, 2, NULL, skin_opt); + enum skin field = Lua_optoption(L, 2, -1, skin_fields_ref); INT32 i; // skins are always valid, only added, never removed @@ -253,6 +256,8 @@ int LUA_SkinLib(lua_State *L) lua_setfield(L, -2, "__len"); lua_pop(L,1); + skin_fields_ref = Lua_CreateFieldTable(L, skin_opt); + luaL_newmetatable(L, META_SOUNDSID); lua_pushcfunction(L, soundsid_get); lua_setfield(L, -2, "__index"); diff --git a/src/m_cheat.c b/src/m_cheat.c index 91ca536c8..abada4be5 100644 --- a/src/m_cheat.c +++ b/src/m_cheat.c @@ -909,8 +909,9 @@ static mapthing_t *OP_CreateNewMapThing(player_t *player, UINT16 type, boolean c mo = (mobj_t *)th; // get offset from mt, which points to old mapthings, then add new location - if (mo->spawnpoint) - mo->spawnpoint = (mo->spawnpoint - mt) + mapthings; + if (!mo->spawnpoint) + continue; + mo->spawnpoint = (mo->spawnpoint - mt) + mapthings; } } diff --git a/src/m_fixed.c b/src/m_fixed.c index 2da72fe05..ddd1ce63a 100644 --- a/src/m_fixed.c +++ b/src/m_fixed.c @@ -1011,13 +1011,6 @@ int main(int argc, char** argv) exit(0); } -static void *cpu_cpy(void *dest, const void *src, size_t n) -{ - return memcpy(dest, src, n); -} - -void *(*M_Memcpy)(void* dest, const void* src, size_t n) = cpu_cpy; - void I_Error(const char *error, ...) { (void)error; diff --git a/src/m_menu.c b/src/m_menu.c index cc7d45d33..5a53d11bb 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -82,6 +82,9 @@ // protocol handling #include "d_protocol.h" +#include "z_zone.h" +#include "mserv.h" + #if defined(HAVE_SDL) #include "SDL.h" #if SDL_VERSION_ATLEAST(2,0,0) @@ -321,6 +324,10 @@ static void M_AssignJoystick(INT32 choice); static void M_ChangeControl(INT32 choice); static void M_ResetControls(INT32 choice); +//camera options menu +menu_t OP_CamOptionsDef; +menu_t OP_Player1CamOptionsDef, OP_Player2CamOptionsDef, OP_Player3CamOptionsDef, OP_Player4CamOptionsDef; + // Video & Sound menu_t OP_VideoOptionsDef, OP_VideoModeDef, OP_ExpOptionsDef, OP_ColorOptionsDef; #ifdef HWRENDER @@ -358,6 +365,7 @@ static void M_DeleteProtocol(void); // Saturn menu_t OP_SaturnDef; +menu_t OP_SaturnHudDef; menu_t OP_HudOffsetDef; menu_t OP_PlayerDistortDef; menu_t OP_SaturnCreditsDef; @@ -383,6 +391,7 @@ menu_t OP_DriftGaugeDef; menu_t MISC_ReplayHutDef; menu_t MISC_ReplayOptionsDef; static void M_HandleReplayHutList(INT32 choice); +static void M_HutCheckReplays(size_t maxnum); static void M_DrawReplayHut(void); static void M_DrawReplayStartMenu(void); static boolean M_QuitReplayHut(void); @@ -457,10 +466,16 @@ static void Newgametype_OnChange(void); static void Dummymenuplayer_OnChange(void); static void Dummystaff_OnChange(void); +// crap to force hud to show when in saturns hud options +boolean forceshowhud = false; + // ========================================================================== // CONSOLE VARIABLES AND THEIR POSSIBLE VALUES GO HERE. // ========================================================================== +// How much replays are checked per frame when using search +consvar_t cv_replaysearchrate = {"replaysearchrate", "1000", CV_SAVE, CV_Natural, NULL, 0, NULL, NULL, 0, 0, NULL }; + consvar_t cv_showfocuslost = {"showfocuslost", "Yes", CV_SAVE, CV_YesNo, NULL, 0, NULL, NULL, 0, 0, NULL }; static CV_PossibleValue_t map_cons_t[] = { @@ -613,9 +628,11 @@ static menuitem_t MISC_ReplayStartMenu[] = static menuitem_t MISC_ReplayOptionsMenu[] = { - {IT_CVAR|IT_STRING, NULL, "Record Replays", &cv_recordmultiplayerdemos, 0}, - {IT_CVAR|IT_STRING, NULL, "Sync Check Interval", &cv_netdemosyncquality, 10}, - {IT_CVAR|IT_STRING, NULL, "Max demo size (MiB)", &cv_maxdemosize, 20}, + {IT_CVAR|IT_STRING, NULL, "Record Replays", &cv_recordmultiplayerdemos, 0}, + {IT_CVAR|IT_STRING, NULL, "Save Replays on Map change", &cv_demochangemap, 10}, + {IT_CVAR|IT_STRING, NULL, "Sync Check Interval", &cv_netdemosyncquality, 20}, + {IT_CVAR|IT_STRING, NULL, "Max demo size (MiB)", &cv_maxdemosize, 30}, + {IT_CVAR|IT_STRING, NULL, "Replay Search Rate", &cv_replaysearchrate, 40}, }; static tic_t playback_last_menu_interaction_leveltime = 0; @@ -1041,7 +1058,6 @@ static menuitem_t MP_MainMenu[] = }; #ifndef NONET - static menuitem_t MP_ServerMenu[] = { {IT_STRING|IT_CVAR, NULL, "Max. Player Count", &cv_maxplayers, 10}, @@ -1057,7 +1073,6 @@ static menuitem_t MP_ServerMenu[] = {IT_WHITESTRING|IT_CALL, NULL, "Start", M_StartServer, 130}, }; - #endif // Separated offline and normal servers. @@ -1076,9 +1091,6 @@ static menuitem_t MP_PlayerSetupMenu[] = {IT_KEYHANDLER | IT_STRING, NULL, "Color", M_HandleSetupMultiPlayer, 152}, }; - - - #ifndef NONET static menuitem_t MP_ConnectMenu[] = { @@ -1116,23 +1128,24 @@ static menuitem_t OP_MainMenu[] = { {IT_SUBMENU|IT_STRING, NULL, "Control Setup...", &OP_ControlsDef, 0}, - {IT_SUBMENU|IT_STRING, NULL, "Video Options...", &OP_VideoOptionsDef, 20}, - {IT_SUBMENU|IT_STRING, NULL, "Sound Options...", &OP_SoundOptionsDef, 30}, + {IT_SUBMENU|IT_STRING, NULL, "Video Options...", &OP_VideoOptionsDef, 15}, + {IT_SUBMENU|IT_STRING, NULL, "Sound Options...", &OP_SoundOptionsDef, 25}, - {IT_SUBMENU|IT_STRING, NULL, "HUD Options...", &OP_HUDOptionsDef, 50}, + {IT_SUBMENU|IT_STRING, NULL, "HUD Options...", &OP_HUDOptionsDef, 40}, + {IT_SUBMENU|IT_STRING, NULL, "Camera Options...", &OP_CamOptionsDef, 50}, {IT_SUBMENU|IT_STRING, NULL, "Gameplay Options...", &OP_GameOptionsDef, 60}, {IT_SUBMENU|IT_STRING, NULL, "Server Options...", &OP_ServerOptionsDef, 70}, - {IT_SUBMENU|IT_STRING, NULL, "Data Options...", &OP_DataOptionsDef, 90}, - {IT_CALL|IT_STRING, NULL, "Custom Options...", M_CustomCvarMenu, 100}, + {IT_SUBMENU|IT_STRING, NULL, "Data Options...", &OP_DataOptionsDef, 85}, + {IT_CALL|IT_STRING, NULL, "Custom Options...", M_CustomCvarMenu, 95}, - {IT_CALL|IT_STRING, NULL, "Tricks & Secrets (F1)", M_Manual, 110}, - {IT_CALL|IT_STRING, NULL, "Play Credits", M_Credits, 120}, + {IT_CALL|IT_STRING, NULL, "Tricks & Secrets (F1)", M_Manual, 105}, + {IT_CALL|IT_STRING, NULL, "Play Credits", M_Credits, 115}, - {IT_SUBMENU|IT_STRING, NULL, "Saturn Options...", &OP_SaturnDef, 140}, + {IT_SUBMENU|IT_STRING, NULL, "Saturn Options...", &OP_SaturnDef, 135}, - {IT_SUBMENU|IT_STRING, NULL, "Bird", &OP_BirdDef, 150}, - {IT_CALL|IT_STRING, NULL, "Local Skin Options...", M_LocalSkinMenu, 160}, + {IT_SUBMENU|IT_STRING, NULL, "Bird...", &OP_BirdDef, 145}, + {IT_CALL|IT_STRING, NULL, "Local Skin Options...", M_LocalSkinMenu, 155}, }; static menuitem_t OP_ControlsMenu[] = @@ -1195,6 +1208,7 @@ static menuitem_t OP_AllControlsMenu[] = {IT_CONTROL, NULL, "Look Up", M_ChangeControl, gc_lookup }, {IT_CONTROL, NULL, "Look Down", M_ChangeControl, gc_lookdown }, {IT_CONTROL, NULL, "Center View", M_ChangeControl, gc_centerview }, + {IT_CONTROL, NULL, "Toggle Director", M_ChangeControl, gc_director }, {IT_HEADER, NULL, "Custom Lua Actions", NULL, 0}, {IT_SPACE, NULL, NULL, NULL, 0}, {IT_CONTROL, NULL, "Custom Action 1", M_ChangeControl, gc_custom1 }, @@ -1205,73 +1219,89 @@ static menuitem_t OP_AllControlsMenu[] = static menuitem_t OP_Joystick1Menu[] = { {IT_STRING | IT_CALL, NULL, "Select Gamepad..." , M_Setup1PJoystickMenu, 10}, - {IT_STRING | IT_CVAR, NULL, "Aim Forward/Back" , &cv_aimaxis , 30}, - {IT_STRING | IT_CVAR, NULL, "Turn Left/Right" , &cv_turnaxis , 40}, - {IT_STRING | IT_CVAR, NULL, "Accelerate" , &cv_moveaxis , 50}, - {IT_STRING | IT_CVAR, NULL, "Brake" , &cv_brakeaxis , 60}, - {IT_STRING | IT_CVAR, NULL, "Drift" , &cv_driftaxis , 70}, - {IT_STRING | IT_CVAR, NULL, "Use Item" , &cv_fireaxis , 80}, - {IT_STRING | IT_CVAR, NULL, "Look Backward" , &cv_lookbackaxis , 90}, - {IT_STRING | IT_CVAR, NULL, "Spec. Look Up/Down" , &cv_lookaxis , 100}, - {IT_STRING | IT_CVAR, NULL, "Custom Button 1" , &cv_custom1axis , 110}, - {IT_STRING | IT_CVAR, NULL, "Custom Button 2" , &cv_custom2axis , 120}, - {IT_STRING | IT_CVAR, NULL, "Custom Button 3" , &cv_custom3axis , 130}, - {IT_STRING | IT_CVAR, NULL, "X deadzone" , &cv_xdeadzone , 140}, - {IT_STRING | IT_CVAR, NULL, "Y deadzone" , &cv_ydeadzone , 150}, + {IT_STRING | IT_CVAR, NULL, "Aim Forward/Back" , &cv_aimaxis , 20}, + {IT_STRING | IT_CVAR, NULL, "Turn Left/Right" , &cv_turnaxis , 25}, + {IT_STRING | IT_CVAR, NULL, "Accelerate" , &cv_moveaxis , 30}, + {IT_STRING | IT_CVAR, NULL, "Brake" , &cv_brakeaxis , 35}, + {IT_STRING | IT_CVAR, NULL, "Drift" , &cv_driftaxis , 40}, + {IT_STRING | IT_CVAR, NULL, "Use Item" , &cv_fireaxis , 45}, + {IT_STRING | IT_CVAR, NULL, "Look Backward" , &cv_lookbackaxis , 50}, + {IT_STRING | IT_CVAR, NULL, "Spec. Look Up/Down" , &cv_lookaxis , 55}, + {IT_STRING | IT_CVAR, NULL, "Custom Button 1" , &cv_custom1axis , 60}, + {IT_STRING | IT_CVAR, NULL, "Custom Button 2" , &cv_custom2axis , 65}, + {IT_STRING | IT_CVAR, NULL, "Custom Button 3" , &cv_custom3axis , 70}, + {IT_STRING | IT_CVAR, NULL, "X deadzone" , &cv_xdeadzone , 75}, + {IT_STRING | IT_CVAR, NULL, "Y deadzone" , &cv_ydeadzone , 80}, + + {IT_STRING | IT_CVAR, NULL, "Controller Rumble" , &cv_rumble[0] , 90}, + {IT_STRING | IT_CVAR, NULL, "Set LED to skin color" , &cv_gamepadled[0] , 95}, + {IT_STRING | IT_CVAR, NULL, "Flash LED on powerups" , &cv_ledpowerup[0] , 100}, }; static menuitem_t OP_Joystick2Menu[] = { {IT_STRING | IT_CALL, NULL, "Select Gamepad..." , M_Setup2PJoystickMenu, 10}, - {IT_STRING | IT_CVAR, NULL, "Aim Forward/Back" , &cv_aimaxis2 , 30}, - {IT_STRING | IT_CVAR, NULL, "Turn Left/Right" , &cv_turnaxis2 , 40}, - {IT_STRING | IT_CVAR, NULL, "Accelerate" , &cv_moveaxis2 , 50}, - {IT_STRING | IT_CVAR, NULL, "Brake" , &cv_brakeaxis2 , 60}, - {IT_STRING | IT_CVAR, NULL, "Drift" , &cv_driftaxis2 , 70}, - {IT_STRING | IT_CVAR, NULL, "Use Item" , &cv_fireaxis2 , 80}, - {IT_STRING | IT_CVAR, NULL, "Look Backward" , &cv_lookbackaxis2 , 90}, - {IT_STRING | IT_CVAR, NULL, "Spec. Look Up/Down" , &cv_lookaxis2 , 100}, - {IT_STRING | IT_CVAR, NULL, "Custom Button 1" , &cv_custom1axis2 , 110}, - {IT_STRING | IT_CVAR, NULL, "Custom Button 2" , &cv_custom2axis2 , 120}, - {IT_STRING | IT_CVAR, NULL, "Custom Button 3" , &cv_custom3axis2 , 130}, - {IT_STRING | IT_CVAR, NULL, "X deadzone" , &cv_xdeadzone2 , 140}, - {IT_STRING | IT_CVAR, NULL, "Y deadzone" , &cv_ydeadzone2 , 150}, + {IT_STRING | IT_CVAR, NULL, "Aim Forward/Back" , &cv_aimaxis2 , 20}, + {IT_STRING | IT_CVAR, NULL, "Turn Left/Right" , &cv_turnaxis2 , 25}, + {IT_STRING | IT_CVAR, NULL, "Accelerate" , &cv_moveaxis2 , 30}, + {IT_STRING | IT_CVAR, NULL, "Brake" , &cv_brakeaxis2 , 35}, + {IT_STRING | IT_CVAR, NULL, "Drift" , &cv_driftaxis2 , 40}, + {IT_STRING | IT_CVAR, NULL, "Use Item" , &cv_fireaxis2 , 45}, + {IT_STRING | IT_CVAR, NULL, "Look Backward" , &cv_lookbackaxis2 , 50}, + {IT_STRING | IT_CVAR, NULL, "Spec. Look Up/Down" , &cv_lookaxis2 , 55}, + {IT_STRING | IT_CVAR, NULL, "Custom Button 1" , &cv_custom1axis2 , 60}, + {IT_STRING | IT_CVAR, NULL, "Custom Button 2" , &cv_custom2axis2 , 65}, + {IT_STRING | IT_CVAR, NULL, "Custom Button 3" , &cv_custom3axis2 , 70}, + {IT_STRING | IT_CVAR, NULL, "X deadzone" , &cv_xdeadzone2 , 75}, + {IT_STRING | IT_CVAR, NULL, "Y deadzone" , &cv_ydeadzone2 , 80}, + + {IT_STRING | IT_CVAR, NULL, "Controller Rumble" , &cv_rumble[1] , 90}, + {IT_STRING | IT_CVAR, NULL, "Set LED to skin color" , &cv_gamepadled[1] , 95}, + {IT_STRING | IT_CVAR, NULL, "Flash LED on powerups" , &cv_ledpowerup[1] , 100}, }; static menuitem_t OP_Joystick3Menu[] = { {IT_STRING | IT_CALL, NULL, "Select Gamepad..." , M_Setup3PJoystickMenu, 10}, - {IT_STRING | IT_CVAR, NULL, "Aim Forward/Back" , &cv_aimaxis3 , 30}, - {IT_STRING | IT_CVAR, NULL, "Turn Left/Right" , &cv_turnaxis3 , 40}, - {IT_STRING | IT_CVAR, NULL, "Accelerate" , &cv_moveaxis3 , 50}, - {IT_STRING | IT_CVAR, NULL, "Brake" , &cv_brakeaxis3 , 60}, - {IT_STRING | IT_CVAR, NULL, "Drift" , &cv_driftaxis3 , 70}, - {IT_STRING | IT_CVAR, NULL, "Use Item" , &cv_fireaxis3 , 80}, - {IT_STRING | IT_CVAR, NULL, "Look Backward" , &cv_lookbackaxis3 , 90}, - {IT_STRING | IT_CVAR, NULL, "Spec. Look Up/Down" , &cv_lookaxis3 , 100}, - {IT_STRING | IT_CVAR, NULL, "Custom Button 1" , &cv_custom1axis3 , 110}, - {IT_STRING | IT_CVAR, NULL, "Custom Button 2" , &cv_custom2axis3 , 120}, - {IT_STRING | IT_CVAR, NULL, "Custom Button 3" , &cv_custom3axis3 , 130}, - {IT_STRING | IT_CVAR, NULL, "X deadzone" , &cv_xdeadzone3 , 140}, - {IT_STRING | IT_CVAR, NULL, "Y deadzone" , &cv_ydeadzone3 , 150}, + {IT_STRING | IT_CVAR, NULL, "Aim Forward/Back" , &cv_aimaxis3 , 20}, + {IT_STRING | IT_CVAR, NULL, "Turn Left/Right" , &cv_turnaxis3 , 25}, + {IT_STRING | IT_CVAR, NULL, "Accelerate" , &cv_moveaxis3 , 30}, + {IT_STRING | IT_CVAR, NULL, "Brake" , &cv_brakeaxis3 , 35}, + {IT_STRING | IT_CVAR, NULL, "Drift" , &cv_driftaxis3 , 40}, + {IT_STRING | IT_CVAR, NULL, "Use Item" , &cv_fireaxis3 , 45}, + {IT_STRING | IT_CVAR, NULL, "Look Backward" , &cv_lookbackaxis3 , 50}, + {IT_STRING | IT_CVAR, NULL, "Spec. Look Up/Down" , &cv_lookaxis3 , 55}, + {IT_STRING | IT_CVAR, NULL, "Custom Button 1" , &cv_custom1axis3 , 60}, + {IT_STRING | IT_CVAR, NULL, "Custom Button 2" , &cv_custom2axis3 , 65}, + {IT_STRING | IT_CVAR, NULL, "Custom Button 3" , &cv_custom3axis3 , 70}, + {IT_STRING | IT_CVAR, NULL, "X deadzone" , &cv_xdeadzone3 , 75}, + {IT_STRING | IT_CVAR, NULL, "Y deadzone" , &cv_ydeadzone3 , 80}, + + {IT_STRING | IT_CVAR, NULL, "Controller Rumble" , &cv_rumble[2] , 90}, + {IT_STRING | IT_CVAR, NULL, "Set LED to skin color" , &cv_gamepadled[2] , 95}, + {IT_STRING | IT_CVAR, NULL, "Flash LED on powerups" , &cv_ledpowerup[2] , 100}, }; static menuitem_t OP_Joystick4Menu[] = { {IT_STRING | IT_CALL, NULL, "Select Gamepad..." , M_Setup4PJoystickMenu, 10}, - {IT_STRING | IT_CVAR, NULL, "Aim Forward/Back" , &cv_aimaxis4 , 30}, - {IT_STRING | IT_CVAR, NULL, "Turn Left/Right" , &cv_turnaxis4 , 40}, - {IT_STRING | IT_CVAR, NULL, "Accelerate" , &cv_moveaxis4 , 50}, - {IT_STRING | IT_CVAR, NULL, "Brake" , &cv_brakeaxis4 , 60}, - {IT_STRING | IT_CVAR, NULL, "Drift" , &cv_driftaxis4 , 70}, - {IT_STRING | IT_CVAR, NULL, "Use Item" , &cv_fireaxis4 , 80}, - {IT_STRING | IT_CVAR, NULL, "Look Backward" , &cv_lookbackaxis4 , 90}, - {IT_STRING | IT_CVAR, NULL, "Spec. Look Up/Down" , &cv_lookaxis4 , 100}, - {IT_STRING | IT_CVAR, NULL, "Custom Button 1" , &cv_custom1axis4 , 110}, - {IT_STRING | IT_CVAR, NULL, "Custom Button 2" , &cv_custom2axis4 , 120}, - {IT_STRING | IT_CVAR, NULL, "Custom Button 3" , &cv_custom3axis4 , 130}, - {IT_STRING | IT_CVAR, NULL, "X deadzone" , &cv_xdeadzone4 , 140}, - {IT_STRING | IT_CVAR, NULL, "Y deadzone" , &cv_ydeadzone4 , 150}, + {IT_STRING | IT_CVAR, NULL, "Aim Forward/Back" , &cv_aimaxis4 , 20}, + {IT_STRING | IT_CVAR, NULL, "Turn Left/Right" , &cv_turnaxis4 , 25}, + {IT_STRING | IT_CVAR, NULL, "Accelerate" , &cv_moveaxis4 , 30}, + {IT_STRING | IT_CVAR, NULL, "Brake" , &cv_brakeaxis4 , 35}, + {IT_STRING | IT_CVAR, NULL, "Drift" , &cv_driftaxis4 , 40}, + {IT_STRING | IT_CVAR, NULL, "Use Item" , &cv_fireaxis4 , 45}, + {IT_STRING | IT_CVAR, NULL, "Look Backward" , &cv_lookbackaxis4 , 50}, + {IT_STRING | IT_CVAR, NULL, "Spec. Look Up/Down" , &cv_lookaxis4 , 55}, + {IT_STRING | IT_CVAR, NULL, "Custom Button 1" , &cv_custom1axis4 , 60}, + {IT_STRING | IT_CVAR, NULL, "Custom Button 2" , &cv_custom2axis4 , 65}, + {IT_STRING | IT_CVAR, NULL, "Custom Button 3" , &cv_custom3axis4 , 70}, + {IT_STRING | IT_CVAR, NULL, "X deadzone" , &cv_xdeadzone4 , 75}, + {IT_STRING | IT_CVAR, NULL, "Y deadzone" , &cv_ydeadzone4 , 80}, + + {IT_STRING | IT_CVAR, NULL, "Controller Rumble" , &cv_rumble[3] , 90}, + {IT_STRING | IT_CVAR, NULL, "Set LED to skin color" , &cv_gamepadled[3] , 95}, + {IT_STRING | IT_CVAR, NULL, "Flash LED on powerups" , &cv_ledpowerup[3] , 100}, }; static menuitem_t OP_JoystickSetMenu[] = @@ -1342,17 +1372,16 @@ static menuitem_t OP_VideoOptionsMenu[] = {IT_STRING | IT_CVAR, NULL, "Draw Distance", &cv_drawdist, 65}, {IT_STRING | IT_CVAR, NULL, "Weather Draw Distance",&cv_drawdist_precip, 75}, - {IT_STRING | IT_CVAR | IT_CV_BIGFLOAT, NULL, "Field of View", &cv_fov, 95}, - {IT_STRING | IT_CVAR, NULL, "Show FPS", &cv_ticrate, 105}, - {IT_STRING | IT_CVAR, NULL, "Vertical Sync", &cv_vidwait, 115}, - {IT_STRING | IT_CVAR, NULL, "FPS Cap", &cv_fpscap, 125}, - {IT_STRING | IT_CVAR, NULL, "Drift spark pulse size",&cv_driftsparkpulse, 135}, - {IT_STRING | IT_CVAR, NULL, "VHS effect", &cv_vhseffect, 145}, + {IT_STRING | IT_CVAR, NULL, "Show FPS", &cv_ticrate, 95}, + {IT_STRING | IT_CVAR, NULL, "Vertical Sync", &cv_vidwait, 105}, + {IT_STRING | IT_CVAR, NULL, "FPS Cap", &cv_fpscap, 115}, + {IT_STRING | IT_CVAR, NULL, "Drift spark pulse size",&cv_driftsparkpulse, 125}, + {IT_STRING | IT_CVAR, NULL, "VHS effect", &cv_vhseffect, 135}, #ifdef HWRENDER - {IT_SUBMENU|IT_STRING, NULL, "OpenGL Options...", &OP_OpenGLOptionsDef, 155}, + {IT_SUBMENU|IT_STRING, NULL, "OpenGL Options...", &OP_OpenGLOptionsDef, 145}, #endif - {IT_SUBMENU|IT_STRING, NULL, "Experimental Options...", &OP_ExpOptionsDef, 165}, + {IT_SUBMENU|IT_STRING, NULL, "Advanced Video Options...", &OP_ExpOptionsDef, 155}, }; @@ -1367,7 +1396,6 @@ static const char* OP_VideoTooltips[] = "Advanced color settings of the game.", "How far away objects are drawn.", "How far away weather is drawn.", - "Player field of view.", "Show current game framerate and select the style.", "Sync game framerate to refresh rate of monitor.", "Set manual framerate cap.", @@ -1376,7 +1404,7 @@ static const char* OP_VideoTooltips[] = #ifdef HWRENDER "Options for OpenGL renderer.", #endif - "Experimental graphical options.", + "Advanced graphical options.", }; @@ -1391,7 +1419,6 @@ enum op_video_color, op_video_dd, op_video_wdd, - op_video_fov, op_video_fps, op_video_vsync, op_video_fpscap, @@ -1451,30 +1478,23 @@ static menuitem_t OP_ColorOptionsMenu[] = static menuitem_t OP_ExpOptionsMenu[] = { - {IT_HEADER, NULL, "Experimental Options", NULL, 10}, - {IT_STRING|IT_CVAR, NULL, "Interpolation Distance", &cv_grmaxinterpdist, 20}, - {IT_STRING|IT_CVAR, NULL, "Mobj Subsector Interpolation", &cv_mobjssector, 25}, - {IT_STRING | IT_CVAR, NULL, "Weather Interpolation", &cv_precipinterp, 30}, - {IT_STRING | IT_CVAR, NULL, "Less Weather Effects", &cv_lessprecip, 35}, + {IT_HEADER, NULL, "Advanced Video Options", NULL, 10}, + {IT_STRING|IT_CVAR, NULL, "Interpolation Distance", &cv_grmaxinterpdist, 30}, + {IT_STRING | IT_CVAR, NULL, "Weather Interpolation", &cv_precipinterp, 40}, - {IT_STRING | IT_CVAR, NULL, "Skyboxes", &cv_skybox, 42}, + {IT_STRING | IT_CVAR, NULL, "Scale Weather with Mobjscale", &cv_mobjscaleprecip, 60}, + {IT_STRING | IT_CVAR, NULL, "Less Weather Effects", &cv_lessprecip, 70}, - {IT_STRING | IT_CVAR, NULL, "Clipping R_PointToAngle Version", &cv_pointoangleexor64, 49}, + {IT_STRING | IT_CVAR, NULL, "Skyboxes", &cv_skybox, 80}, - {IT_STRING | IT_CVAR, NULL, "FFloorclip", &cv_ffloorclip, 56}, - {IT_STRING | IT_CVAR, NULL, "Spriteclip", &cv_spriteclip, 61}, #ifdef HWRENDER - {IT_STRING | IT_CVAR, NULL, "Screen Textures", &cv_grscreentextures, 68}, + {IT_STRING | IT_CVAR, NULL, "Screen Textures", &cv_grscreentextures, 100}, #ifdef USE_FBO_OGL - {IT_STRING | IT_CVAR, NULL, "FBO Downsampling support", &cv_grframebuffer, 73}, + {IT_STRING | IT_CVAR, NULL, "FBO Downsampling support", &cv_grframebuffer, 110}, #endif + {IT_STRING | IT_CVAR, NULL, "Palette Depth", &cv_grpalettedepth, 130}, - {IT_STRING | IT_CVAR, NULL, "Palette Depth", &cv_grpalettedepth, 80}, - - {IT_STRING | IT_CVAR, NULL, "Splitwall/Slope texture fix", &cv_splitwallfix, 87}, - {IT_STRING | IT_CVAR, NULL, "Slope midtexture peg fix", &cv_slopepegfix, 92}, - {IT_STRING | IT_CVAR, NULL, "ZFighting fix for fofs", &cv_fofzfightfix, 97}, - {IT_STRING | IT_CVAR, NULL, "FOF wall cutoff for slopes", &cv_grfofcut, 102}, + {IT_STRING | IT_CVAR, NULL, "Splitwall/Slope texture fix", &cv_splitwallfix, 150}, #endif }; @@ -1482,23 +1502,17 @@ static const char* OP_ExpTooltips[] = { NULL, "How far Mobj interpolation should take effect.", - "Toggles Mobj Subsector Interpolation.", "Should weather be interpolated? Weather should look about the\nsame but perform a bit better when disabled.", + "Should weather be scaled with Mapobjectscale?.", "When weather is on this will cut the object amount used in half.", "Toggle being able to see the sky.", - "Which version of R_PointToAngle should\nbe used for Sector Clipping?\n64 may fix rendering issues on larger maps\nat the cost of performance.", - "Hides 3DFloors which are not visible\npotentially resulting in a performance boost.", - "Hides Sprites which are not visible\npotentially resulting in a performance boost.", #ifdef HWRENDER "Should the game do Screen Textures? Provides a good boost to frames\nat the cost of some visual effects not working when disabled.", #ifdef USE_FBO_OGL - "Allows the game to downsample from a higher resolution than your display in OpenGL renderer mode\nrequires a GPU with atleast OpenGL 3.0 support.", + "Allows the game to downsample from a higher resolution than your display\nin OpenGL renderer mode. Requires a GPU with atleast OpenGL 3.0 support.", #endif - "Change the depth of the Palette in Palette rendering mod\n 16 bits is like software looks ingame\nwhile 24 bits is how software looks in screenshots.", + "Change the depth of the Palette in Palette rendering mode\n 16 bits is like software looks ingame\nwhile 24 bits is how software looks in screenshots.", "Fixes issues that resulted in Textures sticking from the ground sometimes.\n This may be CPU heavy and result in worse performance in some cases.", - "Fixes issues that resulted in Textures not being properly skewed\n example: Fences on slopes that didnt show proper.\n This may be CPU heavy and result in worse performance in some cases.", - "Fixes issues that resulted in Textures on Floor over Floors\nZFighting heavily.", - "Toggle for FOF wall cutoff with slopes.", #endif }; @@ -1506,13 +1520,10 @@ enum { op_exp_header, op_exp_interpdist, - op_exp_mobjssector, op_exp_precipinter, + op_exp_precipmoscale, op_exp_lessprecip, op_exp_skybox, - op_exp_angleshit, - op_exp_ffclip, - op_exp_sprclip, #ifdef HWRENDER op_exp_grscrtx, #ifdef USE_FBO_OGL @@ -1520,9 +1531,6 @@ enum #endif op_exp_paldepth, op_exp_spltwal, - op_exp_pegging, - op_exp_fofzfight, - op_exp_fofcut, #endif }; @@ -1530,23 +1538,24 @@ enum #ifdef HWRENDER static menuitem_t OP_OpenGLOptionsMenu[] = { - {IT_STRING | IT_CVAR, NULL, "3D Models", &cv_grmdls, 15}, - {IT_STRING | IT_CVAR, NULL, "Fallback Player 3D Model", &cv_grfallbackplayermodel, 20}, - {IT_STRING | IT_CVAR, NULL, "Shaders", &cv_grshaders, 25}, - {IT_STRING | IT_CVAR, NULL, "Palette Rendering", &cv_grpaletterendering, 30}, - {IT_STRING | IT_CVAR, NULL, "Flashpals in Palette Renderer", &cv_grflashpal, 35}, - {IT_STRING | IT_CVAR, NULL, "Min Shader Brightness", &cv_secbright, 40}, + {IT_STRING | IT_CVAR, NULL, "3D Models", &cv_grmdls, 15}, + {IT_STRING | IT_CVAR, NULL, "Fallback Player 3D Model", &cv_grfallbackplayermodel, 20}, + {IT_STRING | IT_CVAR, NULL, "Shaders", &cv_grshaders, 25}, + {IT_STRING | IT_CVAR, NULL, "Palette Rendering", &cv_grpaletterendering, 30}, + {IT_STRING | IT_CVAR, NULL, "Flashpals in Palette Renderer", &cv_grflashpal, 35}, + {IT_STRING | IT_CVAR, NULL, "Min Shader Brightness", &cv_secbright, 40}, - {IT_STRING|IT_CVAR, NULL, "Texture Quality", &cv_scr_depth, 50}, - {IT_STRING|IT_CVAR, NULL, "Texture Filter", &cv_grfiltermode, 55}, - {IT_STRING|IT_CVAR, NULL, "Anisotropic", &cv_granisotropicmode, 60}, - {IT_STRING|IT_CVAR, NULL, "Visual Portals", &cv_grportals, 65}, + {IT_STRING|IT_CVAR, NULL, "Texture Quality", &cv_scr_depth, 50}, + {IT_STRING|IT_CVAR, NULL, "Texture Filter", &cv_grfiltermode, 55}, + {IT_STRING|IT_CVAR, NULL, "Anisotropic", &cv_granisotropicmode, 60}, + {IT_STRING|IT_CVAR, NULL, "Visual Portals", &cv_grportals, 65}, {IT_STRING|IT_CVAR, NULL, "Wall Contrast Style", &cv_grfakecontrast, 75}, {IT_STRING|IT_CVAR, NULL, "Slope Contrast", &cv_grslopecontrast, 80}, - {IT_STRING|IT_CVAR, NULL, "Sprite Billboarding", &cv_grspritebillboarding, 85}, - {IT_STRING|IT_CVAR, NULL, "Software Perspective", &cv_grshearing, 90}, - {IT_STRING|IT_CVAR, NULL, "Rendering Distance", &cv_grrenderdistance, 95}, + {IT_STRING | IT_CVAR, NULL, "Dithered Lightning", &cv_lightdither, 85}, + {IT_STRING|IT_CVAR, NULL, "Sprite Billboarding", &cv_grspritebillboarding, 90}, + {IT_STRING|IT_CVAR, NULL, "Software Perspective", &cv_grshearing, 95}, + {IT_STRING|IT_CVAR, NULL, "Rendering Distance", &cv_grrenderdistance, 100}, }; static const char* OP_OpenGLTooltips[] = @@ -1563,6 +1572,7 @@ static const char* OP_OpenGLTooltips[] = "Recreates an effect from software mode that is used on some maps.", "The look of the wall contrast effect.", "Wall contrast but for slopes.", + "Should OpenGL lightning be dithered?", "Should sprites always face the camera?", "Recreates the look of software mode camera perspective.", "How far the game world should be drawn.", @@ -1592,20 +1602,7 @@ static menuitem_t OP_SoundOptionsMenu[] = {IT_STRING|IT_CVAR, NULL, "Chat Notifications", &cv_chatnotifications, 75}, {IT_STRING|IT_CVAR, NULL, "Character voices", &cv_kartvoices, 85}, - {IT_STRING|IT_CVAR, NULL, "Powerup Warning", &cv_kartinvinsfx, 95}, - - {IT_KEYHANDLER|IT_STRING, NULL, "Sound Test", M_HandleSoundTest, 105}, - {IT_STRING|IT_CALL, NULL, "Music Test", M_MusicTest, 115}, - - {IT_STRING|IT_CVAR, NULL, "Play Music While Unfocused", &cv_playmusicifunfocused, 125}, - {IT_STRING|IT_CVAR, NULL, "Play SFX While Unfocused", &cv_playsoundifunfocused, 135}, - {IT_STRING|IT_SUBMENU, NULL, "Advanced Settings...", &OP_SoundAdvancedDef, 155} -#else - {IT_STRING|IT_CVAR, NULL, "Reverse L/R Channels", &stereoreverse, 60}, - {IT_STRING|IT_CVAR, NULL, "Surround Sound", &surround, 70}, - - {IT_STRING|IT_CVAR, NULL, "Chat Notifications", &cv_chatnotifications, 85}, - {IT_STRING|IT_CVAR, NULL, "Character voices", &cv_kartvoices, 95}, + {IT_STRING|IT_CVAR, NULL, "Hit Em Delay", &cv_karthitemdialog, 95}, {IT_STRING|IT_CVAR, NULL, "Powerup Warning", &cv_kartinvinsfx, 105}, {IT_KEYHANDLER|IT_STRING, NULL, "Sound Test", M_HandleSoundTest, 115}, @@ -1613,6 +1610,21 @@ static menuitem_t OP_SoundOptionsMenu[] = {IT_STRING|IT_CVAR, NULL, "Play Music While Unfocused", &cv_playmusicifunfocused, 135}, {IT_STRING|IT_CVAR, NULL, "Play SFX While Unfocused", &cv_playsoundifunfocused, 145}, + {IT_STRING|IT_SUBMENU, NULL, "Advanced Settings...", &OP_SoundAdvancedDef, 155} +#else + {IT_STRING|IT_CVAR, NULL, "Reverse L/R Channels", &stereoreverse, 60}, + {IT_STRING|IT_CVAR, NULL, "Surround Sound", &surround, 70}, + + {IT_STRING|IT_CVAR, NULL, "Chat Notifications", &cv_chatnotifications, 85}, + {IT_STRING|IT_CVAR, NULL, "Character voices", &cv_kartvoices, 95}, + {IT_STRING|IT_CVAR, NULL, "Hit Em Delay", &cv_karthitemdialog, 105}, + {IT_STRING|IT_CVAR, NULL, "Powerup Warning", &cv_kartinvinsfx, 115}, + + {IT_KEYHANDLER|IT_STRING, NULL, "Sound Test", M_HandleSoundTest, 125}, + {IT_STRING|IT_CALL, NULL, "Music Test", M_MusicTest, 135}, + + {IT_STRING|IT_CVAR, NULL, "Play Music While Unfocused", &cv_playmusicifunfocused, 145}, + {IT_STRING|IT_CVAR, NULL, "Play SFX While Unfocused", &cv_playsoundifunfocused, 155}, {IT_STRING|IT_SUBMENU, NULL, "Advanced Settings...", &OP_SoundAdvancedDef, 165} #endif }; @@ -1631,6 +1643,7 @@ static const char* OP_SoundTooltips[] = "Surround Sound.", "Chat notification sound.", "Frequency of character voice lines.", + "Play 'Hit Em' character line after other player's hurt line.", "Should the powerup warning be a sound effect or music?", "Testing sounds...", "Testing music...", @@ -1655,7 +1668,9 @@ static menuitem_t OP_SoundAdvancedMenu[] = {IT_HEADER, NULL, "Misc", NULL, 105}, {IT_STRING | IT_CVAR, NULL, "Grow Music", &cv_growmusic, 117}, - {IT_STRING | IT_CVAR, NULL, "Invulnerability Music", &cv_supermusic, 137}, + {IT_STRING | IT_CVAR, NULL, "Invulnerability Music", &cv_supermusic, 127}, + + {IT_STRING | IT_CVAR, NULL, "Audio Buffer Size", &cv_audbuffersize, 147}, }; static const char* OP_SoundAdvancedTooltips[] = @@ -1673,7 +1688,7 @@ static const char* OP_SoundAdvancedTooltips[] = NULL, "Should the Grow music be on or off?", "Should the Invulnerability music be on or off?", - + "Size of the Audio Buffer\nreducing it will result in less sound latency\nbut may cause issues such as crackling or distorted Sound.", }; static menuitem_t OP_DataOptionsMenu[] = @@ -1775,7 +1790,7 @@ static menuitem_t OP_HUDOptionsMenu[] = {IT_STRING | IT_CVAR | IT_CV_SLIDER, NULL, "HUD Visibility", &cv_translucenthud, 20}, - {IT_STRING | IT_SUBMENU, NULL, "Online HUD options...",&OP_ChatOptionsDef, 35}, + {IT_STRING | IT_SUBMENU, NULL, "Online HUD options...", &OP_ChatOptionsDef, 35}, {IT_STRING | IT_CVAR, NULL, "Background Glass", &cons_backcolor, 45}, {IT_STRING | IT_CVAR | IT_CV_SLIDER, @@ -1797,6 +1812,95 @@ static menuitem_t OP_HUDOptionsMenu[] = {IT_STRING | IT_CVAR, NULL, "2D character select", &cv_skinselectmenu, 165}, }; +static menuitem_t OP_CamOptionsMenu[] = +{ + {IT_HEADER, NULL, "Camera Options", NULL, 0}, + + {IT_STRING | IT_CVAR | IT_CV_BIGFLOAT, NULL, "Field of View",&cv_fov, 30}, + + {IT_STRING | IT_CVAR, NULL, "Lagless Camera", &cv_laglesscam, 50}, + {IT_STRING | IT_CVAR, NULL, "Camera Lookback Momentum", &cv_lookbackmom, 60}, + + {IT_STRING | IT_SUBMENU, NULL, "Player 1 Camera options...", &OP_Player1CamOptionsDef, 80}, + {IT_STRING | IT_SUBMENU, NULL, "Player 2 Camera options...", &OP_Player2CamOptionsDef, 90}, + {IT_STRING | IT_SUBMENU, NULL, "Player 3 Camera options...", &OP_Player3CamOptionsDef, 100}, + {IT_STRING | IT_SUBMENU, NULL, "Player 4 Camera options...", &OP_Player4CamOptionsDef, 110}, +}; + +static const char* OP_CamOptionsTooltips[] = +{ + NULL, + "Player field of view.", + "Removes Camera Lag in netgames\nMay cause Camera stutters in poor net conditions.", + "Should looking back inherit the Players Momentum?\nEither inherit Player Momentum or double of it\nmay make looking back while boosting or going in high speed less jarring", + NULL, + NULL, + NULL, + NULL, +}; + +static menuitem_t OP_Player1CamOptionsMenu[] = +{ + {IT_HEADER, NULL, "Player 1 Camera Options", NULL, 0}, + + {IT_STRING | IT_CVAR, NULL, "Flipcam", &cv_flipcam, 30}, + {IT_STRING | IT_CVAR | IT_CV_BIGFLOAT, NULL, "Camera Distance", &cv_cam_dist, 40}, + {IT_STRING | IT_CVAR | IT_CV_BIGFLOAT, NULL, "Camera Height", &cv_cam_height, 50}, + {IT_STRING | IT_CVAR, NULL, "Camera Speed", &cv_cam_speed, 60}, + {IT_STRING | IT_CVAR, NULL, "Camera Rotation Speed", &cv_cam_rotspeed, 70}, + + {IT_STRING | IT_CVAR, NULL, "Third Person Camera", &cv_chasecam, 85}, +}; + +static menuitem_t OP_Player2CamOptionsMenu[] = +{ + {IT_HEADER, NULL, "Player 2 Camera Options", NULL, 0}, + + {IT_STRING | IT_CVAR, NULL, "Flipcam", &cv_flipcam2, 30}, + {IT_STRING | IT_CVAR | IT_CV_BIGFLOAT, NULL, "Camera Distance", &cv_cam2_dist, 40}, + {IT_STRING | IT_CVAR | IT_CV_BIGFLOAT, NULL, "Camera Height", &cv_cam2_height, 50}, + {IT_STRING | IT_CVAR, NULL, "Camera Speed", &cv_cam2_speed, 60}, + {IT_STRING | IT_CVAR, NULL, "Camera Rotation Speed", &cv_cam2_rotspeed, 70}, + + {IT_STRING | IT_CVAR, NULL, "Third Person Camera", &cv_chasecam2, 85}, +}; + +static menuitem_t OP_Player3CamOptionsMenu[] = +{ + {IT_HEADER, NULL, "Player 3 Camera Options", NULL, 0}, + + {IT_STRING | IT_CVAR, NULL, "Flipcam", &cv_flipcam3, 30}, + {IT_STRING | IT_CVAR | IT_CV_BIGFLOAT, NULL, "Camera Distance", &cv_cam3_dist, 40}, + {IT_STRING | IT_CVAR | IT_CV_BIGFLOAT, NULL, "Camera Height", &cv_cam3_height, 50}, + {IT_STRING | IT_CVAR, NULL, "Camera Speed", &cv_cam3_speed, 60}, + {IT_STRING | IT_CVAR, NULL, "Camera Rotation Speed", &cv_cam3_rotspeed, 70}, + + {IT_STRING | IT_CVAR, NULL, "Third Person Camera", &cv_chasecam3, 85}, +}; + +static menuitem_t OP_Player4CamOptionsMenu[] = +{ + {IT_HEADER, NULL, "Player 4 Camera Options", NULL, 0}, + + {IT_STRING | IT_CVAR, NULL, "Flipcam", &cv_flipcam4, 30}, + {IT_STRING | IT_CVAR | IT_CV_BIGFLOAT, NULL, "Camera Distance", &cv_cam4_dist, 40}, + {IT_STRING | IT_CVAR | IT_CV_BIGFLOAT, NULL, "Camera Height", &cv_cam4_height, 50}, + {IT_STRING | IT_CVAR, NULL, "Camera Speed", &cv_cam4_speed, 60}, + {IT_STRING | IT_CVAR, NULL, "Camera Rotation Speed", &cv_cam4_rotspeed, 70}, + + {IT_STRING | IT_CVAR, NULL, "Third Person Camera", &cv_chasecam4, 85}, +}; + +static const char* OP_PlayerCamOptionsTooltips[] = +{ + NULL, + "Should the Camera flip on gravity flipped sections?.", + "Camera distance relative to the Player.", + "Height of the Camera", + "Speed of the Camera", + "Speed of the Camera rotation", + "Toggle between Third or First Person camera", +}; // Ok it's still called chatoptions but we'll put ping display in here to be clean static menuitem_t OP_ChatOptionsMenu[] = @@ -1878,7 +1982,6 @@ static menuitem_t OP_ServerOptionsMenu[] = {IT_STRING | IT_CVAR | IT_CV_STRING, NULL, "Server Name", &cv_servername, 10}, #endif - {IT_STRING | IT_CVAR, NULL, "Intermission Timer", &cv_inttime, 40}, {IT_STRING | IT_CVAR, NULL, "Map Progression", &cv_advancemap, 50}, {IT_STRING | IT_CVAR, NULL, "Voting Timer", &cv_votetime, 60}, @@ -1918,34 +2021,50 @@ static const char* OP_ServerOptionsTooltips[] = static menuitem_t OP_AdvServerOptionsMenu[] = { #ifndef MASTERSERVER - {IT_GRAYEDOUT, - - NULL, "Server Browser Address", NULL, 10}, + {IT_GRAYEDOUT, NULL, "Server Browser Address", NULL, 10}, #else {IT_STRING | IT_CVAR | IT_CV_STRING, - - NULL, "Server Browser Address", &cv_masterserver, 10}, + NULL, "Server Browser Address", &cv_masterserver, 10}, #endif - {IT_STRING | IT_CVAR, NULL, "Attempts to resynchronise", &cv_resynchattempts, 40}, + {IT_STRING | IT_CVAR, NULL, "Attempts to resynchronise", &cv_resynchattempts, 25}, +#ifdef SATURNSYNCH + {IT_STRING | IT_CVAR, NULL, "Resend Gamestate Cooldown", &cv_resynchcooldown, 35}, + {IT_STRING | IT_CVAR, NULL, "Resend Gamestate Attempts", &cv_gamestateattempts, 40}, + {IT_STRING | IT_CVAR, NULL, "Delay limit (frames)", &cv_maxping, 50}, - {IT_STRING | IT_CVAR, NULL, "Delay timeout (s)", &cv_pingtimeout, 60}, - {IT_STRING | IT_CVAR, NULL, "Connection timeout (tics)", &cv_nettimeout, 70}, - {IT_STRING | IT_CVAR, NULL, "Join timeout (tics)", &cv_jointimeout, 80}, + {IT_STRING | IT_CVAR, NULL, "Delay timeout (s)", &cv_pingtimeout, 55}, + {IT_STRING | IT_CVAR, NULL, "Connection timeout (tics)", &cv_nettimeout, 60}, + {IT_STRING | IT_CVAR, NULL, "Join timeout (tics)", &cv_jointimeout, 65}, - {IT_STRING | IT_CVAR, NULL, "Max. file transfer send (KB)", &cv_maxsend, 100}, - {IT_STRING | IT_CVAR, NULL, "File transfer packet rate", &cv_downloadspeed, 110}, + {IT_STRING | IT_CVAR, NULL, "Max. file transfer send (KB)", &cv_maxsend, 75}, + {IT_STRING | IT_CVAR, NULL, "File transfer packet rate", &cv_downloadspeed, 80}, - {IT_STRING | IT_CVAR, NULL, "Log join addresses", &cv_showjoinaddress, 130}, - {IT_STRING | IT_CVAR, NULL, "Log resyncs", &cv_blamecfail, 140}, - {IT_STRING | IT_CVAR, NULL, "Log file transfers", &cv_noticedownload, 150}, -}; + {IT_STRING | IT_CVAR, NULL, "Log join addresses", &cv_showjoinaddress, 90}, + {IT_STRING | IT_CVAR, NULL, "Log resyncs", &cv_blamecfail, 95}, + {IT_STRING | IT_CVAR, NULL, "Log file transfers", &cv_noticedownload, 100}, +#else + {IT_STRING | IT_CVAR, NULL, "Delay limit (frames)", &cv_maxping, 35}, + {IT_STRING | IT_CVAR, NULL, "Delay timeout (s)", &cv_pingtimeout, 40}, + {IT_STRING | IT_CVAR, NULL, "Connection timeout (tics)", &cv_nettimeout, 45}, + {IT_STRING | IT_CVAR, NULL, "Join timeout (tics)", &cv_jointimeout, 50}, + + {IT_STRING | IT_CVAR, NULL, "Max. file transfer send (KB)", &cv_maxsend, 60}, + {IT_STRING | IT_CVAR, NULL, "File transfer packet rate", &cv_downloadspeed, 65}, + + {IT_STRING | IT_CVAR, NULL, "Log join addresses", &cv_showjoinaddress, 70}, + {IT_STRING | IT_CVAR, NULL, "Log resyncs", &cv_blamecfail, 75}, + {IT_STRING | IT_CVAR, NULL, "Log file transfers", &cv_noticedownload, 80}, #endif +}; -#ifndef NONET static const char* OP_AdvServerOptionsTooltips[] = { "Server used for master server.", "Attempts to resynchronise player to server.", +#ifdef SATURNSYNCH + "Cooldown in seconds before the Server attempts\nto resend the gamestate to a Saturn Client\nbetween resending attempts.", + "Attempts to resend the Gamestate to player\nThis increments a Counter everytime a gamestate resend occurs\nThis Counter decrements at double the time of the Cooldown\nonce the Counter reaches the threshold, the client gets kicked.", +#endif "Maximum allowed delay.", "Delay timeout in seconds.", "Connection timeout in tics.", @@ -2028,37 +2147,20 @@ static menuitem_t OP_SaturnMenu[] = { {IT_HEADER, NULL, "Saturn Options", NULL, 0}, - {IT_STRING | IT_CVAR, NULL, "Serverqueue waittime", &cv_connectawaittime, 10}, + {IT_STRING | IT_CVAR, NULL, "Serverqueue waittime", &cv_connectawaittime, 10}, - {IT_STRING | IT_CVAR, NULL, "Skin Select Spinning Speed", &cv_skinselectspin, 20}, - {IT_STRING | IT_CVAR, NULL, "Input Display outside of RA", &cv_showinput, 25}, - {IT_STRING | IT_CVAR, NULL, "Speedometer Style", &cv_newspeedometer, 30}, - {IT_STRING | IT_CVAR, NULL, "Stat Display", &cv_showstats, 35}, - {IT_STRING | IT_CVAR, NULL, "Higher Resolution Portraits", &cv_highresportrait, 40}, - {IT_STRING | IT_CVAR, NULL, "Colourized HUD", &cv_colorizedhud, 45}, - {IT_STRING | IT_CVAR, NULL, "Colourized Itembox", &cv_colorizeditembox, 50}, - {IT_STRING | IT_CVAR, NULL, "Colourized HUD Color", &cv_colorizedhudcolor, 55}, - {IT_STRING | IT_CVAR, NULL, "Show Lap Emblem", &cv_showlapemblem, 60}, - {IT_STRING | IT_CVAR, NULL, "Show Minimap Names", &cv_showminimapnames, 65}, - {IT_STRING | IT_CVAR, NULL, "Small Minimap Players", &cv_minihead, 70}, + {IT_STRING | IT_CVAR, NULL, "Skin Select Spinning Speed", &cv_skinselectspin, 20}, - {IT_STRING | IT_CVAR, NULL, "Uncapped HUD", &cv_uncappedhud, 80}, + {IT_STRING | IT_CVAR, NULL, "Show Localskin Menus", &cv_showlocalskinmenus, 30}, + {IT_STRING | IT_CVAR, NULL, "Uppercase Menu", &cv_menucaps, 35}, - {IT_STRING | IT_CVAR, NULL, "Show Cecho Messages", &cv_cechotoggle, 85}, - {IT_STRING | IT_CVAR, NULL, "Show Localskin Menus", &cv_showlocalskinmenus, 90}, - {IT_STRING | IT_CVAR, NULL, "Uppercase Menu", &cv_menucaps, 95}, + {IT_STRING | IT_CVAR, NULL, "Keyboard Layout", &cv_keyboardlayout, 45}, - {IT_STRING | IT_CVAR, NULL, "Keyboard Layout", &cv_keyboardlayout, 105}, + {IT_STRING | IT_CVAR, NULL, "Less Midnight Channel Flicker", &cv_lessflicker, 55}, - {IT_STRING | IT_CVAR, NULL, "Less Midnight Channel Flicker", &cv_lessflicker, 115}, - - {IT_STRING | IT_SUBMENU, NULL, "Nametags...", &OP_NametagDef, 125}, - {IT_STRING | IT_SUBMENU, NULL, "Driftgauge...", &OP_DriftGaugeDef, 130}, - - {IT_SUBMENU|IT_STRING, NULL, "Sprite Distortion...", &OP_PlayerDistortDef, 140}, - {IT_SUBMENU|IT_STRING, NULL, "Hud Offsets...", &OP_HudOffsetDef, 145}, - - {IT_SUBMENU|IT_STRING, NULL, "Saturn Credits", &OP_SaturnCreditsDef, 155}, // uwu + {IT_SUBMENU|IT_STRING, NULL, "Saturn Hud...", &OP_SaturnHudDef, 65}, + {IT_SUBMENU|IT_STRING, NULL, "Sprite Distortion...", &OP_PlayerDistortDef, 70}, + {IT_SUBMENU|IT_STRING, NULL, "Saturn Credits", &OP_SaturnCreditsDef, 80}, // uwu }; static const char* OP_SaturnTooltips[] = @@ -2066,26 +2168,12 @@ static const char* OP_SaturnTooltips[] = NULL, "How long can the game wait before it kicks you out from the server\nconnecting screen.", "How much speen do you want?", - "Displays the input display outside of Record Attack. Also adjusts the\nposition scale to match.", - "Change what style the speedometer is.", - "Enable the stat display.", - "Enable the use of the higher resolution want icons instead of rank\nfor some places.", - "Enable colourized hud.", - "Enable the colourized itembox when colourized hud is enabled.", - "The color to use instead of the player color when colourized hud is enabled.", - "Show the big 'LAP' text on a lap change.", - "Show player names on the minimap.", - "Minimize the player icons on the minimap.", - "Uncaps the HUD framerate, making it appear smoother.", - "Show the big Cecho Messages.", "Show Localskin Menus.", "Force menu to only use uppercase.", "Use your desired Keyboard Layout for Text Input\nthis is either the Default, Native or Azerty\nNative does not affect Gameplay only Text!", "Disables the flicker effect on Midnight Channel.", - "Nametag Options.", - "Driftgauge Options.", + "Options for Saturn specific HUD things.", "Options for sprite distortion effects.", - "Move position of HUD elements.", "See the people who helped make this project possible!", }; @@ -2094,26 +2182,12 @@ enum sm_header, sm_waittime, sm_skinselspeed, - sm_input, - sm_speedometer, - sm_statdisplay, - sm_highresport, - sm_colorhud, - sm_coloritem, - sm_colorhud_customcolor, - sm_lapemblem, - sm_mapnames, - sm_smallmap, - sm_uncappedhud, - sm_cechotogle, sm_showlocalskin, op_uppercase_menu, sm_nativkey, sm_pisschannel, - sm_nametagmen, - sm_driftgaugemen, + sm_hud, sm_distortionmenu, - sm_hudoffsets, sm_credits, }; @@ -2163,6 +2237,92 @@ enum saltsquishy, }; +static menuitem_t OP_SaturnHudMenu[] = +{ + {IT_HEADER, NULL, "Saturn Hud Options", NULL, 0}, + + {IT_STRING | IT_CVAR, NULL, "Speedometer Style", &cv_newspeedometer, 10}, + {IT_STRING | IT_CVAR, NULL, "Battle Speedometer", &cv_battlespeedo, 15}, + + {IT_STRING | IT_CVAR, NULL, "Input Display outside of RA", &cv_showinput, 20}, + + {IT_STRING | IT_CVAR, NULL, "Flash Lap Times", &cv_showlaptimes, 25}, + + {IT_STRING | IT_CVAR, NULL, "Stat Display", &cv_showstats, 30}, + + {IT_STRING | IT_CVAR, NULL, "Higher Resolution Portraits", &cv_highresportrait, 35}, + + {IT_STRING | IT_CVAR, NULL, "Colourized HUD", &cv_colorizedhud, 40}, + {IT_STRING | IT_CVAR, NULL, "Colourized Itembox", &cv_colorizeditembox, 45}, + {IT_STRING | IT_CVAR, NULL, "Colourized HUD Color", &cv_colorizedhudcolor, 50}, + + {IT_STRING | IT_CVAR, NULL, "Show Lap Emblem", &cv_showlapemblem, 60}, + {IT_STRING | IT_CVAR, NULL, "Show Cecho Messages", &cv_cechotoggle, 65}, + + {IT_STRING | IT_CVAR, NULL, "Show Names on Minimap", &cv_showminimapnames, 70}, + {IT_STRING | IT_CVAR, NULL, "Small Minimap Players", &cv_minihead, 75}, + + {IT_STRING | IT_CVAR, NULL, "Show Director Prompt", &cv_showdirectorhud, 80}, + + {IT_STRING | IT_CVAR, NULL, "Beta Intermissionscreen", &cv_betainterscreen, 90}, + + {IT_STRING | IT_CVAR, NULL, "Uncapped HUD", &cv_uncappedhud, 100}, + + {IT_STRING | IT_SUBMENU, NULL, "Nametags...", &OP_NametagDef, 110}, + {IT_STRING | IT_SUBMENU, NULL, "Driftgauge...", &OP_DriftGaugeDef, 115}, + + {IT_SUBMENU|IT_STRING, NULL, "Hud Offsets...", &OP_HudOffsetDef, 125}, +}; + +static const char* OP_SaturnHudTooltips[] = +{ + NULL, + "Change what style the speedometer is.", + "Draw the Speedometer in Battle.", + "Displays the input display outside of Record Attack. Also adjusts the\nposition scale to match.", + "Flash current Lap Time when doing a Lap on the Timer.", + "Enable the stat display.", + "Enable the use of the higher resolution want icons instead of rank\nfor some places.", + "Enable colourized hud.", + "Enable the colourized itembox when colourized hud is enabled.", + "The color to use instead of the player color when\ncolourized hud is enabled.", + "Show the big 'LAP' text on a lap change.", + "Show the big Cecho Messages.", + "Show player names on the minimap.", + "Minimize the player icons on the minimap.", + "Show the Director Toggle prompt when spectating.", + "Make the Intermission screen look like in beta versions of Kart!\nEither with background or just the rest.", + "Uncaps the HUD framerate, making it appear smoother.", + "Nametag Options.", + "Driftgauge Options.", + "Move position of HUD elements.", +}; + +enum +{ + sh_header, + sh_speedometer, + sh_battlespeedo, + sh_input, + sh_laptime, + sh_statdisplay, + sh_highresport, + sh_colorhud, + sh_coloritem, + sh_colorhud_customcolor, + sh_lapemblem, + sh_cechotogle, + sh_mapname, + sh_smallmap, + sh_directorhud, + sh_betainter, + sh_uncappedhud, + sh_nametagmen, + sh_driftgaugemen, + sh_hudoffsets, +}; + + static menuitem_t OP_HudOffsetMenu[] = { {IT_HEADER, NULL, "Kart Hud Offsets", NULL, 0}, @@ -2231,7 +2391,7 @@ static menuitem_t OP_SaturnCreditsMenu[] = {IT_STRING2+IT_SPACE, NULL, "Galactice for Galaxy", NULL, 180}, {IT_STRING+IT_SPACE, NULL, "", NULL, 190}, // dummy text II - {IT_STRING, NULL, "", NULL, 200}, // dummy text III + {IT_STRING, NULL, "", NULL, 250}, // dummy text III }; static const char* OP_CreditTooltips[] = @@ -2420,7 +2580,6 @@ static menuitem_t OP_AdvancedBirdMenu[] = {IT_STRING | IT_CVAR, NULL, "Fade Back In While Respawning", &cv_respawnfademusicback, 40}, {IT_STRING | IT_CVAR, NULL, "Resync Threshold", &cv_music_resync_threshold, 60}, - {IT_STRING | IT_CVAR, NULL, "Resync Special Music Only", &cv_music_resync_powerups_only, 70}, }; static const char* OP_AdvancedBirdTooltips[] = @@ -2806,10 +2965,10 @@ menu_t OP_ControlsDef = DEFAULTMENUSTYLE("M_CONTRO", OP_ControlsMenu, &OP_MainDe //WTF menu_t OP_MouseOptionsDef = DEFAULTMENUSTYLE("M_CONTRO", OP_MouseOptionsMenu, &OP_ControlsDef, 60, 30); menu_t OP_AllControlsDef = CONTROLMENUSTYLE(OP_AllControlsMenu, &OP_ControlsDef); -menu_t OP_Joystick1Def = DEFAULTMENUSTYLE("M_CONTRO", OP_Joystick1Menu, &OP_AllControlsDef, 60, 30); -menu_t OP_Joystick2Def = DEFAULTMENUSTYLE("M_CONTRO", OP_Joystick2Menu, &OP_AllControlsDef, 60, 30); -menu_t OP_Joystick3Def = DEFAULTMENUSTYLE("M_CONTRO", OP_Joystick3Menu, &OP_AllControlsDef, 60, 30); -menu_t OP_Joystick4Def = DEFAULTMENUSTYLE("M_CONTRO", OP_Joystick4Menu, &OP_AllControlsDef, 60, 30); +menu_t OP_Joystick1Def = DEFAULTSCROLLSTYLE("M_CONTRO", OP_Joystick1Menu, &OP_AllControlsDef, 60, 36); +menu_t OP_Joystick2Def = DEFAULTSCROLLSTYLE("M_CONTRO", OP_Joystick2Menu, &OP_AllControlsDef, 60, 36); +menu_t OP_Joystick3Def = DEFAULTSCROLLSTYLE("M_CONTRO", OP_Joystick3Menu, &OP_AllControlsDef, 60, 36); +menu_t OP_Joystick4Def = DEFAULTSCROLLSTYLE("M_CONTRO", OP_Joystick4Menu, &OP_AllControlsDef, 60, 36); menu_t OP_JoystickSetDef = { "M_CONTRO", @@ -2889,6 +3048,11 @@ menu_t OP_HUDOptionsDef = {NULL} }; +menu_t OP_CamOptionsDef = DEFAULTMENUSTYLE(NULL, OP_CamOptionsMenu, &OP_MainDef, 30, 30); +menu_t OP_Player1CamOptionsDef = DEFAULTMENUSTYLE(NULL, OP_Player1CamOptionsMenu, &OP_CamOptionsDef, 30, 30); +menu_t OP_Player2CamOptionsDef = DEFAULTMENUSTYLE(NULL, OP_Player2CamOptionsMenu, &OP_CamOptionsDef, 30, 30); +menu_t OP_Player3CamOptionsDef = DEFAULTMENUSTYLE(NULL, OP_Player3CamOptionsMenu, &OP_CamOptionsDef, 30, 30); +menu_t OP_Player4CamOptionsDef = DEFAULTMENUSTYLE(NULL, OP_Player4CamOptionsMenu, &OP_CamOptionsDef, 30, 30); menu_t OP_ChatOptionsDef = DEFAULTMENUSTYLE("M_HUD", OP_ChatOptionsMenu, &OP_HUDOptionsDef, 30, 30); @@ -2897,7 +3061,7 @@ menu_t OP_SoundAdvancedDef = DEFAULTMENUSTYLE("M_SOUND", OP_SoundAdvancedMenu, & menu_t OP_GameOptionsDef = DEFAULTMENUSTYLE("M_GAME", OP_GameOptionsMenu, &OP_MainDef, 30, 20); menu_t OP_ServerOptionsDef = DEFAULTMENUSTYLE("M_SERVER", OP_ServerOptionsMenu, &OP_MainDef, 24, 20); #ifndef NONET -menu_t OP_AdvServerOptionsDef = DEFAULTMENUSTYLE("M_SERVER", OP_AdvServerOptionsMenu, &OP_ServerOptionsDef, 24, 20); +menu_t OP_AdvServerOptionsDef = DEFAULTSCROLLSTYLE("M_SERVER", OP_AdvServerOptionsMenu, &OP_ServerOptionsDef, 24, 30); #endif //menu_t OP_NetgameOptionsDef = DEFAULTMENUSTYLE("M_SERVER", OP_NetgameOptionsMenu, &OP_ServerOptionsDef, 30, 30); @@ -2920,7 +3084,7 @@ menu_t OP_MonitorToggleDef = menu_t OP_OpenGLOptionsDef = DEFAULTSCROLLSTYLE("M_VIDEO", OP_OpenGLOptionsMenu, &OP_VideoOptionsDef, 30, 30); #endif -menu_t OP_ExpOptionsDef = DEFAULTSCROLLSTYLE("M_VIDEO", OP_ExpOptionsMenu, &OP_VideoOptionsDef, 30, 35); +menu_t OP_ExpOptionsDef = DEFAULTMENUSTYLE("M_VIDEO", OP_ExpOptionsMenu, &OP_VideoOptionsDef, 30, 30); menu_t OP_DataOptionsDef = DEFAULTMENUSTYLE("M_DATA", OP_DataOptionsMenu, &OP_MainDef, 60, 30); menu_t OP_ScreenshotOptionsDef = DEFAULTMENUSTYLE("M_SCSHOT", OP_ScreenshotOptionsMenu, &OP_DataOptionsDef, 30, 30); @@ -2933,13 +3097,15 @@ menu_t OP_EraseDataDef = DEFAULTMENUSTYLE("M_DATA", OP_EraseDataMenu, &OP_DataOp menu_t OP_SaturnDef = DEFAULTSCROLLSTYLE(NULL, OP_SaturnMenu, &OP_MainDef, 30, 30); menu_t OP_PlayerDistortDef = DEFAULTMENUSTYLE("M_VIDEO", OP_PlayerDistortMenu, &OP_SaturnDef, 30, 30); -menu_t OP_HudOffsetDef = DEFAULTSCROLLSTYLE(NULL, OP_HudOffsetMenu, &OP_SaturnDef, 30, 30); +menu_t OP_HudOffsetDef = DEFAULTSCROLLSTYLE(NULL, OP_HudOffsetMenu, &OP_SaturnHudDef, 30, 30); +menu_t OP_SaturnHudDef = DEFAULTSCROLLSTYLE(NULL, OP_SaturnHudMenu, &OP_SaturnDef, 30, 30); + menu_t OP_SaturnCreditsDef = DEFAULTMENUSTYLE(NULL, OP_SaturnCreditsMenu, &OP_SaturnDef, 30, 10); menu_t OP_BirdDef = DEFAULTMENUSTYLE(NULL, OP_BirdMenu, &OP_MainDef, 30, 30); -menu_t OP_NametagDef = DEFAULTMENUSTYLE(NULL, OP_NametagMenu, &OP_SaturnDef, 30, 40); -menu_t OP_DriftGaugeDef = DEFAULTMENUSTYLE(NULL, OP_DriftGaugeMenu, &OP_SaturnDef, 30, 60); +menu_t OP_NametagDef = DEFAULTMENUSTYLE(NULL, OP_NametagMenu, &OP_SaturnHudDef, 30, 40); +menu_t OP_DriftGaugeDef = DEFAULTMENUSTYLE(NULL, OP_DriftGaugeMenu, &OP_SaturnHudDef, 30, 40); menu_t OP_TiltDef = DEFAULTMENUSTYLE(NULL, OP_TiltMenu, &OP_BirdDef, 30, 60); menu_t OP_AdvancedBirdDef = DEFAULTMENUSTYLE(NULL, OP_AdvancedBirdMenu, &OP_BirdDef, 30, 60); @@ -3264,7 +3430,7 @@ void Bird_menu_Onchange(void) } //menu code is nice -void Saturn_menu_Onchange(void) +void SaturnHud_menu_Onchange(void) { UINT16 status; @@ -3273,8 +3439,8 @@ void Saturn_menu_Onchange(void) else status = IT_GRAYEDOUT; - OP_SaturnMenu[sm_coloritem].status = status; - OP_SaturnMenu[sm_colorhud_customcolor].status = status; + OP_SaturnHudMenu[sh_coloritem].status = status; + OP_SaturnHudMenu[sh_colorhud_customcolor].status = status; } // ========================================================================== @@ -3433,6 +3599,11 @@ static void Command_Manual_f(void) itemOn = 0; } +boolean DPADUPSCROLL = false; +boolean DPADDOWNSCROLL = false; +boolean DPADLEFTSCROLL = false; +boolean DPADRIGHTSCROLL = false; + // // M_Responder // @@ -3464,7 +3635,6 @@ boolean M_Responder(event_t *ev) { ch = ev->data1; - // added 5-2-98 remap virtual keys (mouse & joystick buttons) switch (ch) { case KEY_MOUSE1: @@ -3492,6 +3662,52 @@ boolean M_Responder(event_t *ev) ch = KEY_RIGHTARROW; break; } + + if (menuactive) + { + switch (ev->data1) // if you pressed it set those to true + { + case KEY_HAT1: + DPADUPSCROLL = true; + break; + case KEY_HAT1 + 1: + DPADDOWNSCROLL = true; + break; + case KEY_HAT1 + 2: + DPADLEFTSCROLL = true; + break; + case KEY_HAT1 + 3: + DPADRIGHTSCROLL = true; + break; + } + + if (currentMenu == &MISC_ChangeLevelDef || currentMenu == &MP_OfflineServerDef || currentMenu == &MP_ServerDef) + { + if (ev->data1 == gamecontrol[gc_fire][0] + || ev->data1 == gamecontrol[gc_fire][1]) + { + COM_ImmedExecute("add kartencore 1"); + } + } + } + } + else if (ev->type == ev_keyup) + { + switch (ev->data1) // if you let go of those set those to false + { + case KEY_HAT1: + DPADUPSCROLL = false; + break; + case KEY_HAT1 + 1: + DPADDOWNSCROLL = false; + break; + case KEY_HAT1 + 2: + DPADLEFTSCROLL = false; + break; + case KEY_HAT1 + 3: + DPADRIGHTSCROLL = false; + break; + } } else if (menuactive) { @@ -4044,6 +4260,24 @@ boolean M_DemoResponder(event_t *ev) return eatinput; } +// mhhm yes +static boolean ShouldDrawMenuBG(void) +{ + if (WipeInAction) // dont ever draw stuff in wipes + return false; + + if (currentMenu == &PlaybackMenuDef) // Replay playback has its own background + return false; + + if (forceshowhud) + return false; + + // camera options stuff, only do when in level + if (gamestate == GS_LEVEL && (currentMenu == &OP_CamOptionsDef || currentMenu == &OP_Player1CamOptionsDef || currentMenu == &OP_Player2CamOptionsDef || currentMenu == &OP_Player3CamOptionsDef || currentMenu == &OP_Player4CamOptionsDef)) + return false; + + return true; +} // // M_Drawer @@ -4055,10 +4289,12 @@ void M_Drawer(void) if (currentMenu == &MessageDef) menuactive = true; + forceshowhud = (gamestate == GS_LEVEL && menuactive && (currentMenu == &OP_SaturnHudDef || currentMenu == &OP_HudOffsetDef || currentMenu == &OP_NametagDef || currentMenu == &OP_DriftGaugeDef)); // holy fuick + if (menuactive) { // now that's more readable with a faded background (yeah like Quake...) - if (!WipeInAction && currentMenu != &PlaybackMenuDef) // Replay playback has its own background + if (ShouldDrawMenuBG()) V_DrawFadeScreen(0xFF00, 16); if (currentMenu->drawroutine) @@ -4122,6 +4358,11 @@ void M_StartControlPanel(void) menuactive = true; + DPADUPSCROLL = false; + DPADDOWNSCROLL = false; + DPADLEFTSCROLL = false; + DPADRIGHTSCROLL = false; + if (demo.playback) { currentMenu = &PlaybackMenuDef; @@ -4386,6 +4627,9 @@ void M_Ticker(void) else playback_enterheld = 0; + if (demo.inreplayhut) + M_HutCheckReplays(cv_replaysearchrate.value); + interpTimerHackAllow = true; //added : 30-01-98 : test mode for five seconds @@ -4483,15 +4727,10 @@ void M_Init(void) OP_ExpOptionsMenu[op_exp_fbo].status = IT_DISABLED; #endif OP_ExpOptionsMenu[op_exp_spltwal].status = IT_DISABLED; - OP_ExpOptionsMenu[op_exp_pegging].status = IT_DISABLED; - OP_ExpOptionsMenu[op_exp_fofzfight].status = IT_DISABLED; - OP_ExpOptionsMenu[op_exp_fofcut].status = IT_DISABLED; } if (rendermode == render_opengl) { - OP_ExpOptionsMenu[op_exp_ffclip].status = IT_DISABLED; - OP_ExpOptionsMenu[op_exp_sprclip].status = IT_DISABLED; #ifdef USE_FBO_OGL if (!supportFBO) OP_ExpOptionsMenu[op_exp_fbo].status = IT_GRAYEDOUT; @@ -4500,7 +4739,7 @@ void M_Init(void) #endif if (!xtra_speedo && !kartzspeedo && !achi_speedo) // why bother? - OP_SaturnMenu[sm_speedometer].status = IT_GRAYEDOUT; + OP_SaturnHudMenu[sh_speedometer].status = IT_GRAYEDOUT; //if (!xtra_speedo && kartzspeedo) //OP_SaturnMenu[sm_speedometer].text = "Speedometer (No Small)"; @@ -4511,9 +4750,9 @@ void M_Init(void) if (!clr_hud) // uhguauhauguuhee { - OP_SaturnMenu[sm_colorhud].status = IT_GRAYEDOUT; - OP_SaturnMenu[sm_coloritem].status = IT_GRAYEDOUT; - OP_SaturnMenu[sm_colorhud_customcolor].status = IT_GRAYEDOUT; + OP_SaturnHudMenu[sh_colorhud].status = IT_GRAYEDOUT; + OP_SaturnHudMenu[sh_coloritem].status = IT_GRAYEDOUT; + OP_SaturnHudMenu[sh_colorhud_customcolor].status = IT_GRAYEDOUT; } if (!nametaggfx) @@ -4697,6 +4936,12 @@ void M_DrawTextBox(INT32 x, INT32 y, INT32 width, INT32 boxlines) V_DrawFill(x+5, y+5, width*8+6, boxlines*8+6, 239); } +void M_DrawTextBoxFlags(INT32 x, INT32 y, INT32 width, INT32 boxlines, INT32 flags) +{ + // Solid color textbox. + V_DrawFill(x+5, y+5, width*8+6, boxlines*8+6, 239|flags); +} + // horizontally centered text static void M_CentreText(INT32 y, const char *string) { @@ -4974,175 +5219,25 @@ static void M_DrawGenericMenu(void) // dumb hack // tooltips - if (currentMenu == &OP_ControlsDef) - { - if (!(OP_ControlsTooltips[itemOn] == NULL)) - { - M_DrawSplitText(BASEVIDWIDTH / 2, BASEVIDHEIGHT-50, V_ALLOWLOWERCASE|V_SNAPTOBOTTOM, OP_ControlsTooltips[itemOn], coolalphatimer); - if (coolalphatimer > 0 && interpTimerHackAllow) - coolalphatimer--; - } - } - - if (currentMenu == &OP_MouseOptionsDef) - { - if (!(OP_MouseTooltips[itemOn] == NULL)) - { - M_DrawSplitText(BASEVIDWIDTH / 2, BASEVIDHEIGHT-50, V_ALLOWLOWERCASE|V_SNAPTOBOTTOM, OP_MouseTooltips[itemOn], coolalphatimer); - if (coolalphatimer > 0 && interpTimerHackAllow) - coolalphatimer--; - } - } - - if (currentMenu == &OP_VideoOptionsDef) - { - if (!(OP_VideoTooltips[itemOn] == NULL)) - { - M_DrawSplitText(BASEVIDWIDTH / 2, BASEVIDHEIGHT-50, V_ALLOWLOWERCASE|V_SNAPTOBOTTOM, OP_VideoTooltips[itemOn], coolalphatimer); - if (coolalphatimer > 0 && interpTimerHackAllow) - coolalphatimer--; - } - } - - if (currentMenu == &OP_SoundOptionsDef) - { - if (!(OP_SoundTooltips[itemOn] == NULL)) - { - M_DrawSplitText(BASEVIDWIDTH / 2, BASEVIDHEIGHT-50, V_ALLOWLOWERCASE|V_SNAPTOBOTTOM, OP_SoundTooltips[itemOn], coolalphatimer); - if (coolalphatimer > 0 && interpTimerHackAllow) - coolalphatimer--; - } - } - - if (currentMenu == &OP_SoundAdvancedDef) - { - if (!(OP_SoundAdvancedTooltips[itemOn] == NULL)) - { - M_DrawSplitText(BASEVIDWIDTH / 2, BASEVIDHEIGHT-50, V_ALLOWLOWERCASE|V_SNAPTOBOTTOM, OP_SoundAdvancedTooltips[itemOn], coolalphatimer); - if (coolalphatimer > 0 && interpTimerHackAllow) - coolalphatimer--; - } - } - - if (currentMenu == &OP_ExpOptionsDef) - { - if (!(OP_ExpTooltips[itemOn] == NULL)) - { - M_DrawSplitText(BASEVIDWIDTH / 2, BASEVIDHEIGHT-50, V_ALLOWLOWERCASE|V_SNAPTOBOTTOM, OP_ExpTooltips[itemOn], coolalphatimer); - if (coolalphatimer > 0 && interpTimerHackAllow) - coolalphatimer--; - } - } - - if (currentMenu == &OP_ChatOptionsDef) - { - if (!(OP_ChatOptionsTooltips[itemOn] == NULL)) - { - M_DrawSplitText(BASEVIDWIDTH / 2, BASEVIDHEIGHT-50, V_ALLOWLOWERCASE|V_SNAPTOBOTTOM, OP_ChatOptionsTooltips[itemOn], coolalphatimer); - if (coolalphatimer > 0 && interpTimerHackAllow) - coolalphatimer--; - } - } - - if (currentMenu == &OP_GameOptionsDef) - { - if (!(OP_GameTooltips[itemOn] == NULL)) - { - M_DrawSplitText(BASEVIDWIDTH / 2, BASEVIDHEIGHT-50, V_ALLOWLOWERCASE|V_SNAPTOBOTTOM, OP_GameTooltips[itemOn], coolalphatimer); - if (coolalphatimer > 0 && interpTimerHackAllow) - coolalphatimer--; - } - } - - if (currentMenu == &OP_ServerOptionsDef) - { - if (!(OP_ServerOptionsTooltips[itemOn] == NULL)) - { - M_DrawSplitText(BASEVIDWIDTH / 2, BASEVIDHEIGHT-50, V_ALLOWLOWERCASE|V_SNAPTOBOTTOM, OP_ServerOptionsTooltips[itemOn], coolalphatimer); - if (coolalphatimer > 0 && interpTimerHackAllow) - coolalphatimer--; - } - } - - if (currentMenu == &OP_AdvServerOptionsDef) - { - if (!(OP_AdvServerOptionsTooltips[itemOn] == NULL)) - { - M_DrawSplitText(BASEVIDWIDTH / 2, BASEVIDHEIGHT-50, V_ALLOWLOWERCASE|V_SNAPTOBOTTOM, OP_AdvServerOptionsTooltips[itemOn], coolalphatimer); - if (coolalphatimer > 0 && interpTimerHackAllow) - coolalphatimer--; - } - } - - if (currentMenu == &OP_PlayerDistortDef) - { - if (!(OP_PlayerDistortTooltips[itemOn] == NULL)) - { - M_DrawSplitText(BASEVIDWIDTH / 2, BASEVIDHEIGHT-50, V_ALLOWLOWERCASE|V_SNAPTOBOTTOM, OP_PlayerDistortTooltips[itemOn], coolalphatimer); - if (coolalphatimer > 0 && interpTimerHackAllow) - coolalphatimer--; - } - } - - if (currentMenu == &OP_SaturnCreditsDef) // C: - { - if (!(OP_CreditTooltips[itemOn] == NULL)) - { - M_DrawSplitText(BASEVIDWIDTH / 2, BASEVIDHEIGHT-50, V_ALLOWLOWERCASE|V_SNAPTOBOTTOM, OP_CreditTooltips[itemOn], coolalphatimer); - if (coolalphatimer > 0 && interpTimerHackAllow) - coolalphatimer--; - } - } - - if (currentMenu == &OP_BirdDef) - { - if (!(OP_BirdTooltips[itemOn] == NULL)) - { - M_DrawSplitText(BASEVIDWIDTH / 2, BASEVIDHEIGHT-50, V_ALLOWLOWERCASE|V_SNAPTOBOTTOM, OP_BirdTooltips[itemOn], coolalphatimer); - if (coolalphatimer > 0 && interpTimerHackAllow) - coolalphatimer--; - } - } - - if (currentMenu == &OP_TiltDef) - { - if (!(OP_TiltTooltips[itemOn] == NULL)) - { - M_DrawSplitText(BASEVIDWIDTH / 2, BASEVIDHEIGHT-50, V_ALLOWLOWERCASE|V_SNAPTOBOTTOM, OP_TiltTooltips[itemOn], coolalphatimer); - if (coolalphatimer > 0 && interpTimerHackAllow) - coolalphatimer--; - } - } - - if (currentMenu == &OP_AdvancedBirdDef) - { - if (!(OP_AdvancedBirdTooltips[itemOn] == NULL)) - { - M_DrawSplitText(BASEVIDWIDTH / 2, BASEVIDHEIGHT-50, V_ALLOWLOWERCASE|V_SNAPTOBOTTOM, OP_AdvancedBirdTooltips[itemOn], coolalphatimer); - if (coolalphatimer > 0 && interpTimerHackAllow) - coolalphatimer--; - } - } - - if (currentMenu == &OP_NametagDef) - { - if (!(OP_NametagTooltips[itemOn] == NULL)) - { - M_DrawSplitText(BASEVIDWIDTH / 2, BASEVIDHEIGHT-50, V_ALLOWLOWERCASE|V_SNAPTOBOTTOM, OP_NametagTooltips[itemOn], coolalphatimer); - if (coolalphatimer > 0 && interpTimerHackAllow) - coolalphatimer--; - } - } - - if (currentMenu == &OP_DriftGaugeDef) - { - if (!(OP_DriftGaugeTooltips[itemOn] == NULL)) - { - M_DrawSplitText(BASEVIDWIDTH / 2, BASEVIDHEIGHT-50, V_ALLOWLOWERCASE|V_SNAPTOBOTTOM, OP_DriftGaugeTooltips[itemOn], coolalphatimer); - if (coolalphatimer > 0 && interpTimerHackAllow) - coolalphatimer--; - } - } + // replaced with macro so it doesent look as terrible anymore lol + DoToolTips(OP_ControlsDef, OP_ControlsTooltips); + DoToolTips(OP_MouseOptionsDef, OP_MouseTooltips); + DoToolTips(OP_VideoOptionsDef, OP_VideoTooltips); + DoToolTips(OP_ExpOptionsDef, OP_ExpTooltips); + DoToolTips(OP_SoundOptionsDef, OP_SoundTooltips); + DoToolTips(OP_SoundAdvancedDef, OP_SoundAdvancedTooltips); + DoToolTips(OP_ChatOptionsDef, OP_ChatOptionsTooltips); + DoToolTips(OP_GameOptionsDef, OP_GameTooltips); + DoToolTips(OP_ServerOptionsDef, OP_ServerOptionsTooltips); + DoToolTips(OP_PlayerDistortDef, OP_PlayerDistortTooltips); + DoToolTips(OP_SaturnCreditsDef, OP_CreditTooltips); // C: + DoToolTips(OP_BirdDef, OP_BirdTooltips); + DoToolTips(OP_TiltDef, OP_TiltTooltips); + DoToolTips(OP_AdvancedBirdDef, OP_AdvancedBirdTooltips); + DoToolTips(OP_NametagDef, OP_NametagTooltips); + DoToolTips(OP_DriftGaugeDef, OP_DriftGaugeTooltips); + DoToolTips(OP_CamOptionsDef, OP_CamOptionsTooltips); + DoToolTips(OP_Player1CamOptionsDef || currentMenu == &OP_Player2CamOptionsDef || currentMenu == &OP_Player3CamOptionsDef || currentMenu == &OP_Player4CamOptionsDef, OP_PlayerCamOptionsTooltips); // god this one is still terrible lmao } static void M_DrawGenericBackgroundMenu(void) @@ -5271,128 +5366,19 @@ static void M_DrawGenericScrollMenu(void) V_DrawScaledPatch(currentMenu->x - 24, cursory, 0, W_CachePatchName("M_CURSOR", PU_CACHE)); -#ifdef HWRENDER // dumb hack // tooltips - if (currentMenu == &OP_OpenGLOptionsDef) - { - if (!(OP_OpenGLTooltips[itemOn] == NULL)) - { - M_DrawSplitText(BASEVIDWIDTH / 2, BASEVIDHEIGHT-50, V_ALLOWLOWERCASE|V_SNAPTOBOTTOM, OP_OpenGLTooltips[itemOn], coolalphatimer); - if (coolalphatimer > 0 && interpTimerHackAllow) - coolalphatimer--; - } - } + // same macro here +#ifdef HWRENDER + DoToolTips(OP_OpenGLOptionsDef, OP_OpenGLTooltips); #endif - - if (currentMenu == &OP_SaturnDef) - { - if (!(OP_SaturnTooltips[itemOn] == NULL)) - { - M_DrawSplitText(BASEVIDWIDTH / 2, BASEVIDHEIGHT-50, V_ALLOWLOWERCASE|V_SNAPTOBOTTOM, OP_SaturnTooltips[itemOn], coolalphatimer); - if (coolalphatimer > 0 && interpTimerHackAllow) - coolalphatimer--; - } - } + DoToolTips(OP_SaturnDef, OP_SaturnTooltips); + DoToolTips(OP_SaturnHudDef, OP_SaturnHudTooltips); + DoToolTips(OP_AdvServerOptionsDef, OP_AdvServerOptionsTooltips); } static void M_DrawPauseMenu(void) { -#if 0 - if (!netgame && !multiplayer && (gamestate == GS_LEVEL || gamestate == GS_INTERMISSION || gamestate == GS_VOTING)) - { - emblem_t *emblem_detail[3] = {NULL, NULL, NULL}; - char emblem_text[3][20]; - INT32 i; - - M_DrawTextBox(27, 16, 32, 6); - - // Draw any and all emblems at the top. - M_DrawMapEmblems(gamemap, 272, 28); - - if (strlen(mapheaderinfo[gamemap-1]->zonttl) > 0) - { - if (strlen(mapheaderinfo[gamemap-1]->actnum) > 0) - V_DrawString(40, 28, highlightflags, va("%s %s %s", mapheaderinfo[gamemap-1]->lvlttl, mapheaderinfo[gamemap-1]->zonttl, mapheaderinfo[gamemap-1]->actnum)); - else - V_DrawString(40, 28, highlightflags, va("%s %s", mapheaderinfo[gamemap-1]->lvlttl, mapheaderinfo[gamemap-1]->zonttl)); - } - else - { - if (strlen(mapheaderinfo[gamemap-1]->actnum) > 0) - V_DrawString(40, 28, highlightflags, va("%s %s", mapheaderinfo[gamemap-1]->lvlttl, mapheaderinfo[gamemap-1]->actnum)); - else - V_DrawString(40, 28, highlightflags, mapheaderinfo[gamemap-1]->lvlttl); - } - - // Set up the detail boxes. - { - emblem_t *emblem = M_GetLevelEmblems(gamemap); - while (emblem) - { - INT32 emblemslot; - char targettext[9], currenttext[9]; - - switch (emblem->type) - { - case ET_TIME: - emblemslot = emblem->var; // dumb hack - snprintf(targettext, 9, "%i:%02i.%02i", - G_TicsToMinutes((tic_t)emblemslot, false), - G_TicsToSeconds((tic_t)emblemslot), - G_TicsToCentiseconds((tic_t)emblemslot)); - - emblemslot = (INT32)G_GetBestTime(gamemap); // dumb hack pt ii - if ((tic_t)emblemslot == UINT32_MAX) - snprintf(currenttext, 9, "-:--.--"); - else - snprintf(currenttext, 9, "%i:%02i.%02i", - G_TicsToMinutes((tic_t)emblemslot, false), - G_TicsToSeconds((tic_t)emblemslot), - G_TicsToCentiseconds((tic_t)emblemslot)); - - targettext[8] = 0; - currenttext[8] = 0; - - emblemslot = 1; - break; - default: - goto bademblem; - } - if (emblem_detail[emblemslot]) - goto bademblem; - - emblem_detail[emblemslot] = emblem; - snprintf(emblem_text[emblemslot], 20, "%8s /%8s", currenttext, targettext); - emblem_text[emblemslot][19] = 0; - - bademblem: - emblem = M_GetLevelEmblems(-1); - } - } - for (i = 0; i < 3; ++i) - { - emblem_t *emblem = emblem_detail[i]; - if (!emblem) - continue; - - if (emblem->collected) - V_DrawSmallMappedPatch(40, 44 + (i*8), 0, W_CachePatchName(M_GetEmblemPatch(emblem), PU_CACHE), - R_GetTranslationColormap(TC_DEFAULT, M_GetEmblemColor(emblem), GTC_MENUCACHE)); - else - V_DrawSmallScaledPatch(40, 44 + (i*8), 0, W_CachePatchName("NEEDIT", PU_CACHE)); - - switch (emblem->type) - { - case ET_TIME: - V_DrawString(56, 44 + (i*8), highlightflags, "TIME:"); - break; - } - V_DrawRightAlignedString(284, 44 + (i*8), V_MONOSPACE, emblem_text[i]); - } - } -#endif - #ifdef HAVE_DISCORDRPC // kind of hackily baked in here if (currentMenu == &MPauseDef && discordRequestList != NULL) @@ -6577,8 +6563,9 @@ static void M_HandleAddons(INT32 choice) case EXT_KART: #endif case EXT_PK3: - if (browselocalskins) { - if (DumbStartsWith("KC_", dirmenu[dir_on[menudepthleft]]+DIR_STRING) || DumbStartsWith("kc_", dirmenu[dir_on[menudepthleft]]+DIR_STRING)) { + if (browselocalskins) + { + if (DumbStartsWith("KC_", dirmenu[dir_on[menudepthleft]]+DIR_STRING) || DumbStartsWith("kc_", dirmenu[dir_on[menudepthleft]]+DIR_STRING)) { M_StartMessage(va("%c%s\x80\nYou are loading a local skin.\nLocal skins will not be usable\nafter going back from\nthe title screen.\n\n(Press a key)\n", ('\x80' + (highlightflags>>V_CHARCOLORSHIFT)), dirmenu[dir_on[menudepthleft]]+DIR_STRING),NULL,MM_NOTHING); COM_BufAddText(va("addskins \"%s%s\"", menupath, dirmenu[dir_on[menudepthleft]]+DIR_STRING)); errorshitspam = 0; // reset it so it can show the warning screen again lmao @@ -6670,42 +6657,196 @@ static void M_HandleAddons(INT32 choice) } // ---- REPLAY HUT ----- -menudemo_t *demolist; +menudemo_t *demolist; // Replays that that have been checked to match with query + +// Locked behind Lock_search_state +menudemo_t *demolist_all; // All replays +boolean replaynamesloaded = false; + +#ifdef HAVE_THREADS +I_mutex replayquerymutex; + +// g_in_exiting_signal_handler is an evil hack +// to avoid infinite SIGABRT recursion in the signal handler +// due to poisoned locks or mach-o kernel not supporting locks in signals +// or something like that. idk +# define Lock_search_state() if (!g_in_exiting_signal_handler) { I_lock_mutex(&replayquerymutex); } +# define Unlock_search_state() if (!g_in_exiting_signal_handler) { I_unlock_mutex(replayquerymutex); } +#else/*HAVE_THREADS*/ +# define Lock_search_state() +# define Unlock_search_state() +#endif/*HAVE_THREADS*/ + + +#define MAXREPLAYQUERY 40 +char replayqueryinput[MAXREPLAYQUERY+1]; // The input typed +size_t replayquerypos = 0; // Position in input window + +size_t replayqueryfound = 0; // Number of checked replay entries +size_t replayquerycheck = 0; // Index of next replay entry to check in demolist_all #define DF_ENCORE 0x40 static INT16 replayScrollTitle = 0; static SINT8 replayScrollDelay = TICRATE, replayScrollDir = 1; -static void PrepReplayList(void) +static void ReplayNamesLoadThread(void* userdata) +{ + Lock_search_state(); + + size_t demolist_all_size = sizedirmenu; + menudemo_t *demolist_all_local = (menudemo_t*)malloc(sizeof(menudemo_t)*sizedirmenu); + memcpy(demolist_all_local, demolist_all, sizeof(menudemo_t)*sizedirmenu); + char *replaydirpath = (char*)userdata; + + Unlock_search_state(); + + for (size_t i = 0; i < demolist_all_size; ++i) + { + if (demolist_all_local[i].type != MD_SUBDIR) + G_LoadDemoTitle(&demolist_all_local[i]); + } + + Lock_search_state(); + + if (strcmp(menupath, replaydirpath) == 0) + { + memcpy(demolist_all, demolist_all_local, sizeof(menudemo_t)*sizedirmenu); + replaynamesloaded = true; + } + + Unlock_search_state(); + + // Was allocated before thread start, we need to free it + free(replaydirpath); + free(demolist_all_local); +} + +static void LoadReplayNames(void) +{ + char *replaydirpath = strdup(menupath); + + Lock_search_state(); + replaynamesloaded = false; + Unlock_search_state(); + +#ifdef HAVE_THREADS + I_spawn_thread("replay-names-load", ReplayNamesLoadThread, replaydirpath); +#else + ReplayNamesLoadThread(replaydirpath); +#endif +} + +static void ResetReplayQuery(void) +{ + memset(replayqueryinput, 0, MAXREPLAYQUERY); + replayquerypos = 0; + + replayqueryfound = 0; + replayquerycheck = 0; +} + +static void AddCheckedReplay(void) +{ + memcpy(&demolist[replayqueryfound], &demolist_all[replayquerycheck], sizeof(menudemo_t)); + ++replayqueryfound; + ++replayquerycheck; +} + +// Check up to maxnum replays if they match with query +static void M_HutCheckReplays(size_t maxnum) +{ + if (!replaynamesloaded) + return; + + // Already checked everything + if (replayquerycheck == sizedirmenu) + return; + + // If we don't have any query, just copy all demos and consider them checked + if (replayquerypos == 0) + { + // Mark as done + replayqueryfound = replayquerycheck = sizedirmenu; + + memcpy(demolist, demolist_all, sizeof(menudemo_t) * sizedirmenu); + + return; + } + + while (maxnum-- && replayquerycheck < sizedirmenu) + { + switch (demolist_all[replayquerycheck].type) + { + case MD_SUBDIR: + AddCheckedReplay(); // Just add subdirs + // Will also be decremented on next iteration. Basically, we just don't want to + // spend our number of tries on subdirs, since we don't check anything for them + ++maxnum; + break; + + case MD_NOTLOADED: + case MD_OUTDATED: + case MD_LOADED: + if (demolist_all[replayquerycheck].title[0] && strcasestr(demolist_all[replayquerycheck].title, replayqueryinput) != NULL) + AddCheckedReplay(); // It matches, add it! + else + replayquerycheck++; // Doesn't match, moving on... + + break; + + // Don't show invalid replays + case MD_INVALID: + replayquerycheck++; + } + } +} + +static void PrepReplayList(boolean reset) { size_t i; + replayquerycheck = replayqueryfound = 0; + if (demolist) Z_Free(demolist); demolist = Z_Calloc(sizeof(menudemo_t) * sizedirmenu, PU_STATIC, NULL); + // If directory didn't change, keep demolist_all + if (!reset) return; + + Lock_search_state(); + + if (demolist_all) + Z_Free(demolist_all); + + demolist_all = Z_Calloc(sizeof(menudemo_t) * sizedirmenu, PU_STATIC, NULL); + for (i = 0; i < sizedirmenu; i++) { if (dirmenu[i][DIR_TYPE] == EXT_UP) { - demolist[i].type = MD_SUBDIR; - sprintf(demolist[i].title, "UP"); + demolist_all[i].type = MD_SUBDIR; + sprintf(demolist_all[i].title, "UP"); } else if (dirmenu[i][DIR_TYPE] == EXT_FOLDER) { - demolist[i].type = MD_SUBDIR; - strncpy(demolist[i].title, dirmenu[i] + DIR_STRING, 64); + demolist_all[i].type = MD_SUBDIR; + strncpy(demolist_all[i].title, dirmenu[i] + DIR_STRING, 64); } else { - demolist[i].type = MD_NOTLOADED; + demolist_all[i].type = MD_NOTLOADED; // FIXME - do something with buffer sizes. menupath is 1024 chars but filepath is only // 256. I'm not really sure what to do here but don't want to leave warnings... - snprintf(demolist[i].filepath, 255, "%.254s%s", menupath, dirmenu[i] + DIR_STRING); - sprintf(demolist[i].title, "....."); + snprintf(demolist_all[i].filepath, 255, "%.254s%s", menupath, dirmenu[i] + DIR_STRING); + sprintf(demolist_all[i].title, "....."); } } + + Unlock_search_state(); + + LoadReplayNames(); } void M_ReplayHut(INT32 choice) @@ -6717,6 +6858,9 @@ void M_ReplayHut(INT32 choice) snprintf(menupath, 1024, "%s"PATHSEP"replay"PATHSEP"online"PATHSEP, srb2home); menupathindex[(menudepthleft = menudepth-1)] = strlen(menupath); } + + ResetReplayQuery(); + if (!preparefilemenu(false, true)) { M_StartMessage("No replays found.\n\n(Press a key)\n", NULL, MM_NOTHING); @@ -6728,7 +6872,7 @@ void M_ReplayHut(INT32 choice) replayScrollTitle = 0; replayScrollDelay = TICRATE; replayScrollDir = 1; - PrepReplayList(); + PrepReplayList(true); menuactive = true; M_SetupNextMenu(&MISC_ReplayHutDef); @@ -6740,11 +6884,59 @@ void M_ReplayHut(INT32 choice) S_ChangeMusicInternal("replst", true); } -static void M_HandleReplayHutList(INT32 choice) +static boolean M_HandleReplayHutQuery(INT32 choice) { + switch (choice) + { + case KEY_BACKSPACE: + if (replayquerypos == 0) + break; + + S_StartSound(NULL,sfx_menu1); + + replayquerypos--; + replayqueryinput[replayquerypos] = 0; + + preparefilemenu(false, true); + dir_on[menudepthleft] = 0; + PrepReplayList(false); + + return true; + + default: + if (choice < 32 || choice > 127) + break; + + if (replayquerypos < MAXREPLAYQUERY) + { + S_StartSound(NULL,sfx_menu1); + + replayqueryinput[replayquerypos] = choice; + replayqueryinput[replayquerypos+1] = 0; + ++replayquerypos; + + preparefilemenu(false, true); + dir_on[menudepthleft] = 0; + PrepReplayList(false); + } + + return true; + } + + return false; +} + +static void M_HandleReplayHutList(INT32 choice) +{ + if (M_HandleReplayHutQuery(choice)) + return; + switch (choice) { case KEY_UPARROW: + if (!replaynamesloaded) + return; + if (dir_on[menudepthleft]) dir_on[menudepthleft]--; else @@ -6756,7 +6948,10 @@ static void M_HandleReplayHutList(INT32 choice) break; case KEY_DOWNARROW: - if (dir_on[menudepthleft] < sizedirmenu-1) + if (!replaynamesloaded) + return; + + if (dir_on[menudepthleft] < replayqueryfound-1) dir_on[menudepthleft]++; else return; @@ -6771,6 +6966,9 @@ static void M_HandleReplayHutList(INT32 choice) break; case KEY_ENTER: + if (!replaynamesloaded) + return; + switch (dirmenu[dir_on[menudepthleft]][DIR_TYPE]) { case EXT_FOLDER: @@ -6796,7 +6994,8 @@ static void M_HandleReplayHutList(INT32 choice) { S_StartSound(NULL, sfx_menu1); dir_on[menudepthleft] = 1; - PrepReplayList(); + ResetReplayQuery(); + PrepReplayList(true); } } else @@ -6814,7 +7013,7 @@ static void M_HandleReplayHutList(INT32 choice) M_QuitReplayHut(); return; } - PrepReplayList(); + PrepReplayList(true); break; default: // We can't just use M_SetupNextMenu because that'll run ReplayDef's quitroutine and boot us back to the title screen! @@ -7015,7 +7214,7 @@ static void M_DrawReplayHut(void) if (itemOn > replaylistitem) { itemOn = replaylistitem; - dir_on[menudepthleft] = sizedirmenu-1; + dir_on[menudepthleft] = replayqueryfound-1; replayScrollTitle = 0; replayScrollDelay = TICRATE; replayScrollDir = 1; } else if (itemOn < replaylistitem) @@ -7029,7 +7228,7 @@ static void M_DrawReplayHut(void) INT32 maxy; // Scroll menu items if needed cursory = y + currentMenu->menuitems[replaylistitem].alphaKey + dir_on[menudepthleft]*10; - maxy = y + currentMenu->menuitems[replaylistitem].alphaKey + sizedirmenu*10; + maxy = y + currentMenu->menuitems[replaylistitem].alphaKey + replayqueryfound*10; if (cursory > maxy - 20) cursory = maxy - 20; @@ -7063,14 +7262,20 @@ static void M_DrawReplayHut(void) y += currentMenu->menuitems[replaylistitem].alphaKey; - for (i = 0; i < (INT16)sizedirmenu; i++) + if (!replaynamesloaded) + { + const char *msg = "Loading replays, please wait..."; + V_DrawCenteredString(160, 100, V_ALLOWLOWERCASE, msg); + } + + for (i = 0; i < (INT16)replayqueryfound; i++) { INT32 localy = y+i*10; INT32 localx = x; if (localy < 65) continue; - if (localy >= SCALEDVIEWHEIGHT) + if (localy >= SCALEDVIEWHEIGHT - 24) break; if (demolist[i].type == MD_NOTLOADED && !processed_one_this_frame) @@ -7121,7 +7326,7 @@ static void M_DrawReplayHut(void) } // Draw scrollbar - y = sizedirmenu*10 + currentMenu->menuitems[replaylistitem].alphaKey + 30; + y = replayqueryfound*10 + currentMenu->menuitems[replaylistitem].alphaKey + 30; if (y > SCALEDVIEWHEIGHT-80) { V_DrawFill(BASEVIDWIDTH-4, 75, 4, SCALEDVIEWHEIGHT-80, V_SNAPTOTOP|V_SNAPTORIGHT|239); @@ -7140,6 +7345,23 @@ static void M_DrawReplayHut(void) { DrawReplayHutReplayInfo(); } + + x -= 40; + + // Draw search query + M_DrawTextBoxFlags(x, 200 - 22, MAXREPLAYQUERY, 1, V_SNAPTOBOTTOM); + + if (replayquerypos) + V_DrawString(x + 8, 200 - 14, V_ALLOWLOWERCASE|V_SNAPTOBOTTOM, replayqueryinput); + else + V_DrawString(x + 8, 200 - 14, V_ALLOWLOWERCASE|V_SNAPTOBOTTOM, "\x86Type to search..."); + + // draw text cursor for name + if (replayquerypos && skullAnimCounter < 4) // blink cursor + V_DrawCharacter(x + 8 + V_StringWidth(replayqueryinput, V_ALLOWLOWERCASE), 200 - 14, '_'|V_SNAPTOBOTTOM, false); + + if (replaynamesloaded && replayquerycheck < sizedirmenu) + V_DrawString(x + 8, 200 - 30, V_ALLOWLOWERCASE|V_SNAPTOBOTTOM, va("Searching %u/%u...", (unsigned)replayquerycheck, (unsigned)sizedirmenu)); } static void M_DrawReplayStartMenu(void) @@ -7679,11 +7901,11 @@ static void M_Options(INT32 choice) (void)choice; // if the player is not admin or server, disable gameplay & server options - OP_MainMenu[4].status = OP_MainMenu[5].status = (Playing() && !(server || IsPlayerAdmin(consoleplayer))) ? (IT_GRAYEDOUT) : (IT_STRING|IT_SUBMENU); + OP_MainMenu[5].status = OP_MainMenu[6].status = (Playing() && !(server || IsPlayerAdmin(consoleplayer))) ? (IT_GRAYEDOUT) : (IT_STRING|IT_SUBMENU); - OP_MainMenu[9].status = (Playing()) ? (IT_GRAYEDOUT) : (IT_STRING|IT_CALL); // Play credits + OP_MainMenu[10].status = (Playing()) ? (IT_GRAYEDOUT) : (IT_STRING|IT_CALL); // Play credits - OP_MainMenu[12].status = (!cv_showlocalskinmenus.value) ? (IT_DISABLED) : (IT_CALL|IT_STRING); + OP_MainMenu[13].status = (!cv_showlocalskinmenus.value) ? (IT_DISABLED) : (IT_CALL|IT_STRING); #ifdef HAVE_DISCORDRPC OP_DataOptionsMenu[4].status = (Playing()) ? (IT_GRAYEDOUT) : (IT_STRING|IT_SUBMENU); // Erase data @@ -7849,31 +8071,6 @@ static void M_DestroyRobots(INT32 choice) M_StartMessage(M_GetText("Do you want to destroy all\nrobots in the current level?\n\n(Press 'Y' to confirm)\n"),M_DestroyRobotsResponse,MM_YESNO); } -/*static void M_LevelSelectWarp(INT32 choice) -{ - boolean fromloadgame = (currentMenu == &SP_LevelSelectDef); - - (void)choice; - - if (W_CheckNumForName(G_BuildMapName(cv_nextmap.value)) == LUMPERROR) - { -// CONS_Alert(CONS_WARNING, "Internal game map '%s' not found\n", G_BuildMapName(cv_nextmap.value)); - return; - } - - startmap = (INT16)(cv_nextmap.value); - - fromlevelselect = true; - - if (fromloadgame) - G_LoadGame((UINT32)cursaveslot, startmap); - else - { - cursaveslot = -1; - M_SetupChoosePlayer(0); - } -}*/ - // ======== // SKY ROOM // ======== @@ -8169,11 +8366,52 @@ static void M_HandleSoundTest(INT32 choice) static musicdef_t *curplaying = NULL; static INT32 st_sel = 0; -static tic_t st_time = 0; -static size_t st_namescroll = 0; -static size_t st_namescrollstate = 0; -//static patch_t* st_radio[9]; -//static patch_t* st_launchpad[4]; +static tic_t st_musictime = 0; + +static void scrollMusicName(const char name[], size_t len, size_t maxlen, char result[]) +{ + // How much should we scroll. Not sure why +1 is needed, but without it this function skips 2 + // characters at once sometimes + const size_t amount = len - maxlen + 1; + + // Note: anything above 17 will cause zero division + const size_t MAXSPEED = 6; + const size_t t = st_musictime / (35/min(amount, MAXSPEED)); + + const size_t state = (t / amount) % 4; + + switch (state) + { + // Show beginning of the name + case 0: + memcpy(result, name, maxlen-1); + break; + + // Scroll towards end of the name + case 1: + { + const size_t advance = t % amount; + memcpy(result, name+advance, maxlen-1); + } + break; + + // Show end of the name + case 2: + memcpy(result, name+len+1-maxlen, maxlen-1); + break; + + // Scroll towards start of the name + case 3: + { + const size_t advance = t % amount; + memcpy(result, name+len+1-maxlen-advance, maxlen-1); + } + break; + } + + // Technically not necessary, since it gets set again after function call, but just in case + result[maxlen] = 0; +} static void M_MusicTest(INT32 choice) { @@ -8186,7 +8424,6 @@ static void M_MusicTest(INT32 choice) } curplaying = NULL; - st_time = 0; st_sel = 0; @@ -8197,30 +8434,17 @@ static void M_DrawMusicTest(void) { INT32 x, y, i; - // let's handle the ticker first. ideally we'd tick this somewhere else, BUT... - if (curplaying) - { - { - fixed_t work; - work = st_time; - - if (st_time >= (FRACUNIT << (FRACBITS - 2))) // prevent overflow jump - takes about 15 minutes of loop on the same song to reach - st_time = work; - - st_time += renderdeltatics; - } - } - x = 90<usage[0]) V_DrawString(vid.dupx, vid.height - 10*vid.dupy, V_NOSCALESTART|V_ALLOWLOWERCASE, va("%.6s", curplaying->name)); - else { + else V_DrawSmallString(vid.dupx, vid.height - 5*vid.dupy, V_NOSCALESTART|V_ALLOWLOWERCASE, va("%.6s - %.255s\n", curplaying->name, curplaying->usage)); - } if (cv_showmusicfilename.value) V_DrawSmallString(0, 0, V_SNAPTOTOP|V_SNAPTOLEFT|V_ALLOWLOWERCASE, curplaying->filename); @@ -8314,7 +8537,7 @@ static void M_DrawMusicTest(void) x = 24; y = 64; - if (renderisnewtic) ++st_namescroll; + if (renderisnewtic) st_musictime++; while (t <= b) { @@ -8323,76 +8546,16 @@ static void M_DrawMusicTest(void) { const size_t MAXLENGTH = 34; - const tic_t SCROLLSPEED = TICRATE/5; // Number of tics for name being scrolled by 1 letter - size_t nameoffset = 0; - size_t namelength = strlen(soundtestdefs[t]->source); - if (soundtestdefs[t]->title[0]) - namelength = strlen(soundtestdefs[t]->title); + const char *songname = soundtestdefs[t]->title[0] ? soundtestdefs[t]->title : soundtestdefs[t]->source; + + size_t namelength = strlen(songname); char buf[MAXLENGTH+1]; if (t == st_sel && namelength > MAXLENGTH) - { - switch (st_namescrollstate) - { - case 0: - { - // Scroll forward - nameoffset = (st_namescroll/SCROLLSPEED) % (namelength - MAXLENGTH + 1); - - if (nameoffset == namelength - MAXLENGTH) - { - st_namescroll = 0; - st_namescrollstate++; - } - } - break; - - case 1: - { - nameoffset = namelength - MAXLENGTH; - - // Show name end for 1 second, then start scrolling back - if (st_namescroll == TICRATE) - { - st_namescroll = 0; - st_namescrollstate++; - } - } - break; - - case 2: - { - // Scroll back - nameoffset = (namelength - MAXLENGTH - 1) - (st_namescroll/SCROLLSPEED) % (namelength - MAXLENGTH); - - if (nameoffset == 0) - { - st_namescroll = 0; - st_namescrollstate++; - } - } - break; - - case 3: - { - nameoffset = 0; - - // Show name beginning for 1 second, then start scrolling forward again - if (st_namescroll == TICRATE) - { - st_namescroll = 0; - st_namescrollstate = 0; - } - } - break; - } - } - - if (soundtestdefs[t]->title[0]) - memcpy(buf, soundtestdefs[t]->title + nameoffset, MAXLENGTH); + scrollMusicName(songname, namelength, MAXLENGTH, buf); else - memcpy(buf, soundtestdefs[t]->source + nameoffset, MAXLENGTH); + strncpy(buf, songname, MAXLENGTH); buf[MAXLENGTH] = 0; V_DrawString(x, y, (t == st_sel ? V_YELLOWMAP : 0)|V_ALLOWLOWERCASE|V_MONOSPACE, buf); @@ -8419,8 +8582,7 @@ static void M_HandleMusicTest(INT32 choice) { S_StartSound(NULL, sfx_menu1); } - st_namescroll = 0; - st_namescrollstate = 0; + st_musictime = 0; break; case KEY_UPARROW: if (!st_sel--) @@ -8428,8 +8590,7 @@ static void M_HandleMusicTest(INT32 choice) { S_StartSound(NULL, sfx_menu1); } - st_namescroll = 0; - st_namescrollstate = 0; + st_musictime = 0; break; case KEY_PGDN: if (st_sel < numsoundtestdefs-1) @@ -8439,8 +8600,7 @@ static void M_HandleMusicTest(INT32 choice) st_sel = numsoundtestdefs-1; S_StartSound(NULL, sfx_menu1); } - st_namescroll = 0; - st_namescrollstate = 0; + st_musictime = 0; break; case KEY_PGUP: if (st_sel) @@ -8450,8 +8610,7 @@ static void M_HandleMusicTest(INT32 choice) st_sel = 0; S_StartSound(NULL, sfx_menu1); } - st_namescroll = 0; - st_namescrollstate = 0; + st_musictime = 0; break; case KEY_BACKSPACE: if (curplaying) @@ -8459,14 +8618,12 @@ static void M_HandleMusicTest(INT32 choice) S_StopSounds(); S_StopMusic(); curplaying = NULL; - st_time = 0; S_StartSound(NULL, sfx_skid); } break; case KEY_ESCAPE: exitmenu = true; - st_namescroll = 0; - st_namescrollstate = 0; + st_musictime = 0; break; case KEY_RIGHTARROW: @@ -8474,7 +8631,6 @@ static void M_HandleMusicTest(INT32 choice) case KEY_ENTER: S_StopSounds(); S_StopMusic(); - st_time = 0; curplaying = soundtestdefs[st_sel]; S_ChangeMusicInternal(curplaying->name, true); break; @@ -8846,51 +9002,6 @@ void M_DrawTimeAttackMenu(void) V_DrawRightAlignedString(292, 80, highlightflags, "BEST TIME:"); K_drawKartTimestamp(time, 162, 86, cv_nextmap.value, 1); } - /*{ - char beststr[40]; - emblem_t *em; - - if (!mainrecords[cv_nextmap.value-1] || !mainrecords[cv_nextmap.value-1]->time) - sprintf(beststr, "(none)"); - else - sprintf(beststr, "%i:%02i.%02i", G_TicsToMinutes(mainrecords[cv_nextmap.value-1]->time, true), - G_TicsToSeconds(mainrecords[cv_nextmap.value-1]->time), - G_TicsToCentiseconds(mainrecords[cv_nextmap.value-1]->time)); - - V_DrawString(64, y+48, highlightflags, "BEST TIME:"); - V_DrawRightAlignedString(BASEVIDWIDTH - 64 - 24 - 8, y+48, V_ALLOWLOWERCASE, beststr); - - if (!mainrecords[cv_nextmap.value-1] || !mainrecords[cv_nextmap.value-1]->lap) - sprintf(beststr, "(none)"); - else - sprintf(beststr, "%i:%02i.%02i", G_TicsToMinutes(mainrecords[cv_nextmap.value-1]->lap, true), - G_TicsToSeconds(mainrecords[cv_nextmap.value-1]->lap), - G_TicsToCentiseconds(mainrecords[cv_nextmap.value-1]->lap)); - - V_DrawString(64, y+56, highlightflags, "BEST LAP:"); - V_DrawRightAlignedString(BASEVIDWIDTH - 64 - 24 - 8, y+56, V_ALLOWLOWERCASE, beststr); - - // Draw record emblems. - em = M_GetLevelEmblems(cv_nextmap.value); - while (em) - { - switch (em->type) - { - case ET_TIME: break; - default: - goto skipThisOne; - } - - if (em->collected) - V_DrawMappedPatch(BASEVIDWIDTH - 64 - 24, y+48, 0, W_CachePatchName(M_GetEmblemPatch(em), PU_CACHE), - R_GetTranslationColormap(TC_DEFAULT, M_GetEmblemColor(em), GTC_MENUCACHE)); - else - V_DrawScaledPatch(BASEVIDWIDTH - 64 - 24, y+48, 0, W_CachePatchName("NEEDIT", PU_CACHE)); - - skipThisOne: - em = M_GetLevelEmblems(-1); - } - }*/ // ALWAYS DRAW player name, level name, skin and color even when not on this menu! if (currentMenu != &SP_TimeAttackDef) @@ -9900,6 +10011,17 @@ static void M_DrawLevelSelectOnly(boolean leftfade, boolean rightfade) patch_t *PictureOfLevel; INT32 x, y, w, i, oldval, trans, dupadjust = ((vid.width/vid.dupx) - BASEVIDWIDTH)>>1; + char encoretoggle[32] = {0}; + const char *item1 = gamecontrol[gc_fire][0] != 0 ? G_KeynumToString(gamecontrol[gc_fire][0]) : NULL; + const char *item2 = gamecontrol[gc_fire][1] != 0 ? G_KeynumToString(gamecontrol[gc_fire][1]) : NULL; + + if (item1 != NULL && item2 != NULL) + snprintf(encoretoggle, 32, "%s/%s: Toggle Encore", item1, item2); + else + snprintf(encoretoggle, 32, "%s: Toggle Encore", item1 != NULL ? item1 : item2 != NULL ? item2 : "Item"); + + V_DrawThinString(1, BASEVIDHEIGHT-8-1, V_SNAPTOLEFT|V_SNAPTOBOTTOM|V_TRANSLUCENT|V_ALLOWLOWERCASE, encoretoggle); + // A 160x100 image of the level as entry MAPxxP if (cv_nextmap.value) { @@ -9956,8 +10078,6 @@ static void M_DrawLevelSelectOnly(boolean leftfade, boolean rightfade) rubyfloattime += FixedMul(ANGLE_MAX/NEWTICRATE, renderdeltatics); } } - /*V_DrawDiag(x, y, 12, 31); - V_DrawDiag(x, y, 10, G_GetGametypeColor(cv_newgametype.value));*/ y += i/4; i = cv_nextmap.value - 1; @@ -10042,7 +10162,7 @@ static void M_DrawServerMenu(void) { M_DrawLevelSelectOnly(false, false); - #ifdef MASTERSERVER +#ifdef MASTERSERVER if (currentMenu == &MP_ServerDef && cv_advertise.value) // Remind players where they're hosting. { int mservflags = V_ALLOWLOWERCASE; @@ -10052,7 +10172,7 @@ static void M_DrawServerMenu(void) mservflags = mservflags|warningflags; V_DrawCenteredThinString(BASEVIDWIDTH/2, BASEVIDHEIGHT-12, mservflags, va("Master Server: %s", cv_masterserver.string)); } - #endif +#endif M_DrawGenericMenu(); } @@ -10085,6 +10205,9 @@ static void M_StartServerMenu(INT32 choice) levellistmode = LLM_CREATESERVER; M_PrepareLevelSelect(); M_SetupNextMenu(&MP_ServerDef); +#ifdef MASTERSERVER + Get_rules(); +#endif M_PopupMasterServerRules(); } @@ -10418,6 +10541,8 @@ static UINT8 setupm_skinypos; static INT32 setupm_skinselect; static boolean setupm_skinlockedselect; +static UINT8 setupm_playernum; //brap + #define SELECTEDSTATSCOUNT skinstatscount[setupm_skinxpos][setupm_skinypos] #define LASTSELECTEDSTAT skinstats[setupm_skinxpos][setupm_skinypos][skinstatscount[setupm_skinxpos][setupm_skinypos]] @@ -11259,6 +11384,7 @@ static void M_HandleSetupMultiPlayer(INT32 choice) { S_StartSound(NULL,sfx_menu1); // Tails setupm_fakecolor--; + G_SetPlayerGamepadIndicatorColor(setupm_playernum, setupm_fakecolor); } break; @@ -11314,6 +11440,7 @@ static void M_HandleSetupMultiPlayer(INT32 choice) { S_StartSound(NULL,sfx_menu1); // Tails setupm_fakecolor++; + G_SetPlayerGamepadIndicatorColor(setupm_playernum, setupm_fakecolor); } break; @@ -11353,6 +11480,7 @@ static void M_HandleSetupMultiPlayer(INT32 choice) { S_StartSound(NULL,sfx_menu1); // Tails setupm_fakecolor = col; + G_SetPlayerGamepadIndicatorColor(setupm_playernum, setupm_fakecolor); } } break; @@ -11486,6 +11614,8 @@ static void M_SetupMultiPlayer(INT32 choice) setupm_skinypos = 0; setupm_skinlockedselect = false; + setupm_playernum = 0; + // For whatever reason this doesn't work right if you just use ->value setupm_fakeskin = R_SkinAvailable(setupm_cvskin->string); if (setupm_fakeskin == -1) @@ -11525,6 +11655,8 @@ static void M_SetupMultiPlayer2(INT32 choice) setupm_skinypos = 0; setupm_skinlockedselect = false; + setupm_playernum = 1; + // For whatever reason this doesn't work right if you just use ->value setupm_fakeskin = R_SkinAvailable(setupm_cvskin->string); if (setupm_fakeskin == -1) @@ -11564,6 +11696,8 @@ static void M_SetupMultiPlayer3(INT32 choice) setupm_skinypos = 0; setupm_skinlockedselect = false; + setupm_playernum = 2; + // For whatever reason this doesn't work right if you just use ->value setupm_fakeskin = R_SkinAvailable(setupm_cvskin->string); if (setupm_fakeskin == -1) @@ -11603,6 +11737,8 @@ static void M_SetupMultiPlayer4(INT32 choice) setupm_skinypos = 0; setupm_skinlockedselect = false; + setupm_playernum = 3; + // For whatever reason this doesn't work right if you just use ->value setupm_fakeskin = R_SkinAvailable(setupm_cvskin->string); if (setupm_fakeskin == -1) @@ -11641,6 +11777,7 @@ static boolean M_QuitMultiPlayerMenu(void) // you know what? always putting these in the buffer won't hurt anything. COM_BufAddText (va("%s \"%s\"\n",setupm_cvskin->name,skins[setupm_fakeskin].name)); COM_BufAddText (va("%s %d\n",setupm_cvcolor->name,setupm_fakecolor)); + return true; } @@ -11981,22 +12118,13 @@ static void M_Setup1PControlsMenu(INT32 choice) // Unhide P1-only controls OP_AllControlsMenu[15].status = IT_CONTROL; // Chat - //OP_AllControlsMenu[16].status = IT_CONTROL; // Team-chat OP_AllControlsMenu[16].status = IT_CONTROL; // Rankings - //OP_AllControlsMenu[17].status = IT_CONTROL; // Viewpoint // 18 is Reset Camera, 19 is Toggle Chasecam OP_AllControlsMenu[20].status = IT_CONTROL; // Pause OP_AllControlsMenu[21].status = IT_CONTROL; // Screenshot OP_AllControlsMenu[22].status = IT_CONTROL; // GIF OP_AllControlsMenu[23].status = IT_CONTROL; // System Menu OP_AllControlsMenu[24].status = IT_CONTROL; // Console - /*OP_AllControlsMenu[25].status = IT_HEADER; // Spectator Controls header - OP_AllControlsMenu[26].status = IT_SPACE; // Spectator Controls space - OP_AllControlsMenu[27].status = IT_CONTROL; // Spectate - OP_AllControlsMenu[28].status = IT_CONTROL; // Look Up - OP_AllControlsMenu[29].status = IT_CONTROL; // Look Down - OP_AllControlsMenu[30].status = IT_CONTROL; // Center View - */ M_SetupNextMenu(&OP_AllControlsDef); } @@ -12013,22 +12141,13 @@ static void M_Setup2PControlsMenu(INT32 choice) // Hide P1-only controls OP_AllControlsMenu[15].status = IT_GRAYEDOUT2; // Chat - //OP_AllControlsMenu[16].status = IT_GRAYEDOUT2; // Team-chat OP_AllControlsMenu[16].status = IT_GRAYEDOUT2; // Rankings - //OP_AllControlsMenu[17].status = IT_GRAYEDOUT2; // Viewpoint // 18 is Reset Camera, 19 is Toggle Chasecam OP_AllControlsMenu[20].status = IT_GRAYEDOUT2; // Pause OP_AllControlsMenu[21].status = IT_GRAYEDOUT2; // Screenshot OP_AllControlsMenu[22].status = IT_GRAYEDOUT2; // GIF OP_AllControlsMenu[23].status = IT_GRAYEDOUT2; // System Menu OP_AllControlsMenu[24].status = IT_GRAYEDOUT2; // Console - /*OP_AllControlsMenu[25].status = IT_GRAYEDOUT2; // Spectator Controls header - OP_AllControlsMenu[26].status = IT_GRAYEDOUT2; // Spectator Controls space - OP_AllControlsMenu[27].status = IT_GRAYEDOUT2; // Spectate - OP_AllControlsMenu[28].status = IT_GRAYEDOUT2; // Look Up - OP_AllControlsMenu[29].status = IT_GRAYEDOUT2; // Look Down - OP_AllControlsMenu[30].status = IT_GRAYEDOUT2; // Center View - */ M_SetupNextMenu(&OP_AllControlsDef); } @@ -12045,22 +12164,13 @@ static void M_Setup3PControlsMenu(INT32 choice) // Hide P1-only controls OP_AllControlsMenu[15].status = IT_GRAYEDOUT2; // Chat - //OP_AllControlsMenu[16].status = IT_GRAYEDOUT2; // Team-chat OP_AllControlsMenu[16].status = IT_GRAYEDOUT2; // Rankings - //OP_AllControlsMenu[17].status = IT_GRAYEDOUT2; // Viewpoint // 18 is Reset Camera, 19 is Toggle Chasecam OP_AllControlsMenu[20].status = IT_GRAYEDOUT2; // Pause OP_AllControlsMenu[21].status = IT_GRAYEDOUT2; // Screenshot OP_AllControlsMenu[22].status = IT_GRAYEDOUT2; // GIF OP_AllControlsMenu[23].status = IT_GRAYEDOUT2; // System Menu OP_AllControlsMenu[24].status = IT_GRAYEDOUT2; // Console - /*OP_AllControlsMenu[25].status = IT_GRAYEDOUT2; // Spectator Controls header - OP_AllControlsMenu[26].status = IT_GRAYEDOUT2; // Spectator Controls space - OP_AllControlsMenu[27].status = IT_GRAYEDOUT2; // Spectate - OP_AllControlsMenu[28].status = IT_GRAYEDOUT2; // Look Up - OP_AllControlsMenu[29].status = IT_GRAYEDOUT2; // Look Down - OP_AllControlsMenu[30].status = IT_GRAYEDOUT2; // Center View - */ M_SetupNextMenu(&OP_AllControlsDef); } @@ -12077,22 +12187,13 @@ static void M_Setup4PControlsMenu(INT32 choice) // Hide P1-only controls OP_AllControlsMenu[15].status = IT_GRAYEDOUT2; // Chat - //OP_AllControlsMenu[16].status = IT_GRAYEDOUT2; // Team-chat OP_AllControlsMenu[16].status = IT_GRAYEDOUT2; // Rankings - //OP_AllControlsMenu[17].status = IT_GRAYEDOUT2; // Viewpoint // 18 is Reset Camera, 19 is Toggle Chasecam OP_AllControlsMenu[20].status = IT_GRAYEDOUT2; // Pause OP_AllControlsMenu[21].status = IT_GRAYEDOUT2; // Screenshot OP_AllControlsMenu[22].status = IT_GRAYEDOUT2; // GIF OP_AllControlsMenu[23].status = IT_GRAYEDOUT2; // System Menu OP_AllControlsMenu[24].status = IT_GRAYEDOUT2; // Console - /*OP_AllControlsMenu[25].status = IT_GRAYEDOUT2; // Spectator Controls header - OP_AllControlsMenu[26].status = IT_GRAYEDOUT2; // Spectator Controls space - OP_AllControlsMenu[27].status = IT_GRAYEDOUT2; // Spectate - OP_AllControlsMenu[28].status = IT_GRAYEDOUT2; // Look Up - OP_AllControlsMenu[29].status = IT_GRAYEDOUT2; // Look Down - OP_AllControlsMenu[30].status = IT_GRAYEDOUT2; // Center View - */ M_SetupNextMenu(&OP_AllControlsDef); } @@ -12110,11 +12211,6 @@ static void M_DrawControl(void) x = currentMenu->x; y = currentMenu->y; - /*i = itemOn - (controlheight/2); - if (i < 0) - i = 0; - */ - iter = (controlheight/2); for (i = itemOn; ((iter || currentMenu->menuitems[i].status == IT_GRAYEDOUT2) && i > 0); i--) { @@ -12141,16 +12237,6 @@ static void M_DrawControl(void) } } - /*max = i + controlheight; - if (max > currentMenu->numitems) - { - max = currentMenu->numitems; - if (max < controlheight) - i = 0; - else - i = max - controlheight; - }*/ - // draw title (or big pic) M_DrawMenuTitle(); @@ -12175,7 +12261,7 @@ static void M_DrawControl(void) if (currentMenu->menuitems[i].status == IT_CONTROL) { - V_DrawString(x, y, ((i == itemOn) ? highlightflags : 0), currentMenu->menuitems[i].text); + V_DrawString(x, y, ((i == itemOn) ? highlightflags|V_ALLOWLOWERCASE : V_ALLOWLOWERCASE), currentMenu->menuitems[i].text); keys[0] = setupcontrols[currentMenu->menuitems[i].alphaKey][0]; keys[1] = setupcontrols[currentMenu->menuitems[i].alphaKey][1]; @@ -12196,14 +12282,14 @@ static void M_DrawControl(void) strcat (tmp, G_KeynumToString (keys[1])); } - V_DrawRightAlignedString(BASEVIDWIDTH-currentMenu->x, y, highlightflags, tmp); + V_DrawRightAlignedString(BASEVIDWIDTH-currentMenu->x, y, highlightflags|V_ALLOWLOWERCASE, tmp); } /*else if (currentMenu->menuitems[i].status == IT_GRAYEDOUT2) V_DrawString(x, y, V_TRANSLUCENT, currentMenu->menuitems[i].text);*/ else if ((currentMenu->menuitems[i].status == IT_HEADER) && (i != max-1)) - V_DrawString(19, y+6, highlightflags, currentMenu->menuitems[i].text); + V_DrawString(19, y+6, highlightflags|V_ALLOWLOWERCASE, currentMenu->menuitems[i].text); else if (currentMenu->menuitems[i].status & IT_STRING) - V_DrawString(x, y, ((i == itemOn) ? highlightflags : 0), currentMenu->menuitems[i].text); + V_DrawString(x, y, ((i == itemOn) ? highlightflags|V_ALLOWLOWERCASE : V_ALLOWLOWERCASE), currentMenu->menuitems[i].text); y += SMALLLINEHEIGHT; } diff --git a/src/m_menu.h b/src/m_menu.h index bba8d3db3..bd0cd0e69 100644 --- a/src/m_menu.h +++ b/src/m_menu.h @@ -21,6 +21,8 @@ #include "mserv.h" #include "r_things.h" // for SKINNAMESIZE +extern boolean forceshowhud; + // // MENUS // @@ -59,6 +61,9 @@ void M_SortServerList(void); // Draws a box with a texture inside as background for messages void M_DrawTextBox(INT32 x, INT32 y, INT32 width, INT32 boxlines); +// Same but with extra flags applied +void M_DrawTextBoxFlags(INT32 x, INT32 y, INT32 width, INT32 boxlines, INT32 flags); + // Used in d_netcmd to restart time attack void M_ModeAttackRetry(INT32 choice); @@ -74,6 +79,11 @@ typedef enum } menumessagetype_t; void M_StartMessage(const char *string, void *routine, menumessagetype_t itemtype); +extern boolean DPADUPSCROLL; +extern boolean DPADDOWNSCROLL; +extern boolean DPADLEFTSCROLL; +extern boolean DPADRIGHTSCROLL; + typedef enum { M_NOT_WAITING, @@ -250,6 +260,7 @@ extern INT32 mapwads[NUMMAPS]; extern description_t description[MAXSKINS]; +extern consvar_t cv_replaysearchrate; extern consvar_t cv_showfocuslost; extern consvar_t cv_newgametype, cv_nextmap, cv_chooseskin, cv_serversort; extern consvar_t cv_showallmaps; @@ -281,8 +292,8 @@ void PDistort_menu_Onchange(void); // Bird menu updating void Bird_menu_Onchange(void); -// Saturn menu updating -void Saturn_menu_Onchange(void); +// Saturn Hud menu updating +void SaturnHud_menu_Onchange(void); void M_ReplayHut(INT32 choice); void M_SetPlaybackMenuPointer(void); @@ -392,4 +403,15 @@ void M_SlotCvarIntoModMenu(consvar_t* cvar, const char* category, const char* na {NULL}\ } +#define DoToolTips(menu, tooltip)\ +if (currentMenu == &menu)\ +{\ + if (!(tooltip[itemOn] == NULL))\ + {\ + M_DrawSplitText(BASEVIDWIDTH / 2, BASEVIDHEIGHT-50, V_ALLOWLOWERCASE|V_SNAPTOBOTTOM, tooltip[itemOn], coolalphatimer);\ + if (coolalphatimer > 0 && interpTimerHackAllow)\ + coolalphatimer--;\ + }\ +} + #endif //__X_MENU__ diff --git a/src/m_misc.c b/src/m_misc.c index 7d0ce6bfc..b8c88abb5 100644 --- a/src/m_misc.c +++ b/src/m_misc.c @@ -334,6 +334,38 @@ boolean FIL_FileOK(char const *name) return access(name,6)+1; //R_OK|W_OK } +/** Copies contents of one file to another + * + * \param src File to copy from + * \param dst File to write into + * \return true if copy was succesful, false if it doesn't. + */ +boolean FIL_CopyFile(const char *src, const char *dst) +{ + FILE *srcFile = fopen(src, "rb"); + + if (srcFile == NULL) + return false; + + FILE *dstFile = fopen(dst, "wb"); + + if (dstFile == NULL) + { + fclose(srcFile); + return false; + } + + char buffer[1024]; + size_t n; + + while ((n = fread(buffer, 1, sizeof(buffer), srcFile)) > 0) + fwrite(buffer, 1, n, dstFile); + + fclose(srcFile); + fclose(dstFile); + + return true; +} /** Checks if a pathname has a file extension and adds the extension provided * if not. @@ -525,11 +557,28 @@ void M_SaveConfig(const char *filename) { FILE *f; char *filepath; + char backupfile[MAX_WADPATH+4]; // make sure not to write back the config until it's been correctly loaded if (!gameconfig_loaded) return; + // Create backup of the config file + snprintf(backupfile, sizeof backupfile, "%s.bak", configfile); + backupfile[sizeof backupfile - 1] = '\0'; + + FILE *config = fopen(configfile, "r"); + + if (config != NULL) + { + fclose(config); + if (FIL_CopyFile(configfile, backupfile) == false) + { + CONS_Alert(CONS_WARNING,"Failed to create a backup of the configuration file. Will not attempt to write to file\n"); + return; + } + } + // can change the file name if (filename) { @@ -1938,7 +1987,7 @@ char *sizeu5(size_t num) return sizeu5_buf; } -void *M_Memcpy(void *dest, const void *src, size_t n) +FUNCINLINE ATTRINLINE void *M_Memcpy(void *dest, const void *src, size_t n) { return memcpy(dest, src, n); } diff --git a/src/m_misc.h b/src/m_misc.h index 103b1d88a..333398161 100644 --- a/src/m_misc.h +++ b/src/m_misc.h @@ -54,6 +54,7 @@ boolean FIL_FileExists(const char *name); boolean FIL_WriteFileOK(char const *name); boolean FIL_ReadFileOK(char const *name); boolean FIL_FileOK(char const *name); +boolean FIL_CopyFile(const char *src, const char *dst); void FIL_DefaultExtension (char *path, const char *extension); void FIL_ForceExtension(char *path, const char *extension); diff --git a/src/m_perfstats.c b/src/m_perfstats.c index 04e51a657..a8f9550f4 100644 --- a/src/m_perfstats.c +++ b/src/m_perfstats.c @@ -58,7 +58,6 @@ static ps_metric_t ps_regularcount = {0}; static ps_metric_t ps_scenerycount = {0}; static ps_metric_t ps_nothinkcount = {0}; static ps_metric_t ps_otherthcount = {0}; -static ps_metric_t ps_precipcount = {0}; static ps_metric_t ps_removecount = {0}; ps_metric_t ps_checkposition_calls = {0}; @@ -173,7 +172,6 @@ perfstatrow_t thinkercount_rows[] = { {" scenery", " Scenery: ", &ps_scenerycount, PS_LEVEL}, {" nothink", " Nothink: ", &ps_nothinkcount, PS_HIDE_ZERO|PS_LEVEL}, {" other ", " Other: ", &ps_otherthcount, PS_LEVEL}, - {" precip ", " Precipitation: ", &ps_precipcount, PS_LEVEL}, {" remove ", " Pending removal:", &ps_removecount, PS_LEVEL}, {0} }; @@ -572,7 +570,6 @@ static void PS_CountThinkers(void) ps_scenerycount.value.i = 0; ps_nothinkcount.value.i = 0; ps_otherthcount.value.i = 0; - ps_precipcount.value.i = 0; ps_removecount.value.i = 0; for (thinker = thinkercap.next; thinker != &thinkercap; thinker = thinker->next) { @@ -590,8 +587,6 @@ static void PS_CountThinkers(void) else ps_regularcount.value.i++; } - else if (thinker->function.acp1 == (actionf_p1)P_NullPrecipThinker) - ps_precipcount.value.i++; else ps_otherthcount.value.i++; } diff --git a/src/mserv.c b/src/mserv.c index 3b5d84b46..2f172d27d 100644 --- a/src/mserv.c +++ b/src/mserv.c @@ -17,6 +17,7 @@ #include "doomstat.h" #include "doomdef.h" +#include "console.h" // con_startup #include "command.h" #include "i_threads.h" #include "mserv.h" @@ -212,20 +213,50 @@ static void Command_Listserv_f(void) } #endif +static boolean firstmsrules = false; + +static void +Get_masterserver_rules (boolean checkfirst) +{ + char rules[256]; + + if (checkfirst) + { + boolean MSRulesExist; + + Lock_state(); + MSRulesExist = (MSRules != NULL); + Unlock_state(); + + if (MSRulesExist) + return; + } + + if (HMS_fetch_rules(rules, sizeof rules)) + { + Lock_state(); + Z_Free(MSRules); + MSRules = Z_StrDup(rules); + + if (MSRegistered == true) + { + CONS_Printf("\n"); + CONS_Alert(CONS_NOTICE, "%s\n", rules); + } + + firstmsrules = true; + + Unlock_state(); + } +} + static void Finish_registration (void) { int registered; - char *rules = GetMasterServerRules(); CONS_Printf("Registering this server on the master server...\n"); - if (rules) - { - CONS_Printf("\n"); - CONS_Alert(CONS_NOTICE, "%s\n", rules); - } - registered = HMS_register(); Lock_state(); @@ -237,6 +268,17 @@ Finish_registration (void) } Unlock_state(); + char *rules = GetMasterServerRules(); + if (rules == NULL) + { + Get_masterserver_rules(true); + } + else + { + CONS_Printf("\n"); + CONS_Alert(CONS_NOTICE, "%s\n", rules); + } + if (registered) CONS_Printf("Master server registration successful.\n"); } @@ -322,17 +364,10 @@ Finish_unlist (void) static void Finish_masterserver_change (char *api) { - char rules[256]; - HMS_set_api(api); - if (HMS_fetch_rules(rules, sizeof rules)) - { - Lock_state(); - Z_Free(MSRules); - MSRules = Z_StrDup(rules); - Unlock_state(); - } + if (!con_startup) + Get_masterserver_rules(false); } #ifdef HAVE_THREADS @@ -430,6 +465,14 @@ Change_masterserver_thread (char *api) Finish_masterserver_change(api); } + +static void +Get_masterserver_rules_thread (void) +{ + // THIS FUNC has its own lock check in it + Get_masterserver_rules(true); +} + #endif/*HAVE_THREADS*/ void RegisterServer(void) @@ -540,6 +583,20 @@ Set_api (const char *api) #endif } +void +Get_rules (void) +{ +#ifdef HAVE_THREADS + I_spawn_thread( + "get-masterserver-rules", + (I_thread_fn)Get_masterserver_rules_thread, + NULL + ); +#else + Get_masterserver_rules(true); +#endif +} + #endif/*MASTERSERVER*/ static void diff --git a/src/mserv.h b/src/mserv.h index 5a74771a4..8142716ef 100644 --- a/src/mserv.h +++ b/src/mserv.h @@ -82,6 +82,8 @@ extern I_mutex ms_ServerList_mutex; void RegisterServer(void); void UnregisterServer(void); +void Get_rules(void); + void MasterClient_Ticker(void); msg_server_t *GetShortServersList(int id); @@ -90,9 +92,11 @@ char *GetMODVersion(int id); #endif char *GetMasterServerRules(void); +#endif void AddMServCommands(void); +#ifdef MASTERSERVER /* HTTP */ void HMS_set_api (char *api); int HMS_register (void); @@ -105,4 +109,4 @@ const char * HMS_fetch_rules (char *buffer, size_t size_of_buffer); #endif -#endif \ No newline at end of file +#endif diff --git a/src/p_enemy.c b/src/p_enemy.c index 42fc2bcf7..caa85e331 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -29,7 +29,7 @@ #include "hardware/hw3sound.h" #endif -boolean LUA_CallAction(const char *action, mobj_t *actor); +boolean LUA_CallAction(enum actionnum actionnum, mobj_t *actor); INT32 var1; INT32 var2; @@ -781,7 +781,7 @@ void A_Look(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; - if (LUA_CallAction("A_Look", actor)) + if (LUA_CallAction(A_LOOK, actor)) return; if (!P_LookForPlayers(actor, locvar1 & 65535, false , FixedMul((locvar1 >> 16)*FRACUNIT, actor->scale))) @@ -817,7 +817,7 @@ void A_Chase(mobj_t *actor) INT32 delta; INT32 locvar1 = var1; - if (LUA_CallAction("A_Chase", actor)) + if (LUA_CallAction(A_CHASE, actor)) return; I_Assert(actor != NULL); @@ -908,7 +908,7 @@ void A_FaceStabChase(mobj_t *actor) { INT32 delta; - if (LUA_CallAction("A_FaceStabChase", actor)) + if (LUA_CallAction(A_FACESTABCHASE, actor)) return; if (actor->reactiontime) @@ -994,7 +994,7 @@ nomissile: // void A_JetJawRoam(mobj_t *actor) { - if (LUA_CallAction("A_JetJawRoam", actor)) + if (LUA_CallAction(A_JETJAWROAM, actor)) return; if (actor->reactiontime) @@ -1023,7 +1023,7 @@ void A_JetJawChomp(mobj_t *actor) { INT32 delta; - if (LUA_CallAction("A_JetJawChomp", actor)) + if (LUA_CallAction(A_JETJAWCHOMP, actor)) return; // turn towards movement direction if not there yet @@ -1070,7 +1070,7 @@ void A_PointyThink(mobj_t *actor) boolean firsttime = true; INT32 sign; - if (LUA_CallAction("A_PointyThink", actor)) + if (LUA_CallAction(A_POINTYTHINK, actor)) return; actor->momx = actor->momy = actor->momz = 0; @@ -1168,7 +1168,7 @@ void A_CheckBuddy(mobj_t *actor) { INT32 locvar1 = var1; - if (LUA_CallAction("A_CheckBuddy", actor)) + if (LUA_CallAction(A_CHECKBUDDY, actor)) return; if (locvar1 && (!actor->tracer || actor->tracer->health <= 0)) @@ -1186,7 +1186,7 @@ void A_CheckBuddy(mobj_t *actor) // void A_HoodThink(mobj_t *actor) { - if (LUA_CallAction("A_HoodThink", actor)) + if (LUA_CallAction(A_HOODTHINK, actor)) return; // Currently in the air... @@ -1247,7 +1247,7 @@ void A_ArrowCheck(mobj_t *actor) angle_t angle; fixed_t dist; - if (LUA_CallAction("A_ArrowCheck", actor)) + if (LUA_CallAction(A_ARROWCHECK, actor)) return; // Movement vector @@ -1285,7 +1285,7 @@ void A_ArrowCheck(mobj_t *actor) // void A_SnailerThink(mobj_t *actor) { - if (LUA_CallAction("A_SnailerThink", actor)) + if (LUA_CallAction(A_SNAILERTHINK, actor)) return; if (!actor->target || !(actor->target->flags & MF_SHOOTABLE)) @@ -1358,7 +1358,7 @@ void A_SnailerThink(mobj_t *actor) // void A_SharpChase(mobj_t *actor) { - if (LUA_CallAction("A_SharpChase", actor)) + if (LUA_CallAction(A_SHARPCHASE, actor)) return; if (!actor->health) @@ -1416,7 +1416,7 @@ void A_SharpChase(mobj_t *actor) // void A_SharpSpin(mobj_t *actor) { - if (LUA_CallAction("A_SharpSpin", actor)) + if (LUA_CallAction(A_SHARPSPIN, actor)) return; if (!actor->health) @@ -1452,7 +1452,7 @@ void A_SharpSpin(mobj_t *actor) // void A_VultureVtol(mobj_t *actor) { - if (LUA_CallAction("A_VultureVtol", actor)) + if (LUA_CallAction(A_VULTUREVTOL, actor)) return; if (!actor->target) @@ -1487,7 +1487,7 @@ void A_VultureVtol(mobj_t *actor) // void A_VultureCheck(mobj_t *actor) { - if (LUA_CallAction("A_VultureCheck", actor)) + if (LUA_CallAction(A_VULTURECHECK, actor)) return; if (actor->momx || actor->momy) @@ -1513,7 +1513,7 @@ void A_SkimChase(mobj_t *actor) { INT32 delta; - if (LUA_CallAction("A_SkimChase", actor)) + if (LUA_CallAction(A_SKIMCHASE, actor)) return; if (actor->reactiontime) @@ -1599,7 +1599,7 @@ nomissile: // void A_FaceTarget(mobj_t *actor) { - if (LUA_CallAction("A_FaceTarget", actor)) + if (LUA_CallAction(A_FACETARGET, actor)) return; if (!actor->target) @@ -1617,7 +1617,7 @@ void A_FaceTarget(mobj_t *actor) // void A_FaceTracer(mobj_t *actor) { - if (LUA_CallAction("A_FaceTracer", actor)) + if (LUA_CallAction(A_FACETRACER, actor)) return; if (!actor->tracer) @@ -1646,7 +1646,7 @@ void A_LobShot(mobj_t *actor) fixed_t vertical, horizontal; fixed_t airtime = var2 & 65535; - if (LUA_CallAction("A_LobShot", actor)) + if (LUA_CallAction(A_LOBSHOT, actor)) return; if (!actor->target) @@ -1746,7 +1746,7 @@ void A_FireShot(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; - if (LUA_CallAction("A_FireShot", actor)) + if (LUA_CallAction(A_FIRESHOT, actor)) return; if (!actor->target) @@ -1784,7 +1784,7 @@ void A_SuperFireShot(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; - if (LUA_CallAction("A_SuperFireShot", actor)) + if (LUA_CallAction(A_SUPERFIRESHOT, actor)) return; if (!actor->target) @@ -1830,7 +1830,7 @@ void A_BossFireShot(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; - if (LUA_CallAction("A_BossFireShot", actor)) + if (LUA_CallAction(A_BOSSFIRESHOT, actor)) return; if (!actor->target) @@ -1911,7 +1911,7 @@ void A_Boss7FireMissiles(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; - if (LUA_CallAction("A_Boss7FireMissiles", actor)) + if (LUA_CallAction(A_BOSS7FIREMISSILES, actor)) return; if (!actor->target) @@ -1968,7 +1968,7 @@ void A_Boss1Laser(mobj_t *actor) angle_t angle; mobj_t *point; - if (LUA_CallAction("A_Boss1Laser", actor)) + if (LUA_CallAction(A_BOSS1LASER, actor)) return; if (!actor->target) @@ -2069,7 +2069,7 @@ void A_FocusTarget(mobj_t *actor) { INT32 locvar1 = var1; - if (LUA_CallAction("A_FocusTarget", actor)) + if (LUA_CallAction(A_FOCUSTARGET, actor)) return; if (actor->target) @@ -2119,7 +2119,7 @@ void A_Boss4Reverse(mobj_t *actor) { sfxenum_t locvar1 = (sfxenum_t)var1; - if (LUA_CallAction("A_Boss4Reverse", actor)) + if (LUA_CallAction(A_BOSS4REVERSE, actor)) return; S_StartSound(NULL, locvar1); @@ -2141,7 +2141,7 @@ void A_Boss4SpeedUp(mobj_t *actor) { sfxenum_t locvar1 = (sfxenum_t)var1; - if (LUA_CallAction("A_Boss4SpeedUp", actor)) + if (LUA_CallAction(A_BOSS4SPEEDUP, actor)) return; S_StartSound(NULL, locvar1); @@ -2159,7 +2159,7 @@ void A_Boss4Raise(mobj_t *actor) { sfxenum_t locvar1 = (sfxenum_t)var1; - if (LUA_CallAction("A_Boss4Raise", actor)) + if (LUA_CallAction(A_BOSS4RAISE, actor)) return; S_StartSound(NULL, locvar1); @@ -2189,7 +2189,7 @@ void A_SkullAttack(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; - if (LUA_CallAction("A_SkullAttack", actor)) + if (LUA_CallAction(A_SKULLATTACK, actor)) return; if (!actor->target) @@ -2239,7 +2239,7 @@ void A_BossZoom(mobj_t *actor) angle_t an; INT32 dist; - if (LUA_CallAction("A_BossZoom", actor)) + if (LUA_CallAction(A_BOSSZOOM, actor)) return; if (!actor->target) @@ -2279,7 +2279,7 @@ void A_BossScream(mobj_t *actor) INT32 locvar2 = var2; mobjtype_t explodetype; - if (LUA_CallAction("A_BossScream", actor)) + if (LUA_CallAction(A_BOSSSCREAM, actor)) return; switch (locvar1) @@ -2326,7 +2326,7 @@ void A_BossScream(mobj_t *actor) // void A_Scream(mobj_t *actor) { - if (LUA_CallAction("A_Scream", actor)) + if (LUA_CallAction(A_SCREAM, actor)) return; if (actor->tracer && (actor->tracer->type == MT_SHELL || actor->tracer->type == MT_FIREBALL)) @@ -2344,7 +2344,7 @@ void A_Scream(mobj_t *actor) // void A_Pain(mobj_t *actor) { - if (LUA_CallAction("A_Pain", actor)) + if (LUA_CallAction(A_PAIN, actor)) return; if (actor->info->painsound) @@ -2363,7 +2363,7 @@ void A_Pain(mobj_t *actor) // void A_Fall(mobj_t *actor) { - if (LUA_CallAction("A_Fall", actor)) + if (LUA_CallAction(A_FALL, actor)) return; // actor is on ground, it can be walked over @@ -2392,7 +2392,7 @@ void A_1upThinker(mobj_t *actor) fixed_t temp; INT32 closestplayer = -1; - if (LUA_CallAction("A_1upThinker", actor)) + if (LUA_CallAction(A_1UPTHINKER, actor)) return; for (i = 0; i < MAXPLAYERS; i++) @@ -2450,7 +2450,7 @@ void A_MonitorPop(mobj_t *actor) mobjtype_t item = 0; //mobjtype_t newbox; - if (LUA_CallAction("A_MonitorPop", actor)) + if (LUA_CallAction(A_MONITORPOP, actor)) return; // de-solidify @@ -2588,7 +2588,7 @@ for (i = cvar.value; i; --i) spawnchance[numchoices++] = type // void A_Explode(mobj_t *actor) { - if (LUA_CallAction("A_Explode", actor)) + if (LUA_CallAction(A_EXPLODE, actor)) return; P_RadiusAttack(actor, actor->target, actor->info->damage); @@ -2608,7 +2608,7 @@ void A_BossDeath(mobj_t *mo) line_t junk; INT32 i; - if (LUA_CallAction("A_BossDeath", mo)) + if (LUA_CallAction(A_BOSSDEATH, mo)) return; P_LinedefExecute(LE_BOSSDEAD, mo, NULL); @@ -2777,7 +2777,7 @@ void A_CustomPower(mobj_t *actor) INT32 locvar2 = var2; boolean spawnshield = false; - if (LUA_CallAction("A_CustomPower", actor)) + if (LUA_CallAction(A_CUSTOMPOWER, actor)) return; if (!actor->target || !actor->target->player) @@ -2817,7 +2817,7 @@ void A_GiveWeapon(mobj_t *actor) player_t *player; INT32 locvar1 = var1; - if (LUA_CallAction("A_GiveWeapon", actor)) + if (LUA_CallAction(A_GIVEWEAPON, actor)) return; if (!actor->target || !actor->target->player) @@ -2850,7 +2850,7 @@ void A_JumpShield(mobj_t *actor) { player_t *player; - if (LUA_CallAction("A_JumpShield", actor)) + if (LUA_CallAction(A_JUMPSHIELD, actor)) return; if (!actor->target || !actor->target->player) @@ -2881,7 +2881,7 @@ void A_RingShield(mobj_t *actor) { player_t *player; - if (LUA_CallAction("A_RingShield", actor)) + if (LUA_CallAction(A_RINGSHIELD, actor)) return; if (!actor->target || !actor->target->player) @@ -2913,7 +2913,7 @@ void A_RingBox(mobj_t *actor) { player_t *player; - if (LUA_CallAction("A_RingBox", actor)) + if (LUA_CallAction(A_RINGBOX, actor)) return; if (!actor->target || !actor->target->player) @@ -2940,7 +2940,7 @@ void A_Invincibility(mobj_t *actor) { player_t *player; - if (LUA_CallAction("A_Invincibility", actor)) + if (LUA_CallAction(A_INVINCIBILITY, actor)) return; if (!actor->target || !actor->target->player) @@ -2972,7 +2972,7 @@ void A_SuperSneakers(mobj_t *actor) { player_t *player; - if (LUA_CallAction("A_SuperSneakers", actor)) + if (LUA_CallAction(A_SUPERSNEAKERS, actor)) return; if (!actor->target || !actor->target->player) @@ -3008,7 +3008,7 @@ void A_AwardScore(mobj_t *actor) { player_t *player; - if (LUA_CallAction("A_AwardScore", actor)) + if (LUA_CallAction(A_AWARDSCORE, actor)) return; if (!actor->target || !actor->target->player) @@ -3035,7 +3035,7 @@ void A_ExtraLife(mobj_t *actor) { player_t *player; - if (LUA_CallAction("A_ExtraLife", actor)) + if (LUA_CallAction(A_EXTRALIFE, actor)) return; if (!actor->target || !actor->target->player) @@ -3074,7 +3074,7 @@ void A_BombShield(mobj_t *actor) { player_t *player; - if (LUA_CallAction("A_BombShield", actor)) + if (LUA_CallAction(A_BOMBSHIELD, actor)) return; if (!actor->target || !actor->target->player) @@ -3105,7 +3105,7 @@ void A_WaterShield(mobj_t *actor) { player_t *player; - if (LUA_CallAction("A_WaterShield", actor)) + if (LUA_CallAction(A_WATERSHIELD, actor)) return; if (!actor->target || !actor->target->player) @@ -3143,7 +3143,7 @@ void A_ForceShield(mobj_t *actor) { player_t *player; - if (LUA_CallAction("A_ForceShield", actor)) + if (LUA_CallAction(A_FORCESHIELD, actor)) return; if (!actor->target || !actor->target->player) @@ -3180,7 +3180,7 @@ void A_PityShield(mobj_t *actor) { player_t *player; - if (LUA_CallAction("A_PityShield", actor)) + if (LUA_CallAction(A_PITYSHIELD, actor)) return; if (!actor->target || !actor->target->player) @@ -3212,7 +3212,7 @@ void A_GravityBox(mobj_t *actor) { player_t *player; - if (LUA_CallAction("A_GravityBox", actor)) + if (LUA_CallAction(A_GRAVITYBOX, actor)) return; if (!actor->target || !actor->target->player) @@ -3236,7 +3236,7 @@ void A_GravityBox(mobj_t *actor) // void A_ScoreRise(mobj_t *actor) { - if (LUA_CallAction("A_ScoreRise", actor)) + if (LUA_CallAction(A_SCORERISE, actor)) return; // make logo rise! @@ -3257,7 +3257,7 @@ void A_ParticleSpawn(mobj_t *actor) mobjtype_t type; mobj_t *spawn; - if (LUA_CallAction("A_ParticleSpawn", actor)) + if (LUA_CallAction(A_PARTICLESPAWN, actor)) return; if (!actor->spawnpoint) @@ -3293,7 +3293,7 @@ void A_BunnyHop(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; - if (LUA_CallAction("A_BunnyHop", actor)) + if (LUA_CallAction(A_BUNNYHOP, actor)) return; if (((actor->eflags & MFE_VERTICALFLIP) && actor->z + actor->height >= actor->ceilingz) @@ -3317,7 +3317,7 @@ void A_BubbleSpawn(mobj_t *actor) UINT8 prandom; mobj_t *bubble = NULL; - if (LUA_CallAction("A_BubbleSpawn", actor)) + if (LUA_CallAction(A_BUBBLESPAWN, actor)) return; if (!(actor->eflags & MFE_UNDERWATER)) @@ -3370,7 +3370,7 @@ void A_FanBubbleSpawn(mobj_t *actor) mobj_t *bubble = NULL; fixed_t hz = actor->z + (4*actor->height)/5; - if (LUA_CallAction("A_FanBubbleSpawn", actor)) + if (LUA_CallAction(A_FANBUBBLESPAWN, actor)) return; if (!(actor->eflags & MFE_UNDERWATER)) @@ -3416,7 +3416,7 @@ void A_BubbleRise(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; - if (LUA_CallAction("A_BubbleRise", actor)) + if (LUA_CallAction(A_BUBBLERISE, actor)) return; if (actor->type == MT_EXTRALARGEBUBBLE) @@ -3452,7 +3452,7 @@ void A_BubbleRise(mobj_t *actor) // void A_BubbleCheck(mobj_t *actor) { - if (LUA_CallAction("A_BubbleCheck", actor)) + if (LUA_CallAction(A_BUBBLECHECK, actor)) return; if (actor->eflags & MFE_UNDERWATER) @@ -3470,7 +3470,7 @@ void A_BubbleCheck(mobj_t *actor) // void A_AttractChase(mobj_t *actor) { - if (LUA_CallAction("A_AttractChase", actor)) + if (LUA_CallAction(A_ATTRACTCHASE, actor)) return; if (actor->flags2 & MF2_NIGHTSPULL || !actor->health) @@ -3542,7 +3542,7 @@ void A_DropMine(mobj_t *actor) fixed_t z; mobj_t *mine; - if (LUA_CallAction("A_DropMine", actor)) + if (LUA_CallAction(A_DROPMINE, actor)) return; if (locvar2 & 65535) @@ -3589,7 +3589,7 @@ void A_FishJump(mobj_t *actor) { INT32 locvar1 = var1; - if (LUA_CallAction("A_FishJump", actor)) + if (LUA_CallAction(A_FISHJUMP, actor)) return; if ((actor->z <= actor->floorz) || (actor->z <= actor->watertop - FixedMul((64 << FRACBITS), actor->scale))) @@ -3625,7 +3625,7 @@ void A_ThrownRing(mobj_t *actor) player_t *player; fixed_t dist; - if (LUA_CallAction("A_ThrownRing", actor)) + if (LUA_CallAction(A_THROWNRING, actor)) return; if (leveltime % (TICRATE/7) == 0) @@ -3831,7 +3831,7 @@ void A_GrenadeRing(mobj_t *actor) INT32 bx, by, xl, xh, yl, yh; explodedist = FixedMul(actor->info->painchance, mapobjectscale); - if (LUA_CallAction("A_GrenadeRing", actor)) + if (LUA_CallAction(A_GRENADERING, actor)) return; if (actor->flags2 & MF2_DEBRIS) @@ -3902,7 +3902,7 @@ void A_MineExplode(mobj_t *actor) mobjtype_t type; explodedist = FixedMul((3*actor->info->painchance)/2, mapobjectscale); - if (LUA_CallAction("A_MineExplode", actor)) + if (LUA_CallAction(A_MINEEXPLODE, actor)) return; if (actor->flags2 & MF2_DEBRIS) @@ -3947,7 +3947,7 @@ void A_MineExplode(mobj_t *actor) // void A_SetSolidSteam(mobj_t *actor) { - if (LUA_CallAction("A_SetSolidSteam", actor)) + if (LUA_CallAction(A_SETSOLIDSTEAM, actor)) return; actor->flags &= ~MF_NOCLIP; @@ -3980,7 +3980,7 @@ void A_SetSolidSteam(mobj_t *actor) void A_UnsetSolidSteam(mobj_t *actor) { - if (LUA_CallAction("A_UnsetSolidSteam", actor)) + if (LUA_CallAction(A_UNSETSOLIDSTEAM, actor)) return; actor->flags &= ~MF_SOLID; @@ -3998,7 +3998,7 @@ void A_SignPlayer(mobj_t *actor) { mobj_t *ov; - if (LUA_CallAction("A_SignPlayer", actor)) + if (LUA_CallAction(A_SIGNPLAYER, actor)) return; if (!actor->target) @@ -4042,7 +4042,7 @@ void A_OverlayThink(mobj_t *actor) { fixed_t destx, desty; - if (LUA_CallAction("A_OverlayThink", actor)) + if (LUA_CallAction(A_OVERLAYTHINK, actor)) return; if (!actor->target) @@ -4094,7 +4094,7 @@ void A_JetChase(mobj_t *actor) { fixed_t thefloor; - if (LUA_CallAction("A_JetChase", actor)) + if (LUA_CallAction(A_JETCHASE, actor)) return; if (actor->flags2 & MF2_AMBUSH) @@ -4190,7 +4190,7 @@ void A_JetbThink(mobj_t *actor) sector_t *nextsector; fixed_t thefloor; - if (LUA_CallAction("A_JetbThink", actor)) + if (LUA_CallAction(A_JETBTHINK, actor)) return; if (actor->z >= actor->waterbottom && actor->watertop > actor->floorz @@ -4254,7 +4254,7 @@ void A_JetgShoot(mobj_t *actor) { fixed_t dist; - if (LUA_CallAction("A_JetgShoot", actor)) + if (LUA_CallAction(A_JETGSHOOT, actor)) return; if (!actor->target) @@ -4294,7 +4294,7 @@ void A_ShootBullet(mobj_t *actor) { fixed_t dist; - if (LUA_CallAction("A_ShootBullet", actor)) + if (LUA_CallAction(A_SHOOTBULLET, actor)) return; if (!actor->target) @@ -4321,7 +4321,7 @@ void A_ShootBullet(mobj_t *actor) // void A_MinusDigging(mobj_t *actor) { - if (LUA_CallAction("A_MinusDigging", actor)) + if (LUA_CallAction(A_MINUSDIGGING, actor)) return; actor->flags &= ~MF_SPECIAL; @@ -4373,7 +4373,7 @@ void A_MinusDigging(mobj_t *actor) void A_MinusPopup(mobj_t *actor) { - if (LUA_CallAction("A_MinusPopup", actor)) + if (LUA_CallAction(A_MINUSPOPUP, actor)) return; P_SetObjectMomZ(actor, 10*FRACUNIT, false); @@ -4394,7 +4394,7 @@ void A_MinusPopup(mobj_t *actor) // void A_MinusCheck(mobj_t *actor) { - if (LUA_CallAction("A_MinusCheck", actor)) + if (LUA_CallAction(A_MINUSCHECK, actor)) return; if ((!(actor->eflags & MFE_VERTICALFLIP) && actor->z <= actor->floorz) @@ -4421,7 +4421,7 @@ void A_MinusCheck(mobj_t *actor) // void A_ChickenCheck(mobj_t *actor) { - if (LUA_CallAction("A_ChickenCheck", actor)) + if (LUA_CallAction(A_CHICKENCHECK, actor)) return; if ((!(actor->eflags & MFE_VERTICALFLIP) && actor->z <= actor->floorz) @@ -4452,7 +4452,7 @@ void A_JetgThink(mobj_t *actor) fixed_t thefloor; - if (LUA_CallAction("A_JetgThink", actor)) + if (LUA_CallAction(A_JETGTHINK, actor)) return; if (actor->z >= actor->waterbottom && actor->watertop > actor->floorz @@ -4502,7 +4502,7 @@ void A_JetgThink(mobj_t *actor) // void A_MouseThink(mobj_t *actor) { - if (LUA_CallAction("A_MouseThink", actor)) + if (LUA_CallAction(A_MOUSETHINK, actor)) return; if (actor->reactiontime) @@ -4539,7 +4539,7 @@ void A_DetonChase(mobj_t *actor) angle_t exact; fixed_t xydist, dist; - if (LUA_CallAction("A_DetonChase", actor)) + if (LUA_CallAction(A_DETONCHASE, actor)) return; // modify tracer threshold @@ -4685,7 +4685,7 @@ void A_CapeChase(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; - if (LUA_CallAction("A_CapeChase", actor)) + if (LUA_CallAction(A_CAPECHASE, actor)) return; CONS_Debug(DBG_GAMELOGIC, "A_CapeChase called from object type %d, var1: %d, var2: %d\n", actor->type, locvar1, locvar2); @@ -4743,7 +4743,7 @@ void A_RotateSpikeBall(mobj_t *actor) INT32 locvar1 = var1; const fixed_t radius = FixedMul(12*actor->info->speed, actor->scale); - if (LUA_CallAction("A_RotateSpikeBall", actor)) + if (LUA_CallAction(A_ROTATESPIKEBALL, actor)) return; if (actor->type == MT_SPECIALSPIKEBALL) // don't remove this, these spikeballs share the same states as the rotating spikeballs @@ -4797,7 +4797,7 @@ void A_UnidusBall(mobj_t *actor) INT32 locvar1 = var1; boolean canthrow = false; - if (LUA_CallAction("A_UnidusBall", actor)) + if (LUA_CallAction(A_UNIDUSBALL, actor)) return; actor->angle += ANGLE_11hh; @@ -4894,7 +4894,7 @@ void A_RockSpawn(mobj_t *actor) fixed_t dist; fixed_t randomoomph; - if (LUA_CallAction("A_RockSpawn", actor)) + if (LUA_CallAction(A_ROCKSPAWN, actor)) return; if (i == -1) @@ -4948,7 +4948,7 @@ void A_SlingAppear(mobj_t *actor) UINT8 mlength = 4; mobj_t *spawnee; - if (LUA_CallAction("A_SlingAppear", actor)) + if (LUA_CallAction(A_SLINGAPPEAR, actor)) return; P_UnsetThingPosition(actor); @@ -5008,7 +5008,7 @@ void A_MaceRotate(mobj_t *actor) TVector *res; fixed_t radius; - if (LUA_CallAction("A_MaceRotate", actor)) + if (LUA_CallAction(A_MACEROTATE, actor)) return; // Target was removed. @@ -5120,7 +5120,7 @@ void A_SetFuse(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; - if (LUA_CallAction("A_SetFuse", actor)) + if (LUA_CallAction(A_SETFUSE, actor)) return; if ((!actor->fuse || (locvar2 >> 16)) && (locvar2 >> 16) != 2) // set the actor's fuse value @@ -5148,7 +5148,7 @@ void A_CrawlaCommanderThink(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; - if (LUA_CallAction("A_CrawlaCommanderThink", actor)) + if (LUA_CallAction(A_CRAWLACOMMANDERTHINK, actor)) return; if (actor->z >= actor->waterbottom && actor->watertop > actor->floorz @@ -5286,7 +5286,7 @@ void A_RingExplode(mobj_t *actor) thinker_t *th; angle_t d; - if (LUA_CallAction("A_RingExplode", actor)) + if (LUA_CallAction(A_RINGEXPLODE, actor)) return; for (d = 0; d < 16; d++) @@ -5332,7 +5332,7 @@ void A_OldRingExplode(mobj_t *actor) { //INT32 locvar2 = var2; boolean changecolor = (actor->target && actor->target->player); - if (LUA_CallAction("A_OldRingExplode", actor)) + if (LUA_CallAction(A_OLDRINGEXPLODE, actor)) return; for (i = 0; i < 32; i++) @@ -5408,7 +5408,7 @@ void A_MixUp(mobj_t *actor) boolean teleported[MAXPLAYERS]; INT32 i, numplayers = 0, prandom = 0; - if (LUA_CallAction("A_MixUp", actor)) + if (LUA_CallAction(A_MIXUP, actor)) return; if (!multiplayer) @@ -5664,7 +5664,7 @@ void A_RecyclePowers(mobj_t *actor) INT32 weapons[MAXPLAYERS]; INT32 weaponheld[MAXPLAYERS]; - if (LUA_CallAction("A_RecyclePowers", actor)) + if (LUA_CallAction(A_RECYCLEPOWERS, actor)) return; if (!multiplayer) @@ -5757,7 +5757,7 @@ void A_Boss1Chase(mobj_t *actor) { INT32 delta; - if (LUA_CallAction("A_Boss1Chase", actor)) + if (LUA_CallAction(A_BOSS1CHASE, actor)) return; if (!actor->target || !(actor->target->flags & MF_SHOOTABLE)) @@ -5877,7 +5877,7 @@ void A_Boss2Chase(mobj_t *actor) boolean reverse = false; INT32 speedvar; - if (LUA_CallAction("A_Boss2Chase", actor)) + if (LUA_CallAction(A_BOSS2CHASE, actor)) return; if (actor->health <= 0) @@ -6003,7 +6003,7 @@ void A_Boss2Chase(mobj_t *actor) // void A_Boss2Pogo(mobj_t *actor) { - if (LUA_CallAction("A_Boss2Pogo", actor)) + if (LUA_CallAction(A_BOSS2POGO, actor)) return; if (actor->z <= actor->floorz + FixedMul(8*FRACUNIT, actor->scale) && actor->momz <= 0) @@ -6051,7 +6051,7 @@ void A_Boss2TakeDamage(mobj_t *actor) { INT32 locvar1 = var1; - if (LUA_CallAction("A_Boss2TakeDamage", actor)) + if (LUA_CallAction(A_BOSS2TAKEDAMAGE, actor)) return; A_Pain(actor); @@ -6074,7 +6074,7 @@ void A_Boss7Chase(mobj_t *actor) INT32 delta; INT32 i; - if (LUA_CallAction("A_Boss7Chase", actor)) + if (LUA_CallAction(A_BOSS7CHASE, actor)) return; if (actor->z != actor->floorz) @@ -6204,7 +6204,7 @@ void A_Boss7Chase(mobj_t *actor) // void A_GoopSplat(mobj_t *actor) { - if (LUA_CallAction("A_GoopSplat", actor)) + if (LUA_CallAction(A_GOOPSPLAT, actor)) return; P_UnsetThingPosition(actor); @@ -6229,7 +6229,7 @@ void A_Boss2PogoSFX(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; - if (LUA_CallAction("A_Boss2PogoSFX", actor)) + if (LUA_CallAction(A_BOSS2POGOSFX, actor)) return; if (!actor->target || !(actor->target->flags & MF_SHOOTABLE)) @@ -6271,7 +6271,7 @@ void A_Boss2PogoTarget(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; - if (LUA_CallAction("A_Boss2PogoTarget", actor)) + if (LUA_CallAction(A_BOSS2POGOTARGET, actor)) return; if (!actor->target || !(actor->target->flags & MF_SHOOTABLE) || (actor->target->player && actor->target->player->powers[pw_flashing]) @@ -6356,7 +6356,7 @@ void A_Boss2PogoTarget(mobj_t *actor) // void A_EggmanBox(mobj_t *actor) { - if (LUA_CallAction("A_EggmanBox", actor)) + if (LUA_CallAction(A_EGGMANBOX, actor)) return; if (!actor->target || !actor->target->player) @@ -6382,7 +6382,7 @@ void A_TurretFire(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; - if (LUA_CallAction("A_TurretFire", actor)) + if (LUA_CallAction(A_TURRETFIRE, actor)) return; if (locvar2) @@ -6420,7 +6420,7 @@ void A_SuperTurretFire(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; - if (LUA_CallAction("A_SuperTurretFire", actor)) + if (LUA_CallAction(A_SUPERTURRETFIRE, actor)) return; if (locvar2) @@ -6456,7 +6456,7 @@ void A_TurretStop(mobj_t *actor) { INT32 locvar1 = var1; - if (LUA_CallAction("A_TurretStop", actor)) + if (LUA_CallAction(A_TURRETSTOP, actor)) return; actor->flags2 &= ~MF2_FIRING; @@ -6475,7 +6475,7 @@ void A_TurretStop(mobj_t *actor) // void A_SparkFollow(mobj_t *actor) { - if (LUA_CallAction("A_SparkFollow", actor)) + if (LUA_CallAction(A_SPARKFOLLOW, actor)) return; if ((!actor->target || (actor->target->health <= 0)) @@ -6511,7 +6511,7 @@ void A_BuzzFly(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; - if (LUA_CallAction("A_BuzzFly", actor)) + if (LUA_CallAction(A_BUZZFLY, actor)) return; if (actor->flags2 & MF2_AMBUSH) @@ -6610,7 +6610,7 @@ void A_GuardChase(mobj_t *actor) { INT32 delta; - if (LUA_CallAction("A_GuardChase", actor)) + if (LUA_CallAction(A_GUARDCHASE, actor)) return; if (actor->reactiontime) @@ -6685,7 +6685,7 @@ void A_EggShield(mobj_t *actor) fixed_t movex, movey; angle_t angle; - if (LUA_CallAction("A_EggShield", actor)) + if (LUA_CallAction(A_EGGSHIELD, actor)) return; if (!actor->target || !actor->target->health) @@ -6767,7 +6767,7 @@ void A_EggShield(mobj_t *actor) // void A_SetReactionTime(mobj_t *actor) { - if (LUA_CallAction("A_SetReactionTime", actor)) + if (LUA_CallAction(A_SETREACTIONTIME, actor)) return; if (var1) @@ -6789,7 +6789,7 @@ void A_Boss1Spikeballs(mobj_t *actor) INT32 locvar2 = var2; mobj_t *ball; - if (LUA_CallAction("A_Boss1Spikeballs", actor)) + if (LUA_CallAction(A_BOSS1SPIKEBALLS, actor)) return; ball = P_SpawnMobj(actor->x, actor->y, actor->z, MT_EGGMOBILE_BALL); @@ -6811,7 +6811,7 @@ void A_Boss1Spikeballs(mobj_t *actor) // void A_Boss3TakeDamage(mobj_t *actor) { - if (LUA_CallAction("A_Boss3TakeDamage", actor)) + if (LUA_CallAction(A_BOSS3TAKEDAMAGE, actor)) return; actor->movecount = var1; @@ -6829,7 +6829,7 @@ void A_Boss3TakeDamage(mobj_t *actor) // void A_Boss3Path(mobj_t *actor) { - if (LUA_CallAction("A_Boss3Path", actor)) + if (LUA_CallAction(A_BOSS3PATH, actor)) return; if (actor->tracer && actor->tracer->health && actor->tracer->movecount) @@ -6955,7 +6955,7 @@ void A_LinedefExecute(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; - if (LUA_CallAction("A_LinedefExecute", actor)) + if (LUA_CallAction(A_LINEDEFEXECUTE, actor)) return; tagnum = locvar1; @@ -6979,7 +6979,7 @@ void A_LinedefExecute(mobj_t *actor) // void A_PlaySeeSound(mobj_t *actor) { - if (LUA_CallAction("A_PlaySeeSound", actor)) + if (LUA_CallAction(A_PLAYSEESOUND, actor)) return; if (actor->info->seesound) @@ -6995,7 +6995,7 @@ void A_PlaySeeSound(mobj_t *actor) // void A_PlayAttackSound(mobj_t *actor) { - if (LUA_CallAction("A_PlayAttackSound", actor)) + if (LUA_CallAction(A_PLAYATTACKSOUND, actor)) return; if (actor->info->attacksound) @@ -7011,7 +7011,7 @@ void A_PlayAttackSound(mobj_t *actor) // void A_PlayActiveSound(mobj_t *actor) { - if (LUA_CallAction("A_PlayActiveSound", actor)) + if (LUA_CallAction(A_PLAYACTIVESOUND, actor)) return; if (actor->info->activesound) @@ -7030,7 +7030,7 @@ void A_SmokeTrailer(mobj_t *actor) mobj_t *th; INT32 locvar1 = var1; - if (LUA_CallAction("A_SmokeTrailer", actor)) + if (LUA_CallAction(A_SMOKETRAILER, actor)) return; if (leveltime % 4) @@ -7071,7 +7071,7 @@ void A_SpawnObjectAbsolute(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; - if (LUA_CallAction("A_SpawnObjectAbsolute", actor)) + if (LUA_CallAction(A_SPAWNOBJECTABSOLUTE, actor)) return; x = (INT16)(locvar1>>16); @@ -7107,7 +7107,7 @@ void A_SpawnObjectRelative(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; - if (LUA_CallAction("A_SpawnObjectRelative", actor)) + if (LUA_CallAction(A_SPAWNOBJECTRELATIVE, actor)) return; CONS_Debug(DBG_GAMELOGIC, "A_SpawnObjectRelative called from object type %d, var1: %d, var2: %d\n", actor->type, locvar1, locvar2); @@ -7147,7 +7147,7 @@ void A_ChangeAngleRelative(mobj_t *actor) const fixed_t amin = locvar1*FRACUNIT; const fixed_t amax = locvar2*FRACUNIT; - if (LUA_CallAction("A_ChangeAngleRelative", actor)) + if (LUA_CallAction(A_CHANGEANGLERELATIVE, actor)) return; #ifdef PARANOIA @@ -7172,7 +7172,7 @@ void A_ChangeAngleAbsolute(mobj_t *actor) const fixed_t amin = locvar1*FRACUNIT; const fixed_t amax = locvar2*FRACUNIT; - if (LUA_CallAction("A_ChangeAngleAbsolute", actor)) + if (LUA_CallAction(A_CHANGEANGLEABSOLUTE, actor)) return; #ifdef PARANOIA @@ -7196,7 +7196,7 @@ void A_RollAngle(mobj_t *actor) INT32 locvar2 = var2; const angle_t angle = FixedAngle(locvar1*FRACUNIT); - if (LUA_CallAction("A_RollAngle", actor)) + if (LUA_CallAction(A_ROLLANGLE, actor)) return; // relative (default) @@ -7221,7 +7221,7 @@ void A_ChangeRollAngleRelative(mobj_t *actor) const fixed_t amin = locvar1*FRACUNIT; const fixed_t amax = locvar2*FRACUNIT; - if (LUA_CallAction("A_ChangeRollAngleRelative", actor)) + if (LUA_CallAction(A_CHANGEROLLANGLERELATIVE, actor)) return; #ifdef PARANOIA @@ -7246,7 +7246,7 @@ void A_ChangeRollAngleAbsolute(mobj_t *actor) const fixed_t amin = locvar1*FRACUNIT; const fixed_t amax = locvar2*FRACUNIT; - if (LUA_CallAction("A_ChangeRollAngleAbsolute", actor)) + if (LUA_CallAction(A_CHANGEROLLANGLEABSOLUTE, actor)) return; #ifdef PARANOIA @@ -7271,7 +7271,7 @@ void A_PlaySound(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; - if (LUA_CallAction("A_PlaySound", actor)) + if (LUA_CallAction(A_PLAYSOUND, actor)) return; S_StartSound(locvar2 ? actor : NULL, locvar1); @@ -7293,7 +7293,7 @@ void A_FindTarget(mobj_t *actor) mobj_t *mo2; fixed_t dist1 = 0, dist2 = 0; - if (LUA_CallAction("A_FindTarget", actor)) + if (LUA_CallAction(A_FINDTARGET, actor)) return; CONS_Debug(DBG_GAMELOGIC, "A_FindTarget called from object type %d, var1: %d, var2: %d\n", actor->type, locvar1, locvar2); @@ -7357,7 +7357,7 @@ void A_FindTracer(mobj_t *actor) mobj_t *mo2; fixed_t dist1 = 0, dist2 = 0; - if (LUA_CallAction("A_FindTracer", actor)) + if (LUA_CallAction(A_FINDTRACER, actor)) return; CONS_Debug(DBG_GAMELOGIC, "A_FindTracer called from object type %d, var1: %d, var2: %d\n", actor->type, locvar1, locvar2); @@ -7417,7 +7417,7 @@ void A_SetTics(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; - if (LUA_CallAction("A_SetTics", actor)) + if (LUA_CallAction(A_SETTICS, actor)) return; if (locvar1) @@ -7438,7 +7438,7 @@ void A_SetRandomTics(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; - if (LUA_CallAction("A_SetRandomTics", actor)) + if (LUA_CallAction(A_SETRANDOMTICS, actor)) return; actor->tics = P_RandomRange(locvar1, locvar2); @@ -7456,7 +7456,7 @@ void A_ChangeColorRelative(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; - if (LUA_CallAction("A_ChangeColorRelative", actor)) + if (LUA_CallAction(A_CHANGECOLORRELATIVE, actor)) return; if (locvar1) @@ -7481,7 +7481,7 @@ void A_ChangeColorAbsolute(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; - if (LUA_CallAction("A_ChangeColorAbsolute", actor)) + if (LUA_CallAction(A_CHANGECOLORABSOLUTE, actor)) return; if (locvar1) @@ -7505,7 +7505,7 @@ void A_MoveRelative(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; - if (LUA_CallAction("A_MoveRelative", actor)) + if (LUA_CallAction(A_MOVERELATIVE, actor)) return; P_Thrust(actor, actor->angle+FixedAngle(locvar1*FRACUNIT), FixedMul(locvar2*FRACUNIT, actor->scale)); @@ -7523,7 +7523,7 @@ void A_MoveAbsolute(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; - if (LUA_CallAction("A_MoveAbsolute", actor)) + if (LUA_CallAction(A_MOVEABSOLUTE, actor)) return; P_InstaThrust(actor, FixedAngle(locvar1*FRACUNIT), FixedMul(locvar2*FRACUNIT, actor->scale)); @@ -7541,7 +7541,7 @@ void A_Thrust(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; - if (LUA_CallAction("A_Thrust", actor)) + if (LUA_CallAction(A_THRUST, actor)) return; if (!locvar1) @@ -7567,7 +7567,7 @@ void A_ZThrust(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; - if (LUA_CallAction("A_ZThrust", actor)) + if (LUA_CallAction(A_ZTHRUST, actor)) return; if (!locvar1) @@ -7601,7 +7601,7 @@ void A_SetTargetsTarget(mobj_t *actor) INT32 locvar2 = var2; mobj_t *oldtarg = NULL, *newtarg = NULL; - if (LUA_CallAction("A_SetTargetsTarget", actor)) + if (LUA_CallAction(A_SETTARGETSTARGET, actor)) return; // actor's target @@ -7645,7 +7645,7 @@ void A_SetObjectFlags(mobj_t *actor) INT32 locvar2 = var2; boolean unlinkthings = false; - if (LUA_CallAction("A_SetObjectFlags", actor)) + if (LUA_CallAction(A_SETOBJECTFLAGS, actor)) return; if (locvar2 == 2) @@ -7686,7 +7686,7 @@ void A_SetObjectFlags2(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; - if (LUA_CallAction("A_SetObjectFlags2", actor)) + if (LUA_CallAction(A_SETOBJECTFLAGS2, actor)) return; if (locvar2 == 2) @@ -7713,7 +7713,7 @@ void A_BossJetFume(mobj_t *actor) mobj_t *filler; INT32 locvar1 = var1; - if (LUA_CallAction("A_BossJetFume", actor)) + if (LUA_CallAction(A_BOSSJETFUME, actor)) return; if (locvar1 == 0) // Boss1 jet fumes @@ -7823,7 +7823,7 @@ void A_RandomState(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; - if (LUA_CallAction("A_RandomState", actor)) + if (LUA_CallAction(A_RANDOMSTATE, actor)) return; P_SetMobjState(actor, P_RandomChance(FRACUNIT/2) ? locvar1 : locvar2); @@ -7841,7 +7841,7 @@ void A_RandomStateRange(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; - if (LUA_CallAction("A_RandomStateRange", actor)) + if (LUA_CallAction(A_RANDOMSTATERANGE, actor)) return; P_SetMobjState(actor, P_RandomRange(locvar1, locvar2)); @@ -7859,7 +7859,7 @@ void A_DualAction(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; - if (LUA_CallAction("A_DualAction", actor)) + if (LUA_CallAction(A_DUALACTION, actor)) return; CONS_Debug(DBG_GAMELOGIC, "A_DualAction called from object type %d, var1: %d, var2: %d\n", actor->type, locvar1, locvar2); @@ -7892,7 +7892,7 @@ void A_RemoteAction(mobj_t *actor) INT32 locvar2 = var2; mobj_t *originaltarget = actor->target; // Hold on to the target for later. - if (LUA_CallAction("A_RemoteAction", actor)) + if (LUA_CallAction(A_REMOTEACTION, actor)) return; // If >=0, find the closest target. @@ -7974,7 +7974,7 @@ void A_RemoteAction(mobj_t *actor) // void A_ToggleFlameJet(mobj_t* actor) { - if (LUA_CallAction("A_ToggleFlameJet", actor)) + if (LUA_CallAction(A_TOGGLEFLAMEJET, actor)) return; // threshold - off delay @@ -8002,7 +8002,7 @@ void A_ItemPop(mobj_t *actor) mobj_t *remains; mobjtype_t explode; - if (LUA_CallAction("A_ItemPop", actor)) + if (LUA_CallAction(A_ITEMPOP, actor)) return; if (!(actor->target && actor->target->player)) @@ -8068,7 +8068,7 @@ void A_JawzChase(mobj_t *actor) { player_t *player; - if (LUA_CallAction("A_JawzChase", actor)) + if (LUA_CallAction(A_JAWZCHASE, actor)) return; if (actor->tracer) @@ -8113,7 +8113,7 @@ void A_JawzExplode(mobj_t *actor) INT32 shrapnel = 2; mobj_t *truc; - if (LUA_CallAction("A_JawzExplode", actor)) + if (LUA_CallAction(A_JAWZEXPLODE, actor)) return; truc = P_SpawnMobj(actor->x, actor->y, actor->z, MT_BOOMEXPLODE); @@ -8153,7 +8153,7 @@ void A_SPBChase(mobj_t *actor) angle_t hang, vang; fixed_t wspeed, xyspeed, zspeed; - if (LUA_CallAction("A_SPBChase", actor)) + if (LUA_CallAction(A_SPBCHASE, actor)) return; // Default speed @@ -8432,7 +8432,7 @@ void A_BallhogExplode(mobj_t *actor) { mobj_t *mo2; - if (LUA_CallAction("A_BallhogExplode", actor)) + if (LUA_CallAction(A_BALLHOGEXPLODE, actor)) return; mo2 = P_SpawnMobj(actor->x, actor->y, actor->z, MT_BALLHOGBOOM); @@ -8448,7 +8448,7 @@ void A_LightningFollowPlayer(mobj_t *actor) { fixed_t sx, sy; - if (LUA_CallAction("A_LightningFollowPlayer", actor)) + if (LUA_CallAction(A_LIGHTNINGFOLLOWPLAYER, actor)) return; if (!actor->target) @@ -8477,7 +8477,7 @@ void A_FZBoomFlash(mobj_t *actor) { UINT8 i; - if (LUA_CallAction("A_FZBoomFlash", actor)) + if (LUA_CallAction(A_FZBOOMFLASH, actor)) return; for (i = 0; i < MAXPLAYERS; i++) @@ -8500,7 +8500,7 @@ void A_FZBoomSmoke(mobj_t *actor) INT32 i; INT32 rad = 47+(23*var1); - if (LUA_CallAction("A_FZBoomSmoke", actor)) + if (LUA_CallAction(A_FZBOOMSMOKE, actor)) return; for (i = 0; i < 8+(4*var1); i++) @@ -8522,7 +8522,7 @@ void A_RandomShadowFrame(mobj_t *actor) mobj_t *fire; mobj_t *fake; - if (LUA_CallAction("A_RandomShadowFrame", (actor))) + if (LUA_CallAction(A_RANDOMSHADOWFRAME, actor)) return; if (!actor->extravalue1) // Hack that spawns thoks that look like random shadows. Otherwise the state would overwrite our frame and that's a pain. @@ -8569,7 +8569,7 @@ void A_RoamingShadowThinker(mobj_t *actor) { mobj_t *wind; - if (LUA_CallAction("A_RoamingShadowThinker", (actor))) + if (LUA_CallAction(A_ROAMINGSHADOWTHINKER, actor)) return; // extravalue1 replaces "movetimer" @@ -8627,7 +8627,7 @@ void A_MayonakaArrow(mobj_t *actor) INT32 flip = 0; INT32 iswarning; - if (LUA_CallAction("A_MayonakaArrow", (actor))) + if (LUA_CallAction(A_MAYONAKAARROW, actor)) return; iswarning = actor->spawnpoint->options & MTF_OBJECTSPECIAL; // is our object a warning sign? @@ -8667,7 +8667,7 @@ void A_MementosTPParticles(mobj_t *actor) int i = 0; thinker_t *th; - if (LUA_CallAction("A_MementosTPParticles", (actor))) + if (LUA_CallAction(A_MEMENTOSTPPARTICLES, actor)) return; for (; i<4; i++) @@ -8716,7 +8716,7 @@ void A_ReaperThinker(mobj_t *actor) player_t *player; // used as a shortcut in a loop. mobj_t *targetplayermo = NULL; // the player mo we can eventually target, or whatever. - if (LUA_CallAction("A_ReaperThinker", (actor))) + if (LUA_CallAction(A_REAPERTHINKER, actor)) return; // We don't have custom variables or whatever so we'll do with whatever the fuck we have left. @@ -8887,7 +8887,7 @@ void A_FlameParticle(mobj_t *actor) fixed_t rad = actor->radius>>FRACBITS, hei = actor->radius>>FRACBITS; mobj_t *par; - if (LUA_CallAction("A_FlameParticle", actor)) + if (LUA_CallAction(A_FLAMEPARTICLE, actor)) return; par = P_SpawnMobj( @@ -8912,7 +8912,7 @@ void A_OrbitNights(mobj_t* actor) INT32 ofs = (var2 & 0xFFFF); boolean ishelper = (var2 & 0xFFFF0000); - if (LUA_CallAction("A_OrbitNights", actor)) + if (LUA_CallAction(A_ORBITNIGHTS, actor)) return; if (!actor->target || !actor->target->player || @@ -8955,7 +8955,7 @@ void A_OrbitNights(mobj_t* actor) // void A_GhostMe(mobj_t *actor) { - if (LUA_CallAction("A_GhostMe", actor)) + if (LUA_CallAction(A_GHOSTME, actor)) return; P_SpawnGhostMobj(actor); @@ -8976,7 +8976,7 @@ void A_SetObjectState(mobj_t *actor) INT32 locvar2 = var2; mobj_t *target; - if (LUA_CallAction("A_SetObjectState", actor)) + if (LUA_CallAction(A_SETOBJECTSTATE, actor)) return; if ((!locvar2 && !actor->target) || (locvar2 && !actor->tracer)) @@ -9020,7 +9020,7 @@ void A_SetObjectTypeState(mobj_t *actor) mobj_t *mo2; fixed_t dist = 0; - if (LUA_CallAction("A_SetObjectTypeState", actor)) + if (LUA_CallAction(A_SETOBJECTTYPESTATE, actor)) return; for (th = thinkercap.next; th != &thinkercap; th = th->next) @@ -9062,7 +9062,7 @@ void A_KnockBack(mobj_t *actor) INT32 locvar1 = var1; mobj_t *target; - if (LUA_CallAction("A_KnockBack", actor)) + if (LUA_CallAction(A_KNOCKBACK, actor)) return; if (!locvar1) @@ -9097,7 +9097,7 @@ void A_PushAway(mobj_t *actor) mobj_t *target; // target angle_t an; // actor to target angle - if (LUA_CallAction("A_PushAway", actor)) + if (LUA_CallAction(A_PUSHAWAY, actor)) return; if ((!(locvar2 >> 16) && !actor->target) || ((locvar2 >> 16) && !actor->tracer)) @@ -9131,7 +9131,7 @@ void A_RingDrain(mobj_t *actor) INT32 locvar1 = var1; player_t *player; - if (LUA_CallAction("A_RingDrain", actor)) + if (LUA_CallAction(A_RINGDRAIN, actor)) return; if (!actor->target || !actor->target->player) @@ -9163,7 +9163,7 @@ void A_SplitShot(mobj_t *actor) const fixed_t offs = (fixed_t)(locvar1*FRACUNIT); const fixed_t hoffs = (fixed_t)(loc2up*FRACUNIT); - if (LUA_CallAction("A_SplitShot", actor)) + if (LUA_CallAction(A_SPLITSHOT, actor)) return; A_FaceTarget(actor); @@ -9197,7 +9197,7 @@ void A_MissileSplit(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; - if (LUA_CallAction("A_MissileSplit", actor)) + if (LUA_CallAction(A_MISSILESPLIT, actor)) return; if (actor->eflags & MFE_VERTICALFLIP) @@ -9225,7 +9225,7 @@ void A_MultiShot(mobj_t *actor) INT32 count = 0; fixed_t ad; - if (LUA_CallAction("A_MultiShot", actor)) + if (LUA_CallAction(A_MULTISHOT, actor)) return; if (actor->target) @@ -9286,7 +9286,7 @@ void A_InstaLoop(mobj_t *actor) const fixed_t ac = FINECOSINE(fa); const fixed_t as = FINESINE(fa); - if (LUA_CallAction("A_InstaLoop", actor)) + if (LUA_CallAction(A_INSTALOOP, actor)) return; P_InstaThrust(actor, actor->angle, FixedMul(ac, FixedMul(force, actor->scale))); @@ -9319,7 +9319,7 @@ void A_Custom3DRotate(mobj_t *actor) const fixed_t hspeed = FixedMul(loc2up*FRACUNIT/10, actor->scale); const fixed_t vspeed = FixedMul(loc2lw*FRACUNIT/10, actor->scale); - if (LUA_CallAction("A_Custom3DRotate", actor)) + if (LUA_CallAction(A_CUSTOM3DROTATE, actor)) return; if (!actor->target) // Ensure we actually have a target first. @@ -9379,7 +9379,7 @@ void A_SearchForPlayers(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; - if (LUA_CallAction("A_SearchForPlayers", actor)) + if (LUA_CallAction(A_SEARCHFORPLAYERS, actor)) return; if (!actor->target || !(actor->target->flags & MF_SHOOTABLE)) @@ -9411,7 +9411,7 @@ void A_CheckRandom(mobj_t *actor) INT32 locvar2 = var2; fixed_t chance = FRACUNIT; - if (LUA_CallAction("A_CheckRandom", actor)) + if (LUA_CallAction(A_CHECKRANDOM, actor)) return; if ((locvar1 & 0xFFFF) == 0) @@ -9438,7 +9438,7 @@ void A_CheckTargetRings(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; - if (LUA_CallAction("A_CheckTargetRings", actor)) + if (LUA_CallAction(A_CHECKTARGETRINGS, actor)) return; if (!(actor->target) || !(actor->target->player)) @@ -9461,7 +9461,7 @@ void A_CheckRings(mobj_t *actor) INT32 locvar2 = var2; INT32 i, cntr = 0; - if (LUA_CallAction("A_CheckRings", actor)) + if (LUA_CallAction(A_CHECKRINGS, actor)) return; for (i = 0; i < MAXPLAYERS; i++) @@ -9485,7 +9485,7 @@ void A_CheckTotalRings(mobj_t *actor) INT32 i, cntr = 0; - if (LUA_CallAction("A_CheckTotalRings", actor)) + if (LUA_CallAction(A_CHECKTOTALRINGS, actor)) return; for (i = 0; i < MAXPLAYERS; i++) @@ -9507,7 +9507,7 @@ void A_CheckHealth(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; - if (LUA_CallAction("A_CheckHealth", actor)) + if (LUA_CallAction(A_CHECKHEALTH, actor)) return; if (actor->health <= locvar1) @@ -9529,7 +9529,7 @@ void A_CheckRange(mobj_t *actor) INT32 locvar2 = var2; fixed_t dist; - if (LUA_CallAction("A_CheckRange", actor)) + if (LUA_CallAction(A_CHECKRANGE, actor)) return; if ((!(locvar1 >> 16) && !actor->target) || ((locvar1 >> 16) && !actor->tracer)) @@ -9559,7 +9559,7 @@ void A_CheckHeight(mobj_t *actor) INT32 locvar2 = var2; fixed_t height; - if (LUA_CallAction("A_CheckHeight", actor)) + if (LUA_CallAction(A_CHECKHEIGHT, actor)) return; if ((!(locvar1 >> 16) && !actor->target) || ((locvar1 >> 16) && !actor->tracer)) @@ -9591,7 +9591,7 @@ void A_CheckTrueRange(mobj_t *actor) fixed_t dist; // horizontal range fixed_t l; // true range - if (LUA_CallAction("A_CheckTrueRange", actor)) + if (LUA_CallAction(A_CHECKTRUERANGE, actor)) return; if ((!(locvar1 >> 16) && !actor->target) || ((locvar1 >> 16) && !actor->tracer)) @@ -9642,7 +9642,7 @@ void A_CheckThingCount(mobj_t *actor) mobj_t *mo2; fixed_t dist = 0; - if (LUA_CallAction("A_CheckThingCount", actor)) + if (LUA_CallAction(A_CHECKTHINGCOUNT, actor)) return; for (th = thinkercap.next; th != &thinkercap; th = th->next) @@ -9687,7 +9687,7 @@ void A_CheckAmbush(mobj_t *actor) angle_t atp; // actor to target angle angle_t an; // angle between at and atp - if (LUA_CallAction("A_CheckAmbush", actor)) + if (LUA_CallAction(A_CHECKAMBUSH, actor)) return; if ((!locvar1 && !actor->target) || (locvar1 && !actor->tracer)) @@ -9725,7 +9725,7 @@ void A_CheckCustomValue(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; - if (LUA_CallAction("A_CheckCustomValue", actor)) + if (LUA_CallAction(A_CHECKCUSTOMVALUE, actor)) return; if (actor->cusval >= locvar1) @@ -9744,7 +9744,7 @@ void A_CheckCusValMemo(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; - if (LUA_CallAction("A_CheckCusValMemo", actor)) + if (LUA_CallAction(A_CHECKCUSVALMEMO, actor)) return; if (actor->cvmem >= locvar1) @@ -9769,7 +9769,7 @@ void A_SetCustomValue(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; - if (LUA_CallAction("A_SetCustomValue", actor)) + if (LUA_CallAction(A_SETCUSTOMVALUE, actor)) return; if (cv_debug) @@ -9819,7 +9819,7 @@ void A_UseCusValMemo(mobj_t *actor) INT32 temp = actor->cusval; // value being manipulated INT32 tempM = actor->cvmem; // value used to manipulate temp with - if (LUA_CallAction("A_UseCusValMemo", actor)) + if (LUA_CallAction(A_USECUSVALMEMO, actor)) return; if (locvar1 == 1) // cvmem being changed using cusval @@ -9882,7 +9882,7 @@ void A_RelayCustomValue(mobj_t *actor) INT32 temp; // reference value - var1 lower 16 bits changes this INT32 tempT; // target's value - changed to tracer if var1 upper 16 bits set, then modified to become final value - if (LUA_CallAction("A_RelayCustomValue", actor)) + if (LUA_CallAction(A_RELAYCUSTOMVALUE, actor)) return; if ((!(locvar1 >> 16) && !actor->target) || ((locvar1 >> 16) && !actor->tracer)) @@ -9941,7 +9941,7 @@ void A_CusValAction(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; - if (LUA_CallAction("A_CusValAction", actor)) + if (LUA_CallAction(A_CUSVALACTION, actor)) return; if (locvar2 == 5) @@ -9992,7 +9992,7 @@ void A_ForceStop(mobj_t *actor) { INT32 locvar1 = var1; - if (LUA_CallAction("A_ForceStop", actor)) + if (LUA_CallAction(A_FORCESTOP, actor)) return; actor->momx = actor->momy = 0; @@ -10011,7 +10011,7 @@ void A_ForceWin(mobj_t *actor) { INT32 i; - if (LUA_CallAction("A_ForceWin", actor)) + if (LUA_CallAction(A_FORCEWIN, actor)) return; for (i = 0; i < MAXPLAYERS; i++) @@ -10041,7 +10041,7 @@ void A_SpikeRetract(mobj_t *actor) { INT32 locvar1 = var1; - if (LUA_CallAction("A_SpikeRetract", actor)) + if (LUA_CallAction(A_SPIKERETRACT, actor)) return; if (actor->flags & MF_NOBLOCKMAP) @@ -10125,7 +10125,7 @@ void A_Repeat(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; - if (LUA_CallAction("A_Repeat", actor)) + if (LUA_CallAction(A_REPEAT, actor)) return; if ((!(actor->extravalue2)) || actor->extravalue2 > locvar1) @@ -10150,7 +10150,7 @@ void A_SetScale(mobj_t *actor) INT32 locvar2 = var2; mobj_t *target; - if (LUA_CallAction("A_SetScale", actor)) + if (LUA_CallAction(A_SETSCALE, actor)) return; if (locvar1 <= 0) @@ -10195,7 +10195,7 @@ void A_RemoteDamage(mobj_t *actor) mobj_t *target; // we MUST have a target mobj_t *source = NULL; // on the other hand we don't necessarily need a source - if (LUA_CallAction("A_RemoteDamage", actor)) + if (LUA_CallAction(A_REMOTEDAMAGE, actor)) return; if (locvar1 == 1) @@ -10248,7 +10248,7 @@ void A_HomingChase(mobj_t *actor) fixed_t dist; fixed_t speedmul; - if (LUA_CallAction("A_HomingChase", actor)) + if (LUA_CallAction(A_HOMINGCHASE, actor)) return; if (locvar2 == 1) @@ -10296,7 +10296,7 @@ void A_TrapShot(mobj_t *actor) fixed_t x, y, z; fixed_t speed; - if (LUA_CallAction("A_TrapShot", actor)) + if (LUA_CallAction(A_TRAPSHOT, actor)) return; x = actor->x + P_ReturnThrustX(actor, actor->angle, FixedMul(frontoff*FRACUNIT, actor->scale)); @@ -10349,7 +10349,7 @@ void A_VileTarget(mobj_t *actor) mobjtype_t fogtype; INT32 i; - if (LUA_CallAction("A_VileTarget", actor)) + if (LUA_CallAction(A_VILETARGET, actor)) return; if (!actor->target) @@ -10436,7 +10436,7 @@ void A_VileAttack(mobj_t *actor) mobj_t *fire; INT32 i; - if (LUA_CallAction("A_VileAttack", actor)) + if (LUA_CallAction(A_VILEATTACK, actor)) return; if (!actor->target) @@ -10548,7 +10548,7 @@ void A_VileFire(mobj_t *actor) INT32 locvar2 = var2; mobj_t *dest; - if (LUA_CallAction("A_VileFire", actor)) + if (LUA_CallAction(A_VILEFIRE, actor)) return; dest = actor->tracer; @@ -10634,7 +10634,7 @@ void A_BrakChase(mobj_t *actor) INT32 locvar1 = var1; INT32 locvar2 = var2; - if (LUA_CallAction("A_BrakChase", actor)) + if (LUA_CallAction(A_BRAKCHASE, actor)) return; // Set new tics NOW, in case the state changes while we're doing this and we try applying this to the painstate or something silly @@ -10754,7 +10754,7 @@ void A_BrakFireShot(mobj_t *actor) fixed_t x, y, z; INT32 locvar1 = var1; - if (LUA_CallAction("A_BrakFireShot", actor)) + if (LUA_CallAction(A_BRAKFIRESHOT, actor)) return; if (!actor->target) @@ -10817,7 +10817,7 @@ void A_BrakLobShot(mobj_t *actor) INT32 locvar2 = var2 & 0x0000FFFF; INT32 aimDirect = var2 & 0xFFFF0000; - if (LUA_CallAction("A_BrakLobShot", actor)) + if (LUA_CallAction(A_BRAKLOBSHOT, actor)) return; if (!actor->target) @@ -10923,7 +10923,7 @@ void A_NapalmScatter(mobj_t *actor) INT32 i; // for-loop cursor mobj_t *mo; // each and every spawned napalm burst - if (LUA_CallAction("A_NapalmScatter", actor)) + if (LUA_CallAction(A_NAPALMSCATTER, actor)) return; // Some quick sanity-checking @@ -10975,7 +10975,7 @@ void A_SpawnFreshCopy(mobj_t *actor) { mobj_t *newObject; - if (LUA_CallAction("A_SpawnFreshCopy", actor)) + if (LUA_CallAction(A_SPAWNFRESHCOPY, actor)) return; newObject = P_SpawnMobj(actor->x, actor->y, actor->z, actor->type); diff --git a/src/p_floor.c b/src/p_floor.c index 27460eda6..bebc9a272 100644 --- a/src/p_floor.c +++ b/src/p_floor.c @@ -1968,32 +1968,8 @@ void T_ThwompSector(levelspecthink_t *thwomp) } else // Not going anywhere, so look for players. { - //thinker_t *th; - //mobj_t *mo; - thwomp->direction = -1; - /* // SRB2kart 170217 - Thwomps are automatic. - // scan the thinkers to find players! - if (!rover || (rover->flags & FF_EXISTS)) - { - // scan the thinkers to find players! - for (th = thinkercap.next; th != &thinkercap; th = th->next) - { - if (th->function.acp1 != (actionf_p1)P_MobjThinker) - continue; - - mo = (mobj_t *)th; - if (mo->type == MT_PLAYER && mo->health && mo->player && !mo->player->spectator - && mo->z <= thwomp->sector->ceilingheight - && P_AproxDistance(thwompx - mo->x, thwompy - mo->y) <= 96*FRACUNIT) - { - thwomp->direction = -1; - break; - } - } - }*/ - thwomp->sector->ceilspeed = 0; thwomp->sector->floorspeed = 0; } diff --git a/src/p_inter.c b/src/p_inter.c index 14c712033..9d00822f3 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -17,6 +17,7 @@ #include "g_game.h" #include "m_random.h" #include "p_local.h" +#include "p_setup.h" #include "s_sound.h" #include "r_main.h" #include "st_stuff.h" @@ -253,26 +254,21 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) if (heightcheck) { - /*if (special->type == MT_FLINGEMERALD) // little hack here... - { // flingemerald sprites are low to the ground, so extend collision radius down some. - if (toucher->z > (special->z + special->height)) - return; - if (special->z - special->height > (toucher->z + toucher->height)) - return; - } - else*/ + if (toucher->momz < 0) { - if (toucher->momz < 0) { - if (toucher->z + toucher->momz > special->z + special->height) - return; - } else if (toucher->z > special->z + special->height) - return; - if (toucher->momz > 0) { - if (toucher->z + toucher->height + toucher->momz < special->z) - return; - } else if (toucher->z + toucher->height < special->z) + if (toucher->z + toucher->momz > special->z + special->height) return; } + else if (toucher->z > special->z + special->height) + return; + + if (toucher->momz > 0) + { + if (toucher->z + toucher->height + toucher->momz < special->z) + return; + } + else if (toucher->z + toucher->height < special->z) + return; } if (special->health <= 0) @@ -383,16 +379,8 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) player->kartstuff[k_roulettetype] = 2; } -#if 0 - // Eggbox snipe! - if (special->type == MT_EGGMANITEM && special->health > 1) - S_StartSound(toucher, sfx_bsnipe); -#endif - - { - mobj_t *poof = P_SpawnMobj(special->x, special->y, special->z, MT_EXPLODE); - S_StartSound(poof, special->info->deathsound); - } + mobj_t *poof = P_SpawnMobj(special->x, special->y, special->z, MT_EXPLODE); + S_StartSound(poof, special->info->deathsound); if (special->target && special->target->player) { @@ -475,8 +463,8 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) } else if (special->target->player->kartstuff[k_comebackmode] == 1 && P_CanPickupItem(player, 1)) { - mobj_t *poof = P_SpawnMobj(special->x, special->y, special->z, MT_EXPLODE); - S_StartSound(poof, special->info->seesound); + mobj_t *poof2 = P_SpawnMobj(special->x, special->y, special->z, MT_EXPLODE); + S_StartSound(poof2, special->info->seesound); // Karma fireworks for (i = 0; i < 5; i++) @@ -502,10 +490,10 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) } else if (special->target->player->kartstuff[k_comebackmode] == 2 && P_CanPickupItem(player, 2)) { - mobj_t *poof = P_SpawnMobj(special->x, special->y, special->z, MT_EXPLODE); + mobj_t *poof3 = P_SpawnMobj(special->x, special->y, special->z, MT_EXPLODE); UINT8 ptadd = 1; // No WANTED bonus for tricking - S_StartSound(poof, special->info->seesound); + S_StartSound(poof3, special->info->seesound); if (player->kartstuff[k_bumper] == 1) // If you have only one bumper left, and see if it's a 1v1 { @@ -583,10 +571,6 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) else K_SpinPlayer(player, special->target, 0, special, false); return; - /*case MT_EERIEFOG: - special->frame &= ~FF_TRANS80; - special->frame |= FF_TRANS90; - return;*/ case MT_SMK_MOLE: if (special->target && !P_MobjWasRemoved(special->target)) return; @@ -935,12 +919,6 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) player->flyangle = special->threshold; player->speed = FixedMul(special->info->speed, special->scale); - // Potentially causes axis transfer failures. - // Also rarely worked properly anyway. - //P_UnsetThingPosition(player->mo); - //player->mo->x = special->x; - //player->mo->y = special->y; - //P_SetThingPosition(player->mo); toucher->z = special->z+(special->height/4); } else // More like a spring @@ -985,140 +963,6 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) } } return; - /*case MT_NIGHTSSUPERLOOP: - if (player->bot || !(player->pflags & PF_NIGHTSMODE)) - return; - if (!G_IsSpecialStage(gamemap)) - player->powers[pw_nights_superloop] = (UINT16)special->info->speed; - else - { - for (i = 0; i < MAXPLAYERS; i++) - if (playeringame[i] && players[i].pflags & PF_NIGHTSMODE) - players[i].powers[pw_nights_superloop] = (UINT16)special->info->speed; - if (special->info->deathsound != sfx_None) - S_StartSound(NULL, special->info->deathsound); - } - - // CECHO showing you what this item is - if (player == &players[displayplayers[0]] || G_IsSpecialStage(gamemap)) - { - HU_SetCEchoFlags(V_AUTOFADEOUT); - HU_SetCEchoDuration(4); - HU_DoCEcho(M_GetText("\\\\\\\\\\\\\\\\Super Paraloop")); - } - break; - case MT_NIGHTSDRILLREFILL: - if (player->bot || !(player->pflags & PF_NIGHTSMODE)) - return; - if (!G_IsSpecialStage(gamemap)) - player->drillmeter = special->info->speed; - else - { - for (i = 0; i < MAXPLAYERS; i++) - if (playeringame[i] && players[i].pflags & PF_NIGHTSMODE) - players[i].drillmeter = special->info->speed; - if (special->info->deathsound != sfx_None) - S_StartSound(NULL, special->info->deathsound); - } - - // CECHO showing you what this item is - if (player == &players[displayplayers[0]] || G_IsSpecialStage(gamemap)) - { - HU_SetCEchoFlags(V_AUTOFADEOUT); - HU_SetCEchoDuration(4); - HU_DoCEcho(M_GetText("\\\\\\\\\\\\\\\\Drill Refill")); - } - break; - case MT_NIGHTSHELPER: - if (player->bot || !(player->pflags & PF_NIGHTSMODE)) - return; - if (!G_IsSpecialStage(gamemap)) - { - // A flicky orbits us now - mobj_t *flickyobj = P_SpawnMobj(toucher->x, toucher->y, toucher->z + toucher->info->height, MT_NIGHTOPIANHELPER); - P_SetTarget(&flickyobj->target, toucher); - - player->powers[pw_nights_helper] = (UINT16)special->info->speed; - } - else - { - mobj_t *flickyobj; - for (i = 0; i < MAXPLAYERS; i++) - if (playeringame[i] && players[i].mo && players[i].pflags & PF_NIGHTSMODE) { - players[i].powers[pw_nights_helper] = (UINT16)special->info->speed; - flickyobj = P_SpawnMobj(players[i].mo->x, players[i].mo->y, players[i].mo->z + players[i].mo->info->height, MT_NIGHTOPIANHELPER); - P_SetTarget(&flickyobj->target, players[i].mo); - } - if (special->info->deathsound != sfx_None) - S_StartSound(NULL, special->info->deathsound); - } - - // CECHO showing you what this item is - if (player == &players[displayplayers[0]] || G_IsSpecialStage(gamemap)) - { - HU_SetCEchoFlags(V_AUTOFADEOUT); - HU_SetCEchoDuration(4); - HU_DoCEcho(M_GetText("\\\\\\\\\\\\\\\\Nightopian Helper")); - } - break; - case MT_NIGHTSEXTRATIME: - if (player->bot || !(player->pflags & PF_NIGHTSMODE)) - return; - if (!G_IsSpecialStage(gamemap)) - { - player->nightstime += special->info->speed; - player->startedtime += special->info->speed; - P_RestoreMusic(player); - } - else - { - for (i = 0; i < MAXPLAYERS; i++) - if (playeringame[i] && players[i].pflags & PF_NIGHTSMODE) - { - players[i].nightstime += special->info->speed; - players[i].startedtime += special->info->speed; - P_RestoreMusic(&players[i]); - } - if (special->info->deathsound != sfx_None) - S_StartSound(NULL, special->info->deathsound); - } - - // CECHO showing you what this item is - if (player == &players[displayplayers[0]] || G_IsSpecialStage(gamemap)) - { - HU_SetCEchoFlags(V_AUTOFADEOUT); - HU_SetCEchoDuration(4); - HU_DoCEcho(M_GetText("\\\\\\\\\\\\\\\\Extra Time")); - } - break; - case MT_NIGHTSLINKFREEZE: - if (player->bot || !(player->pflags & PF_NIGHTSMODE)) - return; - if (!G_IsSpecialStage(gamemap)) - { - player->powers[pw_nights_linkfreeze] = (UINT16)special->info->speed; - player->linktimer = 2*TICRATE; - } - else - { - for (i = 0; i < MAXPLAYERS; i++) - if (playeringame[i] && players[i].pflags & PF_NIGHTSMODE) - { - players[i].powers[pw_nights_linkfreeze] += (UINT16)special->info->speed; - players[i].linktimer = 2*TICRATE; - } - if (special->info->deathsound != sfx_None) - S_StartSound(NULL, special->info->deathsound); - } - - // CECHO showing you what this item is - if (player == &players[displayplayers[0]] || G_IsSpecialStage(gamemap)) - { - HU_SetCEchoFlags(V_AUTOFADEOUT); - HU_SetCEchoDuration(4); - HU_DoCEcho(M_GetText("\\\\\\\\\\\\\\\\Link Freeze")); - } - break;*/ case MT_NIGHTSWING: if (G_IsSpecialStage(gamemap) && useNightsSS) { // Pseudo-ring. @@ -1132,7 +976,9 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) break; case MT_HOOPCOLLIDE: // This produces a kind of 'domino effect' with the hoop's pieces. - for (; special->hprev != NULL; special = special->hprev); // Move to the first sprite in the hoop + if (!midgamejoin) + for (; special->hprev != NULL; special = special->hprev); // Move to the first sprite in the hoop + i = 0; for (; special->type == MT_HOOP; special = special->hnext) { @@ -1464,7 +1310,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) } else { - P_PlayRinglossSound(toucher); + P_PlayRinglossSound(toucher, NULL); if (toucher->health > 10) toucher->health -= 10; else @@ -1510,23 +1356,6 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) || special->z > toucher->z + (toucher->height*2/3)) return; // Only go in the mouth - /* // SRB2kart - Can't drown. - // Eaten by player! - if (player->powers[pw_underwater] && player->powers[pw_underwater] <= 12*TICRATE + 1) - P_RestoreMusic(player); - - if (player->powers[pw_underwater] < underwatertics + 1) - player->powers[pw_underwater] = underwatertics + 1; - */ - - /* - if (!player->climbing) - { - P_SetPlayerMobjState(toucher, S_PLAY_GASP); - P_ResetPlayer(player); - } - */ - toucher->momx = toucher->momy = toucher->momz = 0; break; @@ -1583,26 +1412,7 @@ void P_CheckTimeLimit(void) if (gameaction == ga_completed) return; - //Tagmode round end but only on the tic before the - //XD_EXITLEVEL packet is received by all players. - /*if (G_TagGametype()) - { - if (leveltime == (timelimitintics + 1)) - { - for (i = 0; i < MAXPLAYERS; i++) - { - if (!playeringame[i] || players[i].spectator - || (players[i].pflags & PF_TAGGED) || (players[i].pflags & PF_TAGIT)) - continue; - - CONS_Printf(M_GetText("%s received double points for surviving the round.\n"), player_names[i]); - P_AddPlayerScore(&players[i], players[i].score); - } - } - } - - //Optional tie-breaker for Match/CTF - else*/ if (cv_overtime.value) + if (cv_overtime.value) { INT32 playerarray[MAXPLAYERS]; INT32 tempplayer = 0; @@ -1675,9 +1485,6 @@ void P_CheckTimeLimit(void) return; P_DoPlayerExit(&players[i]); } - - /*if (server) - SendNetXCmd(XD_EXITLEVEL, NULL, 0);*/ } /** Checks if a player's score is over the pointlimit and the round should end. @@ -1699,127 +1506,27 @@ void P_CheckPointLimit(void) if (G_RaceGametype()) return; - // pointlimit is nonzero, check if it's been reached by this player - /*if (G_GametypeHasTeams()) + for (i = 0; i < MAXPLAYERS; i++) { - // Just check both teams - if ((UINT32)cv_pointlimit.value <= redscore || (UINT32)cv_pointlimit.value <= bluescore) - { - if (server) - SendNetXCmd(XD_EXITLEVEL, NULL, 0); - } - } - else*/ - { - for (i = 0; i < MAXPLAYERS; i++) - { - if (!playeringame[i] || players[i].spectator) - continue; + if (!playeringame[i] || players[i].spectator) + continue; - if ((UINT32)cv_pointlimit.value <= players[i].marescore) + if ((UINT32)cv_pointlimit.value <= players[i].marescore) + { + for (i = 0; i < MAXPLAYERS; i++) // AAAAA nested loop using the same iteration variable ;; { - for (i = 0; i < MAXPLAYERS; i++) // AAAAA nested loop using the same iteration variable ;; - { - if (!playeringame[i] || players[i].spectator) - continue; - if (players[i].exiting) - return; - P_DoPlayerExit(&players[i]); - } - - /*if (server) - SendNetXCmd(XD_EXITLEVEL, NULL, 0);*/ - return; // good thing we're leaving the function immediately instead of letting the loop get mangled! + if (!playeringame[i] || players[i].spectator) + continue; + if (players[i].exiting) + return; + P_DoPlayerExit(&players[i]); } + + return; // good thing we're leaving the function immediately instead of letting the loop get mangled! } } } -/*Checks for untagged remaining players in both tag derivitave modes. - *If no untagged players remain, end the round. - *Also serves as error checking if the only IT player leaves.*/ -/*void P_CheckSurvivors(void) -{ - INT32 i; - INT32 survivors = 0; - INT32 taggers = 0; - INT32 spectators = 0; - INT32 survivorarray[MAXPLAYERS]; - - if (!D_NumPlayers()) //no players in the game, no check performed. - return; - - for (i=0; i < MAXPLAYERS; i++) //figure out counts of taggers, survivors and spectators. - { - if (playeringame[i]) - { - if (players[i].spectator) - spectators++; - else if (players[i].pflags & PF_TAGIT) - taggers++; - else if (!(players[i].pflags & PF_TAGGED)) - { - survivorarray[survivors] = i; - survivors++; - } - } - } - - if (!taggers) //If there are no taggers, pick a survivor at random to be it. - { - // Exception for hide and seek. If a round has started and the IT player leaves, end the round. - if (gametype == GT_HIDEANDSEEK && (leveltime >= (hidetime * TICRATE))) - { - CONS_Printf(M_GetText("The IT player has left the game.\n")); - if (server) - SendNetXCmd(XD_EXITLEVEL, NULL, 0); - - return; - } - - if (survivors) - { - INT32 newtagger = survivorarray[P_RandomKey(survivors)]; - - CONS_Printf(M_GetText("%s is now IT!\n"), player_names[newtagger]); // Tell everyone who is it! - players[newtagger].pflags |= PF_TAGIT; - - survivors--; //Get rid of the guy we just made IT. - - //Yeah, we have an eligible tagger, but we may not have anybody for him to tag! - //If there is only one guy waiting on the game to fill or spectators to enter game, don't bother. - if (!survivors && (D_NumPlayers() - spectators) > 1) - { - CONS_Printf(M_GetText("All players have been tagged!\n")); - if (server) - SendNetXCmd(XD_EXITLEVEL, NULL, 0); - } - - return; - } - - //If we reach this point, no player can replace the one that was IT. - //Unless it is one player waiting on a game, end the round. - if ((D_NumPlayers() - spectators) > 1) - { - CONS_Printf(M_GetText("There are no players able to become IT.\n")); - if (server) - SendNetXCmd(XD_EXITLEVEL, NULL, 0); - } - - return; - } - - //If there are taggers, but no survivors, end the round. - //Except when the tagger is by himself and the rest of the game are spectators. - if (!survivors && (D_NumPlayers() - spectators) > 1) - { - CONS_Printf(M_GetText("All players have been tagged!\n")); - if (server) - SendNetXCmd(XD_EXITLEVEL, NULL, 0); - } -}*/ - // Checks whether or not to end a race netgame. boolean P_CheckRacers(void) { @@ -1908,9 +1615,6 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source) mobj_t *mo; int ms; - //if (inflictor && (inflictor->type == MT_SHELL || inflictor->type == MT_FIREBALL)) - // P_SetTarget(&target->tracer, inflictor); - if (!useNightsSS && G_IsSpecialStage(gamemap) && target->player && sstimer > 6) sstimer = 6; // Just let P_Ticker take care of the rest. @@ -1959,7 +1663,7 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source) K_KillBananaChain(target->target->hnext, inflictor, source); target->target->player->kartstuff[k_itemamount] = 0; } - else + else if (target->target->player->kartstuff[k_itemamount]) target->target->player->kartstuff[k_itemamount]--; } else if ((target->type == MT_ORBINAUT_SHIELD && target->target->player->kartstuff[k_itemtype] == KITEM_ORBINAUT) // orbit items @@ -1991,14 +1695,6 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source) { if (metalrecording) // Ack! Metal Sonic shouldn't die! Cut the tape, end recording! G_StopMetalRecording(); - /*if (gametype == GT_MATCH && cv_match_scoring.value == 0 // note, no team match suicide penalty - && ((target == source) || (source == NULL && inflictor == NULL) || (source && !source->player))) - { // Suicide penalty - Not in Kart - if (target->player->score >= 50) - target->player->score -= 50; - else - target->player->score = 0; - }*/ target->flags2 &= ~MF2_DONTDRAW; } @@ -2015,85 +1711,6 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source) target->fuse = cv_itemrespawntime.value*TICRATE + 2; // Random box generation } } - - // Award Score Tails - /*{ // Enemies shouldn't award points in Kart - INT32 score = 0; - - if (maptol & TOL_NIGHTS) // Enemies always worth 200, bosses don't do anything. - { - if ((target->flags & MF_ENEMY) && !(target->flags & (MF_MISSILE|MF_BOSS))) - { - score = 200; - - if (source->player->bonustime) - score *= 2; - - // Also, add to the link. - // I don't know if NiGHTS did this, but - // Sonic Time Attacked did and it seems like a good enough incentive - // to make people want to actually dash towards/paraloop enemies - if (++source->player->linkcount > source->player->maxlink) - source->player->maxlink = source->player->linkcount; - source->player->linktimer = 2*TICRATE; - } - } - else - { - if (target->flags & MF_BOSS) - score = 1000; - else if ((target->flags & MF_ENEMY) && !(target->flags & MF_MISSILE)) - { - mobj_t *scoremobj; - UINT32 scorestate = mobjinfo[MT_SCORE].spawnstate; - - scoremobj = P_SpawnMobj(target->x, target->y, target->z + (target->height / 2), MT_SCORE); - - // On ground? No chain starts. - if (!source->player->powers[pw_invulnerability] && P_IsObjectOnGround(source)) - { - source->player->scoreadd = 0; - score = 100; - } - // Mario Mode has Mario-like chain point values - else if (mariomode) switch (++source->player->scoreadd) - { - case 1: score = 100; break; - case 2: score = 200; scorestate += 1; break; - case 3: score = 400; scorestate += 5; break; - case 4: score = 800; scorestate += 6; break; - case 5: score = 1000; scorestate += 3; break; - case 6: score = 2000; scorestate += 7; break; - case 7: score = 4000; scorestate += 8; break; - case 8: score = 8000; scorestate += 9; break; - default: // 1up for a chain this long - if (modeattacking) // but 1ups don't exist in record attack! - { // So we just go back to 10k points. - score = 10000; scorestate += 4; break; - } - P_GivePlayerLives(source->player, 1); - P_PlayLivesJingle(source->player); - scorestate += 10; - break; - } - // More Sonic-like point system - else switch (++source->player->scoreadd) - { - case 1: score = 100; break; - case 2: score = 200; scorestate += 1; break; - case 3: score = 500; scorestate += 2; break; - case 4: case 5: case 6: case 7: case 8: case 9: - case 10: case 11: case 12: case 13: case 14: - score = 1000; scorestate += 3; break; - default: score = 10000; scorestate += 4; break; - } - - P_SetMobjState(scoremobj, scorestate); - } - } - - P_AddPlayerScore(source->player, score); - }*/ } // if a player avatar dies... @@ -2120,7 +1737,7 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source) } target->player->playerstate = PST_DEAD; - if (cv_fading.value && cv_birdmusic.value && P_IsLocalPlayer(target->player)) + if (cv_birdmusic.value && cv_fading.value && P_IsLocalPlayer(target->player)) { if (netgame || multiplayer) ms = cv_respawntime.value * 1000; @@ -2131,7 +1748,7 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source) If the time spent with the music paused is less than half a second, continue playing the song (just mute it). */ - if (( ms - cv_respawnfademusicout.value ) < 500) + if ((ms - cv_respawnfademusicout.value) < 500) S_FadeMusic(0, cv_respawnfademusicout.value); else S_FadeOutStopMusic(cv_respawnfademusicout.value); @@ -2157,42 +1774,7 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source) if (target->player == &players[displayplayers[3]]) localaiming[3] = 0; - //tag deaths handled differently in suicide cases. Don't count spectators! - /*if (G_TagGametype() - && !(target->player->pflags & PF_TAGIT) && (!source || !source->player) && !(target->player->spectator)) - { - // if you accidentally die before you run out of time to hide, ignore it. - // allow them to try again, rather than sitting the whole thing out. - if (leveltime >= hidetime * TICRATE) - { - if (gametype == GT_TAG)//suiciding in survivor makes you IT. - { - target->player->pflags |= PF_TAGIT; - CONS_Printf(M_GetText("%s is now IT!\n"), player_names[target->player-players]); // Tell everyone who is it! - P_CheckSurvivors(); - } - else - { - if (!(target->player->pflags & PF_TAGGED)) - { - //otherwise, increment the tagger's score. - //in hide and seek, suiciding players are counted as found. - INT32 w; - - for (w=0; w < MAXPLAYERS; w++) - { - if (players[w].pflags & PF_TAGIT) - P_AddPlayerScore(&players[w], 1); - } - - target->player->pflags |= PF_TAGGED; - CONS_Printf(M_GetText("%s was found!\n"), player_names[target->player-players]); - P_CheckSurvivors(); - } - } - } - } - else*/ if (G_BattleGametype()) + if (G_BattleGametype()) K_CheckBumpers(); target->player->kartstuff[k_pogospring] = 0; @@ -2607,26 +2189,6 @@ static inline boolean P_TagDamage(mobj_t *target, mobj_t *inflictor, mobj_t *sou return false; } - // The tag occurs so long as you aren't shooting another tagger with friendlyfire on. - /*if (source->player->pflags & PF_TAGIT && !(player->pflags & PF_TAGIT)) - { - P_AddPlayerScore(source->player, 1); //award points to tagger. - - if (gametype == GT_TAG) //survivor - { - player->pflags |= PF_TAGIT; //in survivor, the player becomes IT and helps hunt down the survivors. - CONS_Printf(M_GetText("%s is now IT!\n"), player_names[player-players]); // Tell everyone who is it! - } - else - { - player->pflags |= PF_TAGGED; //in hide and seek, the player is tagged and stays stationary. - CONS_Printf(M_GetText("%s was found!\n"), player_names[player-players]); // Tell everyone who is it! - } - - //checks if tagger has tagged all players, if so, end round early. - P_CheckSurvivors(); - }*/ - P_DoPlayerPain(player, source, inflictor); // Check for a shield @@ -2644,7 +2206,7 @@ static inline boolean P_TagDamage(mobj_t *target, mobj_t *inflictor, mobj_t *sou } else if (target->health > 1) // Ring loss { - P_PlayRinglossSound(target); + P_PlayRinglossSound(target, source); P_PlayerRingBurst(player, player->mo->health - 1); } @@ -2665,15 +2227,6 @@ static inline boolean P_PlayerHitsPlayer(mobj_t *target, mobj_t *inflictor, mobj { player_t *player = target->player; - // You can't kill yourself, idiot... // Unless it's Mario kart. Which it is. In this mod. All the time. - //if (source == target) - // return false; - - // In COOP/RACE/CHAOS, you can't hurt other players unless cv_friendlyfire is on - // ...But in SRB2kart, you can! - //if (!cv_friendlyfire.value && (G_RaceGametype())) - // return false; - // Tag handling if (G_TagGametype()) return P_TagDamage(target, inflictor, source, damage); @@ -2725,32 +2278,6 @@ static void P_KillPlayer(player_t *player, mobj_t *source, INT32 damage) P_SetPlayerMobjState(player->mo, player->mo->info->deathstate); - /*if (gametype == GT_CTF && (player->gotflag & (GF_REDFLAG|GF_BLUEFLAG))) - { - P_PlayerFlagBurst(player, false); - if (source && source->player) - { - // Award no points when players shoot each other when cv_friendlyfire is on. - if (!G_GametypeHasTeams() || !(source->player->ctfteam == player->ctfteam && source != player->mo)) - P_AddPlayerScore(source->player, 1); - } - } - if (source && source->player && !player->powers[pw_super]) //don't score points against super players - { - // Award no points when players shoot each other when cv_friendlyfire is on. - if (!G_GametypeHasTeams() || !(source->player->ctfteam == player->ctfteam && source != player->mo)) - P_AddPlayerScore(source->player, 1); - } - - // If the player was super, tell them he/she ain't so super nomore. - if (gametype != GT_COOP && player->powers[pw_super]) - { - S_StartSound(NULL, sfx_s3k66); //let all players hear it. - HU_SetCEchoFlags(0); - HU_SetCEchoDuration(5); - HU_DoCEcho(va("%s\\is no longer super.\\\\\\\\", player_names[player-players])); - }*/ - if (player->pflags & PF_TIMEOVER) { mobj_t *boom; @@ -2811,44 +2338,8 @@ void P_RemoveShield(player_t *player) player->powers[pw_shield] = player->powers[pw_shield] & SH_STACK; } -/* -static void P_ShieldDamage(player_t *player, mobj_t *inflictor, mobj_t *source, INT32 damage) // SRB2kart - unused. -{ - // Must do pain first to set flashing -- P_RemoveShield can cause damage - P_DoPlayerPain(player, source, inflictor); - - P_RemoveShield(player); - - P_ForceFeed(player, 40, 10, TICRATE, 40 + min(damage, 100)*2); - - if (source && (source->type == MT_SPIKE || (source->type == MT_NULL && source->threshold == 43))) // spikes - S_StartSound(player->mo, sfx_spkdth); - else - S_StartSound (player->mo, sfx_shldls); // Ba-Dum! Shield loss. - - if (gametype == GT_CTF && (player->gotflag & (GF_REDFLAG|GF_BLUEFLAG))) - { - P_PlayerFlagBurst(player, false); - if (source && source->player) - { - // Award no points when players shoot each other when cv_friendlyfire is on. - if (!G_GametypeHasTeams() || !(source->player->ctfteam == player->ctfteam && source != player->mo)) - P_AddPlayerScore(source->player, 25); - } - } - if (source && source->player && !player->powers[pw_super]) //don't score points against super players - { - // Award no points when players shoot each other when cv_friendlyfire is on. - if (!G_GametypeHasTeams() || !(source->player->ctfteam == player->ctfteam && source != player->mo)) - P_AddPlayerScore(source->player, cv_match_scoring.value == 1 ? 25 : 50); - } -} -*/ - static void P_RingDamage(player_t *player, mobj_t *inflictor, mobj_t *source, INT32 damage) { - //const UINT8 scoremultiply = ((K_IsWantedPlayer(player) && !trapitem) : 2 ? 1); - if (!(inflictor && ((inflictor->flags & MF_MISSILE) || inflictor->player) && player->powers[pw_super] && ALL7EMERALDS(player->powers[pw_emeralds]))) { P_DoPlayerPain(player, source, inflictor); @@ -2859,26 +2350,8 @@ static void P_RingDamage(player_t *player, mobj_t *inflictor, mobj_t *source, IN S_StartSound(player->mo, sfx_spkdth); } - /*if (source && source->player && !player->powers[pw_super]) //don't score points against super players - { - // Award no points when players shoot each other when cv_friendlyfire is on. - if (!G_GametypeHasTeams() || !(source->player->ctfteam == player->ctfteam && source != player->mo)) - P_AddPlayerScore(source->player, scoremultiply); - } - - if (gametype == GT_CTF && (player->gotflag & (GF_REDFLAG|GF_BLUEFLAG))) - { - P_PlayerFlagBurst(player, false); - if (source && source->player) - { - // Award no points when players shoot each other when cv_friendlyfire is on. - if (!G_GametypeHasTeams() || !(source->player->ctfteam == player->ctfteam && source != player->mo)) - P_AddPlayerScore(source->player, scoremultiply); - } - }*/ - // Ring loss sound plays despite hitting spikes - P_PlayRinglossSound(player->mo); // Ringledingle! + P_PlayRinglossSound(player->mo, source); // Ringledingle! } /** Damages an object, which may or may not be a player. @@ -3676,32 +3149,30 @@ void P_PlayerFlagBurst(player_t *player, boolean toss) P_SetTarget(&flag->target, player->mo); // Flag text + char plname[MAXPLAYERNAME+4]; + const char *flagtext; + char flagcolor; + + snprintf(plname, sizeof(plname), "%s%s%s", + CTFTEAMCODE(player), + player_names[player - players], + CTFTEAMENDCODE(player)); + + if (type == MT_REDFLAG) { - char plname[MAXPLAYERNAME+4]; - const char *flagtext; - char flagcolor; - - snprintf(plname, sizeof(plname), "%s%s%s", - CTFTEAMCODE(player), - player_names[player - players], - CTFTEAMENDCODE(player)); - - if (type == MT_REDFLAG) - { - flagtext = M_GetText("Red flag"); - flagcolor = '\x85'; - } - else - { - flagtext = M_GetText("Blue flag"); - flagcolor = '\x84'; - } - - if (toss) - CONS_Printf(M_GetText("%s tossed the %c%s%c.\n"), plname, flagcolor, flagtext, 0x80); - else - CONS_Printf(M_GetText("%s dropped the %c%s%c.\n"), plname, flagcolor, flagtext, 0x80); + flagtext = M_GetText("Red flag"); + flagcolor = '\x85'; } + else + { + flagtext = M_GetText("Blue flag"); + flagcolor = '\x84'; + } + + if (toss) + CONS_Printf(M_GetText("%s tossed the %c%s%c.\n"), plname, flagcolor, flagtext, 0x80); + else + CONS_Printf(M_GetText("%s dropped the %c%s%c.\n"), plname, flagcolor, flagtext, 0x80); player->gotflag = 0; diff --git a/src/p_local.h b/src/p_local.h index e1a07526a..0193ec09d 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -70,6 +70,7 @@ extern thinker_t thinkercap; void P_InitThinkers(void); void P_AddThinker(thinker_t *thinker); void P_RemoveThinker(thinker_t *thinker); +void P_UnlinkThinker(thinker_t *thinker); // // P_USER @@ -143,6 +144,8 @@ extern consvar_t cv_tiltsmoothing; extern consvar_t cv_actionmovie; +extern consvar_t cv_lookbackmom; + extern fixed_t t_cam_dist, t_cam_height, t_cam_rotate; extern fixed_t t_cam2_dist, t_cam2_height, t_cam2_rotate; extern fixed_t t_cam3_dist, t_cam3_height, t_cam3_rotate; @@ -215,7 +218,7 @@ boolean P_PlayerMoving(INT32 pnum); void P_Telekinesis(player_t *player, fixed_t thrust, fixed_t range); void P_PlayLivesJingle(player_t *player); -void P_PlayRinglossSound(mobj_t *source); +void P_PlayRinglossSound(mobj_t *source, mobj_t *damager); void P_PlayDeathSound(mobj_t *source); void P_PlayVictorySound(mobj_t *source); @@ -245,7 +248,7 @@ void P_RecalcPrecipInSector(sector_t *sector); void P_PrecipitationEffects(void); void P_RemoveMobj(mobj_t *th); -boolean P_MobjWasRemoved(mobj_t *th); +boolean P_MobjWasRemoved(const mobj_t *th); void P_RemoveSavegameMobj(mobj_t *th); boolean P_SetPlayerMobjState(mobj_t *mobj, statenum_t state); boolean P_SetMobjState(mobj_t *mobj, statenum_t state); @@ -288,7 +291,7 @@ mobj_t *P_SPMAngle(mobj_t *source, mobjtype_t type, angle_t angle, UINT8 aimtype #define P_SpawnNameFinder(s,t) P_SPMAngle(s,t,s->angle,true,0) #endif void P_ColorTeamMissile(mobj_t *missile, player_t *source); -SINT8 P_MobjFlip(mobj_t *mobj); +SINT8 P_MobjFlip(const mobj_t *mobj); fixed_t P_GetMobjGravity(mobj_t *mo); FUNCMATH boolean P_WeaponOrPanel(mobjtype_t type); diff --git a/src/p_map.c b/src/p_map.c index 6051d5d1c..bd551829d 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -319,78 +319,6 @@ static void P_DoFanAndGasJet(mobj_t *spring, mobj_t *object) } } -#if 0 -static void P_DoTailsCarry(player_t *sonic, player_t *tails) -{ - INT32 p; - fixed_t zdist; // z distance between the two players' bottoms - - if ((tails->pflags & PF_CARRIED) && tails->mo->tracer == sonic->mo) - return; - if ((sonic->pflags & PF_CARRIED) && sonic->mo->tracer == tails->mo) - return; - if (tails->bot == 1) - return; - - if (sonic->pflags & PF_NIGHTSMODE) - return; - - if (sonic->mo->tracer && sonic->mo->tracer->type == MT_TUBEWAYPOINT - && !(sonic->pflags & PF_ROPEHANG)) - return; // don't steal players from zoomtubes! - - if ((sonic->mo->eflags & MFE_VERTICALFLIP) != (tails->mo->eflags & MFE_VERTICALFLIP)) - return; // Both should be in same gravity - - if (tails->mo->eflags & MFE_VERTICALFLIP) - { - if (tails->mo->ceilingz - (tails->mo->z + tails->mo->height) < sonic->mo->height-FixedMul(2*FRACUNIT, sonic->mo->scale)) - return; - } - else if (tails->mo->z - tails->mo->floorz < sonic->mo->height-FixedMul(2*FRACUNIT, sonic->mo->scale)) - return; // No room to pick up this guy! - - // Search in case another player is already being carried by this fox. - for (p = 0; p < MAXPLAYERS; p++) - if (playeringame[p] && players[p].mo - && players[p].pflags & PF_CARRIED && players[p].mo->tracer == tails->mo) - return; - - if (tails->mo->eflags & MFE_VERTICALFLIP) - zdist = (sonic->mo->z + sonic->mo->height) - (tails->mo->z + tails->mo->height); - else - zdist = tails->mo->z - sonic->mo->z; - - if (zdist <= sonic->mo->height + FixedMul(FRACUNIT, sonic->mo->scale) - && zdist > sonic->mo->height*2/3 - && P_MobjFlip(tails->mo)*sonic->mo->momz <= 0) - { - // Why block opposing teams from tailsflying each other? - // Sneaking into the hands of a flying tails player in Race might be a viable strategy, who knows. - if (tails->spectator || sonic->spectator || G_RaceGametype()) // SRB2kart - sonic->pflags &= ~PF_CARRIED; - else - { - if (sonic-players == consoleplayer && botingame) - //CV_SetValue(&cv_analog2, false); - P_ResetPlayer(sonic); - P_SetTarget(&sonic->mo->tracer, tails->mo); - sonic->pflags |= PF_CARRIED; - S_StartSound(sonic->mo, sfx_s3k4a); - P_UnsetThingPosition(sonic->mo); - sonic->mo->x = tails->mo->x; - sonic->mo->y = tails->mo->y; - P_SetThingPosition(sonic->mo); - } - } - else { - if (sonic-players == consoleplayer && botingame) - //CV_SetValue(&cv_analog2, true); - sonic->pflags &= ~PF_CARRIED; - } -} -#endif - // // PIT_CheckThing // @@ -588,9 +516,6 @@ static boolean PIT_CheckThing(mobj_t *thing) // check for skulls slamming into things if (tmthing->flags2 & MF2_SKULLFLY) { - /*if (tmthing->type == MT_EGGMOBILE) // Don't make Eggman stop! - return true; // Let him RUN YOU RIGHT OVER. >:3 - else*/ { // see if it went over / under if (tmthing->z > thing->z + thing->height) @@ -1676,7 +1601,7 @@ static boolean PIT_CheckLine(line_t *ld) if (P_BoxOnLineSide(tmbbox, ld) != -1) return true; -if (tmthing->flags & MF_PAPERCOLLISION) // Caution! Turning whilst up against a wall will get you stuck. You probably shouldn't give the player this flag. + if (tmthing->flags & MF_PAPERCOLLISION) // Caution! Turning whilst up against a wall will get you stuck. You probably shouldn't give the player this flag. { fixed_t cosradius, sinradius; cosradius = FixedMul(tmthing->radius, FINECOSINE(tmthing->angle>>ANGLETOFINESHIFT)); @@ -2245,6 +2170,9 @@ boolean P_TryCameraMove(fixed_t x, fixed_t y, camera_t *thiscam) floatok = false; + if (dedicated) // this crashes so don't even try it + return false; + if (twodlevel) itsatwodlevel = true; else @@ -2474,14 +2402,6 @@ boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff) else if (P_PlayerTouchingSectorSpecial(thing->player, 1, 12) || GETSECSPECIAL(R_PointInSubsector(x, y)->sector->special, 1) == 12) maxstep = 0; - - // Don't 'step up' while springing, - // Only step up "if needed". - /* // SRB2kart - don't need - if (thing->state == &states[S_PLAY_SPRING] - && P_MobjFlip(thing)*thing->momz > FixedMul(FRACUNIT, thing->scale)) - maxstep = 0; - */ } if (thing->type == MT_SKIM) @@ -4143,7 +4063,7 @@ static inline boolean PIT_GetSectors(line_t *ld) tmbbox[BOXLEFT] >= ld->bbox[BOXRIGHT] || tmbbox[BOXTOP] <= ld->bbox[BOXBOTTOM] || tmbbox[BOXBOTTOM] >= ld->bbox[BOXTOP]) - return true; + return true; if (P_BoxOnLineSide(tmbbox, ld) != -1) return true; @@ -4178,7 +4098,7 @@ static inline boolean PIT_GetPrecipSectors(line_t *ld) preciptmbbox[BOXLEFT] >= ld->bbox[BOXRIGHT] || preciptmbbox[BOXTOP] <= ld->bbox[BOXBOTTOM] || preciptmbbox[BOXBOTTOM] >= ld->bbox[BOXTOP]) - return true; + return true; if (P_BoxOnLineSide(preciptmbbox, ld) != -1) return true; diff --git a/src/p_mobj.c b/src/p_mobj.c index 608d9e821..c70f9816c 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -338,7 +338,7 @@ static boolean P_SetPrecipMobjState(precipmobj_t *mobj, statenum_t state) if (state == S_NULL) { // Remove mobj - P_RemovePrecipMobj(mobj); + P_FreePrecipMobj(mobj); return false; } st = &states[state]; @@ -356,7 +356,7 @@ static boolean P_SetPrecipMobjState(precipmobj_t *mobj, statenum_t state) // // Special utility to return +1 or -1 depending on mobj's gravity // -SINT8 P_MobjFlip(mobj_t *mobj) +SINT8 P_MobjFlip(const mobj_t *mobj) { if (mobj && mobj->eflags & MFE_VERTICALFLIP) return -1; @@ -915,16 +915,18 @@ static void P_PlayerFlip(mobj_t *mo) for (i = 0; i <= splitscreen; i++) { - if (mo->player-players == displayplayers[i]) - { - localaiming[i] = mo->player->aiming; - if (camera[i].chase) { - camera[i].aiming = InvAngle(camera[i].aiming); - camera[i].z = mo->z - camera[i].z + mo->z; - if (mo->eflags & MFE_VERTICALFLIP) - camera[i].z += FixedMul(20*FRACUNIT, mo->scale); - } - } + if (mo->player-players != displayplayers[i]) + continue; + + localaiming[i] = mo->player->aiming; + + if (!camera[i].chase) + continue; + + camera[i].aiming = InvAngle(camera[i].aiming); + camera[i].z = mo->z - camera[i].z + mo->z; + if (mo->eflags & MFE_VERTICALFLIP) + camera[i].z += FixedMul(20*FRACUNIT, mo->scale); } } } @@ -1234,67 +1236,67 @@ static void P_PushableCheckBustables(mobj_t *mo) if (!node->m_sector) break; - if (node->m_sector->ffloors) + if (!node->m_sector->ffloors) + continue; + + ffloor_t *rover; + fixed_t topheight, bottomheight; + + for (rover = node->m_sector->ffloors; rover; rover = rover->next) { - ffloor_t *rover; - fixed_t topheight, bottomheight; + if (!(rover->flags & FF_EXISTS)) continue; - for (rover = node->m_sector->ffloors; rover; rover = rover->next) + if (!(rover->flags & FF_BUSTUP)) continue; + + // Needs ML_EFFECT4 flag for pushables to break it + if (!(rover->master->flags & ML_EFFECT4)) continue; + + if (rover->master->frontsector->crumblestate) + continue; + + topheight = P_GetFOFTopZ(mo, node->m_sector, rover, mo->x, mo->y, NULL); + bottomheight = P_GetFOFBottomZ(mo, node->m_sector, rover, mo->x, mo->y, NULL); + // Height checks + if (rover->flags & FF_SHATTERBOTTOM) { - if (!(rover->flags & FF_EXISTS)) continue; + if (mo->z+mo->momz + mo->height < bottomheight) + continue; - if (!(rover->flags & FF_BUSTUP)) continue; - - // Needs ML_EFFECT4 flag for pushables to break it - if (!(rover->master->flags & ML_EFFECT4)) continue; - - if (!rover->master->frontsector->crumblestate) - { - topheight = P_GetFOFTopZ(mo, node->m_sector, rover, mo->x, mo->y, NULL); - bottomheight = P_GetFOFBottomZ(mo, node->m_sector, rover, mo->x, mo->y, NULL); - // Height checks - if (rover->flags & FF_SHATTERBOTTOM) - { - if (mo->z+mo->momz + mo->height < bottomheight) - continue; - - if (mo->z+mo->height > bottomheight) - continue; - } - else if (rover->flags & FF_SPINBUST) - { - if (mo->z+mo->momz > topheight) - continue; - - if (mo->z+mo->height < bottomheight) - continue; - } - else if (rover->flags & FF_SHATTER) - { - if (mo->z+mo->momz > topheight) - continue; - - if (mo->z+mo->momz + mo->height < bottomheight) - continue; - } - else - { - if (mo->z >= topheight) - continue; - - if (mo->z+mo->height < bottomheight) - continue; - } - - EV_CrumbleChain(node->m_sector, rover); - - // Run a linedef executor?? - if (rover->master->flags & ML_EFFECT5) - P_LinedefExecute((INT16)(P_AproxDistance(rover->master->dx, rover->master->dy)>>FRACBITS), mo, node->m_sector); - - goto bustupdone; - } + if (mo->z+mo->height > bottomheight) + continue; } + else if (rover->flags & FF_SPINBUST) + { + if (mo->z+mo->momz > topheight) + continue; + + if (mo->z+mo->height < bottomheight) + continue; + } + else if (rover->flags & FF_SHATTER) + { + if (mo->z+mo->momz > topheight) + continue; + + if (mo->z+mo->momz + mo->height < bottomheight) + continue; + } + else + { + if (mo->z >= topheight) + continue; + + if (mo->z+mo->height < bottomheight) + continue; + } + + EV_CrumbleChain(node->m_sector, rover); + + // Run a linedef executor?? + if (rover->master->flags & ML_EFFECT5) + P_LinedefExecute((INT16)(P_AproxDistance(rover->master->dx, rover->master->dy)>>FRACBITS), mo, node->m_sector); + + goto bustupdone; } } bustupdone: @@ -2498,42 +2500,42 @@ static void P_PlayerZMovement(mobj_t *mo) if (newsubsec->sector != sec) continue; - if (newsubsec->polyList) + if (!newsubsec->polyList) + continue; + + polyobj_t *po = newsubsec->polyList; + sector_t *polysec; + + while(po) { - polyobj_t *po = newsubsec->polyList; - sector_t *polysec; - - while(po) + if (!P_MobjInsidePolyobj(po, mo) || !(po->flags & POF_SOLID)) { - if (!P_MobjInsidePolyobj(po, mo) || !(po->flags & POF_SOLID)) - { - po = (polyobj_t *)(po->link.next); - continue; - } - - // We're inside it! Yess... - polysec = po->lines[0]->backsector; - - // Moving polyobjects should act like conveyors if the player lands on one. (I.E. none of the momentum cut thing below) -Red - if ((mo->z == polysec->ceilingheight || mo->z+mo->height == polysec->floorheight) && po->thinker) - stopmovecut = true; - - if (!(po->flags & POF_LDEXEC)) - { - po = (polyobj_t *)(po->link.next); - continue; - } - - if (mo->z == polysec->ceilingheight) - { - // We're landing on a PO, so check for - // a linedef executor. - // Trigger tags are 32000 + the PO's ID number. - P_LinedefExecute((INT16)(32000 + po->id), mo, NULL); - } - po = (polyobj_t *)(po->link.next); + continue; } + + // We're inside it! Yess... + polysec = po->lines[0]->backsector; + + // Moving polyobjects should act like conveyors if the player lands on one. (I.E. none of the momentum cut thing below) -Red + if ((mo->z == polysec->ceilingheight || mo->z+mo->height == polysec->floorheight) && po->thinker) + stopmovecut = true; + + if (!(po->flags & POF_LDEXEC)) + { + po = (polyobj_t *)(po->link.next); + continue; + } + + if (mo->z == polysec->ceilingheight) + { + // We're landing on a PO, so check for + // a linedef executor. + // Trigger tags are 32000 + the PO's ID number. + P_LinedefExecute((INT16)(32000 + po->id), mo, NULL); + } + + po = (polyobj_t *)(po->link.next); } } } @@ -3072,16 +3074,16 @@ void P_MobjCheckWater(mobj_t *mobj) mobj->y + FixedMul((prandom[2]<<(FRACBITS-3)) * (prandom[0]&0x40 ? 1 : -1), mobj->scale), mobj->z + FixedMul((prandom[3]<<(FRACBITS-2)), mobj->scale), bubbletype); - if (bubble) - { - if (P_MobjFlip(mobj)*mobj->momz < 0) - bubble->momz = mobj->momz >> 4; - else - bubble->momz = 0; + if (!bubble) + continue; - bubble->destscale = mobj->scale; - P_SetScale(bubble, mobj->scale); - } + if (P_MobjFlip(mobj)*mobj->momz < 0) + bubble->momz = mobj->momz >> 4; + else + bubble->momz = 0; + + bubble->destscale = mobj->scale; + P_SetScale(bubble, mobj->scale); } } } @@ -3144,7 +3146,12 @@ static void P_SceneryCheckWater(mobj_t *mobj) static boolean P_CameraCheckHeat(camera_t *thiscam) { sector_t *sector; - fixed_t halfheight = thiscam->z + (thiscam->height >> 1); + fixed_t halfheight; + + if (!thiscam) + return false; + + halfheight = thiscam->z + (thiscam->height >> 1); // see if we are in water sector = thiscam->subsector->sector; @@ -3177,7 +3184,12 @@ static boolean P_CameraCheckHeat(camera_t *thiscam) static boolean P_CameraCheckWater(camera_t *thiscam) { sector_t *sector; - fixed_t halfheight = thiscam->z + (thiscam->height >> 1); + fixed_t halfheight; + + if (!thiscam) + return false; + + halfheight = thiscam->z + (thiscam->height >> 1); // see if we are in water sector = thiscam->subsector->sector; @@ -3232,6 +3244,7 @@ void P_DestroyRobots(void) boolean P_CameraThinker(player_t *player, camera_t *thiscam, boolean resetcalled) { boolean itsatwodlevel = false; + boolean flipcam = (player->pflags & PF_FLIPCAM && !(player->pflags & PF_NIGHTSMODE) && player->mo->eflags & MFE_VERTICALFLIP); postimg_t postimg = postimg_none; UINT8 i; @@ -3254,10 +3267,12 @@ boolean P_CameraThinker(player_t *player, camera_t *thiscam, boolean resetcalled } } - if (encoremode) + if (encoremode && !flipcam) postimg = postimg_mirror; - else if (player->pflags & PF_FLIPCAM && !(player->pflags & PF_NIGHTSMODE) && player->mo->eflags & MFE_VERTICALFLIP) + else if (!encoremode && flipcam) postimg = postimg_flip; + else if (encoremode && flipcam) + postimg = postimg_mirrorflip; else if (player->awayviewtics && player->awayviewmobj && !P_MobjWasRemoved(player->awayviewmobj)) // Camera must obviously exist { camera_t dummycam; @@ -3286,8 +3301,10 @@ boolean P_CameraThinker(player_t *player, camera_t *thiscam, boolean resetcalled { for (i = 0; i <= splitscreen; i++) { - if (player == &players[displayplayers[i]]) - postimgtype[i] = postimg; + if (player != &players[displayplayers[i]]) + continue; + + postimgtype[i] = postimg; } } @@ -3460,20 +3477,20 @@ static void P_PlayerMobjThinker(mobj_t *mobj) for (node = mobj->touching_sectorlist; node; node = node->m_sectorlist_next) { - if (node->m_sector->ffloors) - { - ffloor_t *rover; - // Get water boundaries first - for (rover = node->m_sector->ffloors; rover; rover = rover->next) - { - if (!(rover->flags & FF_EXISTS)) - continue; + if (!node->m_sector->ffloors) + continue; - if (rover->flags & FF_SWIMMABLE) // Is there water? - { - thereiswater = true; - break; - } + ffloor_t *rover; + // Get water boundaries first + for (rover = node->m_sector->ffloors; rover; rover = rover->next) + { + if (!(rover->flags & FF_EXISTS)) + continue; + + if (rover->flags & FF_SWIMMABLE) // Is there water? + { + thereiswater = true; + break; } } } @@ -3481,21 +3498,21 @@ static void P_PlayerMobjThinker(mobj_t *mobj) { for (node = mobj->touching_sectorlist; node; node = node->m_sectorlist_next) { - if (node->m_sector->ffloors) - { - ffloor_t *rover; - for (rover = node->m_sector->ffloors; rover; rover = rover->next) - { - if (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_FLOATBOB)) - continue; + if (!node->m_sector->ffloors) + continue; - if ((!(mobj->eflags & MFE_VERTICALFLIP) && abs(*rover->topheight-mobj->z) <= abs(mobj->momz)) // The player is landing on the cheese! - || (mobj->eflags & MFE_VERTICALFLIP && abs(*rover->bottomheight-(mobj->z+mobj->height)) <= abs(mobj->momz))) - { - // Initiate a 'bouncy' elevator function - // which slowly diminishes. - EV_BounceSector(rover->master->frontsector, -mobj->momz, rover->master); - } + ffloor_t *rover; + for (rover = node->m_sector->ffloors; rover; rover = rover->next) + { + if (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_FLOATBOB)) + continue; + + if ((!(mobj->eflags & MFE_VERTICALFLIP) && abs(*rover->topheight-mobj->z) <= abs(mobj->momz)) // The player is landing on the cheese! + || (mobj->eflags & MFE_VERTICALFLIP && abs(*rover->bottomheight-(mobj->z+mobj->height)) <= abs(mobj->momz))) + { + // Initiate a 'bouncy' elevator function + // which slowly diminishes. + EV_BounceSector(rover->master->frontsector, -mobj->momz, rover->master); } } } @@ -3590,67 +3607,89 @@ void P_RecalcPrecipInSector(sector_t *sector) // // P_NullPrecipThinker // -// For "Blank" precipitation +// Just the identification of a precip thinker. The thinker +// should never actually be called! // void P_NullPrecipThinker(precipmobj_t *mobj) { - //(void)mobj; - mobj->precipflags &= ~PCF_THUNK; - R_ResetPrecipitationMobjInterpolationState(mobj); + (void)mobj; + I_Assert("P_NullPrecipThinker should not be called" == 0); } -void P_SnowThinker(precipmobj_t *mobj) +boolean P_PrecipThinker(precipmobj_t *mobj) { + if (mobj->lastThink == leveltime) + return true; // already thinked this tick + + mobj->lastThink = leveltime; + + R_ResetPrecipitationMobjInterpolationState(mobj); P_CycleStateAnimation((mobj_t *)mobj); + if (mobj->state == &states[S_RAINRETURN]) + { + // Reset to ceiling! + if (!P_SetPrecipMobjState(mobj, mobj->info->spawnstate)) + return false; + + mobj->z = mobj->ceilingz; + mobj->momz = cv_mobjscaleprecip.value ? FixedMul(mobj->info->speed, mapobjectscale) : mobj->info->speed; + mobj->precipflags &= ~PCF_SPLASH; + R_ResetPrecipitationMobjInterpolationState(mobj); + } + + if (mobj->tics != -1) + { + if (mobj->tics) + { + mobj->tics--; + } + + if (mobj->tics == 0) + { + if ((mobj->precipflags & PCF_SPLASH) && (mobj->state->nextstate == S_NULL)) + { + // HACK: sprite changes are 1 tic late, so you would see splashes on the ceiling if not for this state. + // We need to use the settings from the previous state, since some of those are NOT 1 tic late. + INT32 frame = (mobj->frame & ~FF_FRAMEMASK); + + if (!P_SetPrecipMobjState(mobj, S_RAINRETURN)) + return false; + + mobj->frame = frame; + return true; + } + else + { + if (!P_SetPrecipMobjState(mobj, mobj->state->nextstate)) + return false; + } + } + } + + if (mobj->precipflags & PCF_SPLASH) + return true; + // adjust height if ((mobj->z += mobj->momz) <= mobj->floorz) { - mobj->z = mobj->ceilingz; - R_ResetPrecipitationMobjInterpolationState(mobj); - } -} + if ((mobj->info->deathstate == S_NULL) || (mobj->precipflags & PCF_PIT)) // no splashes on sky or bottomless pits + { + mobj->z = mobj->ceilingz; + R_ResetPrecipitationMobjInterpolationState(mobj); + } + else + { + if (!P_SetPrecipMobjState(mobj, mobj->info->deathstate)) + return false; -void P_RainThinker(precipmobj_t *mobj) -{ - P_CycleStateAnimation((mobj_t *)mobj); - - if (mobj->state != &states[S_RAIN1]) - { - // cycle through states, - // calling action functions at transitions - if (mobj->tics <= 0) - return; - - if (--mobj->tics) - return; - - if (!P_SetPrecipMobjState(mobj, mobj->state->nextstate)) - return; - - if (mobj->state != &states[S_RAINRETURN]) - return; - - mobj->z = mobj->ceilingz; - R_ResetPrecipitationMobjInterpolationState(mobj); - P_SetPrecipMobjState(mobj, S_RAIN1); - - return; + mobj->z = mobj->floorz; + mobj->precipflags |= PCF_SPLASH; + R_ResetPrecipitationMobjInterpolationState(mobj); + } } - // adjust height - if ((mobj->z += mobj->momz) > mobj->floorz) - return; - - // no splashes on sky or bottomless pits - if (mobj->precipflags & PCF_PIT) - { - mobj->z = mobj->ceilingz; - return; - } - - mobj->z = mobj->floorz; - P_SetPrecipMobjState(mobj, S_SPLASH1); + return true; } static void P_RingThinker(mobj_t *mobj) @@ -3746,20 +3785,20 @@ boolean P_SupermanLook4Players(mobj_t *actor) for (c = 0; c < MAXPLAYERS; c++) { - if (playeringame[c]) - { - if (players[c].health <= 0) - continue; // dead + if (!playeringame[c]) + continue; - if (players[c].pflags & PF_INVIS) - continue; // ignore notarget + if (players[c].health <= 0) + continue; // dead - if (!players[c].mo || players[c].bot) - continue; + if (players[c].pflags & PF_INVIS) + continue; // ignore notarget - playersinthegame[stop] = &players[c]; - stop++; - } + if (!players[c].mo || players[c].bot) + continue; + + playersinthegame[stop] = &players[c]; + stop++; } if (!stop) @@ -4111,11 +4150,21 @@ static void P_Boss3Thinker(mobj_t *mobj) continue; mo2 = (mobj_t *)th; - if (mo2->type == MT_BOSS3WAYPOINT && mo2->spawnpoint && mo2->spawnpoint->angle == mobj->threshold) - { - P_SetTarget(&mobj->target, mo2); - break; - } + + if (!mo2) + continue; + + if (mo2->type != MT_BOSS3WAYPOINT) + continue; + + if (!mo2->spawnpoint) + continue; + + if (mo2->spawnpoint->angle != mobj->threshold) + continue; + + P_SetTarget(&mobj->target, mo2); + break; } if (!mobj->target) // Should NEVER happen @@ -4267,18 +4316,20 @@ static void P_Boss4DestroyCage(void) { rsec = §ors[sector->attached[a]]; for (rover = rsec->ffloors; rover; rover = rover->next) - if (rover->flags & FF_EXISTS && rover->secnum == (size_t)snum) + { + if (!(rover->flags & FF_EXISTS && rover->secnum == (size_t)snum)) + continue; + + if (rover->flags & FF_RENDERALL) // checking for FF_RENDERANY. + EV_CrumbleChain(rsec, rover); // This FOF is visible to some extent? Crumble it. + else // Completely invisible FOF { - if (rover->flags & FF_RENDERALL) // checking for FF_RENDERANY. - EV_CrumbleChain(rsec, rover); // This FOF is visible to some extent? Crumble it. - else // Completely invisible FOF - { - // no longer exists (can't collide with again) - rover->flags &= ~FF_EXISTS; - sector->moved = true; - rsec->moved = true; - } + // no longer exists (can't collide with again) + rover->flags &= ~FF_EXISTS; + sector->moved = true; + rsec->moved = true; } + } } } } @@ -4293,8 +4344,10 @@ static void P_Boss4PopSpikeballs(mobj_t *mobj) next = base->tracer; P_SetTarget(&base->tracer, NULL); for (seg = base; seg; seg = seg->hnext) + { if (seg->health) P_KillMobj(seg, NULL, NULL); + } base = next; } } @@ -4953,13 +5006,15 @@ static void P_Boss9Thinker(mobj_t *mobj) else mobj->momz = (mobj->watertop-mobj->z)/40; // Float to your desired position - if (mobj->movecount == 2) { + if (mobj->movecount == 2) + { mobj_t *spawner; fixed_t dist = 0; angle = 0x06000000*leveltime; // Alter your energy bubble's size/position - if (mobj->health > 3) { + if (mobj->health > 3) + { mobj->tracer->destscale = FRACUNIT + (4*TICRATE - mobj->fuse)*(FRACUNIT/2)/TICRATE + FixedMul(FINECOSINE(angle>>ANGLETOFINESHIFT),FRACUNIT/2); P_SetScale(mobj->tracer, mobj->tracer->destscale); P_SetOrigin(mobj->tracer, mobj->x, mobj->y, mobj->z + mobj->height/2 - mobj->tracer->height/2); @@ -4995,8 +5050,10 @@ static void P_Boss9Thinker(mobj_t *mobj) } // Pre-threshold reactiontime stuff for attack phases - if (mobj->reactiontime && mobj->movecount == 3) { - if (mobj->movedir == 0 || mobj->movedir == 2) { // Pausing between bounces in the pinball phase + if (mobj->reactiontime && mobj->movecount == 3) + { + if (mobj->movedir == 0 || mobj->movedir == 2) // Pausing between bounces in the pinball phase + { if (mobj->target->player->powers[pw_tailsfly]) // Trying to escape, eh? mobj->watertop = mobj->target->z + mobj->target->momz*6; // Readjust your aim. >:3 else @@ -5010,13 +5067,16 @@ static void P_Boss9Thinker(mobj_t *mobj) } // threshold is used for attacks/maneuvers. - if (mobj->threshold) { + if (mobj->threshold) + { fixed_t speed = 20*FRACUNIT + FixedMul(40*FRACUNIT, FixedDiv((mobj->info->spawnhealth - mobj->health)<info->spawnhealth<movecount == 3 && mobj->movedir == 1) { - if (!(mobj->threshold&1)) { + if (mobj->movecount == 3 && mobj->movedir == 1) + { + if (!(mobj->threshold&1)) + { mobj_t *missile; if (mobj->info->seesound) S_StartSound(mobj, mobj->info->seesound); @@ -5028,18 +5088,21 @@ static void P_Boss9Thinker(mobj_t *mobj) A_FaceTarget(mobj); missile = P_SpawnMissile(mobj, mobj->target, mobj->info->speed); - if (mobj->extravalue1 == 2 || mobj->extravalue1 == 3) { + if (mobj->extravalue1 == 2 || mobj->extravalue1 == 3) + { missile->destscale = FRACUNIT>>1; P_SetScale(missile, missile->destscale); } missile->fuse = 3*TICRATE; missile->z -= missile->height/2; - if (mobj->extravalue1 == 2) { + if (mobj->extravalue1 == 2) + { int i; mobj_t *spread; missile->flags |= MF_MISSILE; - for (i = 0; i < 5; i++) { + for (i = 0; i < 5; i++) + { if (i == 2) continue; spread = P_SpawnMobj(missile->x, missile->y, missile->z, missile->type); @@ -5052,7 +5115,9 @@ static void P_Boss9Thinker(mobj_t *mobj) } missile->flags &= ~MF_MISSILE; } - } else { + } + else + { P_SetMobjState(mobj, mobj->state->nextstate); if (mobj->extravalue1 == 3) mobj->reactiontime = TICRATE/8; @@ -5066,7 +5131,8 @@ static void P_Boss9Thinker(mobj_t *mobj) P_SpawnGhostMobj(mobj); // Pinball attack! - if (mobj->movecount == 3 && (mobj->movedir == 0 || mobj->movedir == 2)) { + if (mobj->movecount == 3 && (mobj->movedir == 0 || mobj->movedir == 2)) + { if ((statenum_t)(mobj->state-states) != mobj->info->seestate) P_SetMobjState(mobj, mobj->info->seestate); if (mobj->movedir == 0) // mobj health == 1 @@ -5075,16 +5141,22 @@ static void P_Boss9Thinker(mobj_t *mobj) P_InstaThrust(mobj, mobj->angle, 22*FRACUNIT); else // mobj health == 2 P_InstaThrust(mobj, mobj->angle, 30*FRACUNIT); - if (!P_TryMove(mobj, mobj->x+mobj->momx, mobj->y+mobj->momy, true)) { // Hit a wall? Find a direction to bounce + + if (!P_TryMove(mobj, mobj->x+mobj->momx, mobj->y+mobj->momy, true)) // Hit a wall? Find a direction to bounce + { mobj->threshold--; - if (mobj->threshold) { + if (mobj->threshold) + { P_SetMobjState(mobj, mobj->state->nextstate); if (mobj->info->mass) S_StartSound(mobj, mobj->info->mass); - if (!(mobj->threshold%4)) { // We've decided to lock onto the player this bounce. + if (!(mobj->threshold%4)) // We've decided to lock onto the player this bounce. + { mobj->angle = R_PointToAngle2(mobj->x, mobj->y, mobj->target->x + mobj->target->momx*4, mobj->target->y + mobj->target->momy*4); mobj->reactiontime = TICRATE; // targetting time - } else { // No homing, just use P_BounceMove + } + else // No homing, just use P_BounceMove + { P_BounceMove(mobj); mobj->angle = R_PointToAngle2(0,0,mobj->momx,mobj->momy); mobj->reactiontime = TICRATE/4; // just a pause before you bounce away @@ -5098,7 +5170,8 @@ static void P_Boss9Thinker(mobj_t *mobj) // Vector form dodge! mobj->angle += mobj->movedir; P_InstaThrust(mobj, mobj->angle, -speed); - while (!P_TryMove(mobj, mobj->x+mobj->momx, mobj->y+mobj->momy, true) && tries++ < 16) { + while (!P_TryMove(mobj, mobj->x+mobj->momx, mobj->y+mobj->momy, true) && tries++ < 16) + { mobj->angle += mobj->movedir; P_InstaThrust(mobj, mobj->angle, -speed); } @@ -5154,9 +5227,10 @@ static void P_Boss9Thinker(mobj_t *mobj) if (mobj->flags2 & MF2_FRET) return; - if (mobj->state == &states[mobj->info->raisestate]) - { // Charging energy - if (mobj->momx != 0 || mobj->momy != 0) { // Apply the air breaks + if (mobj->state == &states[mobj->info->raisestate]) // Charging energy + { + if (mobj->momx != 0 || mobj->momy != 0) // Apply the air breaks + { if (abs(mobj->momx)+abs(mobj->momy) < FRACUNIT) mobj->momx = mobj->momy = 0; else @@ -5181,7 +5255,8 @@ static void P_Boss9Thinker(mobj_t *mobj) mobj->watertop = mobj->target->floorz + 256*FRACUNIT; break; - case 1: { + case 1: + { // Okay, we're up? Good, time to gather energy... if (mobj->health > mobj->info->damage) { // No more bubble if we're broken (pinch phase) @@ -5207,7 +5282,8 @@ static void P_Boss9Thinker(mobj_t *mobj) P_SetTarget(&mobj->tracer, mobj->hnext); P_RemoveMobj(removemobj); } - if (mobj->health <= mobj->info->damage) { + if (mobj->health <= mobj->info->damage) + { // Attack 1: Pinball dash! if (mobj->health == 1) mobj->movedir = 0; @@ -5222,7 +5298,9 @@ static void P_Boss9Thinker(mobj_t *mobj) mobj->threshold = 32; // bounce 32 times mobj->watertop = mobj->target->floorz + 16*FRACUNIT; P_LinedefExecute(LE_PINCHPHASE, mobj, NULL); - } else { + } + else + { // Attack 2: Energy shot! mobj->movedir = 1; @@ -5235,7 +5313,8 @@ static void P_Boss9Thinker(mobj_t *mobj) else mobj->extravalue1 = 3; - switch(mobj->extravalue1) { + switch(mobj->extravalue1) + { case 0: // shoot once case 2: // spread-shot default: @@ -5299,7 +5378,8 @@ static void P_Boss9Thinker(mobj_t *mobj) danger = false; if (mobj->target->z+mobj->target->momz*2 > mobj->z+mobj->height) danger = false; - if (danger) { + if (danger) + { // An incoming attack is detected! What should we do?! // Go into vector form! mobj->movedir = ANGLE_11hh - FixedAngle(FixedMul(AngleFixed(ANGLE_11hh), FixedDiv((mobj->info->spawnhealth - mobj->health)<info->spawnhealth-1)<type == MT_AXIS) + if (mo2->type != MT_AXIS) + continue; + + if (closestaxis == NULL) { - if (closestaxis == NULL) + closestaxis = mo2; + dist2 = R_PointToDist2(source->x, source->y, mo2->x, mo2->y)-mo2->radius; + } + else + { + dist1 = R_PointToDist2(source->x, source->y, mo2->x, mo2->y)-mo2->radius; + + if (dist1 < dist2) { closestaxis = mo2; - dist2 = R_PointToDist2(source->x, source->y, mo2->x, mo2->y)-mo2->radius; - } - else - { - dist1 = R_PointToDist2(source->x, source->y, mo2->x, mo2->y)-mo2->radius; - - if (dist1 < dist2) - { - closestaxis = mo2; - dist2 = dist1; - } + dist2 = dist1; } } } @@ -5731,7 +5811,8 @@ static void P_AddOverlay(mobj_t *thing) if (overlaycap == NULL) P_SetTarget(&overlaycap, thing); - else { + else + { mobj_t *mo; for (mo = overlaycap; mo && mo->hnext; mo = mo->hnext) ; @@ -5844,7 +5925,8 @@ static void P_AddShadow(mobj_t *thing) if (shadowcap == NULL) P_SetTarget(&shadowcap, thing); - else { + else + { mobj_t *mo; for (mo = shadowcap; mo && mo->hnext; mo = mo->hnext) ; @@ -7154,16 +7236,24 @@ void P_MobjThinker(mobj_t *mobj) INT32 i; P_SetTarget(&mobj->target, NULL); for (i = 0; i < MAXPLAYERS; i++) - if (playeringame[i] && players[i].mo - && players[i].mare == mobj->threshold && players[i].health > 1) - { - fixed_t dist = P_AproxDistance(players[i].mo->x - mobj->x, players[i].mo->y - mobj->y); - if (dist < shortest) - { - P_SetTarget(&mobj->target, players[i].mo); - shortest = dist; - } - } + { + if (!playeringame[i] || !players[i].mo) + continue; + + if (players[i].mare != mobj->threshold) + continue; + + if (!(players[i].health > 1)) + continue; + + fixed_t dist = P_AproxDistance(players[i].mo->x - mobj->x, players[i].mo->y - mobj->y); + + if (!(dist < shortest)) + continue; + + P_SetTarget(&mobj->target, players[i].mo); + shortest = dist; + } } break; case MT_EGGMOBILE2_POGO: @@ -8806,190 +8896,192 @@ void P_MobjThinker(mobj_t *mobj) mobj_t *flagmo, *newmobj; if (!LUAh_MobjFuse(mobj) && !P_MobjWasRemoved(mobj)) - switch (mobj->type) { - // gargoyle and snowman handled in P_PushableThinker, not here - case MT_THROWNGRENADE: - case MT_CYBRAKDEMON_NAPALM_BOMB_LARGE: - P_SetMobjState(mobj, mobj->info->deathstate); - break; - case MT_BLUEFLAG: - case MT_REDFLAG: - if (mobj->spawnpoint) - { - x = mobj->spawnpoint->x << FRACBITS; - y = mobj->spawnpoint->y << FRACBITS; - ss = R_PointInSubsector(x, y); - if (mobj->spawnpoint->options & MTF_OBJECTFLIP) + switch (mobj->type) + { + // gargoyle and snowman handled in P_PushableThinker, not here + case MT_THROWNGRENADE: + case MT_CYBRAKDEMON_NAPALM_BOMB_LARGE: + P_SetMobjState(mobj, mobj->info->deathstate); + break; + case MT_BLUEFLAG: + case MT_REDFLAG: + if (mobj->spawnpoint) { - z = ss->sector->ceilingheight - mobjinfo[mobj->type].height; - if (mobj->spawnpoint->options >> ZSHIFT) - z -= (mobj->spawnpoint->options >> ZSHIFT) << FRACBITS; + x = mobj->spawnpoint->x << FRACBITS; + y = mobj->spawnpoint->y << FRACBITS; + ss = R_PointInSubsector(x, y); + if (mobj->spawnpoint->options & MTF_OBJECTFLIP) + { + z = ss->sector->ceilingheight - mobjinfo[mobj->type].height; + if (mobj->spawnpoint->options >> ZSHIFT) + z -= (mobj->spawnpoint->options >> ZSHIFT) << FRACBITS; + } + else + { + z = ss->sector->floorheight; + if (mobj->spawnpoint->options >> ZSHIFT) + z += (mobj->spawnpoint->options >> ZSHIFT) << FRACBITS; + } + flagmo = P_SpawnMobj(x, y, z, mobj->type); + flagmo->spawnpoint = mobj->spawnpoint; + if (mobj->spawnpoint->options & MTF_OBJECTFLIP) + { + flagmo->eflags |= MFE_VERTICALFLIP; + flagmo->flags2 |= MF2_OBJECTFLIP; + } + + if (mobj->type == MT_REDFLAG) + { + if (!(mobj->flags2 & MF2_JUSTATTACKED)) + CONS_Printf(M_GetText("The %c%s%c has returned to base.\n"), 0x85, M_GetText("Red flag"), 0x80); + + // Assumedly in splitscreen players will be on opposing teams + if (players[consoleplayer].ctfteam == 1 || splitscreen) + S_StartSound(NULL, sfx_hoop1); + else if (players[consoleplayer].ctfteam == 2) + S_StartSound(NULL, sfx_hoop3); + + redflag = flagmo; + } + else // MT_BLUEFLAG + { + if (!(mobj->flags2 & MF2_JUSTATTACKED)) + CONS_Printf(M_GetText("The %c%s%c has returned to base.\n"), 0x84, M_GetText("Blue flag"), 0x80); + + // Assumedly in splitscreen players will be on opposing teams + if (players[consoleplayer].ctfteam == 2 || splitscreen) + S_StartSound(NULL, sfx_hoop1); + else if (players[consoleplayer].ctfteam == 1) + S_StartSound(NULL, sfx_hoop3); + + blueflag = flagmo; + } } - else + P_RemoveMobj(mobj); + return; + case MT_YELLOWTV: // Ring shield box + case MT_BLUETV: // Force shield box + case MT_GREENTV: // Water shield box + case MT_BLACKTV: // Bomb shield box + case MT_WHITETV: // Jump shield box + case MT_SNEAKERTV: // Super Sneaker box + case MT_SUPERRINGBOX: // 10-Ring box + case MT_REDRINGBOX: // Red Team 10-Ring box + case MT_BLUERINGBOX: // Blue Team 10-Ring box + case MT_INV: // Invincibility box + case MT_MIXUPBOX: // Teleporter Mixup box + case MT_RECYCLETV: // Recycler box + case MT_SCORETVSMALL: + case MT_SCORETVLARGE: + case MT_PRUP: // 1up! + case MT_EGGMANBOX: // Eggman box + case MT_GRAVITYBOX: // Gravity box + case MT_QUESTIONBOX: + if ((mobj->flags2 & MF2_AMBUSH || mobj->flags2 & MF2_STRONGBOX) && mobj->type != MT_QUESTIONBOX) { - z = ss->sector->floorheight; - if (mobj->spawnpoint->options >> ZSHIFT) - z += (mobj->spawnpoint->options >> ZSHIFT) << FRACBITS; - } - flagmo = P_SpawnMobj(x, y, z, mobj->type); - flagmo->spawnpoint = mobj->spawnpoint; - if (mobj->spawnpoint->options & MTF_OBJECTFLIP) - { - flagmo->eflags |= MFE_VERTICALFLIP; - flagmo->flags2 |= MF2_OBJECTFLIP; - } + mobjtype_t spawnchance[64]; + INT32 numchoices = 0, i = 0; - if (mobj->type == MT_REDFLAG) - { - if (!(mobj->flags2 & MF2_JUSTATTACKED)) - CONS_Printf(M_GetText("The %c%s%c has returned to base.\n"), 0x85, M_GetText("Red flag"), 0x80); - - // Assumedly in splitscreen players will be on opposing teams - if (players[consoleplayer].ctfteam == 1 || splitscreen) - S_StartSound(NULL, sfx_hoop1); - else if (players[consoleplayer].ctfteam == 2) - S_StartSound(NULL, sfx_hoop3); - - redflag = flagmo; - } - else // MT_BLUEFLAG - { - if (!(mobj->flags2 & MF2_JUSTATTACKED)) - CONS_Printf(M_GetText("The %c%s%c has returned to base.\n"), 0x84, M_GetText("Blue flag"), 0x80); - - // Assumedly in splitscreen players will be on opposing teams - if (players[consoleplayer].ctfteam == 2 || splitscreen) - S_StartSound(NULL, sfx_hoop1); - else if (players[consoleplayer].ctfteam == 1) - S_StartSound(NULL, sfx_hoop3); - - blueflag = flagmo; - } - } - P_RemoveMobj(mobj); - return; - case MT_YELLOWTV: // Ring shield box - case MT_BLUETV: // Force shield box - case MT_GREENTV: // Water shield box - case MT_BLACKTV: // Bomb shield box - case MT_WHITETV: // Jump shield box - case MT_SNEAKERTV: // Super Sneaker box - case MT_SUPERRINGBOX: // 10-Ring box - case MT_REDRINGBOX: // Red Team 10-Ring box - case MT_BLUERINGBOX: // Blue Team 10-Ring box - case MT_INV: // Invincibility box - case MT_MIXUPBOX: // Teleporter Mixup box - case MT_RECYCLETV: // Recycler box - case MT_SCORETVSMALL: - case MT_SCORETVLARGE: - case MT_PRUP: // 1up! - case MT_EGGMANBOX: // Eggman box - case MT_GRAVITYBOX: // Gravity box - case MT_QUESTIONBOX: - if ((mobj->flags2 & MF2_AMBUSH || mobj->flags2 & MF2_STRONGBOX) && mobj->type != MT_QUESTIONBOX) - { - mobjtype_t spawnchance[64]; - INT32 numchoices = 0, i = 0; - -// This define should make it a lot easier to organize and change monitor weights + // This define should make it a lot easier to organize and change monitor weights #define SETMONITORCHANCES(type, strongboxamt, weakboxamt) \ -for (i = ((mobj->flags2 & MF2_STRONGBOX) ? strongboxamt : weakboxamt); i; --i) spawnchance[numchoices++] = type + for (i = ((mobj->flags2 & MF2_STRONGBOX) ? strongboxamt : weakboxamt); i; --i) spawnchance[numchoices++] = type - // Type SRM WRM - SETMONITORCHANCES(MT_SNEAKERTV, 0, 10); // Super Sneakers - SETMONITORCHANCES(MT_INV, 2, 0); // Invincibility - SETMONITORCHANCES(MT_WHITETV, 3, 8); // Whirlwind Shield - SETMONITORCHANCES(MT_GREENTV, 3, 8); // Elemental Shield - SETMONITORCHANCES(MT_YELLOWTV, 2, 0); // Attraction Shield - SETMONITORCHANCES(MT_BLUETV, 3, 3); // Force Shield - SETMONITORCHANCES(MT_BLACKTV, 2, 0); // Armageddon Shield - SETMONITORCHANCES(MT_MIXUPBOX, 0, 1); // Teleporters - SETMONITORCHANCES(MT_RECYCLETV, 0, 1); // Recycler - SETMONITORCHANCES(MT_PRUP, 1, 1); // 1-Up - // ====================================== - // Total 16 32 + // Type SRM WRM + SETMONITORCHANCES(MT_SNEAKERTV, 0, 10); // Super Sneakers + SETMONITORCHANCES(MT_INV, 2, 0); // Invincibility + SETMONITORCHANCES(MT_WHITETV, 3, 8); // Whirlwind Shield + SETMONITORCHANCES(MT_GREENTV, 3, 8); // Elemental Shield + SETMONITORCHANCES(MT_YELLOWTV, 2, 0); // Attraction Shield + SETMONITORCHANCES(MT_BLUETV, 3, 3); // Force Shield + SETMONITORCHANCES(MT_BLACKTV, 2, 0); // Armageddon Shield + SETMONITORCHANCES(MT_MIXUPBOX, 0, 1); // Teleporters + SETMONITORCHANCES(MT_RECYCLETV, 0, 1); // Recycler + SETMONITORCHANCES(MT_PRUP, 1, 1); // 1-Up + // ====================================== + // Total 16 32 #undef SETMONITORCHANCES - i = P_RandomKey(numchoices); // Gotta love those random numbers! - newmobj = P_SpawnMobj(mobj->x, mobj->y, mobj->z, spawnchance[i]); + i = P_RandomKey(numchoices); // Gotta love those random numbers! + newmobj = P_SpawnMobj(mobj->x, mobj->y, mobj->z, spawnchance[i]); - // Transfer flags2 (strongbox, objectflip, ambush) - newmobj->flags2 = mobj->flags2; - } - else - { - newmobj = P_SpawnMobj(mobj->x, mobj->y, mobj->z, mobj->type); - - // Transfer flags2 (strongbox, objectflip) - newmobj->flags2 = mobj->flags2; - } - P_RemoveMobj(mobj); // make sure they disappear - return; - case MT_RANDOMITEM: - if (G_BattleGametype()) - { - if (mobj->threshold != 69) - break; - } - else - { - // Respawn from mapthing if you have one! - if (mobj->spawnpoint) - { - P_SpawnMapThing(mobj->spawnpoint); - newmobj = mobj->spawnpoint->mobj; // this is set to the new mobj in P_SpawnMapThing + // Transfer flags2 (strongbox, objectflip, ambush) + newmobj->flags2 = mobj->flags2; } else + { newmobj = P_SpawnMobj(mobj->x, mobj->y, mobj->z, mobj->type); - // Transfer flags2 (strongbox, objectflip) - newmobj->flags2 = mobj->flags2 & ~MF2_DONTDRAW; - } - P_RemoveMobj(mobj); // make sure they disappear - return; - case MT_METALSONIC_BATTLE: - break; // don't remove - case MT_SPIKE: - P_SetMobjState(mobj, mobj->state->nextstate); - mobj->fuse = mobj->info->speed; - if (mobj->spawnpoint) - mobj->fuse += mobj->spawnpoint->angle; - break; - case MT_NIGHTSCORE: - P_RemoveMobj(mobj); - return; - case MT_PLAYER: - break; // don't remove - case MT_SMK_ICEBLOCK: - { - mobj_t *cur = mobj->hnext, *next; - UINT8 i; - - for (i = 0; i < 5; i++) - { - mobj_t *debris = P_SpawnMobj(mobj->x, mobj->y, mobj->z, MT_SMK_ICEBLOCK_DEBRIS); - debris->angle = FixedAngle(P_RandomRange(0,360)<angle, P_RandomRange(3,18)*(FRACUNIT/4)); - debris->momz = P_RandomRange(4,8)<flags2 = mobj->flags2; } - - while (cur && !P_MobjWasRemoved(cur)) + P_RemoveMobj(mobj); // make sure they disappear + return; + case MT_RANDOMITEM: + if (G_BattleGametype()) { - next = cur->hnext; - P_RemoveMobj(cur); - cur = next; + if (mobj->threshold != 69) + break; } + else + { + // Respawn from mapthing if you have one! + if (mobj->spawnpoint) + { + P_SpawnMapThing(mobj->spawnpoint); + newmobj = mobj->spawnpoint->mobj; // this is set to the new mobj in P_SpawnMapThing + } + else + newmobj = P_SpawnMobj(mobj->x, mobj->y, mobj->z, mobj->type); + // Transfer flags2 (strongbox, objectflip) + newmobj->flags2 = mobj->flags2 & ~MF2_DONTDRAW; + } + P_RemoveMobj(mobj); // make sure they disappear + return; + case MT_METALSONIC_BATTLE: + break; // don't remove + case MT_SPIKE: + P_SetMobjState(mobj, mobj->state->nextstate); + mobj->fuse = mobj->info->speed; + if (mobj->spawnpoint) + mobj->fuse += mobj->spawnpoint->angle; + break; + case MT_NIGHTSCORE: P_RemoveMobj(mobj); return; - } - default: - P_SetMobjState(mobj, mobj->info->xdeathstate); // will remove the mobj if S_NULL. - break; + case MT_PLAYER: + break; // don't remove + case MT_SMK_ICEBLOCK: + { + mobj_t *cur = mobj->hnext, *next; + UINT8 i; + + for (i = 0; i < 5; i++) + { + mobj_t *debris = P_SpawnMobj(mobj->x, mobj->y, mobj->z, MT_SMK_ICEBLOCK_DEBRIS); + debris->angle = FixedAngle(P_RandomRange(0,360)<angle, P_RandomRange(3,18)*(FRACUNIT/4)); + debris->momz = P_RandomRange(4,8)<hnext; + P_RemoveMobj(cur); + cur = next; + } + + P_RemoveMobj(mobj); + return; + } + default: + P_SetMobjState(mobj, mobj->info->xdeathstate); // will remove the mobj if S_NULL. + break; + } } if (P_MobjWasRemoved(mobj)) return; @@ -9550,6 +9642,7 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) { if (!playeringame[i]) continue; + pnum[pcount] = i; pcount++; } @@ -9859,17 +9952,21 @@ mobj_t *P_SpawnShadowMobj(mobj_t * caster) static precipmobj_t *P_SpawnPrecipMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) { + const mobjinfo_t *info = &mobjinfo[type]; state_t *st; precipmobj_t *mobj = Z_Calloc(sizeof (*mobj), PU_LEVEL, NULL); fixed_t starting_floorz; + mobj->type = type; + mobj->info = info; + mobj->x = x; mobj->y = y; - mobj->flags = mobjinfo[type].flags; + mobj->flags = info->flags; // do not set the state with P_SetMobjState, // because action routines can not be called yet - st = &states[mobjinfo[type].spawnstate]; + st = &states[info->spawnstate]; mobj->state = st; mobj->tics = st->tics; @@ -9884,7 +9981,7 @@ static precipmobj_t *P_SpawnPrecipMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype mobj->ceilingz = P_GetSectorCeilingZAt(mobj->subsector->sector, x, y); mobj->z = z; - mobj->momz = mobjinfo[type].speed; + mobj->momz = cv_mobjscaleprecip.value ? FixedMul(info->speed, mapobjectscale) : info->speed; mobj->thinker.function.acp1 = (actionf_p1)P_NullPrecipThinker; P_AddThinker(&mobj->thinker); @@ -9903,21 +10000,6 @@ static precipmobj_t *P_SpawnPrecipMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype return mobj; } -static inline precipmobj_t *P_SpawnRainMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) -{ - precipmobj_t *mo = P_SpawnPrecipMobj(x,y,z,type); - mo->precipflags |= PCF_RAIN; - //mo->thinker.function.acp1 = (actionf_p1)P_RainThinker; - return mo; -} - -static inline precipmobj_t *P_SpawnSnowMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) -{ - precipmobj_t *mo = P_SpawnPrecipMobj(x,y,z,type); - //mo->thinker.function.acp1 = (actionf_p1)P_SnowThinker; - return mo; -} - // // P_RemoveMobj // @@ -10001,20 +10083,18 @@ void P_RemoveMobj(mobj_t *mobj) P_SetTarget(&mobj->target, P_SetTarget(&mobj->tracer, NULL)); // repair hnext chain + mobj_t *cachenext = mobj->hnext; + + if (mobj->hnext && !P_MobjWasRemoved(mobj->hnext)) { - mobj_t *cachenext = mobj->hnext; + P_SetTarget(&mobj->hnext->hprev, mobj->hprev); + P_SetTarget(&mobj->hnext, NULL); + } - if (mobj->hnext && !P_MobjWasRemoved(mobj->hnext)) - { - P_SetTarget(&mobj->hnext->hprev, mobj->hprev); - P_SetTarget(&mobj->hnext, NULL); - } - - if (mobj->hprev && !P_MobjWasRemoved(mobj->hprev)) - { - P_SetTarget(&mobj->hprev->hnext, cachenext); - P_SetTarget(&mobj->hprev, NULL); - } + if (mobj->hprev && !P_MobjWasRemoved(mobj->hprev)) + { + P_SetTarget(&mobj->hprev->hnext, cachenext); + P_SetTarget(&mobj->hprev, NULL); } // clear the reference from the mapthing @@ -10058,14 +10138,12 @@ void P_RemoveMobj(mobj_t *mobj) // This does not need to be added to Lua. // To test it in Lua, check mobj.valid -boolean P_MobjWasRemoved(mobj_t *mobj) +FUNCINLINE ATTRINLINE boolean P_MobjWasRemoved(const mobj_t *mobj) { - if (mobj && mobj->thinker.function.acp1 == (actionf_p1)P_MobjThinker) - return false; - return true; + return !(mobj && mobj->thinker.function.acp1 == (actionf_p1)P_MobjThinker); } -void P_RemovePrecipMobj(precipmobj_t *mobj) +void P_FreePrecipMobj(precipmobj_t *mobj) { // unlink from sector and block lists P_UnsetPrecipThingPosition(mobj); @@ -10077,7 +10155,9 @@ void P_RemovePrecipMobj(precipmobj_t *mobj) } // free block - P_RemoveThinker((thinker_t *)mobj); + // Precipmobjs don't actually think using their thinker, + // so the free cannot be delayed. + P_UnlinkThinker((thinker_t*)mobj); } // Clearing out stuff for savegames @@ -10113,12 +10193,7 @@ void P_RemoveSavegameMobj(mobj_t *mobj) // free block // Here we use the same code as R_RemoveThinkerDelayed, but without reference counting (we're removing everything so it shouldn't matter) and without touching currentthinker since we aren't in P_RunThinkers - { - thinker_t *thinker = (thinker_t *)mobj; - thinker_t *next = thinker->next; - (next->prev = thinker->prev)->next = next; - Z_Free(thinker); - } + P_UnlinkThinker((thinker_t*)mobj); } static CV_PossibleValue_t respawnitemtime_cons_t[] = {{1, "MIN"}, {300, "MAX"}, {0, NULL}}; @@ -10130,8 +10205,9 @@ consvar_t cv_suddendeath = {"suddendeath", "Off", CV_NETVAR|CV_CHEAT|CV_NOSHOWHE void P_SpawnPrecipitation(void) { - INT32 i, mrand; - fixed_t basex, basey, x, y, height; + INT32 i, j, k, mrand; + fixed_t basex, basey, x, y, z, height; + fixed_t precipscale = cv_mobjscaleprecip.value ? mapobjectscale : FRACUNIT; subsector_t *precipsector = NULL; precipmobj_t *rainmo = NULL; @@ -10144,10 +10220,9 @@ void P_SpawnPrecipitation(void) basex = bmaporgx + (i % bmapwidth) * MAPBLOCKSIZE; basey = bmaporgy + (i / bmapwidth) * MAPBLOCKSIZE; - //for (j = 0; j < cv_precipdensity.value; ++j) -- density is 1 for kart always + for (j = 0; j < FRACUNIT; j += precipscale) { - INT32 floorz; - INT32 ceilingz; + UINT16 numparticles = 0; x = ((cv_lessprecip.value ? basex*1.5 : basex) + ((M_RandomKey(MAPBLOCKUNITS<<3)<>3)); y = ((cv_lessprecip.value ? basey*1.5 : basey) + ((M_RandomKey(MAPBLOCKUNITS<<3)<>3)); @@ -10163,37 +10238,49 @@ void P_SpawnPrecipitation(void) if (precipsector->sector->ceilingpic != skyflatnum) continue; + height = precipsector->sector->ceilingheight - precipsector->sector->floorheight; + height = FixedDiv(height, precipscale); + // Exists, but is too small for reasonable precipitation. - if (!(precipsector->sector->floorheight <= precipsector->sector->ceilingheight - (32<sector->ceilingheight; + // Hack around a quirk of this entire system, where taller sectors look like they get less precipitation. + numparticles = 1 + (height / (MAPBLOCKUNITS<<4<sector->ceilingheight; - floorz = rainmo->floorz >> FRACBITS; - ceilingz = rainmo->ceilingz >> FRACBITS; + for (k = 0; k < numparticles; k++) + { + INT32 floorz; + INT32 ceilingz; - if (floorz < ceilingz) - { - // Randomly assign a height, now that floorz is set. - rainmo->z = M_RandomRange(floorz, ceilingz) << FRACBITS; - } - else - { - // ...except if the floor is above the ceiling. - rainmo->z = ceilingz << FRACBITS; + if (curWeather == PRECIP_SNOW) + { + rainmo = P_SpawnPrecipMobj(x, y, z, MT_SNOWFLAKE); + mrand = M_RandomByte(); + if (mrand < 64) + P_SetPrecipMobjState(rainmo, S_SNOW3); + else if (mrand < 144) + P_SetPrecipMobjState(rainmo, S_SNOW2); + } + else // everything else. + rainmo = P_SpawnPrecipMobj(x, y, z, MT_RAIN); + + floorz = rainmo->floorz >> FRACBITS; + ceilingz = rainmo->ceilingz >> FRACBITS; + + if (floorz < ceilingz) + { + // Randomly assign a height, now that floorz is set. + rainmo->z = M_RandomRange(floorz, ceilingz) << FRACBITS; + } + else + { + // ...except if the floor is above the ceiling. + rainmo->z = ceilingz << FRACBITS; + } } } } @@ -10293,15 +10380,16 @@ void P_PrecipitationEffects(void) xl = players[displayplayers[0]].mo->x - 1024*FRACUNIT; xh = players[displayplayers[0]].mo->x + 1024*FRACUNIT; closedist = 2048*FRACUNIT; + for (y = yl; y >= yl && y <= yh; y += FRACUNIT*64) for (x = xl; x >= xl && x <= xh; x += FRACUNIT*64) { - if (R_PointInSubsector(x, y)->sector->ceilingpic == skyflatnum) // Found the outdoors! - { - newdist = S_CalculateSoundDistance(players[displayplayers[0]].mo->x, players[displayplayers[0]].mo->y, 0, x, y, 0); - if (newdist < closedist) - closedist = newdist; - } + if (R_PointInSubsector(x, y)->sector->ceilingpic != skyflatnum) // Found the outdoors! + continue; + + newdist = S_CalculateSoundDistance(players[displayplayers[0]].mo->x, players[displayplayers[0]].mo->y, 0, x, y, 0); + if (newdist < closedist) + closedist = newdist; } volume = 255 - (closedist>>(FRACBITS+2)); @@ -10595,6 +10683,8 @@ void P_SpawnPlayer(INT32 playernum) //P_DoPityCheck(p); p->grieftime = 0; + p->hitemtimer = 0; + p->hitemvictim = 255; if (G_BattleGametype()) // SRB2kart { @@ -10685,11 +10775,13 @@ void P_AfterPlayerSpawn(INT32 playernum) for (i = 0; i <= splitscreen; i++) { - if (camera[i].chase) - { - if (displayplayers[i] == playernum) - P_ResetCamera(p, &camera[i]); - } + if (!camera[i].chase) + continue; + + if (displayplayers[i] != playernum) + continue; + + P_ResetCamera(p, &camera[i]); } if (CheckForReverseGravity) @@ -11365,9 +11457,14 @@ ML_NOCLIMB : Direction not controllable mobj->threshold = min(mthing->extrainfo, 7); break; case MT_TUBEWAYPOINT: - mobj->health = mthing->angle & 255; - mobj->threshold = mthing->angle >> 8; + { + UINT8 sequence = mthing->angle >> 8; + UINT8 id = mthing->angle & 255; + mobj->health = id; + mobj->threshold = sequence; + P_AddWaypoint(sequence, id, mobj); break; + } case MT_NIGHTSDRONE: if (mthing->angle > 0) mobj->health = mthing->angle; @@ -11768,8 +11865,6 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing) { P_SetTarget(&mobj->hprev, nextmobj); P_SetTarget(&mobj->hprev->hnext, mobj); - //mobj->hprev = nextmobj; - //mobj->hprev->hnext = mobj; } else mobj->hprev = mobj->hnext = NULL; @@ -11801,8 +11896,6 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing) mobj->hnext = NULL; P_SetTarget(&mobj->hprev, nextmobj); P_SetTarget(&mobj->hprev->hnext, mobj); - //mobj->hprev = nextmobj; - //mobj->hprev->hnext = mobj; nextmobj = mobj; } @@ -11830,8 +11923,6 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing) mobj->hnext = NULL; P_SetTarget(&mobj->hprev, nextmobj); P_SetTarget(&mobj->hprev->hnext, mobj); - //mobj->hprev = nextmobj; - //mobj->hprev->hnext = mobj; nextmobj = mobj; } @@ -11914,8 +12005,6 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing) { P_SetTarget(&mobj->hprev, nextmobj); P_SetTarget(&mobj->hprev->hnext, mobj); - //mobj->hprev = nextmobj; - //mobj->hprev->hnext = mobj; } else mobj->hprev = mobj->hnext = NULL; @@ -11958,8 +12047,6 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing) mobj->hnext = NULL; P_SetTarget(&mobj->hprev, nextmobj); P_SetTarget(&mobj->hprev->hnext, mobj); - //mobj->hprev = nextmobj; - //mobj->hprev->hnext = mobj; nextmobj = mobj; } diff --git a/src/p_mobj.h b/src/p_mobj.h index a824edc6a..f6b27ae49 100644 --- a/src/p_mobj.h +++ b/src/p_mobj.h @@ -254,24 +254,21 @@ typedef enum // PRECIPITATION flags ?! ?! ?! // typedef enum { - // Don't draw. - PCF_INVISIBLE = 1, - // Above pit. - PCF_PIT = 2, - // Above FOF. - PCF_FOF = 4, - // Above MOVING FOF (this means we need to keep floorz up to date...) - PCF_MOVINGFOF = 8, - // Is rain. - PCF_RAIN = 16, - // Ran the thinker this tic. - PCF_THUNK = 32, + PCF_INVISIBLE = 1, // Don't draw. + PCF_PIT = 1<<1, // Above pit. + PCF_FOF = 1<<2, // Above FOF. + PCF_MOVINGFOF = 1<<3, // Above MOVING FOF (this means we need to keep floorz up to date...) + PCF_SPLASH = 1<<4, // Splashed on the ground, return to the ceiling after the animation's over + PCF_THUNK = 1<<5, // Ran the thinker this tic. } precipflag_t; // Map Object definition. typedef struct mobj_s { // List: thinker links. thinker_t thinker; + + mobjtype_t type; + const mobjinfo_t *info; // &mobjinfo[mobj->type] // Info for drawing: position. fixed_t x, y, z; @@ -345,9 +342,6 @@ typedef struct mobj_s struct mobj_s *hnext; struct mobj_s *hprev; - mobjtype_t type; - const mobjinfo_t *info; // &mobjinfo[mobj->type] - INT32 health; // for player this is rings + 1 // Movement direction, movement generation (zig-zagging). @@ -426,6 +420,9 @@ typedef struct precipmobj_s // List: thinker links. thinker_t thinker; + mobjtype_t type; + const mobjinfo_t *info; // &mobjinfo[mobj->type] + // Info for drawing: position. fixed_t x, y, z; fixed_t old_x, old_y, old_z; // position interpolation @@ -479,6 +476,7 @@ typedef struct precipmobj_s INT32 tics; // state tic counter state_t *state; INT32 flags; // flags from mobjinfo tables + tic_t lastThink; } precipmobj_t; typedef struct actioncache_s @@ -518,10 +516,9 @@ void P_SpawnParaloop(fixed_t x, fixed_t y, fixed_t z, fixed_t radius, INT32 numb boolean P_BossTargetPlayer(mobj_t *actor, boolean closest); boolean P_SupermanLook4Players(mobj_t *actor); void P_DestroyRobots(void); -void P_SnowThinker(precipmobj_t *mobj); -void P_RainThinker(precipmobj_t *mobj); +boolean P_PrecipThinker(precipmobj_t *mobj); void P_NullPrecipThinker(precipmobj_t *mobj); -void P_RemovePrecipMobj(precipmobj_t *mobj); +void P_FreePrecipMobj(precipmobj_t *mobj); void P_SetScale(mobj_t *mobj, fixed_t newscale); void P_XYMovement(mobj_t *mo); void P_EmeraldManager(void); diff --git a/src/p_polyobj.c b/src/p_polyobj.c index 9a3376595..7a21497e3 100644 --- a/src/p_polyobj.c +++ b/src/p_polyobj.c @@ -95,6 +95,8 @@ INT32 numPolyObjects; // Polyobject Blockmap -- initialized in P_LoadBlockMap polymaplink_t **polyblocklinks; +static size_t *KnownPolySides; +static size_t KnownPolySidesCount; // // Static Data @@ -152,6 +154,36 @@ FUNCINLINE static ATTRINLINE void PolyObj_AddThinker(thinker_t *th) thinkercap.next = th; } +static void FreeSideLists(void) +{ + free(KnownPolySides); + KnownPolySides = NULL; + KnownPolySidesCount = 0; +} + +//========================================================================== +// +// InitSideLists [RH] +// +// Group sides by vertex and collect side that are known to belong to a +// polyobject so that they can be initialized fast. +//========================================================================== +static void InitSideLists(void) +{ + size_t i; + FreeSideLists(); + KnownPolySides = malloc(numsegs * sizeof(KnownPolySides[0])); + for (i = 0; i < numsegs; i++) + { + if (segs[i].linedef && + (segs[i].linedef->special == POLYOBJ_START_LINE || + segs[i].linedef->special == POLYOBJ_EXPLICIT_LINE)) + { + KnownPolySides[KnownPolySidesCount++] = i; + } + } +} + // // P_PointInsidePolyobj // @@ -512,11 +544,12 @@ static void Polyobj_findExplicit(polyobj_t *po) size_t numSegItems = 0; size_t numSegItemsAlloc = 0; - size_t i; + size_t i, ii; // first loop: save off all segs with polyobject's id number - for (i = 0; i < numsegs; ++i) + for (ii = 0; ii < KnownPolySidesCount; ii++) { + i = KnownPolySides[ii]; INT32 polyID, parentID; if (segs[i].linedef->special != POLYOBJ_EXPLICIT_LINE) @@ -566,7 +599,7 @@ static void Polyobj_findExplicit(polyobj_t *po) // static void Polyobj_spawnPolyObj(INT32 num, mobj_t *spawnSpot, INT32 id) { - size_t i; + size_t i, ii; polyobj_t *po = &PolyObjects[num]; // don't spawn a polyobject more than once @@ -590,8 +623,9 @@ static void Polyobj_spawnPolyObj(INT32 num, mobj_t *spawnSpot, INT32 id) // 1. Search segs for "line start" special with tag matching this // polyobject's id number. If found, iterate through segs which // share common vertices and record them into the polyobject. - for (i = 0; i < numsegs; ++i) + for (ii = 0; ii < KnownPolySidesCount; ii++) { + i = KnownPolySides[ii]; seg_t *seg = &segs[i]; INT32 polyID, parentID; @@ -1415,7 +1449,10 @@ static boolean Polyobj_rotate(polyobj_t *po, angle_t delta, UINT8 turnthings) { // update seg angles (used only by renderer) for (i = 0; i < po->segCount; ++i) + { po->segs[i]->angle += delta; + P_UpdateSegLightOffset(po->segs[i]); + } // update polyobject's angle po->angle += delta; @@ -1514,29 +1551,29 @@ void Polyobj_InitLevel(void) // the mobj_t pointers on a queue for use below. for (th = thinkercap.next; th != &thinkercap; th = th->next) { - if (th->function.acp1 == (actionf_p1)P_MobjThinker) + if (th->function.acp1 != (actionf_p1)P_MobjThinker) + continue; + + mobj_t *mo = (mobj_t *)th; + + if (mo->info->doomednum == POLYOBJ_SPAWN_DOOMEDNUM || + mo->info->doomednum == POLYOBJ_SPAWNCRUSH_DOOMEDNUM) { - mobj_t *mo = (mobj_t *)th; + ++numPolyObjects; - if (mo->info->doomednum == POLYOBJ_SPAWN_DOOMEDNUM || - mo->info->doomednum == POLYOBJ_SPAWNCRUSH_DOOMEDNUM) - { - ++numPolyObjects; + qitem = malloc(sizeof(mobjqitem_t)); + memset(qitem, 0, sizeof(mobjqitem_t)); + qitem->mo = mo; + M_QueueInsert(&(qitem->mqitem), &spawnqueue); + } + else if (mo->info->doomednum == POLYOBJ_ANCHOR_DOOMEDNUM) + { + ++numAnchors; - qitem = malloc(sizeof(mobjqitem_t)); - memset(qitem, 0, sizeof(mobjqitem_t)); - qitem->mo = mo; - M_QueueInsert(&(qitem->mqitem), &spawnqueue); - } - else if (mo->info->doomednum == POLYOBJ_ANCHOR_DOOMEDNUM) - { - ++numAnchors; - - qitem = malloc(sizeof(mobjqitem_t)); - memset(qitem, 0, sizeof(mobjqitem_t)); - qitem->mo = mo; - M_QueueInsert(&(qitem->mqitem), &anchorqueue); - } + qitem = malloc(sizeof(mobjqitem_t)); + memset(qitem, 0, sizeof(mobjqitem_t)); + qitem->mo = mo; + M_QueueInsert(&(qitem->mqitem), &anchorqueue); } } @@ -1550,6 +1587,9 @@ void Polyobj_InitLevel(void) for (i = 0; i < numPolyObjects; ++i) PolyObjects[i].first = PolyObjects[i].next = numPolyObjects; + // [RH] Make this faster + InitSideLists(); + // setup polyobjects for (i = 0; i < numPolyObjects; ++i) { @@ -1558,6 +1598,9 @@ void Polyobj_InitLevel(void) Polyobj_spawnPolyObj(i, qitem->mo, qitem->mo->spawnpoint->angle); } + // [RH] Don't need the side lists anymore + FreeSideLists(); + // move polyobjects to spawn points for (i = 0; i < numAnchors; ++i) { @@ -1571,39 +1614,6 @@ void Polyobj_InitLevel(void) Polyobj_linkToBlockmap(&PolyObjects[i]); } -#if 0 - // haleyjd 02/22/06: temporary debug - printf("DEBUG: numPolyObjects = %d\n", numPolyObjects); - for (i = 0; i < numPolyObjects; ++i) - { - INT32 j; - polyobj_t *po = &PolyObjects[i]; - - printf("polyobj %d:\n", i); - printf("id = %d, first = %d, next = %d\n", po->id, po->first, po->next); - printf("segCount = %d, numSegsAlloc = %d\n", po->segCount, po->numSegsAlloc); - for (j = 0; j < po->segCount; ++j) - printf("\tseg %d: %p\n", j, po->segs[j]); - printf("numVertices = %d, numVerticesAlloc = %d\n", po->numVertices, po->numVerticesAlloc); - for (j = 0; j < po->numVertices; ++j) - { - printf("\tvtx %d: (%d, %d) / orig: (%d, %d)\n", - j, po->vertices[j]->x>>FRACBITS, po->vertices[j]->y>>FRACBITS, - po->origVerts[j].x>>FRACBITS, po->origVerts[j].y>>FRACBITS); - } - printf("numLines = %d, numLinesAlloc = %d\n", po->numLines, po->numLinesAlloc); - for (j = 0; j < po->numLines; ++j) - printf("\tline %d: %p\n", j, po->lines[j]); - printf("spawnSpot = (%d, %d)\n", po->spawnSpot.x >> FRACBITS, po->spawnSpot.y >> FRACBITS); - printf("centerPt = (%d, %d)\n", po->centerPt.x >> FRACBITS, po->centerPt.y >> FRACBITS); - printf("attached = %d, linked = %d, validcount = %d, isBad = %d\n", - po->attached, po->linked, po->validcount, po->isBad); - printf("blockbox: [%d, %d, %d, %d]\n", - po->blockbox[BOXLEFT], po->blockbox[BOXRIGHT], po->blockbox[BOXBOTTOM], - po->blockbox[BOXTOP]); - } -#endif - // done with mobj queues M_QueueFree(&spawnqueue); M_QueueFree(&anchorqueue); @@ -1789,12 +1799,12 @@ void T_PolyObjMove(polymove_t *th) // void T_PolyObjWaypoint(polywaypoint_t *th) { - mobj_t *mo2; mobj_t *target = NULL; mobj_t *waypoint = NULL; - thinker_t *wp; + mobj_t *mo2; fixed_t adjustx, adjusty, adjustz; fixed_t momx, momy, momz, dist; + thinker_t *wp; INT32 start; polyobj_t *po = Polyobj_GetForNum(th->polyObjNum); polyobj_t *oldpo = po; @@ -1811,7 +1821,7 @@ void T_PolyObjWaypoint(polywaypoint_t *th) #endif // check for displacement due to override and reattach when possible - if (po->thinker == NULL) + if (!po->thinker) po->thinker = &th->thinker; // Find out target first. @@ -1826,11 +1836,14 @@ void T_PolyObjWaypoint(polywaypoint_t *th) if (mo2->type != MT_TUBEWAYPOINT) continue; - if (mo2->threshold == th->sequence && mo2->health == th->pointnum) - { - target = mo2; - break; - } + if (mo2->threshold != th->sequence) + continue; + + if (mo2->health != th->pointnum) + continue; + + target = mo2; + break; } if (!target) @@ -1896,37 +1909,7 @@ void T_PolyObjWaypoint(polywaypoint_t *th) { CONS_Debug(DBG_POLYOBJ, "Looking for next waypoint...\n"); - // Find next waypoint - for (wp = thinkercap.next; wp != &thinkercap; wp = wp->next) - { - if (wp->function.acp1 != (actionf_p1)P_MobjThinker) // Not a mobj thinker - continue; - - mo2 = (mobj_t *)wp; - - if (mo2->type != MT_TUBEWAYPOINT) - continue; - - if (mo2->threshold == th->sequence) - { - if (th->direction == -1) - { - if (mo2->health == target->health - 1) - { - waypoint = mo2; - break; - } - } - else - { - if (mo2->health == target->health + 1) - { - waypoint = mo2; - break; - } - } - } - } + waypoint = (th->direction == -1) ? P_GetPreviousWaypoint(target, false) : P_GetNextWaypoint(target, false); if (!waypoint && th->wrap) // If specified, wrap waypoints { @@ -1936,35 +1919,7 @@ void T_PolyObjWaypoint(polywaypoint_t *th) th->stophere = true; } - for (wp = thinkercap.next; wp != &thinkercap; wp = wp->next) - { - if (wp->function.acp1 != (actionf_p1)P_MobjThinker) // Not a mobj thinker - continue; - - mo2 = (mobj_t *)wp; - - if (mo2->type != MT_TUBEWAYPOINT) - continue; - - if (mo2->threshold == th->sequence) - { - if (th->direction == -1) - { - if (waypoint == NULL) - waypoint = mo2; - else if (mo2->health > waypoint->health) - waypoint = mo2; - } - else - { - if (mo2->health == 0) - { - waypoint = mo2; - break; - } - } - } - } + waypoint = (th->direction == -1) ? P_GetLastWaypoint(th->sequence) : P_GetFirstWaypoint(th->sequence); } else if (!waypoint && th->comeback) // Come back to the start { @@ -1973,36 +1928,7 @@ void T_PolyObjWaypoint(polywaypoint_t *th) if (!th->continuous) th->comeback = false; - for (wp = thinkercap.next; wp != &thinkercap; wp = wp->next) - { - if (wp->function.acp1 != (actionf_p1)P_MobjThinker) // Not a mobj thinker - continue; - - mo2 = (mobj_t *)wp; - - if (mo2->type != MT_TUBEWAYPOINT) - continue; - - if (mo2->threshold == th->sequence) - { - if (th->direction == -1) - { - if (mo2->health == target->health - 1) - { - waypoint = mo2; - break; - } - } - else - { - if (mo2->health == target->health + 1) - { - waypoint = mo2; - break; - } - } - } - } + waypoint = (th->direction == -1) ? P_GetPreviousWaypoint(target, false) : P_GetNextWaypoint(target, false); } } @@ -2452,11 +2378,9 @@ INT32 EV_DoPolyObjWaypoint(polywaypointdata_t *pwdata) polyobj_t *po; polyobj_t *oldpo; polywaypoint_t *th; - mobj_t *mo2; mobj_t *first = NULL; mobj_t *last = NULL; mobj_t *target = NULL; - thinker_t *wp; INT32 start; if (!(po = Polyobj_GetForNum(pwdata->polyObjNum))) @@ -2482,10 +2406,7 @@ INT32 EV_DoPolyObjWaypoint(polywaypointdata_t *pwdata) th->polyObjNum = pwdata->polyObjNum; th->speed = pwdata->speed; th->sequence = pwdata->sequence; // Used to specify sequence # - if (pwdata->reverse) - th->direction = -1; - else - th->direction = 1; + th->direction = pwdata->reverse ? -1 : 1; th->comeback = pwdata->comeback; th->continuous = pwdata->continuous; @@ -2493,44 +2414,8 @@ INT32 EV_DoPolyObjWaypoint(polywaypointdata_t *pwdata) th->stophere = false; // Find the first waypoint we need to use - for (wp = thinkercap.next; wp != &thinkercap; wp = wp->next) - { - if (wp->function.acp1 != (actionf_p1)P_MobjThinker) // Not a mobj thinker - continue; - - mo2 = (mobj_t *)wp; - - if (mo2->type != MT_TUBEWAYPOINT) - continue; - - if (mo2->threshold == th->sequence) - { - if (th->direction == -1) // highest waypoint # - { - if (mo2->health == 0) - last = mo2; - else - { - if (first == NULL) - first = mo2; - else if (mo2->health > first->health) - first = mo2; - } - } - else // waypoint 0 - { - if (mo2->health == 0) - first = mo2; - else - { - if (last == NULL) - last = mo2; - else if (mo2->health > last->health) - last = mo2; - } - } - } - } + first = (th->direction == -1) ? P_GetLastWaypoint(th->sequence) : P_GetFirstWaypoint(th->sequence); + last = (th->direction == -1) ? P_GetFirstWaypoint(th->sequence) : P_GetLastWaypoint(th->sequence); if (!first) { @@ -2564,36 +2449,6 @@ INT32 EV_DoPolyObjWaypoint(polywaypointdata_t *pwdata) // Find the actual target movement waypoint target = first; - /*for (wp = thinkercap.next; wp != &thinkercap; wp = wp->next) - { - if (wp->function.acp1 != (actionf_p1)P_MobjThinker) // Not a mobj thinker - continue; - - mo2 = (mobj_t *)wp; - - if (mo2->type != MT_TUBEWAYPOINT) - continue; - - if (mo2->threshold == th->sequence) - { - if (th->direction == -1) // highest waypoint # - { - if (mo2->health == first->health - 1) - { - target = mo2; - break; - } - } - else // waypoint 0 - { - if (mo2->health == first->health + 1) - { - target = mo2; - break; - } - } - } - }*/ if (!target) { diff --git a/src/p_saveg.c b/src/p_saveg.c index 6469574c8..b8a517f0e 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -107,7 +107,7 @@ static inline void P_UnArchivePlayer(void) // // P_NetArchivePlayers // -static void P_NetArchivePlayers(void) +static void P_NetArchivePlayers(boolean resending) { INT32 i, j; UINT16 flags; @@ -117,6 +117,9 @@ static void P_NetArchivePlayers(void) for (i = 0; i < MAXPLAYERS; i++) { + if (resending) + WRITESINT8(save_p, (SINT8)adminplayers[i]); + if (!playeringame[i]) continue; @@ -124,6 +127,9 @@ static void P_NetArchivePlayers(void) // no longer send ticcmds, player name, skin, or color + if (resending) + WRITESTRINGN(save_p, player_names[i], MAXPLAYERNAME); + WRITEANGLE(save_p, players[i].aiming); WRITEANGLE(save_p, players[i].awayviewaiming); WRITEINT32(save_p, players[i].awayviewtics); @@ -148,6 +154,13 @@ static void P_NetArchivePlayers(void) WRITEUINT16(save_p, players[i].flashpal); WRITEUINT16(save_p, players[i].flashcount); + if (resending) + { + WRITEUINT8(save_p, players[i].skincolor); + WRITEINT32(save_p, players[i].skin); + } + + WRITEUINT32(save_p, players[i].score); WRITEFIXED(save_p, players[i].dashspeed); WRITEINT32(save_p, players[i].dashtime); @@ -285,7 +298,7 @@ static void P_NetArchivePlayers(void) // // P_NetUnArchivePlayers // -static void P_NetUnArchivePlayers(void) +static void P_NetUnArchivePlayers(boolean resending) { INT32 i, j; UINT16 flags; @@ -295,6 +308,8 @@ static void P_NetUnArchivePlayers(void) for (i = 0; i < MAXPLAYERS; i++) { + if (resending) + adminplayers[i] = (INT32)READSINT8(save_p); // Do NOT memset player struct to 0 // other areas may initialize data elsewhere //memset(&players[i], 0, sizeof (player_t)); @@ -305,6 +320,9 @@ static void P_NetUnArchivePlayers(void) // sending player names, skin and color should not be necessary at all! // (that data is handled in the server config now) + if (resending) + READSTRINGN(save_p, player_names[i], MAXPLAYERNAME); + players[i].aiming = READANGLE(save_p); players[i].awayviewaiming = READANGLE(save_p); players[i].awayviewtics = READINT32(save_p); @@ -329,6 +347,12 @@ static void P_NetUnArchivePlayers(void) players[i].flashpal = READUINT16(save_p); players[i].flashcount = READUINT16(save_p); + if (resending) + { + players[i].skincolor = READUINT8(save_p); + players[i].skin = READINT32(save_p); + } + players[i].score = READUINT32(save_p); players[i].dashspeed = READFIXED(save_p); // dashing speed players[i].dashtime = READINT32(save_p); // dashing speed @@ -499,35 +523,16 @@ static void P_NetArchiveWorld(void) UINT8 *put; // reload the map just to see difference - mapsector_t *ms; - mapsidedef_t *msd; - maplinedef_t *mld; + virtres_t* virt = vres_GetMap(lastloadedmaplumpnum); + mapsector_t *ms = (mapsector_t*) vres_Find(virt, "SECTORS")->data; + mapsidedef_t *msd = (mapsidedef_t*) vres_Find(virt, "SIDEDEFS")->data; + maplinedef_t *mld = (maplinedef_t*) vres_Find(virt, "LINEDEFS")->data; const sector_t *ss = sectors; UINT8 diff, diff2; WRITEUINT32(save_p, ARCHIVEBLOCK_WORLD); put = save_p; - if (W_IsLumpWad(lastloadedmaplumpnum)) // welp it's a map wad in a pk3 - { // HACK: Open wad file rather quickly so we can get the data from the relevant lumps - UINT8 *wadData = W_CacheLumpNum(lastloadedmaplumpnum, PU_STATIC); - filelump_t *fileinfo = (filelump_t *)(wadData + ((wadinfo_t *)wadData)->infotableofs); -#define retrieve_mapdata(d, f)\ - d = Z_Malloc((f)->size, PU_CACHE, NULL); \ - M_Memcpy(d, wadData + (f)->filepos, (f)->size) - retrieve_mapdata(ms, fileinfo + ML_SECTORS); - retrieve_mapdata(mld, fileinfo + ML_LINEDEFS); - retrieve_mapdata(msd, fileinfo + ML_SIDEDEFS); -#undef retrieve_mapdata - Z_Free(wadData); // we're done with this now - } - else // phew it's just a WAD - { - ms = W_CacheLumpNum(lastloadedmaplumpnum+ML_SECTORS, PU_CACHE); - mld = W_CacheLumpNum(lastloadedmaplumpnum+ML_LINEDEFS, PU_CACHE); - msd = W_CacheLumpNum(lastloadedmaplumpnum+ML_SIDEDEFS, PU_CACHE); - } - for (i = 0; i < numsectors; i++, ss++, ms++) { diff = diff2 = 0; @@ -737,6 +742,7 @@ static void P_NetArchiveWorld(void) WRITEUINT16(put, 0xffff); R_ClearTextureNumCache(false); + vres_Free(virt); save_p = put; } @@ -1874,7 +1880,7 @@ static void P_NetArchiveThinkers(void) continue; } #ifdef PARANOIA - else if (th->function.acv != P_RemoveThinkerDelayed) // wait garbage collection + else if (th->function.acp1 != P_RemoveThinkerDelayed) // wait garbage collection I_Error("unknown thinker type %p", th->function.acp1); #endif } @@ -1899,8 +1905,11 @@ mobj_t *P_FindNewPosition(UINT32 oldposition) continue; mobj = (mobj_t *)th; - if (mobj->mobjnum == oldposition) - return mobj; + + if (mobj->mobjnum != oldposition) + continue; + + return mobj; } CONS_Debug(DBG_GAMELOGIC, "mobj not found\n"); return NULL; @@ -2899,12 +2908,13 @@ static void P_NetUnArchiveThinkers(void) for (currentthinker = thinkercap.next; currentthinker != &thinkercap; currentthinker = currentthinker->next) { - if (currentthinker->function.acp1 == (actionf_p1)T_ExecutorDelay) - { - delay = (void *)currentthinker; - if ((mobjnum = (UINT32)(size_t)delay->caller)) - delay->caller = P_FindNewPosition(mobjnum); - } + if (currentthinker->function.acp1 != (actionf_p1)T_ExecutorDelay) + continue; + + delay = (void *)currentthinker; + + if ((mobjnum = (UINT32)(size_t)delay->caller)) + delay->caller = P_FindNewPosition(mobjnum); } } } @@ -3013,11 +3023,11 @@ static inline void P_FinishMobjs(void) for (currentthinker = thinkercap.next; currentthinker != &thinkercap; currentthinker = currentthinker->next) { - if (currentthinker->function.acp1 == (actionf_p1)P_MobjThinker) - { - mobj = (mobj_t *)currentthinker; - mobj->info = &mobjinfo[mobj->type]; - } + if (currentthinker->function.acp1 != (actionf_p1)P_MobjThinker) + continue; + + mobj = (mobj_t *)currentthinker; + mobj->info = &mobjinfo[mobj->type]; } } @@ -3031,69 +3041,69 @@ static void P_RelinkPointers(void) for (currentthinker = thinkercap.next; currentthinker != &thinkercap; currentthinker = currentthinker->next) { - if (currentthinker->function.acp1 == (actionf_p1)P_MobjThinker) + if (currentthinker->function.acp1 != (actionf_p1)P_MobjThinker) + continue; + + mobj = (mobj_t *)currentthinker; + + if (mobj->type == MT_HOOP || mobj->type == MT_HOOPCOLLIDE || mobj->type == MT_HOOPCENTER) + continue; + + if (mobj->tracer) { - mobj = (mobj_t *)currentthinker; - - if (mobj->type == MT_HOOP || mobj->type == MT_HOOPCOLLIDE || mobj->type == MT_HOOPCENTER) - continue; - - if (mobj->tracer) - { - temp = (UINT32)(size_t)mobj->tracer; - mobj->tracer = NULL; - if (!P_SetTarget(&mobj->tracer, P_FindNewPosition(temp))) - CONS_Debug(DBG_GAMELOGIC, "tracer not found on %d\n", mobj->type); - } - if (mobj->target) - { - temp = (UINT32)(size_t)mobj->target; - mobj->target = NULL; - if (!P_SetTarget(&mobj->target, P_FindNewPosition(temp))) - CONS_Debug(DBG_GAMELOGIC, "target not found on %d\n", mobj->type); - } - if (mobj->hnext) - { - temp = (UINT32)(size_t)mobj->hnext; - mobj->hnext = NULL; - if (!P_SetTarget(&mobj->hnext, P_FindNewPosition(temp))) - CONS_Debug(DBG_GAMELOGIC, "hnext not found on %d\n", mobj->type); - } - if (mobj->hprev) - { - temp = (UINT32)(size_t)mobj->hprev; - mobj->hprev = NULL; - if (!P_SetTarget(&mobj->hprev, P_FindNewPosition(temp))) - CONS_Debug(DBG_GAMELOGIC, "hprev not found on %d\n", mobj->type); - } - if (mobj->player && mobj->player->capsule) - { - temp = (UINT32)(size_t)mobj->player->capsule; - mobj->player->capsule = NULL; - if (!P_SetTarget(&mobj->player->capsule, P_FindNewPosition(temp))) - CONS_Debug(DBG_GAMELOGIC, "capsule not found on %d\n", mobj->type); - } - if (mobj->player && mobj->player->axis1) - { - temp = (UINT32)(size_t)mobj->player->axis1; - mobj->player->axis1 = NULL; - if (!P_SetTarget(&mobj->player->axis1, P_FindNewPosition(temp))) - CONS_Debug(DBG_GAMELOGIC, "axis1 not found on %d\n", mobj->type); - } - if (mobj->player && mobj->player->axis2) - { - temp = (UINT32)(size_t)mobj->player->axis2; - mobj->player->axis2 = NULL; - if (!P_SetTarget(&mobj->player->axis2, P_FindNewPosition(temp))) - CONS_Debug(DBG_GAMELOGIC, "axis2 not found on %d\n", mobj->type); - } - if (mobj->player && mobj->player->awayviewmobj) - { - temp = (UINT32)(size_t)mobj->player->awayviewmobj; - mobj->player->awayviewmobj = NULL; - if (!P_SetTarget(&mobj->player->awayviewmobj, P_FindNewPosition(temp))) - CONS_Debug(DBG_GAMELOGIC, "awayviewmobj not found on %d\n", mobj->type); - } + temp = (UINT32)(size_t)mobj->tracer; + mobj->tracer = NULL; + if (!P_SetTarget(&mobj->tracer, P_FindNewPosition(temp))) + CONS_Debug(DBG_GAMELOGIC, "tracer not found on %d\n", mobj->type); + } + if (mobj->target) + { + temp = (UINT32)(size_t)mobj->target; + mobj->target = NULL; + if (!P_SetTarget(&mobj->target, P_FindNewPosition(temp))) + CONS_Debug(DBG_GAMELOGIC, "target not found on %d\n", mobj->type); + } + if (mobj->hnext) + { + temp = (UINT32)(size_t)mobj->hnext; + mobj->hnext = NULL; + if (!P_SetTarget(&mobj->hnext, P_FindNewPosition(temp))) + CONS_Debug(DBG_GAMELOGIC, "hnext not found on %d\n", mobj->type); + } + if (mobj->hprev) + { + temp = (UINT32)(size_t)mobj->hprev; + mobj->hprev = NULL; + if (!P_SetTarget(&mobj->hprev, P_FindNewPosition(temp))) + CONS_Debug(DBG_GAMELOGIC, "hprev not found on %d\n", mobj->type); + } + if (mobj->player && mobj->player->capsule) + { + temp = (UINT32)(size_t)mobj->player->capsule; + mobj->player->capsule = NULL; + if (!P_SetTarget(&mobj->player->capsule, P_FindNewPosition(temp))) + CONS_Debug(DBG_GAMELOGIC, "capsule not found on %d\n", mobj->type); + } + if (mobj->player && mobj->player->axis1) + { + temp = (UINT32)(size_t)mobj->player->axis1; + mobj->player->axis1 = NULL; + if (!P_SetTarget(&mobj->player->axis1, P_FindNewPosition(temp))) + CONS_Debug(DBG_GAMELOGIC, "axis1 not found on %d\n", mobj->type); + } + if (mobj->player && mobj->player->axis2) + { + temp = (UINT32)(size_t)mobj->player->axis2; + mobj->player->axis2 = NULL; + if (!P_SetTarget(&mobj->player->axis2, P_FindNewPosition(temp))) + CONS_Debug(DBG_GAMELOGIC, "axis2 not found on %d\n", mobj->type); + } + if (mobj->player && mobj->player->awayviewmobj) + { + temp = (UINT32)(size_t)mobj->player->awayviewmobj; + mobj->player->awayviewmobj = NULL; + if (!P_SetTarget(&mobj->player->awayviewmobj, P_FindNewPosition(temp))) + CONS_Debug(DBG_GAMELOGIC, "awayviewmobj not found on %d\n", mobj->type); } } } @@ -3242,19 +3252,25 @@ static inline void P_UnArchiveSPGame(INT16 mapoverride) playeringame[consoleplayer] = true; } -static void P_NetArchiveMisc(void) +static void P_NetArchiveMisc(boolean resending) { UINT32 pig = 0; INT32 i; WRITEUINT32(save_p, ARCHIVEBLOCK_MISC); + if (resending) + WRITEUINT32(save_p, gametic); + WRITEINT16(save_p, gamemap); if (gamestate != GS_LEVEL) WRITEINT16(save_p, GS_WAITINGPLAYERS); // nice hack to put people back into waitingplayers else WRITEINT16(save_p, gamestate); + if (resending) + WRITEINT16(save_p, gametype); + for (i = 0; i < MAXPLAYERS; i++) pig |= (playeringame[i] != 0)<next) { - if (th->function.acp1 == (actionf_p1)P_MobjThinker) - { - mobj = (mobj_t *)th; - if (mobj->type == MT_HOOP || mobj->type == MT_HOOPCOLLIDE || mobj->type == MT_HOOPCENTER) - continue; - mobj->mobjnum = i++; - } + if (th->function.acp1 != (actionf_p1)P_MobjThinker) + continue; + + mobj = (mobj_t *)th; + + if (mobj->type == MT_HOOP || mobj->type == MT_HOOPCOLLIDE || mobj->type == MT_HOOPCENTER) + continue; + + mobj->mobjnum = i++; } } - P_NetArchivePlayers(); + P_NetArchivePlayers(resending); if (gamestate == GS_LEVEL) { P_NetArchiveWorld(); @@ -3514,12 +3548,12 @@ boolean P_LoadGame(INT16 mapoverride) return true; } -boolean P_LoadNetGame(void) +boolean P_LoadNetGame(boolean resending) { CV_LoadNetVars(&save_p); - if (!P_NetUnArchiveMisc()) + if (!P_NetUnArchiveMisc(resending)) return false; - P_NetUnArchivePlayers(); + P_NetUnArchivePlayers(resending); if (gamestate == GS_LEVEL) { P_NetUnArchiveWorld(); diff --git a/src/p_saveg.h b/src/p_saveg.h index 0992f1185..9e73ad8fc 100644 --- a/src/p_saveg.h +++ b/src/p_saveg.h @@ -22,9 +22,9 @@ // These are the load / save game routines. void P_SaveGame(void); -void P_SaveNetGame(void); +void P_SaveNetGame(boolean resending); boolean P_LoadGame(INT16 mapoverride); -boolean P_LoadNetGame(void); +boolean P_LoadNetGame(boolean resending); mobj_t *P_FindNewPosition(UINT32 oldposition); diff --git a/src/p_setup.c b/src/p_setup.c index c99326116..4f55b4609 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -77,12 +77,12 @@ #endif #ifdef HWRENDER #include "hardware/hw_main.h" -#include "hardware/hw_light.h" #endif #include "p_slopes.h" // SRB2Kart +#include "k_director.h" // K_InitDirector #include "k_kart.h" // @@ -109,6 +109,8 @@ INT32 numstarposts; boolean levelloading; UINT8 levelfadecol; +virtres_t *curmapvirt; + // BLOCKMAP // Created from axis aligned bounding box // of the map, a rectangular array of @@ -144,12 +146,109 @@ mapthing_t *playerstarts[MAXPLAYERS]; mapthing_t *bluectfstarts[MAXPLAYERS]; mapthing_t *redctfstarts[MAXPLAYERS]; +// Maintain waypoints +mobj_t *waypoints[NUMWAYPOINTSEQUENCES][WAYPOINTSEQUENCESIZE]; +UINT16 numwaypoints[NUMWAYPOINTSEQUENCES]; + +void P_AddWaypoint(UINT8 sequence, UINT8 id, mobj_t *waypoint) +{ + waypoints[sequence][id] = waypoint; + if (id >= numwaypoints[sequence]) + numwaypoints[sequence] = id + 1; +} + +static void P_ResetWaypoints(void) +{ + UINT16 sequence, id; + for (sequence = 0; sequence < NUMWAYPOINTSEQUENCES; sequence++) + { + for (id = 0; id < numwaypoints[sequence]; id++) + waypoints[sequence][id] = NULL; + + numwaypoints[sequence] = 0; + } +} + +mobj_t *P_GetFirstWaypoint(UINT8 sequence) +{ + return waypoints[sequence][0]; +} + +mobj_t *P_GetLastWaypoint(UINT8 sequence) +{ + return waypoints[sequence][numwaypoints[sequence] - 1]; +} + +mobj_t *P_GetPreviousWaypoint(mobj_t *current, boolean wrap) +{ + UINT8 sequence = current->threshold; + UINT8 id = current->health; + + if (id == 0) + { + if (!wrap) + return NULL; + + id = numwaypoints[sequence] - 1; + } + else + id--; + + return waypoints[sequence][id]; +} + +mobj_t *P_GetNextWaypoint(mobj_t *current, boolean wrap) +{ + UINT8 sequence = current->threshold; + UINT8 id = current->health; + + if (id == numwaypoints[sequence] - 1) + { + if (!wrap) + return NULL; + + id = 0; + } + else + id++; + + return waypoints[sequence][id]; +} + +mobj_t *P_GetClosestWaypoint(UINT8 sequence, mobj_t *mo) +{ + UINT8 wp; + mobj_t *mo2, *result = NULL; + fixed_t bestdist = 0; + fixed_t curdist; + + for (wp = 0; wp < numwaypoints[sequence]; wp++) + { + mo2 = waypoints[sequence][wp]; + + if (!mo2) + continue; + + curdist = P_AproxDistance(P_AproxDistance(mo->x - mo2->x, mo->y - mo2->y), mo->z - mo2->z); + + if (result && curdist > bestdist) + continue; + + result = mo2; + bestdist = curdist; + } + + return result; +} + // Global state for PartialAddWadFile/MultiSetupWadFiles // Might be replacable with parameters, but non-trivial when the functions are called on separate tics static SINT8 partadd_stage = -1; static boolean partadd_replacescurrentmap = false; static boolean partadd_important = false; +SINT8 midgamejoin = 0; + /** Logs an error about a map being corrupt, then terminate. * This allows reporting highly technical errors for usefulness, without * confusing a novice map designer who simply needs to run ZenNode. @@ -187,83 +286,47 @@ FUNCNORETURN static ATTRNORETURN void CorruptMapError(const char *msg) static void P_ClearSingleMapHeaderInfo(INT16 i) { const INT16 num = (INT16)(i-1); - DEH_WriteUndoline("LEVELNAME", mapheaderinfo[num]->lvlttl, UNDO_NONE); mapheaderinfo[num]->lvlttl[0] = '\0'; - DEH_WriteUndoline("SUBTITLE", mapheaderinfo[num]->subttl, UNDO_NONE); mapheaderinfo[num]->subttl[0] = '\0'; - DEH_WriteUndoline("ZONETITLE", mapheaderinfo[num]->zonttl, UNDO_NONE); // SRB2kart mapheaderinfo[num]->zonttl[0] = '\0'; - DEH_WriteUndoline("ACT", mapheaderinfo[num]->actnum, UNDO_NONE); // SRB2kart mapheaderinfo[num]->actnum[0] = '\0'; - DEH_WriteUndoline("TYPEOFLEVEL", va("%d", mapheaderinfo[num]->typeoflevel), UNDO_NONE); mapheaderinfo[num]->typeoflevel = 0; - DEH_WriteUndoline("NEXTLEVEL", va("%d", mapheaderinfo[num]->nextlevel), UNDO_NONE); mapheaderinfo[num]->nextlevel = (INT16)(i + 1); - DEH_WriteUndoline("MUSIC", mapheaderinfo[num]->musname, UNDO_NONE); snprintf(mapheaderinfo[num]->musname, 7, "%sM", G_BuildMapName(i)); mapheaderinfo[num]->musname[6] = 0; - DEH_WriteUndoline("MUSICTRACK", va("%d", mapheaderinfo[num]->mustrack), UNDO_NONE); mapheaderinfo[num]->mustrack = 0; - DEH_WriteUndoline("MUSICPOS", va("%d", mapheaderinfo[num]->muspos), UNDO_NONE); mapheaderinfo[num]->muspos = 0; - DEH_WriteUndoline("MUSICINTERFADEOUT", va("%d", mapheaderinfo[num]->musinterfadeout), UNDO_NONE); mapheaderinfo[num]->musinterfadeout = 0; - DEH_WriteUndoline("MUSICINTER", mapheaderinfo[num]->musintername, UNDO_NONE); mapheaderinfo[num]->musintername[0] = '\0'; - DEH_WriteUndoline("FORCECHARACTER", va("%d", mapheaderinfo[num]->forcecharacter), UNDO_NONE); mapheaderinfo[num]->forcecharacter[0] = '\0'; - DEH_WriteUndoline("WEATHER", va("%d", mapheaderinfo[num]->weather), UNDO_NONE); mapheaderinfo[num]->weather = 0; - DEH_WriteUndoline("SKYNUM", va("%d", mapheaderinfo[num]->skynum), UNDO_NONE); mapheaderinfo[num]->skynum = 1; - DEH_WriteUndoline("SKYBOXSCALEX", va("%d", mapheaderinfo[num]->skybox_scalex), UNDO_NONE); mapheaderinfo[num]->skybox_scalex = 16; - DEH_WriteUndoline("SKYBOXSCALEY", va("%d", mapheaderinfo[num]->skybox_scaley), UNDO_NONE); mapheaderinfo[num]->skybox_scaley = 16; - DEH_WriteUndoline("SKYBOXSCALEZ", va("%d", mapheaderinfo[num]->skybox_scalez), UNDO_NONE); mapheaderinfo[num]->skybox_scalez = 16; - DEH_WriteUndoline("INTERSCREEN", mapheaderinfo[num]->interscreen, UNDO_NONE); mapheaderinfo[num]->interscreen[0] = '#'; - DEH_WriteUndoline("RUNSOC", mapheaderinfo[num]->runsoc, UNDO_NONE); mapheaderinfo[num]->runsoc[0] = '#'; - DEH_WriteUndoline("SCRIPTNAME", mapheaderinfo[num]->scriptname, UNDO_NONE); mapheaderinfo[num]->scriptname[0] = '#'; - DEH_WriteUndoline("PRECUTSCENENUM", va("%d", mapheaderinfo[num]->precutscenenum), UNDO_NONE); mapheaderinfo[num]->precutscenenum = 0; - DEH_WriteUndoline("CUTSCENENUM", va("%d", mapheaderinfo[num]->cutscenenum), UNDO_NONE); mapheaderinfo[num]->cutscenenum = 0; - DEH_WriteUndoline("COUNTDOWN", va("%d", mapheaderinfo[num]->countdown), UNDO_NONE); mapheaderinfo[num]->countdown = 0; - DEH_WriteUndoline("PALLETE", va("%u", mapheaderinfo[num]->palette), UNDO_NONE); mapheaderinfo[num]->palette = UINT16_MAX; - DEH_WriteUndoline("ENCOREPAL", va("%u", mapheaderinfo[num]->encorepal), UNDO_NONE); mapheaderinfo[num]->encorepal = UINT16_MAX; - DEH_WriteUndoline("NUMLAPS", va("%u", mapheaderinfo[num]->numlaps), UNDO_NONE); mapheaderinfo[num]->numlaps = NUMLAPS_DEFAULT; - DEH_WriteUndoline("UNLOCKABLE", va("%s", mapheaderinfo[num]->unlockrequired), UNDO_NONE); mapheaderinfo[num]->unlockrequired = -1; - DEH_WriteUndoline("LEVELSELECT", va("%d", mapheaderinfo[num]->levelselect), UNDO_NONE); mapheaderinfo[num]->levelselect = 0; - DEH_WriteUndoline("BONUSTYPE", va("%d", mapheaderinfo[num]->bonustype), UNDO_NONE); mapheaderinfo[num]->bonustype = 0; - DEH_WriteUndoline("SAVEOVERRIDE", va("%d", mapheaderinfo[num]->saveoverride), UNDO_NONE); mapheaderinfo[num]->saveoverride = SAVE_DEFAULT; - DEH_WriteUndoline("LEVELFLAGS", va("%d", mapheaderinfo[num]->levelflags), UNDO_NONE); mapheaderinfo[num]->levelflags = 0; - DEH_WriteUndoline("MENUFLAGS", va("%d", mapheaderinfo[num]->menuflags), UNDO_NONE); mapheaderinfo[num]->menuflags = (mainwads ? 0 : LF2_EXISTSHACK); // see p_setup.c - prevents replacing maps in addons with easier versions // TODO grades support for delfile (pfft yeah right) P_DeleteGrades(num); // SRB2Kart - //DEH_WriteUndoline("AUTOMAP", va("%d", mapheaderinfo[num]->automap), UNDO_NONE); //mapheaderinfo[num]->automap = false; - DEH_WriteUndoline("MOBJSCALE", va("%d", mapheaderinfo[num]->mobj_scale), UNDO_NONE); mapheaderinfo[num]->mobj_scale = FRACUNIT; // an even further impossibility, delfile custom opts support mapheaderinfo[num]->customopts = NULL; mapheaderinfo[num]->numCustomOptions = 0; - - DEH_WriteUndoline(va("# uload for map %d", i), NULL, UNDO_DONE); } /** Allocates a new map-header structure. @@ -377,27 +440,12 @@ UINT32 P_GetScoreForGrade(INT16 map, UINT8 mare, UINT8 grade) return mapheaderinfo[map-1]->grades[mare].grade[grade-1]; } -/** Loads the vertexes for a level. - * - * \param lump VERTEXES lump number. - * \sa ML_VERTEXES - */ - -FUNCINLINE static ATTRINLINE void P_LoadRawVertexes(UINT8 *data, size_t i) +// Loads the vertexes for a level. +FUNCINLINE static ATTRINLINE void P_LoadRawVertexes(UINT8 *data) { - mapvertex_t *ml; - vertex_t *li; - - numvertexes = i / sizeof (mapvertex_t); - - if (numvertexes <= 0) - I_Error("Level has no vertices"); // instead of crashing - - // Allocate zone memory for buffer. - vertexes = Z_Calloc(numvertexes * sizeof (*vertexes), PU_LEVEL, NULL); - - ml = (mapvertex_t *)data; - li = vertexes; + mapvertex_t *ml = (mapvertex_t *)data; + vertex_t *li = vertexes; + size_t i; // Copy and convert vertex coordinates, internal representation as fixed. for (i = 0; i < numvertexes; i++, li++, ml++) @@ -407,13 +455,6 @@ FUNCINLINE static ATTRINLINE void P_LoadRawVertexes(UINT8 *data, size_t i) } } -static inline void P_LoadVertexes(lumpnum_t lumpnum) -{ - UINT8 *data = W_CacheLumpNum(lumpnum, PU_STATIC); - P_LoadRawVertexes(data, W_LumpLength(lumpnum)); - Z_Free(data); -} - /** Computes the length of a seg in fracunits. * * \param seg Seg to compute length for. @@ -445,25 +486,36 @@ static inline float P_SegLengthFloat(seg_t *seg) } #endif -/** Loads the SEGS resource from a level. +/** Updates the light offset * - * \param lump Lump number of the SEGS resource. - * \sa ::ML_SEGS + * \param li Seg to update the light offsets of */ -static void P_LoadRawSegs(UINT8 *data, size_t i) +void P_UpdateSegLightOffset(seg_t *li) +{ + const UINT8 contrast = 8; + const fixed_t contrastFixed = ((fixed_t)contrast) * FRACUNIT; + fixed_t light = FRACUNIT; + fixed_t extralight = 0; + + light = FixedDiv(R_PointToAngle2(0, 0, abs(li->v1->x - li->v2->x), abs(li->v1->y - li->v2->y)), ANGLE_90); + extralight = -contrastFixed + FixedMul(light, contrastFixed * 2); + + // Between -2 and 2 for software, -8 and 8 for hardware + li->lightOffset = FixedFloor((extralight / contrast) + (FRACUNIT / 2)) / FRACUNIT; +#ifdef HWRENDER + li->hwLightOffset = FixedFloor(extralight + (FRACUNIT / 2)) / FRACUNIT; +#endif +} + +// Loads the SEGS resource from a level. +static void P_LoadRawSegs(UINT8 *data) { INT32 linedef, side; - mapseg_t *ml; - seg_t *li; + mapseg_t *ml = (mapseg_t*)data; + seg_t *li = segs; line_t *ldef; + size_t i; - numsegs = i / sizeof (mapseg_t); - if (numsegs <= 0) - I_Error("Level has no segs"); // instead of crashing - segs = Z_Calloc(numsegs * sizeof (*segs), PU_LEVEL, NULL); - - ml = (mapseg_t *)data; - li = segs; for (i = 0; i < numsegs; i++, li++, ml++) { li->v1 = &vertexes[SHORT(ml->v1)]; @@ -484,46 +536,30 @@ static void P_LoadRawSegs(UINT8 *data, size_t i) li->side = side = SHORT(ml->side); li->sidedef = &sides[ldef->sidenum[side]]; li->frontsector = sides[ldef->sidenum[side]].sector; - if (ldef-> flags & ML_TWOSIDED) + if (ldef->flags & ML_TWOSIDED) li->backsector = sides[ldef->sidenum[side^1]].sector; else li->backsector = 0; li->numlights = 0; li->rlights = NULL; + + P_UpdateSegLightOffset(li); } } -static void P_LoadSegs(lumpnum_t lumpnum) +// Loads the SSECTORS resource from a level. +FUNCINLINE static ATTRINLINE void P_LoadRawSubsectors(void *data) { - UINT8 *data = W_CacheLumpNum(lumpnum, PU_STATIC); - P_LoadRawSegs(data, W_LumpLength(lumpnum)); - Z_Free(data); -} - - -/** Loads the SSECTORS resource from a level. - * - * \param lump Lump number of the SSECTORS resource. - * \sa ::ML_SSECTORS - */ -FUNCINLINE static ATTRINLINE void P_LoadRawSubsectors(void *data, size_t i) -{ - mapsubsector_t *ms; - subsector_t *ss; - - numsubsectors = i / sizeof (mapsubsector_t); - if (numsubsectors <= 0) - I_Error("Level has no subsectors (did you forget to run it through a nodesbuilder?)"); - ss = subsectors = Z_Calloc(numsubsectors * sizeof (*subsectors), PU_LEVEL, NULL); - - ms = (mapsubsector_t *)data; + mapsubsector_t *ms = (mapsubsector_t*)data; + subsector_t *ss = subsectors; + size_t i; for (i = 0; i < numsubsectors; i++, ss++, ms++) { ss->sector = NULL; ss->numlines = SHORT(ms->numsegs); - ss->firstline = SHORT(ms->firstseg); + ss->firstline = (UINT16)SHORT(ms->firstseg); #ifdef FLOORSPLATS ss->splats = NULL; #endif @@ -531,13 +567,6 @@ FUNCINLINE static ATTRINLINE void P_LoadRawSubsectors(void *data, size_t i) } } -static void P_LoadSubsectors(lumpnum_t lumpnum) -{ - UINT8 *data = W_CacheLumpNum(lumpnum, PU_STATIC); - P_LoadRawSubsectors(data, W_LumpLength(lumpnum)); - Z_Free(data); -} - // // P_LoadSectors // @@ -670,20 +699,13 @@ INT32 P_CheckLevelFlat(const char *flatname) } // Sets up the ingame sectors structures. -// Lumpnum is the lumpnum of a SECTORS lump. -static void P_LoadRawSectors(UINT8 *data, size_t i) +static void P_LoadRawSectors(UINT8 *data) { - mapsector_t *ms; - sector_t *ss; + mapsector_t *ms = (mapsector_t *)data; + sector_t *ss = sectors; levelflat_t *foundflats; - // We count how many sectors we got. - numsectors = i / sizeof (mapsector_t); - if (numsectors <= 0) - I_Error("Level has no sectors"); - - // Allocate as much memory as we need into the global sectors table. - sectors = Z_Calloc(numsectors*sizeof (*sectors), PU_LEVEL, NULL); + size_t i; // Allocate a big chunk of memory as big as our MAXLEVELFLATS limit. //Fab : FIXME: allocate for whatever number of flats - 512 different flats per level should be plenty @@ -694,8 +716,6 @@ static void P_LoadRawSectors(UINT8 *data, size_t i) numlevelflats = 0; // For each counted sector, copy the sector raw data from our cache pointer ms, to the global table pointer ss. - ms = (mapsector_t *)data; - ss = sectors; for (i = 0; i < numsectors; i++, ss++, ms++) { ss->floorheight = SHORT(ms->floorheight)<next) - { - if (th->function.acp1 != (actionf_p1)P_MobjThinker) - continue; - - mo = (mobj_t *)th; - - if (mo->type == MT_HOOPCENTER) - { - // Hoops give me a headache - if (mo->threshold == 4242) // Dead hoop - { - hoopsToRespawn[numHoops++] = mo->spawnpoint; - P_RemoveMobj(mo); - } - continue; - } - if (!(mo->type == MT_RING || mo->type == MT_NIGHTSWING || mo->type == MT_COIN - || mo->type == MT_BLUEBALL)) - continue; - - // Don't auto-disintegrate things being pulled to us - if (mo->flags2 & MF2_NIGHTSPULL) - continue; - - P_RemoveMobj(mo); - } - - // Reiterate through mapthings - for (i = 0; i < nummapthings; i++, mt++) - { - // Notice an omission? We handle hoops differently. - if (mt->type == 300 || mt->type == 308 || mt->type == 309 - || mt->type == 1706 || (mt->type >= 600 && mt->type <= 609) - || mt->type == 1800) - { - mt->mobj = NULL; - - // Z for objects Tails 05-26-2002 - mt->z = (INT16)(R_PointInSubsector(mt->x << FRACBITS, mt->y << FRACBITS) - ->sector->floorheight>>FRACBITS); - - P_SpawnHoopsAndRings (mt); - } - } - for (i = 0; i < numHoops; i++) - { - P_SpawnHoopsAndRings(hoopsToRespawn[i]); - } -} - -#ifdef SCANTHINGS -void P_ScanThings(INT16 mapnum, INT16 wadnum, INT16 lumpnum) -{ - size_t i, n; - UINT8 *data, *datastart; - UINT16 type, maprings; - INT16 tol; - UINT32 flags; - - tol = mapheaderinfo[mapnum-1]->typeoflevel; - if (!(tol & TOL_SP)) - return; - flags = mapheaderinfo[mapnum-1]->levelflags; - - n = W_LumpLengthPwad(wadnum, lumpnum) / (5 * sizeof (INT16)); - //CONS_Printf("%u map things found!\n", n); - - maprings = 0; - data = datastart = W_CacheLumpNumPwad(wadnum, lumpnum, PU_STATIC); - for (i = 0; i < n; i++) - { - data += 3 * sizeof (INT16); // skip x y position, angle - type = READUINT16(data) & 4095; - data += sizeof (INT16); // skip options - - switch (type) - { - case 300: // MT_RING - case 1800: // MT_COIN - case 308: // red team ring - case 309: // blue team ring - maprings++; - break; - case 400: // MT_SUPERRINGBOX - case 414: // red ring box - case 415: // blue ring box - case 603: // 10 diagonal rings - maprings += 10; - break; - case 600: // 5 vertical rings - case 601: // 5 vertical rings - case 602: // 5 diagonal rings - maprings += 5; - break; - case 604: // 8 circle rings - case 609: // 16 circle rings & wings - maprings += 8; - break; - case 605: // 16 circle rings - maprings += 16; - break; - case 608: // 8 circle rings & wings - maprings += 4; - break; - } - } - Z_Free(datastart); - - if (maprings) - CONS_Printf("%s has %u rings\n", G_BuildMapName(mapnum), maprings); -} -#endif - // // P_LoadThings // -static void P_PrepareRawThings(UINT8 *data, size_t i) +static void P_PrepareRawThings(UINT8 *data) { mapthing_t *mt; - - nummapthings = i / (5 * sizeof (INT16)); - mapthings = Z_Calloc(nummapthings * sizeof (*mapthings), PU_LEVEL, NULL); + size_t i; // Spawn axis points first so they are // at the front of the list for fast searching. @@ -981,13 +849,6 @@ static void P_PrepareRawThings(UINT8 *data, size_t i) } } -static void P_PrepareThings(lumpnum_t lumpnum) -{ - UINT8 *data = W_CacheLumpNum(lumpnum, PU_STATIC); - P_PrepareRawThings(data, W_LumpLength(lumpnum)); - Z_Free(data); -} - static void P_LoadThings(void) { size_t i; @@ -1173,33 +1034,43 @@ void P_WriteThings(lumpnum_t lumpnum) CONS_Printf(M_GetText("newthings%d.lmp saved.\n"), gamemap); } -static void P_LoadRawLineDefs(UINT8 *data, size_t i) +static void P_LoadRawLineDefs(UINT8 *data) { - maplinedef_t *mld; - line_t *ld; - vertex_t *v1, *v2; + maplinedef_t *mld = (maplinedef_t *)data; + line_t *ld = lines; + size_t i; - numlines = i / sizeof (maplinedef_t); - if (numlines <= 0) - I_Error("Level has no linedefs"); - lines = Z_Calloc(numlines * sizeof (*lines), PU_LEVEL, NULL); - - mld = (maplinedef_t *)data; - ld = lines; for (i = 0; i < numlines; i++, mld++, ld++) { ld->flags = SHORT(mld->flags); ld->special = SHORT(mld->special); ld->tag = SHORT(mld->tag); - v1 = ld->v1 = &vertexes[SHORT(mld->v1)]; - v2 = ld->v2 = &vertexes[SHORT(mld->v2)]; - ld->dx = v2->x - v1->x; - ld->dy = v2->y - v1->y; + ld->v1 = &vertexes[SHORT(mld->v1)]; + ld->v2 = &vertexes[SHORT(mld->v2)]; + + ld->sidenum[0] = SHORT(mld->sidenum[0]); + ld->sidenum[1] = SHORT(mld->sidenum[1]); + } +} + +static void P_SetupLines(void) +{ + line_t *ld = lines; + size_t i; + + for (i = 0; i < numlines; i++, ld++) + { + vertex_t *v1 = ld->v1; + vertex_t *v2 = ld->v2; #ifdef WALLSPLATS ld->splats = NULL; #endif + ld->polyobj = NULL; + ld->dx = v2->x - v1->x; + ld->dy = v2->y - v1->y; + if (!ld->dx) ld->slopetype = ST_VERTICAL; else if (!ld->dy) @@ -1231,9 +1102,6 @@ static void P_LoadRawLineDefs(UINT8 *data, size_t i) ld->bbox[BOXTOP] = v1->y; } - ld->sidenum[0] = SHORT(mld->sidenum[0]); - ld->sidenum[1] = SHORT(mld->sidenum[1]); - { // cph 2006/09/30 - fix sidedef errors right away. // cph 2002/07/20 - these errors are fatal if not fixed, so apply them @@ -1253,38 +1121,29 @@ static void P_LoadRawLineDefs(UINT8 *data, size_t i) ld->validcount = 0; ld->firsttag = ld->nexttag = -1; ld->callcount = 0; - // killough 11/98: fix common wad errors (missing sidedefs): + // killough 11/98: fix common wad errors (missing sidedefs): if (ld->sidenum[0] == 0xffff) { ld->sidenum[0] = 0; // Substitute dummy sidedef for missing right side // cph - print a warning about the bug - CONS_Debug(DBG_SETUP, "P_LoadRawLineDefs: linedef %s missing first sidedef\n", sizeu1(numlines-i-1)); + CONS_Debug(DBG_SETUP, "Linedef %s missing first sidedef\n", sizeu1(numlines-i-1)); } if ((ld->sidenum[1] == 0xffff) && (ld->flags & ML_TWOSIDED)) { ld->flags &= ~ML_TWOSIDED; // Clear 2s flag for missing left side // cph - print a warning about the bug - CONS_Debug(DBG_SETUP, "P_LoadRawLineDefs: linedef %s has two-sided flag set, but no second sidedef\n", sizeu1(numlines-i-1)); + CONS_Debug(DBG_SETUP, "Linedef %s has two-sided flag set, but no second sidedef\n", sizeu1(numlines-i-1)); } if (ld->sidenum[0] != 0xffff && ld->special) sides[ld->sidenum[0]].special = ld->special; if (ld->sidenum[1] != 0xffff && ld->special) sides[ld->sidenum[1]].special = ld->special; - - ld->polyobj = NULL; } } -static void P_LoadLineDefs(lumpnum_t lumpnum) -{ - UINT8 *data = W_CacheLumpNum(lumpnum, PU_STATIC); - P_LoadRawLineDefs(data, W_LumpLength(lumpnum)); - Z_Free(data); -} - static void P_LoadLineDefs2(void) { size_t i = numlines; @@ -1320,82 +1179,6 @@ static void P_LoadLineDefs2(void) break; } } - - // Optimize sidedefs - if (M_CheckParm("-compress")) - { - side_t *newsides; - size_t numnewsides = 0; - size_t z; - - for (i = 0; i < numsides; i++) - { - size_t j, k; - if (sides[i].sector == NULL) - continue; - - for (k = numlines, ld = lines; k--; ld++) - { - if (ld->sidenum[0] == i) - ld->sidenum[0] = (UINT16)numnewsides; - - if (ld->sidenum[1] == i) - ld->sidenum[1] = (UINT16)numnewsides; - } - - for (j = i+1; j < numsides; j++) - { - if (sides[j].sector == NULL) - continue; - - if (!memcmp(&sides[i], &sides[j], sizeof(side_t))) - { - // Find the linedefs that belong to this one - for (k = numlines, ld = lines; k--; ld++) - { - if (ld->sidenum[0] == j) - ld->sidenum[0] = (UINT16)numnewsides; - - if (ld->sidenum[1] == j) - ld->sidenum[1] = (UINT16)numnewsides; - } - sides[j].sector = NULL; // Flag for deletion - } - } - numnewsides++; - } - - // We're loading crap into this block anyhow, so no point in zeroing it out. - newsides = Z_Malloc(numnewsides * sizeof(*newsides), PU_LEVEL, NULL); - - // Copy the sides to their new block of memory. - for (i = 0, z = 0; i < numsides; i++) - { - if (sides[i].sector != NULL) - M_Memcpy(&newsides[z++], &sides[i], sizeof(side_t)); - } - - CONS_Debug(DBG_SETUP, "Old sides is %s, new sides is %s\n", sizeu1(numsides), sizeu1(numnewsides)); - - Z_Free(sides); - sides = newsides; - numsides = numnewsides; - } -} - - - -static inline void P_LoadRawSideDefs(size_t i) -{ - numsides = i / sizeof (mapsidedef_t); - if (numsides <= 0) - I_Error("Level has no sidedefs"); - sides = Z_Calloc(numsides * sizeof (*sides), PU_LEVEL, NULL); -} - -static inline void P_LoadSideDefs(lumpnum_t lumpnum) -{ - P_LoadRawSideDefs(W_LumpLength(lumpnum)); } static void P_LoadRawSideDefs2(void *data) @@ -1689,16 +1472,6 @@ static void P_LoadRawSideDefs2(void *data) R_ClearTextureNumCache(true); } - -// Delay loading texture names until after loaded linedefs. -static void P_LoadSideDefs2(lumpnum_t lumpnum) -{ - UINT8 *data = W_CacheLumpNum(lumpnum, PU_STATIC); - P_LoadRawSideDefs2(data); - Z_Free(data); -} - - static boolean LineInBlock(fixed_t cx1, fixed_t cy1, fixed_t cx2, fixed_t cy2, fixed_t bx1, fixed_t by1) { fixed_t bbox[4]; @@ -1765,8 +1538,8 @@ static void P_CreateBlockMap(void) { register size_t i; fixed_t minx = INT32_MAX, miny = INT32_MAX, maxx = INT32_MIN, maxy = INT32_MIN; - // First find limits of map + // First find limits of map for (i = 0; i < numvertexes; i++) { if (vertexes[i].x>>FRACBITS < minx) @@ -1979,70 +1752,12 @@ static void P_ReadBlockMapLump(INT16 *wadblockmaplump, size_t count) } } -// -// P_LoadBlockMap -// -// Levels might not have a blockmap, so if one does not exist -// this should return false. -static boolean P_LoadBlockMap(lumpnum_t lumpnum) -{ - size_t count; - const char *lumpname = W_CheckNameForNum(lumpnum); - - // Check if the lump exists, and if it's named "BLOCKMAP" - if (!lumpname || memcmp(lumpname, "BLOCKMAP", 8) != 0) - { - return false; - } - - count = W_LumpLength(lumpnum); - - if (!count || count >= 0x20000) - return false; - - { - INT16 *wadblockmaplump = malloc(count); //INT16 *wadblockmaplump = W_CacheLumpNum (lump, PU_LEVEL); - if (!wadblockmaplump) - return false; - W_ReadLump(lumpnum, wadblockmaplump); - count /= 2; - P_ReadBlockMapLump(wadblockmaplump, count); - free(wadblockmaplump); - } - - bmaporgx = blockmaplump[0]<= 0x20000) return false; @@ -2168,47 +1883,11 @@ static void P_GroupLines(void) } } -// -// P_LoadReject -// -// Detect if the REJECT lump is valid, -// if not, rejectmatrix will be NULL -static void P_LoadReject(lumpnum_t lumpnum) -{ - size_t count; - const char *lumpname = W_CheckNameForNum(lumpnum); - - // Check if the lump exists, and if it's named "REJECT" - if (!lumpname || memcmp(lumpname, "REJECT\0\0", 8) != 0) - { - rejectmatrix = NULL; - CONS_Debug(DBG_SETUP, "P_LoadReject: No valid REJECT lump found\n"); - return; - } - - count = W_LumpLength(lumpnum); - - if (!count) // zero length, someone probably used ZDBSP - { - rejectmatrix = NULL; - CONS_Debug(DBG_SETUP, "P_LoadReject: REJECT lump has size 0, will not be loaded\n"); - } - else - rejectmatrix = W_CacheLumpNum(lumpnum, PU_LEVEL); -} // PK3 version // -- Monster Iestyn 09/01/18 -static void P_LoadRawReject(UINT8 *data, size_t count, const char *lumpname) +static void P_LoadRawReject(UINT8 *data, size_t count) { - // Check if the lump is named "REJECT" - if (!lumpname || memcmp(lumpname, "REJECT\0\0", 8) != 0) - { - rejectmatrix = NULL; - CONS_Debug(DBG_SETUP, "P_LoadRawReject: No valid REJECT lump found\n"); - return; - } - if (!count) // zero length, someone probably used ZDBSP { rejectmatrix = NULL; @@ -2221,6 +1900,99 @@ static void P_LoadRawReject(UINT8 *data, size_t count, const char *lumpname) } } +static void P_LoadMapBSP(const virtres_t* virt) +{ + virtlump_t* virtssectors = vres_Find(virt, "SSECTORS"); + virtlump_t* virtsegs = vres_Find(virt, "SEGS"); + virtlump_t* virtnodes = vres_Find(virt, "NODES"); + + numsubsectors = virtssectors->size / sizeof(mapsubsector_t); + numnodes = virtnodes->size / sizeof(mapnode_t); + numsegs = virtsegs->size / sizeof(mapseg_t); + + if (numsubsectors <= 0) + I_Error("Level has no subsectors (did you forget to run it through a nodesbuilder?)"); + if (numnodes <= 0) + I_Error("Level has no nodes"); + if (numsegs <= 0) + I_Error("Level has no segs"); + + subsectors = Z_Calloc(numsubsectors * sizeof(*subsectors), PU_LEVEL, NULL); + nodes = Z_Calloc(numnodes * sizeof(*nodes), PU_LEVEL, NULL); + segs = Z_Calloc(numsegs * sizeof(*segs), PU_LEVEL, NULL); + + // Nodes + P_LoadRawSubsectors(virtssectors->data); + P_LoadRawNodes(virtnodes->data); + P_LoadRawSegs(virtsegs->data); +} + +static void P_LoadMapLUT(const virtres_t* virt) +{ + virtlump_t* virtblockmap = vres_Find(virt, "BLOCKMAP"); + virtlump_t* virtreject = vres_Find(virt, "REJECT"); + + // Lookup tables + if (virtreject) + P_LoadRawReject(virtreject->data, virtreject->size); + else + rejectmatrix = NULL; + + if (!(virtblockmap && P_LoadRawBlockMap(virtblockmap->data, virtblockmap->size))) + P_CreateBlockMap(); +} + +static void P_LoadMapData(const virtres_t* virt) +{ + virtlump_t* virtvertexes = NULL, * virtsectors = NULL, * virtsidedefs = NULL, * virtlinedefs = NULL, * virtthings = NULL; + + // Count map data. + virtthings = vres_Find(virt, "THINGS"); + virtvertexes = vres_Find(virt, "VERTEXES"); + virtsectors = vres_Find(virt, "SECTORS"); + virtsidedefs = vres_Find(virt, "SIDEDEFS"); + virtlinedefs = vres_Find(virt, "LINEDEFS"); + + if (!virtthings) + I_Error("THINGS lump not found"); + if (!virtvertexes) + I_Error("VERTEXES lump not found"); + if (!virtsectors) + I_Error("SECTORS lump not found"); + if (!virtsidedefs) + I_Error("SIDEDEFS lump not found"); + if (!virtlinedefs) + I_Error("LINEDEFS lump not found"); + + // Traditional doom map format just assumes the number of elements from the lump sizes. + numvertexes = virtvertexes->size / sizeof (mapvertex_t); + numsectors = virtsectors->size / sizeof (mapsector_t); + numsides = virtsidedefs->size / sizeof (mapsidedef_t); + numlines = virtlinedefs->size / sizeof (maplinedef_t); + nummapthings = virtthings->size / (5 * sizeof (INT16)); + + if (numvertexes <= 0) + I_Error("Level has no vertices"); + if (numsectors <= 0) + I_Error("Level has no sectors"); + if (numsides <= 0) + I_Error("Level has no sidedefs"); + if (numlines <= 0) + I_Error("Level has no linedefs"); + + vertexes = Z_Calloc(numvertexes * sizeof (*vertexes), PU_LEVEL, NULL); + sectors = Z_Calloc(numsectors * sizeof (*sectors), PU_LEVEL, NULL); + sides = Z_Calloc(numsides * sizeof (*sides), PU_LEVEL, NULL); + lines = Z_Calloc(numlines * sizeof (*lines), PU_LEVEL, NULL); + mapthings = Z_Calloc(nummapthings * sizeof (*mapthings), PU_LEVEL, NULL); + + // Strict map data + P_LoadRawVertexes(virtvertexes->data); + P_LoadRawSectors(virtsectors->data); + P_LoadRawLineDefs(virtlinedefs->data); + P_SetupLines(); + P_LoadRawSideDefs2(virtsidedefs->data); +} /** Sets up a sky texture to use for the level. * The sky texture is used instead of F_SKY1. @@ -2253,14 +2025,12 @@ lumpnum_t lastloadedmaplumpnum; // for comparative savegame // // Some player initialization for map start. // -static void P_LevelInitStuff(void) +static void P_LevelInitStuff(boolean reloadinggamestate) { INT32 i; leveltime = 0; - memset(localaiming, 0, sizeof(localaiming)); - // map object scale mapobjectscale = mapheaderinfo[gamemap-1]->mobj_scale; @@ -2288,7 +2058,10 @@ static void P_LevelInitStuff(void) // circuit, race and competition stuff circuitmap = false; numstarposts = 0; - totalrings = timeinmap = 0; + totalrings = 0; + + if (!reloadinggamestate) + timeinmap = 0; // special stage stagefailed = false; @@ -2378,6 +2151,9 @@ void P_LoadThingsOnly(void) mobj_t *mo; thinker_t *think; + virtres_t* virt = vres_GetMap(lastloadedmaplumpnum); + virtlump_t* vth = vres_Find(virt, "THINGS"); + for (think = thinkercap.next; think != &thinkercap; think = think->next) { if (think->function.acp1 != (actionf_p1)P_MobjThinker) @@ -2389,20 +2165,15 @@ void P_LoadThingsOnly(void) P_RemoveMobj(mo); } - P_LevelInitStuff(); + P_LevelInitStuff(false); - if (W_IsLumpWad(lastloadedmaplumpnum)) // welp it's a map wad in a pk3 - { // HACK: Open wad file rather quickly so we can use the things lump - UINT8 *wadData = W_CacheLumpNum(lastloadedmaplumpnum, PU_STATIC); - filelump_t *fileinfo = (filelump_t *)(wadData + ((wadinfo_t *)wadData)->infotableofs); - fileinfo += ML_THINGS; // we only need the THINGS lump - P_PrepareRawThings(wadData + fileinfo->filepos, fileinfo->size); - Z_Free(wadData); // we're done with this now - } - else // phew it's just a WAD - P_PrepareThings(lastloadedmaplumpnum + ML_THINGS); + memset(localaiming, 0, sizeof(localaiming)); + + P_PrepareRawThings(vth->data); P_LoadThings(); + vres_Free(virt); + P_SpawnSecretItems(true); } @@ -2432,7 +2203,7 @@ static INT32 P_MakeBufferMD5(const char *buffer, size_t len, void *resblock) #endif } -static void P_MakeMapMD5(lumpnum_t maplumpnum, void *dest) +static void P_MakeMapMD5(virtres_t *virt, void *dest) { unsigned char linemd5[16]; unsigned char sectormd5[16]; @@ -2443,20 +2214,15 @@ static void P_MakeMapMD5(lumpnum_t maplumpnum, void *dest) // Create a hash for the current map // get the actual lumps! - UINT8 *datalines = W_CacheLumpNum(maplumpnum + ML_LINEDEFS, PU_CACHE); - UINT8 *datasectors = W_CacheLumpNum(maplumpnum + ML_SECTORS, PU_CACHE); - UINT8 *datathings = W_CacheLumpNum(maplumpnum + ML_THINGS, PU_CACHE); - UINT8 *datasides = W_CacheLumpNum(maplumpnum + ML_SIDEDEFS, PU_CACHE); + virtlump_t* virtlines = vres_Find(virt, "LINEDEFS"); + virtlump_t* virtsectors = vres_Find(virt, "SECTORS"); + virtlump_t* virtmthings = vres_Find(virt, "THINGS"); + virtlump_t* virtsides = vres_Find(virt, "SIDEDEFS"); - P_MakeBufferMD5((char*)datalines, W_LumpLength(maplumpnum + ML_LINEDEFS), linemd5); - P_MakeBufferMD5((char*)datasectors, W_LumpLength(maplumpnum + ML_SECTORS), sectormd5); - P_MakeBufferMD5((char*)datathings, W_LumpLength(maplumpnum + ML_THINGS), thingmd5); - P_MakeBufferMD5((char*)datasides, W_LumpLength(maplumpnum + ML_SIDEDEFS), sidedefmd5); - - Z_Free(datalines); - Z_Free(datasectors); - Z_Free(datathings); - Z_Free(datasides); + P_MakeBufferMD5((char*)virtlines->data, virtlines->size, linemd5); + P_MakeBufferMD5((char*)virtsectors->data, virtsectors->size, sectormd5); + P_MakeBufferMD5((char*)virtmthings->data, virtmthings->size, thingmd5); + P_MakeBufferMD5((char*)virtsides->data, virtsides->size, sidedefmd5); for (i = 0; i < 16; i++) resmd5[i] = (linemd5[i] + sectormd5[i] + thingmd5[i] + sidedefmd5[i]) & 0xFF; @@ -2464,6 +2230,30 @@ static void P_MakeMapMD5(lumpnum_t maplumpnum, void *dest) M_Memcpy(dest, &resmd5, 16); } +static void P_LoadMapFromFile(void) +{ + P_LoadMapData(curmapvirt); + P_LoadMapBSP(curmapvirt); + P_LoadMapLUT(curmapvirt); + + P_LoadLineDefs2(); + P_GroupLines(); + + P_PrepareRawThings(vres_Find(curmapvirt, "THINGS")->data); + + P_MakeMapMD5(curmapvirt, &mapmd5); + + // We do the following silly + // construction because vres_Free + // no-sells deletions of pointers + // that are == curmapvirt. + { + virtres_t *temp = curmapvirt; + curmapvirt = NULL; + vres_Free(temp); + } +} + static void P_RunLevelScript(const char *scriptname) { if (!(mapheaderinfo[gamemap-1]->levelflags & LF_SCRIPTISFILE)) @@ -2665,30 +2455,36 @@ static void P_SetupCamera(UINT8 pnum, camera_t *cam) } } +static void P_InitCamera(void) +{ + INT32 i; + + if (!dedicated) + { + if (!demo.freecam) + for (i = 0; i <= splitscreen; i++) + P_SetupCamera(displayplayers[i], &camera[i]); + + // Though, I don't think anyone would care about cam_rotate being reset back to the only value that makes sense :P + if (!cv_cam_rotate.changed) + CV_Set(&cv_cam_rotate, cv_cam_rotate.defaultvalue); + + if (!cv_cam2_rotate.changed) + CV_Set(&cv_cam2_rotate, cv_cam2_rotate.defaultvalue); + + if (!cv_cam3_rotate.changed) + CV_Set(&cv_cam3_rotate, cv_cam3_rotate.defaultvalue); + + if (!cv_cam4_rotate.changed) + CV_Set(&cv_cam4_rotate, cv_cam4_rotate.defaultvalue); + + displayplayers[0] = consoleplayer; // Start with your OWN view, please! + } +} + static boolean P_CanSave(void) { -#if 0 - // Saving is completely ignored under these conditions: - if ((cursaveslot < 0) // Playing without saving - || (modifiedgame && !savemoddata) // Game is modified - || (netgame || multiplayer) // Not in single-player - || (demo.playback || demo.recording || metalrecording) // Currently in demo - || (players[consoleplayer].lives <= 0) // Completely dead - || (modeattacking || ultimatemode || G_IsSpecialStage(gamemap))) // Specialized instances - return false; - - if (mapheaderinfo[gamemap-1]->saveoverride == SAVE_ALWAYS) - return true; // Saving should ALWAYS happen! - else if (mapheaderinfo[gamemap-1]->saveoverride == SAVE_NEVER) - return false; // Saving should NEVER happen! - - // Default condition: In a non-hidden map, at the beginning of a zone or on a completed save-file, and not on save reload. - return (!(mapheaderinfo[gamemap-1]->menuflags & LF2_HIDEINMENU) - && (mapheaderinfo[gamemap-1]->actnum < 2 || gamecomplete) - && (gamemap != lastmapsaved)); -#else return false; // SRB2Kart: no SP, no saving. -#endif } /** Loads a level from a lump or external wad. @@ -2696,7 +2492,7 @@ static boolean P_CanSave(void) * \param skipprecip If true, don't spawn precipitation. * \todo Clean up, refactor, split up; get rid of the bloat. */ -boolean P_SetupLevel(boolean skipprecip) +boolean P_SetupLevel(boolean skipprecip, boolean reloadinggamestate) { // use gamemap to get map number. // 99% of the things already did, so. @@ -2704,7 +2500,7 @@ boolean P_SetupLevel(boolean skipprecip) INT32 i, loadprecip = 1, ranspecialwipe = 0; INT32 loademblems = 1; INT32 fromnetsave = 0; - boolean loadedbm = false; + midgamejoin = 0; sector_t *ss; boolean chase; @@ -2734,7 +2530,7 @@ boolean P_SetupLevel(boolean skipprecip) if (cv_runscripts.value && mapheaderinfo[gamemap-1]->scriptname[0] != '#') P_RunLevelScript(mapheaderinfo[gamemap-1]->scriptname); - P_LevelInitStuff(); + P_LevelInitStuff(reloadinggamestate); for (i = 0; i <= splitscreen; i++) postimgtype[i] = postimg_none; @@ -2749,10 +2545,6 @@ boolean P_SetupLevel(boolean skipprecip) if (!dedicated) { - // Salt: CV_ClearChangedFlags() messes with your settings :( - /*if (!cv_cam_speed.changed) - CV_Set(&cv_cam_speed, cv_cam_speed.defaultvalue);*/ - if (!cv_chasecam.changed) CV_SetValue(&cv_chasecam, chase); @@ -2771,9 +2563,12 @@ boolean P_SetupLevel(boolean skipprecip) // will be set by player think. players[consoleplayer].viewz = 1; + // Cancel all d_main.c fadeouts (keep fade in though). + if (reloadinggamestate) + wipegamestate = gamestate; // Don't fade if reloading the gamestate // Encore mode fade to pink to white // This is handled BEFORE sounds are stopped. - if (encoremode && !prevencoremode && !demo.rewinding) + else if (encoremode && !prevencoremode && !demo.rewinding) { tic_t locstarttime, endtime, nowtime; @@ -2832,15 +2627,16 @@ boolean P_SetupLevel(boolean skipprecip) // As oddly named as this is, this handles music only. // We should be fine starting it here. - S_Start(); + if (!reloadinggamestate) + S_Start(); levelfadecol = (encoremode && !ranspecialwipe ? 122 : 120); // Let's fade to white here // But only if we didn't do the encore startup wipe - if (!ranspecialwipe && !demo.rewinding) + if (!ranspecialwipe && !demo.rewinding && !reloadinggamestate) { - if(rendermode != render_none) + if (rendermode != render_none) { F_WipeStartScreen(); V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, levelfadecol); @@ -2903,16 +2699,17 @@ boolean P_SetupLevel(boolean skipprecip) fromnetsave = 1; loadprecip = 0; loademblems = 0; + midgamejoin = 1; } // internal game map maplumpname = G_BuildMapName(gamemap); - //lastloadedmaplumpnum = LUMPERROR; lastloadedmaplumpnum = W_CheckNumForName(maplumpname); - if (lastloadedmaplumpnum == INT16_MAX) I_Error("Map %s not found.\n", maplumpname); + curmapvirt = vres_GetMap(lastloadedmaplumpnum); + R_ReInitColormaps(mapheaderinfo[gamemap-1]->palette, (encoremode ? W_CheckNumForName(va("%sE", maplumpname)) : LUMPERROR)); CON_SetupBackColormap(); @@ -2920,99 +2717,20 @@ boolean P_SetupLevel(boolean skipprecip) // SRB2 determines the sky texture to be used depending on the map header. P_SetupLevelSky(mapheaderinfo[gamemap-1]->skynum, true); - P_MakeMapMD5(lastloadedmaplumpnum, &mapmd5); + numdmstarts = numredctfstarts = numbluectfstarts = 0; - // HACK ALERT: Cache the WAD, get the map data into the tables, free memory. - // As it is implemented right now, we're assuming an uncompressed WAD. - // (As in, a normal PWAD, not ZWAD or anything. The lump itself can be compressed.) - // We're not accounting for extra lumps and scrambled lump positions. Any additional data will cause an error. - if (W_IsLumpWad(lastloadedmaplumpnum)) - { - // Remember that we're assuming that the WAD will have a specific set of lumps in a specific order. - UINT8 *wadData = W_CacheLumpNum(lastloadedmaplumpnum, PU_STATIC); - //filelump_t *fileinfo = wadData + ((wadinfo_t *)wadData)->infotableofs; - filelump_t *fileinfo = (filelump_t *)(wadData + ((wadinfo_t *)wadData)->infotableofs); - UINT32 numlumps = ((wadinfo_t *)wadData)->numlumps; + // reset the player starts + for (i = 0; i < MAXPLAYERS; i++) + playerstarts[i] = NULL; + for (i = 0; i < 2; i++) + skyboxmo[i] = NULL; - if (numlumps < ML_REJECT) // at least 9 lumps should be in the wad for a map to be loaded - { - I_Error("Bad WAD file for map %s!\n", maplumpname); - } + P_ResetWaypoints(); - if (numlumps > ML_BLOCKMAP) // enough room for a BLOCKMAP lump at least - { - loadedbm = P_LoadRawBlockMap( - wadData + (fileinfo + ML_BLOCKMAP)->filepos, - (fileinfo + ML_BLOCKMAP)->size, - (fileinfo + ML_BLOCKMAP)->name); - } - P_LoadRawVertexes(wadData + (fileinfo + ML_VERTEXES)->filepos, (fileinfo + ML_VERTEXES)->size); - P_LoadRawSectors(wadData + (fileinfo + ML_SECTORS)->filepos, (fileinfo + ML_SECTORS)->size); - P_LoadRawSideDefs((fileinfo + ML_SIDEDEFS)->size); - P_LoadRawLineDefs(wadData + (fileinfo + ML_LINEDEFS)->filepos, (fileinfo + ML_LINEDEFS)->size); - P_LoadRawSideDefs2(wadData + (fileinfo + ML_SIDEDEFS)->filepos); - P_LoadRawSubsectors(wadData + (fileinfo + ML_SSECTORS)->filepos, (fileinfo + ML_SSECTORS)->size); - P_LoadRawNodes(wadData + (fileinfo + ML_NODES)->filepos, (fileinfo + ML_NODES)->size); - P_LoadRawSegs(wadData + (fileinfo + ML_SEGS)->filepos, (fileinfo + ML_SEGS)->size); - if (numlumps > ML_REJECT) // enough room for a REJECT lump at least - { - P_LoadRawReject( - wadData + (fileinfo + ML_REJECT)->filepos, - (fileinfo + ML_REJECT)->size, - (fileinfo + ML_REJECT)->name); - } - else - { - rejectmatrix = NULL; - } + P_MapStart(); - // Important: take care of the ordering of the next functions. - if (!loadedbm) - P_CreateBlockMap(); // Graue 02-29-2004 - P_LoadLineDefs2(); - P_GroupLines(); - numdmstarts = numredctfstarts = numbluectfstarts = 0; - - // reset the player starts - for (i = 0; i < MAXPLAYERS; i++) - playerstarts[i] = NULL; - for (i = 0; i < 2; i++) - skyboxmo[i] = NULL; - P_MapStart(); - - P_PrepareRawThings(wadData + (fileinfo + ML_THINGS)->filepos, (fileinfo + ML_THINGS)->size); - Z_Free(wadData); - } - else - { - // Important: take care of the ordering of the next functions. - loadedbm = P_LoadBlockMap(lastloadedmaplumpnum + ML_BLOCKMAP); - P_LoadVertexes(lastloadedmaplumpnum + ML_VERTEXES); - P_LoadSectors(lastloadedmaplumpnum + ML_SECTORS); - P_LoadSideDefs(lastloadedmaplumpnum + ML_SIDEDEFS); - P_LoadLineDefs(lastloadedmaplumpnum + ML_LINEDEFS); - P_LoadSideDefs2(lastloadedmaplumpnum + ML_SIDEDEFS); - P_LoadSubsectors(lastloadedmaplumpnum + ML_SSECTORS); - P_LoadNodes(lastloadedmaplumpnum + ML_NODES); - P_LoadSegs(lastloadedmaplumpnum + ML_SEGS); - P_LoadReject(lastloadedmaplumpnum + ML_REJECT); - - // Important: take care of the ordering of the next functions. - if (!loadedbm) - P_CreateBlockMap(); // Graue 02-29-2004 - - P_LoadLineDefs2(); - P_GroupLines(); - numdmstarts = numredctfstarts = numbluectfstarts = 0; - - // reset the player starts - for (i = 0; i < MAXPLAYERS; i++) - playerstarts[i] = NULL; - for (i = 0; i < 2; i++) - skyboxmo[i] = NULL; - P_MapStart(); - P_PrepareThings(lastloadedmaplumpnum + ML_THINGS); - } + if (lastloadedmaplumpnum) + P_LoadMapFromFile(); P_ResetDynamicSlopes(); @@ -3027,14 +2745,19 @@ boolean P_SetupLevel(boolean skipprecip) globalweather = mapheaderinfo[gamemap-1]->weather; // set up world state - P_SpawnSpecials(fromnetsave); + P_SpawnSpecials(fromnetsave, reloadinggamestate); if (loadprecip) // ugly hack for P_NetUnArchiveMisc (and P_LoadNetGame) P_SpawnPrecipitation(); #ifdef HWRENDER // not win32 only 19990829 by Kin if (rendermode == render_opengl) + { + HWR_FreeExtraSubsectors(); + + // stuff like HWR_CreatePlanePolygons is called there HWR_LoadLevel(); + } #endif // oh god I hope this helps @@ -3074,8 +2797,6 @@ boolean P_SetupLevel(boolean skipprecip) if (modeattacking == ATTACKING_RECORD && !demo.playback) P_LoadRecordGhosts(); - /*else if (modeattacking == ATTACKING_NIGHTS && !demo.playback) - P_LoadNightsGhosts();*/ if (G_TagGametype()) { @@ -3170,81 +2891,20 @@ boolean P_SetupLevel(boolean skipprecip) // landing point for netgames. netgameskip: - if (!dedicated) + if (!reloadinggamestate) { - if (!demo.freecam) - for (i = 0; i <= splitscreen; i++) - P_SetupCamera(displayplayers[i], &camera[i]); - - // Salt: CV_ClearChangedFlags() messes with your settings :( - /*if (!cv_cam_height.changed) - CV_Set(&cv_cam_height, cv_cam_height.defaultvalue); - - if (!cv_cam_dist.changed) - CV_Set(&cv_cam_dist, cv_cam_dist.defaultvalue); - - if (!cv_cam2_height.changed) - CV_Set(&cv_cam2_height, cv_cam2_height.defaultvalue); - - if (!cv_cam2_dist.changed) - CV_Set(&cv_cam2_dist, cv_cam2_dist.defaultvalue);*/ - - // Though, I don't think anyone would care about cam_rotate being reset back to the only value that makes sense :P - if (!cv_cam_rotate.changed) - CV_Set(&cv_cam_rotate, cv_cam_rotate.defaultvalue); - - if (!cv_cam2_rotate.changed) - CV_Set(&cv_cam2_rotate, cv_cam2_rotate.defaultvalue); - - if (!cv_cam3_rotate.changed) - CV_Set(&cv_cam3_rotate, cv_cam3_rotate.defaultvalue); - - if (!cv_cam4_rotate.changed) - CV_Set(&cv_cam4_rotate, cv_cam4_rotate.defaultvalue); - - /*if (!cv_analog.changed) - CV_SetValue(&cv_analog, 0); - if (!cv_analog2.changed) - CV_SetValue(&cv_analog2, 0); - if (!cv_analog3.changed) - CV_SetValue(&cv_analog3, 0); - if (!cv_analog4.changed) - CV_SetValue(&cv_analog4, 0);*/ - - // Shouldn't be necessary with render parity? - /*if (rendermode != render_none) - CV_Set(&cv_fov, cv_fov.defaultvalue);*/ - - displayplayers[0] = consoleplayer; // Start with your OWN view, please! + P_InitCamera(); + memset(localaiming, 0, sizeof(localaiming)); + K_InitDirector(); } - /*if (cv_useranalog.value) - CV_SetValue(&cv_analog, true); - - if ((splitscreen && cv_useranalog2.value) || botingame) - CV_SetValue(&cv_analog2, true); - - if (splitscreen > 1 && cv_useranalog3.value) - CV_SetValue(&cv_analog3, true); - - if (splitscreen > 2 && cv_useranalog4.value) - CV_SetValue(&cv_analog4, true); - - if (twodlevel) - { - CV_SetValue(&cv_analog4, false); - CV_SetValue(&cv_analog3, false); - CV_SetValue(&cv_analog2, false); - CV_SetValue(&cv_analog, false); - }*/ - // clear special respawning que iquehead = iquetail = 0; P_MapEnd(); // Remove the loading shit from the screen - if (rendermode != render_none) + if (rendermode != render_none && !reloadinggamestate) V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, levelfadecol); if (precache || dedicated) @@ -3291,7 +2951,7 @@ boolean P_SetupLevel(boolean skipprecip) LUAh_MapLoad(); } - if (rendermode != render_none) + if (rendermode != render_none && !reloadinggamestate) { R_ResetViewInterpolation(0); R_ResetViewInterpolation(0); @@ -3303,17 +2963,6 @@ boolean P_SetupLevel(boolean skipprecip) return true; } -#ifdef HWRENDER -void HWR_LoadLevel(void) -{ - HWR_FreeMipmapCache(); - HWR_CreatePlanePolygons((INT32)numnodes - 1); - - if (HWR_ShouldUsePaletteRendering()) - HWR_SetMapPalette(); -} -#endif - // // P_RunSOC // diff --git a/src/p_setup.h b/src/p_setup.h index 9e66fff81..c6a18915a 100644 --- a/src/p_setup.h +++ b/src/p_setup.h @@ -17,6 +17,9 @@ #include "doomdata.h" #include "doomstat.h" #include "r_defs.h" +#include "w_wad.h" + +extern SINT8 midgamejoin; // map md5, sent to players via PT_SERVERINFO extern unsigned char mapmd5[16]; @@ -30,6 +33,7 @@ extern boolean levelloading; extern UINT8 levelfadecol; extern lumpnum_t lastloadedmaplumpnum; // for comparative savegame +extern virtres_t *curmapvirt; // // MAP used flats lookup table // @@ -55,11 +59,8 @@ extern size_t nummapthings; extern mapthing_t *mapthings; void P_SetupLevelSky(INT32 skynum, boolean global); -#ifdef SCANTHINGS -void P_ScanThings(INT16 mapnum, INT16 wadnum, INT16 lumpnum); -#endif void P_LoadThingsOnly(void); -boolean P_SetupLevel(boolean skipprecip); +boolean P_SetupLevel(boolean skipprecip, boolean reloadinggamestate); #ifdef HWRENDER void HWR_LoadLevel(void); #endif @@ -87,11 +88,11 @@ SINT8 P_PartialAddGetStage(void); boolean P_RunSOC(const char *socfilename); void P_WriteThings(lumpnum_t lump); +void P_UpdateSegLightOffset(seg_t *li); size_t P_PrecacheLevelFlats(void); void P_AllocMapHeader(INT16 i); // Needed for NiGHTS -void P_ReloadRings(void); void P_DeleteGrades(INT16 i); void P_AddGradesForMare(INT16 i, UINT8 mare, char *gtext); UINT8 P_GetGrade(UINT32 pscore, INT16 map, UINT8 mare); diff --git a/src/p_slopes.c b/src/p_slopes.c index 112ba008b..6270821b1 100644 --- a/src/p_slopes.c +++ b/src/p_slopes.c @@ -27,11 +27,51 @@ static pslope_t *slopelist = NULL; static UINT16 slopecount = 0; +// Calculate light +static void P_UpdateSlopeLightOffset(pslope_t *slope) +{ + const boolean ceiling = (slope->normal.z < 0); + const UINT8 contrast = 8; + + fixed_t contrastFixed = ((fixed_t)contrast) * FRACUNIT; + fixed_t zMul = FRACUNIT; + angle_t slopeDir = ANGLE_MAX; + fixed_t extralight = 0; + + if (slope->normal.z == 0) + { + slope->lightOffset = 0; +#ifdef HWRENDER + slope->hwLightOffset = 0; +#endif + return; + } + + slopeDir = R_PointToAngle2(0, 0, abs(slope->normal.y), abs(slope->normal.x)); + if (ceiling == true) + { + slopeDir ^= ANGLE_180; + } + + zMul = min(FRACUNIT, abs(slope->zdelta)*3/2); // *3/2, to make 60 degree slopes match walls. + contrastFixed = FixedMul(contrastFixed, zMul); + extralight = -contrastFixed + FixedMul(FixedDiv(AngleFixed(slopeDir), ANGLE_90), (contrastFixed * 2)); + + // Between -2 and 2 for software, -8 and 8 for hardware + slope->lightOffset = FixedFloor((extralight / 8) + (FRACUNIT / 2)) / FRACUNIT; +#ifdef HWRENDER + slope->hwLightOffset = FixedFloor(extralight + (FRACUNIT / 2)) / FRACUNIT; +#endif +} + // Calculate line normal -void P_CalculateSlopeNormal(pslope_t *slope) { +void P_CalculateSlopeNormal(pslope_t *slope) +{ slope->normal.z = FINECOSINE(slope->zangle>>ANGLETOFINESHIFT); slope->normal.x = -FixedMul(FINESINE(slope->zangle>>ANGLETOFINESHIFT), -slope->d.x); slope->normal.y = -FixedMul(FINESINE(slope->zangle>>ANGLETOFINESHIFT), -slope->d.y); + + P_UpdateSlopeLightOffset(slope); } // With a vertex slope that has its vertices set, configure relevant slope info @@ -89,18 +129,24 @@ static void P_ReconfigureVertexSlope(pslope_t *slope) slope->real_xydirection = R_PointToAngle2(0, 0, slope->d.x, slope->d.y)+ANGLE_180; slope->real_zangle = InvAngle(R_PointToAngle2(0, 0, FRACUNIT, slope->zdelta)); - if (slope->normal.x == 0 && slope->normal.y == 0) { // Set some defaults for a non-sloped "slope" + if (slope->normal.x == 0 && slope->normal.y == 0) // Set some defaults for a non-sloped "slope" + { slope->zangle = slope->xydirection = 0; slope->zdelta = slope->d.x = slope->d.y = 0; - } else { + } + else + { slope->extent = extent; slope->xydirection = slope->real_xydirection; slope->zangle = slope->real_zangle; } + + P_UpdateSlopeLightOffset(slope); } // Recalculate dynamic slopes -void P_RunDynamicSlopes(void) { +void P_RunDynamicSlopes(void) +{ pslope_t *slope; for (slope = slopelist; slope; slope = slope->next) { @@ -284,7 +330,7 @@ void P_SpawnSlope_Line(int linenum) origin.y = line->v1->y + (line->v2->y - line->v1->y)/2; // For FOF slopes, make a special function to copy to the xy origin & direction relative to the position of the FOF on the map! - if(frontfloor || frontceil) + if (frontfloor || frontceil) { line->frontsector->hasslope = true; // Tell the software renderer that we're sloped @@ -308,7 +354,7 @@ void P_SpawnSlope_Line(int linenum) // TODO: We take origin and point 's xy values and translate them to the center of an FOF! - if(frontfloor) + if (frontfloor) { fixed_t highest, lowest; size_t l; @@ -369,7 +415,8 @@ void P_SpawnSlope_Line(int linenum) P_CalculateSlopeNormal(fslope); } - if(frontceil) + + if (frontceil) { fixed_t highest, lowest; size_t l; @@ -416,7 +463,7 @@ void P_SpawnSlope_Line(int linenum) P_CalculateSlopeNormal(cslope); } } - if(backfloor || backceil) + if (backfloor || backceil) { line->backsector->hasslope = true; // Tell the software renderer that we're sloped @@ -439,7 +486,7 @@ void P_SpawnSlope_Line(int linenum) direction.x = -direction.x; direction.y = -direction.y; - if(backfloor) + if (backfloor) { fixed_t highest, lowest; size_t l; @@ -484,7 +531,7 @@ void P_SpawnSlope_Line(int linenum) P_CalculateSlopeNormal(fslope); } - if(backceil) + if (backceil) { fixed_t highest, lowest; size_t l; @@ -634,7 +681,8 @@ pslope_t *P_SlopeById(UINT16 id) } // Reset the dynamic slopes pointer, and read all of the fancy schmancy slopes -void P_ResetDynamicSlopes(void) { +void P_ResetDynamicSlopes(void) +{ size_t i; slopelist = NULL; @@ -934,4 +982,4 @@ void P_ButteredSlope(mobj_t *mo) P_Thrust(mo, mo->standingslope->xydirection, thrust); } -// EOF \ No newline at end of file +// EOF diff --git a/src/p_spec.c b/src/p_spec.c index 9fb1953ee..133176db6 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -29,6 +29,7 @@ #include "z_zone.h" #include "r_main.h" //Two extra includes. #include "r_sky.h" +#include "st_stuff.h" #include "p_polyobj.h" #include "p_slopes.h" #include "hu_stuff.h" @@ -622,48 +623,6 @@ void P_SetupLevelFlatAnims(void) // UTILITIES // -#if 0 -/** Gets a side from a sector line. - * - * \param currentSector Sector the line is in. - * \param line Index of the line within the sector. - * \param side 0 for front, 1 for back. - * \return Pointer to the side_t of the side you want. - * \sa getSector, twoSided, getNextSector - */ -static inline side_t *getSide(INT32 currentSector, INT32 line, INT32 side) -{ - return &sides[(sectors[currentSector].lines[line])->sidenum[side]]; -} - -/** Gets a sector from a sector line. - * - * \param currentSector Sector the line is in. - * \param line Index of the line within the sector. - * \param side 0 for front, 1 for back. - * \return Pointer to the ::sector_t of the sector on that side. - * \sa getSide, twoSided, getNextSector - */ -static inline sector_t *getSector(INT32 currentSector, INT32 line, INT32 side) -{ - return sides[(sectors[currentSector].lines[line])->sidenum[side]].sector; -} - -/** Determines whether a sector line is two-sided. - * Uses the Boom method, checking if the line's back side is set to -1, rather - * than looking for ::ML_TWOSIDED. - * - * \param sector The sector. - * \param line Line index within the sector. - * \return 1 if the sector is two-sided, 0 otherwise. - * \sa getSide, getSector, getNextSector - */ -static inline boolean twoSided(INT32 sector, INT32 line) -{ - return (sectors[sector].lines[line])->sidenum[1] != 0xffff; -} -#endif - /** Finds sector next to current. * * \param line Pointer to the line to cross. @@ -822,77 +781,6 @@ fixed_t P_FindNextLowestFloor(sector_t *sec, fixed_t currentheight) return currentheight; } -#if 0 -/** Finds next lowest ceiling in adjacent sectors. - * - * \param sec Sector to start in. - * \param currentheight Height to start at. - * \return Next lowest ceiling height in an adjacent sector, or currentheight - * if there are none lower. - * \sa P_FindLowestCeilingSurrounding, P_FindNextHighestCeiling, - * P_FindNextLowestFloor - * \author Lee Killough - */ -static fixed_t P_FindNextLowestCeiling(sector_t *sec, fixed_t currentheight) -{ - sector_t *other; - size_t i; - fixed_t height; - - for (i = 0; i < sec->linecount; i++) - { - other = getNextSector(sec->lines[i],sec); - if (other && other->ceilingheight < currentheight) - { - height = other->ceilingheight; - while (++i < sec->linecount) - { - other = getNextSector(sec->lines[i],sec); - if (other && other->ceilingheight > height - && other->ceilingheight < currentheight) - height = other->ceilingheight; - } - return height; - } - } - return currentheight; -} - -/** Finds next highest ceiling in adjacent sectors. - * - * \param sec Sector to start in. - * \param currentheight Height to start at. - * \return Next highest ceiling height in an adjacent sector, or currentheight - * if there are none higher. - * \sa P_FindHighestCeilingSurrounding, P_FindNextLowestCeiling, - * P_FindNextHighestFloor - * \author Lee Killough - */ -static fixed_t P_FindNextHighestCeiling(sector_t *sec, fixed_t currentheight) -{ - sector_t *other; - size_t i; - fixed_t height; - - for (i = 0; i < sec->linecount; i++) - { - other = getNextSector(sec->lines[i], sec); - if (other && other->ceilingheight > currentheight) - { - height = other->ceilingheight; - while (++i < sec->linecount) - { - other = getNextSector(sec->lines[i],sec); - if (other && other->ceilingheight < height - && other->ceilingheight > currentheight) - height = other->ceilingheight; - } - return height; - } - } - return currentheight; -} -#endif //////////////////////////// // End New Boom functions @@ -962,133 +850,6 @@ fixed_t P_FindHighestCeilingSurrounding(sector_t *sec) return height; } -#if 0 -//SoM: 3/7/2000: UTILS..... -// -// P_FindShortestTextureAround() -// -// Passed a sector number, returns the shortest lower texture on a -// linedef bounding the sector. -// -// -static fixed_t P_FindShortestTextureAround(INT32 secnum) -{ - fixed_t minsize = 32000<linecount; i++) - { - if (twoSided(secnum, i)) - { - side = getSide(secnum,i,0); - if (side->bottomtexture > 0) - if (textureheight[side->bottomtexture] < minsize) - minsize = textureheight[side->bottomtexture]; - side = getSide(secnum,i,1); - if (side->bottomtexture > 0) - if (textureheight[side->bottomtexture] < minsize) - minsize = textureheight[side->bottomtexture]; - } - } - return minsize; -} - -//SoM: 3/7/2000: Stuff.... (can you tell I'm getting tired? It's 12 : 30!) -// -// P_FindShortestUpperAround() -// -// Passed a sector number, returns the shortest upper texture on a -// linedef bounding the sector. -// -// -static fixed_t P_FindShortestUpperAround(INT32 secnum) -{ - fixed_t minsize = 32000<linecount; i++) - { - if (twoSided(secnum, i)) - { - side = getSide(secnum,i,0); - if (side->toptexture > 0) - if (textureheight[side->toptexture] < minsize) - minsize = textureheight[side->toptexture]; - side = getSide(secnum,i,1); - if (side->toptexture > 0) - if (textureheight[side->toptexture] < minsize) - minsize = textureheight[side->toptexture]; - } - } - return minsize; -} - -//SoM: 3/7/2000 -// -// P_FindModelFloorSector() -// -// Passed a floor height and a sector number, return a pointer to a -// a sector with that floor height across the lowest numbered two sided -// line surrounding the sector. -// -// Note: If no sector at that height bounds the sector passed, return NULL -// -// -static sector_t *P_FindModelFloorSector(fixed_t floordestheight, INT32 secnum) -{ - size_t i; - sector_t *sec = §ors[secnum]; - - for (i = 0; i < sec->linecount; i++) - { - if (twoSided(secnum, i)) - { - if (getSide(secnum,i,0)->sector-sectors == secnum) - sec = getSector(secnum,i,1); - else - sec = getSector(secnum,i,0); - - if (sec->floorheight == floordestheight) - return sec; - } - } - return NULL; -} - -// -// P_FindModelCeilingSector() -// -// Passed a ceiling height and a sector number, return a pointer to a -// a sector with that ceiling height across the lowest numbered two sided -// line surrounding the sector. -// -// Note: If no sector at that height bounds the sector passed, return NULL -// -static sector_t *P_FindModelCeilingSector(fixed_t ceildestheight, INT32 secnum) -{ - size_t i; - sector_t *sec = §ors[secnum]; - - for (i = 0; i < sec->linecount; i++) - { - if (twoSided(secnum, i)) - { - if (getSide(secnum, i, 0)->sector - sectors == secnum) - sec = getSector(secnum, i, 1); - else - sec = getSector(secnum, i, 0); - - if (sec->ceilingheight == ceildestheight) - return sec; - } - } - return NULL; -} -#endif /** Searches the tag lists for the next sector tagged to a line. * @@ -1176,37 +937,8 @@ static INT32 P_FindLineFromLineTag(const line_t *line, INT32 start) return start; } } -#if 0 -/** Searches the tag lists for the next line with a given tag and special. - * - * \param tag Tag number. - * \param start -1 to start anew, or the result of a previous call to keep - * searching. - * \return Number of next suitable line found. - * \sa P_FindLineFromLineTag - * \author Graue - */ -static INT32 P_FindLineFromTag(INT32 tag, INT32 start) -{ - if (tag == -1) - { - start++; - if (start >= numlines) - return -1; - return start; - } - else - { - start = start >= 0 ? lines[start].nexttag : - lines[(unsigned)tag % numlines].firsttag; - while (start >= 0 && lines[start].tag != tag) - start = lines[start].nexttag; - return start; - } -} -#endif // // P_FindSpecialLineFromTag // @@ -1707,17 +1439,11 @@ boolean P_RunTriggerLinedef(line_t *triggerline, mobj_t *actor, sector_t *caller if (actor && actor->player && triggerline->flags & ML_EFFECT4) { - /*if (maptol & TOL_NIGHTS) - lap = actor->player->mare; - else*/ - lap = actor->player->laps; + lap = actor->player->laps; } else { - /*if (maptol & TOL_NIGHTS) - lap = P_FindLowestMare(); - else*/ - lap = P_FindLowestLap(); + lap = P_FindLowestLap(); } if (triggerline->flags & ML_NOCLIMB) // Need higher than or equal to @@ -1754,12 +1480,6 @@ boolean P_RunTriggerLinedef(line_t *triggerline, mobj_t *actor, sector_t *caller switch (specialtype) { - /*case 305: // continuous - case 306: // each time - case 307: // once - if (!(actor && actor->player && actor->player->charability == dist/10)) - return false; - break;*/ case 309: // continuous case 310: // each time // Only red team members can activate this. @@ -1930,9 +1650,8 @@ boolean P_RunTriggerLinedef(line_t *triggerline, mobj_t *actor, sector_t *caller // "Trigger on X calls" linedefs reset if noclimb is set if ((specialtype == 321 || specialtype == 322) && triggerline->flags & ML_NOCLIMB) triggerline->callcount = sides[triggerline->sidenum[0]].textureoffset>>FRACBITS; - else // These special types work only once - if (specialtype == 302 // Once + else if (specialtype == 302 // Once || specialtype == 304 // Ring count - Once || specialtype == 307 // Character ability - Once || specialtype == 308 // Race only - Once @@ -2054,16 +1773,18 @@ void P_SwitchWeather(INT32 weathernum) if (purge) { thinker_t *think; + thinker_t *next; precipmobj_t *precipmobj; - for (think = thinkercap.next; think != &thinkercap; think = think->next) + for (think = thinkercap.next; think != &thinkercap; think = next) { + next = think->next; + if (think->function.acp1 != (actionf_p1)P_NullPrecipThinker) continue; // not a precipmobj thinker precipmobj = (precipmobj_t *)think; - - P_RemovePrecipMobj(precipmobj); + P_FreePrecipMobj(precipmobj); } } else if (swap && !((swap == PRECIP_BLANK && curWeather == PRECIP_STORM_NORAIN) || (swap == PRECIP_STORM_NORAIN && curWeather == PRECIP_BLANK))) // Rather than respawn all that crap, reuse it! @@ -2076,27 +1797,29 @@ void P_SwitchWeather(INT32 weathernum) { if (think->function.acp1 != (actionf_p1)P_NullPrecipThinker) continue; // not a precipmobj thinker + precipmobj = (precipmobj_t *)think; if (swap == PRECIP_RAIN) // Snow To Rain { + precipmobj->type = MT_RAIN; // proper set the type + precipmobj->info = &mobjinfo[MT_RAIN]; precipmobj->flags = mobjinfo[MT_RAIN].flags; st = &states[mobjinfo[MT_RAIN].spawnstate]; precipmobj->state = st; precipmobj->tics = st->tics; precipmobj->sprite = st->sprite; precipmobj->frame = st->frame; - precipmobj->momz = mobjinfo[MT_RAIN].speed; + precipmobj->momz = cv_mobjscaleprecip.value ? FixedMul(mobjinfo[MT_RAIN].speed, mapobjectscale) : mobjinfo[MT_RAIN].speed; - precipmobj->precipflags &= ~PCF_INVISIBLE; - - precipmobj->precipflags |= PCF_RAIN; - //think->function.acp1 = (actionf_p1)P_RainThinker; + precipmobj->precipflags &= ~(PCF_INVISIBLE|PCF_SPLASH); // P_PrecipThinker will add this again if it needs to } else if (swap == PRECIP_SNOW) // Rain To Snow { INT32 z; + precipmobj->type = MT_SNOWFLAKE; // proper set the type + precipmobj->info = &mobjinfo[MT_SNOWFLAKE]; precipmobj->flags = mobjinfo[MT_SNOWFLAKE].flags; z = M_RandomByte(); @@ -2112,16 +1835,12 @@ void P_SwitchWeather(INT32 weathernum) precipmobj->tics = st->tics; precipmobj->sprite = st->sprite; precipmobj->frame = st->frame; - precipmobj->momz = mobjinfo[MT_SNOWFLAKE].speed; + precipmobj->momz = cv_mobjscaleprecip.value ? FixedMul(mobjinfo[MT_SNOWFLAKE].speed, mapobjectscale) : mobjinfo[MT_SNOWFLAKE].speed; - precipmobj->precipflags &= ~(PCF_INVISIBLE|PCF_RAIN); - - //think->function.acp1 = (actionf_p1)P_SnowThinker; + precipmobj->precipflags &= ~(PCF_INVISIBLE|PCF_SPLASH); // P_PrecipThinker will add this again if it needs to } else if (swap == PRECIP_BLANK || swap == PRECIP_STORM_NORAIN) // Remove precip, but keep it around for reuse. { - //think->function.acp1 = (actionf_p1)P_NullPrecipThinker; - precipmobj->precipflags |= PCF_INVISIBLE; } } @@ -2300,22 +2019,6 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) EV_DoCeiling(line, moveCeilingByFrontTexture); break; -/* case 405: // Lower floor by line, dx = speed, dy = amount to lower - EV_DoFloor(line, lowerFloorByLine); - break; - - case 406: // Raise floor by line, dx = speed, dy = amount to raise - EV_DoFloor(line, raiseFloorByLine); - break; - - case 407: // Lower ceiling by line, dx = speed, dy = amount to lower - EV_DoCeiling(line, lowerCeilingByLine); - break; - - case 408: // Raise ceiling by line, dx = speed, dy = amount to raise - EV_DoCeiling(line, raiseCeilingByLine); - break;*/ - case 409: // Change tagged sectors' tag // (formerly "Change calling sectors' tag", but behavior was changed) { @@ -2476,7 +2179,9 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) mapmusflags |= MUSIC_FORCERESET; mapmusposition = position; - mapmusresume = 0; + + if (cv_birdmusic.value) + mapmusresume = 0; S_ChangeMusicEx(mapmusname, mapmusflags, !(line->flags & ML_EFFECT4), position, !(line->flags & ML_EFFECT2) ? prefadems : 0, @@ -2614,7 +2319,17 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) CONS_Debug(DBG_SETUP, "SOC Error: script lump %s not found/not valid.\n", newname); } else - COM_BufInsertText(W_CacheLumpNum(lumpnum, PU_CACHE)); + { + // W_CacheLumpNum may not have null terminator, so we need to do this :blobcatgooglyholditsheadinitshands: + size_t len = W_LumpLength(lumpnum); + char *script = Z_Malloc(len+1, PU_STATIC, NULL); + memcpy(script, W_CacheLumpNum(lumpnum, PU_CACHE), len); + script[len] = 0; + + COM_BufInsertText(script); + + Z_Free(script); + } } break; @@ -2891,7 +2606,8 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) // Copy effect to bot if necessary // (Teleport them to you so they don't break it.) - if (bot && (bot->flags2 & MF2_TWOD) != (mo->flags2 & MF2_TWOD)) { + if (bot && (bot->flags2 & MF2_TWOD) != (mo->flags2 & MF2_TWOD)) + { bot->flags2 = (bot->flags2 & ~MF2_TWOD) | (mo->flags2 & MF2_TWOD); P_SetOrigin(bot, mo->x, mo->y, mo->z); } @@ -2924,7 +2640,8 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) P_SetTarget(&dummy->target, mo); A_CustomPower(dummy); - if (bot) { + if (bot) + { P_SetTarget(&dummy->target, bot); A_CustomPower(dummy); } @@ -3317,7 +3034,7 @@ boolean P_IsFlagAtBase(mobjtype_t flag) { thinker_t *think; mobj_t *mo; - INT32 specialnum = 0; + INT32 specialnum = (flag == MT_REDFLAG) ? 3 : 4; for (think = thinkercap.next; think != &thinkercap; think = think->next) { @@ -3329,11 +3046,6 @@ boolean P_IsFlagAtBase(mobjtype_t flag) if (mo->type != flag) continue; - if (mo->type == MT_REDFLAG) - specialnum = 3; - else if (mo->type == MT_BLUEFLAG) - specialnum = 4; - if (GETSECSPECIAL(mo->subsector->sector->special, 4) == specialnum) return true; else if (mo->subsector->sector->ffloors) // Check the 3D floors @@ -3517,10 +3229,6 @@ static boolean P_ThingIsOnThe3DFloor(mobj_t *mo, sector_t *sector, sector_t *tar if (rover->master->frontsector != sector) continue; - // we're assuming the FOF existed when the first player touched it - //if (!(rover->flags & FF_EXISTS)) - // return false; - top = P_GetSpecialTopZ(mo, sector, targetsec); bottom = P_GetSpecialBottomZ(mo, sector, targetsec); @@ -3655,7 +3363,7 @@ void P_ProcessSpecialSector(player_t *player, sector_t *sector, sector_t *rovers } else if (player->mo->health > 1) { - P_PlayRinglossSound(player->mo); + P_PlayRinglossSound(player->mo, NULL); if (player->mo->health > 10) player->mo->health -= 10; else @@ -3766,8 +3474,11 @@ void P_ProcessSpecialSector(player_t *player, sector_t *sector, sector_t *rovers continue; mo2 = (mobj_t *)th; - if (mo2->type == MT_EGGTRAP) - P_KillMobj(mo2, NULL, player->mo); + + if (mo2->type != MT_EGGTRAP) + continue; + + P_KillMobj(mo2, NULL, player->mo); } // clear the special so you can't push the button twice. @@ -4051,8 +3762,6 @@ DoneSection2: player->mo->momz = mobjinfo[MT_FAN].mass; P_ResetPlayer(player); - //if (player->panim != PA_FALL) // SRB2kart - // P_SetPlayerMobjState(player->mo, S_PLAY_FALL1); break; case 6: // SRB2kart 190117 - Sneaker Panel @@ -4078,9 +3787,7 @@ DoneSection2: INT32 sequence; fixed_t speed; INT32 lineindex; - thinker_t *th; mobj_t *waypoint = NULL; - mobj_t *mo2; angle_t an; if (player->mo->tracer && player->mo->tracer->type == MT_TUBEWAYPOINT) @@ -4099,22 +3806,7 @@ DoneSection2: speed = abs(lines[lineindex].dx)/8; sequence = abs(lines[lineindex].dy)>>FRACBITS; - // scan the thinkers - // to find the first waypoint - for (th = thinkercap.next; th != &thinkercap; th = th->next) - { - if (th->function.acp1 != (actionf_p1)P_MobjThinker) - continue; - - mo2 = (mobj_t *)th; - - if (mo2->type == MT_TUBEWAYPOINT && mo2->threshold == sequence - && mo2->health == 0) - { - waypoint = mo2; - break; - } - } + waypoint = P_GetFirstWaypoint(sequence); if (!waypoint) { @@ -4154,9 +3846,7 @@ DoneSection2: INT32 sequence; fixed_t speed; INT32 lineindex; - thinker_t *th; mobj_t *waypoint = NULL; - mobj_t *mo2; angle_t an; if (player->mo->tracer && player->mo->tracer->type == MT_TUBEWAYPOINT) @@ -4175,23 +3865,7 @@ DoneSection2: speed = -(abs(lines[lineindex].dx)/8); // Negative means reverse sequence = abs(lines[lineindex].dy)>>FRACBITS; - // scan the thinkers - // to find the last waypoint - for (th = thinkercap.next; th != &thinkercap; th = th->next) - { - if (th->function.acp1 != (actionf_p1)P_MobjThinker) - continue; - - mo2 = (mobj_t *)th; - - if (mo2->type == MT_TUBEWAYPOINT && mo2->threshold == sequence) - { - if (!waypoint) - waypoint = mo2; - else if (mo2->health > waypoint->health) - waypoint = mo2; - } - } + waypoint = P_GetLastWaypoint(sequence); if (!waypoint) { @@ -4215,12 +3889,6 @@ DoneSection2: if (!(player->mo->state >= &states[S_KART_RUN1] && player->mo->state <= &states[S_KART_RUN2])) P_SetPlayerMobjState(player->mo, S_KART_RUN1); - - //if (!(player->mo->state >= &states[S_PLAY_ATK1] && player->mo->state <= &states[S_PLAY_ATK4])) // SRB2kart - //{ - // P_SetPlayerMobjState(player->mo, S_PLAY_ATK1); - // S_StartSound(player->mo, sfx_spin); - //} } break; @@ -4276,6 +3944,11 @@ DoneSection2: curlap = 0; } + // ONLY FOR HUD + player->laptime[LAP_LAST] = player->laptime[LAP_CUR]; + player->laptime[LAP_CUR] = 0; + // + player->starposttime = player->realtime; player->starpostnum = 0; @@ -4347,15 +4020,12 @@ DoneSection2: INT32 sequence; fixed_t speed; INT32 lineindex; - thinker_t *th; mobj_t *waypointmid = NULL; mobj_t *waypointhigh = NULL; mobj_t *waypointlow = NULL; - mobj_t *mo2; mobj_t *closest = NULL; line_t junk; vertex_t v1, v2, resulthigh, resultlow; - mobj_t *highest = NULL; if (player->mo->tracer && player->mo->tracer->type == MT_TUBEWAYPOINT) break; @@ -4395,98 +4065,16 @@ DoneSection2: // Determine the closest spot on the line between the three waypoints // Put player at that location. - // scan the thinkers - // to find the first waypoint - for (th = thinkercap.next; th != &thinkercap; th = th->next) - { - if (th->function.acp1 != (actionf_p1)P_MobjThinker) - continue; + waypointmid = P_GetClosestWaypoint(sequence, player->mo); - mo2 = (mobj_t *)th; - - if (mo2->type != MT_TUBEWAYPOINT) - continue; - - if (mo2->threshold != sequence) - continue; - - if (!highest) - highest = mo2; - else if (mo2->health > highest->health) // Find the highest waypoint # in case we wrap - highest = mo2; - - if (closest && P_AproxDistance(P_AproxDistance(player->mo->x-mo2->x, player->mo->y-mo2->y), - player->mo->z-mo2->z) > P_AproxDistance(P_AproxDistance(player->mo->x-closest->x, - player->mo->y-closest->y), player->mo->z-closest->z)) - continue; - - // Found a target - closest = mo2; - } - - waypointmid = closest; - - closest = NULL; - - if (waypointmid == NULL) + if (!waypointmid) { CONS_Debug(DBG_GAMELOGIC, "ERROR: WAYPOINT(S) IN SEQUENCE %d NOT FOUND.\n", sequence); break; } - // Find waypoint before this one (waypointlow) - for (th = thinkercap.next; th != &thinkercap; th = th->next) - { - if (th->function.acp1 != (actionf_p1)P_MobjThinker) - continue; - - mo2 = (mobj_t *)th; - - if (mo2->type != MT_TUBEWAYPOINT) - continue; - - if (mo2->threshold != sequence) - continue; - - if (waypointmid->health == 0) - { - if (mo2->health != highest->health) - continue; - } - else if (mo2->health != waypointmid->health - 1) - continue; - - // Found a target - waypointlow = mo2; - break; - } - - // Find waypoint after this one (waypointhigh) - for (th = thinkercap.next; th != &thinkercap; th = th->next) - { - if (th->function.acp1 != (actionf_p1)P_MobjThinker) - continue; - - mo2 = (mobj_t *)th; - - if (mo2->type != MT_TUBEWAYPOINT) - continue; - - if (mo2->threshold != sequence) - continue; - - if (waypointmid->health == highest->health) - { - if (mo2->health != 0) - continue; - } - else if (mo2->health != waypointmid->health + 1) - continue; - - // Found a target - waypointhigh = mo2; - break; - } + waypointlow = P_GetPreviousWaypoint(waypointmid, true); + waypointhigh = P_GetNextWaypoint(waypointmid, true); CONS_Debug(DBG_GAMELOGIC, "WaypointMid: %d; WaypointLow: %d; WaypointHigh: %d\n", waypointmid->health, waypointlow ? waypointlow->health : -1, waypointhigh ? waypointhigh->health : -1); @@ -4537,6 +4125,7 @@ DoneSection2: if (lines[lineindex].flags & ML_EFFECT1) // Don't wrap { + mobj_t *highest = P_GetLastWaypoint(sequence); highest->flags |= MF_SLIDEME; } @@ -4548,7 +4137,7 @@ DoneSection2: player->mo->y = resulthigh.y; player->mo->z = resulthigh.z - P_GetPlayerHeight(player); } - else if ((lines[lineindex].flags & ML_EFFECT1) && waypointmid->health == highest->health) + else if ((lines[lineindex].flags & ML_EFFECT1) && waypointmid->health == numwaypoints[sequence] - 1) { closest = waypointmid; player->mo->x = resultlow.x; @@ -4869,12 +4458,6 @@ static void P_RunSpecialSectorCheck(player_t *player, sector_t *sector) break; } - // Check Section 3 -/* switch(GETSECSPECIAL(sector->special, 3)) - { - - }*/ - // Check Section 4 switch(GETSECSPECIAL(sector->special, 4)) { @@ -4985,7 +4568,8 @@ void P_UpdateSpecials(void) P_CheckPointLimit(); // Dynamic slopeness - P_RunDynamicSlopes(); + if (!midgamejoin) // run here when not joined midgame to prevent any potential issues that may arise + P_RunDynamicSlopes(); // ANIMATE TEXTURES for (anim = anims; anim < lastanim; anim++) @@ -5287,42 +4871,6 @@ static void P_AddFloatThinker(sector_t *sec, INT32 tag, line_t *sourceline) R_CreateInterpolator_SectorPlane(&floater->thinker, sec, true); } -/** Adds a bridge thinker. - * Bridge thinkers cause a group of FOFs to behave like - * a bridge made up of pieces, that bows under weight. - * - * \param sec Control sector. - * \sa P_SpawnSpecials, T_BridgeThinker - * \author SSNTails - */ -/* -static inline void P_AddBridgeThinker(line_t *sourceline, sector_t *sec) -{ - levelspecthink_t *bridge; - - // create an initialize new thinker - bridge = Z_Calloc(sizeof (*bridge), PU_LEVSPEC, NULL); - P_AddThinker(&bridge->thinker); - - bridge->thinker.function.acp1 = (actionf_p1)T_BridgeThinker; - - bridge->sector = sec; - bridge->vars[0] = sourceline->frontsector->floorheight; - bridge->vars[1] = sourceline->frontsector->ceilingheight; - bridge->vars[2] = P_AproxDistance(sourceline->dx, sourceline->dy); // Speed - bridge->vars[2] = FixedDiv(bridge->vars[2], 16*FRACUNIT); - bridge->vars[3] = bridge->vars[2]; - - // Start tag and end tag are TARGET SECTORS, not CONTROL SECTORS - // Control sector tags should be End_Tag + (End_Tag - Start_Tag) - bridge->vars[4] = sourceline->tag; // Start tag - bridge->vars[5] = (sides[sourceline->sidenum[0]].textureoffset>>FRACBITS); // End tag - - // interpolation - R_CreateInterpolator_SectorPlane(&bridge->thinker, §ors[affectee], false); -} -*/ - /** Adds a Mario block thinker, which changes the block's texture between blank * and ? depending on whether it has contents. * Needed in case objects respawn inside. @@ -5686,7 +5234,7 @@ static void P_RunLevelLoadExecutors(void) * as they'll just be erased by UnArchiveThinkers. * \sa P_SpawnPrecipitation, P_SpawnFriction, P_SpawnPushers, P_SpawnScrollers */ -void P_SpawnSpecials(INT32 fromnetsave) +void P_SpawnSpecials(INT32 fromnetsave, boolean reloadinggamestate) { sector_t *sector; size_t i; @@ -5694,6 +5242,7 @@ void P_SpawnSpecials(INT32 fromnetsave) thinkerlist_t *secthinkers; thinker_t *th; + virtres_t* virt = NULL; // This used to be used, and *should* be used in the future, // but currently isn't. (void)fromnetsave; @@ -5739,12 +5288,6 @@ void P_SpawnSpecials(INT32 fromnetsave) break; } - // Process Section 3 -/* switch(GETSECSPECIAL(player->specialsector, 3)) - { - - }*/ - // Process Section 4 switch(GETSECSPECIAL(sector->special, 4)) { @@ -5830,16 +5373,6 @@ void P_SpawnSpecials(INT32 fromnetsave) lines[i].special = 0; continue; } - /*else -- commented out because irrelevant to kart. keeping here because we can use these flags for something else now - { - if ((players[consoleplayer].charability == CA_THOK && (lines[i].flags & ML_NOSONIC)) - || (players[consoleplayer].charability == CA_FLY && (lines[i].flags & ML_NOTAILS)) - || (players[consoleplayer].charability == CA_GLIDEANDCLIMB && (lines[i].flags & ML_NOKNUX))) - { - lines[i].special = 0; - continue; - } - }*/ } switch (lines[i].special) @@ -6020,12 +5553,14 @@ void P_SpawnSpecials(INT32 fromnetsave) break; case 64: // Appearing/Disappearing FOF option - if (lines[i].flags & ML_BLOCKMONSTERS) { // Find FOFs by control sector tag + if (lines[i].flags & ML_BLOCKMONSTERS) // Find FOFs by control sector tag + { for (s = -1; (s = P_FindSectorFromLineTag(lines + i, s)) >= 0 ;) for (j = 0; (unsigned)j < sectors[s].linecount; j++) if (sectors[s].lines[j]->special >= 100 && sectors[s].lines[j]->special < 300) Add_MasterDisappearer(abs(lines[i].dx>>FRACBITS), abs(lines[i].dy>>FRACBITS), abs(sides[lines[i].sidenum[0]].sector->floorheight>>FRACBITS), (INT32)(sectors[s].lines[j]-lines), (INT32)i); - } else // Find FOFs by effect sector tag + } + else // Find FOFs by effect sector tag for (s = -1; (s = P_FindLineFromLineTag(lines + i, s)) >= 0 ;) { if ((size_t)s == i) @@ -6036,10 +5571,6 @@ void P_SpawnSpecials(INT32 fromnetsave) break; case 65: // Bridge Thinker - /* - // Disable this until it's working right! - for (s = -1; (s = P_FindSectorFromLineTag(lines + i, s)) >= 0 ;) - P_AddBridgeThinker(&lines[i], §ors[s]);*/ break; case 100: // FOF (solid, opaque, shadows) @@ -6473,17 +6004,10 @@ void P_SpawnSpecials(INT32 fromnetsave) UINT8 *data; UINT16 b; - if (W_IsLumpWad(lastloadedmaplumpnum)) // welp it's a map wad in a pk3 - { // HACK: Open wad file rather quickly so we can get the data from the sidedefs lump - UINT8 *wadData = W_CacheLumpNum(lastloadedmaplumpnum, PU_STATIC); - filelump_t *fileinfo = (filelump_t *)(wadData + ((wadinfo_t *)wadData)->infotableofs); - fileinfo += ML_SIDEDEFS; // we only need the SIDEDEFS lump - data = Z_Malloc(fileinfo->size, PU_STATIC, NULL); - M_Memcpy(data, wadData + fileinfo->filepos, fileinfo->size); // copy data - Z_Free(wadData); // we're done with this now - } - else // phew it's just a WAD - data = W_CacheLumpNum(lastloadedmaplumpnum + ML_SIDEDEFS,PU_STATIC); + if (!virt) + virt = vres_GetMap(lastloadedmaplumpnum); + + data = (UINT8*) vres_Find(virt, "SIDEDEFS")->data; for (b = 0; b < (INT16)numsides; b++) { @@ -6503,7 +6027,6 @@ void P_SpawnSpecials(INT32 fromnetsave) I_Error("Make-Your-Own-FOF (tag %d) needs a value in the linedef's second side upper texture field.", lines[i].tag); } } - Z_Free(data); } else I_Error("Make-Your-Own FOF (tag %d) found without a 2nd linedef side!", lines[i].tag); @@ -6711,6 +6234,9 @@ void P_SpawnSpecials(INT32 fromnetsave) } } + if (virt) + vres_Free(virt); + // Allocate each list for (i = 0; i < numsectors; i++) if(secthinkers[i].thinkers) @@ -6735,7 +6261,8 @@ void P_SpawnSpecials(INT32 fromnetsave) } } - P_RunLevelLoadExecutors(); + if (!reloadinggamestate) + P_RunLevelLoadExecutors(); } /** Adds 3Dfloors as appropriate based on a common control linedef. @@ -7273,7 +6800,7 @@ void T_Disappear(disappear_t *d) if (*rover->t_slope) sectors[s].soundorg.z = P_GetZAt(*rover->t_slope, sectors[s].soundorg.x, sectors[s].soundorg.y); else - sectors[s].soundorg.z = *rover->topheight; + sectors[s].soundorg.z = *rover->topheight; S_StartSound(§ors[s].soundorg, sfx_appear); } } @@ -7347,17 +6874,6 @@ void T_Friction(friction_t *f) //{ referrer = sectors + f->referrer; - /* if (!(GETSECSPECIAL(referrer->special, 3) == 1 - || GETSECSPECIAL(referrer->special, 3) == 3)) - return; - } - else - { - if (!(GETSECSPECIAL(sec->special, 3) == 1 - || GETSECSPECIAL(sec->special, 3) == 3)) - return; - }*/ - // Assign the friction value to players on the floor, non-floating, // and clipped. Normally the object's friction value is kept at // ORIG_FRICTION and this thinker changes it for icy or muddy floors. @@ -7697,14 +7213,11 @@ void T_Pusher(pusher_t *p) { referrer = §ors[p->referrer]; - //if (!(GETSECSPECIAL(referrer->special, 3) == 2 - // || GETSECSPECIAL(referrer->special, 3) == 3)) if (GETSECSPECIAL(referrer->special, 3) != 2) return; } - //else if (!(GETSECSPECIAL(sec->special, 3) == 2 - // || GETSECSPECIAL(sec->special, 3) == 3)) else if (GETSECSPECIAL(sec->special, 3) != 2) + // For constant pushers (wind/current) there are 3 situations: // // 1) Affected Thing is above the floor. @@ -7942,14 +7455,6 @@ void T_Pusher(pusher_t *p) else localangle[3] += (thing->angle - localangle[3]) / 8; } - /*if (thing->player == &players[consoleplayer]) - localangle[0] = thing->angle; - else if (thing->player == &players[displayplayers[1]]) - localangle[1] = thing->angle; - else if (thing->player == &players[displayplayers[2]]) - localangle[2] = thing->angle; - else if (thing->player == &players[displayplayers[3]]) - localangle[3] = thing->angle;*/ } } @@ -8061,13 +7566,6 @@ static void P_SearchForDisableLinedefs(void) } else if ((lines[i].flags & ML_NETONLY) == ML_NETONLY) continue; // Net-only never triggers in single player - // commented out because irrelevant to kart. keeping here because we can use these flags for something else now - /*else if (players[consoleplayer].charability == CA_THOK && (lines[i].flags & ML_NOSONIC)) - continue; - else if (players[consoleplayer].charability == CA_FLY && (lines[i].flags & ML_NOTAILS)) - continue; - else if (players[consoleplayer].charability == CA_GLIDEANDCLIMB && (lines[i].flags & ML_NOKNUX)) - continue;*/ // Disable any linedef specials with our tag. for (j = -1; (j = P_FindLineFromLineTag(&lines[i], j)) >= 0;) diff --git a/src/p_spec.h b/src/p_spec.h index 1231aeda8..477dd4950 100644 --- a/src/p_spec.h +++ b/src/p_spec.h @@ -32,7 +32,7 @@ void P_InitPicAnims(void); void P_SetupLevelFlatAnims(void); // at map load -void P_SpawnSpecials(INT32 fromnetsave); +void P_SpawnSpecials(INT32 fromnetsave, boolean reloadinggamestate); // every tic void P_UpdateSpecials(void); diff --git a/src/p_telept.c b/src/p_telept.c index 9229079c9..a7cef7b1d 100644 --- a/src/p_telept.c +++ b/src/p_telept.c @@ -84,10 +84,11 @@ void P_MixUp(mobj_t *thing, fixed_t x, fixed_t y, fixed_t z, angle_t angle, { if (thing->player != &players[displayplayers[i]]) continue; + if (camera[i].chase) P_ResetCamera(thing->player, &camera[i]); + R_ResetViewInterpolation(i + 1); - break; } // don't run in place after a teleport @@ -157,14 +158,14 @@ boolean P_Teleport(mobj_t *thing, fixed_t x, fixed_t y, fixed_t z, angle_t angle // move chasecam at new player location for (i = 0; i <= splitscreen; i++) { - if (thing->player == &players[displayplayers[i]]) - { - localangle[i] = angle; - if (camera[i].chase) - P_ResetCamera(thing->player, &camera[i]); - R_ResetViewInterpolation(i + 1); - break; - } + if (thing->player != &players[displayplayers[i]]) + continue; + + localangle[i] = angle; + if (camera[i].chase) + P_ResetCamera(thing->player, &camera[i]); + + R_ResetViewInterpolation(i + 1); } // don't run in place after a teleport diff --git a/src/p_tick.c b/src/p_tick.c index 6416142ce..ed7252dc6 100644 --- a/src/p_tick.c +++ b/src/p_tick.c @@ -18,10 +18,12 @@ #include "z_zone.h" #include "s_sound.h" #include "st_stuff.h" +#include "p_setup.h" #include "p_polyobj.h" #include "m_random.h" #include "lua_script.h" #include "lua_hook.h" +#include "k_director.h" #include "k_kart.h" #include "i_system.h" #include "r_main.h" @@ -32,6 +34,9 @@ // Object place #include "m_cheat.h" +// Dynamic slopes +#include "p_slopes.h" + tic_t leveltime; // @@ -63,8 +68,6 @@ void Command_Numthinkers_f(void) CONS_Printf(M_GetText("numthinkers <#>: Count number of thinkers\n")); CONS_Printf( "\t1: P_MobjThinker\n" - /*"\t2: P_RainThinker\n" - "\t3: P_SnowThinker\n"*/ "\t2: P_NullPrecipThinker\n" "\t3: T_Friction\n" "\t4: T_Pusher\n" @@ -80,14 +83,6 @@ void Command_Numthinkers_f(void) action = (actionf_p1)P_MobjThinker; CONS_Printf(M_GetText("Number of %s: "), "P_MobjThinker"); break; - /*case 2: - action = (actionf_p1)P_RainThinker; - CONS_Printf(M_GetText("Number of %s: "), "P_RainThinker"); - break; - case 3: - action = (actionf_p1)P_SnowThinker; - CONS_Printf(M_GetText("Number of %s: "), "P_SnowThinker"); - break;*/ case 2: action = (actionf_p1)P_NullPrecipThinker; CONS_Printf(M_GetText("Number of %s: "), "P_NullPrecipThinker"); @@ -221,23 +216,41 @@ static thinker_t *currentthinker; // remove it, and set currentthinker to one node preceeding it, so // that the next step in P_RunThinkers() will get its successor. // -void P_RemoveThinkerDelayed(void *pthinker) +void P_RemoveThinkerDelayed(thinker_t *thinker) { - thinker_t *thinker = pthinker; - if (!thinker->references) - { - { - /* Remove from main thinker list */ - thinker_t *next = thinker->next; - /* Note that currentthinker is guaranteed to point to us, - * and since we're freeing our memory, we had better change that. So - * point it to thinker->prev, so the iterator will correctly move on to - * thinker->prev->next = thinker->next */ - (next->prev = currentthinker = thinker->prev)->next = next; - } - R_DestroyLevelInterpolators(thinker); - Z_Free(thinker); - } +#ifdef PARANOIA + if (thinker->next) + thinker->next = NULL; + else if (thinker->references) // Usually gets cleared up in one frame; what's going on here, then? + CONS_Printf("Number of potentially faulty references: %d\n", thinker->references); +#endif + if (thinker->references) + return; + + /* Remove from main thinker list */ + thinker_t *next = thinker->next; + /* Note that currentthinker is guaranteed to point to us, + * and since we're freeing our memory, we had better change that. So + * point it to thinker->prev, so the iterator will correctly move on to + * thinker->prev->next = thinker->next */ + (next->prev = currentthinker = thinker->prev)->next = next; + R_DestroyLevelInterpolators(thinker); + Z_Free(thinker); +} + +// +// P_UnlinkThinker() +// +// Actually removes thinker from the list and frees its memory. +// +void P_UnlinkThinker(thinker_t *thinker) +{ + thinker_t *next = thinker->next; + + I_Assert(thinker->references == 0); + + (next->prev = thinker->prev)->next = next; + Z_Free(thinker); } // @@ -255,7 +268,7 @@ void P_RemoveThinkerDelayed(void *pthinker) void P_RemoveThinker(thinker_t *thinker) { LUA_InvalidateUserdata(thinker); - thinker->function.acp1 = P_RemoveThinkerDelayed; + thinker->function.acp1 = (actionf_p1)P_RemoveThinkerDelayed; } /* @@ -310,265 +323,76 @@ static inline void P_RunThinkers(void) } } -// -// P_DoAutobalanceTeams() -// -// Determine if the teams are unbalanced, and if so, move a player to the other team. -// -/*static void P_DoAutobalanceTeams(void) +static inline void P_DeviceRumbleTick(void) { - changeteam_union NetPacket; - UINT16 usvalue; - INT32 i=0; - INT32 red=0, blue=0; - INT32 redarray[MAXPLAYERS], bluearray[MAXPLAYERS]; - INT32 redflagcarrier = 0, blueflagcarrier = 0; - INT32 totalred = 0, totalblue = 0; + UINT8 i; - NetPacket.value.l = NetPacket.value.b = 0; - memset(redarray, 0, sizeof(redarray)); - memset(bluearray, 0, sizeof(bluearray)); - - // Only do it if we have enough room in the net buffer to send it. - // Otherwise, come back next time and try again. - if (sizeof(usvalue) > GetFreeXCmdSize()) + if (I_NumJoys() == 0 || (cv_rumble[0].value == 0 && cv_rumble[1].value == 0 && cv_rumble[2].value == 0 && cv_rumble[3].value == 0)) + { return; - - //We have to store the players in an array with the rest of their team. - //We can then pick a random player to be forced to change teams. - for (i = 0; i < MAXPLAYERS; i++) - { - if (playeringame[i] && players[i].ctfteam) - { - if (players[i].ctfteam == 1) - { - if (!players[i].gotflag) - { - redarray[red] = i; //store the player's node. - red++; - } - else - redflagcarrier++; - } - else - { - if (!players[i].gotflag) - { - bluearray[blue] = i; //store the player's node. - blue++; - } - else - blueflagcarrier++; - } - } } - totalred = red + redflagcarrier; - totalblue = blue + blueflagcarrier; - - if ((abs(totalred - totalblue) > cv_autobalance.value)) + for (i = 0; i <= splitscreen; i++) { - if (totalred > totalblue) - { - i = M_RandomKey(red); - NetPacket.packet.newteam = 2; - NetPacket.packet.playernum = redarray[i]; - NetPacket.packet.verification = true; - NetPacket.packet.autobalance = true; + player_t *player = &players[displayplayers[i]]; + UINT16 low = 0; + UINT16 high = 0; - usvalue = SHORT(NetPacket.value.l|NetPacket.value.b); - SendNetXCmd(XD_TEAMCHANGE, &usvalue, sizeof(usvalue)); - } - - if (totalblue > totalred) - { - i = M_RandomKey(blue); - NetPacket.packet.newteam = 1; - NetPacket.packet.playernum = bluearray[i]; - NetPacket.packet.verification = true; - NetPacket.packet.autobalance = true; - - usvalue = SHORT(NetPacket.value.l|NetPacket.value.b); - SendNetXCmd(XD_TEAMCHANGE, &usvalue, sizeof(usvalue)); - } - } -} - -// -// P_DoTeamscrambling() -// -// If a team scramble has been started, scramble one person from the -// pre-made scramble array. Said array is created in TeamScramble_OnChange() -// -void P_DoTeamscrambling(void) -{ - changeteam_union NetPacket; - UINT16 usvalue; - NetPacket.value.l = NetPacket.value.b = 0; - - // Only do it if we have enough room in the net buffer to send it. - // Otherwise, come back next time and try again. - if (sizeof(usvalue) > GetFreeXCmdSize()) - return; - - if (scramblecount < scrambletotal) - { - if (players[scrambleplayers[scramblecount]].ctfteam != scrambleteams[scramblecount]) - { - NetPacket.packet.newteam = scrambleteams[scramblecount]; - NetPacket.packet.playernum = scrambleplayers[scramblecount]; - NetPacket.packet.verification = true; - NetPacket.packet.scrambled = true; - - usvalue = SHORT(NetPacket.value.l|NetPacket.value.b); - SendNetXCmd(XD_TEAMCHANGE, &usvalue, sizeof(usvalue)); - } - - scramblecount++; //Increment, and get to the next player when we come back here next time. - } - else - CV_SetValue(&cv_teamscramble, 0); -} - -static inline void P_DoSpecialStageStuff(void) -{ - boolean inwater = false; - INT32 i; - - // Can't drown in a special stage - for (i = 0; i < MAXPLAYERS; i++) - { - if (!playeringame[i] || players[i].spectator) + if (!P_IsLocalPlayer(player)) continue; - players[i].powers[pw_underwater] = players[i].powers[pw_spacetime] = 0; - } + if (G_GetDeviceForPlayer(i) == 0) + continue; - if (sstimer < 15*TICRATE+6 && sstimer > 7 && (mapheaderinfo[gamemap-1]->levelflags & LF_SPEEDMUSIC)) - S_SpeedMusic(1.4f); + if (!playeringame[displayplayers[i]] || player->spectator) + continue; - if (sstimer < 7 && sstimer > 0) // The special stage time is up! - { - sstimer = 0; - for (i = 0; i < MAXPLAYERS; i++) + if (player->mo == NULL) + continue; + + if (player->exiting) { - if (playeringame[i]) - { - players[i].exiting = raceexittime+1; - players[i].pflags &= ~PF_GLIDING; - } - - if (i == consoleplayer) - S_StartSound(NULL, sfx_lose); + G_PlayerDeviceRumble(i, low, high, 0); + continue; } - if (mapheaderinfo[gamemap-1]->levelflags & LF_SPEEDMUSIC) - S_SpeedMusic(1.0f); - - stagefailed = true; - } - - if (sstimer > 1) // As long as time isn't up... - { - UINT32 ssrings = 0; - // Count up the rings of all the players and see if - // they've collected the required amount. - for (i = 0; i < MAXPLAYERS; i++) - if (playeringame[i]) - { - ssrings += (players[i].mo->health-1); - - // If in water, deplete timer 6x as fast. - if ((players[i].mo->eflags & MFE_TOUCHWATER) - || (players[i].mo->eflags & MFE_UNDERWATER)) - inwater = true; - } - - if (ssrings >= totalrings && totalrings > 0) + if (player->kartstuff[k_spinouttimer]) { - // Halt all the players - for (i = 0; i < MAXPLAYERS; i++) - if (playeringame[i]) - { - players[i].mo->momx = players[i].mo->momy = 0; - players[i].exiting = raceexittime+1; - } - - sstimer = 0; - - P_GiveEmerald(true); + low = high = 65536 / 4; + } + else if (player->kartstuff[k_sneakertimer] > (sneakertime-(TICRATE/2))) + { + low = high = 65536 / 8; + } + else if ((player->kartstuff[k_offroad] && !player->kartstuff[k_hyudorotimer]) + && P_IsObjectOnGround(player->mo) && player->speed != 0) + { + low = high = 65536 / 64; + } + else if (player->kartstuff[k_brakedrift]) + { + low = 0; + high = 65536 / 256; } - // Decrement the timer - if (!objectplacing) - { - if (inwater) - sstimer -= 6; - else - sstimer--; - } + if (low == 0 && high == 0) + continue; + + G_PlayerDeviceRumble(i, low, high, 57); // hack alert! i just dont want this think constantly resetting the rumble lol } } -static inline void P_DoTagStuff(void) +void P_RunChaseCameras(void) { - INT32 i; + UINT8 i; - // tell the netgame who the initial IT person is. - if (leveltime == TICRATE) + for (i = 0; i <= splitscreen; i++) { - for (i = 0; i < MAXPLAYERS; i++) - { - if (players[i].pflags & PF_TAGIT) - { - CONS_Printf(M_GetText("%s is now IT!\n"), player_names[i]); // Tell everyone who is it! - break; - } - } - } - - //increment survivor scores - if (leveltime % TICRATE == 0 && leveltime > (hidetime * TICRATE)) - { - INT32 participants = 0; - - for (i=0; i < MAXPLAYERS; i++) - { - if (playeringame[i] && !players[i].spectator) - participants++; - } - - for (i=0; i < MAXPLAYERS; i++) - { - if (playeringame[i] && !players[i].spectator && players[i].playerstate == PST_LIVE - && !(players[i].pflags & (PF_TAGIT|PF_TAGGED))) - //points given is the number of participating players divided by two. - P_AddPlayerScore(&players[i], participants/2); - } + if (camera[i].chase) + P_MoveChaseCamera(&players[displayplayers[i]], &camera[i], false); } } -static inline void P_DoCTFStuff(void) -{ - // Automatic team balance for CTF and team match - if (leveltime % (TICRATE * 5) == 0) //only check once per five seconds for the sake of CPU conservation. - { - // Do not attempt to autobalance and scramble teams at the same time. - // Only the server should execute this. No verified admins, please. - if ((cv_autobalance.value && !cv_teamscramble.value) && cv_allowteamchange.value && server) - P_DoAutobalanceTeams(); - } - - // Team scramble code for team match and CTF. - if ((leveltime % (TICRATE/7)) == 0) - { - // If we run out of time in the level, the beauty is that - // the Y_Ticker() team scramble code will pick it up. - if (cv_teamscramble.value && server) - P_DoTeamscrambling(); - } -}*/ - // // P_Ticker // @@ -581,13 +405,6 @@ void P_Ticker(boolean run) if (playeringame[i]) ++players[i].jointime; - if (run) - { - // Update old view state BEFORE ticking so resetting - // the old interpolation state from game logic works. - R_UpdateViewInterpolation(); - } - if (objectplacing) { if (OP_FreezeObjectplace()) @@ -683,6 +500,10 @@ void P_Ticker(boolean run) if (run) { + // Dynamic slopeness + if (midgamejoin) // only run here if we joined midgame to fix some desynchs + P_RunDynamicSlopes(); + PS_START_TIMING(ps_thinkertime); P_RunThinkers(); PS_STOP_TIMING(ps_thinkertime); @@ -692,6 +513,12 @@ void P_Ticker(boolean run) if (playeringame[i] && players[i].mo && !P_MobjWasRemoved(players[i].mo)) P_PlayerAfterThink(&players[i]); + // Apply rumble to local players + if (!demo.playback) + { + P_DeviceRumbleTick(); + } + PS_START_TIMING(ps_lua_thinkframe_time); LUAh_ThinkFrame(); PS_STOP_TIMING(ps_lua_thinkframe_time); @@ -716,12 +543,6 @@ void P_Ticker(boolean run) if (!(modeattacking && !demo.playback) || leveltime >= starttime - TICRATE*4) timeinmap++; - /*if (G_TagGametype()) - P_DoTagStuff(); - - if (G_GametypeHasTeams()) - P_DoCTFStuff();*/ - if (run) { if (countdowntimer && --countdowntimer <= 0) @@ -824,16 +645,15 @@ void P_Ticker(boolean run) PS_STOP_TIMING(ps_lua_postthinkframe_time); } + K_UpdateDirector(); + // Always move the camera. - for (i = 0; i <= splitscreen; i++) - { - if (camera[i].chase) - P_MoveChaseCamera(&players[displayplayers[i]], &camera[i], false); - } + P_RunChaseCameras(); if (run) { R_UpdateLevelInterpolators(); + R_UpdateViewInterpolation(); // Hack: ensure newview is assigned every tic. // Ensures view interpolation is T-1 to T in poor network conditions @@ -898,6 +718,10 @@ void P_PreTicker(INT32 frames) memcpy(&players[i].cmd, &temptic, sizeof(ticcmd_t)); } + // Dynamic slopeness + if (midgamejoin) + P_RunDynamicSlopes(); + P_RunThinkers(); // Run any "after all the other thinkers" stuff diff --git a/src/p_tick.h b/src/p_tick.h index 169c54c8e..11b5889ed 100644 --- a/src/p_tick.h +++ b/src/p_tick.h @@ -24,10 +24,11 @@ extern tic_t leveltime; void Command_Numthinkers_f(void); void Command_CountMobjs_f(void); +void P_RunChaseCameras(void); void P_Ticker(boolean run); void P_PreTicker(INT32 frames); void P_DoTeamscrambling(void); -void P_RemoveThinkerDelayed(void *pthinker); //killed +void P_RemoveThinkerDelayed(thinker_t *thinker); mobj_t *P_SetTarget(mobj_t **mo, mobj_t *target); // killough 11/98 #endif diff --git a/src/p_user.c b/src/p_user.c index 6b076a132..7d9e0e21f 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -55,7 +55,6 @@ #endif #ifdef HWRENDER -#include "hardware/hw_light.h" #include "hardware/hw_main.h" #endif @@ -500,44 +499,12 @@ void P_GivePlayerLives(player_t *player, INT32 numlives) // Transform into Super Sonic! void P_DoSuperTransformation(player_t *player, boolean giverings) { + (void)player; + (void)giverings; + return; // SRB2kart - this is not a thing we need - player->powers[pw_super] = 1; - if (!(mapheaderinfo[gamemap-1]->levelflags & LF_NOSSMUSIC) && P_IsLocalPlayer(player)) - { - S_StopMusic(); - S_ChangeMusicInternal("supers", true); - } - - S_StartSound(NULL, sfx_supert); //let all players hear it -mattw_cfi - - // Transformation animation - //P_SetPlayerMobjState(player->mo, S_PLAY_SUPERTRANS1); - - player->mo->momx = player->mo->momy = player->mo->momz = 0; - - if (giverings) - { - player->mo->health = 51; - player->health = player->mo->health; - } - - // Just in case. - if (!(mapheaderinfo[gamemap-1]->levelflags & LF_NOSSMUSIC)) - { - player->powers[pw_extralife] = 0; - player->powers[pw_invulnerability] = 0; - player->powers[pw_sneakers] = 0; - } - - if (gametype != GT_COOP) - { - HU_SetCEchoFlags(0); - HU_SetCEchoDuration(5); - HU_DoCEcho(va("%s\\is now super.\\\\\\\\", player_names[player-players])); - } - - P_PlayerFlagBurst(player, false); } + // Adds to the player's score void P_AddPlayerScore(player_t *player, UINT32 amount) { @@ -591,11 +558,30 @@ void P_PlayLivesJingle(player_t *player) } } -void P_PlayRinglossSound(mobj_t *source) +void P_PlayRinglossSound(mobj_t *source, mobj_t *damager) { sfxenum_t key = P_RandomKey(2); + if (cv_kartvoices.value) - S_StartSound(source, (mariomode) ? sfx_mario8 : sfx_khurt1 + key); + { + if (cv_karthitemdialog.value && source != damager && damager && damager->player && P_IsLocalPlayer(damager->player)) + { + sfxenum_t sfx = sfx_khurt1 + key; + + INT32 skinnum = -1; + + // I HATE LOCALSKINS! I HATE LOCALSKINS! :AAAAAAAAAA: + if (source->player) + skinnum = source->player->skinlocal ? (source->player->localskin - 1) : source->player->skin; + + if (skinnum >= 0) + sfx = (source->player->skinlocal ? localskins : skins)[skinnum].soundsid[SKSKPAN1 + key]; + + S_StartSound(NULL, sfx); + } + else + S_StartSound(source, (mariomode) ? sfx_mario8 : sfx_khurt1 + key); + } else S_StartSound(source, sfx_slip); } @@ -795,20 +781,16 @@ void P_RestoreMusic(player_t *player) } // Item - Grow - if (wantedmus == 2 && cv_growmusic.value) + if (wantedmus == 2 && cv_growmusic.value == 1) { S_ChangeMusicInternal("kgrow", true); - - if (cv_birdmusic.value) - S_SetRestoreMusicFadeInCvar(&cv_growmusicfade); + S_SetRestoreMusicFadeInCvar(&cv_growmusicfade); } // Item - Invincibility - else if (wantedmus == 1 && cv_supermusic.value) + else if (wantedmus == 1 && cv_supermusic.value == 1) { S_ChangeMusicInternal("kinvnc", true); - - if (cv_birdmusic.value) - S_SetRestoreMusicFadeInCvar(&cv_invincmusicfade); + S_SetRestoreMusicFadeInCvar(&cv_invincmusicfade); } else { @@ -825,13 +807,12 @@ void P_RestoreMusic(player_t *player) else position = mapmusposition; - S_ChangeMusicEx(mapmusname, mapmusflags, true, position, 0, - S_GetRestoreMusicFadeIn()); + S_ChangeMusicEx(mapmusname, mapmusflags, true, position, 0, S_GetRestoreMusicFadeIn()); S_ClearRestoreMusicFadeInCvar(); } else S_ChangeMusicEx(mapmusname, mapmusflags, true, mapmusposition, 0, 0); - + mapmusresume = 0; } } @@ -2567,10 +2548,7 @@ static void P_MovePlayer(player_t *player) static void P_DoZoomTube(player_t *player) { - INT32 sequence; fixed_t speed; - thinker_t *th; - mobj_t *mo2; mobj_t *waypoint = NULL; fixed_t dist; boolean reverse; @@ -2586,8 +2564,6 @@ static void P_DoZoomTube(player_t *player) speed = abs(player->speed); - sequence = player->mo->tracer->threshold; - // change slope dist = P_AproxDistance(P_AproxDistance(player->mo->tracer->x - player->mo->x, player->mo->tracer->y - player->mo->y), player->mo->tracer->z - player->mo->z); @@ -2619,26 +2595,7 @@ static void P_DoZoomTube(player_t *player) CONS_Debug(DBG_GAMELOGIC, "Looking for next waypoint...\n"); // Find next waypoint - for (th = thinkercap.next; th != &thinkercap; th = th->next) - { - if (th->function.acp1 != (actionf_p1)P_MobjThinker) // Not a mobj thinker - continue; - - mo2 = (mobj_t *)th; - - if (mo2->type != MT_TUBEWAYPOINT) - continue; - - if (mo2->threshold == sequence) - { - if ((reverse && mo2->health == player->mo->tracer->health - 1) - || (!reverse && mo2->health == player->mo->tracer->health + 1)) - { - waypoint = mo2; - break; - } - } - } + waypoint = reverse ? P_GetPreviousWaypoint(player->mo->tracer, false) : P_GetNextWaypoint(player->mo->tracer, false); if (waypoint) { @@ -2989,12 +2946,19 @@ static void P_DeathThink(player_t *player) else curlap++; // This is too complicated to sync to realtime, just sorta hope for the best :V } + + if (player->spectator) + player->laptime[LAP_CUR] = 0; + else + player->laptime[LAP_CUR]++; // This is too complicated to sync to realtime, just sorta hope for the best :V } else { player->realtime = 0; if (player == &players[consoleplayer]) curlap = 0; + + player->laptime[LAP_CUR] = 0; } } @@ -3051,29 +3015,93 @@ static CV_PossibleValue_t CV_CamSpeed[] = {{0, "MIN"}, {1*FRACUNIT, "MAX"}, {0, static CV_PossibleValue_t rotation_cons_t[] = {{1, "MIN"}, {45, "MAX"}, {0, NULL}}; static CV_PossibleValue_t CV_CamRotate[] = {{-720, "MIN"}, {720, "MAX"}, {0, NULL}}; -consvar_t cv_cam_dist = {"cam_dist", "160", CV_FLOAT|CV_SAVE, NULL, NULL, 0, NULL, NULL, 0, 0, NULL}; -consvar_t cv_cam_height = {"cam_height", "50", CV_FLOAT|CV_SAVE, NULL, NULL, 0, NULL, NULL, 0, 0, NULL}; +static void CV_PlayerCam1_OnChange(void) +{ + if (gamestate != GS_LEVEL) + return; + + if (!playeringame[displayplayers[0]] || players[displayplayers[0]].spectator) + return; + + // dont do stuff when cam speeen at map start + if (leveltime < starttime - TICRATE*4) + return; + + if (camera[displayplayers[0]].chase) + P_ResetCamera(&players[displayplayers[0]], &camera[0]); +} + +static void CV_PlayerCam2_OnChange(void) +{ + if (gamestate != GS_LEVEL) + return; + + if (!playeringame[displayplayers[1]] || players[displayplayers[1]].spectator) + return; + + // dont do stuff when cam speeen at map start + if (leveltime < starttime - TICRATE*4) + return; + + if (camera[displayplayers[1]].chase) + P_ResetCamera(&players[displayplayers[1]], &camera[1]); +} + +static void CV_PlayerCam3_OnChange(void) +{ + if (gamestate != GS_LEVEL) + return; + + if (!playeringame[displayplayers[2]] || players[displayplayers[2]].spectator) + return; + + // dont do stuff when cam speeen at map start + if (leveltime < starttime - TICRATE*4) + return; + + if (camera[displayplayers[2]].chase) + P_ResetCamera(&players[displayplayers[2]], &camera[2]); +} + +static void CV_PlayerCam4_OnChange(void) +{ + if (gamestate != GS_LEVEL) + return; + + if (!playeringame[displayplayers[3]] || players[displayplayers[3]].spectator) + return; + + // dont do stuff when cam speeen at map start + if (leveltime < starttime - TICRATE*4) + return; + + if (camera[displayplayers[3]].chase) + P_ResetCamera(&players[displayplayers[3]], &camera[3]); +} + +consvar_t cv_cam_dist = {"cam_dist", "160", CV_FLOAT|CV_SAVE|CV_CALL|CV_NOINIT, NULL, CV_PlayerCam1_OnChange, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_cam_height = {"cam_height", "50", CV_FLOAT|CV_SAVE|CV_CALL|CV_NOINIT, NULL, CV_PlayerCam1_OnChange, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_cam_still = {"cam_still", "Off", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_cam_speed = {"cam_speed", "0.4", CV_FLOAT|CV_SAVE, CV_CamSpeed, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_cam_rotate = {"cam_rotate", "0", CV_CALL|CV_NOINIT, CV_CamRotate, CV_CamRotate_OnChange, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_cam_rotspeed = {"cam_rotspeed", "10", CV_SAVE, rotation_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; -consvar_t cv_cam2_dist = {"cam2_dist", "160", CV_FLOAT|CV_SAVE, NULL, NULL, 0, NULL, NULL, 0, 0, NULL}; -consvar_t cv_cam2_height = {"cam2_height", "50", CV_FLOAT|CV_SAVE, NULL, NULL, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_cam2_dist = {"cam2_dist", "160", CV_FLOAT|CV_SAVE|CV_CALL|CV_NOINIT, NULL, CV_PlayerCam2_OnChange, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_cam2_height = {"cam2_height", "50", CV_FLOAT|CV_SAVE|CV_CALL|CV_NOINIT, NULL, CV_PlayerCam2_OnChange, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_cam2_still = {"cam2_still", "Off", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_cam2_speed = {"cam2_speed", "0.4", CV_FLOAT|CV_SAVE, CV_CamSpeed, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_cam2_rotate = {"cam2_rotate", "0", CV_CALL|CV_NOINIT, CV_CamRotate, CV_CamRotate2_OnChange, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_cam2_rotspeed = {"cam2_rotspeed", "10", CV_SAVE, rotation_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; -consvar_t cv_cam3_dist = {"cam3_dist", "160", CV_FLOAT|CV_SAVE, NULL, NULL, 0, NULL, NULL, 0, 0, NULL}; -consvar_t cv_cam3_height = {"cam3_height", "50", CV_FLOAT|CV_SAVE, NULL, NULL, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_cam3_dist = {"cam3_dist", "160", CV_FLOAT|CV_SAVE|CV_CALL|CV_NOINIT, NULL, CV_PlayerCam3_OnChange, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_cam3_height = {"cam3_height", "50", CV_FLOAT|CV_SAVE|CV_CALL|CV_NOINIT, NULL, CV_PlayerCam3_OnChange, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_cam3_still = {"cam3_still", "Off", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_cam3_speed = {"cam3_speed", "0.4", CV_FLOAT|CV_SAVE, CV_CamSpeed, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_cam3_rotate = {"cam3_rotate", "0", CV_CALL|CV_NOINIT, CV_CamRotate, CV_CamRotate3_OnChange, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_cam3_rotspeed = {"cam3_rotspeed", "10", CV_SAVE, rotation_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; -consvar_t cv_cam4_dist = {"cam4_dist", "160", CV_FLOAT|CV_SAVE, NULL, NULL, 0, NULL, NULL, 0, 0, NULL}; -consvar_t cv_cam4_height = {"cam4_height", "50", CV_FLOAT|CV_SAVE, NULL, NULL, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_cam4_dist = {"cam4_dist", "160", CV_FLOAT|CV_SAVE|CV_CALL|CV_NOINIT, NULL, CV_PlayerCam4_OnChange, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_cam4_height = {"cam4_height", "50", CV_FLOAT|CV_SAVE|CV_CALL|CV_NOINIT, NULL, CV_PlayerCam4_OnChange, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_cam4_still = {"cam4_still", "Off", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_cam4_speed = {"cam4_speed", "0.4", CV_FLOAT|CV_SAVE, CV_CamSpeed, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_cam4_rotate = {"cam4_rotate", "0", CV_CALL|CV_NOINIT, CV_CamRotate, CV_CamRotate4_OnChange, 0, NULL, NULL, 0, 0, NULL}; @@ -3085,6 +3113,9 @@ consvar_t cv_tiltsmoothing = {"tiltsmoothing", "32", CV_SAVE, CV_Natural, NULL, consvar_t cv_actionmovie = {"actionmovie", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; +static CV_PossibleValue_t lookbackmom_cons_t[] = {{0, "Off"}, {1, "On"}, {2, "Double"}, {0, NULL}}; +consvar_t cv_lookbackmom = {"cameralookbackmom", "Off", CV_SAVE, lookbackmom_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; + fixed_t t_cam_dist = -42; fixed_t t_cam_height = -42; fixed_t t_cam_rotate = -42; @@ -3900,6 +3931,16 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall { thiscam->momx = x - thiscam->x; thiscam->momy = y - thiscam->y; + + // when looking back, camera's momentum + // should inherit the momentum of the player + // if value is 2, add extra + if (cv_lookbackmom.value && lookback && lookbackdelay[num]) + { + thiscam->momx += cv_lookbackmom.value*mo->momx; + thiscam->momy += cv_lookbackmom.value*mo->momy; + } + thiscam->momz = FixedMul(z - thiscam->z, camspeed/2); } @@ -3959,6 +4000,7 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall { P_MoveChaseCamera(player, thiscam, false); R_ResetViewInterpolation(num + 1); + R_ResetViewInterpolation(num + 1); } return (x == thiscam->x && y == thiscam->y && z == thiscam->z && angle == thiscam->aiming); @@ -3989,7 +4031,7 @@ boolean P_SpectatorJoinGame(player_t *player) // Pressing fire assigns you to a team that needs players if allowed. // Partial code reproduction from p_tick.c autobalance code. else if (G_GametypeHasTeams()) - { + { INT32 changeto = 0; INT32 z, numplayersred = 0, numplayersblue = 0; @@ -4042,7 +4084,7 @@ boolean P_SpectatorJoinGame(player_t *player) } // Joining in game from firing. else - { + { if (player->mo) { P_RemoveMobj(player->mo); @@ -4143,8 +4185,18 @@ static void P_CalcPostImg(player_t *player) } } - if (player->mo->eflags & MFE_VERTICALFLIP) - *type = postimg_flip; + if (!encoremode) // srb2kart + { + if (player->mo->eflags & MFE_VERTICALFLIP) + *type = postimg_flip; + } + else + { + if (player->mo->eflags & MFE_VERTICALFLIP) + *type = postimg_mirrorflip; + else + *type = postimg_mirror; + } #if 1 (void)param; @@ -4159,9 +4211,6 @@ static void P_CalcPostImg(player_t *player) *param = 5; } #endif - - if (encoremode) // srb2kart - *type = postimg_mirror; } void P_DoTimeOver(player_t *player) @@ -4200,11 +4249,7 @@ Quaketilt (player_t *player) INT32 delta = (INT32)( player->mo->angle - moma ); fixed_t speed; - boolean sliptiding = - ( - player->kartstuff[k_aizdriftstrat] != 0 && - player->kartstuff[k_drift] == 0 - ); + boolean sliptiding = player->kartstuff[k_drift] ? 0 : player->kartstuff[k_aizdriftstrat]; if (delta == (INT32)ANGLE_180)/* FUCK YOU HAVE A HACK */ { @@ -4232,6 +4277,7 @@ Quaketilt (player_t *player) tilt = ANGLE_22h; lowb = 10*FRACUNIT; } + lowb = FixedMul(lowb, player->mo->scale); moma = FixedMul(FixedDiv(delta, ANGLE_90), tilt); speed = abs( player->mo->momx + player->mo->momy ); if (speed < lowb) @@ -4248,6 +4294,19 @@ DoABarrelRoll (player_t *player) angle_t slope; angle_t delta; + fixed_t smoothing; + + if (player->exiting) + { + return; + } + + if (player->kartstuff[k_respawn]) + { + player->tilt = 0; + return; + } + if (player->mo->standingslope) { slope = player->mo->standingslope->real_zangle; @@ -4272,26 +4331,16 @@ DoABarrelRoll (player_t *player) slope -= Quaketilt(player); } - delta = (INT32)( slope - player->tilt )/ cv_tiltsmoothing.value; + delta = slope - player->tilt; + smoothing = FixedDiv(AbsAngle(slope), ANGLE_45); + + delta = FixedDiv(delta, cv_tiltsmoothing.value * + FixedDiv(FRACUNIT, FRACUNIT + smoothing)); if (delta) player->tilt += delta; else - player->tilt = slope; - - if (cv_tilting.value) - { - player->viewrollangle = player->tilt; - - if (cv_actionmovie.value) - { - player->viewrollangle += quake.roll; - } - } - else - { - player->viewrollangle = 0; - } + player->tilt = slope; } // @@ -4303,11 +4352,6 @@ void P_PlayerThink(player_t *player) ticcmd_t *cmd; const size_t playeri = (size_t)(player - players); - player->lerp.aiming = player->aiming; - player->lerp.awayviewaiming = player->awayviewaiming; - player->lerp.frameangle = player->frameangle; - player->lerp.viewrollangle = player->viewrollangle; - #ifdef PARANOIA if (!player->mo) I_Error("p_playerthink: players[%s].mo == NULL", sizeu1(playeri)); @@ -4533,12 +4577,19 @@ void P_PlayerThink(player_t *player) else curlap++; // This is too complicated to sync to realtime, just sorta hope for the best :V } + + if (player->spectator) + player->laptime[LAP_CUR] = 0; + else + player->laptime[LAP_CUR]++; // This is too complicated to sync to realtime, just sorta hope for the best :V } else { player->realtime = 0; if (player == &players[consoleplayer]) curlap = 0; + + player->laptime[LAP_CUR] = 0; } } @@ -4877,7 +4928,7 @@ void P_PlayerAfterThink(player_t *player) #ifdef SECTORSPECIALSAFTERTHINK if (player->onconveyor != 1 || !P_IsObjectOnGround(player->mo)) - player->onconveyor = 0; + player->onconveyor = 0; // check special sectors : damage & secrets if (!player->spectator) diff --git a/src/r_bsp.c b/src/r_bsp.c index 83f530f2a..54d6cada1 100644 --- a/src/r_bsp.c +++ b/src/r_bsp.c @@ -39,6 +39,10 @@ drawseg_t *ds_p = NULL; // indicates doors closed wrt automap bugfix: INT32 doorclosed; +// A wall was drawn covering the whole screen, which means we +// can block off the BSP across that seg. +boolean g_walloffscreen; + boolean R_NoEncore(sector_t *sector, boolean ceiling) { boolean invertencore = (GETSECSPECIAL(sector->special, 2) == 15); @@ -163,7 +167,7 @@ crunch: // Clips the given range of columns, but does not include it in the clip list. // Does handle windows, e.g. LineDefs with upper and lower texture. // -static inline void R_ClipPassWallSegment(INT32 first, INT32 last) +static inline void R_ClipPassWallSegment(INT32 first, INT32 last, boolean soliddontrender) { cliprange_t *start; @@ -178,12 +182,14 @@ static inline void R_ClipPassWallSegment(INT32 first, INT32 last) if (last < start->first - 1) { // Post is entirely visible (above start). - R_StoreWallRange(first, last); + if (!soliddontrender) + R_StoreWallRange(first, last); return; } // There is a fragment above *start. - R_StoreWallRange(first, start->first - 1); + if (!soliddontrender) + R_StoreWallRange(first, start->first - 1); } // Bottom contained in start? @@ -193,7 +199,8 @@ static inline void R_ClipPassWallSegment(INT32 first, INT32 last) while (last >= (start+1)->first - 1) { // There is a fragment between two posts. - R_StoreWallRange(start->last + 1, (start+1)->first - 1); + if (!soliddontrender) + R_StoreWallRange(start->last + 1, (start+1)->first - 1); start++; if (last <= start->last) @@ -201,7 +208,8 @@ static inline void R_ClipPassWallSegment(INT32 first, INT32 last) } // There is a fragment after *next. - R_StoreWallRange(start->last + 1, last); + if (!soliddontrender) + R_StoreWallRange(start->last + 1, last); } // @@ -251,22 +259,25 @@ sector_t *R_FakeFlat(sector_t *sec, sector_t *tempsec, INT32 *floorlightlevel, else if (sec->heightsec != -1) { const sector_t *s = §ors[sec->heightsec]; - mobj_t *viewmobj = viewplayer->mo; + mobj_t *pviewmobj = viewplayer->mo; INT32 heightsec; boolean underwater; UINT8 i; for (i = 0; i <= splitscreen; i++) { - if (viewplayer == &players[displayplayers[i]] && camera[i].chase) - { - heightsec = R_PointInSubsector(camera[i].x, camera[i].y)->sector->heightsec; - break; - } + if (viewplayer != &players[displayplayers[i]]) + continue; + + if (!camera[i].chase) + continue; + + heightsec = R_PointInSubsector(camera[i].x, camera[i].y)->sector->heightsec; + break; } - if (i > splitscreen && viewmobj) - heightsec = R_PointInSubsector(viewmobj->x, viewmobj->y)->sector->heightsec; + if (i > splitscreen && pviewmobj) + heightsec = R_PointInSubsector(pviewmobj->x, pviewmobj->y)->sector->heightsec; else return sec; @@ -412,17 +423,8 @@ static void R_AddLine(seg_t *line) return; // big room fix - - if (cv_pointoangleexor64.value) - { - angle1 = R_PointToAngle64(line->v1->x, line->v1->y); - angle2 = R_PointToAngle64(line->v2->x, line->v2->y); - } - else - { - angle1 = R_PointToAngleEx(viewx, viewy, line->v1->x, line->v1->y); - angle2 = R_PointToAngleEx(viewx, viewy, line->v2->x, line->v2->y); - } + angle1 = R_PointToAngle64(line->v1->x, line->v1->y); + angle2 = R_PointToAngle64(line->v2->x, line->v2->y); curline = line; @@ -579,10 +581,15 @@ static void R_AddLine(seg_t *line) return; clippass: - R_ClipPassWallSegment(x1, x2 - 1); + g_walloffscreen = false; + if (g_walloffscreen) + R_ClipPassWallSegment(x1, x2 - 1, true); + else + R_ClipPassWallSegment(x1, x2 - 1, false); return; clipsolid: + g_walloffscreen = false; R_ClipSolidWallSegment(x1, x2 - 1); } @@ -625,16 +632,8 @@ static boolean R_CheckBBox(const fixed_t *bspcoord) check = checkcoord[boxpos]; // big room fix - if (cv_pointoangleexor64.value) - { - angle1 = R_PointToAngle64(bspcoord[check[0]], bspcoord[check[1]]) - viewangle; - angle2 = R_PointToAngle64(bspcoord[check[2]], bspcoord[check[3]]) - viewangle; - } - else - { - angle1 = R_PointToAngleEx(viewx, viewy, bspcoord[check[0]], bspcoord[check[1]]) - viewangle; - angle2 = R_PointToAngleEx(viewx, viewy, bspcoord[check[2]], bspcoord[check[3]]) - viewangle; - } + angle1 = R_PointToAngle64(bspcoord[check[0]], bspcoord[check[1]]) - viewangle; + angle2 = R_PointToAngle64(bspcoord[check[2]], bspcoord[check[3]]) - viewangle; if ((signed)angle1 < (signed)angle2) { @@ -894,11 +893,11 @@ static void R_Subsector(size_t num) { sector_t *controlSec = §ors[rover->secnum]; - if (controlSec->moved == true) - { - anyMoved = true; - break; - } + if (controlSec->moved != true) + continue; + + anyMoved = true; + break; } } @@ -1075,10 +1074,10 @@ static void R_Subsector(size_t num) { light = R_GetPlaneLight(frontsector, polysec->floorheight, viewz < polysec->floorheight); ffloor[numffloors].plane = R_FindPlane(polysec->floorheight, polysec->floorpic, - polysec->lightlevel, polysec->floor_xoffs, polysec->floor_yoffs, - polysec->floorpic_angle-po->angle, - NULL, NULL, po - , NULL // will ffloors be slopable eventually? + (light == -1 ? frontsector->lightlevel : *frontsector->lightlist[light].lightlevel), polysec->floor_xoffs, polysec->floor_yoffs, + polysec->floorpic_angle-po->angle, + (light == -1 ? frontsector->extra_colormap : frontsector->lightlist[light].extra_colormap), NULL, po + ,NULL // will ffloors be slopable eventually? , R_NoEncore(polysec, false)); ffloor[numffloors].height = polysec->floorheight; @@ -1098,12 +1097,11 @@ static void R_Subsector(size_t num) && polysec->ceilingheight <= ceilingcenterz && (viewz > polysec->ceilingheight)) { - light = R_GetPlaneLight(frontsector, polysec->ceilingheight, viewz < polysec->ceilingheight); + light = R_GetPlaneLight(frontsector, polysec->floorheight, viewz < polysec->floorheight); ffloor[numffloors].plane = R_FindPlane(polysec->ceilingheight, polysec->ceilingpic, - polysec->lightlevel, polysec->ceiling_xoffs, polysec->ceiling_yoffs, - polysec->ceilingpic_angle-po->angle, - NULL, NULL, po - , NULL // will ffloors be slopable eventually? + (light == -1 ? frontsector->lightlevel : *frontsector->lightlist[light].lightlevel), polysec->ceiling_xoffs, polysec->ceiling_yoffs, polysec->ceilingpic_angle-po->angle, + (light == -1 ? frontsector->extra_colormap : frontsector->lightlist[light].extra_colormap), NULL, po + ,NULL // will ffloors be slopable eventually? , R_NoEncore(polysec, true)); ffloor[numffloors].polyobj = po; @@ -1147,7 +1145,7 @@ static void R_Subsector(size_t num) { // CONS_Debug(DBG_GAMELOGIC, "Adding normal line %d...(%d)\n", line->linedef-lines, leveltime); if (!line->polyseg) // ignore segs that belong to polyobjects - R_AddLine(line); + R_AddLine(line); line++; curline = NULL; /* cph 2001/11/18 - must clear curline now we're done with it, so stuff doesn't try using it for other things */ } @@ -1209,7 +1207,7 @@ void R_Prep3DFloors(sector_t *sector) rover->lastlight = 0; if (!(rover->flags & FF_EXISTS) || (rover->flags & FF_NOSHADE && !(rover->flags & FF_CUTLEVEL) && !(rover->flags & FF_CUTSPRITES))) - continue; + continue; heighttest = *rover->t_slope ? P_GetZAt(*rover->t_slope, sector->soundorg.x, sector->soundorg.y) : *rover->topheight; @@ -1311,7 +1309,7 @@ INT32 R_GetPlaneLight(sector_t *sector, fixed_t planeheight, boolean underside) void R_RenderBSPNode(INT32 bspnum) { - node_t *bsp; + const node_t *bsp; INT32 side; ps_numbspcalls.value.i++; diff --git a/src/r_bsp.h b/src/r_bsp.h index f0db9066f..2803a90e4 100644 --- a/src/r_bsp.h +++ b/src/r_bsp.h @@ -32,6 +32,7 @@ extern INT32 checkcoord[12][4]; extern drawseg_t *drawsegs; extern drawseg_t *ds_p; extern INT32 doorclosed; +extern boolean g_walloffscreen; // BSP? void R_ClearClipSegs(void); diff --git a/src/r_data.c b/src/r_data.c index 69b0ce1ac..98431510d 100644 --- a/src/r_data.c +++ b/src/r_data.c @@ -429,22 +429,24 @@ void R_LoadTextures(void) } // Add all the textures between TX_START and TX_END - if (texstart != INT16_MAX && texend != INT16_MAX) + if (texstart == INT16_MAX || texend == INT16_MAX) + continue; + + // PK3s have subfolders, so we can't just make a simple sum + if (W_FileHasFolders(wadfiles[w])) { - // PK3s have subfolders, so we can't just make a simple sum - if (W_FileHasFolders(wadfiles[w])) + for (j = texstart; j < texend; j++) { - for (j = texstart; j < texend; j++) - { - if (!W_IsLumpFolder((UINT16)w, j)) // Check if lump is a folder; if not, then count it - numtextures++; - } - } - else - { - numtextures += (UINT32)(texend - texstart); + if (W_IsLumpFolder((UINT16)w, j)) // Check if lump is a folder; if not, then count it + continue; + + numtextures++; } } + else + { + numtextures += (UINT32)(texend - texstart); + } } // If no textures found by this point, bomb out @@ -522,7 +524,7 @@ void R_LoadTextures(void) patch->wad = (UINT16)w; patch->lump = texstart + j; - Z_Unlock(patchlump); + Z_Free(patchlump); k = 1; while (k << 1 <= texture->width) @@ -1003,26 +1005,26 @@ lumpnum_t R_GetFlatNumForName(const char *name) { switch (wadfiles[i]->type) { - case RET_WAD: - if ((start = W_CheckNumForNamePwad("F_START", (UINT16)i, 0)) == INT16_MAX) - { - if ((start = W_CheckNumForNamePwad("FF_START", (UINT16)i, 0)) == INT16_MAX) + case RET_WAD: + if ((start = W_CheckNumForNamePwad("F_START", (UINT16)i, 0)) == INT16_MAX) + { + if ((start = W_CheckNumForNamePwad("FF_START", (UINT16)i, 0)) == INT16_MAX) + continue; + else if ((end = W_CheckNumForNamePwad("FF_END", (UINT16)i, start)) == INT16_MAX) + continue; + } + else + if ((end = W_CheckNumForNamePwad("F_END", (UINT16)i, start)) == INT16_MAX) + continue; + break; + case RET_PK3: + if ((start = W_CheckNumForFolderStartPK3("Flats/", i, 0)) == INT16_MAX) continue; - else if ((end = W_CheckNumForNamePwad("FF_END", (UINT16)i, start)) == INT16_MAX) + if ((end = W_CheckNumForFolderEndPK3("Flats/", i, start)) == INT16_MAX) continue; - } - else - if ((end = W_CheckNumForNamePwad("F_END", (UINT16)i, start)) == INT16_MAX) - continue; - break; - case RET_PK3: - if ((start = W_CheckNumForFolderStartPK3("Flats/", i, 0)) == INT16_MAX) + break; + default: continue; - if ((end = W_CheckNumForFolderEndPK3("Flats/", i, start)) == INT16_MAX) - continue; - break; - default: - continue; } // Now find lump with specified name in that range. @@ -1310,6 +1312,7 @@ INT32 R_CreateColormap(char *p1, char *p2, char *p3) { if (foundcolormaps[i] != LUMPERROR) continue; + if (maskcolor == extra_colormaps[i].maskcolor && fadecolor == extra_colormaps[i].fadecolor && fabs(maskamt - extra_colormaps[i].maskamt) < DBL_EPSILON diff --git a/src/r_defs.h b/src/r_defs.h index 81e3f0c3a..71e13e4d4 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -25,7 +25,6 @@ #include "screen.h" // MAXVIDWIDTH, MAXVIDHEIGHT - // // ClipWallSegment // Clips the given range of columns @@ -257,6 +256,12 @@ typedef struct pslope_s mapthing_t **vertices; // List should be three long for slopes made by vertex things, or one long for slopes using one vertex thing to anchor struct pslope_s *next; // Make a linked list of dynamic slopes, for easy reference later + + // Light offsets (see seg_t) + SINT8 lightOffset; +#ifdef HWRENDER + INT16 hwLightOffset; +#endif } pslope_t; typedef enum @@ -454,7 +459,7 @@ typedef struct subsector_s { sector_t *sector; INT16 numlines; - UINT16 firstline; + UINT32 firstline; struct polyobj_s *polyList; // haleyjd 02/19/06: list of polyobjects #if 1//#ifdef FLOORSPLATS void *splats; // floorsplat_t list @@ -533,6 +538,12 @@ typedef struct seg_s r_lightlist_t *rlights; polyobj_t *polyseg; boolean dontrenderme; + + // Fake contrast calculated on level load + SINT8 lightOffset; +#ifdef HWRENDER + INT16 hwLightOffset; +#endif } seg_t; // @@ -648,15 +659,8 @@ typedef struct INT16 height; INT16 leftoffset; // pixels to the left of origin INT16 topoffset; // pixels below the origin - INT32 columnofs[8]; // only [width] used - UINT8 *columns; // Software column data + INT32 columnofs[]; // only [width] used // the [0] is &columnofs[width] - - void *hardware; // OpenGL patch, allocated whenever necessary - -#ifdef ROTSPRITE - rotsprite_t *rotated; // Rotated patches -#endif } patch_t; #ifdef _MSC_VER diff --git a/src/r_draw.c b/src/r_draw.c index c19febc8a..fa19a6ac2 100644 --- a/src/r_draw.c +++ b/src/r_draw.c @@ -143,7 +143,7 @@ UINT32 nflatxshift, nflatyshift, nflatshiftup, nflatmask; #define NUM_PALETTE_ENTRIES 256 static UINT8** translationtablecache[TT_CACHE_SIZE] = {NULL}; -static UINT8** localtranslationtablecache[MAXSKINS] = {NULL}; +static UINT8** localtranslationtablecache[MAXLOCALSKINS] = {NULL}; // See also the enum skincolors_t diff --git a/src/r_draw8.c b/src/r_draw8.c index 93a0796a3..57f5366aa 100644 --- a/src/r_draw8.c +++ b/src/r_draw8.c @@ -43,16 +43,15 @@ void R_DrawColumn_8(void) // Use ylookup LUT to avoid multiply with ScreenWidth. // Use columnofs LUT for subwindows? - //dest = ylookup[dc_yl] + columnofs[dc_x]; dest = &topleft[dc_yl*vid.width + dc_x]; count++; // Determine scaling, which is the only mapping to be done. fracstep = dc_iscale; - //frac = dc_texturemid + (dc_yl - centery)*fracstep; frac = (dc_texturemid + FixedMul((dc_yl << FRACBITS) - centeryfrac, fracstep))*(!dc_hires); + // Inner loop that does the actual texture mapping, e.g. a DDA-like scaling. // This is as fast as it gets. { @@ -644,7 +643,7 @@ void R_CalcTiltedLighting(fixed_t start, fixed_t end) } } -#define PLANELIGHTFLOAT (BASEVIDWIDTH * BASEVIDWIDTH / vid.width / (zeroheight - FIXED_TO_FLOAT(viewz)) / 21.0f * FIXED_TO_FLOAT(fovtan)) +#define PLANELIGHTFLOAT ((float)BASEVIDWIDTH * BASEVIDWIDTH / vid.width / (zeroheight - FIXED_TO_FLOAT(viewz)) / 21.0f * FIXED_TO_FLOAT(fovtan)) /** \brief The R_DrawTiltedSpan_8 function Draw slopes! Holy sheit! @@ -943,7 +942,7 @@ void R_DrawTiltedTranslucentWaterSpan_8(void) // Lighting is simple. It's just linear interpolation from start to end { - float planelightfloat = BASEVIDWIDTH*BASEVIDWIDTH/vid.width / (zeroheight - FIXED_TO_FLOAT(viewz)) / 21.0f; + float planelightfloat = PLANELIGHTFLOAT; float lightstart, lightend; lightend = (iz + ds_szp->x*width) * planelightfloat; @@ -1696,7 +1695,7 @@ void R_DrawColumnShadowed_8(void) { dc_colormap = dc_lightlist[i].rcolormap; if (encoremap) - dc_colormap += (256*32); + dc_colormap += COLORMAP_REMAPOFFSET; if (solid && dc_yl < bheight) dc_yl = bheight; continue; @@ -1714,7 +1713,7 @@ void R_DrawColumnShadowed_8(void) dc_colormap = dc_lightlist[i].rcolormap; if (encoremap) - dc_colormap += (256*32); + dc_colormap += COLORMAP_REMAPOFFSET; } dc_yh = realyh; if (dc_yl <= realyh) diff --git a/src/r_fps.c b/src/r_fps.c index 91044b42e..9ccba8a7b 100644 --- a/src/r_fps.c +++ b/src/r_fps.c @@ -23,7 +23,6 @@ #include "r_state.h" #include "z_zone.h" #include "console.h" // con_startup_loadprogress -#include "i_time.h" #ifdef HWRENDER #include "hardware/hw_main.h" // for cv_grshearing @@ -45,8 +44,6 @@ consvar_t cv_fpscap = {"fpscap", "Match refresh rate", CV_SAVE, fpscap_cons_t, N consvar_t cv_precipinterp = {"precipinterpolation", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; -consvar_t cv_mobjssector = {"mobjsubsectorinterp", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; - UINT32 R_GetFramerateCap(void) { if (rendermode == render_none) @@ -82,7 +79,6 @@ static viewvars_t skyview_old[MAXSPLITSCREENPLAYERS]; static viewvars_t skyview_new[MAXSPLITSCREENPLAYERS]; static viewvars_t *oldview = &pview_old[0]; -static tic_t last_view_update; static int oldview_invalid[MAXSPLITSCREENPLAYERS] = {0, 0, 0, 0}; viewvars_t *newview = &pview_new[0]; @@ -94,13 +90,17 @@ static size_t levelinterpolators_len; static size_t levelinterpolators_size; -static fixed_t R_LerpFixed(fixed_t from, fixed_t to, fixed_t frac) +static inline fixed_t R_LerpFixed(fixed_t from, fixed_t to, fixed_t frac) { + if (from == to) + return to; return from + FixedMul(frac, to - from); } -static angle_t R_LerpAngle(angle_t from, angle_t to, fixed_t frac) +static inline angle_t R_LerpAngle(angle_t from, angle_t to, fixed_t frac) { + if (from == to) + return to; return from + FixedMul(frac, to - from); } @@ -149,6 +149,11 @@ static void R_SetupFreelook(void) #undef AIMINGTODY +void R_InterpolateViewRollAngle(fixed_t frac) +{ + viewroll = R_LerpAngle(oldview->roll, newview->roll, frac); +} + void R_InterpolateView(fixed_t frac, boolean forceinvalid) { viewvars_t* prevview = oldview; @@ -180,12 +185,11 @@ void R_InterpolateView(fixed_t frac, boolean forceinvalid) viewangle = R_LerpAngle(prevview->angle, newview->angle, frac); aimingangle = R_LerpAngle(prevview->aim, newview->aim, frac); + viewroll = R_LerpAngle(prevview->roll, newview->roll, frac); viewsin = FINESINE(viewangle>>ANGLETOFINESHIFT); viewcos = FINECOSINE(viewangle>>ANGLETOFINESHIFT); - // this is gonna create some interesting visual errors for long distance teleports... - // might want to recalculate the view sector every frame instead... viewplayer = newview->player; viewsector = R_PointInSubsector(viewx, viewy)->sector; @@ -203,27 +207,21 @@ void R_UpdateViewInterpolation(void) if (oldview_invalid[i]) oldview_invalid[i]--; } - - last_view_update = I_GetTime(); } void R_ResetViewInterpolation(UINT8 p) { - // Wait an extra tic if the interpolation state hasn't - // updated yet. - int t = last_view_update == I_GetTime() ? 1 : 2; - if (p == 0) { UINT8 i; for (i = 0; i < MAXSPLITSCREENPLAYERS; i++) { - oldview_invalid[i] = t; + oldview_invalid[i]++; } } else { - oldview_invalid[p - 1] = t; + oldview_invalid[p - 1]++; } } @@ -308,87 +306,41 @@ void R_InterpolateMobjState(mobj_t *mobj, fixed_t frac, interpmobjstate_t *out) return; } - if (mobj->x == mobj->old_x) - out->x = mobj->x; - else - out->x = R_LerpFixed(mobj->old_x, mobj->x, frac); - - if (mobj->y == mobj->old_y) - out->y = mobj->y; - else - out->y = R_LerpFixed(mobj->old_y, mobj->y, frac); - - if (mobj->z == mobj->old_z) - out->z = mobj->z; - else - out->z = R_LerpFixed(mobj->old_z, mobj->z, frac); - - if (mobj->spritexscale == mobj->old_spritexscale) - out->spritexscale = mobj->spritexscale; - else - out->spritexscale = mobj->resetinterp ? mobj->spritexscale : R_LerpFixed(mobj->old_spritexscale, mobj->spritexscale, frac); - - if (mobj->spriteyscale == mobj->old_spriteyscale) - out->spriteyscale = mobj->spriteyscale; - else - out->spriteyscale = mobj->resetinterp ? mobj->spriteyscale : R_LerpFixed(mobj->old_spriteyscale, mobj->spriteyscale, frac); - - if (mobj->spritexoffset == mobj->old_spritexoffset) - out->spritexoffset = mobj->spritexoffset; - else - out->spritexoffset = mobj->resetinterp ? mobj->spritexoffset : R_LerpFixed(mobj->old_spritexoffset, mobj->spritexoffset, frac); - - if (mobj->spriteyoffset == mobj->old_spriteyoffset) - out->spriteyoffset = mobj->spriteyoffset; - else - out->spriteyoffset = mobj->resetinterp ? mobj->spriteyoffset : R_LerpFixed(mobj->old_spriteyoffset, mobj->spriteyoffset, frac); - - if (mobj->scale == mobj->old_scale) // Tiny optimisation - scale is usually unchanging, so let's skip a lerp, two FixedMuls, and two FixedDivs - out->scale = mobj->scale; - else - out->scale = mobj->resetinterp ? mobj->scale : R_LerpFixed(mobj->old_scale, mobj->scale, frac); - - if (cv_mobjssector.value) - out->subsector = R_PointInSubsector(out->x, out->y); - else - out->subsector = mobj->subsector; + out->x = R_LerpFixed(mobj->old_x, mobj->x, frac); + out->y = R_LerpFixed(mobj->old_y, mobj->y, frac); + out->z = R_LerpFixed(mobj->old_z, mobj->z, frac); + out->spritexscale = mobj->resetinterp ? mobj->spritexscale : R_LerpFixed(mobj->old_spritexscale, mobj->spritexscale, frac); + out->spriteyscale = mobj->resetinterp ? mobj->spriteyscale : R_LerpFixed(mobj->old_spriteyscale, mobj->spriteyscale, frac); + out->spritexoffset = mobj->resetinterp ? mobj->spritexoffset : R_LerpFixed(mobj->old_spritexoffset, mobj->spritexoffset, frac); + out->spriteyoffset = mobj->resetinterp ? mobj->spriteyoffset : R_LerpFixed(mobj->old_spriteyoffset, mobj->spriteyoffset, frac); + out->scale = mobj->resetinterp ? mobj->scale : R_LerpFixed(mobj->old_scale, mobj->scale, frac); + //out->subsector = R_PointInSubsector(out->x, out->y); // why was this even done? + out->subsector = mobj->subsector; if (mobj->player) - { - if (mobj->angle == mobj->player->old_frameangle) - out->angle = mobj->player->frameangle; - else - out->angle = mobj->resetinterp ? mobj->player->frameangle : R_LerpAngle(mobj->player->old_frameangle, mobj->player->frameangle, frac); - } + out->angle = mobj->resetinterp ? mobj->player->frameangle : R_LerpAngle(mobj->player->old_frameangle, mobj->player->frameangle, frac); else - { - if (mobj->angle == mobj->old_angle) - out->angle = mobj->angle; - else - out->angle = mobj->resetinterp ? mobj->angle : R_LerpAngle(mobj->old_angle, mobj->angle, frac); - } + out->angle = mobj->resetinterp ? mobj->angle : R_LerpAngle(mobj->old_angle, mobj->angle, frac); - // pitch roll stuff - if (mobj->pitch == mobj->old_pitch) - out->pitch = mobj->pitch; - else +#ifdef HWRENDER + if (cv_grmdls.value) + { + // pitch roll stuff out->pitch = mobj->resetinterp ? mobj->pitch : R_LerpAngle(mobj->old_pitch, mobj->pitch, frac); - - if (mobj->roll == mobj->old_roll) - out->roll = mobj->roll; - else out->roll = mobj->resetinterp ? mobj->roll : R_LerpAngle(mobj->old_roll, mobj->roll, frac); - // and the slope stuff - if (mobj->slopepitch == mobj->old_slopepitch) - out->slopepitch = mobj->slopepitch; - else + // and the slope stuff out->slopepitch = mobj->resetinterp ? mobj->slopepitch : R_LerpAngle(mobj->old_slopepitch, mobj->slopepitch, frac); - - if (mobj->sloperoll == mobj->old_sloperoll) - out->sloperoll = mobj->sloperoll; - else out->sloperoll = mobj->resetinterp ? mobj->sloperoll : R_LerpAngle(mobj->old_sloperoll, mobj->sloperoll, frac); + } + else +#endif + { + out->pitch = mobj->pitch; + out->roll = mobj->roll; + out->slopepitch = mobj->slopepitch; + out->sloperoll = mobj->sloperoll; + } } void R_InterpolatePrecipMobjState(precipmobj_t *mobj, fixed_t frac, interpmobjstate_t *out) @@ -398,7 +350,7 @@ void R_InterpolatePrecipMobjState(precipmobj_t *mobj, fixed_t frac, interpmobjst out->x = mobj->x; out->y = mobj->y; out->z = mobj->z; - out->scale = FRACUNIT; + out->scale = cv_mobjscaleprecip.value ? mapobjectscale : FRACUNIT; out->subsector = mobj->subsector; out->angle = mobj->angle; out->spritexscale = mobj->spritexscale; @@ -411,21 +363,15 @@ void R_InterpolatePrecipMobjState(precipmobj_t *mobj, fixed_t frac, interpmobjst out->x = R_LerpFixed(mobj->old_x, mobj->x, frac); out->y = R_LerpFixed(mobj->old_y, mobj->y, frac); out->z = R_LerpFixed(mobj->old_z, mobj->z, frac); - out->scale = FRACUNIT; + out->scale = cv_mobjscaleprecip.value ? mapobjectscale : FRACUNIT; out->spritexscale = mobj->spritexscale; out->spriteyscale = mobj->spriteyscale; out->spritexoffset = mobj->spritexoffset; out->spriteyoffset = mobj->spriteyoffset; - if (cv_mobjssector.value) - out->subsector = R_PointInSubsector(out->x, out->y); - else - out->subsector = mobj->subsector; - - if (mobj->angle == mobj->old_angle) - out->angle = mobj->angle; - else - out->angle = R_LerpAngle(mobj->old_angle, mobj->angle, frac); + //out->subsector = R_PointInSubsector(out->x, out->y); // i dont understand lol + out->subsector = mobj->subsector; + out->angle = R_LerpAngle(mobj->old_angle, mobj->angle, frac); } static void AddInterpolator(levelinterpolator_t* interpolator) @@ -634,81 +580,35 @@ void R_ApplyLevelInterpolators(fixed_t frac) { case LVLINTERP_SectorPlane: if (interp->sectorplane.ceiling) - { - if (interp->sectorplane.sector->ceilingheight == interp->sectorplane.oldheight) - interp->sectorplane.sector->ceilingheight = interp->sectorplane.bakheight; - else - interp->sectorplane.sector->ceilingheight = R_LerpFixed(interp->sectorplane.oldheight, interp->sectorplane.bakheight, frac); - } + interp->sectorplane.sector->ceilingheight = R_LerpFixed(interp->sectorplane.oldheight, interp->sectorplane.bakheight, frac); else - { - if (interp->sectorplane.sector->floorheight == interp->sectorplane.oldheight) - interp->sectorplane.sector->floorheight = interp->sectorplane.bakheight; - else - interp->sectorplane.sector->floorheight = R_LerpFixed(interp->sectorplane.oldheight, interp->sectorplane.bakheight, frac); - } + interp->sectorplane.sector->floorheight = R_LerpFixed(interp->sectorplane.oldheight, interp->sectorplane.bakheight, frac); interp->sectorplane.sector->moved = true; break; case LVLINTERP_SectorScroll: if (interp->sectorscroll.ceiling) { - if (interp->sectorscroll.sector->ceiling_xoffs == interp->sectorscroll.oldxoffs) - interp->sectorscroll.sector->ceiling_xoffs = interp->sectorscroll.bakxoffs; - else - interp->sectorscroll.sector->ceiling_xoffs = R_LerpFixed(interp->sectorscroll.oldxoffs, interp->sectorscroll.bakxoffs, frac); - - if (interp->sectorscroll.sector->ceiling_yoffs == interp->sectorscroll.oldyoffs) - interp->sectorscroll.sector->ceiling_yoffs = interp->sectorscroll.bakyoffs; - else - interp->sectorscroll.sector->ceiling_yoffs = R_LerpFixed(interp->sectorscroll.oldyoffs, interp->sectorscroll.bakyoffs, frac); + interp->sectorscroll.sector->ceiling_xoffs = R_LerpFixed(interp->sectorscroll.oldxoffs, interp->sectorscroll.bakxoffs, frac); + interp->sectorscroll.sector->ceiling_yoffs = R_LerpFixed(interp->sectorscroll.oldyoffs, interp->sectorscroll.bakyoffs, frac); } else { - if (interp->sectorscroll.sector->floor_xoffs == interp->sectorscroll.oldxoffs) - interp->sectorscroll.sector->floor_xoffs = interp->sectorscroll.bakxoffs; - else - interp->sectorscroll.sector->floor_xoffs = R_LerpFixed(interp->sectorscroll.oldxoffs, interp->sectorscroll.bakxoffs, frac); - - if (interp->sectorscroll.sector->floor_yoffs == interp->sectorscroll.oldyoffs) - interp->sectorscroll.sector->floor_yoffs = interp->sectorscroll.bakyoffs; - else - interp->sectorscroll.sector->floor_yoffs = R_LerpFixed(interp->sectorscroll.oldyoffs, interp->sectorscroll.bakyoffs, frac); + interp->sectorscroll.sector->floor_xoffs = R_LerpFixed(interp->sectorscroll.oldxoffs, interp->sectorscroll.bakxoffs, frac); + interp->sectorscroll.sector->floor_yoffs = R_LerpFixed(interp->sectorscroll.oldyoffs, interp->sectorscroll.bakyoffs, frac); } break; case LVLINTERP_SideScroll: - if (interp->sidescroll.side->textureoffset == interp->sidescroll.oldtextureoffset) - interp->sidescroll.side->textureoffset = interp->sidescroll.baktextureoffset; - else - interp->sidescroll.side->textureoffset = R_LerpFixed(interp->sidescroll.oldtextureoffset, interp->sidescroll.baktextureoffset, frac); - - if (interp->sidescroll.side->rowoffset == interp->sidescroll.oldrowoffset) - interp->sidescroll.side->rowoffset = interp->sidescroll.bakrowoffset; - else - interp->sidescroll.side->rowoffset = R_LerpFixed(interp->sidescroll.oldrowoffset, interp->sidescroll.bakrowoffset, frac); + interp->sidescroll.side->textureoffset = R_LerpFixed(interp->sidescroll.oldtextureoffset, interp->sidescroll.baktextureoffset, frac); + interp->sidescroll.side->rowoffset = R_LerpFixed(interp->sidescroll.oldrowoffset, interp->sidescroll.bakrowoffset, frac); break; case LVLINTERP_Polyobj: for (ii = 0; ii < interp->polyobj.vertices_size; ii++) { - if (interp->polyobj.polyobj->vertices[ii]->x == interp->polyobj.oldvertices[ii * 2 ]) - interp->polyobj.polyobj->vertices[ii]->x = interp->polyobj.bakvertices[ii * 2 ]; - else - interp->polyobj.polyobj->vertices[ii]->x = R_LerpFixed(interp->polyobj.oldvertices[ii * 2 ], interp->polyobj.bakvertices[ii * 2 ], frac); - - if (interp->polyobj.polyobj->vertices[ii]->y == interp->polyobj.oldvertices[ii * 2 + 1]) - interp->polyobj.polyobj->vertices[ii]->y = interp->polyobj.bakvertices[ii * 2 + 1]; - else - interp->polyobj.polyobj->vertices[ii]->y = R_LerpFixed(interp->polyobj.oldvertices[ii * 2 + 1], interp->polyobj.bakvertices[ii * 2 + 1], frac); + interp->polyobj.polyobj->vertices[ii]->x = R_LerpFixed(interp->polyobj.oldvertices[ii * 2 ], interp->polyobj.bakvertices[ii * 2 ], frac); + interp->polyobj.polyobj->vertices[ii]->y = R_LerpFixed(interp->polyobj.oldvertices[ii * 2 + 1], interp->polyobj.bakvertices[ii * 2 + 1], frac); } - if (interp->polyobj.polyobj->centerPt.x == interp->polyobj.oldcx) - interp->polyobj.polyobj->centerPt.x = interp->polyobj.bakcx; - else - interp->polyobj.polyobj->centerPt.x = R_LerpFixed(interp->polyobj.oldcx, interp->polyobj.bakcx, frac); - - if (interp->polyobj.polyobj->centerPt.y == interp->polyobj.oldcy) - interp->polyobj.polyobj->centerPt.y = interp->polyobj.bakcy; - else - interp->polyobj.polyobj->centerPt.y = R_LerpFixed(interp->polyobj.oldcy, interp->polyobj.bakcy, frac); - + interp->polyobj.polyobj->centerPt.x = R_LerpFixed(interp->polyobj.oldcx, interp->polyobj.bakcx, frac); + interp->polyobj.polyobj->centerPt.y = R_LerpFixed(interp->polyobj.oldcy, interp->polyobj.bakcy, frac); break; /*case LVLINTERP_DynSlope: R_LerpVector3(&interp->dynslope.oldo, &interp->dynslope.bako, frac, &interp->dynslope.slope->o); diff --git a/src/r_fps.h b/src/r_fps.h index 14b7b2157..a4aef71cd 100644 --- a/src/r_fps.h +++ b/src/r_fps.h @@ -21,7 +21,6 @@ extern consvar_t cv_fpscap; extern consvar_t cv_precipinterp; -extern consvar_t cv_mobjssector; UINT32 R_GetFramerateCap(void); boolean R_UsingFrameInterpolation(void); @@ -48,6 +47,7 @@ typedef struct { angle_t angle; angle_t aim; + angle_t roll; fixed_t cos; fixed_t sin; mobj_t *mobj; @@ -119,6 +119,8 @@ typedef struct levelinterpolator_s { // Interpolates the current view variables (r_state.h) against the selected view context in R_SetViewContext void R_InterpolateView(fixed_t frac, boolean forceinvalid); +// Special function just for software +void R_InterpolateViewRollAngle(fixed_t frac); // Buffer the current new views into the old views. Call once after each real tic. void R_UpdateViewInterpolation(void); // Reset the view states (e.g. after level load) so R_InterpolateView doesn't interpolate invalid data diff --git a/src/r_main.c b/src/r_main.c index a15258c48..0e0e7020e 100644 --- a/src/r_main.c +++ b/src/r_main.c @@ -16,6 +16,7 @@ #include "doomdef.h" #include "g_game.h" #include "g_input.h" +#include "g_state.h" #include "r_local.h" #include "r_splats.h" // faB(21jan): testing #include "r_sky.h" @@ -57,7 +58,7 @@ size_t framecount; size_t loopcount; fixed_t viewx, viewy, viewz; -angle_t viewangle, aimingangle; +angle_t viewangle, aimingangle, viewroll; UINT8 viewssnum; fixed_t viewcos, viewsin; boolean skyVisible; @@ -144,13 +145,14 @@ static CV_PossibleValue_t drawdist_cons_t[] = { /*{256, "256"},*/ {512, "512"}, {768, "768"}, {1024, "1024"}, {1536, "1536"}, {2048, "2048"}, {3072, "3072"}, {4096, "4096"}, {6144, "6144"}, - {8192, "8192"}, {0, "Infinite"}, {0, NULL}}; + {8192, "8192"}, {12288, "12288"}, {20480, "20480"}, + {24576, "24576"},{0, "Infinite"}, {0, NULL}}; #if defined(__x86_64__) || defined(__amd64__) || defined(__aarch64__) || defined(__arm64__) // only for 64bit (idk how else to proper check lmao) static CV_PossibleValue_t drawdist_precip_cons_t[] = { - {256, "256"}, {512, "512"}, {768, "768"}, - {1024, "1024"}, {1536, "1536"}, {2048, "2048"}, - {3072, "3072"}, {4096, "4096"}, {0, "None"}, {0, NULL}}; + {256, "256"}, {512, "512"}, {768, "768"}, + {1024, "1024"}, {1536, "1536"}, {2048, "2048"}, + {3072, "3072"}, {4096, "4096"}, {0, "None"}, {0, NULL}}; #else static CV_PossibleValue_t drawdist_precip_cons_t[] = { {256, "256"}, {512, "512"}, {768, "768"}, @@ -159,10 +161,10 @@ static CV_PossibleValue_t drawdist_precip_cons_t[] = { #endif static CV_PossibleValue_t maxinterpdist_cons_t[] = { - /*{256, "256"},*/ {512, "512"}, {768, "768"}, + /*{256, "256"},*/ {512, "512"}, {768, "768"}, {1024, "1024"}, {1536, "1536"}, {2048, "2048"}, {3072, "3072"}, {4096, "4096"}, {6144, "6144"}, - {8192, "8192"}, {0, "Infinite"}, {0, NULL}}; + {8192, "8192"}, {0, "Infinite"}, {0, NULL}}; static CV_PossibleValue_t fov_cons_t[] = {{5*FRACUNIT, "MIN"}, {178*FRACUNIT, "MAX"}, {0, NULL}}; @@ -184,6 +186,8 @@ void SendWeaponPref2(void); void SendWeaponPref3(void); void SendWeaponPref4(void); +static void Precipstuff_OnChange(void); + consvar_t cv_tailspickup = {"tailspickup", "On", CV_NETVAR|CV_NOSHOWHELP, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_chasecam = {"chasecam", "On", CV_CALL, CV_OnOff, ChaseCam_OnChange, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_chasecam2 = {"chasecam2", "On", CV_CALL, CV_OnOff, ChaseCam2_OnChange, 0, NULL, NULL, 0, 0, NULL}; @@ -207,8 +211,9 @@ consvar_t cv_uncappedhud = {"uncappedhud", "Yes", CV_SAVE, CV_YesNo, NULL, 0, NU consvar_t cv_translucency = {"translucency", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_drawdist = {"drawdist", "Infinite", CV_SAVE, drawdist_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; -consvar_t cv_drawdist_precip = {"drawdist_precip", "1024", CV_SAVE, drawdist_precip_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; -consvar_t cv_lessprecip = {"lessweathereffects", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_drawdist_precip = {"drawdist_precip", "1024", CV_SAVE|CV_CALL|CV_NOINIT, drawdist_precip_cons_t, Precipstuff_OnChange, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_lessprecip = {"lessweathereffects", "Off", CV_SAVE|CV_CALL|CV_NOINIT, CV_OnOff, Precipstuff_OnChange, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_mobjscaleprecip = {"scaleprecipmobjscale", "Off", CV_SAVE|CV_CALL|CV_NOINIT, CV_OnOff, Precipstuff_OnChange, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_grmaxinterpdist = {"gr_maxinterpdist", "Infinite", CV_SAVE, maxinterpdist_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; @@ -220,9 +225,6 @@ consvar_t cv_homremoval = {"homremoval", "Yes", CV_SAVE, homremoval_cons_t, NULL consvar_t cv_maxportals = {"maxportals", "2", CV_SAVE, maxportals_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; -static CV_PossibleValue_t pointoangle_cons_t[] = {{0, "Ex"}, {1, "64"}, {0, NULL}}; -consvar_t cv_pointoangleexor64 = {"r_pointtoangle", "64", CV_SAVE, pointoangle_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; - void SplitScreen_OnChange(void) { UINT8 i; @@ -331,6 +333,29 @@ static void FlipCam4_OnChange(void) SendWeaponPref4(); } +static void Precipstuff_OnChange(void) +{ + if (gamestate != GS_LEVEL) + return; + + thinker_t *think; + thinker_t *next; + precipmobj_t *precipmobj; + + for (think = thinkercap.next; think != &thinkercap; think = next) + { + next = think->next; + + if (think->function.acp1 != (actionf_p1)P_NullPrecipThinker) + continue; // not a precipmobj thinker + + precipmobj = (precipmobj_t *)think; + P_FreePrecipMobj(precipmobj); + } + + P_SpawnPrecipitation(); +} + // // R_PointOnSide // Traverse BSP (sub) tree, @@ -426,29 +451,6 @@ angle_t R_PointToAngle64(INT64 x, INT64 y) 0; } -angle_t R_PointToAngleEx(INT32 x2, INT32 y2, INT32 x1, INT32 y1) -{ - INT64 dx = x1-x2; - INT64 dy = y1-y2; - if (dx < INT32_MIN || dx > INT32_MAX || dy < INT32_MIN || dy > INT32_MAX) - { - x1 = (int)(dx / 2 + x2); - y1 = (int)(dy / 2 + y2); - } - return (y1 -= y2, (x1 -= x2) || y1) ? - x1 >= 0 ? - y1 >= 0 ? - (x1 > y1) ? tantoangle[SlopeDivEx(y1,x1)] : // octant 0 - ANGLE_90-tantoangle[SlopeDivEx(x1,y1)] : // octant 1 - x1 > (y1 = -y1) ? 0-tantoangle[SlopeDivEx(y1,x1)] : // octant 8 - ANGLE_270+tantoangle[SlopeDivEx(x1,y1)] : // octant 7 - y1 >= 0 ? (x1 = -x1) > y1 ? ANGLE_180-tantoangle[SlopeDivEx(y1,x1)] : // octant 3 - ANGLE_90 + tantoangle[SlopeDivEx(x1,y1)] : // octant 2 - (x1 = -x1) > (y1 = -y1) ? ANGLE_180+tantoangle[SlopeDivEx(y1,x1)] : // octant 4 - ANGLE_270-tantoangle[SlopeDivEx(x1,y1)] : // octant 5 - 0; -} - angle_t R_PointToAngle2(fixed_t pviewx, fixed_t pviewy, fixed_t x, fixed_t y) { return (y -= pviewy, (x -= pviewx) || y) ? @@ -465,11 +467,6 @@ angle_t R_PointToAngle2(fixed_t pviewx, fixed_t pviewy, fixed_t x, fixed_t y) 0; } -fixed_t R_PointToDist2(fixed_t px2, fixed_t py2, fixed_t px1, fixed_t py1) -{ - return FixedHypot(px1 - px2, py1 - py2); -} - angle_t R_PlayerSliptideAngle(player_t *player) { mobj_t *mo; @@ -514,12 +511,6 @@ angle_t R_PlayerSliptideAngle(player_t *player) return FixedMul(FINECOSINE((ang) >> ANGLETOFINESHIFT), mo->player->sliproll*(mo->player->sliptidemem)); } -// Little extra utility. Works in the same way as R_PointToAngle2 -fixed_t R_PointToDist(fixed_t x, fixed_t y) -{ - return R_PointToDist2(viewx, viewy, x, y); -} - INT32 R_GetHudUncap(void) { return cv_uncappedhud.value ? rendertimefrac & FRACMASK : 0; @@ -759,7 +750,7 @@ void R_CheckViewMorph(void) INT32 end, vx, vy, pos, usedpos; INT32 usedx, usedy, halfwidth = vid.width/2, halfheight = vid.height/2; - angle_t rollangle = players[displayplayers[0]].viewrollangle; + angle_t rollangle = viewroll; rollangle >>= ANGLETOFINESHIFT; rollangle = ((rollangle+2) & ~3) & FINEMASK; // Limit the distinct number of angles to reduce recalcs from angles changing a lot. @@ -943,6 +934,45 @@ void R_ApplyViewMorph(void) vid.width*vid.bpp, vid.height, vid.width*vid.bpp, vid.width); } +static inline int intsign(int n) { + return n < 0 ? -1 : n > 0 ? 1 : 0; +} + +angle_t R_ViewRollAngle(const player_t *player) +{ + angle_t roll = 0; + + if (gamestate != GS_LEVEL) + { + // FIXME: The way this is implemented is totally + // incompatible with cameras that aren't directly + // tied to the player. (podium, titlemap, + // MT_ALTVIEWMAN in general) + + // All of these player variables should affect their + // camera_t in P_MoveChaseCamera, and then this + // just returns that variable instead. + return 0; + } + + roll = player->viewrollangle; + + if (cv_tilting.value) + { + if (!player->spectator && !demo.freecam) + roll += player->tilt; + + if (cv_actionmovie.value) + { + int xs = intsign(quake.x), + ys = intsign(quake.y), + zs = intsign(quake.z); + roll += (xs ^ ys ^ zs) * ANG1; + } + } + + return roll; +} // // R_SetViewSize @@ -1119,8 +1149,8 @@ subsector_t *R_IsPointInSubsector(fixed_t x, fixed_t y) subsector_t *ret; // single subsector is a special case - if (numnodes == 0) - return subsectors; + //if (numnodes == 0) + //return subsectors; nodenum = numnodes - 1; @@ -1133,7 +1163,6 @@ subsector_t *R_IsPointInSubsector(fixed_t x, fixed_t y) ret = &subsectors[nodenum & ~NF_SUBSECTOR]; for (i = 0; i < ret->numlines; i++) - //if (R_PointOnSegSide(x, y, &segs[ret->firstline + i])) -- breaks in ogl because polyvertex_t cast over vertex pointers if (P_PointOnLineSide(x, y, segs[ret->firstline + i].linedef) != segs[ret->firstline + i].side) return 0; @@ -1144,7 +1173,7 @@ subsector_t *R_IsPointInSubsector(fixed_t x, fixed_t y) // R_SetupFrame // -static mobj_t *viewmobj; +mobj_t *viewmobj; void R_SkyboxFrame(player_t *player) { @@ -1214,6 +1243,7 @@ void R_SkyboxFrame(player_t *player) } } newview->angle += viewmobj->angle; + newview->roll = R_ViewRollAngle(player); newview->player = player; @@ -1438,12 +1468,12 @@ void R_SetupFrame(player_t *player, boolean skybox) else if (player->playerstate == PST_DEAD || player->exiting) chasecam = true; // force chasecam on - if (chasecam && !thiscam->chase) + if (chasecam && (thiscam && !thiscam->chase)) { P_ResetCamera(player, thiscam); thiscam->chase = true; } - else if (!chasecam) + else if (thiscam && !chasecam) thiscam->chase = false; newview->sky = !skybox; @@ -1456,7 +1486,7 @@ void R_SetupFrame(player_t *player, boolean skybox) newview->aim = player->awayviewaiming; newview->angle = viewmobj->angle; } - else if (!player->spectator && chasecam) + else if (!player->spectator && (thiscam && chasecam)) // use outside cam view { viewmobj = NULL; @@ -1497,11 +1527,12 @@ void R_SetupFrame(player_t *player, boolean skybox) } } } + newview->roll = R_ViewRollAngle(player); newview->z += quake.z; newview->player = player; - if (chasecam && !player->awayviewtics && !player->spectator) + if ((thiscam && chasecam) && !player->awayviewtics && !player->spectator) { newview->x = thiscam->x; newview->y = thiscam->y; @@ -1520,7 +1551,7 @@ void R_SetupFrame(player_t *player, boolean skybox) newview->x += quake.x; newview->y += quake.y; - if (viewmobj->subsector && thiscam->subsector->sector) + if (!P_MobjWasRemoved(viewmobj) && viewmobj->subsector && thiscam && thiscam->subsector->sector) newview->sector = viewmobj->subsector->sector; else newview->sector = R_PointInSubsector(newview->x, newview->y)->sector; @@ -1667,7 +1698,6 @@ void R_RenderPlayerView(player_t *player) } // Draw over the fourth screen so you don't have to stare at a HOM :V else if (splitscreen == 2 && player == &players[displayplayers[2]]) -#if 1 { // V_DrawPatchFill, but for the fourth screen only patch_t *pat = W_CachePatchName("SRB2BACK", PU_CACHE); @@ -1680,18 +1710,15 @@ void R_RenderPlayerView(player_t *player) V_DrawScaledPatch(x, y, V_NOSCALESTART, pat); } } -#else - V_DrawFill(viewwidth, viewheight, viewwidth, viewheight, 31|V_NOSCALESTART); -#endif // load previous saved value of skyVisible for the player for (i = 0; i <= splitscreen; i++) { - if (player == &players[displayplayers[i]]) - { - skyVisible = skyVisiblePerPlayer[i]; - break; - } + if (player != &players[displayplayers[i]]) + continue; + + skyVisible = skyVisiblePerPlayer[i]; + break; } portalrender = 0; @@ -1747,9 +1774,6 @@ void R_RenderPlayerView(player_t *player) R_ClearVisibleFloorSplats(); #endif - // check for new console commands. - NetUpdate(); - // The head node is the last node output. ps_numbspcalls.value.i = ps_numpolyobjects.value.i = ps_numdrawnodes.value.i = 0; @@ -1807,18 +1831,15 @@ void R_RenderPlayerView(player_t *player) R_DrawMasked(); PS_STOP_TIMING(ps_sw_maskedtime); - // Check for new console commands. - NetUpdate(); - // save value to skyVisiblePerPlayer // this is so that P1 can't affect whether P2 can see a skybox or not, or vice versa for (i = 0; i <= splitscreen; i++) { - if (player == &players[displayplayers[i]]) - { - skyVisiblePerPlayer[i] = skyVisible; - break; - } + if (player != &players[displayplayers[i]]) + continue; + + skyVisiblePerPlayer[i] = skyVisible; + break; } } @@ -1842,12 +1863,11 @@ void R_RegisterEngineStuff(void) if (dedicated) return; - //CV_RegisterVar(&cv_precipdensity); CV_RegisterVar(&cv_translucency); CV_RegisterVar(&cv_drawdist); - //CV_RegisterVar(&cv_drawdist_nights); CV_RegisterVar(&cv_drawdist_precip); CV_RegisterVar(&cv_lessprecip); + CV_RegisterVar(&cv_mobjscaleprecip); CV_RegisterVar(&cv_fov); CV_RegisterVar(&cv_chasecam); @@ -1893,6 +1913,8 @@ void R_RegisterEngineStuff(void) CV_RegisterVar(&cv_tiltsmoothing); CV_RegisterVar(&cv_actionmovie); + CV_RegisterVar(&cv_lookbackmom); + CV_RegisterVar(&cv_driftsparkpulse); CV_RegisterVar(&cv_gravstretch); CV_RegisterVar(&cv_sloperoll); @@ -1906,8 +1928,6 @@ void R_RegisterEngineStuff(void) CV_RegisterVar(&cv_uncappedhud); CV_RegisterVar(&cv_maxportals); - - CV_RegisterVar(&cv_pointoangleexor64); CV_RegisterVar(&cv_grmaxinterpdist); @@ -1918,5 +1938,4 @@ void R_RegisterEngineStuff(void) // Frame interpolation/uncapped CV_RegisterVar(&cv_fpscap); CV_RegisterVar(&cv_precipinterp); - CV_RegisterVar(&cv_mobjssector); } diff --git a/src/r_main.h b/src/r_main.h index 56e351138..dbf1a141b 100644 --- a/src/r_main.h +++ b/src/r_main.h @@ -38,6 +38,8 @@ extern fixed_t renderdeltatics; // The current render is a new logical tic extern boolean renderisnewtic; +extern mobj_t *viewmobj; + // // Lighting LUT. // Used for z-depth cuing per column/row, @@ -64,21 +66,25 @@ extern lighttable_t *zlight[LIGHTLEVELS][MAXLIGHTZ]; // There a 0-31, i.e. 32 LUT in the COLORMAP lump. #define NUMCOLORMAPS 32 +#define COLORMAP_SIZE (256*LIGHTLEVELS) +#define COLORMAP_REMAPOFFSET COLORMAP_SIZE + // Utility functions. INT32 R_PointOnSide(fixed_t x, fixed_t y, const node_t *node); INT32 R_PointOnSegSide(fixed_t x, fixed_t y, const seg_t *line); angle_t R_PointToAngle(fixed_t x, fixed_t y); angle_t R_PointToAngle64(INT64 x, INT64 y); -angle_t R_PointToAngleEx(INT32 x2, INT32 y2, INT32 x1, INT32 y1); angle_t R_PointToAngle2(fixed_t px2, fixed_t py2, fixed_t px1, fixed_t py1); -fixed_t R_PointToDist(fixed_t x, fixed_t y); -fixed_t R_PointToDist2(fixed_t px2, fixed_t py2, fixed_t px1, fixed_t py1); angle_t R_PlayerSliptideAngle(player_t *player); fixed_t R_ScaleFromGlobalAngle(angle_t visangle); subsector_t *R_PointInSubsector(fixed_t x, fixed_t y); subsector_t *R_IsPointInSubsector(fixed_t x, fixed_t y); +#define R_PointToDist(x, y) R_PointToDist2(viewx, viewy, x, y) +#define R_PointToDist2(px2, py2, px1, py1) FixedHypot((px1) - (px2), (py1) - (py2)) + + boolean R_DoCulling(line_t *cullheight, line_t *viewcullheight, fixed_t vz, fixed_t bottomh, fixed_t toph); void R_GetRenderBlockMapDimensions(fixed_t drawdist, INT32 *xl, INT32 *xh, INT32 *yl, INT32 *yh); @@ -113,7 +119,7 @@ extern consvar_t cv_flipcam, cv_flipcam2, cv_flipcam3, cv_flipcam4; extern consvar_t cv_shadow, cv_shadowoffs; extern consvar_t cv_ffloorclip, cv_spriteclip; extern consvar_t cv_translucency; -extern consvar_t cv_drawdist, cv_drawdist_precip, cv_lessprecip; +extern consvar_t cv_drawdist, cv_drawdist_precip, cv_lessprecip, cv_mobjscaleprecip; extern consvar_t cv_fov; extern consvar_t cv_skybox; extern consvar_t cv_tailspickup; @@ -124,6 +130,7 @@ void R_Init(void); void R_CheckViewMorph(void); void R_ApplyViewMorph(void); +angle_t R_ViewRollAngle(const player_t *player); // just sets setsizeneeded true extern boolean setsizeneeded; diff --git a/src/r_patch.c b/src/r_patch.c index 597a1a0de..eea97cfbb 100644 --- a/src/r_patch.c +++ b/src/r_patch.c @@ -48,8 +48,8 @@ boolean R_CheckIfPatch(lumpnum_t lump) patch = (patch_t *)W_CacheLumpNum(lump, PU_STATIC); - width = patch->width; - height = patch->height; + width = SHORT(patch->width); + height = SHORT(patch->height); result = (height > 0 && height <= 16384 && width > 0 && width <= 16384 && width < (INT16)(size / 4)); @@ -772,6 +772,17 @@ static UINT16 GetPatchPixel(patch_t *patch, INT32 x, INT32 y, boolean flip) return 0xFF00; } +#ifdef HWRENDER +static patch_t *R_CreateHardwarePatch(patch_t *patch) +{ + GLPatch_t *grPatch = Z_Calloc(sizeof(GLPatch_t), PU_HWRPATCHINFO, NULL); + grPatch->mipmap = Z_Calloc(sizeof(GLMipmap_t), PU_HWRPATCHINFO, NULL); + grPatch->rawpatch = patch; + HWR_MakePatch(patch, grPatch, grPatch->mipmap, false); + return (patch_t *)grPatch; +} +#endif + #ifdef ROTSPRITE // // R_GetRollAngle @@ -792,11 +803,7 @@ INT32 R_GetRollAngle(angle_t rollangle) return ra; } -patch_t *Patch_GetRotatedSprite( - spriteframe_t *sprite, - size_t frame, size_t spriteangle, - boolean flip, boolean adjustfeet, - void *info, INT32 rotationangle) +patch_t *Patch_GetRotatedSprite(spriteframe_t *sprite, size_t frame, size_t spriteangle, boolean flip, boolean adjustfeet, void *info, INT32 rotationangle) { rotsprite_t *rotsprite; spriteinfo_t *sprinfo = (spriteinfo_t *)info; @@ -882,17 +889,6 @@ static void RotatedPatch_CalculateDimensions( *newheight = max(height, max(h1, h2)); } -#ifdef HWRENDER -static patch_t *R_CreateHardwarePatch(patch_t *patch) -{ - GLPatch_t *grPatch = Z_Calloc(sizeof(GLPatch_t), PU_HWRPATCHINFO, NULL); - grPatch->mipmap = Z_Calloc(sizeof(GLMipmap_t), PU_HWRPATCHINFO, NULL); - grPatch->rawpatch = patch; - HWR_MakePatch(patch, grPatch, grPatch->mipmap, false); - return (patch_t *)grPatch; -} -#endif - void RotatedPatch_DoRotation(rotsprite_t *rotsprite, patch_t *patch, INT32 angle, INT32 xpivot, INT32 ypivot, boolean flip) { UINT32 i; diff --git a/src/r_plane.c b/src/r_plane.c index f89e10330..ec5aa90eb 100644 --- a/src/r_plane.c +++ b/src/r_plane.c @@ -295,7 +295,7 @@ void R_MapPlane(INT32 y, INT32 x1, INT32 x2) ds_colormap = planezlight[pindex]; } if (encoremap && !currentplane->noencore) - ds_colormap += (256*32); + ds_colormap += COLORMAP_REMAPOFFSET; if (currentplane->extra_colormap) ds_colormap = currentplane->extra_colormap->colormap + (ds_colormap - colormaps); @@ -332,10 +332,12 @@ void R_ClearPlanes(void) numffloors = 0; for (i = 0; i < MAXVISPLANES; i++) - for (*freehead = visplanes[i], visplanes[i] = NULL; - freehead && *freehead ;) { - freehead = &(*freehead)->next; + for (*freehead = visplanes[i], visplanes[i] = NULL; + freehead && *freehead ;) + { + freehead = &(*freehead)->next; + } } lastopening = openings; @@ -417,6 +419,11 @@ visplane_t *R_FindPlane(fixed_t height, INT32 picnum, INT32 lightlevel, } } + if (slope != NULL) + { + lightlevel += slope->lightOffset * 8; + } + // This appears to fix the Nimbus Ruins sky bug. if (picnum == skyflatnum && pfloor) { @@ -526,8 +533,7 @@ visplane_t *R_CheckPlane(visplane_t *pl, INT32 start, INT32 stop) } else { - unsigned hash = - visplane_hash(pl->picnum, pl->lightlevel, pl->height); + unsigned hash = visplane_hash(pl->picnum, pl->lightlevel, pl->height); new_pl = new_visplane(hash); } @@ -674,25 +680,26 @@ static void R_DrawSkyPlane(visplane_t *pl) // Because of this hack, sky is not affected // by INVUL inverse mapping. dc_colormap = colormaps; + if (encoremap) - dc_colormap += (256*32); + dc_colormap += COLORMAP_REMAPOFFSET; + dc_texturemid = skytexturemid; - dc_texheight = textureheight[skytexture] - >>FRACBITS; + dc_texheight = textureheight[skytexture] >>FRACBITS; + for (x = pl->minx; x <= pl->maxx; x++) { dc_yl = pl->top[x]; dc_yh = pl->bottom[x]; - if (dc_yl <= dc_yh) - { - angle = (pl->viewangle + xtoviewangle[x])>>ANGLETOSKYSHIFT; - dc_iscale = FixedMul(skyscale, FINECOSINE(xtoviewangle[x]>>ANGLETOFINESHIFT)); - dc_x = x; - dc_source = - R_GetColumn(texturetranslation[skytexture], - angle); - wallcolfunc(); - } + + if (!(dc_yl <= dc_yh)) + continue; + + angle = (pl->viewangle + xtoviewangle[x])>>ANGLETOSKYSHIFT; + dc_iscale = FixedMul(skyscale, FINECOSINE(xtoviewangle[x]>>ANGLETOFINESHIFT)); + dc_x = x; + dc_source = R_GetColumn(texturetranslation[skytexture], angle); + wallcolfunc(); } } @@ -813,7 +820,8 @@ void R_DrawSinglePlane(visplane_t *pl) #endif spanfunc = basespanfunc; - if (pl->polyobj && pl->polyobj->translucency != 0) { + if (pl->polyobj && pl->polyobj->translucency != 0) + { spanfunc = R_DrawTranslucentSpan_8; // Hacked up support for alpha value in software mode Tails 09-24-2002 (sidenote: ported to polys 10-15-2014, there was no time travel involved -Red) @@ -833,112 +841,111 @@ void R_DrawSinglePlane(visplane_t *pl) else light = LIGHTLEVELS-1; - } else - if (pl->ffloor) + } + else { - // Don't draw planes that shouldn't be drawn. - for (rover = pl->ffloor->target->ffloors; rover; rover = rover->next) + if (pl->ffloor) { - if ((pl->ffloor->flags & FF_CUTEXTRA) && (rover->flags & FF_EXTRA)) + // Don't draw planes that shouldn't be drawn. + for (rover = pl->ffloor->target->ffloors; rover; rover = rover->next) { - if (pl->ffloor->flags & FF_EXTRA) - { - // The plane is from an extra 3D floor... Check the flags so - // there are no undesired cuts. - if (((pl->ffloor->flags & (FF_FOG|FF_SWIMMABLE)) == (rover->flags & (FF_FOG|FF_SWIMMABLE))) - && pl->height < *rover->topheight - && pl->height > *rover->bottomheight) - return; - } + if (!((pl->ffloor->flags & FF_CUTEXTRA) && (rover->flags & FF_EXTRA))) + continue; + + // The plane is from an extra 3D floor... Check the flags so + // there are no undesired cuts. + if (((pl->ffloor->flags & (FF_FOG|FF_SWIMMABLE)) == (rover->flags & (FF_FOG|FF_SWIMMABLE))) + && pl->height < *rover->topheight + && pl->height > *rover->bottomheight) + return; } - } - if (pl->ffloor->flags & FF_TRANSLUCENT) - { - spanfunc = R_DrawTranslucentSpan_8; + if (pl->ffloor->flags & FF_TRANSLUCENT) + { + spanfunc = R_DrawTranslucentSpan_8; - // Hacked up support for alpha value in software mode Tails 09-24-2002 - if (pl->ffloor->alpha < 12) - return; // Don't even draw it - else if (pl->ffloor->alpha < 38) - ds_transmap = transtables + ((tr_trans90-1)<ffloor->alpha < 64) - ds_transmap = transtables + ((tr_trans80-1)<ffloor->alpha < 89) - ds_transmap = transtables + ((tr_trans70-1)<ffloor->alpha < 115) - ds_transmap = transtables + ((tr_trans60-1)<ffloor->alpha < 140) - ds_transmap = transtables + ((tr_trans50-1)<ffloor->alpha < 166) - ds_transmap = transtables + ((tr_trans40-1)<ffloor->alpha < 192) - ds_transmap = transtables + ((tr_trans30-1)<ffloor->alpha < 217) - ds_transmap = transtables + ((tr_trans20-1)<ffloor->alpha < 243) - ds_transmap = transtables + ((tr_trans10-1)<ffloor->alpha < 12) + return; // Don't even draw it + else if (pl->ffloor->alpha < 38) + ds_transmap = transtables + ((tr_trans90-1)<ffloor->alpha < 64) + ds_transmap = transtables + ((tr_trans80-1)<ffloor->alpha < 89) + ds_transmap = transtables + ((tr_trans70-1)<ffloor->alpha < 115) + ds_transmap = transtables + ((tr_trans60-1)<ffloor->alpha < 140) + ds_transmap = transtables + ((tr_trans50-1)<ffloor->alpha < 166) + ds_transmap = transtables + ((tr_trans40-1)<ffloor->alpha < 192) + ds_transmap = transtables + ((tr_trans30-1)<ffloor->alpha < 217) + ds_transmap = transtables + ((tr_trans20-1)<ffloor->alpha < 243) + ds_transmap = transtables + ((tr_trans10-1)<extra_colormap && pl->extra_colormap->fog)) + if (spanfunc == splatfunc || (pl->extra_colormap && pl->extra_colormap->fog)) #else - if (!pl->extra_colormap || !(pl->extra_colormap->fog & 2)) + if (!pl->extra_colormap || !(pl->extra_colormap->fog & 2)) #endif + light = (pl->lightlevel >> LIGHTSEGSHIFT); + else + light = LIGHTLEVELS-1; + } + else if (pl->ffloor->flags & FF_FOG) + { + spanfunc = R_DrawFogSpan_8; light = (pl->lightlevel >> LIGHTSEGSHIFT); - else - light = LIGHTLEVELS-1; - } - else if (pl->ffloor->flags & FF_FOG) - { - spanfunc = R_DrawFogSpan_8; - light = (pl->lightlevel >> LIGHTSEGSHIFT); - } - else light = (pl->lightlevel >> LIGHTSEGSHIFT); + } + else light = (pl->lightlevel >> LIGHTSEGSHIFT); #ifndef NOWATER - if (pl->ffloor->flags & FF_RIPPLE) - { - INT32 top, bottom; - UINT8 *scr; - - planeripple.active = true; - - if (spanfunc == R_DrawTranslucentSpan_8) + if (pl->ffloor->flags & FF_RIPPLE) { - spanfunc = R_DrawTranslucentWaterSpan_8; + INT32 top, bottom; + UINT8 *scr; - // Copy the current scene, ugh - top = pl->high-8; - bottom = pl->low+8; + planeripple.active = true; - if (top < 0) - top = 0; - if (bottom > vid.height) - bottom = vid.height; + if (spanfunc == R_DrawTranslucentSpan_8) + { + spanfunc = R_DrawTranslucentWaterSpan_8; - if (splitscreen > 2 && viewplayer == &players[displayplayers[3]]) // Only copy the part of the screen we need - scr = (screens[0] + (top+(viewheight))*vid.width + viewwidth); - else if ((splitscreen == 1 && viewplayer == &players[displayplayers[1]]) - || (splitscreen > 1 && viewplayer == &players[displayplayers[2]])) - scr = (screens[0] + (top+(viewheight))*vid.width); - else if (splitscreen > 1 && viewplayer == &players[displayplayers[1]]) - scr = (screens[0] + ((top)*vid.width) + viewwidth); - else - scr = (screens[0] + ((top)*vid.width)); + // Copy the current scene, ugh + top = pl->high-8; + bottom = pl->low+8; - VID_BlitLinearScreen(scr, screens[1]+((top)*vid.width), - vid.width, bottom-top, - vid.width, vid.width); + if (top < 0) + top = 0; + if (bottom > vid.height) + bottom = vid.height; + + if (splitscreen > 2 && viewplayer == &players[displayplayers[3]]) // Only copy the part of the screen we need + scr = (screens[0] + (top+(viewheight))*vid.width + viewwidth); + else if ((splitscreen == 1 && viewplayer == &players[displayplayers[1]]) + || (splitscreen > 1 && viewplayer == &players[displayplayers[2]])) + scr = (screens[0] + (top+(viewheight))*vid.width); + else if (splitscreen > 1 && viewplayer == &players[displayplayers[1]]) + scr = (screens[0] + ((top)*vid.width) + viewwidth); + else + scr = (screens[0] + ((top)*vid.width)); + + VID_BlitLinearScreen(scr, screens[1]+((top)*vid.width), + vid.width, bottom-top, + vid.width, vid.width); + } } - } #endif + } + else light = (pl->lightlevel >> LIGHTSEGSHIFT); } - else light = (pl->lightlevel >> LIGHTSEGSHIFT); - if (!pl->slope) // Don't mess with angle on slopes! We'll handle this ourselves later - if (viewangle != pl->viewangle+pl->plangle) + if (!pl->slope && viewangle != pl->viewangle+pl->plangle) // Don't mess with angle on slopes! We'll handle this ourselves later { memset(cachedheight, 0, sizeof (cachedheight)); angle = (pl->viewangle+pl->plangle-ANGLE_90)>>ANGLETOFINESHIFT; @@ -1101,9 +1108,9 @@ void R_DrawSinglePlane(visplane_t *pl) spanfunc = R_DrawTiltedSpan_8; planezlight = scalelight[light]; - } else - - planezlight = zlight[light]; + } + else + planezlight = zlight[light]; // set the maximum value for unsigned pl->top[pl->maxx+1] = 0xffff; @@ -1212,9 +1219,9 @@ void R_PlaneBounds(visplane_t *plane) for (i = plane->minx + 1; i <= plane->maxx; i++) { if (plane->top[i] < hi) - hi = plane->top[i]; + hi = plane->top[i]; if (plane->bottom[i] > low) - low = plane->bottom[i]; + low = plane->bottom[i]; } plane->high = hi; plane->low = low; diff --git a/src/r_segs.c b/src/r_segs.c index 8325e0fa0..07d217608 100644 --- a/src/r_segs.c +++ b/src/r_segs.c @@ -208,7 +208,7 @@ static void R_DrawWallSplats(void) pindex = MAXLIGHTSCALE - 1; dc_colormap = walllights[pindex]; if (encoremap && !(seg->linedef->flags & ML_TFERLINE)) - dc_colormap += (256*32); + dc_colormap += COLORMAP_REMAPOFFSET; if (frontsector->extra_colormap) dc_colormap = frontsector->extra_colormap->colormap + (dc_colormap - colormaps); @@ -406,10 +406,8 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2) if (rlight->extra_colormap && rlight->extra_colormap->fog) ; - else if (curline->v1->y == curline->v2->y) - lightnum--; - else if (curline->v1->x == curline->v2->x) - lightnum++; + else + lightnum += curline->lightOffset; rlight->lightnum = lightnum; } @@ -429,10 +427,8 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2) if (colfunc == R_DrawFogColumn_8 || (frontsector->extra_colormap && frontsector->extra_colormap->fog)) ; - else if (curline->v1->y == curline->v2->y) - lightnum--; - else if (curline->v1->x == curline->v2->x) - lightnum++; + else + lightnum += curline->lightOffset; if (lightnum < 0) walllights = scalelight[0]; @@ -496,7 +492,6 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2) } } - dc_texheight = textureheight[texnum]>>FRACBITS; // draw the columns @@ -573,7 +568,7 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2) { dc_colormap = rlight->rcolormap; if (encoremap && !(ldef->flags & ML_TFERLINE)) - dc_colormap += (256*32); + dc_colormap += COLORMAP_REMAPOFFSET; continue; } @@ -594,7 +589,7 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2) windowtop = windowbottom + 1; dc_colormap = rlight->rcolormap; if (encoremap && !(ldef->flags & ML_TFERLINE)) - dc_colormap += (256*32); + dc_colormap += COLORMAP_REMAPOFFSET; } windowbottom = realbot; if (windowtop < windowbottom) @@ -612,7 +607,7 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2) dc_colormap = walllights[pindex]; if (encoremap && !(ldef->flags & ML_TFERLINE)) - dc_colormap += (256*32); + dc_colormap += COLORMAP_REMAPOFFSET; if (frontsector->extra_colormap) dc_colormap = frontsector->extra_colormap->colormap + (dc_colormap - colormaps); @@ -634,12 +629,15 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2) // Loop through R_DrawMaskedColumn calls static void R_DrawRepeatMaskedColumn(column_t *col) { - while (sprtopscreen < sprbotscreen) { + INT64 z; + while (sprtopscreen < sprbotscreen) + { R_DrawMaskedColumn(col); - if (sprtopscreen + (INT64)dc_texheight*spryscale > (INT64)INT32_MAX) // prevent overflow + z = sprtopscreen + (INT64)dc_texheight*spryscale; + if (z > (INT64)INT32_MAX) // prevent overflow sprtopscreen = INT32_MAX; else - sprtopscreen += dc_texheight*spryscale; + sprtopscreen = z; } } @@ -834,10 +832,8 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor) if (pfloor->flags & FF_FOG || rlight->flags & FF_FOG || (rlight->extra_colormap && rlight->extra_colormap->fog)) ; - else if (curline->v1->y == curline->v2->y) - rlight->lightnum--; - else if (curline->v1->x == curline->v2->x) - rlight->lightnum++; + else + rlight->lightnum += curline->lightOffset; p++; } @@ -857,11 +853,10 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor) lightnum = R_FakeFlat(frontsector, &tempsec, &templight, &templight, false) ->lightlevel >> LIGHTSEGSHIFT; - if (pfloor->flags & FF_FOG || (frontsector->extra_colormap && frontsector->extra_colormap->fog)); - else if (curline->v1->y == curline->v2->y) - lightnum--; - else if (curline->v1->x == curline->v2->x) - lightnum++; + if (pfloor->flags & FF_FOG || (frontsector->extra_colormap && frontsector->extra_colormap->fog)) + ; + else + lightnum += curline->lightOffset; if (lightnum < 0) walllights = scalelight[0]; @@ -899,7 +894,7 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor) if (slopeskew) dc_texturemid = left_top; else - dc_texturemid = *pfloor->topheight - viewz; + dc_texturemid = *pfloor->topheight - viewz; if (newline) { @@ -980,7 +975,9 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor) // draw the columns for (dc_x = x1; dc_x <= x2; dc_x++) { - if (maskedtexturecol[dc_x] != INT16_MAX) + if (maskedtexturecol[dc_x] == INT16_MAX) + continue; + { if (ffloortextureslide) { // skew FOF walls if (oldx != -1) @@ -1104,7 +1101,7 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor) { dc_colormap = rlight->rcolormap; if (encoremap && !(curline->linedef->flags & ML_TFERLINE)) - dc_colormap += (256*32); + dc_colormap += COLORMAP_REMAPOFFSET; } if (solid && windowtop < bheight) windowtop = bheight; @@ -1136,7 +1133,7 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor) { dc_colormap = rlight->rcolormap; if (encoremap && !(curline->linedef->flags & ML_TFERLINE)) - dc_colormap += (256*32); + dc_colormap += COLORMAP_REMAPOFFSET; } } windowbottom = sprbotscreen; @@ -1157,7 +1154,7 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor) dc_colormap = walllights[pindex]; if (encoremap && !(curline->linedef->flags & ML_TFERLINE)) - dc_colormap += (256*32); + dc_colormap += COLORMAP_REMAPOFFSET; if (pfloor->flags & FF_FOG && pfloor->master->frontsector->extra_colormap) dc_colormap = pfloor->master->frontsector->extra_colormap->colormap + (dc_colormap - colormaps); @@ -1370,7 +1367,8 @@ static void R_RenderSegLoop (void) //SoM: Calculate offsets for Thick fake floors. // calculate texture offset angle = (rw_centerangle + xtoviewangle[rw_x])>>ANGLETOFINESHIFT; - texturecolumn = rw_offset-FixedMul(FINETANGENT(angle),rw_distance); + // Mask 4095 to guarantee this index is within bounds + texturecolumn = rw_offset-FixedMul(FINETANGENT(angle & 4095),rw_distance); if (oldtexturecolumn != -1) { rw_bottomtexturemid += FixedMul(rw_bottomtextureslide, oldtexturecolumn-texturecolumn); @@ -1393,7 +1391,7 @@ static void R_RenderSegLoop (void) dc_colormap = walllights[pindex]; if (encoremap && !(curline->linedef->flags & ML_TFERLINE)) - dc_colormap += (256*32); + dc_colormap += COLORMAP_REMAPOFFSET; dc_x = rw_x; dc_iscale = 0xffffffffu / (unsigned)rw_scale; @@ -1411,10 +1409,8 @@ static void R_RenderSegLoop (void) if (dc_lightlist[i].extra_colormap) ; - else if (curline->v1->y == curline->v2->y) - lightnum--; - else if (curline->v1->x == curline->v2->x) - lightnum++; + else + lightnum += curline->lightOffset; if (lightnum < 0) xwalllights = scalelight[0]; @@ -1549,8 +1545,7 @@ static void R_RenderSegLoop (void) if (maskedtexture || numthicksides) { - // save texturecol - // for backdrawing of masked mid texture + // save texturecol for backdrawing of masked mid texture maskedtexturecol[rw_x] = (INT16)texturecolumn; if (maskedtextureheight != NULL) { @@ -1691,7 +1686,7 @@ void R_StoreWallRange(INT32 start, INT32 stop) lastopening = openings + pos; if (oldopenings == NULL) - return; + return; // borrowed fix from *cough* zdoom *cough* // [RH] We also need to adjust the openings pointers that @@ -1871,14 +1866,14 @@ void R_StoreWallRange(INT32 start, INT32 stop) texheight = textureheight[midtexture]; // a single sided line is terminal, so it must mark ends markfloor = markceiling = true; - if (linedef->flags & ML_EFFECT2) { + if (linedef->flags & ML_EFFECT2) + { if (linedef->flags & ML_DONTPEGBOTTOM) rw_midtexturemid = frontsector->floorheight + texheight - viewz; else rw_midtexturemid = frontsector->ceilingheight - viewz; } - else - if (linedef->flags & ML_DONTPEGBOTTOM) + else if (linedef->flags & ML_DONTPEGBOTTOM) { rw_midtexturemid = worldbottom + texheight; rw_midtextureslide = floorfrontslide; @@ -1966,37 +1961,21 @@ void R_StoreWallRange(INT32 start, INT32 stop) if (viewsector != frontsector && viewsector != backsector) { - if (worldhigh <= worldbottom && worldhighslope <= worldbottomslope) + //SoM: 3/25/2000: This code fixes an automap bug that didn't check + // frontsector->ceiling and backsector->floor to see if a door was closed. + // Without the following code, sprites get displayed behind closed doors. + if (doorclosed || (worldhigh <= worldbottom && worldhighslope <= worldbottomslope)) { ds_p->sprbottomclip = negonearray; ds_p->bsilheight = INT32_MAX; ds_p->silhouette |= SIL_BOTTOM; } - - if (worldlow >= worldtop && worldlowslope >= worldtopslope) - { + if (doorclosed || (worldlow >= worldtop && worldlowslope >= worldtopslope)) + { // killough 1/17/98, 2/8/98 ds_p->sprtopclip = screenheightarray; ds_p->tsilheight = INT32_MIN; ds_p->silhouette |= SIL_TOP; } - - //SoM: 3/25/2000: This code fixes an automap bug that didn't check - // frontsector->ceiling and backsector->floor to see if a door was closed. - // Without the following code, sprites get displayed behind closed doors. - { - if (doorclosed || (worldhigh <= worldbottom && worldhighslope <= worldbottomslope)) - { - ds_p->sprbottomclip = negonearray; - ds_p->bsilheight = INT32_MAX; - ds_p->silhouette |= SIL_BOTTOM; - } - if (doorclosed || (worldlow >= worldtop && worldlowslope >= worldtopslope)) - { // killough 1/17/98, 2/8/98 - ds_p->sprtopclip = screenheightarray; - ds_p->tsilheight = INT32_MIN; - ds_p->silhouette |= SIL_TOP; - } - } } if (worldlow != worldbottom @@ -2096,9 +2075,7 @@ void R_StoreWallRange(INT32 start, INT32 stop) } } // check BOTTOM TEXTURE - if (worldlow > worldbottom - || worldlowslope > worldbottomslope - ) //seulement si VISIBLE!!! + if (worldlow > worldbottom || worldlowslope > worldbottomslope) // Only if VISIBLE!!! { // bottom texture bottomtexture = R_GetTextureNum(sidedef->bottomtexture); @@ -2353,31 +2330,40 @@ void R_StoreWallRange(INT32 start, INT32 stop) maskedtextureheight = ds_p->maskedtextureheight; // note to red, this == &(ds_p->maskedtextureheight[0]) - if (curline->polyseg) { // use REAL front and back floors please, so midtexture rendering isn't mucked up + if (curline->polyseg) // use REAL front and back floors please, so midtexture rendering isn't mucked up + { rw_midtextureslide = rw_midtexturebackslide = 0; if (!!(linedef->flags & ML_DONTPEGBOTTOM) ^ !!(linedef->flags & ML_EFFECT3)) rw_midtexturemid = rw_midtextureback = max(curline->frontsector->floorheight, curline->backsector->floorheight) - viewz; else rw_midtexturemid = rw_midtextureback = min(curline->frontsector->ceilingheight, curline->backsector->ceilingheight) - viewz; - } else - // Set midtexture starting height - if (linedef->flags & ML_EFFECT2) { // Ignore slopes when texturing - rw_midtextureslide = rw_midtexturebackslide = 0; - if (!!(linedef->flags & ML_DONTPEGBOTTOM) ^ !!(linedef->flags & ML_EFFECT3)) - rw_midtexturemid = rw_midtextureback = max(frontsector->floorheight, backsector->floorheight) - viewz; - else - rw_midtexturemid = rw_midtextureback = min(frontsector->ceilingheight, backsector->ceilingheight) - viewz; + } + else + { + // Set midtexture starting height + if (linedef->flags & ML_EFFECT2) // Ignore slopes when texturing + { + rw_midtextureslide = rw_midtexturebackslide = 0; + if (!!(linedef->flags & ML_DONTPEGBOTTOM) ^ !!(linedef->flags & ML_EFFECT3)) + rw_midtexturemid = rw_midtextureback = max(frontsector->floorheight, backsector->floorheight) - viewz; + else + rw_midtexturemid = rw_midtextureback = min(frontsector->ceilingheight, backsector->ceilingheight) - viewz; - } else if (!!(linedef->flags & ML_DONTPEGBOTTOM) ^ !!(linedef->flags & ML_EFFECT3)) { - rw_midtexturemid = worldbottom; - rw_midtextureslide = floorfrontslide; - rw_midtextureback = worldlow; - rw_midtexturebackslide = floorbackslide; - } else { - rw_midtexturemid = worldtop; - rw_midtextureslide = ceilingfrontslide; - rw_midtextureback = worldhigh; - rw_midtexturebackslide = ceilingbackslide; + } + else if (!!(linedef->flags & ML_DONTPEGBOTTOM) ^ !!(linedef->flags & ML_EFFECT3)) + { + rw_midtexturemid = worldbottom; + rw_midtextureslide = floorfrontslide; + rw_midtextureback = worldlow; + rw_midtexturebackslide = floorbackslide; + } + else + { + rw_midtexturemid = worldtop; + rw_midtextureslide = ceilingfrontslide; + rw_midtextureback = worldhigh; + rw_midtexturebackslide = ceilingbackslide; + } } rw_midtexturemid += sidedef->rowoffset; rw_midtextureback += sidedef->rowoffset; @@ -2426,10 +2412,7 @@ void R_StoreWallRange(INT32 start, INT32 stop) // OPTIMIZE: get rid of LIGHTSEGSHIFT globally lightnum = (frontsector->lightlevel >> LIGHTSEGSHIFT); - if (curline->v1->y == curline->v2->y) - lightnum--; - else if (curline->v1->x == curline->v2->x) - lightnum++; + lightnum += curline->lightOffset; if (lightnum < 0) walllights = scalelight[0]; @@ -2468,22 +2451,27 @@ void R_StoreWallRange(INT32 start, INT32 stop) worldtopslope >>= 4; worldbottomslope >>= 4; - if (linedef->special == 41) { // HORIZON LINES + if (linedef->special == 41) // HORIZON LINES + { topstep = bottomstep = 0; topfrac = bottomfrac = (centeryfrac>>4); topfrac++; // Prevent 1px HOM - } else { + } + else + { topstep = -FixedMul (rw_scalestep, worldtop); topfrac = (centeryfrac>>4) - FixedMul (worldtop, rw_scale); bottomstep = -FixedMul (rw_scalestep,worldbottom); bottomfrac = (centeryfrac>>4) - FixedMul (worldbottom, rw_scale); - if (frontsector->c_slope) { + if (frontsector->c_slope) + { fixed_t topfracend = (centeryfrac>>4) - FixedMul (worldtopslope, ds_p->scale2); topstep = (topfracend-topfrac)/(range); } - if (frontsector->f_slope) { + if (frontsector->f_slope) + { fixed_t bottomfracend = (centeryfrac>>4) - FixedMul (worldbottomslope, ds_p->scale2); bottomstep = (bottomfracend-bottomfrac)/(range); } @@ -2596,23 +2584,26 @@ void R_StoreWallRange(INT32 start, INT32 stop) if (toptexture) { - pixhigh = (centeryfrac>>4) - FixedMul (worldhigh, rw_scale); - pixhighstep = -FixedMul (rw_scalestep,worldhigh); + fixed_t topfracend = (centeryfrac>>4) - FixedMul (worldhighslope, ds_p->scale2); - if (backsector->c_slope) { - fixed_t topfracend = (centeryfrac>>4) - FixedMul (worldhighslope, ds_p->scale2); - pixhighstep = (topfracend-pixhigh)/(range); - } + pixhigh = (centeryfrac>>4) - FixedMul (worldhigh, rw_scale); + pixhighstep = (topfracend-pixhigh)/(range); + + // If the lowest part of a ceiling stretching down covers the entire screen + if (min(pixhigh, topfracend)>>HEIGHTBITS >= viewheight-1) + g_walloffscreen = true; } if (bottomtexture) { + fixed_t bottomfracend = (centeryfrac>>4) - FixedMul (worldlowslope, ds_p->scale2); + pixlow = (centeryfrac>>4) - FixedMul (worldlow, rw_scale); - pixlowstep = -FixedMul (rw_scalestep,worldlow); - if (backsector->f_slope) { - fixed_t bottomfracend = (centeryfrac>>4) - FixedMul (worldlowslope, ds_p->scale2); - pixlowstep = (bottomfracend-pixlow)/(range); - } + pixlowstep = (bottomfracend-pixlow)/(range); + + // If the highest part of a floor stretching up covers the entire screen + if ((max(pixlow, bottomfracend)+HEIGHTUNIT-1)>>HEIGHTBITS <= 0) + g_walloffscreen = true; } { @@ -2687,7 +2678,6 @@ void R_StoreWallRange(INT32 start, INT32 stop) if (rover->norender == leveltime) continue; - // Let the renderer know this sector is sloped. if (*rover->b_slope || *rover->t_slope) frontsector->hasslope = true; @@ -2846,7 +2836,8 @@ void R_StoreWallRange(INT32 start, INT32 stop) } else #endif - R_RenderSegLoop(); + + R_RenderSegLoop(); colfunc = wallcolfunc; if (portalline) // if curline is a portal, set portalrender for drawseg diff --git a/src/r_state.h b/src/r_state.h index 670f800d1..5234d1d62 100644 --- a/src/r_state.h +++ b/src/r_state.h @@ -88,7 +88,7 @@ extern side_t *sides; // POV data. // extern fixed_t viewx, viewy, viewz; -extern angle_t viewangle, aimingangle; +extern angle_t viewangle, aimingangle, viewroll; extern UINT8 viewssnum; // splitscreen view number extern boolean viewsky, skyVisible; extern boolean skyVisiblePerPlayer[MAXSPLITSCREENPLAYERS]; // saved values of skyVisible of each splitscreen player diff --git a/src/r_things.c b/src/r_things.c index dfe05dbdf..85fe49f63 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -20,6 +20,7 @@ #include "z_zone.h" #include "m_misc.h" #include "i_video.h" // rendermode +#include "r_main.h" // stplyr #include "r_fps.h" #include "r_things.h" #include "r_patch.h" @@ -38,12 +39,6 @@ #include "qs22j.h" -#ifdef PC_DOS -#include // for snprintf -int snprintf(char *str, size_t n, const char *fmt, ...); -//int vsnprintf(char *str, size_t n, const char *fmt, va_list ap); -#endif - CV_PossibleValue_t Forceskin_cons_t[MAXSKINS+2]; static void R_InitSkins(void); @@ -152,7 +147,6 @@ static void R_InstallSpriteLump(UINT16 wad, // graphics patch } #endif/*ROTSPRITE*/ - if (rotation == 0) { // the lump should be used for all rotations @@ -276,58 +270,50 @@ static boolean R_AddSingleSpriteDef(const char *sprname, spritedef_t *spritedef, for (l = startlump; l < endlump; l++) { - if (memcmp(lumpinfo[l].name,sprname,4)==0) + if (memcmp(lumpinfo[l].name,sprname,4)) + continue; + + frame = R_Char2Frame(lumpinfo[l].name[4]); + rotation = (UINT8)(lumpinfo[l].name[5] - '0'); + + if (frame >= 64 || !(R_ValidSpriteAngle(rotation))) // Give an actual NAME error -_-... { - frame = R_Char2Frame(lumpinfo[l].name[4]); - rotation = (UINT8)(lumpinfo[l].name[5] - '0'); - - if (frame >= 64 || !(R_ValidSpriteAngle(rotation))) // Give an actual NAME error -_-... - { - CONS_Alert(CONS_WARNING, M_GetText("Bad sprite name: %s\n"), W_CheckNameForNumPwad(wadnum,l)); - continue; - } - - // skip NULL sprites from very old dmadds pwads - if (W_LumpLengthPwad(wadnum,l)<=8) - continue; - - // store sprite info in lookup tables - //FIXME : numspritelumps do not duplicate sprite replacements - W_ReadLumpHeaderPwad(wadnum, l, &patch, sizeof (patch_t), 0); - spritecachedinfo[numspritelumps].width = SHORT(patch.width)<0 && SHORT(patch.topoffset)= max_spritelumps) - { - max_spritelumps *= 2; - Z_Realloc(spritecachedinfo, max_spritelumps*sizeof(*spritecachedinfo), PU_STATIC, &spritecachedinfo); - } - - ++numadded; + CONS_Alert(CONS_WARNING, M_GetText("Bad sprite name: %s\n"), W_CheckNameForNumPwad(wadnum,l)); + continue; } + + // skip NULL sprites from very old dmadds pwads + if (W_LumpLengthPwad(wadnum,l)<=8) + continue; + + // store sprite info in lookup tables + //FIXME : numspritelumps do not duplicate sprite replacements + W_ReadLumpHeaderPwad(wadnum, l, &patch, sizeof (patch_t), 0); + spritecachedinfo[numspritelumps].width = SHORT(patch.width)<= max_spritelumps) + { + max_spritelumps *= 2; + Z_Realloc(spritecachedinfo, max_spritelumps*sizeof(*spritecachedinfo), PU_STATIC, &spritecachedinfo); + } + + ++numadded; } // @@ -456,6 +442,7 @@ void R_AddSpriteDefs(UINT16 wadnum) for (i = 0; i < numsprites; i++) { spritename = sprnames[i]; + if (spritename[4] && wadnum >= (UINT16)spritename[4]) continue; @@ -540,15 +527,6 @@ void R_InitSprites(void) R_AddSkins((UINT16)i, false); R_LoadSpriteInfoLumps(i, wadfiles[i]->numlumps); } - - // - // check if all sprites have frames - // - /* - for (i = 0; i < numsprites; i++) - if (sprites[i].numframes < 1) - CONS_Debug(DBG_SETUP, "R_InitSprites: sprite %s has no frames at all\n", sprnames[i]); - */ } // @@ -578,10 +556,8 @@ static vissprite_t *R_GetVisSprite(UINT32 num) static vissprite_t *R_NewVisSprite(void) { - if (visspritecount == MAXVISSPRITES) { - //CONS_Alert(CONS_ERROR, M_GetText("R_NewVisSprite: too many vissprites requested (maximum is %i)\n"), MAXVISSPRITES); + if (visspritecount == MAXVISSPRITES) return &overflowsprite; - } return R_GetVisSprite(visspritecount++); } @@ -638,7 +614,7 @@ void R_DrawMaskedColumn(column_t *column) if (dc_yh >= vid.height) dc_yh = vid.height - 1; - if (dc_yl <= dc_yh && dc_yl < vid.height && dc_yh > 0) + if (dc_yl <= dc_yh && dc_yh > 0) { dc_source = (UINT8 *)column + 3; dc_texturemid = basetexturemid - (topdelta<length : for flipped column function pointers and multi-patch on 2sided wall = texture->height -static void R_DrawFlippedMaskedColumn(column_t *column, INT32 texheight) +static void R_DrawFlippedMaskedColumn(column_t *column) { INT32 topscreen; INT32 bottomscreen; @@ -674,11 +650,10 @@ static void R_DrawFlippedMaskedColumn(column_t *column, INT32 texheight) if (topdelta <= prevdelta) topdelta += prevdelta; prevdelta = topdelta; - topdelta = texheight-column->length-topdelta; + topdelta = lengthcol-column->length-topdelta; topscreen = sprtopscreen + spryscale*topdelta; bottomscreen = sprbotscreen == INT32_MAX ? topscreen + spryscale*column->length : sprbotscreen + spryscale*column->length; - dc_yl = (topscreen+FRACUNIT-1)>>FRACBITS; dc_yh = (bottomscreen-1)>>FRACBITS; @@ -699,7 +674,7 @@ static void R_DrawFlippedMaskedColumn(column_t *column, INT32 texheight) if (dc_yh >= vid.height) dc_yh = vid.height - 1; - if (dc_yl <= dc_yh && dc_yl < vid.height && dc_yh > 0) + if (dc_yl <= dc_yh && dc_yh > 0) { dc_source = ZZ_Alloc(column->length); for (s = (UINT8 *)column+2+column->length, d = dc_source; d < dc_source+column->length; --s) @@ -724,9 +699,9 @@ static void R_DrawFlippedMaskedColumn(column_t *column, INT32 texheight) static void R_DrawVisSprite(vissprite_t *vis) { column_t *column; -#ifdef RANGECHECK + void (*localcolfunc)(column_t *); INT32 texturecolumn; -#endif + INT32 pwidth; fixed_t frac; patch_t *patch = vis->patch; fixed_t this_scale = vis->thingscale; @@ -751,7 +726,7 @@ static void R_DrawVisSprite(vissprite_t *vis) // TODO This check should not be necessary. But Papersprites near to the camera will sometimes create invalid values // for the vissprite's startfrac. This happens because they are not depth culled like other sprites. // Someone who is more familiar with papersprites pls check and try to fix <3 - if (vis->startfrac < 0 || vis->startfrac > (patch->width << FRACBITS)) + if (vis->startfrac < 0 || vis->startfrac > (SHORT(patch->width) << FRACBITS)) { // never draw vissprites with startfrac out of patch range return; @@ -816,7 +791,7 @@ static void R_DrawVisSprite(vissprite_t *vis) dc_colormap = colormaps; if (encoremap && !vis->mobj->color && !(vis->mobj->flags & MF_DONTENCOREMAP)) - dc_colormap += (256*32); + dc_colormap += COLORMAP_REMAPOFFSET; dc_texturemid = vis->texturemid; dc_texheight = 0; @@ -862,9 +837,6 @@ static void R_DrawVisSprite(vissprite_t *vis) if (vis->x2 >= vid.width) vis->x2 = vid.width-1; - lengthcol = SHORT(patch->height); - -#if 1 // Something is occasionally setting 1px-wide sprites whose frac is exactly the width of the sprite, causing crashes due to // accessing invalid column info. Until the cause is found, let's try to correct those manually... { @@ -872,35 +844,49 @@ static void R_DrawVisSprite(vissprite_t *vis) if (temp > 0) vis->x2 -= temp; } -#endif - for (dc_x = vis->x1; dc_x <= vis->x2; dc_x++, frac += vis->xiscale) + localcolfunc = (vis->vflip) ? R_DrawFlippedMaskedColumn : R_DrawMaskedColumn; + lengthcol = patch->height; + + // Split drawing loops for paper and non-paper to reduce conditional checks per sprite + if (vis->scalestep) { + fixed_t horzscale = FixedMul(vis->spritexscale, this_scale); fixed_t scalestep = FixedMul(vis->scalestep, vis->spriteyscale); - if (vis->scalestep) // currently papersprites only + pwidth = SHORT(patch->width); + + // Papersprite drawing loop + for (dc_x = vis->x1; dc_x <= vis->x2; dc_x++, spryscale += scalestep) { + angle_t angle = ((vis->centerangle + xtoviewangle[dc_x]) >> ANGLETOFINESHIFT) & 0xFFF; + texturecolumn = (vis->paperoffset - FixedMul(FINETANGENT(angle), vis->paperdistance)) / horzscale; + + if (texturecolumn < 0 || texturecolumn >= pwidth) + continue; + + if (vis->xiscale < 0) // Flipped sprite + texturecolumn = pwidth - 1 - texturecolumn; -#ifndef RANGECHECK - if ((frac>>FRACBITS) < 0 || (frac>>FRACBITS) >= SHORT(patch->width)) // if this doesn't work i'm removing papersprites - break; -#endif sprtopscreen = (centeryfrac - FixedMul(dc_texturemid, spryscale)); dc_iscale = (0xffffffffu / (unsigned)spryscale); - spryscale += scalestep; - } -#ifdef RANGECHECK - texturecolumn = frac>>FRACBITS; - if (texturecolumn < 0 || texturecolumn >= SHORT(patch->width)) - I_Error("R_DrawSpriteRange: bad texturecolumn"); - column = (column_t *)((UINT8 *)patch + LONG(patch->columnofs[texturecolumn])); -#else - column = (column_t *)((UINT8 *)patch + LONG(patch->columnofs[frac>>FRACBITS])); -#endif - if (vis->vflip) - R_DrawFlippedMaskedColumn(column, patch->height); - else - R_DrawMaskedColumn(column); + column = (column_t *)((UINT8 *)patch + LONG(patch->columnofs[texturecolumn])); + + localcolfunc (column); + } + } + else + { + pwidth = SHORT(patch->width); + + // Non-paper drawing loop + for (dc_x = vis->x1; dc_x <= vis->x2; dc_x++, frac += vis->xiscale) + { + texturecolumn = CLAMP(frac >> FRACBITS, 0, pwidth - 1); + column = (column_t *)((UINT8 *)patch + LONG(patch->columnofs[texturecolumn])); + + localcolfunc (column); + } } colfunc = basecolfunc; @@ -914,11 +900,10 @@ static void R_DrawVisSprite(vissprite_t *vis) static void R_DrawPrecipitationVisSprite(vissprite_t *vis) { column_t *column; -#ifdef RANGECHECK INT32 texturecolumn; -#endif fixed_t frac; patch_t *patch; + fixed_t this_scale = vis->thingscale; INT64 overflow_test; //Fab : R_InitSprites now sets a wad lump number @@ -939,10 +924,10 @@ static void R_DrawPrecipitationVisSprite(vissprite_t *vis) dc_colormap = colormaps; if (encoremap) - dc_colormap += (256*32); + dc_colormap += COLORMAP_REMAPOFFSET; dc_iscale = FixedDiv(FRACUNIT, vis->scale); - dc_texturemid = vis->texturemid; + dc_texturemid = FixedDiv(vis->texturemid, this_scale); dc_texheight = 0; frac = vis->startfrac; @@ -958,16 +943,9 @@ static void R_DrawPrecipitationVisSprite(vissprite_t *vis) for (dc_x = vis->x1; dc_x <= vis->x2; dc_x++, frac += vis->xiscale) { -#ifdef RANGECHECK - texturecolumn = frac>>FRACBITS; - - if (texturecolumn < 0 || texturecolumn >= SHORT(patch->width)) - I_Error("R_DrawPrecipitationSpriteRange: bad texturecolumn"); - + texturecolumn = CLAMP(frac >> FRACBITS, 0, SHORT(patch->width) - 1); column = (column_t *)((UINT8 *)patch + LONG(patch->columnofs[texturecolumn])); -#else - column = (column_t *)((UINT8 *)patch + LONG(patch->columnofs[frac>>FRACBITS])); -#endif + R_DrawMaskedColumn(column); } @@ -1043,20 +1021,14 @@ static void R_SplitSprite(vissprite_t *sprite, mobj_t *thing) newsprite->extra_colormap = sector->lightlist[i].extra_colormap; -/* - if (thing->frame & FF_TRANSMASK) - ; - else if (thing->flags2 & MF2_SHADOW) - ; - else -*/ if (!((thing->frame & (FF_FULLBRIGHT|FF_TRANSMASK) || thing->flags2 & MF2_SHADOW) && (!newsprite->extra_colormap || !(newsprite->extra_colormap->fog & 1)))) { lindex = FixedMul(sprite->xscale, LIGHTRESOLUTIONFIX)>>(LIGHTSCALESHIFT); - if (lindex >= MAXLIGHTSCALE) - lindex = MAXLIGHTSCALE-1; + // Mitigate against negative xscale and arithmetic overflow + lindex = CLAMP(lindex, 0, MAXLIGHTSCALE - 1); + newsprite->colormap = spritelights[lindex]; } } @@ -1076,6 +1048,7 @@ fixed_t R_GetShadowZ(mobj_t *thing, pslope_t **shadowslope) msecnode_t *node; sector_t *sector; ffloor_t *rover; + #define CHECKZ (isflipped ? z > thing->z+thing->height/2 && z < groundz : z < thing->z+thing->height/2 && z > groundz) for (node = thing->touching_sectorlist; node; node = node->m_sectorlist_next) @@ -1132,6 +1105,7 @@ fixed_t R_GetShadowZ(mobj_t *thing, pslope_t **shadowslope) static void R_ProjectSprite(mobj_t *thing) { mobj_t *oldthing = thing; + fixed_t tr_x, tr_y; fixed_t gxt, gyt; fixed_t tx, tz; @@ -1148,7 +1122,6 @@ static void R_ProjectSprite(mobj_t *thing) size_t rot; UINT8 flip; - /*boolean vflip = (!(thing->eflags & MFE_VERTICALFLIP) != !R_ThingVerticallyFlipped(thing));*/ boolean mirrored = thing->mirrored; boolean hflip = (!(thing->frame & FF_HORIZONTALFLIP) != !mirrored); @@ -1163,6 +1136,7 @@ static void R_ProjectSprite(mobj_t *thing) fixed_t scalestep; // toast '16 fixed_t offset, offset2; boolean papersprite = (thing->frame & FF_PAPERSPRITE); + fixed_t paperoffset = 0, paperdistance = 0; angle_t centerangle = 0; //SoM: 3/17/2000 fixed_t gz, gzt; @@ -1174,6 +1148,7 @@ static void R_ProjectSprite(mobj_t *thing) // rotsprite fixed_t spr_width, spr_height; fixed_t spr_offset, spr_topoffset; + #ifdef ROTSPRITE patch_t *rotsprite = NULL; INT32 rollangle = 0; @@ -1181,8 +1156,6 @@ static void R_ProjectSprite(mobj_t *thing) angle_t pitchnroll = 0; angle_t sliptiderollangle = 0; #endif - - fixed_t ang_scale = FRACUNIT; INT32 dist = -1; @@ -1214,7 +1187,7 @@ static void R_ProjectSprite(mobj_t *thing) tz = gxt-gyt; // thing is behind view plane? - if (!(papersprite) && (tz < FixedMul(MINZ, this_scale))) // papersprite clipping is handled later + if (!papersprite && (tz < FixedMul(MINZ, this_scale))) // papersprite clipping is handled later return; gxt = -FixedMul(tr_x, viewsin); @@ -1285,14 +1258,9 @@ static void R_ProjectSprite(mobj_t *thing) { ang = R_PointToAngle (interp.x, interp.y) - interp.angle; camang = R_PointToAngle (interp.x, interp.y); - } - - if (sprframe->rotate != SRF_SINGLE || papersprite) - { + if (mirrored) ang = InvAngle(ang); - if (papersprite) - ang_scale = abs(FINESINE(ang>>ANGLETOFINESHIFT)); } if (sprframe->rotate == SRF_SINGLE) @@ -1360,7 +1328,7 @@ static void R_ProjectSprite(mobj_t *thing) rollangle = thing->rollangle; } - if ((rollangle) || (pitchnroll) || (thing->player && thing->player->sliproll)) + if (rollangle || pitchnroll || (thing->player && thing->player->sliproll)) { rollsum = pitchnroll; @@ -1375,8 +1343,7 @@ static void R_ProjectSprite(mobj_t *thing) rollsum += thing->rollangle; rollangle = R_GetRollAngle(rollsum); - rotsprite = Patch_GetRotatedSprite( - sprframe, (thing->frame & FF_FRAMEMASK), rot, flip, false, sprinfo, rollangle); + rotsprite = Patch_GetRotatedSprite(sprframe, (thing->frame & FF_FRAMEMASK), rot, flip, false, sprinfo, rollangle); if (rotsprite != NULL) { @@ -1393,10 +1360,11 @@ static void R_ProjectSprite(mobj_t *thing) } #endif + flip = !flip != !hflip; + // calculate edges of the shape spritexscale = interp.spritexscale; spriteyscale = interp.spriteyscale; - if (spritexscale < 1 || spriteyscale < 1) return; @@ -1415,39 +1383,19 @@ static void R_ProjectSprite(mobj_t *thing) spr_offset += interp.spritexoffset * flipoffset; spr_topoffset += interp.spriteyoffset * flipoffset; } - - flip = !flip != !hflip; if (flip) offset = spr_offset - spr_width; else offset = -spr_offset; - //offset = FixedMul(offset, FixedMul(spritexscale, this_scale)); - //offset2 = FixedMul(spr_width, FixedMul(spritexscale, this_scale)); // OH GOD I'M REVOOOOORTINGGGG AHHHHHHH - offset = FixedMul(offset, FixedMul(spritexscale, this_scale)); - tx += FixedMul(offset, ang_scale); - x1 = (centerxfrac + FixedMul (tx,xscale)) >>FRACBITS; - - // off the right side? - if (x1 > viewwidth) - return; - offset2 = FixedMul(spr_width, FixedMul(spritexscale, this_scale)); - tx += FixedMul(offset2, ang_scale); - x2 = ((centerxfrac + FixedMul (tx,xscale)) >> FRACBITS) - 1; - - // off the left side - if (x2 < 0) - return; if (papersprite) { - fixed_t yscale2, cosmul, sinmul, tz2; - - if (x2 <= x1) - return; + fixed_t xscale2, yscale2, cosmul, sinmul, tx2, tz2; + INT32 range; if (ang >= ANGLE_180) { @@ -1464,7 +1412,22 @@ static void R_ProjectSprite(mobj_t *thing) gyt = -FixedMul(tr_y, viewsin); tz = gxt-gyt; yscale = FixedDiv(projectiony, tz); - if (yscale < 64) return; // Fix some funky visuals + + gxt = -FixedMul(tr_x, viewsin); + gyt = FixedMul(tr_y, viewcos); + tx = -(gyt + gxt); + xscale = FixedDiv(projection, tz); + x1 = (centerxfrac + FixedMul(tx,xscale))>>FRACBITS; + + // Get paperoffset (offset) and paperoffset (distance) + paperoffset = -FixedMul(tr_x, cosmul) - FixedMul(tr_y, sinmul); + paperdistance = -FixedMul(tr_x, sinmul) + FixedMul(tr_y, cosmul); + if (paperdistance < 0) + { + paperoffset = -paperoffset; + paperdistance = -paperdistance; + } + centerangle = viewangle - interp.angle; tr_x += FixedMul(offset2, cosmul); tr_y += FixedMul(offset2, sinmul); @@ -1472,14 +1435,72 @@ static void R_ProjectSprite(mobj_t *thing) gyt = -FixedMul(tr_y, viewsin); tz2 = gxt-gyt; yscale2 = FixedDiv(projectiony, tz2); - if (yscale2 < 64) return; // ditto + //if (yscale2 < 64) return; // ditto + + gxt = -FixedMul(tr_x, viewsin); + gyt = FixedMul(tr_y, viewcos); + tx2 = -(gyt + gxt); + xscale2 = FixedDiv(projection, tz2); + x2 = ((centerxfrac + FixedMul(tx2,xscale2))>>FRACBITS); if (max(tz, tz2) < FixedMul(MINZ, this_scale)) // non-papersprite clipping is handled earlier return; - scalestep = (yscale2 - yscale)/(x2 - x1); - scalestep = scalestep ? scalestep : 1; + // Needs partially clipped + if (tz < FixedMul(MINZ, this_scale)) + { + fixed_t div = FixedDiv(tz2-tz, FixedMul(MINZ, this_scale)-tz); + tx += FixedDiv(tx2-tx, div); + tz = FixedMul(MINZ, this_scale); + } + else if (tz2 < FixedMul(MINZ, this_scale)) + { + fixed_t div = FixedDiv(tz-tz2, FixedMul(MINZ, this_scale)-tz2); + tx2 += FixedDiv(tx-tx2, div); + tz2 = FixedMul(MINZ, this_scale); + } + if ((tx2 / 4) < -(FixedMul(tz2, fovtan)) || (tx / 4) > FixedMul(tz, fovtan)) // too far off the side? + return; + + yscale = FixedDiv(projectiony, tz); + xscale = FixedDiv(projection, tz); + + x1 = (centerxfrac + FixedMul(tx,xscale))>>FRACBITS; + + // off the right side? + if (x1 > viewwidth) + return; + + yscale2 = FixedDiv(projectiony, tz2); + xscale2 = FixedDiv(projection, tz2); + + x2 = (centerxfrac + FixedMul(tx2,xscale2))>>FRACBITS; + + // off the left side + if (x2 < 0) + return; + + range = x2 - x1; + + if (range < 0) + return; + + range++; // fencepost problem + + if (range > 32767) + { + // If the range happens to be too large for fixed_t, + // abort the draw to avoid xscale becoming negative due to arithmetic overflow. + return; + } + + scalestep = ((yscale2 - yscale)/range) ?: 1; + + if (scalestep == 0) + scalestep = 1; + + xscale = FixedDiv(range<>FRACBITS; + x1 = centerx + (FixedMul(tx,xscale) / FRACUNIT); + + // off the right side? + if (x1 > viewwidth) + return; + + tx += offset2; + //x2 = ((centerxfrac + FixedMul(tx,xscale))>>FRACBITS); x2--; + x2 = (centerx + (FixedMul(tx,xscale) / FRACUNIT)) - 1; + + // off the left side + if (x2 < 0) + return; } - xscale = FixedMul(xscale, ang_scale); - // PORTAL SPRITE CLIPPING - if (portalrender) + if (portalrender && portalclipline) { if (x2 < portalclipstart || x1 > portalclipend) return; @@ -1532,7 +1566,8 @@ static void R_ProjectSprite(mobj_t *thing) for (lightnum = 1; lightnum < thing->subsector->sector->numlights; lightnum++) { fixed_t h = thing->subsector->sector->lightlist[lightnum].slope ? P_GetZAt(thing->subsector->sector->lightlist[lightnum].slope, interp.x, interp.y) : thing->subsector->sector->lightlist[lightnum].height; - if (h <= gzt) { + if (h <= gzt) + { light = lightnum - 1; break; } @@ -1548,23 +1583,20 @@ static void R_ProjectSprite(mobj_t *thing) } heightsec = thing->subsector->sector->heightsec; - if (viewplayer->mo && viewplayer->mo->subsector) + if (viewplayer && viewplayer->mo && viewplayer->mo->subsector) phs = viewplayer->mo->subsector->sector->heightsec; else phs = -1; if (heightsec != -1 && phs != -1) // only clip things which are in special sectors { - fixed_t top = gzt; - fixed_t bottom = interp.z; - if (viewz < sectors[phs].floorheight ? - bottom >= sectors[heightsec].floorheight : - top < sectors[heightsec].floorheight) + interp.z >= sectors[heightsec].floorheight : + gzt < sectors[heightsec].floorheight) return; if (viewz > sectors[phs].ceilingheight ? - top < sectors[heightsec].ceilingheight && viewz >= sectors[heightsec].ceilingheight : - bottom >= sectors[heightsec].ceilingheight) + gzt < sectors[heightsec].ceilingheight && viewz >= sectors[heightsec].ceilingheight : + interp.z >= sectors[heightsec].ceilingheight) return; } @@ -1585,12 +1617,24 @@ static void R_ProjectSprite(mobj_t *thing) vis->pzt = vis->pz + vis->thingheight; vis->texturemid = FixedDiv(gzt - viewz, spriteyscale); vis->scalestep = scalestep; + vis->paperoffset = paperoffset; + vis->paperdistance = paperdistance; + vis->centerangle = centerangle; vis->mobj = thing; // Easy access! Tails 06-07-2002 vis->x1 = x1 < 0 ? 0 : x1; vis->x2 = x2 >= viewwidth ? viewwidth-1 : x2; + // PORTAL SEMI-CLIPPING + if (portalrender && portalclipline) + { + if (vis->x1 < portalclipstart) + vis->x1 = portalclipstart; + if (vis->x2 > portalclipend) + vis->x2 = portalclipend; + } + vis->sector = thing->subsector->sector; vis->szt = (INT16)((centeryfrac - FixedMul(vis->gzt - viewz, sortscale))>>FRACBITS); vis->sz = (INT16)((centeryfrac - FixedMul(vis->gz - viewz, sortscale))>>FRACBITS); @@ -1601,15 +1645,6 @@ static void R_ProjectSprite(mobj_t *thing) else vis->extra_colormap = thing->subsector->sector->extra_colormap; - // PORTAL SEMI-CLIPPING - if (portalrender) - { - if (vis->x1 < portalclipstart) - vis->x1 = portalclipstart; - if (vis->x2 > portalclipend) - vis->x2 = portalclipend; - } - vis->xscale = FixedMul(spritexscale, xscale); //SoM: 4/17/2000 vis->scale = FixedMul(spriteyscale, yscale); //<thingscale = interp.scale; @@ -1671,8 +1706,8 @@ static void R_ProjectSprite(mobj_t *thing) // diminished light lindex = FixedMul(xscale, LIGHTRESOLUTIONFIX)>>(LIGHTSCALESHIFT); - if (lindex >= MAXLIGHTSCALE) - lindex = MAXLIGHTSCALE-1; + // Mitigate against negative xscale and arithmetic overflow + lindex = CLAMP(lindex, 0, MAXLIGHTSCALE - 1); vis->colormap = spritelights[lindex]; } @@ -1711,7 +1746,8 @@ static void R_ProjectPrecipitationSprite(precipmobj_t *thing) fixed_t iscale; //SoM: 3/17/2000 - fixed_t gz ,gzt; + fixed_t gz, gzt; + fixed_t this_scale; INT32 dist = 1; @@ -1721,6 +1757,12 @@ static void R_ProjectPrecipitationSprite(precipmobj_t *thing) // uncapped/interpolation interpmobjstate_t interp = {0}; + // okay... this is a hack, but weather isn't networked, so it should be ok + if (!P_PrecipThinker(thing)) + { + return; + } + // do interpolation if (R_UsingFrameInterpolation() && !paused && (!cv_grmaxinterpdist.value || dist < cv_grmaxinterpdist.value)) { @@ -1731,6 +1773,8 @@ static void R_ProjectPrecipitationSprite(precipmobj_t *thing) R_InterpolatePrecipMobjState(thing, FRACUNIT, &interp); } + this_scale = interp.scale; + // transform the origin point tr_x = interp.x - viewx; tr_y = interp.y - viewy; @@ -1741,7 +1785,7 @@ static void R_ProjectPrecipitationSprite(precipmobj_t *thing) tz = gxt - gyt; // thing is behind view plane? - if (tz < MINZ) + if (tz < FixedMul(MINZ, this_scale)) return; gxt = -FixedMul(tr_x, viewsin); @@ -1749,7 +1793,7 @@ static void R_ProjectPrecipitationSprite(precipmobj_t *thing) tx = -(gyt + gxt); // too far off the side? - if (abs(tx) > tz<<2) + if (abs(tx) > FixedMul(tz, fovtan)<<2) return; // aspect ratio stuff : @@ -1782,14 +1826,14 @@ static void R_ProjectPrecipitationSprite(precipmobj_t *thing) lump = sprframe->lumpid[0]; //Fab: see note above // calculate edges of the shape - tx -= spritecachedinfo[lump].offset; + tx -= FixedMul(spritecachedinfo[lump].offset, this_scale); x1 = (centerxfrac + FixedMul (tx,xscale)) >>FRACBITS; // off the right side? if (x1 > viewwidth) return; - tx += spritecachedinfo[lump].width; + tx += FixedMul(spritecachedinfo[lump].width, this_scale); x2 = ((centerxfrac + FixedMul (tx,xscale)) >>FRACBITS) - 1; // off the left side @@ -1797,7 +1841,7 @@ static void R_ProjectPrecipitationSprite(precipmobj_t *thing) return; // PORTAL SPRITE CLIPPING - if (portalrender) + if (portalrender && portalclipline) { if (x2 < portalclipstart || x1 > portalclipend) return; @@ -1807,18 +1851,20 @@ static void R_ProjectPrecipitationSprite(precipmobj_t *thing) } //SoM: 3/17/2000: Disregard sprites that are out of view.. - gzt = interp.z + spritecachedinfo[lump].topoffset; - gz = gzt - spritecachedinfo[lump].height; + gzt = interp.z + FixedMul(spritecachedinfo[lump].topoffset, this_scale); + gz = gzt - FixedMul(spritecachedinfo[lump].height, this_scale); if (thing->subsector->sector->cullheight) { if (R_DoCulling(thing->subsector->sector->cullheight, viewsector->cullheight, viewz, gz, gzt)) - goto weatherthink; + return; } // store information in a vissprite vis = R_NewVisSprite(); - vis->scale = vis->sortscale = yscale; //<scale = FixedMul(yscale, this_scale); + vis->sortscale = yscale; //<thingscale = interp.scale; vis->dispoffset = 0; // Monster Iestyn: 23/11/15 vis->gx = interp.x; vis->gy = interp.y; @@ -1829,12 +1875,13 @@ static void R_ProjectPrecipitationSprite(precipmobj_t *thing) vis->pzt = vis->pz + vis->thingheight; vis->texturemid = vis->gzt - viewz; vis->scalestep = 0; + vis->paperdistance = 0; vis->x1 = x1 < 0 ? 0 : x1; vis->x2 = x2 >= viewwidth ? viewwidth-1 : x2; // PORTAL SEMI-CLIPPING - if (portalrender) + if (portalrender && portalclipline) { if (vis->x1 < portalclipstart) vis->x1 = portalclipstart; @@ -1850,9 +1897,7 @@ static void R_ProjectPrecipitationSprite(precipmobj_t *thing) iscale = FixedDiv(FRACUNIT, xscale); vis->startfrac = 0; - vis->xiscale = iscale; - - vis->thingscale = interp.scale; + vis->xiscale = FixedDiv(iscale, this_scale); if (vis->x1 > x1) vis->startfrac += vis->xiscale*(vis->x1-x1); @@ -1877,18 +1922,6 @@ static void R_ProjectPrecipitationSprite(precipmobj_t *thing) vis->precip = true; vis->vflip = false; vis->isScaled = false; - -weatherthink: - // okay... this is a hack, but weather isn't networked, so it should be ok - if (!(thing->precipflags & PCF_THUNK)) - { - if (thing->precipflags & PCF_RAIN) - P_RainThinker(thing); - else - P_SnowThinker(thing); - thing->precipflags |= PCF_THUNK; - } - } // R_AddSprites @@ -1898,17 +1931,13 @@ void R_AddSprites(sector_t *sec, INT32 lightlevel) { mobj_t *thing; INT32 lightnum; - fixed_t approx_dist, limit_dist; - - INT32 splitflags; // check if a mobj has spliscreen flags - boolean split_drawsprite; // used for splitscreen flags if (rendermode != render_soft) return; // BSP is traversed by subsector. // A sector might have been split into several - // subsectors during BSP building. + // subsectors during BSP building. // Thus we check whether its already added. if (sec->validcount == validcount) return; @@ -1932,88 +1961,16 @@ void R_AddSprites(sector_t *sec, INT32 lightlevel) // Handle all things in sector. // If a limit exists, handle things a tiny bit different. - if ((limit_dist = (fixed_t)(/*(maptol & TOL_NIGHTS) ? cv_drawdist_nights.value : */cv_drawdist.value) << FRACBITS)) + const fixed_t limit_dist = (fixed_t)(cv_drawdist.value) * mapobjectscale; + for (thing = sec->thinglist; thing; thing = thing->snext) { - for (thing = sec->thinglist; thing; thing = thing->snext) - { - split_drawsprite = false; + if (!R_ThingWithinDist(thing, limit_dist)) + continue; - if (thing->sprite == SPR_NULL || thing->flags2 & MF2_DONTDRAW) - continue; + if (!R_ThingVisible(thing)) + continue; - splitflags = thing->eflags & (MFE_DRAWONLYFORP1|MFE_DRAWONLYFORP2|MFE_DRAWONLYFORP3|MFE_DRAWONLYFORP4); - - if (splitscreen && splitflags) - { - if (thing->eflags & MFE_DRAWONLYFORP1) - if (viewssnum == 0) - split_drawsprite = true; - - if (thing->eflags & MFE_DRAWONLYFORP2) - if (viewssnum == 1) - split_drawsprite = true; - - if (thing->eflags & MFE_DRAWONLYFORP3 && splitscreen > 1) - if (viewssnum == 2) - split_drawsprite = true; - - if (thing->eflags & MFE_DRAWONLYFORP4 && splitscreen > 2) - if (viewssnum == 3) - split_drawsprite = true; - } - else - split_drawsprite = true; - - if (!split_drawsprite) - continue; - - approx_dist = P_AproxDistance(viewx-thing->x, viewy-thing->y); - - if (approx_dist > limit_dist) - continue; - - R_ProjectSprite(thing); - } - } - else - { - // Draw everything in sector, no checks - for (thing = sec->thinglist; thing; thing = thing->snext) - { - - split_drawsprite = false; - - if (thing->sprite == SPR_NULL || thing->flags2 & MF2_DONTDRAW) - continue; - - splitflags = thing->eflags & (MFE_DRAWONLYFORP1|MFE_DRAWONLYFORP2|MFE_DRAWONLYFORP3|MFE_DRAWONLYFORP4); - - if (splitscreen && splitflags) - { - if (thing->eflags & MFE_DRAWONLYFORP1) - if (viewssnum == 0) - split_drawsprite = true; - - if (thing->eflags & MFE_DRAWONLYFORP2) - if (viewssnum == 1) - split_drawsprite = true; - - if (thing->eflags & MFE_DRAWONLYFORP3 && splitscreen > 1) - if (viewssnum == 2) - split_drawsprite = true; - - if (thing->eflags & MFE_DRAWONLYFORP4 && splitscreen > 2) - if (viewssnum == 3) - split_drawsprite = true; - } - else - split_drawsprite = true; - - if (!split_drawsprite) - continue; - - R_ProjectSprite(thing); - } + R_ProjectSprite(thing); } } @@ -2024,11 +1981,12 @@ void R_AddSprites(sector_t *sec, INT32 lightlevel) // void R_AddPrecipitationSprites(void) { - const fixed_t drawdist = cv_drawdist_precip.value * mapobjectscale; + fixed_t drawdist = (fixed_t)(cv_drawdist_precip.value) * (cv_mobjscaleprecip.value ? mapobjectscale : FRACUNIT); INT32 xl, xh, yl, yh, bx, by; precipmobj_t *th, *next; + // no, no infinite draw distance for precipitation. this option at zero is supposed to turn it off if (drawdist == 0) { return; @@ -2036,7 +1994,6 @@ void R_AddPrecipitationSprites(void) R_GetRenderBlockMapDimensions(drawdist, &xl, &xh, &yl, &yh); - // no, no infinite draw distance for precipitation. this option at zero is supposed to turn it off for (bx = xl; bx <= xh; bx++) { for (by = yl; by <= yh; by++) @@ -2168,13 +2125,15 @@ static void R_CreateDrawNodes(void) } } // Check for a polyobject plane, but only if this is a front line - if (ds->curline->polyseg && ds->curline->polyseg->visplane && !ds->curline->side) { + if (ds->curline->polyseg && ds->curline->polyseg->visplane && !ds->curline->side) + { plane = ds->curline->polyseg->visplane; R_PlaneBounds(plane); if (plane->low < 0 || plane->high > vid.height || plane->high > plane->low) ; - else { + else + { // Put it in! entry = R_CreateDrawNode(&nodehead); entry->plane = plane; @@ -2197,6 +2156,7 @@ static void R_CreateDrawNodes(void) { if (!ds->ffloorplanes[p]) continue; + plane = ds->ffloorplanes[p]; R_PlaneBounds(plane); @@ -2269,10 +2229,12 @@ static void R_CreateDrawNodes(void) continue; // Effective height may be different for each comparison in the case of slopes - if (r2->plane->slope) { + if (r2->plane->slope) + { planeobjectz = P_GetZAt(r2->plane->slope, rover->gx, rover->gy); planecameraz = P_GetZAt(r2->plane->slope, viewx, viewy); - } else + } + else planeobjectz = planecameraz = r2->plane->height; if (rover->mobjflags & MF_NOCLIPHEIGHT) @@ -2331,16 +2293,20 @@ static void R_CreateDrawNodes(void) if (scale <= rover->sortscale) continue; - if (*r2->ffloor->t_slope) { + if (*r2->ffloor->t_slope) + { topplaneobjectz = P_GetZAt(*r2->ffloor->t_slope, rover->gx, rover->gy); topplanecameraz = P_GetZAt(*r2->ffloor->t_slope, viewx, viewy); - } else + } + else topplaneobjectz = topplanecameraz = *r2->ffloor->topheight; - if (*r2->ffloor->b_slope) { + if (*r2->ffloor->b_slope) + { botplaneobjectz = P_GetZAt(*r2->ffloor->b_slope, rover->gx, rover->gy); botplanecameraz = P_GetZAt(*r2->ffloor->b_slope, viewx, viewy); - } else + } + else botplaneobjectz = botplanecameraz = *r2->ffloor->bottomheight; if ((topplanecameraz > viewz && botplanecameraz < viewz) || @@ -2808,6 +2774,41 @@ void R_ClipSprites(void) } } +/* Check if thing may be drawn from our current view. */ +boolean R_ThingVisible (mobj_t *thing) +{ + if (thing->sprite == SPR_NULL || thing->flags2 & MF2_DONTDRAW) + return false; + + if (viewmobj && (thing == viewmobj)) + return false; + + if (splitscreen) + { + if ((viewssnum == 0 && (thing->renderflags & MFE_DRAWONLYFORP1)) + || (viewssnum == 1 && (thing->renderflags & MFE_DRAWONLYFORP2)) + || (viewssnum == 2 && (thing->renderflags & MFE_DRAWONLYFORP2)) + || (viewssnum == 3 && (thing->renderflags & MFE_DRAWONLYFORP4))) + return true; + } + + return true; +} + +boolean R_ThingWithinDist (mobj_t *thing, fixed_t limit_dist) +{ + if (limit_dist) + { + const fixed_t dist = P_AproxDistance(viewx-thing->x, viewy-thing->y); + if (dist > limit_dist) + { + return false; + } + } + + return true; +} + // // R_DrawMasked // @@ -2882,14 +2883,14 @@ UINT8 skinstatscount[9][9] = { {0, 0, 0, 0, 0, 0, 0, 0, 0} }; UINT8 skinsorted[MAXSKINS]; -skin_t localskins[MAXSKINS]; -skin_t allskins[MAXSKINS*2]; +skin_t localskins[MAXLOCALSKINS]; +skin_t allskins[MAXSKINS+MAXLOCALSKINS]; // FIXTHIS: don't work because it must be inistilised before the config load //#define SKINVALUES #ifdef SKINVALUES CV_PossibleValue_t skin_cons_t[MAXSKINS+1]; -CV_PossibleValue_t localskin_cons_t[MAXSKINS+1]; +CV_PossibleValue_t localskin_cons_t[MAXLOCALSKINS+1]; #endif static void Sk_SetDefaultValue(skin_t *skin, boolean local) @@ -2941,6 +2942,9 @@ void R_InitSkins(void) { skin_cons_t[i].value = 0; skin_cons_t[i].strvalue = NULL; + } + for (i = 0; i <= MAXLOCALSKINS; i++) + { localskin_cons_t[i].value = 0; localskin_cons_t[i].strvalue = NULL; } @@ -3114,12 +3118,15 @@ void SetLocalPlayerSkin(INT32 playernum, const char *skinname, consvar_t *cvar) } } - if (cvar != NULL) { - if (player->localskin > 0) { + if (cvar != NULL) + { + if (player->localskin > 0) + { CV_StealthSet(&cv_fakelocalskin, ( (player->skinlocal) ? localskins : skins )[player->localskin - 1].name); CV_StealthSet(cvar, ( (player->skinlocal) ? localskins : skins )[player->localskin - 1].name); } - else { + else + { CV_StealthSet(&cv_fakelocalskin, "none"); CV_StealthSet(cvar, "none"); } @@ -3145,21 +3152,6 @@ void SetPlayerSkinByNum(INT32 playernum, INT32 skinnum) player->kartspeed = skin->kartspeed; player->kartweight = skin->kartweight; - /*if (!(cv_debug || devparm) && !(netgame || multiplayer || demo.playback || modeattacking)) - { - if (playernum == consoleplayer) - CV_StealthSetValue(&cv_playercolor, skin->prefcolor); - else if (playernum == displayplayers[1]) - CV_StealthSetValue(&cv_playercolor2, skin->prefcolor); - else if (playernum == displayplayers[2]) - CV_StealthSetValue(&cv_playercolor3, skin->prefcolor); - else if (playernum == displayplayers[3]) - CV_StealthSetValue(&cv_playercolor4, skin->prefcolor); - player->skincolor = skin->prefcolor; - if (player->mo) - player->mo->color = player->skincolor; - }*/ - if (player->mo) P_SetScale(player->mo, player->mo->scale); @@ -3329,11 +3321,17 @@ void R_AddSkins(UINT16 wadnum, boolean local) // advance by default lastlump = lump + 1; - if (( (local) ? numlocalskins : numskins ) >= MAXSKINS) + if (numskins >= MAXSKINS) { CONS_Alert(CONS_WARNING, M_GetText("Unable to add skin, too many characters are loaded (%d maximum)\n"), MAXSKINS); continue; // so we know how many skins couldn't be added } + if (numlocalskins >= MAXLOCALSKINS) + { + CONS_Alert(CONS_WARNING, M_GetText("Unable to add localskin, too many localskins are loaded (%d maximum)\n"), MAXLOCALSKINS); + continue; // so we know how many skins couldn't be added + } + buf = W_CacheLumpNumPwad(wadnum, lump, PU_CACHE); size = W_LumpLengthPwad(wadnum, lump); @@ -3571,8 +3569,8 @@ next_token: CONS_Printf(M_GetText("Added skin '%s'\n"), skin->name); #ifdef SKINVALUES - ( (local) ? localskin_cons_t : skin_cons_t )[( (local) ? numlocalskins : numskins )].value = ( (local) ? numlocalskins : numskins ); - ( (local) ? localskin_cons_t : skin_cons_t )[( (local) ? numlocalskins : numskins )].strvalue = skin->name; + (local ? localskin_cons_t : skin_cons_t)[(local ? numlocalskins : numskins)].value = (local ? numlocalskins : numskins); + (local ? localskin_cons_t : skin_cons_t)[(local ? numlocalskins : numskins)].strvalue = skin->name; #endif // Update the forceskin possiblevalues @@ -3583,6 +3581,7 @@ next_token: } skin->localskin = local; + // so we dont have to guess if (local) skin->localnum = numlocalskins; @@ -3590,28 +3589,27 @@ next_token: skin->localnum = numskins; // add face graphics - if (local) { + if (local) ST_LoadLocalFaceGraphics(skin->facerank, skin->facewant, skin->facemmap, numlocalskins); - } else { + else ST_LoadFaceGraphics(skin->facerank, skin->facewant, skin->facemmap, numskins); - } #ifdef HWRENDER if (rendermode == render_opengl) - HWR_AddPlayerMD2(( (local) ? numlocalskins : numskins ), local); + HWR_AddPlayerMD2(((local) ? numlocalskins : numskins), local); #endif - if (!local) { + if (!local) + { skinstats[skin->kartspeed-1][skin->kartweight-1][skinstatscount[skin->kartspeed-1][skin->kartweight-1]] = numskins; CONS_Debug(DBG_SETUP, M_GetText("Added %d to %d, %d\n"), numskins, skin->kartweight, skin->kartweight); skinstatscount[skin->kartspeed-1][skin->kartweight-1]++; CONS_Debug(DBG_SETUP, M_GetText("Incremented %d, %d to %d\n"), skin->kartspeed, skin->kartweight, skinstatscount[skin->kartspeed - 1][skin->kartweight - 1]); - skinsorted[numskins] = numskins; } allskins[numallskins] = ( (local) ? localskins : skins )[( (local) ? numlocalskins : numskins )]; - ( (local) ? numlocalskins++ : numskins++ ); + local ? numlocalskins++ : numskins++; numallskins++; } diff --git a/src/r_things.h b/src/r_things.h index 88e1abdab..0e99c490c 100644 --- a/src/r_things.h +++ b/src/r_things.h @@ -72,6 +72,9 @@ void R_InitSprites(void); void R_ClearSprites(void); void R_DrawMasked(void); +boolean R_ThingVisible (mobj_t *thing); +boolean R_ThingWithinDist (mobj_t *thing, fixed_t limit_dist); + // ----------- // SKINS STUFF // ----------- @@ -149,8 +152,11 @@ typedef struct vissprite_s fixed_t thingscale; // the object's scale fixed_t sortscale; // sortscale only differs from scale for flat sprites fixed_t scalestep; // only for flat sprites, 0 otherwise + fixed_t paperoffset, paperdistance; // for paper sprites, offset/dist relative to the angle fixed_t xiscale; // negative if flipped + angle_t centerangle; // for paper sprites + fixed_t texturemid; patch_t *patch; @@ -172,12 +178,10 @@ typedef struct vissprite_s spritecut_e cut; UINT32 renderflags; - UINT8 rotateflags; fixed_t spritexscale, spriteyscale; fixed_t spritexoffset, spriteyoffset; - INT16 clipbot[MAXVIDWIDTH], cliptop[MAXVIDWIDTH]; boolean precip; @@ -219,8 +223,8 @@ extern UINT8 skinstatscount[9][9]; extern UINT8 skinsorted[MAXSKINS]; void sortSkinGrid(void); -extern skin_t localskins[MAXSKINS]; -extern skin_t allskins[MAXSKINS*2]; +extern skin_t localskins[MAXLOCALSKINS]; +extern skin_t allskins[MAXSKINS+MAXLOCALSKINS]; boolean SetPlayerSkin(INT32 playernum,const char *skinname); void SetPlayerSkinByNum(INT32 playernum,INT32 skinnum); // Tails 03-16-2002 diff --git a/src/s_sound.c b/src/s_sound.c index b140978a3..f3450b6f4 100644 --- a/src/s_sound.c +++ b/src/s_sound.c @@ -65,7 +65,7 @@ static void AmigaType_OnChange(void); consvar_t cv_samplerate = {"samplerate", "44100", 0, CV_Unsigned, NULL, 22050, NULL, NULL, 0, 0, NULL}; //Alam: For easy hacking? -static CV_PossibleValue_t audbuffersize_cons_t[] = {{512, "512"}, {1024, "1024"}, {2048, "2048"}, {4096, "4096"}, {0, NULL}}; +static CV_PossibleValue_t audbuffersize_cons_t[] = {{256, "256"}, {512, "512"}, {1024, "1024"}, {2048, "2048"}, {4096, "4096"}, {0, NULL}}; consvar_t cv_audbuffersize = {"buffersize", "2048", CV_SAVE, audbuffersize_cons_t, BufferSize_OnChange, 0, NULL, NULL, 0, 0, NULL}; // stereo reverse @@ -109,8 +109,6 @@ static CV_PossibleValue_t music_resync_threshold_cons_t[] = { }; consvar_t cv_music_resync_threshold = {"music_resync_threshold", "0", CV_SAVE|CV_CALL, music_resync_threshold_cons_t, I_UpdateSongLagThreshold, 0, NULL, NULL, 0, 0, NULL}; -consvar_t cv_music_resync_powerups_only = {"music_resync_powerups_only", "No", CV_SAVE|CV_CALL, CV_YesNo, I_UpdateSongLagConditions, 0, NULL, NULL, 0, 0, NULL}; - consvar_t cv_invincmusicfade = {"invincmusicfade", "300", CV_SAVE, CV_Unsigned, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_growmusicfade = {"growmusicfade", "500", CV_SAVE, CV_Unsigned, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_respawnfademusicout = {"respawnfademusicout", "1000", CV_SAVE, CV_Unsigned, NULL, 0, NULL, NULL, 0, 0, NULL}; @@ -289,7 +287,6 @@ void S_RegisterSoundStuff(void) CV_RegisterVar(&cv_pausemusic); CV_RegisterVar(&cv_music_resync_threshold); - CV_RegisterVar(&cv_music_resync_powerups_only); CV_RegisterVar(&cv_invincmusicfade); CV_RegisterVar(&cv_growmusicfade); @@ -311,8 +308,6 @@ void S_RegisterSoundStuff(void) static void SetChannelsNum(void) { - INT32 i; - // Allocating the internal channels for mixing // (the maximum number of sounds rendered // simultaneously) within zone memory. @@ -322,7 +317,6 @@ static void SetChannelsNum(void) Z_Free(channels); channels = NULL; - if (cv_numChannels.value == 999999999) //Alam_GBC: OH MY ROD!(ROD rimmiced with GOD!) CV_StealthSet(&cv_numChannels,cv_numChannels.defaultvalue); @@ -333,13 +327,10 @@ static void SetChannelsNum(void) return; } #endif - if (cv_numChannels.value) - channels = (channel_t *)Z_Malloc(cv_numChannels.value * sizeof (channel_t), PU_STATIC, NULL); - numofchannels = cv_numChannels.value; - // Free all channels for use - for (i = 0; i < numofchannels; i++) - channels[i].sfxinfo = 0; + if (cv_numChannels.value) + channels = (channel_t *)Z_Calloc(cv_numChannels.value * sizeof (channel_t), PU_STATIC, NULL); + numofchannels = (channels ? cv_numChannels.value : 0); } // Retrieve the lump number of sfx @@ -1046,7 +1037,8 @@ boolean S_AdjustSoundParams(const mobj_t *listener, const mobj_t *source, INT32 if (sfxinfo->pitch & SF_OUTSIDESOUND) // Rain special case { - fixed_t x, y, yl, yh, xl, xh, newdist; + INT64 x, y, yl, yh, xl, xh; + fixed_t newdist; if (R_PointInSubsector(listensource.x, listensource.y)->sector->ceilingpic == skyflatnum) approx_dist = 0; @@ -1313,7 +1305,6 @@ static void *music_data; static UINT16 music_flags; static boolean music_looping; static consvar_t *music_refade_cv; -static int music_usage; static char queue_name[7]; static UINT16 queue_flags; @@ -1375,17 +1366,7 @@ void S_LoadMusicDefs(UINT16 wadnum) // Find music def while (stoken) { - /*if ((stoken[0] == '/' && stoken[1] == '/') - || (stoken[0] == '#')) // skip comments - { - stoken = strtok(NULL, "\r\n"); // skip end of line - if (def) - stoken = strtok(NULL, "\r\n= "); - else - stoken = strtok(NULL, "\r\n "); - line++; - } - else*/ if (!stricmp(stoken, "lump")) + if (!stricmp(stoken, "lump")) { value = strtok(NULL, "\r\n "); @@ -1460,35 +1441,44 @@ skip_lump: return; } - if (!stricmp(stoken, "usage")) { + if (!stricmp(stoken, "usage")) + { STRBUFCPY(def->usage, value); for (value = def->usage; *value; value++) if (*value == '_') *value = ' '; // turn _ into spaces. //CONS_Printf("S_LoadMusicDefs: Set usage to '%s'\n", def->usage); - } else if (!stricmp(stoken, "source")) { + } + else if (!stricmp(stoken, "source")) + { STRBUFCPY(def->source, value); for (value = def->source; *value; value++) if (*value == '_') *value = ' '; // turn _ into spaces. //CONS_Printf("S_LoadMusicDefs: Set source to '%s'\n", def->source); - } else if (!stricmp(stoken, "title")) { + } + else if (!stricmp(stoken, "title")) + { def->use_info = true; STRBUFCPY(def->title, value); for (value = def->title; *value; value++) if (*value == '_') *value = ' '; // turn _ into spaces. //CONS_Printf("S_LoadMusicDefs: Set source to '%s'\n", def->source); - } else if (!stricmp(stoken, "alttitle")) { + } + else if (!stricmp(stoken, "alttitle")) + { STRBUFCPY(def->alttitle, value); for (value = def->alttitle; *value; value++) if (*value == '_') *value = ' '; // turn _ into spaces. //CONS_Printf("S_LoadMusicDefs: Set source to '%s'\n", def->source); - } else if (!stricmp(stoken, "authors")) { + } + else if (!stricmp(stoken, "authors")) + { STRBUFCPY(def->authors, value); for (value = def->authors; *value; value++) if (*value == '_') *value = ' '; // turn _ into spaces. //CONS_Printf("S_LoadMusicDefs: Set source to '%s'\n", def->source); - } else { - CONS_Alert(CONS_WARNING, "MUSICDEF: Invalid field '%s'. (file %s, line %d)\n", stoken, wadfiles[wadnum]->filename, line); } + else + CONS_Alert(CONS_WARNING, "MUSICDEF: Invalid field '%s'. (file %s, line %d)\n", stoken, wadfiles[wadnum]->filename, line); skip_field: stoken = strtok(NULL, "\r\n= "); @@ -1559,17 +1549,7 @@ void S_LoadMTDefs(UINT16 wadnum) // Find music def while (stoken) { - /*if ((stoken[0] == '/' && stoken[1] == '/') - || (stoken[0] == '#')) // skip comments - { - stoken = strtok(NULL, "\r\n"); // skip end of line - if (def) - stoken = strtok(NULL, "\r\n= "); - else - stoken = strtok(NULL, "\r\n "); - line++; - } - else*/ if (!stricmp(stoken, "lump")) + if (!stricmp(stoken, "lump")) { value = strtok(NULL, "\r\n "); @@ -1638,25 +1618,30 @@ skip_lump: return; } - if (!stricmp(stoken, "title")) { + if (!stricmp(stoken, "title")) + { def->use_info = true; STRBUFCPY(def->title, value); for (value = def->title; *value; value++) if (*value == '_') *value = ' '; // turn _ into spaces. //CONS_Printf("S_LoadMusicDefs: Set source to '%s'\n", def->source); - } else if (!stricmp(stoken, "alttitle")) { + } + else if (!stricmp(stoken, "alttitle")) + { STRBUFCPY(def->alttitle, value); for (value = def->alttitle; *value; value++) if (*value == '_') *value = ' '; // turn _ into spaces. //CONS_Printf("S_LoadMusicDefs: Set source to '%s'\n", def->source); - } else if (!stricmp(stoken, "authors")) { + } + else if (!stricmp(stoken, "authors")) + { STRBUFCPY(def->authors, value); for (value = def->authors; *value; value++) if (*value == '_') *value = ' '; // turn _ into spaces. //CONS_Printf("S_LoadMusicDefs: Set source to '%s'\n", def->source); - } else { - CONS_Alert(CONS_WARNING, "MUSCINFO: Invalid field '%s'. (file %s, line %d)\n", stoken, wadfiles[wadnum]->filename, line); } + else + CONS_Alert(CONS_WARNING, "MUSCINFO: Invalid field '%s'. (file %s, line %d)\n", stoken, wadfiles[wadnum]->filename, line); skip_field: stoken = strtok(NULL, "\r\n= "); @@ -1939,7 +1924,6 @@ static void S_UnloadMusic(void) music_looping = false; music_refade_cv = 0; - music_usage = 0; } static boolean S_PlayMusic(boolean looping, UINT32 fadeinms) @@ -1947,8 +1931,7 @@ static boolean S_PlayMusic(boolean looping, UINT32 fadeinms) if (S_MusicDisabled()) return false; - if (cv_birdmusic.value) - I_UpdateSongLagConditions(); + I_UpdateSongLagThreshold(); if ((!fadeinms && !I_PlaySong(looping)) || (fadeinms && !I_FadeInPlaySong(fadeinms, looping))) @@ -1996,7 +1979,7 @@ void S_ChangeMusicEx(const char *mmusic, UINT16 mflags, boolean looping, UINT32 strncpy(newmusic, mmusic, 6); - if(LUAh_MusicChange(music_name, newmusic, &mflags, &looping, &position, &prefadems, &fadeinms)) + if (LUAh_MusicChange(music_name, newmusic, &mflags, &looping, &position, &prefadems, &fadeinms)) return; // No Music (empty string) @@ -2143,6 +2126,9 @@ void S_SetMusicVolume(INT32 digvolume, INT32 seqvolume) void S_SetRestoreMusicFadeInCvar (consvar_t *cv) { + if (!cv_birdmusic.value) + return; + music_refade_cv = cv; } @@ -2154,17 +2140,6 @@ int S_GetRestoreMusicFadeIn (void) return 0; } -void S_SetMusicUsage (int type) -{ - music_usage = type; - I_UpdateSongLagConditions(); -} - -int S_MusicUsage (void) -{ - return music_usage; -} - /// ------------------------ /// Music Fading /// ------------------------ @@ -2363,9 +2338,8 @@ static void Command_ShowMusicCredit_f(void) musicdef_t *def = S_FindMusicCredit(musname); - if (def) { + if (def) CONS_Printf("%.6s - %.255s\n", musname, def->source); - } } static void GameSounds_OnChange(void) @@ -2396,6 +2370,7 @@ static void SoundPrecache_OnChange(void) else if (!S_PrecacheSound()) { S_ClearSfx(); + if (!sound_disabled) S_InitSfxChannels(cv_soundvolume.value); } diff --git a/src/s_sound.h b/src/s_sound.h index 538e8713e..8787ea5e5 100644 --- a/src/s_sound.h +++ b/src/s_sound.h @@ -55,7 +55,6 @@ extern consvar_t cv_amigatype; //bird music stuff extern consvar_t cv_music_resync_threshold; -extern consvar_t cv_music_resync_powerups_only; extern consvar_t cv_invincmusicfade; extern consvar_t cv_growmusicfade; @@ -218,11 +217,6 @@ UINT32 S_GetMusicPosition(void); // Music Playback // -enum -{ - MUS_SPECIAL = 1,/* powerups--invincibility, grow */ -}; - // Start music track, arbitrary, given its name, and set whether looping // note: music flags 12 bits for tracknum (gme, other formats with more than one track) // 13-15 aren't used yet @@ -238,9 +232,6 @@ void S_SetRestoreMusicFadeInCvar (consvar_t *cvar); S_SetRestoreMusicFadeInCvar(0) int S_GetRestoreMusicFadeIn (void); -void S_SetMusicUsage (int type); -int S_MusicUsage (void); - // Stops the music. void S_StopMusic(void); diff --git a/src/screen.c b/src/screen.c index e5c1ebff4..8fe00e821 100644 --- a/src/screen.c +++ b/src/screen.c @@ -331,7 +331,7 @@ void SCR_SetDefaultMode(void) // remember the default screen size CV_SetValue(&cv_scr_width, vid.width); CV_SetValue(&cv_scr_height, vid.height); - CV_SetValue(&cv_scr_depth, vid.bpp*8); + //CV_SetValue(&cv_scr_depth, vid.bpp*8); } // Change fullscreen on/off according to cv_fullscreen diff --git a/src/screen.h b/src/screen.h index a6a0eb477..4f3b0b1ff 100644 --- a/src/screen.h +++ b/src/screen.h @@ -45,8 +45,8 @@ #define BASEVIDHEIGHT 200 // resolution of the graphics. // max res for png capture; seperated it so both MAXVID values can be lower for software performance reasons; OpenGL does not care about those anyways -#define MAXPNGWIDTH 3840 -#define MAXPNGHEIGHT 2160 +#define MAXPNGWIDTH 7680 +#define MAXPNGHEIGHT 4320 // global video state typedef struct viddef_s diff --git a/src/sdl/IMG_xpm.c b/src/sdl/IMG_xpm.c index 458131620..7a68185fa 100644 --- a/src/sdl/IMG_xpm.c +++ b/src/sdl/IMG_xpm.c @@ -1198,6 +1198,8 @@ SDL_Surface *IMG_ReadXPMFromArray(const char **xpm) return load_xpm(xpm, NULL); } +#undef MAX + #else /* not LOAD_XPM */ /* See if an image is contained in a data source */ diff --git a/src/sdl/i_system.c b/src/sdl/i_system.c index 9574d6ec5..66ce038f5 100644 --- a/src/sdl/i_system.c +++ b/src/sdl/i_system.c @@ -446,6 +446,7 @@ SDL_bool consolevent = SDL_FALSE; SDL_bool framebuffer = SDL_FALSE; UINT8 keyboard_started = false; +boolean g_in_exiting_signal_handler = false; static void I_ReportSignal(int num, int coredumped) { @@ -512,6 +513,8 @@ static void I_ReportSignal(int num, int coredumped) #ifndef NEWSIGNALHANDLER FUNCNORETURN static ATTRNORETURN void signal_handler(INT32 num) { + g_in_exiting_signal_handler = true; + D_QuitNetGame(); // Fix server freezes #ifdef HAVE_LIBBACKTRACE @@ -2663,6 +2666,42 @@ const char *I_GetJoyName(INT32 joyindex) return joyname; } +void I_GamepadRumble(INT32 device_id, UINT16 low_strength, UINT16 high_strength, UINT32 duration) +{ +#if !(SDL_VERSION_ATLEAST(2,0,14)) + (void)device_id; + (void)low_strength; + (void)high_strength; +#else + I_Assert(device_id > 0); // Gamepad devices are always ID 1 or higher + + SDL_GameController *controller = SDL_GameControllerFromInstanceID(device_id - 1); + if (controller == NULL) + { + return; + } + + SDL_GameControllerRumble(controller, low_strength, high_strength, duration); +#endif +} + +void I_SetGamepadIndicatorColor(INT32 device_id, UINT8 red, UINT8 green, UINT8 blue) +{ +#if !(SDL_VERSION_ATLEAST(2,0,14)) + (void)device_id; +#else + I_Assert(device_id > 0); // Gamepad devices are always ID 1 or higher + + SDL_GameController *controller = SDL_GameControllerFromInstanceID(device_id - 1); + if (controller == NULL) + { + return; + } + + SDL_GameControllerSetLED(controller, red, green, blue); +#endif +} + #ifndef NOMUMBLE #ifdef HAVE_MUMBLE // Best Mumble positional audio settings: @@ -3189,28 +3228,21 @@ ticcmd_t *I_BaseTiccmd4(void) return &emptycmd4; } +// +// I_GetTime +// returns time in 1/TICRATE second tics +// + static Uint64 timer_frequency; precise_t I_GetPreciseTime(void) { -#if defined(_WIN32) - LARGE_INTEGER counter; - QueryPerformanceCounter(&counter); - return counter.QuadPart; -#else return SDL_GetPerformanceCounter(); -#endif } UINT64 I_GetPrecisePrecision(void) { -#if defined(_WIN32) - LARGE_INTEGER frequency; - QueryPerformanceFrequency(&frequency); - return frequency.QuadPart; -#else return SDL_GetPerformanceFrequency(); -#endif } static UINT32 frame_rate; @@ -3237,24 +3269,14 @@ static void I_InitFrameTime(const UINT64 now, const UINT32 cap) } double I_GetFrameTime(void) -{ -#if defined(_WIN32) - LARGE_INTEGER now; - QueryPerformanceCounter(&now); - const UINT64 nowValue = now.QuadPart; -#else +{ const UINT64 now = SDL_GetPerformanceCounter(); -#endif const UINT32 cap = R_GetFramerateCap(); if (cap != frame_rate) { // Maybe do this in a OnChange function for cv_fpscap? -#if defined(_WIN32) - I_InitFrameTime(nowValue, cap); -#else I_InitFrameTime(now, cap); -#endif } if (frame_rate == 0) @@ -3264,17 +3286,10 @@ double I_GetFrameTime(void) } else { -#if defined(_WIN32) - elapsed_frames += (nowValue - frame_epoch) / frame_frequency; -#else elapsed_frames += (now - frame_epoch) / frame_frequency; -#endif } -#if defined(_WIN32) - frame_epoch = nowValue; // moving epoch -#else - frame_epoch = now; // moving epoch -#endif + + frame_epoch = now; // moving epoch return elapsed_frames; } @@ -3283,13 +3298,8 @@ double I_GetFrameTime(void) // void I_StartupTimer(void) { -#if defined(_WIN32) - LARGE_INTEGER frequency; - QueryPerformanceFrequency(&frequency); - timer_frequency = frequency.QuadPart; -#else timer_frequency = SDL_GetPerformanceFrequency(); -#endif + I_InitFrameTime(0, R_GetFramerateCap()); elapsed_frames = 0.0; } @@ -3335,12 +3345,7 @@ void I_SleepDuration(precise_t duration) // hard sleep function. if (sleepvalue > 0 && (dest - cur) > delaygranularity) { -#if defined(_WIN32) - DWORD sleepDuration = (DWORD)min((INT64)(dest - cur), sleepvalue); - SleepEx(sleepDuration, TRUE); -#else I_Sleep(sleepvalue); -#endif } // Otherwise, this is a spinloop. @@ -3436,13 +3441,13 @@ INT32 I_StartupSystem(void) SDL_version SDLlinked; SDL_VERSION(&SDLcompiled) SDL_GetVersion(&SDLlinked); -#ifdef HAVE_THREADS - I_start_threads(); - I_AddExitFunc(I_stop_threads); -#endif I_StartupConsole(); #ifdef NEWSIGNALHANDLER I_Fork(); +#endif +#ifdef HAVE_THREADS + I_start_threads(); + I_AddExitFunc(I_stop_threads); #endif I_RegisterSignals(); I_OutputMsg("Compiled for SDL version: %d.%d.%d\n", @@ -4039,10 +4044,15 @@ static const char *locateWad(void) #endif #ifndef NOHOME // find in $HOME - I_OutputMsg(",HOME"); + I_OutputMsg(",HOME/" DEFAULTDIR); if ((envstr = I_GetEnv("HOME")) != NULL) { - WadPath = searchWad(envstr); + char *tmp = malloc(strlen(envstr) + sizeof(PATHSEP) + sizeof(DEFAULTDIR)); + strcpy(tmp, envstr); + strcat(tmp, PATHSEP); + strcat(tmp, DEFAULTDIR); + WadPath = searchWad(tmp); + free(tmp); if (WadPath) return WadPath; } diff --git a/src/sdl/i_video.c b/src/sdl/i_video.c index f90f5bb18..241f09e05 100644 --- a/src/sdl/i_video.c +++ b/src/sdl/i_video.c @@ -217,6 +217,10 @@ static SDL_bool Impl_CreateWindow(SDL_bool fullscreen); static void Impl_SetWindowIcon(void); #ifdef USE_FBO_OGL +#if defined (__unix__) +static void I_FixXwaylandNvidia(void); +boolean xwaylandcrap = false; +#endif boolean downsample = false; void RefreshOGLSDLSurface(void) { @@ -263,7 +267,6 @@ static void SDLSetMode(INT32 width, INT32 height, SDL_bool fullscreen) else { Impl_CreateWindow(fullscreen); - Impl_SetWindowIcon(); wasfullscreen = fullscreen; SDL_SetWindowSize(window, width, height); if (fullscreen) @@ -275,6 +278,12 @@ static void SDLSetMode(INT32 width, INT32 height, SDL_bool fullscreen) #ifdef HWRENDER if (rendermode == render_opengl) { +#ifdef USE_FBO_OGL +#if defined (__unix__) + I_FixXwaylandNvidia(); +#endif + I_DownSample(); +#endif OglSdlSurface(vid.width, vid.height); } #endif @@ -749,7 +758,7 @@ static INT32 SDLJoyAxis(const Sint16 axis, evtype_t which) #ifdef USE_FBO_OGL void I_DownSample(void) { - if (!cv_grframebuffer.value || !(rendermode == render_opengl) || (!supportFBO)) //no sense to do this crap if we cant benefit from it + if (!cv_grframebuffer.value || !supportFBO) //no sense to do this crap if we cant benefit from it { downsample = false; return; @@ -758,23 +767,46 @@ void I_DownSample(void) int currentDisplayIndex = SDL_GetWindowDisplayIndex(window); SDL_DisplayMode curmode; - if (SDL_GetCurrentDisplayMode(currentDisplayIndex, &curmode) == 0) + if (SDL_GetCurrentDisplayMode(currentDisplayIndex, &curmode) != 0) { - if ((vid.width > curmode.w) || (vid.height > curmode.h)) //check if current resolution is higher than current display resolution - { - downsample = true; - RefreshOGLSDLSurface(); - } - else - downsample = false; // its not so no need to do crap + downsample = false; // couldnt get display info so turn the thing off + RefreshOGLSDLSurface(); + return; + } + + if ((vid.width > curmode.w) || (vid.height > curmode.h)) //check if current resolution is higher than current display resolution + { + downsample = true; + RefreshOGLSDLSurface(); } else - downsample = false; // couldnt get display info so turn the thing off + { + downsample = false; // its not so no need to do crap + RefreshOGLSDLSurface(); + } } + +#if defined (__unix__) +static void I_FixXwaylandNvidia(void) //dumbass crap, fix ur shit nvidia +{ + if (!supportFBO) + { + xwaylandcrap = false; + return; + } + + // enable fbo resize shit, update the ogl surface and turn crap back off lol + xwaylandcrap = true; + RefreshOGLSDLSurface(); + xwaylandcrap = false; + RefreshOGLSDLSurface(); +} +#endif #endif static void Impl_HandleWindowEvent(SDL_WindowEvent evt) { +#define FOCUSUNION (mousefocus | (kbfocus << 1)) static SDL_bool firsttimeonmouse = SDL_TRUE; static SDL_bool mousefocus = SDL_TRUE; static SDL_bool kbfocus = SDL_TRUE; @@ -782,6 +814,8 @@ static void Impl_HandleWindowEvent(SDL_WindowEvent evt) static SDL_bool windowmoved = SDL_FALSE; #endif + const unsigned int oldfocus = FOCUSUNION; + switch (evt.event) { case SDL_WINDOWEVENT_ENTER: @@ -807,6 +841,18 @@ static void Impl_HandleWindowEvent(SDL_WindowEvent evt) #endif } + if (FOCUSUNION == oldfocus) // No state change + { + return; + } + +#ifdef USE_FBO_OGL + if (windowmoved && rendermode == render_opengl) + { + I_DownSample(); + } +#endif + if (mousefocus && kbfocus) { // Tell game we got focus back, resume music if necessary @@ -843,13 +889,7 @@ static void Impl_HandleWindowEvent(SDL_WindowEvent evt) SDLdoUngrabMouse(); } } - -#ifdef USE_FBO_OGL - if (windowmoved && rendermode == render_opengl) - { - I_DownSample(); - } -#endif +#undef FOCUSUNION } static void Impl_HandleKeyboardEvent(SDL_KeyboardEvent evt, Uint32 type) @@ -1928,11 +1968,6 @@ INT32 VID_SetMode(INT32 modeNum) } //Impl_SetWindowName("SRB2Kart "VERSIONSTRING); -#ifdef USE_FBO_OGL - if (rendermode == render_opengl) - I_DownSample(); -#endif - SDLSetMode(vid.width, vid.height, USE_FULLSCREEN); Impl_VideoSetupBuffer(); @@ -1953,6 +1988,63 @@ INT32 VID_SetMode(INT32 modeNum) return SDL_TRUE; } + +static SDL_bool Impl_CreateContext(void) +{ + // Renderer-specific stuff +#ifdef HWRENDER + if ((rendermode == render_opengl) + && (vid.glstate != VID_GL_LIBRARY_ERROR)) + { + if (!sdlglcontext) + sdlglcontext = SDL_GL_CreateContext(window); + if (sdlglcontext == NULL) + { + SDL_DestroyWindow(window); + I_Error("Failed to create a GL context: %s\n", SDL_GetError()); + } + SDL_GL_MakeCurrent(window, sdlglcontext); + } + else +#endif + if (rendermode == render_soft) + { + int flags = 0; // Use this to set SDL_RENDERER_* flags now + if (usesdl2soft) + flags |= SDL_RENDERER_SOFTWARE; + else if (cv_vidwait.value) + { +#if SDL_VERSION_ATLEAST(2, 0, 18) + // If SDL is new enough, we can turn off vsync later. + flags |= SDL_RENDERER_PRESENTVSYNC; +#else + // However, if it isn't, we should just silently turn vid_wait off + // This is because the renderer will be created before the config + // is read and vid_wait is set from the user's preferences, and thus + // vid_wait will have no effect. + CV_StealthSetValue(&cv_vidwait, 0); +#endif + } + +#ifdef _WIN32 + SDL_SetHint(SDL_HINT_RENDER_DRIVER, "direct3d11"); +#else + SDL_SetHint(SDL_HINT_RENDER_DRIVER, "opengl"); +#endif + + if (!renderer) + renderer = SDL_CreateRenderer(window, -1, flags); + if (renderer == NULL) + { + CONS_Printf(M_GetText("Couldn't create rendering context: %s\n"), SDL_GetError()); + return SDL_FALSE; + } + SDL_RenderSetLogicalSize(renderer, BASEVIDWIDTH, BASEVIDHEIGHT); + } + + return SDL_TRUE; +} + static SDL_bool Impl_CreateWindow(SDL_bool fullscreen) { int flags = 0; @@ -2000,46 +2092,7 @@ static SDL_bool Impl_CreateWindow(SDL_bool fullscreen) return SDL_FALSE; } - // Renderer-specific stuff -#ifdef HWRENDER - if ((rendermode == render_opengl) - && (vid.glstate != VID_GL_LIBRARY_ERROR)) - { - sdlglcontext = SDL_GL_CreateContext(window); - if (sdlglcontext == NULL) - { - SDL_DestroyWindow(window); - I_Error("Failed to create a GL context: %s\n", SDL_GetError()); - } - SDL_GL_MakeCurrent(window, sdlglcontext); - } - else -#endif - if (rendermode == render_soft) - { - flags = 0; // Use this to set SDL_RENDERER_* flags now - if (usesdl2soft) - flags |= SDL_RENDERER_SOFTWARE; - else if (cv_vidwait.value) - flags |= SDL_RENDERER_PRESENTVSYNC; - - // 3 August 2022 - // Possibly a Windows 11 issue; the default - // "direct3d" driver (D3D9) causes Drmingw exchndl - // to not write RPT files. Every other driver - // seems fine. - SDL_SetHint(SDL_HINT_RENDER_DRIVER, "direct3d11"); - - renderer = SDL_CreateRenderer(window, -1, flags); - if (renderer == NULL) - { - CONS_Printf(M_GetText("Couldn't create rendering context: %s\n"), SDL_GetError()); - return SDL_FALSE; - } - SDL_RenderSetLogicalSize(renderer, BASEVIDWIDTH, BASEVIDHEIGHT); - } - - return SDL_TRUE; + return Impl_CreateContext(); } /* @@ -2452,5 +2505,11 @@ static void Impl_SetVsync(void) if (renderer) SDL_RenderSetVSync(renderer, cv_vidwait.value); #endif +#ifdef HWRENDER + if (!renderer && rendermode == render_opengl && sdlglcontext != NULL && SDL_GL_GetCurrentContext() == sdlglcontext) + { + SDL_GL_SetSwapInterval(cv_vidwait.value ? 1 : 0); + } +#endif } #endif diff --git a/src/sdl/mixer_sound.c b/src/sdl/mixer_sound.c index aef996772..12abb7c65 100644 --- a/src/sdl/mixer_sound.c +++ b/src/sdl/mixer_sound.c @@ -93,8 +93,6 @@ static UINT16 SAMPLERATE = 44100; /// ------------------------ UINT8 sound_started = false; - -static UINT32 stutter_threshold_user; static UINT32 stutter_threshold; static Mix_Music *music; @@ -626,9 +624,10 @@ static void count_music_bytes(int chan, void *stream, int len, void *udata) if (!music || I_SongType() == MU_GME || I_SongType() == MU_MOD || I_SongType() == MU_MID) return; + music_bytes += len; - if ((gamestate == GS_LEVEL) && (cv_birdmusic.value)) + if (cv_birdmusic.value && gamestate == GS_LEVEL) Countstutter(len); } @@ -1042,20 +1041,12 @@ UINT32 I_GetSongPosition(void) // 8M: 1 | 8S: 2 | 16M: 2 | 16S: 4 } -void -I_UpdateSongLagThreshold (void) +void I_UpdateSongLagThreshold (void) { - stutter_threshold_user = cv_music_resync_threshold.value/1000.0*(4*44100); - I_UpdateSongLagConditions(); -} + if (!cv_birdmusic.value) + return; -void -I_UpdateSongLagConditions (void) -{ - if (! cv_music_resync_powerups_only.value || S_MusicUsage() == MUS_SPECIAL) - stutter_threshold = stutter_threshold_user; - else - stutter_threshold = 0; + stutter_threshold = cv_music_resync_threshold.value/1000.0*(4*44100); } /// ------------------------ @@ -1115,6 +1106,7 @@ boolean I_LoadSong(char *data, size_t len) if (!gme_open_data(inflatedData, inflatedLen, &gme, SAMPLERATE)) { Z_Free(inflatedData); // GME supposedly makes a copy for itself, so we don't need this lying around + inflateEnd(&stream); return true; } } diff --git a/src/sdl/ogl_sdl.c b/src/sdl/ogl_sdl.c index 5bb6b7347..4adc3dae8 100644 --- a/src/sdl/ogl_sdl.c +++ b/src/sdl/ogl_sdl.c @@ -68,6 +68,12 @@ PFNglGetIntegerv pglGetIntegerv; PFNglGetString pglGetString; #endif +#if defined (__unix__) +#ifdef USE_FBO_OGL +static boolean isnvidiagpu = false; +#endif +#endif + /** \brief SDL video display surface */ INT32 oglflags = 0; @@ -166,8 +172,12 @@ boolean OglSdlSurface(INT32 w, INT32 h) maximumAnisotropy = 1; granisotropicmode_cons_t[1].value = maximumAnisotropy; + +#if defined (__unix__) #ifdef USE_FBO_OGL - I_DownSample(); + if (strstr((const char*)gl_renderer, "NVIDIA")) + isnvidiagpu = true; +#endif #endif } first_init = true; @@ -178,6 +188,7 @@ boolean OglSdlSurface(INT32 w, INT32 h) if (screen_width != w || screen_height != h) { FlushScreenTextures(); + #ifdef USE_FBO_OGL GLFramebuffer_DeleteAttachments(); #endif @@ -191,11 +202,16 @@ boolean OglSdlSurface(INT32 w, INT32 h) pglClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT); #ifdef USE_FBO_OGL - RenderToFramebuffer = FrameBufferEnabled; - GLFramebuffer_Disable(); + RenderToFramebuffer = ((FrameBufferEnabled && supportFBO && downsample) +#if defined (__unix__) + || (isnvidiagpu && xwaylandcrap) +#endif + ); - if (RenderToFramebuffer && downsample) + if (RenderToFramebuffer) GLFramebuffer_Enable(); + else + GLFramebuffer_Disable(); #endif HWR_Startup(); @@ -225,14 +241,20 @@ void OglSdlFinishUpdate(boolean waitvbl) HWR_MakeScreenFinalTexture(); #ifdef USE_FBO_OGL - GLFramebuffer_Disable(); - RenderToFramebuffer = FrameBufferEnabled; + RenderToFramebuffer = ((FrameBufferEnabled && supportFBO && downsample) +#if defined (__unix__) + || (isnvidiagpu && xwaylandcrap) +#endif + ); + + if (RenderToFramebuffer) + GLFramebuffer_Unbind(); #endif HWR_DrawScreenFinalTexture(sdlw, sdlh); #ifdef USE_FBO_OGL - if (RenderToFramebuffer && downsample) + if (RenderToFramebuffer) GLFramebuffer_Enable(); #endif diff --git a/src/sdl/sdl_sound.c b/src/sdl/sdl_sound.c index 503e7205a..33714f32a 100644 --- a/src/sdl/sdl_sound.c +++ b/src/sdl/sdl_sound.c @@ -1410,7 +1410,6 @@ UINT32 I_GetSongPosition(void) } void I_UpdateSongLagThreshold (void) {} -void I_UpdateSongLagConditions (void) {} /// ------------------------ // MUSIC PLAYBACK diff --git a/src/st_stuff.c b/src/st_stuff.c index 2ecfd73d5..983ce4007 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -28,6 +28,9 @@ #include "m_menu.h" #include "m_cheat.h" #include "p_setup.h" // NiGHTS grading + +#include "i_time.h" + #include "k_kart.h" // SRB2kart //random index @@ -56,17 +59,17 @@ patch_t *facerankprefix[MAXSKINS]; // ranking patch_t *facewantprefix[MAXSKINS]; // wanted patch_t *facemmapprefix[MAXSKINS]; // minimap -patch_t *localfacerankprefix[MAXSKINS]; // ranking -patch_t *localfacewantprefix[MAXSKINS]; // wanted -patch_t *localfacemmapprefix[MAXSKINS]; // minimap +patch_t *localfacerankprefix[MAXLOCALSKINS]; // ranking +patch_t *localfacewantprefix[MAXLOCALSKINS]; // wanted +patch_t *localfacemmapprefix[MAXLOCALSKINS]; // minimap -char *facerankprefix_name[MAXSKINS]; // ranking +/*char *facerankprefix_name[MAXSKINS]; // ranking char *facewantprefix_name[MAXSKINS]; // wanted char *facemmapprefix_name[MAXSKINS]; // minimap -char *localfacerankprefix_name[MAXSKINS]; // ranking -char *localfacewantprefix_name[MAXSKINS]; // wanted -char *localfacemmapprefix_name[MAXSKINS]; // minimap +char *localfacerankprefix_name[MAXLOCALSKINS]; // ranking +char *localfacewantprefix_name[MAXLOCALSKINS]; // wanted +char *localfacemmapprefix_name[MAXLOCALSKINS]; // minimap*/ // ------------------------------------------ // status bar overlay @@ -193,7 +196,7 @@ hudinfo_t hudinfo[NUMHUDITEMS] = { 240, 160}, // HUD_LAP }; -static huddrawlist_h luahuddrawlist_game; +static huddrawlist_h luahuddrawlist_game[MAXSPLITSCREENPLAYERS]; // variable to stop mayonaka static from flickering consvar_t cv_lessflicker = {"lessflicker", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; @@ -395,9 +398,9 @@ void ST_LoadFaceGraphics(char *rankstr, char *wantstr, char *mmapstr, INT32 skin facewantprefix[skinnum] = W_CachePatchName(wantstr, PU_HUDGFX); facemmapprefix[skinnum] = W_CachePatchName(mmapstr, PU_HUDGFX); - facerankprefix_name[skinnum] = rankstr; + /*facerankprefix_name[skinnum] = rankstr; facewantprefix_name[skinnum] = wantstr; - facemmapprefix_name[skinnum] = mmapstr; + facemmapprefix_name[skinnum] = mmapstr;*/ } void ST_LoadLocalFaceGraphics(char *rankstr, char *wantstr, char *mmapstr, INT32 skinnum) @@ -406,9 +409,9 @@ void ST_LoadLocalFaceGraphics(char *rankstr, char *wantstr, char *mmapstr, INT32 localfacewantprefix[skinnum] = W_CachePatchName(wantstr, PU_HUDGFX); localfacemmapprefix[skinnum] = W_CachePatchName(mmapstr, PU_HUDGFX); - localfacerankprefix_name[skinnum] = rankstr; + /*localfacerankprefix_name[skinnum] = rankstr; localfacewantprefix_name[skinnum] = wantstr; - localfacemmapprefix_name[skinnum] = mmapstr; + localfacemmapprefix_name[skinnum] = mmapstr;*/ //CONS_Printf("Added rank prefix %s\n", rankstr); //CONS_Printf("Added want prefix %s\n", wantstr); @@ -456,7 +459,9 @@ void ST_Start(void) ST_Stop(); ST_InitData(); - st_stopped = false; + + if (!dedicated) + st_stopped = false; } // @@ -473,7 +478,8 @@ void ST_Init(void) ST_LoadGraphics(); - luahuddrawlist_game = LUA_HUD_CreateDrawList(); + for (int i = 0; i < MAXSPLITSCREENPLAYERS; i++) + luahuddrawlist_game[i] = LUA_HUD_CreateDrawList(); } // change the status bar too, when pressing F12 while viewing a demo. @@ -525,17 +531,7 @@ static void ST_drawDebugInfo(void) if (cv_debug & DBG_DETAILED) { - //V_DrawRightAlignedString(320, height - 104, V_MONOSPACE, va("SHIELD: %5x", stplyr->powers[pw_shield])); V_DrawRightAlignedString(320, height - 96, V_MONOSPACE, va("SCALE: %5d%%", (stplyr->mo->scale*100)/FRACUNIT)); - //V_DrawRightAlignedString(320, height - 88, V_MONOSPACE, va("DASH: %3d/%3d", stplyr->dashspeed>>FRACBITS, FixedMul(stplyr->maxdash,stplyr->mo->scale)>>FRACBITS)); - //V_DrawRightAlignedString(320, height - 80, V_MONOSPACE, va("AIR: %4d, %3d", stplyr->powers[pw_underwater], stplyr->powers[pw_spacetime])); - - // Flags - //V_DrawRightAlignedString(304-64, height - 72, V_MONOSPACE, "Flags:"); - //V_DrawString(304-60, height - 72, (stplyr->jumping) ? V_GREENMAP : V_REDMAP, "JM"); - //V_DrawString(304-40, height - 72, (stplyr->pflags & PF_JUMPED) ? V_GREENMAP : V_REDMAP, "JD"); - //V_DrawString(304-20, height - 72, (stplyr->pflags & PF_SPINNING) ? V_GREENMAP : V_REDMAP, "SP"); - //V_DrawString(304, height - 72, (stplyr->pflags & PF_STARTDASH) ? V_GREENMAP : V_REDMAP, "ST"); V_DrawRightAlignedString(320, height - 64, V_MONOSPACE, va("CEILZ: %6d", stplyr->mo->ceilingz>>FRACBITS)); V_DrawRightAlignedString(320, height - 56, V_MONOSPACE, va("FLOORZ: %6d", stplyr->mo->floorz>>FRACBITS)); @@ -569,132 +565,6 @@ static void ST_drawDebugInfo(void) V_DrawRightAlignedString(320, height, V_MONOSPACE, va("Heap used: %7sKB", sizeu1(Z_TagsUsage(0, INT32_MAX)>>10))); } -/* -static void ST_drawScore(void) -{ - // SCORE: - ST_DrawPatchFromHud(HUD_SCORE, sboscore); - if (objectplacing) - { - if (op_displayflags > UINT16_MAX) - ST_DrawOverlayPatch(SCX(hudinfo[HUD_SCORENUM].x-tallminus->width), SCY(hudinfo[HUD_SCORENUM].y), tallminus); - else - ST_DrawNumFromHud(HUD_SCORENUM, op_displayflags); - } - else - ST_DrawNumFromHud(HUD_SCORENUM, stplyr->score); -} -*/ - -/* -static void ST_drawTime(void) -{ - INT32 seconds, minutes, tictrn, tics; - - // TIME: - ST_DrawPatchFromHudWS(HUD_TIME, sbotime); - - if (objectplacing) - { - tics = objectsdrawn; - seconds = objectsdrawn%100; - minutes = objectsdrawn/100; - tictrn = 0; - } - else - { - tics = stplyr->realtime; - seconds = G_TicsToSeconds(tics); - minutes = G_TicsToMinutes(tics, true); - tictrn = G_TicsToCentiseconds(tics); - } - - if (cv_timetic.value == 1) // Tics only -- how simple is this? - ST_DrawNumFromHudWS(HUD_SECONDS, tics); - else - { - ST_DrawNumFromHudWS(HUD_MINUTES, minutes); // Minutes - ST_DrawPatchFromHudWS(HUD_TIMECOLON, sbocolon); // Colon - ST_DrawPadNumFromHudWS(HUD_SECONDS, seconds, 2); // Seconds - - if (!splitscreen && (cv_timetic.value == 2 || modeattacking)) // there's not enough room for tics in splitscreen, don't even bother trying! - { - ST_DrawPatchFromHud(HUD_TIMETICCOLON, sboperiod); // Period - ST_DrawPadNumFromHud(HUD_TICS, tictrn, 2); // Tics - } - } -} -*/ - -/* -static inline void ST_drawRings(void) // SRB2kart - unused. -{ - INT32 ringnum = max(stplyr->health-1, 0); - - ST_DrawPatchFromHudWS(HUD_RINGS, ((stplyr->health <= 1 && leveltime/5 & 1) ? rrings : sborings)); - - if (objectplacing) - ringnum = op_currentdoomednum; - else if (!useNightsSS && G_IsSpecialStage(gamemap)) - { - INT32 i; - ringnum = 0; - for (i = 0; i < MAXPLAYERS; i++) - if (playeringame[i] && players[i].mo && players[i].mo->health > 1) - ringnum += players[i].mo->health - 1; - } - - ST_DrawNumFromHudWS(HUD_RINGSNUM, ringnum); -} -*/ - -/* -static void ST_drawLives(void) // SRB2kart - unused. -{ - const INT32 v_splitflag = (splitscreen && stplyr == &players[displayplayers[0]] ? V_SPLITSCREEN : 0); - - if (!stplyr->skincolor) - return; // Just joined a server, skin isn't loaded yet! - - // face background - V_DrawSmallScaledPatch(hudinfo[HUD_LIVESPIC].x, hudinfo[HUD_LIVESPIC].y + (v_splitflag ? -12 : 0), - V_SNAPTOLEFT|V_SNAPTOBOTTOM|V_HUDTRANS|v_splitflag, livesback); - - // face - if (stplyr->mo && stplyr->mo->color) - { - // skincolor face/super - UINT8 *colormap = R_GetTranslationColormap(stplyr->skin, stplyr->mo->color, GTC_CACHE); - patch_t *face = facerankprefix[stplyr->skin]; - if (stplyr->powers[pw_super] || stplyr->pflags & PF_NIGHTSMODE) - face = facewantprefix[stplyr->skin]; - V_DrawSmallMappedPatch(hudinfo[HUD_LIVESPIC].x, hudinfo[HUD_LIVESPIC].y + (v_splitflag ? -12 : 0), - V_SNAPTOLEFT|V_SNAPTOBOTTOM|V_HUDTRANS|v_splitflag,face, colormap); - } - else if (stplyr->skincolor) - { - // skincolor face - UINT8 *colormap = R_GetTranslationColormap(stplyr->skin, stplyr->skincolor, GTC_CACHE); - V_DrawSmallMappedPatch(hudinfo[HUD_LIVESPIC].x, hudinfo[HUD_LIVESPIC].y + (v_splitflag ? -12 : 0), - V_SNAPTOLEFT|V_SNAPTOBOTTOM|V_HUDTRANS|v_splitflag,facerankprefix[stplyr->skin], colormap); - } - - // name - if (strlen(skins[stplyr->skin].hudname) > 8) - V_DrawThinString(hudinfo[HUD_LIVESNAME].x, hudinfo[HUD_LIVESNAME].y + (v_splitflag ? -12 : 0), - V_HUDTRANS|V_SNAPTOLEFT|V_SNAPTOBOTTOM|V_MONOSPACE|V_YELLOWMAP|v_splitflag, skins[stplyr->skin].hudname); - else - V_DrawString(hudinfo[HUD_LIVESNAME].x, hudinfo[HUD_LIVESNAME].y + (v_splitflag ? -12 : 0), - V_HUDTRANS|V_SNAPTOLEFT|V_SNAPTOBOTTOM|V_MONOSPACE|V_YELLOWMAP|v_splitflag, skins[stplyr->skin].hudname); - // x - V_DrawScaledPatch(hudinfo[HUD_LIVESX].x, hudinfo[HUD_LIVESX].y + (v_splitflag ? -4 : 0), - V_SNAPTOLEFT|V_SNAPTOBOTTOM|V_HUDTRANS|v_splitflag, stlivex); - // lives - V_DrawRightAlignedString(hudinfo[HUD_LIVESNUM].x, hudinfo[HUD_LIVESNUM].y + (v_splitflag ? -4 : 0), - V_SNAPTOLEFT|V_SNAPTOBOTTOM|V_HUDTRANS|v_splitflag, va("%d",stplyr->lives)); -} -*/ - static void ST_drawLevelTitle(void) { char *lvlttl = mapheaderinfo[gamemap-1]->lvlttl; @@ -792,8 +662,23 @@ static void ST_overlayDrawer(void) if (!hu_showscores) // hide the following if TAB is held { - // Countdown timer for Race Mode - // ...moved to k_kart.c so we can take advantage of the LAPS_Y value + if (cv_showdirectorhud.value && ((demo.playback && (!demo.title || !modeattacking)) || !P_IsLocalPlayer(stplyr)) && !splitscreen) + { + char directortext[20] = {0}; + + snprintf(directortext, 20, "Director: %s", cv_director.value ? "On" : "Off"); + + if (directortoggletimer < 4*TICRATE) + { + V_DrawString(1, BASEVIDHEIGHT-8-1, V_SNAPTOLEFT|V_SNAPTOBOTTOM|V_HUDTRANSHALF|V_ALLOWLOWERCASE, directortext); + if (renderisnewtic) + directortoggletimer++; + } + else if (cv_translucenthud.value != 0) + V_DrawString(1, BASEVIDHEIGHT-8-1, V_SNAPTOLEFT|V_SNAPTOBOTTOM|V_80TRANS|V_ALLOWLOWERCASE, directortext); // idk if V_80TRANS is good? + } + else + directortoggletimer = 0; if (cv_showviewpointtext.value) { @@ -831,27 +716,18 @@ static void ST_overlayDrawer(void) } } } - - // This is where we draw all the fun cheese if you have the chasecam off! - /*if ((stplyr == &players[displayplayers[0]] && !camera[0].chase) - || ((splitscreen && stplyr == &players[displayplayers[1]]) && !camera[1].chase) - || ((splitscreen > 1 && stplyr == &players[displayplayers[2]]) && !camera[2].chase) - || ((splitscreen > 2 && stplyr == &players[displayplayers[3]]) && !camera[3].chase)) - { - ST_drawFirstPersonHUD(); - }*/ } - if (!(netgame || multiplayer) || !hu_showscores) + if ((!(netgame || multiplayer) || !hu_showscores) && !forceshowhud) { if (renderisnewtic) { - LUAh_GameHUD(stplyr, luahuddrawlist_game); + LUAh_GameHUD(luahuddrawlist_game[stplyrnum]); } } // draw level title Tails - if (*mapheaderinfo[gamemap-1]->lvlttl != '\0' && !(hu_showscores && (netgame || multiplayer) && !mapreset) && LUA_HudEnabled(hud_stagetitle)) + if (*mapheaderinfo[gamemap-1]->lvlttl != '\0' && !(hu_showscores && (netgame || multiplayer) && !mapreset) && LUA_HudEnabled(hud_stagetitle) && !forceshowhud) ST_drawLevelTitle(); if (!hu_showscores && netgame && !mapreset) @@ -1024,7 +900,8 @@ void ST_Drawer(void) { if (renderisnewtic) { - LUA_HUD_ClearDrawList(luahuddrawlist_game); + for (i = 0; i <= splitscreen; i++) + LUA_HUD_ClearDrawList(luahuddrawlist_game[i]); } // No deadview! @@ -1035,7 +912,8 @@ void ST_Drawer(void) ST_overlayDrawer(); } - LUA_HUD_DrawList(luahuddrawlist_game); + for (i = 0; i <= splitscreen; i++) + LUA_HUD_DrawList(luahuddrawlist_game[i]); // draw Midnight Channel's overlay ontop if (mapheaderinfo[gamemap-1]->typeoflevel & TOL_TV) // Very specific Midnight Channel stuff. diff --git a/src/st_stuff.h b/src/st_stuff.h index 46fcc4d67..250db1e7f 100644 --- a/src/st_stuff.h +++ b/src/st_stuff.h @@ -78,15 +78,15 @@ extern patch_t *sboperiod; extern patch_t *facerankprefix[MAXSKINS]; // ranking extern patch_t *facewantprefix[MAXSKINS]; // wanted extern patch_t *facemmapprefix[MAXSKINS]; // minimap -extern patch_t *localfacerankprefix[MAXSKINS]; // ranking -extern patch_t *localfacewantprefix[MAXSKINS]; // wanted -extern patch_t *localfacemmapprefix[MAXSKINS]; // minimap -extern char *facerankprefix_name[MAXSKINS]; // ranking +extern patch_t *localfacerankprefix[MAXLOCALSKINS]; // ranking +extern patch_t *localfacewantprefix[MAXLOCALSKINS]; // wanted +extern patch_t *localfacemmapprefix[MAXLOCALSKINS]; // minimap +/*extern char *facerankprefix_name[MAXSKINS]; // ranking extern char *facewantprefix_name[MAXSKINS]; // wanted extern char *facemmapprefix_name[MAXSKINS]; // minimap -extern char *localfacerankprefix_name[MAXSKINS]; // ranking -extern char *localfacewantprefix_name[MAXSKINS]; // wanted -extern char *localfacemmapprefix_name[MAXSKINS]; // minimap +extern char *localfacerankprefix_name[MAXLOCALSKINS]; // ranking +extern char *localfacewantprefix_name[MAXLOCALSKINS]; // wanted +extern char *localfacemmapprefix_name[MAXLOCALSKINS]; // minimap*/ extern patch_t *livesback; extern patch_t *ngradeletters[7]; diff --git a/src/tables.h b/src/tables.h index 761a6499e..f643895a5 100644 --- a/src/tables.h +++ b/src/tables.h @@ -86,7 +86,7 @@ extern angle_t tantoangle[SLOPERANGE+1]; // Utility function, called by R_PointToAngle. FUNCMATH unsigned SlopeDiv(unsigned num, unsigned den); -// Only called by R_PointToAngleEx +// Only called by R_PointToAngle64 FUNCMATH UINT64 SlopeDivEx(unsigned int num, unsigned int den); // 360 - angle_t(ANGLE_45) = ANGLE_315 @@ -94,6 +94,12 @@ FUNCMATH FUNCINLINE static ATTRINLINE angle_t InvAngle(angle_t a) { return (ANGLE_MAX-a)+1; } + +// 315 = 45 +FUNCMATH FUNCINLINE static ATTRINLINE angle_t AbsAngle(angle_t a) +{ + return a & ANGLE_180 ? InvAngle(a) : a; +} // angle_t to fixed_t f(ANGLE_45) = 45*FRACUNIT FUNCMATH fixed_t AngleFixed(angle_t af); // fixed_t to angle_t f(45*FRACUNIT) = ANGLE_45 diff --git a/src/v_video.c b/src/v_video.c index 4ea028cc3..202b5d288 100644 --- a/src/v_video.c +++ b/src/v_video.c @@ -14,7 +14,9 @@ /// Functions to blit a block to the screen. #include "doomdef.h" +#include "d_main.h" #include "r_local.h" +#include "p_local.h" #include "v_video.h" #include "hu_stuff.h" #include "r_draw.h" @@ -131,6 +133,9 @@ static boolean InitCube(void) float globalgammamul, globalgammaoffs; boolean doinggamma; + if (loaded_config == false) + return false; + #define diffcons(cv) (cv.value != atoi(cv.defaultvalue)) doinggamma = diffcons(cv_globalgamma); @@ -567,6 +572,8 @@ void V_SetPaletteLump(const char *pal) static void CV_palette_OnChange(void) { + if (loaded_config == false) + return; // reload palette LoadMapPalette(); V_SetPalette(0); @@ -3135,7 +3142,7 @@ INT32 heatindex[MAXSPLITSCREENPLAYERS] = {0, 0, 0, 0}; // // Perform a particular image postprocessing function. // -#include "p_local.h" + void V_DoPostProcessor(INT32 view, postimg_t type, INT32 param) { #if NUMSCREENS < 5 @@ -3203,8 +3210,8 @@ void V_DoPostProcessor(INT32 view, postimg_t type, INT32 param) } } -/* -Unoptimized version + /* + Unoptimized version for (x = 0; x < vid.width*vid.bpp; x++) { newpix = (x + sine); @@ -3314,6 +3321,19 @@ Unoptimized version tmpscr[y*vid.width + x2] = srcscr[y*vid.width + x]; } + VID_BlitLinearScreen(tmpscr+vid.width*vid.bpp*yoffset+xoffset, screens[0]+vid.width*vid.bpp*yoffset+xoffset, + viewwidth*vid.bpp, viewheight, vid.width*vid.bpp, vid.width); + } + else if (type == postimg_mirrorflip) // Flip the screen upside-down and on the x axis + { + UINT8 *tmpscr = screens[4]; + UINT8 *srcscr = screens[0]; + INT32 y, x; + + for (y = yoffset; y < yoffset + viewheight; y++) + for (x = xoffset; x < xoffset + viewwidth; x++) + tmpscr[((yoffset + viewheight - 1 - y) * vid.width) + xoffset + viewwidth - (x - xoffset) - 1] = srcscr[(y * vid.width) + x]; + VID_BlitLinearScreen(tmpscr+vid.width*vid.bpp*yoffset+xoffset, screens[0]+vid.width*vid.bpp*yoffset+xoffset, viewwidth*vid.bpp, viewheight, vid.width*vid.bpp, vid.width); } diff --git a/src/w_wad.c b/src/w_wad.c index cd2968494..5e2f4ce10 100644 --- a/src/w_wad.c +++ b/src/w_wad.c @@ -62,9 +62,6 @@ #include "md5.h" #include "lua_script.h" #include "st_stuff.h" -#ifdef SCANTHINGS -#include "p_setup.h" // P_ScanThings -#endif #include "m_misc.h" // M_MapNumber #include "p_setup.h" // P_PartialAddFile mayb @@ -117,7 +114,8 @@ void W_Shutdown(void) if (wad->handle) fclose(wad->handle); Z_Free(wad->filename); - while (wad->numlumps--) { + while (wad->numlumps--) + { Z_Free(wad->lumpinfo[wad->numlumps].longname); Z_Free(wad->lumpinfo[wad->numlumps].fullname); } @@ -183,8 +181,11 @@ FILE *W_OpenWadFile(const char **filename, boolean useerrors) { FILE *handle; - if (filenamebuf != *filename) { - // avoid overlap + // Officially, strncpy should not have overlapping buffers, since W_VerifyNMUSlumps is called after this, and it + // changes filename to point at filenamebuf, it would technically be doing that. I doubt any issue will occur since + // they point to the same location, but it's better to be safe and this is a simple change. + if (filenamebuf != *filename) + { strncpy(filenamebuf, *filename, MAX_WADPATH); filenamebuf[MAX_WADPATH - 1] = '\0'; *filename = filenamebuf; @@ -287,22 +288,6 @@ static inline void W_LoadDehackedLumps(UINT16 wadnum) DEH_LoadDehackedLumpPwad(wadnum, lump); } } - -#ifdef SCANTHINGS - // Scan maps for emblems 'n shit - { - lumpinfo_t *lump_p = wadfiles[wadnum]->lumpinfo; - for (lump = 0; lump < wadfiles[wadnum]->numlumps; lump++, lump_p++) - { - const char *name = lump_p->name; - if (name[0] == 'M' && name[1] == 'A' && name[2] == 'P' && name[5]=='\0') - { - INT16 mapnum = (INT16)M_MapNumber(name[3], name[4]); - P_ScanThings(mapnum, wadnum, lump + ML_THINGS); - } - } - } -#endif } /** Compute MD5 message digest for bytes read from STREAM of this filname. @@ -482,27 +467,53 @@ static lumpinfo_t* ResGetLumpsWad (FILE* handle, UINT16* nlmp, const char* filen */ static boolean ResFindSignature (FILE* handle, char endPat[], UINT32 startpos) { + //the Wii U has rather slow filesystem access, and fgetc is *unbearable* + //so I reimplemented this function to buffer 128k chunks char *s; int c; + fseek(handle, 0, SEEK_END); + size_t len = ftell(handle); + fseek(handle, startpos, SEEK_SET); + size_t remaining = len - startpos; + size_t chunkpos = startpos; + s = endPat; - while((c = fgetc(handle)) != EOF) - { - if (*s != c && s > endPat) // No match? - s = endPat; // We "reset" the counter by sending the s pointer back to the start of the array. - if (*s == c) - { - s++; - if (*s == 0x00) // The array pointer has reached the key char which marks the end. It means we have matched the signature. + + //128k buffers + size_t buffer_size = min(128 * 1024 * sizeof(char), remaining); + char* buffer = (char*)(malloc(buffer_size)); + + size_t bytes_read = 0; + while ((bytes_read = fread(buffer, 1, buffer_size, handle)) > 0) { + for (size_t i = 0; i < bytes_read; i++) { + c = (int)buffer[i]; + + if (*s != c && s > endPat) // No match? + s = endPat; // We "reset" the counter by sending the s pointer back to the start of the array. + if (*s == c) { - return true; + s++; + if (*s == 0x00) // The array pointer has reached the key char which marks the end. It means we have matched the signature. + { + //the original function would leave the FILE* seeked to the end of the match + size_t foundpos = chunkpos + i + 1; + fseek(handle, foundpos, SEEK_SET); + + free(buffer); + return true; + } } } + chunkpos += bytes_read; } + + free(buffer); return false; } + #if defined(_MSC_VER) #pragma pack(1) #endif @@ -562,7 +573,6 @@ typedef struct zlentry_s static lumpinfo_t* ResGetLumpsZip (FILE* handle, UINT16* nlmp) { zend_t zend; - zentry_t zentry; zlentry_t zlentry; UINT16 numlumps = *nlmp; @@ -588,42 +598,45 @@ static lumpinfo_t* ResGetLumpsZip (FILE* handle, UINT16* nlmp) CONS_Alert(CONS_ERROR, "Corrupt central directory (%s)\n", M_FileError(handle)); return NULL; } - numlumps = zend.entries; + numlumps = SHORT(zend.entries); lump_p = lumpinfo = Z_Malloc(numlumps * sizeof (*lumpinfo), PU_STATIC, NULL); - fseek(handle, zend.cdiroffset, SEEK_SET); + fseek(handle, LONG(zend.cdiroffset), SEEK_SET); + + char *cdir = (Z_MallocAlign(LONG(zend.cdirsize), PU_STATIC, &cdir, 7)); + + if (fread(cdir, 1, LONG(zend.cdirsize), handle) < (UINT32)(LONG(zend.cdirsize))) + { + CONS_Alert(CONS_ERROR, "Failed to read central directory (%s)\n", M_FileError(handle)); + Z_Free(cdir); + Z_Free(lumpinfo); + return NULL; + } + + size_t offset = 0; + for (i = 0; i < numlumps; i++, lump_p++) { + zentry_t *zentry = (zentry_t*)(cdir + offset); char* fullname; char* trimname; char* dotpos; - if (fread(&zentry, 1, sizeof(zentry_t), handle) < sizeof(zentry_t)) - { - CONS_Alert(CONS_ERROR, "Failed to read central directory (%s)\n", M_FileError(handle)); - Z_Free(lumpinfo); - return NULL; - } - if (memcmp(zentry.signature, pat_central, 4)) + if (memcmp(zentry->signature, pat_central, 4)) { CONS_Alert(CONS_ERROR, "Central directory is corrupt\n"); + Z_Free(cdir); Z_Free(lumpinfo); return NULL; } - lump_p->position = zentry.offset; // NOT ACCURATE YET: we still need to read the local entry to find our true position - lump_p->disksize = zentry.compsize; - lump_p->size = zentry.size; + lump_p->position = LONG(zentry->offset); // NOT ACCURATE YET: we still need to read the local entry to find our true position + lump_p->disksize = LONG(zentry->compsize); + lump_p->size = LONG(zentry->size); - fullname = malloc(zentry.namelen + 1); - if (fgets(fullname, zentry.namelen + 1, handle) != fullname) - { - CONS_Alert(CONS_ERROR, "Unable to read lumpname (%s)\n", M_FileError(handle)); - Z_Free(lumpinfo); - free(fullname); - return NULL; - } + fullname = (char*)(malloc(SHORT(zentry->namelen) + 1)); + strlcpy(fullname, (char*)(zentry + 1), SHORT(zentry->namelen) + 1); // Strip away file address and extension for the 8char name. if ((trimname = strrchr(fullname, '/')) != 0) @@ -640,10 +653,10 @@ static lumpinfo_t* ResGetLumpsZip (FILE* handle, UINT16* nlmp) lump_p->longname = Z_Calloc(dotpos - trimname + 1, PU_STATIC, NULL); strlcpy(lump_p->longname, trimname, dotpos - trimname + 1); - lump_p->fullname = Z_Calloc(zentry.namelen + 1, PU_STATIC, NULL); - strncpy(lump_p->fullname, fullname, zentry.namelen); + lump_p->fullname = (char*)(Z_Calloc(SHORT(zentry->namelen) + 1, PU_STATIC, NULL)); + strncpy(lump_p->fullname, fullname, SHORT(zentry->namelen)); - switch(zentry.compression) + switch(SHORT(zentry->compression)) { case 0: lump_p->compression = CM_NOCOMPRESSION; @@ -664,14 +677,11 @@ static lumpinfo_t* ResGetLumpsZip (FILE* handle, UINT16* nlmp) free(fullname); // skip and ignore comments/extra fields - if (fseek(handle, zentry.xtralen + zentry.commlen, SEEK_CUR) != 0) - { - CONS_Alert(CONS_ERROR, "Central directory is corrupt\n"); - Z_Free(lumpinfo); - return NULL; - } + offset += sizeof *zentry + SHORT(zentry->namelen) + SHORT(zentry->xtralen) + SHORT(zentry->commlen); } + Z_Free(cdir); + // Adjust lump position values properly for (i = 0, lump_p = lumpinfo; i < numlumps; i++, lump_p++) { @@ -683,7 +693,7 @@ static lumpinfo_t* ResGetLumpsZip (FILE* handle, UINT16* nlmp) return NULL; } - lump_p->position += sizeof(zlentry_t) + zlentry.namelen + zlentry.xtralen; + lump_p->position += sizeof(zlentry_t) + SHORT(zlentry.namelen) + SHORT(zlentry.xtralen); } *nlmp = numlumps; @@ -789,7 +799,7 @@ UINT16 W_InitFile(const char *filename, boolean local) // // link wad file to search files // - wadfile = Z_Malloc(sizeof (*wadfile), PU_STATIC, NULL); + wadfile = Z_Calloc(sizeof (*wadfile), PU_STATIC, NULL); wadfile->filename = Z_StrDup(filename); wadfile->handle = handle; wadfile->numlumps = (UINT16)numlumps; @@ -798,7 +808,6 @@ UINT16 W_InitFile(const char *filename, boolean local) fseek(handle, 0, SEEK_END); wadfile->filesize = (unsigned)ftell(handle); wadfile->type = type; - wadfile->majormod = false; // already generated, just copy it over M_Memcpy(&wadfile->md5sum, &md5sum, 16); @@ -1742,7 +1751,7 @@ void W_UnlockCachedPatch(void *patch) HWR_UnlockCachedPatch((GLPatch_t*)patch); else #endif - Z_Unlock(patch); + Z_ChangeTag(patch, PU_LEVEL); } void *W_CachePatchName(const char *name, INT32 tag) @@ -1914,14 +1923,11 @@ W_VerifyPK3 (FILE *fp, lumpchecklist_t *checklist, boolean status) int verified = true; zend_t zend; - zentry_t zentry; zlentry_t zlentry; long file_size;/* size of zip file */ long data_size;/* size of data inside zip file */ - long old_position; - UINT16 numlumps; size_t i; @@ -1947,28 +1953,31 @@ W_VerifyPK3 (FILE *fp, lumpchecklist_t *checklist, boolean status) data_size = sizeof zend; - numlumps = zend.entries; + numlumps = SHORT(zend.entries); + + fseek(fp, LONG(zend.cdiroffset), SEEK_SET); + + char *cdir = (char*)(malloc(LONG(zend.cdirsize))); + + if (fread(cdir, 1, LONG(zend.cdirsize), fp) < (UINT32)(LONG(zend.cdirsize))) + return true; + + size_t offset = 0; - fseek(fp, zend.cdiroffset, SEEK_SET); for (i = 0; i < numlumps; i++) { + zentry_t *zentry = (zentry_t*)(cdir + offset); char* fullname; char* trimname; char* dotpos; - if (fread(&zentry, 1, sizeof(zentry_t), fp) < sizeof(zentry_t)) - return true; - if (memcmp(zentry.signature, pat_central, 4)) + if (memcmp(zentry->signature, pat_central, 4) != 0) return true; if (verified == true) { - fullname = malloc(zentry.namelen + 1); - if (fgets(fullname, zentry.namelen + 1, fp) != fullname) - { - free(fullname); - return true; - } + fullname = (char*)(malloc(SHORT(zentry->namelen) + 1)); + strlcpy(fullname, (char*)(zentry + 1), SHORT(zentry->namelen) + 1); // Strip away file address and extension for the 8char name. if ((trimname = strrchr(fullname, '/')) != 0) @@ -1993,34 +2002,25 @@ W_VerifyPK3 (FILE *fp, lumpchecklist_t *checklist, boolean status) } free(fullname); + } - // skip and ignore comments/extra fields - if (fseek(fp, zentry.xtralen + zentry.commlen, SEEK_CUR) != 0) - return true; - } - else - { - if (fseek(fp, zentry.namelen + zentry.xtralen + zentry.commlen, SEEK_CUR) != 0) - return true; - } + offset += sizeof *zentry + SHORT(zentry->namelen) + SHORT(zentry->xtralen) + SHORT(zentry->commlen); data_size += - sizeof zentry + zentry.namelen + zentry.xtralen + zentry.commlen; + sizeof *zentry + SHORT(zentry->namelen) + SHORT(zentry->xtralen) + SHORT(zentry->commlen); - old_position = ftell(fp); - - if (fseek(fp, zentry.offset, SEEK_SET) != 0) + if (fseek(fp, LONG(zentry->offset), SEEK_SET) != 0) return true; if (fread(&zlentry, 1, sizeof(zlentry_t), fp) < sizeof (zlentry_t)) return true; data_size += - sizeof zlentry + zlentry.namelen + zlentry.xtralen + zlentry.compsize; - - fseek(fp, old_position, SEEK_SET); + sizeof zlentry + SHORT(zlentry.namelen) + SHORT(zlentry.xtralen) + LONG(zlentry.compsize); } + free(cdir); + if (data_size < file_size) { const char * error = "ZIP file has holes (%ld extra bytes)\n"; @@ -2119,3 +2119,137 @@ int W_VerifyNMUSlumps(const char *filename) }; return W_VerifyFile(filename, NMUSlist, false); } + +/** \brief Generates a virtual resource used for level data loading. + * + * \param lumpnum_t reference + * \return Virtual resource + * + */ +virtres_t* vres_GetMap(lumpnum_t lumpnum) +{ + UINT32 i; + virtres_t* vres = NULL; + virtlump_t* vlumps = NULL; + size_t numlumps = 0; + + if (lastloadedmaplumpnum == lumpnum && curmapvirt != NULL) + { + // Avoid duplicating all our hard work. + return curmapvirt; + } + + if (W_IsLumpWad(lumpnum)) + { + UINT32 realentry; + size_t *vsizecache; + + // Remember that we're assuming that the WAD will have a specific set of lumps in a specific order. + UINT8 *wadData = W_CacheLumpNum(lumpnum, PU_LEVEL); + filelump_t *fileinfo = (filelump_t *)(wadData + LONG(((wadinfo_t *)wadData)->infotableofs)); + + i = LONG(((wadinfo_t *)wadData)->numlumps); + vsizecache = Z_Malloc(sizeof(size_t)*i, PU_LEVEL, NULL); + + for (realentry = 0; realentry < i; realentry++) + { + vsizecache[realentry] = (size_t)(LONG(((filelump_t *)(fileinfo + realentry))->size)); + + if (!vsizecache[realentry]) + continue; + + numlumps++; + } + + vlumps = Z_Malloc(sizeof(virtlump_t)*numlumps, PU_LEVEL, NULL); + + // Build the lumps, skipping over empty entries. + for (i = 0, realentry = 0; i < numlumps; realentry++) + { + if (vsizecache[realentry] == 0) + continue; + vlumps[i].size = vsizecache[realentry]; + // Play it safe with the name in this case. + memcpy(vlumps[i].name, (fileinfo + realentry)->name, 8); + vlumps[i].name[8] = '\0'; + vlumps[i].data = Z_Malloc(vlumps[i].size, PU_LEVEL, NULL); // This is memory inefficient, sorry about that. + memcpy(vlumps[i].data, wadData + LONG((fileinfo + realentry)->filepos), vlumps[i].size); + i++; + } + + Z_Free(vsizecache); + Z_Free(wadData); + } + else + { + // Count number of lumps until the end of resource OR up until next "MAPXX" lump. + lumpnum_t lumppos = lumpnum + 1; + for (i = LUMPNUM(lumppos); i < wadfiles[WADFILENUM(lumpnum)]->numlumps; i++, lumppos++, numlumps++) + { + if (memcmp(W_CheckNameForNum(lumppos), "MAP", 3) == 0 || W_LumpLength(lumppos) == 0) + { + break; + } + } + numlumps++; + + vlumps = Z_Malloc(sizeof(virtlump_t)*numlumps, PU_LEVEL, NULL); + for (i = 0; i < numlumps; i++, lumpnum++) + { + vlumps[i].size = W_LumpLength(lumpnum); + memcpy(vlumps[i].name, W_CheckNameForNum(lumpnum), 8); + vlumps[i].name[8] = '\0'; + vlumps[i].data = W_CacheLumpNum(lumpnum, PU_LEVEL); + } + } + vres = Z_Malloc(sizeof(virtres_t), PU_LEVEL, NULL); + vres->vlumps = vlumps; + vres->numlumps = numlumps; + + return vres; +} + +/** \brief Frees zone memory for a given virtual resource. + * + * \param Virtual resource + */ +void vres_Free(virtres_t* vres) +{ + if (vres == curmapvirt) + { + // No-sell multiple references. + return; + } + + while (vres->numlumps--) + Z_Free(vres->vlumps[vres->numlumps].data); + Z_Free(vres->vlumps); + Z_Free(vres); +} + +/** (Debug) Prints lumps from a virtual resource into console. + */ +/* + s *tatic void vres_Diag(const virtres_t* vres) + { + UINT32 i; + for (i = 0; i < vres->numlumps; i++) + CONS_Printf("%s\n", vres->vlumps[i].name); + } + */ + +/** \brief Finds a lump in a given virtual resource. + * + * \param Virtual resource + * \param Lump name to look for + * \return Virtual lump if found, NULL otherwise + * + */ +virtlump_t* vres_Find(const virtres_t* vres, const char* name) +{ + UINT32 i; + for (i = 0; i < vres->numlumps; i++) + if (fastcmp(name, vres->vlumps[i].name)) + return &vres->vlumps[i]; + return NULL; +} diff --git a/src/w_wad.h b/src/w_wad.h index 84ce9775e..4e84ea0e4 100644 --- a/src/w_wad.h +++ b/src/w_wad.h @@ -75,6 +75,25 @@ typedef struct compmethod compression; // lump compression method } lumpinfo_t; +// ========================================================================= +// 'VIRTUAL' RESOURCES +// ========================================================================= + +typedef struct { + char name[9]; + UINT8* data; + size_t size; +} virtlump_t; + +typedef struct { + size_t numlumps; + virtlump_t* vlumps; +} virtres_t; + +virtres_t* vres_GetMap(lumpnum_t); +void vres_Free(virtres_t*); +virtlump_t* vres_Find(const virtres_t*, const char*); + // ========================================================================= // DYNAMIC WAD LOADING // ========================================================================= diff --git a/src/y_inter.c b/src/y_inter.c index cc1d7dd9c..b62566e0a 100644 --- a/src/y_inter.c +++ b/src/y_inter.c @@ -9,6 +9,7 @@ /// \file y_inter.c /// \brief Tally screens, or "Intermissions" as they were formally called in Doom +#include "d_netcmd.h" #include "doomdef.h" #include "doomstat.h" #include "d_main.h" @@ -100,10 +101,6 @@ static y_data data; static patch_t *bgpatch = NULL; // INTERSCR static patch_t *widebgpatch = NULL; // INTERSCW static patch_t *bgtile = NULL; // SPECTILE/SRB2BACK -static patch_t *interpic = NULL; // custom picture defined in map header -static boolean usetile; -boolean usebuffer = false; -static boolean useinterpic; static INT32 timer; static INT32 intertic; @@ -389,34 +386,24 @@ void Y_IntermissionDrawer(void) if (intertype == int_none || rendermode == render_none) return; - if (!usebuffer) - V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 31); - - if (useinterpic) - V_DrawScaledPatch(0, 0, 0, interpic); - else if (!usetile) + if (cv_betainterscreen.value == 1 +#ifdef HWRENDER + || (rendermode == render_opengl && cv_grscreentextures.value != 2) // use the neato kart bg for intermission on disabled screen textures +#endif + ) + V_DrawPatchFill(bgtile); // use the neato kart bg for intermission on disabled screen textures + else { - if (rendermode == render_soft && usebuffer) + if (rendermode == render_soft) VID_BlitLinearScreen(screens[1], screens[0], vid.width*vid.bpp, vid.height, vid.width*vid.bpp, vid.rowbytes); #ifdef HWRENDER - else if(rendermode != render_soft && usebuffer) - { + else if(rendermode == render_opengl) HWR_DrawIntermissionBG(); - } #endif - else - { - if (widebgpatch && rendermode == render_soft && vid.width / vid.dupx == 400) - V_DrawScaledPatch(0, 0, V_SNAPTOLEFT, widebgpatch); - else if (bgpatch) - V_DrawScaledPatch(0, 0, 0, bgpatch); - } } - else if (bgtile) - V_DrawPatchFill(bgtile); - if (usebuffer) // Fade everything out - V_DrawFadeScreen(0xFF00, 22); + // Fade everything out + V_DrawFadeScreen(0xFF00, 22); if (!splitscreen) whiteplayer = demo.playback ? displayplayers[0] : consoleplayer; @@ -430,7 +417,8 @@ void Y_IntermissionDrawer(void) if (sorttic != -1 && intertic >= sorttic && !demo.playback) { - INT32 count = (intertic - sorttic); + // yes this may actually overflow + INT64 count = (intertic - sorttic); if (count < 8) x -= ((((count<>FRACBITS) / (8 * vid.dupx); @@ -438,52 +426,11 @@ void Y_IntermissionDrawer(void) x += (((((16 - count)<>FRACBITS) / (8 * vid.dupx); } - // SRB2kart 290117 - compeltely replaced this block. - /*if (intertype == int_timeattack) - { - // draw time - ST_DrawPatchFromHud(HUD_TIME, sbotime); - if (cv_timetic.value) - ST_DrawNumFromHud(HUD_SECONDS, data.coop.tics); - else - { - INT32 seconds, minutes, tictrn; - - seconds = G_TicsToSeconds(data.coop.tics); - minutes = G_TicsToMinutes(data.coop.tics, true); - tictrn = G_TicsToCentiseconds(data.coop.tics); - - ST_DrawNumFromHud(HUD_MINUTES, minutes); // Minutes - ST_DrawPatchFromHud(HUD_TIMECOLON, sbocolon); // Colon - ST_DrawPadNumFromHud(HUD_SECONDS, seconds, 2); // Seconds - - // SRB2kart - pulled from old coop block, just in case we need it - // we should show centiseconds on the intermission screen too, if the conditions are right. - if (modeattacking || cv_timetic.value == 2) - { - ST_DrawPatchFromHud(HUD_TIMETICCOLON, sboperiod); // Period - ST_DrawPadNumFromHud(HUD_TICS, tictrn, 2); // Tics - } - - ST_DrawPatchFromHud(HUD_TIMETICCOLON, sboperiod); // Period - ST_DrawPadNumFromHud(HUD_TICS, tictrn, 2); // Tics - } - - // draw the "got through act" lines and act number - V_DrawLevelTitle(data.coop.passedx1, 49, 0, data.coop.passed1); - V_DrawLevelTitle(data.coop.passedx2, 49+V_LevelNameHeight(data.coop.passed2)+2, 0, data.coop.passed2); - - if (strlen(mapheaderinfo[prevmap]->actnum) > 0) - V_DrawScaledPatch(244, 57, 0, data.coop.ttlnum); - - //if (gottimebonus && endtic != -1) - // V_DrawCenteredString(BASEVIDWIDTH/2, 172, V_YELLOWMAP, "TIME BONUS UNLOCKED!"); - } - else*/ if (intertype == int_race || intertype == int_match) + if (intertype == int_race || intertype == int_match) { #define NUMFORNEWCOLUMN 8 INT32 y = 41, gutter = ((data.match.numplayers > NUMFORNEWCOLUMN) ? 0 : (BASEVIDWIDTH/2)); - INT32 dupadjust = (vid.width/vid.dupx), duptweak = (dupadjust - BASEVIDWIDTH)/2; + INT32 dupadjust = cv_betainterscreen.value ? 314 : (vid.width/vid.dupx), duptweak = cv_betainterscreen.value ? -3 : (dupadjust - BASEVIDWIDTH)/2; const char *timeheader; if (data.match.rankingsmode) @@ -644,6 +591,7 @@ void Y_IntermissionDrawer(void) } if ((demo.recording || demo.savemode == DSM_SAVED) && !demo.playback) + { switch (demo.savemode) { case DSM_NOTSAVING: @@ -661,10 +609,7 @@ void Y_IntermissionDrawer(void) default: // Don't render any text here break; } - - // Make it obvious that scrambling is happening next round. - if (cv_scrambleonchange.value && cv_teamscramble.value && (intertic/TICRATE % 2 == 0)) - V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT/2, hilicol, M_GetText("Teams will be scrambled next round!")); + } if (renderisnewtic) { @@ -891,14 +836,10 @@ void Y_StartIntermission(void) if (gametype == GT_MATCH) intertype = int_match; - else //if (gametype == GT_RACE) + else intertype = int_race; } - // We couldn't display the intermission even if we wanted to. - // But we still need to give the players their score bonuses, dummy. - //if (dedicated) return; - // This should always exist, but just in case... if(!mapheaderinfo[prevmap]) P_AllocMapHeader(prevmap); @@ -935,12 +876,7 @@ void Y_StartIntermission(void) break; } - //if (intertype == int_race || intertype == int_match) - { - //bgtile = W_CachePatchName("SRB2BACK", PU_STATIC); - usetile = useinterpic = false; - usebuffer = true; - } + bgtile = W_CachePatchName("SRB2BACK", PU_STATIC); LUA_HUD_DestroyDrawList(luahuddrawlist_intermission); luahuddrawlist_intermission = LUA_HUD_CreateDrawList(); @@ -958,7 +894,6 @@ void Y_EndIntermission(void) endtic = -1; sorttic = -1; intertype = int_none; - usebuffer = false; } // @@ -988,7 +923,7 @@ static void Y_UnloadData(void) UNLOAD(bgpatch); UNLOAD(widebgpatch); UNLOAD(bgtile); - UNLOAD(interpic); + //UNLOAD(interpic); } // SRB2Kart: Voting! diff --git a/src/z_zone.c b/src/z_zone.c index b0223460b..dd10f36e3 100644 --- a/src/z_zone.c +++ b/src/z_zone.c @@ -25,6 +25,9 @@ /// allocator was fragmenting badly. Finally, this version is a bit /// simpler (about half the lines of code). +#include +#include + #include "doomdef.h" #include "doomstat.h" #include "r_patch.h" @@ -67,8 +70,9 @@ typedef struct memblock_s struct memblock_s *next, *prev; } memblock_t; -#define MEMORY(x) (void *)((uintptr_t)(x) + sizeof(memblock_t)) -#define MEMBLOCK(x) (memblock_t *)((uintptr_t)(x) - sizeof(memblock_t)) +#define ALIGNPAD (((sizeof (memblock_t) + (alignof (max_align_t) - 1)) & ~(alignof (max_align_t) - 1)) - sizeof (memblock_t)) +#define MEMORY(x) (void *)((uintptr_t)(x) + sizeof(memblock_t) + ALIGNPAD) +#define MEMBLOCK(x) (memblock_t *)((uintptr_t)(x) - ALIGNPAD - sizeof(memblock_t)) // both the head and tail of the zone memory block list static memblock_t head; @@ -219,15 +223,16 @@ void *Z_MallocAlign(size_t size, INT32 tag, void *user, INT32 alignbits) { memblock_t *block; void *ptr; - (void)(alignbits); // no longer used, so silence warnings. + + (void)(alignbits); // no longer used, so silence warnings. TODO we should figure out a solution for this #ifdef ZDEBUG2 CONS_Debug(DBG_MEMORY, "Z_Malloc %s:%d\n", file, line); #endif - block = xm(sizeof (memblock_t) + size); + block = xm(sizeof (memblock_t) + ALIGNPAD + size); ptr = MEMORY(block); - I_Assert((intptr_t)ptr % sizeof (void *) == 0); + I_Assert((intptr_t)ptr % alignof (max_align_t) == 0); #ifdef HAVE_VALGRIND Z_calloc = false; diff --git a/src/z_zone.h b/src/z_zone.h index 6125f2b3f..e4ee811f2 100644 --- a/src/z_zone.h +++ b/src/z_zone.h @@ -144,6 +144,5 @@ size_t Z_TagsUsage(INT32 lowtag, INT32 hightag); // Miscellaneous functions // char *Z_StrDup(const char *in); -#define Z_Unlock(p) (void)p // TODO: remove this now that NDS code has been removed #endif