Merge branch 'master' into improve-backtrace

This commit is contained in:
Alam Ed Arias 2023-10-28 20:00:31 -04:00
commit 11fc21e7ec
205 changed files with 12891 additions and 15587 deletions

View file

@ -1,9 +1,9 @@
version: 2 version: 2
jobs: jobs:
build: build:
working_directory: /root/SRB2 working_directory: /home/circleci/SRB2
docker: docker:
- image: debian:stretch - image: cimg/base:current
environment: environment:
CC: ccache gcc -m32 CC: ccache gcc -m32
PKG_CONFIG_LIBDIR: /usr/lib/i386-linux-gnu/pkgconfig PKG_CONFIG_LIBDIR: /usr/lib/i386-linux-gnu/pkgconfig
@ -11,7 +11,7 @@ jobs:
LIBGME_LDFLAGS: -lgme LIBGME_LDFLAGS: -lgme
CCACHE_COMPRESS: true CCACHE_COMPRESS: true
WFLAGS: -Wno-unsuffixed-float-constants WFLAGS: -Wno-unsuffixed-float-constants
GCC49: true GCC81: true
#- image: ubuntu:trusty #- image: ubuntu:trusty
# environment: # environment:
# CC: ccache gcc -m32 # CC: ccache gcc -m32
@ -25,39 +25,42 @@ jobs:
steps: steps:
- run: - run:
name: Add i386 arch name: Add i386 arch
command: dpkg --add-architecture i386 command: sudo dpkg --add-architecture i386
- run: - run:
name: Add STJr PPA name: Add STJr PPA
command: | command: |
apt-get -qq update sudo apt-get -qq update
apt-get -qq -y install dirmngr sudo apt-get -qq -y install dirmngr
apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 0B1702D71499D9C25F986507F240F4449D3B0EC6 sudo 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 echo "deb http://ppa.launchpad.net/stjr/srb2/ubuntu trusty main" | sudo tee -a /etc/apt/sources.list
- run: - run:
name: Make APT cache folder name: Make APT cache folder
command: mkdir -p /root/.cache/apt/archives/partial command: mkdir -p /home/circleci/.cache/apt/archives/partial
- run: - run:
name: Make APT cache usage by _apt 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: - run:
name: Update APT listing name: Update APT listing
command: apt-get -qq update command: sudo apt-get -qq update
- run: - run:
name: Support S3 upload name: Support S3 upload
command: apt-get -qq -y install ca-certificates command: sudo apt-get -qq -y install ca-certificates
- restore_cache: - restore_cache:
keys: keys:
- v1-SRB2-APT - v1-SRB2-APT
- run: - run:
name: Install SDK name: Uninstall amd64 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 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: - run:
name: make md5sum 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: - save_cache:
key: v1-SRB2-APT-{{ checksum "/root/.cache/apt_archives.md5" }} key: v1-SRB2-APT-{{ checksum "/home/circleci/.cache/apt_archives.md5" }}
paths: paths:
- /root/.cache/apt - /home/circleci/.cache/apt
- checkout - checkout
- run: - run:
name: Compile without network support name: Compile without network support
@ -78,9 +81,9 @@ jobs:
name: Compile name: Compile
command: make -C src LINUX=1 ERRORMODE=1 -k -j4 command: make -C src LINUX=1 ERRORMODE=1 -k -j4
- store_artifacts: - store_artifacts:
path: /root/SRB2/bin/ path: /home/circleci/SRB2/bin/
destination: bin destination: bin
- save_cache: - save_cache:
key: v1-SRB2-{{ .Branch }}-{{ checksum "make/linux/SDL.deps" }} key: v1-SRB2-{{ .Branch }}-{{ checksum "make/linux/SDL.deps" }}
paths: paths:
- /root/.ccache - /home/circleci/.ccache

4
.gitattributes vendored
View file

@ -1,15 +1,17 @@
#Source code #Source code
/Makefile text=auto
/src/*.c text=auto /src/*.c text=auto
/src/*.h text=auto /src/*.h text=auto
/src/*.s text=auto /src/*.s text=auto
/src/*.m text=auto /src/*.m text=auto
/src/*.xpm text=auto /src/*.xpm text=auto
/src/Makefile text=auto /src/Makefile text=auto
/tools/Makefile text=auto
/src/Make*.cfg text=auto /src/Make*.cfg text=auto
/src/CMakeLists.txt text=auto /src/CMakeLists.txt text=auto
*.mk -whitespace text=auto
# Windows EOL # Windows EOL
*.cs -crlf -whitespace *.cs -crlf -whitespace
*.mk -crlf -whitespace
*.bat -crlf -whitespace *.bat -crlf -whitespace
*.dev -crlf -whitespace *.dev -crlf -whitespace
*.dsp -crlf -whitespace *.dsp -crlf -whitespace

3
.gitignore vendored
View file

@ -22,4 +22,5 @@ Win32_LIB_ASM_Release
/make /make
/bin /bin
/build /build
/build.* /build/*
/CMakeUserPresets.json

434
.gitlab-ci.yml Normal file
View file

@ -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

View file

@ -53,11 +53,15 @@ else()
set(SRB2_CONFIG_SYSTEM_LIBRARIES_DEFAULT OFF) set(SRB2_CONFIG_SYSTEM_LIBRARIES_DEFAULT OFF)
endif() 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( option(
SRB2_CONFIG_SYSTEM_LIBRARIES SRB2_CONFIG_SYSTEM_LIBRARIES
"Link dependencies using CMake's find_package and do not use internal builds" "Link dependencies using CMake's find_package and do not use internal builds"
${SRB2_CONFIG_SYSTEM_LIBRARIES_DEFAULT} ${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). # This option isn't recommended for distribution builds and probably won't work (yet).
cmake_dependent_option( cmake_dependent_option(
SRB2_CONFIG_SHARED_INTERNAL_LIBRARIES 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) 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.") 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 # Enable CCache
# (Set USE_CCACHE=ON to use, CCACHE_OPTIONS for options) # (Set USE_CCACHE=ON to use, CCACHE_OPTIONS for options)
if("${CMAKE_HOST_SYSTEM_NAME}" STREQUAL Windows) if("${CMAKE_HOST_SYSTEM_NAME}" STREQUAL Windows)
@ -108,7 +131,11 @@ if("${SRB2_CONFIG_SYSTEM_LIBRARIES}")
find_package(SDL2_mixer REQUIRED) find_package(SDL2_mixer REQUIRED)
find_package(CURL REQUIRED) find_package(CURL REQUIRED)
find_package(OPENMPT 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() endif()
if(${PROJECT_SOURCE_DIR} MATCHES ${PROJECT_BINARY_DIR}) 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.") message(WARNING "Using clang and CCache: You may want to set environment variable CCACHE_CPP2=yes to prevent include errors during compile.")
endif() 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 # bitness check
set(SRB2_SYSTEM_BITS 0) set(SRB2_SYSTEM_BITS 0)
if(CMAKE_SIZEOF_VOID_P EQUAL 8) 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(CMAKE_PDB_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin")
# Set EXE names so the assets CMakeLists can refer to its target # 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) include_directories(${CMAKE_CURRENT_BINARY_DIR}/src)
@ -152,11 +173,37 @@ add_subdirectory(src)
add_subdirectory(assets) add_subdirectory(assets)
## config.h generation
set(GIT_EXECUTABLE "git" CACHE FILEPATH "Path to git binary") set(GIT_EXECUTABLE "git" CACHE FILEPATH "Path to git binary")
include(GitUtilities) include(GitUtilities)
git_latest_commit(SRB2_COMP_COMMIT "${CMAKE_SOURCE_DIR}")
git_current_branch(SRB2_GIT_BRANCH "${CMAKE_SOURCE_DIR}") if("${SRB2_SDL2_EXE_NAME}" STREQUAL "")
set(SRB2_COMP_BRANCH "${SRB2_GIT_BRANCH}") # cause a reconfigure if the branch changes
set(SRB2_COMP_REVISION "${SRB2_COMP_COMMIT}") get_git_dir(SRB2_GIT_DIR)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/src/config.h.in ${CMAKE_CURRENT_BINARY_DIR}/src/config.h) 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})

29
CMakePresets.json Normal file
View file

@ -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"
}
]
}

View file

@ -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/). [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 ## Dependencies
- NASM (x86 builds only)
- SDL2 (Linux/OS X only) - SDL2 (Linux/OS X only)
- SDL2-Mixer (Linux/OS X only) - SDL2-Mixer (Linux/OS X only)
- libupnp (Linux/OS X only) - libupnp (Linux/OS X only)

View file

@ -1992,24 +1992,6 @@ HW3SOUND for 3D hardware sound support
<Option compilerVar="CC" /> <Option compilerVar="CC" />
</Unit> </Unit>
<Unit filename="src/v_video.h" /> <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"> <Unit filename="src/w_wad.c">
<Option compilerVar="CC" /> <Option compilerVar="CC" />
</Unit> </Unit>

View file

@ -25,9 +25,6 @@
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(PlatformTarget)'=='x86'"> <ItemDefinitionGroup Condition="'$(PlatformTarget)'=='x86'">
<ClCompile>
<PreprocessorDefinitions>USEASM;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link> <Link>
<ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers> <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
</Link> </Link>

View file

@ -5,7 +5,7 @@ Ver=3
IsCpp=0 IsCpp=0
Type=0 Type=0
UnitCount=279 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= CommandLine=
CompilerSettings=00000000000100000111e1 CompilerSettings=00000000000100000111e1
PchHead=-1 PchHead=-1
@ -1473,36 +1473,6 @@ Priority=1000
OverrideBuildCmd=0 OverrideBuildCmd=0
BuildCmd= 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] [Unit152]
FileName=src\y_inter.h FileName=src\y_inter.h
Folder=H_Hud Folder=H_Hud
@ -1543,26 +1513,6 @@ Priority=1000
OverrideBuildCmd=0 OverrideBuildCmd=0
BuildCmd= 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] [Unit159]
FileName=src\lzf.h FileName=src\lzf.h
Folder=W_Wad Folder=W_Wad

29
alias-bootstrap.sh Executable file
View file

@ -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'

View file

@ -1,4 +1,4 @@
version: 2.2.10.{branch}-{build} version: 2.2.13.{branch}-{build}
os: MinGW os: MinGW
environment: environment:
@ -7,8 +7,6 @@ environment:
# c:\mingw-w64 i686 has gcc 6.3.0, so use c:\msys64 7.3.0 instead # c:\mingw-w64 i686 has gcc 6.3.0, so use c:\msys64 7.3.0 instead
MINGW_SDK: c:\msys64\mingw32 MINGW_SDK: c:\msys64\mingw32
CFLAGS: -Wno-implicit-fallthrough 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_ZIP: upx391w
UPX_URL: http://upx.sourceforge.net/download/upx391w.zip UPX_URL: http://upx.sourceforge.net/download/upx391w.zip
CCACHE_EXE: ccache.exe CCACHE_EXE: ccache.exe
@ -40,17 +38,12 @@ environment:
ASSET_CLEAN: 0 ASSET_CLEAN: 0
cache: cache:
- nasm-2.12.01.zip
- upx391w.zip - upx391w.zip
- ccache.exe - ccache.exe
- C:\Users\appveyor\.ccache - C:\Users\appveyor\.ccache
- C:\Users\appveyor\srb2_cache - C:\Users\appveyor\srb2_cache
install: 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" - if not exist "%UPX_ZIP%.zip" appveyor DownloadFile "%UPX_URL%" -FileName "%UPX_ZIP%.zip"
- 7z x -y "%UPX_ZIP%.zip" -o%TMP% >null - 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 - 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: before_build:
- set "Path=%MINGW_SDK%\bin;%Path%" - set "Path=%MINGW_SDK%\bin;%Path%"
- mingw32-make --version - mingw32-make --version
- nasm -v
- if not [%NOUPX%] == [1] ( upx -V ) - if not [%NOUPX%] == [1] ( upx -V )
- ccache -V - ccache -V
- ccache -s - ccache -s

View file

@ -29,6 +29,7 @@ set(SRB2_ASSETS_GAME
"srb2.pk3" "srb2.pk3"
"player.dta" "player.dta"
"zones.pk3" "zones.pk3"
"patch.pk3"
"music.dta" "music.dta"
"models.dat" "models.dat"
) )

32
cmake/Comptime.cmake Normal file
View file

@ -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")

View file

@ -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)

View file

@ -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)

View file

@ -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)

View file

@ -6,38 +6,54 @@ endif()
set(__GitUtilities ON) set(__GitUtilities ON)
function(git_describe variable path) macro(_git_command)
execute_process(COMMAND "${GIT_EXECUTABLE}" "describe" execute_process(
WORKING_DIRECTORY "${path}" COMMAND "${GIT_EXECUTABLE}" ${ARGN}
RESULT_VARIABLE result WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
OUTPUT_VARIABLE output OUTPUT_VARIABLE output
ERROR_QUIET ERROR_QUIET
OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_STRIP_TRAILING_WHITESPACE
) )
endmacro()
macro(_git_easy_command)
_git_command(${ARGN})
set(${variable} "${output}" PARENT_SCOPE)
endmacro()
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) set(${variable} "${output}" PARENT_SCOPE)
endfunction() endfunction()
function(git_current_branch variable path) function(git_latest_commit variable)
execute_process(COMMAND ${GIT_EXECUTABLE} "symbolic-ref" "--short" "HEAD" _git_easy_command(rev-parse --short HEAD)
WORKING_DIRECTORY "${path}"
RESULT_VARIABLE result
OUTPUT_VARIABLE output
ERROR_QUIET
OUTPUT_STRIP_TRAILING_WHITESPACE
)
set(${variable} "${output}" PARENT_SCOPE)
endfunction() endfunction()
function(git_latest_commit variable path) function(git_working_tree_dirty variable)
execute_process(COMMAND ${GIT_EXECUTABLE} "rev-parse" "--short" "HEAD" _git_command(status --porcelain -uno)
WORKING_DIRECTORY "${path}"
RESULT_VARIABLE result
OUTPUT_VARIABLE output
ERROR_QUIET
OUTPUT_STRIP_TRAILING_WHITESPACE
)
set(${variable} "${output}" PARENT_SCOPE) if(output STREQUAL "")
endfunction() 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()

View file

@ -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()

View file

@ -3,12 +3,12 @@ ifdef ComSpec
COMSPEC=$(ComSpec) COMSPEC=$(ComSpec)
endif endif
ifdef COMSPEC ifdef COMSPEC
OBJCOPY=objcopy.exe OBJCOPY?=objcopy.exe
OBJDUMP=objdump.exe OBJDUMP?=objdump.exe
GZIP?=gzip.exe GZIP?=gzip.exe
else else
OBJCOPY=objcopy OBJCOPY?=objcopy
OBJDUMP=objdump OBJDUMP?=objdump
GZIP?=gzip GZIP?=gzip
endif endif
DBGNAME=$(BIN).debug DBGNAME=$(BIN).debug

File diff suppressed because it is too large Load diff

View file

@ -15,7 +15,7 @@ common
ignoredextensions = "wad pk3 pk7 bak backup1 backup2 backup3 zip rar 7z"; ignoredextensions = "wad pk3 pk7 bak backup1 backup2 backup3 zip rar 7z";
// Default testing parameters // Default testing parameters
testparameters = "-file \"%AP\" \"%F\" -warp %L"; testparameters = "-folder \"%AF\" -file \"%AA\" \"%F\" -warp %L";
testshortpaths = true; testshortpaths = true;
// Action special help // Action special help
@ -26,7 +26,7 @@ common
generalizedsectors = true; generalizedsectors = true;
// Maximum safe map size check (0 means skip check) // Maximum safe map size check (0 means skip check)
safeboundary = 1; safeboundary = 0;
// Map boundaries. Map objects can only be placed within these boundaries // Map boundaries. Map objects can only be placed within these boundaries
leftboundary = -32768; leftboundary = -32768;
@ -40,6 +40,8 @@ common
defaultflatscale = 1.0f; defaultflatscale = 1.0f;
scaledtextureoffsets = true; scaledtextureoffsets = true;
maxcolormapalpha = 25;
// Thing number for start position in 3D Mode // Thing number for start position in 3D Mode
start3dmode = 3328; start3dmode = 3328;
@ -68,137 +70,6 @@ common
} }
} }
mapformat_doom
{
// The format interface handles the map data format
formatinterface = "DoomMapSetIO";
// Default nodebuilder configurations
defaultsavecompiler = "zennode_normal";
defaulttestcompiler = "zennode_fast";
/*
GAME DETECT PATTERN
Used to guess the game for which a WAD file is made.
1 = One of these lumps must exist
2 = None of these lumps must exist
3 = All of these lumps must exist
*/
gamedetect
{
EXTENDED = 2;
BEHAVIOR = 2;
E#M# = 2;
MAP?? = 1;
}
/*
MAP LUMP NAMES
Map lumps are loaded with the map as long as they are right after each other. When the editor
meets a lump which is not defined in this list it will ignore the map if not satisfied.
The order of items defines the order in which lumps will be written to WAD file on save.
To indicate the map header lump, use ~MAP
Legenda:
required = Lump is required to exist.
blindcopy = Lump will be copied along with the map blindly. (usefull for lumps Doom Builder doesn't use)
nodebuild = The nodebuilder generates this lump.
allowempty = The nodebuilder is allowed to leave this lump empty.
script = This lump is a text-based script. Specify the filename of the script configuration to use.
*/
maplumpnames
{
include("SRB222_misc.cfg", "doommaplumpnames");
}
// When this is set to true, sectors with the same tag will light up when a line is highlighted
linetagindicatesectors = true;
// Special linedefs
include("SRB222_misc.cfg", "speciallinedefs");
// Default flags for first new thing
defaultthingflags
{
}
// DEFAULT SECTOR BRIGHTNESS LEVELS
sectorbrightness
{
include("SRB222_misc.cfg", "sectorbrightness");
}
// SECTOR TYPES
sectortypes
{
include("SRB222_sectors.cfg", "sectortypes");
}
// GENERALISED SECTOR TYPES
gen_sectortypes
{
include("SRB222_sectors.cfg", "gen_sectortypes");
}
// LINEDEF FLAGS
linedefflags
{
include("SRB222_misc.cfg", "linedefflags");
}
// Linedef flags UDMF translation table
// This is needed for copy/paste and prefabs to work properly
// When the UDMF field name is prefixed with ! it is inverted
linedefflagstranslation
{
include("SRB222_misc.cfg", "linedefflagstranslation");
}
// LINEDEF ACTIVATIONS
linedefactivations
{
}
// LINEDEF TYPES
linedeftypes
{
include("SRB222_linedefs.cfg", "doom");
}
// THING FLAGS
thingflags
{
include("SRB222_misc.cfg", "thingflags");
}
// Thing flags UDMF translation table
// This is needed for copy/paste and prefabs to work properly
// When the UDMF field name is prefixed with ! it is inverted
thingflagstranslation
{
include("SRB222_misc.cfg", "thingflagstranslation");
}
// THING FLAGS ERROR MASK
// Mask for the thing flags which indicates the options
// that make the same thing appear in the same modes
thingflagsmask1 = 7; // 1 + 2 + 4
thingflagsmask2 = 0;
// THING TYPES
thingtypes
{
include("SRB222_things.cfg", "doom");
}
}
mapformat_udmf mapformat_udmf
{ {
// The format interface handles the map data format // The format interface handles the map data format
@ -222,9 +93,17 @@ mapformat_udmf
{ {
include("SRB222_misc.cfg", "universalfields"); include("SRB222_misc.cfg", "universalfields");
} }
// Disable Doom-related modes that don't make sense for SRB2
soundsupport = false;
automapsupport = false;
// When this is set to true, sectors with the same tag will light up when a line is highlighted // When this is set to true, sectors with the same tag will light up when a line is highlighted
linetagindicatesectors = false; linetagindicatesectors = false;
localsidedeftextureoffsets = true;
distinctfloorandceilingbrightness = true;
planeequationsupport = true;
// Special linedefs // Special linedefs
include("SRB222_misc.cfg", "speciallinedefs_udmf"); include("SRB222_misc.cfg", "speciallinedefs_udmf");
@ -240,6 +119,11 @@ mapformat_udmf
include("SRB222_misc.cfg", "sectorflags"); include("SRB222_misc.cfg", "sectorflags");
} }
sectorflagscategories
{
include("SRB222_misc.cfg", "sectorflagscategories");
}
// DEFAULT SECTOR BRIGHTNESS LEVELS // DEFAULT SECTOR BRIGHTNESS LEVELS
sectorbrightness sectorbrightness
{ {
@ -247,6 +131,7 @@ mapformat_udmf
} }
damagetypes = "Generic Water Fire Lava Electric Spike DeathPitTilt DeathPitNoTilt Instakill SpecialStage"; damagetypes = "Generic Water Fire Lava Electric Spike DeathPitTilt DeathPitNoTilt Instakill SpecialStage";
triggerertypes = "Player AllPlayers Mobj";
// LINEDEF FLAGS // LINEDEF FLAGS
linedefflags linedefflags
@ -282,7 +167,6 @@ mapformat_udmf
// How to compare thing flags (for the stuck things error checker) // How to compare thing flags (for the stuck things error checker)
thingflagscompare thingflagscompare
{ {
include("UDMF_misc.cfg", "thingflagscompare");
} }
// THING TYPES // THING TYPES

File diff suppressed because it is too large Load diff

View file

@ -1,24 +1,3 @@
linedefflags
{
1 = "[0] Impassable";
2 = "[1] Block Enemies";
4 = "[2] Double-Sided";
8 = "[3] Upper Unpegged";
16 = "[4] Lower Unpegged";
32 = "[5] Slope Skew (E1)";
64 = "[6] Not Climbable";
128 = "[7] No Midtexture Skew (E2)";
256 = "[8] Peg Midtexture (E3)";
512 = "[9] Solid Midtexture (E4)";
1024 = "[10] Repeat Midtexture (E5)";
2048 = "[11] Netgame Only";
4096 = "[12] No Netgame";
8192 = "[13] Effect 6";
16384 = "[14] Bouncy Wall";
32768 = "[15] Transfer Line";
}
// Linedef flags UDMF translation table // Linedef flags UDMF translation table
// This is needed for copy/paste and prefabs to work properly // This is needed for copy/paste and prefabs to work properly
// When the UDMF field name is prefixed with ! it is inverted // When the UDMF field name is prefixed with ! it is inverted
@ -42,7 +21,6 @@ linedefflagstranslation
32768 = "transfer"; 32768 = "transfer";
} }
linedefflags_udmf linedefflags_udmf
{ {
blocking = "Impassable"; blocking = "Impassable";
@ -74,19 +52,13 @@ linedefrenderstyles
sectorflags sectorflags
{ {
colormapfog = "Fog Planes in Colormap";
colormapfadesprites = "Fade Fullbright in Colormap";
colormapprotected = "Protected Colormap";
flipspecial_nofloor = "No Trigger on Floor Touch";
flipspecial_ceiling = "Trigger on Ceiling Touch";
triggerspecial_touch = "Trigger on Edge Touch";
triggerspecial_headbump = "Trigger on Headbump";
triggerline_plane = "Linedef Trigger Requires Plane Touch";
triggerline_mobj = "Non-Pushables Can Trigger Linedef";
invertprecip = "Invert Precipitation"; invertprecip = "Invert Precipitation";
gravityflip = "Flip Objects in Reverse Gravity"; gravityflip = "Flip Objects in Reverse Gravity";
heatwave = "Heat Wave"; heatwave = "Heat Wave";
noclipcamera = "Intangible to the Camera"; noclipcamera = "Intangible to the Camera";
colormapfog = "Fog Planes";
colormapfadesprites = "Fade Fullbright";
colormapprotected = "Protected from Tagging";
outerspace = "Space Countdown"; outerspace = "Space Countdown";
doublestepup = "Ramp Sector (double step-up/down)"; doublestepup = "Ramp Sector (double step-up/down)";
nostepdown = "Non-Ramp Sector (No step-down)"; nostepdown = "Non-Ramp Sector (No step-down)";
@ -104,23 +76,59 @@ sectorflags
zoomtubeend = "Zoom Tube End"; zoomtubeend = "Zoom Tube End";
finishline = "Circuit Finish Line"; finishline = "Circuit Finish Line";
ropehang = "Rope Hang"; ropehang = "Rope Hang";
jumpflip = "Flip Gravity on Jump";
gravityoverride = "Make Reverse Gravity Temporary";
flipspecial_nofloor = "No Trigger on Floor Touch";
flipspecial_ceiling = "Trigger on Ceiling Touch";
triggerspecial_touch = "Trigger on Edge Touch";
triggerspecial_headbump = "Trigger on Headbump";
triggerline_plane = "Linedef Trigger Requires Plane Touch";
triggerline_mobj = "Non-Pushables Can Trigger Linedef";
} }
thingflags sectorflagscategories
{ {
1 = "[1] Extra"; invertprecip = "regular";
2 = "[2] Flip"; gravityflip = "regular";
4 = "[4] Special"; heatwave = "regular";
8 = "[8] Ambush"; noclipcamera = "regular";
colormapfog = "colormap";
colormapfadesprites = "colormap";
colormapprotected = "colormap";
outerspace = "special";
doublestepup = "special";
nostepdown = "special";
speedpad = "special";
starpostactivator = "special";
exit = "special";
specialstagepit = "special";
returnflag = "special";
redteambase = "special";
blueteambase = "special";
fan = "special";
supertransform = "special";
forcespin = "special";
zoomtubestart = "special";
zoomtubeend = "special";
finishline = "special";
ropehang = "special";
jumpflip = "special";
gravityoverride = "special";
flipspecial_nofloor = "trigger";
flipspecial_ceiling = "trigger";
triggerspecial_touch = "trigger";
triggerspecial_headbump = "trigger";
triggerline_plane = "trigger";
triggerline_mobj = "trigger";
} }
// THING FLAGS // THING FLAGS
thingflags_udmf thingflags_udmf
{ {
flip = "Flip"; flip = "Flip";
absolutez = "Absolute Z height";
} }
// Thing flags UDMF translation table // Thing flags UDMF translation table
// This is needed for copy/paste and prefabs to work properly // This is needed for copy/paste and prefabs to work properly
// When the UDMF field name is prefixed with ! it is inverted // When the UDMF field name is prefixed with ! it is inverted
@ -130,9 +138,9 @@ thingflagstranslation
2 = "flip"; 2 = "flip";
4 = "special"; 4 = "special";
8 = "ambush"; 8 = "ambush";
16 = "absolutez";
} }
// DEFAULT SECTOR BRIGHTNESS LEVELS // DEFAULT SECTOR BRIGHTNESS LEVELS
sectorbrightness sectorbrightness
{ {
@ -171,6 +179,8 @@ sectorbrightness
0; 0;
} }
numbrightnesslevels = 32;
/* /*
TEXTURES AND FLAT SOURCES TEXTURES AND FLAT SOURCES
This tells Doom Builder where to find the information for textures This tells Doom Builder where to find the information for textures
@ -221,145 +231,18 @@ universalfields
{ {
sector sector
{ {
lightalpha
{
type = 0;
default = 25;
}
fadealpha
{
type = 0;
default = 25;
}
fadestart
{
type = 0;
default = 0;
}
fadeend
{
type = 0;
default = 33;
}
foglighting
{
type = 3;
default = false;
}
friction
{
type = 1;
default = 0.90625;
}
triggertag
{
type = 15;
default = 0;
}
triggerer
{
type = 2;
default = "Player";
}
} }
linedef linedef
{ {
arg5
{
type = 0;
default = 0;
}
arg6
{
type = 0;
default = 0;
}
arg7
{
type = 0;
default = 0;
}
arg8
{
type = 0;
default = 0;
}
arg9
{
type = 0;
default = 0;
}
stringarg0
{
type = 2;
default = "";
}
stringarg1
{
type = 2;
default = "";
}
executordelay
{
type = 0;
default = 0;
}
} }
sidedef sidedef
{ {
repeatcnt
{
type = 0;
default = 0;
}
} }
thing thing
{ {
arg5
{
type = 0;
default = 0;
}
arg6
{
type = 0;
default = 0;
}
arg7
{
type = 0;
default = 0;
}
arg8
{
type = 0;
default = 0;
}
arg9
{
type = 0;
default = 0;
}
stringarg0
{
type = 2;
default = "";
}
stringarg1
{
type = 2;
default = "";
}
} }
} }
@ -378,87 +261,6 @@ allowempty = The nodebuilder is allowed to leave this lump empty.
scriptbuild = This lump is a text-based script, which should be compiled using current script compiler; scriptbuild = This lump is a text-based script, which should be compiled using current script compiler;
script = This lump is a text-based script. Specify the filename of the script configuration to use. script = This lump is a text-based script. Specify the filename of the script configuration to use.
*/ */
doommaplumpnames
{
~MAP
{
required = true;
blindcopy = true;
nodebuild = false;
}
THINGS
{
required = true;
nodebuild = true;
allowempty = true;
}
LINEDEFS
{
required = true;
nodebuild = true;
allowempty = false;
}
SIDEDEFS
{
required = true;
nodebuild = true;
allowempty = false;
}
VERTEXES
{
required = true;
nodebuild = true;
allowempty = false;
}
SEGS
{
required = false;
nodebuild = true;
allowempty = false;
}
SSECTORS
{
required = false;
nodebuild = true;
allowempty = false;
}
NODES
{
required = false;
nodebuild = true;
allowempty = false;
}
SECTORS
{
required = true;
nodebuild = true;
allowempty = false;
}
REJECT
{
required = false;
nodebuild = true;
allowempty = false;
}
BLOCKMAP
{
required = false;
nodebuild = true;
allowempty = true;
}
}
udmfmaplumpnames udmfmaplumpnames
{ {
ZNODES ZNODES
@ -682,48 +484,32 @@ thingsfilters
} }
//filter3
//{
// name = "Normal Gravity";
// category = "";
// type = -1;
//
// fields
// {
// 2 = false;
// }
//}
filter3 //filter4
{ //{
name = "Normal Gravity"; // name = "Reverse Gravity";
category = ""; // category = "";
type = -1; // type = -1;
//
fields // fields
{ // {
2 = false; // 2 = true;
} // }
//}
}
filter4
{
name = "Reverse Gravity";
category = "";
type = -1;
fields
{
2 = true;
}
}
} }
// Special linedefs // Special linedefs
speciallinedefs
{
soundlinedefflag = 64; // See linedefflags
singlesidedflag = 1; // See linedefflags
doublesidedflag = 4; // See linedefflags
impassableflag = 1;
upperunpeggedflag = 8;
lowerunpeggedflag = 16;
repeatmidtextureflag = 1024;
pegmidtextureflag = 256;
}
speciallinedefs_udmf speciallinedefs_udmf
{ {
soundlinedefflag = "noclimb"; soundlinedefflag = "noclimb";
@ -734,6 +520,8 @@ speciallinedefs_udmf
lowerunpeggedflag = "dontpegbottom"; lowerunpeggedflag = "dontpegbottom";
repeatmidtextureflag = "wrapmidtex"; repeatmidtextureflag = "wrapmidtex";
pegmidtextureflag = "midpeg"; pegmidtextureflag = "midpeg";
slopeskewflag = "skewtd";
nomidtextureskewflag = "noskew";
} }
scriptlumpnames scriptlumpnames

View file

@ -1,107 +0,0 @@
sectortypes
{
0 = "Normal";
1 = "Damage";
2 = "Damage (Water)";
3 = "Damage (Fire)";
4 = "Damage (Electrical)";
5 = "Spikes";
6 = "Death Pit (Camera Tilt)";
7 = "Death Pit (No Camera Tilt)";
8 = "Instant Kill";
9 = "Ring Drainer (Floor Touch)";
10 = "Ring Drainer (Anywhere in Sector)";
11 = "Special Stage Damage";
12 = "Space Countdown";
13 = "Ramp Sector (double step-up/down)";
14 = "Non-Ramp Sector (no step-down)";
15 = "Bouncy FOF <deprecated>";
16 = "Trigger Line Ex. (Pushable Objects)";
32 = "Trigger Line Ex. (Anywhere, All Players)";
48 = "Trigger Line Ex. (Floor Touch, All Players)";
64 = "Trigger Line Ex. (Anywhere in Sector)";
80 = "Trigger Line Ex. (Floor Touch)";
96 = "Trigger Line Ex. (Emerald Check) <deprecated>";
112 = "Trigger Line Ex. (NiGHTS Mare) <deprecated>";
128 = "Check for Linedef Executor on FOFs";
144 = "Egg Capsule";
160 = "Special Stage Time/Spheres Parameters <deprecated>";
176 = "Custom Global Gravity <deprecated>";
1280 = "Speed Pad";
1536 = "Flip Gravity on Jump";
4096 = "Star Post Activator";
8192 = "Exit/Special Stage Pit/Return Flag";
12288 = "CTF Red Team Base";
16384 = "CTF Blue Team Base";
20480 = "Fan Sector";
24576 = "Super Sonic Transform";
28672 = "Force Spin";
32768 = "Zoom Tube Start";
36864 = "Zoom Tube End";
40960 = "Circuit Finish Line";
45056 = "Rope Hang";
49152 = "Intangible to the Camera";
}
gen_sectortypes
{
first
{
0 = "Normal";
1 = "Damage";
2 = "Damage (Water)";
3 = "Damage (Fire)";
4 = "Damage (Electrical)";
5 = "Spikes";
6 = "Death Pit (Camera Tilt)";
7 = "Death Pit (No Camera Tilt)";
8 = "Instant Kill";
9 = "Ring Drainer (Floor Touch)";
10 = "Ring Drainer (Anywhere in Sector)";
11 = "Special Stage Damage";
12 = "Space Countdown";
13 = "Ramp Sector (double step-up/down)";
14 = "Non-Ramp Sector (no step-down)";
15 = "Bouncy FOF <deprecated>";
}
second
{
0 = "Normal";
16 = "Trigger Line Ex. (Pushable Objects)";
32 = "Trigger Line Ex. (Anywhere, All Players)";
48 = "Trigger Line Ex. (Floor Touch, All Players)";
64 = "Trigger Line Ex. (Anywhere in Sector)";
80 = "Trigger Line Ex. (Floor Touch)";
96 = "Trigger Line Ex. (Emerald Check) <deprecated>";
112 = "Trigger Line Ex. (NiGHTS Mare) <deprecated>";
128 = "Check for Linedef Executor on FOFs";
144 = "Egg Capsule";
160 = "Special Stage Time/Spheres Parameters <deprecated>";
176 = "Custom Global Gravity <deprecated>";
}
third
{
0 = "Normal";
1280 = "Speed Pad";
1536 = "Flip Gravity on Jump";
}
fourth
{
0 = "Normal";
4096 = "Star Post Activator";
8192 = "Exit/Special Stage Pit/Return Flag";
12288 = "CTF Red Team Base";
16384 = "CTF Blue Team Base";
20480 = "Fan Sector";
24576 = "Super Sonic Transform";
28672 = "Force Spin";
32768 = "Zoom Tube Start";
36864 = "Zoom Tube End";
40960 = "Circuit Finish Line";
45056 = "Rope Hang";
49152 = "Intangible to the Camera";
}
}

File diff suppressed because it is too large Load diff

View file

@ -1,32 +0,0 @@
/************************************************************************\
Ultimate Doom Builder Game Configuration for Sonic Robo Blast 2 Version 2.2
\************************************************************************/
// This is required to prevent accidental use of a different configuration
type = "Doom Builder 2 Game Configuration";
// This is the title to show for this game
game = "Sonic Robo Blast 2 - 2.2 (Doom format)";
// This is the simplified game engine/sourceport name
engine = "zdoom";
// Settings common to all games and all map formats
include("Includes\\SRB222_common.cfg", "common");
// Settings common to Doom map format
include("Includes\\SRB222_common.cfg", "mapformat_doom");
include("Includes\\Game_SRB222.cfg");
// Script lumps detection
scriptlumpnames
{
include("Includes\\SRB222_misc.cfg", "scriptlumpnames");
}
//Default things filters
thingsfilters
{
include("Includes\\SRB222_misc.cfg", "thingsfilters");
}

View file

@ -76,7 +76,7 @@ LOCAL_SRC_FILES := am_map.c \
android/i_system.c \ android/i_system.c \
android/i_video.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 LOCAL_MODULE := libsrb2

View file

@ -1,23 +1,150 @@
add_executable(SRB2SDL2 MACOSX_BUNDLE WIN32) include(clang-tidy-default)
if("${CMAKE_COMPILER_IS_GNUCC}" AND "${CMAKE_SYSTEM_NAME}" MATCHES "Windows" AND NOT "${SRB2_CONFIG_SYSTEM_LIBRARIES}" AND NOT "${SRB2_CONFIG_SHARED_INTERNAL_LIBRARIES}") add_executable(SRB2SDL2 MACOSX_BUNDLE WIN32
# On MinGW with internal libraries, link the standard library statically comptime.c
target_link_options(SRB2SDL2 PRIVATE "-static") 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
)
# 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
)
# 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)
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() endif()
# Core sources target_compile_features(SRB2SDL2 PRIVATE c_std_11 cxx_std_17)
target_sourcefile(c)
target_sources(SRB2SDL2 PRIVATE comptime.c md5.c config.h.in)
set(SRB2_ASM_SOURCES vid_copy.s)
set(SRB2_NASM_SOURCES tmap_mmx.nas tmap.nas)
### Configuration ### 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 set(SRB2_CONFIG_DEV_BUILD OFF CACHE BOOL
"Compile a development build of SRB2.") "Compile a development build of SRB2.")
@ -74,33 +201,6 @@ if("${SRB2_CONFIG_HWRENDER}")
endif() endif()
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 # Targets
# If using CCACHE, then force it. # If using CCACHE, then force it.
@ -289,6 +389,9 @@ if(SRB2_CONFIG_PROFILEMODE AND "${CMAKE_C_COMPILER_ID}" STREQUAL "GNU")
endif() endif()
add_subdirectory(sdl) add_subdirectory(sdl)
if(SRB2_CONFIG_ENABLE_TESTS)
add_subdirectory(tests)
endif()
# strip debug symbols into separate file when using gcc. # strip debug symbols into separate file when using gcc.
# to be consistent with Makefile, don't generate for OS X. # 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" COMMENT "Copying runtime DLLs"
) )
endif() 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()

View file

@ -47,8 +47,6 @@
# HAVE_MINIUPNPC=1 - Enable automated port forwarding. # HAVE_MINIUPNPC=1 - Enable automated port forwarding.
# Already enabled by default for 32-bit # Already enabled by default for 32-bit
# Windows. # Windows.
# NOASM=1 - Disable hand optimized assembly code for the
# Software renderer.
# NOPNG=1 - Disable PNG graphics support. (TODO: double # NOPNG=1 - Disable PNG graphics support. (TODO: double
# check netplay compatible.) # check netplay compatible.)
# NOCURL=1 - Disable libcurl--HTTP capability. # NOCURL=1 - Disable libcurl--HTTP capability.
@ -88,7 +86,6 @@
# executable. # executable.
# WINDOWSHELL=1 - Use Windows commands. # WINDOWSHELL=1 - Use Windows commands.
# PREFIX= - Prefix to many commands, for cross compiling. # PREFIX= - Prefix to many commands, for cross compiling.
# YASM=1 - Use Yasm instead of NASM assembler.
# STABS=1 - ? # STABS=1 - ?
# ECHO=1 - Print out each command in the build process. # ECHO=1 - Print out each command in the build process.
# NOECHOFILENAMES=1 - Don't print out each that is being # NOECHOFILENAMES=1 - Don't print out each that is being
@ -144,25 +141,9 @@ endif
OBJDUMP_OPTS?=--wide --source --line-numbers OBJDUMP_OPTS?=--wide --source --line-numbers
OBJCOPY:=$(call Prefix,objcopy) OBJCOPY?=$(call Prefix,objcopy)
OBJDUMP:=$(call Prefix,objdump) OBJDUMP?=$(call Prefix,objdump)
WINDRES:=$(call Prefix,windres) 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
GZIP?=gzip GZIP?=gzip
GZIP_OPTS?=-9 -f -n GZIP_OPTS?=-9 -f -n
@ -187,8 +168,6 @@ makedir:=../make
opts:=-DCOMPVERSION -g opts:=-DCOMPVERSION -g
libs:= libs:=
nasm_format:=
# This is a list of variables names, of which if defined, # This is a list of variables names, of which if defined,
# also defines the name as a macro to the compiler. # also defines the name as a macro to the compiler.
passthru_opts:= passthru_opts:=
@ -316,7 +295,6 @@ endif
LD:=$(CC) LD:=$(CC)
cc:=$(cc) $(opts) cc:=$(cc) $(opts)
nasm=$(NASM) $(NASMOPTS) -f $(nasm_format)
ifdef UPX ifdef UPX
upx=$(UPX) $(UPX_OPTS) upx=$(UPX) $(UPX_OPTS)
endif endif
@ -393,7 +371,6 @@ $(objdir)/%.$(1) : %.$(2) | $$$$(@D)/
endef endef
$(eval $(call _recipe,o,c,$(cc) -c -o $$@ $$<)) $(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,o,s,$(cc) $(asflags) -c -o $$@ $$<))
$(eval $(call _recipe,res,rc,$(windres) -i $$< -o $$@)) $(eval $(call _recipe,res,rc,$(windres) -i $$< -o $$@))
@ -414,3 +391,5 @@ ifdef WINDOWSHELL
else else
@: @:
endif endif
#$(warning The handwritten GNU Makefile for SRB2 is deprecated, and may be removed in the future. Please consider switching to CMake.)

View file

@ -56,15 +56,18 @@ endif
# This must have high to low order. # This must have high to low order.
gcc_versions:=\ gcc_versions:=\
102 101\ 132 131 130\
93 92 91\ 123 122 121 120\
84 83 82 81\ 114 113 112 111 110\
75 74 73 72 71\ 105 104 103 102 101 100\
64 63 62 61\ 95 94 93 92 91 90\
55 54 53 52 51\ 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 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 # Automatically set version flag, but not if one was
# manually set. And don't bother if this is a clean only # 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 # 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 # also gcc outputs the information to stderr, so I had to do 2>&1
# this program really doesn't like identifying itself # 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 # check if this is in fact GCC
ifneq (,$(findstring gcc version,$(version))) ifneq (,$(findstring gcc version,$(version)))
# in stark contrast to the name, gcc will give me a nicely formatted version number for free # 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 # Turn version into words of major, minor
v:=$(subst ., ,$(version)) v:=$(subst ., ,$(version))

View file

@ -1,75 +1,72 @@
# #
# Makefile for feature flags. # Makefile for feature flags.
# #
passthru_opts+=\ passthru_opts+=\
NONET NO_IPV6 NOHW NOMD5 NOPOSTPROCESSING\ NONET NO_IPV6 NOHW NOMD5 NOPOSTPROCESSING\
MOBJCONSISTANCY PACKETDROP ZDEBUG\ MOBJCONSISTANCY PACKETDROP ZDEBUG\
HAVE_MINIUPNPC\ HAVE_MINIUPNPC\
# build with debugging information # build with debugging information
ifdef DEBUGMODE ifdef DEBUGMODE
PACKETDROP=1 PACKETDROP=1
opts+=-DPARANOIA -DRANGECHECK opts+=-DPARANOIA -DRANGECHECK
endif endif
ifndef NOHW ifndef NOHW
opts+=-DHWRENDER opts+=-DHWRENDER
sources+=$(call List,hardware/Sourcefile) sources+=$(call List,hardware/Sourcefile)
endif endif
ifndef NOASM ifdef NONET
ifndef NONX86 NOCURL=1
sources+=tmap.nas tmap_mmx.nas endif
opts+=-DUSEASM
endif ifndef NOMD5
endif sources+=md5.c
endif
ifndef NOMD5
sources+=md5.c ifndef NOZLIB
endif ifndef NOPNG
ifdef PNG_PKGCONFIG
ifndef NOZLIB $(eval $(call Use_pkg_config,PNG_PKGCONFIG))
ifndef NOPNG else
ifdef PNG_PKGCONFIG PNG_CONFIG?=$(call Prefix,libpng-config)
$(eval $(call Use_pkg_config,PNG_PKGCONFIG)) $(eval $(call Configure,PNG,$(PNG_CONFIG) \
else $(if $(PNG_STATIC),--static),,--ldflags))
PNG_CONFIG?=$(call Prefix,libpng-config) endif
$(eval $(call Configure,PNG,$(PNG_CONFIG) \ ifdef LINUX
$(if $(PNG_STATIC),--static),,--ldflags)) opts+=-D_LARGEFILE64_SOURCE
endif endif
ifdef LINUX opts+=-DHAVE_PNG
opts+=-D_LARGEFILE64_SOURCE sources+=apng.c
endif endif
opts+=-DHAVE_PNG endif
sources+=apng.c
endif ifndef NONET
endif ifndef NOCURL
CURLCONFIG?=curl-config
ifndef NONET $(eval $(call Configure,CURL,$(CURLCONFIG)))
ifndef NOCURL opts+=-DHAVE_CURL
CURLCONFIG?=curl-config endif
$(eval $(call Configure,CURL,$(CURLCONFIG))) endif
opts+=-DHAVE_CURL
endif ifdef HAVE_MINIUPNPC
endif libs+=-lminiupnpc
endif
ifdef HAVE_MINIUPNPC
libs+=-lminiupnpc # (Valgrind is a memory debugger.)
endif ifdef VALGRIND
VALGRIND_PKGCONFIG?=valgrind
# (Valgrind is a memory debugger.) $(eval $(call Use_pkg_config,VALGRIND))
ifdef VALGRIND ZDEBUG=1
VALGRIND_PKGCONFIG?=valgrind opts+=-DHAVE_VALGRIND
$(eval $(call Use_pkg_config,VALGRIND)) endif
ZDEBUG=1
opts+=-DHAVE_VALGRIND default_packages:=\
endif GME/libgme/LIBGME\
OPENMPT/libopenmpt/LIBOPENMPT\
default_packages:=\ ZLIB/zlib\
GME/libgme/LIBGME\
OPENMPT/libopenmpt/LIBOPENMPT\ $(foreach p,$(default_packages),\
ZLIB/zlib\ $(eval $(call Check_pkg_config,$(p))))
$(foreach p,$(default_packages),\
$(eval $(call Check_pkg_config,$(p))))

View file

@ -9,10 +9,6 @@ opts+=-DUNIXCOMMON -DLUA_USE_POSIX
# instead of addresses # instead of addresses
libs+=-lm -rdynamic libs+=-lm -rdynamic
ifndef nasm_format
nasm_format:=elf -DLINUX
endif
ifndef NOHW ifndef NOHW
opts+=-I/usr/X11R6/include opts+=-I/usr/X11R6/include
libs+=-L/usr/X11R6/lib libs+=-L/usr/X11R6/lib
@ -29,13 +25,12 @@ endif
# Tested by Steel, as of release 2.2.8. # Tested by Steel, as of release 2.2.8.
ifdef FREEBSD ifdef FREEBSD
opts+=-I/usr/X11R6/include -DLINUX -DFREEBSD opts+=-I/usr/X11R6/include -DLINUX -DFREEBSD
libs+=-L/usr/X11R6/lib -lipx -lkvm libs+=-L/usr/X11R6/lib -lkvm -lexecinfo
endif endif
# FIXME: UNTESTED # FIXME: UNTESTED
#ifdef SOLARIS #ifdef SOLARIS
#NOIPX=1 #NOIPX=1
#NOASM=1
#opts+=-I/usr/local/include -I/opt/sfw/include \ #opts+=-I/usr/local/include -I/opt/sfw/include \
# -DSOLARIS -DINADDR_NONE=INADDR_ANY -DBSD_COMP # -DSOLARIS -DINADDR_NONE=INADDR_ANY -DBSD_COMP
#libs+=-L/opt/sfw/lib -lsocket -lnsl #libs+=-L/opt/sfw/lib -lsocket -lnsl

View file

@ -39,7 +39,6 @@ else ifdef SOLARIS # FIXME: UNTESTED
UNIX=1 UNIX=1
platform=solaris platform=solaris
else ifdef CYGWIN32 # FIXME: UNTESTED else ifdef CYGWIN32 # FIXME: UNTESTED
nasm_format=win32
platform=cygwin platform=cygwin
else ifdef MINGW else ifdef MINGW
ifdef MINGW64 ifdef MINGW64

View file

@ -56,13 +56,6 @@ SDL_LDFLAGS?=$(shell $(SDL_CONFIG) \
$(eval $(call Propogate_flags,SDL)) $(eval $(call Propogate_flags,SDL))
endif endif
# use the x86 asm code
ifndef CYGWIN32
ifndef NOASM
USEASM=1
endif
endif
ifdef MINGW ifdef MINGW
ifndef NOSDLMAIN ifndef NOSDLMAIN
SDLMAIN=1 SDLMAIN=1

View file

@ -17,8 +17,6 @@ sources+=win32/Srb2win.rc
opts+=-DSTDC_HEADERS opts+=-DSTDC_HEADERS
libs+=-ladvapi32 -lkernel32 -lmsvcrt -luser32 libs+=-ladvapi32 -lkernel32 -lmsvcrt -luser32
nasm_format:=win32
SDL?=1 SDL?=1
ifndef NOHW ifndef NOHW

View file

@ -64,6 +64,7 @@ r_skins.c
r_sky.c r_sky.c
r_splats.c r_splats.c
r_things.c r_things.c
r_bbox.c
r_textures.c r_textures.c
r_patch.c r_patch.c
r_patchrotation.c r_patchrotation.c
@ -80,8 +81,8 @@ mserv.c
http-mserv.c http-mserv.c
i_tcp.c i_tcp.c
lzf.c lzf.c
vid_copy.s
b_bot.c b_bot.c
u_list.c
lua_script.c lua_script.c
lua_baselib.c lua_baselib.c
lua_mathlib.c lua_mathlib.c

View file

@ -24,7 +24,7 @@ static INT64 start_time; // as microseconds since the epoch
// I should probably return how much memory is remaining // I should probably return how much memory is remaining
// for this process, considering Android's process memory limit. // for this process, considering Android's process memory limit.
UINT32 I_GetFreeMem(UINT32 *total) size_t I_GetFreeMem(size_t *total)
{ {
// what the heck? sysinfo() is partially missing in bionic? // what the heck? sysinfo() is partially missing in bionic?
/* struct sysinfo si; */ /* struct sysinfo si; */
@ -278,4 +278,26 @@ char *I_ClipboardPaste(void)
void I_RegisterSysCommands(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" #include "../sdl/dosstr.c"

View file

@ -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

View file

@ -631,7 +631,8 @@ void B_HandleFlightIndicator(player_t *player)
} }
// otherwise, update its visibility // 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; tails->hnext->flags2 &= ~MF2_DONTDRAW;
else else
tails->hnext->flags2 |= MF2_DONTDRAW; tails->hnext->flags2 |= MF2_DONTDRAW;

View file

@ -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
)

View file

@ -23,3 +23,4 @@ lstring.c
ltable.c ltable.c
ltm.c ltm.c
lvm.c lvm.c
loslib.c

View file

@ -18,6 +18,7 @@ static const luaL_Reg lualibs[] = {
{"", luaopen_base}, {"", luaopen_base},
{LUA_TABLIBNAME, luaopen_table}, {LUA_TABLIBNAME, luaopen_table},
{LUA_IOLIBNAME, luaopen_io}, {LUA_IOLIBNAME, luaopen_io},
{LUA_OSLIBNAME, luaopen_os},
{LUA_STRLIBNAME, luaopen_string}, {LUA_STRLIBNAME, luaopen_string},
{NULL, NULL} {NULL, NULL}
}; };

167
src/blua/loslib.c Normal file
View file

@ -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;
}

View file

@ -24,6 +24,9 @@ LUALIB_API int (luaopen_table) (lua_State *L);
#define LUA_IOLIBNAME "io" #define LUA_IOLIBNAME "io"
LUALIB_API int (luaopen_io) (lua_State *L); LUALIB_API int (luaopen_io) (lua_State *L);
#define LUA_OSLIBNAME "os"
LUALIB_API int (luaopen_os) (lua_State *L);
#define LUA_STRLIBNAME "string" #define LUA_STRLIBNAME "string"
LUALIB_API int (luaopen_string) (lua_State *L); LUALIB_API int (luaopen_string) (lua_State *L);

View file

@ -34,6 +34,7 @@
#include "lua_script.h" #include "lua_script.h"
#include "d_netfil.h" // findfile #include "d_netfil.h" // findfile
#include "r_data.h" // Color_cons_t #include "r_data.h" // Color_cons_t
#include "d_main.h" // D_IsPathAllowed
//======== //========
// protos. // protos.
@ -75,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_YesNo[] = {{0, "No"}, {1, "Yes"}, {0, NULL}};
CV_PossibleValue_t CV_Unsigned[] = {{0, "MIN"}, {999999999, "MAX"}, {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_Natural[] = {{1, "MIN"}, {999999999, "MAX"}, {0, NULL}};
CV_PossibleValue_t CV_TrueFalse[] = {{0, "False"}, {1, "True"}, {0, NULL}};
// Filter consvars by EXECVERSION // Filter consvars by EXECVERSION
// First implementation is 26 (2.1.21), so earlier configs default at 25 (2.1.20) // First implementation is 26 (2.1.21), so earlier configs default at 25 (2.1.20)
@ -679,25 +681,58 @@ static void COM_ExecuteString(char *ptext)
// SCRIPT COMMANDS // 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. /** Creates a command name that replaces another command.
*/ */
static void COM_Alias_f(void) static void COM_Alias_f(void)
{ {
cmdalias_t *a; char *name;
char *zcmd;
char cmd[1024]; char cmd[1024];
size_t i, c; size_t i, c;
if (COM_Argc() < 3) if (COM_Argc() < 3)
{ {
CONS_Printf(M_GetText("alias <name> <command>: create a shortcut command that executes other command(s)\n")); CONS_Printf(M_GetText("alias <name> <command>: create a shortcut command that executes other command(s)\n"));
print_alias();
return; return;
} }
a = ZZ_Alloc(sizeof *a); name = Z_StrDup(COM_Argv(1));
a->next = com_alias;
com_alias = a;
a->name = Z_StrDup(COM_Argv(1));
// copy the rest of the command line // copy the rest of the command line
cmd[0] = 0; // start out with a null string cmd[0] = 0; // start out with a null string
@ -709,8 +744,8 @@ static void COM_Alias_f(void)
strcat(cmd, " "); strcat(cmd, " ");
} }
strcat(cmd, "\n"); strcat(cmd, "\n");
zcmd = Z_StrDup(cmd);
a->value = Z_StrDup(cmd); add_alias(name, zcmd);
} }
/** Prints a line of text to the console. /** Prints a line of text to the console.
@ -781,6 +816,9 @@ static void COM_Exec_f(void)
return; return;
} }
if (!D_CheckPathAllowed(COM_Argv(1), "tried to exec"))
return;
// load file // load file
// Try with Argv passed verbatim first, for back compat // Try with Argv passed verbatim first, for back compat
FIL_ReadFile(COM_Argv(1), &buf); FIL_ReadFile(COM_Argv(1), &buf);
@ -859,9 +897,11 @@ static void COM_Help_f(void)
{ {
CONS_Printf(" Possible values:\n"); CONS_Printf(" Possible values:\n");
if (cvar->PossibleValue == CV_YesNo) 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) 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) else if (cvar->PossibleValue == Color_cons_t)
{ {
for (i = 1; i < numskincolors; ++i) for (i = 1; i < numskincolors; ++i)
@ -1012,7 +1052,7 @@ static void COM_Toggle_f(void)
if (CV_Immutable(cvar)) if (CV_Immutable(cvar))
return; 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)); CONS_Alert(CONS_NOTICE, M_GetText("%s is not a boolean value\n"), COM_Argv(1));
return; return;
@ -1503,12 +1543,12 @@ static void Setvalue(consvar_t *var, const char *valstr, boolean stealth)
goto found; goto found;
} }
// Not found ... but wait, there's hope! // 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; overrideval = -1;
if (!stricmp(valstr, "on") || !stricmp(valstr, "yes")) if (!stricmp(valstr, "on") || !stricmp(valstr, "yes") || !stricmp(valstr, "true"))
overrideval = 1; overrideval = 1;
else if (!stricmp(valstr, "off") || !stricmp(valstr, "no")) else if (!stricmp(valstr, "off") || !stricmp(valstr, "no") || !stricmp(valstr, "false"))
overrideval = 0; overrideval = 0;
if (overrideval != -1) if (overrideval != -1)

View file

@ -177,6 +177,7 @@ extern CV_PossibleValue_t CV_OnOff[];
extern CV_PossibleValue_t CV_YesNo[]; extern CV_PossibleValue_t CV_YesNo[];
extern CV_PossibleValue_t CV_Unsigned[]; extern CV_PossibleValue_t CV_Unsigned[];
extern CV_PossibleValue_t CV_Natural[]; extern CV_PossibleValue_t CV_Natural[];
extern CV_PossibleValue_t CV_TrueFalse[];
// Filter consvars by version // Filter consvars by version
extern consvar_t cv_execversion; extern consvar_t cv_execversion;

View file

@ -11,6 +11,9 @@
#include "config.h" #include "config.h"
const char *compbranch = SRB2_COMP_BRANCH; const char *compbranch = SRB2_COMP_BRANCH;
const char *comprevision = SRB2_COMP_REVISION; 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)) #elif (defined(COMPVERSION))
#include "comptime.h" #include "comptime.h"
@ -21,5 +24,12 @@ const char *comprevision = "illegal";
#endif #endif
const int compuncommitted =
#if (defined(COMPVERSION_UNCOMMITTED))
1;
#else
0;
#endif
const char *compdate = __DATE__; const char *compdate = __DATE__;
const char *comptime = __TIME__; const char *comptime = __TIME__;

View file

@ -11,8 +11,18 @@
#ifdef CMAKECONFIG #ifdef CMAKECONFIG
#define SRB2_COMP_REVISION "${SRB2_COMP_REVISION}" #define SRB2_COMP_REVISION "${SRB2_COMP_REVISION}"
#define SRB2_COMP_BRANCH "${SRB2_COMP_BRANCH}" #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 #endif
@ -27,12 +37,15 @@
* Last updated 2020 / 10 / 02 - v2.2.8 - patch.pk3 * Last updated 2020 / 10 / 02 - v2.2.8 - patch.pk3
* Last updated 2021 / 05 / 06 - v2.2.9 - patch.pk3 & zones.pk3 * Last updated 2021 / 05 / 06 - v2.2.9 - patch.pk3 & zones.pk3
* Last updated 2022 / 03 / 06 - v2.2.10 - main assets * 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_SRB2_PK3 "ad911f29a28a18968ee5b2d11c2acb39"
#define ASSET_HASH_ZONES_PK3 "86ae55cae4e0a93ceda868635706a093" #define ASSET_HASH_ZONES_PK3 "1c8adf8d079ecb87d00081f158acf3c7"
#define ASSET_HASH_PLAYER_DTA "2e7aaae8a6b1b77d90ffe7606ceadb6c" #define ASSET_HASH_PLAYER_DTA "2e7aaae8a6b1b77d90ffe7606ceadb6c"
#ifdef USE_PATCH_DTA #ifdef USE_PATCH_DTA
#define ASSET_HASH_PATCH_PK3 "7d467a883f7887b3c311798ee2f56b6a" #define ASSET_HASH_PATCH_PK3 "3c7b73f34af7e9a7bceb2d5260f76172"
#endif #endif
#endif #endif

View file

@ -61,7 +61,7 @@ static boolean con_started = false; // console has been initialised
static boolean con_forcepic = true; // at startup toggle console translucency when first off static boolean con_forcepic = true; // at startup toggle console translucency when first off
boolean con_recalc; // set true when screen size has changed boolean con_recalc; // set true when screen size has changed
static tic_t con_tick; // console ticker for anim or blinking prompt cursor static tic_t con_tick; // console ticker for blinking prompt cursor
// con_scrollup should use time (currenttime - lasttime).. // con_scrollup should use time (currenttime - lasttime)..
static boolean consoletoggle; // true when console key pushed, ticker will handle static boolean consoletoggle; // true when console key pushed, ticker will handle
@ -72,8 +72,8 @@ static INT32 con_curlines; // vid lines currently used by console
INT32 con_clipviewtop; // (useless) INT32 con_clipviewtop; // (useless)
static INT32 con_hudlines; // number of console heads up message lines static UINT8 con_hudlines; // number of console heads up message lines
static INT32 con_hudtime[MAXHUDLINES]; // remaining time of display for hud msg 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 INT32 con_clearlines; // top screen lines to refresh when view reduced
boolean con_hudupdate; // when messages scroll, we need a backgrnd refresh boolean con_hudupdate; // when messages scroll, we need a backgrnd refresh
@ -110,6 +110,7 @@ static void CON_RecalcSize(void);
static void CON_ChangeHeight(void); static void CON_ChangeHeight(void);
static void CON_DrawBackpic(void); static void CON_DrawBackpic(void);
static void CONS_height_Change(void);
static void CONS_hudlines_Change(void); static void CONS_hudlines_Change(void);
static void CONS_backcolor_Change(void); static void CONS_backcolor_Change(void);
@ -125,10 +126,13 @@ static void CONS_backcolor_Change(void);
static char con_buffer[CON_BUFFERSIZE]; static char con_buffer[CON_BUFFERSIZE];
// how many seconds the hud messages lasts on the screen // 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 // 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 // number of lines console move per frame
// (con_speed needs a limit, apparently) // (con_speed needs a limit, apparently)
@ -136,7 +140,7 @@ static CV_PossibleValue_t speed_cons_t[] = {{0, "MIN"}, {64, "MAX"}, {0, NULL}};
static consvar_t cons_speed = CVAR_INIT ("con_speed", "8", CV_SAVE, speed_cons_t, NULL); static consvar_t cons_speed = CVAR_INIT ("con_speed", "8", CV_SAVE, speed_cons_t, NULL);
// percentage of screen height to use for console // percentage of screen height to use for console
static consvar_t cons_height = CVAR_INIT ("con_height", "50", CV_SAVE, CV_Unsigned, NULL); static consvar_t cons_height = CVAR_INIT ("con_height", "50", CV_CALL|CV_SAVE, CV_Unsigned, CONS_height_Change);
static CV_PossibleValue_t backpic_cons_t[] = {{0, "translucent"}, {1, "picture"}, {0, NULL}}; static CV_PossibleValue_t backpic_cons_t[] = {{0, "translucent"}, {1, "picture"}, {0, NULL}};
// whether to use console background picture, or translucent mode // whether to use console background picture, or translucent mode
@ -156,6 +160,18 @@ consvar_t cons_backcolor = CVAR_INIT ("con_backcolor", "Green", CV_CALL|CV_SAVE,
static void CON_Print(char *msg); static void CON_Print(char *msg);
// Change the console height on demand
//
static void CONS_height_Change(void)
{
Lock_state();
if (con_destlines > 0 && !con_startup) // If the console is open (as in, not using "bind")...
CON_ChangeHeight(); // ...update its height now, not only when it's closed and re-opened
Unlock_state();
}
// //
// //
static void CONS_hudlines_Change(void) static void CONS_hudlines_Change(void)
@ -168,11 +184,6 @@ static void CONS_hudlines_Change(void)
for (i = 0; i < con_hudlines; i++) for (i = 0; i < con_hudlines; i++)
con_hudtime[i] = 0; 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; con_hudlines = cons_hudlines.value;
Unlock_state(); Unlock_state();
@ -382,16 +393,16 @@ static void CON_SetupColormaps(void)
// 0x1 0x3 0x9 0xF // 0x1 0x3 0x9 0xF
colset(magentamap, 177, 177, 178, 178, 178, 180, 180, 180, 182, 182, 182, 182, 184, 184, 184, 185); colset(magentamap, 177, 177, 178, 178, 178, 180, 180, 180, 182, 182, 182, 182, 184, 184, 184, 185);
colset(yellowmap, 82, 82, 73, 73, 73, 64, 64, 64, 66, 66, 66, 66, 67, 67, 67, 68); colset(yellowmap, 82, 82, 73, 73, 73, 74, 74, 74, 66, 66, 66, 66, 67, 67, 67, 68);
colset(lgreenmap, 96, 96, 98, 98, 98, 101, 101, 101, 104, 104, 104, 104, 106, 106, 106, 107); colset(lgreenmap, 96, 96, 98, 98, 98, 100, 100, 100, 103, 103, 103, 103, 105, 105, 105, 107);
colset(bluemap, 146, 146, 147, 147, 147, 149, 149, 149, 152, 152, 152, 152, 155, 155, 155, 157); colset(bluemap, 146, 146, 147, 147, 147, 148, 148, 148, 149, 149, 149, 149, 150, 150, 150, 151);
colset(redmap, 32, 32, 33, 33, 33, 35, 35, 35, 39, 39, 39, 39, 42, 42, 42, 44); colset(redmap, 32, 32, 33, 33, 33, 34, 34, 34, 35, 35, 35, 35, 37, 37, 37, 39);
colset(graymap, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23); colset(graymap, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23);
colset(orangemap, 50, 50, 52, 52, 52, 54, 54, 54, 56, 56, 56, 56, 59, 59, 59, 60); colset(orangemap, 50, 50, 52, 52, 52, 54, 54, 54, 56, 56, 56, 56, 59, 59, 59, 60);
colset(skymap, 129, 129, 130, 130, 130, 131, 131, 131, 133, 133, 133, 133, 135, 135, 135, 136); colset(skymap, 129, 129, 130, 130, 130, 131, 131, 131, 133, 133, 133, 133, 135, 135, 135, 136);
colset(purplemap, 160, 160, 161, 161, 161, 162, 162, 162, 163, 163, 163, 163, 164, 164, 164, 165); colset(purplemap, 160, 160, 161, 161, 161, 162, 162, 162, 163, 163, 163, 163, 164, 164, 164, 165);
colset(aquamap, 120, 120, 121, 121, 121, 122, 122, 122, 123, 123, 123, 123, 124, 124, 124, 125); colset(aquamap, 120, 120, 121, 121, 121, 122, 122, 122, 123, 123, 123, 123, 124, 124, 124, 125);
colset(peridotmap, 72, 72, 188, 188, 189, 189, 189, 189, 190, 190, 190, 190, 191, 191, 191, 94); colset(peridotmap, 73, 73, 188, 188, 188, 189, 189, 189, 190, 190, 190, 190, 191, 191, 191, 94);
colset(azuremap, 144, 144, 145, 145, 145, 146, 146, 146, 170, 170, 170, 170, 171, 171, 171, 172); colset(azuremap, 144, 144, 145, 145, 145, 146, 146, 146, 170, 170, 170, 170, 171, 171, 171, 172);
colset(brownmap, 219, 219, 221, 221, 221, 222, 222, 222, 224, 224, 224, 224, 227, 227, 227, 229); colset(brownmap, 219, 219, 221, 221, 221, 222, 222, 222, 224, 224, 224, 224, 227, 227, 227, 229);
colset(rosymap, 200, 200, 201, 201, 201, 202, 202, 202, 203, 203, 203, 203, 204, 204, 204, 205); colset(rosymap, 200, 200, 201, 201, 201, 202, 202, 202, 203, 203, 203, 203, 204, 204, 204, 205);
@ -464,7 +475,7 @@ void CON_Init(void)
Unlock_state(); Unlock_state();
CV_RegisterVar(&cons_msgtimeout); CV_RegisterVar(&cons_hudtime);
CV_RegisterVar(&cons_hudlines); CV_RegisterVar(&cons_hudlines);
CV_RegisterVar(&cons_speed); CV_RegisterVar(&cons_speed);
CV_RegisterVar(&cons_height); CV_RegisterVar(&cons_height);
@ -643,33 +654,39 @@ static void CON_ChangeHeight(void)
// //
static void CON_MoveConsole(void) static void CON_MoveConsole(void)
{ {
fixed_t conspeed; static fixed_t fracmovement = 0;
Lock_state(); Lock_state();
conspeed = FixedDiv(cons_speed.value*vid.fdupy, FRACUNIT);
// instant // instant
if (!cons_speed.value) if (!cons_speed.value)
{ {
con_curlines = con_destlines; con_curlines = con_destlines;
Unlock_state();
return; return;
} }
// up/down move to dest // Not instant - Increment fracmovement fractionally
if (con_curlines < con_destlines) fracmovement += FixedMul(cons_speed.value*vid.fdupy, renderdeltatics);
if (con_curlines < con_destlines) // Move the console downwards
{ {
con_curlines += FixedInt(conspeed); con_curlines += FixedInt(fracmovement); // Move by fracmovement's integer value
if (con_curlines > con_destlines) if (con_curlines > con_destlines) // If we surpassed the destination...
con_curlines = con_destlines; con_curlines = con_destlines; // ...clamp to it!
} }
else if (con_curlines > con_destlines) else // Move the console upwards
{ {
con_curlines -= FixedInt(conspeed); con_curlines -= FixedInt(fracmovement);
if (con_curlines < con_destlines) if (con_curlines < con_destlines)
con_curlines = con_destlines; con_curlines = con_destlines;
if (con_destlines == 0) // If the console is being closed, not just moved up...
con_tick = 0; // ...don't show the blinking cursor
} }
fracmovement %= FRACUNIT; // Reset fracmovement's integer value, but keep the fraction
Unlock_state(); Unlock_state();
} }
@ -752,10 +769,6 @@ void CON_Ticker(void)
CON_ChangeHeight(); CON_ChangeHeight();
} }
// console movement
if (con_destlines != con_curlines)
CON_MoveConsole();
// clip the view, so that the part under the console is not drawn // clip the view, so that the part under the console is not drawn
con_clipviewtop = -1; con_clipviewtop = -1;
if (cons_backpic.value) // clip only when using an opaque background if (cons_backpic.value) // clip only when using an opaque background
@ -777,9 +790,8 @@ void CON_Ticker(void)
// make overlay messages disappear after a while // make overlay messages disappear after a while
for (i = 0; i < con_hudlines; i++) for (i = 0; i < con_hudlines; i++)
{ {
con_hudtime[i]--; if (con_hudtime[i])
if (con_hudtime[i] < 0) con_hudtime[i]--;
con_hudtime[i] = 0;
} }
Unlock_state(); Unlock_state();
@ -1328,7 +1340,8 @@ boolean CON_Responder(event_t *ev)
static void CON_Linefeed(void) static void CON_Linefeed(void)
{ {
// set time for heads up messages // 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_cy++;
con_cx = 0; con_cx = 0;
@ -1684,7 +1697,7 @@ static void CON_DrawHudlines(void)
INT32 charwidth = 8 * con_scalefactor; INT32 charwidth = 8 * con_scalefactor;
INT32 charheight = 8 * con_scalefactor; INT32 charheight = 8 * con_scalefactor;
if (con_hudlines <= 0) if (!con_hudlines)
return; return;
if (chat_on && OLDCHAT) if (chat_on && OLDCHAT)
@ -1692,7 +1705,7 @@ static void CON_DrawHudlines(void)
else else
y = 0; 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; size_t c;
INT32 x; INT32 x;
@ -1809,41 +1822,41 @@ static void CON_DrawConsole(void)
} }
// draw console text lines from top to bottom // draw console text lines from top to bottom
if (con_curlines < minheight) if (con_curlines >= minheight)
return;
i = con_cy - con_scrollup;
// skip the last empty line due to the cursor being at the start of a new line
i--;
i -= (con_curlines - minheight) / charheight;
if (rendermode == render_none) return;
for (y = (con_curlines-minheight) % charheight; y <= con_curlines-minheight; y += charheight, i++)
{ {
INT32 x; i = con_cy - con_scrollup;
size_t c;
p = (UINT8 *)&con_buffer[((i > 0 ? i : 0)%con_totallines)*con_width]; // skip the last empty line due to the cursor being at the start of a new line
i--;
for (c = 0, x = charwidth; c < con_width; c++, x += charwidth, p++) i -= (con_curlines - minheight) / charheight;
if (rendermode == render_none) return;
for (y = (con_curlines-minheight) % charheight; y <= con_curlines-minheight; y += charheight, i++)
{ {
while (*p & 0x80) INT32 x;
size_t c;
p = (UINT8 *)&con_buffer[((i > 0 ? i : 0)%con_totallines)*con_width];
for (c = 0, x = charwidth; c < con_width; c++, x += charwidth, p++)
{ {
charflags = (*p & 0x7f) << V_CHARCOLORSHIFT; while (*p & 0x80)
p++; {
c++; charflags = (*p & 0x7f) << V_CHARCOLORSHIFT;
p++;
c++;
}
if (c >= con_width)
break;
V_DrawCharacter(x, y, (INT32)(*p) | charflags | cv_constextsize.value | V_NOSCALESTART, true);
} }
if (c >= con_width)
break;
V_DrawCharacter(x, y, (INT32)(*p) | charflags | cv_constextsize.value | V_NOSCALESTART, true);
} }
} }
// draw prompt if enough place (not while game startup) // draw prompt if enough place (not while game startup)
if ((con_curlines == con_destlines) && (con_curlines >= minheight) && !con_startup) if ((con_curlines >= (minheight-charheight)) && !con_startup)
CON_DrawInput(); CON_DrawInput();
} }
@ -1866,11 +1879,15 @@ void CON_Drawer(void)
CON_ClearHUD(); CON_ClearHUD();
} }
// console movement
if (con_curlines != con_destlines)
CON_MoveConsole();
if (con_curlines > 0) if (con_curlines > 0)
CON_DrawConsole(); CON_DrawConsole();
else if (gamestate == GS_LEVEL else if (gamestate == GS_LEVEL
|| gamestate == GS_INTERMISSION || gamestate == GS_ENDING || gamestate == GS_CUTSCENE || 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(); CON_DrawHudlines();
Unlock_state(); Unlock_state();

View file

@ -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 // true when a player is connecting or disconnecting so that the gameplay has stopped in its tracks
boolean hu_stopped = false; boolean hu_stopped = false;
consvar_t cv_dedicatedidletime = CVAR_INIT ("dedicatedidletime", "10", CV_SAVE, CV_Unsigned, NULL);
UINT8 adminpassmd5[16]; UINT8 adminpassmd5[16];
boolean adminpasswordset = false; boolean adminpasswordset = false;
@ -1293,6 +1295,7 @@ static boolean CL_AskFileList(INT32 firstfile)
static boolean CL_SendJoin(void) static boolean CL_SendJoin(void)
{ {
UINT8 localplayers = 1; UINT8 localplayers = 1;
char const *player2name;
if (netgame) if (netgame)
CONS_Printf(M_GetText("Sending join request...\n")); CONS_Printf(M_GetText("Sending join request...\n"));
netbuffer->packettype = PT_CLIENTJOIN; netbuffer->packettype = PT_CLIENTJOIN;
@ -1309,18 +1312,23 @@ static boolean CL_SendJoin(void)
CleanupPlayerName(consoleplayer, cv_playername.zstring); CleanupPlayerName(consoleplayer, cv_playername.zstring);
if (splitscreen) if (splitscreen)
CleanupPlayerName(1, cv_playername2.zstring);/* 1 is a HACK? oh no */ 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[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)); return HSendPacket(servernode, true, 0, sizeof (clientconfig_pak));
} }
static INT32 FindRejoinerNum(SINT8 node) static INT32 FindRejoinerNum(SINT8 node)
{ {
char strippednodeaddress[64]; char addressbuffer[64];
const char *nodeaddress; const char *nodeaddress;
char *port; const char *strippednodeaddress;
INT32 i; INT32 i;
// Make sure there is no dead dress before proceeding to the stripping // Make sure there is no dead dress before proceeding to the stripping
@ -1331,10 +1339,8 @@ static INT32 FindRejoinerNum(SINT8 node)
return -1; return -1;
// Strip the address of its port // Strip the address of its port
strcpy(strippednodeaddress, nodeaddress); strcpy(addressbuffer, nodeaddress);
port = strchr(strippednodeaddress, ':'); strippednodeaddress = I_NetSplitAddress(addressbuffer, NULL);
if (port)
*port = '\0';
// Check if any player matches the stripped address // Check if any player matches the stripped address
for (i = 0; i < MAXPLAYERS; i++) for (i = 0; i < MAXPLAYERS; i++)
@ -1506,6 +1512,7 @@ static boolean SV_SendServerConfig(INT32 node)
netbuffer->u.servercfg.gamestate = (UINT8)gamestate; netbuffer->u.servercfg.gamestate = (UINT8)gamestate;
netbuffer->u.servercfg.gametype = (UINT8)gametype; netbuffer->u.servercfg.gametype = (UINT8)gametype;
netbuffer->u.servercfg.modifiedgame = (UINT8)modifiedgame; netbuffer->u.servercfg.modifiedgame = (UINT8)modifiedgame;
netbuffer->u.servercfg.usedCheats = (UINT8)usedCheats;
memcpy(netbuffer->u.servercfg.server_context, server_context, 8); memcpy(netbuffer->u.servercfg.server_context, server_context, 8);
@ -2486,7 +2493,7 @@ static boolean CL_ServerConnectionTicker(const char *tmpsave, tic_t *oldtic, tic
{ {
if (!snake) if (!snake)
{ {
F_MenuPresTicker(true); // title sky F_MenuPresTicker(); // title sky
F_TitleScreenTicker(true); F_TitleScreenTicker(true);
F_TitleScreenDrawer(); F_TitleScreenDrawer();
} }
@ -2601,6 +2608,8 @@ static void CL_ConnectToServer(void)
} }
while (!(cl_mode == CL_CONNECTED && (client || (server && nodewaited <= pnumnodes)))); while (!(cl_mode == CL_CONNECTED && (client || (server && nodewaited <= pnumnodes))));
if (netgame)
F_StartWaitingPlayers();
DEBFILE(va("Synchronisation Finished\n")); DEBFILE(va("Synchronisation Finished\n"));
displayplayer = consoleplayer; displayplayer = consoleplayer;
@ -2734,7 +2743,6 @@ static void Command_ClearBans(void)
static void Ban_Load_File(boolean warning) static void Ban_Load_File(boolean warning)
{ {
FILE *f; FILE *f;
size_t i;
const char *address, *mask; const char *address, *mask;
char buffer[MAX_WADPATH]; char buffer[MAX_WADPATH];
@ -2752,7 +2760,7 @@ static void Ban_Load_File(boolean warning)
Ban_Clear(); 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"); address = strtok(buffer, " \t\r\n");
mask = strtok(NULL, " \t\r\n"); mask = strtok(NULL, " \t\r\n");
@ -3644,6 +3652,9 @@ void SV_ResetServer(void)
CV_RevertNetVars(); CV_RevertNetVars();
// Ensure synched when creating a new server
M_CopyGameData(serverGamedata, clientGamedata);
DEBFILE("\n-=-=-=-=-=-=-= Server Reset =-=-=-=-=-=-=-\n\n"); DEBFILE("\n-=-=-=-=-=-=-= Server Reset =-=-=-=-=-=-=-\n\n");
} }
@ -3767,14 +3778,13 @@ static void Got_AddPlayer(UINT8 **p, INT32 playernum)
if (server && I_GetNodeAddress) if (server && I_GetNodeAddress)
{ {
char addressbuffer[64];
const char *address = I_GetNodeAddress(node); const char *address = I_GetNodeAddress(node);
char *port = NULL;
if (address) // MI: fix msvcrt.dll!_mbscat crash? if (address) // MI: fix msvcrt.dll!_mbscat crash?
{ {
strcpy(playeraddress[newplayernum], address); strcpy(addressbuffer, address);
port = strchr(playeraddress[newplayernum], ':'); strcpy(playeraddress[newplayernum],
if (port) I_NetSplitAddress(addressbuffer, NULL));
*port = '\0';
} }
} }
} }
@ -4406,6 +4416,8 @@ static void HandlePacketFromAwayNode(SINT8 node)
maketic = gametic = neededtic = (tic_t)LONG(netbuffer->u.servercfg.gametic); maketic = gametic = neededtic = (tic_t)LONG(netbuffer->u.servercfg.gametic);
G_SetGametype(netbuffer->u.servercfg.gametype); G_SetGametype(netbuffer->u.servercfg.gametype);
modifiedgame = netbuffer->u.servercfg.modifiedgame; modifiedgame = netbuffer->u.servercfg.modifiedgame;
if (netbuffer->u.servercfg.usedCheats)
G_SetUsedCheats(true);
memcpy(server_context, netbuffer->u.servercfg.server_context, 8); memcpy(server_context, netbuffer->u.servercfg.server_context, 8);
} }
@ -4515,6 +4527,7 @@ static void HandlePacketFromPlayer(SINT8 node)
netconsole = 0; netconsole = 0;
else else
netconsole = nodetoplayer[node]; netconsole = nodetoplayer[node];
#ifdef PARANOIA #ifdef PARANOIA
if (netconsole >= MAXPLAYERS) if (netconsole >= MAXPLAYERS)
I_Error("bad table nodetoplayer: node %d player %d", doomcom->remotenode, netconsole); I_Error("bad table nodetoplayer: node %d player %d", doomcom->remotenode, netconsole);
@ -4553,21 +4566,32 @@ static void HandlePacketFromPlayer(SINT8 node)
// Update the nettics // Update the nettics
nettics[node] = realend; nettics[node] = realend;
// Don't do anything for packets of type NODEKEEPALIVE? // This should probably still timeout though, as the node should always have a player 1 number
if (netconsole == -1 || netbuffer->packettype == PT_NODEKEEPALIVE if (netconsole == -1)
|| netbuffer->packettype == PT_NODEKEEPALIVEMIS)
break; break;
// As long as clients send valid ticcmds, the server can keep running, so reset the timeout // 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? /// \todo Use a separate cvar for that kind of timeout?
freezetimeout[node] = I_GetTime() + connectiontimeout; 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 // 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" // Check ticcmd for "speed hacks"
if (netcmds[maketic%BACKUPTICS][netconsole].forwardmove > MAXPLMOVE || netcmds[maketic%BACKUPTICS][netconsole].forwardmove < -MAXPLMOVE if (netcmds[faketic%BACKUPTICS][netconsole].forwardmove > MAXPLMOVE || netcmds[faketic%BACKUPTICS][netconsole].forwardmove < -MAXPLMOVE
|| netcmds[maketic%BACKUPTICS][netconsole].sidemove > MAXPLMOVE || netcmds[maketic%BACKUPTICS][netconsole].sidemove < -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); CONS_Alert(CONS_WARNING, M_GetText("Illegal movement value received from node %d\n"), netconsole);
//D_Clearticcmd(k); //D_Clearticcmd(k);
@ -4579,9 +4603,10 @@ static void HandlePacketFromPlayer(SINT8 node)
// Splitscreen cmd // Splitscreen cmd
if ((netbuffer->packettype == PT_CLIENT2CMD || netbuffer->packettype == PT_CLIENT2MIS) if ((netbuffer->packettype == PT_CLIENT2CMD || netbuffer->packettype == PT_CLIENT2MIS)
&& nodetoplayer2[node] >= 0) && nodetoplayer2[node] >= 0)
G_MoveTiccmd(&netcmds[maketic%BACKUPTICS][(UINT8)nodetoplayer2[node]], G_MoveTiccmd(&netcmds[faketic%BACKUPTICS][(UINT8)nodetoplayer2[node]],
&netbuffer->u.client2pak.cmd2, 1); &netbuffer->u.client2pak.cmd2, 1);
// Check player consistancy during the level // Check player consistancy during the level
if (realstart <= gametic && realstart + BACKUPTICS - 1 > gametic && gamestate == GS_LEVEL if (realstart <= gametic && realstart + BACKUPTICS - 1 > gametic && gamestate == GS_LEVEL
&& consistancy[realstart%BACKUPTICS] != SHORT(netbuffer->u.clientpak.consistancy) && consistancy[realstart%BACKUPTICS] != SHORT(netbuffer->u.clientpak.consistancy)
@ -4618,6 +4643,21 @@ static void HandlePacketFromPlayer(SINT8 node)
} }
} }
break; 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 case PT_TEXTCMD2: // splitscreen special
netconsole = nodetoplayer2[node]; netconsole = nodetoplayer2[node];
/* FALLTHRU */ /* FALLTHRU */
@ -5044,39 +5084,66 @@ static INT16 Consistancy(void)
return (INT16)(ret & 0xFFFF); 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 // send the client packet to the server
static void CL_SendClientCmd(void) static void CL_SendClientCmd(void)
{ {
size_t packetsize = 0; size_t packetsize = 0;
boolean mis = false;
netbuffer->packettype = PT_CLIENTCMD; netbuffer->packettype = PT_CLIENTCMD;
if (cl_packetmissed) if (cl_packetmissed)
netbuffer->packettype++; {
netbuffer->packettype = PT_CLIENTMIS;
mis = true;
}
netbuffer->u.clientpak.resendfrom = (UINT8)(neededtic & UINT8_MAX); netbuffer->u.clientpak.resendfrom = (UINT8)(neededtic & UINT8_MAX);
netbuffer->u.clientpak.client_tic = (UINT8)(gametic & UINT8_MAX); netbuffer->u.clientpak.client_tic = (UINT8)(gametic & UINT8_MAX);
if (gamestate == GS_WAITINGPLAYERS) if (gamestate == GS_WAITINGPLAYERS)
{ {
// Send PT_NODEKEEPALIVE packet // Send PT_NODEKEEPALIVE packet
netbuffer->packettype += 4; netbuffer->packettype = (mis ? PT_NODEKEEPALIVEMIS : PT_NODEKEEPALIVE);
packetsize = sizeof (clientcmd_pak) - sizeof (ticcmd_t) - sizeof (INT16); packetsize = sizeof (clientcmd_pak) - sizeof (ticcmd_t) - sizeof (INT16);
HSendPacket(servernode, false, 0, packetsize); HSendPacket(servernode, false, 0, packetsize);
} }
else if (gamestate != GS_NULL && (addedtogame || dedicated)) else if (gamestate != GS_NULL && (addedtogame || dedicated))
{ {
packetsize = sizeof (clientcmd_pak);
G_MoveTiccmd(&netbuffer->u.clientpak.cmd, &localcmds, 1); G_MoveTiccmd(&netbuffer->u.clientpak.cmd, &localcmds, 1);
netbuffer->u.clientpak.consistancy = SHORT(consistancy[gametic%BACKUPTICS]); netbuffer->u.clientpak.consistancy = SHORT(consistancy[gametic%BACKUPTICS]);
// Send a special packet with 2 cmd for splitscreen // Send a special packet with 2 cmd for splitscreen
if (splitscreen || botingame) if (splitscreen || botingame)
{ {
netbuffer->packettype += 2; netbuffer->packettype = (mis ? PT_CLIENT2MIS : PT_CLIENT2CMD);
G_MoveTiccmd(&netbuffer->u.client2pak.cmd2, &localcmds2, 1);
packetsize = sizeof (client2cmd_pak); packetsize = sizeof (client2cmd_pak);
G_MoveTiccmd(&netbuffer->u.client2pak.cmd2, &localcmds2, 1);
} }
else
packetsize = sizeof (clientcmd_pak);
HSendPacket(servernode, false, 0, packetsize); HSendPacket(servernode, false, 0, packetsize);
} }
@ -5087,7 +5154,7 @@ static void CL_SendClientCmd(void)
if (localtextcmd[0]) if (localtextcmd[0])
{ {
netbuffer->packettype = PT_TEXTCMD; 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 // All extra data have been sent
if (HSendPacket(servernode, true, 0, localtextcmd[0]+1)) // Send can fail... if (HSendPacket(servernode, true, 0, localtextcmd[0]+1)) // Send can fail...
localtextcmd[0] = 0; localtextcmd[0] = 0;
@ -5467,28 +5534,11 @@ static inline void PingUpdate(void)
pingmeasurecount = 1; //Reset count pingmeasurecount = 1; //Reset count
} }
void NetUpdate(void) static tic_t gametime = 0;
static void UpdatePingTable(void)
{ {
static tic_t gametime = 0;
static tic_t resptime = 0;
tic_t nowtime;
INT32 i; INT32 i;
INT32 realtics;
nowtime = I_GetTime();
realtics = nowtime - gametime;
if (realtics <= 0) // nothing new to update
return;
if (realtics > 5)
{
if (server)
realtics = 1;
else
realtics = 5;
}
gametime = nowtime;
if (server) if (server)
{ {
@ -5500,6 +5550,150 @@ void NetUpdate(void)
realpingtable[i] += G_TicsToMilliseconds(GetLag(playernode[i])); realpingtable[i] += G_TicsToMilliseconds(GetLag(playernode[i]));
pingmeasurecount++; 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 resptime = 0;
tic_t nowtime;
INT32 i;
INT32 realtics;
nowtime = I_GetTime();
realtics = nowtime - gametime;
if (realtics <= 0) // nothing new to update
return;
if (realtics > 5)
{
if (server)
realtics = 1;
else
realtics = 5;
}
if (server && dedicated && gamestate == GS_LEVEL)
{
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) if (client)
maketic = neededtic; maketic = neededtic;
@ -5531,25 +5725,26 @@ void NetUpdate(void)
} }
else else
{ {
if (!demoplayback) if (!demoplayback && realtics > 0)
{ {
INT32 counts; INT32 counts;
hu_redownloadinggamestate = false; hu_redownloadinggamestate = false;
firstticstosend = gametic;
for (i = 0; i < MAXNETNODES; i++)
if (nodeingame[i] && nettics[i] < firstticstosend)
{
firstticstosend = nettics[i];
if (maketic + 1 >= nettics[i] + BACKUPTICS)
Net_ConnectionTimeout(i);
}
// Don't erase tics not acknowledged // Don't erase tics not acknowledged
counts = realtics; counts = realtics;
firstticstosend = gametic;
for (i = 0; i < MAXNETNODES; i++)
{
if (!nodeingame[i])
continue;
if (nettics[i] < firstticstosend)
firstticstosend = nettics[i];
if (maketic + counts >= nettics[i] + (BACKUPTICS - TICRATE))
Net_ConnectionTimeout(i);
}
if (maketic + counts >= firstticstosend + BACKUPTICS) if (maketic + counts >= firstticstosend + BACKUPTICS)
counts = firstticstosend+BACKUPTICS-maketic-1; counts = firstticstosend+BACKUPTICS-maketic-1;
@ -5566,20 +5761,10 @@ void NetUpdate(void)
} }
Net_AckTicker(); Net_AckTicker();
HandleNodeTimeouts();
// 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);
}
nowtime /= NEWTICRATERATIO; nowtime /= NEWTICRATERATIO;
if (nowtime > resptime) if (nowtime > resptime)
{ {
resptime = nowtime; resptime = nowtime;

View file

@ -77,6 +77,8 @@ typedef enum
PT_ASKLUAFILE, // Client telling the server they don't have the file PT_ASKLUAFILE, // Client telling the server they don't have the file
PT_HASLUAFILE, // Client telling the server they 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. // Add non-PT_CANFAIL packet types here to avoid breaking MS compatibility.
PT_CANFAIL, // This is kind of a priority. Anything bigger than CANFAIL PT_CANFAIL, // This is kind of a priority. Anything bigger than CANFAIL
@ -158,6 +160,7 @@ typedef struct
UINT8 gametype; UINT8 gametype;
UINT8 modifiedgame; UINT8 modifiedgame;
UINT8 usedCheats;
char server_context[8]; // Unique context id, generated at server startup. char server_context[8]; // Unique context id, generated at server startup.
} ATTRPACK serverconfig_pak; } ATTRPACK serverconfig_pak;
@ -397,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_netticbuffer, cv_allownewplayer, cv_joinnextround, cv_maxplayers, cv_joindelay, cv_rejointimeout;
extern consvar_t cv_resynchattempts, cv_blamecfail; extern consvar_t cv_resynchattempts, cv_blamecfail;
extern consvar_t cv_maxsend, cv_noticedownload, cv_downloadspeed; extern consvar_t cv_maxsend, cv_noticedownload, cv_downloadspeed;
extern consvar_t cv_dedicatedidletime;
// Used in d_net, the only dependence // Used in d_net, the only dependence
tic_t ExpandTics(INT32 low, INT32 node); tic_t ExpandTics(INT32 low, INT32 node);
@ -411,6 +415,9 @@ void SendKick(UINT8 playernum, UINT8 msg);
// Create any new ticcmds and broadcast to other players. // Create any new ticcmds and broadcast to other players.
void NetUpdate(void); void NetUpdate(void);
// Maintain connections to nodes without timing them all out.
void NetKeepAlive(void);
void SV_StartSinglePlayerServer(void); void SV_StartSinglePlayerServer(void);
boolean SV_SpawnServer(void); boolean SV_SpawnServer(void);
void SV_StopServer(void); void SV_StopServer(void);

View file

@ -70,6 +70,8 @@
#include "filesrch.h" // refreshdirmenu #include "filesrch.h" // refreshdirmenu
#include "g_input.h" // tutorial mode control scheming #include "g_input.h" // tutorial mode control scheming
#include "m_perfstats.h" #include "m_perfstats.h"
#include "m_random.h"
#include "command.h"
#ifdef CMAKECONFIG #ifdef CMAKECONFIG
#include "config.h" #include "config.h"
@ -458,6 +460,13 @@ static void D_Display(void)
case GS_WAITINGPLAYERS: case GS_WAITINGPLAYERS:
// The clientconnect drawer is independent... // 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_DEDICATEDSERVER:
case GS_NULL: case GS_NULL:
break; break;
@ -1208,6 +1217,15 @@ D_ConvertVersionNumbers (void)
#endif #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 // D_SRB2Main
// //
@ -1221,6 +1239,11 @@ void D_SRB2Main(void)
/* break the version string into version numbers, for netplay */ /* break the version string into version numbers, for netplay */
D_ConvertVersionNumbers(); D_ConvertVersionNumbers();
if (!strcmp(compbranch, ""))
{
compbranch = "detached HEAD";
}
// Print GPL notice for our console users (Linux) // Print GPL notice for our console users (Linux)
CONS_Printf( CONS_Printf(
"\n\nSonic Robo Blast 2\n" "\n\nSonic Robo Blast 2\n"
@ -1334,11 +1357,12 @@ void D_SRB2Main(void)
snprintf(addonsdir, sizeof addonsdir, "%s%s%s", srb2home, PATHSEP, "addons"); snprintf(addonsdir, sizeof addonsdir, "%s%s%s", srb2home, PATHSEP, "addons");
I_mkdir(addonsdir, 0755); I_mkdir(addonsdir, 0755);
// rand() needs seeded regardless of password // seed M_Random because it is necessary; seed P_Random for scripts that
srand((unsigned int)time(NULL)); // might want to use random numbers immediately at start
rand(); if (!M_RandomSeedFromOS())
rand(); M_RandomSeed((UINT32)time(NULL)); // less good but serviceable
rand();
P_SetRandSeed(M_RandomizedSeed());
if (M_CheckParm("-password") && M_IsNextParm()) if (M_CheckParm("-password") && M_IsNextParm())
D_SetPassword(M_GetNextParm()); D_SetPassword(M_GetNextParm());
@ -1350,9 +1374,14 @@ void D_SRB2Main(void)
CONS_Printf("Z_Init(): Init zone memory allocation daemon. \n"); CONS_Printf("Z_Init(): Init zone memory allocation daemon. \n");
Z_Init(); Z_Init();
clientGamedata = M_NewGameDataStruct();
serverGamedata = M_NewGameDataStruct();
// Do this up here so that WADs loaded through the command line can use ExecCfg // Do this up here so that WADs loaded through the command line can use ExecCfg
COM_Init(); COM_Init();
COM_AddCommand("assert", Command_assert, COM_LUA);
// Add any files specified on the command line with // Add any files specified on the command line with
// "-file <file>" or "-folder <folder>" to the add-on list // "-file <file>" or "-folder <folder>" to the add-on list
if (!((M_GetUrlProtocolArg() || M_CheckParm("-connect")) && !M_CheckParm("-server"))) if (!((M_GetUrlProtocolArg() || M_CheckParm("-connect")) && !M_CheckParm("-server")))
@ -1473,7 +1502,15 @@ void D_SRB2Main(void)
//--------------------------------------------------------- CONFIG.CFG //--------------------------------------------------------- CONFIG.CFG
M_FirstLoadConfig(); // WARNING : this do a "COM_BufExecute()" M_FirstLoadConfig(); // WARNING : this do a "COM_BufExecute()"
G_LoadGameData(); if (M_CheckParm("-gamedata") && M_IsNextParm())
{
// Moved from G_LoadGameData itself, as it would cause some crazy
// confusion issues when loading mods.
strlcpy(gamedatafilename, M_GetNextParm(), sizeof gamedatafilename);
}
G_LoadGameData(clientGamedata);
M_CopyGameData(serverGamedata, clientGamedata);
#if defined (__unix__) || defined (UNIXCOMMON) || defined (HAVE_SDL) #if defined (__unix__) || defined (UNIXCOMMON) || defined (HAVE_SDL)
VID_PrepareModeList(); // Regenerate Modelist according to cv_fullscreen VID_PrepareModeList(); // Regenerate Modelist according to cv_fullscreen
@ -1500,7 +1537,7 @@ void D_SRB2Main(void)
else else
{ {
if (!M_CheckParm("-server")) if (!M_CheckParm("-server"))
G_SetGameModified(true); G_SetUsedCheats(true);
autostart = true; autostart = true;
} }
} }
@ -1700,14 +1737,15 @@ void D_SRB2Main(void)
// Prevent warping to nonexistent levels // Prevent warping to nonexistent levels
if (W_CheckNumForName(G_BuildMapName(pstartmap)) == LUMPERROR) if (W_CheckNumForName(G_BuildMapName(pstartmap)) == LUMPERROR)
I_Error("Could not warp to %s (map not found)\n", G_BuildMapName(pstartmap)); 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))
I_Error("You need to unlock this level before you can warp to it!\n");
else 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); D_MapChange(pstartmap, gametype, ultimatemode, true, 0, false, false);
} }
} }
@ -1777,3 +1815,85 @@ const char *D_Home(void)
if (usehome) return userhome; if (usehome) return userhome;
else return NULL; else return NULL;
} }
static boolean check_top_dir(const char **path, const char *top)
{
// empty string does NOT match
if (!strcmp(top, ""))
return false;
if (!startswith(*path, top))
return false;
*path += strlen(top);
// if it doesn't already end with a path separator,
// check if a separator follows
if (!endswith(top, PATHSEP))
{
if (startswith(*path, PATHSEP))
*path += strlen(PATHSEP);
else
return false;
}
return true;
}
static int cmp_strlen_desc(const void *a, const void *b)
{
return ((int)strlen(*(const char*const*)b) - (int)strlen(*(const char*const*)a));
}
boolean D_IsPathAllowed(const char *path)
{
const char *paths[] = {
srb2home,
srb2path,
cv_addons_folder.string
};
const size_t n_paths = sizeof paths / sizeof *paths;
size_t i;
// Sort folder paths by longest to shortest so
// overlapping paths work. E.g.:
// Path 1: /home/james/.srb2/addons
// Path 2: /home/james/.srb2
qsort(paths, n_paths, sizeof *paths, cmp_strlen_desc);
// These paths are allowed to be absolute
// path is offset so ".." can be checked only in the
// rest of the path
for (i = 0; i < n_paths; ++i)
{
if (check_top_dir(&path, paths[i]))
break;
}
// Only if none of the presets matched
if (i == n_paths)
{
// Cannot be an absolute path
if (M_IsPathAbsolute(path))
return false;
}
// Cannot traverse upwards
if (strstr(path, ".."))
return false;
return true;
}
boolean D_CheckPathAllowed(const char *path, const char *why)
{
if (!D_IsPathAllowed(path))
{
CONS_Alert(CONS_WARNING, "%s: %s, location is not allowed\n", why, path);
return false;
}
return true;
}

View file

@ -44,6 +44,9 @@ void D_ProcessEvents(void);
const char *D_Home(void); const char *D_Home(void);
boolean D_IsPathAllowed(const char *path);
boolean D_CheckPathAllowed(const char *path, const char *why);
// //
// BASE LEVEL // BASE LEVEL
// //

View file

@ -869,6 +869,9 @@ static void DebugPrintpacket(const char *header)
(UINT32)ExpandTics(netbuffer->u.clientpak.client_tic, doomcom->remotenode), (UINT32)ExpandTics(netbuffer->u.clientpak.client_tic, doomcom->remotenode),
(UINT32)ExpandTics (netbuffer->u.clientpak.resendfrom, doomcom->remotenode)); (UINT32)ExpandTics (netbuffer->u.clientpak.resendfrom, doomcom->remotenode));
break; break;
case PT_BASICKEEPALIVE:
fprintf(debugfile, " wipetime\n");
break;
case PT_TEXTCMD: case PT_TEXTCMD:
case PT_TEXTCMD2: case PT_TEXTCMD2:
fprintf(debugfile, " length %d\n ", netbuffer->u.textcmd[0]); fprintf(debugfile, " length %d\n ", netbuffer->u.textcmd[0]);
@ -1207,26 +1210,32 @@ static void Internal_FreeNodenum(INT32 nodenum)
(void)nodenum; (void)nodenum;
} }
char *I_NetSplitAddress(char *host, char **port)
{
boolean v4 = (strchr(host, '.') != NULL);
host = strtok(host, v4 ? ":" : "[]");
if (port)
*port = strtok(NULL, ":");
return host;
}
SINT8 I_NetMakeNode(const char *hostname) SINT8 I_NetMakeNode(const char *hostname)
{ {
SINT8 newnode = -1; SINT8 newnode = -1;
if (I_NetMakeNodewPort) if (I_NetMakeNodewPort)
{ {
char *localhostname = strdup(hostname); char *localhostname = strdup(hostname);
char *t = localhostname; char *port;
const char *port;
if (!localhostname) if (!localhostname)
return newnode; return newnode;
// retrieve portnum from address! // retrieve portnum from address!
strtok(localhostname, ":"); hostname = I_NetSplitAddress(localhostname, &port);
port = strtok(NULL, ":");
// remove the port in the hostname as we've it already newnode = I_NetMakeNodewPort(hostname, port);
while ((*t != ':') && (*t != '\0'))
t++;
*t = '\0';
newnode = I_NetMakeNodewPort(localhostname, port);
free(localhostname); free(localhostname);
} }
return newnode; return newnode;

View file

@ -49,7 +49,7 @@
#include "m_anigif.h" #include "m_anigif.h"
#include "md5.h" #include "md5.h"
#include "m_perfstats.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 #ifdef NETGAME_DEVMODE
#define CV_RESTRICT CV_NETVAR #define CV_RESTRICT CV_NETVAR
@ -599,6 +599,7 @@ void D_RegisterServerCommands(void)
CV_RegisterVar(&cv_joinnextround); CV_RegisterVar(&cv_joinnextround);
CV_RegisterVar(&cv_showjoinaddress); CV_RegisterVar(&cv_showjoinaddress);
CV_RegisterVar(&cv_blamecfail); CV_RegisterVar(&cv_blamecfail);
CV_RegisterVar(&cv_dedicatedidletime);
#endif #endif
COM_AddCommand("ping", Command_Ping_f, COM_LUA); COM_AddCommand("ping", Command_Ping_f, COM_LUA);
@ -613,6 +614,10 @@ void D_RegisterServerCommands(void)
CV_RegisterVar(&cv_allowseenames); CV_RegisterVar(&cv_allowseenames);
// Other filesrch.c consvars are defined in D_RegisterClientCommands
CV_RegisterVar(&cv_addons_option);
CV_RegisterVar(&cv_addons_folder);
CV_RegisterVar(&cv_dummyconsvar); CV_RegisterVar(&cv_dummyconsvar);
} }
@ -771,6 +776,8 @@ void D_RegisterClientCommands(void)
CV_RegisterVar(&cv_showfocuslost); CV_RegisterVar(&cv_showfocuslost);
CV_RegisterVar(&cv_pauseifunfocused); CV_RegisterVar(&cv_pauseifunfocused);
CV_RegisterVar(&cv_instantretry);
// g_input.c // g_input.c
CV_RegisterVar(&cv_sideaxis); CV_RegisterVar(&cv_sideaxis);
CV_RegisterVar(&cv_sideaxis2); CV_RegisterVar(&cv_sideaxis2);
@ -794,8 +801,8 @@ void D_RegisterClientCommands(void)
CV_RegisterVar(&cv_digitaldeadzone2); CV_RegisterVar(&cv_digitaldeadzone2);
// filesrch.c // filesrch.c
CV_RegisterVar(&cv_addons_option); //CV_RegisterVar(&cv_addons_option); // These two are now defined
CV_RegisterVar(&cv_addons_folder); //CV_RegisterVar(&cv_addons_folder); // in D_RegisterServerCommands
CV_RegisterVar(&cv_addons_md5); CV_RegisterVar(&cv_addons_md5);
CV_RegisterVar(&cv_addons_showall); CV_RegisterVar(&cv_addons_showall);
CV_RegisterVar(&cv_addons_search_type); CV_RegisterVar(&cv_addons_search_type);
@ -869,10 +876,15 @@ void D_RegisterClientCommands(void)
// screen.c // screen.c
CV_RegisterVar(&cv_fullscreen); CV_RegisterVar(&cv_fullscreen);
CV_RegisterVar(&cv_renderview); CV_RegisterVar(&cv_renderview);
CV_RegisterVar(&cv_renderhitboxinterpolation);
CV_RegisterVar(&cv_renderhitboxgldepth);
CV_RegisterVar(&cv_renderhitbox);
CV_RegisterVar(&cv_renderer); CV_RegisterVar(&cv_renderer);
CV_RegisterVar(&cv_scr_depth); CV_RegisterVar(&cv_scr_depth);
CV_RegisterVar(&cv_scr_width); CV_RegisterVar(&cv_scr_width);
CV_RegisterVar(&cv_scr_height); CV_RegisterVar(&cv_scr_height);
CV_RegisterVar(&cv_scr_width_w);
CV_RegisterVar(&cv_scr_height_w);
CV_RegisterVar(&cv_soundtest); CV_RegisterVar(&cv_soundtest);
@ -1633,9 +1645,14 @@ static void Command_Playdemo_f(void)
{ {
char name[256]; 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; return;
} }
@ -1657,6 +1674,16 @@ static void Command_Playdemo_f(void)
CONS_Printf(M_GetText("Playing back demo '%s'.\n"), name); 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 // Internal if no extension, external if one exists
// If external, convert the file name to a path in SRB2's home directory // If external, convert the file name to a path in SRB2's home directory
if (FIL_CheckExtension(name)) if (FIL_CheckExtension(name))
@ -1877,8 +1904,8 @@ static void Command_Map_f(void)
size_t option_gametype; size_t option_gametype;
const char *gametypename; const char *gametypename;
boolean newresetplayers; boolean newresetplayers;
boolean prevent_cheat;
boolean mustmodifygame; boolean set_cheated;
INT32 newmapnum; INT32 newmapnum;
@ -1899,21 +1926,34 @@ static void Command_Map_f(void)
option_gametype = COM_CheckPartialParm("-g"); option_gametype = COM_CheckPartialParm("-g");
newresetplayers = ! COM_CheckParm("-noresetplayers"); newresetplayers = ! COM_CheckParm("-noresetplayers");
mustmodifygame = prevent_cheat = !( usedCheats ) && !( option_force || cv_debug );
!( netgame || multiplayer ) && set_cheated = false;
(!modifiedgame || savemoddata );
if (mustmodifygame && !option_force) if (!( netgame || multiplayer ))
{ {
/* May want to be more descriptive? */ if (prevent_cheat)
CONS_Printf(M_GetText("Sorry, level change disabled in single player.\n")); {
return; /* 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")); if (prevent_cheat)
return; {
CONS_Printf(M_GetText("Cheats must be enabled to use -noresetplayers.\n"));
return;
}
else
{
set_cheated = true;
}
} }
if (option_gametype) if (option_gametype)
@ -1921,7 +1961,7 @@ static void Command_Map_f(void)
if (!multiplayer) if (!multiplayer)
{ {
CONS_Printf(M_GetText( CONS_Printf(M_GetText(
"You can't switch gametypes in single player!\n")); "You can't switch gametypes in single player!\n"));
return; return;
} }
else if (COM_Argc() < option_gametype + 2)/* no argument after? */ else if (COM_Argc() < option_gametype + 2)/* no argument after? */
@ -1934,7 +1974,9 @@ static void Command_Map_f(void)
} }
if (!( first_option = COM_FirstOption() )) if (!( first_option = COM_FirstOption() ))
{
first_option = COM_Argc(); first_option = COM_Argc();
}
if (first_option < 2) if (first_option < 2)
{ {
@ -1957,11 +1999,6 @@ static void Command_Map_f(void)
return; return;
} }
if (mustmodifygame && option_force)
{
G_SetGameModified(false);
}
// new gametype value // new gametype value
// use current one by default // use current one by default
if (option_gametype) if (option_gametype)
@ -2003,15 +2040,13 @@ static void Command_Map_f(void)
} }
// don't use a gametype the map doesn't support // 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 // G_TOLFlag handles both multiplayer gametype and ignores it for !multiplayer
else if (!(
mapheaderinfo[newmapnum-1] &&
mapheaderinfo[newmapnum-1]->typeoflevel & G_TOLFlag(newgametype)
))
{ {
if (!( if (prevent_cheat && !cv_skipmapcheck.value)
mapheaderinfo[newmapnum-1] &&
mapheaderinfo[newmapnum-1]->typeoflevel & G_TOLFlag(newgametype)
))
{ {
CONS_Alert(CONS_WARNING, M_GetText("%s (%s) doesn't support %s mode!\n(Use -force to override)\n"), realmapname, G_BuildMapName(newmapnum), 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")); (multiplayer ? gametype_cons_t[newgametype].strvalue : "Single Player"));
@ -2021,23 +2056,33 @@ static void Command_Map_f(void)
} }
else else
{ {
fromlevelselect = // The player wants us to trek on anyway. Do so.
( netgame || multiplayer ) && fromlevelselect = false;
newgametype == gametype && set_cheated = ((gametypedefaultrules[newgametype] & GTR_CAMPAIGN) == GTR_CAMPAIGN);
gametypedefaultrules[newgametype] & GTR_CAMPAIGN;
} }
} }
else
{
fromlevelselect =
( netgame || multiplayer ) &&
newgametype == gametype &&
(gametypedefaultrules[newgametype] & GTR_CAMPAIGN);
}
// Prevent warping to locked levels // Prevent warping to locked levels
// ... unless you're in a dedicated server. Yes, technically this means you can view any level by if (M_CampaignWarpIsCheat(newgametype, newmapnum, serverGamedata))
// running a dedicated server and joining it yourself, but that's better than making dedicated server's
// lives hell.
if (!dedicated && M_MapLocked(newmapnum))
{ {
CONS_Alert(CONS_NOTICE, M_GetText("You need to unlock this level before you can warp to it!\n")); if (prevent_cheat)
Z_Free(realmapname); {
Z_Free(mapname); CONS_Alert(CONS_NOTICE, M_GetText("Cheats must be enabled to warp to a locked level!\n"));
return; Z_Free(realmapname);
Z_Free(mapname);
return;
}
else
{
set_cheated = true;
}
} }
// Ultimate Mode only in SP via menu // Ultimate Mode only in SP via menu
@ -2054,6 +2099,11 @@ static void Command_Map_f(void)
} }
tutorialmode = false; // warping takes us out of tutorial mode 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); D_MapChange(newmapnum, newgametype, false, newresetplayers, 0, false, fromlevelselect);
Z_Free(realmapname); Z_Free(realmapname);
@ -2095,11 +2145,13 @@ static void Got_Mapcmd(UINT8 **cp, INT32 playernum)
lastgametype = gametype; lastgametype = gametype;
gametype = READUINT8(*cp); gametype = READUINT8(*cp);
G_SetGametype(gametype); // I fear putting that macro as an argument
if (gametype < 0 || gametype >= gametypecount) if (gametype < 0 || gametype >= gametypecount)
gametype = lastgametype; gametype = lastgametype;
else if (gametype != lastgametype) else
G_SetGametype(gametype);
if (gametype != lastgametype)
D_GameTypeChanged(lastgametype); // emulate consvar_t behavior for gametype D_GameTypeChanged(lastgametype); // emulate consvar_t behavior for gametype
skipprecutscene = ((flags & (1<<2)) != 0); skipprecutscene = ((flags & (1<<2)) != 0);
@ -2121,12 +2173,6 @@ static void Got_Mapcmd(UINT8 **cp, INT32 playernum)
if (demoplayback && !timingdemo) if (demoplayback && !timingdemo)
precache = false; precache = false;
if (resetplayer && !FLS)
{
emeralds = 0;
memset(&luabanks, 0, sizeof(luabanks));
}
if (modeattacking) if (modeattacking)
{ {
SetPlayerSkinByNum(0, cv_chooseskin.value-1); SetPlayerSkinByNum(0, cv_chooseskin.value-1);
@ -2167,7 +2213,7 @@ static void Command_Pause(void)
if (cv_pause.value || server || (IsPlayerAdmin(consoleplayer))) 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")); CONS_Printf(M_GetText("You can't pause here.\n"));
return; return;
@ -2330,7 +2376,7 @@ static void Got_Clearscores(UINT8 **cp, INT32 playernum)
} }
for (i = 0; i < MAXPLAYERS; i++) 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")); CONS_Printf(M_GetText("Scores have been reset by the server.\n"));
} }
@ -3834,7 +3880,7 @@ static void Command_ListWADS_f(void)
static void Command_Version_f(void) static void Command_Version_f(void)
{ {
#ifdef DEVELOP #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 #else
CONS_Printf("Sonic Robo Blast 2 %s (%s %s %s %s) ", VERSIONSTRING, compdate, comptime, comprevision, compbranch); CONS_Printf("Sonic Robo Blast 2 %s (%s %s %s %s) ", VERSIONSTRING, compdate, comptime, comprevision, compbranch);
#endif #endif
@ -3868,11 +3914,6 @@ static void Command_Version_f(void)
else // 16-bit? 128-bit? else // 16-bit? 128-bit?
CONS_Printf("Bits Unknown "); CONS_Printf("Bits Unknown ");
// No ASM?
#ifdef NOASM
CONS_Printf("\x85" "NOASM " "\x80");
#endif
// Debug build // Debug build
#ifdef _DEBUG #ifdef _DEBUG
CONS_Printf("\x85" "DEBUG " "\x80"); CONS_Printf("\x85" "DEBUG " "\x80");
@ -3941,18 +3982,12 @@ void ItemFinder_OnChange(void)
if (!cv_itemfinder.value) if (!cv_itemfinder.value)
return; // it's fine. return; // it's fine.
if (!M_SecretUnlocked(SECRET_ITEMFINDER)) if (!M_SecretUnlocked(SECRET_ITEMFINDER, clientGamedata))
{ {
CONS_Printf(M_GetText("You haven't earned this yet.\n")); CONS_Printf(M_GetText("You haven't earned this yet.\n"));
CV_StealthSetValue(&cv_itemfinder, 0); CV_StealthSetValue(&cv_itemfinder, 0);
return; return;
} }
else if (netgame || multiplayer)
{
CONS_Printf(M_GetText("This only works in single player.\n"));
CV_StealthSetValue(&cv_itemfinder, 0);
return;
}
} }
/** Deals with a pointlimit change by printing the change to the console. /** Deals with a pointlimit change by printing the change to the console.
@ -4244,9 +4279,6 @@ void D_GameTypeChanged(INT32 lastgametype)
else if (!multiplayer && !netgame) else if (!multiplayer && !netgame)
{ {
G_SetGametype(GT_COOP); 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 // reset timelimit and pointlimit in race/coop, prevent stupid cheats
@ -4301,7 +4333,7 @@ void D_GameTypeChanged(INT32 lastgametype)
static void Ringslinger_OnChange(void) static void Ringslinger_OnChange(void)
{ {
if (!M_SecretUnlocked(SECRET_PANDORA) && !netgame && cv_ringslinger.value && !cv_debug) if (!M_SecretUnlocked(SECRET_PANDORA, serverGamedata) && !netgame && cv_ringslinger.value && !cv_debug)
{ {
CONS_Printf(M_GetText("You haven't earned this yet.\n")); CONS_Printf(M_GetText("You haven't earned this yet.\n"));
CV_StealthSetValue(&cv_ringslinger, 0); CV_StealthSetValue(&cv_ringslinger, 0);
@ -4309,12 +4341,12 @@ static void Ringslinger_OnChange(void)
} }
if (cv_ringslinger.value) // Only if it's been turned on if (cv_ringslinger.value) // Only if it's been turned on
G_SetGameModified(multiplayer); G_SetUsedCheats(false);
} }
static void Gravity_OnChange(void) static void Gravity_OnChange(void)
{ {
if (!M_SecretUnlocked(SECRET_PANDORA) && !netgame && !cv_debug if (!M_SecretUnlocked(SECRET_PANDORA, serverGamedata) && !netgame && !cv_debug
&& strcmp(cv_gravity.string, cv_gravity.defaultvalue)) && strcmp(cv_gravity.string, cv_gravity.defaultvalue))
{ {
CONS_Printf(M_GetText("You haven't earned this yet.\n")); CONS_Printf(M_GetText("You haven't earned this yet.\n"));
@ -4330,7 +4362,7 @@ static void Gravity_OnChange(void)
#endif #endif
if (!CV_IsSetToDefault(&cv_gravity)) if (!CV_IsSetToDefault(&cv_gravity))
G_SetGameModified(multiplayer); G_SetUsedCheats(false);
gravity = cv_gravity.value; gravity = cv_gravity.value;
} }
@ -4547,25 +4579,37 @@ static void Command_Mapmd5_f(void)
CONS_Printf(M_GetText("You must be in a level to use this.\n")); 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) static void Command_ExitLevel_f(void)
{ {
if (!(netgame || (multiplayer && gametype != GT_COOP)) && !cv_debug) if (!(server || (IsPlayerAdmin(consoleplayer))))
CONS_Printf(M_GetText("This only works in a netgame.\n"));
else if (!(server || (IsPlayerAdmin(consoleplayer))))
CONS_Printf(M_GetText("Only the server or a remote admin can use this.\n")); CONS_Printf(M_GetText("Only the server or a remote admin can use this.\n"));
else if (( gamestate != GS_LEVEL && gamestate != GS_CREDITS ) || demoplayback) else if (( gamestate != GS_LEVEL && gamestate != GS_CREDITS ) || demoplayback)
CONS_Printf(M_GetText("You must be in a level to use this.\n")); CONS_Printf(M_GetText("You must be in a level to use this.\n"));
else else
SendNetXCmd(XD_EXITLEVEL, NULL, 0); D_SendExitLevel(true);
} }
static void Got_ExitLevelcmd(UINT8 **cp, INT32 playernum) static void Got_ExitLevelcmd(UINT8 **cp, INT32 playernum)
{ {
(void)cp; boolean cheat = false;
cheat = (boolean)READUINT8(*cp);
// Ignore duplicate XD_EXITLEVEL commands. // Ignore duplicate XD_EXITLEVEL commands.
if (gameaction == ga_completed) if (gameaction == ga_completed)
{
return; return;
}
if (playernum != serverplayer && !IsPlayerAdmin(playernum)) if (playernum != serverplayer && !IsPlayerAdmin(playernum))
{ {
@ -4575,6 +4619,11 @@ static void Got_ExitLevelcmd(UINT8 **cp, INT32 playernum)
return; return;
} }
if (G_CoopGametype() && cheat)
{
G_SetUsedCheats(false);
}
G_ExitLevel(); G_ExitLevel();
} }
@ -4611,6 +4660,7 @@ void Command_ExitGame_f(void)
botskin = 0; botskin = 0;
cv_debug = 0; cv_debug = 0;
emeralds = 0; emeralds = 0;
automapactive = false;
memset(&luabanks, 0, sizeof(luabanks)); memset(&luabanks, 0, sizeof(luabanks));
if (dirmenu) if (dirmenu)
@ -4646,7 +4696,7 @@ static void Fishcake_OnChange(void)
// so don't make modifiedgame always on! // so don't make modifiedgame always on!
if (cv_debug) if (cv_debug)
{ {
G_SetGameModified(multiplayer); G_SetUsedCheats(false);
} }
else if (cv_debug != cv_fishcake.value) else if (cv_debug != cv_fishcake.value)
@ -4663,11 +4713,11 @@ static void Fishcake_OnChange(void)
static void Command_Isgamemodified_f(void) static void Command_Isgamemodified_f(void)
{ {
if (savemoddata) if (savemoddata)
CONS_Printf(M_GetText("modifiedgame is true, but you can save emblem and time data in this mod.\n")); CONS_Printf(M_GetText("modifiedgame is true, but you can save time data in this mod.\n"));
else if (modifiedgame) else if (modifiedgame)
CONS_Printf(M_GetText("modifiedgame is true, extras will not be unlocked\n")); CONS_Printf(M_GetText("modifiedgame is true, time data can't be saved\n"));
else else
CONS_Printf(M_GetText("modifiedgame is false, you can unlock extras\n")); CONS_Printf(M_GetText("modifiedgame is false, you can save time data\n"));
} }
static void Command_Cheats_f(void) static void Command_Cheats_f(void)

View file

@ -201,6 +201,7 @@ void D_SendPlayerConfig(void);
void Command_ExitGame_f(void); void Command_ExitGame_f(void);
void Command_Retry_f(void); void Command_Retry_f(void);
void D_GameTypeChanged(INT32 lastgametype); // not a real _OnChange function anymore 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); void D_MapChange(INT32 pmapnum, INT32 pgametype, boolean pultmode, boolean presetplayers, INT32 pdelay, boolean pskipprecutscene, boolean pfromlevelselect);
boolean IsPlayerAdmin(INT32 playernum); boolean IsPlayerAdmin(INT32 playernum);
void SetAdminPlayer(INT32 playernum); void SetAdminPlayer(INT32 playernum);

View file

@ -498,7 +498,7 @@ INT32 CL_CheckFiles(void)
CONS_Debug(DBG_NETPLAY, "searching for '%s' ", fileneeded[i].filename); CONS_Debug(DBG_NETPLAY, "searching for '%s' ", fileneeded[i].filename);
// Check in already loaded files // Check in already loaded files
for (j = mainwads; wadfiles[j]; j++) for (j = mainwads; j < numwadfiles; j++)
{ {
nameonly(strcpy(wadfilename, wadfiles[j]->filename)); nameonly(strcpy(wadfilename, wadfiles[j]->filename));
if (!stricmp(wadfilename, fileneeded[i].filename) && if (!stricmp(wadfilename, fileneeded[i].filename) &&

View file

@ -249,6 +249,38 @@ typedef enum
CR_FAN CR_FAN
} carrytype_t; // pw_carry } 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) // Player powers. (don't edit this comment)
typedef enum 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_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 NUMPOWERS
} powertype_t; } powertype_t;
@ -407,6 +441,7 @@ typedef struct player_s
// playing animation. // playing animation.
panim_t panim; panim_t panim;
UINT8 stronganim;
// For screen flashing (bright). // For screen flashing (bright).
UINT16 flashcount; UINT16 flashcount;
@ -418,7 +453,8 @@ typedef struct player_s
INT32 skin; INT32 skin;
UINT32 availabilities; 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 dashspeed; // dashing speed
fixed_t normalspeed; // Normal ground fixed_t normalspeed; // Normal ground

View file

@ -17,6 +17,8 @@
#ifndef __D_THINK__ #ifndef __D_THINK__
#define __D_THINK__ #define __D_THINK__
#include "doomdef.h"
#ifdef __GNUG__ #ifdef __GNUG__
#pragma interface #pragma interface
#endif #endif
@ -49,6 +51,11 @@ typedef struct thinker_s
// killough 11/98: count of how many other objects reference // killough 11/98: count of how many other objects reference
// this one using pointers. Used for garbage collection. // this one using pointers. Used for garbage collection.
INT32 references; INT32 references;
#ifdef PARANOIA
INT32 debug_mobjtype;
tic_t debug_time;
#endif
} thinker_t; } thinker_t;
#endif #endif

View file

@ -10,20 +10,7 @@
/// \file deh_lua.c /// \file deh_lua.c
/// \brief Lua SOC library /// \brief Lua SOC library
#include "g_game.h"
#include "s_sound.h"
#include "z_zone.h"
#include "m_menu.h"
#include "m_misc.h"
#include "p_local.h"
#include "st_stuff.h"
#include "fastcmp.h"
#include "lua_script.h"
#include "lua_libs.h"
#include "dehacked.h"
#include "deh_lua.h" #include "deh_lua.h"
#include "deh_tables.h"
// freeslot takes a name (string only!) // freeslot takes a name (string only!)
// and allocates it to the appropriate free slot. // and allocates it to the appropriate free slot.
@ -89,6 +76,8 @@ static inline int lib_freeslot(lua_State *L)
strncpy(sprnames[j],word,4); strncpy(sprnames[j],word,4);
//sprnames[j][4] = 0; //sprnames[j][4] = 0;
used_spr[(j-SPR_FIRSTFREESLOT)/8] |= 1<<(j%8); // Okay, this sprite slot has been named now. used_spr[(j-SPR_FIRSTFREESLOT)/8] |= 1<<(j%8); // Okay, this sprite slot has been named now.
// Lua needs to update the value in _G if it exists
LUA_UpdateSprName(word, j);
lua_pushinteger(L, j); lua_pushinteger(L, j);
r++; r++;
break; break;
@ -188,6 +177,9 @@ static inline int lib_freeslot(lua_State *L)
lua_remove(L, 1); lua_remove(L, 1);
continue; continue;
} }
R_RefreshSprite2();
return r; return r;
} }
@ -195,39 +187,54 @@ static inline int lib_freeslot(lua_State *L)
// Arguments: mobj_t actor, int var1, int var2 // Arguments: mobj_t actor, int var1, int var2
static int action_call(lua_State *L) 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)); actionf_t *action = *((actionf_t **)luaL_checkudata(L, 1, META_ACTION));
mobj_t *actor = *((mobj_t **)luaL_checkudata(L, 2, META_MOBJ)); mobj_t *actor = *((mobj_t **)luaL_checkudata(L, 2, META_MOBJ));
var1 = (INT32)luaL_optinteger(L, 3, 0); var1 = (INT32)luaL_optinteger(L, 3, 0);
var2 = (INT32)luaL_optinteger(L, 4, 0); var2 = (INT32)luaL_optinteger(L, 4, 0);
if (!actor) if (!actor)
{
return LUA_ErrInvalid(L, "mobj_t"); return LUA_ErrInvalid(L, "mobj_t");
}
action->acp1(actor); action->acp1(actor);
return 0; return 0;
} }
// Hardcoded A_Action name to call for super() or NULL if super() would be invalid. // Hardcoded A_Action name to call for super() or NULL if super() would be invalid.
// Set in lua_infolib. // Set in lua_infolib.
const char *superactions[MAXRECURSION]; const char *luaactions[MAX_ACTION_RECURSION];
UINT8 superstack = 0; UINT8 luaactionstack = 0;
static int lib_dummysuper(lua_State *L) 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 inline int lib_getenum(lua_State *L) static void CacheAndPushConstant(lua_State *L, const char *name, lua_Integer value)
{ {
const char *word, *p; // "cache" into _G
lua_pushstring(L, name);
lua_pushinteger(L, value);
lua_rawset(L, LUA_GLOBALSINDEX);
// push
lua_pushinteger(L, value);
}
// Search for a matching constant variable.
// Result is stored into _G for faster subsequent use. (Except for SPR_ in the SOC parser)
static int ScanConstants(lua_State *L, boolean mathlib, const char *word)
{
const char *p;
fixed_t i; fixed_t i;
boolean mathlib = lua_toboolean(L, lua_upvalueindex(1));
if (lua_type(L,2) != LUA_TSTRING)
return 0;
word = lua_tostring(L,2);
if (strlen(word) == 1) { // Assume sprite frame if length 1. if (strlen(word) == 1) { // Assume sprite frame if length 1.
if (*word >= 'A' && *word <= '~') if (*word >= 'A' && *word <= '~')
{ {
lua_pushinteger(L, *word-'A'); CacheAndPushConstant(L, word, *word-'A');
return 1; return 1;
} }
if (mathlib) return luaL_error(L, "constant '%s' could not be parsed.\n", word); if (mathlib) return luaL_error(L, "constant '%s' could not be parsed.\n", word);
@ -237,7 +244,7 @@ static inline int lib_getenum(lua_State *L)
p = word+3; p = word+3;
for (i = 0; MOBJFLAG_LIST[i]; i++) for (i = 0; MOBJFLAG_LIST[i]; i++)
if (fastcmp(p, MOBJFLAG_LIST[i])) { if (fastcmp(p, MOBJFLAG_LIST[i])) {
lua_pushinteger(L, ((lua_Integer)1<<i)); CacheAndPushConstant(L, word, ((lua_Integer)1<<i));
return 1; return 1;
} }
if (mathlib) return luaL_error(L, "mobjflag '%s' could not be found.\n", word); if (mathlib) return luaL_error(L, "mobjflag '%s' could not be found.\n", word);
@ -247,7 +254,7 @@ static inline int lib_getenum(lua_State *L)
p = word+4; p = word+4;
for (i = 0; MOBJFLAG2_LIST[i]; i++) for (i = 0; MOBJFLAG2_LIST[i]; i++)
if (fastcmp(p, MOBJFLAG2_LIST[i])) { if (fastcmp(p, MOBJFLAG2_LIST[i])) {
lua_pushinteger(L, ((lua_Integer)1<<i)); CacheAndPushConstant(L, word, ((lua_Integer)1<<i));
return 1; return 1;
} }
if (mathlib) return luaL_error(L, "mobjflag2 '%s' could not be found.\n", word); if (mathlib) return luaL_error(L, "mobjflag2 '%s' could not be found.\n", word);
@ -257,12 +264,12 @@ static inline int lib_getenum(lua_State *L)
p = word+4; p = word+4;
for (i = 0; MOBJEFLAG_LIST[i]; i++) for (i = 0; MOBJEFLAG_LIST[i]; i++)
if (fastcmp(p, MOBJEFLAG_LIST[i])) { if (fastcmp(p, MOBJEFLAG_LIST[i])) {
lua_pushinteger(L, ((lua_Integer)1<<i)); CacheAndPushConstant(L, word, ((lua_Integer)1<<i));
return 1; return 1;
} }
if (fastcmp(p, "REVERSESUPER")) if (fastcmp(p, "REVERSESUPER"))
{ {
lua_pushinteger(L, (lua_Integer)MFE_REVERSESUPER); CacheAndPushConstant(L, word, (lua_Integer)MFE_REVERSESUPER);
return 1; return 1;
} }
if (mathlib) return luaL_error(L, "mobjeflag '%s' could not be found.\n", word); if (mathlib) return luaL_error(L, "mobjeflag '%s' could not be found.\n", word);
@ -270,9 +277,9 @@ static inline int lib_getenum(lua_State *L)
} }
else if (fastncmp("MTF_", word, 4)) { else if (fastncmp("MTF_", word, 4)) {
p = word+4; p = word+4;
for (i = 0; i < 4; i++) for (i = 0; MAPTHINGFLAG_LIST[i]; i++)
if (MAPTHINGFLAG_LIST[i] && fastcmp(p, MAPTHINGFLAG_LIST[i])) { if (fastcmp(p, MAPTHINGFLAG_LIST[i])) {
lua_pushinteger(L, ((lua_Integer)1<<i)); CacheAndPushConstant(L, word, ((lua_Integer)1<<i));
return 1; return 1;
} }
if (mathlib) return luaL_error(L, "mapthingflag '%s' could not be found.\n", word); if (mathlib) return luaL_error(L, "mapthingflag '%s' could not be found.\n", word);
@ -282,17 +289,17 @@ static inline int lib_getenum(lua_State *L)
p = word+3; p = word+3;
for (i = 0; PLAYERFLAG_LIST[i]; i++) for (i = 0; PLAYERFLAG_LIST[i]; i++)
if (fastcmp(p, PLAYERFLAG_LIST[i])) { if (fastcmp(p, PLAYERFLAG_LIST[i])) {
lua_pushinteger(L, ((lua_Integer)1<<i)); CacheAndPushConstant(L, word, ((lua_Integer)1<<i));
return 1; return 1;
} }
if (fastcmp(p, "FULLSTASIS")) if (fastcmp(p, "FULLSTASIS"))
{ {
lua_pushinteger(L, (lua_Integer)PF_FULLSTASIS); CacheAndPushConstant(L, word, (lua_Integer)PF_FULLSTASIS);
return 1; return 1;
} }
else if (fastcmp(p, "USEDOWN")) // Remove case when 2.3 nears release... else if (fastcmp(p, "USEDOWN")) // Remove case when 2.3 nears release...
{ {
lua_pushinteger(L, (lua_Integer)PF_SPINDOWN); CacheAndPushConstant(L, word, (lua_Integer)PF_SPINDOWN);
return 1; return 1;
} }
if (mathlib) return luaL_error(L, "playerflag '%s' could not be found.\n", word); if (mathlib) return luaL_error(L, "playerflag '%s' could not be found.\n", word);
@ -302,7 +309,7 @@ static inline int lib_getenum(lua_State *L)
p = word; p = word;
for (i = 0; Gametype_ConstantNames[i]; i++) for (i = 0; Gametype_ConstantNames[i]; i++)
if (fastcmp(p, Gametype_ConstantNames[i])) { if (fastcmp(p, Gametype_ConstantNames[i])) {
lua_pushinteger(L, i); CacheAndPushConstant(L, word, i);
return 1; return 1;
} }
if (mathlib) return luaL_error(L, "gametype '%s' could not be found.\n", word); if (mathlib) return luaL_error(L, "gametype '%s' could not be found.\n", word);
@ -312,7 +319,7 @@ static inline int lib_getenum(lua_State *L)
p = word+4; p = word+4;
for (i = 0; GAMETYPERULE_LIST[i]; i++) for (i = 0; GAMETYPERULE_LIST[i]; i++)
if (fastcmp(p, GAMETYPERULE_LIST[i])) { if (fastcmp(p, GAMETYPERULE_LIST[i])) {
lua_pushinteger(L, ((lua_Integer)1<<i)); CacheAndPushConstant(L, word, ((lua_Integer)1<<i));
return 1; return 1;
} }
if (mathlib) return luaL_error(L, "game type rule '%s' could not be found.\n", word); if (mathlib) return luaL_error(L, "game type rule '%s' could not be found.\n", word);
@ -322,7 +329,7 @@ static inline int lib_getenum(lua_State *L)
p = word+4; p = word+4;
for (i = 0; TYPEOFLEVEL[i].name; i++) for (i = 0; TYPEOFLEVEL[i].name; i++)
if (fastcmp(p, TYPEOFLEVEL[i].name)) { if (fastcmp(p, TYPEOFLEVEL[i].name)) {
lua_pushinteger(L, TYPEOFLEVEL[i].flag); CacheAndPushConstant(L, word, TYPEOFLEVEL[i].flag);
return 1; return 1;
} }
if (mathlib) return luaL_error(L, "typeoflevel '%s' could not be found.\n", word); if (mathlib) return luaL_error(L, "typeoflevel '%s' could not be found.\n", word);
@ -330,9 +337,10 @@ static inline int lib_getenum(lua_State *L)
} }
else if (fastncmp("ML_", word, 3)) { else if (fastncmp("ML_", word, 3)) {
p = word+3; p = word+3;
for (i = 0; ML_LIST[i]; i++) for (i = 0; ML_LIST[i]; i++)
if (fastcmp(p, ML_LIST[i])) { if (fastcmp(p, ML_LIST[i])) {
lua_pushinteger(L, ((lua_Integer)1<<i)); CacheAndPushConstant(L, word, ((lua_Integer)1<<i));
return 1; return 1;
} }
// Aliases // Aliases
@ -415,13 +423,13 @@ static inline int lib_getenum(lua_State *L)
if (!FREE_STATES[i]) if (!FREE_STATES[i])
break; break;
if (fastcmp(p, FREE_STATES[i])) { if (fastcmp(p, FREE_STATES[i])) {
lua_pushinteger(L, S_FIRSTFREESLOT+i); CacheAndPushConstant(L, word, S_FIRSTFREESLOT+i);
return 1; return 1;
} }
} }
for (i = 0; i < S_FIRSTFREESLOT; i++) for (i = 0; i < S_FIRSTFREESLOT; i++)
if (fastcmp(p, STATE_LIST[i]+2)) { if (fastcmp(p, STATE_LIST[i]+2)) {
lua_pushinteger(L, i); CacheAndPushConstant(L, word, i);
return 1; return 1;
} }
return luaL_error(L, "state '%s' does not exist.\n", word); return luaL_error(L, "state '%s' does not exist.\n", word);
@ -432,13 +440,13 @@ static inline int lib_getenum(lua_State *L)
if (!FREE_MOBJS[i]) if (!FREE_MOBJS[i])
break; break;
if (fastcmp(p, FREE_MOBJS[i])) { if (fastcmp(p, FREE_MOBJS[i])) {
lua_pushinteger(L, MT_FIRSTFREESLOT+i); CacheAndPushConstant(L, word, MT_FIRSTFREESLOT+i);
return 1; return 1;
} }
} }
for (i = 0; i < MT_FIRSTFREESLOT; i++) for (i = 0; i < MT_FIRSTFREESLOT; i++)
if (fastcmp(p, MOBJTYPE_LIST[i]+3)) { if (fastcmp(p, MOBJTYPE_LIST[i]+3)) {
lua_pushinteger(L, i); CacheAndPushConstant(L, word, i);
return 1; return 1;
} }
return luaL_error(L, "mobjtype '%s' does not exist.\n", word); return luaL_error(L, "mobjtype '%s' does not exist.\n", word);
@ -447,7 +455,12 @@ static inline int lib_getenum(lua_State *L)
p = word+4; p = word+4;
for (i = 0; i < NUMSPRITES; i++) for (i = 0; i < NUMSPRITES; i++)
if (!sprnames[i][4] && fastncmp(p,sprnames[i],4)) { if (!sprnames[i][4] && fastncmp(p,sprnames[i],4)) {
lua_pushinteger(L, i); // updating overridden sprnames is not implemented for soc parser,
// so don't use cache
if (mathlib)
lua_pushinteger(L, i);
else
CacheAndPushConstant(L, word, i);
return 1; return 1;
} }
if (mathlib) return luaL_error(L, "sprite '%s' could not be found.\n", word); if (mathlib) return luaL_error(L, "sprite '%s' could not be found.\n", word);
@ -462,12 +475,12 @@ static inline int lib_getenum(lua_State *L)
// the spr2names entry will have "_" on the end, as in "RUN_" // the spr2names entry will have "_" on the end, as in "RUN_"
if (spr2names[i][3] == '_' && !p[3]) { if (spr2names[i][3] == '_' && !p[3]) {
if (fastncmp(p,spr2names[i],3)) { if (fastncmp(p,spr2names[i],3)) {
lua_pushinteger(L, i); CacheAndPushConstant(L, word, i);
return 1; return 1;
} }
} }
else if (fastncmp(p,spr2names[i],4)) { else if (fastncmp(p,spr2names[i],4)) {
lua_pushinteger(L, i); CacheAndPushConstant(L, word, i);
return 1; return 1;
} }
} }
@ -478,7 +491,7 @@ static inline int lib_getenum(lua_State *L)
p = word+4; p = word+4;
for (i = 0; i < NUMSFX; i++) for (i = 0; i < NUMSFX; i++)
if (S_sfx[i].name && fastcmp(p, S_sfx[i].name)) { if (S_sfx[i].name && fastcmp(p, S_sfx[i].name)) {
lua_pushinteger(L, i); CacheAndPushConstant(L, word, i);
return 1; return 1;
} }
return 0; return 0;
@ -487,7 +500,7 @@ static inline int lib_getenum(lua_State *L)
p = word+4; p = word+4;
for (i = 0; i < NUMSFX; i++) for (i = 0; i < NUMSFX; i++)
if (S_sfx[i].name && fasticmp(p, S_sfx[i].name)) { if (S_sfx[i].name && fasticmp(p, S_sfx[i].name)) {
lua_pushinteger(L, i); CacheAndPushConstant(L, word, i);
return 1; return 1;
} }
return luaL_error(L, "sfx '%s' could not be found.\n", word); return luaL_error(L, "sfx '%s' could not be found.\n", word);
@ -496,7 +509,7 @@ static inline int lib_getenum(lua_State *L)
p = word+2; p = word+2;
for (i = 0; i < NUMSFX; i++) for (i = 0; i < NUMSFX; i++)
if (S_sfx[i].name && fasticmp(p, S_sfx[i].name)) { if (S_sfx[i].name && fasticmp(p, S_sfx[i].name)) {
lua_pushinteger(L, i); CacheAndPushConstant(L, word, i);
return 1; return 1;
} }
if (mathlib) return luaL_error(L, "sfx '%s' could not be found.\n", word); if (mathlib) return luaL_error(L, "sfx '%s' could not be found.\n", word);
@ -506,7 +519,7 @@ static inline int lib_getenum(lua_State *L)
p = word+3; p = word+3;
for (i = 0; i < NUMPOWERS; i++) for (i = 0; i < NUMPOWERS; i++)
if (fasticmp(p, POWERS_LIST[i])) { if (fasticmp(p, POWERS_LIST[i])) {
lua_pushinteger(L, i); CacheAndPushConstant(L, word, i);
return 1; return 1;
} }
return 0; return 0;
@ -515,7 +528,7 @@ static inline int lib_getenum(lua_State *L)
p = word+3; p = word+3;
for (i = 0; i < NUMPOWERS; i++) for (i = 0; i < NUMPOWERS; i++)
if (fastcmp(p, POWERS_LIST[i])) { if (fastcmp(p, POWERS_LIST[i])) {
lua_pushinteger(L, i); CacheAndPushConstant(L, word, i);
return 1; return 1;
} }
return luaL_error(L, "power '%s' could not be found.\n", word); return luaL_error(L, "power '%s' could not be found.\n", word);
@ -524,7 +537,7 @@ static inline int lib_getenum(lua_State *L)
p = word+4; p = word+4;
for (i = 0; i < NUMHUDITEMS; i++) for (i = 0; i < NUMHUDITEMS; i++)
if (fastcmp(p, HUDITEMS_LIST[i])) { if (fastcmp(p, HUDITEMS_LIST[i])) {
lua_pushinteger(L, i); CacheAndPushConstant(L, word, i);
return 1; return 1;
} }
if (mathlib) return luaL_error(L, "huditem '%s' could not be found.\n", word); if (mathlib) return luaL_error(L, "huditem '%s' could not be found.\n", word);
@ -536,13 +549,13 @@ static inline int lib_getenum(lua_State *L)
if (!FREE_SKINCOLORS[i]) if (!FREE_SKINCOLORS[i])
break; break;
if (fastcmp(p, FREE_SKINCOLORS[i])) { if (fastcmp(p, FREE_SKINCOLORS[i])) {
lua_pushinteger(L, SKINCOLOR_FIRSTFREESLOT+i); CacheAndPushConstant(L, word, SKINCOLOR_FIRSTFREESLOT+i);
return 1; return 1;
} }
} }
for (i = 0; i < SKINCOLOR_FIRSTFREESLOT; i++) for (i = 0; i < SKINCOLOR_FIRSTFREESLOT; i++)
if (fastcmp(p, COLOR_ENUMS[i])) { if (fastcmp(p, COLOR_ENUMS[i])) {
lua_pushinteger(L, i); CacheAndPushConstant(L, word, i);
return 1; return 1;
} }
return luaL_error(L, "skincolor '%s' could not be found.\n", word); return luaL_error(L, "skincolor '%s' could not be found.\n", word);
@ -553,7 +566,7 @@ static inline int lib_getenum(lua_State *L)
for (i = 0; NIGHTSGRADE_LIST[i]; i++) for (i = 0; NIGHTSGRADE_LIST[i]; i++)
if (*p == NIGHTSGRADE_LIST[i]) if (*p == NIGHTSGRADE_LIST[i])
{ {
lua_pushinteger(L, i); CacheAndPushConstant(L, word, i);
return 1; return 1;
} }
if (mathlib) return luaL_error(L, "NiGHTS grade '%s' could not be found.\n", word); if (mathlib) return luaL_error(L, "NiGHTS grade '%s' could not be found.\n", word);
@ -563,70 +576,127 @@ static inline int lib_getenum(lua_State *L)
p = word+3; p = word+3;
for (i = 0; i < NUMMENUTYPES; i++) for (i = 0; i < NUMMENUTYPES; i++)
if (fastcmp(p, MENUTYPES_LIST[i])) { if (fastcmp(p, MENUTYPES_LIST[i])) {
lua_pushinteger(L, i); CacheAndPushConstant(L, word, i);
return 1; return 1;
} }
if (mathlib) return luaL_error(L, "menutype '%s' could not be found.\n", word); if (mathlib) return luaL_error(L, "menutype '%s' could not be found.\n", word);
return 0; return 0;
} }
else if (!mathlib && fastncmp("A_",word,2)) {
char *caps;
// Try to get a Lua action first.
/// \todo Push a closure that sets superactions[] and superstack.
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)
{
lua_pushcfunction(L, lib_dummysuper);
return 1;
}
for (i = 0; actionpointers[i].name; i++)
if (fasticmp(superactions[superstack-1], actionpointers[i].name)) {
LUA_PushUserdata(L, &actionpointers[i].action, META_ACTION);
return 1;
}
return 0;
}
if (fastcmp(word, "BT_USE")) // Remove case when 2.3 nears release... if (fastcmp(word, "BT_USE")) // Remove case when 2.3 nears release...
{ {
lua_pushinteger(L, (lua_Integer)BT_SPIN); CacheAndPushConstant(L, word, (lua_Integer)BT_SPIN);
return 1; return 1;
} }
for (i = 0; INT_CONST[i].n; i++) for (i = 0; INT_CONST[i].n; i++)
if (fastcmp(word,INT_CONST[i].n)) { if (fastcmp(word,INT_CONST[i].n)) {
lua_pushinteger(L, INT_CONST[i].v); CacheAndPushConstant(L, word, INT_CONST[i].v);
return 1; return 1;
} }
return 0;
}
static inline int lib_getenum(lua_State *L)
{
const char *word;
fixed_t i;
boolean mathlib = lua_toboolean(L, lua_upvalueindex(1));
if (lua_type(L,2) != LUA_TSTRING)
return 0;
word = lua_tostring(L,2);
// check actions, super and globals first, as they don't have _G caching implemented
// so they benefit from being checked first
if (!mathlib && fastncmp("A_",word,2)) {
char *caps;
// 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
return 0;
}
else if (!mathlib && fastcmp("super",word))
{
if (!luaactionstack)
{
// Not in A_ action routine
lua_pushcfunction(L, lib_dummysuper);
return 1;
}
for (i = 0; actionpointers[i].name; i++)
{
if (fasticmp(luaactions[luaactionstack-1], actionpointers[i].name))
{
LUA_PushUserdata(L, &actionpointers[i].action, META_ACTION);
return 1;
}
}
// 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;
if (mathlib) return luaL_error(L, "constant '%s' could not be parsed.\n", word); if (mathlib) return luaL_error(L, "constant '%s' could not be parsed.\n", word);
// DYNAMIC variables too!! return 0;
// Try not to add anything that would break netgames or timeattack replays here. }
// You know, like consoleplayer, displayplayer, secondarydisplayplayer, or gametime.
return LUA_PushGlobals(L, word); // If a sprname has been "cached" to _G, update it to a new value.
void LUA_UpdateSprName(const char *name, lua_Integer value)
{
char fullname[9] = "SPR_XXXX";
if (!gL)
return;
strncpy(&fullname[4], name, 4);
lua_pushstring(gL, fullname);
lua_rawget(gL, LUA_GLOBALSINDEX);
if (!lua_isnil(gL, -1))
{
lua_pushstring(gL, name);
lua_pushinteger(gL, value);
lua_rawset(gL, LUA_GLOBALSINDEX);
}
lua_pop(gL, 1); // pop the rawget result
} }
int LUA_EnumLib(lua_State *L) int LUA_EnumLib(lua_State *L)

View file

@ -13,6 +13,21 @@
#ifndef __DEH_LUA_H__ #ifndef __DEH_LUA_H__
#define __DEH_LUA_H__ #define __DEH_LUA_H__
#include "g_game.h"
#include "s_sound.h"
#include "z_zone.h"
#include "m_menu.h"
#include "m_misc.h"
#include "p_local.h"
#include "st_stuff.h"
#include "fastcmp.h"
#include "lua_script.h"
#include "lua_libs.h"
#include "dehacked.h"
#include "deh_tables.h"
void LUA_UpdateSprName(const char *name, lua_Integer value);
boolean LUA_SetLuaAction(void *state, const char *actiontocompare); boolean LUA_SetLuaAction(void *state, const char *actiontocompare);
const char *LUA_GetActionName(void *action); const char *LUA_GetActionName(void *action);
void LUA_SetActionByName(void *state, const char *actiontocompare); void LUA_SetActionByName(void *state, const char *actiontocompare);

View file

@ -45,6 +45,7 @@
#include "dehacked.h" #include "dehacked.h"
#include "deh_soc.h" #include "deh_soc.h"
#include "deh_lua.h" // included due to some LUA_SetLuaAction hack smh #include "deh_lua.h" // included due to some LUA_SetLuaAction hack smh
// also used for LUA_UpdateSprName
#include "deh_tables.h" #include "deh_tables.h"
// Loops through every constant and operation in word and performs its calculations, returning the final value. // Loops through every constant and operation in word and performs its calculations, returning the final value.
@ -439,6 +440,8 @@ void readfreeslots(MYFILE *f)
strncpy(sprnames[i],word,4); strncpy(sprnames[i],word,4);
//sprnames[i][4] = 0; //sprnames[i][4] = 0;
used_spr[(i-SPR_FIRSTFREESLOT)/8] |= 1<<(i%8); // Okay, this sprite slot has been named now. used_spr[(i-SPR_FIRSTFREESLOT)/8] |= 1<<(i%8); // Okay, this sprite slot has been named now.
// Lua needs to update the value in _G if it exists
LUA_UpdateSprName(word, i);
break; break;
} }
} }
@ -513,6 +516,8 @@ void readfreeslots(MYFILE *f)
} while (!myfeof(f)); // finish when the line is empty } while (!myfeof(f)); // finish when the line is empty
Z_Free(s); Z_Free(s);
R_RefreshSprite2();
} }
void readthing(MYFILE *f, INT32 num) void readthing(MYFILE *f, INT32 num)
@ -907,7 +912,7 @@ static void readspriteframe(MYFILE *f, spriteinfo_t *sprinfo, UINT8 frame)
else if (fastcmp(word, "YPIVOT")) else if (fastcmp(word, "YPIVOT"))
sprinfo->pivot[frame].y = value; sprinfo->pivot[frame].y = value;
else if (fastcmp(word, "ROTAXIS")) else if (fastcmp(word, "ROTAXIS"))
sprinfo->pivot[frame].rotaxis = value; deh_warning("SpriteInfo: ROTAXIS is deprecated and will be removed.");
else else
{ {
f->curpos = lastline; f->curpos = lastline;
@ -2907,7 +2912,9 @@ static boolean GoodDataFileName(const char *s)
p = s + strlen(s) - strlen(tail); p = s + strlen(s) - strlen(tail);
if (p <= s) return false; // too short if (p <= s) return false; // too short
if (!fasticmp(p, tail)) return false; // doesn't end in .dat if (!fasticmp(p, tail)) return false; // doesn't end in .dat
if (fasticmp(s, "gamedata.dat")) return false;
if (fasticmp(s, "gamedata.dat")) return false; // Don't overwrite default gamedata
if (fasticmp(s, "main.dat")) return false; // Don't overwrite default time attack replays
return true; return true;
} }
@ -3835,6 +3842,10 @@ void readmaincfg(MYFILE *f)
{ {
useContinues = (UINT8)(value || word2[0] == 'T' || word2[0] == 'Y'); useContinues = (UINT8)(value || word2[0] == 'T' || word2[0] == 'Y');
} }
else if (fastcmp(word, "SHAREEMBLEMS"))
{
shareEmblems = (UINT8)(value || word2[0] == 'T' || word2[0] == 'Y');
}
else if (fastcmp(word, "GAMEDATA")) else if (fastcmp(word, "GAMEDATA"))
{ {
@ -3845,7 +3856,7 @@ void readmaincfg(MYFILE *f)
if (!GoodDataFileName(word2)) if (!GoodDataFileName(word2))
I_Error("Maincfg: bad data file name '%s'\n", word2); I_Error("Maincfg: bad data file name '%s'\n", word2);
G_SaveGameData(); G_SaveGameData(clientGamedata);
strlcpy(gamedatafilename, word2, sizeof (gamedatafilename)); strlcpy(gamedatafilename, word2, sizeof (gamedatafilename));
strlwr(gamedatafilename); strlwr(gamedatafilename);
savemoddata = true; savemoddata = true;

View file

@ -198,6 +198,7 @@ actionpointer_t actionpointers[] =
{{A_Boss3TakeDamage}, "A_BOSS3TAKEDAMAGE"}, {{A_Boss3TakeDamage}, "A_BOSS3TAKEDAMAGE"},
{{A_Boss3Path}, "A_BOSS3PATH"}, {{A_Boss3Path}, "A_BOSS3PATH"},
{{A_Boss3ShockThink}, "A_BOSS3SHOCKTHINK"}, {{A_Boss3ShockThink}, "A_BOSS3SHOCKTHINK"},
{{A_Shockwave}, "A_SHOCKWAVE"},
{{A_LinedefExecute}, "A_LINEDEFEXECUTE"}, {{A_LinedefExecute}, "A_LINEDEFEXECUTE"},
{{A_LinedefExecuteFromArg}, "A_LINEDEFEXECUTEFROMARG"}, {{A_LinedefExecuteFromArg}, "A_LINEDEFEXECUTEFROMARG"},
{{A_PlaySeeSound}, "A_PLAYSEESOUND"}, {{A_PlaySeeSound}, "A_PLAYSEESOUND"},
@ -4409,11 +4410,12 @@ const char *const MOBJEFLAG_LIST[] = {
NULL NULL
}; };
const char *const MAPTHINGFLAG_LIST[4] = { const char *const MAPTHINGFLAG_LIST[] = {
"EXTRA", // Extra flag for objects. "EXTRA", // Extra flag for objects.
"OBJECTFLIP", // Reverse gravity flag for objects. "OBJECTFLIP", // Reverse gravity flag for objects.
"OBJECTSPECIAL", // Special flag used with certain 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[] = { const char *const PLAYERFLAG_LIST[] = {
@ -4550,6 +4552,7 @@ const char *const MSF_LIST[] = {
const char *const SSF_LIST[] = { const char *const SSF_LIST[] = {
"OUTERSPACE", "OUTERSPACE",
"DOUBLESTEPUP", "DOUBLESTEPUP",
"NOSTEPDOWN",
"WINDCURRENT", "WINDCURRENT",
"CONVEYOR", "CONVEYOR",
"SPEEDPAD", "SPEEDPAD",
@ -4566,6 +4569,8 @@ const char *const SSF_LIST[] = {
"ZOOMTUBEEND", "ZOOMTUBEEND",
"FINISHLINE", "FINISHLINE",
"ROPEHANG", "ROPEHANG",
"JUMPFLIP",
"GRAVITYOVERRIDE",
NULL NULL
}; };
@ -4609,66 +4614,111 @@ const char *COLOR_ENUMS[] = {
// Desaturated // Desaturated
"AETHER", // SKINCOLOR_AETHER, "AETHER", // SKINCOLOR_AETHER,
"SLATE", // SKINCOLOR_SLATE, "SLATE", // SKINCOLOR_SLATE,
"MOONSTONE", // SKINCOLOR_MOONSTONE,
"BLUEBELL", // SKINCOLOR_BLUEBELL, "BLUEBELL", // SKINCOLOR_BLUEBELL,
"PINK", // SKINCOLOR_PINK, "PINK", // SKINCOLOR_PINK,
"ROSEWOOD", // SKINCOLOR_ROSEWOOD,
"YOGURT", // SKINCOLOR_YOGURT, "YOGURT", // SKINCOLOR_YOGURT,
"LATTE", // SKINCOLOR_LATTE,
"BROWN", // SKINCOLOR_BROWN, "BROWN", // SKINCOLOR_BROWN,
"BOULDER", // SKINCOLOR_BOULDER
"BRONZE", // SKINCOLOR_BRONZE, "BRONZE", // SKINCOLOR_BRONZE,
"TAN", // SKINCOLOR_TAN, "SEPIA", // SKINCOLOR_SEPIA,
"ECRU", // SKINCOLOR_ECRU,
"TAN", // SKINCOLOR_TAN,
"BEIGE", // SKINCOLOR_BEIGE, "BEIGE", // SKINCOLOR_BEIGE,
"ROSEBUSH", // SKINCOLOR_ROSEBUSH,
"MOSS", // SKINCOLOR_MOSS, "MOSS", // SKINCOLOR_MOSS,
"AZURE", // SKINCOLOR_AZURE, "AZURE", // SKINCOLOR_AZURE,
"LAVENDER", // SKINCOLOR_LAVENDER, "EGGPLANT", // SKINCOLOR_EGGPLANT,
"LAVENDER", // SKINCOLOR_LAVENDER,
// Viv's vivid colours (toast 21/07/17) // Viv's vivid colours (toast 21/07/17)
// Tweaks & additions (Lach, sphere, Alice, MotorRoach 26/10/22)
"RUBY", // SKINCOLOR_RUBY, "RUBY", // SKINCOLOR_RUBY,
"CHERRY", // SKINCOLOR_CHERRY,
"SALMON", // SKINCOLOR_SALMON, "SALMON", // SKINCOLOR_SALMON,
"PEPPER", // SKINCOLOR_PEPPER,
"RED", // SKINCOLOR_RED, "RED", // SKINCOLOR_RED,
"CRIMSON", // SKINCOLOR_CRIMSON, "CRIMSON", // SKINCOLOR_CRIMSON,
"FLAME", // SKINCOLOR_FLAME, "FLAME", // SKINCOLOR_FLAME,
"GARNET", // SKINCOLOR_GARNET,
"KETCHUP", // SKINCOLOR_KETCHUP, "KETCHUP", // SKINCOLOR_KETCHUP,
"PEACHY", // SKINCOLOR_PEACHY, "PEACHY", // SKINCOLOR_PEACHY,
"QUAIL", // SKINCOLOR_QUAIL, "QUAIL", // SKINCOLOR_QUAIL,
"FOUNDATION", // SKINCOLOR_FOUNDATION,
"SUNSET", // SKINCOLOR_SUNSET, "SUNSET", // SKINCOLOR_SUNSET,
"COPPER", // SKINCOLOR_COPPER, "COPPER", // SKINCOLOR_COPPER,
"APRICOT", // SKINCOLOR_APRICOT, "APRICOT", // SKINCOLOR_APRICOT,
"ORANGE", // SKINCOLOR_ORANGE, "ORANGE", // SKINCOLOR_ORANGE,
"RUST", // SKINCOLOR_RUST, "RUST", // SKINCOLOR_RUST,
"TANGERINE", // SKINCOLOR_TANGERINE,
"TOPAZ", // SKINCOLOR_TOPAZ,
"GOLD", // SKINCOLOR_GOLD, "GOLD", // SKINCOLOR_GOLD,
"SANDY", // SKINCOLOR_SANDY, "SANDY", // SKINCOLOR_SANDY,
"GOLDENROD", // SKINCOLOR_GOLDENROD,
"YELLOW", // SKINCOLOR_YELLOW, "YELLOW", // SKINCOLOR_YELLOW,
"OLIVE", // SKINCOLOR_OLIVE, "OLIVE", // SKINCOLOR_OLIVE,
"PEAR", // SKINCOLOR_PEAR,
"LEMON", // SKINCOLOR_LEMON,
"LIME", // SKINCOLOR_LIME, "LIME", // SKINCOLOR_LIME,
"PERIDOT", // SKINCOLOR_PERIDOT, "PERIDOT", // SKINCOLOR_PERIDOT,
"APPLE", // SKINCOLOR_APPLE, "APPLE", // SKINCOLOR_APPLE,
"HEADLIGHT", // SKINCOLOR_HEADLIGHT,
"CHARTREUSE", // SKINCOLOR_CHARTREUSE,
"GREEN", // SKINCOLOR_GREEN, "GREEN", // SKINCOLOR_GREEN,
"FOREST", // SKINCOLOR_FOREST, "FOREST", // SKINCOLOR_FOREST,
"EMERALD", // SKINCOLOR_EMERALD, "SHAMROCK", // SKINCOLOR_SHAMROCK,
"JADE", // SKINCOLOR_JADE,
"MINT", // SKINCOLOR_MINT, "MINT", // SKINCOLOR_MINT,
"MASTER", // SKINCOLOR_MASTER,
"EMERALD", // SKINCOLOR_EMERALD,
"SEAFOAM", // SKINCOLOR_SEAFOAM, "SEAFOAM", // SKINCOLOR_SEAFOAM,
"ISLAND", // SKINCOLOR_ISLAND,
"BOTTLE", // SKINCOLOR_BOTTLE,
"AQUA", // SKINCOLOR_AQUA, "AQUA", // SKINCOLOR_AQUA,
"TEAL", // SKINCOLOR_TEAL, "TEAL", // SKINCOLOR_TEAL,
"OCEAN", // SKINCOLOR_OCEAN,
"WAVE", // SKINCOLOR_WAVE, "WAVE", // SKINCOLOR_WAVE,
"CYAN", // SKINCOLOR_CYAN, "CYAN", // SKINCOLOR_CYAN,
"TURQUOISE", // SKINCOLOR_TURQUOISE,
"AQUAMARINE", // SKINCOLOR_AQUAMARINE,
"SKY", // SKINCOLOR_SKY, "SKY", // SKINCOLOR_SKY,
"MARINE", // SKINCOLOR_MARINE,
"CERULEAN", // SKINCOLOR_CERULEAN, "CERULEAN", // SKINCOLOR_CERULEAN,
"DREAM", // SKINCOLOR_DREAM,
"ICY", // SKINCOLOR_ICY, "ICY", // SKINCOLOR_ICY,
"DAYBREAK", // SKINCOLOR_DAYBREAK,
"SAPPHIRE", // SKINCOLOR_SAPPHIRE, "SAPPHIRE", // SKINCOLOR_SAPPHIRE,
"ARCTIC", // SKINCOLOR_ARCTIC,
"CORNFLOWER", // SKINCOLOR_CORNFLOWER, "CORNFLOWER", // SKINCOLOR_CORNFLOWER,
"BLUE", // SKINCOLOR_BLUE, "BLUE", // SKINCOLOR_BLUE,
"COBALT", // SKINCOLOR_COBALT, "COBALT", // SKINCOLOR_COBALT,
"MIDNIGHT", // SKINCOLOR_MIDNIGHT,
"GALAXY", // SKINCOLOR_GALAXY,
"VAPOR", // SKINCOLOR_VAPOR, "VAPOR", // SKINCOLOR_VAPOR,
"DUSK", // SKINCOLOR_DUSK, "DUSK", // SKINCOLOR_DUSK,
"MAJESTY", // SKINCOLOR_MAJESTY,
"PASTEL", // SKINCOLOR_PASTEL, "PASTEL", // SKINCOLOR_PASTEL,
"PURPLE", // SKINCOLOR_PURPLE, "PURPLE", // SKINCOLOR_PURPLE,
"BUBBLEGUM", // SKINCOLOR_BUBBLEGUM, "NOBLE", // SKINCOLOR_NOBLE,
"FUCHSIA", // SKINCOLOR_FUCHSIA,
"BUBBLEGUM", // SKINCOLOR_BUBBLEGUM,
"SIBERITE", // SKINCOLOR_SIBERITE,
"MAGENTA", // SKINCOLOR_MAGENTA, "MAGENTA", // SKINCOLOR_MAGENTA,
"NEON", // SKINCOLOR_NEON, "NEON", // SKINCOLOR_NEON,
"VIOLET", // SKINCOLOR_VIOLET, "VIOLET", // SKINCOLOR_VIOLET,
"ROYAL", // SKINCOLOR_ROYAL,
"LILAC", // SKINCOLOR_LILAC, "LILAC", // SKINCOLOR_LILAC,
"MAUVE", // SKINCOLOR_MAUVE,
"EVENTIDE", // SKINCOLOR_EVENTIDE,
"PLUM", // SKINCOLOR_PLUM, "PLUM", // SKINCOLOR_PLUM,
"RASPBERRY", // SKINCOLOR_RASPBERRY, "RASPBERRY", // SKINCOLOR_RASPBERRY,
"TAFFY", // SKINCOLOR_TAFFY,
"ROSY", // SKINCOLOR_ROSY, "ROSY", // SKINCOLOR_ROSY,
"FANCY", // SKINCOLOR_FANCY,
"SANGRIA", // SKINCOLOR_SANGRIA,
"VOLCANIC", // SKINCOLOR_VOLCANIC,
// Super special awesome Super flashing colors! // Super special awesome Super flashing colors!
"SUPERSILVER1", // SKINCOLOR_SUPERSILVER1 "SUPERSILVER1", // SKINCOLOR_SUPERSILVER1
@ -4768,7 +4818,9 @@ const char *const POWERS_LIST[] = {
"JUSTLAUNCHED", "JUSTLAUNCHED",
"IGNORELATCH" "IGNORELATCH",
"STRONG"
}; };
const char *const HUDITEMS_LIST[] = { const char *const HUDITEMS_LIST[] = {
@ -5121,6 +5173,30 @@ struct int_const_s const INT_CONST[] = {
{"CR_DUSTDEVIL",CR_DUSTDEVIL}, {"CR_DUSTDEVIL",CR_DUSTDEVIL},
{"CR_FAN",CR_FAN}, {"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) // Ring weapons (ringweapons_t)
// Useful for A_GiveWeapon // Useful for A_GiveWeapon
{"RW_AUTO",RW_AUTO}, {"RW_AUTO",RW_AUTO},

View file

@ -30,6 +30,7 @@ extern UINT8 used_spr[(NUMSPRITEFREESLOTS / 8) + 1]; // Bitwise flag for sprite
memset(FREE_MOBJS,0,sizeof(char *) * NUMMOBJFREESLOTS);\ memset(FREE_MOBJS,0,sizeof(char *) * NUMMOBJFREESLOTS);\
memset(FREE_SKINCOLORS,0,sizeof(char *) * NUMCOLORFREESLOTS);\ memset(FREE_SKINCOLORS,0,sizeof(char *) * NUMCOLORFREESLOTS);\
memset(used_spr,0,sizeof(UINT8) * ((NUMSPRITEFREESLOTS / 8) + 1));\ memset(used_spr,0,sizeof(UINT8) * ((NUMSPRITEFREESLOTS / 8) + 1));\
memset(actionsoverridden, LUA_REFNIL, sizeof(actionsoverridden));\
} }
struct flickytypes_s { struct flickytypes_s {
@ -61,7 +62,7 @@ extern const char *const MOBJTYPE_LIST[];
extern const char *const MOBJFLAG_LIST[]; extern const char *const MOBJFLAG_LIST[];
extern const char *const MOBJFLAG2_LIST[]; // \tMF2_(\S+).*// (.+) --> \t"\1", // \2 extern const char *const MOBJFLAG2_LIST[]; // \tMF2_(\S+).*// (.+) --> \t"\1", // \2
extern const char *const MOBJEFLAG_LIST[]; 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 PLAYERFLAG_LIST[];
extern const char *const GAMETYPERULE_LIST[]; extern const char *const GAMETYPERULE_LIST[];
extern const char *const ML_LIST[]; // Linedef flags extern const char *const ML_LIST[]; // Linedef flags

View file

@ -575,7 +575,7 @@ static void DEH_LoadDehackedFile(MYFILE *f, boolean mainfile)
} // end while } // end while
if (gamedataadded) if (gamedataadded)
G_LoadGameData(); G_LoadGameData(clientGamedata);
if (gamestate == GS_TITLESCREEN) if (gamestate == GS_TITLESCREEN)
{ {

View file

@ -40,9 +40,9 @@ extern boolean gamedataadded;
extern boolean titlechanged; extern boolean titlechanged;
extern boolean introchanged; extern boolean introchanged;
#define MAXRECURSION 30 #define MAX_ACTION_RECURSION 30
extern const char *superactions[MAXRECURSION]; extern const char *luaactions[MAX_ACTION_RECURSION];
extern UINT8 superstack; extern UINT8 luaactionstack;
// If the dehacked patch does not match this version, we throw a warning // If the dehacked patch does not match this version, we throw a warning
#define PATCHVERSION 220 #define PATCHVERSION 220

View file

@ -62,6 +62,10 @@ enum
#define MTF_AMBUSH 8 #define MTF_AMBUSH 8
// Do not use bit five or after, as they are used for object z-offsets. // 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) #if defined(_MSC_VER)
#pragma pack(1) #pragma pack(1)
@ -211,6 +215,7 @@ typedef struct
UINT8 extrainfo; UINT8 extrainfo;
taglist_t tags; taglist_t tags;
fixed_t scale; fixed_t scale;
fixed_t spritexscale, spriteyscale;
INT32 args[NUMMAPTHINGARGS]; INT32 args[NUMMAPTHINGARGS];
char *stringargs[NUMMAPTHINGSTRINGARGS]; char *stringargs[NUMMAPTHINGSTRINGARGS];
struct mobj_s *mobj; struct mobj_s *mobj;

View file

@ -104,8 +104,18 @@
#include <io.h> #include <io.h>
#endif #endif
FILE *fopenfile(const char*, const char*);
//#define NOMD5 //#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 // Uncheck this to compile debugging code
//#define RANGECHECK //#define RANGECHECK
//#ifndef PARANOIA //#ifndef PARANOIA
@ -150,7 +160,7 @@ extern char logfilename[1024];
// Does this version require an added patch file? // Does this version require an added patch file?
// Comment or uncomment this as necessary. // Comment or uncomment this as necessary.
// #define USE_PATCH_DTA #define USE_PATCH_DTA
// Enforce a limit of loaded WAD files. // Enforce a limit of loaded WAD files.
//#define ENFORCE_WAD_LIMIT //#define ENFORCE_WAD_LIMIT
@ -259,66 +269,111 @@ typedef enum
// Desaturated // Desaturated
SKINCOLOR_AETHER, SKINCOLOR_AETHER,
SKINCOLOR_SLATE, SKINCOLOR_SLATE,
SKINCOLOR_MOONSTONE,
SKINCOLOR_BLUEBELL, SKINCOLOR_BLUEBELL,
SKINCOLOR_PINK, SKINCOLOR_PINK,
SKINCOLOR_ROSEWOOD,
SKINCOLOR_YOGURT, SKINCOLOR_YOGURT,
SKINCOLOR_LATTE,
SKINCOLOR_BROWN, SKINCOLOR_BROWN,
SKINCOLOR_BOULDER,
SKINCOLOR_BRONZE, SKINCOLOR_BRONZE,
SKINCOLOR_SEPIA,
SKINCOLOR_ECRU,
SKINCOLOR_TAN, SKINCOLOR_TAN,
SKINCOLOR_BEIGE, SKINCOLOR_BEIGE,
SKINCOLOR_ROSEBUSH,
SKINCOLOR_MOSS, SKINCOLOR_MOSS,
SKINCOLOR_AZURE, SKINCOLOR_AZURE,
SKINCOLOR_EGGPLANT,
SKINCOLOR_LAVENDER, SKINCOLOR_LAVENDER,
// Viv's vivid colours (toast 21/07/17) // Viv's vivid colours (toast 21/07/17)
// Tweaks & additions (Lach, sphere, Alice, MotorRoach 26/10/22)
SKINCOLOR_RUBY, SKINCOLOR_RUBY,
SKINCOLOR_CHERRY,
SKINCOLOR_SALMON, SKINCOLOR_SALMON,
SKINCOLOR_PEPPER,
SKINCOLOR_RED, SKINCOLOR_RED,
SKINCOLOR_CRIMSON, SKINCOLOR_CRIMSON,
SKINCOLOR_FLAME, SKINCOLOR_FLAME,
SKINCOLOR_GARNET,
SKINCOLOR_KETCHUP, SKINCOLOR_KETCHUP,
SKINCOLOR_PEACHY, SKINCOLOR_PEACHY,
SKINCOLOR_QUAIL, SKINCOLOR_QUAIL,
SKINCOLOR_FOUNDATION,
SKINCOLOR_SUNSET, SKINCOLOR_SUNSET,
SKINCOLOR_COPPER, SKINCOLOR_COPPER,
SKINCOLOR_APRICOT, SKINCOLOR_APRICOT,
SKINCOLOR_ORANGE, SKINCOLOR_ORANGE,
SKINCOLOR_RUST, SKINCOLOR_RUST,
SKINCOLOR_TANGERINE,
SKINCOLOR_TOPAZ,
SKINCOLOR_GOLD, SKINCOLOR_GOLD,
SKINCOLOR_SANDY, SKINCOLOR_SANDY,
SKINCOLOR_GOLDENROD,
SKINCOLOR_YELLOW, SKINCOLOR_YELLOW,
SKINCOLOR_OLIVE, SKINCOLOR_OLIVE,
SKINCOLOR_PEAR,
SKINCOLOR_LEMON,
SKINCOLOR_LIME, SKINCOLOR_LIME,
SKINCOLOR_PERIDOT, SKINCOLOR_PERIDOT,
SKINCOLOR_APPLE, SKINCOLOR_APPLE,
SKINCOLOR_HEADLIGHT,
SKINCOLOR_CHARTREUSE,
SKINCOLOR_GREEN, SKINCOLOR_GREEN,
SKINCOLOR_FOREST, SKINCOLOR_FOREST,
SKINCOLOR_EMERALD, SKINCOLOR_SHAMROCK,
SKINCOLOR_JADE,
SKINCOLOR_MINT, SKINCOLOR_MINT,
SKINCOLOR_MASTER,
SKINCOLOR_EMERALD,
SKINCOLOR_SEAFOAM, SKINCOLOR_SEAFOAM,
SKINCOLOR_ISLAND,
SKINCOLOR_BOTTLE,
SKINCOLOR_AQUA, SKINCOLOR_AQUA,
SKINCOLOR_TEAL, SKINCOLOR_TEAL,
SKINCOLOR_OCEAN,
SKINCOLOR_WAVE, SKINCOLOR_WAVE,
SKINCOLOR_CYAN, SKINCOLOR_CYAN,
SKINCOLOR_TURQUOISE,
SKINCOLOR_AQUAMARINE,
SKINCOLOR_SKY, SKINCOLOR_SKY,
SKINCOLOR_MARINE,
SKINCOLOR_CERULEAN, SKINCOLOR_CERULEAN,
SKINCOLOR_DREAM,
SKINCOLOR_ICY, SKINCOLOR_ICY,
SKINCOLOR_DAYBREAK,
SKINCOLOR_SAPPHIRE, // sweet mother, i cannot weave slender aphrodite has overcome me with longing for a girl SKINCOLOR_SAPPHIRE, // sweet mother, i cannot weave slender aphrodite has overcome me with longing for a girl
SKINCOLOR_ARCTIC,
SKINCOLOR_CORNFLOWER, SKINCOLOR_CORNFLOWER,
SKINCOLOR_BLUE, SKINCOLOR_BLUE,
SKINCOLOR_COBALT, SKINCOLOR_COBALT,
SKINCOLOR_MIDNIGHT,
SKINCOLOR_GALAXY,
SKINCOLOR_VAPOR, SKINCOLOR_VAPOR,
SKINCOLOR_DUSK, SKINCOLOR_DUSK,
SKINCOLOR_MAJESTY,
SKINCOLOR_PASTEL, SKINCOLOR_PASTEL,
SKINCOLOR_PURPLE, SKINCOLOR_PURPLE,
SKINCOLOR_NOBLE,
SKINCOLOR_FUCHSIA,
SKINCOLOR_BUBBLEGUM, SKINCOLOR_BUBBLEGUM,
SKINCOLOR_SIBERITE,
SKINCOLOR_MAGENTA, SKINCOLOR_MAGENTA,
SKINCOLOR_NEON, SKINCOLOR_NEON,
SKINCOLOR_VIOLET, SKINCOLOR_VIOLET,
SKINCOLOR_ROYAL,
SKINCOLOR_LILAC, SKINCOLOR_LILAC,
SKINCOLOR_MAUVE,
SKINCOLOR_EVENTIDE,
SKINCOLOR_PLUM, SKINCOLOR_PLUM,
SKINCOLOR_RASPBERRY, SKINCOLOR_RASPBERRY,
SKINCOLOR_TAFFY,
SKINCOLOR_ROSY, SKINCOLOR_ROSY,
SKINCOLOR_FANCY,
SKINCOLOR_SANGRIA,
SKINCOLOR_VOLCANIC,
FIRSTSUPERCOLOR, FIRSTSUPERCOLOR,
@ -590,7 +645,16 @@ UINT32 quickncasehash (const char *p, size_t n)
#define PUNCTUATION "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~" #define PUNCTUATION "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~"
// Compile date and time and revision. // 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 // Disabled code and code under testing
// None of these that are disabled in the normal build are guaranteed to work perfectly // None of these that are disabled in the normal build are guaranteed to work perfectly

View file

@ -75,6 +75,7 @@ extern SINT8 startinglivesbalance[maxgameovers+1];
extern boolean modifiedgame; extern boolean modifiedgame;
extern UINT16 mainwads; extern UINT16 mainwads;
extern boolean savemoddata; // This mod saves time/emblem data. extern boolean savemoddata; // This mod saves time/emblem data.
extern boolean usedCheats;
extern boolean disableSpeedAdjust; // Don't alter the duration of player states if true extern boolean disableSpeedAdjust; // Don't alter the duration of player states if true
extern boolean imcontinuing; // Temporary flag while continuing extern boolean imcontinuing; // Temporary flag while continuing
extern boolean metalrecording; extern boolean metalrecording;
@ -131,8 +132,6 @@ extern INT32 postimgparam2;
extern INT32 viewwindowx, viewwindowy; extern INT32 viewwindowx, viewwindowy;
extern INT32 viewwidth, scaledviewwidth; extern INT32 viewwidth, scaledviewwidth;
extern boolean gamedataloaded;
// Player taking events, and displaying. // Player taking events, and displaying.
extern INT32 consoleplayer; extern INT32 consoleplayer;
extern INT32 displayplayer; extern INT32 displayplayer;
@ -250,6 +249,7 @@ extern textprompt_t *textprompts[MAX_PROMPTS];
// For the Custom Exit linedef. // For the Custom Exit linedef.
extern INT16 nextmapoverride; extern INT16 nextmapoverride;
extern UINT8 skipstats; extern UINT8 skipstats;
extern INT16 nextgametype;
extern UINT32 ssspheres; // Total # of spheres in a level extern UINT32 ssspheres; // Total # of spheres in a level
@ -494,8 +494,6 @@ typedef struct
extern tolinfo_t TYPEOFLEVEL[NUMTOLNAMES]; extern tolinfo_t TYPEOFLEVEL[NUMTOLNAMES];
extern UINT32 lastcustomtol; extern UINT32 lastcustomtol;
extern tic_t totalplaytime;
extern boolean stagefailed; extern boolean stagefailed;
// Emeralds stored as bits to throw savegame hackers off. // Emeralds stored as bits to throw savegame hackers off.
@ -514,52 +512,6 @@ extern INT32 luabanks[NUM_LUABANKS];
extern INT32 nummaprings; //keep track of spawned rings/coins extern INT32 nummaprings; //keep track of spawned rings/coins
/** Time attack information, currently a very small structure.
*/
typedef struct
{
tic_t time; ///< Time in which the level was finished.
UINT32 score; ///< Score when the level was finished.
UINT16 rings; ///< Rings when the level was finished.
} recorddata_t;
/** Setup for one NiGHTS map.
* These are dynamically allocated because I am insane
*/
#define GRADE_F 0
#define GRADE_E 1
#define GRADE_D 2
#define GRADE_C 3
#define GRADE_B 4
#define GRADE_A 5
#define GRADE_S 6
typedef struct
{
// 8 mares, 1 overall (0)
UINT8 nummares;
UINT32 score[9];
UINT8 grade[9];
tic_t time[9];
} nightsdata_t;
extern nightsdata_t *nightsrecords[NUMMAPS];
extern recorddata_t *mainrecords[NUMMAPS];
// mapvisited is now a set of flags that says what we've done in the map.
#define MV_VISITED 1
#define MV_BEATEN 2
#define MV_ALLEMERALDS 4
#define MV_ULTIMATE 8
#define MV_PERFECT 16
#define MV_PERFECTRA 32
#define MV_MAX 63 // used in gamedata check, update whenever MV's are added
#define MV_MP 128
extern UINT8 mapvisited[NUMMAPS];
// Temporary holding place for nights data for the current map
extern nightsdata_t ntemprecords;
extern UINT32 token; ///< Number of tokens collected in a level extern UINT32 token; ///< Number of tokens collected in a level
extern UINT32 tokenlist; ///< List of tokens collected extern UINT32 tokenlist; ///< List of tokens collected
extern boolean gottoken; ///< Did you get a token? Used for end of act extern boolean gottoken; ///< Did you get a token? Used for end of act
@ -592,9 +544,12 @@ extern UINT8 useBlackRock;
extern UINT8 use1upSound; extern UINT8 use1upSound;
extern UINT8 maxXtraLife; // Max extra lives from rings extern UINT8 maxXtraLife; // Max extra lives from rings
extern UINT8 useContinues; extern UINT8 useContinues;
#define continuesInSession (!multiplayer && (ultimatemode || (useContinues && !marathonmode) || (!modeattacking && !(cursaveslot > 0)))) #define continuesInSession (!multiplayer && (ultimatemode || (useContinues && !marathonmode) || (!modeattacking && !(cursaveslot > 0))))
extern UINT8 shareEmblems;
extern mobj_t *hunt1, *hunt2, *hunt3; // Emerald hunt locations extern mobj_t *hunt1, *hunt2, *hunt3; // Emerald hunt locations
// For racing // For racing
@ -615,10 +570,6 @@ extern INT32 cheats;
extern tic_t hidetime; extern tic_t hidetime;
extern UINT32 timesBeaten; // # of times the game has been beaten.
extern UINT32 timesBeatenWithEmeralds;
extern UINT32 timesBeatenUltimate;
// =========================== // ===========================
// Internal parameters, fixed. // Internal parameters, fixed.
// =========================== // ===========================

View file

@ -17,6 +17,10 @@
#ifndef __DOOMTYPE__ #ifndef __DOOMTYPE__
#define __DOOMTYPE__ #define __DOOMTYPE__
#ifdef __cplusplus
extern "C" {
#endif
#ifdef _WIN32 #ifdef _WIN32
//#define WIN32_LEAN_AND_MEAN //#define WIN32_LEAN_AND_MEAN
#define RPC_NO_WINDOWS_H #define RPC_NO_WINDOWS_H
@ -78,7 +82,9 @@ typedef long ssize_t;
#endif #endif
#define strncasecmp strnicmp #define strncasecmp strnicmp
#define strcasecmp stricmp #define strcasecmp stricmp
#ifndef __cplusplus
#define inline __inline #define inline __inline
#endif
#elif defined (__WATCOMC__) #elif defined (__WATCOMC__)
#include <dos.h> #include <dos.h>
#include <sys\types.h> #include <sys\types.h>
@ -94,31 +100,28 @@ typedef long ssize_t;
#define strnicmp(x,y,n) strncasecmp(x,y,n) #define strnicmp(x,y,n) strncasecmp(x,y,n)
#endif #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 #define stristr strcasestr
#if defined (macintosh) //|| defined (__APPLE__) //skip all boolean/Boolean crap int startswith (const char *base, const char *tag);
#define true 1 int endswith (const char *base, const char *tag);
#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
#endif
#define boolean INT32
#ifndef O_BINARY
#define O_BINARY 0
#endif
#endif //macintosh
#if defined (_WIN32) || defined (__HAIKU__) #if defined (_WIN32) || defined (__HAIKU__)
#define HAVE_DOSSTR_FUNCS #define HAVE_DOSSTR_FUNCS
#endif #endif
#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
#ifndef HAVE_DOSSTR_FUNCS #ifndef HAVE_DOSSTR_FUNCS
int strupr(char *n); // from dosstr.c int strupr(char *n); // from dosstr.c
int strlwr(char *n); // from dosstr.c int strlwr(char *n); // from dosstr.c
@ -126,7 +129,7 @@ int strlwr(char *n); // from dosstr.c
#include <stddef.h> // for size_t #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 strlcat(char *dst, const char *src, size_t siz);
size_t strlcpy(char *dst, const char *src, size_t siz); size_t strlcpy(char *dst, const char *src, size_t siz);
#endif #endif
@ -141,22 +144,24 @@ size_t strlcpy(char *dst, const char *src, size_t siz);
/* Boolean type definition */ /* Boolean type definition */
// \note __BYTEBOOL__ used to be set above if "macintosh" was defined, // Note: C++ bool and C99/C11 _Bool are NOT compatible.
// if macintosh's version of boolean type isn't needed anymore, then isn't this macro pointless now? // Historically, boolean was win32 BOOL on Windows. For equivalence, it's now
#ifndef __BYTEBOOL__ // int32_t. "true" and "false" are only declared for C code; in C++, conversion
#define __BYTEBOOL__ // between "bool" and "int32_t" takes over.
#ifndef _WIN32
typedef int32_t boolean;
#else
#define boolean BOOL
#endif
//faB: clean that up !! #ifndef __cplusplus
#if defined( _MSC_VER) && (_MSC_VER >= 1800) // MSVC 2013 and forward #ifndef _WIN32
#include "stdbool.h" enum {false = 0, true = 1};
#elif defined (_WIN32) #else
#define false FALSE // use windows types #define false FALSE
#define true TRUE #define true TRUE
#define boolean BOOL #endif
#else #endif
typedef enum {false, true} boolean;
#endif
#endif // __BYTEBOOL__
/* 7.18.2.1 Limits of exact-width integer types */ /* 7.18.2.1 Limits of exact-width integer types */
@ -384,4 +389,8 @@ unset_bit_array (bitarray_t * const array, const int value)
typedef UINT64 precise_t; typedef UINT64 precise_t;
#ifdef __cplusplus
} // extern "C"
#endif
#endif //__DOOMTYPE__ #endif //__DOOMTYPE__

View file

@ -8,19 +8,24 @@ UINT8 graphics_started = 0;
UINT8 keyboard_started = 0; UINT8 keyboard_started = 0;
UINT32 I_GetFreeMem(UINT32 *total) size_t I_GetFreeMem(size_t *total)
{ {
*total = 0; *total = 0;
return 0; 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; return 0;
} }
UINT64 I_GetPrecisePrecision(void) { UINT64 I_GetPrecisePrecision(void)
{
return 1000000; return 1000000;
} }
@ -180,7 +185,14 @@ const char *I_ClipboardPaste(void)
return NULL; 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) void I_GetCursorPosition(INT32 *x, INT32 *y)
{ {

View file

@ -57,6 +57,8 @@ const char *VID_GetModeName(INT32 modenum)
return NULL; return NULL;
} }
UINT32 I_GetRefreshRate(void) { return 35; }
void I_UpdateNoBlit(void){} void I_UpdateNoBlit(void){}
void I_FinishUpdate(void){} void I_FinishUpdate(void){}

View file

@ -63,7 +63,6 @@ static tic_t stoptimer;
static boolean keypressed = false; static boolean keypressed = false;
// (no longer) De-Demo'd Title Screen // (no longer) De-Demo'd Title Screen
static INT32 menuanimtimer; // Title screen: background animation timing
mobj_t *titlemapcameraref = NULL; mobj_t *titlemapcameraref = NULL;
// menu presentation state // menu presentation state
@ -75,6 +74,8 @@ INT32 curbgyspeed;
boolean curbghide; boolean curbghide;
boolean hidetitlemap; // WARNING: set to false by M_SetupNextMenu and M_ClearMenus boolean hidetitlemap; // WARNING: set to false by M_SetupNextMenu and M_ClearMenus
static fixed_t curbgx = 0;
static fixed_t curbgy = 0;
static UINT8 curDemo = 0; static UINT8 curDemo = 0;
static UINT32 demoDelayLeft; static UINT32 demoDelayLeft;
static UINT32 demoIdleLeft; static UINT32 demoIdleLeft;
@ -223,7 +224,6 @@ static INT32 cutscene_writeptr = 0;
static INT32 cutscene_textcount = 0; static INT32 cutscene_textcount = 0;
static INT32 cutscene_textspeed = 0; static INT32 cutscene_textspeed = 0;
static UINT8 cutscene_boostspeed = 0; static UINT8 cutscene_boostspeed = 0;
static tic_t cutscene_lasttextwrite = 0;
// STJR Intro // STJR Intro
char stjrintro[9] = "STJRI000"; char stjrintro[9] = "STJRI000";
@ -239,11 +239,6 @@ static UINT8 F_WriteText(void)
{ {
INT32 numtowrite = 1; INT32 numtowrite = 1;
const char *c; const char *c;
tic_t ltw = I_GetTime();
if (cutscene_lasttextwrite == ltw)
return 1; // singletics prevention
cutscene_lasttextwrite = ltw;
if (cutscene_boostspeed) if (cutscene_boostspeed)
{ {
@ -337,7 +332,7 @@ static tic_t introscenetime[NUMINTROSCENES] =
}; };
// custom intros // custom intros
void F_StartCustomCutscene(INT32 cutscenenum, boolean precutscene, boolean resetplayer); void F_StartCustomCutscene(INT32 cutscenenum, boolean precutscene, boolean resetplayer, boolean FLS);
void F_StartIntro(void) void F_StartIntro(void)
{ {
@ -349,7 +344,7 @@ void F_StartIntro(void)
if (!cutscenes[introtoplay - 1]) if (!cutscenes[introtoplay - 1])
D_StartTitle(); D_StartTitle();
else else
F_StartCustomCutscene(introtoplay - 1, false, false); F_StartCustomCutscene(introtoplay - 1, false, false, false);
return; return;
} }
@ -1067,12 +1062,14 @@ static const char *credits[] = {
"\"Golden\"", "\"Golden\"",
"Vivian \"toaster\" Grannell", "Vivian \"toaster\" Grannell",
"Julio \"Chaos Zero 64\" Guir", "Julio \"Chaos Zero 64\" Guir",
"\"Hanicef\"",
"\"Hannu_Hanhi\"", // For many OpenGL performance improvements! "\"Hannu_Hanhi\"", // For many OpenGL performance improvements!
"Kepa \"Nev3r\" Iceta", "Kepa \"Nev3r\" Iceta",
"Thomas \"Shadow Hog\" Igoe", "Thomas \"Shadow Hog\" Igoe",
"Iestyn \"Monster Iestyn\" Jealous", "Iestyn \"Monster Iestyn\" Jealous",
"\"Kaito Sinclaire\"", "\"Kaito Sinclaire\"",
"\"Kalaron\"", // Coded some of Sryder13's collection of OpenGL fixes, especially fog "\"Kalaron\"", // Coded some of Sryder13's collection of OpenGL fixes, especially fog
"\"katsy\"",
"Ronald \"Furyhunter\" Kinard", // The SDL2 port "Ronald \"Furyhunter\" Kinard", // The SDL2 port
"\"Lat'\"", // SRB2-CHAT, the chat window from Kart "\"Lat'\"", // SRB2-CHAT, the chat window from Kart
"\"LZA\"", "\"LZA\"",
@ -1095,6 +1092,7 @@ static const char *credits[] = {
"Ben \"Cue\" Woodford", "Ben \"Cue\" Woodford",
"Lachlan \"Lach\" Wright", "Lachlan \"Lach\" Wright",
"Marco \"mazmazz\" Zafra", "Marco \"mazmazz\" Zafra",
"\"Zwip-Zwap Zapony\"",
"", "",
"\1Art", "\1Art",
"Victor \"VAdaPEGA\" Ara\x1Fjo", // Araújo -- sorry for our limited font! D: "Victor \"VAdaPEGA\" Ara\x1Fjo", // Araújo -- sorry for our limited font! D:
@ -1202,6 +1200,7 @@ static const char *credits[] = {
"FreeDoom Project", // Used some of the mancubus and rocket launcher sprites for Brak "FreeDoom Project", // Used some of the mancubus and rocket launcher sprites for Brak
"Kart Krew", "Kart Krew",
"Alex \"MistaED\" Fuller", "Alex \"MistaED\" Fuller",
"Howard Drossin", // Virtual Sonic - Sonic & Knuckles Theme
"Pascal \"CodeImp\" vd Heiden", // Doom Builder developer "Pascal \"CodeImp\" vd Heiden", // Doom Builder developer
"Randi Heit (<!>)", // For their MSPaint <!> sprite that we nicked "Randi Heit (<!>)", // For their MSPaint <!> sprite that we nicked
"Simon \"sirjuddington\" Judd", // SLADE developer "Simon \"sirjuddington\" Judd", // SLADE developer
@ -1257,7 +1256,7 @@ void F_StartCredits(void)
if (creditscutscene) if (creditscutscene)
{ {
F_StartCustomCutscene(creditscutscene - 1, false, false); F_StartCustomCutscene(creditscutscene - 1, false, false, false);
return; return;
} }
@ -1279,14 +1278,23 @@ void F_CreditDrawer(void)
UINT16 i; UINT16 i;
INT16 zagpos = (timetonext - finalecount - animtimer) % 32; INT16 zagpos = (timetonext - finalecount - animtimer) % 32;
fixed_t y = (80<<FRACBITS) - (animtimer<<FRACBITS>>1); 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); V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 31);
// Zig Zagz // Zig Zagz
V_DrawScaledPatch(-16, zagpos, V_SNAPTOLEFT, W_CachePatchName("LTZIGZAG", PU_PATCH_LOWPRIORITY)); V_DrawFixedPatch(-16*FRACUNIT, zagpos<<FRACBITS, FRACUNIT, V_SNAPTOLEFT, W_CachePatchName("LTZIGZAG", PU_PATCH_LOWPRIORITY), colormap);
V_DrawScaledPatch(-16, zagpos - 320, V_SNAPTOLEFT, W_CachePatchName("LTZIGZAG", PU_PATCH_LOWPRIORITY)); V_DrawFixedPatch(-16*FRACUNIT, (zagpos - 320)<<FRACBITS, FRACUNIT, V_SNAPTOLEFT, W_CachePatchName("LTZIGZAG", PU_PATCH_LOWPRIORITY), colormap);
V_DrawScaledPatch(BASEVIDWIDTH + 16, zagpos, V_SNAPTORIGHT|V_FLIP, W_CachePatchName("LTZIGZAG", PU_PATCH_LOWPRIORITY)); V_DrawFixedPatch((BASEVIDWIDTH + 16)*FRACUNIT, zagpos<<FRACBITS, FRACUNIT, V_SNAPTORIGHT|V_FLIP, W_CachePatchName("LTZIGZAG", PU_PATCH_LOWPRIORITY), colormap);
V_DrawScaledPatch(BASEVIDWIDTH + 16, zagpos - 320, V_SNAPTORIGHT|V_FLIP, W_CachePatchName("LTZIGZAG", PU_PATCH_LOWPRIORITY)); V_DrawFixedPatch((BASEVIDWIDTH + 16)*FRACUNIT, (zagpos - 320)<<FRACBITS, FRACUNIT, V_SNAPTORIGHT|V_FLIP, W_CachePatchName("LTZIGZAG", PU_PATCH_LOWPRIORITY), colormap);
// Draw background pictures first // Draw background pictures first
for (i = 0; credits_pics[i].patch; i++) for (i = 0; credits_pics[i].patch; i++)
@ -1411,7 +1419,7 @@ boolean F_CreditResponder(event_t *event)
break; break;
} }
if (!(timesBeaten) && !(netgame || multiplayer) && !cv_debug) if (!(serverGamedata->timesBeaten) && !(netgame || multiplayer) && !cv_debug)
return false; return false;
if (event->type != ev_keydown) if (event->type != ev_keydown)
@ -1573,27 +1581,19 @@ void F_GameEvaluationDrawer(void)
#if 0 // the following looks like hot garbage the more unlockables we add, and we now have a lot of unlockables #if 0 // the following looks like hot garbage the more unlockables we add, and we now have a lot of unlockables
if (finalecount >= 5*TICRATE) if (finalecount >= 5*TICRATE)
{ {
INT32 startcoord = 32;
V_DrawString(8, 16, V_YELLOWMAP, "Unlocked:"); V_DrawString(8, 16, V_YELLOWMAP, "Unlocked:");
if (!(netgame) && (!modifiedgame || savemoddata)) for (i = 0; i < MAXUNLOCKABLES; i++)
{ {
INT32 startcoord = 32; if (unlockables[i].conditionset && unlockables[i].conditionset < MAXCONDITIONSETS
&& unlockables[i].type && !unlockables[i].nocecho)
for (i = 0; i < MAXUNLOCKABLES; i++)
{ {
if (unlockables[i].conditionset && unlockables[i].conditionset < MAXCONDITIONSETS if (clientGamedata->unlocked[i])
&& unlockables[i].type && !unlockables[i].nocecho) V_DrawString(8, startcoord, 0, unlockables[i].name);
{ startcoord += 8;
if (unlockables[i].unlocked)
V_DrawString(8, startcoord, 0, unlockables[i].name);
startcoord += 8;
}
} }
} }
else if (netgame)
V_DrawString(8, 96, V_YELLOWMAP, "Multiplayer games\ncan't unlock\nextras!");
else
V_DrawString(8, 96, V_YELLOWMAP, "Modified games\ncan't unlock\nextras!");
} }
#endif #endif
@ -1648,37 +1648,29 @@ void F_GameEvaluationTicker(void)
sparklloop = 0; sparklloop = 0;
} }
if (finalecount == 5*TICRATE) if (G_CoopGametype() && !stagefailed && finalecount == 5*TICRATE)
{ {
if (netgame || multiplayer) // modify this when we finally allow unlocking stuff in 2P serverGamedata->timesBeaten++;
clientGamedata->timesBeaten++;
if (ALL7EMERALDS(emeralds))
{ {
HU_SetCEchoFlags(V_YELLOWMAP|V_RETURN8); serverGamedata->timesBeatenWithEmeralds++;
HU_SetCEchoDuration(6); clientGamedata->timesBeatenWithEmeralds++;
HU_DoCEcho("\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\Multiplayer games can't unlock extras!"); }
if (ultimatemode)
{
serverGamedata->timesBeatenUltimate++;
clientGamedata->timesBeatenUltimate++;
}
M_SilentUpdateUnlockablesAndEmblems(serverGamedata);
if (M_UpdateUnlockablesAndExtraEmblems(clientGamedata))
S_StartSound(NULL, sfx_s3k68); S_StartSound(NULL, sfx_s3k68);
}
else if (!modifiedgame || savemoddata)
{
++timesBeaten;
if (ALL7EMERALDS(emeralds)) G_SaveGameData(clientGamedata);
++timesBeatenWithEmeralds;
if (ultimatemode)
++timesBeatenUltimate;
if (M_UpdateUnlockablesAndExtraEmblems())
S_StartSound(NULL, sfx_s3k68);
G_SaveGameData();
}
else
{
HU_SetCEchoFlags(V_YELLOWMAP|V_RETURN8);
HU_SetCEchoDuration(6);
HU_DoCEcho("\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\Modified games can't unlock extras!");
S_StartSound(NULL, sfx_s3k68);
}
} }
} }
@ -2192,7 +2184,7 @@ void F_EndingDrawer(void)
//colset(linkmap, 164, 165, 169); -- the ideal purple colour to represent a clicked in-game link, but not worth it just for a soundtest-controlled secret //colset(linkmap, 164, 165, 169); -- the ideal purple colour to represent a clicked in-game link, but not worth it just for a soundtest-controlled secret
V_DrawCenteredString(BASEVIDWIDTH/2, 8, V_ALLOWLOWERCASE|(trans<<V_ALPHASHIFT), str); V_DrawCenteredString(BASEVIDWIDTH/2, 8, V_ALLOWLOWERCASE|(trans<<V_ALPHASHIFT), str);
V_DrawCharacter(32, BASEVIDHEIGHT-16, '>'|(trans<<V_ALPHASHIFT), false); V_DrawCharacter(32, BASEVIDHEIGHT-16, '>'|(trans<<V_ALPHASHIFT), false);
V_DrawString(40, ((finalecount == STOPPINGPOINT-(20+TICRATE)) ? 1 : 0)+BASEVIDHEIGHT-16, ((timesBeaten || finalecount >= STOPPINGPOINT-TICRATE) ? V_PURPLEMAP : V_BLUEMAP)|(trans<<V_ALPHASHIFT), " [S] ===>"); V_DrawString(40, ((finalecount == STOPPINGPOINT-(20+TICRATE)) ? 1 : 0)+BASEVIDHEIGHT-16, ((serverGamedata->timesBeaten || finalecount >= STOPPINGPOINT-TICRATE) ? V_PURPLEMAP : V_BLUEMAP)|(trans<<V_ALPHASHIFT), " [S] ===>");
} }
if (finalecount > STOPPINGPOINT-(20+(2*TICRATE))) if (finalecount > STOPPINGPOINT-(20+(2*TICRATE)))
@ -2258,7 +2250,8 @@ void F_GameEndTicker(void)
void F_InitMenuPresValues(void) void F_InitMenuPresValues(void)
{ {
menuanimtimer = 0; curbgx = 0;
curbgy = 0;
prevMenuId = 0; prevMenuId = 0;
activeMenuId = MainDef.menuid; activeMenuId = MainDef.menuid;
@ -2267,7 +2260,7 @@ void F_InitMenuPresValues(void)
curfadevalue = 16; curfadevalue = 16;
curbgcolor = -1; curbgcolor = -1;
curbgxspeed = (gamestate == GS_TIMEATTACK) ? 0 : titlescrollxspeed; curbgxspeed = (gamestate == GS_TIMEATTACK) ? 0 : titlescrollxspeed;
curbgyspeed = (gamestate == GS_TIMEATTACK) ? 22 : titlescrollyspeed; curbgyspeed = (gamestate == GS_TIMEATTACK) ? 18 : titlescrollyspeed;
curbghide = (gamestate == GS_TIMEATTACK) ? false : true; curbghide = (gamestate == GS_TIMEATTACK) ? false : true;
curhidepics = hidetitlepics; curhidepics = hidetitlepics;
@ -2291,17 +2284,11 @@ void F_InitMenuPresValues(void)
// //
// F_SkyScroll // F_SkyScroll
// //
void F_SkyScroll(INT32 scrollxspeed, INT32 scrollyspeed, const char *patchname) void F_SkyScroll(const char *patchname)
{ {
INT32 xscrolled, x, xneg = (scrollxspeed > 0) - (scrollxspeed < 0), tilex; INT32 x, basey = 0;
INT32 yscrolled, y, yneg = (scrollyspeed > 0) - (scrollyspeed < 0), tiley;
boolean xispos = (scrollxspeed >= 0), yispos = (scrollyspeed >= 0);
INT32 dupz = (vid.dupx < vid.dupy ? vid.dupx : vid.dupy); INT32 dupz = (vid.dupx < vid.dupy ? vid.dupx : vid.dupy);
INT16 patwidth, patheight;
INT32 pw, ph; // scaled by dupz
patch_t *pat; patch_t *pat;
INT32 i, j;
fixed_t fracmenuanimtimer, xscrolltimer, yscrolltimer;
if (rendermode == render_none) if (rendermode == render_none)
return; return;
@ -2312,43 +2299,34 @@ void F_SkyScroll(INT32 scrollxspeed, INT32 scrollyspeed, const char *patchname)
return; return;
} }
if (!scrollxspeed && !scrollyspeed) pat = W_CachePatchName(patchname, PU_PATCH_LOWPRIORITY);
if (!curbgxspeed && !curbgyspeed)
{ {
V_DrawPatchFill(W_CachePatchName(patchname, PU_PATCH_LOWPRIORITY)); V_DrawPatchFill(pat);
W_UnlockCachedPatch(pat);
return; return;
} }
pat = W_CachePatchName(patchname, PU_PATCH_LOWPRIORITY); // Modulo the background scrolling to prevent jumps from integer overflows
// We already load the background patch here, so we can modulo it here
// to avoid also having to load the patch in F_MenuPresTicker
curbgx %= pat->width * 16;
curbgy %= pat->height * 16;
patwidth = pat->width; // Ooh, fancy frame interpolation
patheight = pat->height; x = ((curbgx*dupz) + FixedInt((rendertimefrac-FRACUNIT) * curbgxspeed*dupz)) / 16;
pw = patwidth * dupz; basey = ((curbgy*dupz) + FixedInt((rendertimefrac-FRACUNIT) * curbgyspeed*dupz)) / 16;
ph = patheight * dupz;
tilex = max(FixedCeil(FixedDiv(vid.width, pw)) >> FRACBITS, 1)+2; // one tile on both sides of center if (x > 0) // Make sure that we don't leave the left or top sides empty
tiley = max(FixedCeil(FixedDiv(vid.height, ph)) >> FRACBITS, 1)+2; x -= pat->width * dupz;
if (basey > 0)
basey -= pat->height * dupz;
fracmenuanimtimer = (menuanimtimer * FRACUNIT) - (FRACUNIT - rendertimefrac); for (; x < vid.width; x += pat->width * dupz)
xscrolltimer = ((fracmenuanimtimer*scrollxspeed)/16 + patwidth*xneg*FRACUNIT) % (patwidth * FRACUNIT);
yscrolltimer = ((fracmenuanimtimer*scrollyspeed)/16 + patheight*yneg*FRACUNIT) % (patheight * FRACUNIT);
// coordinate offsets
xscrolled = FixedInt(xscrolltimer * dupz);
yscrolled = FixedInt(yscrolltimer * dupz);
for (x = (xispos) ? -pw*(tilex-1)+pw : 0, i = 0;
i < tilex;
x += pw, i++)
{ {
for (y = (yispos) ? -ph*(tiley-1)+ph : 0, j = 0; for (INT32 y = basey; y < vid.height; y += pat->height * dupz)
j < tiley; V_DrawScaledPatch(x, y, V_NOSCALESTART, pat);
y += ph, j++)
{
V_DrawScaledPatch(
(xispos) ? xscrolled - x : x + xscrolled,
(yispos) ? yscrolled - y : y + yscrolled,
V_NOSCALESTART, pat);
}
} }
W_UnlockCachedPatch(pat); W_UnlockCachedPatch(pat);
@ -2671,7 +2649,7 @@ void F_TitleScreenDrawer(void)
if (curbgcolor >= 0) if (curbgcolor >= 0)
V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, curbgcolor); V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, curbgcolor);
else if (!curbghide || !titlemapinaction || gamestate == GS_WAITINGPLAYERS) else if (!curbghide || !titlemapinaction || gamestate == GS_WAITINGPLAYERS)
F_SkyScroll(curbgxspeed, curbgyspeed, curbgname); F_SkyScroll(curbgname);
// Don't draw outside of the title screen, or if the patch isn't there. // Don't draw outside of the title screen, or if the patch isn't there.
if (gamestate != GS_TITLESCREEN && gamestate != GS_WAITINGPLAYERS) if (gamestate != GS_TITLESCREEN && gamestate != GS_WAITINGPLAYERS)
@ -3426,10 +3404,10 @@ luahook:
// separate animation timer for backgrounds, since we also count // separate animation timer for backgrounds, since we also count
// during GS_TIMEATTACK // during GS_TIMEATTACK
void F_MenuPresTicker(boolean run) void F_MenuPresTicker(void)
{ {
if (run) curbgx += curbgxspeed;
menuanimtimer++; curbgy += curbgyspeed;
} }
// (no longer) De-Demo'd Title Screen // (no longer) De-Demo'd Title Screen
@ -3535,6 +3513,7 @@ void F_TitleScreenTicker(boolean run)
} }
titledemo = true; titledemo = true;
demofileoverride = DFILE_OVERRIDE_NONE;
G_DoPlayDemo(dname); G_DoPlayDemo(dname);
} }
} }
@ -3859,7 +3838,7 @@ static INT32 scenenum, cutnum;
static INT32 picxpos, picypos, picnum, pictime, picmode, numpics, pictoloop; static INT32 picxpos, picypos, picnum, pictime, picmode, numpics, pictoloop;
static INT32 textxpos, textypos; static INT32 textxpos, textypos;
static boolean cutsceneover = false; static boolean cutsceneover = false;
static boolean runningprecutscene = false, precutresetplayer = false; static boolean runningprecutscene = false, precutresetplayer = false, precutFLS = false;
static void F_AdvanceToNextScene(void) static void F_AdvanceToNextScene(void)
{ {
@ -3928,7 +3907,7 @@ void F_EndCutScene(void)
if (runningprecutscene) if (runningprecutscene)
{ {
if (server) if (server)
D_MapChange(gamemap, gametype, ultimatemode, precutresetplayer, 0, true, false); D_MapChange(gamemap, gametype, ultimatemode, precutresetplayer, 0, true, precutFLS);
} }
else else
{ {
@ -3943,7 +3922,7 @@ void F_EndCutScene(void)
} }
} }
void F_StartCustomCutscene(INT32 cutscenenum, boolean precutscene, boolean resetplayer) void F_StartCustomCutscene(INT32 cutscenenum, boolean precutscene, boolean resetplayer, boolean FLS)
{ {
if (!cutscenes[cutscenenum]) if (!cutscenes[cutscenenum])
return; return;
@ -3962,6 +3941,7 @@ void F_StartCustomCutscene(INT32 cutscenenum, boolean precutscene, boolean reset
cutsceneover = false; cutsceneover = false;
runningprecutscene = precutscene; runningprecutscene = precutscene;
precutresetplayer = resetplayer; precutresetplayer = resetplayer;
precutFLS = FLS;
scenenum = picnum = 0; scenenum = picnum = 0;
cutnum = cutscenenum; cutnum = cutscenenum;
@ -4694,3 +4674,36 @@ void F_TextPromptTicker(void)
animtimer--; 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);
}

View file

@ -40,7 +40,7 @@ void F_TextPromptTicker(void);
void F_GameEndDrawer(void); void F_GameEndDrawer(void);
void F_IntroDrawer(void); void F_IntroDrawer(void);
void F_TitleScreenDrawer(void); void F_TitleScreenDrawer(void);
void F_SkyScroll(INT32 scrollxspeed, INT32 scrollyspeed, const char *patchname); void F_SkyScroll(const char *patchname);
void F_GameEvaluationDrawer(void); void F_GameEvaluationDrawer(void);
void F_StartGameEvaluation(void); void F_StartGameEvaluation(void);
@ -52,7 +52,7 @@ void F_EndingDrawer(void);
void F_CreditTicker(void); void F_CreditTicker(void);
void F_CreditDrawer(void); void F_CreditDrawer(void);
void F_StartCustomCutscene(INT32 cutscenenum, boolean precutscene, boolean resetplayer); void F_StartCustomCutscene(INT32 cutscenenum, boolean precutscene, boolean resetplayer, boolean FLS);
void F_CutsceneDrawer(void); void F_CutsceneDrawer(void);
void F_EndCutScene(void); void F_EndCutScene(void);
@ -74,6 +74,10 @@ void F_StartContinue(void);
void F_ContinueTicker(void); void F_ContinueTicker(void);
void F_ContinueDrawer(void); void F_ContinueDrawer(void);
void F_StartWaitingPlayers(void);
void F_WaitingPlayersTicker(void);
void F_WaitingPlayersDrawer(void);
extern INT32 finalecount; extern INT32 finalecount;
extern INT32 titlescrollxspeed; extern INT32 titlescrollxspeed;
extern INT32 titlescrollyspeed; extern INT32 titlescrollyspeed;
@ -131,7 +135,7 @@ extern UINT16 curtttics;
#define TITLEBACKGROUNDACTIVE (curfadevalue >= 0 || curbgname[0]) #define TITLEBACKGROUNDACTIVE (curfadevalue >= 0 || curbgname[0])
void F_InitMenuPresValues(void); void F_InitMenuPresValues(void);
void F_MenuPresTicker(boolean run); void F_MenuPresTicker(void);
// //
// WIPE // WIPE

View file

@ -614,6 +614,8 @@ void F_RunWipe(UINT8 wipetype, boolean drawMenu)
if (moviemode) if (moviemode)
M_SaveFrame(); M_SaveFrame();
NetKeepAlive(); // Update the network so we don't cause timeouts
} }
WipeInAction = false; WipeInAction = false;

View file

@ -39,6 +39,7 @@
#define SUFFIX "*" #define SUFFIX "*"
#define SLASH "\\" #define SLASH "\\"
#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) #define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
#ifndef INVALID_FILE_ATTRIBUTES #ifndef INVALID_FILE_ATTRIBUTES
@ -307,6 +308,39 @@ closedir (DIR * dirp)
} }
#endif #endif
// fopen but it REALLY only works on regular files
// Turns out, on linux, anyway, you can fopen directories
// in read mode. (It's supposed to fail in write mode
// though!!)
FILE *fopenfile(const char *path, const char *mode)
{
FILE *h = fopen(path, mode);
if (h != NULL)
{
struct stat st;
int eno;
if (fstat(fileno(h), &st) == -1)
{
eno = errno;
}
else if (!S_ISREG(st.st_mode))
{
eno = EACCES; // set some kinda error
}
else
{
return h; // ok
}
fclose(h);
errno = eno;
}
return NULL;
}
static CV_PossibleValue_t addons_cons_t[] = {{0, "Default"}, static CV_PossibleValue_t addons_cons_t[] = {{0, "Default"},
#if 1 #if 1
{1, "HOME"}, {2, "SRB2"}, {1, "HOME"}, {2, "SRB2"},

View file

@ -39,6 +39,7 @@
#include "v_video.h" #include "v_video.h"
#include "lua_hook.h" #include "lua_hook.h"
#include "md5.h" // demo checksums #include "md5.h" // demo checksums
#include "d_netfil.h" // G_CheckDemoExtraFiles
boolean timingdemo; // if true, exit with report on completion boolean timingdemo; // if true, exit with report on completion
boolean nodrawers; // for comparative timing purposes boolean nodrawers; // for comparative timing purposes
@ -49,6 +50,7 @@ static char demoname[64];
boolean demorecording; boolean demorecording;
boolean demoplayback; boolean demoplayback;
boolean titledemo; // Title Screen demo can be cancelled by any key boolean titledemo; // Title Screen demo can be cancelled by any key
demo_file_override_e demofileoverride;
static UINT8 *demobuffer = NULL; static UINT8 *demobuffer = NULL;
static UINT8 *demo_p, *demotime_p; static UINT8 *demo_p, *demotime_p;
static UINT8 *demoend; static UINT8 *demoend;
@ -56,6 +58,7 @@ static UINT8 demoflags;
static UINT16 demoversion; static UINT16 demoversion;
boolean singledemo; // quit after playing a demo from cmdline boolean singledemo; // quit after playing a demo from cmdline
boolean demo_start; // don't start playing demo right away 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 demosynced = true; // console warning message
boolean metalrecording; // recording as metal sonic boolean metalrecording; // recording as metal sonic
@ -95,7 +98,7 @@ demoghost *ghosts = NULL;
// DEMO RECORDING // DEMO RECORDING
// //
#define DEMOVERSION 0x000f #define DEMOVERSION 0x0010
#define DEMOHEADER "\xF0" "SRB2Replay" "\x0F" #define DEMOHEADER "\xF0" "SRB2Replay" "\x0F"
#define DF_GHOST 0x01 // This demo contains ghost data too! #define DF_GHOST 0x01 // This demo contains ghost data too!
@ -1413,6 +1416,10 @@ void G_BeginRecording(void)
char name[MAXCOLORNAME+1]; char name[MAXCOLORNAME+1];
player_t *player = &players[consoleplayer]; player_t *player = &players[consoleplayer];
char *filename;
UINT16 totalfiles;
UINT8 *m;
if (demo_p) if (demo_p)
return; return;
memset(name,0,sizeof(name)); memset(name,0,sizeof(name));
@ -1435,23 +1442,43 @@ void G_BeginRecording(void)
M_Memcpy(demo_p, mapmd5, 16); demo_p += 16; M_Memcpy(demo_p, mapmd5, 16); demo_p += 16;
WRITEUINT8(demo_p,demoflags); 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) switch ((demoflags & DF_ATTACKMASK)>>DF_ATTACKSHIFT)
{ {
case ATTACKING_NONE: // 0 case ATTACKING_NONE: // 0
break; break;
case ATTACKING_RECORD: // 1 case ATTACKING_RECORD: // 1
demotime_p = demo_p; demotime_p = demo_p;
WRITEUINT32(demo_p,UINT32_MAX); // time WRITEUINT32(demo_p,UINT32_MAX); // time
WRITEUINT32(demo_p,0); // score WRITEUINT32(demo_p,0); // score
WRITEUINT16(demo_p,0); // rings WRITEUINT16(demo_p,0); // rings
break; break;
case ATTACKING_NIGHTS: // 2 case ATTACKING_NIGHTS: // 2
demotime_p = demo_p; demotime_p = demo_p;
WRITEUINT32(demo_p,UINT32_MAX); // time WRITEUINT32(demo_p,UINT32_MAX); // time
WRITEUINT32(demo_p,0); // score WRITEUINT32(demo_p,0); // score
break; break;
default: // 3 default: // 3
break; break;
} }
WRITEUINT32(demo_p,P_GetInitSeed()); WRITEUINT32(demo_p,P_GetInitSeed());
@ -1483,18 +1510,18 @@ void G_BeginRecording(void)
// Stats // Stats
WRITEUINT8(demo_p,player->charability); WRITEUINT8(demo_p,player->charability);
WRITEUINT8(demo_p,player->charability2); WRITEUINT8(demo_p,player->charability2);
WRITEUINT8(demo_p,player->actionspd>>FRACBITS); WRITEFIXED(demo_p,player->actionspd);
WRITEUINT8(demo_p,player->mindash>>FRACBITS); WRITEFIXED(demo_p,player->mindash);
WRITEUINT8(demo_p,player->maxdash>>FRACBITS); WRITEFIXED(demo_p,player->maxdash);
WRITEUINT8(demo_p,player->normalspeed>>FRACBITS); WRITEFIXED(demo_p,player->normalspeed);
WRITEUINT8(demo_p,player->runspeed>>FRACBITS); WRITEFIXED(demo_p,player->runspeed);
WRITEUINT8(demo_p,player->thrustfactor); WRITEUINT8(demo_p,player->thrustfactor);
WRITEUINT8(demo_p,player->accelstart); WRITEUINT8(demo_p,player->accelstart);
WRITEUINT8(demo_p,player->acceleration); WRITEUINT8(demo_p,player->acceleration);
WRITEFIXED(demo_p,player->height); WRITEFIXED(demo_p,player->height);
WRITEFIXED(demo_p,player->spinheight); WRITEFIXED(demo_p,player->spinheight);
WRITEUINT8(demo_p,player->camerascale>>FRACBITS); WRITEFIXED(demo_p,player->camerascale);
WRITEUINT8(demo_p,player->shieldscale>>FRACBITS); WRITEFIXED(demo_p,player->shieldscale);
// Trying to convert it back to % causes demo desync due to precision loss. // Trying to convert it back to % causes demo desync due to precision loss.
// Don't do it. // Don't do it.
@ -1590,6 +1617,183 @@ void G_BeginMetal(void)
oldmetal.angle = mo->angle>>24; 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) void G_SetDemoTime(UINT32 ptime, UINT32 pscore, UINT16 prings)
{ {
if (!demorecording || !demotime_p) if (!demorecording || !demotime_p)
@ -1618,10 +1822,9 @@ UINT8 G_CmpDemoTime(char *oldname, char *newname)
UINT8 *buffer,*p; UINT8 *buffer,*p;
UINT8 flags; UINT8 flags;
UINT32 oldtime, newtime, oldscore, newscore; UINT32 oldtime, newtime, oldscore, newscore;
UINT16 oldrings, newrings, oldversion; UINT16 oldrings, newrings, oldversion, newversion;
size_t bufsize ATTRUNUSED; size_t bufsize ATTRUNUSED;
UINT8 c; UINT8 c;
UINT16 s ATTRUNUSED;
UINT8 aflags = 0; UINT8 aflags = 0;
// load the new file // load the new file
@ -1637,15 +1840,15 @@ UINT8 G_CmpDemoTime(char *oldname, char *newname)
I_Assert(c == VERSION); I_Assert(c == VERSION);
c = READUINT8(p); // SUBVERSION c = READUINT8(p); // SUBVERSION
I_Assert(c == SUBVERSION); I_Assert(c == SUBVERSION);
s = READUINT16(p); newversion = READUINT16(p);
I_Assert(s >= 0x000c); I_Assert(newversion == DEMOVERSION);
p += 16; // demo checksum p += 16; // demo checksum
I_Assert(!memcmp(p, "PLAY", 4)); I_Assert(!memcmp(p, "PLAY", 4));
p += 4; // PLAY p += 4; // PLAY
p += 2; // gamemap p += 2; // gamemap
p += 16; // map md5 p += 16; // map md5
flags = READUINT8(p); // demoflags flags = READUINT8(p); // demoflags
G_SkipDemoExtraFiles(&p, newversion);
aflags = flags & (DF_RECORDATTACK|DF_NIGHTSATTACK); aflags = flags & (DF_RECORDATTACK|DF_NIGHTSATTACK);
I_Assert(aflags); I_Assert(aflags);
if (flags & DF_RECORDATTACK) if (flags & DF_RECORDATTACK)
@ -1687,7 +1890,8 @@ UINT8 G_CmpDemoTime(char *oldname, char *newname)
switch(oldversion) // demoversion switch(oldversion) // demoversion
{ {
case DEMOVERSION: // latest always supported 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 0x000d: // all that changed between then and now was longer color name
case 0x000c: case 0x000c:
break; break;
@ -1710,6 +1914,7 @@ UINT8 G_CmpDemoTime(char *oldname, char *newname)
p += 2; // gamemap p += 2; // gamemap
p += 16; // mapmd5 p += 16; // mapmd5
flags = READUINT8(p); flags = READUINT8(p);
G_SkipDemoExtraFiles(&p, oldversion);
if (!(flags & aflags)) if (!(flags & aflags))
{ {
CONS_Alert(CONS_NOTICE, M_GetText("File '%s' not from same game mode. It will be overwritten.\n"), oldname); 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); version = READUINT8(demo_p);
subversion = READUINT8(demo_p); subversion = READUINT8(demo_p);
demoversion = READUINT16(demo_p); demoversion = READUINT16(demo_p);
demo_forwardmove_rng = (demoversion < 0x0010);
switch(demoversion) switch(demoversion)
{ {
case 0x000f:
case 0x000d: case 0x000d:
case 0x000e: case 0x000e:
case DEMOVERSION: // latest always supported case DEMOVERSION: // latest always supported
@ -1871,6 +2078,69 @@ void G_DoPlayDemo(char *defdemoname)
demo_p += 16; // mapmd5 demo_p += 16; // mapmd5
demoflags = READUINT8(demo_p); 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; modeattacking = (demoflags & DF_ATTACKMASK)>>DF_ATTACKSHIFT;
CON_ToggleOff(); CON_ToggleOff();
@ -1913,18 +2183,18 @@ void G_DoPlayDemo(char *defdemoname)
charability = READUINT8(demo_p); charability = READUINT8(demo_p);
charability2 = READUINT8(demo_p); charability2 = READUINT8(demo_p);
actionspd = (fixed_t)READUINT8(demo_p)<<FRACBITS; actionspd = (demoversion < 0x0010) ? (fixed_t)READUINT8(demo_p)<<FRACBITS : READFIXED(demo_p);
mindash = (fixed_t)READUINT8(demo_p)<<FRACBITS; mindash = (demoversion < 0x0010) ? (fixed_t)READUINT8(demo_p)<<FRACBITS : READFIXED(demo_p);
maxdash = (fixed_t)READUINT8(demo_p)<<FRACBITS; maxdash = (demoversion < 0x0010) ? (fixed_t)READUINT8(demo_p)<<FRACBITS : READFIXED(demo_p);
normalspeed = (fixed_t)READUINT8(demo_p)<<FRACBITS; normalspeed = (demoversion < 0x0010) ? (fixed_t)READUINT8(demo_p)<<FRACBITS : READFIXED(demo_p);
runspeed = (fixed_t)READUINT8(demo_p)<<FRACBITS; runspeed = (demoversion < 0x0010) ? (fixed_t)READUINT8(demo_p)<<FRACBITS : READFIXED(demo_p);
thrustfactor = READUINT8(demo_p); thrustfactor = READUINT8(demo_p);
accelstart = READUINT8(demo_p); accelstart = READUINT8(demo_p);
acceleration = READUINT8(demo_p); acceleration = READUINT8(demo_p);
height = (demoversion < 0x000e) ? (fixed_t)READUINT8(demo_p)<<FRACBITS : READFIXED(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); spinheight = (demoversion < 0x000e) ? (fixed_t)READUINT8(demo_p)<<FRACBITS : READFIXED(demo_p);
camerascale = (fixed_t)READUINT8(demo_p)<<FRACBITS; camerascale = (demoversion < 0x0010) ? (fixed_t)READUINT8(demo_p)<<FRACBITS : READFIXED(demo_p);
shieldscale = (fixed_t)READUINT8(demo_p)<<FRACBITS; shieldscale = (demoversion < 0x0010) ? (fixed_t)READUINT8(demo_p)<<FRACBITS : READFIXED(demo_p);
jumpfactor = READFIXED(demo_p); jumpfactor = READFIXED(demo_p);
followitem = READUINT32(demo_p); followitem = READUINT32(demo_p);
@ -2026,6 +2296,88 @@ void G_DoPlayDemo(char *defdemoname)
demo_start = true; 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) void G_AddGhost(char *defdemoname)
{ {
INT32 i; INT32 i;
@ -2085,6 +2437,7 @@ void G_AddGhost(char *defdemoname)
ghostversion = READUINT16(p); ghostversion = READUINT16(p);
switch(ghostversion) switch(ghostversion)
{ {
case 0x000f:
case 0x000d: case 0x000d:
case 0x000e: case 0x000e:
case DEMOVERSION: // latest always supported case DEMOVERSION: // latest always supported
@ -2130,6 +2483,9 @@ void G_AddGhost(char *defdemoname)
Z_Free(buffer); Z_Free(buffer);
return; return;
} }
G_SkipDemoExtraFiles(&p, ghostversion); // Don't wanna modify the file list for ghosts.
switch ((flags & DF_ATTACKMASK)>>DF_ATTACKSHIFT) switch ((flags & DF_ATTACKMASK)>>DF_ATTACKSHIFT)
{ {
case ATTACKING_NONE: // 0 case ATTACKING_NONE: // 0
@ -2161,17 +2517,12 @@ void G_AddGhost(char *defdemoname)
// Ghosts do not have a player structure to put this in. // Ghosts do not have a player structure to put this in.
p++; // charability p++; // charability
p++; // charability2 p++; // charability2
p++; // actionspd p += (ghostversion < 0x0010) ? 5 : 5 * sizeof(fixed_t); // actionspd, mindash, maxdash, normalspeed, and runspeed
p++; // mindash
p++; // maxdash
p++; // normalspeed
p++; // runspeed
p++; // thrustfactor p++; // thrustfactor
p++; // accelstart p++; // accelstart
p++; // acceleration p++; // acceleration
p += (ghostversion < 0x000e) ? 2 : 2 * sizeof(fixed_t); // height and spinheight p += (ghostversion < 0x000e) ? 2 : 2 * sizeof(fixed_t); // height and spinheight
p++; // camerascale p += (ghostversion < 0x0010) ? 2 : 2 * sizeof(fixed_t); // camerascale and shieldscale
p++; // shieldscale
p += 4; // jumpfactor p += 4; // jumpfactor
p += 4; // followitem p += 4; // followitem
@ -2347,6 +2698,7 @@ void G_DoPlayMetal(void)
switch(metalversion) switch(metalversion)
{ {
case DEMOVERSION: // latest always supported case DEMOVERSION: // latest always supported
case 0x000f:
case 0x000e: // There are checks wheter the momentum is from older demo versions or not 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 0x000d: // all that changed between then and now was longer color name
case 0x000c: case 0x000c:

View file

@ -26,9 +26,19 @@
extern boolean demoplayback, titledemo, demorecording, timingdemo; extern boolean demoplayback, titledemo, demorecording, timingdemo;
extern tic_t demostarttime; 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. // Quit after playing a demo from cmdline.
extern boolean singledemo; extern boolean singledemo;
extern boolean demo_start; extern boolean demo_start;
extern boolean demo_forwardmove_rng;
extern boolean demosynced; extern boolean demosynced;
extern mobj_t *metalplayback; extern mobj_t *metalplayback;
@ -53,6 +63,18 @@ typedef enum
GHC_RETURNSKIN // ditto GHC_RETURNSKIN // ditto
} ghostcolor_t; } 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 // Record/playback tics
void G_ReadDemoTiccmd(ticcmd_t *cmd, INT32 playernum); void G_ReadDemoTiccmd(ticcmd_t *cmd, INT32 playernum);
void G_WriteDemoTiccmd(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); void G_StopDemo(void);
boolean G_CheckDemoStatus(void); boolean G_CheckDemoStatus(void);
INT32 G_ConvertOldFrameFlags(INT32 frame); INT32 G_ConvertOldFrameFlags(INT32 frame);
UINT8 G_CheckDemoForError(char *defdemoname);
#endif // __G_DEMO__ #endif // __G_DEMO__

File diff suppressed because it is too large Load diff

View file

@ -19,6 +19,7 @@
#include "d_event.h" #include "d_event.h"
#include "g_demo.h" #include "g_demo.h"
#include "m_cheat.h" // objectplacing #include "m_cheat.h" // objectplacing
#include "m_cond.h"
extern char gamedatafilename[64]; extern char gamedatafilename[64];
extern char timeattackfolder[64]; extern char timeattackfolder[64];
@ -48,6 +49,8 @@ extern boolean promptactive;
extern consvar_t cv_pauseifunfocused; extern consvar_t cv_pauseifunfocused;
extern consvar_t cv_instantretry;
// used in game menu // used in game menu
extern consvar_t cv_tutorialprompt; extern consvar_t cv_tutorialprompt;
extern consvar_t cv_chatwidth, cv_chatnotifications, cv_chatheight, cv_chattime, cv_consolechat, cv_chatbacktint, cv_chatspamprotection, cv_compactscoreboard; extern consvar_t cv_chatwidth, cv_chatnotifications, cv_chatheight, cv_chattime, cv_consolechat, cv_chatbacktint, cv_chatspamprotection, cv_compactscoreboard;
@ -183,7 +186,7 @@ boolean G_IsTitleCardAvailable(void);
// Can be called by the startup code or M_Responder, calls P_SetupLevel. // Can be called by the startup code or M_Responder, calls P_SetupLevel.
void G_LoadGame(UINT32 slot, INT16 mapoverride); void G_LoadGame(UINT32 slot, INT16 mapoverride);
void G_SaveGameData(void); void G_SaveGameData(gamedata_t *data);
void G_SaveGame(UINT32 slot, INT16 mapnum); void G_SaveGame(UINT32 slot, INT16 mapnum);
@ -239,27 +242,27 @@ void G_SetModeAttackRetryFlag(void);
void G_ClearModeAttackRetryFlag(void); void G_ClearModeAttackRetryFlag(void);
boolean G_GetModeAttackRetryFlag(void); boolean G_GetModeAttackRetryFlag(void);
void G_LoadGameData(void); void G_LoadGameData(gamedata_t *data);
void G_LoadGameSettings(void); void G_LoadGameSettings(void);
void G_SetGameModified(boolean silent); void G_SetGameModified(boolean silent);
void G_SetUsedCheats(boolean silent);
void G_SetGamestate(gamestate_t newstate); void G_SetGamestate(gamestate_t newstate);
// Gamedata record shit // Gamedata record shit
void G_AllocMainRecordData(INT16 i); void G_AllocMainRecordData(INT16 i, gamedata_t *data);
void G_AllocNightsRecordData(INT16 i); void G_AllocNightsRecordData(INT16 i, gamedata_t *data);
void G_ClearRecords(void); void G_ClearRecords(gamedata_t *data);
UINT32 G_GetBestScore(INT16 map); UINT32 G_GetBestScore(INT16 map, gamedata_t *data);
tic_t G_GetBestTime(INT16 map); tic_t G_GetBestTime(INT16 map, gamedata_t *data);
UINT16 G_GetBestRings(INT16 map); UINT16 G_GetBestRings(INT16 map, gamedata_t *data);
UINT32 G_GetBestNightsScore(INT16 map, UINT8 mare); UINT32 G_GetBestNightsScore(INT16 map, UINT8 mare, gamedata_t *data);
tic_t G_GetBestNightsTime(INT16 map, UINT8 mare); tic_t G_GetBestNightsTime(INT16 map, UINT8 mare, gamedata_t *data);
UINT8 G_GetBestNightsGrade(INT16 map, UINT8 mare); UINT8 G_GetBestNightsGrade(INT16 map, UINT8 mare, gamedata_t *data);
void G_AddTempNightsRecords(UINT32 pscore, tic_t ptime, UINT8 mare); void G_AddTempNightsRecords(player_t *player, UINT32 pscore, tic_t ptime, UINT8 mare);
void G_SetNightsRecords(void);
FUNCMATH INT32 G_TicsToHours(tic_t tics); FUNCMATH INT32 G_TicsToHours(tic_t tics);
FUNCMATH INT32 G_TicsToMinutes(tic_t tics, boolean full); FUNCMATH INT32 G_TicsToMinutes(tic_t tics, boolean full);

View file

@ -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
)

View file

@ -8,6 +8,5 @@ hw_cache.c
hw_md2load.c hw_md2load.c
hw_md3load.c hw_md3load.c
hw_model.c hw_model.c
u_list.c
hw_batching.c hw_batching.c
r_opengl/r_opengl.c r_opengl/r_opengl.c

View file

@ -42,10 +42,10 @@ int unsortedVertexArrayAllocSize = 65536;
// Call HWR_RenderBatches to render all the collected geometry. // Call HWR_RenderBatches to render all the collected geometry.
void HWR_StartBatching(void) void HWR_StartBatching(void)
{ {
if (currently_batching) if (currently_batching)
I_Error("Repeat call to HWR_StartBatching without HWR_RenderBatches"); 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) if (!finalVertexArray)
{ {
finalVertexArray = malloc(finalVertexArrayAllocSize * sizeof(FOutVector)); finalVertexArray = malloc(finalVertexArrayAllocSize * sizeof(FOutVector));
@ -55,7 +55,7 @@ void HWR_StartBatching(void)
unsortedVertexArray = malloc(unsortedVertexArrayAllocSize * sizeof(FOutVector)); unsortedVertexArray = malloc(unsortedVertexArrayAllocSize * sizeof(FOutVector));
} }
currently_batching = true; currently_batching = true;
} }
// This replaces the direct calls to pfnSetTexture in cases where batching is available. // This replaces the direct calls to pfnSetTexture in cases where batching is available.

View file

@ -93,33 +93,22 @@ typedef struct FVector
//Hurdler: Transform (coords + angles) //Hurdler: Transform (coords + angles)
//BP: transform order : scale(rotation_x(rotation_y(translation(v)))) //BP: transform order : scale(rotation_x(rotation_y(translation(v))))
// Kart features
//#define USE_FTRANSFORM_ANGLEZ
//#define USE_FTRANSFORM_MIRROR
// Vanilla features // Vanilla features
#define USE_MODEL_NEXTFRAME #define USE_MODEL_NEXTFRAME
typedef struct typedef struct
{ {
FLOAT x,y,z; // position FLOAT x,y,z; // position
#ifdef USE_FTRANSFORM_ANGLEZ
FLOAT anglex,angley,anglez; // aimingangle / viewangle FLOAT anglex,angley,anglez; // aimingangle / viewangle
#else
FLOAT anglex,angley; // aimingangle / viewangle
#endif
FLOAT scalex,scaley,scalez; FLOAT scalex,scaley,scalez;
FLOAT fovxangle, fovyangle; FLOAT fovxangle, fovyangle;
UINT8 splitscreen; UINT8 splitscreen;
boolean flip; // screenflip boolean flip; // screenflip
boolean roll; boolean roll;
SINT8 rollflip;
FLOAT rollangle; // done to not override USE_FTRANSFORM_ANGLEZ FLOAT rollangle; // done to not override USE_FTRANSFORM_ANGLEZ
UINT8 rotaxis;
FLOAT centerx, centery; FLOAT centerx, centery;
#ifdef USE_FTRANSFORM_MIRROR FLOAT rollx, rollz;
boolean mirror; // SRB2Kart: Encore Mode boolean mirror; // SRB2Kart: Encore Mode
#endif
boolean shearing; // 14042019 boolean shearing; // 14042019
float viewaiming; // 17052019 float viewaiming; // 17052019
} FTransform; } FTransform;
@ -136,6 +125,7 @@ typedef struct
// Predefined shader types // Predefined shader types
enum enum
{ {
SHADER_NONE = -1,
SHADER_DEFAULT = 0, SHADER_DEFAULT = 0,
SHADER_FLOOR, SHADER_FLOOR,
@ -237,7 +227,8 @@ enum EPolyFlags
PF_RemoveYWrap = 0x00010000, // Forces clamp texture on Y PF_RemoveYWrap = 0x00010000, // Forces clamp texture on Y
PF_ForceWrapX = 0x00020000, // Forces repeat texture on X PF_ForceWrapX = 0x00020000, // Forces repeat texture on X
PF_ForceWrapY = 0x00040000, // Forces repeat texture on Y 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
}; };

View file

@ -51,7 +51,7 @@ EXPORT void HWRAPI(ClearMipMapCache) (void);
EXPORT void HWRAPI(SetSpecialState) (hwdspecialstate_t IdState, INT32 Value); EXPORT void HWRAPI(SetSpecialState) (hwdspecialstate_t IdState, INT32 Value);
//Hurdler: added for new development //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(CreateModelVBOs) (model_t *model);
EXPORT void HWRAPI(SetTransform) (FTransform *ptransform); EXPORT void HWRAPI(SetTransform) (FTransform *ptransform);
EXPORT INT32 HWRAPI(GetTextureUsed) (void); EXPORT INT32 HWRAPI(GetTextureUsed) (void);
@ -136,4 +136,3 @@ extern struct hwdriver_s hwdriver;
#endif //not defined _CREATE_DLL_ #endif //not defined _CREATE_DLL_
#endif //__HWR_DRV_H__ #endif //__HWR_DRV_H__

View file

@ -81,6 +81,7 @@ typedef struct gl_vissprite_s
boolean flip, vflip; boolean flip, vflip;
boolean precip; // Tails 08-25-2002 boolean precip; // Tails 08-25-2002
boolean bbox;
boolean rotated; boolean rotated;
UINT8 translucency; //alpha level 0-255 UINT8 translucency; //alpha level 0-255
@ -88,7 +89,7 @@ typedef struct gl_vissprite_s
//Hurdler: 25/04/2000: now support colormap in hardware mode //Hurdler: 25/04/2000: now support colormap in hardware mode
UINT8 *colormap; UINT8 *colormap;
INT32 dispoffset; // copy of info->dispoffset, affects ordering but not drawing INT32 dispoffset; // copy of mobj->dispoffset, affects ordering but not drawing
patch_t *gpatch; patch_t *gpatch;
mobj_t *mobj; // NOTE: This is a precipmobj_t if precip is true !!! Watch out. mobj_t *mobj; // NOTE: This is a precipmobj_t if precip is true !!! Watch out.

View file

@ -66,6 +66,7 @@ static void HWR_ProjectSprite(mobj_t *thing);
#ifdef HWPRECIP #ifdef HWPRECIP
static void HWR_ProjectPrecipitationSprite(precipmobj_t *thing); static void HWR_ProjectPrecipitationSprite(precipmobj_t *thing);
#endif #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_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, 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 angle_t dup_viewangle;
static float gl_viewx, gl_viewy, gl_viewz; 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!) // Maybe not necessary with the new T&L code (needs to be checked!)
static float gl_viewludsin, gl_viewludcos; // look up down kik test 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 if (!isceiling) // it's a floor
{ {
scrollx = FIXED_TO_FLOAT(FOFsector->floor_xoffs)/fflatwidth; scrollx = FIXED_TO_FLOAT(FOFsector->floorxoffset)/fflatwidth;
scrolly = FIXED_TO_FLOAT(FOFsector->floor_yoffs)/fflatheight; scrolly = FIXED_TO_FLOAT(FOFsector->flooryoffset)/fflatheight;
angle = FOFsector->floorpic_angle; angle = FOFsector->floorangle;
} }
else // it's a ceiling else // it's a ceiling
{ {
scrollx = FIXED_TO_FLOAT(FOFsector->ceiling_xoffs)/fflatwidth; scrollx = FIXED_TO_FLOAT(FOFsector->ceilingxoffset)/fflatwidth;
scrolly = FIXED_TO_FLOAT(FOFsector->ceiling_yoffs)/fflatheight; scrolly = FIXED_TO_FLOAT(FOFsector->ceilingyoffset)/fflatheight;
angle = FOFsector->ceilingpic_angle; angle = FOFsector->ceilingangle;
} }
} }
else if (gl_frontsector) else if (gl_frontsector)
{ {
if (!isceiling) // it's a floor if (!isceiling) // it's a floor
{ {
scrollx = FIXED_TO_FLOAT(gl_frontsector->floor_xoffs)/fflatwidth; scrollx = FIXED_TO_FLOAT(gl_frontsector->floorxoffset)/fflatwidth;
scrolly = FIXED_TO_FLOAT(gl_frontsector->floor_yoffs)/fflatheight; scrolly = FIXED_TO_FLOAT(gl_frontsector->flooryoffset)/fflatheight;
angle = gl_frontsector->floorpic_angle; angle = gl_frontsector->floorangle;
} }
else // it's a ceiling else // it's a ceiling
{ {
scrollx = FIXED_TO_FLOAT(gl_frontsector->ceiling_xoffs)/fflatwidth; scrollx = FIXED_TO_FLOAT(gl_frontsector->ceilingxoffset)/fflatwidth;
scrolly = FIXED_TO_FLOAT(gl_frontsector->ceiling_yoffs)/fflatheight; scrolly = FIXED_TO_FLOAT(gl_frontsector->ceilingyoffset)/fflatheight;
angle = gl_frontsector->ceilingpic_angle; angle = gl_frontsector->ceilingangle;
} }
} }
@ -1153,7 +1154,7 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom
else else
texturevpeg = gl_backsector->ceilingheight + textureheight[gl_toptexture] - gl_frontsector->ceilingheight; texturevpeg = gl_backsector->ceilingheight + textureheight[gl_toptexture] - gl_frontsector->ceilingheight;
texturevpeg += gl_sidedef->rowoffset; texturevpeg += gl_sidedef->rowoffset + gl_sidedef->offsety_top;
// This is so that it doesn't overflow and screw up the wall, it doesn't need to go higher than the texture's height anyway // This is so that it doesn't overflow and screw up the wall, it doesn't need to go higher than the texture's height anyway
texturevpeg %= textureheight[gl_toptexture]; texturevpeg %= textureheight[gl_toptexture];
@ -1162,8 +1163,8 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom
wallVerts[3].t = wallVerts[2].t = texturevpeg * grTex->scaleY; wallVerts[3].t = wallVerts[2].t = texturevpeg * grTex->scaleY;
wallVerts[0].t = wallVerts[1].t = (texturevpeg + gl_frontsector->ceilingheight - gl_backsector->ceilingheight) * grTex->scaleY; wallVerts[0].t = wallVerts[1].t = (texturevpeg + gl_frontsector->ceilingheight - gl_backsector->ceilingheight) * grTex->scaleY;
wallVerts[0].s = wallVerts[3].s = cliplow * grTex->scaleX; wallVerts[0].s = wallVerts[3].s = (cliplow + gl_sidedef->offsetx_top) * grTex->scaleX;
wallVerts[2].s = wallVerts[1].s = cliphigh * grTex->scaleX; wallVerts[2].s = wallVerts[1].s = (cliphigh + gl_sidedef->offsetx_top) * grTex->scaleX;
// Adjust t value for sloped walls // Adjust t value for sloped walls
if (!(gl_linedef->flags & ML_SKEWTD)) if (!(gl_linedef->flags & ML_SKEWTD))
@ -1213,7 +1214,7 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom
else else
texturevpeg = gl_frontsector->floorheight - gl_backsector->floorheight; texturevpeg = gl_frontsector->floorheight - gl_backsector->floorheight;
texturevpeg += gl_sidedef->rowoffset; texturevpeg += gl_sidedef->rowoffset + gl_sidedef->offsety_bot;
// This is so that it doesn't overflow and screw up the wall, it doesn't need to go higher than the texture's height anyway // This is so that it doesn't overflow and screw up the wall, it doesn't need to go higher than the texture's height anyway
texturevpeg %= textureheight[gl_bottomtexture]; texturevpeg %= textureheight[gl_bottomtexture];
@ -1222,8 +1223,8 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom
wallVerts[3].t = wallVerts[2].t = texturevpeg * grTex->scaleY; wallVerts[3].t = wallVerts[2].t = texturevpeg * grTex->scaleY;
wallVerts[0].t = wallVerts[1].t = (texturevpeg + gl_backsector->floorheight - gl_frontsector->floorheight) * grTex->scaleY; wallVerts[0].t = wallVerts[1].t = (texturevpeg + gl_backsector->floorheight - gl_frontsector->floorheight) * grTex->scaleY;
wallVerts[0].s = wallVerts[3].s = cliplow * grTex->scaleX; wallVerts[0].s = wallVerts[3].s = (cliplow + gl_sidedef->offsetx_bot) * grTex->scaleX;
wallVerts[2].s = wallVerts[1].s = cliphigh * grTex->scaleX; wallVerts[2].s = wallVerts[1].s = (cliphigh + gl_sidedef->offsetx_bot) * grTex->scaleX;
// Adjust t value for sloped walls // Adjust t value for sloped walls
if (!(gl_linedef->flags & ML_SKEWTD)) if (!(gl_linedef->flags & ML_SKEWTD))
@ -1333,13 +1334,13 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom
// Peg it to the floor // Peg it to the floor
if (gl_linedef->flags & ML_MIDPEG) if (gl_linedef->flags & ML_MIDPEG)
{ {
polybottom = max(front->floorheight, back->floorheight) + gl_sidedef->rowoffset; polybottom = max(front->floorheight, back->floorheight) + gl_sidedef->rowoffset + gl_sidedef->offsety_mid;
polytop = polybottom + midtexheight; polytop = polybottom + midtexheight;
} }
// Peg it to the ceiling // Peg it to the ceiling
else else
{ {
polytop = min(front->ceilingheight, back->ceilingheight) + gl_sidedef->rowoffset; polytop = min(front->ceilingheight, back->ceilingheight) + gl_sidedef->rowoffset + gl_sidedef->offsety_mid;
polybottom = polytop - midtexheight; polybottom = polytop - midtexheight;
} }
@ -1350,9 +1351,9 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom
// Skew the texture, but peg it to the floor // Skew the texture, but peg it to the floor
else if (gl_linedef->flags & ML_MIDPEG) else if (gl_linedef->flags & ML_MIDPEG)
{ {
polybottom = popenbottom + gl_sidedef->rowoffset; polybottom = popenbottom + gl_sidedef->rowoffset + gl_sidedef->offsety_mid;
polytop = polybottom + midtexheight; polytop = polybottom + midtexheight;
polybottomslope = popenbottomslope + gl_sidedef->rowoffset; polybottomslope = popenbottomslope + gl_sidedef->rowoffset + gl_sidedef->offsety_mid;
polytopslope = polybottomslope + midtexheight; polytopslope = polybottomslope + midtexheight;
} }
// Skew it according to the ceiling's slope // Skew it according to the ceiling's slope
@ -1407,12 +1408,12 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom
// Left side // Left side
wallVerts[3].t = texturevpeg * grTex->scaleY; wallVerts[3].t = texturevpeg * grTex->scaleY;
wallVerts[0].t = (h - l + texturevpeg) * grTex->scaleY; wallVerts[0].t = (h - l + texturevpeg) * grTex->scaleY;
wallVerts[0].s = wallVerts[3].s = cliplow * grTex->scaleX; wallVerts[0].s = wallVerts[3].s = (cliplow + gl_sidedef->offsetx_mid) * grTex->scaleX;
// Right side // Right side
wallVerts[2].t = texturevpegslope * grTex->scaleY; wallVerts[2].t = texturevpegslope * grTex->scaleY;
wallVerts[1].t = (hS - lS + texturevpegslope) * grTex->scaleY; wallVerts[1].t = (hS - lS + texturevpegslope) * grTex->scaleY;
wallVerts[2].s = wallVerts[1].s = cliphigh * grTex->scaleX; wallVerts[2].s = wallVerts[1].s = (cliphigh + gl_sidedef->offsetx_mid) * grTex->scaleX;
// set top/bottom coords // set top/bottom coords
// Take the texture peg into account, rather than changing the offsets past // Take the texture peg into account, rather than changing the offsets past
@ -1474,19 +1475,19 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom
// PEGGING // PEGGING
if ((gl_linedef->flags & (ML_DONTPEGBOTTOM|ML_NOSKEW)) == (ML_DONTPEGBOTTOM|ML_NOSKEW)) if ((gl_linedef->flags & (ML_DONTPEGBOTTOM|ML_NOSKEW)) == (ML_DONTPEGBOTTOM|ML_NOSKEW))
texturevpeg = gl_frontsector->floorheight + textureheight[gl_sidedef->midtexture] - gl_frontsector->ceilingheight + gl_sidedef->rowoffset; texturevpeg = gl_frontsector->floorheight + textureheight[gl_sidedef->midtexture] - gl_frontsector->ceilingheight + gl_sidedef->rowoffset + gl_sidedef->offsety_mid;
else if (gl_linedef->flags & ML_DONTPEGBOTTOM) else if (gl_linedef->flags & ML_DONTPEGBOTTOM)
texturevpeg = worldbottom + textureheight[gl_sidedef->midtexture] - worldtop + gl_sidedef->rowoffset; texturevpeg = worldbottom + textureheight[gl_sidedef->midtexture] - worldtop + gl_sidedef->rowoffset + gl_sidedef->offsety_mid;
else else
// top of texture at top // top of texture at top
texturevpeg = gl_sidedef->rowoffset; texturevpeg = gl_sidedef->rowoffset + gl_sidedef->offsety_mid;
grTex = HWR_GetTexture(gl_midtexture); grTex = HWR_GetTexture(gl_midtexture);
wallVerts[3].t = wallVerts[2].t = texturevpeg * grTex->scaleY; wallVerts[3].t = wallVerts[2].t = texturevpeg * grTex->scaleY;
wallVerts[0].t = wallVerts[1].t = (texturevpeg + gl_frontsector->ceilingheight - gl_frontsector->floorheight) * grTex->scaleY; wallVerts[0].t = wallVerts[1].t = (texturevpeg + gl_frontsector->ceilingheight - gl_frontsector->floorheight) * grTex->scaleY;
wallVerts[0].s = wallVerts[3].s = cliplow * grTex->scaleX; wallVerts[0].s = wallVerts[3].s = (cliplow + gl_sidedef->offsetx_mid) * grTex->scaleX;
wallVerts[2].s = wallVerts[1].s = cliphigh * grTex->scaleX; wallVerts[2].s = wallVerts[1].s = (cliphigh + gl_sidedef->offsetx_mid) * grTex->scaleX;
// Texture correction for slopes // Texture correction for slopes
if (gl_linedef->flags & ML_NOSKEW) { if (gl_linedef->flags & ML_NOSKEW) {
@ -1634,13 +1635,13 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom
// -- Monster Iestyn 26/06/18 // -- Monster Iestyn 26/06/18
if (newline) if (newline)
{ {
texturevpeg = sides[newline->sidenum[0]].rowoffset; texturevpeg = sides[newline->sidenum[0]].rowoffset + sides[newline->sidenum[0]].offsety_mid;
attachtobottom = !!(newline->flags & ML_DONTPEGBOTTOM); attachtobottom = !!(newline->flags & ML_DONTPEGBOTTOM);
slopeskew = !!(newline->flags & ML_SKEWTD); slopeskew = !!(newline->flags & ML_SKEWTD);
} }
else else
{ {
texturevpeg = sides[rover->master->sidenum[0]].rowoffset; texturevpeg = sides[rover->master->sidenum[0]].rowoffset + sides[rover->master->sidenum[0]].offsety_mid;
attachtobottom = !!(gl_linedef->flags & ML_DONTPEGBOTTOM); attachtobottom = !!(gl_linedef->flags & ML_DONTPEGBOTTOM);
slopeskew = !!(rover->master->flags & ML_SKEWTD); slopeskew = !!(rover->master->flags & ML_SKEWTD);
} }
@ -1672,8 +1673,8 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom
} }
} }
wallVerts[0].s = wallVerts[3].s = cliplow * grTex->scaleX; wallVerts[0].s = wallVerts[3].s = (cliplow + gl_sidedef->offsetx_mid) * grTex->scaleX;
wallVerts[2].s = wallVerts[1].s = cliphigh * grTex->scaleX; wallVerts[2].s = wallVerts[1].s = (cliphigh + gl_sidedef->offsetx_mid) * grTex->scaleX;
} }
if (rover->fofflags & FOF_FOG) if (rover->fofflags & FOF_FOG)
{ {
@ -1698,7 +1699,7 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom
if ((rover->fofflags & FOF_TRANSLUCENT && !(rover->fofflags & FOF_SPLAT)) || rover->blend) if ((rover->fofflags & FOF_TRANSLUCENT && !(rover->fofflags & FOF_SPLAT)) || rover->blend)
{ {
blendmode = rover->blend ? HWR_GetBlendModeFlag(rover->blend) : PF_Translucent; 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) if (gl_frontsector->numlights)
@ -1785,17 +1786,17 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom
if (newline) if (newline)
{ {
wallVerts[3].t = wallVerts[2].t = (*rover->topheight - h + sides[newline->sidenum[0]].rowoffset) * grTex->scaleY; wallVerts[3].t = wallVerts[2].t = (*rover->topheight - h + sides[newline->sidenum[0]].rowoffset + sides[newline->sidenum[0]].offsety_mid) * grTex->scaleY;
wallVerts[0].t = wallVerts[1].t = (h - l + (*rover->topheight - h + sides[newline->sidenum[0]].rowoffset)) * grTex->scaleY; wallVerts[0].t = wallVerts[1].t = (h - l + (*rover->topheight - h + sides[newline->sidenum[0]].rowoffset) + sides[newline->sidenum[0]].offsety_mid) * grTex->scaleY;
} }
else else
{ {
wallVerts[3].t = wallVerts[2].t = (*rover->topheight - h + sides[rover->master->sidenum[0]].rowoffset) * grTex->scaleY; wallVerts[3].t = wallVerts[2].t = (*rover->topheight - h + sides[rover->master->sidenum[0]].rowoffset + sides[rover->master->sidenum[0]].offsety_mid) * grTex->scaleY;
wallVerts[0].t = wallVerts[1].t = (h - l + (*rover->topheight - h + sides[rover->master->sidenum[0]].rowoffset)) * grTex->scaleY; wallVerts[0].t = wallVerts[1].t = (h - l + (*rover->topheight - h + sides[rover->master->sidenum[0]].rowoffset + sides[rover->master->sidenum[0]].offsety_mid)) * grTex->scaleY;
} }
wallVerts[0].s = wallVerts[3].s = cliplow * grTex->scaleX; wallVerts[0].s = wallVerts[3].s = (cliplow + gl_sidedef->offsetx_mid) * grTex->scaleX;
wallVerts[2].s = wallVerts[1].s = cliphigh * grTex->scaleX; wallVerts[2].s = wallVerts[1].s = (cliphigh + gl_sidedef->offsetx_mid) * grTex->scaleX;
} }
if (rover->fofflags & FOF_FOG) if (rover->fofflags & FOF_FOG)
@ -1821,7 +1822,7 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom
if ((rover->fofflags & FOF_TRANSLUCENT && !(rover->fofflags & FOF_SPLAT)) || rover->blend) if ((rover->fofflags & FOF_TRANSLUCENT && !(rover->fofflags & FOF_SPLAT)) || rover->blend)
{ {
blendmode = rover->blend ? HWR_GetBlendModeFlag(rover->blend) : PF_Translucent; 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) if (gl_backsector->numlights)
@ -2719,30 +2720,30 @@ static void HWR_RenderPolyObjectPlane(polyobj_t *polysector, boolean isceiling,
{ {
if (!isceiling) // it's a floor if (!isceiling) // it's a floor
{ {
scrollx = FIXED_TO_FLOAT(FOFsector->floor_xoffs)/fflatwidth; scrollx = FIXED_TO_FLOAT(FOFsector->floorxoffset)/fflatwidth;
scrolly = FIXED_TO_FLOAT(FOFsector->floor_yoffs)/fflatheight; scrolly = FIXED_TO_FLOAT(FOFsector->flooryoffset)/fflatheight;
angle = FOFsector->floorpic_angle; angle = FOFsector->floorangle;
} }
else // it's a ceiling else // it's a ceiling
{ {
scrollx = FIXED_TO_FLOAT(FOFsector->ceiling_xoffs)/fflatwidth; scrollx = FIXED_TO_FLOAT(FOFsector->ceilingxoffset)/fflatwidth;
scrolly = FIXED_TO_FLOAT(FOFsector->ceiling_yoffs)/fflatheight; scrolly = FIXED_TO_FLOAT(FOFsector->ceilingyoffset)/fflatheight;
angle = FOFsector->ceilingpic_angle; angle = FOFsector->ceilingangle;
} }
} }
else if (gl_frontsector) else if (gl_frontsector)
{ {
if (!isceiling) // it's a floor if (!isceiling) // it's a floor
{ {
scrollx = FIXED_TO_FLOAT(gl_frontsector->floor_xoffs)/fflatwidth; scrollx = FIXED_TO_FLOAT(gl_frontsector->floorxoffset)/fflatwidth;
scrolly = FIXED_TO_FLOAT(gl_frontsector->floor_yoffs)/fflatheight; scrolly = FIXED_TO_FLOAT(gl_frontsector->flooryoffset)/fflatheight;
angle = gl_frontsector->floorpic_angle; angle = gl_frontsector->floorangle;
} }
else // it's a ceiling else // it's a ceiling
{ {
scrollx = FIXED_TO_FLOAT(gl_frontsector->ceiling_xoffs)/fflatwidth; scrollx = FIXED_TO_FLOAT(gl_frontsector->ceilingxoffset)/fflatwidth;
scrolly = FIXED_TO_FLOAT(gl_frontsector->ceiling_yoffs)/fflatheight; scrolly = FIXED_TO_FLOAT(gl_frontsector->ceilingyoffset)/fflatheight;
angle = gl_frontsector->ceilingpic_angle; angle = gl_frontsector->ceilingangle;
} }
} }
@ -3094,7 +3095,7 @@ static void HWR_Subsector(size_t num)
false, false,
*rover->bottomheight, *rover->bottomheight,
*gl_frontsector->lightlist[light].lightlevel, *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), HWR_RippleBlend(gl_frontsector, rover, false) | (rover->blend ? HWR_GetBlendModeFlag(rover->blend) : PF_Translucent),
false, *gl_frontsector->lightlist[light].extra_colormap); false, *gl_frontsector->lightlist[light].extra_colormap);
} }
@ -3140,7 +3141,7 @@ static void HWR_Subsector(size_t num)
true, true,
*rover->topheight, *rover->topheight,
*gl_frontsector->lightlist[light].lightlevel, *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), HWR_RippleBlend(gl_frontsector, rover, false) | (rover->blend ? HWR_GetBlendModeFlag(rover->blend) : PF_Translucent),
false, *gl_frontsector->lightlist[light].extra_colormap); false, *gl_frontsector->lightlist[light].extra_colormap);
} }
@ -3594,7 +3595,7 @@ static void HWR_DrawDropShadow(mobj_t *thing, fixed_t scale)
return; 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; alpha = floordiff / (4*FRACUNIT) + 75;
if (alpha >= 255) return; if (alpha >= 255) return;
@ -3605,7 +3606,7 @@ static void HWR_DrawDropShadow(mobj_t *thing, fixed_t scale)
HWR_GetPatch(gpatch); HWR_GetPatch(gpatch);
scalemul = FixedMul(FRACUNIT - floordiff/640, scale); scalemul = FixedMul(FRACUNIT - floordiff/640, scale);
scalemul = FixedMul(scalemul, (thing->radius*2) / gpatch->height); scalemul = FixedMul(scalemul, (interp.radius*2) / gpatch->height);
fscale = FIXED_TO_FLOAT(scalemul); fscale = FIXED_TO_FLOAT(scalemul);
fx = FIXED_TO_FLOAT(interp.x); fx = FIXED_TO_FLOAT(interp.x);
@ -3717,7 +3718,7 @@ static void HWR_RotateSpritePolyToAim(gl_vissprite_t *spr, FOutVector *wallVerts
if (P_MobjFlip(spr->mobj) == -1) if (P_MobjFlip(spr->mobj) == -1)
{ {
basey = FIXED_TO_FLOAT(interp.z + spr->mobj->height); basey = FIXED_TO_FLOAT(interp.z + interp.height);
} }
else else
{ {
@ -4036,6 +4037,54 @@ static void HWR_SplitSprite(gl_vissprite_t *spr)
HWR_LinkDrawHackAdd(wallVerts, 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 // HWR_DrawSprite : Draw flat sprites
// : (monsters, bonuses, weapons, lights, ...) // : (monsters, bonuses, weapons, lights, ...)
@ -4092,14 +4141,11 @@ static void HWR_DrawSprite(gl_vissprite_t *spr)
float xscale, yscale; float xscale, yscale;
float xoffset, yoffset; float xoffset, yoffset;
float leftoffset, topoffset; float leftoffset, topoffset;
float scale = spr->scale;
float zoffset = (P_MobjFlip(spr->mobj) * 0.05f); float zoffset = (P_MobjFlip(spr->mobj) * 0.05f);
pslope_t *splatslope = NULL; pslope_t *splatslope = NULL;
INT32 i; INT32 i;
renderflags_t renderflags = spr->renderflags; renderflags_t renderflags = spr->renderflags;
if (renderflags & RF_SHADOWEFFECTS)
scale *= spr->shadowscale;
if (spr->rotateflags & SRF_3D || renderflags & RF_NOSPLATBILLBOARD) if (spr->rotateflags & SRF_3D || renderflags & RF_NOSPLATBILLBOARD)
angle = spr->mobj->angle; angle = spr->mobj->angle;
@ -4107,7 +4153,7 @@ static void HWR_DrawSprite(gl_vissprite_t *spr)
angle = viewangle; angle = viewangle;
if (!spr->rotated) if (!spr->rotated)
angle += spr->mobj->rollangle; angle += spr->mobj->spriteroll;
angle = -angle; angle = -angle;
angle += ANGLE_90; angle += ANGLE_90;
@ -4480,9 +4526,16 @@ static int CompareVisSprites(const void *p1, const void *p2)
int transparency1; int transparency1;
int transparency2; 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 // 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; linkdraw1 = !spr1->precip && (spr1->mobj->flags2 & MF2_LINKDRAW) && spr1->mobj->tracer;
int linkdraw2 = !spr2->precip && (spr2->mobj->flags2 & MF2_LINKDRAW) && spr2->mobj->tracer; linkdraw2 = !spr2->precip && (spr2->mobj->flags2 & MF2_LINKDRAW) && spr2->mobj->tracer;
// ^ is the XOR operation // ^ is the XOR operation
// if comparing a linkdraw and non-linkdraw sprite or 2 linkdraw sprites with different tracers, then use // if comparing a linkdraw and non-linkdraw sprite or 2 linkdraw sprites with different tracers, then use
@ -4852,6 +4905,9 @@ static void HWR_DrawSprites(void)
for (i = 0; i < gl_visspritecount; i++) for (i = 0; i < gl_visspritecount; i++)
{ {
gl_vissprite_t *spr = gl_vsprorder[i]; gl_vissprite_t *spr = gl_vsprorder[i];
if (spr->bbox)
HWR_DrawBoundingBox(spr);
else
#ifdef HWPRECIP #ifdef HWPRECIP
if (spr->precip) if (spr->precip)
HWR_DrawPrecipitationSprite(spr); HWR_DrawPrecipitationSprite(spr);
@ -4951,8 +5007,15 @@ static void HWR_AddSprites(sector_t *sec)
hoop_limit_dist = (fixed_t)(cv_drawdist_nights.value) << FRACBITS; hoop_limit_dist = (fixed_t)(cv_drawdist_nights.value) << FRACBITS;
for (thing = sec->thinglist; thing; thing = thing->snext) for (thing = sec->thinglist; thing; thing = thing->snext)
{ {
if (R_ThingVisibleWithinDist(thing, limit_dist, hoop_limit_dist)) if (R_ThingWithinDist(thing, limit_dist, hoop_limit_dist))
HWR_ProjectSprite(thing); {
if (R_ThingVisible(thing))
{
HWR_ProjectSprite(thing);
}
HWR_ProjectBoundingBox(thing);
}
} }
#ifdef HWPRECIP #ifdef HWPRECIP
@ -5010,6 +5073,7 @@ static void HWR_ProjectSprite(mobj_t *thing)
#ifdef ROTSPRITE #ifdef ROTSPRITE
patch_t *rotsprite = NULL; patch_t *rotsprite = NULL;
INT32 rollangle = 0; INT32 rollangle = 0;
angle_t spriterotangle = 0;
#endif #endif
// uncapped/interpolation // uncapped/interpolation
@ -5031,7 +5095,7 @@ static void HWR_ProjectSprite(mobj_t *thing)
return; return;
} }
dispoffset = thing->info->dispoffset; dispoffset = thing->dispoffset;
if (R_UsingFrameInterpolation() && !paused) if (R_UsingFrameInterpolation() && !paused)
@ -5177,18 +5241,21 @@ static void HWR_ProjectSprite(mobj_t *thing)
spr_topoffset = spritecachedinfo[lumpoff].topoffset; spr_topoffset = spritecachedinfo[lumpoff].topoffset;
#ifdef ROTSPRITE #ifdef ROTSPRITE
if (thing->rollangle spriterotangle = R_SpriteRotationAngle(&interp);
if (spriterotangle != 0
&& !(splat && !(thing->renderflags & RF_NOSPLATROLLANGLE))) && !(splat && !(thing->renderflags & RF_NOSPLATROLLANGLE)))
{ {
if (papersprite) if (papersprite)
{ {
// a positive rollangle should should pitch papersprites upwards relative to their facing angle // 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 else
{ {
rollangle = R_GetRollAngle(thing->rollangle); rollangle = R_GetRollAngle(spriterotangle);
} }
rotsprite = Patch_GetRotatedSprite(sprframe, (thing->frame & FF_FRAMEMASK), rot, flip, false, sprinfo, rollangle); rotsprite = Patch_GetRotatedSprite(sprframe, (thing->frame & FF_FRAMEMASK), rot, flip, false, sprinfo, rollangle);
if (rotsprite != NULL) if (rotsprite != NULL)
@ -5254,7 +5321,7 @@ static void HWR_ProjectSprite(mobj_t *thing)
} }
groundz = R_GetShadowZ(thing, NULL); 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); shadowheight = FIXED_TO_FLOAT(floordiff);
shadowscale = FIXED_TO_FLOAT(FixedMul(FRACUNIT - floordiff/640, casterinterp.scale)); shadowscale = FIXED_TO_FLOAT(FixedMul(FRACUNIT - floordiff/640, casterinterp.scale));
@ -5306,7 +5373,7 @@ static void HWR_ProjectSprite(mobj_t *thing)
if (vflip) 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); gzt = gz + (FIXED_TO_FLOAT(spr_height) * this_yscale);
} }
else else
@ -5470,6 +5537,7 @@ static void HWR_ProjectSprite(mobj_t *thing)
vis->vflip = vflip; vis->vflip = vflip;
vis->precip = false; vis->precip = false;
vis->bbox = false;
vis->angle = interp.angle; vis->angle = interp.angle;
} }
@ -5592,6 +5660,7 @@ static void HWR_ProjectPrecipitationSprite(precipmobj_t *thing)
vis->gz = vis->gzt - FIXED_TO_FLOAT(spritecachedinfo[lumpoff].height); vis->gz = vis->gzt - FIXED_TO_FLOAT(spritecachedinfo[lumpoff].height);
vis->precip = true; vis->precip = true;
vis->bbox = false;
// okay... this is a hack, but weather isn't networked, so it should be ok // okay... this is a hack, but weather isn't networked, so it should be ok
if (!(thing->precipflags & PCF_THUNK)) if (!(thing->precipflags & PCF_THUNK))
@ -5605,6 +5674,58 @@ static void HWR_ProjectPrecipitationSprite(precipmobj_t *thing)
} }
#endif #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+ // Sky dome rendering, ported from PrBoom+
// ========================================================================== // ==========================================================================
@ -5788,6 +5909,8 @@ static void HWR_DrawSkyBackground(player_t *player)
fixed_t rol = AngleFixed(player->viewrollangle); fixed_t rol = AngleFixed(player->viewrollangle);
dometransform.rollangle = FIXED_TO_FLOAT(rol); dometransform.rollangle = FIXED_TO_FLOAT(rol);
dometransform.roll = true; dometransform.roll = true;
dometransform.rollx = 1.0f;
dometransform.rollz = 0.0f;
} }
dometransform.splitscreen = splitscreen; dometransform.splitscreen = splitscreen;
@ -6066,6 +6189,8 @@ void HWR_RenderSkyboxView(INT32 viewnumber, player_t *player)
fixed_t rol = AngleFixed(player->viewrollangle); fixed_t rol = AngleFixed(player->viewrollangle);
atransform.rollangle = FIXED_TO_FLOAT(rol); atransform.rollangle = FIXED_TO_FLOAT(rol);
atransform.roll = true; atransform.roll = true;
atransform.rollx = 1.0f;
atransform.rollz = 0.0f;
} }
atransform.splitscreen = splitscreen; atransform.splitscreen = splitscreen;
@ -6280,6 +6405,8 @@ void HWR_RenderPlayerView(INT32 viewnumber, player_t *player)
fixed_t rol = AngleFixed(player->viewrollangle); fixed_t rol = AngleFixed(player->viewrollangle);
atransform.rollangle = FIXED_TO_FLOAT(rol); atransform.rollangle = FIXED_TO_FLOAT(rol);
atransform.roll = true; atransform.roll = true;
atransform.rollx = 1.0f;
atransform.rollz = 0.0f;
} }
atransform.splitscreen = splitscreen; atransform.splitscreen = splitscreen;

View file

@ -115,6 +115,7 @@ extern float gl_viewwindowx, gl_basewindowcentery;
// BP: big hack for a test in lighting ref : 1249753487AB // BP: big hack for a test in lighting ref : 1249753487AB
extern fixed_t *hwbbox; extern fixed_t *hwbbox;
extern FTransform atransform; extern FTransform atransform;
extern float gl_viewsin, gl_viewcos;
// Render stats // Render stats

View file

@ -486,7 +486,7 @@ void HWR_InitModels(void)
size_t i; size_t i;
INT32 s; INT32 s;
FILE *f; FILE *f;
char name[24], filename[32]; char name[26], filename[32];
float scale, offset; float scale, offset;
size_t prefixlen; size_t prefixlen;
@ -585,7 +585,7 @@ modelfound:
void HWR_AddPlayerModel(int skin) // For skins that were added after startup void HWR_AddPlayerModel(int skin) // For skins that were added after startup
{ {
FILE *f; FILE *f;
char name[24], filename[32]; char name[26], filename[32];
float scale, offset; float scale, offset;
size_t prefixlen; 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 // 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 // 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 // PLAYERMODELPREFIX is 6 characters long
char name[24], filename[32]; char name[26], filename[32];
float scale, offset; float scale, offset;
if (nomd2s) 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) static boolean HWR_AllowModel(mobj_t *mobj)
{ {
// Signpost overlay. Not needed. // Signpost overlay. Not needed.
if (mobj->state-states == S_PLAY_SIGN) if (mobj->sprite2 == SPR2_SIGN || mobj->state-states == S_PLAY_SIGN)
return false; return false;
// Otherwise, render the model. // 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)); const UINT8 hflip = (UINT8)(!(spr->mobj->mirrored) != !R_ThingHorizontallyFlipped(spr->mobj));
spritedef_t *sprdef; spritedef_t *sprdef;
spriteframe_t *sprframe; spriteframe_t *sprframe;
spriteinfo_t *sprinfo;
angle_t ang;
INT32 mod; INT32 mod;
float finalscale;
interpmobjstate_t interp; interpmobjstate_t interp;
if (R_UsingFrameInterpolation() && !paused) 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 = &md2_playermodels[(skin_t*)spr->mobj->skin-skins];
md2->skin = (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 else
{ {
md2 = &md2_models[spr->mobj->sprite]; 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 // 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? //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 //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 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; p.y = FIXED_TO_FLOAT(interp.y)+md2->offset;
if (flip) if (flip)
p.z = FIXED_TO_FLOAT(interp.z + spr->mobj->height); p.z = FIXED_TO_FLOAT(interp.z + interp.height);
else else
p.z = FIXED_TO_FLOAT(interp.z); 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.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); fixed_t anglef = AngleFixed(R_ModelRotationAngle(&interp));
p.rollangle = FIXED_TO_FLOAT(anglef);
p.roll = true;
// rotation pivot p.rollangle = 0.0f;
p.centerx = FIXED_TO_FLOAT(spr->mobj->radius/2);
p.centery = FIXED_TO_FLOAT(spr->mobj->height/(flip ? -2 : 2));
// rotation axis if (anglef)
if (sprinfo->available) {
p.rotaxis = (UINT8)(sprinfo->pivot[(spr->mobj->frame & FF_FRAMEMASK)].rotaxis); fixed_t camAngleDiff = AngleFixed(viewangle) - FLOAT_TO_FIXED(p.angley); // dumb reconversion back, I know
// for NiGHTS specifically but should work everywhere else p.rollangle = FIXED_TO_FLOAT(anglef);
ang = R_PointToAngle (interp.x, interp.y) - interp.angle; p.roll = true;
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) // rotation pivot
p.rollflip *= -1; 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));
}
} }
p.anglex = 0.0f; #if 0
p.anglez = FIXED_TO_FLOAT(AngleFixed(interp.pitch));
#ifdef USE_FTRANSFORM_ANGLEZ p.anglex = FIXED_TO_FLOAT(AngleFixed(interp.roll));
// Slope rotation from Kart #else
p.anglez = 0.0f; p.anglez = 0.f;
if (spr->mobj->standingslope) p.anglex = 0.f;
{
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);
}
#endif #endif
// SRB2CBTODO: MD2 scaling support
finalscale *= FIXED_TO_FLOAT(spr->mobj->scale);
p.flip = atransform.flip; p.flip = atransform.flip;
#ifdef USE_FTRANSFORM_MIRROR p.mirror = atransform.mirror;
p.mirror = atransform.mirror; // from Kart
#endif
HWD.pfnSetShader(SHADER_MODEL); // model shader 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; return true;

View file

@ -15,7 +15,7 @@
#include "hw_md2load.h" #include "hw_md2load.h"
#include "hw_md3load.h" #include "hw_md3load.h"
#include "hw_md2.h" #include "hw_md2.h"
#include "u_list.h" #include "../u_list.h"
#include <string.h> #include <string.h>
static float PI = (3.1415926535897932384626433832795f); static float PI = (3.1415926535897932384626433832795f);
@ -672,6 +672,9 @@ void GeneratePolygonNormals(model_t *model, int ztag)
for (k = 0; k < mesh->numTriangles; k++) for (k = 0; k < mesh->numTriangles; k++)
{ {
/// TODO: normalize vectors
(void)vertices;
(void)polyNormals;
// Vector::Normal(vertices, polyNormals); // Vector::Normal(vertices, polyNormals);
vertices += 3 * 3; vertices += 3 * 3;
polyNormals++; polyNormals++;

View file

@ -1030,6 +1030,12 @@ EXPORT void HWRAPI(LoadCustomShader) (int number, char *code, size_t size, boole
EXPORT void HWRAPI(SetShader) (int type) EXPORT void HWRAPI(SetShader) (int type)
{ {
#ifdef GL_SHADERS #ifdef GL_SHADERS
if (type == SHADER_NONE)
{
UnSetShader();
return;
}
if (gl_allowshaders != HWD_SHADEROPTION_OFF) if (gl_allowshaders != HWD_SHADEROPTION_OFF)
{ {
gl_shader_t *shader = gl_shaderstate.current; 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); pglVertexPointer(3, GL_FLOAT, sizeof(FOutVector), &pOutVerts[0].x);
pglTexCoordPointer(2, GL_FLOAT, sizeof(FOutVector), &pOutVerts[0].s); 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) if (PolyFlags & PF_RemoveYWrap)
pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); 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)) #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 poly = {0,0,0,0};
static GLRGBAFloat tint = {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 #endif
// Affect input model scaling // Affect input model scaling
scale *= 0.5f; hscale *= 0.5f;
scalex = scale; vscale *= 0.5f;
scaley = scale; scalex = hscale;
scalez = scale; scaley = vscale;
scalez = hscale;
if (duration > 0.0 && tics >= 0.0) // don't interpolate if instantaneous or infinite in length 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_CULL_FACE);
pglEnable(GL_NORMALIZE); pglEnable(GL_NORMALIZE);
#ifdef USE_FTRANSFORM_MIRROR
// flipped is if the object is vertically flipped // flipped is if the object is vertically flipped
// hflipped is if the object is horizontally flipped // hflipped is if the object is horizontally flipped
// pos->flip is if the screen is flipped vertically // 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 else
pglCullFace(GL_BACK); 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 pglPushMatrix(); // should be the same as glLoadIdentity
//Hurdler: now it seems to work //Hurdler: now it seems to work
@ -2809,22 +2804,14 @@ static void DrawModelEx(model_t *model, INT32 frameIndex, float duration, float
if (hflipped) if (hflipped)
scalez = -scalez; scalez = -scalez;
#ifdef USE_FTRANSFORM_ANGLEZ pglRotatef(pos->anglez, 0.0f, 0.0f, -1.0f);
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->anglex, 1.0f, 0.0f, 0.0f); pglRotatef(pos->anglex, 1.0f, 0.0f, 0.0f);
pglRotatef(pos->angley, 0.0f, -1.0f, 0.0f);
if (pos->roll) if (pos->roll)
{ {
float roll = (1.0f * pos->rollflip);
pglTranslatef(pos->centerx, pos->centery, 0); pglTranslatef(pos->centerx, pos->centery, 0);
if (pos->rotaxis == 2) // Z pglRotatef(pos->rollangle, pos->rollx, 0.0f, pos->rollz);
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);
pglTranslatef(-pos->centerx, -pos->centery, 0); 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 // 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) if (stransform)
{ {
used_fov = stransform->fovxangle; used_fov = stransform->fovxangle;
#ifdef USE_FTRANSFORM_MIRROR
// mirroring from Kart
if (stransform->mirror) if (stransform->mirror)
pglScalef(-stransform->scalex, stransform->scaley, -stransform->scalez); pglScalef(-stransform->scalex, stransform->scaley, -stransform->scalez);
else else if (stransform->flip)
#endif
if (stransform->flip)
pglScalef(stransform->scalex, -stransform->scaley, -stransform->scalez); pglScalef(stransform->scalex, -stransform->scaley, -stransform->scalez);
else else
pglScalef(stransform->scalex, stransform->scaley, -stransform->scalez); pglScalef(stransform->scalex, stransform->scaley, -stransform->scalez);

View file

@ -159,7 +159,7 @@ HMS_connect (const char *format, ...)
return NULL; 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); quack_token = curl_easy_escape(curl, cv_masterserver_token.string, 0);
token_length = ( sizeof "?token="-1 )+ strlen(quack_token); token_length = ( sizeof "?token="-1 )+ strlen(quack_token);
@ -216,7 +216,11 @@ HMS_connect (const char *format, ...)
curl_easy_setopt(curl, CURLOPT_URL, url); curl_easy_setopt(curl, CURLOPT_URL, url);
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
curl_easy_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
#ifndef NO_IPV6
if (M_CheckParm("-noipv6"))
#endif
curl_easy_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
curl_easy_setopt(curl, CURLOPT_TIMEOUT, cv_masterserver_timeout.value); curl_easy_setopt(curl, CURLOPT_TIMEOUT, cv_masterserver_timeout.value);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, HMS_on_read); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, HMS_on_read);

View file

@ -2025,7 +2025,7 @@ void HU_Drawer(void)
V_DrawCenteredString(BASEVIDWIDTH/2, 180, V_YELLOWMAP | V_ALLOWLOWERCASE, resynch_text); 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 strength = ((pausedelay - 1 - NEWTICRATE/2)*10)/(NEWTICRATE/3);
INT32 y = hudinfo[HUD_LIVES].y - 13; INT32 y = hudinfo[HUD_LIVES].y - 13;
@ -2862,18 +2862,6 @@ static void HU_DrawRankings(void)
V_DrawCenteredString(256, 16, 0, va("%d", cv_pointlimit.value)); V_DrawCenteredString(256, 16, 0, va("%d", cv_pointlimit.value));
} }
} }
else if (gametyperankings[gametype] == GT_COOP)
{
INT32 totalscore = 0;
for (i = 0; i < MAXPLAYERS; i++)
{
if (playeringame[i])
totalscore += players[i].score;
}
V_DrawCenteredString(256, 8, 0, "TOTAL SCORE");
V_DrawCenteredString(256, 16, 0, va("%u", totalscore));
}
else else
{ {
if (circuitmap) if (circuitmap)
@ -2994,9 +2982,9 @@ static void HU_DrawCoopOverlay(void)
V_DrawSmallScaledPatch(148, 172, 0, tokenicon); V_DrawSmallScaledPatch(148, 172, 0, tokenicon);
} }
if (LUA_HudEnabled(hud_tabemblems) && (!modifiedgame || savemoddata)) if (LUA_HudEnabled(hud_tabemblems))
{ {
V_DrawString(160, 144, 0, va("- %d/%d", M_CountEmblems(), numemblems+numextraemblems)); V_DrawString(160, 144, 0, va("- %d/%d", M_CountEmblems(clientGamedata), numemblems+numextraemblems));
V_DrawScaledPatch(128, 144 - emblemicon->height/4, 0, emblemicon); V_DrawScaledPatch(128, 144 - emblemicon->height/4, 0, emblemicon);
} }
@ -3029,6 +3017,15 @@ static void HU_DrawNetplayCoopOverlay(void)
V_DrawSmallScaledPatch(148, 6, 0, tokenicon); V_DrawSmallScaledPatch(148, 6, 0, tokenicon);
} }
if (G_CoopGametype() && LUA_HudEnabled(hud_tabemblems))
{
V_DrawCenteredString(256, 14, 0, "/");
V_DrawString(256 + 4, 14, 0, va("%d", numemblems + numextraemblems));
V_DrawRightAlignedString(256 - 4, 14, 0, va("%d", M_CountEmblems(clientGamedata)));
V_DrawSmallScaledPatch(256 - (emblemicon->width / 4), 6, 0, emblemicon);
}
if (!LUA_HudEnabled(hud_coopemeralds)) if (!LUA_HudEnabled(hud_coopemeralds))
return; return;

View file

@ -109,6 +109,17 @@ extern boolean (*I_NetCanSend)(void);
*/ */
extern void (*I_NetFreeNodenum)(INT32 nodenum); extern void (*I_NetFreeNodenum)(INT32 nodenum);
/**
\brief split a string into address and port
\param address string to split
\param port double pointer to hold port component (optional)
\return address component
*/
extern char *I_NetSplitAddress(char *address, char **port);
/** \brief open a connection with specified address /** \brief open a connection with specified address
\param address address to connect to \param address address to connect to

View file

@ -40,7 +40,7 @@ extern UINT8 keyboard_started;
\return free memory in the system \return free memory in the system
*/ */
UINT32 I_GetFreeMem(UINT32 *total); size_t I_GetFreeMem(size_t *total);
/** \brief Returns precise time value for performance measurement. The precise /** \brief Returns precise time value for performance measurement. The precise
time should be a monotonically increasing counter, and will wrap. time should be a monotonically increasing counter, and will wrap.
@ -49,6 +49,10 @@ UINT32 I_GetFreeMem(UINT32 *total);
*/ */
precise_t I_GetPreciseTime(void); 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 /** \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. this function for the program's duration MUST return the same value.
*/ */

View file

@ -340,8 +340,14 @@ static inline void I_UPnP_rem(const char *port, const char * servicetype)
static const char *SOCK_AddrToStr(mysockaddr_t *sk) static const char *SOCK_AddrToStr(mysockaddr_t *sk)
{ {
static char s[64]; // 255.255.255.255:65535 or IPv6:65535 static char s[64]; // 255.255.255.255:65535 or
// [ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff]:65535
#ifdef HAVE_NTOP #ifdef HAVE_NTOP
#ifdef HAVE_IPV6
int v6 = (sk->any.sa_family == AF_INET6);
#else
int v6 = 0;
#endif
void *addr; void *addr;
if(sk->any.sa_family == AF_INET) if(sk->any.sa_family == AF_INET)
@ -355,14 +361,21 @@ static const char *SOCK_AddrToStr(mysockaddr_t *sk)
if(addr == NULL) if(addr == NULL)
sprintf(s, "No address"); sprintf(s, "No address");
else if(inet_ntop(sk->any.sa_family, addr, s, sizeof (s)) == NULL) else if(inet_ntop(sk->any.sa_family, addr, &s[v6], sizeof (s) - v6) == NULL)
sprintf(s, "Unknown family type, error #%u", errno); sprintf(s, "Unknown family type, error #%u", errno);
#ifdef HAVE_IPV6 #ifdef HAVE_IPV6
else if(sk->any.sa_family == AF_INET6 && sk->ip6.sin6_port != 0) else if(sk->any.sa_family == AF_INET6)
strcat(s, va(":%d", ntohs(sk->ip6.sin6_port))); {
s[0] = '[';
strcat(s, "]");
if (sk->ip6.sin6_port != 0)
strcat(s, va(":%d", ntohs(sk->ip6.sin6_port)));
}
#endif #endif
else if(sk->any.sa_family == AF_INET && sk->ip4.sin_port != 0) else if(sk->any.sa_family == AF_INET && sk->ip4.sin_port != 0)
strcat(s, va(":%d", ntohs(sk->ip4.sin_port))); strcat(s, va(":%d", ntohs(sk->ip4.sin_port)));
#else #else
if (sk->any.sa_family == AF_INET) if (sk->any.sa_family == AF_INET)
{ {
@ -427,7 +440,7 @@ static boolean SOCK_cmpaddr(mysockaddr_t *a, mysockaddr_t *b, UINT8 mask)
&& (b->ip4.sin_port == 0 || (a->ip4.sin_port == b->ip4.sin_port)); && (b->ip4.sin_port == 0 || (a->ip4.sin_port == b->ip4.sin_port));
#ifdef HAVE_IPV6 #ifdef HAVE_IPV6
else if (b->any.sa_family == AF_INET6) else if (b->any.sa_family == AF_INET6)
return memcmp(&a->ip6.sin6_addr, &b->ip6.sin6_addr, sizeof(b->ip6.sin6_addr)) return !memcmp(&a->ip6.sin6_addr, &b->ip6.sin6_addr, sizeof(b->ip6.sin6_addr))
&& (b->ip6.sin6_port == 0 || (a->ip6.sin6_port == b->ip6.sin6_port)); && (b->ip6.sin6_port == 0 || (a->ip6.sin6_port == b->ip6.sin6_port));
#endif #endif
else else
@ -735,8 +748,7 @@ static SOCKET_TYPE UDP_Bind(int family, struct sockaddr *addr, socklen_t addrlen
unsigned long trueval = true; unsigned long trueval = true;
#endif #endif
mysockaddr_t straddr; mysockaddr_t straddr;
struct sockaddr_in sin; socklen_t len = sizeof(straddr);
socklen_t len = sizeof(sin);
if (s == (SOCKET_TYPE)ERRSOCKET) if (s == (SOCKET_TYPE)ERRSOCKET)
return (SOCKET_TYPE)ERRSOCKET; return (SOCKET_TYPE)ERRSOCKET;
@ -754,14 +766,12 @@ static SOCKET_TYPE UDP_Bind(int family, struct sockaddr *addr, socklen_t addrlen
} }
#endif #endif
straddr.any = *addr; memcpy(&straddr, addr, addrlen);
I_OutputMsg("Binding to %s\n", SOCK_AddrToStr(&straddr)); I_OutputMsg("Binding to %s\n", SOCK_AddrToStr(&straddr));
if (family == AF_INET) if (family == AF_INET)
{ {
mysockaddr_t tmpaddr; if (straddr.ip4.sin_addr.s_addr == htonl(INADDR_ANY))
tmpaddr.any = *addr ;
if (tmpaddr.ip4.sin_addr.s_addr == htonl(INADDR_ANY))
{ {
opt = true; opt = true;
opts = (socklen_t)sizeof(opt); opts = (socklen_t)sizeof(opt);
@ -778,7 +788,7 @@ static SOCKET_TYPE UDP_Bind(int family, struct sockaddr *addr, socklen_t addrlen
#ifdef HAVE_IPV6 #ifdef HAVE_IPV6
else if (family == AF_INET6) else if (family == AF_INET6)
{ {
if (memcmp(addr, &in6addr_any, sizeof(in6addr_any)) == 0) //IN6_ARE_ADDR_EQUAL if (memcmp(&straddr.ip6.sin6_addr, &in6addr_any, sizeof(in6addr_any)) == 0) //IN6_ARE_ADDR_EQUAL
{ {
opt = true; opt = true;
opts = (socklen_t)sizeof(opt); opts = (socklen_t)sizeof(opt);
@ -788,7 +798,7 @@ static SOCKET_TYPE UDP_Bind(int family, struct sockaddr *addr, socklen_t addrlen
// make it IPv6 ony // make it IPv6 ony
opt = true; opt = true;
opts = (socklen_t)sizeof(opt); opts = (socklen_t)sizeof(opt);
if (setsockopt(s, SOL_SOCKET, IPV6_V6ONLY, (char *)&opt, opts)) if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&opt, opts))
{ {
CONS_Alert(CONS_WARNING, M_GetText("Could not limit IPv6 bind\n")); // I do not care anymore CONS_Alert(CONS_WARNING, M_GetText("Could not limit IPv6 bind\n")); // I do not care anymore
} }
@ -830,10 +840,17 @@ static SOCKET_TYPE UDP_Bind(int family, struct sockaddr *addr, socklen_t addrlen
CONS_Printf(M_GetText("Network system buffer set to: %dKb\n"), opt>>10); CONS_Printf(M_GetText("Network system buffer set to: %dKb\n"), opt>>10);
} }
if (getsockname(s, (struct sockaddr *)&sin, &len) == -1) if (getsockname(s, &straddr.any, &len) == -1)
CONS_Alert(CONS_WARNING, M_GetText("Failed to get port number\n")); CONS_Alert(CONS_WARNING, M_GetText("Failed to get port number\n"));
else else
current_port = (UINT16)ntohs(sin.sin_port); {
if (family == AF_INET)
current_port = (UINT16)ntohs(straddr.ip4.sin_port);
#ifdef HAVE_IPV6
else if (family == AF_INET6)
current_port = (UINT16)ntohs(straddr.ip6.sin6_port);
#endif
}
return s; return s;
} }
@ -844,7 +861,7 @@ static boolean UDP_Socket(void)
struct my_addrinfo *ai, *runp, hints; struct my_addrinfo *ai, *runp, hints;
int gaie; int gaie;
#ifdef HAVE_IPV6 #ifdef HAVE_IPV6
const INT32 b_ipv6 = M_CheckParm("-ipv6"); const INT32 b_ipv6 = !M_CheckParm("-noipv6");
#endif #endif
const char *serv; const char *serv;
@ -1156,6 +1173,7 @@ static SINT8 SOCK_NetMakeNodewPort(const char *address, const char *port)
SINT8 newnode = -1; SINT8 newnode = -1;
struct my_addrinfo *ai = NULL, *runp, hints; struct my_addrinfo *ai = NULL, *runp, hints;
int gaie; int gaie;
size_t i;
if (!port || !port[0]) if (!port || !port[0])
port = DEFAULTPORT; port = DEFAULTPORT;
@ -1183,13 +1201,24 @@ static SINT8 SOCK_NetMakeNodewPort(const char *address, const char *port)
while (runp != NULL) while (runp != NULL)
{ {
// find ip of the server // test ip address of server
if (sendto(mysockets[0], NULL, 0, 0, runp->ai_addr, runp->ai_addrlen) == 0) for (i = 0; i < mysocketses; ++i)
{ {
memcpy(&clientaddress[newnode], runp->ai_addr, runp->ai_addrlen); /* sendto tests that there is a network to this
break; address */
if (runp->ai_addr->sa_family == myfamily[i] &&
sendto(mysockets[i], NULL, 0, 0,
runp->ai_addr, runp->ai_addrlen) == 0)
{
memcpy(&clientaddress[newnode], runp->ai_addr, runp->ai_addrlen);
break;
}
} }
runp = runp->ai_next;
if (i < mysocketses)
runp = runp->ai_next;
else
break;
} }
I_freeaddrinfo(ai); I_freeaddrinfo(ai);
return newnode; return newnode;

View file

@ -7194,7 +7194,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
sfx_cgot, // deathsound sfx_cgot, // deathsound
EMERALD1, // speed EMERALD1, // speed
16*FRACUNIT, // radius 16*FRACUNIT, // radius
32*FRACUNIT, // height 24*FRACUNIT, // height
0, // display offset 0, // display offset
16, // mass 16, // mass
0, // damage 0, // damage
@ -7220,7 +7220,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
sfx_cgot, // deathsound sfx_cgot, // deathsound
EMERALD2, // speed EMERALD2, // speed
16*FRACUNIT, // radius 16*FRACUNIT, // radius
32*FRACUNIT, // height 24*FRACUNIT, // height
0, // display offset 0, // display offset
16, // mass 16, // mass
0, // damage 0, // damage
@ -7246,7 +7246,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
sfx_cgot, // deathsound sfx_cgot, // deathsound
EMERALD3, // speed EMERALD3, // speed
16*FRACUNIT, // radius 16*FRACUNIT, // radius
32*FRACUNIT, // height 24*FRACUNIT, // height
0, // display offset 0, // display offset
16, // mass 16, // mass
0, // damage 0, // damage
@ -7272,7 +7272,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
sfx_cgot, // deathsound sfx_cgot, // deathsound
EMERALD4, // speed EMERALD4, // speed
16*FRACUNIT, // radius 16*FRACUNIT, // radius
32*FRACUNIT, // height 24*FRACUNIT, // height
0, // display offset 0, // display offset
16, // mass 16, // mass
0, // damage 0, // damage
@ -7298,7 +7298,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
sfx_cgot, // deathsound sfx_cgot, // deathsound
EMERALD5, // speed EMERALD5, // speed
16*FRACUNIT, // radius 16*FRACUNIT, // radius
32*FRACUNIT, // height 24*FRACUNIT, // height
0, // display offset 0, // display offset
16, // mass 16, // mass
0, // damage 0, // damage
@ -7324,7 +7324,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
sfx_cgot, // deathsound sfx_cgot, // deathsound
EMERALD6, // speed EMERALD6, // speed
16*FRACUNIT, // radius 16*FRACUNIT, // radius
32*FRACUNIT, // height 24*FRACUNIT, // height
0, // display offset 0, // display offset
16, // mass 16, // mass
0, // damage 0, // damage
@ -7350,7 +7350,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
sfx_cgot, // deathsound sfx_cgot, // deathsound
EMERALD7, // speed EMERALD7, // speed
16*FRACUNIT, // radius 16*FRACUNIT, // radius
32*FRACUNIT, // height 24*FRACUNIT, // height
0, // display offset 0, // display offset
16, // mass 16, // mass
0, // damage 0, // damage
@ -18344,7 +18344,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
S_NULL, // xdeathstate S_NULL, // xdeathstate
sfx_itemup, // deathsound sfx_itemup, // deathsound
60*FRACUNIT, // speed 60*FRACUNIT, // speed
24*FRACUNIT, // radius 16*FRACUNIT, // radius
24*FRACUNIT, // height 24*FRACUNIT, // height
0, // display offset 0, // display offset
pw_bouncering, // mass pw_bouncering, // mass
@ -18371,7 +18371,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
S_NULL, // xdeathstate S_NULL, // xdeathstate
sfx_itemup, // deathsound sfx_itemup, // deathsound
60*FRACUNIT, // speed 60*FRACUNIT, // speed
24*FRACUNIT, // radius 16*FRACUNIT, // radius
24*FRACUNIT, // height 24*FRACUNIT, // height
0, // display offset 0, // display offset
pw_railring, // mass pw_railring, // mass
@ -18425,7 +18425,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
S_NULL, // xdeathstate S_NULL, // xdeathstate
sfx_itemup, // deathsound sfx_itemup, // deathsound
60*FRACUNIT, // speed 60*FRACUNIT, // speed
24*FRACUNIT, // radius 16*FRACUNIT, // radius
24*FRACUNIT, // height 24*FRACUNIT, // height
0, // display offset 0, // display offset
pw_automaticring, // mass pw_automaticring, // mass
@ -18452,7 +18452,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
S_NULL, // xdeathstate S_NULL, // xdeathstate
sfx_itemup, // deathsound sfx_itemup, // deathsound
60*FRACUNIT, // speed 60*FRACUNIT, // speed
24*FRACUNIT, // radius 16*FRACUNIT, // radius
24*FRACUNIT, // height 24*FRACUNIT, // height
0, // display offset 0, // display offset
pw_explosionring, // mass pw_explosionring, // mass
@ -18479,7 +18479,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
S_NULL, // xdeathstate S_NULL, // xdeathstate
sfx_itemup, // deathsound sfx_itemup, // deathsound
60*FRACUNIT, // speed 60*FRACUNIT, // speed
24*FRACUNIT, // radius 16*FRACUNIT, // radius
24*FRACUNIT, // height 24*FRACUNIT, // height
0, // display offset 0, // display offset
pw_scatterring, // mass pw_scatterring, // mass
@ -18506,7 +18506,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
S_NULL, // xdeathstate S_NULL, // xdeathstate
sfx_itemup, // deathsound sfx_itemup, // deathsound
60*FRACUNIT, // speed 60*FRACUNIT, // speed
24*FRACUNIT, // radius 16*FRACUNIT, // radius
24*FRACUNIT, // height 24*FRACUNIT, // height
0, // display offset 0, // display offset
pw_grenadering, // mass pw_grenadering, // mass
@ -18535,7 +18535,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
sfx_ncitem, // deathsound sfx_ncitem, // deathsound
60*FRACUNIT, // speed 60*FRACUNIT, // speed
24*FRACUNIT, // radius 24*FRACUNIT, // radius
24*FRACUNIT, // height 40*FRACUNIT, // height
0, // display offset 0, // display offset
pw_bouncering, // mass pw_bouncering, // mass
2*TICRATE, // damage 2*TICRATE, // damage
@ -18562,7 +18562,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
sfx_ncitem, // deathsound sfx_ncitem, // deathsound
60*FRACUNIT, // speed 60*FRACUNIT, // speed
24*FRACUNIT, // radius 24*FRACUNIT, // radius
24*FRACUNIT, // height 40*FRACUNIT, // height
0, // display offset 0, // display offset
pw_railring, // mass pw_railring, // mass
2*TICRATE, // damage 2*TICRATE, // damage
@ -18589,7 +18589,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
sfx_ncitem, // deathsound sfx_ncitem, // deathsound
60*FRACUNIT, // speed 60*FRACUNIT, // speed
24*FRACUNIT, // radius 24*FRACUNIT, // radius
24*FRACUNIT, // height 40*FRACUNIT, // height
0, // display offset 0, // display offset
pw_automaticring, // mass pw_automaticring, // mass
2*TICRATE, // damage 2*TICRATE, // damage
@ -18616,7 +18616,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
sfx_ncitem, // deathsound sfx_ncitem, // deathsound
60*FRACUNIT, // speed 60*FRACUNIT, // speed
24*FRACUNIT, // radius 24*FRACUNIT, // radius
24*FRACUNIT, // height 40*FRACUNIT, // height
0, // display offset 0, // display offset
pw_explosionring, // mass pw_explosionring, // mass
2*TICRATE, // damage 2*TICRATE, // damage
@ -18643,7 +18643,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
sfx_ncitem, // deathsound sfx_ncitem, // deathsound
60*FRACUNIT, // speed 60*FRACUNIT, // speed
24*FRACUNIT, // radius 24*FRACUNIT, // radius
24*FRACUNIT, // height 40*FRACUNIT, // height
0, // display offset 0, // display offset
pw_scatterring, // mass pw_scatterring, // mass
2*TICRATE, // damage 2*TICRATE, // damage
@ -18670,7 +18670,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
sfx_ncitem, // deathsound sfx_ncitem, // deathsound
60*FRACUNIT, // speed 60*FRACUNIT, // speed
24*FRACUNIT, // radius 24*FRACUNIT, // radius
24*FRACUNIT, // height 40*FRACUNIT, // height
0, // display offset 0, // display offset
pw_grenadering, // mass pw_grenadering, // mass
2*TICRATE, // damage 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 {"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 // 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 {"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 {"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 {"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
{"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 {"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
{"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 {"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
{"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 {"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
{"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 {"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
{"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 {"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
{"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 {"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
{"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 {"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
{"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 {"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
{"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 {"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) // 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 {"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 {"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 {"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 {"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 {"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 {"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 {"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 {"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 {"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 {"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 {"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 {"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 {"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 {"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 {"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 {"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 {"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 {"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 {"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 {"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 {"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 {"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 {"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 {"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 {"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 {"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 {"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 {"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 {"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 {"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 {"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 {"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 {"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 {"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 {"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 {"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 {"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 {"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 {"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 {"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 {"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
{"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 {"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

View file

@ -18,6 +18,7 @@
#include "d_think.h" #include "d_think.h"
#include "sounds.h" #include "sounds.h"
#include "m_fixed.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! // deh_tables.c now has lists for the more named enums! PLEASE keep them up to date!
// For great modding!! // For great modding!!
@ -151,6 +152,7 @@ enum actionnum
A_BOSS3TAKEDAMAGE, A_BOSS3TAKEDAMAGE,
A_BOSS3PATH, A_BOSS3PATH,
A_BOSS3SHOCKTHINK, A_BOSS3SHOCKTHINK,
A_SHOCKWAVE,
A_LINEDEFEXECUTE, A_LINEDEFEXECUTE,
A_LINEDEFEXECUTEFROMARG, A_LINEDEFEXECUTEFROMARG,
A_PLAYSEESOUND, A_PLAYSEESOUND,
@ -415,6 +417,7 @@ void A_Boss1Spikeballs();
void A_Boss3TakeDamage(); void A_Boss3TakeDamage();
void A_Boss3Path(); void A_Boss3Path();
void A_Boss3ShockThink(); void A_Boss3ShockThink();
void A_Shockwave();
void A_LinedefExecute(); void A_LinedefExecute();
void A_LinedefExecuteFromArg(); void A_LinedefExecuteFromArg();
void A_PlaySeeSound(); void A_PlaySeeSound();
@ -564,7 +567,7 @@ void A_DragonWing();
void A_DragonSegment(); void A_DragonSegment();
void A_ChangeHeight(); 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 // ratio of states to sprites to mobj types is roughly 6 : 1 : 1
#define NUMMOBJFREESLOTS 512 #define NUMMOBJFREESLOTS 512

View file

@ -581,6 +581,11 @@ static inline void libdivide_u128_shift(uint64_t *u1, uint64_t *u0, int32_t sign
////////// UINT32 ////////// 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) { static inline struct libdivide_u32_t libdivide_internal_u32_gen(uint32_t d, int branchfree) {
struct libdivide_u32_t result; struct libdivide_u32_t result;
uint32_t floor_log_2_d; uint32_t floor_log_2_d;
@ -647,6 +652,10 @@ struct libdivide_u32_t libdivide_u32_gen(uint32_t d) {
return ret; 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) { uint32_t libdivide_u32_do(uint32_t numer, const struct libdivide_u32_t *denom) {
uint8_t more = denom->more; uint8_t more = denom->more;
if (!denom->magic) { if (!denom->magic) {

Some files were not shown because too many files have changed in this diff Show more