Merge branch 'next' into lua-colorlib

This commit is contained in:
Alam Ed Arias 2023-10-23 14:49:26 -04:00
commit befd9596df
137 changed files with 8908 additions and 8034 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 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

1
.gitignore vendored
View file

@ -23,3 +23,4 @@ Win32_LIB_ASM_Release
/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

@ -1,4 +1,4 @@
version: 2.2.11.{branch}-{build} version: 2.2.13.{branch}-{build}
os: MinGW os: MinGW
environment: environment:

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

View file

@ -4367,7 +4367,6 @@ thingtypes
{ {
color = 14; // Yellow color = 14; // Yellow
title = "Rings and Weapon Panels"; title = "Rings and Weapon Panels";
width = 24;
height = 24; height = 24;
flags8height = 24; flags8height = 24;
flags8text = "[8] Float"; flags8text = "[8] Float";
@ -4377,7 +4376,6 @@ thingtypes
{ {
title = "Ring"; title = "Ring";
sprite = "RINGA0"; sprite = "RINGA0";
width = 16;
} }
301 301
{ {
@ -4393,6 +4391,7 @@ thingtypes
{ {
title = "Infinity Ring"; title = "Infinity Ring";
sprite = "RNGIA0"; sprite = "RNGIA0";
width = 24;
} }
304 304
{ {
@ -4418,43 +4417,53 @@ thingtypes
{ {
title = "CTF Team Ring (Red)"; title = "CTF Team Ring (Red)";
sprite = "internal:TRNGA0R"; sprite = "internal:TRNGA0R";
width = 16;
} }
309 309
{ {
title = "CTF Team Ring (Blue)"; title = "CTF Team Ring (Blue)";
sprite = "internal:TRNGA0B"; sprite = "internal:TRNGA0B";
width = 16;
} }
330 330
{ {
title = "Bounce Ring Panel"; title = "Bounce Ring Panel";
sprite = "PIKBA0"; sprite = "PIKBA0";
width = 24;
height = 40;
} }
331 331
{ {
title = "Rail Ring Panel"; title = "Rail Ring Panel";
sprite = "PIKRA0"; sprite = "PIKRA0";
width = 24;
height = 40;
} }
332 332
{ {
title = "Automatic Ring Panel"; title = "Automatic Ring Panel";
sprite = "PIKAA0"; sprite = "PIKAA0";
width = 24;
height = 40;
} }
333 333
{ {
title = "Explosion Ring Panel"; title = "Explosion Ring Panel";
sprite = "PIKEA0"; sprite = "PIKEA0";
width = 24;
height = 40;
} }
334 334
{ {
title = "Scatter Ring Panel"; title = "Scatter Ring Panel";
sprite = "PIKSA0"; sprite = "PIKSA0";
width = 24;
height = 40;
} }
335 335
{ {
title = "Grenade Ring Panel"; title = "Grenade Ring Panel";
sprite = "PIKGA0"; sprite = "PIKGA0";
width = 24;
height = 40;
} }
} }
@ -4463,7 +4472,7 @@ thingtypes
color = 10; // Light Green color = 10; // Light Green
title = "Other Collectibles"; title = "Other Collectibles";
width = 16; width = 16;
height = 32; height = 24;
sort = 1; sort = 1;
sprite = "CEMGA0"; sprite = "CEMGA0";
@ -4529,6 +4538,7 @@ thingtypes
{ {
title = "Emerald Hunt Location"; title = "Emerald Hunt Location";
sprite = "SHRDA0"; sprite = "SHRDA0";
height = 32;
flags8height = 24; flags8height = 24;
flags8text = "[8] Float"; flags8text = "[8] Float";
} }

View file

@ -1185,7 +1185,7 @@ udmf
{ {
color = 14; // Yellow color = 14; // Yellow
title = "Rings and Weapon Panels"; title = "Rings and Weapon Panels";
width = 24; width = 16;
height = 24; height = 24;
sprite = "RINGA0"; sprite = "RINGA0";
@ -1193,7 +1193,6 @@ udmf
{ {
title = "Ring"; title = "Ring";
sprite = "RINGA0"; sprite = "RINGA0";
width = 16;
arg0 arg0
{ {
title = "Float?"; title = "Float?";
@ -1227,6 +1226,7 @@ udmf
{ {
title = "Infinity Ring"; title = "Infinity Ring";
sprite = "RNGIA0"; sprite = "RNGIA0";
width = 24;
arg0 arg0
{ {
title = "Float?"; title = "Float?";
@ -1282,7 +1282,6 @@ udmf
{ {
title = "CTF Team Ring (Red)"; title = "CTF Team Ring (Red)";
sprite = "internal:TRNGA0R"; sprite = "internal:TRNGA0R";
width = 16;
arg0 arg0
{ {
title = "Float?"; title = "Float?";
@ -1294,7 +1293,6 @@ udmf
{ {
title = "CTF Team Ring (Blue)"; title = "CTF Team Ring (Blue)";
sprite = "internal:TRNGA0B"; sprite = "internal:TRNGA0B";
width = 16;
arg0 arg0
{ {
title = "Float?"; title = "Float?";
@ -1306,6 +1304,8 @@ udmf
{ {
title = "Bounce Ring Panel"; title = "Bounce Ring Panel";
sprite = "PIKBA0"; sprite = "PIKBA0";
width = 24;
height = 40;
arg0 arg0
{ {
title = "Float?"; title = "Float?";
@ -1317,6 +1317,8 @@ udmf
{ {
title = "Rail Ring Panel"; title = "Rail Ring Panel";
sprite = "PIKRA0"; sprite = "PIKRA0";
width = 24;
height = 40;
arg0 arg0
{ {
title = "Float?"; title = "Float?";
@ -1328,6 +1330,8 @@ udmf
{ {
title = "Automatic Ring Panel"; title = "Automatic Ring Panel";
sprite = "PIKAA0"; sprite = "PIKAA0";
width = 24;
height = 40;
arg0 arg0
{ {
title = "Float?"; title = "Float?";
@ -1339,6 +1343,8 @@ udmf
{ {
title = "Explosion Ring Panel"; title = "Explosion Ring Panel";
sprite = "PIKEA0"; sprite = "PIKEA0";
width = 24;
height = 40;
arg0 arg0
{ {
title = "Float?"; title = "Float?";
@ -1350,6 +1356,8 @@ udmf
{ {
title = "Scatter Ring Panel"; title = "Scatter Ring Panel";
sprite = "PIKSA0"; sprite = "PIKSA0";
width = 24;
height = 40;
arg0 arg0
{ {
title = "Float?"; title = "Float?";
@ -1361,6 +1369,8 @@ udmf
{ {
title = "Grenade Ring Panel"; title = "Grenade Ring Panel";
sprite = "PIKGA0"; sprite = "PIKGA0";
width = 24;
height = 40;
arg0 arg0
{ {
title = "Float?"; title = "Float?";
@ -1375,7 +1385,7 @@ udmf
color = 10; // Light_Green color = 10; // Light_Green
title = "Other Collectibles"; title = "Other Collectibles";
width = 16; width = 16;
height = 32; height = 24;
sort = 1; sort = 1;
sprite = "CEMGA0"; sprite = "CEMGA0";
@ -1445,6 +1455,7 @@ udmf
{ {
title = "Emerald Hunt Location"; title = "Emerald Hunt Location";
sprite = "SHRDA0"; sprite = "SHRDA0";
height = 32;
arg0 arg0
{ {
title = "Float?"; title = "Float?";

View file

@ -8,11 +8,7 @@ LOCAL_SRC_FILES := am_map.c \
command.c \ command.c \
comptime.c \ comptime.c \
console.c \ console.c \
d_clisrv.c \
d_main.c \ d_main.c \
d_net.c \
d_netcmd.c \
d_netfil.c \
dehacked.c \ dehacked.c \
f_finale.c \ f_finale.c \
f_wipe.c \ f_wipe.c \
@ -20,7 +16,6 @@ LOCAL_SRC_FILES := am_map.c \
g_game.c \ g_game.c \
g_input.c \ g_input.c \
hu_stuff.c \ hu_stuff.c \
i_tcp.c \
info.c \ info.c \
lzf.c \ lzf.c \
m_argv.c \ m_argv.c \
@ -32,7 +27,6 @@ LOCAL_SRC_FILES := am_map.c \
m_queue.c \ m_queue.c \
m_random.c \ m_random.c \
md5.c \ md5.c \
mserv.c \
p_ceilng.c \ p_ceilng.c \
p_enemy.c \ p_enemy.c \
p_fab.c \ p_fab.c \
@ -61,6 +55,7 @@ LOCAL_SRC_FILES := am_map.c \
r_things.c \ r_things.c \
s_sound.c \ s_sound.c \
screen.c \ screen.c \
snake.c \
sounds.c \ sounds.c \
st_stuff.c \ st_stuff.c \
string.c \ string.c \

View file

@ -6,10 +6,6 @@ add_executable(SRB2SDL2 MACOSX_BUNDLE WIN32
config.h.in config.h.in
string.c string.c
d_main.c d_main.c
d_clisrv.c
d_net.c
d_netfil.c
d_netcmd.c
dehacked.c dehacked.c
deh_soc.c deh_soc.c
deh_lua.c deh_lua.c
@ -83,12 +79,10 @@ add_executable(SRB2SDL2 MACOSX_BUNDLE WIN32
sounds.c sounds.c
w_wad.c w_wad.c
filesrch.c filesrch.c
mserv.c
http-mserv.c
i_tcp.c
lzf.c lzf.c
b_bot.c b_bot.c
u_list.c u_list.c
snake.c
lua_script.c lua_script.c
lua_baselib.c lua_baselib.c
lua_mathlib.c lua_mathlib.c
@ -150,6 +144,7 @@ set(SRB2_CONFIG_DEV_BUILD OFF CACHE BOOL
"Compile a development build of SRB2.") "Compile a development build of SRB2.")
add_subdirectory(blua) add_subdirectory(blua)
add_subdirectory(netcode)
# OS macros # OS macros
if (UNIX) if (UNIX)

View file

@ -62,7 +62,6 @@
# #
# Netplay incompatible # Netplay incompatible
# -------------------- # --------------------
# NONET=1 - Disable online capability.
# NOMD5=1 - Disable MD5 checksum (validation tool). # NOMD5=1 - Disable MD5 checksum (validation tool).
# NOPOSTPROCESSING=1 - ? # NOPOSTPROCESSING=1 - ?
# MOBJCONSISTANCY=1 - ?? # MOBJCONSISTANCY=1 - ??
@ -141,9 +140,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)
GZIP?=gzip GZIP?=gzip
GZIP_OPTS?=-9 -f -n GZIP_OPTS?=-9 -f -n
@ -187,6 +186,7 @@ objdir:=$(makedir)/objs
sources+=\ sources+=\
$(call List,Sourcefile)\ $(call List,Sourcefile)\
$(call List,blua/Sourcefile)\ $(call List,blua/Sourcefile)\
$(call List,netcode/Sourcefile)\
depends:=$(basename $(filter %.c %.s,$(sources))) depends:=$(basename $(filter %.c %.s,$(sources)))
objects:=$(basename $(filter %.c %.s %.nas,$(sources))) objects:=$(basename $(filter %.c %.s %.nas,$(sources)))
@ -392,4 +392,4 @@ else
@: @:
endif endif
$(warning The handwritten GNU Makefile for SRB2 is deprecated, and may be removed in the future. Please consider switching to CMake.) #$(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,68 +1,66 @@
# #
# Makefile for feature flags. # Makefile for feature flags.
# #
passthru_opts+=\ passthru_opts+=\
NONET NO_IPV6 NOHW NOMD5 NOPOSTPROCESSING\ 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 NOMD5 ifndef NOMD5
sources+=md5.c sources+=md5.c
endif endif
ifndef NOZLIB ifndef NOZLIB
ifndef NOPNG ifndef NOPNG
ifdef PNG_PKGCONFIG ifdef PNG_PKGCONFIG
$(eval $(call Use_pkg_config,PNG_PKGCONFIG)) $(eval $(call Use_pkg_config,PNG_PKGCONFIG))
else else
PNG_CONFIG?=$(call Prefix,libpng-config) PNG_CONFIG?=$(call Prefix,libpng-config)
$(eval $(call Configure,PNG,$(PNG_CONFIG) \ $(eval $(call Configure,PNG,$(PNG_CONFIG) \
$(if $(PNG_STATIC),--static),,--ldflags)) $(if $(PNG_STATIC),--static),,--ldflags))
endif endif
ifdef LINUX ifdef LINUX
opts+=-D_LARGEFILE64_SOURCE opts+=-D_LARGEFILE64_SOURCE
endif endif
opts+=-DHAVE_PNG opts+=-DHAVE_PNG
sources+=apng.c sources+=apng.c
endif endif
endif endif
ifndef NONET ifndef NOCURL
ifndef NOCURL CURLCONFIG?=curl-config
CURLCONFIG?=curl-config $(eval $(call Configure,CURL,$(CURLCONFIG)))
$(eval $(call Configure,CURL,$(CURLCONFIG))) opts+=-DHAVE_CURL
opts+=-DHAVE_CURL endif
endif
endif ifdef HAVE_MINIUPNPC
libs+=-lminiupnpc
ifdef HAVE_MINIUPNPC endif
libs+=-lminiupnpc
endif # (Valgrind is a memory debugger.)
ifdef VALGRIND
# (Valgrind is a memory debugger.) VALGRIND_PKGCONFIG?=valgrind
ifdef VALGRIND $(eval $(call Use_pkg_config,VALGRIND))
VALGRIND_PKGCONFIG?=valgrind ZDEBUG=1
$(eval $(call Use_pkg_config,VALGRIND)) opts+=-DHAVE_VALGRIND
ZDEBUG=1 endif
opts+=-DHAVE_VALGRIND
endif default_packages:=\
GME/libgme/LIBGME\
default_packages:=\ OPENMPT/libopenmpt/LIBOPENMPT\
GME/libgme/LIBGME\ ZLIB/zlib\
OPENMPT/libopenmpt/LIBOPENMPT\
ZLIB/zlib\ $(foreach p,$(default_packages),\
$(eval $(call Check_pkg_config,$(p))))
$(foreach p,$(default_packages),\
$(eval $(call Check_pkg_config,$(p))))

View file

@ -25,7 +25,7 @@ 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

View file

@ -33,12 +33,10 @@ libs+=-lws2_32
endif endif
endif endif
ifndef NONET
ifndef MINGW64 # miniupnc is broken with MINGW64 ifndef MINGW64 # miniupnc is broken with MINGW64
opts+=-I../libs -DSTATIC_MINIUPNPC opts+=-I../libs -DSTATIC_MINIUPNPC
libs+=-L../libs/miniupnpc/mingw$(32) -lws2_32 -liphlpapi libs+=-L../libs/miniupnpc/mingw$(32) -lws2_32 -liphlpapi
endif endif
endif
ifndef MINGW64 ifndef MINGW64
32=32 32=32

View file

@ -1,9 +1,5 @@
string.c string.c
d_main.c d_main.c
d_clisrv.c
d_net.c
d_netfil.c
d_netcmd.c
dehacked.c dehacked.c
deh_soc.c deh_soc.c
deh_lua.c deh_lua.c
@ -77,12 +73,10 @@ s_sound.c
sounds.c sounds.c
w_wad.c w_wad.c
filesrch.c filesrch.c
mserv.c
http-mserv.c
i_tcp.c
lzf.c lzf.c
b_bot.c b_bot.c
u_list.c u_list.c
snake.c
lua_script.c lua_script.c
lua_baselib.c lua_baselib.c
lua_mathlib.c lua_mathlib.c

View file

@ -1071,7 +1071,6 @@ static inline void AM_drawPlayers(void)
return; return;
} }
// multiplayer (how??)
for (i = 0; i < MAXPLAYERS; i++) for (i = 0; i < MAXPLAYERS; i++)
{ {
if (!playeringame[i] || players[i].spectator) if (!playeringame[i] || players[i].spectator)

View file

@ -1,4 +1,4 @@
#include "../i_net.h" #include "../netcode/i_net.h"
boolean I_InitNetwork(void) boolean I_InitNetwork(void)
{ {

View file

@ -19,7 +19,8 @@
#include "lualib.h" #include "lualib.h"
#include "../i_system.h" #include "../i_system.h"
#include "../g_game.h" #include "../g_game.h"
#include "../d_netfil.h" #include "../netcode/d_netfil.h"
#include "../netcode/net_command.h"
#include "../lua_libs.h" #include "../lua_libs.h"
#include "../byteptr.h" #include "../byteptr.h"
#include "../lua_script.h" #include "../lua_script.h"

View file

@ -28,11 +28,12 @@
#include "byteptr.h" #include "byteptr.h"
#include "p_saveg.h" #include "p_saveg.h"
#include "g_game.h" // for player_names #include "g_game.h" // for player_names
#include "d_netcmd.h" #include "netcode/d_netcmd.h"
#include "netcode/net_command.h"
#include "hu_stuff.h" #include "hu_stuff.h"
#include "p_setup.h" #include "p_setup.h"
#include "lua_script.h" #include "lua_script.h"
#include "d_netfil.h" // findfile #include "netcode/d_netfil.h" // findfile
#include "r_data.h" // Color_cons_t #include "r_data.h" // Color_cons_t
#include "d_main.h" // D_IsPathAllowed #include "d_main.h" // D_IsPathAllowed

View file

@ -38,12 +38,14 @@
* 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 / 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 "1c8adf8d079ecb87d00081f158acf3c7" #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 "2e69558bce3b9610624549a75e29e19b" #define ASSET_HASH_PATCH_PK3 "3c7b73f34af7e9a7bceb2d5260f76172"
#endif #endif
#endif #endif

File diff suppressed because it is too large Load diff

View file

@ -34,7 +34,7 @@
#include "doomdef.h" #include "doomdef.h"
#include "am_map.h" #include "am_map.h"
#include "console.h" #include "console.h"
#include "d_net.h" #include "netcode/d_net.h"
#include "f_finale.h" #include "f_finale.h"
#include "g_game.h" #include "g_game.h"
#include "hu_stuff.h" #include "hu_stuff.h"
@ -56,11 +56,11 @@
#include "w_wad.h" #include "w_wad.h"
#include "z_zone.h" #include "z_zone.h"
#include "d_main.h" #include "d_main.h"
#include "d_netfil.h" #include "netcode/d_netfil.h"
#include "m_cheat.h" #include "m_cheat.h"
#include "y_inter.h" #include "y_inter.h"
#include "p_local.h" // chasecam #include "p_local.h" // chasecam
#include "mserv.h" // ms_RoomId #include "netcode/mserv.h" // ms_RoomId
#include "m_misc.h" // screenshot functionality #include "m_misc.h" // screenshot functionality
#include "deh_tables.h" // Dehacked list test #include "deh_tables.h" // Dehacked list test
#include "m_cond.h" // condition initialization #include "m_cond.h" // condition initialization
@ -981,6 +981,7 @@ void D_StartTitle(void)
emeralds = 0; emeralds = 0;
memset(&luabanks, 0, sizeof(luabanks)); memset(&luabanks, 0, sizeof(luabanks));
lastmaploaded = 0; lastmaploaded = 0;
pickedchar = R_SkinAvailable(cv_defaultskin.string);
// In case someone exits out at the same time they start a time attack run, // In case someone exits out at the same time they start a time attack run,
// reset modeattacking // reset modeattacking
@ -1626,6 +1627,8 @@ void D_SRB2Main(void)
autostart = true; autostart = true;
} }
pickedchar = R_SkinAvailable(cv_defaultskin.string);
// user settings come before "+" parameters. // user settings come before "+" parameters.
if (dedicated) if (dedicated)
COM_ImmedExecute(va("exec \"%s"PATHSEP"adedserv.cfg\"\n", srb2home)); COM_ImmedExecute(va("exec \"%s"PATHSEP"adedserv.cfg\"\n", srb2home));
@ -1737,14 +1740,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, serverGamedata))
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);
} }
} }

View file

@ -277,8 +277,8 @@ static int ScanConstants(lua_State *L, boolean mathlib, const char *word)
} }
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])) {
CacheAndPushConstant(L, word, ((lua_Integer)1<<i)); CacheAndPushConstant(L, word, ((lua_Integer)1<<i));
return 1; return 1;
} }

View file

@ -34,7 +34,7 @@
#include "r_sky.h" #include "r_sky.h"
#include "fastcmp.h" #include "fastcmp.h"
#include "lua_script.h" // Reluctantly included for LUA_EvalMath #include "lua_script.h" // Reluctantly included for LUA_EvalMath
#include "d_clisrv.h" #include "netcode/d_clisrv.h"
#ifdef HWRENDER #ifdef HWRENDER
#include "hardware/hw_light.h" #include "hardware/hw_light.h"

View file

@ -35,7 +35,7 @@
#include "r_sky.h" #include "r_sky.h"
#include "fastcmp.h" #include "fastcmp.h"
#include "lua_script.h" // Reluctantly included for LUA_EvalMath #include "lua_script.h" // Reluctantly included for LUA_EvalMath
#include "d_clisrv.h" #include "netcode/d_clisrv.h"
#ifdef HWRENDER #ifdef HWRENDER
#include "hardware/hw_light.h" #include "hardware/hw_light.h"

View file

@ -4410,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[] = {
@ -4613,8 +4614,7 @@ const char *COLOR_ENUMS[] = {
// Desaturated // Desaturated
"AETHER", // SKINCOLOR_AETHER, "AETHER", // SKINCOLOR_AETHER,
"SLATE", // SKINCOLOR_SLATE, "SLATE", // SKINCOLOR_SLATE,
"METEORITE", // SKINCOLOR_METEORITE, "MOONSTONE", // SKINCOLOR_MOONSTONE,
"MERCURY", // SKINCOLOR_MERCURY,
"BLUEBELL", // SKINCOLOR_BLUEBELL, "BLUEBELL", // SKINCOLOR_BLUEBELL,
"PINK", // SKINCOLOR_PINK, "PINK", // SKINCOLOR_PINK,
"ROSEWOOD", // SKINCOLOR_ROSEWOOD, "ROSEWOOD", // SKINCOLOR_ROSEWOOD,
@ -4651,10 +4651,10 @@ const char *COLOR_ENUMS[] = {
"COPPER", // SKINCOLOR_COPPER, "COPPER", // SKINCOLOR_COPPER,
"APRICOT", // SKINCOLOR_APRICOT, "APRICOT", // SKINCOLOR_APRICOT,
"ORANGE", // SKINCOLOR_ORANGE, "ORANGE", // SKINCOLOR_ORANGE,
"PUMPKIN", // SKINCOLOR_PUMPKIN,
"RUST", // SKINCOLOR_RUST, "RUST", // SKINCOLOR_RUST,
"GOLD", // SKINCOLOR_GOLD, "TANGERINE", // SKINCOLOR_TANGERINE,
"TOPAZ", // SKINCOLOR_TOPAZ, "TOPAZ", // SKINCOLOR_TOPAZ,
"GOLD", // SKINCOLOR_GOLD,
"SANDY", // SKINCOLOR_SANDY, "SANDY", // SKINCOLOR_SANDY,
"GOLDENROD", // SKINCOLOR_GOLDENROD, "GOLDENROD", // SKINCOLOR_GOLDENROD,
"YELLOW", // SKINCOLOR_YELLOW, "YELLOW", // SKINCOLOR_YELLOW,
@ -4664,20 +4664,21 @@ const char *COLOR_ENUMS[] = {
"LIME", // SKINCOLOR_LIME, "LIME", // SKINCOLOR_LIME,
"PERIDOT", // SKINCOLOR_PERIDOT, "PERIDOT", // SKINCOLOR_PERIDOT,
"APPLE", // SKINCOLOR_APPLE, "APPLE", // SKINCOLOR_APPLE,
"HEADLIGHT", // SKINCOLOR_HEADLIGHT,
"CHARTREUSE", // SKINCOLOR_CHARTREUSE, "CHARTREUSE", // SKINCOLOR_CHARTREUSE,
"GREEN", // SKINCOLOR_GREEN, "GREEN", // SKINCOLOR_GREEN,
"FOREST", // SKINCOLOR_FOREST, "FOREST", // SKINCOLOR_FOREST,
"SHAMROCK", // SKINCOLOR_SHAMROCK, "SHAMROCK", // SKINCOLOR_SHAMROCK,
"JADE", // SKINCOLOR_JADE, "JADE", // SKINCOLOR_JADE,
"HEADLIGHT", // SKINCOLOR_HEADLIGHT,
"MINT", // SKINCOLOR_MINT, "MINT", // SKINCOLOR_MINT,
"MASTER", // SKINCOLOR_MASTER, "MASTER", // SKINCOLOR_MASTER,
"EMERALD", // SKINCOLOR_EMERALD, "EMERALD", // SKINCOLOR_EMERALD,
"BOTTLE", // SKINCOLOR_BOTTLE,
"SEAFOAM", // SKINCOLOR_SEAFOAM, "SEAFOAM", // SKINCOLOR_SEAFOAM,
"ISLAND", // SKINCOLOR_ISLAND, "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, "TURQUOISE", // SKINCOLOR_TURQUOISE,
@ -4703,7 +4704,7 @@ const char *COLOR_ENUMS[] = {
"NOBLE", // SKINCOLOR_NOBLE, "NOBLE", // SKINCOLOR_NOBLE,
"FUCHSIA", // SKINCOLOR_FUCHSIA, "FUCHSIA", // SKINCOLOR_FUCHSIA,
"BUBBLEGUM", // SKINCOLOR_BUBBLEGUM, "BUBBLEGUM", // SKINCOLOR_BUBBLEGUM,
"CRYSTAL", // SKINCOLOR_CRYSTAL, "SIBERITE", // SKINCOLOR_SIBERITE,
"MAGENTA", // SKINCOLOR_MAGENTA, "MAGENTA", // SKINCOLOR_MAGENTA,
"NEON", // SKINCOLOR_NEON, "NEON", // SKINCOLOR_NEON,
"VIOLET", // SKINCOLOR_VIOLET, "VIOLET", // SKINCOLOR_VIOLET,
@ -4882,7 +4883,7 @@ const char *const MENUTYPES_LIST[] = {
"MP_SERVER", "MP_SERVER",
"MP_CONNECT", "MP_CONNECT",
"MP_ROOM", "MP_ROOM",
"MP_PLAYERSETUP", // MP_PlayerSetupDef shared with SPLITSCREEN if #defined NONET "MP_PLAYERSETUP",
"MP_SERVER_OPTIONS", "MP_SERVER_OPTIONS",
// Options // Options

View file

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

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

@ -56,7 +56,6 @@
#endif #endif
#ifdef _WINDOWS #ifdef _WINDOWS
#define NONET
#if !defined (HWRENDER) && !defined (NOHW) #if !defined (HWRENDER) && !defined (NOHW)
#define HWRENDER #define HWRENDER
#endif #endif
@ -269,8 +268,7 @@ typedef enum
// Desaturated // Desaturated
SKINCOLOR_AETHER, SKINCOLOR_AETHER,
SKINCOLOR_SLATE, SKINCOLOR_SLATE,
SKINCOLOR_METEORITE, SKINCOLOR_MOONSTONE,
SKINCOLOR_MERCURY,
SKINCOLOR_BLUEBELL, SKINCOLOR_BLUEBELL,
SKINCOLOR_PINK, SKINCOLOR_PINK,
SKINCOLOR_ROSEWOOD, SKINCOLOR_ROSEWOOD,
@ -307,10 +305,10 @@ typedef enum
SKINCOLOR_COPPER, SKINCOLOR_COPPER,
SKINCOLOR_APRICOT, SKINCOLOR_APRICOT,
SKINCOLOR_ORANGE, SKINCOLOR_ORANGE,
SKINCOLOR_PUMPKIN,
SKINCOLOR_RUST, SKINCOLOR_RUST,
SKINCOLOR_GOLD, SKINCOLOR_TANGERINE,
SKINCOLOR_TOPAZ, SKINCOLOR_TOPAZ,
SKINCOLOR_GOLD,
SKINCOLOR_SANDY, SKINCOLOR_SANDY,
SKINCOLOR_GOLDENROD, SKINCOLOR_GOLDENROD,
SKINCOLOR_YELLOW, SKINCOLOR_YELLOW,
@ -320,20 +318,21 @@ typedef enum
SKINCOLOR_LIME, SKINCOLOR_LIME,
SKINCOLOR_PERIDOT, SKINCOLOR_PERIDOT,
SKINCOLOR_APPLE, SKINCOLOR_APPLE,
SKINCOLOR_HEADLIGHT,
SKINCOLOR_CHARTREUSE, SKINCOLOR_CHARTREUSE,
SKINCOLOR_GREEN, SKINCOLOR_GREEN,
SKINCOLOR_FOREST, SKINCOLOR_FOREST,
SKINCOLOR_SHAMROCK, SKINCOLOR_SHAMROCK,
SKINCOLOR_JADE, SKINCOLOR_JADE,
SKINCOLOR_HEADLIGHT,
SKINCOLOR_MINT, SKINCOLOR_MINT,
SKINCOLOR_MASTER, SKINCOLOR_MASTER,
SKINCOLOR_EMERALD, SKINCOLOR_EMERALD,
SKINCOLOR_BOTTLE,
SKINCOLOR_SEAFOAM, SKINCOLOR_SEAFOAM,
SKINCOLOR_ISLAND, 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_TURQUOISE,
@ -359,7 +358,7 @@ typedef enum
SKINCOLOR_NOBLE, SKINCOLOR_NOBLE,
SKINCOLOR_FUCHSIA, SKINCOLOR_FUCHSIA,
SKINCOLOR_BUBBLEGUM, SKINCOLOR_BUBBLEGUM,
SKINCOLOR_CRYSTAL, SKINCOLOR_SIBERITE,
SKINCOLOR_MAGENTA, SKINCOLOR_MAGENTA,
SKINCOLOR_NEON, SKINCOLOR_NEON,
SKINCOLOR_VIOLET, SKINCOLOR_VIOLET,
@ -724,7 +723,7 @@ extern int
/// Maintain compatibility with older 2.2 demos /// Maintain compatibility with older 2.2 demos
#define OLD22DEMOCOMPAT #define OLD22DEMOCOMPAT
#if defined (HAVE_CURL) && ! defined (NONET) #ifdef HAVE_CURL
#define MASTERSERVER #define MASTERSERVER
#else #else
#undef UPDATE_ALERT #undef UPDATE_ALERT

View file

@ -249,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
@ -633,7 +634,7 @@ extern boolean singletics;
// Netgame stuff // Netgame stuff
// ============= // =============
#include "d_clisrv.h" #include "netcode/d_clisrv.h"
extern consvar_t cv_timetic; // display high resolution timer extern consvar_t cv_timetic; // display high resolution timer
extern consvar_t cv_powerupdisplay; // display powerups extern consvar_t cv_powerupdisplay; // display powerups

View file

@ -113,6 +113,15 @@ int endswith (const char *base, const char *tag);
#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
@ -120,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

View file

@ -1,4 +1,4 @@
#include "../i_net.h" #include "../netcode/i_net.h"
boolean I_InitNetwork(void) boolean I_InitNetwork(void)
{ {

View file

@ -14,13 +14,18 @@ size_t I_GetFreeMem(size_t *total)
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;
} }
@ -182,10 +187,12 @@ const char *I_ClipboardPaste(void)
size_t I_GetRandomBytes(char *destination, size_t amount) size_t I_GetRandomBytes(char *destination, size_t amount)
{ {
(void)destination;
(void)amount;
return 0; return 0;
} }
void I_RegisterSysCommands(void) {} void I_RegisterSysCommands(void){}
void I_GetCursorPosition(INT32 *x, INT32 *y) void I_GetCursorPosition(INT32 *x, INT32 *y)
{ {

View file

@ -14,7 +14,7 @@
#include "doomdef.h" #include "doomdef.h"
#include "doomstat.h" #include "doomstat.h"
#include "d_main.h" #include "d_main.h"
#include "d_netcmd.h" #include "netcode/d_netcmd.h"
#include "f_finale.h" #include "f_finale.h"
#include "g_game.h" #include "g_game.h"
#include "hu_stuff.h" #include "hu_stuff.h"
@ -1062,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\"",
@ -1090,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:
@ -1197,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
@ -1644,7 +1648,7 @@ void F_GameEvaluationTicker(void)
sparklloop = 0; sparklloop = 0;
} }
if (finalecount == 5*TICRATE) if (G_CoopGametype() && !stagefailed && finalecount == 5*TICRATE)
{ {
serverGamedata->timesBeaten++; serverGamedata->timesBeaten++;
clientGamedata->timesBeaten++; clientGamedata->timesBeaten++;
@ -2256,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;

View file

@ -26,7 +26,7 @@
#include <string.h> #include <string.h>
#include "filesrch.h" #include "filesrch.h"
#include "d_netfil.h" #include "netcode/d_netfil.h"
#include "m_misc.h" #include "m_misc.h"
#include "z_zone.h" #include "z_zone.h"
#include "m_menu.h" // Addons_option_Onchange #include "m_menu.h" // Addons_option_Onchange

View file

@ -5,7 +5,7 @@
#define __FILESRCH_H__ #define __FILESRCH_H__
#include "doomdef.h" #include "doomdef.h"
#include "d_netfil.h" #include "netcode/d_netfil.h"
#include "m_menu.h" // MAXSTRINGLENGTH #include "m_menu.h" // MAXSTRINGLENGTH
#include "w_wad.h" #include "w_wad.h"

View file

@ -15,7 +15,7 @@
#include "console.h" #include "console.h"
#include "d_main.h" #include "d_main.h"
#include "d_player.h" #include "d_player.h"
#include "d_clisrv.h" #include "netcode/d_clisrv.h"
#include "p_setup.h" #include "p_setup.h"
#include "i_time.h" #include "i_time.h"
#include "i_system.h" #include "i_system.h"
@ -39,7 +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 #include "netcode/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
@ -1500,8 +1500,12 @@ void G_BeginRecording(void)
demo_p += 16; demo_p += 16;
// Color // Color
for (i = 0; i < MAXCOLORNAME && cv_playercolor.string[i]; i++) UINT16 skincolor = players[0].skincolor;
name[i] = cv_playercolor.string[i]; if (skincolor >= numskincolors)
skincolor = SKINCOLOR_NONE;
const char *skincolor_name = skincolors[skincolor].name;
for (i = 0; i < MAXCOLORNAME && skincolor_name[i]; i++)
name[i] = skincolor_name[i];
for (; i < MAXCOLORNAME; i++) for (; i < MAXCOLORNAME; i++)
name[i] = '\0'; name[i] = '\0';
M_Memcpy(demo_p,name,MAXCOLORNAME); M_Memcpy(demo_p,name,MAXCOLORNAME);
@ -1617,7 +1621,7 @@ void G_BeginMetal(void)
oldmetal.angle = mo->angle>>24; oldmetal.angle = mo->angle>>24;
} }
static void G_LoadDemoExtraFiles(UINT8 **pp) static void G_LoadDemoExtraFiles(UINT8 **pp, UINT16 this_demo_version)
{ {
UINT16 totalfiles; UINT16 totalfiles;
char filename[MAX_WADPATH]; char filename[MAX_WADPATH];
@ -1627,6 +1631,12 @@ static void G_LoadDemoExtraFiles(UINT8 **pp)
boolean alreadyloaded; boolean alreadyloaded;
UINT16 i, j; UINT16 i, j;
if (this_demo_version < 0x0010)
{
// demo has no file list
return;
}
totalfiles = READUINT16((*pp)); totalfiles = READUINT16((*pp));
for (i = 0; i < totalfiles; ++i) for (i = 0; i < totalfiles; ++i)
{ {
@ -1686,12 +1696,12 @@ static void G_LoadDemoExtraFiles(UINT8 **pp)
} }
} }
static void G_SkipDemoExtraFiles(UINT8 **pp) static void G_SkipDemoExtraFiles(UINT8 **pp, UINT16 this_demo_version)
{ {
UINT16 totalfiles; UINT16 totalfiles;
UINT16 i; UINT16 i;
if (demoversion < 0x0010) if (this_demo_version < 0x0010)
{ {
// demo has no file list // demo has no file list
return; return;
@ -1707,7 +1717,7 @@ static void G_SkipDemoExtraFiles(UINT8 **pp)
// G_CheckDemoExtraFiles: checks if our loaded WAD list matches the demo's. // 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. // Enabling quick prevents filesystem checks to see if needed files are available to load.
static UINT8 G_CheckDemoExtraFiles(UINT8 **pp, boolean quick) static UINT8 G_CheckDemoExtraFiles(UINT8 **pp, boolean quick, UINT16 this_demo_version)
{ {
UINT16 totalfiles, filesloaded, nmusfilecount; UINT16 totalfiles, filesloaded, nmusfilecount;
char filename[MAX_WADPATH]; char filename[MAX_WADPATH];
@ -1717,7 +1727,7 @@ static UINT8 G_CheckDemoExtraFiles(UINT8 **pp, boolean quick)
UINT16 i, j; UINT16 i, j;
UINT8 error = DFILE_ERROR_NONE; UINT8 error = DFILE_ERROR_NONE;
if (demoversion < 0x0010) if (this_demo_version < 0x0010)
{ {
// demo has no file list // demo has no file list
return DFILE_ERROR_NONE; return DFILE_ERROR_NONE;
@ -1816,10 +1826,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
@ -1835,15 +1844,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); 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)
@ -1882,16 +1891,9 @@ UINT8 G_CmpDemoTime(char *oldname, char *newname)
p++; // VERSION p++; // VERSION
p++; // SUBVERSION p++; // SUBVERSION
oldversion = READUINT16(p); oldversion = READUINT16(p);
switch(oldversion) // demoversion if (oldversion < 0x000c || oldversion > DEMOVERSION)
{ {
case DEMOVERSION: // latest always supported // too old (or new), cannot support
case 0x000f: // The previous demoversions also supported
case 0x000e:
case 0x000d: // all that changed between then and now was longer color name
case 0x000c:
break;
// too old, cannot support.
default:
CONS_Alert(CONS_NOTICE, M_GetText("File '%s' invalid format. It will be overwritten.\n"), oldname); CONS_Alert(CONS_NOTICE, M_GetText("File '%s' invalid format. It will be overwritten.\n"), oldname);
Z_Free(buffer); Z_Free(buffer);
return UINT8_MAX; return UINT8_MAX;
@ -1909,7 +1911,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); 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);
@ -1964,14 +1966,11 @@ void G_DoPlayDemo(char *defdemoname)
UINT8 i; UINT8 i;
lumpnum_t l; lumpnum_t l;
char skin[17],color[MAXCOLORNAME+1],*n,*pdemoname; char skin[17],color[MAXCOLORNAME+1],*n,*pdemoname;
UINT8 version,subversion,charability,charability2,thrustfactor,accelstart,acceleration,cnamelen; UINT8 version,subversion,charability,charability2,thrustfactor,accelstart,acceleration;
pflags_t pflags; pflags_t pflags;
UINT32 randseed, followitem; UINT32 randseed, followitem;
fixed_t camerascale,shieldscale,actionspd,mindash,maxdash,normalspeed,runspeed,jumpfactor,height,spinheight; fixed_t camerascale,shieldscale,actionspd,mindash,maxdash,normalspeed,runspeed,jumpfactor,height,spinheight;
char msg[1024]; char msg[1024];
#ifdef OLD22DEMOCOMPAT
boolean use_old_demo_vars = false;
#endif
skin[16] = '\0'; skin[16] = '\0';
color[MAXCOLORNAME] = '\0'; color[MAXCOLORNAME] = '\0';
@ -2030,23 +2029,13 @@ void G_DoPlayDemo(char *defdemoname)
subversion = READUINT8(demo_p); subversion = READUINT8(demo_p);
demoversion = READUINT16(demo_p); demoversion = READUINT16(demo_p);
demo_forwardmove_rng = (demoversion < 0x0010); demo_forwardmove_rng = (demoversion < 0x0010);
switch(demoversion)
{
case 0x000f:
case 0x000d:
case 0x000e:
case DEMOVERSION: // latest always supported
cnamelen = MAXCOLORNAME;
break;
#ifdef OLD22DEMOCOMPAT #ifdef OLD22DEMOCOMPAT
// all that changed between then and now was longer color name if (demoversion < 0x000c || demoversion > DEMOVERSION)
case 0x000c: #else
cnamelen = 16; if (demoversion < 0x000d || demoversion > DEMOVERSION)
use_old_demo_vars = true;
break;
#endif #endif
// too old, cannot support. {
default: // too old (or new), cannot support
snprintf(msg, 1024, M_GetText("%s is an incompatible replay format and cannot be played.\n"), pdemoname); snprintf(msg, 1024, M_GetText("%s is an incompatible replay format and cannot be played.\n"), pdemoname);
CONS_Alert(CONS_ERROR, "%s", msg); CONS_Alert(CONS_ERROR, "%s", msg);
M_StartMessage(msg, NULL, MM_NOTHING); M_StartMessage(msg, NULL, MM_NOTHING);
@ -2074,26 +2063,22 @@ void G_DoPlayDemo(char *defdemoname)
demoflags = READUINT8(demo_p); demoflags = READUINT8(demo_p);
if (demoversion < 0x0010) if (titledemo)
{
; // Don't do anything with files.
}
else if (titledemo)
{ {
// Titledemos should always play and ought to always be compatible with whatever wadlist is running. // Titledemos should always play and ought to always be compatible with whatever wadlist is running.
G_SkipDemoExtraFiles(&demo_p); G_SkipDemoExtraFiles(&demo_p, demoversion);
} }
else if (demofileoverride == DFILE_OVERRIDE_LOAD) else if (demofileoverride == DFILE_OVERRIDE_LOAD)
{ {
G_LoadDemoExtraFiles(&demo_p); G_LoadDemoExtraFiles(&demo_p, demoversion);
} }
else if (demofileoverride == DFILE_OVERRIDE_SKIP) else if (demofileoverride == DFILE_OVERRIDE_SKIP)
{ {
G_SkipDemoExtraFiles(&demo_p); G_SkipDemoExtraFiles(&demo_p, demoversion);
} }
else else
{ {
UINT8 error = G_CheckDemoExtraFiles(&demo_p, false); UINT8 error = G_CheckDemoExtraFiles(&demo_p, false, demoversion);
if (error) if (error)
{ {
@ -2177,8 +2162,8 @@ void G_DoPlayDemo(char *defdemoname)
demo_p += 16; demo_p += 16;
// Color // Color
M_Memcpy(color,demo_p,cnamelen); M_Memcpy(color, demo_p, (demoversion < 0x000d) ? 16 : MAXCOLORNAME);
demo_p += cnamelen; demo_p += (demoversion < 0x000d) ? 16 : MAXCOLORNAME;
charability = READUINT8(demo_p); charability = READUINT8(demo_p);
charability2 = READUINT8(demo_p); charability2 = READUINT8(demo_p);
@ -2214,7 +2199,7 @@ void G_DoPlayDemo(char *defdemoname)
// net var data // net var data
#ifdef OLD22DEMOCOMPAT #ifdef OLD22DEMOCOMPAT
if (use_old_demo_vars) if (demoversion < 0x000d)
CV_LoadOldDemoVars(&demo_p); CV_LoadOldDemoVars(&demo_p);
else else
#endif #endif
@ -2262,7 +2247,6 @@ void G_DoPlayDemo(char *defdemoname)
players[0].skincolor = i; players[0].skincolor = i;
break; break;
} }
CV_StealthSetValue(&cv_playercolor, players[0].skincolor);
if (players[0].mo) if (players[0].mo)
{ {
players[0].mo->color = players[0].skincolor; players[0].mo->color = players[0].skincolor;
@ -2302,6 +2286,13 @@ UINT8 G_CheckDemoForError(char *defdemoname)
{ {
lumpnum_t l; lumpnum_t l;
char *n,*pdemoname; 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); n = defdemoname+strlen(defdemoname);
while (*n != '/' && *n != '\\' && n != defdemoname) while (*n != '/' && *n != '\\' && n != defdemoname)
@ -2340,21 +2331,14 @@ UINT8 G_CheckDemoForError(char *defdemoname)
demo_p++; // version demo_p++; // version
demo_p++; // subversion demo_p++; // subversion
demoversion = READUINT16(demo_p); our_demo_version = READUINT16(demo_p);
demo_forwardmove_rng = (demoversion < 0x0010);
switch(demoversion)
{
case 0x000d:
case 0x000e:
case 0x000f:
case DEMOVERSION: // latest always supported
break;
#ifdef OLD22DEMOCOMPAT #ifdef OLD22DEMOCOMPAT
case 0x000c: if (our_demo_version < 0x000c || our_demo_version > DEMOVERSION)
break; #else
if (our_demo_version < 0x000d || our_demo_version > DEMOVERSION)
#endif #endif
// too old, cannot support. {
default: // too old (or new), cannot support
return DFILE_ERROR_NOTDEMO; return DFILE_ERROR_NOTDEMO;
} }
demo_p += 16; // demo checksum demo_p += 16; // demo checksum
@ -2368,17 +2352,7 @@ UINT8 G_CheckDemoForError(char *defdemoname)
demo_p++; // demoflags demo_p++; // demoflags
// Don't do anything with files. return G_CheckDemoExtraFiles(&demo_p, true, our_demo_version);
if (demoversion < 0x0010)
{
return DFILE_ERROR_NONE;
}
else if (titledemo)
{
return DFILE_ERROR_NONE;
}
return G_CheckDemoExtraFiles(&demo_p, true);
} }
void G_AddGhost(char *defdemoname) void G_AddGhost(char *defdemoname)
@ -2386,7 +2360,6 @@ void G_AddGhost(char *defdemoname)
INT32 i; INT32 i;
lumpnum_t l; lumpnum_t l;
char name[17],skin[17],color[MAXCOLORNAME+1],*n,*pdemoname,md5[16]; char name[17],skin[17],color[MAXCOLORNAME+1],*n,*pdemoname,md5[16];
UINT8 cnamelen;
demoghost *gh; demoghost *gh;
UINT8 flags, subversion; UINT8 flags, subversion;
UINT8 *buffer,*p; UINT8 *buffer,*p;
@ -2438,20 +2411,9 @@ void G_AddGhost(char *defdemoname)
p++; // VERSION p++; // VERSION
subversion = READUINT8(p); // SUBVERSION subversion = READUINT8(p); // SUBVERSION
ghostversion = READUINT16(p); ghostversion = READUINT16(p);
switch(ghostversion) if (ghostversion < 0x000c || ghostversion > DEMOVERSION)
{ {
case 0x000f: // too old (or new), cannot support
case 0x000d:
case 0x000e:
case DEMOVERSION: // latest always supported
cnamelen = MAXCOLORNAME;
break;
// all that changed between then and now was longer color name
case 0x000c:
cnamelen = 16;
break;
// too old, cannot support.
default:
CONS_Alert(CONS_NOTICE, M_GetText("Ghost %s: Demo version incompatible.\n"), pdemoname); CONS_Alert(CONS_NOTICE, M_GetText("Ghost %s: Demo version incompatible.\n"), pdemoname);
Z_Free(pdemoname); Z_Free(pdemoname);
Z_Free(buffer); Z_Free(buffer);
@ -2487,7 +2449,7 @@ void G_AddGhost(char *defdemoname)
return; return;
} }
G_SkipDemoExtraFiles(&p); // Don't wanna modify the file list for ghosts. 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)
{ {
@ -2514,8 +2476,8 @@ void G_AddGhost(char *defdemoname)
p += 16; p += 16;
// Color // Color
M_Memcpy(color, p,cnamelen); M_Memcpy(color, p, (ghostversion < 0x000d) ? 16 : MAXCOLORNAME);
p += cnamelen; p += (ghostversion < 0x000d) ? 16 : MAXCOLORNAME;
// 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
@ -2698,16 +2660,9 @@ void G_DoPlayMetal(void)
metal_p++; // VERSION metal_p++; // VERSION
metal_p++; // SUBVERSION metal_p++; // SUBVERSION
metalversion = READUINT16(metal_p); metalversion = READUINT16(metal_p);
switch(metalversion) if (metalversion < 0x000c || metalversion > DEMOVERSION)
{ {
case DEMOVERSION: // latest always supported // too old (or new), cannot support
case 0x000f:
case 0x000e: // There are checks wheter the momentum is from older demo versions or not
case 0x000d: // all that changed between then and now was longer color name
case 0x000c:
break;
// too old, cannot support.
default:
CONS_Alert(CONS_WARNING, M_GetText("Failed to load bot recording for this map, format version incompatible.\n")); CONS_Alert(CONS_WARNING, M_GetText("Failed to load bot recording for this map, format version incompatible.\n"));
Z_Free(metalbuffer); Z_Free(metalbuffer);
return; return;

View file

@ -15,7 +15,8 @@
#include "console.h" #include "console.h"
#include "d_main.h" #include "d_main.h"
#include "d_player.h" #include "d_player.h"
#include "d_clisrv.h" #include "netcode/d_clisrv.h"
#include "netcode/net_command.h"
#include "f_finale.h" #include "f_finale.h"
#include "p_setup.h" #include "p_setup.h"
#include "p_saveg.h" #include "p_saveg.h"
@ -55,6 +56,8 @@ gameaction_t gameaction;
gamestate_t gamestate = GS_NULL; gamestate_t gamestate = GS_NULL;
UINT8 ultimatemode = false; UINT8 ultimatemode = false;
INT32 pickedchar;
boolean botingame; boolean botingame;
UINT8 botskin; UINT8 botskin;
UINT16 botcolor; UINT16 botcolor;
@ -156,6 +159,7 @@ textprompt_t *textprompts[MAX_PROMPTS];
INT16 nextmapoverride; INT16 nextmapoverride;
UINT8 skipstats; UINT8 skipstats;
INT16 nextgametype = -1;
// Pointers to each CTF flag // Pointers to each CTF flag
mobj_t *redflag; mobj_t *redflag;
@ -315,6 +319,8 @@ consvar_t cv_consolechat = CVAR_INIT ("chatmode", "Window", CV_SAVE, consolechat
// Pause game upon window losing focus // Pause game upon window losing focus
consvar_t cv_pauseifunfocused = CVAR_INIT ("pauseifunfocused", "Yes", CV_SAVE, CV_YesNo, NULL); consvar_t cv_pauseifunfocused = CVAR_INIT ("pauseifunfocused", "Yes", CV_SAVE, CV_YesNo, NULL);
consvar_t cv_instantretry = CVAR_INIT ("instantretry", "No", CV_SAVE, CV_YesNo, NULL);
consvar_t cv_crosshair = CVAR_INIT ("crosshair", "Cross", CV_SAVE, crosshair_cons_t, NULL); consvar_t cv_crosshair = CVAR_INIT ("crosshair", "Cross", CV_SAVE, crosshair_cons_t, NULL);
consvar_t cv_crosshair2 = CVAR_INIT ("crosshair2", "Cross", CV_SAVE, crosshair_cons_t, NULL); consvar_t cv_crosshair2 = CVAR_INIT ("crosshair2", "Cross", CV_SAVE, crosshair_cons_t, NULL);
consvar_t cv_invertmouse = CVAR_INIT ("invertmouse", "Off", CV_SAVE, CV_OnOff, NULL); consvar_t cv_invertmouse = CVAR_INIT ("invertmouse", "Off", CV_SAVE, CV_OnOff, NULL);
@ -2079,7 +2085,7 @@ boolean G_Responder(event_t *ev)
if (gameaction == ga_nothing && !singledemo && if (gameaction == ga_nothing && !singledemo &&
((demoplayback && !modeattacking && !titledemo) || gamestate == GS_TITLESCREEN)) ((demoplayback && !modeattacking && !titledemo) || gamestate == GS_TITLESCREEN))
{ {
if (ev->type == ev_keydown && ev->key != 301 && !(gamestate == GS_TITLESCREEN && finalecount < TICRATE)) if (ev->type == ev_keydown && ev->key != 301 && !(gamestate == GS_TITLESCREEN && finalecount < (cv_tutorialprompt.value ? TICRATE : 0)))
{ {
M_StartControlPanel(); M_StartControlPanel();
return true; return true;
@ -2137,7 +2143,7 @@ boolean G_Responder(event_t *ev)
if (! netgame) if (! netgame)
F_StartGameEvaluation(); F_StartGameEvaluation();
else if (server || IsPlayerAdmin(consoleplayer)) else if (server || IsPlayerAdmin(consoleplayer))
SendNetXCmd(XD_EXITLEVEL, NULL, 0); D_SendExitLevel(false);
return true; return true;
} }
} }
@ -2172,9 +2178,9 @@ boolean G_Responder(event_t *ev)
if (menuactive || pausedelay < 0 || leveltime < 2) if (menuactive || pausedelay < 0 || leveltime < 2)
return true; return true;
if (pausedelay < 1+(NEWTICRATE/2)) if (!cv_instantretry.value && pausedelay < 1+(NEWTICRATE/2))
pausedelay = 1+(NEWTICRATE/2); pausedelay = 1+(NEWTICRATE/2);
else if (++pausedelay > 1+(NEWTICRATE/2)+(NEWTICRATE/3)) else if (cv_instantretry.value || ++pausedelay > 1+(NEWTICRATE/2)+(NEWTICRATE/3))
{ {
G_SetModeAttackRetryFlag(); G_SetModeAttackRetryFlag();
return true; return true;
@ -2748,25 +2754,6 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
//if ((netgame || multiplayer) && !p->spectator) -- moved into P_SpawnPlayer to account for forced changes there //if ((netgame || multiplayer) && !p->spectator) -- moved into P_SpawnPlayer to account for forced changes there
//p->powers[pw_flashing] = flashingtics-1; // Babysitting deterrent //p->powers[pw_flashing] = flashingtics-1; // Babysitting deterrent
// Check to make sure their color didn't change somehow...
if (G_GametypeHasTeams())
{
if (p->ctfteam == 1 && p->skincolor != skincolor_redteam)
{
if (p == &players[consoleplayer])
CV_SetValue(&cv_playercolor, skincolor_redteam);
else if (p == &players[secondarydisplayplayer])
CV_SetValue(&cv_playercolor2, skincolor_redteam);
}
else if (p->ctfteam == 2 && p->skincolor != skincolor_blueteam)
{
if (p == &players[consoleplayer])
CV_SetValue(&cv_playercolor, skincolor_blueteam);
else if (p == &players[secondarydisplayplayer])
CV_SetValue(&cv_playercolor2, skincolor_blueteam);
}
}
if (betweenmaps) if (betweenmaps)
return; return;
@ -3461,9 +3448,7 @@ UINT32 gametypedefaultrules[NUMGAMETYPES] =
}; };
// //
// G_SetGametype // Sets a new gametype.
//
// Set a new gametype, also setting gametype rules accordingly. Yay!
// //
void G_SetGametype(INT16 gtype) void G_SetGametype(INT16 gtype)
{ {
@ -3861,7 +3846,7 @@ static INT16 RandMap(UINT32 tolflags, INT16 pprevmap)
for (ix = 0; ix < NUMMAPS; ix++) for (ix = 0; ix < NUMMAPS; ix++)
if (mapheaderinfo[ix] && (mapheaderinfo[ix]->typeoflevel & tolflags) == tolflags if (mapheaderinfo[ix] && (mapheaderinfo[ix]->typeoflevel & tolflags) == tolflags
&& ix != pprevmap // Don't pick the same map. && ix != pprevmap // Don't pick the same map.
&& (dedicated || !M_MapLocked(ix+1, serverGamedata)) // Don't pick locked maps. && (!M_MapLocked(ix+1, serverGamedata)) // Don't pick locked maps.
) )
okmaps[numokmaps++] = ix; okmaps[numokmaps++] = ix;
@ -4053,6 +4038,13 @@ static void G_DoCompleted(void)
nextmap = 1100-1; // No infinite loop for you nextmap = 1100-1; // No infinite loop for you
} }
INT16 gametype_to_use;
if (nextgametype >= 0 && nextgametype < gametypecount)
gametype_to_use = nextgametype;
else
gametype_to_use = gametype;
// If nextmap is actually going to get used, make sure it points to // If nextmap is actually going to get used, make sure it points to
// a map of the proper gametype -- skip levels that don't support // a map of the proper gametype -- skip levels that don't support
// the current gametype. (Helps avoid playing boss levels in Race, // the current gametype. (Helps avoid playing boss levels in Race,
@ -4061,8 +4053,8 @@ static void G_DoCompleted(void)
{ {
if (nextmap >= 0 && nextmap < NUMMAPS) if (nextmap >= 0 && nextmap < NUMMAPS)
{ {
register INT16 cm = nextmap; INT16 cm = nextmap;
UINT32 tolflag = G_TOLFlag(gametype); UINT32 tolflag = G_TOLFlag(gametype_to_use);
UINT8 visitedmap[(NUMMAPS+7)/8]; UINT8 visitedmap[(NUMMAPS+7)/8];
memset(visitedmap, 0, sizeof (visitedmap)); memset(visitedmap, 0, sizeof (visitedmap));
@ -4117,7 +4109,7 @@ static void G_DoCompleted(void)
{ {
token--; token--;
if (!nextmapoverride) // if (!nextmapoverride) // Having a token should pull the player into the special stage before going to the overridden map (Issue #933)
for (i = 0; i < 7; i++) for (i = 0; i < 7; i++)
if (!(emeralds & (1<<i))) if (!(emeralds & (1<<i)))
{ {
@ -4142,7 +4134,7 @@ static void G_DoCompleted(void)
if (cv_advancemap.value == 0) // Stay on same map. if (cv_advancemap.value == 0) // Stay on same map.
nextmap = prevmap; nextmap = prevmap;
else if (cv_advancemap.value == 2) // Go to random map. else if (cv_advancemap.value == 2) // Go to random map.
nextmap = RandMap(G_TOLFlag(gametype), prevmap); nextmap = RandMap(G_TOLFlag(gametype_to_use), prevmap);
} }
// We are committed to this map now. // We are committed to this map now.
@ -4151,7 +4143,6 @@ static void G_DoCompleted(void)
if (nextmap < NUMMAPS && !mapheaderinfo[nextmap]) if (nextmap < NUMMAPS && !mapheaderinfo[nextmap])
P_AllocMapHeader(nextmap); P_AllocMapHeader(nextmap);
// If the current gametype has no intermission screen set, then don't start it.
Y_DetermineIntermissionType(); Y_DetermineIntermissionType();
if ((skipstats && !modeattacking) || (modeattacking && stagefailed) || (intertype == int_none)) if ((skipstats && !modeattacking) || (modeattacking && stagefailed) || (intertype == int_none))
@ -4217,12 +4208,21 @@ static void G_DoWorldDone(void)
{ {
if (server) if (server)
{ {
INT16 gametype_to_use;
if (nextgametype >= 0 && nextgametype < gametypecount)
gametype_to_use = nextgametype;
else
gametype_to_use = gametype;
if (gametyperules & GTR_CAMPAIGN) if (gametyperules & GTR_CAMPAIGN)
// don't reset player between maps // don't reset player between maps
D_MapChange(nextmap+1, gametype, ultimatemode, false, 0, false, false); D_MapChange(nextmap+1, gametype_to_use, ultimatemode, false, 0, false, false);
else else
// resetplayer in match/chaos/tag/CTF/race for more equality // resetplayer in match/chaos/tag/CTF/race for more equality
D_MapChange(nextmap+1, gametype, ultimatemode, true, 0, false, false); D_MapChange(nextmap+1, gametype_to_use, ultimatemode, true, 0, false, false);
nextgametype = -1;
} }
gameaction = ga_nothing; gameaction = ga_nothing;
@ -4789,12 +4789,9 @@ void G_LoadGame(UINT32 slot, INT16 mapoverride)
Z_Free(savebuffer); Z_Free(savebuffer);
save_p = savebuffer = NULL; save_p = savebuffer = NULL;
// gameaction = ga_nothing;
// G_SetGamestate(GS_LEVEL);
displayplayer = consoleplayer; displayplayer = consoleplayer;
multiplayer = splitscreen = false; multiplayer = splitscreen = false;
// G_DeferedInitNew(sk_medium, G_BuildMapName(1), 0, 0, 1);
if (setsizeneeded) if (setsizeneeded)
R_ExecuteSetViewSize(); R_ExecuteSetViewSize();
@ -4987,9 +4984,9 @@ cleanup:
// Can be called by the startup code or the menu task, // Can be called by the startup code or the menu task,
// consoleplayer, displayplayer, playeringame[] should be set. // consoleplayer, displayplayer, playeringame[] should be set.
// //
void G_DeferedInitNew(boolean pultmode, const char *mapname, INT32 pickedchar, boolean SSSG, boolean FLS) void G_DeferedInitNew(boolean pultmode, const char *mapname, INT32 character, boolean SSSG, boolean FLS)
{ {
UINT16 color = skins[pickedchar].prefcolor; pickedchar = character;
paused = false; paused = false;
if (demoplayback) if (demoplayback)
@ -5010,10 +5007,7 @@ void G_DeferedInitNew(boolean pultmode, const char *mapname, INT32 pickedchar, b
SplitScreen_OnChange(); SplitScreen_OnChange();
} }
color = skins[pickedchar].prefcolor; SetPlayerSkinByNum(consoleplayer, character);
SetPlayerSkinByNum(consoleplayer, pickedchar);
CV_StealthSet(&cv_skin, skins[pickedchar].name);
CV_StealthSetValue(&cv_playercolor, color);
if (mapname) if (mapname)
D_MapChange(M_MapNumber(mapname[3], mapname[4]), gametype, pultmode, true, 1, false, FLS); D_MapChange(M_MapNumber(mapname[3], mapname[4]), gametype, pultmode, true, 1, false, FLS);
@ -5093,6 +5087,10 @@ void G_InitNew(UINT8 pultmode, const char *mapname, boolean resetplayer, boolean
CV_StealthSetValue(&cv_itemfinder, 0); CV_StealthSetValue(&cv_itemfinder, 0);
} }
// Restore each player's skin if it was previously forced to be a specific one
// (Looks a bit silly, but it works.)
boolean reset_skin = netgame && mapheaderinfo[gamemap-1] && mapheaderinfo[gamemap-1]->forcecharacter[0] != '\0';
// internal game map // internal game map
// well this check is useless because it is done before (d_netcmd.c::command_map_f) // well this check is useless because it is done before (d_netcmd.c::command_map_f)
// but in case of for demos.... // but in case of for demos....
@ -5120,6 +5118,9 @@ void G_InitNew(UINT8 pultmode, const char *mapname, boolean resetplayer, boolean
automapactive = false; automapactive = false;
imcontinuing = false; imcontinuing = false;
if (reset_skin)
D_SendPlayerConfig();
// fetch saved data if available // fetch saved data if available
if (savedata.lives > 0) if (savedata.lives > 0)
{ {

View file

@ -49,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;
@ -174,8 +176,7 @@ void G_SpawnPlayer(INT32 playernum);
// Can be called by the startup code or M_Responder. // Can be called by the startup code or M_Responder.
// A normal game starts at map 1, but a warp test can start elsewhere // A normal game starts at map 1, but a warp test can start elsewhere
void G_DeferedInitNew(boolean pultmode, const char *mapname, INT32 pickedchar, void G_DeferedInitNew(boolean pultmode, const char *mapname, INT32 character, boolean SSSG, boolean FLS);
boolean SSSG, boolean FLS);
void G_DoLoadLevel(boolean resetplayer); void G_DoLoadLevel(boolean resetplayer);
void G_StartTitleCard(void); void G_StartTitleCard(void);
void G_PreLevelTitleCard(void); void G_PreLevelTitleCard(void);

View file

@ -16,7 +16,7 @@
#include "g_input.h" #include "g_input.h"
#include "keys.h" #include "keys.h"
#include "hu_stuff.h" // need HUFONT start & end #include "hu_stuff.h" // need HUFONT start & end
#include "d_net.h" #include "netcode/d_net.h"
#include "console.h" #include "console.h"
#define MAXMOUSESENSITIVITY 100 // sensitivity steps #define MAXMOUSESENSITIVITY 100 // sensitivity steps

View file

@ -53,9 +53,11 @@ typedef enum
extern gamestate_t gamestate; extern gamestate_t gamestate;
extern UINT8 titlemapinaction; extern UINT8 titlemapinaction;
extern UINT8 ultimatemode; // was sk_insane extern UINT8 ultimatemode;
extern gameaction_t gameaction; extern gameaction_t gameaction;
extern INT32 pickedchar;
extern boolean botingame; extern boolean botingame;
extern UINT8 botskin; extern UINT8 botskin;
extern UINT16 botcolor; extern UINT16 botcolor;

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

@ -29,7 +29,7 @@
#include "../r_patch.h" #include "../r_patch.h"
#include "../r_picformats.h" #include "../r_picformats.h"
#include "../r_bsp.h" #include "../r_bsp.h"
#include "../d_clisrv.h" #include "../netcode/d_clisrv.h"
#include "../w_wad.h" #include "../w_wad.h"
#include "../z_zone.h" #include "../z_zone.h"
#include "../r_splats.h" #include "../r_splats.h"
@ -1699,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)
@ -1822,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)
@ -3095,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);
} }
@ -3141,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);
} }
@ -3595,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;
@ -3606,9 +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);
if ((thing->scale != thing->old_scale) && (thing->scale >= FRACUNIT/1024)) // Interpolate shadows when scaling mobjs
scalemul = FixedMul(scalemul, FixedDiv(interp.scale, thing->scale));
fscale = FIXED_TO_FLOAT(scalemul); fscale = FIXED_TO_FLOAT(scalemul);
fx = FIXED_TO_FLOAT(interp.x); fx = FIXED_TO_FLOAT(interp.x);
@ -3720,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
{ {
@ -4055,32 +4053,32 @@ static void HWR_DrawBoundingBox(gl_vissprite_t *vis)
// repeat this 4 times (overhead) // repeat this 4 times (overhead)
// //
// //
// 17 20 21 11 // 15 16 17 09
// 16 15 14 10 // 14 13 12 08
// 27 22 *--* 07 12 // 23 18 *--* 07 10
// | | // | |
// 26 23 *--* 06 13 // 22 19 *--* 06 11
// 24 00 01 02 // 20 00 01 02
// 25 05 04 03 // 21 05 04 03
// //
v[000].x = v[005].x = v[015].x = v[016].x = v[017].x = v[020].x = v[ 0].x = v[ 5].x = v[13].x = v[14].x = v[15].x = v[16].x =
v[022].x = v[023].x = v[024].x = v[025].x = v[026].x = v[027].x = vis->x1; // west v[18].x = v[19].x = v[20].x = v[21].x = v[22].x = v[23].x = vis->x1; // west
v[001].x = v[002].x = v[003].x = v[004].x = v[006].x = v[007].x = v[ 1].x = v[ 2].x = v[ 3].x = v[ 4].x = v[ 6].x = v[ 7].x =
v[010].x = v[011].x = v[012].x = v[013].x = v[014].x = v[021].x = vis->x2; // east v[ 8].x = v[ 9].x = v[10].x = v[11].x = v[12].x = v[17].x = vis->x2; // east
v[000].z = v[001].z = v[002].z = v[003].z = v[004].z = v[005].z = v[ 0].z = v[ 1].z = v[ 2].z = v[ 3].z = v[ 4].z = v[ 5].z =
v[006].z = v[013].z = v[023].z = v[024].z = v[025].z = v[026].z = vis->z1; // south v[ 6].z = v[11].z = v[19].z = v[20].z = v[21].z = v[22].z = vis->z1; // south
v[007].z = v[010].z = v[011].z = v[012].z = v[014].z = v[015].z = v[ 7].z = v[ 8].z = v[ 9].z = v[10].z = v[12].z = v[13].z =
v[016].z = v[017].z = v[020].z = v[021].z = v[022].z = v[027].z = vis->z2; // north v[14].z = v[15].z = v[16].z = v[17].z = v[18].z = v[23].z = vis->z2; // north
v[000].y = v[001].y = v[002].y = v[006].y = v[007].y = v[010].y = v[ 0].y = v[ 1].y = v[ 2].y = v[ 6].y = v[ 7].y = v[ 8].y =
v[014].y = v[015].y = v[016].y = v[022].y = v[023].y = v[024].y = vis->gz; // bottom v[12].y = v[13].y = v[14].y = v[18].y = v[19].y = v[20].y = vis->gz; // bottom
v[003].y = v[004].y = v[005].y = v[011].y = v[012].y = v[013].y = v[ 3].y = v[ 4].y = v[ 5].y = v[ 9].y = v[10].y = v[11].y =
v[017].y = v[020].y = v[021].y = v[025].y = v[026].y = v[027].y = vis->gzt; // top 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)); Surf.PolyColor = V_GetColor(R_GetBoundingBoxColor(vis->mobj));
@ -4143,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;
@ -5326,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));
@ -5378,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
@ -5684,7 +5679,6 @@ static void HWR_ProjectBoundingBox(mobj_t *thing)
gl_vissprite_t *vis; gl_vissprite_t *vis;
float tr_x, tr_y; float tr_x, tr_y;
float tz; float tz;
float rad;
if (!thing) if (!thing)
return; return;
@ -5719,15 +5713,13 @@ static void HWR_ProjectBoundingBox(mobj_t *thing)
tr_x += gl_viewx; tr_x += gl_viewx;
tr_y += gl_viewy; tr_y += gl_viewy;
rad = FIXED_TO_FLOAT(thing->radius);
vis = HWR_NewVisSprite(); vis = HWR_NewVisSprite();
vis->x1 = tr_x - rad; vis->x1 = tr_x - FIXED_TO_FLOAT(interp.radius);
vis->x2 = tr_x + rad; vis->x2 = tr_x + FIXED_TO_FLOAT(interp.radius);
vis->z1 = tr_y - rad; vis->z1 = tr_y - FIXED_TO_FLOAT(interp.radius);
vis->z2 = tr_y + rad; vis->z2 = tr_y + FIXED_TO_FLOAT(interp.radius);
vis->gz = FIXED_TO_FLOAT(interp.z); vis->gz = FIXED_TO_FLOAT(interp.z);
vis->gzt = vis->gz + FIXED_TO_FLOAT(thing->height); vis->gzt = vis->gz + FIXED_TO_FLOAT(interp.height);
vis->mobj = thing; vis->mobj = thing;
vis->precip = false; vis->precip = false;

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)
@ -1582,7 +1582,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);
@ -1618,8 +1618,8 @@ boolean HWR_DrawModel(gl_vissprite_t *spr)
p.roll = true; p.roll = true;
// rotation pivot // rotation pivot
p.centerx = FIXED_TO_FLOAT(spr->mobj->radius / 2); p.centerx = FIXED_TO_FLOAT(interp.radius / 2);
p.centery = FIXED_TO_FLOAT(spr->mobj->height / 2); p.centery = FIXED_TO_FLOAT(interp.height / 2);
// rotation axes relative to camera // rotation axes relative to camera
p.rollx = FIXED_TO_FLOAT(FINECOSINE(FixedAngle(camAngleDiff) >> ANGLETOFINESHIFT)); p.rollx = FIXED_TO_FLOAT(FINECOSINE(FixedAngle(camAngleDiff) >> ANGLETOFINESHIFT));

View file

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

@ -19,7 +19,9 @@
#include "m_cond.h" // emblems #include "m_cond.h" // emblems
#include "m_misc.h" // word jumping #include "m_misc.h" // word jumping
#include "d_clisrv.h" #include "netcode/d_clisrv.h"
#include "netcode/net_command.h"
#include "netcode/gamestate.h"
#include "g_game.h" #include "g_game.h"
#include "g_input.h" #include "g_input.h"
@ -175,14 +177,12 @@ static huddrawlist_h luahuddrawlist_scores;
static tic_t resynch_ticker = 0; static tic_t resynch_ticker = 0;
#ifndef NONET
// just after // just after
static void Command_Say_f(void); static void Command_Say_f(void);
static void Command_Sayto_f(void); static void Command_Sayto_f(void);
static void Command_Sayteam_f(void); static void Command_Sayteam_f(void);
static void Command_CSay_f(void); static void Command_CSay_f(void);
static void Got_Saycmd(UINT8 **p, INT32 playernum); static void Got_Saycmd(UINT8 **p, INT32 playernum);
#endif
void HU_LoadGraphics(void) void HU_LoadGraphics(void)
{ {
@ -327,13 +327,11 @@ void HU_LoadGraphics(void)
// //
void HU_Init(void) void HU_Init(void)
{ {
#ifndef NONET
COM_AddCommand("say", Command_Say_f, COM_LUA); COM_AddCommand("say", Command_Say_f, COM_LUA);
COM_AddCommand("sayto", Command_Sayto_f, COM_LUA); COM_AddCommand("sayto", Command_Sayto_f, COM_LUA);
COM_AddCommand("sayteam", Command_Sayteam_f, COM_LUA); COM_AddCommand("sayteam", Command_Sayteam_f, COM_LUA);
COM_AddCommand("csay", Command_CSay_f, COM_LUA); COM_AddCommand("csay", Command_CSay_f, COM_LUA);
RegisterNetXCmd(XD_SAY, Got_Saycmd); RegisterNetXCmd(XD_SAY, Got_Saycmd);
#endif
// set shift translation table // set shift translation table
shiftxform = english_shiftxform; shiftxform = english_shiftxform;
@ -363,8 +361,6 @@ void HU_Start(void)
// EXECUTION // EXECUTION
//====================================================================== //======================================================================
#ifndef NONET
// EVERY CHANGE IN THIS SCRIPT IS LOL XD! BY VINCYTM // EVERY CHANGE IN THIS SCRIPT IS LOL XD! BY VINCYTM
static UINT32 chat_nummsg_log = 0; static UINT32 chat_nummsg_log = 0;
@ -412,11 +408,9 @@ static void HU_removeChatText_Log(void)
} }
chat_nummsg_log--; // lost 1 msg. chat_nummsg_log--; // lost 1 msg.
} }
#endif
void HU_AddChatText(const char *text, boolean playsound) void HU_AddChatText(const char *text, boolean playsound)
{ {
#ifndef NONET
if (playsound && cv_consolechat.value != 2) // Don't play the sound if we're using hidden chat. if (playsound && cv_consolechat.value != 2) // Don't play the sound if we're using hidden chat.
S_StartSound(NULL, sfx_radio); S_StartSound(NULL, sfx_radio);
// reguardless of our preferences, put all of this in the chat buffer in case we decide to change from oldchat mid-game. // reguardless of our preferences, put all of this in the chat buffer in case we decide to change from oldchat mid-game.
@ -438,14 +432,8 @@ void HU_AddChatText(const char *text, boolean playsound)
CONS_Printf("%s\n", text); CONS_Printf("%s\n", text);
else // if we aren't, still save the message to log.txt else // if we aren't, still save the message to log.txt
CON_LogMessage(va("%s\n", text)); CON_LogMessage(va("%s\n", text));
#else
(void)playsound;
CONS_Printf("%s\n", text);
#endif
} }
#ifndef NONET
/** Runs a say command, sending an ::XD_SAY message. /** Runs a say command, sending an ::XD_SAY message.
* A say command consists of a signed 8-bit integer for the target, an * A say command consists of a signed 8-bit integer for the target, an
* unsigned 8-bit flag variable, and then the message itself. * unsigned 8-bit flag variable, and then the message itself.
@ -865,8 +853,6 @@ static void Got_Saycmd(UINT8 **p, INT32 playernum)
#endif #endif
} }
#endif
// //
// //
void HU_Ticker(void) void HU_Ticker(void)
@ -882,7 +868,6 @@ void HU_Ticker(void)
else else
hu_showscores = false; hu_showscores = false;
#ifndef NONET
if (chat_on) if (chat_on)
{ {
// count down the scroll timer. // count down the scroll timer.
@ -910,7 +895,6 @@ void HU_Ticker(void)
HU_removeChatText_Mini(); HU_removeChatText_Mini();
} }
} }
#endif
if (cechotimer > 0) --cechotimer; if (cechotimer > 0) --cechotimer;
@ -918,8 +902,6 @@ void HU_Ticker(void)
resynch_ticker++; resynch_ticker++;
} }
#ifndef NONET
static boolean teamtalk = false; static boolean teamtalk = false;
static boolean justscrolleddown; static boolean justscrolleddown;
static boolean justscrolledup; static boolean justscrolledup;
@ -1027,8 +1009,6 @@ static void HU_sendChatMessage(void)
} }
} }
#endif
void HU_clearChatChars(void) void HU_clearChatChars(void)
{ {
memset(w_chat, '\0', sizeof(w_chat)); memset(w_chat, '\0', sizeof(w_chat));
@ -1043,9 +1023,7 @@ void HU_clearChatChars(void)
// //
boolean HU_Responder(event_t *ev) boolean HU_Responder(event_t *ev)
{ {
#ifndef NONET
INT32 c=0; INT32 c=0;
#endif
if (ev->type != ev_keydown) if (ev->type != ev_keydown)
return false; return false;
@ -1072,7 +1050,6 @@ boolean HU_Responder(event_t *ev)
return false; return false;
}*/ //We don't actually care about that unless we get splitscreen netgames. :V }*/ //We don't actually care about that unless we get splitscreen netgames. :V
#ifndef NONET
c = (INT32)ev->key; c = (INT32)ev->key;
if (!chat_on) if (!chat_on)
@ -1222,7 +1199,6 @@ boolean HU_Responder(event_t *ev)
return true; return true;
} }
#endif
return false; return false;
} }
@ -1232,8 +1208,6 @@ boolean HU_Responder(event_t *ev)
// HEADS UP DRAWING // HEADS UP DRAWING
//====================================================================== //======================================================================
#ifndef NONET
// Precompile a wordwrapped string to any given width. // Precompile a wordwrapped string to any given width.
// This is a muuuch better method than V_WORDWRAP. // This is a muuuch better method than V_WORDWRAP.
// again stolen and modified a bit from video.c, don't mind me, will need to rearrange this one day. // again stolen and modified a bit from video.c, don't mind me, will need to rearrange this one day.
@ -1813,7 +1787,6 @@ static void HU_DrawChat_Old(void)
if (hu_tick < 4) if (hu_tick < 4)
V_DrawCharacter(HU_INPUTX + c, y, '_' | cv_constextsize.value |V_NOSCALESTART|t, true); V_DrawCharacter(HU_INPUTX + c, y, '_' | cv_constextsize.value |V_NOSCALESTART|t, true);
} }
#endif
// Draw crosshairs at the exact center of the view. // Draw crosshairs at the exact center of the view.
// In splitscreen, crosshairs are stretched vertically to compensate for V_PERPLAYER squishing them. // In splitscreen, crosshairs are stretched vertically to compensate for V_PERPLAYER squishing them.
@ -1953,7 +1926,6 @@ static void HU_DrawDemoInfo(void)
// //
void HU_Drawer(void) void HU_Drawer(void)
{ {
#ifndef NONET
// draw chat string plus cursor // draw chat string plus cursor
if (chat_on) if (chat_on)
{ {
@ -1970,7 +1942,6 @@ void HU_Drawer(void)
if (!OLDCHAT && cv_consolechat.value < 2 && netgame) // Don't display minimized chat if you set the mode to Window (Hidden) if (!OLDCHAT && cv_consolechat.value < 2 && netgame) // Don't display minimized chat if you set the mode to Window (Hidden)
HU_drawMiniChat(); // draw messages in a cool fashion. HU_drawMiniChat(); // draw messages in a cool fashion.
} }
#endif
if (cechotimer) if (cechotimer)
HU_DrawCEcho(); HU_DrawCEcho();
@ -2025,7 +1996,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;

View file

@ -17,7 +17,7 @@
#include "command.h" #include "command.h"
#include "doomtype.h" #include "doomtype.h"
#include "d_netcmd.h" #include "netcode/d_netcmd.h"
#include "m_fixed.h" #include "m_fixed.h"
#include "i_system.h" #include "i_system.h"

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,10 +21584,9 @@ 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
{"Meteorite", { 0, 4, 8, 9, 11, 12, 14, 15, 171, 172, 173, 174, 175, 27, 29, 31}, SKINCOLOR_TOPAZ, 15, V_GRAYMAP, true}, // SKINCOLOR_METEORITE {"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
{"Mercury", { 0, 3, 4, 7, 11, 12, 14, 15, 171, 172, 173, 155, 157, 159, 253, 254}, SKINCOLOR_ECRU, 15, V_AZUREMAP, true}, // SKINCOLOR_MERCURY
{"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 {"Bluebell", {0x90, 0x91, 0x92, 0x93, 0x94, 0x94, 0x95, 0xac, 0xac, 0xad, 0xad, 0xa8, 0xa8, 0xa9, 0xfd, 0xfe}, SKINCOLOR_COPPER, 4, V_BLUEMAP, true}, // SKINCOLOR_BLUEBELL
{"Pink", {0xd0, 0xd0, 0xd1, 0xd1, 0xd2, 0xd2, 0xd3, 0xd3, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0x2b, 0x2c, 0x2e}, SKINCOLOR_AZURE, 9, V_REDMAP, true}, // SKINCOLOR_PINK {"Pink", {0xd0, 0xd0, 0xd1, 0xd1, 0xd2, 0xd2, 0xd3, 0xd3, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0x2b, 0x2c, 0x2e}, SKINCOLOR_AZURE, 9, V_REDMAP, true}, // SKINCOLOR_PINK
{"Rosewood", { 209, 210, 211, 212, 213, 214, 228, 230, 232, 234, 235, 237, 26, 27, 28, 29}, SKINCOLOR_SEPIA, 5, V_BROWNMAP, true}, // SKINCOLOR_ROSEWOOD {"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
@ -21597,37 +21596,37 @@ skincolor_t skincolors[MAXSKINCOLORS] = {
{"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 {"Boulder", {0xde, 0xe0, 0xe1, 0xe4, 0xe7, 0xe9, 0xeb, 0xec, 0xed, 0xed, 0xed, 0x19, 0x19, 0x1b, 0x1d, 0x1e}, SKINCOLOR_KETCHUP, 0, V_BROWNMAP, true}, // SKINCOLOR_BOULDER
{"Bronze", { 82, 84, 50, 51, 223, 228, 230, 232, 234, 236, 237, 238, 239, 239, 30, 31}, SKINCOLOR_VOLCANIC, 9, V_BROWNMAP, true}, // SKINCOLOR_BRONZE {"Bronze", { 82, 84, 50, 51, 223, 228, 230, 232, 234, 236, 237, 238, 239, 239, 30, 31}, SKINCOLOR_VOLCANIC, 9, V_BROWNMAP, true}, // SKINCOLOR_BRONZE
{"Sepia", { 88, 84, 85, 86, 224, 226, 228, 230, 232, 235, 236, 237, 238, 239, 28, 28}, SKINCOLOR_ROSEWOOD, 5, V_BROWNMAP, true}, // SKINCOLOR_SEPIA {"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_MERCURY, 15, V_BROWNMAP, true}, // SKINCOLOR_ECRU {"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 {"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 {"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 {"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 {"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 {"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 {"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_HEADLIGHT, 8, V_PURPLEMAP, true}, // SKINCOLOR_LAVENDER {"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, sphere, Alice, MotorRoach 26/10/22) // 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 {"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_GREEN, 10, V_REDMAP, true}, // SKINCOLOR_PEPPER {"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_MASTER, 8, 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
{"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 {"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 {"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, 195, 196, 186, 187, 30}, SKINCOLOR_DREAM, 6, V_ORANGEMAP, true}, // SKINCOLOR_FOUNDATION {"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", { 49, 50, 51, 52, 53, 54, 55, 57, 58, 59, 60, 42, 44, 45, 46, 46}, 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
{"Pumpkin", { 51, 52, 53, 54, 56, 58, 59, 59, 61, 61, 63, 45, 46, 47, 47, 31}, SKINCOLOR_ARCTIC, 12, V_ORANGEMAP, true}, // SKINCOLOR_PUMPKIN
{"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
{"Gold", {0x51, 0x51, 0x54, 0x54, 0x41, 0x42, 0x43, 0x43, 0x44, 0x45, 0x46, 0x3f, 0x2d, 0x2e, 0x2f, 0x2f}, SKINCOLOR_MAUVE, 8, V_YELLOWMAP, true}, // SKINCOLOR_GOLD {"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_METEORITE, 10, V_YELLOWMAP, true}, // SKINCOLOR_TOPAZ {"Topaz", { 0, 81, 83, 73, 74, 74, 65, 52, 53, 54, 56, 58, 60, 42, 43, 45}, SKINCOLOR_MOONSTONE, 10, V_YELLOWMAP, true}, // SKINCOLOR_TOPAZ
{"Gold", {0x51, 0x51, 0x54, 0x54, 0x41, 0x42, 0x43, 0x43, 0x44, 0x45, 0x46, 0x3f, 0x2d, 0x2e, 0x2f, 0x2f}, SKINCOLOR_LAVENDER, 10, V_YELLOWMAP, true}, // SKINCOLOR_GOLD
{"Sandy", {0x53, 0x40, 0x41, 0x42, 0x43, 0xe6, 0xe9, 0xe9, 0xea, 0xec, 0xec, 0xc6, 0xc6, 0xc7, 0xc7, 0xfe}, SKINCOLOR_SKY, 8, V_YELLOWMAP, true}, // SKINCOLOR_SANDY {"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 {"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
@ -21637,20 +21636,21 @@ skincolor_t skincolors[MAXSKINCOLORS] = {
{"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 {"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_PEPPER, 8, 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
{"Shamrock", {0x70, 0x70, 0x71, 0x71, 0x72, 0x72, 0x73, 0x73, 0x73, 0x74, 0x75, 0x75, 0x76, 0x76, 0x77, 0x77}, SKINCOLOR_CRYSTAL, 10, V_GREENMAP, true}, // SKINCOLOR_SHAMROCK {"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_ROSY, 7, V_GREENMAP, true}, // SKINCOLOR_JADE {"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
{"Headlight", { 0, 80, 81, 82, 73, 84, 64, 65, 91, 91, 124, 125, 126, 137, 138, 139}, SKINCOLOR_LAVENDER, 10, V_YELLOWMAP, true}, // SKINCOLOR_HEADLIGHT
{"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
{"Master", { 0, 80, 88, 96, 112, 113, 99, 100, 124, 125, 126, 117, 107, 118, 119, 111}, SKINCOLOR_RED, 6, V_GREENMAP, true}, // SKINCOLOR_MASTER {"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 {"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
{"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
{"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 {"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 {"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
{"Aqua", {0x78, 0x79, 0x7a, 0x7a, 0x7b, 0x7b, 0x7c, 0x7c, 0x7c, 0x7d, 0x7e, 0x7e, 0x7f, 0x7f, 0x76, 0x77}, SKINCOLOR_TAFFY, 10, V_AQUAMAP, true}, // SKINCOLOR_AQUA {"Bottle", { 0, 1, 3, 4, 5, 140, 141, 141, 124, 125, 126, 127, 118, 119, 111, 111}, SKINCOLOR_LATTE, 14, V_AQUAMAP, true}, // SKINCOLOR_BOTTLE
{"Aqua", {0x78, 0x79, 0x7a, 0x7a, 0x7b, 0x7b, 0x7c, 0x7c, 0x7c, 0x7d, 0x7e, 0x7e, 0x7f, 0x7f, 0x76, 0x77}, SKINCOLOR_ROSY, 7, V_AQUAMAP, true}, // SKINCOLOR_AQUA
{"Teal", {0x78, 0x78, 0x8c, 0x8c, 0x8d, 0x8d, 0x8d, 0x8e, 0x8e, 0x8f, 0x8f, 0x8f, 0x8a, 0x8a, 0x8a, 0x8a}, SKINCOLOR_PEACHY, 7, V_SKYMAP, true}, // SKINCOLOR_TEAL {"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 {"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
@ -21661,12 +21661,12 @@ skincolor_t skincolors[MAXSKINCOLORS] = {
{"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 {"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
{"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 {"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_SKYMAP, true}, // SKINCOLOR_SAPPHIRE {"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, 146, 146, 147, 148, 148, 149, 150, 153, 156, 159, 253, 254}, SKINCOLOR_PUMPKIN, 6, V_BLUEMAP, true}, // SKINCOLOR_ARCTIC {"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", { 145, 147, 149, 150, 151, 153, 154, 155, 156, 157, 158, 159, 253, 253, 254, 254}, 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, 155, 156, 157, 159, 253, 253, 254, 254, 31, 31}, SKINCOLOR_CHERRY, 10, V_GRAYMAP, true}, // SKINCOLOR_MIDNIGHT {"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 {"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
@ -21676,21 +21676,21 @@ skincolor_t skincolors[MAXSKINCOLORS] = {
{"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 {"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 {"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 {"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
{"Crystal", { 252, 177, 179, 180, 181, 181, 182, 182, 183, 164, 166, 167, 167, 168, 169, 159}, SKINCOLOR_EMERALD, 8, V_MAGENTAMAP, true}, // SKINCOLOR_CRYSTAL {"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 {"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_GOLD, 4, V_PURPLEMAP, true}, // SKINCOLOR_MAUVE {"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 {"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_AQUA, 1, V_ROSYMAP, true}, // SKINCOLOR_TAFFY {"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_JADE, 8, 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 {"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 {"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", { 35, 38, 41, 42, 44, 46, 46, 169, 169, 159, 253, 254, 30, 30, 31, 31}, SKINCOLOR_BRONZE, 9, V_REDMAP, true}, // SKINCOLOR_VOLCANIC {"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

@ -26,11 +26,11 @@
#include "y_inter.h" #include "y_inter.h"
#include "hu_stuff.h" // HU_AddChatText #include "hu_stuff.h" // HU_AddChatText
#include "console.h" #include "console.h"
#include "d_netcmd.h" // IsPlayerAdmin #include "netcode/d_netcmd.h" // IsPlayerAdmin
#include "m_menu.h" // Player Setup menu color stuff #include "m_menu.h" // Player Setup menu color stuff
#include "m_misc.h" // M_MapNumber #include "m_misc.h" // M_MapNumber
#include "b_bot.h" // B_UpdateBotleader #include "b_bot.h" // B_UpdateBotleader
#include "d_clisrv.h" // CL_RemovePlayer #include "netcode/d_clisrv.h" // CL_RemovePlayer
#include "i_system.h" // I_GetPreciseTime, I_GetPrecisePrecision #include "i_system.h" // I_GetPreciseTime, I_GetPrecisePrecision
#include "lua_script.h" #include "lua_script.h"
@ -3566,7 +3566,7 @@ static int lib_gAddGametype(lua_State *L)
// Partly lifted from Got_AddPlayer // Partly lifted from Got_AddPlayer
static int lib_gAddPlayer(lua_State *L) static int lib_gAddPlayer(lua_State *L)
{ {
INT16 i, newplayernum, botcount = 1; INT16 i, newplayernum;
player_t *newplayer; player_t *newplayer;
SINT8 skinnum = 0, bot; SINT8 skinnum = 0, bot;
@ -3574,10 +3574,8 @@ static int lib_gAddPlayer(lua_State *L)
{ {
if (!playeringame[i]) if (!playeringame[i])
break; break;
if (players[i].bot)
botcount++; // How many of us are there already?
} }
if (i >= MAXPLAYERS) if (i >= MAXPLAYERS)
{ {
lua_pushnil(L); lua_pushnil(L);
@ -3848,7 +3846,7 @@ static int lib_gDoReborn(lua_State *L)
} }
// Another Lua function that doesn't actually exist! // Another Lua function that doesn't actually exist!
// Sets nextmapoverride & skipstats without instantly ending the level, for instances where other sources should be exiting the level, like normal signposts. // Sets nextmapoverride, skipstats and nextgametype without instantly ending the level, for instances where other sources should be exiting the level, like normal signposts.
static int lib_gSetCustomExitVars(lua_State *L) static int lib_gSetCustomExitVars(lua_State *L)
{ {
int n = lua_gettop(L); // Num arguments int n = lua_gettop(L); // Num arguments
@ -3857,18 +3855,21 @@ static int lib_gSetCustomExitVars(lua_State *L)
// LUA EXTENSION: Custom exit like support // LUA EXTENSION: Custom exit like support
// Supported: // Supported:
// G_SetCustomExitVars(); [reset to defaults] // G_SetCustomExitVars(); [reset to defaults]
// G_SetCustomExitVars(int) [nextmap override only] // G_SetCustomExitVars(int) [nextmap override only]
// G_SetCustomExitVars(nil, int) [skipstats only] // G_SetCustomExitVars(nil, int) [skipstats only]
// G_SetCustomExitVars(int, int) [both of the above] // G_SetCustomExitVars(int, int) [both of the above]
// G_SetCustomExitVars(int, int, int) [nextmapoverride, skipstats and nextgametype]
nextmapoverride = 0; nextmapoverride = 0;
skipstats = 0; skipstats = 0;
nextgametype = -1;
if (n >= 1) if (n >= 1)
{ {
nextmapoverride = (INT16)luaL_optinteger(L, 1, 0); nextmapoverride = (INT16)luaL_optinteger(L, 1, 0);
skipstats = (INT16)luaL_optinteger(L, 2, 0); skipstats = (INT16)luaL_optinteger(L, 2, 0);
nextgametype = (INT16)luaL_optinteger(L, 3, -1);
} }
return 0; return 0;

View file

@ -16,6 +16,7 @@
#include "g_game.h" #include "g_game.h"
#include "byteptr.h" #include "byteptr.h"
#include "z_zone.h" #include "z_zone.h"
#include "netcode/net_command.h"
#include "lua_script.h" #include "lua_script.h"
#include "lua_libs.h" #include "lua_libs.h"
@ -615,7 +616,7 @@ static int cvar_get(lua_State *L)
break; break;
default: default:
if (devparm) if (devparm)
return luaL_error(L, LUA_QL("consvar_t") " has no field named " LUA_QS, field); return luaL_error(L, LUA_QL("consvar_t") " has no field named " LUA_QS ".", lua_tostring(L, 2));
else else
return 0; return 0;
} }

View file

@ -24,7 +24,7 @@
#include "lua_hud.h" // hud_running errors #include "lua_hud.h" // hud_running errors
#include "m_perfstats.h" #include "m_perfstats.h"
#include "d_netcmd.h" // for cv_perfstats #include "netcode/d_netcmd.h" // for cv_perfstats
#include "i_system.h" // I_GetPreciseTime #include "i_system.h" // I_GetPreciseTime
/* ========================================================================= /* =========================================================================

View file

@ -282,7 +282,6 @@ static int patch_get(lua_State *L)
patch_t *patch = *((patch_t **)luaL_checkudata(L, 1, META_PATCH)); patch_t *patch = *((patch_t **)luaL_checkudata(L, 1, META_PATCH));
enum patch field = Lua_optoption(L, 2, -1, patch_fields_ref); enum patch field = Lua_optoption(L, 2, -1, patch_fields_ref);
// patches are invalidated when switching renderers
if (!patch) { if (!patch) {
if (field == patch_valid) { if (field == patch_valid) {
lua_pushboolean(L, 0); lua_pushboolean(L, 0);
@ -436,7 +435,7 @@ static int camera_set(lua_State *L)
cam->momz = luaL_checkfixed(L, 3); cam->momz = luaL_checkfixed(L, 3);
break; break;
default: default:
return luaL_error(L, LUA_QL("camera_t") " has no field named " LUA_QS, camera_opt[field]); return luaL_error(L, LUA_QL("camera_t") " has no field named " LUA_QS ".", lua_tostring(L, 2));
} }
return 0; return 0;
} }
@ -1487,7 +1486,6 @@ void LUA_SetHudHook(int hook, huddrawlist_h list)
break; break;
case HUD_HOOK(intermission): case HUD_HOOK(intermission):
lua_pushboolean(gL, intertype == int_spec && lua_pushboolean(gL, stagefailed);
stagefailed);
} }
} }

View file

@ -805,8 +805,9 @@ static int sector_set(lua_State *L)
case sector_fslope: // f_slope case sector_fslope: // f_slope
case sector_cslope: // c_slope case sector_cslope: // c_slope
case sector_friction: // friction case sector_friction: // friction
default:
return luaL_error(L, "sector_t field " LUA_QS " cannot be set.", sector_opt[field]); return luaL_error(L, "sector_t field " LUA_QS " cannot be set.", sector_opt[field]);
default:
return luaL_error(L, "sector_t has no field named " LUA_QS ".", lua_tostring(L, 2));
case sector_floorheight: { // floorheight case sector_floorheight: { // floorheight
boolean flag; boolean flag;
mobj_t *ptmthing = tmthing; mobj_t *ptmthing = tmthing;
@ -1284,8 +1285,9 @@ static int side_set(lua_State *L)
case side_sector: case side_sector:
case side_special: case side_special:
case side_text: case side_text:
default:
return luaL_error(L, "side_t field " LUA_QS " cannot be set.", side_opt[field]); return luaL_error(L, "side_t field " LUA_QS " cannot be set.", side_opt[field]);
default:
return luaL_error(L, "side_t has no field named " LUA_QS ".", lua_tostring(L, 2));
case side_textureoffset: case side_textureoffset:
side->textureoffset = luaL_checkfixed(L, 3); side->textureoffset = luaL_checkfixed(L, 3);
break; break;
@ -2296,8 +2298,9 @@ static int ffloor_set(lua_State *L)
case ffloor_target: // target case ffloor_target: // target
case ffloor_next: // next case ffloor_next: // next
case ffloor_prev: // prev case ffloor_prev: // prev
default:
return luaL_error(L, "ffloor_t field " LUA_QS " cannot be set.", ffloor_opt[field]); return luaL_error(L, "ffloor_t field " LUA_QS " cannot be set.", ffloor_opt[field]);
default:
return luaL_error(L, "ffloor_t has no field named " LUA_QS ".", lua_tostring(L, 2));
case ffloor_topheight: { // topheight case ffloor_topheight: { // topheight
boolean flag; boolean flag;
fixed_t lastpos = *ffloor->topheight; fixed_t lastpos = *ffloor->topheight;
@ -2431,8 +2434,9 @@ static int slope_set(lua_State *L)
case slope_d: // d case slope_d: // d
case slope_flags: // flags case slope_flags: // flags
case slope_normal: // normal case slope_normal: // normal
default:
return luaL_error(L, "pslope_t field " LUA_QS " cannot be set.", slope_opt[field]); return luaL_error(L, "pslope_t field " LUA_QS " cannot be set.", slope_opt[field]);
default:
return luaL_error(L, "pslope_t has no field named " LUA_QS ".", lua_tostring(L, 2));
case slope_o: { // o case slope_o: { // o
luaL_checktype(L, 3, LUA_TTABLE); luaL_checktype(L, 3, LUA_TTABLE);

View file

@ -925,6 +925,8 @@ enum mapthing_e {
mapthing_type, mapthing_type,
mapthing_options, mapthing_options,
mapthing_scale, mapthing_scale,
mapthing_spritexscale,
mapthing_spriteyscale,
mapthing_z, mapthing_z,
mapthing_extrainfo, mapthing_extrainfo,
mapthing_tag, mapthing_tag,
@ -944,6 +946,8 @@ const char *const mapthing_opt[] = {
"type", "type",
"options", "options",
"scale", "scale",
"spritexscale",
"spriteyscale",
"z", "z",
"extrainfo", "extrainfo",
"tag", "tag",
@ -999,7 +1003,13 @@ static int mapthing_get(lua_State *L)
lua_pushinteger(L, mt->options); lua_pushinteger(L, mt->options);
break; break;
case mapthing_scale: case mapthing_scale:
lua_pushinteger(L, mt->scale); lua_pushfixed(L, mt->scale);
break;
case mapthing_spritexscale:
lua_pushfixed(L, mt->spritexscale);
break;
case mapthing_spriteyscale:
lua_pushfixed(L, mt->spriteyscale);
break; break;
case mapthing_z: case mapthing_z:
lua_pushinteger(L, mt->z); lua_pushinteger(L, mt->z);
@ -1072,6 +1082,12 @@ static int mapthing_set(lua_State *L)
case mapthing_scale: case mapthing_scale:
mt->scale = luaL_checkfixed(L, 3); mt->scale = luaL_checkfixed(L, 3);
break; break;
case mapthing_spritexscale:
mt->spritexscale = luaL_checkfixed(L, 3);
break;
case mapthing_spriteyscale:
mt->spriteyscale = luaL_checkfixed(L, 3);
break;
case mapthing_z: case mapthing_z:
mt->z = (INT16)luaL_checkinteger(L, 3); mt->z = (INT16)luaL_checkinteger(L, 3);
break; break;

View file

@ -28,7 +28,7 @@
#include "p_slopes.h" // for P_SlopeById and slopelist #include "p_slopes.h" // for P_SlopeById and slopelist
#include "p_polyobj.h" // polyobj_t, PolyObjects #include "p_polyobj.h" // polyobj_t, PolyObjects
#ifdef LUA_ALLOW_BYTECODE #ifdef LUA_ALLOW_BYTECODE
#include "d_netfil.h" // for LUA_DumpFile #include "netcode/d_netfil.h" // for LUA_DumpFile
#endif #endif
#include "lua_script.h" #include "lua_script.h"

View file

@ -25,6 +25,7 @@ enum skin {
skin_flags, skin_flags,
skin_realname, skin_realname,
skin_hudname, skin_hudname,
skin_supername,
skin_ability, skin_ability,
skin_ability2, skin_ability2,
skin_thokitem, skin_thokitem,
@ -63,6 +64,7 @@ static const char *const skin_opt[] = {
"flags", "flags",
"realname", "realname",
"hudname", "hudname",
"supername",
"ability", "ability",
"ability2", "ability2",
"thokitem", "thokitem",
@ -126,6 +128,9 @@ static int skin_get(lua_State *L)
case skin_hudname: case skin_hudname:
lua_pushstring(L, skin->hudname); lua_pushstring(L, skin->hudname);
break; break;
case skin_supername:
lua_pushstring(L, skin->supername);
break;
case skin_ability: case skin_ability:
lua_pushinteger(L, skin->ability); lua_pushinteger(L, skin->ability);
break; break;

View file

@ -19,7 +19,7 @@
#include "r_local.h" #include "r_local.h"
#include "p_local.h" #include "p_local.h"
#include "p_setup.h" #include "p_setup.h"
#include "d_net.h" #include "netcode/d_net.h"
#include "m_cheat.h" #include "m_cheat.h"
#include "m_menu.h" #include "m_menu.h"
@ -1102,6 +1102,8 @@ static mapthing_t *OP_CreateNewMapThing(player_t *player, UINT16 type, boolean c
mt->options = (mt->z << ZSHIFT) | (UINT16)cv_opflags.value; mt->options = (mt->z << ZSHIFT) | (UINT16)cv_opflags.value;
mt->scale = player->mo->scale; mt->scale = player->mo->scale;
mt->spritexscale = player->mo->spritexscale;
mt->spriteyscale = player->mo->spriteyscale;
memset(mt->args, 0, NUMMAPTHINGARGS*sizeof(*mt->args)); memset(mt->args, 0, NUMMAPTHINGARGS*sizeof(*mt->args));
memset(mt->stringargs, 0x00, NUMMAPTHINGSTRINGARGS*sizeof(*mt->stringargs)); memset(mt->stringargs, 0x00, NUMMAPTHINGSTRINGARGS*sizeof(*mt->stringargs));
mt->pitch = mt->roll = 0; mt->pitch = mt->roll = 0;

View file

@ -467,6 +467,15 @@ UINT8 M_SecretUnlocked(INT32 type, gamedata_t *data)
UINT8 M_MapLocked(INT32 mapnum, gamedata_t *data) UINT8 M_MapLocked(INT32 mapnum, gamedata_t *data)
{ {
if (dedicated)
{
// If you're in a dedicated server, every level is unlocked.
// Yes, technically this means you can view any level by
// running a dedicated server and joining it yourself, but
// that's better than making dedicated server's lives hell.
return false;
}
if (!mapheaderinfo[mapnum-1] || mapheaderinfo[mapnum-1]->unlockrequired < 0) if (!mapheaderinfo[mapnum-1] || mapheaderinfo[mapnum-1]->unlockrequired < 0)
{ {
return false; return false;
@ -480,6 +489,48 @@ UINT8 M_MapLocked(INT32 mapnum, gamedata_t *data)
return false; return false;
} }
UINT8 M_CampaignWarpIsCheat(INT32 gt, INT32 mapnum, gamedata_t *data)
{
if (M_MapLocked(mapnum, data) == true)
{
// Warping to locked maps is definitely always a cheat
return true;
}
if ((gametypedefaultrules[gt] & GTR_CAMPAIGN) == 0)
{
// Not a campaign, do whatever you want.
return false;
}
if (G_IsSpecialStage(mapnum))
{
// Warping to special stages is a cheat
return true;
}
if (!mapheaderinfo[mapnum-1] || mapheaderinfo[mapnum-1]->menuflags & LF2_HIDEINMENU)
{
// You're never allowed to warp to this level.
return true;
}
if (mapheaderinfo[mapnum-1]->menuflags & LF2_NOVISITNEEDED)
{
// You're always allowed to warp to this level.
return false;
}
if (mapnum == spstage_start)
{
// Warping to the first level is never a cheat
return false;
}
// It's only a cheat if you've never been there.
return (!(data->mapvisited[mapnum-1]));
}
INT32 M_CountEmblems(gamedata_t *data) INT32 M_CountEmblems(gamedata_t *data)
{ {
INT32 found = 0, i; INT32 found = 0, i;

View file

@ -252,6 +252,7 @@ void M_SilentUpdateSkinAvailabilites(void);
UINT8 M_AnySecretUnlocked(gamedata_t *data); UINT8 M_AnySecretUnlocked(gamedata_t *data);
UINT8 M_SecretUnlocked(INT32 type, gamedata_t *data); UINT8 M_SecretUnlocked(INT32 type, gamedata_t *data);
UINT8 M_MapLocked(INT32 mapnum, gamedata_t *data); UINT8 M_MapLocked(INT32 mapnum, gamedata_t *data);
UINT8 M_CampaignWarpIsCheat(INT32 gt, INT32 mapnum, gamedata_t *data);
INT32 M_CountEmblems(gamedata_t *data); INT32 M_CountEmblems(gamedata_t *data);
// Emblem shit // Emblem shit

View file

@ -20,7 +20,7 @@
#include "doomdef.h" #include "doomdef.h"
#include "d_main.h" #include "d_main.h"
#include "d_netcmd.h" #include "netcode/d_netcmd.h"
#include "console.h" #include "console.h"
#include "r_fps.h" #include "r_fps.h"
#include "r_local.h" #include "r_local.h"
@ -53,8 +53,10 @@
#include "hardware/hw_main.h" #include "hardware/hw_main.h"
#endif #endif
#include "d_net.h" #include "netcode/d_net.h"
#include "mserv.h" #include "netcode/mserv.h"
#include "netcode/server_connection.h"
#include "netcode/client_connection.h"
#include "m_misc.h" #include "m_misc.h"
#include "m_anigif.h" #include "m_anigif.h"
#include "byteptr.h" #include "byteptr.h"
@ -149,9 +151,7 @@ levellist_mode_t levellistmode = LLM_CREATESERVER;
UINT8 maplistoption = 0; UINT8 maplistoption = 0;
static char joystickInfo[MAX_JOYSTICKS+1][29]; static char joystickInfo[MAX_JOYSTICKS+1][29];
#ifndef NONET
static UINT32 serverlistpage; static UINT32 serverlistpage;
#endif
static UINT8 numsaves = 0; static UINT8 numsaves = 0;
static saveinfo_t* savegameinfo = NULL; // Extra info about the save games. static saveinfo_t* savegameinfo = NULL; // Extra info about the save games.
@ -190,10 +190,8 @@ static void M_GoBack(INT32 choice);
static void M_StopMessage(INT32 choice); static void M_StopMessage(INT32 choice);
static boolean stopstopmessage = false; static boolean stopstopmessage = false;
#ifndef NONET
static void M_HandleServerPage(INT32 choice); static void M_HandleServerPage(INT32 choice);
static void M_RoomMenu(INT32 choice); static void M_RoomMenu(INT32 choice);
#endif
// Prototyping is fun, innit? // Prototyping is fun, innit?
// ========================================================================== // ==========================================================================
@ -296,7 +294,6 @@ static void M_SetupMultiPlayer2(INT32 choice);
static void M_StartSplitServerMenu(INT32 choice); static void M_StartSplitServerMenu(INT32 choice);
static void M_StartServer(INT32 choice); static void M_StartServer(INT32 choice);
static void M_ServerOptions(INT32 choice); static void M_ServerOptions(INT32 choice);
#ifndef NONET
static void M_StartServerMenu(INT32 choice); static void M_StartServerMenu(INT32 choice);
static void M_ConnectMenu(INT32 choice); static void M_ConnectMenu(INT32 choice);
static void M_ConnectMenuModChecks(INT32 choice); static void M_ConnectMenuModChecks(INT32 choice);
@ -304,7 +301,6 @@ static void M_Refresh(INT32 choice);
static void M_Connect(INT32 choice); static void M_Connect(INT32 choice);
static void M_ChooseRoom(INT32 choice); static void M_ChooseRoom(INT32 choice);
menu_t MP_MainDef; menu_t MP_MainDef;
#endif
// Options // Options
// Split into multiple parts due to size // Split into multiple parts due to size
@ -382,11 +378,9 @@ static void M_DrawVideoMode(void);
static void M_DrawColorMenu(void); static void M_DrawColorMenu(void);
static void M_DrawScreenshotMenu(void); static void M_DrawScreenshotMenu(void);
static void M_DrawMonitorToggles(void); static void M_DrawMonitorToggles(void);
#ifndef NONET
static void M_DrawConnectMenu(void); static void M_DrawConnectMenu(void);
static void M_DrawMPMainMenu(void); static void M_DrawMPMainMenu(void);
static void M_DrawRoomMenu(void); static void M_DrawRoomMenu(void);
#endif
static void M_DrawJoystick(void); static void M_DrawJoystick(void);
static void M_DrawSetupMultiPlayerMenu(void); static void M_DrawSetupMultiPlayerMenu(void);
static void M_DrawColorRamp(INT32 x, INT32 y, INT32 w, INT32 h, skincolor_t color); static void M_DrawColorRamp(INT32 x, INT32 y, INT32 w, INT32 h, skincolor_t color);
@ -401,10 +395,8 @@ static void M_HandleImageDef(INT32 choice);
static void M_HandleLoadSave(INT32 choice); static void M_HandleLoadSave(INT32 choice);
static void M_HandleLevelStats(INT32 choice); static void M_HandleLevelStats(INT32 choice);
static void M_HandlePlaystyleMenu(INT32 choice); static void M_HandlePlaystyleMenu(INT32 choice);
#ifndef NONET
static boolean M_CancelConnect(void); static boolean M_CancelConnect(void);
static void M_HandleConnectIP(INT32 choice); static void M_HandleConnectIP(INT32 choice);
#endif
static void M_HandleSetupMultiPlayer(INT32 choice); static void M_HandleSetupMultiPlayer(INT32 choice);
static void M_HandleVideoMode(INT32 choice); static void M_HandleVideoMode(INT32 choice);
@ -503,11 +495,7 @@ consvar_t cv_dummyloadless = CVAR_INIT ("dummyloadless", "In-game", CV_HIDEN, lo
static menuitem_t MainMenu[] = static menuitem_t MainMenu[] =
{ {
{IT_STRING|IT_CALL, NULL, "1 Player", M_SinglePlayerMenu, 76}, {IT_STRING|IT_CALL, NULL, "1 Player", M_SinglePlayerMenu, 76},
#ifndef NONET
{IT_STRING|IT_SUBMENU, NULL, "Multiplayer", &MP_MainDef, 84}, {IT_STRING|IT_SUBMENU, NULL, "Multiplayer", &MP_MainDef, 84},
#else
{IT_STRING|IT_CALL, NULL, "Multiplayer", M_StartSplitServerMenu, 84},
#endif
{IT_STRING|IT_CALL, NULL, "Extras", M_SecretsMenu, 92}, {IT_STRING|IT_CALL, NULL, "Extras", M_SecretsMenu, 92},
{IT_CALL |IT_STRING, NULL, "Addons", M_Addons, 100}, {IT_CALL |IT_STRING, NULL, "Addons", M_Addons, 100},
{IT_STRING|IT_CALL, NULL, "Options", M_Options, 108}, {IT_STRING|IT_CALL, NULL, "Options", M_Options, 108},
@ -930,16 +918,10 @@ static menuitem_t SP_PlayerMenu[] =
static menuitem_t MP_SplitServerMenu[] = static menuitem_t MP_SplitServerMenu[] =
{ {
{IT_STRING|IT_CALL, NULL, "Select Gametype/Level...", M_MapChange, 100}, {IT_STRING|IT_CALL, NULL, "Select Gametype/Level...", M_MapChange, 100},
#ifdef NONET // In order to keep player setup accessible.
{IT_STRING|IT_CALL, NULL, "Player 1 setup...", M_SetupMultiPlayer, 110},
{IT_STRING|IT_CALL, NULL, "Player 2 setup...", M_SetupMultiPlayer2, 120},
#endif
{IT_STRING|IT_CALL, NULL, "More Options...", M_ServerOptions, 130}, {IT_STRING|IT_CALL, NULL, "More Options...", M_ServerOptions, 130},
{IT_WHITESTRING|IT_CALL, NULL, "Start", M_StartServer, 140}, {IT_WHITESTRING|IT_CALL, NULL, "Start", M_StartServer, 140},
}; };
#ifndef NONET
static menuitem_t MP_MainMenu[] = static menuitem_t MP_MainMenu[] =
{ {
{IT_HEADER, NULL, "Join a game", NULL, 0}, {IT_HEADER, NULL, "Join a game", NULL, 0},
@ -1026,8 +1008,6 @@ menuitem_t MP_RoomMenu[] =
{IT_DISABLED, NULL, "", M_ChooseRoom, 162}, {IT_DISABLED, NULL, "", M_ChooseRoom, 162},
}; };
#endif
static menuitem_t MP_PlayerSetupMenu[] = static menuitem_t MP_PlayerSetupMenu[] =
{ {
{IT_KEYHANDLER, NULL, "", M_HandleSetupMultiPlayer, 0}, // name {IT_KEYHANDLER, NULL, "", M_HandleSetupMultiPlayer, 0}, // name
@ -1586,14 +1566,12 @@ enum
static menuitem_t OP_ServerOptionsMenu[] = static menuitem_t OP_ServerOptionsMenu[] =
{ {
{IT_HEADER, NULL, "General", NULL, 0}, {IT_HEADER, NULL, "General", NULL, 0},
#ifndef NONET
{IT_STRING | IT_CVAR | IT_CV_STRING, {IT_STRING | IT_CVAR | IT_CV_STRING,
NULL, "Server name", &cv_servername, 7}, NULL, "Server name", &cv_servername, 7},
{IT_STRING | IT_CVAR, NULL, "Max Players", &cv_maxplayers, 21}, {IT_STRING | IT_CVAR, NULL, "Max Players", &cv_maxplayers, 21},
{IT_STRING | IT_CVAR, NULL, "Allow Add-on Downloading", &cv_downloading, 26}, {IT_STRING | IT_CVAR, NULL, "Allow Add-on Downloading", &cv_downloading, 26},
{IT_STRING | IT_CVAR, NULL, "Allow players to join", &cv_allownewplayer, 31}, {IT_STRING | IT_CVAR, NULL, "Allow players to join", &cv_allownewplayer, 31},
{IT_STRING | IT_CVAR, NULL, "Minutes for reconnecting", &cv_rejointimeout, 36}, {IT_STRING | IT_CVAR, NULL, "Minutes for reconnecting", &cv_rejointimeout, 36},
#endif
{IT_STRING | IT_CVAR, NULL, "Map progression", &cv_advancemap, 41}, {IT_STRING | IT_CVAR, NULL, "Map progression", &cv_advancemap, 41},
{IT_STRING | IT_CVAR, NULL, "Intermission Timer", &cv_inttime, 46}, {IT_STRING | IT_CVAR, NULL, "Intermission Timer", &cv_inttime, 46},
@ -1632,7 +1610,6 @@ static menuitem_t OP_ServerOptionsMenu[] =
{IT_STRING | IT_CVAR, NULL, "Autobalance sizes", &cv_autobalance, 216}, {IT_STRING | IT_CVAR, NULL, "Autobalance sizes", &cv_autobalance, 216},
{IT_STRING | IT_CVAR, NULL, "Scramble on Map Change", &cv_scrambleonchange, 221}, {IT_STRING | IT_CVAR, NULL, "Scramble on Map Change", &cv_scrambleonchange, 221},
#ifndef NONET
{IT_HEADER, NULL, "Advanced", NULL, 230}, {IT_HEADER, NULL, "Advanced", NULL, 230},
{IT_STRING | IT_CVAR | IT_CV_STRING, NULL, "Master server", &cv_masterserver, 236}, {IT_STRING | IT_CVAR | IT_CV_STRING, NULL, "Master server", &cv_masterserver, 236},
@ -1640,7 +1617,6 @@ static menuitem_t OP_ServerOptionsMenu[] =
{IT_STRING | IT_CVAR, NULL, "Attempts to resynchronise", &cv_resynchattempts, 256}, {IT_STRING | IT_CVAR, NULL, "Attempts to resynchronise", &cv_resynchattempts, 256},
{IT_STRING | IT_CVAR, NULL, "Show IP Address of Joiners", &cv_showjoinaddress, 261}, {IT_STRING | IT_CVAR, NULL, "Show IP Address of Joiners", &cv_showjoinaddress, 261},
#endif
}; };
static menuitem_t OP_MonitorToggleMenu[] = static menuitem_t OP_MonitorToggleMenu[] =
@ -1954,11 +1930,7 @@ menu_t MP_SplitServerDef =
MTREE2(MN_MP_MAIN, MN_MP_SPLITSCREEN), MTREE2(MN_MP_MAIN, MN_MP_SPLITSCREEN),
"M_MULTI", "M_MULTI",
sizeof (MP_SplitServerMenu)/sizeof (menuitem_t), sizeof (MP_SplitServerMenu)/sizeof (menuitem_t),
#ifndef NONET
&MP_MainDef, &MP_MainDef,
#else
&MainDef,
#endif
MP_SplitServerMenu, MP_SplitServerMenu,
M_DrawServerMenu, M_DrawServerMenu,
27, 30 - 50, 27, 30 - 50,
@ -1966,8 +1938,6 @@ menu_t MP_SplitServerDef =
NULL NULL
}; };
#ifndef NONET
menu_t MP_MainDef = menu_t MP_MainDef =
{ {
MN_MP_MAIN, MN_MP_MAIN,
@ -2019,15 +1989,10 @@ menu_t MP_RoomDef =
0, 0,
NULL NULL
}; };
#endif
menu_t MP_PlayerSetupDef = menu_t MP_PlayerSetupDef =
{ {
#ifdef NONET
MTREE2(MN_MP_MAIN, MN_MP_PLAYERSETUP),
#else
MTREE3(MN_MP_MAIN, MN_MP_SPLITSCREEN, MN_MP_PLAYERSETUP), MTREE3(MN_MP_MAIN, MN_MP_SPLITSCREEN, MN_MP_PLAYERSETUP),
#endif
"M_SPLAYR", "M_SPLAYR",
sizeof (MP_PlayerSetupMenu)/sizeof (menuitem_t), sizeof (MP_PlayerSetupMenu)/sizeof (menuitem_t),
&MainDef, // doesn't matter &MainDef, // doesn't matter
@ -2649,7 +2614,7 @@ static boolean MIT_SetCurBackground(UINT32 menutype, INT32 level, INT32 *retval,
{ {
strncpy(curbgname, defaultname, 9); strncpy(curbgname, defaultname, 9);
curbgxspeed = (gamestate == GS_TIMEATTACK) ? 0 : titlescrollxspeed; curbgxspeed = (gamestate == GS_TIMEATTACK) ? 0 : titlescrollxspeed;
curbgyspeed = (gamestate == GS_TIMEATTACK) ? 0 : titlescrollyspeed; curbgyspeed = (gamestate == GS_TIMEATTACK) ? 18 : titlescrollyspeed;
} }
} }
return false; return false;
@ -2787,6 +2752,7 @@ void M_SetMenuCurBackground(const char *defaultname)
{ {
char name[9]; char name[9];
strncpy(name, defaultname, 8); strncpy(name, defaultname, 8);
name[8] = '\0';
M_IterateMenuTree(MIT_SetCurBackground, &name); M_IterateMenuTree(MIT_SetCurBackground, &name);
} }
@ -2843,8 +2809,8 @@ static void M_HandleMenuPresState(menu_t *newMenu)
curfadevalue = 16; curfadevalue = 16;
curhidepics = hidetitlepics; curhidepics = hidetitlepics;
curbgcolor = -1; curbgcolor = -1;
curbgxspeed = titlescrollxspeed; curbgxspeed = (gamestate == GS_TIMEATTACK) ? 0 : titlescrollxspeed;
curbgyspeed = titlescrollyspeed; curbgyspeed = (gamestate == GS_TIMEATTACK) ? 18 : titlescrollyspeed;
curbghide = (gamestate != GS_TIMEATTACK); // show in time attack, hide in other menus curbghide = (gamestate != GS_TIMEATTACK); // show in time attack, hide in other menus
curttmode = ttmode; curttmode = ttmode;
@ -3196,7 +3162,7 @@ boolean M_Responder(event_t *ev)
|| gamestate == GS_CREDITS || gamestate == GS_EVALUATION || gamestate == GS_GAMEEND) || gamestate == GS_CREDITS || gamestate == GS_EVALUATION || gamestate == GS_GAMEEND)
return false; return false;
if (gamestate == GS_TITLESCREEN && finalecount < TICRATE) if (gamestate == GS_TITLESCREEN && finalecount < (cv_tutorialprompt.value ? TICRATE : 0))
return false; return false;
if (CON_Ready() && gamestate != GS_WAITINGPLAYERS) if (CON_Ready() && gamestate != GS_WAITINGPLAYERS)
@ -3956,9 +3922,7 @@ void M_Init(void)
OP_JoystickSetMenu[i].itemaction = M_AssignJoystick; OP_JoystickSetMenu[i].itemaction = M_AssignJoystick;
} }
#ifndef NONET
CV_RegisterVar(&cv_serversort); CV_RegisterVar(&cv_serversort);
#endif
} }
void M_InitCharacterTables(void) void M_InitCharacterTables(void)
@ -11108,7 +11072,6 @@ static void M_EndGame(INT32 choice)
#define S_LINEY(n) currentMenu->y + SERVERHEADERHEIGHT + (n * SERVERLINEHEIGHT) #define S_LINEY(n) currentMenu->y + SERVERHEADERHEIGHT + (n * SERVERLINEHEIGHT)
#ifndef NONET
static UINT32 localservercount; static UINT32 localservercount;
static void M_HandleServerPage(INT32 choice) static void M_HandleServerPage(INT32 choice)
@ -11380,11 +11343,9 @@ static int ServerListEntryComparator_modified(const void *entry1, const void *en
// Default to strcmp. // Default to strcmp.
return strcmp(sa->info.servername, sb->info.servername); return strcmp(sa->info.servername, sb->info.servername);
} }
#endif
void M_SortServerList(void) void M_SortServerList(void)
{ {
#ifndef NONET
switch(cv_serversort.value) switch(cv_serversort.value)
{ {
case 0: // Ping. case 0: // Ping.
@ -11406,10 +11367,8 @@ void M_SortServerList(void)
qsort(serverlist, serverlistcount, sizeof(serverelem_t), ServerListEntryComparator_gametypename); qsort(serverlist, serverlistcount, sizeof(serverelem_t), ServerListEntryComparator_gametypename);
break; break;
} }
#endif
} }
#ifndef NONET
#ifdef UPDATE_ALERT #ifdef UPDATE_ALERT
static boolean M_CheckMODVersion(int id) static boolean M_CheckMODVersion(int id)
{ {
@ -11608,7 +11567,6 @@ static void M_ChooseRoom(INT32 choice)
if (currentMenu == &MP_ConnectDef) if (currentMenu == &MP_ConnectDef)
M_Refresh(0); M_Refresh(0);
} }
#endif //NONET
//=========================================================================== //===========================================================================
// Start Server Menu // Start Server Menu
@ -11656,7 +11614,6 @@ static void M_DrawServerMenu(void)
{ {
M_DrawGenericMenu(); M_DrawGenericMenu();
#ifndef NONET
// Room name // Room name
if (currentMenu == &MP_ServerDef) if (currentMenu == &MP_ServerDef)
{ {
@ -11668,15 +11625,10 @@ static void M_DrawServerMenu(void)
V_DrawRightAlignedString(BASEVIDWIDTH - currentMenu->x, currentMenu->y + MP_ServerMenu[mp_server_room].alphaKey, V_DrawRightAlignedString(BASEVIDWIDTH - currentMenu->x, currentMenu->y + MP_ServerMenu[mp_server_room].alphaKey,
V_YELLOWMAP, room_list[menuRoomIndex].name); V_YELLOWMAP, room_list[menuRoomIndex].name);
} }
#endif
if (cv_nextmap.value) if (cv_nextmap.value)
{ {
#ifndef NONET
#define imgheight MP_ServerMenu[mp_server_levelgt].alphaKey #define imgheight MP_ServerMenu[mp_server_levelgt].alphaKey
#else
#define imgheight 100
#endif
patch_t *PictureOfLevel; patch_t *PictureOfLevel;
lumpnum_t lumpnum; lumpnum_t lumpnum;
char headerstr[40]; char headerstr[40];
@ -11728,7 +11680,6 @@ static void M_ServerOptions(INT32 choice)
{ {
(void)choice; (void)choice;
#ifndef NONET
if ((splitscreen && !netgame) || currentMenu == &MP_SplitServerDef) if ((splitscreen && !netgame) || currentMenu == &MP_SplitServerDef)
{ {
OP_ServerOptionsMenu[ 1].status = IT_GRAYEDOUT; // Server name OP_ServerOptionsMenu[ 1].status = IT_GRAYEDOUT; // Server name
@ -11749,7 +11700,6 @@ static void M_ServerOptions(INT32 choice)
OP_ServerOptionsMenu[37].status = IT_STRING | IT_CVAR; OP_ServerOptionsMenu[37].status = IT_STRING | IT_CVAR;
OP_ServerOptionsMenu[38].status = IT_STRING | IT_CVAR; OP_ServerOptionsMenu[38].status = IT_STRING | IT_CVAR;
} }
#endif
/* Disable fading because of different menu head. */ /* Disable fading because of different menu head. */
if (currentMenu == &OP_MainDef)/* from Options menu */ if (currentMenu == &OP_MainDef)/* from Options menu */
@ -11761,7 +11711,6 @@ static void M_ServerOptions(INT32 choice)
M_SetupNextMenu(&OP_ServerOptionsDef); M_SetupNextMenu(&OP_ServerOptionsDef);
} }
#ifndef NONET
static void M_StartServerMenu(INT32 choice) static void M_StartServerMenu(INT32 choice)
{ {
(void)choice; (void)choice;
@ -12028,7 +11977,6 @@ static void M_HandleConnectIP(INT32 choice)
M_ClearMenus(true); M_ClearMenus(true);
} }
} }
#endif //!NONET
// ======================== // ========================
// MULTIPLAYER PLAYER SETUP // MULTIPLAYER PLAYER SETUP
@ -12054,6 +12002,136 @@ static INT32 setupm_fakeskin;
static menucolor_t *setupm_fakecolor; static menucolor_t *setupm_fakecolor;
static boolean colorgrid; static boolean colorgrid;
#define COLOR_GRID_ROW_SIZE (16)
static UINT16 M_GetColorGridIndex(UINT16 color)
{
menucolor_t *look;
UINT16 i = 0;
if (!skincolors[color].accessible)
{
return 0;
}
for (look = menucolorhead; ; i++, look = look->next)
{
while (!skincolors[look->color].accessible) // skip inaccessible colors
{
if (look == menucolortail)
{
return 0;
}
look = look->next;
}
if (look->color == color)
{
return i;
}
if (look == menucolortail)
{
return 0;
}
}
}
static INT32 M_GridIndexToX(UINT16 index)
{
return (index % COLOR_GRID_ROW_SIZE);
}
static INT32 M_GridIndexToY(UINT16 index)
{
return (index / COLOR_GRID_ROW_SIZE);
}
static UINT16 M_ColorGridLen(void)
{
menucolor_t *look;
UINT16 i = 0;
for (look = menucolorhead; ; i++)
{
do
{
if (look == menucolortail)
{
return i;
}
look = look->next;
}
while (!skincolors[look->color].accessible); // skip inaccessible colors
}
}
static UINT16 M_GridPosToGridIndex(INT32 x, INT32 y)
{
const UINT16 grid_len = M_ColorGridLen();
const UINT16 grid_height = ((grid_len - 1) / COLOR_GRID_ROW_SIZE) + 1;
const UINT16 last_row_len = COLOR_GRID_ROW_SIZE - ((grid_height * COLOR_GRID_ROW_SIZE) - grid_len);
UINT16 row_len = COLOR_GRID_ROW_SIZE;
UINT16 new_index = 0;
while (y < 0)
{
y += grid_height;
}
y = (y % grid_height);
if (y >= grid_height-1 && last_row_len > 0)
{
row_len = last_row_len;
}
while (x < 0)
{
x += row_len;
}
x = (x % row_len);
new_index = (y * COLOR_GRID_ROW_SIZE) + x;
if (new_index >= grid_len)
{
new_index = grid_len - 1;
}
return new_index;
}
static menucolor_t *M_GridIndexToMenuColor(UINT16 index)
{
menucolor_t *look = menucolorhead;
UINT16 i = 0;
for (look = menucolorhead; ; i++, look = look->next)
{
while (!skincolors[look->color].accessible) // skip inaccessible colors
{
if (look == menucolortail)
{
return menucolorhead;
}
look = look->next;
}
if (i == index)
{
return look;
}
if (look == menucolortail)
{
return menucolorhead;
}
}
}
static void M_DrawSetupMultiPlayerMenu(void) static void M_DrawSetupMultiPlayerMenu(void)
{ {
INT32 x, y, cursory = 0, flags = 0; INT32 x, y, cursory = 0, flags = 0;
@ -12172,32 +12250,54 @@ colordraw:
boolean stoprow = false; boolean stoprow = false;
menucolor_t *mc; // Last accessed color menucolor_t *mc; // Last accessed color
const UINT16 grid_len = M_ColorGridLen();
const UINT16 grid_end_y = M_GridIndexToY(grid_len - 1);
INT32 grid_select = M_GetColorGridIndex(setupm_fakecolor->color);
INT32 grid_select_y = M_GridIndexToY(grid_select);
x = 132; x = 132;
y = 66; y = 66;
pos = min(max(0, 16*((M_GetColorIndex(setupm_fakecolor->color)-1)/16) - 64), 16*(M_GetColorIndex(menucolortail->color)/16-1) - 128);
mc = M_GetColorFromIndex(pos); pos = M_GridPosToGridIndex(0, max(0, min(grid_select_y - 3, grid_end_y - 7)));
mc = M_GridIndexToMenuColor(pos);
// Draw grid // Draw grid
V_DrawFill(x-2, y-2, 132, 132, 159); V_DrawFill(x-2, y-2, 132, 132, 159);
for (j = 0; j < 8; j++) for (j = 0; j < 8; j++)
{ {
for (i = 0; i < 16; i++) for (i = 0; i < COLOR_GRID_ROW_SIZE; i++)
{ {
if (skincolors[mc->color].accessible && !stoprow) if (skincolors[mc->color].accessible)
{ {
M_DrawColorRamp(x + i*w, y + j*16, w, 1, skincolors[mc->color]); M_DrawColorRamp(x + i*w, y + j*16, w, 1, skincolors[mc->color]);
if (mc->color == setupm_fakecolor->color) // store current color position
{ if (mc == setupm_fakecolor) // store current color position
cx = x + i*w; {
cy = y + j*16; cx = x + i*w;
} cy = y + j*16;
}
} }
mc = mc->next;
while (!skincolors[mc->color].accessible && !stoprow) // Find accessible color after this one if (stoprow)
{
break;
}
// Find accessible color after this one
do
{ {
mc = mc->next; mc = mc->next;
if (mc == menucolortail) stoprow = true; if (mc == menucolortail)
} {
stoprow = true;
}
} while (!skincolors[mc->color].accessible && !stoprow);
}
if (stoprow)
{
break;
} }
} }
@ -12318,15 +12418,16 @@ static void M_HandleSetupMultiPlayer(INT32 choice)
case KEY_DOWNARROW: case KEY_DOWNARROW:
case KEY_UPARROW: case KEY_UPARROW:
{ {
UINT8 i;
if (itemOn == 2 && colorgrid) if (itemOn == 2 && colorgrid)
{ {
for (i = 0; i < 16; i++) UINT16 index = M_GetColorGridIndex(setupm_fakecolor->color);
{ INT32 x = M_GridIndexToX(index);
setupm_fakecolor = (choice == KEY_UPARROW) ? setupm_fakecolor->prev : setupm_fakecolor->next; INT32 y = M_GridIndexToY(index);
while (!skincolors[setupm_fakecolor->color].accessible) // skip inaccessible colors
setupm_fakecolor = (choice == KEY_UPARROW) ? setupm_fakecolor->prev : setupm_fakecolor->next; y += (choice == KEY_UPARROW) ? -1 : 1;
}
index = M_GridPosToGridIndex(x, y);
setupm_fakecolor = M_GridIndexToMenuColor(index);
} }
else if (choice == KEY_UPARROW) else if (choice == KEY_UPARROW)
M_PrevOpt(); M_PrevOpt();
@ -12353,8 +12454,8 @@ static void M_HandleSetupMultiPlayer(INT32 choice)
} }
else if (itemOn == 2) // player color else if (itemOn == 2) // player color
{ {
S_StartSound(NULL,sfx_menu1); // Tails
setupm_fakecolor = setupm_fakecolor->prev; setupm_fakecolor = setupm_fakecolor->prev;
S_StartSound(NULL,sfx_menu1); // Tails
} }
break; break;
@ -12393,8 +12494,8 @@ static void M_HandleSetupMultiPlayer(INT32 choice)
} }
else if (itemOn == 2) // player color else if (itemOn == 2) // player color
{ {
S_StartSound(NULL,sfx_menu1); // Tails
setupm_fakecolor = setupm_fakecolor->next; setupm_fakecolor = setupm_fakecolor->next;
S_StartSound(NULL,sfx_menu1); // Tails
} }
break; break;
@ -12404,13 +12505,28 @@ static void M_HandleSetupMultiPlayer(INT32 choice)
UINT8 i; UINT8 i;
if (itemOn == 2) // player color if (itemOn == 2) // player color
{ {
S_StartSound(NULL,sfx_menu1); if (colorgrid)
for (i = 0; i < (colorgrid ? 64 : 13); i++) // or (282-charw)/(2*indexwidth)
{ {
setupm_fakecolor = (choice == KEY_PGUP) ? setupm_fakecolor->prev : setupm_fakecolor->next; UINT16 index = M_GetColorGridIndex(setupm_fakecolor->color);
while (!skincolors[setupm_fakecolor->color].accessible) // skip inaccessible colors INT32 x = M_GridIndexToX(index);
setupm_fakecolor = (choice == KEY_PGUP) ? setupm_fakecolor->prev : setupm_fakecolor->next; INT32 y = M_GridIndexToY(index);
y += (choice == KEY_UPARROW) ? -4 : 4;
index = M_GridPosToGridIndex(x, y);
setupm_fakecolor = M_GridIndexToMenuColor(index);
} }
else
{
for (i = 0; i < 13; i++) // or (282-charw)/(2*indexwidth)
{
setupm_fakecolor = (choice == KEY_PGUP) ? setupm_fakecolor->prev : setupm_fakecolor->next;
while (!skincolors[setupm_fakecolor->color].accessible) // skip inaccessible colors
setupm_fakecolor = (choice == KEY_PGUP) ? setupm_fakecolor->prev : setupm_fakecolor->next;
}
}
S_StartSound(NULL, sfx_menu1); // Tails
} }
} }
break; break;
@ -12440,7 +12556,6 @@ static void M_HandleSetupMultiPlayer(INT32 choice)
} }
} }
break; break;
break;
case KEY_DEL: case KEY_DEL:
if (itemOn == 0 && (l = strlen(setupm_name))!=0) if (itemOn == 0 && (l = strlen(setupm_name))!=0)
@ -12523,11 +12638,7 @@ static void M_SetupMultiPlayer(INT32 choice)
else else
MP_PlayerSetupMenu[1].status = (IT_KEYHANDLER|IT_STRING); MP_PlayerSetupMenu[1].status = (IT_KEYHANDLER|IT_STRING);
// ditto with colour MP_PlayerSetupMenu[2].status = (IT_KEYHANDLER|IT_STRING);
if (Playing() && G_GametypeHasTeams())
MP_PlayerSetupMenu[2].status = (IT_GRAYEDOUT);
else
MP_PlayerSetupMenu[2].status = (IT_KEYHANDLER|IT_STRING);
multi_spr2 = P_GetSkinSprite2(&skins[setupm_fakeskin], SPR2_WALK, NULL); multi_spr2 = P_GetSkinSprite2(&skins[setupm_fakeskin], SPR2_WALK, NULL);
@ -12542,7 +12653,7 @@ static void M_SetupMultiPlayer2(INT32 choice)
multi_frame = 0; multi_frame = 0;
multi_tics = 4*FRACUNIT; multi_tics = 4*FRACUNIT;
strcpy (setupm_name, cv_playername2.string); strcpy (setupm_name, cv_playername2.string);
// set for splitscreen secondary player // set for splitscreen secondary player
@ -12568,11 +12679,7 @@ static void M_SetupMultiPlayer2(INT32 choice)
else else
MP_PlayerSetupMenu[1].status = (IT_KEYHANDLER | IT_STRING); MP_PlayerSetupMenu[1].status = (IT_KEYHANDLER | IT_STRING);
// ditto with colour MP_PlayerSetupMenu[2].status = (IT_KEYHANDLER|IT_STRING);
if (Playing() && G_GametypeHasTeams())
MP_PlayerSetupMenu[2].status = (IT_GRAYEDOUT);
else
MP_PlayerSetupMenu[2].status = (IT_KEYHANDLER|IT_STRING);
multi_spr2 = P_GetSkinSprite2(&skins[setupm_fakeskin], SPR2_WALK, NULL); multi_spr2 = P_GetSkinSprite2(&skins[setupm_fakeskin], SPR2_WALK, NULL);

View file

@ -20,7 +20,7 @@
#include "command.h" #include "command.h"
#include "f_finale.h" // for ttmode_enum #include "f_finale.h" // for ttmode_enum
#include "i_threads.h" #include "i_threads.h"
#include "mserv.h" #include "netcode/mserv.h"
#include "r_things.h" // for SKINNAMESIZE #include "r_things.h" // for SKINNAMESIZE
// Compatibility with old-style named NiGHTS replay files. // Compatibility with old-style named NiGHTS replay files.
@ -74,7 +74,7 @@ typedef enum
MN_MP_SERVER, MN_MP_SERVER,
MN_MP_CONNECT, MN_MP_CONNECT,
MN_MP_ROOM, MN_MP_ROOM,
MN_MP_PLAYERSETUP, // MP_PlayerSetupDef shared with SPLITSCREEN if #defined NONET MN_MP_PLAYERSETUP,
MN_MP_SERVER_OPTIONS, MN_MP_SERVER_OPTIONS,
// Options // Options

View file

@ -12,7 +12,7 @@
#include "m_perfstats.h" #include "m_perfstats.h"
#include "v_video.h" #include "v_video.h"
#include "i_video.h" #include "i_video.h"
#include "d_netcmd.h" #include "netcode/d_netcmd.h"
#include "r_main.h" #include "r_main.h"
#include "i_system.h" #include "i_system.h"
#include "z_zone.h" #include "z_zone.h"

View file

@ -0,0 +1,15 @@
target_sources(SRB2SDL2 PRIVATE
d_clisrv.c
server_connection.c
client_connection.c
tic_command.c
net_command.c
gamestate.c
commands.c
d_net.c
d_netcmd.c
d_netfil.c
http-mserv.c
i_tcp.c
mserv.c
)

13
src/netcode/Sourcefile Normal file
View file

@ -0,0 +1,13 @@
d_clisrv.c
server_connection.c
client_connection.c
tic_command.c
net_command.c
gamestate.c
commands.c
d_net.c
d_netcmd.c
d_netfil.c
http-mserv.c
i_tcp.c
mserv.c

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,61 @@
// 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 client_connection.h
/// \brief Client connection handling
#ifndef __D_CLIENT_CONNECTION__
#define __D_CLIENT_CONNECTION__
#include "../doomtype.h"
#include "d_clisrv.h"
#define MAXSERVERLIST (MAXNETNODES-1)
typedef struct
{
SINT8 node;
serverinfo_pak info;
} serverelem_t;
typedef enum
{
CL_SEARCHING,
CL_CHECKFILES,
CL_DOWNLOADFILES,
CL_ASKJOIN,
CL_LOADFILES,
CL_WAITJOINRESPONSE,
CL_DOWNLOADSAVEGAME,
CL_CONNECTED,
CL_ABORTED,
CL_ASKFULLFILELIST,
CL_CONFIRMCONNECT
} cl_mode_t;
extern serverelem_t serverlist[MAXSERVERLIST];
extern UINT32 serverlistcount;
extern cl_mode_t cl_mode;
extern boolean serverisfull; //lets us be aware if the server was full after we check files, but before downloading, so we can ask if the user still wants to download or not
extern tic_t firstconnectattempttime;
extern UINT8 mynode; // my address pointofview server
void CL_QueryServerList(msg_server_t *list);
void CL_UpdateServerList(boolean internetsearch, INT32 room);
void CL_ConnectToServer(void);
boolean CL_SendJoin(void);
void PT_ServerInfo(SINT8 node);
void PT_MoreFilesNeeded(SINT8 node);
void PT_ServerRefuse(SINT8 node);
void PT_ServerCFG(SINT8 node);
#endif

484
src/netcode/commands.c Normal file
View file

@ -0,0 +1,484 @@
// 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 commands.c
/// \brief Various netgame commands, such as kick and ban
#include "commands.h"
#include "d_clisrv.h"
#include "client_connection.h"
#include "net_command.h"
#include "d_netcmd.h"
#include "d_net.h"
#include "i_net.h"
#include "protocol.h"
#include "../byteptr.h"
#include "../d_main.h"
#include "../g_game.h"
#include "../w_wad.h"
#include "../z_zone.h"
#include "../doomstat.h"
#include "../doomdef.h"
#include "../r_local.h"
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
typedef struct banreason_s
{
char *reason;
struct banreason_s *prev; //-1
struct banreason_s *next; //+1
} banreason_t;
static banreason_t *reasontail = NULL; //last entry, use prev
static banreason_t *reasonhead = NULL; //1st entry, use next
void Ban_Add(const char *reason)
{
banreason_t *reasonlist = malloc(sizeof(*reasonlist));
if (!reasonlist)
return;
if (!reason)
reason = "NA";
reasonlist->next = NULL;
reasonlist->reason = Z_StrDup(reason);
if ((reasonlist->prev = reasontail) == NULL)
reasonhead = reasonlist;
else
reasontail->next = reasonlist;
reasontail = reasonlist;
}
static void Ban_Clear(void)
{
banreason_t *temp;
I_ClearBans();
reasontail = NULL;
while (reasonhead)
{
temp = reasonhead->next;
Z_Free(reasonhead->reason);
free(reasonhead);
reasonhead = temp;
}
}
void Ban_Load_File(boolean warning)
{
FILE *f;
const char *address, *mask;
char buffer[MAX_WADPATH];
if (!I_ClearBans)
return;
f = fopen(va("%s"PATHSEP"%s", srb2home, "ban.txt"), "r");
if (!f)
{
if (warning)
CONS_Alert(CONS_WARNING, M_GetText("Could not open ban.txt for ban list\n"));
return;
}
Ban_Clear();
for (; fgets(buffer, (int)sizeof(buffer), f);)
{
address = strtok(buffer, " \t\r\n");
mask = strtok(NULL, " \t\r\n");
I_SetBanAddress(address, mask);
Ban_Add(strtok(NULL, "\r\n"));
}
fclose(f);
}
void D_SaveBan(void)
{
FILE *f;
banreason_t *reasonlist = reasonhead;
const char *address, *mask;
const char *path = va("%s"PATHSEP"%s", srb2home, "ban.txt");
if (!reasonhead)
{
remove(path);
return;
}
f = fopen(path, "w");
if (!f)
{
CONS_Alert(CONS_WARNING, M_GetText("Could not save ban list into ban.txt\n"));
return;
}
for (size_t i = 0;(address = I_GetBanAddress(i)) != NULL;i++)
{
if (!I_GetBanMask || (mask = I_GetBanMask(i)) == NULL)
fprintf(f, "%s 0", address);
else
fprintf(f, "%s %s", address, mask);
if (reasonlist && reasonlist->reason)
fprintf(f, " %s\n", reasonlist->reason);
else
fprintf(f, " %s\n", "NA");
if (reasonlist) reasonlist = reasonlist->next;
}
fclose(f);
}
void Command_ShowBan(void) //Print out ban list
{
size_t i;
const char *address, *mask;
banreason_t *reasonlist = reasonhead;
if (I_GetBanAddress)
CONS_Printf(M_GetText("Ban List:\n"));
else
return;
for (i = 0;(address = I_GetBanAddress(i)) != NULL;i++)
{
if (!I_GetBanMask || (mask = I_GetBanMask(i)) == NULL)
CONS_Printf("%s: %s ", sizeu1(i+1), address);
else
CONS_Printf("%s: %s/%s ", sizeu1(i+1), address, mask);
if (reasonlist && reasonlist->reason)
CONS_Printf("(%s)\n", reasonlist->reason);
else
CONS_Printf("\n");
if (reasonlist) reasonlist = reasonlist->next;
}
if (i == 0 && !address)
CONS_Printf(M_GetText("(empty)\n"));
}
void Command_ClearBans(void)
{
if (!I_ClearBans)
return;
Ban_Clear();
D_SaveBan();
}
void Command_Ban(void)
{
if (COM_Argc() < 2)
{
CONS_Printf(M_GetText("Ban <playername/playernum> <reason>: ban and kick a player\n"));
return;
}
if (!netgame) // Don't kick Tails in splitscreen!
{
CONS_Printf(M_GetText("This only works in a netgame.\n"));
return;
}
if (server || IsPlayerAdmin(consoleplayer))
{
UINT8 buf[3 + MAX_REASONLENGTH];
UINT8 *p = buf;
const SINT8 pn = nametonum(COM_Argv(1));
const INT32 node = playernode[(INT32)pn];
if (pn == -1 || pn == 0)
return;
WRITEUINT8(p, pn);
if (server && I_Ban && !I_Ban(node)) // only the server is allowed to do this right now
{
CONS_Alert(CONS_WARNING, M_GetText("Too many bans! Geez, that's a lot of people you're excluding...\n"));
WRITEUINT8(p, KICK_MSG_GO_AWAY);
SendNetXCmd(XD_KICK, &buf, 2);
}
else
{
if (server) // only the server is allowed to do this right now
{
Ban_Add(COM_Argv(2));
D_SaveBan(); // save the ban list
}
if (COM_Argc() == 2)
{
WRITEUINT8(p, KICK_MSG_BANNED);
SendNetXCmd(XD_KICK, &buf, 2);
}
else
{
size_t j = COM_Argc();
char message[MAX_REASONLENGTH];
//Steal from the motd code so you don't have to put the reason in quotes.
strlcpy(message, COM_Argv(2), sizeof message);
for (size_t i = 3; i < j; i++)
{
strlcat(message, " ", sizeof message);
strlcat(message, COM_Argv(i), sizeof message);
}
WRITEUINT8(p, KICK_MSG_CUSTOM_BAN);
WRITESTRINGN(p, message, MAX_REASONLENGTH);
SendNetXCmd(XD_KICK, &buf, p - buf);
}
}
}
else
CONS_Printf(M_GetText("Only the server or a remote admin can use this.\n"));
}
void Command_BanIP(void)
{
if (COM_Argc() < 2)
{
CONS_Printf(M_GetText("banip <ip> <reason>: ban an ip address\n"));
return;
}
if (server) // Only the server can use this, otherwise does nothing.
{
const char *address = (COM_Argv(1));
const char *reason;
if (COM_Argc() == 2)
reason = NULL;
else
reason = COM_Argv(2);
if (I_SetBanAddress && I_SetBanAddress(address, NULL))
{
if (reason)
CONS_Printf("Banned IP address %s for: %s\n", address, reason);
else
CONS_Printf("Banned IP address %s\n", address);
Ban_Add(reason);
D_SaveBan();
}
else
{
return;
}
}
}
void Command_ReloadBan(void) //recheck ban.txt
{
Ban_Load_File(true);
}
void Command_Kick(void)
{
if (COM_Argc() < 2)
{
CONS_Printf(M_GetText("kick <playername/playernum> <reason>: kick a player\n"));
return;
}
if (!netgame) // Don't kick Tails in splitscreen!
{
CONS_Printf(M_GetText("This only works in a netgame.\n"));
return;
}
if (server || IsPlayerAdmin(consoleplayer))
{
UINT8 buf[3 + MAX_REASONLENGTH];
UINT8 *p = buf;
const SINT8 pn = nametonum(COM_Argv(1));
if (pn == -1 || pn == 0)
return;
// Special case if we are trying to kick a player who is downloading the game state:
// trigger a timeout instead of kicking them, because a kick would only
// take effect after they have finished downloading
if (server && playernode[pn] != UINT8_MAX && netnodes[playernode[pn]].sendingsavegame)
{
Net_ConnectionTimeout(playernode[pn]);
return;
}
WRITESINT8(p, pn);
if (COM_Argc() == 2)
{
WRITEUINT8(p, KICK_MSG_GO_AWAY);
SendNetXCmd(XD_KICK, &buf, 2);
}
else
{
size_t j = COM_Argc();
char message[MAX_REASONLENGTH];
//Steal from the motd code so you don't have to put the reason in quotes.
strlcpy(message, COM_Argv(2), sizeof message);
for (size_t i = 3; i < j; i++)
{
strlcat(message, " ", sizeof message);
strlcat(message, COM_Argv(i), sizeof message);
}
WRITEUINT8(p, KICK_MSG_CUSTOM_KICK);
WRITESTRINGN(p, message, MAX_REASONLENGTH);
SendNetXCmd(XD_KICK, &buf, p - buf);
}
}
else
CONS_Printf(M_GetText("Only the server or a remote admin can use this.\n"));
}
void Command_connect(void)
{
if (COM_Argc() < 2 || *COM_Argv(1) == 0)
{
CONS_Printf(M_GetText(
"Connect <serveraddress> (port): connect to a server\n"
"Connect ANY: connect to the first lan server found\n"
//"Connect SELF: connect to your own server.\n"
));
return;
}
if (Playing() || titledemo)
{
CONS_Printf(M_GetText("You cannot connect while in a game. End this game first.\n"));
return;
}
server = false;
/*
if (!stricmp(COM_Argv(1), "self"))
{
servernode = 0;
server = true;
/// \bug should be but...
//SV_SpawnServer();
}
else
*/
{
// used in menu to connect to a server in the list
if (netgame && !stricmp(COM_Argv(1), "node"))
{
servernode = (SINT8)atoi(COM_Argv(2));
}
else if (netgame)
{
CONS_Printf(M_GetText("You cannot connect while in a game. End this game first.\n"));
return;
}
else if (I_NetOpenSocket)
{
I_NetOpenSocket();
netgame = true;
multiplayer = true;
if (!stricmp(COM_Argv(1), "any"))
servernode = BROADCASTADDR;
else if (I_NetMakeNodewPort)
{
if (COM_Argc() >= 3) // address AND port
servernode = I_NetMakeNodewPort(COM_Argv(1), COM_Argv(2));
else // address only, or address:port
servernode = I_NetMakeNode(COM_Argv(1));
}
else
{
CONS_Alert(CONS_ERROR, M_GetText("There is no server identification with this network driver\n"));
D_CloseConnection();
return;
}
}
else
CONS_Alert(CONS_ERROR, M_GetText("There is no network driver\n"));
}
splitscreen = false;
SplitScreen_OnChange();
botingame = false;
botskin = 0;
CL_ConnectToServer();
}
void Command_GetPlayerNum(void)
{
for (INT32 i = 0; i < MAXPLAYERS; i++)
if (playeringame[i])
{
if (serverplayer == i)
CONS_Printf(M_GetText("num:%2d node:%2d %s\n"), i, playernode[i], player_names[i]);
else
CONS_Printf(M_GetText("\x82num:%2d node:%2d %s\n"), i, playernode[i], player_names[i]);
}
}
/** Lists all players and their player numbers.
*
* \sa Command_GetPlayerNum
*/
void Command_Nodes(void)
{
size_t maxlen = 0;
const char *address;
for (INT32 i = 0; i < MAXPLAYERS; i++)
{
const size_t plen = strlen(player_names[i]);
if (playeringame[i] && plen > maxlen)
maxlen = plen;
}
for (INT32 i = 0; i < MAXPLAYERS; i++)
{
if (playeringame[i])
{
CONS_Printf("%.2u: %*s", i, (int)maxlen, player_names[i]);
if (playernode[i] != UINT8_MAX)
{
CONS_Printf(" - node %.2d", playernode[i]);
if (I_GetNodeAddress && (address = I_GetNodeAddress(playernode[i])) != NULL)
CONS_Printf(" - %s", address);
}
if (IsPlayerAdmin(i))
CONS_Printf(M_GetText(" (verified admin)"));
if (players[i].spectator)
CONS_Printf(M_GetText(" (spectator)"));
CONS_Printf("\n");
}
}
}

33
src/netcode/commands.h Normal file
View file

@ -0,0 +1,33 @@
// 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 commands.h
/// \brief Various netgame commands, such as kick and ban
#ifndef __COMMANDS__
#define __COMMANDS__
#include "../doomdef.h"
#define MAX_REASONLENGTH 30
void Ban_Add(const char *reason);
void D_SaveBan(void);
void Ban_Load_File(boolean warning);
void Command_ShowBan(void);
void Command_ClearBans(void);
void Command_Ban(void);
void Command_BanIP(void);
void Command_ReloadBan(void);
void Command_Kick(void);
void Command_connect(void);
void Command_GetPlayerNum(void);
void Command_Nodes(void);
#endif

1736
src/netcode/d_clisrv.c Normal file

File diff suppressed because it is too large Load diff

135
src/netcode/d_clisrv.h Normal file
View file

@ -0,0 +1,135 @@
// 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 d_clisrv.h
/// \brief high level networking stuff
#ifndef __D_CLISRV__
#define __D_CLISRV__
#include "protocol.h"
#include "../d_ticcmd.h"
#include "d_net.h"
#include "d_netcmd.h"
#include "d_net.h"
#include "../tables.h"
#include "../d_player.h"
#include "mserv.h"
#define CLIENTBACKUPTICS 32
#ifdef PACKETDROP
void Command_Drop(void);
void Command_Droprate(void);
#endif
#ifdef _DEBUG
void Command_Numnodes(void);
#endif
extern INT32 mapchangepending;
// Points inside doomcom
extern doomdata_t *netbuffer;
#define BASEPACKETSIZE offsetof(doomdata_t, u)
#define BASESERVERTICSSIZE offsetof(doomdata_t, u.serverpak.cmds[0])
typedef enum
{
KR_KICK = 1, //Kicked by server
KR_PINGLIMIT = 2, //Broke Ping Limit
KR_SYNCH = 3, //Synch Failure
KR_TIMEOUT = 4, //Connection Timeout
KR_BAN = 5, //Banned by server
KR_LEAVE = 6, //Quit the game
} kickreason_t;
/* the max number of name changes in some time period */
#define MAXNAMECHANGES (5)
#define NAMECHANGERATE (60*TICRATE)
extern boolean server;
extern boolean serverrunning;
#define client (!server)
extern boolean dedicated; // For dedicated server
extern UINT16 software_MAXPACKETLENGTH;
extern boolean acceptnewnode;
extern SINT8 servernode;
extern tic_t maketic;
extern tic_t neededtic;
extern INT16 consistancy[BACKUPTICS];
void Command_Ping_f(void);
extern tic_t connectiontimeout;
extern UINT16 pingmeasurecount;
extern UINT32 realpingtable[MAXPLAYERS];
extern UINT32 playerpingtable[MAXPLAYERS];
extern tic_t servermaxping;
extern consvar_t cv_netticbuffer, cv_resynchattempts, cv_blamecfail, cv_playbackspeed, cv_dedicatedidletime;
// Used in d_net, the only dependence
void D_ClientServerInit(void);
// Create any new ticcmds and broadcast to other players.
void NetUpdate(void);
// Maintain connections to nodes without timing them all out.
void NetKeepAlive(void);
void GetPackets(void);
void ResetNode(INT32 node);
INT16 Consistancy(void);
void SV_StartSinglePlayerServer(void);
void SV_SpawnServer(void);
void SV_StopServer(void);
void SV_ResetServer(void);
void CL_AddSplitscreenPlayer(void);
void CL_RemoveSplitscreenPlayer(void);
void CL_Reset(void);
void CL_ClearPlayer(INT32 playernum);
void CL_RemovePlayer(INT32 playernum, kickreason_t reason);
void CL_HandleTimeout(void);
// Is there a game running
boolean Playing(void);
// Broadcasts special packets to other players
// to notify of game exit
void D_QuitNetGame(void);
//? How many ticks to run?
boolean TryRunTics(tic_t realtic);
// extra data for lmps
// these functions scare me. they contain magic.
/*boolean AddLmpExtradata(UINT8 **demo_p, INT32 playernum);
void ReadLmpExtraData(UINT8 **demo_pointer, INT32 playernum);*/
// translate a playername in a player number return -1 if not found and
// print a error message in the console
SINT8 nametonum(const char *name);
extern char motd[254], server_context[8];
extern UINT8 playernode[MAXPLAYERS];
INT32 D_NumPlayers(void);
INT32 D_NumBots(void);
tic_t GetLag(INT32 node);
void D_MD5PasswordPass(const UINT8 *buffer, size_t len, const char *salt, void *dest);
extern UINT8 adminpassmd5[16];
extern boolean adminpasswordset;
extern boolean hu_stopped;
#endif

View file

@ -16,19 +16,21 @@
/// This protocol uses a mix of "goback n" and "selective repeat" implementation /// This protocol uses a mix of "goback n" and "selective repeat" implementation
/// The NOTHING packet is sent when connection is idle to acknowledge packets /// The NOTHING packet is sent when connection is idle to acknowledge packets
#include "doomdef.h" #include "../doomdef.h"
#include "g_game.h" #include "../g_game.h"
#include "i_time.h" #include "../i_time.h"
#include "i_net.h" #include "i_net.h"
#include "i_system.h" #include "../i_system.h"
#include "m_argv.h" #include "../m_argv.h"
#include "d_net.h" #include "d_net.h"
#include "w_wad.h" #include "../w_wad.h"
#include "d_netfil.h" #include "d_netfil.h"
#include "d_clisrv.h" #include "d_clisrv.h"
#include "z_zone.h" #include "tic_command.h"
#include "net_command.h"
#include "../z_zone.h"
#include "i_tcp.h" #include "i_tcp.h"
#include "d_main.h" // srb2home #include "../d_main.h" // srb2home
// //
// NETWORKING // NETWORKING
@ -138,7 +140,6 @@ boolean Net_GetNetStat(void)
#define URGENTFREESLOTNUM 10 #define URGENTFREESLOTNUM 10
#define ACKTOSENDTIMEOUT (TICRATE/11) #define ACKTOSENDTIMEOUT (TICRATE/11)
#ifndef NONET
typedef struct typedef struct
{ {
UINT8 acknum; UINT8 acknum;
@ -152,7 +153,6 @@ typedef struct
doomdata_t data; doomdata_t data;
} pak; } pak;
} ackpak_t; } ackpak_t;
#endif
typedef enum typedef enum
{ {
@ -160,10 +160,8 @@ typedef enum
NF_TIMEOUT = 2, // Flag is set when the node got a timeout NF_TIMEOUT = 2, // Flag is set when the node got a timeout
} node_flags_t; } node_flags_t;
#ifndef NONET
// Table of packets that were not acknowleged can be resent (the sender window) // Table of packets that were not acknowleged can be resent (the sender window)
static ackpak_t ackpak[MAXACKPACKETS]; static ackpak_t ackpak[MAXACKPACKETS];
#endif
typedef struct typedef struct
{ {
@ -191,7 +189,6 @@ typedef struct
static node_t nodes[MAXNETNODES]; static node_t nodes[MAXNETNODES];
#define NODETIMEOUT 14 #define NODETIMEOUT 14
#ifndef NONET
// return <0 if a < b (mod 256) // return <0 if a < b (mod 256)
// 0 if a = n (mod 256) // 0 if a = n (mod 256)
// >0 if a > b (mod 256) // >0 if a > b (mod 256)
@ -214,7 +211,7 @@ FUNCMATH static INT32 cmpack(UINT8 a, UINT8 b)
static boolean GetFreeAcknum(UINT8 *freeack, boolean lowtimer) static boolean GetFreeAcknum(UINT8 *freeack, boolean lowtimer)
{ {
node_t *node = &nodes[doomcom->remotenode]; node_t *node = &nodes[doomcom->remotenode];
INT32 i, numfreeslot = 0; INT32 numfreeslot = 0;
if (cmpack((UINT8)((node->remotefirstack + MAXACKTOSEND) % 256), node->nextacknum) < 0) if (cmpack((UINT8)((node->remotefirstack + MAXACKTOSEND) % 256), node->nextacknum) < 0)
{ {
@ -222,7 +219,7 @@ static boolean GetFreeAcknum(UINT8 *freeack, boolean lowtimer)
return false; return false;
} }
for (i = 0; i < MAXACKPACKETS; i++) for (INT32 i = 0; i < MAXACKPACKETS; i++)
if (!ackpak[i].acknum) if (!ackpak[i].acknum)
{ {
// For low priority packets, make sure to let freeslots so urgent packets can be sent // For low priority packets, make sure to let freeslots so urgent packets can be sent
@ -279,10 +276,10 @@ static boolean GetFreeAcknum(UINT8 *freeack, boolean lowtimer)
*/ */
INT32 Net_GetFreeAcks(boolean urgent) INT32 Net_GetFreeAcks(boolean urgent)
{ {
INT32 i, numfreeslot = 0; INT32 numfreeslot = 0;
INT32 n = 0; // Number of free acks found INT32 n = 0; // Number of free acks found
for (i = 0; i < MAXACKPACKETS; i++) for (INT32 i = 0; i < MAXACKPACKETS; i++)
if (!ackpak[i].acknum) if (!ackpak[i].acknum)
{ {
// For low priority packets, make sure to let freeslots so urgent packets can be sent // For low priority packets, make sure to let freeslots so urgent packets can be sent
@ -318,7 +315,6 @@ static void RemoveAck(INT32 i)
// We have got a packet, proceed the ack request and ack return // We have got a packet, proceed the ack request and ack return
static boolean Processackpak(void) static boolean Processackpak(void)
{ {
INT32 i;
boolean goodpacket = true; boolean goodpacket = true;
node_t *node = &nodes[doomcom->remotenode]; node_t *node = &nodes[doomcom->remotenode];
@ -327,7 +323,7 @@ static boolean Processackpak(void)
{ {
node->remotefirstack = netbuffer->ackreturn; node->remotefirstack = netbuffer->ackreturn;
// Search the ackbuffer and free it // Search the ackbuffer and free it
for (i = 0; i < MAXACKPACKETS; i++) for (INT32 i = 0; i < MAXACKPACKETS; i++)
if (ackpak[i].acknum && ackpak[i].destinationnode == node - nodes if (ackpak[i].acknum && ackpak[i].destinationnode == node - nodes
&& cmpack(ackpak[i].acknum, netbuffer->ackreturn) <= 0) && cmpack(ackpak[i].acknum, netbuffer->ackreturn) <= 0)
{ {
@ -349,7 +345,7 @@ static boolean Processackpak(void)
else else
{ {
// Check if it is not already in the queue // Check if it is not already in the queue
for (i = node->acktosend_tail; i != node->acktosend_head; i = (i+1) % MAXACKTOSEND) for (INT32 i = node->acktosend_tail; i != node->acktosend_head; i = (i+1) % MAXACKTOSEND)
if (node->acktosend[i] == ack) if (node->acktosend[i] == ack)
{ {
DEBFILE(va("Discard(2) ack %d (duplicated)\n", ack)); DEBFILE(va("Discard(2) ack %d (duplicated)\n", ack));
@ -377,7 +373,7 @@ static boolean Processackpak(void)
while (change) while (change)
{ {
change = false; change = false;
for (i = node->acktosend_tail; i != node->acktosend_head; for (INT32 i = node->acktosend_tail; i != node->acktosend_head;
i = (i+1) % MAXACKTOSEND) i = (i+1) % MAXACKTOSEND)
{ {
if (cmpack(node->acktosend[i], nextfirstack) <= 0) if (cmpack(node->acktosend[i], nextfirstack) <= 0)
@ -426,28 +422,20 @@ static boolean Processackpak(void)
} }
return goodpacket; return goodpacket;
} }
#endif
// send special packet with only ack on it // send special packet with only ack on it
void Net_SendAcks(INT32 node) void Net_SendAcks(INT32 node)
{ {
#ifdef NONET
(void)node;
#else
netbuffer->packettype = PT_NOTHING; netbuffer->packettype = PT_NOTHING;
M_Memcpy(netbuffer->u.textcmd, nodes[node].acktosend, MAXACKTOSEND); M_Memcpy(netbuffer->u.textcmd, nodes[node].acktosend, MAXACKTOSEND);
HSendPacket(node, false, 0, MAXACKTOSEND); HSendPacket(node, false, 0, MAXACKTOSEND);
#endif
} }
#ifndef NONET
static void GotAcks(void) static void GotAcks(void)
{ {
INT32 i, j; for (INT32 j = 0; j < MAXACKTOSEND; j++)
for (j = 0; j < MAXACKTOSEND; j++)
if (netbuffer->u.textcmd[j]) if (netbuffer->u.textcmd[j])
for (i = 0; i < MAXACKPACKETS; i++) for (INT32 i = 0; i < MAXACKPACKETS; i++)
if (ackpak[i].acknum && ackpak[i].destinationnode == doomcom->remotenode) if (ackpak[i].acknum && ackpak[i].destinationnode == doomcom->remotenode)
{ {
if (ackpak[i].acknum == netbuffer->u.textcmd[j]) if (ackpak[i].acknum == netbuffer->u.textcmd[j])
@ -463,7 +451,6 @@ static void GotAcks(void)
} }
} }
} }
#endif
void Net_ConnectionTimeout(INT32 node) void Net_ConnectionTimeout(INT32 node)
{ {
@ -472,14 +459,10 @@ void Net_ConnectionTimeout(INT32 node)
return; return;
nodes[node].flags |= NF_TIMEOUT; nodes[node].flags |= NF_TIMEOUT;
// Send a very special packet to self (hack the reboundstore queue) if (server)
// Main code will handle it SendKicksForNode(node, KICK_MSG_TIMEOUT | KICK_MSG_KEEP_BODY);
reboundstore[rebound_head].packettype = PT_NODETIMEOUT; else
reboundstore[rebound_head].ack = 0; CL_HandleTimeout();
reboundstore[rebound_head].ackreturn = 0;
reboundstore[rebound_head].u.textcmd[0] = (UINT8)node;
reboundsize[rebound_head] = (INT16)(BASEPACKETSIZE + 1);
rebound_head = (rebound_head+1) % MAXREBOUND;
// Do not redo it quickly (if we do not close connection it is // Do not redo it quickly (if we do not close connection it is
// for a good reason!) // for a good reason!)
@ -489,10 +472,8 @@ void Net_ConnectionTimeout(INT32 node)
// Resend the data if needed // Resend the data if needed
void Net_AckTicker(void) void Net_AckTicker(void)
{ {
#ifndef NONET
INT32 i;
for (i = 0; i < MAXACKPACKETS; i++) for (INT32 i = 0; i < MAXACKPACKETS; i++)
{ {
const INT32 nodei = ackpak[i].destinationnode; const INT32 nodei = ackpak[i].destinationnode;
node_t *node = &nodes[nodei]; node_t *node = &nodes[nodei];
@ -519,7 +500,7 @@ void Net_AckTicker(void)
} }
} }
for (i = 1; i < MAXNETNODES; i++) for (INT32 i = 1; i < MAXNETNODES; i++)
{ {
// This is something like node open flag // This is something like node open flag
if (nodes[i].firstacktosend) if (nodes[i].firstacktosend)
@ -536,16 +517,12 @@ void Net_AckTicker(void)
} }
} }
} }
#endif
} }
// Remove last packet received ack before resending the ackreturn // Remove last packet received ack before resending the ackreturn
// (the higher layer doesn't have room, or something else ....) // (the higher layer doesn't have room, or something else ....)
void Net_UnAcknowledgePacket(INT32 node) void Net_UnAcknowledgePacket(INT32 node)
{ {
#ifdef NONET
(void)node;
#else
INT32 hm1 = (nodes[node].acktosend_head-1+MAXACKTOSEND) % MAXACKTOSEND; INT32 hm1 = (nodes[node].acktosend_head-1+MAXACKTOSEND) % MAXACKTOSEND;
DEBFILE(va("UnAcknowledge node %d\n", node)); DEBFILE(va("UnAcknowledge node %d\n", node));
if (!node) if (!node)
@ -577,10 +554,8 @@ void Net_UnAcknowledgePacket(INT32 node)
if (!nodes[node].firstacktosend) if (!nodes[node].firstacktosend)
nodes[node].firstacktosend = 1; nodes[node].firstacktosend = 1;
} }
#endif
} }
#ifndef NONET
/** Checks if all acks have been received /** Checks if all acks have been received
* *
* \return True if all acks have been received * \return True if all acks have been received
@ -588,15 +563,12 @@ void Net_UnAcknowledgePacket(INT32 node)
*/ */
static boolean Net_AllAcksReceived(void) static boolean Net_AllAcksReceived(void)
{ {
INT32 i; for (INT32 i = 0; i < MAXACKPACKETS; i++)
for (i = 0; i < MAXACKPACKETS; i++)
if (ackpak[i].acknum) if (ackpak[i].acknum)
return false; return false;
return true; return true;
} }
#endif
/** Waits for all ackreturns /** Waits for all ackreturns
* *
@ -605,9 +577,6 @@ static boolean Net_AllAcksReceived(void)
*/ */
void Net_WaitAllAckReceived(UINT32 timeout) void Net_WaitAllAckReceived(UINT32 timeout)
{ {
#ifdef NONET
(void)timeout;
#else
tic_t tictac = I_GetTime(); tic_t tictac = I_GetTime();
timeout = tictac + timeout*NEWTICRATE; timeout = tictac + timeout*NEWTICRATE;
@ -623,7 +592,6 @@ void Net_WaitAllAckReceived(UINT32 timeout)
HGetPacket(); HGetPacket();
Net_AckTicker(); Net_AckTicker();
} }
#endif
} }
static void InitNode(node_t *node) static void InitNode(node_t *node)
@ -637,14 +605,10 @@ static void InitNode(node_t *node)
static void InitAck(void) static void InitAck(void)
{ {
INT32 i; for (INT32 i = 0; i < MAXACKPACKETS; i++)
#ifndef NONET
for (i = 0; i < MAXACKPACKETS; i++)
ackpak[i].acknum = 0; ackpak[i].acknum = 0;
#endif
for (i = 0; i < MAXNETNODES; i++) for (INT32 i = 0; i < MAXNETNODES; i++)
InitNode(&nodes[i]); InitNode(&nodes[i]);
} }
@ -655,17 +619,12 @@ static void InitAck(void)
*/ */
void Net_AbortPacketType(UINT8 packettype) void Net_AbortPacketType(UINT8 packettype)
{ {
#ifdef NONET for (INT32 i = 0; i < MAXACKPACKETS; i++)
(void)packettype;
#else
INT32 i;
for (i = 0; i < MAXACKPACKETS; i++)
if (ackpak[i].acknum && (ackpak[i].pak.data.packettype == packettype if (ackpak[i].acknum && (ackpak[i].pak.data.packettype == packettype
|| packettype == UINT8_MAX)) || packettype == UINT8_MAX))
{ {
ackpak[i].acknum = 0; ackpak[i].acknum = 0;
} }
#endif
} }
// ----------------------------------------------------------------- // -----------------------------------------------------------------
@ -675,10 +634,6 @@ void Net_AbortPacketType(UINT8 packettype)
// remove a node, clear all ack from this node and reset askret // remove a node, clear all ack from this node and reset askret
void Net_CloseConnection(INT32 node) void Net_CloseConnection(INT32 node)
{ {
#ifdef NONET
(void)node;
#else
INT32 i;
boolean forceclose = (node & FORCECLOSE) != 0; boolean forceclose = (node & FORCECLOSE) != 0;
if (node == -1) if (node == -1)
@ -708,7 +663,7 @@ void Net_CloseConnection(INT32 node)
} }
// check if we are waiting for an ack from this node // check if we are waiting for an ack from this node
for (i = 0; i < MAXACKPACKETS; i++) for (INT32 i = 0; i < MAXACKPACKETS; i++)
if (ackpak[i].acknum && ackpak[i].destinationnode == node) if (ackpak[i].acknum && ackpak[i].destinationnode == node)
{ {
if (!forceclose) if (!forceclose)
@ -722,10 +677,8 @@ void Net_CloseConnection(INT32 node)
if (server) if (server)
SV_AbortLuaFileTransfer(node); SV_AbortLuaFileTransfer(node);
I_NetFreeNodenum(node); I_NetFreeNodenum(node);
#endif
} }
#ifndef NONET
// //
// Checksum // Checksum
// //
@ -734,23 +687,20 @@ static UINT32 NetbufferChecksum(void)
UINT32 c = 0x1234567; UINT32 c = 0x1234567;
const INT32 l = doomcom->datalength - 4; const INT32 l = doomcom->datalength - 4;
const UINT8 *buf = (UINT8 *)netbuffer + 4; const UINT8 *buf = (UINT8 *)netbuffer + 4;
INT32 i;
for (i = 0; i < l; i++, buf++) for (INT32 i = 0; i < l; i++, buf++)
c += (*buf) * (i+1); c += (*buf) * (i+1);
return LONG(c); return LONG(c);
} }
#endif
#ifdef DEBUGFILE #ifdef DEBUGFILE
static void fprintfstring(char *s, size_t len) static void fprintfstring(char *s, size_t len)
{ {
INT32 mode = 0; INT32 mode = 0;
size_t i;
for (i = 0; i < len; i++) for (size_t i = 0; i < len; i++)
if (s[i] < 32) if (s[i] < 32)
{ {
if (!mode) if (!mode)
@ -810,6 +760,8 @@ static const char *packettypename[NUMPACKETTYPE] =
"ASKLUAFILE", "ASKLUAFILE",
"HASLUAFILE", "HASLUAFILE",
"PT_BASICKEEPALIVE",
"FILEFRAGMENT", "FILEFRAGMENT",
"FILEACK", "FILEACK",
"FILERECEIVED", "FILERECEIVED",
@ -817,7 +769,6 @@ static const char *packettypename[NUMPACKETTYPE] =
"TEXTCMD", "TEXTCMD",
"TEXTCMD2", "TEXTCMD2",
"CLIENTJOIN", "CLIENTJOIN",
"NODETIMEOUT",
"LOGIN", "LOGIN",
"TELLFILESNEEDED", "TELLFILESNEEDED",
"MOREFILESNEEDED", "MOREFILESNEEDED",
@ -921,7 +872,6 @@ void Command_Drop(void)
{ {
INT32 packetquantity; INT32 packetquantity;
const char *packetname; const char *packetname;
size_t i;
if (COM_Argc() < 2) if (COM_Argc() < 2)
{ {
@ -951,11 +901,11 @@ void Command_Drop(void)
packetname = COM_Argv(1); packetname = COM_Argv(1);
if (!(stricmp(packetname, "all") && stricmp(packetname, "any"))) if (!(stricmp(packetname, "all") && stricmp(packetname, "any")))
for (i = 0; i < NUMPACKETTYPE; i++) for (size_t i = 0; i < NUMPACKETTYPE; i++)
packetdropquantity[i] = packetquantity; packetdropquantity[i] = packetquantity;
else else
{ {
for (i = 0; i < NUMPACKETTYPE; i++) for (size_t i = 0; i < NUMPACKETTYPE; i++)
if (!stricmp(packetname, packettypename[i])) if (!stricmp(packetname, packettypename[i]))
{ {
packetdropquantity[i] = packetquantity; packetdropquantity[i] = packetquantity;
@ -986,14 +936,12 @@ void Command_Droprate(void)
packetdroprate = droprate; packetdroprate = droprate;
} }
#ifndef NONET
static boolean ShouldDropPacket(void) static boolean ShouldDropPacket(void)
{ {
return (packetdropquantity[netbuffer->packettype]) return (packetdropquantity[netbuffer->packettype])
|| (packetdroprate != 0 && rand() < (RAND_MAX * (packetdroprate / 100.f))) || packetdroprate == 100; || (packetdroprate != 0 && rand() < (RAND_MAX * (packetdroprate / 100.f))) || packetdroprate == 100;
} }
#endif #endif
#endif
// //
// HSendPacket // HSendPacket
@ -1028,11 +976,6 @@ boolean HSendPacket(INT32 node, boolean reliable, UINT8 acknum, size_t packetlen
if (!netgame) if (!netgame)
I_Error("Tried to transmit to another node"); I_Error("Tried to transmit to another node");
#ifdef NONET
(void)node;
(void)reliable;
(void)acknum;
#else
// do this before GetFreeAcknum because this function backups // do this before GetFreeAcknum because this function backups
// the current packet // the current packet
doomcom->remotenode = (INT16)node; doomcom->remotenode = (INT16)node;
@ -1093,8 +1036,6 @@ boolean HSendPacket(INT32 node, boolean reliable, UINT8 acknum, size_t packetlen
} }
#endif #endif
#endif // ndef NONET
return true; return true;
} }
@ -1112,10 +1053,7 @@ boolean HGetPacket(void)
{ {
M_Memcpy(netbuffer, &reboundstore[rebound_tail], reboundsize[rebound_tail]); M_Memcpy(netbuffer, &reboundstore[rebound_tail], reboundsize[rebound_tail]);
doomcom->datalength = reboundsize[rebound_tail]; doomcom->datalength = reboundsize[rebound_tail];
if (netbuffer->packettype == PT_NODETIMEOUT) doomcom->remotenode = 0;
doomcom->remotenode = netbuffer->u.textcmd[0];
else
doomcom->remotenode = 0;
rebound_tail = (rebound_tail+1) % MAXREBOUND; rebound_tail = (rebound_tail+1) % MAXREBOUND;
#ifdef DEBUGFILE #ifdef DEBUGFILE
@ -1128,8 +1066,6 @@ boolean HGetPacket(void)
if (!netgame) if (!netgame)
return false; return false;
#ifndef NONET
while(true) while(true)
{ {
//nodejustjoined = I_NetGet(); //nodejustjoined = I_NetGet();
@ -1189,7 +1125,6 @@ boolean HGetPacket(void)
} }
break; break;
} }
#endif // ndef NONET
return true; return true;
} }
@ -1399,13 +1334,12 @@ void Command_Ping_f(void)
int name_width = 0; int name_width = 0;
int ms_width = 0; int ms_width = 0;
int n;
INT32 i;
pingc = 0; pingc = 0;
for (i = 1; i < MAXPLAYERS; ++i) for (INT32 i = 1; i < MAXPLAYERS; ++i)
if (playeringame[i]) if (playeringame[i])
{ {
int n;
n = strlen(player_names[i]); n = strlen(player_names[i]);
if (n > name_width) if (n > name_width)
name_width = n; name_width = n;
@ -1425,7 +1359,7 @@ void Command_Ping_f(void)
qsort(pingv, pingc, sizeof (struct pingcell), &pingcellcmp); qsort(pingv, pingc, sizeof (struct pingcell), &pingcellcmp);
for (i = 0; i < pingc; ++i) for (INT32 i = 0; i < pingc; ++i)
{ {
CONS_Printf("%02d : %-*s %*d ms\n", CONS_Printf("%02d : %-*s %*d ms\n",
pingv[i].num, pingv[i].num,
@ -1441,15 +1375,13 @@ void Command_Ping_f(void)
void D_CloseConnection(void) void D_CloseConnection(void)
{ {
INT32 i;
if (netgame) if (netgame)
{ {
// wait the ackreturn with timout of 5 Sec // wait the ackreturn with timout of 5 Sec
Net_WaitAllAckReceived(5); Net_WaitAllAckReceived(5);
// close all connection // close all connection
for (i = 0; i < MAXNETNODES; i++) for (INT32 i = 0; i < MAXNETNODES; i++)
Net_CloseConnection(i|FORCECLOSE); Net_CloseConnection(i|FORCECLOSE);
InitAck(); InitAck();

View file

@ -18,6 +18,8 @@
#ifndef __D_NET__ #ifndef __D_NET__
#define __D_NET__ #define __D_NET__
#include "../doomtype.h"
// Max computers in a game // Max computers in a game
// 127 is probably as high as this can go, because // 127 is probably as high as this can go, because
// SINT8 is used for nodes sometimes >:( // SINT8 is used for nodes sometimes >:(
@ -37,10 +39,24 @@ boolean Net_GetNetStat(void);
extern INT32 getbytes; extern INT32 getbytes;
extern INT64 sendbytes; // Realtime updated extern INT64 sendbytes; // Realtime updated
extern SINT8 nodetoplayer[MAXNETNODES]; typedef struct netnode_s
extern SINT8 nodetoplayer2[MAXNETNODES]; // Say the numplayer for this node if any (splitscreen) {
extern UINT8 playerpernode[MAXNETNODES]; // Used specially for splitscreen boolean ingame; // set false as nodes leave game
extern boolean nodeingame[MAXNETNODES]; // Set false as nodes leave game tic_t freezetimeout; // Until when can this node freeze the server before getting a timeout?
SINT8 player;
SINT8 player2; // say the numplayer for this node if any (splitscreen)
UINT8 numplayers; // used specialy for scplitscreen
tic_t tic; // what tic the client have received
tic_t supposedtic; // nettics prevision for smaller packet
boolean sendingsavegame; // Are we sending the savegame?
boolean resendingsavegame; // Are we resending the savegame?
tic_t savegameresendcooldown; // How long before we can resend again?
} netnode_t;
extern netnode_t netnodes[MAXNETNODES];
extern boolean serverrunning; extern boolean serverrunning;
@ -52,9 +68,6 @@ boolean HSendPacket(INT32 node, boolean reliable, UINT8 acknum,
size_t packetlength); size_t packetlength);
boolean HGetPacket(void); boolean HGetPacket(void);
void D_SetDoomcom(void); void D_SetDoomcom(void);
#ifndef NONET
void D_SaveBan(void);
#endif
boolean D_CheckNetGame(void); boolean D_CheckNetGame(void);
void D_CloseConnection(void); void D_CloseConnection(void);
void Net_UnAcknowledgePacket(INT32 node); void Net_UnAcknowledgePacket(INT32 node);

View file

@ -12,44 +12,46 @@
/// commands are executed through the command buffer /// commands are executed through the command buffer
/// like console commands, other miscellaneous commands (at the end) /// like console commands, other miscellaneous commands (at the end)
#include "doomdef.h" #include "../doomdef.h"
#include "console.h" #include "../console.h"
#include "command.h" #include "../command.h"
#include "i_time.h" #include "../i_time.h"
#include "i_system.h" #include "../i_system.h"
#include "g_game.h" #include "../g_game.h"
#include "hu_stuff.h" #include "../hu_stuff.h"
#include "g_input.h" #include "../g_input.h"
#include "m_menu.h" #include "../m_menu.h"
#include "r_local.h" #include "../r_local.h"
#include "r_skins.h" #include "../r_skins.h"
#include "p_local.h" #include "../p_local.h"
#include "p_setup.h" #include "../p_setup.h"
#include "s_sound.h" #include "../s_sound.h"
#include "i_sound.h" #include "../i_sound.h"
#include "m_misc.h" #include "../m_misc.h"
#include "am_map.h" #include "../am_map.h"
#include "byteptr.h" #include "../byteptr.h"
#include "d_netfil.h" #include "d_netfil.h"
#include "p_spec.h" #include "../p_spec.h"
#include "m_cheat.h" #include "../m_cheat.h"
#include "d_clisrv.h" #include "d_clisrv.h"
#include "server_connection.h"
#include "net_command.h"
#include "d_net.h" #include "d_net.h"
#include "v_video.h" #include "../v_video.h"
#include "d_main.h" #include "../d_main.h"
#include "m_random.h" #include "../m_random.h"
#include "f_finale.h" #include "../f_finale.h"
#include "filesrch.h" #include "../filesrch.h"
#include "mserv.h" #include "mserv.h"
#include "z_zone.h" #include "../z_zone.h"
#include "lua_script.h" #include "../lua_script.h"
#include "lua_hook.h" #include "../lua_hook.h"
#include "m_cond.h" #include "../m_cond.h"
#include "m_anigif.h" #include "../m_anigif.h"
#include "md5.h" #include "../md5.h"
#include "m_perfstats.h" #include "../m_perfstats.h"
#include "u_list.h" #include "../u_list.h"
#ifdef NETGAME_DEVMODE #ifdef NETGAME_DEVMODE
#define CV_RESTRICT CV_NETVAR #define CV_RESTRICT CV_NETVAR
@ -225,6 +227,7 @@ consvar_t cv_seenames = CVAR_INIT ("seenames", "Ally/Foe", CV_SAVE|CV_ALLOWLUA,
consvar_t cv_allowseenames = CVAR_INIT ("allowseenames", "Yes", CV_SAVE|CV_NETVAR|CV_ALLOWLUA, CV_YesNo, NULL); consvar_t cv_allowseenames = CVAR_INIT ("allowseenames", "Yes", CV_SAVE|CV_NETVAR|CV_ALLOWLUA, CV_YesNo, NULL);
// names // names
static char *lastskinnames[2];
consvar_t cv_playername = CVAR_INIT ("name", "Sonic", CV_SAVE|CV_CALL|CV_NOINIT, NULL, Name_OnChange); consvar_t cv_playername = CVAR_INIT ("name", "Sonic", CV_SAVE|CV_CALL|CV_NOINIT, NULL, Name_OnChange);
consvar_t cv_playername2 = CVAR_INIT ("name2", "Tails", CV_SAVE|CV_CALL|CV_NOINIT, NULL, Name2_OnChange); consvar_t cv_playername2 = CVAR_INIT ("name2", "Tails", CV_SAVE|CV_CALL|CV_NOINIT, NULL, Name2_OnChange);
// player colors // player colors
@ -594,13 +597,10 @@ void D_RegisterServerCommands(void)
CV_RegisterVar(&cv_maxsend); CV_RegisterVar(&cv_maxsend);
CV_RegisterVar(&cv_noticedownload); CV_RegisterVar(&cv_noticedownload);
CV_RegisterVar(&cv_downloadspeed); CV_RegisterVar(&cv_downloadspeed);
#ifndef NONET
CV_RegisterVar(&cv_allownewplayer); CV_RegisterVar(&cv_allownewplayer);
CV_RegisterVar(&cv_joinnextround);
CV_RegisterVar(&cv_showjoinaddress); CV_RegisterVar(&cv_showjoinaddress);
CV_RegisterVar(&cv_blamecfail); CV_RegisterVar(&cv_blamecfail);
CV_RegisterVar(&cv_dedicatedidletime); CV_RegisterVar(&cv_dedicatedidletime);
#endif
COM_AddCommand("ping", Command_Ping_f, COM_LUA); COM_AddCommand("ping", Command_Ping_f, COM_LUA);
CV_RegisterVar(&cv_nettimeout); CV_RegisterVar(&cv_nettimeout);
@ -776,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);
@ -1203,27 +1205,38 @@ UINT8 CanChangeSkin(INT32 playernum)
static void ForceAllSkins(INT32 forcedskin) static void ForceAllSkins(INT32 forcedskin)
{ {
INT32 i; for (INT32 i = 0; i < MAXPLAYERS; ++i)
for (i = 0; i < MAXPLAYERS; ++i)
{ {
if (!playeringame[i]) if (playeringame[i])
continue; SetPlayerSkinByNum(i, forcedskin);
SetPlayerSkinByNum(i, forcedskin);
// If it's me (or my brother), set appropriate skin value in cv_skin/cv_skin2
if (!dedicated) // But don't do this for dedicated servers, of course.
{
if (i == consoleplayer)
CV_StealthSet(&cv_skin, skins[forcedskin].name);
else if (i == secondarydisplayplayer)
CV_StealthSet(&cv_skin2, skins[forcedskin].name);
}
} }
} }
static INT32 snacpending = 0, snac2pending = 0, chmappending = 0; static INT32 snacpending = 0, snac2pending = 0, chmappending = 0;
static void SetSkinLocal(INT32 playernum, INT32 skinnum)
{
if (metalrecording && playernum == consoleplayer)
{
// Starring Metal Sonic as themselves, obviously.
SetPlayerSkinByNum(playernum, 5);
return;
}
if (skinnum != -1 && R_SkinUsable(playernum, skinnum))
SetPlayerSkinByNum(playernum, skinnum);
else
SetPlayerSkinByNum(playernum, GetPlayerDefaultSkin(playernum));
}
static void SetColorLocal(INT32 playernum, UINT16 color)
{
players[playernum].skincolor = color;
if (players[playernum].mo && !players[playernum].powers[pw_dye])
players[playernum].mo->color = P_GetPlayerColor(&players[playernum]);
}
// name, color, or skin has changed // name, color, or skin has changed
// //
static void SendNameAndColor(void) static void SendNameAndColor(void)
@ -1233,15 +1246,6 @@ static void SendNameAndColor(void)
p = buf; p = buf;
// normal player colors
if (G_GametypeHasTeams())
{
if (players[consoleplayer].ctfteam == 1 && cv_playercolor.value != skincolor_redteam)
CV_StealthSetValue(&cv_playercolor, skincolor_redteam);
else if (players[consoleplayer].ctfteam == 2 && cv_playercolor.value != skincolor_blueteam)
CV_StealthSetValue(&cv_playercolor, skincolor_blueteam);
}
// don't allow inaccessible colors // don't allow inaccessible colors
if (!skincolors[cv_playercolor.value].accessible) if (!skincolors[cv_playercolor.value].accessible)
{ {
@ -1272,50 +1276,15 @@ static void SendNameAndColor(void)
// If you're not in a netgame, merely update the skin, color, and name. // If you're not in a netgame, merely update the skin, color, and name.
if (!netgame) if (!netgame)
{ {
INT32 foundskin;
CleanupPlayerName(consoleplayer, cv_playername.zstring); CleanupPlayerName(consoleplayer, cv_playername.zstring);
strcpy(player_names[consoleplayer], cv_playername.zstring); strcpy(player_names[consoleplayer], cv_playername.zstring);
players[consoleplayer].skincolor = cv_playercolor.value; SetColorLocal(consoleplayer, cv_playercolor.value);
if (players[consoleplayer].mo && !players[consoleplayer].powers[pw_dye]) if (splitscreen)
players[consoleplayer].mo->color = players[consoleplayer].skincolor; SetSkinLocal(consoleplayer, R_SkinAvailable(cv_skin.string));
if (metalrecording)
{ // Starring Metal Sonic as themselves, obviously.
SetPlayerSkinByNum(consoleplayer, 5);
CV_StealthSet(&cv_skin, skins[5].name);
}
else if ((foundskin = R_SkinAvailable(cv_skin.string)) != -1 && R_SkinUsable(consoleplayer, foundskin))
{
//boolean notsame;
cv_skin.value = foundskin;
//notsame = (cv_skin.value != players[consoleplayer].skin);
SetPlayerSkin(consoleplayer, cv_skin.string);
CV_StealthSet(&cv_skin, skins[cv_skin.value].name);
/*if (notsame)
{
CV_StealthSetValue(&cv_playercolor, skins[cv_skin.value].prefcolor);
players[consoleplayer].skincolor = cv_playercolor.value % numskincolors;
if (players[consoleplayer].mo)
players[consoleplayer].mo->color = (UINT16)players[consoleplayer].skincolor;
}*/
}
else else
{ SetSkinLocal(consoleplayer, pickedchar);
cv_skin.value = players[consoleplayer].skin;
CV_StealthSet(&cv_skin, skins[players[consoleplayer].skin].name);
// will always be same as current
SetPlayerSkin(consoleplayer, cv_skin.string);
}
return; return;
} }
@ -1332,10 +1301,6 @@ static void SendNameAndColor(void)
else // Cleanup name if changing it else // Cleanup name if changing it
CleanupPlayerName(consoleplayer, cv_playername.zstring); CleanupPlayerName(consoleplayer, cv_playername.zstring);
// Don't change skin if the server doesn't want you to.
if (!CanChangeSkin(consoleplayer))
CV_StealthSet(&cv_skin, skins[players[consoleplayer].skin].name);
// check if player has the skin loaded (cv_skin may have // check if player has the skin loaded (cv_skin may have
// the name of a skin that was available in the previous game) // the name of a skin that was available in the previous game)
cv_skin.value = R_SkinAvailable(cv_skin.string); cv_skin.value = R_SkinAvailable(cv_skin.string);
@ -1367,16 +1332,6 @@ static void SendNameAndColor2(void)
else // HACK else // HACK
secondplaya = 1; secondplaya = 1;
// normal player colors
if (G_GametypeHasTeams())
{
if (players[secondplaya].ctfteam == 1 && cv_playercolor2.value != skincolor_redteam)
CV_StealthSetValue(&cv_playercolor2, skincolor_redteam);
else if (players[secondplaya].ctfteam == 2 && cv_playercolor2.value != skincolor_blueteam)
CV_StealthSetValue(&cv_playercolor2, skincolor_blueteam);
}
// don't allow inaccessible colors
if (!skincolors[cv_playercolor2.value].accessible) if (!skincolors[cv_playercolor2.value].accessible)
{ {
if (players[secondplaya].skincolor && skincolors[players[secondplaya].skincolor].accessible) if (players[secondplaya].skincolor && skincolors[players[secondplaya].skincolor].accessible)
@ -1398,63 +1353,24 @@ static void SendNameAndColor2(void)
if (!Playing()) if (!Playing())
return; return;
// If you're not in a netgame, merely update the skin, color, and name.
if (botingame) if (botingame)
{ {
players[secondplaya].skincolor = botcolor; SetColorLocal(secondplaya, botcolor);
if (players[secondplaya].mo && !players[secondplaya].powers[pw_dye])
players[secondplaya].mo->color = players[secondplaya].skincolor;
SetPlayerSkinByNum(secondplaya, botskin-1); SetPlayerSkinByNum(secondplaya, botskin-1);
return; return;
} }
else if (!netgame) else if (!netgame)
{ {
INT32 foundskin; // If you're not in a netgame, merely update the skin, color, and name.
CleanupPlayerName(secondplaya, cv_playername2.zstring); CleanupPlayerName(secondplaya, cv_playername2.zstring);
strcpy(player_names[secondplaya], cv_playername2.zstring); strcpy(player_names[secondplaya], cv_playername2.zstring);
// don't use secondarydisplayplayer: the second player must be 1 SetColorLocal(secondplaya, cv_playercolor2.value);
players[secondplaya].skincolor = cv_playercolor2.value;
if (players[secondplaya].mo && !players[secondplaya].powers[pw_dye])
players[secondplaya].mo->color = players[secondplaya].skincolor;
if (cv_forceskin.value >= 0 && (netgame || multiplayer)) // Server wants everyone to use the same player if (cv_forceskin.value >= 0)
{ SetSkinLocal(secondplaya, cv_forceskin.value);
const INT32 forcedskin = cv_forceskin.value;
SetPlayerSkinByNum(secondplaya, forcedskin);
CV_StealthSet(&cv_skin2, skins[forcedskin].name);
}
else if ((foundskin = R_SkinAvailable(cv_skin2.string)) != -1 && R_SkinUsable(secondplaya, foundskin))
{
//boolean notsame;
cv_skin2.value = foundskin;
//notsame = (cv_skin2.value != players[secondplaya].skin);
SetPlayerSkin(secondplaya, cv_skin2.string);
CV_StealthSet(&cv_skin2, skins[cv_skin2.value].name);
/*if (notsame)
{
CV_StealthSetValue(&cv_playercolor2, skins[players[secondplaya].skin].prefcolor);
players[secondplaya].skincolor = cv_playercolor2.value % numskincolors;
if (players[secondplaya].mo)
players[secondplaya].mo->color = players[secondplaya].skincolor;
}*/
}
else else
{ SetSkinLocal(secondplaya, R_SkinAvailable(cv_skin2.string));
cv_skin2.value = players[secondplaya].skin;
CV_StealthSet(&cv_skin2, skins[players[secondplaya].skin].name);
// will always be same as current
SetPlayerSkin(secondplaya, cv_skin2.string);
}
return; return;
} }
@ -1498,7 +1414,7 @@ static void Got_NameAndColor(UINT8 **cp, INT32 playernum)
// set color // set color
p->skincolor = color % numskincolors; p->skincolor = color % numskincolors;
if (p->mo) if (p->mo)
p->mo->color = (UINT16)p->skincolor; p->mo->color = P_GetPlayerColor(p);
// normal player colors // normal player colors
if (server && (p != &players[consoleplayer] && p != &players[secondarydisplayplayer])) if (server && (p != &players[consoleplayer] && p != &players[secondarydisplayplayer]))
@ -1507,15 +1423,6 @@ static void Got_NameAndColor(UINT8 **cp, INT32 playernum)
UINT32 unlockShift = 0; UINT32 unlockShift = 0;
UINT32 i; UINT32 i;
// team colors
if (G_GametypeHasTeams())
{
if (p->ctfteam == 1 && p->skincolor != skincolor_redteam)
kick = true;
else if (p->ctfteam == 2 && p->skincolor != skincolor_blueteam)
kick = true;
}
// don't allow inaccessible colors // don't allow inaccessible colors
if (skincolors[p->skincolor].accessible == false) if (skincolors[p->skincolor].accessible == false)
kick = true; kick = true;
@ -1556,16 +1463,9 @@ static void Got_NameAndColor(UINT8 **cp, INT32 playernum)
} }
// set skin // set skin
if (cv_forceskin.value >= 0 && (netgame || multiplayer)) // Server wants everyone to use the same player INT32 forcedskin = R_GetForcedSkin(playernum);
{ if (forcedskin != -1 && (netgame || multiplayer)) // Server wants everyone to use the same player (or the level is forcing one.)
const INT32 forcedskin = cv_forceskin.value;
SetPlayerSkinByNum(playernum, forcedskin); SetPlayerSkinByNum(playernum, forcedskin);
if (playernum == consoleplayer)
CV_StealthSet(&cv_skin, skins[forcedskin].name);
else if (playernum == secondarydisplayplayer)
CV_StealthSet(&cv_skin2, skins[forcedskin].name);
}
else else
SetPlayerSkinByNum(playernum, skin); SetPlayerSkinByNum(playernum, skin);
} }
@ -1841,8 +1741,7 @@ void D_MapChange(INT32 mapnum, INT32 newgametype, boolean pultmode, boolean rese
// reset players if there is a new one // reset players if there is a new one
if (!IsPlayerAdmin(consoleplayer)) if (!IsPlayerAdmin(consoleplayer))
{ {
if (SV_SpawnServer()) SV_SpawnServer();
buf[0] &= ~(1<<1);
if (!Playing()) // you failed to start a server somehow, so cancel the map change if (!Playing()) // you failed to start a server somehow, so cancel the map change
return; return;
} }
@ -1902,8 +1801,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 wouldSetCheats; boolean set_cheated;
INT32 newmapnum; INT32 newmapnum;
@ -1924,21 +1823,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");
wouldSetCheats = prevent_cheat = !( usedCheats ) && !( option_force || cv_debug );
!( netgame || multiplayer ) && set_cheated = false;
!( usedCheats );
if (wouldSetCheats && !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)
@ -1946,7 +1858,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? */
@ -1959,7 +1871,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)
{ {
@ -1982,11 +1896,6 @@ static void Command_Map_f(void)
return; return;
} }
if (wouldSetCheats && option_force)
{
G_SetUsedCheats(false);
}
// new gametype value // new gametype value
// use current one by default // use current one by default
if (option_gametype) if (option_gametype)
@ -2028,15 +1937,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"));
@ -2046,23 +1953,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, serverGamedata))
{ {
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
@ -2079,6 +1996,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);
@ -2120,11 +2042,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);
@ -2150,7 +2074,6 @@ static void Got_Mapcmd(UINT8 **cp, INT32 playernum)
{ {
SetPlayerSkinByNum(0, cv_chooseskin.value-1); SetPlayerSkinByNum(0, cv_chooseskin.value-1);
players[0].skincolor = skins[players[0].skin].prefcolor; players[0].skincolor = skins[players[0].skin].prefcolor;
CV_StealthSetValue(&cv_playercolor, players[0].skincolor);
} }
mapnumber = M_MapNumber(mapname[3], mapname[4]); mapnumber = M_MapNumber(mapname[3], mapname[4]);
@ -2904,17 +2827,6 @@ static void Got_Teamchange(UINT8 **cp, INT32 playernum)
displayplayer = consoleplayer; displayplayer = consoleplayer;
} }
if (G_GametypeHasTeams())
{
if (NetPacket.packet.newteam)
{
if (playernum == consoleplayer) //CTF and Team Match colors.
CV_SetValue(&cv_playercolor, NetPacket.packet.newteam + 5);
else if (playernum == secondarydisplayplayer)
CV_SetValue(&cv_playercolor2, NetPacket.packet.newteam + 5);
}
}
// In tag, check to see if you still have a game. // In tag, check to see if you still have a game.
if (G_TagGametype()) if (G_TagGametype())
P_CheckSurvivors(); P_CheckSurvivors();
@ -4252,9 +4164,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
@ -4555,25 +4464,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))
{ {
@ -4583,6 +4504,11 @@ static void Got_ExitLevelcmd(UINT8 **cp, INT32 playernum)
return; return;
} }
if (G_CoopGametype() && cheat)
{
G_SetUsedCheats(false);
}
G_ExitLevel(); G_ExitLevel();
} }
@ -4779,11 +4705,16 @@ static void ForceSkin_OnChange(void)
return; return;
if (cv_forceskin.value < 0) if (cv_forceskin.value < 0)
{
CONS_Printf("The server has lifted the forced skin restrictions.\n"); CONS_Printf("The server has lifted the forced skin restrictions.\n");
if (Playing())
D_SendPlayerConfig();
}
else else
{ {
CONS_Printf("The server is restricting all players to skin \"%s\".\n",skins[cv_forceskin.value].name); CONS_Printf("The server is restricting all players to skin \"%s\".\n",skins[cv_forceskin.value].name);
ForceAllSkins(cv_forceskin.value); if (Playing())
ForceAllSkins(cv_forceskin.value);
} }
} }
@ -4797,7 +4728,6 @@ static void Name_OnChange(void)
} }
else else
SendNameAndColor(); SendNameAndColor();
} }
static void Name2_OnChange(void) static void Name2_OnChange(void)
@ -4820,19 +4750,33 @@ static void Skin_OnChange(void)
if (!Playing()) if (!Playing())
return; // do whatever you want return; // do whatever you want
if (!(cv_debug || devparm) && !(multiplayer || netgame) // In single player. if (lastskinnames[0] == NULL)
&& (gamestate != GS_WAITINGPLAYERS)) // allows command line -warp x +skin y lastskinnames[0] = Z_StrDup(cv_skin.string);
if (!(multiplayer || netgame)) // In single player.
{ {
CV_StealthSet(&cv_skin, skins[players[consoleplayer].skin].name); if (!(cv_debug || devparm)
&& (gamestate != GS_WAITINGPLAYERS)) // allows command line -warp x +skin y
{
CV_StealthSet(&cv_skin, skins[players[consoleplayer].skin].name);
return;
}
// Just do it here if devmode is enabled
SetSkinLocal(consoleplayer, R_SkinAvailable(cv_skin.string));
return; return;
} }
if (CanChangeSkin(consoleplayer) && !P_PlayerMoving(consoleplayer)) if (CanChangeSkin(consoleplayer) && !P_PlayerMoving(consoleplayer))
{
SendNameAndColor(); SendNameAndColor();
Z_Free(lastskinnames[0]);
lastskinnames[0] = Z_StrDup(cv_skin.string);
}
else else
{ {
CONS_Alert(CONS_NOTICE, M_GetText("You can't change your skin at the moment.\n")); CONS_Alert(CONS_NOTICE, M_GetText("You can't change your skin at the moment.\n"));
CV_StealthSet(&cv_skin, skins[players[consoleplayer].skin].name); CV_StealthSet(&cv_skin, lastskinnames[0]);
} }
} }
@ -4846,12 +4790,19 @@ static void Skin2_OnChange(void)
if (!Playing() || !splitscreen) if (!Playing() || !splitscreen)
return; // do whatever you want return; // do whatever you want
if (lastskinnames[1] == NULL)
lastskinnames[1] = Z_StrDup(cv_skin2.string);
if (CanChangeSkin(secondarydisplayplayer) && !P_PlayerMoving(secondarydisplayplayer)) if (CanChangeSkin(secondarydisplayplayer) && !P_PlayerMoving(secondarydisplayplayer))
{
SendNameAndColor2(); SendNameAndColor2();
Z_Free(lastskinnames[1]);
lastskinnames[1] = Z_StrDup(cv_skin.string);
}
else else
{ {
CONS_Alert(CONS_NOTICE, M_GetText("You can't change your skin at the moment.\n")); CONS_Alert(CONS_NOTICE, M_GetText("You can't change your skin at the moment.\n"));
CV_StealthSet(&cv_skin2, skins[players[secondarydisplayplayer].skin].name); CV_StealthSet(&cv_skin2, lastskinnames[1]);
} }
} }
@ -4861,15 +4812,18 @@ static void Skin2_OnChange(void)
*/ */
static void Color_OnChange(void) static void Color_OnChange(void)
{ {
if (!Playing()) { if (!Playing())
{
if (!cv_playercolor.value || !skincolors[cv_playercolor.value].accessible) if (!cv_playercolor.value || !skincolors[cv_playercolor.value].accessible)
CV_StealthSetValue(&cv_playercolor, lastgoodcolor); CV_StealthSetValue(&cv_playercolor, lastgoodcolor);
} }
else else
{ {
if (!(cv_debug || devparm) && !(multiplayer || netgame)) // In single player. if (!(multiplayer || netgame)) // In single player.
{ {
CV_StealthSet(&cv_skin, skins[players[consoleplayer].skin].name); // Just do it here if devmode is enabled
if (cv_debug || devparm)
SetColorLocal(consoleplayer, cv_playercolor.value);
return; return;
} }

View file

@ -15,7 +15,7 @@
#ifndef __D_NETCMD__ #ifndef __D_NETCMD__
#define __D_NETCMD__ #define __D_NETCMD__
#include "command.h" #include "../command.h"
// console vars // console vars
extern consvar_t cv_playername; extern consvar_t cv_playername;
@ -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

@ -31,24 +31,25 @@
#include <sys/utime.h> #include <sys/utime.h>
#endif #endif
#include "doomdef.h" #include "../doomdef.h"
#include "doomstat.h" #include "../doomstat.h"
#include "d_main.h" #include "../d_main.h"
#include "g_game.h" #include "../g_game.h"
#include "i_time.h" #include "../i_time.h"
#include "i_net.h" #include "i_net.h"
#include "i_system.h" #include "../i_system.h"
#include "m_argv.h" #include "../m_argv.h"
#include "d_net.h" #include "d_net.h"
#include "w_wad.h" #include "../w_wad.h"
#include "d_netfil.h" #include "d_netfil.h"
#include "z_zone.h" #include "net_command.h"
#include "byteptr.h" #include "../z_zone.h"
#include "p_setup.h" #include "../byteptr.h"
#include "m_misc.h" #include "../p_setup.h"
#include "m_menu.h" #include "../m_misc.h"
#include "md5.h" #include "../m_menu.h"
#include "filesrch.h" #include "../md5.h"
#include "../filesrch.h"
#include <errno.h> #include <errno.h>
@ -103,26 +104,31 @@ typedef struct
} pauseddownload_t; } pauseddownload_t;
static pauseddownload_t *pauseddownload = NULL; static pauseddownload_t *pauseddownload = NULL;
#ifndef NONET
// for cl loading screen // for cl loading screen
INT32 lastfilenum = -1; INT32 lastfilenum = -1;
INT32 downloadcompletednum = 0; INT32 downloadcompletednum = 0;
UINT32 downloadcompletedsize = 0; UINT32 downloadcompletedsize = 0;
INT32 totalfilesrequestednum = 0; INT32 totalfilesrequestednum = 0;
UINT32 totalfilesrequestedsize = 0; UINT32 totalfilesrequestedsize = 0;
#endif
luafiletransfer_t *luafiletransfers = NULL; luafiletransfer_t *luafiletransfers = NULL;
boolean waitingforluafiletransfer = false; boolean waitingforluafiletransfer = false;
boolean waitingforluafilecommand = false; boolean waitingforluafilecommand = false;
char luafiledir[256 + 16] = "luafiles"; char luafiledir[256 + 16] = "luafiles";
// max file size to send to a player (in kilobytes)
static CV_PossibleValue_t maxsend_cons_t[] = {{0, "MIN"}, {204800, "MAX"}, {0, NULL}};
consvar_t cv_maxsend = CVAR_INIT ("maxsend", "4096", CV_SAVE|CV_NETVAR, maxsend_cons_t, NULL);
consvar_t cv_noticedownload = CVAR_INIT ("noticedownload", "Off", CV_SAVE|CV_NETVAR, CV_OnOff, NULL);
// Speed of file downloading (in packets per tic)
static CV_PossibleValue_t downloadspeed_cons_t[] = {{1, "MIN"}, {300, "MAX"}, {0, NULL}};
consvar_t cv_downloadspeed = CVAR_INIT ("downloadspeed", "16", CV_SAVE|CV_NETVAR, downloadspeed_cons_t, NULL);
static UINT16 GetWadNumFromFileNeededId(UINT8 id) static UINT16 GetWadNumFromFileNeededId(UINT8 id)
{ {
UINT16 wadnum; for (UINT16 wadnum = mainwads; wadnum < numwadfiles; wadnum++)
for (wadnum = mainwads; wadnum < numwadfiles; wadnum++)
{ {
if (!wadfiles[wadnum]->important) if (!wadfiles[wadnum]->important)
continue; continue;
@ -142,14 +148,13 @@ static UINT16 GetWadNumFromFileNeededId(UINT8 id)
*/ */
UINT8 *PutFileNeeded(UINT16 firstfile) UINT8 *PutFileNeeded(UINT16 firstfile)
{ {
size_t i;
UINT8 count = 0; UINT8 count = 0;
UINT8 *p_start = netbuffer->packettype == PT_MOREFILESNEEDED ? netbuffer->u.filesneededcfg.files : netbuffer->u.serverinfo.fileneeded; UINT8 *p_start = netbuffer->packettype == PT_MOREFILESNEEDED ? netbuffer->u.filesneededcfg.files : netbuffer->u.serverinfo.fileneeded;
UINT8 *p = p_start; UINT8 *p = p_start;
char wadfilename[MAX_WADPATH] = ""; char wadfilename[MAX_WADPATH] = "";
UINT8 filestatus, folder; UINT8 filestatus, folder;
for (i = mainwads; i < numwadfiles; i++) //mainwads, otherwise we start on the first mainwad for (size_t i = mainwads; i < numwadfiles; i++) //mainwads, otherwise we start on the first mainwad
{ {
// If it has only music/sound lumps, don't put it in the list // If it has only music/sound lumps, don't put it in the list
if (!wadfiles[i]->important) if (!wadfiles[i]->important)
@ -224,7 +229,6 @@ void FreeFileNeeded(void)
*/ */
void D_ParseFileneeded(INT32 fileneedednum_parm, UINT8 *fileneededstr, UINT16 firstfile) void D_ParseFileneeded(INT32 fileneedednum_parm, UINT8 *fileneededstr, UINT16 firstfile)
{ {
INT32 i;
UINT8 *p; UINT8 *p;
UINT8 filestatus; UINT8 filestatus;
@ -233,7 +237,7 @@ void D_ParseFileneeded(INT32 fileneedednum_parm, UINT8 *fileneededstr, UINT16 fi
AllocFileNeeded(fileneedednum); AllocFileNeeded(fileneedednum);
for (i = firstfile; i < fileneedednum; i++) for (INT32 i = firstfile; i < fileneedednum; i++)
{ {
fileneeded[i].type = FILENEEDED_WAD; fileneeded[i].type = FILENEEDED_WAD;
fileneeded[i].status = FS_NOTCHECKED; // We haven't even started looking for the file yet fileneeded[i].status = FS_NOTCHECKED; // We haven't even started looking for the file yet
@ -250,9 +254,7 @@ void D_ParseFileneeded(INT32 fileneedednum_parm, UINT8 *fileneededstr, UINT16 fi
void CL_PrepareDownloadSaveGame(const char *tmpsave) void CL_PrepareDownloadSaveGame(const char *tmpsave)
{ {
#ifndef NONET
lastfilenum = -1; lastfilenum = -1;
#endif
FreeFileNeeded(); FreeFileNeeded();
AllocFileNeeded(1); AllocFileNeeded(1);
@ -275,9 +277,9 @@ void CL_PrepareDownloadSaveGame(const char *tmpsave)
*/ */
boolean CL_CheckDownloadable(void) boolean CL_CheckDownloadable(void)
{ {
UINT8 i,dlstatus = 0; UINT8 dlstatus = 0;
for (i = 0; i < fileneedednum; i++) for (UINT8 i = 0; i < fileneedednum; i++)
if (fileneeded[i].status != FS_FOUND && fileneeded[i].status != FS_OPEN) if (fileneeded[i].status != FS_FOUND && fileneeded[i].status != FS_OPEN)
{ {
if (fileneeded[i].willsend == 1) if (fileneeded[i].willsend == 1)
@ -298,7 +300,7 @@ boolean CL_CheckDownloadable(void)
// not downloadable, put reason in console // not downloadable, put reason in console
CONS_Alert(CONS_NOTICE, M_GetText("You need additional files to connect to this server:\n")); CONS_Alert(CONS_NOTICE, M_GetText("You need additional files to connect to this server:\n"));
for (i = 0; i < fileneedednum; i++) for (UINT8 i = 0; i < fileneedednum; i++)
if (fileneeded[i].status != FS_FOUND && fileneeded[i].status != FS_OPEN) if (fileneeded[i].status != FS_FOUND && fileneeded[i].status != FS_OPEN)
{ {
CONS_Printf(" * \"%s\" (%dK)", fileneeded[i].filename, fileneeded[i].totalsize >> 10); CONS_Printf(" * \"%s\" (%dK)", fileneeded[i].filename, fileneeded[i].totalsize >> 10);
@ -368,14 +370,13 @@ void CL_AbortDownloadResume(void)
boolean CL_SendFileRequest(void) boolean CL_SendFileRequest(void)
{ {
char *p; char *p;
INT32 i;
INT64 totalfreespaceneeded = 0, availablefreespace; INT64 totalfreespaceneeded = 0, availablefreespace;
#ifdef PARANOIA #ifdef PARANOIA
if (M_CheckParm("-nodownload")) if (M_CheckParm("-nodownload"))
I_Error("Attempted to download files in -nodownload mode"); I_Error("Attempted to download files in -nodownload mode");
for (i = 0; i < fileneedednum; i++) for (INT32 i = 0; i < fileneedednum; i++)
if (fileneeded[i].status != FS_FOUND && fileneeded[i].status != FS_OPEN if (fileneeded[i].status != FS_FOUND && fileneeded[i].status != FS_OPEN
&& (fileneeded[i].willsend == 0 || fileneeded[i].willsend == 2)) && (fileneeded[i].willsend == 0 || fileneeded[i].willsend == 2))
{ {
@ -385,7 +386,7 @@ boolean CL_SendFileRequest(void)
netbuffer->packettype = PT_REQUESTFILE; netbuffer->packettype = PT_REQUESTFILE;
p = (char *)netbuffer->u.textcmd; p = (char *)netbuffer->u.textcmd;
for (i = 0; i < fileneedednum; i++) for (INT32 i = 0; i < fileneedednum; i++)
if ((fileneeded[i].status == FS_NOTFOUND || fileneeded[i].status == FS_MD5SUMBAD)) if ((fileneeded[i].status == FS_NOTFOUND || fileneeded[i].status == FS_MD5SUMBAD))
{ {
totalfreespaceneeded += fileneeded[i].totalsize; totalfreespaceneeded += fileneeded[i].totalsize;
@ -413,26 +414,31 @@ boolean CL_SendFileRequest(void)
} }
// get request filepak and put it on the send queue // get request filepak and put it on the send queue
// returns false if a requested file was not found or cannot be sent void PT_RequestFile(SINT8 node)
boolean PT_RequestFile(INT32 node)
{ {
UINT8 *p = netbuffer->u.textcmd; UINT8 *p = netbuffer->u.textcmd;
UINT8 id;
if (client || !cv_downloading.value)
{
Net_CloseConnection(node); // close connection if you are not the server or disabled downloading
return;
}
while (p < netbuffer->u.textcmd + MAXTEXTCMD-1) // Don't allow hacked client to overflow while (p < netbuffer->u.textcmd + MAXTEXTCMD-1) // Don't allow hacked client to overflow
{ {
id = READUINT8(p); UINT8 id = READUINT8(p);
if (id == 0xFF) if (id == 0xFF)
break; break;
if (!AddFileToSendQueue(node, id)) if (!AddFileToSendQueue(node, id))
{ {
SV_AbortSendFiles(node); SV_AbortSendFiles(node);
return false; // don't read the rest of the files Net_CloseConnection(node); // close connection if one of the requested files could not be sent
return; // don't read the rest of the files
} }
} }
return true; // no problems with any files return; // no problems with any files
} }
/** Checks if the files needed aren't already loaded or on the disk /** Checks if the files needed aren't already loaded or on the disk
@ -531,9 +537,7 @@ INT32 CL_CheckFiles(void)
// Load it now // Load it now
boolean CL_LoadServerFiles(void) boolean CL_LoadServerFiles(void)
{ {
INT32 i; for (INT32 i = 0; i < fileneedednum; i++)
for (i = 0; i < fileneedednum; i++)
{ {
if (fileneeded[i].status == FS_OPEN) if (fileneeded[i].status == FS_OPEN)
continue; // Already loaded continue; // Already loaded
@ -629,11 +633,10 @@ void AddLuaFileTransfer(const char *filename, const char *mode)
static void SV_PrepareSendLuaFileToNextNode(void) static void SV_PrepareSendLuaFileToNextNode(void)
{ {
INT32 i;
UINT8 success = 1; UINT8 success = 1;
// Find a client to send the file to // Find a client to send the file to
for (i = 1; i < MAXNETNODES; i++) for (INT32 i = 1; i < MAXNETNODES; i++)
if (luafiletransfers->nodestatus[i] == LFTNS_WAITING) // Node waiting if (luafiletransfers->nodestatus[i] == LFTNS_WAITING) // Node waiting
{ {
// Tell the client we're about to send them the file // Tell the client we're about to send them the file
@ -655,13 +658,12 @@ static void SV_PrepareSendLuaFileToNextNode(void)
void SV_PrepareSendLuaFile(void) void SV_PrepareSendLuaFile(void)
{ {
char *binfilename; char *binfilename;
INT32 i;
luafiletransfers->ongoing = true; luafiletransfers->ongoing = true;
// Set status to "waiting" for everyone // Set status to "waiting" for everyone
for (i = 0; i < MAXNETNODES; i++) for (INT32 i = 0; i < MAXNETNODES; i++)
luafiletransfers->nodestatus[i] = (nodeingame[i] ? LFTNS_WAITING : LFTNS_NONE); luafiletransfers->nodestatus[i] = (netnodes[i].ingame ? LFTNS_WAITING : LFTNS_NONE);
if (FIL_ReadFileOK(luafiletransfers->realfilename)) if (FIL_ReadFileOK(luafiletransfers->realfilename))
{ {
@ -1137,12 +1139,13 @@ void FileSendTicker(void)
} }
} }
void PT_FileAck(void) void PT_FileAck(SINT8 node)
{ {
fileack_pak *packet = &netbuffer->u.fileack; fileack_pak *packet = &netbuffer->u.fileack;
INT32 node = doomcom->remotenode;
filetran_t *trans = &transfer[node]; filetran_t *trans = &transfer[node];
INT32 i, j;
if (client)
return;
// Wrong file id? Ignore it, it's probably a late packet // Wrong file id? Ignore it, it's probably a late packet
if (!(trans->txlist && packet->fileid == trans->txlist->fileid)) if (!(trans->txlist && packet->fileid == trans->txlist->fileid))
@ -1161,11 +1164,11 @@ void PT_FileAck(void)
trans->dontsenduntil = 0; trans->dontsenduntil = 0;
} }
for (i = 0; i < packet->numsegments; i++) for (INT32 i = 0; i < packet->numsegments; i++)
{ {
fileacksegment_t *segment = &packet->segments[i]; fileacksegment_t *segment = &packet->segments[i];
for (j = 0; j < 32; j++) for (INT32 j = 0; j < 32; j++)
if (LONG(segment->acks) & (1 << j)) if (LONG(segment->acks) & (1 << j))
{ {
if (LONG(segment->start) * FILEFRAGMENTSIZE >= trans->txlist->size) if (LONG(segment->start) * FILEFRAGMENTSIZE >= trans->txlist->size)
@ -1190,24 +1193,23 @@ void PT_FileAck(void)
} }
} }
void PT_FileReceived(void) void PT_FileReceived(SINT8 node)
{ {
filetx_t *trans = transfer[doomcom->remotenode].txlist; filetx_t *trans = transfer[node].txlist;
if (trans && netbuffer->u.filereceived == trans->fileid) if (server && trans && netbuffer->u.filereceived == trans->fileid)
SV_EndFileSend(doomcom->remotenode); SV_EndFileSend(node);
} }
static void SendAckPacket(fileack_pak *packet, UINT8 fileid) static void SendAckPacket(fileack_pak *packet, UINT8 fileid)
{ {
size_t packetsize; size_t packetsize;
INT32 i;
packetsize = sizeof(*packet) + packet->numsegments * sizeof(*packet->segments); packetsize = sizeof(*packet) + packet->numsegments * sizeof(*packet->segments);
// Finalise the packet // Finalise the packet
packet->fileid = fileid; packet->fileid = fileid;
for (i = 0; i < packet->numsegments; i++) for (INT32 i = 0; i < packet->numsegments; i++)
{ {
packet->segments[i].start = LONG(packet->segments[i].start); packet->segments[i].start = LONG(packet->segments[i].start);
packet->segments[i].acks = LONG(packet->segments[i].acks); packet->segments[i].acks = LONG(packet->segments[i].acks);
@ -1247,9 +1249,7 @@ static void AddFragmentToAckPacket(fileack_pak *packet, UINT8 iteration, UINT32
void FileReceiveTicker(void) void FileReceiveTicker(void)
{ {
INT32 i; for (INT32 i = 0; i < fileneedednum; i++)
for (i = 0; i < fileneedednum; i++)
{ {
fileneeded_t *file = &fileneeded[i]; fileneeded_t *file = &fileneeded[i];
@ -1263,8 +1263,7 @@ void FileReceiveTicker(void)
if (file->ackresendposition != UINT32_MAX && file->status == FS_DOWNLOADING) if (file->ackresendposition != UINT32_MAX && file->status == FS_DOWNLOADING)
{ {
// Acknowledge ~70 MB/s, whichs means the client sends ~18 KB/s // Acknowledge ~70 MB/s, whichs means the client sends ~18 KB/s
INT32 j; for (INT32 j = 0; j < 2048; j++)
for (j = 0; j < 2048; j++)
{ {
if (file->receivedfragments[file->ackresendposition]) if (file->receivedfragments[file->ackresendposition])
AddFragmentToAckPacket(file->ackpacket, file->iteration, file->ackresendposition, i); AddFragmentToAckPacket(file->ackpacket, file->iteration, file->ackresendposition, i);
@ -1281,8 +1280,27 @@ void FileReceiveTicker(void)
} }
} }
void PT_FileFragment(void) void PT_FileFragment(SINT8 node, INT32 netconsole)
{ {
if (netnodes[node].ingame)
{
// Only accept PT_FILEFRAGMENT from the server.
if (node != servernode)
{
CONS_Alert(CONS_WARNING, M_GetText("%s received from non-host %d\n"), "PT_FILEFRAGMENT", node);
if (server)
SendKick(netconsole, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY);
return;
}
if (server)
return;
}
else if (server || node != servernode)
{
Net_CloseConnection(node);
return;
}
INT32 filenum = netbuffer->u.filetxpak.fileid; INT32 filenum = netbuffer->u.filetxpak.fileid;
fileneeded_t *file = &fileneeded[filenum]; fileneeded_t *file = &fileneeded[filenum];
UINT32 fragmentpos = LONG(netbuffer->u.filetxpak.position); UINT32 fragmentpos = LONG(netbuffer->u.filetxpak.position);
@ -1439,9 +1457,7 @@ void PT_FileFragment(void)
I_Error("Received a file not requested (file id: %d, file status: %s)\n", filenum, s); I_Error("Received a file not requested (file id: %d, file status: %s)\n", filenum, s);
} }
#ifndef NONET
lastfilenum = filenum; lastfilenum = filenum;
#endif
} }
/** \brief Checks if a node is downloading a file /** \brief Checks if a node is downloading a file
@ -1469,15 +1485,14 @@ void SV_AbortSendFiles(INT32 node)
void CloseNetFile(void) void CloseNetFile(void)
{ {
INT32 i;
// Is sending? // Is sending?
for (i = 0; i < MAXNETNODES; i++) for (INT32 i = 0; i < MAXNETNODES; i++)
SV_AbortSendFiles(i); SV_AbortSendFiles(i);
// Receiving a file? // Receiving a file?
if (fileneeded) if (fileneeded)
{ {
for (i = 0; i < fileneedednum; i++) for (INT32 i = 0; i < fileneedednum; i++)
if (fileneeded[i].status == FS_DOWNLOADING && fileneeded[i].file) if (fileneeded[i].status == FS_DOWNLOADING && fileneeded[i].file)
{ {
fclose(fileneeded[i].file); fclose(fileneeded[i].file);
@ -1510,9 +1525,7 @@ void CloseNetFile(void)
void Command_Downloads_f(void) void Command_Downloads_f(void)
{ {
INT32 node; for (INT32 node = 0; node < MAXNETNODES; node++)
for (node = 0; node < MAXNETNODES; node++)
if (transfer[node].txlist if (transfer[node].txlist
&& transfer[node].txlist->ram == SF_FILE) // Node is downloading a file? && transfer[node].txlist->ram == SF_FILE) // Node is downloading a file?
{ {
@ -1546,14 +1559,11 @@ void Command_Downloads_f(void)
void nameonly(char *s) void nameonly(char *s)
{ {
size_t j, len; for (size_t j = strlen(s); j != (size_t)-1; j--)
void *ns;
for (j = strlen(s); j != (size_t)-1; j--)
if ((s[j] == '\\') || (s[j] == ':') || (s[j] == '/')) if ((s[j] == '\\') || (s[j] == ':') || (s[j] == '/'))
{ {
ns = &(s[j+1]); void *ns = &(s[j+1]);
len = strlen(ns); size_t len = strlen(ns);
#if 0 #if 0
M_Memcpy(s, ns, len+1); M_Memcpy(s, ns, len+1);
#else #else
@ -1566,9 +1576,9 @@ void nameonly(char *s)
// Returns the length in characters of the last element of a path. // Returns the length in characters of the last element of a path.
size_t nameonlylength(const char *s) size_t nameonlylength(const char *s)
{ {
size_t j, len = strlen(s); size_t len = strlen(s);
for (j = len; j != (size_t)-1; j--) for (size_t j = len; j != (size_t)-1; j--)
if ((s[j] == '\\') || (s[j] == ':') || (s[j] == '/')) if ((s[j] == '\\') || (s[j] == ':') || (s[j] == '/'))
return len - j - 1; return len - j - 1;

View file

@ -15,7 +15,7 @@
#include "d_net.h" #include "d_net.h"
#include "d_clisrv.h" #include "d_clisrv.h"
#include "w_wad.h" #include "../w_wad.h"
typedef enum typedef enum
{ {
@ -70,13 +70,13 @@ extern INT32 fileneedednum;
extern fileneeded_t *fileneeded; extern fileneeded_t *fileneeded;
extern char downloaddir[512]; extern char downloaddir[512];
#ifndef NONET
extern INT32 lastfilenum; extern INT32 lastfilenum;
extern INT32 downloadcompletednum; extern INT32 downloadcompletednum;
extern UINT32 downloadcompletedsize; extern UINT32 downloadcompletedsize;
extern INT32 totalfilesrequestednum; extern INT32 totalfilesrequestednum;
extern UINT32 totalfilesrequestedsize; extern UINT32 totalfilesrequestedsize;
#endif
extern consvar_t cv_maxsend, cv_noticedownload, cv_downloadspeed;
void AllocFileNeeded(INT32 size); void AllocFileNeeded(INT32 size);
void FreeFileNeeded(void); void FreeFileNeeded(void);
@ -90,16 +90,16 @@ void AddRamToSendQueue(INT32 node, void *data, size_t size, freemethod_t freemet
UINT8 fileid); UINT8 fileid);
void FileSendTicker(void); void FileSendTicker(void);
void PT_FileAck(void); void PT_FileAck(SINT8 node);
void PT_FileReceived(void); void PT_FileReceived(SINT8 node);
boolean SendingFile(INT32 node); boolean SendingFile(INT32 node);
void FileReceiveTicker(void); void FileReceiveTicker(void);
void PT_FileFragment(void); void PT_FileFragment(SINT8 node, INT32 netconsole);
boolean CL_CheckDownloadable(void); boolean CL_CheckDownloadable(void);
boolean CL_SendFileRequest(void); boolean CL_SendFileRequest(void);
boolean PT_RequestFile(INT32 node); void PT_RequestFile(SINT8 node);
typedef enum typedef enum
{ {

336
src/netcode/gamestate.c Normal file
View file

@ -0,0 +1,336 @@
// 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 gamestate.c
/// \brief Gamestate (re)sending
#include "d_clisrv.h"
#include "d_netfil.h"
#include "gamestate.h"
#include "i_net.h"
#include "protocol.h"
#include "server_connection.h"
#include "../am_map.h"
#include "../byteptr.h"
#include "../console.h"
#include "../d_main.h"
#include "../doomstat.h"
#include "../doomtype.h"
#include "../f_finale.h"
#include "../g_demo.h"
#include "../g_game.h"
#include "../i_time.h"
#include "../lua_script.h"
#include "../lzf.h"
#include "../m_misc.h"
#include "../p_local.h"
#include "../p_saveg.h"
#include "../r_main.h"
#include "../tables.h"
#include "../z_zone.h"
#if defined (__GNUC__) || defined (__unix__)
#include <unistd.h>
#endif
#define SAVEGAMESIZE (768*1024)
UINT8 hu_redownloadinggamestate = 0;
boolean cl_redownloadinggamestate = false;
boolean SV_ResendingSavegameToAnyone(void)
{
for (INT32 i = 0; i < MAXNETNODES; i++)
if (netnodes[i].resendingsavegame)
return true;
return false;
}
void SV_SendSaveGame(INT32 node, boolean resending)
{
size_t length, compressedlen;
UINT8 *savebuffer;
UINT8 *compressedsave;
UINT8 *buffertosend;
// first save it in a malloced buffer
savebuffer = (UINT8 *)malloc(SAVEGAMESIZE);
if (!savebuffer)
{
CONS_Alert(CONS_ERROR, M_GetText("No more free memory for savegame\n"));
return;
}
// Leave room for the uncompressed length.
save_p = savebuffer + sizeof(UINT32);
P_SaveNetGame(resending);
length = save_p - savebuffer;
if (length > SAVEGAMESIZE)
{
free(savebuffer);
save_p = NULL;
I_Error("Savegame buffer overrun");
}
// Allocate space for compressed save: one byte fewer than for the
// uncompressed data to ensure that the compression is worthwhile.
compressedsave = malloc(length - 1);
if (!compressedsave)
{
CONS_Alert(CONS_ERROR, M_GetText("No more free memory for savegame\n"));
return;
}
// Attempt to compress it.
if((compressedlen = lzf_compress(savebuffer + sizeof(UINT32), length - sizeof(UINT32), compressedsave + sizeof(UINT32), length - sizeof(UINT32) - 1)))
{
// Compressing succeeded; send compressed data
free(savebuffer);
// State that we're compressed.
buffertosend = compressedsave;
WRITEUINT32(compressedsave, length - sizeof(UINT32));
length = compressedlen + sizeof(UINT32);
}
else
{
// Compression failed to make it smaller; send original
free(compressedsave);
// State that we're not compressed
buffertosend = savebuffer;
WRITEUINT32(savebuffer, 0);
}
AddRamToSendQueue(node, buffertosend, length, SF_RAM, 0);
save_p = NULL;
// Remember when we started sending the savegame so we can handle timeouts
netnodes[node].sendingsavegame = true;
netnodes[node].freezetimeout = I_GetTime() + jointimeout + length / 1024; // 1 extra tic for each kilobyte
}
#ifdef DUMPCONSISTENCY
#define TMPSAVENAME "badmath.sav"
static consvar_t cv_dumpconsistency = CVAR_INIT ("dumpconsistency", "Off", CV_SAVE|CV_NETVAR, CV_OnOff, NULL);
void SV_SavedGame(void)
{
size_t length;
UINT8 *savebuffer;
char tmpsave[256];
if (!cv_dumpconsistency.value)
return;
sprintf(tmpsave, "%s" PATHSEP TMPSAVENAME, srb2home);
// first save it in a malloced buffer
save_p = savebuffer = (UINT8 *)malloc(SAVEGAMESIZE);
if (!save_p)
{
CONS_Alert(CONS_ERROR, M_GetText("No more free memory for savegame\n"));
return;
}
P_SaveNetGame(false);
length = save_p - savebuffer;
if (length > SAVEGAMESIZE)
{
free(savebuffer);
save_p = NULL;
I_Error("Savegame buffer overrun");
}
// then save it!
if (!FIL_WriteFile(tmpsave, savebuffer, length))
CONS_Printf(M_GetText("Didn't save %s for netgame"), tmpsave);
free(savebuffer);
save_p = NULL;
}
#undef TMPSAVENAME
#endif
#define TMPSAVENAME "$$$.sav"
void CL_LoadReceivedSavegame(boolean reloading)
{
UINT8 *savebuffer = NULL;
size_t length, decompressedlen;
char tmpsave[256];
FreeFileNeeded();
sprintf(tmpsave, "%s" PATHSEP TMPSAVENAME, srb2home);
length = FIL_ReadFile(tmpsave, &savebuffer);
CONS_Printf(M_GetText("Loading savegame length %s\n"), sizeu1(length));
if (!length)
{
I_Error("Can't read savegame sent");
return;
}
save_p = savebuffer;
// Decompress saved game if necessary.
decompressedlen = READUINT32(save_p);
if(decompressedlen > 0)
{
UINT8 *decompressedbuffer = Z_Malloc(decompressedlen, PU_STATIC, NULL);
lzf_decompress(save_p, length - sizeof(UINT32), decompressedbuffer, decompressedlen);
Z_Free(savebuffer);
save_p = savebuffer = decompressedbuffer;
}
paused = false;
demoplayback = false;
titlemapinaction = TITLEMAP_OFF;
titledemo = false;
automapactive = false;
// load a base level
if (P_LoadNetGame(reloading))
{
const UINT8 actnum = mapheaderinfo[gamemap-1]->actnum;
CONS_Printf(M_GetText("Map is now \"%s"), G_BuildMapName(gamemap));
if (strcmp(mapheaderinfo[gamemap-1]->lvlttl, ""))
{
CONS_Printf(": %s", mapheaderinfo[gamemap-1]->lvlttl);
if (!(mapheaderinfo[gamemap-1]->levelflags & LF_NOZONE))
CONS_Printf(M_GetText(" Zone"));
if (actnum > 0)
CONS_Printf(" %2d", actnum);
}
CONS_Printf("\"\n");
}
// done
Z_Free(savebuffer);
save_p = NULL;
if (unlink(tmpsave) == -1)
CONS_Alert(CONS_ERROR, M_GetText("Can't delete %s\n"), tmpsave);
consistancy[gametic%BACKUPTICS] = Consistancy();
CON_ToggleOff();
// Tell the server we have received and reloaded the gamestate
// so they know they can resume the game
netbuffer->packettype = PT_RECEIVEDGAMESTATE;
HSendPacket(servernode, true, 0, 0);
}
void CL_ReloadReceivedSavegame(void)
{
for (INT32 i = 0; i < MAXPLAYERS; i++)
{
LUA_InvalidatePlayer(&players[i]);
sprintf(player_names[i], "Player %d", i + 1);
}
CL_LoadReceivedSavegame(true);
neededtic = max(neededtic, gametic);
maketic = neededtic;
ticcmd_oldangleturn[0] = players[consoleplayer].oldrelangleturn;
P_ForceLocalAngle(&players[consoleplayer], (angle_t)(players[consoleplayer].angleturn << 16));
if (splitscreen)
{
ticcmd_oldangleturn[1] = players[secondarydisplayplayer].oldrelangleturn;
P_ForceLocalAngle(&players[secondarydisplayplayer], (angle_t)(players[secondarydisplayplayer].angleturn << 16));
}
camera.subsector = R_PointInSubsector(camera.x, camera.y);
camera2.subsector = R_PointInSubsector(camera2.x, camera2.y);
cl_redownloadinggamestate = false;
CONS_Printf(M_GetText("Game state reloaded\n"));
}
void Command_ResendGamestate(void)
{
SINT8 playernum;
if (COM_Argc() == 1)
{
CONS_Printf(M_GetText("resendgamestate <playername/playernum>: resend the game state to a player\n"));
return;
}
else if (client)
{
CONS_Printf(M_GetText("Only the server can use this.\n"));
return;
}
playernum = nametonum(COM_Argv(1));
if (playernum == -1 || playernum == 0)
return;
// Send a PT_WILLRESENDGAMESTATE packet to the client so they know what's going on
netbuffer->packettype = PT_WILLRESENDGAMESTATE;
if (!HSendPacket(playernode[playernum], true, 0, 0))
{
CONS_Alert(CONS_ERROR, M_GetText("A problem occurred, please try again.\n"));
return;
}
}
void PT_CanReceiveGamestate(SINT8 node)
{
if (client || netnodes[node].sendingsavegame)
return;
CONS_Printf(M_GetText("Resending game state to %s...\n"), player_names[netnodes[node].player]);
SV_SendSaveGame(node, true); // Resend a complete game state
netnodes[node].resendingsavegame = true;
}
void PT_ReceivedGamestate(SINT8 node)
{
netnodes[node].sendingsavegame = false;
netnodes[node].resendingsavegame = false;
netnodes[node].savegameresendcooldown = I_GetTime() + 5 * TICRATE;
}
void PT_WillResendGamestate(SINT8 node)
{
(void)node;
char tmpsave[256];
if (server || cl_redownloadinggamestate)
return;
// Send back a PT_CANRECEIVEGAMESTATE packet to the server
// so they know they can start sending the game state
netbuffer->packettype = PT_CANRECEIVEGAMESTATE;
if (!HSendPacket(servernode, true, 0, 0))
return;
CONS_Printf(M_GetText("Reloading game state...\n"));
sprintf(tmpsave, "%s" PATHSEP TMPSAVENAME, srb2home);
// Don't get a corrupt savegame error because tmpsave already exists
if (FIL_FileExists(tmpsave) && unlink(tmpsave) == -1)
I_Error("Can't delete %s\n", tmpsave);
CL_PrepareDownloadSaveGame(tmpsave);
cl_redownloadinggamestate = true;
}

31
src/netcode/gamestate.h Normal file
View file

@ -0,0 +1,31 @@
// 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 gamestate.h
/// \brief Gamestate (re)sending
#ifndef __GAMESTATE__
#define __GAMESTATE__
#include "../doomtype.h"
extern UINT8 hu_redownloadinggamestate;
extern boolean cl_redownloadinggamestate;
boolean SV_ResendingSavegameToAnyone(void);
void SV_SendSaveGame(INT32 node, boolean resending);
void SV_SavedGame(void);
void CL_LoadReceivedSavegame(boolean reloading);
void CL_ReloadReceivedSavegame(void);
void Command_ResendGamestate(void);
void PT_CanReceiveGamestate(SINT8 node);
void PT_ReceivedGamestate(SINT8 node);
void PT_WillResendGamestate(SINT8 node);
#endif

View file

@ -18,14 +18,15 @@ Documentation available here.
#include <curl/curl.h> #include <curl/curl.h>
#endif #endif
#include "doomdef.h" #include "../doomdef.h"
#include "d_clisrv.h" #include "d_clisrv.h"
#include "command.h" #include "client_connection.h"
#include "m_argv.h" #include "../command.h"
#include "m_menu.h" #include "../m_argv.h"
#include "../m_menu.h"
#include "mserv.h" #include "mserv.h"
#include "i_tcp.h"/* for current_port */ #include "i_tcp.h"/* for current_port */
#include "i_threads.h" #include "../i_threads.h"
/* reasonable default I guess?? */ /* reasonable default I guess?? */
#define DEFAULT_BUFFER_SIZE (4096) #define DEFAULT_BUFFER_SIZE (4096)
@ -95,7 +96,7 @@ init_user_agent_once(void)
{ {
if (hms_useragent[0] != '\0') if (hms_useragent[0] != '\0')
return; return;
get_user_agent(hms_useragent, 512); get_user_agent(hms_useragent, 512);
} }

View file

@ -18,8 +18,8 @@
#pragma interface #pragma interface
#endif #endif
#include "doomdef.h" #include "../doomdef.h"
#include "command.h" #include "../command.h"
/// \brief program net id /// \brief program net id
#define DOOMCOM_ID (INT32)0x12345678l #define DOOMCOM_ID (INT32)0x12345678l

View file

@ -36,109 +36,100 @@
#include <ws2tcpip.h> #include <ws2tcpip.h>
#endif #endif
#include "doomdef.h" #include "../doomdef.h"
#if defined (NOMD5) && !defined (NONET) #ifdef USE_WINSOCK1
//#define NONET #include <winsock.h>
#else
#ifndef USE_WINSOCK
#include <arpa/inet.h>
#ifdef __APPLE_CC__
#ifndef _BSD_SOCKLEN_T_
#define _BSD_SOCKLEN_T_
#endif //_BSD_SOCKLEN_T_
#endif //__APPLE_CC__
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <sys/ioctl.h>
#endif //normal BSD API
#include <errno.h>
#include <time.h>
#if defined (__unix__) || defined (__APPLE__) || defined (UNIXCOMMON)
#include <sys/time.h>
#endif // UNIXCOMMON
#endif #endif
#ifdef NONET #ifdef USE_WINSOCK
#undef HAVE_MINIUPNPC // some undefined under win32
#else #undef errno
#ifdef USE_WINSOCK1 //#define errno WSAGetLastError() //Alam_GBC: this is the correct way, right?
#include <winsock.h> #define errno h_errno // some very strange things happen when not using h_error?!?
#else #ifdef EWOULDBLOCK
#ifndef USE_WINSOCK #undef EWOULDBLOCK
#include <arpa/inet.h>
#ifdef __APPLE_CC__
#ifndef _BSD_SOCKLEN_T_
#define _BSD_SOCKLEN_T_
#endif //_BSD_SOCKLEN_T_
#endif //__APPLE_CC__
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <sys/ioctl.h>
#endif //normal BSD API
#include <errno.h>
#include <time.h>
#if defined (__unix__) || defined (__APPLE__) || defined (UNIXCOMMON)
#include <sys/time.h>
#endif // UNIXCOMMON
#endif #endif
#define EWOULDBLOCK WSAEWOULDBLOCK
#ifdef USE_WINSOCK #ifdef EMSGSIZE
// some undefined under win32 #undef EMSGSIZE
#undef errno
//#define errno WSAGetLastError() //Alam_GBC: this is the correct way, right?
#define errno h_errno // some very strange things happen when not using h_error?!?
#ifdef EWOULDBLOCK
#undef EWOULDBLOCK
#endif
#define EWOULDBLOCK WSAEWOULDBLOCK
#ifdef EMSGSIZE
#undef EMSGSIZE
#endif
#define EMSGSIZE WSAEMSGSIZE
#ifdef ECONNREFUSED
#undef ECONNREFUSED
#endif
#define ECONNREFUSED WSAECONNREFUSED
#ifdef ETIMEDOUT
#undef ETIMEDOUT
#endif
#define ETIMEDOUT WSAETIMEDOUT
#ifndef IOC_VENDOR
#define IOC_VENDOR 0x18000000
#endif
#ifndef _WSAIOW
#define _WSAIOW(x,y) (IOC_IN|(x)|(y))
#endif
#ifndef SIO_UDP_CONNRESET
#define SIO_UDP_CONNRESET _WSAIOW(IOC_VENDOR,12)
#endif
#ifndef AI_ADDRCONFIG
#define AI_ADDRCONFIG 0x00000400
#endif
#ifndef STATUS_INVALID_PARAMETER
#define STATUS_INVALID_PARAMETER 0xC000000D
#endif
#endif // USE_WINSOCK
typedef union
{
struct sockaddr any;
struct sockaddr_in ip4;
#ifdef HAVE_IPV6
struct sockaddr_in6 ip6;
#endif #endif
} mysockaddr_t; #define EMSGSIZE WSAEMSGSIZE
#ifdef ECONNREFUSED
#undef ECONNREFUSED
#endif
#define ECONNREFUSED WSAECONNREFUSED
#ifdef ETIMEDOUT
#undef ETIMEDOUT
#endif
#define ETIMEDOUT WSAETIMEDOUT
#ifndef IOC_VENDOR
#define IOC_VENDOR 0x18000000
#endif
#ifndef _WSAIOW
#define _WSAIOW(x,y) (IOC_IN|(x)|(y))
#endif
#ifndef SIO_UDP_CONNRESET
#define SIO_UDP_CONNRESET _WSAIOW(IOC_VENDOR,12)
#endif
#ifndef AI_ADDRCONFIG
#define AI_ADDRCONFIG 0x00000400
#endif
#ifndef STATUS_INVALID_PARAMETER
#define STATUS_INVALID_PARAMETER 0xC000000D
#endif
#endif // USE_WINSOCK
#ifdef HAVE_MINIUPNPC typedef union
#ifdef STATIC_MINIUPNPC {
#define STATICLIB struct sockaddr any;
#endif struct sockaddr_in ip4;
#include "miniupnpc/miniwget.h" #ifdef HAVE_IPV6
#include "miniupnpc/miniupnpc.h" struct sockaddr_in6 ip6;
#include "miniupnpc/upnpcommands.h" #endif
#undef STATICLIB } mysockaddr_t;
static UINT8 UPNP_support = TRUE;
#endif // HAVE_MINIUPNC
#endif // !NONET #ifdef HAVE_MINIUPNPC
#ifdef STATIC_MINIUPNPC
#define STATICLIB
#endif
#include "miniupnpc/miniwget.h"
#include "miniupnpc/miniupnpc.h"
#include "miniupnpc/upnpcommands.h"
#undef STATICLIB
static UINT8 UPNP_support = TRUE;
#endif // HAVE_MINIUPNC
#define MAXBANS 100 #define MAXBANS 100
#include "i_system.h" #include "../i_system.h"
#include "i_net.h" #include "i_net.h"
#include "d_net.h" #include "d_net.h"
#include "d_netfil.h" #include "d_netfil.h"
#include "i_tcp.h" #include "i_tcp.h"
#include "m_argv.h" #include "../m_argv.h"
#include "doomstat.h" #include "../doomstat.h"
// win32 // win32
#ifdef USE_WINSOCK #ifdef USE_WINSOCK
@ -151,7 +142,7 @@
#define SELECTTEST #define SELECTTEST
#define DEFAULTPORT "5029" #define DEFAULTPORT "5029"
#if defined (USE_WINSOCK) && !defined (NONET) #ifdef USE_WINSOCK
typedef SOCKET SOCKET_TYPE; typedef SOCKET SOCKET_TYPE;
#define ERRSOCKET (SOCKET_ERROR) #define ERRSOCKET (SOCKET_ERROR)
#else #else
@ -163,22 +154,20 @@
#define ERRSOCKET (-1) #define ERRSOCKET (-1)
#endif #endif
#ifndef NONET // define socklen_t in DOS/Windows if it is not already defined
// define socklen_t in DOS/Windows if it is not already defined #ifdef USE_WINSOCK1
#ifdef USE_WINSOCK1 typedef int socklen_t;
typedef int socklen_t;
#endif
static SOCKET_TYPE mysockets[MAXNETNODES+1] = {ERRSOCKET};
static size_t mysocketses = 0;
static int myfamily[MAXNETNODES+1] = {0};
static SOCKET_TYPE nodesocket[MAXNETNODES+1] = {ERRSOCKET};
static mysockaddr_t clientaddress[MAXNETNODES+1];
static mysockaddr_t broadcastaddress[MAXNETNODES+1];
static size_t broadcastaddresses = 0;
static boolean nodeconnected[MAXNETNODES+1];
static mysockaddr_t banned[MAXBANS];
static UINT8 bannedmask[MAXBANS];
#endif #endif
static SOCKET_TYPE mysockets[MAXNETNODES+1] = {ERRSOCKET};
static size_t mysocketses = 0;
static int myfamily[MAXNETNODES+1] = {0};
static SOCKET_TYPE nodesocket[MAXNETNODES+1] = {ERRSOCKET};
static mysockaddr_t clientaddress[MAXNETNODES+1];
static mysockaddr_t broadcastaddress[MAXNETNODES+1];
static size_t broadcastaddresses = 0;
static boolean nodeconnected[MAXNETNODES+1];
static mysockaddr_t banned[MAXBANS];
static UINT8 bannedmask[MAXBANS];
static size_t numbans = 0; static size_t numbans = 0;
static boolean SOCK_bannednode[MAXNETNODES+1]; /// \note do we really need the +1? static boolean SOCK_bannednode[MAXNETNODES+1]; /// \note do we really need the +1?
@ -187,7 +176,6 @@ static boolean init_tcp_driver = false;
static const char *serverport_name = DEFAULTPORT; static const char *serverport_name = DEFAULTPORT;
static const char *clientport_name;/* any port */ static const char *clientport_name;/* any port */
#ifndef NONET
#ifdef USE_WINSOCK #ifdef USE_WINSOCK
// stupid microsoft makes things complicated // stupid microsoft makes things complicated
static char *get_WSAErrorStr(int e) static char *get_WSAErrorStr(int e)
@ -387,47 +375,33 @@ static const char *SOCK_AddrToStr(mysockaddr_t *sk)
#endif #endif
return s; return s;
} }
#endif
static const char *SOCK_GetNodeAddress(INT32 node) static const char *SOCK_GetNodeAddress(INT32 node)
{ {
if (node == 0) if (node == 0)
return "self"; return "self";
#ifdef NONET
return NULL;
#else
if (!nodeconnected[node]) if (!nodeconnected[node])
return NULL; return NULL;
return SOCK_AddrToStr(&clientaddress[node]); return SOCK_AddrToStr(&clientaddress[node]);
#endif
} }
static const char *SOCK_GetBanAddress(size_t ban) static const char *SOCK_GetBanAddress(size_t ban)
{ {
if (ban >= numbans) if (ban >= numbans)
return NULL; return NULL;
#ifdef NONET
return NULL;
#else
return SOCK_AddrToStr(&banned[ban]); return SOCK_AddrToStr(&banned[ban]);
#endif
} }
static const char *SOCK_GetBanMask(size_t ban) static const char *SOCK_GetBanMask(size_t ban)
{ {
#ifdef NONET
(void)ban;
#else
static char s[16]; //255.255.255.255 netmask? no, just CDIR for only static char s[16]; //255.255.255.255 netmask? no, just CDIR for only
if (ban >= numbans) if (ban >= numbans)
return NULL; return NULL;
if (sprintf(s,"%d",bannedmask[ban]) > 0) if (sprintf(s,"%d",bannedmask[ban]) > 0)
return s; return s;
#endif
return NULL; return NULL;
} }
#ifndef NONET
static boolean SOCK_cmpaddr(mysockaddr_t *a, mysockaddr_t *b, UINT8 mask) static boolean SOCK_cmpaddr(mysockaddr_t *a, mysockaddr_t *b, UINT8 mask)
{ {
UINT32 bitmask = INADDR_NONE; UINT32 bitmask = INADDR_NONE;
@ -455,24 +429,20 @@ static boolean SOCK_cmpaddr(mysockaddr_t *a, mysockaddr_t *b, UINT8 mask)
*/ */
static void cleanupnodes(void) static void cleanupnodes(void)
{ {
SINT8 j;
if (!Playing()) if (!Playing())
return; return;
// Why can't I start at zero? // Why can't I start at zero?
for (j = 1; j < MAXNETNODES; j++) for (SINT8 j = 1; j < MAXNETNODES; j++)
if (!(nodeingame[j] || SendingFile(j))) if (!(netnodes[j].ingame || SendingFile(j)))
nodeconnected[j] = false; nodeconnected[j] = false;
} }
static SINT8 getfreenode(void) static SINT8 getfreenode(void)
{ {
SINT8 j;
cleanupnodes(); cleanupnodes();
for (j = 0; j < MAXNETNODES; j++) for (SINT8 j = 0; j < MAXNETNODES; j++)
if (!nodeconnected[j]) if (!nodeconnected[j])
{ {
nodeconnected[j] = true; nodeconnected[j] = true;
@ -485,8 +455,8 @@ static SINT8 getfreenode(void)
* downloading a needed wad, but it's better than not letting anyone join... * downloading a needed wad, but it's better than not letting anyone join...
*/ */
/*I_Error("No more free nodes!!1!11!11!!1111\n"); /*I_Error("No more free nodes!!1!11!11!!1111\n");
for (j = 1; j < MAXNETNODES; j++) for (SINT8 j = 1; j < MAXNETNODES; j++)
if (!nodeingame[j]) if (!netnodes[j].ingame)
return j;*/ return j;*/
return -1; return -1;
@ -497,28 +467,27 @@ void Command_Numnodes(void)
{ {
INT32 connected = 0; INT32 connected = 0;
INT32 ingame = 0; INT32 ingame = 0;
INT32 i;
for (i = 1; i < MAXNETNODES; i++) for (INT32 i = 1; i < MAXNETNODES; i++)
{ {
if (!(nodeconnected[i] || nodeingame[i])) if (!(nodeconnected[i] || netnodes[i].ingame))
continue; continue;
if (nodeconnected[i]) if (nodeconnected[i])
connected++; connected++;
if (nodeingame[i]) if (netnodes[i].ingame)
ingame++; ingame++;
CONS_Printf("%2d - ", i); CONS_Printf("%2d - ", i);
if (nodetoplayer[i] != -1) if (netnodes[i].player != -1)
CONS_Printf("player %.2d", nodetoplayer[i]); CONS_Printf("player %.2d", netnodes[i].player);
else else
CONS_Printf(" "); CONS_Printf(" ");
if (nodeconnected[i]) if (nodeconnected[i])
CONS_Printf(" - connected"); CONS_Printf(" - connected");
else else
CONS_Printf(" - "); CONS_Printf(" - ");
if (nodeingame[i]) if (netnodes[i].ingame)
CONS_Printf(" - ingame"); CONS_Printf(" - ingame");
else else
CONS_Printf(" - "); CONS_Printf(" - ");
@ -531,19 +500,17 @@ void Command_Numnodes(void)
connected, ingame); connected, ingame);
} }
#endif #endif
#endif
#ifndef NONET
// Returns true if a packet was received from a new node, false in all other cases // Returns true if a packet was received from a new node, false in all other cases
static boolean SOCK_Get(void) static boolean SOCK_Get(void)
{ {
size_t i, n; size_t i;
int j; int j;
ssize_t c; ssize_t c;
mysockaddr_t fromaddress; mysockaddr_t fromaddress;
socklen_t fromlen; socklen_t fromlen;
for (n = 0; n < mysocketses; n++) for (size_t n = 0; n < mysocketses; n++)
{ {
fromlen = (socklen_t)sizeof(fromaddress); fromlen = (socklen_t)sizeof(fromaddress);
c = recvfrom(mysockets[n], (char *)&doomcom->data, MAXPACKETLENGTH, 0, c = recvfrom(mysockets[n], (char *)&doomcom->data, MAXPACKETLENGTH, 0,
@ -596,20 +563,17 @@ static boolean SOCK_Get(void)
doomcom->remotenode = -1; // no packet doomcom->remotenode = -1; // no packet
return false; return false;
} }
#endif
// check if we can send (do not go over the buffer) // check if we can send (do not go over the buffer)
#ifndef NONET
static fd_set masterset; static fd_set masterset;
#ifdef SELECTTEST #ifdef SELECTTEST
static boolean FD_CPY(fd_set *src, fd_set *dst, SOCKET_TYPE *fd, size_t len) static boolean FD_CPY(fd_set *src, fd_set *dst, SOCKET_TYPE *fd, size_t len)
{ {
size_t i;
boolean testset = false; boolean testset = false;
FD_ZERO(dst); FD_ZERO(dst);
for (i = 0; i < len;i++) for (size_t i = 0; i < len;i++)
{ {
if(fd[i] != (SOCKET_TYPE)ERRSOCKET && if(fd[i] != (SOCKET_TYPE)ERRSOCKET &&
FD_ISSET(fd[i], src) && !FD_ISSET(fd[i], dst)) // no checking for dups FD_ISSET(fd[i], src) && !FD_ISSET(fd[i], dst)) // no checking for dups
@ -649,9 +613,7 @@ static boolean SOCK_CanGet(void)
return false; return false;
} }
#endif #endif
#endif
#ifndef NONET
static inline ssize_t SOCK_SendToAddr(SOCKET_TYPE socket, mysockaddr_t *sockaddr) static inline ssize_t SOCK_SendToAddr(SOCKET_TYPE socket, mysockaddr_t *sockaddr)
{ {
socklen_t d4 = (socklen_t)sizeof(struct sockaddr_in); socklen_t d4 = (socklen_t)sizeof(struct sockaddr_in);
@ -675,16 +637,15 @@ static inline ssize_t SOCK_SendToAddr(SOCKET_TYPE socket, mysockaddr_t *sockaddr
static void SOCK_Send(void) static void SOCK_Send(void)
{ {
ssize_t c = ERRSOCKET; ssize_t c = ERRSOCKET;
size_t i, j;
if (!nodeconnected[doomcom->remotenode]) if (!nodeconnected[doomcom->remotenode])
return; return;
if (doomcom->remotenode == BROADCASTADDR) if (doomcom->remotenode == BROADCASTADDR)
{ {
for (i = 0; i < mysocketses; i++) for (size_t i = 0; i < mysocketses; i++)
{ {
for (j = 0; j < broadcastaddresses; j++) for (size_t j = 0; j < broadcastaddresses; j++)
{ {
if (myfamily[i] == broadcastaddress[j].any.sa_family) if (myfamily[i] == broadcastaddress[j].any.sa_family)
SOCK_SendToAddr(mysockets[i], &broadcastaddress[j]); SOCK_SendToAddr(mysockets[i], &broadcastaddress[j]);
@ -694,7 +655,7 @@ static void SOCK_Send(void)
} }
else if (nodesocket[doomcom->remotenode] == (SOCKET_TYPE)ERRSOCKET) else if (nodesocket[doomcom->remotenode] == (SOCKET_TYPE)ERRSOCKET)
{ {
for (i = 0; i < mysocketses; i++) for (size_t i = 0; i < mysocketses; i++)
{ {
if (myfamily[i] == clientaddress[doomcom->remotenode].any.sa_family) if (myfamily[i] == clientaddress[doomcom->remotenode].any.sa_family)
SOCK_SendToAddr(mysockets[i], &clientaddress[doomcom->remotenode]); SOCK_SendToAddr(mysockets[i], &clientaddress[doomcom->remotenode]);
@ -714,9 +675,7 @@ static void SOCK_Send(void)
SOCK_GetNodeAddress(doomcom->remotenode), e, strerror(e)); SOCK_GetNodeAddress(doomcom->remotenode), e, strerror(e));
} }
} }
#endif
#ifndef NONET
static void SOCK_FreeNodenum(INT32 numnode) static void SOCK_FreeNodenum(INT32 numnode)
{ {
// can't disconnect from self :) // can't disconnect from self :)
@ -731,12 +690,10 @@ static void SOCK_FreeNodenum(INT32 numnode)
// put invalid address // put invalid address
memset(&clientaddress[numnode], 0, sizeof (clientaddress[numnode])); memset(&clientaddress[numnode], 0, sizeof (clientaddress[numnode]));
} }
#endif
// //
// UDPsocket // UDPsocket
// //
#ifndef NONET
// allocate a socket // allocate a socket
static SOCKET_TYPE UDP_Bind(int family, struct sockaddr *addr, socklen_t addrlen) static SOCKET_TYPE UDP_Bind(int family, struct sockaddr *addr, socklen_t addrlen)
@ -1061,12 +1018,10 @@ static boolean UDP_Socket(void)
return true; return true;
} }
#endif
boolean I_InitTcpDriver(void) boolean I_InitTcpDriver(void)
{ {
boolean tcp_was_up = init_tcp_driver; boolean tcp_was_up = init_tcp_driver;
#ifndef NONET
if (!init_tcp_driver) if (!init_tcp_driver)
{ {
#ifdef USE_WINSOCK #ifdef USE_WINSOCK
@ -1121,7 +1076,7 @@ boolean I_InitTcpDriver(void)
#endif #endif
init_tcp_driver = true; init_tcp_driver = true;
} }
#endif
if (!tcp_was_up && init_tcp_driver) if (!tcp_was_up && init_tcp_driver)
{ {
I_AddExitFunc(I_ShutdownTcpDriver); I_AddExitFunc(I_ShutdownTcpDriver);
@ -1135,11 +1090,9 @@ boolean I_InitTcpDriver(void)
return init_tcp_driver; return init_tcp_driver;
} }
#ifndef NONET
static void SOCK_CloseSocket(void) static void SOCK_CloseSocket(void)
{ {
size_t i; for (size_t i=0; i < MAXNETNODES+1; i++)
for (i=0; i < MAXNETNODES+1; i++)
{ {
if (mysockets[i] != (SOCKET_TYPE)ERRSOCKET if (mysockets[i] != (SOCKET_TYPE)ERRSOCKET
&& FD_ISSET(mysockets[i], &masterset)) && FD_ISSET(mysockets[i], &masterset))
@ -1150,11 +1103,9 @@ static void SOCK_CloseSocket(void)
mysockets[i] = ERRSOCKET; mysockets[i] = ERRSOCKET;
} }
} }
#endif
void I_ShutdownTcpDriver(void) void I_ShutdownTcpDriver(void)
{ {
#ifndef NONET
SOCK_CloseSocket(); SOCK_CloseSocket();
CONS_Printf("I_ShutdownTcpDriver: "); CONS_Printf("I_ShutdownTcpDriver: ");
@ -1164,10 +1115,8 @@ void I_ShutdownTcpDriver(void)
#endif #endif
CONS_Printf("shut down\n"); CONS_Printf("shut down\n");
init_tcp_driver = false; init_tcp_driver = false;
#endif
} }
#ifndef NONET
static SINT8 SOCK_NetMakeNodewPort(const char *address, const char *port) static SINT8 SOCK_NetMakeNodewPort(const char *address, const char *port)
{ {
SINT8 newnode = -1; SINT8 newnode = -1;
@ -1223,17 +1172,13 @@ static SINT8 SOCK_NetMakeNodewPort(const char *address, const char *port)
I_freeaddrinfo(ai); I_freeaddrinfo(ai);
return newnode; return newnode;
} }
#endif
static boolean SOCK_OpenSocket(void) static boolean SOCK_OpenSocket(void)
{ {
#ifndef NONET
size_t i;
memset(clientaddress, 0, sizeof (clientaddress)); memset(clientaddress, 0, sizeof (clientaddress));
nodeconnected[0] = true; // always connected to self nodeconnected[0] = true; // always connected to self
for (i = 1; i < MAXNETNODES; i++) for (size_t i = 1; i < MAXNETNODES; i++)
nodeconnected[i] = false; nodeconnected[i] = false;
nodeconnected[BROADCASTADDR] = true; nodeconnected[BROADCASTADDR] = true;
I_NetSend = SOCK_Send; I_NetSend = SOCK_Send;
@ -1251,18 +1196,12 @@ static boolean SOCK_OpenSocket(void)
// build the socket but close it first // build the socket but close it first
SOCK_CloseSocket(); SOCK_CloseSocket();
return UDP_Socket(); return UDP_Socket();
#else
return false;
#endif
} }
static boolean SOCK_Ban(INT32 node) static boolean SOCK_Ban(INT32 node)
{ {
if (node > MAXNETNODES) if (node > MAXNETNODES)
return false; return false;
#ifdef NONET
return false;
#else
if (numbans == MAXBANS) if (numbans == MAXBANS)
return false; return false;
@ -1281,16 +1220,10 @@ static boolean SOCK_Ban(INT32 node)
#endif #endif
numbans++; numbans++;
return true; return true;
#endif
} }
static boolean SOCK_SetBanAddress(const char *address, const char *mask) static boolean SOCK_SetBanAddress(const char *address, const char *mask)
{ {
#ifdef NONET
(void)address;
(void)mask;
return false;
#else
struct my_addrinfo *ai, *runp, hints; struct my_addrinfo *ai, *runp, hints;
int gaie; int gaie;
@ -1335,7 +1268,6 @@ static boolean SOCK_SetBanAddress(const char *address, const char *mask)
I_freeaddrinfo(ai); I_freeaddrinfo(ai);
return true; return true;
#endif
} }
static void SOCK_ClearBans(void) static void SOCK_ClearBans(void)

View file

@ -15,13 +15,14 @@
#include <time.h> #include <time.h>
#endif #endif
#include "doomstat.h" #include "../doomstat.h"
#include "doomdef.h" #include "../doomdef.h"
#include "command.h" #include "../command.h"
#include "i_threads.h" #include "../i_threads.h"
#include "mserv.h" #include "mserv.h"
#include "m_menu.h" #include "client_connection.h"
#include "z_zone.h" #include "../m_menu.h"
#include "../z_zone.h"
#ifdef MASTERSERVER #ifdef MASTERSERVER
@ -45,9 +46,7 @@ static I_cond MSCond;
# define Unlock_state() # define Unlock_state()
#endif/*HAVE_THREADS*/ #endif/*HAVE_THREADS*/
#ifndef NONET
static void Command_Listserv_f(void); static void Command_Listserv_f(void);
#endif
#endif/*MASTERSERVER*/ #endif/*MASTERSERVER*/
@ -89,7 +88,6 @@ msg_rooms_t room_list[NUM_LIST_ROOMS+1]; // +1 for easy test
*/ */
void AddMServCommands(void) void AddMServCommands(void)
{ {
#ifndef NONET
CV_RegisterVar(&cv_masterserver); CV_RegisterVar(&cv_masterserver);
CV_RegisterVar(&cv_masterserver_update_rate); CV_RegisterVar(&cv_masterserver_update_rate);
CV_RegisterVar(&cv_masterserver_timeout); CV_RegisterVar(&cv_masterserver_timeout);
@ -100,7 +98,6 @@ void AddMServCommands(void)
COM_AddCommand("listserv", Command_Listserv_f, 0); COM_AddCommand("listserv", Command_Listserv_f, 0);
COM_AddCommand("masterserver_update", Update_parameters, COM_LUA); // allows people to updates manually in case you were delisted by accident COM_AddCommand("masterserver_update", Update_parameters, COM_LUA); // allows people to updates manually in case you were delisted by accident
#endif #endif
#endif
} }
#ifdef MASTERSERVER #ifdef MASTERSERVER
@ -189,7 +186,6 @@ void GetMODVersion_Console(void)
} }
#endif #endif
#ifndef NONET
/** Gets a list of game servers. Called from console. /** Gets a list of game servers. Called from console.
*/ */
static void Command_Listserv_f(void) static void Command_Listserv_f(void)
@ -200,7 +196,6 @@ static void Command_Listserv_f(void)
HMS_list_servers(); HMS_list_servers();
} }
} }
#endif
static void static void
Finish_registration (void) Finish_registration (void)

View file

@ -14,7 +14,7 @@
#ifndef _MSERV_H_ #ifndef _MSERV_H_
#define _MSERV_H_ #define _MSERV_H_
#include "i_threads.h" #include "../i_threads.h"
// lowered from 32 due to menu changes // lowered from 32 due to menu changes
#define NUM_LIST_ROOMS 16 #define NUM_LIST_ROOMS 16

382
src/netcode/net_command.c Normal file
View file

@ -0,0 +1,382 @@
// SONIC ROBO BLAST 2
//-----------------------------------------------------------------------------
// Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2022 by Sonic Team Junior.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
// See the 'LICENSE' file for more details.
//-----------------------------------------------------------------------------
/// \file net_command.c
/// \brief Net command handling
#include "net_command.h"
#include "tic_command.h"
#include "gamestate.h"
#include "server_connection.h"
#include "d_clisrv.h"
#include "i_net.h"
#include "../byteptr.h"
#include "../g_game.h"
#include "../z_zone.h"
#include "../doomtype.h"
textcmdtic_t *textcmds[TEXTCMD_HASH_SIZE] = {NULL};
UINT8 localtextcmd[MAXTEXTCMD];
UINT8 localtextcmd2[MAXTEXTCMD]; // splitscreen
static void (*listnetxcmd[MAXNETXCMD])(UINT8 **p, INT32 playernum);
void RegisterNetXCmd(netxcmd_t id, void (*cmd_f)(UINT8 **p, INT32 playernum))
{
#ifdef PARANOIA
if (id >= MAXNETXCMD)
I_Error("Command id %d too big", id);
if (listnetxcmd[id] != 0)
I_Error("Command id %d already used", id);
#endif
listnetxcmd[id] = cmd_f;
}
void SendNetXCmd(netxcmd_t id, const void *param, size_t nparam)
{
if (localtextcmd[0]+2+nparam > MAXTEXTCMD)
{
// for future reference: if (cv_debug) != debug disabled.
CONS_Alert(CONS_ERROR, M_GetText("NetXCmd buffer full, cannot add netcmd %d! (size: %d, needed: %s)\n"), id, localtextcmd[0], sizeu1(nparam));
return;
}
localtextcmd[0]++;
localtextcmd[localtextcmd[0]] = (UINT8)id;
if (param && nparam)
{
M_Memcpy(&localtextcmd[localtextcmd[0]+1], param, nparam);
localtextcmd[0] = (UINT8)(localtextcmd[0] + (UINT8)nparam);
}
}
// splitscreen player
void SendNetXCmd2(netxcmd_t id, const void *param, size_t nparam)
{
if (localtextcmd2[0]+2+nparam > MAXTEXTCMD)
{
I_Error("No more place in the buffer for netcmd %d\n",id);
return;
}
localtextcmd2[0]++;
localtextcmd2[localtextcmd2[0]] = (UINT8)id;
if (param && nparam)
{
M_Memcpy(&localtextcmd2[localtextcmd2[0]+1], param, nparam);
localtextcmd2[0] = (UINT8)(localtextcmd2[0] + (UINT8)nparam);
}
}
UINT8 GetFreeXCmdSize(void)
{
// -1 for the size and another -1 for the ID.
return (UINT8)(localtextcmd[0] - 2);
}
// Frees all textcmd memory for the specified tic
void D_FreeTextcmd(tic_t tic)
{
textcmdtic_t **tctprev = &textcmds[tic & (TEXTCMD_HASH_SIZE - 1)];
textcmdtic_t *textcmdtic = *tctprev;
while (textcmdtic && textcmdtic->tic != tic)
{
tctprev = &textcmdtic->next;
textcmdtic = textcmdtic->next;
}
if (textcmdtic)
{
// Remove this tic from the list.
*tctprev = textcmdtic->next;
// Free all players.
for (INT32 i = 0; i < TEXTCMD_HASH_SIZE; i++)
{
textcmdplayer_t *textcmdplayer = textcmdtic->playercmds[i];
while (textcmdplayer)
{
textcmdplayer_t *tcpnext = textcmdplayer->next;
Z_Free(textcmdplayer);
textcmdplayer = tcpnext;
}
}
// Free this tic's own memory.
Z_Free(textcmdtic);
}
}
// Gets the buffer for the specified ticcmd, or NULL if there isn't one
UINT8* D_GetExistingTextcmd(tic_t tic, INT32 playernum)
{
textcmdtic_t *textcmdtic = textcmds[tic & (TEXTCMD_HASH_SIZE - 1)];
while (textcmdtic && textcmdtic->tic != tic) textcmdtic = textcmdtic->next;
// Do we have an entry for the tic? If so, look for player.
if (textcmdtic)
{
textcmdplayer_t *textcmdplayer = textcmdtic->playercmds[playernum & (TEXTCMD_HASH_SIZE - 1)];
while (textcmdplayer && textcmdplayer->playernum != playernum) textcmdplayer = textcmdplayer->next;
if (textcmdplayer) return textcmdplayer->cmd;
}
return NULL;
}
// Gets the buffer for the specified ticcmd, creating one if necessary
UINT8* D_GetTextcmd(tic_t tic, INT32 playernum)
{
textcmdtic_t *textcmdtic = textcmds[tic & (TEXTCMD_HASH_SIZE - 1)];
textcmdtic_t **tctprev = &textcmds[tic & (TEXTCMD_HASH_SIZE - 1)];
textcmdplayer_t *textcmdplayer, **tcpprev;
// Look for the tic.
while (textcmdtic && textcmdtic->tic != tic)
{
tctprev = &textcmdtic->next;
textcmdtic = textcmdtic->next;
}
// If we don't have an entry for the tic, make it.
if (!textcmdtic)
{
textcmdtic = *tctprev = Z_Calloc(sizeof (textcmdtic_t), PU_STATIC, NULL);
textcmdtic->tic = tic;
}
tcpprev = &textcmdtic->playercmds[playernum & (TEXTCMD_HASH_SIZE - 1)];
textcmdplayer = *tcpprev;
// Look for the player.
while (textcmdplayer && textcmdplayer->playernum != playernum)
{
tcpprev = &textcmdplayer->next;
textcmdplayer = textcmdplayer->next;
}
// If we don't have an entry for the player, make it.
if (!textcmdplayer)
{
textcmdplayer = *tcpprev = Z_Calloc(sizeof (textcmdplayer_t), PU_STATIC, NULL);
textcmdplayer->playernum = playernum;
}
return textcmdplayer->cmd;
}
void ExtraDataTicker(void)
{
for (INT32 i = 0; i < MAXPLAYERS; i++)
if (playeringame[i] || i == 0)
{
UINT8 *bufferstart = D_GetExistingTextcmd(gametic, i);
if (bufferstart)
{
UINT8 *curpos = bufferstart;
UINT8 *bufferend = &curpos[curpos[0]+1];
curpos++;
while (curpos < bufferend)
{
if (*curpos < MAXNETXCMD && listnetxcmd[*curpos])
{
const UINT8 id = *curpos;
curpos++;
DEBFILE(va("executing x_cmd %s ply %u ", netxcmdnames[id - 1], i));
(listnetxcmd[id])(&curpos, i);
DEBFILE("done\n");
}
else
{
if (server)
{
SendKick(i, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY);
DEBFILE(va("player %d kicked [gametic=%u] reason as follows:\n", i, gametic));
}
CONS_Alert(CONS_WARNING, M_GetText("Got unknown net command [%s]=%d (max %d)\n"), sizeu1(curpos - bufferstart), *curpos, bufferstart[0]);
break;
}
}
}
}
// If you are a client, you can safely forget the net commands for this tic
// If you are the server, you need to remember them until every client has been acknowledged,
// because if you need to resend a PT_SERVERTICS packet, you will need to put the commands in it
if (client)
D_FreeTextcmd(gametic);
}
// used at txtcmds received to check packetsize bound
size_t TotalTextCmdPerTic(tic_t tic)
{
size_t total = 1; // num of textcmds in the tic (ntextcmd byte)
for (INT32 i = 0; i < MAXPLAYERS; i++)
{
UINT8 *textcmd = D_GetExistingTextcmd(tic, i);
if ((!i || playeringame[i]) && textcmd)
total += 2 + textcmd[0]; // "+2" for size and playernum
}
return total;
}
void PT_TextCmd(SINT8 node, INT32 netconsole)
{
if (client)
return;
// splitscreen special
if (netbuffer->packettype == PT_TEXTCMD2)
netconsole = netnodes[node].player2;
if (netconsole < 0 || netconsole >= MAXPLAYERS)
Net_UnAcknowledgePacket(node);
else
{
size_t j;
tic_t tic = maketic;
UINT8 *textcmd;
// ignore if the textcmd has a reported size of zero
// this shouldn't be sent at all
if (!netbuffer->u.textcmd[0])
{
DEBFILE(va("GetPacket: Textcmd with size 0 detected! (node %u, player %d)\n",
node, netconsole));
Net_UnAcknowledgePacket(node);
return;
}
// ignore if the textcmd size var is actually larger than it should be
// BASEPACKETSIZE + 1 (for size) + textcmd[0] should == datalength
if (netbuffer->u.textcmd[0] > (size_t)doomcom->datalength-BASEPACKETSIZE-1)
{
DEBFILE(va("GetPacket: Bad Textcmd packet size! (expected %d, actual %s, node %u, player %d)\n",
netbuffer->u.textcmd[0], sizeu1((size_t)doomcom->datalength-BASEPACKETSIZE-1),
node, netconsole));
Net_UnAcknowledgePacket(node);
return;
}
// check if tic that we are making isn't too large else we cannot send it :(
// doomcom->numslots+1 "+1" since doomcom->numslots can change within this time and sent time
j = software_MAXPACKETLENGTH
- (netbuffer->u.textcmd[0]+2+BASESERVERTICSSIZE
+ (doomcom->numslots+1)*sizeof(ticcmd_t));
// search a tic that have enougth space in the ticcmd
while ((textcmd = D_GetExistingTextcmd(tic, netconsole)),
(TotalTextCmdPerTic(tic) > j || netbuffer->u.textcmd[0] + (textcmd ? textcmd[0] : 0) > MAXTEXTCMD)
&& tic < firstticstosend + BACKUPTICS)
tic++;
if (tic >= firstticstosend + BACKUPTICS)
{
DEBFILE(va("GetPacket: Textcmd too long (max %s, used %s, mak %d, "
"tosend %u, node %u, player %d)\n", sizeu1(j), sizeu2(TotalTextCmdPerTic(maketic)),
maketic, firstticstosend, node, netconsole));
Net_UnAcknowledgePacket(node);
return;
}
// Make sure we have a buffer
if (!textcmd) textcmd = D_GetTextcmd(tic, netconsole);
DEBFILE(va("textcmd put in tic %u at position %d (player %d) ftts %u mk %u\n",
tic, textcmd[0]+1, netconsole, firstticstosend, maketic));
M_Memcpy(&textcmd[textcmd[0]+1], netbuffer->u.textcmd+1, netbuffer->u.textcmd[0]);
textcmd[0] += (UINT8)netbuffer->u.textcmd[0];
}
}
void SV_WriteNetCommandsForTic(tic_t tic, UINT8 **buf)
{
UINT8 *numcmds;
numcmds = (*buf)++;
*numcmds = 0;
for (INT32 i = 0; i < MAXPLAYERS; i++)
{
UINT8 *cmd = D_GetExistingTextcmd(tic, i);
INT32 size = cmd ? cmd[0] : 0;
if ((!i || playeringame[i]) && size)
{
(*numcmds)++;
WRITEUINT8(*buf, i);
M_Memcpy(*buf, cmd, size + 1);
*buf += size + 1;
}
}
}
void CL_CopyNetCommandsFromServerPacket(tic_t tic, UINT8 **buf)
{
UINT8 numcmds = *(*buf)++;
for (UINT32 i = 0; i < numcmds; i++)
{
INT32 playernum = *(*buf)++; // playernum
size_t size = (*buf)[0]+1;
if (tic >= gametic) // Don't copy old net commands
M_Memcpy(D_GetTextcmd(tic, playernum), *buf, size);
*buf += size;
}
}
void CL_SendNetCommands(void)
{
// Send extra data if needed
if (localtextcmd[0])
{
netbuffer->packettype = PT_TEXTCMD;
M_Memcpy(netbuffer->u.textcmd,localtextcmd, localtextcmd[0]+1);
// All extra data have been sent
if (HSendPacket(servernode, true, 0, localtextcmd[0]+1)) // Send can fail...
localtextcmd[0] = 0;
}
// Send extra data if needed for player 2 (splitscreen)
if (localtextcmd2[0])
{
netbuffer->packettype = PT_TEXTCMD2;
M_Memcpy(netbuffer->u.textcmd, localtextcmd2, localtextcmd2[0]+1);
// All extra data have been sent
if (HSendPacket(servernode, true, 0, localtextcmd2[0]+1)) // Send can fail...
localtextcmd2[0] = 0;
}
}
void SendKick(UINT8 playernum, UINT8 msg)
{
UINT8 buf[2];
if (!(server && cv_rejointimeout.value))
msg &= ~KICK_MSG_KEEP_BODY;
buf[0] = playernum;
buf[1] = msg;
SendNetXCmd(XD_KICK, &buf, 2);
}
void SendKicksForNode(SINT8 node, UINT8 msg)
{
if (!netnodes[node].ingame)
return;
for (INT32 playernum = netnodes[node].player; playernum != -1; playernum = netnodes[node].player2)
if (playernum != -1 && playeringame[playernum])
SendKick(playernum, msg);
}

66
src/netcode/net_command.h Normal file
View file

@ -0,0 +1,66 @@
// SONIC ROBO BLAST 2
//-----------------------------------------------------------------------------
// Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2022 by Sonic Team Junior.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
// See the 'LICENSE' file for more details.
//-----------------------------------------------------------------------------
/// \file net_command.h
/// \brief Net command handling
#ifndef __D_NET_COMMAND__
#define __D_NET_COMMAND__
#include "d_clisrv.h"
#include "../doomtype.h"
// Must be a power of two
#define TEXTCMD_HASH_SIZE 4
typedef struct textcmdplayer_s
{
INT32 playernum;
UINT8 cmd[MAXTEXTCMD];
struct textcmdplayer_s *next;
} textcmdplayer_t;
typedef struct textcmdtic_s
{
tic_t tic;
textcmdplayer_t *playercmds[TEXTCMD_HASH_SIZE];
struct textcmdtic_s *next;
} textcmdtic_t;
extern textcmdtic_t *textcmds[TEXTCMD_HASH_SIZE];
extern UINT8 localtextcmd[MAXTEXTCMD];
extern UINT8 localtextcmd2[MAXTEXTCMD]; // splitscreen
void RegisterNetXCmd(netxcmd_t id, void (*cmd_f)(UINT8 **p, INT32 playernum));
void SendNetXCmd(netxcmd_t id, const void *param, size_t nparam);
void SendNetXCmd2(netxcmd_t id, const void *param, size_t nparam); // splitsreen player
UINT8 GetFreeXCmdSize(void);
void D_FreeTextcmd(tic_t tic);
// Gets the buffer for the specified ticcmd, or NULL if there isn't one
UINT8* D_GetExistingTextcmd(tic_t tic, INT32 playernum);
// Gets the buffer for the specified ticcmd, creating one if necessary
UINT8* D_GetTextcmd(tic_t tic, INT32 playernum);
void ExtraDataTicker(void);
// used at txtcmds received to check packetsize bound
size_t TotalTextCmdPerTic(tic_t tic);
void PT_TextCmd(SINT8 node, INT32 netconsole);
void SV_WriteNetCommandsForTic(tic_t tic, UINT8 **buf);
void CL_CopyNetCommandsFromServerPacket(tic_t tic, UINT8 **buf);
void CL_SendNetCommands(void);
void SendKick(UINT8 playernum, UINT8 msg);
void SendKicksForNode(SINT8 node, UINT8 msg);
#endif

View file

@ -7,19 +7,15 @@
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.
// See the 'LICENSE' file for more details. // See the 'LICENSE' file for more details.
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
/// \file d_clisrv.h /// \file protocol.h
/// \brief high level networking stuff /// \brief Data exchanged through the network
#ifndef __D_CLISRV__ #ifndef __PROTOCOL__
#define __D_CLISRV__ #define __PROTOCOL__
#include "d_ticcmd.h"
#include "d_net.h" #include "d_net.h"
#include "d_netcmd.h" #include "../d_ticcmd.h"
#include "d_net.h" #include "../doomdef.h"
#include "tables.h"
#include "d_player.h"
#include "mserv.h"
/* /*
The 'packet version' is used to distinguish packet The 'packet version' is used to distinguish packet
@ -38,10 +34,9 @@ therein, increment this number.
// one that defines the actual packets to // one that defines the actual packets to
// be transmitted. // be transmitted.
// Networking and tick handling related.
#define BACKUPTICS 1024 #define BACKUPTICS 1024
#define CLIENTBACKUPTICS 32
#define MAXTEXTCMD 256 #define MAXTEXTCMD 256
// //
// Packet structure // Packet structure
// //
@ -77,7 +72,7 @@ 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 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.
@ -92,7 +87,6 @@ typedef enum
PT_TEXTCMD, // Extra text commands from the client. PT_TEXTCMD, // Extra text commands from the client.
PT_TEXTCMD2, // Splitscreen text commands. PT_TEXTCMD2, // Splitscreen text commands.
PT_CLIENTJOIN, // Client wants to join; used in start game. PT_CLIENTJOIN, // Client wants to join; used in start game.
PT_NODETIMEOUT, // Packet sent to self if the connection times out.
PT_LOGIN, // Login attempt from the client. PT_LOGIN, // Login attempt from the client.
@ -103,14 +97,6 @@ typedef enum
NUMPACKETTYPE NUMPACKETTYPE
} packettype_t; } packettype_t;
#ifdef PACKETDROP
void Command_Drop(void);
void Command_Droprate(void);
#endif
#ifdef _DEBUG
void Command_Numnodes(void);
#endif
#if defined(_MSC_VER) #if defined(_MSC_VER)
#pragma pack(1) #pragma pack(1)
#endif #endif
@ -139,13 +125,12 @@ typedef struct
#endif #endif
// Server to client packet // Server to client packet
// this packet is too large
typedef struct typedef struct
{ {
tic_t starttic; tic_t starttic;
UINT8 numtics; UINT8 numtics;
UINT8 numslots; // "Slots filled": Highest player number in use plus one. UINT8 numslots; // "Slots filled": Highest player number in use plus one.
ticcmd_t cmds[45]; // Normally [BACKUPTIC][MAXPLAYERS] but too large ticcmd_t cmds[45];
} ATTRPACK servertics_pak; } ATTRPACK servertics_pak;
typedef struct typedef struct
@ -215,6 +200,7 @@ enum {
#define MAXSERVERNAME 32 #define MAXSERVERNAME 32
#define MAXFILENEEDED 915 #define MAXFILENEEDED 915
// This packet is too large // This packet is too large
typedef struct typedef struct
{ {
@ -275,7 +261,7 @@ typedef struct
UINT8 data; // Color is first four bits, hasflag, isit and issuper have one bit each, the last is unused. UINT8 data; // Color is first four bits, hasflag, isit and issuper have one bit each, the last is unused.
UINT32 score; UINT32 score;
UINT16 timeinserver; // In seconds. UINT16 timeinserver; // In seconds.
} ATTRPACK plrinfo; } ATTRPACK plrinfo_pak;
// Shortest player information for join during intermission. // Shortest player information for join during intermission.
typedef struct typedef struct
@ -286,7 +272,7 @@ typedef struct
UINT32 pflags; UINT32 pflags;
UINT32 score; UINT32 score;
UINT8 ctfteam; UINT8 ctfteam;
} ATTRPACK plrconfig; } ATTRPACK plrconfig_pak;
typedef struct typedef struct
{ {
@ -309,25 +295,25 @@ typedef struct
UINT8 reserved; // Padding UINT8 reserved; // Padding
union union
{ {
clientcmd_pak clientpak; // 144 bytes clientcmd_pak clientpak;
client2cmd_pak client2pak; // 200 bytes client2cmd_pak client2pak;
servertics_pak serverpak; // 132495 bytes (more around 360, no?) servertics_pak serverpak;
serverconfig_pak servercfg; // 773 bytes serverconfig_pak servercfg;
UINT8 textcmd[MAXTEXTCMD+1]; // 66049 bytes (wut??? 64k??? More like 257 bytes...) UINT8 textcmd[MAXTEXTCMD+1];
filetx_pak filetxpak; // 139 bytes filetx_pak filetxpak;
fileack_pak fileack; fileack_pak fileack;
UINT8 filereceived; UINT8 filereceived;
clientconfig_pak clientcfg; // 136 bytes clientconfig_pak clientcfg;
UINT8 md5sum[16]; UINT8 md5sum[16];
serverinfo_pak serverinfo; // 1024 bytes serverinfo_pak serverinfo;
serverrefuse_pak serverrefuse; // 65025 bytes (somehow I feel like those values are garbage...) serverrefuse_pak serverrefuse;
askinfo_pak askinfo; // 61 bytes askinfo_pak askinfo;
msaskinfo_pak msaskinfo; // 22 bytes msaskinfo_pak msaskinfo;
plrinfo playerinfo[MAXPLAYERS]; // 576 bytes(?) plrinfo_pak playerinfo[MAXPLAYERS];
plrconfig playerconfig[MAXPLAYERS]; // (up to) 528 bytes(?) plrconfig_pak playerconfig[MAXPLAYERS];
INT32 filesneedednum; // 4 bytes INT32 filesneedednum;
filesneededconfig_pak filesneededcfg; // ??? bytes filesneededconfig_pak filesneededcfg;
UINT32 pingtable[MAXPLAYERS+1]; // 68 bytes UINT32 pingtable[MAXPLAYERS+1];
} u; // This is needed to pack diff packet types data together } u; // This is needed to pack diff packet types data together
} ATTRPACK doomdata_t; } ATTRPACK doomdata_t;
@ -335,26 +321,7 @@ typedef struct
#pragma pack() #pragma pack()
#endif #endif
#define MAXSERVERLIST (MAXNETNODES-1)
typedef struct
{
SINT8 node;
serverinfo_pak info;
} serverelem_t;
extern serverelem_t serverlist[MAXSERVERLIST];
extern UINT32 serverlistcount;
extern INT32 mapchangepending;
// Points inside doomcom
extern doomdata_t *netbuffer;
extern consvar_t cv_showjoinaddress;
extern consvar_t cv_playbackspeed;
#define BASEPACKETSIZE offsetof(doomdata_t, u)
#define FILETXHEADER offsetof(filetx_pak, data) #define FILETXHEADER offsetof(filetx_pak, data)
#define BASESERVERTICSSIZE offsetof(doomdata_t, u.serverpak.cmds[0])
#define KICK_MSG_GO_AWAY 1 #define KICK_MSG_GO_AWAY 1
#define KICK_MSG_CON_FAIL 2 #define KICK_MSG_CON_FAIL 2
@ -366,107 +333,4 @@ extern consvar_t cv_playbackspeed;
#define KICK_MSG_CUSTOM_BAN 8 #define KICK_MSG_CUSTOM_BAN 8
#define KICK_MSG_KEEP_BODY 0x80 #define KICK_MSG_KEEP_BODY 0x80
typedef enum
{
KR_KICK = 1, //Kicked by server
KR_PINGLIMIT = 2, //Broke Ping Limit
KR_SYNCH = 3, //Synch Failure
KR_TIMEOUT = 4, //Connection Timeout
KR_BAN = 5, //Banned by server
KR_LEAVE = 6, //Quit the game
} kickreason_t;
/* the max number of name changes in some time period */
#define MAXNAMECHANGES (5)
#define NAMECHANGERATE (60*TICRATE)
extern boolean server;
extern boolean serverrunning;
#define client (!server)
extern boolean dedicated; // For dedicated server
extern UINT16 software_MAXPACKETLENGTH;
extern boolean acceptnewnode;
extern SINT8 servernode;
void Command_Ping_f(void);
extern tic_t connectiontimeout;
extern tic_t jointimeout;
extern UINT16 pingmeasurecount;
extern UINT32 realpingtable[MAXPLAYERS];
extern UINT32 playerpingtable[MAXPLAYERS];
extern tic_t servermaxping;
extern consvar_t cv_netticbuffer, cv_allownewplayer, cv_joinnextround, cv_maxplayers, cv_joindelay, cv_rejointimeout;
extern consvar_t cv_resynchattempts, cv_blamecfail;
extern consvar_t cv_maxsend, cv_noticedownload, cv_downloadspeed;
extern consvar_t cv_dedicatedidletime;
// Used in d_net, the only dependence
tic_t ExpandTics(INT32 low, INT32 node);
void D_ClientServerInit(void);
// Initialise the other field
void RegisterNetXCmd(netxcmd_t id, void (*cmd_f)(UINT8 **p, INT32 playernum));
void SendNetXCmd(netxcmd_t id, const void *param, size_t nparam);
void SendNetXCmd2(netxcmd_t id, const void *param, size_t nparam); // splitsreen player
void SendKick(UINT8 playernum, UINT8 msg);
// Create any new ticcmds and broadcast to other players.
void NetUpdate(void);
// Maintain connections to nodes without timing them all out.
void NetKeepAlive(void);
void SV_StartSinglePlayerServer(void);
boolean SV_SpawnServer(void);
void SV_StopServer(void);
void SV_ResetServer(void);
void CL_AddSplitscreenPlayer(void);
void CL_RemoveSplitscreenPlayer(void);
void CL_Reset(void);
void CL_ClearPlayer(INT32 playernum);
void CL_QueryServerList(msg_server_t *list);
void CL_UpdateServerList(boolean internetsearch, INT32 room);
void CL_RemovePlayer(INT32 playernum, kickreason_t reason);
// Is there a game running
boolean Playing(void);
// Broadcasts special packets to other players
// to notify of game exit
void D_QuitNetGame(void);
//? How many ticks to run?
boolean TryRunTics(tic_t realtic);
// extra data for lmps
// these functions scare me. they contain magic.
/*boolean AddLmpExtradata(UINT8 **demo_p, INT32 playernum);
void ReadLmpExtraData(UINT8 **demo_pointer, INT32 playernum);*/
#ifndef NONET
// translate a playername in a player number return -1 if not found and
// print a error message in the console
SINT8 nametonum(const char *name);
#endif
extern char motd[254], server_context[8];
extern UINT8 playernode[MAXPLAYERS];
INT32 D_NumPlayers(void);
INT32 D_NumBots(void);
void D_ResetTiccmds(void);
tic_t GetLag(INT32 node);
UINT8 GetFreeXCmdSize(void);
void D_MD5PasswordPass(const UINT8 *buffer, size_t len, const char *salt, void *dest);
extern UINT8 hu_redownloadinggamestate;
extern UINT8 adminpassmd5[16];
extern boolean adminpasswordset;
extern boolean hu_stopped;
#endif #endif

View file

@ -0,0 +1,507 @@
// 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 server_connection.c
/// \brief Server-side part of connection handling
#include "server_connection.h"
#include "i_net.h"
#include "d_clisrv.h"
#include "d_netfil.h"
#include "mserv.h"
#include "net_command.h"
#include "gamestate.h"
#include "../byteptr.h"
#include "../g_game.h"
#include "../g_state.h"
#include "../p_setup.h"
#include "../p_tick.h"
#include "../command.h"
#include "../doomstat.h"
// Minimum timeout for sending the savegame
// The actual timeout will be longer depending on the savegame length
tic_t jointimeout = (10*TICRATE);
// Incremented by cv_joindelay when a client joins, decremented each tic.
// If higher than cv_joindelay * 2 (3 joins in a short timespan), joins are temporarily disabled.
tic_t joindelay = 0;
// Minimum timeout for sending the savegame
// The actual timeout will be longer depending on the savegame length
char playeraddress[MAXPLAYERS][64];
consvar_t cv_showjoinaddress = CVAR_INIT ("showjoinaddress", "Off", CV_SAVE|CV_NETVAR, CV_OnOff, NULL);
consvar_t cv_allownewplayer = CVAR_INIT ("allowjoin", "On", CV_SAVE|CV_NETVAR|CV_ALLOWLUA, CV_OnOff, NULL);
static CV_PossibleValue_t maxplayers_cons_t[] = {{2, "MIN"}, {32, "MAX"}, {0, NULL}};
consvar_t cv_maxplayers = CVAR_INIT ("maxplayers", "8", CV_SAVE|CV_NETVAR|CV_ALLOWLUA, maxplayers_cons_t, NULL);
static CV_PossibleValue_t joindelay_cons_t[] = {{1, "MIN"}, {3600, "MAX"}, {0, "Off"}, {0, NULL}};
consvar_t cv_joindelay = CVAR_INIT ("joindelay", "10", CV_SAVE|CV_NETVAR, joindelay_cons_t, NULL);
static CV_PossibleValue_t rejointimeout_cons_t[] = {{1, "MIN"}, {60 * FRACUNIT, "MAX"}, {0, "Off"}, {0, NULL}};
consvar_t cv_rejointimeout = CVAR_INIT ("rejointimeout", "2", CV_SAVE|CV_NETVAR|CV_FLOAT, rejointimeout_cons_t, NULL);
static INT32 FindRejoinerNum(SINT8 node)
{
char addressbuffer[64];
const char *nodeaddress;
const char *strippednodeaddress;
// Make sure there is no dead dress before proceeding to the stripping
if (!I_GetNodeAddress)
return -1;
nodeaddress = I_GetNodeAddress(node);
if (!nodeaddress)
return -1;
// Strip the address of its port
strcpy(addressbuffer, nodeaddress);
strippednodeaddress = I_NetSplitAddress(addressbuffer, NULL);
// Check if any player matches the stripped address
for (INT32 i = 0; i < MAXPLAYERS; i++)
{
if (playeringame[i] && playeraddress[i][0] && playernode[i] == UINT8_MAX
&& !strcmp(playeraddress[i], strippednodeaddress))
return i;
}
return -1;
}
static UINT8
GetRefuseReason (INT32 node)
{
if (!node || FindRejoinerNum(node) != -1)
return 0;
else if (bannednode && bannednode[node])
return REFUSE_BANNED;
else if (!cv_allownewplayer.value)
return REFUSE_JOINS_DISABLED;
else if (D_NumPlayers() >= cv_maxplayers.value)
return REFUSE_SLOTS_FULL;
else
return 0;
}
static void SV_SendServerInfo(INT32 node, tic_t servertime)
{
UINT8 *p;
netbuffer->packettype = PT_SERVERINFO;
netbuffer->u.serverinfo._255 = 255;
netbuffer->u.serverinfo.packetversion = PACKETVERSION;
netbuffer->u.serverinfo.version = VERSION;
netbuffer->u.serverinfo.subversion = SUBVERSION;
strncpy(netbuffer->u.serverinfo.application, SRB2APPLICATION,
sizeof netbuffer->u.serverinfo.application);
// return back the time value so client can compute their ping
netbuffer->u.serverinfo.time = (tic_t)LONG(servertime);
netbuffer->u.serverinfo.leveltime = (tic_t)LONG(leveltime);
// Exclude bots from both counts
netbuffer->u.serverinfo.numberofplayer = (UINT8)(D_NumPlayers() - D_NumBots());
netbuffer->u.serverinfo.maxplayer = (UINT8)(cv_maxplayers.value - D_NumBots());
netbuffer->u.serverinfo.refusereason = GetRefuseReason(node);
strncpy(netbuffer->u.serverinfo.gametypename, Gametype_Names[gametype],
sizeof netbuffer->u.serverinfo.gametypename);
netbuffer->u.serverinfo.modifiedgame = (UINT8)modifiedgame;
netbuffer->u.serverinfo.cheatsenabled = CV_CheatsEnabled();
netbuffer->u.serverinfo.flags = (dedicated ? SV_DEDICATED : 0);
strncpy(netbuffer->u.serverinfo.servername, cv_servername.string,
MAXSERVERNAME);
strncpy(netbuffer->u.serverinfo.mapname, G_BuildMapName(gamemap), 7);
M_Memcpy(netbuffer->u.serverinfo.mapmd5, mapmd5, 16);
memset(netbuffer->u.serverinfo.maptitle, 0, sizeof netbuffer->u.serverinfo.maptitle);
if (mapheaderinfo[gamemap-1] && *mapheaderinfo[gamemap-1]->lvlttl)
{
char *read = mapheaderinfo[gamemap-1]->lvlttl, *writ = netbuffer->u.serverinfo.maptitle;
while (writ < (netbuffer->u.serverinfo.maptitle+32) && *read != '\0')
{
if (!(*read & 0x80))
{
*writ = toupper(*read);
writ++;
}
read++;
}
*writ = '\0';
//strncpy(netbuffer->u.serverinfo.maptitle, (char *)mapheaderinfo[gamemap-1]->lvlttl, 33);
}
else
strncpy(netbuffer->u.serverinfo.maptitle, "UNKNOWN", 32);
if (mapheaderinfo[gamemap-1] && !(mapheaderinfo[gamemap-1]->levelflags & LF_NOZONE))
netbuffer->u.serverinfo.iszone = 1;
else
netbuffer->u.serverinfo.iszone = 0;
if (mapheaderinfo[gamemap-1])
netbuffer->u.serverinfo.actnum = mapheaderinfo[gamemap-1]->actnum;
p = PutFileNeeded(0);
HSendPacket(node, false, 0, p - ((UINT8 *)&netbuffer->u));
}
static void SV_SendPlayerInfo(INT32 node)
{
netbuffer->packettype = PT_PLAYERINFO;
for (UINT8 i = 0; i < MAXPLAYERS; i++)
{
if (!playeringame[i])
{
netbuffer->u.playerinfo[i].num = 255; // This slot is empty.
continue;
}
netbuffer->u.playerinfo[i].num = i;
strncpy(netbuffer->u.playerinfo[i].name, (const char *)&player_names[i], MAXPLAYERNAME+1);
netbuffer->u.playerinfo[i].name[MAXPLAYERNAME] = '\0';
//fetch IP address
//No, don't do that, you fuckface.
memset(netbuffer->u.playerinfo[i].address, 0, 4);
if (G_GametypeHasTeams())
{
if (!players[i].ctfteam)
netbuffer->u.playerinfo[i].team = 255;
else
netbuffer->u.playerinfo[i].team = (UINT8)players[i].ctfteam;
}
else
{
if (players[i].spectator)
netbuffer->u.playerinfo[i].team = 255;
else
netbuffer->u.playerinfo[i].team = 0;
}
netbuffer->u.playerinfo[i].score = LONG(players[i].score);
netbuffer->u.playerinfo[i].timeinserver = SHORT((UINT16)(players[i].jointime / TICRATE));
netbuffer->u.playerinfo[i].skin = (UINT8)(players[i].skin
#ifdef DEVELOP // it's safe to do this only because PLAYERINFO isn't read by the game itself
% 3
#endif
);
// Extra data
netbuffer->u.playerinfo[i].data = 0; //players[i].skincolor;
if (players[i].pflags & PF_TAGIT)
netbuffer->u.playerinfo[i].data |= 0x20;
if (players[i].gotflag)
netbuffer->u.playerinfo[i].data |= 0x40;
if (players[i].powers[pw_super])
netbuffer->u.playerinfo[i].data |= 0x80;
}
HSendPacket(node, false, 0, sizeof(plrinfo_pak) * MAXPLAYERS);
}
/** Sends a PT_SERVERCFG packet
*
* \param node The destination
* \return True if the packet was successfully sent
*
*/
static boolean SV_SendServerConfig(INT32 node)
{
boolean waspacketsent;
netbuffer->packettype = PT_SERVERCFG;
netbuffer->u.servercfg.serverplayer = (UINT8)serverplayer;
netbuffer->u.servercfg.totalslotnum = (UINT8)(doomcom->numslots);
netbuffer->u.servercfg.gametic = (tic_t)LONG(gametic);
netbuffer->u.servercfg.clientnode = (UINT8)node;
netbuffer->u.servercfg.gamestate = (UINT8)gamestate;
netbuffer->u.servercfg.gametype = (UINT8)gametype;
netbuffer->u.servercfg.modifiedgame = (UINT8)modifiedgame;
netbuffer->u.servercfg.usedCheats = (UINT8)usedCheats;
memcpy(netbuffer->u.servercfg.server_context, server_context, 8);
{
const size_t len = sizeof (serverconfig_pak);
#ifdef DEBUGFILE
if (debugfile)
{
fprintf(debugfile, "ServerConfig Packet about to be sent, size of packet:%s to node:%d\n",
sizeu1(len), node);
}
#endif
waspacketsent = HSendPacket(node, true, 0, len);
}
#ifdef DEBUGFILE
if (debugfile)
{
if (waspacketsent)
{
fprintf(debugfile, "ServerConfig Packet was sent\n");
}
else
{
fprintf(debugfile, "ServerConfig Packet could not be sent right now\n");
}
}
#endif
return waspacketsent;
}
// Adds a node to the game (player will follow at map change or at savegame....)
static inline void SV_AddNode(INT32 node)
{
netnodes[node].tic = gametic;
netnodes[node].supposedtic = gametic;
// little hack because the server connects to itself and puts
// nodeingame when connected not here
if (node)
netnodes[node].ingame = true;
}
static void SV_AddPlayer(SINT8 node, const char *name)
{
INT32 n;
UINT8 buf[2 + MAXPLAYERNAME];
UINT8 *p;
INT32 newplayernum;
newplayernum = FindRejoinerNum(node);
if (newplayernum == -1)
{
// search for a free playernum
// we can't use playeringame since it is not updated here
for (newplayernum = dedicated ? 1 : 0; newplayernum < MAXPLAYERS; newplayernum++)
{
if (playeringame[newplayernum])
continue;
for (n = 0; n < MAXNETNODES; n++)
if (netnodes[n].player == newplayernum || netnodes[n].player2 == newplayernum)
break;
if (n == MAXNETNODES)
break;
}
}
// should never happen since we check the playernum
// before accepting the join
I_Assert(newplayernum < MAXPLAYERS);
playernode[newplayernum] = (UINT8)node;
p = buf + 2;
buf[0] = (UINT8)node;
buf[1] = newplayernum;
if (netnodes[node].numplayers < 1)
{
netnodes[node].player = newplayernum;
}
else
{
netnodes[node].player2 = newplayernum;
buf[1] |= 0x80;
}
WRITESTRINGN(p, name, MAXPLAYERNAME);
netnodes[node].numplayers++;
SendNetXCmd(XD_ADDPLAYER, &buf, p - buf);
DEBFILE(va("Server added player %d node %d\n", newplayernum, node));
}
static void SV_SendRefuse(INT32 node, const char *reason)
{
strcpy(netbuffer->u.serverrefuse.reason, reason);
netbuffer->packettype = PT_SERVERREFUSE;
HSendPacket(node, true, 0, strlen(netbuffer->u.serverrefuse.reason) + 1);
Net_CloseConnection(node);
}
static const char *
GetRefuseMessage (SINT8 node, INT32 rejoinernum)
{
clientconfig_pak *cc = &netbuffer->u.clientcfg;
boolean rejoining = (rejoinernum != -1);
if (!node)/* server connecting to itself */
return NULL;
if (
cc->modversion != MODVERSION ||
strncmp(cc->application, SRB2APPLICATION,
sizeof cc->application)
){
return/* this is probably client's fault */
"Incompatible.";
}
else if (bannednode && bannednode[node])
{
return
"You have been banned\n"
"from the server.";
}
else if (cc->localplayers != 1)
{
return
"Wrong player count.";
}
if (!rejoining)
{
if (!cv_allownewplayer.value)
{
return
"The server is not accepting\n"
"joins for the moment.";
}
else if (D_NumPlayers() >= cv_maxplayers.value)
{
return va(
"Maximum players reached: %d",
cv_maxplayers.value);
}
}
if (luafiletransfers)
{
return
"The serveris broadcasting a file\n"
"requested by a Lua script.\n"
"Please wait a bit and then\n"
"try rejoining.";
}
if (netgame)
{
const tic_t th = 2 * cv_joindelay.value * TICRATE;
if (joindelay > th)
{
return va(
"Too many people are connecting.\n"
"Please wait %d seconds and then\n"
"try rejoining.",
(joindelay - th) / TICRATE);
}
}
return NULL;
}
/** Called when a PT_CLIENTJOIN packet is received
*
* \param node The packet sender
*
*/
void PT_ClientJoin(SINT8 node)
{
char names[MAXSPLITSCREENPLAYERS][MAXPLAYERNAME + 1];
INT32 numplayers = netbuffer->u.clientcfg.localplayers;
INT32 rejoinernum;
// Ignore duplicate packets
if (client || netnodes[node].ingame)
return;
rejoinernum = FindRejoinerNum(node);
const char *refuse = GetRefuseMessage(node, rejoinernum);
if (refuse)
{
SV_SendRefuse(node, refuse);
return;
}
for (INT32 i = 0; i < numplayers; i++)
{
strlcpy(names[i], netbuffer->u.clientcfg.names[i], MAXPLAYERNAME + 1);
if (!EnsurePlayerNameIsGood(names[i], rejoinernum))
{
SV_SendRefuse(node, "Bad player name");
return;
}
}
SV_AddNode(node);
if (!SV_SendServerConfig(node))
{
/// \note Shouldn't SV_SendRefuse be called before ResetNode?
ResetNode(node);
SV_SendRefuse(node, M_GetText("Server couldn't send info, please try again"));
/// \todo fix this !!!
return;
}
DEBFILE("new node joined\n");
if (gamestate == GS_LEVEL || gamestate == GS_INTERMISSION)
{
SV_SendSaveGame(node, false); // send a complete game state
DEBFILE("send savegame\n");
}
// Splitscreen can allow 2 players in one node
for (INT32 i = 0; i < numplayers; i++)
SV_AddPlayer(node, names[i]);
joindelay += cv_joindelay.value * TICRATE;
}
void PT_AskInfoViaMS(SINT8 node)
{
Net_CloseConnection(node);
}
void PT_TellFilesNeeded(SINT8 node)
{
if (server && serverrunning)
{
UINT8 *p;
INT32 firstfile = netbuffer->u.filesneedednum;
netbuffer->packettype = PT_MOREFILESNEEDED;
netbuffer->u.filesneededcfg.first = firstfile;
netbuffer->u.filesneededcfg.more = 0;
p = PutFileNeeded(firstfile);
HSendPacket(node, false, 0, p - ((UINT8 *)&netbuffer->u));
}
else // Shouldn't get this if you aren't the server...?
Net_CloseConnection(node);
}
void PT_AskInfo(SINT8 node)
{
if (server && serverrunning)
{
SV_SendServerInfo(node, (tic_t)LONG(netbuffer->u.askinfo.time));
SV_SendPlayerInfo(node); // Send extra info
}
Net_CloseConnection(node);
}

View file

@ -0,0 +1,30 @@
// 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 server_connection.h
/// \brief Server-side part of connection handling
#ifndef __D_SERVER_CONNECTION__
#define __D_SERVER_CONNECTION__
#include "../command.h"
#include "../doomdef.h"
#include "../doomtype.h"
void PT_ClientJoin(SINT8 node);
void PT_AskInfoViaMS(SINT8 node);
void PT_TellFilesNeeded(SINT8 node);
void PT_AskInfo(SINT8 node);
extern tic_t jointimeout;
extern tic_t joindelay;
extern char playeraddress[MAXPLAYERS][64];
extern consvar_t cv_showjoinaddress, cv_allownewplayer, cv_maxplayers, cv_joindelay, cv_rejointimeout;
#endif

471
src/netcode/tic_command.c Normal file
View file

@ -0,0 +1,471 @@
// 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 tic_command.c
/// \brief Tic command handling
#include "tic_command.h"
#include "d_clisrv.h"
#include "net_command.h"
#include "client_connection.h"
#include "gamestate.h"
#include "i_net.h"
#include "../d_main.h"
#include "../g_game.h"
#include "../i_system.h"
#include "../i_time.h"
#include "../byteptr.h"
#include "../doomstat.h"
#include "../doomtype.h"
tic_t firstticstosend; // Smallest netnode.tic
tic_t tictoclear = 0; // Optimize D_ClearTiccmd
ticcmd_t localcmds;
ticcmd_t localcmds2;
boolean cl_packetmissed;
ticcmd_t netcmds[BACKUPTICS][MAXPLAYERS];
static inline void *G_DcpyTiccmd(void* dest, const ticcmd_t* src, const size_t n)
{
const size_t d = n / sizeof(ticcmd_t);
const size_t r = n % sizeof(ticcmd_t);
UINT8 *ret = dest;
if (r)
M_Memcpy(dest, src, n);
else if (d)
G_MoveTiccmd(dest, src, d);
return ret+n;
}
static inline void *G_ScpyTiccmd(ticcmd_t* dest, void* src, const size_t n)
{
const size_t d = n / sizeof(ticcmd_t);
const size_t r = n % sizeof(ticcmd_t);
UINT8 *ret = src;
if (r)
M_Memcpy(dest, src, n);
else if (d)
G_MoveTiccmd(dest, src, d);
return ret+n;
}
/** Guesses the full value of a tic from its lowest byte, for a specific node
*
* \param low The lowest byte of the tic value
* \param node The node to deduce the tic for
* \return The full tic value
*
*/
tic_t ExpandTics(INT32 low, INT32 node)
{
INT32 delta;
delta = low - (netnodes[node].tic & UINT8_MAX);
if (delta >= -64 && delta <= 64)
return (netnodes[node].tic & ~UINT8_MAX) + low;
else if (delta > 64)
return (netnodes[node].tic & ~UINT8_MAX) - 256 + low;
else //if (delta < -64)
return (netnodes[node].tic & ~UINT8_MAX) + 256 + low;
}
void D_Clearticcmd(tic_t tic)
{
D_FreeTextcmd(tic);
for (INT32 i = 0; i < MAXPLAYERS; i++)
netcmds[tic%BACKUPTICS][i].angleturn = 0;
DEBFILE(va("clear tic %5u (%2u)\n", tic, tic%BACKUPTICS));
}
void D_ResetTiccmds(void)
{
memset(&localcmds, 0, sizeof(ticcmd_t));
memset(&localcmds2, 0, sizeof(ticcmd_t));
// Reset the net command list
for (INT32 i = 0; i < TEXTCMD_HASH_SIZE; i++)
while (textcmds[i])
D_Clearticcmd(textcmds[i]->tic);
}
// Check ticcmd for "speed hacks"
static void CheckTiccmdHacks(INT32 playernum, tic_t tic)
{
ticcmd_t *cmd = &netcmds[tic%BACKUPTICS][playernum];
if (cmd->forwardmove > MAXPLMOVE || cmd->forwardmove < -MAXPLMOVE
|| cmd->sidemove > MAXPLMOVE || cmd->sidemove < -MAXPLMOVE)
{
CONS_Alert(CONS_WARNING, M_GetText("Illegal movement value received from node %d\n"), playernum);
SendKick(playernum, KICK_MSG_CON_FAIL);
}
}
// Check player consistancy during the level
static void CheckConsistancy(SINT8 nodenum, tic_t tic)
{
netnode_t *node = &netnodes[nodenum];
INT16 neededconsistancy = consistancy[tic%BACKUPTICS];
INT16 clientconsistancy = SHORT(netbuffer->u.clientpak.consistancy);
if (tic > gametic || tic + BACKUPTICS - 1 <= gametic || gamestate != GS_LEVEL
|| neededconsistancy == clientconsistancy || SV_ResendingSavegameToAnyone()
|| node->resendingsavegame || node->savegameresendcooldown > I_GetTime())
return;
if (cv_resynchattempts.value)
{
// Tell the client we are about to resend them the gamestate
netbuffer->packettype = PT_WILLRESENDGAMESTATE;
HSendPacket(nodenum, true, 0, 0);
node->resendingsavegame = true;
if (cv_blamecfail.value)
CONS_Printf(M_GetText("Synch failure for player %d (%s); expected %hd, got %hd\n"),
node->player+1, player_names[node->player],
neededconsistancy, clientconsistancy);
DEBFILE(va("Restoring player %d (synch failure) [%update] %d!=%d\n",
node->player, tic, neededconsistancy, clientconsistancy));
}
else
{
SendKick(node->player, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY);
DEBFILE(va("player %d kicked (synch failure) [%u] %d!=%d\n",
node->player, tic, neededconsistancy, clientconsistancy));
}
}
void PT_ClientCmd(SINT8 nodenum, INT32 netconsole)
{
netnode_t *node = &netnodes[nodenum];
tic_t realend, realstart;
if (client)
return;
// To save bytes, only the low byte of tic numbers are sent
// Use ExpandTics to figure out what the rest of the bytes are
realstart = ExpandTics(netbuffer->u.clientpak.client_tic, nodenum);
realend = ExpandTics(netbuffer->u.clientpak.resendfrom, nodenum);
if (netbuffer->packettype == PT_CLIENTMIS || netbuffer->packettype == PT_CLIENT2MIS
|| netbuffer->packettype == PT_NODEKEEPALIVEMIS
|| node->supposedtic < realend)
{
node->supposedtic = realend;
}
// Discard out of order packet
if (node->tic > realend)
{
DEBFILE(va("out of order ticcmd discarded nettics = %u\n", node->tic));
return;
}
// Update the nettics
node->tic = realend;
// This should probably still timeout though, as the node should always have a player 1 number
if (netconsole == -1)
return;
// 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?
node->freezetimeout = 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)
return;
// If we've alredy received a ticcmd for this tic, just submit it for the next one.
tic_t faketic = maketic;
if ((!!(netcmds[maketic % BACKUPTICS][netconsole].angleturn & TICCMD_RECEIVED))
&& (maketic - firstticstosend < BACKUPTICS - 1))
faketic++;
// Copy ticcmd
G_MoveTiccmd(&netcmds[faketic%BACKUPTICS][netconsole], &netbuffer->u.clientpak.cmd, 1);
// Splitscreen cmd
if ((netbuffer->packettype == PT_CLIENT2CMD || netbuffer->packettype == PT_CLIENT2MIS)
&& node->player2 >= 0)
G_MoveTiccmd(&netcmds[faketic%BACKUPTICS][(UINT8)node->player2],
&netbuffer->u.client2pak.cmd2, 1);
CheckTiccmdHacks(netconsole, faketic);
CheckConsistancy(nodenum, realstart);
}
void PT_ServerTics(SINT8 node, INT32 netconsole)
{
tic_t realend, realstart;
servertics_pak *packet = &netbuffer->u.serverpak;
if (!netnodes[node].ingame)
{
// Do not remove my own server (we have just get a out of order packet)
if (node != servernode)
{
DEBFILE(va("unknown packet received (%d) from unknown host\n",netbuffer->packettype));
Net_CloseConnection(node);
}
return;
}
// Only accept PT_SERVERTICS from the server.
if (node != servernode)
{
CONS_Alert(CONS_WARNING, M_GetText("%s received from non-host %d\n"), "PT_SERVERTICS", node);
if (server)
SendKick(netconsole, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY);
return;
}
realstart = packet->starttic;
realend = realstart + packet->numtics;
realend = min(realend, gametic + CLIENTBACKUPTICS);
cl_packetmissed = realstart > neededtic;
if (realstart <= neededtic && realend > neededtic)
{
UINT8 *pak = (UINT8 *)&packet->cmds;
UINT8 *txtpak = (UINT8 *)&packet->cmds[packet->numslots * packet->numtics];
for (tic_t i = realstart; i < realend; i++)
{
// clear first
D_Clearticcmd(i);
// copy the tics
pak = G_ScpyTiccmd(netcmds[i%BACKUPTICS], pak,
packet->numslots*sizeof (ticcmd_t));
CL_CopyNetCommandsFromServerPacket(i, &txtpak);
}
neededtic = realend;
}
else
{
DEBFILE(va("frame not in bound: %u\n", neededtic));
}
}
// send the client packet to the server
void CL_SendClientCmd(void)
{
size_t packetsize = 0;
boolean mis = false;
netbuffer->packettype = PT_CLIENTCMD;
if (cl_packetmissed)
{
netbuffer->packettype = PT_CLIENTMIS;
mis = true;
}
netbuffer->u.clientpak.resendfrom = (UINT8)(neededtic & UINT8_MAX);
netbuffer->u.clientpak.client_tic = (UINT8)(gametic & UINT8_MAX);
if (gamestate == GS_WAITINGPLAYERS)
{
// Send PT_NODEKEEPALIVE packet
netbuffer->packettype = (mis ? PT_NODEKEEPALIVEMIS : PT_NODEKEEPALIVE);
packetsize = sizeof (clientcmd_pak) - sizeof (ticcmd_t) - sizeof (INT16);
HSendPacket(servernode, false, 0, packetsize);
}
else if (gamestate != GS_NULL && (addedtogame || dedicated))
{
packetsize = sizeof (clientcmd_pak);
G_MoveTiccmd(&netbuffer->u.clientpak.cmd, &localcmds, 1);
netbuffer->u.clientpak.consistancy = SHORT(consistancy[gametic%BACKUPTICS]);
// Send a special packet with 2 cmd for splitscreen
if (splitscreen || botingame)
{
netbuffer->packettype = (mis ? PT_CLIENT2MIS : PT_CLIENT2CMD);
packetsize = sizeof (client2cmd_pak);
G_MoveTiccmd(&netbuffer->u.client2pak.cmd2, &localcmds2, 1);
}
HSendPacket(servernode, false, 0, packetsize);
}
if (cl_mode == CL_CONNECTED || dedicated)
CL_SendNetCommands();
}
// PT_SERVERTICS packets can grow too large for a single UDP packet,
// So this checks how many tics worth of data can be sent in one packet.
// The rest can be sent later, usually the next tic.
static tic_t SV_CalculateNumTicsForPacket(SINT8 nodenum, tic_t firsttic, tic_t lasttic)
{
size_t size = BASESERVERTICSSIZE;
for (tic_t tic = firsttic; tic < lasttic; tic++)
{
size += sizeof (ticcmd_t) * doomcom->numslots;
size += TotalTextCmdPerTic(tic);
if (size > software_MAXPACKETLENGTH)
{
DEBFILE(va("packet too large (%s) at tic %d (should be from %d to %d)\n",
sizeu1(size), tic, firsttic, lasttic));
lasttic = tic;
// Too bad: too many players have sent extra data
// and there is too much data for a single tic.
// To avoid that, keep the data for the next tic (see PT_TEXTCMD).
if (lasttic == firsttic)
{
if (size > MAXPACKETLENGTH)
I_Error("Too many players: can't send %s data for %d players to node %d\n"
"Well sorry nobody is perfect....\n",
sizeu1(size), doomcom->numslots, nodenum);
else
{
lasttic++; // send it anyway!
DEBFILE("sending it anyway\n");
}
}
break;
}
}
return lasttic - firsttic;
}
// Sends the server packet
// Sends tic/net commands from firstticstosend to maketic-1
void SV_SendTics(void)
{
tic_t realfirsttic, lasttictosend;
// Send to all clients except yourself
// For each node, create a packet with x tics and send it
// x is computed using node.supposedtic, max packet size and maketic
for (INT32 n = 1; n < MAXNETNODES; n++)
if (netnodes[n].ingame)
{
netnode_t *node = &netnodes[n];
// assert node->supposedtic>=node->tic
realfirsttic = node->supposedtic;
lasttictosend = min(maketic, node->tic + CLIENTBACKUPTICS);
if (realfirsttic >= lasttictosend)
{
// Well, we have sent all the tics, so we will use extra bandwidth
// to resend packets that are supposed lost.
// This is necessary since lost packet detection
// works when we receive a packet with firsttic > neededtic (PT_SERVERTICS)
DEBFILE(va("Nothing to send node %u mak=%u sup=%u net=%u \n",
n, maketic, node->supposedtic, node->tic));
realfirsttic = node->tic;
if (realfirsttic >= lasttictosend || (I_GetTime() + n)&3)
// All tics are Ok
continue;
DEBFILE(va("Sent %d anyway\n", realfirsttic));
}
realfirsttic = max(realfirsttic, firstticstosend);
lasttictosend = realfirsttic + SV_CalculateNumTicsForPacket(n, realfirsttic, lasttictosend);
// Prepare the packet header
netbuffer->packettype = PT_SERVERTICS;
netbuffer->u.serverpak.starttic = realfirsttic;
netbuffer->u.serverpak.numtics = (UINT8)(lasttictosend - realfirsttic);
netbuffer->u.serverpak.numslots = (UINT8)SHORT(doomcom->numslots);
// Fill and send the packet
UINT8 *bufpos = (UINT8 *)&netbuffer->u.serverpak.cmds;
for (tic_t i = realfirsttic; i < lasttictosend; i++)
bufpos = G_DcpyTiccmd(bufpos, netcmds[i%BACKUPTICS], doomcom->numslots * sizeof (ticcmd_t));
for (tic_t i = realfirsttic; i < lasttictosend; i++)
SV_WriteNetCommandsForTic(i, &bufpos);
size_t packsize = bufpos - (UINT8 *)&(netbuffer->u);
HSendPacket(n, false, 0, packsize);
// When tics are too large, only one tic is sent so don't go backwards!
if (lasttictosend-doomcom->extratics > realfirsttic)
node->supposedtic = lasttictosend-doomcom->extratics;
else
node->supposedtic = lasttictosend;
node->supposedtic = max(node->supposedtic, node->tic);
}
// node 0 is me!
netnodes[0].supposedtic = maketic;
}
void Local_Maketic(INT32 realtics)
{
I_OsPolling(); // I_Getevent
D_ProcessEvents(); // menu responder, cons responder,
// game responder calls HU_Responder, AM_Responder,
// and G_MapEventsToControls
if (!dedicated)
rendergametic = gametic;
// translate inputs (keyboard/mouse/joystick) into game controls
G_BuildTiccmd(&localcmds, realtics, 1);
if (splitscreen || botingame)
G_BuildTiccmd(&localcmds2, realtics, 2);
localcmds.angleturn |= TICCMD_RECEIVED;
localcmds2.angleturn |= TICCMD_RECEIVED;
}
// create missed tic
void SV_Maketic(void)
{
for (INT32 i = 0; i < MAXPLAYERS; i++)
{
if (!playeringame[i])
continue;
// We didn't receive this tic
if ((netcmds[maketic % BACKUPTICS][i].angleturn & TICCMD_RECEIVED) == 0)
{
ticcmd_t * ticcmd = &netcmds[(maketic ) % BACKUPTICS][i];
ticcmd_t *prevticcmd = &netcmds[(maketic - 1) % BACKUPTICS][i];
if (players[i].quittime)
{
// Copy the angle/aiming from the previous tic
// and empty the other inputs
memset(ticcmd, 0, sizeof(netcmds[0][0]));
ticcmd->angleturn = prevticcmd->angleturn | TICCMD_RECEIVED;
ticcmd->aiming = prevticcmd->aiming;
}
else
{
DEBFILE(va("MISS tic%4d for player %d\n", maketic, i));
// Copy the input from the previous tic
*ticcmd = *prevticcmd;
ticcmd->angleturn &= ~TICCMD_RECEIVED;
}
}
}
// All tics have been processed, make the next
maketic++;
}

44
src/netcode/tic_command.h Normal file
View file

@ -0,0 +1,44 @@
// 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 tic_command.h
/// \brief Tic command handling
#ifndef __D_TIC_COMMAND__
#define __D_TIC_COMMAND__
#include "d_clisrv.h"
#include "../d_ticcmd.h"
#include "../doomdef.h"
#include "../doomtype.h"
extern tic_t firstticstosend; // min of the nettics
extern tic_t tictoclear; // optimize d_clearticcmd
extern ticcmd_t localcmds;
extern ticcmd_t localcmds2;
extern boolean cl_packetmissed;
extern ticcmd_t netcmds[BACKUPTICS][MAXPLAYERS];
tic_t ExpandTics(INT32 low, INT32 node);
void D_Clearticcmd(tic_t tic);
void D_ResetTiccmds(void);
void PT_ClientCmd(SINT8 nodenum, INT32 netconsole);
void PT_ServerTics(SINT8 node, INT32 netconsole);
// send the client packet to the server
void CL_SendClientCmd(void);
void SV_SendTics(void);
void Local_Maketic(INT32 realtics);
void SV_Maketic(void);
#endif

View file

@ -17,7 +17,7 @@
#include "r_main.h" #include "r_main.h"
#include "s_sound.h" #include "s_sound.h"
#include "z_zone.h" #include "z_zone.h"
#include "d_netcmd.h" #include "netcode/d_netcmd.h"
// ========================================================================== // ==========================================================================
// CEILINGS // CEILINGS

View file

@ -5248,7 +5248,7 @@ void A_SignPlayer(mobj_t *actor)
return; return;
skin = &skins[actor->target->player->skin]; skin = &skins[actor->target->player->skin];
facecolor = actor->target->player->skincolor; facecolor = P_GetPlayerColor(actor->target->player);
if (signcolor) if (signcolor)
; ;
@ -9059,7 +9059,7 @@ void A_Dye(mobj_t *actor)
if (!color) if (!color)
{ {
target->colorized = false; target->colorized = false;
target->color = target->player ? target->player->skincolor : SKINCOLOR_NONE; target->color = target->player ? P_GetPlayerColor(target->player) : SKINCOLOR_NONE;
} }
else if (!(target->player)) else if (!(target->player))
{ {

View file

@ -28,6 +28,7 @@
#include "m_misc.h" #include "m_misc.h"
#include "v_video.h" // video flags for CEchos #include "v_video.h" // video flags for CEchos
#include "f_finale.h" #include "f_finale.h"
#include "netcode/net_command.h"
// CTF player names // CTF player names
#define CTFTEAMCODE(pl) pl->ctfteam ? (pl->ctfteam == 1 ? "\x85" : "\x84") : "" #define CTFTEAMCODE(pl) pl->ctfteam ? (pl->ctfteam == 1 ? "\x85" : "\x84") : ""
@ -1144,7 +1145,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
if (!(mo2->type == MT_RING || mo2->type == MT_COIN if (!(mo2->type == MT_RING || mo2->type == MT_COIN
|| mo2->type == MT_BLUESPHERE || mo2->type == MT_BOMBSPHERE || mo2->type == MT_BLUESPHERE || mo2->type == MT_BOMBSPHERE
|| mo2->type == MT_NIGHTSCHIP || mo2->type == MT_NIGHTSSTAR || mo2->type == MT_NIGHTSCHIP || mo2->type == MT_NIGHTSSTAR
|| ((mo2->type == MT_EMBLEM) && (mo2->reactiontime & GE_NIGHTSPULL)))) || ((mo2->type == MT_EMBLEM) && (mo2->reactiontime & GE_NIGHTSPULL) && P_CanPickupEmblem(player, mo2->health - 1) && !P_EmblemWasCollected(mo2->health - 1))))
continue; continue;
// Yay! The thing's in reach! Pull it in! // Yay! The thing's in reach! Pull it in!
@ -2235,7 +2236,7 @@ void P_CheckTimeLimit(void)
} }
if (server) if (server)
SendNetXCmd(XD_EXITLEVEL, NULL, 0); D_SendExitLevel(false);
} }
//Optional tie-breaker for Match/CTF //Optional tie-breaker for Match/CTF
@ -2298,11 +2299,11 @@ void P_CheckTimeLimit(void)
} }
} }
if (server) if (server)
SendNetXCmd(XD_EXITLEVEL, NULL, 0); D_SendExitLevel(false);
} }
if (server) if (server)
SendNetXCmd(XD_EXITLEVEL, NULL, 0); D_SendExitLevel(false);
} }
/** Checks if a player's score is over the pointlimit and the round should end. /** Checks if a player's score is over the pointlimit and the round should end.
@ -2331,7 +2332,7 @@ void P_CheckPointLimit(void)
if ((UINT32)cv_pointlimit.value <= redscore || (UINT32)cv_pointlimit.value <= bluescore) if ((UINT32)cv_pointlimit.value <= redscore || (UINT32)cv_pointlimit.value <= bluescore)
{ {
if (server) if (server)
SendNetXCmd(XD_EXITLEVEL, NULL, 0); D_SendExitLevel(false);
} }
} }
else else
@ -2344,7 +2345,7 @@ void P_CheckPointLimit(void)
if ((UINT32)cv_pointlimit.value <= players[i].score) if ((UINT32)cv_pointlimit.value <= players[i].score)
{ {
if (server) if (server)
SendNetXCmd(XD_EXITLEVEL, NULL, 0); D_SendExitLevel(false);
return; return;
} }
} }
@ -2388,7 +2389,7 @@ void P_CheckSurvivors(void)
{ {
CONS_Printf(M_GetText("The IT player has left the game.\n")); CONS_Printf(M_GetText("The IT player has left the game.\n"));
if (server) if (server)
SendNetXCmd(XD_EXITLEVEL, NULL, 0); D_SendExitLevel(false);
return; return;
} }
@ -2408,7 +2409,7 @@ void P_CheckSurvivors(void)
{ {
CONS_Printf(M_GetText("All players have been tagged!\n")); CONS_Printf(M_GetText("All players have been tagged!\n"));
if (server) if (server)
SendNetXCmd(XD_EXITLEVEL, NULL, 0); D_SendExitLevel(false);
} }
return; return;
@ -2420,7 +2421,7 @@ void P_CheckSurvivors(void)
{ {
CONS_Printf(M_GetText("There are no players able to become IT.\n")); CONS_Printf(M_GetText("There are no players able to become IT.\n"));
if (server) if (server)
SendNetXCmd(XD_EXITLEVEL, NULL, 0); D_SendExitLevel(false);
} }
return; return;
@ -2432,7 +2433,7 @@ void P_CheckSurvivors(void)
{ {
CONS_Printf(M_GetText("All players have been tagged!\n")); CONS_Printf(M_GetText("All players have been tagged!\n"));
if (server) if (server)
SendNetXCmd(XD_EXITLEVEL, NULL, 0); D_SendExitLevel(false);
} }
} }
@ -2630,7 +2631,7 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget
} }
} }
target->color = target->player->skincolor; target->color = P_GetPlayerColor(target->player);
target->colorized = false; target->colorized = false;
G_GhostAddColor(GHC_NORMAL); G_GhostAddColor(GHC_NORMAL);
@ -3323,7 +3324,7 @@ static void P_KillPlayer(player_t *player, mobj_t *source, INT32 damage)
// Get rid of shield // Get rid of shield
player->powers[pw_shield] = SH_NONE; player->powers[pw_shield] = SH_NONE;
player->mo->color = player->skincolor; player->mo->color = P_GetPlayerColor(player);
// Get rid of emeralds // Get rid of emeralds
player->powers[pw_emeralds] = 0; player->powers[pw_emeralds] = 0;
@ -3440,7 +3441,7 @@ void P_RemoveShield(player_t *player)
{ // Second layer shields { // Second layer shields
if (((player->powers[pw_shield] & SH_STACK) == SH_FIREFLOWER) && !(player->powers[pw_super] || (mariomode && player->powers[pw_invulnerability]))) if (((player->powers[pw_shield] & SH_STACK) == SH_FIREFLOWER) && !(player->powers[pw_super] || (mariomode && player->powers[pw_invulnerability])))
{ {
player->mo->color = player->skincolor; player->mo->color = P_GetPlayerColor(player);
G_GhostAddColor(GHC_NORMAL); G_GhostAddColor(GHC_NORMAL);
} }
player->powers[pw_shield] = SH_NONE; player->powers[pw_shield] = SH_NONE;

View file

@ -17,7 +17,7 @@
#include "r_state.h" #include "r_state.h"
#include "z_zone.h" #include "z_zone.h"
#include "m_random.h" #include "m_random.h"
#include "d_netcmd.h" #include "netcode/d_netcmd.h"
/** Removes any active lighting effects in a sector. /** Removes any active lighting effects in a sector.
* *

View file

@ -146,6 +146,7 @@ void P_ForceLocalAngle(player_t *player, angle_t angle);
boolean P_PlayerFullbright(player_t *player); boolean P_PlayerFullbright(player_t *player);
boolean P_PlayerCanEnterSpinGaps(player_t *player); boolean P_PlayerCanEnterSpinGaps(player_t *player);
boolean P_PlayerShouldUseSpinHeight(player_t *player); boolean P_PlayerShouldUseSpinHeight(player_t *player);
UINT16 P_GetPlayerColor(player_t *player);
boolean P_IsObjectInGoop(mobj_t *mo); boolean P_IsObjectInGoop(mobj_t *mo);
boolean P_IsObjectOnGround(mobj_t *mo); boolean P_IsObjectOnGround(mobj_t *mo);

View file

@ -2524,7 +2524,6 @@ boolean P_CheckCameraPosition(fixed_t x, fixed_t y, camera_t *thiscam)
boolean P_TryCameraMove(fixed_t x, fixed_t y, camera_t *thiscam) boolean P_TryCameraMove(fixed_t x, fixed_t y, camera_t *thiscam)
{ {
subsector_t *s = R_PointInSubsector(x, y); subsector_t *s = R_PointInSubsector(x, y);
boolean retval = true;
boolean itsatwodlevel = false; boolean itsatwodlevel = false;
floatok = false; floatok = false;
@ -2539,8 +2538,8 @@ boolean P_TryCameraMove(fixed_t x, fixed_t y, camera_t *thiscam)
fixed_t tryx = thiscam->x; fixed_t tryx = thiscam->x;
fixed_t tryy = thiscam->y; fixed_t tryy = thiscam->y;
if ((thiscam == &camera && (players[displayplayer].pflags & PF_NOCLIP)) if ((thiscam == &camera && (players[displayplayer].pflags & PF_NOCLIP || players[displayplayer].powers[pw_carry] == CR_NIGHTSMODE))
|| (thiscam == &camera2 && (players[secondarydisplayplayer].pflags & PF_NOCLIP))) || (thiscam == &camera2 && (players[secondarydisplayplayer].pflags & PF_NOCLIP || players[secondarydisplayplayer].powers[pw_carry] == CR_NIGHTSMODE)))
{ // Noclipping player camera noclips too!! { // Noclipping player camera noclips too!!
floatok = true; floatok = true;
thiscam->floorz = thiscam->z; thiscam->floorz = thiscam->z;
@ -2608,7 +2607,7 @@ boolean P_TryCameraMove(fixed_t x, fixed_t y, camera_t *thiscam)
thiscam->y = y; thiscam->y = y;
thiscam->subsector = s; thiscam->subsector = s;
return retval; return true;
} }
// //
@ -3731,7 +3730,9 @@ void P_SlideMove(mobj_t *mo)
boolean papercol = false; boolean papercol = false;
vertex_t v1, v2; // fake vertexes vertex_t v1, v2; // fake vertexes
line_t junk; // fake linedef static line_t junk; // fake linedef
memset(&junk, 0x00, sizeof(junk));
if (tmhitthing && mo->z + mo->height > tmhitthing->z && mo->z < tmhitthing->z + tmhitthing->height) if (tmhitthing && mo->z + mo->height > tmhitthing->z && mo->z < tmhitthing->z + tmhitthing->height)
{ {

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