diff --git a/.circleci/config.yml b/.circleci/config.yml index 711be39d76fdfb80c4680bbae19c8dd135af0afb..b3b97363eeb3f31e41ddf01f01e6f01f52c86204 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,9 +1,9 @@ version: 2 jobs: build: - working_directory: /root/SRB2 + working_directory: /home/circleci/SRB2 docker: - - image: debian:stretch + - image: cimg/base:current environment: CC: ccache gcc -m32 PKG_CONFIG_LIBDIR: /usr/lib/i386-linux-gnu/pkgconfig @@ -11,7 +11,7 @@ jobs: LIBGME_LDFLAGS: -lgme CCACHE_COMPRESS: true WFLAGS: -Wno-unsuffixed-float-constants - GCC49: true + GCC81: true #- image: ubuntu:trusty # environment: # CC: ccache gcc -m32 @@ -25,39 +25,42 @@ jobs: steps: - run: name: Add i386 arch - command: dpkg --add-architecture i386 + command: sudo dpkg --add-architecture i386 - run: name: Add STJr PPA command: | - apt-get -qq update - apt-get -qq -y install dirmngr - apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 0B1702D71499D9C25F986507F240F4449D3B0EC6 - echo "deb http://ppa.launchpad.net/stjr/srb2/ubuntu trusty main" >> /etc/apt/sources.list + sudo apt-get -qq update + sudo apt-get -qq -y install dirmngr + sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 0B1702D71499D9C25F986507F240F4449D3B0EC6 + echo "deb http://ppa.launchpad.net/stjr/srb2/ubuntu trusty main" | sudo tee -a /etc/apt/sources.list - run: name: Make APT cache folder - command: mkdir -p /root/.cache/apt/archives/partial + command: mkdir -p /home/circleci/.cache/apt/archives/partial - run: name: Make APT cache usage by _apt - command: chown -Rv _apt:root /root/.cache/apt/archives/partial + command: sudo chown -Rv _apt:root /home/circleci/.cache/apt/archives/partial - run: name: Update APT listing - command: apt-get -qq update + command: sudo apt-get -qq update - run: name: Support S3 upload - command: apt-get -qq -y install ca-certificates + command: sudo apt-get -qq -y install ca-certificates - restore_cache: keys: - v1-SRB2-APT - run: - name: Install SDK - command: apt-get -o Dir::Cache="/root/.cache/apt" -qq -y --no-install-recommends install git build-essential nasm libpng-dev:i386 libsdl2-mixer-dev:i386 libgme-dev:i386 libcurl4-openssl-dev:i386 libopenmpt-dev:i386 gettext ccache wget gcc-multilib upx openssh-client + name: Uninstall amd64 SDK + command: sudo apt-get -o Dir::Cache="/home/circleci/.cache/apt" -qq -y --no-install-recommends remove libcurl4-openssl-dev:amd64 + - run: + name: Install i386 SDK + command: sudo apt-get -o Dir::Cache="/home/circleci/.cache/apt" -qq -y --no-install-recommends install git build-essential libpng-dev:i386 libsdl2-mixer-dev:i386 libgme-dev:i386 libcurl4-openssl-dev:i386 libopenmpt-dev:i386 gettext ccache wget gcc-multilib upx openssh-client - run: name: make md5sum - command: find /root/.cache/apt/archives -type f -print0 | sort -z | xargs -r0 md5sum > /root/.cache/apt_archives.md5 + command: sudo find /home/circleci/.cache/apt/archives -type f -print0 | sort -z | sudo xargs -r0 md5sum > /home/circleci/.cache/apt_archives.md5 - save_cache: - key: v1-SRB2-APT-{{ checksum "/root/.cache/apt_archives.md5" }} + key: v1-SRB2-APT-{{ checksum "/home/circleci/.cache/apt_archives.md5" }} paths: - - /root/.cache/apt + - /home/circleci/.cache/apt - checkout - run: name: Compile without network support @@ -78,9 +81,9 @@ jobs: name: Compile command: make -C src LINUX=1 ERRORMODE=1 -k -j4 - store_artifacts: - path: /root/SRB2/bin/ + path: /home/circleci/SRB2/bin/ destination: bin - save_cache: key: v1-SRB2-{{ .Branch }}-{{ checksum "make/linux/SDL.deps" }} paths: - - /root/.ccache + - /home/circleci/.ccache diff --git a/.gitattributes b/.gitattributes index 7751149ac07713a953529c5e8ba579109d76356d..c2e507352e6419be54e8866cc5bb40f5570a0fc7 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,15 +1,17 @@ #Source code +/Makefile text=auto /src/*.c text=auto /src/*.h text=auto /src/*.s text=auto /src/*.m text=auto /src/*.xpm text=auto /src/Makefile text=auto +/tools/Makefile text=auto /src/Make*.cfg text=auto /src/CMakeLists.txt text=auto +*.mk -whitespace text=auto # Windows EOL *.cs -crlf -whitespace -*.mk -crlf -whitespace *.bat -crlf -whitespace *.dev -crlf -whitespace *.dsp -crlf -whitespace diff --git a/.gitignore b/.gitignore index cd828dc116957ceda70d6c5b8a2b929b158f1f80..268e3632906a9b840747e6c015b32848ba45b50f 100644 --- a/.gitignore +++ b/.gitignore @@ -22,4 +22,5 @@ Win32_LIB_ASM_Release /make /bin /build -/build.* +/build/* +/CMakeUserPresets.json \ No newline at end of file diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000000000000000000000000000000000000..b292bfc06c21f5ef02d6bb155ae4ab5e4ee6533c --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,434 @@ +variables: + GIT_STRATEGY: clone + GIT_CLONE_PATH: $CI_BUILDS_DIR/$CI_CONCURRENT_ID/$CI_PROJECT_PATH + +default: + image: debian:stable-slim + + cache: + - key: ccache-$CI_PROJECT_PATH_SLUG-$CI_JOB_NAME_SLUG + fallback_keys: + - cache-$CI_PROJECT_PATH_SLUG-$CI_DEFAULT_BRANCH + - cache-$CI_PROJECT_PATH_SLUG-default + paths: + - ccache + - ccache_statslog + + - key: apt-$CI_JOB_IMAGE + paths: + - apt-cache + unprotect: true + + before_script: + - - | + # debconf + echo -e "\e[0Ksection_start:`date +%s`:debconf[collapsed=true]\r\e[0KSetup debconf's environment" + - export DEBIAN_FRONTEND="noninteractive" + - export DEBIAN_PRIORITY="low" + - export DEBCONF_NONINTERACTIVE_SEEN="true" + - | + # debconf + echo -e "\e[0Ksection_end:`date +%s`:debconf\r\e[0K" + - - | + # dpkg_aa + echo -e "\e[0Ksection_start:`date +%s`:dpkg_aa[collapsed=true]\r\e[0KAdding architectures to dpkg" + - dpkg --add-architecture i386 + - dpkg --add-architecture amd64 + - dpkg --add-architecture arm64 + - | + # dpkg_aa + echo -e "\e[0Ksection_end:`date +%s`:dpkg_aa\r\e[0K" + - - | + # apt_conf + echo -e "\e[0Ksection_start:`date +%s`:apt_conf[collapsed=true]\r\e[0KSetting up APT conf" + - export APT_CACHE_DIR=`pwd`/apt-cache + - mkdir --parents --verbose $APT_CACHE_DIR/partial/ + - touch /etc/apt/apt.conf.d/99build + - | + # apt.conf + echo Adding options to apt.conf':' + - | + # APT::Install-Recommends + echo APT::Install-Recommends "false"\; | tee --append /etc/apt/apt.conf.d/99build + - | + # quit + echo quiet "1"\; | tee --append /etc/apt/apt.conf.d/99build + - | + # APT::Get::Assume-Yes + echo APT::Get::Assume-Yes "true"\; | tee --append /etc/apt/apt.conf.d/99build + - | + # Dir::Cache::Archives + echo Dir::Cache::Archives "$APT_CACHE_DIR"\; | tee --append /etc/apt/apt.conf.d/99build + - | + # apt_conf + echo -e "\e[0Ksection_end:`date +%s`:apt_conf\r\e[0K" + - - | + # apt_update + echo -e "\e[0Ksection_start:`date +%s`:apt_update[collapsed=true]\r\e[0KUpdating APT listing" + - apt-get update + - | + # apt_update + echo -e "\e[0Ksection_end:`date +%s`:apt_update\r\e[0K" + + - - | + # apt_pre + echo -e "\e[0Ksection_start:`date +%s`:apt_pre[collapsed=true]\r\e[0KInstalling pre packages" + - apt-get install apt-utils + - | + # apt_pre + echo -e "\e[0Ksection_end:`date +%s`:apt_pre\r\e[0K" + + - - | + # apt_upgrade + echo -e "\e[0Ksection_start:`date +%s`:apt_upgrade[collapsed=true]\r\e[0KUpdating existing packages" + - apt-get upgrade + - | + # apt_update + echo -e "\e[0Ksection_end:`date +%s`:apt_upgrade\r\e[0K" + + - - | + # apt_common + echo -e "\e[0Ksection_start:`date +%s`:apt_common[collapsed=true]\r\e[0KInstalling common packages" + - apt-get install make git ccache nasm + - | + # apt_common + echo -e "\e[0Ksection_end:`date +%s`:apt_common\r\e[0K" + + - - | + # ccache_config + echo -e "\e[0Ksection_start:`date +%s`:ccache_config[collapsed=true]\r\e[0KSetting up ccache config" + - mkdir --parents --verbose ~/.ccache/ + - touch ~/.ccache/ccache.conf + - | + # cache.conf + echo Adding ccache configution option + - | + # base_dir + echo base_dir = $PWD | tee --append ~/.ccache/ccache.conf + - | + # cache_dir + echo cache_dir = $PWD/ccache | tee --append ~/.ccache/ccache.conf + - | + # compiler_check + echo compiler_check = content | tee --append ~/.ccache/ccache.conf + - | + # stats_log + echo stats_log = $PWD/ccache_statslog | tee --append ~/.ccache/ccache.conf + - | + # max_size + echo max_size = 50M | tee --append ~/.ccache/ccache.conf + - | + # ccache_config + echo -e "\e[0Ksection_end:`date +%s`:ccache_config\r\e[0K" + + - - | + # cache_reset + echo -e "\e[0Ksection_start:`date +%s`:ccache_reset[collapsed=true]\r\e[0KResetting ccache statistics" + - ccache --zero-stats + - ccache --show-stats + - | + # ccache_reset + echo -e "\e[0Ksection_end:`date +%s`:ccache_reset\r\e[0K" + + artifacts: + paths: + - "bin/" + - "src/comptime.h" + name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-$CI_JOB_NAME_SLUG" + + after_script: + - - | + # apt_clean + echo -e "\e[0Ksection_start:`date +%s`:apt_clean[collapsed=true]\r\e[0KCleaning of unneeded APT packages" + - apt-get autoclean + - | + # apt_clean + echo -e "\e[0Ksection_end:`date +%s`:apt_clean\r\e[0K" + + - - | + # ccache_stats + echo -e "\e[0Ksection_start:`date +%s`:ccache_stats[collapsed=true]\r\e[0Kccache statistics:" + - ccache --show-stats --verbose + - ccache --show-log-stats --verbose + - | + # ccahe_stats + echo -e "\e[0Ksection_end:`date +%s`:ccache_stats\r\e[0K" + +stages: + - build + +Debian testing GCC: + stage: build + image: debian:testing-slim + + allow_failure: true + + artifacts: + name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-testing-gcc" + + variables: + CC: gcc + LDFLAGS: -Wl,-fuse-ld=gold + + script: + - - | + # apt_toolchain + echo -e "\e[0Ksection_start:`date +%s`:apt_toolchain[collapsed=true]\r\e[0KInstalling toolchain packages" + - apt-get install gcc + - | + # apt_toolchain + echo -e "\e[0Ksection_end:`date +%s`:apt_toolchain\r\e[0K" + + - - | + # apt_development + echo -e "\e[0Ksection_start:`date +%s`:apt_development[collapsed=true]\r\e[0KInstalling development packages" + - apt-get install libsdl2-mixer-dev libpng-dev libcurl4-openssl-dev libgme-dev libopenmpt-dev + - | + # apt_development + echo -e "\e[0Ksection_end:`date +%s`:apt_development\r\e[0K" + + - - | + # make + echo -e "\e[0Ksection_start:`date +%s`:make[collapsed=false]\r\e[0KCompiling SRB2" + - make --directory=src --keep-going CCACHE=1 ERRORMODE=1 NONX86=1 || make --directory=src --keep-going CCACHE=1 ERRORMODE=1 NONX86=1 + - | + # make + echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K" + +Windows x86: + stage: build + + artifacts: + paths: + - "bin/" + - "src/comptime.h" + expose_as: "Win32" + name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-Win32" + + variables: + PREFIX: i686-w64-mingw32 + + script: + - - | + # apt_toolchain + echo -e "\e[0Ksection_start:`date +%s`:apt_toolchain[collapsed=true]\r\e[0KInstalling toolchain packages" + - apt-get install gcc-mingw-w64-i686-win32 + - | + # apt_toolchain + echo -e "\e[0Ksection_end:`date +%s`:apt_toolchain\r\e[0K" + + - - | + # make + echo -e "\e[0Ksection_start:`date +%s`:make[collapsed=false]\r\e[0KCompiling SRB2" + - make --directory=src --keep-going CCACHE=1 ERRORMODE=1 MINGW=1 SDL=1 || make --directory=src --keep-going CCACHE=1 ERRORMODE=1 MINGW=1 SDL=1 + - | + # make + echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K" + +Debian stable:amd64: + stage: build + + artifacts: + paths: + - "bin/" + - "src/comptime.h" + expose_as: "Debian amd64" + name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-x86-64" + + variables: + CC: x86_64-linux-gnu-gcc + LDFLAGS: -Wl,-fuse-ld=gold + OBJCOPY: x86_64-linux-gnu-objcopy + OBJDUMP: x86_64-linux-gnu-objdump + PKG_CONFIG_PATH: /usr/lib/x86_64-linux-gnu/pkgconfig + + script: + - - | + # apt_toolchain + echo -e "\e[0Ksection_start:`date +%s`:apt_toolchain[collapsed=true]\r\e[0KInstalling toolchain packages" + - apt-get install gcc-x86-64-linux-gnu || apt-get install gcc + - | + # apt_toolchain + echo -e "\e[0Ksection_end:`date +%s`:apt_toolchain\r\e[0K" + + - - | + # apt_development + echo -e "\e[0Ksection_start:`date +%s`:apt_development[collapsed=true]\r\e[0KInstalling development packages" + - apt-get install libsdl2-mixer-dev:amd64 libpng-dev:amd64 libcurl4-openssl-dev:amd64 libgme-dev:amd64 libopenmpt-dev:amd64 + - | + # apt_development + echo -e "\e[0Ksection_end:`date +%s`:apt_development\r\e[0K" + + - - | + # make + echo -e "\e[0Ksection_start:`date +%s`:make[collapsed=false]\r\e[0KCompiling SRB2" + - make --directory=src --keep-going CCACHE=1 ERRORMODE=1 LINUX64=1 || make --directory=src --keep-going CCACHE=1 ERRORMODE=1 LINUX64=1 + - | + # make + echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K" + +Debian stable:i386: + stage: build + + artifacts: + paths: + - "bin/" + - "src/comptime.h" + expose_as: "Debian i386" + name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-i686" + + variables: + CC: i686-linux-gnu-gcc + OBJCOPY: i686-linux-gnu-objcopy + OBJDUMP: i686-linux-gnu-objdump + PKG_CONFIG_PATH: /usr/lib/i386-linux-gnu/pkgconfig + + script: + - - | + # apt_toolchain + echo -e "\e[0Ksection_start:`date +%s`:apt_toolchain[collapsed=true]\r\e[0KInstalling toolchain packages" + - apt-get install gcc-i686-linux-gnu || apt-get install gcc + - | + # apt_toolchain + echo -e "\e[0Ksection_end:`date +%s`:apt_toolchain\r\e[0K" + + - - | + # apt_development + echo -e "\e[0Ksection_start:`date +%s`:apt_development[collapsed=true]\r\e[0KInstalling development packages" + - apt-get install libsdl2-mixer-dev:i386 libpng-dev:i386 libcurl4-openssl-dev:i386 libgme-dev:i386 libopenmpt-dev:i386 + - | + # apt_development + echo -e "\e[0Ksection_end:`date +%s`:apt_development\r\e[0K" + + - - | + # make + echo -e "\e[0Ksection_start:`date +%s`:make[collapsed=false]\r\e[0KCompiling SRB2" + - make --directory=src --keep-going CCACHE=1 ERRORMODE=1 LINUX=1 || make --directory=src --keep-going CCACHE=1 ERRORMODE=1 LINUX=1 + - | + # make + echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K" + +Debian stable:arm64: + stage: build + + artifacts: + paths: + - "bin/" + - "src/comptime.h" + expose_as: "Debian arm64" + name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-aarch64" + + variables: + CC: aarch64-linux-gnu-gcc + LDFLAGS: -Wl,-fuse-ld=gold + OBJCOPY: aarch64-linux-gnu-objcopy + OBJDUMP: aarch64-linux-gnu-objdump + PKG_CONFIG_PATH: /usr/lib/aarch64-linux-gnu/pkgconfig + + script: + - - | + # apt_toolchain + echo -e "\e[0Ksection_start:`date +%s`:apt_toolchain[collapsed=true]\r\e[0KInstalling toolchain packages" + - apt-get install gcc-aarch64-linux-gnu || apt-get install gcc + - | + # apt_toolchain + echo -e "\e[0Ksection_end:`date +%s`:apt_toolchain\r\e[0K" + + - - | + # apt_development + echo -e "\e[0Ksection_start:`date +%s`:apt_development[collapsed=true]\r\e[0KInstalling development packages" + - apt-get install libsdl2-mixer-dev:arm64 libpng-dev:arm64 libcurl4-openssl-dev:arm64 libgme-dev:arm64 libopenmpt-dev:arm64 + - | + # apt_development + echo -e "\e[0Ksection_end:`date +%s`:apt_development\r\e[0K" + + - - | + # make + echo -e "\e[0Ksection_start:`date +%s`:make[collapsed=false]\r\e[0KCompiling SRB2" + - make --directory=src --keep-going CCACHE=1 ERRORMODE=1 LINUX64=1 ERRORMODE=1 NONX86=1 || make --directory=src --keep-going CCACHE=1 ERRORMODE=1 LINUX64=1 NONX86=1 + - | + # make + echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K" + +Windows x64: + stage: build + + artifacts: + paths: + - "bin/" + - "src/comptime.h" + expose_as: "Win64" + name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-Win64" + + variables: + PREFIX: x86_64-w64-mingw32 + + script: + - - | + # apt_toolchain + echo -e "\e[0Ksection_start:`date +%s`:apt_toolchain[collapsed=true]\r\e[0KInstalling toolchain packages" + - apt-get install gcc-mingw-w64-x86-64-win32 + - | + # apt_toolchain + echo -e "\e[0Ksection_end:`date +%s`:apt_toolchain\r\e[0K" + + - - | + # make + echo -e "\e[0Ksection_start:`date +%s`:make[collapsed=false]\r\e[0KCompiling SRB2" + - make --directory=src --keep-going CCACHE=1 ERRORMODE=1 MINGW64=1 SDL=1 || make --directory=src --keep-going CCACHE=1 ERRORMODE=1 MINGW64=1 SDL=1 + - | + # make + echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K" + +Debian stable Clang: + stage: build + + allow_failure: true + + artifacts: + name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-clang" + + variables: + CC: clang + WFLAGS: -Wno-cast-align + CFLAGS: -Wno-cast-align + LDFLAGS: -Wl,-fuse-ld=gold + + script: + - - | + # apt_toolchain + echo -e "\e[0Ksection_start:`date +%s`:apt_toolchain[collapsed=true]\r\e[0KInstalling toolchain packages" + - apt-get install clang + - | + # apt_toolchain + echo -e "\e[0Ksection_end:`date +%s`:apt_toolchain\r\e[0K" + + - - | + # apt_development + echo -e "\e[0Ksection_start:`date +%s`:apt_development[collapsed=true]\r\e[0KInstalling development packages" + - apt-get install libsdl2-mixer-dev libpng-dev libcurl4-openssl-dev libgme-dev libopenmpt-dev + - | + # apt_development + echo -e "\e[0Ksection_end:`date +%s`:apt_development\r\e[0K" + + - - | + # make + echo -e "\e[0Ksection_start:`date +%s`:make[collapsed=false]\r\e[0KCompiling SRB2" + - make --directory=src --keep-going CCACHE=1 ERRORMODE=1 NONX86=1 || make --directory=src --keep-going CCACHE=1 ERRORMODE=1 NONX86=1 + - | + # make + echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K" + +Debian testing Clang: + extends: Debian stable Clang + + image: debian:testing-slim + + artifacts: + name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-testing-clang" + + variables: + CC: clang + WFLAGS: -Wno-cast-align -Wno-deprecated-non-prototype + CFLAGS: -Wno-cast-align -Wno-deprecated-non-prototype + LDFLAGS: -Wl,-fuse-ld=gold diff --git a/CMakeLists.txt b/CMakeLists.txt index 915912af5e8689b782e62b30c8eafbee66804b97..80a3bdcd6798a48d10ea928d60ca3c4fb77bf353 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -53,11 +53,15 @@ else() set(SRB2_CONFIG_SYSTEM_LIBRARIES_DEFAULT OFF) endif() +# Clang tidy options will be ignored if CMAKE_<LANG>_CLANG_TIDY are set. +option(SRB2_CONFIG_ENABLE_CLANG_TIDY_C "Enable default clang-tidy check configuration for C" OFF) +option(SRB2_CONFIG_ENABLE_CLANG_TIDY_CXX "Enable default clang-tidy check configuration for C++" OFF) option( SRB2_CONFIG_SYSTEM_LIBRARIES "Link dependencies using CMake's find_package and do not use internal builds" ${SRB2_CONFIG_SYSTEM_LIBRARIES_DEFAULT} ) +option(SRB2_CONFIG_ENABLE_TESTS "Build the test suite" ON) # This option isn't recommended for distribution builds and probably won't work (yet). cmake_dependent_option( SRB2_CONFIG_SHARED_INTERNAL_LIBRARIES @@ -76,6 +80,25 @@ option(SRB2_CONFIG_ZDEBUG "Compile with ZDEBUG defined." OFF) option(SRB2_CONFIG_PROFILEMODE "Compile for profiling (GCC only)." OFF) set(SRB2_CONFIG_ASSET_DIRECTORY "" CACHE PATH "Path to directory that contains all asset files for the installer. If set, assets will be part of installation and cpack.") +if(SRB2_CONFIG_ENABLE_TESTS) + # https://github.com/catchorg/Catch2 + CPMAddPackage( + NAME Catch2 + VERSION 3.4.0 + GITHUB_REPOSITORY catchorg/Catch2 + OPTIONS + "CATCH_INSTALL_DOCS OFF" + ) + list(APPEND CMAKE_MODULE_PATH "${Catch2_SOURCE_DIR}/extras") + include(CTest) + include(Catch) + add_executable(srb2tests) + # To add tests, use target_sources to add individual test files to the target in subdirs. + target_link_libraries(srb2tests PRIVATE Catch2::Catch2 Catch2::Catch2WithMain) + target_compile_features(srb2tests PRIVATE c_std_11 cxx_std_17) + catch_discover_tests(srb2tests) +endif() + # Enable CCache # (Set USE_CCACHE=ON to use, CCACHE_OPTIONS for options) if("${CMAKE_HOST_SYSTEM_NAME}" STREQUAL Windows) @@ -108,7 +131,11 @@ if("${SRB2_CONFIG_SYSTEM_LIBRARIES}") find_package(SDL2_mixer REQUIRED) find_package(CURL REQUIRED) find_package(OPENMPT REQUIRED) - find_package(GME REQUIRED) + + # libgme defaults to "Nuked" YM2612 emulator, which is + # very SLOW. The system library probably uses the + # default so just always build it. + #find_package(GME REQUIRED) endif() if(${PROJECT_SOURCE_DIR} MATCHES ${PROJECT_BINARY_DIR}) @@ -119,13 +146,6 @@ if ((${SRB2_USE_CCACHE}) AND (${CMAKE_C_COMPILER} MATCHES "clang")) message(WARNING "Using clang and CCache: You may want to set environment variable CCACHE_CPP2=yes to prevent include errors during compile.") endif() -# Add sources from Sourcefile -function(target_sourcefile type) - file(STRINGS Sourcefile list - REGEX "[-0-9A-Za-z_]+\.${type}") - target_sources(SRB2SDL2 PRIVATE ${list}) -endfunction() - # bitness check set(SRB2_SYSTEM_BITS 0) if(CMAKE_SIZEOF_VOID_P EQUAL 8) @@ -144,7 +164,8 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin") set(CMAKE_PDB_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin") # Set EXE names so the assets CMakeLists can refer to its target -set(SRB2_SDL2_EXE_NAME srb2 CACHE STRING "Executable binary output name") +set(SRB2_SDL2_EXE_NAME "" CACHE STRING "Override executable binary output name") +set(SRB2_SDL2_EXE_SUFFIX "" CACHE STRING "Optional executable suffix, separated by an underscore") include_directories(${CMAKE_CURRENT_BINARY_DIR}/src) @@ -152,11 +173,37 @@ add_subdirectory(src) add_subdirectory(assets) -## config.h generation set(GIT_EXECUTABLE "git" CACHE FILEPATH "Path to git binary") include(GitUtilities) -git_latest_commit(SRB2_COMP_COMMIT "${CMAKE_SOURCE_DIR}") -git_current_branch(SRB2_GIT_BRANCH "${CMAKE_SOURCE_DIR}") -set(SRB2_COMP_BRANCH "${SRB2_GIT_BRANCH}") -set(SRB2_COMP_REVISION "${SRB2_COMP_COMMIT}") -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/src/config.h.in ${CMAKE_CURRENT_BINARY_DIR}/src/config.h) + +if("${SRB2_SDL2_EXE_NAME}" STREQUAL "") + # cause a reconfigure if the branch changes + get_git_dir(SRB2_GIT_DIR) + configure_file("${SRB2_GIT_DIR}/HEAD" HEAD COPYONLY) + + git_current_branch(SRB2_GIT_REVISION) + + if("${SRB2_GIT_REVISION}" STREQUAL "") + # use abbreviated commit hash if on detached HEAD + git_latest_commit(SRB2_GIT_REVISION) + endif() + + if("${CMAKE_SYSTEM_NAME}" MATCHES "Windows") + list(APPEND EXE_NAME_PARTS "srb2win") + elseif("${CMAKE_SYSTEM_NAME}" MATCHES "Linux") + list(APPEND EXE_NAME_PARTS "lsdlsrb2") + else() + list(APPEND EXE_NAME_PARTS "srb2") + endif() + + if(NOT "${SRB2_GIT_REVISION}" STREQUAL "master") + list(APPEND EXE_NAME_PARTS ${SRB2_GIT_REVISION}) + endif() +else() + list(APPEND EXE_NAME_PARTS ${SRB2_SDL2_EXE_NAME}) +endif() + +list(APPEND EXE_NAME_PARTS ${SRB2_SDL2_EXE_SUFFIX}) + +list(JOIN EXE_NAME_PARTS "_" EXE_NAME) +set_target_properties(SRB2SDL2 PROPERTIES OUTPUT_NAME ${EXE_NAME}) diff --git a/CMakePresets.json b/CMakePresets.json new file mode 100644 index 0000000000000000000000000000000000000000..7713bb38516877d5e8e50cc46914a7f58c9c6d73 --- /dev/null +++ b/CMakePresets.json @@ -0,0 +1,29 @@ +{ + "version": 3, + "configurePresets": [ + { + "name": "default", + "description": "Build using default generator", + "binaryDir": "build", + "cacheVariables": { + "CMAKE_C_FLAGS": "-fdiagnostics-color", + "CMAKE_CXX_FLAGS": "-fdiagnostics-color", + "CMAKE_BUILD_TYPE": "RelWithDebInfo" + } + }, + { + "name": "debug", + "description": "Build for development (no optimizations)", + "inherits": "default", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Debug" + } + } + ], + "buildPresets": [ + { + "name": "default", + "configurePreset": "default" + } + ] +} diff --git a/README.md b/README.md index 49a3cc36d167169467a2d65bec7527610691694d..56ff2d02d24e39fe6f8038a0770e7b1b265c7ae7 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,6 @@ [Sonic Robo Blast 2](https://srb2.org/) is a 3D Sonic the Hedgehog fangame based on a modified version of [Doom Legacy](http://doomlegacy.sourceforge.net/). ## Dependencies -- NASM (x86 builds only) - SDL2 (Linux/OS X only) - SDL2-Mixer (Linux/OS X only) - libupnp (Linux/OS X only) diff --git a/SRB2.cbp b/SRB2.cbp index 2a1eb87b8565b3d2d9c13216c23d39dceecd6f92..9e887bf859c05ab821b3936f29cb3089daef2b2d 100644 --- a/SRB2.cbp +++ b/SRB2.cbp @@ -1992,24 +1992,6 @@ HW3SOUND for 3D hardware sound support <Option compilerVar="CC" /> </Unit> <Unit filename="src/v_video.h" /> - <Unit filename="src/vid_copy.s"> - <Option compilerVar="CC" /> - <Option compiler="avrgcc" use="1" buildCommand="$compiler $options -x assembler-with-cpp -c $file -o $object" /> - <Option compiler="gnu_gcc_compiler_for_mingw32" use="1" buildCommand="$compiler $options -x assembler-with-cpp -c $file -o $object" /> - <Option compiler="gnu_gcc_compiler_for_mingw64" use="1" buildCommand="$compiler $options -x assembler-with-cpp -c $file -o $object" /> - <Option compiler="armelfgcc" use="1" buildCommand="$compiler $options -x assembler-with-cpp -c $file -o $object" /> - <Option compiler="tricoregcc" use="1" buildCommand="$compiler $options -x assembler-with-cpp -c $file -o $object" /> - <Option compiler="ppcgcc" use="1" buildCommand="$compiler $options -x assembler-with-cpp -c $file -o $object" /> - <Option compiler="gcc" use="1" buildCommand="$compiler $options -x assembler-with-cpp -c $file -o $object" /> - <Option target="Debug Native/SDL" /> - <Option target="Release Native/SDL" /> - <Option target="Debug Linux/SDL" /> - <Option target="Release Linux/SDL" /> - <Option target="Debug Mingw/SDL" /> - <Option target="Release Mingw/SDL" /> - <Option target="Debug Mingw/DirectX" /> - <Option target="Release Mingw/DirectX" /> - </Unit> <Unit filename="src/w_wad.c"> <Option compilerVar="CC" /> </Unit> diff --git a/SRB2_common.props b/SRB2_common.props index 0f80ceb174874e682f0205de06733cb25e2b247a..6a0d53484f10106bc254851b1e1056dc7b24a86a 100644 --- a/SRB2_common.props +++ b/SRB2_common.props @@ -25,9 +25,6 @@ </Link> </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(PlatformTarget)'=='x86'"> - <ClCompile> - <PreprocessorDefinitions>USEASM;%(PreprocessorDefinitions)</PreprocessorDefinitions> - </ClCompile> <Link> <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers> </Link> diff --git a/Srb2.dev b/Srb2.dev index 21683e7c3c5e055393d91778fba3405bfae240de..8bd36cf490cc84dae69d25399113d346392e4fc8 100644 --- a/Srb2.dev +++ b/Srb2.dev @@ -5,7 +5,7 @@ Ver=3 IsCpp=0 Type=0 UnitCount=279 -Folders=A_Asm,B_Bot,BLUA,D_Doom,F_Frame,G_Game,H_Hud,Hw_Hardware,Hw_Hardware/r_opengl,I_Interface,I_Interface/Dummy,I_Interface/SDL,I_Interface/Win32,LUA,M_Misc,P_Play,R_Rend,S_Sounds,W_Wad +Folders=B_Bot,BLUA,D_Doom,F_Frame,G_Game,H_Hud,Hw_Hardware,Hw_Hardware/r_opengl,I_Interface,I_Interface/Dummy,I_Interface/SDL,I_Interface/Win32,LUA,M_Misc,P_Play,R_Rend,S_Sounds,W_Wad CommandLine= CompilerSettings=00000000000100000111e1 PchHead=-1 @@ -1473,36 +1473,6 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= -[Unit149] -FileName=src\tmap.nas -Folder=A_Asm -Compile=0 -CompileCpp=0 -Link=0 -Priority=1000 -OverrideBuildCmd=1 -BuildCmd=nasm.exe -g -o $@ -f win32 src/tmap.nas - -[Unit150] -FileName=src\asm_defs.inc -Folder=A_Asm -Compile=0 -CompileCpp=0 -Link=0 -Priority=1000 -OverrideBuildCmd=0 -BuildCmd= - -[Unit151] -FileName=src\vid_copy.s -Folder=A_Asm -Compile=1 -CompileCpp=0 -Link=1 -Priority=1000 -OverrideBuildCmd=1 -BuildCmd=$(CC) $(CFLAGS) -x assembler-with-cpp -c src/vid_copy.s -o $@ - [Unit152] FileName=src\y_inter.h Folder=H_Hud @@ -1543,26 +1513,6 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= -[Unit156] -FileName=src\p5prof.h -Folder=A_Asm -Compile=1 -CompileCpp=0 -Link=1 -Priority=1000 -OverrideBuildCmd=0 -BuildCmd= - -[Unit157] -FileName=src\tmap_mmx.nas -Folder=A_Asm -Compile=0 -CompileCpp=0 -Link=0 -Priority=1000 -OverrideBuildCmd=1 -BuildCmd=nasm.exe -g -o $@ -f win32 src/tmap_mmx.nas - [Unit159] FileName=src\lzf.h Folder=W_Wad diff --git a/alias-bootstrap.sh b/alias-bootstrap.sh new file mode 100755 index 0000000000000000000000000000000000000000..f1a6ac4ed918db4391a39c9a3076dfcc38d2861b --- /dev/null +++ b/alias-bootstrap.sh @@ -0,0 +1,29 @@ +#!/usr/bin/env sh + +# All these commands can be run from anywhere in the git +# tree, not just the top level. + +# Usage: git cmake +# +# Same usage as standard CMake command. +# +git config 'alias.cmake' '!cmake' + +# Usage: git build <build preset> [options] +# Usage: git build [options] +# +# In the second usage, when no preset is given, the +# "default" build preset is used. +# +# Available options can be found by running: +# +# git cmake --build +# +git config 'alias.build' '!p="${1##-*}"; [ "$p" ] && shift; git cmake --build --preset "${p:-default}"' + +# Usage: git crossmake +# +# Shortcut to i686-w64-mingw32-cmake (CMake cross +# compiler) +# +git config 'alias.crossmake' '!i686-w64-mingw32-cmake' diff --git a/appveyor.yml b/appveyor.yml index e3348d35cb2b001fba3162792867548b278d63f5..63d801b734719bf4ba47dfb42b1b7849c3a23189 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,4 +1,4 @@ -version: 2.2.11.{branch}-{build} +version: 2.2.13.{branch}-{build} os: MinGW environment: @@ -7,8 +7,6 @@ environment: # c:\mingw-w64 i686 has gcc 6.3.0, so use c:\msys64 7.3.0 instead MINGW_SDK: c:\msys64\mingw32 CFLAGS: -Wno-implicit-fallthrough - NASM_ZIP: nasm-2.12.01 - NASM_URL: http://www.nasm.us/pub/nasm/releasebuilds/2.12.01/win64/nasm-2.12.01-win64.zip UPX_ZIP: upx391w UPX_URL: http://upx.sourceforge.net/download/upx391w.zip CCACHE_EXE: ccache.exe @@ -40,17 +38,12 @@ environment: ASSET_CLEAN: 0 cache: -- nasm-2.12.01.zip - upx391w.zip - ccache.exe - C:\Users\appveyor\.ccache - C:\Users\appveyor\srb2_cache install: -- if not exist "%NASM_ZIP%.zip" appveyor DownloadFile "%NASM_URL%" -FileName "%NASM_ZIP%.zip" -- 7z x -y "%NASM_ZIP%.zip" -o%TMP% >null -- robocopy /S /xx /ns /nc /nfl /ndl /np /njh /njs "%TMP%\%NASM_ZIP%" "%MINGW_SDK%\bin" nasm.exe || exit 0 - - if not exist "%UPX_ZIP%.zip" appveyor DownloadFile "%UPX_URL%" -FileName "%UPX_ZIP%.zip" - 7z x -y "%UPX_ZIP%.zip" -o%TMP% >null - robocopy /S /xx /ns /nc /nfl /ndl /np /njh /njs "%TMP%\%UPX_ZIP%" "%MINGW_SDK%\bin" upx.exe || exit 0 @@ -65,7 +58,6 @@ configuration: before_build: - set "Path=%MINGW_SDK%\bin;%Path%" - mingw32-make --version -- nasm -v - if not [%NOUPX%] == [1] ( upx -V ) - ccache -V - ccache -s diff --git a/cmake/Comptime.cmake b/cmake/Comptime.cmake new file mode 100644 index 0000000000000000000000000000000000000000..8388aed9ece077229a35d601ffd0679cb2ecd035 --- /dev/null +++ b/cmake/Comptime.cmake @@ -0,0 +1,32 @@ +cmake_minimum_required(VERSION 3.3 FATAL_ERROR) + +set(CMAKE_BINARY_DIR "${BINARY_DIR}") +set(CMAKE_CURRENT_BINARY_DIR "${BINARY_DIR}") + +# Set up CMAKE path +set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules/") + +include(GitUtilities) + +git_current_branch(SRB2_COMP_BRANCH) +git_working_tree_dirty(SRB2_COMP_UNCOMMITTED) + +git_latest_commit(SRB2_COMP_REVISION) +git_subject(subject) +string(REGEX REPLACE "([\"\\])" "\\\\\\1" SRB2_COMP_NOTE "${subject}") + +if("${CMAKE_BUILD_TYPE}" STREQUAL "") + set(CMAKE_BUILD_TYPE None) +endif() + +# These build types enable optimizations of some kind by default. +set(optimized_build_types "MINSIZEREL;RELEASE;RELWITHDEBINFO") + +string(TOUPPER "${CMAKE_BUILD_TYPE}" build_type) +if("${build_type}" IN_LIST optimized_build_types) + set(SRB2_COMP_OPTIMIZED TRUE) +else() + set(SRB2_COMP_OPTIMIZED FALSE) +endif() + +configure_file("${CMAKE_CURRENT_SOURCE_DIR}/src/config.h.in" "${CMAKE_CURRENT_BINARY_DIR}/src/config.h") diff --git a/cmake/Modules/CMakeASM_YASMInformation.cmake b/cmake/Modules/CMakeASM_YASMInformation.cmake deleted file mode 100644 index 1765180853bb2d23217a1eb785f97737411e68b1..0000000000000000000000000000000000000000 --- a/cmake/Modules/CMakeASM_YASMInformation.cmake +++ /dev/null @@ -1,46 +0,0 @@ - -#============================================================================= -# Copyright 2010 Kitware, Inc. -# -# Distributed under the OSI-approved BSD License (the "License"); -# see accompanying file Copyright.txt for details. -# -# This software is distributed WITHOUT ANY WARRANTY; without even the -# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -# See the License for more information. -#============================================================================= -# (To distribute this file outside of CMake, substitute the full -# License text for the above reference.) - -# support for the yasm assembler - -set(CMAKE_ASM_YASM_SOURCE_FILE_EXTENSIONS nasm yasm asm) - -if(NOT CMAKE_ASM_YASM_OBJECT_FORMAT) - if(WIN32) - if(CMAKE_C_SIZEOF_DATA_PTR EQUAL 8) - set(CMAKE_ASM_YASM_OBJECT_FORMAT win64) - else() - set(CMAKE_ASM_YASM_OBJECT_FORMAT win32) - endif() - elseif(APPLE) - if(CMAKE_C_SIZEOF_DATA_PTR EQUAL 8) - set(CMAKE_ASM_YASM_OBJECT_FORMAT macho64) - else() - set(CMAKE_ASM_YASM_OBJECT_FORMAT macho) - endif() - else() - if(CMAKE_C_SIZEOF_DATA_PTR EQUAL 8) - set(CMAKE_ASM_YASM_OBJECT_FORMAT elf64) - else() - set(CMAKE_ASM_YASM_OBJECT_FORMAT elf) - endif() - endif() -endif() - -set(CMAKE_ASM_YASM_COMPILE_OBJECT "<CMAKE_ASM_YASM_COMPILER> <FLAGS> -f ${CMAKE_ASM_YASM_OBJECT_FORMAT} -o <OBJECT> <SOURCE>") - -# Load the generic ASMInformation file: -set(ASM_DIALECT "_YASM") -include(CMakeASMInformation) -set(ASM_DIALECT) diff --git a/cmake/Modules/CMakeDetermineASM_YASMCompiler.cmake b/cmake/Modules/CMakeDetermineASM_YASMCompiler.cmake deleted file mode 100644 index a5e7c9e5801121f04411e5f1b1c6efa98736bcc1..0000000000000000000000000000000000000000 --- a/cmake/Modules/CMakeDetermineASM_YASMCompiler.cmake +++ /dev/null @@ -1,27 +0,0 @@ - -#============================================================================= -# Copyright 2010 Kitware, Inc. -# -# Distributed under the OSI-approved BSD License (the "License"); -# see accompanying file Copyright.txt for details. -# -# This software is distributed WITHOUT ANY WARRANTY; without even the -# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -# See the License for more information. -#============================================================================= -# (To distribute this file outside of CMake, substitute the full -# License text for the above reference.) - -# Find the nasm assembler. yasm (http://www.tortall.net/projects/yasm/) is nasm compatible - -set(CMAKE_ASM_YASM_COMPILER_LIST nasm yasm) - -if(NOT CMAKE_ASM_YASM_COMPILER) - find_program(CMAKE_ASM_YASM_COMPILER yasm - "$ENV{ProgramFiles}/YASM") -endif() - -# Load the generic DetermineASM compiler file with the DIALECT set properly: -set(ASM_DIALECT "_YASM") -include(CMakeDetermineASMCompiler) -set(ASM_DIALECT) diff --git a/cmake/Modules/CMakeTestASM_YASMCompiler.cmake b/cmake/Modules/CMakeTestASM_YASMCompiler.cmake deleted file mode 100644 index 745f7125c4a2f7a003c488b89d977b75a8eb3ebc..0000000000000000000000000000000000000000 --- a/cmake/Modules/CMakeTestASM_YASMCompiler.cmake +++ /dev/null @@ -1,23 +0,0 @@ - -#============================================================================= -# Copyright 2010 Kitware, Inc. -# -# Distributed under the OSI-approved BSD License (the "License"); -# see accompanying file Copyright.txt for details. -# -# This software is distributed WITHOUT ANY WARRANTY; without even the -# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -# See the License for more information. -#============================================================================= -# (To distribute this file outside of CMake, substitute the full -# License text for the above reference.) - -# This file is used by EnableLanguage in cmGlobalGenerator to -# determine that the selected ASM_NASM "compiler" works. -# For assembler this can only check whether the compiler has been found, -# because otherwise there would have to be a separate assembler source file -# for each assembler on every architecture. - -set(ASM_DIALECT "_YASM") -include(CMakeTestASMCompiler) -set(ASM_DIALECT) diff --git a/cmake/Modules/GitUtilities.cmake b/cmake/Modules/GitUtilities.cmake index d29e6b509dd27015f429c9e8f4de12e20fcc5b12..586c7b433ff31476fe2a4cf0d5634d36d2c997be 100644 --- a/cmake/Modules/GitUtilities.cmake +++ b/cmake/Modules/GitUtilities.cmake @@ -6,38 +6,54 @@ endif() set(__GitUtilities ON) -function(git_describe variable path) - execute_process(COMMAND "${GIT_EXECUTABLE}" "describe" - WORKING_DIRECTORY "${path}" - RESULT_VARIABLE result +macro(_git_command) + execute_process( + COMMAND "${GIT_EXECUTABLE}" ${ARGN} + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" OUTPUT_VARIABLE output ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE ) +endmacro() +macro(_git_easy_command) + _git_command(${ARGN}) set(${variable} "${output}" PARENT_SCOPE) -endfunction() +endmacro() -function(git_current_branch variable path) - execute_process(COMMAND ${GIT_EXECUTABLE} "symbolic-ref" "--short" "HEAD" - WORKING_DIRECTORY "${path}" - RESULT_VARIABLE result - OUTPUT_VARIABLE output - ERROR_QUIET - OUTPUT_STRIP_TRAILING_WHITESPACE - ) +function(git_current_branch variable) + _git_command(symbolic-ref -q --short HEAD) + + # If a detached head, a ref could still be resolved. + if("${output}" STREQUAL "") + _git_command(describe --all --exact-match) + + # Get the ref, in the form heads/master or + # remotes/origin/master so isolate the final part. + string(REGEX REPLACE ".*/" "" output "${output}") + endif() set(${variable} "${output}" PARENT_SCOPE) endfunction() -function(git_latest_commit variable path) - execute_process(COMMAND ${GIT_EXECUTABLE} "rev-parse" "--short" "HEAD" - WORKING_DIRECTORY "${path}" - RESULT_VARIABLE result - OUTPUT_VARIABLE output - ERROR_QUIET - OUTPUT_STRIP_TRAILING_WHITESPACE - ) +function(git_latest_commit variable) + _git_easy_command(rev-parse --short HEAD) +endfunction() - set(${variable} "${output}" PARENT_SCOPE) -endfunction() \ No newline at end of file +function(git_working_tree_dirty variable) + _git_command(status --porcelain -uno) + + if(output STREQUAL "") + set(${variable} FALSE PARENT_SCOPE) + else() + set(${variable} TRUE PARENT_SCOPE) + endif() +endfunction() + +function(git_subject variable) + _git_easy_command(log -1 --format=%s) +endfunction() + +function(get_git_dir variable) + _git_easy_command(rev-parse --git-dir) +endfunction() diff --git a/cmake/Modules/clang-tidy-default.cmake b/cmake/Modules/clang-tidy-default.cmake new file mode 100644 index 0000000000000000000000000000000000000000..2be3af10d961229bac835c7083a0d81f677f7144 --- /dev/null +++ b/cmake/Modules/clang-tidy-default.cmake @@ -0,0 +1,21 @@ +find_program(CLANG_TIDY clang-tidy) + +# Note: Apple Clang does not ship with clang tools. If you want clang-tidy on +# macOS, it's best to install the Homebrew llvm bottle and set CLANG_TIDY +# in your build directory. The llvm package is keg-only, so it will not +# collide with Apple Clang. + +function(target_set_default_clang_tidy target lang checks) + if("${CLANG_TIDY}" STREQUAL "CLANG_TIDY-NOTFOUND") + return() + endif() + + get_target_property(c_clang_tidy_prop SRB2SDL2 C_CLANG_TIDY) + if(NOT ("${c_clang_tidy_prop}" STREQUAL "c_clang_tidy_prop-NOTFOUND")) + return() + endif() + + set_target_properties("${target}" PROPERTIES + ${lang}_CLANG_TIDY "${CLANG_TIDY};-checks=${checks}" + ) +endfunction() diff --git a/cpdebug.mk b/cpdebug.mk index 6baedf2275db4bbb06606a646cce9a4cb2c1d35e..75f08c66f4af721939c6f6c904aefc62f0d75534 100644 --- a/cpdebug.mk +++ b/cpdebug.mk @@ -3,12 +3,12 @@ ifdef ComSpec COMSPEC=$(ComSpec) endif ifdef COMSPEC -OBJCOPY=objcopy.exe -OBJDUMP=objdump.exe +OBJCOPY?=objcopy.exe +OBJDUMP?=objdump.exe GZIP?=gzip.exe else -OBJCOPY=objcopy -OBJDUMP=objdump +OBJCOPY?=objcopy +OBJDUMP?=objdump GZIP?=gzip endif DBGNAME=$(BIN).debug diff --git a/extras/conf/SRB2-22.cfg b/extras/conf/SRB2-22.cfg index dd5cdb46b2c2338fd1b2728f877ab903389054ad..41ad998891154f56fe850cdfe457a48189dd648f 100644 --- a/extras/conf/SRB2-22.cfg +++ b/extras/conf/SRB2-22.cfg @@ -4367,7 +4367,6 @@ thingtypes { color = 14; // Yellow title = "Rings and Weapon Panels"; - width = 24; height = 24; flags8height = 24; flags8text = "[8] Float"; @@ -4377,7 +4376,6 @@ thingtypes { title = "Ring"; sprite = "RINGA0"; - width = 16; } 301 { @@ -4393,6 +4391,7 @@ thingtypes { title = "Infinity Ring"; sprite = "RNGIA0"; + width = 24; } 304 { @@ -4418,43 +4417,53 @@ thingtypes { title = "CTF Team Ring (Red)"; sprite = "internal:TRNGA0R"; - width = 16; } 309 { title = "CTF Team Ring (Blue)"; sprite = "internal:TRNGA0B"; - width = 16; } 330 { title = "Bounce Ring Panel"; sprite = "PIKBA0"; + width = 24; + height = 40; } 331 { title = "Rail Ring Panel"; sprite = "PIKRA0"; + width = 24; + height = 40; } 332 { title = "Automatic Ring Panel"; sprite = "PIKAA0"; + width = 24; + height = 40; } 333 { title = "Explosion Ring Panel"; sprite = "PIKEA0"; + width = 24; + height = 40; } 334 { title = "Scatter Ring Panel"; sprite = "PIKSA0"; + width = 24; + height = 40; } 335 { title = "Grenade Ring Panel"; sprite = "PIKGA0"; + width = 24; + height = 40; } } @@ -4463,7 +4472,7 @@ thingtypes color = 10; // Light Green title = "Other Collectibles"; width = 16; - height = 32; + height = 24; sort = 1; sprite = "CEMGA0"; @@ -4529,6 +4538,7 @@ thingtypes { title = "Emerald Hunt Location"; sprite = "SHRDA0"; + height = 32; flags8height = 24; flags8text = "[8] Float"; } diff --git a/extras/conf/udb/Includes/SRB222_linedefs.cfg b/extras/conf/udb/Includes/SRB222_linedefs.cfg index 621b4abd53c4ff087664c9b24b0b424eae5d1e8b..68077862392a0ca2668d296f051203cd250e93ed 100644 --- a/extras/conf/udb/Includes/SRB222_linedefs.cfg +++ b/extras/conf/udb/Includes/SRB222_linedefs.cfg @@ -1221,52 +1221,6 @@ udmf } } } - 260 - { - title = "Generalized 3D Floor"; - prefix = "(260)"; - id = "Sector_Set3dFloor"; - requiresactivation = false; - - arg0 - { - title = "Target sector tag"; - type = 13; - } - arg1 - { - title = "Type"; - type = 26; - default = 1; - enum - { - 1 = "Solid"; - 2 = "Water"; - 3 = "Intangible"; - } - flags - { - 4 = "Render insides"; - 16 = "Only render insides"; - } - } - arg2 - { - title = "Flags"; - type = 12; - enum - { - 1 = "No shadow"; - 2 = "Double shadow"; - 4 = "Fog"; - } - } - arg3 - { - title = "Alpha"; - default = 255; - } - } } linedeftrigger diff --git a/extras/conf/udb/Includes/SRB222_things.cfg b/extras/conf/udb/Includes/SRB222_things.cfg index df08e3ac50fb47c80b412da2966e10cc2cec5f79..9eb227974dfd0b33de593a7ced83b42fab7d6738 100644 --- a/extras/conf/udb/Includes/SRB222_things.cfg +++ b/extras/conf/udb/Includes/SRB222_things.cfg @@ -1185,7 +1185,7 @@ udmf { color = 14; // Yellow title = "Rings and Weapon Panels"; - width = 24; + width = 16; height = 24; sprite = "RINGA0"; @@ -1193,7 +1193,6 @@ udmf { title = "Ring"; sprite = "RINGA0"; - width = 16; arg0 { title = "Float?"; @@ -1227,6 +1226,7 @@ udmf { title = "Infinity Ring"; sprite = "RNGIA0"; + width = 24; arg0 { title = "Float?"; @@ -1282,7 +1282,6 @@ udmf { title = "CTF Team Ring (Red)"; sprite = "internal:TRNGA0R"; - width = 16; arg0 { title = "Float?"; @@ -1294,7 +1293,6 @@ udmf { title = "CTF Team Ring (Blue)"; sprite = "internal:TRNGA0B"; - width = 16; arg0 { title = "Float?"; @@ -1306,6 +1304,8 @@ udmf { title = "Bounce Ring Panel"; sprite = "PIKBA0"; + width = 24; + height = 40; arg0 { title = "Float?"; @@ -1317,6 +1317,8 @@ udmf { title = "Rail Ring Panel"; sprite = "PIKRA0"; + width = 24; + height = 40; arg0 { title = "Float?"; @@ -1328,6 +1330,8 @@ udmf { title = "Automatic Ring Panel"; sprite = "PIKAA0"; + width = 24; + height = 40; arg0 { title = "Float?"; @@ -1339,6 +1343,8 @@ udmf { title = "Explosion Ring Panel"; sprite = "PIKEA0"; + width = 24; + height = 40; arg0 { title = "Float?"; @@ -1350,6 +1356,8 @@ udmf { title = "Scatter Ring Panel"; sprite = "PIKSA0"; + width = 24; + height = 40; arg0 { title = "Float?"; @@ -1361,6 +1369,8 @@ udmf { title = "Grenade Ring Panel"; sprite = "PIKGA0"; + width = 24; + height = 40; arg0 { title = "Float?"; @@ -1375,7 +1385,7 @@ udmf color = 10; // Light_Green title = "Other Collectibles"; width = 16; - height = 32; + height = 24; sort = 1; sprite = "CEMGA0"; @@ -1445,6 +1455,7 @@ udmf { title = "Emerald Hunt Location"; sprite = "SHRDA0"; + height = 32; arg0 { title = "Float?"; diff --git a/src/Android.mk b/src/Android.mk index a461da2242c7ab813831c95c1d442353756b0907..035d48887727c2a6d6b63a6acb38fc7ec65a9342 100644 --- a/src/Android.mk +++ b/src/Android.mk @@ -76,7 +76,7 @@ LOCAL_SRC_FILES := am_map.c \ android/i_system.c \ android/i_video.c -LOCAL_CFLAGS += -DPLATFORM_ANDROID -DNONX86 -DLINUX -DDEBUGMODE -DNOASM -DNOPIX -DUNIXCOMMON -DNOTERMIOS +LOCAL_CFLAGS += -DPLATFORM_ANDROID -DNONX86 -DLINUX -DDEBUGMODE -DNOPIX -DUNIXCOMMON -DNOTERMIOS LOCAL_MODULE := libsrb2 diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 2f4467a322026aa73b4281b97daeae8800855deb..b926b3b7a3372d206df781fd65bbf7a947ddaef3 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,23 +1,150 @@ -add_executable(SRB2SDL2 MACOSX_BUNDLE WIN32) +include(clang-tidy-default) + +add_executable(SRB2SDL2 MACOSX_BUNDLE WIN32 + comptime.c + md5.c + config.h.in + string.c + d_main.c + d_clisrv.c + d_net.c + d_netfil.c + d_netcmd.c + dehacked.c + deh_soc.c + deh_lua.c + deh_tables.c + z_zone.c + f_finale.c + f_wipe.c + g_demo.c + g_game.c + g_input.c + am_map.c + command.c + console.c + hu_stuff.c + i_time.c + y_inter.c + st_stuff.c + m_aatree.c + m_anigif.c + m_argv.c + m_bbox.c + m_cheat.c + m_cond.c + m_easing.c + m_fixed.c + m_menu.c + m_misc.c + m_perfstats.c + m_random.c + m_queue.c + info.c + p_ceilng.c + p_enemy.c + p_floor.c + p_inter.c + p_lights.c + p_map.c + p_maputl.c + p_mobj.c + p_polyobj.c + p_saveg.c + p_setup.c + p_sight.c + p_spec.c + p_telept.c + p_tick.c + p_user.c + p_slopes.c + tables.c + r_bsp.c + r_data.c + r_draw.c + r_fps.c + r_main.c + r_plane.c + r_segs.c + r_skins.c + r_sky.c + r_splats.c + r_things.c + r_bbox.c + r_textures.c + r_patch.c + r_patchrotation.c + r_picformats.c + r_portal.c + screen.c + taglist.c + v_video.c + s_sound.c + sounds.c + w_wad.c + filesrch.c + mserv.c + http-mserv.c + i_tcp.c + lzf.c + b_bot.c + u_list.c + lua_script.c + lua_baselib.c + lua_mathlib.c + lua_hooklib.c + lua_consolelib.c + lua_infolib.c + lua_mobjlib.c + lua_playerlib.c + lua_skinlib.c + lua_thinkerlib.c + lua_maplib.c + lua_taglib.c + lua_polyobjlib.c + lua_blockmaplib.c + lua_hudlib.c + lua_hudlib_drawlist.c + lua_inputlib.c +) -if("${CMAKE_COMPILER_IS_GNUCC}" AND "${CMAKE_SYSTEM_NAME}" MATCHES "Windows" AND NOT "${SRB2_CONFIG_SYSTEM_LIBRARIES}" AND NOT "${SRB2_CONFIG_SHARED_INTERNAL_LIBRARIES}") - # On MinGW with internal libraries, link the standard library statically - target_link_options(SRB2SDL2 PRIVATE "-static") -endif() +# This updates the modification time for comptime.c at the +# end of building so when the build system is ran next time, +# that file gets flagged. comptime.c will always be rebuilt. +# +# This begs the question, why always rebuild comptime.c? +# Some things like the git commit must be checked each time +# the program is built. But the build system determines which +# files should be rebuilt before anything else. So +# comptime.c, which only needs to be rebuilt based on +# information known at build time, must be told to rebuild +# before that information can be ascertained. +add_custom_command( + TARGET SRB2SDL2 + POST_BUILD + COMMAND ${CMAKE_COMMAND} -E touch_nocreate ${CMAKE_CURRENT_SOURCE_DIR}/comptime.c +) -# Core sources -target_sourcefile(c) -target_sources(SRB2SDL2 PRIVATE comptime.c md5.c config.h.in) +# config.h is generated by this command. It should be done at +# build time for accurate git information and before anything +# that needs it, obviously. +add_custom_target(_SRB2_reconf ALL + COMMAND ${CMAKE_COMMAND} -DGIT_EXECUTABLE=${GIT_EXECUTABLE} -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} -DBINARY_DIR=${CMAKE_CURRENT_BINARY_DIR}/.. -P ${CMAKE_CURRENT_SOURCE_DIR}/../cmake/Comptime.cmake + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/.." +) +add_dependencies(SRB2SDL2 _SRB2_reconf) -set(SRB2_ASM_SOURCES vid_copy.s) +if("${CMAKE_COMPILER_IS_GNUCC}" AND "${CMAKE_SYSTEM_NAME}" MATCHES "Windows") + target_link_options(SRB2SDL2 PRIVATE "-Wl,--disable-dynamicbase") + if(NOT "${SRB2_CONFIG_SYSTEM_LIBRARIES}" AND NOT "${SRB2_CONFIG_SHARED_INTERNAL_LIBRARIES}") + # On MinGW with internal libraries, link the standard library statically + target_link_options(SRB2SDL2 PRIVATE "-static") + endif() +endif() -set(SRB2_NASM_SOURCES tmap_mmx.nas tmap.nas) +target_compile_features(SRB2SDL2 PRIVATE c_std_11 cxx_std_17) ### Configuration -set(SRB2_CONFIG_USEASM OFF CACHE BOOL - "Enable NASM tmap implementation for software mode speedup.") -set(SRB2_CONFIG_YASM OFF CACHE BOOL - "Use YASM in place of NASM.") set(SRB2_CONFIG_DEV_BUILD OFF CACHE BOOL "Compile a development build of SRB2.") @@ -74,33 +201,6 @@ if("${SRB2_CONFIG_HWRENDER}") endif() endif() -if(${SRB2_CONFIG_USEASM}) - #SRB2_ASM_FLAGS can be used to pass flags to either nasm or yasm. - if("${CMAKE_SYSTEM_NAME}" MATCHES "Linux") - set(SRB2_ASM_FLAGS "-DLINUX ${SRB2_ASM_FLAGS}") - endif() - - if(${SRB2_CONFIG_YASM}) - set(CMAKE_ASM_YASM_SOURCE_FILE_EXTENSIONS ${CMAKE_ASM_YASM_SOURCE_FILE_EXTENSIONS} nas) - set(CMAKE_ASM_YASM_FLAGS "${SRB2_ASM_FLAGS}" CACHE STRING "Flags used by the assembler during all build types.") - enable_language(ASM_YASM) - else() - set(CMAKE_ASM_NASM_SOURCE_FILE_EXTENSIONS ${CMAKE_ASM_NASM_SOURCE_FILE_EXTENSIONS} nas) - set(CMAKE_ASM_NASM_FLAGS "${SRB2_ASM_FLAGS}" CACHE STRING "Flags used by the assembler during all build types.") - enable_language(ASM_NASM) - endif() - - set(SRB2_USEASM ON) - target_compile_definitions(SRB2SDL2 PRIVATE -DUSEASM) - target_compile_options(SRB2SDL2 PRIVATE -msse3 -mfpmath=sse) - - target_sources(SRB2SDL2 PRIVATE ${SRB2_ASM_SOURCES} - ${SRB2_NASM_SOURCES}) -else() - set(SRB2_USEASM OFF) - target_compile_definitions(SRB2SDL2 PRIVATE -DNONX86 -DNORUSEASM) -endif() - # Targets # If using CCACHE, then force it. @@ -289,6 +389,9 @@ if(SRB2_CONFIG_PROFILEMODE AND "${CMAKE_C_COMPILER_ID}" STREQUAL "GNU") endif() add_subdirectory(sdl) +if(SRB2_CONFIG_ENABLE_TESTS) + add_subdirectory(tests) +endif() # strip debug symbols into separate file when using gcc. # to be consistent with Makefile, don't generate for OS X. @@ -329,3 +432,11 @@ if("${CMAKE_SYSTEM_NAME}" STREQUAL Windows AND NOT "${SRB2_CONFIG_INTERNAL_LIBRA COMMENT "Copying runtime DLLs" ) endif() + +# Setup clang-tidy +if(SRB2_CONFIG_ENABLE_CLANG_TIDY_C) + target_set_default_clang_tidy(SRB2SDL2 C "-*,clang-analyzer-*,-clang-analyzer-cplusplus-*") +endif() +if(SRB2_CONFIG_ENABLE_CLANG_TIDY_CXX) + target_set_default_clang_tidy(SRB2SDL2 CXX "-*,clang-analyzer-*,modernize-*") +endif() diff --git a/src/Makefile b/src/Makefile index 36b1a7efabea7416f42c624fc03ab93d2a15c05f..539c2fa743cc46071c94b8736c49802e6034e62c 100644 --- a/src/Makefile +++ b/src/Makefile @@ -47,8 +47,6 @@ # HAVE_MINIUPNPC=1 - Enable automated port forwarding. # Already enabled by default for 32-bit # Windows. -# NOASM=1 - Disable hand optimized assembly code for the -# Software renderer. # NOPNG=1 - Disable PNG graphics support. (TODO: double # check netplay compatible.) # NOCURL=1 - Disable libcurl--HTTP capability. @@ -88,7 +86,6 @@ # executable. # WINDOWSHELL=1 - Use Windows commands. # PREFIX= - Prefix to many commands, for cross compiling. -# YASM=1 - Use Yasm instead of NASM assembler. # STABS=1 - ? # ECHO=1 - Print out each command in the build process. # NOECHOFILENAMES=1 - Don't print out each that is being @@ -144,25 +141,9 @@ endif OBJDUMP_OPTS?=--wide --source --line-numbers -OBJCOPY:=$(call Prefix,objcopy) -OBJDUMP:=$(call Prefix,objdump) -WINDRES:=$(call Prefix,windres) - -ifdef YASM -NASM?=yasm -else -NASM?=nasm -endif - -ifdef YASM -ifdef STABS -NASMOPTS?=-g stabs -else -NASMOPTS?=-g dwarf2 -endif -else -NASMOPTS?=-g -endif +OBJCOPY?=$(call Prefix,objcopy) +OBJDUMP?=$(call Prefix,objdump) +WINDRES?=$(call Prefix,windres) GZIP?=gzip GZIP_OPTS?=-9 -f -n @@ -187,8 +168,6 @@ makedir:=../make opts:=-DCOMPVERSION -g libs:= -nasm_format:= - # This is a list of variables names, of which if defined, # also defines the name as a macro to the compiler. passthru_opts:= @@ -316,7 +295,6 @@ endif LD:=$(CC) cc:=$(cc) $(opts) -nasm=$(NASM) $(NASMOPTS) -f $(nasm_format) ifdef UPX upx=$(UPX) $(UPX_OPTS) endif @@ -393,7 +371,6 @@ $(objdir)/%.$(1) : %.$(2) | $$$$(@D)/ endef $(eval $(call _recipe,o,c,$(cc) -c -o $$@ $$<)) -$(eval $(call _recipe,o,nas,$(nasm) -o $$@ $$<)) $(eval $(call _recipe,o,s,$(cc) $(asflags) -c -o $$@ $$<)) $(eval $(call _recipe,res,rc,$(windres) -i $$< -o $$@)) @@ -414,3 +391,5 @@ ifdef WINDOWSHELL else @: endif + +#$(warning The handwritten GNU Makefile for SRB2 is deprecated, and may be removed in the future. Please consider switching to CMake.) diff --git a/src/Makefile.d/detect.mk b/src/Makefile.d/detect.mk index aca4987213419adb6d93056a8413c2d0330ae057..9e27369462b00c407f02cb95dbda22ef284a91d1 100644 --- a/src/Makefile.d/detect.mk +++ b/src/Makefile.d/detect.mk @@ -56,15 +56,18 @@ endif # This must have high to low order. gcc_versions:=\ - 102 101\ - 93 92 91\ - 84 83 82 81\ - 75 74 73 72 71\ - 64 63 62 61\ - 55 54 53 52 51\ + 132 131 130\ + 123 122 121 120\ + 114 113 112 111 110\ + 105 104 103 102 101 100\ + 95 94 93 92 91 90\ + 85 84 83 82 81 80\ + 75 74 73 72 71 70\ + 64 63 62 61 60\ + 55 54 53 52 51 50\ 49 48 47 46 45 44 43 42 41 40 -latest_gcc_version:=10.2 +latest_gcc_version:=13.2 # Automatically set version flag, but not if one was # manually set. And don't bother if this is a clean only @@ -74,13 +77,18 @@ ifeq (,$(call Wildvar,GCC% destructive)) # can't use $(CC) --version here since that uses argv[0] to display the name # also gcc outputs the information to stderr, so I had to do 2>&1 # this program really doesn't like identifying itself -version:=$(shell $(CC) -v 2>&1) +shellversion:=$(shell $(CC) -v 2>&1) +# Try to remove "-win32" +version:=$(subst -win32,.0,$(shellversion)) # check if this is in fact GCC ifneq (,$(findstring gcc version,$(version))) # in stark contrast to the name, gcc will give me a nicely formatted version number for free -version:=$(shell $(CC) -dumpfullversion) +shellversion:=$(shell $(CC) -dumpfullversion) + +# Try to remove "-win32" +version:=$(subst -win32,.0,$(shellversion)) # Turn version into words of major, minor v:=$(subst ., ,$(version)) diff --git a/src/Makefile.d/features.mk b/src/Makefile.d/features.mk index 8ba33383bb2f0c8169e92f91c6c8fea25c6c852f..a66779c07a77c72a4ae0c085ff738ce58e62cf73 100644 --- a/src/Makefile.d/features.mk +++ b/src/Makefile.d/features.mk @@ -1,75 +1,72 @@ -# -# Makefile for feature flags. -# - -passthru_opts+=\ - NONET NO_IPV6 NOHW NOMD5 NOPOSTPROCESSING\ - MOBJCONSISTANCY PACKETDROP ZDEBUG\ - HAVE_MINIUPNPC\ - -# build with debugging information -ifdef DEBUGMODE -PACKETDROP=1 -opts+=-DPARANOIA -DRANGECHECK -endif - -ifndef NOHW -opts+=-DHWRENDER -sources+=$(call List,hardware/Sourcefile) -endif - -ifndef NOASM -ifndef NONX86 -sources+=tmap.nas tmap_mmx.nas -opts+=-DUSEASM -endif -endif - -ifndef NOMD5 -sources+=md5.c -endif - -ifndef NOZLIB -ifndef NOPNG -ifdef PNG_PKGCONFIG -$(eval $(call Use_pkg_config,PNG_PKGCONFIG)) -else -PNG_CONFIG?=$(call Prefix,libpng-config) -$(eval $(call Configure,PNG,$(PNG_CONFIG) \ - $(if $(PNG_STATIC),--static),,--ldflags)) -endif -ifdef LINUX -opts+=-D_LARGEFILE64_SOURCE -endif -opts+=-DHAVE_PNG -sources+=apng.c -endif -endif - -ifndef NONET -ifndef NOCURL -CURLCONFIG?=curl-config -$(eval $(call Configure,CURL,$(CURLCONFIG))) -opts+=-DHAVE_CURL -endif -endif - -ifdef HAVE_MINIUPNPC -libs+=-lminiupnpc -endif - -# (Valgrind is a memory debugger.) -ifdef VALGRIND -VALGRIND_PKGCONFIG?=valgrind -$(eval $(call Use_pkg_config,VALGRIND)) -ZDEBUG=1 -opts+=-DHAVE_VALGRIND -endif - -default_packages:=\ - GME/libgme/LIBGME\ - OPENMPT/libopenmpt/LIBOPENMPT\ - ZLIB/zlib\ - -$(foreach p,$(default_packages),\ - $(eval $(call Check_pkg_config,$(p)))) +# +# Makefile for feature flags. +# + +passthru_opts+=\ + NONET NO_IPV6 NOHW NOMD5 NOPOSTPROCESSING\ + MOBJCONSISTANCY PACKETDROP ZDEBUG\ + HAVE_MINIUPNPC\ + +# build with debugging information +ifdef DEBUGMODE +PACKETDROP=1 +opts+=-DPARANOIA -DRANGECHECK +endif + +ifndef NOHW +opts+=-DHWRENDER +sources+=$(call List,hardware/Sourcefile) +endif + +ifdef NONET +NOCURL=1 +endif + +ifndef NOMD5 +sources+=md5.c +endif + +ifndef NOZLIB +ifndef NOPNG +ifdef PNG_PKGCONFIG +$(eval $(call Use_pkg_config,PNG_PKGCONFIG)) +else +PNG_CONFIG?=$(call Prefix,libpng-config) +$(eval $(call Configure,PNG,$(PNG_CONFIG) \ + $(if $(PNG_STATIC),--static),,--ldflags)) +endif +ifdef LINUX +opts+=-D_LARGEFILE64_SOURCE +endif +opts+=-DHAVE_PNG +sources+=apng.c +endif +endif + +ifndef NONET +ifndef NOCURL +CURLCONFIG?=curl-config +$(eval $(call Configure,CURL,$(CURLCONFIG))) +opts+=-DHAVE_CURL +endif +endif + +ifdef HAVE_MINIUPNPC +libs+=-lminiupnpc +endif + +# (Valgrind is a memory debugger.) +ifdef VALGRIND +VALGRIND_PKGCONFIG?=valgrind +$(eval $(call Use_pkg_config,VALGRIND)) +ZDEBUG=1 +opts+=-DHAVE_VALGRIND +endif + +default_packages:=\ + GME/libgme/LIBGME\ + OPENMPT/libopenmpt/LIBOPENMPT\ + ZLIB/zlib\ + +$(foreach p,$(default_packages),\ + $(eval $(call Check_pkg_config,$(p)))) diff --git a/src/Makefile.d/nix.mk b/src/Makefile.d/nix.mk index 767b64c12be4bf42fede8e07e80cba68151ef92a..9adf3f0f14fdc2b052e48053cabedee48a1a7edd 100644 --- a/src/Makefile.d/nix.mk +++ b/src/Makefile.d/nix.mk @@ -9,10 +9,6 @@ opts+=-DUNIXCOMMON -DLUA_USE_POSIX # instead of addresses libs+=-lm -rdynamic -ifndef nasm_format -nasm_format:=elf -DLINUX -endif - ifndef NOHW opts+=-I/usr/X11R6/include libs+=-L/usr/X11R6/lib @@ -29,13 +25,12 @@ endif # Tested by Steel, as of release 2.2.8. ifdef FREEBSD opts+=-I/usr/X11R6/include -DLINUX -DFREEBSD -libs+=-L/usr/X11R6/lib -lipx -lkvm +libs+=-L/usr/X11R6/lib -lkvm -lexecinfo endif # FIXME: UNTESTED #ifdef SOLARIS #NOIPX=1 -#NOASM=1 #opts+=-I/usr/local/include -I/opt/sfw/include \ # -DSOLARIS -DINADDR_NONE=INADDR_ANY -DBSD_COMP #libs+=-L/opt/sfw/lib -lsocket -lnsl diff --git a/src/Makefile.d/platform.mk b/src/Makefile.d/platform.mk index c5ac71a20adc24766a961cb544af54cf3a1b59b1..d19143e4cf6040dc161b201553db3942b123ee39 100644 --- a/src/Makefile.d/platform.mk +++ b/src/Makefile.d/platform.mk @@ -39,7 +39,6 @@ else ifdef SOLARIS # FIXME: UNTESTED UNIX=1 platform=solaris else ifdef CYGWIN32 # FIXME: UNTESTED -nasm_format=win32 platform=cygwin else ifdef MINGW ifdef MINGW64 diff --git a/src/Makefile.d/sdl.mk b/src/Makefile.d/sdl.mk index 99ca624e69f2f18c10625c93585f14681636f36e..a1bfa33038bbacebada85790a7565fceb9440985 100644 --- a/src/Makefile.d/sdl.mk +++ b/src/Makefile.d/sdl.mk @@ -56,13 +56,6 @@ SDL_LDFLAGS?=$(shell $(SDL_CONFIG) \ $(eval $(call Propogate_flags,SDL)) endif -# use the x86 asm code -ifndef CYGWIN32 -ifndef NOASM -USEASM=1 -endif -endif - ifdef MINGW ifndef NOSDLMAIN SDLMAIN=1 diff --git a/src/Makefile.d/win32.mk b/src/Makefile.d/win32.mk index 0e48ed68359523e70b4ba0a6d8eade4b81d1d9ca..73a3d9e453ecaa0a01e32e15f71326bd7be57920 100644 --- a/src/Makefile.d/win32.mk +++ b/src/Makefile.d/win32.mk @@ -17,8 +17,6 @@ sources+=win32/Srb2win.rc opts+=-DSTDC_HEADERS libs+=-ladvapi32 -lkernel32 -lmsvcrt -luser32 -nasm_format:=win32 - SDL?=1 ifndef NOHW diff --git a/src/Sourcefile b/src/Sourcefile index de90bb60910286242ae4b62b41af5d9ad57706ad..f2b408c665d28306ce9c778646f6139b6874099a 100644 --- a/src/Sourcefile +++ b/src/Sourcefile @@ -64,6 +64,7 @@ r_skins.c r_sky.c r_splats.c r_things.c +r_bbox.c r_textures.c r_patch.c r_patchrotation.c @@ -80,8 +81,8 @@ mserv.c http-mserv.c i_tcp.c lzf.c -vid_copy.s b_bot.c +u_list.c lua_script.c lua_baselib.c lua_mathlib.c diff --git a/src/android/i_system.c b/src/android/i_system.c index ff8b88de539353bfd93ae612a3739770b267c416..9d798d452fb1b36460553fd35870894be2a3e406 100644 --- a/src/android/i_system.c +++ b/src/android/i_system.c @@ -278,4 +278,26 @@ char *I_ClipboardPaste(void) void I_RegisterSysCommands(void) {} +// This is identical to the SDL implementation. +size_t I_GetRandomBytes(char *destination, size_t count) +{ + FILE *rndsource; + size_t actual_bytes; + + if (!(rndsource = fopen("/dev/urandom", "r"))) + if (!(rndsource = fopen("/dev/random", "r"))) + actual_bytes = 0; + + if (rndsource) + { + actual_bytes = fread(destination, 1, count, rndsource); + fclose(rndsource); + } + + if (actual_bytes == 0) + I_OutputMsg("I_GetRandomBytes(): couldn't get any random bytes"); + + return actual_bytes; +} + #include "../sdl/dosstr.c" diff --git a/src/asm_defs.inc b/src/asm_defs.inc deleted file mode 100644 index 48f8da0d8f582f28ad09674eec97b4af840f40b9..0000000000000000000000000000000000000000 --- a/src/asm_defs.inc +++ /dev/null @@ -1,43 +0,0 @@ -// SONIC ROBO BLAST 2 -//----------------------------------------------------------------------------- -// Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2023 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 asm_defs.inc -/// \brief must match the C structures - -#ifndef __ASM_DEFS__ -#define __ASM_DEFS__ - -// this makes variables more noticable, -// and make the label match with C code - -// Linux, unlike DOS, has no "_" 19990119 by Kin -// and nasm needs .data code segs under linux 20010210 by metzgermeister -// FIXME: nasm ignores these settings, so I put the macros into the makefile -#ifdef __ELF__ -#define C(label) label -#define CODE_SEG .data -#else -#define C(label) _##label -#define CODE_SEG .text -#endif - -/* This is a more readable way to access the arguments passed from C code */ -/* PLEASE NOTE: it is supposed that all arguments passed from C code are */ -/* 32bit integer (INT32, long, and most *pointers) */ -#define ARG1 8(%ebp) -#define ARG2 12(%ebp) -#define ARG3 16(%ebp) -#define ARG4 20(%ebp) -#define ARG5 24(%ebp) -#define ARG6 28(%ebp) -#define ARG7 32(%ebp) -#define ARG8 36(%ebp) -#define ARG9 40(%ebp) //(c)tm ... Allegro by Shawn Hargreaves. - -#endif diff --git a/src/b_bot.c b/src/b_bot.c index d1465f891d481dd8314507b8f6b5e2c795abb1dd..57f7623042d318df981af823ac59d1865c44fb75 100644 --- a/src/b_bot.c +++ b/src/b_bot.c @@ -631,7 +631,8 @@ void B_HandleFlightIndicator(player_t *player) } // otherwise, update its visibility - if (P_IsLocalPlayer(player->botleader)) + tails->hnext->drawonlyforplayer = player->botleader; // Hide it from the other player in splitscreen, and yourself when spectating + if (P_IsLocalPlayer(player->botleader)) // Only display it on your own view. Don't display it for spectators tails->hnext->flags2 &= ~MF2_DONTDRAW; else tails->hnext->flags2 |= MF2_DONTDRAW; diff --git a/src/blua/CMakeLists.txt b/src/blua/CMakeLists.txt index 4e9c67d2f348a8bfed899e4002d25136284b031f..892bf534addc810434bdd00960ebe7a92ef7bde4 100644 --- a/src/blua/CMakeLists.txt +++ b/src/blua/CMakeLists.txt @@ -1 +1,28 @@ -target_sourcefile(c) +target_sources(SRB2SDL2 PRIVATE + lapi.c + lbaselib.c + ldo.c + lfunc.c + linit.c + liolib.c + llex.c + lmem.c + lobject.c + lstate.c + lstrlib.c + ltablib.c + lundump.c + lzio.c + lauxlib.c + lcode.c + ldebug.c + ldump.c + lgc.c + lopcodes.c + lparser.c + lstring.c + ltable.c + ltm.c + lvm.c + loslib.c +) diff --git a/src/blua/Sourcefile b/src/blua/Sourcefile index f99c89c8dfb8e8b5da643cb2c8625a764e84580d..dae94310981fce03d6aefd30b6e7e5781a4a4eae 100644 --- a/src/blua/Sourcefile +++ b/src/blua/Sourcefile @@ -23,3 +23,4 @@ lstring.c ltable.c ltm.c lvm.c +loslib.c diff --git a/src/blua/linit.c b/src/blua/linit.c index d17390b20a01dca0cff486c4c25cc5e31cd9570a..dcf05d9f2c925e49457514c57f99afe7bf66c1d8 100644 --- a/src/blua/linit.c +++ b/src/blua/linit.c @@ -18,6 +18,7 @@ static const luaL_Reg lualibs[] = { {"", luaopen_base}, {LUA_TABLIBNAME, luaopen_table}, {LUA_IOLIBNAME, luaopen_io}, + {LUA_OSLIBNAME, luaopen_os}, {LUA_STRLIBNAME, luaopen_string}, {NULL, NULL} }; diff --git a/src/blua/loslib.c b/src/blua/loslib.c new file mode 100644 index 0000000000000000000000000000000000000000..ba2e1e3846c77809d0fe06673243b537417ea4ea --- /dev/null +++ b/src/blua/loslib.c @@ -0,0 +1,167 @@ +/* +** $Id: loslib.c,v 1.19.1.3 2008/01/18 16:38:18 roberto Exp $ +** Standard Operating System library +** See Copyright Notice in lua.h +*/ + + +#include <errno.h> +#include <locale.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> + +#define loslib_c +#define LUA_LIB + +#include "lua.h" + +#include "lauxlib.h" +#include "lualib.h" + + +static int os_clock (lua_State *L) { + lua_pushnumber(L, ((lua_Number)clock())/(lua_Number)CLOCKS_PER_SEC); + return 1; +} + + +/* +** {====================================================== +** Time/Date operations +** { year=%Y, month=%m, day=%d, hour=%H, min=%M, sec=%S, +** wday=%w+1, yday=%j, isdst=? } +** ======================================================= +*/ + +static void setfield (lua_State *L, const char *key, int value) { + lua_pushinteger(L, value); + lua_setfield(L, -2, key); +} + +static void setboolfield (lua_State *L, const char *key, int value) { + if (value < 0) /* undefined? */ + return; /* does not set field */ + lua_pushboolean(L, value); + lua_setfield(L, -2, key); +} + +static int getboolfield (lua_State *L, const char *key) { + int res; + lua_getfield(L, -1, key); + res = lua_isnil(L, -1) ? -1 : lua_toboolean(L, -1); + lua_pop(L, 1); + return res; +} + + +static int getfield (lua_State *L, const char *key, int d) { + int res; + lua_getfield(L, -1, key); + if (lua_isnumber(L, -1)) + res = (int)lua_tointeger(L, -1); + else { + if (d < 0) + return luaL_error(L, "field " LUA_QS " missing in date table", key); + res = d; + } + lua_pop(L, 1); + return res; +} + + +static int os_date (lua_State *L) { + const char *s = luaL_optstring(L, 1, "%c"); + time_t t = luaL_opt(L, (time_t)luaL_checknumber, 2, time(NULL)); + struct tm *stm; + if (*s == '!') { /* UTC? */ + stm = gmtime(&t); + s++; /* skip `!' */ + } + else + stm = localtime(&t); + if (stm == NULL) /* invalid date? */ + lua_pushnil(L); + else if (strcmp(s, "*t") == 0) { + lua_createtable(L, 0, 9); /* 9 = number of fields */ + setfield(L, "sec", stm->tm_sec); + setfield(L, "min", stm->tm_min); + setfield(L, "hour", stm->tm_hour); + setfield(L, "day", stm->tm_mday); + setfield(L, "month", stm->tm_mon+1); + setfield(L, "year", stm->tm_year+1900); + setfield(L, "wday", stm->tm_wday+1); + setfield(L, "yday", stm->tm_yday+1); + setboolfield(L, "isdst", stm->tm_isdst); + } + else { + char cc[3]; + luaL_Buffer b; + cc[0] = '%'; cc[2] = '\0'; + luaL_buffinit(L, &b); + for (; *s; s++) { + if (*s != '%' || *(s + 1) == '\0') /* no conversion specifier? */ + luaL_addchar(&b, *s); + else { + size_t reslen; + char buff[200]; /* should be big enough for any conversion result */ + cc[1] = *(++s); + reslen = strftime(buff, sizeof(buff), cc, stm); + luaL_addlstring(&b, buff, reslen); + } + } + luaL_pushresult(&b); + } + return 1; +} + + +static int os_time (lua_State *L) { + time_t t; + if (lua_isnoneornil(L, 1)) /* called without args? */ + t = time(NULL); /* get current time */ + else { + struct tm ts; + luaL_checktype(L, 1, LUA_TTABLE); + lua_settop(L, 1); /* make sure table is at the top */ + ts.tm_sec = getfield(L, "sec", 0); + ts.tm_min = getfield(L, "min", 0); + ts.tm_hour = getfield(L, "hour", 12); + ts.tm_mday = getfield(L, "day", -1); + ts.tm_mon = getfield(L, "month", -1) - 1; + ts.tm_year = getfield(L, "year", -1) - 1900; + ts.tm_isdst = getboolfield(L, "isdst"); + t = mktime(&ts); + } + if (t == (time_t)(-1)) + lua_pushnil(L); + else + lua_pushnumber(L, (lua_Number)t); + return 1; +} + + +static int os_difftime (lua_State *L) { + lua_pushnumber(L, difftime((time_t)(luaL_checknumber(L, 1)), + (time_t)(luaL_optnumber(L, 2, 0)))); + return 1; +} + +/* }====================================================== */ + +static const luaL_Reg syslib[] = { + {"clock", os_clock}, + {"date", os_date}, + {"difftime", os_difftime}, + {"time", os_time}, + {NULL, NULL} +}; + +/* }====================================================== */ + + + +LUALIB_API int luaopen_os (lua_State *L) { + luaL_register(L, LUA_OSLIBNAME, syslib); + return 1; +} diff --git a/src/blua/lualib.h b/src/blua/lualib.h index 4ea97edf3d22d585b57390b2db435b4ceec73330..7127e4d77e56c1d2aee9c7079b59c5a3adc959a2 100644 --- a/src/blua/lualib.h +++ b/src/blua/lualib.h @@ -24,6 +24,9 @@ LUALIB_API int (luaopen_table) (lua_State *L); #define LUA_IOLIBNAME "io" LUALIB_API int (luaopen_io) (lua_State *L); +#define LUA_OSLIBNAME "os" +LUALIB_API int (luaopen_os) (lua_State *L); + #define LUA_STRLIBNAME "string" LUALIB_API int (luaopen_string) (lua_State *L); diff --git a/src/command.c b/src/command.c index a34d9694a1c4f5026225780bca1d2e1d47b77c25..e1a43522da9946fe73b10efcf4f250008318fb50 100644 --- a/src/command.c +++ b/src/command.c @@ -76,6 +76,7 @@ CV_PossibleValue_t CV_OnOff[] = {{0, "Off"}, {1, "On"}, {0, NULL}}; CV_PossibleValue_t CV_YesNo[] = {{0, "No"}, {1, "Yes"}, {0, NULL}}; CV_PossibleValue_t CV_Unsigned[] = {{0, "MIN"}, {999999999, "MAX"}, {0, NULL}}; CV_PossibleValue_t CV_Natural[] = {{1, "MIN"}, {999999999, "MAX"}, {0, NULL}}; +CV_PossibleValue_t CV_TrueFalse[] = {{0, "False"}, {1, "True"}, {0, NULL}}; // Filter consvars by EXECVERSION // First implementation is 26 (2.1.21), so earlier configs default at 25 (2.1.20) @@ -680,25 +681,58 @@ static void COM_ExecuteString(char *ptext) // SCRIPT COMMANDS // ========================================================================= +static void print_alias(void) +{ + cmdalias_t *a; + + CONS_Printf("\x82""Current alias commands:\n"); + for (a = com_alias; a; a = a->next) + { + CONS_Printf("%s : %s", a->name, a->value); + } +} + +static void add_alias(char *newname, char *newcmd) +{ + cmdalias_t *a; + + // Check for existing aliases first + for (a = com_alias; a; a = a->next) + { + if (!stricmp(newname, a->name)) + { + Z_Free(a->value); // Free old cmd + a->value = newcmd; + return; + } + } + + // No alias found, add it instead + a = ZZ_Alloc(sizeof *a); + a->next = com_alias; + com_alias = a; + + a->name = newname; + a->value = newcmd; +} + /** Creates a command name that replaces another command. */ static void COM_Alias_f(void) { - cmdalias_t *a; + char *name; + char *zcmd; char cmd[1024]; size_t i, c; if (COM_Argc() < 3) { CONS_Printf(M_GetText("alias <name> <command>: create a shortcut command that executes other command(s)\n")); + print_alias(); return; } - a = ZZ_Alloc(sizeof *a); - a->next = com_alias; - com_alias = a; - - a->name = Z_StrDup(COM_Argv(1)); + name = Z_StrDup(COM_Argv(1)); // copy the rest of the command line cmd[0] = 0; // start out with a null string @@ -710,8 +744,8 @@ static void COM_Alias_f(void) strcat(cmd, " "); } strcat(cmd, "\n"); - - a->value = Z_StrDup(cmd); + zcmd = Z_StrDup(cmd); + add_alias(name, zcmd); } /** Prints a line of text to the console. @@ -863,9 +897,11 @@ static void COM_Help_f(void) { CONS_Printf(" Possible values:\n"); if (cvar->PossibleValue == CV_YesNo) - CONS_Printf(" Yes or No (On or Off, 1 or 0)\n"); + CONS_Printf(" Yes or No (On or Off, True or False, 1 or 0)\n"); else if (cvar->PossibleValue == CV_OnOff) - CONS_Printf(" On or Off (Yes or No, 1 or 0)\n"); + CONS_Printf(" On or Off (Yes or No, True or False, 1 or 0)\n"); + else if (cvar->PossibleValue == CV_TrueFalse) + CONS_Printf(" True or False (On or Off, Yes or No, 1 or 0)\n"); else if (cvar->PossibleValue == Color_cons_t) { for (i = 1; i < numskincolors; ++i) @@ -1016,7 +1052,7 @@ static void COM_Toggle_f(void) if (CV_Immutable(cvar)) return; - if (!(cvar->PossibleValue == CV_YesNo || cvar->PossibleValue == CV_OnOff)) + if (!(cvar->PossibleValue == CV_YesNo || cvar->PossibleValue == CV_OnOff || cvar->PossibleValue == CV_TrueFalse)) { CONS_Alert(CONS_NOTICE, M_GetText("%s is not a boolean value\n"), COM_Argv(1)); return; @@ -1507,12 +1543,12 @@ static void Setvalue(consvar_t *var, const char *valstr, boolean stealth) goto found; } // Not found ... but wait, there's hope! - if (var->PossibleValue == CV_OnOff || var->PossibleValue == CV_YesNo) + if (var->PossibleValue == CV_OnOff || var->PossibleValue == CV_YesNo || var->PossibleValue == CV_TrueFalse) { overrideval = -1; - if (!stricmp(valstr, "on") || !stricmp(valstr, "yes")) + if (!stricmp(valstr, "on") || !stricmp(valstr, "yes") || !stricmp(valstr, "true")) overrideval = 1; - else if (!stricmp(valstr, "off") || !stricmp(valstr, "no")) + else if (!stricmp(valstr, "off") || !stricmp(valstr, "no") || !stricmp(valstr, "false")) overrideval = 0; if (overrideval != -1) diff --git a/src/command.h b/src/command.h index 69d1890d34d068ac67eb48c10e5c0ec5b8764b7f..619d8c1dcab07a7ab5dfbe20e98cae409c77fb9d 100644 --- a/src/command.h +++ b/src/command.h @@ -177,6 +177,7 @@ extern CV_PossibleValue_t CV_OnOff[]; extern CV_PossibleValue_t CV_YesNo[]; extern CV_PossibleValue_t CV_Unsigned[]; extern CV_PossibleValue_t CV_Natural[]; +extern CV_PossibleValue_t CV_TrueFalse[]; // Filter consvars by version extern consvar_t cv_execversion; diff --git a/src/comptime.c b/src/comptime.c index 398eda0743706cecb4a22d1996f8949564f1fe07..386b53f46904df87fc5f64749cc11db6e6821e3f 100644 --- a/src/comptime.c +++ b/src/comptime.c @@ -11,6 +11,9 @@ #include "config.h" const char *compbranch = SRB2_COMP_BRANCH; const char *comprevision = SRB2_COMP_REVISION; +const char *compnote = SRB2_COMP_NOTE; +const char *comptype = CMAKE_BUILD_TYPE; +const int compoptimized = SRB2_COMP_OPTIMIZED; #elif (defined(COMPVERSION)) #include "comptime.h" @@ -21,5 +24,12 @@ const char *comprevision = "illegal"; #endif +const int compuncommitted = +#if (defined(COMPVERSION_UNCOMMITTED)) +1; +#else +0; +#endif + const char *compdate = __DATE__; const char *comptime = __TIME__; diff --git a/src/config.h.in b/src/config.h.in index 3d6d98375693b220329ebd7b8fe1619def9fe792..6d49a698934bf8b498f6bfb402bbaa7f8ff93191 100644 --- a/src/config.h.in +++ b/src/config.h.in @@ -11,8 +11,18 @@ #ifdef CMAKECONFIG -#define SRB2_COMP_REVISION "${SRB2_COMP_REVISION}" -#define SRB2_COMP_BRANCH "${SRB2_COMP_BRANCH}" +#define SRB2_COMP_REVISION "${SRB2_COMP_REVISION}" +#define SRB2_COMP_BRANCH "${SRB2_COMP_BRANCH}" +#define SRB2_COMP_NOTE "${SRB2_COMP_NOTE}" +// This is done with configure_file instead of defines in order to avoid +// recompiling the whole target whenever the working directory state changes +#cmakedefine SRB2_COMP_UNCOMMITTED +#ifdef SRB2_COMP_UNCOMMITTED +#define COMPVERSION_UNCOMMITTED +#endif + +#define CMAKE_BUILD_TYPE "${CMAKE_BUILD_TYPE}" +#cmakedefine01 SRB2_COMP_OPTIMIZED #endif @@ -28,12 +38,14 @@ * Last updated 2021 / 05 / 06 - v2.2.9 - patch.pk3 & zones.pk3 * Last updated 2022 / 03 / 06 - v2.2.10 - main assets * Last updated 2023 / 05 / 02 - v2.2.11 - patch.pk3 & zones.pk3 + * Last updated 2023 / 09 / 06 - v2.2.12 - patch.pk3 + * Last updated 2023 / 09 / 09 - v2.2.13 - none */ #define ASSET_HASH_SRB2_PK3 "ad911f29a28a18968ee5b2d11c2acb39" #define ASSET_HASH_ZONES_PK3 "1c8adf8d079ecb87d00081f158acf3c7" #define ASSET_HASH_PLAYER_DTA "2e7aaae8a6b1b77d90ffe7606ceadb6c" #ifdef USE_PATCH_DTA -#define ASSET_HASH_PATCH_PK3 "2e69558bce3b9610624549a75e29e19b" +#define ASSET_HASH_PATCH_PK3 "3c7b73f34af7e9a7bceb2d5260f76172" #endif #endif diff --git a/src/console.c b/src/console.c index 6d273f62076b0b544b27acf1b22bf313009fc8b6..21b608ce4df88ac5719cb8c43bb739e314450cbd 100644 --- a/src/console.c +++ b/src/console.c @@ -72,8 +72,8 @@ static INT32 con_curlines; // vid lines currently used by console INT32 con_clipviewtop; // (useless) -static INT32 con_hudlines; // number of console heads up message lines -static INT32 con_hudtime[MAXHUDLINES]; // remaining time of display for hud msg lines +static UINT8 con_hudlines; // number of console heads up message lines +static UINT32 con_hudtime[MAXHUDLINES]; // remaining time of display for hud msg lines INT32 con_clearlines; // top screen lines to refresh when view reduced boolean con_hudupdate; // when messages scroll, we need a backgrnd refresh @@ -126,10 +126,13 @@ static void CONS_backcolor_Change(void); static char con_buffer[CON_BUFFERSIZE]; // how many seconds the hud messages lasts on the screen -static consvar_t cons_msgtimeout = CVAR_INIT ("con_hudtime", "5", CV_SAVE, CV_Unsigned, NULL); +// CV_Unsigned can overflow when multiplied by TICRATE later, so let's use a 3-year limit instead +static CV_PossibleValue_t hudtime_cons_t[] = {{0, "MIN"}, {99999999, "MAX"}, {0, NULL}}; +static consvar_t cons_hudtime = CVAR_INIT ("con_hudtime", "5", CV_SAVE, hudtime_cons_t, NULL); // number of lines displayed on the HUD -static consvar_t cons_hudlines = CVAR_INIT ("con_hudlines", "5", CV_CALL|CV_SAVE, CV_Unsigned, CONS_hudlines_Change); +static CV_PossibleValue_t hudlines_cons_t[] = {{0, "MIN"}, {MAXHUDLINES, "MAX"}, {0, NULL}}; +static consvar_t cons_hudlines = CVAR_INIT ("con_hudlines", "5", CV_CALL|CV_SAVE, hudlines_cons_t, CONS_hudlines_Change); // number of lines console move per frame // (con_speed needs a limit, apparently) @@ -181,11 +184,6 @@ static void CONS_hudlines_Change(void) for (i = 0; i < con_hudlines; i++) con_hudtime[i] = 0; - if (cons_hudlines.value < 1) - cons_hudlines.value = 1; - else if (cons_hudlines.value > MAXHUDLINES) - cons_hudlines.value = MAXHUDLINES; - con_hudlines = cons_hudlines.value; Unlock_state(); @@ -477,7 +475,7 @@ void CON_Init(void) Unlock_state(); - CV_RegisterVar(&cons_msgtimeout); + CV_RegisterVar(&cons_hudtime); CV_RegisterVar(&cons_hudlines); CV_RegisterVar(&cons_speed); CV_RegisterVar(&cons_height); @@ -792,9 +790,8 @@ void CON_Ticker(void) // make overlay messages disappear after a while for (i = 0; i < con_hudlines; i++) { - con_hudtime[i]--; - if (con_hudtime[i] < 0) - con_hudtime[i] = 0; + if (con_hudtime[i]) + con_hudtime[i]--; } Unlock_state(); @@ -1343,7 +1340,8 @@ boolean CON_Responder(event_t *ev) static void CON_Linefeed(void) { // set time for heads up messages - con_hudtime[con_cy%con_hudlines] = cons_msgtimeout.value*TICRATE; + if (con_hudlines) + con_hudtime[con_cy%con_hudlines] = cons_hudtime.value*TICRATE; con_cy++; con_cx = 0; @@ -1699,7 +1697,7 @@ static void CON_DrawHudlines(void) INT32 charwidth = 8 * con_scalefactor; INT32 charheight = 8 * con_scalefactor; - if (con_hudlines <= 0) + if (!con_hudlines) return; if (chat_on && OLDCHAT) @@ -1707,7 +1705,7 @@ static void CON_DrawHudlines(void) else y = 0; - for (i = con_cy - con_hudlines+1; i <= con_cy; i++) + for (i = con_cy - con_hudlines; i <= con_cy; i++) { size_t c; INT32 x; @@ -1889,7 +1887,7 @@ void CON_Drawer(void) CON_DrawConsole(); else if (gamestate == GS_LEVEL || gamestate == GS_INTERMISSION || gamestate == GS_ENDING || gamestate == GS_CUTSCENE - || gamestate == GS_CREDITS || gamestate == GS_EVALUATION) + || gamestate == GS_CREDITS || gamestate == GS_EVALUATION || gamestate == GS_WAITINGPLAYERS) CON_DrawHudlines(); Unlock_state(); diff --git a/src/d_clisrv.c b/src/d_clisrv.c index ca9f4a24e73094ab2bcbb369e28903917bad86da..1ec9cf1e94b9fcbe2c135109cd4fb52031945620 100755 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -120,6 +120,8 @@ UINT8 hu_redownloadinggamestate = 0; // true when a player is connecting or disconnecting so that the gameplay has stopped in its tracks boolean hu_stopped = false; +consvar_t cv_dedicatedidletime = CVAR_INIT ("dedicatedidletime", "10", CV_SAVE, CV_Unsigned, NULL); + UINT8 adminpassmd5[16]; boolean adminpasswordset = false; @@ -1293,6 +1295,7 @@ static boolean CL_AskFileList(INT32 firstfile) static boolean CL_SendJoin(void) { UINT8 localplayers = 1; + char const *player2name; if (netgame) CONS_Printf(M_GetText("Sending join request...\n")); netbuffer->packettype = PT_CLIENTJOIN; @@ -1309,9 +1312,14 @@ static boolean CL_SendJoin(void) CleanupPlayerName(consoleplayer, cv_playername.zstring); if (splitscreen) CleanupPlayerName(1, cv_playername2.zstring);/* 1 is a HACK? oh no */ + // Avoid empty string on bots to avoid softlocking in singleplayer + if (botingame) + player2name = strcmp(cv_playername.zstring, "Tails") == 0 ? "Tail" : "Tails"; + else + player2name = cv_playername2.zstring; strncpy(netbuffer->u.clientcfg.names[0], cv_playername.zstring, MAXPLAYERNAME); - strncpy(netbuffer->u.clientcfg.names[1], cv_playername2.zstring, MAXPLAYERNAME); + strncpy(netbuffer->u.clientcfg.names[1], player2name, MAXPLAYERNAME); return HSendPacket(servernode, true, 0, sizeof (clientconfig_pak)); } @@ -2600,6 +2608,8 @@ static void CL_ConnectToServer(void) } while (!(cl_mode == CL_CONNECTED && (client || (server && nodewaited <= pnumnodes)))); + if (netgame) + F_StartWaitingPlayers(); DEBFILE(va("Synchronisation Finished\n")); displayplayer = consoleplayer; @@ -2733,7 +2743,6 @@ static void Command_ClearBans(void) static void Ban_Load_File(boolean warning) { FILE *f; - size_t i; const char *address, *mask; char buffer[MAX_WADPATH]; @@ -2751,7 +2760,7 @@ static void Ban_Load_File(boolean warning) Ban_Clear(); - for (i=0; fgets(buffer, (int)sizeof(buffer), f); i++) + for (; fgets(buffer, (int)sizeof(buffer), f);) { address = strtok(buffer, " \t\r\n"); mask = strtok(NULL, " \t\r\n"); @@ -4518,6 +4527,7 @@ static void HandlePacketFromPlayer(SINT8 node) netconsole = 0; else netconsole = nodetoplayer[node]; + #ifdef PARANOIA if (netconsole >= MAXPLAYERS) I_Error("bad table nodetoplayer: node %d player %d", doomcom->remotenode, netconsole); @@ -4556,21 +4566,32 @@ static void HandlePacketFromPlayer(SINT8 node) // Update the nettics nettics[node] = realend; - // Don't do anything for packets of type NODEKEEPALIVE? - if (netconsole == -1 || netbuffer->packettype == PT_NODEKEEPALIVE - || netbuffer->packettype == PT_NODEKEEPALIVEMIS) + // This should probably still timeout though, as the node should always have a player 1 number + if (netconsole == -1) break; // As long as clients send valid ticcmds, the server can keep running, so reset the timeout /// \todo Use a separate cvar for that kind of timeout? freezetimeout[node] = I_GetTime() + connectiontimeout; + // Don't do anything for packets of type NODEKEEPALIVE? + // Sryder 2018/07/01: Update the freezetimeout still! + if (netbuffer->packettype == PT_NODEKEEPALIVE + || netbuffer->packettype == PT_NODEKEEPALIVEMIS) + break; + + // If we've alredy received a ticcmd for this tic, just submit it for the next one. + tic_t faketic = maketic; + if ((!!(netcmds[maketic % BACKUPTICS][netconsole].angleturn & TICCMD_RECEIVED)) + && (maketic - firstticstosend < BACKUPTICS - 1)) + faketic++; + // Copy ticcmd - G_MoveTiccmd(&netcmds[maketic%BACKUPTICS][netconsole], &netbuffer->u.clientpak.cmd, 1); + G_MoveTiccmd(&netcmds[faketic%BACKUPTICS][netconsole], &netbuffer->u.clientpak.cmd, 1); // Check ticcmd for "speed hacks" - if (netcmds[maketic%BACKUPTICS][netconsole].forwardmove > MAXPLMOVE || netcmds[maketic%BACKUPTICS][netconsole].forwardmove < -MAXPLMOVE - || netcmds[maketic%BACKUPTICS][netconsole].sidemove > MAXPLMOVE || netcmds[maketic%BACKUPTICS][netconsole].sidemove < -MAXPLMOVE) + if (netcmds[faketic%BACKUPTICS][netconsole].forwardmove > MAXPLMOVE || netcmds[faketic%BACKUPTICS][netconsole].forwardmove < -MAXPLMOVE + || netcmds[faketic%BACKUPTICS][netconsole].sidemove > MAXPLMOVE || netcmds[faketic%BACKUPTICS][netconsole].sidemove < -MAXPLMOVE) { CONS_Alert(CONS_WARNING, M_GetText("Illegal movement value received from node %d\n"), netconsole); //D_Clearticcmd(k); @@ -4582,9 +4603,10 @@ static void HandlePacketFromPlayer(SINT8 node) // Splitscreen cmd if ((netbuffer->packettype == PT_CLIENT2CMD || netbuffer->packettype == PT_CLIENT2MIS) && nodetoplayer2[node] >= 0) - G_MoveTiccmd(&netcmds[maketic%BACKUPTICS][(UINT8)nodetoplayer2[node]], + G_MoveTiccmd(&netcmds[faketic%BACKUPTICS][(UINT8)nodetoplayer2[node]], &netbuffer->u.client2pak.cmd2, 1); + // Check player consistancy during the level if (realstart <= gametic && realstart + BACKUPTICS - 1 > gametic && gamestate == GS_LEVEL && consistancy[realstart%BACKUPTICS] != SHORT(netbuffer->u.clientpak.consistancy) @@ -4621,6 +4643,21 @@ static void HandlePacketFromPlayer(SINT8 node) } } break; + case PT_BASICKEEPALIVE: + if (client) + break; + + // This should probably still timeout though, as the node should always have a player 1 number + if (netconsole == -1) + break; + + // If a client sends this it should mean they are done receiving the savegame + sendingsavegame[node] = false; + + // As long as clients send keep alives, the server can keep running, so reset the timeout + /// \todo Use a separate cvar for that kind of timeout? + freezetimeout[node] = I_GetTime() + connectiontimeout; + break; case PT_TEXTCMD2: // splitscreen special netconsole = nodetoplayer2[node]; /* FALLTHRU */ @@ -5047,39 +5084,66 @@ static INT16 Consistancy(void) return (INT16)(ret & 0xFFFF); } +// confusing, but this DOESN'T send PT_NODEKEEPALIVE, it sends PT_BASICKEEPALIVE +// used during wipes to tell the server that a node is still connected +static void CL_SendClientKeepAlive(void) +{ + netbuffer->packettype = PT_BASICKEEPALIVE; + + HSendPacket(servernode, false, 0, 0); +} + +static void SV_SendServerKeepAlive(void) +{ + INT32 n; + + for (n = 1; n < MAXNETNODES; n++) + { + if (nodeingame[n]) + { + netbuffer->packettype = PT_BASICKEEPALIVE; + HSendPacket(n, false, 0, 0); + } + } +} + // send the client packet to the server static void CL_SendClientCmd(void) { size_t packetsize = 0; + boolean mis = false; netbuffer->packettype = PT_CLIENTCMD; if (cl_packetmissed) - netbuffer->packettype++; + { + netbuffer->packettype = PT_CLIENTMIS; + mis = true; + } + netbuffer->u.clientpak.resendfrom = (UINT8)(neededtic & UINT8_MAX); netbuffer->u.clientpak.client_tic = (UINT8)(gametic & UINT8_MAX); if (gamestate == GS_WAITINGPLAYERS) { // Send PT_NODEKEEPALIVE packet - netbuffer->packettype += 4; + netbuffer->packettype = (mis ? PT_NODEKEEPALIVEMIS : PT_NODEKEEPALIVE); packetsize = sizeof (clientcmd_pak) - sizeof (ticcmd_t) - sizeof (INT16); HSendPacket(servernode, false, 0, packetsize); } else if (gamestate != GS_NULL && (addedtogame || dedicated)) { + packetsize = sizeof (clientcmd_pak); G_MoveTiccmd(&netbuffer->u.clientpak.cmd, &localcmds, 1); netbuffer->u.clientpak.consistancy = SHORT(consistancy[gametic%BACKUPTICS]); // Send a special packet with 2 cmd for splitscreen if (splitscreen || botingame) { - netbuffer->packettype += 2; - G_MoveTiccmd(&netbuffer->u.client2pak.cmd2, &localcmds2, 1); + netbuffer->packettype = (mis ? PT_CLIENT2MIS : PT_CLIENT2CMD); packetsize = sizeof (client2cmd_pak); + G_MoveTiccmd(&netbuffer->u.client2pak.cmd2, &localcmds2, 1); } - else - packetsize = sizeof (clientcmd_pak); HSendPacket(servernode, false, 0, packetsize); } @@ -5090,7 +5154,7 @@ static void CL_SendClientCmd(void) if (localtextcmd[0]) { netbuffer->packettype = PT_TEXTCMD; - M_Memcpy(netbuffer->u.textcmd,localtextcmd, localtextcmd[0]+1); + M_Memcpy(netbuffer->u.textcmd, localtextcmd, localtextcmd[0]+1); // All extra data have been sent if (HSendPacket(servernode, true, 0, localtextcmd[0]+1)) // Send can fail... localtextcmd[0] = 0; @@ -5470,9 +5534,82 @@ static inline void PingUpdate(void) pingmeasurecount = 1; //Reset count } +static tic_t gametime = 0; + +static void UpdatePingTable(void) +{ + INT32 i; + + if (server) + { + if (netgame && !(gametime % 35)) // update once per second. + PingUpdate(); + // update node latency values so we can take an average later. + for (i = 0; i < MAXPLAYERS; i++) + if (playeringame[i] && playernode[i] != UINT8_MAX) + realpingtable[i] += G_TicsToMilliseconds(GetLag(playernode[i])); + pingmeasurecount++; + } +} + +// Handle timeouts to prevent definitive freezes from happenning +static void HandleNodeTimeouts(void) +{ + INT32 i; + + if (server) + { + for (i = 1; i < MAXNETNODES; i++) + if (nodeingame[i] && freezetimeout[i] < I_GetTime()) + Net_ConnectionTimeout(i); + + // In case the cvar value was lowered + if (joindelay) + joindelay = min(joindelay - 1, 3 * (tic_t)cv_joindelay.value * TICRATE); + } +} + +// Keep the network alive while not advancing tics! +void NetKeepAlive(void) +{ + tic_t nowtime; + INT32 realtics; + + nowtime = I_GetTime(); + realtics = nowtime - gametime; + + // return if there's no time passed since the last call + if (realtics <= 0) // nothing new to update + return; + + UpdatePingTable(); + + GetPackets(); + +#ifdef MASTERSERVER + MasterClient_Ticker(); +#endif + + if (client) + { + // send keep alive + CL_SendClientKeepAlive(); + // No need to check for resynch because we aren't running any tics + } + else + { + SV_SendServerKeepAlive(); + } + + // No else because no tics are being run and we can't resynch during this + + Net_AckTicker(); + HandleNodeTimeouts(); + FileSendTicker(); +} + void NetUpdate(void) { - static tic_t gametime = 0; static tic_t resptime = 0; tic_t nowtime; INT32 i; @@ -5483,6 +5620,7 @@ void NetUpdate(void) if (realtics <= 0) // nothing new to update return; + if (realtics > 5) { if (server) @@ -5491,19 +5629,72 @@ void NetUpdate(void) realtics = 5; } - gametime = nowtime; - - if (server) + if (server && dedicated && gamestate == GS_LEVEL) { - if (netgame && !(gametime % 35)) // update once per second. - PingUpdate(); - // update node latency values so we can take an average later. - for (i = 0; i < MAXPLAYERS; i++) - if (playeringame[i] && playernode[i] != UINT8_MAX) - realpingtable[i] += G_TicsToMilliseconds(GetLag(playernode[i])); - pingmeasurecount++; + const tic_t dedicatedidletime = cv_dedicatedidletime.value * TICRATE; + static tic_t dedicatedidletimeprev = 0; + static tic_t dedicatedidle = 0; + + if (dedicatedidletime > 0) + { + for (i = 1; i < MAXNETNODES; ++i) + if (nodeingame[i]) + { + if (dedicatedidle >= dedicatedidletime) + { + CONS_Printf("DEDICATED: Awakening from idle (Node %d detected...)\n", i); + dedicatedidle = 0; + } + break; + } + + if (i == MAXNETNODES) + { + if (leveltime == 2) + { + // On next tick... + dedicatedidle = dedicatedidletime-1; + } + else if (dedicatedidle >= dedicatedidletime) + { + if (D_GetExistingTextcmd(gametic, 0) || D_GetExistingTextcmd(gametic+1, 0)) + { + CONS_Printf("DEDICATED: Awakening from idle (Netxcmd detected...)\n"); + dedicatedidle = 0; + } + else + { + realtics = 0; + } + } + else if ((dedicatedidle += realtics) >= dedicatedidletime) + { + const char *idlereason = "at round start"; + if (leveltime > 3) + idlereason = va("for %d seconds", dedicatedidle/TICRATE); + + CONS_Printf("DEDICATED: No nodes %s, idling...\n", idlereason); + realtics = 0; + dedicatedidle = dedicatedidletime; + } + } + } + else + { + if (dedicatedidletimeprev > 0 && dedicatedidle >= dedicatedidletimeprev) + { + CONS_Printf("DEDICATED: Awakening from idle (Idle disabled...)\n"); + } + dedicatedidle = 0; + } + + dedicatedidletimeprev = dedicatedidletime; } + gametime = nowtime; + + UpdatePingTable(); + if (client) maketic = neededtic; @@ -5534,24 +5725,25 @@ void NetUpdate(void) } else { - if (!demoplayback) + if (!demoplayback && realtics > 0) { INT32 counts; hu_redownloadinggamestate = false; + // Don't erase tics not acknowledged + counts = realtics; + firstticstosend = gametic; for (i = 0; i < MAXNETNODES; i++) - if (nodeingame[i] && nettics[i] < firstticstosend) - { + { + if (!nodeingame[i]) + continue; + if (nettics[i] < firstticstosend) firstticstosend = nettics[i]; - - if (maketic + 1 >= nettics[i] + BACKUPTICS) - Net_ConnectionTimeout(i); - } - - // Don't erase tics not acknowledged - counts = realtics; + if (maketic + counts >= nettics[i] + (BACKUPTICS - TICRATE)) + Net_ConnectionTimeout(i); + } if (maketic + counts >= firstticstosend + BACKUPTICS) counts = firstticstosend+BACKUPTICS-maketic-1; @@ -5569,20 +5761,10 @@ void NetUpdate(void) } Net_AckTicker(); - - // Handle timeouts to prevent definitive freezes from happenning - if (server) - { - for (i = 1; i < MAXNETNODES; i++) - if (nodeingame[i] && freezetimeout[i] < I_GetTime()) - Net_ConnectionTimeout(i); - - // In case the cvar value was lowered - if (joindelay) - joindelay = min(joindelay - 1, 3 * (tic_t)cv_joindelay.value * TICRATE); - } + HandleNodeTimeouts(); nowtime /= NEWTICRATERATIO; + if (nowtime > resptime) { resptime = nowtime; diff --git a/src/d_clisrv.h b/src/d_clisrv.h index 04a7b5ba2f40e648f3eae21e4f48f89d0c0aa1e9..49fb5fc1db1507a75c1b379451c27141146d1036 100644 --- a/src/d_clisrv.h +++ b/src/d_clisrv.h @@ -77,6 +77,8 @@ typedef enum PT_ASKLUAFILE, // Client telling the server they don't have the file PT_HASLUAFILE, // Client telling the server they have the file + PT_BASICKEEPALIVE,// Keep the network alive during wipes, as tics aren't advanced and NetUpdate isn't called + // Add non-PT_CANFAIL packet types here to avoid breaking MS compatibility. PT_CANFAIL, // This is kind of a priority. Anything bigger than CANFAIL @@ -398,6 +400,7 @@ extern tic_t servermaxping; extern consvar_t cv_netticbuffer, cv_allownewplayer, cv_joinnextround, cv_maxplayers, cv_joindelay, cv_rejointimeout; extern consvar_t cv_resynchattempts, cv_blamecfail; extern consvar_t cv_maxsend, cv_noticedownload, cv_downloadspeed; +extern consvar_t cv_dedicatedidletime; // Used in d_net, the only dependence tic_t ExpandTics(INT32 low, INT32 node); @@ -412,6 +415,9 @@ void SendKick(UINT8 playernum, UINT8 msg); // Create any new ticcmds and broadcast to other players. void NetUpdate(void); +// Maintain connections to nodes without timing them all out. +void NetKeepAlive(void); + void SV_StartSinglePlayerServer(void); boolean SV_SpawnServer(void); void SV_StopServer(void); diff --git a/src/d_main.c b/src/d_main.c index 5861f988655c62e9b812b13d48832c940f66ebc2..24c70843a3bd03d383651d7423914a7fd4d3f0e5 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -70,6 +70,8 @@ #include "filesrch.h" // refreshdirmenu #include "g_input.h" // tutorial mode control scheming #include "m_perfstats.h" +#include "m_random.h" +#include "command.h" #ifdef CMAKECONFIG #include "config.h" @@ -458,6 +460,13 @@ static void D_Display(void) case GS_WAITINGPLAYERS: // The clientconnect drawer is independent... + if (netgame) + { + // I don't think HOM from nothing drawing is independent... + F_WaitingPlayersDrawer(); + HU_Erase(); + HU_Drawer(); + } case GS_DEDICATEDSERVER: case GS_NULL: break; @@ -1208,6 +1217,15 @@ D_ConvertVersionNumbers (void) #endif } +static void Command_assert(void) +{ +#if !defined(NDEBUG) || defined(PARANOIA) + CONS_Printf("Yes, assertions are enabled.\n"); +#else + CONS_Printf("No, assertions are NOT enabled.\n"); +#endif +} + // // D_SRB2Main // @@ -1221,6 +1239,11 @@ void D_SRB2Main(void) /* break the version string into version numbers, for netplay */ D_ConvertVersionNumbers(); + if (!strcmp(compbranch, "")) + { + compbranch = "detached HEAD"; + } + // Print GPL notice for our console users (Linux) CONS_Printf( "\n\nSonic Robo Blast 2\n" @@ -1334,11 +1357,12 @@ void D_SRB2Main(void) snprintf(addonsdir, sizeof addonsdir, "%s%s%s", srb2home, PATHSEP, "addons"); I_mkdir(addonsdir, 0755); - // rand() needs seeded regardless of password - srand((unsigned int)time(NULL)); - rand(); - rand(); - rand(); + // seed M_Random because it is necessary; seed P_Random for scripts that + // might want to use random numbers immediately at start + if (!M_RandomSeedFromOS()) + M_RandomSeed((UINT32)time(NULL)); // less good but serviceable + + P_SetRandSeed(M_RandomizedSeed()); if (M_CheckParm("-password") && M_IsNextParm()) D_SetPassword(M_GetNextParm()); @@ -1356,6 +1380,8 @@ void D_SRB2Main(void) // Do this up here so that WADs loaded through the command line can use ExecCfg COM_Init(); + COM_AddCommand("assert", Command_assert, COM_LUA); + // Add any files specified on the command line with // "-file <file>" or "-folder <folder>" to the add-on list if (!((M_GetUrlProtocolArg() || M_CheckParm("-connect")) && !M_CheckParm("-server"))) @@ -1711,14 +1737,15 @@ void D_SRB2Main(void) // Prevent warping to nonexistent levels if (W_CheckNumForName(G_BuildMapName(pstartmap)) == LUMPERROR) I_Error("Could not warp to %s (map not found)\n", G_BuildMapName(pstartmap)); - // Prevent warping to locked levels - // ... unless you're in a dedicated server. Yes, technically this means you can view any level by - // running a dedicated server and joining it yourself, but that's better than making dedicated server's - // lives hell. - else if (!dedicated && M_MapLocked(pstartmap, serverGamedata)) - I_Error("You need to unlock this level before you can warp to it!\n"); else { + if (M_CampaignWarpIsCheat(gametype, pstartmap, serverGamedata)) + { + // If you're warping via command line, you know what you're doing. + // No need to I_Error over this. + G_SetUsedCheats(false); + } + D_MapChange(pstartmap, gametype, ultimatemode, true, 0, false, false); } } diff --git a/src/d_net.c b/src/d_net.c index 768c9ac7eb898e67967e9836695fa6c109d6748f..6d8c72942bbe8cd6714db4c6761a17e13f70bdef 100644 --- a/src/d_net.c +++ b/src/d_net.c @@ -869,6 +869,9 @@ static void DebugPrintpacket(const char *header) (UINT32)ExpandTics(netbuffer->u.clientpak.client_tic, doomcom->remotenode), (UINT32)ExpandTics (netbuffer->u.clientpak.resendfrom, doomcom->remotenode)); break; + case PT_BASICKEEPALIVE: + fprintf(debugfile, " wipetime\n"); + break; case PT_TEXTCMD: case PT_TEXTCMD2: fprintf(debugfile, " length %d\n ", netbuffer->u.textcmd[0]); diff --git a/src/d_netcmd.c b/src/d_netcmd.c index af44e53d63540ddfcde7cdb51e927522533db243..3426c1f835d8025fcb18b245a90a2fd6c4c42c70 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -49,7 +49,7 @@ #include "m_anigif.h" #include "md5.h" #include "m_perfstats.h" -#include "hardware/u_list.h" // TODO: this should be a standard utility class +#include "u_list.h" #ifdef NETGAME_DEVMODE #define CV_RESTRICT CV_NETVAR @@ -599,6 +599,7 @@ void D_RegisterServerCommands(void) CV_RegisterVar(&cv_joinnextround); CV_RegisterVar(&cv_showjoinaddress); CV_RegisterVar(&cv_blamecfail); + CV_RegisterVar(&cv_dedicatedidletime); #endif COM_AddCommand("ping", Command_Ping_f, COM_LUA); @@ -775,6 +776,8 @@ void D_RegisterClientCommands(void) CV_RegisterVar(&cv_showfocuslost); CV_RegisterVar(&cv_pauseifunfocused); + CV_RegisterVar(&cv_instantretry); + // g_input.c CV_RegisterVar(&cv_sideaxis); CV_RegisterVar(&cv_sideaxis2); @@ -873,10 +876,15 @@ void D_RegisterClientCommands(void) // screen.c CV_RegisterVar(&cv_fullscreen); CV_RegisterVar(&cv_renderview); + CV_RegisterVar(&cv_renderhitboxinterpolation); + CV_RegisterVar(&cv_renderhitboxgldepth); + CV_RegisterVar(&cv_renderhitbox); CV_RegisterVar(&cv_renderer); CV_RegisterVar(&cv_scr_depth); CV_RegisterVar(&cv_scr_width); CV_RegisterVar(&cv_scr_height); + CV_RegisterVar(&cv_scr_width_w); + CV_RegisterVar(&cv_scr_height_w); CV_RegisterVar(&cv_soundtest); @@ -1637,9 +1645,14 @@ static void Command_Playdemo_f(void) { char name[256]; - if (COM_Argc() != 2) + if (COM_Argc() < 2) { - CONS_Printf(M_GetText("playdemo <demoname>: playback a demo\n")); + CONS_Printf("playdemo <demoname> [-addfiles / -force]:\n"); + CONS_Printf(M_GetText( + "Play back a demo file. The full path from your SRB2 directory must be given.\n\n" + + "* With \"-addfiles\", any required files are added from a list contained within the demo file.\n" + "* With \"-force\", the demo is played even if the necessary files have not been added.\n")); return; } @@ -1661,6 +1674,16 @@ static void Command_Playdemo_f(void) CONS_Printf(M_GetText("Playing back demo '%s'.\n"), name); + demofileoverride = DFILE_OVERRIDE_NONE; + if (strcmp(COM_Argv(2), "-addfiles") == 0) + { + demofileoverride = DFILE_OVERRIDE_LOAD; + } + else if (strcmp(COM_Argv(2), "-force") == 0) + { + demofileoverride = DFILE_OVERRIDE_SKIP; + } + // Internal if no extension, external if one exists // If external, convert the file name to a path in SRB2's home directory if (FIL_CheckExtension(name)) @@ -1881,8 +1904,8 @@ static void Command_Map_f(void) size_t option_gametype; const char *gametypename; boolean newresetplayers; - - boolean wouldSetCheats; + boolean prevent_cheat; + boolean set_cheated; INT32 newmapnum; @@ -1903,21 +1926,34 @@ static void Command_Map_f(void) option_gametype = COM_CheckPartialParm("-g"); newresetplayers = ! COM_CheckParm("-noresetplayers"); - wouldSetCheats = - !( netgame || multiplayer ) && - !( usedCheats ); + prevent_cheat = !( usedCheats ) && !( option_force || cv_debug ); + set_cheated = false; - if (wouldSetCheats && !option_force) + if (!( netgame || multiplayer )) { - /* May want to be more descriptive? */ - CONS_Printf(M_GetText("Sorry, level change disabled in single player.\n")); - return; + if (prevent_cheat) + { + /* May want to be more descriptive? */ + CONS_Printf(M_GetText("Cheats must be enabled to level change in single player.\n")); + return; + } + else + { + set_cheated = true; + } } - if (!newresetplayers && !cv_debug) + if (!newresetplayers) { - CONS_Printf(M_GetText("DEVMODE must be enabled.\n")); - return; + if (prevent_cheat) + { + CONS_Printf(M_GetText("Cheats must be enabled to use -noresetplayers.\n")); + return; + } + else + { + set_cheated = true; + } } if (option_gametype) @@ -1925,7 +1961,7 @@ static void Command_Map_f(void) if (!multiplayer) { CONS_Printf(M_GetText( - "You can't switch gametypes in single player!\n")); + "You can't switch gametypes in single player!\n")); return; } else if (COM_Argc() < option_gametype + 2)/* no argument after? */ @@ -1938,7 +1974,9 @@ static void Command_Map_f(void) } if (!( first_option = COM_FirstOption() )) + { first_option = COM_Argc(); + } if (first_option < 2) { @@ -1961,11 +1999,6 @@ static void Command_Map_f(void) return; } - if (wouldSetCheats && option_force) - { - G_SetUsedCheats(false); - } - // new gametype value // use current one by default if (option_gametype) @@ -2007,15 +2040,13 @@ static void Command_Map_f(void) } // don't use a gametype the map doesn't support - if (cv_debug || option_force || cv_skipmapcheck.value) - fromlevelselect = false; // The player wants us to trek on anyway. Do so. // G_TOLFlag handles both multiplayer gametype and ignores it for !multiplayer - else + if (!( + mapheaderinfo[newmapnum-1] && + mapheaderinfo[newmapnum-1]->typeoflevel & G_TOLFlag(newgametype) + )) { - if (!( - mapheaderinfo[newmapnum-1] && - mapheaderinfo[newmapnum-1]->typeoflevel & G_TOLFlag(newgametype) - )) + if (prevent_cheat && !cv_skipmapcheck.value) { CONS_Alert(CONS_WARNING, M_GetText("%s (%s) doesn't support %s mode!\n(Use -force to override)\n"), realmapname, G_BuildMapName(newmapnum), (multiplayer ? gametype_cons_t[newgametype].strvalue : "Single Player")); @@ -2025,23 +2056,33 @@ static void Command_Map_f(void) } else { - fromlevelselect = - ( netgame || multiplayer ) && - newgametype == gametype && - gametypedefaultrules[newgametype] & GTR_CAMPAIGN; + // The player wants us to trek on anyway. Do so. + fromlevelselect = false; + set_cheated = ((gametypedefaultrules[newgametype] & GTR_CAMPAIGN) == GTR_CAMPAIGN); } } + else + { + fromlevelselect = + ( netgame || multiplayer ) && + newgametype == gametype && + (gametypedefaultrules[newgametype] & GTR_CAMPAIGN); + } // Prevent warping to locked levels - // ... unless you're in a dedicated server. Yes, technically this means you can view any level by - // running a dedicated server and joining it yourself, but that's better than making dedicated server's - // lives hell. - if (!dedicated && M_MapLocked(newmapnum, serverGamedata)) + if (M_CampaignWarpIsCheat(newgametype, newmapnum, serverGamedata)) { - CONS_Alert(CONS_NOTICE, M_GetText("You need to unlock this level before you can warp to it!\n")); - Z_Free(realmapname); - Z_Free(mapname); - return; + if (prevent_cheat) + { + CONS_Alert(CONS_NOTICE, M_GetText("Cheats must be enabled to warp to a locked level!\n")); + Z_Free(realmapname); + Z_Free(mapname); + return; + } + else + { + set_cheated = true; + } } // Ultimate Mode only in SP via menu @@ -2058,6 +2099,11 @@ static void Command_Map_f(void) } tutorialmode = false; // warping takes us out of tutorial mode + if (set_cheated && !usedCheats) + { + G_SetUsedCheats(false); + } + D_MapChange(newmapnum, newgametype, false, newresetplayers, 0, false, fromlevelselect); Z_Free(realmapname); @@ -2099,11 +2145,13 @@ static void Got_Mapcmd(UINT8 **cp, INT32 playernum) lastgametype = gametype; gametype = READUINT8(*cp); - G_SetGametype(gametype); // I fear putting that macro as an argument if (gametype < 0 || gametype >= gametypecount) gametype = lastgametype; - else if (gametype != lastgametype) + else + G_SetGametype(gametype); + + if (gametype != lastgametype) D_GameTypeChanged(lastgametype); // emulate consvar_t behavior for gametype skipprecutscene = ((flags & (1<<2)) != 0); @@ -2125,12 +2173,6 @@ static void Got_Mapcmd(UINT8 **cp, INT32 playernum) if (demoplayback && !timingdemo) precache = false; - if (resetplayer && !FLS) - { - emeralds = 0; - memset(&luabanks, 0, sizeof(luabanks)); - } - if (modeattacking) { SetPlayerSkinByNum(0, cv_chooseskin.value-1); @@ -2171,7 +2213,7 @@ static void Command_Pause(void) if (cv_pause.value || server || (IsPlayerAdmin(consoleplayer))) { - if (modeattacking || !(gamestate == GS_LEVEL || gamestate == GS_INTERMISSION) || (marathonmode && gamestate == GS_INTERMISSION)) + if (modeattacking || !(gamestate == GS_LEVEL || gamestate == GS_INTERMISSION || gamestate == GS_WAITINGPLAYERS) || (marathonmode && gamestate == GS_INTERMISSION)) { CONS_Printf(M_GetText("You can't pause here.\n")); return; @@ -2334,7 +2376,7 @@ static void Got_Clearscores(UINT8 **cp, INT32 playernum) } for (i = 0; i < MAXPLAYERS; i++) - players[i].score = 0; + players[i].score = players[i].recordscore = 0; CONS_Printf(M_GetText("Scores have been reset by the server.\n")); } @@ -3838,7 +3880,7 @@ static void Command_ListWADS_f(void) static void Command_Version_f(void) { #ifdef DEVELOP - CONS_Printf("Sonic Robo Blast 2 %s-%s (%s %s) ", compbranch, comprevision, compdate, comptime); + CONS_Printf("Sonic Robo Blast 2 %s %s %s (%s %s) ", compbranch, comprevision, compnote, compdate, comptime); #else CONS_Printf("Sonic Robo Blast 2 %s (%s %s %s %s) ", VERSIONSTRING, compdate, comptime, comprevision, compbranch); #endif @@ -3872,11 +3914,6 @@ static void Command_Version_f(void) else // 16-bit? 128-bit? CONS_Printf("Bits Unknown "); - // No ASM? -#ifdef NOASM - CONS_Printf("\x85" "NOASM " "\x80"); -#endif - // Debug build #ifdef _DEBUG CONS_Printf("\x85" "DEBUG " "\x80"); @@ -4242,9 +4279,6 @@ void D_GameTypeChanged(INT32 lastgametype) else if (!multiplayer && !netgame) { G_SetGametype(GT_COOP); - // These shouldn't matter anymore - //CV_Set(&cv_itemrespawntime, cv_itemrespawntime.defaultvalue); - //CV_SetValue(&cv_itemrespawn, 0); } // reset timelimit and pointlimit in race/coop, prevent stupid cheats @@ -4545,25 +4579,37 @@ static void Command_Mapmd5_f(void) CONS_Printf(M_GetText("You must be in a level to use this.\n")); } +void D_SendExitLevel(boolean cheat) +{ + UINT8 buf[8]; + UINT8 *buf_p = buf; + + WRITEUINT8(buf_p, cheat); + + SendNetXCmd(XD_EXITLEVEL, &buf, buf_p - buf); +} + static void Command_ExitLevel_f(void) { - if (!(netgame || (multiplayer && gametype != GT_COOP)) && !cv_debug) - CONS_Printf(M_GetText("This only works in a netgame.\n")); - else if (!(server || (IsPlayerAdmin(consoleplayer)))) + if (!(server || (IsPlayerAdmin(consoleplayer)))) CONS_Printf(M_GetText("Only the server or a remote admin can use this.\n")); else if (( gamestate != GS_LEVEL && gamestate != GS_CREDITS ) || demoplayback) CONS_Printf(M_GetText("You must be in a level to use this.\n")); else - SendNetXCmd(XD_EXITLEVEL, NULL, 0); + D_SendExitLevel(true); } static void Got_ExitLevelcmd(UINT8 **cp, INT32 playernum) { - (void)cp; + boolean cheat = false; + + cheat = (boolean)READUINT8(*cp); // Ignore duplicate XD_EXITLEVEL commands. if (gameaction == ga_completed) + { return; + } if (playernum != serverplayer && !IsPlayerAdmin(playernum)) { @@ -4573,6 +4619,11 @@ static void Got_ExitLevelcmd(UINT8 **cp, INT32 playernum) return; } + if (G_CoopGametype() && cheat) + { + G_SetUsedCheats(false); + } + G_ExitLevel(); } @@ -4609,6 +4660,7 @@ void Command_ExitGame_f(void) botskin = 0; cv_debug = 0; emeralds = 0; + automapactive = false; memset(&luabanks, 0, sizeof(luabanks)); if (dirmenu) diff --git a/src/d_netcmd.h b/src/d_netcmd.h index 26bf4d5c6bfbcfe9e481b35b84f38c44360ec3fa..8bbc801d0ef700868482fd982346dff5296c5e14 100644 --- a/src/d_netcmd.h +++ b/src/d_netcmd.h @@ -201,6 +201,7 @@ void D_SendPlayerConfig(void); void Command_ExitGame_f(void); void Command_Retry_f(void); void D_GameTypeChanged(INT32 lastgametype); // not a real _OnChange function anymore +void D_SendExitLevel(boolean cheat); void D_MapChange(INT32 pmapnum, INT32 pgametype, boolean pultmode, boolean presetplayers, INT32 pdelay, boolean pskipprecutscene, boolean pfromlevelselect); boolean IsPlayerAdmin(INT32 playernum); void SetAdminPlayer(INT32 playernum); diff --git a/src/d_netfil.c b/src/d_netfil.c index e60af2c2c2db2de4b7271b343a1982c40d98b2aa..3fef7568128f34bda6d8716cf5d227a19495b9de 100644 --- a/src/d_netfil.c +++ b/src/d_netfil.c @@ -498,7 +498,7 @@ INT32 CL_CheckFiles(void) CONS_Debug(DBG_NETPLAY, "searching for '%s' ", fileneeded[i].filename); // Check in already loaded files - for (j = mainwads; wadfiles[j]; j++) + for (j = mainwads; j < numwadfiles; j++) { nameonly(strcpy(wadfilename, wadfiles[j]->filename)); if (!stricmp(wadfilename, fileneeded[i].filename) && diff --git a/src/d_player.h b/src/d_player.h index 756c7141e3707c37a6f2ea0dde7a723aac12e834..7ad5b9f811962cb56ffcf55030f2ff1d2aea331d 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -249,6 +249,38 @@ typedef enum CR_FAN } carrytype_t; // pw_carry +typedef enum +{ + STR_NONE = 0, // All strong powers can stack onto each other + + // Attack powers + STR_ANIM = 0x1, // remove powers when leaving current animation + STR_PUNCH = 0x2, // frontal attack (knuckles glide) + STR_TAIL = 0x4, // rear attack + STR_STOMP = 0x8, // falling onto object (fang bounce) + STR_UPPER = 0x10, // moving upwards into object (tails fly) + STR_GUARD = 0x20, //protect against damage + STR_HEAVY = 0x40, // ignore vertical rebound + STR_DASH = 0x80, // special type for machine dashmode, automatically removes your powers when leaving dashmode + + // Environment powers + STR_WALL = 0x100, // fof busting + STR_FLOOR = 0x200, + STR_CEILING = 0x400, + STR_SPRING = 0x800, // power up hit springs + STR_SPIKE = 0x1000, // break spikes + + // Shortcuts + STR_ATTACK = STR_PUNCH|STR_TAIL|STR_STOMP|STR_UPPER, + STR_BUST = STR_WALL|STR_FLOOR|STR_CEILING, + STR_FLY = STR_ANIM|STR_UPPER, + STR_GLIDE = STR_ANIM|STR_PUNCH, + STR_TWINSPIN = STR_ANIM|STR_ATTACK|STR_BUST|STR_SPRING|STR_SPIKE, + STR_MELEE = STR_ANIM|STR_PUNCH|STR_HEAVY|STR_WALL|STR_FLOOR|STR_SPRING|STR_SPIKE, + STR_BOUNCE = STR_ANIM|STR_STOMP|STR_FLOOR, + STR_METAL = STR_DASH|STR_SPIKE +} strongtype_t; // pw_strong + // Player powers. (don't edit this comment) typedef enum { @@ -293,6 +325,8 @@ typedef enum pw_ignorelatch, // Don't grab onto CR_GENERIC, add 32768 (powers[pw_ignorelatch] & 1<<15) to avoid ALL not-NiGHTS CR_ types + pw_strong, // Additional properties for powerful attacks + NUMPOWERS } powertype_t; @@ -407,6 +441,7 @@ typedef struct player_s // playing animation. panim_t panim; + UINT8 stronganim; // For screen flashing (bright). UINT16 flashcount; @@ -418,7 +453,8 @@ typedef struct player_s INT32 skin; UINT32 availabilities; - UINT32 score; // player score + UINT32 score; // player score (total) + UINT32 recordscore; // player score (per life / map) fixed_t dashspeed; // dashing speed fixed_t normalspeed; // Normal ground diff --git a/src/d_think.h b/src/d_think.h index bdb5db3f54135545d27b0018943f0c995fffdcd4..efc1589bf62e277a67ab309f05d33d66af741865 100644 --- a/src/d_think.h +++ b/src/d_think.h @@ -17,6 +17,8 @@ #ifndef __D_THINK__ #define __D_THINK__ +#include "doomdef.h" + #ifdef __GNUG__ #pragma interface #endif @@ -49,6 +51,11 @@ typedef struct thinker_s // killough 11/98: count of how many other objects reference // this one using pointers. Used for garbage collection. INT32 references; + +#ifdef PARANOIA + INT32 debug_mobjtype; + tic_t debug_time; +#endif } thinker_t; #endif diff --git a/src/deh_lua.c b/src/deh_lua.c index 6dabb7e2d9f2b9a95dd389f9363ba05d67da6487..0b789547b266aeb238701ca6b34c4f8702c334fb 100644 --- a/src/deh_lua.c +++ b/src/deh_lua.c @@ -187,25 +187,31 @@ static inline int lib_freeslot(lua_State *L) // Arguments: mobj_t actor, int var1, int var2 static int action_call(lua_State *L) { - //actionf_t *action = lua_touserdata(L,lua_upvalueindex(1)); actionf_t *action = *((actionf_t **)luaL_checkudata(L, 1, META_ACTION)); mobj_t *actor = *((mobj_t **)luaL_checkudata(L, 2, META_MOBJ)); + var1 = (INT32)luaL_optinteger(L, 3, 0); var2 = (INT32)luaL_optinteger(L, 4, 0); + if (!actor) + { return LUA_ErrInvalid(L, "mobj_t"); + } + action->acp1(actor); return 0; } // Hardcoded A_Action name to call for super() or NULL if super() would be invalid. // Set in lua_infolib. -const char *superactions[MAXRECURSION]; -UINT8 superstack = 0; +const char *luaactions[MAX_ACTION_RECURSION]; +UINT8 luaactionstack = 0; static int lib_dummysuper(lua_State *L) { - return luaL_error(L, "Can't call super() outside of hardcode-replacing A_Action functions being called by state changes!"); // convoluted, I know. @_@;; + // TODO: Now that the restriction on only being allowed in state changes was lifted, + // it'd be nice to have super extend to Lua A_ functions too :) + return luaL_error(L, "Can't call super() outside of hardcode-replacing A_Action functions!"); } static void CacheAndPushConstant(lua_State *L, const char *name, lua_Integer value) @@ -271,8 +277,8 @@ static int ScanConstants(lua_State *L, boolean mathlib, const char *word) } else if (fastncmp("MTF_", word, 4)) { p = word+4; - for (i = 0; i < 4; i++) - if (MAPTHINGFLAG_LIST[i] && fastcmp(p, MAPTHINGFLAG_LIST[i])) { + for (i = 0; MAPTHINGFLAG_LIST[i]; i++) + if (fastcmp(p, MAPTHINGFLAG_LIST[i])) { CacheAndPushConstant(L, word, ((lua_Integer)1<<i)); return 1; } @@ -606,42 +612,62 @@ static inline int lib_getenum(lua_State *L) if (!mathlib && fastncmp("A_",word,2)) { char *caps; - // Try to get a Lua action first. - /// \todo Push a closure that sets superactions[] and superstack. + + // Hardcoded actions come first. + // Trying to call them will invoke LUA_CallAction, which will handle super properly. + // Retrieving them from this metatable allows them to be case-insensitive! + for (i = 0; actionpointers[i].name; i++) + { + if (fasticmp(word, actionpointers[i].name)) + { + // We push the actionf_t* itself as userdata! + LUA_PushUserdata(L, &actionpointers[i].action, META_ACTION); + return 1; + } + } + + // Now try to get Lua actions. + /// \todo Push a closure that sets luaactions[] and luaactionstack. + /// This would be part one of a step to get super functions working for custom A_ functions. + /// Custom functions. lua_getfield(L, LUA_REGISTRYINDEX, LREG_ACTIONS); + // actions are stored in all uppercase. caps = Z_StrDup(word); strupr(caps); lua_getfield(L, -1, caps); Z_Free(caps); + if (!lua_isnil(L, -1)) + { return 1; // Success! :D That was easy. + } + // Welp, that failed. lua_pop(L, 2); // pop nil and LREG_ACTIONS - - // Hardcoded actions as callable Lua functions! - // Retrieving them from this metatable allows them to be case-insensitive! - for (i = 0; actionpointers[i].name; i++) - if (fasticmp(word, actionpointers[i].name)) { - // We push the actionf_t* itself as userdata! - LUA_PushUserdata(L, &actionpointers[i].action, META_ACTION); - return 1; - } return 0; } else if (!mathlib && fastcmp("super",word)) { - if (!superstack) + if (!luaactionstack) { + // Not in A_ action routine lua_pushcfunction(L, lib_dummysuper); return 1; } + for (i = 0; actionpointers[i].name; i++) - if (fasticmp(superactions[superstack-1], actionpointers[i].name)) { + { + if (fasticmp(luaactions[luaactionstack-1], actionpointers[i].name)) + { LUA_PushUserdata(L, &actionpointers[i].action, META_ACTION); return 1; } - return 0; + } + + // Not a hardcoded A_ action. + lua_pushcfunction(L, lib_dummysuper); + return 1; } else if ((!mathlib && LUA_PushGlobals(L, word)) || ScanConstants(L, mathlib, word)) return 1; diff --git a/src/deh_soc.c b/src/deh_soc.c index 8dd849daf428ad1dce95dd52d30a105c5fbe2b3b..2193cd875cd00898c035c0d47d030f189045572c 100644 --- a/src/deh_soc.c +++ b/src/deh_soc.c @@ -912,7 +912,7 @@ static void readspriteframe(MYFILE *f, spriteinfo_t *sprinfo, UINT8 frame) else if (fastcmp(word, "YPIVOT")) sprinfo->pivot[frame].y = value; else if (fastcmp(word, "ROTAXIS")) - sprinfo->pivot[frame].rotaxis = value; + deh_warning("SpriteInfo: ROTAXIS is deprecated and will be removed."); else { f->curpos = lastline; diff --git a/src/deh_tables.c b/src/deh_tables.c index c3b2cfccd64aae8601e045c4587d3b435036ab97..0801cf935a184d5a30d0edd215fe90e2b68db737 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -198,6 +198,7 @@ actionpointer_t actionpointers[] = {{A_Boss3TakeDamage}, "A_BOSS3TAKEDAMAGE"}, {{A_Boss3Path}, "A_BOSS3PATH"}, {{A_Boss3ShockThink}, "A_BOSS3SHOCKTHINK"}, + {{A_Shockwave}, "A_SHOCKWAVE"}, {{A_LinedefExecute}, "A_LINEDEFEXECUTE"}, {{A_LinedefExecuteFromArg}, "A_LINEDEFEXECUTEFROMARG"}, {{A_PlaySeeSound}, "A_PLAYSEESOUND"}, @@ -4409,11 +4410,12 @@ const char *const MOBJEFLAG_LIST[] = { NULL }; -const char *const MAPTHINGFLAG_LIST[4] = { +const char *const MAPTHINGFLAG_LIST[] = { "EXTRA", // Extra flag for objects. "OBJECTFLIP", // Reverse gravity flag for objects. "OBJECTSPECIAL", // Special flag used with certain objects. - "AMBUSH" // Deaf monsters/do not react to sound. + "AMBUSH", // Deaf monsters/do not react to sound. + "ABSOLUTEZ" // Absolute spawn height flag for objects. }; const char *const PLAYERFLAG_LIST[] = { @@ -4550,6 +4552,7 @@ const char *const MSF_LIST[] = { const char *const SSF_LIST[] = { "OUTERSPACE", "DOUBLESTEPUP", + "NOSTEPDOWN", "WINDCURRENT", "CONVEYOR", "SPEEDPAD", @@ -4566,6 +4569,8 @@ const char *const SSF_LIST[] = { "ZOOMTUBEEND", "FINISHLINE", "ROPEHANG", + "JUMPFLIP", + "GRAVITYOVERRIDE", NULL }; @@ -4609,66 +4614,111 @@ const char *COLOR_ENUMS[] = { // Desaturated "AETHER", // SKINCOLOR_AETHER, "SLATE", // SKINCOLOR_SLATE, + "MOONSTONE", // SKINCOLOR_MOONSTONE, "BLUEBELL", // SKINCOLOR_BLUEBELL, "PINK", // SKINCOLOR_PINK, + "ROSEWOOD", // SKINCOLOR_ROSEWOOD, "YOGURT", // SKINCOLOR_YOGURT, + "LATTE", // SKINCOLOR_LATTE, "BROWN", // SKINCOLOR_BROWN, + "BOULDER", // SKINCOLOR_BOULDER "BRONZE", // SKINCOLOR_BRONZE, - "TAN", // SKINCOLOR_TAN, + "SEPIA", // SKINCOLOR_SEPIA, + "ECRU", // SKINCOLOR_ECRU, + "TAN", // SKINCOLOR_TAN, "BEIGE", // SKINCOLOR_BEIGE, + "ROSEBUSH", // SKINCOLOR_ROSEBUSH, "MOSS", // SKINCOLOR_MOSS, "AZURE", // SKINCOLOR_AZURE, - "LAVENDER", // SKINCOLOR_LAVENDER, + "EGGPLANT", // SKINCOLOR_EGGPLANT, + "LAVENDER", // SKINCOLOR_LAVENDER, // Viv's vivid colours (toast 21/07/17) + // Tweaks & additions (Lach, sphere, Alice, MotorRoach 26/10/22) "RUBY", // SKINCOLOR_RUBY, + "CHERRY", // SKINCOLOR_CHERRY, "SALMON", // SKINCOLOR_SALMON, + "PEPPER", // SKINCOLOR_PEPPER, "RED", // SKINCOLOR_RED, "CRIMSON", // SKINCOLOR_CRIMSON, "FLAME", // SKINCOLOR_FLAME, + "GARNET", // SKINCOLOR_GARNET, "KETCHUP", // SKINCOLOR_KETCHUP, "PEACHY", // SKINCOLOR_PEACHY, "QUAIL", // SKINCOLOR_QUAIL, + "FOUNDATION", // SKINCOLOR_FOUNDATION, "SUNSET", // SKINCOLOR_SUNSET, "COPPER", // SKINCOLOR_COPPER, "APRICOT", // SKINCOLOR_APRICOT, "ORANGE", // SKINCOLOR_ORANGE, "RUST", // SKINCOLOR_RUST, + "TANGERINE", // SKINCOLOR_TANGERINE, + "TOPAZ", // SKINCOLOR_TOPAZ, "GOLD", // SKINCOLOR_GOLD, "SANDY", // SKINCOLOR_SANDY, + "GOLDENROD", // SKINCOLOR_GOLDENROD, "YELLOW", // SKINCOLOR_YELLOW, "OLIVE", // SKINCOLOR_OLIVE, + "PEAR", // SKINCOLOR_PEAR, + "LEMON", // SKINCOLOR_LEMON, "LIME", // SKINCOLOR_LIME, "PERIDOT", // SKINCOLOR_PERIDOT, "APPLE", // SKINCOLOR_APPLE, + "HEADLIGHT", // SKINCOLOR_HEADLIGHT, + "CHARTREUSE", // SKINCOLOR_CHARTREUSE, "GREEN", // SKINCOLOR_GREEN, "FOREST", // SKINCOLOR_FOREST, - "EMERALD", // SKINCOLOR_EMERALD, + "SHAMROCK", // SKINCOLOR_SHAMROCK, + "JADE", // SKINCOLOR_JADE, "MINT", // SKINCOLOR_MINT, + "MASTER", // SKINCOLOR_MASTER, + "EMERALD", // SKINCOLOR_EMERALD, "SEAFOAM", // SKINCOLOR_SEAFOAM, + "ISLAND", // SKINCOLOR_ISLAND, + "BOTTLE", // SKINCOLOR_BOTTLE, "AQUA", // SKINCOLOR_AQUA, "TEAL", // SKINCOLOR_TEAL, + "OCEAN", // SKINCOLOR_OCEAN, "WAVE", // SKINCOLOR_WAVE, "CYAN", // SKINCOLOR_CYAN, + "TURQUOISE", // SKINCOLOR_TURQUOISE, + "AQUAMARINE", // SKINCOLOR_AQUAMARINE, "SKY", // SKINCOLOR_SKY, + "MARINE", // SKINCOLOR_MARINE, "CERULEAN", // SKINCOLOR_CERULEAN, + "DREAM", // SKINCOLOR_DREAM, "ICY", // SKINCOLOR_ICY, + "DAYBREAK", // SKINCOLOR_DAYBREAK, "SAPPHIRE", // SKINCOLOR_SAPPHIRE, + "ARCTIC", // SKINCOLOR_ARCTIC, "CORNFLOWER", // SKINCOLOR_CORNFLOWER, "BLUE", // SKINCOLOR_BLUE, "COBALT", // SKINCOLOR_COBALT, + "MIDNIGHT", // SKINCOLOR_MIDNIGHT, + "GALAXY", // SKINCOLOR_GALAXY, "VAPOR", // SKINCOLOR_VAPOR, "DUSK", // SKINCOLOR_DUSK, + "MAJESTY", // SKINCOLOR_MAJESTY, "PASTEL", // SKINCOLOR_PASTEL, "PURPLE", // SKINCOLOR_PURPLE, - "BUBBLEGUM", // SKINCOLOR_BUBBLEGUM, + "NOBLE", // SKINCOLOR_NOBLE, + "FUCHSIA", // SKINCOLOR_FUCHSIA, + "BUBBLEGUM", // SKINCOLOR_BUBBLEGUM, + "SIBERITE", // SKINCOLOR_SIBERITE, "MAGENTA", // SKINCOLOR_MAGENTA, "NEON", // SKINCOLOR_NEON, "VIOLET", // SKINCOLOR_VIOLET, + "ROYAL", // SKINCOLOR_ROYAL, "LILAC", // SKINCOLOR_LILAC, + "MAUVE", // SKINCOLOR_MAUVE, + "EVENTIDE", // SKINCOLOR_EVENTIDE, "PLUM", // SKINCOLOR_PLUM, "RASPBERRY", // SKINCOLOR_RASPBERRY, + "TAFFY", // SKINCOLOR_TAFFY, "ROSY", // SKINCOLOR_ROSY, + "FANCY", // SKINCOLOR_FANCY, + "SANGRIA", // SKINCOLOR_SANGRIA, + "VOLCANIC", // SKINCOLOR_VOLCANIC, // Super special awesome Super flashing colors! "SUPERSILVER1", // SKINCOLOR_SUPERSILVER1 @@ -4768,7 +4818,9 @@ const char *const POWERS_LIST[] = { "JUSTLAUNCHED", - "IGNORELATCH" + "IGNORELATCH", + + "STRONG" }; const char *const HUDITEMS_LIST[] = { @@ -5121,6 +5173,30 @@ struct int_const_s const INT_CONST[] = { {"CR_DUSTDEVIL",CR_DUSTDEVIL}, {"CR_FAN",CR_FAN}, + // Strong powers + {"STR_NONE",STR_NONE}, + {"STR_ANIM",STR_ANIM}, + {"STR_PUNCH",STR_PUNCH}, + {"STR_TAIL",STR_TAIL}, + {"STR_STOMP",STR_STOMP}, + {"STR_UPPER",STR_UPPER}, + {"STR_GUARD",STR_GUARD}, + {"STR_HEAVY",STR_HEAVY}, + {"STR_DASH",STR_DASH}, + {"STR_WALL",STR_WALL}, + {"STR_FLOOR",STR_FLOOR}, + {"STR_CEILING",STR_CEILING}, + {"STR_SPRING",STR_SPRING}, + {"STR_SPIKE",STR_SPIKE}, + {"STR_ATTACK",STR_ATTACK}, + {"STR_BUST",STR_BUST}, + {"STR_FLY",STR_FLY}, + {"STR_GLIDE",STR_GLIDE}, + {"STR_TWINSPIN",STR_TWINSPIN}, + {"STR_MELEE",STR_MELEE}, + {"STR_BOUNCE",STR_BOUNCE}, + {"STR_METAL",STR_METAL}, + // Ring weapons (ringweapons_t) // Useful for A_GiveWeapon {"RW_AUTO",RW_AUTO}, diff --git a/src/deh_tables.h b/src/deh_tables.h index 8943ab71a4a2c29e5740f707ee240c6d6f0bba7c..42716f9b4bd271c98aca83737f419670d862d7e5 100644 --- a/src/deh_tables.h +++ b/src/deh_tables.h @@ -30,6 +30,7 @@ extern UINT8 used_spr[(NUMSPRITEFREESLOTS / 8) + 1]; // Bitwise flag for sprite memset(FREE_MOBJS,0,sizeof(char *) * NUMMOBJFREESLOTS);\ memset(FREE_SKINCOLORS,0,sizeof(char *) * NUMCOLORFREESLOTS);\ memset(used_spr,0,sizeof(UINT8) * ((NUMSPRITEFREESLOTS / 8) + 1));\ + memset(actionsoverridden, LUA_REFNIL, sizeof(actionsoverridden));\ } struct flickytypes_s { @@ -61,7 +62,7 @@ extern const char *const MOBJTYPE_LIST[]; extern const char *const MOBJFLAG_LIST[]; extern const char *const MOBJFLAG2_LIST[]; // \tMF2_(\S+).*// (.+) --> \t"\1", // \2 extern const char *const MOBJEFLAG_LIST[]; -extern const char *const MAPTHINGFLAG_LIST[4]; +extern const char *const MAPTHINGFLAG_LIST[]; extern const char *const PLAYERFLAG_LIST[]; extern const char *const GAMETYPERULE_LIST[]; extern const char *const ML_LIST[]; // Linedef flags diff --git a/src/dehacked.h b/src/dehacked.h index 902404df7e0b1dffa533a3222554c2e564646aa9..b39f090352adf6b7e7e5d744d5644e78da48ee58 100644 --- a/src/dehacked.h +++ b/src/dehacked.h @@ -40,9 +40,9 @@ extern boolean gamedataadded; extern boolean titlechanged; extern boolean introchanged; -#define MAXRECURSION 30 -extern const char *superactions[MAXRECURSION]; -extern UINT8 superstack; +#define MAX_ACTION_RECURSION 30 +extern const char *luaactions[MAX_ACTION_RECURSION]; +extern UINT8 luaactionstack; // If the dehacked patch does not match this version, we throw a warning #define PATCHVERSION 220 diff --git a/src/doomdata.h b/src/doomdata.h index 4c5bdefaf968f073462ab37b295cf85b5185954e..276e03297b6f0d453ad0d0c65fc8bd9196d9680c 100644 --- a/src/doomdata.h +++ b/src/doomdata.h @@ -62,6 +62,10 @@ enum #define MTF_AMBUSH 8 // Do not use bit five or after, as they are used for object z-offsets. +// Unless it's exclusive to UDMF. + +// Flag to use Z as absolute spawn height, ignoring the floor and ceiling. +#define MTF_ABSOLUTEZ 16 #if defined(_MSC_VER) #pragma pack(1) @@ -211,6 +215,7 @@ typedef struct UINT8 extrainfo; taglist_t tags; fixed_t scale; + fixed_t spritexscale, spriteyscale; INT32 args[NUMMAPTHINGARGS]; char *stringargs[NUMMAPTHINGSTRINGARGS]; struct mobj_s *mobj; diff --git a/src/doomdef.h b/src/doomdef.h index d521d4fbbb0ef978edddd6696328b45de64c55ab..45d6645faa0bc0ff884e11cb5722e4967f679560 100644 --- a/src/doomdef.h +++ b/src/doomdef.h @@ -108,6 +108,14 @@ FILE *fopenfile(const char*, const char*); //#define NOMD5 +// If you don't disable ALL debug first, you get ALL debug enabled +#if !defined (NDEBUG) +#define PACKETDROP +#define PARANOIA +#define RANGECHECK +#define ZDEBUG +#endif + // Uncheck this to compile debugging code //#define RANGECHECK //#ifndef PARANOIA @@ -261,66 +269,111 @@ typedef enum // Desaturated SKINCOLOR_AETHER, SKINCOLOR_SLATE, + SKINCOLOR_MOONSTONE, SKINCOLOR_BLUEBELL, SKINCOLOR_PINK, + SKINCOLOR_ROSEWOOD, SKINCOLOR_YOGURT, + SKINCOLOR_LATTE, SKINCOLOR_BROWN, + SKINCOLOR_BOULDER, SKINCOLOR_BRONZE, + SKINCOLOR_SEPIA, + SKINCOLOR_ECRU, SKINCOLOR_TAN, SKINCOLOR_BEIGE, + SKINCOLOR_ROSEBUSH, SKINCOLOR_MOSS, SKINCOLOR_AZURE, + SKINCOLOR_EGGPLANT, SKINCOLOR_LAVENDER, // Viv's vivid colours (toast 21/07/17) + // Tweaks & additions (Lach, sphere, Alice, MotorRoach 26/10/22) SKINCOLOR_RUBY, + SKINCOLOR_CHERRY, SKINCOLOR_SALMON, + SKINCOLOR_PEPPER, SKINCOLOR_RED, SKINCOLOR_CRIMSON, SKINCOLOR_FLAME, + SKINCOLOR_GARNET, SKINCOLOR_KETCHUP, SKINCOLOR_PEACHY, SKINCOLOR_QUAIL, + SKINCOLOR_FOUNDATION, SKINCOLOR_SUNSET, SKINCOLOR_COPPER, SKINCOLOR_APRICOT, SKINCOLOR_ORANGE, SKINCOLOR_RUST, + SKINCOLOR_TANGERINE, + SKINCOLOR_TOPAZ, SKINCOLOR_GOLD, SKINCOLOR_SANDY, + SKINCOLOR_GOLDENROD, SKINCOLOR_YELLOW, SKINCOLOR_OLIVE, + SKINCOLOR_PEAR, + SKINCOLOR_LEMON, SKINCOLOR_LIME, SKINCOLOR_PERIDOT, SKINCOLOR_APPLE, + SKINCOLOR_HEADLIGHT, + SKINCOLOR_CHARTREUSE, SKINCOLOR_GREEN, SKINCOLOR_FOREST, - SKINCOLOR_EMERALD, + SKINCOLOR_SHAMROCK, + SKINCOLOR_JADE, SKINCOLOR_MINT, + SKINCOLOR_MASTER, + SKINCOLOR_EMERALD, SKINCOLOR_SEAFOAM, + SKINCOLOR_ISLAND, + SKINCOLOR_BOTTLE, SKINCOLOR_AQUA, SKINCOLOR_TEAL, + SKINCOLOR_OCEAN, SKINCOLOR_WAVE, SKINCOLOR_CYAN, + SKINCOLOR_TURQUOISE, + SKINCOLOR_AQUAMARINE, SKINCOLOR_SKY, + SKINCOLOR_MARINE, SKINCOLOR_CERULEAN, + SKINCOLOR_DREAM, SKINCOLOR_ICY, + SKINCOLOR_DAYBREAK, SKINCOLOR_SAPPHIRE, // sweet mother, i cannot weave – slender aphrodite has overcome me with longing for a girl + SKINCOLOR_ARCTIC, SKINCOLOR_CORNFLOWER, SKINCOLOR_BLUE, SKINCOLOR_COBALT, + SKINCOLOR_MIDNIGHT, + SKINCOLOR_GALAXY, SKINCOLOR_VAPOR, SKINCOLOR_DUSK, + SKINCOLOR_MAJESTY, SKINCOLOR_PASTEL, SKINCOLOR_PURPLE, + SKINCOLOR_NOBLE, + SKINCOLOR_FUCHSIA, SKINCOLOR_BUBBLEGUM, + SKINCOLOR_SIBERITE, SKINCOLOR_MAGENTA, SKINCOLOR_NEON, SKINCOLOR_VIOLET, + SKINCOLOR_ROYAL, SKINCOLOR_LILAC, + SKINCOLOR_MAUVE, + SKINCOLOR_EVENTIDE, SKINCOLOR_PLUM, SKINCOLOR_RASPBERRY, + SKINCOLOR_TAFFY, SKINCOLOR_ROSY, + SKINCOLOR_FANCY, + SKINCOLOR_SANGRIA, + SKINCOLOR_VOLCANIC, FIRSTSUPERCOLOR, @@ -592,7 +645,16 @@ UINT32 quickncasehash (const char *p, size_t n) #define PUNCTUATION "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~" // Compile date and time and revision. -extern const char *compdate, *comptime, *comprevision, *compbranch; +extern const char + *compdate, + *comptime, + *comprevision, + *compbranch, + *compnote, + *comptype; +extern int + compuncommitted, + compoptimized; // Disabled code and code under testing // None of these that are disabled in the normal build are guaranteed to work perfectly diff --git a/src/doomstat.h b/src/doomstat.h index a812cc304f6e0b19cab8f2fecf37868264ed9b16..fdd0d0b834ff58601cce67881e399709f9277d8b 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -249,6 +249,7 @@ extern textprompt_t *textprompts[MAX_PROMPTS]; // For the Custom Exit linedef. extern INT16 nextmapoverride; extern UINT8 skipstats; +extern INT16 nextgametype; extern UINT32 ssspheres; // Total # of spheres in a level diff --git a/src/doomtype.h b/src/doomtype.h index f6c236e20bf3979ec9f1ef2353ed80b647e45b73..4070e346a1b13dd516a91504f056cebc4defb20d 100644 --- a/src/doomtype.h +++ b/src/doomtype.h @@ -17,6 +17,10 @@ #ifndef __DOOMTYPE__ #define __DOOMTYPE__ +#ifdef __cplusplus +extern "C" { +#endif + #ifdef _WIN32 //#define WIN32_LEAN_AND_MEAN #define RPC_NO_WINDOWS_H @@ -78,7 +82,9 @@ typedef long ssize_t; #endif #define strncasecmp strnicmp #define strcasecmp stricmp +#ifndef __cplusplus #define inline __inline +#endif #elif defined (__WATCOMC__) #include <dos.h> #include <sys\types.h> @@ -94,32 +100,26 @@ typedef long ssize_t; #define strnicmp(x,y,n) strncasecmp(x,y,n) #endif -char *strcasestr(const char *in, const char *what); +char *nongnu_strcasestr(const char *in, const char *what); +#ifndef _GNU_SOURCE +#define strcasestr nongnu_strcasestr +#endif #define stristr strcasestr int startswith (const char *base, const char *tag); int endswith (const char *base, const char *tag); -#if defined (macintosh) //|| defined (__APPLE__) //skip all boolean/Boolean crap - #define true 1 - #define false 0 - #define min(x,y) (((x)<(y)) ? (x) : (y)) - #define max(x,y) (((x)>(y)) ? (x) : (y)) - -#ifdef macintosh - #define stricmp strcmp - #define strnicmp strncmp +#if defined (_WIN32) || defined (__HAIKU__) +#define HAVE_DOSSTR_FUNCS #endif - #define boolean INT32 - - #ifndef O_BINARY - #define O_BINARY 0 +#if defined (__APPLE__) + #define SRB2_HAVE_STRLCPY +#elif defined (__GLIBC_PREREQ) + // glibc 2.38: added strlcpy and strlcat to _DEFAULT_SOURCE + #if __GLIBC_PREREQ(2, 38) + #define SRB2_HAVE_STRLCPY #endif -#endif //macintosh - -#if defined (_WIN32) || defined (__HAIKU__) -#define HAVE_DOSSTR_FUNCS #endif #ifndef HAVE_DOSSTR_FUNCS @@ -129,7 +129,7 @@ int strlwr(char *n); // from dosstr.c #include <stddef.h> // for size_t -#ifndef __APPLE__ +#ifndef SRB2_HAVE_STRLCPY size_t strlcat(char *dst, const char *src, size_t siz); size_t strlcpy(char *dst, const char *src, size_t siz); #endif @@ -144,22 +144,24 @@ size_t strlcpy(char *dst, const char *src, size_t siz); /* Boolean type definition */ -// \note __BYTEBOOL__ used to be set above if "macintosh" was defined, -// if macintosh's version of boolean type isn't needed anymore, then isn't this macro pointless now? -#ifndef __BYTEBOOL__ - #define __BYTEBOOL__ - - //faB: clean that up !! - #if defined( _MSC_VER) && (_MSC_VER >= 1800) // MSVC 2013 and forward - #include "stdbool.h" - #elif defined (_WIN32) - #define false FALSE // use windows types - #define true TRUE - #define boolean BOOL - #else - typedef enum {false, true} boolean; - #endif -#endif // __BYTEBOOL__ +// Note: C++ bool and C99/C11 _Bool are NOT compatible. +// Historically, boolean was win32 BOOL on Windows. For equivalence, it's now +// int32_t. "true" and "false" are only declared for C code; in C++, conversion +// between "bool" and "int32_t" takes over. +#ifndef _WIN32 +typedef int32_t boolean; +#else +#define boolean BOOL +#endif + +#ifndef __cplusplus +#ifndef _WIN32 +enum {false = 0, true = 1}; +#else +#define false FALSE +#define true TRUE +#endif +#endif /* 7.18.2.1 Limits of exact-width integer types */ @@ -387,4 +389,8 @@ unset_bit_array (bitarray_t * const array, const int value) typedef UINT64 precise_t; +#ifdef __cplusplus +} // extern "C" +#endif + #endif //__DOOMTYPE__ diff --git a/src/dummy/i_system.c b/src/dummy/i_system.c index 8556c0248651d04469b4c1114a780bba47824421..70e1ef4ec2b7aba9699731c0d743733750bc26fc 100644 --- a/src/dummy/i_system.c +++ b/src/dummy/i_system.c @@ -14,13 +14,18 @@ size_t I_GetFreeMem(size_t *total) return 0; } -void I_Sleep(UINT32 ms){} +void I_Sleep(UINT32 ms) +{ + (void)ms; +} -precise_t I_GetPreciseTime(void) { +precise_t I_GetPreciseTime(void) +{ return 0; } -UINT64 I_GetPrecisePrecision(void) { +UINT64 I_GetPrecisePrecision(void) +{ return 1000000; } @@ -180,7 +185,14 @@ const char *I_ClipboardPaste(void) return NULL; } -void I_RegisterSysCommands(void) {} +size_t I_GetRandomBytes(char *destination, size_t amount) +{ + (void)destination; + (void)amount; + return 0; +} + +void I_RegisterSysCommands(void){} void I_GetCursorPosition(INT32 *x, INT32 *y) { diff --git a/src/dummy/i_video.c b/src/dummy/i_video.c index 3b0a12a328df587e1cd20d0312cf96ce6c8df847..bb796b6767a1d55990209ba46cd8245377b013d9 100644 --- a/src/dummy/i_video.c +++ b/src/dummy/i_video.c @@ -57,6 +57,8 @@ const char *VID_GetModeName(INT32 modenum) return NULL; } +UINT32 I_GetRefreshRate(void) { return 35; } + void I_UpdateNoBlit(void){} void I_FinishUpdate(void){} diff --git a/src/f_finale.c b/src/f_finale.c index f529b4564723ea850d5d97b8a57a3b2c05f07177..91c06b31652ab2902668fdb82009519ee6811108 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -224,7 +224,6 @@ static INT32 cutscene_writeptr = 0; static INT32 cutscene_textcount = 0; static INT32 cutscene_textspeed = 0; static UINT8 cutscene_boostspeed = 0; -static tic_t cutscene_lasttextwrite = 0; // STJR Intro char stjrintro[9] = "STJRI000"; @@ -240,11 +239,6 @@ static UINT8 F_WriteText(void) { INT32 numtowrite = 1; const char *c; - tic_t ltw = I_GetTime(); - - if (cutscene_lasttextwrite == ltw) - return 1; // singletics prevention - cutscene_lasttextwrite = ltw; if (cutscene_boostspeed) { @@ -1068,12 +1062,14 @@ static const char *credits[] = { "\"Golden\"", "Vivian \"toaster\" Grannell", "Julio \"Chaos Zero 64\" Guir", + "\"Hanicef\"", "\"Hannu_Hanhi\"", // For many OpenGL performance improvements! "Kepa \"Nev3r\" Iceta", "Thomas \"Shadow Hog\" Igoe", "Iestyn \"Monster Iestyn\" Jealous", "\"Kaito Sinclaire\"", "\"Kalaron\"", // Coded some of Sryder13's collection of OpenGL fixes, especially fog + "\"katsy\"", "Ronald \"Furyhunter\" Kinard", // The SDL2 port "\"Lat'\"", // SRB2-CHAT, the chat window from Kart "\"LZA\"", @@ -1096,6 +1092,7 @@ static const char *credits[] = { "Ben \"Cue\" Woodford", "Lachlan \"Lach\" Wright", "Marco \"mazmazz\" Zafra", + "\"Zwip-Zwap Zapony\"", "", "\1Art", "Victor \"VAdaPEGA\" Ara\x1Fjo", // Araújo -- sorry for our limited font! D: @@ -1203,6 +1200,7 @@ static const char *credits[] = { "FreeDoom Project", // Used some of the mancubus and rocket launcher sprites for Brak "Kart Krew", "Alex \"MistaED\" Fuller", + "Howard Drossin", // Virtual Sonic - Sonic & Knuckles Theme "Pascal \"CodeImp\" vd Heiden", // Doom Builder developer "Randi Heit (<!>)", // For their MSPaint <!> sprite that we nicked "Simon \"sirjuddington\" Judd", // SLADE developer @@ -1280,14 +1278,23 @@ void F_CreditDrawer(void) UINT16 i; INT16 zagpos = (timetonext - finalecount - animtimer) % 32; fixed_t y = (80<<FRACBITS) - (animtimer<<FRACBITS>>1); + UINT8 colornum; + const UINT8 *colormap; + + if (players[consoleplayer].skincolor) + colornum = players[consoleplayer].skincolor; + else + colornum = cv_playercolor.value; + + colormap = R_GetTranslationColormap(TC_DEFAULT, colornum, GTC_CACHE); V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 31); // Zig Zagz - V_DrawScaledPatch(-16, zagpos, V_SNAPTOLEFT, W_CachePatchName("LTZIGZAG", PU_PATCH_LOWPRIORITY)); - V_DrawScaledPatch(-16, zagpos - 320, V_SNAPTOLEFT, W_CachePatchName("LTZIGZAG", PU_PATCH_LOWPRIORITY)); - V_DrawScaledPatch(BASEVIDWIDTH + 16, zagpos, V_SNAPTORIGHT|V_FLIP, W_CachePatchName("LTZIGZAG", PU_PATCH_LOWPRIORITY)); - V_DrawScaledPatch(BASEVIDWIDTH + 16, zagpos - 320, V_SNAPTORIGHT|V_FLIP, W_CachePatchName("LTZIGZAG", PU_PATCH_LOWPRIORITY)); + V_DrawFixedPatch(-16*FRACUNIT, zagpos<<FRACBITS, FRACUNIT, V_SNAPTOLEFT, W_CachePatchName("LTZIGZAG", PU_PATCH_LOWPRIORITY), colormap); + V_DrawFixedPatch(-16*FRACUNIT, (zagpos - 320)<<FRACBITS, FRACUNIT, V_SNAPTOLEFT, W_CachePatchName("LTZIGZAG", PU_PATCH_LOWPRIORITY), colormap); + V_DrawFixedPatch((BASEVIDWIDTH + 16)*FRACUNIT, zagpos<<FRACBITS, FRACUNIT, V_SNAPTORIGHT|V_FLIP, W_CachePatchName("LTZIGZAG", PU_PATCH_LOWPRIORITY), colormap); + V_DrawFixedPatch((BASEVIDWIDTH + 16)*FRACUNIT, (zagpos - 320)<<FRACBITS, FRACUNIT, V_SNAPTORIGHT|V_FLIP, W_CachePatchName("LTZIGZAG", PU_PATCH_LOWPRIORITY), colormap); // Draw background pictures first for (i = 0; credits_pics[i].patch; i++) @@ -1641,7 +1648,7 @@ void F_GameEvaluationTicker(void) sparklloop = 0; } - if (finalecount == 5*TICRATE) + if (G_CoopGametype() && !stagefailed && finalecount == 5*TICRATE) { serverGamedata->timesBeaten++; clientGamedata->timesBeaten++; @@ -2253,7 +2260,7 @@ void F_InitMenuPresValues(void) curfadevalue = 16; curbgcolor = -1; curbgxspeed = (gamestate == GS_TIMEATTACK) ? 0 : titlescrollxspeed; - curbgyspeed = (gamestate == GS_TIMEATTACK) ? 22 : titlescrollyspeed; + curbgyspeed = (gamestate == GS_TIMEATTACK) ? 18 : titlescrollyspeed; curbghide = (gamestate == GS_TIMEATTACK) ? false : true; curhidepics = hidetitlepics; @@ -3506,6 +3513,7 @@ void F_TitleScreenTicker(boolean run) } titledemo = true; + demofileoverride = DFILE_OVERRIDE_NONE; G_DoPlayDemo(dname); } } @@ -4666,3 +4674,36 @@ void F_TextPromptTicker(void) animtimer--; } } + +// ================ +// WAITINGPLAYERS +// ================ + +void F_StartWaitingPlayers(void) +{ + wipegamestate = GS_TITLESCREEN; // technically wiping from title screen + finalecount = 0; +} + +void F_WaitingPlayersTicker(void) +{ + if (paused) + return; + + finalecount++; + + // dumb hack, only start the music on the 1st tick so if you instantly go into the map you aren't hearing a tic of music + if (finalecount == 2) + S_ChangeMusicInternal("_CHSEL", true); +} + +void F_WaitingPlayersDrawer(void) +{ + const char *waittext1 = "You will join"; + const char *waittext2 = "next level..."; + + V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 31); + + V_DrawCreditString((160 - (V_CreditStringWidth(waittext1)>>1))<<FRACBITS, 48<<FRACBITS, 0, waittext1); + V_DrawCreditString((160 - (V_CreditStringWidth(waittext2)>>1))<<FRACBITS, 64<<FRACBITS, 0, waittext2); +} diff --git a/src/f_finale.h b/src/f_finale.h index 7f53bfbad59b18814693db553eb7d25815a082bd..cb71775d05fc109aa4c3468c19cfe381eff72635 100644 --- a/src/f_finale.h +++ b/src/f_finale.h @@ -74,6 +74,10 @@ void F_StartContinue(void); void F_ContinueTicker(void); void F_ContinueDrawer(void); +void F_StartWaitingPlayers(void); +void F_WaitingPlayersTicker(void); +void F_WaitingPlayersDrawer(void); + extern INT32 finalecount; extern INT32 titlescrollxspeed; extern INT32 titlescrollyspeed; diff --git a/src/f_wipe.c b/src/f_wipe.c index 6014fb7f9471d851532a3df4a94b01c1b04ef6e8..4bcfb029b2ed1815e895ff126127bb628c6709fb 100644 --- a/src/f_wipe.c +++ b/src/f_wipe.c @@ -614,6 +614,8 @@ void F_RunWipe(UINT8 wipetype, boolean drawMenu) if (moviemode) M_SaveFrame(); + + NetKeepAlive(); // Update the network so we don't cause timeouts } WipeInAction = false; diff --git a/src/g_demo.c b/src/g_demo.c index 0403da16da95c5d4e41a614fa2640797ece217f2..4b9ff56e80f5711faabd18b53a9474f2c0a60c5e 100644 --- a/src/g_demo.c +++ b/src/g_demo.c @@ -39,6 +39,7 @@ #include "v_video.h" #include "lua_hook.h" #include "md5.h" // demo checksums +#include "d_netfil.h" // G_CheckDemoExtraFiles boolean timingdemo; // if true, exit with report on completion boolean nodrawers; // for comparative timing purposes @@ -49,6 +50,7 @@ static char demoname[64]; boolean demorecording; boolean demoplayback; boolean titledemo; // Title Screen demo can be cancelled by any key +demo_file_override_e demofileoverride; static UINT8 *demobuffer = NULL; static UINT8 *demo_p, *demotime_p; static UINT8 *demoend; @@ -56,6 +58,7 @@ static UINT8 demoflags; static UINT16 demoversion; boolean singledemo; // quit after playing a demo from cmdline boolean demo_start; // don't start playing demo right away +boolean demo_forwardmove_rng; // old demo backwards compatibility boolean demosynced = true; // console warning message boolean metalrecording; // recording as metal sonic @@ -95,7 +98,7 @@ demoghost *ghosts = NULL; // DEMO RECORDING // -#define DEMOVERSION 0x000f +#define DEMOVERSION 0x0010 #define DEMOHEADER "\xF0" "SRB2Replay" "\x0F" #define DF_GHOST 0x01 // This demo contains ghost data too! @@ -1413,6 +1416,10 @@ void G_BeginRecording(void) char name[MAXCOLORNAME+1]; player_t *player = &players[consoleplayer]; + char *filename; + UINT16 totalfiles; + UINT8 *m; + if (demo_p) return; memset(name,0,sizeof(name)); @@ -1435,23 +1442,43 @@ void G_BeginRecording(void) M_Memcpy(demo_p, mapmd5, 16); demo_p += 16; WRITEUINT8(demo_p,demoflags); + + // file list + m = demo_p;/* file count */ + demo_p += 2; + + totalfiles = 0; + for (i = mainwads; ++i < numwadfiles; ) + { + if (wadfiles[i]->important) + { + nameonly(( filename = va("%s", wadfiles[i]->filename) )); + WRITESTRINGL(demo_p, filename, MAX_WADPATH); + WRITEMEM(demo_p, wadfiles[i]->md5sum, 16); + + totalfiles++; + } + } + + WRITEUINT16(m, totalfiles); + switch ((demoflags & DF_ATTACKMASK)>>DF_ATTACKSHIFT) { - case ATTACKING_NONE: // 0 - break; - case ATTACKING_RECORD: // 1 - demotime_p = demo_p; - WRITEUINT32(demo_p,UINT32_MAX); // time - WRITEUINT32(demo_p,0); // score - WRITEUINT16(demo_p,0); // rings - break; - case ATTACKING_NIGHTS: // 2 - demotime_p = demo_p; - WRITEUINT32(demo_p,UINT32_MAX); // time - WRITEUINT32(demo_p,0); // score - break; - default: // 3 - break; + case ATTACKING_NONE: // 0 + break; + case ATTACKING_RECORD: // 1 + demotime_p = demo_p; + WRITEUINT32(demo_p,UINT32_MAX); // time + WRITEUINT32(demo_p,0); // score + WRITEUINT16(demo_p,0); // rings + break; + case ATTACKING_NIGHTS: // 2 + demotime_p = demo_p; + WRITEUINT32(demo_p,UINT32_MAX); // time + WRITEUINT32(demo_p,0); // score + break; + default: // 3 + break; } WRITEUINT32(demo_p,P_GetInitSeed()); @@ -1483,18 +1510,18 @@ void G_BeginRecording(void) // Stats WRITEUINT8(demo_p,player->charability); WRITEUINT8(demo_p,player->charability2); - WRITEUINT8(demo_p,player->actionspd>>FRACBITS); - WRITEUINT8(demo_p,player->mindash>>FRACBITS); - WRITEUINT8(demo_p,player->maxdash>>FRACBITS); - WRITEUINT8(demo_p,player->normalspeed>>FRACBITS); - WRITEUINT8(demo_p,player->runspeed>>FRACBITS); + WRITEFIXED(demo_p,player->actionspd); + WRITEFIXED(demo_p,player->mindash); + WRITEFIXED(demo_p,player->maxdash); + WRITEFIXED(demo_p,player->normalspeed); + WRITEFIXED(demo_p,player->runspeed); WRITEUINT8(demo_p,player->thrustfactor); WRITEUINT8(demo_p,player->accelstart); WRITEUINT8(demo_p,player->acceleration); WRITEFIXED(demo_p,player->height); WRITEFIXED(demo_p,player->spinheight); - WRITEUINT8(demo_p,player->camerascale>>FRACBITS); - WRITEUINT8(demo_p,player->shieldscale>>FRACBITS); + WRITEFIXED(demo_p,player->camerascale); + WRITEFIXED(demo_p,player->shieldscale); // Trying to convert it back to % causes demo desync due to precision loss. // Don't do it. @@ -1590,6 +1617,183 @@ void G_BeginMetal(void) oldmetal.angle = mo->angle>>24; } +static void G_LoadDemoExtraFiles(UINT8 **pp, UINT16 this_demo_version) +{ + UINT16 totalfiles; + char filename[MAX_WADPATH]; + UINT8 md5sum[16]; + filestatus_t ncs; + boolean toomany = false; + boolean alreadyloaded; + UINT16 i, j; + + if (this_demo_version < 0x0010) + { + // demo has no file list + return; + } + + totalfiles = READUINT16((*pp)); + for (i = 0; i < totalfiles; ++i) + { + if (toomany) + SKIPSTRING((*pp)); + else + { + strlcpy(filename, (char *)(*pp), sizeof filename); + SKIPSTRING((*pp)); + } + READMEM((*pp), md5sum, 16); + + if (!toomany) + { + alreadyloaded = false; + + for (j = 0; j < numwadfiles; ++j) + { + if (memcmp(md5sum, wadfiles[j]->md5sum, 16) == 0) + { + alreadyloaded = true; + break; + } + } + + if (alreadyloaded) + continue; + + if (numwadfiles >= MAX_WADFILES) + toomany = true; + else + ncs = findfile(filename, md5sum, false); + + if (toomany) + { + CONS_Alert(CONS_WARNING, M_GetText("Too many files loaded to add anymore for demo playback\n")); + if (!CON_Ready()) + M_StartMessage(M_GetText("There are too many files loaded to add this demo's addons.\n\nDemo playback may desync.\n\nPress ESC\n"), NULL, MM_NOTHING); + } + else if (ncs != FS_FOUND) + { + if (ncs == FS_NOTFOUND) + CONS_Alert(CONS_NOTICE, M_GetText("You do not have a copy of %s\n"), filename); + else if (ncs == FS_MD5SUMBAD) + CONS_Alert(CONS_NOTICE, M_GetText("Checksum mismatch on %s\n"), filename); + else + CONS_Alert(CONS_NOTICE, M_GetText("Unknown error finding file %s\n"), filename); + + if (!CON_Ready()) + M_StartMessage(M_GetText("There were errors trying to add this demo's addons. Check the console for more information.\n\nDemo playback may desync.\n\nPress ESC\n"), NULL, MM_NOTHING); + } + else + { + P_AddWadFile(filename); + } + } + } +} + +static void G_SkipDemoExtraFiles(UINT8 **pp, UINT16 this_demo_version) +{ + UINT16 totalfiles; + UINT16 i; + + if (this_demo_version < 0x0010) + { + // demo has no file list + return; + } + + totalfiles = READUINT16((*pp)); + for (i = 0; i < totalfiles; ++i) + { + SKIPSTRING((*pp));// file name + (*pp) += 16;// md5 + } +} + +// G_CheckDemoExtraFiles: checks if our loaded WAD list matches the demo's. +// Enabling quick prevents filesystem checks to see if needed files are available to load. +static UINT8 G_CheckDemoExtraFiles(UINT8 **pp, boolean quick, UINT16 this_demo_version) +{ + UINT16 totalfiles, filesloaded, nmusfilecount; + char filename[MAX_WADPATH]; + UINT8 md5sum[16]; + boolean toomany = false; + boolean alreadyloaded; + UINT16 i, j; + UINT8 error = DFILE_ERROR_NONE; + + if (this_demo_version < 0x0010) + { + // demo has no file list + return DFILE_ERROR_NONE; + } + + totalfiles = READUINT16((*pp)); + filesloaded = 0; + for (i = 0; i < totalfiles; ++i) + { + if (toomany) + SKIPSTRING((*pp)); + else + { + strlcpy(filename, (char *)(*pp), sizeof filename); + SKIPSTRING((*pp)); + } + READMEM((*pp), md5sum, 16); + + if (!toomany) + { + alreadyloaded = false; + nmusfilecount = 0; + + for (j = 0; j < numwadfiles; ++j) + { + if (wadfiles[j]->important && j > mainwads) + nmusfilecount++; + else + continue; + + if (memcmp(md5sum, wadfiles[j]->md5sum, 16) == 0) + { + alreadyloaded = true; + + if (i != nmusfilecount-1 && error < DFILE_ERROR_OUTOFORDER) + error |= DFILE_ERROR_OUTOFORDER; + + break; + } + } + + if (alreadyloaded) + { + filesloaded++; + continue; + } + + if (numwadfiles >= MAX_WADFILES) + error = DFILE_ERROR_CANNOTLOAD; + else if (!quick && findfile(filename, md5sum, false) != FS_FOUND) + error = DFILE_ERROR_CANNOTLOAD; + else if (error < DFILE_ERROR_INCOMPLETEOUTOFORDER) + error |= DFILE_ERROR_NOTLOADED; + } else + error = DFILE_ERROR_CANNOTLOAD; + } + + // Get final file count + nmusfilecount = 0; + + for (j = 0; j < numwadfiles; ++j) + if (wadfiles[j]->important && j > mainwads) + nmusfilecount++; + + if (!error && filesloaded < nmusfilecount) + error = DFILE_ERROR_EXTRAFILES; + + return error; +} + void G_SetDemoTime(UINT32 ptime, UINT32 pscore, UINT16 prings) { if (!demorecording || !demotime_p) @@ -1618,10 +1822,9 @@ UINT8 G_CmpDemoTime(char *oldname, char *newname) UINT8 *buffer,*p; UINT8 flags; UINT32 oldtime, newtime, oldscore, newscore; - UINT16 oldrings, newrings, oldversion; + UINT16 oldrings, newrings, oldversion, newversion; size_t bufsize ATTRUNUSED; UINT8 c; - UINT16 s ATTRUNUSED; UINT8 aflags = 0; // load the new file @@ -1637,15 +1840,15 @@ UINT8 G_CmpDemoTime(char *oldname, char *newname) I_Assert(c == VERSION); c = READUINT8(p); // SUBVERSION I_Assert(c == SUBVERSION); - s = READUINT16(p); - I_Assert(s >= 0x000c); + newversion = READUINT16(p); + I_Assert(newversion == DEMOVERSION); p += 16; // demo checksum I_Assert(!memcmp(p, "PLAY", 4)); p += 4; // PLAY p += 2; // gamemap p += 16; // map md5 flags = READUINT8(p); // demoflags - + G_SkipDemoExtraFiles(&p, newversion); aflags = flags & (DF_RECORDATTACK|DF_NIGHTSATTACK); I_Assert(aflags); if (flags & DF_RECORDATTACK) @@ -1687,7 +1890,8 @@ UINT8 G_CmpDemoTime(char *oldname, char *newname) switch(oldversion) // demoversion { case DEMOVERSION: // latest always supported - case 0x000e: // The previous demoversions also supported + case 0x000f: // The previous demoversions also supported + case 0x000e: case 0x000d: // all that changed between then and now was longer color name case 0x000c: break; @@ -1710,6 +1914,7 @@ UINT8 G_CmpDemoTime(char *oldname, char *newname) p += 2; // gamemap p += 16; // mapmd5 flags = READUINT8(p); + G_SkipDemoExtraFiles(&p, oldversion); if (!(flags & aflags)) { CONS_Alert(CONS_NOTICE, M_GetText("File '%s' not from same game mode. It will be overwritten.\n"), oldname); @@ -1829,8 +2034,10 @@ void G_DoPlayDemo(char *defdemoname) version = READUINT8(demo_p); subversion = READUINT8(demo_p); demoversion = READUINT16(demo_p); + demo_forwardmove_rng = (demoversion < 0x0010); switch(demoversion) { + case 0x000f: case 0x000d: case 0x000e: case DEMOVERSION: // latest always supported @@ -1871,6 +2078,69 @@ void G_DoPlayDemo(char *defdemoname) demo_p += 16; // mapmd5 demoflags = READUINT8(demo_p); + + if (titledemo) + { + // Titledemos should always play and ought to always be compatible with whatever wadlist is running. + G_SkipDemoExtraFiles(&demo_p, demoversion); + } + else if (demofileoverride == DFILE_OVERRIDE_LOAD) + { + G_LoadDemoExtraFiles(&demo_p, demoversion); + } + else if (demofileoverride == DFILE_OVERRIDE_SKIP) + { + G_SkipDemoExtraFiles(&demo_p, demoversion); + } + else + { + UINT8 error = G_CheckDemoExtraFiles(&demo_p, false, demoversion); + + if (error) + { + switch (error) + { + case DFILE_ERROR_NOTLOADED: + snprintf(msg, 1024, + M_GetText("Required files for this demo are not loaded.\n\nUse\n\"playdemo %s -addfiles\"\nto load them and play the demo.\n"), + pdemoname); + break; + + case DFILE_ERROR_OUTOFORDER: + snprintf(msg, 1024, + M_GetText("Required files for this demo are loaded out of order.\n\nUse\n\"playdemo %s -force\"\nto play the demo anyway.\n"), + pdemoname); + break; + + case DFILE_ERROR_INCOMPLETEOUTOFORDER: + snprintf(msg, 1024, + M_GetText("Required files for this demo are not loaded, and some are out of order.\n\nUse\n\"playdemo %s -addfiles\"\nto load needed files and play the demo.\n"), + pdemoname); + break; + + case DFILE_ERROR_CANNOTLOAD: + snprintf(msg, 1024, + M_GetText("Required files for this demo cannot be loaded.\n\nUse\n\"playdemo %s -force\"\nto play the demo anyway.\n"), + pdemoname); + break; + + case DFILE_ERROR_EXTRAFILES: + snprintf(msg, 1024, + M_GetText("You have additional files loaded beyond the demo's file list.\n\nUse\n\"playdemo %s -force\"\nto play the demo anyway.\n"), + pdemoname); + break; + } + + CONS_Alert(CONS_ERROR, "%s", msg); + M_StartMessage(msg, NULL, MM_NOTHING); + Z_Free(pdemoname); + Z_Free(demobuffer); + demoplayback = false; + titledemo = false; + return; + } + } + modeattacking = (demoflags & DF_ATTACKMASK)>>DF_ATTACKSHIFT; CON_ToggleOff(); @@ -1913,18 +2183,18 @@ void G_DoPlayDemo(char *defdemoname) charability = READUINT8(demo_p); charability2 = READUINT8(demo_p); - actionspd = (fixed_t)READUINT8(demo_p)<<FRACBITS; - mindash = (fixed_t)READUINT8(demo_p)<<FRACBITS; - maxdash = (fixed_t)READUINT8(demo_p)<<FRACBITS; - normalspeed = (fixed_t)READUINT8(demo_p)<<FRACBITS; - runspeed = (fixed_t)READUINT8(demo_p)<<FRACBITS; + actionspd = (demoversion < 0x0010) ? (fixed_t)READUINT8(demo_p)<<FRACBITS : READFIXED(demo_p); + mindash = (demoversion < 0x0010) ? (fixed_t)READUINT8(demo_p)<<FRACBITS : READFIXED(demo_p); + maxdash = (demoversion < 0x0010) ? (fixed_t)READUINT8(demo_p)<<FRACBITS : READFIXED(demo_p); + normalspeed = (demoversion < 0x0010) ? (fixed_t)READUINT8(demo_p)<<FRACBITS : READFIXED(demo_p); + runspeed = (demoversion < 0x0010) ? (fixed_t)READUINT8(demo_p)<<FRACBITS : READFIXED(demo_p); thrustfactor = READUINT8(demo_p); accelstart = READUINT8(demo_p); acceleration = READUINT8(demo_p); height = (demoversion < 0x000e) ? (fixed_t)READUINT8(demo_p)<<FRACBITS : READFIXED(demo_p); spinheight = (demoversion < 0x000e) ? (fixed_t)READUINT8(demo_p)<<FRACBITS : READFIXED(demo_p); - camerascale = (fixed_t)READUINT8(demo_p)<<FRACBITS; - shieldscale = (fixed_t)READUINT8(demo_p)<<FRACBITS; + camerascale = (demoversion < 0x0010) ? (fixed_t)READUINT8(demo_p)<<FRACBITS : READFIXED(demo_p); + shieldscale = (demoversion < 0x0010) ? (fixed_t)READUINT8(demo_p)<<FRACBITS : READFIXED(demo_p); jumpfactor = READFIXED(demo_p); followitem = READUINT32(demo_p); @@ -2026,6 +2296,88 @@ void G_DoPlayDemo(char *defdemoname) demo_start = true; } +// +// Check if a replay can be loaded from the menu +// +UINT8 G_CheckDemoForError(char *defdemoname) +{ + lumpnum_t l; + char *n,*pdemoname; + UINT16 our_demo_version; + + if (titledemo) + { + // Don't do anything with files for these. + return DFILE_ERROR_NONE; + } + + n = defdemoname+strlen(defdemoname); + while (*n != '/' && *n != '\\' && n != defdemoname) + n--; + if (n != defdemoname) + n++; + pdemoname = ZZ_Alloc(strlen(n)+1); + strcpy(pdemoname,n); + + // Internal if no extension, external if one exists + if (FIL_CheckExtension(defdemoname)) + { + //FIL_DefaultExtension(defdemoname, ".lmp"); + if (!FIL_ReadFile(defdemoname, &demobuffer)) + { + return DFILE_ERROR_NOTDEMO; + } + demo_p = demobuffer; + } + // load demo resource from WAD + else if ((l = W_CheckNumForName(defdemoname)) == LUMPERROR) + { + return DFILE_ERROR_NOTDEMO; + } + else // it's an internal demo + { + demobuffer = demo_p = W_CacheLumpNum(l, PU_STATIC); + } + + // read demo header + if (memcmp(demo_p, DEMOHEADER, 12)) + { + return DFILE_ERROR_NOTDEMO; + } + demo_p += 12; // DEMOHEADER + + demo_p++; // version + demo_p++; // subversion + our_demo_version = READUINT16(demo_p); + switch(our_demo_version) + { + case 0x000d: + case 0x000e: + case 0x000f: + case DEMOVERSION: // latest always supported + break; +#ifdef OLD22DEMOCOMPAT + case 0x000c: + break; +#endif + // too old, cannot support. + default: + return DFILE_ERROR_NOTDEMO; + } + demo_p += 16; // demo checksum + if (memcmp(demo_p, "PLAY", 4)) + { + return DFILE_ERROR_NOTDEMO; + } + demo_p += 4; // "PLAY" + demo_p += 2; // gamemap + demo_p += 16; // mapmd5 + + demo_p++; // demoflags + + return G_CheckDemoExtraFiles(&demo_p, true, our_demo_version); +} + void G_AddGhost(char *defdemoname) { INT32 i; @@ -2085,6 +2437,7 @@ void G_AddGhost(char *defdemoname) ghostversion = READUINT16(p); switch(ghostversion) { + case 0x000f: case 0x000d: case 0x000e: case DEMOVERSION: // latest always supported @@ -2130,6 +2483,9 @@ void G_AddGhost(char *defdemoname) Z_Free(buffer); return; } + + G_SkipDemoExtraFiles(&p, ghostversion); // Don't wanna modify the file list for ghosts. + switch ((flags & DF_ATTACKMASK)>>DF_ATTACKSHIFT) { case ATTACKING_NONE: // 0 @@ -2161,17 +2517,12 @@ void G_AddGhost(char *defdemoname) // Ghosts do not have a player structure to put this in. p++; // charability p++; // charability2 - p++; // actionspd - p++; // mindash - p++; // maxdash - p++; // normalspeed - p++; // runspeed + p += (ghostversion < 0x0010) ? 5 : 5 * sizeof(fixed_t); // actionspd, mindash, maxdash, normalspeed, and runspeed p++; // thrustfactor p++; // accelstart p++; // acceleration p += (ghostversion < 0x000e) ? 2 : 2 * sizeof(fixed_t); // height and spinheight - p++; // camerascale - p++; // shieldscale + p += (ghostversion < 0x0010) ? 2 : 2 * sizeof(fixed_t); // camerascale and shieldscale p += 4; // jumpfactor p += 4; // followitem @@ -2347,6 +2698,7 @@ void G_DoPlayMetal(void) switch(metalversion) { case DEMOVERSION: // latest always supported + case 0x000f: case 0x000e: // There are checks wheter the momentum is from older demo versions or not case 0x000d: // all that changed between then and now was longer color name case 0x000c: diff --git a/src/g_demo.h b/src/g_demo.h index f25315a58c9b6040f38baca3d7f50abc9050a69e..379c57428a6db9daeef1b5d6ab6368436224c828 100644 --- a/src/g_demo.h +++ b/src/g_demo.h @@ -26,9 +26,19 @@ extern boolean demoplayback, titledemo, demorecording, timingdemo; extern tic_t demostarttime; +typedef enum +{ + DFILE_OVERRIDE_NONE = 0, // Show errors normally + DFILE_OVERRIDE_LOAD, // Forcefully load demo, add files beforehand + DFILE_OVERRIDE_SKIP, // Forcefully load demo, skip file list +} demo_file_override_e; + +extern demo_file_override_e demofileoverride; + // Quit after playing a demo from cmdline. extern boolean singledemo; extern boolean demo_start; +extern boolean demo_forwardmove_rng; extern boolean demosynced; extern mobj_t *metalplayback; @@ -53,6 +63,18 @@ typedef enum GHC_RETURNSKIN // ditto } ghostcolor_t; +// G_CheckDemoExtraFiles: checks if our loaded WAD list matches the demo's. +typedef enum +{ + DFILE_ERROR_NONE = 0, // No file error + DFILE_ERROR_NOTLOADED, // Files are not loaded, but can be without a restart. + DFILE_ERROR_OUTOFORDER, // Files are loaded, but out of order. + DFILE_ERROR_INCOMPLETEOUTOFORDER, // Some files are loaded out of order, but others are not. + DFILE_ERROR_CANNOTLOAD, // Files are missing and cannot be loaded. + DFILE_ERROR_EXTRAFILES, // Extra files outside of the replay's file list are loaded. + DFILE_ERROR_NOTDEMO = UINT8_MAX, // This replay isn't even a replay... +} demo_file_error_e; + // Record/playback tics void G_ReadDemoTiccmd(ticcmd_t *cmd, INT32 playernum); void G_WriteDemoTiccmd(ticcmd_t *cmd, INT32 playernum); @@ -83,5 +105,6 @@ ATTRNORETURN void FUNCNORETURN G_StopMetalRecording(boolean kill); void G_StopDemo(void); boolean G_CheckDemoStatus(void); INT32 G_ConvertOldFrameFlags(INT32 frame); +UINT8 G_CheckDemoForError(char *defdemoname); #endif // __G_DEMO__ diff --git a/src/g_game.c b/src/g_game.c index b239800447972d1bf9e8931ddf6c5796e397824f..619ed8c89d722280375a30fe3059c58785ae61b2 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -156,6 +156,7 @@ textprompt_t *textprompts[MAX_PROMPTS]; INT16 nextmapoverride; UINT8 skipstats; +INT16 nextgametype = -1; // Pointers to each CTF flag mobj_t *redflag; @@ -315,6 +316,8 @@ consvar_t cv_consolechat = CVAR_INIT ("chatmode", "Window", CV_SAVE, consolechat // Pause game upon window losing focus consvar_t cv_pauseifunfocused = CVAR_INIT ("pauseifunfocused", "Yes", CV_SAVE, CV_YesNo, NULL); +consvar_t cv_instantretry = CVAR_INIT ("instantretry", "No", CV_SAVE, CV_YesNo, NULL); + consvar_t cv_crosshair = CVAR_INIT ("crosshair", "Cross", CV_SAVE, crosshair_cons_t, NULL); consvar_t cv_crosshair2 = CVAR_INIT ("crosshair2", "Cross", CV_SAVE, crosshair_cons_t, NULL); consvar_t cv_invertmouse = CVAR_INIT ("invertmouse", "Off", CV_SAVE, CV_OnOff, NULL); @@ -519,140 +522,154 @@ UINT8 G_GetBestNightsGrade(INT16 map, UINT8 mare, gamedata_t *data) } // For easy adding of NiGHTS records -void G_AddTempNightsRecords(UINT32 pscore, tic_t ptime, UINT8 mare) +void G_AddTempNightsRecords(player_t *player, UINT32 pscore, tic_t ptime, UINT8 mare) { - ntemprecords.score[mare] = pscore; - ntemprecords.grade[mare] = P_GetGrade(pscore, gamemap, mare - 1); - ntemprecords.time[mare] = ptime; + const UINT8 playerID = player - players; + + I_Assert(player != NULL); + + ntemprecords[playerID].score[mare] = pscore; + ntemprecords[playerID].grade[mare] = P_GetGrade(pscore, gamemap, mare - 1); + ntemprecords[playerID].time[mare] = ptime; // Update nummares // Note that mare "0" is overall, mare "1" is the first real mare - if (ntemprecords.nummares < mare) - ntemprecords.nummares = mare; + if (ntemprecords[playerID].nummares < mare) + ntemprecords[playerID].nummares = mare; } // -// G_UpdateRecordReplays +// G_SetMainRecords // // Update replay files/data, etc. for Record Attack // See G_SetNightsRecords for NiGHTS Attack. // -static void G_UpdateRecordReplays(gamedata_t *data) +static void G_SetMainRecords(gamedata_t *data, player_t *player) { - const size_t glen = strlen(srb2home)+1+strlen("replay")+1+strlen(timeattackfolder)+1+strlen("MAPXX")+1; - char *gpath; - char lastdemo[256], bestdemo[256]; UINT8 earnedEmblems; + I_Assert(player != NULL); + // Record new best time if (!data->mainrecords[gamemap-1]) G_AllocMainRecordData(gamemap-1, data); - if (players[consoleplayer].score > data->mainrecords[gamemap-1]->score) - data->mainrecords[gamemap-1]->score = players[consoleplayer].score; + if (player->recordscore > data->mainrecords[gamemap-1]->score) + data->mainrecords[gamemap-1]->score = player->recordscore; - if ((data->mainrecords[gamemap-1]->time == 0) || (players[consoleplayer].realtime < data->mainrecords[gamemap-1]->time)) - data->mainrecords[gamemap-1]->time = players[consoleplayer].realtime; + if ((data->mainrecords[gamemap-1]->time == 0) || (player->realtime < data->mainrecords[gamemap-1]->time)) + data->mainrecords[gamemap-1]->time = player->realtime; - if ((UINT16)(players[consoleplayer].rings) > data->mainrecords[gamemap-1]->rings) - data->mainrecords[gamemap-1]->rings = (UINT16)(players[consoleplayer].rings); + if ((UINT16)(player->rings) > data->mainrecords[gamemap-1]->rings) + data->mainrecords[gamemap-1]->rings = (UINT16)(player->rings); - // Save demo! - bestdemo[255] = '\0'; - lastdemo[255] = '\0'; - G_SetDemoTime(players[consoleplayer].realtime, players[consoleplayer].score, (UINT16)(players[consoleplayer].rings)); - G_CheckDemoStatus(); + if (modeattacking) + { + const size_t glen = strlen(srb2home)+1+strlen("replay")+1+strlen(timeattackfolder)+1+strlen("MAPXX")+1; + char *gpath; + char lastdemo[256], bestdemo[256]; - I_mkdir(va("%s"PATHSEP"replay", srb2home), 0755); - I_mkdir(va("%s"PATHSEP"replay"PATHSEP"%s", srb2home, timeattackfolder), 0755); + // Save demo! + bestdemo[255] = '\0'; + lastdemo[255] = '\0'; + G_SetDemoTime(player->realtime, player->recordscore, (UINT16)(player->rings)); + G_CheckDemoStatus(); - if ((gpath = malloc(glen)) == NULL) - I_Error("Out of memory for replay filepath\n"); + I_mkdir(va("%s"PATHSEP"replay", srb2home), 0755); + I_mkdir(va("%s"PATHSEP"replay"PATHSEP"%s", srb2home, timeattackfolder), 0755); - sprintf(gpath,"%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s", srb2home, timeattackfolder, G_BuildMapName(gamemap)); - snprintf(lastdemo, 255, "%s-%s-last.lmp", gpath, skins[cv_chooseskin.value-1].name); + if ((gpath = malloc(glen)) == NULL) + I_Error("Out of memory for replay filepath\n"); - if (FIL_FileExists(lastdemo)) - { - UINT8 *buf; - size_t len = FIL_ReadFile(lastdemo, &buf); + sprintf(gpath,"%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s", srb2home, timeattackfolder, G_BuildMapName(gamemap)); + snprintf(lastdemo, 255, "%s-%s-last.lmp", gpath, skins[cv_chooseskin.value-1].name); - snprintf(bestdemo, 255, "%s-%s-time-best.lmp", gpath, skins[cv_chooseskin.value-1].name); - if (!FIL_FileExists(bestdemo) || G_CmpDemoTime(bestdemo, lastdemo) & 1) - { // Better time, save this demo. - if (FIL_FileExists(bestdemo)) - remove(bestdemo); - FIL_WriteFile(bestdemo, buf, len); - CONS_Printf("\x83%s\x80 %s '%s'\n", M_GetText("NEW RECORD TIME!"), M_GetText("Saved replay as"), bestdemo); - } + if (FIL_FileExists(lastdemo)) + { + UINT8 *buf; + size_t len = FIL_ReadFile(lastdemo, &buf); + + snprintf(bestdemo, 255, "%s-%s-time-best.lmp", gpath, skins[cv_chooseskin.value-1].name); + if (!FIL_FileExists(bestdemo) || G_CmpDemoTime(bestdemo, lastdemo) & 1) + { // Better time, save this demo. + if (FIL_FileExists(bestdemo)) + remove(bestdemo); + FIL_WriteFile(bestdemo, buf, len); + CONS_Printf("\x83%s\x80 %s '%s'\n", M_GetText("NEW RECORD TIME!"), M_GetText("Saved replay as"), bestdemo); + } - snprintf(bestdemo, 255, "%s-%s-score-best.lmp", gpath, skins[cv_chooseskin.value-1].name); - if (!FIL_FileExists(bestdemo) || (G_CmpDemoTime(bestdemo, lastdemo) & (1<<1))) - { // Better score, save this demo. - if (FIL_FileExists(bestdemo)) - remove(bestdemo); - FIL_WriteFile(bestdemo, buf, len); - CONS_Printf("\x83%s\x80 %s '%s'\n", M_GetText("NEW HIGH SCORE!"), M_GetText("Saved replay as"), bestdemo); - } + snprintf(bestdemo, 255, "%s-%s-score-best.lmp", gpath, skins[cv_chooseskin.value-1].name); + if (!FIL_FileExists(bestdemo) || (G_CmpDemoTime(bestdemo, lastdemo) & (1<<1))) + { // Better score, save this demo. + if (FIL_FileExists(bestdemo)) + remove(bestdemo); + FIL_WriteFile(bestdemo, buf, len); + CONS_Printf("\x83%s\x80 %s '%s'\n", M_GetText("NEW HIGH SCORE!"), M_GetText("Saved replay as"), bestdemo); + } - snprintf(bestdemo, 255, "%s-%s-rings-best.lmp", gpath, skins[cv_chooseskin.value-1].name); - if (!FIL_FileExists(bestdemo) || (G_CmpDemoTime(bestdemo, lastdemo) & (1<<2))) - { // Better rings, save this demo. - if (FIL_FileExists(bestdemo)) - remove(bestdemo); - FIL_WriteFile(bestdemo, buf, len); - CONS_Printf("\x83%s\x80 %s '%s'\n", M_GetText("NEW MOST RINGS!"), M_GetText("Saved replay as"), bestdemo); - } + snprintf(bestdemo, 255, "%s-%s-rings-best.lmp", gpath, skins[cv_chooseskin.value-1].name); + if (!FIL_FileExists(bestdemo) || (G_CmpDemoTime(bestdemo, lastdemo) & (1<<2))) + { // Better rings, save this demo. + if (FIL_FileExists(bestdemo)) + remove(bestdemo); + FIL_WriteFile(bestdemo, buf, len); + CONS_Printf("\x83%s\x80 %s '%s'\n", M_GetText("NEW MOST RINGS!"), M_GetText("Saved replay as"), bestdemo); + } - //CONS_Printf("%s '%s'\n", M_GetText("Saved replay as"), lastdemo); + //CONS_Printf("%s '%s'\n", M_GetText("Saved replay as"), lastdemo); - Z_Free(buf); + Z_Free(buf); + } + free(gpath); } - free(gpath); // Check emblems when level data is updated if ((earnedEmblems = M_CheckLevelEmblems(data))) + { CONS_Printf(M_GetText("\x82" "Earned %hu emblem%s for Record Attack records.\n"), (UINT16)earnedEmblems, earnedEmblems > 1 ? "s" : ""); + } // Update timeattack menu's replay availability. Nextmap_OnChange(); } -void G_SetNightsRecords(gamedata_t *data) +static void G_SetNightsRecords(gamedata_t *data, player_t *player) { - INT32 i; + nightsdata_t *const ntemprecord = &ntemprecords[player - players]; UINT32 totalscore = 0; tic_t totaltime = 0; - UINT8 earnedEmblems; + INT32 i; - const size_t glen = strlen(srb2home)+1+strlen("replay")+1+strlen(timeattackfolder)+1+strlen("MAPXX")+1; - char *gpath; - char lastdemo[256], bestdemo[256]; + UINT8 earnedEmblems; - if (!ntemprecords.nummares) + if (!ntemprecord->nummares) + { return; + } // Set overall { UINT8 totalrank = 0, realrank = 0; - for (i = 1; i <= ntemprecords.nummares; ++i) + for (i = 1; i <= ntemprecord->nummares; ++i) { - totalscore += ntemprecords.score[i]; - totalrank += ntemprecords.grade[i]; - totaltime += ntemprecords.time[i]; + totalscore += ntemprecord->score[i]; + totalrank += ntemprecord->grade[i]; + totaltime += ntemprecord->time[i]; } // Determine overall grade - realrank = (UINT8)((FixedDiv((fixed_t)totalrank << FRACBITS, ntemprecords.nummares << FRACBITS) + (FRACUNIT/2)) >> FRACBITS); + realrank = (UINT8)((FixedDiv((fixed_t)totalrank << FRACBITS, ntemprecord->nummares << FRACBITS) + (FRACUNIT/2)) >> FRACBITS); // You need ALL rainbow As to get a rainbow A overall - if (realrank == GRADE_S && (totalrank / ntemprecords.nummares) != GRADE_S) + if (realrank == GRADE_S && (totalrank / ntemprecord->nummares) != GRADE_S) + { realrank = GRADE_A; + } - ntemprecords.score[0] = totalscore; - ntemprecords.grade[0] = realrank; - ntemprecords.time[0] = totaltime; + ntemprecord->score[0] = totalscore; + ntemprecord->grade[0] = realrank; + ntemprecord->time[0] = totaltime; } // Now take all temp records and put them in the actual records @@ -660,71 +677,85 @@ void G_SetNightsRecords(gamedata_t *data) nightsdata_t *maprecords; if (!data->nightsrecords[gamemap-1]) + { G_AllocNightsRecordData(gamemap-1, data); + } + maprecords = data->nightsrecords[gamemap-1]; - if (maprecords->nummares != ntemprecords.nummares) - maprecords->nummares = ntemprecords.nummares; + if (maprecords->nummares != ntemprecord->nummares) + { + maprecords->nummares = ntemprecord->nummares; + } - for (i = 0; i < ntemprecords.nummares + 1; ++i) + for (i = 0; i < ntemprecord->nummares + 1; ++i) { - if (maprecords->score[i] < ntemprecords.score[i]) - maprecords->score[i] = ntemprecords.score[i]; - if (maprecords->grade[i] < ntemprecords.grade[i]) - maprecords->grade[i] = ntemprecords.grade[i]; - if (!maprecords->time[i] || maprecords->time[i] > ntemprecords.time[i]) - maprecords->time[i] = ntemprecords.time[i]; + if (maprecords->score[i] < ntemprecord->score[i]) + maprecords->score[i] = ntemprecord->score[i]; + if (maprecords->grade[i] < ntemprecord->grade[i]) + maprecords->grade[i] = ntemprecord->grade[i]; + if (!maprecords->time[i] || maprecords->time[i] > ntemprecord->time[i]) + maprecords->time[i] = ntemprecord->time[i]; } } - memset(&ntemprecords, 0, sizeof(nightsdata_t)); + memset(&ntemprecords[player - players], 0, sizeof(nightsdata_t)); - // Save demo! - bestdemo[255] = '\0'; - lastdemo[255] = '\0'; - G_SetDemoTime(totaltime, totalscore, 0); - G_CheckDemoStatus(); + if (modeattacking) + { + const size_t glen = strlen(srb2home)+1+strlen("replay")+1+strlen(timeattackfolder)+1+strlen("MAPXX")+1; + char *gpath; + char lastdemo[256], bestdemo[256]; - I_mkdir(va("%s"PATHSEP"replay", srb2home), 0755); - I_mkdir(va("%s"PATHSEP"replay"PATHSEP"%s", srb2home, timeattackfolder), 0755); + // Save demo! + bestdemo[255] = '\0'; + lastdemo[255] = '\0'; + G_SetDemoTime(totaltime, totalscore, 0); + G_CheckDemoStatus(); - if ((gpath = malloc(glen)) == NULL) - I_Error("Out of memory for replay filepath\n"); + I_mkdir(va("%s"PATHSEP"replay", srb2home), 0755); + I_mkdir(va("%s"PATHSEP"replay"PATHSEP"%s", srb2home, timeattackfolder), 0755); - sprintf(gpath,"%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s", srb2home, timeattackfolder, G_BuildMapName(gamemap)); - snprintf(lastdemo, 255, "%s-%s-last.lmp", gpath, skins[cv_chooseskin.value-1].name); + if ((gpath = malloc(glen)) == NULL) + I_Error("Out of memory for replay filepath\n"); - if (FIL_FileExists(lastdemo)) - { - UINT8 *buf; - size_t len = FIL_ReadFile(lastdemo, &buf); + sprintf(gpath,"%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s", srb2home, timeattackfolder, G_BuildMapName(gamemap)); + snprintf(lastdemo, 255, "%s-%s-last.lmp", gpath, skins[cv_chooseskin.value-1].name); - snprintf(bestdemo, 255, "%s-%s-time-best.lmp", gpath, skins[cv_chooseskin.value-1].name);; - if (!FIL_FileExists(bestdemo) || G_CmpDemoTime(bestdemo, lastdemo) & 1) - { // Better time, save this demo. - if (FIL_FileExists(bestdemo)) - remove(bestdemo); - FIL_WriteFile(bestdemo, buf, len); - CONS_Printf("\x83%s\x80 %s '%s'\n", M_GetText("NEW RECORD TIME!"), M_GetText("Saved replay as"), bestdemo); - } + if (FIL_FileExists(lastdemo)) + { + UINT8 *buf; + size_t len = FIL_ReadFile(lastdemo, &buf); + + snprintf(bestdemo, 255, "%s-%s-time-best.lmp", gpath, skins[cv_chooseskin.value-1].name);; + if (!FIL_FileExists(bestdemo) || G_CmpDemoTime(bestdemo, lastdemo) & 1) + { // Better time, save this demo. + if (FIL_FileExists(bestdemo)) + remove(bestdemo); + FIL_WriteFile(bestdemo, buf, len); + CONS_Printf("\x83%s\x80 %s '%s'\n", M_GetText("NEW RECORD TIME!"), M_GetText("Saved replay as"), bestdemo); + } - snprintf(bestdemo, 255, "%s-%s-score-best.lmp", gpath, skins[cv_chooseskin.value-1].name); - if (!FIL_FileExists(bestdemo) || (G_CmpDemoTime(bestdemo, lastdemo) & (1<<1))) - { // Better score, save this demo. - if (FIL_FileExists(bestdemo)) - remove(bestdemo); - FIL_WriteFile(bestdemo, buf, len); - CONS_Printf("\x83%s\x80 %s '%s'\n", M_GetText("NEW HIGH SCORE!"), M_GetText("Saved replay as"), bestdemo); - } + snprintf(bestdemo, 255, "%s-%s-score-best.lmp", gpath, skins[cv_chooseskin.value-1].name); + if (!FIL_FileExists(bestdemo) || (G_CmpDemoTime(bestdemo, lastdemo) & (1<<1))) + { // Better score, save this demo. + if (FIL_FileExists(bestdemo)) + remove(bestdemo); + FIL_WriteFile(bestdemo, buf, len); + CONS_Printf("\x83%s\x80 %s '%s'\n", M_GetText("NEW HIGH SCORE!"), M_GetText("Saved replay as"), bestdemo); + } - //CONS_Printf("%s '%s'\n", M_GetText("Saved replay as"), lastdemo); + //CONS_Printf("%s '%s'\n", M_GetText("Saved replay as"), lastdemo); - Z_Free(buf); + Z_Free(buf); + } + free(gpath); } - free(gpath); if ((earnedEmblems = M_CheckLevelEmblems(data))) + { CONS_Printf(M_GetText("\x82" "Earned %hu emblem%s for NiGHTS records.\n"), (UINT16)earnedEmblems, earnedEmblems > 1 ? "s" : ""); + } // If the mare count changed, this will update the score display Nextmap_OnChange(); @@ -1413,6 +1444,7 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer) // I assume this is netgame-safe because gunslinger spawns this for only the local player...... *sweats intensely* newtarget = P_SpawnMobj(ticcmd_ztargetfocus[forplayer]->x, ticcmd_ztargetfocus[forplayer]->y, ticcmd_ztargetfocus[forplayer]->z, MT_LOCKON); // positioning, flip handled in P_SceneryThinker P_SetTarget(&newtarget->target, ticcmd_ztargetfocus[forplayer]); + newtarget->drawonlyforplayer = player; // Hide it from the other player in splitscreen, and yourself when spectating if (player->mo && P_AproxDistance( player->mo->x - ticcmd_ztargetfocus[forplayer]->x, @@ -1915,6 +1947,7 @@ void G_PreLevelTitleCard(void) ST_runTitleCard(); ST_preLevelTitleCardDrawer(); I_FinishUpdate(); // page flip or blit buffer + NetKeepAlive(); // Prevent timeouts if (moviemode) M_SaveFrame(); @@ -2049,7 +2082,7 @@ boolean G_Responder(event_t *ev) if (gameaction == ga_nothing && !singledemo && ((demoplayback && !modeattacking && !titledemo) || gamestate == GS_TITLESCREEN)) { - if (ev->type == ev_keydown && ev->key != 301 && !(gamestate == GS_TITLESCREEN && finalecount < TICRATE)) + if (ev->type == ev_keydown && ev->key != 301 && !(gamestate == GS_TITLESCREEN && finalecount < (cv_tutorialprompt.value ? TICRATE : 0))) { M_StartControlPanel(); return true; @@ -2107,7 +2140,7 @@ boolean G_Responder(event_t *ev) if (! netgame) F_StartGameEvaluation(); else if (server || IsPlayerAdmin(consoleplayer)) - SendNetXCmd(XD_EXITLEVEL, NULL, 0); + D_SendExitLevel(false); return true; } } @@ -2142,9 +2175,9 @@ boolean G_Responder(event_t *ev) if (menuactive || pausedelay < 0 || leveltime < 2) return true; - if (pausedelay < 1+(NEWTICRATE/2)) + if (!cv_instantretry.value && pausedelay < 1+(NEWTICRATE/2)) pausedelay = 1+(NEWTICRATE/2); - else if (++pausedelay > 1+(NEWTICRATE/2)+(NEWTICRATE/3)) + else if (cv_instantretry.value || ++pausedelay > 1+(NEWTICRATE/2)+(NEWTICRATE/3)) { G_SetModeAttackRetryFlag(); return true; @@ -2287,7 +2320,7 @@ void G_Ticker(boolean run) p->lives = startinglivesbalance[0]; p->continues = 1; - p->score = 0; + p->score = p->recordscore = 0; // The latter two should clear by themselves, but just in case p->pflags &= ~(PF_TAGIT|PF_GAMETYPEOVER|PF_FULLSTASIS); @@ -2437,14 +2470,17 @@ void G_Ticker(boolean run) case GS_TITLESCREEN: if (titlemapinaction) P_Ticker(run); - // then intentionally fall through - /* FALLTHRU */ - case GS_WAITINGPLAYERS: if (run) F_MenuPresTicker(); F_TitleScreenTicker(run); break; + case GS_WAITINGPLAYERS: + if (netgame) + F_WaitingPlayersTicker(); + HU_Ticker(); + break; + case GS_DEDICATEDSERVER: case GS_NULL: break; // do nothing @@ -3165,6 +3201,7 @@ void G_DoReborn(INT32 playernum) { if (!playeringame[i]) continue; + players[i].recordscore = 0; players[i].starpostscale = 0; players[i].starpostangle = 0; players[i].starposttime = 0; @@ -3427,9 +3464,7 @@ UINT32 gametypedefaultrules[NUMGAMETYPES] = }; // -// G_SetGametype -// -// Set a new gametype, also setting gametype rules accordingly. Yay! +// Sets a new gametype. // void G_SetGametype(INT16 gtype) { @@ -3827,7 +3862,7 @@ static INT16 RandMap(UINT32 tolflags, INT16 pprevmap) for (ix = 0; ix < NUMMAPS; ix++) if (mapheaderinfo[ix] && (mapheaderinfo[ix]->typeoflevel & tolflags) == tolflags && ix != pprevmap // Don't pick the same map. - && (dedicated || !M_MapLocked(ix+1, serverGamedata)) // Don't pick locked maps. + && (!M_MapLocked(ix+1, serverGamedata)) // Don't pick locked maps. ) okmaps[numokmaps++] = ix; @@ -3844,15 +3879,16 @@ static INT16 RandMap(UINT32 tolflags, INT16 pprevmap) // // G_UpdateVisited // -static void G_UpdateVisited(gamedata_t *data, boolean silent) +static void G_UpdateVisited(gamedata_t *data, player_t *player, boolean silent) { - boolean spec = G_IsSpecialStage(gamemap); // Update visitation flags? if (!demoplayback && G_CoopGametype() // Campaign mode && !stagefailed) // Did not fail the stage { UINT8 earnedEmblems; + UINT16 totalrings = 0; + INT32 i; // Update visitation flags data->mapvisited[gamemap-1] |= MV_BEATEN; @@ -3861,36 +3897,62 @@ static void G_UpdateVisited(gamedata_t *data, boolean silent) if (ultimatemode) data->mapvisited[gamemap-1] |= MV_ULTIMATE; + for (i = 0; i < MAXPLAYERS; i++) + { + if (!playeringame[i]) + { + continue; + } + + totalrings += players[i].rings; + } + // may seem incorrect but IS possible in what the main game uses as mp special stages, and nummaprings will be -1 in NiGHTS - if (nummaprings > 0 && players[consoleplayer].rings >= nummaprings) + if (nummaprings > 0 && totalrings >= nummaprings) { data->mapvisited[gamemap-1] |= MV_PERFECT; if (modeattacking) data->mapvisited[gamemap-1] |= MV_PERFECTRA; } - if (!spec) + if (!G_IsSpecialStage(gamemap)) { // not available to special stages because they can only really be done in one order in an unmodified game, so impossible for first six and trivial for seventh if (ALL7EMERALDS(emeralds)) data->mapvisited[gamemap-1] |= MV_ALLEMERALDS; } + if ((earnedEmblems = M_CompletionEmblems(data)) && !silent) + { + CONS_Printf(M_GetText("\x82" "Earned %hu emblem%s for level completion.\n"), (UINT16)earnedEmblems, earnedEmblems > 1 ? "s" : ""); + } + if (silent) { - if (modeattacking) - M_CheckLevelEmblems(data); + M_CheckLevelEmblems(data); } else { - if (modeattacking == ATTACKING_RECORD) - G_UpdateRecordReplays(data); - else if (modeattacking == ATTACKING_NIGHTS) - G_SetNightsRecords(data); + if (mapheaderinfo[gamemap-1]->menuflags & LF2_RECORDATTACK) + G_SetMainRecords(data, player); + else if (mapheaderinfo[gamemap-1]->menuflags & LF2_NIGHTSATTACK) + G_SetNightsRecords(data, player); } + } +} - if ((earnedEmblems = M_CompletionEmblems(data)) && !silent) - CONS_Printf(M_GetText("\x82" "Earned %hu emblem%s for level completion.\n"), (UINT16)earnedEmblems, earnedEmblems > 1 ? "s" : ""); +static void G_UpdateAllVisited(void) +{ + // Update server + G_UpdateVisited(serverGamedata, &players[serverplayer], true); + + // Update client + G_UpdateVisited(clientGamedata, &players[consoleplayer], false); + + if (splitscreen) + { + // Allow P2 to get emblems too, why not :) + G_UpdateVisited(clientGamedata, &players[secondarydisplayplayer], false); } } @@ -3914,6 +3976,9 @@ static boolean CanSaveLevel(INT32 mapnum) static void G_HandleSaveLevel(void) { + // Update records & emblems + G_UpdateAllVisited(); + // do this before running the intermission or custom cutscene, mostly for the sake of marathon mode but it also massively reduces redundant file save events in f_finale.c if (nextmap >= 1100-1) { @@ -3989,6 +4054,13 @@ static void G_DoCompleted(void) nextmap = 1100-1; // No infinite loop for you } + INT16 gametype_to_use; + + if (nextgametype >= 0 && nextgametype < gametypecount) + gametype_to_use = nextgametype; + else + gametype_to_use = gametype; + // If nextmap is actually going to get used, make sure it points to // a map of the proper gametype -- skip levels that don't support // the current gametype. (Helps avoid playing boss levels in Race, @@ -3997,8 +4069,8 @@ static void G_DoCompleted(void) { if (nextmap >= 0 && nextmap < NUMMAPS) { - register INT16 cm = nextmap; - UINT32 tolflag = G_TOLFlag(gametype); + INT16 cm = nextmap; + UINT32 tolflag = G_TOLFlag(gametype_to_use); UINT8 visitedmap[(NUMMAPS+7)/8]; memset(visitedmap, 0, sizeof (visitedmap)); @@ -4053,7 +4125,7 @@ static void G_DoCompleted(void) { token--; - if (!nextmapoverride) +// if (!nextmapoverride) // Having a token should pull the player into the special stage before going to the overridden map (Issue #933) for (i = 0; i < 7; i++) if (!(emeralds & (1<<i))) { @@ -4078,7 +4150,7 @@ static void G_DoCompleted(void) if (cv_advancemap.value == 0) // Stay on same map. nextmap = prevmap; else if (cv_advancemap.value == 2) // Go to random map. - nextmap = RandMap(G_TOLFlag(gametype), prevmap); + nextmap = RandMap(G_TOLFlag(gametype_to_use), prevmap); } // We are committed to this map now. @@ -4087,13 +4159,10 @@ static void G_DoCompleted(void) if (nextmap < NUMMAPS && !mapheaderinfo[nextmap]) P_AllocMapHeader(nextmap); - // If the current gametype has no intermission screen set, then don't start it. Y_DetermineIntermissionType(); if ((skipstats && !modeattacking) || (modeattacking && stagefailed) || (intertype == int_none)) { - G_UpdateVisited(serverGamedata, true); - G_UpdateVisited(clientGamedata, false); G_HandleSaveLevel(); G_AfterIntermission(); } @@ -4102,8 +4171,6 @@ static void G_DoCompleted(void) G_SetGamestate(GS_INTERMISSION); Y_StartIntermission(); Y_LoadIntermissionData(); - G_UpdateVisited(serverGamedata, true); - G_UpdateVisited(clientGamedata, false); G_HandleSaveLevel(); } } @@ -4157,12 +4224,21 @@ static void G_DoWorldDone(void) { if (server) { + INT16 gametype_to_use; + + if (nextgametype >= 0 && nextgametype < gametypecount) + gametype_to_use = nextgametype; + else + gametype_to_use = gametype; + if (gametyperules & GTR_CAMPAIGN) // don't reset player between maps - D_MapChange(nextmap+1, gametype, ultimatemode, false, 0, false, false); + D_MapChange(nextmap+1, gametype_to_use, ultimatemode, false, 0, false, false); else // resetplayer in match/chaos/tag/CTF/race for more equality - D_MapChange(nextmap+1, gametype, ultimatemode, true, 0, false, false); + D_MapChange(nextmap+1, gametype_to_use, ultimatemode, true, 0, false, false); + + nextgametype = -1; } gameaction = ga_nothing; @@ -4205,7 +4281,7 @@ static void G_DoContinued(void) { player_t *pl = &players[consoleplayer]; I_Assert(!netgame && !multiplayer); - I_Assert(pl->continues > 0); + //I_Assert(pl->continues > 0); if (pl->continues) pl->continues--; @@ -4309,6 +4385,12 @@ void G_LoadGameData(gamedata_t *data) // Stop saving, until we successfully load it again. data->loaded = false; + // Backwards compat stuff + INT32 max_emblems = MAXEMBLEMS; + INT32 max_extraemblems = MAXEXTRAEMBLEMS; + INT32 max_unlockables = MAXUNLOCKABLES; + INT32 max_conditionsets = MAXCONDITIONSETS; + // Clear things so previously read gamedata doesn't transfer // to new gamedata G_ClearRecords(data); // main and nights records @@ -4325,7 +4407,7 @@ void G_LoadGameData(gamedata_t *data) { // Don't load, but do save. (essentially, reset) data->loaded = true; - return; + return; } length = FIL_ReadFile(va(pandf, srb2home, gamedatafilename), &savebuffer); @@ -4355,6 +4437,14 @@ void G_LoadGameData(gamedata_t *data) I_Error("Game data is from another version of SRB2.\nDelete %s(maybe in %s) and try again.", gamedatafilename, gdfolder); } +#ifdef COMPAT_GAMEDATA_ID // Account for lower MAXUNLOCKABLES and MAXEXTRAEMBLEMS from older versions + if (versionID == COMPAT_GAMEDATA_ID) + { + max_extraemblems = 16; + max_unlockables = 32; + } +#endif + data->totalplaytime = READUINT32(save_p); #ifdef COMPAT_GAMEDATA_ID @@ -4372,6 +4462,17 @@ void G_LoadGameData(gamedata_t *data) { goto datacorrupt; } + + // make a backup of the old data + char currentfilename[64]; + char backupfilename[69]; + char bak[5]; + + strcpy(bak, ".bak"); + strcpy(currentfilename, gamedatafilename); + STRBUFCPY(backupfilename, strcat(currentfilename, bak)); + + FIL_WriteFile(va(pandf, srb2home, backupfilename), savebuffer, length); } else #endif @@ -4393,31 +4494,31 @@ void G_LoadGameData(gamedata_t *data) goto datacorrupt; // To save space, use one bit per collected/achieved/unlocked flag - for (i = 0; i < MAXEMBLEMS;) + for (i = 0; i < max_emblems;) { rtemp = READUINT8(save_p); - for (j = 0; j < 8 && j+i < MAXEMBLEMS; ++j) + for (j = 0; j < 8 && j+i < max_emblems; ++j) data->collected[j+i] = ((rtemp >> j) & 1); i += j; } - for (i = 0; i < MAXEXTRAEMBLEMS;) + for (i = 0; i < max_extraemblems;) { rtemp = READUINT8(save_p); - for (j = 0; j < 8 && j+i < MAXEXTRAEMBLEMS; ++j) + for (j = 0; j < 8 && j+i < max_extraemblems; ++j) data->extraCollected[j+i] = ((rtemp >> j) & 1); i += j; } - for (i = 0; i < MAXUNLOCKABLES;) + for (i = 0; i < max_unlockables;) { rtemp = READUINT8(save_p); - for (j = 0; j < 8 && j+i < MAXUNLOCKABLES; ++j) + for (j = 0; j < 8 && j+i < max_unlockables; ++j) data->unlocked[j+i] = ((rtemp >> j) & 1); i += j; } - for (i = 0; i < MAXCONDITIONSETS;) + for (i = 0; i < max_conditionsets;) { rtemp = READUINT8(save_p); - for (j = 0; j < 8 && j+i < MAXCONDITIONSETS; ++j) + for (j = 0; j < 8 && j+i < max_conditionsets; ++j) data->achieved[j+i] = ((rtemp >> j) & 1); i += j; } @@ -4962,12 +5063,20 @@ void G_InitNew(UINT8 pultmode, const char *mapname, boolean resetplayer, boolean numgameovers = tokenlist = token = sstimer = redscore = bluescore = lastmap = 0; countdown = countdown2 = exitfadestarted = 0; + if (!FLS) + { + emeralds = 0; + memset(&luabanks, 0, sizeof(luabanks)); + } + for (i = 0; i < MAXPLAYERS; i++) { players[i].playerstate = PST_REBORN; players[i].starpostscale = players[i].starpostangle = players[i].starpostnum = players[i].starposttime = 0; players[i].starpostx = players[i].starposty = players[i].starpostz = 0; + players[i].recordscore = 0; + // default lives, continues and score if (netgame || multiplayer) { if (!FLS || (players[i].lives < 1)) @@ -5027,6 +5136,19 @@ void G_InitNew(UINT8 pultmode, const char *mapname, boolean resetplayer, boolean automapactive = false; imcontinuing = false; + // fetch saved data if available + if (savedata.lives > 0) + { + numgameovers = savedata.numgameovers; + players[consoleplayer].continues = savedata.continues; + players[consoleplayer].lives = savedata.lives; + players[consoleplayer].score = savedata.score; + if ((botingame = ((botskin = savedata.botskin) != 0))) + botcolor = skins[botskin-1].prefcolor; + emeralds = savedata.emeralds; + savedata.lives = 0; + } + if ((gametyperules & GTR_CUTSCENES) && !skipprecutscene && mapheaderinfo[gamemap-1]->precutscenenum && !modeattacking && !(marathonmode & MA_NOCUTSCENES)) // Start a custom cutscene. F_StartCustomCutscene(mapheaderinfo[gamemap-1]->precutscenenum-1, true, resetplayer, FLS); else diff --git a/src/g_game.h b/src/g_game.h index 6cda7ca9ccd8e4d7a7cba990fb2b9ffd58983103..9873430b936fd4b79f89d0adbcf714a303fae2ce 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -49,6 +49,8 @@ extern boolean promptactive; extern consvar_t cv_pauseifunfocused; +extern consvar_t cv_instantretry; + // used in game menu extern consvar_t cv_tutorialprompt; extern consvar_t cv_chatwidth, cv_chatnotifications, cv_chatheight, cv_chattime, cv_consolechat, cv_chatbacktint, cv_chatspamprotection, cv_compactscoreboard; @@ -260,8 +262,7 @@ UINT32 G_GetBestNightsScore(INT16 map, UINT8 mare, gamedata_t *data); tic_t G_GetBestNightsTime(INT16 map, UINT8 mare, gamedata_t *data); UINT8 G_GetBestNightsGrade(INT16 map, UINT8 mare, gamedata_t *data); -void G_AddTempNightsRecords(UINT32 pscore, tic_t ptime, UINT8 mare); -void G_SetNightsRecords(gamedata_t *data); +void G_AddTempNightsRecords(player_t *player, UINT32 pscore, tic_t ptime, UINT8 mare); FUNCMATH INT32 G_TicsToHours(tic_t tics); FUNCMATH INT32 G_TicsToMinutes(tic_t tics, boolean full); diff --git a/src/hardware/CMakeLists.txt b/src/hardware/CMakeLists.txt index 4e9c67d2f348a8bfed899e4002d25136284b031f..e7819aba97e2065d36f6f920d4725d7b294505f3 100644 --- a/src/hardware/CMakeLists.txt +++ b/src/hardware/CMakeLists.txt @@ -1 +1,14 @@ -target_sourcefile(c) +target_sources(SRB2SDL2 PRIVATE + hw_bsp.c + hw_draw.c + hw_light.c + hw_main.c + hw_clip.c + hw_md2.c + hw_cache.c + hw_md2load.c + hw_md3load.c + hw_model.c + hw_batching.c + r_opengl/r_opengl.c +) diff --git a/src/hardware/Sourcefile b/src/hardware/Sourcefile index 1c05de76cca6d71251023e3e9e7bdde7d8cffaab..6c374621d7b1de61f2b5a5c6fd9171f0685eccbf 100644 --- a/src/hardware/Sourcefile +++ b/src/hardware/Sourcefile @@ -8,6 +8,5 @@ hw_cache.c hw_md2load.c hw_md3load.c hw_model.c -u_list.c hw_batching.c r_opengl/r_opengl.c diff --git a/src/hardware/hw_batching.c b/src/hardware/hw_batching.c index d1b84a5eecb4aff512bb75cf7562327675622bf1..dc0b5ee5b00fae1b28591f78ab3cb39627f11645 100644 --- a/src/hardware/hw_batching.c +++ b/src/hardware/hw_batching.c @@ -42,10 +42,10 @@ int unsortedVertexArrayAllocSize = 65536; // Call HWR_RenderBatches to render all the collected geometry. void HWR_StartBatching(void) { - if (currently_batching) - I_Error("Repeat call to HWR_StartBatching without HWR_RenderBatches"); + if (currently_batching) + I_Error("Repeat call to HWR_StartBatching without HWR_RenderBatches"); - // init arrays if that has not been done yet + // init arrays if that has not been done yet if (!finalVertexArray) { finalVertexArray = malloc(finalVertexArrayAllocSize * sizeof(FOutVector)); @@ -55,7 +55,7 @@ void HWR_StartBatching(void) unsortedVertexArray = malloc(unsortedVertexArrayAllocSize * sizeof(FOutVector)); } - currently_batching = true; + currently_batching = true; } // This replaces the direct calls to pfnSetTexture in cases where batching is available. diff --git a/src/hardware/hw_defs.h b/src/hardware/hw_defs.h index b0859f478bd37d2315d742d0f7c80a580a5300bc..74c4ed7d2eec91d1c846ca0a43f23d636a1024f8 100644 --- a/src/hardware/hw_defs.h +++ b/src/hardware/hw_defs.h @@ -93,33 +93,22 @@ typedef struct FVector //Hurdler: Transform (coords + angles) //BP: transform order : scale(rotation_x(rotation_y(translation(v)))) -// Kart features -//#define USE_FTRANSFORM_ANGLEZ -//#define USE_FTRANSFORM_MIRROR - // Vanilla features #define USE_MODEL_NEXTFRAME typedef struct { FLOAT x,y,z; // position -#ifdef USE_FTRANSFORM_ANGLEZ FLOAT anglex,angley,anglez; // aimingangle / viewangle -#else - FLOAT anglex,angley; // aimingangle / viewangle -#endif FLOAT scalex,scaley,scalez; FLOAT fovxangle, fovyangle; UINT8 splitscreen; boolean flip; // screenflip boolean roll; - SINT8 rollflip; FLOAT rollangle; // done to not override USE_FTRANSFORM_ANGLEZ - UINT8 rotaxis; FLOAT centerx, centery; -#ifdef USE_FTRANSFORM_MIRROR + FLOAT rollx, rollz; boolean mirror; // SRB2Kart: Encore Mode -#endif boolean shearing; // 14042019 float viewaiming; // 17052019 } FTransform; @@ -136,6 +125,7 @@ typedef struct // Predefined shader types enum { + SHADER_NONE = -1, SHADER_DEFAULT = 0, SHADER_FLOOR, @@ -237,7 +227,8 @@ enum EPolyFlags PF_RemoveYWrap = 0x00010000, // Forces clamp texture on Y PF_ForceWrapX = 0x00020000, // Forces repeat texture on X PF_ForceWrapY = 0x00040000, // Forces repeat texture on Y - PF_Ripple = 0x00100000 // Water ripple effect. The current backend doesn't use it for anything. + PF_Ripple = 0x00100000, // Water ripple effect. The current backend doesn't use it for anything. + PF_WireFrame = 0x00200000, // Draws vertices as lines instead of triangles }; diff --git a/src/hardware/hw_drv.h b/src/hardware/hw_drv.h index 426d2f283b35668e70fe12520ad2dab0b6d23fd5..1c4cd99ab03d34498fa13d132a01ef53af9e6e61 100644 --- a/src/hardware/hw_drv.h +++ b/src/hardware/hw_drv.h @@ -51,7 +51,7 @@ EXPORT void HWRAPI(ClearMipMapCache) (void); EXPORT void HWRAPI(SetSpecialState) (hwdspecialstate_t IdState, INT32 Value); //Hurdler: added for new development -EXPORT void HWRAPI(DrawModel) (model_t *model, INT32 frameIndex, float duration, float tics, INT32 nextFrameIndex, FTransform *pos, float scale, UINT8 flipped, UINT8 hflipped, FSurfaceInfo *Surface); +EXPORT void HWRAPI(DrawModel) (model_t *model, INT32 frameIndex, float duration, float tics, INT32 nextFrameIndex, FTransform *pos, float hscale, float vscale, UINT8 flipped, UINT8 hflipped, FSurfaceInfo *Surface); EXPORT void HWRAPI(CreateModelVBOs) (model_t *model); EXPORT void HWRAPI(SetTransform) (FTransform *ptransform); EXPORT INT32 HWRAPI(GetTextureUsed) (void); @@ -136,4 +136,3 @@ extern struct hwdriver_s hwdriver; #endif //not defined _CREATE_DLL_ #endif //__HWR_DRV_H__ - diff --git a/src/hardware/hw_glob.h b/src/hardware/hw_glob.h index b5daba82261ce46cbe0393ca765146b4118fcfff..d391c415670846fad27d4a22e1e33f46ccb367b3 100644 --- a/src/hardware/hw_glob.h +++ b/src/hardware/hw_glob.h @@ -81,6 +81,7 @@ typedef struct gl_vissprite_s boolean flip, vflip; boolean precip; // Tails 08-25-2002 + boolean bbox; boolean rotated; UINT8 translucency; //alpha level 0-255 diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index 7ec0f76c2dea496d5b84eaac315f343abc7529b3..a17d454608ba9818b62fd3b1a7e86e8ab89ca18d 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -66,6 +66,7 @@ static void HWR_ProjectSprite(mobj_t *thing); #ifdef HWPRECIP static void HWR_ProjectPrecipitationSprite(precipmobj_t *thing); #endif +static void HWR_ProjectBoundingBox(mobj_t *thing); void HWR_AddTransparentFloor(levelflat_t *levelflat, extrasubsector_t *xsub, boolean isceiling, fixed_t fixedheight, INT32 lightlevel, INT32 alpha, sector_t *FOFSector, FBITFIELD blend, boolean fogplane, extracolormap_t *planecolormap); void HWR_AddTransparentPolyobjectFloor(levelflat_t *levelflat, polyobj_t *polysector, boolean isceiling, fixed_t fixedheight, @@ -139,7 +140,7 @@ static fixed_t dup_viewx, dup_viewy, dup_viewz; static angle_t dup_viewangle; static float gl_viewx, gl_viewy, gl_viewz; -static float gl_viewsin, gl_viewcos; +float gl_viewsin, gl_viewcos; // Maybe not necessary with the new T&L code (needs to be checked!) static float gl_viewludsin, gl_viewludcos; // look up down kik test @@ -459,30 +460,30 @@ static void HWR_RenderPlane(subsector_t *subsector, extrasubsector_t *xsub, bool { if (!isceiling) // it's a floor { - scrollx = FIXED_TO_FLOAT(FOFsector->floor_xoffs)/fflatwidth; - scrolly = FIXED_TO_FLOAT(FOFsector->floor_yoffs)/fflatheight; - angle = FOFsector->floorpic_angle; + scrollx = FIXED_TO_FLOAT(FOFsector->floorxoffset)/fflatwidth; + scrolly = FIXED_TO_FLOAT(FOFsector->flooryoffset)/fflatheight; + angle = FOFsector->floorangle; } else // it's a ceiling { - scrollx = FIXED_TO_FLOAT(FOFsector->ceiling_xoffs)/fflatwidth; - scrolly = FIXED_TO_FLOAT(FOFsector->ceiling_yoffs)/fflatheight; - angle = FOFsector->ceilingpic_angle; + scrollx = FIXED_TO_FLOAT(FOFsector->ceilingxoffset)/fflatwidth; + scrolly = FIXED_TO_FLOAT(FOFsector->ceilingyoffset)/fflatheight; + angle = FOFsector->ceilingangle; } } else if (gl_frontsector) { if (!isceiling) // it's a floor { - scrollx = FIXED_TO_FLOAT(gl_frontsector->floor_xoffs)/fflatwidth; - scrolly = FIXED_TO_FLOAT(gl_frontsector->floor_yoffs)/fflatheight; - angle = gl_frontsector->floorpic_angle; + scrollx = FIXED_TO_FLOAT(gl_frontsector->floorxoffset)/fflatwidth; + scrolly = FIXED_TO_FLOAT(gl_frontsector->flooryoffset)/fflatheight; + angle = gl_frontsector->floorangle; } else // it's a ceiling { - scrollx = FIXED_TO_FLOAT(gl_frontsector->ceiling_xoffs)/fflatwidth; - scrolly = FIXED_TO_FLOAT(gl_frontsector->ceiling_yoffs)/fflatheight; - angle = gl_frontsector->ceilingpic_angle; + scrollx = FIXED_TO_FLOAT(gl_frontsector->ceilingxoffset)/fflatwidth; + scrolly = FIXED_TO_FLOAT(gl_frontsector->ceilingyoffset)/fflatheight; + angle = gl_frontsector->ceilingangle; } } @@ -1712,7 +1713,7 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom if ((rover->fofflags & FOF_TRANSLUCENT && !(rover->fofflags & FOF_SPLAT)) || rover->blend) { blendmode = rover->blend ? HWR_GetBlendModeFlag(rover->blend) : PF_Translucent; - Surf.PolyColor.s.alpha = (UINT8)rover->alpha-1 > 255 ? 255 : rover->alpha-1; + Surf.PolyColor.s.alpha = max(0, min(rover->alpha, 255)); } if (gl_frontsector->numlights) @@ -1837,7 +1838,7 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom if ((rover->fofflags & FOF_TRANSLUCENT && !(rover->fofflags & FOF_SPLAT)) || rover->blend) { blendmode = rover->blend ? HWR_GetBlendModeFlag(rover->blend) : PF_Translucent; - Surf.PolyColor.s.alpha = (UINT8)rover->alpha-1 > 255 ? 255 : rover->alpha-1; + Surf.PolyColor.s.alpha = max(0, min(rover->alpha, 255)); } if (gl_backsector->numlights) @@ -2735,30 +2736,30 @@ static void HWR_RenderPolyObjectPlane(polyobj_t *polysector, boolean isceiling, { if (!isceiling) // it's a floor { - scrollx = FIXED_TO_FLOAT(FOFsector->floor_xoffs)/fflatwidth; - scrolly = FIXED_TO_FLOAT(FOFsector->floor_yoffs)/fflatheight; - angle = FOFsector->floorpic_angle; + scrollx = FIXED_TO_FLOAT(FOFsector->floorxoffset)/fflatwidth; + scrolly = FIXED_TO_FLOAT(FOFsector->flooryoffset)/fflatheight; + angle = FOFsector->floorangle; } else // it's a ceiling { - scrollx = FIXED_TO_FLOAT(FOFsector->ceiling_xoffs)/fflatwidth; - scrolly = FIXED_TO_FLOAT(FOFsector->ceiling_yoffs)/fflatheight; - angle = FOFsector->ceilingpic_angle; + scrollx = FIXED_TO_FLOAT(FOFsector->ceilingxoffset)/fflatwidth; + scrolly = FIXED_TO_FLOAT(FOFsector->ceilingyoffset)/fflatheight; + angle = FOFsector->ceilingangle; } } else if (gl_frontsector) { if (!isceiling) // it's a floor { - scrollx = FIXED_TO_FLOAT(gl_frontsector->floor_xoffs)/fflatwidth; - scrolly = FIXED_TO_FLOAT(gl_frontsector->floor_yoffs)/fflatheight; - angle = gl_frontsector->floorpic_angle; + scrollx = FIXED_TO_FLOAT(gl_frontsector->floorxoffset)/fflatwidth; + scrolly = FIXED_TO_FLOAT(gl_frontsector->flooryoffset)/fflatheight; + angle = gl_frontsector->floorangle; } else // it's a ceiling { - scrollx = FIXED_TO_FLOAT(gl_frontsector->ceiling_xoffs)/fflatwidth; - scrolly = FIXED_TO_FLOAT(gl_frontsector->ceiling_yoffs)/fflatheight; - angle = gl_frontsector->ceilingpic_angle; + scrollx = FIXED_TO_FLOAT(gl_frontsector->ceilingxoffset)/fflatwidth; + scrolly = FIXED_TO_FLOAT(gl_frontsector->ceilingyoffset)/fflatheight; + angle = gl_frontsector->ceilingangle; } } @@ -3110,7 +3111,7 @@ static void HWR_Subsector(size_t num) false, *rover->bottomheight, *gl_frontsector->lightlist[light].lightlevel, - rover->alpha-1 > 255 ? 255 : rover->alpha-1, rover->master->frontsector, + max(0, min(rover->alpha, 255)), rover->master->frontsector, HWR_RippleBlend(gl_frontsector, rover, false) | (rover->blend ? HWR_GetBlendModeFlag(rover->blend) : PF_Translucent), false, *gl_frontsector->lightlist[light].extra_colormap); } @@ -3156,7 +3157,7 @@ static void HWR_Subsector(size_t num) true, *rover->topheight, *gl_frontsector->lightlist[light].lightlevel, - rover->alpha-1 > 255 ? 255 : rover->alpha-1, rover->master->frontsector, + max(0, min(rover->alpha, 255)), rover->master->frontsector, HWR_RippleBlend(gl_frontsector, rover, false) | (rover->blend ? HWR_GetBlendModeFlag(rover->blend) : PF_Translucent), false, *gl_frontsector->lightlist[light].extra_colormap); } @@ -3610,7 +3611,7 @@ static void HWR_DrawDropShadow(mobj_t *thing, fixed_t scale) return; } - floordiff = abs((flip < 0 ? thing->height : 0) + interp.z - groundz); + floordiff = abs((flip < 0 ? interp.height : 0) + interp.z - groundz); alpha = floordiff / (4*FRACUNIT) + 75; if (alpha >= 255) return; @@ -3621,9 +3622,7 @@ static void HWR_DrawDropShadow(mobj_t *thing, fixed_t scale) HWR_GetPatch(gpatch); scalemul = FixedMul(FRACUNIT - floordiff/640, scale); - scalemul = FixedMul(scalemul, (thing->radius*2) / gpatch->height); - if ((thing->scale != thing->old_scale) && (thing->scale >= FRACUNIT/1024)) // Interpolate shadows when scaling mobjs - scalemul = FixedMul(scalemul, FixedDiv(interp.scale, thing->scale)); + scalemul = FixedMul(scalemul, (interp.radius*2) / gpatch->height); fscale = FIXED_TO_FLOAT(scalemul); fx = FIXED_TO_FLOAT(interp.x); @@ -3735,7 +3734,7 @@ static void HWR_RotateSpritePolyToAim(gl_vissprite_t *spr, FOutVector *wallVerts if (P_MobjFlip(spr->mobj) == -1) { - basey = FIXED_TO_FLOAT(interp.z + spr->mobj->height); + basey = FIXED_TO_FLOAT(interp.z + interp.height); } else { @@ -4054,6 +4053,54 @@ static void HWR_SplitSprite(gl_vissprite_t *spr) HWR_LinkDrawHackAdd(wallVerts, spr); } +static void HWR_DrawBoundingBox(gl_vissprite_t *vis) +{ + FOutVector v[24]; + FSurfaceInfo Surf = {0}; + + // + // create a cube (side view) + // + // 5--4 3 + // | + // | + // 0--1 2 + // + // repeat this 4 times (overhead) + // + // + // 15 16 17 09 + // 14 13 12 08 + // 23 18 *--* 07 10 + // | | + // 22 19 *--* 06 11 + // 20 00 01 02 + // 21 05 04 03 + // + + v[ 0].x = v[ 5].x = v[13].x = v[14].x = v[15].x = v[16].x = + v[18].x = v[19].x = v[20].x = v[21].x = v[22].x = v[23].x = vis->x1; // west + + v[ 1].x = v[ 2].x = v[ 3].x = v[ 4].x = v[ 6].x = v[ 7].x = + v[ 8].x = v[ 9].x = v[10].x = v[11].x = v[12].x = v[17].x = vis->x2; // east + + v[ 0].z = v[ 1].z = v[ 2].z = v[ 3].z = v[ 4].z = v[ 5].z = + v[ 6].z = v[11].z = v[19].z = v[20].z = v[21].z = v[22].z = vis->z1; // south + + v[ 7].z = v[ 8].z = v[ 9].z = v[10].z = v[12].z = v[13].z = + v[14].z = v[15].z = v[16].z = v[17].z = v[18].z = v[23].z = vis->z2; // north + + v[ 0].y = v[ 1].y = v[ 2].y = v[ 6].y = v[ 7].y = v[ 8].y = + v[12].y = v[13].y = v[14].y = v[18].y = v[19].y = v[20].y = vis->gz; // bottom + + v[ 3].y = v[ 4].y = v[ 5].y = v[ 9].y = v[10].y = v[11].y = + v[15].y = v[16].y = v[17].y = v[21].y = v[22].y = v[23].y = vis->gzt; // top + + Surf.PolyColor = V_GetColor(R_GetBoundingBoxColor(vis->mobj)); + + HWR_ProcessPolygon(&Surf, v, 24, (cv_renderhitboxgldepth.value ? 0 : PF_NoDepthTest)|PF_Modulated|PF_NoTexture|PF_WireFrame, SHADER_NONE, false); +} + // -----------------+ // HWR_DrawSprite : Draw flat sprites // : (monsters, bonuses, weapons, lights, ...) @@ -4110,14 +4157,11 @@ static void HWR_DrawSprite(gl_vissprite_t *spr) float xscale, yscale; float xoffset, yoffset; float leftoffset, topoffset; - float scale = spr->scale; float zoffset = (P_MobjFlip(spr->mobj) * 0.05f); pslope_t *splatslope = NULL; INT32 i; renderflags_t renderflags = spr->renderflags; - if (renderflags & RF_SHADOWEFFECTS) - scale *= spr->shadowscale; if (spr->rotateflags & SRF_3D || renderflags & RF_NOSPLATBILLBOARD) angle = spr->mobj->angle; @@ -4125,7 +4169,7 @@ static void HWR_DrawSprite(gl_vissprite_t *spr) angle = viewangle; if (!spr->rotated) - angle += spr->mobj->rollangle; + angle += spr->mobj->spriteroll; angle = -angle; angle += ANGLE_90; @@ -4498,9 +4542,16 @@ static int CompareVisSprites(const void *p1, const void *p2) int transparency1; int transparency2; + int linkdraw1; + int linkdraw2; + + // draw bbox after everything else + if (spr1->bbox || spr2->bbox) + return (spr1->bbox - spr2->bbox); + // check for precip first, because then sprX->mobj is actually a precipmobj_t and does not have flags2 or tracer - int linkdraw1 = !spr1->precip && (spr1->mobj->flags2 & MF2_LINKDRAW) && spr1->mobj->tracer; - int linkdraw2 = !spr2->precip && (spr2->mobj->flags2 & MF2_LINKDRAW) && spr2->mobj->tracer; + linkdraw1 = !spr1->precip && (spr1->mobj->flags2 & MF2_LINKDRAW) && spr1->mobj->tracer; + linkdraw2 = !spr2->precip && (spr2->mobj->flags2 & MF2_LINKDRAW) && spr2->mobj->tracer; // ^ is the XOR operation // if comparing a linkdraw and non-linkdraw sprite or 2 linkdraw sprites with different tracers, then use @@ -4870,6 +4921,9 @@ static void HWR_DrawSprites(void) for (i = 0; i < gl_visspritecount; i++) { gl_vissprite_t *spr = gl_vsprorder[i]; + if (spr->bbox) + HWR_DrawBoundingBox(spr); + else #ifdef HWPRECIP if (spr->precip) HWR_DrawPrecipitationSprite(spr); @@ -4969,8 +5023,15 @@ static void HWR_AddSprites(sector_t *sec) hoop_limit_dist = (fixed_t)(cv_drawdist_nights.value) << FRACBITS; for (thing = sec->thinglist; thing; thing = thing->snext) { - if (R_ThingVisibleWithinDist(thing, limit_dist, hoop_limit_dist)) - HWR_ProjectSprite(thing); + if (R_ThingWithinDist(thing, limit_dist, hoop_limit_dist)) + { + if (R_ThingVisible(thing)) + { + HWR_ProjectSprite(thing); + } + + HWR_ProjectBoundingBox(thing); + } } #ifdef HWPRECIP @@ -5028,6 +5089,7 @@ static void HWR_ProjectSprite(mobj_t *thing) #ifdef ROTSPRITE patch_t *rotsprite = NULL; INT32 rollangle = 0; + angle_t spriterotangle = 0; #endif // uncapped/interpolation @@ -5195,18 +5257,21 @@ static void HWR_ProjectSprite(mobj_t *thing) spr_topoffset = spritecachedinfo[lumpoff].topoffset; #ifdef ROTSPRITE - if (thing->rollangle + spriterotangle = R_SpriteRotationAngle(&interp); + + if (spriterotangle != 0 && !(splat && !(thing->renderflags & RF_NOSPLATROLLANGLE))) { if (papersprite) { // a positive rollangle should should pitch papersprites upwards relative to their facing angle - rollangle = R_GetRollAngle(InvAngle(thing->rollangle)); + rollangle = R_GetRollAngle(InvAngle(spriterotangle)); } else { - rollangle = R_GetRollAngle(thing->rollangle); + rollangle = R_GetRollAngle(spriterotangle); } + rotsprite = Patch_GetRotatedSprite(sprframe, (thing->frame & FF_FRAMEMASK), rot, flip, false, sprinfo, rollangle); if (rotsprite != NULL) @@ -5272,7 +5337,7 @@ static void HWR_ProjectSprite(mobj_t *thing) } groundz = R_GetShadowZ(thing, NULL); - floordiff = abs(((thing->eflags & MFE_VERTICALFLIP) ? caster->height : 0) + casterinterp.z - groundz); + floordiff = abs(((thing->eflags & MFE_VERTICALFLIP) ? casterinterp.height : 0) + casterinterp.z - groundz); shadowheight = FIXED_TO_FLOAT(floordiff); shadowscale = FIXED_TO_FLOAT(FixedMul(FRACUNIT - floordiff/640, casterinterp.scale)); @@ -5324,7 +5389,7 @@ static void HWR_ProjectSprite(mobj_t *thing) if (vflip) { - gz = FIXED_TO_FLOAT(interp.z + thing->height) - (FIXED_TO_FLOAT(spr_topoffset) * this_yscale); + gz = FIXED_TO_FLOAT(interp.z + interp.height) - (FIXED_TO_FLOAT(spr_topoffset) * this_yscale); gzt = gz + (FIXED_TO_FLOAT(spr_height) * this_yscale); } else @@ -5488,6 +5553,7 @@ static void HWR_ProjectSprite(mobj_t *thing) vis->vflip = vflip; vis->precip = false; + vis->bbox = false; vis->angle = interp.angle; } @@ -5610,6 +5676,7 @@ static void HWR_ProjectPrecipitationSprite(precipmobj_t *thing) vis->gz = vis->gzt - FIXED_TO_FLOAT(spritecachedinfo[lumpoff].height); vis->precip = true; + vis->bbox = false; // okay... this is a hack, but weather isn't networked, so it should be ok if (!(thing->precipflags & PCF_THUNK)) @@ -5623,6 +5690,58 @@ static void HWR_ProjectPrecipitationSprite(precipmobj_t *thing) } #endif +static void HWR_ProjectBoundingBox(mobj_t *thing) +{ + gl_vissprite_t *vis; + float tr_x, tr_y; + float tz; + + if (!thing) + return; + + if (!R_ThingBoundingBoxVisible(thing)) + return; + + // uncapped/interpolation + boolean interpolate = cv_renderhitboxinterpolation.value; + interpmobjstate_t interp = {0}; + + if (R_UsingFrameInterpolation() && !paused && interpolate) + { + R_InterpolateMobjState(thing, rendertimefrac, &interp); + } + else + { + R_InterpolateMobjState(thing, FRACUNIT, &interp); + } + + // transform the origin point + tr_x = FIXED_TO_FLOAT(interp.x) - gl_viewx; + tr_y = FIXED_TO_FLOAT(interp.y) - gl_viewy; + + // rotation around vertical axis + tz = (tr_x * gl_viewcos) + (tr_y * gl_viewsin); + + // thing is behind view plane? + if (tz < ZCLIP_PLANE) + return; + + tr_x += gl_viewx; + tr_y += gl_viewy; + + vis = HWR_NewVisSprite(); + vis->x1 = tr_x - FIXED_TO_FLOAT(interp.radius); + vis->x2 = tr_x + FIXED_TO_FLOAT(interp.radius); + vis->z1 = tr_y - FIXED_TO_FLOAT(interp.radius); + vis->z2 = tr_y + FIXED_TO_FLOAT(interp.radius); + vis->gz = FIXED_TO_FLOAT(interp.z); + vis->gzt = vis->gz + FIXED_TO_FLOAT(interp.height); + vis->mobj = thing; + + vis->precip = false; + vis->bbox = true; +} + // ========================================================================== // Sky dome rendering, ported from PrBoom+ // ========================================================================== @@ -5806,6 +5925,8 @@ static void HWR_DrawSkyBackground(player_t *player) fixed_t rol = AngleFixed(player->viewrollangle); dometransform.rollangle = FIXED_TO_FLOAT(rol); dometransform.roll = true; + dometransform.rollx = 1.0f; + dometransform.rollz = 0.0f; } dometransform.splitscreen = splitscreen; @@ -6084,6 +6205,8 @@ void HWR_RenderSkyboxView(INT32 viewnumber, player_t *player) fixed_t rol = AngleFixed(player->viewrollangle); atransform.rollangle = FIXED_TO_FLOAT(rol); atransform.roll = true; + atransform.rollx = 1.0f; + atransform.rollz = 0.0f; } atransform.splitscreen = splitscreen; @@ -6298,6 +6421,8 @@ void HWR_RenderPlayerView(INT32 viewnumber, player_t *player) fixed_t rol = AngleFixed(player->viewrollangle); atransform.rollangle = FIXED_TO_FLOAT(rol); atransform.roll = true; + atransform.rollx = 1.0f; + atransform.rollz = 0.0f; } atransform.splitscreen = splitscreen; diff --git a/src/hardware/hw_main.h b/src/hardware/hw_main.h index 4a1b412fc6539e64b86ac63a9b20288ac506b52f..9450ca2c56ed56d52916f587136e2e9352f3f4b4 100644 --- a/src/hardware/hw_main.h +++ b/src/hardware/hw_main.h @@ -115,6 +115,7 @@ extern float gl_viewwindowx, gl_basewindowcentery; // BP: big hack for a test in lighting ref : 1249753487AB extern fixed_t *hwbbox; extern FTransform atransform; +extern float gl_viewsin, gl_viewcos; // Render stats diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c index 38e8e8fc4266f6158068906b516363ff8959cdaf..0f834213592e041c866ca05a90d2599476c81c76 100644 --- a/src/hardware/hw_md2.c +++ b/src/hardware/hw_md2.c @@ -486,7 +486,7 @@ void HWR_InitModels(void) size_t i; INT32 s; FILE *f; - char name[24], filename[32]; + char name[26], filename[32]; float scale, offset; size_t prefixlen; @@ -585,7 +585,7 @@ modelfound: void HWR_AddPlayerModel(int skin) // For skins that were added after startup { FILE *f; - char name[24], filename[32]; + char name[26], filename[32]; float scale, offset; size_t prefixlen; @@ -644,7 +644,7 @@ void HWR_AddSpriteModel(size_t spritenum) // For sprites that were added after s // name[24] is used to check for names in the models.dat file that match with sprites or player skins // sprite names are always 4 characters long, and names is for player skins can be up to 19 characters long // PLAYERMODELPREFIX is 6 characters long - char name[24], filename[32]; + char name[26], filename[32]; float scale, offset; if (nomd2s) @@ -1146,7 +1146,7 @@ static void HWR_GetBlendedTexture(patch_t *patch, patch_t *blendpatch, INT32 ski static boolean HWR_AllowModel(mobj_t *mobj) { // Signpost overlay. Not needed. - if (mobj->state-states == S_PLAY_SIGN) + if (mobj->sprite2 == SPR2_SIGN || mobj->state-states == S_PLAY_SIGN) return false; // Otherwise, render the model. @@ -1346,10 +1346,7 @@ boolean HWR_DrawModel(gl_vissprite_t *spr) const UINT8 hflip = (UINT8)(!(spr->mobj->mirrored) != !R_ThingHorizontallyFlipped(spr->mobj)); spritedef_t *sprdef; spriteframe_t *sprframe; - spriteinfo_t *sprinfo; - angle_t ang; INT32 mod; - float finalscale; interpmobjstate_t interp; if (R_UsingFrameInterpolation() && !paused) @@ -1388,12 +1385,10 @@ boolean HWR_DrawModel(gl_vissprite_t *spr) { md2 = &md2_playermodels[(skin_t*)spr->mobj->skin-skins]; md2->skin = (skin_t*)spr->mobj->skin-skins; - sprinfo = &((skin_t *)spr->mobj->skin)->sprinfo[spr->mobj->sprite2]; } else { md2 = &md2_models[spr->mobj->sprite]; - sprinfo = &spriteinfo[spr->mobj->sprite]; } // texture loading before model init, so it knows if sprite graphics are used, which @@ -1455,7 +1450,6 @@ boolean HWR_DrawModel(gl_vissprite_t *spr) } //HWD.pfnSetBlend(blend); // This seems to actually break translucency? - finalscale = md2->scale; //Hurdler: arf, I don't like that implementation at all... too much crappy if (gpatch && hwrPatch && hwrPatch->mipmap->format) // else if meant that if a texture couldn't be loaded, it would just end up using something else's texture @@ -1591,7 +1585,7 @@ boolean HWR_DrawModel(gl_vissprite_t *spr) p.y = FIXED_TO_FLOAT(interp.y)+md2->offset; if (flip) - p.z = FIXED_TO_FLOAT(interp.z + spr->mobj->height); + p.z = FIXED_TO_FLOAT(interp.z + interp.height); else p.z = FIXED_TO_FLOAT(interp.z); @@ -1614,61 +1608,56 @@ boolean HWR_DrawModel(gl_vissprite_t *spr) p.angley = FIXED_TO_FLOAT(anglef); } - p.rollangle = 0.0f; - p.rollflip = 1; - p.rotaxis = 0; - if (spr->mobj->rollangle) { - fixed_t anglef = AngleFixed(spr->mobj->rollangle); - p.rollangle = FIXED_TO_FLOAT(anglef); - p.roll = true; - - // rotation pivot - p.centerx = FIXED_TO_FLOAT(spr->mobj->radius/2); - p.centery = FIXED_TO_FLOAT(spr->mobj->height/(flip ? -2 : 2)); - - // rotation axis - if (sprinfo->available) - p.rotaxis = (UINT8)(sprinfo->pivot[(spr->mobj->frame & FF_FRAMEMASK)].rotaxis); - - // for NiGHTS specifically but should work everywhere else - ang = R_PointToAngle (interp.x, interp.y) - interp.angle; - if ((sprframe->rotate & SRF_RIGHT) && (ang < ANGLE_180)) // See from right - p.rollflip = 1; - else if ((sprframe->rotate & SRF_LEFT) && (ang >= ANGLE_180)) // See from left - p.rollflip = -1; - - if (flip) - p.rollflip *= -1; - } + fixed_t anglef = AngleFixed(R_ModelRotationAngle(&interp)); - p.anglex = 0.0f; + p.rollangle = 0.0f; -#ifdef USE_FTRANSFORM_ANGLEZ - // Slope rotation from Kart - p.anglez = 0.0f; - if (spr->mobj->standingslope) - { - fixed_t tempz = spr->mobj->standingslope->normal.z; - fixed_t tempy = spr->mobj->standingslope->normal.y; - fixed_t tempx = spr->mobj->standingslope->normal.x; - fixed_t tempangle = AngleFixed(R_PointToAngle2(0, 0, FixedSqrt(FixedMul(tempy, tempy) + FixedMul(tempz, tempz)), tempx)); - p.anglez = FIXED_TO_FLOAT(tempangle); - tempangle = -AngleFixed(R_PointToAngle2(0, 0, tempz, tempy)); - p.anglex = FIXED_TO_FLOAT(tempangle); + if (anglef) + { + fixed_t camAngleDiff = AngleFixed(viewangle) - FLOAT_TO_FIXED(p.angley); // dumb reconversion back, I know + + p.rollangle = FIXED_TO_FLOAT(anglef); + p.roll = true; + + // rotation pivot + p.centerx = FIXED_TO_FLOAT(interp.radius / 2); + p.centery = FIXED_TO_FLOAT(interp.height / 2); + + // rotation axes relative to camera + p.rollx = FIXED_TO_FLOAT(FINECOSINE(FixedAngle(camAngleDiff) >> ANGLETOFINESHIFT)); + p.rollz = FIXED_TO_FLOAT(FINESINE(FixedAngle(camAngleDiff) >> ANGLETOFINESHIFT)); + } } -#endif - // SRB2CBTODO: MD2 scaling support - finalscale *= FIXED_TO_FLOAT(interp.scale); +#if 0 + p.anglez = FIXED_TO_FLOAT(AngleFixed(interp.pitch)); + p.anglex = FIXED_TO_FLOAT(AngleFixed(interp.roll)); +#else + p.anglez = 0.f; + p.anglex = 0.f; +#endif p.flip = atransform.flip; -#ifdef USE_FTRANSFORM_MIRROR - p.mirror = atransform.mirror; // from Kart -#endif + p.mirror = atransform.mirror; HWD.pfnSetShader(SHADER_MODEL); // model shader - HWD.pfnDrawModel(md2->model, frame, durs, tics, nextFrame, &p, finalscale, flip, hflip, &Surf); + { + float this_scale = FIXED_TO_FLOAT(interp.scale); + + float xs = this_scale * FIXED_TO_FLOAT(interp.spritexscale); + float ys = this_scale * FIXED_TO_FLOAT(interp.spriteyscale); + + float ox = xs * FIXED_TO_FLOAT(interp.spritexoffset); + float oy = ys * FIXED_TO_FLOAT(interp.spriteyoffset); + + // offset perpendicular to the camera angle + p.x -= ox * gl_viewsin; + p.y += ox * gl_viewcos; + p.z += oy; + + HWD.pfnDrawModel(md2->model, frame, durs, tics, nextFrame, &p, md2->scale * xs, md2->scale * ys, flip, hflip, &Surf); + } } return true; diff --git a/src/hardware/hw_model.c b/src/hardware/hw_model.c index 4ed03744bfe072db597c0e2d120fd72ccd77a6ca..4b6bce6f7b55834167d496a361c3936cd22cc8ac 100644 --- a/src/hardware/hw_model.c +++ b/src/hardware/hw_model.c @@ -15,7 +15,7 @@ #include "hw_md2load.h" #include "hw_md3load.h" #include "hw_md2.h" -#include "u_list.h" +#include "../u_list.h" #include <string.h> static float PI = (3.1415926535897932384626433832795f); @@ -672,6 +672,9 @@ void GeneratePolygonNormals(model_t *model, int ztag) for (k = 0; k < mesh->numTriangles; k++) { + /// TODO: normalize vectors + (void)vertices; + (void)polyNormals; // Vector::Normal(vertices, polyNormals); vertices += 3 * 3; polyNormals++; diff --git a/src/hardware/r_opengl/r_opengl.c b/src/hardware/r_opengl/r_opengl.c index 569ddfee84032f9c88650216fa5f2127ce54df33..71cb5ca70375629ee06c7943e0c5be881555a0c1 100644 --- a/src/hardware/r_opengl/r_opengl.c +++ b/src/hardware/r_opengl/r_opengl.c @@ -1030,6 +1030,12 @@ EXPORT void HWRAPI(LoadCustomShader) (int number, char *code, size_t size, boole EXPORT void HWRAPI(SetShader) (int type) { #ifdef GL_SHADERS + if (type == SHADER_NONE) + { + UnSetShader(); + return; + } + if (gl_allowshaders != HWD_SHADEROPTION_OFF) { gl_shader_t *shader = gl_shaderstate.current; @@ -2290,7 +2296,7 @@ EXPORT void HWRAPI(DrawPolygon) (FSurfaceInfo *pSurf, FOutVector *pOutVerts, FUI pglVertexPointer(3, GL_FLOAT, sizeof(FOutVector), &pOutVerts[0].x); pglTexCoordPointer(2, GL_FLOAT, sizeof(FOutVector), &pOutVerts[0].s); - pglDrawArrays(GL_TRIANGLE_FAN, 0, iNumPts); + pglDrawArrays(PolyFlags & PF_WireFrame ? GL_LINES : GL_TRIANGLE_FAN, 0, iNumPts); if (PolyFlags & PF_RemoveYWrap) pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); @@ -2673,7 +2679,7 @@ EXPORT void HWRAPI(CreateModelVBOs) (model_t *model) #define BUFFER_OFFSET(i) ((void*)(i)) -static void DrawModelEx(model_t *model, INT32 frameIndex, float duration, float tics, INT32 nextFrameIndex, FTransform *pos, float scale, UINT8 flipped, UINT8 hflipped, FSurfaceInfo *Surface) +static void DrawModelEx(model_t *model, INT32 frameIndex, float duration, float tics, INT32 nextFrameIndex, FTransform *pos, float hscale, float vscale, UINT8 flipped, UINT8 hflipped, FSurfaceInfo *Surface) { static GLRGBAFloat poly = {0,0,0,0}; static GLRGBAFloat tint = {0,0,0,0}; @@ -2697,10 +2703,11 @@ static void DrawModelEx(model_t *model, INT32 frameIndex, float duration, float #endif // Affect input model scaling - scale *= 0.5f; - scalex = scale; - scaley = scale; - scalez = scale; + hscale *= 0.5f; + vscale *= 0.5f; + scalex = hscale; + scaley = vscale; + scalez = hscale; if (duration > 0.0 && tics >= 0.0) // don't interpolate if instantaneous or infinite in length { @@ -2776,7 +2783,6 @@ static void DrawModelEx(model_t *model, INT32 frameIndex, float duration, float pglEnable(GL_CULL_FACE); pglEnable(GL_NORMALIZE); -#ifdef USE_FTRANSFORM_MIRROR // flipped is if the object is vertically flipped // hflipped is if the object is horizontally flipped // pos->flip is if the screen is flipped vertically @@ -2789,17 +2795,6 @@ static void DrawModelEx(model_t *model, INT32 frameIndex, float duration, float else pglCullFace(GL_BACK); } -#else - // pos->flip is if the screen is flipped too - if (flipped ^ hflipped ^ pos->flip) // If one or three of these are active, but not two, invert the model's culling - { - pglCullFace(GL_FRONT); - } - else - { - pglCullFace(GL_BACK); - } -#endif pglPushMatrix(); // should be the same as glLoadIdentity //Hurdler: now it seems to work @@ -2809,22 +2804,14 @@ static void DrawModelEx(model_t *model, INT32 frameIndex, float duration, float if (hflipped) scalez = -scalez; -#ifdef USE_FTRANSFORM_ANGLEZ - pglRotatef(pos->anglez, 0.0f, 0.0f, -1.0f); // rotate by slope from Kart -#endif - pglRotatef(pos->angley, 0.0f, -1.0f, 0.0f); + pglRotatef(pos->anglez, 0.0f, 0.0f, -1.0f); pglRotatef(pos->anglex, 1.0f, 0.0f, 0.0f); + pglRotatef(pos->angley, 0.0f, -1.0f, 0.0f); if (pos->roll) { - float roll = (1.0f * pos->rollflip); pglTranslatef(pos->centerx, pos->centery, 0); - if (pos->rotaxis == 2) // Z - pglRotatef(pos->rollangle, 0.0f, 0.0f, roll); - else if (pos->rotaxis == 1) // Y - pglRotatef(pos->rollangle, 0.0f, roll, 0.0f); - else // X - pglRotatef(pos->rollangle, roll, 0.0f, 0.0f); + pglRotatef(pos->rollangle, pos->rollx, 0.0f, pos->rollz); pglTranslatef(-pos->centerx, -pos->centery, 0); } @@ -2978,9 +2965,9 @@ static void DrawModelEx(model_t *model, INT32 frameIndex, float duration, float // -----------------+ // HWRAPI DrawModel : Draw a model // -----------------+ -EXPORT void HWRAPI(DrawModel) (model_t *model, INT32 frameIndex, float duration, float tics, INT32 nextFrameIndex, FTransform *pos, float scale, UINT8 flipped, UINT8 hflipped, FSurfaceInfo *Surface) +EXPORT void HWRAPI(DrawModel) (model_t *model, INT32 frameIndex, float duration, float tics, INT32 nextFrameIndex, FTransform *pos, float hscale, float vscale, UINT8 flipped, UINT8 hflipped, FSurfaceInfo *Surface) { - DrawModelEx(model, frameIndex, duration, tics, nextFrameIndex, pos, scale, flipped, hflipped, Surface); + DrawModelEx(model, frameIndex, duration, tics, nextFrameIndex, pos, hscale, vscale, flipped, hflipped, Surface); } // -----------------+ @@ -2997,13 +2984,9 @@ EXPORT void HWRAPI(SetTransform) (FTransform *stransform) if (stransform) { used_fov = stransform->fovxangle; -#ifdef USE_FTRANSFORM_MIRROR - // mirroring from Kart if (stransform->mirror) pglScalef(-stransform->scalex, stransform->scaley, -stransform->scalez); - else -#endif - if (stransform->flip) + else if (stransform->flip) pglScalef(stransform->scalex, -stransform->scaley, -stransform->scalez); else pglScalef(stransform->scalex, stransform->scaley, -stransform->scalez); diff --git a/src/http-mserv.c b/src/http-mserv.c index b7032e89a3d65ecec15f195d1d46334435a411d9..df9a71a5c5d6cfcb8f73ecd3eeff371170e76c8e 100644 --- a/src/http-mserv.c +++ b/src/http-mserv.c @@ -159,7 +159,7 @@ HMS_connect (const char *format, ...) return NULL; } - if (cv_masterserver_token.string[0]) + if (cv_masterserver_token.string && cv_masterserver_token.string[0]) { quack_token = curl_easy_escape(curl, cv_masterserver_token.string, 0); token_length = ( sizeof "?token="-1 )+ strlen(quack_token); diff --git a/src/hu_stuff.c b/src/hu_stuff.c index 091e2b2fba50e46638aa6ee52bff2d7e6c81f9f0..e223d320814c6dff885886d6d57a434c0d120493 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -2025,7 +2025,7 @@ void HU_Drawer(void) V_DrawCenteredString(BASEVIDWIDTH/2, 180, V_YELLOWMAP | V_ALLOWLOWERCASE, resynch_text); } - if (modeattacking && pausedelay > 0 && !pausebreakkey) + if (modeattacking && pausedelay > 0 && !(pausebreakkey || cv_instantretry.value)) { INT32 strength = ((pausedelay - 1 - NEWTICRATE/2)*10)/(NEWTICRATE/3); INT32 y = hudinfo[HUD_LIVES].y - 13; diff --git a/src/i_system.h b/src/i_system.h index deea9f8a8de8b0a5128336a03c4ca4d6069b0867..834dd4091487b295fd1faed9d11018e498d79b12 100644 --- a/src/i_system.h +++ b/src/i_system.h @@ -49,6 +49,10 @@ size_t I_GetFreeMem(size_t *total); */ precise_t I_GetPreciseTime(void); +/** \brief Fills a buffer with random data, returns amount of data obtained. + */ +size_t I_GetRandomBytes(char *destination, size_t count); + /** \brief Get the precision of precise_t in units per second. Invocations of this function for the program's duration MUST return the same value. */ diff --git a/src/info.c b/src/info.c index 09452a74f54b04dc2a1c702ea515b793e25b311b..36389d849a38e21064e0f4e94b803cccfc9f7ef0 100644 --- a/src/info.c +++ b/src/info.c @@ -7194,7 +7194,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = sfx_cgot, // deathsound EMERALD1, // speed 16*FRACUNIT, // radius - 32*FRACUNIT, // height + 24*FRACUNIT, // height 0, // display offset 16, // mass 0, // damage @@ -7220,7 +7220,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = sfx_cgot, // deathsound EMERALD2, // speed 16*FRACUNIT, // radius - 32*FRACUNIT, // height + 24*FRACUNIT, // height 0, // display offset 16, // mass 0, // damage @@ -7246,7 +7246,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = sfx_cgot, // deathsound EMERALD3, // speed 16*FRACUNIT, // radius - 32*FRACUNIT, // height + 24*FRACUNIT, // height 0, // display offset 16, // mass 0, // damage @@ -7272,7 +7272,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = sfx_cgot, // deathsound EMERALD4, // speed 16*FRACUNIT, // radius - 32*FRACUNIT, // height + 24*FRACUNIT, // height 0, // display offset 16, // mass 0, // damage @@ -7298,7 +7298,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = sfx_cgot, // deathsound EMERALD5, // speed 16*FRACUNIT, // radius - 32*FRACUNIT, // height + 24*FRACUNIT, // height 0, // display offset 16, // mass 0, // damage @@ -7324,7 +7324,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = sfx_cgot, // deathsound EMERALD6, // speed 16*FRACUNIT, // radius - 32*FRACUNIT, // height + 24*FRACUNIT, // height 0, // display offset 16, // mass 0, // damage @@ -7350,7 +7350,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = sfx_cgot, // deathsound EMERALD7, // speed 16*FRACUNIT, // radius - 32*FRACUNIT, // height + 24*FRACUNIT, // height 0, // display offset 16, // mass 0, // damage @@ -18344,7 +18344,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL, // xdeathstate sfx_itemup, // deathsound 60*FRACUNIT, // speed - 24*FRACUNIT, // radius + 16*FRACUNIT, // radius 24*FRACUNIT, // height 0, // display offset pw_bouncering, // mass @@ -18371,7 +18371,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL, // xdeathstate sfx_itemup, // deathsound 60*FRACUNIT, // speed - 24*FRACUNIT, // radius + 16*FRACUNIT, // radius 24*FRACUNIT, // height 0, // display offset pw_railring, // mass @@ -18425,7 +18425,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL, // xdeathstate sfx_itemup, // deathsound 60*FRACUNIT, // speed - 24*FRACUNIT, // radius + 16*FRACUNIT, // radius 24*FRACUNIT, // height 0, // display offset pw_automaticring, // mass @@ -18452,7 +18452,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL, // xdeathstate sfx_itemup, // deathsound 60*FRACUNIT, // speed - 24*FRACUNIT, // radius + 16*FRACUNIT, // radius 24*FRACUNIT, // height 0, // display offset pw_explosionring, // mass @@ -18479,7 +18479,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL, // xdeathstate sfx_itemup, // deathsound 60*FRACUNIT, // speed - 24*FRACUNIT, // radius + 16*FRACUNIT, // radius 24*FRACUNIT, // height 0, // display offset pw_scatterring, // mass @@ -18506,7 +18506,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL, // xdeathstate sfx_itemup, // deathsound 60*FRACUNIT, // speed - 24*FRACUNIT, // radius + 16*FRACUNIT, // radius 24*FRACUNIT, // height 0, // display offset pw_grenadering, // mass @@ -18535,7 +18535,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = sfx_ncitem, // deathsound 60*FRACUNIT, // speed 24*FRACUNIT, // radius - 24*FRACUNIT, // height + 40*FRACUNIT, // height 0, // display offset pw_bouncering, // mass 2*TICRATE, // damage @@ -18562,7 +18562,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = sfx_ncitem, // deathsound 60*FRACUNIT, // speed 24*FRACUNIT, // radius - 24*FRACUNIT, // height + 40*FRACUNIT, // height 0, // display offset pw_railring, // mass 2*TICRATE, // damage @@ -18589,7 +18589,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = sfx_ncitem, // deathsound 60*FRACUNIT, // speed 24*FRACUNIT, // radius - 24*FRACUNIT, // height + 40*FRACUNIT, // height 0, // display offset pw_automaticring, // mass 2*TICRATE, // damage @@ -18616,7 +18616,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = sfx_ncitem, // deathsound 60*FRACUNIT, // speed 24*FRACUNIT, // radius - 24*FRACUNIT, // height + 40*FRACUNIT, // height 0, // display offset pw_explosionring, // mass 2*TICRATE, // damage @@ -18643,7 +18643,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = sfx_ncitem, // deathsound 60*FRACUNIT, // speed 24*FRACUNIT, // radius - 24*FRACUNIT, // height + 40*FRACUNIT, // height 0, // display offset pw_scatterring, // mass 2*TICRATE, // damage @@ -18670,7 +18670,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = sfx_ncitem, // deathsound 60*FRACUNIT, // speed 24*FRACUNIT, // radius - 24*FRACUNIT, // height + 40*FRACUNIT, // height 0, // display offset pw_grenadering, // mass 2*TICRATE, // damage @@ -21584,68 +21584,113 @@ skincolor_t skincolors[MAXSKINCOLORS] = { {"Black", {0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1b, 0x1b, 0x1c, 0x1d, 0x1d, 0x1e, 0x1e, 0x1f, 0x1f}, SKINCOLOR_WHITE, 7, V_GRAYMAP, true}, // SKINCOLOR_BLACK // Desaturated - {"Aether", {0x00, 0x00, 0x01, 0x02, 0x02, 0x03, 0x91, 0x91, 0x91, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xaf}, SKINCOLOR_GREY, 15, 0, true}, // SKINCOLOR_AETHER - {"Slate", {0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0xaa, 0xaa, 0xaa, 0xab, 0xac, 0xac, 0xad, 0xad, 0xae, 0xaf}, SKINCOLOR_SILVER, 12, 0, true}, // SKINCOLOR_SLATE - {"Bluebell", {0x90, 0x91, 0x92, 0x93, 0x94, 0x94, 0x95, 0xac, 0xac, 0xad, 0xad, 0xa8, 0xa8, 0xa9, 0xfd, 0xfe}, SKINCOLOR_COPPER, 4, V_BLUEMAP, true}, // SKINCOLOR_BLUEBELL - {"Pink", {0xd0, 0xd0, 0xd1, 0xd1, 0xd2, 0xd2, 0xd3, 0xd3, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0x2b, 0x2c, 0x2e}, SKINCOLOR_AZURE, 9, V_REDMAP, true}, // SKINCOLOR_PINK - {"Yogurt", {0xd0, 0x30, 0xd8, 0xd9, 0xda, 0xdb, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe3, 0xe6, 0xe8, 0xe9}, SKINCOLOR_RUST, 7, V_BROWNMAP, true}, // SKINCOLOR_YOGURT - {"Brown", {0xdf, 0xe0, 0xe1, 0xe2, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef}, SKINCOLOR_TAN, 2, V_BROWNMAP, true}, // SKINCOLOR_BROWN - {"Bronze", {0xde, 0xe0, 0xe1, 0xe4, 0xe7, 0xe9, 0xeb, 0xec, 0xed, 0xed, 0xed, 0x19, 0x19, 0x1b, 0x1d, 0x1e}, SKINCOLOR_KETCHUP, 0, V_BROWNMAP, true}, // SKINCOLOR_BRONZE - {"Tan", {0x51, 0x51, 0x54, 0x54, 0x55, 0x55, 0x56, 0x56, 0x56, 0x57, 0xf5, 0xf5, 0xf9, 0xf9, 0xed, 0xed}, SKINCOLOR_BROWN, 12, V_BROWNMAP, true}, // SKINCOLOR_TAN - {"Beige", {0x54, 0x55, 0x56, 0x56, 0xf2, 0xf3, 0xf3, 0xf4, 0xf5, 0xf6, 0xf8, 0xf9, 0xfa, 0xfb, 0xed, 0xed}, SKINCOLOR_MOSS, 5, V_BROWNMAP, true}, // SKINCOLOR_BEIGE - {"Moss", {0x58, 0x58, 0x59, 0x59, 0x5a, 0x5a, 0x5b, 0x5b, 0x5b, 0x5c, 0x5d, 0x5d, 0x5e, 0x5e, 0x5f, 0x5f}, SKINCOLOR_BEIGE, 13, V_GREENMAP, true}, // SKINCOLOR_MOSS - {"Azure", {0x90, 0x90, 0x91, 0x91, 0xaa, 0xaa, 0xab, 0xab, 0xab, 0xac, 0xad, 0xad, 0xae, 0xae, 0xaf, 0xaf}, SKINCOLOR_PINK, 5, V_AZUREMAP, true}, // SKINCOLOR_AZURE - {"Lavender", {0xc0, 0xc0, 0xc1, 0xc1, 0xc2, 0xc2, 0xc3, 0xc3, 0xc3, 0xc4, 0xc5, 0xc5, 0xc6, 0xc6, 0xc7, 0xc7}, SKINCOLOR_GOLD, 4, V_PURPLEMAP, true}, // SKINCOLOR_LAVENDER + {"Aether", {0x00, 0x00, 0x01, 0x01, 0x90, 0x90, 0x91, 0x91, 0x92, 0xaa, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xae}, SKINCOLOR_GREY, 15, 0, true}, // SKINCOLOR_AETHER + {"Slate", {0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0xaa, 0xaa, 0xaa, 0xab, 0xac, 0xac, 0xad, 0xad, 0xae, 0xaf}, SKINCOLOR_SILVER, 12, 0, true}, // SKINCOLOR_SLATE + {"Moonstone", { 0, 4, 8, 9, 11, 12, 14, 15, 171, 172, 173, 174, 175, 27, 29, 31}, SKINCOLOR_TOPAZ, 15, V_GRAYMAP, true}, // SKINCOLOR_MOONSTONE + {"Bluebell", {0x90, 0x91, 0x92, 0x93, 0x94, 0x94, 0x95, 0xac, 0xac, 0xad, 0xad, 0xa8, 0xa8, 0xa9, 0xfd, 0xfe}, SKINCOLOR_COPPER, 4, V_BLUEMAP, true}, // SKINCOLOR_BLUEBELL + {"Pink", {0xd0, 0xd0, 0xd1, 0xd1, 0xd2, 0xd2, 0xd3, 0xd3, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0x2b, 0x2c, 0x2e}, SKINCOLOR_AZURE, 9, V_REDMAP, true}, // SKINCOLOR_PINK + {"Rosewood", { 209, 210, 211, 212, 213, 214, 228, 230, 232, 234, 235, 237, 26, 27, 28, 29}, SKINCOLOR_SEPIA, 5, V_BROWNMAP, true}, // SKINCOLOR_ROSEWOOD + {"Yogurt", {0xd0, 0x30, 0xd8, 0xd9, 0xda, 0xdb, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe3, 0xe6, 0xe8, 0xe9}, SKINCOLOR_RUST, 7, V_BROWNMAP, true}, // SKINCOLOR_YOGURT + {"Latte", { 48, 217, 219, 221, 223, 224, 226, 228, 68, 69, 70, 70, 44, 45, 46, 47}, SKINCOLOR_BOTTLE, 12, V_BROWNMAP, true}, // SKINCOLOR_LATTE + {"Brown", {0xdf, 0xe0, 0xe1, 0xe2, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef}, SKINCOLOR_TAN, 2, V_BROWNMAP, true}, // SKINCOLOR_BROWN + {"Boulder", {0xde, 0xe0, 0xe1, 0xe4, 0xe7, 0xe9, 0xeb, 0xec, 0xed, 0xed, 0xed, 0x19, 0x19, 0x1b, 0x1d, 0x1e}, SKINCOLOR_KETCHUP, 0, V_BROWNMAP, true}, // SKINCOLOR_BOULDER + {"Bronze", { 82, 84, 50, 51, 223, 228, 230, 232, 234, 236, 237, 238, 239, 239, 30, 31}, SKINCOLOR_VOLCANIC, 9, V_BROWNMAP, true}, // SKINCOLOR_BRONZE + {"Sepia", { 88, 84, 85, 86, 224, 226, 228, 230, 232, 235, 236, 237, 238, 239, 28, 28}, SKINCOLOR_ROSEWOOD, 5, V_BROWNMAP, true}, // SKINCOLOR_SEPIA + {"Ecru", { 80, 83, 84, 85, 86, 242, 243, 245, 230, 232, 234, 236, 238, 239, 47, 47}, SKINCOLOR_ARCTIC, 12, V_BROWNMAP, true}, // SKINCOLOR_ECRU + {"Tan", {0x51, 0x51, 0x54, 0x54, 0x55, 0x55, 0x56, 0x56, 0x56, 0x57, 0xf5, 0xf5, 0xf9, 0xf9, 0xed, 0xed}, SKINCOLOR_BROWN, 12, V_BROWNMAP, true}, // SKINCOLOR_TAN + {"Beige", {0x54, 0x55, 0x56, 0x56, 0xf2, 0xf3, 0xf3, 0xf4, 0xf5, 0xf6, 0xf8, 0xf9, 0xfa, 0xfb, 0xed, 0xed}, SKINCOLOR_MOSS, 5, V_BROWNMAP, true}, // SKINCOLOR_BEIGE + {"Rosebush", { 208, 216, 209, 85, 90, 91, 91, 92, 191, 93, 94, 107, 109, 110, 111, 111}, SKINCOLOR_EGGPLANT, 5, V_GREENMAP, true}, // SKINCOLOR_ROSEBUSH + {"Moss", {0x58, 0x58, 0x59, 0x59, 0x5a, 0x5a, 0x5b, 0x5b, 0x5b, 0x5c, 0x5d, 0x5d, 0x5e, 0x5e, 0x5f, 0x5f}, SKINCOLOR_BEIGE, 13, V_GREENMAP, true}, // SKINCOLOR_MOSS + {"Azure", {0x90, 0x90, 0x91, 0x91, 0xaa, 0xaa, 0xab, 0xab, 0xab, 0xac, 0xad, 0xad, 0xae, 0xae, 0xaf, 0xaf}, SKINCOLOR_PINK, 5, V_AZUREMAP, true}, // SKINCOLOR_AZURE + {"Eggplant", { 4, 8, 11, 11, 16, 195, 195, 195, 196, 186, 187, 187, 254, 254, 30, 31}, SKINCOLOR_ROSEBUSH, 5, V_PURPLEMAP, true}, // SKINCOLOR_EGGPLANT + {"Lavender", {0xc0, 0xc0, 0xc1, 0xc1, 0xc2, 0xc2, 0xc3, 0xc3, 0xc3, 0xc4, 0xc5, 0xc5, 0xc6, 0xc6, 0xc7, 0xc7}, SKINCOLOR_GOLD, 4, V_PURPLEMAP, true}, // SKINCOLOR_LAVENDER // Viv's vivid colours (toast 21/07/17) + // Tweaks & additions (Lach, Chrispy, sphere, Alice, MotorRoach & Saneko 26/10/22) {"Ruby", {0xb0, 0xb0, 0xc9, 0xca, 0xcc, 0x26, 0x27, 0x28, 0x29, 0x2a, 0xb9, 0xb9, 0xba, 0xba, 0xbb, 0xfd}, SKINCOLOR_EMERALD, 10, V_REDMAP, true}, // SKINCOLOR_RUBY + {"Cherry", { 202, 203, 204, 205, 206, 40, 41, 42, 43, 44, 186, 187, 28, 29, 30, 31}, SKINCOLOR_MIDNIGHT, 10, V_REDMAP, true}, // SKINCOLOR_CHERRY {"Salmon", {0xd0, 0xd0, 0xd1, 0xd2, 0x20, 0x21, 0x24, 0x25, 0x26, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e}, SKINCOLOR_FOREST, 6, V_REDMAP, true}, // SKINCOLOR_SALMON + {"Pepper", { 210, 32, 33, 34, 35, 35, 36, 37, 38, 39, 41, 43, 45, 45, 46, 47}, SKINCOLOR_MASTER, 8, V_REDMAP, true}, // SKINCOLOR_PEPPER {"Red", {0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x47, 0x2e, 0x2f}, SKINCOLOR_GREEN, 10, V_REDMAP, true}, // SKINCOLOR_RED {"Crimson", {0x27, 0x27, 0x28, 0x28, 0x29, 0x2a, 0x2b, 0x2b, 0x2c, 0x2d, 0x2e, 0x2e, 0x2e, 0x2f, 0x2f, 0x1f}, SKINCOLOR_ICY, 10, V_REDMAP, true}, // SKINCOLOR_CRIMSON {"Flame", {0x31, 0x32, 0x33, 0x36, 0x22, 0x22, 0x25, 0x25, 0x25, 0xcd, 0xcf, 0xcf, 0xc5, 0xc5, 0xc7, 0xc7}, SKINCOLOR_PURPLE, 8, V_REDMAP, true}, // SKINCOLOR_FLAME - {"Ketchup", {0x48, 0x49, 0x40, 0x33, 0x34, 0x36, 0x22, 0x24, 0x26, 0x28, 0x2a, 0x2b, 0x2c, 0x47, 0x2e, 0x2f}, SKINCOLOR_BRONZE, 8, V_REDMAP, true}, // SKINCOLOR_KETCHUP + {"Garnet", { 0, 83, 50, 53, 34, 35, 37, 38, 39, 40, 42, 44, 45, 46, 47, 47}, SKINCOLOR_AQUAMARINE, 6, V_REDMAP, true}, // SKINCOLOR_GARNET + {"Ketchup", {0x48, 0x49, 0x40, 0x33, 0x34, 0x36, 0x22, 0x24, 0x26, 0x28, 0x2a, 0x2b, 0x2c, 0x47, 0x2e, 0x2f}, SKINCOLOR_BOULDER, 8, V_REDMAP, true}, // SKINCOLOR_KETCHUP {"Peachy", {0xd0, 0x30, 0x31, 0x31, 0x32, 0x32, 0xdc, 0xdc, 0xdc, 0xd3, 0xd4, 0xd4, 0xcc, 0xcd, 0xce, 0xcf}, SKINCOLOR_TEAL, 7, V_ROSYMAP, true}, // SKINCOLOR_PEACHY {"Quail", {0xd8, 0xd9, 0xdb, 0xdc, 0xde, 0xdf, 0xd5, 0xd5, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0x1d, 0x1f}, SKINCOLOR_WAVE, 5, V_BROWNMAP, true}, // SKINCOLOR_QUAIL + {"Foundation", { 80, 81, 82, 84, 219, 221, 221, 212, 213, 214, 215, 197, 186, 187, 187, 30}, SKINCOLOR_DREAM, 6, V_ORANGEMAP, true}, // SKINCOLOR_FOUNDATION {"Sunset", {0x51, 0x52, 0x40, 0x40, 0x34, 0x36, 0xd5, 0xd5, 0xd6, 0xd7, 0xcf, 0xcf, 0xc6, 0xc6, 0xc7, 0xfe}, SKINCOLOR_SAPPHIRE, 5, V_ORANGEMAP, true}, // SKINCOLOR_SUNSET {"Copper", {0x58, 0x54, 0x40, 0x34, 0x35, 0x38, 0x3a, 0x3c, 0x3d, 0x2a, 0x2b, 0x2c, 0x2c, 0xba, 0xba, 0xbb}, SKINCOLOR_BLUEBELL, 5, V_ORANGEMAP, true}, // SKINCOLOR_COPPER {"Apricot", {0x00, 0xd8, 0xd9, 0xda, 0xdb, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e}, SKINCOLOR_CYAN, 4, V_ORANGEMAP, true}, // SKINCOLOR_APRICOT - {"Orange", {0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x2c}, SKINCOLOR_BLUE, 4, V_ORANGEMAP, true}, // SKINCOLOR_ORANGE + {"Orange", { 49, 50, 51, 52, 53, 54, 55, 57, 58, 59, 60, 42, 44, 45, 46, 46}, SKINCOLOR_BLUE, 4, V_ORANGEMAP, true}, // SKINCOLOR_ORANGE {"Rust", {0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3c, 0x3d, 0x3d, 0x3d, 0x3f, 0x2c, 0x2d, 0x47, 0x2e, 0x2f, 0x2f}, SKINCOLOR_YOGURT, 8, V_ORANGEMAP, true}, // SKINCOLOR_RUST + {"Tangerine", { 81, 83, 64, 64, 51, 52, 53, 54, 56, 58, 60, 61, 63, 45, 46, 47}, SKINCOLOR_OCEAN, 12, V_ORANGEMAP, true}, // SKINCOLOR_TANGERINE + {"Topaz", { 0, 81, 83, 73, 74, 74, 65, 52, 53, 54, 56, 58, 60, 42, 43, 45}, SKINCOLOR_MOONSTONE, 10, V_YELLOWMAP, true}, // SKINCOLOR_TOPAZ {"Gold", {0x51, 0x51, 0x54, 0x54, 0x41, 0x42, 0x43, 0x43, 0x44, 0x45, 0x46, 0x3f, 0x2d, 0x2e, 0x2f, 0x2f}, SKINCOLOR_LAVENDER, 10, V_YELLOWMAP, true}, // SKINCOLOR_GOLD {"Sandy", {0x53, 0x40, 0x41, 0x42, 0x43, 0xe6, 0xe9, 0xe9, 0xea, 0xec, 0xec, 0xc6, 0xc6, 0xc7, 0xc7, 0xfe}, SKINCOLOR_SKY, 8, V_YELLOWMAP, true}, // SKINCOLOR_SANDY + {"Goldenrod", { 0, 80, 81, 81, 83, 73, 73, 64, 65, 66, 67, 68, 69, 62, 44, 45}, SKINCOLOR_MAJESTY, 8, V_YELLOWMAP, true}, // SKINCOLOR_GOLDENROD {"Yellow", {0x52, 0x53, 0x49, 0x49, 0x4a, 0x4a, 0x4b, 0x4b, 0x4b, 0x4c, 0x4d, 0x4d, 0x4e, 0x4e, 0x4f, 0xed}, SKINCOLOR_CORNFLOWER, 8, V_YELLOWMAP, true}, // SKINCOLOR_YELLOW {"Olive", {0x4b, 0x4b, 0x4c, 0x4c, 0x4d, 0x4e, 0xe7, 0xe7, 0xe9, 0xc5, 0xc5, 0xc6, 0xc6, 0xc7, 0xc7, 0xfd}, SKINCOLOR_DUSK, 3, V_YELLOWMAP, true}, // SKINCOLOR_OLIVE + {"Pear", { 88, 89, 188, 189, 189, 76, 76, 67, 67, 68, 69, 70, 45, 46, 47, 47}, SKINCOLOR_MARINE, 9, V_PERIDOTMAP, true}, // SKINCOLOR_PEAR + {"Lemon", { 0, 80, 81, 83, 73, 73, 74, 74, 76, 76, 191, 191, 79, 79, 110, 111}, SKINCOLOR_FUCHSIA, 8, V_YELLOWMAP, true}, // SKINCOLOR_LEMON {"Lime", {0x50, 0x51, 0x52, 0x53, 0x48, 0xbc, 0xbd, 0xbe, 0xbe, 0xbf, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f}, SKINCOLOR_MAGENTA, 9, V_PERIDOTMAP, true}, // SKINCOLOR_LIME {"Peridot", {0x58, 0x58, 0xbc, 0xbc, 0xbd, 0xbd, 0xbe, 0xbe, 0xbe, 0xbf, 0x5e, 0x5e, 0x5f, 0x5f, 0x77, 0x77}, SKINCOLOR_COBALT, 2, V_PERIDOTMAP, true}, // SKINCOLOR_PERIDOT {"Apple", {0x49, 0x49, 0xbc, 0xbd, 0xbe, 0xbe, 0xbe, 0x67, 0x69, 0x6a, 0x6b, 0x6b, 0x6c, 0x6d, 0x6d, 0x6d}, SKINCOLOR_RASPBERRY, 13, V_PERIDOTMAP, true}, // SKINCOLOR_APPLE + {"Headlight", { 0, 80, 81, 82, 73, 84, 64, 65, 91, 91, 124, 125, 126, 137, 138, 139}, SKINCOLOR_MAUVE, 8, V_YELLOWMAP, true}, // SKINCOLOR_HEADLIGHT + {"Chartreuse", { 80, 82, 72, 73, 188, 188, 113, 114, 114, 125, 126, 137, 138, 139, 253, 254}, SKINCOLOR_NOBLE, 9, V_PERIDOTMAP, true}, // SKINCOLOR_CHARTREUSE {"Green", {0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f}, SKINCOLOR_RED, 6, V_GREENMAP, true}, // SKINCOLOR_GREEN {"Forest", {0x65, 0x66, 0x67, 0x68, 0x69, 0x69, 0x6a, 0x6b, 0x6b, 0x6c, 0x6d, 0x6d, 0x6e, 0x6e, 0x6e, 0x6f}, SKINCOLOR_SALMON, 9, V_GREENMAP, true}, // SKINCOLOR_FOREST - {"Emerald", {0x70, 0x70, 0x71, 0x71, 0x72, 0x72, 0x73, 0x73, 0x73, 0x74, 0x75, 0x75, 0x76, 0x76, 0x77, 0x77}, SKINCOLOR_RUBY, 4, V_GREENMAP, true}, // SKINCOLOR_EMERALD + {"Shamrock", {0x70, 0x70, 0x71, 0x71, 0x72, 0x72, 0x73, 0x73, 0x73, 0x74, 0x75, 0x75, 0x76, 0x76, 0x77, 0x77}, SKINCOLOR_SIBERITE, 10, V_GREENMAP, true}, // SKINCOLOR_SHAMROCK + {"Jade", { 128, 120, 121, 122, 122, 113, 114, 114, 115, 116, 117, 118, 119, 110, 111, 30}, SKINCOLOR_TAFFY, 10, V_GREENMAP, true}, // SKINCOLOR_JADE {"Mint", {0x00, 0x00, 0x58, 0x58, 0x59, 0x62, 0x62, 0x62, 0x64, 0x67, 0x7e, 0x7e, 0x8f, 0x8f, 0x8a, 0x8a}, SKINCOLOR_VIOLET, 5, V_GREENMAP, true}, // SKINCOLOR_MINT - {"Seafoam", {0x01, 0x58, 0x59, 0x5a, 0x7d, 0x7d, 0x7e, 0x7e, 0x7e, 0x8f, 0x8f, 0x8a, 0x8a, 0x8a, 0xfd, 0xfd}, SKINCOLOR_PLUM, 6, V_AQUAMAP, true}, // SKINCOLOR_SEAFOAM + {"Master", { 0, 80, 88, 96, 112, 113, 99, 100, 124, 125, 126, 117, 107, 118, 119, 111}, SKINCOLOR_PEPPER, 8, V_GREENMAP, true}, // SKINCOLOR_MASTER + {"Emerald", { 80, 96, 112, 113, 114, 114, 125, 125, 126, 126, 137, 137, 138, 138, 139, 139}, SKINCOLOR_RUBY, 9, V_GREENMAP, true}, // SKINCOLOR_EMERALD + {"Seafoam", {0x01, 0x58, 0x59, 0x5a, 0x7c, 0x7d, 0x7d, 0x7e, 0x7e, 0x8f, 0x8f, 0x8a, 0x8a, 0x8b, 0xfd, 0xfd}, SKINCOLOR_PLUM, 6, V_AQUAMAP, true}, // SKINCOLOR_SEAFOAM + {"Island", { 96, 97, 113, 113, 114, 124, 142, 136, 136, 150, 151, 153, 168, 168, 169, 169}, SKINCOLOR_GALAXY, 7, V_AQUAMAP, true}, // SKINCOLOR_ISLAND + {"Bottle", { 0, 1, 3, 4, 5, 140, 141, 141, 124, 125, 126, 127, 118, 119, 111, 111}, SKINCOLOR_LATTE, 14, V_AQUAMAP, true}, // SKINCOLOR_BOTTLE {"Aqua", {0x78, 0x79, 0x7a, 0x7a, 0x7b, 0x7b, 0x7c, 0x7c, 0x7c, 0x7d, 0x7e, 0x7e, 0x7f, 0x7f, 0x76, 0x77}, SKINCOLOR_ROSY, 7, V_AQUAMAP, true}, // SKINCOLOR_AQUA {"Teal", {0x78, 0x78, 0x8c, 0x8c, 0x8d, 0x8d, 0x8d, 0x8e, 0x8e, 0x8f, 0x8f, 0x8f, 0x8a, 0x8a, 0x8a, 0x8a}, SKINCOLOR_PEACHY, 7, V_SKYMAP, true}, // SKINCOLOR_TEAL + {"Ocean", { 120, 121, 122, 122, 123, 141, 142, 142, 136, 137, 138, 138, 139, 139, 253, 253}, SKINCOLOR_TANGERINE, 4, V_AQUAMAP, true}, // SKINCOLOR_OCEAN {"Wave", {0x00, 0x78, 0x78, 0x79, 0x8d, 0x87, 0x88, 0x89, 0x89, 0xae, 0xa8, 0xa8, 0xa9, 0xa9, 0xfd, 0xfd}, SKINCOLOR_QUAIL, 5, V_SKYMAP, true}, // SKINCOLOR_WAVE {"Cyan", {0x80, 0x81, 0xff, 0xff, 0x83, 0x83, 0x8d, 0x8d, 0x8d, 0x8e, 0x7e, 0x7f, 0x76, 0x76, 0x77, 0x6e}, SKINCOLOR_APRICOT, 6, V_SKYMAP, true}, // SKINCOLOR_CYAN + {"Turquoise", { 0, 120, 121, 122, 123, 141, 141, 135, 136, 136, 150, 153, 155, 157, 159, 253}, SKINCOLOR_SANGRIA, 12, V_SKYMAP, true}, // SKINCOLOR_TURQUOISE + {"Aquamarine", { 0, 120, 121, 131, 132, 133, 134, 134, 135, 135, 149, 149, 172, 173, 174, 175}, SKINCOLOR_GARNET, 8, V_SKYMAP, true}, // SKINCOLOR_AQUAMARINE {"Sky", {0x80, 0x80, 0x81, 0x82, 0x83, 0x83, 0x84, 0x85, 0x85, 0x86, 0x87, 0x88, 0x89, 0x89, 0x8a, 0x8b}, SKINCOLOR_SANDY, 1, V_SKYMAP, true}, // SKINCOLOR_SKY + {"Marine", { 144, 146, 147, 147, 148, 135, 136, 136, 137, 137, 127, 118, 119, 111, 111, 111}, SKINCOLOR_PEAR, 13, V_SKYMAP, true}, // SKINCOLOR_MARINE {"Cerulean", {0x85, 0x86, 0x87, 0x88, 0x88, 0x89, 0x89, 0x89, 0x8a, 0x8a, 0xfd, 0xfd, 0xfd, 0x1f, 0x1f, 0x1f}, SKINCOLOR_NEON, 4, V_SKYMAP, true}, // SKINCOLOR_CERULEAN + {"Dream", { 80, 208, 200, 200, 146, 146, 133, 134, 135, 136, 137, 138, 139, 139, 254, 254}, SKINCOLOR_FOUNDATION, 9, V_SKYMAP, true}, // SKINCOLOR_DREAM {"Icy", {0x00, 0x00, 0x00, 0x00, 0x80, 0x81, 0x83, 0x83, 0x86, 0x87, 0x95, 0x95, 0xad, 0xad, 0xae, 0xaf}, SKINCOLOR_CRIMSON, 0, V_SKYMAP, true}, // SKINCOLOR_ICY - {"Sapphire", {0x80, 0x83, 0x86, 0x87, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xfd, 0xfe}, SKINCOLOR_SUNSET, 5, V_SKYMAP, true}, // SKINCOLOR_SAPPHIRE + {"Daybreak", { 80, 81, 82, 72, 64, 9, 11, 171, 149, 150, 151, 153, 156, 157, 159, 253}, SKINCOLOR_EVENTIDE, 12, V_BLUEMAP, true}, // SKINCOLOR_DAYBREAK + {"Sapphire", {0x80, 0x82, 0x86, 0x87, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xfd, 0xfe}, SKINCOLOR_SUNSET, 5, V_BLUEMAP, true}, // SKINCOLOR_SAPPHIRE + {"Arctic", { 0, 1, 3, 4, 145, 146, 147, 148, 148, 149, 150, 153, 156, 159, 253, 254}, SKINCOLOR_ECRU, 15, V_BLUEMAP, true}, // SKINCOLOR_ARCTIC {"Cornflower", {0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x9a, 0x9c, 0x9d, 0x9d, 0x9e, 0x9e, 0x9e}, SKINCOLOR_YELLOW, 4, V_BLUEMAP, true}, // SKINCOLOR_CORNFLOWER {"Blue", {0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xfd, 0xfe}, SKINCOLOR_ORANGE, 5, V_BLUEMAP, true}, // SKINCOLOR_BLUE - {"Cobalt", {0x93, 0x94, 0x95, 0x96, 0x98, 0x9a, 0x9b, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xfd, 0xfd, 0xfe, 0xfe}, SKINCOLOR_PERIDOT, 5, V_BLUEMAP, true}, // SKINCOLOR_COBALT + {"Cobalt", { 145, 147, 149, 150, 151, 153, 154, 155, 156, 157, 158, 159, 253, 253, 254, 254}, SKINCOLOR_PERIDOT, 5, V_BLUEMAP, true}, // SKINCOLOR_COBALT + {"Midnight", { 171, 171, 172, 173, 173, 174, 175, 157, 158, 159, 253, 253, 254, 254, 31, 31}, SKINCOLOR_CHERRY, 10, V_GRAYMAP, true}, // SKINCOLOR_MIDNIGHT + {"Galaxy", { 160, 161, 162, 163, 164, 165, 166, 166, 154, 155, 156, 157, 159, 253, 254, 31}, SKINCOLOR_ISLAND, 7, V_PURPLEMAP, true}, // SKINCOLOR_GALAXY {"Vapor", {0x80, 0x81, 0x83, 0x86, 0x94, 0x94, 0xa3, 0xa3, 0xa4, 0xa6, 0xa6, 0xa6, 0xa8, 0xa8, 0xa9, 0xa9}, SKINCOLOR_LILAC, 4, V_SKYMAP, true}, // SKINCOLOR_VAPOR {"Dusk", {0x92, 0x93, 0x94, 0x94, 0xac, 0xad, 0xad, 0xad, 0xae, 0xae, 0xaf, 0xaf, 0xa9, 0xa9, 0xfd, 0xfd}, SKINCOLOR_OLIVE, 0, V_BLUEMAP, true}, // SKINCOLOR_DUSK + {"Majesty", { 0, 1, 176, 160, 160, 161, 162, 162, 163, 172, 173, 174, 174, 175, 139, 139}, SKINCOLOR_GOLDENROD, 9, V_PURPLEMAP, true}, // SKINCOLOR_MAJESTY {"Pastel", {0x90, 0x90, 0xa0, 0xa0, 0xa1, 0xa1, 0xa2, 0xa2, 0xa2, 0xa3, 0xa4, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8}, SKINCOLOR_BUBBLEGUM, 9, V_PURPLEMAP, true}, // SKINCOLOR_PASTEL {"Purple", {0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa4, 0xa5, 0xa5, 0xa5, 0xa6, 0xa7, 0xa7, 0xa8, 0xa8, 0xa9, 0xa9}, SKINCOLOR_FLAME, 7, V_PURPLEMAP, true}, // SKINCOLOR_PURPLE - {"Bubblegum", {0x00, 0xd0, 0xd0, 0xc8, 0xc8, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8}, SKINCOLOR_PASTEL, 8, V_MAGENTAMAP, true}, // SKINCOLOR_BUBBLEGUM + {"Noble", { 144, 146, 147, 148, 149, 164, 164, 165, 166, 185, 186, 186, 187, 187, 28, 29}, SKINCOLOR_CHARTREUSE, 12, V_PURPLEMAP, true}, // SKINCOLOR_NOBLE + {"Fuchsia", { 200, 201, 203, 204, 204, 183, 184, 184, 165, 166, 167, 168, 169, 159, 253, 254}, SKINCOLOR_LEMON, 10, V_PURPLEMAP, true}, // SKINCOLOR_FUCHSIA + {"Bubblegum", { 0, 208, 208, 176, 177, 178, 179, 180, 181, 182, 164, 166, 167, 168, 169, 253}, SKINCOLOR_PASTEL, 8, V_MAGENTAMAP, true}, // SKINCOLOR_BUBBLEGUM + {"Siberite", { 252, 177, 179, 180, 181, 181, 182, 182, 183, 164, 166, 167, 167, 168, 169, 159}, SKINCOLOR_EMERALD, 8, V_MAGENTAMAP, true}, // SKINCOLOR_SIBERITE {"Magenta", {0xb3, 0xb3, 0xb4, 0xb5, 0xb6, 0xb6, 0xb7, 0xb7, 0xb7, 0xb8, 0xb9, 0xb9, 0xba, 0xba, 0xbb, 0xbb}, SKINCOLOR_LIME, 6, V_MAGENTAMAP, true}, // SKINCOLOR_MAGENTA {"Neon", {0xb3, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xb9, 0xba, 0xba, 0xbb, 0xbb, 0xc7, 0xc7, 0x1d, 0x1d, 0x1e}, SKINCOLOR_CERULEAN, 2, V_MAGENTAMAP, true}, // SKINCOLOR_NEON {"Violet", {0xd0, 0xd1, 0xd2, 0xca, 0xcc, 0xb8, 0xb9, 0xb9, 0xba, 0xa8, 0xa8, 0xa9, 0xa9, 0xfd, 0xfe, 0xfe}, SKINCOLOR_MINT, 6, V_MAGENTAMAP, true}, // SKINCOLOR_VIOLET + {"Royal", { 208, 209, 192, 192, 192, 193, 193, 194, 194, 172, 173, 174, 175, 175, 139, 139}, SKINCOLOR_FANCY, 9, V_PURPLEMAP, true}, // SKINCOLOR_ROYAL {"Lilac", {0x00, 0xd0, 0xd1, 0xd2, 0xd3, 0xc1, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc5, 0xc6, 0xc6, 0xfe, 0x1f}, SKINCOLOR_VAPOR, 4, V_ROSYMAP, true}, // SKINCOLOR_LILAC + {"Mauve", { 176, 177, 178, 192, 193, 194, 195, 195, 196, 185, 185, 186, 186, 187, 187, 253}, SKINCOLOR_HEADLIGHT, 8, V_PURPLEMAP, true}, // SKINCOLOR_MAUVE + {"Eventide", { 51, 52, 53, 33, 34, 204, 183, 183, 184, 184, 166, 167, 168, 169, 253, 254}, SKINCOLOR_DAYBREAK, 13, V_MAGENTAMAP, true}, // SKINCOLOR_EVENTIDE {"Plum", {0xc8, 0xd3, 0xd5, 0xd6, 0xd7, 0xce, 0xcf, 0xb9, 0xb9, 0xba, 0xba, 0xa9, 0xa9, 0xa9, 0xfd, 0xfe}, SKINCOLOR_MINT, 7, V_ROSYMAP, true}, // SKINCOLOR_PLUM {"Raspberry", {0xc8, 0xc9, 0xca, 0xcb, 0xcb, 0xcc, 0xcd, 0xcd, 0xce, 0xb9, 0xb9, 0xba, 0xba, 0xbb, 0xfe, 0xfe}, SKINCOLOR_APPLE, 13, V_ROSYMAP, true}, // SKINCOLOR_RASPBERRY + {"Taffy", { 1, 176, 176, 177, 178, 179, 202, 203, 204, 204, 205, 206, 207, 44, 45, 46}, SKINCOLOR_JADE, 8, V_ROSYMAP, true}, // SKINCOLOR_TAFFY {"Rosy", {0xfc, 0xc8, 0xc8, 0xc9, 0xc9, 0xca, 0xca, 0xcb, 0xcb, 0xcc, 0xcc, 0xcd, 0xcd, 0xce, 0xce, 0xcf}, SKINCOLOR_AQUA, 1, V_ROSYMAP, true}, // SKINCOLOR_ROSY + {"Fancy", { 0, 208, 49, 210, 210, 202, 202, 203, 204, 204, 205, 206, 207, 207, 186, 186}, SKINCOLOR_ROYAL, 9, V_ROSYMAP, true}, // SKINCOLOR_FANCY + {"Sangria", { 210, 32, 33, 34, 34, 215, 215, 207, 207, 185, 186, 186, 186, 169, 169, 253}, SKINCOLOR_TURQUOISE, 12, V_ROSYMAP, true}, // SKINCOLOR_SANGRIA + {"Volcanic", { 54, 36, 42, 44, 45, 46, 46, 47, 28, 253, 253, 254, 254, 30, 31, 31}, SKINCOLOR_BRONZE, 9, V_REDMAP, true}, // SKINCOLOR_VOLCANIC // super {"Super Silver 1", {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x03}, SKINCOLOR_BLACK, 15, 0, false}, // SKINCOLOR_SUPERSILVER1 diff --git a/src/info.h b/src/info.h index 502ecd726006ecae626f44a0657bcd4245a01eaa..5c7a9f3fd428579c674c7f969db44f7d71b88f07 100644 --- a/src/info.h +++ b/src/info.h @@ -18,6 +18,7 @@ #include "d_think.h" #include "sounds.h" #include "m_fixed.h" +#include "dehacked.h" // MAX_ACTION_RECURSION // deh_tables.c now has lists for the more named enums! PLEASE keep them up to date! // For great modding!! @@ -151,6 +152,7 @@ enum actionnum A_BOSS3TAKEDAMAGE, A_BOSS3PATH, A_BOSS3SHOCKTHINK, + A_SHOCKWAVE, A_LINEDEFEXECUTE, A_LINEDEFEXECUTEFROMARG, A_PLAYSEESOUND, @@ -415,6 +417,7 @@ void A_Boss1Spikeballs(); void A_Boss3TakeDamage(); void A_Boss3Path(); void A_Boss3ShockThink(); +void A_Shockwave(); void A_LinedefExecute(); void A_LinedefExecuteFromArg(); void A_PlaySeeSound(); @@ -564,7 +567,7 @@ void A_DragonWing(); void A_DragonSegment(); void A_ChangeHeight(); -extern boolean actionsoverridden[NUMACTIONS]; +extern int actionsoverridden[NUMACTIONS][MAX_ACTION_RECURSION]; // ratio of states to sprites to mobj types is roughly 6 : 1 : 1 #define NUMMOBJFREESLOTS 512 diff --git a/src/libdivide.h b/src/libdivide.h index 1a589c7e5508957b0c4a8e15d37cd02c0402f349..71a5ae6be16589bbf08e1a8a764217fd121681de 100644 --- a/src/libdivide.h +++ b/src/libdivide.h @@ -581,6 +581,11 @@ static inline void libdivide_u128_shift(uint64_t *u1, uint64_t *u0, int32_t sign ////////// UINT32 +#if defined(__GNUC__) || defined(__clang__) // Suppress intentional compiler warnings + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Waggregate-return" +#endif + static inline struct libdivide_u32_t libdivide_internal_u32_gen(uint32_t d, int branchfree) { struct libdivide_u32_t result; uint32_t floor_log_2_d; @@ -647,6 +652,10 @@ struct libdivide_u32_t libdivide_u32_gen(uint32_t d) { return ret; }*/ +#if defined(__GNUC__) || defined(__clang__) // Stop suppressing intentional compiler warnings + #pragma GCC diagnostic pop +#endif + uint32_t libdivide_u32_do(uint32_t numer, const struct libdivide_u32_t *denom) { uint8_t more = denom->more; if (!denom->magic) { diff --git a/src/lua_baselib.c b/src/lua_baselib.c index 25fa38769aed22267fe68a05eaa6bd59db343905..1d183cdec6b6a518f38ed32725ed5f19ec4a45cd 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -689,11 +689,12 @@ static int lib_pSpawnLockOn(lua_State *L) return LUA_ErrInvalid(L, "player_t"); if (state >= NUMSTATES) return luaL_error(L, "state %d out of range (0 - %d)", state, NUMSTATES-1); - if (P_IsLocalPlayer(player)) // Only display it on your own view. + if (P_IsLocalPlayer(player)) // Only display it on your own view. Don't display it for spectators { mobj_t *visual = P_SpawnMobj(lockon->x, lockon->y, lockon->z, MT_LOCKON); // positioning, flip handled in P_SceneryThinker P_SetTarget(&visual->target, lockon); visual->flags2 |= MF2_DONTDRAW; + visual->drawonlyforplayer = player; // Hide it from the other player in splitscreen, and yourself when spectating P_SetMobjStateNF(visual, state); } return 0; @@ -1078,7 +1079,8 @@ static int lib_pZMovement(lua_State *L) if (!actor) return LUA_ErrInvalid(L, "mobj_t"); lua_pushboolean(L, P_ZMovement(actor)); - P_CheckPosition(actor, actor->x, actor->y); + if (!P_MobjWasRemoved(actor)) + P_CheckPosition(actor, actor->x, actor->y); P_SetTarget(&tmthing, ptmthing); return 1; } @@ -1106,7 +1108,8 @@ static int lib_pSceneryZMovement(lua_State *L) if (!actor) return LUA_ErrInvalid(L, "mobj_t"); lua_pushboolean(L, P_SceneryZMovement(actor)); - P_CheckPosition(actor, actor->x, actor->y); + if (!P_MobjWasRemoved(actor)) + P_CheckPosition(actor, actor->x, actor->y); P_SetTarget(&tmthing, ptmthing); return 1; } @@ -2453,7 +2456,7 @@ static int lib_pFadeLight(lua_State *L) static int lib_pIsFlagAtBase(lua_State *L) { mobjtype_t flag = luaL_checkinteger(L, 1); - NOHUD + //HUDSAFE INLEVEL if (flag >= NUMMOBJTYPES) return luaL_error(L, "mobj type %d out of range (0 - %d)", flag, NUMMOBJTYPES-1); @@ -2846,6 +2849,22 @@ static int lib_rTextureNumForName(lua_State *L) return 1; } +static int lib_rCheckTextureNameForNum(lua_State *L) +{ + INT32 num = (INT32)luaL_checkinteger(L, 1); + //HUDSAFE + lua_pushstring(L, R_CheckTextureNameForNum(num)); + return 1; +} + +static int lib_rTextureNameForNum(lua_State *L) +{ + INT32 num = (INT32)luaL_checkinteger(L, 1); + //HUDSAFE + lua_pushstring(L, R_TextureNameForNum(num)); + return 1; +} + // R_DRAW //////////// static int lib_rGetColorByName(lua_State *L) @@ -3525,7 +3544,7 @@ static int lib_gAddGametype(lua_State *L) // Partly lifted from Got_AddPlayer static int lib_gAddPlayer(lua_State *L) { - INT16 i, newplayernum, botcount = 1; + INT16 i, newplayernum; player_t *newplayer; SINT8 skinnum = 0, bot; @@ -3533,10 +3552,8 @@ static int lib_gAddPlayer(lua_State *L) { if (!playeringame[i]) break; - - if (players[i].bot) - botcount++; // How many of us are there already? } + if (i >= MAXPLAYERS) { lua_pushnil(L); @@ -3807,7 +3824,7 @@ static int lib_gDoReborn(lua_State *L) } // Another Lua function that doesn't actually exist! -// Sets nextmapoverride & skipstats without instantly ending the level, for instances where other sources should be exiting the level, like normal signposts. +// Sets nextmapoverride, skipstats and nextgametype without instantly ending the level, for instances where other sources should be exiting the level, like normal signposts. static int lib_gSetCustomExitVars(lua_State *L) { int n = lua_gettop(L); // Num arguments @@ -3816,18 +3833,21 @@ static int lib_gSetCustomExitVars(lua_State *L) // LUA EXTENSION: Custom exit like support // Supported: - // G_SetCustomExitVars(); [reset to defaults] - // G_SetCustomExitVars(int) [nextmap override only] - // G_SetCustomExitVars(nil, int) [skipstats only] - // G_SetCustomExitVars(int, int) [both of the above] + // G_SetCustomExitVars(); [reset to defaults] + // G_SetCustomExitVars(int) [nextmap override only] + // G_SetCustomExitVars(nil, int) [skipstats only] + // G_SetCustomExitVars(int, int) [both of the above] + // G_SetCustomExitVars(int, int, int) [nextmapoverride, skipstats and nextgametype] nextmapoverride = 0; skipstats = 0; + nextgametype = -1; if (n >= 1) { nextmapoverride = (INT16)luaL_optinteger(L, 1, 0); skipstats = (INT16)luaL_optinteger(L, 2, 0); + nextgametype = (INT16)luaL_optinteger(L, 3, -1); } return 0; @@ -4203,6 +4223,8 @@ static luaL_Reg lib[] = { // r_data {"R_CheckTextureNumForName",lib_rCheckTextureNumForName}, {"R_TextureNumForName",lib_rTextureNumForName}, + {"R_CheckTextureNameForNum", lib_rCheckTextureNameForNum}, + {"R_TextureNameForNum", lib_rTextureNameForNum}, // r_draw {"R_GetColorByName", lib_rGetColorByName}, diff --git a/src/lua_consolelib.c b/src/lua_consolelib.c index 1d15b3b145c5e5d0f2bccdd055ff1dcde60056b0..3783b8f7b6dac036a2e169c807e8e1079f130c76 100644 --- a/src/lua_consolelib.c +++ b/src/lua_consolelib.c @@ -357,7 +357,7 @@ static int lib_cvRegisterVar(lua_State *L) if (lua_islightuserdata(L, 4)) { CV_PossibleValue_t *pv = lua_touserdata(L, 4); - if (pv == CV_OnOff || pv == CV_YesNo || pv == CV_Unsigned || pv == CV_Natural) + if (pv == CV_OnOff || pv == CV_YesNo || pv == CV_Unsigned || pv == CV_Natural || pv == CV_TrueFalse) cvar->PossibleValue = pv; else FIELDERROR("PossibleValue", "CV_PossibleValue_t expected, got unrecognised pointer") @@ -615,7 +615,7 @@ static int cvar_get(lua_State *L) break; default: if (devparm) - return luaL_error(L, LUA_QL("consvar_t") " has no field named " LUA_QS, field); + return luaL_error(L, LUA_QL("consvar_t") " has no field named " LUA_QS ".", lua_tostring(L, 2)); else return 0; } @@ -652,6 +652,8 @@ int LUA_ConsoleLib(lua_State *L) lua_setglobal(L, "CV_Unsigned"); lua_pushlightuserdata(L, CV_Natural); lua_setglobal(L, "CV_Natural"); + lua_pushlightuserdata(L, CV_TrueFalse); + lua_setglobal(L, "CV_TrueFalse"); // Set global functions lua_pushvalue(L, LUA_GLOBALSINDEX); diff --git a/src/lua_hudlib.c b/src/lua_hudlib.c index c7f67e93ac07d194a25a2ce365726219d52a3ee4..6eec91273352db4adc598a80b7e0138795589640 100644 --- a/src/lua_hudlib.c +++ b/src/lua_hudlib.c @@ -282,7 +282,6 @@ static int patch_get(lua_State *L) patch_t *patch = *((patch_t **)luaL_checkudata(L, 1, META_PATCH)); enum patch field = Lua_optoption(L, 2, -1, patch_fields_ref); - // patches are invalidated when switching renderers if (!patch) { if (field == patch_valid) { lua_pushboolean(L, 0); @@ -436,7 +435,7 @@ static int camera_set(lua_State *L) cam->momz = luaL_checkfixed(L, 3); break; default: - return luaL_error(L, LUA_QL("camera_t") " has no field named " LUA_QS, camera_opt[field]); + return luaL_error(L, LUA_QL("camera_t") " has no field named " LUA_QS ".", lua_tostring(L, 2)); } return 0; } @@ -1256,8 +1255,6 @@ static int libd_RandomKey(lua_State *L) INT32 a = (INT32)luaL_checkinteger(L, 1); HUDONLY - if (a > 65536) - LUA_UsageWarning(L, "v.RandomKey: range > 65536 is undefined behavior"); lua_pushinteger(L, M_RandomKey(a)); return 1; } @@ -1268,13 +1265,6 @@ static int libd_RandomRange(lua_State *L) INT32 b = (INT32)luaL_checkinteger(L, 2); HUDONLY - if (b < a) { - INT32 c = a; - a = b; - b = c; - } - if ((b-a+1) > 65536) - LUA_UsageWarning(L, "v.RandomRange: range > 65536 is undefined behavior"); lua_pushinteger(L, M_RandomRange(a, b)); return 1; } @@ -1496,7 +1486,6 @@ void LUA_SetHudHook(int hook, huddrawlist_h list) break; case HUD_HOOK(intermission): - lua_pushboolean(gL, intertype == int_spec && - stagefailed); + lua_pushboolean(gL, stagefailed); } } diff --git a/src/lua_hudlib_drawlist.c b/src/lua_hudlib_drawlist.c index f46f207c100dc03e1256938dceda2e4e31b6eff7..c518ba52540ff874480d7cda2c8314a31987e993 100644 --- a/src/lua_hudlib_drawlist.c +++ b/src/lua_hudlib_drawlist.c @@ -103,7 +103,7 @@ huddrawlist_h LUA_HUD_CreateDrawList(void) { huddrawlist_h drawlist; - drawlist = (huddrawlist_h) Z_CallocAlign(sizeof(struct huddrawlist_s), PU_STATIC, NULL, 64); + drawlist = (huddrawlist_h) Z_Calloc(sizeof(struct huddrawlist_s), PU_STATIC, NULL); drawlist->items = NULL; drawlist->items_capacity = 0; drawlist->items_len = 0; @@ -160,7 +160,7 @@ static size_t AllocateDrawItem(huddrawlist_h list) { if (list->items_capacity == 0) list->items_capacity = 128; else list->items_capacity *= 2; - list->items = (drawitem_t *) Z_ReallocAlign(list->items, sizeof(struct drawitem_s) * list->items_capacity, PU_STATIC, NULL, 64); + list->items = (drawitem_t *) Z_Realloc(list->items, sizeof(struct drawitem_s) * list->items_capacity, PU_STATIC, NULL); } return list->items_len++; @@ -177,9 +177,18 @@ static const char *CopyString(huddrawlist_h list, const char* str) lenstr = strlen(str); if (list->strbuf_capacity <= list->strbuf_len + lenstr + 1) { + const char *old_offset = list->strbuf; + size_t i; if (list->strbuf_capacity == 0) list->strbuf_capacity = 256; else list->strbuf_capacity *= 2; - list->strbuf = (char*) Z_ReallocAlign(list->strbuf, sizeof(char) * list->strbuf_capacity, PU_STATIC, NULL, 8); + list->strbuf = (char*) Z_Realloc(list->strbuf, sizeof(char) * list->strbuf_capacity, PU_STATIC, NULL); + + // align the string pointers to make sure old pointers don't point towards invalid addresses + // this is necessary since Z_ReallocAlign might actually move the string buffer in memory + for (i = 0; i < list->items_len; i++) + { + list->items[i].str += list->strbuf - old_offset; + } } const char *result = (const char *) &list->strbuf[list->strbuf_len]; strncpy(&list->strbuf[list->strbuf_len], str, lenstr + 1); diff --git a/src/lua_infolib.c b/src/lua_infolib.c index fb07ccebb53dc00a7c93a2be141d05e54b24baa9..3764acf6a40945489506ce8d94b1b976fa771752 100644 --- a/src/lua_infolib.c +++ b/src/lua_infolib.c @@ -66,7 +66,7 @@ const char *const sfxinfo_wopt[] = { "caption", NULL}; -boolean actionsoverridden[NUMACTIONS] = {false}; +int actionsoverridden[NUMACTIONS][MAX_ACTION_RECURSION]; // // Sprite Names @@ -319,7 +319,7 @@ static int PopPivotSubTable(spriteframepivot_t *pivot, lua_State *L, int stk, in else if (ikey == 2 || (key && fastcmp(key, "y"))) pivot[idx].y = (INT32)value; else if (ikey == 3 || (key && fastcmp(key, "rotaxis"))) - pivot[idx].rotaxis = (UINT8)value; + LUA_UsageWarning(L, "\"rotaxis\" is deprecated and will be removed.") else if (ikey == -1 && (key != NULL)) FIELDERROR("pivot key", va("invalid option %s", key)); okcool = 1; @@ -508,8 +508,6 @@ static int pivotlist_get(lua_State *L) const char *field = luaL_checkstring(L, 2); UINT8 frame; - I_Assert(framepivot != NULL); - frame = R_Char2Frame(field[0]); if (frame == 255) luaL_error(L, "invalid frame %s", field); @@ -539,8 +537,6 @@ static int pivotlist_set(lua_State *L) if (hook_cmd_running) return luaL_error(L, "Do not alter spriteframepivot_t in CMD building code!"); - I_Assert(pivotlist != NULL); - frame = R_Char2Frame(field[0]); if (frame == 255) luaL_error(L, "invalid frame %s", field); @@ -576,7 +572,10 @@ static int framepivot_get(lua_State *L) else if (fastcmp("y", field)) lua_pushinteger(L, framepivot->y); else if (fastcmp("rotaxis", field)) - lua_pushinteger(L, (UINT8)framepivot->rotaxis); + { + LUA_UsageWarning(L, "\"rotaxis\" is deprecated and will be removed."); + lua_pushinteger(L, 0); + } else return luaL_error(L, va("Field %s does not exist in spriteframepivot_t", field)); @@ -602,7 +601,7 @@ static int framepivot_set(lua_State *L) else if (fastcmp("y", field)) framepivot->y = luaL_checkinteger(L, 3); else if (fastcmp("rotaxis", field)) - framepivot->rotaxis = luaL_checkinteger(L, 3); + LUA_UsageWarning(L, "\"rotaxis\" is deprecated and will be removed.") else return luaL_error(L, va("Field %s does not exist in spriteframepivot_t", field)); @@ -645,8 +644,8 @@ static void A_Lua(mobj_t *actor) if (lua_rawequal(gL, -1, -4)) { found = true; - superactions[superstack] = lua_tostring(gL, -2); // "A_ACTION" - ++superstack; + luaactions[luaactionstack] = lua_tostring(gL, -2); // "A_ACTION" + ++luaactionstack; lua_pop(gL, 2); // pop the name and function break; } @@ -661,8 +660,8 @@ static void A_Lua(mobj_t *actor) if (found) { - --superstack; - superactions[superstack] = NULL; + --luaactionstack; + luaactions[luaactionstack] = NULL; } } @@ -812,22 +811,54 @@ boolean LUA_SetLuaAction(void *stv, const char *action) return true; // action successfully set. } +static UINT8 superstack[NUMACTIONS]; boolean LUA_CallAction(enum actionnum actionnum, mobj_t *actor) { I_Assert(actor != NULL); - if (!actionsoverridden[actionnum]) // The action is not overriden, - return false; // action not called. + if (actionsoverridden[actionnum][0] == LUA_REFNIL) + { + // The action was not overridden at all, + // so just call the hardcoded version. + return false; + } + + if (luaactionstack && fasticmp(actionpointers[actionnum].name, luaactions[luaactionstack-1])) + { + // The action is calling itself, + // so look up the next Lua reference in its stack. - if (superstack && fasticmp(actionpointers[actionnum].name, superactions[superstack-1])) // the action is calling itself, - return false; // let it call the hardcoded function instead. + // 0 is just the reference to the one we're calling, + // so we increment here. + superstack[actionnum]++; + if (superstack[actionnum] >= MAX_ACTION_RECURSION) + { + CONS_Alert(CONS_WARNING, "Max Lua super recursion reached! Cool it on calling super!\n"); + superstack[actionnum] = 0; + return false; + } + } + + if (actionsoverridden[actionnum][superstack[actionnum]] == LUA_REFNIL) + { + // No Lua reference beyond this point. + // Let it call the hardcoded function instead. + + if (superstack[actionnum]) + { + // Decrement super stack + superstack[actionnum]--; + } + + return false; + } + + // Push error function lua_pushcfunction(gL, LUA_GetErrorMessage); - // grab function by uppercase name. - lua_getfield(gL, LUA_REGISTRYINDEX, LREG_ACTIONS); - lua_getfield(gL, -1, actionpointers[actionnum].name); - lua_remove(gL, -2); // pop LREG_ACTIONS + // Push function by reference. + lua_getref(gL, actionsoverridden[actionnum][superstack[actionnum]]); if (lua_isnil(gL, -1)) // no match { @@ -835,7 +866,7 @@ boolean LUA_CallAction(enum actionnum actionnum, mobj_t *actor) return false; // action not called. } - if (superstack == MAXRECURSION) + if (luaactionstack >= MAX_ACTION_RECURSION) { CONS_Alert(CONS_WARNING, "Max Lua Action recursion reached! Cool it on the calling A_Action functions from inside A_Action functions!\n"); lua_pop(gL, 2); // pop function and error handler @@ -849,14 +880,20 @@ boolean LUA_CallAction(enum actionnum actionnum, mobj_t *actor) lua_pushinteger(gL, var1); lua_pushinteger(gL, var2); - superactions[superstack] = actionpointers[actionnum].name; - ++superstack; + luaactions[luaactionstack] = actionpointers[actionnum].name; + ++luaactionstack; LUA_Call(gL, 3, 0, -(2 + 3)); lua_pop(gL, -1); // Error handler - --superstack; - superactions[superstack] = NULL; + if (superstack[actionnum]) + { + // Decrement super stack + superstack[actionnum]--; + } + + --luaactionstack; + luaactions[luaactionstack] = NULL; return true; // action successfully called. } @@ -1168,7 +1205,7 @@ static int mobjinfo_fields_ref = LUA_NOREF; static int mobjinfo_get(lua_State *L) { mobjinfo_t *info = *((mobjinfo_t **)luaL_checkudata(L, 1, META_MOBJINFO)); - enum mobjinfo_e field = luaL_checkoption(L, 2, mobjinfo_opt[0], mobjinfo_opt); + enum mobjinfo_e field = Lua_optoption(L, 2, mobjinfo_doomednum, mobjinfo_fields_ref); I_Assert(info != NULL); I_Assert(info >= mobjinfo); @@ -1709,7 +1746,7 @@ static int lib_setSkinColor(lua_State *L) else if (i == 6 || (str && fastcmp(str,"accessible"))) { boolean v = lua_toboolean(L, 3); if (cnum < FIRSTSUPERCOLOR && v != skincolors[cnum].accessible) - return luaL_error(L, "skincolors[] index %d is a standard color; accessibility changes are prohibited.", cnum); + CONS_Alert(CONS_WARNING, "skincolors[] index %d is a standard color; accessibility changes are prohibited.", cnum); else info->accessible = v; } @@ -1804,7 +1841,7 @@ static int skincolor_set(lua_State *L) else if (fastcmp(field,"accessible")) { boolean v = lua_toboolean(L, 3); if (cnum < FIRSTSUPERCOLOR && v != skincolors[cnum].accessible) - return luaL_error(L, "skincolors[] index %d is a standard color; accessibility changes are prohibited.", cnum); + CONS_Alert(CONS_WARNING, "skincolors[] index %d is a standard color; accessibility changes are prohibited.", cnum); else info->accessible = v; } else diff --git a/src/lua_maplib.c b/src/lua_maplib.c index 942fdf45a37db3146aecec161b51f607121f0f33..134e1c915d4d8d852e2ea48ea3d5d7adbb71452b 100644 --- a/src/lua_maplib.c +++ b/src/lua_maplib.c @@ -33,12 +33,20 @@ enum sector_e { sector_floorheight, sector_ceilingheight, sector_floorpic, + sector_floorxoffset, + sector_flooryoffset, + sector_floorangle, sector_ceilingpic, + sector_ceilingxoffset, + sector_ceilingyoffset, + sector_ceilingangle, sector_lightlevel, sector_floorlightlevel, sector_floorlightabsolute, + sector_floorlightsec, sector_ceilinglightlevel, sector_ceilinglightabsolute, + sector_ceilinglightsec, sector_special, sector_tag, sector_taglist, @@ -63,12 +71,20 @@ static const char *const sector_opt[] = { "floorheight", "ceilingheight", "floorpic", + "floorxoffset", + "flooryoffset", + "floorangle", "ceilingpic", + "ceilingxoffset", + "ceilingyoffset", + "ceilingangle", "lightlevel", "floorlightlevel", "floorlightabsolute", + "floorlightsec", "ceilinglightlevel", "ceilinglightabsolute", + "ceilinglightsec", "special", "tag", "taglist", @@ -649,6 +665,21 @@ static int sector_get(lua_State *L) lua_pushlstring(L, levelflat->name, i); return 1; } + case sector_floorxoffset: + { + lua_pushfixed(L, sector->floorxoffset); + return 1; + } + case sector_flooryoffset: + { + lua_pushfixed(L, sector->flooryoffset); + return 1; + } + case sector_floorangle: + { + lua_pushangle(L, sector->floorangle); + return 1; + } case sector_ceilingpic: // ceilingpic { levelflat_t *levelflat = &levelflats[sector->ceilingpic]; @@ -658,6 +689,21 @@ static int sector_get(lua_State *L) lua_pushlstring(L, levelflat->name, i); return 1; } + case sector_ceilingxoffset: + { + lua_pushfixed(L, sector->ceilingxoffset); + return 1; + } + case sector_ceilingyoffset: + { + lua_pushfixed(L, sector->ceilingyoffset); + return 1; + } + case sector_ceilingangle: + { + lua_pushangle(L, sector->ceilingangle); + return 1; + } case sector_lightlevel: lua_pushinteger(L, sector->lightlevel); return 1; @@ -667,12 +713,18 @@ static int sector_get(lua_State *L) case sector_floorlightabsolute: lua_pushboolean(L, sector->floorlightabsolute); return 1; + case sector_floorlightsec: + lua_pushinteger(L, sector->floorlightsec); + return 1; case sector_ceilinglightlevel: lua_pushinteger(L, sector->ceilinglightlevel); return 1; case sector_ceilinglightabsolute: lua_pushboolean(L, sector->ceilinglightabsolute); return 1; + case sector_ceilinglightsec: + lua_pushinteger(L, sector->ceilinglightsec); + return 1; case sector_special: lua_pushinteger(L, sector->special); return 1; @@ -760,8 +812,9 @@ static int sector_set(lua_State *L) case sector_fslope: // f_slope case sector_cslope: // c_slope case sector_friction: // friction - default: return luaL_error(L, "sector_t field " LUA_QS " cannot be set.", sector_opt[field]); + default: + return luaL_error(L, "sector_t has no field named " LUA_QS ".", lua_tostring(L, 2)); case sector_floorheight: { // floorheight boolean flag; mobj_t *ptmthing = tmthing; @@ -793,9 +846,27 @@ static int sector_set(lua_State *L) case sector_floorpic: sector->floorpic = P_AddLevelFlatRuntime(luaL_checkstring(L, 3)); break; + case sector_floorxoffset: + sector->floorxoffset = luaL_checkfixed(L, 3); + break; + case sector_flooryoffset: + sector->flooryoffset = luaL_checkfixed(L, 3); + break; + case sector_floorangle: + sector->floorangle = luaL_checkangle(L, 3); + break; case sector_ceilingpic: sector->ceilingpic = P_AddLevelFlatRuntime(luaL_checkstring(L, 3)); break; + case sector_ceilingxoffset: + sector->ceilingxoffset = luaL_checkfixed(L, 3); + break; + case sector_ceilingyoffset: + sector->ceilingyoffset = luaL_checkfixed(L, 3); + break; + case sector_ceilingangle: + sector->ceilingangle = luaL_checkangle(L, 3); + break; case sector_lightlevel: sector->lightlevel = (INT16)luaL_checkinteger(L, 3); break; @@ -805,12 +876,18 @@ static int sector_set(lua_State *L) case sector_floorlightabsolute: sector->floorlightabsolute = luaL_checkboolean(L, 3); break; + case sector_floorlightsec: + sector->floorlightsec = (INT32)luaL_checkinteger(L, 3); + break; case sector_ceilinglightlevel: sector->ceilinglightlevel = (INT16)luaL_checkinteger(L, 3); break; case sector_ceilinglightabsolute: sector->ceilinglightabsolute = luaL_checkboolean(L, 3); break; + case sector_ceilinglightsec: + sector->ceilinglightsec = (INT32)luaL_checkinteger(L, 3); + break; case sector_special: sector->special = (INT16)luaL_checkinteger(L, 3); break; @@ -1044,8 +1121,24 @@ static int line_get(lua_State *L) LUA_PushUserdata(L, line->polyobj, META_POLYOBJ); return 1; case line_text: - lua_pushstring(L, line->text); - return 1; + { + if (udmf) + { + LUA_Deprecated(L, "(linedef_t).text", "(linedef_t).stringargs"); + lua_pushnil(L); + return 1; + } + + if (line->special == 331 || line->special == 443) + { + // See P_ProcessLinedefsAfterSidedefs, P_ConvertBinaryLinedefTypes + lua_pushstring(L, line->stringargs[0]); + } + else + lua_pushnil(L); + + return 1; + } case line_callcount: lua_pushinteger(L, line->callcount); return 1; @@ -1179,8 +1272,19 @@ static int side_get(lua_State *L) lua_pushinteger(L, side->repeatcnt); return 1; case side_text: - lua_pushstring(L, side->text); - return 1; + { + if (udmf) + { + LUA_Deprecated(L, "(sidedef_t).text", "(sidedef_t).line.stringargs"); + lua_pushnil(L); + return 1; + } + + boolean isfrontside = side->line->sidenum[0] == side-sides; + + lua_pushstring(L, side->line->stringargs[isfrontside ? 0 : 1]); + return 1; + } } return 0; } @@ -1206,8 +1310,9 @@ static int side_set(lua_State *L) case side_sector: case side_special: case side_text: - default: return luaL_error(L, "side_t field " LUA_QS " cannot be set.", side_opt[field]); + default: + return luaL_error(L, "side_t has no field named " LUA_QS ".", lua_tostring(L, 2)); case side_textureoffset: side->textureoffset = luaL_checkfixed(L, 3); break; @@ -2236,8 +2341,9 @@ static int ffloor_set(lua_State *L) case ffloor_target: // target case ffloor_next: // next case ffloor_prev: // prev - default: return luaL_error(L, "ffloor_t field " LUA_QS " cannot be set.", ffloor_opt[field]); + default: + return luaL_error(L, "ffloor_t has no field named " LUA_QS ".", lua_tostring(L, 2)); case ffloor_topheight: { // topheight boolean flag; fixed_t lastpos = *ffloor->topheight; @@ -2371,8 +2477,9 @@ static int slope_set(lua_State *L) case slope_d: // d case slope_flags: // flags case slope_normal: // normal - default: return luaL_error(L, "pslope_t field " LUA_QS " cannot be set.", slope_opt[field]); + default: + return luaL_error(L, "pslope_t has no field named " LUA_QS ".", lua_tostring(L, 2)); case slope_o: { // o luaL_checktype(L, 3, LUA_TTABLE); @@ -2767,6 +2874,7 @@ static int mapheaderinfo_get(lua_State *L) break; // TODO add support for reading numGradedMares and grades default: + { // Read custom vars now // (note: don't include the "LUA." in your lua scripts!) UINT8 j = 0; @@ -2777,6 +2885,7 @@ static int mapheaderinfo_get(lua_State *L) else lua_pushnil(L); } + } return 1; } diff --git a/src/lua_mobjlib.c b/src/lua_mobjlib.c index 09d244c9101bc7b562e4c082113b197be5abf618..fddf958beb783e27671cb966c3afbc3e20b0c620 100644 --- a/src/lua_mobjlib.c +++ b/src/lua_mobjlib.c @@ -33,7 +33,8 @@ enum mobj_e { mobj_angle, mobj_pitch, mobj_roll, - mobj_rollangle, + mobj_spriteroll, + mobj_rollangle, // backwards compat mobj_sprite, mobj_frame, mobj_sprite2, @@ -43,6 +44,8 @@ enum mobj_e { mobj_spritexoffset, mobj_spriteyoffset, mobj_floorspriteslope, + mobj_drawonlyforplayer, + mobj_dontdrawforviewmobj, mobj_touching_sectorlist, mobj_subsector, mobj_floorz, @@ -110,7 +113,8 @@ static const char *const mobj_opt[] = { "angle", "pitch", "roll", - "rollangle", + "spriteroll", + "rollangle", // backwards compat "sprite", "frame", "sprite2", @@ -120,6 +124,8 @@ static const char *const mobj_opt[] = { "spritexoffset", "spriteyoffset", "floorspriteslope", + "drawonlyforplayer", + "dontdrawforviewmobj", "touching_sectorlist", "subsector", "floorz", @@ -229,8 +235,9 @@ static int mobj_get(lua_State *L) case mobj_roll: lua_pushangle(L, mo->roll); break; - case mobj_rollangle: - lua_pushangle(L, mo->rollangle); + case mobj_spriteroll: + case mobj_rollangle: // backwards compat + lua_pushangle(L, mo->spriteroll); break; case mobj_sprite: lua_pushinteger(L, mo->sprite); @@ -259,6 +266,17 @@ static int mobj_get(lua_State *L) case mobj_floorspriteslope: LUA_PushUserdata(L, mo->floorspriteslope, META_SLOPE); break; + case mobj_drawonlyforplayer: + LUA_PushUserdata(L, mo->drawonlyforplayer, META_PLAYER); + break; + case mobj_dontdrawforviewmobj: + if (mo->dontdrawforviewmobj && P_MobjWasRemoved(mo->dontdrawforviewmobj)) + { // don't put invalid mobj back into Lua. + P_SetTarget(&mo->dontdrawforviewmobj, NULL); + return 0; + } + LUA_PushUserdata(L, mo->dontdrawforviewmobj, META_MOBJ); + break; case mobj_touching_sectorlist: return UNIMPLEMENTED; case mobj_subsector: @@ -518,8 +536,9 @@ static int mobj_set(lua_State *L) case mobj_roll: mo->roll = luaL_checkangle(L, 3); break; - case mobj_rollangle: - mo->rollangle = luaL_checkangle(L, 3); + case mobj_spriteroll: + case mobj_rollangle: // backwards compat + mo->spriteroll = luaL_checkangle(L, 3); break; case mobj_sprite: mo->sprite = luaL_checkinteger(L, 3); @@ -547,6 +566,24 @@ static int mobj_set(lua_State *L) break; case mobj_floorspriteslope: return NOSET; + case mobj_drawonlyforplayer: + if (lua_isnil(L, 3)) + mo->drawonlyforplayer = NULL; + else + { + player_t *drawonlyforplayer = *((player_t **)luaL_checkudata(L, 3, META_PLAYER)); + mo->drawonlyforplayer = drawonlyforplayer; + } + break; + case mobj_dontdrawforviewmobj: + if (lua_isnil(L, 3)) + P_SetTarget(&mo->dontdrawforviewmobj, NULL); + else + { + mobj_t *dontdrawforviewmobj = *((mobj_t **)luaL_checkudata(L, 3, META_MOBJ)); + P_SetTarget(&mo->dontdrawforviewmobj, dontdrawforviewmobj); + } + break; case mobj_touching_sectorlist: return UNIMPLEMENTED; case mobj_subsector: @@ -888,6 +925,8 @@ enum mapthing_e { mapthing_type, mapthing_options, mapthing_scale, + mapthing_spritexscale, + mapthing_spriteyscale, mapthing_z, mapthing_extrainfo, mapthing_tag, @@ -907,6 +946,8 @@ const char *const mapthing_opt[] = { "type", "options", "scale", + "spritexscale", + "spriteyscale", "z", "extrainfo", "tag", @@ -962,7 +1003,13 @@ static int mapthing_get(lua_State *L) lua_pushinteger(L, mt->options); break; case mapthing_scale: - lua_pushinteger(L, mt->scale); + lua_pushfixed(L, mt->scale); + break; + case mapthing_spritexscale: + lua_pushfixed(L, mt->spritexscale); + break; + case mapthing_spriteyscale: + lua_pushfixed(L, mt->spriteyscale); break; case mapthing_z: lua_pushinteger(L, mt->z); @@ -1035,15 +1082,23 @@ static int mapthing_set(lua_State *L) case mapthing_scale: mt->scale = luaL_checkfixed(L, 3); break; + case mapthing_spritexscale: + mt->spritexscale = luaL_checkfixed(L, 3); + break; + case mapthing_spriteyscale: + mt->spriteyscale = luaL_checkfixed(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_tag: Tag_FSet(&mt->tags, (INT16)luaL_checkinteger(L, 3)); break; diff --git a/src/lua_playerlib.c b/src/lua_playerlib.c index 1d06e081b114435fd6595d8c9896a5ba10660d81..827e5a405fffb7fa1dda25f58aea049dc244bf38 100644 --- a/src/lua_playerlib.c +++ b/src/lua_playerlib.c @@ -114,6 +114,7 @@ enum player_e player_skin, player_availabilities, player_score, + player_recordscore, player_dashspeed, player_normalspeed, player_runspeed, @@ -222,6 +223,7 @@ enum player_e player_blocked, player_jointime, player_quittime, + player_ping, #ifdef HWRENDER player_fovadd, #endif @@ -260,6 +262,7 @@ static const char *const player_opt[] = { "skin", "availabilities", "score", + "recordscore", "dashspeed", "normalspeed", "runspeed", @@ -368,6 +371,7 @@ static const char *const player_opt[] = { "blocked", "jointime", "quittime", + "ping", #ifdef HWRENDER "fovadd", #endif @@ -495,6 +499,9 @@ static int player_get(lua_State *L) case player_score: lua_pushinteger(L, plr->score); break; + case player_recordscore: + lua_pushinteger(L, plr->recordscore); + break; case player_dashspeed: lua_pushfixed(L, plr->dashspeed); break; @@ -819,6 +826,9 @@ static int player_get(lua_State *L) case player_quittime: lua_pushinteger(L, plr->quittime); break; + case player_ping: + lua_pushinteger(L, playerpingtable[plr - players]); + break; #ifdef HWRENDER case player_fovadd: lua_pushfixed(L, plr->fovadd); @@ -843,7 +853,7 @@ static int player_get(lua_State *L) return 1; } -#define NOSET luaL_error(L, LUA_QL("player_t") " field " LUA_QS " should not be set directly.", field) +#define NOSET luaL_error(L, LUA_QL("player_t") " field " LUA_QS " should not be set directly.", player_opt[field]) static int player_set(lua_State *L) { player_t *plr = *((player_t **)luaL_checkudata(L, 1, META_PLAYER)); @@ -957,6 +967,9 @@ static int player_set(lua_State *L) case player_score: plr->score = (UINT32)luaL_checkinteger(L, 3); break; + case player_recordscore: + plr->recordscore = (UINT32)luaL_checkinteger(L, 3); + break; case player_dashspeed: plr->dashspeed = luaL_checkfixed(L, 3); break; @@ -1278,14 +1291,33 @@ static int player_set(lua_State *L) mobj_t *mo = NULL; if (!lua_isnil(L, 3)) mo = *((mobj_t **)luaL_checkudata(L, 3, META_MOBJ)); - P_SetTarget(&plr->awayviewmobj, mo); + if (plr->awayviewmobj != mo) { + P_SetTarget(&plr->awayviewmobj, mo); + if (plr->awayviewtics) { + if (!plr->awayviewmobj) + plr->awayviewtics = 0; // can't have a NULL awayviewmobj with awayviewtics! + if (plr == &players[displayplayer]) + P_ResetCamera(plr, &camera); // reset p1 camera on p1 getting an awayviewmobj + else if (splitscreen && plr == &players[secondarydisplayplayer]) + P_ResetCamera(plr, &camera2); // reset p2 camera on p2 getting an awayviewmobj + } + } break; } case player_awayviewtics: - plr->awayviewtics = (INT32)luaL_checkinteger(L, 3); - if (plr->awayviewtics && !plr->awayviewmobj) // awayviewtics must ALWAYS have an awayviewmobj set!! + { + INT32 tics = (INT32)luaL_checkinteger(L, 3); + if (tics && !plr->awayviewmobj) // awayviewtics must ALWAYS have an awayviewmobj set!! P_SetTarget(&plr->awayviewmobj, plr->mo); // but since the script might set awayviewmobj immediately AFTER setting awayviewtics, use player mobj as filler for now. + if ((tics && !plr->awayviewtics) || (!tics && plr->awayviewtics)) { + if (plr == &players[displayplayer]) + P_ResetCamera(plr, &camera); // reset p1 camera on p1 transitioning to/from zero awayviewtics + else if (splitscreen && plr == &players[secondarydisplayplayer]) + P_ResetCamera(plr, &camera2); // reset p2 camera on p2 transitioning to/from zero awayviewtics + } + plr->awayviewtics = tics; break; + } case player_awayviewaiming: plr->awayviewaiming = luaL_checkangle(L, 3); break; @@ -1392,7 +1424,7 @@ static int power_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) +#define NOSET luaL_error(L, LUA_QL("ticcmd_t") " field " LUA_QS " should not be set directly.", ticcmd_opt[field]) enum ticcmd_e { diff --git a/src/lua_script.c b/src/lua_script.c index 6893265d5754995ce2ef75a778b895f69c075480..6a5982006379d3e32e9694009e73fe67111a7f40 100644 --- a/src/lua_script.c +++ b/src/lua_script.c @@ -225,6 +225,18 @@ int LUA_PushGlobals(lua_State *L, const char *word) } else if (fastcmp(word,"pointlimit")) { lua_pushinteger(L, cv_pointlimit.value); return 1; + } else if (fastcmp(word, "redflag")) { + LUA_PushUserdata(L, redflag, META_MOBJ); + return 1; + } else if (fastcmp(word, "blueflag")) { + LUA_PushUserdata(L, blueflag, META_MOBJ); + return 1; + } else if (fastcmp(word, "rflagpoint")) { + LUA_PushUserdata(L, rflagpoint, META_MAPTHING); + return 1; + } else if (fastcmp(word, "bflagpoint")) { + LUA_PushUserdata(L, bflagpoint, META_MAPTHING); + return 1; // begin map vars } else if (fastcmp(word,"spstage_start")) { lua_pushinteger(L, spstage_start); @@ -501,7 +513,19 @@ static int setglobals(lua_State *L) actionnum = LUA_GetActionNumByName(name); if (actionnum < NUMACTIONS) - actionsoverridden[actionnum] = true; + { + int i; + + for (i = MAX_ACTION_RECURSION-1; i > 0; i--) + { + // Move other references deeper. + actionsoverridden[actionnum][i] = actionsoverridden[actionnum][i - 1]; + } + + // Add the new reference. + lua_pushvalue(L, 2); + actionsoverridden[actionnum][0] = luaL_ref(L, LUA_REGISTRYINDEX); + } Z_Free(name); return 0; @@ -965,6 +989,7 @@ enum ARCH_MAPHEADER, ARCH_SKINCOLOR, ARCH_MOUSE, + ARCH_SKIN, ARCH_TEND=0xFF, }; @@ -993,6 +1018,7 @@ static const struct { {META_MAPHEADER, ARCH_MAPHEADER}, {META_SKINCOLOR, ARCH_SKINCOLOR}, {META_MOUSE, ARCH_MOUSE}, + {META_SKIN, ARCH_SKIN}, {NULL, ARCH_NULL} }; @@ -1314,6 +1340,13 @@ static UINT8 ArchiveValue(int TABLESINDEX, int myindex) WRITEUINT8(save_p, m == &mouse ? 1 : 2); break; } + case ARCH_SKIN: + { + skin_t *skin = *((skin_t **)lua_touserdata(gL, myindex)); + WRITEUINT8(save_p, ARCH_SKIN); + WRITEUINT8(save_p, skin - skins); // UINT8 because MAXSKINS is only 32 + break; + } default: WRITEUINT8(save_p, ARCH_NULL); return 2; @@ -1560,6 +1593,9 @@ static UINT8 UnArchiveValue(int TABLESINDEX) case ARCH_MOUSE: LUA_PushUserdata(gL, READUINT16(save_p) == 1 ? &mouse : &mouse2, META_MOUSE); break; + case ARCH_SKIN: + LUA_PushUserdata(gL, &skins[READUINT8(save_p)], META_SKIN); + break; case ARCH_TEND: return 1; } diff --git a/src/lua_skinlib.c b/src/lua_skinlib.c index b7890a6c71ecdd1356715a7df95d73b4ab573ea5..041c5d59851f3669b03d45c899c20b3440e193f0 100644 --- a/src/lua_skinlib.c +++ b/src/lua_skinlib.c @@ -25,6 +25,7 @@ enum skin { skin_flags, skin_realname, skin_hudname, + skin_supername, skin_ability, skin_ability2, skin_thokitem, @@ -63,6 +64,7 @@ static const char *const skin_opt[] = { "flags", "realname", "hudname", + "supername", "ability", "ability2", "thokitem", @@ -126,6 +128,9 @@ static int skin_get(lua_State *L) case skin_hudname: lua_pushstring(L, skin->hudname); break; + case skin_supername: + lua_pushstring(L, skin->supername); + break; case skin_ability: lua_pushinteger(L, skin->ability); break; @@ -334,13 +339,13 @@ static const char *const sprites_opt[] = { // skin.sprites[i] -> sprites[i] static int lib_getSkinSprite(lua_State *L) { - spritedef_t *sprites = *(spritedef_t **)luaL_checkudata(L, 1, META_SKINSPRITES); + spritedef_t *sksprites = *(spritedef_t **)luaL_checkudata(L, 1, META_SKINSPRITES); playersprite_t i = luaL_checkinteger(L, 2); if (i < 0 || i >= NUMPLAYERSPRITES*2) return luaL_error(L, LUA_QL("skin_t") " field 'sprites' index %d out of range (0 - %d)", i, (NUMPLAYERSPRITES*2)-1); - LUA_PushUserdata(L, &sprites[i], META_SKINSPRITESLIST); + LUA_PushUserdata(L, &sksprites[i], META_SKINSPRITESLIST); return 1; } diff --git a/src/m_cheat.c b/src/m_cheat.c index e370335f8332d65fd7f5824270f99a81d9ba7a4b..7ad86353ac86916b167d3e0768f9a8ad6f23444e 100644 --- a/src/m_cheat.c +++ b/src/m_cheat.c @@ -1102,6 +1102,8 @@ static mapthing_t *OP_CreateNewMapThing(player_t *player, UINT16 type, boolean c mt->options = (mt->z << ZSHIFT) | (UINT16)cv_opflags.value; mt->scale = player->mo->scale; + mt->spritexscale = player->mo->spritexscale; + mt->spriteyscale = player->mo->spriteyscale; memset(mt->args, 0, NUMMAPTHINGARGS*sizeof(*mt->args)); memset(mt->stringargs, 0x00, NUMMAPTHINGSTRINGARGS*sizeof(*mt->stringargs)); mt->pitch = mt->roll = 0; diff --git a/src/m_cond.c b/src/m_cond.c index a54988f67accbb8f790fbfc06e9a9055b2362f7c..6c87ebf6e5d8fb30789be6b5675f10daa574a22e 100644 --- a/src/m_cond.c +++ b/src/m_cond.c @@ -45,7 +45,7 @@ INT32 numemblems = 0; INT32 numextraemblems = 0; // Temporary holding place for nights data for the current map -nightsdata_t ntemprecords; +nightsdata_t ntemprecords[MAXPLAYERS]; // Create a new gamedata_t, for start-up gamedata_t *M_NewGameDataStruct(void) @@ -113,7 +113,7 @@ void M_AddRawCondition(UINT8 set, UINT8 id, conditiontype_t c, INT32 r, INT16 x1 condition_t *cond; UINT32 num, wnum; - I_Assert(set && set <= MAXCONDITIONSETS); + I_Assert(set < MAXCONDITIONSETS); wnum = conditionSets[set - 1].numconditions; num = ++conditionSets[set - 1].numconditions; @@ -467,6 +467,15 @@ UINT8 M_SecretUnlocked(INT32 type, gamedata_t *data) UINT8 M_MapLocked(INT32 mapnum, gamedata_t *data) { + if (dedicated) + { + // If you're in a dedicated server, every level is unlocked. + // Yes, technically this means you can view any level by + // running a dedicated server and joining it yourself, but + // that's better than making dedicated server's lives hell. + return false; + } + if (!mapheaderinfo[mapnum-1] || mapheaderinfo[mapnum-1]->unlockrequired < 0) { return false; @@ -480,6 +489,48 @@ UINT8 M_MapLocked(INT32 mapnum, gamedata_t *data) return false; } +UINT8 M_CampaignWarpIsCheat(INT32 gt, INT32 mapnum, gamedata_t *data) +{ + if (M_MapLocked(mapnum, data) == true) + { + // Warping to locked maps is definitely always a cheat + return true; + } + + if ((gametypedefaultrules[gt] & GTR_CAMPAIGN) == 0) + { + // Not a campaign, do whatever you want. + return false; + } + + if (G_IsSpecialStage(mapnum)) + { + // Warping to special stages is a cheat + return true; + } + + if (mapheaderinfo[mapnum-1]->menuflags & LF2_HIDEINMENU) + { + // You're never allowed to warp to this level. + return true; + } + + if (mapheaderinfo[mapnum-1]->menuflags & LF2_NOVISITNEEDED) + { + // You're always allowed to warp to this level. + return false; + } + + if (mapnum == spstage_start) + { + // Warping to the first level is never a cheat + return false; + } + + // It's only a cheat if you've never been there. + return (!(data->mapvisited[mapnum-1])); +} + INT32 M_CountEmblems(gamedata_t *data) { INT32 found = 0, i; diff --git a/src/m_cond.h b/src/m_cond.h index 6a3da79ece7091c7ef0f68981355e6d0a691bb79..2491a384c02aa5f34ba47933eba689811ac599d0 100644 --- a/src/m_cond.h +++ b/src/m_cond.h @@ -139,8 +139,8 @@ typedef struct // you seriously need to get a life. #define MAXCONDITIONSETS 128 #define MAXEMBLEMS 512 -#define MAXEXTRAEMBLEMS 16 -#define MAXUNLOCKABLES 32 +#define MAXEXTRAEMBLEMS 48 +#define MAXUNLOCKABLES 80 /** Time attack information, currently a very small structure. */ @@ -181,7 +181,7 @@ typedef struct #define MV_MAX 63 // used in gamedata check, update whenever MV's are added // Temporary holding place for nights data for the current map -extern nightsdata_t ntemprecords; +extern nightsdata_t ntemprecords[MAXPLAYERS]; // GAMEDATA STRUCTURE // Everything that would get saved in gamedata.dat @@ -252,6 +252,7 @@ void M_SilentUpdateSkinAvailabilites(void); UINT8 M_AnySecretUnlocked(gamedata_t *data); UINT8 M_SecretUnlocked(INT32 type, gamedata_t *data); UINT8 M_MapLocked(INT32 mapnum, gamedata_t *data); +UINT8 M_CampaignWarpIsCheat(INT32 gt, INT32 mapnum, gamedata_t *data); INT32 M_CountEmblems(gamedata_t *data); // Emblem shit diff --git a/src/m_fixed.c b/src/m_fixed.c index ad283119646b75abf514360bcf64d96972e86214..b674e3b2c8e230524d57ea540dada83b8bf75eb6 100644 --- a/src/m_fixed.c +++ b/src/m_fixed.c @@ -21,50 +21,6 @@ #include "doomdef.h" #include "m_fixed.h" -#ifdef __USE_C_FIXEDMUL__ - -/** \brief The FixedMul function - - \param a fixed_t number - \param b fixed_t number - - \return a*b>>FRACBITS - -*/ -fixed_t FixedMul(fixed_t a, fixed_t b) -{ - // Need to cast to unsigned before shifting to avoid undefined behaviour - // for negative integers - return (fixed_t)(((UINT64)((INT64)a * b)) >> FRACBITS); -} - -#endif //__USE_C_FIXEDMUL__ - -#ifdef __USE_C_FIXEDDIV__ -/** \brief The FixedDiv2 function - - \param a fixed_t number - \param b fixed_t number - - \return a/b * FRACUNIT - -*/ -fixed_t FixedDiv2(fixed_t a, fixed_t b) -{ - INT64 ret; - - if (b == 0) - I_Error("FixedDiv: divide by zero"); - - ret = (((INT64)a * FRACUNIT)) / b; - - if ((ret > INT32_MAX) || (ret < INT32_MIN)) - I_Error("FixedDiv: divide by zero"); - return (fixed_t)ret; -} - -#endif // __USE_C_FIXEDDIV__ - fixed_t FixedSqrt(fixed_t x) { #ifdef HAVE_SQRT diff --git a/src/m_fixed.h b/src/m_fixed.h index 4a5b7ce2adf863571000b2134948d0c8e4e3e86f..94bd6a16bbf86e70c4f38c86a4758424da325db1 100644 --- a/src/m_fixed.h +++ b/src/m_fixed.h @@ -53,127 +53,35 @@ FUNCMATH FUNCINLINE static ATTRINLINE fixed_t FloatToFixed(float f) #define FIXED_TO_FLOAT(x) FixedToFloat(x) // (((float)(x)) / ((float)FRACUNIT)) #define FLOAT_TO_FIXED(f) FloatToFixed(f) // (fixed_t)((f) * ((float)FRACUNIT)) +/** \brief The FixedMul function -#if defined (__WATCOMC__) && FRACBITS == 16 - #pragma aux FixedMul = \ - "imul ebx", \ - "shrd eax,edx,16" \ - parm [eax] [ebx] \ - value [eax] \ - modify exact [eax edx] - - #pragma aux FixedDiv2 = \ - "cdq", \ - "shld edx,eax,16", \ - "sal eax,16", \ - "idiv ebx" \ - parm [eax] [ebx] \ - value [eax] \ - modify exact [eax edx] -#elif defined (__GNUC__) && defined (__i386__) && !defined (NOASM) - // i386 linux, cygwin or mingw - FUNCMATH FUNCINLINE static inline fixed_t FixedMul(fixed_t a, fixed_t b) // asm - { - fixed_t ret; - asm - ( - "imull %2;" // a*b - "shrdl %3,%%edx,%0;" // shift logical right FRACBITS bits - :"=a" (ret) // eax is always the result and the first operand (%0,%1) - :"0" (a), "r" (b) // and %2 is what we use imull on with what in %1 - , "I" (FRACBITS) // %3 holds FRACBITS (normally 16) - :"cc", "%edx" // edx and condition codes clobbered - ); - return ret; - } + \param a fixed_t number + \param b fixed_t number - FUNCMATH FUNCINLINE static inline fixed_t FixedDiv2(fixed_t a, fixed_t b) - { - fixed_t ret; - asm - ( - "movl %1,%%edx;" // these two instructions allow the next two to pair, on the Pentium processor. - "sarl $31,%%edx;" // shift arithmetic right 31 on EDX - "shldl %3,%1,%%edx;" // DP shift logical left FRACBITS on EDX - "sall %3,%0;" // shift arithmetic left FRACBITS on EAX - "idivl %2;" // EDX/b = EAX - : "=a" (ret) - : "0" (a), "r" (b) - , "I" (FRACBITS) - : "%edx" - ); - return ret; - } -#elif defined (__GNUC__) && defined (__arm__) && !defined(__thumb__) && !defined(NOASM) //ARMv4 ASM - FUNCMATH FUNCINLINE static inline fixed_t FixedMul(fixed_t a, fixed_t b) // let abuse smull - { - fixed_t ret; - asm - ( - "smull %[lo], r1, %[a], %[b];" - "mov %[lo], %[lo], lsr %3;" - "orr %[lo], %[lo], r1, lsl %3;" - : [lo] "=&r" (ret) // rhi, rlo and rm must be distinct registers - : [a] "r" (a), [b] "r" (b) - , "i" (FRACBITS) - : "r1" - ); - return ret; - } + \return a*b>>FRACBITS - #define __USE_C_FIXEDDIV__ // no double or asm div in ARM land -#elif defined (__GNUC__) && defined (__ppc__) && !defined(NOASM) && 0 // WII: PPC CPU - FUNCMATH FUNCINLINE static inline fixed_t FixedMul(fixed_t a, fixed_t b) // asm - { - fixed_t ret, hi, lo; - asm - ( - "mullw %0, %2, %3;" - "mulhw %1, %2, %3" - : "=r" (hi), "=r" (lo) - : "r" (a), "r" (b) - , "I" (FRACBITS) - ); - ret = (INT64)((hi>>FRACBITS)+lo)<<FRACBITS; - return ret; - } +*/ +FUNCMATH FUNCINLINE static ATTRINLINE fixed_t FixedMul(fixed_t a, fixed_t b) +{ + // Need to cast to unsigned before shifting to avoid undefined behaviour + // for negative integers + return (fixed_t)(((UINT64)((INT64)a * b)) >> FRACBITS); +} - #define __USE_C_FIXEDDIV__// Alam: I am lazy -#elif defined (__GNUC__) && defined (__mips__) && !defined(NOASM) && 0 // PSP: MIPS CPU - FUNCMATH FUNCINLINE static inline fixed_t FixedMul(fixed_t a, fixed_t b) // asm - { - fixed_t ret; - asm - ( - "mult %3, %4;" // a*b=h<32+l - : "=r" (ret), "=l" (a), "=h" (b) //todo: abuse shr opcode - : "0" (a), "r" (b) - , "I" (FRACBITS) - //: "+l", "+h" - ); - ret = (INT64)((a>>FRACBITS)+b)<<FRACBITS; - return ret; - } +/** \brief The FixedDiv2 function - #define __USE_C_FIXEDDIV__ // no 64b asm div in MIPS land -#elif defined (__GNUC__) && defined (__sh__) && 0 // DC: SH4 CPU -#elif defined (__GNUC__) && defined (__m68k__) && 0 // DEAD: Motorola 6800 CPU -#elif defined (_MSC_VER) && defined(USEASM) && FRACBITS == 16 - // Microsoft Visual C++ (no asm inline) - fixed_t __cdecl FixedMul(fixed_t a, fixed_t b); - fixed_t __cdecl FixedDiv2(fixed_t a, fixed_t b); -#else - #define __USE_C_FIXEDMUL__ - #define __USE_C_FIXEDDIV__ -#endif + \param a fixed_t number + \param b fixed_t number -#ifdef __USE_C_FIXEDMUL__ -FUNCMATH fixed_t FixedMul(fixed_t a, fixed_t b); -#endif + \return a/b * FRACUNIT -#ifdef __USE_C_FIXEDDIV__ -FUNCMATH fixed_t FixedDiv2(fixed_t a, fixed_t b); -#endif +*/ +FUNCMATH FUNCINLINE static ATTRINLINE fixed_t FixedDiv2(fixed_t a, fixed_t b) +{ + // This does not check for division overflow or division by 0! + // That is the caller's responsibility. + return (fixed_t)(((INT64)a * FRACUNIT) / b); +} /** \brief The FixedInt function diff --git a/src/m_menu.c b/src/m_menu.c index f9f52335d00dd56f488e2c73f8242546cb33743f..3946803b290e0240cac36accd363113256580933 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -389,6 +389,7 @@ static void M_DrawRoomMenu(void); #endif static void M_DrawJoystick(void); static void M_DrawSetupMultiPlayerMenu(void); +static void M_DrawColorRamp(INT32 x, INT32 y, INT32 w, INT32 h, skincolor_t color); // Handling functions static boolean M_ExitPandorasBox(void); @@ -693,42 +694,10 @@ static menuitem_t SR_PandorasBox[] = }; // Sky Room Custom Unlocks -static menuitem_t SR_MainMenu[] = +static menuitem_t SR_MainMenu[MAXUNLOCKABLES+1] = { {IT_STRING|IT_SUBMENU,NULL, "Extras Checklist", &SR_UnlockChecklistDef, 0}, - {IT_DISABLED, NULL, "", NULL, 0}, // Custom1 - {IT_DISABLED, NULL, "", NULL, 0}, // Custom2 - {IT_DISABLED, NULL, "", NULL, 0}, // Custom3 - {IT_DISABLED, NULL, "", NULL, 0}, // Custom4 - {IT_DISABLED, NULL, "", NULL, 0}, // Custom5 - {IT_DISABLED, NULL, "", NULL, 0}, // Custom6 - {IT_DISABLED, NULL, "", NULL, 0}, // Custom7 - {IT_DISABLED, NULL, "", NULL, 0}, // Custom8 - {IT_DISABLED, NULL, "", NULL, 0}, // Custom9 - {IT_DISABLED, NULL, "", NULL, 0}, // Custom10 - {IT_DISABLED, NULL, "", NULL, 0}, // Custom11 - {IT_DISABLED, NULL, "", NULL, 0}, // Custom12 - {IT_DISABLED, NULL, "", NULL, 0}, // Custom13 - {IT_DISABLED, NULL, "", NULL, 0}, // Custom14 - {IT_DISABLED, NULL, "", NULL, 0}, // Custom15 - {IT_DISABLED, NULL, "", NULL, 0}, // Custom16 - {IT_DISABLED, NULL, "", NULL, 0}, // Custom17 - {IT_DISABLED, NULL, "", NULL, 0}, // Custom18 - {IT_DISABLED, NULL, "", NULL, 0}, // Custom19 - {IT_DISABLED, NULL, "", NULL, 0}, // Custom20 - {IT_DISABLED, NULL, "", NULL, 0}, // Custom21 - {IT_DISABLED, NULL, "", NULL, 0}, // Custom22 - {IT_DISABLED, NULL, "", NULL, 0}, // Custom23 - {IT_DISABLED, NULL, "", NULL, 0}, // Custom24 - {IT_DISABLED, NULL, "", NULL, 0}, // Custom25 - {IT_DISABLED, NULL, "", NULL, 0}, // Custom26 - {IT_DISABLED, NULL, "", NULL, 0}, // Custom27 - {IT_DISABLED, NULL, "", NULL, 0}, // Custom28 - {IT_DISABLED, NULL, "", NULL, 0}, // Custom29 - {IT_DISABLED, NULL, "", NULL, 0}, // Custom30 - {IT_DISABLED, NULL, "", NULL, 0}, // Custom31 - {IT_DISABLED, NULL, "", NULL, 0}, // Custom32 - + // The remaining (MAXUNLOCKABLES) items are now initialized in M_SecretsMenu }; static menuitem_t SR_LevelSelectMenu[] = @@ -1345,17 +1314,17 @@ static menuitem_t OP_VideoOptionsMenu[] = {IT_STRING | IT_CALL, NULL, "Set Resolution...", M_VideoModeMenu, 6}, #if defined (__unix__) || defined (UNIXCOMMON) || defined (HAVE_SDL) - {IT_STRING|IT_CVAR, NULL, "Fullscreen", &cv_fullscreen, 11}, + {IT_STRING|IT_CVAR, NULL, "Fullscreen (F11)", &cv_fullscreen, 11}, #endif {IT_STRING | IT_CVAR, NULL, "Vertical Sync", &cv_vidwait, 16}, #ifdef HWRENDER - {IT_STRING | IT_CVAR, NULL, "Renderer", &cv_renderer, 21}, + {IT_STRING | IT_CVAR, NULL, "Renderer (F10)", &cv_renderer, 21}, #else - {IT_TRANSTEXT | IT_PAIR, "Renderer", "Software", &cv_renderer, 21}, + {IT_TRANSTEXT | IT_PAIR, "Renderer", "Software", &cv_renderer, 21}, #endif {IT_HEADER, NULL, "Color Profile", NULL, 30}, - {IT_STRING | IT_CVAR | IT_CV_SLIDER, NULL, "Brightness (F11)", &cv_globalgamma,36}, + {IT_STRING | IT_CVAR | IT_CV_SLIDER, NULL, "Brightness", &cv_globalgamma,36}, {IT_STRING | IT_CVAR | IT_CV_SLIDER, NULL, "Saturation", &cv_globalsaturation, 41}, {IT_SUBMENU|IT_STRING, NULL, "Advanced Settings...", &OP_ColorOptionsDef, 46}, @@ -2170,7 +2139,7 @@ static void M_VideoOptions(INT32 choice) { OP_VideoOptionsMenu[op_video_renderer].status = (IT_STRING | IT_CVAR); OP_VideoOptionsMenu[op_video_renderer].patch = NULL; - OP_VideoOptionsMenu[op_video_renderer].text = "Renderer"; + OP_VideoOptionsMenu[op_video_renderer].text = "Renderer (F10)"; } #endif @@ -2680,7 +2649,7 @@ static boolean MIT_SetCurBackground(UINT32 menutype, INT32 level, INT32 *retval, { strncpy(curbgname, defaultname, 9); curbgxspeed = (gamestate == GS_TIMEATTACK) ? 0 : titlescrollxspeed; - curbgyspeed = (gamestate == GS_TIMEATTACK) ? 0 : titlescrollyspeed; + curbgyspeed = (gamestate == GS_TIMEATTACK) ? 18 : titlescrollyspeed; } } return false; @@ -2874,8 +2843,8 @@ static void M_HandleMenuPresState(menu_t *newMenu) curfadevalue = 16; curhidepics = hidetitlepics; curbgcolor = -1; - curbgxspeed = titlescrollxspeed; - curbgyspeed = titlescrollyspeed; + curbgxspeed = (gamestate == GS_TIMEATTACK) ? 0 : titlescrollxspeed; + curbgyspeed = (gamestate == GS_TIMEATTACK) ? 18 : titlescrollyspeed; curbghide = (gamestate != GS_TIMEATTACK); // show in time attack, hide in other menus curttmode = ttmode; @@ -3227,7 +3196,7 @@ boolean M_Responder(event_t *ev) || gamestate == GS_CREDITS || gamestate == GS_EVALUATION || gamestate == GS_GAMEEND) return false; - if (gamestate == GS_TITLESCREEN && finalecount < TICRATE) + if (gamestate == GS_TITLESCREEN && finalecount < (cv_tutorialprompt.value ? TICRATE : 0)) return false; if (CON_Ready() && gamestate != GS_WAITINGPLAYERS) @@ -3410,12 +3379,12 @@ boolean M_Responder(event_t *ev) // Screenshots on F8 now handled elsewhere // Same with Moviemode on F9 - case KEY_F10: // Quit SRB2 - M_QuitSRB2(0); + case KEY_F10: // Renderer toggle, also processed inside menus + CV_AddValue(&cv_renderer, 1); return true; - case KEY_F11: // Gamma Level - CV_AddValue(&cv_globalgamma, 1); + case KEY_F11: // Fullscreen toggle, also processed inside menus + CV_SetValue(&cv_fullscreen, !cv_fullscreen.value); return true; // Spymode on F12 handled in game logic @@ -3531,10 +3500,10 @@ boolean M_Responder(event_t *ev) #ifndef DEVELOP // TODO: Replays are scary, so I left the remaining instances of this alone. // It'd be nice to get rid of this once and for all though! - if (((currentMenu->menuitems[itemOn].status & IT_CALLTYPE) & IT_CALL_NOTMODIFIED) && (modifiedgame && !savemoddata) && !usedCheats) + if (((currentMenu->menuitems[itemOn].status & IT_CALLTYPE) & IT_CALL_NOTMODIFIED) && usedCheats) { S_StartSound(NULL, sfx_skid); - M_StartMessage(M_GetText("This cannot be done in a modified game.\n\n(Press a key)\n"), NULL, MM_NOTHING); + M_StartMessage(M_GetText("This cannot be done in a cheated game.\n\n(Press a key)\n"), NULL, MM_NOTHING); return true; } #endif @@ -3596,6 +3565,14 @@ boolean M_Responder(event_t *ev) // M_SetupNextMenu(currentMenu->prevMenu); return false; + case KEY_F10: // Renderer toggle, also processed outside menus + CV_AddValue(&cv_renderer, 1); + return true; + + case KEY_F11: // Fullscreen toggle, also processed outside menus + CV_SetValue(&cv_fullscreen, !cv_fullscreen.value); + return true; + default: CON_Responder(ev); break; @@ -4226,15 +4203,6 @@ static void M_DrawSaveLoadBorder(INT32 x,INT32 y) } #endif -// horizontally centered text -static void M_CentreText(INT32 y, const char *string) -{ - INT32 x; - //added : 02-02-98 : centre on 320, because V_DrawString centers on vid.width... - x = (BASEVIDWIDTH - V_StringWidth(string, V_OLDSPACING))>>1; - V_DrawString(x,y,V_OLDSPACING,string); -} - // // M_DrawMapEmblems // @@ -7132,9 +7100,6 @@ static void M_DestroyRobots(INT32 choice) static void M_LevelSelectWarp(INT32 choice) { - boolean fromloadgame = (currentMenu == &SP_LevelSelectDef); - boolean frompause = (currentMenu == &SP_PauseLevelSelectDef); - (void)choice; if (W_CheckNumForName(G_BuildMapName(cv_nextmap.value)) == LUMPERROR) @@ -7146,13 +7111,11 @@ static void M_LevelSelectWarp(INT32 choice) startmap = (INT16)(cv_nextmap.value); fromlevelselect = true; - if (fromloadgame) - G_LoadGame((UINT32)cursaveslot, startmap); - else + if (currentMenu == &SP_LevelSelectDef || currentMenu == &SP_PauseLevelSelectDef) { - cursaveslot = 0; - - if (frompause) + if (cursaveslot > 0) // do we have a save slot to load? + G_LoadGame((UINT32)cursaveslot, startmap); // reload from SP save data: this is needed to keep score/lives/continues from reverting to defaults + else // no save slot, start new game but keep the current skin { M_ClearMenus(true); @@ -7163,8 +7126,11 @@ static void M_LevelSelectWarp(INT32 choice) Z_Free(levelselect.rows); levelselect.rows = NULL; } - else - M_SetupChoosePlayer(0); + } + else // start new game + { + cursaveslot = 0; + M_SetupChoosePlayer(0); } } @@ -8129,14 +8095,15 @@ static void M_SecretsMenu(INT32 choice) (void)choice; - // Clear all before starting - for (i = 1; i < MAXUNLOCKABLES+1; ++i) - SR_MainMenu[i].status = IT_DISABLED; + // Initialize array with placeholder entries + menuitem_t placeholder = {IT_DISABLED, NULL, "", NULL, 0}; + for (i = 1; i <= MAXUNLOCKABLES; ++i) + SR_MainMenu[i] = placeholder; memset(skyRoomMenuTranslations, 0, sizeof(skyRoomMenuTranslations)); memset(done, 0, sizeof(done)); - for (i = 1; i < MAXUNLOCKABLES+1; ++i) + for (i = 1; i <= MAXUNLOCKABLES; ++i) { curheight = UINT16_MAX; ul = -1; @@ -8520,7 +8487,7 @@ static void M_DrawLoadGameData(void) if (charskin->prefoppositecolor) { col = charskin->prefoppositecolor; - col = skincolors[col].ramp[skincolors[skincolors[col].invcolor].invshade]; + col = skincolors[col].ramp[skincolors[charskin->prefcolor].invshade]; } else { @@ -10480,13 +10447,23 @@ static void M_ChooseTimeAttack(INT32 choice) G_DeferedInitNew(false, G_BuildMapName(cv_nextmap.value), (UINT8)(cv_chooseskin.value-1), false, false); } +static char ra_demoname[1024]; + +static void M_StartTimeAttackReplay(INT32 choice) +{ + if (choice == 'y' || choice == KEY_ENTER) + { + M_ClearMenus(true); + modeattacking = ATTACKING_RECORD; // set modeattacking before G_DoPlayDemo so the map loader knows + G_DoPlayDemo(ra_demoname); + } +} + // Player has selected the "REPLAY" from the time attack screen static void M_ReplayTimeAttack(INT32 choice) { const char *which; - char *demoname; - M_ClearMenus(true); - modeattacking = ATTACKING_RECORD; // set modeattacking before G_DoPlayDemo so the map loader knows + UINT8 error = DFILE_ERROR_NONE; if (currentMenu == &SP_ReplayDef) { @@ -10506,11 +10483,15 @@ static void M_ReplayTimeAttack(INT32 choice) break; case 4: // guest // srb2/replay/main/map01-guest.lmp - G_DoPlayDemo(va("%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-guest.lmp", srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value))); - return; + snprintf(ra_demoname, 1024, "%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-guest.lmp", srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value)); + break; + } + + if (choice != 4) + { + // srb2/replay/main/map01-sonic-time-best.lmp + snprintf(ra_demoname, 1024, "%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-%s-%s.lmp", srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value), skins[cv_chooseskin.value-1].name, which); } - // srb2/replay/main/map01-sonic-time-best.lmp - G_DoPlayDemo(va("%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-%s-%s.lmp", srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value), skins[cv_chooseskin.value-1].name, which)); } else if (currentMenu == &SP_NightsReplayDef) { @@ -10526,19 +10507,78 @@ static void M_ReplayTimeAttack(INT32 choice) which = "last"; break; case 3: // guest - G_DoPlayDemo(va("%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-guest.lmp", srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value))); - return; + snprintf(ra_demoname, 1024, "%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-guest.lmp", srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value)); + break; } - demoname = va("%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-%s-%s.lmp", srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value), skins[cv_chooseskin.value-1].name, which); + if (choice != 3) + { + snprintf(ra_demoname, 1024, "%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-%s-%s.lmp", srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value), skins[cv_chooseskin.value-1].name, which); #ifdef OLDNREPLAYNAME // Check for old style named NiGHTS replay if a new style replay doesn't exist. - if (!FIL_FileExists(demoname)) - demoname = va("%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-%s.lmp", srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value), which); + if (!FIL_FileExists(ra_demoname)) + { + snprintf(ra_demoname, 1024, "%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-%s.lmp", srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value), which); + } #endif + } + } + + demofileoverride = DFILE_OVERRIDE_NONE; + error = G_CheckDemoForError(ra_demoname); + + if (error) + { + S_StartSound(NULL, sfx_skid); + + switch (error) + { + case DFILE_ERROR_NOTDEMO: + M_StartMessage(M_GetText("An error occurred loading this replay.\n\n(Press a key)\n"), NULL, MM_NOTHING); + break; + + case DFILE_ERROR_NOTLOADED: + demofileoverride = DFILE_OVERRIDE_LOAD; + M_StartMessage(M_GetText("Add-ons for this replay\nhave not been loaded.\n\nAttempt to load files?\n\n(Press 'Y' to confirm)\n"), M_StartTimeAttackReplay, MM_YESNO); + break; + + case DFILE_ERROR_OUTOFORDER: + /* + demofileoverride = DFILE_OVERRIDE_SKIP; + M_StartMessage(M_GetText("Add-ons for this replay\nwere loaded out of order.\n\nAttempt to playback anyway?\n\n(Press 'Y' to confirm)\n"), M_StartTimeAttackReplay, MM_YESNO); + */ + M_StartMessage(M_GetText("Add-ons for this replay\nwere loaded out of order.\n\n(Press a key)\n"), NULL, MM_NOTHING); + break; + + case DFILE_ERROR_INCOMPLETEOUTOFORDER: + /* + demofileoverride = DFILE_OVERRIDE_LOAD; + M_StartMessage(M_GetText("Add-ons for this replay\nhave not been loaded,\nand some are in the wrong order.\n\nAttempt to load files?\n\n(Press 'Y' to confirm)\n"), M_StartTimeAttackReplay, MM_YESNO); + */ + M_StartMessage(M_GetText("Add-ons for this replay\nhave not been loaded,\nand some are in the wrong order.\n\n(Press a key)\n"), NULL, MM_NOTHING); + break; + + case DFILE_ERROR_CANNOTLOAD: + /* + demofileoverride = DFILE_OVERRIDE_SKIP; + M_StartMessage(M_GetText("Add-ons for this replay\ncould not be loaded.\n\nAttempt to playback anyway?\n\n(Press 'Y' to confirm)\n"), M_StartTimeAttackReplay, MM_YESNO); + */ + M_StartMessage(M_GetText("Add-ons for this replay\ncould not be loaded.\n\n(Press a key)\n"), NULL, MM_NOTHING); + break; + + case DFILE_ERROR_EXTRAFILES: + /* + demofileoverride = DFILE_OVERRIDE_SKIP; + M_StartMessage(M_GetText("You have more files loaded\nthan the replay does.\n\nAttempt to playback anyway?\n\n(Press 'Y' to confirm)\n"), M_StartTimeAttackReplay, MM_YESNO); + */ + M_StartMessage(M_GetText("You have more files loaded\nthan the replay does.\n\n(Press a key)\n"), NULL, MM_NOTHING); + break; + } - G_DoPlayDemo(demoname); + return; } + + M_StartTimeAttackReplay(KEY_ENTER); } static void M_EraseGuest(INT32 choice) @@ -11998,6 +12038,8 @@ static void M_HandleConnectIP(INT32 choice) static fixed_t multi_tics; static UINT8 multi_frame; static UINT8 multi_spr2; +static boolean multi_paused; +static boolean multi_invcolor; // this is set before entering the MultiPlayer setup menu, // for either player 1 or 2 @@ -12010,6 +12052,137 @@ static consvar_t *setupm_cvdefaultskin; static consvar_t *setupm_cvdefaultcolor; static INT32 setupm_fakeskin; static menucolor_t *setupm_fakecolor; +static boolean colorgrid; + +#define COLOR_GRID_ROW_SIZE (16) + +static UINT16 M_GetColorGridIndex(UINT16 color) +{ + menucolor_t *look; + UINT16 i = 0; + + if (!skincolors[color].accessible) + { + return 0; + } + + for (look = menucolorhead; ; i++, look = look->next) + { + while (!skincolors[look->color].accessible) // skip inaccessible colors + { + if (look == menucolortail) + { + return 0; + } + + look = look->next; + } + + if (look->color == color) + { + return i; + } + + if (look == menucolortail) + { + return 0; + } + } +} + +static INT32 M_GridIndexToX(UINT16 index) +{ + return (index % COLOR_GRID_ROW_SIZE); +} + +static INT32 M_GridIndexToY(UINT16 index) +{ + return (index / COLOR_GRID_ROW_SIZE); +} + +static UINT16 M_ColorGridLen(void) +{ + menucolor_t *look; + UINT16 i = 0; + + for (look = menucolorhead; ; i++) + { + do + { + if (look == menucolortail) + { + return i; + } + + look = look->next; + } + while (!skincolors[look->color].accessible); // skip inaccessible colors + } +} + +static UINT16 M_GridPosToGridIndex(INT32 x, INT32 y) +{ + const UINT16 grid_len = M_ColorGridLen(); + const UINT16 grid_height = ((grid_len - 1) / COLOR_GRID_ROW_SIZE) + 1; + const UINT16 last_row_len = COLOR_GRID_ROW_SIZE - ((grid_height * COLOR_GRID_ROW_SIZE) - grid_len); + + UINT16 row_len = COLOR_GRID_ROW_SIZE; + UINT16 new_index = 0; + + while (y < 0) + { + y += grid_height; + } + y = (y % grid_height); + + if (y >= grid_height-1 && last_row_len > 0) + { + row_len = last_row_len; + } + + while (x < 0) + { + x += row_len; + } + x = (x % row_len); + + new_index = (y * COLOR_GRID_ROW_SIZE) + x; + if (new_index >= grid_len) + { + new_index = grid_len - 1; + } + + return new_index; +} + +static menucolor_t *M_GridIndexToMenuColor(UINT16 index) +{ + menucolor_t *look = menucolorhead; + UINT16 i = 0; + + for (look = menucolorhead; ; i++, look = look->next) + { + while (!skincolors[look->color].accessible) // skip inaccessible colors + { + if (look == menucolortail) + { + return menucolorhead; + } + + look = look->next; + } + + if (i == index) + { + return look; + } + + if (look == menucolortail) + { + return menucolorhead; + } + } +} static void M_DrawSetupMultiPlayerMenu(void) { @@ -12059,12 +12232,12 @@ static void M_DrawSetupMultiPlayerMenu(void) '\x1D' | V_YELLOWMAP, false); } - x = BASEVIDWIDTH/2; + x = colorgrid ? 92 : BASEVIDWIDTH/2; y += 11; // anim the player in the box multi_tics -= renderdeltatics; - while (multi_tics <= 0) + while (!multi_paused && multi_tics <= 0) { multi_frame++; multi_tics += 4*FRACUNIT; @@ -12073,7 +12246,8 @@ static void M_DrawSetupMultiPlayerMenu(void) #define charw 74 // draw box around character - V_DrawFill(x-(charw/2), y, charw, 84, 159); + V_DrawFill(x-(charw/2), y, charw, 84, + multi_invcolor ?skincolors[skincolors[setupm_fakecolor->color].invcolor].ramp[skincolors[setupm_fakecolor->color].invshade] : 159); sprdef = &skins[setupm_fakeskin].sprites[multi_spr2]; @@ -12116,61 +12290,143 @@ faildraw: #undef chary colordraw: - x = MP_PlayerSetupDef.x; - y += 75; - - M_DrawLevelPlatterHeader(y - (lsheadingheight - 12), "Color", true, false); - if (itemOn == 2) - cursory = y; - // draw color string - V_DrawRightAlignedString(BASEVIDWIDTH - x, y, - ((MP_PlayerSetupMenu[2].status & IT_TYPE) == IT_SPACE ? V_TRANSLUCENT : 0)|(itemOn == 2 ? V_YELLOWMAP : 0)|V_ALLOWLOWERCASE, - skincolors[setupm_fakecolor->color].name); +#define indexwidth 8 - if (itemOn == 2 && (MP_PlayerSetupMenu[2].status & IT_TYPE) != IT_SPACE) + if (colorgrid) // Draw color grid & skip the later options { - V_DrawCharacter(BASEVIDWIDTH - x - 10 - V_StringWidth(skincolors[setupm_fakecolor->color].name, V_ALLOWLOWERCASE) - (skullAnimCounter/5), y, - '\x1C' | V_YELLOWMAP, false); - V_DrawCharacter(BASEVIDWIDTH - x + 2 + (skullAnimCounter/5), y, - '\x1D' | V_YELLOWMAP, false); - } + UINT16 pos; + INT16 cx = 96, cy = 66; + INT16 i, j; + INT32 w = indexwidth; // Width of a singular color block + boolean stoprow = false; + menucolor_t *mc; // Last accessed color - y += 11; + const UINT16 grid_len = M_ColorGridLen(); + const UINT16 grid_end_y = M_GridIndexToY(grid_len - 1); -#define indexwidth 8 + INT32 grid_select = M_GetColorGridIndex(setupm_fakecolor->color); + INT32 grid_select_y = M_GridIndexToY(grid_select); + + x = 132; + y = 66; + + pos = M_GridPosToGridIndex(0, max(0, min(grid_select_y - 3, grid_end_y - 7))); + mc = M_GridIndexToMenuColor(pos); + + // Draw grid + V_DrawFill(x-2, y-2, 132, 132, 159); + for (j = 0; j < 8; j++) + { + for (i = 0; i < COLOR_GRID_ROW_SIZE; i++) + { + if (skincolors[mc->color].accessible) + { + M_DrawColorRamp(x + i*w, y + j*16, w, 1, skincolors[mc->color]); + + if (mc == setupm_fakecolor) // store current color position + { + cx = x + i*w; + cy = y + j*16; + } + } + + if (stoprow) + { + break; + } + + // Find accessible color after this one + do + { + mc = mc->next; + if (mc == menucolortail) + { + stoprow = true; + } + } while (!skincolors[mc->color].accessible && !stoprow); + } + + if (stoprow) + { + break; + } + } + + // Draw arrows, if needed + if (pos > 0) + V_DrawCharacter(264, y - (skullAnimCounter/5), '\x1A' | V_YELLOWMAP, false); + if (!stoprow) + V_DrawCharacter(264, y+120 + (skullAnimCounter/5), '\x1B' | V_YELLOWMAP, false); + + // Draw cursor & current skincolor + V_DrawFill(cx - 2, cy - 2, 12, 20, 0); + V_DrawFill(cx - 1, cy - 1, 11, 19, 31); + V_DrawFill( cx, cy, 9, 17, 0); + M_DrawColorRamp(cx, cy, w, 1, skincolors[setupm_fakecolor->color]); + + // Draw color string (with background) + V_DrawFill(55, 148, 74, 1, 73); + V_DrawFill(55, 149, 74, 1, 26); + M_DrawColorRamp(55, 150, 74, 1, skincolors[setupm_fakecolor->color]); + V_DrawRightAlignedString(x-2,166, + ((MP_PlayerSetupMenu[2].status & IT_TYPE) == IT_SPACE ? V_TRANSLUCENT : 0)|(itemOn == 2 ? V_YELLOWMAP : 0)|V_ALLOWLOWERCASE, + skincolors[setupm_fakecolor->color].name); + + return; // Don't draw anything after this + } + else // Draw color strip & the rest of the menu options { const INT32 numcolors = (282-charw)/(2*indexwidth); // Number of colors per side INT32 w = indexwidth; // Width of a singular color block menucolor_t *mc = setupm_fakecolor->prev; // Last accessed color - UINT8 h; INT16 i; + x = MP_PlayerSetupDef.x; + y += 75; + + // Draw color header & string + M_DrawLevelPlatterHeader(y - (lsheadingheight - 12), "Color...", true, false); + V_DrawRightAlignedString(BASEVIDWIDTH - x, y, + ((MP_PlayerSetupMenu[2].status & IT_TYPE) == IT_SPACE ? V_TRANSLUCENT : 0)|(itemOn == 2 ? V_YELLOWMAP : 0)|V_ALLOWLOWERCASE, + skincolors[setupm_fakecolor->color].name); + + // Draw horizontal arrows + if (itemOn == 2) + { + cursory = y; + if ((MP_PlayerSetupMenu[2].status & IT_TYPE) != IT_SPACE) + { + V_DrawCharacter(BASEVIDWIDTH - x - 10 - V_StringWidth(skincolors[setupm_fakecolor->color].name, V_ALLOWLOWERCASE) - (skullAnimCounter/5), y, + '\x1C' | V_YELLOWMAP, false); + V_DrawCharacter(BASEVIDWIDTH - x + 2 + (skullAnimCounter/5), y, + '\x1D' | V_YELLOWMAP, false); + } + } + // Draw color in the middle x += numcolors*w; - for (h = 0; h < 16; h++) - V_DrawFill(x, y+h, charw, 1, skincolors[setupm_fakecolor->color].ramp[h]); + y += 11; + M_DrawColorRamp(x, y, charw, 1, skincolors[setupm_fakecolor->color]); - //Draw colors from middle to left - for (i=0; i<numcolors; i++) { + // Draw colors from middle to left + for (i = 0; i < numcolors; i++) + { x -= w; - // Find accessible color before this one - while (!skincolors[mc->color].accessible) + while (!skincolors[mc->color].accessible) // Find accessible color before this one mc = mc->prev; - for (h = 0; h < 16; h++) - V_DrawFill(x, y+h, w, 1, skincolors[mc->color].ramp[h]); + M_DrawColorRamp(x, y, w, 1, skincolors[mc->color]); mc = mc->prev; } // Draw colors from middle to right mc = setupm_fakecolor->next; x += numcolors*w + charw; - for (i=0; i<numcolors; i++) { - // Find accessible color after this one - while (!skincolors[mc->color].accessible) + for (i = 0; i < numcolors; i++) + { + while (!skincolors[mc->color].accessible) // Find accessible color after this one mc = mc->next; - for (h = 0; h < 16; h++) - V_DrawFill(x, y+h, w, 1, skincolors[mc->color].ramp[h]); + M_DrawColorRamp(x, y, w, 1, skincolors[mc->color]); x += w; mc = mc->next; } @@ -12195,6 +12451,13 @@ colordraw: W_CachePatchName("M_CURSOR", PU_PATCH)); } +static void M_DrawColorRamp(INT32 x, INT32 y, INT32 w, INT32 h, skincolor_t color) +{ + UINT8 i; + for (i = 0; i < 16; i++) + V_DrawFill(x, y+(i*h), w, h, color.ramp[i]); +} + // Handle 1P/2P MP Setup static void M_HandleSetupMultiPlayer(INT32 choice) { @@ -12205,13 +12468,26 @@ static void M_HandleSetupMultiPlayer(INT32 choice) switch (choice) { case KEY_DOWNARROW: - M_NextOpt(); - S_StartSound(NULL,sfx_menu1); // Tails - break; - case KEY_UPARROW: - M_PrevOpt(); - S_StartSound(NULL,sfx_menu1); // Tails + { + if (itemOn == 2 && colorgrid) + { + UINT16 index = M_GetColorGridIndex(setupm_fakecolor->color); + INT32 x = M_GridIndexToX(index); + INT32 y = M_GridIndexToY(index); + + y += (choice == KEY_UPARROW) ? -1 : 1; + + index = M_GridPosToGridIndex(x, y); + setupm_fakecolor = M_GridIndexToMenuColor(index); + } + else if (choice == KEY_UPARROW) + M_PrevOpt(); + else + M_NextOpt(); + + S_StartSound(NULL,sfx_menu1); + } break; case KEY_LEFTARROW: @@ -12230,8 +12506,8 @@ static void M_HandleSetupMultiPlayer(INT32 choice) } else if (itemOn == 2) // player color { - S_StartSound(NULL,sfx_menu1); // Tails setupm_fakecolor = setupm_fakecolor->prev; + S_StartSound(NULL,sfx_menu1); // Tails } break; @@ -12246,6 +12522,13 @@ static void M_HandleSetupMultiPlayer(INT32 choice) COM_BufAddText (va("%s %d\n",setupm_cvdefaultcolor->name,setupm_fakecolor->color)); break; } + else if (itemOn == 2) + { + if (!colorgrid) + S_StartSound(NULL,sfx_menu1); + colorgrid = !colorgrid; + break; + } /* FALLTHRU */ case KEY_RIGHTARROW: if (itemOn == 1) //player skin @@ -12263,13 +12546,48 @@ static void M_HandleSetupMultiPlayer(INT32 choice) } else if (itemOn == 2) // player color { - S_StartSound(NULL,sfx_menu1); // Tails setupm_fakecolor = setupm_fakecolor->next; + S_StartSound(NULL,sfx_menu1); // Tails + } + break; + + case KEY_PGUP: + case KEY_PGDN: + { + UINT8 i; + if (itemOn == 2) // player color + { + if (colorgrid) + { + UINT16 index = M_GetColorGridIndex(setupm_fakecolor->color); + INT32 x = M_GridIndexToX(index); + INT32 y = M_GridIndexToY(index); + + y += (choice == KEY_UPARROW) ? -4 : 4; + + index = M_GridPosToGridIndex(x, y); + setupm_fakecolor = M_GridIndexToMenuColor(index); + } + else + { + for (i = 0; i < 13; i++) // or (282-charw)/(2*indexwidth) + { + setupm_fakecolor = (choice == KEY_PGUP) ? setupm_fakecolor->prev : setupm_fakecolor->next; + while (!skincolors[setupm_fakecolor->color].accessible) // skip inaccessible colors + setupm_fakecolor = (choice == KEY_PGUP) ? setupm_fakecolor->prev : setupm_fakecolor->next; + } + } + + S_StartSound(NULL, sfx_menu1); // Tails + } } break; case KEY_ESCAPE: - exitmenu = true; + if (itemOn == 2 && colorgrid) + colorgrid = false; + else + exitmenu = true; break; case KEY_BACKSPACE: @@ -12290,7 +12608,6 @@ static void M_HandleSetupMultiPlayer(INT32 choice) } } break; - break; case KEY_DEL: if (itemOn == 0 && (l = strlen(setupm_name))!=0) @@ -12300,6 +12617,14 @@ static void M_HandleSetupMultiPlayer(INT32 choice) } break; + case KEY_PAUSE: + multi_paused = !multi_paused; + break; + + case KEY_INS: + multi_invcolor = !multi_invcolor; + break; + default: if (itemOn != 0 || choice < 32 || choice > 127) break; @@ -12339,6 +12664,7 @@ static void M_SetupMultiPlayer(INT32 choice) multi_frame = 0; multi_tics = 4*FRACUNIT; + strcpy(setupm_name, cv_playername.string); // set for player 1 @@ -12383,6 +12709,7 @@ static void M_SetupMultiPlayer2(INT32 choice) multi_frame = 0; multi_tics = 4*FRACUNIT; + strcpy (setupm_name, cv_playername2.string); // set for splitscreen secondary player @@ -12579,6 +12906,42 @@ UINT16 M_GetColorAfter(UINT16 color) { } } +UINT16 M_GetColorIndex(UINT16 color) { + menucolor_t *look; + UINT16 i = 0; + + if (color >= numskincolors) { + CONS_Printf("M_GetColorIndex: color %d does not exist.\n",color); + return 0; + } + + for (look=menucolorhead;;look=look->next) { + if (look->color == color) + return i; + if (look==menucolortail) + return 0; + i++; + } +} + +menucolor_t* M_GetColorFromIndex(UINT16 index) { + menucolor_t *look = menucolorhead; + UINT16 i = 0; + + if (index >= numskincolors) { + CONS_Printf("M_GetColorIndex: index %d does not exist.\n",index); + return 0; + } + + for (i = 0; i <= index; i++) { + if (look==menucolortail) + return menucolorhead; + look=look->next; + } + + return look; +} + void M_InitPlayerSetupColors(void) { UINT8 i; numskincolors = SKINCOLOR_FIRSTFREESLOT; @@ -12980,12 +13343,12 @@ static void M_DrawControl(void) if (tutorialmode && tutorialgcs) { if ((gametic / TICRATE) % 2) - M_CentreText(30, "\202EXIT THE TUTORIAL TO CHANGE THE CONTROLS"); + V_DrawCenteredString(BASEVIDWIDTH/2, 30, 0, "\202EXIT THE TUTORIAL TO CHANGE THE CONTROLS"); else - M_CentreText(30, "EXIT THE TUTORIAL TO CHANGE THE CONTROLS"); + V_DrawCenteredString(BASEVIDWIDTH/2, 30, 0, "EXIT THE TUTORIAL TO CHANGE THE CONTROLS"); } else - M_CentreText(30, + V_DrawCenteredString(BASEVIDWIDTH/2, 30, 0, (setupcontrols_secondaryplayer ? "SET CONTROLS FOR SECONDARY PLAYER" : "PRESS ENTER TO CHANGE, BACKSPACE TO CLEAR")); @@ -13350,11 +13713,11 @@ static void M_DrawVideoMode(void) // draw title M_DrawMenuTitle(); - V_DrawCenteredString(BASEVIDWIDTH/2, OP_VideoModeDef.y, - V_YELLOWMAP, "Choose mode, reselect to change default"); + V_DrawCenteredString(BASEVIDWIDTH/2, OP_VideoModeDef.y, V_YELLOWMAP, "Choose mode, reselect to change default"); + V_DrawCenteredString(BASEVIDWIDTH/2, OP_VideoModeDef.y+8, V_YELLOWMAP, "Press F11 to toggle fullscreen"); row = 41; - col = OP_VideoModeDef.y + 14; + col = OP_VideoModeDef.y + 24; for (i = 0; i < vidm_nummodes; i++) { if (i == vidm_selected) @@ -13367,7 +13730,7 @@ static void M_DrawVideoMode(void) if ((i % vidm_column_size) == (vidm_column_size-1)) { row += 7*13; - col = OP_VideoModeDef.y + 14; + col = OP_VideoModeDef.y + 24; } } @@ -13375,28 +13738,34 @@ static void M_DrawVideoMode(void) { INT32 testtime = (vidm_testingmode/TICRATE) + 1; - M_CentreText(OP_VideoModeDef.y + 116, + V_DrawCenteredString(BASEVIDWIDTH/2, OP_VideoModeDef.y + 116, 0, va("Previewing mode %c%dx%d", (SCR_IsAspectCorrect(vid.width, vid.height)) ? 0x83 : 0x80, vid.width, vid.height)); - M_CentreText(OP_VideoModeDef.y + 138, + V_DrawCenteredString(BASEVIDWIDTH/2, OP_VideoModeDef.y + 138, 0, "Press ENTER again to keep this mode"); - M_CentreText(OP_VideoModeDef.y + 150, + V_DrawCenteredString(BASEVIDWIDTH/2, OP_VideoModeDef.y + 150, 0, va("Wait %d second%s", testtime, (testtime > 1) ? "s" : "")); - M_CentreText(OP_VideoModeDef.y + 158, + V_DrawCenteredString(BASEVIDWIDTH/2, OP_VideoModeDef.y + 158, 0, "or press ESC to return"); - } else { - M_CentreText(OP_VideoModeDef.y + 116, + V_DrawFill(60, OP_VideoModeDef.y + 98, 200, 12, 159); + V_DrawFill(60, OP_VideoModeDef.y + 114, 200, 20, 159); + + V_DrawCenteredString(BASEVIDWIDTH/2, OP_VideoModeDef.y + 100, 0, va("Current mode is %c%dx%d", (SCR_IsAspectCorrect(vid.width, vid.height)) ? 0x83 : 0x80, vid.width, vid.height)); - M_CentreText(OP_VideoModeDef.y + 124, + V_DrawCenteredString(BASEVIDWIDTH/2, OP_VideoModeDef.y + 116, (cv_fullscreen.value ? 0 : V_TRANSLUCENT), va("Default mode is %c%dx%d", - (SCR_IsAspectCorrect(cv_scr_width.value, cv_scr_height.value)) ? 0x83 : 0x80, + (SCR_IsAspectCorrect(cv_scr_width.value, cv_scr_height.value)) ? 0x83 : (!(VID_GetModeForSize(cv_scr_width.value, cv_scr_height.value)+1) ? 0x85 : 0x80), cv_scr_width.value, cv_scr_height.value)); + V_DrawCenteredString(BASEVIDWIDTH/2, OP_VideoModeDef.y + 124, (cv_fullscreen.value ? V_TRANSLUCENT : 0), + va("Windowed mode is %c%dx%d", + (SCR_IsAspectCorrect(cv_scr_width_w.value, cv_scr_height_w.value)) ? 0x83 : (!(VID_GetModeForSize(cv_scr_width_w.value, cv_scr_height_w.value)+1) ? 0x85 : 0x80), + cv_scr_width_w.value, cv_scr_height_w.value)); V_DrawCenteredString(BASEVIDWIDTH/2, OP_VideoModeDef.y + 138, V_GREENMAP, "Green modes are recommended."); @@ -13408,7 +13777,7 @@ static void M_DrawVideoMode(void) // Draw the cursor for the VidMode menu i = 41 - 10 + ((vidm_selected / vidm_column_size)*7*13); - j = OP_VideoModeDef.y + 14 + ((vidm_selected % vidm_column_size)*8); + j = OP_VideoModeDef.y + 24 + ((vidm_selected % vidm_column_size)*8); V_DrawScaledPatch(i - 8, j, 0, W_CachePatchName("M_CURSOR", PU_PATCH)); @@ -13591,11 +13960,14 @@ static void M_HandleVideoMode(INT32 ch) break; case KEY_ENTER: - S_StartSound(NULL, sfx_menu1); if (vid.modenum == modedescs[vidm_selected].modenum) + { + S_StartSound(NULL, sfx_strpst); SCR_SetDefaultMode(); + } else { + S_StartSound(NULL, sfx_menu1); vidm_testingmode = 15*TICRATE; vidm_previousmode = vid.modenum; if (!setmodeneeded) // in case the previous setmode was not finished @@ -13610,6 +13982,27 @@ static void M_HandleVideoMode(INT32 ch) M_ClearMenus(true); break; + case KEY_BACKSPACE: + S_StartSound(NULL, sfx_menu1); + CV_Set(&cv_scr_width, cv_scr_width.defaultvalue); + CV_Set(&cv_scr_height, cv_scr_height.defaultvalue); + CV_Set(&cv_scr_width_w, cv_scr_width_w.defaultvalue); + CV_Set(&cv_scr_height_w, cv_scr_height_w.defaultvalue); + if (cv_fullscreen.value) + setmodeneeded = VID_GetModeForSize(cv_scr_width.value, cv_scr_height.value)+1; + else + setmodeneeded = VID_GetModeForSize(cv_scr_width_w.value, cv_scr_height_w.value)+1; + break; + + case KEY_F10: // Renderer toggle, also processed inside menus + CV_AddValue(&cv_renderer, 1); + break; + + case KEY_F11: + S_StartSound(NULL, sfx_menu1); + CV_SetValue(&cv_fullscreen, !cv_fullscreen.value); + break; + default: break; } diff --git a/src/m_menu.h b/src/m_menu.h index 35c77cc438a8c295c3d86d5caa5b127548cc0df8..c925c7f49c775d4a6e0becd7e2c5eb03d60784e4 100644 --- a/src/m_menu.h +++ b/src/m_menu.h @@ -482,6 +482,8 @@ void M_MoveColorBefore(UINT16 color, UINT16 targ); void M_MoveColorAfter(UINT16 color, UINT16 targ); UINT16 M_GetColorBefore(UINT16 color); UINT16 M_GetColorAfter(UINT16 color); +UINT16 M_GetColorIndex(UINT16 color); +menucolor_t* M_GetColorFromIndex(UINT16 index); void M_InitPlayerSetupColors(void); void M_FreePlayerSetupColors(void); diff --git a/src/m_misc.c b/src/m_misc.c index c24896600e1b69533073c2bee6433d3988ae98c4..f547f5c41ac8fb0fea405f8ed760ffe4070fdeb2 100644 --- a/src/m_misc.c +++ b/src/m_misc.c @@ -63,7 +63,7 @@ typedef off_t off64_t; #if defined(__MINGW32__) && ((__GNUC__ > 7) || (__GNUC__ == 6 && __GNUC_MINOR__ >= 3)) && (__GNUC__ < 8) #define PRIdS "u" -#elif defined (_WIN32) +#elif defined(_WIN32) && !defined(__MINGW64__) #define PRIdS "Iu" #else #define PRIdS "zu" diff --git a/src/m_random.c b/src/m_random.c index 8b5138b9c86f77e6fa4a0d0867e4e62198fb2dca..536fbfbbd1077abf6ae400bd4d8773a7574e4b08 100644 --- a/src/m_random.c +++ b/src/m_random.c @@ -3,6 +3,7 @@ // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. // Copyright (C) 2012-2016 by Matthew "Kaito Sinclaire" Walsh. +// Copyright (C) 2022-2023 by tertu marybig. // Copyright (C) 1999-2023 by Sonic Team Junior. // // This program is free software distributed under the @@ -14,11 +15,122 @@ #include "doomdef.h" #include "doomtype.h" +#include "i_system.h" // I_GetRandomBytes #include "m_random.h" #include "m_fixed.h" -#include "m_cond.h" // totalplaytime +// SFC32 random number generator implementation + +typedef struct rnstate_s { + UINT32 data[3]; + UINT32 counter; +} rnstate_t; + +/** Generate a raw uniform random number using a particular state. + * + * \param state The RNG state to use. + * \return A random UINT32. + */ +static inline UINT32 RandomState_Get32(rnstate_t *state) { + UINT32 result, b, c; + + b = state->data[1]; + c = state->data[2]; + result = state->data[0] + b + state->counter++; + + state->data[0] = b ^ (b >> 9); + state->data[1] = c * 9; + state->data[2] = ((c << 21) | (c >> 11)) + result; + + return result; +} + +/** Seed an SFC32 RNG state with up to 96 bits of seed data. + * + * \param state The RNG state to seed. + * \param seeds A pointer to up to 3 UINT32s to use as seed data. + * \param seed_count The number of seed words. + */ +static inline void RandomState_Seed(rnstate_t *state, UINT32 *seeds, size_t seed_count) +{ + size_t i; + + state->counter = 1; + + for(i = 0; i < 3; i++) + { + UINT32 seed_word; + + if(i < seed_count) + seed_word = seeds[i]; + else + seed_word = 0; + + // For SFC32, seed data should be stored in the state in reverse order. + state->data[2-i] = seed_word; + } + + for(i = 0; i < 16; i++) + RandomState_Get32(state); +} + +/** Gets a uniform number in the range [0, limit). + * Technique is based on a combination of scaling and rejection sampling + * and is adapted from Daniel Lemire. + * + * \note Any UINT32 is a valid argument for limit. + * + * \param state The RNG state to use. + * \param limit The upper limit of the range. + * \return A UINT32 in the range [0, limit). + */ +static inline UINT32 RandomState_GetKey32(rnstate_t *state, const UINT32 limit) +{ + UINT32 raw_random, scaled_lower_word; + UINT64 scaled_random; + + // This algorithm won't work correctly if passed a 0. + if (limit == 0) return 0; + + raw_random = RandomState_Get32(state); + scaled_random = (UINT64)raw_random * (UINT64)limit; + + /*The high bits of scaled_random now contain the number we want, but it is + possible, depending on the number we generated and the value of limit, + that there is bias in the result. The rest of this code is for ensuring + that does not happen. + */ + scaled_lower_word = (UINT32)scaled_random; + + // If we're lucky, we can bail out now and avoid the division + if (scaled_lower_word < limit) + { + // Scale the limit to improve the chance of success. + // After this, the first result might turn out to be good enough. + UINT32 scaled_limit; + // An explanation for this trick: scaled_limit should be + // (UINT32_MAX+1)%range, but if that was computed directly the result + // would need to be computed as a UINT64. This trick allows it to be + // computed using 32-bit arithmetic. + scaled_limit = (-limit) % limit; + + while (scaled_lower_word < scaled_limit) + { + raw_random = RandomState_Get32(state); + scaled_random = (UINT64)raw_random * (UINT64)limit; + scaled_lower_word = (UINT32)scaled_random; + } + } + + return scaled_random >> 32; +} + +// The default seed is the hexadecimal digits of pi, though it will be overwritten. +static rnstate_t m_randomstate = { + .data = {0x4A3B6035U, 0x99555606U, 0x6F603421U}, + .counter = 16 +}; // --------------------------- // RNG functions (not synched) @@ -31,13 +143,7 @@ */ fixed_t M_RandomFixed(void) { -#if RAND_MAX < 65535 - // Compensate for insufficient randomness. - fixed_t rndv = (rand()&1)<<15; - return rand()^rndv; -#else - return (rand() & 0xFFFF); -#endif + return RandomState_Get32(&m_randomstate) >> (32-FRACBITS); } /** Provides a random byte. Distribution is uniform. @@ -47,7 +153,7 @@ fixed_t M_RandomFixed(void) */ UINT8 M_RandomByte(void) { - return (rand() & 0xFF); + return RandomState_Get32(&m_randomstate) >> 24; } /** Provides a random integer for picking random elements from an array. @@ -59,7 +165,22 @@ UINT8 M_RandomByte(void) */ INT32 M_RandomKey(INT32 a) { - return (INT32)((rand()/((float)RAND_MAX+1.0f))*a); + boolean range_is_negative; + INT64 range; + INT32 random_result; + + range = a; + range_is_negative = range < 0; + + if(range_is_negative) + range = -range; + + random_result = RandomState_GetKey32(&m_randomstate, (UINT32)range); + + if(range_is_negative) + random_result = -random_result; + + return random_result; } /** Provides a random integer in a given range. @@ -72,7 +193,46 @@ INT32 M_RandomKey(INT32 a) */ INT32 M_RandomRange(INT32 a, INT32 b) { - return (INT32)((rand()/((float)RAND_MAX+1.0f))*(b-a+1))+a; + if (b < a) + { + INT32 temp; + + temp = a; + a = b; + b = temp; + } + + const UINT32 spread = b-a+1; + return (INT32)((INT64)RandomState_GetKey32(&m_randomstate, spread) + a); +} + +/** Attempts to seed the unsynched RNG from a good random number source + * provided by the operating system. + * \return true on success, false on failure. + */ +boolean M_RandomSeedFromOS(void) +{ + UINT32 complete_word_count; + + union { + UINT32 words[3]; + char bytes[sizeof(UINT32[3])]; + } seed_data; + + complete_word_count = I_GetRandomBytes((char *)&seed_data.bytes, sizeof(seed_data)) / sizeof(UINT32); + + // If we get even 1 word of seed, it's fine, but any less probably is not fine. + if (complete_word_count == 0) + return false; + + RandomState_Seed(&m_randomstate, (UINT32 *)&seed_data.words, complete_word_count); + + return true; +} + +void M_RandomSeed(UINT32 seed) +{ + RandomState_Seed(&m_randomstate, &seed, 1); } @@ -246,10 +406,18 @@ void P_SetRandSeedD(const char *rfile, INT32 rline, UINT32 seed) } /** Gets a randomized seed for setting the random seed. + * This function will never return 0, as the current P_Random implementation + * cannot handle a zero seed. Any other seed is equally likely. * * \sa P_GetRandSeed */ UINT32 M_RandomizedSeed(void) { - return ((serverGamedata->totalplaytime & 0xFFFF) << 16) | M_RandomFixed(); + UINT32 seed; + + do { + seed = RandomState_Get32(&m_randomstate); + } while(seed == 0); + + return seed; } diff --git a/src/m_random.h b/src/m_random.h index 824287e27d486906c60d976e60817cb5ac9ffb73..a7c07a46b5e2c951548d67f409287e80345c20dd 100644 --- a/src/m_random.h +++ b/src/m_random.h @@ -3,6 +3,7 @@ // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. // Copyright (C) 2012-2016 by Matthew "Kaito Sinclaire" Walsh. +// Copyright (C) 2022-2023 by tertu marybig. // Copyright (C) 1999-2023 by Sonic Team Junior. // // This program is free software distributed under the @@ -29,6 +30,8 @@ fixed_t M_RandomFixed(void); UINT8 M_RandomByte(void); INT32 M_RandomKey(INT32 a); INT32 M_RandomRange(INT32 a, INT32 b); +boolean M_RandomSeedFromOS(void); +void M_RandomSeed(UINT32 a); // PRNG functions #ifdef DEBUGRANDOM diff --git a/src/p5prof.h b/src/p5prof.h deleted file mode 100644 index a9ed3965e9691f9931cd360da7cc41efc2ee5c55..0000000000000000000000000000000000000000 --- a/src/p5prof.h +++ /dev/null @@ -1,278 +0,0 @@ -/********************************************************* - * - * File: p5prof.h - * By: Kevin Baca - * - * MODIFIED BY Fab SO THAT RDMSR(...) WRITES EDX : EAX TO A LONG LONG - * (WHICH MEANS WRITE THE LOW DWORD FIRST) - * - * Now in yer code do: - * INT64 count,total; - * - * ... - * RDMSR(0x10,&count); //inner loop count - * total += count; - * ... - * - * printf("0x%x %x", (INT32)total, *((INT32 *)&total+1)); - * // HIGH LOW - * - *********************************************************/ -/**\file - \brief This file provides macros to profile your code. - - Here's how they work... - - As you may or may not know, the Pentium class of - processors provides extremely fine grained profiling - capabilities through the use of what are called - Machine Specific Registers (MSRs). These registers - can provide information about almost any aspect of - CPU performance down to a single cycle. - - The MSRs of interest for profiling are specified by - indices 0x10, 0x11, 0x12, and 0x13. Here is a brief - description of each of these registers: - - MSR 0x10 - This register is simple a cycle counter. - - MSR 0x11 - This register controls what type of profiling data - will be gathered. - - MSRs 0x12 and 0x13 - These registers gather the profiling data specified in - MSR 0x11. - - Each MSR is 64 bits wide. For the Pentium processor, - only the lower 32 bits of MSR 0x11 are valid. Bits 0-15 - specify what data will be gathered in MSR 0x12. Bits 16-31 - specify what data will be gathered in MSR 0x13. Both sets - of bits have the same format: - - Bits 0-5 specify which hardware event will be tracked. - Bit 6, if set, indicates events will be tracked in - rings 0-2. - Bit 7, if set, indicates events will be tracked in - ring 3. - Bit 8, if set, indicates cycles should be counted for - the specified event. If clear, it indicates the - number of events should be counted. - - Two instructions are provided for manupulating the MSRs. - RDMSR (Read Machine Specific Register) and WRMSR - (Write Machine Specific Register). These opcodes were - originally undocumented and therefore most assemblers don't - recognize them. Their byte codes are provided in the - macros below. - - RDMSR takes the MSR index in ecx and the profiling criteria - in edx : eax. - - WRMSR takes the MSR index in ecx and returns the profile data - in edx : eax. - - Two profiling registers limits profiling capability to - gathering only two types of information. The register - usage can, however, be combined in interesting ways. - For example, you can set one register to gather the - number of a specific type of event while the other gathers - the number of cycles for the same event. Or you can - gather the number of two separate events while using - MSR 0x10 to gather the number of cycles. - - The enumerated list provides somewhat readable labels for - the types of events that can be tracked. - - For more information, get ahold of appendix H from the - Intel Pentium programmer's manual (I don't remember the - order number) or go to - http://green.kaist.ac.kr/jwhahn/art3.htm. - That's an article by Terje Mathisen where I got most of - my information. - - You may use this code however you wish. I hope it's - useful and I hope I got everything right. - - -Kevin - - kbaca@skygames.com - -*/ - -#ifdef __GNUC__ - -#define RDTSC(_dst) \ -__asm__(" - .byte 0x0F,0x31 - movl %%edx,(%%edi) - movl %%eax,4(%%edi)"\ -: : "D" (_dst) : "eax", "edx", "edi") - -// the old code... swapped it -// movl %%edx,(%%edi) -// movl %%eax,4(%%edi)" -#define RDMSR(_msri, _msrd) \ -__asm__(" - .byte 0x0F,0x32 - movl %%eax,(%%edi) - movl %%edx,4(%%edi)"\ -: : "c" (_msri), "D" (_msrd) : "eax", "ecx", "edx", "edi") - -#define WRMSR(_msri, _msrd) \ -__asm__(" - xorl %%edx,%%edx - .byte 0x0F,0x30"\ -: : "c" (_msri), "a" (_msrd) : "eax", "ecx", "edx") - -#define RDMSR_0x12_0x13(_msr12, _msr13) \ -__asm__(" - movl $0x12,%%ecx - .byte 0x0F,0x32 - movl %%edx,(%%edi) - movl %%eax,4(%%edi) - movl $0x13,%%ecx - .byte 0x0F,0x32 - movl %%edx,(%%esi) - movl %%eax,4(%%esi)"\ -: : "D" (_msr12), "S" (_msr13) : "eax", "ecx", "edx", "edi") - -#define ZERO_MSR_0x12_0x13() \ -__asm__(" - xorl %%edx,%%edx - xorl %%eax,%%eax - movl $0x12,%%ecx - .byte 0x0F,0x30 - movl $0x13,%%ecx - .byte 0x0F,0x30"\ -: : : "eax", "ecx", "edx") - -#elif defined (__WATCOMC__) - -extern void RDTSC(UINT32 *dst); -#pragma aux RDTSC =\ - "db 0x0F,0x31"\ - "mov [edi],edx"\ - "mov [4+edi],eax"\ - parm [edi]\ - modify [eax edx edi]; - -extern void RDMSR(UINT32 msri, UINT32 *msrd); -#pragma aux RDMSR =\ - "db 0x0F,0x32"\ - "mov [edi],edx"\ - "mov [4+edi],eax"\ - parm [ecx] [edi]\ - modify [eax ecx edx edi]; - -extern void WRMSR(UINT32 msri, UINT32 msrd); -#pragma aux WRMSR =\ - "xor edx,edx"\ - "db 0x0F,0x30"\ - parm [ecx] [eax]\ - modify [eax ecx edx]; - -extern void RDMSR_0x12_0x13(UINT32 *msr12, UINT32 *msr13); -#pragma aux RDMSR_0x12_0x13 =\ - "mov ecx,0x12"\ - "db 0x0F,0x32"\ - "mov [edi],edx"\ - "mov [4+edi],eax"\ - "mov ecx,0x13"\ - "db 0x0F,0x32"\ - "mov [esi],edx"\ - "mov [4+esi],eax"\ - parm [edi] [esi]\ - modify [eax ecx edx edi esi]; - -extern void ZERO_MSR_0x12_0x13(void); -#pragma aux ZERO_MSR_0x12_0x13 =\ - "xor edx,edx"\ - "xor eax,eax"\ - "mov ecx,0x12"\ - "db 0x0F,0x30"\ - "mov ecx,0x13"\ - "db 0x0F,0x30"\ - modify [eax ecx edx]; - -#endif - -typedef enum -{ - DataRead, - DataWrite, - DataTLBMiss, - DataReadMiss, - DataWriteMiss, - WriteHitEM, - DataCacheLinesWritten, - DataCacheSnoops, - DataCacheSnoopHit, - MemAccessBothPipes, - BankConflict, - MisalignedDataRef, - CodeRead, - CodeTLBMiss, - CodeCacheMiss, - SegRegLoad, - RESERVED0, - RESERVED1, - Branch, - BTBHit, - TakenBranchOrBTBHit, - PipelineFlush, - InstructionsExeced, - InstructionsExecedVPipe, - BusUtilizationClocks, - PipelineStalledWriteBackup, - PipelineStalledDateMemRead, - PipeLineStalledWriteEM, - LockedBusCycle, - IOReadOrWriteCycle, - NonCacheableMemRef, - AGI, - RESERVED2, - RESERVED3, - FPOperation, - Breakpoint0Match, - Breakpoint1Match, - Breakpoint2Match, - Breakpoint3Match, - HWInterrupt, - DataReadOrWrite, - DataReadOrWriteMiss -}; - -#define PROF_CYCLES (0x100) -#define PROF_EVENTS (0x000) -#define RING_012 (0x40) -#define RING_3 (0x80) -#define RING_0123 (RING_012 | RING_3) - -/*void ProfSetProfiles(UINT32 msr12, UINT32 msr13);*/ -#define ProfSetProfiles(_msr12, _msr13)\ -{\ - UINT32 prof;\ -\ - prof = (_msr12) | ((_msr13) << 16);\ - WRMSR(0x11, prof);\ -} - -/*void ProfBeginProfiles(void);*/ -#define ProfBeginProfiles()\ - ZERO_MSR_0x12_0x13(); - -/*void ProfGetProfiles(UINT32 msr12[2], UINT32 msr13[2]);*/ -#define ProfGetProfiles(_msr12, _msr13)\ - RDMSR_0x12_0x13(_msr12, _msr13); - -/*void ProfZeroTimer(void);*/ -#define ProfZeroTimer()\ - WRMSR(0x10, 0); - -/*void ProfReadTimer(UINT32 timer[2]);*/ -#define ProfReadTimer(timer)\ - RDMSR(0x10, timer); - -/*EOF*/ diff --git a/src/p_enemy.c b/src/p_enemy.c index c7d87b88ada52c2ab1c45c947431f0a984243d20..eebb65f3cb146f229183b014acdc89e0042f8da2 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -174,6 +174,7 @@ void A_Boss1Spikeballs(mobj_t *actor); void A_Boss3TakeDamage(mobj_t *actor); void A_Boss3Path(mobj_t *actor); void A_Boss3ShockThink(mobj_t *actor); +void A_Shockwave(mobj_t *actor); void A_LinedefExecute(mobj_t *actor); void A_LinedefExecuteFromArg(mobj_t *actor); void A_PlaySeeSound(mobj_t *actor); @@ -828,7 +829,7 @@ static boolean P_LookForShield(mobj_t *actor) continue; if ((player->powers[pw_shield] & SH_PROTECTELECTRIC) - && (P_AproxDistance(P_AproxDistance(actor->x-player->mo->x, actor->y-player->mo->y), actor->z-player->mo->z) < FixedMul(RING_DIST, player->mo->scale))) + && (R_PointToDist2(0, 0, R_PointToDist2(0, 0, actor->x-player->mo->x, actor->y-player->mo->y), actor->z-player->mo->z) < FixedMul(RING_DIST, player->mo->scale))) { P_SetTarget(&actor->tracer, player->mo); @@ -3938,7 +3939,7 @@ static void P_DoBossVictory(mobj_t *mo) } // victory! - if (mo->spawnpoint) + if (mo->spawnpoint && mo->spawnpoint->args[3]) P_LinedefExecute(mo->spawnpoint->args[3], mo, NULL); if (stoppedclock && modeattacking) // if you're just time attacking, skip making the capsule appear since you don't need to step on it anyways. @@ -4157,7 +4158,7 @@ void A_BossDeath(mobj_t *mo) if (LUA_CallAction(A_BOSSDEATH, mo)) return; - if (mo->spawnpoint) + if (mo->spawnpoint && mo->spawnpoint->args[2]) P_LinedefExecute(mo->spawnpoint->args[2], mo, NULL); mo->health = 0; @@ -4886,7 +4887,9 @@ void A_FishJump(mobj_t *actor) jumpval = locvar1; else { - if (actor->spawnpoint && actor->spawnpoint->args[0]) + if (!udmf && actor->angle) + jumpval = AngleFixed(actor->angle)>>2; + else if (actor->spawnpoint && actor->spawnpoint->args[0]) jumpval = actor->spawnpoint->args[0] << (FRACBITS - 2); else jumpval = 44 << (FRACBITS - 2); @@ -5321,7 +5324,7 @@ void A_SignPlayer(mobj_t *actor) actor->tracer->color = signcolor; if (signcolor && signcolor < numskincolors) - signframe += (15 - skincolors[skincolors[signcolor].invcolor].invshade); + signframe += (15 - skincolors[facecolor].invshade); actor->tracer->frame = signframe; } @@ -7136,7 +7139,7 @@ void A_Boss1Chase(mobj_t *actor) } else { - if (actor->spawnpoint) + if (actor->spawnpoint && actor->spawnpoint->args[4]) P_LinedefExecute(actor->spawnpoint->args[4], actor, NULL); P_SetMobjState(actor, actor->info->raisestate); } @@ -8377,6 +8380,56 @@ void A_Boss3ShockThink(mobj_t *actor) } } +// Function: A_Shockwave +// +// Description: Spawns a shockwave of objects. Best used to spawn objects that call A_Boss3ShockThink. +// +// var1 = object spawned +// var2 = amount of objects spawned +// +void A_Shockwave(mobj_t *actor) +{ + INT32 locvar1 = var1; + INT32 locvar2 = var2; + INT32 i; + + angle_t ang = 0, interval; + mobj_t *shock = NULL, *sfirst = NULL, *sprev = NULL; + + if (LUA_CallAction(A_SHOCKWAVE, actor)) + return; + + if (locvar2 == 0) + locvar2 = 24; // a sensible default, just in case + + interval = FixedAngle((360 << FRACBITS) / locvar2); + + for (i = 0; i < locvar2; i++) + { + shock = P_SpawnMobj(actor->x, actor->y, actor->z, locvar1); + P_SetTarget(&shock->target, actor); + shock->fuse = shock->info->painchance; + + if (i % 2 == 0) + P_SetMobjState(shock, shock->state->nextstate); + + if (!sprev) + sfirst = shock; + else + { + if (i == locvar2 - 1) + P_SetTarget(&shock->hnext, sfirst); + P_SetTarget(&sprev->hnext, shock); + } + + P_Thrust(shock, ang, shock->info->speed); + ang += interval; + sprev = shock; + } + + S_StartSound(actor, shock->info->seesound); +} + // Function: A_LinedefExecute // // Description: Object's location is used to set the calling sector. The tag used is var1. Optionally, if var2 is set, the actor's angle (multiplied by var2) is added to the tag number as well. @@ -8685,10 +8738,10 @@ void A_RollAngle(mobj_t *actor) // relative (default) if (!locvar2) - actor->rollangle += angle; + actor->spriteroll += angle; // absolute else - actor->rollangle = angle; + actor->spriteroll = angle; } // Function: A_ChangeRollAngleRelative @@ -8713,7 +8766,7 @@ void A_ChangeRollAngleRelative(mobj_t *actor) I_Error("A_ChangeRollAngleRelative: var1 is greater than var2"); #endif - actor->rollangle += FixedAngle(P_RandomRange(amin, amax)); + actor->spriteroll += FixedAngle(P_RandomRange(amin, amax)); } // Function: A_ChangeRollAngleAbsolute @@ -8738,7 +8791,7 @@ void A_ChangeRollAngleAbsolute(mobj_t *actor) I_Error("A_ChangeRollAngleAbsolute: var1 is greater than var2"); #endif - actor->rollangle = FixedAngle(P_RandomRange(amin, amax)); + actor->spriteroll = FixedAngle(P_RandomRange(amin, amax)); } // Function: A_PlaySound @@ -12583,8 +12636,7 @@ void A_MineRange(mobj_t *actor) void A_ConnectToGround(mobj_t *actor) { mobj_t *work; - fixed_t workz; - fixed_t workh; + fixed_t endz; angle_t ang; INT32 locvar1 = var1; INT32 locvar2 = var2; @@ -12595,38 +12647,42 @@ void A_ConnectToGround(mobj_t *actor) if (actor->subsector->sector->ffloors) P_AdjustMobjFloorZ_FFloors(actor, actor->subsector->sector, 2); + endz = actor->z; if (actor->flags2 & MF2_OBJECTFLIP) - workz = (actor->z + actor->height) - actor->ceilingz; + actor->z = actor->ceilingz - actor->height; // Ensures perfect ceiling connection else - workz = actor->floorz - actor->z; + actor->z = actor->floorz; // Ensures perfect floor connection if (locvar2) { - workh = FixedMul(mobjinfo[locvar2].height, actor->scale); - if (actor->flags2 & MF2_OBJECTFLIP) - workz += workh; - work = P_SpawnMobjFromMobj(actor, 0, 0, workz, locvar2); - workz += workh; - } + work = P_SpawnMobjFromMobj(actor, 0, 0, 0, locvar2); + if (work) + work->old_z = work->z; // Don't copy old_z from the actor - if (!locvar1) - return; + actor->z += P_MobjFlip(actor) * FixedMul(mobjinfo[locvar2].height, actor->scale); + } - if (!(workh = FixedMul(mobjinfo[locvar1].height, actor->scale))) + if (!locvar1 || !mobjinfo[locvar1].height) // Can't tile the middle object? + { + actor->z = endz; return; + } ang = actor->angle + ANGLE_45; - while (workz < 0) + while ((actor->flags2 & MF2_OBJECTFLIP) ? (actor->z > endz) : (actor->z < endz)) { - work = P_SpawnMobjFromMobj(actor, 0, 0, workz, locvar1); + work = P_SpawnMobjFromMobj(actor, 0, 0, 0, locvar1); if (work) - work->angle = ang; + { + work->angle = work->old_angle = ang; + work->old_z = work->z; // Don't copy old_z from the actor + } + ang += ANGLE_90; - workz += workh; + actor->z += P_MobjFlip(actor) * FixedMul(mobjinfo[locvar1].height, actor->scale); } - if (workz != 0) - actor->z += P_MobjFlip(actor)*workz; + actor->old_z = actor->z; // Reset Z interpolation - the spawned objects intentionally don't have any Z interpolation either, after all } // Function: A_SpawnParticleRelative diff --git a/src/p_floor.c b/src/p_floor.c index 9c24f585141f3223c223c902f80fbba21896c4f3..38f0c5a0fbc496564e7b69c96f7cacd8a93287f6 100644 --- a/src/p_floor.c +++ b/src/p_floor.c @@ -155,7 +155,7 @@ result_e T_MovePlane(sector_t *sector, fixed_t speed, fixed_t dest, boolean crus } } - return ok; + return planeok; } // @@ -1128,7 +1128,7 @@ void T_ThwompSector(thwomp_t *thwomp) thwomp->direction // direction ); - if (res == ok || res == pastdest) + if (res == planeok || res == pastdest) T_MovePlane ( thwomp->sector, // sector @@ -1160,7 +1160,7 @@ void T_ThwompSector(thwomp_t *thwomp) thwomp->direction // direction ); - if (res == ok || res == pastdest) + if (res == planeok || res == pastdest) T_MovePlane ( thwomp->sector, // sector @@ -1465,7 +1465,7 @@ void T_RaiseSector(raise_t *raise) direction // direction ); - if (res == ok || res == pastdest) + if (res == planeok || res == pastdest) T_MovePlane ( raise->sector, // sector diff --git a/src/p_inter.c b/src/p_inter.c index 046a0a198ef4df08727b33b90b69d38596c9fc3e..271b6ebc45a5bf42d048b39ace8db61d212741c8 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -255,42 +255,19 @@ void P_DoNightsScore(player_t *player) player->linktimer = nightslinktics; } - if (player->linkcount < 10) - { - if (player->bonustime) - { - P_AddPlayerScore(player, player->linkcount*20); - P_SetMobjState(dummymo, dummymo->info->xdeathstate+player->linkcount-1); - } - else - { - P_AddPlayerScore(player, player->linkcount*10); - P_SetMobjState(dummymo, dummymo->info->spawnstate+player->linkcount-1); - } - } - else - { - if (player->bonustime) - { - P_AddPlayerScore(player, 200); - P_SetMobjState(dummymo, dummymo->info->xdeathstate+9); - } - else - { - P_AddPlayerScore(player, 100); - P_SetMobjState(dummymo, dummymo->info->spawnstate+9); - } - } + // Award 10-100 score, doubled if bonus time is active + P_AddPlayerScore(player, min(player->linkcount,10)*(player->bonustime ? 20 : 10)); + P_SetMobjState(dummymo, (player->bonustime ? dummymo->info->xdeathstate : dummymo->info->spawnstate) + min(player->linkcount,10)-1); - // Hoops are the only things that should add to your drill meter - //player->drillmeter += TICRATE; + // Make objects slowly rise & scale up dummymo->momz = FRACUNIT; dummymo->fuse = 3*TICRATE; - - // What?! NO, don't use the camera! Scale up instead! - //P_InstaThrust(dummymo, R_PointToAngle2(dummymo->x, dummymo->y, camera.x, camera.y), 3*FRACUNIT); dummymo->scalespeed = FRACUNIT/25; dummymo->destscale = 2*FRACUNIT; + + // Add extra values used for color variety + dummymo->extravalue1 = player->linkcount-1; + dummymo->extravalue2 = ((player->linkcount-1 >= 300) ? (player->linkcount-1 >= 600) ? 2 : 1 : 0); } // @@ -521,23 +498,20 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) if (special->type == MT_PTERABYTE && special->target == player->mo && special->extravalue1 == 1) return; // Can't hurt a Pterabyte if it's trying to pick you up - if ((P_MobjFlip(toucher)*toucher->momz < 0) && (elementalpierce != 1)) + if ((P_MobjFlip(toucher)*toucher->momz < 0) && (elementalpierce != 1) && (!(player->powers[pw_strong] & STR_HEAVY))) { - if (!(player->charability2 == CA2_MELEE && player->panim == PA_ABILITY2)) + fixed_t setmomz = -toucher->momz; // Store this, momz get changed by P_DoJump within P_DoBubbleBounce + + if (elementalpierce == 2) // Reset bubblewrap, part 1 + P_DoBubbleBounce(player); + toucher->momz = setmomz; + if (elementalpierce == 2) // Reset bubblewrap, part 2 { - fixed_t setmomz = -toucher->momz; // Store this, momz get changed by P_DoJump within P_DoBubbleBounce - - if (elementalpierce == 2) // Reset bubblewrap, part 1 - P_DoBubbleBounce(player); - toucher->momz = setmomz; - if (elementalpierce == 2) // Reset bubblewrap, part 2 - { - boolean underwater = toucher->eflags & MFE_UNDERWATER; - - if (underwater) - toucher->momz /= 2; - toucher->momz -= (toucher->momz/(underwater ? 8 : 4)); // Cap the height! - } + boolean underwater = toucher->eflags & MFE_UNDERWATER; + + if (underwater) + toucher->momz /= 2; + toucher->momz -= (toucher->momz/(underwater ? 8 : 4)); // Cap the height! } } if (player->pflags & PF_BOUNCING) @@ -556,8 +530,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) toucher->momx = 7*toucher->momx>>3; toucher->momy = 7*toucher->momy>>3; } - else if (player->dashmode >= DASHMODE_THRESHOLD && (player->charflags & (SF_DASHMODE|SF_MACHINE)) == (SF_DASHMODE|SF_MACHINE) - && player->panim == PA_DASH) + else if ((player->powers[pw_strong] & STR_DASH) && player->panim == PA_DASH) P_DoPlayerPain(player, special, special); } P_DamageMobj(special, toucher, toucher, 1, 0); @@ -1171,7 +1144,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) if (!(mo2->type == MT_RING || mo2->type == MT_COIN || mo2->type == MT_BLUESPHERE || mo2->type == MT_BOMBSPHERE || mo2->type == MT_NIGHTSCHIP || mo2->type == MT_NIGHTSSTAR - || ((mo2->type == MT_EMBLEM) && (mo2->reactiontime & GE_NIGHTSPULL)))) + || ((mo2->type == MT_EMBLEM) && (mo2->reactiontime & GE_NIGHTSPULL) && P_CanPickupEmblem(player, mo2->health - 1) && !P_EmblemWasCollected(mo2->health - 1)))) continue; // Yay! The thing's in reach! Pull it in! @@ -2262,7 +2235,7 @@ void P_CheckTimeLimit(void) } if (server) - SendNetXCmd(XD_EXITLEVEL, NULL, 0); + D_SendExitLevel(false); } //Optional tie-breaker for Match/CTF @@ -2325,11 +2298,11 @@ void P_CheckTimeLimit(void) } } if (server) - SendNetXCmd(XD_EXITLEVEL, NULL, 0); + D_SendExitLevel(false); } if (server) - SendNetXCmd(XD_EXITLEVEL, NULL, 0); + D_SendExitLevel(false); } /** Checks if a player's score is over the pointlimit and the round should end. @@ -2358,7 +2331,7 @@ void P_CheckPointLimit(void) if ((UINT32)cv_pointlimit.value <= redscore || (UINT32)cv_pointlimit.value <= bluescore) { if (server) - SendNetXCmd(XD_EXITLEVEL, NULL, 0); + D_SendExitLevel(false); } } else @@ -2371,7 +2344,7 @@ void P_CheckPointLimit(void) if ((UINT32)cv_pointlimit.value <= players[i].score) { if (server) - SendNetXCmd(XD_EXITLEVEL, NULL, 0); + D_SendExitLevel(false); return; } } @@ -2415,7 +2388,7 @@ void P_CheckSurvivors(void) { CONS_Printf(M_GetText("The IT player has left the game.\n")); if (server) - SendNetXCmd(XD_EXITLEVEL, NULL, 0); + D_SendExitLevel(false); return; } @@ -2435,7 +2408,7 @@ void P_CheckSurvivors(void) { CONS_Printf(M_GetText("All players have been tagged!\n")); if (server) - SendNetXCmd(XD_EXITLEVEL, NULL, 0); + D_SendExitLevel(false); } return; @@ -2447,7 +2420,7 @@ void P_CheckSurvivors(void) { CONS_Printf(M_GetText("There are no players able to become IT.\n")); if (server) - SendNetXCmd(XD_EXITLEVEL, NULL, 0); + D_SendExitLevel(false); } return; @@ -2459,7 +2432,7 @@ void P_CheckSurvivors(void) { CONS_Printf(M_GetText("All players have been tagged!\n")); if (server) - SendNetXCmd(XD_EXITLEVEL, NULL, 0); + D_SendExitLevel(false); } } @@ -3144,7 +3117,7 @@ static void P_NiGHTSDamage(mobj_t *target, mobj_t *source) P_SetPlayerMobjState(target, S_PLAY_NIGHTS_STUN); S_StartSound(target, sfx_nghurt); - player->mo->rollangle = 0; + player->mo->spriteroll = 0; if (oldnightstime > 10*TICRATE && player->nightstime < 10*TICRATE) @@ -3326,7 +3299,7 @@ static boolean P_PlayerHitsPlayer(mobj_t *target, mobj_t *inflictor, mobj_t *sou return false; // Add pity. - if (!player->powers[pw_flashing] && !player->powers[pw_invulnerability] && !player->powers[pw_super] + if (!player->powers[pw_flashing] && !player->powers[pw_invulnerability] && !player->powers[pw_super] && !(player->powers[pw_strong] & STR_GUARD) && source->player->score > player->score) player->pity++; @@ -3798,7 +3771,7 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da } return false; } - else if (player->powers[pw_invulnerability] || player->powers[pw_flashing] || player->powers[pw_super]) // ignore bouncing & such in invulnerability + else if (player->powers[pw_invulnerability] || player->powers[pw_flashing] || player->powers[pw_super] || (player->powers[pw_strong] & STR_GUARD)) // ignore bouncing & such in invulnerability { if (force || (inflictor && inflictor->flags & MF_MISSILE && inflictor->flags2 & MF2_SUPERFIRE)) // Super Sonic is stunned! diff --git a/src/p_local.h b/src/p_local.h index 3c84d6fe2f2ddaded0260623b3a402969a8fe11c..563e257d8f1e67e7e5d45d0a8f7122659c66b435 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -537,5 +537,6 @@ void P_Thrust(mobj_t *mo, angle_t angle, fixed_t move); void P_DoSuperTransformation(player_t *player, boolean giverings); void P_ExplodeMissile(mobj_t *mo); void P_CheckGravity(mobj_t *mo, boolean affect); +void P_SetPitchRollFromSlope(mobj_t *mo, pslope_t *slope); #endif // __P_LOCAL__ diff --git a/src/p_map.c b/src/p_map.c index aa2bda90d9b4b7efe899176eadc34099267293f8..251837876caab9f979b92ef1ece83a1750f24768 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -177,10 +177,8 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object) { if (spring->info->painchance == 3) ; - else if (object->player->charability == CA_TWINSPIN && object->player->panim == PA_ABILITY) + else if (object->player->powers[pw_strong] & STR_SPRING) strong = 1; - else if (object->player->charability2 == CA2_MELEE && object->player->panim == PA_ABILITY2) - strong = 2; } if (spring->info->painchance == -1) // Pinball bumper mode. @@ -495,7 +493,8 @@ springstate: if (strong) { - P_TwinSpinRejuvenate(object->player, (strong == 1 ? object->player->thokitem : object->player->revitem)); + if (object->player->charability == CA_TWINSPIN || object->player->charability2 == CA2_MELEE) + P_TwinSpinRejuvenate(object->player, (object->player->charability == CA_TWINSPIN ? object->player->thokitem : object->player->revitem)); S_StartSound(object, sfx_sprong); // strong spring. sprong. } } @@ -836,43 +835,25 @@ static boolean PIT_CheckThing(mobj_t *thing) return true; } - // SF_DASHMODE users destroy spikes and monitors, CA_TWINSPIN users and CA2_MELEE users destroy spikes. - if ((tmthing->player) - && ((((tmthing->player->charflags & (SF_DASHMODE|SF_MACHINE)) == (SF_DASHMODE|SF_MACHINE)) && (tmthing->player->dashmode >= DASHMODE_THRESHOLD) - && (thing->flags & (MF_MONITOR) - || (thing->type == MT_SPIKE - || thing->type == MT_WALLSPIKE))) - || ((((tmthing->player->charability == CA_TWINSPIN) && (tmthing->player->panim == PA_ABILITY)) - || (tmthing->player->charability2 == CA2_MELEE && tmthing->player->panim == PA_ABILITY2)) - && (thing->type == MT_SPIKE - || thing->type == MT_WALLSPIKE)))) - { - if ((thing->flags & (MF_MONITOR)) && (thing->health <= 0 || !(thing->flags & MF_SHOOTABLE))) - return true; - blockdist = thing->radius + tmthing->radius; - if (abs(thing->x - tmx) >= blockdist || abs(thing->y - tmy) >= blockdist) - return true; // didn't hit it - // see if it went over / under - if (tmthing->z > thing->z + thing->height) - return true; // overhead - if (tmthing->z + tmthing->height < thing->z) - return true; // underneath - if (thing->type == MT_SPIKE - || thing->type == MT_WALLSPIKE) - { - mobj_t *iter; - if (thing->flags & MF_SOLID) - S_StartSound(tmthing, thing->info->deathsound); - for (iter = thing->subsector->sector->thinglist; iter; iter = iter->snext) - if (iter->type == thing->type && iter->health > 0 && iter->flags & MF_SOLID && (iter == thing || P_AproxDistance(P_AproxDistance(thing->x - iter->x, thing->y - iter->y), thing->z - iter->z) < 56*thing->scale))//FixedMul(56*FRACUNIT, thing->scale)) - P_KillMobj(iter, tmthing, tmthing, 0); - return true; - } - else - { - if (P_DamageMobj(thing, tmthing, tmthing, 1, 0)) - return true; - } + // STR_SPIKE users destroy spikes + if ((tmthing->player) && ((tmthing->player->powers[pw_strong] & STR_SPIKE) && (thing->type == MT_SPIKE || thing->type == MT_WALLSPIKE))) + { + mobj_t *iter; + blockdist = thing->radius + tmthing->radius; + if (abs(thing->x - tmx) >= blockdist || abs(thing->y - tmy) >= blockdist) + return true; // didn't hit it + // see if it went over / under + if (tmthing->z > thing->z + thing->height) + return true; // overhead + if (tmthing->z + tmthing->height < thing->z) + return true; // underneath + + if (thing->flags & MF_SOLID) + S_StartSound(tmthing, thing->info->deathsound); + for (iter = thing->subsector->sector->thinglist; iter; iter = iter->snext) + if (iter->type == thing->type && iter->health > 0 && iter->flags & MF_SOLID && (iter == thing || P_AproxDistance(P_AproxDistance(thing->x - iter->x, thing->y - iter->y), thing->z - iter->z) < 56*thing->scale))//FixedMul(56*FRACUNIT, thing->scale)) + P_KillMobj(iter, tmthing, tmthing, 0); + return true; } // vectorise metal - done in a special case as at this point neither has the right flags for touching @@ -1185,7 +1166,7 @@ static boolean PIT_CheckThing(mobj_t *thing) } // When solid spikes move, assume they just popped up and teleport things on top of them to hurt. - if (tmthing->type == MT_SPIKE && tmthing->flags & MF_SOLID) + if (tmthing->type == MT_SPIKE && (thing->flags & MF_SOLID) && (tmthing->flags & MF_SOLID)) { if (thing->z > tmthing->z + tmthing->height) return true; // overhead @@ -1727,25 +1708,22 @@ static boolean PIT_CheckThing(mobj_t *thing) // Going down? Then bounce back up. if (P_DamageMobj(thing, tmthing, tmthing, 1, 0) // break the monitor && (flipval*(*momz) < 0) // monitor is on the floor and you're going down, or on the ceiling and you're going up - && (elementalpierce != 1)) // you're not piercing through the monitor... + && (elementalpierce != 1) && (!(player->powers[pw_strong] & STR_HEAVY))) // you're not piercing through the monitor... { - if (!(player->charability2 == CA2_MELEE && player->panim == PA_ABILITY2)) + fixed_t setmomz = -*momz; // Store this, momz get changed by P_DoJump within P_DoBubbleBounce + + if (elementalpierce == 2) // Reset bubblewrap, part 1 + P_DoBubbleBounce(player); + *momz = setmomz; // Therefore, you should be thrust in the opposite direction, vertically. + if (player->charability == CA_TWINSPIN && player->panim == PA_ABILITY) + P_TwinSpinRejuvenate(player, player->thokitem); + if (elementalpierce == 2) // Reset bubblewrap, part 2 { - fixed_t setmomz = -*momz; // Store this, momz get changed by P_DoJump within P_DoBubbleBounce - - if (elementalpierce == 2) // Reset bubblewrap, part 1 - P_DoBubbleBounce(player); - *momz = setmomz; // Therefore, you should be thrust in the opposite direction, vertically. - if (player->charability == CA_TWINSPIN && player->panim == PA_ABILITY) - P_TwinSpinRejuvenate(player, player->thokitem); - if (elementalpierce == 2) // Reset bubblewrap, part 2 - { - boolean underwater = tmthing->eflags & MFE_UNDERWATER; + boolean underwater = tmthing->eflags & MFE_UNDERWATER; - if (underwater) - *momz /= 2; - *momz -= (*momz/(underwater ? 8 : 4)); // Cap the height! - } + if (underwater) + *momz /= 2; + *momz -= (*momz/(underwater ? 8 : 4)); // Cap the height! } } if (!(elementalpierce == 1 && thing->flags & MF_GRENADEBOUNCE)) // prevent gold monitor clipthrough. @@ -2546,7 +2524,6 @@ boolean P_CheckCameraPosition(fixed_t x, fixed_t y, camera_t *thiscam) boolean P_TryCameraMove(fixed_t x, fixed_t y, camera_t *thiscam) { subsector_t *s = R_PointInSubsector(x, y); - boolean retval = true; boolean itsatwodlevel = false; floatok = false; @@ -2561,8 +2538,8 @@ boolean P_TryCameraMove(fixed_t x, fixed_t y, camera_t *thiscam) fixed_t tryx = thiscam->x; fixed_t tryy = thiscam->y; - if ((thiscam == &camera && (players[displayplayer].pflags & PF_NOCLIP)) - || (thiscam == &camera2 && (players[secondarydisplayplayer].pflags & PF_NOCLIP))) + if ((thiscam == &camera && (players[displayplayer].pflags & PF_NOCLIP || players[displayplayer].powers[pw_carry] == CR_NIGHTSMODE)) + || (thiscam == &camera2 && (players[secondarydisplayplayer].pflags & PF_NOCLIP || players[secondarydisplayplayer].powers[pw_carry] == CR_NIGHTSMODE))) { // Noclipping player camera noclips too!! floatok = true; thiscam->floorz = thiscam->z; @@ -2630,7 +2607,7 @@ boolean P_TryCameraMove(fixed_t x, fixed_t y, camera_t *thiscam) thiscam->y = y; thiscam->subsector = s; - return retval; + return true; } // @@ -2950,6 +2927,8 @@ boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff) if (thing->momz <= 0) { thing->standingslope = tmfloorslope; + P_SetPitchRollFromSlope(thing, thing->standingslope); + if (thing->momz == 0 && thing->player && !startingonground) P_PlayerHitFloor(thing->player, true); } @@ -2961,6 +2940,8 @@ boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff) if (thing->momz >= 0) { thing->standingslope = tmceilingslope; + P_SetPitchRollFromSlope(thing, thing->standingslope); + if (thing->momz == 0 && thing->player && !startingonground) P_PlayerHitFloor(thing->player, true); } @@ -3749,7 +3730,9 @@ void P_SlideMove(mobj_t *mo) boolean papercol = false; vertex_t v1, v2; // fake vertexes - line_t junk; // fake linedef + static line_t junk; // fake linedef + + memset(&junk, 0x00, sizeof(junk)); if (tmhitthing && mo->z + mo->height > tmhitthing->z && mo->z < tmhitthing->z + tmhitthing->height) { @@ -4027,131 +4010,135 @@ void P_BounceMove(mobj_t *mo) slidemo = mo; hitcount = 0; -retry: - if (++hitcount == 3) - goto bounceback; // don't loop forever - - if (mo->player) - { - mmomx = mo->player->rmomx; - mmomy = mo->player->rmomy; - } - else + do { - mmomx = mo->momx; - mmomy = mo->momy; - } + if (++hitcount == 3) + goto bounceback; // don't loop forever - // trace along the three leading corners - if (mo->momx > 0) - { - leadx = mo->x + mo->radius; - trailx = mo->x - mo->radius; - } - else - { - leadx = mo->x - mo->radius; - trailx = mo->x + mo->radius; - } + if (mo->player) + { + mmomx = mo->player->rmomx; + mmomy = mo->player->rmomy; + } + else + { + mmomx = mo->momx; + mmomy = mo->momy; + } - if (mo->momy > 0) - { - leady = mo->y + mo->radius; - traily = mo->y - mo->radius; - } - else - { - leady = mo->y - mo->radius; - traily = mo->y + mo->radius; - } + // trace along the three leading corners + if (mo->momx > 0) + { + leadx = mo->x + mo->radius; + trailx = mo->x - mo->radius; + } + else + { + leadx = mo->x - mo->radius; + trailx = mo->x + mo->radius; + } - bestslidefrac = FRACUNIT + 1; + if (mo->momy > 0) + { + leady = mo->y + mo->radius; + traily = mo->y - mo->radius; + } + else + { + leady = mo->y - mo->radius; + traily = mo->y + mo->radius; + } - P_PathTraverse(leadx, leady, leadx + mmomx, leady + mmomy, PT_ADDLINES, PTR_SlideTraverse); - P_PathTraverse(trailx, leady, trailx + mmomx, leady + mmomy, PT_ADDLINES, PTR_SlideTraverse); - P_PathTraverse(leadx, traily, leadx + mmomx, traily + mmomy, PT_ADDLINES, PTR_SlideTraverse); + bestslidefrac = FRACUNIT + 1; - // move up to the wall - if (bestslidefrac == FRACUNIT + 1) - { - // the move must have hit the middle, so bounce straight back + P_PathTraverse(leadx, leady, leadx + mmomx, leady + mmomy, PT_ADDLINES, PTR_SlideTraverse); + P_PathTraverse(trailx, leady, trailx + mmomx, leady + mmomy, PT_ADDLINES, PTR_SlideTraverse); + P_PathTraverse(leadx, traily, leadx + mmomx, traily + mmomy, PT_ADDLINES, PTR_SlideTraverse); + + // move up to the wall + if (bestslidefrac == FRACUNIT + 1) + { + // the move must have hit the middle, so bounce straight back bounceback: - if (P_TryMove(mo, mo->x - mmomx, mo->y - mmomy, true)) + if (P_TryMove(mo, mo->x - mmomx, mo->y - mmomy, true)) + { + mo->momx *= -1; + mo->momy *= -1; + mo->momx = FixedMul(mo->momx, (FRACUNIT - (FRACUNIT>>2) - (FRACUNIT>>3))); + mo->momy = FixedMul(mo->momy, (FRACUNIT - (FRACUNIT>>2) - (FRACUNIT>>3))); + + if (mo->player) + { + mo->player->cmomx *= -1; + mo->player->cmomy *= -1; + mo->player->cmomx = FixedMul(mo->player->cmomx, + (FRACUNIT - (FRACUNIT>>2) - (FRACUNIT>>3))); + mo->player->cmomy = FixedMul(mo->player->cmomy, + (FRACUNIT - (FRACUNIT>>2) - (FRACUNIT>>3))); + } + } + return; + } + + // fudge a bit to make sure it doesn't hit + bestslidefrac -= 0x800; + if (bestslidefrac > 0) { - mo->momx *= -1; - mo->momy *= -1; - mo->momx = FixedMul(mo->momx, (FRACUNIT - (FRACUNIT>>2) - (FRACUNIT>>3))); - mo->momy = FixedMul(mo->momy, (FRACUNIT - (FRACUNIT>>2) - (FRACUNIT>>3))); + newx = FixedMul(mmomx, bestslidefrac); + newy = FixedMul(mmomy, bestslidefrac); - if (mo->player) + if (!P_TryMove(mo, mo->x + newx, mo->y + newy, true)) { - mo->player->cmomx *= -1; - mo->player->cmomy *= -1; - mo->player->cmomx = FixedMul(mo->player->cmomx, - (FRACUNIT - (FRACUNIT>>2) - (FRACUNIT>>3))); - mo->player->cmomy = FixedMul(mo->player->cmomy, - (FRACUNIT - (FRACUNIT>>2) - (FRACUNIT>>3))); + if (P_MobjWasRemoved(mo)) + return; + goto bounceback; } } - return; - } - // fudge a bit to make sure it doesn't hit - bestslidefrac -= 0x800; - if (bestslidefrac > 0) - { - newx = FixedMul(mmomx, bestslidefrac); - newy = FixedMul(mmomy, bestslidefrac); + // Now continue along the wall. + // First calculate remainder. + bestslidefrac = FRACUNIT - bestslidefrac; - if (!P_TryMove(mo, mo->x + newx, mo->y + newy, true)) - goto bounceback; - } + if (bestslidefrac > FRACUNIT) + bestslidefrac = FRACUNIT; - // Now continue along the wall. - // First calculate remainder. - bestslidefrac = FRACUNIT - bestslidefrac; - - if (bestslidefrac > FRACUNIT) - bestslidefrac = FRACUNIT; - - if (bestslidefrac <= 0) - return; + if (bestslidefrac <= 0) + return; - if (mo->type == MT_SHELL) - { - tmxmove = mmomx; - tmymove = mmomy; - } - else if (mo->type == MT_THROWNBOUNCE) - { - tmxmove = FixedMul(mmomx, (FRACUNIT - (FRACUNIT>>6) - (FRACUNIT>>5))); - tmymove = FixedMul(mmomy, (FRACUNIT - (FRACUNIT>>6) - (FRACUNIT>>5))); - } - else if (mo->type == MT_THROWNGRENADE || mo->type == MT_CYBRAKDEMON_NAPALM_BOMB_LARGE) - { - // Quickly decay speed as it bounces - tmxmove = FixedDiv(mmomx, 2*FRACUNIT); - tmymove = FixedDiv(mmomy, 2*FRACUNIT); - } - else - { - tmxmove = FixedMul(mmomx, (FRACUNIT - (FRACUNIT>>2) - (FRACUNIT>>3))); - tmymove = FixedMul(mmomy, (FRACUNIT - (FRACUNIT>>2) - (FRACUNIT>>3))); - } + if (mo->type == MT_SHELL) + { + tmxmove = mmomx; + tmymove = mmomy; + } + else if (mo->type == MT_THROWNBOUNCE) + { + tmxmove = FixedMul(mmomx, (FRACUNIT - (FRACUNIT>>6) - (FRACUNIT>>5))); + tmymove = FixedMul(mmomy, (FRACUNIT - (FRACUNIT>>6) - (FRACUNIT>>5))); + } + else if (mo->type == MT_THROWNGRENADE || mo->type == MT_CYBRAKDEMON_NAPALM_BOMB_LARGE) + { + // Quickly decay speed as it bounces + tmxmove = FixedDiv(mmomx, 2*FRACUNIT); + tmymove = FixedDiv(mmomy, 2*FRACUNIT); + } + else + { + tmxmove = FixedMul(mmomx, (FRACUNIT - (FRACUNIT>>2) - (FRACUNIT>>3))); + tmymove = FixedMul(mmomy, (FRACUNIT - (FRACUNIT>>2) - (FRACUNIT>>3))); + } - P_HitBounceLine(bestslideline); // clip the moves + P_HitBounceLine(bestslideline); // clip the moves - mo->momx = tmxmove; - mo->momy = tmymove; + mo->momx = tmxmove; + mo->momy = tmymove; - if (mo->player) - { - mo->player->cmomx = tmxmove; - mo->player->cmomy = tmymove; + if (mo->player) + { + mo->player->cmomx = tmxmove; + mo->player->cmomy = tmymove; + } } - - if (!P_TryMove(mo, mo->x + tmxmove, mo->y + tmymove, true)) - goto retry; + while (!P_TryMove(mo, mo->x + tmxmove, mo->y + tmymove, true) && !P_MobjWasRemoved(mo)); } // diff --git a/src/p_mobj.c b/src/p_mobj.c index 3eab29c09599f66cab4c58c97facaf2b2d89bb7f..686f08478e8d7006e3d01c7a69ea3f38b4e1534a 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -1551,6 +1551,31 @@ void P_CheckGravity(mobj_t *mo, boolean affect) } } +// +// P_SetPitchRollFromSlope +// +void P_SetPitchRollFromSlope(mobj_t *mo, pslope_t *slope) +{ +#if 0 + if (slope) + { + fixed_t tempz = slope->normal.z; + fixed_t tempy = slope->normal.y; + fixed_t tempx = slope->normal.x; + + mo->pitch = R_PointToAngle2(0, 0, FixedSqrt(FixedMul(tempy, tempy) + FixedMul(tempz, tempz)), tempx); + mo->roll = R_PointToAngle2(0, 0, tempz, tempy); + } + else + { + mo->pitch = mo->roll = 0; + } +#else + (void)mo; + (void)slope; +#endif +} + #define STOPSPEED (FRACUNIT) // @@ -1985,6 +2010,7 @@ void P_XYMovement(mobj_t *mo) // Now compare the Zs of the different quantizations if (oldangle-newangle > ANG30 && oldangle-newangle < ANGLE_180) { // Allow for a bit of sticking - this value can be adjusted later mo->standingslope = oldslope; + P_SetPitchRollFromSlope(mo, mo->standingslope); P_SlopeLaunch(mo); //CONS_Printf("launched off of slope - "); @@ -2557,6 +2583,7 @@ boolean P_ZMovement(mobj_t *mo) if (((mo->eflags & MFE_VERTICALFLIP) ? tmceilingslope : tmfloorslope) && (mo->type != MT_STEAM)) { mo->standingslope = (mo->eflags & MFE_VERTICALFLIP) ? tmceilingslope : tmfloorslope; + P_SetPitchRollFromSlope(mo, mo->standingslope); P_ReverseQuantizeMomentumToSlope(&mom, mo->standingslope); } @@ -3661,7 +3688,7 @@ boolean P_CameraThinker(player_t *player, camera_t *thiscam, boolean resetcalled dummy.y = thiscam->y; dummy.z = thiscam->z; dummy.height = thiscam->height; - if (!resetcalled && !(player->pflags & PF_NOCLIP) && !P_CheckSight(&dummy, player->mo)) // TODO: "P_CheckCameraSight" instead. + if (!resetcalled && !(player->pflags & PF_NOCLIP || player->powers[pw_carry] == CR_NIGHTSMODE) && !P_CheckSight(&dummy, player->mo)) // TODO: "P_CheckCameraSight" instead. P_ResetCamera(player, thiscam); else { @@ -3692,7 +3719,7 @@ boolean P_CameraThinker(player_t *player, camera_t *thiscam, boolean resetcalled // adjust height thiscam->z += thiscam->momz + player->mo->pmomz; - if (!itsatwodlevel && !(player->pflags & PF_NOCLIP)) + if (!itsatwodlevel && !(player->pflags & PF_NOCLIP || player->powers[pw_carry] == CR_NIGHTSMODE)) { // clip movement if (thiscam->z <= thiscam->floorz) // hit the floor @@ -7924,11 +7951,6 @@ static void P_MobjSceneryThink(mobj_t *mobj) return; } - if (!camera.chase) - mobj->flags2 |= MF2_DONTDRAW; - else - mobj->flags2 &= ~MF2_DONTDRAW; - P_UnsetThingPosition(mobj); { fixed_t radius = FixedMul(10*mobj->info->speed, mobj->target->scale); @@ -9205,7 +9227,7 @@ static void P_DragonbomberThink(mobj_t *mobj) else { fixed_t vspeed = FixedMul(mobj->info->speed >> 3, mobj->scale); - fixed_t z = mobj->target->z + (mobj->height >> 1) + (mobj->flags & MFE_VERTICALFLIP ? -128*mobj->scale : 128*mobj->scale + mobj->target->height); + fixed_t z = mobj->target->z + (mobj->height >> 1) + (mobj->eflags & MFE_VERTICALFLIP ? -128*mobj->scale : (128*mobj->scale + mobj->target->height)); angle_t diff = R_PointToAngle2(mobj->x, mobj->y, mobj->target->x, mobj->target->y) - mobj->angle; if (diff > ANGLE_180) mobj->angle -= DRAGONTURNSPEED; @@ -9603,7 +9625,7 @@ static boolean P_MobjRegularThink(mobj_t *mobj) case MT_BOSSFLYPOINT: return false; case MT_NIGHTSCORE: - mobj->color = (UINT16)(leveltime % SKINCOLOR_WHITE); + mobj->color = linkColor[mobj->extravalue2][(leveltime + mobj->extravalue1) % NUMLINKCOLORS]; break; case MT_JETFUME1: if (!P_JetFume1Think(mobj)) @@ -9846,9 +9868,9 @@ static boolean P_MobjRegularThink(mobj_t *mobj) break; case MT_MINUS: if (P_IsObjectOnGround(mobj)) - mobj->rollangle = 0; + mobj->spriteroll = 0; else - mobj->rollangle = R_PointToAngle2(0, 0, P_MobjFlip(mobj)*mobj->momz, (mobj->scale << 1) - min(abs(mobj->momz), mobj->scale << 1)); + mobj->spriteroll = R_PointToAngle2(0, 0, P_MobjFlip(mobj)*mobj->momz, (mobj->scale << 1) - min(abs(mobj->momz), mobj->scale << 1)); break; case MT_PUSH: P_PointPushThink(mobj); @@ -10541,6 +10563,29 @@ static fixed_t P_DefaultMobjShadowScale (mobj_t *thing) case MT_REDFLAG: case MT_BLUEFLAG: + case MT_BOUNCERING: + case MT_AUTOMATICRING: + case MT_INFINITYRING: + case MT_RAILRING: + case MT_EXPLOSIONRING: + case MT_SCATTERRING: + case MT_GRENADERING: + + case MT_BOUNCEPICKUP: + case MT_RAILPICKUP: + case MT_AUTOPICKUP: + case MT_EXPLODEPICKUP: + case MT_SCATTERPICKUP: + case MT_GRENADEPICKUP: + + case MT_REDRING: + case MT_THROWNBOUNCE: + case MT_THROWNINFINITY: + case MT_THROWNAUTOMATIC: + case MT_THROWNSCATTER: + case MT_THROWNEXPLOSION: + case MT_THROWNGRENADE: + case MT_EMBLEM: case MT_TOKEN: @@ -11158,12 +11203,6 @@ void P_RemoveMobj(mobj_t *mobj) P_SetTarget(&mobj->hnext, P_SetTarget(&mobj->hprev, NULL)); - // DBG: set everything in mobj_t to 0xFF instead of leaving it. debug memory error. -#ifdef SCRAMBLE_REMOVED - // Invalidate mobj_t data to cause crashes if accessed! - memset((UINT8 *)mobj + sizeof(thinker_t), 0xff, sizeof(mobj_t) - sizeof(thinker_t)); -#endif - R_RemoveMobjInterpolator(mobj); // free block @@ -11182,6 +11221,17 @@ void P_RemoveMobj(mobj_t *mobj) } P_RemoveThinker((thinker_t *)mobj); + +#ifdef PARANOIA + // Saved to avoid being scrambled like below... + mobj->thinker.debug_mobjtype = mobj->type; +#endif + + // DBG: set everything in mobj_t to 0xFF instead of leaving it. debug memory error. +#ifdef SCRAMBLE_REMOVED + // Invalidate mobj_t data to cause crashes if accessed! + memset((UINT8 *)mobj + sizeof(thinker_t), 0xff, sizeof(mobj_t) - sizeof(thinker_t)); +#endif } // This does not need to be added to Lua. @@ -11813,7 +11863,7 @@ void P_MovePlayerToStarpost(INT32 playernum) mapthing_t *huntemeralds[MAXHUNTEMERALDS]; INT32 numhuntemeralds; -fixed_t P_GetMobjSpawnHeight(const mobjtype_t mobjtype, const fixed_t x, const fixed_t y, const fixed_t dz, const fixed_t offset, const boolean flip, const fixed_t scale) +fixed_t P_GetMobjSpawnHeight(const mobjtype_t mobjtype, const fixed_t x, const fixed_t y, const fixed_t dz, const fixed_t offset, const boolean flip, const fixed_t scale, const boolean absolutez) { const subsector_t *ss = R_PointInSubsector(x, y); @@ -11823,9 +11873,9 @@ fixed_t P_GetMobjSpawnHeight(const mobjtype_t mobjtype, const fixed_t x, const f // Establish height. if (flip) - return P_GetSectorCeilingZAt(ss->sector, x, y) - dz - FixedMul(scale, offset + mobjinfo[mobjtype].height); + return (absolutez ? dz : P_GetSectorCeilingZAt(ss->sector, x, y) - dz) - FixedMul(scale, offset + mobjinfo[mobjtype].height); else - return P_GetSectorFloorZAt(ss->sector, x, y) + dz + FixedMul(scale, offset); + return (absolutez ? dz : P_GetSectorFloorZAt(ss->sector, x, y) + dz) + FixedMul(scale, offset); } fixed_t P_GetMapThingSpawnHeight(const mobjtype_t mobjtype, const mapthing_t* mthing, const fixed_t x, const fixed_t y) @@ -11833,6 +11883,7 @@ fixed_t P_GetMapThingSpawnHeight(const mobjtype_t mobjtype, const mapthing_t* mt fixed_t dz = mthing->z << FRACBITS; // Base offset from the floor. fixed_t offset = 0; // Specific scaling object offset. boolean flip = (!!(mobjinfo[mobjtype].flags & MF_SPAWNCEILING) ^ !!(mthing->options & MTF_OBJECTFLIP)); + boolean absolutez = !!(mthing->options & MTF_ABSOLUTEZ); switch (mobjtype) { @@ -11888,7 +11939,7 @@ fixed_t P_GetMapThingSpawnHeight(const mobjtype_t mobjtype, const mapthing_t* mt offset += mthing->args[0] ? 0 : 24*FRACUNIT; } - if (!(dz + offset)) // Snap to the surfaces when there's no offset set. + if (!(dz + offset) && !absolutez) // Snap to the surfaces when there's no offset set. { if (flip) return ONCEILINGZ; @@ -11896,7 +11947,7 @@ fixed_t P_GetMapThingSpawnHeight(const mobjtype_t mobjtype, const mapthing_t* mt return ONFLOORZ; } - return P_GetMobjSpawnHeight(mobjtype, x, y, dz, offset, flip, mthing->scale); + return P_GetMobjSpawnHeight(mobjtype, x, y, dz, offset, flip, mthing->scale, absolutez); } static boolean P_SpawnNonMobjMapThing(mapthing_t *mthing) @@ -12565,7 +12616,7 @@ static boolean P_SetupNiGHTSDrone(mapthing_t *mthing, mobj_t *mobj) dronemangoaldiff = max(mobjinfo[MT_NIGHTSDRONE_MAN].height - mobjinfo[MT_NIGHTSDRONE_GOAL].height, 0); if (flip && mobj->height != oldheight) - P_MoveOrigin(mobj, mobj->x, mobj->y, mobj->z - (mobj->height - oldheight)); + P_SetOrigin(mobj, mobj->x, mobj->y, mobj->z - (mobj->height - oldheight)); if (!flip) { @@ -13304,6 +13355,9 @@ static mobj_t *P_SpawnMobjFromMapThing(mapthing_t *mthing, fixed_t x, fixed_t y, P_SetScale(mobj, FixedMul(mobj->scale, mthing->scale)); mobj->destscale = FixedMul(mobj->destscale, mthing->scale); + mobj->spritexscale = mthing->spritexscale; + mobj->spriteyscale = mthing->spriteyscale; + if (!P_SetupSpawnedMapThing(mthing, mobj, &doangle)) return mobj; @@ -13390,7 +13444,7 @@ void P_SpawnHoop(mapthing_t *mthing) vector4_t v, res; fixed_t x = mthing->x << FRACBITS; fixed_t y = mthing->y << FRACBITS; - fixed_t z = P_GetMobjSpawnHeight(MT_HOOP, x, y, mthing->z << FRACBITS, 0, false, mthing->scale); + fixed_t z = P_GetMobjSpawnHeight(MT_HOOP, x, y, mthing->z << FRACBITS, 0, false, mthing->scale, mthing->options & MTF_ABSOLUTEZ); hoopcenter = P_SpawnMobj(x, y, z, MT_HOOPCENTER); hoopcenter->spawnpoint = mthing; @@ -13517,7 +13571,7 @@ static void P_SpawnItemRow(mapthing_t *mthing, mobjtype_t *itemtypes, UINT8 numi itemtypes[r] = P_GetMobjtypeSubstitute(&dummything, itemtypes[r]); } } - z = P_GetMobjSpawnHeight(itemtypes[0], x, y, z, 0, mthing->options & MTF_OBJECTFLIP, mthing->scale); + z = P_GetMobjSpawnHeight(itemtypes[0], x, y, z, 0, mthing->options & MTF_OBJECTFLIP, mthing->scale, mthing->options & MTF_ABSOLUTEZ); for (r = 0; r < numitems; r++) { @@ -13576,7 +13630,7 @@ static void P_SpawnItemCircle(mapthing_t *mthing, mobjtype_t *itemtypes, UINT8 n itemtypes[i] = P_GetMobjtypeSubstitute(&dummything, itemtypes[i]); } } - z = P_GetMobjSpawnHeight(itemtypes[0], x, y, z, 0, false, mthing->scale); + z = P_GetMobjSpawnHeight(itemtypes[0], x, y, z, 0, false, mthing->scale, mthing->options & MTF_ABSOLUTEZ); for (i = 0; i < numitems; i++) { @@ -14145,6 +14199,13 @@ mobj_t *P_SpawnMobjFromMobj(mobj_t *mobj, fixed_t xofs, fixed_t yofs, fixed_t zo newmobj->old_angle = mobj->old_angle; } + newmobj->old_pitch2 = mobj->old_pitch2; + newmobj->old_pitch = mobj->old_pitch; + newmobj->old_roll2 = mobj->old_roll2; + newmobj->old_roll = mobj->old_roll; + newmobj->old_spriteroll2 = mobj->old_spriteroll2; + newmobj->old_spriteroll = mobj->old_spriteroll; + newmobj->old_scale2 = mobj->old_scale2; newmobj->old_scale = mobj->old_scale; newmobj->old_spritexscale = mobj->old_spritexscale; diff --git a/src/p_mobj.h b/src/p_mobj.h index 6717c4add0ab016d32821e3e6b1de7c44c06d205..a980691beb8b296b4fd16415141e4f9e5f484af8 100644 --- a/src/p_mobj.h +++ b/src/p_mobj.h @@ -122,7 +122,7 @@ typedef enum MF_AMBIENT = 1<<10, // Slide this object when it hits a wall. MF_SLIDEME = 1<<11, - // Player cheat. + // Don't collide with walls or solid objects. Two MF_NOCLIP objects can't touch each other at all! MF_NOCLIP = 1<<12, // Allow moves to any height, no gravity. For active floaters. MF_FLOAT = 1<<13, @@ -292,7 +292,7 @@ typedef struct mobj_s angle_t angle, pitch, roll; // orientation angle_t old_angle, old_pitch, old_roll; // orientation interpolation angle_t old_angle2, old_pitch2, old_roll2; - angle_t rollangle; + angle_t spriteroll, old_spriteroll, old_spriteroll2; spritenum_t sprite; // used to find patch_t and flip value UINT32 frame; // frame number, plus bits see p_pspr.h UINT8 sprite2; // player sprites @@ -334,6 +334,8 @@ typedef struct mobj_s // Player and mobj sprites in multiplayer modes are modified // using an internal color lookup table for re-indexing. UINT16 color; // This replaces MF_TRANSLATION. Use 0 for default (no translation). + struct player_s *drawonlyforplayer; // If set, hides the mobj for everyone except this player and their spectators + struct mobj_s *dontdrawforviewmobj; // If set, hides the mobj if dontdrawforviewmobj is the current camera (first-person player or awayviewmobj) // Interaction info, by BLOCKMAP. // Links in blocks (if needed). @@ -429,7 +431,7 @@ typedef struct precipmobj_s angle_t angle, pitch, roll; // orientation angle_t old_angle, old_pitch, old_roll; // orientation interpolation angle_t old_angle2, old_pitch2, old_roll2; - angle_t rollangle; + angle_t spriteroll, old_spriteroll, old_spriteroll2; spritenum_t sprite; // used to find patch_t and flip value UINT32 frame; // frame number, plus bits see p_pspr.h UINT8 sprite2; // player sprites @@ -489,7 +491,7 @@ void P_MovePlayerToSpawn(INT32 playernum, mapthing_t *mthing); void P_MovePlayerToStarpost(INT32 playernum); void P_AfterPlayerSpawn(INT32 playernum); -fixed_t P_GetMobjSpawnHeight(const mobjtype_t mobjtype, const fixed_t x, const fixed_t y, const fixed_t dz, const fixed_t offset, const boolean flip, const fixed_t scale); +fixed_t P_GetMobjSpawnHeight(const mobjtype_t mobjtype, const fixed_t x, const fixed_t y, const fixed_t dz, const fixed_t offset, const boolean flip, const fixed_t scale, const boolean absolutez); fixed_t P_GetMapThingSpawnHeight(const mobjtype_t mobjtype, const mapthing_t* mthing, const fixed_t x, const fixed_t y); mobj_t *P_SpawnMapThing(mapthing_t *mthing); diff --git a/src/p_saveg.c b/src/p_saveg.c index c18319c69816c7e9928795249963188c07929cbc..faecd13770b3d81b992017af51b4b663487aa50d 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -169,6 +169,7 @@ static void P_NetArchivePlayers(void) WRITEUINT8(save_p, players[i].playerstate); WRITEUINT32(save_p, players[i].pflags); WRITEUINT8(save_p, players[i].panim); + WRITEUINT8(save_p, players[i].stronganim); WRITEUINT8(save_p, players[i].spectator); WRITEUINT16(save_p, players[i].flashpal); @@ -178,6 +179,7 @@ static void P_NetArchivePlayers(void) WRITEINT32(save_p, players[i].skin); WRITEUINT32(save_p, players[i].availabilities); WRITEUINT32(save_p, players[i].score); + WRITEUINT32(save_p, players[i].recordscore); WRITEFIXED(save_p, players[i].dashspeed); WRITESINT8(save_p, players[i].lives); WRITESINT8(save_p, players[i].continues); @@ -396,6 +398,7 @@ static void P_NetUnArchivePlayers(void) players[i].playerstate = READUINT8(save_p); players[i].pflags = READUINT32(save_p); players[i].panim = READUINT8(save_p); + players[i].stronganim = READUINT8(save_p); players[i].spectator = READUINT8(save_p); players[i].flashpal = READUINT16(save_p); @@ -405,6 +408,7 @@ static void P_NetUnArchivePlayers(void) players[i].skin = READINT32(save_p); players[i].availabilities = READUINT32(save_p); players[i].score = READUINT32(save_p); + players[i].recordscore = READUINT32(save_p); players[i].dashspeed = READFIXED(save_p); // dashing speed players[i].lives = READSINT8(save_p); players[i].continues = READSINT8(save_p); // continues that player has acquired @@ -1023,17 +1027,17 @@ static void ArchiveSectors(void) if (ss->special != spawnss->special) diff |= SD_SPECIAL; - if (ss->floor_xoffs != spawnss->floor_xoffs) + if (ss->floorxoffset != spawnss->floorxoffset) diff2 |= SD_FXOFFS; - if (ss->floor_yoffs != spawnss->floor_yoffs) + if (ss->flooryoffset != spawnss->flooryoffset) diff2 |= SD_FYOFFS; - if (ss->ceiling_xoffs != spawnss->ceiling_xoffs) + if (ss->ceilingxoffset != spawnss->ceilingxoffset) diff2 |= SD_CXOFFS; - if (ss->ceiling_yoffs != spawnss->ceiling_yoffs) + if (ss->ceilingyoffset != spawnss->ceilingyoffset) diff2 |= SD_CYOFFS; - if (ss->floorpic_angle != spawnss->floorpic_angle) + if (ss->floorangle != spawnss->floorangle) diff2 |= SD_FLOORANG; - if (ss->ceilingpic_angle != spawnss->ceilingpic_angle) + if (ss->ceilingangle != spawnss->ceilingangle) diff2 |= SD_CEILANG; if (!Tag_Compare(&ss->tags, &spawnss->tags)) @@ -1096,17 +1100,17 @@ static void ArchiveSectors(void) if (diff & SD_SPECIAL) WRITEINT16(save_p, ss->special); if (diff2 & SD_FXOFFS) - WRITEFIXED(save_p, ss->floor_xoffs); + WRITEFIXED(save_p, ss->floorxoffset); if (diff2 & SD_FYOFFS) - WRITEFIXED(save_p, ss->floor_yoffs); + WRITEFIXED(save_p, ss->flooryoffset); if (diff2 & SD_CXOFFS) - WRITEFIXED(save_p, ss->ceiling_xoffs); + WRITEFIXED(save_p, ss->ceilingxoffset); if (diff2 & SD_CYOFFS) - WRITEFIXED(save_p, ss->ceiling_yoffs); + WRITEFIXED(save_p, ss->ceilingyoffset); if (diff2 & SD_FLOORANG) - WRITEANGLE(save_p, ss->floorpic_angle); + WRITEANGLE(save_p, ss->floorangle); if (diff2 & SD_CEILANG) - WRITEANGLE(save_p, ss->ceilingpic_angle); + WRITEANGLE(save_p, ss->ceilingangle); if (diff2 & SD_TAG) { WRITEUINT32(save_p, ss->tags.count); @@ -1197,17 +1201,17 @@ static void UnArchiveSectors(void) sectors[i].special = READINT16(save_p); if (diff2 & SD_FXOFFS) - sectors[i].floor_xoffs = READFIXED(save_p); + sectors[i].floorxoffset = READFIXED(save_p); if (diff2 & SD_FYOFFS) - sectors[i].floor_yoffs = READFIXED(save_p); + sectors[i].flooryoffset = READFIXED(save_p); if (diff2 & SD_CXOFFS) - sectors[i].ceiling_xoffs = READFIXED(save_p); + sectors[i].ceilingxoffset = READFIXED(save_p); if (diff2 & SD_CYOFFS) - sectors[i].ceiling_yoffs = READFIXED(save_p); + sectors[i].ceilingyoffset = READFIXED(save_p); if (diff2 & SD_FLOORANG) - sectors[i].floorpic_angle = READANGLE(save_p); + sectors[i].floorangle = READANGLE(save_p); if (diff2 & SD_CEILANG) - sectors[i].ceilingpic_angle = READANGLE(save_p); + sectors[i].ceilingangle = READANGLE(save_p); if (diff2 & SD_TAG) { size_t ncount = READUINT32(save_p); @@ -1549,30 +1553,32 @@ typedef enum typedef enum { - MD2_CUSVAL = 1, - MD2_CVMEM = 1<<1, - MD2_SKIN = 1<<2, - MD2_COLOR = 1<<3, - MD2_SCALESPEED = 1<<4, - MD2_EXTVAL1 = 1<<5, - MD2_EXTVAL2 = 1<<6, - MD2_HNEXT = 1<<7, - MD2_HPREV = 1<<8, - MD2_FLOORROVER = 1<<9, - MD2_CEILINGROVER = 1<<10, - MD2_SLOPE = 1<<11, - MD2_COLORIZED = 1<<12, - MD2_MIRRORED = 1<<13, - MD2_ROLLANGLE = 1<<14, - MD2_SHADOWSCALE = 1<<15, - MD2_RENDERFLAGS = 1<<16, - MD2_BLENDMODE = 1<<17, - MD2_SPRITEXSCALE = 1<<18, - MD2_SPRITEYSCALE = 1<<19, - MD2_SPRITEXOFFSET = 1<<20, - MD2_SPRITEYOFFSET = 1<<21, - MD2_FLOORSPRITESLOPE = 1<<22, - MD2_DISPOFFSET = 1<<23 + MD2_CUSVAL = 1, + MD2_CVMEM = 1<<1, + MD2_SKIN = 1<<2, + MD2_COLOR = 1<<3, + MD2_SCALESPEED = 1<<4, + MD2_EXTVAL1 = 1<<5, + MD2_EXTVAL2 = 1<<6, + MD2_HNEXT = 1<<7, + MD2_HPREV = 1<<8, + MD2_FLOORROVER = 1<<9, + MD2_CEILINGROVER = 1<<10, + MD2_SLOPE = 1<<11, + MD2_COLORIZED = 1<<12, + MD2_MIRRORED = 1<<13, + MD2_SPRITEROLL = 1<<14, + MD2_SHADOWSCALE = 1<<15, + MD2_RENDERFLAGS = 1<<16, + MD2_BLENDMODE = 1<<17, + MD2_SPRITEXSCALE = 1<<18, + MD2_SPRITEYSCALE = 1<<19, + MD2_SPRITEXOFFSET = 1<<20, + MD2_SPRITEYOFFSET = 1<<21, + MD2_FLOORSPRITESLOPE = 1<<22, + MD2_DISPOFFSET = 1<<23, + MD2_DRAWONLYFORPLAYER = 1<<24, + MD2_DONTDRAWFORVIEWMOBJ = 1<<25 } mobj_diff2_t; typedef enum @@ -1781,8 +1787,8 @@ static void SaveMobjThinker(const thinker_t *th, const UINT8 type) diff2 |= MD2_COLORIZED; if (mobj->mirrored) diff2 |= MD2_MIRRORED; - if (mobj->rollangle) - diff2 |= MD2_ROLLANGLE; + if (mobj->spriteroll) + diff2 |= MD2_SPRITEROLL; if (mobj->shadowscale) diff2 |= MD2_SHADOWSCALE; if (mobj->renderflags) @@ -1807,6 +1813,10 @@ static void SaveMobjThinker(const thinker_t *th, const UINT8 type) || (slope->normal.z != FRACUNIT)) diff2 |= MD2_FLOORSPRITESLOPE; } + if (mobj->drawonlyforplayer) + diff2 |= MD2_DRAWONLYFORPLAYER; + if (mobj->dontdrawforviewmobj) + diff2 |= MD2_DONTDRAWFORVIEWMOBJ; if (mobj->dispoffset != mobj->info->dispoffset) diff2 |= MD2_DISPOFFSET; @@ -1949,8 +1959,8 @@ static void SaveMobjThinker(const thinker_t *th, const UINT8 type) WRITEUINT8(save_p, mobj->colorized); if (diff2 & MD2_MIRRORED) WRITEUINT8(save_p, mobj->mirrored); - if (diff2 & MD2_ROLLANGLE) - WRITEANGLE(save_p, mobj->rollangle); + if (diff2 & MD2_SPRITEROLL) + WRITEANGLE(save_p, mobj->spriteroll); if (diff2 & MD2_SHADOWSCALE) WRITEFIXED(save_p, mobj->shadowscale); if (diff2 & MD2_RENDERFLAGS) @@ -1984,6 +1994,10 @@ static void SaveMobjThinker(const thinker_t *th, const UINT8 type) WRITEFIXED(save_p, slope->normal.y); WRITEFIXED(save_p, slope->normal.z); } + if (diff2 & MD2_DRAWONLYFORPLAYER) + WRITEUINT8(save_p, mobj->drawonlyforplayer-players); + if (diff2 & MD2_DONTDRAWFORVIEWMOBJ) + WRITEUINT32(save_p, mobj->dontdrawforviewmobj->mobjnum); if (diff2 & MD2_DISPOFFSET) WRITEINT32(save_p, mobj->dispoffset); @@ -2702,8 +2716,8 @@ static void P_NetArchiveThinkers(void) continue; } #ifdef PARANOIA - else if (th->function.acp1 != (actionf_p1)P_RemoveThinkerDelayed) // wait garbage collection - I_Error("unknown thinker type %p", th->function.acp1); + else + I_Assert(th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed); // wait garbage collection #endif } @@ -2999,8 +3013,8 @@ static thinker_t* LoadMobjThinker(actionf_p1 thinker) mobj->colorized = READUINT8(save_p); if (diff2 & MD2_MIRRORED) mobj->mirrored = READUINT8(save_p); - if (diff2 & MD2_ROLLANGLE) - mobj->rollangle = READANGLE(save_p); + if (diff2 & MD2_SPRITEROLL) + mobj->spriteroll = READANGLE(save_p); if (diff2 & MD2_SHADOWSCALE) mobj->shadowscale = READFIXED(save_p); if (diff2 & MD2_RENDERFLAGS) @@ -3040,6 +3054,10 @@ static thinker_t* LoadMobjThinker(actionf_p1 thinker) slope->normal.y = READFIXED(save_p); slope->normal.z = READFIXED(save_p); } + if (diff2 & MD2_DRAWONLYFORPLAYER) + mobj->drawonlyforplayer = &players[READUINT8(save_p)]; + if (diff2 & MD2_DONTDRAWFORVIEWMOBJ) + mobj->dontdrawforviewmobj = (mobj_t *)(size_t)READUINT32(save_p); if (diff2 & MD2_DISPOFFSET) mobj->dispoffset = READINT32(save_p); else @@ -4059,6 +4077,13 @@ static void P_RelinkPointers(void) if (mobj->type == MT_HOOP || mobj->type == MT_HOOPCOLLIDE || mobj->type == MT_HOOPCENTER) continue; + if (mobj->dontdrawforviewmobj) + { + temp = (UINT32)(size_t)mobj->dontdrawforviewmobj; + mobj->dontdrawforviewmobj = NULL; + if (!P_SetTarget(&mobj->dontdrawforviewmobj, P_FindNewPosition(temp))) + CONS_Debug(DBG_GAMELOGIC, "dontdrawforviewmobj not found on %d\n", mobj->type); + } if (mobj->tracer) { temp = (UINT32)(size_t)mobj->tracer; @@ -4277,7 +4302,11 @@ static void P_NetArchiveMisc(boolean resending) if (resending) WRITEUINT32(save_p, gametic); WRITEINT16(save_p, gamemap); - WRITEINT16(save_p, gamestate); + + if (gamestate != GS_LEVEL) + WRITEINT16(save_p, GS_WAITINGPLAYERS); // nice hack to put people back into waitingplayers + else + WRITEINT16(save_p, gamestate); WRITEINT16(save_p, gametype); { @@ -4340,8 +4369,6 @@ static void P_NetArchiveMisc(boolean resending) WRITEUINT32(save_p, hidetime); - WRITEUINT32(save_p, unlocktriggers); - // Is it paused? if (paused) WRITEUINT8(save_p, 0x2f); @@ -4440,8 +4467,6 @@ static inline boolean P_NetUnArchiveMisc(boolean reloading) hidetime = READUINT32(save_p); - unlocktriggers = READUINT32(save_p); - // Is it paused? if (READUINT8(save_p) == 0x2f) paused = true; @@ -4449,7 +4474,6 @@ static inline boolean P_NetUnArchiveMisc(boolean reloading) return true; } - static inline void P_NetArchiveEmblems(void) { gamedata_t *data = serverGamedata; @@ -4548,6 +4572,27 @@ static inline void P_NetArchiveEmblems(void) WRITEUINT32(save_p, data->nightsrecords[i]->time[curmare]); } } + + // Mid-map stuff + WRITEUINT32(save_p, unlocktriggers); + + for (i = 0; i < MAXPLAYERS; i++) + { + if (!ntemprecords[i].nummares) + { + WRITEUINT8(save_p, 0); + continue; + } + + WRITEUINT8(save_p, ntemprecords[i].nummares); + + for (curmare = 0; curmare < (ntemprecords[i].nummares + 1); ++curmare) + { + WRITEUINT32(save_p, ntemprecords[i].score[curmare]); + WRITEUINT8(save_p, ntemprecords[i].grade[curmare]); + WRITEUINT32(save_p, ntemprecords[i].time[curmare]); + } + } } static inline void P_NetUnArchiveEmblems(void) @@ -4567,9 +4612,9 @@ static inline void P_NetUnArchiveEmblems(void) savemoddata = (boolean)READUINT8(save_p); // this one is actually necessary because savemoddata stays false otherwise for some reason. if (numemblems != READINT32(save_p)) - I_Error("numemblems mismatch"); + I_Error("Bad $$$.sav dearchiving Emblems (numemblems mismatch)"); if (numextraemblems != READINT32(save_p)) - I_Error("numextraemblems mismatch"); + I_Error("Bad $$$.sav dearchiving Emblems (numextraemblems mismatch)"); // This shouldn't happen, but if something really fucked up happens and you transfer // the SERVER player's gamedata over your own CLIENT gamedata, @@ -4588,7 +4633,7 @@ static inline void P_NetUnArchiveEmblems(void) // TODO put another cipher on these things? meh, I don't care... for (i = 0; i < NUMMAPS; i++) if ((data->mapvisited[i] = READUINT8(save_p)) > MV_MAX) - I_Error("Bad $$$.sav dearchiving Emblems"); + I_Error("Bad $$$.sav dearchiving Emblems (invalid visit flags)"); // To save space, use one bit per collected/achieved/unlocked flag for (i = 0; i < MAXEMBLEMS;) @@ -4632,7 +4677,7 @@ static inline void P_NetUnArchiveEmblems(void) recrings = READUINT16(save_p); if (recrings > 10000 || recscore > MAXSCORE) - I_Error("Bad $$$.sav dearchiving Emblems"); + I_Error("Bad $$$.sav dearchiving Emblems (invalid score)"); if (recscore || rectime || recrings) { @@ -4659,12 +4704,35 @@ static inline void P_NetUnArchiveEmblems(void) if (data->nightsrecords[i]->grade[curmare] > GRADE_S) { - I_Error("Bad $$$.sav dearchiving Emblems"); + I_Error("Bad $$$.sav dearchiving Emblems (invalid grade)"); } } data->nightsrecords[i]->nummares = recmares; } + + // Mid-map stuff + unlocktriggers = READUINT32(save_p); + + for (i = 0; i < MAXPLAYERS; ++i) + { + if ((recmares = READUINT8(save_p)) == 0) + continue; + + for (curmare = 0; curmare < (recmares+1); ++curmare) + { + ntemprecords[i].score[curmare] = READUINT32(save_p); + ntemprecords[i].grade[curmare] = READUINT8(save_p); + ntemprecords[i].time[curmare] = (tic_t)READUINT32(save_p); + + if (ntemprecords[i].grade[curmare] > GRADE_S) + { + I_Error("Bad $$$.sav dearchiving Emblems (invalid temp grade)"); + } + } + + ntemprecords[i].nummares = recmares; + } } static inline void P_ArchiveLuabanksAndConsistency(void) diff --git a/src/p_setup.c b/src/p_setup.c index 07961b5c750893cb4f0b14239697a5c20384d9b7..11e185507b2f2c40070822da2659065c339643a7 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -50,6 +50,7 @@ #include "m_random.h" #include "dehacked.h" // for map headers +#include "deh_tables.h" // FREE_SKINCOLORS #include "r_main.h" #include "m_cond.h" // for emblems @@ -1049,10 +1050,10 @@ static void P_LoadSectors(UINT8 *data) ss->special = SHORT(ms->special); Tag_FSet(&ss->tags, SHORT(ms->tag)); - ss->floor_xoffs = ss->floor_yoffs = 0; - ss->ceiling_xoffs = ss->ceiling_yoffs = 0; + ss->floorxoffset = ss->flooryoffset = 0; + ss->ceilingxoffset = ss->ceilingyoffset = 0; - ss->floorpic_angle = ss->ceilingpic_angle = 0; + ss->floorangle = ss->ceilingangle = 0; ss->floorlightlevel = ss->ceilinglightlevel = 0; ss->floorlightabsolute = ss->ceilinglightabsolute = false; @@ -1103,7 +1104,6 @@ static void P_InitializeLinedef(line_t *ld) ld->validcount = 0; ld->polyobj = NULL; - ld->text = NULL; ld->callcount = 0; // cph 2006/09/30 - fix sidedef errors right away. @@ -1207,10 +1207,115 @@ static void P_InitializeSidedef(side_t *sd) sd->special = sd->line->special; } - sd->text = NULL; sd->colormap_data = NULL; } +static boolean contextdrift = false; + +// In Ring Racers, this is just the reference implementation. +// But in SRB2, backwards compatibility is a design goal!? +// So we let the map function on load, but report that there's +// an issue which could prevent saving it as a UDMF map. +// +// ... "context drift" is a term I learned from the story "Lena", +// styled after a wikipedia article on a man whose brain scan +// spawns an industry of digital brain emulation. It is a term +// to describe that the understanding of the world MMAcevedo has +// is rooted in a specific moment and time and will lose relevance +// as societal norms, languages, and events change and are changed. +// It is on the real wikipedia, but under the name "concept drift". +// I am connecting the idea of the rooted-in-time brainstate with +// the numerical evaluation of get_number(), the ground truth +// CONTEXT for all these silly integers, that will trip up future +// builds of SRB2 that have modified states and object lists. +// Golden statues rotating in place of carousel rides is perhaps +// not quite what qntm meant, but is a TEXTMAP, a human-readable +// document for imparting a sense of place made/read by machines, +// not its own language providing a vulnerable context? +// ~toast 200723, see https://qntm.org/mmacevedo +// +static void P_WriteConstant(INT32 constant, char **target, const char *desc, UINT32 id) +{ + char buffer[12]; + size_t len; + + CONS_Alert( + CONS_WARNING, M_GetText( + "P_WriteConstant has been called for %s %d, " + "this level is vulnerable to context drift " + "if -writetextmap is used.\n"), + desc, id + ); + + contextdrift = true; + + sprintf(buffer, "%d", constant); + len = strlen(buffer) + 1; + *target = Z_Malloc(len, PU_LEVEL, NULL); + M_Memcpy(*target, buffer, len); +} + +static void P_WriteDuplicateText(const char *text, char **target) +{ + if (text == NULL || text[0] == '\0') + return; + + size_t len = strlen(text) + 1; + *target = Z_Malloc(len, PU_LEVEL, NULL); + M_Memcpy(*target, text, len); +} + +static void P_WriteSkincolor(INT32 constant, char **target) +{ + const char *color_name; + + if (constant <= SKINCOLOR_NONE + || constant >= (INT32)numskincolors) + return; + + if (constant >= SKINCOLOR_FIRSTFREESLOT) + color_name = FREE_SKINCOLORS[constant - SKINCOLOR_FIRSTFREESLOT]; + else + color_name = COLOR_ENUMS[constant]; + + P_WriteDuplicateText( + va("SKINCOLOR_%s", color_name), + target + ); +} + +static void P_WriteSfx(INT32 constant, char **target) +{ + if (constant <= sfx_None + || constant >= (INT32)sfxfree) + return; + + P_WriteDuplicateText( + va("SFX_%s", S_sfx[constant].name), + target + ); +} + +static void P_WriteTics(INT32 tics, char **target) +{ + if (!tics) + return; + + INT32 seconds = (tics / TICRATE); + tics %= TICRATE; + + const char *text; + + if (tics && !seconds) + text = va("%d", tics); + else if (seconds && !tics) + text = va("(%d*TICRATE)", seconds); + else + text = va("(%d*TICRATE)%s%d", seconds, (tics > 0) ? "+" : "", tics); + + P_WriteDuplicateText(text, target); +} + static void P_LoadSidedefs(UINT8 *data) { mapsidedef_t *msd = (mapsidedef_t*)data; @@ -1262,9 +1367,13 @@ static void P_LoadSidedefs(UINT8 *data) case 413: // Change music { + sd->toptexture = sd->midtexture = sd->bottomtexture = 0; + + if (!isfrontside) + break; + char process[8+1]; - sd->toptexture = sd->midtexture = sd->bottomtexture = 0; if (msd->bottomtexture[0] != '-' || msd->bottomtexture[1] != '\0') { M_Memcpy(process,msd->bottomtexture,8); @@ -1279,48 +1388,39 @@ static void P_LoadSidedefs(UINT8 *data) sd->midtexture = get_number(process); } - sd->text = Z_Malloc(7, PU_LEVEL, NULL); - if (isfrontside && !(msd->toptexture[0] == '-' && msd->toptexture[1] == '\0')) + if (msd->toptexture[0] != '-' && msd->toptexture[1] != '\0') { + sd->line->stringargs[0] = Z_Malloc(7, PU_LEVEL, NULL); + M_Memcpy(process,msd->toptexture,8); process[8] = '\0'; // If they type in O_ or D_ and their music name, just shrug, // then copy the rest instead. if ((process[0] == 'O' || process[0] == 'D') && process[7]) - M_Memcpy(sd->text, process+2, 6); + M_Memcpy(sd->line->stringargs[0], process+2, 6); else // Assume it's a proper music name. - M_Memcpy(sd->text, process, 6); - sd->text[6] = 0; + M_Memcpy(sd->line->stringargs[0], process, 6); + sd->line->stringargs[0][6] = '\0'; } - else - sd->text[0] = 0; - break; - } - case 4: // Speed pad parameters - { - sd->toptexture = sd->midtexture = sd->bottomtexture = 0; - if (msd->toptexture[0] != '-' || msd->toptexture[1] != '\0') - { - char process[8+1]; - M_Memcpy(process,msd->toptexture,8); - process[8] = '\0'; - sd->toptexture = get_number(process); - } break; } + case 4: // Speed pad parameters case 414: // Play SFX { sd->toptexture = sd->midtexture = sd->bottomtexture = 0; + + if (!isfrontside) + break; + if (msd->toptexture[0] != '-' || msd->toptexture[1] != '\0') { char process[8 + 1]; M_Memcpy(process, msd->toptexture, 8); process[8] = '\0'; - sd->text = Z_Malloc(strlen(process) + 1, PU_LEVEL, NULL); - M_Memcpy(sd->text, process, strlen(process) + 1); + P_WriteDuplicateText(process, &sd->line->stringargs[0]); } break; } @@ -1329,21 +1429,13 @@ static void P_LoadSidedefs(UINT8 *data) case 14: // Bustable block parameters case 15: // Fan particle spawner parameters { - char process[8*3+1]; - memset(process,0,8*3+1); - sd->toptexture = sd->midtexture = sd->bottomtexture = 0; - if (msd->toptexture[0] == '-' && msd->toptexture[1] == '\0') + if (msd->toptexture[7] == '\0' && strcasecmp(msd->toptexture, "MT_NULL") == 0) + { + // Don't bulk the conversion with irrelevant types break; - else - M_Memcpy(process,msd->toptexture,8); - if (msd->midtexture[0] != '-' || msd->midtexture[1] != '\0') - M_Memcpy(process+strlen(process), msd->midtexture, 8); - if (msd->bottomtexture[0] != '-' || msd->bottomtexture[1] != '\0') - M_Memcpy(process+strlen(process), msd->bottomtexture, 8); - sd->toptexture = get_number(process); - break; + } } - + // FALLTHRU case 331: // Trigger linedef executor: Skin - Continuous case 332: // Trigger linedef executor: Skin - Each time case 333: // Trigger linedef executor: Skin - Once @@ -1369,8 +1461,11 @@ static void P_LoadSidedefs(UINT8 *data) M_Memcpy(process+strlen(process), msd->midtexture, 8); if (msd->bottomtexture[0] != '-' || msd->bottomtexture[1] != '\0') M_Memcpy(process+strlen(process), msd->bottomtexture, 8); - sd->text = Z_Malloc(strlen(process)+1, PU_LEVEL, NULL); - M_Memcpy(sd->text, process, strlen(process)+1); + + P_WriteDuplicateText( + process, + &sd->line->stringargs[(isfrontside) ? 0 : 1] + ); break; } @@ -1426,6 +1521,7 @@ static void P_LoadThings(UINT8 *data) mt->extrainfo = (UINT8)(mt->type >> 12); Tag_FSet(&mt->tags, 0); mt->scale = FRACUNIT; + mt->spritexscale = mt->spriteyscale = FRACUNIT; memset(mt->args, 0, NUMMAPTHINGARGS*sizeof(*mt->args)); memset(mt->stringargs, 0x00, NUMMAPTHINGSTRINGARGS*sizeof(*mt->stringargs)); mt->pitch = mt->roll = 0; @@ -1584,19 +1680,19 @@ static void ParseTextmapSectorParameter(UINT32 i, const char *param, const char if ((id = strchr(id, ' '))) id++; } - } + } else if (fastcmp(param, "xpanningfloor")) - sectors[i].floor_xoffs = FLOAT_TO_FIXED(atof(val)); + sectors[i].floorxoffset = FLOAT_TO_FIXED(atof(val)); else if (fastcmp(param, "ypanningfloor")) - sectors[i].floor_yoffs = FLOAT_TO_FIXED(atof(val)); + sectors[i].flooryoffset = FLOAT_TO_FIXED(atof(val)); else if (fastcmp(param, "xpanningceiling")) - sectors[i].ceiling_xoffs = FLOAT_TO_FIXED(atof(val)); + sectors[i].ceilingxoffset = FLOAT_TO_FIXED(atof(val)); else if (fastcmp(param, "ypanningceiling")) - sectors[i].ceiling_yoffs = FLOAT_TO_FIXED(atof(val)); + sectors[i].ceilingyoffset = FLOAT_TO_FIXED(atof(val)); else if (fastcmp(param, "rotationfloor")) - sectors[i].floorpic_angle = FixedAngle(FLOAT_TO_FIXED(atof(val))); + sectors[i].floorangle = FixedAngle(FLOAT_TO_FIXED(atof(val))); else if (fastcmp(param, "rotationceiling")) - sectors[i].ceilingpic_angle = FixedAngle(FLOAT_TO_FIXED(atof(val))); + sectors[i].ceilingangle = FixedAngle(FLOAT_TO_FIXED(atof(val))); else if (fastcmp(param, "floorplane_a")) { textmap_planefloor.defined |= PD_A; @@ -1941,11 +2037,19 @@ static void ParseTextmapThingParameter(UINT32 i, const char *param, const char * mapthings[i].roll = atol(val); else if (fastcmp(param, "type")) mapthings[i].type = atol(val); - else if (fastcmp(param, "scale") || fastcmp(param, "scalex") || fastcmp(param, "scaley")) + else if (fastcmp(param, "scale")) + mapthings[i].spritexscale = mapthings[i].spriteyscale = FLOAT_TO_FIXED(atof(val)); + else if (fastcmp(param, "scalex")) + mapthings[i].spritexscale = FLOAT_TO_FIXED(atof(val)); + else if (fastcmp(param, "scaley")) + mapthings[i].spriteyscale = FLOAT_TO_FIXED(atof(val)); + else if (fastcmp(param, "mobjscale")) mapthings[i].scale = FLOAT_TO_FIXED(atof(val)); // Flags else if (fastcmp(param, "flip") && fastcmp("true", val)) mapthings[i].options |= MTF_OBJECTFLIP; + else if (fastcmp(param, "absolutez") && fastcmp("true", val)) + mapthings[i].options |= MTF_ABSOLUTEZ; else if (fastncmp(param, "stringarg", 9) && strlen(param) > 9) { @@ -1996,47 +2100,47 @@ static void TextmapParse(UINT32 dataPos, size_t num, void (*parser)(UINT32, cons */ static void TextmapFixFlatOffsets(sector_t *sec) { - if (sec->floorpic_angle) + if (sec->floorangle) { - fixed_t pc = FINECOSINE(sec->floorpic_angle>>ANGLETOFINESHIFT); - fixed_t ps = FINESINE (sec->floorpic_angle>>ANGLETOFINESHIFT); - fixed_t xoffs = sec->floor_xoffs; - fixed_t yoffs = sec->floor_yoffs; - sec->floor_xoffs = (FixedMul(xoffs, pc) % MAXFLATSIZE) - (FixedMul(yoffs, ps) % MAXFLATSIZE); - sec->floor_yoffs = (FixedMul(xoffs, ps) % MAXFLATSIZE) + (FixedMul(yoffs, pc) % MAXFLATSIZE); + fixed_t pc = FINECOSINE(sec->floorangle>>ANGLETOFINESHIFT); + fixed_t ps = FINESINE (sec->floorangle>>ANGLETOFINESHIFT); + fixed_t xoffs = sec->floorxoffset; + fixed_t yoffs = sec->flooryoffset; + sec->floorxoffset = (FixedMul(xoffs, pc) % MAXFLATSIZE) - (FixedMul(yoffs, ps) % MAXFLATSIZE); + sec->flooryoffset = (FixedMul(xoffs, ps) % MAXFLATSIZE) + (FixedMul(yoffs, pc) % MAXFLATSIZE); } - if (sec->ceilingpic_angle) + if (sec->ceilingangle) { - fixed_t pc = FINECOSINE(sec->ceilingpic_angle>>ANGLETOFINESHIFT); - fixed_t ps = FINESINE (sec->ceilingpic_angle>>ANGLETOFINESHIFT); - fixed_t xoffs = sec->ceiling_xoffs; - fixed_t yoffs = sec->ceiling_yoffs; - sec->ceiling_xoffs = (FixedMul(xoffs, pc) % MAXFLATSIZE) - (FixedMul(yoffs, ps) % MAXFLATSIZE); - sec->ceiling_yoffs = (FixedMul(xoffs, ps) % MAXFLATSIZE) + (FixedMul(yoffs, pc) % MAXFLATSIZE); + fixed_t pc = FINECOSINE(sec->ceilingangle>>ANGLETOFINESHIFT); + fixed_t ps = FINESINE (sec->ceilingangle>>ANGLETOFINESHIFT); + fixed_t xoffs = sec->ceilingxoffset; + fixed_t yoffs = sec->ceilingyoffset; + sec->ceilingxoffset = (FixedMul(xoffs, pc) % MAXFLATSIZE) - (FixedMul(yoffs, ps) % MAXFLATSIZE); + sec->ceilingyoffset = (FixedMul(xoffs, ps) % MAXFLATSIZE) + (FixedMul(yoffs, pc) % MAXFLATSIZE); } } static void TextmapUnfixFlatOffsets(sector_t *sec) { - if (sec->floorpic_angle) + if (sec->floorangle) { - fixed_t pc = FINECOSINE(sec->floorpic_angle >> ANGLETOFINESHIFT); - fixed_t ps = FINESINE(sec->floorpic_angle >> ANGLETOFINESHIFT); - fixed_t xoffs = sec->floor_xoffs; - fixed_t yoffs = sec->floor_yoffs; - sec->floor_xoffs = (FixedMul(xoffs, ps) % MAXFLATSIZE) + (FixedMul(yoffs, pc) % MAXFLATSIZE); - sec->floor_yoffs = (FixedMul(xoffs, pc) % MAXFLATSIZE) - (FixedMul(yoffs, ps) % MAXFLATSIZE); + fixed_t pc = FINECOSINE(sec->floorangle >> ANGLETOFINESHIFT); + fixed_t ps = FINESINE(sec->floorangle >> ANGLETOFINESHIFT); + fixed_t xoffs = sec->floorxoffset; + fixed_t yoffs = sec->flooryoffset; + sec->floorxoffset = (FixedMul(xoffs, ps) % MAXFLATSIZE) + (FixedMul(yoffs, pc) % MAXFLATSIZE); + sec->flooryoffset = (FixedMul(xoffs, pc) % MAXFLATSIZE) - (FixedMul(yoffs, ps) % MAXFLATSIZE); } - if (sec->ceilingpic_angle) + if (sec->ceilingangle) { - fixed_t pc = FINECOSINE(sec->ceilingpic_angle >> ANGLETOFINESHIFT); - fixed_t ps = FINESINE(sec->ceilingpic_angle >> ANGLETOFINESHIFT); - fixed_t xoffs = sec->ceiling_xoffs; - fixed_t yoffs = sec->ceiling_yoffs; - sec->ceiling_xoffs = (FixedMul(xoffs, ps) % MAXFLATSIZE) + (FixedMul(yoffs, pc) % MAXFLATSIZE); - sec->ceiling_yoffs = (FixedMul(xoffs, pc) % MAXFLATSIZE) - (FixedMul(yoffs, ps) % MAXFLATSIZE); + fixed_t pc = FINECOSINE(sec->ceilingangle >> ANGLETOFINESHIFT); + fixed_t ps = FINESINE(sec->ceilingangle >> ANGLETOFINESHIFT); + fixed_t xoffs = sec->ceilingxoffset; + fixed_t yoffs = sec->ceilingyoffset; + sec->ceilingxoffset = (FixedMul(xoffs, ps) % MAXFLATSIZE) + (FixedMul(yoffs, pc) % MAXFLATSIZE); + sec->ceilingyoffset = (FixedMul(xoffs, pc) % MAXFLATSIZE) - (FixedMul(yoffs, ps) % MAXFLATSIZE); } } @@ -2359,8 +2463,12 @@ static void P_WriteTextmap(void) fprintf(f, "roll = %d;\n", wmapthings[i].roll); if (wmapthings[i].type != 0) fprintf(f, "type = %d;\n", wmapthings[i].type); + if (wmapthings[i].spritexscale != FRACUNIT) + fprintf(f, "scalex = %f;\n", FIXED_TO_FLOAT(wmapthings[i].spritexscale)); + if (wmapthings[i].spriteyscale != FRACUNIT) + fprintf(f, "scaley = %f;\n", FIXED_TO_FLOAT(wmapthings[i].spriteyscale)); if (wmapthings[i].scale != FRACUNIT) - fprintf(f, "scale = %f;\n", FIXED_TO_FLOAT(wmapthings[i].scale)); + fprintf(f, "mobjscale = %f;\n", FIXED_TO_FLOAT(wmapthings[i].scale)); if (wmapthings[i].options & MTF_OBJECTFLIP) fprintf(f, "flip = true;\n"); for (j = 0; j < NUMMAPTHINGARGS; j++) @@ -2562,18 +2670,18 @@ static void P_WriteTextmap(void) } sector_t tempsec = wsectors[i]; TextmapUnfixFlatOffsets(&tempsec); - if (tempsec.floor_xoffs != 0) - fprintf(f, "xpanningfloor = %f;\n", FIXED_TO_FLOAT(tempsec.floor_xoffs)); - if (tempsec.floor_yoffs != 0) - fprintf(f, "ypanningfloor = %f;\n", FIXED_TO_FLOAT(tempsec.floor_yoffs)); - if (tempsec.ceiling_xoffs != 0) - fprintf(f, "xpanningceiling = %f;\n", FIXED_TO_FLOAT(tempsec.ceiling_xoffs)); - if (tempsec.ceiling_yoffs != 0) - fprintf(f, "ypanningceiling = %f;\n", FIXED_TO_FLOAT(tempsec.ceiling_yoffs)); - if (wsectors[i].floorpic_angle != 0) - fprintf(f, "rotationfloor = %f;\n", FIXED_TO_FLOAT(AngleFixed(wsectors[i].floorpic_angle))); - if (wsectors[i].ceilingpic_angle != 0) - fprintf(f, "rotationceiling = %f;\n", FIXED_TO_FLOAT(AngleFixed(wsectors[i].ceilingpic_angle))); + if (tempsec.floorxoffset != 0) + fprintf(f, "xpanningfloor = %f;\n", FIXED_TO_FLOAT(tempsec.floorxoffset)); + if (tempsec.flooryoffset != 0) + fprintf(f, "ypanningfloor = %f;\n", FIXED_TO_FLOAT(tempsec.flooryoffset)); + if (tempsec.ceilingxoffset != 0) + fprintf(f, "xpanningceiling = %f;\n", FIXED_TO_FLOAT(tempsec.ceilingxoffset)); + if (tempsec.ceilingyoffset != 0) + fprintf(f, "ypanningceiling = %f;\n", FIXED_TO_FLOAT(tempsec.ceilingyoffset)); + if (wsectors[i].floorangle != 0) + fprintf(f, "rotationfloor = %f;\n", FIXED_TO_FLOAT(AngleFixed(wsectors[i].floorangle))); + if (wsectors[i].ceilingangle != 0) + fprintf(f, "rotationceiling = %f;\n", FIXED_TO_FLOAT(AngleFixed(wsectors[i].ceilingangle))); if (wsectors[i].extra_colormap) { INT32 lightcolor = P_RGBAToColor(wsectors[i].extra_colormap->rgba); @@ -2743,6 +2851,15 @@ static void P_WriteTextmap(void) Z_Free(wlines); Z_Free(wsides); Z_Free(specialthings); + + if (contextdrift) + { + CONS_Alert( + CONS_WARNING, M_GetText( + "Some elements of this level are vulnerable to context drift." + "Please check the console log for more information.\n") + ); + } } /** Loads the textmap data, after obtaining the elements count and allocating their respective space. @@ -2793,10 +2910,10 @@ static void P_LoadTextmap(void) sc->special = 0; Tag_FSet(&sc->tags, 0); - sc->floor_xoffs = sc->floor_yoffs = 0; - sc->ceiling_xoffs = sc->ceiling_yoffs = 0; + sc->floorxoffset = sc->flooryoffset = 0; + sc->ceilingxoffset = sc->ceilingyoffset = 0; - sc->floorpic_angle = sc->ceilingpic_angle = 0; + sc->floorangle = sc->ceilingangle = 0; sc->floorlightlevel = sc->ceilinglightlevel = 0; sc->floorlightabsolute = sc->ceilinglightabsolute = false; @@ -2911,6 +3028,7 @@ static void P_LoadTextmap(void) mt->extrainfo = 0; Tag_FSet(&mt->tags, 0); mt->scale = FRACUNIT; + mt->spritexscale = mt->spriteyscale = FRACUNIT; memset(mt->args, 0, NUMMAPTHINGARGS*sizeof(*mt->args)); memset(mt->stringargs, 0x00, NUMMAPTHINGSTRINGARGS*sizeof(*mt->stringargs)); mt->mobj = NULL; @@ -2938,15 +3056,20 @@ static void P_ProcessLinedefsAfterSidedefs(void) case 332: // Trigger linedef executor: Skin - Each time case 333: // Trigger linedef executor: Skin - Once case 443: // Calls a named Lua function - if (sides[ld->sidenum[0]].text) + if (ld->stringargs[0] && ld->stringargs[1]) { - size_t len = strlen(sides[ld->sidenum[0]].text) + 1; - if (ld->sidenum[1] != 0xffff && sides[ld->sidenum[1]].text) - len += strlen(sides[ld->sidenum[1]].text); - ld->text = Z_Malloc(len, PU_LEVEL, NULL); - M_Memcpy(ld->text, sides[ld->sidenum[0]].text, strlen(sides[ld->sidenum[0]].text) + 1); - if (ld->sidenum[1] != 0xffff && sides[ld->sidenum[1]].text) - M_Memcpy(ld->text + strlen(ld->text) + 1, sides[ld->sidenum[1]].text, strlen(sides[ld->sidenum[1]].text) + 1); + size_t len[2]; + len[0] = strlen(ld->stringargs[0]); + len[1] = strlen(ld->stringargs[1]); + + if (len[1]) + { + ld->stringargs[0] = Z_Realloc(ld->stringargs[0], len[0] + len[1] + 1, PU_LEVEL, NULL); + M_Memcpy(ld->stringargs[0] + len[0] + 1, ld->stringargs[1], len[1] + 1); + } + + Z_Free(ld->stringargs[1]); + ld->stringargs[1] = NULL; } break; case 447: // Change colormap @@ -3234,10 +3357,17 @@ static nodetype_t P_GetNodetype(const virtres_t *virt, UINT8 **nodedata) nodetype_t nodetype = NT_UNSUPPORTED; char signature[4 + 1]; + *nodedata = NULL; + if (udmf) { - *nodedata = vres_Find(virt, "ZNODES")->data; - supported[NT_XGLN] = supported[NT_XGL3] = true; + virtlump_t *virtznodes = vres_Find(virt, "ZNODES"); + + if (virtznodes && virtznodes->size) + { + *nodedata = virtznodes->data; + supported[NT_XGLN] = supported[NT_XGL3] = true; + } } else { @@ -3246,24 +3376,39 @@ static nodetype_t P_GetNodetype(const virtres_t *virt, UINT8 **nodedata) if (virtsegs && virtsegs->size) { - *nodedata = vres_Find(virt, "NODES")->data; - return NT_DOOM; // Traditional map format BSP tree. - } - - virtssectors = vres_Find(virt, "SSECTORS"); - - if (virtssectors && virtssectors->size) - { // Possibly GL nodes: NODES ignored, SSECTORS takes precedence as nodes lump, (It is confusing yeah) and has a signature. - *nodedata = virtssectors->data; - supported[NT_XGLN] = supported[NT_ZGLN] = supported[NT_XGL3] = true; + virtlump_t *virtnodes = vres_Find(virt, "NODES"); + if (virtnodes && virtnodes->size) + { + *nodedata = virtnodes->data; + return NT_DOOM; // Traditional map format BSP tree. + } } else - { // Possibly ZDoom extended nodes: SSECTORS is empty, NODES has a signature. - *nodedata = vres_Find(virt, "NODES")->data; - supported[NT_XNOD] = supported[NT_ZNOD] = true; + { + virtssectors = vres_Find(virt, "SSECTORS"); + + if (virtssectors && virtssectors->size) + { // Possibly GL nodes: NODES ignored, SSECTORS takes precedence as nodes lump, (It is confusing yeah) and has a signature. + *nodedata = virtssectors->data; + supported[NT_XGLN] = supported[NT_ZGLN] = supported[NT_XGL3] = true; + } + else + { // Possibly ZDoom extended nodes: SSECTORS is empty, NODES has a signature. + virtlump_t *virtnodes = vres_Find(virt, "NODES"); + if (virtnodes && virtnodes->size) + { + *nodedata = virtnodes->data; + supported[NT_XNOD] = supported[NT_ZNOD] = true; + } + } } } + if (*nodedata == NULL) + { + I_Error("Level has no nodes (does your map have at least 2 sectors?)"); + } + M_Memcpy(signature, *nodedata, 4); signature[4] = '\0'; (*nodedata) += 4; @@ -4040,14 +4185,6 @@ static void P_AddBinaryMapTags(void) } } -static void P_WriteConstant(INT32 constant, char **target) -{ - char buffer[12]; - sprintf(buffer, "%d", constant); - *target = Z_Malloc(strlen(buffer) + 1, PU_LEVEL, NULL); - M_Memcpy(*target, buffer, strlen(buffer) + 1); -} - static line_t *P_FindPointPushLine(taglist_t *list) { INT32 i, l; @@ -4190,7 +4327,6 @@ static void P_ConvertBinaryLinedefTypes(void) lines[i].args[1] |= TMSP_NOTELEPORT; if (lines[i].flags & ML_WRAPMIDTEX) lines[i].args[1] |= TMSP_FORCESPIN; - P_WriteConstant(sides[lines[i].sidenum[0]].toptexture ? sides[lines[i].sidenum[0]].toptexture : sfx_spdpad, &lines[i].stringargs[0]); break; case 7: //Sector flat alignment lines[i].args[0] = tag; @@ -4276,8 +4412,6 @@ static void P_ConvertBinaryLinedefTypes(void) lines[i].args[0] = sides[lines[i].sidenum[0]].textureoffset >> FRACBITS; lines[i].args[1] = sides[lines[i].sidenum[0]].rowoffset >> FRACBITS; lines[i].args[2] = !!(lines[i].flags & ML_SKEWTD); - if (sides[lines[i].sidenum[0]].toptexture) - P_WriteConstant(sides[lines[i].sidenum[0]].toptexture, &lines[i].stringargs[0]); break; case 16: //Minecart parameters lines[i].args[0] = sides[lines[i].sidenum[0]].textureoffset >> FRACBITS; @@ -4740,7 +4874,7 @@ static void P_ConvertBinaryLinedefTypes(void) lines[i].args[2] = 16; } if (lines[i].flags & ML_MIDSOLID) - P_WriteConstant(sides[lines[i].sidenum[0]].textureoffset >> FRACBITS, &lines[i].stringargs[0]); + P_WriteSfx(sides[lines[i].sidenum[0]].textureoffset >> FRACBITS, &lines[i].stringargs[0]); break; case 252: //FOF: Shatter block case 253: //FOF: Shatter block, translucent @@ -5007,11 +5141,6 @@ static void P_ConvertBinaryLinedefTypes(void) else lines[i].args[0] = TMT_CONTINUOUS; lines[i].args[1] = !!(lines[i].flags & ML_NOCLIMB); - if (lines[i].text) - { - lines[i].stringargs[0] = Z_Malloc(strlen(lines[i].text) + 1, PU_LEVEL, NULL); - M_Memcpy(lines[i].stringargs[0], lines[i].text, strlen(lines[i].text) + 1); - } lines[i].special = 331; break; case 334: // Object dye - continuous @@ -5024,11 +5153,6 @@ static void P_ConvertBinaryLinedefTypes(void) else lines[i].args[0] = TMT_CONTINUOUS; lines[i].args[1] = !!(lines[i].flags & ML_NOCLIMB); - if (sides[lines[i].sidenum[0]].text) - { - lines[i].stringargs[0] = Z_Malloc(strlen(sides[lines[i].sidenum[0]].text) + 1, PU_LEVEL, NULL); - M_Memcpy(lines[i].stringargs[0], sides[lines[i].sidenum[0]].text, strlen(sides[lines[i].sidenum[0]].text) + 1); - } lines[i].special = 334; break; case 337: //Emerald check - continuous @@ -5175,11 +5299,6 @@ static void P_ConvertBinaryLinedefTypes(void) lines[i].args[4] = (lines[i].sidenum[1] != 0xffff) ? sides[lines[i].sidenum[1]].textureoffset >> FRACBITS : 0; lines[i].args[5] = (lines[i].sidenum[1] != 0xffff) ? sides[lines[i].sidenum[1]].rowoffset >> FRACBITS : -1; lines[i].args[6] = sides[lines[i].sidenum[0]].bottomtexture; - if (sides[lines[i].sidenum[0]].text) - { - lines[i].stringargs[0] = Z_Malloc(strlen(sides[lines[i].sidenum[0]].text) + 1, PU_LEVEL, NULL); - M_Memcpy(lines[i].stringargs[0], sides[lines[i].sidenum[0]].text, strlen(sides[lines[i].sidenum[0]].text) + 1); - } break; case 414: //Play sound effect lines[i].args[2] = tag; @@ -5219,11 +5338,6 @@ static void P_ConvertBinaryLinedefTypes(void) lines[i].args[1] = TMSL_EVERYONE; } } - if (sides[lines[i].sidenum[0]].text) - { - lines[i].stringargs[0] = Z_Malloc(strlen(sides[lines[i].sidenum[0]].text) + 1, PU_LEVEL, NULL); - M_Memcpy(lines[i].stringargs[0], sides[lines[i].sidenum[0]].text, strlen(sides[lines[i].sidenum[0]].text) + 1); - } break; case 415: //Run script { @@ -5314,13 +5428,6 @@ static void P_ConvertBinaryLinedefTypes(void) lines[i].args[0] = sides[lines[i].sidenum[0]].textureoffset >> FRACBITS; lines[i].args[1] = !!(lines[i].flags & ML_NOCLIMB); break; - case 425: //Change object state - if (sides[lines[i].sidenum[0]].text) - { - lines[i].stringargs[0] = Z_Malloc(strlen(sides[lines[i].sidenum[0]].text) + 1, PU_LEVEL, NULL); - M_Memcpy(lines[i].stringargs[0], sides[lines[i].sidenum[0]].text, strlen(sides[lines[i].sidenum[0]].text) + 1); - } - break; case 426: //Stop object lines[i].args[0] = !!(lines[i].flags & ML_NOCLIMB); break; @@ -5360,18 +5467,18 @@ static void P_ConvertBinaryLinedefTypes(void) lines[i].args[2] = !!(lines[i].flags & ML_BLOCKMONSTERS); break; case 434: //Award power-up - if (sides[lines[i].sidenum[0]].text) + if ((lines[i].flags & ML_BLOCKMONSTERS) == 0) { - lines[i].stringargs[0] = Z_Malloc(strlen(sides[lines[i].sidenum[0]].text) + 1, PU_LEVEL, NULL); - M_Memcpy(lines[i].stringargs[0], sides[lines[i].sidenum[0]].text, strlen(sides[lines[i].sidenum[0]].text) + 1); - } - if (lines[i].sidenum[1] != 0xffff && lines[i].flags & ML_BLOCKMONSTERS) // read power from back sidedef - { - lines[i].stringargs[1] = Z_Malloc(strlen(sides[lines[i].sidenum[1]].text) + 1, PU_LEVEL, NULL); - M_Memcpy(lines[i].stringargs[1], sides[lines[i].sidenum[1]].text, strlen(sides[lines[i].sidenum[1]].text) + 1); + // do NOT read power from back sidedef if this flag is not present + if (lines[i].stringargs[1] != NULL) + { + Z_Free(lines[i].stringargs[1]); + lines[i].stringargs[1] = NULL; + } + + // Instead... write the desired time! + P_WriteTics((lines[i].flags & ML_NOCLIMB) ? -1 : (sides[lines[i].sidenum[0]].textureoffset >> FRACBITS), &lines[i].stringargs[1]); } - else - P_WriteConstant((lines[i].flags & ML_NOCLIMB) ? -1 : (sides[lines[i].sidenum[0]].textureoffset >> FRACBITS), &lines[i].stringargs[1]); break; case 435: //Change plane scroller direction lines[i].args[0] = tag; @@ -5399,30 +5506,10 @@ static void P_ConvertBinaryLinedefTypes(void) break; case 442: //Change object type state lines[i].args[0] = tag; - if (sides[lines[i].sidenum[0]].text) - { - lines[i].stringargs[0] = Z_Malloc(strlen(sides[lines[i].sidenum[0]].text) + 1, PU_LEVEL, NULL); - M_Memcpy(lines[i].stringargs[0], sides[lines[i].sidenum[0]].text, strlen(sides[lines[i].sidenum[0]].text) + 1); - } - if (lines[i].sidenum[1] == 0xffff) - lines[i].args[1] = 1; - else - { - lines[i].args[1] = 0; - if (sides[lines[i].sidenum[1]].text) - { - lines[i].stringargs[1] = Z_Malloc(strlen(sides[lines[i].sidenum[1]].text) + 1, PU_LEVEL, NULL); - M_Memcpy(lines[i].stringargs[1], sides[lines[i].sidenum[1]].text, strlen(sides[lines[i].sidenum[1]].text) + 1); - } - } + lines[i].args[1] = (lines[i].sidenum[1] == 0xffff) ? 1 : 0; break; case 443: //Call Lua function - if (lines[i].text) - { - lines[i].stringargs[0] = Z_Malloc(strlen(lines[i].text) + 1, PU_LEVEL, NULL); - M_Memcpy(lines[i].stringargs[0], lines[i].text, strlen(lines[i].text) + 1); - } - else + if (lines[i].stringargs[0] == NULL) CONS_Alert(CONS_WARNING, "Linedef %s is missing the hook name of the Lua function to call! (This should be given in the front texture fields)\n", sizeu1(i)); break; case 444: //Earthquake @@ -5575,11 +5662,6 @@ static void P_ConvertBinaryLinedefTypes(void) if (lines[i].flags & ML_MIDSOLID) lines[i].args[2] |= TMP_FREEZETHINKERS;*/ lines[i].args[3] = (lines[i].sidenum[1] != 0xFFFF) ? sides[lines[i].sidenum[1]].textureoffset >> FRACBITS : tag; - if (sides[lines[i].sidenum[0]].text) - { - lines[i].stringargs[0] = Z_Malloc(strlen(sides[lines[i].sidenum[0]].text) + 1, PU_LEVEL, NULL); - M_Memcpy(lines[i].stringargs[0], sides[lines[i].sidenum[0]].text, strlen(sides[lines[i].sidenum[0]].text) + 1); - } break; case 460: //Award rings lines[i].args[0] = sides[lines[i].sidenum[0]].textureoffset >> FRACBITS; @@ -5607,18 +5689,6 @@ static void P_ConvertBinaryLinedefTypes(void) } else lines[i].args[4] = 0; - if (sides[lines[i].sidenum[0]].text) - { - lines[i].stringargs[0] = Z_Malloc(strlen(sides[lines[i].sidenum[0]].text) + 1, PU_LEVEL, NULL); - M_Memcpy(lines[i].stringargs[0], sides[lines[i].sidenum[0]].text, strlen(sides[lines[i].sidenum[0]].text) + 1); - } - break; - case 463: //Dye object - if (sides[lines[i].sidenum[0]].text) - { - lines[i].stringargs[0] = Z_Malloc(strlen(sides[lines[i].sidenum[0]].text) + 1, PU_LEVEL, NULL); - M_Memcpy(lines[i].stringargs[0], sides[lines[i].sidenum[0]].text, strlen(sides[lines[i].sidenum[0]].text) + 1); - } break; case 464: //Trigger egg capsule lines[i].args[0] = tag; @@ -6447,7 +6517,7 @@ static void P_ConvertBinaryThingTypes(void) break; case 543: //Balloon if (mapthings[i].angle > 0) - P_WriteConstant(((mapthings[i].angle - 1) % (numskincolors - 1)) + 1, &mapthings[i].stringargs[0]); + P_WriteSkincolor(((mapthings[i].angle - 1) % (numskincolors - 1)) + 1, &mapthings[i].stringargs[0]); mapthings[i].args[0] = !!(mapthings[i].options & MTF_AMBUSH); break; case 555: //Diagonal yellow spring @@ -6472,22 +6542,22 @@ static void P_ConvertBinaryThingTypes(void) case 706: //Water ambience G case 707: //Water ambience H mapthings[i].args[0] = 35; - P_WriteConstant(sfx_amwtr1 + mapthings[i].type - 700, &mapthings[i].stringargs[0]); + P_WriteSfx(sfx_amwtr1 + mapthings[i].type - 700, &mapthings[i].stringargs[0]); mapthings[i].type = 700; break; case 708: //Disco ambience mapthings[i].args[0] = 512; - P_WriteConstant(sfx_ambint, &mapthings[i].stringargs[0]); + P_WriteSfx(sfx_ambint, &mapthings[i].stringargs[0]); mapthings[i].type = 700; break; case 709: //Volcano ambience mapthings[i].args[0] = 220; - P_WriteConstant(sfx_ambin2, &mapthings[i].stringargs[0]); + P_WriteSfx(sfx_ambin2, &mapthings[i].stringargs[0]); mapthings[i].type = 700; break; case 710: //Machine ambience mapthings[i].args[0] = 24; - P_WriteConstant(sfx_ambmac, &mapthings[i].stringargs[0]); + P_WriteSfx(sfx_ambmac, &mapthings[i].stringargs[0]); mapthings[i].type = 700; break; case 750: //Slope vertex @@ -6550,8 +6620,7 @@ static void P_ConvertBinaryThingTypes(void) mapthings[i].args[3] = sides[lines[j].sidenum[0]].rowoffset >> FRACBITS; mapthings[i].args[4] = lines[j].backsector ? sides[lines[j].sidenum[1]].textureoffset >> FRACBITS : 0; mapthings[i].args[6] = mapthings[i].angle; - if (sides[lines[j].sidenum[0]].toptexture) - P_WriteConstant(sides[lines[j].sidenum[0]].toptexture, &mapthings[i].stringargs[0]); + P_WriteDuplicateText(lines[j].stringargs[0], &mapthings[i].stringargs[0]); break; } case 762: //PolyObject spawn point (crush) @@ -6640,8 +6709,8 @@ static void P_ConvertBinaryThingTypes(void) mapthings[i].args[8] |= TMM_ALWAYSTHINK; if (mapthings[i].type == 1110) { - P_WriteConstant(sides[lines[j].sidenum[0]].toptexture, &mapthings[i].stringargs[0]); - P_WriteConstant(lines[j].backsector ? sides[lines[j].sidenum[1]].toptexture : MT_NULL, &mapthings[i].stringargs[1]); + P_WriteDuplicateText(lines[j].stringargs[0], &mapthings[i].stringargs[0]); + P_WriteDuplicateText(lines[j].stringargs[1], &mapthings[i].stringargs[1]); } break; } @@ -6682,7 +6751,13 @@ static void P_ConvertBinaryThingTypes(void) mapthings[i].args[0] = P_AproxDistance(lines[j].dx, lines[j].dy) >> FRACBITS; mapthings[i].args[1] = sides[lines[j].sidenum[0]].textureoffset >> FRACBITS; mapthings[i].args[2] = !!(lines[j].flags & ML_NOCLIMB); - P_WriteConstant(MT_ROCKCRUMBLE1 + (sides[lines[j].sidenum[0]].rowoffset >> FRACBITS), &mapthings[i].stringargs[0]); + INT32 id = (sides[lines[j].sidenum[0]].rowoffset >> FRACBITS); + // Rather than introduce deh_tables.h as a dependency for literally one + // conversion, we just... recreate the string expected to be produced. + if (id > 0 && id < 16) + P_WriteDuplicateText(va("MT_ROCKCRUMBLE%d", id+1), &mapthings[i].stringargs[0]); + else + P_WriteConstant(MT_ROCKCRUMBLE1 + id, &mapthings[i].stringargs[0], "Mapthing", i); break; } case 1221: //Minecart saloon door @@ -6774,6 +6849,9 @@ static void P_ConvertBinaryThingTypes(void) default: break; } + + // Clear binary thing height hacks, to prevent interfering with UDMF-only flags + mapthings[i].options &= 0xF; } } @@ -6815,6 +6893,7 @@ static void P_ConvertBinaryLinedefFlags(void) //For maps in binary format, converts setup of specials to UDMF format. static void P_ConvertBinaryMap(void) { + contextdrift = false; P_ConvertBinaryLinedefTypes(); P_ConvertBinarySectorTypes(); P_ConvertBinaryThingTypes(); @@ -7014,7 +7093,7 @@ static void P_InitLevelSettings(void) stagefailed = G_IsSpecialStage(gamemap); // Reset temporary record data - memset(&ntemprecords, 0, sizeof(nightsdata_t)); + memset(&ntemprecords, 0, sizeof(ntemprecords)); // earthquake camera memset(&quake,0,sizeof(struct quake)); @@ -7465,6 +7544,7 @@ static void P_RunSpecialStageWipe(void) lastwipetic = nowtime; if (moviemode) // make sure we save frames for the white hold too M_SaveFrame(); + NetKeepAlive(); // Prevent timeout } } @@ -7769,18 +7849,6 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate) R_InitMobjInterpolators(); P_InitCachedActions(); - if (!fromnetsave && savedata.lives > 0) - { - numgameovers = savedata.numgameovers; - players[consoleplayer].continues = savedata.continues; - players[consoleplayer].lives = savedata.lives; - players[consoleplayer].score = savedata.score; - if ((botingame = ((botskin = savedata.botskin) != 0))) - botcolor = skins[botskin-1].prefcolor; - emeralds = savedata.emeralds; - savedata.lives = 0; - } - // internal game map maplumpname = G_BuildMapName(gamemap); lastloadedmaplumpnum = W_CheckNumForMap(maplumpname); @@ -8212,7 +8280,7 @@ static boolean P_LoadAddon(UINT16 numlumps) { CONS_Printf(M_GetText("Current map %d replaced by added file, ending the level to ensure consistency.\n"), gamemap); if (server) - SendNetXCmd(XD_EXITLEVEL, NULL, 0); + D_SendExitLevel(false); } return true; diff --git a/src/p_slopes.c b/src/p_slopes.c index 48a13a07d61bc88b45a67ce4d5a0e181b31b53f6..1c0ee81a7e9453d204049d2f0ab5986a07849edb 100644 --- a/src/p_slopes.c +++ b/src/p_slopes.c @@ -328,7 +328,7 @@ static void line_SpawnViaLine(const int linenum, const boolean spawnthinker) if(!frontfloor && !backfloor && !frontceil && !backceil) { - CONS_Printf("line_SpawnViaLine: Slope special with nothing to do.\n"); + CONS_Printf("line_SpawnViaLine: Unused slope special with nothing to do on line number %i\n", linenum); return; } @@ -566,6 +566,7 @@ static void line_SpawnViaMapthingVertexes(const int linenum, const boolean spawn case TMSP_BACKCEILING: slopetoset = &line->backsector->c_slope; side = &sides[line->sidenum[1]]; + break; default: return; } @@ -899,6 +900,8 @@ void P_HandleSlopeLanding(mobj_t *thing, pslope_t *slope) if (P_MobjFlip(thing)*(thing->momz) < 0) // falling, land on slope { thing->standingslope = slope; + P_SetPitchRollFromSlope(thing, slope); + if (!thing->player || !(thing->player->pflags & PF_BOUNCING)) thing->momz = -P_MobjFlip(thing); } @@ -915,6 +918,7 @@ void P_HandleSlopeLanding(mobj_t *thing, pslope_t *slope) thing->momx = mom.x; thing->momy = mom.y; thing->standingslope = slope; + P_SetPitchRollFromSlope(thing, slope); if (!thing->player || !(thing->player->pflags & PF_BOUNCING)) thing->momz = -P_MobjFlip(thing); } diff --git a/src/p_spec.c b/src/p_spec.c index 71ea145b9e79372102e0c2d9746d35a86d27c141..28ecc60f4dedb5f67f9aa33e092232eb0b3782f6 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -1741,14 +1741,13 @@ static boolean P_ActivateLinedefExecutorsInSector(line_t *triggerline, mobj_t *a /** Used by P_LinedefExecute to check a trigger linedef's conditions * The linedef executor specials in the trigger linedef's sector are run if all conditions are met. - * Return false cancels P_LinedefExecute, this happens if a condition is not met. * * \param triggerline Trigger linedef to check conditions for; should NEVER be NULL. * \param actor Object initiating the action; should not be NULL. * \param caller Sector in which the action was started. May be NULL. * \sa P_ProcessLineSpecial, P_LinedefExecute */ -boolean P_RunTriggerLinedef(line_t *triggerline, mobj_t *actor, sector_t *caller) +void P_RunTriggerLinedef(line_t *triggerline, mobj_t *actor, sector_t *caller) { INT16 specialtype = triggerline->special; @@ -1761,12 +1760,12 @@ boolean P_RunTriggerLinedef(line_t *triggerline, mobj_t *actor, sector_t *caller if (caller->triggerer == TO_PLAYEREMERALDS) { if (!(ALL7EMERALDS(emeralds))) - return false; + return; } else if (caller->triggerer == TO_PLAYERNIGHTS) { if (!P_CheckPlayerMareOld(triggerline)) - return false; + return; } } @@ -1774,22 +1773,22 @@ boolean P_RunTriggerLinedef(line_t *triggerline, mobj_t *actor, sector_t *caller { case 303: if (!P_CheckPlayerRings(triggerline, actor)) - return false; + return; break; case 305: if (!(actor && actor->player && actor->player->charability == triggerline->args[1])) - return false; + return; break; case 309: // Only red/blue team members can activate this. if (!(actor && actor->player)) - return false; + return; if (actor->player->ctfteam != ((triggerline->args[1] == TMT_RED) ? 1 : 2)) - return false; + return; break; case 314: if (!P_CheckPushables(triggerline, caller)) - return false; + return; break; case 317: { // Unlockable triggers required @@ -1798,23 +1797,23 @@ boolean P_RunTriggerLinedef(line_t *triggerline, mobj_t *actor, sector_t *caller if (trigid < 0 || trigid > 31) // limited by 32 bit variable { CONS_Debug(DBG_GAMELOGIC, "Unlockable trigger (sidedef %hu): bad trigger ID %d\n", triggerline->sidenum[0], trigid); - return false; + return; } else if (!(unlocktriggers & (1 << trigid))) - return false; + return; } break; case 319: { // An unlockable itself must be unlocked! INT32 unlockid = triggerline->args[1]; - if (unlockid < 0 || unlockid >= MAXUNLOCKABLES) // limited by unlockable count + if (unlockid <= 0 || unlockid > MAXUNLOCKABLES) // limited by unlockable count { CONS_Debug(DBG_GAMELOGIC, "Unlockable check (sidedef %hu): bad unlockable ID %d\n", triggerline->sidenum[0], unlockid); - return false; + return; } else if (!(serverGamedata->unlocked[unlockid-1])) - return false; + return; } break; case 321: @@ -1822,7 +1821,7 @@ boolean P_RunTriggerLinedef(line_t *triggerline, mobj_t *actor, sector_t *caller if (triggerline->callcount > 0) { if (--triggerline->callcount > 0) - return false; + return; } break; case 323: // nightserize @@ -1830,15 +1829,15 @@ boolean P_RunTriggerLinedef(line_t *triggerline, mobj_t *actor, sector_t *caller case 327: // nights lap case 329: // nights egg capsule touch if (!P_CheckNightsTriggerLine(triggerline, actor)) - return false; + return; break; case 331: if (!(actor && actor->player)) - return false; + return; if (!triggerline->stringargs[0]) - return false; + return; if (!(stricmp(triggerline->stringargs[0], skins[actor->player->skin].name) == 0) ^ !!(triggerline->args[1])) - return false; + return; break; case 334: // object dye { @@ -1846,22 +1845,22 @@ boolean P_RunTriggerLinedef(line_t *triggerline, mobj_t *actor, sector_t *caller UINT16 color = (actor->player ? actor->player->powers[pw_dye] : actor->color); if (!!(triggerline->args[1]) ^ (triggercolor != color)) - return false; + return; } break; case 337: // emerald check if (!P_CheckEmeralds(triggerline->args[2], (UINT16)triggerline->args[1])) - return false; + return; break; case 340: // NiGHTS mare if (!P_CheckPlayerMare(triggerline)) - return false; + return; break; case 343: // gravity check if (triggerline->args[1] == TMG_TEMPREVERSE && (!(actor->flags2 & MF2_OBJECTFLIP) != !(actor->player->powers[pw_gravityboots]))) - return false; + return; if ((triggerline->args[1] == TMG_NORMAL) != !(actor->eflags & MFE_VERTICALFLIP)) - return false; + return; break; default: break; @@ -1872,7 +1871,7 @@ boolean P_RunTriggerLinedef(line_t *triggerline, mobj_t *actor, sector_t *caller ///////////////////////////////// if (!P_ActivateLinedefExecutorsInSector(triggerline, actor, caller)) - return false; + return; // "Trigger on X calls" linedefs reset if args[2] is set if (specialtype == 321 && triggerline->args[2]) @@ -1905,8 +1904,6 @@ boolean P_RunTriggerLinedef(line_t *triggerline, mobj_t *actor, sector_t *caller && triggerline->args[0] == TMT_ONCE) triggerline->special = 0; } - - return true; } /** Runs a linedef executor. @@ -1959,8 +1956,7 @@ void P_LinedefExecute(INT16 tag, mobj_t *actor, sector_t *caller) if (lines[masterline].special == 321 && lines[masterline].args[0] > TMXT_EACHTIMEMASK) // Trigger after X calls continue; - if (!P_RunTriggerLinedef(&lines[masterline], actor, caller)) - return; // cancel P_LinedefExecute if function returns false + P_RunTriggerLinedef(&lines[masterline], actor, caller); // Even if it fails, there might be more linedefs to trigger } } @@ -2565,11 +2561,13 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) // Change the music and apply position/fade operations else { - if (!line->stringargs[0]) - break; - - strncpy(mapmusname, line->stringargs[0], 7); - mapmusname[6] = 0; + if (!line->stringargs[0] || !strcmp(line->stringargs[0], "-")) + strcpy(mapmusname, ""); + else + { + strncpy(mapmusname, line->stringargs[0], 7); + mapmusname[6] = 0; + } mapmusflags = tracknum & MUSIC_TRACKMASK; if (!(line->args[0] & TMM_NORELOAD)) @@ -2661,10 +2659,13 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) // This is not revoked until overwritten; awayviewtics is ignored if (titlemapinaction) titlemapcameraref = altview; - else - { + else if (!mo->player->awayviewtics || mo->player->awayviewmobj != altview) { P_SetTarget(&mo->player->awayviewmobj, altview); - mo->player->awayviewtics = line->args[1]; + + if (mo->player == &players[displayplayer]) + P_ResetCamera(mo->player, &camera); // reset p1 camera on p1 getting an awayviewmobj + else if (splitscreen && mo->player == &players[secondarydisplayplayer]) + P_ResetCamera(mo->player, &camera2); // reset p2 camera on p2 getting an awayviewmobj } aim = udmf ? altview->spawnpoint->pitch : line->args[2]; @@ -2674,8 +2675,10 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) aim <<= 8; if (titlemapinaction) titlemapcameraref->cusval = (angle_t)aim; - else + else { mo->player->awayviewaiming = (angle_t)aim; + mo->player->awayviewtics = line->args[1]; + } } break; @@ -3283,19 +3286,18 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) foundrover = true; // If fading an invisible FOF whose render flags we did not yet set, - // initialize its alpha to 1 - // for relative alpha calc + // initialize its alpha to 0 for relative alpha calculation if (!(line->args[3] & TMST_DONTDOTRANSLUCENT) && // do translucent (rover->spawnflags & FOF_NOSHADE) && // do not include light blocks, which don't set FOF_NOSHADE !(rover->spawnflags & FOF_RENDERSIDES) && !(rover->spawnflags & FOF_RENDERPLANES) && !(rover->fofflags & FOF_RENDERALL)) - rover->alpha = 1; + rover->alpha = 0; P_RemoveFakeFloorFader(rover); P_FadeFakeFloor(rover, rover->alpha, - max(1, min(256, (line->args[3] & TMST_RELATIVE) ? rover->alpha + destvalue : destvalue)), + max(0, min(255, (line->args[3] & TMST_RELATIVE) ? rover->alpha + destvalue : destvalue)), 0, // set alpha immediately false, NULL, // tic-based logic false, // do not handle FOF_EXISTS @@ -3369,19 +3371,18 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) else { // If fading an invisible FOF whose render flags we did not yet set, - // initialize its alpha to 1 - // for relative alpha calc + // initialize its alpha to 1 for relative alpha calculation if (!(line->args[4] & TMFT_DONTDOTRANSLUCENT) && // do translucent (rover->spawnflags & FOF_NOSHADE) && // do not include light blocks, which don't set FOF_NOSHADE !(rover->spawnflags & FOF_RENDERSIDES) && !(rover->spawnflags & FOF_RENDERPLANES) && !(rover->fofflags & FOF_RENDERALL)) - rover->alpha = 1; + rover->alpha = 0; P_RemoveFakeFloorFader(rover); P_FadeFakeFloor(rover, rover->alpha, - max(1, min(256, (line->args[4] & TMFT_RELATIVE) ? rover->alpha + destvalue : destvalue)), + max(0, min(255, (line->args[4] & TMFT_RELATIVE) ? rover->alpha + destvalue : destvalue)), 0, // set alpha immediately false, NULL, // tic-based logic !(line->args[4] & TMFT_DONTDOEXISTS), // do not handle FOF_EXISTS @@ -5593,17 +5594,17 @@ static ffloor_t *P_AddFakeFloor(sector_t *sec, sector_t *sec2, line_t *master, I fflr->target = sec; fflr->bottomheight = &sec2->floorheight; fflr->bottompic = &sec2->floorpic; - fflr->bottomxoffs = &sec2->floor_xoffs; - fflr->bottomyoffs = &sec2->floor_yoffs; - fflr->bottomangle = &sec2->floorpic_angle; + fflr->bottomxoffs = &sec2->floorxoffset; + fflr->bottomyoffs = &sec2->flooryoffset; + fflr->bottomangle = &sec2->floorangle; // Add the ceiling fflr->topheight = &sec2->ceilingheight; fflr->toppic = &sec2->ceilingpic; fflr->toplightlevel = &sec2->lightlevel; - fflr->topxoffs = &sec2->ceiling_xoffs; - fflr->topyoffs = &sec2->ceiling_yoffs; - fflr->topangle = &sec2->ceilingpic_angle; + fflr->topxoffs = &sec2->ceilingxoffset; + fflr->topyoffs = &sec2->ceilingyoffset; + fflr->topangle = &sec2->ceilingangle; // Add slopes fflr->t_slope = &sec2->c_slope; @@ -6119,16 +6120,16 @@ void P_ApplyFlatAlignment(sector_t *sector, angle_t flatangle, fixed_t xoffs, fi { if (floor) { - sector->floorpic_angle = flatangle; - sector->floor_xoffs += xoffs; - sector->floor_yoffs += yoffs; + sector->floorangle = flatangle; + sector->floorxoffset += xoffs; + sector->flooryoffset += yoffs; } if (ceiling) { - sector->ceilingpic_angle = flatangle; - sector->ceiling_xoffs += xoffs; - sector->ceiling_yoffs += yoffs; + sector->ceilingangle = flatangle; + sector->ceilingxoffset += xoffs; + sector->ceilingyoffset += yoffs; } } @@ -6562,10 +6563,10 @@ void P_SpawnSpecials(boolean fromnetsave) //Cutting options if (ffloorflags & FOF_RENDERALL) { - //If inside is visible, cut inner walls - if ((lines[i].args[1] < 255) || (lines[i].args[3] & TMFA_SPLAT) || (lines[i].args[4] & TMFT_VISIBLEFROMINSIDE)) + //If inside is visible from the outside, cut inner walls + if (lines[i].args[1] < 255 || (lines[i].args[3] & TMFA_SPLAT)) ffloorflags |= FOF_CUTEXTRA|FOF_EXTRA; - else + else if (!(lines[i].args[4] & TMFT_VISIBLEFROMINSIDE)) ffloorflags |= FOF_CUTLEVEL; } @@ -6621,20 +6622,19 @@ void P_SpawnSpecials(boolean fromnetsave) if (lines[i].args[4] & TMFC_SPLAT) ffloorflags |= FOF_SPLAT; - //If inside is visible, cut inner walls - if (lines[i].args[1] < 0xff || (lines[i].args[3] & TMFT_VISIBLEFROMINSIDE) || (lines[i].args[4] & TMFC_SPLAT)) + //If inside is visible from the outside, cut inner walls + if (lines[i].args[1] < 255 || (lines[i].args[4] & TMFC_SPLAT)) ffloorflags |= FOF_CUTEXTRA|FOF_EXTRA; - else - ffloorflags |= FOF_CUTLEVEL; - - //If player can enter it, render insides - if (lines[i].args[3] & TMFT_VISIBLEFROMINSIDE) + //If player can view it from the inside, render insides + else if (lines[i].args[3] & TMFT_VISIBLEFROMINSIDE) { if (ffloorflags & FOF_RENDERPLANES) ffloorflags |= FOF_BOTHPLANES; if (ffloorflags & FOF_RENDERSIDES) ffloorflags |= FOF_ALLSIDES; } + else + ffloorflags |= FOF_CUTLEVEL; P_AddFakeFloorsByLine(i, lines[i].args[1], lines[i].args[2], ffloorflags, secthinkers); if (lines[i].args[4] & TMFC_AIRBOB) @@ -6685,10 +6685,10 @@ void P_SpawnSpecials(boolean fromnetsave) //Cutting options if (ffloorflags & FOF_RENDERALL) { - //If inside is visible, cut inner walls - if ((lines[i].args[1] < 255) || (lines[i].args[3] & TMFA_SPLAT) || (lines[i].args[4] & TMFT_VISIBLEFROMINSIDE)) + //If inside is visible from the outside, cut inner walls + if (lines[i].args[1] < 255 || (lines[i].args[3] & TMFA_SPLAT)) ffloorflags |= FOF_CUTEXTRA|FOF_EXTRA; - else + else if (!(lines[i].args[4] & TMFT_VISIBLEFROMINSIDE)) ffloorflags |= FOF_CUTLEVEL; } @@ -6880,71 +6880,6 @@ void P_SpawnSpecials(boolean fromnetsave) } break; - case 260: // GZDoom-like 3D Floor. - { - UINT8 dtype = lines[i].args[1] & 3; - UINT8 dflags1 = lines[i].args[1] - dtype; - UINT8 dflags2 = lines[i].args[2]; - UINT8 dopacity = lines[i].args[3]; - boolean isfog = false; - - if (dtype == 0) - dtype = 1; - - ffloorflags = FOF_EXISTS; - - if (dflags2 & 1) ffloorflags |= FOF_NOSHADE; // Disable light effects (Means no shadowcast) - if (dflags2 & 2) ffloorflags |= FOF_DOUBLESHADOW; // Restrict light inside (Means doubleshadow) - if (dflags2 & 4) isfog = true; // Fog effect (Explicitly render like a fog block) - - if (dflags1 & 4) ffloorflags |= FOF_BOTHPLANES|FOF_ALLSIDES; // Render-inside - if (dflags1 & 16) ffloorflags |= FOF_INVERTSIDES|FOF_INVERTPLANES; // Invert visibility rules - - // Fog block - if (isfog) - ffloorflags |= FOF_RENDERALL|FOF_CUTEXTRA|FOF_CUTSPRITES|FOF_BOTHPLANES|FOF_EXTRA|FOF_FOG|FOF_INVERTPLANES|FOF_ALLSIDES|FOF_INVERTSIDES; - else - { - ffloorflags |= FOF_RENDERALL; - - // Solid - if (dtype == 1) - ffloorflags |= FOF_SOLID|FOF_CUTLEVEL; - // Water - else if (dtype == 2) - ffloorflags |= FOF_SWIMMABLE|FOF_CUTEXTRA|FOF_CUTSPRITES|FOF_EXTRA|FOF_RIPPLE; - // Intangible - else if (dtype == 3) - ffloorflags |= FOF_CUTEXTRA|FOF_CUTSPRITES|FOF_EXTRA; - } - - // Non-opaque - if (dopacity < 255) - { - // Invisible - if (dopacity == 0) - { - // True invisible - if (ffloorflags & FOF_NOSHADE) - ffloorflags &= ~(FOF_RENDERALL|FOF_CUTEXTRA|FOF_CUTSPRITES|FOF_EXTRA|FOF_BOTHPLANES|FOF_ALLSIDES|FOF_CUTLEVEL); - // Shadow block - else - { - ffloorflags |= FOF_CUTSPRITES; - ffloorflags &= ~(FOF_RENDERALL|FOF_CUTEXTRA|FOF_EXTRA|FOF_BOTHPLANES|FOF_ALLSIDES|FOF_CUTLEVEL); - } - } - else - { - ffloorflags |= FOF_TRANSLUCENT|FOF_CUTEXTRA|FOF_EXTRA; - ffloorflags &= ~FOF_CUTLEVEL; - } - } - - P_AddFakeFloorsByLine(i, dopacity, TMB_TRANSLUCENT, ffloorflags, secthinkers); - } - break; - case 300: // Trigger linedef executor case 303: // Count rings case 305: // Character ability @@ -7363,14 +7298,14 @@ void T_Scroll(scroll_t *s) case sc_floor: // scroll floor texture sec = sectors + s->affectee; - sec->floor_xoffs += dx; - sec->floor_yoffs += dy; + sec->floorxoffset += dx; + sec->flooryoffset += dy; break; case sc_ceiling: // scroll ceiling texture sec = sectors + s->affectee; - sec->ceiling_xoffs += dx; - sec->ceiling_yoffs += dy; + sec->ceilingxoffset += dx; + sec->ceilingyoffset += dy; break; case sc_carry: @@ -7818,15 +7753,14 @@ static boolean P_FadeFakeFloor(ffloor_t *rover, INT16 sourcevalue, INT16 destval if (rover->master->special == 258) // Laser block return false; - // If fading an invisible FOF whose render flags we did not yet set, - // initialize its alpha to 1 + // If fading an invisible FOF whose render flags we did not yet set, initialize its alpha to 1 if (dotranslucent && (rover->spawnflags & FOF_NOSHADE) && // do not include light blocks, which don't set FOF_NOSHADE !(rover->fofflags & FOF_FOG) && // do not include fog !(rover->spawnflags & FOF_RENDERSIDES) && !(rover->spawnflags & FOF_RENDERPLANES) && !(rover->fofflags & FOF_RENDERALL)) - rover->alpha = 1; + rover->alpha = 0; if (fadingdata) alpha = fadingdata->alpha; @@ -7912,7 +7846,7 @@ static boolean P_FadeFakeFloor(ffloor_t *rover, INT16 sourcevalue, INT16 destval { if (doexists && !(rover->spawnflags & FOF_BUSTUP)) { - if (alpha <= 1) + if (alpha <= 0) rover->fofflags &= ~FOF_EXISTS; else rover->fofflags |= FOF_EXISTS; @@ -7924,7 +7858,7 @@ static boolean P_FadeFakeFloor(ffloor_t *rover, INT16 sourcevalue, INT16 destval if (dotranslucent && !(rover->fofflags & FOF_FOG)) { - if (alpha >= 256) + if (alpha >= 255) { if (!(rover->fofflags & FOF_CUTSOLIDS) && (rover->spawnflags & FOF_CUTSOLIDS)) @@ -8024,11 +7958,11 @@ static boolean P_FadeFakeFloor(ffloor_t *rover, INT16 sourcevalue, INT16 destval else // clamp fadingdata->alpha to software's alpha levels { if (alpha < 12) - rover->alpha = destvalue < 12 ? destvalue : 1; // Don't even draw it + rover->alpha = destvalue < 12 ? destvalue : 0; // Don't even draw it else if (alpha < 38) rover->alpha = destvalue >= 12 && destvalue < 38 ? destvalue : 25; else if (alpha < 64) - rover->alpha = destvalue >=38 && destvalue < 64 ? destvalue : 51; + rover->alpha = destvalue >= 38 && destvalue < 64 ? destvalue : 51; else if (alpha < 89) rover->alpha = destvalue >= 64 && destvalue < 89 ? destvalue : 76; else if (alpha < 115) @@ -8044,7 +7978,7 @@ static boolean P_FadeFakeFloor(ffloor_t *rover, INT16 sourcevalue, INT16 destval else if (alpha < 243) rover->alpha = destvalue >= 217 && destvalue < 243 ? destvalue : 230; else // Opaque - rover->alpha = destvalue >= 243 ? destvalue : 256; + rover->alpha = destvalue >= 243 ? destvalue : 255; } } @@ -8074,17 +8008,16 @@ static void P_AddFakeFloorFader(ffloor_t *rover, size_t sectornum, size_t ffloor { fade_t *d; - // If fading an invisible FOF whose render flags we did not yet set, - // initialize its alpha to 1 + // If fading an invisible FOF whose render flags we did not yet set, initialize its alpha to 1 if (dotranslucent && (rover->spawnflags & FOF_NOSHADE) && // do not include light blocks, which don't set FOF_NOSHADE !(rover->spawnflags & FOF_RENDERSIDES) && !(rover->spawnflags & FOF_RENDERPLANES) && !(rover->fofflags & FOF_RENDERALL)) - rover->alpha = 1; + rover->alpha = 0; // already equal, nothing to do - if (rover->alpha == max(1, min(256, relative ? rover->alpha + destvalue : destvalue))) + if (rover->alpha == max(0, min(255, relative ? rover->alpha + destvalue : destvalue))) return; d = Z_Malloc(sizeof *d, PU_LEVSPEC, NULL); @@ -8095,7 +8028,7 @@ static void P_AddFakeFloorFader(ffloor_t *rover, size_t sectornum, size_t ffloor d->ffloornum = (UINT32)ffloornum; d->alpha = d->sourcevalue = rover->alpha; - d->destvalue = max(1, min(256, relative ? rover->alpha + destvalue : destvalue)); // rover->alpha is 1-256 + d->destvalue = max(0, min(255, relative ? rover->alpha + destvalue : destvalue)); // rover->alpha is 0-255 if (ticbased) { diff --git a/src/p_spec.h b/src/p_spec.h index 91dfccb70fabb355f1111f5e38ce9cec35876fca..50ab6410f145b0d2ad180b492525cec51d786365 100644 --- a/src/p_spec.h +++ b/src/p_spec.h @@ -527,7 +527,7 @@ boolean P_IsMobjTouchingPolyobj(mobj_t *mo, polyobj_t *po, sector_t *polysec); void P_SwitchWeather(INT32 weathernum); -boolean P_RunTriggerLinedef(line_t *triggerline, mobj_t *actor, sector_t *caller); +void P_RunTriggerLinedef(line_t *triggerline, mobj_t *actor, sector_t *caller); void P_LinedefExecute(INT16 tag, mobj_t *actor, sector_t *caller); void P_RunNightserizeExecutors(mobj_t *actor); void P_RunDeNightserizeExecutors(mobj_t *actor); @@ -895,7 +895,7 @@ typedef struct typedef enum { - ok, + planeok, crushed, pastdest } result_e; diff --git a/src/p_tick.c b/src/p_tick.c index b1fd367ed94721e5aedab16b3a3e743a6df63425..ec5d8a2da0a487a6e4743e39dedc04c2fb27069d 100644 --- a/src/p_tick.c +++ b/src/p_tick.c @@ -30,6 +30,10 @@ // Object place #include "m_cheat.h" +#ifdef PARANOIA +#include "deh_tables.h" // MOBJTYPE_LIST +#endif + tic_t leveltime; // @@ -211,7 +215,48 @@ void P_AddThinker(const thinklistnum_t n, thinker_t *thinker) thlist[n].prev = thinker; thinker->references = 0; // killough 11/98: init reference counter to 0 + +#ifdef PARANOIA + thinker->debug_mobjtype = MT_NULL; +#endif +} + +#ifdef PARANOIA +static const char *MobjTypeName(const mobj_t *mobj) +{ + actionf_p1 p1 = mobj->thinker.function.acp1; + + if (p1 == (actionf_p1)P_MobjThinker) + { + return MOBJTYPE_LIST[mobj->type]; + } + else if (p1 == (actionf_p1)P_RemoveThinkerDelayed) + { + if (mobj->thinker.debug_mobjtype != MT_NULL) + { + return MOBJTYPE_LIST[mobj->thinker.debug_mobjtype]; + } + } + + return "<Not a mobj>"; +} + +static const char *MobjThinkerName(const mobj_t *mobj) +{ + actionf_p1 p1 = mobj->thinker.function.acp1; + + if (p1 == (actionf_p1)P_MobjThinker) + { + return "P_MobjThinker"; + } + else if (p1 == (actionf_p1)P_RemoveThinkerDelayed) + { + return "P_RemoveThinkerDelayed"; + } + + return "<Unknown Thinker>"; } +#endif // // killough 11/98: @@ -234,20 +279,34 @@ static thinker_t *currentthinker; void P_RemoveThinkerDelayed(thinker_t *thinker) { thinker_t *next; -#ifdef PARANOIA -#define BEENAROUNDBIT (0x40000000) // has to be sufficiently high that it's unlikely to happen in regular gameplay. If you change this, pay attention to the bit pattern of INT32_MIN. - if (thinker->references & ~BEENAROUNDBIT) + + if (thinker->references != 0) { - if (thinker->references & BEENAROUNDBIT) // Usually gets cleared up in one frame; what's going on here, then? - CONS_Printf("Number of potentially faulty references: %d\n", (thinker->references & ~BEENAROUNDBIT)); - thinker->references |= BEENAROUNDBIT; +#ifdef PARANOIA + if (thinker->debug_time > leveltime) + { + thinker->debug_time = leveltime + 2; // do not print errors again + } + // Removed mobjs can be the target of another mobj. In + // that case, the other mobj will manage its reference + // to the removed mobj in P_MobjThinker. However, if + // the removed mobj is removed after the other object + // thinks, the reference management is delayed by one + // tic. + else if (thinker->debug_time < leveltime) + { + CONS_Printf( + "PARANOIA/P_RemoveThinkerDelayed: %p %s references=%d\n", + (void*)thinker, + MobjTypeName((mobj_t*)thinker), + thinker->references + ); + + thinker->debug_time = leveltime + 2; // do not print this error again + } +#endif return; } -#undef BEENAROUNDBIT -#else - if (thinker->references) - return; -#endif /* Remove from main thinker list */ next = thinker->next; @@ -291,12 +350,45 @@ void P_RemoveThinker(thinker_t *thinker) * references, and delay removal until the count is 0. */ -mobj_t *P_SetTarget(mobj_t **mop, mobj_t *targ) +mobj_t *P_SetTarget2(mobj_t **mop, mobj_t *targ +#ifdef PARANOIA + , const char *source_file, int source_line +#endif +) { - if (*mop) // If there was a target already, decrease its refcount + if (*mop) // If there was a target already, decrease its refcount + { (*mop)->thinker.references--; -if ((*mop = targ) != NULL) // Set new target and if non-NULL, increase its counter + +#ifdef PARANOIA + if ((*mop)->thinker.references < 0) + { + CONS_Printf( + "PARANOIA/P_SetTarget: %p %s %s references=%d, references go negative! (%s:%d)\n", + (void*)*mop, + MobjTypeName(*mop), + MobjThinkerName(*mop), + (*mop)->thinker.references, + source_file, + source_line + ); + } + + (*mop)->thinker.debug_time = leveltime; +#endif + } + + if (targ != NULL) // Set new target and if non-NULL, increase its counter + { targ->thinker.references++; + +#ifdef PARANOIA + targ->thinker.debug_time = leveltime; +#endif + } + + *mop = targ; + return targ; } diff --git a/src/p_tick.h b/src/p_tick.h index 594bbc7afb608ce88a54b8f63ae7e5494f96af4f..bbc227e081433652a9a3d79b8ab0513c531677bc 100644 --- a/src/p_tick.h +++ b/src/p_tick.h @@ -14,6 +14,8 @@ #ifndef __P_TICK__ #define __P_TICK__ +#include "doomdef.h" + #ifdef __GNUG__ #pragma interface #endif @@ -28,6 +30,17 @@ void P_Ticker(boolean run); void P_PreTicker(INT32 frames); void P_DoTeamscrambling(void); void P_RemoveThinkerDelayed(thinker_t *thinker); //killed -mobj_t *P_SetTarget(mobj_t **mo, mobj_t *target); // killough 11/98 + +mobj_t *P_SetTarget2(mobj_t **mo, mobj_t *target +#ifdef PARANOIA + , const char *source_file, int source_line +#endif +); + +#ifdef PARANOIA +#define P_SetTarget(...) P_SetTarget2(__VA_ARGS__, __FILE__, __LINE__) +#else +#define P_SetTarget P_SetTarget2 +#endif #endif diff --git a/src/p_user.c b/src/p_user.c index 0f3282da5582f122c9f383ba9509ea28fa6d458a..3b2c60e3a6d744d5da157e0a5952efd5ad0cf3d4 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -398,6 +398,7 @@ void P_GiveFinishFlags(player_t *player) angle += FixedAngle(120*FRACUNIT); P_SetTarget(&flag->target, player->mo); + P_SetTarget(&flag->dontdrawforviewmobj, player->mo); // Hide the flag in first-person } } @@ -676,7 +677,7 @@ static void P_DeNightserizePlayer(player_t *player) player->marebonuslap = 0; player->flyangle = 0; player->anotherflyangle = 0; - player->mo->rollangle = 0; + player->mo->spriteroll = 0; P_SetTarget(&player->mo->target, NULL); P_SetTarget(&player->axis1, P_SetTarget(&player->axis2, NULL)); @@ -802,7 +803,7 @@ void P_NightserizePlayer(player_t *player, INT32 nighttime) player->secondjump = 0; player->flyangle = 0; player->anotherflyangle = 0; - player->mo->rollangle = 0; + player->mo->spriteroll = 0; player->powers[pw_shield] = SH_NONE; player->powers[pw_super] = 0; @@ -882,8 +883,7 @@ void P_NightserizePlayer(player_t *player, INT32 nighttime) } // Add score to leaderboards now - if (!(netgame||multiplayer) && P_IsLocalPlayer(&players[i])) - G_AddTempNightsRecords(players[i].marescore, leveltime - player->marebegunat, players[i].mare + 1); + G_AddTempNightsRecords(player, players[i].marescore, leveltime - player->marebegunat, players[i].mare + 1); // transfer scores anyway players[i].totalmarescore += players[i].marescore; @@ -909,8 +909,7 @@ void P_NightserizePlayer(player_t *player, INT32 nighttime) player->finishedrings = (INT16)(player->rings); // Add score to temp leaderboards - if (!(netgame||multiplayer) && P_IsLocalPlayer(player)) - G_AddTempNightsRecords(player->marescore, leveltime - player->marebegunat, (UINT8)(oldmare + 1)); + G_AddTempNightsRecords(player, player->marescore, leveltime - player->marebegunat, (UINT8)(oldmare + 1)); // Starting a new mare, transfer scores player->totalmarescore += player->marescore; @@ -989,6 +988,8 @@ void P_DoPlayerPain(player_t *player, mobj_t *source, mobj_t *inflictor) if (player->powers[pw_carry] == CR_ROPEHANG) P_SetTarget(&player->mo->tracer, NULL); + player->powers[pw_strong] = STR_NONE; + { angle_t ang; fixed_t fallbackspeed; @@ -1106,6 +1107,7 @@ void P_ResetPlayer(player_t *player) boolean P_PlayerCanDamage(player_t *player, mobj_t *thing) { fixed_t bottomheight, topheight; + boolean allatk = ((player->powers[pw_strong] & STR_PUNCH) && (player->powers[pw_strong] & STR_TAIL) && (player->powers[pw_strong] & STR_STOMP) && (player->powers[pw_strong] & STR_UPPER)); if (!player->mo || player->spectator || !thing || P_MobjWasRemoved(thing)) return false; @@ -1130,22 +1132,33 @@ boolean P_PlayerCanDamage(player_t *player, mobj_t *thing) // Jumping. if ((player->pflags & PF_JUMPED) - && (!(player->pflags & PF_NOJUMPDAMAGE) - || (player->charability == CA_TWINSPIN && player->panim == PA_ABILITY))) + && (!(player->pflags & PF_NOJUMPDAMAGE))) return true; // Spinning. if (player->pflags & PF_SPINNING) return true; - if (player->dashmode >= DASHMODE_THRESHOLD && (player->charflags & (SF_DASHMODE|SF_MACHINE)) == (SF_DASHMODE|SF_MACHINE)) + // Shield stomp. + if (((player->powers[pw_shield] & SH_NOSTACK) == SH_ELEMENTAL || (player->powers[pw_shield] & SH_NOSTACK) == SH_BUBBLEWRAP) && (player->pflags & PF_SHIELDABILITY)) + return true; + + // pw_strong checks below here + + // Omnidirectional attacks. + if (allatk || (player->powers[pw_strong] & STR_DASH)) return true; // From the front. - if (((player->pflags & PF_GLIDING) || (player->charability2 == CA2_MELEE && player->panim == PA_ABILITY2)) + if ((player->powers[pw_strong] & STR_PUNCH) && (player->drawangle - R_PointToAngle2(player->mo->x - player->mo->momx, player->mo->y - player->mo->momy, thing->x, thing->y) + + ANGLE_90) < ANGLE_180) return true; + // From the back. + if ((player->powers[pw_strong] & STR_TAIL) + && (player->drawangle - R_PointToAngle2(player->mo->x - player->mo->momx, player->mo->y - player->mo->momy, thing->x, thing->y) + + ANGLE_90) >= ANGLE_180) + return true; + // From the top/bottom. bottomheight = player->mo->z; topheight = player->mo->z + player->mo->height; @@ -1159,19 +1172,15 @@ boolean P_PlayerCanDamage(player_t *player, mobj_t *thing) if (P_MobjFlip(player->mo)*(bottomheight - (thing->z + thing->height/2)) > 0) { - if ((player->charflags & SF_STOMPDAMAGE || player->pflags & PF_BOUNCING) && (P_MobjFlip(player->mo)*(player->mo->momz - thing->momz) < 0)) + if ((player->charflags & SF_STOMPDAMAGE || player->powers[pw_strong] & STR_STOMP) && (P_MobjFlip(player->mo)*(player->mo->momz - thing->momz) < 0)) return true; } else if (P_MobjFlip(player->mo)*(topheight - (thing->z + thing->height/2)) < 0) { - if (player->charability == CA_FLY && player->panim == PA_ABILITY && !(player->mo->eflags & MFE_UNDERWATER) && (P_MobjFlip(player->mo)*(player->mo->momz - thing->momz) > 0)) + if ((player->powers[pw_strong] & STR_UPPER) && (player->mo->sprite2 != SPR2_SWIM) && (P_MobjFlip(player->mo)*(player->mo->momz - thing->momz) > 0)) return true; } - // Shield stomp. - if (((player->powers[pw_shield] & SH_NOSTACK) == SH_ELEMENTAL || (player->powers[pw_shield] & SH_NOSTACK) == SH_BUBBLEWRAP) && (player->pflags & PF_SHIELDABILITY)) - return true; - return false; } @@ -1430,6 +1439,10 @@ void P_AddPlayerScore(player_t *player, UINT32 amount) if (player->score > MAXSCORE) player->score = MAXSCORE; + player->recordscore += amount; + if (player->recordscore > MAXSCORE) + player->recordscore = MAXSCORE; + // check for extra lives every 50000 pts if (!ultimatemode && !modeattacking && player->score > oldscore && player->score % 50000 < amount && (gametyperules & GTR_LIVES)) { @@ -1828,6 +1841,7 @@ void P_SpawnShieldOrb(player_t *player) shieldobj = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, orbtype); shieldobj->flags2 |= MF2_SHIELD; P_SetTarget(&shieldobj->target, player->mo); + P_SetTarget(&shieldobj->dontdrawforviewmobj, player->mo); // Hide the shield in first-person if ((player->powers[pw_shield] & SH_NOSTACK) == SH_PINK) { shieldobj->color = SKINCOLOR_PINK; @@ -1841,6 +1855,7 @@ void P_SpawnShieldOrb(player_t *player) { ov = P_SpawnMobj(shieldobj->x, shieldobj->y, shieldobj->z, MT_OVERLAY); P_SetTarget(&ov->target, shieldobj); + P_SetTarget(&ov->dontdrawforviewmobj, player->mo); // Hide the shield in first-person P_SetMobjState(ov, shieldobj->info->seestate); P_SetTarget(&shieldobj->tracer, ov); } @@ -1848,12 +1863,14 @@ void P_SpawnShieldOrb(player_t *player) { ov = P_SpawnMobj(shieldobj->x, shieldobj->y, shieldobj->z, MT_OVERLAY); P_SetTarget(&ov->target, shieldobj); + P_SetTarget(&ov->dontdrawforviewmobj, player->mo); // Hide the shield in first-person P_SetMobjState(ov, shieldobj->info->meleestate); } if (shieldobj->info->missilestate) { ov = P_SpawnMobj(shieldobj->x, shieldobj->y, shieldobj->z, MT_OVERLAY); P_SetTarget(&ov->target, shieldobj); + P_SetTarget(&ov->dontdrawforviewmobj, player->mo); // Hide the shield in first-person P_SetMobjState(ov, shieldobj->info->missilestate); } if (player->powers[pw_shield] & SH_FORCE) @@ -1952,6 +1969,7 @@ mobj_t *P_SpawnGhostMobj(mobj_t *mobj) mobj_t *ghost = P_SpawnMobj(mobj->x, mobj->y, mobj->z, MT_GHOST); P_SetTarget(&ghost->target, mobj); + P_SetTarget(&ghost->dontdrawforviewmobj, mobj); // Hide the ghost in first-person P_SetScale(ghost, mobj->scale); ghost->destscale = mobj->scale; @@ -1966,7 +1984,9 @@ mobj_t *P_SpawnGhostMobj(mobj_t *mobj) ghost->colorized = mobj->colorized; // alternatively, "true" for sonic advance style colourisation ghost->angle = (mobj->player ? mobj->player->drawangle : mobj->angle); - ghost->rollangle = mobj->rollangle; + ghost->roll = mobj->roll; + ghost->pitch = mobj->pitch; + ghost->spriteroll = mobj->spriteroll; ghost->sprite = mobj->sprite; ghost->sprite2 = mobj->sprite2; @@ -1985,15 +2005,17 @@ mobj_t *P_SpawnGhostMobj(mobj_t *mobj) ghost->fuse = ghost->info->damage; ghost->skin = mobj->skin; + ghost->standingslope = mobj->standingslope; if (mobj->flags2 & MF2_OBJECTFLIP) - ghost->flags |= MF2_OBJECTFLIP; + ghost->flags2 |= MF2_OBJECTFLIP; if (mobj->player && mobj->player->followmobj) { mobj_t *ghost2 = P_SpawnGhostMobj(mobj->player->followmobj); P_SetTarget(&ghost2->tracer, ghost); P_SetTarget(&ghost->tracer, ghost2); + P_SetTarget(&ghost2->dontdrawforviewmobj, mobj); // Hide the follow-ghost for the non-follow target ghost2->flags2 |= (mobj->player->followmobj->flags2 & MF2_LINKDRAW); } @@ -2004,6 +2026,7 @@ mobj_t *P_SpawnGhostMobj(mobj_t *mobj) ghost->old_angle = (mobj->player ? mobj->player->old_drawangle2 : mobj->old_angle2); ghost->old_pitch = mobj->old_pitch2; ghost->old_roll = mobj->old_roll2; + ghost->old_spriteroll = mobj->old_spriteroll2; return ghost; } @@ -2333,6 +2356,7 @@ boolean P_PlayerHitFloor(player_t *player, boolean dorollstuff) player->mo->tics = (player->mo->movefactor == FRACUNIT) ? TICRATE/2 : (FixedDiv(35<<(FRACBITS-1), FixedSqrt(player->mo->movefactor)))>>FRACBITS; S_StartSound(player->mo, sfx_s3k8b); player->pflags |= PF_FULLSTASIS; + player->powers[pw_strong] = STR_MELEE; // hearticles if (type) @@ -2557,17 +2581,13 @@ static boolean P_PlayerCanBust(player_t *player, ffloor_t *rover) return true; // Passive wall breaking - if (player->charflags & SF_CANBUSTWALLS) + if (player->charflags & SF_CANBUSTWALLS || player->powers[pw_strong] & (STR_WALL|STR_FLOOR|STR_CEILING|STR_DASH)) return true; // Super if (player->powers[pw_super]) return true; - // Dashmode - if ((player->charflags & (SF_DASHMODE|SF_MACHINE)) == (SF_DASHMODE|SF_MACHINE) && player->dashmode >= DASHMODE_THRESHOLD) - return true; - // NiGHTS drill if (player->pflags & PF_DRILLING) return true; @@ -2578,21 +2598,11 @@ static boolean P_PlayerCanBust(player_t *player, ffloor_t *rover) /* FALLTHRU */ case BT_STRONG: // Requires a "strong ability" - if (player->charflags & SF_CANBUSTWALLS) - return true; - - if (player->pflags & PF_BOUNCING) - return true; - - if (player->charability == CA_TWINSPIN && player->panim == PA_ABILITY) - return true; - - if (player->charability2 == CA2_MELEE && player->panim == PA_ABILITY2) + if (player->charflags & SF_CANBUSTWALLS || player->powers[pw_strong] & (STR_WALL|STR_FLOOR|STR_CEILING)) return true; break; } - return false; } @@ -2608,7 +2618,7 @@ static void P_CheckBustableBlocks(player_t *player) oldx = player->mo->x; oldy = player->mo->y; - if (!(player->pflags & PF_BOUNCING)) // Bouncers only get to break downwards, not sideways + if (!((player->powers[pw_strong] & (STR_FLOOR|STR_CEILING)) && (!(player->powers[pw_strong] & STR_WALL)) && (!(player->charflags & SF_CANBUSTWALLS)))) // Don't break sideways without wall powers { P_UnsetThingPosition(player->mo); player->mo->x += player->mo->momx; @@ -2635,8 +2645,24 @@ static void P_CheckBustableBlocks(player_t *player) topheight = P_GetFOFTopZ(player->mo, node->m_sector, rover, player->mo->x, player->mo->y, NULL); bottomheight = P_GetFOFBottomZ(player->mo, node->m_sector, rover, player->mo->x, player->mo->y, NULL); - if (((player->charability == CA_TWINSPIN) && (player->panim == PA_ABILITY)) - || ((P_MobjFlip(player->mo)*player->mo->momz < 0) && (player->pflags & PF_BOUNCING || ((player->charability2 == CA2_MELEE) && (player->panim == PA_ABILITY2))))) + // Height checks + if (player->mo->eflags & MFE_VERTICALFLIP) + { + if ((player->powers[pw_strong] & STR_FLOOR) && (!(player->powers[pw_strong] & STR_CEILING)) && player->mo->z > topheight) + continue; + + if ((player->powers[pw_strong] & STR_CEILING) && (!(player->powers[pw_strong] & STR_FLOOR)) && player->mo->z + player->mo->height < bottomheight) + continue; + } + else + { + if ((player->powers[pw_strong] & STR_FLOOR) && (!(player->powers[pw_strong] & STR_CEILING)) && player->mo->z < bottomheight) + continue; + + if ((player->powers[pw_strong] & STR_CEILING) && (!(player->powers[pw_strong] & STR_FLOOR)) && player->mo->z + player->mo->height > topheight) + continue; + } + if (player->powers[pw_strong] & (STR_FLOOR|STR_CEILING)) { topheight -= player->mo->momz; bottomheight -= player->mo->momz; @@ -2704,7 +2730,7 @@ static void P_CheckBustableBlocks(player_t *player) } } bustupdone: - if (!(player->pflags & PF_BOUNCING)) + if (!((player->powers[pw_strong] & (STR_FLOOR|STR_CEILING)) && (!(player->powers[pw_strong] & STR_WALL)) && (!(player->charflags & SF_CANBUSTWALLS)))) { P_UnsetThingPosition(player->mo); player->mo->x = oldx; @@ -2984,7 +3010,7 @@ static void P_CheckInvincibilityTimer(player_t *player) return; if (mariomode && !player->powers[pw_super]) - player->mo->color = (UINT16)(SKINCOLOR_RUBY + (leveltime % (numskincolors - SKINCOLOR_RUBY))); // Passes through all saturated colours + player->mo->color = (UINT16)(SKINCOLOR_RUBY + (leveltime % (FIRSTSUPERCOLOR - SKINCOLOR_RUBY))); // Passes through all saturated colours else if (leveltime % (TICRATE/7) == 0) { mobj_t *sparkle = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_IVSP); @@ -3104,39 +3130,41 @@ static void P_DoBubbleBreath(player_t *player) // static void P_DoPlayerHeadSigns(player_t *player) { + mobj_t *sign = NULL; + if (G_TagGametype()) { - // If you're "IT", show a big "IT" over your head for others to see. - if (player->pflags & PF_TAGIT && !P_IsLocalPlayer(player)) + // If you're "IT", show a big "IT" over your head for others to see, including spectators + // (and even yourself if you spectate someone else). + if (player->pflags & PF_TAGIT && (!P_IsLocalPlayer(player) || consoleplayer != displayplayer || splitscreen)) { - mobj_t* it = P_SpawnMobjFromMobj(player->mo, 0, 0, 0, MT_TAG); - it->x = player->mo->x; - it->y = player->mo->y; - it->z = player->mo->z; - it->old_x = player->mo->old_x; - it->old_y = player->mo->old_y; - it->old_z = player->mo->old_z; + sign = P_SpawnMobjFromMobj(player->mo, 0, 0, 0, MT_TAG); + sign->x = player->mo->x; + sign->y = player->mo->y; + sign->z = player->mo->z; + sign->old_x = player->mo->old_x; + sign->old_y = player->mo->old_y; + sign->old_z = player->mo->old_z; if (!(player->mo->eflags & MFE_VERTICALFLIP)) { - it->z += player->mo->height; - it->old_z += player->mo->height; + sign->z += player->mo->height; + sign->old_z += player->mo->height; } else { - it->z -= mobjinfo[MT_TAG].height; - it->old_z -= mobjinfo[MT_TAG].height; + sign->z -= mobjinfo[MT_TAG].height; + sign->old_z -= mobjinfo[MT_TAG].height; } } } else if ((gametyperules & GTR_TEAMFLAGS) && (player->gotflag & (GF_REDFLAG|GF_BLUEFLAG))) // If you have the flag (duh). { - // Spawn a got-flag message over the head of the player that - // has it (but not on your own screen if you have the flag). - if (splitscreen || player != &players[consoleplayer]) + // Spawn a got-flag message over the head of the player that has it + // (but not on your own screen if you have the flag, unless you're spectating). + if (!P_IsLocalPlayer(player) || consoleplayer != displayplayer || splitscreen) { fixed_t zofs; - mobj_t *sign; boolean player_is_flipped = (player->mo->eflags & MFE_VERTICALFLIP) > 0; zofs = player->mo->momz; @@ -3168,6 +3196,43 @@ static void P_DoPlayerHeadSigns(player_t *player) sign->frame = 2|FF_FULLBRIGHT; } } + + if (!P_MobjWasRemoved(sign) && splitscreen) // Hide the sign from yourself in splitscreen - In single-screen, it wouldn't get spawned if it shouldn't be visible + { + if (player == &players[displayplayer]) + sign->drawonlyforplayer = &players[secondarydisplayplayer]; + else + sign->drawonlyforplayer = &players[displayplayer]; + +#ifdef QUADS + if (splitscreen > 1) // Can be seen by at least two local views, so we need an extra copy of the sign + { + UINT32 signframe = sign->frame; // Copy the flag frame + sign = P_SpawnMobjFromMobj(sign, 0, 0, 0, MT_TAG); + if (P_MobjWasRemoved(sign)) + return; + + sign->frame = signframe; + if (player == &players[displayplayer] || player == &players[secondarydisplayplayer]) + sign->drawonlyforplayer = &players[thirddisplayplayer]; + else + sign->drawonlyforplayer = &players[secondarydisplayplayer]; + + if (splitscreen > 2) // Can be seen by three local views + { + sign = P_SpawnMobjFromMobj(sign, 0, 0, 0, MT_TAG); + if (P_MobjWasRemoved(sign)) + return; + + sign->frame = signframe; + if (player != &players[fourthdisplayplayer]) + sign->drawonlyforplayer = &players[fourthdisplayplayer]; + else + sign->drawonlyforplayer = &players[thirddisplayplayer]; + } + } +#endif + } } // @@ -4688,10 +4753,11 @@ static void P_DoSpinAbility(player_t *player, ticcmd_t *cmd) mobj_t *lockon = P_LookForEnemies(player, false, true); if (lockon) { - if (P_IsLocalPlayer(player)) // Only display it on your own view. + if (P_IsLocalPlayer(player)) // Only display it on your own view. Don't display it for spectators { mobj_t *visual = P_SpawnMobj(lockon->x, lockon->y, lockon->z, MT_LOCKON); // positioning, flip handled in P_SceneryThinker P_SetTarget(&visual->target, lockon); + visual->drawonlyforplayer = player; // Hide it from the other player in splitscreen, and yourself when spectating } } if ((cmd->buttons & BT_SPIN) && !(player->pflags & PF_SPINDOWN)) @@ -4769,6 +4835,7 @@ static void P_DoSpinAbility(player_t *player, ticcmd_t *cmd) player->mo->momx += player->cmomx; player->mo->momy += player->cmomy; P_SetPlayerMobjState(player->mo, S_PLAY_MELEE); + player->powers[pw_strong] = STR_MELEE; S_StartSound(player->mo, sfx_s3k42); } player->pflags |= PF_SPINDOWN; @@ -5016,6 +5083,7 @@ static void P_DoTwinSpin(player_t *player) S_StartSound(player->mo, sfx_s3k42); player->mo->frame = 0; P_SetPlayerMobjState(player->mo, S_PLAY_TWINSPIN); + player->powers[pw_strong] = STR_TWINSPIN; } // @@ -5033,7 +5101,7 @@ static boolean P_PlayerShieldThink(player_t *player, ticcmd_t *cmd, mobj_t *lock { if ((lockonshield = P_LookForEnemies(player, false, false))) { - if (P_IsLocalPlayer(player)) // Only display it on your own view. + if (P_IsLocalPlayer(player)) // Only display it on your own view. Don't display it for spectators { boolean dovis = true; if (lockonshield == lockonthok) @@ -5047,6 +5115,7 @@ static boolean P_PlayerShieldThink(player_t *player, ticcmd_t *cmd, mobj_t *lock { visual = P_SpawnMobj(lockonshield->x, lockonshield->y, lockonshield->z, MT_LOCKON); // positioning, flip handled in P_SceneryThinker P_SetTarget(&visual->target, lockonshield); + visual->drawonlyforplayer = player; // Hide it from the other player in splitscreen, and yourself when spectating P_SetMobjStateNF(visual, visual->info->spawnstate+1); } } @@ -5150,10 +5219,11 @@ static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd) if ((player->charability == CA_HOMINGTHOK) && !player->homing && (player->pflags & PF_JUMPED) && (!(player->pflags & PF_THOKKED) || (player->charflags & SF_MULTIABILITY)) && (lockonthok = P_LookForEnemies(player, true, false))) { - if (P_IsLocalPlayer(player)) // Only display it on your own view. + if (P_IsLocalPlayer(player)) // Only display it on your own view. Don't display it for spectators { visual = P_SpawnMobj(lockonthok->x, lockonthok->y, lockonthok->z, MT_LOCKON); // positioning, flip handled in P_SceneryThinker P_SetTarget(&visual->target, lockonthok); + visual->drawonlyforplayer = player; // Hide it from the other player in splitscreen, and yourself when spectating } } @@ -5383,6 +5453,7 @@ static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd) player->pflags |= PF_THOKKED; else player->pflags |= (PF_THOKKED|PF_CANCARRY); + player->powers[pw_strong] = STR_FLY; } break; case CA_GLIDEANDCLIMB: @@ -5409,7 +5480,8 @@ static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd) P_SetPlayerMobjState(player->mo, S_PLAY_GLIDE); if (playerspeed < glidespeed) P_Thrust(player->mo, player->mo->angle, glidespeed - playerspeed); - player->pflags &= ~(PF_SPINNING|PF_STARTDASH); + player->pflags &= ~(PF_JUMPED|PF_SPINNING|PF_STARTDASH); + player->powers[pw_strong] = STR_GLIDE; } break; case CA_DOUBLEJUMP: // Double-Jump @@ -5469,6 +5541,7 @@ static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd) P_SetPlayerMobjState(player->mo, S_PLAY_BOUNCE); player->pflags &= ~(PF_JUMPED|PF_NOJUMPDAMAGE|PF_SPINNING); player->pflags |= PF_THOKKED|PF_BOUNCING; + player->powers[pw_strong] = STR_BOUNCE; player->mo->momx >>= 1; player->mo->momy >>= 1; player->mo->momz >>= 1; @@ -6772,9 +6845,9 @@ static void P_DoNiGHTSCapsule(player_t *player) { if ((player->mo->state == &states[S_PLAY_NIGHTS_PULL]) && (player->mo->sprite2 == SPR2_NPUL)) - player->mo->rollangle -= ANG30; + player->mo->spriteroll -= ANG30; else - player->mo->rollangle = 0; + player->mo->spriteroll = 0; } if (G_IsSpecialStage(gamemap)) @@ -7227,7 +7300,7 @@ static void P_NiGHTSMovement(player_t *player) && player->mo->state <= &states[S_PLAY_NIGHTS_TRANS6]) { player->mo->momx = player->mo->momy = player->mo->momz = 0; - player->mo->rollangle = 0; + player->mo->spriteroll = 0; return; } @@ -7245,7 +7318,7 @@ static void P_NiGHTSMovement(player_t *player) { if (player->mo->state != &states[S_PLAY_NIGHTS_DRILL]) P_SetPlayerMobjState(player->mo, S_PLAY_NIGHTS_DRILL); - player->mo->rollangle = ANGLE_90; + player->mo->spriteroll = ANGLE_90; } else #endif @@ -7578,9 +7651,9 @@ static void P_NiGHTSMovement(player_t *player) P_SetPlayerMobjState(player->mo, flystate); if (player->charflags & SF_NONIGHTSROTATION) - player->mo->rollangle = 0; + player->mo->spriteroll = 0; else - player->mo->rollangle = rollangle; + player->mo->spriteroll = rollangle; P_SetPlayerAngle(player, player->mo->angle); @@ -8647,7 +8720,10 @@ void P_MovePlayer(player_t *player) player->mo->height = P_GetPlayerHeight(player); if (player->mo->eflags & MFE_VERTICALFLIP && player->mo->height != oldheight) // adjust z height for reverse gravity, similar to how it's done for scaling - player->mo->z -= player->mo->height - oldheight; + { + player->mo->z -= player->mo->height - oldheight; + player->mo->old_z -= player->mo->height - oldheight; // Snap the Z adjustment, while keeping the Z interpolation + } // Crush test... if ((player->mo->ceilingz - player->mo->floorz < player->mo->height) @@ -9217,7 +9293,7 @@ mobj_t *P_LookForEnemies(player_t *player, boolean nonenemies, boolean bullet) { fixed_t zdist = (player->mo->z + player->mo->height/2) - (mo->z + mo->height/2); - dist = P_AproxDistance(player->mo->x-mo->x, player->mo->y-mo->y); + dist = R_PointToDist2(0, 0, player->mo->x-mo->x, player->mo->y-mo->y); if (bullet) { if ((R_PointToAngle2(0, 0, dist, zdist) + span) > span*2) @@ -9234,7 +9310,7 @@ mobj_t *P_LookForEnemies(player_t *player, boolean nonenemies, boolean bullet) continue; } - dist = P_AproxDistance(dist, zdist); + dist = R_PointToDist2(0, 0, dist, zdist); if (dist > maxdist) continue; // out of range } @@ -11060,17 +11136,30 @@ static void P_MinecartThink(player_t *player) // Mark interpolation; the old positions need to be relative to the displacement from the minecart _after_ it's moved. // This isn't quite correct (it captures the landing wobble) but it works well enough + // Additionally, hide other players' marks if (detleft) { - detleft->old_x = detleft->x - (minecart->old_x - minecart->old_x2); - detleft->old_y = detleft->y - (minecart->old_y - minecart->old_y2); - detleft->old_z = detleft->z - (minecart->old_z - minecart->old_z2); + if (P_IsLocalPlayer(player)) + { + detleft->old_x = detleft->x - (minecart->old_x - minecart->old_x2); + detleft->old_y = detleft->y - (minecart->old_y - minecart->old_y2); + detleft->old_z = detleft->z - (minecart->old_z - minecart->old_z2); + detleft->drawonlyforplayer = player; // Hide it from the other player in splitscreen, and yourself when spectating + } + else // Don't see others' marks when spectating others + P_RemoveMobj(detleft); // Lock-on markers are only spawned client-side, so this SHOULD be safe too... } if (detright) { - detright->old_x = detright->x - (minecart->old_x - minecart->old_x2); - detright->old_y = detright->y - (minecart->old_y - minecart->old_y2); - detright->old_z = detright->z - (minecart->old_z - minecart->old_z2); + if (P_IsLocalPlayer(player)) + { + detright->old_x = detright->x - (minecart->old_x - minecart->old_x2); + detright->old_y = detright->y - (minecart->old_y - minecart->old_y2); + detright->old_z = detright->z - (minecart->old_z - minecart->old_z2); + detright->drawonlyforplayer = player; + } + else + P_RemoveMobj(detleft); } } else @@ -11362,12 +11451,15 @@ static void P_DoMetalJetFume(player_t *player, mobj_t *fume) for (i = -1; i < 2; i += 2) { + mobj_t *bubble; offsetH = i*P_ReturnThrustX(fume, fume->movedir, radiusV); offsetV = i*P_ReturnThrustY(fume, fume->movedir, radiusV); x = mo->x + radiusX + FixedMul(offsetH, factorX); y = mo->y + radiusY + FixedMul(offsetH, factorY); z = mo->z + heightoffset + offsetV; - P_SpawnMobj(x, y, z, MT_SMALLBUBBLE)->scale = mo->scale >> 1; + bubble = P_SpawnMobj(x, y, z, MT_SMALLBUBBLE); + bubble->scale = mo->scale >> 1; + P_SetTarget(&bubble->dontdrawforviewmobj, mo); // Hide the bubble in first-person } fume->movefactor = 0; @@ -11421,7 +11513,7 @@ static void P_DoMetalJetFume(player_t *player, mobj_t *fume) } fume->movecount = dashmode; // keeps track of previous dashmode value so we know whether Metal is entering or leaving it - fume->eflags = (fume->flags2 & ~MF2_OBJECTFLIP) | (mo->flags2 & MF2_OBJECTFLIP); // Make sure to flip in reverse gravity! + fume->flags2 = (fume->flags2 & ~MF2_OBJECTFLIP) | (mo->flags2 & MF2_OBJECTFLIP); // Make sure to flip in reverse gravity! fume->eflags = (fume->eflags & ~MFE_VERTICALFLIP) | (mo->eflags & MFE_VERTICALFLIP); // Make sure to flip in reverse gravity! // Finally, set its position @@ -11436,7 +11528,11 @@ static void P_DoMetalJetFume(player_t *player, mobj_t *fume) // If dashmode is high enough, spawn a trail if (player->normalspeed >= skins[player->skin].normalspeed*2) - P_SpawnGhostMobj(fume); + { + mobj_t *ghost = P_SpawnGhostMobj(fume); + if (!P_MobjWasRemoved(ghost)) + P_SetTarget(&ghost->dontdrawforviewmobj, mo); // Hide the trail in first-person + } } // @@ -11507,15 +11603,24 @@ void P_PlayerThink(player_t *player) if (player->awayviewmobj && P_MobjWasRemoved(player->awayviewmobj)) { P_SetTarget(&player->awayviewmobj, NULL); // remove awayviewmobj asap if invalid - player->awayviewtics = 0; // reset to zero + player->awayviewtics = 1; // reset to one, the below code will immediately set it to zero + } + + if (player->awayviewtics && player->awayviewtics != -1) + { + player->awayviewtics--; + if (!(player->awayviewtics)) + { + if (player == &players[displayplayer]) + P_ResetCamera(player, &camera); // reset p1 camera on p1 running out of awayviewtics + else if (splitscreen && player == &players[secondarydisplayplayer]) + P_ResetCamera(player, &camera2); // reset p2 camera on p2 running out of awayviewtics + } } if (player->flashcount) player->flashcount--; - if (player->awayviewtics && player->awayviewtics != -1) - player->awayviewtics--; - /// \note do this in the cheat code if (player->pflags & PF_NOCLIP) player->mo->flags |= MF_NOCLIP; @@ -11524,9 +11629,12 @@ void P_PlayerThink(player_t *player) cmd = &player->cmd; - // Add some extra randomization. - if (cmd->forwardmove) - P_RandomFixed(); + if (demoplayback && demo_forwardmove_rng) + { + // Smelly demo backwards compatibility + if (cmd->forwardmove) + P_RandomFixed(); + } #ifdef PARANOIA if (player->playerstate == PST_REBORN) @@ -11656,7 +11764,7 @@ void P_PlayerThink(player_t *player) if (!total || ((4*exiting)/total) >= numneeded) { if (server) - SendNetXCmd(XD_EXITLEVEL, NULL, 0); + D_SendExitLevel(false); } else player->exiting = 3; @@ -11664,7 +11772,7 @@ void P_PlayerThink(player_t *player) else { if (server) - SendNetXCmd(XD_EXITLEVEL, NULL, 0); + D_SendExitLevel(false); } } @@ -11705,7 +11813,7 @@ void P_PlayerThink(player_t *player) if (player->spectator) { if (!(gametyperules & GTR_CAMPAIGN)) - player->score = 0; + player->score = player->recordscore = 0; } else if ((netgame || multiplayer) && player->lives <= 0 && !G_CoopGametype()) { @@ -11762,7 +11870,7 @@ void P_PlayerThink(player_t *player) mo2 = (mobj_t *)th; if (!(mo2->type == MT_RING || mo2->type == MT_COIN - || mo2->type == MT_BLUESPHERE || mo2->type == MT_BOMBSPHERE + || mo2->type == MT_BLUESPHERE // || mo2->type == MT_BOMBSPHERE || mo2->type == MT_NIGHTSCHIP || mo2->type == MT_NIGHTSSTAR)) continue; @@ -12071,14 +12179,6 @@ void P_PlayerThink(player_t *player) gmobj->tracer->frame |= tr_trans70<<FF_TRANSSHIFT; } } - - // Hide the mobj from our sights if we're the displayplayer and chasecam is off, - // or secondarydisplayplayer and chasecam2 is off. - // Why not just not spawn the mobj? Well, I'd rather only flirt with - // consistency so much... - if ((player == &players[displayplayer] && !camera.chase) - || (splitscreen && player == &players[secondarydisplayplayer] && !camera2.chase)) - gmobj->flags2 |= MF2_DONTDRAW; } #endif @@ -12172,6 +12272,16 @@ void P_PlayerThink(player_t *player) else player->powers[pw_ignorelatch] = 0; + if (player->powers[pw_strong] & STR_ANIM) + { + if (!(player->stronganim)) + player->stronganim = player->panim; + else if (player->panim != player->stronganim) + player->powers[pw_strong] = STR_NONE; + } + else if (player->stronganim) + player->stronganim = 0; + //pw_super acts as a timer now if (player->powers[pw_super] && (player->mo->state < &states[S_PLAY_SUPER_TRANS1] @@ -12266,6 +12376,8 @@ void P_PlayerThink(player_t *player) { player->normalspeed = skins[player->skin].normalspeed; // Reset to default if not capable of entering dash mode. player->jumpfactor = skins[player->skin].jumpfactor; + if (player->powers[pw_strong] & STR_DASH) + player->powers[pw_strong] = STR_NONE; } } else if (P_IsObjectOnGround(player->mo)) // Activate dash mode if we're on the ground. @@ -12275,6 +12387,9 @@ void P_PlayerThink(player_t *player) if (player->jumpfactor < FixedMul(skins[player->skin].jumpfactor, 5*FRACUNIT/4)) // Boost jump height. player->jumpfactor += FRACUNIT/300; + + if ((player->charflags & SF_MACHINE) && (!(player->powers[pw_strong] == STR_METAL))) + player->powers[pw_strong] = STR_METAL; } if (player->normalspeed >= skins[player->skin].normalspeed*2) @@ -12292,6 +12407,8 @@ void P_PlayerThink(player_t *player) player->normalspeed = skins[player->skin].normalspeed; player->jumpfactor = skins[player->skin].jumpfactor; S_StartSound(player->mo, sfx_kc65); + if (player->powers[pw_strong] & STR_DASH) + player->powers[pw_strong] = STR_NONE; } dashmode = 0; } diff --git a/src/r_bbox.c b/src/r_bbox.c new file mode 100644 index 0000000000000000000000000000000000000000..cf417ec37639477b43a5a5e5035b059dc81490b4 --- /dev/null +++ b/src/r_bbox.c @@ -0,0 +1,321 @@ +// SONIC ROBO BLAST 2 +//----------------------------------------------------------------------------- +// Copyright (C) 1993-1996 by id Software, Inc. +// Copyright (C) 1998-2000 by DooM Legacy Team. +// Copyright (C) 2022 by Kart Krew. +// Copyright (C) 1999-2022 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 r_bbox.c +/// \brief Boundary box (cube) renderer + +#include "doomdef.h" +#include "command.h" +#include "r_local.h" +#include "screen.h" // cv_renderhitbox +#include "v_video.h" // V_DrawFill + +enum { + RENDERHITBOX_OFF, + RENDERHITBOX_TANGIBLE, + RENDERHITBOX_ALL, + RENDERHITBOX_INTANGIBLE, + RENDERHITBOX_RINGS, +}; + +static CV_PossibleValue_t renderhitbox_cons_t[] = { + {RENDERHITBOX_OFF, "Off"}, + {RENDERHITBOX_TANGIBLE, "Tangible"}, + {RENDERHITBOX_ALL, "All"}, + {RENDERHITBOX_INTANGIBLE, "Intangible"}, + {RENDERHITBOX_RINGS, "Rings"}, + {0}}; + +consvar_t cv_renderhitbox = CVAR_INIT ("renderhitbox", "Off", CV_CHEAT|CV_NOTINNET, renderhitbox_cons_t, NULL); +consvar_t cv_renderhitboxinterpolation = CVAR_INIT ("renderhitbox_interpolation", "On", CV_SAVE, CV_OnOff, NULL); +consvar_t cv_renderhitboxgldepth = CVAR_INIT ("renderhitbox_gldepth", "Off", CV_SAVE, CV_OnOff, NULL); + +struct bbox_col { + INT32 x; + INT32 y; + INT32 h; +}; + +struct bbox_config { + fixed_t height; + fixed_t tz; + struct bbox_col col[4]; + UINT8 color; +}; + +static inline void +raster_bbox_seg +( INT32 x, + fixed_t y, + fixed_t h, + UINT8 pixel) +{ + y /= FRACUNIT; + + if (y < 0) + y = 0; + + h = y + (FixedCeil(abs(h)) / FRACUNIT); + + if (h >= viewheight) + h = viewheight; + + while (y < h) + { + topleft[x + y * vid.width] = pixel; + y++; + } +} + +static void +draw_bbox_col +( struct bbox_config * bb, + size_t p, + fixed_t tx, + fixed_t ty) +{ + struct bbox_col *col = &bb->col[p]; + + fixed_t xscale, yscale; + + if (ty < FRACUNIT) // projection breaks down here + ty = FRACUNIT; + + xscale = FixedDiv(projection, ty); + yscale = FixedDiv(projectiony, ty); + + col->x = (centerxfrac + FixedMul(tx, xscale)) / FRACUNIT; + col->y = (centeryfrac - FixedMul(bb->tz, yscale)); + col->h = FixedMul(bb->height, yscale); + + // Using this function is TOO EASY! + V_DrawFill( + viewwindowx + col->x, + viewwindowy + col->y / FRACUNIT, 1, + col->h / FRACUNIT, V_NOSCALESTART | bb->color); +} + +static void +draw_bbox_row +( struct bbox_config * bb, + size_t p1, + size_t p2) +{ + struct bbox_col + *a = &bb->col[p1], + *b = &bb->col[p2]; + + INT32 x1, x2; // left, right + INT32 dx; // width + + fixed_t y1, y2; // top, bottom + fixed_t s1, s2; // top and bottom increment + + if (a->x > b->x) + { + struct bbox_col *c = a; + a = b; + b = c; + } + + x1 = a->x; + x2 = b->x; + + if (x1 == x2 || x1 >= viewwidth || x2 < 0) + return; + + dx = x2 - x1; + + y1 = a->y; + y2 = b->y; + s1 = (y2 - y1) / dx; + + y2 = y1 + a->h; + s2 = ((b->y + b->h) - y2) / dx; + + // FixedCeil needs a minimum!!! :D :D + + if (s1 == 0) + s1 = 1; + + if (s2 == 0) + s2 = 1; + + if (x1 < 0) + { + y1 -= x1 * s1; + y2 -= x1 * s2; + x1 = 0; + } + + if (x2 >= viewwidth) + x2 = viewwidth - 1; + + while (x1 < x2) + { + raster_bbox_seg(x1, y1, s1, bb->color); + raster_bbox_seg(x1, y2, s2, bb->color); + + y1 += s1; + y2 += s2; + + x1++; + } +} + +UINT8 R_GetBoundingBoxColor(mobj_t *thing) +{ + UINT32 flags = thing->flags; + + if (thing->player) + return 255; // 0FF + + if (flags & (MF_NOCLIPTHING)) + return 7; // BFBFBF + + if (flags & (MF_BOSS|MF_ENEMY)) + return 35; // F00 + + if (flags & (MF_MISSILE|MF_PAIN)) + return 54; // F70 + + if (flags & (MF_SPECIAL|MF_MONITOR)) + return 73; // FF0 + + if (flags & MF_PUSHABLE) + return 112; // 0F0 + + if (flags & (MF_SPRING)) + return 181; // F0F + + if (flags & (MF_NOCLIP)) + return 152; // 00F + + return 0; // FFF +} + +void R_DrawThingBoundingBox(vissprite_t *vis) +{ + // radius offsets + fixed_t rs = vis->scale; + fixed_t rc = vis->xscale; + + // translated coordinates + fixed_t tx = vis->gx; + fixed_t ty = vis->gy; + + struct bbox_config bb = { + .height = vis->thingheight, + .tz = vis->texturemid, + .color = R_GetBoundingBoxColor(vis->mobj), + }; + + // 1--3 + // | | + // 0--2 + + // left + + draw_bbox_col(&bb, 0, tx, ty); // bottom + draw_bbox_col(&bb, 1, tx - rc, ty + rs); // top + + // right + + tx += rs; + ty += rc; + + draw_bbox_col(&bb, 2, tx, ty); // bottom + draw_bbox_col(&bb, 3, tx - rc, ty + rs); // top + + // connect all four columns + + draw_bbox_row(&bb, 0, 1); + draw_bbox_row(&bb, 1, 3); + draw_bbox_row(&bb, 3, 2); + draw_bbox_row(&bb, 2, 0); +} + +static boolean is_tangible (mobj_t *thing) +{ + // These objects can never touch another + if (thing->flags & (MF_NOCLIPTHING)) + { + return false; + } + + // These objects probably do nothing! :D + if ((thing->flags & (MF_SPECIAL|MF_SOLID|MF_SHOOTABLE + |MF_PUSHABLE|MF_BOSS|MF_MISSILE|MF_SPRING + |MF_BOUNCE|MF_MONITOR|MF_FIRE|MF_ENEMY + |MF_PAIN|MF_STICKY + |MF_GRENADEBOUNCE)) == 0U) + { + return false; + } + + return true; +} + +boolean R_ThingBoundingBoxVisible(mobj_t *thing) +{ + INT32 cvmode = cv_renderhitbox.value; + + if (multiplayer) // No hitboxes in multiplayer to avoid cheating + return false; + + // Do not render bbox for these + switch (thing->type) + { + default: + // First person / awayviewmobj -- rendering + // a bbox too close to the viewpoint causes + // anomalies and these are exactly on the + // viewpoint! + if (thing != r_viewmobj) + { + break; + } + // FALLTHRU + + case MT_SKYBOX: + // Ditto for skybox viewpoint but because they + // are rendered using portals in Software, + // r_viewmobj does not point here. + return false; + } + + switch (cvmode) + { + case RENDERHITBOX_OFF: + return false; + + case RENDERHITBOX_ALL: + return true; + + case RENDERHITBOX_INTANGIBLE: + return !is_tangible(thing); + + case RENDERHITBOX_TANGIBLE: + // Exclude rings from here, lots of them! + if (thing->type == MT_RING) + { + return false; + } + + return is_tangible(thing); + + case RENDERHITBOX_RINGS: + return (thing->type == MT_RING || thing->type == MT_BLUESPHERE); + + default: + return false; + } +} diff --git a/src/r_bsp.c b/src/r_bsp.c index 121ddaae5ae1340b5c0b2e33b983b061be060f86..42e050adf831f15a7b3e653c57e265cab781b6cc 100644 --- a/src/r_bsp.c +++ b/src/r_bsp.c @@ -275,9 +275,9 @@ sector_t *R_FakeFlat(sector_t *sec, sector_t *tempsec, INT32 *floorlightlevel, tempsec->ceilingheight = s->floorheight - 1, !back)) || viewz <= s->floorheight) { // head-below-floor hack tempsec->floorpic = s->floorpic; - tempsec->floor_xoffs = s->floor_xoffs; - tempsec->floor_yoffs = s->floor_yoffs; - tempsec->floorpic_angle = s->floorpic_angle; + tempsec->floorxoffset = s->floorxoffset; + tempsec->flooryoffset = s->flooryoffset; + tempsec->floorangle = s->floorangle; if (underwater) { @@ -285,16 +285,16 @@ sector_t *R_FakeFlat(sector_t *sec, sector_t *tempsec, INT32 *floorlightlevel, { tempsec->floorheight = tempsec->ceilingheight+1; tempsec->ceilingpic = tempsec->floorpic; - tempsec->ceiling_xoffs = tempsec->floor_xoffs; - tempsec->ceiling_yoffs = tempsec->floor_yoffs; - tempsec->ceilingpic_angle = tempsec->floorpic_angle; + tempsec->ceilingxoffset = tempsec->floorxoffset; + tempsec->ceilingyoffset = tempsec->flooryoffset; + tempsec->ceilingangle = tempsec->floorangle; } else { tempsec->ceilingpic = s->ceilingpic; - tempsec->ceiling_xoffs = s->ceiling_xoffs; - tempsec->ceiling_yoffs = s->ceiling_yoffs; - tempsec->ceilingpic_angle = s->ceilingpic_angle; + tempsec->ceilingxoffset = s->ceilingxoffset; + tempsec->ceilingyoffset = s->ceilingyoffset; + tempsec->ceilingangle = s->ceilingangle; } } @@ -315,25 +315,25 @@ sector_t *R_FakeFlat(sector_t *sec, sector_t *tempsec, INT32 *floorlightlevel, tempsec->floorheight = s->ceilingheight + 1; tempsec->floorpic = tempsec->ceilingpic = s->ceilingpic; - tempsec->floor_xoffs = tempsec->ceiling_xoffs = s->ceiling_xoffs; - tempsec->floor_yoffs = tempsec->ceiling_yoffs = s->ceiling_yoffs; - tempsec->floorpic_angle = tempsec->ceilingpic_angle = s->ceilingpic_angle; + tempsec->floorxoffset = tempsec->ceilingxoffset = s->ceilingxoffset; + tempsec->flooryoffset = tempsec->ceilingyoffset = s->ceilingyoffset; + tempsec->floorangle = tempsec->ceilingangle = s->ceilingangle; if (s->floorpic == skyflatnum) // SKYFIX? { tempsec->ceilingheight = tempsec->floorheight-1; tempsec->floorpic = tempsec->ceilingpic; - tempsec->floor_xoffs = tempsec->ceiling_xoffs; - tempsec->floor_yoffs = tempsec->ceiling_yoffs; - tempsec->floorpic_angle = tempsec->ceilingpic_angle; + tempsec->floorxoffset = tempsec->ceilingxoffset; + tempsec->flooryoffset = tempsec->ceilingyoffset; + tempsec->floorangle = tempsec->ceilingangle; } else { tempsec->ceilingheight = sec->ceilingheight; tempsec->floorpic = s->floorpic; - tempsec->floor_xoffs = s->floor_xoffs; - tempsec->floor_yoffs = s->floor_yoffs; - tempsec->floorpic_angle = s->floorpic_angle; + tempsec->floorxoffset = s->floorxoffset; + tempsec->flooryoffset = s->flooryoffset; + tempsec->floorangle = s->floorangle; } tempsec->lightlevel = s->lightlevel; @@ -363,12 +363,12 @@ boolean R_IsEmptyLine(seg_t *line, sector_t *front, sector_t *back) && back->lightlevel == front->lightlevel && !line->sidedef->midtexture // Check offsets too! - && back->floor_xoffs == front->floor_xoffs - && back->floor_yoffs == front->floor_yoffs - && back->floorpic_angle == front->floorpic_angle - && back->ceiling_xoffs == front->ceiling_xoffs - && back->ceiling_yoffs == front->ceiling_yoffs - && back->ceilingpic_angle == front->ceilingpic_angle + && back->floorxoffset == front->floorxoffset + && back->flooryoffset == front->flooryoffset + && back->floorangle == front->floorangle + && back->ceilingxoffset == front->ceilingxoffset + && back->ceilingyoffset == front->ceilingyoffset + && back->ceilingangle == front->ceilingangle // Consider altered lighting. && back->floorlightlevel == front->floorlightlevel && back->floorlightabsolute == front->floorlightabsolute @@ -909,7 +909,7 @@ static void R_Subsector(size_t num) || (frontsector->heightsec != -1 && sectors[frontsector->heightsec].ceilingpic == skyflatnum)) { floorplane = R_FindPlane(frontsector->floorheight, frontsector->floorpic, floorlightlevel, - frontsector->floor_xoffs, frontsector->floor_yoffs, frontsector->floorpic_angle, floorcolormap, NULL, NULL, frontsector->f_slope); + frontsector->floorxoffset, frontsector->flooryoffset, frontsector->floorangle, floorcolormap, NULL, NULL, frontsector->f_slope); } else floorplane = NULL; @@ -919,7 +919,7 @@ static void R_Subsector(size_t num) || (frontsector->heightsec != -1 && sectors[frontsector->heightsec].floorpic == skyflatnum)) { ceilingplane = R_FindPlane(frontsector->ceilingheight, frontsector->ceilingpic, - ceilinglightlevel, frontsector->ceiling_xoffs, frontsector->ceiling_yoffs, frontsector->ceilingpic_angle, + ceilinglightlevel, frontsector->ceilingxoffset, frontsector->ceilingyoffset, frontsector->ceilingangle, ceilingcolormap, NULL, NULL, frontsector->c_slope); } else @@ -1033,8 +1033,8 @@ 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, - (light == -1 ? frontsector->lightlevel : *frontsector->lightlist[light].lightlevel), polysec->floor_xoffs, polysec->floor_yoffs, - polysec->floorpic_angle-po->angle, + (light == -1 ? frontsector->lightlevel : *frontsector->lightlist[light].lightlevel), polysec->floorxoffset, polysec->flooryoffset, + polysec->floorangle-po->angle, (light == -1 ? frontsector->extra_colormap : *frontsector->lightlist[light].extra_colormap), NULL, po, NULL); // will ffloors be slopable eventually? @@ -1057,7 +1057,7 @@ static void R_Subsector(size_t num) { light = R_GetPlaneLight(frontsector, polysec->floorheight, viewz < polysec->floorheight); ffloor[numffloors].plane = R_FindPlane(polysec->ceilingheight, polysec->ceilingpic, - (light == -1 ? frontsector->lightlevel : *frontsector->lightlist[light].lightlevel), polysec->ceiling_xoffs, polysec->ceiling_yoffs, polysec->ceilingpic_angle-po->angle, + (light == -1 ? frontsector->lightlevel : *frontsector->lightlist[light].lightlevel), polysec->ceilingxoffset, polysec->ceilingyoffset, polysec->ceilingangle-po->angle, (light == -1 ? frontsector->extra_colormap : *frontsector->lightlist[light].extra_colormap), NULL, po, NULL); // will ffloors be slopable eventually? diff --git a/src/r_defs.h b/src/r_defs.h index 7f440179ff04b4e9393ab7ce131a7e0fa503fc6a..83d9825ca683c5dca13b5c648371ff49f54428d1 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -423,12 +423,12 @@ typedef struct sector_s void *fadecolormapdata; // fade colormap thinker // floor and ceiling texture offsets - fixed_t floor_xoffs, floor_yoffs; - fixed_t ceiling_xoffs, ceiling_yoffs; + fixed_t floorxoffset, flooryoffset; + fixed_t ceilingxoffset, ceilingyoffset; // flat angle - angle_t floorpic_angle; - angle_t ceilingpic_angle; + angle_t floorangle; + angle_t ceilingangle; INT32 heightsec; // other sector, or -1 if no other sector INT32 camsec; // used for camera clipping @@ -547,7 +547,6 @@ typedef struct line_s size_t validcount; // if == validcount, already checked polyobj_t *polyobj; // Belongs to a polyobject? - char *text; // a concatenation of all front and back texture names, for linedef specials that require a string. INT16 callcount; // no. of calls left before triggering, for the "X calls" linedef specials, defaults to 0 } line_t; @@ -579,8 +578,6 @@ typedef struct INT16 special; // the special of the linedef this side belongs to INT16 repeatcnt; // # of times to repeat midtexture - char *text; // a concatenation of all top, bottom, and mid texture names, for linedef specials that require a string. - extracolormap_t *colormap_data; // storage for colormaps; not applied to sectors. } side_t; @@ -763,12 +760,12 @@ typedef struct drawseg_s // Pointers to lists for sprite clipping, all three adjusted so [x1] is first value. INT16 *sprtopclip; INT16 *sprbottomclip; - INT16 *maskedtexturecol; + fixed_t *maskedtexturecol; struct visplane_s *ffloorplanes[MAXFFLOORS]; INT32 numffloorplanes; struct ffloor_s *thicksides[MAXFFLOORS]; - INT16 *thicksidecol; + fixed_t *thicksidecol; INT32 numthicksides; fixed_t frontscale[MAXVIDWIDTH]; diff --git a/src/r_draw.c b/src/r_draw.c index b0467e4f728d4cf757b53484a3d5ca4fda9d91cc..df9e1a4608b568706452df29bbc347adef075b01 100644 --- a/src/r_draw.c +++ b/src/r_draw.c @@ -179,8 +179,6 @@ CV_PossibleValue_t Color_cons_t[MAXSKINCOLORS+1]; void R_InitTranslucencyTables(void) { // Load here the transparency lookup tables 'TRANSx0' - // NOTE: the TRANSx0 resources MUST BE aligned on 64k for the asm - // optimised code (in other words, transtables pointer low word is 0) transtables = Z_MallocAlign(NUMTRANSTABLES*0x10000, PU_STATIC, NULL, 16); diff --git a/src/r_draw.h b/src/r_draw.h index ea03a8e3d53e059570822a0119ee6431f45d105a..0103ed82782b22c7a51beb10c20473a3e8ba3787 100644 --- a/src/r_draw.h +++ b/src/r_draw.h @@ -225,18 +225,6 @@ void R_DrawTiltedTransSolidColorSpan_8(void); void R_DrawWaterSolidColorSpan_8(void); void R_DrawTiltedWaterSolidColorSpan_8(void); -#ifdef USEASM -void ASMCALL R_DrawColumn_8_ASM(void); -void ASMCALL R_DrawShadeColumn_8_ASM(void); -void ASMCALL R_DrawTranslucentColumn_8_ASM(void); -void ASMCALL R_Draw2sMultiPatchColumn_8_ASM(void); - -void ASMCALL R_DrawColumn_8_MMX(void); - -void ASMCALL R_Draw2sMultiPatchColumn_8_MMX(void); -void ASMCALL R_DrawSpan_8_MMX(void); -#endif - // ------------------ // 16bpp DRAWING CODE // ------------------ diff --git a/src/r_draw8_npo2.c b/src/r_draw8_npo2.c index faf1cdba80bb1acda4b5c595378f0aa428043431..91f3b06c4270ba28901d35b561f68a002ddbc6f3 100644 --- a/src/r_draw8_npo2.c +++ b/src/r_draw8_npo2.c @@ -18,6 +18,11 @@ #define SPANSIZE 16 #define INVSPAN 0.0625f +#if defined(__GNUC__) || defined(__clang__) // Suppress intentional libdivide compiler warnings - Also added to libdivide.h + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Waggregate-return" +#endif + /** \brief The R_DrawSpan_NPO2_8 function Draws the actual span. */ @@ -1572,3 +1577,7 @@ void R_DrawTiltedWaterSpan_NPO2_8(void) } #endif } + +#if defined(__GNUC__) || defined(__clang__) // Stop suppressing intentional libdivide compiler warnings + #pragma GCC diagnostic pop +#endif diff --git a/src/r_fps.c b/src/r_fps.c index 2d30c9f01920959c783da056d1db2f0858969209..de450aaa7f465b8d47891baec585c757de361c60 100644 --- a/src/r_fps.c +++ b/src/r_fps.c @@ -292,8 +292,13 @@ void R_InterpolateMobjState(mobj_t *mobj, fixed_t frac, interpmobjstate_t *out) out->y = mobj->y; out->z = mobj->z; out->scale = mobj->scale; + out->radius = mobj->radius; + out->height = mobj->height; out->subsector = mobj->subsector; out->angle = mobj->player ? mobj->player->drawangle : mobj->angle; + out->pitch = mobj->pitch; + out->roll = mobj->roll; + out->spriteroll = mobj->spriteroll; out->spritexscale = mobj->spritexscale; out->spriteyscale = mobj->spriteyscale; out->spritexoffset = mobj->spritexoffset; @@ -304,10 +309,22 @@ void R_InterpolateMobjState(mobj_t *mobj, fixed_t frac, interpmobjstate_t *out) 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 = mobj->resetinterp ? mobj->scale : R_LerpFixed(mobj->old_scale, mobj->scale, 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); + 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; + out->radius = mobj->radius; + out->height = mobj->height; + } + else + { + out->scale = R_LerpFixed(mobj->old_scale, mobj->scale, frac); + out->radius = FixedMul(mobj->radius, FixedDiv(out->scale, mobj->scale)); + out->height = FixedMul(mobj->height, FixedDiv(out->scale, mobj->scale)); + } + // Sprite offsets are not interpolated until we have a way to interpolate them explicitly in Lua. // It seems existing mods visually break more often than not if it is interpolated. out->spritexoffset = mobj->spritexoffset; @@ -323,6 +340,10 @@ void R_InterpolateMobjState(mobj_t *mobj, fixed_t frac, interpmobjstate_t *out) { out->angle = mobj->resetinterp ? mobj->angle : R_LerpAngle(mobj->old_angle, mobj->angle, frac); } + + out->pitch = mobj->resetinterp ? mobj->pitch : R_LerpAngle(mobj->old_pitch, mobj->pitch, frac); + out->roll = mobj->resetinterp ? mobj->roll : R_LerpAngle(mobj->old_roll, mobj->roll, frac); + out->spriteroll = mobj->resetinterp ? mobj->spriteroll : R_LerpAngle(mobj->old_spriteroll, mobj->spriteroll, frac); } void R_InterpolatePrecipMobjState(precipmobj_t *mobj, fixed_t frac, interpmobjstate_t *out) @@ -333,8 +354,13 @@ void R_InterpolatePrecipMobjState(precipmobj_t *mobj, fixed_t frac, interpmobjst out->y = mobj->y; out->z = mobj->z; out->scale = FRACUNIT; + out->radius = mobj->radius; + out->height = mobj->height; out->subsector = mobj->subsector; out->angle = mobj->angle; + out->pitch = mobj->angle; + out->roll = mobj->roll; + out->spriteroll = mobj->spriteroll; out->spritexscale = mobj->spritexscale; out->spriteyscale = mobj->spriteyscale; out->spritexoffset = mobj->spritexoffset; @@ -346,6 +372,8 @@ void R_InterpolatePrecipMobjState(precipmobj_t *mobj, fixed_t frac, interpmobjst out->y = R_LerpFixed(mobj->old_y, mobj->y, frac); out->z = R_LerpFixed(mobj->old_z, mobj->z, frac); out->scale = FRACUNIT; + out->radius = mobj->radius; + out->height = mobj->height; out->spritexscale = R_LerpFixed(mobj->old_spritexscale, mobj->spritexscale, frac); out->spriteyscale = R_LerpFixed(mobj->old_spriteyscale, mobj->spriteyscale, frac); out->spritexoffset = R_LerpFixed(mobj->old_spritexoffset, mobj->spritexoffset, frac); @@ -354,6 +382,9 @@ void R_InterpolatePrecipMobjState(precipmobj_t *mobj, fixed_t frac, interpmobjst out->subsector = R_PointInSubsector(out->x, out->y); out->angle = R_LerpAngle(mobj->old_angle, mobj->angle, frac); + out->pitch = R_LerpAngle(mobj->old_pitch, mobj->pitch, frac); + out->roll = R_LerpAngle(mobj->old_roll, mobj->roll, frac); + out->spriteroll = R_LerpAngle(mobj->old_spriteroll, mobj->spriteroll, frac); } static void AddInterpolator(levelinterpolator_t* interpolator) @@ -369,12 +400,11 @@ static void AddInterpolator(levelinterpolator_t* interpolator) levelinterpolators_size *= 2; } - levelinterpolators = Z_ReallocAlign( + levelinterpolators = Z_Realloc( (void*) levelinterpolators, sizeof(levelinterpolator_t*) * levelinterpolators_size, PU_LEVEL, - NULL, - sizeof(levelinterpolator_t*) * 8 + NULL ); } @@ -384,11 +414,8 @@ static void AddInterpolator(levelinterpolator_t* interpolator) static levelinterpolator_t *CreateInterpolator(levelinterpolator_type_e type, thinker_t *thinker) { - levelinterpolator_t *ret = (levelinterpolator_t*) Z_CallocAlign( - sizeof(levelinterpolator_t), - PU_LEVEL, - NULL, - sizeof(levelinterpolator_t) * 8 + levelinterpolator_t *ret = (levelinterpolator_t*) Z_Calloc( + sizeof(levelinterpolator_t), PU_LEVEL, NULL ); ret->type = type; @@ -421,13 +448,13 @@ void R_CreateInterpolator_SectorScroll(thinker_t *thinker, sector_t *sector, boo interp->sectorscroll.ceiling = ceiling; if (ceiling) { - interp->sectorscroll.oldxoffs = interp->sectorscroll.bakxoffs = sector->ceiling_xoffs; - interp->sectorscroll.oldyoffs = interp->sectorscroll.bakyoffs = sector->ceiling_yoffs; + interp->sectorscroll.oldxoffs = interp->sectorscroll.bakxoffs = sector->ceilingxoffset; + interp->sectorscroll.oldyoffs = interp->sectorscroll.bakyoffs = sector->ceilingyoffset; } else { - interp->sectorscroll.oldxoffs = interp->sectorscroll.bakxoffs = sector->floor_xoffs; - interp->sectorscroll.oldyoffs = interp->sectorscroll.bakyoffs = sector->floor_yoffs; + interp->sectorscroll.oldxoffs = interp->sectorscroll.bakxoffs = sector->floorxoffset; + interp->sectorscroll.oldyoffs = interp->sectorscroll.bakyoffs = sector->flooryoffset; } } @@ -490,9 +517,9 @@ static void UpdateLevelInterpolatorState(levelinterpolator_t *interp) break; case LVLINTERP_SectorScroll: interp->sectorscroll.oldxoffs = interp->sectorscroll.bakxoffs; - interp->sectorscroll.bakxoffs = interp->sectorscroll.ceiling ? interp->sectorscroll.sector->ceiling_xoffs : interp->sectorscroll.sector->floor_xoffs; + interp->sectorscroll.bakxoffs = interp->sectorscroll.ceiling ? interp->sectorscroll.sector->ceilingxoffset : interp->sectorscroll.sector->floorxoffset; interp->sectorscroll.oldyoffs = interp->sectorscroll.bakyoffs; - interp->sectorscroll.bakyoffs = interp->sectorscroll.ceiling ? interp->sectorscroll.sector->ceiling_yoffs : interp->sectorscroll.sector->floor_yoffs; + interp->sectorscroll.bakyoffs = interp->sectorscroll.ceiling ? interp->sectorscroll.sector->ceilingyoffset : interp->sectorscroll.sector->flooryoffset; break; case LVLINTERP_SideScroll: interp->sidescroll.oldtextureoffset = interp->sidescroll.baktextureoffset; @@ -578,13 +605,13 @@ void R_ApplyLevelInterpolators(fixed_t frac) case LVLINTERP_SectorScroll: if (interp->sectorscroll.ceiling) { - 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); + interp->sectorscroll.sector->ceilingxoffset = R_LerpFixed(interp->sectorscroll.oldxoffs, interp->sectorscroll.bakxoffs, frac); + interp->sectorscroll.sector->ceilingyoffset = R_LerpFixed(interp->sectorscroll.oldyoffs, interp->sectorscroll.bakyoffs, frac); } else { - 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); + interp->sectorscroll.sector->floorxoffset = R_LerpFixed(interp->sectorscroll.oldxoffs, interp->sectorscroll.bakxoffs, frac); + interp->sectorscroll.sector->flooryoffset = R_LerpFixed(interp->sectorscroll.oldyoffs, interp->sectorscroll.bakyoffs, frac); } break; case LVLINTERP_SideScroll: @@ -633,13 +660,13 @@ void R_RestoreLevelInterpolators(void) case LVLINTERP_SectorScroll: if (interp->sectorscroll.ceiling) { - interp->sectorscroll.sector->ceiling_xoffs = interp->sectorscroll.bakxoffs; - interp->sectorscroll.sector->ceiling_yoffs = interp->sectorscroll.bakyoffs; + interp->sectorscroll.sector->ceilingxoffset = interp->sectorscroll.bakxoffs; + interp->sectorscroll.sector->ceilingyoffset = interp->sectorscroll.bakyoffs; } else { - interp->sectorscroll.sector->floor_xoffs = interp->sectorscroll.bakxoffs; - interp->sectorscroll.sector->floor_yoffs = interp->sectorscroll.bakyoffs; + interp->sectorscroll.sector->floorxoffset = interp->sectorscroll.bakxoffs; + interp->sectorscroll.sector->flooryoffset = interp->sectorscroll.bakyoffs; } break; case LVLINTERP_SideScroll: @@ -703,12 +730,11 @@ void R_AddMobjInterpolator(mobj_t *mobj) interpolated_mobjs_capacity *= 2; } - interpolated_mobjs = Z_ReallocAlign( + interpolated_mobjs = Z_Realloc( interpolated_mobjs, sizeof(mobj_t *) * interpolated_mobjs_capacity, PU_LEVEL, - NULL, - 64 + NULL ); } @@ -771,6 +797,7 @@ void R_ResetMobjInterpolationState(mobj_t *mobj) mobj->old_angle2 = mobj->old_angle; mobj->old_pitch2 = mobj->old_pitch; mobj->old_roll2 = mobj->old_roll; + mobj->old_spriteroll2 = mobj->old_spriteroll; mobj->old_scale2 = mobj->old_scale; mobj->old_x = mobj->x; mobj->old_y = mobj->y; @@ -778,6 +805,7 @@ void R_ResetMobjInterpolationState(mobj_t *mobj) mobj->old_angle = mobj->angle; mobj->old_pitch = mobj->pitch; mobj->old_roll = mobj->roll; + mobj->old_spriteroll = mobj->spriteroll; mobj->old_scale = mobj->scale; mobj->old_spritexscale = mobj->spritexscale; mobj->old_spriteyscale = mobj->spriteyscale; @@ -806,10 +834,14 @@ void R_ResetPrecipitationMobjInterpolationState(precipmobj_t *mobj) mobj->old_angle2 = mobj->old_angle; mobj->old_pitch2 = mobj->old_pitch; mobj->old_roll2 = mobj->old_roll; + mobj->old_spriteroll2 = mobj->old_spriteroll; mobj->old_x = mobj->x; mobj->old_y = mobj->y; mobj->old_z = mobj->z; mobj->old_angle = mobj->angle; + mobj->old_pitch = mobj->pitch; + mobj->old_roll = mobj->roll; + mobj->old_spriteroll = mobj->spriteroll; mobj->old_spritexscale = mobj->spritexscale; mobj->old_spriteyscale = mobj->spriteyscale; mobj->old_spritexoffset = mobj->spritexoffset; diff --git a/src/r_fps.h b/src/r_fps.h index 85c87a2f49ff1c3177f7fb8b8e9136e88316ebc9..f43d29f300a8a6707a3e4c6f5fa24e1e3f0ea37f 100644 --- a/src/r_fps.h +++ b/src/r_fps.h @@ -59,7 +59,12 @@ typedef struct { fixed_t z; subsector_t *subsector; angle_t angle; + angle_t pitch; + angle_t roll; + angle_t spriteroll; fixed_t scale; + fixed_t radius; + fixed_t height; fixed_t spritexscale; fixed_t spriteyscale; fixed_t spritexoffset; diff --git a/src/r_main.c b/src/r_main.c index 55bb9c4ffefdfee11f38ec50a28cff7de2748ffb..54f7d7639e775f73b1d8de57d9923745eb9ff493 100644 --- a/src/r_main.c +++ b/src/r_main.c @@ -41,16 +41,6 @@ #include "hardware/hw_main.h" #endif -//profile stuff --------------------------------------------------------- -//#define TIMING -#ifdef TIMING -#include "p5prof.h" -INT64 mycount; -INT64 mytotal = 0; -//unsigned long nombre = 100000; -#endif -//profile stuff --------------------------------------------------------- - // Fineangles in the SCREENWIDTH wide window. #define FIELDOFVIEW 2048 @@ -157,7 +147,8 @@ consvar_t cv_flipcam2 = CVAR_INIT ("flipcam2", "No", CV_SAVE|CV_CALL|CV_NOINIT, consvar_t cv_shadow = CVAR_INIT ("shadow", "On", CV_SAVE, CV_OnOff, NULL); consvar_t cv_skybox = CVAR_INIT ("skybox", "On", CV_SAVE, CV_OnOff, NULL); -consvar_t cv_ffloorclip = CVAR_INIT ("ffloorclip", "On", CV_SAVE, CV_OnOff, NULL); +consvar_t cv_ffloorclip = CVAR_INIT ("r_ffloorclip", "On", CV_SAVE, CV_OnOff, NULL); +consvar_t cv_spriteclip = CVAR_INIT ("r_spriteclip", "On", CV_SAVE, CV_OnOff, NULL); consvar_t cv_allowmlook = CVAR_INIT ("allowmlook", "Yes", CV_NETVAR|CV_ALLOWLUA, CV_YesNo, NULL); consvar_t cv_showhud = CVAR_INIT ("showhud", "Yes", CV_CALL|CV_ALLOWLUA, CV_YesNo, R_SetViewSize); consvar_t cv_translucenthud = CVAR_INIT ("translucenthud", "10", CV_SAVE, translucenthud_cons_t, NULL); @@ -1479,6 +1470,7 @@ void R_RenderPlayerView(player_t *player) R_ClearClipSegs(); } R_ClearDrawSegs(); + R_ClearSegTables(); R_ClearSprites(); Portal_InitList(); @@ -1489,29 +1481,17 @@ void R_RenderPlayerView(player_t *player) Mask_Pre(&masks[nummasks - 1]); curdrawsegs = ds_p; -//profile stuff --------------------------------------------------------- -#ifdef TIMING - mytotal = 0; - ProfZeroTimer(); -#endif ps_numbspcalls.value.i = ps_numpolyobjects.value.i = ps_numdrawnodes.value.i = 0; PS_START_TIMING(ps_bsptime); R_RenderBSPNode((INT32)numnodes - 1); PS_STOP_TIMING(ps_bsptime); - ps_numsprites.value.i = visspritecount; -#ifdef TIMING - RDMSR(0x10, &mycount); - mytotal += mycount; // 64bit add - - CONS_Debug(DBG_RENDER, "RenderBSPNode: 0x%d %d\n", *((INT32 *)&mytotal + 1), (INT32)mytotal); -#endif -//profile stuff --------------------------------------------------------- Mask_Post(&masks[nummasks - 1]); PS_START_TIMING(ps_sw_spritecliptime); R_ClipSprites(drawsegs, NULL); PS_STOP_TIMING(ps_sw_spritecliptime); + ps_numsprites.value.i = numvisiblesprites; // Add skybox portals caused by sky visplanes. if (cv_skybox.value && skyboxmo[0]) @@ -1602,6 +1582,7 @@ void R_RegisterEngineStuff(void) CV_RegisterVar(&cv_shadow); CV_RegisterVar(&cv_skybox); CV_RegisterVar(&cv_ffloorclip); + CV_RegisterVar(&cv_spriteclip); CV_RegisterVar(&cv_cam_dist); CV_RegisterVar(&cv_cam_still); diff --git a/src/r_main.h b/src/r_main.h index f08070d0f387b544c9b0b5089e65b6251999db99..a6fb42ba2410ba42c8adc7ba84ef8fde21e0802f 100644 --- a/src/r_main.h +++ b/src/r_main.h @@ -114,7 +114,7 @@ extern consvar_t cv_chasecam, cv_chasecam2; extern consvar_t cv_flipcam, cv_flipcam2; extern consvar_t cv_shadow; -extern consvar_t cv_ffloorclip; +extern consvar_t cv_ffloorclip, cv_spriteclip; extern consvar_t cv_translucency; extern consvar_t cv_drawdist, cv_drawdist_nights, cv_drawdist_precip; extern consvar_t cv_fov; diff --git a/src/r_patch.h b/src/r_patch.h index d2106a390019b357702c573c414842a615ba555b..a0ab3e75ac0c81a7fa16b6129cd2deabb8d02d46 100644 --- a/src/r_patch.h +++ b/src/r_patch.h @@ -14,6 +14,7 @@ #include "r_defs.h" #include "r_picformats.h" +#include "r_fps.h" #include "doomdef.h" // Patch functions @@ -38,6 +39,8 @@ patch_t *Patch_GetRotatedSprite( size_t frame, size_t spriteangle, boolean flip, boolean adjustfeet, void *info, INT32 rotationangle); +angle_t R_ModelRotationAngle(interpmobjstate_t *interp); +angle_t R_SpriteRotationAngle(interpmobjstate_t *interp); INT32 R_GetRollAngle(angle_t rollangle); #endif diff --git a/src/r_patchrotation.c b/src/r_patchrotation.c index 3d3c6c512893d1670b4b93b96b32d670b6300e93..b0cbeaa42911d1506d9928b906198afdf50ff0be 100644 --- a/src/r_patchrotation.c +++ b/src/r_patchrotation.c @@ -13,11 +13,33 @@ #include "r_things.h" // FEETADJUST #include "z_zone.h" #include "w_wad.h" +#include "r_main.h" // R_PointToAngle #ifdef ROTSPRITE fixed_t rollcosang[ROTANGLES]; fixed_t rollsinang[ROTANGLES]; +angle_t R_ModelRotationAngle(interpmobjstate_t *interp) +{ + return interp->spriteroll; +} + +angle_t R_SpriteRotationAngle(interpmobjstate_t *interp) +{ +#if 0 + angle_t viewingAngle = R_PointToAngle(interp->x, interp->y); + + fixed_t pitchMul = -FINESINE(viewingAngle >> ANGLETOFINESHIFT); + fixed_t rollMul = FINECOSINE(viewingAngle >> ANGLETOFINESHIFT); + + angle_t rollOrPitch = FixedMul(interp->pitch, pitchMul) + FixedMul(interp->roll, rollMul); + + return (rollOrPitch + R_ModelRotationAngle(interp)); +#else + return R_ModelRotationAngle(interp); +#endif +} + INT32 R_GetRollAngle(angle_t rollangle) { INT32 ra = AngleFixed(rollangle)>>FRACBITS; diff --git a/src/r_picformats.c b/src/r_picformats.c index 9aea8c6c1496430cac950ad7c7a7de408f6fbf62..3e817f4a06199bb47c38f198c6ceb6cd447a6452 100644 --- a/src/r_picformats.c +++ b/src/r_picformats.c @@ -1407,7 +1407,6 @@ static void R_ParseSpriteInfoFrame(spriteinfo_t *info) UINT8 frameFrame = 0xFF; INT16 frameXPivot = 0; INT16 frameYPivot = 0; - rotaxis_t frameRotAxis = 0; // Sprite identifier sprinfoToken = M_GetToken(NULL); @@ -1458,12 +1457,6 @@ static void R_ParseSpriteInfoFrame(spriteinfo_t *info) { Z_Free(sprinfoToken); sprinfoToken = M_GetToken(NULL); - if ((stricmp(sprinfoToken, "X")==0) || (stricmp(sprinfoToken, "XAXIS")==0) || (stricmp(sprinfoToken, "ROLL")==0)) - frameRotAxis = ROTAXIS_X; - else if ((stricmp(sprinfoToken, "Y")==0) || (stricmp(sprinfoToken, "YAXIS")==0) || (stricmp(sprinfoToken, "PITCH")==0)) - frameRotAxis = ROTAXIS_Y; - else if ((stricmp(sprinfoToken, "Z")==0) || (stricmp(sprinfoToken, "ZAXIS")==0) || (stricmp(sprinfoToken, "YAW")==0)) - frameRotAxis = ROTAXIS_Z; } Z_Free(sprinfoToken); @@ -1480,7 +1473,6 @@ static void R_ParseSpriteInfoFrame(spriteinfo_t *info) // set fields info->pivot[frameFrame].x = frameXPivot; info->pivot[frameFrame].y = frameYPivot; - info->pivot[frameFrame].rotaxis = frameRotAxis; } // diff --git a/src/r_picformats.h b/src/r_picformats.h index 4f9637460085b98ae3e5c629fff57c06678f9b02..4050a1b71dc01e8a60cbb14cbe017716c61038c3 100644 --- a/src/r_picformats.h +++ b/src/r_picformats.h @@ -95,7 +95,6 @@ typedef enum typedef struct { INT32 x, y; - rotaxis_t rotaxis; } spriteframepivot_t; typedef struct diff --git a/src/r_plane.c b/src/r_plane.c index c568484b6ed7e71335a665a40710753d2608133f..29ce26b292e5ea529d937aded0028e41a8d294ba 100644 --- a/src/r_plane.c +++ b/src/r_plane.c @@ -53,10 +53,6 @@ INT32 numffloors; #define visplane_hash(picnum,lightlevel,height) \ ((unsigned)((picnum)*3+(lightlevel)+(height)*7) & VISPLANEHASHMASK) -//SoM: 3/23/2000: Use boom opening limit removal -size_t maxopenings; -INT16 *openings, *lastopening; /// \todo free leak - // // Clip values are the solid pixel bounding the range. // floorclip starts out SCREENHEIGHT @@ -366,8 +362,6 @@ void R_ClearPlanes(void) freehead = &(*freehead)->next; } - lastopening = openings; - // texture calculation memset(cachedheight, 0, sizeof (cachedheight)); } diff --git a/src/r_plane.h b/src/r_plane.h index 9870a43e26286e5e888a13f20fa72ecf8b38be08..917e8b041b75775016dbc2a1e10b8cc6ad7a3778 100644 --- a/src/r_plane.h +++ b/src/r_plane.h @@ -60,9 +60,6 @@ extern visplane_t *floorplane; extern visplane_t *ceilingplane; // Visplane related. -extern INT16 *lastopening, *openings; -extern size_t maxopenings; - extern INT16 floorclip[MAXVIDWIDTH], ceilingclip[MAXVIDWIDTH]; extern fixed_t frontscale[MAXVIDWIDTH], yslopetab[MAXVIDHEIGHT*16]; extern fixed_t cachedheight[MAXVIDHEIGHT]; diff --git a/src/r_segs.c b/src/r_segs.c index 5bb4f48369fc67a11b8453e130997a54d13c4e06..ac365f6d5038db60a946d83b8c3ed14041c8d26b 100644 --- a/src/r_segs.c +++ b/src/r_segs.c @@ -76,9 +76,22 @@ static fixed_t bottomfrac, bottomstep; static fixed_t topxscale, topyscale, midxscale, midyscale, botxscale, botyscale; static lighttable_t **walllights; -static INT16 *maskedtexturecol; +static fixed_t *maskedtexturecol; static fixed_t *maskedtextureheight = NULL; +//SoM: 3/23/2000: Use boom opening limit removal +static size_t numopenings; +static INT16 *openings, *lastopening; + +static size_t texturecolumntablesize; +static fixed_t *texturecolumntable, *curtexturecolumntable; + +void R_ClearSegTables(void) +{ + lastopening = openings; + curtexturecolumntable = texturecolumntable; +} + // ========================================================================== // R_RenderMaskedSegRange // ========================================================================== @@ -355,170 +368,115 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2) dc_texturemid += (textureheight[texnum])*times + textureheight[texnum]; else dc_texturemid -= (textureheight[texnum])*times; - // calculate lighting - if (maskedtexturecol[dc_x] != INT16_MAX) + + // Check for overflows first + overflow_test = (INT64)centeryfrac - (((INT64)dc_texturemid*spryscale)>>FRACBITS); + if (overflow_test < 0) overflow_test = -overflow_test; + if ((UINT64)overflow_test&0xFFFFFFFF80000000ULL) { - // Check for overflows first - overflow_test = (INT64)centeryfrac - (((INT64)dc_texturemid*spryscale)>>FRACBITS); - if (overflow_test < 0) overflow_test = -overflow_test; - if ((UINT64)overflow_test&0xFFFFFFFF80000000ULL) + // Eh, no, go away, don't waste our time + if (dc_numlights) { - // Eh, no, go away, don't waste our time - if (dc_numlights) + for (i = 0; i < dc_numlights; i++) { - for (i = 0; i < dc_numlights; i++) - { - rlight = &dc_lightlist[i]; - rlight->height += rlight->heightstep; - } + rlight = &dc_lightlist[i]; + rlight->height += rlight->heightstep; } - spryscale += rw_scalestep; - continue; } + spryscale += rw_scalestep; + continue; + } - if (dc_numlights) - { - lighttable_t **xwalllights; - - sprbotscreen = INT32_MAX; - sprtopscreen = windowtop = (centeryfrac - FixedMul(dc_texturemid, spryscale)); - - realbot = windowbottom = FixedMul(textureheight[texnum], spryscale) + sprtopscreen; - dc_iscale = 0xffffffffu / (unsigned)spryscale; + // calculate lighting + if (dc_numlights) + { + lighttable_t **xwalllights; - // draw the texture - col = (column_t *)((UINT8 *)R_GetColumn(texnum, maskedtexturecol[dc_x]) - 3); + sprbotscreen = INT32_MAX; + sprtopscreen = windowtop = (centeryfrac - FixedMul(dc_texturemid, spryscale)); - for (i = 0; i < dc_numlights; i++) - { - rlight = &dc_lightlist[i]; + realbot = windowbottom = FixedMul(textureheight[texnum], spryscale) + sprtopscreen; + dc_iscale = 0xffffffffu / (unsigned)spryscale; - if ((rlight->flags & FOF_NOSHADE)) - continue; + // draw the texture + col = (column_t *)((UINT8 *)R_GetColumn(texnum, (maskedtexturecol[dc_x] >> FRACBITS)) - 3); - if (rlight->lightnum < 0) - xwalllights = scalelight[0]; - else if (rlight->lightnum >= LIGHTLEVELS) - xwalllights = scalelight[LIGHTLEVELS-1]; - else - xwalllights = scalelight[rlight->lightnum]; + for (i = 0; i < dc_numlights; i++) + { + rlight = &dc_lightlist[i]; - pindex = FixedMul(spryscale, LIGHTRESOLUTIONFIX)>>LIGHTSCALESHIFT; + if ((rlight->flags & FOF_NOSHADE)) + continue; - if (pindex >= MAXLIGHTSCALE) - pindex = MAXLIGHTSCALE - 1; + if (rlight->lightnum < 0) + xwalllights = scalelight[0]; + else if (rlight->lightnum >= LIGHTLEVELS) + xwalllights = scalelight[LIGHTLEVELS-1]; + else + xwalllights = scalelight[rlight->lightnum]; - if (rlight->extra_colormap) - rlight->rcolormap = rlight->extra_colormap->colormap + (xwalllights[pindex] - colormaps); - else - rlight->rcolormap = xwalllights[pindex]; + pindex = FixedMul(spryscale, LIGHTRESOLUTIONFIX)>>LIGHTSCALESHIFT; - height = rlight->height; - rlight->height += rlight->heightstep; + if (pindex >= MAXLIGHTSCALE) + pindex = MAXLIGHTSCALE - 1; - if (height <= windowtop) - { - dc_colormap = rlight->rcolormap; - continue; - } + if (rlight->extra_colormap) + rlight->rcolormap = rlight->extra_colormap->colormap + (xwalllights[pindex] - colormaps); + else + rlight->rcolormap = xwalllights[pindex]; - windowbottom = height; - if (windowbottom >= realbot) - { - windowbottom = realbot; - colfunc_2s(col); - for (i++; i < dc_numlights; i++) - { - rlight = &dc_lightlist[i]; - rlight->height += rlight->heightstep; - } + height = rlight->height; + rlight->height += rlight->heightstep; - continue; - } - colfunc_2s(col); - windowtop = windowbottom + 1; + if (height <= windowtop) + { dc_colormap = rlight->rcolormap; + continue; } - windowbottom = realbot; - if (windowtop < windowbottom) + + windowbottom = height; + if (windowbottom >= realbot) + { + windowbottom = realbot; colfunc_2s(col); + for (i++; i < dc_numlights; i++) + { + rlight = &dc_lightlist[i]; + rlight->height += rlight->heightstep; + } - spryscale += rw_scalestep; - continue; + continue; + } + colfunc_2s(col); + windowtop = windowbottom + 1; + dc_colormap = rlight->rcolormap; } + windowbottom = realbot; + if (windowtop < windowbottom) + colfunc_2s(col); - // calculate lighting - pindex = FixedMul(spryscale, LIGHTRESOLUTIONFIX)>>LIGHTSCALESHIFT; - - if (pindex >= MAXLIGHTSCALE) - pindex = MAXLIGHTSCALE - 1; - - dc_colormap = walllights[pindex]; - - if (frontsector->extra_colormap) - dc_colormap = frontsector->extra_colormap->colormap + (dc_colormap - colormaps); - - sprtopscreen = centeryfrac - FixedMul(dc_texturemid, spryscale); - dc_iscale = 0xffffffffu / (unsigned)spryscale; - - // draw the texture - col = (column_t *)((UINT8 *)R_GetColumn(texnum, maskedtexturecol[dc_x]) - 3); - -#if 0 // Disabling this allows inside edges to render below the planes, for until the clipping is fixed to work right when POs are near the camera. -Red - if (curline->dontrenderme && curline->polyseg && (curline->polyseg->flags & POF_RENDERPLANES)) - { - fixed_t my_topscreen; - fixed_t my_bottomscreen; - fixed_t my_yl, my_yh; + spryscale += rw_scalestep; + continue; + } - my_topscreen = sprtopscreen + spryscale*col->topdelta; - my_bottomscreen = sprbotscreen == INT32_MAX ? my_topscreen + spryscale*col->length - : sprbotscreen + spryscale*col->length; + // calculate lighting + pindex = FixedMul(spryscale, LIGHTRESOLUTIONFIX)>>LIGHTSCALESHIFT; - my_yl = (my_topscreen+FRACUNIT-1)>>FRACBITS; - my_yh = (my_bottomscreen-1)>>FRACBITS; - // CONS_Debug(DBG_RENDER, "my_topscreen: %d\nmy_bottomscreen: %d\nmy_yl: %d\nmy_yh: %d\n", my_topscreen, my_bottomscreen, my_yl, my_yh); + if (pindex >= MAXLIGHTSCALE) + pindex = MAXLIGHTSCALE - 1; - if (numffloors) - { - INT32 top = my_yl; - INT32 bottom = my_yh; + dc_colormap = walllights[pindex]; - for (i = 0; i < numffloors; i++) - { - if (!ffloor[i].polyobj || ffloor[i].polyobj != curline->polyseg) - continue; + if (frontsector->extra_colormap) + dc_colormap = frontsector->extra_colormap->colormap + (dc_colormap - colormaps); - if (ffloor[i].height < viewz) - { - INT32 top_w = ffloor[i].plane->top[dc_x]; + sprtopscreen = centeryfrac - FixedMul(dc_texturemid, spryscale); + dc_iscale = 0xffffffffu / (unsigned)spryscale; - // CONS_Debug(DBG_RENDER, "Leveltime : %d\n", leveltime); - // CONS_Debug(DBG_RENDER, "Top is %d, top_w is %d\n", top, top_w); - if (top_w < top) - { - ffloor[i].plane->top[dc_x] = (INT16)top; - ffloor[i].plane->picnum = 0; - } - // CONS_Debug(DBG_RENDER, "top_w is now %d\n", ffloor[i].plane->top[dc_x]); - } - else if (ffloor[i].height > viewz) - { - INT32 bottom_w = ffloor[i].plane->bottom[dc_x]; + // draw the texture + col = (column_t *)((UINT8 *)R_GetColumn(texnum, (maskedtexturecol[dc_x] >> FRACBITS)) - 3); + colfunc_2s(col); - if (bottom_w > bottom) - { - ffloor[i].plane->bottom[dc_x] = (INT16)bottom; - ffloor[i].plane->picnum = 0; - } - } - } - } - } - else -#endif - colfunc_2s(col); - } spryscale += rw_scalestep; } } @@ -862,183 +820,182 @@ 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) + // skew FOF walls + if (ffloortextureslide) { - if (ffloortextureslide) { // skew FOF walls - if (oldx != -1) - dc_texturemid += FixedMul(ffloortextureslide, (maskedtexturecol[oldx]-maskedtexturecol[dc_x])<<FRACBITS); - oldx = dc_x; - } - // Calculate bounds - // clamp the values if necessary to avoid overflows and rendering glitches caused by them + if (oldx != -1) + dc_texturemid += FixedMul(ffloortextureslide, maskedtexturecol[oldx]-maskedtexturecol[dc_x]); + oldx = dc_x; + } - if (top_frac > (INT64)CLAMPMAX) sprtopscreen = windowtop = CLAMPMAX; - else if (top_frac > (INT64)CLAMPMIN) sprtopscreen = windowtop = (fixed_t)top_frac; - else sprtopscreen = windowtop = CLAMPMIN; - if (bottom_frac > (INT64)CLAMPMAX) sprbotscreen = windowbottom = CLAMPMAX; - else if (bottom_frac > (INT64)CLAMPMIN) sprbotscreen = windowbottom = (fixed_t)bottom_frac; - else sprbotscreen = windowbottom = CLAMPMIN; + // Calculate bounds + // clamp the values if necessary to avoid overflows and rendering glitches caused by them + if (top_frac > (INT64)CLAMPMAX) sprtopscreen = windowtop = CLAMPMAX; + else if (top_frac > (INT64)CLAMPMIN) sprtopscreen = windowtop = (fixed_t)top_frac; + else sprtopscreen = windowtop = CLAMPMIN; + if (bottom_frac > (INT64)CLAMPMAX) sprbotscreen = windowbottom = CLAMPMAX; + else if (bottom_frac > (INT64)CLAMPMIN) sprbotscreen = windowbottom = (fixed_t)bottom_frac; + else sprbotscreen = windowbottom = CLAMPMIN; - top_frac += top_step; - bottom_frac += bottom_step; + top_frac += top_step; + bottom_frac += bottom_step; - // SoM: If column is out of range, why bother with it?? - if (windowbottom < topbounds || windowtop > bottombounds) + // SoM: If column is out of range, why bother with it?? + if (windowbottom < topbounds || windowtop > bottombounds) + { + if (dc_numlights) { - if (dc_numlights) + for (i = 0; i < dc_numlights; i++) { - for (i = 0; i < dc_numlights; i++) - { - rlight = &dc_lightlist[i]; - rlight->height += rlight->heightstep; - if (rlight->flags & FOF_CUTLEVEL) - rlight->botheight += rlight->botheightstep; - } + rlight = &dc_lightlist[i]; + rlight->height += rlight->heightstep; + if (rlight->flags & FOF_CUTLEVEL) + rlight->botheight += rlight->botheightstep; } - spryscale += rw_scalestep; - continue; } + spryscale += rw_scalestep; + continue; + } - dc_iscale = 0xffffffffu / (unsigned)spryscale; + dc_iscale = 0xffffffffu / (unsigned)spryscale; - // Get data for the column - col = (column_t *)((UINT8 *)R_GetColumn(texnum,maskedtexturecol[dc_x]) - 3); + // Get data for the column + col = (column_t *)((UINT8 *)R_GetColumn(texnum, (maskedtexturecol[dc_x] >> FRACBITS)) - 3); - // SoM: New code does not rely on R_DrawColumnShadowed_8 which - // will (hopefully) put less strain on the stack. - if (dc_numlights) - { - lighttable_t **xwalllights; - fixed_t height; - fixed_t bheight = 0; - INT32 solid = 0; - INT32 lighteffect = 0; + // SoM: New code does not rely on R_DrawColumnShadowed_8 which + // will (hopefully) put less strain on the stack. + if (dc_numlights) + { + lighttable_t **xwalllights; + fixed_t height; + fixed_t bheight = 0; + INT32 solid = 0; + INT32 lighteffect = 0; - for (i = 0; i < dc_numlights; i++) + for (i = 0; i < dc_numlights; i++) + { + // Check if the current light effects the colormap/lightlevel + rlight = &dc_lightlist[i]; + lighteffect = !(dc_lightlist[i].flags & FOF_NOSHADE); + if (lighteffect) { - // Check if the current light effects the colormap/lightlevel - rlight = &dc_lightlist[i]; - lighteffect = !(dc_lightlist[i].flags & FOF_NOSHADE); - if (lighteffect) - { - lightnum = rlight->lightnum; - - if (lightnum < 0) - xwalllights = scalelight[0]; - else if (lightnum >= LIGHTLEVELS) - xwalllights = scalelight[LIGHTLEVELS-1]; - else - xwalllights = scalelight[lightnum]; - - pindex = FixedMul(spryscale, LIGHTRESOLUTIONFIX)>>LIGHTSCALESHIFT; + lightnum = rlight->lightnum; - if (pindex >= MAXLIGHTSCALE) - pindex = MAXLIGHTSCALE-1; + if (lightnum < 0) + xwalllights = scalelight[0]; + else if (lightnum >= LIGHTLEVELS) + xwalllights = scalelight[LIGHTLEVELS-1]; + else + xwalllights = scalelight[lightnum]; - if (pfloor->fofflags & FOF_FOG) - { - if (pfloor->master->frontsector->extra_colormap) - rlight->rcolormap = pfloor->master->frontsector->extra_colormap->colormap + (xwalllights[pindex] - colormaps); - else - rlight->rcolormap = xwalllights[pindex]; - } - else - { - if (rlight->extra_colormap) - rlight->rcolormap = rlight->extra_colormap->colormap + (xwalllights[pindex] - colormaps); - else - rlight->rcolormap = xwalllights[pindex]; - } - } + pindex = FixedMul(spryscale, LIGHTRESOLUTIONFIX)>>LIGHTSCALESHIFT; - solid = 0; // don't carry over solid-cutting flag from the previous light + if (pindex >= MAXLIGHTSCALE) + pindex = MAXLIGHTSCALE-1; - // Check if the current light can cut the current 3D floor. - if (rlight->flags & FOF_CUTSOLIDS && !(pfloor->fofflags & FOF_EXTRA)) - solid = 1; - else if (rlight->flags & FOF_CUTEXTRA && pfloor->fofflags & FOF_EXTRA) + if (pfloor->fofflags & FOF_FOG) { - if (rlight->flags & FOF_EXTRA) - { - // The light is from an extra 3D floor... Check the flags so - // there are no undesired cuts. - if ((rlight->flags & (FOF_FOG|FOF_SWIMMABLE)) == (pfloor->fofflags & (FOF_FOG|FOF_SWIMMABLE))) - solid = 1; - } + if (pfloor->master->frontsector->extra_colormap) + rlight->rcolormap = pfloor->master->frontsector->extra_colormap->colormap + (xwalllights[pindex] - colormaps); else - solid = 1; + rlight->rcolormap = xwalllights[pindex]; } else - solid = 0; - - height = rlight->height; - rlight->height += rlight->heightstep; - - if (solid) { - bheight = rlight->botheight - (FRACUNIT >> 1); - rlight->botheight += rlight->botheightstep; + if (rlight->extra_colormap) + rlight->rcolormap = rlight->extra_colormap->colormap + (xwalllights[pindex] - colormaps); + else + rlight->rcolormap = xwalllights[pindex]; } + } - if (height <= windowtop) - { - if (lighteffect) - dc_colormap = rlight->rcolormap; - if (solid && windowtop < bheight) - windowtop = bheight; - continue; - } + solid = 0; // don't carry over solid-cutting flag from the previous light - windowbottom = height; - if (windowbottom >= sprbotscreen) + // Check if the current light can cut the current 3D floor. + if (rlight->flags & FOF_CUTSOLIDS && !(pfloor->fofflags & FOF_EXTRA)) + solid = 1; + else if (rlight->flags & FOF_CUTEXTRA && pfloor->fofflags & FOF_EXTRA) + { + if (rlight->flags & FOF_EXTRA) { - windowbottom = sprbotscreen; - // draw the texture - colfunc_2s (col); - for (i++; i < dc_numlights; i++) - { - rlight = &dc_lightlist[i]; - rlight->height += rlight->heightstep; - if (rlight->flags & FOF_CUTLEVEL) - rlight->botheight += rlight->botheightstep; - } - continue; + // The light is from an extra 3D floor... Check the flags so + // there are no undesired cuts. + if ((rlight->flags & (FOF_FOG|FOF_SWIMMABLE)) == (pfloor->fofflags & (FOF_FOG|FOF_SWIMMABLE))) + solid = 1; } - // draw the texture - colfunc_2s (col); - if (solid) - windowtop = bheight; else - windowtop = windowbottom + 1; + solid = 1; + } + else + solid = 0; + + height = rlight->height; + rlight->height += rlight->heightstep; + + if (solid) + { + bheight = rlight->botheight - (FRACUNIT >> 1); + rlight->botheight += rlight->botheightstep; + } + + if (height <= windowtop) + { if (lighteffect) dc_colormap = rlight->rcolormap; + if (solid && windowtop < bheight) + windowtop = bheight; + continue; } - windowbottom = sprbotscreen; - // draw the texture, if there is any space left - if (windowtop < windowbottom) - colfunc_2s (col); - spryscale += rw_scalestep; - continue; + windowbottom = height; + if (windowbottom >= sprbotscreen) + { + windowbottom = sprbotscreen; + // draw the texture + colfunc_2s (col); + for (i++; i < dc_numlights; i++) + { + rlight = &dc_lightlist[i]; + rlight->height += rlight->heightstep; + if (rlight->flags & FOF_CUTLEVEL) + rlight->botheight += rlight->botheightstep; + } + continue; + } + // draw the texture + colfunc_2s (col); + if (solid) + windowtop = bheight; + else + windowtop = windowbottom + 1; + if (lighteffect) + dc_colormap = rlight->rcolormap; } + windowbottom = sprbotscreen; + // draw the texture, if there is any space left + if (windowtop < windowbottom) + colfunc_2s (col); - // calculate lighting - pindex = FixedMul(spryscale, LIGHTRESOLUTIONFIX)>>LIGHTSCALESHIFT; + spryscale += rw_scalestep; + continue; + } - if (pindex >= MAXLIGHTSCALE) - pindex = MAXLIGHTSCALE - 1; + // calculate lighting + pindex = FixedMul(spryscale, LIGHTRESOLUTIONFIX)>>LIGHTSCALESHIFT; - dc_colormap = walllights[pindex]; + if (pindex >= MAXLIGHTSCALE) + pindex = MAXLIGHTSCALE - 1; - if (pfloor->fofflags & FOF_FOG && pfloor->master->frontsector->extra_colormap) - dc_colormap = pfloor->master->frontsector->extra_colormap->colormap + (dc_colormap - colormaps); - else if (frontsector->extra_colormap) - dc_colormap = frontsector->extra_colormap->colormap + (dc_colormap - colormaps); + dc_colormap = walllights[pindex]; - // draw the texture - colfunc_2s (col); - spryscale += rw_scalestep; - } + if (pfloor->fofflags & FOF_FOG && pfloor->master->frontsector->extra_colormap) + dc_colormap = pfloor->master->frontsector->extra_colormap->colormap + (dc_colormap - colormaps); + else if (frontsector->extra_colormap) + dc_colormap = frontsector->extra_colormap->colormap + (dc_colormap - colormaps); + + // draw the texture + colfunc_2s (col); + spryscale += rw_scalestep; } colfunc = colfuncs[BASEDRAWFUNC]; @@ -1281,7 +1238,7 @@ static void R_RenderSegLoop (void) } oldtexturecolumn = texturecolumn; - texturecolumn >>= FRACBITS; + INT32 itexturecolumn = texturecolumn >> FRACBITS; // texturecolumn and lighting are independent of wall tiers if (segtextured) @@ -1348,7 +1305,7 @@ static void R_RenderSegLoop (void) dc_yh = yh; dc_texturemid = FixedMul(rw_midtexturemid, midyscale); dc_iscale = FixedMul(0xffffffffu / (unsigned)rw_scale, midyscale); - dc_source = R_GetColumn(midtexture, texturecolumn_mid); + dc_source = R_GetColumn(midtexture, itexturecolumn + texturecolumn_mid); dc_texheight = textureheight[midtexture]>>FRACBITS; //profile stuff --------------------------------------------------------- @@ -1410,7 +1367,7 @@ static void R_RenderSegLoop (void) dc_yh = mid; dc_texturemid = FixedMul(rw_toptexturemid, topyscale); dc_iscale = FixedMul(0xffffffffu / (unsigned)rw_scale, topyscale); - dc_source = R_GetColumn(toptexture, texturecolumn_top); + dc_source = R_GetColumn(toptexture, itexturecolumn + texturecolumn_top); dc_texheight = textureheight[toptexture]>>FRACBITS; colfunc(); ceilingclip[rw_x] = (INT16)mid; @@ -1447,7 +1404,7 @@ static void R_RenderSegLoop (void) dc_yh = yh; dc_texturemid = FixedMul(rw_bottomtexturemid, botyscale); dc_iscale = FixedMul(0xffffffffu / (unsigned)rw_scale, botyscale); - dc_source = R_GetColumn(bottomtexture, texturecolumn_bot); + dc_source = R_GetColumn(bottomtexture, itexturecolumn + texturecolumn_bot); dc_texheight = textureheight[bottomtexture]>>FRACBITS; colfunc(); floorclip[rw_x] = (INT16)mid; @@ -1525,6 +1482,73 @@ static INT64 R_CalcSegDist(seg_t* seg, INT64 x2, INT64 y2) } } +//SoM: Code to remove limits on openings. +static void R_AllocClippingTables(size_t range) +{ + size_t pos = lastopening - openings; + size_t need = range * 2; // for both sprtopclip and sprbottomclip + + if (pos + need < numopenings) + return; + + INT16 *oldopenings = openings; + INT16 *oldlast = lastopening; + + if (numopenings == 0) + numopenings = 16384; + + numopenings += need; + openings = Z_Realloc(openings, numopenings * sizeof (*openings), PU_STATIC, NULL); + lastopening = openings + pos; + + if (oldopenings == NULL) + return; + + // borrowed fix from *cough* zdoom *cough* + // [RH] We also need to adjust the openings pointers that + // were already stored in drawsegs. + for (drawseg_t *ds = drawsegs; ds < ds_p; ds++) + { + // Check if it's in range of the openings + if (ds->sprtopclip + ds->x1 >= oldopenings && ds->sprtopclip + ds->x1 <= oldlast) + ds->sprtopclip = (ds->sprtopclip - oldopenings) + openings; + if (ds->sprbottomclip + ds->x1 >= oldopenings && ds->sprbottomclip + ds->x1 <= oldlast) + ds->sprbottomclip = (ds->sprbottomclip - oldopenings) + openings; + } +} + +static void R_AllocTextureColumnTables(size_t range) +{ + size_t pos = curtexturecolumntable - texturecolumntable; + + // For both tables, we reserve exactly an amount of memory that's equivalent to + // how many columns the seg will take on the entire screen (think about it) + if (pos + range < texturecolumntablesize) + return; + + fixed_t *oldtable = texturecolumntable; + fixed_t *oldlast = curtexturecolumntable; + + if (texturecolumntablesize == 0) + texturecolumntablesize = 16384; + + texturecolumntablesize += range; + texturecolumntable = Z_Realloc(texturecolumntable, texturecolumntablesize * sizeof (*texturecolumntable), PU_STATIC, NULL); + curtexturecolumntable = texturecolumntable + pos; + + if (oldtable == NULL) + return; + + for (drawseg_t *ds = drawsegs; ds < ds_p; ds++) + { + // Check if it's in range of the tables + if (ds->maskedtexturecol + ds->x1 >= oldtable && ds->maskedtexturecol + ds->x1 <= oldlast) + ds->maskedtexturecol = (ds->maskedtexturecol - oldtable) + texturecolumntable; + if (ds->thicksidecol + ds->x1 >= oldtable && ds->thicksidecol + ds->x1 <= oldlast) + ds->thicksidecol = (ds->thicksidecol - oldtable) + texturecolumntable; + } +} + // // R_StoreWallRange // A wall segment will be drawn @@ -1593,37 +1617,6 @@ void R_StoreWallRange(INT32 start, INT32 stop) ds_p->curline = curline; rw_stopx = stop+1; - //SoM: Code to remove limits on openings. - { - size_t pos = lastopening - openings; - size_t need = (rw_stopx - start)*4 + pos; - if (need > maxopenings) - { - drawseg_t *ds; //needed for fix from *cough* zdoom *cough* - INT16 *oldopenings = openings; - INT16 *oldlast = lastopening; - - do - maxopenings = maxopenings ? maxopenings*2 : 16384; - while (need > maxopenings); - openings = Z_Realloc(openings, maxopenings * sizeof (*openings), PU_STATIC, NULL); - lastopening = openings + pos; - - // borrowed fix from *cough* zdoom *cough* - // [RH] We also need to adjust the openings pointers that - // were already stored in drawsegs. - for (ds = drawsegs; ds < ds_p; ds++) - { -#define ADJUST(p) if (ds->p + ds->x1 >= oldopenings && ds->p + ds->x1 <= oldlast) ds->p = ds->p - oldopenings + openings; - ADJUST(maskedtexturecol); - ADJUST(sprtopclip); - ADJUST(sprbottomclip); - ADJUST(thicksidecol); -#undef ADJUST - } - } - } // end of code to remove limits on openings - // calculate scale at both ends and step ds_p->scale1 = rw_scale = R_ScaleFromGlobalAngle(viewangle + xtoviewangle[start]); @@ -1920,9 +1913,9 @@ void R_StoreWallRange(INT32 start, INT32 stop) || backsector->floorpic != frontsector->floorpic || backsector->lightlevel != frontsector->lightlevel //SoM: 3/22/2000: Check floor x and y offsets. - || backsector->floor_xoffs != frontsector->floor_xoffs - || backsector->floor_yoffs != frontsector->floor_yoffs - || backsector->floorpic_angle != frontsector->floorpic_angle + || backsector->floorxoffset != frontsector->floorxoffset + || backsector->flooryoffset != frontsector->flooryoffset + || backsector->floorangle != frontsector->floorangle //SoM: 3/22/2000: Prevents bleeding. || (frontsector->heightsec != -1 && frontsector->floorpic != skyflatnum) || backsector->floorlightlevel != frontsector->floorlightlevel @@ -1953,9 +1946,9 @@ void R_StoreWallRange(INT32 start, INT32 stop) || backsector->ceilingpic != frontsector->ceilingpic || backsector->lightlevel != frontsector->lightlevel //SoM: 3/22/2000: Check floor x and y offsets. - || backsector->ceiling_xoffs != frontsector->ceiling_xoffs - || backsector->ceiling_yoffs != frontsector->ceiling_yoffs - || backsector->ceilingpic_angle != frontsector->ceilingpic_angle + || backsector->ceilingxoffset != frontsector->ceilingxoffset + || backsector->ceilingyoffset != frontsector->ceilingyoffset + || backsector->ceilingangle != frontsector->ceilingangle //SoM: 3/22/2000: Prevents bleeding. || (frontsector->heightsec != -1 && frontsector->ceilingpic != skyflatnum) || backsector->ceilinglightlevel != frontsector->ceilinglightlevel @@ -2039,6 +2032,8 @@ void R_StoreWallRange(INT32 start, INT32 stop) rw_toptexturemid += sidedef->rowoffset + sidedef->offsety_top; rw_bottomtexturemid += sidedef->rowoffset + sidedef->offsety_bot; + R_AllocTextureColumnTables(rw_stopx - start); + // allocate space for masked texture tables if (frontsector && backsector && !Tag_Compare(&frontsector->tags, &backsector->tags) && (backsector->ffloors || frontsector->ffloors)) { @@ -2053,8 +2048,8 @@ void R_StoreWallRange(INT32 start, INT32 stop) //markceiling = markfloor = true; maskedtexture = true; - ds_p->thicksidecol = maskedtexturecol = lastopening - rw_x; - lastopening += rw_stopx - rw_x; + ds_p->thicksidecol = maskedtexturecol = curtexturecolumntable - rw_x; + curtexturecolumntable += rw_stopx - rw_x; lowcut = max(worldbottom, worldlow) + viewz; highcut = min(worldtop, worldhigh) + viewz; @@ -2237,8 +2232,8 @@ void R_StoreWallRange(INT32 start, INT32 stop) // masked midtexture if (!ds_p->thicksidecol) { - ds_p->maskedtexturecol = maskedtexturecol = lastopening - rw_x; - lastopening += rw_stopx - rw_x; + ds_p->maskedtexturecol = maskedtexturecol = curtexturecolumntable - rw_x; + curtexturecolumntable += rw_stopx - rw_x; } else ds_p->maskedtexturecol = ds_p->thicksidecol; @@ -2762,29 +2757,34 @@ void R_StoreWallRange(INT32 start, INT32 stop) ds_p->portalpass = 0; // save sprite clipping info - if (((ds_p->silhouette & SIL_TOP) || maskedtexture) && !ds_p->sprtopclip) + if (maskedtexture || (ds_p->silhouette & (SIL_TOP | SIL_BOTTOM))) { - M_Memcpy(lastopening, ceilingclip+start, 2*(rw_stopx - start)); - ds_p->sprtopclip = lastopening - start; - lastopening += rw_stopx - start; - } + R_AllocClippingTables(rw_stopx - start); - if (((ds_p->silhouette & SIL_BOTTOM) || maskedtexture) && !ds_p->sprbottomclip) - { - M_Memcpy(lastopening, floorclip + start, 2*(rw_stopx-start)); - ds_p->sprbottomclip = lastopening - start; - lastopening += rw_stopx - start; + if (((ds_p->silhouette & SIL_TOP) || maskedtexture) && !ds_p->sprtopclip) + { + M_Memcpy(lastopening, ceilingclip + start, 2*(rw_stopx - start)); + ds_p->sprtopclip = lastopening - start; + lastopening += rw_stopx - start; + } + + if (((ds_p->silhouette & SIL_BOTTOM) || maskedtexture) && !ds_p->sprbottomclip) + { + M_Memcpy(lastopening, floorclip + start, 2*(rw_stopx - start)); + ds_p->sprbottomclip = lastopening - start; + lastopening += rw_stopx - start; + } } if (maskedtexture && !(ds_p->silhouette & SIL_TOP)) { ds_p->silhouette |= SIL_TOP; - ds_p->tsilheight = (sidedef->midtexture > 0 && sidedef->midtexture < numtextures) ? INT32_MIN: INT32_MAX; + ds_p->tsilheight = (sidedef->midtexture > 0 && sidedef->midtexture < numtextures) ? INT32_MIN : INT32_MAX; } if (maskedtexture && !(ds_p->silhouette & SIL_BOTTOM)) { ds_p->silhouette |= SIL_BOTTOM; - ds_p->bsilheight = (sidedef->midtexture > 0 && sidedef->midtexture < numtextures) ? INT32_MAX: INT32_MIN; + ds_p->bsilheight = (sidedef->midtexture > 0 && sidedef->midtexture < numtextures) ? INT32_MAX : INT32_MIN; } ds_p++; } diff --git a/src/r_segs.h b/src/r_segs.h index 09c68b27e95eb34deb1302762d9d8a50e72e44dc..cad0146748bb4ab77325285a6290fc195d4399bc 100644 --- a/src/r_segs.h +++ b/src/r_segs.h @@ -22,5 +22,6 @@ transnum_t R_GetLinedefTransTable(fixed_t alpha); void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2); void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pffloor); void R_StoreWallRange(INT32 start, INT32 stop); +void R_ClearSegTables(void); #endif diff --git a/src/r_skins.c b/src/r_skins.c index 2c031ee851d129b4d2d2254c517e9c8e90924661..72598f38185acf3d5801365e315e54a920e38511 100644 --- a/src/r_skins.c +++ b/src/r_skins.c @@ -113,6 +113,7 @@ static void Sk_SetDefaultValue(skin_t *skin) strcpy(skin->realname, "Someone"); strcpy(skin->hudname, "???"); + strcpy(skin->supername, "Someone super"); skin->starttranscolor = 96; skin->prefcolor = SKINCOLOR_GREEN; @@ -190,7 +191,8 @@ UINT32 R_GetSkinAvailabilities(void) // This crash is impossible to trigger as is, // but it could happen if MAXUNLOCKABLES is ever made higher than 32, // and someone makes a mod that has 33+ unlockable characters. :V - I_Error("Too many unlockable characters\n"); + // 2022/03/15: MAXUNLOCKABLES is now higher than 32 + I_Error("Too many unlockable characters! (maximum is 32)\n"); return 0; } @@ -534,7 +536,7 @@ static void R_LoadSkinSprites(UINT16 wadnum, UINT16 *lump, UINT16 *lastlump, ski R_AddSingleSpriteDef(spr2names[sprite2], &skin->sprites[sprite2], wadnum, *lump, *lastlump); if (skin->sprites[0].numframes == 0) - I_Error("R_LoadSkinSprites: no frames found for sprite SPR2_%s\n", spr2names[0]); + CONS_Alert(CONS_ERROR, M_GetText("No frames found for sprite SPR2_%s\n"), spr2names[0]); } // returns whether found appropriate property @@ -681,7 +683,7 @@ void R_AddSkins(UINT16 wadnum, boolean mainfile) char *value; size_t size; skin_t *skin; - boolean hudname, realname; + boolean hudname, realname, supername; // // search for all skin markers in pwad @@ -711,7 +713,7 @@ void R_AddSkins(UINT16 wadnum, boolean mainfile) skin = &skins[numskins]; Sk_SetDefaultValue(skin); skin->wadnum = wadnum; - hudname = realname = false; + hudname = realname = supername = false; // parse stoken = strtok (buf2, "\r\n= "); while (stoken) @@ -754,7 +756,7 @@ void R_AddSkins(UINT16 wadnum, boolean mainfile) Z_Free(value2); } - // copy to hudname and fullname as a default. + // copy to hudname, realname, and supername as a default. if (!realname) { STRBUFCPY(skin->realname, skin->name); @@ -770,6 +772,19 @@ void R_AddSkins(UINT16 wadnum, boolean mainfile) strupr(skin->hudname); SYMBOLCONVERT(skin->hudname) } + if (!supername) + { + char superstring[SKINNAMESIZE+7]; + strcpy(superstring, "Super "); + strlcat(superstring, skin->name, sizeof(superstring)); + STRBUFCPY(skin->supername, superstring); + } + } + else if (!stricmp(stoken, "supername")) + { // Super name (eg. "Super Knuckles") + supername = true; + STRBUFCPY(skin->supername, value); + SYMBOLCONVERT(skin->supername) } else if (!stricmp(stoken, "realname")) { // Display name (eg. "Knuckles") @@ -778,6 +793,13 @@ void R_AddSkins(UINT16 wadnum, boolean mainfile) SYMBOLCONVERT(skin->realname) if (!hudname) HUDNAMEWRITE(skin->realname); + if (!supername) //copy over default to capitalise the name + { + char superstring[SKINNAMESIZE+7]; + strcpy(superstring, "Super "); + strlcat(superstring, skin->realname, sizeof(superstring)); + STRBUFCPY(skin->supername, superstring); + } } else if (!stricmp(stoken, "hudname")) { // Life icon name (eg. "K.T.E") @@ -830,7 +852,7 @@ void R_PatchSkins(UINT16 wadnum, boolean mainfile) char *value; size_t size; skin_t *skin; - boolean noskincomplain, realname, hudname; + boolean noskincomplain, realname, hudname, supername; // // search for all skin patch markers in pwad @@ -854,7 +876,7 @@ void R_PatchSkins(UINT16 wadnum, boolean mainfile) buf2[size] = '\0'; skin = NULL; - noskincomplain = realname = hudname = false; + noskincomplain = realname = hudname = supername = false; /* Parse. Has more phases than the parser in R_AddSkins because it needs to have the patching name first (no default skin name is acceptible for patching, unlike skin creation) @@ -893,13 +915,26 @@ void R_PatchSkins(UINT16 wadnum, boolean mainfile) else // Get the properties! { // Some of these can't go in R_ProcessPatchableFields because they have side effects for future lines. - if (!stricmp(stoken, "realname")) + if (!stricmp(stoken, "supername")) + { // Super name (eg. "Super Knuckles") + supername = true; + STRBUFCPY(skin->supername, value); + SYMBOLCONVERT(skin->supername) + } + else if (!stricmp(stoken, "realname")) { // Display name (eg. "Knuckles") realname = true; STRBUFCPY(skin->realname, value); SYMBOLCONVERT(skin->realname) if (!hudname) HUDNAMEWRITE(skin->realname); + if (!supername) //copy over default to capitalise the name + { + char superstring[SKINNAMESIZE+7]; + strcpy(superstring, "Super "); + strlcat(superstring, skin->realname, sizeof(superstring)); + STRBUFCPY(skin->supername, superstring); + } } else if (!stricmp(stoken, "hudname")) { // Life icon name (eg. "K.T.E") diff --git a/src/r_skins.h b/src/r_skins.h index 082b690dda8294ed2f250a5aaba118a765073a21..fab6fc12c0f659e8b35f5d111a497850edf127b0 100644 --- a/src/r_skins.h +++ b/src/r_skins.h @@ -35,8 +35,9 @@ typedef struct UINT16 wadnum; skinflags_t flags; - char realname[SKINNAMESIZE+1]; // Display name for level completion. + char realname[SKINNAMESIZE+1]; // Display name for level completion char hudname[SKINNAMESIZE+1]; // HUD name to display (officially exactly 5 characters long) + char supername[SKINNAMESIZE+7]; // Super name to display when collecting all emeralds UINT8 ability; // ability definition UINT8 ability2; // secondary ability definition diff --git a/src/r_splats.c b/src/r_splats.c index 72bfe74b3a7be6ac50313793f4ea28e7f6bc8c5e..0b482d7988cc0e3a32f719a0f84a272fdf63d2f3 100644 --- a/src/r_splats.c +++ b/src/r_splats.c @@ -31,20 +31,8 @@ static void prepare_rastertab(void); static void R_RasterizeFloorSplat(floorsplat_t *pSplat, vector2_t *verts, vissprite_t *vis); -#ifdef USEASM -void ASMCALL rasterize_segment_tex_asm(INT32 x1, INT32 y1, INT32 x2, INT32 y2, INT32 tv1, INT32 tv2, INT32 tc, INT32 dir); -#endif - static void rasterize_segment_tex(INT32 x1, INT32 y1, INT32 x2, INT32 y2, INT32 tv1, INT32 tv2, INT32 tc, INT32 dir) { -#ifdef USEASM - if (R_ASM) - { - rasterize_segment_tex_asm(x1, y1, x2, y2, tv1, tv2, tc, dir); - return; - } - else -#endif { fixed_t xs, xe, count; fixed_t dx0, dx1; @@ -191,7 +179,7 @@ void R_DrawFloorSplat(vissprite_t *spr) splatangle = spr->viewpoint.angle; if (!(spr->cut & SC_ISROTATED)) - splatangle += mobj->rollangle; + splatangle += mobj->spriteroll; splat.angle = -splatangle; splat.angle += ANGLE_90; @@ -326,9 +314,7 @@ static void R_RasterizeFloorSplat(floorsplat_t *pSplat, vector2_t *verts, visspr fixed_t planeheight = 0; fixed_t step; - int spanfunctype = SPANDRAWFUNC_SPRITE; - - prepare_rastertab(); + int spanfunctype; #define RASTERPARAMS(vnum1, vnum2, tv1, tv2, tc, dir) \ x1 = verts[vnum1].x; \ @@ -379,21 +365,15 @@ static void R_RasterizeFloorSplat(floorsplat_t *pSplat, vector2_t *verts, visspr if (ry1 > maxy) \ maxy = ry1; - // do segment a -> top of texture - RASTERPARAMS(3,2,0,pSplat->width-1,0,0); - // do segment b -> right side of texture - RASTERPARAMS(2,1,0,pSplat->width-1,pSplat->height-1,0); - // do segment c -> bottom of texture - RASTERPARAMS(1,0,pSplat->width-1,0,pSplat->height-1,0); - // do segment d -> left side of texture - RASTERPARAMS(0,3,pSplat->width-1,0,0,1); - ds_source = (UINT8 *)pSplat->pic; ds_flatwidth = pSplat->width; ds_flatheight = pSplat->height; - ds_powersoftwo = false; - if (R_CheckPowersOfTwo()) + ds_powersoftwo = ds_solidcolor = false; + + if (R_CheckSolidColorFlat()) + ds_solidcolor = true; + else if (R_CheckPowersOfTwo()) { R_SetFlatVars(ds_flatwidth * ds_flatheight); ds_powersoftwo = true; @@ -404,9 +384,8 @@ static void R_RasterizeFloorSplat(floorsplat_t *pSplat, vector2_t *verts, visspr R_SetTiltedSpan(0); R_SetScaledSlopePlane(pSplat->slope, vis->viewpoint.x, vis->viewpoint.y, vis->viewpoint.z, pSplat->xscale, pSplat->yscale, -pSplat->verts[0].x, pSplat->verts[0].y, vis->viewpoint.angle, pSplat->angle); R_CalculateSlopeVectors(); - spanfunctype = SPANDRAWFUNC_TILTEDSPRITE; } - else + else if (!ds_solidcolor) { planeheight = abs(pSplat->z - vis->viewpoint.z); @@ -441,23 +420,70 @@ static void R_RasterizeFloorSplat(floorsplat_t *pSplat, vector2_t *verts, visspr ds_colormap = &vis->extra_colormap->colormap[ds_colormap - colormaps]; } - if (vis->transmap) + ds_transmap = vis->transmap; + + // Determine which R_DrawWhatever to use + + // Solid color + if (ds_solidcolor) { - ds_transmap = vis->transmap; + UINT16 px = *(UINT16 *)ds_source; + + // Uh, it's not visible. + if (!(px & 0xFF00)) + return; + + // Pixel color is contained in the lower 8 bits (upper 8 are the opacity), so advance the pointer + ds_source++; + if (pSplat->slope) + { + if (ds_transmap) + spanfunctype = SPANDRAWFUNC_TILTEDTRANSSOLID; + else + spanfunctype = SPANDRAWFUNC_TILTEDSOLID; + } + else + { + if (ds_transmap) + spanfunctype = SPANDRAWFUNC_TRANSSOLID; + else + spanfunctype = SPANDRAWFUNC_SOLID; + } + } + // Transparent + else if (ds_transmap) + { if (pSplat->slope) spanfunctype = SPANDRAWFUNC_TILTEDTRANSSPRITE; else spanfunctype = SPANDRAWFUNC_TRANSSPRITE; } + // Opaque else - ds_transmap = NULL; + { + if (pSplat->slope) + spanfunctype = SPANDRAWFUNC_TILTEDSPRITE; + else + spanfunctype = SPANDRAWFUNC_SPRITE; + } - if (ds_powersoftwo) + if (ds_powersoftwo || ds_solidcolor) spanfunc = spanfuncs[spanfunctype]; else spanfunc = spanfuncs_npo2[spanfunctype]; + prepare_rastertab(); + + // do segment a -> top of texture + RASTERPARAMS(3,2,0,pSplat->width-1,0,0); + // do segment b -> right side of texture + RASTERPARAMS(2,1,0,pSplat->width-1,pSplat->height-1,0); + // do segment c -> bottom of texture + RASTERPARAMS(1,0,pSplat->width-1,0,pSplat->height-1,0); + // do segment d -> left side of texture + RASTERPARAMS(0,3,pSplat->width-1,0,0,1); + if (maxy >= vid.height) maxy = vid.height-1; @@ -512,7 +538,7 @@ static void R_RasterizeFloorSplat(floorsplat_t *pSplat, vector2_t *verts, visspr if (x2 < x1) continue; - if (!pSplat->slope) + if (!ds_solidcolor && !pSplat->slope) { fixed_t xstep, ystep; fixed_t distance, span; @@ -561,7 +587,7 @@ static void R_RasterizeFloorSplat(floorsplat_t *pSplat, vector2_t *verts, visspr rastertab[y].maxx = INT32_MIN; } - if (pSplat->angle && !pSplat->slope) + if (!ds_solidcolor && pSplat->angle && !pSplat->slope) memset(cachedheight, 0, sizeof(cachedheight)); } diff --git a/src/r_textures.c b/src/r_textures.c index 69e64074d8acefa5e73e52e6311cc3a776d191da..8b47f455e8bc7e2e3a9cb766fb38b357b96d4091 100644 --- a/src/r_textures.c +++ b/src/r_textures.c @@ -1662,6 +1662,35 @@ INT32 R_CheckTextureNumForName(const char *name) return -1; } +// +// R_CheckTextureNameForNum +// +// because sidedefs use numbers and sometimes you want names +// returns no texture marker if no texture was found +// +const char *R_CheckTextureNameForNum(INT32 num) +{ + if (num > 0 && num < numtextures) + return textures[num]->name; + + return "-"; +} + +// +// R_TextureNameForNum +// +// calls R_CheckTextureNameForNum and returns REDWALL if result is a no texture marker +// +const char *R_TextureNameForNum(INT32 num) +{ + const char *result = R_CheckTextureNameForNum(num); + + if (strcmp(result, "-") == 0) + return "REDWALL"; + + return result; +} + // // R_TextureNumForName // diff --git a/src/r_textures.h b/src/r_textures.h index 4a3c10b9ec999fc133a5f5ffe220f03f86ce2ff6..394b4f8243a7fa7a0de120f2ff893bc1dc9f0702 100644 --- a/src/r_textures.h +++ b/src/r_textures.h @@ -104,6 +104,10 @@ INT32 R_TextureNumForName(const char *name); INT32 R_CheckTextureNumForName(const char *name); lumpnum_t R_GetFlatNumForName(const char *name); +// Returns the texture name for the texture number (in case you ever needed it) +const char *R_CheckTextureNameForNum(INT32 num); +const char *R_TextureNameForNum(INT32 num); + extern INT32 numtextures; #endif diff --git a/src/r_things.c b/src/r_things.c index 89b9fe07ef89ddd0307317ca0933608b7cbdf7ff..be9c5cdffe26be0a5482489d9540a50a2a599998 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -80,6 +80,33 @@ static spriteframe_t sprtemp[64]; static size_t maxframe; static const char *spritename; +// +// Clipping against drawsegs optimization, from prboom-plus +// +// TODO: This should be done with proper subsector pass through +// sprites which would ideally remove the need to do it at all. +// Unfortunately, SRB2's drawing loop has lots of annoying +// changes from Doom for portals, which make it hard to implement. + +typedef struct drawseg_xrange_item_s +{ + INT16 x1, x2; + drawseg_t *user; +} drawseg_xrange_item_t; + +typedef struct drawsegs_xrange_s +{ + drawseg_xrange_item_t *items; + INT32 count; +} drawsegs_xrange_t; + +#define DS_RANGES_COUNT 3 +static drawsegs_xrange_t drawsegs_xranges[DS_RANGES_COUNT]; + +static drawseg_xrange_item_t *drawsegs_xrange; +static size_t drawsegs_xrange_size = 0; +static INT32 drawsegs_xrange_count = 0; + // ========================================================================== // // Sprite loading routines: support sprites in pwad, dehacked sprite renaming, @@ -497,7 +524,8 @@ void R_AddSpriteDefs(UINT16 wadnum) // // GAME FUNCTIONS // -UINT32 visspritecount; +UINT32 visspritecount, numvisiblesprites; + static UINT32 clippedvissprites; static vissprite_t *visspritechunks[MAXVISSPRITES >> VISSPRITECHUNKBITS] = {NULL}; @@ -571,7 +599,7 @@ void R_InitSprites(void) // void R_ClearSprites(void) { - visspritecount = clippedvissprites = 0; + visspritecount = numvisiblesprites = clippedvissprites = 0; } // @@ -817,6 +845,15 @@ static void R_DrawVisSprite(vissprite_t *vis) if ((UINT64)overflow_test&0xFFFFFFFF80000000ULL) return; // ditto } + // 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)) + { + // never draw vissprites with startfrac out of patch range + return; + } + colfunc = colfuncs[BASEDRAWFUNC]; // hack: this isn't resetting properly somewhere. dc_colormap = vis->colormap; dc_translation = R_GetSpriteTranslation(vis); @@ -860,7 +897,7 @@ static void R_DrawVisSprite(vissprite_t *vis) frac = vis->startfrac; windowtop = windowbottom = sprbotscreen = INT32_MAX; - if (!(vis->cut & SC_PRECIP) && vis->mobj->skin && ((skin_t *)vis->mobj->skin)->flags & SF_HIRES) + if (vis->cut & SC_SHADOW && vis->mobj->skin && ((skin_t *)vis->mobj->skin)->flags & SF_HIRES) this_scale = FixedMul(this_scale, ((skin_t *)vis->mobj->skin)->highresscale); if (this_scale <= 0) this_scale = 1; @@ -870,10 +907,10 @@ static void R_DrawVisSprite(vissprite_t *vis) { vis->scale = FixedMul(vis->scale, this_scale); vis->scalestep = FixedMul(vis->scalestep, this_scale); - vis->xiscale = FixedDiv(vis->xiscale,this_scale); + vis->xiscale = FixedDiv(vis->xiscale, this_scale); vis->cut |= SC_ISSCALED; } - dc_texturemid = FixedDiv(dc_texturemid,this_scale); + dc_texturemid = FixedDiv(dc_texturemid, this_scale); } spryscale = vis->scale; @@ -1157,7 +1194,7 @@ fixed_t R_GetShadowZ(mobj_t *thing, pslope_t **shadowslope) R_InterpolateMobjState(thing, FRACUNIT, &interp); } - halfHeight = interp.z + (thing->height >> 1); + halfHeight = interp.z + (interp.height >> 1); floorz = P_GetFloorZ(thing, interp.subsector->sector, interp.x, interp.y, NULL); ceilingz = P_GetCeilingZ(thing, interp.subsector->sector, interp.x, interp.y, NULL); @@ -1221,8 +1258,8 @@ fixed_t R_GetShadowZ(mobj_t *thing, pslope_t **shadowslope) } } - if (isflipped ? (ceilingz < groundz - (!groundslope ? 0 : FixedMul(abs(groundslope->zdelta), thing->radius*3/2))) - : (floorz > groundz + (!groundslope ? 0 : FixedMul(abs(groundslope->zdelta), thing->radius*3/2)))) + if (isflipped ? (ceilingz < groundz - (!groundslope ? 0 : FixedMul(abs(groundslope->zdelta), interp.radius*3/2))) + : (floorz > groundz + (!groundslope ? 0 : FixedMul(abs(groundslope->zdelta), interp.radius*3/2)))) { groundz = isflipped ? ceilingz : floorz; groundslope = NULL; @@ -1265,9 +1302,9 @@ static void R_SkewShadowSprite( //CONS_Printf("Shadow is sloped by %d %d\n", xslope, zslope); if (viewz < groundz) - *shadowyscale += FixedMul(FixedMul(thing->radius*2 / spriteheight, scalemul), zslope); + *shadowyscale += FixedMul(FixedMul(interp.radius*2 / spriteheight, scalemul), zslope); else - *shadowyscale -= FixedMul(FixedMul(thing->radius*2 / spriteheight, scalemul), zslope); + *shadowyscale -= FixedMul(FixedMul(interp.radius*2 / spriteheight, scalemul), zslope); *shadowyscale = abs((*shadowyscale)); *shadowskew = xslope; @@ -1318,20 +1355,18 @@ static void R_ProjectDropShadow(mobj_t *thing, vissprite_t *vis, fixed_t scale, return; } - floordiff = abs((isflipped ? thing->height : 0) + interp.z - groundz); + floordiff = abs((isflipped ? interp.height : 0) + interp.z - groundz); trans = floordiff / (100*FRACUNIT) + 3; if (trans >= 9) return; scalemul = FixedMul(FRACUNIT - floordiff/640, scale); - if ((thing->scale != thing->old_scale) && (thing->scale >= FRACUNIT/1024)) // Interpolate shadows when scaling mobjs - scalemul = FixedMul(scalemul, FixedDiv(interp.scale, thing->scale)); patch = W_CachePatchName("DSHADOW", PU_SPRITE); xscale = FixedDiv(projection, tz); yscale = FixedDiv(projectiony, tz); - shadowxscale = FixedMul(thing->radius*2, scalemul); - shadowyscale = FixedMul(FixedMul(thing->radius*2, scalemul), FixedDiv(abs(groundz - viewz), tz)); + shadowxscale = FixedMul(interp.radius*2, scalemul); + shadowyscale = FixedMul(FixedMul(interp.radius*2, scalemul), FixedDiv(abs(groundz - viewz), tz)); shadowyscale = min(shadowyscale, shadowxscale) / patch->height; shadowxscale /= patch->width; shadowskew = 0; @@ -1426,6 +1461,105 @@ static void R_ProjectDropShadow(mobj_t *thing, vissprite_t *vis, fixed_t scale, objectsdrawn++; } +static void R_ProjectBoundingBox(mobj_t *thing, vissprite_t *vis) +{ + fixed_t gx, gy; + fixed_t tx, tz; + + vissprite_t *box; + + if (!R_ThingBoundingBoxVisible(thing)) + { + return; + } + + // uncapped/interpolation + boolean interpolate = cv_renderhitboxinterpolation.value; + interpmobjstate_t interp = {0}; + + // do interpolation + if (R_UsingFrameInterpolation() && !paused && interpolate) + { + R_InterpolateMobjState(thing, rendertimefrac, &interp); + } + else + { + R_InterpolateMobjState(thing, FRACUNIT, &interp); + } + + // 1--3 + // | | + // 0--2 + + // start in the (0) corner + gx = interp.x - interp.radius - viewx; + gy = interp.y - interp.radius - viewy; + + tz = FixedMul(gx, viewcos) + FixedMul(gy, viewsin); + + // thing is behind view plane? + // if parent vis is visible, ignore this + if (!vis && (tz < FixedMul(MINZ, interp.scale))) + { + return; + } + + tx = FixedMul(gx, viewsin) - FixedMul(gy, viewcos); + + // too far off the side? + if (!vis && abs(tx) > FixedMul(tz, fovtan)<<2) + { + return; + } + + box = R_NewVisSprite(); + box->mobj = thing; + box->mobjflags = thing->flags; + box->thingheight = interp.height; + box->cut = SC_BBOX; + + box->gx = tx; + box->gy = tz; + + box->scale = 2 * FixedMul(interp.radius, viewsin); + box->xscale = 2 * FixedMul(interp.radius, viewcos); + + box->pz = interp.z; + box->pzt = box->pz + box->thingheight; + + box->gzt = box->pzt; + box->gz = box->pz; + box->texturemid = box->gzt - viewz; + + if (vis) + { + box->x1 = vis->x1; + box->x2 = vis->x2; + box->szt = vis->szt; + box->sz = vis->sz; + + box->sortscale = vis->sortscale; // link sorting to sprite + box->dispoffset = vis->dispoffset + 5; + + box->cut |= SC_LINKDRAW; + } + else + { + fixed_t xscale = FixedDiv(projection, tz); + fixed_t yscale = FixedDiv(projectiony, tz); + fixed_t top = (centeryfrac - FixedMul(box->texturemid, yscale)); + + box->x1 = (centerxfrac + FixedMul(box->gx, xscale)) / FRACUNIT; + box->x2 = box->x1; + + box->szt = top / FRACUNIT; + box->sz = (top + FixedMul(box->thingheight, yscale)) / FRACUNIT; + + box->sortscale = yscale; + box->dispoffset = 0; + } +} + // // R_ProjectSprite // Generates a vissprite for a thing @@ -1437,6 +1571,7 @@ static void R_ProjectSprite(mobj_t *thing) fixed_t tr_x, tr_y; fixed_t tx, tz; fixed_t xscale, yscale; //added : 02-02-98 : aaargll..if I were a math-guy!!! + fixed_t radius, height; // For drop shadows fixed_t sortscale, sortsplat = 0; fixed_t linkscale = 0; fixed_t sort_x = 0, sort_y = 0, sort_z; @@ -1495,6 +1630,7 @@ static void R_ProjectSprite(mobj_t *thing) #ifdef ROTSPRITE patch_t *rotsprite = NULL; INT32 rollangle = 0; + angle_t spriterotangle = 0; #endif // uncapped/interpolation @@ -1511,6 +1647,8 @@ static void R_ProjectSprite(mobj_t *thing) } this_scale = interp.scale; + radius = interp.radius; // For drop shadows + height = interp.height; // Ditto // transform the origin point tr_x = interp.x - viewx; @@ -1631,9 +1769,6 @@ static void R_ProjectSprite(mobj_t *thing) I_Assert(lump < max_spritelumps); - if (thing->skin && ((skin_t *)thing->skin)->flags & SF_HIRES) - this_scale = FixedMul(this_scale, ((skin_t *)thing->skin)->highresscale); - spr_width = spritecachedinfo[lump].width; spr_height = spritecachedinfo[lump].height; spr_offset = spritecachedinfo[lump].offset; @@ -1644,17 +1779,19 @@ static void R_ProjectSprite(mobj_t *thing) patch = W_CachePatchNum(sprframe->lumppat[rot], PU_SPRITE); #ifdef ROTSPRITE - if (thing->rollangle + spriterotangle = R_SpriteRotationAngle(&interp); + + if (spriterotangle != 0 && !(splat && !(thing->renderflags & RF_NOSPLATROLLANGLE))) { if (papersprite && ang >= ANGLE_180) { // Makes Software act much more sane like OpenGL - rollangle = R_GetRollAngle(InvAngle(thing->rollangle)); + rollangle = R_GetRollAngle(InvAngle(spriterotangle)); } else { - rollangle = R_GetRollAngle(thing->rollangle); + rollangle = R_GetRollAngle(spriterotangle); } rotsprite = Patch_GetRotatedSprite(sprframe, (thing->frame & FF_FRAMEMASK), rot, flip, false, sprinfo, rollangle); @@ -1681,6 +1818,14 @@ static void R_ProjectSprite(mobj_t *thing) // calculate edges of the shape spritexscale = interp.spritexscale; spriteyscale = interp.spriteyscale; + + if (thing->skin && ((skin_t *)thing->skin)->flags & SF_HIRES) + { + fixed_t highresscale = ((skin_t *)thing->skin)->highresscale; + spritexscale = FixedMul(spritexscale, highresscale); + spriteyscale = FixedMul(spriteyscale, highresscale); + } + if (spritexscale < 1 || spriteyscale < 1) return; @@ -1848,6 +1993,8 @@ static void R_ProjectSprite(mobj_t *thing) { R_InterpolateMobjState(thing, FRACUNIT, &tracer_interp); } + radius = tracer_interp.radius; // For drop shadows + height = tracer_interp.height; // Ditto tr_x = (tracer_interp.x + sort_x) - viewx; tr_y = (tracer_interp.y + sort_y) - viewy; @@ -1939,7 +2086,7 @@ static void R_ProjectSprite(mobj_t *thing) if (abs(groundz-viewz)/tz > 4) return; // Prevent stretchy shadows and possible crashes - floordiff = abs((isflipped ? caster->height : 0) + casterinterp.z - groundz); + floordiff = abs((isflipped ? casterinterp.height : 0) + casterinterp.z - groundz); trans += ((floordiff / (100*FRACUNIT)) + 3); shadowscale = FixedMul(FRACUNIT - floordiff/640, casterinterp.scale); } @@ -1954,8 +2101,8 @@ static void R_ProjectSprite(mobj_t *thing) if (shadowdraw) { - spritexscale = FixedMul(thing->radius * 2, FixedMul(shadowscale, spritexscale)); - spriteyscale = FixedMul(thing->radius * 2, FixedMul(shadowscale, spriteyscale)); + spritexscale = FixedMul(radius * 2, FixedMul(shadowscale, spritexscale)); + spriteyscale = FixedMul(radius * 2, FixedMul(shadowscale, spriteyscale)); spriteyscale = FixedMul(spriteyscale, FixedDiv(abs(groundz - viewz), tz)); spriteyscale = min(spriteyscale, spritexscale) / patch->height; spritexscale /= patch->width; @@ -1970,7 +2117,7 @@ static void R_ProjectSprite(mobj_t *thing) { R_SkewShadowSprite(thing, thing->standingslope, groundz, patch->height, shadowscale, &spriteyscale, &sheartan); - gzt = (isflipped ? (interp.z + thing->height) : interp.z) + patch->height * spriteyscale / 2; + gzt = (isflipped ? (interp.z + height) : interp.z) + patch->height * spriteyscale / 2; gz = gzt - patch->height * spriteyscale; cut |= SC_SHEAR; @@ -1985,7 +2132,7 @@ static void R_ProjectSprite(mobj_t *thing) // When vertical flipped, draw sprites from the top down, at least as far as offsets are concerned. // sprite height - sprite topoffset is the proper inverse of the vertical offset, of course. // remember gz and gzt should be seperated by sprite height, not thing height - thing height can be shorter than the sprite itself sometimes! - gz = interp.z + oldthing->height - FixedMul(spr_topoffset, FixedMul(spriteyscale, this_scale)); + gz = interp.z + interp.height - FixedMul(spr_topoffset, FixedMul(spriteyscale, this_scale)); gzt = gz + FixedMul(spr_height, FixedMul(spriteyscale, this_scale)); } else @@ -2064,7 +2211,7 @@ static void R_ProjectSprite(mobj_t *thing) vis->gy = interp.y; vis->gz = gz; vis->gzt = gzt; - vis->thingheight = thing->height; + vis->thingheight = height; vis->pz = interp.z; vis->pzt = vis->pz + vis->thingheight; vis->texturemid = FixedDiv(gzt - viewz, spriteyscale); @@ -2187,6 +2334,8 @@ static void R_ProjectSprite(mobj_t *thing) if (oldthing->shadowscale && cv_shadow.value) R_ProjectDropShadow(oldthing, vis, oldthing->shadowscale, basetx, basetz); + R_ProjectBoundingBox(oldthing, vis); + // Debug ++objectsdrawn; } @@ -2412,8 +2561,26 @@ void R_AddSprites(sector_t *sec, INT32 lightlevel) hoop_limit_dist = (fixed_t)(cv_drawdist_nights.value) << FRACBITS; for (thing = sec->thinglist; thing; thing = thing->snext) { - if (R_ThingVisibleWithinDist(thing, limit_dist, hoop_limit_dist)) - R_ProjectSprite(thing); + if (R_ThingWithinDist(thing, limit_dist, hoop_limit_dist)) + { + const INT32 oldobjectsdrawn = objectsdrawn; + + if (R_ThingVisible(thing)) + { + R_ProjectSprite(thing); + } + + // I'm so smart :^) + if (objectsdrawn == oldobjectsdrawn) + { + /* + Object is invisible OR is off screen but + render its bbox even if the latter because + radius could be bigger than sprite. + */ + R_ProjectBoundingBox(thing, NULL); + } + } } // no, no infinite draw distance for precipitation. this option at zero is supposed to turn it off @@ -2484,6 +2651,14 @@ static void R_SortVisSprites(vissprite_t* vsprsortedhead, UINT32 start, UINT32 e // bundle linkdraw for (ds = unsorted.prev; ds != &unsorted; ds = ds->prev) { + // Remove this sprite if it was determined to not be visible + if (ds->cut & SC_NOTVISIBLE) + { + ds->next->prev = ds->prev; + ds->prev->next = ds->next; + continue; + } + if (!(ds->cut & SC_LINKDRAW)) continue; @@ -2501,26 +2676,36 @@ static void R_SortVisSprites(vissprite_t* vsprsortedhead, UINT32 start, UINT32 e if (dsfirst->cut & SC_SHADOW) continue; + // don't connect to your bounding box! + if (dsfirst->cut & SC_BBOX) + continue; + // don't connect if it's not the tracer if (dsfirst->mobj != ds->mobj) continue; // don't connect if the tracer's top is cut off, but lower than the link's top - if ((dsfirst->cut & SC_TOP) - && dsfirst->szt > ds->szt) + if ((dsfirst->cut & SC_TOP) && dsfirst->szt > ds->szt) continue; // don't connect if the tracer's bottom is cut off, but higher than the link's bottom - if ((dsfirst->cut & SC_BOTTOM) - && dsfirst->sz < ds->sz) + if ((dsfirst->cut & SC_BOTTOM) && dsfirst->sz < ds->sz) continue; + // If the object isn't visible, then the bounding box isn't either + if (ds->cut & SC_BBOX && dsfirst->cut & SC_NOTVISIBLE) + ds->cut |= SC_NOTVISIBLE; + break; } // remove from chain ds->next->prev = ds->prev; ds->prev->next = ds->next; + + if (ds->cut & SC_NOTVISIBLE) + continue; + linkedvissprites++; if (dsfirst != &unsorted) @@ -2572,12 +2757,15 @@ static void R_SortVisSprites(vissprite_t* vsprsortedhead, UINT32 start, UINT32 e best = ds; } } - best->next->prev = best->prev; - best->prev->next = best->next; - best->next = vsprsortedhead; - best->prev = vsprsortedhead->prev; - vsprsortedhead->prev->next = best; - vsprsortedhead->prev = best; + if (best) + { + best->next->prev = best->prev; + best->prev->next = best->next; + best->next = vsprsortedhead; + best->prev = vsprsortedhead->prev; + vsprsortedhead->prev->next = best; + vsprsortedhead->prev = best; + } } } @@ -2941,7 +3129,9 @@ static void R_DrawSprite(vissprite_t *spr) mfloorclip = spr->clipbot; mceilingclip = spr->cliptop; - if (spr->cut & SC_SPLAT) + if (spr->cut & SC_BBOX) + R_DrawThingBoundingBox(spr); + else if (spr->cut & SC_SPLAT) R_DrawFloorSplat(spr); else R_DrawVisSprite(spr); @@ -3006,9 +3196,47 @@ static void R_HeightSecClip(vissprite_t *spr, INT32 x1, INT32 x2) } } +static boolean R_CheckSpriteVisible(vissprite_t *spr, INT32 x1, INT32 x2) +{ + INT16 sz = spr->sz; + INT16 szt = spr->szt; + + fixed_t texturemid, yscale, scalestep = spr->scalestep; + INT32 height; + + if (scalestep) + { + height = spr->patch->height; + yscale = spr->scale; + scalestep = FixedMul(scalestep, spr->spriteyscale); + + if (spr->thingscale != FRACUNIT) + texturemid = FixedDiv(spr->texturemid, max(spr->thingscale, 1)); + else + texturemid = spr->texturemid; + } + + for (INT32 x = x1; x <= x2; x++) + { + if (scalestep) + { + fixed_t top = centeryfrac - FixedMul(texturemid, yscale); + fixed_t bottom = top + (height * yscale); + szt = (INT16)(top >> FRACBITS); + sz = (INT16)(bottom >> FRACBITS); + yscale += scalestep; + } + + if (spr->cliptop[x] < spr->clipbot[x] && sz > spr->cliptop[x] && szt < spr->clipbot[x]) + return true; + } + + return false; +} + // R_ClipVisSprite // Clips vissprites without drawing, so that portals can work. -Red -void R_ClipVisSprite(vissprite_t *spr, INT32 x1, INT32 x2, drawseg_t* dsstart, portal_t* portal) +static void R_ClipVisSprite(vissprite_t *spr, INT32 x1, INT32 x2, portal_t* portal) { drawseg_t *ds; INT32 x; @@ -3028,21 +3256,23 @@ void R_ClipVisSprite(vissprite_t *spr, INT32 x1, INT32 x2, drawseg_t* dsstart, p // Pointer check was originally nonportable // and buggy, by going past LEFT end of array: - // for (ds = ds_p-1; ds >= drawsegs; ds--) old buggy code - for (ds = ds_p; ds-- > dsstart;) + // e6y: optimization + if (drawsegs_xrange_size) { - // determine if the drawseg obscures the sprite - if (ds->x1 > x2 || - ds->x2 < x1 || - (!ds->silhouette - && !ds->maskedtexturecol)) - { - // does not cover sprite - continue; - } + const drawseg_xrange_item_t *last = &drawsegs_xrange[drawsegs_xrange_count - 1]; + drawseg_xrange_item_t *curr = &drawsegs_xrange[-1]; - if (ds->portalpass != 66) + while (++curr <= last) { + // determine if the drawseg obscures the sprite + if (curr->x1 > x2 || curr->x2 < x1) + { + // does not cover sprite + continue; + } + + ds = curr->user; + if (ds->portalpass > 0 && ds->portalpass <= portalrender) continue; // is a portal @@ -3067,43 +3297,43 @@ void R_ClipVisSprite(vissprite_t *spr, INT32 x1, INT32 x2, drawseg_t* dsstart, p // seg is behind sprite continue; } - } - r1 = ds->x1 < x1 ? x1 : ds->x1; - r2 = ds->x2 > x2 ? x2 : ds->x2; + r1 = ds->x1 < x1 ? x1 : ds->x1; + r2 = ds->x2 > x2 ? x2 : ds->x2; - // clip this piece of the sprite - silhouette = ds->silhouette; + // clip this piece of the sprite + silhouette = ds->silhouette; - if (spr->gz >= ds->bsilheight) - silhouette &= ~SIL_BOTTOM; + if (spr->gz >= ds->bsilheight) + silhouette &= ~SIL_BOTTOM; - if (spr->gzt <= ds->tsilheight) - silhouette &= ~SIL_TOP; + if (spr->gzt <= ds->tsilheight) + silhouette &= ~SIL_TOP; - if (silhouette == SIL_BOTTOM) - { - // bottom sil - for (x = r1; x <= r2; x++) - if (spr->clipbot[x] == -2) - spr->clipbot[x] = ds->sprbottomclip[x]; - } - else if (silhouette == SIL_TOP) - { - // top sil - for (x = r1; x <= r2; x++) - if (spr->cliptop[x] == -2) - spr->cliptop[x] = ds->sprtopclip[x]; - } - else if (silhouette == (SIL_TOP|SIL_BOTTOM)) - { - // both - for (x = r1; x <= r2; x++) + if (silhouette == SIL_BOTTOM) + { + // bottom sil + for (x = r1; x <= r2; x++) + if (spr->clipbot[x] == -2) + spr->clipbot[x] = ds->sprbottomclip[x]; + } + else if (silhouette == SIL_TOP) { - if (spr->clipbot[x] == -2) - spr->clipbot[x] = ds->sprbottomclip[x]; - if (spr->cliptop[x] == -2) - spr->cliptop[x] = ds->sprtopclip[x]; + // top sil + for (x = r1; x <= r2; x++) + if (spr->cliptop[x] == -2) + spr->cliptop[x] = ds->sprtopclip[x]; + } + else if (silhouette == (SIL_TOP|SIL_BOTTOM)) + { + // both + for (x = r1; x <= r2; x++) + { + if (spr->clipbot[x] == -2) + spr->clipbot[x] = ds->sprbottomclip[x]; + if (spr->cliptop[x] == -2) + spr->cliptop[x] = ds->sprtopclip[x]; + } } } } @@ -3147,8 +3377,7 @@ void R_ClipVisSprite(vissprite_t *spr, INT32 x1, INT32 x2, drawseg_t* dsstart, p spr->clipbot[x] = (INT16)viewheight; if (spr->cliptop[x] == -2) - //Fab : 26-04-98: was -1, now clips against console bottom - spr->cliptop[x] = (INT16)con_clipviewtop; + spr->cliptop[x] = -1; } if (portal) @@ -3173,16 +3402,119 @@ void R_ClipVisSprite(vissprite_t *spr, INT32 x1, INT32 x2, drawseg_t* dsstart, p spr->cliptop[x] = -1; } } + + // Check if it'll be visible + // Not done for floorsprites. + if (cv_spriteclip.value && (spr->cut & SC_SPLAT) == 0) + { + if (!R_CheckSpriteVisible(spr, x1, x2)) + spr->cut |= SC_NOTVISIBLE; + } } void R_ClipSprites(drawseg_t* dsstart, portal_t* portal) { + const size_t maxdrawsegs = ds_p - drawsegs; + const INT32 cx = viewwidth / 2; + drawseg_t* ds; + INT32 i; + + // e6y + // Reducing of cache misses in the following R_DrawSprite() + // Makes sense for scenes with huge amount of drawsegs. + // ~12% of speed improvement on epic.wad map05 + for (i = 0; i < DS_RANGES_COUNT; i++) + { + drawsegs_xranges[i].count = 0; + } + + if (visspritecount - clippedvissprites <= 0) + { + return; + } + + if (drawsegs_xrange_size < maxdrawsegs) + { + drawsegs_xrange_size = 2 * maxdrawsegs; + + for (i = 0; i < DS_RANGES_COUNT; i++) + { + drawsegs_xranges[i].items = Z_Realloc( + drawsegs_xranges[i].items, + drawsegs_xrange_size * sizeof(drawsegs_xranges[i].items[0]), + PU_STATIC, NULL + ); + } + } + + for (ds = ds_p; ds-- > dsstart;) + { + if (ds->silhouette || ds->maskedtexturecol) + { + drawsegs_xranges[0].items[drawsegs_xranges[0].count].x1 = ds->x1; + drawsegs_xranges[0].items[drawsegs_xranges[0].count].x2 = ds->x2; + drawsegs_xranges[0].items[drawsegs_xranges[0].count].user = ds; + + // e6y: ~13% of speed improvement on sunder.wad map10 + if (ds->x1 < cx) + { + drawsegs_xranges[1].items[drawsegs_xranges[1].count] = + drawsegs_xranges[0].items[drawsegs_xranges[0].count]; + drawsegs_xranges[1].count++; + } + + if (ds->x2 >= cx) + { + drawsegs_xranges[2].items[drawsegs_xranges[2].count] = + drawsegs_xranges[0].items[drawsegs_xranges[0].count]; + drawsegs_xranges[2].count++; + } + + drawsegs_xranges[0].count++; + } + } + for (; clippedvissprites < visspritecount; clippedvissprites++) { vissprite_t *spr = R_GetVisSprite(clippedvissprites); + + if (cv_spriteclip.value + && (spr->szt > vid.height || spr->sz < 0) + && !((spr->cut & SC_SPLAT) || spr->scalestep)) + { + spr->cut |= SC_NOTVISIBLE; + continue; + } + + if (spr->cut & SC_BBOX) + { + numvisiblesprites++; + continue; + } + INT32 x1 = (spr->cut & SC_SPLAT) ? 0 : spr->x1; INT32 x2 = (spr->cut & SC_SPLAT) ? viewwidth : spr->x2; - R_ClipVisSprite(spr, x1, x2, dsstart, portal); + + if (x2 < cx) + { + drawsegs_xrange = drawsegs_xranges[1].items; + drawsegs_xrange_count = drawsegs_xranges[1].count; + } + else if (x1 >= cx) + { + drawsegs_xrange = drawsegs_xranges[2].items; + drawsegs_xrange_count = drawsegs_xranges[2].count; + } + else + { + drawsegs_xrange = drawsegs_xranges[0].items; + drawsegs_xrange_count = drawsegs_xranges[0].count; + } + + R_ClipVisSprite(spr, x1, x2, portal); + + if ((spr->cut & SC_NOTVISIBLE) == 0) + numvisiblesprites++; } } @@ -3190,22 +3522,22 @@ void R_ClipSprites(drawseg_t* dsstart, portal_t* portal) boolean R_ThingVisible (mobj_t *thing) { return (!( - thing->sprite == SPR_NULL || - ( thing->flags2 & (MF2_DONTDRAW) ) || - (r_viewmobj && (thing == r_viewmobj || (r_viewmobj->player && r_viewmobj->player->followmobj == thing))) + (thing->sprite == SPR_NULL) || // Don't draw null-sprites + (thing->flags2 & MF2_DONTDRAW) || // Don't draw MF2_LINKDRAW objects + (thing->drawonlyforplayer && thing->drawonlyforplayer != viewplayer) || // Don't draw other players' personal objects + (r_viewmobj && ( + (r_viewmobj == thing) || // Don't draw first-person players or awayviewmobj objects + (r_viewmobj->player && r_viewmobj->player->followmobj == thing) || // Don't draw first-person players' followmobj + (r_viewmobj == thing->dontdrawforviewmobj) // Don't draw objects that are hidden for the current view + )) )); } -boolean R_ThingVisibleWithinDist (mobj_t *thing, +boolean R_ThingWithinDist (mobj_t *thing, fixed_t limit_dist, fixed_t hoop_limit_dist) { - fixed_t approx_dist; - - if (! R_ThingVisible(thing)) - return false; - - approx_dist = P_AproxDistance(viewx-thing->x, viewy-thing->y); + const fixed_t approx_dist = P_AproxDistance(viewx-thing->x, viewy-thing->y); if (thing->sprite == SPR_HOOP) { diff --git a/src/r_things.h b/src/r_things.h index 22a37a0eaccbd622bcb92ec6c4fa2836a5aa9456..318234886bbbfa2b603f1883d50bbfea4c67d370 100644 --- a/src/r_things.h +++ b/src/r_things.h @@ -66,9 +66,12 @@ void R_AddSprites(sector_t *sec, INT32 lightlevel); void R_InitSprites(void); void R_ClearSprites(void); +UINT8 R_GetBoundingBoxColor(mobj_t *thing); +boolean R_ThingBoundingBoxVisible(mobj_t *thing); + boolean R_ThingVisible (mobj_t *thing); -boolean R_ThingVisibleWithinDist (mobj_t *thing, +boolean R_ThingWithinDist (mobj_t *thing, fixed_t draw_dist, fixed_t nights_draw_dist); @@ -120,20 +123,22 @@ typedef enum SC_NONE = 0, SC_TOP = 1, SC_BOTTOM = 1<<1, + SC_NOTVISIBLE = 1<<2, // other flags - SC_PRECIP = 1<<2, - SC_LINKDRAW = 1<<3, - SC_FULLBRIGHT = 1<<4, - SC_SEMIBRIGHT = 1<<5, - SC_FULLDARK = 1<<6, - SC_VFLIP = 1<<7, - SC_ISSCALED = 1<<8, - SC_ISROTATED = 1<<9, - SC_SHADOW = 1<<10, - SC_SHEAR = 1<<11, - SC_SPLAT = 1<<12, + SC_PRECIP = 1<<3, + SC_LINKDRAW = 1<<4, + SC_FULLBRIGHT = 1<<5, + SC_SEMIBRIGHT = 1<<6, + SC_FULLDARK = 1<<7, + SC_VFLIP = 1<<8, + SC_ISSCALED = 1<<9, + SC_ISROTATED = 1<<10, + SC_SHADOW = 1<<11, + SC_SHEAR = 1<<12, + SC_SPLAT = 1<<13, + SC_BBOX = 1<<14, // masks - SC_CUTMASK = SC_TOP|SC_BOTTOM, + SC_CUTMASK = SC_TOP|SC_BOTTOM|SC_NOTVISIBLE, SC_FLAGMASK = ~SC_CUTMASK } spritecut_e; @@ -215,12 +220,14 @@ typedef struct vissprite_s INT32 dispoffset; // copy of mobj->dispoffset, affects ordering but not drawing } vissprite_t; -extern UINT32 visspritecount; +extern UINT32 visspritecount, numvisiblesprites; void R_ClipSprites(drawseg_t* dsstart, portal_t* portal); -void R_ClipVisSprite(vissprite_t *spr, INT32 x1, INT32 x2, drawseg_t* dsstart, portal_t* portal); boolean R_SpriteIsFlashing(vissprite_t *vis); + +void R_DrawThingBoundingBox(vissprite_t *spr); + UINT8 *R_GetSpriteTranslation(vissprite_t *vis); // ---------- diff --git a/src/screen.c b/src/screen.c index f8af4c504a74d2d6b779bd6befdee2ab2277c544..417e793bde540c62a9edf2b6a0b8073250ee7f73 100644 --- a/src/screen.c +++ b/src/screen.c @@ -44,10 +44,6 @@ // SRB2Kart #include "r_fps.h" // R_GetFramerateCap -#if defined (USEASM) && !defined (NORUSEASM)//&& (!defined (_MSC_VER) || (_MSC_VER <= 1200)) -#define RUSEASM //MSC.NET can't patch itself -#endif - // -------------------------------------------- // assembly or c drawer routines for 8bpp/16bpp // -------------------------------------------- @@ -70,6 +66,8 @@ static CV_PossibleValue_t scr_depth_cons_t[] = {{8, "8 bits"}, {16, "16 bits"}, //added : 03-02-98: default screen mode, as loaded/saved in config consvar_t cv_scr_width = CVAR_INIT ("scr_width", "1280", CV_SAVE, CV_Unsigned, NULL); consvar_t cv_scr_height = CVAR_INIT ("scr_height", "800", CV_SAVE, CV_Unsigned, NULL); +consvar_t cv_scr_width_w = CVAR_INIT ("scr_width_w", "640", CV_SAVE, CV_Unsigned, NULL); +consvar_t cv_scr_height_w = CVAR_INIT ("scr_height_w", "400", CV_SAVE, CV_Unsigned, NULL); consvar_t cv_scr_depth = CVAR_INIT ("scr_depth", "16 bits", CV_SAVE, scr_depth_cons_t, NULL); consvar_t cv_renderview = CVAR_INIT ("renderview", "On", 0, CV_OnOff, NULL); @@ -100,7 +98,6 @@ UINT8 *scr_borderpatch; // flat used to fill the reduced view borders set at ST_ // Short and Tall sky drawer, for the current color mode void (*walldrawerfunc)(void); -boolean R_ASM = true; boolean R_486 = false; boolean R_586 = false; boolean R_MMX = false; @@ -167,26 +164,6 @@ void SCR_SetDrawFuncs(void) spanfuncs_npo2[SPANDRAWFUNC_WATER] = R_DrawWaterSpan_NPO2_8; spanfuncs_npo2[SPANDRAWFUNC_TILTEDWATER] = R_DrawTiltedWaterSpan_NPO2_8; -#ifdef RUSEASM - if (R_ASM) - { - if (R_MMX) - { - colfuncs[BASEDRAWFUNC] = R_DrawColumn_8_MMX; - //colfuncs[COLDRAWFUNC_SHADE] = R_DrawShadeColumn_8_ASM; - //colfuncs[COLDRAWFUNC_FUZZY] = R_DrawTranslucentColumn_8_ASM; - colfuncs[COLDRAWFUNC_TWOSMULTIPATCH] = R_Draw2sMultiPatchColumn_8_MMX; - spanfuncs[BASEDRAWFUNC] = R_DrawSpan_8_MMX; - } - else - { - colfuncs[BASEDRAWFUNC] = R_DrawColumn_8_ASM; - //colfuncs[COLDRAWFUNC_SHADE] = R_DrawShadeColumn_8_ASM; - //colfuncs[COLDRAWFUNC_FUZZY] = R_DrawTranslucentColumn_8_ASM; - colfuncs[COLDRAWFUNC_TWOSMULTIPATCH] = R_Draw2sMultiPatchColumn_8_ASM; - } - } -#endif } /* else if (vid.bpp > 1) { @@ -269,8 +246,6 @@ void SCR_Startup(void) CONS_Printf("CPU Info: 486: %i, 586: %i, MMX: %i, 3DNow: %i, MMXExt: %i, SSE2: %i\n", R_486, R_586, R_MMX, R_3DNow, R_MMXExt, R_SSE2); } - if (M_CheckParm("-noASM")) - R_ASM = false; if (M_CheckParm("-486")) R_486 = true; if (M_CheckParm("-586")) @@ -377,10 +352,16 @@ void SCR_CheckDefaultMode(void) } else { - CONS_Printf(M_GetText("Default resolution: %d x %d (%d bits)\n"), cv_scr_width.value, - cv_scr_height.value, cv_scr_depth.value); - // see note above - setmodeneeded = VID_GetModeForSize(cv_scr_width.value, cv_scr_height.value) + 1; + CONS_Printf(M_GetText("Default resolution: %d x %d\n"), cv_scr_width.value, cv_scr_height.value); + CONS_Printf(M_GetText("Windowed resolution: %d x %d\n"), cv_scr_width_w.value, cv_scr_height_w.value); + CONS_Printf(M_GetText("Default bit depth: %d bits\n"), cv_scr_depth.value); + if (cv_fullscreen.value) + setmodeneeded = VID_GetModeForSize(cv_scr_width.value, cv_scr_height.value) + 1; // see note above + else + setmodeneeded = VID_GetModeForSize(cv_scr_width_w.value, cv_scr_height_w.value) + 1; // see note above + + if (setmodeneeded <= 0) + CONS_Alert(CONS_WARNING, "Invalid resolution given, defaulting to base resolution\n"); } if (cv_renderer.value != (signed)rendermode) @@ -398,9 +379,8 @@ void SCR_CheckDefaultMode(void) // sets the modenum as the new default video mode to be saved in the config file 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_fullscreen.value ? &cv_scr_width : &cv_scr_width_w, vid.width); + CV_SetValue(cv_fullscreen.value ? &cv_scr_height : &cv_scr_height_w, vid.height); } // Change fullscreen on/off according to cv_fullscreen @@ -415,7 +395,16 @@ void SCR_ChangeFullscreen(void) if (graphics_started) { VID_PrepareModeList(); - setmodeneeded = VID_GetModeForSize(vid.width, vid.height) + 1; + if (cv_fullscreen.value) + setmodeneeded = VID_GetModeForSize(cv_scr_width.value, cv_scr_height.value) + 1; + else + setmodeneeded = VID_GetModeForSize(cv_scr_width_w.value, cv_scr_height_w.value) + 1; + + if (setmodeneeded <= 0) // hacky safeguard + { + CONS_Alert(CONS_WARNING, "Invalid resolution given, defaulting to base resolution.\n"); + setmodeneeded = VID_GetModeForSize(BASEVIDWIDTH, BASEVIDHEIGHT) + 1; + } } return; #endif @@ -462,11 +451,11 @@ double averageFPS = 0.0f; #define USE_FPS_SAMPLES #ifdef USE_FPS_SAMPLES -#define FPS_SAMPLE_RATE (0.05) // How often to update FPS samples, in seconds +#define MAX_FRAME_TIME 0.05 #define NUM_FPS_SAMPLES (16) // Number of samples to store -static double fps_samples[NUM_FPS_SAMPLES]; -static double updateElapsed = 0.0; +static double total_frame_time = 0.0; +static int frame_index; #endif static boolean fps_init = false; @@ -489,34 +478,12 @@ void SCR_CalculateFPS(void) fps_enter = fps_finish; #ifdef USE_FPS_SAMPLES - updateElapsed += frameElapsed; - - if (updateElapsed >= FPS_SAMPLE_RATE) - { - static int sampleIndex = 0; - int i; - - fps_samples[sampleIndex] = frameElapsed; - - sampleIndex++; - if (sampleIndex >= NUM_FPS_SAMPLES) - sampleIndex = 0; - - averageFPS = 0.0; - for (i = 0; i < NUM_FPS_SAMPLES; i++) - { - averageFPS += fps_samples[i]; - } - - if (averageFPS > 0.0) - { - averageFPS = 1.0 / (averageFPS / NUM_FPS_SAMPLES); - } - } - - while (updateElapsed >= FPS_SAMPLE_RATE) + total_frame_time += frameElapsed; + if (frame_index++ >= NUM_FPS_SAMPLES || total_frame_time >= MAX_FRAME_TIME) { - updateElapsed -= FPS_SAMPLE_RATE; + averageFPS = 1.0 / (total_frame_time / frame_index); + total_frame_time = 0.0; + frame_index = 0; } #else // Direct, unsampled counter. diff --git a/src/screen.h b/src/screen.h index 19103b0df59036c80ea85112f47a7673596ded67..65e82ff4df2bff3701a0f57d4667ee32a34784f5 100644 --- a/src/screen.h +++ b/src/screen.h @@ -199,7 +199,9 @@ extern CV_PossibleValue_t cv_renderer_t[]; extern INT32 scr_bpp; extern UINT8 *scr_borderpatch; // patch used to fill the view borders -extern consvar_t cv_scr_width, cv_scr_height, cv_scr_depth, cv_renderview, cv_renderer, cv_fullscreen; +extern consvar_t cv_scr_width, cv_scr_height, cv_scr_width_w, cv_scr_height_w, cv_scr_depth, cv_fullscreen; +extern consvar_t cv_renderview, cv_renderer; +extern consvar_t cv_renderhitbox, cv_renderhitboxinterpolation, cv_renderhitboxgldepth; // wait for page flipping to end or not extern consvar_t cv_vidwait; extern consvar_t cv_timescale; diff --git a/src/sdl/CMakeLists.txt b/src/sdl/CMakeLists.txt index be540b778b733976a9ceb08c636bcd30d36d29d2..4c4cdafb640e7806ee1efb79380ee10eaf26e119 100644 --- a/src/sdl/CMakeLists.txt +++ b/src/sdl/CMakeLists.txt @@ -1,17 +1,17 @@ # Declare SDL2 interface sources -target_sources(SRB2SDL2 PRIVATE mixer_sound.c) - -target_sourcefile(c) - -target_sources(SRB2SDL2 PRIVATE ogl_sdl.c) - -target_sources(SRB2SDL2 PRIVATE i_threads.c) - -if(${SRB2_USEASM}) - set_source_files_properties(${SRB2_ASM_SOURCES} PROPERTIES LANGUAGE C) - set_source_files_properties(${SRB2_ASM_SOURCES} PROPERTIES COMPILE_FLAGS "-x assembler-with-cpp") -endif() +target_sources(SRB2SDL2 PRIVATE + mixer_sound.c + ogl_sdl.c + i_threads.c + i_net.c + i_system.c + i_main.c + i_video.c + dosstr.c + endtxt.c + hwsym_sdl.c +) if("${CMAKE_SYSTEM_NAME}" MATCHES Windows) target_sources(SRB2SDL2 PRIVATE @@ -68,18 +68,6 @@ if("${CMAKE_SYSTEM_NAME}" MATCHES Linux) target_link_libraries(SRB2SDL2 PRIVATE m rt) endif() -if(${SRB2_USEASM}) - if(${SRB2_CONFIG_YASM}) - set(ASM_ASSEMBLER_TEMP ${CMAKE_ASM_YASM_COMPILER}) - set(ASM_ASSEMBLER_OBJFORMAT ${CMAKE_ASM_YASM_OBJECT_FORMAT}) - set_source_files_properties(${SRB2_NASM_SOURCES} LANGUAGE ASM_YASM) - else() - set(ASM_ASSEMBLER_TEMP ${CMAKE_ASM_NASM_COMPILER}) - set(ASM_ASSEMBLER_OBJFORMAT ${CMAKE_ASM_NASM_OBJECT_FORMAT}) - set_source_files_properties(${SRB2_NASM_SOURCES} LANGUAGE ASM_NASM) - endif() -endif() - if("${CMAKE_SYSTEM_NAME}" MATCHES Windows) target_link_libraries(SRB2SDL2 PRIVATE ws2_32 diff --git a/src/sdl/MakeCYG.cfg b/src/sdl/MakeCYG.cfg index 5907579c1bc9d16abb0e338cb709566fd75b6c61..b78316b00142dfcb96188f6fb45baa047a628ed0 100644 --- a/src/sdl/MakeCYG.cfg +++ b/src/sdl/MakeCYG.cfg @@ -7,7 +7,6 @@ NOHW=1 NOHS=1 - NOASM=1 OPTS+=-DLINUX diff --git a/src/sdl/Srb2SDL-vc10.vcxproj b/src/sdl/Srb2SDL-vc10.vcxproj index c20265ed17cde4a7d17844029489a713ba5ad617..0b95cd0b2e0732b3f562d85d5e7454c7ec351b64 100644 --- a/src/sdl/Srb2SDL-vc10.vcxproj +++ b/src/sdl/Srb2SDL-vc10.vcxproj @@ -259,7 +259,7 @@ <ClInclude Include="..\hardware\hw_md2load.h" /> <ClInclude Include="..\hardware\hw_md3load.h" /> <ClInclude Include="..\hardware\hw_model.h" /> - <ClInclude Include="..\hardware\u_list.h" /> + <ClInclude Include="..\u_list.h" /> <ClInclude Include="..\hu_stuff.h" /> <ClInclude Include="..\info.h" /> <ClInclude Include="..\i_addrinfo.h" /> @@ -424,7 +424,7 @@ <ClCompile Include="..\hardware\hw_md3load.c" /> <ClCompile Include="..\hardware\hw_model.c" /> <ClCompile Include="..\hardware\r_opengl\r_opengl.c" /> - <ClCompile Include="..\hardware\u_list.c" /> + <ClCompile Include="..\u_list.c" /> <ClCompile Include="..\hu_stuff.c" /> <ClCompile Include="..\info.c" /> <ClCompile Include="..\i_addrinfo.c"> @@ -556,4 +556,4 @@ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <ImportGroup Label="ExtensionTargets"> </ImportGroup> -</Project> \ No newline at end of file +</Project> diff --git a/src/sdl/i_main.c b/src/sdl/i_main.c index 1dee379c0d8d95db186f1e9e3bb301554ed0549f..3eeacd83569188bd3bfdb5c8f2b9e720b5dce9f4 100644 --- a/src/sdl/i_main.c +++ b/src/sdl/i_main.c @@ -70,39 +70,6 @@ char logfilename[1024]; typedef BOOL (WINAPI *p_IsDebuggerPresent)(VOID); #endif -#if defined (_WIN32) -static inline VOID MakeCodeWritable(VOID) -{ -#ifdef USEASM // Disable write-protection of code segment - DWORD OldRights; - const DWORD NewRights = PAGE_EXECUTE_READWRITE; - PBYTE pBaseOfImage = (PBYTE)GetModuleHandle(NULL); - PIMAGE_DOS_HEADER dosH =(PIMAGE_DOS_HEADER)pBaseOfImage; - PIMAGE_NT_HEADERS ntH = (PIMAGE_NT_HEADERS)(pBaseOfImage + dosH->e_lfanew); - PIMAGE_OPTIONAL_HEADER oH = (PIMAGE_OPTIONAL_HEADER) - ((PBYTE)ntH + sizeof (IMAGE_NT_SIGNATURE) + sizeof (IMAGE_FILE_HEADER)); - LPVOID pA = pBaseOfImage+oH->BaseOfCode; - SIZE_T pS = oH->SizeOfCode; -#if 1 // try to find the text section - PIMAGE_SECTION_HEADER ntS = IMAGE_FIRST_SECTION (ntH); - WORD s; - for (s = 0; s < ntH->FileHeader.NumberOfSections; s++) - { - if (memcmp (ntS[s].Name, ".text\0\0", 8) == 0) - { - pA = pBaseOfImage+ntS[s].VirtualAddress; - pS = ntS[s].Misc.VirtualSize; - break; - } - } -#endif - - if (!VirtualProtect(pA,pS,NewRights,&OldRights)) - I_Error("Could not make code writable\n"); -#endif -} -#endif - #ifdef LOGMESSAGES static void InitLogging(void) { @@ -243,7 +210,6 @@ int main(int argc, char **argv) #ifndef __MINGW32__ prevExceptionFilter = SetUnhandledExceptionFilter(RecordExceptionInfo); #endif - MakeCodeWritable(); #endif // startup SRB2 diff --git a/src/sdl/i_system.c b/src/sdl/i_system.c index 66eeffa30b7717597c1732ab9355a8cb76317362..2a26f3f501f9c5708ec56d1f5624d087056f40ae 100644 --- a/src/sdl/i_system.c +++ b/src/sdl/i_system.c @@ -23,12 +23,6 @@ /// \file /// \brief SRB2 system stuff for SDL -#ifdef CMAKECONFIG -#include "config.h" -#else -#include "../config.h.in" -#endif - #include <signal.h> #ifdef _WIN32 @@ -41,6 +35,12 @@ typedef DWORD (WINAPI *p_timeGetTime) (void); typedef UINT (WINAPI *p_timeEndPeriod) (UINT); typedef HANDLE (WINAPI *p_OpenFileMappingA) (DWORD, BOOL, LPCSTR); typedef LPVOID (WINAPI *p_MapViewOfFile) (HANDLE, DWORD, DWORD, DWORD, SIZE_T); + +// This is for RtlGenRandom. +#define SystemFunction036 NTAPI SystemFunction036 +#include <ntsecapi.h> +#undef SystemFunction036 + #endif #include <stdio.h> #include <stdlib.h> @@ -90,7 +90,7 @@ typedef LPVOID (WINAPI *p_MapViewOfFile) (HANDLE, DWORD, DWORD, DWORD, SIZE_T); #include <kvm.h> #endif #include <nlist.h> -#include <sys/vmmeter.h> +#include <sys/sysctl.h> #endif #endif @@ -259,10 +259,10 @@ UINT8 keyboard_started = false; #ifdef UNIXBACKTRACE #define STDERR_WRITE(string) if (fd != -1) I_OutputMsg("%s", string) -#define CRASHLOG_WRITE(string) if (fd != -1) write(fd, string, strlen(string)) +#define CRASHLOG_WRITE(string) if (fd != -1) junk = write(fd, string, strlen(string)) #define CRASHLOG_STDERR_WRITE(string) \ if (fd != -1)\ - write(fd, string, strlen(string));\ + junk = write(fd, string, strlen(string));\ I_OutputMsg("%s", string) static void write_backtrace(INT32 signal) @@ -271,6 +271,7 @@ static void write_backtrace(INT32 signal) size_t size; time_t rawtime; struct tm timeinfo; + ssize_t junk; enum { BT_SIZE = 1024, STR_SIZE = 32 }; void *array[BT_SIZE]; @@ -314,7 +315,7 @@ static void write_backtrace(INT32 signal) backtrace_symbols_fd(array, size, STDERR_FILENO); CRASHLOG_WRITE("\n"); // Write another newline to the log so it looks nice :) - + (void)junk; close(fd); } #undef STDERR_WRITE @@ -325,56 +326,90 @@ static void write_backtrace(INT32 signal) static void I_ReportSignal(int num, int coredumped) { //static char msg[] = "oh no! back to reality!\r\n"; - const char * sigmsg; - char msg[128]; + const char *sigmsg, *signame; + char ttl[128]; + char sigttl[512] = "Process killed by signal: "; + const char *reportmsg = "\n\nTo help us figure out the cause, you can visit our official Discord server\nwhere you will find more instructions on how to submit a crash report.\n\nSorry for the inconvenience!"; switch (num) { // case SIGINT: -// sigmsg = "SIGINT - interrupted"; +// sigttl = "SIGINT" +// sigmsg = "SRB2 was interrupted prematurely by the user."; // break; case SIGILL: - sigmsg = "SIGILL - illegal instruction - invalid function image"; + sigmsg = "SRB2 has attempted to execute an illegal instruction and needs to close."; + signame = "SIGILL"; // illegal instruction - invalid function image break; case SIGFPE: - sigmsg = "SIGFPE - mathematical exception"; + sigmsg = "SRB2 has encountered a mathematical exception and needs to close."; + signame = "SIGFPE"; // mathematical exception break; case SIGSEGV: - sigmsg = "SIGSEGV - segment violation"; + sigmsg = "SRB2 has attempted to access a memory location that it shouldn't and needs to close."; + signame = "SIGSEGV"; // segment violation break; // case SIGTERM: -// sigmsg = "SIGTERM - Software termination signal from kill"; +// sigmsg = "SRB2 was terminated by a kill signal."; +// sigttl = "SIGTERM"; // Software termination signal from kill // break; // case SIGBREAK: -// sigmsg = "SIGBREAK - Ctrl-Break sequence"; +// sigmsg = "SRB2 was terminated by a Ctrl-Break sequence."; +// sigttl = "SIGBREAK" // Ctrl-Break sequence // break; case SIGABRT: - sigmsg = "SIGABRT - abnormal termination triggered by abort call"; + sigmsg = "SRB2 was terminated by an abort signal."; + signame = "SIGABRT"; // abnormal termination triggered by abort call break; default: - sprintf(msg,"signal number %d", num); + sigmsg = "SRB2 was terminated by an unknown signal."; + + sprintf(ttl, "number %d", num); if (coredumped) - sigmsg = 0; + signame = 0; else - sigmsg = msg; + signame = ttl; } if (coredumped) { - if (sigmsg) - sprintf(msg, "%s (core dumped)", sigmsg); + if (signame) + sprintf(ttl, "%s (core dumped)", signame); else - strcat(msg, " (core dumped)"); + strcat(ttl, " (core dumped)"); - sigmsg = msg; + signame = ttl; } - I_OutputMsg("\nProcess killed by signal: %s\n\n", sigmsg); + strcat(sigttl, signame); + I_OutputMsg("%s\n", sigttl); - if (!M_CheckParm("-dedicated")) - SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, - "Process killed by signal", - sigmsg, NULL); + if (M_CheckParm("-dedicated")) + return; + + const SDL_MessageBoxButtonData buttons[] = { + { SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT, 0, "OK" }, + { 0, 1, "Discord" }, + }; + + const SDL_MessageBoxData messageboxdata = { + SDL_MESSAGEBOX_ERROR, /* .flags */ + NULL, /* .window */ + sigttl, /* .title */ + va("%s %s", sigmsg, reportmsg), /* .message */ + SDL_arraysize(buttons), /* .numbuttons */ + buttons, /* .buttons */ + NULL /* .colorScheme */ + }; + + int buttonid; + + SDL_ShowMessageBox(&messageboxdata, &buttonid); + +#if SDL_VERSION_ATLEAST(2,0,14) + if (buttonid == 1) + SDL_OpenURL("https://www.srb2.org/discord"); +#endif } #ifndef NEWSIGNALHANDLER @@ -2230,7 +2265,7 @@ void I_Sleep(UINT32 ms) } #ifdef NEWSIGNALHANDLER -static void newsignalhandler_Warn(const char *pr) +ATTRNORETURN static FUNCNORETURN void newsignalhandler_Warn(const char *pr) { char text[128]; @@ -2322,7 +2357,10 @@ INT32 I_StartupSystem(void) #endif I_StartupConsole(); #ifdef NEWSIGNALHANDLER - I_Fork(); + // This is useful when debugging. It lets GDB attach to + // the correct process easily. + if (!M_CheckParm("-nofork")) + I_Fork(); #endif I_RegisterSignals(); I_OutputMsg("Compiled for SDL version: %d.%d.%d\n", @@ -2608,9 +2646,10 @@ void I_ShutdownSystem(void) { INT32 c; -#ifndef NEWSIGNALHANDLER - I_ShutdownConsole(); +#ifdef NEWSIGNALHANDLER + if (M_CheckParm("-nofork")) #endif + I_ShutdownConsole(); for (c = MAX_QUIT_FUNCS-1; c >= 0; c--) if (quit_funcs[c]) @@ -2742,6 +2781,38 @@ INT32 I_PutEnv(char *variable) #endif } +size_t I_GetRandomBytes(char *destination, size_t count) +{ +#if defined (__unix__) || defined (UNIXCOMMON) || defined(__APPLE__) + FILE *rndsource; + size_t actual_bytes; + + if (!(rndsource = fopen("/dev/urandom", "r"))) + if (!(rndsource = fopen("/dev/random", "r"))) + actual_bytes = 0; + + if (rndsource) + { + actual_bytes = fread(destination, 1, count, rndsource); + fclose(rndsource); + } + + if (actual_bytes == 0) + I_OutputMsg("I_GetRandomBytes(): couldn't get any random bytes"); + + return actual_bytes; +#elif defined (_WIN32) + if (RtlGenRandom(destination, count)) + return count; + + I_OutputMsg("I_GetRandomBytes(): couldn't get any random bytes"); + return 0; +#else + #warning SDL I_GetRandomBytes is not implemented on this platform. + return 0; +#endif +} + INT32 I_ClipboardCopy(const char *data, size_t size) { char storage[256]; @@ -2965,40 +3036,17 @@ static long get_entry(const char* name, const char* buf) size_t I_GetFreeMem(size_t *total) { #ifdef FREEBSD - struct vmmeter sum; - kvm_t *kd; - struct nlist namelist[] = - { -#define X_SUM 0 - {"_cnt"}, - {NULL} - }; - if ((kd = kvm_open(NULL, NULL, NULL, O_RDONLY, "kvm_open")) == NULL) - { - if (total) - *total = 0L; - return 0; - } - if (kvm_nlist(kd, namelist) != 0) - { - kvm_close (kd); - if (total) - *total = 0L; - return 0; - } - if (kvm_read(kd, namelist[X_SUM].n_value, &sum, - sizeof (sum)) != sizeof (sum)) - { - kvm_close(kd); - if (total) - *total = 0L; - return 0; - } - kvm_close(kd); + u_int v_free_count, v_page_size, v_page_count; + size_t size = sizeof(v_free_count); + sysctlbyname("vm.stats.vm.v_free_count", &v_free_count, &size, NULL, 0); + size = sizeof(v_page_size); + sysctlbyname("vm.stats.vm.v_page_size", &v_page_size, &size, NULL, 0); + size = sizeof(v_page_count); + sysctlbyname("vm.stats.vm.v_page_count", &v_page_count, &size, NULL, 0); if (total) - *total = sum.v_page_count * sum.v_page_size; - return sum.v_free_count * sum.v_page_size; + *total = v_page_count * v_page_size; + return v_free_count * v_page_size; #elif defined (SOLARIS) /* Just guess */ if (total) diff --git a/src/sdl/i_video.c b/src/sdl/i_video.c index d2fbb90063f13f5ed663ee7a2665b95f8aac296e..590d7d142a7a536678bfb96d3891c78264a19fba 100644 --- a/src/sdl/i_video.c +++ b/src/sdl/i_video.c @@ -1593,7 +1593,6 @@ boolean VID_CheckRenderer(void) else if (vid.glstate == VID_GL_LIBRARY_ERROR) rendererchanged = false; } - else #endif if (!contextcreated) @@ -1859,7 +1858,7 @@ void I_StartupGraphics(void) borderlesswindow = M_CheckParm("-borderless"); //SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY>>1,SDL_DEFAULT_REPEAT_INTERVAL<<2); - VID_Command_ModeList_f(); + //VID_Command_ModeList_f(); #ifdef HWRENDER if (rendermode == render_opengl) @@ -1907,7 +1906,7 @@ void I_StartupGraphics(void) realwidth = (Uint16)vid.width; realheight = (Uint16)vid.height; - VID_Command_Info_f(); + //VID_Command_Info_f(); SDLdoUngrabMouse(); SDL_RaiseWindow(window); diff --git a/src/sdl/mixer_sound.c b/src/sdl/mixer_sound.c index f13aaef5d660f7e626f3e9c4c522b007fa6abd2d..0a39c7f286f8dc3e4b563709de240b0370e1b2b9 100644 --- a/src/sdl/mixer_sound.c +++ b/src/sdl/mixer_sound.c @@ -108,6 +108,7 @@ static UINT32 fading_timer; static UINT32 fading_duration; static INT32 fading_id; static void (*fading_callback)(void); +static boolean fading_do_callback; static boolean fading_nocleanup; #ifdef HAVE_GME @@ -213,7 +214,10 @@ static void var_cleanup(void) // HACK: See music_loop, where we want the fade timing to proceed after a non-looping // song has stopped playing if (!fading_nocleanup) + { fading_callback = NULL; + fading_do_callback = false; + } else fading_nocleanup = false; // use it once, set it back immediately @@ -330,6 +334,13 @@ void I_ShutdownSound(void) void I_UpdateSound(void) { + if (fading_do_callback) + { + if (fading_callback) + (*fading_callback)(); + fading_callback = NULL; + fading_do_callback = false; + } } /// ------------------------ @@ -654,9 +665,8 @@ static UINT32 get_adjusted_position(UINT32 position) static void do_fading_callback(void) { - if (fading_callback) - (*fading_callback)(); - fading_callback = NULL; + // TODO: Should I use a mutex here or something? + fading_do_callback = true; } /// ------------------------ diff --git a/src/st_stuff.c b/src/st_stuff.c index dcab2bb9c585e48b3be8d74323463ebeb6d44827..b9f0c6bb93e1ab4d1b9e35a958670571883086e4 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -170,6 +170,15 @@ hudinfo_t hudinfo[NUMHUDITEMS] = static huddrawlist_h luahuddrawlist_game[2]; static huddrawlist_h luahuddrawlist_titlecard; +// NiGHTS link colors; 3 sets with increasingly fancy colors (1 to 299, 300 to 599, 600 and above) +skincolornum_t linkColor[3][NUMLINKCOLORS] = { +{SKINCOLOR_SHAMROCK, SKINCOLOR_AQUA, SKINCOLOR_SKY, SKINCOLOR_BLUE, SKINCOLOR_PURPLE, SKINCOLOR_MAGENTA, + SKINCOLOR_ROSY, SKINCOLOR_RED, SKINCOLOR_ORANGE, SKINCOLOR_GOLD, SKINCOLOR_YELLOW, SKINCOLOR_PERIDOT}, +{SKINCOLOR_EMERALD, SKINCOLOR_OCEAN, SKINCOLOR_AQUAMARINE, SKINCOLOR_SAPPHIRE, SKINCOLOR_GALAXY, SKINCOLOR_SIBERITE, + SKINCOLOR_TAFFY, SKINCOLOR_RUBY, SKINCOLOR_GARNET, SKINCOLOR_TOPAZ, SKINCOLOR_LEMON, SKINCOLOR_LIME}, +{SKINCOLOR_ISLAND, SKINCOLOR_TURQUOISE, SKINCOLOR_DREAM, SKINCOLOR_DAYBREAK, SKINCOLOR_VAPOR, SKINCOLOR_FUCHSIA, + SKINCOLOR_VIOLET, SKINCOLOR_EVENTIDE, SKINCOLOR_KETCHUP, SKINCOLOR_FOUNDATION, SKINCOLOR_HEADLIGHT, SKINCOLOR_CHARTREUSE}}; + // // STATUS BAR CODE // @@ -806,7 +815,7 @@ static inline void ST_drawRings(void) static void ST_drawLivesArea(void) { INT32 v_colmap = V_YELLOWMAP, livescount; - boolean notgreyedout; + boolean notgreyedout = false; if (!stplyr->skincolor) return; // Just joined a server, skin isn't loaded yet! @@ -859,39 +868,36 @@ static void ST_drawLivesArea(void) if (metalrecording) { if (((2*leveltime)/TICRATE) & 1) + { V_DrawRightAlignedString(hudinfo[HUD_LIVES].x+58, hudinfo[HUD_LIVES].y+8, hudinfo[HUD_LIVES].f|V_PERPLAYER|V_REDMAP|V_HUDTRANS, "REC"); + } } // Spectator else if (stplyr->spectator) - v_colmap = V_GRAYMAP; - // Tag - else if (gametyperules & GTR_TAG) { - if (stplyr->pflags & PF_TAGIT) - { - V_DrawRightAlignedString(hudinfo[HUD_LIVES].x+58, hudinfo[HUD_LIVES].y+8, V_HUDTRANS|hudinfo[HUD_LIVES].f|V_PERPLAYER, "IT!"); - v_colmap = V_ORANGEMAP; - } + v_colmap = V_GRAYMAP; } - // Team name - else if (G_GametypeHasTeams()) + else { - if (stplyr->ctfteam == 1) + boolean candrawlives = false; + + // Set the player's name color. + if (G_TagGametype() && (stplyr->pflags & PF_TAGIT)) { - V_DrawRightAlignedString(hudinfo[HUD_LIVES].x+58, hudinfo[HUD_LIVES].y+8, V_HUDTRANS|hudinfo[HUD_LIVES].f|V_PERPLAYER, "RED"); - v_colmap = V_REDMAP; + v_colmap = V_ORANGEMAP; } - else if (stplyr->ctfteam == 2) + else if (G_GametypeHasTeams()) { - V_DrawRightAlignedString(hudinfo[HUD_LIVES].x+58, hudinfo[HUD_LIVES].y+8, V_HUDTRANS|hudinfo[HUD_LIVES].f|V_PERPLAYER, "BLUE"); - v_colmap = V_BLUEMAP; + if (stplyr->ctfteam == 1) + { + v_colmap = V_REDMAP; + } + else if (stplyr->ctfteam == 2) + { + v_colmap = V_BLUEMAP; + } } - } - // Lives number - else - { - boolean candrawlives = true; // Co-op and Competition, normal life counter if (G_GametypeUsesLives()) @@ -927,12 +933,15 @@ static void ST_drawLivesArea(void) livescount = (((netgame || multiplayer) && G_GametypeUsesCoopLives() && cv_cooplives.value == 0) ? INFLIVES : stplyr->lives); notgreyedout = true; } + + candrawlives = true; } // Infinity symbol (Race) else if (G_PlatformGametype() && !(gametyperules & GTR_LIVES)) { livescount = INFLIVES; notgreyedout = true; + candrawlives = true; } // Otherwise nothing, sorry. // Special Stages keep not showing lives, @@ -941,8 +950,6 @@ static void ST_drawLivesArea(void) // cannot show up because Special Stages // still have the GTR_LIVES gametype rule // by default. - else - candrawlives = false; // Draw the lives counter here. if (candrawlives) @@ -950,8 +957,10 @@ static void ST_drawLivesArea(void) // x V_DrawScaledPatch(hudinfo[HUD_LIVES].x+22, hudinfo[HUD_LIVES].y+10, hudinfo[HUD_LIVES].f|V_PERPLAYER|V_HUDTRANS, stlivex); if (livescount == INFLIVES) + { V_DrawCharacter(hudinfo[HUD_LIVES].x+50, hudinfo[HUD_LIVES].y+8, '\x16' | 0x80 | hudinfo[HUD_LIVES].f|V_PERPLAYER|V_HUDTRANS, false); + } else { if (stplyr->playerstate == PST_DEAD && !(stplyr->spectator) && (livescount || stplyr->deadtimer < (TICRATE<<1)) && !(stplyr->pflags & PF_FINISHED)) @@ -962,6 +971,25 @@ static void ST_drawLivesArea(void) hudinfo[HUD_LIVES].f|V_PERPLAYER|(notgreyedout ? V_HUDTRANS : V_HUDTRANSHALF), va("%d",livescount)); } } + else + { + // Draw team name instead of lives, if possible. + if (G_TagGametype() && (stplyr->pflags & PF_TAGIT)) + { + V_DrawRightAlignedString(hudinfo[HUD_LIVES].x+58, hudinfo[HUD_LIVES].y+8, V_HUDTRANS|hudinfo[HUD_LIVES].f|V_PERPLAYER, "IT!"); + } + else if (G_GametypeHasTeams()) + { + if (stplyr->ctfteam == 1) + { + V_DrawRightAlignedString(hudinfo[HUD_LIVES].x+58, hudinfo[HUD_LIVES].y+8, V_HUDTRANS|hudinfo[HUD_LIVES].f|V_PERPLAYER, "RED"); + } + else if (stplyr->ctfteam == 2) + { + V_DrawRightAlignedString(hudinfo[HUD_LIVES].x+58, hudinfo[HUD_LIVES].y+8, V_HUDTRANS|hudinfo[HUD_LIVES].f|V_PERPLAYER, "BLUE"); + } + } + } #undef ST_drawLivesX } @@ -1751,43 +1779,11 @@ static void ST_drawNightsRecords(void) } } -// 2.0-1: [21:42] <+Rob> Beige - Lavender - Steel Blue - Peach - Orange - Purple - Silver - Yellow - Pink - Red - Blue - Green - Cyan - Gold -/*#define NUMLINKCOLORS 14 -static skincolornum_t linkColor[NUMLINKCOLORS] = -{SKINCOLOR_BEIGE, SKINCOLOR_LAVENDER, SKINCOLOR_AZURE, SKINCOLOR_PEACH, SKINCOLOR_ORANGE, - SKINCOLOR_MAGENTA, SKINCOLOR_SILVER, SKINCOLOR_SUPERGOLD4, SKINCOLOR_PINK, SKINCOLOR_RED, - SKINCOLOR_BLUE, SKINCOLOR_GREEN, SKINCOLOR_CYAN, SKINCOLOR_GOLD};*/ - -// 2.2 indev list: (unix time 1470866042) <Rob> Emerald, Aqua, Cyan, Blue, Pastel, Purple, Magenta, Rosy, Red, Orange, Gold, Yellow, Peridot -/*#define NUMLINKCOLORS 13 -static skincolornum_t linkColor[NUMLINKCOLORS] = -{SKINCOLOR_EMERALD, SKINCOLOR_AQUA, SKINCOLOR_CYAN, SKINCOLOR_BLUE, SKINCOLOR_PASTEL, - SKINCOLOR_PURPLE, SKINCOLOR_MAGENTA, SKINCOLOR_ROSY, SKINCOLOR_RED, SKINCOLOR_ORANGE, - SKINCOLOR_GOLD, SKINCOLOR_YELLOW, SKINCOLOR_PERIDOT};*/ - -// 2.2 indev list again: [19:59:52] <baldobo> Ruby > Red > Flame > Sunset > Orange > Gold > Yellow > Lime > Green > Aqua > cyan > Sky > Blue > Pastel > Purple > Bubblegum > Magenta > Rosy > repeat -// [20:00:25] <baldobo> Also Icy for the link freeze text color -// [20:04:03] <baldobo> I would start it on lime -/*#define NUMLINKCOLORS 18 -static skincolornum_t linkColor[NUMLINKCOLORS] = -{SKINCOLOR_LIME, SKINCOLOR_EMERALD, SKINCOLOR_AQUA, SKINCOLOR_CYAN, SKINCOLOR_SKY, - SKINCOLOR_SAPPHIRE, SKINCOLOR_PASTEL, SKINCOLOR_PURPLE, SKINCOLOR_BUBBLEGUM, SKINCOLOR_MAGENTA, - SKINCOLOR_ROSY, SKINCOLOR_RUBY, SKINCOLOR_RED, SKINCOLOR_FLAME, SKINCOLOR_SUNSET, - SKINCOLOR_ORANGE, SKINCOLOR_GOLD, SKINCOLOR_YELLOW};*/ - -// 2.2+ list for real this time: https://wiki.srb2.org/wiki/User:Rob/Sandbox (check history around 31/10/17, spoopy) -#define NUMLINKCOLORS 12 -static skincolornum_t linkColor[2][NUMLINKCOLORS] = { -{SKINCOLOR_EMERALD, SKINCOLOR_AQUA, SKINCOLOR_SKY, SKINCOLOR_BLUE, SKINCOLOR_PURPLE, SKINCOLOR_MAGENTA, - SKINCOLOR_ROSY, SKINCOLOR_RED, SKINCOLOR_ORANGE, SKINCOLOR_GOLD, SKINCOLOR_YELLOW, SKINCOLOR_PERIDOT}, -{SKINCOLOR_SEAFOAM, SKINCOLOR_CYAN, SKINCOLOR_WAVE, SKINCOLOR_SAPPHIRE, SKINCOLOR_VAPOR, SKINCOLOR_BUBBLEGUM, - SKINCOLOR_VIOLET, SKINCOLOR_RUBY, SKINCOLOR_FLAME, SKINCOLOR_SUNSET, SKINCOLOR_SANDY, SKINCOLOR_LIME}}; - static void ST_drawNiGHTSLink(void) { static INT32 prevsel[2] = {0, 0}, prevtime[2] = {0, 0}; const UINT8 q = ((splitscreen && stplyr == &players[secondarydisplayplayer]) ? 1 : 0); - INT32 sel = ((stplyr->linkcount-1) / 5) % NUMLINKCOLORS, aflag = V_PERPLAYER, mag = ((stplyr->linkcount-1 >= 300) ? 1 : 0); + INT32 sel = ((stplyr->linkcount-1) / 5) % NUMLINKCOLORS, aflag = V_PERPLAYER, mag = ((stplyr->linkcount-1 >= 300) ? (stplyr->linkcount-1 >= 600) ? 2 : 1 : 0); skincolornum_t colornum; fixed_t x, y, scale; @@ -2516,6 +2512,8 @@ num: static INT32 ST_drawEmeraldHuntIcon(mobj_t *hunt, patch_t **patches, INT32 offset) { INT32 interval, i; + if (stplyr->mo == NULL) + return 0; // player just joined after spectating, can happen on custom gamemodes. UINT32 dist = ((UINT32)P_AproxDistance(P_AproxDistance(stplyr->mo->x - hunt->x, stplyr->mo->y - hunt->y), stplyr->mo->z - hunt->z))>>FRACBITS; if (dist < 128) diff --git a/src/st_stuff.h b/src/st_stuff.h index 68ac900f7724f4a64f27a0dc2a0a499707387d58..603be3c309c761b31fa269f2b0fbad795a489676 100644 --- a/src/st_stuff.h +++ b/src/st_stuff.h @@ -124,4 +124,7 @@ extern hudinfo_t hudinfo[NUMHUDITEMS]; extern UINT16 objectsdrawn; +#define NUMLINKCOLORS 12 +extern skincolornum_t linkColor[3][NUMLINKCOLORS]; + #endif diff --git a/src/strcasestr.c b/src/strcasestr.c index 2796f11d52658f2376b547a3d41d6b2d2974f15e..37899a8425b3d2082957c41cbdae07056798fe74 100644 --- a/src/strcasestr.c +++ b/src/strcasestr.c @@ -61,7 +61,7 @@ swapp (char ***ppap, char ***ppbp, char **cpap, char **cpbp) } char * -strcasestr (const char *s, const char *q) +nongnu_strcasestr (const char *s, const char *q) { size_t qn; diff --git a/src/string.c b/src/string.c index dd3080a979ca3ccffa811f27ee408bef7540bb26..2f16fa4c68a35fa287156f546fc2973e9d4ad426 100644 --- a/src/string.c +++ b/src/string.c @@ -15,7 +15,7 @@ #include <string.h> #include "doomdef.h" -#if !defined (__APPLE__) +#ifndef SRB2_HAVE_STRLCPY // Like the OpenBSD version, but it doesn't check for src not being a valid // C string. diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..28c4ce492f2d8b4e7590e3ac10f9ce6a95d98a0f --- /dev/null +++ b/src/tests/CMakeLists.txt @@ -0,0 +1,3 @@ +target_sources(srb2tests PRIVATE + boolcompat.cpp +) diff --git a/src/tests/boolcompat.cpp b/src/tests/boolcompat.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fee40cd36f2bce34217a875024d6b41fe71adbd1 --- /dev/null +++ b/src/tests/boolcompat.cpp @@ -0,0 +1,8 @@ +#include <catch2/catch_test_macros.hpp> + +#include "../doomtype.h" + +TEST_CASE("C++ bool is convertible to doomtype.h boolean") { + REQUIRE(static_cast<boolean>(true) == 1); + REQUIRE(static_cast<boolean>(false) == 0); +} diff --git a/src/tmap.nas b/src/tmap.nas deleted file mode 100644 index 85091cbd5d8dd9b1ab33cdd4938325eefeb1922b..0000000000000000000000000000000000000000 --- a/src/tmap.nas +++ /dev/null @@ -1,957 +0,0 @@ -;; SONIC ROBO BLAST 2 -;;----------------------------------------------------------------------------- -;; Copyright (C) 1998-2000 by DooM Legacy Team. -;; Copyright (C) 1999-2023 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: -;; tmap.nas -;; DESCRIPTION: -;; Assembler optimised rendering code for software mode. -;; Draw wall columns. - - -[BITS 32] - -%define FRACBITS 16 -%define TRANSPARENTPIXEL 255 - -%ifdef LINUX -%macro cextern 1 -[extern %1] -%endmacro - -%macro cglobal 1 -[global %1] -%endmacro - -%else -%macro cextern 1 -%define %1 _%1 -[extern %1] -%endmacro - -%macro cglobal 1 -%define %1 _%1 -[global %1] -%endmacro - -%endif - - -; The viddef_s structure. We only need the width field. -struc viddef_s - resb 12 -.width: resb 4 - resb 44 -endstruc - -;; externs -;; columns -cextern dc_x -cextern dc_yl -cextern dc_yh -cextern ylookup -cextern columnofs -cextern dc_source -cextern dc_texturemid -cextern dc_texheight -cextern dc_iscale -cextern dc_hires -cextern centery -cextern centeryfrac -cextern dc_colormap -cextern dc_transmap -cextern colormaps -cextern vid -cextern topleft - -; DELME -cextern R_DrawColumn_8 - -; polygon edge rasterizer -cextern prastertab - -[SECTION .data] - -;;.align 4 -loopcount dd 0 -pixelcount dd 0 -tystep dd 0 - -[SECTION .text] - -;;---------------------------------------------------------------------- -;; -;; R_DrawColumn : 8bpp column drawer -;; -;; New optimised version 10-01-1998 by D.Fabrice and P.Boris -;; Revised by G. Dick July 2010 to support the intervening twelve years' -;; worth of changes to the renderer. Since I only vaguely know what I'm -;; doing, this is probably rather suboptimal. Help appreciated! -;; -;;---------------------------------------------------------------------- -;; fracstep, vid.width in memory -;; eax = accumulator -;; ebx = colormap -;; ecx = count -;; edx = heightmask -;; esi = source -;; edi = dest -;; ebp = frac -;;---------------------------------------------------------------------- - -cglobal R_DrawColumn_8_ASM -; align 16 -R_DrawColumn_8_ASM: - push ebp ;; preserve caller's stack frame pointer - push esi ;; preserve register variables - push edi - push ebx -;; -;; dest = ylookup[dc_yl] + columnofs[dc_x]; -;; - mov ebp,[dc_yl] - mov edi,[ylookup+ebp*4] - mov ebx,[dc_x] - add edi,[columnofs+ebx*4] ;; edi = dest -;; -;; pixelcount = yh - yl + 1 -;; - mov ecx,[dc_yh] - add ecx,1 - sub ecx,ebp ;; pixel count - jle near .done ;; nothing to scale -;; -;; fracstep = dc_iscale; // But we just use [dc_iscale] -;; frac = (dc_texturemid + FixedMul((dc_yl << FRACBITS) - centeryfrac, fracstep)); -;; - mov eax,ebp ;; dc_yl - shl eax,FRACBITS - sub eax,[centeryfrac] - imul dword [dc_iscale] - shrd eax,edx,FRACBITS - add eax,[dc_texturemid] - mov ebp,eax ;; ebp = frac - - mov ebx,[dc_colormap] - - mov esi,[dc_source] -;; -;; if (dc_hires) frac = 0; -;; - test byte [dc_hires],0x01 - jz .texheightcheck - xor ebp,ebp - -;; -;; Check for power of two -;; -.texheightcheck: - mov edx,[dc_texheight] - sub edx,1 ;; edx = heightmask - test edx,[dc_texheight] - jnz .notpowertwo - - test ecx,0x01 ;; Test for odd no. pixels - jnz .odd - -;; -;; Texture height is a power of two, so we get modular arithmetic by -;; masking -;; -.powertwo: - mov eax,ebp ;; eax = frac - sar eax,FRACBITS ;; Integer part - and eax,edx ;; eax &= heightmask - movzx eax,byte [esi + eax] ;; eax = texel - add ebp,[dc_iscale] ;; frac += fracstep - movzx eax,byte [ebx+eax] ;; Map through colormap - mov [edi],al ;; Write pixel - ;; dest += vid.width - add edi,[vid + viddef_s.width] - -.odd: - mov eax,ebp ;; eax = frac - sar eax,FRACBITS ;; Integer part - and eax,edx ;; eax &= heightmask - movzx eax,byte [esi + eax] ;; eax = texel - add ebp,[dc_iscale] ;; frac += fracstep - movzx eax,byte [ebx+eax] ;; Map through colormap - mov [edi],al ;; Write pixel - ;; dest += vid.width - add edi,[vid + viddef_s.width] - - - sub ecx,2 ;; count -= 2 - jg .powertwo - - jmp .done - -.notpowertwo: - add edx,1 - shl edx,FRACBITS - test ebp,ebp - jns .notpowtwoloop - -.makefracpos: - add ebp,edx ;; frac is negative; make it positive - js .makefracpos - -.notpowtwoloop: - cmp ebp,edx ;; Reduce mod height - jl .writenonpowtwo - sub ebp,edx - jmp .notpowtwoloop - -.writenonpowtwo: - mov eax,ebp ;; eax = frac - sar eax,FRACBITS ;; Integer part. - mov bl,[esi + eax] ;; ebx = colormap + texel - add ebp,[dc_iscale] ;; frac += fracstep - movzx eax,byte [ebx] ;; Map through colormap - mov [edi],al ;; Write pixel - ;; dest += vid.width - add edi,[vid + viddef_s.width] - - sub ecx,1 - jnz .notpowtwoloop - -;; - -.done: - pop ebx ;; restore register variables - pop edi - pop esi - pop ebp ;; restore caller's stack frame pointer - ret - - -;;---------------------------------------------------------------------- -;; -;; R_Draw2sMultiPatchColumn : Like R_DrawColumn, but omits transparent -;; pixels. -;; -;; New optimised version 10-01-1998 by D.Fabrice and P.Boris -;; Revised by G. Dick July 2010 to support the intervening twelve years' -;; worth of changes to the renderer. Since I only vaguely know what I'm -;; doing, this is probably rather suboptimal. Help appreciated! -;; -;;---------------------------------------------------------------------- -;; fracstep, vid.width in memory -;; eax = accumulator -;; ebx = colormap -;; ecx = count -;; edx = heightmask -;; esi = source -;; edi = dest -;; ebp = frac -;;---------------------------------------------------------------------- - -cglobal R_Draw2sMultiPatchColumn_8_ASM -; align 16 -R_Draw2sMultiPatchColumn_8_ASM: - push ebp ;; preserve caller's stack frame pointer - push esi ;; preserve register variables - push edi - push ebx -;; -;; dest = ylookup[dc_yl] + columnofs[dc_x]; -;; - mov ebp,[dc_yl] - mov edi,[ylookup+ebp*4] - mov ebx,[dc_x] - add edi,[columnofs+ebx*4] ;; edi = dest -;; -;; pixelcount = yh - yl + 1 -;; - mov ecx,[dc_yh] - add ecx,1 - sub ecx,ebp ;; pixel count - jle near .done ;; nothing to scale -;; -;; fracstep = dc_iscale; // But we just use [dc_iscale] -;; frac = (dc_texturemid + FixedMul((dc_yl << FRACBITS) - centeryfrac, fracstep)); -;; - mov eax,ebp ;; dc_yl - shl eax,FRACBITS - sub eax,[centeryfrac] - imul dword [dc_iscale] - shrd eax,edx,FRACBITS - add eax,[dc_texturemid] - mov ebp,eax ;; ebp = frac - - mov ebx,[dc_colormap] - - mov esi,[dc_source] -;; -;; if (dc_hires) frac = 0; -;; - test byte [dc_hires],0x01 - jz .texheightcheck - xor ebp,ebp - -;; -;; Check for power of two -;; -.texheightcheck: - mov edx,[dc_texheight] - sub edx,1 ;; edx = heightmask - test edx,[dc_texheight] - jnz .notpowertwo - - test ecx,0x01 ;; Test for odd no. pixels - jnz .odd - -;; -;; Texture height is a power of two, so we get modular arithmetic by -;; masking -;; -.powertwo: - mov eax,ebp ;; eax = frac - sar eax,FRACBITS ;; Integer part - and eax,edx ;; eax &= heightmask - movzx eax,byte [esi + eax] ;; eax = texel - add ebp,[dc_iscale] ;; frac += fracstep - cmp al,TRANSPARENTPIXEL ;; Is pixel transparent? - je .nextpowtwoeven ;; If so, advance. - movzx eax,byte [ebx+eax] ;; Map through colormap - mov [edi],al ;; Write pixel -.nextpowtwoeven: - ;; dest += vid.width - add edi,[vid + viddef_s.width] - -.odd: - mov eax,ebp ;; eax = frac - sar eax,FRACBITS ;; Integer part - and eax,edx ;; eax &= heightmask - movzx eax,byte [esi + eax] ;; eax = texel - add ebp,[dc_iscale] ;; frac += fracstep - cmp al,TRANSPARENTPIXEL ;; Is pixel transparent? - je .nextpowtwoodd ;; If so, advance. - movzx eax,byte [ebx+eax] ;; Map through colormap - mov [edi],al ;; Write pixel -.nextpowtwoodd: - ;; dest += vid.width - add edi,[vid + viddef_s.width] - - - sub ecx,2 ;; count -= 2 - jg .powertwo - - jmp .done - -.notpowertwo: - add edx,1 - shl edx,FRACBITS - test ebp,ebp - jns .notpowtwoloop - -.makefracpos: - add ebp,edx ;; frac is negative; make it positive - js .makefracpos - -.notpowtwoloop: - cmp ebp,edx ;; Reduce mod height - jl .writenonpowtwo - sub ebp,edx - jmp .notpowtwoloop - -.writenonpowtwo: - mov eax,ebp ;; eax = frac - sar eax,FRACBITS ;; Integer part. - mov bl,[esi + eax] ;; ebx = colormap + texel - add ebp,[dc_iscale] ;; frac += fracstep - cmp bl,TRANSPARENTPIXEL ;; Is pixel transparent? - je .nextnonpowtwo ;; If so, advance. - movzx eax,byte [ebx] ;; Map through colormap - mov [edi],al ;; Write pixel -.nextnonpowtwo: - ;; dest += vid.width - add edi,[vid + viddef_s.width] - - sub ecx,1 - jnz .notpowtwoloop - -;; - -.done: - pop ebx ;; restore register variables - pop edi - pop esi - pop ebp ;; restore caller's stack frame pointer - ret - -;;---------------------------------------------------------------------- -;; R_DrawTranslucentColumnA_8 -;; -;; Vertical column texture drawer, with transparency. Replaces Doom2's -;; 'fuzz' effect, which was not so beautiful. -;; Transparency is always impressive in some way, don't know why... -;;---------------------------------------------------------------------- - -cglobal R_DrawTranslucentColumn_8_ASM -R_DrawTranslucentColumn_8_ASM: - push ebp ;; preserve caller's stack frame pointer - push esi ;; preserve register variables - push edi - push ebx -;; -;; dest = ylookup[dc_yl] + columnofs[dc_x]; -;; - mov ebp,[dc_yl] - mov ebx,ebp - mov edi,[ylookup+ebx*4] - mov ebx,[dc_x] - add edi,[columnofs+ebx*4] ;; edi = dest -;; -;; pixelcount = yh - yl + 1 -;; - mov eax,[dc_yh] - inc eax - sub eax,ebp ;; pixel count - mov [pixelcount],eax ;; save for final pixel - jle near vtdone ;; nothing to scale -;; -;; frac = dc_texturemid - (centery-dc_yl)*fracstep; -;; - mov ecx,[dc_iscale] ;; fracstep - mov eax,[centery] - sub eax,ebp - imul eax,ecx - mov edx,[dc_texturemid] - sub edx,eax - mov ebx,edx - - shr ebx,16 ;; frac int. - and ebx,0x7f - shl edx,16 ;; y frac up - - mov ebp,ecx - shl ebp,16 ;; fracstep f. up - shr ecx,16 ;; fracstep i. ->cl - and cl,0x7f - push cx - mov ecx,edx - pop cx - mov edx,[dc_colormap] - mov esi,[dc_source] -;; -;; lets rock :) ! -;; - mov eax,[pixelcount] - shr eax,0x2 - test byte [pixelcount],0x3 - mov ch,al ;; quad count - mov eax,[dc_transmap] - je vt4quadloop -;; -;; do un-even pixel -;; - test byte [pixelcount],0x1 - je trf2 - - mov ah,[esi+ebx] ;; fetch texel : colormap number - add ecx,ebp - adc bl,cl - mov al,[edi] ;; fetch dest : index into colormap - and bl,0x7f - mov dl,[eax] - mov dl,[edx] - mov [edi],dl -pf: add edi,0x12345678 -;; -;; do two non-quad-aligned pixels -;; -trf2: test byte [pixelcount],0x2 - je trf3 - - mov ah,[esi+ebx] ;; fetch texel : colormap number - add ecx,ebp - adc bl,cl - mov al,[edi] ;; fetch dest : index into colormap - and bl,0x7f - mov dl,[eax] - mov dl,[edx] - mov [edi],dl -pg: add edi,0x12345678 - - mov ah,[esi+ebx] ;; fetch texel : colormap number - add ecx,ebp - adc bl,cl - mov al,[edi] ;; fetch dest : index into colormap - and bl,0x7f - mov dl,[eax] - mov dl,[edx] - mov [edi],dl -ph: add edi,0x12345678 -;; -;; test if there was at least 4 pixels -;; -trf3: test ch,0xff ;; test quad count - je near vtdone - -;; -;; ebp : ystep frac. upper 24 bits -;; edx : y frac. upper 24 bits -;; ebx : y i. lower 7 bits, masked for index -;; ecx : ch = counter, cl = y step i. -;; eax : colormap aligned 256 -;; esi : source texture column -;; edi : dest screen -;; -vt4quadloop: - mov ah,[esi+ebx] ;; fetch texel : colormap number - mov [tystep],ebp -pi: add edi,0x12345678 - mov al,[edi] ;; fetch dest : index into colormap -pj: sub edi,0x12345678 - mov ebp,edi -pk: sub edi,0x12345678 - jmp short inloop -align 4 -vtquadloop: - add ecx,[tystep] - adc bl,cl -q1: add ebp,0x23456789 - and bl,0x7f - mov dl,[eax] - mov ah,[esi+ebx] ;; fetch texel : colormap number - mov dl,[edx] - mov [edi],dl - mov al,[ebp] ;; fetch dest : index into colormap -inloop: - add ecx,[tystep] - adc bl,cl -q2: add edi,0x23456789 - and bl,0x7f - mov dl,[eax] - mov ah,[esi+ebx] ;; fetch texel : colormap number - mov dl,[edx] - mov [ebp+0x0],dl - mov al,[edi] ;; fetch dest : index into colormap - - add ecx,[tystep] - adc bl,cl -q3: add ebp,0x23456789 - and bl,0x7f - mov dl,[eax] - mov ah,[esi+ebx] ;; fetch texel : colormap number - mov dl,[edx] - mov [edi],dl - mov al,[ebp] ;; fetch dest : index into colormap - - add ecx,[tystep] - adc bl,cl -q4: add edi,0x23456789 - and bl,0x7f - mov dl,[eax] - mov ah,[esi+ebx] ;; fetch texel : colormap number - mov dl,[edx] - mov [ebp],dl - mov al,[edi] ;; fetch dest : index into colormap - - dec ch - jne vtquadloop -vtdone: - pop ebx - pop edi - pop esi - pop ebp - ret - -;;---------------------------------------------------------------------- -;; R_DrawShadeColumn -;; -;; for smoke..etc.. test. -;;---------------------------------------------------------------------- -cglobal R_DrawShadeColumn_8_ASM -R_DrawShadeColumn_8_ASM: - push ebp ;; preserve caller's stack frame pointer - push esi ;; preserve register variables - push edi - push ebx - -;; -;; dest = ylookup[dc_yl] + columnofs[dc_x]; -;; - mov ebp,[dc_yl] - mov ebx,ebp - mov edi,[ylookup+ebx*4] - mov ebx,[dc_x] - add edi,[columnofs+ebx*4] ;; edi = dest -;; -;; pixelcount = yh - yl + 1 -;; - mov eax,[dc_yh] - inc eax - sub eax,ebp ;; pixel count - mov [pixelcount],eax ;; save for final pixel - jle near shdone ;; nothing to scale -;; -;; frac = dc_texturemid - (centery-dc_yl)*fracstep; -;; - mov ecx,[dc_iscale] ;; fracstep - mov eax,[centery] - sub eax,ebp - imul eax,ecx - mov edx,[dc_texturemid] - sub edx,eax - mov ebx,edx - shr ebx,16 ;; frac int. - and ebx,byte +0x7f - shl edx,16 ;; y frac up - - mov ebp,ecx - shl ebp,16 ;; fracstep f. up - shr ecx,16 ;; fracstep i. ->cl - and cl,0x7f - - mov esi,[dc_source] -;; -;; lets rock :) ! -;; - mov eax,[pixelcount] - mov dh,al - shr eax,2 - mov ch,al ;; quad count - mov eax,[colormaps] - test dh,3 - je sh4quadloop -;; -;; do un-even pixel -;; - test dh,0x1 - je shf2 - - mov ah,[esi+ebx] ;; fetch texel : colormap number - add edx,ebp - adc bl,cl - mov al,[edi] ;; fetch dest : index into colormap - and bl,0x7f - mov dl,[eax] - mov [edi],dl -pl: add edi,0x12345678 -;; -;; do two non-quad-aligned pixels -;; -shf2: - test dh,0x2 - je shf3 - - mov ah,[esi+ebx] ;; fetch texel : colormap number - add edx,ebp - adc bl,cl - mov al,[edi] ;; fetch dest : index into colormap - and bl,0x7f - mov dl,[eax] - mov [edi],dl -pm: add edi,0x12345678 - - mov ah,[esi+ebx] ;; fetch texel : colormap number - add edx,ebp - adc bl,cl - mov al,[edi] ;; fetch dest : index into colormap - and bl,0x7f - mov dl,[eax] - mov [edi],dl -pn: add edi,0x12345678 -;; -;; test if there was at least 4 pixels -;; -shf3: - test ch,0xff ;; test quad count - je near shdone - -;; -;; ebp : ystep frac. upper 24 bits -;; edx : y frac. upper 24 bits -;; ebx : y i. lower 7 bits, masked for index -;; ecx : ch = counter, cl = y step i. -;; eax : colormap aligned 256 -;; esi : source texture column -;; edi : dest screen -;; -sh4quadloop: - mov dh,0x7f ;; prep mask - mov ah,[esi+ebx] ;; fetch texel : colormap number - mov [tystep],ebp -po: add edi,0x12345678 - mov al,[edi] ;; fetch dest : index into colormap -pp: sub edi,0x12345678 - mov ebp,edi -pq: sub edi,0x12345678 - jmp short shinloop - -align 4 -shquadloop: - add edx,[tystep] - adc bl,cl - and bl,dh -q5: add ebp,0x12345678 - mov dl,[eax] - mov ah,[esi+ebx] ;; fetch texel : colormap number - mov [edi],dl - mov al,[ebp] ;; fetch dest : index into colormap -shinloop: - add edx,[tystep] - adc bl,cl - and bl,dh -q6: add edi,0x12345678 - mov dl,[eax] - mov ah,[esi+ebx] ;; fetch texel : colormap number - mov [ebp],dl - mov al,[edi] ;; fetch dest : index into colormap - - add edx,[tystep] - adc bl,cl - and bl,dh -q7: add ebp,0x12345678 - mov dl,[eax] - mov ah,[esi+ebx] ;; fetch texel : colormap number - mov [edi],dl - mov al,[ebp] ;; fetch dest : index into colormap - - add edx,[tystep] - adc bl,cl - and bl,dh -q8: add edi,0x12345678 - mov dl,[eax] - mov ah,[esi+ebx] ;; fetch texel : colormap number - mov [ebp],dl - mov al,[edi] ;; fetch dest : index into colormap - - dec ch - jne shquadloop - -shdone: - pop ebx ;; restore register variables - pop edi - pop esi - pop ebp ;; restore caller's stack frame pointer - ret - - -;; ======================================================================== -;; Rasterization of the segments of a LINEAR polygne textur of manire. -;; It is thus a question of interpolating coordinate them at the edges of texture in -;; the time that the X-coordinates minx/maxx for each line. -;; the argument ' dir' indicates which edges of texture are Interpol?: -;; 0: segments associs at edge TOP? and BOTTOM? (constant TY) -;; 1: segments associs at the LEFT and RIGHT edge (constant TX) -;; ======================================================================== -;; -;; void rasterize_segment_tex( LONG x1, LONG y1, LONG x2, LONG y2, LONG tv1, LONG tv2, LONG tc, LONG dir ); -;; ARG1 ARG2 ARG3 ARG4 ARG5 ARG6 ARG7 ARG8 -;; -;; Pour dir = 0, (tv1,tv2) = (tX1,tX2), tc = tY, en effet TY est constant. -;; -;; Pour dir = 1, (tv1,tv2) = (tY1,tY2), tc = tX, en effet TX est constant. -;; -;; -;; Uses: extern struct rastery *_rastertab; -;; - -MINX EQU 0 -MAXX EQU 4 -TX1 EQU 8 -TY1 EQU 12 -TX2 EQU 16 -TY2 EQU 20 -RASTERY_SIZEOF EQU 24 - -cglobal rasterize_segment_tex_asm -rasterize_segment_tex_asm: - push ebp - mov ebp,esp - - sub esp,byte +0x8 ;; allocate the local variables - - push ebx - push esi - push edi - o16 mov ax,es - push eax - -;; #define DX [ebp-4] -;; #define TD [ebp-8] - - mov eax,[ebp+0xc] ;; y1 - mov ebx,[ebp+0x14] ;; y2 - cmp ebx,eax - je near .L_finished ;; special (y1==y2) segment horizontal, exit! - - jg near .L_rasterize_right - -;;rasterize_left: ;; one rasterize a segment LEFT of the polygne - - mov ecx,eax - sub ecx,ebx - inc ecx ;; y1-y2+1 - - mov eax,RASTERY_SIZEOF - mul ebx ;; * y2 - mov esi,[prastertab] - add esi,eax ;; point into rastertab[y2] - - mov eax,[ebp+0x8] ;; ARG1 - sub eax,[ebp+0x10] ;; ARG3 - shl eax,0x10 ;; ((x1-x2)<<PRE) ... - cdq - idiv ecx ;; dx = ... / (y1-y2+1) - mov [ebp-0x4],eax ;; DX - - mov eax,[ebp+0x18] ;; ARG5 - sub eax,[ebp+0x1c] ;; ARG6 - shl eax,0x10 - cdq - idiv ecx ;; tdx =((tx1-tx2)<<PRE) / (y1-y2+1) - mov [ebp-0x8],eax ;; idem tdy =((ty1-ty2)<<PRE) / (y1-y2+1) - - mov eax,[ebp+0x10] ;; ARG3 - shl eax,0x10 ;; x = x2<<PRE - - mov ebx,[ebp+0x1c] ;; ARG6 - shl ebx,0x10 ;; tx = tx2<<PRE d0 - ;; ty = ty2<<PRE d1 - mov edx,[ebp+0x20] ;; ARG7 - shl edx,0x10 ;; ty = ty<<PRE d0 - ;; tx = tx<<PRE d1 - push ebp - mov edi,[ebp-0x4] ;; DX - cmp dword [ebp+0x24],byte +0x0 ;; ARG8 direction ? - - mov ebp,[ebp-0x8] ;; TD - je .L_rleft_h_loop -;; -;; TY varies, TX is constant -;; -.L_rleft_v_loop: - mov [esi+MINX],eax ;; rastertab[y].minx = x - add ebx,ebp - mov [esi+TX1],edx ;; .tx1 = tx - add eax,edi - mov [esi+TY1],ebx ;; .ty1 = ty - - ;;addl DX, %eax // x += dx - ;;addl TD, %ebx // ty += tdy - - add esi,RASTERY_SIZEOF ;; next raster line into rastertab[] - dec ecx - jne .L_rleft_v_loop - pop ebp - jmp .L_finished -;; -;; TX varies, TY is constant -;; -.L_rleft_h_loop: - mov [esi+MINX],eax ;; rastertab[y].minx = x - add eax,edi - mov [esi+TX1],ebx ;; .tx1 = tx - add ebx,ebp - mov [esi+TY1],edx ;; .ty1 = ty - - ;;addl DX, %eax // x += dx - ;;addl TD, %ebx // tx += tdx - - add esi,RASTERY_SIZEOF ;; next raster line into rastertab[] - dec ecx - jne .L_rleft_h_loop - pop ebp - jmp .L_finished -;; -;; one rasterize a segment LINE of the polygne -;; -.L_rasterize_right: - mov ecx,ebx - sub ecx,eax - inc ecx ;; y2-y1+1 - - mov ebx,RASTERY_SIZEOF - mul ebx ;; * y1 - mov esi,[prastertab] - add esi,eax ;; point into rastertab[y1] - - mov eax,[ebp+0x10] ;; ARG3 - sub eax,[ebp+0x8] ;; ARG1 - shl eax,0x10 ;; ((x2-x1)<<PRE) ... - cdq - idiv ecx ;; dx = ... / (y2-y1+1) - mov [ebp-0x4],eax ;; DX - - mov eax,[ebp+0x1c] ;; ARG6 - sub eax,[ebp+0x18] ;; ARG5 - shl eax,0x10 - cdq - idiv ecx ;; tdx =((tx2-tx1)<<PRE) / (y2-y1+1) - mov [ebp-0x8],eax ;; idem tdy =((ty2-ty1)<<PRE) / (y2-y1+1) - - mov eax,[ebp+0x8] ;; ARG1 - shl eax,0x10 ;; x = x1<<PRE - - mov ebx,[ebp+0x18] ;; ARG5 - shl ebx,0x10 ;; tx = tx1<<PRE d0 - ;; ty = ty1<<PRE d1 - mov edx,[ebp+0x20] ;; ARG7 - shl edx,0x10 ;; ty = ty<<PRE d0 - ;; tx = tx<<PRE d1 - push ebp - mov edi,[ebp-0x4] ;; DX - - cmp dword [ebp+0x24], 0 ;; direction ? - - mov ebp,[ebp-0x8] ;; TD - je .L_rright_h_loop -;; -;; TY varies, TX is constant -;; -.L_rright_v_loop: - - mov [esi+MAXX],eax ;; rastertab[y].maxx = x - add ebx,ebp - mov [esi+TX2],edx ;; .tx2 = tx - add eax,edi - mov [esi+TY2],ebx ;; .ty2 = ty - - ;;addl DX, %eax // x += dx - ;;addl TD, %ebx // ty += tdy - - add esi,RASTERY_SIZEOF - dec ecx - jne .L_rright_v_loop - - pop ebp - - jmp short .L_finished -;; -;; TX varies, TY is constant -;; -.L_rright_h_loop: - mov [esi+MAXX],eax ;; rastertab[y].maxx = x - add eax,edi - mov [esi+TX2],ebx ;; .tx2 = tx - add ebx,ebp - mov [esi+TY2],edx ;; .ty2 = ty - - ;;addl DX, %eax // x += dx - ;;addl TD, %ebx // tx += tdx - - add esi,RASTERY_SIZEOF - dec ecx - jne .L_rright_h_loop - - pop ebp - -.L_finished: - pop eax - o16 mov es,ax - pop edi - pop esi - pop ebx - - mov esp,ebp - pop ebp - ret diff --git a/src/tmap.s b/src/tmap.s deleted file mode 100644 index d98d82e25cedbea383b71beb122e7f250e12d765..0000000000000000000000000000000000000000 --- a/src/tmap.s +++ /dev/null @@ -1,1587 +0,0 @@ -// SONIC ROBO BLAST 2 -//----------------------------------------------------------------------------- -// Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2023 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 tmap.s -/// \brief optimised drawing routines for span/column rendering - -// structures, must match the C structures! -#include "asm_defs.inc" - -// Rappel: seuls EAX, ECX, EDX peuvent �tre �cras�s librement. -// il faut sauver esi,edi, cd...gs - -/* Attention aux comparaisons! */ -/* */ -/* Intel_compare: */ -/* */ -/* cmp A,B // A-B , set flags */ -/* jg A_greater_than_B */ -/* */ -/* AT&T_compare: */ -/* */ -/* cmp A,B // B-A , set flags */ -/* jg B_greater_than_A */ -/* */ -/* (soustrait l'op�rande source DE l'op�rande destination, */ -/* comme sur Motorola! ) */ - -// RAPPEL: Intel -// SECTION:[BASE+INDEX*SCALE+DISP] -// devient SECTION:DISP(BASE,INDEX,SCALE) - -//---------------------------------------------------------------------- -// -// R_DrawColumn -// -// New optimised version 10-01-1998 by D.Fabrice and P.Boris -// TO DO: optimise it much farther... should take at most 3 cycles/pix -// once it's fixed, add code to patch the offsets so that it -// works in every screen width. -// -//---------------------------------------------------------------------- - - .data -#ifdef LINUX - .align 2 -#else - .align 4 -#endif -C(loopcount): .long 0 -C(pixelcount): .long 0 -C(tystep): .long 0 - -C(vidwidth): .long 0 //use this one out of the inner loops - //so you don't need to patch everywhere... - -#ifdef USEASM -#if !defined( LINUX) - .text -#endif -.globl C(ASM_PatchRowBytes) -C(ASM_PatchRowBytes): - pushl %ebp - movl %esp, %ebp // assure l'"adressabilit� du stack" - - movl ARG1, %edx // read first arg - movl %edx, C(vidwidth) - - // 1 * vidwidth - movl %edx,p1+2 - movl %edx,w1+2 //water - movl %edx,p1b+2 //sky - - movl %edx,p5+2 - movl %edx,sh5+2 //smokie test - - // 2 * vidwidth - addl ARG1,%edx - - movl %edx,p2+2 - movl %edx,w2+2 //water - movl %edx,p2b+2 //sky - - movl %edx,p6+2 - movl %edx,p7+2 - movl %edx,p8+2 - movl %edx,p9+2 - movl %edx,sh6+2 //smokie test - movl %edx,sh7+2 - movl %edx,sh8+2 - movl %edx,sh9+2 - - // 3 * vidwidth - addl ARG1,%edx - - movl %edx,p3+2 - movl %edx,w3+2 //water - movl %edx,p3b+2 //sky - - // 4 * vidwidth - addl ARG1,%edx - - movl %edx,p4+2 - movl %edx,w4+2 //water - movl %edx,p4b+2 //sky - - popl %ebp - ret - - -#ifdef LINUX - .align 2 -#else - .align 5 -#endif -.globl C(R_DrawColumn_8) -C(R_DrawColumn_8): - pushl %ebp // preserve caller's stack frame pointer - pushl %esi // preserve register variables - pushl %edi - pushl %ebx - -// -// dest = ylookup[dc_yl] + columnofs[dc_x]; -// - movl C(dc_yl),%ebp - movl %ebp,%ebx - movl C(ylookup)(,%ebx,4),%edi - movl C(dc_x),%ebx - addl C(columnofs)(,%ebx,4),%edi // edi = dest - -// -// pixelcount = yh - yl + 1 -// - movl C(dc_yh),%eax - incl %eax - subl %ebp,%eax // pixel count - movl %eax,C(pixelcount) // save for final pixel - jle vdone // nothing to scale - -// -// frac = dc_texturemid - (centery-dc_yl)*fracstep; -// - movl C(dc_iscale),%ecx // fracstep - movl C(centery),%eax - subl %ebp,%eax - imul %ecx,%eax - movl C(dc_texturemid),%edx - subl %eax,%edx - movl %edx,%ebx - shrl $16,%ebx // frac int. - andl $0x0000007f,%ebx - shll $16,%edx // y frac up - - movl %ecx,%ebp - shll $16,%ebp // fracstep f. up - shrl $16,%ecx // fracstep i. ->cl - andb $0x7f,%cl - - movl C(dc_source),%esi - -// -// lets rock :) ! -// - movl C(pixelcount),%eax - movb %al,%dh - shrl $2,%eax - movb %al,%ch // quad count - movl C(dc_colormap),%eax - testb $3,%dh - jz v4quadloop - -// -// do un-even pixel -// - testb $1,%dh - jz 2f - - movb (%esi,%ebx),%al // prep un-even loops - addl %ebp,%edx // ypos f += ystep f - adcb %cl,%bl // ypos i += ystep i - movb (%eax),%dl // colormap texel - andb $0x7f,%bl // mask 0-127 texture index - movb %dl,(%edi) // output pixel - addl C(vidwidth),%edi - -// -// do two non-quad-aligned pixels -// -2: - testb $2,%dh - jz 3f - - movb (%esi,%ebx),%al // fetch source texel - addl %ebp,%edx // ypos f += ystep f - adcb %cl,%bl // ypos i += ystep i - movb (%eax),%dl // colormap texel - andb $0x7f,%bl // mask 0-127 texture index - movb %dl,(%edi) // output pixel - - movb (%esi,%ebx),%al // fetch source texel - addl %ebp,%edx // ypos f += ystep f - adcb %cl,%bl // ypos i += ystep i - movb (%eax),%dl // colormap texel - andb $0x7f,%bl // mask 0-127 texture index - addl C(vidwidth),%edi - movb %dl,(%edi) // output pixel - - addl C(vidwidth),%edi - -// -// test if there was at least 4 pixels -// -3: - testb $0xFF,%ch // test quad count - jz vdone - -// -// ebp : ystep frac. upper 24 bits -// edx : y frac. upper 24 bits -// ebx : y i. lower 7 bits, masked for index -// ecx : ch = counter, cl = y step i. -// eax : colormap aligned 256 -// esi : source texture column -// edi : dest screen -// -v4quadloop: - movb $0x7f,%dh // prep mask -// .align 4 -vquadloop: - movb (%esi,%ebx),%al // prep loop - addl %ebp,%edx // ypos f += ystep f - adcb %cl,%bl // ypos i += ystep i - movb (%eax),%dl // colormap texel - movb %dl,(%edi) // output pixel - andb $0x7f,%bl // mask 0-127 texture index - - movb (%esi,%ebx),%al // fetch source texel - addl %ebp,%edx - adcb %cl,%bl - movb (%eax),%dl -p1: movb %dl,0x12345678(%edi) - andb $0x7f,%bl - - movb (%esi,%ebx),%al // fetch source texel - addl %ebp,%edx - adcb %cl,%bl - movb (%eax),%dl -p2: movb %dl,2*0x12345678(%edi) - andb $0x7f,%bl - - movb (%esi,%ebx),%al // fetch source texel - addl %ebp,%edx - adcb %cl,%bl - movb (%eax),%dl -p3: movb %dl,3*0x12345678(%edi) - andb $0x7f,%bl - -p4: addl $4*0x12345678,%edi - - decb %ch - jnz vquadloop - -vdone: - popl %ebx // restore register variables - popl %edi - popl %esi - popl %ebp // restore caller's stack frame pointer - ret - -#ifdef HORIZONTALDRAW -// -------------------------------------------------------------------------- -// Horizontal Column Drawer Optimisation -// -------------------------------------------------------------------------- - -#ifdef LINUX - .align 2 -#else - .align 5 -#endif -.globl C(R_DrawHColumn_8) -C(R_DrawHColumn_8): - pushl %ebp - pushl %esi - pushl %edi - pushl %ebx - -// -// dest = yhlookup[dc_x] + hcolumnofs[dc_yl]; -// - movl C(dc_x),%ebx - movl C(yhlookup)(,%ebx,4),%edi - movl C(dc_yl),%ebp - movl %ebp,%ebx - addl C(hcolumnofs)(,%ebx,4),%edi // edi = dest - -// -// pixelcount = yh - yl + 1 -// - movl C(dc_yh),%eax - incl %eax - subl %ebp,%eax // pixel count - movl %eax,C(pixelcount) // save for final pixel - jle vhdone // nothing to scale - -// -// frac = dc_texturemid - (centery-dc_yl)*fracstep; -// - movl C(dc_iscale),%ecx // fracstep - movl C(centery),%eax - subl %ebp,%eax - imul %ecx,%eax - movl C(dc_texturemid),%edx - subl %eax,%edx - movl %edx,%ebx - shrl $16,%ebx // frac int. - andl $0x0000007f,%ebx - shll $16,%edx // y frac up - - movl %ecx,%ebp - shll $16,%ebp // fracstep f. up - shrl $16,%ecx // fracstep i. ->cl - andb $0x7f,%cl - - movl C(dc_source),%esi - -// -// lets rock :) ! -// - - movl C(pixelcount),%eax - movb %al,%dh - shrl $2,%eax - movb %al,%ch // quad count - - testb %ch, %ch - jz vhnearlydone - - movl C(dc_colormap),%eax - decl %edi //----- - -vhloop: - movb (%esi,%ebx),%al // fetch source texel - addl %ebp,%edx - adcb %cl,%bl - andb $0x7f,%bl - incl %edi //----- - movb (%eax),%dh - movb %dh,(%edi) //----- - - movb (%esi,%ebx),%al // fetch source texel - addl %ebp,%edx - incl %edi //----- - adcb %cl,%bl - movb (%eax),%dl - andb $0x7f,%bl - movb %dl,(%edi) //----- - - movb (%esi,%ebx),%al // fetch source texel - addl %ebp,%edx - adcb %cl,%bl -// shll $16,%edx - andb $0x7f,%bl - incl %edi //----- - movb (%eax),%dh - movb %dh,(%edi) //----- - - movb (%esi,%ebx),%al // fetch source texel - addl %ebp,%edx - incl %edi //----- - adcb %cl,%bl - movb (%eax),%dl - andb $0x7f,%bl - movb %dl,(%edi) -// movl %edx,(%edi) -// addl $4,%edi - - decb %ch - jnz vhloop - -vhnearlydone: -// movl C(pixelcount) - -vhdone: - popl %ebx - popl %edi - popl %esi - popl %ebp - ret - - -// -------------------------------------------------------------------------- -// Rotate a buffer 90 degree in clockwise order after horiz.col. draws -// -------------------------------------------------------------------------- - -#ifdef LINUX - .align 2 -#else - .align 5 -#endif -.globl C(R_RotateBuffer) -C(R_RotateBuffer): - pushl %ebp - pushl %esi - pushl %edi - pushl %ebx - - - movl C(dc_source),%esi - movl C(dc_colormap),%edi - - - movb (%esi),%ah - addl $200,%esi - movb (%ebx),%al - addl $200,%ebx - bswap %eax - movb (%esi),%ah - addl $200,%esi - movb (%ebx),%al - addl $200,%ebx - movl %eax,(%edi) - addl $4,%edi - - - popl %ebx - popl %edi - popl %esi - popl %ebp - ret -#endif - -//---------------------------------------------------------------------- -//13-02-98: -// R_DrawSkyColumn : same as R_DrawColumn but: -// -// - wrap around 256 instead of 127. -// this is needed because we have a higher texture for mouselook, -// we need at least 200 lines for the sky. -// -// NOTE: the sky should never wrap, so it could use a faster method. -// for the moment, we'll still use a wrapping method... -// -// IT S JUST A QUICK CUT N PASTE, WAS NOT OPTIMISED AS IT SHOULD BE !!! -// -//---------------------------------------------------------------------- - -#ifdef LINUX - .align 2 -#else - .align 5 -#endif -.globl C(R_DrawSkyColumn_8) -C(R_DrawSkyColumn_8): - pushl %ebp - pushl %esi - pushl %edi - pushl %ebx - -// -// dest = ylookup[dc_yl] + columnofs[dc_x]; -// - movl C(dc_yl),%ebp - movl %ebp,%ebx - movl C(ylookup)(,%ebx,4),%edi - movl C(dc_x),%ebx - addl C(columnofs)(,%ebx,4),%edi // edi = dest - -// -// pixelcount = yh - yl + 1 -// - movl C(dc_yh),%eax - incl %eax - subl %ebp,%eax // pixel count - movl %eax,C(pixelcount) // save for final pixel - jle vskydone // nothing to scale - -// -// frac = dc_texturemid - (centery-dc_yl)*fracstep; -// - movl C(dc_iscale),%ecx // fracstep - movl C(centery),%eax - subl %ebp,%eax - imul %ecx,%eax - movl C(dc_texturemid),%edx - subl %eax,%edx - movl %edx,%ebx - shrl $16,%ebx // frac int. - andl $0x000000ff,%ebx - shll $16,%edx // y frac up - - movl %ecx,%ebp - shll $16,%ebp // fracstep f. up - shrl $16,%ecx // fracstep i. ->cl - - movl C(dc_source),%esi - -// -// lets rock :) ! -// - movl C(pixelcount),%eax - movb %al,%dh - shrl $2,%eax - movb %al,%ch // quad count - movl C(dc_colormap),%eax - testb $3,%dh - jz v4skyquadloop - -// -// do un-even pixel -// - testb $1,%dh - jz 2f - - movb (%esi,%ebx),%al // prep un-even loops - addl %ebp,%edx // ypos f += ystep f - adcb %cl,%bl // ypos i += ystep i - movb (%eax),%dl // colormap texel - movb %dl,(%edi) // output pixel - addl C(vidwidth),%edi - -// -// do two non-quad-aligned pixels -// -2: - testb $2,%dh - jz 3f - - movb (%esi,%ebx),%al // fetch source texel - addl %ebp,%edx // ypos f += ystep f - adcb %cl,%bl // ypos i += ystep i - movb (%eax),%dl // colormap texel - movb %dl,(%edi) // output pixel - - movb (%esi,%ebx),%al // fetch source texel - addl %ebp,%edx // ypos f += ystep f - adcb %cl,%bl // ypos i += ystep i - movb (%eax),%dl // colormap texel - addl C(vidwidth),%edi - movb %dl,(%edi) // output pixel - - addl C(vidwidth),%edi - -// -// test if there was at least 4 pixels -// -3: - testb $0xFF,%ch // test quad count - jz vskydone - -// -// ebp : ystep frac. upper 24 bits -// edx : y frac. upper 24 bits -// ebx : y i. lower 7 bits, masked for index -// ecx : ch = counter, cl = y step i. -// eax : colormap aligned 256 -// esi : source texture column -// edi : dest screen -// -v4skyquadloop: -// .align 4 -vskyquadloop: - movb (%esi,%ebx),%al // prep loop - addl %ebp,%edx // ypos f += ystep f - adcb %cl,%bl // ypos i += ystep i - movb (%eax),%dl // colormap texel - movb %dl,(%edi) // output pixel - - movb (%esi,%ebx),%al // fetch source texel - addl %ebp,%edx - adcb %cl,%bl - movb (%eax),%dl -p1b: movb %dl,0x12345678(%edi) - - movb (%esi,%ebx),%al // fetch source texel - addl %ebp,%edx - adcb %cl,%bl - movb (%eax),%dl -p2b: movb %dl,2*0x12345678(%edi) - - movb (%esi,%ebx),%al // fetch source texel - addl %ebp,%edx - adcb %cl,%bl - movb (%eax),%dl -p3b: movb %dl,3*0x12345678(%edi) - -p4b: addl $4*0x12345678,%edi - - decb %ch - jnz vskyquadloop - -vskydone: - popl %ebx // restore register variables - popl %edi - popl %esi - popl %ebp // restore caller's stack frame pointer - ret - - - -//---------------------------------------------------------------------- -// -// R_DrawSpan -// -// Horizontal texture mapping -// -//---------------------------------------------------------------------- - - .data - -ystep: .long 0 -xstep: .long 0 -C(texwidth): .long 64 // texture width -#if !defined( LINUX) - .text -#endif -#ifdef LINUX - .align 2 -#else - .align 4 -#endif -.globl C(R_DrawSpan_8) -C(R_DrawSpan_8): - pushl %ebp // preserve caller's stack frame pointer - pushl %esi // preserve register variables - pushl %edi - pushl %ebx - - -// -// find loop count -// - movl C(ds_x2),%eax - incl %eax - subl C(ds_x1),%eax // pixel count - movl %eax,C(pixelcount) // save for final pixel - js hdone // nothing to scale - shrl $1,%eax // double pixel count - movl %eax,C(loopcount) - -// -// build composite position -// - movl C(ds_xfrac),%ebp - shll $10,%ebp - andl $0x0ffff0000,%ebp - movl C(ds_yfrac),%eax - shrl $6,%eax - andl $0x0ffff,%eax - movl C(ds_y),%edi - orl %eax,%ebp - - movl C(ds_source),%esi - -// -// calculate screen dest -// - - movl C(ylookup)(,%edi,4),%edi - movl C(ds_x1),%eax - addl C(columnofs)(,%eax,4),%edi - -// -// build composite step -// - movl C(ds_xstep),%ebx - shll $10,%ebx - andl $0x0ffff0000,%ebx - movl C(ds_ystep),%eax - shrl $6,%eax - andl $0x0ffff,%eax - orl %eax,%ebx - - //movl %eax,OFFSET hpatch1+2 // convice tasm to modify code... - movl %ebx,hpatch1+2 - //movl %eax,OFFSET hpatch2+2 // convice tasm to modify code... - movl %ebx,hpatch2+2 - movl %esi,hpatch3+2 - movl %esi,hpatch4+2 -// %eax aligned colormap -// %ebx aligned colormap -// %ecx,%edx scratch -// %esi virtual source -// %edi moving destination pointer -// %ebp frac - movl C(ds_colormap),%eax -// shld $22,%ebp,%ecx // begin calculating third pixel (y units) -// shld $6,%ebp,%ecx // begin calculating third pixel (x units) - movl %ebp,%ecx - addl %ebx,%ebp // advance frac pointer - shrw $10,%cx - roll $6,%ecx - andl $4095,%ecx // finish calculation for third pixel -// shld $22,%ebp,%edx // begin calculating fourth pixel (y units) -// shld $6,%ebp,%edx // begin calculating fourth pixel (x units) - movl %ebp,%edx - shrw $10,%dx - roll $6,%edx - addl %ebx,%ebp // advance frac pointer - andl $4095,%edx // finish calculation for fourth pixel - movl %eax,%ebx - movb (%esi,%ecx),%al // get first pixel - movb (%esi,%edx),%bl // get second pixel - testl $0x0fffffffe,C(pixelcount) - movb (%eax),%dl // color translate first pixel - -// jnz hdoubleloop // at least two pixels to map -// jmp hchecklast - -// movw $0xf0f0,%dx //see visplanes start - - jz hchecklast - movb (%ebx),%dh // color translate second pixel - movl C(loopcount),%esi -// .align 4 -hdoubleloop: -// shld $22,%ebp,%ecx // begin calculating third pixel (y units) -// shld $6,%ebp,%ecx // begin calculating third pixel (x units) - movl %ebp,%ecx - shrw $10,%cx - roll $6,%ecx -hpatch1: - addl $0x012345678,%ebp // advance frac pointer - movw %dx,(%edi) // write first pixel - andl $4095,%ecx // finish calculation for third pixel -// shld $22,%ebp,%edx // begin calculating fourth pixel (y units) -// shld $6,%ebp,%edx // begin calculating fourth pixel (x units) - movl %ebp,%edx - shrw $10,%dx - roll $6,%edx -hpatch3: - movb 0x012345678(%ecx),%al // get third pixel -// movb %bl,1(%edi) // write second pixel - andl $4095,%edx // finish calculation for fourth pixel -hpatch2: - addl $0x012345678,%ebp // advance frac pointer -hpatch4: - movb 0x012345678(%edx),%bl // get fourth pixel - movb (%eax),%dl // color translate third pixel - addl $2,%edi // advance to third pixel destination - decl %esi // done with loop? - movb (%ebx),%dh // color translate fourth pixel - jnz hdoubleloop - -// check for final pixel -hchecklast: - testl $1,C(pixelcount) - jz hdone - movb %dl,(%edi) // write final pixel - -hdone: - popl %ebx // restore register variables - popl %edi - popl %esi - popl %ebp // restore caller's stack frame pointer - ret - - -//.endif - - -//---------------------------------------------------------------------- -// R_DrawTransColumn -// -// Vertical column texture drawer, with transparency. Replaces Doom2's -// 'fuzz' effect, which was not so beautiful. -// Transparency is always impressive in some way, don't know why... -//---------------------------------------------------------------------- - -#ifdef LINUX - .align 2 -#else - .align 5 -#endif - -.globl C(R_DrawTranslucentColumn_8) -C(R_DrawTranslucentColumn_8): - pushl %ebp // preserve caller's stack frame pointer - pushl %esi // preserve register variables - pushl %edi - pushl %ebx - -// -// dest = ylookup[dc_yl] + columnofs[dc_x]; -// - movl C(dc_yl),%ebp - movl %ebp,%ebx - movl C(ylookup)(,%ebx,4),%edi - movl C(dc_x),%ebx - addl C(columnofs)(,%ebx,4),%edi // edi = dest - -// -// pixelcount = yh - yl + 1 -// - movl C(dc_yh),%eax - incl %eax - subl %ebp,%eax // pixel count - movl %eax,C(pixelcount) // save for final pixel - jle vtdone // nothing to scale - -// -// frac = dc_texturemid - (centery-dc_yl)*fracstep; -// - movl C(dc_iscale),%ecx // fracstep - movl C(centery),%eax - subl %ebp,%eax - imul %ecx,%eax - movl C(dc_texturemid),%edx - subl %eax,%edx - movl %edx,%ebx - - shrl $16,%ebx // frac int. - andl $0x0000007f,%ebx - shll $16,%edx // y frac up - - movl %ecx,%ebp - shll $16,%ebp // fracstep f. up - shrl $16,%ecx // fracstep i. ->cl - andb $0x7f,%cl - pushw %cx - movl %edx,%ecx - popw %cx - movl C(dc_colormap),%edx - movl C(dc_source),%esi - -// -// lets rock :) ! -// - movl C(pixelcount),%eax - shrl $2,%eax - testb $0x03,C(pixelcount) - movb %al,%ch // quad count - movl C(dc_transmap),%eax - jz vt4quadloop -// -// do un-even pixel -// - testb $1,C(pixelcount) - jz 2f - - movb (%esi,%ebx),%ah // fetch texel : colormap number - addl %ebp,%ecx - adcb %cl,%bl - movb (%edi),%al // fetch dest : index into colormap - andb $0x7f,%bl - movb (%eax),%dl - movb (%edx), %dl // use colormap now ! - movb %dl,(%edi) - addl C(vidwidth),%edi -// -// do two non-quad-aligned pixels -// -2: - testb $2,C(pixelcount) - jz 3f - - movb (%esi,%ebx),%ah // fetch texel : colormap number - addl %ebp,%ecx - adcb %cl,%bl - movb (%edi),%al // fetch dest : index into colormap - andb $0x7f,%bl - movb (%eax),%dl - movb (%edx), %dl // use colormap now ! - movb %dl,(%edi) - addl C(vidwidth),%edi - - movb (%esi,%ebx),%ah // fetch texel : colormap number - addl %ebp,%ecx - adcb %cl,%bl - movb (%edi),%al // fetch dest : index into colormap - andb $0x7f,%bl - movb (%eax),%dl - movb (%edx), %dl // use colormap now ! - movb %dl,(%edi) - addl C(vidwidth),%edi - -// -// test if there was at least 4 pixels -// -3: - testb $0xFF,%ch // test quad count - jz vtdone - -// -// tystep : ystep frac. upper 24 bits -// edx : upper 24 bit : colomap -// dl : tmp pixel to write -// ebx : y i. lower 7 bits, masked for index -// ecx : y frac. upper 16 bits -// ecx : ch = counter, cl = y step i. -// eax : transmap aligned 65535 (upper 16 bit) -// ah : background pixel (from the screen buffer) -// al : foreground pixel (from the texture) -// esi : source texture column -// ebp,edi : dest screen -// -vt4quadloop: - movb (%esi,%ebx),%ah // fetch texel : colormap number -p5: movb 0x12345678(%edi),%al // fetch dest : index into colormap - - movl %ebp,C(tystep) - movl %edi,%ebp - subl C(vidwidth),%edi - jmp inloop -// .align 4 -vtquadloop: - addl C(tystep),%ecx - adcb %cl,%bl -p6: addl $2*0x12345678,%ebp - andb $0x7f,%bl - movb (%eax),%dl - movb (%esi,%ebx),%ah // fetch texel : colormap number - movb (%edx), %dl // use colormap now ! - movb %dl,(%edi) - movb (%ebp),%al // fetch dest : index into colormap -inloop: - addl C(tystep),%ecx - adcb %cl,%bl -p7: addl $2*0x12345678,%edi - andb $0x7f,%bl - movb (%eax),%dl - movb (%esi,%ebx),%ah // fetch texel : colormap number - movb (%edx), %dl // use colormap now ! - movb %dl,(%ebp) - movb (%edi),%al // fetch dest : index into colormap - - addl C(tystep),%ecx - adcb %cl,%bl -p8: addl $2*0x12345678,%ebp - andb $0x7f,%bl - movb (%eax),%dl - movb (%esi,%ebx),%ah // fetch texel : colormap number - movb (%edx), %dl // use colormap now ! - movb %dl,(%edi) - movb (%ebp),%al // fetch dest : index into colormap - - addl C(tystep),%ecx - adcb %cl,%bl -p9: addl $2*0x12345678,%edi - andb $0x7f,%bl - movb (%eax),%dl - movb (%esi,%ebx),%ah // fetch texel : colormap number - movb (%edx), %dl // use colormap now ! - movb %dl,(%ebp) - movb (%edi),%al // fetch dest : index into colormap - - decb %ch - jnz vtquadloop - -vtdone: - popl %ebx // restore register variables - popl %edi - popl %esi - popl %ebp // restore caller's stack frame pointer - ret - -#endif // ifdef USEASM - - - -//---------------------------------------------------------------------- -// R_DrawShadeColumn -// -// for smoke..etc.. test. -//---------------------------------------------------------------------- - -#ifdef LINUX - .align 2 -#else - .align 5 -#endif -.globl C(R_DrawShadeColumn_8) -C(R_DrawShadeColumn_8): - pushl %ebp // preserve caller's stack frame pointer - pushl %esi // preserve register variables - pushl %edi - pushl %ebx - -// -// dest = ylookup[dc_yl] + columnofs[dc_x]; -// - movl C(dc_yl),%ebp - movl %ebp,%ebx - movl C(ylookup)(,%ebx,4),%edi - movl C(dc_x),%ebx - addl C(columnofs)(,%ebx,4),%edi // edi = dest - -// -// pixelcount = yh - yl + 1 -// - movl C(dc_yh),%eax - incl %eax - subl %ebp,%eax // pixel count - movl %eax,C(pixelcount) // save for final pixel - jle shdone // nothing to scale - -// -// frac = dc_texturemid - (centery-dc_yl)*fracstep; -// - movl C(dc_iscale),%ecx // fracstep - movl C(centery),%eax - subl %ebp,%eax - imul %ecx,%eax - movl C(dc_texturemid),%edx - subl %eax,%edx - movl %edx,%ebx - shrl $16,%ebx // frac int. - andl $0x0000007f,%ebx - shll $16,%edx // y frac up - - movl %ecx,%ebp - shll $16,%ebp // fracstep f. up - shrl $16,%ecx // fracstep i. ->cl - andb $0x7f,%cl - - movl C(dc_source),%esi - -// -// lets rock :) ! -// - movl C(pixelcount),%eax - movb %al,%dh - shrl $2,%eax - movb %al,%ch // quad count - movl C(colormaps),%eax - testb $0x03,%dh - jz sh4quadloop - -// -// do un-even pixel -// - testb $1,%dh - jz 2f - - movb (%esi,%ebx),%ah // fetch texel : colormap number - addl %ebp,%edx - adcb %cl,%bl - movb (%edi),%al // fetch dest : index into colormap - andb $0x7f,%bl - movb (%eax),%dl - movb %dl,(%edi) - addl C(vidwidth),%edi - -// -// do two non-quad-aligned pixels -// -2: - testb $2,%dh - jz 3f - - movb (%esi,%ebx),%ah // fetch texel : colormap number - addl %ebp,%edx - adcb %cl,%bl - movb (%edi),%al // fetch dest : index into colormap - andb $0x7f,%bl - movb (%eax),%dl - movb %dl,(%edi) - addl C(vidwidth),%edi - - movb (%esi,%ebx),%ah // fetch texel : colormap number - addl %ebp,%edx - adcb %cl,%bl - movb (%edi),%al // fetch dest : index into colormap - andb $0x7f,%bl - movb (%eax),%dl - movb %dl,(%edi) - addl C(vidwidth),%edi - -// -// test if there was at least 4 pixels -// -3: - testb $0xFF,%ch // test quad count - jz shdone - -// -// ebp : ystep frac. upper 24 bits -// edx : y frac. upper 24 bits -// ebx : y i. lower 7 bits, masked for index -// ecx : ch = counter, cl = y step i. -// eax : colormap aligned 256 -// esi : source texture column -// edi : dest screen -// -sh4quadloop: - movb $0x7f,%dh // prep mask - - movb (%esi,%ebx),%ah // fetch texel : colormap number -sh5: movb 0x12345678(%edi),%al // fetch dest : index into colormap - - movl %ebp,C(tystep) - movl %edi,%ebp - subl C(vidwidth),%edi - jmp shinloop -// .align 4 -shquadloop: - addl C(tystep),%edx - adcb %cl,%bl - andb %dh,%bl -sh6: addl $2*0x12345678,%ebp - movb (%eax),%dl - movb (%esi,%ebx),%ah // fetch texel : colormap number - movb %dl,(%edi) - movb (%ebp),%al // fetch dest : index into colormap -shinloop: - addl C(tystep),%edx - adcb %cl,%bl - andb %dh,%bl -sh7: addl $2*0x12345678,%edi - movb (%eax),%dl - movb (%esi,%ebx),%ah // fetch texel : colormap number - movb %dl,(%ebp) - movb (%edi),%al // fetch dest : index into colormap - - addl C(tystep),%edx - adcb %cl,%bl - andb %dh,%bl -sh8: addl $2*0x12345678,%ebp - movb (%eax),%dl - movb (%esi,%ebx),%ah // fetch texel : colormap number - movb %dl,(%edi) - movb (%ebp),%al // fetch dest : index into colormap - - addl C(tystep),%edx - adcb %cl,%bl - andb %dh,%bl -sh9: addl $2*0x12345678,%edi - movb (%eax),%dl - movb (%esi,%ebx),%ah // fetch texel : colormap number - movb %dl,(%ebp) - movb (%edi),%al // fetch dest : index into colormap - - decb %ch - jnz shquadloop - -shdone: - popl %ebx // restore register variables - popl %edi - popl %esi - popl %ebp // restore caller's stack frame pointer - ret - - - -//---------------------------------------------------------------------- -// -// R_DrawWaterColumn : basically it's just a copy of R_DrawColumn, -// but it uses dc_colormap from dc_yl to dc_yw-1 -// then it uses dc_wcolormap from dc_yw to dc_yh -// -// Thus, the 'underwater' part of the walls is remapped to 'water-like' -// colors. -// -//---------------------------------------------------------------------- - -#ifdef LINUX - .align 2 -#else - .align 5 -#endif -.globl C(R_DrawWaterColumn) -C(R_DrawWaterColumn): - pushl %ebp // preserve caller's stack frame pointer - pushl %esi // preserve register variables - pushl %edi - pushl %ebx - -// -// dest = ylookup[dc_yl] + columnofs[dc_x]; -// - movl C(dc_yl),%ebp - movl %ebp,%ebx - movl C(ylookup)(,%ebx,4),%edi - movl C(dc_x),%ebx - addl C(columnofs)(,%ebx,4),%edi // edi = dest - -// -// pixelcount = yh - yl + 1 -// - movl C(dc_yh),%eax - incl %eax - subl %ebp,%eax // pixel count - movl %eax,C(pixelcount) // save for final pixel - jle wdone // nothing to scale - -// -// frac = dc_texturemid - (centery-dc_yl)*fracstep; -// - movl C(dc_iscale),%ecx // fracstep - movl C(centery),%eax - subl %ebp,%eax - imul %ecx,%eax - movl C(dc_texturemid),%edx - subl %eax,%edx - movl %edx,%ebx - shrl $16,%ebx // frac int. - andl $0x0000007f,%ebx - shll $16,%edx // y frac up - - movl %ecx,%ebp - shll $16,%ebp // fracstep f. up - shrl $16,%ecx // fracstep i. ->cl - andb $0x7f,%cl - - movl C(dc_source),%esi - -// -// lets rock :) ! -// - movl C(pixelcount),%eax - movb %al,%dh - shrl $2,%eax - movb %al,%ch // quad count - movl C(dc_wcolormap),%eax - testb $3,%dh - jz w4quadloop - -// -// do un-even pixel -// - testb $1,%dh - jz 2f - - movb (%esi,%ebx),%al // prep un-even loops - addl %ebp,%edx // ypos f += ystep f - adcb %cl,%bl // ypos i += ystep i - movb (%eax),%dl // colormap texel - andb $0x7f,%bl // mask 0-127 texture index - movb %dl,(%edi) // output pixel - addl C(vidwidth),%edi - -// -// do two non-quad-aligned pixels -// -2: - testb $2,%dh - jz 3f - - movb (%esi,%ebx),%al // fetch source texel - addl %ebp,%edx // ypos f += ystep f - adcb %cl,%bl // ypos i += ystep i - movb (%eax),%dl // colormap texel - andb $0x7f,%bl // mask 0-127 texture index - movb %dl,(%edi) // output pixel - - movb (%esi,%ebx),%al // fetch source texel - addl %ebp,%edx // ypos f += ystep f - adcb %cl,%bl // ypos i += ystep i - movb (%eax),%dl // colormap texel - andb $0x7f,%bl // mask 0-127 texture index - addl C(vidwidth),%edi - movb %dl,(%edi) // output pixel - - addl C(vidwidth),%edi - -// -// test if there was at least 4 pixels -// -3: - testb $0xFF,%ch // test quad count - jz wdone - -// -// ebp : ystep frac. upper 24 bits -// edx : y frac. upper 24 bits -// ebx : y i. lower 7 bits, masked for index -// ecx : ch = counter, cl = y step i. -// eax : colormap aligned 256 -// esi : source texture column -// edi : dest screen -// -w4quadloop: - movb $0x7f,%dh // prep mask -// .align 4 -wquadloop: - movb (%esi,%ebx),%al // prep loop - addl %ebp,%edx // ypos f += ystep f - adcb %cl,%bl // ypos i += ystep i - movb (%eax),%dl // colormap texel - movb %dl,(%edi) // output pixel - andb $0x7f,%bl // mask 0-127 texture index - - movb (%esi,%ebx),%al // fetch source texel - addl %ebp,%edx - adcb %cl,%bl - movb (%eax),%dl -w1: movb %dl,0x12345678(%edi) - andb $0x7f,%bl - - movb (%esi,%ebx),%al // fetch source texel - addl %ebp,%edx - adcb %cl,%bl - movb (%eax),%dl -w2: movb %dl,2*0x12345678(%edi) - andb $0x7f,%bl - - movb (%esi,%ebx),%al // fetch source texel - addl %ebp,%edx - adcb %cl,%bl - movb (%eax),%dl -w3: movb %dl,3*0x12345678(%edi) - andb $0x7f,%bl - -w4: addl $4*0x12345678,%edi - - decb %ch - jnz wquadloop - -wdone: - popl %ebx // restore register variables - popl %edi - popl %esi - popl %ebp // restore caller's stack frame pointer - ret - - - - - - - -//---------------------------------------------------------------------- -// -// R_DrawSpanNoWrap -// -// Horizontal texture mapping, does not remap colors, -// neither needs to wrap around the source texture. -// -// Thus, a special optimisation can be used... -// -//---------------------------------------------------------------------- - - .data - -advancetable: .long 0, 0 -#if !defined( LINUX) - .text -#endif -#ifdef LINUX - .align 2 -#else - .align 4 -#endif -.globl C(R_DrawSpanNoWrap) -C(R_DrawSpanNoWrap): - pushl %ebp // preserve caller's stack frame pointer - pushl %esi // preserve register variables - pushl %edi - pushl %ebx - -// -// find loop count -// - - movl C(ds_x2),%eax - incl %eax - subl C(ds_x1),%eax // pixel count - movl %eax,C(pixelcount) // save for final pixel - jle htvdone // nothing to scale -// shrl $1,%eax // double pixel count -// movl %eax,C(loopcount) - -// -// calculate screen dest -// - - movl C(ds_y),%edi //full destination start address - -// -// set up advancetable -// - - movl C(ds_xstep),%ebp - movl C(ds_ystep),%ecx - movl %ecx,%eax - movl %ebp,%edx - sarl $16,%edx // xstep >>= 16; - movl C(vidwidth),%ebx - sarl $16,%eax // ystep >>= 16; - jz 0f - imull %ebx,%eax // (ystep >> 16) * texwidth; -0: - addl %edx,%eax // add in xstep - // (ystep >> 16) * texwidth + (xstep >> 16); - - movl %eax,advancetable+4 // advance base in y - addl %ebx,%eax // ((ystep >> 16) + 1) * texwidth + - // (xstep >> 16); - movl %eax,advancetable // advance extra in y - - shll $16,%ebp // left-justify xstep fractional part - movl %ebp,xstep - shll $16,%ecx // left-justify ystep fractional part - movl %ecx,ystep - -// -// calculate the texture starting address -// - movl C(ds_source),%esi // texture source - - movl C(ds_yfrac),%eax - movl %eax,%edx - sarl $16,%eax - movl C(ds_xfrac),%ecx - imull %ebx,%eax // (yfrac >> 16) * texwidth - movl %ecx,%ebx - sarl $16,%ecx - movl %ecx,%ebp - addl %eax,%ebp // source = (xfrac >> 16) + - // ((yfrac >> 16) * texwidth); - -// -// esi : texture source -// edi : screen dest -// eax : colormap aligned on 256 boundary, hehehe... -// ebx : xfrac << 16 -// ecx : used in loop, contains either 0 or -1, *4, offset into advancetable -// edx : yfrac << 16 -// ebp : offset into texture -// - - shll $16,%edx // yfrac upper word, lower byte will be used - movl C(ds_colormap),%eax - shll $16,%ebx // xfrac upper word, lower unused - - movl C(pixelcount),%ecx - shrl $2,%ecx - movb %cl,%dh // quad pixels count - - movl C(pixelcount),%ecx - andl $3,%ecx - jz htvquadloop // pixelcount is multiple of 4 - decl %ecx - jz 1f - decl %ecx - jz 2f - -// -// do one to three pixels first -// - addl ystep,%edx // yfrac += ystep - sbbl %ecx,%ecx // turn carry into 0 or -1 if set - movb (%esi,%ebp),%al // get texture pixel - addl xstep,%ebx // xfrac += xstep -// movb (%eax),%dl // pixel goes through colormap - adcl advancetable+4(,%ecx,4),%ebp // advance source - movb %al,(%edi) // write pixel dest - - incl %edi - -2: - addl ystep,%edx // yfrac += ystep - sbbl %ecx,%ecx // turn carry into 0 or -1 if set - movb (%esi,%ebp),%al // get texture pixel - addl xstep,%ebx // xfrac += xstep -// movb (%eax),%dl // pixel goes through colormap - adcl advancetable+4(,%ecx,4),%ebp // advance source - movb %al,(%edi) // write pixel dest - - incl %edi - -1: - addl ystep,%edx // yfrac += ystep - sbbl %ecx,%ecx // turn carry into 0 or -1 if set - movb (%esi,%ebp),%al // get texture pixel - addl xstep,%ebx // xfrac += xstep -// movb (%eax),%dl // pixel goes through colormap - adcl advancetable+4(,%ecx,4),%ebp // advance source - movb %al,(%edi) // write pixel dest - - incl %edi - -// -// test if there was at least 4 pixels -// - testb $0xFF,%dh - jz htvdone - -// -// two pixels per loop -// U -// V -htvquadloop: - addl ystep,%edx // yfrac += ystep - sbbl %ecx,%ecx // turn carry into 0 or -1 if set - movb (%esi,%ebp),%al // get texture pixel - addl xstep,%ebx // xfrac += xstep -// movb (%eax),%dl // pixel goes through colormap - adcl advancetable+4(,%ecx,4),%ebp // advance source - movb %al,(%edi) // write pixel dest - - addl ystep,%edx - sbbl %ecx,%ecx - movb (%esi,%ebp),%al - addl xstep,%ebx -// movb (%eax),%dl - adcl advancetable+4(,%ecx,4),%ebp - movb %al,1(%edi) - - addl ystep,%edx - sbbl %ecx,%ecx - movb (%esi,%ebp),%al - addl xstep,%ebx -// movb (%eax),%dl - adcl advancetable+4(,%ecx,4),%ebp - movb %al,2(%edi) - - addl ystep,%edx - sbbl %ecx,%ecx - movb (%esi,%ebp),%al - addl xstep,%ebx -// movb (%eax),%dl - adcl advancetable+4(,%ecx,4),%ebp - movb %al,3(%edi) - - addl $4, %edi - incl %ecx //dummy - - decb %dh - jnz htvquadloop // paire dans V-pipe - -htvdone: - popl %ebx // restore register variables - popl %edi - popl %esi - popl %ebp // restore caller's stack frame pointer - ret - - -//.endif - -#ifdef HORIZONTALDRAW -// void R_RotateBuffere (void) - -#ifdef LINUX - .align 2 -#else - .align 4 -#endif -.globl C(R_RotateBufferasm) -C(R_RotateBufferasm): - pushl %ebp // preserve caller's stack frame pointer - pushl %esi // preserve register variables - pushl %edi - pushl %ebx - - movl C(dc_source),%esi - movl C(dc_colormap),%edi - - movl $200,%edx -ra2: - movl $40,%ecx -ra: - movb -2*200(%esi),%al - movb -6*200(%esi),%bl - movb -3*200(%esi),%ah - movb -7*200(%esi),%bh - shll $16,%eax - shll $16,%ebx - movb (%esi),%al - movb -4*200(%esi),%bl - movb -1*200(%esi),%ah - movb -5*200(%esi),%bh - movl %eax,(%edi) - subl $8*200,%esi - movl %ebx,4(%edi) - addl $8,%edi - decl %ecx - jnz ra - - addl $320*200+1,%esi //32*480 passe a la ligne suivante -// addl 320-32,%edi - - decl %edx - jnz ra2 - - pop %ebp // preserve caller's stack frame pointer - pop %esi // preserve register variables - pop %edi - pop %ebx - ret -#endif diff --git a/src/tmap_asm.s b/src/tmap_asm.s deleted file mode 100644 index d8967178cdf28e3b9bedbda863232ef0bf0978d4..0000000000000000000000000000000000000000 --- a/src/tmap_asm.s +++ /dev/null @@ -1,322 +0,0 @@ -// SONIC ROBO BLAST 2 -//----------------------------------------------------------------------------- -// Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2023 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 tmap_asm.s -/// \brief ??? - -//.comm _dc_colormap,4 -//.comm _dc_x,4 -//.comm _dc_yl,4 -//.comm _dc_yh,4 -//.comm _dc_iscale,4 -//.comm _dc_texturemid,4 -//.comm _dc_source,4 -//.comm _ylookup,4 -//.comm _columnofs,4 -//.comm _loopcount,4 -//.comm _pixelcount,4 -.data -_pixelcount: -.long 0x00000000 -_loopcount: -.long 0x00000000 -.align 8 -_mmxcomm: -.long 0x00000000 -.text - - .align 4 -.globl _R_DrawColumn8_NOMMX -_R_DrawColumn8_NOMMX: - pushl %ebp - pushl %esi - pushl %edi - pushl %ebx - movl _dc_yl,%edx - movl _dc_yh,%eax - subl %edx,%eax - leal 1(%eax),%ebx - testl %ebx,%ebx - jle rdc8ndone - movl _dc_x,%eax - movl _ylookup, %edi - movl (%edi,%edx,4),%esi - movl _columnofs, %edi - addl (%edi,%eax,4),%esi - movl _dc_iscale,%edi - movl %edx,%eax - imull %edi,%eax - movl _dc_texturemid,%ecx - addl %eax,%ecx - - movl _dc_source,%ebp - xorl %edx, %edx - subl $0x12345678, %esi -.globl rdc8nwidth1 -rdc8nwidth1: - .align 4,0x90 -rdc8nloop: - movl %ecx,%eax - shrl $16,%eax - addl %edi,%ecx - andl $127,%eax - addl $0x12345678,%esi -.globl rdc8nwidth2 -rdc8nwidth2: - movb (%eax,%ebp),%dl - movl _dc_colormap,%eax - movb (%eax,%edx),%al - movb %al,(%esi) - decl %ebx - jne rdc8nloop -rdc8ndone: - popl %ebx - popl %edi - popl %esi - popl %ebp - ret - -// -// Optimised specifically for P54C/P55C (aka Pentium with/without MMX) -// By ES 1998/08/01 -// - -.globl _R_DrawColumn_8_Pentium -_R_DrawColumn_8_Pentium: - pushl %ebp - pushl %ebx - pushl %esi - pushl %edi - movl _dc_yl,%eax // Top pixel - movl _dc_yh,%ebx // Bottom pixel - movl _ylookup, %edi - movl (%edi,%ebx,4),%ecx - subl %eax,%ebx // ebx=number of pixels-1 - jl rdc8pdone // no pixel to draw, done - jnz rdc8pmany - movl _dc_x,%edx // Special case: only one pixel - movl _columnofs, %edi - addl (%edi,%edx,4),%ecx // dest pixel at (%ecx) - movl _dc_iscale,%esi - imull %esi,%eax - movl _dc_texturemid,%edi - addl %eax,%edi // texture index in edi - movl _dc_colormap,%edx - shrl $16, %edi - movl _dc_source,%ebp - andl $127,%edi - movb (%edi,%ebp),%dl // read texture pixel - movb (%edx),%al // lookup for light - movb %al,0(%ecx) // write it - jmp rdc8pdone // done! -.align 4, 0x90 -rdc8pmany: // draw >1 pixel - movl _dc_x,%edx - movl _columnofs, %edi - movl (%edi,%edx,4),%edx - leal 0x12345678(%edx, %ecx), %edi // edi = two pixels above bottom -.globl rdc8pwidth5 -rdc8pwidth5: // DeadBeef = -2*SCREENWIDTH - movl _dc_iscale,%edx // edx = fracstep - imull %edx,%eax - shll $9, %edx // fixme: Should get 7.25 fix as input - movl _dc_texturemid,%ecx - addl %eax,%ecx // ecx = frac - movl _dc_colormap,%eax // eax = lighting/special effects LUT - shll $9, %ecx - movl _dc_source,%esi // esi = source ptr - - imull $0x12345678, %ebx // ebx = negative offset to pixel -.globl rdc8pwidth6 -rdc8pwidth6: // DeadBeef = -SCREENWIDTH - -// Begin the calculation of the two first pixels - leal (%ecx, %edx), %ebp - shrl $25, %ecx - movb (%esi, %ecx), %al - leal (%edx, %ebp), %ecx - shrl $25, %ebp - movb (%eax), %dl - -// The main loop -rdc8ploop: - movb (%esi,%ebp), %al // load 1 - leal (%ecx, %edx), %ebp // calc frac 3 - - shrl $25, %ecx // shift frac 2 - movb %dl, 0x12345678(%edi, %ebx)// store 0 -.globl rdc8pwidth1 -rdc8pwidth1: // DeadBeef = 2*SCREENWIDTH - - movb (%eax), %al // lookup 1 - - movb %al, 0x12345678(%edi, %ebx)// store 1 -.globl rdc8pwidth2 -rdc8pwidth2: // DeadBeef = 3*SCREENWIDTH - movb (%esi, %ecx), %al // load 2 - - leal (%ebp, %edx), %ecx // calc frac 4 - - shrl $25, %ebp // shift frac 3 - movb (%eax), %dl // lookup 2 - - addl $0x12345678, %ebx // counter -.globl rdc8pwidth3 -rdc8pwidth3: // DeadBeef = 2*SCREENWIDTH - jl rdc8ploop // loop - -// End of loop. Write extra pixel or just exit. - jnz rdc8pdone - movb %dl, 0x12345678(%edi, %ebx)// Write odd pixel -.globl rdc8pwidth4 -rdc8pwidth4: // DeadBeef = 2*SCREENWIDTH - -rdc8pdone: - - popl %edi - popl %esi - popl %ebx - popl %ebp - ret - -// -// MMX asm version, optimised for K6 -// By ES 1998/07/05 -// - -.globl _R_DrawColumn_8_K6_MMX -_R_DrawColumn_8_K6_MMX: - pushl %ebp - pushl %ebx - pushl %esi - pushl %edi - - movl %esp, %eax // Push 8 or 12, so that (%esp) gets aligned by 8 - andl $7,%eax - addl $8,%eax - movl %eax, _mmxcomm // Temp storage in mmxcomm: (%esp) is used instead - subl %eax,%esp - - movl _dc_yl,%edx // Top pixel - movl _dc_yh,%ebx // Bottom pixel - movl _ylookup, %edi - movl (%edi,%ebx,4),%ecx - subl %edx,%ebx // ebx=number of pixels-1 - jl 0x12345678 // no pixel to draw, done -.globl rdc8moffs1 -rdc8moffs1: - jnz rdc8mmany - movl _dc_x,%eax // Special case: only one pixel - movl _columnofs, %edi - addl (%edi,%eax,4),%ecx // dest pixel at (%ecx) - movl _dc_iscale,%esi - imull %esi,%edx - movl _dc_texturemid,%edi - addl %edx,%edi // texture index in edi - movl _dc_colormap,%edx - shrl $16, %edi - movl _dc_source,%ebp - andl $127,%edi - movb (%edi,%ebp),%dl // read texture pixel - movb (%edx),%al // lookup for light - movb %al,0(%ecx) // write it - jmp rdc8mdone // done! -.globl rdc8moffs2 -rdc8moffs2: -.align 4, 0x90 -rdc8mmany: // draw >1 pixel - movl _dc_x,%eax - movl _columnofs, %edi - movl (%edi,%eax,4),%eax - leal 0x12345678(%eax, %ecx), %esi // esi = two pixels above bottom -.globl rdc8mwidth3 -rdc8mwidth3: // DeadBeef = -2*SCREENWIDTH - movl _dc_iscale,%ecx // ecx = fracstep - imull %ecx,%edx - shll $9, %ecx // fixme: Should get 7.25 fix as input - movl _dc_texturemid,%eax - addl %edx,%eax // eax = frac - movl _dc_colormap,%edx // edx = lighting/special effects LUT - shll $9, %eax - leal (%ecx, %ecx), %edi - movl _dc_source,%ebp // ebp = source ptr - movl %edi, 0(%esp) // Start moving frac and fracstep to MMX regs - - imull $0x12345678, %ebx // ebx = negative offset to pixel -.globl rdc8mwidth5 -rdc8mwidth5: // DeadBeef = -SCREENWIDTH - - movl %edi, 4(%esp) - leal (%eax, %ecx), %edi - movq 0(%esp), %mm1 // fracstep:fracstep in mm1 - movl %eax, 0(%esp) - shrl $25, %eax - movl %edi, 4(%esp) - movzbl (%ebp, %eax), %eax - movq 0(%esp), %mm0 // frac:frac in mm0 - - paddd %mm1, %mm0 - shrl $25, %edi - movq %mm0, %mm2 - psrld $25, %mm2 // texture index in mm2 - paddd %mm1, %mm0 - movq %mm2, 0(%esp) - -.globl rdc8mloop -rdc8mloop: // The main loop - movq %mm0, %mm2 // move 4-5 to temp reg - movzbl (%ebp, %edi), %edi // read 1 - - psrld $25, %mm2 // shift 4-5 - movb (%edx,%eax), %cl // lookup 0 - - movl 0(%esp), %eax // load 2 - addl $0x12345678, %ebx // counter -.globl rdc8mwidth2 -rdc8mwidth2: // DeadBeef = 2*SCREENWIDTH - - movb %cl, (%esi, %ebx) // write 0 - movb (%edx,%edi), %ch // lookup 1 - - movb %ch, 0x12345678(%esi, %ebx) // write 1 -.globl rdc8mwidth1 -rdc8mwidth1: // DeadBeef = SCREENWIDTH - movl 4(%esp), %edi // load 3 - - paddd %mm1, %mm0 // frac 6-7 - movzbl (%ebp, %eax), %eax // lookup 2 - - movq %mm2, 0(%esp) // store texture index 4-5 - jl rdc8mloop - - jnz rdc8mno_odd - movb (%edx,%eax), %cl // write the last odd pixel - movb %cl, 0x12345678(%esi) -.globl rdc8mwidth4 -rdc8mwidth4: // DeadBeef = 2*SCREENWIDTH -rdc8mno_odd: - -.globl rdc8mdone -rdc8mdone: - emms - - addl _mmxcomm, %esp - popl %edi - popl %esi - popl %ebx - popl %ebp - ret - -// Need some extra space to align run-time -.globl R_DrawColumn_8_K6_MMX_end -R_DrawColumn_8_K6_MMX_end: -nop;nop;nop;nop;nop;nop;nop;nop; -nop;nop;nop;nop;nop;nop;nop;nop; -nop;nop;nop;nop;nop;nop;nop;nop; -nop;nop;nop;nop;nop;nop;nop; diff --git a/src/tmap_mmx.nas b/src/tmap_mmx.nas deleted file mode 100644 index a45667e23d539997193e0df23862dba71458c6f6..0000000000000000000000000000000000000000 --- a/src/tmap_mmx.nas +++ /dev/null @@ -1,674 +0,0 @@ -;; SONIC ROBO BLAST 2 -;;----------------------------------------------------------------------------- -;; Copyright (C) 1998-2000 by DOSDOOM. -;; Copyright (C) 2010-2023 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: -;; tmap_mmx.nas -;; DESCRIPTION: -;; Assembler optimised rendering code for software mode, using SIMD -;; instructions. -;; Draw wall columns. - - -[BITS 32] - -%define FRACBITS 16 -%define TRANSPARENTPIXEL 255 - -%ifdef LINUX -%macro cextern 1 -[extern %1] -%endmacro - -%macro cglobal 1 -[global %1] -%endmacro - -%else -%macro cextern 1 -%define %1 _%1 -[extern %1] -%endmacro - -%macro cglobal 1 -%define %1 _%1 -[global %1] -%endmacro - -%endif - - -; The viddef_s structure. We only need the width field. -struc viddef_s - resb 12 -.width: resb 4 - resb 44 -endstruc - - -;; externs -;; columns -cextern dc_colormap -cextern dc_x -cextern dc_yl -cextern dc_yh -cextern dc_iscale -cextern dc_texturemid -cextern dc_texheight -cextern dc_source -cextern dc_hires -cextern centery -cextern centeryfrac -cextern dc_transmap - -cextern R_DrawColumn_8_ASM -cextern R_Draw2sMultiPatchColumn_8_ASM - -;; spans -cextern nflatshiftup -cextern nflatxshift -cextern nflatyshift -cextern nflatmask -cextern ds_xfrac -cextern ds_yfrac -cextern ds_xstep -cextern ds_ystep -cextern ds_x1 -cextern ds_x2 -cextern ds_y -cextern ds_source -cextern ds_colormap - -cextern ylookup -cextern columnofs -cextern vid - -[SECTION .data] - -nflatmask64 dq 0 - - -[SECTION .text] - -;;---------------------------------------------------------------------- -;; -;; R_DrawColumn : 8bpp column drawer -;; -;; MMX column drawer. -;; -;;---------------------------------------------------------------------- -;; eax = accumulator -;; ebx = colormap -;; ecx = count -;; edx = accumulator -;; esi = source -;; edi = dest -;; ebp = vid.width -;; mm0 = accumulator -;; mm1 = heightmask, twice -;; mm2 = 2 * fracstep, twice -;; mm3 = pair of consecutive fracs -;;---------------------------------------------------------------------- - - -cglobal R_DrawColumn_8_MMX -R_DrawColumn_8_MMX: - push ebp ;; preserve caller's stack frame pointer - push esi ;; preserve register variables - push edi - push ebx - -;; -;; Our algorithm requires that the texture height be a power of two. -;; If not, fall back to the non-MMX drawer. -;; -.texheightcheck: - mov edx, [dc_texheight] - sub edx, 1 ;; edx = heightmask - test edx, [dc_texheight] - jnz near .usenonMMX - - mov ebp, edx ;; Keep a copy of heightmask in a - ;; GPR for the time being. - -;; -;; Fill mm1 with heightmask -;; - movd mm1, edx ;; low dword = heightmask - punpckldq mm1, mm1 ;; copy low dword to high dword - -;; -;; dest = ylookup[dc_yl] + columnofs[dc_x]; -;; - mov eax, [dc_yl] - mov edi, [ylookup+eax*4] - mov ebx, [dc_x] - add edi, [columnofs+ebx*4] ;; edi = dest - - -;; -;; pixelcount = yh - yl + 1 -;; - mov ecx, [dc_yh] - add ecx, 1 - sub ecx, eax ;; pixel count - jle near .done ;; nothing to scale - -;; -;; fracstep = dc_iscale; -;; - movd mm2, [dc_iscale] ;; fracstep in low dword - punpckldq mm2, mm2 ;; copy to high dword - - mov ebx, [dc_colormap] - mov esi, [dc_source] - -;; -;; frac = (dc_texturemid + FixedMul((dc_yl << FRACBITS) - centeryfrac, fracstep)); -;; - ;; eax == dc_yl already - shl eax, FRACBITS - sub eax, [centeryfrac] - imul dword [dc_iscale] - shrd eax, edx, FRACBITS - add eax, [dc_texturemid] - -;; -;; if (dc_hires) frac = 0; -;; - test byte [dc_hires], 0x01 - jz .mod2 - xor eax, eax - - -;; -;; Do mod-2 pixel. -;; -.mod2: - test ecx, 1 - jz .pairprepare - mov edx, eax ;; edx = frac - add eax, [dc_iscale] ;; eax += fracstep - sar edx, FRACBITS - and edx, ebp ;; edx &= heightmask - movzx edx, byte [esi + edx] - movzx edx, byte [ebx + edx] - mov [edi], dl - - add edi, [vid + viddef_s.width] - sub ecx, 1 - jz .done - -.pairprepare: -;; -;; Prepare for the main loop. -;; - movd mm3, eax ;; Low dword = frac - movq mm4, mm3 ;; Copy to intermediate register - paddd mm4, mm2 ;; dwords of mm4 += fracstep - punpckldq mm3, mm4 ;; Low dword = first frac, high = second - pslld mm2, 1 ;; fracstep *= 2 - -;; -;; ebp = vid.width -;; - mov ebp, [vid + viddef_s.width] - - align 16 -.pairloop: - movq mm0, mm3 ;; 3B 1u. - psrad mm0, FRACBITS ;; 4B 1u. - pand mm0, mm1 ;; 3B 1u. frac &= heightmask - paddd mm3, mm2 ;; 3B 1u. frac += fracstep - - movd eax, mm0 ;; 3B 1u. Get first frac -;; IFETCH boundary - movzx eax, byte [esi + eax] ;; 4B 1u. Texture map - movzx eax, byte [ebx + eax] ;; 4B 1u. Colormap - - punpckhdq mm0, mm0 ;; 3B 1(2)u. low dword = high dword - movd edx, mm0 ;; 3B 1u. Get second frac - mov [edi], al ;; 2B 1(2)u. First pixel -;; IFETCH boundary - - movzx edx, byte [esi + edx] ;; 4B 1u. Texture map - movzx edx, byte [ebx + edx] ;; 4B 1u. Colormap - mov [edi + 1*ebp], dl ;; 3B 1(2)u. Second pixel - - lea edi, [edi + 2*ebp] ;; 3B 1u. edi += 2 * vid.width -;; IFETCH boundary - sub ecx, 2 ;; 3B 1u. count -= 2 - jnz .pairloop ;; 2B 1u. if(count != 0) goto .pairloop - - -.done: -;; -;; Clear MMX state, or else FPU operations will go badly awry. -;; - emms - - pop ebx - pop edi - pop esi - pop ebp - ret - -.usenonMMX: - call R_DrawColumn_8_ASM - jmp .done - - -;;---------------------------------------------------------------------- -;; -;; R_Draw2sMultiPatchColumn : Like R_DrawColumn, but omits transparent -;; pixels. -;; -;; MMX column drawer. -;; -;;---------------------------------------------------------------------- -;; eax = accumulator -;; ebx = colormap -;; ecx = count -;; edx = accumulator -;; esi = source -;; edi = dest -;; ebp = vid.width -;; mm0 = accumulator -;; mm1 = heightmask, twice -;; mm2 = 2 * fracstep, twice -;; mm3 = pair of consecutive fracs -;;---------------------------------------------------------------------- - - -cglobal R_Draw2sMultiPatchColumn_8_MMX -R_Draw2sMultiPatchColumn_8_MMX: - push ebp ;; preserve caller's stack frame pointer - push esi ;; preserve register variables - push edi - push ebx - -;; -;; Our algorithm requires that the texture height be a power of two. -;; If not, fall back to the non-MMX drawer. -;; -.texheightcheck: - mov edx, [dc_texheight] - sub edx, 1 ;; edx = heightmask - test edx, [dc_texheight] - jnz near .usenonMMX - - mov ebp, edx ;; Keep a copy of heightmask in a - ;; GPR for the time being. - -;; -;; Fill mm1 with heightmask -;; - movd mm1, edx ;; low dword = heightmask - punpckldq mm1, mm1 ;; copy low dword to high dword - -;; -;; dest = ylookup[dc_yl] + columnofs[dc_x]; -;; - mov eax, [dc_yl] - mov edi, [ylookup+eax*4] - mov ebx, [dc_x] - add edi, [columnofs+ebx*4] ;; edi = dest - - -;; -;; pixelcount = yh - yl + 1 -;; - mov ecx, [dc_yh] - add ecx, 1 - sub ecx, eax ;; pixel count - jle near .done ;; nothing to scale -;; -;; fracstep = dc_iscale; -;; - movd mm2, [dc_iscale] ;; fracstep in low dword - punpckldq mm2, mm2 ;; copy to high dword - - mov ebx, [dc_colormap] - mov esi, [dc_source] - -;; -;; frac = (dc_texturemid + FixedMul((dc_yl << FRACBITS) - centeryfrac, fracstep)); -;; - ;; eax == dc_yl already - shl eax, FRACBITS - sub eax, [centeryfrac] - imul dword [dc_iscale] - shrd eax, edx, FRACBITS - add eax, [dc_texturemid] - -;; -;; if (dc_hires) frac = 0; -;; - test byte [dc_hires], 0x01 - jz .mod2 - xor eax, eax - - -;; -;; Do mod-2 pixel. -;; -.mod2: - test ecx, 1 - jz .pairprepare - mov edx, eax ;; edx = frac - add eax, [dc_iscale] ;; eax += fracstep - sar edx, FRACBITS - and edx, ebp ;; edx &= heightmask - movzx edx, byte [esi + edx] - cmp dl, TRANSPARENTPIXEL - je .nextmod2 - movzx edx, byte [ebx + edx] - mov [edi], dl - -.nextmod2: - add edi, [vid + viddef_s.width] - sub ecx, 1 - jz .done - -.pairprepare: -;; -;; Prepare for the main loop. -;; - movd mm3, eax ;; Low dword = frac - movq mm4, mm3 ;; Copy to intermediate register - paddd mm4, mm2 ;; dwords of mm4 += fracstep - punpckldq mm3, mm4 ;; Low dword = first frac, high = second - pslld mm2, 1 ;; fracstep *= 2 - -;; -;; ebp = vid.width -;; - mov ebp, [vid + viddef_s.width] - - align 16 -.pairloop: - movq mm0, mm3 ;; 3B 1u. - psrad mm0, FRACBITS ;; 4B 1u. - pand mm0, mm1 ;; 3B 1u. frac &= heightmask - paddd mm3, mm2 ;; 3B 1u. frac += fracstep - - movd eax, mm0 ;; 3B 1u. Get first frac -;; IFETCH boundary - movzx eax, byte [esi + eax] ;; 4B 1u. Texture map - punpckhdq mm0, mm0 ;; 3B 1(2)u. low dword = high dword - movd edx, mm0 ;; 3B 1u. Get second frac - cmp al, TRANSPARENTPIXEL ;; 2B 1u. - je .secondinpair ;; 2B 1u. -;; IFETCH boundary - movzx eax, byte [ebx + eax] ;; 4B 1u. Colormap - mov [edi], al ;; 2B 1(2)u. First pixel - -.secondinpair: - movzx edx, byte [esi + edx] ;; 4B 1u. Texture map - cmp dl, TRANSPARENTPIXEL ;; 2B 1u. - je .nextpair ;; 2B 1u. -;; IFETCH boundary - movzx edx, byte [ebx + edx] ;; 4B 1u. Colormap - mov [edi + 1*ebp], dl ;; 3B 1(2)u. Second pixel - -.nextpair: - lea edi, [edi + 2*ebp] ;; 3B 1u. edi += 2 * vid.width - sub ecx, 2 ;; 3B 1u. count -= 2 - jnz .pairloop ;; 2B 1u. if(count != 0) goto .pairloop - - -.done: -;; -;; Clear MMX state, or else FPU operations will go badly awry. -;; - emms - - pop ebx - pop edi - pop esi - pop ebp - ret - -.usenonMMX: - call R_Draw2sMultiPatchColumn_8_ASM - jmp .done - - -;;---------------------------------------------------------------------- -;; -;; R_DrawSpan : 8bpp span drawer -;; -;; MMX span drawer. -;; -;;---------------------------------------------------------------------- -;; eax = accumulator -;; ebx = colormap -;; ecx = count -;; edx = accumulator -;; esi = source -;; edi = dest -;; ebp = two pixels -;; mm0 = accumulator -;; mm1 = xposition -;; mm2 = yposition -;; mm3 = 2 * xstep -;; mm4 = 2 * ystep -;; mm5 = nflatxshift -;; mm6 = nflatyshift -;; mm7 = accumulator -;;---------------------------------------------------------------------- - -cglobal R_DrawSpan_8_MMX -R_DrawSpan_8_MMX: - push ebp ;; preserve caller's stack frame pointer - push esi ;; preserve register variables - push edi - push ebx - -;; -;; esi = ds_source -;; ebx = ds_colormap -;; - mov esi, [ds_source] - mov ebx, [ds_colormap] - -;; -;; edi = ylookup[ds_y] + columnofs[ds_x1] -;; - mov eax, [ds_y] - mov edi, [ylookup + eax*4] - mov edx, [ds_x1] - add edi, [columnofs + edx*4] - -;; -;; ecx = ds_x2 - ds_x1 + 1 -;; - mov ecx, [ds_x2] - sub ecx, edx - add ecx, 1 - -;; -;; Needed for fracs and steps -;; - movd mm7, [nflatshiftup] - -;; -;; mm3 = xstep -;; - movd mm3, [ds_xstep] - pslld mm3, mm7 - punpckldq mm3, mm3 - -;; -;; mm4 = ystep -;; - movd mm4, [ds_ystep] - pslld mm4, mm7 - punpckldq mm4, mm4 - -;; -;; mm1 = pair of consecutive xpositions -;; - movd mm1, [ds_xfrac] - pslld mm1, mm7 - movq mm6, mm1 - paddd mm6, mm3 - punpckldq mm1, mm6 - -;; -;; mm2 = pair of consecutive ypositions -;; - movd mm2, [ds_yfrac] - pslld mm2, mm7 - movq mm6, mm2 - paddd mm6, mm4 - punpckldq mm2, mm6 - -;; -;; mm5 = nflatxshift -;; mm6 = nflatyshift -;; - movd mm5, [nflatxshift] - movd mm6, [nflatyshift] - -;; -;; Mask is in memory due to lack of registers. -;; - mov eax, [nflatmask] - mov [nflatmask64], eax - mov [nflatmask64 + 4], eax - - -;; -;; Go until we reach a dword boundary. -;; -.unaligned: - test edi, 3 - jz .alignedprep -.stragglers: - cmp ecx, 0 - je .done ;; If ecx == 0, we're finished. - -;; -;; eax = ((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift) -;; - movq mm0, mm1 ;; mm0 = xposition - movq mm7, mm2 ;; mm7 = yposition - paddd mm1, mm3 ;; xposition += xstep (once!) - paddd mm2, mm4 ;; yposition += ystep (once!) - psrld mm0, mm5 ;; shift - psrld mm7, mm6 ;; shift - pand mm7, [nflatmask64] ;; mask - por mm0, mm7 ;; or x and y together - - movd eax, mm0 ;; eax = index of first pixel - movzx eax, byte [esi + eax] ;; al = source[eax] - movzx eax, byte [ebx + eax] ;; al = colormap[al] - - mov [edi], al - add edi, 1 - - sub ecx, 1 - jmp .unaligned - - -.alignedprep: -;; -;; We can double the steps now. -;; - pslld mm3, 1 - pslld mm4, 1 - - -;; -;; Generate chunks of four pixels. -;; -.alignedloop: - -;; -;; Make sure we have at least four pixels. -;; - cmp ecx, 4 - jl .prestragglers - -;; -;; First two pixels. -;; - movq mm0, mm1 ;; mm0 = xposition - movq mm7, mm2 ;; mm7 = yposition - paddd mm1, mm3 ;; xposition += xstep - paddd mm2, mm4 ;; yposition += ystep - psrld mm0, mm5 ;; shift - psrld mm7, mm6 ;; shift - pand mm7, [nflatmask64] ;; mask - por mm0, mm7 ;; or x and y together - - movd eax, mm0 ;; eax = index of first pixel - movzx eax, byte [esi + eax] ;; al = source[eax] - movzx ebp, byte [ebx + eax] ;; ebp = colormap[al] - - punpckhdq mm0, mm0 ;; both dwords = high dword - movd eax, mm0 ;; eax = index of second pixel - movzx eax, byte [esi + eax] ;; al = source[eax] - movzx eax, byte [ebx + eax] ;; al = colormap[al] - shl eax, 8 ;; get pixel in right byte - or ebp, eax ;; put pixel in ebp - -;; -;; Next two pixels. -;; - movq mm0, mm1 ;; mm0 = xposition - movq mm7, mm2 ;; mm7 = yposition - paddd mm1, mm3 ;; xposition += xstep - paddd mm2, mm4 ;; yposition += ystep - psrld mm0, mm5 ;; shift - psrld mm7, mm6 ;; shift - pand mm7, [nflatmask64] ;; mask - por mm0, mm7 ;; or x and y together - - movd eax, mm0 ;; eax = index of third pixel - movzx eax, byte [esi + eax] ;; al = source[eax] - movzx eax, byte [ebx + eax] ;; al = colormap[al] - shl eax, 16 ;; get pixel in right byte - or ebp, eax ;; put pixel in ebp - - punpckhdq mm0, mm0 ;; both dwords = high dword - movd eax, mm0 ;; eax = index of second pixel - movzx eax, byte [esi + eax] ;; al = source[eax] - movzx eax, byte [ebx + eax] ;; al = colormap[al] - shl eax, 24 ;; get pixel in right byte - or ebp, eax ;; put pixel in ebp - -;; -;; Write pixels. -;; - mov [edi], ebp - add edi, 4 - - sub ecx, 4 - jmp .alignedloop - -.prestragglers: -;; -;; Back to one step at a time. -;; - psrad mm3, 1 - psrad mm4, 1 - jmp .stragglers - -.done: -;; -;; Clear MMX state, or else FPU operations will go badly awry. -;; - emms - - pop ebx - pop edi - pop esi - pop ebp - ret diff --git a/src/tmap_vc.nas b/src/tmap_vc.nas deleted file mode 100644 index c85cf70035f8588387420d479725242bb708cc42..0000000000000000000000000000000000000000 --- a/src/tmap_vc.nas +++ /dev/null @@ -1,48 +0,0 @@ -;; SONIC ROBO BLAST 2 -;;----------------------------------------------------------------------------- -;; Copyright (C) 1998-2000 by DooM Legacy Team. -;; Copyright (C) 1999-2023 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: -;; tmap_vc.nas -;; DESCRIPTION: -;; Assembler optimised math code for Visual C++. - - -[BITS 32] - -%macro cglobal 1 -%define %1 _%1 -[global %1] -%endmacro - -[SECTION .text write] - -;---------------------------------------------------------------------------- -;fixed_t FixedMul (fixed_t a, fixed_t b) -;---------------------------------------------------------------------------- -cglobal FixedMul -; align 16 -FixedMul: - mov eax,[esp+4] - imul dword [esp+8] - shrd eax,edx,16 - ret - -;---------------------------------------------------------------------------- -;fixed_t FixedDiv2 (fixed_t a, fixed_t b); -;---------------------------------------------------------------------------- -cglobal FixedDiv2 -; align 16 -FixedDiv2: - mov eax,[esp+4] - mov edx,eax ;; these two instructions allow the next - sar edx,31 ;; two to pair, on the Pentium processor. - shld edx,eax,16 - sal eax,16 - idiv dword [esp+8] - ret diff --git a/src/hardware/u_list.c b/src/u_list.c similarity index 99% rename from src/hardware/u_list.c rename to src/u_list.c index dc49a74e7f7ab1a0502fbf5fb5f13cbbad888275..d5cfd5717ac2786e846abaf61c1dd91e2de184fe 100644 --- a/src/hardware/u_list.c +++ b/src/u_list.c @@ -8,7 +8,7 @@ */ #include "u_list.h" -#include "../z_zone.h" +#include "z_zone.h" // Utility for managing // structures in a linked diff --git a/src/hardware/u_list.h b/src/u_list.h similarity index 100% rename from src/hardware/u_list.h rename to src/u_list.h diff --git a/src/v_video.c b/src/v_video.c index 461a5e3bc7671684f5fdcc62a8c1a728ea913a55..3f958b286cdfdcc275a23c5822605812d218c242 100644 --- a/src/v_video.c +++ b/src/v_video.c @@ -447,12 +447,6 @@ static void CV_palette_OnChange(void) V_SetPalette(0); } -#if defined (__GNUC__) && defined (__i386__) && !defined (NOASM) && !defined (__APPLE__) && !defined (NORUSEASM) -void VID_BlitLinearScreen_ASM(const UINT8 *srcptr, UINT8 *destptr, INT32 width, INT32 height, size_t srcrowbytes, - size_t destrowbytes); -#define HAVE_VIDCOPY -#endif - static void CV_constextsize_OnChange(void) { if (!con_refresh) @@ -466,9 +460,6 @@ static void CV_constextsize_OnChange(void) void VID_BlitLinearScreen(const UINT8 *srcptr, UINT8 *destptr, INT32 width, INT32 height, size_t srcrowbytes, size_t destrowbytes) { -#ifdef HAVE_VIDCOPY - VID_BlitLinearScreen_ASM(srcptr,destptr,width,height,srcrowbytes,destrowbytes); -#else if (srcrowbytes == destrowbytes) M_Memcpy(destptr, srcptr, srcrowbytes * height); else @@ -481,7 +472,6 @@ void VID_BlitLinearScreen(const UINT8 *srcptr, UINT8 *destptr, INT32 width, INT3 srcptr += srcrowbytes; } } -#endif } static UINT8 hudplusalpha[11] = { 10, 8, 6, 4, 2, 0, 0, 0, 0, 0, 0}; diff --git a/src/version.h b/src/version.h index 083c531343cf0dd0628133110d338374fde71231..3242cad672df6757e74741ca482a403f7544e31b 100644 --- a/src/version.h +++ b/src/version.h @@ -1,4 +1,4 @@ -#define SRB2VERSION "2.2.11"/* this must be the first line, for cmake !! */ +#define SRB2VERSION "2.2.13"/* this must be the first line, for cmake !! */ // The Modification ID; must be obtained from a Master Server Admin ( https://mb.srb2.org/members/?key=ms_admin ). // DO NOT try to set this otherwise, or your modification will be unplayable through the Master Server. @@ -9,7 +9,7 @@ // it's only for detection of the version the player is using so the MS can alert them of an update. // Only set it higher, not lower, obviously. // Note that we use this to help keep internal testing in check; this is why v2.2.0 is not version "1". -#define MODVERSION 52 +#define MODVERSION 54 // Define this as a prerelease version suffix (pre#, RC#) //#define BETAVERSION "pre1" diff --git a/src/vid_copy.s b/src/vid_copy.s deleted file mode 100644 index 1473a3856f192145e3739738de85bd4f6cb96222..0000000000000000000000000000000000000000 --- a/src/vid_copy.s +++ /dev/null @@ -1,61 +0,0 @@ -// SONIC ROBO BLAST 2 -//----------------------------------------------------------------------------- -// Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2023 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 vid_copy.s -/// \brief code for updating the linear frame buffer screen. - -#include "asm_defs.inc" // structures, must match the C structures! - -// DJGPPv2 is as fast as this one, but then someone may compile with a less -// good version of DJGPP than mine, so this little asm will do the trick! - -#define srcptr 4+16 -#define destptr 8+16 -#define width 12+16 -#define height 16+16 -#define srcrowbytes 20+16 -#define destrowbytes 24+16 - -// VID_BlitLinearScreen( src, dest, width, height, srcwidth, destwidth ); -// width is given as BYTES - -#ifdef __i386__ - -.globl C(VID_BlitLinearScreen_ASM) -C(VID_BlitLinearScreen_ASM): - pushl %ebp // preserve caller's stack frame - pushl %edi - pushl %esi // preserve register variables - pushl %ebx - - cld - movl srcptr(%esp),%esi - movl destptr(%esp),%edi - movl width(%esp),%ebx - movl srcrowbytes(%esp),%eax - subl %ebx,%eax - movl destrowbytes(%esp),%edx - subl %ebx,%edx - shrl $2,%ebx - movl height(%esp),%ebp -LLRowLoop: - movl %ebx,%ecx - rep/movsl (%esi),(%edi) - addl %eax,%esi - addl %edx,%edi - decl %ebp - jnz LLRowLoop - - popl %ebx // restore register variables - popl %esi - popl %edi - popl %ebp // restore the caller's stack frame - - ret -#endif diff --git a/src/w_wad.c b/src/w_wad.c index 456afef7b9edd18fe26d188dd4326ea8469f2007..c8880f6934f0f04bbe892da599e90f487339b242 100644 --- a/src/w_wad.c +++ b/src/w_wad.c @@ -201,7 +201,7 @@ FILE *W_OpenWadFile(const char **filename, boolean useerrors) } // Look for all DEHACKED and Lua scripts inside a PK3 archive. -static inline void W_LoadDehackedLumpsPK3(UINT16 wadnum, boolean mainfile) +static void W_LoadDehackedLumpsPK3(UINT16 wadnum, boolean mainfile) { UINT16 posStart, posEnd; @@ -241,7 +241,7 @@ static inline void W_LoadDehackedLumpsPK3(UINT16 wadnum, boolean mainfile) } // search for all DEHACKED lump in all wads and load it -static inline void W_LoadDehackedLumps(UINT16 wadnum, boolean mainfile) +static void W_LoadDehackedLumps(UINT16 wadnum, boolean mainfile) { UINT16 lump; @@ -305,7 +305,7 @@ static inline void W_LoadDehackedLumps(UINT16 wadnum, boolean mainfile) * \param resblock resulting MD5 checksum * \return 0 if MD5 checksum was made, and is at resblock, 1 if error was found */ -static inline INT32 W_MakeFileMD5(const char *filename, void *resblock) +static INT32 W_MakeFileMD5(const char *filename, void *resblock) { #ifdef NOMD5 (void)filename; @@ -972,7 +972,7 @@ UINT16 W_InitFile(const char *filename, boolean mainfile, boolean startup) // add the wadfile // CONS_Printf(M_GetText("Added file %s (%u lumps)\n"), filename, numlumps); - wadfiles = Z_Realloc(wadfiles, sizeof(wadfile_t) * (numwadfiles + 1), PU_STATIC, NULL); + wadfiles = Z_Realloc(wadfiles, sizeof(wadfile_t *) * (numwadfiles + 1), PU_STATIC, NULL); wadfiles[numwadfiles] = wadfile; numwadfiles++; // must come BEFORE W_LoadDehackedLumps, so any addfile called by COM_BufInsertText called by Lua doesn't overwrite what we just loaded @@ -1150,6 +1150,7 @@ UINT16 W_InitFolder(const char *path, boolean mainfile, boolean startup) Z_Calloc(numlumps * sizeof (*wadfile->patchcache), PU_STATIC, &wadfile->patchcache); CONS_Printf(M_GetText("Added folder %s (%u files, %u folders)\n"), fn, numlumps, foldercount); + wadfiles = Z_Realloc(wadfiles, sizeof(wadfile_t *) * (numwadfiles + 1), PU_STATIC, NULL); wadfiles[numwadfiles] = wadfile; numwadfiles++; @@ -1956,7 +1957,7 @@ void *W_CacheLumpNumForce(lumpnum_t lumpnum, INT32 tag) // return false. // // no outside code uses the PWAD form, for now -static inline boolean W_IsLumpCachedPWAD(UINT16 wad, UINT16 lump, void *ptr) +static boolean W_IsLumpCachedPWAD(UINT16 wad, UINT16 lump, void *ptr) { void *lcache; @@ -1988,7 +1989,7 @@ boolean W_IsLumpCached(lumpnum_t lumpnum, void *ptr) // return false. // // no outside code uses the PWAD form, for now -static inline boolean W_IsPatchCachedPWAD(UINT16 wad, UINT16 lump, void *ptr) +static boolean W_IsPatchCachedPWAD(UINT16 wad, UINT16 lump, void *ptr) { void *lcache; diff --git a/src/win32/Srb2win.rc b/src/win32/Srb2win.rc index 869c0e7d36e24a86f299d6013ec933c69a92ec4b..b699007463ad3f37527367b40e4a1c29411012ab 100644 --- a/src/win32/Srb2win.rc +++ b/src/win32/Srb2win.rc @@ -77,8 +77,8 @@ END #include "../doomdef.h" // Needed for version string VS_VERSION_INFO VERSIONINFO - FILEVERSION 2,2,11,0 - PRODUCTVERSION 2,2,11,0 + FILEVERSION 2,2,13,0 + PRODUCTVERSION 2,2,13,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L diff --git a/src/y_inter.c b/src/y_inter.c index 6e7d362a779d9f8bcfb43d7999aacaf433cb2ee1..8bec2b30f4e9314eb529defe4578daac5d0b697b 100644 --- a/src/y_inter.c +++ b/src/y_inter.c @@ -998,8 +998,7 @@ void Y_Ticker(void) if (paused || P_AutoPause()) return; - LUA_HookBool(intertype == int_spec && stagefailed, - HOOK(IntermissionThinker)); + LUA_HookBool(stagefailed, HOOK(IntermissionThinker)); intertic++; @@ -1477,10 +1476,10 @@ void Y_StartIntermission(void) if (players[consoleplayer].charflags & SF_SUPER) { strcpy(data.spec.passed3, "can now become"); - snprintf(data.spec.passed4, - sizeof data.spec.passed4, "Super %s", - skins[players[consoleplayer].skin].realname); - data.spec.passed4[sizeof data.spec.passed4 - 1] = '\0'; + if (strlen(skins[players[consoleplayer].skin].supername) > 20) //too long, use generic + strcpy(data.spec.passed4, "their super form"); + else + strcpy(data.spec.passed4, skins[players[consoleplayer].skin].supername); } } else @@ -2044,7 +2043,7 @@ static void Y_AwardCoopBonuses(void) y_bonus_t localbonuses[4]; // set score/total first - data.coop.total = 0; + data.coop.total = players[consoleplayer].recordscore; data.coop.score = players[consoleplayer].score; data.coop.gotperfbonus = -1; memset(data.coop.bonuses, 0, sizeof(data.coop.bonuses)); @@ -2065,6 +2064,9 @@ static void Y_AwardCoopBonuses(void) players[i].score += localbonuses[j].points; if (players[i].score > MAXSCORE) players[i].score = MAXSCORE; + players[i].recordscore += localbonuses[j].points; + if (players[i].recordscore > MAXSCORE) + players[i].recordscore = MAXSCORE; } ptlives = min( @@ -2121,6 +2123,10 @@ static void Y_AwardSpecialStageBonus(void) players[i].score += localbonuses[1].points; if (players[i].score > MAXSCORE) players[i].score = MAXSCORE; + players[i].recordscore += localbonuses[0].points; + players[i].recordscore += localbonuses[1].points; + if (players[i].recordscore > MAXSCORE) + players[i].recordscore = MAXSCORE; // grant extra lives right away since tally is faked ptlives = min( diff --git a/src/z_zone.c b/src/z_zone.c index 11c4bcb2c789f6d58715ace2a59198ce4d83c98b..5750f8ae016becd9c9548b690b0e7fd5b32ec7cb 100644 --- a/src/z_zone.c +++ b/src/z_zone.c @@ -51,27 +51,11 @@ static boolean Z_calloc = false; //#define ZDEBUG2 #endif -struct memblock_s; - -typedef struct -{ - struct memblock_s *block; // Describing this memory - UINT32 id; // Should be ZONEID -} ATTRPACK memhdr_t; - -// Some code might want aligned memory. Assume it wants memory n bytes -// aligned -- then we allocate n-1 extra bytes and return a pointer to -// the first byte aligned as requested. -// Thus, "real" is the pointer we get from malloc() and will free() -// later, but "hdr" is where the memhdr_t starts. -// For non-aligned allocations they will be the same. typedef struct memblock_s { - void *real; - memhdr_t *hdr; - void **user; INT32 tag; // purgelevel + UINT32 id; // Should be ZONEID size_t size; // including the header and blocks size_t realsize; // size of real data only @@ -82,7 +66,10 @@ typedef struct memblock_s #endif struct memblock_s *next, *prev; -} ATTRPACK memblock_t; +} memblock_t; + +#define MEMORY(x) (void *)((uintptr_t)(x) + sizeof(memblock_t)) +#define MEMBLOCK(x) (memblock_t *)((uintptr_t)(x) - sizeof(memblock_t)) // both the head and tail of the zone memory block list static memblock_t head; @@ -128,64 +115,6 @@ void Z_Init(void) // Zone memory allocation // ---------------------- -/** Returns the corresponding memblock_t for a given memory block. - * - * \param ptr A pointer to allocated memory, - * assumed to have been allocated with Z_Malloc/Z_Calloc. - * \param func A string containing the name of the function that called this, - * to be printed if the function I_Errors - * \return A pointer to the memblock_t for the given memory. - * \sa Z_Free, Z_ReallocAlign - */ -#ifdef ZDEBUG -#define Ptr2Memblock(s, f) Ptr2Memblock2(s, f, __FILE__, __LINE__) -static memblock_t *Ptr2Memblock2(void *ptr, const char* func, const char *file, INT32 line) -#else -static memblock_t *Ptr2Memblock(void *ptr, const char* func) -#endif -{ - memhdr_t *hdr; - memblock_t *block; - - if (ptr == NULL) - return NULL; - -#ifdef ZDEBUG2 - CONS_Printf("%s %s:%d\n", func, file, line); -#endif - - hdr = (memhdr_t *)((UINT8 *)ptr - sizeof *hdr); - -#ifdef VALGRIND_MAKE_MEM_DEFINED - VALGRIND_MAKE_MEM_DEFINED(hdr, sizeof *hdr); -#endif - -#ifdef VALGRIND_MEMPOOL_EXISTS - if (!VALGRIND_MEMPOOL_EXISTS(hdr->block)) - { -#ifdef ZDEBUG - I_Error("%s: bad memblock from %s:%d", func, file, line); -#else - I_Error("%s: bad memblock", func); -#endif - } -#endif - if (hdr->id != ZONEID) - { -#ifdef ZDEBUG - I_Error("%s: wrong id from %s:%d", func, file, line); -#else - I_Error("%s: wrong id", func); -#endif - } - block = hdr->block; -#ifdef VALGRIND_MAKE_MEM_NOACCESS - VALGRIND_MAKE_MEM_NOACCESS(hdr, sizeof *hdr); -#endif - return block; - -} - /** Frees allocated memory. * * \param ptr A pointer to allocated memory, @@ -207,10 +136,14 @@ void Z_Free(void *ptr) CONS_Debug(DBG_MEMORY, "Z_Free %s:%d\n", file, line); #endif + block = MEMBLOCK(ptr); +#ifdef PARANOIA + if (block->id != ZONEID) #ifdef ZDEBUG - block = Ptr2Memblock2(ptr, "Z_Free", file, line); + I_Error("Z_Free at %s:%d: wrong id", file, line); #else - block = Ptr2Memblock(ptr, "Z_Free"); + I_Error("Z_Free: wrong id"); +#endif #endif #ifdef ZDEBUG @@ -229,8 +162,6 @@ void Z_Free(void *ptr) if (block->user != NULL) *block->user = NULL; - // Free the memory and get rid of the block. - free(block->real); #ifdef VALGRIND_DESTROY_MEMPOOL VALGRIND_DESTROY_MEMPOOL(block); #endif @@ -287,34 +218,17 @@ void *Z_Malloc2(size_t size, INT32 tag, void *user, INT32 alignbits, void *Z_MallocAlign(size_t size, INT32 tag, void *user, INT32 alignbits) #endif { - size_t extrabytes = (1<<alignbits) - 1; - size_t padsize = 0; memblock_t *block; void *ptr; - memhdr_t *hdr; - void *given; - size_t blocksize = extrabytes + sizeof *hdr + size; + (void)(alignbits); // no longer used, so silence warnings. #ifdef ZDEBUG2 CONS_Debug(DBG_MEMORY, "Z_Malloc %s:%d\n", file, line); #endif - if (blocksize < size)/* overflow check */ - I_Error("You are allocating memory too large!"); - - block = xm(sizeof *block); -#ifdef HAVE_VALGRIND - padsize += (1<<sizeof(size_t))*2; -#endif - ptr = xm(blocksize + padsize*2); - - // This horrible calculation makes sure that "given" is aligned - // properly. - given = (void *)((size_t)((UINT8 *)ptr + extrabytes + sizeof *hdr + padsize/2) - & ~extrabytes); - - // The mem header lives 'sizeof (memhdr_t)' bytes before given. - hdr = (memhdr_t *)((UINT8 *)given - sizeof *hdr); + block = xm(sizeof (memblock_t) + size); + ptr = MEMORY(block); + I_Assert((intptr_t)ptr % sizeof (void *) == 0); #ifdef HAVE_VALGRIND Z_calloc = false; @@ -325,41 +239,31 @@ void *Z_MallocAlign(size_t size, INT32 tag, void *user, INT32 alignbits) head.next = block; block->next->prev = block; - block->real = ptr; - block->hdr = hdr; block->tag = tag; block->user = NULL; #ifdef ZDEBUG block->ownerline = line; block->ownerfile = file; #endif - block->size = blocksize; + block->size = sizeof (memblock_t) + size; block->realsize = size; #ifdef VALGRIND_CREATE_MEMPOOL - VALGRIND_CREATE_MEMPOOL(block, padsize, Z_calloc); + VALGRIND_CREATE_MEMPOOL(block, size, Z_calloc); #endif -//#ifdef VALGRIND_MEMPOOL_ALLOC -// VALGRIND_MEMPOOL_ALLOC(block, hdr, size + sizeof *hdr); -//#endif - hdr->id = ZONEID; - hdr->block = block; - -#ifdef VALGRIND_MAKE_MEM_NOACCESS - VALGRIND_MAKE_MEM_NOACCESS(hdr, sizeof *hdr); -#endif + block->id = ZONEID; if (user != NULL) { block->user = user; - *(void **)user = given; + *(void **)user = ptr; } else if (tag >= PU_PURGELEVEL) I_Error("Z_Malloc: attempted to allocate purgable block " "(size %s) with no user", sizeu1(size)); - return given; + return ptr; } /** The Z_CallocAlign function. @@ -436,10 +340,14 @@ void *Z_ReallocAlign(void *ptr, size_t size, INT32 tag, void *user, INT32 alignb #endif } + block = MEMBLOCK(ptr); +#ifdef PARANOIA + if (block->id != ZONEID) #ifdef ZDEBUG - block = Ptr2Memblock2(ptr, "Z_Realloc", file, line); + I_Error("Z_ReallocAlign at %s:%d: wrong id", file, line); #else - block = Ptr2Memblock(ptr, "Z_Realloc"); + I_Error("Z_ReallocAlign: wrong id"); +#endif #endif if (block == NULL) @@ -490,9 +398,8 @@ void Z_FreeTags(INT32 lowtag, INT32 hightag) for (block = head.next; block != &head; block = next) { next = block->next; // get link before freeing - if (block->tag >= lowtag && block->tag <= hightag) - Z_Free((UINT8 *)block->hdr + sizeof *block->hdr); + Z_Free(MEMORY(block)); } } @@ -515,7 +422,7 @@ void Z_IterateTags(INT32 lowtag, INT32 hightag, boolean (*iterfunc)(void *)) if (block->tag >= lowtag && block->tag <= hightag) { - void *mem = (UINT8 *)block->hdr + sizeof *block->hdr; + void *mem = MEMORY(block); boolean free = iterfunc(mem); if (free) Z_Free(mem); @@ -560,15 +467,13 @@ void Z_CheckMemCleanup(void) void Z_CheckHeap(INT32 i) { memblock_t *block; - memhdr_t *hdr; UINT32 blocknumon = 0; void *given; for (block = head.next; block != &head; block = block->next) { blocknumon++; - hdr = block->hdr; - given = (UINT8 *)hdr + sizeof *hdr; + given = MEMORY(block); #ifdef ZDEBUG2 CONS_Debug(DBG_MEMORY, "block %u owned by %s:%d\n", blocknumon, block->ownerfile, block->ownerline); @@ -584,7 +489,7 @@ void Z_CheckHeap(INT32 i) #ifdef ZDEBUG , block->ownerfile, block->ownerline #endif - ); + ); } #endif if (block->user != NULL && *(block->user) != given) @@ -597,7 +502,7 @@ void Z_CheckHeap(INT32 i) #ifdef ZDEBUG , block->ownerfile, block->ownerline #endif - ); + ); } if (block->next->prev != block) { @@ -609,7 +514,7 @@ void Z_CheckHeap(INT32 i) #ifdef ZDEBUG , block->ownerfile, block->ownerline #endif - ); + ); } if (block->prev->next != block) { @@ -621,25 +526,9 @@ void Z_CheckHeap(INT32 i) #ifdef ZDEBUG , block->ownerfile, block->ownerline #endif - ); + ); } -#ifdef VALGRIND_MAKE_MEM_DEFINED - VALGRIND_MAKE_MEM_DEFINED(hdr, sizeof *hdr); -#endif - if (hdr->block != block) - { - I_Error("Z_CheckHeap %d: block %u" -#ifdef ZDEBUG - "(owned by %s:%d)" -#endif - " doesn't have linkback from allocated memory", - i, blocknumon -#ifdef ZDEBUG - , block->ownerfile, block->ownerline -#endif - ); - } - if (hdr->id != ZONEID) + if (block->id != ZONEID) { I_Error("Z_CheckHeap %d: block %u" #ifdef ZDEBUG @@ -649,11 +538,8 @@ void Z_CheckHeap(INT32 i) #ifdef ZDEBUG , block->ownerfile, block->ownerline #endif - ); + ); } -#ifdef VALGRIND_MAKE_MEM_NOACCESS - VALGRIND_MAKE_MEM_NOACCESS(hdr, sizeof *hdr); -#endif } } @@ -675,35 +561,14 @@ void Z_ChangeTag(void *ptr, INT32 tag) #endif { memblock_t *block; - memhdr_t *hdr; if (ptr == NULL) return; - hdr = (memhdr_t *)((UINT8 *)ptr - sizeof *hdr); - -#ifdef VALGRIND_MAKE_MEM_DEFINED - VALGRIND_MAKE_MEM_DEFINED(hdr, sizeof *hdr); -#endif + block = MEMBLOCK(ptr); -#ifdef VALGRIND_MEMPOOL_EXISTS - if (!VALGRIND_MEMPOOL_EXISTS(hdr->block)) - { -#ifdef PARANOIA - I_Error("Z_CT at %s:%d: bad memblock", file, line); -#else - I_Error("Z_CT: bad memblock"); -#endif - } -#endif #ifdef PARANOIA - if (hdr->id != ZONEID) I_Error("Z_CT at %s:%d: wrong id", file, line); -#endif - - block = hdr->block; - -#ifdef VALGRIND_MAKE_MEM_NOACCESS - VALGRIND_MAKE_MEM_NOACCESS(hdr, sizeof *hdr); + if (block->id != ZONEID) I_Error("Z_ChangeTag at %s:%d: wrong id", file, line); #endif if (tag >= PU_PURGELEVEL && block->user == NULL) @@ -727,25 +592,14 @@ void Z_SetUser(void *ptr, void **newuser) #endif { memblock_t *block; - memhdr_t *hdr; if (ptr == NULL) return; - hdr = (memhdr_t *)((UINT8 *)ptr - sizeof *hdr); - -#ifdef VALGRIND_MAKE_MEM_DEFINED - VALGRIND_MAKE_MEM_DEFINED(hdr, sizeof *hdr); -#endif + block = MEMBLOCK(ptr); #ifdef PARANOIA - if (hdr->id != ZONEID) I_Error("Z_CT at %s:%d: wrong id", file, line); -#endif - - block = hdr->block; - -#ifdef VALGRIND_MAKE_MEM_NOACCESS - VALGRIND_MAKE_MEM_NOACCESS(hdr, sizeof *hdr); + if (block->id != ZONEID) I_Error("Z_SetUser at %s:%d: wrong id", file, line); #endif if (block->tag >= PU_PURGELEVEL && newuser == NULL) diff --git a/src/z_zone.h b/src/z_zone.h index c3cd4f01157b3871c6727c2a223a97d49a34bfdd..ce7af4a159555e3a6c2be83e8d0eadcf8a7a69eb 100644 --- a/src/z_zone.h +++ b/src/z_zone.h @@ -15,6 +15,7 @@ #define __Z_ZONE__ #include <stdio.h> +#include "doomdef.h" #include "doomtype.h" #ifdef __GNUC__ // __attribute__ ((X)) @@ -101,10 +102,10 @@ void *Z_CallocAlign(size_t size, INT32 tag, void *user, INT32 alignbits) FUNCALL void *Z_ReallocAlign(void *ptr, size_t size, INT32 tag, void *user, INT32 alignbits) FUNCALLOC(2); #endif -// Alloc with no alignment -#define Z_Malloc(s,t,u) Z_MallocAlign(s, t, u, 0) -#define Z_Calloc(s,t,u) Z_CallocAlign(s, t, u, 0) -#define Z_Realloc(p,s,t,u) Z_ReallocAlign(p, s, t, u, 0) +// Alloc with standard alignment +#define Z_Malloc(s,t,u) Z_MallocAlign(s, t, u, sizeof(void *)) +#define Z_Calloc(s,t,u) Z_CallocAlign(s, t, u, sizeof(void *)) +#define Z_Realloc(p,s,t,u) Z_ReallocAlign(p, s, t, u, sizeof(void *)) // Free all memory by tag // these don't give line numbers for ZDEBUG currently though diff --git a/thirdparty/CMakeLists.txt b/thirdparty/CMakeLists.txt index 7aff16601efd49d71693a137a4aab7b98721e7fa..f33b3bf3f836b86b98fda8e78f73ec5be19758d8 100644 --- a/thirdparty/CMakeLists.txt +++ b/thirdparty/CMakeLists.txt @@ -9,521 +9,13 @@ else() set(NOT_SRB2_CONFIG_SHARED_INTERNAL_LIBRARIES ON) endif() - -if(NOT "${SRB2_CONFIG_SYSTEM_LIBRARIES}") - CPMAddPackage( - NAME SDL2 - VERSION 2.24.2 - URL "https://github.com/libsdl-org/SDL/archive/refs/tags/release-2.24.2.zip" - EXCLUDE_FROM_ALL ON - OPTIONS - "BUILD_SHARED_LIBS ${SRB2_CONFIG_SHARED_INTERNAL_LIBRARIES}" - "SDL_SHARED ${SRB2_CONFIG_SHARED_INTERNAL_LIBRARIES}" - "SDL_STATIC ${NOT_SRB2_CONFIG_SHARED_INTERNAL_LIBRARIES}" - "SDL_TEST OFF" - "SDL2_DISABLE_SDL2MAIN ON" - "SDL2_DISABLE_INSTALL ON" - ) -endif() - -if(NOT "${SRB2_CONFIG_SYSTEM_LIBRARIES}") - CPMAddPackage( - NAME SDL2_mixer - VERSION 2.6.2 - URL "https://github.com/libsdl-org/SDL_mixer/archive/refs/tags/release-2.6.2.zip" - EXCLUDE_FROM_ALL ON - OPTIONS - "BUILD_SHARED_LIBS ${SRB2_CONFIG_SHARED_INTERNAL_LIBRARIES}" - "SDL2MIXER_INSTALL OFF" - "SDL2MIXER_DEPS_SHARED OFF" - "SDL2MIXER_SAMPLES OFF" - "SDL2MIXER_VENDORED ON" - "SDL2MIXER_FLAC ON" - "SDL2MIXER_FLAC_LIBFLAC OFF" - "SDL2MIXER_FLAC_DRFLAC ON" - "SDL2MIXER_MOD OFF" - "SDL2MIXER_MP3 ON" - "SDL2MIXER_MP3_DRMP3 ON" - "SDL2MIXER_MIDI ON" - "SDL2MIXER_OPUS OFF" - "SDL2MIXER_VORBIS STB" - "SDL2MIXER_WAVE ON" - ) -endif() - -if(NOT "${SRB2_CONFIG_SYSTEM_LIBRARIES}") - CPMAddPackage( - NAME ZLIB - VERSION 1.2.13 - URL "https://github.com/madler/zlib/archive/refs/tags/v1.2.13.zip" - EXCLUDE_FROM_ALL - DOWNLOAD_ONLY YES - ) - if(ZLIB_ADDED) - set(ZLIB_SRCS - crc32.h - deflate.h - gzguts.h - inffast.h - inffixed.h - inflate.h - inftrees.h - trees.h - zutil.h - - adler32.c - compress.c - crc32.c - deflate.c - gzclose.c - gzlib.c - gzread.c - gzwrite.c - inflate.c - infback.c - inftrees.c - inffast.c - trees.c - uncompr.c - zutil.c - ) - list(TRANSFORM ZLIB_SRCS PREPEND "${ZLIB_SOURCE_DIR}/") - - configure_file("${ZLIB_SOURCE_DIR}/zlib.pc.cmakein" "${ZLIB_BINARY_DIR}/zlib.pc" @ONLY) - configure_file("${ZLIB_SOURCE_DIR}/zconf.h.cmakein" "${ZLIB_BINARY_DIR}/include/zconf.h" @ONLY) - configure_file("${ZLIB_SOURCE_DIR}/zlib.h" "${ZLIB_BINARY_DIR}/include/zlib.h" @ONLY) - - add_library(ZLIB ${SRB2_INTERNAL_LIBRARY_TYPE} ${ZLIB_SRCS}) - set_target_properties(ZLIB PROPERTIES - VERSION 1.2.13 - OUTPUT_NAME "z" - ) - target_include_directories(ZLIB PRIVATE "${ZLIB_SOURCE_DIR}") - target_include_directories(ZLIB PUBLIC "${ZLIB_BINARY_DIR}/include") - if(MSVC) - target_compile_definitions(ZLIB PRIVATE -D_CRT_SECURE_NO_DEPRECATE -D_CRT_NONSTDC_NO_DEPRECATE) - endif() - add_library(ZLIB::ZLIB ALIAS ZLIB) - endif() -endif() - if(NOT "${SRB2_CONFIG_SYSTEM_LIBRARIES}") - CPMAddPackage( - NAME png - VERSION 1.6.38 - URL "https://github.com/glennrp/libpng/archive/refs/tags/v1.6.38.zip" - # png cmake build is broken on msys/mingw32 - DOWNLOAD_ONLY YES - ) - - if(png_ADDED) - # Since png's cmake build is broken, we're going to create a target manually - set( - PNG_SOURCES - - png.h - pngconf.h - - pngpriv.h - pngdebug.h - pnginfo.h - pngstruct.h - - png.c - pngerror.c - pngget.c - pngmem.c - pngpread.c - pngread.c - pngrio.c - pngrtran.c - pngrutil.c - pngset.c - pngtrans.c - pngwio.c - pngwrite.c - pngwtran.c - pngwutil.c - ) - list(TRANSFORM PNG_SOURCES PREPEND "${png_SOURCE_DIR}/") - - add_custom_command( - OUTPUT "${png_BINARY_DIR}/include/png.h" "${png_BINARY_DIR}/include/pngconf.h" - COMMAND ${CMAKE_COMMAND} -E copy "${png_SOURCE_DIR}/png.h" "${png_SOURCE_DIR}/pngconf.h" "${png_BINARY_DIR}/include" - DEPENDS "${png_SOURCE_DIR}/png.h" "${png_SOURCE_DIR}/pngconf.h" - VERBATIM - ) - add_custom_command( - OUTPUT "${png_BINARY_DIR}/include/pnglibconf.h" - COMMAND ${CMAKE_COMMAND} -E copy "${png_SOURCE_DIR}/scripts/pnglibconf.h.prebuilt" "${png_BINARY_DIR}/include/pnglibconf.h" - DEPENDS "${png_SOURCE_DIR}/scripts/pnglibconf.h.prebuilt" - VERBATIM - ) - list( - APPEND PNG_SOURCES - "${png_BINARY_DIR}/include/png.h" - "${png_BINARY_DIR}/include/pngconf.h" - "${png_BINARY_DIR}/include/pnglibconf.h" - ) - add_library(png "${SRB2_INTERNAL_LIBRARY_TYPE}" ${PNG_SOURCES}) - - # Disable ARM NEON since having it automatic breaks libpng external build on clang for some reason - target_compile_definitions(png PRIVATE -DPNG_ARM_NEON_OPT=0) - - # The png includes need to be available to consumers - target_include_directories(png PUBLIC "${png_BINARY_DIR}/include") - - # ... and these also need to be present only for png build - target_include_directories(png PRIVATE "${ZLIB_SOURCE_DIR}") - target_include_directories(png PRIVATE "${ZLIB_BINARY_DIR}") - target_include_directories(png PRIVATE "${png_BINARY_DIR}") - - target_link_libraries(png PRIVATE ZLIB::ZLIB) - add_library(PNG::PNG ALIAS png) - endif() + include("cpm-sdl2.cmake") + include("cpm-sdl2-mixer.cmake") + include("cpm-zlib.cmake") + include("cpm-png.cmake") + include("cpm-curl.cmake") + include("cpm-openmpt.cmake") endif() -if(NOT "${SRB2_CONFIG_SYSTEM_LIBRARIES}") - set( - internal_curl_options - - "BUILD_CURL_EXE OFF" - "BUILD_SHARED_LIBS ${SRB2_CONFIG_SHARED_INTERNAL_LIBRARIES}" - "CURL_DISABLE_TESTS ON" - "HTTP_ONLY ON" - "CURL_DISABLE_CRYPTO_AUTH ON" - "CURL_DISABLE_NTLM ON" - "ENABLE_MANUAL OFF" - "ENABLE_THREADED_RESOLVER OFF" - "CURL_USE_LIBPSL OFF" - "CURL_USE_LIBSSH2 OFF" - "USE_LIBIDN2 OFF" - "CURL_ENABLE_EXPORT_TARGET OFF" - ) - if(${CMAKE_SYSTEM} MATCHES Windows) - list(APPEND internal_curl_options "CURL_USE_OPENSSL OFF") - list(APPEND internal_curl_options "CURL_USE_SCHANNEL ON") - endif() - if(${CMAKE_SYSTEM} MATCHES Darwin) - list(APPEND internal_curl_options "CURL_USE_OPENSSL OFF") - list(APPEND internal_curl_options "CURL_USE_SECTRANSP ON") - endif() - if(${CMAKE_SYSTEM} MATCHES Linux) - list(APPEND internal_curl_options "CURL_USE_OPENSSL ON") - endif() - - CPMAddPackage( - NAME curl - VERSION 7.86.0 - URL "https://github.com/curl/curl/archive/refs/tags/curl-7_86_0.zip" - EXCLUDE_FROM_ALL ON - OPTIONS ${internal_curl_options} - ) -endif() - -if(NOT "${SRB2_CONFIG_SYSTEM_LIBRARIES}") - CPMAddPackage( - NAME openmpt - VERSION 0.4.30 - URL "https://github.com/OpenMPT/openmpt/archive/refs/tags/libopenmpt-0.4.30.zip" - DOWNLOAD_ONLY ON - ) - - if(openmpt_ADDED) - set( - openmpt_SOURCES - - # minimp3 - # -DMPT_WITH_MINIMP3 - include/minimp3/minimp3.c - - common/mptStringParse.cpp - common/mptLibrary.cpp - common/Logging.cpp - common/Profiler.cpp - common/version.cpp - common/mptCPU.cpp - common/ComponentManager.cpp - common/mptOS.cpp - common/serialization_utils.cpp - common/mptStringFormat.cpp - common/FileReader.cpp - common/mptWine.cpp - common/mptPathString.cpp - common/mptAlloc.cpp - common/mptUUID.cpp - common/mptTime.cpp - common/mptString.cpp - common/mptFileIO.cpp - common/mptStringBuffer.cpp - common/mptRandom.cpp - common/mptIO.cpp - common/misc_util.cpp - - common/mptCRC.h - common/mptLibrary.h - common/mptIO.h - common/version.h - common/stdafx.h - common/ComponentManager.h - common/Endianness.h - common/mptStringFormat.h - common/mptMutex.h - common/mptUUID.h - common/mptExceptionText.h - common/BuildSettings.h - common/mptAlloc.h - common/mptTime.h - common/FileReaderFwd.h - common/Logging.h - common/mptException.h - common/mptWine.h - common/mptStringBuffer.h - common/misc_util.h - common/mptBaseMacros.h - common/mptMemory.h - common/mptFileIO.h - common/serialization_utils.h - common/mptSpan.h - common/mptThread.h - common/FlagSet.h - common/mptString.h - common/mptStringParse.h - common/mptBaseUtils.h - common/mptRandom.h - common/CompilerDetect.h - common/FileReader.h - common/mptAssert.h - common/mptPathString.h - common/Profiler.h - common/mptOS.h - common/mptBaseTypes.h - common/mptCPU.h - common/mptBufferIO.h - common/versionNumber.h - - soundlib/WAVTools.cpp - soundlib/ITTools.cpp - soundlib/AudioCriticalSection.cpp - soundlib/Load_stm.cpp - soundlib/MixerLoops.cpp - soundlib/Load_dbm.cpp - soundlib/ModChannel.cpp - soundlib/Load_gdm.cpp - soundlib/Snd_fx.cpp - soundlib/Load_mid.cpp - soundlib/mod_specifications.cpp - soundlib/Snd_flt.cpp - soundlib/Load_psm.cpp - soundlib/Load_far.cpp - soundlib/patternContainer.cpp - soundlib/Load_med.cpp - soundlib/Load_dmf.cpp - soundlib/Paula.cpp - soundlib/modcommand.cpp - soundlib/Message.cpp - soundlib/SoundFilePlayConfig.cpp - soundlib/Load_uax.cpp - soundlib/plugins/PlugInterface.cpp - soundlib/plugins/LFOPlugin.cpp - soundlib/plugins/PluginManager.cpp - soundlib/plugins/DigiBoosterEcho.cpp - soundlib/plugins/dmo/DMOPlugin.cpp - soundlib/plugins/dmo/Flanger.cpp - soundlib/plugins/dmo/Distortion.cpp - soundlib/plugins/dmo/ParamEq.cpp - soundlib/plugins/dmo/Gargle.cpp - soundlib/plugins/dmo/I3DL2Reverb.cpp - soundlib/plugins/dmo/Compressor.cpp - soundlib/plugins/dmo/WavesReverb.cpp - soundlib/plugins/dmo/Echo.cpp - soundlib/plugins/dmo/Chorus.cpp - soundlib/Load_ams.cpp - soundlib/tuningbase.cpp - soundlib/ContainerUMX.cpp - soundlib/Load_ptm.cpp - soundlib/ContainerXPK.cpp - soundlib/SampleFormatMP3.cpp - soundlib/tuning.cpp - soundlib/Sndfile.cpp - soundlib/ContainerMMCMP.cpp - soundlib/Load_amf.cpp - soundlib/Load_669.cpp - soundlib/modsmp_ctrl.cpp - soundlib/Load_mtm.cpp - soundlib/OggStream.cpp - soundlib/Load_plm.cpp - soundlib/Tables.cpp - soundlib/Load_c67.cpp - soundlib/Load_mod.cpp - soundlib/Load_sfx.cpp - soundlib/Sndmix.cpp - soundlib/load_j2b.cpp - soundlib/ModSequence.cpp - soundlib/SampleFormatFLAC.cpp - soundlib/ModInstrument.cpp - soundlib/Load_mo3.cpp - soundlib/ModSample.cpp - soundlib/Dlsbank.cpp - soundlib/Load_itp.cpp - soundlib/UpgradeModule.cpp - soundlib/MIDIMacros.cpp - soundlib/ContainerPP20.cpp - soundlib/RowVisitor.cpp - soundlib/Load_imf.cpp - soundlib/SampleFormatVorbis.cpp - soundlib/Load_dsm.cpp - soundlib/Load_mt2.cpp - soundlib/MixerSettings.cpp - soundlib/S3MTools.cpp - soundlib/Load_xm.cpp - soundlib/MIDIEvents.cpp - soundlib/pattern.cpp - soundlib/Load_digi.cpp - soundlib/Load_s3m.cpp - soundlib/tuningCollection.cpp - soundlib/SampleIO.cpp - soundlib/Dither.cpp - soundlib/Load_mdl.cpp - soundlib/OPL.cpp - soundlib/WindowedFIR.cpp - soundlib/SampleFormats.cpp - soundlib/Load_wav.cpp - soundlib/Load_it.cpp - soundlib/UMXTools.cpp - soundlib/Load_stp.cpp - soundlib/Load_okt.cpp - soundlib/Load_ult.cpp - soundlib/MixFuncTable.cpp - soundlib/SampleFormatOpus.cpp - soundlib/Fastmix.cpp - soundlib/Tagging.cpp - soundlib/ITCompression.cpp - soundlib/Load_dtm.cpp - soundlib/MPEGFrame.cpp - soundlib/XMTools.cpp - soundlib/SampleFormatMediaFoundation.cpp - soundlib/InstrumentExtensions.cpp - - soundlib/MixerInterface.h - soundlib/SoundFilePlayConfig.h - soundlib/ModSample.h - soundlib/MIDIEvents.h - soundlib/ModSampleCopy.h - soundlib/patternContainer.h - soundlib/ChunkReader.h - soundlib/ITCompression.h - soundlib/Dither.h - soundlib/S3MTools.h - soundlib/MPEGFrame.h - soundlib/WAVTools.h - soundlib/mod_specifications.h - soundlib/ITTools.h - soundlib/RowVisitor.h - soundlib/plugins/PluginMixBuffer.h - soundlib/plugins/PluginStructs.h - soundlib/plugins/LFOPlugin.h - soundlib/plugins/PlugInterface.h - soundlib/plugins/DigiBoosterEcho.h - soundlib/plugins/OpCodes.h - soundlib/plugins/dmo/Echo.h - soundlib/plugins/dmo/I3DL2Reverb.h - soundlib/plugins/dmo/WavesReverb.h - soundlib/plugins/dmo/ParamEq.h - soundlib/plugins/dmo/Gargle.h - soundlib/plugins/dmo/DMOPlugin.h - soundlib/plugins/dmo/Chorus.h - soundlib/plugins/dmo/Compressor.h - soundlib/plugins/dmo/Distortion.h - soundlib/plugins/dmo/Flanger.h - soundlib/plugins/PluginManager.h - soundlib/SampleIO.h - soundlib/Container.h - soundlib/ModSequence.h - soundlib/UMXTools.h - soundlib/Message.h - soundlib/modcommand.h - soundlib/XMTools.h - soundlib/Snd_defs.h - soundlib/MixFuncTable.h - soundlib/pattern.h - soundlib/modsmp_ctrl.h - soundlib/Tagging.h - soundlib/tuningcollection.h - soundlib/Mixer.h - soundlib/FloatMixer.h - soundlib/AudioCriticalSection.h - soundlib/Tables.h - soundlib/tuningbase.h - soundlib/WindowedFIR.h - soundlib/Sndfile.h - soundlib/Paula.h - soundlib/ModInstrument.h - soundlib/Dlsbank.h - soundlib/IntMixer.h - soundlib/OPL.h - soundlib/Resampler.h - soundlib/ModChannel.h - soundlib/MixerSettings.h - soundlib/AudioReadTarget.h - soundlib/MixerLoops.h - soundlib/tuning.h - soundlib/MIDIMacros.h - soundlib/OggStream.h - soundlib/Loaders.h - soundlib/BitReader.h - soundlib/opal.h - - sounddsp/AGC.cpp - sounddsp/EQ.cpp - sounddsp/DSP.cpp - sounddsp/Reverb.cpp - sounddsp/Reverb.h - sounddsp/EQ.h - sounddsp/DSP.h - sounddsp/AGC.h - - libopenmpt/libopenmpt_c.cpp - libopenmpt/libopenmpt_cxx.cpp - libopenmpt/libopenmpt_impl.cpp - libopenmpt/libopenmpt_ext_impl.cpp - ) - list(TRANSFORM openmpt_SOURCES PREPEND "${openmpt_SOURCE_DIR}/") - - # -DLIBOPENMPT_BUILD - configure_file("openmpt_svn_version.h" "svn_version.h") - add_library(openmpt "${SRB2_INTERNAL_LIBRARY_TYPE}" ${openmpt_SOURCES} ${CMAKE_CURRENT_BINARY_DIR}/svn_version.h) - if("${CMAKE_C_COMPILER_ID}" STREQUAL GNU OR "${CMAKE_C_COMPILER_ID}" STREQUAL Clang OR "${CMAKE_C_COMPILER_ID}" STREQUAL AppleClang) - target_compile_options(openmpt PRIVATE "-g0") - endif() - if("${CMAKE_SYSTEM_NAME}" STREQUAL Windows AND "${CMAKE_C_COMPILER_ID}" STREQUAL MSVC) - target_link_libraries(openmpt PRIVATE Rpcrt4) - endif() - target_compile_features(openmpt PRIVATE cxx_std_11) - target_compile_definitions(openmpt PRIVATE -DLIBOPENMPT_BUILD) - - target_include_directories(openmpt PRIVATE "${openmpt_SOURCE_DIR}/common") - target_include_directories(openmpt PRIVATE "${openmpt_SOURCE_DIR}/src") - target_include_directories(openmpt PRIVATE "${openmpt_SOURCE_DIR}/include") - target_include_directories(openmpt PRIVATE "${openmpt_SOURCE_DIR}") - target_include_directories(openmpt PRIVATE "${CMAKE_CURRENT_BINARY_DIR}") - - # I wish this wasn't necessary, but it is - target_include_directories(openmpt PUBLIC "${openmpt_SOURCE_DIR}") - endif() -endif() - -if(NOT "${SRB2_CONFIG_SYSTEM_LIBRARIES}") - CPMAddPackage( - NAME libgme - VERSION 0.6.3 - URL "https://bitbucket.org/mpyne/game-music-emu/get/e76bdc0cb916e79aa540290e6edd0c445879d3ba.zip" - EXCLUDE_FROM_ALL ON - OPTIONS - "BUILD_SHARED_LIBS ${SRB2_CONFIG_SHARED_INTERNAL_LIBRARIES}" - "ENABLE_UBSAN OFF" - "GME_YM2612_EMU MAME" - ) - target_compile_features(gme PRIVATE cxx_std_11) - target_link_libraries(gme PRIVATE ZLIB::ZLIB) -endif() +include("cpm-libgme.cmake") diff --git a/thirdparty/cpm-curl.cmake b/thirdparty/cpm-curl.cmake new file mode 100644 index 0000000000000000000000000000000000000000..3d8c6e61d46dee6f06f4e6d69beb09d1605f6584 --- /dev/null +++ b/thirdparty/cpm-curl.cmake @@ -0,0 +1,35 @@ +set( + internal_curl_options + + "BUILD_CURL_EXE OFF" + "BUILD_SHARED_LIBS ${SRB2_CONFIG_SHARED_INTERNAL_LIBRARIES}" + "CURL_DISABLE_TESTS ON" + "HTTP_ONLY ON" + "CURL_DISABLE_CRYPTO_AUTH ON" + "CURL_DISABLE_NTLM ON" + "ENABLE_MANUAL OFF" + "ENABLE_THREADED_RESOLVER OFF" + "CURL_USE_LIBPSL OFF" + "CURL_USE_LIBSSH2 OFF" + "USE_LIBIDN2 OFF" + "CURL_ENABLE_EXPORT_TARGET OFF" +) +if(${CMAKE_SYSTEM} MATCHES Windows) + list(APPEND internal_curl_options "CURL_USE_OPENSSL OFF") + list(APPEND internal_curl_options "CURL_USE_SCHANNEL ON") +endif() +if(${CMAKE_SYSTEM} MATCHES Darwin) + list(APPEND internal_curl_options "CURL_USE_OPENSSL OFF") + list(APPEND internal_curl_options "CURL_USE_SECTRANSP ON") +endif() +if(${CMAKE_SYSTEM} MATCHES Linux) + list(APPEND internal_curl_options "CURL_USE_OPENSSL ON") +endif() + +CPMAddPackage( + NAME curl + VERSION 7.86.0 + URL "https://github.com/curl/curl/archive/refs/tags/curl-7_86_0.zip" + EXCLUDE_FROM_ALL ON + OPTIONS ${internal_curl_options} +) diff --git a/thirdparty/cpm-libgme.cmake b/thirdparty/cpm-libgme.cmake new file mode 100644 index 0000000000000000000000000000000000000000..f15bc3b31cb23ed7663ed950c14c1d6a0dc36567 --- /dev/null +++ b/thirdparty/cpm-libgme.cmake @@ -0,0 +1,16 @@ +CPMAddPackage( + NAME libgme + VERSION 0.6.3 + URL "https://bitbucket.org/mpyne/game-music-emu/get/e76bdc0cb916e79aa540290e6edd0c445879d3ba.zip" + EXCLUDE_FROM_ALL ON + OPTIONS + "BUILD_SHARED_LIBS ${SRB2_CONFIG_SHARED_INTERNAL_LIBRARIES}" + "ENABLE_UBSAN OFF" + "GME_YM2612_EMU MAME" +) + +if(libgme_ADDED) + target_compile_features(gme PRIVATE cxx_std_11) + # libgme's CMakeLists.txt already links this + #target_link_libraries(gme PRIVATE ZLIB::ZLIB) +endif() diff --git a/thirdparty/cpm-openmpt.cmake b/thirdparty/cpm-openmpt.cmake new file mode 100644 index 0000000000000000000000000000000000000000..01f7ff75f64d915799e432f2923a2c7e8c344466 --- /dev/null +++ b/thirdparty/cpm-openmpt.cmake @@ -0,0 +1,289 @@ +CPMAddPackage( + NAME openmpt + VERSION 0.4.30 + URL "https://github.com/OpenMPT/openmpt/archive/refs/tags/libopenmpt-0.4.30.zip" + DOWNLOAD_ONLY ON +) + +if(openmpt_ADDED) + set( + openmpt_SOURCES + + # minimp3 + # -DMPT_WITH_MINIMP3 + include/minimp3/minimp3.c + + common/mptStringParse.cpp + common/mptLibrary.cpp + common/Logging.cpp + common/Profiler.cpp + common/version.cpp + common/mptCPU.cpp + common/ComponentManager.cpp + common/mptOS.cpp + common/serialization_utils.cpp + common/mptStringFormat.cpp + common/FileReader.cpp + common/mptWine.cpp + common/mptPathString.cpp + common/mptAlloc.cpp + common/mptUUID.cpp + common/mptTime.cpp + common/mptString.cpp + common/mptFileIO.cpp + common/mptStringBuffer.cpp + common/mptRandom.cpp + common/mptIO.cpp + common/misc_util.cpp + + common/mptCRC.h + common/mptLibrary.h + common/mptIO.h + common/version.h + common/stdafx.h + common/ComponentManager.h + common/Endianness.h + common/mptStringFormat.h + common/mptMutex.h + common/mptUUID.h + common/mptExceptionText.h + common/BuildSettings.h + common/mptAlloc.h + common/mptTime.h + common/FileReaderFwd.h + common/Logging.h + common/mptException.h + common/mptWine.h + common/mptStringBuffer.h + common/misc_util.h + common/mptBaseMacros.h + common/mptMemory.h + common/mptFileIO.h + common/serialization_utils.h + common/mptSpan.h + common/mptThread.h + common/FlagSet.h + common/mptString.h + common/mptStringParse.h + common/mptBaseUtils.h + common/mptRandom.h + common/CompilerDetect.h + common/FileReader.h + common/mptAssert.h + common/mptPathString.h + common/Profiler.h + common/mptOS.h + common/mptBaseTypes.h + common/mptCPU.h + common/mptBufferIO.h + common/versionNumber.h + + soundlib/WAVTools.cpp + soundlib/ITTools.cpp + soundlib/AudioCriticalSection.cpp + soundlib/Load_stm.cpp + soundlib/MixerLoops.cpp + soundlib/Load_dbm.cpp + soundlib/ModChannel.cpp + soundlib/Load_gdm.cpp + soundlib/Snd_fx.cpp + soundlib/Load_mid.cpp + soundlib/mod_specifications.cpp + soundlib/Snd_flt.cpp + soundlib/Load_psm.cpp + soundlib/Load_far.cpp + soundlib/patternContainer.cpp + soundlib/Load_med.cpp + soundlib/Load_dmf.cpp + soundlib/Paula.cpp + soundlib/modcommand.cpp + soundlib/Message.cpp + soundlib/SoundFilePlayConfig.cpp + soundlib/Load_uax.cpp + soundlib/plugins/PlugInterface.cpp + soundlib/plugins/LFOPlugin.cpp + soundlib/plugins/PluginManager.cpp + soundlib/plugins/DigiBoosterEcho.cpp + soundlib/plugins/dmo/DMOPlugin.cpp + soundlib/plugins/dmo/Flanger.cpp + soundlib/plugins/dmo/Distortion.cpp + soundlib/plugins/dmo/ParamEq.cpp + soundlib/plugins/dmo/Gargle.cpp + soundlib/plugins/dmo/I3DL2Reverb.cpp + soundlib/plugins/dmo/Compressor.cpp + soundlib/plugins/dmo/WavesReverb.cpp + soundlib/plugins/dmo/Echo.cpp + soundlib/plugins/dmo/Chorus.cpp + soundlib/Load_ams.cpp + soundlib/tuningbase.cpp + soundlib/ContainerUMX.cpp + soundlib/Load_ptm.cpp + soundlib/ContainerXPK.cpp + soundlib/SampleFormatMP3.cpp + soundlib/tuning.cpp + soundlib/Sndfile.cpp + soundlib/ContainerMMCMP.cpp + soundlib/Load_amf.cpp + soundlib/Load_669.cpp + soundlib/modsmp_ctrl.cpp + soundlib/Load_mtm.cpp + soundlib/OggStream.cpp + soundlib/Load_plm.cpp + soundlib/Tables.cpp + soundlib/Load_c67.cpp + soundlib/Load_mod.cpp + soundlib/Load_sfx.cpp + soundlib/Sndmix.cpp + soundlib/load_j2b.cpp + soundlib/ModSequence.cpp + soundlib/SampleFormatFLAC.cpp + soundlib/ModInstrument.cpp + soundlib/Load_mo3.cpp + soundlib/ModSample.cpp + soundlib/Dlsbank.cpp + soundlib/Load_itp.cpp + soundlib/UpgradeModule.cpp + soundlib/MIDIMacros.cpp + soundlib/ContainerPP20.cpp + soundlib/RowVisitor.cpp + soundlib/Load_imf.cpp + soundlib/SampleFormatVorbis.cpp + soundlib/Load_dsm.cpp + soundlib/Load_mt2.cpp + soundlib/MixerSettings.cpp + soundlib/S3MTools.cpp + soundlib/Load_xm.cpp + soundlib/MIDIEvents.cpp + soundlib/pattern.cpp + soundlib/Load_digi.cpp + soundlib/Load_s3m.cpp + soundlib/tuningCollection.cpp + soundlib/SampleIO.cpp + soundlib/Dither.cpp + soundlib/Load_mdl.cpp + soundlib/OPL.cpp + soundlib/WindowedFIR.cpp + soundlib/SampleFormats.cpp + soundlib/Load_wav.cpp + soundlib/Load_it.cpp + soundlib/UMXTools.cpp + soundlib/Load_stp.cpp + soundlib/Load_okt.cpp + soundlib/Load_ult.cpp + soundlib/MixFuncTable.cpp + soundlib/SampleFormatOpus.cpp + soundlib/Fastmix.cpp + soundlib/Tagging.cpp + soundlib/ITCompression.cpp + soundlib/Load_dtm.cpp + soundlib/MPEGFrame.cpp + soundlib/XMTools.cpp + soundlib/SampleFormatMediaFoundation.cpp + soundlib/InstrumentExtensions.cpp + + soundlib/MixerInterface.h + soundlib/SoundFilePlayConfig.h + soundlib/ModSample.h + soundlib/MIDIEvents.h + soundlib/ModSampleCopy.h + soundlib/patternContainer.h + soundlib/ChunkReader.h + soundlib/ITCompression.h + soundlib/Dither.h + soundlib/S3MTools.h + soundlib/MPEGFrame.h + soundlib/WAVTools.h + soundlib/mod_specifications.h + soundlib/ITTools.h + soundlib/RowVisitor.h + soundlib/plugins/PluginMixBuffer.h + soundlib/plugins/PluginStructs.h + soundlib/plugins/LFOPlugin.h + soundlib/plugins/PlugInterface.h + soundlib/plugins/DigiBoosterEcho.h + soundlib/plugins/OpCodes.h + soundlib/plugins/dmo/Echo.h + soundlib/plugins/dmo/I3DL2Reverb.h + soundlib/plugins/dmo/WavesReverb.h + soundlib/plugins/dmo/ParamEq.h + soundlib/plugins/dmo/Gargle.h + soundlib/plugins/dmo/DMOPlugin.h + soundlib/plugins/dmo/Chorus.h + soundlib/plugins/dmo/Compressor.h + soundlib/plugins/dmo/Distortion.h + soundlib/plugins/dmo/Flanger.h + soundlib/plugins/PluginManager.h + soundlib/SampleIO.h + soundlib/Container.h + soundlib/ModSequence.h + soundlib/UMXTools.h + soundlib/Message.h + soundlib/modcommand.h + soundlib/XMTools.h + soundlib/Snd_defs.h + soundlib/MixFuncTable.h + soundlib/pattern.h + soundlib/modsmp_ctrl.h + soundlib/Tagging.h + soundlib/tuningcollection.h + soundlib/Mixer.h + soundlib/FloatMixer.h + soundlib/AudioCriticalSection.h + soundlib/Tables.h + soundlib/tuningbase.h + soundlib/WindowedFIR.h + soundlib/Sndfile.h + soundlib/Paula.h + soundlib/ModInstrument.h + soundlib/Dlsbank.h + soundlib/IntMixer.h + soundlib/OPL.h + soundlib/Resampler.h + soundlib/ModChannel.h + soundlib/MixerSettings.h + soundlib/AudioReadTarget.h + soundlib/MixerLoops.h + soundlib/tuning.h + soundlib/MIDIMacros.h + soundlib/OggStream.h + soundlib/Loaders.h + soundlib/BitReader.h + soundlib/opal.h + + sounddsp/AGC.cpp + sounddsp/EQ.cpp + sounddsp/DSP.cpp + sounddsp/Reverb.cpp + sounddsp/Reverb.h + sounddsp/EQ.h + sounddsp/DSP.h + sounddsp/AGC.h + + libopenmpt/libopenmpt_c.cpp + libopenmpt/libopenmpt_cxx.cpp + libopenmpt/libopenmpt_impl.cpp + libopenmpt/libopenmpt_ext_impl.cpp + ) + list(TRANSFORM openmpt_SOURCES PREPEND "${openmpt_SOURCE_DIR}/") + + # -DLIBOPENMPT_BUILD + configure_file("openmpt_svn_version.h" "svn_version.h") + add_library(openmpt "${SRB2_INTERNAL_LIBRARY_TYPE}" ${openmpt_SOURCES} ${CMAKE_CURRENT_BINARY_DIR}/svn_version.h) + if("${CMAKE_C_COMPILER_ID}" STREQUAL GNU OR "${CMAKE_C_COMPILER_ID}" STREQUAL Clang OR "${CMAKE_C_COMPILER_ID}" STREQUAL AppleClang) + target_compile_options(openmpt PRIVATE "-g0") + endif() + if("${CMAKE_SYSTEM_NAME}" STREQUAL Windows AND "${CMAKE_C_COMPILER_ID}" STREQUAL MSVC) + target_link_libraries(openmpt PRIVATE Rpcrt4) + endif() + target_compile_features(openmpt PRIVATE cxx_std_11) + target_compile_definitions(openmpt PRIVATE -DLIBOPENMPT_BUILD) + + target_include_directories(openmpt PRIVATE "${openmpt_SOURCE_DIR}/common") + target_include_directories(openmpt PRIVATE "${openmpt_SOURCE_DIR}/src") + target_include_directories(openmpt PRIVATE "${openmpt_SOURCE_DIR}/include") + target_include_directories(openmpt PRIVATE "${openmpt_SOURCE_DIR}") + target_include_directories(openmpt PRIVATE "${CMAKE_CURRENT_BINARY_DIR}") + + # I wish this wasn't necessary, but it is + target_include_directories(openmpt PUBLIC "${openmpt_SOURCE_DIR}") +endif() diff --git a/thirdparty/cpm-png.cmake b/thirdparty/cpm-png.cmake new file mode 100644 index 0000000000000000000000000000000000000000..f16ac037b0cc9c077f3ef315b67b430e68cf9b40 --- /dev/null +++ b/thirdparty/cpm-png.cmake @@ -0,0 +1,69 @@ +CPMAddPackage( + NAME png + VERSION 1.6.38 + URL "https://github.com/glennrp/libpng/archive/refs/tags/v1.6.38.zip" + # png cmake build is broken on msys/mingw32 + DOWNLOAD_ONLY YES +) + +if(png_ADDED) + # Since png's cmake build is broken, we're going to create a target manually + set( + PNG_SOURCES + png.h + pngconf.h + pngpriv.h + pngdebug.h + pnginfo.h + pngstruct.h + png.c + pngerror.c + pngget.c + pngmem.c + pngpread.c + pngread.c + pngrio.c + pngrtran.c + pngrutil.c + pngset.c + pngtrans.c + pngwio.c + pngwrite.c + pngwtran.c + pngwutil.c + ) + list(TRANSFORM PNG_SOURCES PREPEND "${png_SOURCE_DIR}/") + + add_custom_command( + OUTPUT "${png_BINARY_DIR}/include/png.h" "${png_BINARY_DIR}/include/pngconf.h" + COMMAND ${CMAKE_COMMAND} -E copy "${png_SOURCE_DIR}/png.h" "${png_SOURCE_DIR}/pngconf.h" "${png_BINARY_DIR}/include" + DEPENDS "${png_SOURCE_DIR}/png.h" "${png_SOURCE_DIR}/pngconf.h" + VERBATIM + ) + add_custom_command( + OUTPUT "${png_BINARY_DIR}/include/pnglibconf.h" + COMMAND ${CMAKE_COMMAND} -E copy "${png_SOURCE_DIR}/scripts/pnglibconf.h.prebuilt" "${png_BINARY_DIR}/include/pnglibconf.h" + DEPENDS "${png_SOURCE_DIR}/scripts/pnglibconf.h.prebuilt" + VERBATIM + ) + list( + APPEND PNG_SOURCES + "${png_BINARY_DIR}/include/png.h" + "${png_BINARY_DIR}/include/pngconf.h" + "${png_BINARY_DIR}/include/pnglibconf.h" + ) + add_library(png "${SRB2_INTERNAL_LIBRARY_TYPE}" ${PNG_SOURCES}) + + # Disable ARM NEON since having it automatic breaks libpng external build on clang for some reason + target_compile_definitions(png PRIVATE -DPNG_ARM_NEON_OPT=0) + + # The png includes need to be available to consumers + target_include_directories(png PUBLIC "${png_BINARY_DIR}/include") + + # ... and these also need to be present only for png build + target_include_directories(png PRIVATE "${ZLIB_SOURCE_DIR}") + target_include_directories(png PRIVATE "${ZLIB_BINARY_DIR}") + target_include_directories(png PRIVATE "${png_BINARY_DIR}") + target_link_libraries(png PRIVATE ZLIB::ZLIB) + add_library(PNG::PNG ALIAS png) +endif() diff --git a/thirdparty/cpm-sdl2-mixer.cmake b/thirdparty/cpm-sdl2-mixer.cmake new file mode 100644 index 0000000000000000000000000000000000000000..b7dfeae0d3eab254651f0c5e6e69e7af0626012e --- /dev/null +++ b/thirdparty/cpm-sdl2-mixer.cmake @@ -0,0 +1,22 @@ +CPMAddPackage( + NAME SDL2_mixer + VERSION 2.6.2 + URL "https://github.com/libsdl-org/SDL_mixer/archive/refs/tags/release-2.6.2.zip" + EXCLUDE_FROM_ALL ON + OPTIONS + "BUILD_SHARED_LIBS ${SRB2_CONFIG_SHARED_INTERNAL_LIBRARIES}" + "SDL2MIXER_INSTALL OFF" + "SDL2MIXER_DEPS_SHARED OFF" + "SDL2MIXER_SAMPLES OFF" + "SDL2MIXER_VENDORED ON" + "SDL2MIXER_FLAC ON" + "SDL2MIXER_FLAC_LIBFLAC OFF" + "SDL2MIXER_FLAC_DRFLAC ON" + "SDL2MIXER_MOD OFF" + "SDL2MIXER_MP3 ON" + "SDL2MIXER_MP3_DRMP3 ON" + "SDL2MIXER_MIDI ON" + "SDL2MIXER_OPUS OFF" + "SDL2MIXER_VORBIS STB" + "SDL2MIXER_WAVE ON" +) diff --git a/thirdparty/cpm-sdl2.cmake b/thirdparty/cpm-sdl2.cmake new file mode 100644 index 0000000000000000000000000000000000000000..58cf9afc2a8c9f443379625049ebd28446382b84 --- /dev/null +++ b/thirdparty/cpm-sdl2.cmake @@ -0,0 +1,13 @@ +CPMAddPackage( + NAME SDL2 + VERSION 2.24.2 + URL "https://github.com/libsdl-org/SDL/archive/refs/tags/release-2.24.2.zip" + EXCLUDE_FROM_ALL ON + OPTIONS + "BUILD_SHARED_LIBS ${SRB2_CONFIG_SHARED_INTERNAL_LIBRARIES}" + "SDL_SHARED ${SRB2_CONFIG_SHARED_INTERNAL_LIBRARIES}" + "SDL_STATIC ${NOT_SRB2_CONFIG_SHARED_INTERNAL_LIBRARIES}" + "SDL_TEST OFF" + "SDL2_DISABLE_SDL2MAIN ON" + "SDL2_DISABLE_INSTALL ON" +) diff --git a/thirdparty/cpm-zlib.cmake b/thirdparty/cpm-zlib.cmake new file mode 100644 index 0000000000000000000000000000000000000000..5368366fd14a4246da476e48bb98ce708812646e --- /dev/null +++ b/thirdparty/cpm-zlib.cmake @@ -0,0 +1,53 @@ +CPMAddPackage( + NAME ZLIB + VERSION 1.2.13 + URL "https://github.com/madler/zlib/archive/refs/tags/v1.2.13.zip" + EXCLUDE_FROM_ALL + DOWNLOAD_ONLY YES +) + +if(ZLIB_ADDED) + set(ZLIB_SRCS + crc32.h + deflate.h + gzguts.h + inffast.h + inffixed.h + inflate.h + inftrees.h + trees.h + zutil.h + adler32.c + compress.c + crc32.c + deflate.c + gzclose.c + gzlib.c + gzread.c + gzwrite.c + inflate.c + infback.c + inftrees.c + inffast.c + trees.c + uncompr.c + zutil.c + ) + list(TRANSFORM ZLIB_SRCS PREPEND "${ZLIB_SOURCE_DIR}/") + + configure_file("${ZLIB_SOURCE_DIR}/zlib.pc.cmakein" "${ZLIB_BINARY_DIR}/zlib.pc" @ONLY) + configure_file("${ZLIB_SOURCE_DIR}/zconf.h.cmakein" "${ZLIB_BINARY_DIR}/include/zconf.h" @ONLY) + configure_file("${ZLIB_SOURCE_DIR}/zlib.h" "${ZLIB_BINARY_DIR}/include/zlib.h" @ONLY) + + add_library(ZLIB ${SRB2_INTERNAL_LIBRARY_TYPE} ${ZLIB_SRCS}) + set_target_properties(ZLIB PROPERTIES + VERSION 1.2.13 + OUTPUT_NAME "z" + ) + target_include_directories(ZLIB PRIVATE "${ZLIB_SOURCE_DIR}") + target_include_directories(ZLIB PUBLIC "${ZLIB_BINARY_DIR}/include") + if(MSVC) + target_compile_definitions(ZLIB PRIVATE -D_CRT_SECURE_NO_DEPRECATE -D_CRT_NONSTDC_NO_DEPRECATE) + endif() + add_library(ZLIB::ZLIB ALIAS ZLIB) +endif() diff --git a/tools/anglechk.c b/tools/anglechk.c index 4a67069bf744772082afeac5d8875991f2075903..7f56abff7e56336090af76e81335d76951dcec39 100644 --- a/tools/anglechk.c +++ b/tools/anglechk.c @@ -22,7 +22,6 @@ #ifdef _MSC_VER #include <assert.h> #endif -#define NOASM #include "../src/tables.h" #define NO_M #include "../src/m_fixed.c"