diff --git a/.circleci/config.yml b/.circleci/config.yml
new file mode 100644
index 000000000..b5c43d017
--- /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/CMakeLists.txt b/CMakeLists.txt
index cb93d22f0..31597f399 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.17
LANGUAGES C)
if(${PROJECT_SOURCE_DIR} MATCHES ${PROJECT_BINARY_DIR})
diff --git a/README.md b/README.md
index eb06156b4..d16071454 100644
--- a/README.md
+++ b/README.md
@@ -2,6 +2,7 @@
[](https://ci.appveyor.com/project/STJr/srb2)
[](https://travis-ci.org/STJr/SRB2)
+[](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/).
diff --git a/SRB2.cbp b/SRB2.cbp
index 99a712264..74ec96c6e 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,1811 +1491,265 @@ HW3SOUND for 3D hardware sound support
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
+
+
-
+
-
-
-
-
-
-
-
-
-
-
+
+
-
+
@@ -4166,15 +1758,7 @@ HW3SOUND for 3D hardware sound support
-
-
-
-
-
-
-
-
-
+
@@ -4183,7 +1767,15 @@ HW3SOUND for 3D hardware sound support
-
+
+
+
+
+
+
+
+
+
@@ -4192,7 +1784,7 @@ HW3SOUND for 3D hardware sound support
-
+
@@ -4200,7 +1792,7 @@ HW3SOUND for 3D hardware sound support
-
+
@@ -4209,15 +1801,7 @@ HW3SOUND for 3D hardware sound support
-
-
-
-
-
-
-
-
-
+
@@ -4226,7 +1810,7 @@ HW3SOUND for 3D hardware sound support
-
+
@@ -4235,7 +1819,7 @@ HW3SOUND for 3D hardware sound support
-
+
@@ -4244,7 +1828,7 @@ HW3SOUND for 3D hardware sound support
-
+
@@ -4253,7 +1837,15 @@ HW3SOUND for 3D hardware sound support
-
+
+
+
+
+
+
+
+
+
@@ -4262,15 +1854,7 @@ HW3SOUND for 3D hardware sound support
-
-
-
-
-
-
-
-
-
+
@@ -4279,7 +1863,7 @@ HW3SOUND for 3D hardware sound support
-
+
@@ -4288,7 +1872,15 @@ HW3SOUND for 3D hardware sound support
-
+
+
+
+
+
+
+
+
+
@@ -4297,24 +1889,7 @@ HW3SOUND for 3D hardware sound support
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
@@ -4324,120 +1899,39 @@ HW3SOUND for 3D hardware sound support
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
@@ -4460,46 +1954,17 @@ HW3SOUND for 3D hardware sound support
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
+
+
-
-
+
+
@@ -4511,37 +1976,8 @@ HW3SOUND for 3D hardware sound support
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
@@ -4667,70 +2103,12 @@ HW3SOUND for 3D hardware sound support
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
diff --git a/appveyor.yml b/appveyor.yml
index e0ee99c61..b0544a90b 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -1,4 +1,4 @@
-version: 2.1.16.{branch}-{build}
+version: 2.1.17.{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
build_script:
- cmd: mingw32-make.exe %SRB2_MFLAGS% %CONFIGURATION%=1 clean
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index ba354c289..46a42a92c 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -390,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.cfg b/src/Makefile.cfg
index 3630c6367..22546fbff 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
diff --git a/src/d_clisrv.c b/src/d_clisrv.c
index 7e9dcf8ef..f47f6637c 100644
--- a/src/d_clisrv.c
+++ b/src/d_clisrv.c
@@ -72,14 +72,21 @@
#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;
@@ -404,7 +411,7 @@ static void ExtraDataTicker(void)
// 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 (!server)
+ if (client)
D_FreeTextcmd(gametic);
}
@@ -868,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;
@@ -883,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);
@@ -897,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]);
@@ -1038,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));
+ 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:
@@ -1151,25 +1154,31 @@ 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
@@ -1458,6 +1467,10 @@ static void SV_SendSaveGame(INT32 node)
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
@@ -1750,7 +1763,7 @@ static boolean CL_ServerConnectionSearchTicker(boolean viams, tic_t *asksent)
return false;
}
- if (!server)
+ if (client)
{
D_ParseFileneeded(serverlist[i].info.fileneedednum,
serverlist[i].info.fileneeded);
@@ -1924,7 +1937,7 @@ static boolean CL_ServerConnectionTicker(boolean viams, const char *tmpsave, tic
*oldtic = I_GetTime();
#ifdef CLIENT_LOADINGSCREEN
- if (!server && cl_mode != CL_CONNECTED && cl_mode != CL_ABORTED)
+ if (client && cl_mode != CL_CONNECTED && cl_mode != CL_ABORTED)
{
F_TitleScreenTicker(true);
F_TitleScreenDrawer();
@@ -1966,7 +1979,7 @@ static void CL_ConnectToServer(boolean viams)
cl_mode = CL_SEARCHING;
#ifdef CLIENT_LOADINGSCREEN
- lastfilenum = 0;
+ lastfilenum = -1;
#endif
#ifdef JOININGAME
@@ -2037,7 +2050,7 @@ static void CL_ConnectToServer(boolean viams)
pnumnodes++;
}
}
- while (!(cl_mode == CL_CONNECTED && (!server || (server && nodewaited <= pnumnodes))));
+ while (!(cl_mode == CL_CONNECTED && (client || (server && nodewaited <= pnumnodes))));
DEBFILE(va("Synchronisation Finished\n"));
@@ -2574,6 +2587,14 @@ static void Command_Kick(void)
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;
+ }
if (COM_Argc() == 2)
{
WRITEUINT8(p, KICK_MSG_GO_AWAY);
@@ -2786,7 +2807,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);
@@ -2809,6 +2835,9 @@ void D_ClientServerInit(void)
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);
@@ -2844,6 +2873,7 @@ static void ResetNode(INT32 node)
supposedtics[node] = gametic;
nodewaiting[node] = 0;
playerpernode[node] = 0;
+ sendingsavegame[node] = false;
}
void SV_ResetServer(void)
@@ -3136,7 +3166,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)
@@ -3399,12 +3429,19 @@ static void HandlePacketFromAwayNode(SINT8 node)
}
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"),
- netbuffer->u.serverrefuse.reason), NULL, MM_NOTHING);
+ reason), NULL, MM_NOTHING);
+
+ free(reason);
// Will be reset by caller. Signals refusal.
cl_mode = CL_ABORTED;
@@ -3425,7 +3462,7 @@ static void HandlePacketFromAwayNode(SINT8 node)
if (cl_mode != CL_WAITJOINRESPONSE)
break;
- if (!server)
+ if (client)
{
maketic = gametic = neededtic = (tic_t)LONG(netbuffer->u.servercfg.gametic);
gametype = netbuffer->u.servercfg.gametype;
@@ -3553,7 +3590,7 @@ FILESTAMP
case PT_CLIENT2MIS:
case PT_NODEKEEPALIVE:
case PT_NODEKEEPALIVEMIS:
- if (!server)
+ if (client)
break;
// Ignore tics from those not synched
@@ -3586,6 +3623,13 @@ FILESTAMP
|| 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);
@@ -3652,7 +3696,7 @@ FILESTAMP
case PT_TEXTCMD2: // splitscreen special
netconsole = nodetoplayer2[node];
case PT_TEXTCMD:
- if (!server)
+ if (client)
break;
if (netconsole < 0 || netconsole >= MAXPLAYERS)
@@ -3696,7 +3740,7 @@ FILESTAMP
break;
case PT_NODETIMEOUT:
case PT_CLIENTQUIT:
- if (!server)
+ if (client)
break;
// nodeingame will be put false in the execution of kick command
@@ -3728,7 +3772,7 @@ FILESTAMP
// 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);
+ CONS_Alert(CONS_WARNING, M_GetText("%s received from non-host %d\n"), "PT_RESYNCHEND", node);
if (server)
{
@@ -3806,13 +3850,20 @@ FILESTAMP
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 recieved from non-host %d\n"), "PT_RESYNCHING", node);
+ CONS_Alert(CONS_WARNING, M_GetText("%s received from non-host %d\n"), "PT_RESYNCHING", node);
if (server)
{
@@ -3832,7 +3883,7 @@ FILESTAMP
// 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);
+ CONS_Alert(CONS_WARNING, M_GetText("%s received from non-host %d\n"), "PT_PING", node);
if (server)
{
@@ -3846,7 +3897,7 @@ FILESTAMP
}
//Update client ping table from the server.
- if (!server)
+ if (client)
{
INT32 i;
for (i = 0; i < MAXNETNODES; i++)
@@ -3859,7 +3910,7 @@ FILESTAMP
case PT_SERVERCFG:
break;
case PT_FILEFRAGMENT:
- if (!server)
+ if (client)
Got_Filetxpak();
break;
default:
@@ -3889,17 +3940,18 @@ FILESTAMP
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
@@ -3916,7 +3968,7 @@ FILESTAMP
// Packet received from someone already playing
if (nodeingame[node])
HandlePacketFromPlayer(node);
- // Packet received from someone trying to join
+ // Packet received from someone not playing
else
HandlePacketFromAwayNode(node);
}
@@ -4047,7 +4099,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);
@@ -4057,7 +4109,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;
@@ -4072,23 +4124,23 @@ static void CL_SendClientCmd(void)
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;
}
}
@@ -4352,7 +4404,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))
{
@@ -4366,7 +4418,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])
{
@@ -4381,7 +4433,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.
@@ -4391,7 +4443,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);
@@ -4440,7 +4492,7 @@ void NetUpdate(void)
}
#endif
- if (!server)
+ if (client)
maketic = neededtic;
Local_Maketic(realtics); // make local tic, and call menu?
@@ -4455,7 +4507,7 @@ FILESTAMP
MasterClient_Ticker(); // Acking the Master Server
- if (!server)
+ if (client)
{
if (!resynch_local_inprogress)
CL_SendClientCmd(); // Send tic cmd
@@ -4505,6 +4557,11 @@ FILESTAMP
}
}
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)
{
diff --git a/src/d_clisrv.h b/src/d_clisrv.h
index fe80be1be..e7f1e8433 100644
--- a/src/d_clisrv.h
+++ b/src/d_clisrv.h
@@ -80,6 +80,9 @@ typedef enum
void Command_Drop(void);
void Command_Droprate(void);
#endif
+#ifdef _DEBUG
+void Command_Numnodes(void);
+#endif
#if defined(_MSC_VER)
#pragma pack(1)
@@ -133,7 +136,7 @@ typedef struct
fixed_t flagz[2];
UINT32 ingame; // Spectator bit for each player
- UINT32 ctfteam; // If not spectator, then which team?
+ 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
@@ -442,6 +445,7 @@ extern consvar_t cv_playbackspeed;
#define KICK_MSG_CUSTOM_BAN 8
extern boolean server;
+#define client (!server)
extern boolean dedicated; // For dedicated server
extern UINT16 software_MAXPACKETLENGTH;
extern boolean acceptnewnode;
@@ -449,13 +453,14 @@ 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
tic_t ExpandTics(INT32 low);
diff --git a/src/d_main.c b/src/d_main.c
index 2caf50087..4080087c1 100644
--- a/src/d_main.c
+++ b/src/d_main.c
@@ -187,7 +187,7 @@ UINT8 altdown = 0; // 0x1 left, 0x2 right
//
static inline void D_ModifierKeyResponder(event_t *ev)
{
- if (ev->type == ev_keydown) switch (ev->data1)
+ if (ev->type == ev_keydown || ev->type == ev_console) switch (ev->data1)
{
case KEY_LSHIFT: shiftdown |= 0x1; return;
case KEY_RSHIFT: shiftdown |= 0x2; return;
diff --git a/src/d_net.c b/src/d_net.c
index 6be1dbe5c..7f16c302d 100644
--- a/src/d_net.c
+++ b/src/d_net.c
@@ -42,7 +42,7 @@
// 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;
@@ -142,7 +142,7 @@ typedef struct
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
+ 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
@@ -274,6 +275,38 @@ static boolean GetFreeAcknum(UINT8 *freeack, boolean lowtimer)
return false;
}
+/** 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)
{
@@ -298,7 +331,7 @@ 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);
}
@@ -452,8 +485,13 @@ static void GotAcks(void)
}
#endif
-static inline void Net_ConnectionTimeout(INT32 node)
+void Net_ConnectionTimeout(INT32 node)
{
+ // 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;
@@ -484,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));
@@ -520,7 +558,7 @@ void Net_AckTicker(void)
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);
@@ -678,7 +716,7 @@ void Net_CloseConnection(INT32 node)
if (!node)
return;
- nodes[node].flags |= CLOSE;
+ nodes[node].flags |= NF_CLOSE;
// try to Send ack back (two army problem)
if (GetAcktosend(node))
@@ -813,18 +851,20 @@ static void DebugPrintpacket(const char *header)
case PT_SERVERTICS:
{
servertics_pak *serverpak = &netbuffer->u.serverpak;
- ticcmd_t *cmd = &serverpak->cmds[serverpak->numslots * serverpak->numtics];
- size_t ntxtcmd = &((UINT8 *)netbuffer)[doomcom->datalength] - (UINT8 *)cmd;
+ 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(serverpak->starttic), serverpak->numslots, serverpak->numtics, sizeu1(ntxtcmd));
- fprintfstring((char *)cmd, 3);
+ /// \todo Display more readable information about net commands
+ fprintfstringnewline((char *)cmd, ntxtcmd);
+ /*fprintfstring((char *)cmd, 3);
if (ntxtcmd > 4)
{
- fprintf(debugfile, "[%s]", netxcmdnames[*(((UINT8 *)cmd) + 3) - 1]);
+ fprintf(debugfile, "[%s]", netxcmdnames[*((cmd) + 3) - 1]);
fprintfstring(((char *)cmd) + 4, ntxtcmd - 4);
}
- fprintf(debugfile, "\n");
+ fprintf(debugfile, "\n");*/
break;
}
case PT_CLIENTCMD:
@@ -891,7 +931,7 @@ void Command_Drop(void)
if (COM_Argc() < 2)
{
CONS_Printf("drop [quantity]: drop packets\n"
- "drop reset: cancel all packet drops");
+ "drop reset: cancel all packet drops\n");
return;
}
@@ -951,12 +991,14 @@ void Command_Droprate(void)
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
@@ -1067,6 +1109,8 @@ boolean HSendPacket(INT32 node, boolean reliable, UINT8 acknum, size_t packetlen
//
boolean HGetPacket(void)
{
+ //boolean nodejustjoined;
+
// Get a packet from self
if (rebound_tail != rebound_head)
{
@@ -1092,9 +1136,10 @@ 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
@@ -1110,6 +1155,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;
}
@@ -1119,11 +1165,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();
@@ -1136,9 +1197,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)
@@ -1223,7 +1285,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
diff --git a/src/d_net.h b/src/d_net.h
index 190e07a60..84814ce39 100644
--- a/src/d_net.h
+++ b/src/d_net.h
@@ -39,6 +39,7 @@ extern SINT8 nodetoplayer2[MAXNETNODES]; // Say the numplayer for this node if a
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);
// If reliable return true if packet sent, 0 else
@@ -53,6 +54,7 @@ boolean D_CheckNetGame(void);
void D_CloseConnection(void);
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);
diff --git a/src/d_netcmd.c b/src/d_netcmd.c
index d70805e1c..f61c80cb2 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
@@ -546,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);
@@ -1005,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.
@@ -1616,7 +1622,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;
@@ -1943,7 +1949,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];
@@ -2658,7 +2664,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;
@@ -2717,7 +2723,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
@@ -2739,7 +2745,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;
@@ -2823,7 +2829,7 @@ static void Command_MotD_f(void)
return;
}
- if ((netgame || multiplayer) && !server)
+ if ((netgame || multiplayer) && client)
SendNetXCmd(XD_SETMOTD, mymotd, sizeof(motd));
else
{
@@ -3080,7 +3086,7 @@ static void Got_RequestAddfilecmd(UINT8 **cp, INT32 playernum)
READMEM(*cp, md5sum, 16);
// Only the server processes this message.
- if (!server)
+ if (client)
return;
// Disallow non-printing characters and semicolons.
@@ -3347,6 +3353,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.
@@ -3989,7 +4000,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++;
@@ -4091,8 +4102,7 @@ static void Skin_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_netfil.c b/src/d_netfil.c
index 4e3d70fa9..bf4e59878 100644
--- a/src/d_netfil.c
+++ b/src/d_netfil.c
@@ -97,7 +97,7 @@ 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.
@@ -487,6 +487,9 @@ static void SV_SendFile(INT32 node, const char *filename, UINT8 fileid)
INT32 i;
char wadfilename[MAX_WADPATH];
+ if (cv_noticedownload.value)
+ CONS_Printf("Sending file \"%s\" to node %d\n", filename, node);
+
// Find the last file in the list and set a pointer to its "next" field
q = &transfer[node].txlist;
while (*q)
@@ -609,6 +612,8 @@ static void SV_EndFileSend(INT32 node)
switch (p->ram)
{
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->id.filename);
@@ -636,6 +641,9 @@ static void SV_EndFileSend(INT32 node)
/** 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)
@@ -644,17 +652,38 @@ void SV_FileSendTicker(void)
filetx_pak *p;
size_t size;
filetx_t *f;
- INT32 packetsent = PACKETPERTIC, ram, i;
+ INT32 packetsent, ram, i, j;
+ INT32 maxpacketsent;
- if (!filestosend)
+ if (!filestosend) // No file to send
return;
- if (!packetsent)
- packetsent++;
+
+ if (cv_downloadspeed.value) // New (and experimental) behavior
+ {
+ 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, ram = 0; ram < MAXNETNODES;
- i = (i+1) % MAXNETNODES, ram++)
+ for (i = currentnode, j = 0; j < MAXNETNODES;
+ i = (i+1) % MAXNETNODES, j++)
{
if (transfer[i].txlist)
goto found;
@@ -713,7 +742,6 @@ void SV_FileSendTicker(void)
p->position |= LONG(0x80000000);
p->fileid = f->fileid;
p->size = SHORT((UINT16)size);
- netbuffer->packettype = PT_FILEFRAGMENT;
// Send the packet
if (HSendPacket(i, true, 0, FILETXHEADER + size)) // Reliable SEND
@@ -735,27 +763,40 @@ void SV_FileSendTicker(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));
+ //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].file)
+ if (file->file)
I_Error("Got_Filetxpak: already open file\n");
- fileneeded[filenum].file = fopen(fileneeded[filenum].filename, "wb");
- if (!fileneeded[filenum].file)
- 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;
+ 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);
@@ -764,27 +805,47 @@ void Got_Filetxpak(void)
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].file, pos, SEEK_SET);
- if (fwrite(netbuffer->u.filetxpak.data,size,1,fileneeded[filenum].file) != 1)
- I_Error("Can't write to %s: %s\n",fileneeded[filenum].filename, strerror(ferror(fileneeded[filenum].file)));
- fileneeded[filenum].currentsize += size;
+ 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)
+ if (file->currentsize == file->totalsize)
{
- fclose(fileneeded[filenum].file);
- fileneeded[filenum].file = 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");
-
+ {
+ 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)
{
@@ -797,12 +858,23 @@ void Got_Filetxpak(void)
#endif
}
-/** Cancels all file requests for a node
+/** \brief Checks if a node is downloading a file
*
- * \param node The destination
- * \sa SV_EndFileSend
+ * \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)
diff --git a/src/d_netfil.h b/src/d_netfil.h
index e82b57d67..c9085a5b0 100644
--- a/src/d_netfil.h
+++ b/src/d_netfil.h
@@ -65,6 +65,7 @@ void SV_SendRam(INT32 node, void *data, size_t size, freemethod_t freemethod,
void SV_FileSendTicker(void);
void Got_Filetxpak(void);
+boolean SV_SendingFile(INT32 node);
boolean CL_CheckDownloadable(void);
boolean CL_SendRequestFile(void);
diff --git a/src/doomdef.h b/src/doomdef.h
index 4b2d8c737..99e54c077 100644
--- a/src/doomdef.h
+++ b/src/doomdef.h
@@ -150,9 +150,9 @@ extern FILE *logstream;
// we use comprevision and compbranch instead.
#else
#define VERSION 201 // Game version
-#define SUBVERSION 16 // more precise version number
-#define VERSIONSTRING "v2.1.16"
-#define VERSIONSTRINGW L"v2.1.16"
+#define SUBVERSION 17 // more precise version number
+#define VERSIONSTRING "v2.1.17"
+#define VERSIONSTRINGW L"v2.1.17"
// Hey! If you change this, add 1 to the MODVERSION below!
// Otherwise we can't force updates!
#endif
@@ -214,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 21
+#define MODVERSION 22
// =========================================================================
diff --git a/src/f_finale.c b/src/f_finale.c
index 2245a534f..692abb35f 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,7 @@ 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
@@ -1020,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",
diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c
index 5251e0b30..45b59f9b8 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
@@ -1558,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)
{
@@ -1608,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)
@@ -1638,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;
@@ -1683,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);
}
@@ -1695,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
@@ -1721,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;
@@ -1766,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;
@@ -2134,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)
@@ -2232,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
@@ -2366,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;
@@ -4401,7 +4405,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;
@@ -4455,19 +4458,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)
{
@@ -4501,8 +4523,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;
@@ -5289,6 +5311,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
@@ -5301,7 +5328,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
diff --git a/src/hardware/r_opengl/r_opengl.c b/src/hardware/r_opengl/r_opengl.c
index 54dd94854..3a0bf7054 100644
--- a/src/hardware/r_opengl/r_opengl.c
+++ b/src/hardware/r_opengl/r_opengl.c
@@ -1836,7 +1836,7 @@ EXPORT void HWRAPI(SetSpecialState) (hwdspecialstate_t IdState, INT32 Value)
}
}
-static inline 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)
+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;
diff --git a/src/hu_stuff.c b/src/hu_stuff.c
index a57566910..646bdcbad 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);
@@ -1102,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/i_net.h b/src/i_net.h
index e378f5723..2bfa5eac7 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_tcp.c b/src/i_tcp.c
index f6212458b..c65a536a8 100644
--- a/src/i_tcp.c
+++ b/src/i_tcp.c
@@ -179,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"
@@ -482,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;
@@ -506,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;
@@ -535,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)
{
@@ -564,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
@@ -1256,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_hudlib.c b/src/lua_hudlib.c
index 7aadd9c0e..60cbbe501 100644
--- a/src/lua_hudlib.c
+++ b/src/lua_hudlib.c
@@ -369,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 c512bf3c5..208aebe37 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/m_aatree.h b/src/m_aatree.h
index c9077b974..eeaebca3b 100644
--- a/src/m_aatree.h
+++ b/src/m_aatree.h
@@ -28,4 +28,4 @@ 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
\ No newline at end of file
+#endif
diff --git a/src/m_cheat.c b/src/m_cheat.c
index 89334596e..3bbaadc5b 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 34fd25db2..1cf9abbae 100644
--- a/src/m_fixed.h
+++ b/src/m_fixed.h
@@ -248,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;
}
@@ -266,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)
@@ -289,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;
}
@@ -309,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)<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_inter.c b/src/p_inter.c
index cf5512a18..4892d9775 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);
}
}
diff --git a/src/p_map.c b/src/p_map.c
index c4616db48..86776f8d1 100644
--- a/src/p_map.c
+++ b/src/p_map.c
@@ -985,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
@@ -1022,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
diff --git a/src/p_maputl.c b/src/p_maputl.c
index fea8530a1..46b033386 100644
--- a/src/p_maputl.c
+++ b/src/p_maputl.c
@@ -572,51 +572,54 @@ void P_LineOpening(line_t *linedef, mobj_t *mobj)
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
+ // 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
+ // 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_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);
+ {
+ 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(mobj->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;
+ }
}
}
diff --git a/src/p_mobj.c b/src/p_mobj.c
index 5e5961d41..b9412ee77 100644
--- a/src/p_mobj.c
+++ b/src/p_mobj.c
@@ -2017,13 +2017,13 @@ static void P_AdjustMobjFloorZ_FFloors(mobj_t *mo, sector_t *sector, UINT8 motyp
delta2 = thingtop - (bottomheight + ((topheight - bottomheight)/2));
if (topheight > mo->floorz && abs(delta1) < abs(delta2)
&& !(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)
+ && ((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)
- && ((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
+ && ((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;
}
@@ -4436,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)
@@ -4450,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)
@@ -4566,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++)
{
@@ -4622,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
{
@@ -4631,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
@@ -4641,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);
@@ -6048,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
@@ -7683,6 +7685,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;
diff --git a/src/p_saveg.c b/src/p_saveg.c
index 5e457ca3a..75f7b3e51 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 111c717d3..8e746457b 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;
@@ -2587,10 +2651,6 @@ boolean P_SetupLevel(boolean skipprecip)
R_ReInitColormaps(mapheaderinfo[gamemap-1]->palette);
CON_SetupBackColormap();
- // now part of level loading since in future each level may have
- // its own anim texture sequences, switches etc.
- P_InitPicAnims();
-
// SRB2 determines the sky texture to be used depending on the map header.
P_SetupLevelSky(mapheaderinfo[gamemap-1]->skynum, true);
@@ -3001,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 0d735fd71..3bca11047 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_spec.c b/src/p_spec.c
index 30b08ebb1..3d83561a9 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)++;
}
@@ -1498,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--)
@@ -5321,6 +5344,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);
@@ -7428,7 +7455,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 3867137ad..cb5235854 100644
--- a/src/p_user.c
+++ b/src/p_user.c
@@ -2280,14 +2280,13 @@ static void P_DoClimbing(player_t *player)
fixed_t platy;
subsector_t *glidesector;
boolean climb = true;
- boolean onesided = ((player->lastsidehit != -1 && player->lastlinehit != -1) && !(lines[player->lastlinehit].backsector));
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 (onesided || glidesector->sector != player->mo->subsector->sector)
+ if (!glidesector || glidesector->sector != player->mo->subsector->sector)
{
boolean floorclimb = false;
boolean thrust = false;
@@ -2295,7 +2294,7 @@ static void P_DoClimbing(player_t *player)
boolean skyclimber = false;
fixed_t floorheight, ceilingheight; // ESLOPE
- if (onesided)
+ if (!glidesector)
floorclimb = true;
else
{
@@ -7058,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);
@@ -7079,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;
@@ -7129,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);
@@ -7147,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)
@@ -7190,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);
@@ -7224,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)
@@ -7235,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");
@@ -7299,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);
@@ -7309,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
{
@@ -7329,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
diff --git a/src/r_bsp.c b/src/r_bsp.c
index 69aa7be29..44cb991a7 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;
diff --git a/src/r_data.c b/src/r_data.c
index cb5cf3591..7bad6bb89 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
//
@@ -1499,6 +1525,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 69a2882af..1e9e0eb5e 100644
--- a/src/r_data.h
+++ b/src/r_data.h
@@ -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 3669ec8f3..b8c21764e 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;
@@ -383,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;
diff --git a/src/r_main.c b/src/r_main.c
index e1fe0dce7..e50e80013 100644
--- a/src/r_main.c
+++ b/src/r_main.c
@@ -708,7 +708,7 @@ subsector_t *R_PointInSubsector(fixed_t x, fixed_t y)
}
//
-// R_IsPointInSubsector, same as above but returns 0 if not in subsector - this does not work in opengl because of polyvertex_t
+// R_IsPointInSubsector, same as above but returns 0 if not in subsector
//
subsector_t *R_IsPointInSubsector(fixed_t x, fixed_t y)
{
@@ -732,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;
diff --git a/src/r_plane.c b/src/r_plane.c
index 19007d88f..b7b9eaff3 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 ec1940716..16c8c12a4 100644
--- a/src/r_plane.h
+++ b/src/r_plane.h
@@ -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 cb78743b6..502ff3304 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)
@@ -1878,14 +1896,16 @@ 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_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 - viewz;
}
@@ -1894,10 +1914,10 @@ void R_StoreWallRange(INT32 start, INT32 stop)
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
@@ -2129,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
@@ -2209,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
@@ -2494,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)
@@ -3101,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_things.c b/src/r_things.c
index 22551a02d..331febabd 100644
--- a/src/r_things.c
+++ b/src/r_things.c
@@ -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;
@@ -1699,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;
}
@@ -1756,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;
@@ -1812,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/screen.c b/src/screen.c
index 376586c5d..2780edb60 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
diff --git a/src/sdl/macosx/Srb2mac.xcodeproj/project.pbxproj b/src/sdl/macosx/Srb2mac.xcodeproj/project.pbxproj
index c3f0d3b38..32ae88c02 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.17;
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.17;
GCC_ENABLE_FIX_AND_CONTINUE = NO;
GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
GCC_PREPROCESSOR_DEFINITIONS = (
diff --git a/src/sdl12/macosx/Srb2mac.xcodeproj/project.pbxproj b/src/sdl12/macosx/Srb2mac.xcodeproj/project.pbxproj
index 98599fb60..13e78f314 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.17;
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.17;
GCC_ENABLE_FIX_AND_CONTINUE = NO;
GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
GCC_PREPROCESSOR_DEFINITIONS = (
diff --git a/src/v_video.c b/src/v_video.c
index f6a966e67..1fb10fb5d 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
diff --git a/src/w_wad.c b/src/w_wad.c
index aeaad3ced..e4cb93050 100644
--- a/src/w_wad.c
+++ b/src/w_wad.c
@@ -1223,6 +1223,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/win32/win_dbg.c b/src/win32/win_dbg.c
index 23416af1b..fe6ebb04a 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 563466dc2..4ac05f94f 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;
diff --git a/src/win32/win_main.h b/src/win32/win_main.h
index ed55246ab..326a813dd 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;