diff --git a/.circleci/config.yml b/.circleci/config.yml
new file mode 100644
index 00000000..b5c43d01
--- /dev/null
+++ b/.circleci/config.yml
@@ -0,0 +1,63 @@
+version: 2
+jobs:
+ build:
+ working_directory: /root/SRB2
+ docker:
+ - image: debian:jessie
+ environment:
+ CC: ccache gcc -m32
+ PKG_CONFIG_LIBDIR: /usr/lib/i386-linux-gnu/pkgconfig
+ LIBGME_CFLAGS: -I/usr/include
+ LIBGME_LDFLAGS: -lgme
+ CCACHE_COMPRESS: true
+ WFLAGS: -Wno-unsuffixed-float-constants
+ GCC49: true
+ #- image: ubuntu:trusty
+ # environment:
+ # CC: ccache gcc -m32
+ # PKG_CONFIG_LIBDIR: /usr/lib/i386-linux-gnu/pkgconfig
+ # LIBGME_CFLAGS: -I/usr/include
+ # LIBGME_LDFLAGS: -lgme
+ # CCACHE_COMPRESS: true
+ # WFLAGS: -Wno-unsuffixed-float-constants
+ # GCC48: true
+ steps:
+ - run:
+ name: Add i386 arch
+ command: dpkg --add-architecture i386
+ - run:
+ name: Update APT listing
+ command: apt-get -qq update
+ - run:
+ name: Support S3 upload
+ command: apt-get -qq -y install ca-certificates
+ - restore_cache:
+ keys:
+ - v1-SRB2-APT
+ - run:
+ name: Install SDK
+ command: apt-get -qq -y install git build-essential nasm libpng12-dev:i386 libsdl2-mixer-dev:i386 libgme-dev:i386 gettext ccache wget gcc-multilib upx
+ - save_cache:
+ key: v1-SRB2-APT
+ paths:
+ - /var/cache/apt/archives
+ - checkout
+ - run:
+ name: Clean build
+ command: make -C src LINUX=1 clean
+ - restore_cache:
+ keys:
+ - v1-SRB2-{{ .Branch }}-{{ checksum "objs/Linux/SDL/Release/depend.dep" }}
+ - run:
+ name: Compile
+ command: make -C src LINUX=1 ERRORMODE=1 -k
+ - store_artifacts:
+ path: /root/SRB2/bin/Linux/Release/
+ destination: bin
+ - save_cache:
+ key: v1-SRB2-{{ .Branch }}-{{ checksum "objs/Linux/SDL/Release/depend.dep" }}
+ paths:
+ - /root/.ccache
+
+
+
diff --git a/.travis.yml b/.travis.yml
index e3408cf6..e5dbb58e 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -98,7 +98,7 @@ matrix:
- p7zip-full
- gcc-6
compiler: gcc-6
- env: WFLAGS="-Wno-error=tautological-compare"
+ env: WFLAGS="-Wno-tautological-compare"
#gcc-6 (Ubuntu 6.1.1-3ubuntu11~14.04.1) 6.1.1 20160511
- os: linux
compiler: clang
@@ -162,28 +162,28 @@ matrix:
- clang-3.8
compiler: clang-3.8
#clang version 3.8.1-svn271127-1~exp1 (branches/release_38)
- - os: osx
- osx_image: beta-xcode6.1
- #Apple LLVM version 6.0 (clang-600.0.54) (based on LLVM 3.5svn)
- - os: osx
- osx_image: beta-xcode6.2
- compiler: gcc
- #Apple LLVM version 6.0 (clang-600.0.57) (based on LLVM 3.5svn)
# - os: osx
-# osx_image: beta-xcode6.3
-# #I think xcode.6.3 VM is broken, it does not boot
- - os: osx
- osx_image: xcode6.4
- #Apple LLVM version 6.1.0 (clang-602.0.53) (based on LLVM 3.6.0svn)
- - os: osx
- osx_image: xcode7
- #Apple LLVM version 7.0.0 (clang-700.0.72)
- - os: osx
- osx_image: xcode7.1
- #Apple LLVM version 7.0.0 (clang-700.1.76)
- - os: osx
- osx_image: xcode7.2
- #Apple LLVM version 7.0.2 (clang-700.1.81)
+# osx_image: beta-xcode6.1
+# #Apple LLVM version 6.0 (clang-600.0.54) (based on LLVM 3.5svn)
+# - os: osx
+# osx_image: beta-xcode6.2
+# compiler: gcc
+# #Apple LLVM version 6.0 (clang-600.0.57) (based on LLVM 3.5svn)
+## - os: osx
+## osx_image: beta-xcode6.3
+## #I think xcode.6.3 VM is broken, it does not boot
+# - os: osx
+# osx_image: xcode6.4
+# #Apple LLVM version 6.1.0 (clang-602.0.53) (based on LLVM 3.6.0svn)
+# - os: osx
+# osx_image: xcode7
+# #Apple LLVM version 7.0.0 (clang-700.0.72)
+# - os: osx
+# osx_image: xcode7.1
+# #Apple LLVM version 7.0.0 (clang-700.1.76)
+# - os: osx
+# osx_image: xcode7.2
+# #Apple LLVM version 7.0.2 (clang-700.1.81)
- os: osx
osx_image: xcode7.3
#Apple LLVM version 7.3.0 (clang-703.0.31)
@@ -213,7 +213,7 @@ before_script:
- 7z x $HOME/srb2_cache/SRB2-v2115-assets-2.7z -oassets
- mkdir build
- cd build
- - export CFLAGS="-Wall -W $WFLAGS"
+ - export CFLAGS="-Wall -W -Werror $WFLAGS"
- export CCACHE_COMPRESS=true
- cmake .. -DCMAKE_BUILD_TYPE=Release
diff --git a/CMakeLists.txt b/CMakeLists.txt
index cb93d22f..f9364fdd 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.0)
project(SRB2
- VERSION 2.1.14
+ VERSION 2.1.19
LANGUAGES C)
if(${PROJECT_SOURCE_DIR} MATCHES ${PROJECT_BINARY_DIR})
diff --git a/README.md b/README.md
new file mode 100644
index 00000000..d1607145
--- /dev/null
+++ b/README.md
@@ -0,0 +1,23 @@
+# Sonic Robo Blast 2
+
+[![Build status](https://ci.appveyor.com/api/projects/status/399d4hcw9yy7hg2y?svg=true)](https://ci.appveyor.com/project/STJr/srb2)
+[![Build status](https://travis-ci.org/STJr/SRB2.svg?branch=master)](https://travis-ci.org/STJr/SRB2)
+[![CircleCI](https://circleci.com/gh/STJr/SRB2/tree/master.svg?style=svg)](https://circleci.com/gh/STJr/SRB2/tree/master)
+
+[Sonic Robo Blast 2](https://srb2.org/) is a 3D Sonic the Hedgehog fangame based on a modified version of [Doom Legacy](http://doomlegacy.sourceforge.net/).
+
+## Dependencies
+- NASM (x86 builds only)
+- SDL2 (Linux/OS X only)
+- SDL2-Mixer (Linux/OS X only)
+- libupnp (Linux/OS X only)
+- libgme (Linux/OS X only)
+
+Warning: 64-bit builds are not netgame compatible with 32-bit builds. Use at your own risk.
+
+## Compiling
+
+See [SRB2 Wiki/Source code compiling](http://wiki.srb2.org/wiki/Source_code_compiling)
+
+## Disclaimer
+Sonic Team Junior is in no way affiliated with SEGA or Sonic Team. We do not claim ownership of any of SEGA's intellectual property used in SRB2.
diff --git a/SRB2.cbp b/SRB2.cbp
index 43696ee2..74ec96c6 100644
--- a/SRB2.cbp
+++ b/SRB2.cbp
@@ -14,7 +14,7 @@ If you are compiling for Windows, use Mingw targets
Interface Defines:
_WINDOWS for DirectX Interface
SDL for SDL Interface
-HAVE_MIXER for SDL_Mixer
+HAVE_MIXER for SDL2_mixer
HAVE_PNG for PNG support (for APNG support. compile libs/libpng-src)
HWRENDER for hardware render support
@@ -31,7 +31,7 @@ HW3SOUND for 3D hardware sound support
-
+
@@ -41,8 +41,8 @@ HW3SOUND for 3D hardware sound support
-
-
+
+
@@ -54,7 +54,7 @@ HW3SOUND for 3D hardware sound support
-
+
@@ -62,8 +62,8 @@ HW3SOUND for 3D hardware sound support
-
-
+
+
@@ -74,7 +74,7 @@ HW3SOUND for 3D hardware sound support
-
+
@@ -89,9 +89,9 @@ HW3SOUND for 3D hardware sound support
-
+
-
+
@@ -104,7 +104,7 @@ HW3SOUND for 3D hardware sound support
-
+
@@ -117,9 +117,9 @@ HW3SOUND for 3D hardware sound support
-
+
-
+
@@ -152,6 +152,8 @@ HW3SOUND for 3D hardware sound support
+
+
@@ -167,6 +169,8 @@ HW3SOUND for 3D hardware sound support
+
+
@@ -198,6 +202,8 @@ HW3SOUND for 3D hardware sound support
+
+
@@ -213,6 +219,8 @@ HW3SOUND for 3D hardware sound support
+
+
@@ -567,7 +575,7 @@ HW3SOUND for 3D hardware sound support
-
+
@@ -606,7 +614,7 @@ HW3SOUND for 3D hardware sound support
-
+
@@ -884,385 +892,90 @@ HW3SOUND for 3D hardware sound support
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -1270,478 +983,62 @@ HW3SOUND for 3D hardware sound support
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
@@ -1772,187 +1069,28 @@ HW3SOUND for 3D hardware sound support
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
@@ -2353,1778 +1491,265 @@ HW3SOUND for 3D hardware sound support
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
+
+
-
+
-
-
-
-
-
-
-
-
-
-
+
+
-
+
@@ -4133,15 +1758,7 @@ HW3SOUND for 3D hardware sound support
-
-
-
-
-
-
-
-
-
+
@@ -4150,7 +1767,15 @@ HW3SOUND for 3D hardware sound support
-
+
+
+
+
+
+
+
+
+
@@ -4159,7 +1784,7 @@ HW3SOUND for 3D hardware sound support
-
+
@@ -4167,7 +1792,7 @@ HW3SOUND for 3D hardware sound support
-
+
@@ -4176,15 +1801,7 @@ HW3SOUND for 3D hardware sound support
-
-
-
-
-
-
-
-
-
+
@@ -4193,7 +1810,7 @@ HW3SOUND for 3D hardware sound support
-
+
@@ -4202,7 +1819,7 @@ HW3SOUND for 3D hardware sound support
-
+
@@ -4211,7 +1828,7 @@ HW3SOUND for 3D hardware sound support
-
+
@@ -4220,7 +1837,15 @@ HW3SOUND for 3D hardware sound support
-
+
+
+
+
+
+
+
+
+
@@ -4229,15 +1854,7 @@ HW3SOUND for 3D hardware sound support
-
-
-
-
-
-
-
-
-
+
@@ -4246,7 +1863,7 @@ HW3SOUND for 3D hardware sound support
-
+
@@ -4255,7 +1872,15 @@ HW3SOUND for 3D hardware sound support
-
+
+
+
+
+
+
+
+
+
@@ -4264,24 +1889,7 @@ HW3SOUND for 3D hardware sound support
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
@@ -4291,120 +1899,39 @@ HW3SOUND for 3D hardware sound support
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
@@ -4427,46 +1954,17 @@ HW3SOUND for 3D hardware sound support
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
+
+
-
-
+
+
@@ -4478,37 +1976,8 @@ HW3SOUND for 3D hardware sound support
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
@@ -4634,70 +2103,12 @@ HW3SOUND for 3D hardware sound support
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
diff --git a/appveyor.yml b/appveyor.yml
index 85cee6a3..23b9b628 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -1,4 +1,4 @@
-version: 2.1.14.{branch}-{build}
+version: 2.1.19.{branch}-{build}
os: MinGW
environment:
@@ -47,7 +47,7 @@ before_build:
- upx -V
- ccache -V
- ccache -s
-- set SRB2_MFLAGS=-C src MINGW=1 WARNINGMODE=1 GCC53=1 CCACHE=1
+- set SRB2_MFLAGS=-C src MINGW=1 WARNINGMODE=1 GCC63=1 CCACHE=1 NOOBJDUMP=1
build_script:
- cmd: mingw32-make.exe %SRB2_MFLAGS% %CONFIGURATION%=1 clean
@@ -58,26 +58,29 @@ after_build:
- cmd: git rev-parse --short %APPVEYOR_REPO_COMMIT%>%TMP%/gitshort.txt
- cmd: set /P GITSHORT=<%TMP%/gitshort.txt
- set BUILD_ARCHIVE=%APPVEYOR_REPO_BRANCH%-%GITSHORT%-%CONFIGURATION%.7z
+- set BUILDSARCHIVE=%APPVEYOR_REPO_BRANCH%-%CONFIGURATION%.7z
- cmd: 7z a %BUILD_ARCHIVE% bin\Mingw\Release -xr!.gitignore
- appveyor PushArtifact %BUILD_ARCHIVE%
+- cmd: copy %BUILD_ARCHIVE% %BUILDSARCHIVE%
+- appveyor PushArtifact %BUILDSARCHIVE%
test: off
-deploy:
- - provider: FTP
- protocol: ftps
- host:
- secure: NsLJEPIBvmwCOj8Tg8RoRQ==
- username:
- secure: ejxi5mvk7oLYu7QtbYojajEPigMy0mokaKhuEVuDZcA=
- password:
- secure: Hbn6Uy3lT0YZ88yFJ3aW4w==
- folder: appveyor
- application:
- active_mode: false
- on:
- branch: master
- appveyor_repo_tag: true
+#deploy:
+# - provider: FTP
+# protocol: ftps
+# host:
+# secure: NsLJEPIBvmwCOj8Tg8RoRQ==
+# username:
+# secure: ejxi5mvk7oLYu7QtbYojajEPigMy0mokaKhuEVuDZcA=
+# password:
+# secure: Hbn6Uy3lT0YZ88yFJ3aW4w==
+# folder: appveyor
+# application:
+# active_mode: false
+# on:
+# branch: master
+# appveyor_repo_tag: true
on_finish:
diff --git a/bin/Mingw/Debug/.gitignore b/bin/Mingw/Debug/.gitignore
index e431dca5..834f313e 100644
--- a/bin/Mingw/Debug/.gitignore
+++ b/bin/Mingw/Debug/.gitignore
@@ -1,3 +1,3 @@
-/srb2sdl.exe
-/srb2win.exe
-/r_opengl.dll
+*.exe
+*.mo
+r_opengl.dll
diff --git a/bin/Mingw/Release/.gitignore b/bin/Mingw/Release/.gitignore
index e431dca5..834f313e 100644
--- a/bin/Mingw/Release/.gitignore
+++ b/bin/Mingw/Release/.gitignore
@@ -1,3 +1,3 @@
-/srb2sdl.exe
-/srb2win.exe
-/r_opengl.dll
+*.exe
+*.mo
+r_opengl.dll
diff --git a/debian/docs b/debian/docs
index f3d4ef20..b43bf86b 100644
--- a/debian/docs
+++ b/debian/docs
@@ -1,2 +1 @@
-readme.txt
-readme.txt
+README.md
diff --git a/objs/.gitignore b/objs/.gitignore
new file mode 100644
index 00000000..35ecd6de
--- /dev/null
+++ b/objs/.gitignore
@@ -0,0 +1,8 @@
+#All folders
+SRB2.res
+depend.dep
+depend.ped
+*.o
+#VC9 folder only
+/VC9/Win32
+/VC9/x64
diff --git a/objs/DC/SDL/Debug/.gitignore b/objs/DC/SDL/Debug/.gitignore
index 867fcb4e..42c6dc2c 100644
--- a/objs/DC/SDL/Debug/.gitignore
+++ b/objs/DC/SDL/Debug/.gitignore
@@ -1 +1,2 @@
-/depend.dep
+# DON'T REMOVE
+# This keeps the folder from disappearing
diff --git a/objs/DC/SDL/Release/.gitignore b/objs/DC/SDL/Release/.gitignore
index 867fcb4e..42c6dc2c 100644
--- a/objs/DC/SDL/Release/.gitignore
+++ b/objs/DC/SDL/Release/.gitignore
@@ -1 +1,2 @@
-/depend.dep
+# DON'T REMOVE
+# This keeps the folder from disappearing
diff --git a/objs/Linux/SDL/Debug/.gitignore b/objs/Linux/SDL/Debug/.gitignore
index 8f6d0bdc..42c6dc2c 100644
--- a/objs/Linux/SDL/Debug/.gitignore
+++ b/objs/Linux/SDL/Debug/.gitignore
@@ -1,2 +1,2 @@
-/depend.dep
-/*.o
+# DON'T REMOVE
+# This keeps the folder from disappearing
diff --git a/objs/Linux/SDL/Release/.gitignore b/objs/Linux/SDL/Release/.gitignore
index 8f6d0bdc..42c6dc2c 100644
--- a/objs/Linux/SDL/Release/.gitignore
+++ b/objs/Linux/SDL/Release/.gitignore
@@ -1,2 +1,2 @@
-/depend.dep
-/*.o
+# DON'T REMOVE
+# This keeps the folder from disappearing
diff --git a/objs/Linux64/SDL/Debug/.gitignore b/objs/Linux64/SDL/Debug/.gitignore
index 8f6d0bdc..42c6dc2c 100644
--- a/objs/Linux64/SDL/Debug/.gitignore
+++ b/objs/Linux64/SDL/Debug/.gitignore
@@ -1,2 +1,2 @@
-/depend.dep
-/*.o
+# DON'T REMOVE
+# This keeps the folder from disappearing
diff --git a/objs/Linux64/SDL/Release/.gitignore b/objs/Linux64/SDL/Release/.gitignore
index 8f6d0bdc..42c6dc2c 100644
--- a/objs/Linux64/SDL/Release/.gitignore
+++ b/objs/Linux64/SDL/Release/.gitignore
@@ -1,2 +1,2 @@
-/depend.dep
-/*.o
+# DON'T REMOVE
+# This keeps the folder from disappearing
diff --git a/objs/Mingw/Debug/.gitignore b/objs/Mingw/Debug/.gitignore
index da4b3e91..42c6dc2c 100644
--- a/objs/Mingw/Debug/.gitignore
+++ b/objs/Mingw/Debug/.gitignore
@@ -1,3 +1,2 @@
-/SRB2.res
-/depend.dep
-/*.o
+# DON'T REMOVE
+# This keeps the folder from disappearing
diff --git a/objs/Mingw/Release/.gitignore b/objs/Mingw/Release/.gitignore
index da4b3e91..42c6dc2c 100644
--- a/objs/Mingw/Release/.gitignore
+++ b/objs/Mingw/Release/.gitignore
@@ -1,3 +1,2 @@
-/SRB2.res
-/depend.dep
-/*.o
+# DON'T REMOVE
+# This keeps the folder from disappearing
diff --git a/objs/Mingw/SDL/Debug/.gitignore b/objs/Mingw/SDL/Debug/.gitignore
index da4b3e91..42c6dc2c 100644
--- a/objs/Mingw/SDL/Debug/.gitignore
+++ b/objs/Mingw/SDL/Debug/.gitignore
@@ -1,3 +1,2 @@
-/SRB2.res
-/depend.dep
-/*.o
+# DON'T REMOVE
+# This keeps the folder from disappearing
diff --git a/objs/Mingw/SDL/Release/.gitignore b/objs/Mingw/SDL/Release/.gitignore
index da4b3e91..42c6dc2c 100644
--- a/objs/Mingw/SDL/Release/.gitignore
+++ b/objs/Mingw/SDL/Release/.gitignore
@@ -1,3 +1,2 @@
-/SRB2.res
-/depend.dep
-/*.o
+# DON'T REMOVE
+# This keeps the folder from disappearing
diff --git a/objs/Mingw64/Debug/.gitignore b/objs/Mingw64/Debug/.gitignore
index da4b3e91..42c6dc2c 100644
--- a/objs/Mingw64/Debug/.gitignore
+++ b/objs/Mingw64/Debug/.gitignore
@@ -1,3 +1,2 @@
-/SRB2.res
-/depend.dep
-/*.o
+# DON'T REMOVE
+# This keeps the folder from disappearing
diff --git a/objs/Mingw64/Release/.gitignore b/objs/Mingw64/Release/.gitignore
index da4b3e91..42c6dc2c 100644
--- a/objs/Mingw64/Release/.gitignore
+++ b/objs/Mingw64/Release/.gitignore
@@ -1,3 +1,2 @@
-/SRB2.res
-/depend.dep
-/*.o
+# DON'T REMOVE
+# This keeps the folder from disappearing
diff --git a/objs/Mingw64/SDL/Debug/.gitignore b/objs/Mingw64/SDL/Debug/.gitignore
index da4b3e91..42c6dc2c 100644
--- a/objs/Mingw64/SDL/Debug/.gitignore
+++ b/objs/Mingw64/SDL/Debug/.gitignore
@@ -1,3 +1,2 @@
-/SRB2.res
-/depend.dep
-/*.o
+# DON'T REMOVE
+# This keeps the folder from disappearing
diff --git a/objs/Mingw64/SDL/Release/.gitignore b/objs/Mingw64/SDL/Release/.gitignore
index da4b3e91..42c6dc2c 100644
--- a/objs/Mingw64/SDL/Release/.gitignore
+++ b/objs/Mingw64/SDL/Release/.gitignore
@@ -1,3 +1,2 @@
-/SRB2.res
-/depend.dep
-/*.o
+# DON'T REMOVE
+# This keeps the folder from disappearing
diff --git a/objs/PS3/SDL/Debug/.gitignore b/objs/PS3/SDL/Debug/.gitignore
index 8f6d0bdc..42c6dc2c 100644
--- a/objs/PS3/SDL/Debug/.gitignore
+++ b/objs/PS3/SDL/Debug/.gitignore
@@ -1,2 +1,2 @@
-/depend.dep
-/*.o
+# DON'T REMOVE
+# This keeps the folder from disappearing
diff --git a/objs/PS3/SDL/Release/.gitignore b/objs/PS3/SDL/Release/.gitignore
index 8f6d0bdc..42c6dc2c 100644
--- a/objs/PS3/SDL/Release/.gitignore
+++ b/objs/PS3/SDL/Release/.gitignore
@@ -1,2 +1,2 @@
-/depend.dep
-/*.o
+# DON'T REMOVE
+# This keeps the folder from disappearing
diff --git a/objs/PSP/SDL/Release/.gitignore b/objs/PSP/SDL/Release/.gitignore
index 867fcb4e..42c6dc2c 100644
--- a/objs/PSP/SDL/Release/.gitignore
+++ b/objs/PSP/SDL/Release/.gitignore
@@ -1 +1,2 @@
-/depend.dep
+# DON'T REMOVE
+# This keeps the folder from disappearing
diff --git a/objs/SDL/Release/.gitignore b/objs/SDL/Release/.gitignore
index 4a262f94..42c6dc2c 100644
--- a/objs/SDL/Release/.gitignore
+++ b/objs/SDL/Release/.gitignore
@@ -1 +1,2 @@
-/depend.ped
+# DON'T REMOVE
+# This keeps the folder from disappearing
diff --git a/objs/VC/.gitignore b/objs/VC/.gitignore
index e69de29b..42c6dc2c 100644
--- a/objs/VC/.gitignore
+++ b/objs/VC/.gitignore
@@ -0,0 +1,2 @@
+# DON'T REMOVE
+# This keeps the folder from disappearing
diff --git a/objs/VC9/.gitignore b/objs/VC9/.gitignore
index 205fe45d..42c6dc2c 100644
--- a/objs/VC9/.gitignore
+++ b/objs/VC9/.gitignore
@@ -1,2 +1,2 @@
-/Win32
-/x64
+# DON'T REMOVE
+# This keeps the folder from disappearing
diff --git a/objs/Wii/SDL/Debug/.gitignore b/objs/Wii/SDL/Debug/.gitignore
index 8f6d0bdc..42c6dc2c 100644
--- a/objs/Wii/SDL/Debug/.gitignore
+++ b/objs/Wii/SDL/Debug/.gitignore
@@ -1,2 +1,2 @@
-/depend.dep
-/*.o
+# DON'T REMOVE
+# This keeps the folder from disappearing
diff --git a/objs/Wii/SDL/Release/.gitignore b/objs/Wii/SDL/Release/.gitignore
index 8f6d0bdc..42c6dc2c 100644
--- a/objs/Wii/SDL/Release/.gitignore
+++ b/objs/Wii/SDL/Release/.gitignore
@@ -1,2 +1,2 @@
-/depend.dep
-/*.o
+# DON'T REMOVE
+# This keeps the folder from disappearing
diff --git a/objs/WinCE/SDL/Release/.gitignore b/objs/WinCE/SDL/Release/.gitignore
index 867fcb4e..42c6dc2c 100644
--- a/objs/WinCE/SDL/Release/.gitignore
+++ b/objs/WinCE/SDL/Release/.gitignore
@@ -1 +1,2 @@
-/depend.dep
+# DON'T REMOVE
+# This keeps the folder from disappearing
diff --git a/objs/djgppdos/Debug/.gitignore b/objs/djgppdos/Debug/.gitignore
index 867fcb4e..42c6dc2c 100644
--- a/objs/djgppdos/Debug/.gitignore
+++ b/objs/djgppdos/Debug/.gitignore
@@ -1 +1,2 @@
-/depend.dep
+# DON'T REMOVE
+# This keeps the folder from disappearing
diff --git a/objs/djgppdos/Release/.gitignore b/objs/djgppdos/Release/.gitignore
index 867fcb4e..42c6dc2c 100644
--- a/objs/djgppdos/Release/.gitignore
+++ b/objs/djgppdos/Release/.gitignore
@@ -1 +1,2 @@
-/depend.dep
+# DON'T REMOVE
+# This keeps the folder from disappearing
diff --git a/objs/nds/Debug/.gitignore b/objs/nds/Debug/.gitignore
index 8f6d0bdc..42c6dc2c 100644
--- a/objs/nds/Debug/.gitignore
+++ b/objs/nds/Debug/.gitignore
@@ -1,2 +1,2 @@
-/depend.dep
-/*.o
+# DON'T REMOVE
+# This keeps the folder from disappearing
diff --git a/objs/nds/Release/.gitignore b/objs/nds/Release/.gitignore
index 8f6d0bdc..42c6dc2c 100644
--- a/objs/nds/Release/.gitignore
+++ b/objs/nds/Release/.gitignore
@@ -1,2 +1,2 @@
-/depend.dep
-/*.o
+# DON'T REMOVE
+# This keeps the folder from disappearing
diff --git a/readme.txt b/readme.txt
deleted file mode 100644
index c1898d49..00000000
--- a/readme.txt
+++ /dev/null
@@ -1,155 +0,0 @@
-Here it is! SRB2 v2.1.14 source code!
-(why do we keep the version number up to date
- when everything else in this file is hilariously old?
- - Inuyasha)
-
-
-Win32 with Visual C (6SP6+Processor Pack OR 7)
-~~~
-
-2 VC++ 6.0 project files are included:
-
-Win32/DirectX/FMOD
-src\win32\wLegacy.dsw
-You'll need FMOD to compile this version (www.fmod.org)
-or
-Win32/SDL/SDL_mixer
-src\sdl\Win32SDL.dsp
-You'll need SDL and SDL_mixer for this version (www.libsdl.org)
-
-Both needs NASM (http://sourceforge.net/projects/nasm)
-For PNG screenshot, libPNG, and Zlib (from http://gnuwin32.sourceforge.net/)
-
-No warranty, support, etc. of any kind is offered,
-just plain old as is.
-Some bits of code are still really scary.
-Go nuts!
-
-
-Win32 with Dev-C++ (http://bloodshed.net/ free!)
-~~~
-2 Dev-C++ project files are included:
-
-Win32/DirectX/FMOD
-src\win32\SRB2.dev
-or
-Win32/SDL/SDL_mixer
-src\sdl\Win32SDL.dev
-You'll need SDL and SDL_mixer for this version (www.libsdl.org)
-libPNG and Zlib (from http://gnuwin32.sourceforge.net/)
-Note there are precompiled libpng.a and libz.a for Mingw
-
-you will need NASM for both SDL/SDL_mixer and DirectX/FMOD
-and you need DirectX 6 (or up) Dev-Paks to compile DirectX version
-
-GNU/Linux
-~~~
-
-Dependencies:
- SDL 1.2.7 or better (from libsdl.org)
- SDL_Mixer 1.2.2(.7 for file-less music playback) (from libsdl.org)
- Nasm (use NOASM=1 if you don't have it or have an non-i386 system, I think)
- libPNG 1.2.7
- Zlib 1.2.3
- The Xiph.org libogg and libvorbis libraries
- The OpenGL headers (from Mesa, usually shipped with your X.org or XFree
- installation, so you needn't worry, most likely)
- GCC 3.x toolchain and binutils
- GNU Make
-
-Build instructions:
-
-make -C src LINUX=1
-
-Build instructions (64 bit):
-
-make -C src LINUX64=1
-
-Build instructions to build for Wii Linux/SRB2Wii on a PowerPC system,
-follow cross-compiling instructions for cross-compiling on a x86 system:
-
-make -C src LINUX=1 WIILINUX=1
-
-Build instructions to build for Pandora (Linux) on a ARM system,
-follow cross-compiling instructions for cross-compiling on a x86 system:
-
-make -C src PANDORA=1
-
-Solaris
-~~~
-
-Dependencies:
- SDL 1.2.5 or better (from libsdl.org)
- SDL_Mixer 1.2.2(.7 for file-less music playback) (from libsdl.org)
- libPNG 1.2.7
- Zlib 1.2.3
- The Xiph.org libogg and libvorbis libraries
- The OpenGL headers (from Mesa, usually shipped with your X.org or XFree
- installation, so you needn't worry, most likely)
- GCC 3.x toolchain and binutils
- GNU Make
-
- You can get all these programs/libraries from the Companion CD (except SDL_mixer and OpenGL)
-
-Build instructions:
-
-gmake -C src SOLARIS=1
-
-FreeBSD
-~~~
-
-Dependencies:
- SDL 1.2.7 or better (from libsdl.org)
- SDL_Mixer 1.2.2(.7 for file-less music playback) (from libsdl.org)
- Nasm (use NOASM=1 if you don't have it or have an non-i386 system, I think)
- libPNG 1.2.7
- Zlib 1.2.3
- The Xiph.org libogg and libvorbis libraries
- The OpenGL headers (from Mesa, usually shipped with your X.org or XFree
- installation, so you needn't worry, most likely)
- GCC 3.x toolchain and binutils
- GNU Make
-
-Build instructions:
-
-gmake -C src FREEBSD=1
-
-DJGPP/DOS
-~~~
-
-Dependencies:
- Allegro 3.12 game programming library, (from
- http://alleg.sourceforge.net/index.html)
- Nasm (use NOASM=1 if you don't have it)
- libsocket (from http://homepages.nildram.co.uk/~phekda/richdawe/lsck/) or
- Watt-32 (from http://www.bgnett.no/~giva/)
- GCC 3.x toolchain and binutils
- GNU Make
-
-Build instructions:
-
-make -C src # to link with Watt-32, add WATTCP=1
- # for remote debugging over the COM port, add RDB=1
-
-Notes:
- use tools\djgpp\all313.diff to update Allegro to a "more usable" version ;)
- Example: E:\djgpp\allegro>patch -p# < D:\SRB2Code\1.1\srb2\tools\djgpp\all313.diff
-
-Windows CE
-~~~
-
-Dependencies:
- SDL 1.27
-
-Build instructions:
-
-use src\SDL\WinCE\SRB2CE.vcw
-
--------------------------------------------------------------------------------
-
-binaries will turn in up in bin/
-
-note: read the src/makefile for more options
-
-- Sonic Team Junior
-http://www.srb2.org
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 035b4655..46a42a92 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -22,6 +22,7 @@ set(SRB2_CORE_SOURCES
i_tcp.c
info.c
lzf.c
+ m_aatree.c
m_anigif.c
m_argv.c
m_bbox.c
@@ -83,6 +84,7 @@ set(SRB2_CORE_HEADERS
info.h
keys.h
lzf.h
+ m_aatree.h
m_anigif.h
m_argv.h
m_bbox.h
@@ -388,18 +390,25 @@ if(${SRB2_CONFIG_HWRENDER} AND ${SRB2_CONFIG_STATIC_OPENGL})
endif()
if(${SRB2_CONFIG_USEASM})
+ #SRB2_ASM_FLAGS can be used to pass flags to either nasm or yasm.
+ if(${CMAKE_SYSTEM} MATCHES "Linux")
+ set(SRB2_ASM_FLAGS "-DLINUX ${SRB2_ASM_FLAGS}")
+ endif()
+
if(${SRB2_CONFIG_YASM})
set(CMAKE_ASM_YASM_SOURCE_FILE_EXTENSIONS ${CMAKE_ASM_YASM_SOURCE_FILE_EXTENSIONS} nas)
+ set(CMAKE_ASM_YASM_FLAGS "${SRB2_ASM_FLAGS}" CACHE STRING "Flags used by the assembler during all build types.")
enable_language(ASM_YASM)
else()
set(CMAKE_ASM_NASM_SOURCE_FILE_EXTENSIONS ${CMAKE_ASM_NASM_SOURCE_FILE_EXTENSIONS} nas)
+ set(CMAKE_ASM_NASM_FLAGS "${SRB2_ASM_FLAGS}" CACHE STRING "Flags used by the assembler during all build types.")
enable_language(ASM_NASM)
endif()
set(SRB2_USEASM ON)
add_definitions(-DUSEASM)
else()
set(SRB2_USEASM OFF)
- add_definitions(-DNOASM -DNONX86)
+ add_definitions(-DNONX86 -DNORUSEASM)
endif()
# Targets
diff --git a/src/Makefile b/src/Makefile
index f7a8c1b8..426dc228 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -179,6 +179,9 @@ endif
ifdef LINUX
UNIXCOMMON=1
+ifndef NOGME
+HAVE_LIBGME=1
+endif
endif
ifdef SOLARIS
@@ -189,6 +192,10 @@ ifdef FREEBSD
UNIXCOMMON=1
endif
+ifdef MACOSX
+UNIXCOMMON=1
+endif
+
ifdef NDS
NOPNG=1
NONET=1
@@ -311,6 +318,13 @@ LIBS+=$(PNG_LDFLAGS)
CFLAGS+=$(PNG_CFLAGS)
endif
+ZLIB_PKGCONFIG?=zlib
+ZLIB_CFLAGS?=$(shell $(PKG_CONFIG) $(ZLIB_PKGCONFIG) --cflags)
+ZLIB_LDFLAGS?=$(shell $(PKG_CONFIG) $(ZLIB_PKGCONFIG) --libs)
+
+LIBS+=$(ZLIB_LDFLAGS)
+CFLAGS+=$(ZLIB_CFLAGS)
+
ifdef HAVE_LIBGME
OPTS+=-DHAVE_LIBGME
@@ -362,6 +376,14 @@ endif
OPTS:=-fno-exceptions $(OPTS)
+ifdef MOBJCONSISTANCY
+ OPTS+=-DMOBJCONSISTANCY
+endif
+
+ifdef PACKETDROP
+ OPTS+=-DPACKETDROP
+endif
+
ifdef DEBUGMODE
# build with debugging information
@@ -371,7 +393,7 @@ ifdef GCC48
else
CFLAGS+=-O0
endif
- CFLAGS+= -Wall -DPARANOIA -DRANGECHECK
+ CFLAGS+= -Wall -DPARANOIA -DRANGECHECK -DPACKETDROP -DMOBJCONSISTANCY
else
@@ -429,6 +451,7 @@ OBJS:=$(i_main_o) \
$(OBJDIR)/hu_stuff.o \
$(OBJDIR)/y_inter.o \
$(OBJDIR)/st_stuff.o \
+ $(OBJDIR)/m_aatree.o \
$(OBJDIR)/m_anigif.o \
$(OBJDIR)/m_argv.o \
$(OBJDIR)/m_bbox.o \
@@ -488,13 +511,11 @@ OBJS:=$(i_main_o) \
# For reference, this is the command I use to build a srb2.pot file from the source code.
# (The listed source files are the ones containing translated strings).
# FILES=""; for file in `find ./ | grep "\.c" | grep -v svn`; do [ "`grep "M_GetText(" $file`" ] && FILES="$FILES $file"; done; xgettext -d srb2 -o locale/srb2.pot -kM_GetText -F --no-wrap $FILES
-ifndef NOGETTEXT
ifdef GETTEXT
POS:=$(BIN)/en.mo
OPTS+=-DGETTEXT
endif
-endif
ifdef DJGPPDOS
all: pre-build $(BIN)/$(EXENAME)
@@ -593,11 +614,15 @@ ifndef WINDOWSHELL
-$(GZIP) $(GZIP_OPT2) $(BIN)/$(DBGNAME).txt
endif
endif
+
+# mac os x lsdlsrb2 does not like objcopy
+ifndef MACOSX
ifndef PSP
$(OBJCOPY) $(BIN)/$(EXENAME) $(BIN)/$(DBGNAME)
$(OBJCOPY) --strip-debug $(BIN)/$(EXENAME)
-$(OBJCOPY) --add-gnu-debuglink=$(BIN)/$(DBGNAME) $(BIN)/$(EXENAME)
endif
+endif
ifndef NOUPX
-$(UPX) $(UPX_OPTS) $(BIN)/$(EXENAME)
endif
@@ -745,6 +770,11 @@ $(OBJDIR)/%.o: %.c
$(OBJDIR)/%.o: $(INTERFACE)/%.c
$(CC) $(CFLAGS) $(WFLAGS) -c $< -o $@
+ifdef MACOSX
+$(OBJDIR)/%.o: sdl/macosx/%.c
+ $(CC) $(CFLAGS) $(WFLAGS) -c $< -o $@
+endif
+
$(OBJDIR)/%.o: hardware/%.c
$(CC) $(CFLAGS) $(WFLAGS) -c $< -o $@
diff --git a/src/Makefile.cfg b/src/Makefile.cfg
index 347efa5e..5bf7f247 100644
--- a/src/Makefile.cfg
+++ b/src/Makefile.cfg
@@ -7,6 +7,23 @@
# and other things
#
+
+ifdef GCC63
+GCC62=1
+endif
+
+ifdef GCC62
+GCC61=1
+endif
+
+ifdef GCC61
+GCC54=1
+endif
+
+ifdef GCC54
+GCC53=1
+endif
+
ifdef GCC53
GCC52=1
endif
@@ -164,19 +181,29 @@ ifdef GCC45
WFLAGS+=-Wunsuffixed-float-constants
endif
endif
+
ifdef NOLDWARNING
LDFLAGS+=-Wl,--as-needed
endif
+
ifdef ERRORMODE
WFLAGS+=-Werror
endif
+
+WFLAGS+=$(OLDWFLAGS)
+
ifdef GCC43
#WFLAGS+=-Wno-error=clobbered
endif
ifdef GCC46
WFLAGS+=-Wno-error=suggest-attribute=noreturn
endif
-WFLAGS+=$(OLDWFLAGS)
+ifdef GCC54
+ WFLAGS+=-Wno-logical-op -Wno-error=logical-op
+endif
+ifdef GCC61
+ WFLAGS+=-Wno-tautological-compare -Wno-error=tautological-compare
+endif
#indicate platform and what interface use with
@@ -256,9 +283,6 @@ else
ifdef LINUX
NASMFORMAT=elf -DLINUX
SDL=1
-ifndef NOGETTEXT
- GETTEXT=1
-endif
ifdef LINUX64
OBJDIR:=$(OBJDIR)/Linux64
BIN:=$(BIN)/Linux64
@@ -294,9 +318,6 @@ else
ifdef MINGW64
INTERFACE=win32
#NASMFORMAT=win64
-ifndef NOGETTEXT
- #GETTEXT=1
-endif
OBJDIR:=$(OBJDIR)/Mingw64
BIN:=$(BIN)/Mingw64
else
@@ -327,9 +348,6 @@ else
ifdef MINGW
INTERFACE=win32
NASMFORMAT=win32
-ifndef NOGETTEXT
- GETTEXT=1
-endif
OBJDIR:=$(OBJDIR)/Mingw
BIN:=$(BIN)/Mingw
else
@@ -406,6 +424,15 @@ else
WINDRES=windres
endif
+# because Apple screws with us on this
+# need to get bintools from homebrew
+ifdef MACOSX
+ CC=clang
+ CXX=clang
+ OBJCOPY=gobjcopy
+ OBJDUMP=gobjdump
+endif
+
OBJDUMP_OPTS?=--wide --source --line-numbers
LD=$(CC)
diff --git a/src/android/i_system.c b/src/android/i_system.c
index 150cbd50..58fca7c1 100644
--- a/src/android/i_system.c
+++ b/src/android/i_system.c
@@ -258,6 +258,18 @@ INT32 I_PutEnv(char *variable)
return -1;
}
+INT32 I_ClipboardCopy(const char *data, size_t size)
+{
+ (void)data;
+ (void)size;
+ return -1;
+}
+
+char *I_ClipboardPaste(void)
+{
+ return NULL;
+}
+
void I_RegisterSysCommands(void) {}
#include "../sdl/dosstr.c"
diff --git a/src/blua/lvm.c b/src/blua/lvm.c
index a921d443..b654613f 100644
--- a/src/blua/lvm.c
+++ b/src/blua/lvm.c
@@ -732,7 +732,8 @@ void luaV_execute (lua_State *L, int nexeccalls) {
luaG_runerror(L, LUA_QL("for") " limit must be a number");
else if (!tonumber(pstep, ra+2))
luaG_runerror(L, LUA_QL("for") " step must be a number");
- setnvalue(ra, luai_numsub(nvalue(ra), nvalue(pstep)));
+ if (ra && pstep)
+ setnvalue(ra, luai_numsub(nvalue(ra), nvalue(pstep)));
dojump(L, pc, GETARG_sBx(i));
continue;
}
diff --git a/src/command.c b/src/command.c
index 84d777ac..a15471c8 100644
--- a/src/command.c
+++ b/src/command.c
@@ -966,9 +966,11 @@ void CV_RegisterVar(consvar_t *variable)
// check net variables
if (variable->flags & CV_NETVAR)
{
+ const consvar_t *netvar;
variable->netid = CV_ComputeNetid(variable->name);
- if (CV_FindNetVar(variable->netid))
- I_Error("Variables %s and %s have same netid\n", variable->name, CV_FindNetVar(variable->netid)->name);
+ netvar = CV_FindNetVar(variable->netid);
+ if (netvar)
+ I_Error("Variables %s and %s have same netid\n", variable->name, netvar->name);
}
// link the variable in
diff --git a/src/console.c b/src/console.c
index 025bc1c1..70f8ab6f 100644
--- a/src/console.c
+++ b/src/console.c
@@ -84,19 +84,23 @@ UINT32 con_scalefactor; // text size scale factor
// hold 32 last lines of input for history
#define CON_MAXPROMPTCHARS 256
-#define CON_PROMPTCHAR '>'
+#define CON_PROMPTCHAR '$'
static char inputlines[32][CON_MAXPROMPTCHARS]; // hold last 32 prompt lines
static INT32 inputline; // current input line number
static INT32 inputhist; // line number of history input line to restore
-static size_t input_cx; // position in current input line
+static size_t input_cur; // position of cursor in line
+static size_t input_sel; // position of selection marker (I.E.: anything between this and input_cur is "selected")
+static size_t input_len; // length of current line, used to bound cursor and such
+// notice: input does NOT include the "$" at the start of the line. - 11/3/16
// protos.
static void CON_InputInit(void);
static void CON_RecalcSize(void);
static void CONS_hudlines_Change(void);
+static void CONS_backcolor_Change(void);
static void CON_DrawBackpic(patch_t *pic, INT32 startx, INT32 destwidth);
//static void CON_DrawBackpic2(pic_t *pic, INT32 startx, INT32 destwidth);
@@ -129,10 +133,11 @@ static CV_PossibleValue_t backpic_cons_t[] = {{0, "translucent"}, {1, "picture"}
// whether to use console background picture, or translucent mode
static consvar_t cons_backpic = {"con_backpic", "translucent", CV_SAVE, backpic_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
-static CV_PossibleValue_t backcolor_cons_t[] = {{0, "White"}, {1, "Orange"},
- {2, "Blue"}, {3, "Green"}, {4, "Gray"},
- {5, "Red"}, {0, NULL}};
-consvar_t cons_backcolor = {"con_backcolor", "3", CV_SAVE, backcolor_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
+static CV_PossibleValue_t backcolor_cons_t[] = {{0, "White"}, {1, "Gray"}, {2, "Brown"},
+ {3, "Red"}, {4, "Orange"}, {5, "Yellow"},
+ {6, "Green"}, {7, "Blue"}, {8, "Cyan"},
+ {0, NULL}};
+consvar_t cons_backcolor = {"con_backcolor", "Green", CV_CALL|CV_SAVE, backcolor_cons_t, CONS_backcolor_Change, 0, NULL, NULL, 0, 0, NULL};
static void CON_Print(char *msg);
@@ -219,8 +224,9 @@ static void CONS_Bind_f(void)
// CONSOLE SETUP
//======================================================================
-// Prepare a colormap for GREEN ONLY translucency over background
-//
+// Font colormap colors
+// TODO: This could probably be improved somehow...
+// These colormaps are 99% identical, with just a few changed bytes
UINT8 *yellowmap;
UINT8 *purplemap;
UINT8 *lgreenmap;
@@ -229,44 +235,49 @@ UINT8 *graymap;
UINT8 *redmap;
UINT8 *orangemap;
-// Console BG colors
-UINT8 *cwhitemap;
-UINT8 *corangemap;
-UINT8 *cbluemap;
-UINT8 *cgreenmap;
-UINT8 *cgraymap;
-UINT8 *credmap;
+// Console BG color
+UINT8 *consolebgmap = NULL;
-void CON_ReSetupBackColormap(UINT16 num)
+void CON_SetupBackColormap(void)
{
- UINT16 i, j;
- UINT8 k;
- UINT8 *pal = W_CacheLumpName(R_GetPalname(num), PU_CACHE);
+ UINT16 i, palsum;
+ UINT8 j, palindex;
+ UINT8 *pal = W_CacheLumpName(GetPalette(), PU_CACHE);
- // setup the green translucent background colormaps
- for (i = 0, k = 0; i < 768; i += 3, k++)
+ if (!consolebgmap)
+ consolebgmap = (UINT8 *)Z_Malloc(256, PU_STATIC, NULL);
+
+ switch (cons_backcolor.value)
{
- j = pal[i] + pal[i+1] + pal[i+2];
- cwhitemap[k] = (UINT8)(15 - (j>>6));
- corangemap[k] = (UINT8)(95 - (j>>6));
- cbluemap[k] = (UINT8)(239 - (j>>6));
- cgreenmap[k] = (UINT8)(175 - (j>>6));
- cgraymap[k] = (UINT8)(31 - (j>>6));
- credmap[k] = (UINT8)(143 - (j>>6));
+ case 0: palindex = 15; break; // White
+ case 1: palindex = 31; break; // Gray
+ case 2: palindex = 63; break; // Brown
+ case 3: palindex = 143; break; // Red
+ case 4: palindex = 95; break; // Orange
+ case 5: palindex = 111; break; // Yellow
+ case 6: palindex = 175; break; // Green
+ case 7: palindex = 239; break; // Blue
+ case 8: palindex = 219; break; // Cyan
+ // Default green
+ default: palindex = 175; break;
+}
+
+ // setup background colormap
+ for (i = 0, j = 0; i < 768; i += 3, j++)
+ {
+ palsum = (pal[i] + pal[i+1] + pal[i+2]) >> 6;
+ consolebgmap[j] = (UINT8)(palindex - palsum);
}
}
-static void CON_SetupBackColormap(void)
+static void CONS_backcolor_Change(void)
{
- INT32 i, j, k;
- UINT8 *pal;
+ CON_SetupBackColormap();
+}
- cwhitemap = (UINT8 *)Z_Malloc(256, PU_STATIC, NULL);
- corangemap = (UINT8 *)Z_Malloc(256, PU_STATIC, NULL);
- cbluemap = (UINT8 *)Z_Malloc(256, PU_STATIC, NULL);
- cgreenmap = (UINT8 *)Z_Malloc(256, PU_STATIC, NULL);
- cgraymap = (UINT8 *)Z_Malloc(256, PU_STATIC, NULL);
- credmap = (UINT8 *)Z_Malloc(256, PU_STATIC, NULL);
+static void CON_SetupColormaps(void)
+{
+ INT32 i;
yellowmap = (UINT8 *)Z_Malloc(256, PU_STATIC, NULL);
graymap = (UINT8 *)Z_Malloc(256, PU_STATIC, NULL);
@@ -276,20 +287,6 @@ static void CON_SetupBackColormap(void)
redmap = (UINT8 *)Z_Malloc(256, PU_STATIC, NULL);
orangemap = (UINT8 *)Z_Malloc(256, PU_STATIC, NULL);
- pal = W_CacheLumpName("PLAYPAL", PU_CACHE);
-
- // setup the green translucent background colormaps
- for (i = 0, k = 0; i < 768; i += 3, k++)
- {
- j = pal[i] + pal[i+1] + pal[i+2];
- cwhitemap[k] = (UINT8)(15 - (j>>6));
- corangemap[k] = (UINT8)(95 - (j>>6));
- cbluemap[k] = (UINT8)(239 - (j>>6));
- cgreenmap[k] = (UINT8)(175 - (j>>6));
- cgraymap[k] = (UINT8)(31 - (j>>6));
- credmap[k] = (UINT8)(143 - (j>>6));
- }
-
// setup the other colormaps, for console text
// these don't need to be aligned, unless you convert the
@@ -320,6 +317,9 @@ static void CON_SetupBackColormap(void)
redmap[9] = (UINT8)127;
orangemap[3] = (UINT8)85;
orangemap[9] = (UINT8)90;
+
+ // Init back colormap
+ CON_SetupBackColormap();
}
// Setup the console text buffer
@@ -343,7 +343,7 @@ void CON_Init(void)
con_width = 0;
CON_RecalcSize();
- CON_SetupBackColormap();
+ CON_SetupColormaps();
//note: CON_Ticker should always execute at least once before D_Display()
con_clipviewtop = -1; // -1 does not clip
@@ -386,14 +386,10 @@ void CON_Init(void)
//
static void CON_InputInit(void)
{
- INT32 i;
-
// prepare the first prompt line
memset(inputlines, 0, sizeof (inputlines));
- for (i = 0; i < 32; i++)
- inputlines[i][0] = CON_PROMPTCHAR;
inputline = 0;
- input_cx = 1;
+ input_cur = input_sel = input_len = 0;
}
//======================================================================
@@ -618,13 +614,91 @@ void CON_Ticker(void)
}
}
+//
+// ----
+//
+// Shortcuts for adding and deleting characters, strings, and sections
+// Necessary due to moving cursor
+//
+
+static void CON_InputClear(void)
+{
+ memset(inputlines[inputline], 0, CON_MAXPROMPTCHARS);
+ input_cur = input_sel = input_len = 0;
+}
+
+static void CON_InputSetString(const char *c)
+{
+ memset(inputlines[inputline], 0, CON_MAXPROMPTCHARS);
+ strcpy(inputlines[inputline], c);
+ input_cur = input_sel = input_len = strlen(c);
+}
+
+static void CON_InputAddString(const char *c)
+{
+ size_t csize = strlen(c);
+ if (input_len + csize > CON_MAXPROMPTCHARS-1)
+ return;
+ if (input_cur != input_len)
+ memmove(&inputlines[inputline][input_cur+csize], &inputlines[inputline][input_cur], input_len-input_cur);
+ memcpy(&inputlines[inputline][input_cur], c, csize);
+ input_len += csize;
+ input_sel = (input_cur += csize);
+}
+
+static void CON_InputDelSelection(void)
+{
+ size_t start, end, len;
+ if (input_cur > input_sel)
+ {
+ start = input_sel;
+ end = input_cur;
+ }
+ else
+ {
+ start = input_cur;
+ end = input_sel;
+ }
+ len = (end - start);
+
+ if (end != input_len)
+ memmove(&inputlines[inputline][start], &inputlines[inputline][end], input_len-end);
+ memset(&inputlines[inputline][input_len - len], 0, len);
+
+ input_len -= len;
+ input_sel = input_cur = start;
+}
+
+static void CON_InputAddChar(char c)
+{
+ if (input_len >= CON_MAXPROMPTCHARS-1)
+ return;
+ if (input_cur != input_len)
+ memmove(&inputlines[inputline][input_cur+1], &inputlines[inputline][input_cur], input_len-input_cur);
+ inputlines[inputline][input_cur++] = c;
+ inputlines[inputline][++input_len] = 0;
+ input_sel = input_cur;
+}
+
+static void CON_InputDelChar(void)
+{
+ if (!input_cur)
+ return;
+ if (input_cur != input_len)
+ memmove(&inputlines[inputline][input_cur-1], &inputlines[inputline][input_cur], input_len-input_cur);
+ inputlines[inputline][--input_len] = 0;
+ input_sel = --input_cur;
+}
+
+//
+// ----
+//
+
// Handles console key input
//
boolean CON_Responder(event_t *ev)
{
- static boolean consdown;
- static boolean shiftdown;
- static boolean ctrldown;
+ static UINT8 consdown = false; // console is treated differently due to rare usage
// sequential completions a la 4dos
static char completion[80];
@@ -639,13 +713,8 @@ boolean CON_Responder(event_t *ev)
// let go keyup events, don't eat them
if (ev->type != ev_keydown && ev->type != ev_console)
{
- if (ev->data1 == KEY_LSHIFT || ev->data1 == KEY_RSHIFT)
- shiftdown = false;
- else if (ev->data1 == KEY_LCTRL || ev->data1 == KEY_RCTRL)
- ctrldown = false;
- else if (ev->data1 == gamecontrol[gc_console][0] || ev->data1 == gamecontrol[gc_console][1])
+ if (ev->data1 == gamecontrol[gc_console][0] || ev->data1 == gamecontrol[gc_console][1])
consdown = false;
-
return false;
}
@@ -684,94 +753,110 @@ boolean CON_Responder(event_t *ev)
consoletoggle = true;
return true;
}
-
}
- // eat shift only if console active
- if (key == KEY_LSHIFT || key == KEY_RSHIFT)
- {
- shiftdown = true;
+ // Always eat ctrl/shift/alt if console open, so the menu doesn't get ideas
+ if (key == KEY_LSHIFT || key == KEY_RSHIFT
+ || key == KEY_LCTRL || key == KEY_RCTRL
+ || key == KEY_LALT || key == KEY_RALT)
return true;
- }
- // same for ctrl
- if (key == KEY_LCTRL || key == KEY_RCTRL)
+ // ctrl modifier -- changes behavior, adds shortcuts
+ if (ctrldown)
{
- ctrldown = true;
- return true;
+ // show all cvars/commands that match what we have inputted
+ if (key == KEY_TAB)
+ {
+ size_t i, len;
+
+ if (!completion[0])
+ {
+ if (!input_len || input_len >= 40 || strchr(inputlines[inputline], ' '))
+ return true;
+ strcpy(completion, inputlines[inputline]);
+ comskips = varskips = 0;
+ }
+ len = strlen(completion);
+
+ //first check commands
+ CONS_Printf("\nCommands:\n");
+ for (i = 0, cmd = COM_CompleteCommand(completion, i); cmd; cmd = COM_CompleteCommand(completion, ++i))
+ CONS_Printf(" \x83" "%s" "\x80" "%s\n", completion, cmd+len);
+ if (i == 0) CONS_Printf(" (none)\n");
+
+ //now we move on to CVARs
+ CONS_Printf("Variables:\n");
+ for (i = 0, cmd = CV_CompleteVar(completion, i); cmd; cmd = CV_CompleteVar(completion, ++i))
+ CONS_Printf(" \x83" "%s" "\x80" "%s\n", completion, cmd+len);
+ if (i == 0) CONS_Printf(" (none)\n");
+
+ return true;
+ }
+ // ---
+
+ if (key == KEY_HOME) // oldest text in buffer
+ {
+ con_scrollup = (con_totallines-((con_curlines-16)>>3));
+ return true;
+ }
+ else if (key == KEY_END) // most recent text in buffer
+ {
+ con_scrollup = 0;
+ return true;
+ }
+
+ if (key == 'x' || key == 'X')
+ {
+ if (input_sel > input_cur)
+ I_ClipboardCopy(&inputlines[inputline][input_cur], input_sel-input_cur);
+ else
+ I_ClipboardCopy(&inputlines[inputline][input_sel], input_cur-input_sel);
+ CON_InputDelSelection();
+ completion[0] = 0;
+ return true;
+ }
+ else if (key == 'c' || key == 'C')
+ {
+ if (input_sel > input_cur)
+ I_ClipboardCopy(&inputlines[inputline][input_cur], input_sel-input_cur);
+ else
+ I_ClipboardCopy(&inputlines[inputline][input_sel], input_cur-input_sel);
+ return true;
+ }
+ else if (key == 'v' || key == 'V')
+ {
+ const char *paste = I_ClipboardPaste();
+ if (input_sel != input_cur)
+ CON_InputDelSelection();
+ if (paste != NULL)
+ CON_InputAddString(paste);
+ completion[0] = 0;
+ return true;
+ }
+
+ // Select all
+ if (key == 'a' || key == 'A')
+ {
+ input_sel = 0;
+ input_cur = input_len;
+ return true;
+ }
+
+ // don't eat the key
+ return false;
}
// command completion forward (tab) and backward (shift-tab)
if (key == KEY_TAB)
{
- // show all cvars/commands that match what we have inputted
- if (ctrldown)
- {
- UINT32 i;
- size_t stop = input_cx - 1;
- char nameremainder[255];
-
- if (input_cx < 2 || strlen(inputlines[inputline]+1) >= 80)
- return true;
-
- strcpy(completion, inputlines[inputline]+1);
-
- // trimming: stop at the first newline
- for (i = 0; i < input_cx - 1; ++i)
- {
- if (completion[i] == ' ')
- {
- completion[i] = '\0';
- stop = i;
- break;
- }
- }
-
- i = 0;
-
- //first check commands
- CONS_Printf("\nCommands:\n");
-
- for (cmd = COM_CompleteCommand(completion, i); cmd; cmd = COM_CompleteCommand(completion, i))
- {
- strncpy(nameremainder, cmd+(stop), strlen(cmd)-(stop));
- nameremainder[strlen(cmd)-(stop)] = '\0';
-
- CONS_Printf(" \x83" "%s" "\x80" "%s\n", completion, nameremainder);
- ++i;
- }
- if (i == 0)
- CONS_Printf(" (none)\n");
-
- i = 0;
-
- //now we move on to CVARs
- CONS_Printf("Variables:\n");
-
- for (cmd = CV_CompleteVar(completion, i); cmd; cmd = CV_CompleteVar(completion, i))
- {
- strncpy(nameremainder, cmd+(stop), strlen(cmd)-(stop));
- nameremainder[strlen(cmd)-(stop)] = '\0';
-
- CONS_Printf(" \x83" "%s" "\x80" "%s\n", completion, nameremainder);
- ++i;
- }
- if (i == 0)
- CONS_Printf(" (none)\n");
-
- return true;
- }
-
// sequential command completion forward and backward
// remember typing for several completions (a-la-4dos)
- if (inputlines[inputline][input_cx-1] != ' ')
+ if (!completion[0])
{
- if (strlen(inputlines[inputline]+1) < 80)
- strcpy(completion, inputlines[inputline]+1);
- else
- completion[0] = 0;
-
+ if (!input_len || input_len >= 40 || strchr(inputlines[inputline], ' '))
+ return true;
+ strcpy(completion, inputlines[inputline]);
comskips = varskips = 0;
}
else
@@ -783,37 +868,26 @@ boolean CON_Responder(event_t *ev)
if (--varskips < 0)
comskips = -comskips - 2;
}
- else if (comskips > 0)
- comskips--;
+ else if (comskips > 0) comskips--;
}
else
{
- if (comskips < 0)
- varskips++;
- else
- comskips++;
+ if (comskips < 0) varskips++;
+ else comskips++;
}
}
if (comskips >= 0)
{
cmd = COM_CompleteCommand(completion, comskips);
- if (!cmd)
- // dirty: make sure if comskips is zero, to have a neg value
+ if (!cmd) // dirty: make sure if comskips is zero, to have a neg value
comskips = -comskips - 1;
}
if (comskips < 0)
cmd = CV_CompleteVar(completion, varskips);
if (cmd)
- {
- memset(inputlines[inputline]+1, 0, CON_MAXPROMPTCHARS-1);
- strcpy(inputlines[inputline]+1, cmd);
- input_cx = strlen(cmd) + 1;
- inputlines[inputline][input_cx] = ' ';
- input_cx++;
- inputlines[inputline][input_cx] = 0;
- }
+ CON_InputSetString(va("%s ", cmd));
else
{
if (comskips > 0)
@@ -839,47 +913,80 @@ boolean CON_Responder(event_t *ev)
return true;
}
- if (key == KEY_HOME) // oldest text in buffer
+ if (key == KEY_LEFTARROW)
{
- con_scrollup = (con_totallines-((con_curlines-16)>>3));
+ if (input_cur != 0)
+ --input_cur;
+ if (!shiftdown)
+ input_sel = input_cur;
return true;
}
- else if (key == KEY_END) // most recent text in buffer
+ else if (key == KEY_RIGHTARROW)
{
- con_scrollup = 0;
+ if (input_cur < input_len)
+ ++input_cur;
+ if (!shiftdown)
+ input_sel = input_cur;
return true;
}
+ else if (key == KEY_HOME)
+ {
+ input_cur = 0;
+ if (!shiftdown)
+ input_sel = input_cur;
+ return true;
+ }
+ else if (key == KEY_END)
+ {
+ input_cur = input_len;
+ if (!shiftdown)
+ input_sel = input_cur;
+ return true;
+ }
+
+ // At this point we're messing with input
+ // Clear completion
+ completion[0] = 0;
// command enter
if (key == KEY_ENTER)
{
- if (input_cx < 2)
+ if (!input_len)
return true;
// push the command
- COM_BufAddText(inputlines[inputline]+1);
+ COM_BufAddText(inputlines[inputline]);
COM_BufAddText("\n");
- CONS_Printf("%s\n", inputlines[inputline]);
+ CONS_Printf("\x86""%c""\x80""%s\n", CON_PROMPTCHAR, inputlines[inputline]);
inputline = (inputline+1) & 31;
inputhist = inputline;
-
- memset(inputlines[inputline], 0, CON_MAXPROMPTCHARS);
- inputlines[inputline][0] = CON_PROMPTCHAR;
- input_cx = 1;
+ CON_InputClear();
return true;
}
- // backspace command prompt
- if (key == KEY_BACKSPACE)
+ // backspace and delete command prompt
+ if (input_sel != input_cur)
{
- if (input_cx > 1)
+ if (key == KEY_BACKSPACE || key == KEY_DEL)
{
- input_cx--;
- inputlines[inputline][input_cx] = 0;
+ CON_InputDelSelection();
+ return true;
}
+ }
+ else if (key == KEY_BACKSPACE)
+ {
+ CON_InputDelChar();
+ return true;
+ }
+ else if (key == KEY_DEL)
+ {
+ if (input_cur == input_len)
+ return true;
+ ++input_cur;
+ CON_InputDelChar();
return true;
}
@@ -888,18 +995,15 @@ boolean CON_Responder(event_t *ev)
{
// copy one of the previous inputlines to the current
do
- {
inputhist = (inputhist - 1) & 31; // cycle back
- } while (inputhist != inputline && !inputlines[inputhist][1]);
+ while (inputhist != inputline && !inputlines[inputhist][0]);
// stop at the last history input line, which is the
// current line + 1 because we cycle through the 32 input lines
if (inputhist == inputline)
inputhist = (inputline + 1) & 31;
- M_Memcpy(inputlines[inputline], inputlines[inputhist], CON_MAXPROMPTCHARS);
- input_cx = strlen(inputlines[inputline]);
-
+ CON_InputSetString(inputlines[inputhist]);
return true;
}
@@ -909,23 +1013,14 @@ boolean CON_Responder(event_t *ev)
if (inputhist == inputline)
return true;
do
- {
inputhist = (inputhist + 1) & 31;
- } while (inputhist != inputline && !inputlines[inputhist][1]);
-
- memset(inputlines[inputline], 0, CON_MAXPROMPTCHARS);
+ while (inputhist != inputline && !inputlines[inputhist][0]);
// back to currentline
if (inputhist == inputline)
- {
- inputlines[inputline][0] = CON_PROMPTCHAR;
- input_cx = 1;
- }
+ CON_InputClear();
else
- {
- strcpy(inputlines[inputline], inputlines[inputhist]);
- input_cx = strlen(inputlines[inputline]);
- }
+ CON_InputSetString(inputlines[inputhist]);
return true;
}
@@ -950,15 +1045,12 @@ boolean CON_Responder(event_t *ev)
return false;
// add key to cmd line here
- if (input_cx < CON_MAXPROMPTCHARS)
- {
- if (key >= 'A' && key <= 'Z' && !shiftdown) //this is only really necessary for dedicated servers
- key = key + 'a' - 'A';
+ if (key >= 'A' && key <= 'Z' && !shiftdown) //this is only really necessary for dedicated servers
+ key = key + 'a' - 'A';
- inputlines[inputline][input_cx] = (char)key;
- inputlines[inputline][input_cx + 1] = 0;
- input_cx++;
- }
+ if (input_sel != input_cur)
+ CON_InputDelSelection();
+ CON_InputAddChar(key);
return true;
}
@@ -1242,26 +1334,89 @@ void CONS_Error(const char *msg)
//
static void CON_DrawInput(void)
{
- char *p;
- size_t c;
- INT32 x, y;
INT32 charwidth = (INT32)con_scalefactor << 3;
-
- // input line scrolls left if it gets too long
- p = inputlines[inputline];
- if (input_cx >= con_width-11)
- p += input_cx - (con_width-11) + 1;
+ const char *p = inputlines[inputline];
+ size_t c, clen, cend;
+ UINT8 lellip = 0, rellip = 0;
+ INT32 x, y, i;
y = con_curlines - 12 * con_scalefactor;
+ x = charwidth*2;
- for (c = 0, x = charwidth; c < con_width-11; c++, x += charwidth)
- V_DrawCharacter(x, y, p[c] | cv_constextsize.value | V_NOSCALESTART, !cv_allcaps.value);
+ clen = con_width-13;
- // draw the blinking cursor
- //
- x = ((input_cx >= con_width-11) ? (INT32)(con_width-11) : (INT32)((input_cx + 1)) * charwidth);
- if (con_tick < 4)
- V_DrawCharacter(x, y, '_' | cv_constextsize.value | V_NOSCALESTART, !cv_allcaps.value);
+ if (input_len <= clen)
+ {
+ c = 0;
+ clen = input_len;
+ }
+ else // input line scrolls left if it gets too long
+ {
+ clen -= 2; // There will always be some extra truncation -- but where is what we'll find out
+
+ if (input_cur <= clen/2)
+ {
+ // Close enough to right edge to show all
+ c = 0;
+ // Always will truncate right side from this position, so always draw right ellipsis
+ rellip = 1;
+ }
+ else
+ {
+ // Cursor in the middle (or right side) of input
+ // Move over for the ellipsis
+ c = input_cur - (clen/2) + 2;
+ x += charwidth*2;
+ lellip = 1;
+
+ if (c + clen >= input_len)
+ {
+ // Cursor in the right side of input
+ // We were too far over, so move back
+ c = input_len - clen;
+ }
+ else
+ {
+ // Cursor in the middle -- ellipses on both sides
+ clen -= 2;
+ rellip = 1;
+ }
+ }
+ }
+
+ if (lellip)
+ {
+ x -= charwidth*3;
+ if (input_sel < c)
+ V_DrawFill(x, y, charwidth*3, (10 * con_scalefactor), 107 | V_NOSCALESTART);
+ for (i = 0; i < 3; ++i, x += charwidth)
+ V_DrawCharacter(x, y, '.' | cv_constextsize.value | V_GRAYMAP | V_NOSCALESTART, !cv_allcaps.value);
+ }
+ else
+ V_DrawCharacter(x-charwidth, y, CON_PROMPTCHAR | cv_constextsize.value | V_GRAYMAP | V_NOSCALESTART, !cv_allcaps.value);
+
+ for (cend = c + clen; c < cend; ++c, x += charwidth)
+ {
+ if ((input_sel > c && input_cur <= c) || (input_sel <= c && input_cur > c))
+ {
+ V_DrawFill(x, y, charwidth, (10 * con_scalefactor), 107 | V_NOSCALESTART);
+ V_DrawCharacter(x, y, p[c] | cv_constextsize.value | V_YELLOWMAP | V_NOSCALESTART, !cv_allcaps.value);
+ }
+ else
+ V_DrawCharacter(x, y, p[c] | cv_constextsize.value | V_NOSCALESTART, !cv_allcaps.value);
+
+ if (c == input_cur && con_tick >= 4)
+ V_DrawCharacter(x, y + (con_scalefactor*2), '_' | cv_constextsize.value | V_NOSCALESTART, !cv_allcaps.value);
+ }
+ if (cend == input_cur && con_tick >= 4)
+ V_DrawCharacter(x, y + (con_scalefactor*2), '_' | cv_constextsize.value | V_NOSCALESTART, !cv_allcaps.value);
+ if (rellip)
+ {
+ if (input_sel > cend)
+ V_DrawFill(x, y, charwidth*3, (10 * con_scalefactor), 107 | V_NOSCALESTART);
+ for (i = 0; i < 3; ++i, x += charwidth)
+ V_DrawCharacter(x, y, '.' | cv_constextsize.value | V_GRAYMAP | V_NOSCALESTART, !cv_allcaps.value);
+ }
}
// draw the last lines of console text to the top of the screen
@@ -1417,7 +1572,7 @@ static void CON_DrawConsole(void)
{
// inu: no more width (was always 0 and vid.width)
if (rendermode != render_none)
- V_DrawFadeConsBack(con_curlines, cons_backcolor.value); // translucent background
+ V_DrawFadeConsBack(con_curlines); // translucent background
}
// draw console text lines from top to bottom
diff --git a/src/console.h b/src/console.h
index 47af65e2..8cf6483f 100644
--- a/src/console.h
+++ b/src/console.h
@@ -40,11 +40,10 @@ extern consvar_t cons_backcolor;
extern UINT8 *yellowmap, *purplemap, *lgreenmap, *bluemap, *graymap, *redmap, *orangemap;
-// Console bg colors:
-extern UINT8 *cwhitemap, *corangemap, *cbluemap, *cgreenmap, *cgraymap,
- *credmap;
+// Console bg color (auto updated to match)
+extern UINT8 *consolebgmap;
-void CON_ReSetupBackColormap(UINT16 num);
+void CON_SetupBackColormap(void);
void CON_ClearHUD(void); // clear heads up messages
void CON_Ticker(void);
diff --git a/src/d_clisrv.c b/src/d_clisrv.c
index c0f81ba3..7c21d79f 100644
--- a/src/d_clisrv.c
+++ b/src/d_clisrv.c
@@ -58,28 +58,35 @@
// NETWORKING
//
// gametic is the tic about to (or currently being) run
-// maketic is the tic that hasn't had control made for it yet
-// server:
+// Server:
+// maketic is the tic that hasn't had control made for it yet
// nettics is the tic for each node
// firstticstosend is the lowest value of nettics
-// client:
-// neededtic is the tic needed by the client for run the game
+// Client:
+// neededtic is the tic needed by the client to run the game
// firstticstosend is used to optimize a condition
-// normally maketic >= gametic > 0
+// Normally maketic >= gametic > 0
#define PREDICTIONQUEUE BACKUPTICS
#define PREDICTIONMASK (PREDICTIONQUEUE-1)
#define MAX_REASONLENGTH 30
boolean server = true; // true or false but !server == client
+#define client (!server)
boolean nodownload = false;
static boolean serverrunning = false;
INT32 serverplayer = 0;
char motd[254], server_context[8]; // Message of the Day, Unique Context (even without Mumble support)
-// server specific vars
+// Server specific vars
UINT8 playernode[MAXPLAYERS];
+// Minimum timeout for sending the savegame
+// The actual timeout will be longer depending on the savegame length
+tic_t jointimeout = (10*TICRATE);
+static boolean sendingsavegame[MAXNETNODES]; // Are we sending the savegame?
+static tic_t freezetimeout[MAXNETNODES]; // Until when can this node freeze the server before getting a timeout?
+
#ifdef NEWPING
UINT16 pingmeasurecount = 1;
UINT32 realpingtable[MAXPLAYERS]; //the base table of ping where an average will be sent to everyone.
@@ -108,7 +115,7 @@ static UINT8 resynch_local_inprogress = false; // WE are desynched and getting p
static UINT8 player_joining = false;
UINT8 hu_resynching = 0;
-// client specific
+// Client specific
static ticcmd_t localcmds;
static ticcmd_t localcmds2;
static boolean cl_packetmissed;
@@ -151,12 +158,6 @@ static consvar_t cv_showjoinaddress = {"showjoinaddress", "On", 0, CV_OnOff, NUL
static CV_PossibleValue_t playbackspeed_cons_t[] = {{1, "MIN"}, {10, "MAX"}, {0, NULL}};
consvar_t cv_playbackspeed = {"playbackspeed", "1", 0, playbackspeed_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
-void D_ResetTiccmds(void)
-{
- memset(&localcmds, 0, sizeof(ticcmd_t));
- memset(&localcmds2, 0, sizeof(ticcmd_t));
-}
-
static inline void *G_DcpyTiccmd(void* dest, const ticcmd_t* src, const size_t n)
{
const size_t d = n / sizeof(ticcmd_t);
@@ -185,11 +186,17 @@ static inline void *G_ScpyTiccmd(ticcmd_t* dest, void* src, const size_t n)
-// some software don't support largest packet
-// (original sersetup, not exactely, but the probabylity of sending a packet
-// of 512 octet is like 0.1)
+// Some software don't support largest packet
+// (original sersetup, not exactely, but the probability of sending a packet
+// of 512 bytes is like 0.1)
UINT16 software_MAXPACKETLENGTH;
+/** Guesses the value of a tic from its lowest byte and from maketic
+ *
+ * \param low The lowest byte of the tic value
+ * \return The full tic value
+ *
+ */
tic_t ExpandTics(INT32 low)
{
INT32 delta;
@@ -214,7 +221,7 @@ 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);
+ I_Error("Command id %d too big", id);
if (listnetxcmd[id] != 0)
I_Error("Command id %d already used", id);
#endif
@@ -378,7 +385,7 @@ static void ExtraDataTicker(void)
{
const UINT8 id = *curpos;
curpos++;
- DEBFILE(va("executing x_cmd %u ply %u ", id, i));
+ DEBFILE(va("executing x_cmd %s ply %u ", netxcmdnames[id - 1], i));
(listnetxcmd[id])(&curpos, i);
DEBFILE("done\n");
}
@@ -401,7 +408,11 @@ static void ExtraDataTicker(void)
}
}
- D_FreeTextcmd(gametic);
+ // 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 aknowledged,
+ // because if you need to resend a PT_SERVERTICS packet, you need to put the commands in it
+ if (client)
+ D_FreeTextcmd(gametic);
}
static void D_Clearticcmd(tic_t tic)
@@ -416,6 +427,19 @@ static void D_Clearticcmd(tic_t tic)
DEBFILE(va("clear tic %5u (%2u)\n", tic, tic%BACKUPTICS));
}
+void D_ResetTiccmds(void)
+{
+ INT32 i;
+
+ memset(&localcmds, 0, sizeof(ticcmd_t));
+ memset(&localcmds2, 0, sizeof(ticcmd_t));
+
+ // Reset the net command list
+ for (i = 0; i < TEXTCMD_HASH_SIZE; i++)
+ while (textcmds[i])
+ D_Clearticcmd(textcmds[i]->tic);
+}
+
// -----------------------------------------------------------------
// end of extra data function
// -----------------------------------------------------------------
@@ -851,12 +875,13 @@ static inline void resynch_write_others(resynchend_pak *rst)
{
UINT8 i;
- rst->ingame = rst->ctfteam = 0;
+ rst->ingame = 0;
for (i = 0; i < MAXPLAYERS; ++i)
{
if (!playeringame[i])
{
+ rst->ctfteam[i] = 0;
rst->score[i] = 0;
rst->numboxes[i] = 0;
rst->totalring[i] = 0;
@@ -866,11 +891,8 @@ static inline void resynch_write_others(resynchend_pak *rst)
}
if (!players[i].spectator)
- {
rst->ingame |= (1< 1)
- rst->ctfteam |= (1<ctfteam[i] = (INT32)LONG(players[i].ctfteam);
rst->score[i] = (UINT32)LONG(players[i].score);
rst->numboxes[i] = SHORT(players[i].numboxes);
rst->totalring[i] = SHORT(players[i].totalring);
@@ -880,28 +902,18 @@ static inline void resynch_write_others(resynchend_pak *rst)
// endian safeness
rst->ingame = (UINT32)LONG(rst->ingame);
- rst->ctfteam = (UINT32)LONG(rst->ctfteam);
}
static inline void resynch_read_others(resynchend_pak *p)
{
UINT8 i;
UINT32 loc_ingame = (UINT32)LONG(p->ingame);
- UINT32 loc_ctfteam = (UINT32)LONG(p->ctfteam);
for (i = 0; i < MAXPLAYERS; ++i)
{
// We don't care if they're in the game or not, just write all the data.
- if (loc_ingame & (1<ctfteam[i]); // no, 0 does not mean spectator, at least not in Match
players[i].score = (UINT32)LONG(p->score[i]);
players[i].numboxes = SHORT(p->numboxes[i]);
players[i].totalring = SHORT(p->totalring[i]);
@@ -1021,6 +1033,9 @@ static void SV_AcknowledgeResynchAck(INT32 node, UINT8 rsg)
resynch_status[node] &= ~(1<>10));
- V_DrawRightAlignedString(BASEVIDWIDTH/2+128, BASEVIDHEIGHT-24, V_20TRANS|V_MONOSPACE,
- va("%3.1fK/s ", ((double)getbps)/1024));
+ case CL_DOWNLOADSAVEGAME:
+ if (lastfilenum != -1)
+ {
+ cltext = M_GetText("Downloading game state...");
+ Net_GetNetStat();
+ V_DrawString(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-24, V_20TRANS|V_MONOSPACE,
+ va(" %4uK",fileneeded[lastfilenum].currentsize>>10));
+ V_DrawRightAlignedString(BASEVIDWIDTH/2+128, BASEVIDHEIGHT-24, V_20TRANS|V_MONOSPACE,
+ va("%3.1fK/s ", ((double)getbps)/1024));
+ }
+ else
+ cltext = M_GetText("Waiting to download game state...");
break;
#endif
- case cl_askjoin:
- case cl_waitjoinresponse:
+ case CL_ASKJOIN:
+ case CL_WAITJOINRESPONSE:
cltext = M_GetText("Requesting to join...");
break;
default:
@@ -1134,34 +1154,45 @@ static inline void CL_DrawConnectionStatus(void)
}
else
{
- INT32 dldlength;
- static char tempname[32];
+ if (lastfilenum != -1)
+ {
+ INT32 dldlength;
+ static char tempname[32];
- Net_GetNetStat();
- dldlength = (INT32)((fileneeded[lastfilenum].currentsize/(double)fileneeded[lastfilenum].totalsize) * 256);
- if (dldlength > 256)
- dldlength = 256;
- V_DrawFill(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-24, 256, 8, 175);
- V_DrawFill(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-24, dldlength, 8, 160);
+ Net_GetNetStat();
+ dldlength = (INT32)((fileneeded[lastfilenum].currentsize/(double)fileneeded[lastfilenum].totalsize) * 256);
+ if (dldlength > 256)
+ dldlength = 256;
+ V_DrawFill(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-24, 256, 8, 175);
+ V_DrawFill(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-24, dldlength, 8, 160);
- memset(tempname, 0, sizeof(tempname));
- nameonly(strncpy(tempname, fileneeded[lastfilenum].filename, 31));
+ memset(tempname, 0, sizeof(tempname));
+ nameonly(strncpy(tempname, fileneeded[lastfilenum].filename, 31));
- V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT-24-32, V_YELLOWMAP,
- va(M_GetText("Downloading \"%s\""), tempname));
- V_DrawString(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-24, V_20TRANS|V_MONOSPACE,
- va(" %4uK/%4uK",fileneeded[lastfilenum].currentsize>>10,fileneeded[lastfilenum].totalsize>>10));
- V_DrawRightAlignedString(BASEVIDWIDTH/2+128, BASEVIDHEIGHT-24, V_20TRANS|V_MONOSPACE,
- va("%3.1fK/s ", ((double)getbps)/1024));
+ V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT-24-32, V_YELLOWMAP,
+ va(M_GetText("Downloading \"%s\""), tempname));
+ V_DrawString(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-24, V_20TRANS|V_MONOSPACE,
+ va(" %4uK/%4uK",fileneeded[lastfilenum].currentsize>>10,fileneeded[lastfilenum].totalsize>>10));
+ V_DrawRightAlignedString(BASEVIDWIDTH/2+128, BASEVIDHEIGHT-24, V_20TRANS|V_MONOSPACE,
+ va("%3.1fK/s ", ((double)getbps)/1024));
+ }
+ else
+ V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT-24-32, V_YELLOWMAP,
+ M_GetText("Waiting to download files..."));
}
}
#endif
-//
-// CL_SendJoin
-//
-// send a special packet for declare how many player in local
-// used only in arbitratrenetstart()
+/** Sends a special packet to declare how many players in local
+ * Used only in arbitratrenetstart()
+ * Sends a PT_CLIENTJOIN packet to the server
+ *
+ * \return True if the packet was successfully sent
+ * \todo Improve the description...
+ * Because to be honest, I have no idea what arbitratrenetstart is...
+ * Is it even used...?
+ *
+ */
static boolean CL_SendJoin(void)
{
UINT8 localplayers = 1;
@@ -1296,6 +1327,12 @@ static void SV_SendPlayerInfo(INT32 node)
HSendPacket(node, false, 0, sizeof(plrinfo) * MAXPLAYERS);
}
+/** Sends a PT_SERVERCFG packet
+ *
+ * \param node The destination
+ * \return True if the packet was successfully sent
+ *
+ */
static boolean SV_SendServerConfig(INT32 node)
{
INT32 i;
@@ -1428,8 +1465,12 @@ static void SV_SendSaveGame(INT32 node)
WRITEUINT32(savebuffer, 0);
}
- SendRam(node, buffertosend, length, SF_RAM, 0);
+ SV_SendRam(node, buffertosend, length, SF_RAM, 0);
save_p = NULL;
+
+ // Remember when we started sending the savegame so we can handle timeouts
+ sendingsavegame[node] = true;
+ freezetimeout[node] = I_GetTime() + jointimeout + length / 1024; // 1 extra tic for each kilobyte
}
#ifdef DUMPCONSISTENCY
@@ -1523,7 +1564,7 @@ static void CL_LoadReceivedSavegame(void)
{
CONS_Printf(": %s", mapheaderinfo[gamemap-1]->lvlttl);
if (!(mapheaderinfo[gamemap-1]->levelflags & LF_NOZONE))
- CONS_Printf(M_GetText("ZONE"));
+ CONS_Printf(M_GetText(" ZONE"));
if (actnum > 0)
CONS_Printf(" %2d", actnum);
}
@@ -1679,11 +1720,263 @@ void CL_UpdateServerList(boolean internetsearch, INT32 room)
#endif // ifndef NONET
-// use adaptive send using net_bandwidth and stat.sendbytes
+/** Called by CL_ServerConnectionTicker
+ *
+ * \param viams ???
+ * \param asksent ???
+ * \return False if the connection was aborted
+ * \sa CL_ServerConnectionTicker
+ * \sa CL_ConnectToServer
+ *
+ */
+static boolean CL_ServerConnectionSearchTicker(boolean viams, tic_t *asksent)
+{
+#ifndef NONET
+ INT32 i;
+
+ // serverlist is updated by GetPacket function
+ if (serverlistcount > 0)
+ {
+ // this can be a responce to our broadcast request
+ if (servernode == -1 || servernode >= MAXNETNODES)
+ {
+ i = 0;
+ servernode = serverlist[i].node;
+ CONS_Printf(M_GetText("Found, "));
+ }
+ else
+ {
+ i = SL_SearchServer(servernode);
+ if (i < 0)
+ return true;
+ }
+
+ // Quit here rather than downloading files and being refused later.
+ if (serverlist[i].info.numberofplayer >= serverlist[i].info.maxplayer)
+ {
+ D_QuitNetGame();
+ CL_Reset();
+ D_StartTitle();
+ M_StartMessage(va(M_GetText("Maximum players reached: %d\n\nPress ESC\n"), serverlist[i].info.maxplayer), NULL, MM_NOTHING);
+ return false;
+ }
+
+ if (client)
+ {
+ D_ParseFileneeded(serverlist[i].info.fileneedednum,
+ serverlist[i].info.fileneeded);
+ CONS_Printf(M_GetText("Checking files...\n"));
+ i = CL_CheckFiles();
+ if (i == 3) // too many files
+ {
+ D_QuitNetGame();
+ CL_Reset();
+ D_StartTitle();
+ M_StartMessage(M_GetText(
+ "You have too many WAD files loaded\n"
+ "to add ones the server is using.\n"
+ "Please restart SRB2 before connecting.\n\n"
+ "Press ESC\n"
+ ), NULL, MM_NOTHING);
+ return false;
+ }
+ else if (i == 2) // cannot join for some reason
+ {
+ D_QuitNetGame();
+ CL_Reset();
+ D_StartTitle();
+ M_StartMessage(M_GetText(
+ "You have WAD files loaded or have\n"
+ "modified the game in some way, and\n"
+ "your file list does not match\n"
+ "the server's file list.\n"
+ "Please restart SRB2 before connecting.\n\n"
+ "Press ESC\n"
+ ), NULL, MM_NOTHING);
+ return false;
+ }
+ else if (i == 1)
+ cl_mode = CL_ASKJOIN;
+ else
+ {
+ // must download something
+ // can we, though?
+ if (!CL_CheckDownloadable()) // nope!
+ {
+ D_QuitNetGame();
+ CL_Reset();
+ D_StartTitle();
+ M_StartMessage(M_GetText(
+ "You cannot connect to this server\n"
+ "because you cannot download the files\n"
+ "that you are missing from the server.\n\n"
+ "See the console or log file for\n"
+ "more details.\n\n"
+ "Press ESC\n"
+ ), NULL, MM_NOTHING);
+ return false;
+ }
+ // no problem if can't send packet, we will retry later
+ if (CL_SendRequestFile())
+ cl_mode = CL_DOWNLOADFILES;
+ }
+ }
+ else
+ cl_mode = CL_ASKJOIN; // files need not be checked for the server.
+
+ return true;
+ }
+
+ // Ask the info to the server (askinfo packet)
+ if (*asksent + NEWTICRATE < I_GetTime())
+ {
+ SendAskInfo(servernode, viams);
+ *asksent = I_GetTime();
+ }
+#else
+ (void)viams;
+ (void)asksent;
+ // No netgames, so we skip this state.
+ cl_mode = CL_ASKJOIN;
+#endif // ifndef NONET/else
+
+ return true;
+}
+
+/** Called by CL_ConnectToServer
+ *
+ * \param viams ???
+ * \param tmpsave The name of the gamestate file???
+ * \param oldtic Used for knowing when to poll events and redraw
+ * \param asksent ???
+ * \return False if the connection was aborted
+ * \sa CL_ServerConnectionSearchTicker
+ * \sa CL_ConnectToServer
+ *
+ */
+static boolean CL_ServerConnectionTicker(boolean viams, const char *tmpsave, tic_t *oldtic, tic_t *asksent)
+{
+ boolean waitmore;
+ INT32 i;
+
+#ifdef NONET
+ (void)tmpsave;
+#endif
+
+ switch (cl_mode)
+ {
+ case CL_SEARCHING:
+ if (!CL_ServerConnectionSearchTicker(viams, asksent))
+ return false;
+ break;
+
+ case CL_DOWNLOADFILES:
+ waitmore = false;
+ for (i = 0; i < fileneedednum; i++)
+ if (fileneeded[i].status == FS_DOWNLOADING
+ || fileneeded[i].status == FS_REQUESTED)
+ {
+ waitmore = true;
+ break;
+ }
+ if (waitmore)
+ break; // exit the case
+
+ cl_mode = CL_ASKJOIN; // don't break case continue to cljoin request now
+
+ case CL_ASKJOIN:
+ CL_LoadServerFiles();
+#ifdef JOININGAME
+ // prepare structures to save the file
+ // WARNING: this can be useless in case of server not in GS_LEVEL
+ // but since the network layer doesn't provide ordered packets...
+ CL_PrepareDownloadSaveGame(tmpsave);
+#endif
+ if (CL_SendJoin())
+ cl_mode = CL_WAITJOINRESPONSE;
+ break;
+
+#ifdef JOININGAME
+ case CL_DOWNLOADSAVEGAME:
+ // At this state, the first (and only) needed file is the gamestate
+ if (fileneeded[0].status == FS_FOUND)
+ {
+ // Gamestate is now handled within CL_LoadReceivedSavegame()
+ CL_LoadReceivedSavegame();
+ cl_mode = CL_CONNECTED;
+ } // don't break case continue to CL_CONNECTED
+ else
+ break;
+#endif
+
+ case CL_WAITJOINRESPONSE:
+ case CL_CONNECTED:
+ default:
+ break;
+
+ // Connection closed by cancel, timeout or refusal.
+ case CL_ABORTED:
+ cl_mode = CL_SEARCHING;
+ return false;
+
+ }
+
+ GetPackets();
+ Net_AckTicker();
+
+ // Call it only once by tic
+ if (*oldtic != I_GetTime())
+ {
+ INT32 key;
+
+ I_OsPolling();
+ key = I_GetKey();
+ if (key == KEY_ESCAPE)
+ {
+ CONS_Printf(M_GetText("Network game synchronization aborted.\n"));
+// M_StartMessage(M_GetText("Network game synchronization aborted.\n\nPress ESC\n"), NULL, MM_NOTHING);
+ D_QuitNetGame();
+ CL_Reset();
+ D_StartTitle();
+ return false;
+ }
+
+ // why are these here? this is for servers, we're a client
+ //if (key == 's' && server)
+ // doomcom->numnodes = (INT16)pnumnodes;
+ //SV_FileSendTicker();
+ *oldtic = I_GetTime();
+
+#ifdef CLIENT_LOADINGSCREEN
+ if (client && cl_mode != CL_CONNECTED && cl_mode != CL_ABORTED)
+ {
+ F_TitleScreenTicker(true);
+ F_TitleScreenDrawer();
+ CL_DrawConnectionStatus();
+ I_UpdateNoVsync(); // page flip or blit buffer
+ if (moviemode)
+ M_SaveFrame();
+ }
+#else
+ CON_Drawer();
+ I_UpdateNoVsync();
+#endif
+ }
+ else
+ I_Sleep();
+
+ return true;
+}
+
+/** Use adaptive send using net_bandwidth and stat.sendbytes
+ *
+ * \param viams ???
+ * \todo Better description...
+ *
+ */
static void CL_ConnectToServer(boolean viams)
{
INT32 pnumnodes, nodewaited = doomcom->numnodes, i;
- boolean waitmore;
tic_t oldtic;
#ifndef NONET
tic_t asksent;
@@ -1694,14 +1987,14 @@ static void CL_ConnectToServer(boolean viams)
sprintf(tmpsave, "%s" PATHSEP TMPSAVENAME, srb2home);
#endif
- cl_mode = cl_searching;
+ cl_mode = CL_SEARCHING;
#ifdef CLIENT_LOADINGSCREEN
- lastfilenum = 0;
+ lastfilenum = -1;
#endif
#ifdef JOININGAME
- // don't get a corrupt savegame error because tmpsave already exists
+ // 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);
#endif
@@ -1725,7 +2018,7 @@ static void CL_ConnectToServer(boolean viams)
pnumnodes = 1;
oldtic = I_GetTime() - 1;
#ifndef NONET
- asksent = (tic_t)-TICRATE;
+ asksent = (tic_t) - TICRATE;
i = SL_SearchServer(servernode);
@@ -1752,197 +2045,23 @@ static void CL_ConnectToServer(boolean viams)
do
{
- switch (cl_mode)
- {
- case cl_searching:
+ // If the connection was aborted for some reason, leave
#ifndef NONET
- // serverlist is updated by GetPacket function
- if (serverlistcount > 0)
- {
- // this can be a responce to our broadcast request
- if (servernode == -1 || servernode >= MAXNETNODES)
- {
- i = 0;
- servernode = serverlist[i].node;
- CONS_Printf(M_GetText("Found, "));
- }
- else
- {
- i = SL_SearchServer(servernode);
- if (i < 0)
- break; // the case
- }
-
- // Quit here rather than downloading files and being refused later.
- if (serverlist[i].info.numberofplayer >= serverlist[i].info.maxplayer)
- {
- D_QuitNetGame();
- CL_Reset();
- D_StartTitle();
- M_StartMessage(va(M_GetText("Maximum players reached: %d\n\nPress ESC\n"), serverlist[i].info.maxplayer), NULL, MM_NOTHING);
- return;
- }
-
- if (!server)
- {
- D_ParseFileneeded(serverlist[i].info.fileneedednum,
- serverlist[i].info.fileneeded);
- CONS_Printf(M_GetText("Checking files...\n"));
- i = CL_CheckFiles();
- if (i == 2) // cannot join for some reason
- {
- D_QuitNetGame();
- CL_Reset();
- D_StartTitle();
- M_StartMessage(M_GetText(
- "You have WAD files loaded or have\n"
- "modified the game in some way, and\n"
- "your file list does not match\n"
- "the server's file list.\n"
- "Please restart SRB2 before connecting.\n\n"
- "Press ESC\n"
- ), NULL, MM_NOTHING);
- return;
- }
- else if (i == 1)
- cl_mode = cl_askjoin;
- else
- {
- // must download something
- // can we, though?
- if (!CL_CheckDownloadable()) // nope!
- {
- D_QuitNetGame();
- CL_Reset();
- D_StartTitle();
- M_StartMessage(M_GetText(
- "You cannot conect to this server\n"
- "because you cannot download the files\n"
- "that you are missing from the server.\n\n"
- "See the console or log file for\n"
- "more details.\n\n"
- "Press ESC\n"
- ), NULL, MM_NOTHING);
- return;
- }
- // no problem if can't send packet, we will retry later
- if (CL_SendRequestFile())
- cl_mode = cl_downloadfiles;
- }
- }
- else
- cl_mode = cl_askjoin; // files need not be checked for the server.
- break;
- }
- // ask the info to the server (askinfo packet)
- if (asksent + NEWTICRATE < I_GetTime())
- {
- SendAskInfo(servernode, viams);
- asksent = I_GetTime();
- }
+ if (!CL_ServerConnectionTicker(viams, tmpsave, &oldtic, &asksent))
#else
- (void)viams;
- // No netgames, so we skip this state.
- cl_mode = cl_askjoin;
-#endif // ifndef NONET/else
- break;
- case cl_downloadfiles:
- waitmore = false;
- for (i = 0; i < fileneedednum; i++)
- if (fileneeded[i].status == FS_DOWNLOADING
- || fileneeded[i].status == FS_REQUESTED)
- {
- waitmore = true;
- break;
- }
- if (waitmore)
- break; // exit the case
-
- cl_mode = cl_askjoin; // don't break case continue to cljoin request now
- case cl_askjoin:
- CL_LoadServerFiles();
-#ifdef JOININGAME
- // prepare structures to save the file
- // WARNING: this can be useless in case of server not in GS_LEVEL
- // but since the network layer doesn't provide ordered packets...
- CL_PrepareDownloadSaveGame(tmpsave);
+ if (!CL_ServerConnectionTicker(viams, (char*)NULL, &oldtic, (tic_t *)NULL))
#endif
- if (CL_SendJoin())
- cl_mode = cl_waitjoinresponse;
- break;
-#ifdef JOININGAME
- case cl_downloadsavegame:
- if (fileneeded[0].status == FS_FOUND)
- {
- // Gamestate is now handled within CL_LoadReceivedSavegame()
- CL_LoadReceivedSavegame();
- cl_mode = cl_connected;
- } // don't break case continue to cl_connected
- else
- break;
-#endif
- case cl_waitjoinresponse:
- case cl_connected:
- default:
- break;
-
- // Connection closed by cancel, timeout or refusal.
- case cl_aborted:
- cl_mode = cl_searching;
- return;
- }
-
- GetPackets();
- Net_AckTicker();
-
- // call it only one by tic
- if (oldtic != I_GetTime())
- {
- INT32 key;
-
- I_OsPolling();
- key = I_GetKey();
- if (key == KEY_ESCAPE)
- {
- CONS_Printf(M_GetText("Network game synchronization aborted.\n"));
-// M_StartMessage(M_GetText("Network game synchronization aborted.\n\nPress ESC\n"), NULL, MM_NOTHING);
- D_QuitNetGame();
- CL_Reset();
- D_StartTitle();
- return;
- }
-
- // why are these here? this is for servers, we're a client
- //if (key == 's' && server)
- // doomcom->numnodes = (INT16)pnumnodes;
- //FiletxTicker();
- oldtic = I_GetTime();
-
-#ifdef CLIENT_LOADINGSCREEN
- if (!server && cl_mode != cl_connected && cl_mode != cl_aborted)
- {
- F_TitleScreenTicker(true);
- F_TitleScreenDrawer();
- CL_DrawConnectionStatus();
- I_UpdateNoVsync(); // page flip or blit buffer
- if (moviemode)
- M_SaveFrame();
- }
-#else
- CON_Drawer();
- I_UpdateNoVsync();
-#endif
- }
- else I_Sleep();
+ return;
if (server)
{
pnumnodes = 0;
for (i = 0; i < MAXNETNODES; i++)
- if (nodeingame[i]) pnumnodes++;
+ if (nodeingame[i])
+ pnumnodes++;
}
}
- while (!(cl_mode == cl_connected && (!server || (server && nodewaited <= pnumnodes))));
+ while (!(cl_mode == CL_CONNECTED && (client || (server && nodewaited <= pnumnodes))));
DEBFILE(va("Synchronisation Finished\n"));
@@ -2199,7 +2318,6 @@ void CL_ClearPlayer(INT32 playernum)
P_RemoveMobj(players[playernum].mo->tracer);
P_RemoveMobj(players[playernum].mo);
}
- players[playernum].mo = NULL;
memset(&players[playernum], 0, sizeof (player_t));
}
@@ -2407,12 +2525,18 @@ static void Command_Nodes(void)
static void Command_Ban(void)
{
- if (COM_Argc() == 1)
+ if (COM_Argc() < 2)
{
CONS_Printf(M_GetText("Ban : 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 || adminplayer == consoleplayer)
{
XBOXSTATIC UINT8 buf[3 + MAX_REASONLENGTH];
@@ -2422,9 +2546,10 @@ static void Command_Ban(void)
if (pn == -1 || pn == 0)
return;
- else
- WRITEUINT8(p, pn);
- if (I_Ban && !I_Ban(node))
+
+ 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);
@@ -2432,7 +2557,8 @@ static void Command_Ban(void)
}
else
{
- Ban_Add(COM_Argv(2));
+ if (server) // only the server is allowed to do this right now
+ Ban_Add(COM_Argv(2));
if (COM_Argc() == 2)
{
@@ -2465,21 +2591,38 @@ static void Command_Ban(void)
static void Command_Kick(void)
{
- XBOXSTATIC UINT8 buf[3 + MAX_REASONLENGTH];
- UINT8 *p = buf;
-
- if (COM_Argc() == 1)
+ if (COM_Argc() < 2)
{
CONS_Printf(M_GetText("kick : 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 || adminplayer == consoleplayer)
{
+ XBOXSTATIC UINT8 buf[3 + MAX_REASONLENGTH];
+ UINT8 *p = buf;
const SINT8 pn = nametonum(COM_Argv(1));
- WRITESINT8(p, pn);
+
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 (sendingsavegame[playernode[pn]])
+ {
+ Net_ConnectionTimeout(playernode[pn]);
+ return;
+ }
+
+ WRITESINT8(p, pn);
+
if (COM_Argc() == 2)
{
WRITEUINT8(p, KICK_MSG_GO_AWAY);
@@ -2581,12 +2724,14 @@ static void Got_KickCmd(UINT8 **p, INT32 playernum)
// If a verified admin banned someone, the server needs to know about it.
// If the playernum isn't zero (the server) then the server needs to record the ban.
- if (server && playernum && msg == KICK_MSG_BANNED)
+ if (server && playernum && (msg == KICK_MSG_BANNED || msg == KICK_MSG_CUSTOM_BAN))
{
if (I_Ban && !I_Ban(playernode[(INT32)pnum]))
- {
CONS_Alert(CONS_WARNING, M_GetText("Too many bans! Geez, that's a lot of people you're excluding...\n"));
- }
+#ifndef NONET
+ else
+ Ban_Add(reason);
+#endif
}
switch (msg)
@@ -2692,7 +2837,12 @@ consvar_t cv_blamecfail = {"blamecfail", "Off", 0, CV_OnOff, NULL, 0, NULL, NULL
// max file size to send to a player (in kilobytes)
static CV_PossibleValue_t maxsend_cons_t[] = {{0, "MIN"}, {51200, "MAX"}, {0, NULL}};
-consvar_t cv_maxsend = {"maxsend", "1024", CV_SAVE, maxsend_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_maxsend = {"maxsend", "4096", CV_SAVE, maxsend_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_noticedownload = {"noticedownload", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
+
+// Speed of file downloading (in packets per tic)
+static CV_PossibleValue_t downloadspeed_cons_t[] = {{0, "MIN"}, {32, "MAX"}, {0, NULL}};
+consvar_t cv_downloadspeed = {"downloadspeed", "16", CV_SAVE, downloadspeed_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
static void Got_AddPlayer(UINT8 **p, INT32 playernum);
@@ -2711,6 +2861,13 @@ void D_ClientServerInit(void)
COM_AddCommand("reloadbans", Command_ReloadBan);
COM_AddCommand("connect", Command_connect);
COM_AddCommand("nodes", Command_Nodes);
+#ifdef PACKETDROP
+ COM_AddCommand("drop", Command_Drop);
+ COM_AddCommand("droprate", Command_Droprate);
+#endif
+#ifdef _DEBUG
+ COM_AddCommand("numnodes", Command_Numnodes);
+#endif
#endif
RegisterNetXCmd(XD_KICK, Got_KickCmd);
@@ -2746,6 +2903,7 @@ static void ResetNode(INT32 node)
supposedtics[node] = gametic;
nodewaiting[node] = 0;
playerpernode[node] = 0;
+ sendingsavegame[node] = false;
}
void SV_ResetServer(void)
@@ -2754,7 +2912,7 @@ void SV_ResetServer(void)
// +1 because this command will be executed in com_executebuffer in
// tryruntic so gametic will be incremented, anyway maketic > gametic
- // is not a issue
+ // is not an issue
maketic = gametic + 1;
neededtic = maketic;
@@ -2808,7 +2966,7 @@ static inline void SV_GenContext(void)
for (i = 0; i < 8; i++)
{
const char a = M_RandomKey(26*2);
- if (a <= 26) // uppercase
+ if (a < 26) // uppercase
server_context[i] = 'A'+a;
else // lowercase
server_context[i] = 'a'+(a-26);
@@ -2843,7 +3001,7 @@ void D_QuitNetGame(void)
if (serverrunning && ms_RoomId > 0)
UnregisterServer();
}
- else if (servernode > 0 && servernode < MAXNETNODES && nodeingame[(UINT8)servernode]!=0)
+ else if (servernode > 0 && servernode < MAXNETNODES && nodeingame[(UINT8)servernode])
{
netbuffer->packettype = PT_CLIENTQUIT;
HSendPacket(servernode, true, 0, 0);
@@ -2864,12 +3022,12 @@ void D_QuitNetGame(void)
#endif
}
-// add a node to the game (player will follow at map change or at savegame....)
+// Adds a node to the game (player will follow at map change or at savegame....)
static inline void SV_AddNode(INT32 node)
{
nettics[node] = gametic;
supposedtics[node] = gametic;
- // little hack because the server connect to itself and put
+ // little hack because the server connects to itself and puts
// nodeingame when connected not here
if (node)
nodeingame[node] = true;
@@ -3019,7 +3177,7 @@ static boolean SV_AddWaitingPlayers(void)
void CL_AddSplitscreenPlayer(void)
{
- if (cl_mode == cl_connected)
+ if (cl_mode == CL_CONNECTED)
CL_SendJoin();
}
@@ -3027,7 +3185,7 @@ void CL_RemoveSplitscreenPlayer(void)
{
XBOXSTATIC UINT8 buf[2];
- if (cl_mode != cl_connected)
+ if (cl_mode != CL_CONNECTED)
return;
buf[0] = (UINT8)secondarydisplayplayer;
@@ -3038,7 +3196,7 @@ void CL_RemoveSplitscreenPlayer(void)
// is there a game running
boolean Playing(void)
{
- return (server && serverrunning) || (!server && cl_mode == cl_connected);
+ return (server && serverrunning) || (client && cl_mode == CL_CONNECTED);
}
boolean SV_SpawnServer(void)
@@ -3086,7 +3244,7 @@ void SV_StopServer(void)
D_Clearticcmd(i);
consoleplayer = 0;
- cl_mode = cl_searching;
+ cl_mode = CL_SEARCHING;
maketic = gametic+1;
neededtic = maketic;
serverrunning = false;
@@ -3132,6 +3290,11 @@ static size_t TotalTextCmdPerTic(tic_t tic)
return total;
}
+/** Called when a PT_CLIENTJOIN packet is received
+ *
+ * \param node The packet sender
+ *
+ */
static void HandleConnect(SINT8 node)
{
if (bannednode && bannednode[node])
@@ -3163,6 +3326,9 @@ static void HandleConnect(SINT8 node)
#endif
SV_AddNode(node);
+ /// \note Wait what???
+ /// What if the gamestate takes more than one second to get downloaded?
+ /// Or if a lagspike happens?
// you get a free second before desynch checks. use it wisely.
SV_InitResynchVars(node);
@@ -3171,6 +3337,7 @@ static void HandleConnect(SINT8 node)
if (!SV_SendServerConfig(node))
{
G_SetGamestate(backupstate);
+ /// \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 !!!
@@ -3201,6 +3368,11 @@ static void HandleConnect(SINT8 node)
}
}
+/** Called when a PT_SERVERSHUTDOWN packet is received
+ *
+ * \param node The packet sender (should be the server)
+ *
+ */
static void HandleShutdown(SINT8 node)
{
(void)node;
@@ -3210,6 +3382,11 @@ static void HandleShutdown(SINT8 node)
M_StartMessage(M_GetText("Server has shutdown\n\nPress Esc\n"), NULL, MM_NOTHING);
}
+/** Called when a PT_NODETIMEOUT packet is received
+ *
+ * \param node The packet sender (should be the server)
+ *
+ */
static void HandleTimeout(SINT8 node)
{
(void)node;
@@ -3220,6 +3397,12 @@ static void HandleTimeout(SINT8 node)
}
#ifndef NONET
+/** Called when a PT_SERVERINFO packet is received
+ *
+ * \param node The packet sender
+ * \note What happens if the packet comes from a client or something like that?
+ *
+ */
static void HandleServerInfo(SINT8 node)
{
// compute ping in ms
@@ -3233,39 +3416,644 @@ static void HandleServerInfo(SINT8 node)
}
#endif
-/** \brief GetPackets
+/** Handles a packet received from a node that isn't in game
+ *
+ * \param node The packet sender
+ * \todo Choose a better name, as the packet can also come from the server apparently?
+ * \sa HandlePacketFromPlayer
+ * \sa GetPackets
+ *
+ */
+static void HandlePacketFromAwayNode(SINT8 node)
+{
+ if (node != servernode)
+ DEBFILE(va("Received packet from unknown host %d\n", node));
- \todo break this 300 line function into multiple functions
-*/
-static void GetPackets(void)
+// macro for packets that should only be sent by the server
+// if it is NOT from the server, bail out and close the connection!
+#define SERVERONLY \
+ if (node != servernode) \
+ { \
+ Net_CloseConnection(node); \
+ break; \
+ }
+ switch (netbuffer->packettype)
+ {
+ case PT_ASKINFOVIAMS:
+#if 0
+ if (server && serverrunning)
+ {
+ INT32 clientnode;
+ if (ms_RoomId < 0) // ignore if we're not actually on the MS right now
+ {
+ Net_CloseConnection(node); // and yes, close connection
+ return;
+ }
+ clientnode = I_NetMakeNode(netbuffer->u.msaskinfo.clientaddr);
+ if (clientnode != -1)
+ {
+ SV_SendServerInfo(clientnode, (tic_t)LONG(netbuffer->u.msaskinfo.time));
+ SV_SendPlayerInfo(clientnode); // Send extra info
+ Net_CloseConnection(clientnode);
+ // Don't close connection to MS...
+ }
+ else
+ Net_CloseConnection(node); // ...unless the IP address is not valid
+ }
+ else
+ Net_CloseConnection(node); // you're not supposed to get it, so ignore it
+#else
+ Net_CloseConnection(node);
+#endif
+ break;
+
+ case PT_ASKINFO:
+ if (server && serverrunning)
+ {
+ SV_SendServerInfo(node, (tic_t)LONG(netbuffer->u.askinfo.time));
+ SV_SendPlayerInfo(node); // Send extra info
+ }
+ Net_CloseConnection(node);
+ break;
+
+ case PT_SERVERREFUSE: // Negative response of client join request
+ if (server && serverrunning)
+ { // But wait I thought I'm the server?
+ Net_CloseConnection(node);
+ break;
+ }
+ SERVERONLY
+ if (cl_mode == CL_WAITJOINRESPONSE)
+ {
+ // Save the reason so it can be displayed after quitting the netgame
+ char *reason = strdup(netbuffer->u.serverrefuse.reason);
+ if (!reason)
+ I_Error("Out of memory!\n");
+
+ D_QuitNetGame();
+ CL_Reset();
+ D_StartTitle();
+
+ M_StartMessage(va(M_GetText("Server refuses connection\n\nReason:\n%s"),
+ reason), NULL, MM_NOTHING);
+
+ free(reason);
+
+ // Will be reset by caller. Signals refusal.
+ cl_mode = CL_ABORTED;
+ }
+ break;
+
+ case PT_SERVERCFG: // Positive response of client join request
+ {
+ INT32 j;
+ UINT8 *scp;
+
+ if (server && serverrunning && node != servernode)
+ { // but wait I thought I'm the server?
+ Net_CloseConnection(node);
+ break;
+ }
+ SERVERONLY
+ /// \note how would this happen? and is it doing the right thing if it does?
+ if (cl_mode != CL_WAITJOINRESPONSE)
+ break;
+
+ if (client)
+ {
+ maketic = gametic = neededtic = (tic_t)LONG(netbuffer->u.servercfg.gametic);
+ gametype = netbuffer->u.servercfg.gametype;
+ modifiedgame = netbuffer->u.servercfg.modifiedgame;
+ adminplayer = netbuffer->u.servercfg.adminplayer;
+ memcpy(server_context, netbuffer->u.servercfg.server_context, 8);
+ }
+
+ nodeingame[(UINT8)servernode] = true;
+ serverplayer = netbuffer->u.servercfg.serverplayer;
+ doomcom->numslots = SHORT(netbuffer->u.servercfg.totalslotnum);
+ mynode = netbuffer->u.servercfg.clientnode;
+ if (serverplayer >= 0)
+ playernode[(UINT8)serverplayer] = servernode;
+
+ if (netgame)
+#ifdef JOININGAME
+ CONS_Printf(M_GetText("Join accepted, waiting for complete game state...\n"));
+#else
+ CONS_Printf(M_GetText("Join accepted, waiting for next level change...\n"));
+#endif
+ DEBFILE(va("Server accept join gametic=%u mynode=%d\n", gametic, mynode));
+
+ memset(playeringame, 0, sizeof(playeringame));
+ for (j = 0; j < MAXPLAYERS; j++)
+ {
+ if (netbuffer->u.servercfg.playerskins[j] == 0xFF
+ && netbuffer->u.servercfg.playercolor[j] == 0xFF)
+ continue; // not in game
+
+ playeringame[j] = true;
+ SetPlayerSkinByNum(j, (INT32)netbuffer->u.servercfg.playerskins[j]);
+ players[j].skincolor = netbuffer->u.servercfg.playercolor[j];
+ }
+
+ scp = netbuffer->u.servercfg.varlengthinputs;
+ CV_LoadPlayerNames(&scp);
+ CV_LoadNetVars(&scp);
+#ifdef JOININGAME
+ /// \note Wait. What if a Lua script uses some global custom variables synched with the NetVars hook?
+ /// Shouldn't them be downloaded even at intermission time?
+ /// Also, according to HandleConnect, the server will send the savegame even during intermission...
+ if (netbuffer->u.servercfg.gamestate == GS_LEVEL/* ||
+ netbuffer->u.servercfg.gamestate == GS_INTERMISSION*/)
+ cl_mode = CL_DOWNLOADSAVEGAME;
+ else
+#endif
+ cl_mode = CL_CONNECTED;
+ break;
+ }
+
+ // Handled in d_netfil.c
+ case PT_FILEFRAGMENT:
+ if (server)
+ { // But wait I thought I'm the server?
+ Net_CloseConnection(node);
+ break;
+ }
+ SERVERONLY
+ Got_Filetxpak();
+ break;
+
+ case PT_REQUESTFILE:
+ if (server)
+ {
+ if (!cv_downloading.value || !Got_RequestFilePak(node))
+ Net_CloseConnection(node); // close connection if one of the requested files could not be sent, or you disabled downloading anyway
+ }
+ else
+ Net_CloseConnection(node); // nope
+ break;
+
+ case PT_NODETIMEOUT:
+ case PT_CLIENTQUIT:
+ if (server)
+ Net_CloseConnection(node);
+ break;
+
+ case PT_CLIENTCMD:
+ break; // This is not an "unknown packet"
+
+ case PT_SERVERTICS:
+ // Do not remove my own server (we have just get a out of order packet)
+ if (node == servernode)
+ break;
+
+ default:
+ DEBFILE(va("unknown packet received (%d) from unknown host\n",netbuffer->packettype));
+ Net_CloseConnection(node);
+ break; // Ignore it
+
+ }
+#undef SERVERONLY
+}
+
+/** Handles a packet received from a node that is in game
+ *
+ * \param node The packet sender
+ * \todo Choose a better name
+ * \sa HandlePacketFromAwayNode
+ * \sa GetPackets
+ *
+ */
+static void HandlePacketFromPlayer(SINT8 node)
{FILESTAMP
XBOXSTATIC INT32 netconsole;
- XBOXSTATIC SINT8 node;
- XBOXSTATIC tic_t realend,realstart;
+ XBOXSTATIC tic_t realend, realstart;
XBOXSTATIC UINT8 *pak, *txtpak, numtxtpak;
FILESTAMP
+ txtpak = NULL;
+
+ if (dedicated && node == 0)
+ netconsole = 0;
+ else
+ netconsole = nodetoplayer[node];
+#ifdef PARANOIA
+ if (netconsole >= MAXPLAYERS)
+ I_Error("bad table nodetoplayer: node %d player %d", doomcom->remotenode, netconsole);
+#endif
+
+ switch (netbuffer->packettype)
+ {
+// -------------------------------------------- SERVER RECEIVE ----------
+ case PT_RESYNCHGET:
+ if (client)
+ break;
+ SV_AcknowledgeResynchAck(netconsole, netbuffer->u.resynchgot);
+ break;
+ case PT_CLIENTCMD:
+ case PT_CLIENT2CMD:
+ case PT_CLIENTMIS:
+ case PT_CLIENT2MIS:
+ case PT_NODEKEEPALIVE:
+ case PT_NODEKEEPALIVEMIS:
+ if (client)
+ break;
+
+ // Ignore tics from those not synched
+ if (resynch_inprogress[node])
+ break;
+
+ // 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);
+ realend = ExpandTics(netbuffer->u.clientpak.resendfrom);
+
+ if (netbuffer->packettype == PT_CLIENTMIS || netbuffer->packettype == PT_CLIENT2MIS
+ || netbuffer->packettype == PT_NODEKEEPALIVEMIS
+ || supposedtics[node] < realend)
+ {
+ supposedtics[node] = realend;
+ }
+ // Discard out of order packet
+ if (nettics[node] > realend)
+ {
+ DEBFILE(va("out of order ticcmd discarded nettics = %u\n", nettics[node]));
+ break;
+ }
+
+ // Update the nettics
+ nettics[node] = realend;
+
+ // Don't do anything for packets of type NODEKEEPALIVE?
+ if (netconsole == -1 || netbuffer->packettype == PT_NODEKEEPALIVE
+ || netbuffer->packettype == PT_NODEKEEPALIVEMIS)
+ break;
+
+ // If a client sends a ticcmd it should mean they are done receiving the savegame
+ sendingsavegame[node] = false;
+
+ // As long as clients send valid ticcmds, the server can keep running, so reset the timeout
+ /// \todo Use a separate cvar for that kind of timeout?
+ freezetimeout[node] = I_GetTime() + connectiontimeout;
+
+ // Copy ticcmd
+ G_MoveTiccmd(&netcmds[maketic%BACKUPTICS][netconsole], &netbuffer->u.clientpak.cmd, 1);
+
+ // Check ticcmd for "speed hacks"
+ if (netcmds[maketic%BACKUPTICS][netconsole].forwardmove > MAXPLMOVE || netcmds[maketic%BACKUPTICS][netconsole].forwardmove < -MAXPLMOVE
+ || netcmds[maketic%BACKUPTICS][netconsole].sidemove > MAXPLMOVE || netcmds[maketic%BACKUPTICS][netconsole].sidemove < -MAXPLMOVE)
+ {
+ XBOXSTATIC char buf[2];
+ CONS_Alert(CONS_WARNING, M_GetText("Illegal movement value received from node %d\n"), netconsole);
+ //D_Clearticcmd(k);
+
+ buf[0] = (char)netconsole;
+ buf[1] = KICK_MSG_CON_FAIL;
+ SendNetXCmd(XD_KICK, &buf, 2);
+ break;
+ }
+
+ // Splitscreen cmd
+ if ((netbuffer->packettype == PT_CLIENT2CMD || netbuffer->packettype == PT_CLIENT2MIS)
+ && nodetoplayer2[node] >= 0)
+ G_MoveTiccmd(&netcmds[maketic%BACKUPTICS][(UINT8)nodetoplayer2[node]],
+ &netbuffer->u.client2pak.cmd2, 1);
+
+ // A delay before we check resynching
+ // Used on join or just after a synch fail
+ if (resynch_delay[node])
+ {
+ --resynch_delay[node];
+ break;
+ }
+ // Check player consistancy during the level
+ if (realstart <= gametic && realstart > gametic - BACKUPTICS+1 && gamestate == GS_LEVEL
+ && consistancy[realstart%BACKUPTICS] != SHORT(netbuffer->u.clientpak.consistancy))
+ {
+ SV_RequireResynch(node);
+
+ if (cv_resynchattempts.value && resynch_score[node] <= (unsigned)cv_resynchattempts.value*250)
+ {
+ if (cv_blamecfail.value)
+ CONS_Printf(M_GetText("Synch failure for player %d (%s); expected %hd, got %hd\n"),
+ netconsole+1, player_names[netconsole],
+ consistancy[realstart%BACKUPTICS],
+ SHORT(netbuffer->u.clientpak.consistancy));
+ DEBFILE(va("Restoring player %d (synch failure) [%update] %d!=%d\n",
+ netconsole, realstart, consistancy[realstart%BACKUPTICS],
+ SHORT(netbuffer->u.clientpak.consistancy)));
+ break;
+ }
+ else
+ {
+ XBOXSTATIC UINT8 buf[3];
+
+ buf[0] = (UINT8)netconsole;
+ buf[1] = KICK_MSG_CON_FAIL;
+ SendNetXCmd(XD_KICK, &buf, 2);
+ DEBFILE(va("player %d kicked (synch failure) [%u] %d!=%d\n",
+ netconsole, realstart, consistancy[realstart%BACKUPTICS],
+ SHORT(netbuffer->u.clientpak.consistancy)));
+ break;
+ }
+ }
+ else if (resynch_score[node])
+ --resynch_score[node];
+ break;
+ case PT_TEXTCMD2: // splitscreen special
+ netconsole = nodetoplayer2[node];
+ case PT_TEXTCMD:
+ if (client)
+ break;
+
+ 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);
+ break;
+ }
+
+ // 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);
+ break;
+ }
+
+ // 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);
+ break;
+ }
+
+ // 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];
+ }
+ break;
+ case PT_NODETIMEOUT:
+ case PT_CLIENTQUIT:
+ if (client)
+ break;
+
+ // nodeingame will be put false in the execution of kick command
+ // this allow to send some packets to the quitting client to have their ack back
+ nodewaiting[node] = 0;
+ if (netconsole != -1 && playeringame[netconsole])
+ {
+ XBOXSTATIC UINT8 buf[2];
+ buf[0] = (UINT8)netconsole;
+ if (netbuffer->packettype == PT_NODETIMEOUT)
+ buf[1] = KICK_MSG_TIMEOUT;
+ else
+ buf[1] = KICK_MSG_PLAYER_QUIT;
+ SendNetXCmd(XD_KICK, &buf, 2);
+ nodetoplayer[node] = -1;
+ if (nodetoplayer2[node] != -1 && nodetoplayer2[node] >= 0
+ && playeringame[(UINT8)nodetoplayer2[node]])
+ {
+ buf[0] = nodetoplayer2[node];
+ SendNetXCmd(XD_KICK, &buf, 2);
+ nodetoplayer2[node] = -1;
+ }
+ }
+ Net_CloseConnection(node);
+ nodeingame[node] = false;
+ break;
+// -------------------------------------------- CLIENT RECEIVE ----------
+ case PT_RESYNCHEND:
+ // Only accept PT_RESYNCHEND from the server.
+ if (node != servernode)
+ {
+ CONS_Alert(CONS_WARNING, M_GetText("%s received from non-host %d\n"), "PT_RESYNCHEND", node);
+
+ if (server)
+ {
+ XBOXSTATIC UINT8 buf[2];
+ buf[0] = (UINT8)node;
+ buf[1] = KICK_MSG_CON_FAIL;
+ SendNetXCmd(XD_KICK, &buf, 2);
+ }
+
+ break;
+ }
+ resynch_local_inprogress = false;
+
+ P_SetRandSeed(netbuffer->u.resynchend.randomseed);
+
+ if (gametype == GT_CTF)
+ resynch_read_ctf(&netbuffer->u.resynchend);
+ resynch_read_others(&netbuffer->u.resynchend);
+
+ break;
+ case PT_SERVERTICS:
+ // 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)
+ {
+ XBOXSTATIC UINT8 buf[2];
+ buf[0] = (UINT8)node;
+ buf[1] = KICK_MSG_CON_FAIL;
+ SendNetXCmd(XD_KICK, &buf, 2);
+ }
+
+ break;
+ }
+
+ realstart = ExpandTics(netbuffer->u.serverpak.starttic);
+ realend = realstart + netbuffer->u.serverpak.numtics;
+
+ if (!txtpak)
+ txtpak = (UINT8 *)&netbuffer->u.serverpak.cmds[netbuffer->u.serverpak.numslots
+ * netbuffer->u.serverpak.numtics];
+
+ if (realend > gametic + BACKUPTICS)
+ realend = gametic + BACKUPTICS;
+ cl_packetmissed = realstart > neededtic;
+
+ if (realstart <= neededtic && realend > neededtic)
+ {
+ tic_t i, j;
+ pak = (UINT8 *)&netbuffer->u.serverpak.cmds;
+
+ for (i = realstart; i < realend; i++)
+ {
+ // clear first
+ D_Clearticcmd(i);
+
+ // copy the tics
+ pak = G_ScpyTiccmd(netcmds[i%BACKUPTICS], pak,
+ netbuffer->u.serverpak.numslots*sizeof (ticcmd_t));
+
+ // copy the textcmds
+ numtxtpak = *txtpak++;
+ for (j = 0; j < numtxtpak; j++)
+ {
+ INT32 k = *txtpak++; // playernum
+ const size_t txtsize = txtpak[0]+1;
+
+ M_Memcpy(D_GetTextcmd(i, k), txtpak, txtsize);
+ txtpak += txtsize;
+ }
+ }
+
+ neededtic = realend;
+ }
+ else
+ {
+ DEBFILE(va("frame not in bound: %u\n", neededtic));
+ /*if (realend < neededtic - 2 * TICRATE || neededtic + 2 * TICRATE < realstart)
+ I_Error("Received an out of order PT_SERVERTICS packet!\n"
+ "Got tics %d-%d, needed tic %d\n\n"
+ "Please report this crash on the Master Board,\n"
+ "IRC or Discord so it can be fixed.\n", (INT32)realstart, (INT32)realend, (INT32)neededtic);*/
+ }
+ break;
+ case PT_RESYNCHING:
+ // Only accept PT_RESYNCHING from the server.
+ if (node != servernode)
+ {
+ CONS_Alert(CONS_WARNING, M_GetText("%s received from non-host %d\n"), "PT_RESYNCHING", node);
+
+ if (server)
+ {
+ XBOXSTATIC char buf[2];
+ buf[0] = (char)node;
+ buf[1] = KICK_MSG_CON_FAIL;
+ SendNetXCmd(XD_KICK, &buf, 2);
+ }
+
+ break;
+ }
+ resynch_local_inprogress = true;
+ CL_AcknowledgeResynch(&netbuffer->u.resynchpak);
+ break;
+#ifdef NEWPING
+ case PT_PING:
+ // Only accept PT_PING from the server.
+ if (node != servernode)
+ {
+ CONS_Alert(CONS_WARNING, M_GetText("%s received from non-host %d\n"), "PT_PING", node);
+
+ if (server)
+ {
+ XBOXSTATIC char buf[2];
+ buf[0] = (char)node;
+ buf[1] = KICK_MSG_CON_FAIL;
+ SendNetXCmd(XD_KICK, &buf, 2);
+ }
+
+ break;
+ }
+
+ //Update client ping table from the server.
+ if (client)
+ {
+ INT32 i;
+ for (i = 0; i < MAXNETNODES; i++)
+ if (playeringame[i])
+ playerpingtable[i] = (tic_t)netbuffer->u.pingtable[i];
+ }
+
+ break;
+#endif
+ case PT_SERVERCFG:
+ break;
+ case PT_FILEFRAGMENT:
+ // 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)
+ {
+ XBOXSTATIC UINT8 buf[2];
+ buf[0] = (UINT8)node;
+ buf[1] = KICK_MSG_CON_FAIL;
+ SendNetXCmd(XD_KICK, &buf, 2);
+ }
+
+ break;
+ }
+ if (client)
+ Got_Filetxpak();
+ break;
+ default:
+ DEBFILE(va("UNKNOWN PACKET TYPE RECEIVED %d from host %d\n",
+ netbuffer->packettype, node));
+ } // end switch
+}
+
+/** Handles all received packets, if any
+ *
+ * \todo Add details to this description (lol)
+ *
+ */
+static void GetPackets(void)
+{FILESTAMP
+ XBOXSTATIC SINT8 node; // The packet sender
+FILESTAMP
+
player_joining = false;
while (HGetPacket())
{
node = (SINT8)doomcom->remotenode;
+
if (netbuffer->packettype == PT_CLIENTJOIN && server)
{
HandleConnect(node);
continue;
}
- if (netbuffer->packettype == PT_SERVERSHUTDOWN && node == servernode
- && !server && cl_mode != cl_searching)
+ if (node == servernode && client && cl_mode != CL_SEARCHING)
{
- HandleShutdown(node);
- continue;
- }
- if (netbuffer->packettype == PT_NODETIMEOUT && node == servernode
- && !server && cl_mode != cl_searching)
- {
- HandleTimeout(node);
- continue;
+ if (netbuffer->packettype == PT_SERVERSHUTDOWN)
+ {
+ HandleShutdown(node);
+ continue;
+ }
+ if (netbuffer->packettype == PT_NODETIMEOUT)
+ {
+ HandleTimeout(node);
+ continue;
+ }
}
#ifndef NONET
@@ -3279,481 +4067,13 @@ FILESTAMP
if (netbuffer->packettype == PT_PLAYERINFO)
continue; // We do nothing with PLAYERINFO, that's for the MS browser.
- if (!nodeingame[node])
- {
- if (node != servernode)
- DEBFILE(va("Received packet from unknown host %d\n", node));
-
- // anyone trying to join
- switch (netbuffer->packettype)
- {
- case PT_ASKINFOVIAMS:
- if (server && serverrunning)
- {
- INT32 clientnode = I_NetMakeNode(netbuffer->u.msaskinfo.clientaddr);
- SV_SendServerInfo(clientnode, (tic_t)LONG(netbuffer->u.msaskinfo.time));
- SV_SendPlayerInfo(clientnode); // send extra info
- Net_CloseConnection(clientnode);
- // Don't close connection to MS.
- }
- break;
-
- case PT_ASKINFO:
- if (server && serverrunning)
- {
- SV_SendServerInfo(node, (tic_t)LONG(netbuffer->u.askinfo.time));
- SV_SendPlayerInfo(node); // send extra info
- Net_CloseConnection(node);
- }
- break;
- case PT_SERVERREFUSE: // negative response of client join request
- if (server && serverrunning)
- { // but wait I thought I'm the server?
- Net_CloseConnection(node);
- break;
- }
- if (cl_mode == cl_waitjoinresponse)
- {
- D_QuitNetGame();
- CL_Reset();
- D_StartTitle();
-
- M_StartMessage(va(M_GetText("Server refuses connection\n\nReason:\n%s"),
- netbuffer->u.serverrefuse.reason), NULL, MM_NOTHING);
-
- // Will be reset by caller. Signals refusal.
- cl_mode = cl_aborted;
- }
- break;
- case PT_SERVERCFG: // positive response of client join request
- {
- INT32 j;
- UINT8 *scp;
-
- if (server && serverrunning && node != servernode)
- { // but wait I thought I'm the server?
- Net_CloseConnection(node);
- break;
- }
- /// \note how would this happen? and is it doing the right thing if it does?
- if (cl_mode != cl_waitjoinresponse)
- break;
-
- if (!server)
- {
- maketic = gametic = neededtic = (tic_t)LONG(netbuffer->u.servercfg.gametic);
- gametype = netbuffer->u.servercfg.gametype;
- modifiedgame = netbuffer->u.servercfg.modifiedgame;
- adminplayer = netbuffer->u.servercfg.adminplayer;
- memcpy(server_context, netbuffer->u.servercfg.server_context, 8);
- }
-
- nodeingame[(UINT8)servernode] = true;
- serverplayer = netbuffer->u.servercfg.serverplayer;
- doomcom->numslots = SHORT(netbuffer->u.servercfg.totalslotnum);
- mynode = netbuffer->u.servercfg.clientnode;
- if (serverplayer >= 0)
- playernode[(UINT8)serverplayer] = servernode;
-
- if (netgame)
-#ifdef JOININGAME
- CONS_Printf(M_GetText("Join accepted, waiting for complete game state...\n"));
-#else
- CONS_Printf(M_GetText("Join accepted, waiting for next level change...\n"));
-#endif
- DEBFILE(va("Server accept join gametic=%u mynode=%d\n", gametic, mynode));
-
- memset(playeringame, 0, sizeof(playeringame));
- for (j = 0; j < MAXPLAYERS; j++)
- {
- if (netbuffer->u.servercfg.playerskins[j] == 0xFF
- && netbuffer->u.servercfg.playercolor[j] == 0xFF)
- continue; // not in game
-
- playeringame[j] = true;
- SetPlayerSkinByNum(j, (INT32)netbuffer->u.servercfg.playerskins[j]);
- players[j].skincolor = netbuffer->u.servercfg.playercolor[j];
- }
-
- scp = netbuffer->u.servercfg.varlengthinputs;
- CV_LoadPlayerNames(&scp);
- CV_LoadNetVars(&scp);
-#ifdef JOININGAME
- if (netbuffer->u.servercfg.gamestate == GS_LEVEL/* ||
- netbuffer->u.servercfg.gamestate == GS_INTERMISSION*/)
- cl_mode = cl_downloadsavegame;
- else
-#endif
- cl_mode = cl_connected;
- break;
- }
- // handled in d_netfil.c
- case PT_FILEFRAGMENT:
- if (server)
- { // but wait I thought I'm the server?
- Net_CloseConnection(node);
- break;
- }
- else
- Got_Filetxpak();
- break;
- case PT_REQUESTFILE:
- if (server)
- Got_RequestFilePak(node);
- break;
- case PT_NODETIMEOUT:
- case PT_CLIENTQUIT:
- if (server)
- Net_CloseConnection(node);
- break;
- case PT_CLIENTCMD:
- break; // this is not an "unknown packet"
- case PT_SERVERTICS:
- // do not remove my own server (we have just get a out of order packet)
- if (node == servernode)
- break;
- default:
- DEBFILE(va("unknown packet received (%d) from unknown host\n",netbuffer->packettype));
- Net_CloseConnection(node);
- break; // ignore it
- } // switch
- continue; //while
- }
- if (dedicated && node == 0) netconsole = 0;
- else netconsole = nodetoplayer[node];
-#ifdef PARANOIA
- if (netconsole >= MAXPLAYERS)
- I_Error("bad table nodetoplayer: node %d player %d", doomcom->remotenode, netconsole);
-#endif
-
- txtpak = NULL;
-
- switch (netbuffer->packettype)
- {
-// -------------------------------------------- SERVER RECEIVE ----------
- case PT_RESYNCHGET:
- SV_AcknowledgeResynchAck(netconsole, netbuffer->u.resynchgot);
- break;
- case PT_CLIENTCMD:
- case PT_CLIENT2CMD:
- case PT_CLIENTMIS:
- case PT_CLIENT2MIS:
- case PT_NODEKEEPALIVE:
- case PT_NODEKEEPALIVEMIS:
- if (!server)
- break;
-
- // ignore tics from those not synched
- if (resynch_inprogress[node])
- break;
-
- // to save bytes, only the low byte of tic numbers are sent
- // Figure out what the rest of the bytes are
- realstart = ExpandTics(netbuffer->u.clientpak.client_tic);
- realend = ExpandTics(netbuffer->u.clientpak.resendfrom);
-
- if (netbuffer->packettype == PT_CLIENTMIS || netbuffer->packettype == PT_CLIENT2MIS
- || netbuffer->packettype == PT_NODEKEEPALIVEMIS
- || supposedtics[node] < realend)
- {
- supposedtics[node] = realend;
- }
- // discard out of order packet
- if (nettics[node] > realend)
- {
- DEBFILE(va("out of order ticcmd discarded nettics = %u\n", nettics[node]));
- break;
- }
-
- // update the nettics
- nettics[node] = realend;
-
- // don't do anything for packets of type NODEKEEPALIVE?
- if (netconsole == -1 || netbuffer->packettype == PT_NODEKEEPALIVE
- || netbuffer->packettype == PT_NODEKEEPALIVEMIS)
- break;
-
- // copy ticcmd
- G_MoveTiccmd(&netcmds[maketic%BACKUPTICS][netconsole], &netbuffer->u.clientpak.cmd, 1);
-
- // check ticcmd for "speed hacks"
- if (netcmds[maketic%BACKUPTICS][netconsole].forwardmove > MAXPLMOVE || netcmds[maketic%BACKUPTICS][netconsole].forwardmove < -MAXPLMOVE
- || netcmds[maketic%BACKUPTICS][netconsole].sidemove > MAXPLMOVE || netcmds[maketic%BACKUPTICS][netconsole].sidemove < -MAXPLMOVE)
- {
- XBOXSTATIC char buf[2];
- CONS_Alert(CONS_WARNING, M_GetText("Illegal movement value recieved from node %d\n"), netconsole);
- //D_Clearticcmd(k);
-
- buf[0] = (char)netconsole;
- buf[1] = KICK_MSG_CON_FAIL;
- SendNetXCmd(XD_KICK, &buf, 2);
- break;
- }
-
- // splitscreen cmd
- if (netbuffer->packettype == PT_CLIENT2CMD && nodetoplayer2[node] >= 0)
- G_MoveTiccmd(&netcmds[maketic%BACKUPTICS][(UINT8)nodetoplayer2[node]],
- &netbuffer->u.client2pak.cmd2, 1);
-
- // a delay before we check resynching
- // used on join or just after a synch fail
- if (resynch_delay[node])
- {
- --resynch_delay[node];
- break;
- }
- // check player consistancy during the level
- if (realstart <= gametic && realstart > gametic - BACKUPTICS+1 && gamestate == GS_LEVEL
- && consistancy[realstart%BACKUPTICS] != SHORT(netbuffer->u.clientpak.consistancy))
- {
- SV_RequireResynch(node);
-
- if (cv_resynchattempts.value && resynch_score[node] <= (unsigned)cv_resynchattempts.value*250)
- {
- if (cv_blamecfail.value)
- CONS_Printf(M_GetText("Synch failure for player %d (%s); expected %hd, got %hd\n"),
- netconsole+1, player_names[netconsole],
- consistancy[realstart%BACKUPTICS],
- SHORT(netbuffer->u.clientpak.consistancy));
- DEBFILE(va("Restoring player %d (synch failure) [%update] %d!=%d\n",
- netconsole, realstart, consistancy[realstart%BACKUPTICS],
- SHORT(netbuffer->u.clientpak.consistancy)));
- break;
- }
- else
- {
- XBOXSTATIC UINT8 buf[3];
-
- buf[0] = (UINT8)netconsole;
- buf[1] = KICK_MSG_CON_FAIL;
- SendNetXCmd(XD_KICK, &buf, 2);
- DEBFILE(va("player %d kicked (synch failure) [%u] %d!=%d\n",
- netconsole, realstart, consistancy[realstart%BACKUPTICS],
- SHORT(netbuffer->u.clientpak.consistancy)));
- break;
- }
- }
- else if (resynch_score[node])
- --resynch_score[node];
- break;
- case PT_TEXTCMD2: // splitscreen special
- netconsole = nodetoplayer2[node];
- case PT_TEXTCMD:
- if (!server)
- break;
-
- if (netconsole < 0 || netconsole >= MAXPLAYERS)
- Net_UnAcknowledgPacket(node);
- else
- {
- size_t j;
- tic_t tic = maketic;
- UINT8 *textcmd;
-
- // 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_UnAcknowledgPacket(node);
- break;
- }
-
- // 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];
- }
- break;
- case PT_NODETIMEOUT:
- case PT_CLIENTQUIT:
- if (!server)
- break;
-
- // nodeingame will be put false in the execution of kick command
- // this allow to send some packets to the quitting client to have their ack back
- nodewaiting[node] = 0;
- if (netconsole != -1 && playeringame[netconsole])
- {
- XBOXSTATIC UINT8 buf[2];
- buf[0] = (UINT8)netconsole;
- if (netbuffer->packettype == PT_NODETIMEOUT)
- buf[1] = KICK_MSG_TIMEOUT;
- else
- buf[1] = KICK_MSG_PLAYER_QUIT;
- SendNetXCmd(XD_KICK, &buf, 2);
- nodetoplayer[node] = -1;
- if (nodetoplayer2[node] != -1 && nodetoplayer2[node] >= 0
- && playeringame[(UINT8)nodetoplayer2[node]])
- {
- buf[0] = nodetoplayer2[node];
- SendNetXCmd(XD_KICK, &buf, 2);
- nodetoplayer2[node] = -1;
- }
- }
- Net_CloseConnection(node);
- nodeingame[node] = false;
- break;
-// -------------------------------------------- CLIENT RECEIVE ----------
- case PT_RESYNCHEND:
- // Only accept PT_RESYNCHEND from the server.
- if (node != servernode)
- {
- CONS_Alert(CONS_WARNING, M_GetText("%s recieved from non-host %d\n"), "PT_RESYNCHEND", node);
-
- if (server)
- {
- XBOXSTATIC UINT8 buf[2];
- buf[0] = (UINT8)node;
- buf[1] = KICK_MSG_CON_FAIL;
- SendNetXCmd(XD_KICK, &buf, 2);
- }
-
- break;
- }
- resynch_local_inprogress = false;
-
- P_SetRandSeed(netbuffer->u.resynchend.randomseed);
-
- if (gametype == GT_CTF)
- resynch_read_ctf(&netbuffer->u.resynchend);
- resynch_read_others(&netbuffer->u.resynchend);
-
- break;
- case PT_SERVERTICS:
- // Only accept PT_SERVERTICS from the server.
- if (node != servernode)
- {
- CONS_Alert(CONS_WARNING, M_GetText("%s recieved from non-host %d\n"), "PT_SERVERTICS", node);
-
- if (server)
- {
- XBOXSTATIC UINT8 buf[2];
- buf[0] = (UINT8)node;
- buf[1] = KICK_MSG_CON_FAIL;
- SendNetXCmd(XD_KICK, &buf, 2);
- }
-
- break;
- }
-
- realstart = ExpandTics(netbuffer->u.serverpak.starttic);
- realend = realstart + netbuffer->u.serverpak.numtics;
-
- if (!txtpak)
- txtpak = (UINT8 *)&netbuffer->u.serverpak.cmds[netbuffer->u.serverpak.numslots
- * netbuffer->u.serverpak.numtics];
-
- if (realend > gametic + BACKUPTICS)
- realend = gametic + BACKUPTICS;
- cl_packetmissed = realstart > neededtic;
-
- if (realstart <= neededtic && realend > neededtic)
- {
- tic_t i, j;
- pak = (UINT8 *)&netbuffer->u.serverpak.cmds;
-
- for (i = realstart; i < realend; i++)
- {
- // clear first
- D_Clearticcmd(i);
-
- // copy the tics
- pak = G_ScpyTiccmd(netcmds[i%BACKUPTICS], pak,
- netbuffer->u.serverpak.numslots*sizeof (ticcmd_t));
-
- // copy the textcmds
- numtxtpak = *txtpak++;
- for (j = 0; j < numtxtpak; j++)
- {
- INT32 k = *txtpak++; // playernum
- const size_t txtsize = txtpak[0]+1;
-
- M_Memcpy(D_GetTextcmd(i, k), txtpak, txtsize);
- txtpak += txtsize;
- }
- }
-
- neededtic = realend;
- }
- else
- DEBFILE(va("frame not in bound: %u\n", neededtic));
- break;
- case PT_RESYNCHING:
- // Only accept PT_RESYNCHING from the server.
- if (node != servernode)
- {
- CONS_Alert(CONS_WARNING, M_GetText("%s recieved from non-host %d\n"), "PT_RESYNCHING", node);
-
- if (server)
- {
- XBOXSTATIC char buf[2];
- buf[0] = (char)node;
- buf[1] = KICK_MSG_CON_FAIL;
- SendNetXCmd(XD_KICK, &buf, 2);
- }
-
- break;
- }
- resynch_local_inprogress = true;
- CL_AcknowledgeResynch(&netbuffer->u.resynchpak);
- break;
-#ifdef NEWPING
- case PT_PING:
- // Only accept PT_PING from the server.
- if (node != servernode)
- {
- CONS_Alert(CONS_WARNING, M_GetText("%s recieved from non-host %d\n"), "PT_PING", node);
-
- if (server)
- {
- XBOXSTATIC char buf[2];
- buf[0] = (char)node;
- buf[1] = KICK_MSG_CON_FAIL;
- SendNetXCmd(XD_KICK, &buf, 2);
- }
-
- break;
- }
-
- //Update client ping table from the server.
- if (!server)
- {
- INT32 i;
- for (i = 0; i < MAXNETNODES; i++)
- if (playeringame[i])
- playerpingtable[i] = (tic_t)netbuffer->u.pingtable[i];
- }
-
- break;
-#endif
- case PT_SERVERCFG:
- break;
- case PT_FILEFRAGMENT:
- if (!server)
- Got_Filetxpak();
- break;
- default:
- DEBFILE(va("UNKNOWN PACKET TYPE RECEIVED %d from host %d\n",
- netbuffer->packettype, node));
- } // end switch
- } // end while
+ // Packet received from someone already playing
+ if (nodeingame[node])
+ HandlePacketFromPlayer(node);
+ // Packet received from someone not playing
+ else
+ HandlePacketFromAwayNode(node);
+ }
}
//
@@ -3768,6 +4088,10 @@ static INT16 Consistancy(void)
{
INT32 i;
UINT32 ret = 0;
+#ifdef MOBJCONSISTANCY
+ thinker_t *th;
+ mobj_t *mo;
+#endif
DEBFILE(va("TIC %u ", gametic));
@@ -3789,6 +4113,77 @@ static INT16 Consistancy(void)
if (!G_PlatformGametype())
ret += P_GetRandSeed();
+#ifdef MOBJCONSISTANCY
+ if (!thinkercap.next)
+ return ret;
+ for (th = thinkercap.next; th != &thinkercap; th = th->next)
+ {
+ if (th->function.acp1 != (actionf_p1)P_MobjThinker)
+ continue;
+
+ mo = (mobj_t *)th;
+
+ if (mo->flags & (MF_SPECIAL | MF_SOLID | MF_PUSHABLE | MF_BOSS | MF_MISSILE | MF_SPRING | MF_MONITOR | MF_FIRE | MF_ENEMY | MF_PAIN | MF_STICKY))
+ {
+ ret -= mo->type;
+ ret += mo->x;
+ ret -= mo->y;
+ ret += mo->z;
+ ret -= mo->momx;
+ ret += mo->momy;
+ ret -= mo->momz;
+ ret += mo->angle;
+ ret -= mo->flags;
+ ret += mo->flags2;
+ ret -= mo->eflags;
+ if (mo->target)
+ {
+ ret += mo->target->type;
+ ret -= mo->target->x;
+ ret += mo->target->y;
+ ret -= mo->target->z;
+ ret += mo->target->momx;
+ ret -= mo->target->momy;
+ ret += mo->target->momz;
+ ret -= mo->target->angle;
+ ret += mo->target->flags;
+ ret -= mo->target->flags2;
+ ret += mo->target->eflags;
+ ret -= mo->target->state - states;
+ ret += mo->target->tics;
+ ret -= mo->target->sprite;
+ ret += mo->target->frame;
+ }
+ else
+ ret ^= 0x3333;
+ if (mo->tracer && mo->tracer->type != MT_OVERLAY)
+ {
+ ret += mo->tracer->type;
+ ret -= mo->tracer->x;
+ ret += mo->tracer->y;
+ ret -= mo->tracer->z;
+ ret += mo->tracer->momx;
+ ret -= mo->tracer->momy;
+ ret += mo->tracer->momz;
+ ret -= mo->tracer->angle;
+ ret += mo->tracer->flags;
+ ret -= mo->tracer->flags2;
+ ret += mo->tracer->eflags;
+ ret -= mo->tracer->state - states;
+ ret += mo->tracer->tics;
+ ret -= mo->tracer->sprite;
+ ret += mo->tracer->frame;
+ }
+ else
+ ret ^= 0xAAAA;
+ ret -= mo->state - states;
+ ret += mo->tics;
+ ret -= mo->sprite;
+ ret += mo->frame;
+ }
+ }
+#endif
+
return (INT16)(ret & 0xFFFF);
}
@@ -3806,7 +4201,7 @@ static void CL_SendClientCmd(void)
if (gamestate == GS_WAITINGPLAYERS)
{
- // send NODEKEEPALIVE packet
+ // Send PT_NODEKEEPALIVE packet
netbuffer->packettype += 4;
packetsize = sizeof (clientcmd_pak) - sizeof (ticcmd_t) - sizeof (INT16);
HSendPacket(servernode, false, 0, packetsize);
@@ -3816,7 +4211,7 @@ static void CL_SendClientCmd(void)
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
+ // Send a special packet with 2 cmd for splitscreen
if (splitscreen || botingame)
{
netbuffer->packettype += 2;
@@ -3829,25 +4224,25 @@ static void CL_SendClientCmd(void)
HSendPacket(servernode, false, 0, packetsize);
}
- if (cl_mode == cl_connected || dedicated)
+ if (cl_mode == CL_CONNECTED || dedicated)
{
- // send extra data if needed
+ // 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 sended
- if (HSendPacket(servernode, true, 0, localtextcmd[0]+1)) // send can fail...
+ // 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)
+ // 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 sended
- if (HSendPacket(servernode, true, 0, localtextcmd2[0]+1)) // send can fail...
+ // All extra data have been sent
+ if (HSendPacket(servernode, true, 0, localtextcmd2[0]+1)) // Send can fail...
localtextcmd2[0] = 0;
}
}
@@ -4111,7 +4506,7 @@ static inline void PingUpdate(void)
//check for ping limit breakage.
if (cv_maxping.value)
{
- for (i = 1; i < MAXNETNODES; i++)
+ for (i = 1; i < MAXPLAYERS; i++)
{
if (playeringame[i] && (realpingtable[i] / pingmeasurecount > (unsigned)cv_maxping.value))
{
@@ -4125,7 +4520,7 @@ static inline void PingUpdate(void)
//in that case, it is probably the server's fault.
if (numlaggers < D_NumPlayers() - 1)
{
- for (i = 1; i < MAXNETNODES; i++)
+ for (i = 1; i < MAXPLAYERS; i++)
{
if (playeringame[i] && laggers[i])
{
@@ -4140,7 +4535,7 @@ static inline void PingUpdate(void)
}
//make the ping packet and clear server data for next one
- for (i = 0; i < MAXNETNODES; i++)
+ for (i = 0; i < MAXPLAYERS; i++)
{
netbuffer->u.pingtable[i] = realpingtable[i] / pingmeasurecount;
//server takes a snapshot of the real ping for display.
@@ -4150,7 +4545,7 @@ static inline void PingUpdate(void)
}
//send out our ping packets
- for (i = 0; i < MAXNETNODES; i++)
+ for (i = 0; i < MAXPLAYERS; i++)
if (playeringame[i])
HSendPacket(i, true, 0, sizeof(INT32) * MAXPLAYERS);
@@ -4199,7 +4594,7 @@ void NetUpdate(void)
}
#endif
- if (!server)
+ if (client)
maketic = neededtic;
Local_Maketic(realtics); // make local tic, and call menu?
@@ -4212,12 +4607,12 @@ FILESTAMP
// client send the command after a receive of the server
// the server send before because in single player is beter
- MasterClient_Ticker(); // acking the master server
+ MasterClient_Ticker(); // Acking the Master Server
- if (!server)
+ if (client)
{
if (!resynch_local_inprogress)
- CL_SendClientCmd(); // send tic cmd
+ CL_SendClientCmd(); // Send tic cmd
hu_resynching = resynch_local_inprogress;
}
else
@@ -4243,27 +4638,32 @@ FILESTAMP
counts = -666;
}
- // do not make tics while resynching
+ // Do not make tics while resynching
if (counts != -666)
{
if (maketic + counts >= firstticstosend + BACKUPTICS)
counts = firstticstosend+BACKUPTICS-maketic-1;
for (i = 0; i < counts; i++)
- SV_Maketic(); // create missed tics and increment maketic
+ SV_Maketic(); // Create missed tics and increment maketic
- for (; tictoclear < firstticstosend; tictoclear++) // clear only when acknoledged
- D_Clearticcmd(tictoclear); // clear the maketic the new tic
+ for (; tictoclear < firstticstosend; tictoclear++) // Clear only when acknowledged
+ D_Clearticcmd(tictoclear); // Clear the maketic the new tic
SV_SendTics();
- neededtic = maketic; // the server is a client too
+ neededtic = maketic; // The server is a client too
}
else
hu_resynching = true;
}
}
Net_AckTicker();
+ // Handle timeouts to prevent definitive freezes from happenning
+ if (server)
+ for (i = 1; i < MAXNETNODES; i++)
+ if (nodeingame[i] && freezetimeout[i] < I_GetTime())
+ Net_ConnectionTimeout(i);
nowtime /= NEWTICRATERATIO;
if (nowtime > resptime)
{
@@ -4271,7 +4671,7 @@ FILESTAMP
M_Ticker();
CON_Ticker();
}
- FiletxTicker();
+ SV_FileSendTicker();
}
/** Returns the number of players playing.
diff --git a/src/d_clisrv.h b/src/d_clisrv.h
index 14b59092..e7f1e843 100644
--- a/src/d_clisrv.h
+++ b/src/d_clisrv.h
@@ -59,7 +59,7 @@ typedef enum
// Add non-PT_CANFAIL packet types here to avoid breaking MS compatibility.
PT_CANFAIL, // This is kind of a priority. Anything bigger than CANFAIL
- // allows HSendPacket(,true,,) to return false.
+ // allows HSendPacket(*, true, *, *) to return false.
// In addition, this packet can't occupy all the available slots.
PT_FILEFRAGMENT = PT_CANFAIL, // A part of a file.
@@ -76,11 +76,19 @@ typedef enum
NUMPACKETTYPE
} packettype_t;
+#ifdef PACKETDROP
+void Command_Drop(void);
+void Command_Droprate(void);
+#endif
+#ifdef _DEBUG
+void Command_Numnodes(void);
+#endif
+
#if defined(_MSC_VER)
#pragma pack(1)
#endif
-// client to server packet
+// Client to server packet
typedef struct
{
UINT8 client_tic;
@@ -89,7 +97,7 @@ typedef struct
ticcmd_t cmd;
} ATTRPACK clientcmd_pak;
-// splitscreen packet
+// Splitscreen packet
// WARNING: must have the same format of clientcmd_pak, for more easy use
typedef struct
{
@@ -110,16 +118,16 @@ typedef struct
UINT8 starttic;
UINT8 numtics;
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]; // Normally [BACKUPTIC][MAXPLAYERS] but too large
} ATTRPACK servertics_pak;
-// sent to client when all consistency data
+// Sent to client when all consistency data
// for players has been restored
typedef struct
{
UINT32 randomseed;
- //ctf flag stuff
+ // CTF flag stuff
SINT8 flagplayer[2];
INT32 flagloose[2];
INT32 flagflags[2];
@@ -127,11 +135,11 @@ typedef struct
fixed_t flagy[2];
fixed_t flagz[2];
- UINT32 ingame; // spectator bit for each player
- UINT32 ctfteam; // if not spectator, then which team?
+ UINT32 ingame; // Spectator bit for each player
+ INT32 ctfteam[MAXPLAYERS]; // Which team? (can't be 1 bit, since in regular Match there are no teams)
// Resynch game scores and the like all at once
- UINT32 score[MAXPLAYERS]; // Everyone's score.
+ UINT32 score[MAXPLAYERS]; // Everyone's score
INT16 numboxes[MAXPLAYERS];
INT16 totalring[MAXPLAYERS];
tic_t realtime[MAXPLAYERS];
@@ -140,14 +148,14 @@ typedef struct
typedef struct
{
- //player stuff
+ // Player stuff
UINT8 playernum;
// Do not send anything visual related.
// Only send data that we need to know for physics.
- UINT8 playerstate; //playerstate_t
- UINT32 pflags; //pflags_t
- UINT8 panim; //panim_t
+ UINT8 playerstate; // playerstate_t
+ UINT32 pflags; // pflags_t
+ UINT8 panim; // panim_t
angle_t aiming;
INT32 currentweapon;
@@ -174,9 +182,9 @@ typedef struct
UINT8 charability;
UINT8 charability2;
UINT32 charflags;
- UINT32 thokitem; //mobjtype_t
- UINT32 spinitem; //mobjtype_t
- UINT32 revitem; //mobjtype_t
+ UINT32 thokitem; // mobjtype_t
+ UINT32 spinitem; // mobjtype_t
+ UINT32 revitem; // mobjtype_t
fixed_t actionspd;
fixed_t mindash;
fixed_t maxdash;
@@ -230,7 +238,7 @@ typedef struct
INT32 onconveyor;
//player->mo stuff
- UINT8 hasmo; //boolean
+ UINT8 hasmo; // Boolean
angle_t angle;
fixed_t x;
@@ -257,10 +265,10 @@ typedef struct
typedef struct
{
- UINT8 version; // different versions don't work
- UINT8 subversion; // contains build version
+ UINT8 version; // Different versions don't work
+ UINT8 subversion; // Contains build version
- // server launch stuffs
+ // Server launch stuffs
UINT8 serverplayer;
UINT8 totalslotnum; // "Slots": highest player number in use plus one.
@@ -274,18 +282,18 @@ typedef struct
UINT8 gametype;
UINT8 modifiedgame;
- SINT8 adminplayer; // needs to be signed
+ SINT8 adminplayer; // Needs to be signed
- char server_context[8]; // unique context id, generated at server startup.
+ char server_context[8]; // Unique context id, generated at server startup.
- UINT8 varlengthinputs[0]; // playernames and netvars
+ UINT8 varlengthinputs[0]; // Playernames and netvars
} ATTRPACK serverconfig_pak;
typedef struct {
UINT8 fileid;
UINT32 position;
UINT16 size;
- UINT8 data[0]; // size is variable using hardware_MAXPACKETLENGTH
+ UINT8 data[0]; // Size is variable using hardware_MAXPACKETLENGTH
} ATTRPACK filetx_pak;
#ifdef _MSC_VER
@@ -294,14 +302,14 @@ typedef struct {
typedef struct
{
- UINT8 version; // different versions don't work
- UINT8 subversion; // contains build version
+ UINT8 version; // Different versions don't work
+ UINT8 subversion; // Contains build version
UINT8 localplayers;
UINT8 mode;
} ATTRPACK clientconfig_pak;
#define MAXSERVERNAME 32
-// this packet is too large
+// This packet is too large
typedef struct
{
UINT8 version;
@@ -367,45 +375,45 @@ typedef struct
} ATTRPACK plrconfig;
//
-// Network packet data.
+// Network packet data
//
typedef struct
{
UINT32 checksum;
- UINT8 ack; // if not null the node asks for acknowledgement, the receiver must resend the ack
- UINT8 ackreturn; // the return of the ack number
+ UINT8 ack; // If not zero the node asks for acknowledgement, the receiver must resend the ack
+ UINT8 ackreturn; // The return of the ack number
UINT8 packettype;
- UINT8 reserved; // padding
+ UINT8 reserved; // Padding
union
{
- clientcmd_pak clientpak; // 144 bytes
- client2cmd_pak client2pak; // 200 bytes
- servertics_pak serverpak; // 132495 bytes
- serverconfig_pak servercfg; // 773 bytes
- resynchend_pak resynchend; //
- resynch_pak resynchpak; //
- UINT8 resynchgot; //
- UINT8 textcmd[MAXTEXTCMD+1]; // 66049 bytes
- filetx_pak filetxpak; // 139 bytes
- clientconfig_pak clientcfg; // 136 bytes
- serverinfo_pak serverinfo; // 1024 bytes
- serverrefuse_pak serverrefuse; // 65025 bytes
- askinfo_pak askinfo; // 61 bytes
- msaskinfo_pak msaskinfo; // 22 bytes
- plrinfo playerinfo[MAXPLAYERS]; // 1152 bytes
- plrconfig playerconfig[MAXPLAYERS]; // (up to) 896 bytes
+ clientcmd_pak clientpak; // 144 bytes
+ client2cmd_pak client2pak; // 200 bytes
+ servertics_pak serverpak; // 132495 bytes (more around 360, no?)
+ serverconfig_pak servercfg; // 773 bytes
+ resynchend_pak resynchend; //
+ resynch_pak resynchpak; //
+ UINT8 resynchgot; //
+ UINT8 textcmd[MAXTEXTCMD+1]; // 66049 bytes (wut??? 64k??? More like 257 bytes...)
+ filetx_pak filetxpak; // 139 bytes
+ clientconfig_pak clientcfg; // 136 bytes
+ serverinfo_pak serverinfo; // 1024 bytes
+ serverrefuse_pak serverrefuse; // 65025 bytes (somehow I feel like those values are garbage...)
+ askinfo_pak askinfo; // 61 bytes
+ msaskinfo_pak msaskinfo; // 22 bytes
+ plrinfo playerinfo[MAXPLAYERS]; // 1152 bytes (I'd say 36~38)
+ plrconfig playerconfig[MAXPLAYERS]; // (up to) 896 bytes (welp they ARE)
#ifdef NEWPING
- UINT32 pingtable[MAXPLAYERS]; // 128 bytes
+ UINT32 pingtable[MAXPLAYERS]; // 128 bytes
#endif
- } 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;
#if defined(_MSC_VER)
#pragma pack()
#endif
-#define MAXSERVERLIST 64 // depends only on the display
+#define MAXSERVERLIST 64 // Depends only on the display
typedef struct
{
SINT8 node;
@@ -416,7 +424,7 @@ extern serverelem_t serverlist[MAXSERVERLIST];
extern UINT32 serverlistcount;
extern INT32 mapchangepending;
-// points inside doomcom
+// Points inside doomcom
extern doomdata_t *netbuffer;
extern consvar_t cv_playbackspeed;
@@ -437,26 +445,28 @@ extern consvar_t cv_playbackspeed;
#define KICK_MSG_CUSTOM_BAN 8
extern boolean server;
-extern boolean dedicated; // for dedicated server
+#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;
#ifdef NEWPING
extern UINT16 pingmeasurecount;
extern UINT32 realpingtable[MAXPLAYERS];
extern UINT32 playerpingtable[MAXPLAYERS];
#endif
-extern consvar_t cv_joinnextround, cv_allownewplayer, cv_maxplayers, cv_resynchattempts, cv_blamecfail, cv_maxsend;
+extern consvar_t cv_joinnextround, cv_allownewplayer, cv_maxplayers, cv_resynchattempts, cv_blamecfail, cv_maxsend, cv_noticedownload, cv_downloadspeed;
-// used in d_net, the only dependence
+// Used in d_net, the only dependence
tic_t ExpandTics(INT32 low);
void D_ClientServerInit(void);
-// initialise the other field
+// 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
@@ -474,14 +484,14 @@ void CL_RemoveSplitscreenPlayer(void);
void CL_Reset(void);
void CL_ClearPlayer(INT32 playernum);
void CL_UpdateServerList(boolean internetsearch, INT32 room);
-// is there a game running
+// 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?
+//? How many ticks to run?
void TryRunTics(tic_t realtic);
// extra data for lmps
diff --git a/src/d_main.c b/src/d_main.c
index 14a8a06e..4080087c 100644
--- a/src/d_main.c
+++ b/src/d_main.c
@@ -73,6 +73,7 @@ int snprintf(char *str, size_t n, const char *fmt, ...);
#include "dehacked.h" // Dehacked list test
#include "m_cond.h" // condition initialization
#include "fastcmp.h"
+#include "keys.h"
#ifdef CMAKECONFIG
#include "config.h"
@@ -176,6 +177,38 @@ void D_PostEvent(const event_t *ev)
void D_PostEvent_end(void) {};
#endif
+// modifier keys
+UINT8 shiftdown = 0; // 0x1 left, 0x2 right
+UINT8 ctrldown = 0; // 0x1 left, 0x2 right
+UINT8 altdown = 0; // 0x1 left, 0x2 right
+//
+// D_ModifierKeyResponder
+// Sets global shift/ctrl/alt variables, never actually eats events
+//
+static inline void D_ModifierKeyResponder(event_t *ev)
+{
+ if (ev->type == ev_keydown || ev->type == ev_console) switch (ev->data1)
+ {
+ case KEY_LSHIFT: shiftdown |= 0x1; return;
+ case KEY_RSHIFT: shiftdown |= 0x2; return;
+ case KEY_LCTRL: ctrldown |= 0x1; return;
+ case KEY_RCTRL: ctrldown |= 0x2; return;
+ case KEY_LALT: altdown |= 0x1; return;
+ case KEY_RALT: altdown |= 0x2; return;
+ default: return;
+ }
+ else if (ev->type == ev_keyup) switch (ev->data1)
+ {
+ case KEY_LSHIFT: shiftdown &= ~0x1; return;
+ case KEY_RSHIFT: shiftdown &= ~0x2; return;
+ case KEY_LCTRL: ctrldown &= ~0x1; return;
+ case KEY_RCTRL: ctrldown &= ~0x2; return;
+ case KEY_LALT: altdown &= ~0x1; return;
+ case KEY_RALT: altdown &= ~0x2; return;
+ default: return;
+ }
+}
+
//
// D_ProcessEvents
// Send all the events of the given timestamp down the responder chain
@@ -188,6 +221,9 @@ void D_ProcessEvents(void)
{
ev = &events[eventtail];
+ // Set global shift/ctrl/alt down variables
+ D_ModifierKeyResponder(ev); // never eats events
+
// Screenshots over everything so that they can be taken anywhere.
if (M_ScreenshotResponder(ev))
continue; // ate the event
@@ -1060,10 +1096,11 @@ void D_SRB2Main(void)
if (M_CheckParm("-warp") && M_IsNextParm())
{
const char *word = M_GetNextParm();
- if (fastncmp(word, "MAP", 3))
+ char ch; // use this with sscanf to catch non-digits with
+ if (fastncmp(word, "MAP", 3)) // MAPxx name
pstartmap = M_MapNumber(word[3], word[4]);
- else
- pstartmap = atoi(word);
+ else if (sscanf(word, "%d%c", &pstartmap, &ch) != 1) // a plain number
+ I_Error("Cannot warp to map %s (invalid map name)\n", word);
// Don't check if lump exists just yet because the wads haven't been loaded!
// Just do a basic range check here.
if (pstartmap < 1 || pstartmap > NUMMAPS)
diff --git a/src/d_main.h b/src/d_main.h
index 88387a57..6dc273b1 100644
--- a/src/d_main.h
+++ b/src/d_main.h
@@ -41,7 +41,7 @@ void D_SRB2Main(void);
// Called by IO functions when input is detected.
void D_PostEvent(const event_t *ev);
#ifndef DOXYGEN
-void D_PostEvent_end(void); // delimiter for locking memory
+FUNCMATH void D_PostEvent_end(void); // delimiter for locking memory
#endif
void D_ProcessEvents(void);
diff --git a/src/d_net.c b/src/d_net.c
index 03e126b5..50b6c8cf 100644
--- a/src/d_net.c
+++ b/src/d_net.c
@@ -31,18 +31,18 @@
//
// NETWORKING
//
-// gametic is the tic about to be (or currently being) run
-// server:
+// gametic is the tic about to (or currently being) run
+// Server:
// maketic is the tic that hasn't had control made for it yet
-// nettics: is the tic for each node
-// firsttictosend: is the lowest value of nettics
-// client:
-// neededtic: is the tic needed by the client to run the game
-// firsttictosend: is used to optimize a condition
-// normally maketic >= gametic > 0
+// nettics is the tic for each node
+// firstticstosend is the lowest value of nettics
+// Client:
+// neededtic is the tic needed by the client to run the game
+// firstticstosend is used to optimize a condition
+// Normally maketic >= gametic > 0
#define FORCECLOSE 0x8000
-tic_t connectiontimeout = (15*TICRATE);
+tic_t connectiontimeout = (10*TICRATE);
/// \brief network packet
doomcom_t *doomcom = NULL;
@@ -62,7 +62,7 @@ INT32 net_bandwidth;
/// \brief max length per packet
INT16 hardware_MAXPACKETLENGTH;
-void (*I_NetGet)(void) = NULL;
+boolean (*I_NetGet)(void) = NULL;
void (*I_NetSend)(void) = NULL;
boolean (*I_NetCanSend)(void) = NULL;
boolean (*I_NetCanGet)(void) = NULL;
@@ -129,9 +129,9 @@ boolean Net_GetNetStat(void)
// -----------------------------------------------------------------
// Some structs and functions for acknowledgement of packets
// -----------------------------------------------------------------
-#define MAXACKPACKETS 96 // minimum number of nodes
+#define MAXACKPACKETS 96 // Minimum number of nodes (wat)
#define MAXACKTOSEND 96
-#define URGENTFREESLOTENUM 10
+#define URGENTFREESLOTNUM 10
#define ACKTOSENDTIMEOUT (TICRATE/11)
#ifndef NONET
@@ -139,10 +139,10 @@ typedef struct
{
UINT8 acknum;
UINT8 nextacknum;
- UINT8 destinationnode;
- tic_t senttime;
- UINT16 length;
- UINT16 resentnum;
+ UINT8 destinationnode; // The node to send the ack to
+ tic_t senttime; // The time when the ack was sent
+ UINT16 length; // The packet size
+ UINT16 resentnum; // The number of times the ack has been resent
union {
SINT8 raw[MAXPACKETLENGTH];
doomdata_t data;
@@ -152,11 +152,12 @@ typedef struct
typedef enum
{
- CLOSE = 1, // flag is set when connection is closing
+ NF_CLOSE = 1, // Flag is set when connection is closing
+ NF_TIMEOUT = 2, // Flag is set when the node got a timeout
} node_flags_t;
#ifndef NONET
-// table of packet that was not acknowleged can be resend (the sender window)
+// Table of packets that were not acknowleged can be resent (the sender window)
static ackpak_t ackpak[MAXACKPACKETS];
#endif
@@ -212,11 +213,16 @@ FUNCMATH static INT32 cmpack(UINT8 a, UINT8 b)
return d;
}
-// return a free acknum and copy netbuffer in the ackpak table
+/** Sets freeack to a free acknum and copies the netbuffer in the ackpak table
+ *
+ * \param freeack The address to store the free acknum at
+ * \param lowtimer ???
+ * \return True if a free acknum was found
+ */
static boolean GetFreeAcknum(UINT8 *freeack, boolean lowtimer)
{
node_t *node = &nodes[doomcom->remotenode];
- INT32 i, numfreeslote = 0;
+ INT32 i, numfreeslot = 0;
if (cmpack((UINT8)((node->remotefirstack + MAXACKTOSEND) % 256), node->nextacknum) < 0)
{
@@ -227,10 +233,13 @@ static boolean GetFreeAcknum(UINT8 *freeack, boolean lowtimer)
for (i = 0; i < MAXACKPACKETS; i++)
if (!ackpak[i].acknum)
{
- // for low priority packet, make sure let freeslotes so urgents packets can be sent
- numfreeslote++;
- if (netbuffer->packettype >= PT_CANFAIL && numfreeslote < URGENTFREESLOTENUM)
- continue;
+ // For low priority packets, make sure to let freeslots so urgent packets can be sent
+ if (netbuffer->packettype >= PT_CANFAIL)
+ {
+ numfreeslot++;
+ if (numfreeslot <= URGENTFREESLOTNUM)
+ continue;
+ }
ackpak[i].acknum = node->nextacknum;
ackpak[i].nextacknum = node->nextacknum;
@@ -241,7 +250,7 @@ static boolean GetFreeAcknum(UINT8 *freeack, boolean lowtimer)
ackpak[i].length = doomcom->datalength;
if (lowtimer)
{
- // lowtime mean can't be sent now so try it soon as possible
+ // Lowtime means can't be sent now so try it as soon as possible
ackpak[i].senttime = 0;
ackpak[i].resentnum = 1;
}
@@ -254,7 +263,7 @@ static boolean GetFreeAcknum(UINT8 *freeack, boolean lowtimer)
*freeack = ackpak[i].acknum;
- sendackpacket++; // for stat
+ sendackpacket++; // For stat
return true;
}
@@ -266,14 +275,46 @@ static boolean GetFreeAcknum(UINT8 *freeack, boolean lowtimer)
return false;
}
-// Get a ack to send in the queu of this node
+/** Counts how many acks are free
+ *
+ * \param urgent True if the type of the packet meant to
+ * use an ack is lower than PT_CANFAIL
+ * If for some reason you don't want use it
+ * for any packet type in particular,
+ * just set to false
+ * \return The number of free acks
+ *
+ */
+INT32 Net_GetFreeAcks(boolean urgent)
+{
+ INT32 i, numfreeslot = 0;
+ INT32 n = 0; // Number of free acks found
+
+ for (i = 0; i < MAXACKPACKETS; i++)
+ if (!ackpak[i].acknum)
+ {
+ // For low priority packets, make sure to let freeslots so urgent packets can be sent
+ if (!urgent)
+ {
+ numfreeslot++;
+ if (numfreeslot <= URGENTFREESLOTNUM)
+ continue;
+ }
+
+ n++;
+ }
+
+ return n;
+}
+
+// Get a ack to send in the queue of this node
static UINT8 GetAcktosend(INT32 node)
{
nodes[node].lasttimeacktosend_sent = I_GetTime();
return nodes[node].firstacktosend;
}
-static void Removeack(INT32 i)
+static void RemoveAck(INT32 i)
{
INT32 node = ackpak[i].destinationnode;
#ifndef NEWPING
@@ -290,31 +331,31 @@ static void Removeack(INT32 i)
DEBFILE(va("Remove ack %d\n",ackpak[i].acknum));
#endif
ackpak[i].acknum = 0;
- if (nodes[node].flags & CLOSE)
+ if (nodes[node].flags & NF_CLOSE)
Net_CloseConnection(node);
}
-// 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)
{
INT32 i;
boolean goodpacket = true;
node_t *node = &nodes[doomcom->remotenode];
- // received an ack return, so remove the ack in the list
+ // Received an ack return, so remove the ack in the list
if (netbuffer->ackreturn && cmpack(node->remotefirstack, netbuffer->ackreturn) < 0)
{
node->remotefirstack = netbuffer->ackreturn;
- // search the ackbuffer and free it
+ // Search the ackbuffer and free it
for (i = 0; i < MAXACKPACKETS; i++)
if (ackpak[i].acknum && ackpak[i].destinationnode == node - nodes
&& cmpack(ackpak[i].acknum, netbuffer->ackreturn) <= 0)
{
- Removeack(i);
+ RemoveAck(i);
}
}
- // received a packet with ack, queue it to send the ack back
+ // Received a packet with ack, queue it to send the ack back
if (netbuffer->ack)
{
UINT8 ack = netbuffer->ack;
@@ -323,23 +364,23 @@ static boolean Processackpak(void)
{
DEBFILE(va("Discard(1) ack %d (duplicated)\n", ack));
duppacket++;
- goodpacket = false; // discard packet (duplicate)
+ goodpacket = false; // Discard packet (duplicate)
}
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)
if (node->acktosend[i] == ack)
{
DEBFILE(va("Discard(2) ack %d (duplicated)\n", ack));
duppacket++;
- goodpacket = false; // discard packet (duplicate)
+ goodpacket = false; // Discard packet (duplicate)
break;
}
if (goodpacket)
{
- // is a good packet so increment the acknowledge number,
- // then search for a "hole" in the queue
+ // Is a good packet so increment the acknowledge number,
+ // Then search for a "hole" in the queue
UINT8 nextfirstack = (UINT8)(node->firstacktosend + 1);
if (!nextfirstack)
nextfirstack = 1;
@@ -383,10 +424,10 @@ static boolean Processackpak(void)
}
}
}
- else // out of order packet
+ else // Out of order packet
{
- // don't increment firsacktosend, put it in asktosend queue
- // will be incremented when the nextfirstack comes (code above)
+ // Don't increment firsacktosend, put it in asktosend queue
+ // Will be incremented when the nextfirstack comes (code above)
UINT8 newhead = (UINT8)((node->acktosend_head+1) % MAXACKTOSEND);
DEBFILE(va("out of order packet (%d expected)\n", nextfirstack));
if (newhead != node->acktosend_tail)
@@ -394,8 +435,8 @@ static boolean Processackpak(void)
node->acktosend[node->acktosend_head] = ack;
node->acktosend_head = newhead;
}
- else // buffer full discard packet, sender will resend it
- { // we can admit the packet but we will not detect the duplication after :(
+ else // Buffer full discard packet, sender will resend it
+ { // We can admit the packet but we will not detect the duplication after :(
DEBFILE("no more freeackret\n");
goodpacket = false;
}
@@ -430,25 +471,29 @@ static void GotAcks(void)
if (ackpak[i].acknum && ackpak[i].destinationnode == doomcom->remotenode)
{
if (ackpak[i].acknum == netbuffer->u.textcmd[j])
- Removeack(i);
- else
- // nextacknum is first equal to acknum, then when receiving bigger ack
- // there is big chance the packet is lost
- // when resent, nextacknum = nodes[node].nextacknum
- // will redo the same but with different value
- if (cmpack(ackpak[i].nextacknum, netbuffer->u.textcmd[j]) <= 0
- && ackpak[i].senttime > 0)
- {
- ackpak[i].senttime--; // hurry up
- }
+ RemoveAck(i);
+ // nextacknum is first equal to acknum, then when receiving bigger ack
+ // there is big chance the packet is lost
+ // When resent, nextacknum = nodes[node].nextacknum
+ // will redo the same but with different value
+ else if (cmpack(ackpak[i].nextacknum, netbuffer->u.textcmd[j]) <= 0
+ && ackpak[i].senttime > 0)
+ {
+ ackpak[i].senttime--; // hurry up
+ }
}
}
#endif
-static inline void Net_ConnectionTimeout(INT32 node)
+void Net_ConnectionTimeout(INT32 node)
{
- // send a very special packet to self (hack the reboundstore queue)
- // main code will handle it
+ // Don't timeout several times
+ if (nodes[node].flags & NF_TIMEOUT)
+ return;
+ nodes[node].flags |= NF_TIMEOUT;
+
+ // Send a very special packet to self (hack the reboundstore queue)
+ // Main code will handle it
reboundstore[rebound_head].packettype = PT_NODETIMEOUT;
reboundstore[rebound_head].ack = 0;
reboundstore[rebound_head].ackreturn = 0;
@@ -456,12 +501,12 @@ static inline void Net_ConnectionTimeout(INT32 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!)
nodes[node].lasttimepacketreceived = I_GetTime();
}
-// resend the data if needed
+// Resend the data if needed
void Net_AckTicker(void)
{
#ifndef NONET
@@ -477,7 +522,7 @@ void Net_AckTicker(void)
if (ackpak[i].acknum && ackpak[i].senttime + node->timeout < I_GetTime())
#endif
{
- if (ackpak[i].resentnum > 10 && (node->flags & CLOSE))
+ if (ackpak[i].resentnum > 10 && (node->flags & NF_CLOSE))
{
DEBFILE(va("ack %d sent 10 times so connection is supposed lost: node %d\n",
i, nodei));
@@ -497,7 +542,7 @@ void Net_AckTicker(void)
ackpak[i].senttime = I_GetTime();
ackpak[i].resentnum++;
ackpak[i].nextacknum = node->nextacknum;
- retransmit++; // for stat
+ retransmit++; // For stat
HSendPacket((INT32)(node - nodes), false, ackpak[i].acknum,
(size_t)(ackpak[i].length - BASEPACKETSIZE));
}
@@ -505,15 +550,15 @@ void Net_AckTicker(void)
for (i = 1; i < MAXNETNODES; i++)
{
- // this is something like node open flag
+ // This is something like node open flag
if (nodes[i].firstacktosend)
{
- // we haven't sent a packet for a long time
- // acknowledge packet if needed
+ // We haven't sent a packet for a long time
+ // Acknowledge packet if needed
if (nodes[i].lasttimeacktosend_sent + ACKTOSENDTIMEOUT < I_GetTime())
Net_SendAcks(i);
- if (!(nodes[i].flags & CLOSE)
+ if (!(nodes[i].flags & NF_CLOSE)
&& nodes[i].lasttimepacketreceived + connectiontimeout < I_GetTime())
{
Net_ConnectionTimeout(i);
@@ -523,9 +568,9 @@ void Net_AckTicker(void)
#endif
}
-// remove last packet received ack before resending the ackret
+// Remove last packet received ack before resending the ackreturn
// (the higher layer doesn't have room, or something else ....)
-void Net_UnAcknowledgPacket(INT32 node)
+void Net_UnAcknowledgePacket(INT32 node)
{
#ifdef NONET
(void)node;
@@ -564,20 +609,29 @@ void Net_UnAcknowledgPacket(INT32 node)
#endif
}
-boolean Net_AllAckReceived(void)
-{
#ifndef NONET
+/** Checks if all acks have been received
+ *
+ * \return True if all acks have been received
+ *
+ */
+static boolean Net_AllAcksReceived(void)
+{
INT32 i;
for (i = 0; i < MAXACKPACKETS; i++)
if (ackpak[i].acknum)
return false;
-#endif
return true;
}
+#endif
-// wait for all ackreturns with timeout in seconds
+/** Waits for all ackreturns
+ *
+ * \param timeout Timeout in seconds
+ *
+ */
void Net_WaitAllAckReceived(UINT32 timeout)
{
#ifdef NONET
@@ -587,7 +641,7 @@ void Net_WaitAllAckReceived(UINT32 timeout)
timeout = tictac + timeout*NEWTICRATE;
HGetPacket();
- while (timeout > I_GetTime() && !Net_AllAckReceived())
+ while (timeout > I_GetTime() && !Net_AllAcksReceived())
{
while (tictac == I_GetTime())
I_Sleep();
@@ -598,18 +652,18 @@ void Net_WaitAllAckReceived(UINT32 timeout)
#endif
}
-static void InitNode(INT32 node)
+static void InitNode(node_t *node)
{
- nodes[node].acktosend_head = nodes[node].acktosend_tail = 0;
+ node->acktosend_head = node->acktosend_tail = 0;
#ifndef NEWPING
- nodes[node].ping = PINGDEFAULT;
- nodes[node].varping = VARPINGDEFAULT;
- nodes[node].timeout = TIMEOUT(nodes[node].ping,nodes[node].varping);
+ node->ping = PINGDEFAULT;
+ node->varping = VARPINGDEFAULT;
+ node->timeout = TIMEOUT(node->ping, node->varping);
#endif
- nodes[node].firstacktosend = 0;
- nodes[node].nextacknum = 1;
- nodes[node].remotefirstack = 0;
- nodes[node].flags = 0;
+ node->firstacktosend = 0;
+ node->nextacknum = 1;
+ node->remotefirstack = 0;
+ node->flags = 0;
}
static void InitAck(void)
@@ -622,9 +676,14 @@ static void InitAck(void)
#endif
for (i = 0; i < MAXNETNODES; i++)
- InitNode(i);
+ InitNode(&nodes[i]);
}
+/** Removes all acks of a given packet type
+ *
+ * \param packettype The packet type to forget
+ *
+ */
void Net_AbortPacketType(UINT8 packettype)
{
#ifdef NONET
@@ -652,12 +711,25 @@ void Net_CloseConnection(INT32 node)
#else
INT32 i;
boolean forceclose = (node & FORCECLOSE) != 0;
+
+ if (node == -1)
+ {
+ DEBFILE(M_GetText("Net_CloseConnection: node -1 detected!\n"));
+ return; // nope, just ignore it
+ }
+
node &= ~FORCECLOSE;
if (!node)
return;
- nodes[node].flags |= CLOSE;
+ if (node < 0 || node >= MAXNETNODES) // prevent invalid nodes from crashing the game
+ {
+ DEBFILE(va(M_GetText("Net_CloseConnection: invalid node %d detected!\n"), node));
+ return;
+ }
+
+ nodes[node].flags |= NF_CLOSE;
// try to Send ack back (two army problem)
if (GetAcktosend(node))
@@ -676,8 +748,8 @@ void Net_CloseConnection(INT32 node)
ackpak[i].acknum = 0;
}
- InitNode(node);
- AbortSendFiles(node);
+ InitNode(&nodes[node]);
+ SV_AbortSendFiles(node);
I_NetFreeNodenum(node);
#endif
}
@@ -729,9 +801,15 @@ static void fprintfstring(char *s, size_t len)
}
if (mode)
fprintf(debugfile, "]");
+}
+
+static void fprintfstringnewline(char *s, size_t len)
+{
+ fprintfstring(s, len);
fprintf(debugfile, "\n");
}
+/// \warning Keep this up-to-date if you add/remove/rename packet types
static const char *packettypename[NUMPACKETTYPE] =
{
"NOTHING",
@@ -749,15 +827,22 @@ static const char *packettypename[NUMPACKETTYPE] =
"ASKINFO",
"SERVERINFO",
+ "PLAYERINFO",
"REQUESTFILE",
"ASKINFOVIAMS",
- "PLAYERCONFIGS",
+ "RESYNCHEND",
+ "RESYNCHGET",
+
"FILEFRAGMENT",
"TEXTCMD",
"TEXTCMD2",
"CLIENTJOIN",
"NODETIMEOUT",
+ "RESYNCHING",
+#ifdef NEWPING
+ "PING"
+#endif
};
static void DebugPrintpacket(const char *header)
@@ -770,20 +855,31 @@ static void DebugPrintpacket(const char *header)
{
case PT_ASKINFO:
case PT_ASKINFOVIAMS:
- fprintf(debugfile, " time %u\n", (tic_t)LONG(netbuffer->u.askinfo.time) );
+ fprintf(debugfile, " time %u\n", (tic_t)LONG(netbuffer->u.askinfo.time));
break;
case PT_CLIENTJOIN:
fprintf(debugfile, " number %d mode %d\n", netbuffer->u.clientcfg.localplayers,
netbuffer->u.clientcfg.mode);
break;
case PT_SERVERTICS:
+ {
+ servertics_pak *serverpak = &netbuffer->u.serverpak;
+ UINT8 *cmd = (UINT8 *)(&serverpak->cmds[serverpak->numslots * serverpak->numtics]);
+ size_t ntxtcmd = &((UINT8 *)netbuffer)[doomcom->datalength] - cmd;
+
fprintf(debugfile, " firsttic %u ply %d tics %d ntxtcmd %s\n ",
- (UINT32)ExpandTics(netbuffer->u.serverpak.starttic), netbuffer->u.serverpak.numslots,
- netbuffer->u.serverpak.numtics,
- sizeu1((size_t)(&((UINT8 *)netbuffer)[doomcom->datalength] - (UINT8 *)&netbuffer->u.serverpak.cmds[netbuffer->u.serverpak.numslots*netbuffer->u.serverpak.numtics])));
- fprintfstring((char *)&netbuffer->u.serverpak.cmds[netbuffer->u.serverpak.numslots*netbuffer->u.serverpak.numtics],(size_t)(
- &((UINT8 *)netbuffer)[doomcom->datalength] - (UINT8 *)&netbuffer->u.serverpak.cmds[netbuffer->u.serverpak.numslots*netbuffer->u.serverpak.numtics]));
+ (UINT32)ExpandTics(serverpak->starttic), serverpak->numslots, serverpak->numtics, sizeu1(ntxtcmd));
+ /// \todo Display more readable information about net commands
+ fprintfstringnewline((char *)cmd, ntxtcmd);
+ /*fprintfstring((char *)cmd, 3);
+ if (ntxtcmd > 4)
+ {
+ fprintf(debugfile, "[%s]", netxcmdnames[*((cmd) + 3) - 1]);
+ fprintfstring(((char *)cmd) + 4, ntxtcmd - 4);
+ }
+ fprintf(debugfile, "\n");*/
break;
+ }
case PT_CLIENTCMD:
case PT_CLIENT2CMD:
case PT_CLIENTMIS:
@@ -797,7 +893,8 @@ static void DebugPrintpacket(const char *header)
case PT_TEXTCMD:
case PT_TEXTCMD2:
fprintf(debugfile, " length %d\n ", netbuffer->u.textcmd[0]);
- fprintfstring((char *)netbuffer->u.textcmd+1, netbuffer->u.textcmd[0]);
+ fprintf(debugfile, "[%s]", netxcmdnames[netbuffer->u.textcmd[1] - 1]);
+ fprintfstringnewline((char *)netbuffer->u.textcmd + 2, netbuffer->u.textcmd[0] - 1);
break;
case PT_SERVERCFG:
fprintf(debugfile, " playerslots %d clientnode %d serverplayer %d "
@@ -813,7 +910,7 @@ static void DebugPrintpacket(const char *header)
netbuffer->u.serverinfo.maxplayer, netbuffer->u.serverinfo.mapname,
netbuffer->u.serverinfo.fileneedednum,
(UINT32)LONG(netbuffer->u.serverinfo.time));
- fprintfstring((char *)netbuffer->u.serverinfo.fileneeded,
+ fprintfstringnewline((char *)netbuffer->u.serverinfo.fileneeded,
(UINT8)((UINT8 *)netbuffer + doomcom->datalength
- (UINT8 *)netbuffer->u.serverinfo.fileneeded));
break;
@@ -827,20 +924,102 @@ static void DebugPrintpacket(const char *header)
break;
case PT_REQUESTFILE:
default: // write as a raw packet
- fprintfstring((char *)netbuffer->u.textcmd,
+ fprintfstringnewline((char *)netbuffer->u.textcmd,
(UINT8)((UINT8 *)netbuffer + doomcom->datalength - (UINT8 *)netbuffer->u.textcmd));
break;
}
}
#endif
+#ifdef PACKETDROP
+static INT32 packetdropquantity[NUMPACKETTYPE] = {0};
+static INT32 packetdroprate = 0;
+
+void Command_Drop(void)
+{
+ INT32 packetquantity;
+ const char *packetname;
+ size_t i;
+
+ if (COM_Argc() < 2)
+ {
+ CONS_Printf("drop [quantity]: drop packets\n"
+ "drop reset: cancel all packet drops\n");
+ return;
+ }
+
+ if (!(stricmp(COM_Argv(1), "reset") && stricmp(COM_Argv(1), "cancel") && stricmp(COM_Argv(1), "stop")))
+ {
+ memset(packetdropquantity, 0, sizeof(packetdropquantity));
+ return;
+ }
+
+ if (COM_Argc() >= 3)
+ {
+ packetquantity = atoi(COM_Argv(2));
+ if (packetquantity <= 0 && COM_Argv(2)[0] != '0')
+ {
+ CONS_Printf("Invalid quantity\n");
+ return;
+ }
+ }
+ else
+ packetquantity = -1;
+
+ packetname = COM_Argv(1);
+
+ if (!(stricmp(packetname, "all") && stricmp(packetname, "any")))
+ for (i = 0; i < NUMPACKETTYPE; i++)
+ packetdropquantity[i] = packetquantity;
+ else
+ {
+ for (i = 0; i < NUMPACKETTYPE; i++)
+ if (!stricmp(packetname, packettypename[i]))
+ {
+ packetdropquantity[i] = packetquantity;
+ return;
+ }
+
+ CONS_Printf("Unknown packet name\n");
+ }
+}
+
+void Command_Droprate(void)
+{
+ INT32 droprate;
+
+ if (COM_Argc() < 2)
+ {
+ CONS_Printf("Packet drop rate: %d%%\n", packetdroprate);
+ return;
+ }
+
+ droprate = atoi(COM_Argv(1));
+ if ((droprate <= 0 && COM_Argv(1)[0] != '0') || droprate > 100)
+ {
+ CONS_Printf("Packet drop rate must be between 0 and 100!\n");
+ return;
+ }
+
+ packetdroprate = droprate;
+}
+
+#ifndef NONET
+static boolean ShouldDropPacket(void)
+{
+ return (packetdropquantity[netbuffer->packettype])
+ || (packetdroprate != 0 && rand() < (RAND_MAX * (packetdroprate / 100.f))) || packetdroprate == 100;
+}
+#endif
+#endif
+
//
// HSendPacket
//
boolean HSendPacket(INT32 node, boolean reliable, UINT8 acknum, size_t packetlength)
{
doomcom->datalength = (INT16)(packetlength + BASEPACKETSIZE);
- if (node == 0) // packet is to go back to us
+ if (node == 0) // Packet is to go back to us
{
if ((rebound_head+1) % MAXREBOUND == rebound_tail)
{
@@ -871,7 +1050,7 @@ boolean HSendPacket(INT32 node, boolean reliable, UINT8 acknum, size_t packetlen
(void)reliable;
(void)acknum;
#else
- // do this before GetFreeAcknum because this function backup
+ // do this before GetFreeAcknum because this function backups
// the current packet
doomcom->remotenode = (INT16)node;
if (doomcom->datalength <= 0)
@@ -884,7 +1063,7 @@ boolean HSendPacket(INT32 node, boolean reliable, UINT8 acknum, size_t packetlen
return false;
}
- if (node < MAXNETNODES) // can be a broadcast
+ if (node < MAXNETNODES) // Can be a broadcast
netbuffer->ackreturn = GetAcktosend(node);
else
netbuffer->ackreturn = 0;
@@ -905,20 +1084,30 @@ boolean HSendPacket(INT32 node, boolean reliable, UINT8 acknum, size_t packetlen
netbuffer->ack = acknum;
netbuffer->checksum = NetbufferChecksum();
- sendbytes += packetheaderlength + doomcom->datalength; // for stat
+ sendbytes += packetheaderlength + doomcom->datalength; // For stat
- // simulate internet :)
- if (true || rand()<(INT32)RAND_MAX/5)
+#ifdef PACKETDROP
+ // Simulate internet :)
+ //if (rand() >= (INT32)(RAND_MAX * (PACKETLOSSRATE / 100.f)))
+ if (!ShouldDropPacket())
{
+#endif
#ifdef DEBUGFILE
if (debugfile)
- DebugPrintpacket("SEND");
+ DebugPrintpacket("SENT");
#endif
I_NetSend();
+#ifdef PACKETDROP
}
+ else
+ {
+ if (packetdropquantity[netbuffer->packettype] > 0)
+ packetdropquantity[netbuffer->packettype]--;
#ifdef DEBUGFILE
- else if (debugfile)
- DebugPrintpacket("NOTSEND");
+ if (debugfile)
+ DebugPrintpacket("NOT SENT");
+#endif
+ }
#endif
#endif // ndef NONET
@@ -933,7 +1122,9 @@ boolean HSendPacket(INT32 node, boolean reliable, UINT8 acknum, size_t packetlen
//
boolean HGetPacket(void)
{
- // get a packet from self
+ //boolean nodejustjoined;
+
+ // Get a packet from self
if (rebound_tail != rebound_head)
{
M_Memcpy(netbuffer, &reboundstore[rebound_tail], reboundsize[rebound_tail]);
@@ -958,16 +1149,17 @@ boolean HGetPacket(void)
while(true)
{
+ //nodejustjoined = I_NetGet();
I_NetGet();
- if (doomcom->remotenode == -1)
+ if (doomcom->remotenode == -1) // No packet received
return false;
- getbytes += packetheaderlength + doomcom->datalength; // for stat
+ getbytes += packetheaderlength + doomcom->datalength; // For stat
if (doomcom->remotenode >= MAXNETNODES)
{
- DEBFILE(va("receive packet from node %d !\n", doomcom->remotenode));
+ DEBFILE(va("Received packet from node %d!\n", doomcom->remotenode));
continue;
}
@@ -976,6 +1168,7 @@ boolean HGetPacket(void)
if (netbuffer->checksum != NetbufferChecksum())
{
DEBFILE("Bad packet checksum\n");
+ //Net_CloseConnection(nodejustjoined ? (doomcom->remotenode | FORCECLOSE) : doomcom->remotenode);
Net_CloseConnection(doomcom->remotenode);
continue;
}
@@ -985,11 +1178,26 @@ boolean HGetPacket(void)
DebugPrintpacket("GET");
#endif
- // proceed the ack and ackreturn field
+ /*// If a new node sends an unexpected packet, just ignore it
+ if (nodejustjoined && server
+ && !(netbuffer->packettype == PT_ASKINFO
+ || netbuffer->packettype == PT_SERVERINFO
+ || netbuffer->packettype == PT_PLAYERINFO
+ || netbuffer->packettype == PT_REQUESTFILE
+ || netbuffer->packettype == PT_ASKINFOVIAMS
+ || netbuffer->packettype == PT_CLIENTJOIN))
+ {
+ DEBFILE(va("New node sent an unexpected %s packet\n", packettypename[netbuffer->packettype]));
+ //CONS_Alert(CONS_NOTICE, "New node sent an unexpected %s packet\n", packettypename[netbuffer->packettype]);
+ Net_CloseConnection(doomcom->remotenode | FORCECLOSE);
+ continue;
+ }*/
+
+ // Proceed the ack and ackreturn field
if (!Processackpak())
continue; // discarded (duplicated)
- // a packet with just ackreturn
+ // A packet with just ackreturn
if (netbuffer->packettype == PT_NOTHING)
{
GotAcks();
@@ -1002,9 +1210,10 @@ boolean HGetPacket(void)
return true;
}
-static void Internal_Get(void)
+static boolean Internal_Get(void)
{
doomcom->remotenode = -1;
+ return false;
}
FUNCNORETURN static ATTRNORETURN void Internal_Send(void)
@@ -1089,7 +1298,7 @@ boolean D_CheckNetGame(void)
if (netgame)
ret = true;
- if (!server && netgame)
+ if (client && netgame)
netgame = false;
server = true; // WTF? server always true???
// no! The deault mode is server. Client is set elsewhere
@@ -1230,4 +1439,6 @@ void D_CloseConnection(void)
netgame = false;
addedtogame = false;
}
+
+ D_ResetTiccmds();
}
diff --git a/src/d_net.h b/src/d_net.h
index 285b4423..84814ce3 100644
--- a/src/d_net.h
+++ b/src/d_net.h
@@ -18,10 +18,10 @@
#ifndef __D_NET__
#define __D_NET__
-// Max computers in a game.
+// Max computers in a game
#define MAXNETNODES 32
#define BROADCASTADDR MAXNETNODES
-#define MAXSPLITSCREENPLAYERS 2 // max number of players on a single computer
+#define MAXSPLITSCREENPLAYERS 2 // Max number of players on a single computer
#define STATLENGTH (TICRATE*2)
@@ -32,17 +32,17 @@ extern float lostpercent, duppercent, gamelostpercent;
extern INT32 packetheaderlength;
boolean Net_GetNetStat(void);
extern INT32 getbytes;
-extern INT64 sendbytes; // realtime updated
+extern INT64 sendbytes; // Realtime updated
extern SINT8 nodetoplayer[MAXNETNODES];
-extern SINT8 nodetoplayer2[MAXNETNODES]; // say the numplayer for this node if any (splitscreen)
-extern UINT8 playerpernode[MAXNETNODES]; // used specialy for scplitscreen
-extern boolean nodeingame[MAXNETNODES]; // set false as nodes leave game
+extern SINT8 nodetoplayer2[MAXNETNODES]; // Say the numplayer for this node if any (splitscreen)
+extern UINT8 playerpernode[MAXNETNODES]; // Used specially for splitscreen
+extern boolean nodeingame[MAXNETNODES]; // Set false as nodes leave game
+INT32 Net_GetFreeAcks(boolean urgent);
void Net_AckTicker(void);
-boolean Net_AllAckReceived(void);
-// if reliable return true if packet sent, 0 else
+// If reliable return true if packet sent, 0 else
boolean HSendPacket(INT32 node, boolean reliable, UINT8 acknum,
size_t packetlength);
boolean HGetPacket(void);
@@ -52,9 +52,11 @@ void D_SaveBan(void);
#endif
boolean D_CheckNetGame(void);
void D_CloseConnection(void);
-void Net_UnAcknowledgPacket(INT32 node);
+void Net_UnAcknowledgePacket(INT32 node);
void Net_CloseConnection(INT32 node);
+void Net_ConnectionTimeout(INT32 node);
void Net_AbortPacketType(UINT8 packettype);
void Net_SendAcks(INT32 node);
void Net_WaitAllAckReceived(UINT32 timeout);
+
#endif
diff --git a/src/d_netcmd.c b/src/d_netcmd.c
index 4f73a256..b5563f4e 100644
--- a/src/d_netcmd.c
+++ b/src/d_netcmd.c
@@ -82,6 +82,7 @@ static void AutoBalance_OnChange(void);
static void TeamScramble_OnChange(void);
static void NetTimeout_OnChange(void);
+static void JoinTimeout_OnChange(void);
static void Ringslinger_OnChange(void);
static void Gravity_OnChange(void);
@@ -340,7 +341,9 @@ consvar_t cv_killingdead = {"killingdead", "Off", CV_NETVAR, CV_OnOff, NULL, 0,
consvar_t cv_netstat = {"netstat", "Off", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; // show bandwidth statistics
static CV_PossibleValue_t nettimeout_cons_t[] = {{TICRATE/7, "MIN"}, {60*TICRATE, "MAX"}, {0, NULL}};
-consvar_t cv_nettimeout = {"nettimeout", "525", CV_CALL|CV_SAVE, nettimeout_cons_t, NetTimeout_OnChange, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_nettimeout = {"nettimeout", "350", CV_CALL|CV_SAVE, nettimeout_cons_t, NetTimeout_OnChange, 0, NULL, NULL, 0, 0, NULL};
+static CV_PossibleValue_t jointimeout_cons_t[] = {{5*TICRATE, "MIN"}, {60*TICRATE, "MAX"}, {0, NULL}};
+consvar_t cv_jointimeout = {"jointimeout", "350", CV_CALL|CV_SAVE, jointimeout_cons_t, JoinTimeout_OnChange, 0, NULL, NULL, 0, 0, NULL};
#ifdef NEWPING
consvar_t cv_maxping = {"maxping", "0", CV_SAVE, CV_Unsigned, NULL, 0, NULL, NULL, 0, 0, NULL};
#endif
@@ -365,6 +368,35 @@ boolean splitscreen = false;
boolean circuitmap = false;
INT32 adminplayer = -1;
+/// \warning Keep this up-to-date if you add/remove/rename net text commands
+const char *netxcmdnames[MAXNETXCMD - 1] =
+{
+ "NAMEANDCOLOR",
+ "WEAPONPREF",
+ "KICK",
+ "NETVAR",
+ "SAY",
+ "MAP",
+ "EXITLEVEL",
+ "ADDFILE",
+ "PAUSE",
+ "ADDPLAYER",
+ "TEAMCHANGE",
+ "CLEARSCORES",
+ "LOGIN",
+ "VERIFIED",
+ "RANDOMSEED",
+ "RUNSOC",
+ "REQADDFILE",
+ "DELFILE",
+ "SETMOTD",
+ "SUICIDE",
+#ifdef HAVE_BLUA
+ "LUACMD",
+ "LUAVAR"
+#endif
+};
+
// =========================================================================
// SERVER STARTUP
// =========================================================================
@@ -517,9 +549,12 @@ void D_RegisterServerCommands(void)
// d_clisrv
CV_RegisterVar(&cv_maxplayers);
CV_RegisterVar(&cv_maxsend);
+ CV_RegisterVar(&cv_noticedownload);
+ CV_RegisterVar(&cv_downloadspeed);
COM_AddCommand("ping", Command_Ping_f);
CV_RegisterVar(&cv_nettimeout);
+ CV_RegisterVar(&cv_jointimeout);
CV_RegisterVar(&cv_skipmapcheck);
CV_RegisterVar(&cv_sleep);
@@ -976,7 +1011,7 @@ UINT8 CanChangeSkin(INT32 playernum)
return true;
// Force skin in effect.
- if (!server && (cv_forceskin.value != -1) && !(adminplayer == playernum && serverplayer == -1))
+ if (client && (cv_forceskin.value != -1) && !(adminplayer == playernum && serverplayer == -1))
return false;
// Can change skin in intermission and whatnot.
@@ -1534,8 +1569,13 @@ void D_MapChange(INT32 mapnum, INT32 newgametype, boolean pultmode, boolean rese
mapchangepending = 0;
// spawn the server if needed
// reset players if there is a new one
- if (!(adminplayer == consoleplayer) && SV_SpawnServer())
- buf[0] &= ~(1<<1);
+ if (!(adminplayer == consoleplayer))
+ {
+ if (SV_SpawnServer())
+ buf[0] &= ~(1<<1);
+ if (!Playing()) // you failed to start a server somehow, so cancel the map change
+ return;
+ }
// Kick bot from special stages
if (botskin)
@@ -1587,7 +1627,7 @@ static void Command_Map_f(void)
return;
}
- if (!server && !(adminplayer == consoleplayer))
+ if (client && !(adminplayer == consoleplayer))
{
CONS_Printf(M_GetText("Only the server or a remote admin can use this.\n"));
return;
@@ -1914,7 +1954,7 @@ static void Got_Suicide(UINT8 **cp, INT32 playernum)
// You can't suicide someone else. Nice try, there.
if (suicideplayer != playernum || (!G_PlatformGametype()))
{
- CONS_Alert(CONS_WARNING, M_GetText("Illegal suicide command recieved from %s\n"), player_names[playernum]);
+ CONS_Alert(CONS_WARNING, M_GetText("Illegal suicide command received from %s\n"), player_names[playernum]);
if (server)
{
XBOXSTATIC UINT8 buf[2];
@@ -2081,7 +2121,7 @@ static void Command_Teamchange_f(void)
return;
}
- if (!cv_allowteamchange.value && !NetPacket.packet.newteam) // allow swapping to spectator even in locked teams.
+ if (!cv_allowteamchange.value && NetPacket.packet.newteam) // allow swapping to spectator even in locked teams.
{
CONS_Alert(CONS_NOTICE, M_GetText("The server is not allowing team changes at the moment.\n"));
return;
@@ -2178,7 +2218,7 @@ static void Command_Teamchange2_f(void)
return;
}
- if (!cv_allowteamchange.value && !NetPacket.packet.newteam) // allow swapping to spectator even in locked teams.
+ if (!cv_allowteamchange.value && NetPacket.packet.newteam) // allow swapping to spectator even in locked teams.
{
CONS_Alert(CONS_NOTICE, M_GetText("The server is not allowing team changes at the moment.\n"));
return;
@@ -2629,7 +2669,7 @@ static void Command_Changepassword_f(void)
// If we have no MD5 support then completely disable XD_LOGIN responses for security.
CONS_Alert(CONS_NOTICE, "Remote administration commands are not supported in this build.\n");
#else
- if (!server) // cannot change remotely
+ if (client) // cannot change remotely
{
CONS_Printf(M_GetText("Only the server can use this.\n"));
return;
@@ -2688,7 +2728,7 @@ static void Got_Login(UINT8 **cp, INT32 playernum)
READMEM(*cp, sentmd5, 16);
- if (!server)
+ if (client)
return;
// Do the final pass to compare with the sent md5
@@ -2710,7 +2750,7 @@ static void Command_Verify_f(void)
char *temp;
INT32 playernum;
- if (!server)
+ if (client)
{
CONS_Printf(M_GetText("Only the server can use this.\n"));
return;
@@ -2794,7 +2834,7 @@ static void Command_MotD_f(void)
return;
}
- if ((netgame || multiplayer) && !server)
+ if ((netgame || multiplayer) && client)
SendNetXCmd(XD_SETMOTD, mymotd, sizeof(motd));
else
{
@@ -2932,6 +2972,7 @@ static void Command_Addfile(void)
XBOXSTATIC char buf[256];
char *buf_p = buf;
INT32 i;
+ int musiconly; // W_VerifyNMUSlumps isn't boolean
if (COM_Argc() != 2)
{
@@ -2946,7 +2987,9 @@ static void Command_Addfile(void)
if (!isprint(fn[i]) || fn[i] == ';')
return;
- if (!W_VerifyNMUSlumps(fn))
+ musiconly = W_VerifyNMUSlumps(fn);
+
+ if (!musiconly)
{
// ... But only so long as they contain nothing more then music and sprites.
if (netgame && !(server || adminplayer == consoleplayer))
@@ -2958,7 +3001,7 @@ static void Command_Addfile(void)
}
// Add file on your client directly if it is trivial, or you aren't in a netgame.
- if (!(netgame || multiplayer) || W_VerifyNMUSlumps(fn))
+ if (!(netgame || multiplayer) || musiconly)
{
P_AddWadFile(fn, NULL);
return;
@@ -2978,9 +3021,7 @@ static void Command_Addfile(void)
#else
FILE *fhandle;
- fhandle = fopen(fn, "rb");
-
- if (fhandle)
+ if ((fhandle = W_OpenWadFile(&fn, true)) != NULL)
{
tic_t t = I_GetTime();
CONS_Debug(DBG_SETUP, "Making MD5 for %s\n",fn);
@@ -2988,11 +3029,8 @@ static void Command_Addfile(void)
CONS_Debug(DBG_SETUP, "MD5 calc for %s took %f second\n", fn, (float)(I_GetTime() - t)/TICRATE);
fclose(fhandle);
}
- else
- {
- CONS_Printf(M_GetText("File %s not found.\n"), fn);
+ else // file not found
return;
- }
#endif
WRITEMEM(buf_p, md5sum, 16);
}
@@ -3045,13 +3083,19 @@ static void Got_RequestAddfilecmd(UINT8 **cp, INT32 playernum)
filestatus_t ncs = FS_NOTFOUND;
UINT8 md5sum[16];
boolean kick = false;
+ boolean toomany = false;
INT32 i;
+ size_t packetsize = 0;
+ serverinfo_pak *dummycheck = NULL;
+
+ // Shut the compiler up.
+ (void)dummycheck;
READSTRINGN(*cp, filename, 240);
READMEM(*cp, md5sum, 16);
// Only the server processes this message.
- if (!server)
+ if (client)
return;
// Disallow non-printing characters and semicolons.
@@ -3071,13 +3115,25 @@ static void Got_RequestAddfilecmd(UINT8 **cp, INT32 playernum)
return;
}
- ncs = findfile(filename,md5sum,true);
+ // See W_LoadWadFile in w_wad.c
+ for (i = 0; i < numwadfiles; i++)
+ packetsize += nameonlylength(wadfiles[i]->filename) + 22;
- if (ncs != FS_FOUND)
+ packetsize += nameonlylength(filename) + 22;
+
+ if ((numwadfiles >= MAX_WADFILES)
+ || (packetsize > sizeof(dummycheck->fileneeded)))
+ toomany = true;
+ else
+ ncs = findfile(filename,md5sum,true);
+
+ if (ncs != FS_FOUND || toomany)
{
char message[256];
- if (ncs == FS_NOTFOUND)
+ if (toomany)
+ sprintf(message, M_GetText("Too many files loaded to add %s\n"), filename);
+ else if (ncs == FS_NOTFOUND)
sprintf(message, M_GetText("The server doesn't have %s\n"), filename);
else if (ncs == FS_MD5SUMBAD)
sprintf(message, M_GetText("Checksum mismatch on %s\n"), filename);
@@ -3147,10 +3203,15 @@ static void Got_Addfilecmd(UINT8 **cp, INT32 playernum)
ncs = findfile(filename,md5sum,true);
- if (ncs != FS_FOUND)
+ if (ncs != FS_FOUND || !P_AddWadFile(filename, NULL))
{
Command_ExitGame_f();
- if (ncs == FS_NOTFOUND)
+ if (ncs == FS_FOUND)
+ {
+ CONS_Printf(M_GetText("The server tried to add %s,\nbut you have too many files added.\nRestart the game to clear loaded files\nand play on this server."), filename);
+ M_StartMessage(va("The server added a file \n(%s)\nbut you have too many files added.\nRestart the game to clear loaded files.\n\nPress ESC\n",filename), NULL, MM_NOTHING);
+ }
+ else if (ncs == FS_NOTFOUND)
{
CONS_Printf(M_GetText("The server tried to add %s,\nbut you don't have this file.\nYou need to find it in order\nto play on this server."), filename);
M_StartMessage(va("The server added a file \n(%s)\nthat you do not have.\n\nPress ESC\n",filename), NULL, MM_NOTHING);
@@ -3168,7 +3229,6 @@ static void Got_Addfilecmd(UINT8 **cp, INT32 playernum)
return;
}
- P_AddWadFile(filename, NULL);
G_SetGameModified(true);
}
@@ -3318,6 +3378,11 @@ static void NetTimeout_OnChange(void)
connectiontimeout = (tic_t)cv_nettimeout.value;
}
+static void JoinTimeout_OnChange(void)
+{
+ jointimeout = (tic_t)cv_jointimeout.value;
+}
+
UINT32 timelimitintics = 0;
/** Deals with a timelimit change by printing the change to the console.
@@ -3960,7 +4025,7 @@ static void Command_Archivetest_f(void)
}
// assign mobjnum
- i = 0;
+ i = 1;
for (th = thinkercap.next; th != &thinkercap; th = th->next)
if (th->function.acp1 == (actionf_p1)P_MobjThinker)
((mobj_t *)th)->mobjnum = i++;
@@ -4063,7 +4128,7 @@ static void Skin_OnChange(void)
return; // do whatever you want
if (!(cv_debug || devparm) && !(multiplayer || netgame) // In single player.
- && (gamestate == GS_LEVEL || gamestate == GS_INTERMISSION || gamestate == GS_CONTINUING))
+ && (gamestate != GS_WAITINGPLAYERS)) // allows command line -warp x +skin y
{
CV_StealthSet(&cv_skin, skins[players[consoleplayer].skin].name);
return;
@@ -4106,8 +4171,7 @@ static void Color_OnChange(void)
if (!Playing())
return; // do whatever you want
- if (!(cv_debug || devparm) && !(multiplayer || netgame) // In single player.
- && (gamestate == GS_LEVEL || gamestate == GS_INTERMISSION || gamestate == GS_CONTINUING))
+ if (!(cv_debug || devparm) && !(multiplayer || netgame)) // In single player.
{
CV_StealthSet(&cv_skin, skins[players[consoleplayer].skin].name);
return;
diff --git a/src/d_netcmd.h b/src/d_netcmd.h
index c090699f..d8fae72f 100644
--- a/src/d_netcmd.h
+++ b/src/d_netcmd.h
@@ -162,6 +162,8 @@ typedef enum
MAXNETXCMD
} netxcmd_t;
+extern const char *netxcmdnames[MAXNETXCMD - 1];
+
#if defined(_MSC_VER)
#pragma pack(1)
#endif
diff --git a/src/d_netfil.c b/src/d_netfil.c
index 85196217..172624ad 100644
--- a/src/d_netfil.c
+++ b/src/d_netfil.c
@@ -62,44 +62,49 @@
#include
-static void SendFile(INT32 node, const char *filename, UINT8 fileid);
+// Prototypes
+static boolean SV_SendFile(INT32 node, const char *filename, UINT8 fileid);
-// sender structure
+// Sender structure
typedef struct filetx_s
{
INT32 ram;
- char *filename; // name of the file or ptr of the data in ram
- UINT32 size;
+ union {
+ char *filename; // Name of the file
+ char *ram; // Pointer to the data in RAM
+ } id;
+ UINT32 size; // Size of the file
UINT8 fileid;
- INT32 node; // destination
- struct filetx_s *next; // a queue
+ INT32 node; // Destination
+ struct filetx_s *next; // Next file in the list
} filetx_t;
-// current transfers (one for each node)
+// Current transfers (one for each node)
typedef struct filetran_s
{
- filetx_t *txlist;
- UINT32 position;
- FILE *currentfile;
+ filetx_t *txlist; // Linked list of all files for the node
+ UINT32 position; // The current position in the file
+ FILE *currentfile; // The file currently being sent/received
} filetran_t;
static filetran_t transfer[MAXNETNODES];
-// read time of file: stat _stmtime
-// write time of file: utime
+// Read time of file: stat _stmtime
+// Write time of file: utime
-// receiver structure
-INT32 fileneedednum;
-fileneeded_t fileneeded[MAX_WADFILES];
+// Receiver structure
+INT32 fileneedednum; // Number of files needed to join the server
+fileneeded_t fileneeded[MAX_WADFILES]; // List of needed files
char downloaddir[256] = "DOWNLOAD";
#ifdef CLIENT_LOADINGSCREEN
// for cl loading screen
-INT32 lastfilenum = 0;
+INT32 lastfilenum = -1;
#endif
/** Fills a serverinfo packet with information about wad files loaded.
*
* \todo Give this function a better name since it is in global scope.
+ *
*/
UINT8 *PutFileNeeded(void)
{
@@ -111,19 +116,19 @@ UINT8 *PutFileNeeded(void)
for (i = 0; i < numwadfiles; i++)
{
- // if it has only music/sound lumps, mark it as unimportant
+ // If it has only music/sound lumps, mark it as unimportant
if (W_VerifyNMUSlumps(wadfiles[i]->filename))
filestatus = 0;
else
- filestatus = 1; // important
+ filestatus = 1; // Important
// Store in the upper four bits
if (!cv_downloading.value)
- filestatus += (2 << 4); // won't send
+ filestatus += (2 << 4); // Won't send
else if ((wadfiles[i]->filesize > (UINT32)cv_maxsend.value * 1024))
- filestatus += (0 << 4); // won't send
+ filestatus += (0 << 4); // Won't send
else
- filestatus += (1 << 4); // will send if requested
+ filestatus += (1 << 4); // Will send if requested
bytesused += (nameonlylength(wadfilename) + 22);
@@ -144,7 +149,12 @@ UINT8 *PutFileNeeded(void)
return p;
}
-// parse the serverinfo packet and fill fileneeded table on client
+/** Parses the serverinfo packet and fills the fileneeded table on client
+ *
+ * \param fileneedednum_parm The number of files needed to join the server
+ * \param fileneededstr The memory block containing the list of needed files
+ *
+ */
void D_ParseFileneeded(INT32 fileneedednum_parm, UINT8 *fileneededstr)
{
INT32 i;
@@ -155,14 +165,14 @@ void D_ParseFileneeded(INT32 fileneedednum_parm, UINT8 *fileneededstr)
p = (UINT8 *)fileneededstr;
for (i = 0; i < fileneedednum; i++)
{
- fileneeded[i].status = FS_NOTFOUND;
- filestatus = READUINT8(p);
+ fileneeded[i].status = FS_NOTFOUND; // We haven't even started looking for the file yet
+ filestatus = READUINT8(p); // The first byte is the file status
fileneeded[i].important = (UINT8)(filestatus & 3);
fileneeded[i].willsend = (UINT8)(filestatus >> 4);
- fileneeded[i].totalsize = READUINT32(p);
- fileneeded[i].phandle = NULL;
- READSTRINGN(p, fileneeded[i].filename, MAX_WADPATH);
- READMEM(p, fileneeded[i].md5sum, 16);
+ fileneeded[i].totalsize = READUINT32(p); // The four next bytes are the file size
+ fileneeded[i].file = NULL; // The file isn't open yet
+ READSTRINGN(p, fileneeded[i].filename, MAX_WADPATH); // The next bytes are the file name
+ READMEM(p, fileneeded[i].md5sum, 16); // The last 16 bytes are the file checksum
}
}
@@ -171,13 +181,16 @@ void CL_PrepareDownloadSaveGame(const char *tmpsave)
fileneedednum = 1;
fileneeded[0].status = FS_REQUESTED;
fileneeded[0].totalsize = UINT32_MAX;
- fileneeded[0].phandle = NULL;
+ fileneeded[0].file = NULL;
memset(fileneeded[0].md5sum, 0, 16);
strcpy(fileneeded[0].filename, tmpsave);
}
/** Checks the server to see if we CAN download all the files,
* before starting to create them and requesting.
+ *
+ * \return True if we can download all the files
+ *
*/
boolean CL_CheckDownloadable(void)
{
@@ -239,8 +252,12 @@ boolean CL_CheckDownloadable(void)
return false;
}
-/** Send requests for files in the ::fileneeded table with a status of
+/** Sends requests for files in the ::fileneeded table with a status of
* ::FS_NOTFOUND.
+ *
+ * \return True if the packet was successfully sent
+ * \note Sends a PT_REQUESTFILE packet
+ *
*/
boolean CL_SendRequestFile(void)
{
@@ -287,7 +304,8 @@ boolean CL_SendRequestFile(void)
}
// get request filepak and put it on the send queue
-void Got_RequestFilePak(INT32 node)
+// returns false if a requested file was not found or cannot be sent
+boolean Got_RequestFilePak(INT32 node)
{
char wad[MAX_WADPATH+1];
UINT8 *p = netbuffer->u.textcmd;
@@ -298,16 +316,33 @@ void Got_RequestFilePak(INT32 node)
if (id == 0xFF)
break;
READSTRINGN(p, wad, MAX_WADPATH);
- SendFile(node, wad, id);
+ if (!SV_SendFile(node, wad, id))
+ {
+ SV_AbortSendFiles(node);
+ return false; // don't read the rest of the files
+ }
}
+ return true; // no problems with any files
}
-// client check if the fileneeded aren't already loaded or on the disk
+/** Checks if the files needed aren't already loaded or on the disk
+ *
+ * \return 0 if some files are missing
+ * 1 if all files exist
+ * 2 if some already loaded files are not requested or are in a different order
+ *
+ */
INT32 CL_CheckFiles(void)
{
INT32 i, j;
char wadfilename[MAX_WADPATH];
INT32 ret = 1;
+ size_t packetsize = 0;
+ size_t filestoget = 0;
+ serverinfo_pak *dummycheck = NULL;
+
+ // Shut the compiler up.
+ (void)dummycheck;
// if (M_CheckParm("-nofiles"))
// return 1;
@@ -333,7 +368,7 @@ INT32 CL_CheckFiles(void)
}
if (j < numwadfiles && W_VerifyNMUSlumps(wadfiles[j]->filename))
{
- // unimportant on our side. still don't care.
+ // Unimportant on our side. still don't care.
++j;
continue;
}
@@ -343,11 +378,11 @@ INT32 CL_CheckFiles(void)
if (i >= fileneedednum || j >= numwadfiles)
return 2;
- // for the sake of speed, only bother with a md5 check
+ // For the sake of speed, only bother with a md5 check
if (memcmp(wadfiles[j]->md5sum, fileneeded[i].md5sum, 16))
return 2;
- // it's accounted for! let's keep going.
+ // It's accounted for! let's keep going.
CONS_Debug(DBG_NETPLAY, "'%s' accounted for\n", fileneeded[i].filename);
fileneeded[i].status = FS_OPEN;
++i;
@@ -356,11 +391,15 @@ INT32 CL_CheckFiles(void)
return 1;
}
+ // See W_LoadWadFile in w_wad.c
+ for (i = 0; i < numwadfiles; i++)
+ packetsize += nameonlylength(wadfiles[i]->filename) + 22;
+
for (i = 1; i < fileneedednum; i++)
{
CONS_Debug(DBG_NETPLAY, "searching for '%s' ", fileneeded[i].filename);
- // check in allready loaded files
+ // Check in already loaded files
for (j = 1; wadfiles[j]; j++)
{
nameonly(strcpy(wadfilename, wadfiles[j]->filename));
@@ -375,6 +414,14 @@ INT32 CL_CheckFiles(void)
if (fileneeded[i].status != FS_NOTFOUND || !fileneeded[i].important)
continue;
+ packetsize += nameonlylength(fileneeded[i].filename) + 22;
+
+ if ((numwadfiles+filestoget >= MAX_WADFILES)
+ || (packetsize > sizeof(dummycheck->fileneeded)))
+ return 3;
+
+ filestoget++;
+
fileneeded[i].status = findfile(fileneeded[i].filename, fileneeded[i].md5sum, true);
CONS_Debug(DBG_NETPLAY, "found %d\n", fileneeded[i].status);
if (fileneeded[i].status != FS_FOUND)
@@ -383,7 +430,7 @@ INT32 CL_CheckFiles(void)
return ret;
}
-// load it now
+// Load it now
void CL_LoadServerFiles(void)
{
INT32 i;
@@ -394,7 +441,7 @@ void CL_LoadServerFiles(void)
for (i = 1; i < fileneedednum; i++)
{
if (fileneeded[i].status == FS_OPEN)
- continue; // already loaded
+ continue; // Already loaded
else if (fileneeded[i].status == FS_FOUND)
{
P_AddWadFile(fileneeded[i].filename, NULL);
@@ -423,172 +470,270 @@ void CL_LoadServerFiles(void)
DEBFILE(va("File %s found but with different md5sum\n", fileneeded[i].filename));
}
else if (fileneeded[i].important)
- I_Error("Try to load file %s with status of %d\n", fileneeded[i].filename,
- fileneeded[i].status);
+ {
+ const char *s;
+ switch(fileneeded[i].status)
+ {
+ case FS_NOTFOUND:
+ s = "FS_NOTFOUND";
+ break;
+ case FS_REQUESTED:
+ s = "FS_REQUESTED";
+ break;
+ case FS_DOWNLOADING:
+ s = "FS_DOWNLOADING";
+ break;
+ default:
+ s = "unknown";
+ break;
+ }
+ I_Error("Try to load file \"%s\" with status of %d (%s)\n", fileneeded[i].filename,
+ fileneeded[i].status, s);
+ }
}
}
-// little optimization to test if there is a file in the queue
-static INT32 filetosend = 0;
+// Number of files to send
+// Little optimization to quickly test if there is a file in the queue
+static INT32 filestosend = 0;
-static void SendFile(INT32 node, const char *filename, UINT8 fileid)
+/** Adds a file to the file list for a node
+ *
+ * \param node The node to send the file to
+ * \param filename The file to send
+ * \param fileid ???
+ * \sa SV_SendRam
+ *
+ */
+static boolean SV_SendFile(INT32 node, const char *filename, UINT8 fileid)
{
- filetx_t **q;
- filetx_t *p;
+ filetx_t **q; // A pointer to the "next" field of the last file in the list
+ filetx_t *p; // The new file request
INT32 i;
char wadfilename[MAX_WADPATH];
+ if (cv_noticedownload.value)
+ CONS_Printf("Sending file \"%s\" to node %d (%s)\n", filename, node, I_GetNodeAddress(node));
+
+ // Find the last file in the list and set a pointer to its "next" field
q = &transfer[node].txlist;
while (*q)
q = &((*q)->next);
+
+ // Allocate a file request and append it to the file list
p = *q = (filetx_t *)malloc(sizeof (filetx_t));
- if (p)
- memset(p, 0, sizeof (filetx_t));
- else
- I_Error("SendFile: No more ram\n");
- p->filename = (char *)malloc(MAX_WADPATH);
- if (!p->filename)
- I_Error("SendFile: No more ram\n");
+ if (!p)
+ I_Error("SV_SendFile: No more memory\n");
- // a minimum of security, can get only file in srb2 direcory
- strlcpy(p->filename, filename, MAX_WADPATH);
- nameonly(p->filename);
+ // Initialise with zeros
+ memset(p, 0, sizeof (filetx_t));
- // check first in wads loaded the majority of case
+ // Allocate the file name
+ p->id.filename = (char *)malloc(MAX_WADPATH);
+ if (!p->id.filename)
+ I_Error("SV_SendFile: No more memory\n");
+
+ // Set the file name and get rid of the path
+ strlcpy(p->id.filename, filename, MAX_WADPATH);
+ nameonly(p->id.filename);
+
+ // Look for the requested file through all loaded files
for (i = 0; wadfiles[i]; i++)
{
strlcpy(wadfilename, wadfiles[i]->filename, MAX_WADPATH);
nameonly(wadfilename);
- if (!stricmp(wadfilename, p->filename))
+ if (!stricmp(wadfilename, p->id.filename))
{
- // copy filename with full path
- strlcpy(p->filename, wadfiles[i]->filename, MAX_WADPATH);
+ // Copy file name with full path
+ strlcpy(p->id.filename, wadfiles[i]->filename, MAX_WADPATH);
break;
}
}
+ // Handle non-loaded file requests
if (!wadfiles[i])
{
DEBFILE(va("%s not found in wadfiles\n", filename));
- // this formerly checked if (!findfile(p->filename, NULL, true))
+ // This formerly checked if (!findfile(p->id.filename, NULL, true))
- // not found
- // don't inform client (probably hacker)
+ // Not found
+ // Don't inform client (probably someone who thought they could leak 2.2 ACZ)
DEBFILE(va("Client %d request %s: not found\n", node, filename));
- free(p->filename);
+ free(p->id.filename);
free(p);
*q = NULL;
- return;
+ return false; // cancel the rest of the requests
}
+ // Handle huge file requests (i.e. bigger than cv_maxsend.value KB)
if (wadfiles[i]->filesize > (UINT32)cv_maxsend.value * 1024)
{
- // too big
- // don't inform client (client sucks, man)
+ // Too big
+ // Don't inform client (client sucks, man)
DEBFILE(va("Client %d request %s: file too big, not sending\n", node, filename));
- free(p->filename);
+ free(p->id.filename);
free(p);
*q = NULL;
- return;
+ return false; // cancel the rest of the requests
}
DEBFILE(va("Sending file %s (id=%d) to %d\n", filename, fileid, node));
- p->ram = SF_FILE;
+ p->ram = SF_FILE; // It's a file, we need to close it and free its name once we're done sending it
p->fileid = fileid;
- p->next = NULL; // end of list
- filetosend++;
+ p->next = NULL; // End of list
+ filestosend++;
+ return true;
}
-void SendRam(INT32 node, void *data, size_t size, freemethod_t freemethod, UINT8 fileid)
+/** Adds a memory block to the file list for a node
+ *
+ * \param node The node to send the memory block to
+ * \param data The memory block to send
+ * \param size The size of the block in bytes
+ * \param freemethod How to free the block after it has been sent
+ * \param fileid ???
+ * \sa SV_SendFile
+ *
+ */
+void SV_SendRam(INT32 node, void *data, size_t size, freemethod_t freemethod, UINT8 fileid)
{
- filetx_t **q;
- filetx_t *p;
+ filetx_t **q; // A pointer to the "next" field of the last file in the list
+ filetx_t *p; // The new file request
+ // Find the last file in the list and set a pointer to its "next" field
q = &transfer[node].txlist;
while (*q)
q = &((*q)->next);
+
+ // Allocate a file request and append it to the file list
p = *q = (filetx_t *)malloc(sizeof (filetx_t));
- if (p)
- memset(p, 0, sizeof (filetx_t));
- else
- I_Error("SendRam: No more ram\n");
- p->ram = freemethod;
- p->filename = data;
+ if (!p)
+ I_Error("SV_SendRam: No more memory\n");
+
+ // Initialise with zeros
+ memset(p, 0, sizeof (filetx_t));
+
+ p->ram = freemethod; // Remember how to free the memory block for when we're done sending it
+ p->id.ram = data;
p->size = (UINT32)size;
p->fileid = fileid;
- p->next = NULL; // end of list
+ p->next = NULL; // End of list
- DEBFILE(va("Sending ram %p(size:%u) to %d (id=%u)\n",p->filename,p->size,node,fileid));
+ DEBFILE(va("Sending ram %p(size:%u) to %d (id=%u)\n",p->id.ram,p->size,node,fileid));
- filetosend++;
+ filestosend++;
}
-static void EndSend(INT32 node)
+/** Stops sending a file for a node, and removes the file request from the list,
+ * either because the file has been fully sent or because the node was disconnected
+ *
+ * \param node The destination
+ *
+ */
+static void SV_EndFileSend(INT32 node)
{
filetx_t *p = transfer[node].txlist;
+
+ // Free the file request according to the freemethod parameter used with SV_SendFile/Ram
switch (p->ram)
{
- case SF_FILE:
+ case SF_FILE: // It's a file, close it and free its filename
+ if (cv_noticedownload.value)
+ CONS_Printf("Ending file transfer for node %d\n", node);
if (transfer[node].currentfile)
fclose(transfer[node].currentfile);
- free(p->filename);
+ free(p->id.filename);
break;
- case SF_Z_RAM:
- Z_Free(p->filename);
+ case SF_Z_RAM: // It's a memory block allocated with Z_Alloc or the likes, use Z_Free
+ Z_Free(p->id.ram);
break;
- case SF_RAM:
- free(p->filename);
- case SF_NOFREERAM:
+ case SF_RAM: // It's a memory block allocated with malloc, use free
+ free(p->id.ram);
+ case SF_NOFREERAM: // Nothing to free
break;
}
+
+ // Remove the file request from the list
transfer[node].txlist = p->next;
- transfer[node].currentfile = NULL;
free(p);
- filetosend--;
+
+ // Indicate that the transmission is over
+ transfer[node].currentfile = NULL;
+
+ filestosend--;
}
#define PACKETPERTIC net_bandwidth/(TICRATE*software_MAXPACKETLENGTH)
-void FiletxTicker(void)
+/** Handles file transmission
+ *
+ * \todo Use an acknowledging method more adapted to file transmission
+ * The current download speed suffers from lack of ack packets,
+ * especially when the one downloading has high latency
+ *
+ */
+void SV_FileSendTicker(void)
{
static INT32 currentnode = 0;
filetx_pak *p;
size_t size;
filetx_t *f;
- INT32 packetsent = PACKETPERTIC, ram, i;
+ INT32 packetsent, ram, i, j;
+ INT32 maxpacketsent;
- if (!filetosend)
+ if (!filestosend) // No file to send
return;
- if (!packetsent)
- packetsent++;
- // (((sendbytes-nowsentbyte)*TICRATE)/(I_GetTime()-starttime)<(UINT32)net_bandwidth)
- while (packetsent-- && filetosend != 0)
+
+ if (cv_downloadspeed.value) // New (and experimental) behavior
{
- for (i = currentnode, ram = 0; ram < MAXNETNODES;
- i = (i+1) % MAXNETNODES, ram++)
+ packetsent = cv_downloadspeed.value;
+ // Don't send more packets than we have free acks
+#ifndef NONET
+ maxpacketsent = Net_GetFreeAcks(false) - 5; // Let 5 extra acks just in case
+#else
+ maxpacketsent = 1;
+#endif
+ if (packetsent > maxpacketsent && maxpacketsent > 0) // Send at least one packet
+ packetsent = maxpacketsent;
+ }
+ else // Old behavior
+ {
+ packetsent = PACKETPERTIC;
+ if (!packetsent)
+ packetsent = 1;
+ }
+
+ netbuffer->packettype = PT_FILEFRAGMENT;
+
+ // (((sendbytes-nowsentbyte)*TICRATE)/(I_GetTime()-starttime)<(UINT32)net_bandwidth)
+ while (packetsent-- && filestosend != 0)
+ {
+ for (i = currentnode, j = 0; j < MAXNETNODES;
+ i = (i+1) % MAXNETNODES, j++)
{
if (transfer[i].txlist)
goto found;
}
// no transfer to do
- I_Error("filetosend=%d but no filetosend found\n", filetosend);
+ I_Error("filestosend=%d but no file to send found\n", filestosend);
found:
currentnode = (i+1) % MAXNETNODES;
f = transfer[i].txlist;
ram = f->ram;
- if (!transfer[i].currentfile) // file not already open
+ // Open the file if it isn't open yet, or
+ if (!transfer[i].currentfile)
{
- if (!ram)
+ if (!ram) // Sending a file
{
long filesize;
transfer[i].currentfile =
- fopen(f->filename, "rb");
+ fopen(f->id.filename, "rb");
if (!transfer[i].currentfile)
I_Error("File %s does not exist",
- f->filename);
+ f->id.filename);
fseek(transfer[i].currentfile, 0, SEEK_END);
filesize = ftell(transfer[i].currentfile);
@@ -596,45 +741,47 @@ void FiletxTicker(void)
// Nobody wants to transfer a file bigger
// than 4GB!
if (filesize >= LONG_MAX)
- I_Error("filesize of %s is too large", f->filename);
- if (-1 == filesize)
- I_Error("Error getting filesize of %s", f->filename);
+ I_Error("filesize of %s is too large", f->id.filename);
+ if (filesize == -1)
+ I_Error("Error getting filesize of %s", f->id.filename);
f->size = (UINT32)filesize;
fseek(transfer[i].currentfile, 0, SEEK_SET);
}
- else
- transfer[i].currentfile = (FILE *)1;
+ else // Sending RAM
+ transfer[i].currentfile = (FILE *)1; // Set currentfile to a non-null value to indicate that it is open
transfer[i].position = 0;
}
+ // Build a packet containing a file fragment
p = &netbuffer->u.filetxpak;
size = software_MAXPACKETLENGTH - (FILETXHEADER + BASEPACKETSIZE);
if (f->size-transfer[i].position < size)
size = f->size-transfer[i].position;
if (ram)
- M_Memcpy(p->data, &f->filename[transfer[i].position], size);
+ M_Memcpy(p->data, &f->id.ram[transfer[i].position], size);
else if (fread(p->data, 1, size, transfer[i].currentfile) != size)
- I_Error("FiletxTicker: can't read %s byte on %s at %d because %s", sizeu1(size), f->filename, transfer[i].position, strerror(ferror(transfer[i].currentfile)));
+ I_Error("SV_FileSendTicker: can't read %s byte on %s at %d because %s", sizeu1(size), f->id.filename, transfer[i].position, strerror(ferror(transfer[i].currentfile)));
p->position = LONG(transfer[i].position);
- // put flag so receiver know the totalsize
+ // Put flag so receiver knows the total size
if (transfer[i].position + size == f->size)
p->position |= LONG(0x80000000);
p->fileid = f->fileid;
p->size = SHORT((UINT16)size);
- netbuffer->packettype = PT_FILEFRAGMENT;
- if (!HSendPacket(i, true, 0, FILETXHEADER + size)) // reliable SEND
- { // not sent for some odd reason, retry at next call
- if (!ram)
- fseek(transfer[i].currentfile,transfer[i].position,SEEK_SET);
- // exit the while (can't send this one so why should i send the next?)
- break;
+
+ // Send the packet
+ if (HSendPacket(i, true, 0, FILETXHEADER + size)) // Reliable SEND
+ { // Success
+ transfer[i].position = (UINT32)(transfer[i].position + size);
+ if (transfer[i].position == f->size) // Finish?
+ SV_EndFileSend(i);
}
- else // success
- {
- transfer[i].position = (UINT32)(size+transfer[i].position);
- if (transfer[i].position == f->size) // finish ?
- EndSend(i);
+ else
+ { // Not sent for some odd reason, retry at next call
+ if (!ram)
+ fseek(transfer[i].currentfile,transfer[i].position, SEEK_SET);
+ // Exit the while (can't send this one so why should i send the next?)
+ break;
}
}
}
@@ -642,55 +789,90 @@ void FiletxTicker(void)
void Got_Filetxpak(void)
{
INT32 filenum = netbuffer->u.filetxpak.fileid;
+ fileneeded_t *file = &fileneeded[filenum];
+ char *filename = file->filename;
static INT32 filetime = 0;
+ if (!(strcmp(filename, "srb2.srb")
+ && strcmp(filename, "srb2.wad")
+ && strcmp(filename, "zones.dta")
+ && strcmp(filename, "player.dta")
+ && strcmp(filename, "rings.dta")
+ && strcmp(filename, "patch.dta")
+ && strcmp(filename, "music.dta")
+ ))
+ I_Error("Tried to download \"%s\"", filename);
+
if (filenum >= fileneedednum)
{
- DEBFILE(va("fileframent not needed %d>%d\n",filenum, fileneedednum));
+ DEBFILE(va("fileframent not needed %d>%d\n", filenum, fileneedednum));
+ //I_Error("Received an unneeded file fragment (file id received: %d, file id needed: %d)\n", filenum, fileneedednum);
return;
}
- if (fileneeded[filenum].status == FS_REQUESTED)
+ if (file->status == FS_REQUESTED)
{
- if (fileneeded[filenum].phandle) I_Error("Got_Filetxpak: allready open file\n");
- fileneeded[filenum].phandle = fopen(fileneeded[filenum].filename, "wb");
- if (!fileneeded[filenum].phandle) I_Error("Can't create file %s: %s",fileneeded[filenum].filename, strerror(errno));
- CONS_Printf("\r%s...\n",fileneeded[filenum].filename);
- fileneeded[filenum].currentsize = 0;
- fileneeded[filenum].status = FS_DOWNLOADING;
+ if (file->file)
+ I_Error("Got_Filetxpak: already open file\n");
+ file->file = fopen(filename, "wb");
+ if (!file->file)
+ I_Error("Can't create file %s: %s", filename, strerror(errno));
+ CONS_Printf("\r%s...\n",filename);
+ file->currentsize = 0;
+ file->status = FS_DOWNLOADING;
}
- if (fileneeded[filenum].status == FS_DOWNLOADING)
+ if (file->status == FS_DOWNLOADING)
{
UINT32 pos = LONG(netbuffer->u.filetxpak.position);
UINT16 size = SHORT(netbuffer->u.filetxpak.size);
- // use a special tric to know when file is finished (not allways used)
- // WARNING: filepak can arrive out of order so don't stop now !
+ // Use a special trick to know when the file is complete (not always used)
+ // WARNING: file fragments can arrive out of order so don't stop yet!
if (pos & 0x80000000)
{
pos &= ~0x80000000;
- fileneeded[filenum].totalsize = pos + size;
+ file->totalsize = pos + size;
}
- // we can receive packet in the wrong order, anyway all os support gaped file
- fseek(fileneeded[filenum].phandle,pos,SEEK_SET);
- if (fwrite(netbuffer->u.filetxpak.data,size,1,fileneeded[filenum].phandle)!=1)
- I_Error("Can't write to %s: %s\n",fileneeded[filenum].filename, strerror(ferror(fileneeded[filenum].phandle)));
- fileneeded[filenum].currentsize += size;
+ // We can receive packet in the wrong order, anyway all os support gaped file
+ fseek(file->file, pos, SEEK_SET);
+ if (fwrite(netbuffer->u.filetxpak.data,size,1,file->file) != 1)
+ I_Error("Can't write to %s: %s\n",filename, strerror(ferror(file->file)));
+ file->currentsize += size;
- // finished?
- if (fileneeded[filenum].currentsize == fileneeded[filenum].totalsize)
+ // Finished?
+ if (file->currentsize == file->totalsize)
{
- fclose(fileneeded[filenum].phandle);
- fileneeded[filenum].phandle = NULL;
- fileneeded[filenum].status = FS_FOUND;
+ fclose(file->file);
+ file->file = NULL;
+ file->status = FS_FOUND;
CONS_Printf(M_GetText("Downloading %s...(done)\n"),
- fileneeded[filenum].filename);
+ filename);
}
}
else
- I_Error("Received a file not requested\n");
- // send ack back quickly
-
+ {
+ const char *s;
+ switch(file->status)
+ {
+ case FS_NOTFOUND:
+ s = "FS_NOTFOUND";
+ break;
+ case FS_FOUND:
+ s = "FS_FOUND";
+ break;
+ case FS_OPEN:
+ s = "FS_OPEN";
+ break;
+ case FS_MD5SUMBAD:
+ s = "FS_MD5SUMBAD";
+ break;
+ default:
+ s = "unknown";
+ break;
+ }
+ I_Error("Received a file not requested (file id: %d, file status: %s)\n", filenum, s);
+ }
+ // Send ack back quickly
if (++filetime == 3)
{
Net_SendAcks(servernode);
@@ -702,33 +884,50 @@ void Got_Filetxpak(void)
#endif
}
-void AbortSendFiles(INT32 node)
+/** \brief Checks if a node is downloading a file
+ *
+ * \param node The node to check for
+ * \return True if the node is downloading a file
+ *
+ */
+boolean SV_SendingFile(INT32 node)
+{
+ return transfer[node].txlist != NULL;
+}
+
+/** Cancels all file requests for a node
+ *
+ * \param node The destination
+ * \sa SV_EndFileSend
+ *
+ */
+void SV_AbortSendFiles(INT32 node)
{
while (transfer[node].txlist)
- EndSend(node);
+ SV_EndFileSend(node);
}
void CloseNetFile(void)
{
INT32 i;
- // is sending?
+ // Is sending?
for (i = 0; i < MAXNETNODES; i++)
- AbortSendFiles(i);
+ SV_AbortSendFiles(i);
- // receiving a file?
+ // Receiving a file?
for (i = 0; i < MAX_WADFILES; i++)
- if (fileneeded[i].status == FS_DOWNLOADING && fileneeded[i].phandle)
+ if (fileneeded[i].status == FS_DOWNLOADING && fileneeded[i].file)
{
- fclose(fileneeded[i].phandle);
- // file is not complete delete it
+ fclose(fileneeded[i].file);
+ // File is not complete delete it
remove(fileneeded[i].filename);
}
- // remove FILEFRAGMENT from acknledge list
+ // Remove PT_FILEFRAGMENT from acknowledge list
Net_AbortPacketType(PT_FILEFRAGMENT);
}
-// functions cut and pasted from doomatic :)
+// Functions cut and pasted from Doomatic :)
void nameonly(char *s)
{
diff --git a/src/d_netfil.h b/src/d_netfil.h
index a68119f1..b9b7b2f2 100644
--- a/src/d_netfil.h
+++ b/src/d_netfil.h
@@ -29,21 +29,21 @@ typedef enum
FS_FOUND,
FS_REQUESTED,
FS_DOWNLOADING,
- FS_OPEN, // is opened and used in w_wad
+ FS_OPEN, // Is opened and used in w_wad
FS_MD5SUMBAD
} filestatus_t;
typedef struct
{
UINT8 important;
- UINT8 willsend; // is the server willing to send it?
+ UINT8 willsend; // Is the server willing to send it?
char filename[MAX_WADPATH];
UINT8 md5sum[16];
- // used only for download
- FILE *phandle;
+ // Used only for download
+ FILE *file;
UINT32 currentsize;
UINT32 totalsize;
- filestatus_t status; // the value returned by recsearch
+ filestatus_t status; // The value returned by recsearch
} fileneeded_t;
extern INT32 fileneedednum;
@@ -58,28 +58,25 @@ UINT8 *PutFileNeeded(void);
void D_ParseFileneeded(INT32 fileneedednum_parm, UINT8 *fileneededstr);
void CL_PrepareDownloadSaveGame(const char *tmpsave);
-// check file list in wadfiles return 0 when a file is not found
-// 1 if all file are found
-// 2 if you cannot connect (different wad version or
-// no enought space to download files)
INT32 CL_CheckFiles(void);
void CL_LoadServerFiles(void);
-void SendRam(INT32 node, void *data, size_t size, freemethod_t freemethod,
+void SV_SendRam(INT32 node, void *data, size_t size, freemethod_t freemethod,
UINT8 fileid);
-void FiletxTicker(void);
+void SV_FileSendTicker(void);
void Got_Filetxpak(void);
+boolean SV_SendingFile(INT32 node);
boolean CL_CheckDownloadable(void);
boolean CL_SendRequestFile(void);
-void Got_RequestFilePak(INT32 node);
+boolean Got_RequestFilePak(INT32 node);
-void AbortSendFiles(INT32 node);
+void SV_AbortSendFiles(INT32 node);
void CloseNetFile(void);
boolean fileexist(char *filename, time_t ptime);
-// search a file in the wadpath, return FS_FOUND when found
+// Search a file in the wadpath, return FS_FOUND when found
filestatus_t findfile(char *filename, const UINT8 *wantedmd5sum,
boolean completepath);
filestatus_t checkfilemd5(char *filename, const UINT8 *wantedmd5sum);
diff --git a/src/dehacked.c b/src/dehacked.c
index 199ea43c..f03dd73b 100644
--- a/src/dehacked.c
+++ b/src/dehacked.c
@@ -6717,12 +6717,14 @@ static const char *const MOBJEFLAG_LIST[] = {
NULL
};
+#ifdef HAVE_BLUA
static const char *const MAPTHINGFLAG_LIST[4] = {
NULL,
"OBJECTFLIP", // Reverse gravity flag for objects.
"OBJECTSPECIAL", // Special flag used with certain objects.
"AMBUSH" // Deaf monsters/do not react to sound.
};
+#endif
static const char *const PLAYERFLAG_LIST[] = {
// Flip camera angle with gravity flip prefrence.
@@ -6795,6 +6797,7 @@ static const char *const PLAYERFLAG_LIST[] = {
NULL // stop loop here.
};
+#ifdef HAVE_BLUA
// Linedef flags
static const char *const ML_LIST[16] = {
"IMPASSIBLE",
@@ -6814,6 +6817,7 @@ static const char *const ML_LIST[16] = {
"BOUNCY",
"TFERLINE"
};
+#endif
// This DOES differ from r_draw's Color_Names, unfortunately.
// Also includes Super colors
@@ -7762,7 +7766,7 @@ fixed_t get_number(const char *word)
#endif
}
-void DEH_Check(void)
+void FUNCMATH DEH_Check(void)
{
#if defined(_DEBUG) || defined(PARANOIA)
const size_t dehstates = sizeof(STATE_LIST)/sizeof(const char*);
@@ -8276,6 +8280,9 @@ static inline int lib_getenum(lua_State *L)
} else if (fastcmp(word,"VERSIONSTRING")) {
lua_pushstring(L, VERSIONSTRING);
return 1;
+ } else if (fastcmp(word, "token")) {
+ lua_pushinteger(L, token);
+ return 1;
}
return 0;
diff --git a/src/djgppdos/i_system.c b/src/djgppdos/i_system.c
index 854d68f4..dae9ed16 100644
--- a/src/djgppdos/i_system.c
+++ b/src/djgppdos/i_system.c
@@ -1721,6 +1721,18 @@ INT32 I_PutEnv(char *variable)
return putenv(variable);
}
+INT32 I_ClipboardCopy(const char *data, size_t size)
+{
+ (void)data;
+ (void)size;
+ return -1;
+}
+
+char *I_ClipboardPaste(void)
+{
+ return NULL;
+}
+
const CPUInfoFlags *I_CPUInfo(void)
{
static CPUInfoFlags DOS_CPUInfo;
diff --git a/src/doomdef.h b/src/doomdef.h
index 9a1e5af9..cdb1a7db 100644
--- a/src/doomdef.h
+++ b/src/doomdef.h
@@ -60,6 +60,7 @@
#endif
#ifdef _WINDOWS
+#define NONET
#if !defined (HWRENDER) && !defined (NOHW)
#define HWRENDER
#endif
@@ -149,9 +150,9 @@ extern FILE *logstream;
// we use comprevision and compbranch instead.
#else
#define VERSION 201 // Game version
-#define SUBVERSION 15 // more precise version number
-#define VERSIONSTRING "v2.1.15"
-#define VERSIONSTRINGW L"v2.1.15"
+#define SUBVERSION 19 // more precise version number
+#define VERSIONSTRING "v2.1.19"
+#define VERSIONSTRINGW L"v2.1.19"
// Hey! If you change this, add 1 to the MODVERSION below!
// Otherwise we can't force updates!
#endif
@@ -213,7 +214,7 @@ extern FILE *logstream;
// it's only for detection of the version the player is using so the MS can alert them of an update.
// Only set it higher, not lower, obviously.
// Note that we use this to help keep internal testing in check; this is why v2.1.0 is not version "1".
-#define MODVERSION 20
+#define MODVERSION 24
// =========================================================================
@@ -393,6 +394,9 @@ extern INT32 cv_debug;
// Misc stuff for later...
// =======================
+// Modifier key variables, accessible anywhere
+extern UINT8 shiftdown, ctrldown, altdown;
+
// if we ever make our alloc stuff...
#define ZZ_Alloc(x) Z_Malloc(x, PU_STATIC, NULL)
@@ -431,6 +435,12 @@ extern const char *compdate, *comptime, *comprevision, *compbranch;
/// Kalaron/Eternity Engine slope code (SRB2CB ported)
#define ESLOPE
+#ifdef ESLOPE
+/// Backwards compatibility with SRB2CB's slope linedef types.
+/// \note A simple shim that prints a warning.
+#define ESLOPE_TYPESHIM
+#endif
+
/// Delete file while the game is running.
/// \note EXTREMELY buggy, tends to crash game.
//#define DELFILE
diff --git a/src/doomtype.h b/src/doomtype.h
index 2d9d3632..a711b466 100644
--- a/src/doomtype.h
+++ b/src/doomtype.h
@@ -92,7 +92,7 @@ typedef long ssize_t;
#endif
#ifdef __APPLE_CC__
-#define DIRECTFULLSCREEN
+#define DIRECTFULLSCREEN 1
#define DEBUG_LOG
#define NOIPX
#endif
diff --git a/src/dummy/i_system.c b/src/dummy/i_system.c
index c1e48b60..a3fe3077 100644
--- a/src/dummy/i_system.c
+++ b/src/dummy/i_system.c
@@ -162,6 +162,18 @@ INT32 I_PutEnv(char *variable)
return -1;
}
+INT32 I_ClipboardCopy(const char *data, size_t size)
+{
+ (void)data;
+ (void)size;
+ return -1;
+}
+
+char *I_ClipboardPaste(void)
+{
+ return NULL;
+}
+
void I_RegisterSysCommands(void) {}
#include "../sdl/dosstr.c"
diff --git a/src/f_finale.c b/src/f_finale.c
index 776bec98..692abb35 100644
--- a/src/f_finale.c
+++ b/src/f_finale.c
@@ -974,7 +974,7 @@ static const char *credits[] = {
"Scott \"Graue\" Feeney",
"Nathan \"Jazz\" Giroux",
"Thomas \"Shadow Hog\" Igoe",
- "\"Monster\" Iestyn Jealous",
+ "Iestyn \"Monster Iestyn\" Jealous",
"Ronald \"Furyhunter\" Kinard", // The SDL2 port
"John \"JTE\" Muniz",
"Ehab \"Wolfy\" Saeed",
@@ -986,6 +986,8 @@ static const char *credits[] = {
"\"chi.miru\"", // Red's secret weapon, the REAL reason slopes exist (also helped port drawing code from ZDoom)
"Andrew \"orospakr\" Clunis",
"Gregor \"Oogaland\" Dick",
+ "Louis-Antoine \"LJSonic\" de Moulins", // for fixing 2.1's netcode (de Rochefort doesn't quite fit on the screen sorry lol)
+ "Vivian \"toaster\" Grannell",
"Julio \"Chaos Zero 64\" Guir",
"\"Kalaron\"", // Coded some of Sryder13's collection of OpenGL fixes, especially fog
"Matthew \"Shuffle\" Marsalko",
@@ -1019,7 +1021,7 @@ static const char *credits[] = {
"Paul \"Boinciel\" Clempson",
"Cyan Helkaraxe",
"Kepa \"Nev3r\" Iceta",
- "\"Monster\" Iestyn Jealous",
+ "Iestyn \"Monster Iestyn\" Jealous",
"Jarel \"Arrow\" Jones",
"Stefan \"Stuf\" Rimalia",
"Shane Mychal Sexton",
@@ -1724,6 +1726,7 @@ static void F_AdvanceToNextScene(void)
void F_EndCutScene(void)
{
+ cutsceneover = true; // do this first, just in case Y_EndGame or something wants to turn it back false later
if (runningprecutscene)
{
if (server)
@@ -1740,7 +1743,6 @@ void F_EndCutScene(void)
else
Y_EndGame();
}
- cutsceneover = true;
}
void F_StartCustomCutscene(INT32 cutscenenum, boolean precutscene, boolean resetplayer)
diff --git a/src/f_finale.h b/src/f_finale.h
index 8ee02bdf..1f23643b 100644
--- a/src/f_finale.h
+++ b/src/f_finale.h
@@ -35,7 +35,7 @@ void F_CutsceneTicker(void);
void F_TitleDemoTicker(void);
// Called by main loop.
-void F_GameEndDrawer(void);
+FUNCMATH void F_GameEndDrawer(void);
void F_IntroDrawer(void);
void F_TitleScreenDrawer(void);
diff --git a/src/g_game.c b/src/g_game.c
index 8931f8b6..7499fe7a 100644
--- a/src/g_game.c
+++ b/src/g_game.c
@@ -711,6 +711,10 @@ void G_SetGameModified(boolean silent)
if (!silent)
CONS_Alert(CONS_NOTICE, M_GetText("Game must be restarted to record statistics.\n"));
+
+ // If in record attack recording, cancel it.
+ if (modeattacking)
+ M_EndModeAttackRun();
}
/** Builds an original game map name from a map number.
@@ -2884,7 +2888,7 @@ static void G_DoCompleted(void)
if (nextmap < NUMMAPS && !mapheaderinfo[nextmap])
P_AllocMapHeader(nextmap);
- if (skipstats)
+ if (skipstats && !modeattacking) // Don't skip stats if we're in record attack
G_AfterIntermission();
else
{
@@ -5575,7 +5579,7 @@ boolean G_CheckDemoStatus(void)
WRITEUINT8(demo_p, DEMOMARKER); // add the demo end marker
md5_buffer((char *)p+16, demo_p - (p+16), p); // make a checksum of everything after the checksum in the file.
#endif
- saved = FIL_WriteFile(demoname, demobuffer, demo_p - demobuffer); // finally output the file.
+ saved = FIL_WriteFile(va(pandf, srb2home, demoname), demobuffer, demo_p - demobuffer); // finally output the file.
free(demobuffer);
demorecording = false;
diff --git a/src/hardware/hw_dll.h b/src/hardware/hw_dll.h
index d9620be0..6b9f4d53 100644
--- a/src/hardware/hw_dll.h
+++ b/src/hardware/hw_dll.h
@@ -54,7 +54,7 @@
#endif
#endif
-typedef void (*I_Error_t) (const char *error, ...);
+typedef void (*I_Error_t) (const char *error, ...) FUNCIERROR;
// ==========================================================================
// MATHS
diff --git a/src/hardware/hw_draw.c b/src/hardware/hw_draw.c
index 60183b58..f23753ee 100644
--- a/src/hardware/hw_draw.c
+++ b/src/hardware/hw_draw.c
@@ -656,6 +656,7 @@ void HWR_DrawFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 color)
{
FOutVector v[4];
FSurfaceInfo Surf;
+ float sdupx, sdupy;
if (w < 0 || h < 0)
return; // consistency w/ software
@@ -664,10 +665,16 @@ void HWR_DrawFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 color)
// | /|
// |/ |
// 0--1
- v[0].x = v[3].x = (x - 160.0f)/160.0f;
- v[2].x = v[1].x = ((x+w) - 160.0f)/160.0f;
- v[0].y = v[1].y = -(y - 100.0f)/100.0f;
- v[2].y = v[3].y = -((y+h) - 100.0f)/100.0f;
+ sdupx = FIXED_TO_FLOAT(vid.fdupx)*2.0f;
+ sdupy = FIXED_TO_FLOAT(vid.fdupy)*2.0f;
+
+ if (color & V_NOSCALESTART)
+ sdupx = sdupy = 2.0f;
+
+ v[0].x = v[3].x = (x*sdupx)/vid.width - 1;
+ v[2].x = v[1].x = (x*sdupx + w*sdupx)/vid.width - 1;
+ v[0].y = v[1].y = 1-(y*sdupy)/vid.height;
+ v[2].y = v[3].y = 1-(y*sdupy + h*sdupy)/vid.height;
//Hurdler: do we still use this argb color? if not, we should remove it
v[0].argb = v[1].argb = v[2].argb = v[3].argb = 0xff00ff00; //;
diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c
index 35a01ffd..05391f4d 100644
--- a/src/hardware/hw_main.c
+++ b/src/hardware/hw_main.c
@@ -45,7 +45,7 @@
#include "hw_md2.h"
#define R_FAKEFLOORS
-//#define HWPRECIP
+#define HWPRECIP
#define SORTING
//#define POLYSKY
@@ -66,9 +66,9 @@ static void HWR_ProjectPrecipitationSprite(precipmobj_t *thing);
#endif
#ifdef SORTING
-void HWR_AddTransparentFloor(lumpnum_t lumpnum, extrasubsector_t *xsub, fixed_t fixedheight,
+void HWR_AddTransparentFloor(lumpnum_t lumpnum, extrasubsector_t *xsub, boolean isceiling, fixed_t fixedheight,
INT32 lightlevel, INT32 alpha, sector_t *FOFSector, FBITFIELD blend, boolean fogplane, extracolormap_t *planecolormap);
-void HWR_AddTransparentPolyobjectFloor(lumpnum_t lumpnum, polyobj_t *polysector, fixed_t fixedheight,
+void HWR_AddTransparentPolyobjectFloor(lumpnum_t lumpnum, polyobj_t *polysector, boolean isceiling, fixed_t fixedheight,
INT32 lightlevel, INT32 alpha, sector_t *FOFSector, FBITFIELD blend, extracolormap_t *planecolormap);
#else
static void HWR_Add3DWater(lumpnum_t lumpnum, extrasubsector_t *xsub, fixed_t fixedheight,
@@ -521,7 +521,7 @@ static UINT8 HWR_FogBlockAlpha(INT32 light, UINT32 color, UINT32 fadecolor) // L
// -----------------+
// HWR_RenderPlane : Render a floor or ceiling convex polygon
// -----------------+
-static void HWR_RenderPlane(sector_t *sector, extrasubsector_t *xsub, fixed_t fixedheight,
+static void HWR_RenderPlane(sector_t *sector, extrasubsector_t *xsub, boolean isceiling, fixed_t fixedheight,
FBITFIELD PolyFlags, INT32 lightlevel, lumpnum_t lumpnum, sector_t *FOFsector, UINT8 alpha, boolean fogplane, extracolormap_t *planecolormap)
{
polyvertex_t * pv;
@@ -554,17 +554,16 @@ static void HWR_RenderPlane(sector_t *sector, extrasubsector_t *xsub, fixed_t fi
// Get the slope pointer to simplify future code
if (FOFsector)
{
- if (FOFsector->f_slope && FOFsector->floorheight == fixedheight)
+ if (FOFsector->f_slope && !isceiling)
slope = FOFsector->f_slope;
- else if (FOFsector->c_slope && FOFsector->ceilingheight == fixedheight)
+ else if (FOFsector->c_slope && isceiling)
slope = FOFsector->c_slope;
}
else
{
- // Use fixedheight to determine whether to check floor or ceiling because I hate my life
- if (gr_frontsector->f_slope && gr_frontsector->floorheight == fixedheight)
+ if (gr_frontsector->f_slope && !isceiling)
slope = gr_frontsector->f_slope;
- else if (gr_frontsector->c_slope && gr_frontsector->ceilingheight == fixedheight)
+ else if (gr_frontsector->c_slope && isceiling)
slope = gr_frontsector->c_slope;
}
@@ -638,12 +637,7 @@ static void HWR_RenderPlane(sector_t *sector, extrasubsector_t *xsub, fixed_t fi
if (FOFsector != NULL)
{
-#ifdef ESLOPE
- if ((slope && slope == FOFsector->f_slope)
- || fixedheight == FOFsector->floorheight) // it's a floor
-#else
- if (fixedheight == FOFsector->floorheight) // it's a floor
-#endif
+ if (!isceiling) // it's a floor
{
scrollx = FIXED_TO_FLOAT(FOFsector->floor_xoffs)/fflatsize;
scrolly = FIXED_TO_FLOAT(FOFsector->floor_yoffs)/fflatsize;
@@ -658,12 +652,7 @@ static void HWR_RenderPlane(sector_t *sector, extrasubsector_t *xsub, fixed_t fi
}
else if (gr_frontsector)
{
-#ifdef ESLOPE
- if ((slope && slope == gr_frontsector->f_slope)
- || fixedheight == gr_frontsector->floorheight) // it's a floor
-#else
- if (fixedheight < dup_viewz) // it's a floor
-#endif
+ if (!isceiling) // it's a floor
{
scrollx = FIXED_TO_FLOAT(gr_frontsector->floor_xoffs)/fflatsize;
scrolly = FIXED_TO_FLOAT(gr_frontsector->floor_yoffs)/fflatsize;
@@ -1095,9 +1084,9 @@ static void HWR_SplitWall(sector_t *sector, wallVert3D *wallVerts, INT32 texnum,
float endheight = 0.0f, endbheight = 0.0f;
fixed_t v1x = FLOAT_TO_FIXED(wallVerts[0].x);
- fixed_t v1y = FLOAT_TO_FIXED(wallVerts[0].y);
+ fixed_t v1y = FLOAT_TO_FIXED(wallVerts[0].z); // not a typo
fixed_t v2x = FLOAT_TO_FIXED(wallVerts[1].x);
- fixed_t v2y = FLOAT_TO_FIXED(wallVerts[1].y);
+ fixed_t v2y = FLOAT_TO_FIXED(wallVerts[1].z); // not a typo
// compiler complains when P_GetZAt is used in FLOAT_TO_FIXED directly
// use this as a temp var to store P_GetZAt's return value each time
fixed_t temp;
@@ -1569,6 +1558,7 @@ static void HWR_StoreWallRange(double startfrac, double endfrac)
if (gr_backsector)
{
+ INT32 gr_toptexture, gr_bottomtexture;
// two sided line
if (gr_backsector->heightsec != -1)
{
@@ -1619,19 +1609,22 @@ static void HWR_StoreWallRange(double startfrac, double endfrac)
#endif
}
+ gr_toptexture = R_GetTextureNum(gr_sidedef->toptexture);
+ gr_bottomtexture = R_GetTextureNum(gr_sidedef->bottomtexture);
+
// check TOP TEXTURE
if ((
#ifdef ESLOPE
worldhighslope < worldtopslope ||
#endif
worldhigh < worldtop
- ) && texturetranslation[gr_sidedef->toptexture])
+ ) && gr_toptexture)
{
if (drawtextured)
{
fixed_t texturevpegtop; // top
- grTex = HWR_GetTexture(texturetranslation[gr_sidedef->toptexture]);
+ grTex = HWR_GetTexture(gr_toptexture);
// PEGGING
if (gr_linedef->flags & ML_DONTPEGTOP)
@@ -1649,7 +1642,7 @@ static void HWR_StoreWallRange(double startfrac, double endfrac)
texturevpegtop += gr_sidedef->rowoffset;
// This is so that it doesn't overflow and screw up the wall, it doesn't need to go higher than the texture's height anyway
- texturevpegtop %= SHORT(textures[texturetranslation[gr_sidedef->toptexture]]->height)<height)<scaleY;
wallVerts[0].t = wallVerts[1].t = (texturevpegtop + gr_frontsector->ceilingheight - gr_backsector->ceilingheight) * grTex->scaleY;
@@ -1694,9 +1687,9 @@ static void HWR_StoreWallRange(double startfrac, double endfrac)
#endif
if (gr_frontsector->numlights)
- HWR_SplitWall(gr_frontsector, wallVerts, texturetranslation[gr_sidedef->toptexture], &Surf, FF_CUTSOLIDS);
+ HWR_SplitWall(gr_frontsector, wallVerts, gr_toptexture, &Surf, FF_CUTSOLIDS);
else if (grTex->mipmap.flags & TF_TRANSPARENT)
- HWR_AddTransparentWall(wallVerts, &Surf, texturetranslation[gr_sidedef->toptexture], PF_Environment, false, lightnum, colormap);
+ HWR_AddTransparentWall(wallVerts, &Surf, gr_toptexture, PF_Environment, false, lightnum, colormap);
else
HWR_ProjectWall(wallVerts, &Surf, PF_Masked, lightnum, colormap);
}
@@ -1706,13 +1699,13 @@ static void HWR_StoreWallRange(double startfrac, double endfrac)
#ifdef ESLOPE
worldlowslope > worldbottomslope ||
#endif
- worldlow > worldbottom) && texturetranslation[gr_sidedef->bottomtexture]) //only if VISIBLE!!!
+ worldlow > worldbottom) && gr_bottomtexture) //only if VISIBLE!!!
{
if (drawtextured)
{
fixed_t texturevpegbottom = 0; // bottom
- grTex = HWR_GetTexture(texturetranslation[gr_sidedef->bottomtexture]);
+ grTex = HWR_GetTexture(gr_bottomtexture);
// PEGGING
#ifdef ESLOPE
@@ -1732,7 +1725,7 @@ static void HWR_StoreWallRange(double startfrac, double endfrac)
texturevpegbottom += gr_sidedef->rowoffset;
// This is so that it doesn't overflow and screw up the wall, it doesn't need to go higher than the texture's height anyway
- texturevpegbottom %= SHORT(textures[texturetranslation[gr_sidedef->bottomtexture]]->height)<height)<scaleY;
wallVerts[0].t = wallVerts[1].t = (texturevpegbottom + gr_backsector->floorheight - gr_frontsector->floorheight) * grTex->scaleY;
@@ -1777,13 +1770,13 @@ static void HWR_StoreWallRange(double startfrac, double endfrac)
#endif
if (gr_frontsector->numlights)
- HWR_SplitWall(gr_frontsector, wallVerts, texturetranslation[gr_sidedef->bottomtexture], &Surf, FF_CUTSOLIDS);
+ HWR_SplitWall(gr_frontsector, wallVerts, gr_bottomtexture, &Surf, FF_CUTSOLIDS);
else if (grTex->mipmap.flags & TF_TRANSPARENT)
- HWR_AddTransparentWall(wallVerts, &Surf, texturetranslation[gr_sidedef->bottomtexture], PF_Environment, false, lightnum, colormap);
+ HWR_AddTransparentWall(wallVerts, &Surf, gr_bottomtexture, PF_Environment, false, lightnum, colormap);
else
HWR_ProjectWall(wallVerts, &Surf, PF_Masked, lightnum, colormap);
}
- gr_midtexture = texturetranslation[gr_sidedef->midtexture];
+ gr_midtexture = R_GetTextureNum(gr_sidedef->midtexture);
if (gr_midtexture)
{
FBITFIELD blendmode;
@@ -2145,7 +2138,7 @@ static void HWR_StoreWallRange(double startfrac, double endfrac)
else
{
// Single sided line... Deal only with the middletexture (if one exists)
- gr_midtexture = texturetranslation[gr_sidedef->midtexture];
+ gr_midtexture = R_GetTextureNum(gr_sidedef->midtexture);
if (gr_midtexture)
{
if (drawtextured)
@@ -2243,13 +2236,13 @@ static void HWR_StoreWallRange(double startfrac, double endfrac)
if (*rover->topheight < lowcut || *rover->bottomheight > highcut)
continue;
- texnum = texturetranslation[sides[rover->master->sidenum[0]].midtexture];
+ texnum = R_GetTextureNum(sides[rover->master->sidenum[0]].midtexture);
if (rover->master->flags & ML_TFERLINE)
{
size_t linenum = gr_curline->linedef-gr_backsector->lines[0];
newline = rover->master->frontsector->lines[0] + linenum;
- texnum = texturetranslation[sides[newline->sidenum[0]].midtexture];
+ texnum = R_GetTextureNum(sides[newline->sidenum[0]].midtexture);
}
#ifdef ESLOPE
@@ -2377,13 +2370,13 @@ static void HWR_StoreWallRange(double startfrac, double endfrac)
if (*rover->topheight < lowcut || *rover->bottomheight > highcut)
continue;
- texnum = texturetranslation[sides[rover->master->sidenum[0]].midtexture];
+ texnum = R_GetTextureNum(sides[rover->master->sidenum[0]].midtexture);
if (rover->master->flags & ML_TFERLINE)
{
size_t linenum = gr_curline->linedef-gr_backsector->lines[0];
newline = rover->master->frontsector->lines[0] + linenum;
- texnum = texturetranslation[sides[newline->sidenum[0]].midtexture];
+ texnum = R_GetTextureNum(sides[newline->sidenum[0]].midtexture);
}
#ifdef ESLOPE //backsides
h = *rover->t_slope ? P_GetZAt(*rover->t_slope, v1x, v1y) : *rover->topheight;
@@ -3111,7 +3104,7 @@ static inline void HWR_AddPolyObjectSegs(void)
}
#ifdef POLYOBJECTS_PLANES
-static void HWR_RenderPolyObjectPlane(polyobj_t *polysector, fixed_t fixedheight,
+static void HWR_RenderPolyObjectPlane(polyobj_t *polysector, boolean isceiling, fixed_t fixedheight,
FBITFIELD blendmode, UINT8 lightlevel, lumpnum_t lumpnum, sector_t *FOFsector,
UINT8 alpha, extracolormap_t *planecolormap)
{
@@ -3195,7 +3188,7 @@ static void HWR_RenderPolyObjectPlane(polyobj_t *polysector, fixed_t fixedheight
if (FOFsector != NULL)
{
- if (fixedheight == FOFsector->floorheight) // it's a floor
+ if (!isceiling) // it's a floor
{
scrollx = FIXED_TO_FLOAT(FOFsector->floor_xoffs)/fflatsize;
scrolly = FIXED_TO_FLOAT(FOFsector->floor_yoffs)/fflatsize;
@@ -3210,7 +3203,7 @@ static void HWR_RenderPolyObjectPlane(polyobj_t *polysector, fixed_t fixedheight
}
else if (gr_frontsector)
{
- if (fixedheight < dup_viewz) // it's a floor
+ if (!isceiling) // it's a floor
{
scrollx = FIXED_TO_FLOAT(gr_frontsector->floor_xoffs)/fflatsize;
scrolly = FIXED_TO_FLOAT(gr_frontsector->floor_yoffs)/fflatsize;
@@ -3303,13 +3296,13 @@ static void HWR_AddPolyObjectPlanes(void)
{
FSurfaceInfo Surf;
FBITFIELD blendmode = HWR_TranstableToAlpha(po_ptrs[i]->translucency, &Surf);
- HWR_AddTransparentPolyobjectFloor(levelflats[polyobjsector->floorpic].lumpnum, po_ptrs[i], polyobjsector->floorheight,
+ HWR_AddTransparentPolyobjectFloor(levelflats[polyobjsector->floorpic].lumpnum, po_ptrs[i], false, polyobjsector->floorheight,
polyobjsector->lightlevel, Surf.FlatColor.s.alpha, polyobjsector, blendmode, NULL);
}
else
{
HWR_GetFlat(levelflats[polyobjsector->floorpic].lumpnum);
- HWR_RenderPolyObjectPlane(po_ptrs[i], polyobjsector->floorheight, PF_Occlude,
+ HWR_RenderPolyObjectPlane(po_ptrs[i], false, polyobjsector->floorheight, PF_Occlude,
polyobjsector->lightlevel, levelflats[polyobjsector->floorpic].lumpnum,
polyobjsector, 255, NULL);
}
@@ -3325,13 +3318,13 @@ static void HWR_AddPolyObjectPlanes(void)
FBITFIELD blendmode;
memset(&Surf, 0x00, sizeof(Surf));
blendmode = HWR_TranstableToAlpha(po_ptrs[i]->translucency, &Surf);
- HWR_AddTransparentPolyobjectFloor(levelflats[polyobjsector->ceilingpic].lumpnum, po_ptrs[i], polyobjsector->ceilingheight,
+ HWR_AddTransparentPolyobjectFloor(levelflats[polyobjsector->ceilingpic].lumpnum, po_ptrs[i], true, polyobjsector->ceilingheight,
polyobjsector->lightlevel, Surf.FlatColor.s.alpha, polyobjsector, blendmode, NULL);
}
else
{
HWR_GetFlat(levelflats[polyobjsector->ceilingpic].lumpnum);
- HWR_RenderPolyObjectPlane(po_ptrs[i], polyobjsector->ceilingheight, PF_Occlude,
+ HWR_RenderPolyObjectPlane(po_ptrs[i], true, polyobjsector->ceilingheight, PF_Occlude,
polyobjsector->lightlevel, levelflats[polyobjsector->floorpic].lumpnum,
polyobjsector, 255, NULL);
}
@@ -3485,7 +3478,7 @@ static void HWR_Subsector(size_t num)
if (sub->validcount != validcount)
{
HWR_GetFlat(levelflats[gr_frontsector->floorpic].lumpnum);
- HWR_RenderPlane(gr_frontsector, &extrasubsectors[num],
+ HWR_RenderPlane(gr_frontsector, &extrasubsectors[num], false,
// Hack to make things continue to work around slopes.
locFloorHeight == cullFloorHeight ? locFloorHeight : gr_frontsector->floorheight,
// We now return you to your regularly scheduled rendering.
@@ -3507,7 +3500,7 @@ static void HWR_Subsector(size_t num)
if (sub->validcount != validcount)
{
HWR_GetFlat(levelflats[gr_frontsector->ceilingpic].lumpnum);
- HWR_RenderPlane(NULL, &extrasubsectors[num],
+ HWR_RenderPlane(NULL, &extrasubsectors[num], true,
// Hack to make things continue to work around slopes.
locCeilingHeight == cullCeilingHeight ? locCeilingHeight : gr_frontsector->ceilingheight,
// We now return you to your regularly scheduled rendering.
@@ -3576,6 +3569,7 @@ static void HWR_Subsector(size_t num)
HWR_AddTransparentFloor(0,
&extrasubsectors[num],
+ false,
*rover->bottomheight,
*gr_frontsector->lightlist[light].lightlevel,
alpha, rover->master->frontsector, PF_Translucent|PF_NoTexture,
@@ -3593,6 +3587,7 @@ static void HWR_Subsector(size_t num)
#else
HWR_AddTransparentFloor(levelflats[*rover->bottompic].lumpnum,
&extrasubsectors[num],
+ false,
*rover->bottomheight,
*gr_frontsector->lightlist[light].lightlevel,
rover->alpha-1 > 255 ? 255 : rover->alpha-1, rover->master->frontsector, PF_Translucent,
@@ -3603,7 +3598,7 @@ static void HWR_Subsector(size_t num)
{
HWR_GetFlat(levelflats[*rover->bottompic].lumpnum);
light = R_GetPlaneLight(gr_frontsector, centerHeight, dup_viewz < cullHeight ? true : false);
- HWR_RenderPlane(NULL, &extrasubsectors[num], *rover->bottomheight, PF_Occlude, *gr_frontsector->lightlist[light].lightlevel, levelflats[*rover->bottompic].lumpnum,
+ HWR_RenderPlane(NULL, &extrasubsectors[num], false, *rover->bottomheight, PF_Occlude, *gr_frontsector->lightlist[light].lightlevel, levelflats[*rover->bottompic].lumpnum,
rover->master->frontsector, 255, false, gr_frontsector->lightlist[light].extra_colormap);
}
}
@@ -3637,6 +3632,7 @@ static void HWR_Subsector(size_t num)
HWR_AddTransparentFloor(0,
&extrasubsectors[num],
+ true,
*rover->topheight,
*gr_frontsector->lightlist[light].lightlevel,
alpha, rover->master->frontsector, PF_Translucent|PF_NoTexture,
@@ -3654,6 +3650,7 @@ static void HWR_Subsector(size_t num)
#else
HWR_AddTransparentFloor(levelflats[*rover->toppic].lumpnum,
&extrasubsectors[num],
+ true,
*rover->topheight,
*gr_frontsector->lightlist[light].lightlevel,
rover->alpha-1 > 255 ? 255 : rover->alpha-1, rover->master->frontsector, PF_Translucent,
@@ -3665,7 +3662,7 @@ static void HWR_Subsector(size_t num)
{
HWR_GetFlat(levelflats[*rover->toppic].lumpnum);
light = R_GetPlaneLight(gr_frontsector, centerHeight, dup_viewz < cullHeight ? true : false);
- HWR_RenderPlane(NULL, &extrasubsectors[num], *rover->topheight, PF_Occlude, *gr_frontsector->lightlist[light].lightlevel, levelflats[*rover->toppic].lumpnum,
+ HWR_RenderPlane(NULL, &extrasubsectors[num], true, *rover->topheight, PF_Occlude, *gr_frontsector->lightlist[light].lightlevel, levelflats[*rover->toppic].lumpnum,
rover->master->frontsector, 255, false, gr_frontsector->lightlist[light].extra_colormap);
}
}
@@ -3725,6 +3722,9 @@ static void HWR_Subsector(size_t num)
while (count--)
{
+#ifdef POLYOBJECTS
+ if (!line->polyseg) // ignore segs that belong to polyobjects
+#endif
HWR_AddLine(line);
line++;
}
@@ -4408,7 +4408,6 @@ static inline void HWR_DrawPrecipitationSprite(gr_vissprite_t *spr)
FOutVector *wv;
GLPatch_t *gpatch; // sprite patch converted to hardware
FSurfaceInfo Surf;
- sector_t *sector;
if (!spr->mobj)
return;
@@ -4462,19 +4461,38 @@ static inline void HWR_DrawPrecipitationSprite(gr_vissprite_t *spr)
//Hurdler: 25/04/2000: now support colormap in hardware mode
HWR_GetMappedPatch(gpatch, spr->colormap);
- sector = spr->mobj->subsector->sector;
-
- if (sector->ffloors)
+ // colormap test
{
- ffloor_t *caster = sector->lightlist[R_GetPlaneLight(sector, spr->mobj->z, false)].caster;
- sector = caster ? §ors[caster->secnum] : sector;
- }
+ sector_t *sector = spr->mobj->subsector->sector;
+ UINT8 lightlevel = 255;
+ extracolormap_t *colormap = sector->extra_colormap;
- // sprite lighting by modulating the RGB components
- if (sector->extra_colormap)
- Surf.FlatColor.rgba = HWR_Lighting(spr->sectorlight,sector->extra_colormap->rgba,sector->extra_colormap->fadergba, false, false);
+ if (sector->numlights)
+ {
+ INT32 light;
+
+ light = R_GetPlaneLight(sector, spr->mobj->z + spr->mobj->height, false); // Always use the light at the top instead of whatever I was doing before
+
+ if (!(spr->mobj->frame & FF_FULLBRIGHT))
+ lightlevel = *sector->lightlist[light].lightlevel;
+
+ if (sector->lightlist[light].extra_colormap)
+ colormap = sector->lightlist[light].extra_colormap;
+ }
else
- Surf.FlatColor.rgba = HWR_Lighting(spr->sectorlight,NORMALFOG,FADEFOG, false, false);
+ {
+ if (!(spr->mobj->frame & FF_FULLBRIGHT))
+ lightlevel = sector->lightlevel;
+
+ if (sector->extra_colormap)
+ colormap = sector->extra_colormap;
+ }
+
+ if (colormap)
+ Surf.FlatColor.rgba = HWR_Lighting(lightlevel, colormap->rgba, colormap->fadergba, false, false);
+ else
+ Surf.FlatColor.rgba = HWR_Lighting(lightlevel, NORMALFOG, FADEFOG, false, false);
+ }
if (spr->mobj->flags2 & MF2_SHADOW)
{
@@ -4508,8 +4526,8 @@ static void HWR_SortVisSprites(void)
gr_vissprite_t *ds, *dsprev, *dsnext, *dsfirst;
gr_vissprite_t *best = NULL;
gr_vissprite_t unsorted;
- float bestdist;
- INT32 bestdispoffset;
+ float bestdist = 0.0f;
+ INT32 bestdispoffset = 0;
if (!gr_visspritecount)
return;
@@ -4529,7 +4547,8 @@ static void HWR_SortVisSprites(void)
// Fix first and last. ds still points to the last one after the loop
dsfirst->prev = &unsorted;
unsorted.next = dsfirst;
- ds->next = &unsorted;
+ if (ds)
+ ds->next = &unsorted;
unsorted.prev = ds;
// pull the vissprites out by scale
@@ -4552,10 +4571,13 @@ static void HWR_SortVisSprites(void)
best = ds;
}
}
- best->next->prev = best->prev;
- best->prev->next = best->next;
- best->next = &gr_vsprsortedhead;
- best->prev = gr_vsprsortedhead.prev;
+ if (best)
+ {
+ best->next->prev = best->prev;
+ best->prev->next = best->next;
+ best->next = &gr_vsprsortedhead;
+ best->prev = gr_vsprsortedhead.prev;
+ }
gr_vsprsortedhead.prev->next = best;
gr_vsprsortedhead.prev = best;
}
@@ -4588,6 +4610,7 @@ static void HWR_RenderWall(wallVert3D *wallVerts, FSurfaceInfo *pSurf, FBITFIE
typedef struct
{
extrasubsector_t *xsub;
+ boolean isceiling;
fixed_t fixedheight;
INT32 lightlevel;
lumpnum_t lumpnum;
@@ -4605,6 +4628,7 @@ static planeinfo_t *planeinfo = NULL;
typedef struct
{
polyobj_t *polysector;
+ boolean isceiling;
fixed_t fixedheight;
INT32 lightlevel;
lumpnum_t lumpnum;
@@ -4640,7 +4664,7 @@ static INT32 drawcount = 0;
#define MAX_TRANSPARENTFLOOR 512
// This will likely turn into a copy of HWR_Add3DWater and replace it.
-void HWR_AddTransparentFloor(lumpnum_t lumpnum, extrasubsector_t *xsub,
+void HWR_AddTransparentFloor(lumpnum_t lumpnum, extrasubsector_t *xsub, boolean isceiling,
fixed_t fixedheight, INT32 lightlevel, INT32 alpha, sector_t *FOFSector, FBITFIELD blend, boolean fogplane, extracolormap_t *planecolormap)
{
static size_t allocedplanes = 0;
@@ -4655,6 +4679,7 @@ void HWR_AddTransparentFloor(lumpnum_t lumpnum, extrasubsector_t *xsub,
Z_Realloc(planeinfo, allocedplanes * sizeof (*planeinfo), PU_LEVEL, &planeinfo);
}
+ planeinfo[numplanes].isceiling = isceiling;
planeinfo[numplanes].fixedheight = fixedheight;
planeinfo[numplanes].lightlevel = lightlevel;
planeinfo[numplanes].lumpnum = lumpnum;
@@ -4665,12 +4690,13 @@ void HWR_AddTransparentFloor(lumpnum_t lumpnum, extrasubsector_t *xsub,
planeinfo[numplanes].fogplane = fogplane;
planeinfo[numplanes].planecolormap = planecolormap;
planeinfo[numplanes].drawcount = drawcount++;
+
numplanes++;
}
// Adding this for now until I can create extrasubsector info for polyobjects
// When that happens it'll just be done through HWR_AddTransparentFloor and HWR_RenderPlane
-void HWR_AddTransparentPolyobjectFloor(lumpnum_t lumpnum, polyobj_t *polysector,
+void HWR_AddTransparentPolyobjectFloor(lumpnum_t lumpnum, polyobj_t *polysector, boolean isceiling,
fixed_t fixedheight, INT32 lightlevel, INT32 alpha, sector_t *FOFSector, FBITFIELD blend, extracolormap_t *planecolormap)
{
static size_t allocedpolyplanes = 0;
@@ -4685,6 +4711,7 @@ void HWR_AddTransparentPolyobjectFloor(lumpnum_t lumpnum, polyobj_t *polysector,
Z_Realloc(polyplaneinfo, allocedpolyplanes * sizeof (*polyplaneinfo), PU_LEVEL, &polyplaneinfo);
}
+ polyplaneinfo[numpolyplanes].isceiling = isceiling;
polyplaneinfo[numpolyplanes].fixedheight = fixedheight;
polyplaneinfo[numpolyplanes].lightlevel = lightlevel;
polyplaneinfo[numpolyplanes].lumpnum = lumpnum;
@@ -4850,7 +4877,7 @@ static void HWR_CreateDrawNodes(void)
if (!(sortnode[sortindex[i]].plane->blend & PF_NoTexture))
HWR_GetFlat(sortnode[sortindex[i]].plane->lumpnum);
- HWR_RenderPlane(NULL, sortnode[sortindex[i]].plane->xsub, sortnode[sortindex[i]].plane->fixedheight, sortnode[sortindex[i]].plane->blend, sortnode[sortindex[i]].plane->lightlevel,
+ HWR_RenderPlane(NULL, sortnode[sortindex[i]].plane->xsub, sortnode[sortindex[i]].plane->isceiling, sortnode[sortindex[i]].plane->fixedheight, sortnode[sortindex[i]].plane->blend, sortnode[sortindex[i]].plane->lightlevel,
sortnode[sortindex[i]].plane->lumpnum, sortnode[sortindex[i]].plane->FOFSector, sortnode[sortindex[i]].plane->alpha, sortnode[sortindex[i]].plane->fogplane, sortnode[sortindex[i]].plane->planecolormap);
}
else if (sortnode[sortindex[i]].polyplane)
@@ -4860,7 +4887,7 @@ static void HWR_CreateDrawNodes(void)
if (!(sortnode[sortindex[i]].polyplane->blend & PF_NoTexture))
HWR_GetFlat(sortnode[sortindex[i]].polyplane->lumpnum);
- HWR_RenderPolyObjectPlane(sortnode[sortindex[i]].polyplane->polysector, sortnode[sortindex[i]].polyplane->fixedheight, sortnode[sortindex[i]].polyplane->blend, sortnode[sortindex[i]].polyplane->lightlevel,
+ HWR_RenderPolyObjectPlane(sortnode[sortindex[i]].polyplane->polysector, sortnode[sortindex[i]].polyplane->isceiling, sortnode[sortindex[i]].polyplane->fixedheight, sortnode[sortindex[i]].polyplane->blend, sortnode[sortindex[i]].polyplane->lightlevel,
sortnode[sortindex[i]].polyplane->lumpnum, sortnode[sortindex[i]].polyplane->FOFSector, sortnode[sortindex[i]].polyplane->alpha, sortnode[sortindex[i]].polyplane->planecolormap);
}
else if (sortnode[sortindex[i]].wall)
@@ -5287,6 +5314,11 @@ static void HWR_ProjectPrecipitationSprite(precipmobj_t *thing)
//
vis = HWR_NewVisSprite();
vis->x1 = x1;
+#if 0
+ vis->x2 = x2;
+#else
+ (void)x2;
+#endif
vis->x2 = tx;
vis->tz = tz;
vis->dispoffset = 0; // Monster Iestyn: 23/11/15: HARDWARE SUPPORT AT LAST
@@ -5299,7 +5331,6 @@ static void HWR_ProjectPrecipitationSprite(precipmobj_t *thing)
// set top/bottom coords
vis->ty = FIXED_TO_FLOAT(thing->z + spritecachedinfo[lumpoff].topoffset) - gr_viewz;
- vis->sectorlight = 0xff;
vis->precip = true;
}
#endif
@@ -6157,7 +6188,7 @@ static void HWR_Render3DWater(void)
for (i = 0; i < numfloors; i++)
{
HWR_GetFlat(planeinfo[i].lumpnum);
- HWR_RenderPlane(NULL, planeinfo[i].xsub, planeinfo[i].fixedheight, PF_Translucent, planeinfo[i].lightlevel, planeinfo[i].lumpnum,
+ HWR_RenderPlane(NULL, planeinfo[i].xsub, planeinfo[i].isceiling, planeinfo[i].fixedheight, PF_Translucent, planeinfo[i].lightlevel, planeinfo[i].lumpnum,
planeinfo[i].FOFSector, planeinfo[i].alpha, planeinfo[i].fogplane, planeinfo[i].planecolormap);
}
numfloors = 0;
diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c
index 8e48ec11..4ec2e346 100644
--- a/src/hardware/hw_md2.c
+++ b/src/hardware/hw_md2.c
@@ -308,6 +308,23 @@ static md2_model_t *md2_readModel(const char *filename)
model->header.numSkins = 1;
+#define MD2LIMITCHECK(field, max, msgname) \
+ if (field > max) \
+ { \
+ CONS_Alert(CONS_ERROR, "md2_readModel: %s has too many " msgname " (# found: %d, maximum: %d)\n", filename, field, max); \
+ md2_freeModel (model); \
+ return 0; \
+ }
+
+ // Uncomment if these are actually needed
+// MD2LIMITCHECK(model->header.numSkins, MD2_MAX_SKINS, "skins")
+// MD2LIMITCHECK(model->header.numTexCoords, MD2_MAX_TEXCOORDS, "texture coordinates")
+ MD2LIMITCHECK(model->header.numTriangles, MD2_MAX_TRIANGLES, "triangles")
+ MD2LIMITCHECK(model->header.numFrames, MD2_MAX_FRAMES, "frames")
+ MD2LIMITCHECK(model->header.numVertices, MD2_MAX_VERTICES, "vertices")
+
+#undef MD2LIMITCHECK
+
// read skins
fseek(file, model->header.offsetSkins, SEEK_SET);
if (model->header.numSkins > 0)
@@ -319,8 +336,6 @@ static md2_model_t *md2_readModel(const char *filename)
md2_freeModel (model);
return 0;
}
-
- ;
}
// read texture coordinates
@@ -334,8 +349,6 @@ static md2_model_t *md2_readModel(const char *filename)
md2_freeModel (model);
return 0;
}
-
-
}
// read triangles
@@ -769,6 +782,7 @@ void HWR_InitMD2(void)
md2_playermodels[s].grpatch = NULL;
md2_playermodels[s].skin = -1;
md2_playermodels[s].notfound = true;
+ md2_playermodels[s].error = false;
}
for (i = 0; i < NUMSPRITES; i++)
{
@@ -777,6 +791,7 @@ void HWR_InitMD2(void)
md2_models[i].grpatch = NULL;
md2_models[i].skin = -1;
md2_models[i].notfound = true;
+ md2_models[i].error = false;
}
// read the md2.dat file
@@ -1269,6 +1284,8 @@ void HWR_DrawMD2(gr_vissprite_t *spr)
else
md2 = &md2_models[spr->mobj->sprite];
+ if (md2->error)
+ return; // we already failed loading this before :(
if (!md2->model)
{
//CONS_Debug(DBG_RENDER, "Loading MD2... (%s)", sprnames[spr->mobj->sprite]);
@@ -1282,6 +1299,7 @@ void HWR_DrawMD2(gr_vissprite_t *spr)
else
{
//CONS_Debug(DBG_RENDER, " FAILED\n");
+ md2->error = true; // prevent endless fail
return;
}
}
diff --git a/src/hardware/hw_md2.h b/src/hardware/hw_md2.h
index 36078268..5a7e6d2b 100644
--- a/src/hardware/hw_md2.h
+++ b/src/hardware/hw_md2.h
@@ -123,6 +123,7 @@ typedef struct
void *blendgrpatch;
boolean notfound;
INT32 skin;
+ boolean error;
} md2_t;
extern md2_t md2_models[NUMSPRITES];
diff --git a/src/hardware/r_opengl/r_opengl.c b/src/hardware/r_opengl/r_opengl.c
index 1a81fe79..e6ff83e8 100644
--- a/src/hardware/r_opengl/r_opengl.c
+++ b/src/hardware/r_opengl/r_opengl.c
@@ -244,6 +244,7 @@ FUNCPRINTF void DBG_Printf(const char *lpFmt, ...)
#define pglMaterialfv glMaterialfv
/* Raster functions */
+#define pglPixelStorei glPixelStorei
#define pglReadPixels glReadPixels
/* Texture mapping */
@@ -262,15 +263,8 @@ FUNCPRINTF void DBG_Printf(const char *lpFmt, ...)
/* texture mapping */ //GL_EXT_copy_texture
#ifndef KOS_GL_COMPATIBILITY
#define pglCopyTexImage2D glCopyTexImage2D
+#endif
-/* GLU functions */
-#define pgluBuild2DMipmaps gluBuild2DMipmaps
-#endif
-#ifndef MINI_GL_COMPATIBILITY
-/* 1.3 functions for multitexturing */
-#define pglActiveTexture glActiveTexture
-#define pglMultiTexCoord2f glMultiTexCoord2f
-#endif
#else //!STATIC_OPENGL
/* 1.0 functions */
@@ -365,6 +359,8 @@ typedef void (APIENTRY * PFNglMaterialfv) (GLint face, GLenum pname, GLfloat *pa
static PFNglMaterialfv pglMaterialfv;
/* Raster functions */
+typedef void (APIENTRY * PFNglPixelStorei) (GLenum pname, GLint param);
+static PFNglPixelStorei pglPixelStorei;
typedef void (APIENTRY * PFNglReadPixels) (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels);
static PFNglReadPixels pglReadPixels;
@@ -391,7 +387,7 @@ static PFNglBindTexture pglBindTexture;
/* texture mapping */ //GL_EXT_copy_texture
typedef void (APIENTRY * PFNglCopyTexImage2D) (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border);
static PFNglCopyTexImage2D pglCopyTexImage2D;
-
+#endif
/* GLU functions */
typedef GLint (APIENTRY * PFNgluBuild2DMipmaps) (GLenum target, GLint internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *data);
static PFNgluBuild2DMipmaps pgluBuild2DMipmaps;
@@ -403,7 +399,6 @@ static PFNglActiveTexture pglActiveTexture;
typedef void (APIENTRY *PFNglMultiTexCoord2f) (GLenum, GLfloat, GLfloat);
static PFNglMultiTexCoord2f pglMultiTexCoord2f;
#endif
-#endif
#ifndef MINI_GL_COMPATIBILITY
/* 1.2 Parms */
@@ -494,6 +489,7 @@ boolean SetupGLfunc(void)
GETOPENGLFUNC(pglLightModelfv , glLightModelfv)
GETOPENGLFUNC(pglMaterialfv , glMaterialfv)
+ GETOPENGLFUNC(pglPixelStorei , glPixelStorei)
GETOPENGLFUNC(pglReadPixels , glReadPixels)
GETOPENGLFUNC(pglTexEnvi , glTexEnvi)
@@ -519,35 +515,23 @@ boolean SetupGLfunc(void)
// This has to be done after the context is created so the version number can be obtained
boolean SetupGLFunc13(void)
{
+#ifdef MINI_GL_COMPATIBILITY
+ return false;
+#else
const GLubyte *version = pglGetString(GL_VERSION);
int glmajor, glminor;
gl13 = false;
-#ifdef MINI_GL_COMPATIBILITY
- return false;
-#else
-#ifdef STATIC_OPENGL
- gl13 = true;
-#else
-
// Parse the GL version
if (version != NULL)
{
if (sscanf((const char*)version, "%d.%d", &glmajor, &glminor) == 2)
{
// Look, we gotta prepare for the inevitable arrival of GL 2.0 code...
- switch (glmajor)
- {
- case 1:
- if (glminor == 3) gl13 = true;
- break;
- case 2:
- case 3:
- case 4:
- gl13 = true;
- default:
- break;
- }
+ if (glmajor == 1 && glminor >= 3)
+ gl13 = true;
+ else if (glmajor > 1)
+ gl13 = true;
}
}
@@ -568,9 +552,6 @@ boolean SetupGLFunc13(void)
}
else
DBG_Printf("GL_ARB_multitexture support: disabled\n");
-#undef GETOPENGLFUNC
-
-#endif
return true;
#endif
}
@@ -897,7 +878,9 @@ EXPORT void HWRAPI(ReadRect) (INT32 x, INT32 y, INT32 width, INT32 height,
GLubyte*top = (GLvoid*)dst_data, *bottom = top + dst_stride * (height - 1);
GLubyte *row = malloc(dst_stride);
if (!row) return;
+ pglPixelStorei(GL_PACK_ALIGNMENT, 1);
pglReadPixels(x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, dst_data);
+ pglPixelStorei(GL_UNPACK_ALIGNMENT, 1);
for(i = 0; i < height/2; i++)
{
memcpy(row, top, dst_stride);
@@ -913,7 +896,9 @@ EXPORT void HWRAPI(ReadRect) (INT32 x, INT32 y, INT32 width, INT32 height,
INT32 j;
GLubyte *image = malloc(width*height*3*sizeof (*image));
if (!image) return;
+ pglPixelStorei(GL_PACK_ALIGNMENT, 1);
pglReadPixels(x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, image);
+ pglPixelStorei(GL_UNPACK_ALIGNMENT, 1);
for (i = height-1; i >= 0; i--)
{
for (j = 0; j < width; j++)
@@ -1815,13 +1800,11 @@ EXPORT void HWRAPI(SetSpecialState) (hwdspecialstate_t IdState, INT32 Value)
min_filter = GL_NEAREST;
#endif
}
-#ifndef STATIC_OPENGL
if (!pgluBuild2DMipmaps)
{
MipMap = GL_FALSE;
min_filter = GL_LINEAR;
}
-#endif
Flush(); //??? if we want to change filter mode by texture, remove this
break;
@@ -1836,10 +1819,7 @@ EXPORT void HWRAPI(SetSpecialState) (hwdspecialstate_t IdState, INT32 Value)
}
}
-// -----------------+
-// HWRAPI DrawMD2 : Draw an MD2 model with glcommands
-// -----------------+
-EXPORT void HWRAPI(DrawMD2i) (INT32 *gl_cmd_buffer, md2_frame_t *frame, UINT32 duration, UINT32 tics, md2_frame_t *nextframe, FTransform *pos, float scale, UINT8 flipped, UINT8 *color)
+static void DrawMD2Ex(INT32 *gl_cmd_buffer, md2_frame_t *frame, UINT32 duration, UINT32 tics, md2_frame_t *nextframe, FTransform *pos, float scale, UINT8 flipped, UINT8 *color)
{
INT32 val, count, pindex;
GLfloat s, t;
@@ -1931,7 +1911,7 @@ EXPORT void HWRAPI(DrawMD2i) (INT32 *gl_cmd_buffer, md2_frame_t *frame, UINT32 d
//pglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // alpha = level of transparency
// Remove depth mask when the model is transparent so it doesn't cut thorugh sprites // SRB2CBTODO: For all stuff too?!
- if (color[3] < 255)
+ if (color && color[3] < 255)
{
pglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // alpha = level of transparency
pglDepthMask(GL_FALSE);
@@ -2007,11 +1987,20 @@ EXPORT void HWRAPI(DrawMD2i) (INT32 *gl_cmd_buffer, md2_frame_t *frame, UINT32 d
pglDisable(GL_CULL_FACE);
}
+// -----------------+
+// HWRAPI DrawMD2 : Draw an MD2 model with glcommands
+// -----------------+
+EXPORT void HWRAPI(DrawMD2i) (INT32 *gl_cmd_buffer, md2_frame_t *frame, UINT32 duration, UINT32 tics, md2_frame_t *nextframe, FTransform *pos, float scale, UINT8 flipped, UINT8 *color)
+{
+ DrawMD2Ex(gl_cmd_buffer, frame, duration, tics, nextframe, pos, scale, flipped, color);
+}
+
EXPORT void HWRAPI(DrawMD2) (INT32 *gl_cmd_buffer, md2_frame_t *frame, FTransform *pos, float scale)
{
- DrawMD2i(gl_cmd_buffer, frame, 0, 0, NULL, pos, scale, false, NULL);
+ DrawMD2Ex(gl_cmd_buffer, frame, 0, 0, NULL, pos, scale, false, NULL);
}
+
// -----------------+
// SetTransform :
// -----------------+
diff --git a/src/hu_stuff.c b/src/hu_stuff.c
index ec747305..646bdcba 100644
--- a/src/hu_stuff.c
+++ b/src/hu_stuff.c
@@ -470,7 +470,7 @@ static void Got_Saycmd(UINT8 **p, INT32 playernum)
boolean action = false;
char *ptr;
- CONS_Debug(DBG_NETPLAY,"Recieved SAY cmd from Player %d (%s)\n", playernum+1, player_names[playernum]);
+ CONS_Debug(DBG_NETPLAY,"Received SAY cmd from Player %d (%s)\n", playernum+1, player_names[playernum]);
target = READSINT8(*p);
flags = READUINT8(*p);
@@ -757,15 +757,8 @@ void HU_clearChatChars(void)
//
boolean HU_Responder(event_t *ev)
{
- static boolean shiftdown = false;
UINT8 c;
- if (ev->data1 == KEY_LSHIFT || ev->data1 == KEY_RSHIFT)
- {
- shiftdown = (ev->type == ev_keydown);
- return chat_on;
- }
-
if (ev->type != ev_keydown)
return false;
@@ -797,6 +790,14 @@ boolean HU_Responder(event_t *ev)
}
else // if chat_on
{
+ // Ignore modifier keys
+ // Note that we do this here so users can still set
+ // their chat keys to one of these, if they so desire.
+ if (ev->data1 == KEY_LSHIFT || ev->data1 == KEY_RSHIFT
+ || ev->data1 == KEY_LCTRL || ev->data1 == KEY_RCTRL
+ || ev->data1 == KEY_LALT || ev->data1 == KEY_RALT)
+ return true;
+
c = (UINT8)ev->data1;
// use console translations
@@ -1101,7 +1102,19 @@ void HU_Drawer(void)
// draw desynch text
if (hu_resynching)
- V_DrawCenteredString(BASEVIDWIDTH/2, 180, V_YELLOWMAP, "Resynching...");
+ {
+ static UINT32 resynch_ticker = 0;
+ char resynch_text[14];
+ UINT32 i;
+
+ // Animate the dots
+ resynch_ticker++;
+ strcpy(resynch_text, "Resynching");
+ for (i = 0; i < (resynch_ticker / 16) % 4; i++)
+ strcat(resynch_text, ".");
+
+ V_DrawCenteredString(BASEVIDWIDTH/2, 180, V_YELLOWMAP | V_ALLOWLOWERCASE, resynch_text);
+ }
}
//======================================================================
diff --git a/src/hu_stuff.h b/src/hu_stuff.h
index f0dd4009..7b22f33f 100644
--- a/src/hu_stuff.h
+++ b/src/hu_stuff.h
@@ -87,7 +87,7 @@ void HU_Init(void);
void HU_LoadGraphics(void);
// reset heads up when consoleplayer respawns.
-void HU_Start(void);
+FUNCMATH void HU_Start(void);
boolean HU_Responder(event_t *ev);
diff --git a/src/i_net.h b/src/i_net.h
index e378f572..2bfa5eac 100644
--- a/src/i_net.h
+++ b/src/i_net.h
@@ -85,7 +85,7 @@ extern doomcom_t *doomcom;
/** \brief return packet in doomcom struct
*/
-extern void (*I_NetGet)(void);
+extern boolean (*I_NetGet)(void);
/** \brief ask to driver if there is data waiting
*/
diff --git a/src/i_system.h b/src/i_system.h
index c161851e..d61f2d16 100644
--- a/src/i_system.h
+++ b/src/i_system.h
@@ -296,6 +296,14 @@ char *I_GetEnv(const char *name);
INT32 I_PutEnv(char *variable);
+/** \brief Put data in system clipboard
+*/
+INT32 I_ClipboardCopy(const char *data, size_t size);
+
+/** \brief Retrieve data from system clipboard
+*/
+const char *I_ClipboardPaste(void);
+
void I_RegisterSysCommands(void);
#endif
diff --git a/src/i_tcp.c b/src/i_tcp.c
index eca218c8..c65a536a 100644
--- a/src/i_tcp.c
+++ b/src/i_tcp.c
@@ -56,7 +56,9 @@
//#define NONET
#endif
-#ifndef NONET
+#ifdef NONET
+#undef HAVE_MINIUPNPC
+#else
#ifdef USE_WINSOCK1
#include
#elif !defined (SCOUW2) && !defined (SCOUW7) && !defined (__OS2__)
@@ -177,6 +179,7 @@ static UINT8 UPNP_support = TRUE;
#include "i_system.h"
#include "i_net.h"
#include "d_net.h"
+#include "d_netfil.h"
#include "i_tcp.h"
#include "m_argv.h"
@@ -480,21 +483,12 @@ static boolean SOCK_cmpaddr(mysockaddr_t *a, mysockaddr_t *b, UINT8 mask)
return false;
}
-static SINT8 getfreenode(void)
-{
- SINT8 j;
-
- for (j = 0; j < MAXNETNODES; j++)
- if (!nodeconnected[j])
- {
- nodeconnected[j] = true;
- return j;
- }
- return -1;
-}
-
// This is a hack. For some reason, nodes aren't being freed properly.
// This goes through and cleans up what nodes were supposed to be freed.
+/** \warning This function causes the file downloading to stop if someone joins.
+ * How? Because it removes nodes that are connected but not in game,
+ * which is exactly what clients downloading a file are.
+ */
static void cleanupnodes(void)
{
SINT8 j;
@@ -504,13 +498,81 @@ static void cleanupnodes(void)
// Why can't I start at zero?
for (j = 1; j < MAXNETNODES; j++)
+ //if (!(nodeingame[j] || SV_SendingFile(j)))
if (!nodeingame[j])
nodeconnected[j] = false;
}
+
+static SINT8 getfreenode(void)
+{
+ SINT8 j;
+
+ cleanupnodes();
+
+ for (j = 0; j < MAXNETNODES; j++)
+ if (!nodeconnected[j])
+ {
+ nodeconnected[j] = true;
+ return j;
+ }
+
+ /** \warning No free node? Just in case a node might not have been freed properly,
+ * look if there are connected nodes that aren't in game, and forget them.
+ * It's dirty, and might result in a poor guy having to restart
+ * downloading a needed wad, but it's better than not letting anyone join...
+ */
+ /*I_Error("No more free nodes!!1!11!11!!1111\n");
+ for (j = 1; j < MAXNETNODES; j++)
+ if (!nodeingame[j])
+ return j;*/
+
+ return -1;
+}
+
+#ifdef _DEBUG
+void Command_Numnodes(void)
+{
+ INT32 connected = 0;
+ INT32 ingame = 0;
+ INT32 i;
+
+ for (i = 1; i < MAXNETNODES; i++)
+ {
+ if (!(nodeconnected[i] || nodeingame[i]))
+ continue;
+
+ if (nodeconnected[i])
+ connected++;
+ if (nodeingame[i])
+ ingame++;
+
+ CONS_Printf("%2d - ", i);
+ if (nodetoplayer[i] != -1)
+ CONS_Printf("player %.2d", nodetoplayer[i]);
+ else
+ CONS_Printf(" ");
+ if (nodeconnected[i])
+ CONS_Printf(" - connected");
+ else
+ CONS_Printf(" - ");
+ if (nodeingame[i])
+ CONS_Printf(" - ingame");
+ else
+ CONS_Printf(" - ");
+ CONS_Printf(" - %s\n", I_GetNodeAddress(i));
+ }
+
+ CONS_Printf("\n"
+ "Connected: %d\n"
+ "Ingame: %d\n",
+ connected, ingame);
+}
+#endif
#endif
#ifndef NONET
-static void SOCK_Get(void)
+// Returns true if a packet was received from a new node, false in all other cases
+static boolean SOCK_Get(void)
{
size_t i, n;
int j;
@@ -533,13 +595,12 @@ static void SOCK_Get(void)
doomcom->remotenode = (INT16)j; // good packet from a game player
doomcom->datalength = (INT16)c;
nodesocket[j] = mysockets[n];
- return;
+ return false;
}
}
// not found
// find a free slot
- cleanupnodes();
j = getfreenode();
if (j > 0)
{
@@ -562,14 +623,15 @@ static void SOCK_Get(void)
}
if (i == numbans)
SOCK_bannednode[j] = false;
- return;
+ return true;
}
else
DEBFILE("New node detected: No more free slots\n");
-
}
}
+
doomcom->remotenode = -1; // no packet
+ return false;
}
#endif
@@ -1254,7 +1316,6 @@ static SINT8 SOCK_NetMakeNodewPort(const char *address, const char *port)
gaie = I_getaddrinfo(address, port, &hints, &ai);
if (gaie == 0)
{
- cleanupnodes();
newnode = getfreenode();
}
if (newnode == -1)
diff --git a/src/lua_baselib.c b/src/lua_baselib.c
index 7678c7c4..e8e8fd02 100644
--- a/src/lua_baselib.c
+++ b/src/lua_baselib.c
@@ -437,6 +437,16 @@ static int lib_pMobjFlip(lua_State *L)
return 1;
}
+static int lib_pGetMobjGravity(lua_State *L)
+{
+ mobj_t *mobj = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
+ //HUDSAFE
+ if (!mobj)
+ return LUA_ErrInvalid(L, "mobj_t");
+ lua_pushfixed(L, P_GetMobjGravity(mobj));
+ return 1;
+}
+
static int lib_pWeaponOrPanel(lua_State *L)
{
mobjtype_t type = luaL_checkinteger(L, 1);
@@ -2008,6 +2018,7 @@ static luaL_Reg lib[] = {
{"P_SPMAngle",lib_pSPMAngle},
{"P_SpawnPlayerMissile",lib_pSpawnPlayerMissile},
{"P_MobjFlip",lib_pMobjFlip},
+ {"P_GetMobjGravity",lib_pGetMobjGravity},
{"P_WeaponOrPanel",lib_pWeaponOrPanel},
{"P_FlashPal",lib_pFlashPal},
{"P_GetClosestAxis",lib_pGetClosestAxis},
diff --git a/src/lua_hook.h b/src/lua_hook.h
index 804d99e1..53e0a7d8 100644
--- a/src/lua_hook.h
+++ b/src/lua_hook.h
@@ -60,7 +60,7 @@ UINT8 LUAh_MobjCollideHook(mobj_t *thing1, mobj_t *thing2, enum hook which);
#define LUAh_MobjMoveCollide(thing1, thing2) LUAh_MobjCollideHook(thing1, thing2, hook_MobjMoveCollide) // Hook for PIT_CheckThing by (tmthing) mobj type
boolean LUAh_TouchSpecial(mobj_t *special, mobj_t *toucher); // Hook for P_TouchSpecialThing by mobj type
#define LUAh_MobjFuse(mo) LUAh_MobjHook(mo, hook_MobjFuse) // Hook for mobj->fuse == 0 by mobj type
-#define LUAh_MobjThinker(mo) LUAh_MobjHook(mo, hook_MobjThinker) // Hook for P_MobjThinker or P_SceneryThinker by mobj type
+boolean LUAh_MobjThinker(mobj_t *mo); // Hook for P_MobjThinker or P_SceneryThinker by mobj type
#define LUAh_BossThinker(mo) LUAh_MobjHook(mo, hook_BossThinker) // Hook for P_GenericBossThinker by mobj type
UINT8 LUAh_ShouldDamage(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 damage); // Hook for P_DamageMobj by mobj type (Should mobj take damage?)
boolean LUAh_MobjDamage(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 damage); // Hook for P_DamageMobj by mobj type (Mobj actually takes damage!)
diff --git a/src/lua_hooklib.c b/src/lua_hooklib.c
index 1b965257..a24473ba 100644
--- a/src/lua_hooklib.c
+++ b/src/lua_hooklib.c
@@ -74,12 +74,30 @@ typedef struct hook_s* hook_p;
#define FMT_HOOKID "hook_%d"
+// For each mobj type, a linked list to its thinker and collision hooks.
+// That way, we don't have to iterate through all the hooks.
+// We could do that with all other mobj hooks, but it would probably just be
+// a waste of memory since they are only called occasionally. Probably...
+static hook_p mobjthinkerhooks[NUMMOBJTYPES];
+static hook_p mobjcollidehooks[NUMMOBJTYPES];
+
+// For each mobj type, a linked list for other mobj hooks
+static hook_p mobjhooks[NUMMOBJTYPES];
+
+// A linked list for player hooks
+static hook_p playerhooks;
+
+// A linked list for linedef executor hooks
+static hook_p linedefexecutorhooks;
+
+// For other hooks, a unique linked list
hook_p roothook;
// Takes hook, function, and additional arguments (mobj type to act on, etc.)
static int lib_addHook(lua_State *L)
{
static struct hook_s hook = {NULL, 0, 0, {0}, false};
+ static UINT32 nextid;
hook_p hookp, *lastp;
hook.type = luaL_checkoption(L, 1, NULL, hookNames);
@@ -109,6 +127,7 @@ static int lib_addHook(lua_State *L)
hook.s.mt = MT_NULL;
if (lua_isnumber(L, 2))
hook.s.mt = lua_tonumber(L, 2);
+ luaL_argcheck(L, hook.s.mt < NUMMOBJTYPES, 2, "invalid mobjtype_t");
break;
case hook_BotAI:
hook.s.skinname = NULL;
@@ -141,18 +160,49 @@ static int lib_addHook(lua_State *L)
hooksAvailable[hook.type/8] |= 1<<(hook.type%8);
- // iterate the hook metadata structs
// set hook.id to the highest id + 1
- // set lastp to the last hook struct's "next" pointer.
- lastp = &roothook;
- hook.id = 0;
- for (hookp = roothook; hookp; hookp = hookp->next)
+ hook.id = nextid++;
+
+ // Special cases for some hook types (see the comments above mobjthinkerhooks declaration)
+ switch(hook.type)
{
- if (hookp->id >= hook.id)
- hook.id = hookp->id+1;
- lastp = &hookp->next;
+ case hook_MobjThinker:
+ lastp = &mobjthinkerhooks[hook.s.mt];
+ break;
+ case hook_MobjCollide:
+ case hook_MobjMoveCollide:
+ lastp = &mobjcollidehooks[hook.s.mt];
+ break;
+ case hook_MobjSpawn:
+ case hook_TouchSpecial:
+ case hook_MobjFuse:
+ case hook_BossThinker:
+ case hook_ShouldDamage:
+ case hook_MobjDamage:
+ case hook_MobjDeath:
+ case hook_BossDeath:
+ case hook_MobjRemoved:
+ lastp = &mobjhooks[hook.s.mt];
+ break;
+ case hook_JumpSpecial:
+ case hook_AbilitySpecial:
+ case hook_SpinSpecial:
+ case hook_JumpSpinSpecial:
+ case hook_PlayerSpawn:
+ lastp = &playerhooks;
+ break;
+ case hook_LinedefExecute:
+ lastp = &linedefexecutorhooks;
+ break;
+ default:
+ lastp = &roothook;
+ break;
}
+ // iterate the hook metadata structs
+ // set lastp to the last hook struct's "next" pointer.
+ for (hookp = *lastp; hookp; hookp = hookp->next)
+ lastp = &hookp->next;
// allocate a permanent memory struct to stuff hook.
hookp = ZZ_Alloc(sizeof(struct hook_s));
memcpy(hookp, &hook, sizeof(struct hook_s));
@@ -183,9 +233,29 @@ boolean LUAh_MobjHook(mobj_t *mo, enum hook which)
lua_settop(gL, 0);
- for (hookp = roothook; hookp; hookp = hookp->next)
- if (hookp->type == which
- && (hookp->s.mt == MT_NULL || hookp->s.mt == mo->type))
+ // Look for all generic mobj hooks
+ for (hookp = mobjhooks[MT_NULL]; hookp; hookp = hookp->next)
+ if (hookp->type == which)
+ {
+ if (lua_gettop(gL) == 0)
+ LUA_PushUserdata(gL, mo, META_MOBJ);
+ lua_pushfstring(gL, FMT_HOOKID, hookp->id);
+ lua_gettable(gL, LUA_REGISTRYINDEX);
+ lua_pushvalue(gL, -2);
+ if (lua_pcall(gL, 1, 1, 0)) {
+ if (!hookp->error || cv_debug & DBG_LUA)
+ CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1));
+ lua_pop(gL, 1);
+ hookp->error = true;
+ continue;
+ }
+ if (lua_toboolean(gL, -1))
+ hooked = true;
+ lua_pop(gL, 1);
+ }
+
+ for (hookp = mobjhooks[mo->type]; hookp; hookp = hookp->next)
+ if (hookp->type == which)
{
if (lua_gettop(gL) == 0)
LUA_PushUserdata(gL, mo, META_MOBJ);
@@ -217,7 +287,7 @@ boolean LUAh_PlayerHook(player_t *plr, enum hook which)
lua_settop(gL, 0);
- for (hookp = roothook; hookp; hookp = hookp->next)
+ for (hookp = playerhooks; hookp; hookp = hookp->next)
if (hookp->type == which)
{
if (lua_gettop(gL) == 0)
@@ -338,9 +408,38 @@ UINT8 LUAh_MobjCollideHook(mobj_t *thing1, mobj_t *thing2, enum hook which)
lua_settop(gL, 0);
- for (hookp = roothook; hookp; hookp = hookp->next)
- if (hookp->type == which
- && (hookp->s.mt == MT_NULL || hookp->s.mt == thing1->type))
+ // Look for all generic mobj collision hooks
+ for (hookp = mobjcollidehooks[MT_NULL]; hookp; hookp = hookp->next)
+ if (hookp->type == which)
+ {
+ if (lua_gettop(gL) == 0)
+ {
+ LUA_PushUserdata(gL, thing1, META_MOBJ);
+ LUA_PushUserdata(gL, thing2, META_MOBJ);
+ }
+ lua_pushfstring(gL, FMT_HOOKID, hookp->id);
+ lua_gettable(gL, LUA_REGISTRYINDEX);
+ lua_pushvalue(gL, -3);
+ lua_pushvalue(gL, -3);
+ if (lua_pcall(gL, 2, 1, 0)) {
+ if (!hookp->error || cv_debug & DBG_LUA)
+ CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1));
+ lua_pop(gL, 1);
+ hookp->error = true;
+ continue;
+ }
+ if (!lua_isnil(gL, -1))
+ { // if nil, leave shouldCollide = 0.
+ if (lua_toboolean(gL, -1))
+ shouldCollide = 1; // Force yes
+ else
+ shouldCollide = 2; // Force no
+ }
+ lua_pop(gL, 1);
+ }
+
+ for (hookp = mobjcollidehooks[thing1->type]; hookp; hookp = hookp->next)
+ if (hookp->type == which)
{
if (lua_gettop(gL) == 0)
{
@@ -372,6 +471,59 @@ UINT8 LUAh_MobjCollideHook(mobj_t *thing1, mobj_t *thing2, enum hook which)
return shouldCollide;
}
+// Hook for mobj thinkers
+boolean LUAh_MobjThinker(mobj_t *mo)
+{
+ hook_p hookp;
+ boolean hooked = false;
+ if (!gL || !(hooksAvailable[hook_MobjThinker/8] & (1<<(hook_MobjThinker%8))))
+ return false;
+
+ lua_settop(gL, 0);
+
+ // Look for all generic mobj thinker hooks
+ for (hookp = mobjthinkerhooks[MT_NULL]; hookp; hookp = hookp->next)
+ {
+ if (lua_gettop(gL) == 0)
+ LUA_PushUserdata(gL, mo, META_MOBJ);
+ lua_pushfstring(gL, FMT_HOOKID, hookp->id);
+ lua_gettable(gL, LUA_REGISTRYINDEX);
+ lua_pushvalue(gL, -2);
+ if (lua_pcall(gL, 1, 1, 0)) {
+ if (!hookp->error || cv_debug & DBG_LUA)
+ CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1));
+ lua_pop(gL, 1);
+ hookp->error = true;
+ continue;
+ }
+ if (lua_toboolean(gL, -1))
+ hooked = true;
+ lua_pop(gL, 1);
+ }
+
+ for (hookp = mobjthinkerhooks[mo->type]; hookp; hookp = hookp->next)
+ {
+ if (lua_gettop(gL) == 0)
+ LUA_PushUserdata(gL, mo, META_MOBJ);
+ lua_pushfstring(gL, FMT_HOOKID, hookp->id);
+ lua_gettable(gL, LUA_REGISTRYINDEX);
+ lua_pushvalue(gL, -2);
+ if (lua_pcall(gL, 1, 1, 0)) {
+ if (!hookp->error || cv_debug & DBG_LUA)
+ CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1));
+ lua_pop(gL, 1);
+ hookp->error = true;
+ continue;
+ }
+ if (lua_toboolean(gL, -1))
+ hooked = true;
+ lua_pop(gL, 1);
+ }
+
+ lua_settop(gL, 0);
+ return hooked;
+}
+
// Hook for P_TouchSpecialThing by mobj type
boolean LUAh_TouchSpecial(mobj_t *special, mobj_t *toucher)
{
@@ -382,9 +534,33 @@ boolean LUAh_TouchSpecial(mobj_t *special, mobj_t *toucher)
lua_settop(gL, 0);
- for (hookp = roothook; hookp; hookp = hookp->next)
- if (hookp->type == hook_TouchSpecial
- && (hookp->s.mt == MT_NULL || hookp->s.mt == special->type))
+ // Look for all generic touch special hooks
+ for (hookp = mobjhooks[MT_NULL]; hookp; hookp = hookp->next)
+ if (hookp->type == hook_TouchSpecial)
+ {
+ if (lua_gettop(gL) == 0)
+ {
+ LUA_PushUserdata(gL, special, META_MOBJ);
+ LUA_PushUserdata(gL, toucher, META_MOBJ);
+ }
+ lua_pushfstring(gL, FMT_HOOKID, hookp->id);
+ lua_gettable(gL, LUA_REGISTRYINDEX);
+ lua_pushvalue(gL, -3);
+ lua_pushvalue(gL, -3);
+ if (lua_pcall(gL, 2, 1, 0)) {
+ if (!hookp->error || cv_debug & DBG_LUA)
+ CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1));
+ lua_pop(gL, 1);
+ hookp->error = true;
+ continue;
+ }
+ if (lua_toboolean(gL, -1))
+ hooked = true;
+ lua_pop(gL, 1);
+ }
+
+ for (hookp = mobjhooks[special->type]; hookp; hookp = hookp->next)
+ if (hookp->type == hook_TouchSpecial)
{
if (lua_gettop(gL) == 0)
{
@@ -421,9 +597,42 @@ UINT8 LUAh_ShouldDamage(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32
lua_settop(gL, 0);
- for (hookp = roothook; hookp; hookp = hookp->next)
- if (hookp->type == hook_ShouldDamage
- && (hookp->s.mt == MT_NULL || hookp->s.mt == target->type))
+ // Look for all generic should damage hooks
+ for (hookp = mobjhooks[MT_NULL]; hookp; hookp = hookp->next)
+ if (hookp->type == hook_ShouldDamage)
+ {
+ if (lua_gettop(gL) == 0)
+ {
+ LUA_PushUserdata(gL, target, META_MOBJ);
+ LUA_PushUserdata(gL, inflictor, META_MOBJ);
+ LUA_PushUserdata(gL, source, META_MOBJ);
+ lua_pushinteger(gL, damage);
+ }
+ lua_pushfstring(gL, FMT_HOOKID, hookp->id);
+ lua_gettable(gL, LUA_REGISTRYINDEX);
+ lua_pushvalue(gL, -5);
+ lua_pushvalue(gL, -5);
+ lua_pushvalue(gL, -5);
+ lua_pushvalue(gL, -5);
+ if (lua_pcall(gL, 4, 1, 0)) {
+ if (!hookp->error || cv_debug & DBG_LUA)
+ CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1));
+ lua_pop(gL, 1);
+ hookp->error = true;
+ continue;
+ }
+ if (!lua_isnil(gL, -1))
+ {
+ if (lua_toboolean(gL, -1))
+ shouldDamage = 1; // Force yes
+ else
+ shouldDamage = 2; // Force no
+ }
+ lua_pop(gL, 1);
+ }
+
+ for (hookp = mobjhooks[target->type]; hookp; hookp = hookp->next)
+ if (hookp->type == hook_ShouldDamage)
{
if (lua_gettop(gL) == 0)
{
@@ -469,9 +678,37 @@ boolean LUAh_MobjDamage(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32
lua_settop(gL, 0);
- for (hookp = roothook; hookp; hookp = hookp->next)
- if (hookp->type == hook_MobjDamage
- && (hookp->s.mt == MT_NULL || hookp->s.mt == target->type))
+ // Look for all generic mobj damage hooks
+ for (hookp = mobjhooks[MT_NULL]; hookp; hookp = hookp->next)
+ if (hookp->type == hook_MobjDamage)
+ {
+ if (lua_gettop(gL) == 0)
+ {
+ LUA_PushUserdata(gL, target, META_MOBJ);
+ LUA_PushUserdata(gL, inflictor, META_MOBJ);
+ LUA_PushUserdata(gL, source, META_MOBJ);
+ lua_pushinteger(gL, damage);
+ }
+ lua_pushfstring(gL, FMT_HOOKID, hookp->id);
+ lua_gettable(gL, LUA_REGISTRYINDEX);
+ lua_pushvalue(gL, -5);
+ lua_pushvalue(gL, -5);
+ lua_pushvalue(gL, -5);
+ lua_pushvalue(gL, -5);
+ if (lua_pcall(gL, 4, 1, 0)) {
+ if (!hookp->error || cv_debug & DBG_LUA)
+ CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1));
+ lua_pop(gL, 1);
+ hookp->error = true;
+ continue;
+ }
+ if (lua_toboolean(gL, -1))
+ hooked = true;
+ lua_pop(gL, 1);
+ }
+
+ for (hookp = mobjhooks[target->type]; hookp; hookp = hookp->next)
+ if (hookp->type == hook_MobjDamage)
{
if (lua_gettop(gL) == 0)
{
@@ -512,9 +749,35 @@ boolean LUAh_MobjDeath(mobj_t *target, mobj_t *inflictor, mobj_t *source)
lua_settop(gL, 0);
- for (hookp = roothook; hookp; hookp = hookp->next)
- if (hookp->type == hook_MobjDeath
- && (hookp->s.mt == MT_NULL || hookp->s.mt == target->type))
+ // Look for all generic mobj death hooks
+ for (hookp = mobjhooks[MT_NULL]; hookp; hookp = hookp->next)
+ if (hookp->type == hook_MobjDeath)
+ {
+ if (lua_gettop(gL) == 0)
+ {
+ LUA_PushUserdata(gL, target, META_MOBJ);
+ LUA_PushUserdata(gL, inflictor, META_MOBJ);
+ LUA_PushUserdata(gL, source, META_MOBJ);
+ }
+ lua_pushfstring(gL, FMT_HOOKID, hookp->id);
+ lua_gettable(gL, LUA_REGISTRYINDEX);
+ lua_pushvalue(gL, -4);
+ lua_pushvalue(gL, -4);
+ lua_pushvalue(gL, -4);
+ if (lua_pcall(gL, 3, 1, 0)) {
+ if (!hookp->error || cv_debug & DBG_LUA)
+ CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1));
+ lua_pop(gL, 1);
+ hookp->error = true;
+ continue;
+ }
+ if (lua_toboolean(gL, -1))
+ hooked = true;
+ lua_pop(gL, 1);
+ }
+
+ for (hookp = mobjhooks[target->type]; hookp; hookp = hookp->next)
+ if (hookp->type == hook_MobjDeath)
{
if (lua_gettop(gL) == 0)
{
@@ -652,9 +915,8 @@ boolean LUAh_LinedefExecute(line_t *line, mobj_t *mo, sector_t *sector)
lua_settop(gL, 0);
- for (hookp = roothook; hookp; hookp = hookp->next)
- if (hookp->type == hook_LinedefExecute
- && !strcmp(hookp->s.funcname, line->text))
+ for (hookp = linedefexecutorhooks; hookp; hookp = hookp->next)
+ if (!strcmp(hookp->s.funcname, line->text))
{
if (lua_gettop(gL) == 0)
{
diff --git a/src/lua_hud.h b/src/lua_hud.h
index 799ce2fb..ba0a1d89 100644
--- a/src/lua_hud.h
+++ b/src/lua_hud.h
@@ -18,6 +18,9 @@ enum hud {
hud_time,
hud_rings,
hud_lives,
+ // Match / CTF / Tag / Ringslinger
+ hud_weaponrings,
+ hud_powerstones,
// NiGHTS mode
hud_nightslink,
hud_nightsdrill,
diff --git a/src/lua_hudlib.c b/src/lua_hudlib.c
index 31549afa..60cbbe50 100644
--- a/src/lua_hudlib.c
+++ b/src/lua_hudlib.c
@@ -44,6 +44,9 @@ static const char *const hud_disable_options[] = {
"rings",
"lives",
+ "weaponrings",
+ "powerstones",
+
"nightslink",
"nightsdrill",
"nightsrings",
@@ -366,6 +369,8 @@ static int libd_drawScaled(lua_State *L)
x = luaL_checkinteger(L, 1);
y = luaL_checkinteger(L, 2);
scale = luaL_checkinteger(L, 3);
+ if (scale < 0)
+ return luaL_error(L, "negative scale");
patch = *((patch_t **)luaL_checkudata(L, 4, META_PATCH));
flags = luaL_optinteger(L, 5, 0);
if (!lua_isnoneornil(L, 6))
diff --git a/src/lua_maplib.c b/src/lua_maplib.c
index c512bf3c..208aebe3 100644
--- a/src/lua_maplib.c
+++ b/src/lua_maplib.c
@@ -348,22 +348,12 @@ static int sector_get(lua_State *L)
case sector_ceilingheight:
lua_pushfixed(L, sector->ceilingheight);
return 1;
- case sector_floorpic: { // floorpic
- levelflat_t *levelflat;
- INT16 i;
- for (i = 0, levelflat = levelflats; i != sector->floorpic; i++, levelflat++)
- ;
- lua_pushlstring(L, levelflat->name, 8);
+ case sector_floorpic: // floorpic
+ lua_pushlstring(L, levelflats[sector->floorpic].name, 8);
return 1;
- }
- case sector_ceilingpic: { // ceilingpic
- levelflat_t *levelflat;
- INT16 i;
- for (i = 0, levelflat = levelflats; i != sector->ceilingpic; i++, levelflat++)
- ;
- lua_pushlstring(L, levelflat->name, 8);
+ case sector_ceilingpic: // ceilingpic
+ lua_pushlstring(L, levelflats[sector->ceilingpic].name, 8);
return 1;
- }
case sector_lightlevel:
lua_pushinteger(L, sector->lightlevel);
return 1;
@@ -400,46 +390,6 @@ static int sector_get(lua_State *L)
return 0;
}
-// help function for P_LoadSectors, find a flat in the active wad files,
-// allocate an id for it, and set the levelflat (to speedup search)
-//
-static INT32 P_AddLevelFlatRuntime(const char *flatname)
-{
- size_t i;
- levelflat_t *levelflat = levelflats;
-
- //
- // first scan through the already found flats
- //
- for (i = 0; i < numlevelflats; i++, levelflat++)
- if (strnicmp(levelflat->name,flatname,8)==0)
- break;
-
- // that flat was already found in the level, return the id
- if (i == numlevelflats)
- {
- // allocate new flat memory
- levelflats = Z_Realloc(levelflats, (numlevelflats + 1) * sizeof(*levelflats), PU_LEVEL, NULL);
- levelflat = levelflats+i;
-
- // store the name
- strlcpy(levelflat->name, flatname, sizeof (levelflat->name));
- strupr(levelflat->name);
-
- // store the flat lump number
- levelflat->lumpnum = R_GetFlatNumForName(flatname);
-
-#ifndef ZDEBUG
- CONS_Debug(DBG_SETUP, "flat #%03d: %s\n", atoi(sizeu1(numlevelflats)), levelflat->name);
-#endif
-
- numlevelflats++;
- }
-
- // level flat id
- return (INT32)i;
-}
-
static int sector_set(lua_State *L)
{
sector_t *sector = *((sector_t **)luaL_checkudata(L, 1, META_SECTOR));
diff --git a/src/lzf.c b/src/lzf.c
index 33a1b2dc..272174f3 100644
--- a/src/lzf.c
+++ b/src/lzf.c
@@ -59,7 +59,11 @@
* Unconditionally aligning does not cost very much, so do it if unsure
*/
#ifndef STRICT_ALIGN
-# define STRICT_ALIGN !(defined(__i386) || defined (__amd64)) || defined (__clang__)
+#if !(defined(__i386) || defined (__amd64)) || defined (__clang__)
+#define STRICT_ALIGN 1
+#else
+#define STRICT_ALIGN 0
+#endif
#endif
/*
diff --git a/src/m_aatree.c b/src/m_aatree.c
new file mode 100644
index 00000000..6cb3a32c
--- /dev/null
+++ b/src/m_aatree.c
@@ -0,0 +1,167 @@
+// SONIC ROBO BLAST 2
+//-----------------------------------------------------------------------------
+// Copyright (C) 1993-1996 by id Software, Inc.
+// Copyright (C) 1998-2000 by DooM Legacy Team.
+// Copyright (C) 1999-2016 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 m_aatree.h
+/// \brief AA trees code
+
+#include "m_aatree.h"
+#include "z_zone.h"
+
+// A partial implementation of AA trees,
+// according to the algorithms given on Wikipedia.
+// http://en.wikipedia.org/wiki/AA_tree
+
+typedef struct aatree_node_s
+{
+ INT32 level;
+ INT32 key;
+ void* value;
+
+ struct aatree_node_s *left, *right;
+} aatree_node_t;
+
+struct aatree_s
+{
+ aatree_node_t *root;
+ UINT32 flags;
+};
+
+aatree_t *M_AATreeAlloc(UINT32 flags)
+{
+ aatree_t *aatree = Z_Malloc(sizeof (aatree_t), PU_STATIC, NULL);
+ aatree->root = NULL;
+ aatree->flags = flags;
+ return aatree;
+}
+
+static void M_AATreeFree_Node(aatree_node_t *node)
+{
+ if (node->left) M_AATreeFree_Node(node->left);
+ if (node->right) M_AATreeFree_Node(node->right);
+ Z_Free(node);
+}
+
+void M_AATreeFree(aatree_t *aatree)
+{
+ if (aatree->root)
+ M_AATreeFree_Node(aatree->root);
+
+ Z_Free(aatree);
+}
+
+static aatree_node_t *M_AATreeSkew(aatree_node_t *node)
+{
+ if (node && node->left && node->left->level == node->level)
+ {
+ // Not allowed: horizontal left-link. Reverse the
+ // horizontal link and hook the orphan back in.
+ aatree_node_t *oldleft = node->left;
+ node->left = oldleft->right;
+ oldleft->right = node;
+
+ return oldleft;
+ }
+
+ // No change needed.
+ return node;
+}
+
+static aatree_node_t *M_AATreeSplit(aatree_node_t *node)
+{
+ if (node && node->right && node->right->right && node->level == node->right->right->level)
+ {
+ // Not allowed: two consecutive horizontal right-links.
+ // The middle one becomes the new root at this point,
+ // with suitable adjustments below.
+
+ aatree_node_t *oldright = node->right;
+ node->right = oldright->left;
+ oldright->left = node;
+ oldright->level++;
+
+ return oldright;
+ }
+
+ // No change needed.
+ return node;
+}
+
+static aatree_node_t *M_AATreeSet_Node(aatree_node_t *node, UINT32 flags, INT32 key, void* value)
+{
+ if (!node)
+ {
+ // Nothing here, so just add where we are
+
+ node = Z_Malloc(sizeof (aatree_node_t), PU_STATIC, NULL);
+ node->level = 1;
+ node->key = key;
+ if (value && (flags & AATREE_ZUSER)) Z_SetUser(value, &node->value);
+ else node->value = value;
+ node->left = node->right = NULL;
+ }
+ else
+ {
+ if (key < node->key)
+ node->left = M_AATreeSet_Node(node->left, flags, key, value);
+ else if (key > node->key)
+ node->right = M_AATreeSet_Node(node->right, flags, key, value);
+ else
+ {
+ if (value && (flags & AATREE_ZUSER)) Z_SetUser(value, &node->value);
+ else node->value = value;
+ }
+
+ node = M_AATreeSkew(node);
+ node = M_AATreeSplit(node);
+ }
+
+ return node;
+}
+
+void M_AATreeSet(aatree_t *aatree, INT32 key, void* value)
+{
+ aatree->root = M_AATreeSet_Node(aatree->root, aatree->flags, key, value);
+}
+
+// Caveat: we don't distinguish between nodes that don't exists
+// and nodes with value == NULL.
+static void *M_AATreeGet_Node(aatree_node_t *node, INT32 key)
+{
+ if (node)
+ {
+ if (node->key == key)
+ return node->value;
+ else if(node->key < key)
+ return M_AATreeGet_Node(node->right, key);
+ else
+ return M_AATreeGet_Node(node->left, key);
+ }
+
+ return NULL;
+}
+
+void *M_AATreeGet(aatree_t *aatree, INT32 key)
+{
+ return M_AATreeGet_Node(aatree->root, key);
+}
+
+
+static void M_AATreeIterate_Node(aatree_node_t *node, aatree_iter_t callback)
+{
+ if (node->left) M_AATreeIterate_Node(node->left, callback);
+ callback(node->key, node->value);
+ if (node->right) M_AATreeIterate_Node(node->right, callback);
+}
+
+void M_AATreeIterate(aatree_t *aatree, aatree_iter_t callback)
+{
+ if (aatree->root)
+ M_AATreeIterate_Node(aatree->root, callback);
+}
diff --git a/src/m_aatree.h b/src/m_aatree.h
new file mode 100644
index 00000000..eeaebca3
--- /dev/null
+++ b/src/m_aatree.h
@@ -0,0 +1,31 @@
+// SONIC ROBO BLAST 2
+//-----------------------------------------------------------------------------
+// Copyright (C) 1993-1996 by id Software, Inc.
+// Copyright (C) 1998-2000 by DooM Legacy Team.
+// Copyright (C) 1999-2016 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 m_aatree.h
+/// \brief AA trees code
+
+#ifndef __M_AATREE__
+#define __M_AATREE__
+
+#include "doomtype.h"
+
+// Flags for AA trees.
+#define AATREE_ZUSER 1 // Treat values as z_zone-allocated blocks and set their user fields
+
+typedef struct aatree_s aatree_t;
+typedef void (*aatree_iter_t)(INT32 key, void *value);
+
+aatree_t *M_AATreeAlloc(UINT32 flags);
+void M_AATreeFree(aatree_t *aatree);
+void M_AATreeSet(aatree_t *aatree, INT32 key, void* value);
+void *M_AATreeGet(aatree_t *aatree, INT32 key);
+void M_AATreeIterate(aatree_t *aatree, aatree_iter_t callback);
+
+#endif
diff --git a/src/m_cheat.c b/src/m_cheat.c
index 89334596..3bbaadc5 100644
--- a/src/m_cheat.c
+++ b/src/m_cheat.c
@@ -452,7 +452,7 @@ void Command_RTeleport_f(void)
else
inty = 0;
- ss = R_PointInSubsector(p->mo->x + intx*FRACUNIT, p->mo->y + inty*FRACUNIT);
+ ss = R_IsPointInSubsector(p->mo->x + intx*FRACUNIT, p->mo->y + inty*FRACUNIT);
if (!ss || ss->sector->ceilingheight - ss->sector->floorheight < p->mo->height)
{
CONS_Alert(CONS_NOTICE, M_GetText("Not a valid location.\n"));
diff --git a/src/m_fixed.h b/src/m_fixed.h
index 70402f27..1cf9abba 100644
--- a/src/m_fixed.h
+++ b/src/m_fixed.h
@@ -46,41 +46,6 @@ typedef INT32 fixed_t;
#define FLOAT_TO_FIXED(f) (fixed_t)((f) * ((float)FRACUNIT))
-/** \brief The TMulScale16 function
-
- \param a a parameter of type fixed_t
- \param b a parameter of type fixed_t
- \param c a parameter of type fixed_t
- \param d a parameter of type fixed_t
- \param e a parameter of type fixed_t
- \param f a parameter of type fixed_t
-
- \return fixed_t
-
-
-*/
-FUNCMATH FUNCINLINE static ATTRINLINE fixed_t TMulScale16(fixed_t a, fixed_t b, fixed_t c, fixed_t d, fixed_t e, fixed_t f) \
-{ \
- return (fixed_t)((((INT64)a * (INT64)b) + ((INT64)c * (INT64)d) \
- + ((INT64)e * (INT64)f)) >> 16); \
-}
-
-/** \brief The DMulScale16 function
-
- \param a a parameter of type fixed_t
- \param b a parameter of type fixed_t
- \param c a parameter of type fixed_t
- \param d a parameter of type fixed_t
-
- \return fixed_t
-
-
-*/
-FUNCMATH FUNCINLINE static ATTRINLINE fixed_t DMulScale16(fixed_t a, fixed_t b, fixed_t c, fixed_t d) \
-{ \
- return (fixed_t)((((INT64)a * (INT64)b) + ((INT64)c * (INT64)d)) >> 16); \
-}
-
#if defined (__WATCOMC__) && FRACBITS == 16
#pragma aux FixedMul = \
"imul ebx", \
@@ -283,9 +248,16 @@ FUNCMATH FUNCINLINE static ATTRINLINE fixed_t FixedFloor(fixed_t x)
{
const fixed_t a = abs(x); //absolute of x
const fixed_t i = (a>>FRACBITS)< 0)
+ return x-f;
+ else
+ return x-(FRACUNIT-f);
+ }
return INT32_MIN;
}
@@ -301,7 +273,7 @@ FUNCMATH FUNCINLINE static ATTRINLINE fixed_t FixedTrunc(fixed_t x)
{
const fixed_t a = abs(x); //absolute of x
const fixed_t i = (a>>FRACBITS)< 0)
@@ -324,11 +296,18 @@ FUNCMATH FUNCINLINE static ATTRINLINE fixed_t FixedCeil(fixed_t x)
{
const fixed_t a = abs(x); //absolute of x
const fixed_t i = (a>>FRACBITS)< 0)
+ return x+(FRACUNIT-f);
+ else
+ return x+f;
+ }
return INT32_MAX;
}
@@ -344,7 +323,9 @@ FUNCMATH FUNCINLINE static ATTRINLINE fixed_t FixedRound(fixed_t x)
{
const fixed_t a = abs(x); //absolute of x
const fixed_t i = (a>>FRACBITS)<type == ev_keyup && (ev->data1 == KEY_LSHIFT || ev->data1 == KEY_RSHIFT))
- {
- shiftdown = false;
- return false;
- }
if (noFurtherInput)
{
// Ignore input after enter/escape/other buttons
@@ -2098,10 +2090,6 @@ boolean M_Responder(event_t *ev)
// added 5-2-98 remap virtual keys (mouse & joystick buttons)
switch (ch)
{
- case KEY_LSHIFT:
- case KEY_RSHIFT:
- shiftdown = true;
- break; //return false;
case KEY_MOUSE1:
case KEY_JOY1:
case KEY_JOY1 + 2:
@@ -3702,6 +3690,11 @@ static void M_DrawMessageMenu(void)
mlines = currentMenu->lastOn>>8;
max = (INT16)((UINT8)(currentMenu->lastOn & 0xFF)*8);
+
+ // hack: draw RA background in RA menus
+ if (gamestate == GS_TIMEATTACK)
+ V_DrawPatchFill(W_CachePatchName("SRB2BACK", PU_CACHE));
+
M_DrawTextBox(currentMenu->x, y - 8, (max+7)>>3, mlines);
while (*(msg+start))
@@ -3856,6 +3849,7 @@ static void M_ChangeLevel(INT32 choice)
static void M_ConfirmSpectate(INT32 choice)
{
(void)choice;
+ // We allow switching to spectator even if team changing is not allowed
M_ClearMenus(true);
COM_ImmedExecute("changeteam spectator");
}
@@ -3863,6 +3857,11 @@ static void M_ConfirmSpectate(INT32 choice)
static void M_ConfirmEnterGame(INT32 choice)
{
(void)choice;
+ if (!cv_allowteamchange.value)
+ {
+ M_StartMessage(M_GetText("The server is not allowing\nteam changes at this time.\nPress a key.\n"), NULL, MM_NOTHING);
+ return;
+ }
M_ClearMenus(true);
COM_ImmedExecute("changeteam playing");
}
@@ -4310,9 +4309,9 @@ static void M_SinglePlayerMenu(INT32 choice)
{
(void)choice;
SP_MainMenu[sprecordattack].status =
- (M_SecretUnlocked(SECRET_RECORDATTACK)) ? IT_CALL|IT_STRING|IT_CALL_NOTMODIFIED : IT_SECRET;
+ (M_SecretUnlocked(SECRET_RECORDATTACK)) ? IT_CALL|IT_STRING : IT_SECRET;
SP_MainMenu[spnightsmode].status =
- (M_SecretUnlocked(SECRET_NIGHTSMODE)) ? IT_CALL|IT_STRING|IT_CALL_NOTMODIFIED : IT_SECRET;
+ (M_SecretUnlocked(SECRET_NIGHTSMODE)) ? IT_CALL|IT_STRING : IT_SECRET;
M_SetupNextMenu(&SP_MainDef);
}
diff --git a/src/m_misc.c b/src/m_misc.c
index 64054d4f..d88643ec 100644
--- a/src/m_misc.c
+++ b/src/m_misc.c
@@ -585,7 +585,7 @@ static const char *Newsnapshotfile(const char *pathname, const char *ext)
i += add * result;
- if (add < 0 || add > 9999)
+ if (i < 0 || i > 9999)
return NULL;
}
@@ -1675,6 +1675,7 @@ char *M_GetToken(const char *inputString)
|| stringToUse[startPos] == '\r'
|| stringToUse[startPos] == '\n'
|| stringToUse[startPos] == '\0'
+ || stringToUse[startPos] == '"' // we're treating this as whitespace because SLADE likes adding it for no good reason
|| inComment != 0)
&& startPos < stringLength)
{
@@ -1742,6 +1743,7 @@ char *M_GetToken(const char *inputString)
&& stringToUse[endPos] != ','
&& stringToUse[endPos] != '{'
&& stringToUse[endPos] != '}'
+ && stringToUse[endPos] != '"' // see above
&& inComment == 0)
&& endPos < stringLength)
{
@@ -2323,158 +2325,3 @@ void M_SetupMemcpy(void)
M_Memcpy = cpu_cpy;
#endif
}
-
-
-// A partial implementation of AA trees,
-// according to the algorithms given on Wikipedia.
-// http://en.wikipedia.org/wiki/AA_tree
-
-
-
-typedef struct aatree_node_s
-{
- INT32 level;
- INT32 key;
- void* value;
-
- struct aatree_node_s *left, *right;
-} aatree_node_t;
-
-struct aatree_s
-{
- aatree_node_t *root;
- UINT32 flags;
-};
-
-aatree_t *M_AATreeAlloc(UINT32 flags)
-{
- aatree_t *aatree = Z_Malloc(sizeof (aatree_t), PU_STATIC, NULL);
- aatree->root = NULL;
- aatree->flags = flags;
- return aatree;
-}
-
-static void M_AATreeFree_Node(aatree_node_t *node)
-{
- if (node->left) M_AATreeFree_Node(node->left);
- if (node->right) M_AATreeFree_Node(node->right);
- Z_Free(node);
-}
-
-void M_AATreeFree(aatree_t *aatree)
-{
- if (aatree->root)
- M_AATreeFree_Node(aatree->root);
-
- Z_Free(aatree);
-}
-
-static aatree_node_t *M_AATreeSkew(aatree_node_t *node)
-{
- if (node && node->left && node->left->level == node->level)
- {
- // Not allowed: horizontal left-link. Reverse the
- // horizontal link and hook the orphan back in.
- aatree_node_t *oldleft = node->left;
- node->left = oldleft->right;
- oldleft->right = node;
-
- return oldleft;
- }
-
- // No change needed.
- return node;
-}
-
-static aatree_node_t *M_AATreeSplit(aatree_node_t *node)
-{
- if (node && node->right && node->right->right && node->level == node->right->right->level)
- {
- // Not allowed: two consecutive horizontal right-links.
- // The middle one becomes the new root at this point,
- // with suitable adjustments below.
-
- aatree_node_t *oldright = node->right;
- node->right = oldright->left;
- oldright->left = node;
- oldright->level++;
-
- return oldright;
- }
-
- // No change needed.
- return node;
-}
-
-static aatree_node_t *M_AATreeSet_Node(aatree_node_t *node, UINT32 flags, INT32 key, void* value)
-{
- if (!node)
- {
- // Nothing here, so just add where we are
-
- node = Z_Malloc(sizeof (aatree_node_t), PU_STATIC, NULL);
- node->level = 1;
- node->key = key;
- if (value && (flags & AATREE_ZUSER)) Z_SetUser(value, &node->value);
- else node->value = value;
- node->left = node->right = NULL;
- }
- else
- {
- if (key < node->key)
- node->left = M_AATreeSet_Node(node->left, flags, key, value);
- else if (key > node->key)
- node->right = M_AATreeSet_Node(node->right, flags, key, value);
- else
- {
- if (value && (flags & AATREE_ZUSER)) Z_SetUser(value, &node->value);
- else node->value = value;
- }
-
- node = M_AATreeSkew(node);
- node = M_AATreeSplit(node);
- }
-
- return node;
-}
-
-void M_AATreeSet(aatree_t *aatree, INT32 key, void* value)
-{
- aatree->root = M_AATreeSet_Node(aatree->root, aatree->flags, key, value);
-}
-
-// Caveat: we don't distinguish between nodes that don't exists
-// and nodes with value == NULL.
-static void *M_AATreeGet_Node(aatree_node_t *node, INT32 key)
-{
- if (node)
- {
- if (node->key == key)
- return node->value;
- else if(node->key < key)
- return M_AATreeGet_Node(node->right, key);
- else
- return M_AATreeGet_Node(node->left, key);
- }
-
- return NULL;
-}
-
-void *M_AATreeGet(aatree_t *aatree, INT32 key)
-{
- return M_AATreeGet_Node(aatree->root, key);
-}
-
-
-static void M_AATreeIterate_Node(aatree_node_t *node, aatree_iter_t callback)
-{
- if (node->left) M_AATreeIterate_Node(node->left, callback);
- callback(node->key, node->value);
- if (node->right) M_AATreeIterate_Node(node->right, callback);
-}
-
-void M_AATreeIterate(aatree_t *aatree, aatree_iter_t callback)
-{
- if (aatree->root)
- M_AATreeIterate_Node(aatree->root, callback);
-}
diff --git a/src/m_misc.h b/src/m_misc.h
index fa1f3b33..dc540dc1 100644
--- a/src/m_misc.h
+++ b/src/m_misc.h
@@ -96,19 +96,6 @@ void M_SetupMemcpy(void);
// counting bits, for weapon ammo code, usually
FUNCMATH UINT8 M_CountBits(UINT32 num, UINT8 size);
-// Flags for AA trees.
-#define AATREE_ZUSER 1 // Treat values as z_zone-allocated blocks and set their user fields
-
-typedef struct aatree_s aatree_t;
-typedef void (*aatree_iter_t)(INT32 key, void *value);
-
-aatree_t *M_AATreeAlloc(UINT32 flags);
-void M_AATreeFree(aatree_t *aatree);
-void M_AATreeSet(aatree_t *aatree, INT32 key, void* value);
-void *M_AATreeGet(aatree_t *aatree, INT32 key);
-void M_AATreeIterate(aatree_t *aatree, aatree_iter_t callback);
-
-// Nasty cyclic dependency workaround. This must come after aatree stuff.
#include "w_wad.h"
extern char configfile[MAX_WADPATH];
diff --git a/src/nds/i_system.c b/src/nds/i_system.c
index 0ed58029..3e5c4b8c 100644
--- a/src/nds/i_system.c
+++ b/src/nds/i_system.c
@@ -269,6 +269,18 @@ INT32 I_PutEnv(char *variable)
return -1;
}
+INT32 I_ClipboardCopy(const char *data, size_t size)
+{
+ (void)data;
+ (void)size;
+ return -1;
+}
+
+char *I_ClipboardPaste(void)
+{
+ return NULL;
+}
+
void I_RegisterSysCommands(void) {}
#include "../sdl/dosstr.c"
diff --git a/src/p_enemy.c b/src/p_enemy.c
index 025a2597..649c7883 100644
--- a/src/p_enemy.c
+++ b/src/p_enemy.c
@@ -1102,7 +1102,7 @@ void A_JetJawChomp(mobj_t *actor)
if (!actor->target || !(actor->target->flags & MF_SHOOTABLE)
|| actor->target->health <= 0 || !P_CheckSight(actor, actor->target))
{
- P_SetMobjState(actor, actor->info->spawnstate);
+ P_SetMobjStateNF(actor, actor->info->spawnstate);
return;
}
@@ -7644,7 +7644,7 @@ void A_SetObjectFlags(mobj_t *actor)
else if (locvar2 == 1)
locvar1 = actor->flags & ~locvar1;
- if ((locvar1 & (MF_NOBLOCKMAP|MF_NOSECTOR)) != (actor->flags & (MF_NOBLOCKMAP|MF_NOSECTOR))) // Blockmap/sector status has changed, so reset the links
+ if ((UINT32)(locvar1 & (MF_NOBLOCKMAP|MF_NOSECTOR)) != (actor->flags & (MF_NOBLOCKMAP|MF_NOSECTOR))) // Blockmap/sector status has changed, so reset the links
unlinkthings = true;
if (unlinkthings) {
diff --git a/src/p_floor.c b/src/p_floor.c
index 1c396c87..91121301 100644
--- a/src/p_floor.c
+++ b/src/p_floor.c
@@ -1163,7 +1163,7 @@ void T_SpikeSector(levelspecthink_t *spikes)
node = spikes->sector->touching_thinglist; // things touching this sector
- for (; node; node = node->m_snext)
+ for (; node; node = node->m_thinglist_next)
{
thing = node->m_thing;
if (!thing->player)
@@ -1316,7 +1316,7 @@ void T_BridgeThinker(levelspecthink_t *bridge)
controlsec = §ors[k];
// Is a player standing on me?
- for (node = sector->touching_thinglist; node; node = node->m_snext)
+ for (node = sector->touching_thinglist; node; node = node->m_thinglist_next)
{
thing = node->m_thing;
@@ -1739,7 +1739,7 @@ wegotit:
static mobj_t *SearchMarioNode(msecnode_t *node)
{
mobj_t *thing = NULL;
- for (; node; node = node->m_snext)
+ for (; node; node = node->m_thinglist_next)
{
// Things which should NEVER be ejected from a MarioBlock, by type.
switch (node->m_thing->type)
@@ -2003,7 +2003,7 @@ void T_NoEnemiesSector(levelspecthink_t *nobaddies)
goto foundenemy;
}
- node = node->m_snext;
+ node = node->m_thinglist_next;
}
}
}
@@ -2288,7 +2288,7 @@ void T_RaiseSector(levelspecthink_t *raise)
sector = §ors[i];
// Is a player standing on me?
- for (node = sector->touching_thinglist; node; node = node->m_snext)
+ for (node = sector->touching_thinglist; node; node = node->m_thinglist_next)
{
thing = node->m_thing;
diff --git a/src/p_inter.c b/src/p_inter.c
index 884b22ad..4892d977 100644
--- a/src/p_inter.c
+++ b/src/p_inter.c
@@ -1684,7 +1684,7 @@ void P_CheckTimeLimit(void)
return;
//Tagmode round end but only on the tic before the
- //XD_EXITLEVEL packet is recieved by all players.
+ //XD_EXITLEVEL packet is received by all players.
if (G_TagGametype())
{
if (leveltime == (timelimitintics + 1))
@@ -1695,7 +1695,7 @@ void P_CheckTimeLimit(void)
|| (players[i].pflags & PF_TAGGED) || (players[i].pflags & PF_TAGIT))
continue;
- CONS_Printf(M_GetText("%s recieved double points for surviving the round.\n"), player_names[i]);
+ CONS_Printf(M_GetText("%s received double points for surviving the round.\n"), player_names[i]);
P_AddPlayerScore(&players[i], players[i].score);
}
}
@@ -3626,7 +3626,7 @@ void P_PlayerFlagBurst(player_t *player, boolean toss)
// Flag text
{
char plname[MAXPLAYERNAME+4];
- char *flagtext;
+ const char *flagtext;
char flagcolor;
snprintf(plname, sizeof(plname), "%s%s%s",
diff --git a/src/p_local.h b/src/p_local.h
index c8930aed..1fd7ada0 100644
--- a/src/p_local.h
+++ b/src/p_local.h
@@ -251,7 +251,8 @@ mobj_t *P_SPMAngle(mobj_t *source, mobjtype_t type, angle_t angle, UINT8 aimtype
#endif
void P_ColorTeamMissile(mobj_t *missile, player_t *source);
SINT8 P_MobjFlip(mobj_t *mobj);
-boolean P_WeaponOrPanel(mobjtype_t type);
+fixed_t P_GetMobjGravity(mobj_t *mo);
+FUNCMATH boolean P_WeaponOrPanel(mobjtype_t type);
boolean P_CameraThinker(player_t *player, camera_t *thiscam, boolean resetcalled);
diff --git a/src/p_map.c b/src/p_map.c
index 71adf2e1..86776f8d 100644
--- a/src/p_map.c
+++ b/src/p_map.c
@@ -129,6 +129,10 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object)
return false;
}
+#ifdef ESLOPE
+ object->standingslope = NULL; // Okay, now we can't return - no launching off at silly angles for you.
+#endif
+
object->eflags |= MFE_SPRUNG; // apply this flag asap!
spring->flags &= ~(MF_SOLID|MF_SPECIAL); // De-solidify
@@ -232,20 +236,24 @@ static void P_DoFanAndGasJet(mobj_t *spring, mobj_t *object)
if (p && object->state == &states[object->info->painstate]) // can't use fans and gas jets when player is in pain!
return;
- // is object below thruster's position? if not, calculate distance between their bottoms
+ // is object's top below thruster's position? if not, calculate distance between their bottoms
if (spring->eflags & MFE_VERTICALFLIP)
{
- if (object->z + object->height > spring->z + spring->height)
+ if (object->z > spring->z + spring->height)
return;
zdist = (spring->z + spring->height) - (object->z + object->height);
}
else
{
- if (object->z < spring->z)
+ if (object->z + object->height < spring->z)
return;
zdist = object->z - spring->z;
}
+#ifdef ESLOPE
+ object->standingslope = NULL; // No launching off at silly angles for you.
+#endif
+
switch (spring->type)
{
case MT_FAN: // fan
@@ -977,18 +985,24 @@ static boolean PIT_CheckThing(mobj_t *thing)
return true;
}
- topz = thing->z - FixedMul(FRACUNIT, thing->scale);
+ topz = thing->z - thing->scale; // FixedMul(FRACUNIT, thing->scale), but thing->scale == FRACUNIT in base scale anyways
// block only when jumping not high enough,
// (dont climb max. 24units while already in air)
- // if not in air, let P_TryMove() decide if it's not too high
+ // since return false doesn't handle momentum properly,
+ // we lie to P_TryMove() so it's always too high
if (tmthing->player && tmthing->z + tmthing->height > topz
&& tmthing->z + tmthing->height < tmthing->ceilingz)
- return false; // block while in air
-
- if (thing->flags & MF_SPRING)
+ {
+ tmfloorz = tmceilingz = topz; // block while in air
+#ifdef ESLOPE
+ tmceilingslope = NULL;
+#endif
+ tmfloorthing = thing; // needed for side collision
+ }
+ else if (thing->flags & MF_SPRING)
;
- else if (topz < tmceilingz && tmthing->z+tmthing->height <= thing->z+thing->height)
+ else if (topz < tmceilingz && tmthing->z <= thing->z+thing->height)
{
tmceilingz = topz;
#ifdef ESLOPE
@@ -1014,17 +1028,24 @@ static boolean PIT_CheckThing(mobj_t *thing)
return true;
}
- topz = thing->z + thing->height + FixedMul(FRACUNIT, thing->scale);
+ topz = thing->z + thing->height + thing->scale; // FixedMul(FRACUNIT, thing->scale), but thing->scale == FRACUNIT in base scale anyways
// block only when jumping not high enough,
// (dont climb max. 24units while already in air)
- // if not in air, let P_TryMove() decide if it's not too high
- if (tmthing->player && tmthing->z < topz && tmthing->z > tmthing->floorz)
- return false; // block while in air
-
- if (thing->flags & MF_SPRING)
+ // since return false doesn't handle momentum properly,
+ // we lie to P_TryMove() so it's always too high
+ if (tmthing->player && tmthing->z < topz
+ && tmthing->z > tmthing->floorz)
+ {
+ tmfloorz = tmceilingz = topz; // block while in air
+#ifdef ESLOPE
+ tmfloorslope = NULL;
+#endif
+ tmfloorthing = thing; // needed for side collision
+ }
+ else if (thing->flags & MF_SPRING)
;
- else if (topz > tmfloorz && tmthing->z >= thing->z)
+ else if (topz > tmfloorz && tmthing->z+tmthing->height >= thing->z)
{
tmfloorz = topz;
#ifdef ESLOPE
@@ -1145,7 +1166,7 @@ static boolean PIT_CheckLine(line_t *ld)
}
// set openrange, opentop, openbottom
- P_LineOpening(ld);
+ P_LineOpening(ld, tmthing);
// adjust floor / ceiling heights
if (opentop < tmceilingz)
@@ -1263,7 +1284,7 @@ boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y)
topheight = P_GetFOFTopZ(thing, newsubsec->sector, rover, x, y, NULL);
bottomheight = P_GetFOFBottomZ(thing, newsubsec->sector, rover, x, y, NULL);
- if (rover->flags & FF_GOOWATER && !(thing->flags & MF_NOGRAVITY))
+ if ((rover->flags & (FF_SWIMMABLE|FF_GOOWATER)) == (FF_SWIMMABLE|FF_GOOWATER) && !(thing->flags & MF_NOGRAVITY))
{
// If you're inside goowater and slowing down
fixed_t sinklevel = FixedMul(thing->info->height/6, thing->scale);
@@ -1962,8 +1983,12 @@ boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff)
}
// Ramp test
- if (thing->player && maxstep > 0
- && !(P_PlayerTouchingSectorSpecial(thing->player, 1, 14) || GETSECSPECIAL(R_PointInSubsector(x, y)->sector->special, 1) == 14))
+ if (maxstep > 0 && !(
+ thing->player && (
+ P_PlayerTouchingSectorSpecial(thing->player, 1, 14)
+ || GETSECSPECIAL(R_PointInSubsector(x, y)->sector->special, 1) == 14)
+ )
+ )
{
// If the floor difference is MAXSTEPMOVE or less, and the sector isn't Section1:14, ALWAYS
// step down! Formerly required a Section1:13 sector for the full MAXSTEPMOVE, but no more.
@@ -2423,6 +2448,8 @@ isblocking:
//
// P_IsClimbingValid
//
+// Unlike P_DoClimbing, don't use when up against a one-sided linedef.
+//
static boolean P_IsClimbingValid(player_t *player, angle_t angle)
{
fixed_t platx, platy;
@@ -2571,7 +2598,7 @@ static boolean PTR_SlideTraverse(intercept_t *in)
}
// set openrange, opentop, openbottom
- P_LineOpening(li);
+ P_LineOpening(li, slidemo);
if (openrange < slidemo->height)
goto isblocking; // doesn't fit
@@ -2647,6 +2674,7 @@ isblocking:
// see about climbing on the wall
if (!(checkline->flags & ML_NOCLIMB))
{
+ boolean canclimb;
angle_t climbangle, climbline;
INT32 whichside = P_PointOnLineSide(slidemo->x, slidemo->y, li);
@@ -2657,9 +2685,11 @@ isblocking:
climbangle += (ANGLE_90 * (whichside ? -1 : 1));
+ canclimb = (li->backsector ? P_IsClimbingValid(slidemo->player, climbangle) : true);
+
if (((!slidemo->player->climbing && abs((signed)(slidemo->angle - ANGLE_90 - climbline)) < ANGLE_45)
|| (slidemo->player->climbing == 1 && abs((signed)(slidemo->angle - climbline)) < ANGLE_135))
- && P_IsClimbingValid(slidemo->player, climbangle))
+ && canclimb)
{
slidemo->angle = climbangle;
if (!demoplayback || P_AnalogMove(slidemo->player))
@@ -3365,7 +3395,7 @@ boolean P_CheckSector(sector_t *sector, boolean crunch)
for (i = 0; i < sector->numattached; i++)
{
sec = §ors[sector->attached[i]];
- for (n = sec->touching_thinglist; n; n = n->m_snext)
+ for (n = sec->touching_thinglist; n; n = n->m_thinglist_next)
n->visited = false;
sec->moved = true;
@@ -3377,7 +3407,7 @@ boolean P_CheckSector(sector_t *sector, boolean crunch)
do
{
- for (n = sec->touching_thinglist; n; n = n->m_snext)
+ for (n = sec->touching_thinglist; n; n = n->m_thinglist_next)
if (!n->visited)
{
n->visited = true;
@@ -3398,12 +3428,12 @@ boolean P_CheckSector(sector_t *sector, boolean crunch)
// Mark all things invalid
sector->moved = true;
- for (n = sector->touching_thinglist; n; n = n->m_snext)
+ for (n = sector->touching_thinglist; n; n = n->m_thinglist_next)
n->visited = false;
do
{
- for (n = sector->touching_thinglist; n; n = n->m_snext) // go through list
+ for (n = sector->touching_thinglist; n; n = n->m_thinglist_next) // go through list
if (!n->visited) // unprocessed thing found
{
n->visited = true; // mark thing as processed
@@ -3427,7 +3457,7 @@ boolean P_CheckSector(sector_t *sector, boolean crunch)
for (i = 0; i < sector->numattached; i++)
{
sec = §ors[sector->attached[i]];
- for (n = sec->touching_thinglist; n; n = n->m_snext)
+ for (n = sec->touching_thinglist; n; n = n->m_thinglist_next)
n->visited = false;
sec->moved = true;
@@ -3439,7 +3469,7 @@ boolean P_CheckSector(sector_t *sector, boolean crunch)
do
{
- for (n = sec->touching_thinglist; n; n = n->m_snext)
+ for (n = sec->touching_thinglist; n; n = n->m_thinglist_next)
if (!n->visited)
{
n->visited = true;
@@ -3457,12 +3487,12 @@ boolean P_CheckSector(sector_t *sector, boolean crunch)
// Mark all things invalid
sector->moved = true;
- for (n = sector->touching_thinglist; n; n = n->m_snext)
+ for (n = sector->touching_thinglist; n; n = n->m_thinglist_next)
n->visited = false;
do
{
- for (n = sector->touching_thinglist; n; n = n->m_snext) // go through list
+ for (n = sector->touching_thinglist; n; n = n->m_thinglist_next) // go through list
if (!n->visited) // unprocessed thing found
{
n->visited = true; // mark thing as processed
@@ -3502,7 +3532,7 @@ static msecnode_t *P_GetSecnode(void)
if (headsecnode)
{
node = headsecnode;
- headsecnode = headsecnode->m_snext;
+ headsecnode = headsecnode->m_thinglist_next;
}
else
node = Z_Calloc(sizeof (*node), PU_LEVEL, NULL);
@@ -3516,7 +3546,7 @@ static mprecipsecnode_t *P_GetPrecipSecnode(void)
if (headprecipsecnode)
{
node = headprecipsecnode;
- headprecipsecnode = headprecipsecnode->m_snext;
+ headprecipsecnode = headprecipsecnode->m_thinglist_next;
}
else
node = Z_Calloc(sizeof (*node), PU_LEVEL, NULL);
@@ -3527,14 +3557,14 @@ static mprecipsecnode_t *P_GetPrecipSecnode(void)
static inline void P_PutSecnode(msecnode_t *node)
{
- node->m_snext = headsecnode;
+ node->m_thinglist_next = headsecnode;
headsecnode = node;
}
// Tails 08-25-2002
static inline void P_PutPrecipSecnode(mprecipsecnode_t *node)
{
- node->m_snext = headprecipsecnode;
+ node->m_thinglist_next = headprecipsecnode;
headprecipsecnode = node;
}
@@ -3555,7 +3585,7 @@ static msecnode_t *P_AddSecnode(sector_t *s, mobj_t *thing, msecnode_t *nextnode
node->m_thing = thing; // Yes. Setting m_thing says 'keep it'.
return nextnode;
}
- node = node->m_tnext;
+ node = node->m_sectorlist_next;
}
// Couldn't find an existing node for this sector. Add one at the head
@@ -3568,17 +3598,17 @@ static msecnode_t *P_AddSecnode(sector_t *s, mobj_t *thing, msecnode_t *nextnode
node->m_sector = s; // sector
node->m_thing = thing; // mobj
- node->m_tprev = NULL; // prev node on Thing thread
- node->m_tnext = nextnode; // next node on Thing thread
+ node->m_sectorlist_prev = NULL; // prev node on Thing thread
+ node->m_sectorlist_next = nextnode; // next node on Thing thread
if (nextnode)
- nextnode->m_tprev = node; // set back link on Thing
+ nextnode->m_sectorlist_prev = node; // set back link on Thing
// Add new node at head of sector thread starting at s->touching_thinglist
- node->m_sprev = NULL; // prev node on sector thread
- node->m_snext = s->touching_thinglist; // next node on sector thread
+ node->m_thinglist_prev = NULL; // prev node on sector thread
+ node->m_thinglist_next = s->touching_thinglist; // next node on sector thread
if (s->touching_thinglist)
- node->m_snext->m_sprev = node;
+ node->m_thinglist_next->m_thinglist_prev = node;
s->touching_thinglist = node;
return node;
}
@@ -3596,7 +3626,7 @@ static mprecipsecnode_t *P_AddPrecipSecnode(sector_t *s, precipmobj_t *thing, mp
node->m_thing = thing; // Yes. Setting m_thing says 'keep it'.
return nextnode;
}
- node = node->m_tnext;
+ node = node->m_sectorlist_next;
}
// Couldn't find an existing node for this sector. Add one at the head
@@ -3609,17 +3639,17 @@ static mprecipsecnode_t *P_AddPrecipSecnode(sector_t *s, precipmobj_t *thing, mp
node->m_sector = s; // sector
node->m_thing = thing; // mobj
- node->m_tprev = NULL; // prev node on Thing thread
- node->m_tnext = nextnode; // next node on Thing thread
+ node->m_sectorlist_prev = NULL; // prev node on Thing thread
+ node->m_sectorlist_next = nextnode; // next node on Thing thread
if (nextnode)
- nextnode->m_tprev = node; // set back link on Thing
+ nextnode->m_sectorlist_prev = node; // set back link on Thing
// Add new node at head of sector thread starting at s->touching_thinglist
- node->m_sprev = NULL; // prev node on sector thread
- node->m_snext = s->touching_preciplist; // next node on sector thread
+ node->m_thinglist_prev = NULL; // prev node on sector thread
+ node->m_thinglist_next = s->touching_preciplist; // next node on sector thread
if (s->touching_preciplist)
- node->m_snext->m_sprev = node;
+ node->m_thinglist_next->m_thinglist_prev = node;
s->touching_preciplist = node;
return node;
}
@@ -3641,24 +3671,24 @@ static msecnode_t *P_DelSecnode(msecnode_t *node)
// Unlink from the Thing thread. The Thing thread begins at
// sector_list and not from mobj_t->touching_sectorlist.
- tp = node->m_tprev;
- tn = node->m_tnext;
+ tp = node->m_sectorlist_prev;
+ tn = node->m_sectorlist_next;
if (tp)
- tp->m_tnext = tn;
+ tp->m_sectorlist_next = tn;
if (tn)
- tn->m_tprev = tp;
+ tn->m_sectorlist_prev = tp;
// Unlink from the sector thread. This thread begins at
// sector_t->touching_thinglist.
- sp = node->m_sprev;
- sn = node->m_snext;
+ sp = node->m_thinglist_prev;
+ sn = node->m_thinglist_next;
if (sp)
- sp->m_snext = sn;
+ sp->m_thinglist_next = sn;
else
node->m_sector->touching_thinglist = sn;
if (sn)
- sn->m_sprev = sp;
+ sn->m_thinglist_prev = sp;
// Return this node to the freelist
@@ -3680,24 +3710,24 @@ static mprecipsecnode_t *P_DelPrecipSecnode(mprecipsecnode_t *node)
// Unlink from the Thing thread. The Thing thread begins at
// sector_list and not from mobj_t->touching_sectorlist.
- tp = node->m_tprev;
- tn = node->m_tnext;
+ tp = node->m_sectorlist_prev;
+ tn = node->m_sectorlist_next;
if (tp)
- tp->m_tnext = tn;
+ tp->m_sectorlist_next = tn;
if (tn)
- tn->m_tprev = tp;
+ tn->m_sectorlist_prev = tp;
// Unlink from the sector thread. This thread begins at
// sector_t->touching_thinglist.
- sp = node->m_sprev;
- sn = node->m_snext;
+ sp = node->m_thinglist_prev;
+ sn = node->m_thinglist_next;
if (sp)
- sp->m_snext = sn;
+ sp->m_thinglist_next = sn;
else
node->m_sector->touching_preciplist = sn;
if (sn)
- sn->m_sprev = sp;
+ sn->m_thinglist_prev = sp;
// Return this node to the freelist
@@ -3812,7 +3842,7 @@ void P_CreateSecNodeList(mobj_t *thing, fixed_t x, fixed_t y)
while (node)
{
node->m_thing = NULL;
- node = node->m_tnext;
+ node = node->m_sectorlist_next;
}
P_SetTarget(&tmthing, thing);
@@ -3850,11 +3880,11 @@ void P_CreateSecNodeList(mobj_t *thing, fixed_t x, fixed_t y)
if (!node->m_thing)
{
if (node == sector_list)
- sector_list = node->m_tnext;
+ sector_list = node->m_sectorlist_next;
node = P_DelSecnode(node);
}
else
- node = node->m_tnext;
+ node = node->m_sectorlist_next;
}
/* cph -
@@ -3895,7 +3925,7 @@ void P_CreatePrecipSecNodeList(precipmobj_t *thing,fixed_t x,fixed_t y)
while (node)
{
node->m_thing = NULL;
- node = node->m_tnext;
+ node = node->m_sectorlist_next;
}
tmprecipthing = thing;
@@ -3929,11 +3959,11 @@ void P_CreatePrecipSecNodeList(precipmobj_t *thing,fixed_t x,fixed_t y)
if (!node->m_thing)
{
if (node == precipsector_list)
- precipsector_list = node->m_tnext;
+ precipsector_list = node->m_sectorlist_next;
node = P_DelPrecipSecnode(node);
}
else
- node = node->m_tnext;
+ node = node->m_sectorlist_next;
}
/* cph -
diff --git a/src/p_maputl.c b/src/p_maputl.c
index c3a6fa84..46b03338 100644
--- a/src/p_maputl.c
+++ b/src/p_maputl.c
@@ -489,7 +489,7 @@ void P_CameraLineOpening(line_t *linedef)
}
}
-void P_LineOpening(line_t *linedef)
+void P_LineOpening(line_t *linedef, mobj_t *mobj)
{
sector_t *front, *back;
@@ -520,8 +520,8 @@ void P_LineOpening(line_t *linedef)
{ // Set open and high/low values here
fixed_t frontheight, backheight;
- frontheight = P_GetCeilingZ(tmthing, front, tmx, tmy, linedef);
- backheight = P_GetCeilingZ(tmthing, back, tmx, tmy, linedef);
+ frontheight = P_GetCeilingZ(mobj, front, tmx, tmy, linedef);
+ backheight = P_GetCeilingZ(mobj, back, tmx, tmy, linedef);
if (frontheight < backheight)
{
@@ -540,8 +540,8 @@ void P_LineOpening(line_t *linedef)
#endif
}
- frontheight = P_GetFloorZ(tmthing, front, tmx, tmy, linedef);
- backheight = P_GetFloorZ(tmthing, back, tmx, tmy, linedef);
+ frontheight = P_GetFloorZ(mobj, front, tmx, tmy, linedef);
+ backheight = P_GetFloorZ(mobj, back, tmx, tmy, linedef);
if (frontheight > backheight)
{
@@ -561,52 +561,65 @@ void P_LineOpening(line_t *linedef)
}
}
- if (tmthing)
+ if (mobj)
{
- fixed_t thingtop = tmthing->z + tmthing->height;
+ fixed_t thingtop = mobj->z + mobj->height;
// Check for collision with front side's midtexture if Effect 4 is set
- if (linedef->flags & ML_EFFECT4) {
+ if (linedef->flags & ML_EFFECT4
+ && !linedef->polyobj // don't do anything for polyobjects! ...for now
+ ) {
side_t *side = &sides[linedef->sidenum[0]];
fixed_t textop, texbottom, texheight;
fixed_t texmid, delta1, delta2;
+ INT32 texnum = R_GetTextureNum(side->midtexture); // make sure the texture is actually valid
- // Get the midtexture's height
- texheight = textures[texturetranslation[side->midtexture]]->height << FRACBITS;
+ if (texnum) {
+ // Get the midtexture's height
+ texheight = textures[texnum]->height << FRACBITS;
- // Set texbottom and textop to the Z coordinates of the texture's boundaries
-#ifdef POLYOBJECTS
- if (linedef->polyobj && (linedef->polyobj->flags & POF_TESTHEIGHT)) {
- if (linedef->flags & ML_DONTPEGBOTTOM) {
- texbottom = back->floorheight + side->rowoffset;
- textop = texbottom + texheight*(side->repeatcnt+1);
- } else {
- textop = back->ceilingheight - side->rowoffset;
- texbottom = textop - texheight*(side->repeatcnt+1);
- }
- } else
+ // Set texbottom and textop to the Z coordinates of the texture's boundaries
+#if 0 // #ifdef POLYOBJECTS
+ // don't remove this code unless solid midtextures
+ // on non-solid polyobjects should NEVER happen in the future
+ if (linedef->polyobj && (linedef->polyobj->flags & POF_TESTHEIGHT)) {
+ if (linedef->flags & ML_EFFECT5 && !side->repeatcnt) { // "infinite" repeat
+ texbottom = back->floorheight + side->rowoffset;
+ textop = back->ceilingheight + side->rowoffset;
+ } else if (!!(linedef->flags & ML_DONTPEGBOTTOM) ^ !!(linedef->flags & ML_EFFECT3)) {
+ texbottom = back->floorheight + side->rowoffset;
+ textop = texbottom + texheight*(side->repeatcnt+1);
+ } else {
+ textop = back->ceilingheight + side->rowoffset;
+ texbottom = textop - texheight*(side->repeatcnt+1);
+ }
+ } else
#endif
- {
- if (linedef->flags & ML_DONTPEGBOTTOM) {
- texbottom = openbottom + side->rowoffset;
- textop = texbottom + texheight*(side->repeatcnt+1);
- } else {
- textop = opentop - side->rowoffset;
- texbottom = textop - texheight*(side->repeatcnt+1);
+ {
+ if (linedef->flags & ML_EFFECT5 && !side->repeatcnt) { // "infinite" repeat
+ texbottom = openbottom + side->rowoffset;
+ textop = opentop + side->rowoffset;
+ } else if (!!(linedef->flags & ML_DONTPEGBOTTOM) ^ !!(linedef->flags & ML_EFFECT3)) {
+ texbottom = openbottom + side->rowoffset;
+ textop = texbottom + texheight*(side->repeatcnt+1);
+ } else {
+ textop = opentop + side->rowoffset;
+ texbottom = textop - texheight*(side->repeatcnt+1);
+ }
}
- }
- texmid = texbottom+(textop-texbottom)/2;
+ texmid = texbottom+(textop-texbottom)/2;
- delta1 = abs(tmthing->z - texmid);
- delta2 = abs(thingtop - texmid);
+ delta1 = abs(mobj->z - texmid);
+ delta2 = abs(thingtop - texmid);
- if (delta1 > delta2) { // Below
- if (opentop > texbottom)
- opentop = texbottom;
- } else { // Above
- if (openbottom < textop)
- openbottom = textop;
+ if (delta1 > delta2) { // Below
+ if (opentop > texbottom)
+ opentop = texbottom;
+ } else { // Above
+ if (openbottom < textop)
+ openbottom = textop;
+ }
}
}
@@ -636,16 +649,16 @@ void P_LineOpening(line_t *linedef)
if (!(rover->flags & FF_EXISTS))
continue;
- if (tmthing->player && (P_CheckSolidLava(tmthing, rover) || P_CanRunOnWater(tmthing->player, rover)))
+ if (mobj->player && (P_CheckSolidLava(mobj, rover) || P_CanRunOnWater(mobj->player, rover)))
;
- else if (!((rover->flags & FF_BLOCKPLAYER && tmthing->player)
- || (rover->flags & FF_BLOCKOTHERS && !tmthing->player)))
+ else if (!((rover->flags & FF_BLOCKPLAYER && mobj->player)
+ || (rover->flags & FF_BLOCKOTHERS && !mobj->player)))
continue;
- topheight = P_GetFOFTopZ(tmthing, front, rover, tmx, tmy, linedef);
- bottomheight = P_GetFOFBottomZ(tmthing, front, rover, tmx, tmy, linedef);
+ topheight = P_GetFOFTopZ(mobj, front, rover, tmx, tmy, linedef);
+ bottomheight = P_GetFOFBottomZ(mobj, front, rover, tmx, tmy, linedef);
- delta1 = abs(tmthing->z - (bottomheight + ((topheight - bottomheight)/2)));
+ delta1 = abs(mobj->z - (bottomheight + ((topheight - bottomheight)/2)));
delta2 = abs(thingtop - (bottomheight + ((topheight - bottomheight)/2)));
if (delta1 >= delta2 && !(rover->flags & FF_PLATFORM)) // thing is below FOF
@@ -680,16 +693,16 @@ void P_LineOpening(line_t *linedef)
if (!(rover->flags & FF_EXISTS))
continue;
- if (tmthing->player && (P_CheckSolidLava(tmthing, rover) || P_CanRunOnWater(tmthing->player, rover)))
+ if (mobj->player && (P_CheckSolidLava(mobj, rover) || P_CanRunOnWater(mobj->player, rover)))
;
- else if (!((rover->flags & FF_BLOCKPLAYER && tmthing->player)
- || (rover->flags & FF_BLOCKOTHERS && !tmthing->player)))
+ else if (!((rover->flags & FF_BLOCKPLAYER && mobj->player)
+ || (rover->flags & FF_BLOCKOTHERS && !mobj->player)))
continue;
- topheight = P_GetFOFTopZ(tmthing, back, rover, tmx, tmy, linedef);
- bottomheight = P_GetFOFBottomZ(tmthing, back, rover, tmx, tmy, linedef);
+ topheight = P_GetFOFTopZ(mobj, back, rover, tmx, tmy, linedef);
+ bottomheight = P_GetFOFBottomZ(mobj, back, rover, tmx, tmy, linedef);
- delta1 = abs(tmthing->z - (bottomheight + ((topheight - bottomheight)/2)));
+ delta1 = abs(mobj->z - (bottomheight + ((topheight - bottomheight)/2)));
delta2 = abs(thingtop - (bottomheight + ((topheight - bottomheight)/2)));
if (delta1 >= delta2 && !(rover->flags & FF_PLATFORM)) // thing is below FOF
@@ -723,7 +736,7 @@ void P_LineOpening(line_t *linedef)
{
const sector_t *polysec = linedef->backsector;
- delta1 = abs(tmthing->z - (polysec->floorheight + ((polysec->ceilingheight - polysec->floorheight)/2)));
+ delta1 = abs(mobj->z - (polysec->floorheight + ((polysec->ceilingheight - polysec->floorheight)/2)));
delta2 = abs(thingtop - (polysec->floorheight + ((polysec->ceilingheight - polysec->floorheight)/2)));
if (polysec->floorheight < lowestceiling && delta1 >= delta2) {
lowestceiling = polysec->floorheight;
diff --git a/src/p_maputl.h b/src/p_maputl.h
index c160bfa2..3d74e927 100644
--- a/src/p_maputl.h
+++ b/src/p_maputl.h
@@ -59,7 +59,7 @@ extern fixed_t opentop, openbottom, openrange, lowfloor, highceiling;
extern pslope_t *opentopslope, *openbottomslope;
#endif
-void P_LineOpening(line_t *plinedef);
+void P_LineOpening(line_t *plinedef, mobj_t *mobj);
boolean P_BlockLinesIterator(INT32 x, INT32 y, boolean(*func)(line_t *));
boolean P_BlockThingsIterator(INT32 x, INT32 y, boolean(*func)(mobj_t *));
diff --git a/src/p_mobj.c b/src/p_mobj.c
index 4122619d..9fdbc37f 100644
--- a/src/p_mobj.c
+++ b/src/p_mobj.c
@@ -1252,13 +1252,12 @@ static void P_PlayerFlip(mobj_t *mo)
}
//
-// P_CheckGravity
+// P_GetMobjGravity
//
-// Checks the current gravity state
-// of the object. If affect is true,
-// a gravity force will be applied.
+// Returns the current gravity
+// value of the object.
//
-void P_CheckGravity(mobj_t *mo, boolean affect)
+fixed_t P_GetMobjGravity(mobj_t *mo)
{
fixed_t gravityadd = 0;
boolean no3dfloorgrav = true; // Custom gravity
@@ -1279,25 +1278,23 @@ void P_CheckGravity(mobj_t *mo, boolean affect)
for (rover = mo->subsector->sector->ffloors; rover; rover = rover->next)
{
- if (!(rover->flags & FF_EXISTS))
+ if (!(rover->flags & FF_EXISTS) || !P_InsideANonSolidFFloor(mo, rover)) // P_InsideANonSolidFFloor checks for FF_EXISTS itself, but let's not always call this function
continue;
- if (P_InsideANonSolidFFloor(mo, rover))
- {
- if ((rover->flags & (FF_SWIMMABLE|FF_GOOWATER)) == (FF_SWIMMABLE|FF_GOOWATER))
- goopgravity = true;
- if (rover->master->frontsector->gravity)
- {
- gravityadd = -FixedMul(gravity,
- (FixedDiv(*rover->master->frontsector->gravity>>FRACBITS, 1000)));
+ if ((rover->flags & (FF_SWIMMABLE|FF_GOOWATER)) == (FF_SWIMMABLE|FF_GOOWATER))
+ goopgravity = true;
- if (rover->master->frontsector->verticalflip && gravityadd > 0)
- mo->eflags |= MFE_VERTICALFLIP;
+ if (!(rover->master->frontsector->gravity))
+ continue;
- no3dfloorgrav = false;
- break;
- }
- }
+ gravityadd = -FixedMul(gravity,
+ (FixedDiv(*rover->master->frontsector->gravity>>FRACBITS, 1000)));
+
+ if (rover->master->frontsector->verticalflip && gravityadd > 0)
+ mo->eflags |= MFE_VERTICALFLIP;
+
+ no3dfloorgrav = false;
+ break;
}
}
@@ -1317,33 +1314,22 @@ void P_CheckGravity(mobj_t *mo, boolean affect)
if (mo->eflags & MFE_UNDERWATER && !goopgravity)
gravityadd = gravityadd/3;
- if (!mo->momz) // mobj at stop, no floor, so feel the push of gravity!
- gravityadd <<= 1;
-
if (mo->player)
{
- if (mo->player->charability == CA_FLY && (mo->player->powers[pw_tailsfly]
- || (mo->state >= &states[S_PLAY_SPC1] && mo->state <= &states[S_PLAY_SPC4])))
- gravityadd = gravityadd/3; // less gravity while flying
- if (mo->player->pflags & PF_GLIDING)
- gravityadd = gravityadd/3; // less gravity while gliding
- if (mo->player->climbing)
- gravityadd = 0;
- if (mo->player->pflags & PF_NIGHTSMODE)
+ if ((mo->player->pflags & PF_GLIDING)
+ || (mo->player->charability == CA_FLY && (mo->player->powers[pw_tailsfly]
+ || (mo->state >= &states[S_PLAY_SPC1] && mo->state <= &states[S_PLAY_SPC4]))))
+ gravityadd = gravityadd/3; // less gravity while flying/gliding
+ if (mo->player->climbing || (mo->player->pflags & PF_NIGHTSMODE))
gravityadd = 0;
+ if (!(mo->flags2 & MF2_OBJECTFLIP) != !(mo->player->powers[pw_gravityboots])) // negated to turn numeric into bool - would be double negated, but not needed if both would be
{
- UINT8 bits = 0;
- if (mo->flags2 & MF2_OBJECTFLIP)
- bits ^= 1;
- if (mo->player->powers[pw_gravityboots])
- bits ^= 1;
- if (bits & 1)
- {
- gravityadd = -gravityadd;
- mo->eflags ^= MFE_VERTICALFLIP;
- }
+ gravityadd = -gravityadd;
+ mo->eflags ^= MFE_VERTICALFLIP;
}
+ if (wasflip == !(mo->eflags & MFE_VERTICALFLIP)) // note!! == ! is not equivalent to != here - turns numeric into bool this way
+ P_PlayerFlip(mo);
}
else
{
@@ -1351,10 +1337,10 @@ void P_CheckGravity(mobj_t *mo, boolean affect)
if (mo->flags2 & MF2_OBJECTFLIP)
{
mo->eflags |= MFE_VERTICALFLIP;
- if (gravityadd < 0) // Don't sink, only rise up
- gravityadd *= -1;
if (mo->z + mo->height >= mo->ceilingz)
gravityadd = 0;
+ else if (gravityadd < 0) // Don't sink, only rise up
+ gravityadd *= -1;
}
else //Otherwise, sort through the other exceptions.
{
@@ -1400,11 +1386,27 @@ void P_CheckGravity(mobj_t *mo, boolean affect)
if (goopgravity)
gravityadd = -gravityadd/5;
- if (affect)
- mo->momz += FixedMul(gravityadd, mo->scale);
+ gravityadd = FixedMul(gravityadd, mo->scale);
- if (mo->player && !!(mo->eflags & MFE_VERTICALFLIP) != wasflip)
- P_PlayerFlip(mo);
+ return gravityadd;
+}
+
+//
+// P_CheckGravity
+//
+// Checks the current gravity state
+// of the object. If affect is true,
+// a gravity force will be applied.
+//
+void P_CheckGravity(mobj_t *mo, boolean affect)
+{
+ fixed_t gravityadd = P_GetMobjGravity(mo);
+
+ if (!mo->momz) // mobj at stop, no floor, so feel the push of gravity!
+ gravityadd <<= 1;
+
+ if (affect)
+ mo->momz += gravityadd;
if (mo->type == MT_SKIM && mo->z + mo->momz <= mo->watertop && mo->z >= mo->watertop)
{
@@ -1480,7 +1482,7 @@ static void P_XYFriction(mobj_t *mo, fixed_t oldx, fixed_t oldy)
&& abs(player->rmomy) < FixedMul(STOPSPEED, mo->scale)
&& (!(player->cmd.forwardmove && !(twodlevel || mo->flags2 & MF2_TWOD)) && !player->cmd.sidemove && !(player->pflags & PF_SPINNING))
#ifdef ESLOPE
- && !(player->mo->standingslope && abs(player->mo->standingslope->zdelta) >= FRACUNIT/2)
+ && !(player->mo->standingslope && (!(player->mo->standingslope->flags & SL_NOPHYSICS)) && (abs(player->mo->standingslope->zdelta) >= FRACUNIT/2))
#endif
)
{
@@ -1530,7 +1532,7 @@ static void P_PushableCheckBustables(mobj_t *mo)
mo->y += mo->momy;
P_SetThingPosition(mo);
- for (node = mo->touching_sectorlist; node; node = node->m_snext)
+ for (node = mo->touching_sectorlist; node; node = node->m_sectorlist_next)
{
if (!node->m_sector)
break;
@@ -1538,6 +1540,7 @@ static void P_PushableCheckBustables(mobj_t *mo)
if (node->m_sector->ffloors)
{
ffloor_t *rover;
+ fixed_t topheight, bottomheight;
for (rover = node->m_sector->ffloors; rover; rover = rover->next)
{
@@ -1550,37 +1553,39 @@ static void P_PushableCheckBustables(mobj_t *mo)
if (!rover->master->frontsector->crumblestate)
{
+ topheight = P_GetFOFTopZ(mo, node->m_sector, rover, mo->x, mo->y, NULL);
+ bottomheight = P_GetFOFBottomZ(mo, node->m_sector, rover, mo->x, mo->y, NULL);
// Height checks
if (rover->flags & FF_SHATTERBOTTOM)
{
- if (mo->z+mo->momz + mo->height < *rover->bottomheight)
+ if (mo->z+mo->momz + mo->height < bottomheight)
continue;
- if (mo->z+mo->height > *rover->bottomheight)
+ if (mo->z+mo->height > bottomheight)
continue;
}
else if (rover->flags & FF_SPINBUST)
{
- if (mo->z+mo->momz > *rover->topheight)
+ if (mo->z+mo->momz > topheight)
continue;
- if (mo->z+mo->height < *rover->bottomheight)
+ if (mo->z+mo->height < bottomheight)
continue;
}
else if (rover->flags & FF_SHATTER)
{
- if (mo->z+mo->momz > *rover->topheight)
+ if (mo->z+mo->momz > topheight)
continue;
- if (mo->z+mo->momz + mo->height < *rover->bottomheight)
+ if (mo->z+mo->momz + mo->height < bottomheight)
continue;
}
else
{
- if (mo->z >= *rover->topheight)
+ if (mo->z >= topheight)
continue;
- if (mo->z+mo->height < *rover->bottomheight)
+ if (mo->z+mo->height < bottomheight)
continue;
}
@@ -1635,8 +1640,6 @@ void P_XYMovement(mobj_t *mo)
I_Assert(mo != NULL);
I_Assert(!P_MobjWasRemoved(mo));
- moved = true;
-
// if it's stopped
if (!mo->momx && !mo->momy)
{
@@ -1693,9 +1696,9 @@ void P_XYMovement(mobj_t *mo)
if (!P_TryMove(mo, mo->x + xmove, mo->y + ymove, true) && !(mo->eflags & MFE_SPRUNG))
{
// blocked move
+ moved = false;
if (player) {
- moved = false;
if (player->bot)
B_MoveBlocked(player);
}
@@ -1800,7 +1803,7 @@ void P_XYMovement(mobj_t *mo)
else
mo->momx = mo->momy = 0;
}
- else if (player)
+ else
moved = true;
if (P_MobjWasRemoved(mo)) // MF_SPECIAL touched a player! O_o;;
@@ -2013,12 +2016,14 @@ static void P_AdjustMobjFloorZ_FFloors(mobj_t *mo, sector_t *sector, UINT8 motyp
delta1 = mo->z - (bottomheight + ((topheight - bottomheight)/2));
delta2 = thingtop - (bottomheight + ((topheight - bottomheight)/2));
if (topheight > mo->floorz && abs(delta1) < abs(delta2)
- && !(rover->flags & FF_REVERSEPLATFORM))
+ && !(rover->flags & FF_REVERSEPLATFORM)
+ && ((P_MobjFlip(mo)*mo->momz >= 0) || (!(rover->flags & FF_PLATFORM)))) // In reverse gravity, only clip for FOFs that are intangible from their bottom (the "top" you're falling through) if you're coming from above ("below" in your frame of reference)
{
mo->floorz = topheight;
}
if (bottomheight < mo->ceilingz && abs(delta1) >= abs(delta2)
- && !(rover->flags & FF_PLATFORM))
+ && !(rover->flags & FF_PLATFORM)
+ && ((P_MobjFlip(mo)*mo->momz >= 0) || (!(rover->flags & FF_REVERSEPLATFORM)))) // In normal gravity, only clip for FOFs that are intangible from the top if you're coming from below
{
mo->ceilingz = bottomheight;
}
@@ -2152,16 +2157,6 @@ static boolean P_ZMovement(mobj_t *mo)
I_Assert(mo != NULL);
I_Assert(!P_MobjWasRemoved(mo));
-#ifdef ESLOPE
- if (mo->standingslope)
- {
- if (mo->flags & MF_NOCLIPHEIGHT)
- mo->standingslope = NULL;
- else if (!P_IsObjectOnGround(mo))
- P_SlopeLaunch(mo);
- }
-#endif
-
// Intercept the stupid 'fall through 3dfloors' bug
if (mo->subsector->sector->ffloors)
P_AdjustMobjFloorZ_FFloors(mo, mo->subsector->sector, 0);
@@ -2176,6 +2171,16 @@ static boolean P_ZMovement(mobj_t *mo)
}
mo->z += mo->momz;
+#ifdef ESLOPE
+ if (mo->standingslope)
+ {
+ if (mo->flags & MF_NOCLIPHEIGHT)
+ mo->standingslope = NULL;
+ else if (!P_IsObjectOnGround(mo))
+ P_SlopeLaunch(mo);
+ }
+#endif
+
switch (mo->type)
{
case MT_THROWNBOUNCE:
@@ -2245,6 +2250,7 @@ static boolean P_ZMovement(mobj_t *mo)
case MT_BLUETEAMRING:
case MT_FLINGRING:
case MT_FLINGCOIN:
+ case MT_FLINGEMERALD:
// Remove flinged stuff from death pits.
if (P_CheckDeathPitCollide(mo))
{
@@ -2276,7 +2282,6 @@ static boolean P_ZMovement(mobj_t *mo)
if (!(mo->momx || mo->momy || mo->momz))
return true;
break;
- case MT_FLINGEMERALD:
case MT_NIGHTSWING:
if (!(mo->momx || mo->momy || mo->momz))
return true;
@@ -2358,14 +2363,17 @@ static boolean P_ZMovement(mobj_t *mo)
mo->z = mo->floorz;
#ifdef ESLOPE
- P_CheckPosition(mo, mo->x, mo->y); // Sets mo->standingslope correctly
- if ((mo->eflags & MFE_VERTICALFLIP) ? tmceilingslope : tmfloorslope) {
- mo->standingslope = (mo->eflags & MFE_VERTICALFLIP) ? tmceilingslope : tmfloorslope;
+ if (!(mo->flags & MF_MISSILE) && mo->standingslope) // You're still on the ground; why are we here?
+ {
+ mo->momz = 0;
+ return true;
+ }
- // Reverse quantizing might could use its own function later
- mo->standingslope->zangle = ANGLE_MAX-mo->standingslope->zangle;
- P_QuantizeMomentumToSlope(&mom, mo->standingslope);
- mo->standingslope->zangle = ANGLE_MAX-mo->standingslope->zangle;
+ P_CheckPosition(mo, mo->x, mo->y); // Sets mo->standingslope correctly
+ if (((mo->eflags & MFE_VERTICALFLIP) ? tmceilingslope : tmfloorslope) && (mo->type != MT_STEAM))
+ {
+ mo->standingslope = (mo->eflags & MFE_VERTICALFLIP) ? tmceilingslope : tmfloorslope;
+ P_ReverseQuantizeMomentumToSlope(&mom, mo->standingslope);
}
#endif
@@ -2518,7 +2526,7 @@ static boolean P_ZMovement(mobj_t *mo)
mom.z = tmfloorthing->momz;
#ifdef ESLOPE
- if (mo->standingslope) {
+ if (mo->standingslope) { // MT_STEAM will never have a standingslope, see above.
P_QuantizeMomentumToSlope(&mom, mo->standingslope);
}
#endif
@@ -2703,7 +2711,7 @@ static void P_PlayerZMovement(mobj_t *mo)
msecnode_t *node;
boolean stopmovecut = false;
- for (node = mo->touching_sectorlist; node; node = node->m_snext)
+ for (node = mo->touching_sectorlist; node; node = node->m_sectorlist_next)
{
sector_t *sec = node->m_sector;
subsector_t *newsubsec;
@@ -2880,7 +2888,7 @@ nightsdone:
if (CheckForMarioBlocks && !(netgame && mo->player->spectator)) // Only let the player punch
{
// Search the touching sectors, from side-to-side...
- for (node = mo->touching_sectorlist; node; node = node->m_snext)
+ for (node = mo->touching_sectorlist; node; node = node->m_sectorlist_next)
{
ffloor_t *rover;
if (!node->m_sector->ffloors)
@@ -3648,7 +3656,7 @@ static void P_PlayerMobjThinker(mobj_t *mobj)
if (!(netgame && mobj->player->spectator))
{
// Crumbling platforms
- for (node = mobj->touching_sectorlist; node; node = node->m_snext)
+ for (node = mobj->touching_sectorlist; node; node = node->m_sectorlist_next)
{
fixed_t topheight, bottomheight;
ffloor_t *rover;
@@ -3673,7 +3681,7 @@ static void P_PlayerMobjThinker(mobj_t *mobj)
{
boolean thereiswater = false;
- for (node = mobj->touching_sectorlist; node; node = node->m_snext)
+ for (node = mobj->touching_sectorlist; node; node = node->m_sectorlist_next)
{
if (node->m_sector->ffloors)
{
@@ -3694,7 +3702,7 @@ static void P_PlayerMobjThinker(mobj_t *mobj)
}
if (thereiswater)
{
- for (node = mobj->touching_sectorlist; node; node = node->m_snext)
+ for (node = mobj->touching_sectorlist; node; node = node->m_sectorlist_next)
{
if (node->m_sector->ffloors)
{
@@ -3807,7 +3815,7 @@ void P_RecalcPrecipInSector(sector_t *sector)
sector->moved = true; // Recalc lighting and things too, maybe
- for (psecnode = sector->touching_preciplist; psecnode; psecnode = psecnode->m_snext)
+ for (psecnode = sector->touching_preciplist; psecnode; psecnode = psecnode->m_thinglist_next)
CalculatePrecipFloor(psecnode->m_thing);
}
@@ -4428,7 +4436,7 @@ static void P_Boss4MoveSpikeballs(mobj_t *mobj, angle_t angle, fixed_t fz)
{
INT32 s;
mobj_t *base = mobj, *seg;
- fixed_t dist, bz = (mobj->spawnpoint->z+16)<watertop+(16<tracer))
{
for (seg = base, dist = 172*FRACUNIT, s = 9; seg; seg = seg->hnext, dist += 124*FRACUNIT, --s)
@@ -4442,7 +4450,7 @@ static void P_Boss4PinchSpikeballs(mobj_t *mobj, angle_t angle, fixed_t fz)
{
INT32 s;
mobj_t *base = mobj, *seg;
- fixed_t dist, bz = (mobj->spawnpoint->z+16)<watertop+(16<tracer))
{
for (seg = base, dist = 112*FRACUNIT, s = 9; seg; seg = seg->hnext, dist += 132*FRACUNIT, --s)
@@ -4558,7 +4566,7 @@ static void P_Boss4Thinker(mobj_t *mobj)
INT32 i, arm;
mobj_t *seg, *base = mobj;
// First frame init, spawn all the things.
- mobj->spawnpoint->z = mobj->z>>FRACBITS;
+ mobj->watertop = mobj->z;
z = mobj->z + mobj->height/2 - mobjinfo[MT_EGGMOBILE4_MACE].height/2;
for (arm = 0; arm <3 ; arm++)
{
@@ -4614,7 +4622,7 @@ static void P_Boss4Thinker(mobj_t *mobj)
case 3:
{
fixed_t z;
- if (mobj->z < (mobj->spawnpoint->z+512)<z < mobj->watertop+(512<momz = 8*FRACUNIT;
else
{
@@ -4623,7 +4631,7 @@ static void P_Boss4Thinker(mobj_t *mobj)
}
mobj->movecount += 400<<(FRACBITS>>1);
mobj->movecount %= 360*FRACUNIT;
- z = mobj->z - (mobj->spawnpoint->z<height/2;
+ z = mobj->z - mobj->watertop - mobjinfo[MT_EGGMOBILE4_MACE].height - mobj->height/2;
if (z < 0) // We haven't risen high enough to pull the spikeballs along yet
P_Boss4MoveSpikeballs(mobj, FixedAngle(mobj->movecount), 0); // So don't pull the spikeballs along yet.
else
@@ -4633,13 +4641,13 @@ static void P_Boss4Thinker(mobj_t *mobj)
// Pinch phase!
case 4:
{
- if (mobj->z < (mobj->spawnpoint->z+512+128*(mobj->info->damage-mobj->health))<z < (mobj->watertop + ((512+128*(mobj->info->damage-mobj->health))<momz = 8*FRACUNIT;
else
mobj->momz = 0;
mobj->movecount += (800+800*(mobj->info->damage-mobj->health))<<(FRACBITS>>1);
mobj->movecount %= 360*FRACUNIT;
- P_Boss4PinchSpikeballs(mobj, FixedAngle(mobj->movecount), mobj->z - (mobj->spawnpoint->z<height/2);
+ P_Boss4PinchSpikeballs(mobj, FixedAngle(mobj->movecount), mobj->z - mobj->watertop - mobjinfo[MT_EGGMOBILE4_MACE].height - mobj->height/2);
if (!mobj->target || !mobj->target->health)
P_SupermanLook4Players(mobj);
@@ -6040,6 +6048,8 @@ void P_RunOverlays(void)
P_UnsetThingPosition(mo);
mo->x = destx;
mo->y = desty;
+ mo->radius = mo->target->radius;
+ mo->height = mo->target->height;
if (mo->eflags & MFE_VERTICALFLIP)
mo->z = (mo->target->z + mo->target->height - mo->height) - zoffs;
else
@@ -6638,6 +6648,18 @@ void P_MobjThinker(mobj_t *mobj)
}
else switch (mobj->type)
{
+ case MT_FALLINGROCK:
+ // Despawn rocks here in case zmovement code can't do so (blame slopes)
+ if (!mobj->momx && !mobj->momy && !mobj->momz
+ && ((mobj->eflags & MFE_VERTICALFLIP) ?
+ mobj->z + mobj->height >= mobj->ceilingz
+ : mobj->z <= mobj->floorz))
+ {
+ P_RemoveMobj(mobj);
+ return;
+ }
+ P_MobjCheckWater(mobj);
+ break;
case MT_EMERALDSPAWN:
if (mobj->threshold)
{
@@ -6917,6 +6939,7 @@ void P_MobjThinker(mobj_t *mobj)
{
mobj->flags &= ~MF_NOGRAVITY;
P_SetMobjState(mobj, S_NIGHTSDRONE1);
+ mobj->flags2 |= MF2_DONTDRAW;
}
}
else if (mobj->tracer && mobj->tracer->player)
@@ -7674,6 +7697,10 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type)
if (mobj->type == MT_UNIDUS)
mobj->z -= FixedMul(mobj->info->mass, mobj->scale);
+
+ // defaults onground
+ if (mobj->z + mobj->height == mobj->ceilingz)
+ mobj->eflags |= MFE_ONGROUND;
}
else
mobj->z = z;
@@ -7780,6 +7807,7 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type)
break;
case MT_EGGCAPSULE:
mobj->extravalue1 = -1; // timer for how long a player has been at the capsule
+ break;
case MT_REDTEAMRING:
mobj->color = skincolor_redteam;
break;
diff --git a/src/p_mobj.h b/src/p_mobj.h
index 9542ce8b..79cffae8 100644
--- a/src/p_mobj.h
+++ b/src/p_mobj.h
@@ -441,7 +441,7 @@ boolean P_SupermanLook4Players(mobj_t *actor);
void P_DestroyRobots(void);
void P_SnowThinker(precipmobj_t *mobj);
void P_RainThinker(precipmobj_t *mobj);
-void P_NullPrecipThinker(precipmobj_t *mobj);
+FUNCMATH void P_NullPrecipThinker(precipmobj_t *mobj);
void P_RemovePrecipMobj(precipmobj_t *mobj);
void P_SetScale(mobj_t *mobj, fixed_t newscale);
void P_XYMovement(mobj_t *mo);
diff --git a/src/p_saveg.c b/src/p_saveg.c
index 5e457ca3..75f7b3e5 100644
--- a/src/p_saveg.c
+++ b/src/p_saveg.c
@@ -460,6 +460,7 @@ static void P_NetUnArchivePlayers(void)
#define SD_TAG 0x10
#define SD_FLOORANG 0x20
#define SD_CEILANG 0x40
+#define SD_TAGLIST 0x80
#define LD_FLAG 0x01
#define LD_SPECIAL 0x02
@@ -509,10 +510,9 @@ static void P_NetArchiveWorld(void)
//
// flats
//
- // P_AddLevelFlat should not add but just return the number
- if (ss->floorpic != P_AddLevelFlat(ms->floorpic, levelflats))
+ if (ss->floorpic != P_CheckLevelFlat(ms->floorpic))
diff |= SD_FLOORPIC;
- if (ss->ceilingpic != P_AddLevelFlat(ms->ceilingpic, levelflats))
+ if (ss->ceilingpic != P_CheckLevelFlat(ms->ceilingpic))
diff |= SD_CEILPIC;
if (ss->lightlevel != SHORT(ms->lightlevel))
@@ -535,6 +535,8 @@ static void P_NetArchiveWorld(void)
if (ss->tag != SHORT(ms->tag))
diff2 |= SD_TAG;
+ if (ss->nexttag != ss->spawn_nexttag || ss->firsttag != ss->spawn_firsttag)
+ diff2 |= SD_TAGLIST;
// Check if any of the sector's FOFs differ from how they spawned
if (ss->ffloors)
@@ -582,16 +584,17 @@ static void P_NetArchiveWorld(void)
WRITEFIXED(put, ss->ceiling_xoffs);
if (diff2 & SD_CYOFFS)
WRITEFIXED(put, ss->ceiling_yoffs);
- if (diff2 & SD_TAG)
- {
+ if (diff2 & SD_TAG) // save only the tag
WRITEINT16(put, ss->tag);
- WRITEINT32(put, ss->firsttag);
- WRITEINT32(put, ss->nexttag);
- }
if (diff2 & SD_FLOORANG)
WRITEANGLE(put, ss->floorpic_angle);
if (diff2 & SD_CEILANG)
WRITEANGLE(put, ss->ceilingpic_angle);
+ if (diff2 & SD_TAGLIST) // save both firsttag and nexttag
+ { // either of these could be changed even if tag isn't
+ WRITEINT32(put, ss->firsttag);
+ WRITEINT32(put, ss->nexttag);
+ }
// Special case: save the stats of all modified ffloors along with their ffloor "number"s
// we don't bother with ffloors that haven't changed, that would just add to savegame even more than is really needed
@@ -752,12 +755,12 @@ static void P_NetUnArchiveWorld(void)
sectors[i].ceilingheight = READFIXED(get);
if (diff & SD_FLOORPIC)
{
- sectors[i].floorpic = P_AddLevelFlat((char *)get, levelflats);
+ sectors[i].floorpic = P_AddLevelFlatRuntime((char *)get);
get += 8;
}
if (diff & SD_CEILPIC)
{
- sectors[i].ceilingpic = P_AddLevelFlat((char *)get, levelflats);
+ sectors[i].ceilingpic = P_AddLevelFlatRuntime((char *)get);
get += 8;
}
if (diff & SD_LIGHT)
@@ -774,12 +777,11 @@ static void P_NetUnArchiveWorld(void)
if (diff2 & SD_CYOFFS)
sectors[i].ceiling_yoffs = READFIXED(get);
if (diff2 & SD_TAG)
+ sectors[i].tag = READINT16(get); // DON'T use P_ChangeSectorTag
+ if (diff2 & SD_TAGLIST)
{
- INT16 tag;
- tag = READINT16(get);
sectors[i].firsttag = READINT32(get);
sectors[i].nexttag = READINT32(get);
- P_ChangeSectorTag(i, tag);
}
if (diff2 & SD_FLOORANG)
sectors[i].floorpic_angle = READANGLE(get);
@@ -2607,6 +2609,7 @@ static void P_NetUnArchiveThinkers(void)
thinker_t *next;
UINT8 tclass;
UINT8 restoreNum = false;
+ UINT32 i;
if (READUINT32(save_p) != ARCHIVEBLOCK_THINKERS)
I_Error("Bad $$$.sav at archive block Thinkers");
@@ -2627,6 +2630,12 @@ static void P_NetUnArchiveThinkers(void)
iquetail = iquehead = 0;
P_InitThinkers();
+ // clear sector thinker pointers so they don't point to non-existant thinkers for all of eternity
+ for (i = 0; i < numsectors; i++)
+ {
+ sectors[i].floordata = sectors[i].ceilingdata = sectors[i].lightingdata = NULL;
+ }
+
// read in saved thinkers
for (;;)
{
@@ -3285,7 +3294,7 @@ void P_SaveNetGame(void)
{
thinker_t *th;
mobj_t *mobj;
- INT32 i = 0;
+ INT32 i = 1; // don't start from 0, it'd be confused with a blank pointer otherwise
CV_SaveNetVars(&save_p);
P_NetArchiveMisc();
diff --git a/src/p_setup.c b/src/p_setup.c
index b36bf0b8..8e746457 100644
--- a/src/p_setup.c
+++ b/src/p_setup.c
@@ -574,6 +574,69 @@ INT32 P_AddLevelFlat(const char *flatname, levelflat_t *levelflat)
return (INT32)i;
}
+// help function for Lua and $$$.sav reading
+// same as P_AddLevelFlat, except this is not setup so we must realloc levelflats to fit in the new flat
+// no longer a static func in lua_maplib.c because p_saveg.c also needs it
+//
+INT32 P_AddLevelFlatRuntime(const char *flatname)
+{
+ size_t i;
+ levelflat_t *levelflat = levelflats;
+
+ //
+ // first scan through the already found flats
+ //
+ for (i = 0; i < numlevelflats; i++, levelflat++)
+ if (strnicmp(levelflat->name,flatname,8)==0)
+ break;
+
+ // that flat was already found in the level, return the id
+ if (i == numlevelflats)
+ {
+ // allocate new flat memory
+ levelflats = Z_Realloc(levelflats, (numlevelflats + 1) * sizeof(*levelflats), PU_LEVEL, NULL);
+ levelflat = levelflats+i;
+
+ // store the name
+ strlcpy(levelflat->name, flatname, sizeof (levelflat->name));
+ strupr(levelflat->name);
+
+ // store the flat lump number
+ levelflat->lumpnum = R_GetFlatNumForName(flatname);
+
+#ifndef ZDEBUG
+ CONS_Debug(DBG_SETUP, "flat #%03d: %s\n", atoi(sizeu1(numlevelflats)), levelflat->name);
+#endif
+
+ numlevelflats++;
+ }
+
+ // level flat id
+ return (INT32)i;
+}
+
+// help function for $$$.sav checking
+// this simply returns the flat # for the name given
+//
+INT32 P_CheckLevelFlat(const char *flatname)
+{
+ size_t i;
+ levelflat_t *levelflat = levelflats;
+
+ //
+ // scan through the already found flats
+ //
+ for (i = 0; i < numlevelflats; i++, levelflat++)
+ if (strnicmp(levelflat->name,flatname,8)==0)
+ break;
+
+ if (i == numlevelflats)
+ return 0; // ??? flat was not found, this should not happen!
+
+ // level flat id
+ return (INT32)i;
+}
+
static void P_LoadSectors(lumpnum_t lumpnum)
{
UINT8 *data;
@@ -614,6 +677,7 @@ static void P_LoadSectors(lumpnum_t lumpnum)
ss->special = SHORT(ms->special);
ss->tag = SHORT(ms->tag);
ss->nexttag = ss->firsttag = -1;
+ ss->spawn_nexttag = ss->spawn_firsttag = -1;
memset(&ss->soundorg, 0, sizeof(ss->soundorg));
ss->validcount = 0;
@@ -1931,10 +1995,18 @@ static void P_GroupLines(void)
// allocate linebuffers for each sector
for (i = 0, sector = sectors; i < numsectors; i++, sector++)
{
- sector->lines = Z_Calloc(sector->linecount * sizeof(line_t*), PU_LEVEL, NULL);
+ if (sector->linecount == 0) // no lines found?
+ {
+ sector->lines = NULL;
+ CONS_Debug(DBG_SETUP, "P_GroupLines: sector %s has no lines\n", sizeu1(i));
+ }
+ else
+ {
+ sector->lines = Z_Calloc(sector->linecount * sizeof(line_t*), PU_LEVEL, NULL);
- // zero the count, since we'll later use this to track how many we've recorded
- sector->linecount = 0;
+ // zero the count, since we'll later use this to track how many we've recorded
+ sector->linecount = 0;
+ }
}
// iterate through lines, assigning them to sectors' linebuffers,
@@ -1952,11 +2024,14 @@ static void P_GroupLines(void)
{
M_ClearBox(bbox);
- for (j = 0; j < sector->linecount; j++)
+ if (sector->linecount != 0)
{
- li = sector->lines[j];
- M_AddToBox(bbox, li->v1->x, li->v1->y);
- M_AddToBox(bbox, li->v2->x, li->v2->y);
+ for (j = 0; j < sector->linecount; j++)
+ {
+ li = sector->lines[j];
+ M_AddToBox(bbox, li->v1->x, li->v1->y);
+ M_AddToBox(bbox, li->v2->x, li->v2->y);
+ }
}
// set the degenmobj_t to the middle of the bounding box
@@ -1966,6 +2041,35 @@ static void P_GroupLines(void)
}
}
+//
+// P_LoadReject
+//
+// Detect if the REJECT lump is valid,
+// if not, rejectmatrix will be NULL
+static void P_LoadReject(lumpnum_t lumpnum)
+{
+ size_t count;
+ const char *lumpname = W_CheckNameForNum(lumpnum);
+
+ // Check if the lump exists, and if it's named "REJECT"
+ if (!lumpname || memcmp(lumpname, "REJECT\0\0", 8) != 0)
+ {
+ rejectmatrix = NULL;
+ CONS_Debug(DBG_SETUP, "P_LoadReject: No valid REJECT lump found\n");
+ return;
+ }
+
+ count = W_LumpLength(lumpnum);
+
+ if (!count) // zero length, someone probably used ZDBSP
+ {
+ rejectmatrix = NULL;
+ CONS_Debug(DBG_SETUP, "P_LoadReject: REJECT lump has size 0, will not be loaded\n");
+ }
+ else
+ rejectmatrix = W_CacheLumpNum(lumpnum, PU_LEVEL);
+}
+
#if 0
static char *levellumps[] =
{
@@ -2545,11 +2649,7 @@ boolean P_SetupLevel(boolean skipprecip)
lastloadedmaplumpnum = W_GetNumForName(maplumpname = G_BuildMapName(gamemap));
R_ReInitColormaps(mapheaderinfo[gamemap-1]->palette);
- CON_ReSetupBackColormap(mapheaderinfo[gamemap-1]->palette);
-
- // now part of level loading since in future each level may have
- // its own anim texture sequences, switches etc.
- P_InitPicAnims();
+ CON_SetupBackColormap();
// SRB2 determines the sky texture to be used depending on the map header.
P_SetupLevelSky(mapheaderinfo[gamemap-1]->skynum, true);
@@ -2574,7 +2674,7 @@ boolean P_SetupLevel(boolean skipprecip)
P_LoadSubsectors(lastloadedmaplumpnum + ML_SSECTORS);
P_LoadNodes(lastloadedmaplumpnum + ML_NODES);
P_LoadSegs(lastloadedmaplumpnum + ML_SEGS);
- rejectmatrix = W_CacheLumpNum(lastloadedmaplumpnum + ML_REJECT, PU_LEVEL);
+ P_LoadReject(lastloadedmaplumpnum + ML_REJECT);
P_GroupLines();
numdmstarts = numredctfstarts = numbluectfstarts = 0;
@@ -2961,6 +3061,9 @@ boolean P_AddWadFile(const char *wadfilename, char **firstmapname)
else
R_FlushTextureCache(); // just reload it from file
+ // Reload ANIMATED / ANIMDEFS
+ P_InitPicAnims();
+
// Flush and reload HUD graphics
ST_UnloadGraphics();
HU_LoadGraphics();
diff --git a/src/p_setup.h b/src/p_setup.h
index 0d735fd7..3bca1104 100644
--- a/src/p_setup.h
+++ b/src/p_setup.h
@@ -47,6 +47,8 @@ typedef struct
extern size_t numlevelflats;
extern levelflat_t *levelflats;
INT32 P_AddLevelFlat(const char *flatname, levelflat_t *levelflat);
+INT32 P_AddLevelFlatRuntime(const char *flatname);
+INT32 P_CheckLevelFlat(const char *flatname);
extern size_t nummapthings;
extern mapthing_t *mapthings;
diff --git a/src/p_sight.c b/src/p_sight.c
index 14c1c945..bd6ab4d7 100644
--- a/src/p_sight.c
+++ b/src/p_sight.c
@@ -325,9 +325,12 @@ boolean P_CheckSight(mobj_t *t1, mobj_t *t2)
s2 = t2->subsector->sector;
pnum = (s1-sectors)*numsectors + (s2-sectors);
- // Check in REJECT table.
- if (rejectmatrix[pnum>>3] & (1 << (pnum&7))) // can't possibly be connected
- return false;
+ if (rejectmatrix != NULL)
+ {
+ // Check in REJECT table.
+ if (rejectmatrix[pnum>>3] & (1 << (pnum&7))) // can't possibly be connected
+ return false;
+ }
// killough 11/98: shortcut for melee situations
// same subsector? obviously visible
diff --git a/src/p_slopes.c b/src/p_slopes.c
index 6393ca4b..d939fee9 100644
--- a/src/p_slopes.c
+++ b/src/p_slopes.c
@@ -199,7 +199,6 @@ static fixed_t P_GetExtent(sector_t *sector, line_t *line)
// Find furthest vertex from the reference line. It, along with the two ends
// of the line, will define the plane.
- // SRB2CBTODO: Use a formula to get the slope to slide objects depending on how steep
for(i = 0; i < sector->linecount; i++)
{
line_t *li = sector->lines[i];
@@ -231,7 +230,6 @@ static fixed_t P_GetExtent(sector_t *sector, line_t *line)
//
// Creates one or more slopes based on the given line type and front/back
// sectors.
-// Kalaron: Check if dynamic slopes need recalculation
//
void P_SpawnSlope_Line(int linenum)
{
@@ -276,7 +274,6 @@ void P_SpawnSlope_Line(int linenum)
ny = -FixedDiv(line->dx, len);
}
- // SRB2CBTODO: Transform origin relative to the bounds of an individual FOF
origin.x = line->v1->x + (line->v2->x - line->v1->x)/2;
origin.y = line->v1->y + (line->v2->y - line->v1->y)/2;
@@ -327,7 +324,7 @@ void P_SpawnSlope_Line(int linenum)
// fslope->normal is a 3D line perpendicular to the 3D vector
// Sync the linedata of the line that started this slope
- // SRB2CBTODO: Anything special for remote(control sector)-based slopes later?
+ // TODO: Anything special for control sector based slopes later?
fslope->sourceline = line;
// To find the real highz/lowz of a slope, you need to check all the vertexes
@@ -379,7 +376,7 @@ void P_SpawnSlope_Line(int linenum)
cslope->refpos = 2;
// Sync the linedata of the line that started this slope
- // SRB2CBTODO: Anything special for remote(control sector)-based slopes later?
+ // TODO: Anything special for control sector based slopes later?
cslope->sourceline = line;
// Remember the way the slope is formed
@@ -445,7 +442,7 @@ void P_SpawnSlope_Line(int linenum)
fslope->refpos = 3;
// Sync the linedata of the line that started this slope
- // SRB2CBTODO: Anything special for remote(control sector)-based slopes later?
+ // TODO: Anything special for control sector based slopes later?
fslope->sourceline = line;
// Remember the way the slope is formed
@@ -488,7 +485,7 @@ void P_SpawnSlope_Line(int linenum)
cslope->refpos = 4;
// Sync the linedata of the line that started this slope
- // SRB2CBTODO: Anything special for remote(control sector)-based slopes later?
+ // TODO: Anything special for control sector based slopes later?
cslope->sourceline = line;
// Remember the way the slope is formed
@@ -554,16 +551,11 @@ static pslope_t *P_NewVertexSlope(INT16 tag1, INT16 tag2, INT16 tag3, UINT8 flag
ret->vertices[2] = mt;
}
- if (!ret->vertices[0])
- CONS_Printf("PANIC 0\n");
- if (!ret->vertices[1])
- CONS_Printf("PANIC 1\n");
- if (!ret->vertices[2])
- CONS_Printf("PANIC 2\n");
-
// Now set heights for each vertex, because they haven't been set yet
for (i = 0; i < 3; i++) {
mt = ret->vertices[i];
+ if (!mt) // If a vertex wasn't found, it's game over. There's nothing you can do to recover (except maybe try and kill the slope instead - TODO?)
+ I_Error("P_NewVertexSlope: Slope vertex %s (for linedef tag %d) not found!", sizeu1(i), tag1);
if (mt->extrainfo)
mt->z = mt->options;
else
@@ -623,265 +615,10 @@ pslope_t *P_SlopeById(UINT16 id)
return ret;
}
-#ifdef SPRINGCLEAN
-#include "byteptr.h"
-
-#include "p_setup.h"
-#include "p_local.h"
-
-//==========================================================================
-//
-// P_SetSlopesFromVertexHeights
-//
-//==========================================================================
-void P_SetSlopesFromVertexHeights(lumpnum_t lumpnum)
-{
- mapthing_t *mt;
- boolean vt_found = false;
- size_t i, j, k, l, q;
-
- //size_t i;
- //mapthing_t *mt;
- char *data;
- char *datastart;
-
- // SRB2CBTODO: WHAT IS (5 * sizeof (short))?! It = 10
- // anything else seems to make a map not load properly,
- // but this hard-coded value MUST have some reason for being what it is
- size_t snummapthings = W_LumpLength(lumpnum) / (5 * sizeof (short));
- mapthing_t *smapthings = Z_Calloc(snummapthings * sizeof (*smapthings), PU_LEVEL, NULL);
- fixed_t x, y;
- sector_t *sector;
- // Spawn axis points first so they are
- // at the front of the list for fast searching.
- data = datastart = W_CacheLumpNum(lumpnum, PU_LEVEL);
- mt = smapthings;
- for (i = 0; i < snummapthings; i++, mt++)
- {
- mt->x = READINT16(data);
- mt->y = READINT16(data);
- mt->angle = READINT16(data);
- mt->type = READINT16(data);
- mt->options = READINT16(data);
- // mt->z hasn't been set yet!
- //mt->extrainfo = (byte)(mt->type >> 12); // slope things are special, they have a bigger range of types
-
- //mt->type &= 4095; // SRB2CBTODO: WHAT IS THIS???? Mobj type limits?!!!!
- x = mt->x*FRACUNIT;
- y = mt->y*FRACUNIT;
- sector = R_PointInSubsector(x, y)->sector;
- // Z for objects
-#ifdef ESLOPE
- if (sector->f_slope)
- mt->z = (short)(P_GetZAt(sector->f_slope, x, y)>>FRACBITS);
- else
-#endif
- mt->z = (short)(sector->floorheight>>FRACBITS);
-
- mt->z = mt->z + (mt->options >> ZSHIFT);
-
- if (mt->type == THING_VertexFloorZ || mt->type == THING_VertexCeilingZ) // THING_VertexFloorZ
- {
- for(l = 0; l < numvertexes; l++)
- {
- if (vertexes[l].x == mt->x*FRACUNIT && vertexes[l].y == mt->y*FRACUNIT)
- {
- if (mt->type == THING_VertexFloorZ)
- {
- vertexes[l].z = mt->z*FRACUNIT;
- //I_Error("Z value: %i", vertexes[l].z/FRACUNIT);
-
- }
- else
- {
- vertexes[l].z = mt->z*FRACUNIT; // celing floor
- }
- vt_found = true;
- }
- }
- //mt->type = 0; // VPHYSICS: Dynamic slopes
-
-
-
-
-
-
- if (vt_found)
- {
- for (k = 0; k < numsectors; k++)
- {
- sector_t *sec = §ors[k];
- if (sec->linecount != 3) continue; // only works with triangular sectors
-
- v3float_t vt1, vt2, vt3; // cross = ret->normalf
- v3float_t vec1, vec2;
-
- int vi1, vi2, vi3;
-
- vi1 = (int)(sec->lines[0]->v1 - vertexes);
- vi2 = (int)(sec->lines[0]->v2 - vertexes);
- vi3 = (sec->lines[1]->v1 == sec->lines[0]->v1 || sec->lines[1]->v1 == sec->lines[0]->v2)?
- (int)(sec->lines[1]->v2 - vertexes) : (int)(sec->lines[1]->v1 - vertexes);
-
- //if (vertexes[vi1].z)
- // I_Error("OSNAP %i", vertexes[vi1].z/FRACUNIT);
- //if (vertexes[vi2].z)
- // I_Error("OSNAP %i", vertexes[vi2].z/FRACUNIT);
- //if (vertexes[vi3].z)
- // I_Error("OSNAP %i", vertexes[vi3].z/FRACUNIT);
-
- //I_Error("%i, %i", mt->z*FRACUNIT, vertexes[vi1].z);
-
- //I_Error("%i, %i, %i", mt->x, mt->y, mt->z);
- //P_SpawnMobj(mt->x*FRACUNIT, mt->y*FRACUNIT, mt->z*FRACUNIT, MT_RING);
-
- // TODO: Make sure not to spawn in the same place 2x! (we need an object in every vertex of the
- // triangle sector to setup the real vertex slopes
- // Check for the vertexes of all sectors
- for(q = 0; q < numvertexes; q++)
- {
- if (vertexes[q].x == mt->x*FRACUNIT && vertexes[q].y == mt->y*FRACUNIT)
- {
- //I_Error("yeah %i", vertexes[q].z);
- P_SpawnMobj(vertexes[q].x, vertexes[q].y, vertexes[q].z, MT_RING);
-#if 0
- if ((mt->y*FRACUNIT == vertexes[vi1].y && mt->x*FRACUNIT == vertexes[vi1].x && mt->z*FRACUNIT == vertexes[vi1].z)
- && !(mt->y*FRACUNIT == vertexes[vi2].y && mt->x*FRACUNIT == vertexes[vi2].x && mt->z*FRACUNIT == vertexes[vi2].z)
- && !(mt->y*FRACUNIT == vertexes[vi3].y && mt->x*FRACUNIT == vertexes[vi3].x && mt->z*FRACUNIT == vertexes[vi3].z))
- P_SpawnMobj(vertexes[vi1].x, vertexes[vi1].y, vertexes[vi1].z, MT_RING);
- else if ((mt->y*FRACUNIT == vertexes[vi2].y && mt->x*FRACUNIT == vertexes[vi2].x && mt->z*FRACUNIT == vertexes[vi2].z)
- && !(mt->y*FRACUNIT == vertexes[vi1].y && mt->x*FRACUNIT == vertexes[vi1].x && mt->z*FRACUNIT == vertexes[vi1].z)
- && !(mt->y*FRACUNIT == vertexes[vi3].y && mt->x*FRACUNIT == vertexes[vi3].x && mt->z*FRACUNIT == vertexes[vi3].z))
- P_SpawnMobj(vertexes[vi2].x, vertexes[vi2].y, vertexes[vi2].z, MT_BOUNCETV);
- else if ((mt->y*FRACUNIT == vertexes[vi3].y && mt->x*FRACUNIT == vertexes[vi3].x && mt->z*FRACUNIT == vertexes[vi3].z)
- && !(mt->y*FRACUNIT == vertexes[vi2].y && mt->x*FRACUNIT == vertexes[vi2].x && mt->z*FRACUNIT == vertexes[vi2].z)
- && !(mt->y*FRACUNIT == vertexes[vi1].y && mt->x*FRACUNIT == vertexes[vi1].x && mt->z*FRACUNIT == vertexes[vi1].z))
- P_SpawnMobj(vertexes[vi3].x, vertexes[vi3].y, vertexes[vi3].z, MT_GFZFLOWER1);
- else
-#endif
- continue;
- }
- }
-
- vt1.x = FIXED_TO_FLOAT(vertexes[vi1].x);
- vt1.y = FIXED_TO_FLOAT(vertexes[vi1].y);
- vt2.x = FIXED_TO_FLOAT(vertexes[vi2].x);
- vt2.y = FIXED_TO_FLOAT(vertexes[vi2].y);
- vt3.x = FIXED_TO_FLOAT(vertexes[vi3].x);
- vt3.y = FIXED_TO_FLOAT(vertexes[vi3].y);
-
- for(j = 0; j < 2; j++)
- {
-
- fixed_t z3;
- //I_Error("Lo hicimos");
-
- vt1.z = mt->z;//FIXED_TO_FLOAT(j==0 ? sec->floorheight : sec->ceilingheight);
- vt2.z = mt->z;//FIXED_TO_FLOAT(j==0? sec->floorheight : sec->ceilingheight);
- z3 = mt->z;//j==0? sec->floorheight : sec->ceilingheight; // Destination height
- vt3.z = FIXED_TO_FLOAT(z3);
-
- if (P_PointOnLineSide(vertexes[vi3].x, vertexes[vi3].y, sec->lines[0]) == 0)
- {
- vec1.x = vt2.x - vt3.x;
- vec1.y = vt2.y - vt3.y;
- vec1.z = vt2.z - vt3.z;
-
- vec2.x = vt1.x - vt3.x;
- vec2.y = vt1.y - vt3.y;
- vec2.z = vt1.z - vt3.z;
- }
- else
- {
- vec1.x = vt1.x - vt3.x;
- vec1.y = vt1.y - vt3.y;
- vec1.z = vt1.z - vt3.z;
-
- vec2.x = vt2.x - vt3.x;
- vec2.y = vt2.y - vt3.y;
- vec2.z = vt2.z - vt3.z;
- }
-
-
- pslope_t *ret = Z_Malloc(sizeof(pslope_t), PU_LEVEL, NULL);
- memset(ret, 0, sizeof(*ret));
-
- {
- M_CrossProduct3f(&ret->normalf, &vec1, &vec2);
-
- // Cross product length
- float len = (float)sqrt(ret->normalf.x * ret->normalf.x +
- ret->normalf.y * ret->normalf.y +
- ret->normalf.z * ret->normalf.z);
-
- if (len == 0)
- {
- // Only happens when all vertices in this sector are on the same line.
- // Let's just ignore this case.
- //CONS_Printf("Slope thing at (%d,%d) lies directly on its target line.\n", (int)(x>>16), (int)(y>>16));
- return;
- }
- // cross/len
- ret->normalf.x /= len;
- ret->normalf.y /= len;
- ret->normalf.z /= len;
-
- // ZDoom cross = ret->normalf
- // Fix backward normals
- if ((ret->normalf.z < 0 && j == 0) || (ret->normalf.z > 0 && j == 1))
- {
- // cross = -cross
- ret->normalf.x = -ret->normalf.x;
- ret->normalf.y = -ret->normalf.x;
- ret->normalf.z = -ret->normalf.x;
- }
- }
-
- secplane_t *srcplane = Z_Calloc(sizeof(*srcplane), PU_LEVEL, NULL);
-
- srcplane->a = FLOAT_TO_FIXED (ret->normalf.x);
- srcplane->b = FLOAT_TO_FIXED (ret->normalf.y);
- srcplane->c = FLOAT_TO_FIXED (ret->normalf.z);
- //srcplane->ic = FixedDiv(FRACUNIT, srcplane->c);
- srcplane->d = -TMulScale16 (srcplane->a, vertexes[vi3].x,
- srcplane->b, vertexes[vi3].y,
- srcplane->c, z3);
-
- if (j == 0)
- {
- sec->f_slope = ret;
- sec->f_slope->secplane = *srcplane;
- }
- else if (j == 1)
- {
- sec->c_slope = ret;
- sec->c_slope->secplane = *srcplane;
- }
- }
- }
- }
-
-
-
-
-
-
-
-
- }
- }
- Z_Free(datastart);
-
-
-
-
-}
-#endif
-
// Reset the dynamic slopes pointer, and read all of the fancy schmancy slopes
void P_ResetDynamicSlopes(void) {
size_t i;
-#if 1 // Rewrite old specials to new ones, and give a console warning
+#ifdef ESLOPE_TYPESHIM // Rewrite old specials to new ones, and give a console warning
boolean warned = false;
#endif
@@ -894,7 +631,7 @@ void P_ResetDynamicSlopes(void) {
{
switch (lines[i].special)
{
-#if 1 // Rewrite old specials to new ones, and give a console warning
+#ifdef ESLOPE_TYPESHIM // Rewrite old specials to new ones, and give a console warning
#define WARNME if (!warned) {warned = true; CONS_Alert(CONS_WARNING, "This level uses old slope specials.\nA conversion will be needed before 2.2's release.\n");}
case 386:
case 387:
@@ -1018,7 +755,11 @@ fixed_t P_GetZAt(pslope_t *slope, fixed_t x, fixed_t y)
// When given a vector, rotates it and aligns it to a slope
void P_QuantizeMomentumToSlope(vector3_t *momentum, pslope_t *slope)
{
- vector3_t axis;
+ vector3_t axis; // Fuck you, C90.
+
+ if (slope->flags & SL_NOPHYSICS)
+ return; // No physics, no quantizing.
+
axis.x = -slope->d.y;
axis.y = slope->d.x;
axis.z = 0;
@@ -1026,24 +767,38 @@ void P_QuantizeMomentumToSlope(vector3_t *momentum, pslope_t *slope)
FV3_Rotate(momentum, &axis, slope->zangle >> ANGLETOFINESHIFT);
}
+//
+// P_ReverseQuantizeMomentumToSlope
+//
+// When given a vector, rotates and aligns it to a flat surface (from being relative to a given slope)
+void P_ReverseQuantizeMomentumToSlope(vector3_t *momentum, pslope_t *slope)
+{
+ slope->zangle = InvAngle(slope->zangle);
+ P_QuantizeMomentumToSlope(momentum, slope);
+ slope->zangle = InvAngle(slope->zangle);
+}
+
//
// P_SlopeLaunch
//
// Handles slope ejection for objects
void P_SlopeLaunch(mobj_t *mo)
{
- // Double the pre-rotation Z, then halve the post-rotation Z. This reduces the
- // vertical launch given from slopes while increasing the horizontal launch
- // given. Good for SRB2's gravity and horizontal speeds.
- vector3_t slopemom;
- slopemom.x = mo->momx;
- slopemom.y = mo->momy;
- slopemom.z = mo->momz*2;
- P_QuantizeMomentumToSlope(&slopemom, mo->standingslope);
+ if (!(mo->standingslope->flags & SL_NOPHYSICS)) // If there's physics, time for launching.
+ {
+ // Double the pre-rotation Z, then halve the post-rotation Z. This reduces the
+ // vertical launch given from slopes while increasing the horizontal launch
+ // given. Good for SRB2's gravity and horizontal speeds.
+ vector3_t slopemom;
+ slopemom.x = mo->momx;
+ slopemom.y = mo->momy;
+ slopemom.z = mo->momz*2;
+ P_QuantizeMomentumToSlope(&slopemom, mo->standingslope);
- mo->momx = slopemom.x;
- mo->momy = slopemom.y;
- mo->momz = slopemom.z/2;
+ mo->momx = slopemom.x;
+ mo->momy = slopemom.y;
+ mo->momz = slopemom.z/2;
+ }
//CONS_Printf("Launched off of slope.\n");
mo->standingslope = NULL;
@@ -1052,17 +807,21 @@ void P_SlopeLaunch(mobj_t *mo)
// Function to help handle landing on slopes
void P_HandleSlopeLanding(mobj_t *thing, pslope_t *slope)
{
- vector3_t mom;
+ vector3_t mom; // Ditto.
+
+ if (slope->flags & SL_NOPHYSICS) { // No physics, no need to make anything complicated.
+ if (P_MobjFlip(thing)*(thing->momz) < 0) { // falling, land on slope
+ thing->momz = -P_MobjFlip(thing);
+ thing->standingslope = slope;
+ }
+ return;
+ }
+
mom.x = thing->momx;
mom.y = thing->momy;
mom.z = thing->momz*2;
- //CONS_Printf("langing on slope\n");
-
- // Reverse quantizing might could use its own function later
- slope->zangle = ANGLE_MAX-slope->zangle;
- P_QuantizeMomentumToSlope(&mom, slope);
- slope->zangle = ANGLE_MAX-slope->zangle;
+ P_ReverseQuantizeMomentumToSlope(&mom, slope);
if (P_MobjFlip(thing)*mom.z < 0) { // falling, land on slope
thing->momx = mom.x;
@@ -1082,6 +841,9 @@ void P_ButteredSlope(mobj_t *mo)
if (!mo->standingslope)
return;
+ if (mo->standingslope->flags & SL_NOPHYSICS)
+ return; // No physics, no butter.
+
if (mo->flags & (MF_NOCLIPHEIGHT|MF_NOGRAVITY))
return; // don't slide down slopes if you can't touch them or you're not affected by gravity
@@ -1106,8 +868,6 @@ void P_ButteredSlope(mobj_t *mo)
mult = FINECOSINE(angle >> ANGLETOFINESHIFT);
}
- //CONS_Printf("%d\n", mult);
-
thrust = FixedMul(thrust, FRACUNIT*2/3 + mult/8);
}
@@ -1115,10 +875,11 @@ void P_ButteredSlope(mobj_t *mo)
thrust = FixedMul(thrust, FRACUNIT+P_AproxDistance(mo->momx, mo->momy)/16);
// This makes it harder to zigzag up steep slopes, as well as allows greater top speed when rolling down
- // Multiply by gravity
- thrust = FixedMul(thrust, gravity); // TODO account for per-sector gravity etc
- // Multiply by scale (gravity strength depends on mobj scale)
- thrust = FixedMul(thrust, mo->scale);
+ // Let's get the gravity strength for the object...
+ thrust = FixedMul(thrust, abs(P_GetMobjGravity(mo)));
+
+ // ... and its friction against the ground for good measure (divided by original friction to keep behaviour for normal slopes the same).
+ thrust = FixedMul(thrust, FixedDiv(mo->friction, ORIG_FRICTION));
P_Thrust(mo, mo->standingslope->xydirection, thrust);
}
diff --git a/src/p_slopes.h b/src/p_slopes.h
index 80921a84..de38f1d9 100644
--- a/src/p_slopes.h
+++ b/src/p_slopes.h
@@ -21,26 +21,6 @@ void P_RunDynamicSlopes(void);
// sectors.
void P_SpawnSlope_Line(int linenum);
-#ifdef SPRINGCLEAN
-// Loads just map objects that make slopes,
-// terrain affecting objects have to be spawned first
-void P_SetSlopesFromVertexHeights(lumpnum_t lumpnum);
-
-typedef enum
-{
- THING_SlopeFloorPointLine = 9500,
- THING_SlopeCeilingPointLine = 9501,
- THING_SetFloorSlope = 9502,
- THING_SetCeilingSlope = 9503,
- THING_CopyFloorPlane = 9510,
- THING_CopyCeilingPlane = 9511,
- THING_VavoomFloor=1500,
- THING_VavoomCeiling=1501,
- THING_VertexFloorZ=1504,
- THING_VertexCeilingZ=1505,
-} slopething_e;
-#endif
-
//
// P_CopySectorSlope
//
@@ -55,6 +35,7 @@ fixed_t P_GetZAt(pslope_t *slope, fixed_t x, fixed_t y);
// Lots of physics-based bullshit
void P_QuantizeMomentumToSlope(vector3_t *momentum, pslope_t *slope);
+void P_ReverseQuantizeMomentumToSlope(vector3_t *momentum, pslope_t *slope);
void P_SlopeLaunch(mobj_t *mo);
void P_HandleSlopeLanding(mobj_t *thing, pslope_t *slope);
void P_ButteredSlope(mobj_t *mo);
diff --git a/src/p_spec.c b/src/p_spec.c
index fbcb8b4f..48c0f58b 100644
--- a/src/p_spec.c
+++ b/src/p_spec.c
@@ -221,8 +221,8 @@ static animdef_t harddefs[] =
static animdef_t *animdefs = NULL;
// A prototype; here instead of p_spec.h, so they're "private"
-void P_ParseANIMDEFSLump(INT32 wadNum, UINT16 lumpnum, INT32 *i);
-void P_ParseAnimationDefintion(SINT8 istexture, INT32 *i);
+void P_ParseANIMDEFSLump(INT32 wadNum, UINT16 lumpnum);
+void P_ParseAnimationDefintion(SINT8 istexture);
/** Sets up texture and flat animations.
*
@@ -232,24 +232,21 @@ void P_ParseAnimationDefintion(SINT8 istexture, INT32 *i);
* Issues an error if any animation cycles are invalid.
*
* \sa P_FindAnimatedFlat, P_SetupLevelFlatAnims
- * \author Steven McGranahan (original), Shadow Hog (had to rewrite it to handle multiple WADs)
+ * \author Steven McGranahan (original), Shadow Hog (had to rewrite it to handle multiple WADs), JTE (had to rewrite it to handle multiple WADs _correctly_)
*/
void P_InitPicAnims(void)
{
// Init animation
- INT32 i; // Position in the animdefs array
INT32 w; // WAD
- UINT8 *wadAnimdefs; // not to be confused with animdefs, the combined total of every ANIMATED lump in every WAD, or ANIMDEFS, the ZDoom lump I intend to implement later
+ UINT8 *animatedLump;
UINT8 *currentPos;
+ size_t i;
+
+ I_Assert(animdefs == NULL);
if (W_CheckNumForName("ANIMATED") != LUMPERROR || W_CheckNumForName("ANIMDEFS") != LUMPERROR)
{
- if (animdefs)
- {
- Z_Free(animdefs);
- animdefs = NULL;
- }
- for (w = 0, i = 0, maxanims = 0; w < numwadfiles; w++)
+ for (w = numwadfiles-1, maxanims = 0; w >= 0; w--)
{
UINT16 animatedLumpNum;
UINT16 animdefsLumpNum;
@@ -258,20 +255,20 @@ void P_InitPicAnims(void)
animatedLumpNum = W_CheckNumForNamePwad("ANIMATED", w, 0);
if (animatedLumpNum != INT16_MAX)
{
- wadAnimdefs = (UINT8 *)W_CacheLumpNumPwad(w, animatedLumpNum, PU_STATIC);
+ animatedLump = (UINT8 *)W_CacheLumpNumPwad(w, animatedLumpNum, PU_STATIC);
// Get the number of animations in the file
- for (currentPos = wadAnimdefs; *currentPos != UINT8_MAX; maxanims++, currentPos+=23);
+ i = maxanims;
+ for (currentPos = animatedLump; *currentPos != UINT8_MAX; maxanims++, currentPos+=23);
// Resize animdefs (or if it hasn't been created, create it)
animdefs = (animdef_t *)Z_Realloc(animdefs, sizeof(animdef_t)*(maxanims + 1), PU_STATIC, NULL);
// Sanity check it
- if (!animdefs) {
+ if (!animdefs)
I_Error("Not enough free memory for ANIMATED data");
- }
// Populate the new array
- for (currentPos = wadAnimdefs; *currentPos != UINT8_MAX; i++, currentPos+=23)
+ for (currentPos = animatedLump; *currentPos != UINT8_MAX; i++, currentPos+=23)
{
M_Memcpy(&(animdefs[i].istexture), currentPos, 1); // istexture, 1 byte
M_Memcpy(animdefs[i].endname, (currentPos + 1), 9); // endname, 9 bytes
@@ -279,15 +276,13 @@ void P_InitPicAnims(void)
M_Memcpy(&(animdefs[i].speed), (currentPos + 19), 4); // speed, 4 bytes
}
- Z_Free(wadAnimdefs);
+ Z_Free(animatedLump);
}
// Now find ANIMDEFS
animdefsLumpNum = W_CheckNumForNamePwad("ANIMDEFS", w, 0);
if (animdefsLumpNum != INT16_MAX)
- {
- P_ParseANIMDEFSLump(w, animdefsLumpNum, &i);
- }
+ P_ParseANIMDEFSLump(w, animdefsLumpNum);
}
// Define the last one
animdefs[maxanims].istexture = -1;
@@ -347,16 +342,20 @@ void P_InitPicAnims(void)
lastanim->istexture = -1;
R_ClearTextureNumCache(false);
+ // Clear animdefs now that we're done with it.
+ // We'll only be using anims from now on.
if (animdefs != harddefs)
- Z_ChangeTag(animdefs, PU_CACHE);
+ Z_Free(animdefs);
+ animdefs = NULL;
}
-void P_ParseANIMDEFSLump(INT32 wadNum, UINT16 lumpnum, INT32 *i)
+void P_ParseANIMDEFSLump(INT32 wadNum, UINT16 lumpnum)
{
char *animdefsLump;
size_t animdefsLumpLength;
char *animdefsText;
char *animdefsToken;
+ char *p;
// Since lumps AREN'T \0-terminated like I'd assumed they should be, I'll
// need to make a space of memory where I can ensure that it will terminate
@@ -376,18 +375,19 @@ void P_ParseANIMDEFSLump(INT32 wadNum, UINT16 lumpnum, INT32 *i)
Z_Free(animdefsLump);
// Now, let's start parsing this thing
- animdefsToken = M_GetToken(animdefsText);
+ p = animdefsText;
+ animdefsToken = M_GetToken(p);
while (animdefsToken != NULL)
{
if (stricmp(animdefsToken, "TEXTURE") == 0)
{
Z_Free(animdefsToken);
- P_ParseAnimationDefintion(1, i);
+ P_ParseAnimationDefintion(1);
}
else if (stricmp(animdefsToken, "FLAT") == 0)
{
Z_Free(animdefsToken);
- P_ParseAnimationDefintion(0, i);
+ P_ParseAnimationDefintion(0);
}
else if (stricmp(animdefsToken, "OSCILLATE") == 0)
{
@@ -398,23 +398,22 @@ void P_ParseANIMDEFSLump(INT32 wadNum, UINT16 lumpnum, INT32 *i)
{
I_Error("Error parsing ANIMDEFS lump: Expected \"TEXTURE\" or \"FLAT\", got \"%s\"",animdefsToken);
}
- animdefsToken = M_GetToken(NULL);
+ // parse next line
+ while (*p != '\0' && *p != '\n') ++p;
+ if (*p == '\n') ++p;
+ animdefsToken = M_GetToken(p);
}
Z_Free(animdefsToken);
Z_Free((void *)animdefsText);
}
-void P_ParseAnimationDefintion(SINT8 istexture, INT32 *i)
+void P_ParseAnimationDefintion(SINT8 istexture)
{
char *animdefsToken;
size_t animdefsTokenLength;
char *endPos;
INT32 animSpeed;
-
- // Increase the size to make room for the new animation definition
- maxanims++;
- animdefs = (animdef_t *)Z_Realloc(animdefs, sizeof(animdef_t)*(maxanims + 1), PU_STATIC, NULL);
- animdefs[*i].istexture = istexture;
+ size_t i;
// Startname
animdefsToken = M_GetToken(NULL);
@@ -448,14 +447,39 @@ void P_ParseAnimationDefintion(SINT8 istexture, INT32 *i)
{
I_Error("Error parsing ANIMDEFS lump: lump name \"%s\" exceeds 8 characters", animdefsToken);
}
- strncpy(animdefs[*i].startname, animdefsToken, 9);
+
+ // Search for existing animdef
+ for (i = 0; i < maxanims; i++)
+ if (stricmp(animdefsToken, animdefs[i].startname) == 0)
+ {
+ //CONS_Alert(CONS_NOTICE, "Duplicate animation: %s\n", animdefsToken);
+
+ // If we weren't parsing in reverse order, we would `break` here and parse the new data into the existing slot we found.
+ // Instead, we're just going to skip parsing the rest of this line entirely.
+ Z_Free(animdefsToken);
+ return;
+ }
+
+ // Not found
+ if (i == maxanims)
+ {
+ // Increase the size to make room for the new animation definition
+ maxanims++;
+ animdefs = (animdef_t *)Z_Realloc(animdefs, sizeof(animdef_t)*(maxanims + 1), PU_STATIC, NULL);
+ strncpy(animdefs[i].startname, animdefsToken, 9);
+ }
+
+ // animdefs[i].startname is now set to animdefsToken either way.
Z_Free(animdefsToken);
+ // set texture type
+ animdefs[i].istexture = istexture;
+
// "RANGE"
animdefsToken = M_GetToken(NULL);
if (animdefsToken == NULL)
{
- I_Error("Error parsing ANIMDEFS lump: Unexpected end of file where \"RANGE\" after \"%s\"'s startname should be", animdefs[*i].startname);
+ I_Error("Error parsing ANIMDEFS lump: Unexpected end of file where \"RANGE\" after \"%s\"'s startname should be", animdefs[i].startname);
}
if (stricmp(animdefsToken, "ALLOWDECALS") == 0)
{
@@ -470,7 +494,7 @@ void P_ParseAnimationDefintion(SINT8 istexture, INT32 *i)
}
if (stricmp(animdefsToken, "RANGE") != 0)
{
- I_Error("Error parsing ANIMDEFS lump: Expected \"RANGE\" after \"%s\"'s startname, got \"%s\"", animdefs[*i].startname, animdefsToken);
+ I_Error("Error parsing ANIMDEFS lump: Expected \"RANGE\" after \"%s\"'s startname, got \"%s\"", animdefs[i].startname, animdefsToken);
}
Z_Free(animdefsToken);
@@ -478,21 +502,21 @@ void P_ParseAnimationDefintion(SINT8 istexture, INT32 *i)
animdefsToken = M_GetToken(NULL);
if (animdefsToken == NULL)
{
- I_Error("Error parsing ANIMDEFS lump: Unexpected end of file where \"%s\"'s end texture/flat name should be", animdefs[*i].startname);
+ I_Error("Error parsing ANIMDEFS lump: Unexpected end of file where \"%s\"'s end texture/flat name should be", animdefs[i].startname);
}
animdefsTokenLength = strlen(animdefsToken);
if (animdefsTokenLength>8)
{
I_Error("Error parsing ANIMDEFS lump: lump name \"%s\" exceeds 8 characters", animdefsToken);
}
- strncpy(animdefs[*i].endname, animdefsToken, 9);
+ strncpy(animdefs[i].endname, animdefsToken, 9);
Z_Free(animdefsToken);
// "TICS"
animdefsToken = M_GetToken(NULL);
if (animdefsToken == NULL)
{
- I_Error("Error parsing ANIMDEFS lump: Unexpected end of file where \"%s\"'s \"TICS\" should be", animdefs[*i].startname);
+ I_Error("Error parsing ANIMDEFS lump: Unexpected end of file where \"%s\"'s \"TICS\" should be", animdefs[i].startname);
}
if (stricmp(animdefsToken, "RAND") == 0)
{
@@ -501,7 +525,7 @@ void P_ParseAnimationDefintion(SINT8 istexture, INT32 *i)
}
if (stricmp(animdefsToken, "TICS") != 0)
{
- I_Error("Error parsing ANIMDEFS lump: Expected \"TICS\" in animation definition for \"%s\", got \"%s\"", animdefs[*i].startname, animdefsToken);
+ I_Error("Error parsing ANIMDEFS lump: Expected \"TICS\" in animation definition for \"%s\", got \"%s\"", animdefs[i].startname, animdefsToken);
}
Z_Free(animdefsToken);
@@ -509,7 +533,7 @@ void P_ParseAnimationDefintion(SINT8 istexture, INT32 *i)
animdefsToken = M_GetToken(NULL);
if (animdefsToken == NULL)
{
- I_Error("Error parsing TEXTURES lump: Unexpected end of file where \"%s\"'s animation speed should be", animdefs[*i].startname);
+ I_Error("Error parsing ANIMDEFS lump: Unexpected end of file where \"%s\"'s animation speed should be", animdefs[i].startname);
}
endPos = NULL;
#ifndef AVOID_ERRNO
@@ -523,13 +547,10 @@ void P_ParseAnimationDefintion(SINT8 istexture, INT32 *i)
#endif
|| animSpeed < 0) // Number is not positive
{
- I_Error("Error parsing TEXTURES lump: Expected a positive integer for \"%s\"'s animation speed, got \"%s\"", animdefs[*i].startname, animdefsToken);
+ I_Error("Error parsing ANIMDEFS lump: Expected a positive integer for \"%s\"'s animation speed, got \"%s\"", animdefs[i].startname, animdefsToken);
}
- animdefs[*i].speed = animSpeed;
+ animdefs[i].speed = animSpeed;
Z_Free(animdefsToken);
-
- // Increment i before we go, so this doesn't cause issues later
- (*i)++;
}
@@ -1188,7 +1209,12 @@ INT32 P_FindSpecialLineFromTag(INT16 special, INT16 tag, INT32 start)
{
start++;
- while (lines[start].special != special)
+ // This redundant check stops the compiler from complaining about function expansion
+ // elsewhere for some reason and everything is awful
+ if (start >= (INT32)numlines)
+ return -1;
+
+ while (start < (INT32)numlines && lines[start].special != special)
start++;
if (start >= (INT32)numlines)
@@ -1493,6 +1519,8 @@ static inline void P_InitTagLists(void)
size_t j = (unsigned)sectors[i].tag % numsectors;
sectors[i].nexttag = sectors[j].firsttag;
sectors[j].firsttag = (INT32)i;
+ sectors[i].spawn_nexttag = sectors[i].nexttag;
+ sectors[j].spawn_firsttag = sectors[j].firsttag;
}
for (i = numlines - 1; i != (size_t)-1; i--)
@@ -1642,7 +1670,7 @@ boolean P_RunTriggerLinedef(line_t *triggerline, mobj_t *actor, sector_t *caller
mo = node->m_thing;
if (mo->flags & MF_PUSHABLE)
numpush++;
- node = node->m_snext;
+ node = node->m_thinglist_next;
}
if (triggerline->flags & ML_NOCLIMB) // Need at least or more
@@ -2434,10 +2462,10 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec)
if (rover->master->frontsector->tag != line->tag)
continue;
- if (mo->z > *rover->topheight)
+ if (mo->z > P_GetSpecialTopZ(mo, sectors + rover->secnum, mo->subsector->sector))
continue;
- if (mo->z + mo->height < *rover->bottomheight)
+ if (mo->z + mo->height < P_GetSpecialBottomZ(mo, sectors + rover->secnum, mo->subsector->sector))
continue;
foundit = true;
@@ -3011,7 +3039,10 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec)
case 443: // Calls a named Lua function
#ifdef HAVE_BLUA
- LUAh_LinedefExecute(line, mo, callsec);
+ if (line->text)
+ LUAh_LinedefExecute(line, mo, callsec);
+ else
+ CONS_Alert(CONS_WARNING, "Linedef %s is missing the hook name of the Lua function to call! (This should be given in the front texture fields)\n", sizeu1(line-lines));
#else
CONS_Alert(CONS_ERROR, "The map is trying to run a Lua script, but this exe was not compiled with Lua support!\n");
#endif
@@ -3144,7 +3175,7 @@ void P_SetupSignExit(player_t *player)
thinker_t *think;
INT32 numfound = 0;
- for (; node; node = node->m_snext)
+ for (; node; node = node->m_thinglist_next)
{
thing = node->m_thing;
if (thing->type != MT_SIGN)
@@ -3227,8 +3258,8 @@ boolean P_IsFlagAtBase(mobjtype_t flag)
if (GETSECSPECIAL(rover->master->frontsector->special, 4) != specialnum)
continue;
- if (mo->z <= *rover->topheight
- && mo->z >= *rover->bottomheight)
+ if (mo->z <= P_GetSpecialTopZ(mo, sectors + rover->secnum, mo->subsector->sector)
+ && mo->z >= P_GetSpecialBottomZ(mo, sectors + rover->secnum, mo->subsector->sector))
return true;
}
}
@@ -3262,12 +3293,17 @@ sector_t *P_PlayerTouchingSectorSpecial(player_t *player, INT32 section, INT32 n
// Hmm.. maybe there's a FOF that has it...
for (rover = player->mo->subsector->sector->ffloors; rover; rover = rover->next)
{
+ fixed_t topheight, bottomheight;
+
if (GETSECSPECIAL(rover->master->frontsector->special, section) != number)
continue;
if (!(rover->flags & FF_EXISTS))
continue;
+ topheight = P_GetSpecialTopZ(player->mo, sectors + rover->secnum, player->mo->subsector->sector);
+ bottomheight = P_GetSpecialBottomZ(player->mo, sectors + rover->secnum, player->mo->subsector->sector);
+
// Check the 3D floor's type...
if (rover->flags & FF_BLOCKPLAYER)
{
@@ -3275,27 +3311,27 @@ sector_t *P_PlayerTouchingSectorSpecial(player_t *player, INT32 section, INT32 n
if ((rover->master->frontsector->flags & SF_FLIPSPECIAL_FLOOR)
&& !(rover->master->frontsector->flags & SF_FLIPSPECIAL_CEILING))
{
- if ((player->mo->eflags & MFE_VERTICALFLIP) || player->mo->z != *rover->topheight)
+ if ((player->mo->eflags & MFE_VERTICALFLIP) || player->mo->z != topheight)
continue;
}
else if ((rover->master->frontsector->flags & SF_FLIPSPECIAL_CEILING)
&& !(rover->master->frontsector->flags & SF_FLIPSPECIAL_FLOOR))
{
if (!(player->mo->eflags & MFE_VERTICALFLIP)
- || player->mo->z + player->mo->height != *rover->bottomheight)
+ || player->mo->z + player->mo->height != bottomheight)
continue;
}
else if (rover->master->frontsector->flags & SF_FLIPSPECIAL_BOTH)
{
- if (!((player->mo->eflags & MFE_VERTICALFLIP && player->mo->z + player->mo->height == *rover->bottomheight)
- || (!(player->mo->eflags & MFE_VERTICALFLIP) && player->mo->z == *rover->topheight)))
+ if (!((player->mo->eflags & MFE_VERTICALFLIP && player->mo->z + player->mo->height == bottomheight)
+ || (!(player->mo->eflags & MFE_VERTICALFLIP) && player->mo->z == topheight)))
continue;
}
}
else
{
// Water and DEATH FOG!!! heh
- if (player->mo->z > *rover->topheight || (player->mo->z + player->mo->height) < *rover->bottomheight)
+ if (player->mo->z > topheight || (player->mo->z + player->mo->height) < bottomheight)
continue;
}
@@ -3303,7 +3339,7 @@ sector_t *P_PlayerTouchingSectorSpecial(player_t *player, INT32 section, INT32 n
return rover->master->frontsector;
}
- for (node = player->mo->touching_sectorlist; node; node = node->m_snext)
+ for (node = player->mo->touching_sectorlist; node; node = node->m_sectorlist_next)
{
if (GETSECSPECIAL(node->m_sector->special, section) == number)
{
@@ -3317,12 +3353,17 @@ sector_t *P_PlayerTouchingSectorSpecial(player_t *player, INT32 section, INT32 n
// Hmm.. maybe there's a FOF that has it...
for (rover = node->m_sector->ffloors; rover; rover = rover->next)
{
+ fixed_t topheight, bottomheight;
+
if (GETSECSPECIAL(rover->master->frontsector->special, section) != number)
continue;
if (!(rover->flags & FF_EXISTS))
continue;
+ topheight = P_GetSpecialTopZ(player->mo, sectors + rover->secnum, player->mo->subsector->sector);
+ bottomheight = P_GetSpecialBottomZ(player->mo, sectors + rover->secnum, player->mo->subsector->sector);
+
// Check the 3D floor's type...
if (rover->flags & FF_BLOCKPLAYER)
{
@@ -3330,27 +3371,27 @@ sector_t *P_PlayerTouchingSectorSpecial(player_t *player, INT32 section, INT32 n
if ((rover->master->frontsector->flags & SF_FLIPSPECIAL_FLOOR)
&& !(rover->master->frontsector->flags & SF_FLIPSPECIAL_CEILING))
{
- if ((player->mo->eflags & MFE_VERTICALFLIP) || player->mo->z != *rover->topheight)
+ if ((player->mo->eflags & MFE_VERTICALFLIP) || player->mo->z != topheight)
continue;
}
else if ((rover->master->frontsector->flags & SF_FLIPSPECIAL_CEILING)
&& !(rover->master->frontsector->flags & SF_FLIPSPECIAL_FLOOR))
{
if (!(player->mo->eflags & MFE_VERTICALFLIP)
- || player->mo->z + player->mo->height != *rover->bottomheight)
+ || player->mo->z + player->mo->height != bottomheight)
continue;
}
else if (rover->master->frontsector->flags & SF_FLIPSPECIAL_BOTH)
{
- if (!((player->mo->eflags & MFE_VERTICALFLIP && player->mo->z + player->mo->height == *rover->bottomheight)
- || (!(player->mo->eflags & MFE_VERTICALFLIP) && player->mo->z == *rover->topheight)))
+ if (!((player->mo->eflags & MFE_VERTICALFLIP && player->mo->z + player->mo->height == bottomheight)
+ || (!(player->mo->eflags & MFE_VERTICALFLIP) && player->mo->z == topheight)))
continue;
}
}
else
{
// Water and DEATH FOG!!! heh
- if (player->mo->z > *rover->topheight || (player->mo->z + player->mo->height) < *rover->bottomheight)
+ if (player->mo->z > topheight || (player->mo->z + player->mo->height) < bottomheight)
continue;
}
@@ -4335,12 +4376,17 @@ sector_t *P_ThingOnSpecial3DFloor(mobj_t *mo)
for (rover = sector->ffloors; rover; rover = rover->next)
{
+ fixed_t topheight, bottomheight;
+
if (!rover->master->frontsector->special)
continue;
if (!(rover->flags & FF_EXISTS))
continue;
+ topheight = P_GetSpecialTopZ(mo, sectors + rover->secnum, sector);
+ bottomheight = P_GetSpecialBottomZ(mo, sectors + rover->secnum, sector);
+
// Check the 3D floor's type...
if (((rover->flags & FF_BLOCKPLAYER) && mo->player)
|| ((rover->flags & FF_BLOCKOTHERS) && !mo->player))
@@ -4349,27 +4395,27 @@ sector_t *P_ThingOnSpecial3DFloor(mobj_t *mo)
if ((rover->master->frontsector->flags & SF_FLIPSPECIAL_FLOOR)
&& !(rover->master->frontsector->flags & SF_FLIPSPECIAL_CEILING))
{
- if ((mo->eflags & MFE_VERTICALFLIP) || mo->z != *rover->topheight)
+ if ((mo->eflags & MFE_VERTICALFLIP) || mo->z != topheight)
continue;
}
else if ((rover->master->frontsector->flags & SF_FLIPSPECIAL_CEILING)
&& !(rover->master->frontsector->flags & SF_FLIPSPECIAL_FLOOR))
{
if (!(mo->eflags & MFE_VERTICALFLIP)
- || mo->z + mo->height != *rover->bottomheight)
+ || mo->z + mo->height != bottomheight)
continue;
}
else if (rover->master->frontsector->flags & SF_FLIPSPECIAL_BOTH)
{
- if (!((mo->eflags & MFE_VERTICALFLIP && mo->z + mo->height == *rover->bottomheight)
- || (!(mo->eflags & MFE_VERTICALFLIP) && mo->z == *rover->topheight)))
+ if (!((mo->eflags & MFE_VERTICALFLIP && mo->z + mo->height == bottomheight)
+ || (!(mo->eflags & MFE_VERTICALFLIP) && mo->z == topheight)))
continue;
}
}
else
{
// Water and intangible FOFs
- if (mo->z > *rover->topheight || (mo->z + mo->height) < *rover->bottomheight)
+ if (mo->z > topheight || (mo->z + mo->height) < bottomheight)
continue;
}
@@ -4391,12 +4437,17 @@ static void P_PlayerOnSpecial3DFloor(player_t *player, sector_t *sector)
for (rover = sector->ffloors; rover; rover = rover->next)
{
+ fixed_t topheight, bottomheight;
+
if (!rover->master->frontsector->special)
continue;
if (!(rover->flags & FF_EXISTS))
continue;
+ topheight = P_GetSpecialTopZ(player->mo, sectors + rover->secnum, sector);
+ bottomheight = P_GetSpecialBottomZ(player->mo, sectors + rover->secnum, sector);
+
// Check the 3D floor's type...
if (rover->flags & FF_BLOCKPLAYER)
{
@@ -4404,27 +4455,27 @@ static void P_PlayerOnSpecial3DFloor(player_t *player, sector_t *sector)
if ((rover->master->frontsector->flags & SF_FLIPSPECIAL_FLOOR)
&& !(rover->master->frontsector->flags & SF_FLIPSPECIAL_CEILING))
{
- if ((player->mo->eflags & MFE_VERTICALFLIP) || player->mo->z != P_GetSpecialTopZ(player->mo, sectors + rover->secnum, sector))
+ if ((player->mo->eflags & MFE_VERTICALFLIP) || player->mo->z != topheight)
continue;
}
else if ((rover->master->frontsector->flags & SF_FLIPSPECIAL_CEILING)
&& !(rover->master->frontsector->flags & SF_FLIPSPECIAL_FLOOR))
{
if (!(player->mo->eflags & MFE_VERTICALFLIP)
- || player->mo->z + player->mo->height != P_GetSpecialBottomZ(player->mo, sectors + rover->secnum, sector))
+ || player->mo->z + player->mo->height != bottomheight)
continue;
}
else if (rover->master->frontsector->flags & SF_FLIPSPECIAL_BOTH)
{
- if (!((player->mo->eflags & MFE_VERTICALFLIP && player->mo->z + player->mo->height == P_GetSpecialBottomZ(player->mo, sectors + rover->secnum, sector))
- || (!(player->mo->eflags & MFE_VERTICALFLIP) && player->mo->z == P_GetSpecialTopZ(player->mo, sectors + rover->secnum, sector))))
+ if (!((player->mo->eflags & MFE_VERTICALFLIP && player->mo->z + player->mo->height == bottomheight)
+ || (!(player->mo->eflags & MFE_VERTICALFLIP) && player->mo->z == topheight)))
continue;
}
}
else
{
// Water and DEATH FOG!!! heh
- if (player->mo->z > P_GetSpecialTopZ(player->mo, sectors + rover->secnum, sector) || (player->mo->z + player->mo->height) < P_GetSpecialBottomZ(player->mo, sectors + rover->secnum, sector))
+ if (player->mo->z > topheight || (player->mo->z + player->mo->height) < bottomheight)
continue;
}
@@ -4637,7 +4688,7 @@ void P_PlayerInSpecialSector(player_t *player)
P_RunSpecialSectorCheck(player, sector);
// Iterate through touching_sectorlist
- for (node = player->mo->touching_sectorlist; node; node = node->m_snext)
+ for (node = player->mo->touching_sectorlist; node; node = node->m_sectorlist_next)
{
sector = node->m_sector;
@@ -5276,11 +5327,19 @@ void T_LaserFlash(laserthink_t *flash)
sourcesec = ffloor->master->frontsector; // Less to type!
+#ifdef ESLOPE
+ top = (*ffloor->t_slope) ? P_GetZAt(*ffloor->t_slope, sector->soundorg.x, sector->soundorg.y)
+ : *ffloor->topheight;
+ bottom = (*ffloor->b_slope) ? P_GetZAt(*ffloor->b_slope, sector->soundorg.x, sector->soundorg.y)
+ : *ffloor->bottomheight;
+ sector->soundorg.z = (top + bottom)/2;
+#else
sector->soundorg.z = (*ffloor->topheight + *ffloor->bottomheight)/2;
+#endif
S_StartSound(§or->soundorg, sfx_laser);
// Seek out objects to DESTROY! MUAHAHHAHAHAA!!!*cough*
- for (node = sector->touching_thinglist; node && node->m_thing; node = node->m_snext)
+ for (node = sector->touching_thinglist; node && node->m_thing; node = node->m_thinglist_next)
{
thing = node->m_thing;
@@ -5288,6 +5347,10 @@ void T_LaserFlash(laserthink_t *flash)
&& thing->flags & MF_BOSS)
continue; // Don't hurt bosses
+ // Don't endlessly kill egg guard shields (or anything else for that matter)
+ if (thing->health <= 0)
+ continue;
+
top = P_GetSpecialTopZ(thing, sourcesec, sector);
bottom = P_GetSpecialBottomZ(thing, sourcesec, sector);
@@ -6551,7 +6614,7 @@ void T_Scroll(scroll_t *s)
sector_t *psec;
psec = sectors + sect;
- for (node = psec->touching_thinglist; node; node = node->m_snext)
+ for (node = psec->touching_thinglist; node; node = node->m_thinglist_next)
{
thing = node->m_thing;
@@ -6573,7 +6636,7 @@ void T_Scroll(scroll_t *s)
if (!is3dblock)
{
- for (node = sec->touching_thinglist; node; node = node->m_snext)
+ for (node = sec->touching_thinglist; node; node = node->m_thinglist_next)
{
thing = node->m_thing;
@@ -6614,7 +6677,7 @@ void T_Scroll(scroll_t *s)
sector_t *psec;
psec = sectors + sect;
- for (node = psec->touching_thinglist; node; node = node->m_snext)
+ for (node = psec->touching_thinglist; node; node = node->m_thinglist_next)
{
thing = node->m_thing;
@@ -6636,7 +6699,7 @@ void T_Scroll(scroll_t *s)
if (!is3dblock)
{
- for (node = sec->touching_thinglist; node; node = node->m_snext)
+ for (node = sec->touching_thinglist; node; node = node->m_thinglist_next)
{
thing = node->m_thing;
@@ -6875,6 +6938,11 @@ void T_Disappear(disappear_t *d)
if (!(lines[d->sourceline].flags & ML_NOCLIMB))
{
+#ifdef ESLOPE
+ if (*rover->t_slope)
+ sectors[s].soundorg.z = P_GetZAt(*rover->t_slope, sectors[s].soundorg.x, sectors[s].soundorg.y);
+ else
+#endif
sectors[s].soundorg.z = *rover->topheight;
S_StartSound(§ors[s].soundorg, sfx_appear);
}
@@ -6981,7 +7049,7 @@ void T_Friction(friction_t *f)
{
if (thing->floorz != P_GetSpecialTopZ(thing, referrer, sec))
{
- node = node->m_snext;
+ node = node->m_thinglist_next;
continue;
}
@@ -6999,7 +7067,7 @@ void T_Friction(friction_t *f)
thing->movefactor = f->movefactor;
}
}
- node = node->m_snext;
+ node = node->m_thinglist_next;
}
}
@@ -7339,7 +7407,7 @@ void T_Pusher(pusher_t *p)
// constant pushers p_wind and p_current
node = sec->touching_thinglist; // things touching this sector
- for (; node; node = node->m_snext)
+ for (; node; node = node->m_thinglist_next)
{
thing = node->m_thing;
if (thing->flags & (MF_NOGRAVITY | MF_NOCLIP)
@@ -7390,7 +7458,7 @@ void T_Pusher(pusher_t *p)
}
else
{
- if (top < thing->z || referrer->floorheight > (thing->z + (thing->height >> 1)))
+ if (top < thing->z || bottom > (thing->z + (thing->height >> 1)))
continue;
if (thing->z + thing->height > top)
touching = true;
diff --git a/src/p_user.c b/src/p_user.c
index 0ee5a36b..cb523585 100644
--- a/src/p_user.c
+++ b/src/p_user.c
@@ -1684,7 +1684,7 @@ static void P_CheckBustableBlocks(player_t *player)
player->mo->y += player->mo->momy;
P_SetThingPosition(player->mo);
- for (node = player->mo->touching_sectorlist; node; node = node->m_snext)
+ for (node = player->mo->touching_sectorlist; node; node = node->m_sectorlist_next)
{
if (!node->m_sector)
break;
@@ -1692,6 +1692,7 @@ static void P_CheckBustableBlocks(player_t *player)
if (node->m_sector->ffloors)
{
ffloor_t *rover;
+ fixed_t topheight, bottomheight;
for (rover = node->m_sector->ffloors; rover; rover = rover->next)
{
@@ -1717,42 +1718,45 @@ static void P_CheckBustableBlocks(player_t *player)
if (!(rover->flags & FF_SHATTER) && (rover->flags & FF_ONLYKNUX) && !(player->charability == CA_GLIDEANDCLIMB))
continue;
+ topheight = P_GetFOFTopZ(player->mo, node->m_sector, rover, player->mo->x, player->mo->y, NULL);
+ bottomheight = P_GetFOFBottomZ(player->mo, node->m_sector, rover, player->mo->x, player->mo->y, NULL);
+
// Height checks
if (rover->flags & FF_SHATTERBOTTOM)
{
- if (player->mo->z+player->mo->momz + player->mo->height < *rover->bottomheight)
+ if (player->mo->z+player->mo->momz + player->mo->height < bottomheight)
continue;
- if (player->mo->z+player->mo->height > *rover->bottomheight)
+ if (player->mo->z+player->mo->height > bottomheight)
continue;
}
else if (rover->flags & FF_SPINBUST)
{
- if (player->mo->z+player->mo->momz > *rover->topheight)
+ if (player->mo->z+player->mo->momz > topheight)
continue;
- if (player->mo->z + player->mo->height < *rover->bottomheight)
+ if (player->mo->z + player->mo->height < bottomheight)
continue;
}
else if (rover->flags & FF_SHATTER)
{
- if (player->mo->z + player->mo->momz > *rover->topheight)
+ if (player->mo->z + player->mo->momz > topheight)
continue;
- if (player->mo->z+player->mo->momz + player->mo->height < *rover->bottomheight)
+ if (player->mo->z+player->mo->momz + player->mo->height < bottomheight)
continue;
}
else
{
- if (player->mo->z >= *rover->topheight)
+ if (player->mo->z >= topheight)
continue;
- if (player->mo->z + player->mo->height < *rover->bottomheight)
+ if (player->mo->z + player->mo->height < bottomheight)
continue;
}
// Impede the player's fall a bit
- if (((rover->flags & FF_SPINBUST) || (rover->flags & FF_SHATTER)) && player->mo->z >= *rover->topheight)
+ if (((rover->flags & FF_SPINBUST) || (rover->flags & FF_SHATTER)) && player->mo->z >= topheight)
player->mo->momz >>= 1;
else if (rover->flags & FF_SHATTER)
{
@@ -1801,7 +1805,7 @@ static void P_CheckBouncySectors(player_t *player)
player->mo->z += player->mo->momz;
P_SetThingPosition(player->mo);
- for (node = player->mo->touching_sectorlist; node; node = node->m_snext)
+ for (node = player->mo->touching_sectorlist; node; node = node->m_sectorlist_next)
{
if (!node->m_sector)
break;
@@ -1851,12 +1855,8 @@ static void P_CheckBouncySectors(player_t *player)
momentum.y = player->mo->momy;
momentum.z = player->mo->momz*2;
- if (slope) {
- // Reverse quantizing might could use its own function later
- slope->zangle = ANGLE_MAX-slope->zangle;
- P_QuantizeMomentumToSlope(&momentum, slope);
- slope->zangle = ANGLE_MAX-slope->zangle;
- }
+ if (slope)
+ P_ReverseQuantizeMomentumToSlope(&momentum, slope);
newmom = momentum.z = -FixedMul(momentum.z,linedist)/2;
#else
@@ -2284,309 +2284,310 @@ static void P_DoClimbing(player_t *player)
platx = P_ReturnThrustX(player->mo, player->mo->angle, player->mo->radius + FixedMul(8*FRACUNIT, player->mo->scale));
platy = P_ReturnThrustY(player->mo, player->mo->angle, player->mo->radius + FixedMul(8*FRACUNIT, player->mo->scale));
- glidesector = R_PointInSubsector(player->mo->x + platx, player->mo->y + platy);
+ glidesector = R_IsPointInSubsector(player->mo->x + platx, player->mo->y + platy);
- if (glidesector->sector != player->mo->subsector->sector)
+ if (!glidesector || glidesector->sector != player->mo->subsector->sector)
{
- boolean floorclimb;
- boolean thrust;
- boolean boostup;
- boolean skyclimber;
+ boolean floorclimb = false;
+ boolean thrust = false;
+ boolean boostup = false;
+ boolean skyclimber = false;
fixed_t floorheight, ceilingheight; // ESLOPE
- thrust = false;
- floorclimb = false;
- boostup = false;
- skyclimber = false;
-#ifdef ESLOPE
- floorheight = glidesector->sector->f_slope ? P_GetZAt(glidesector->sector->f_slope, player->mo->x, player->mo->y)
- : glidesector->sector->floorheight;
- ceilingheight = glidesector->sector->c_slope ? P_GetZAt(glidesector->sector->c_slope, player->mo->x, player->mo->y)
- : glidesector->sector->ceilingheight;
-#else
- floorheight = glidesector->sector->floorheight;
- ceilingheight = glidesector->sector->ceilingheight;
-#endif
-
- if (glidesector->sector->ffloors)
- {
- ffloor_t *rover;
- fixed_t topheight, bottomheight; // ESLOPE
-
- for (rover = glidesector->sector->ffloors; rover; rover = rover->next)
- {
- if (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_BLOCKPLAYER) || (rover->flags & FF_BUSTUP))
- continue;
-
- floorclimb = true;
-
-#ifdef ESLOPE
- bottomheight = *rover->b_slope ? P_GetZAt(*rover->b_slope, player->mo->x, player->mo->y) : *rover->bottomheight;
- topheight = *rover->t_slope ? P_GetZAt(*rover->t_slope, player->mo->x, player->mo->y) : *rover->topheight;
-#else
- bottomheight = *rover->bottomheight;
- topheight = *rover->topheight;
-#endif
-
- // Only supports rovers that are moving like an 'elevator', not just the top or bottom.
- if (rover->master->frontsector->floorspeed && rover->master->frontsector->ceilspeed == 42)
- {
- if ((!(player->mo->eflags & MFE_VERTICALFLIP) && (bottomheight < player->mo->z+player->mo->height)
- && (topheight >= player->mo->z + FixedMul(16*FRACUNIT, player->mo->scale)))
- || ((player->mo->eflags & MFE_VERTICALFLIP) && (topheight > player->mo->z)
- && (bottomheight <= player->mo->z + player->mo->height - FixedMul(16*FRACUNIT, player->mo->scale))))
- {
- if (cmd->forwardmove != 0)
- player->mo->momz += rover->master->frontsector->floorspeed;
- else
- {
- player->mo->momz = rover->master->frontsector->floorspeed;
- climb = false;
- }
- }
- }
-
- // Gravity is flipped, so the comments are, too.
- if (player->mo->eflags & MFE_VERTICALFLIP)
- {
- // Trying to climb down past the bottom of the FOF
- if ((topheight >= player->mo->z + player->mo->height) && ((player->mo->z + player->mo->height + player->mo->momz) >= topheight))
- {
- fixed_t bottomheight2;
- ffloor_t *roverbelow;
- boolean foundfof = false;
- floorclimb = true;
- boostup = false;
-
- // Is there a FOF directly below this one that we can move onto?
- for (roverbelow = glidesector->sector->ffloors; roverbelow; roverbelow = roverbelow->next)
- {
- if (!(roverbelow->flags & FF_EXISTS) || !(roverbelow->flags & FF_BLOCKPLAYER) || (roverbelow->flags & FF_BUSTUP))
- continue;
-
- if (roverbelow == rover)
- continue;
-
-#ifdef ESLOPE
- bottomheight2 = *roverbelow->b_slope ? P_GetZAt(*roverbelow->b_slope, player->mo->x, player->mo->y) : *roverbelow->bottomheight;
-#else
- bottomheight2 = *roverbelow->bottomheight;
-#endif
-
- if (bottomheight2 < topheight + FixedMul(16*FRACUNIT, player->mo->scale))
- foundfof = true;
- }
-
- if (!foundfof)
- player->mo->momz = 0;
- }
-
- // Below the FOF
- if (topheight <= player->mo->z)
- {
- floorclimb = false;
- boostup = false;
- thrust = false;
- }
-
- // Above the FOF
- if (bottomheight > player->mo->z + player->mo->height - FixedMul(16*FRACUNIT, player->mo->scale))
- {
- floorclimb = false;
- thrust = true;
- boostup = true;
- }
- }
- else
- {
- // Trying to climb down past the bottom of a FOF
- if ((bottomheight <= player->mo->z) && ((player->mo->z + player->mo->momz) <= bottomheight))
- {
- fixed_t topheight2;
- ffloor_t *roverbelow;
- boolean foundfof = false;
- floorclimb = true;
- boostup = false;
-
- // Is there a FOF directly below this one that we can move onto?
- for (roverbelow = glidesector->sector->ffloors; roverbelow; roverbelow = roverbelow->next)
- {
- if (!(roverbelow->flags & FF_EXISTS) || !(roverbelow->flags & FF_BLOCKPLAYER) || (roverbelow->flags & FF_BUSTUP))
- continue;
-
- if (roverbelow == rover)
- continue;
-
-#ifdef ESLOPE
- topheight2 = *roverbelow->t_slope ? P_GetZAt(*roverbelow->t_slope, player->mo->x, player->mo->y) : *roverbelow->topheight;
-#else
- topheight2 = *roverbelow->topheight;
-#endif
-
- if (topheight2 > bottomheight - FixedMul(16*FRACUNIT, player->mo->scale))
- foundfof = true;
- }
-
- if (!foundfof)
- player->mo->momz = 0;
- }
-
- // Below the FOF
- if (bottomheight >= player->mo->z + player->mo->height)
- {
- floorclimb = false;
- boostup = false;
- thrust = false;
- }
-
- // Above the FOF
- if (topheight < player->mo->z + FixedMul(16*FRACUNIT, player->mo->scale))
- {
- floorclimb = false;
- thrust = true;
- boostup = true;
- }
- }
-
- if (floorclimb)
- {
- if (rover->flags & FF_CRUMBLE && !(netgame && player->spectator))
- EV_StartCrumble(rover->master->frontsector, rover, (rover->flags & FF_FLOATBOB), player, rover->alpha, !(rover->flags & FF_NORETURN));
- break;
- }
- }
- }
-
- // Gravity is flipped, so are comments.
- if (player->mo->eflags & MFE_VERTICALFLIP)
- {
- // Trying to climb down past the upper texture area
- if ((floorheight >= player->mo->z + player->mo->height) && ((player->mo->z + player->mo->height + player->mo->momz) >= floorheight))
- {
- boolean foundfof = false;
- floorclimb = true;
-
- // Is there a FOF directly below that we can move onto?
- if (glidesector->sector->ffloors)
- {
- fixed_t bottomheight;
- ffloor_t *rover;
- for (rover = glidesector->sector->ffloors; rover; rover = rover->next)
- {
- if (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_BLOCKPLAYER) || (rover->flags & FF_BUSTUP))
- continue;
-
-#ifdef ESLOPE
- bottomheight = *rover->b_slope ? P_GetZAt(*rover->b_slope, player->mo->x, player->mo->y) : *rover->bottomheight;
-#else
- bottomheight = *rover->bottomheight;
-#endif
-
- if (bottomheight < floorheight + FixedMul(16*FRACUNIT, player->mo->scale))
- {
- foundfof = true;
- break;
- }
- }
- }
-
- if (!foundfof)
- player->mo->momz = 0;
- }
-
- // Reached the top of the lower texture area
- if (!floorclimb && ceilingheight > player->mo->z + player->mo->height - FixedMul(16*FRACUNIT, player->mo->scale)
- && (glidesector->sector->ceilingpic == skyflatnum || floorheight < (player->mo->z - FixedMul(8*FRACUNIT, player->mo->scale))))
- {
- thrust = true;
- boostup = true;
- // Play climb-up animation here
- }
- }
+ if (!glidesector)
+ floorclimb = true;
else
{
- // Trying to climb down past the upper texture area
- if ((ceilingheight <= player->mo->z) && ((player->mo->z + player->mo->momz) <= ceilingheight))
+#ifdef ESLOPE
+ floorheight = glidesector->sector->f_slope ? P_GetZAt(glidesector->sector->f_slope, player->mo->x, player->mo->y)
+ : glidesector->sector->floorheight;
+ ceilingheight = glidesector->sector->c_slope ? P_GetZAt(glidesector->sector->c_slope, player->mo->x, player->mo->y)
+ : glidesector->sector->ceilingheight;
+#else
+ floorheight = glidesector->sector->floorheight;
+ ceilingheight = glidesector->sector->ceilingheight;
+#endif
+
+ if (glidesector->sector->ffloors)
{
- boolean foundfof = false;
- floorclimb = true;
+ ffloor_t *rover;
+ fixed_t topheight, bottomheight; // ESLOPE
- // Is there a FOF directly below that we can move onto?
- if (glidesector->sector->ffloors)
+ for (rover = glidesector->sector->ffloors; rover; rover = rover->next)
{
- ffloor_t *rover;
- for (rover = glidesector->sector->ffloors; rover; rover = rover->next)
- {
- if (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_BLOCKPLAYER) || (rover->flags & FF_BUSTUP))
- continue;
+ if (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_BLOCKPLAYER) || (rover->flags & FF_BUSTUP))
+ continue;
- if (*rover->topheight > ceilingheight - FixedMul(16*FRACUNIT, player->mo->scale))
+ floorclimb = true;
+
+#ifdef ESLOPE
+ bottomheight = *rover->b_slope ? P_GetZAt(*rover->b_slope, player->mo->x, player->mo->y) : *rover->bottomheight;
+ topheight = *rover->t_slope ? P_GetZAt(*rover->t_slope, player->mo->x, player->mo->y) : *rover->topheight;
+#else
+ bottomheight = *rover->bottomheight;
+ topheight = *rover->topheight;
+#endif
+
+ // Only supports rovers that are moving like an 'elevator', not just the top or bottom.
+ if (rover->master->frontsector->floorspeed && rover->master->frontsector->ceilspeed == 42)
+ {
+ if ((!(player->mo->eflags & MFE_VERTICALFLIP) && (bottomheight < player->mo->z+player->mo->height)
+ && (topheight >= player->mo->z + FixedMul(16*FRACUNIT, player->mo->scale)))
+ || ((player->mo->eflags & MFE_VERTICALFLIP) && (topheight > player->mo->z)
+ && (bottomheight <= player->mo->z + player->mo->height - FixedMul(16*FRACUNIT, player->mo->scale))))
{
- foundfof = true;
- break;
+ if (cmd->forwardmove != 0)
+ player->mo->momz += rover->master->frontsector->floorspeed;
+ else
+ {
+ player->mo->momz = rover->master->frontsector->floorspeed;
+ climb = false;
+ }
}
}
- }
- if (!foundfof)
- player->mo->momz = 0;
+ // Gravity is flipped, so the comments are, too.
+ if (player->mo->eflags & MFE_VERTICALFLIP)
+ {
+ // Trying to climb down past the bottom of the FOF
+ if ((topheight >= player->mo->z + player->mo->height) && ((player->mo->z + player->mo->height + player->mo->momz) >= topheight))
+ {
+ fixed_t bottomheight2;
+ ffloor_t *roverbelow;
+ boolean foundfof = false;
+ floorclimb = true;
+ boostup = false;
+
+ // Is there a FOF directly below this one that we can move onto?
+ for (roverbelow = glidesector->sector->ffloors; roverbelow; roverbelow = roverbelow->next)
+ {
+ if (!(roverbelow->flags & FF_EXISTS) || !(roverbelow->flags & FF_BLOCKPLAYER) || (roverbelow->flags & FF_BUSTUP))
+ continue;
+
+ if (roverbelow == rover)
+ continue;
+
+#ifdef ESLOPE
+ bottomheight2 = *roverbelow->b_slope ? P_GetZAt(*roverbelow->b_slope, player->mo->x, player->mo->y) : *roverbelow->bottomheight;
+#else
+ bottomheight2 = *roverbelow->bottomheight;
+#endif
+
+ if (bottomheight2 < topheight + FixedMul(16*FRACUNIT, player->mo->scale))
+ foundfof = true;
+ }
+
+ if (!foundfof)
+ player->mo->momz = 0;
+ }
+
+ // Below the FOF
+ if (topheight <= player->mo->z)
+ {
+ floorclimb = false;
+ boostup = false;
+ thrust = false;
+ }
+
+ // Above the FOF
+ if (bottomheight > player->mo->z + player->mo->height - FixedMul(16*FRACUNIT, player->mo->scale))
+ {
+ floorclimb = false;
+ thrust = true;
+ boostup = true;
+ }
+ }
+ else
+ {
+ // Trying to climb down past the bottom of a FOF
+ if ((bottomheight <= player->mo->z) && ((player->mo->z + player->mo->momz) <= bottomheight))
+ {
+ fixed_t topheight2;
+ ffloor_t *roverbelow;
+ boolean foundfof = false;
+ floorclimb = true;
+ boostup = false;
+
+ // Is there a FOF directly below this one that we can move onto?
+ for (roverbelow = glidesector->sector->ffloors; roverbelow; roverbelow = roverbelow->next)
+ {
+ if (!(roverbelow->flags & FF_EXISTS) || !(roverbelow->flags & FF_BLOCKPLAYER) || (roverbelow->flags & FF_BUSTUP))
+ continue;
+
+ if (roverbelow == rover)
+ continue;
+
+#ifdef ESLOPE
+ topheight2 = *roverbelow->t_slope ? P_GetZAt(*roverbelow->t_slope, player->mo->x, player->mo->y) : *roverbelow->topheight;
+#else
+ topheight2 = *roverbelow->topheight;
+#endif
+
+ if (topheight2 > bottomheight - FixedMul(16*FRACUNIT, player->mo->scale))
+ foundfof = true;
+ }
+
+ if (!foundfof)
+ player->mo->momz = 0;
+ }
+
+ // Below the FOF
+ if (bottomheight >= player->mo->z + player->mo->height)
+ {
+ floorclimb = false;
+ boostup = false;
+ thrust = false;
+ }
+
+ // Above the FOF
+ if (topheight < player->mo->z + FixedMul(16*FRACUNIT, player->mo->scale))
+ {
+ floorclimb = false;
+ thrust = true;
+ boostup = true;
+ }
+ }
+
+ if (floorclimb)
+ {
+ if (rover->flags & FF_CRUMBLE && !(netgame && player->spectator))
+ EV_StartCrumble(rover->master->frontsector, rover, (rover->flags & FF_FLOATBOB), player, rover->alpha, !(rover->flags & FF_NORETURN));
+ break;
+ }
+ }
}
- // Allow climbing from a FOF or lower texture onto the upper texture and vice versa.
- if (player->mo->z > ceilingheight - FixedMul(16*FRACUNIT, player->mo->scale))
+ // Gravity is flipped, so are comments.
+ if (player->mo->eflags & MFE_VERTICALFLIP)
+ {
+ // Trying to climb down past the upper texture area
+ if ((floorheight >= player->mo->z + player->mo->height) && ((player->mo->z + player->mo->height + player->mo->momz) >= floorheight))
+ {
+ boolean foundfof = false;
+ floorclimb = true;
+
+ // Is there a FOF directly below that we can move onto?
+ if (glidesector->sector->ffloors)
+ {
+ fixed_t bottomheight;
+ ffloor_t *rover;
+ for (rover = glidesector->sector->ffloors; rover; rover = rover->next)
+ {
+ if (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_BLOCKPLAYER) || (rover->flags & FF_BUSTUP))
+ continue;
+
+#ifdef ESLOPE
+ bottomheight = *rover->b_slope ? P_GetZAt(*rover->b_slope, player->mo->x, player->mo->y) : *rover->bottomheight;
+#else
+ bottomheight = *rover->bottomheight;
+#endif
+
+ if (bottomheight < floorheight + FixedMul(16*FRACUNIT, player->mo->scale))
+ {
+ foundfof = true;
+ break;
+ }
+ }
+ }
+
+ if (!foundfof)
+ player->mo->momz = 0;
+ }
+
+ // Reached the top of the lower texture area
+ if (!floorclimb && ceilingheight > player->mo->z + player->mo->height - FixedMul(16*FRACUNIT, player->mo->scale)
+ && (glidesector->sector->ceilingpic == skyflatnum || floorheight < (player->mo->z - FixedMul(8*FRACUNIT, player->mo->scale))))
+ {
+ thrust = true;
+ boostup = true;
+ // Play climb-up animation here
+ }
+ }
+ else
+ {
+ // Trying to climb down past the upper texture area
+ if ((ceilingheight <= player->mo->z) && ((player->mo->z + player->mo->momz) <= ceilingheight))
+ {
+ boolean foundfof = false;
+ floorclimb = true;
+
+ // Is there a FOF directly below that we can move onto?
+ if (glidesector->sector->ffloors)
+ {
+ ffloor_t *rover;
+ for (rover = glidesector->sector->ffloors; rover; rover = rover->next)
+ {
+ if (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_BLOCKPLAYER) || (rover->flags & FF_BUSTUP))
+ continue;
+
+ if (*rover->topheight > ceilingheight - FixedMul(16*FRACUNIT, player->mo->scale))
+ {
+ foundfof = true;
+ break;
+ }
+ }
+ }
+
+ if (!foundfof)
+ player->mo->momz = 0;
+ }
+
+ // Allow climbing from a FOF or lower texture onto the upper texture and vice versa.
+ if (player->mo->z > ceilingheight - FixedMul(16*FRACUNIT, player->mo->scale))
+ {
+ floorclimb = true;
+ thrust = false;
+ boostup = false;
+ }
+
+ // Reached the top of the lower texture area
+ if (!floorclimb && floorheight < player->mo->z + FixedMul(16*FRACUNIT, player->mo->scale)
+ && (glidesector->sector->ceilingpic == skyflatnum || ceilingheight > (player->mo->z + player->mo->height + FixedMul(8*FRACUNIT, player->mo->scale))))
+ {
+ thrust = true;
+ boostup = true;
+ // Play climb-up animation here
+ }
+ }
+
+ // Trying to climb on the sky
+ if ((ceilingheight < player->mo->z) && glidesector->sector->ceilingpic == skyflatnum)
+ {
+ skyclimber = true;
+ }
+
+ // Climbing on the lower texture area?
+ if ((!(player->mo->eflags & MFE_VERTICALFLIP) && player->mo->z + FixedMul(16*FRACUNIT, player->mo->scale) < floorheight)
+ || ((player->mo->eflags & MFE_VERTICALFLIP) && player->mo->z + player->mo->height <= floorheight))
{
floorclimb = true;
- thrust = false;
- boostup = false;
- }
- // Reached the top of the lower texture area
- if (!floorclimb && floorheight < player->mo->z + FixedMul(16*FRACUNIT, player->mo->scale)
- && (glidesector->sector->ceilingpic == skyflatnum || ceilingheight > (player->mo->z + player->mo->height + FixedMul(8*FRACUNIT, player->mo->scale))))
- {
- thrust = true;
- boostup = true;
- // Play climb-up animation here
- }
- }
-
- // Trying to climb on the sky
- if ((ceilingheight < player->mo->z) && glidesector->sector->ceilingpic == skyflatnum)
- {
- skyclimber = true;
- }
-
- // Climbing on the lower texture area?
- if ((!(player->mo->eflags & MFE_VERTICALFLIP) && player->mo->z + FixedMul(16*FRACUNIT, player->mo->scale) < floorheight)
- || ((player->mo->eflags & MFE_VERTICALFLIP) && player->mo->z + player->mo->height <= floorheight))
- {
- floorclimb = true;
-
- if (glidesector->sector->floorspeed)
- {
- if (cmd->forwardmove != 0)
- player->mo->momz += glidesector->sector->floorspeed;
- else
+ if (glidesector->sector->floorspeed)
{
- player->mo->momz = glidesector->sector->floorspeed;
- climb = false;
+ if (cmd->forwardmove != 0)
+ player->mo->momz += glidesector->sector->floorspeed;
+ else
+ {
+ player->mo->momz = glidesector->sector->floorspeed;
+ climb = false;
+ }
}
}
- }
- // Climbing on the upper texture area?
- else if ((!(player->mo->eflags & MFE_VERTICALFLIP) && player->mo->z >= ceilingheight)
- || ((player->mo->eflags & MFE_VERTICALFLIP) && player->mo->z + player->mo->height - FixedMul(16*FRACUNIT, player->mo->scale) > ceilingheight))
- {
- floorclimb = true;
-
- if (glidesector->sector->ceilspeed)
+ // Climbing on the upper texture area?
+ else if ((!(player->mo->eflags & MFE_VERTICALFLIP) && player->mo->z >= ceilingheight)
+ || ((player->mo->eflags & MFE_VERTICALFLIP) && player->mo->z + player->mo->height - FixedMul(16*FRACUNIT, player->mo->scale) > ceilingheight))
{
- if (cmd->forwardmove != 0)
- player->mo->momz += glidesector->sector->ceilspeed;
- else
+ floorclimb = true;
+
+ if (glidesector->sector->ceilspeed)
{
- player->mo->momz = glidesector->sector->ceilspeed;
- climb = false;
+ if (cmd->forwardmove != 0)
+ player->mo->momz += glidesector->sector->ceilspeed;
+ else
+ {
+ player->mo->momz = glidesector->sector->ceilspeed;
+ climb = false;
+ }
}
}
}
@@ -2849,94 +2850,20 @@ static boolean PIT_CheckSolidsTeeter(mobj_t *thing)
//
static void P_DoTeeter(player_t *player)
{
- msecnode_t *node;
boolean teeter = false;
boolean roverfloor; // solid 3d floors?
- boolean checkedforteeter = false;
+ fixed_t floorheight, ceilingheight;
+ fixed_t topheight, bottomheight; // for 3d floor usage
const fixed_t tiptop = FixedMul(MAXSTEPMOVE, player->mo->scale); // Distance you have to be above the ground in order to teeter.
- for (node = player->mo->touching_sectorlist; node; node = node->m_snext)
+ if (player->mo->standingslope && player->mo->standingslope->zdelta >= (FRACUNIT/2)) // Always teeter if the slope is too steep.
+ teeter = true;
+ else // Let's do some checks...
{
- // Ledge teetering. Check if any nearby sectors are low enough from your current one.
- checkedforteeter = true;
- roverfloor = false;
- if (node->m_sector->ffloors)
- {
- ffloor_t *rover;
- for (rover = node->m_sector->ffloors; rover; rover = rover->next)
- {
- if (!(rover->flags & FF_EXISTS)) continue;
-
- if (P_CheckSolidLava(player->mo, rover))
- ;
- else if (!(rover->flags & FF_BLOCKPLAYER || rover->flags & FF_QUICKSAND))
- continue; // intangible 3d floor
-
- if (player->mo->eflags & MFE_VERTICALFLIP)
- {
- if (*rover->bottomheight > node->m_sector->ceilingheight) // Above the ceiling
- continue;
-
- if (*rover->bottomheight > player->mo->z + player->mo->height + tiptop
- || (*rover->topheight < player->mo->z
- && player->mo->z + player->mo->height < node->m_sector->ceilingheight - tiptop))
- {
- teeter = true;
- roverfloor = true;
- }
- else
- {
- teeter = false;
- roverfloor = true;
- break;
- }
- }
- else
- {
- if (*rover->topheight < node->m_sector->floorheight) // Below the floor
- continue;
-
- if (*rover->topheight < player->mo->z - tiptop
- || (*rover->bottomheight > player->mo->z + player->mo->height
- && player->mo->z > node->m_sector->floorheight + tiptop))
- {
- teeter = true;
- roverfloor = true;
- }
- else
- {
- teeter = false;
- roverfloor = true;
- break;
- }
- }
- }
- }
-
- if (!teeter && !roverfloor)
- {
- if (player->mo->eflags & MFE_VERTICALFLIP)
- {
- if (node->m_sector->ceilingheight > player->mo->z + player->mo->height + tiptop)
- teeter = true;
- }
- else
- {
- if (node->m_sector->floorheight < player->mo->z - tiptop)
- teeter = true;
- }
- }
- }
-
- if (checkedforteeter && !teeter) // Backup code
- {
- subsector_t *subsec[4]; // changed abcd into array instead
UINT8 i;
-
- subsec[0] = R_PointInSubsector(player->mo->x + FixedMul(5*FRACUNIT, player->mo->scale), player->mo->y + FixedMul(5*FRACUNIT, player->mo->scale));
- subsec[1] = R_PointInSubsector(player->mo->x - FixedMul(5*FRACUNIT, player->mo->scale), player->mo->y + FixedMul(5*FRACUNIT, player->mo->scale));
- subsec[2] = R_PointInSubsector(player->mo->x + FixedMul(5*FRACUNIT, player->mo->scale), player->mo->y - FixedMul(5*FRACUNIT, player->mo->scale));
- subsec[3] = R_PointInSubsector(player->mo->x - FixedMul(5*FRACUNIT, player->mo->scale), player->mo->y - FixedMul(5*FRACUNIT, player->mo->scale));
+ sector_t *sec;
+ fixed_t highestceilingheight = INT32_MIN;
+ fixed_t lowestfloorheight = INT32_MAX;
teeter = false;
roverfloor = false;
@@ -2944,13 +2871,43 @@ static void P_DoTeeter(player_t *player)
{
ffloor_t *rover;
- if (!(subsec[i]->sector->ffloors))
+#define xsign ((i & 1) ? -1 : 1) // 0 -> 1 | 1 -> -1 | 2 -> 1 | 3 -> -1
+#define ysign ((i & 2) ? 1 : -1) // 0 -> 1 | 1 -> 1 | 2 -> -1 | 3 -> -1
+ fixed_t checkx = player->mo->x + (xsign*FixedMul(5*FRACUNIT, player->mo->scale));
+ fixed_t checky = player->mo->y + (ysign*FixedMul(5*FRACUNIT, player->mo->scale));
+#undef xsign
+#undef ysign
+
+ sec = R_PointInSubsector(checkx, checky)->sector;
+
+ ceilingheight = sec->ceilingheight;
+ floorheight = sec->floorheight;
+#ifdef ESLOPE
+ if (sec->c_slope)
+ ceilingheight = P_GetZAt(sec->c_slope, checkx, checky);
+ if (sec->f_slope)
+ floorheight = P_GetZAt(sec->f_slope, checkx, checky);
+#endif
+ highestceilingheight = (ceilingheight > highestceilingheight) ? ceilingheight : highestceilingheight;
+ lowestfloorheight = (floorheight < lowestfloorheight) ? floorheight : lowestfloorheight;
+
+ if (!(sec->ffloors))
continue; // move on to the next subsector
- for (rover = subsec[i]->sector->ffloors; rover; rover = rover->next)
+ for (rover = sec->ffloors; rover; rover = rover->next)
{
if (!(rover->flags & FF_EXISTS)) continue;
+ topheight = *rover->topheight;
+ bottomheight = *rover->bottomheight;
+
+#ifdef ESLOPE
+ if (*rover->t_slope)
+ topheight = P_GetZAt(*rover->t_slope, player->mo->x, player->mo->y);
+ if (*rover->b_slope)
+ bottomheight = P_GetZAt(*rover->b_slope, player->mo->x, player->mo->y);
+#endif
+
if (P_CheckSolidLava(player->mo, rover))
;
else if (!(rover->flags & FF_BLOCKPLAYER || rover->flags & FF_QUICKSAND))
@@ -2958,12 +2915,12 @@ static void P_DoTeeter(player_t *player)
if (player->mo->eflags & MFE_VERTICALFLIP)
{
- if (*rover->bottomheight > subsec[i]->sector->ceilingheight) // Above the ceiling
+ if (bottomheight > ceilingheight) // Above the ceiling
continue;
- if (*rover->bottomheight > player->mo->z + player->mo->height + tiptop
- || (*rover->topheight < player->mo->z
- && player->mo->z + player->mo->height < subsec[i]->sector->ceilingheight - tiptop))
+ if (bottomheight > player->mo->z + player->mo->height + tiptop
+ || (topheight < player->mo->z
+ && player->mo->z + player->mo->height < ceilingheight - tiptop))
{
teeter = true;
roverfloor = true;
@@ -2977,12 +2934,12 @@ static void P_DoTeeter(player_t *player)
}
else
{
- if (*rover->topheight < subsec[i]->sector->floorheight) // Below the floor
+ if (topheight < floorheight) // Below the floor
continue;
- if (*rover->topheight < player->mo->z - tiptop
- || (*rover->bottomheight > player->mo->z + player->mo->height
- && player->mo->z > subsec[i]->sector->floorheight + tiptop))
+ if (topheight < player->mo->z - tiptop
+ || (bottomheight > player->mo->z + player->mo->height
+ && player->mo->z > floorheight + tiptop))
{
teeter = true;
roverfloor = true;
@@ -3000,18 +2957,12 @@ static void P_DoTeeter(player_t *player)
if (player->mo->eflags & MFE_VERTICALFLIP)
{
- if (!teeter && !roverfloor && (subsec[0]->sector->ceilingheight > player->mo->ceilingz + tiptop
- || subsec[1]->sector->ceilingheight > player->mo->ceilingz + tiptop
- || subsec[2]->sector->ceilingheight > player->mo->ceilingz + tiptop
- || subsec[3]->sector->ceilingheight > player->mo->ceilingz + tiptop))
+ if (!teeter && !roverfloor && (highestceilingheight > player->mo->ceilingz + tiptop))
teeter = true;
}
else
{
- if (!teeter && !roverfloor && (subsec[0]->sector->floorheight < player->mo->floorz - tiptop
- || subsec[1]->sector->floorheight < player->mo->floorz - tiptop
- || subsec[2]->sector->floorheight < player->mo->floorz - tiptop
- || subsec[3]->sector->floorheight < player->mo->floorz - tiptop))
+ if (!teeter && !roverfloor && (lowestfloorheight < player->mo->floorz - tiptop))
teeter = true;
}
}
@@ -3147,7 +3098,7 @@ teeterdone:
if ((player->mo->state == &states[S_PLAY_STND] || player->mo->state == &states[S_PLAY_TAP1] || player->mo->state == &states[S_PLAY_TAP2] || player->mo->state == &states[S_PLAY_SUPERSTAND]))
P_SetPlayerMobjState(player->mo, S_PLAY_TEETER1);
}
- else if (checkedforteeter && (player->mo->state == &states[S_PLAY_TEETER1] || player->mo->state == &states[S_PLAY_TEETER2] || player->mo->state == &states[S_PLAY_SUPERTEETER]))
+ else if ((player->mo->state == &states[S_PLAY_TEETER1] || player->mo->state == &states[S_PLAY_TEETER2] || player->mo->state == &states[S_PLAY_SUPERTEETER]))
P_SetPlayerMobjState(player->mo, S_PLAY_STND);
}
@@ -3741,7 +3692,7 @@ static void P_DoSpinDash(player_t *player, ticcmd_t *cmd)
{
if ((cmd->buttons & BT_USE) && player->speed < FixedMul(5<mo->scale) && !player->mo->momz && onground && !(player->pflags & PF_USEDOWN) && !(player->pflags & PF_SPINNING)
#ifdef ESLOPE
- && (!player->mo->standingslope || abs(player->mo->standingslope->zdelta) < FRACUNIT/2)
+ && (!player->mo->standingslope || (player->mo->standingslope->flags & SL_NOPHYSICS) || abs(player->mo->standingslope->zdelta) < FRACUNIT/2)
#endif
)
{
@@ -3774,7 +3725,7 @@ static void P_DoSpinDash(player_t *player, ticcmd_t *cmd)
else if ((cmd->buttons & BT_USE || ((twodlevel || (player->mo->flags2 & MF2_TWOD)) && cmd->forwardmove < -20))
&& !player->climbing && !player->mo->momz && onground && (player->speed > FixedMul(5<mo->scale)
#ifdef ESLOPE
- || (player->mo->standingslope && abs(player->mo->standingslope->zdelta) >= FRACUNIT/2)
+ || (player->mo->standingslope && (!(player->mo->standingslope->flags & SL_NOPHYSICS)) && abs(player->mo->standingslope->zdelta) >= FRACUNIT/2)
#endif
) && !(player->pflags & PF_USEDOWN) && !(player->pflags & PF_SPINNING))
{
@@ -3790,7 +3741,7 @@ static void P_DoSpinDash(player_t *player, ticcmd_t *cmd)
if (onground && player->pflags & PF_SPINNING && !(player->pflags & PF_STARTDASH)
&& player->speed < FixedMul(5*FRACUNIT,player->mo->scale)
#ifdef ESLOPE
- && (!player->mo->standingslope || abs(player->mo->standingslope->zdelta) < FRACUNIT/2)
+ && (!player->mo->standingslope || (player->mo->standingslope->flags & SL_NOPHYSICS) || abs(player->mo->standingslope->zdelta) < FRACUNIT/2)
#endif
)
{
@@ -4776,7 +4727,7 @@ static void P_3dMovement(player_t *player)
#ifdef ESLOPE
if ((totalthrust.x || totalthrust.y)
- && player->mo->standingslope && abs(player->mo->standingslope->zdelta) > FRACUNIT/2) {
+ && player->mo->standingslope && (!(player->mo->standingslope->flags & SL_NOPHYSICS)) && abs(player->mo->standingslope->zdelta) > FRACUNIT/2) {
// Factor thrust to slope, but only for the part pushing up it!
// The rest is unaffected.
angle_t thrustangle = R_PointToAngle2(0, 0, totalthrust.x, totalthrust.y)-player->mo->standingslope->xydirection;
@@ -7028,6 +6979,7 @@ static void P_MovePlayer(player_t *player)
msecnode_t *node; // only place it's being used in P_MovePlayer now
fixed_t oldx;
fixed_t oldy;
+ fixed_t floorz, ceilingz;
oldx = player->mo->x;
oldy = player->mo->y;
@@ -7037,7 +6989,7 @@ static void P_MovePlayer(player_t *player)
player->mo->y += player->mo->momy;
P_SetThingPosition(player->mo);
- for (node = player->mo->touching_sectorlist; node; node = node->m_snext)
+ for (node = player->mo->touching_sectorlist; node; node = node->m_sectorlist_next)
{
if (!node->m_sector)
break;
@@ -7045,31 +6997,34 @@ static void P_MovePlayer(player_t *player)
if (node->m_sector->ffloors)
{
ffloor_t *rover;
+ fixed_t topheight, bottomheight;
for (rover = node->m_sector->ffloors; rover; rover = rover->next)
{
- if (!(rover->flags & FF_EXISTS)) continue;
+ if (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_BLOCKPLAYER))
+ continue;
- if ((rover->flags & FF_BLOCKPLAYER))
+ topheight = P_GetFOFTopZ(player->mo, node->m_sector, rover, player->mo->x, player->mo->y, NULL);
+ bottomheight = P_GetFOFBottomZ(player->mo, node->m_sector, rover, player->mo->x, player->mo->y, NULL);
+ if (topheight > player->mo->z && bottomheight < player->mo->z)
{
- if (*rover->topheight > player->mo->z && *rover->bottomheight < player->mo->z)
- {
- P_ResetPlayer(player);
- S_StartSound(player->mo, sfx_s3k4a);
- player->climbing = 5;
- player->mo->momx = player->mo->momy = player->mo->momz = 0;
- break;
- }
+ P_ResetPlayer(player);
+ S_StartSound(player->mo, sfx_s3k4a);
+ player->climbing = 5;
+ player->mo->momx = player->mo->momy = player->mo->momz = 0;
+ break;
}
}
}
- if (player->mo->z+player->mo->height > node->m_sector->ceilingheight
+ floorz = P_GetFloorZ(player->mo, node->m_sector, player->mo->x, player->mo->y, NULL);
+ ceilingz = P_GetCeilingZ(player->mo, node->m_sector, player->mo->x, player->mo->y, NULL);
+
+ if (player->mo->z+player->mo->height > ceilingz
&& node->m_sector->ceilingpic == skyflatnum)
continue;
- if (node->m_sector->floorheight > player->mo->z
- || node->m_sector->ceilingheight < player->mo->z)
+ if (floorz > player->mo->z || ceilingz < player->mo->z)
{
P_ResetPlayer(player);
S_StartSound(player->mo, sfx_s3k4a);
@@ -7102,7 +7057,6 @@ static void P_DoZoomTube(player_t *player)
mobj_t *waypoint = NULL;
fixed_t dist;
boolean reverse;
- fixed_t speedx,speedy,speedz;
player->mo->height = P_GetPlayerSpinHeight(player);
@@ -7123,17 +7077,17 @@ static void P_DoZoomTube(player_t *player)
if (dist < 1)
dist = 1;
- speedx = FixedMul(FixedDiv(player->mo->tracer->x - player->mo->x, dist), (speed));
- speedy = FixedMul(FixedDiv(player->mo->tracer->y - player->mo->y, dist), (speed));
- speedz = FixedMul(FixedDiv(player->mo->tracer->z - player->mo->z, dist), (speed));
+ player->mo->momx = FixedMul(FixedDiv(player->mo->tracer->x - player->mo->x, dist), (speed));
+ player->mo->momy = FixedMul(FixedDiv(player->mo->tracer->y - player->mo->y, dist), (speed));
+ player->mo->momz = FixedMul(FixedDiv(player->mo->tracer->z - player->mo->z, dist), (speed));
// Calculate the distance between the player and the waypoint
// 'dist' already equals this.
- // Will the player be FURTHER away if the momx/momy/momz is added to
- // his current coordinates, or closer? (shift down to fracunits to avoid approximation errors)
- if (dist>>FRACBITS <= P_AproxDistance(P_AproxDistance(player->mo->tracer->x - player->mo->x - speedx, player->mo->tracer->y - player->mo->y - speedy), player->mo->tracer->z - player->mo->z - speedz)>>FRACBITS)
+ // Will the player go past the waypoint?
+ if (speed > dist)
{
+ speed -= dist;
// If further away, set XYZ of player to waypoint location
P_UnsetThingPosition(player->mo);
player->mo->x = player->mo->tracer->x;
@@ -7173,14 +7127,9 @@ static void P_DoZoomTube(player_t *player)
{
CONS_Debug(DBG_GAMELOGIC, "Found waypoint (sequence %d, number %d).\n", waypoint->threshold, waypoint->health);
- // calculate MOMX/MOMY/MOMZ for next waypoint
- // change angle
- player->mo->angle = R_PointToAngle2(player->mo->x, player->mo->y, player->mo->tracer->x, player->mo->tracer->y);
+ P_SetTarget(&player->mo->tracer, waypoint);
- if (player == &players[consoleplayer])
- localangle = player->mo->angle;
- else if (player == &players[secondarydisplayplayer])
- localangle2 = player->mo->angle;
+ // calculate MOMX/MOMY/MOMZ for next waypoint
// change slope
dist = P_AproxDistance(P_AproxDistance(player->mo->tracer->x - player->mo->x, player->mo->tracer->y - player->mo->y), player->mo->tracer->z - player->mo->z);
@@ -7191,22 +7140,14 @@ static void P_DoZoomTube(player_t *player)
player->mo->momx = FixedMul(FixedDiv(player->mo->tracer->x - player->mo->x, dist), (speed));
player->mo->momy = FixedMul(FixedDiv(player->mo->tracer->y - player->mo->y, dist), (speed));
player->mo->momz = FixedMul(FixedDiv(player->mo->tracer->z - player->mo->z, dist), (speed));
-
- P_SetTarget(&player->mo->tracer, waypoint);
}
else
{
- P_SetTarget(&player->mo->tracer, NULL); // Else, we just let him fly.
+ P_SetTarget(&player->mo->tracer, NULL); // Else, we just let them fly.
CONS_Debug(DBG_GAMELOGIC, "Next waypoint not found, releasing from track...\n");
}
}
- else
- {
- player->mo->momx = speedx;
- player->mo->momy = speedy;
- player->mo->momz = speedz;
- }
// change angle
if (player->mo->tracer)
@@ -7234,24 +7175,10 @@ static void P_DoRopeHang(player_t *player)
mobj_t *mo2;
mobj_t *waypoint = NULL;
fixed_t dist;
- fixed_t speedx,speedy,speedz;
fixed_t playerz;
player->mo->height = P_GetPlayerHeight(player);
- if (player->cmd.buttons & BT_USE && !(player->pflags & PF_STASIS)) // Drop off of the rope
- {
- P_SetTarget(&player->mo->tracer, NULL);
-
- player->pflags |= PF_JUMPED;
- player->pflags &= ~PF_ROPEHANG;
-
- if (!(player->pflags & PF_SLIDING) && (player->pflags & PF_JUMPED)
- && !(player->panim == PA_ROLL) && player->charability2 == CA2_SPINDASH)
- P_SetPlayerMobjState(player->mo, S_PLAY_ATK1);
- return;
- }
-
// Play the 'clink' sound only if the player is moving.
if (!(leveltime & 7) && player->speed)
S_StartSound(player->mo, sfx_s3k55);
@@ -7268,9 +7195,22 @@ static void P_DoRopeHang(player_t *player)
if (dist < 1)
dist = 1;
- speedx = FixedMul(FixedDiv(player->mo->tracer->x - player->mo->x, dist), (speed));
- speedy = FixedMul(FixedDiv(player->mo->tracer->y - player->mo->y, dist), (speed));
- speedz = FixedMul(FixedDiv(player->mo->tracer->z - playerz, dist), (speed));
+ player->mo->momx = FixedMul(FixedDiv(player->mo->tracer->x - player->mo->x, dist), (speed));
+ player->mo->momy = FixedMul(FixedDiv(player->mo->tracer->y - player->mo->y, dist), (speed));
+ player->mo->momz = FixedMul(FixedDiv(player->mo->tracer->z - playerz, dist), (speed));
+
+ if (player->cmd.buttons & BT_USE && !(player->pflags & PF_STASIS)) // Drop off of the rope
+ {
+ P_SetTarget(&player->mo->tracer, NULL);
+
+ player->pflags |= PF_JUMPED;
+ player->pflags &= ~PF_ROPEHANG;
+
+ if (!(player->pflags & PF_SLIDING) && (player->pflags & PF_JUMPED)
+ && !(player->panim == PA_ROLL) && player->charability2 == CA2_SPINDASH)
+ P_SetPlayerMobjState(player->mo, S_PLAY_ATK1);
+ return;
+ }
// If not allowed to move, we're done here.
if (!speed)
@@ -7279,15 +7219,16 @@ static void P_DoRopeHang(player_t *player)
// Calculate the distance between the player and the waypoint
// 'dist' already equals this.
- // Will the player be FURTHER away if the momx/momy/momz is added to
- // his current coordinates, or closer? (shift down to fracunits to avoid approximation errors)
- if (dist>>FRACBITS <= P_AproxDistance(P_AproxDistance(player->mo->tracer->x - player->mo->x - speedx, player->mo->tracer->y - player->mo->y - speedy), player->mo->tracer->z - playerz - speedz)>>FRACBITS)
+ // Will the player go past the waypoint?
+ if (speed > dist)
{
+ speed -= dist;
// If further away, set XYZ of player to waypoint location
P_UnsetThingPosition(player->mo);
player->mo->x = player->mo->tracer->x;
player->mo->y = player->mo->tracer->y;
player->mo->z = player->mo->tracer->z - player->mo->height;
+ playerz = player->mo->tracer->z;
P_SetThingPosition(player->mo);
CONS_Debug(DBG_GAMELOGIC, "Looking for next waypoint...\n");
@@ -7343,6 +7284,8 @@ static void P_DoRopeHang(player_t *player)
{
CONS_Debug(DBG_GAMELOGIC, "Found waypoint (sequence %d, number %d).\n", waypoint->threshold, waypoint->health);
+ P_SetTarget(&player->mo->tracer, waypoint);
+
// calculate MOMX/MOMY/MOMZ for next waypoint
// change slope
dist = P_AproxDistance(P_AproxDistance(player->mo->tracer->x - player->mo->x, player->mo->tracer->y - player->mo->y), player->mo->tracer->z - playerz);
@@ -7353,8 +7296,6 @@ static void P_DoRopeHang(player_t *player)
player->mo->momx = FixedMul(FixedDiv(player->mo->tracer->x - player->mo->x, dist), (speed));
player->mo->momy = FixedMul(FixedDiv(player->mo->tracer->y - player->mo->y, dist), (speed));
player->mo->momz = FixedMul(FixedDiv(player->mo->tracer->z - playerz, dist), (speed));
-
- P_SetTarget(&player->mo->tracer, waypoint);
}
else
{
@@ -7373,12 +7314,6 @@ static void P_DoRopeHang(player_t *player)
CONS_Debug(DBG_GAMELOGIC, "Next waypoint not found!\n");
}
}
- else
- {
- player->mo->momx = speedx;
- player->mo->momy = speedy;
- player->mo->momz = speedz;
- }
}
#if 0
@@ -8123,6 +8058,8 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall
{
fixed_t myfloorz, myceilingz;
fixed_t midz = thiscam->z + (thiscam->z - mo->z)/2;
+ fixed_t midx = ((mo->x>>FRACBITS) + (thiscam->x>>FRACBITS))<<(FRACBITS-1);
+ fixed_t midy = ((mo->y>>FRACBITS) + (thiscam->y>>FRACBITS))<<(FRACBITS-1);
// Cameras use the heightsec's heights rather then the actual sector heights.
// If you can see through it, why not move the camera through it too?
@@ -8138,8 +8075,8 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall
}
else
{
- myfloorz = newsubsec->sector->floorheight;
- myceilingz = newsubsec->sector->ceilingheight;
+ myfloorz = P_CameraGetFloorZ(thiscam, newsubsec->sector, midx, midy, NULL);
+ myceilingz = P_CameraGetCeilingZ(thiscam, newsubsec->sector, midx, midy, NULL);
}
// Check list of fake floors and see if floorz/ceilingz need to be altered.
@@ -8151,17 +8088,21 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall
for (rover = newsubsec->sector->ffloors; rover; rover = rover->next)
{
+ fixed_t topheight, bottomheight;
if (!(rover->flags & FF_BLOCKOTHERS) || !(rover->flags & FF_EXISTS) || !(rover->flags & FF_RENDERALL) || GETSECSPECIAL(rover->master->frontsector->special, 4) == 12)
continue;
- delta1 = midz - (*rover->bottomheight
- + ((*rover->topheight - *rover->bottomheight)/2));
- delta2 = thingtop - (*rover->bottomheight
- + ((*rover->topheight - *rover->bottomheight)/2));
- if (*rover->topheight > myfloorz && abs(delta1) < abs(delta2))
- myfloorz = *rover->topheight;
- if (*rover->bottomheight < myceilingz && abs(delta1) >= abs(delta2))
- myceilingz = *rover->bottomheight;
+ topheight = P_CameraGetFOFTopZ(thiscam, newsubsec->sector, rover, midx, midy, NULL);
+ bottomheight = P_CameraGetFOFBottomZ(thiscam, newsubsec->sector, rover, midx, midy, NULL);
+
+ delta1 = midz - (bottomheight
+ + ((topheight - bottomheight)/2));
+ delta2 = thingtop - (bottomheight
+ + ((topheight - bottomheight)/2));
+ if (topheight > myfloorz && abs(delta1) < abs(delta2))
+ myfloorz = topheight;
+ if (bottomheight < myceilingz && abs(delta1) >= abs(delta2))
+ myceilingz = bottomheight;
}
}
@@ -8275,18 +8216,22 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall
for (rover = newsubsec->sector->ffloors; rover; rover = rover->next)
{
+ fixed_t topheight, bottomheight;
if ((rover->flags & FF_BLOCKOTHERS) && (rover->flags & FF_RENDERALL) && (rover->flags & FF_EXISTS) && GETSECSPECIAL(rover->master->frontsector->special, 4) != 12)
{
- if (*rover->bottomheight - thiscam->height < z
- && midz < *rover->bottomheight)
- z = *rover->bottomheight - thiscam->height-FixedMul(11*FRACUNIT, mo->scale);
+ topheight = P_CameraGetFOFTopZ(thiscam, newsubsec->sector, rover, midx, midy, NULL);
+ bottomheight = P_CameraGetFOFBottomZ(thiscam, newsubsec->sector, rover, midx, midy, NULL);
- else if (*rover->topheight + thiscam->height > z
- && midz > *rover->topheight)
- z = *rover->topheight;
+ if (bottomheight - thiscam->height < z
+ && midz < bottomheight)
+ z = bottomheight - thiscam->height-FixedMul(11*FRACUNIT, mo->scale);
- if ((mo->z >= *rover->topheight && midz < *rover->bottomheight)
- || ((mo->z < *rover->bottomheight && mo->z+mo->height < *rover->topheight) && midz >= *rover->topheight))
+ else if (topheight + thiscam->height > z
+ && midz > topheight)
+ z = topheight;
+
+ if ((mo->z >= topheight && midz < bottomheight)
+ || ((mo->z < bottomheight && mo->z+mo->height < topheight) && midz >= topheight))
{
// Can't see
if (!resetcalled)
diff --git a/src/r_bsp.c b/src/r_bsp.c
index 69aa7be2..abb11204 100644
--- a/src/r_bsp.c
+++ b/src/r_bsp.c
@@ -210,7 +210,7 @@ void R_PortalClearClipSegs(INT32 start, INT32 end)
//
// It assumes that Doom has already ruled out a door being closed because
// of front-back closure (e.g. front floor is taller than back ceiling).
-static inline INT32 R_DoorClosed(void)
+static INT32 R_DoorClosed(void)
{
return
@@ -859,6 +859,7 @@ static void R_Subsector(size_t num)
static sector_t tempsec; // Deep water hack
extracolormap_t *floorcolormap;
extracolormap_t *ceilingcolormap;
+ fixed_t floorcenterz, ceilingcenterz;
#ifdef RANGECHECK
if (num >= numsubsectors)
@@ -879,6 +880,18 @@ static void R_Subsector(size_t num)
floorcolormap = ceilingcolormap = frontsector->extra_colormap;
+ floorcenterz =
+#ifdef ESLOPE
+ frontsector->f_slope ? P_GetZAt(frontsector->f_slope, frontsector->soundorg.x, frontsector->soundorg.y) :
+#endif
+ frontsector->floorheight;
+
+ ceilingcenterz =
+#ifdef ESLOPE
+ frontsector->c_slope ? P_GetZAt(frontsector->c_slope, frontsector->soundorg.x, frontsector->soundorg.y) :
+#endif
+ frontsector->ceilingheight;
+
// Check and prep all 3D floors. Set the sector floor/ceiling light levels and colormaps.
if (frontsector->ffloors)
{
@@ -891,19 +904,11 @@ static void R_Subsector(size_t num)
sub->sector->moved = frontsector->moved = false;
}
- light = R_GetPlaneLight(frontsector,
-#ifdef ESLOPE
- frontsector->f_slope ? P_GetZAt(frontsector->f_slope, frontsector->soundorg.x, frontsector->soundorg.y) :
-#endif
- frontsector->floorheight, false);
+ light = R_GetPlaneLight(frontsector, floorcenterz, false);
if (frontsector->floorlightsec == -1)
floorlightlevel = *frontsector->lightlist[light].lightlevel;
floorcolormap = frontsector->lightlist[light].extra_colormap;
- light = R_GetPlaneLight(frontsector,
-#ifdef ESLOPE
- frontsector->c_slope ? P_GetZAt(frontsector->c_slope, frontsector->soundorg.x, frontsector->soundorg.y) :
-#endif
- frontsector->ceilingheight, false);
+ light = R_GetPlaneLight(frontsector, ceilingcenterz, false);
if (frontsector->ceilinglightsec == -1)
ceilinglightlevel = *frontsector->lightlist[light].lightlevel;
ceilingcolormap = frontsector->lightlist[light].extra_colormap;
@@ -920,6 +925,9 @@ static void R_Subsector(size_t num)
{
floorplane = R_FindPlane(frontsector->floorheight, frontsector->floorpic, floorlightlevel,
frontsector->floor_xoffs, frontsector->floor_yoffs, frontsector->floorpic_angle, floorcolormap, NULL
+#ifdef POLYOBJECTS_PLANES
+ , NULL
+#endif
#ifdef ESLOPE
, frontsector->f_slope
#endif
@@ -939,6 +947,9 @@ static void R_Subsector(size_t num)
ceilingplane = R_FindPlane(frontsector->ceilingheight, frontsector->ceilingpic,
ceilinglightlevel, frontsector->ceiling_xoffs, frontsector->ceiling_yoffs, frontsector->ceilingpic_angle,
ceilingcolormap, NULL
+#ifdef POLYOBJECTS_PLANES
+ , NULL
+#endif
#ifdef ESLOPE
, frontsector->c_slope
#endif
@@ -956,7 +967,7 @@ static void R_Subsector(size_t num)
if (frontsector->ffloors)
{
ffloor_t *rover;
- fixed_t heightcheck, planecenterz, floorcenterz, ceilingcenterz;
+ fixed_t heightcheck, planecenterz;
for (rover = frontsector->ffloors; rover && numffloors < MAXFFLOORS; rover = rover->next)
{
@@ -975,18 +986,6 @@ static void R_Subsector(size_t num)
ffloor[numffloors].plane = NULL;
ffloor[numffloors].polyobj = NULL;
- floorcenterz =
-#ifdef ESLOPE
- frontsector->f_slope ? P_GetZAt(frontsector->f_slope, frontsector->soundorg.x, frontsector->soundorg.y) :
-#endif
- frontsector->floorheight;
-
- ceilingcenterz =
-#ifdef ESLOPE
- frontsector->c_slope ? P_GetZAt(frontsector->c_slope, frontsector->soundorg.x, frontsector->soundorg.y) :
-#endif
- frontsector->ceilingheight;
-
heightcheck =
#ifdef ESLOPE
*rover->b_slope ? P_GetZAt(*rover->b_slope, viewx, viewy) :
@@ -1009,6 +1008,9 @@ static void R_Subsector(size_t num)
ffloor[numffloors].plane = R_FindPlane(*rover->bottomheight, *rover->bottompic,
*frontsector->lightlist[light].lightlevel, *rover->bottomxoffs,
*rover->bottomyoffs, *rover->bottomangle, frontsector->lightlist[light].extra_colormap, rover
+#ifdef POLYOBJECTS_PLANES
+ , NULL
+#endif
#ifdef ESLOPE
, *rover->b_slope
#endif
@@ -1052,6 +1054,9 @@ static void R_Subsector(size_t num)
ffloor[numffloors].plane = R_FindPlane(*rover->topheight, *rover->toppic,
*frontsector->lightlist[light].lightlevel, *rover->topxoffs, *rover->topyoffs, *rover->topangle,
frontsector->lightlist[light].extra_colormap, rover
+#ifdef POLYOBJECTS_PLANES
+ , NULL
+#endif
#ifdef ESLOPE
, *rover->t_slope
#endif
@@ -1093,8 +1098,8 @@ static void R_Subsector(size_t num)
polysec = po->lines[0]->backsector;
ffloor[numffloors].plane = NULL;
- if (polysec->floorheight <= frontsector->ceilingheight
- && polysec->floorheight >= frontsector->floorheight
+ if (polysec->floorheight <= ceilingcenterz
+ && polysec->floorheight >= floorcenterz
&& (viewz < polysec->floorheight))
{
fixed_t xoff, yoff;
@@ -1118,11 +1123,13 @@ static void R_Subsector(size_t num)
polysec->floorpic_angle-po->angle,
NULL,
NULL
+#ifdef POLYOBJECTS_PLANES
+ , po
+#endif
#ifdef ESLOPE
, NULL // will ffloors be slopable eventually?
#endif
);
- //ffloor[numffloors].plane->polyobj = po;
ffloor[numffloors].height = polysec->floorheight;
ffloor[numffloors].polyobj = po;
@@ -1139,8 +1146,8 @@ static void R_Subsector(size_t num)
ffloor[numffloors].plane = NULL;
- if (polysec->ceilingheight >= frontsector->floorheight
- && polysec->ceilingheight <= frontsector->ceilingheight
+ if (polysec->ceilingheight >= floorcenterz
+ && polysec->ceilingheight <= ceilingcenterz
&& (viewz > polysec->ceilingheight))
{
fixed_t xoff, yoff;
@@ -1162,11 +1169,13 @@ static void R_Subsector(size_t num)
ffloor[numffloors].plane = R_FindPlane(polysec->ceilingheight, polysec->ceilingpic,
polysec->lightlevel, xoff, yoff, polysec->ceilingpic_angle-po->angle,
NULL, NULL
+#ifdef POLYOBJECTS_PLANES
+ , po
+#endif
#ifdef ESLOPE
, NULL // will ffloors be slopable eventually?
#endif
);
- //ffloor[numffloors].plane->polyobj = po;
ffloor[numffloors].polyobj = po;
ffloor[numffloors].height = polysec->ceilingheight;
@@ -1213,6 +1222,9 @@ static void R_Subsector(size_t num)
while (count--)
{
// CONS_Debug(DBG_GAMELOGIC, "Adding normal line %d...(%d)\n", line->linedef-lines, leveltime);
+#ifdef POLYOBJECTS
+ if (!line->polyseg) // ignore segs that belong to polyobjects
+#endif
R_AddLine(line);
line++;
curline = NULL; /* cph 2001/11/18 - must clear curline now we're done with it, so stuff doesn't try using it for other things */
diff --git a/src/r_data.c b/src/r_data.c
index cb5cf359..d19882dd 100644
--- a/src/r_data.c
+++ b/src/r_data.c
@@ -303,6 +303,32 @@ done:
return blocktex;
}
+//
+// R_GetTextureNum
+//
+// Returns the actual texture id that we should use.
+// This can either be texnum, the current frame for texnum's anim (if animated),
+// or 0 if not valid.
+//
+INT32 R_GetTextureNum(INT32 texnum)
+{
+ if (texnum < 0 || texnum >= numtextures)
+ return 0;
+ return texturetranslation[texnum];
+}
+
+//
+// R_CheckTextureCache
+//
+// Use this if you need to make sure the texture is cached before R_GetColumn calls
+// e.g.: midtextures and FOF walls
+//
+void R_CheckTextureCache(INT32 tex)
+{
+ if (!texturecache[tex])
+ R_GenerateTexture(tex);
+}
+
//
// R_GetColumn
//
@@ -918,23 +944,24 @@ static void R_InitExtraColormaps(void)
for (cfile = clump = 0; cfile < numwadfiles; cfile++, clump = 0)
{
startnum = W_CheckNumForNamePwad("C_START", cfile, clump);
- if (startnum == LUMPERROR)
+ if (startnum == INT16_MAX)
continue;
endnum = W_CheckNumForNamePwad("C_END", cfile, clump);
- if (endnum == LUMPERROR)
+ if (endnum == INT16_MAX)
I_Error("R_InitExtraColormaps: C_START without C_END\n");
- if (WADFILENUM(startnum) != WADFILENUM(endnum))
- I_Error("R_InitExtraColormaps: C_START and C_END in different wad files!\n");
+ // This shouldn't be possible when you use the Pwad function, silly
+ //if (WADFILENUM(startnum) != WADFILENUM(endnum))
+ //I_Error("R_InitExtraColormaps: C_START and C_END in different wad files!\n");
if (numcolormaplumps >= maxcolormaplumps)
maxcolormaplumps *= 2;
colormaplumps = Z_Realloc(colormaplumps,
sizeof (*colormaplumps) * maxcolormaplumps, PU_STATIC, NULL);
- colormaplumps[numcolormaplumps].wadfile = WADFILENUM(startnum);
- colormaplumps[numcolormaplumps].firstlump = LUMPNUM(startnum+1);
+ colormaplumps[numcolormaplumps].wadfile = cfile;
+ colormaplumps[numcolormaplumps].firstlump = startnum+1;
colormaplumps[numcolormaplumps].numlumps = endnum - (startnum + 1);
numcolormaplumps++;
}
@@ -1499,6 +1526,9 @@ void R_InitData(void)
CONS_Printf("R_LoadTextures()...\n");
R_LoadTextures();
+ CONS_Printf("P_InitPicAnims()...\n");
+ P_InitPicAnims();
+
CONS_Printf("R_InitSprites()...\n");
R_InitSpriteLumps();
R_InitSprites();
diff --git a/src/r_data.h b/src/r_data.h
index 4a37f82c..1e9e0eb5 100644
--- a/src/r_data.h
+++ b/src/r_data.h
@@ -30,7 +30,7 @@ typedef struct
{
// Block origin (always UL), which has already accounted for the internal origin of the patch.
INT16 originx, originy;
- INT16 wad, lump;
+ UINT16 wad, lump;
} texpatch_t;
// A maptexturedef_t describes a rectangular texture,
@@ -65,6 +65,9 @@ extern CV_PossibleValue_t Color_cons_t[];
void R_LoadTextures(void);
void R_FlushTextureCache(void);
+INT32 R_GetTextureNum(INT32 texnum);
+void R_CheckTextureCache(INT32 tex);
+
// Retrieve column data for span blitting.
UINT8 *R_GetColumn(fixed_t tex, INT32 col);
diff --git a/src/r_defs.h b/src/r_defs.h
index 84870816..b8c21764 100644
--- a/src/r_defs.h
+++ b/src/r_defs.h
@@ -203,6 +203,7 @@ typedef struct r_lightlist_s
fixed_t heightstep;
fixed_t botheight;
fixed_t botheightstep;
+ fixed_t startheight; // for repeating midtextures
INT16 lightlevel;
extracolormap_t *extra_colormap;
lighttable_t *rcolormap;
@@ -224,15 +225,6 @@ typedef struct linechain_s
-// ZDoom C++ to Legacy C conversion Tails 04-29-2002 (for slopes)
-typedef struct secplane_t
-{
- // the plane is defined as a*x + b*y + c*z + d = 0
- // ic is 1/c, for faster Z calculations
-
- fixed_t a, b, c, d, ic;
-} secplane_t;
-
// Slopes
#ifdef ESLOPE
typedef enum {
@@ -392,6 +384,7 @@ typedef struct sector_s
#endif
// these are saved for netgames, so do not let Lua touch these!
+ INT32 spawn_nexttag, spawn_firsttag; // the actual nexttag/firsttag values may differ if the sector's tag was changed
// offsets sector spawned with (via linedef type 7)
fixed_t spawn_flr_xoffs, spawn_flr_yoffs;
@@ -500,10 +493,10 @@ typedef struct subsector_s
// Sector list node showing all sectors an object appears in.
//
// There are two threads that flow through these nodes. The first thread
-// starts at touching_thinglist in a sector_t and flows through the m_snext
+// starts at touching_thinglist in a sector_t and flows through the m_thinglist_next
// links to find all mobjs that are entirely or partially in the sector.
// The second thread starts at touching_sectorlist in an mobj_t and flows
-// through the m_tnext links to find all sectors a thing touches. This is
+// through the m_sectorlist_next links to find all sectors a thing touches. This is
// useful when applying friction or push effects to sectors. These effects
// can be done as thinkers that act upon all objects touching their sectors.
// As an mobj moves through the world, these nodes are created and
@@ -515,10 +508,10 @@ typedef struct msecnode_s
{
sector_t *m_sector; // a sector containing this object
struct mobj_s *m_thing; // this object
- struct msecnode_s *m_tprev; // prev msecnode_t for this thing
- struct msecnode_s *m_tnext; // next msecnode_t for this thing
- struct msecnode_s *m_sprev; // prev msecnode_t for this sector
- struct msecnode_s *m_snext; // next msecnode_t for this sector
+ struct msecnode_s *m_sectorlist_prev; // prev msecnode_t for this thing
+ struct msecnode_s *m_sectorlist_next; // next msecnode_t for this thing
+ struct msecnode_s *m_thinglist_prev; // prev msecnode_t for this sector
+ struct msecnode_s *m_thinglist_next; // next msecnode_t for this sector
boolean visited; // used in search algorithms
} msecnode_t;
@@ -526,10 +519,10 @@ typedef struct mprecipsecnode_s
{
sector_t *m_sector; // a sector containing this object
struct precipmobj_s *m_thing; // this object
- struct mprecipsecnode_s *m_tprev; // prev msecnode_t for this thing
- struct mprecipsecnode_s *m_tnext; // next msecnode_t for this thing
- struct mprecipsecnode_s *m_sprev; // prev msecnode_t for this sector
- struct mprecipsecnode_s *m_snext; // next msecnode_t for this sector
+ struct mprecipsecnode_s *m_sectorlist_prev; // prev msecnode_t for this thing
+ struct mprecipsecnode_s *m_sectorlist_next; // next msecnode_t for this thing
+ struct mprecipsecnode_s *m_thinglist_prev; // prev msecnode_t for this sector
+ struct mprecipsecnode_s *m_thinglist_next; // next msecnode_t for this sector
boolean visited; // used in search algorithms
} mprecipsecnode_t;
diff --git a/src/r_draw8.c b/src/r_draw8.c
index c22cd236..39585f58 100644
--- a/src/r_draw8.c
+++ b/src/r_draw8.c
@@ -874,9 +874,9 @@ void R_DrawTiltedSplat_8(void)
colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps);
- val = colormap[source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)]];
+ val = source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)];
if (val != TRANSPARENTPIXEL)
- *dest = val;
+ *dest = colormap[val];
dest++;
iz += ds_sz.x;
uz += ds_su.x;
@@ -913,9 +913,9 @@ void R_DrawTiltedSplat_8(void)
for (i = SPANSIZE-1; i >= 0; i--)
{
colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps);
- val = colormap[source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)]];
+ val = source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)];
if (val != TRANSPARENTPIXEL)
- *dest = val;
+ *dest = colormap[val];
dest++;
u += stepu;
v += stepv;
@@ -931,9 +931,9 @@ void R_DrawTiltedSplat_8(void)
u = (INT64)(startu);
v = (INT64)(startv);
colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps);
- val = colormap[source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)]];
+ val = source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)];
if (val != TRANSPARENTPIXEL)
- *dest = val;
+ *dest = colormap[val];
}
else
{
@@ -954,9 +954,9 @@ void R_DrawTiltedSplat_8(void)
for (; width != 0; width--)
{
colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps);
- val = colormap[source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)]];
+ val = source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)];
if (val != TRANSPARENTPIXEL)
- *dest = val;
+ *dest = colormap[val];
dest++;
u += stepu;
v += stepv;
@@ -1124,49 +1124,49 @@ void R_DrawTranslucentSplat_8 (void)
// need!
val = source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)];
if (val != TRANSPARENTPIXEL)
- dest[0] = colormap[*(ds_transmap + (source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)] << 8) + dest[0])];
+ dest[0] = colormap[*(ds_transmap + (val << 8) + dest[0])];
xposition += xstep;
yposition += ystep;
val = source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)];
if (val != TRANSPARENTPIXEL)
- dest[1] = colormap[*(ds_transmap + (source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)] << 8) + dest[1])];
+ dest[1] = colormap[*(ds_transmap + (val << 8) + dest[1])];
xposition += xstep;
yposition += ystep;
val = source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)];
if (val != TRANSPARENTPIXEL)
- dest[2] = colormap[*(ds_transmap + (source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)] << 8) + dest[2])];
+ dest[2] = colormap[*(ds_transmap + (val << 8) + dest[2])];
xposition += xstep;
yposition += ystep;
val = source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)];
if (val != TRANSPARENTPIXEL)
- dest[3] = colormap[*(ds_transmap + (source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)] << 8) + dest[3])];
+ dest[3] = colormap[*(ds_transmap + (val << 8) + dest[3])];
xposition += xstep;
yposition += ystep;
val = source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)];
if (val != TRANSPARENTPIXEL)
- dest[4] = colormap[*(ds_transmap + (source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)] << 8) + dest[4])];
+ dest[4] = colormap[*(ds_transmap + (val << 8) + dest[4])];
xposition += xstep;
yposition += ystep;
val = source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)];
if (val != TRANSPARENTPIXEL)
- dest[5] = colormap[*(ds_transmap + (source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)] << 8) + dest[5])];
+ dest[5] = colormap[*(ds_transmap + (val << 8) + dest[5])];
xposition += xstep;
yposition += ystep;
val = source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)];
if (val != TRANSPARENTPIXEL)
- dest[6] = colormap[*(ds_transmap + (source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)] << 8) + dest[6])];
+ dest[6] = colormap[*(ds_transmap + (val << 8) + dest[6])];
xposition += xstep;
yposition += ystep;
val = source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)];
if (val != TRANSPARENTPIXEL)
- dest[7] = colormap[*(ds_transmap + (source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)] << 8) + dest[7])];
+ dest[7] = colormap[*(ds_transmap + (val << 8) + dest[7])];
xposition += xstep;
yposition += ystep;
@@ -1175,9 +1175,9 @@ void R_DrawTranslucentSplat_8 (void)
}
while (count--)
{
- val =colormap[source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)]];
+ val = source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)];
if (val != TRANSPARENTPIXEL)
- *dest = colormap[*(ds_transmap + (source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)] << 8) + *dest)];
+ *dest = colormap[*(ds_transmap + (val << 8) + *dest)];
dest++;
xposition += xstep;
@@ -1363,7 +1363,19 @@ void R_DrawColumnShadowed_8(void)
height = dc_lightlist[i].height >> LIGHTSCALESHIFT;
if (solid)
+ {
bheight = dc_lightlist[i].botheight >> LIGHTSCALESHIFT;
+ if (bheight < height)
+ {
+ // confounded slopes sometimes allow partial invertedness,
+ // even including cases where the top and bottom heights
+ // should actually be the same!
+ // swap the height values as a workaround for this quirk
+ INT32 temp = height;
+ height = bheight;
+ bheight = temp;
+ }
+ }
if (height <= dc_yl)
{
dc_colormap = dc_lightlist[i].rcolormap;
diff --git a/src/r_main.c b/src/r_main.c
index e7c37cce..e50e8001 100644
--- a/src/r_main.c
+++ b/src/r_main.c
@@ -366,69 +366,6 @@ fixed_t R_PointToDist(fixed_t x, fixed_t y)
return R_PointToDist2(viewx, viewy, x, y);
}
-/***************************************
-*** Zdoom C++ to Legacy C conversion ***
-****************************************/
-
-// Utility to find the Z height at an XY location in a sector (for slopes)
-fixed_t R_SecplaneZatPoint(secplane_t *secplane, fixed_t x, fixed_t y)
-{
- return FixedMul(secplane->ic, -secplane->d - DMulScale16(secplane->a, x, secplane->b, y));
-}
-
-// Returns the value of z at (x,y) if d is equal to dist
-fixed_t R_SecplaneZatPointDist (secplane_t *secplane, fixed_t x, fixed_t y, fixed_t dist)
-{
- return FixedMul(secplane->ic, -dist - DMulScale16(secplane->a, x, secplane->b, y));
-}
-
-// Flips the plane's vertical orientiation, so that if it pointed up,
-// it will point down, and vice versa.
-void R_SecplaneFlipVert(secplane_t *secplane)
-{
- secplane->a = -secplane->a;
- secplane->b = -secplane->b;
- secplane->c = -secplane->c;
- secplane->d = -secplane->d;
- secplane->ic = -secplane->ic;
-}
-
-// Returns true if 2 planes are the same
-boolean R_ArePlanesSame(secplane_t *original, secplane_t *other)
-{
- return original->a == other->a && original->b == other->b
- && original->c == other->c && original->d == other->d;
-}
-
-// Returns true if 2 planes are different
-boolean R_ArePlanesDifferent(secplane_t *original, secplane_t *other)
-{
- return original->a != other->a || original->b != other->b
- || original->c != other->c || original->d != other->d;
-}
-
-// Moves a plane up/down by hdiff units
-void R_SecplaneChangeHeight(secplane_t *secplane, fixed_t hdiff)
-{
- secplane->d = secplane->d - FixedMul(hdiff, secplane->c);
-}
-
-// Returns how much this plane's height would change if d were set to oldd
-fixed_t R_SecplaneHeightDiff(secplane_t *secplane, fixed_t oldd)
-{
- return FixedMul(oldd - secplane->d, secplane->ic);
-}
-
-fixed_t R_SecplanePointToDist(secplane_t *secplane, fixed_t x, fixed_t y, fixed_t z)
-{
- return -TMulScale16(secplane->a, x, y, secplane->b, z, secplane->c);
-}
-
-fixed_t R_SecplanePointToDist2(secplane_t *secplane, fixed_t x, fixed_t y, fixed_t z)
-{
- return -TMulScale16(secplane->a, x, secplane->b, y, z, secplane->c);
-}
-
//
// R_ScaleFromGlobalAngle
// Returns the texture mapping scale for the current line (horizontal span)
@@ -795,7 +732,8 @@ subsector_t *R_IsPointInSubsector(fixed_t x, fixed_t y)
ret = &subsectors[nodenum & ~NF_SUBSECTOR];
for (i = 0; i < ret->numlines; i++)
- if (R_PointOnSegSide(x, y, &segs[ret->firstline + i]))
+ //if (R_PointOnSegSide(x, y, &segs[ret->firstline + i])) -- breaks in ogl because polyvertex_t cast over vertex pointers
+ if (P_PointOnLineSide(x, y, segs[ret->firstline + i].linedef) != segs[ret->firstline + i].side)
return 0;
return ret;
@@ -919,9 +857,9 @@ void R_SkyboxFrame(player_t *player)
}
}
if (mh->skybox_scalez > 0)
- viewz += player->awayviewmobj->z / mh->skybox_scalez;
+ viewz += (player->awayviewmobj->z + 20*FRACUNIT) / mh->skybox_scalez;
else if (mh->skybox_scalez < 0)
- viewz += player->awayviewmobj->z * -mh->skybox_scalez;
+ viewz += (player->awayviewmobj->z + 20*FRACUNIT) * -mh->skybox_scalez;
}
else if (thiscam->chase)
{
@@ -966,9 +904,9 @@ void R_SkyboxFrame(player_t *player)
}
}
if (mh->skybox_scalez > 0)
- viewz += thiscam->z / mh->skybox_scalez;
+ viewz += (thiscam->z + (thiscam->height>>1)) / mh->skybox_scalez;
else if (mh->skybox_scalez < 0)
- viewz += thiscam->z * -mh->skybox_scalez;
+ viewz += (thiscam->z + (thiscam->height>>1)) * -mh->skybox_scalez;
}
else
{
@@ -1324,6 +1262,7 @@ void R_RenderPlayerView(player_t *player)
#endif
R_RenderBSPNode((INT32)numnodes - 1);
+ R_ClipSprites();
R_DrawPlanes();
#ifdef FLOORSPLATS
R_DrawVisibleFloorSplats();
diff --git a/src/r_main.h b/src/r_main.h
index 8f46a938..2e768cb9 100644
--- a/src/r_main.h
+++ b/src/r_main.h
@@ -61,18 +61,6 @@ angle_t R_PointToAngle2(fixed_t px2, fixed_t py2, fixed_t px1, fixed_t py1);
fixed_t R_PointToDist(fixed_t x, fixed_t y);
fixed_t R_PointToDist2(fixed_t px2, fixed_t py2, fixed_t px1, fixed_t py1);
-// ZDoom C++ to Legacy C conversion Tails 04-29-2002
-fixed_t R_SecplaneZatPoint(secplane_t *secplane, fixed_t x, fixed_t y);
-fixed_t R_SecplaneZatPointDist(secplane_t *secplane, fixed_t x, fixed_t y,
- fixed_t dist);
-void R_SecplaneFlipVert(secplane_t *secplane);
-boolean R_ArePlanesSame(secplane_t *original, secplane_t *other);
-boolean R_ArePlanesDifferent(secplane_t *original, secplane_t *other);
-void R_SecplaneChangeHeight(secplane_t *secplane, fixed_t hdiff);
-fixed_t R_SecplaneHeightDiff(secplane_t *secplane, fixed_t oldd);
-fixed_t R_SecplanePointToDist(secplane_t *secplane, fixed_t x, fixed_t y, fixed_t z);
-fixed_t R_SecplanePointToDist2(secplane_t *secplane, fixed_t x, fixed_t y, fixed_t z);
-
fixed_t R_ScaleFromGlobalAngle(angle_t visangle);
subsector_t *R_PointInSubsector(fixed_t x, fixed_t y);
subsector_t *R_IsPointInSubsector(fixed_t x, fixed_t y);
diff --git a/src/r_plane.c b/src/r_plane.c
index 19007d88..b7b9eaff 100644
--- a/src/r_plane.c
+++ b/src/r_plane.c
@@ -431,6 +431,9 @@ static visplane_t *new_visplane(unsigned hash)
visplane_t *R_FindPlane(fixed_t height, INT32 picnum, INT32 lightlevel,
fixed_t xoff, fixed_t yoff, angle_t plangle, extracolormap_t *planecolormap,
ffloor_t *pfloor
+#ifdef POLYOBJECTS_PLANES
+ , polyobj_t *polyobj
+#endif
#ifdef ESLOPE
, pslope_t *slope
#endif
@@ -470,6 +473,8 @@ visplane_t *R_FindPlane(fixed_t height, INT32 picnum, INT32 lightlevel,
#ifdef POLYOBJECTS_PLANES
if (check->polyobj && pfloor)
continue;
+ if (polyobj != check->polyobj)
+ continue;
#endif
if (height == check->height && picnum == check->picnum
&& lightlevel == check->lightlevel
@@ -504,7 +509,7 @@ visplane_t *R_FindPlane(fixed_t height, INT32 picnum, INT32 lightlevel,
check->viewangle = viewangle;
check->plangle = plangle;
#ifdef POLYOBJECTS_PLANES
- check->polyobj = NULL;
+ check->polyobj = polyobj;
#endif
#ifdef ESLOPE
check->slope = slope;
@@ -719,7 +724,11 @@ void R_DrawPlanes(void)
continue;
}
- if (pl->ffloor != NULL)
+ if (pl->ffloor != NULL
+#ifdef POLYOBJECTS_PLANES
+ || pl->polyobj != NULL
+#endif
+ )
continue;
R_DrawSinglePlane(pl);
diff --git a/src/r_plane.h b/src/r_plane.h
index 8730bcef..16c8c12a 100644
--- a/src/r_plane.h
+++ b/src/r_plane.h
@@ -87,7 +87,7 @@ extern lighttable_t **planezlight;
extern fixed_t *yslope;
extern fixed_t distscale[MAXVIDWIDTH];
-void R_InitPlanes(void);
+FUNCMATH void R_InitPlanes(void);
void R_PortalStoreClipValues(INT32 start, INT32 end, INT16 *ceil, INT16 *floor, fixed_t *scale);
void R_PortalRestoreClipValues(INT32 start, INT32 end, INT16 *ceil, INT16 *floor, fixed_t *scale);
void R_ClearPlanes(void);
@@ -97,6 +97,9 @@ void R_MakeSpans(INT32 x, INT32 t1, INT32 b1, INT32 t2, INT32 b2);
void R_DrawPlanes(void);
visplane_t *R_FindPlane(fixed_t height, INT32 picnum, INT32 lightlevel, fixed_t xoff, fixed_t yoff, angle_t plangle,
extracolormap_t *planecolormap, ffloor_t *ffloor
+#ifdef POLYOBJECTS_PLANES
+ , polyobj_t *polyobj
+#endif
#ifdef ESLOPE
, pslope_t *slope
#endif
diff --git a/src/r_segs.c b/src/r_segs.c
index 11b4c8ae..502ff330 100644
--- a/src/r_segs.c
+++ b/src/r_segs.c
@@ -300,7 +300,7 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2)
curline = ds->curline;
frontsector = curline->frontsector;
backsector = curline->backsector;
- texnum = texturetranslation[curline->sidedef->midtexture];
+ texnum = R_GetTextureNum(curline->sidedef->midtexture);
windowbottom = windowtop = sprbotscreen = INT32_MAX;
// hack translucent linedef types (900-909 for transtables 1-9)
@@ -344,6 +344,9 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2)
rw_scalestep = ds->scalestep;
spryscale = ds->scale1 + (x1 - ds->x1)*rw_scalestep;
+ // Texture must be cached before setting colfunc_2s,
+ // otherwise texture[texnum]->holes may be false when it shouldn't be
+ R_CheckTextureCache(texnum);
// handle case where multipatch texture is drawn on a 2sided wall, multi-patch textures
// are not stored per-column with post info in SRB2
if (textures[texnum]->holes)
@@ -391,6 +394,7 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2)
rlight->height = (centeryfrac) - FixedMul((light->height - viewz), spryscale);
rlight->heightstep = -FixedMul(rw_scalestep, (light->height - viewz));
#endif
+ rlight->startheight = rlight->height; // keep starting value here to reset for each repeat
rlight->lightlevel = *light->lightlevel;
rlight->extra_colormap = light->extra_colormap;
rlight->flags = light->flags;
@@ -484,6 +488,14 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2)
{
rw_scalestep = ds->scalestep;
spryscale = ds->scale1 + (x1 - ds->x1)*rw_scalestep;
+ if (dc_numlights)
+ { // reset all lights to their starting heights
+ for (i = 0; i < dc_numlights; i++)
+ {
+ rlight = &dc_lightlist[i];
+ rlight->height = rlight->startheight;
+ }
+ }
}
#ifndef ESLOPE
@@ -694,10 +706,13 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2)
// Loop through R_DrawMaskedColumn calls
static void R_DrawRepeatMaskedColumn(column_t *col)
{
- do {
+ while (sprtopscreen < sprbotscreen) {
R_DrawMaskedColumn(col);
- sprtopscreen += dc_texheight*spryscale;
- } while (sprtopscreen < sprbotscreen);
+ if ((INT64)sprtopscreen + dc_texheight*spryscale > (INT64)INT32_MAX) // prevent overflow
+ sprtopscreen = INT32_MAX;
+ else
+ sprtopscreen += dc_texheight*spryscale;
+ }
}
//
@@ -740,7 +755,7 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
curline = ds->curline;
backsector = pfloor->target;
frontsector = curline->frontsector == pfloor->target ? curline->backsector : curline->frontsector;
- texnum = texturetranslation[sides[pfloor->master->sidenum[0]].midtexture];
+ texnum = R_GetTextureNum(sides[pfloor->master->sidenum[0]].midtexture);
colfunc = wallcolfunc;
@@ -748,7 +763,7 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
{
size_t linenum = curline->linedef-backsector->lines[0];
newline = pfloor->master->frontsector->lines[0] + linenum;
- texnum = texturetranslation[sides[newline->sidenum[0]].midtexture];
+ texnum = R_GetTextureNum(sides[newline->sidenum[0]].midtexture);
}
if (pfloor->flags & FF_TRANSLUCENT)
@@ -968,6 +983,9 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
dc_texturemid += offsetvalue;
+ // Texture must be cached before setting colfunc_2s,
+ // otherwise texture[texnum]->holes may be false when it shouldn't be
+ R_CheckTextureCache(texnum);
//faB: handle case where multipatch texture is drawn on a 2sided wall, multi-patch textures
// are not stored per-column with post info anymore in Doom Legacy
if (textures[texnum]->holes)
@@ -1453,34 +1471,45 @@ static void R_RenderSegLoop (void)
frontscale[rw_x] = rw_scale;
// draw the wall tiers
- if (midtexture && yl <= yh && yh < vid.height && yh > 0)
+ if (midtexture)
{
// single sided line
- dc_yl = yl;
- dc_yh = yh;
- dc_texturemid = rw_midtexturemid;
- dc_source = R_GetColumn(midtexture,texturecolumn);
- dc_texheight = textureheight[midtexture]>>FRACBITS;
+ if (yl <= yh && yh >= 0 && yl < viewheight)
+ {
+ dc_yl = yl;
+ dc_yh = yh;
+ dc_texturemid = rw_midtexturemid;
+ dc_source = R_GetColumn(midtexture,texturecolumn);
+ dc_texheight = textureheight[midtexture]>>FRACBITS;
- //profile stuff ---------------------------------------------------------
+ //profile stuff ---------------------------------------------------------
#ifdef TIMING
- ProfZeroTimer();
+ ProfZeroTimer();
#endif
- colfunc();
+ colfunc();
#ifdef TIMING
- RDMSR(0x10,&mycount);
- mytotal += mycount; //64bit add
+ RDMSR(0x10,&mycount);
+ mytotal += mycount; //64bit add
- if (nombre--==0)
- I_Error("R_DrawColumn CPU Spy reports: 0x%d %d\n", *((INT32 *)&mytotal+1),
- (INT32)mytotal);
+ if (nombre--==0)
+ I_Error("R_DrawColumn CPU Spy reports: 0x%d %d\n", *((INT32 *)&mytotal+1),
+ (INT32)mytotal);
#endif
- //profile stuff ---------------------------------------------------------
+ //profile stuff ---------------------------------------------------------
- // dont draw anything more for this column, since
- // a midtexture blocks the view
- ceilingclip[rw_x] = (INT16)viewheight;
- floorclip[rw_x] = -1;
+ // dont draw anything more for this column, since
+ // a midtexture blocks the view
+ ceilingclip[rw_x] = (INT16)viewheight;
+ floorclip[rw_x] = -1;
+ }
+ else
+ {
+ // note: don't use min/max macros, since casting from INT32 to INT16 is involved here
+ if (markceiling)
+ ceilingclip[rw_x] = (yl >= 0) ? ((yl > viewheight) ? (INT16)viewheight : (INT16)((INT16)yl - 1)) : -1;
+ if (markfloor)
+ floorclip[rw_x] = (yh < viewheight) ? ((yh < -1) ? -1 : (INT16)((INT16)yh + 1)) : (INT16)viewheight;
+ }
}
else
{
@@ -1494,21 +1523,28 @@ static void R_RenderSegLoop (void)
if (mid >= floorclip[rw_x])
mid = floorclip[rw_x]-1;
- if (mid >= yl && yh < vid.height && yh > 0)
+ if (mid >= yl) // back ceiling lower than front ceiling ?
{
- dc_yl = yl;
- dc_yh = mid;
- dc_texturemid = rw_toptexturemid;
- dc_source = R_GetColumn(toptexture,texturecolumn);
- dc_texheight = textureheight[toptexture]>>FRACBITS;
- colfunc();
- ceilingclip[rw_x] = (INT16)mid;
+ if (yl >= viewheight) // entirely off bottom of screen
+ ceilingclip[rw_x] = (INT16)viewheight;
+ else if (mid >= 0) // safe to draw top texture
+ {
+ dc_yl = yl;
+ dc_yh = mid;
+ dc_texturemid = rw_toptexturemid;
+ dc_source = R_GetColumn(toptexture,texturecolumn);
+ dc_texheight = textureheight[toptexture]>>FRACBITS;
+ colfunc();
+ ceilingclip[rw_x] = (INT16)mid;
+ }
+ else // entirely off top of screen
+ ceilingclip[rw_x] = -1;
}
else
- ceilingclip[rw_x] = (INT16)((INT16)yl - 1);
+ ceilingclip[rw_x] = (yl >= 0) ? ((yl > viewheight) ? (INT16)viewheight : (INT16)((INT16)yl - 1)) : -1;
}
else if (markceiling) // no top wall
- ceilingclip[rw_x] = (INT16)((INT16)yl - 1);
+ ceilingclip[rw_x] = (yl >= 0) ? ((yl > viewheight) ? (INT16)viewheight : (INT16)((INT16)yl - 1)) : -1;
if (bottomtexture)
{
@@ -1520,22 +1556,29 @@ static void R_RenderSegLoop (void)
if (mid <= ceilingclip[rw_x])
mid = ceilingclip[rw_x]+1;
- if (mid <= yh && yh < vid.height && yh > 0)
+ if (mid <= yh) // back floor higher than front floor ?
{
- dc_yl = mid;
- dc_yh = yh;
- dc_texturemid = rw_bottomtexturemid;
- dc_source = R_GetColumn(bottomtexture,
- texturecolumn);
- dc_texheight = textureheight[bottomtexture]>>FRACBITS;
- colfunc();
- floorclip[rw_x] = (INT16)mid;
+ if (yh < 0) // entirely off top of screen
+ floorclip[rw_x] = -1;
+ else if (mid < viewheight) // safe to draw bottom texture
+ {
+ dc_yl = mid;
+ dc_yh = yh;
+ dc_texturemid = rw_bottomtexturemid;
+ dc_source = R_GetColumn(bottomtexture,
+ texturecolumn);
+ dc_texheight = textureheight[bottomtexture]>>FRACBITS;
+ colfunc();
+ floorclip[rw_x] = (INT16)mid;
+ }
+ else // entirely off bottom of screen
+ floorclip[rw_x] = (INT16)viewheight;
}
else
- floorclip[rw_x] = (INT16)((INT16)yh + 1);
+ floorclip[rw_x] = (yh < viewheight) ? ((yh < -1) ? -1 : (INT16)((INT16)yh + 1)) : (INT16)viewheight;
}
else if (markfloor) // no bottom wall
- floorclip[rw_x] = (INT16)((INT16)yh + 1);
+ floorclip[rw_x] = (yh < viewheight) ? ((yh < -1) ? -1 : (INT16)((INT16)yh + 1)) : (INT16)viewheight;
}
if (maskedtexture || numthicksides)
@@ -1853,25 +1896,28 @@ void R_StoreWallRange(INT32 start, INT32 stop)
if (!backsector)
{
+ fixed_t texheight;
// single sided line
- midtexture = texturetranslation[sidedef->midtexture];
+ midtexture = R_GetTextureNum(sidedef->midtexture);
+ texheight = textureheight[midtexture];
// a single sided line is terminal, so it must mark ends
markfloor = markceiling = true;
#ifdef ESLOPE
- if (!(linedef->flags & ML_EFFECT1)) {
+ if (linedef->flags & ML_EFFECT2) {
if (linedef->flags & ML_DONTPEGBOTTOM)
- rw_midtexturemid = frontsector->floorheight + textureheight[sidedef->midtexture] - viewz;
+ rw_midtexturemid = frontsector->floorheight + texheight - viewz;
else
- rw_midtexturemid = frontsector->ceilingheight;
+ rw_midtexturemid = frontsector->ceilingheight - viewz;
}
+ else
#endif
if (linedef->flags & ML_DONTPEGBOTTOM)
{
#ifdef ESLOPE
- rw_midtexturemid = worldbottom + textureheight[sidedef->midtexture];
+ rw_midtexturemid = worldbottom + texheight;
rw_midtextureslide = floorfrontslide;
#else
- vtop = frontsector->floorheight + textureheight[sidedef->midtexture];
+ vtop = frontsector->floorheight + texheight;
// bottom of texture at bottom
rw_midtexturemid = vtop - viewz;
#endif
@@ -2103,76 +2149,50 @@ void R_StoreWallRange(INT32 start, INT32 stop)
#endif
)
{
+ fixed_t texheight;
// top texture
if ((linedef->flags & (ML_DONTPEGTOP) && (linedef->flags & ML_DONTPEGBOTTOM))
&& linedef->sidenum[1] != 0xffff)
{
// Special case... use offsets from 2nd side but only if it has a texture.
side_t *def = &sides[linedef->sidenum[1]];
- toptexture = texturetranslation[def->toptexture];
+ toptexture = R_GetTextureNum(def->toptexture);
if (!toptexture) //Second side has no texture, use the first side's instead.
- toptexture = texturetranslation[sidedef->toptexture];
-
-#ifdef ESLOPE
- if (!(linedef->flags & ML_EFFECT1)) { // Ignore slopes for lower/upper textures unless flag is checked
- if (linedef->flags & ML_DONTPEGTOP)
- rw_toptexturemid = frontsector->ceilingheight - viewz;
- else
- rw_toptexturemid = backsector->ceilingheight - viewz;
- } else
-#endif
- if (linedef->flags & ML_DONTPEGTOP)
- {
- // top of texture at top
- rw_toptexturemid = worldtop;
-#ifdef ESLOPE
- rw_toptextureslide = ceilingfrontslide;
-#endif
- }
- else
- {
-#ifdef ESLOPE
- rw_toptexturemid = worldhigh + textureheight[def->toptexture];
- rw_toptextureslide = ceilingbackslide;
-#else
- vtop = backsector->ceilingheight + textureheight[def->toptexture];
- // bottom of texture
- rw_toptexturemid = vtop - viewz;
-#endif
- }
+ toptexture = R_GetTextureNum(sidedef->toptexture);
+ texheight = textureheight[toptexture];
}
else
{
- toptexture = texturetranslation[sidedef->toptexture];
-
+ toptexture = R_GetTextureNum(sidedef->toptexture);
+ texheight = textureheight[toptexture];
+ }
#ifdef ESLOPE
- if (!(linedef->flags & ML_EFFECT1)) { // Ignore slopes for lower/upper textures unless flag is checked
- if (linedef->flags & ML_DONTPEGTOP)
- rw_toptexturemid = frontsector->ceilingheight - viewz;
- else
- rw_toptexturemid = backsector->ceilingheight - viewz;
- } else
-#endif
+ if (!(linedef->flags & ML_EFFECT1)) { // Ignore slopes for lower/upper textures unless flag is checked
if (linedef->flags & ML_DONTPEGTOP)
- {
- // top of texture at top
- rw_toptexturemid = worldtop;
-#ifdef ESLOPE
- rw_toptextureslide = ceilingfrontslide;
-#endif
- }
+ rw_toptexturemid = frontsector->ceilingheight - viewz;
else
- {
-#ifdef ESLOPE
- rw_toptexturemid = worldhigh + textureheight[sidedef->toptexture];
- rw_toptextureslide = ceilingbackslide;
-#else
- vtop = backsector->ceilingheight + textureheight[sidedef->toptexture];
- // bottom of texture
- rw_toptexturemid = vtop - viewz;
+ rw_toptexturemid = backsector->ceilingheight - viewz;
+ } else
+#endif
+ if (linedef->flags & ML_DONTPEGTOP)
+ {
+ // top of texture at top
+ rw_toptexturemid = worldtop;
+#ifdef ESLOPE
+ rw_toptextureslide = ceilingfrontslide;
+#endif
+ }
+ else
+ {
+#ifdef ESLOPE
+ rw_toptexturemid = worldhigh + texheight;
+ rw_toptextureslide = ceilingbackslide;
+#else
+ vtop = backsector->ceilingheight + texheight;
+ // bottom of texture
+ rw_toptexturemid = vtop - viewz;
#endif
- }
}
}
// check BOTTOM TEXTURE
@@ -2183,7 +2203,7 @@ void R_StoreWallRange(INT32 start, INT32 stop)
) //seulement si VISIBLE!!!
{
// bottom texture
- bottomtexture = texturetranslation[sidedef->bottomtexture];
+ bottomtexture = R_GetTextureNum(sidedef->bottomtexture);
#ifdef ESLOPE
if (!(linedef->flags & ML_EFFECT1)) { // Ignore slopes for lower/upper textures unless flag is checked
@@ -2468,7 +2488,7 @@ void R_StoreWallRange(INT32 start, INT32 stop)
ds_p->numthicksides = numthicksides = i;
}
- if (sidedef->midtexture)
+ if (sidedef->midtexture > 0 && sidedef->midtexture < numtextures)
{
// masked midtexture
if (!ds_p->thicksidecol)
@@ -2482,6 +2502,15 @@ void R_StoreWallRange(INT32 start, INT32 stop)
#ifdef ESLOPE
maskedtextureheight = ds_p->maskedtextureheight; // note to red, this == &(ds_p->maskedtextureheight[0])
+#ifdef POLYOBJECTS
+ if (curline->polyseg) { // use REAL front and back floors please, so midtexture rendering isn't mucked up
+ rw_midtextureslide = rw_midtexturebackslide = 0;
+ if (!!(linedef->flags & ML_DONTPEGBOTTOM) ^ !!(linedef->flags & ML_EFFECT3))
+ rw_midtexturemid = rw_midtextureback = max(curline->frontsector->floorheight, curline->backsector->floorheight) - viewz;
+ else
+ rw_midtexturemid = rw_midtextureback = min(curline->frontsector->ceilingheight, curline->backsector->ceilingheight) - viewz;
+ } else
+#endif
// Set midtexture starting height
if (linedef->flags & ML_EFFECT2) { // Ignore slopes when texturing
rw_midtextureslide = rw_midtexturebackslide = 0;
@@ -3066,12 +3095,12 @@ void R_StoreWallRange(INT32 start, INT32 stop)
if (maskedtexture && !(ds_p->silhouette & SIL_TOP))
{
ds_p->silhouette |= SIL_TOP;
- ds_p->tsilheight = sidedef->midtexture ? INT32_MIN: INT32_MAX;
+ ds_p->tsilheight = (sidedef->midtexture > 0 && sidedef->midtexture < numtextures) ? INT32_MIN: INT32_MAX;
}
if (maskedtexture && !(ds_p->silhouette & SIL_BOTTOM))
{
ds_p->silhouette |= SIL_BOTTOM;
- ds_p->bsilheight = sidedef->midtexture ? INT32_MAX: INT32_MIN;
+ ds_p->bsilheight = (sidedef->midtexture > 0 && sidedef->midtexture < numtextures) ? INT32_MAX: INT32_MIN;
}
ds_p++;
}
diff --git a/src/r_splats.h b/src/r_splats.h
index 349d8fa7..c0ba6881 100644
--- a/src/r_splats.h
+++ b/src/r_splats.h
@@ -63,7 +63,11 @@ typedef struct floorsplat_s
fixed_t P_SegLength(seg_t *seg);
// call at P_SetupLevel()
+#if !(defined (WALLSPLATS) || defined (FLOORSPLATS))
+FUNCMATH void R_ClearLevelSplats(void);
+#else
void R_ClearLevelSplats(void);
+#endif
#ifdef WALLSPLATS
void R_AddWallSplat(line_t *wallline, INT16 sectorside, const char *patchname, fixed_t top,
diff --git a/src/r_things.c b/src/r_things.c
index eaab5361..331febab 100644
--- a/src/r_things.c
+++ b/src/r_things.c
@@ -280,7 +280,7 @@ static boolean R_AddSingleSpriteDef(const char *sprname, spritedef_t *spritedef,
{
case 0xff:
// no rotations were found for that frame at all
- I_Error("R_AddSingleSpriteDef: No patches found for %s frame %c", sprname, R_Frame2Char(frame));
+ I_Error("R_AddSingleSpriteDef: No patches found for %.4s frame %c", sprname, R_Frame2Char(frame));
break;
case 0:
@@ -293,7 +293,7 @@ static boolean R_AddSingleSpriteDef(const char *sprname, spritedef_t *spritedef,
// we test the patch lump, or the id lump whatever
// if it was not loaded the two are LUMPERROR
if (sprtemp[frame].lumppat[rotation] == LUMPERROR)
- I_Error("R_AddSingleSpriteDef: Sprite %s frame %c is missing rotations",
+ I_Error("R_AddSingleSpriteDef: Sprite %.4s frame %c is missing rotations",
sprname, R_Frame2Char(frame));
break;
}
@@ -891,12 +891,18 @@ static void R_DrawPrecipitationVisSprite(vissprite_t *vis)
#endif
fixed_t frac;
patch_t *patch;
+ INT64 overflow_test;
//Fab : R_InitSprites now sets a wad lump number
patch = W_CacheLumpNum(vis->patch, PU_CACHE);
if (!patch)
return;
+ // Check for overflow
+ overflow_test = (INT64)centeryfrac - (((INT64)vis->texturemid*vis->scale)>>FRACBITS);
+ if (overflow_test < 0) overflow_test = -overflow_test;
+ if ((UINT64)overflow_test&0xFFFFFFFF80000000ULL) return; // fixed point mult would overflow
+
if (vis->transmap)
{
colfunc = fuzzcolfunc;
@@ -1634,7 +1640,8 @@ void R_SortVisSprites(void)
// Fix first and last. ds still points to the last one after the loop
dsfirst->prev = &unsorted;
unsorted.next = dsfirst;
- ds->next = &unsorted;
+ if (ds)
+ ds->next = &unsorted;
unsorted.prev = ds;
// pull the vissprites out by scale
@@ -1698,21 +1705,25 @@ static void R_CreateDrawNodes(void)
entry->ffloor = ds->thicksides[i];
}
}
+#ifdef POLYOBJECTS_PLANES
+ // Check for a polyobject plane, but only if this is a front line
+ if (ds->curline->polyseg && ds->curline->polyseg->visplane && !ds->curline->side) {
+ plane = ds->curline->polyseg->visplane;
+ R_PlaneBounds(plane);
+
+ if (plane->low < con_clipviewtop || plane->high > vid.height || plane->high > plane->low)
+ ;
+ else {
+ // Put it in!
+ entry = R_CreateDrawNode(&nodehead);
+ entry->plane = plane;
+ entry->seg = ds;
+ }
+ ds->curline->polyseg->visplane = NULL;
+ }
+#endif
if (ds->maskedtexturecol)
{
-#ifdef POLYOBJECTS_PLANES
- // Check for a polyobject plane, but only if this is a front line
- if (ds->curline->polyseg && ds->curline->polyseg->visplane && !ds->curline->side) {
- // Put it in!
-
- entry = R_CreateDrawNode(&nodehead);
- entry->plane = ds->curline->polyseg->visplane;
- entry->seg = ds;
- ds->curline->polyseg->visplane->polyobj = ds->curline->polyseg;
- ds->curline->polyseg->visplane = NULL;
- }
-#endif
-
entry = R_CreateDrawNode(&nodehead);
entry->seg = ds;
}
@@ -1755,6 +1766,29 @@ static void R_CreateDrawNodes(void)
}
}
+#ifdef POLYOBJECTS_PLANES
+ // find all the remaining polyobject planes and add them on the end of the list
+ // probably this is a terrible idea if we wanted them to be sorted properly
+ // but it works getting them in for now
+ for (i = 0; i < numPolyObjects; i++)
+ {
+ if (!PolyObjects[i].visplane)
+ continue;
+ plane = PolyObjects[i].visplane;
+ R_PlaneBounds(plane);
+
+ if (plane->low < con_clipviewtop || plane->high > vid.height || plane->high > plane->low)
+ {
+ PolyObjects[i].visplane = NULL;
+ continue;
+ }
+ entry = R_CreateDrawNode(&nodehead);
+ entry->plane = plane;
+ // note: no seg is set, for what should be obvious reasons
+ PolyObjects[i].visplane = NULL;
+ }
+#endif
+
if (visspritecount == 0)
return;
@@ -1811,13 +1845,16 @@ static void R_CreateDrawNodes(void)
if (x1 < r2->plane->minx) x1 = r2->plane->minx;
if (x2 > r2->plane->maxx) x2 = r2->plane->maxx;
- for (i = x1; i <= x2; i++)
+ if (r2->seg) // if no seg set, assume the whole thing is in front or something stupid
{
- if (r2->seg->frontscale[i] > rover->scale)
- break;
+ for (i = x1; i <= x2; i++)
+ {
+ if (r2->seg->frontscale[i] > rover->scale)
+ break;
+ }
+ if (i > x2)
+ continue;
}
- if (i > x2)
- continue;
entry = R_CreateDrawNode(NULL);
(entry->prev = r2->prev)->next = entry;
diff --git a/src/s_sound.h b/src/s_sound.h
index bcc7979a..39ec769a 100644
--- a/src/s_sound.h
+++ b/src/s_sound.h
@@ -119,7 +119,7 @@ void S_ResumeAudio(void);
//
void S_UpdateSounds(void);
-fixed_t S_CalculateSoundDistance(fixed_t px1, fixed_t py1, fixed_t pz1, fixed_t px2, fixed_t py2, fixed_t pz2);
+FUNCMATH fixed_t S_CalculateSoundDistance(fixed_t px1, fixed_t py1, fixed_t pz1, fixed_t px2, fixed_t py2, fixed_t pz2);
void S_SetDigMusicVolume(INT32 volume);
void S_SetMIDIMusicVolume(INT32 volume);
diff --git a/src/screen.c b/src/screen.c
index 3834f72d..2780edb6 100644
--- a/src/screen.c
+++ b/src/screen.c
@@ -30,7 +30,7 @@
#include "f_finale.h"
-#if defined (USEASM) //&& (!defined (_MSC_VER) || (_MSC_VER <= 1200))
+#if defined (USEASM) && !defined (NORUSEASM)//&& (!defined (_MSC_VER) || (_MSC_VER <= 1200))
#define RUSEASM //MSC.NET can't patch itself
#endif
@@ -69,6 +69,13 @@ consvar_t cv_scr_height = {"scr_height", "800", CV_SAVE, CV_Unsigned, NULL, 0, N
consvar_t cv_scr_depth = {"scr_depth", "16 bits", CV_SAVE, scr_depth_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
#endif
consvar_t cv_renderview = {"renderview", "On", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
+
+#ifdef DIRECTFULLSCREEN
+static FUNCMATH void SCR_ChangeFullscreen (void);
+#else
+static void SCR_ChangeFullscreen (void);
+#endif
+
consvar_t cv_fullscreen = {"fullscreen", "Yes", CV_SAVE|CV_CALL, CV_YesNo, SCR_ChangeFullscreen, 0, NULL, NULL, 0, 0, NULL};
// =========================================================================
diff --git a/src/screen.h b/src/screen.h
index bdf8e5a7..2dff4590 100644
--- a/src/screen.h
+++ b/src/screen.h
@@ -175,9 +175,7 @@ void SCR_SetDefaultMode (void);
void SCR_Startup (void);
-void SCR_ChangeFullscreen (void);
-
-boolean SCR_IsAspectCorrect(INT32 width, INT32 height);
+FUNCMATH boolean SCR_IsAspectCorrect(INT32 width, INT32 height);
// move out to main code for consistency
void SCR_DisplayTicRate(void);
diff --git a/src/sdl/MakeNIX.cfg b/src/sdl/MakeNIX.cfg
index f5c9b207..1a0b5421 100644
--- a/src/sdl/MakeNIX.cfg
+++ b/src/sdl/MakeNIX.cfg
@@ -56,6 +56,15 @@ ifdef FREEBSD
LIBS+=-lipx -lkvm
endif
+#
+#here is Mac OS X
+#
+ifdef MACOSX
+ OBJS+=$(OBJDIR)/mac_resources.o
+ OBJS+=$(OBJDIR)/mac_alert.o
+ LIBS+=-framework CoreFoundation
+endif
+
#
#here is GP2x (arm-gp2x-linux)
#
diff --git a/src/sdl/Srb2SDL-vc10.vcxproj b/src/sdl/Srb2SDL-vc10.vcxproj
index d12a7efb..82019264 100644
--- a/src/sdl/Srb2SDL-vc10.vcxproj
+++ b/src/sdl/Srb2SDL-vc10.vcxproj
@@ -167,6 +167,7 @@
+
@@ -308,6 +309,7 @@
+
diff --git a/src/sdl/Srb2SDL-vc10.vcxproj.filters b/src/sdl/Srb2SDL-vc10.vcxproj.filters
index 9396b482..d04007dd 100644
--- a/src/sdl/Srb2SDL-vc10.vcxproj.filters
+++ b/src/sdl/Srb2SDL-vc10.vcxproj.filters
@@ -294,6 +294,9 @@
M_Misc
+
+ M_Misc
+
M_Misc
@@ -666,6 +669,9 @@
M_Misc
+
+ M_Misc
+
M_Misc
diff --git a/src/sdl/i_cdmus.c b/src/sdl/i_cdmus.c
index f3f70366..3105f512 100644
--- a/src/sdl/i_cdmus.c
+++ b/src/sdl/i_cdmus.c
@@ -12,25 +12,25 @@ consvar_t cd_volume = {"cd_volume","31",CV_SAVE,soundvolume_cons_t, NULL, 0, NUL
consvar_t cdUpdate = {"cd_update","1",CV_SAVE, NULL, NULL, 0, NULL, NULL, 0, 0, NULL};
-void I_InitCD(void){}
+FUNCMATH void I_InitCD(void){}
-void I_StopCD(void){}
+FUNCMATH void I_StopCD(void){}
-void I_PauseCD(void){}
+FUNCMATH void I_PauseCD(void){}
-void I_ResumeCD(void){}
+FUNCMATH void I_ResumeCD(void){}
-void I_ShutdownCD(void){}
+FUNCMATH void I_ShutdownCD(void){}
-void I_UpdateCD(void){}
+FUNCMATH void I_UpdateCD(void){}
-void I_PlayCD(UINT8 track, UINT8 looping)
+FUNCMATH void I_PlayCD(UINT8 track, UINT8 looping)
{
(void)track;
(void)looping;
}
-boolean I_SetVolumeCD(int volume)
+FUNCMATH boolean I_SetVolumeCD(int volume)
{
(void)volume;
return false;
diff --git a/src/sdl/i_system.c b/src/sdl/i_system.c
index 0212e620..f72a9857 100644
--- a/src/sdl/i_system.c
+++ b/src/sdl/i_system.c
@@ -590,70 +590,78 @@ static BOOL I_ReadyConsole(HANDLE ci)
static boolean entering_con_command = false;
+static void Impl_HandleKeyboardConsoleEvent(KEY_EVENT_RECORD evt, HANDLE co)
+{
+ event_t event;
+ CONSOLE_SCREEN_BUFFER_INFO CSBI;
+ DWORD t;
+
+ memset(&event,0x00,sizeof (event));
+
+ if (evt.bKeyDown)
+ {
+ event.type = ev_console;
+ entering_con_command = true;
+ switch (evt.wVirtualKeyCode)
+ {
+ case VK_ESCAPE:
+ case VK_TAB:
+ event.data1 = KEY_NULL;
+ break;
+ case VK_SHIFT:
+ event.data1 = KEY_LSHIFT;
+ break;
+ case VK_RETURN:
+ entering_con_command = false;
+ // Fall through.
+ default:
+ event.data1 = MapVirtualKey(evt.wVirtualKeyCode,2); // convert in to char
+ }
+ if (co != INVALID_HANDLE_VALUE && GetFileType(co) == FILE_TYPE_CHAR && GetConsoleMode(co, &t))
+ {
+ if (event.data1 && event.data1 != KEY_LSHIFT && event.data1 != KEY_RSHIFT)
+ {
+#ifdef _UNICODE
+ WriteConsole(co, &evt.uChar.UnicodeChar, 1, &t, NULL);
+#else
+ WriteConsole(co, &evt.uChar.AsciiChar, 1 , &t, NULL);
+#endif
+ }
+ if (evt.wVirtualKeyCode == VK_BACK
+ && GetConsoleScreenBufferInfo(co,&CSBI))
+ {
+ WriteConsoleOutputCharacterA(co, " ",1, CSBI.dwCursorPosition, &t);
+ }
+ }
+ }
+ else
+ {
+ event.type = ev_keyup;
+ switch (evt.wVirtualKeyCode)
+ {
+ case VK_SHIFT:
+ event.data1 = KEY_LSHIFT;
+ break;
+ default:
+ break;
+ }
+ }
+ if (event.data1) D_PostEvent(&event);
+}
+
void I_GetConsoleEvents(void)
{
- event_t ev = {0,0,0,0};
HANDLE ci = GetStdHandle(STD_INPUT_HANDLE);
HANDLE co = GetStdHandle(STD_OUTPUT_HANDLE);
- CONSOLE_SCREEN_BUFFER_INFO CSBI;
INPUT_RECORD input;
DWORD t;
while (I_ReadyConsole(ci) && ReadConsoleInput(ci, &input, 1, &t) && t)
{
- memset(&ev,0x00,sizeof (ev));
switch (input.EventType)
{
case KEY_EVENT:
- if (input.Event.KeyEvent.bKeyDown)
- {
- ev.type = ev_console;
- entering_con_command = true;
- switch (input.Event.KeyEvent.wVirtualKeyCode)
- {
- case VK_ESCAPE:
- case VK_TAB:
- ev.data1 = KEY_NULL;
- break;
- case VK_SHIFT:
- ev.data1 = KEY_LSHIFT;
- break;
- case VK_RETURN:
- entering_con_command = false;
- // Fall through.
- default:
- ev.data1 = MapVirtualKey(input.Event.KeyEvent.wVirtualKeyCode,2); // convert in to char
- }
- if (co != INVALID_HANDLE_VALUE && GetFileType(co) == FILE_TYPE_CHAR && GetConsoleMode(co, &t))
- {
- if (ev.data1 && ev.data1 != KEY_LSHIFT && ev.data1 != KEY_RSHIFT)
- {
-#ifdef _UNICODE
- WriteConsole(co, &input.Event.KeyEvent.uChar.UnicodeChar, 1, &t, NULL);
-#else
- WriteConsole(co, &input.Event.KeyEvent.uChar.AsciiChar, 1 , &t, NULL);
-#endif
- }
- if (input.Event.KeyEvent.wVirtualKeyCode == VK_BACK
- && GetConsoleScreenBufferInfo(co,&CSBI))
- {
- WriteConsoleOutputCharacterA(co, " ",1, CSBI.dwCursorPosition, &t);
- }
- }
- }
- else
- {
- ev.type = ev_keyup;
- switch (input.Event.KeyEvent.wVirtualKeyCode)
- {
- case VK_SHIFT:
- ev.data1 = KEY_LSHIFT;
- break;
- default:
- break;
- }
- }
- if (ev.data1) D_PostEvent(&ev);
+ Impl_HandleKeyboardConsoleEvent(input.Event.KeyEvent, co);
break;
case MOUSE_EVENT:
case WINDOW_BUFFER_SIZE_EVENT:
@@ -2049,14 +2057,14 @@ void I_StartupMouse2(void)
//
// I_Tactile
//
-void I_Tactile(FFType pFFType, const JoyFF_t *FFEffect)
+FUNCMATH void I_Tactile(FFType pFFType, const JoyFF_t *FFEffect)
{
// UNUSED.
(void)pFFType;
(void)FFEffect;
}
-void I_Tactile2(FFType pFFType, const JoyFF_t *FFEffect)
+FUNCMATH void I_Tactile2(FFType pFFType, const JoyFF_t *FFEffect)
{
// UNUSED.
(void)pFFType;
@@ -2067,7 +2075,7 @@ void I_Tactile2(FFType pFFType, const JoyFF_t *FFEffect)
*/
static ticcmd_t emptycmd;
-ticcmd_t *I_BaseTiccmd(void)
+FUNCMATH ticcmd_t *I_BaseTiccmd(void)
{
return &emptycmd;
}
@@ -2076,7 +2084,7 @@ ticcmd_t *I_BaseTiccmd(void)
*/
static ticcmd_t emptycmd2;
-ticcmd_t *I_BaseTiccmd2(void)
+FUNCMATH ticcmd_t *I_BaseTiccmd2(void)
{
return &emptycmd2;
}
@@ -2179,7 +2187,7 @@ tic_t I_GetTime (void)
//
//I_StartupTimer
//
-void I_StartupTimer(void)
+FUNCMATH void I_StartupTimer(void)
{
#if (defined (_WIN32) && !defined (_WIN32_WCE)) && !defined (_XBOX)
// for win2k time bug
@@ -2313,11 +2321,11 @@ void I_WaitVBL(INT32 count)
SDL_Delay(count);
}
-void I_BeginRead(void)
+FUNCMATH void I_BeginRead(void)
{
}
-void I_EndRead(void)
+FUNCMATH void I_EndRead(void)
{
}
@@ -2647,6 +2655,47 @@ INT32 I_PutEnv(char *variable)
#endif
}
+INT32 I_ClipboardCopy(const char *data, size_t size)
+{
+ char storage[256];
+ if (size > 255)
+ size = 255;
+ memcpy(storage, data, size);
+ storage[size] = 0;
+
+ if (SDL_SetClipboardText(storage))
+ return 0;
+ return -1;
+}
+
+const char *I_ClipboardPaste(void)
+{
+ static char clipboard_modified[256];
+ char *clipboard_contents, *i = clipboard_modified;
+
+ if (!SDL_HasClipboardText())
+ return NULL;
+ clipboard_contents = SDL_GetClipboardText();
+ memcpy(clipboard_modified, clipboard_contents, 255);
+ SDL_free(clipboard_contents);
+ clipboard_modified[255] = 0;
+
+ while (*i)
+ {
+ if (*i == '\n' || *i == '\r')
+ { // End on newline
+ *i = 0;
+ break;
+ }
+ else if (*i == '\t')
+ *i = ' '; // Tabs become spaces
+ else if (*i < 32 || (unsigned)*i > 127)
+ *i = '?'; // Nonprintable chars become question marks
+ ++i;
+ }
+ return (const char *)&clipboard_modified;
+}
+
/** \brief The isWadPathOk function
\param path string path to check
@@ -3067,5 +3116,5 @@ const CPUInfoFlags *I_CPUInfo(void)
}
// note CPUAFFINITY code used to reside here
-void I_RegisterSysCommands(void) {}
+FUNCMATH void I_RegisterSysCommands(void) {}
#endif
diff --git a/src/sdl/i_video.c b/src/sdl/i_video.c
index 9800c8cc..1f1fd8a1 100644
--- a/src/sdl/i_video.c
+++ b/src/sdl/i_video.c
@@ -33,14 +33,6 @@
#pragma warning(default : 4214 4244)
#endif
-#if SDL_VERSION_ATLEAST(1,3,0)
-#define SDLK_EQUALS SDLK_KP_EQUALSAS400
-#define SDLK_LMETA SDLK_LGUI
-#define SDLK_RMETA SDLK_RGUI
-#else
-#define HAVE_SDLMETAKEYS
-#endif
-
#ifdef HAVE_TTF
#include "i_ttf.h"
#endif
@@ -190,15 +182,13 @@ static void SDLSetMode(INT32 width, INT32 height, SDL_bool fullscreen)
wasfullscreen = SDL_TRUE;
SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN_DESKTOP);
}
- else if (!fullscreen && wasfullscreen)
- {
- wasfullscreen = SDL_FALSE;
- SDL_SetWindowFullscreen(window, 0);
- SDL_SetWindowSize(window, width, height);
- SDL_SetWindowPosition(window, SDL_WINDOWPOS_CENTERED_DISPLAY(1), SDL_WINDOWPOS_CENTERED_DISPLAY(1));
- }
- else if (!wasfullscreen)
+ else // windowed mode
{
+ if (wasfullscreen)
+ {
+ wasfullscreen = SDL_FALSE;
+ SDL_SetWindowFullscreen(window, 0);
+ }
// Reposition window only in windowed mode
SDL_SetWindowSize(window, width, height);
SDL_SetWindowPosition(window, SDL_WINDOWPOS_CENTERED_DISPLAY(1), SDL_WINDOWPOS_CENTERED_DISPLAY(1));
@@ -283,129 +273,70 @@ static INT32 Impl_SDL_Scancode_To_Keycode(SDL_Scancode code)
}
switch (code)
{
- case SDL_SCANCODE_F11: // F11 and F12 are
- return KEY_F11; // separated from the
- case SDL_SCANCODE_F12: // rest of the function
- return KEY_F12; // keys
+ // F11 and F12 are separated from the rest of the function keys
+ case SDL_SCANCODE_F11: return KEY_F11;
+ case SDL_SCANCODE_F12: return KEY_F12;
- case SDL_SCANCODE_KP_0:
- return KEY_KEYPAD0;
- case SDL_SCANCODE_KP_1:
- return KEY_KEYPAD1;
- case SDL_SCANCODE_KP_2:
- return KEY_KEYPAD2;
- case SDL_SCANCODE_KP_3:
- return KEY_KEYPAD3;
- case SDL_SCANCODE_KP_4:
- return KEY_KEYPAD4;
- case SDL_SCANCODE_KP_5:
- return KEY_KEYPAD5;
- case SDL_SCANCODE_KP_6:
- return KEY_KEYPAD6;
- case SDL_SCANCODE_KP_7:
- return KEY_KEYPAD7;
- case SDL_SCANCODE_KP_8:
- return KEY_KEYPAD8;
- case SDL_SCANCODE_KP_9:
- return KEY_KEYPAD9;
+ case SDL_SCANCODE_KP_0: return KEY_KEYPAD0;
+ case SDL_SCANCODE_KP_1: return KEY_KEYPAD1;
+ case SDL_SCANCODE_KP_2: return KEY_KEYPAD2;
+ case SDL_SCANCODE_KP_3: return KEY_KEYPAD3;
+ case SDL_SCANCODE_KP_4: return KEY_KEYPAD4;
+ case SDL_SCANCODE_KP_5: return KEY_KEYPAD5;
+ case SDL_SCANCODE_KP_6: return KEY_KEYPAD6;
+ case SDL_SCANCODE_KP_7: return KEY_KEYPAD7;
+ case SDL_SCANCODE_KP_8: return KEY_KEYPAD8;
+ case SDL_SCANCODE_KP_9: return KEY_KEYPAD9;
- case SDL_SCANCODE_RETURN:
- return KEY_ENTER;
- case SDL_SCANCODE_ESCAPE:
- return KEY_ESCAPE;
- case SDL_SCANCODE_BACKSPACE:
- return KEY_BACKSPACE;
- case SDL_SCANCODE_TAB:
- return KEY_TAB;
- case SDL_SCANCODE_SPACE:
- return KEY_SPACE;
- case SDL_SCANCODE_MINUS:
- return KEY_MINUS;
- case SDL_SCANCODE_EQUALS:
- return KEY_EQUALS;
- case SDL_SCANCODE_LEFTBRACKET:
- return '[';
- case SDL_SCANCODE_RIGHTBRACKET:
- return ']';
- case SDL_SCANCODE_BACKSLASH:
- return '\\';
- case SDL_SCANCODE_NONUSHASH:
- return '#';
- case SDL_SCANCODE_SEMICOLON:
- return ';';
- case SDL_SCANCODE_APOSTROPHE:
- return '\'';
- case SDL_SCANCODE_GRAVE:
- return '`';
- case SDL_SCANCODE_COMMA:
- return ',';
- case SDL_SCANCODE_PERIOD:
- return '.';
- case SDL_SCANCODE_SLASH:
- return '/';
- case SDL_SCANCODE_CAPSLOCK:
- return KEY_CAPSLOCK;
- case SDL_SCANCODE_PRINTSCREEN:
- return 0; // undefined?
- case SDL_SCANCODE_SCROLLLOCK:
- return KEY_SCROLLLOCK;
- case SDL_SCANCODE_PAUSE:
- return KEY_PAUSE;
- case SDL_SCANCODE_INSERT:
- return KEY_INS;
- case SDL_SCANCODE_HOME:
- return KEY_HOME;
- case SDL_SCANCODE_PAGEUP:
- return KEY_PGUP;
- case SDL_SCANCODE_DELETE:
- return KEY_DEL;
- case SDL_SCANCODE_END:
- return KEY_END;
- case SDL_SCANCODE_PAGEDOWN:
- return KEY_PGDN;
- case SDL_SCANCODE_RIGHT:
- return KEY_RIGHTARROW;
- case SDL_SCANCODE_LEFT:
- return KEY_LEFTARROW;
- case SDL_SCANCODE_DOWN:
- return KEY_DOWNARROW;
- case SDL_SCANCODE_UP:
- return KEY_UPARROW;
- case SDL_SCANCODE_NUMLOCKCLEAR:
- return KEY_NUMLOCK;
- case SDL_SCANCODE_KP_DIVIDE:
- return KEY_KPADSLASH;
- case SDL_SCANCODE_KP_MULTIPLY:
- return '*'; // undefined?
- case SDL_SCANCODE_KP_MINUS:
- return KEY_MINUSPAD;
- case SDL_SCANCODE_KP_PLUS:
- return KEY_PLUSPAD;
- case SDL_SCANCODE_KP_ENTER:
- return KEY_ENTER;
- case SDL_SCANCODE_KP_PERIOD:
- return KEY_KPADDEL;
- case SDL_SCANCODE_NONUSBACKSLASH:
- return '\\';
+ case SDL_SCANCODE_RETURN: return KEY_ENTER;
+ case SDL_SCANCODE_ESCAPE: return KEY_ESCAPE;
+ case SDL_SCANCODE_BACKSPACE: return KEY_BACKSPACE;
+ case SDL_SCANCODE_TAB: return KEY_TAB;
+ case SDL_SCANCODE_SPACE: return KEY_SPACE;
+ case SDL_SCANCODE_MINUS: return KEY_MINUS;
+ case SDL_SCANCODE_EQUALS: return KEY_EQUALS;
+ case SDL_SCANCODE_LEFTBRACKET: return '[';
+ case SDL_SCANCODE_RIGHTBRACKET: return ']';
+ case SDL_SCANCODE_BACKSLASH: return '\\';
+ case SDL_SCANCODE_NONUSHASH: return '#';
+ case SDL_SCANCODE_SEMICOLON: return ';';
+ case SDL_SCANCODE_APOSTROPHE: return '\'';
+ case SDL_SCANCODE_GRAVE: return '`';
+ case SDL_SCANCODE_COMMA: return ',';
+ case SDL_SCANCODE_PERIOD: return '.';
+ case SDL_SCANCODE_SLASH: return '/';
+ case SDL_SCANCODE_CAPSLOCK: return KEY_CAPSLOCK;
+ case SDL_SCANCODE_PRINTSCREEN: return 0; // undefined?
+ case SDL_SCANCODE_SCROLLLOCK: return KEY_SCROLLLOCK;
+ case SDL_SCANCODE_PAUSE: return KEY_PAUSE;
+ case SDL_SCANCODE_INSERT: return KEY_INS;
+ case SDL_SCANCODE_HOME: return KEY_HOME;
+ case SDL_SCANCODE_PAGEUP: return KEY_PGUP;
+ case SDL_SCANCODE_DELETE: return KEY_DEL;
+ case SDL_SCANCODE_END: return KEY_END;
+ case SDL_SCANCODE_PAGEDOWN: return KEY_PGDN;
+ case SDL_SCANCODE_RIGHT: return KEY_RIGHTARROW;
+ case SDL_SCANCODE_LEFT: return KEY_LEFTARROW;
+ case SDL_SCANCODE_DOWN: return KEY_DOWNARROW;
+ case SDL_SCANCODE_UP: return KEY_UPARROW;
+ case SDL_SCANCODE_NUMLOCKCLEAR: return KEY_NUMLOCK;
+ case SDL_SCANCODE_KP_DIVIDE: return KEY_KPADSLASH;
+ case SDL_SCANCODE_KP_MULTIPLY: return '*'; // undefined?
+ case SDL_SCANCODE_KP_MINUS: return KEY_MINUSPAD;
+ case SDL_SCANCODE_KP_PLUS: return KEY_PLUSPAD;
+ case SDL_SCANCODE_KP_ENTER: return KEY_ENTER;
+ case SDL_SCANCODE_KP_PERIOD: return KEY_KPADDEL;
+ case SDL_SCANCODE_NONUSBACKSLASH: return '\\';
- case SDL_SCANCODE_LSHIFT:
- return KEY_LSHIFT;
- case SDL_SCANCODE_RSHIFT:
- return KEY_RSHIFT;
- case SDL_SCANCODE_LCTRL:
- return KEY_LCTRL;
- case SDL_SCANCODE_RCTRL:
- return KEY_RCTRL;
- case SDL_SCANCODE_LALT:
- return KEY_LALT;
- case SDL_SCANCODE_RALT:
- return KEY_RALT;
- case SDL_SCANCODE_LGUI:
- return KEY_LEFTWIN;
- case SDL_SCANCODE_RGUI:
- return KEY_RIGHTWIN;
- default:
- break;
+ case SDL_SCANCODE_LSHIFT: return KEY_LSHIFT;
+ case SDL_SCANCODE_RSHIFT: return KEY_RSHIFT;
+ case SDL_SCANCODE_LCTRL: return KEY_LCTRL;
+ case SDL_SCANCODE_RCTRL: return KEY_RCTRL;
+ case SDL_SCANCODE_LALT: return KEY_LALT;
+ case SDL_SCANCODE_RALT: return KEY_RALT;
+ case SDL_SCANCODE_LGUI: return KEY_LEFTWIN;
+ case SDL_SCANCODE_RGUI: return KEY_RIGHTWIN;
+ default: break;
}
#ifdef HWRENDER
DBG_Printf("Unknown incoming scancode: %d, represented %c\n",
@@ -437,15 +368,10 @@ static void VID_Command_NumModes_f (void)
CONS_Printf(M_GetText("%d video mode(s) available(s)\n"), VID_NumModes());
}
+// SDL2 doesn't have SDL_GetVideoSurface or a lot of the SDL_Surface flags that SDL 1.2 had
static void SurfaceInfo(const SDL_Surface *infoSurface, const char *SurfaceText)
{
-#if 1
- (void)infoSurface;
- (void)SurfaceText;
- SDL2STUB();
-#else
INT32 vfBPP;
- const SDL_Surface *VidSur = SDL_GetVideoSurface();
if (!infoSurface)
return;
@@ -458,49 +384,12 @@ static void SurfaceInfo(const SDL_Surface *infoSurface, const char *SurfaceText)
CONS_Printf("\x82" "%s\n", SurfaceText);
CONS_Printf(M_GetText(" %ix%i at %i bit color\n"), infoSurface->w, infoSurface->h, vfBPP);
- if (infoSurface->flags&SDL_HWSURFACE)
- CONS_Printf("%s", M_GetText(" Stored in video memory\n"));
- else if (infoSurface->flags&SDL_OPENGL)
- CONS_Printf("%s", M_GetText(" Stored in an OpenGL context\n"));
- else if (infoSurface->flags&SDL_PREALLOC)
+ if (infoSurface->flags&SDL_PREALLOC)
CONS_Printf("%s", M_GetText(" Uses preallocated memory\n"));
else
CONS_Printf("%s", M_GetText(" Stored in system memory\n"));
-
- if (infoSurface->flags&SDL_ASYNCBLIT)
- CONS_Printf("%s", M_GetText(" Uses asynchronous blits if possible\n"));
- else
- CONS_Printf("%s", M_GetText(" Uses synchronous blits if possible\n"));
-
- if (infoSurface->flags&SDL_ANYFORMAT)
- CONS_Printf("%s", M_GetText(" Allows any pixel-format\n"));
-
- if (infoSurface->flags&SDL_HWPALETTE)
- CONS_Printf("%s", M_GetText(" Has exclusive palette access\n"));
- else if (VidSur == infoSurface)
- CONS_Printf("%s", M_GetText(" Has nonexclusive palette access\n"));
-
- if (infoSurface->flags&SDL_DOUBLEBUF)
- CONS_Printf("%s", M_GetText(" Double buffered\n"));
- else if (VidSur == infoSurface)
- CONS_Printf("%s", M_GetText(" No hardware flipping\n"));
-
- if (infoSurface->flags&SDL_FULLSCREEN)
- CONS_Printf("%s", M_GetText(" Full screen\n"));
- else if (infoSurface->flags&SDL_RESIZABLE)
- CONS_Printf("%s", M_GetText(" Resizable window\n"));
- else if (VidSur == infoSurface)
- CONS_Printf("%s", M_GetText(" Nonresizable window\n"));
-
- if (infoSurface->flags&SDL_HWACCEL)
- CONS_Printf("%s", M_GetText(" Uses hardware acceleration blit\n"));
- if (infoSurface->flags&SDL_SRCCOLORKEY)
- CONS_Printf("%s", M_GetText(" Use colorkey blitting\n"));
if (infoSurface->flags&SDL_RLEACCEL)
CONS_Printf("%s", M_GetText(" Colorkey RLE acceleration blit\n"));
- if (infoSurface->flags&SDL_SRCALPHA)
- CONS_Printf("%s", M_GetText(" Use alpha blending acceleration blit\n"));
-#endif
}
static void VID_Command_Info_f (void)
@@ -584,23 +473,6 @@ static void VID_Command_Mode_f (void)
setmodeneeded = modenum+1; // request vid mode change
}
-#if 0
-#if defined(RPC_NO_WINDOWS_H)
-static VOID MainWndproc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
-{
- UNREFERENCED_PARAMETER(hWnd);
- UNREFERENCED_PARAMETER(message);
- UNREFERENCED_PARAMETER(wParam);
- switch (message)
- {
- case WM_SETTEXT:
- COM_BufAddText((LPCSTR)lParam);
- break;
- }
-}
-#endif
-#endif
-
static inline void SDLJoyRemap(event_t *event)
{
(void)event;
@@ -966,218 +838,6 @@ void I_GetEvent(void)
// In order to make wheels act like buttons, we have to set their state to Up.
// This is because wheel messages don't have an up/down state.
gamekeydown[KEY_MOUSEWHEELDOWN] = gamekeydown[KEY_MOUSEWHEELUP] = 0;
-
-#if 0
- SDL_Event inputEvent;
- static SDL_bool sdlquit = SDL_FALSE; //Alam: once, just once
- event_t event;
-
- if (!graphics_started)
- return;
-
- memset(&inputEvent, 0x00, sizeof(inputEvent));
- while (SDL_PollEvent(&inputEvent))
- {
- memset(&event,0x00,sizeof (event_t));
- switch (inputEvent.type)
- {
- case SDL_ACTIVEEVENT:
- if (inputEvent.active.state & (SDL_APPACTIVE|SDL_APPINPUTFOCUS))
- {
- // pause music when alt-tab
- if (inputEvent.active.gain /*&& !paused */)
- {
- static SDL_bool firsttimeonmouse = SDL_TRUE;
- if (!firsttimeonmouse)
- {
- if (cv_usemouse.value) I_StartupMouse();
- }
- else firsttimeonmouse = SDL_FALSE;
- //if (!netgame && !con_destlines) paused = false;
- if (gamestate == GS_LEVEL)
- if (!paused) I_ResumeSong(0); //resume it
- }
- else /*if (!paused)*/
- {
- if (!disable_mouse)
- SDLforceUngrabMouse();
- if (!netgame && gamestate == GS_LEVEL) paused = true;
- memset(gamekeydown, 0, NUMKEYS);
- //S_PauseSound();
- if (gamestate == GS_LEVEL)
- I_PauseSong(0); //pause it
- }
- }
- if (MOUSE_MENU)
- {
- SDLdoUngrabMouse();
- break;
- }
- if ((SDL_APPMOUSEFOCUS&inputEvent.active.state) && USE_MOUSEINPUT && inputEvent.active.gain)
- HalfWarpMouse(realwidth, realheight);
- break;
- case SDL_KEYDOWN:
- case SDL_KEYUP:
- /// \todo inputEvent.key.which?
- if (inputEvent.type == SDL_KEYUP)
- event.type = ev_keyup;
- else if (inputEvent.type == SDL_KEYDOWN)
- event.type = ev_keydown;
- else break;
- event.data1 = SDLatekey(inputEvent.key.keysym.sym);
- if (event.data1) D_PostEvent(&event);
- break;
- case SDL_MOUSEMOTION:
- /// \todo inputEvent.motion.which
- if (MOUSE_MENU)
- {
- SDLdoUngrabMouse();
- break;
- }
- //if (USE_MOUSEINPUT) TODO SDL2 stub
- {
- // If the event is from warping the pointer back to middle
- // of the screen then ignore it.
- if ((inputEvent.motion.x == realwidth/2) &&
- (inputEvent.motion.y == realheight/2))
- {
- break;
- }
- else
- {
- event.data2 = +inputEvent.motion.xrel;
- event.data3 = -inputEvent.motion.yrel;
- }
- event.type = ev_mouse;
- D_PostEvent(&event);
- // Warp the pointer back to the middle of the window
- // or we cannot move any further if it's at a border.
- if ((inputEvent.motion.x < (realwidth/2 )-(realwidth/4 )) ||
- (inputEvent.motion.y < (realheight/2)-(realheight/4)) ||
- (inputEvent.motion.x > (realwidth/2 )+(realwidth/4 )) ||
- (inputEvent.motion.y > (realheight/2)+(realheight/4) ) )
- {
- //if (SDL_GRAB_ON == SDL_WM_GrabInput(SDL_GRAB_QUERY) || !mousegrabok)
- HalfWarpMouse(realwidth, realheight);
- }
- }
- break;
- case SDL_MOUSEBUTTONDOWN:
- case SDL_MOUSEBUTTONUP:
- /// \todo inputEvent.button.which
- if (USE_MOUSEINPUT)
- {
- if (inputEvent.type == SDL_MOUSEBUTTONUP)
- event.type = ev_keyup;
- else if (inputEvent.type == SDL_MOUSEBUTTONDOWN)
- event.type = ev_keydown;
- else break;
- if (inputEvent.button.button==SDL_BUTTON_WHEELUP || inputEvent.button.button==SDL_BUTTON_WHEELDOWN)
- {
- if (inputEvent.type == SDL_MOUSEBUTTONUP)
- event.data1 = 0; //Alam: dumb! this could be a real button with some mice
- else
- event.data1 = KEY_MOUSEWHEELUP + inputEvent.button.button - SDL_BUTTON_WHEELUP;
- }
- else if (inputEvent.button.button == SDL_BUTTON_MIDDLE)
- event.data1 = KEY_MOUSE1+2;
- else if (inputEvent.button.button == SDL_BUTTON_RIGHT)
- event.data1 = KEY_MOUSE1+1;
- else if (inputEvent.button.button <= MOUSEBUTTONS)
- event.data1 = KEY_MOUSE1 + inputEvent.button.button - SDL_BUTTON_LEFT;
- if (event.data1) D_PostEvent(&event);
- }
- break;
- case SDL_JOYAXISMOTION:
- inputEvent.jaxis.which++;
- inputEvent.jaxis.axis++;
- event.data1 = event.data2 = event.data3 = INT32_MAX;
- if (cv_usejoystick.value == inputEvent.jaxis.which)
- {
- event.type = ev_joystick;
- }
- else if (cv_usejoystick.value == inputEvent.jaxis.which)
- {
- event.type = ev_joystick2;
- }
- else break;
- //axis
- if (inputEvent.jaxis.axis > JOYAXISSET*2)
- break;
- //vaule
- if (inputEvent.jaxis.axis%2)
- {
- event.data1 = inputEvent.jaxis.axis / 2;
- event.data2 = SDLJoyAxis(inputEvent.jaxis.value, event.type);
- }
- else
- {
- inputEvent.jaxis.axis--;
- event.data1 = inputEvent.jaxis.axis / 2;
- event.data3 = SDLJoyAxis(inputEvent.jaxis.value, event.type);
- }
- D_PostEvent(&event);
- break;
- case SDL_JOYBALLMOTION:
- case SDL_JOYHATMOTION:
- break; //NONE
- case SDL_JOYBUTTONDOWN:
- case SDL_JOYBUTTONUP:
- inputEvent.jbutton.which++;
- if (cv_usejoystick.value == inputEvent.jbutton.which)
- event.data1 = KEY_JOY1;
- else if (cv_usejoystick.value == inputEvent.jbutton.which)
- event.data1 = KEY_2JOY1;
- else break;
- if (inputEvent.type == SDL_JOYBUTTONUP)
- event.type = ev_keyup;
- else if (inputEvent.type == SDL_JOYBUTTONDOWN)
- event.type = ev_keydown;
- else break;
- if (inputEvent.jbutton.button < JOYBUTTONS)
- event.data1 += inputEvent.jbutton.button;
- else
- break;
- SDLJoyRemap(&event);
- if (event.type != ev_console) D_PostEvent(&event);
- break;
- case SDL_QUIT:
- if (!sdlquit)
- {
- sdlquit = SDL_TRUE;
- M_QuitResponse('y');
- }
- break;
-#if defined(RPC_NO_WINDOWS_H)
- case SDL_SYSWMEVENT:
- MainWndproc(inputEvent.syswm.msg->hwnd,
- inputEvent.syswm.msg->msg,
- inputEvent.syswm.msg->wParam,
- inputEvent.syswm.msg->lParam);
- break;
-#endif
- case SDL_VIDEORESIZE:
- if (gamestate == GS_LEVEL || gamestate == GS_TITLESCREEN || gamestate == GS_EVALUATION)
- setmodeneeded = VID_GetModeForSize(inputEvent.resize.w,inputEvent.resize.h)+1;
- if (render_soft == rendermode)
- {
- SDLSetMode(realwidth, realheight, vid.bpp*8, surfaceFlagsW);
- if (vidSurface) SDL_SetColors(vidSurface, localPalette, 0, 256);
- }
- else
- SDLSetMode(realwidth, realheight, vid.bpp*8, surfaceFlagsW);
- if (!vidSurface)
- I_Error("Could not reset vidmode: %s\n",SDL_GetError());
- break;
- case SDL_VIDEOEXPOSE:
- exposevideo = SDL_TRUE;
- break;
- default:
- break;
- }
- }
- //reset wheel like in win32, I don't understand it but works
-#endif
}
void I_StartupMouse(void)
@@ -1251,7 +911,7 @@ static inline boolean I_SkipFrame(void)
{
static boolean skip = false;
- if (render_soft != rendermode)
+ if (rendermode != render_soft)
return false;
skip = !skip;
@@ -1283,7 +943,7 @@ void I_FinishUpdate(void)
if (cv_ticrate.value)
SCR_DisplayTicRate();
- if (render_soft == rendermode && screens[0])
+ if (rendermode == render_soft && screens[0])
{
SDL_Rect rect;
@@ -1310,7 +970,7 @@ void I_FinishUpdate(void)
}
#ifdef HWRENDER
- else
+ else if (rendermode == render_opengl)
{
OglSdlFinishUpdate(cv_vidwait.value);
}
@@ -1360,7 +1020,7 @@ void I_SetPalette(RGBA_t *palette)
}
// return number of fullscreen + X11 modes
-INT32 VID_NumModes(void)
+FUNCMATH INT32 VID_NumModes(void)
{
if (USE_FULLSCREEN && numVidModes != -1)
return numVidModes - firstEntry;
@@ -1368,7 +1028,7 @@ INT32 VID_NumModes(void)
return MAXWINMODES;
}
-const char *VID_GetModeName(INT32 modeNum)
+FUNCMATH const char *VID_GetModeName(INT32 modeNum)
{
#if 0
if (USE_FULLSCREEN && numVidModes != -1) // fullscreen modes
@@ -1398,7 +1058,7 @@ const char *VID_GetModeName(INT32 modeNum)
return &vidModeName[modeNum][0];
}
-INT32 VID_GetModeForSize(INT32 w, INT32 h)
+FUNCMATH INT32 VID_GetModeForSize(INT32 w, INT32 h)
{
int i;
for (i = 0; i < MAXWINMODES; i++)
@@ -1508,11 +1168,6 @@ void VID_PrepareModeList(void)
#endif
}
-static inline void SDLESSet(void)
-{
- SDL2STUB();
-}
-
INT32 VID_SetMode(INT32 modeNum)
{
SDLdoUngrabMouse();
@@ -1545,9 +1200,9 @@ INT32 VID_SetMode(INT32 modeNum)
}
Impl_SetWindowName("SRB2 "VERSIONSTRING);
- SDLSetMode(windowedModes[modeNum][0], windowedModes[modeNum][1], USE_FULLSCREEN);
+ SDLSetMode(vid.width, vid.height, USE_FULLSCREEN);
- if (render_soft == rendermode)
+ if (rendermode == render_soft)
{
if (bufSurface)
{
@@ -1564,56 +1219,63 @@ INT32 VID_SetMode(INT32 modeNum)
static SDL_bool Impl_CreateWindow(SDL_bool fullscreen)
{
int flags = 0;
+
+ if (rendermode == render_none) // dedicated
+ return SDL_TRUE; // Monster Iestyn -- not sure if it really matters what we return here tbh
+
if (window != NULL)
- {
return SDL_FALSE;
- }
if (fullscreen)
- {
flags |= SDL_WINDOW_FULLSCREEN_DESKTOP;
- }
if (borderlesswindow)
- {
flags |= SDL_WINDOW_BORDERLESS;
- }
#ifdef HWRENDER
if (rendermode == render_opengl)
+ flags |= SDL_WINDOW_OPENGL;
+#endif
+
+ // Create a window
+ window = SDL_CreateWindow("SRB2 "VERSIONSTRING, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
+ realwidth, realheight, flags);
+
+ if (window == NULL)
{
- window = SDL_CreateWindow("SRB2 "VERSIONSTRING, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
- realwidth, realheight, flags | SDL_WINDOW_OPENGL);
- if (window != NULL)
- {
- sdlglcontext = SDL_GL_CreateContext(window);
- if (sdlglcontext == NULL)
- {
- SDL_DestroyWindow(window);
- I_Error("Failed to create a GL context: %s\n", SDL_GetError());
- }
- else
- {
- SDL_GL_MakeCurrent(window, sdlglcontext);
- }
- }
- else return SDL_FALSE;
+ CONS_Printf(M_GetText("Couldn't create window: %s\n"), SDL_GetError());
+ return SDL_FALSE;
}
+
+ // Renderer-specific stuff
+#ifdef HWRENDER
+ if (rendermode == render_opengl)
+ {
+ sdlglcontext = SDL_GL_CreateContext(window);
+ if (sdlglcontext == NULL)
+ {
+ SDL_DestroyWindow(window);
+ I_Error("Failed to create a GL context: %s\n", SDL_GetError());
+ }
+ SDL_GL_MakeCurrent(window, sdlglcontext);
+ }
+ else
#endif
if (rendermode == render_soft)
{
- window = SDL_CreateWindow("SRB2 "VERSIONSTRING, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
- realwidth, realheight, flags);
- if (window != NULL)
+ flags = 0; // Use this to set SDL_RENDERER_* flags now
+ if (usesdl2soft)
+ flags |= SDL_RENDERER_SOFTWARE;
+ else if (cv_vidwait.value)
+ flags |= SDL_RENDERER_PRESENTVSYNC;
+
+ renderer = SDL_CreateRenderer(window, -1, flags);
+ if (renderer == NULL)
{
- renderer = SDL_CreateRenderer(window, -1, (usesdl2soft ? SDL_RENDERER_SOFTWARE : 0) | (cv_vidwait.value && !usesdl2soft ? SDL_RENDERER_PRESENTVSYNC : 0));
- if (renderer != NULL)
- {
- SDL_RenderSetLogicalSize(renderer, BASEVIDWIDTH, BASEVIDHEIGHT);
- }
- else return SDL_FALSE;
+ CONS_Printf(M_GetText("Couldn't create rendering context: %s\n"), SDL_GetError());
+ return SDL_FALSE;
}
- else return SDL_FALSE;
+ SDL_RenderSetLogicalSize(renderer, BASEVIDWIDTH, BASEVIDHEIGHT);
}
return SDL_TRUE;
@@ -1634,7 +1296,7 @@ static void Impl_SetWindowIcon(void)
{
return;
}
- SDL2STUB();
+ //SDL2STUB(); // Monster Iestyn: why is this stubbed?
SDL_SetWindowIcon(window, icoSurface);
}
@@ -1732,7 +1394,6 @@ void I_StartupGraphics(void)
borderlesswindow = M_CheckParm("-borderless");
//SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY>>1,SDL_DEFAULT_REPEAT_INTERVAL<<2);
- SDLESSet();
VID_Command_ModeList_f();
#ifdef HWRENDER
if (M_CheckParm("-opengl") || rendermode == render_opengl)
@@ -1830,7 +1491,7 @@ void I_ShutdownGraphics(void)
rendermode = render_none;
if (icoSurface) SDL_FreeSurface(icoSurface);
icoSurface = NULL;
- if (render_soft == oldrendermode)
+ if (oldrendermode == render_soft)
{
if (vidSurface) SDL_FreeSurface(vidSurface);
vidSurface = NULL;
diff --git a/src/sdl/macosx/Srb2mac.xcodeproj/project.pbxproj b/src/sdl/macosx/Srb2mac.xcodeproj/project.pbxproj
index c3f0d3b3..68391f99 100644
--- a/src/sdl/macosx/Srb2mac.xcodeproj/project.pbxproj
+++ b/src/sdl/macosx/Srb2mac.xcodeproj/project.pbxproj
@@ -1214,7 +1214,7 @@
C01FCF4B08A954540054247B /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
- CURRENT_PROJECT_VERSION = 2.1.14;
+ CURRENT_PROJECT_VERSION = 2.1.19;
GCC_PREPROCESSOR_DEFINITIONS = (
"$(inherited)",
NORMALSRB2,
@@ -1226,7 +1226,7 @@
C01FCF4C08A954540054247B /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
- CURRENT_PROJECT_VERSION = 2.1.14;
+ CURRENT_PROJECT_VERSION = 2.1.19;
GCC_ENABLE_FIX_AND_CONTINUE = NO;
GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
GCC_PREPROCESSOR_DEFINITIONS = (
diff --git a/src/sdl/macosx/mac_alert.c b/src/sdl/macosx/mac_alert.c
index 455e3650..2a139041 100644
--- a/src/sdl/macosx/mac_alert.c
+++ b/src/sdl/macosx/mac_alert.c
@@ -25,19 +25,38 @@
#include "mac_alert.h"
#include
+#define CFSTRINGIFY(x) CFStringCreateWithCString(NULL, x, kCFStringEncodingASCII)
+
int MacShowAlert(const char *title, const char *message, const char *button1, const char *button2, const char *button3)
{
CFOptionFlags results;
- CFUserNotificationDisplayAlert(0,
- kCFUserNotificationStopAlertLevel | kCFUserNotificationNoDefaultButtonFlag,
- NULL, NULL, NULL,
- CFStringCreateWithCString(NULL, title, kCFStringEncodingASCII),
- CFStringCreateWithCString(NULL, message, kCFStringEncodingASCII),
- button1 != NULL ? CFStringCreateWithCString(NULL, button1, kCFStringEncodingASCII) : NULL,
- button2 != NULL ? CFStringCreateWithCString(NULL, button2, kCFStringEncodingASCII) : NULL,
- button3 != NULL ? CFStringCreateWithCString(NULL, button3, kCFStringEncodingASCII) : NULL,
- &results);
+ CFStringRef cf_title = CFSTRINGIFY(title);
+ CFStringRef cf_message = CFSTRINGIFY(message);
+ CFStringRef cf_button1 = NULL;
+ CFStringRef cf_button2 = NULL;
+ CFStringRef cf_button3 = NULL;
+
+ if (button1 != NULL)
+ cf_button1 = CFSTRINGIFY(button1);
+ if (button2 != NULL)
+ cf_button2 = CFSTRINGIFY(button2);
+ if (button3 != NULL)
+ cf_button3 = CFSTRINGIFY(button3);
+
+ CFOptionFlags alert_flags = kCFUserNotificationStopAlertLevel | kCFUserNotificationNoDefaultButtonFlag;
+
+ CFUserNotificationDisplayAlert(0, alert_flags, NULL, NULL, NULL, cf_title, cf_message,
+ cf_button1, cf_button2, cf_button3, &results);
+
+ if (cf_button1 != NULL)
+ CFRelease(cf_button1);
+ if (cf_button2 != NULL)
+ CFRelease(cf_button2);
+ if (cf_button3 != NULL)
+ CFRelease(cf_button3);
+ CFRelease(cf_message);
+ CFRelease(cf_title);
return (int)results;
}
diff --git a/src/sdl/macosx/mac_resources.c b/src/sdl/macosx/mac_resources.c
index dacc8014..d67b9258 100644
--- a/src/sdl/macosx/mac_resources.c
+++ b/src/sdl/macosx/mac_resources.c
@@ -9,23 +9,29 @@ void OSX_GetResourcesPath(char * buffer)
mainBundle = CFBundleGetMainBundle();
if (mainBundle)
{
+ const int BUF_SIZE = 256; // because we somehow always know that
+
CFURLRef appUrlRef = CFBundleCopyBundleURL(mainBundle);
- CFStringRef macPath = CFURLCopyFileSystemPath(appUrlRef, kCFURLPOSIXPathStyle);
- CFStringRef resources = CFStringCreateWithCString(kCFAllocatorMalloc, "/Contents/Resources", kCFStringEncodingASCII);
- const void* rawarray[2] = {macPath, resources};
- CFArrayRef array = CFArrayCreate(kCFAllocatorMalloc, rawarray, 2, NULL);
- CFStringRef separator = CFStringCreateWithCString(kCFAllocatorMalloc, "", kCFStringEncodingASCII);
- CFStringRef fullPath = CFStringCreateByCombiningStrings(kCFAllocatorMalloc, array, separator);
- const char * path = CFStringGetCStringPtr(fullPath, kCFStringEncodingASCII);
- strcpy(buffer, path);
- CFRelease(fullPath);
- path = NULL;
- CFRelease(array);
- CFRelease(resources);
+ CFStringRef macPath;
+ if (appUrlRef != NULL)
+ macPath = CFURLCopyFileSystemPath(appUrlRef, kCFURLPOSIXPathStyle);
+ else
+ macPath = NULL;
+
+ const char* rawPath;
+
+ if (macPath != NULL)
+ rawPath = CFStringGetCStringPtr(macPath, kCFStringEncodingASCII);
+ else
+ rawPath = NULL;
+
+ if (rawPath != NULL && (CFStringGetLength(macPath) + strlen("/Contents/Resources") < BUF_SIZE))
+ {
+ strcpy(buffer, rawPath);
+ strcat(buffer, "/Contents/Resources");
+ }
+
CFRelease(macPath);
CFRelease(appUrlRef);
- //CFRelease(mainBundle);
- CFRelease(separator);
}
-
-}
\ No newline at end of file
+}
diff --git a/src/sdl/mixer_sound.c b/src/sdl/mixer_sound.c
index faebca6b..88bbadd2 100644
--- a/src/sdl/mixer_sound.c
+++ b/src/sdl/mixer_sound.c
@@ -126,7 +126,7 @@ void I_ShutdownSound(void)
#endif
}
-void I_UpdateSound(void)
+FUNCMATH void I_UpdateSound(void)
{
}
@@ -220,7 +220,7 @@ static Mix_Chunk *ds2chunk(void *stream)
break;
default: // convert arbitrary hz to 44100.
step = 0;
- frac = ((UINT32)freq << FRACBITS) / 44100;
+ frac = ((UINT32)freq << FRACBITS) / 44100 + 1; //Add 1 to counter truncation.
while (i < samples)
{
o = (INT16)(*s+0x80)<<8; // changed signedness and shift up to 16 bits
@@ -464,7 +464,7 @@ static void mix_gme(void *udata, Uint8 *stream, int len)
}
#endif
-void I_InitMusic(void)
+FUNCMATH void I_InitMusic(void)
{
}
@@ -769,7 +769,7 @@ boolean I_SetSongTrack(int track)
// MIDI Music
//
-void I_InitMIDIMusic(void)
+FUNCMATH void I_InitMIDIMusic(void)
{
}
diff --git a/src/sdl/ogl_sdl.c b/src/sdl/ogl_sdl.c
index 21afd831..cd7ced7c 100644
--- a/src/sdl/ogl_sdl.c
+++ b/src/sdl/ogl_sdl.c
@@ -71,7 +71,6 @@ INT32 oglflags = 0;
void *GLUhandle = NULL;
SDL_GLContext sdlglcontext = 0;
-#ifndef STATIC_OPENGL
void *GetGLFunc(const char *proc)
{
if (strncmp(proc, "glu", 3) == 0)
@@ -83,7 +82,6 @@ void *GetGLFunc(const char *proc)
}
return SDL_GL_GetProcAddress(proc);
}
-#endif
boolean LoadGL(void)
{
diff --git a/src/sdl/ogl_sdl.h b/src/sdl/ogl_sdl.h
index 7e144644..2d6209f2 100644
--- a/src/sdl/ogl_sdl.h
+++ b/src/sdl/ogl_sdl.h
@@ -24,7 +24,6 @@ boolean OglSdlSurface(INT32 w, INT32 h);
void OglSdlFinishUpdate(boolean vidwait);
-extern SDL_Window *window;
extern SDL_Renderer *renderer;
extern SDL_GLContext sdlglcontext;
extern Uint16 realwidth;
diff --git a/src/sdl/sdlmain.h b/src/sdl/sdlmain.h
index 7ac32f4b..fea1e164 100644
--- a/src/sdl/sdlmain.h
+++ b/src/sdl/sdlmain.h
@@ -71,4 +71,7 @@ void I_GetConsoleEvents(void);
void SDLforceUngrabMouse(void);
+// Needed for some WIN32 functions
+extern SDL_Window *window;
+
#endif
diff --git a/src/sdl12/i_system.c b/src/sdl12/i_system.c
index 888a6a50..ed0db653 100644
--- a/src/sdl12/i_system.c
+++ b/src/sdl12/i_system.c
@@ -2666,6 +2666,18 @@ INT32 I_PutEnv(char *variable)
#endif
}
+INT32 I_ClipboardCopy(const char *data, size_t size)
+{
+ (void)data;
+ (void)size;
+ return -1;
+}
+
+char *I_ClipboardPaste(void)
+{
+ return NULL;
+}
+
/** \brief The isWadPathOk function
\param path string path to check
diff --git a/src/sdl12/macosx/Srb2mac.xcodeproj/project.pbxproj b/src/sdl12/macosx/Srb2mac.xcodeproj/project.pbxproj
index 98599fb6..fada7849 100644
--- a/src/sdl12/macosx/Srb2mac.xcodeproj/project.pbxproj
+++ b/src/sdl12/macosx/Srb2mac.xcodeproj/project.pbxproj
@@ -1214,7 +1214,7 @@
C01FCF4B08A954540054247B /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
- CURRENT_PROJECT_VERSION = 2.1.14;
+ CURRENT_PROJECT_VERSION = 2.1.19;
GCC_PREPROCESSOR_DEFINITIONS = (
"$(inherited)",
NORMALSRB2,
@@ -1226,7 +1226,7 @@
C01FCF4C08A954540054247B /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
- CURRENT_PROJECT_VERSION = 2.1.14;
+ CURRENT_PROJECT_VERSION = 2.1.19;
GCC_ENABLE_FIX_AND_CONTINUE = NO;
GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
GCC_PREPROCESSOR_DEFINITIONS = (
diff --git a/src/st_stuff.c b/src/st_stuff.c
index aac6b09d..3562a9b7 100644
--- a/src/st_stuff.c
+++ b/src/st_stuff.c
@@ -974,7 +974,7 @@ static void ST_drawNiGHTSHUD(void)
if (cv_debug & DBG_NIGHTSBASIC)
minlink = 0;
- // Cheap hack: don't display when the score is showing
+ // Cheap hack: don't display when the score is showing (it popping up for a split second when exiting a map is intentional)
if (stplyr->texttimer && stplyr->textvar == 4)
minlink = INT32_MAX;
@@ -1385,6 +1385,10 @@ static void ST_drawMatchHUD(void)
if (G_TagGametype() && !(stplyr->pflags & PF_TAGIT))
return;
+#ifdef HAVE_BLUA
+ if (LUA_HudEnabled(hud_weaponrings)) {
+#endif
+
if (stplyr->powers[pw_infinityring])
ST_drawWeaponRing(pw_infinityring, 0, 0, offset, infinityring);
else if (stplyr->health > 1)
@@ -1408,6 +1412,12 @@ static void ST_drawMatchHUD(void)
offset += 20;
ST_drawWeaponRing(pw_railring, RW_RAIL, WEP_RAIL, offset, railring);
+#ifdef HAVE_BLUA
+ }
+
+ if (LUA_HudEnabled(hud_powerstones)) {
+#endif
+
// Power Stones collected
offset = 136; // Used for Y now
@@ -1439,6 +1449,10 @@ static void ST_drawMatchHUD(void)
if (stplyr->powers[pw_emeralds] & EMERALD7)
V_DrawScaledPatch(28, STRINGY(offset), V_SNAPTOLEFT, tinyemeraldpics[6]);
+
+#ifdef HAVE_BLUA
+ }
+#endif
}
static inline void ST_drawRaceHUD(void)
diff --git a/src/st_stuff.h b/src/st_stuff.h
index 6fafca40..c11559d2 100644
--- a/src/st_stuff.h
+++ b/src/st_stuff.h
@@ -24,7 +24,7 @@
//
// Called by main loop.
-void ST_Ticker(void);
+FUNCMATH void ST_Ticker(void);
// Called by main loop.
void ST_Drawer(void);
diff --git a/src/tables.h b/src/tables.h
index 0e4853cb..e05b8184 100644
--- a/src/tables.h
+++ b/src/tables.h
@@ -82,7 +82,7 @@ typedef UINT32 angle_t;
extern angle_t tantoangle[SLOPERANGE+1];
// Utility function, called by R_PointToAngle.
-unsigned SlopeDiv(unsigned num, unsigned den);
+FUNCMATH unsigned SlopeDiv(unsigned num, unsigned den);
// 360 - angle_t(ANGLE_45) = ANGLE_315
FUNCMATH FUNCINLINE static ATTRINLINE angle_t InvAngle(angle_t a)
diff --git a/src/v_video.c b/src/v_video.c
index 3cc6d195..64bb3214 100644
--- a/src/v_video.c
+++ b/src/v_video.c
@@ -267,7 +267,7 @@ static void CV_Gammaxxx_ONChange(void)
#endif
-#if defined (__GNUC__) && defined (__i386__) && !defined (NOASM) && !defined (__APPLE__)
+#if defined (__GNUC__) && defined (__i386__) && !defined (NOASM) && !defined (__APPLE__) && !defined (NORUSEASM)
void VID_BlitLinearScreen_ASM(const UINT8 *srcptr, UINT8 *destptr, INT32 width, INT32 height, size_t srcrowbytes,
size_t destrowbytes);
#define HAVE_VIDCOPY
@@ -758,71 +758,80 @@ void V_DrawFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 c)
{
UINT8 *dest;
const UINT8 *deststop;
- INT32 u, v, dupx, dupy;
+
+ if (rendermode == render_none)
+ return;
#ifdef HWRENDER
- if (rendermode != render_soft && rendermode != render_none)
+ if (rendermode != render_soft && !con_startup)
{
HWR_DrawFill(x, y, w, h, c);
return;
}
#endif
- dupx = vid.dupx;
- dupy = vid.dupy;
+ if (!(c & V_NOSCALESTART))
+ {
+ INT32 dupx = vid.dupx, dupy = vid.dupy;
- if (!screens[0])
- return;
+ if (x == 0 && y == 0 && w == BASEVIDWIDTH && h == BASEVIDHEIGHT)
+ { // Clear the entire screen, from dest to deststop. Yes, this really works.
+ memset(screens[0], (UINT8)(c&255), vid.width * vid.height * vid.bpp);
+ return;
+ }
- if (x == 0 && y == 0 && w == BASEVIDWIDTH && h == BASEVIDHEIGHT)
- { // Clear the entire screen, from dest to deststop. Yes, this really works.
- memset(screens[0], (UINT8)(c&255), vid.width * vid.height * vid.bpp);
- return;
- }
-
- dest = screens[0] + y*dupy*vid.width + x*dupx;
- deststop = screens[0] + vid.rowbytes * vid.height;
-
- if (w == BASEVIDWIDTH)
- w = vid.width;
- else
+ x *= dupx;
+ y *= dupy;
w *= dupx;
- if (h == BASEVIDHEIGHT)
- h = vid.height;
- else
h *= dupy;
- if (x && y && x + w < vid.width && y + h < vid.height)
- {
// Center it if necessary
if (vid.width != BASEVIDWIDTH * dupx)
{
// dupx adjustments pretend that screen width is BASEVIDWIDTH * dupx,
// so center this imaginary screen
if (c & V_SNAPTORIGHT)
- dest += (vid.width - (BASEVIDWIDTH * dupx));
+ x += (vid.width - (BASEVIDWIDTH * dupx));
else if (!(c & V_SNAPTOLEFT))
- dest += (vid.width - (BASEVIDWIDTH * dupx)) / 2;
+ x += (vid.width - (BASEVIDWIDTH * dupx)) / 2;
}
if (vid.height != BASEVIDHEIGHT * dupy)
{
// same thing here
if (c & V_SNAPTOBOTTOM)
- dest += (vid.height - (BASEVIDHEIGHT * dupy)) * vid.width;
+ y += (vid.height - (BASEVIDHEIGHT * dupy));
else if (!(c & V_SNAPTOTOP))
- dest += (vid.height - (BASEVIDHEIGHT * dupy)) * vid.width / 2;
+ y += (vid.height - (BASEVIDHEIGHT * dupy)) / 2;
}
}
+ if (x >= vid.width || y >= vid.height)
+ return; // off the screen
+ if (x < 0)
+ {
+ w += x;
+ x = 0;
+ }
+ if (y < 0)
+ {
+ h += y;
+ y = 0;
+ }
+
+ if (w <= 0 || h <= 0)
+ return; // zero width/height wouldn't draw anything
+ if (x + w > vid.width)
+ w = vid.width - x;
+ if (y + h > vid.height)
+ h = vid.height - y;
+
+ dest = screens[0] + y*vid.width + x;
+ deststop = screens[0] + vid.rowbytes * vid.height;
+
c &= 255;
- for (v = 0; v < h; v++, dest += vid.width)
- for (u = 0; u < w; u++)
- {
- if (dest > deststop)
- return;
- dest[u] = (UINT8)c;
- }
+ for (;(--h >= 0) && dest < deststop; dest += vid.width)
+ memset(dest, (UINT8)(c&255), w * vid.bpp);
}
//
@@ -968,45 +977,38 @@ void V_DrawFadeScreen(void)
}
// Simple translucency with one color, over a set number of lines starting from the top.
-void V_DrawFadeConsBack(INT32 plines, INT32 pcolor)
+void V_DrawFadeConsBack(INT32 plines)
{
- UINT8 *deststop, *colormap, *buf;
+ UINT8 *deststop, *buf;
#ifdef HWRENDER // not win32 only 19990829 by Kin
if (rendermode != render_soft && rendermode != render_none)
{
UINT32 hwcolor;
- switch (pcolor)
+ switch (cons_backcolor.value)
{
- case 0: hwcolor = 0xffffff00; break; //white
- case 1: hwcolor = 0xff800000; break; //orange
- case 2: hwcolor = 0x0000ff00; break; //blue
- case 3: hwcolor = 0x00800000; break; //green
- case 4: hwcolor = 0x80808000; break; //gray
- case 5: hwcolor = 0xff000000; break; //red
- default: hwcolor = 0x00800000; break; //green
+ case 0: hwcolor = 0xffffff00; break; // White
+ case 1: hwcolor = 0x80808000; break; // Gray
+ case 2: hwcolor = 0x40201000; break; // Brown
+ case 3: hwcolor = 0xff000000; break; // Red
+ case 4: hwcolor = 0xff800000; break; // Orange
+ case 5: hwcolor = 0x80800000; break; // Yellow
+ case 6: hwcolor = 0x00800000; break; // Green
+ case 7: hwcolor = 0x0000ff00; break; // Blue
+ case 8: hwcolor = 0x4080ff00; break; // Cyan
+ // Default green
+ default: hwcolor = 0x00800000; break;
}
HWR_DrawConsoleBack(hwcolor, plines);
return;
}
#endif
- switch (pcolor)
- {
- case 0: colormap = cwhitemap; break;
- case 1: colormap = corangemap; break;
- case 2: colormap = cbluemap; break;
- case 3: colormap = cgreenmap; break;
- case 4: colormap = cgraymap; break;
- case 5: colormap = credmap; break;
- default: colormap = cgreenmap; break;
- }
-
// heavily simplified -- we don't need to know x or y position,
// just the stop position
deststop = screens[0] + vid.rowbytes * min(plines, vid.height);
for (buf = screens[0]; buf < deststop; ++buf)
- *buf = colormap[*buf];
+ *buf = consolebgmap[*buf];
}
// Gets string colormap, used for 0x80 color codes
diff --git a/src/v_video.h b/src/v_video.h
index 70255d0e..353f84c1 100644
--- a/src/v_video.h
+++ b/src/v_video.h
@@ -145,7 +145,7 @@ void V_DrawFlatFill(INT32 x, INT32 y, INT32 w, INT32 h, lumpnum_t flatnum);
// fade down the screen buffer before drawing the menu over
void V_DrawFadeScreen(void);
-void V_DrawFadeConsBack(INT32 plines, INT32 pcolor);
+void V_DrawFadeConsBack(INT32 plines);
// draw a single character
void V_DrawCharacter(INT32 x, INT32 y, INT32 c, boolean lowercaseallowed);
diff --git a/src/w_wad.c b/src/w_wad.c
index 40fea522..3a828559 100644
--- a/src/w_wad.c
+++ b/src/w_wad.c
@@ -133,6 +133,47 @@ void W_Shutdown(void)
static char filenamebuf[MAX_WADPATH];
+// W_OpenWadFile
+// Helper function for opening the WAD file.
+// Returns the FILE * handle for the file, or NULL if not found or could not be opened
+// If "useerrors" is true then print errors in the console, else just don't bother
+// "filename" may be modified to have the correct path the actual file is located in, if necessary
+FILE *W_OpenWadFile(const char **filename, boolean useerrors)
+{
+ FILE *handle;
+
+ strncpy(filenamebuf, *filename, MAX_WADPATH);
+ filenamebuf[MAX_WADPATH - 1] = '\0';
+ *filename = filenamebuf;
+
+ // open wad file
+ if ((handle = fopen(*filename, "rb")) == NULL)
+ {
+ // If we failed to load the file with the path as specified by
+ // the user, strip the directories and search for the file.
+ nameonly(filenamebuf);
+
+ // If findfile finds the file, the full path will be returned
+ // in filenamebuf == *filename.
+ if (findfile(filenamebuf, NULL, true))
+ {
+ if ((handle = fopen(*filename, "rb")) == NULL)
+ {
+ if (useerrors)
+ CONS_Alert(CONS_ERROR, M_GetText("Can't open %s\n"), *filename);
+ return NULL;
+ }
+ }
+ else
+ {
+ if (useerrors)
+ CONS_Alert(CONS_ERROR, M_GetText("File %s not found.\n"), *filename);
+ return NULL;
+ }
+ }
+ return handle;
+}
+
// search for all DEHACKED lump in all wads and load it
static inline void W_LoadDehackedLumps(UINT16 wadnum)
{
@@ -234,7 +275,6 @@ static void W_InvalidateLumpnumCache(void)
memset(lumpnumcache, 0, sizeof (lumpnumcache));
}
-
// Allocate a wadfile, setup the lumpinfo (directory) and
// lumpcache, add the wadfile to the current active wadfiles
//
@@ -271,33 +311,9 @@ UINT16 W_LoadWadFile(const char *filename)
return INT16_MAX;
}
- strncpy(filenamebuf, filename, MAX_WADPATH);
- filenamebuf[MAX_WADPATH - 1] = '\0';
- filename = filenamebuf;
-
// open wad file
- if ((handle = fopen(filename, "rb")) == NULL)
- {
- // If we failed to load the file with the path as specified by
- // the user, strip the directories and search for the file.
- nameonly(filenamebuf);
-
- // If findfile finds the file, the full path will be returned
- // in filenamebuf == filename.
- if (findfile(filenamebuf, NULL, true))
- {
- if ((handle = fopen(filename, "rb")) == NULL)
- {
- CONS_Alert(CONS_ERROR, M_GetText("Can't open %s\n"), filename);
- return INT16_MAX;
- }
- }
- else
- {
- CONS_Alert(CONS_ERROR, M_GetText("File %s not found.\n"), filename);
- return INT16_MAX;
- }
- }
+ if ((handle = W_OpenWadFile(&filename, true)) == NULL)
+ return INT16_MAX;
// Check if wad files will overflow fileneededbuffer. Only the filename part
// is send in the packet; cf.
@@ -475,11 +491,11 @@ UINT16 W_LoadWadFile(const char *filename)
//
CONS_Printf(M_GetText("Added file %s (%u lumps)\n"), filename, numlumps);
wadfiles[numwadfiles] = wadfile;
- W_LoadDehackedLumps(numwadfiles);
+ numwadfiles++; // must come BEFORE W_LoadDehackedLumps, so any addfile called by COM_BufInsertText called by Lua doesn't overwrite what we just loaded
+ W_LoadDehackedLumps(numwadfiles-1);
W_InvalidateLumpnumCache();
- numwadfiles++;
return wadfile->numlumps;
}
@@ -1115,21 +1131,11 @@ static int W_VerifyFile(const char *filename, lumpchecklist_t *checklist,
size_t i, j;
int goodfile = false;
- if (!checklist) I_Error("No checklist for %s\n", filename);
- strlcpy(filenamebuf, filename, MAX_WADPATH);
- filename = filenamebuf;
+ if (!checklist)
+ I_Error("No checklist for %s\n", filename);
// open wad file
- if ((handle = fopen(filename, "rb")) == NULL)
- {
- nameonly(filenamebuf); // leave full path here
- if (findfile(filenamebuf, NULL, true))
- {
- if ((handle = fopen(filename, "rb")) == NULL)
- return -1;
- }
- else
- return -1;
- }
+ if ((handle = W_OpenWadFile(&filename, false)) == NULL)
+ return -1;
// detect dehacked file with the "soc" extension
if (stricmp(&filename[strlen(filename) - 4], ".soc") != 0
@@ -1223,6 +1229,7 @@ int W_VerifyNMUSlumps(const char *filename)
{"COLORMAP", 8},
{"PAL", 3},
{"CLM", 3},
+ {"TRANS", 5},
{NULL, 0},
};
return W_VerifyFile(filename, NMUSlist, false);
diff --git a/src/w_wad.h b/src/w_wad.h
index c13f6933..f7ea64a5 100644
--- a/src/w_wad.h
+++ b/src/w_wad.h
@@ -54,10 +54,8 @@ typedef struct
#define lumpcache_t void *
-// Annoying cyclic dependency workaround: this inlcusion must come after
-// the definition of MAX_WADPATH.
#ifdef HWRENDER
-#include "m_misc.h"
+#include "m_aatree.h"
#endif
typedef struct wadfile_s
@@ -84,6 +82,8 @@ extern wadfile_t *wadfiles[MAX_WADFILES];
void W_Shutdown(void);
+// Opens a WAD file. Returns the FILE * handle for the file, or NULL if not found or could not be opened
+FILE *W_OpenWadFile(const char **filename, boolean useerrors);
// Load and add a wadfile to the active wad files, returns numbers of lumps, INT16_MAX on error
UINT16 W_LoadWadFile(const char *filename);
#ifdef DELFILE
diff --git a/src/win32/Makefile.cfg b/src/win32/Makefile.cfg
index f309f7db..99b8bc9b 100644
--- a/src/win32/Makefile.cfg
+++ b/src/win32/Makefile.cfg
@@ -85,13 +85,21 @@ endif
OBJS=$(OBJDIR)/dx_error.o $(OBJDIR)/fabdxlib.o $(OBJDIR)/win_vid.o $(OBJDIR)/win_dll.o
endif
+
+ZLIB_CFLAGS?=-I../libs/zlib
+ifdef MINGW64
+ZLIB_LDFLAGS?=-L../libs/zlib/win32 -lz64
+else
+ZLIB_LDFLAGS?=-L../libs/zlib/win32 -lz32
+endif
+
ifndef NOPNG
ifndef PNG_CONFIG
- PNG_CFLAGS?=-I../libs/libpng-src -I../libs/zlib
+ PNG_CFLAGS?=-I../libs/libpng-src
ifdef MINGW64
- PNG_LDFLAGS?=-L../libs/libpng-src/projects -lpng64 -L../libs/zlib/win32 -lz64
+ PNG_LDFLAGS?=-L../libs/libpng-src/projects -lpng64
else
- PNG_LDFLAGS?=-L../libs/libpng-src/projects -lpng32 -L../libs/zlib/win32 -lz32
+ PNG_LDFLAGS?=-L../libs/libpng-src/projects -lpng32
endif #MINGW64
endif #PNG_CONFIG
endif #NOPNG
diff --git a/src/win32/Srb2win-vc10.vcxproj b/src/win32/Srb2win-vc10.vcxproj
index 1e9d8241..064f75d7 100644
--- a/src/win32/Srb2win-vc10.vcxproj
+++ b/src/win32/Srb2win-vc10.vcxproj
@@ -145,6 +145,7 @@
+
@@ -300,6 +301,7 @@
+
diff --git a/src/win32/Srb2win-vc10.vcxproj.filters b/src/win32/Srb2win-vc10.vcxproj.filters
index 3f5b84bf..b2647ea1 100644
--- a/src/win32/Srb2win-vc10.vcxproj.filters
+++ b/src/win32/Srb2win-vc10.vcxproj.filters
@@ -255,6 +255,9 @@
LUA
+
+ M_Misc
+
M_Misc
@@ -662,6 +665,9 @@
M_Misc
+
+ M_Misc
+
M_Misc
diff --git a/src/win32/win_cd.c b/src/win32/win_cd.c
index d73b9552..ae13d3e5 100644
--- a/src/win32/win_cd.c
+++ b/src/win32/win_cd.c
@@ -180,9 +180,9 @@ static LPSTR hms(UINT seconds)
hours = minutes / 60;
minutes %= 60;
if (hours > 0)
- sprintf (s, "%lu:%02lu:%02lu", hours, minutes, seconds);
+ sprintf (s, "%lu:%02lu:%02lu", (long unsigned int)hours, (long unsigned int)minutes, (long unsigned int)seconds);
else
- sprintf (s, "%2lu:%02lu", minutes, seconds);
+ sprintf (s, "%2lu:%02lu", (long unsigned int)minutes, (long unsigned int)seconds);
return s;
}
diff --git a/src/win32/win_dbg.c b/src/win32/win_dbg.c
index 23416af1..fe6ebb04 100644
--- a/src/win32/win_dbg.c
+++ b/src/win32/win_dbg.c
@@ -20,7 +20,9 @@
#include
+#ifndef HAVE_SDL
#include "win_main.h"
+#endif
#include "../doomdef.h" //just for VERSION
#include "win_dbg.h"
#include "../m_argv.h" //print the parameter in the log
diff --git a/src/win32/win_main.c b/src/win32/win_main.c
index 663eddbd..4ac05f94 100644
--- a/src/win32/win_main.c
+++ b/src/win32/win_main.c
@@ -69,7 +69,7 @@ static HCURSOR windowCursor = NULL; // main window cursor
static LPCSTR wClassName = "SRB2WC";
-boolean appActive = false; // app window is active
+INT appActive = false; // app window is active
#ifdef LOGMESSAGES
FILE *logstream;
@@ -470,7 +470,7 @@ static inline BOOL tlErrorMessage(const TCHAR *err)
//
// warn user if there is one
//
- printf("Error %Ts..\n", err);
+ printf("Error %s..\n", err);
fflush(stdout);
MessageBox(hWndMain, err, TEXT("ERROR"), MB_OK);
diff --git a/src/win32/win_main.h b/src/win32/win_main.h
index ed55246a..326a813d 100644
--- a/src/win32/win_main.h
+++ b/src/win32/win_main.h
@@ -23,7 +23,7 @@
extern HWND hWndMain;
-extern boolean appActive;
+extern INT appActive;
VOID I_GetSysMouseEvents(INT mouse_state);
extern UINT MSHWheelMessage;
diff --git a/src/win32/win_sys.c b/src/win32/win_sys.c
index 0331080c..80b89a6e 100644
--- a/src/win32/win_sys.c
+++ b/src/win32/win_sys.c
@@ -3598,6 +3598,18 @@ INT32 I_PutEnv(char *variable)
return putenv(variable);
}
+INT32 I_ClipboardCopy(const char *data, size_t size)
+{
+ (void)data;
+ (void)size;
+ return -1;
+}
+
+const char *I_ClipboardPaste(void)
+{
+ return NULL;
+}
+
typedef BOOL (WINAPI *p_IsProcessorFeaturePresent) (DWORD);
const CPUInfoFlags *I_CPUInfo(void)
diff --git a/src/win32ce/win_sys.c b/src/win32ce/win_sys.c
index 88764ef7..3b6a4725 100644
--- a/src/win32ce/win_sys.c
+++ b/src/win32ce/win_sys.c
@@ -3470,6 +3470,18 @@ INT32 I_PutEnv(char *variable)
return putenv(variable);
}
+INT32 I_ClipboardCopy(const char *data, size_t size)
+{
+ (void)data;
+ (void)size;
+ return -1;
+}
+
+char *I_ClipboardPaste(void)
+{
+ return NULL;
+}
+
typedef BOOL (WINAPI *MyFunc3) (DWORD);
const CPUInfoFlags *I_CPUInfo(void)
diff --git a/src/y_inter.c b/src/y_inter.c
index b2e1cdf9..42f1e223 100644
--- a/src/y_inter.c
+++ b/src/y_inter.c
@@ -159,6 +159,20 @@ static void Y_CalculateMatchWinners(void);
static void Y_FollowIntermission(void);
static void Y_UnloadData(void);
+// Stuff copy+pasted from st_stuff.c
+static INT32 SCX(INT32 x)
+{
+ return FixedInt(FixedMul(x<