mirror of
https://git.do.srb2.org/KartKrew/Kart-Public.git
synced 2024-11-10 07:12:03 +00:00
Merge remote-tracking branch 'origin/master' into SDL2_RelMouse
This commit is contained in:
commit
c25b2eb37f
154 changed files with 5873 additions and 7074 deletions
63
.circleci/config.yml
Normal file
63
.circleci/config.yml
Normal file
|
@ -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
|
||||
|
||||
|
||||
|
46
.travis.yml
46
.travis.yml
|
@ -98,7 +98,7 @@ matrix:
|
|||
- p7zip-full
|
||||
- gcc-6
|
||||
compiler: gcc-6
|
||||
env: WFLAGS="-Wno-error=tautological-compare"
|
||||
env: WFLAGS="-Wno-tautological-compare"
|
||||
#gcc-6 (Ubuntu 6.1.1-3ubuntu11~14.04.1) 6.1.1 20160511
|
||||
- os: linux
|
||||
compiler: clang
|
||||
|
@ -162,28 +162,28 @@ matrix:
|
|||
- clang-3.8
|
||||
compiler: clang-3.8
|
||||
#clang version 3.8.1-svn271127-1~exp1 (branches/release_38)
|
||||
- os: osx
|
||||
osx_image: beta-xcode6.1
|
||||
#Apple LLVM version 6.0 (clang-600.0.54) (based on LLVM 3.5svn)
|
||||
- os: osx
|
||||
osx_image: beta-xcode6.2
|
||||
compiler: gcc
|
||||
#Apple LLVM version 6.0 (clang-600.0.57) (based on LLVM 3.5svn)
|
||||
# - os: osx
|
||||
# osx_image: beta-xcode6.3
|
||||
# #I think xcode.6.3 VM is broken, it does not boot
|
||||
- os: osx
|
||||
osx_image: xcode6.4
|
||||
#Apple LLVM version 6.1.0 (clang-602.0.53) (based on LLVM 3.6.0svn)
|
||||
- os: osx
|
||||
osx_image: xcode7
|
||||
#Apple LLVM version 7.0.0 (clang-700.0.72)
|
||||
- os: osx
|
||||
osx_image: xcode7.1
|
||||
#Apple LLVM version 7.0.0 (clang-700.1.76)
|
||||
- os: osx
|
||||
osx_image: xcode7.2
|
||||
#Apple LLVM version 7.0.2 (clang-700.1.81)
|
||||
# osx_image: beta-xcode6.1
|
||||
# #Apple LLVM version 6.0 (clang-600.0.54) (based on LLVM 3.5svn)
|
||||
# - os: osx
|
||||
# osx_image: beta-xcode6.2
|
||||
# compiler: gcc
|
||||
# #Apple LLVM version 6.0 (clang-600.0.57) (based on LLVM 3.5svn)
|
||||
## - os: osx
|
||||
## osx_image: beta-xcode6.3
|
||||
## #I think xcode.6.3 VM is broken, it does not boot
|
||||
# - os: osx
|
||||
# osx_image: xcode6.4
|
||||
# #Apple LLVM version 6.1.0 (clang-602.0.53) (based on LLVM 3.6.0svn)
|
||||
# - os: osx
|
||||
# osx_image: xcode7
|
||||
# #Apple LLVM version 7.0.0 (clang-700.0.72)
|
||||
# - os: osx
|
||||
# osx_image: xcode7.1
|
||||
# #Apple LLVM version 7.0.0 (clang-700.1.76)
|
||||
# - os: osx
|
||||
# osx_image: xcode7.2
|
||||
# #Apple LLVM version 7.0.2 (clang-700.1.81)
|
||||
- os: osx
|
||||
osx_image: xcode7.3
|
||||
#Apple LLVM version 7.3.0 (clang-703.0.31)
|
||||
|
@ -213,7 +213,7 @@ before_script:
|
|||
- 7z x $HOME/srb2_cache/SRB2-v2115-assets-2.7z -oassets
|
||||
- mkdir build
|
||||
- cd build
|
||||
- export CFLAGS="-Wall -W $WFLAGS"
|
||||
- export CFLAGS="-Wall -W -Werror $WFLAGS"
|
||||
- export CCACHE_COMPRESS=true
|
||||
- cmake .. -DCMAKE_BUILD_TYPE=Release
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
cmake_minimum_required(VERSION 3.0)
|
||||
project(SRB2
|
||||
VERSION 2.1.14
|
||||
VERSION 2.1.19
|
||||
LANGUAGES C)
|
||||
|
||||
if(${PROJECT_SOURCE_DIR} MATCHES ${PROJECT_BINARY_DIR})
|
||||
|
|
23
README.md
Normal file
23
README.md
Normal file
|
@ -0,0 +1,23 @@
|
|||
# Sonic Robo Blast 2
|
||||
|
||||
[![Build status](https://ci.appveyor.com/api/projects/status/399d4hcw9yy7hg2y?svg=true)](https://ci.appveyor.com/project/STJr/srb2)
|
||||
[![Build status](https://travis-ci.org/STJr/SRB2.svg?branch=master)](https://travis-ci.org/STJr/SRB2)
|
||||
[![CircleCI](https://circleci.com/gh/STJr/SRB2/tree/master.svg?style=svg)](https://circleci.com/gh/STJr/SRB2/tree/master)
|
||||
|
||||
[Sonic Robo Blast 2](https://srb2.org/) is a 3D Sonic the Hedgehog fangame based on a modified version of [Doom Legacy](http://doomlegacy.sourceforge.net/).
|
||||
|
||||
## Dependencies
|
||||
- NASM (x86 builds only)
|
||||
- SDL2 (Linux/OS X only)
|
||||
- SDL2-Mixer (Linux/OS X only)
|
||||
- libupnp (Linux/OS X only)
|
||||
- libgme (Linux/OS X only)
|
||||
|
||||
Warning: 64-bit builds are not netgame compatible with 32-bit builds. Use at your own risk.
|
||||
|
||||
## Compiling
|
||||
|
||||
See [SRB2 Wiki/Source code compiling](http://wiki.srb2.org/wiki/Source_code_compiling)
|
||||
|
||||
## Disclaimer
|
||||
Sonic Team Junior is in no way affiliated with SEGA or Sonic Team. We do not claim ownership of any of SEGA's intellectual property used in SRB2.
|
37
appveyor.yml
37
appveyor.yml
|
@ -1,4 +1,4 @@
|
|||
version: 2.1.14.{branch}-{build}
|
||||
version: 2.1.19.{branch}-{build}
|
||||
os: MinGW
|
||||
|
||||
environment:
|
||||
|
@ -47,7 +47,7 @@ before_build:
|
|||
- upx -V
|
||||
- ccache -V
|
||||
- ccache -s
|
||||
- set SRB2_MFLAGS=-C src MINGW=1 WARNINGMODE=1 GCC53=1 CCACHE=1
|
||||
- set SRB2_MFLAGS=-C src MINGW=1 WARNINGMODE=1 GCC63=1 CCACHE=1 NOOBJDUMP=1
|
||||
|
||||
build_script:
|
||||
- cmd: mingw32-make.exe %SRB2_MFLAGS% %CONFIGURATION%=1 clean
|
||||
|
@ -58,26 +58,29 @@ after_build:
|
|||
- cmd: git rev-parse --short %APPVEYOR_REPO_COMMIT%>%TMP%/gitshort.txt
|
||||
- cmd: set /P GITSHORT=<%TMP%/gitshort.txt
|
||||
- set BUILD_ARCHIVE=%APPVEYOR_REPO_BRANCH%-%GITSHORT%-%CONFIGURATION%.7z
|
||||
- set BUILDSARCHIVE=%APPVEYOR_REPO_BRANCH%-%CONFIGURATION%.7z
|
||||
- cmd: 7z a %BUILD_ARCHIVE% bin\Mingw\Release -xr!.gitignore
|
||||
- appveyor PushArtifact %BUILD_ARCHIVE%
|
||||
- cmd: copy %BUILD_ARCHIVE% %BUILDSARCHIVE%
|
||||
- appveyor PushArtifact %BUILDSARCHIVE%
|
||||
|
||||
test: off
|
||||
|
||||
deploy:
|
||||
- provider: FTP
|
||||
protocol: ftps
|
||||
host:
|
||||
secure: NsLJEPIBvmwCOj8Tg8RoRQ==
|
||||
username:
|
||||
secure: ejxi5mvk7oLYu7QtbYojajEPigMy0mokaKhuEVuDZcA=
|
||||
password:
|
||||
secure: Hbn6Uy3lT0YZ88yFJ3aW4w==
|
||||
folder: appveyor
|
||||
application:
|
||||
active_mode: false
|
||||
on:
|
||||
branch: master
|
||||
appveyor_repo_tag: true
|
||||
#deploy:
|
||||
# - provider: FTP
|
||||
# protocol: ftps
|
||||
# host:
|
||||
# secure: NsLJEPIBvmwCOj8Tg8RoRQ==
|
||||
# username:
|
||||
# secure: ejxi5mvk7oLYu7QtbYojajEPigMy0mokaKhuEVuDZcA=
|
||||
# password:
|
||||
# secure: Hbn6Uy3lT0YZ88yFJ3aW4w==
|
||||
# folder: appveyor
|
||||
# application:
|
||||
# active_mode: false
|
||||
# on:
|
||||
# branch: master
|
||||
# appveyor_repo_tag: true
|
||||
|
||||
|
||||
on_finish:
|
||||
|
|
6
bin/Mingw/Debug/.gitignore
vendored
6
bin/Mingw/Debug/.gitignore
vendored
|
@ -1,3 +1,3 @@
|
|||
/srb2sdl.exe
|
||||
/srb2win.exe
|
||||
/r_opengl.dll
|
||||
*.exe
|
||||
*.mo
|
||||
r_opengl.dll
|
||||
|
|
6
bin/Mingw/Release/.gitignore
vendored
6
bin/Mingw/Release/.gitignore
vendored
|
@ -1,3 +1,3 @@
|
|||
/srb2sdl.exe
|
||||
/srb2win.exe
|
||||
/r_opengl.dll
|
||||
*.exe
|
||||
*.mo
|
||||
r_opengl.dll
|
||||
|
|
3
debian/docs
vendored
3
debian/docs
vendored
|
@ -1,2 +1 @@
|
|||
readme.txt
|
||||
readme.txt
|
||||
README.md
|
||||
|
|
8
objs/.gitignore
vendored
Normal file
8
objs/.gitignore
vendored
Normal file
|
@ -0,0 +1,8 @@
|
|||
#All folders
|
||||
SRB2.res
|
||||
depend.dep
|
||||
depend.ped
|
||||
*.o
|
||||
#VC9 folder only
|
||||
/VC9/Win32
|
||||
/VC9/x64
|
3
objs/DC/SDL/Debug/.gitignore
vendored
3
objs/DC/SDL/Debug/.gitignore
vendored
|
@ -1 +1,2 @@
|
|||
/depend.dep
|
||||
# DON'T REMOVE
|
||||
# This keeps the folder from disappearing
|
||||
|
|
3
objs/DC/SDL/Release/.gitignore
vendored
3
objs/DC/SDL/Release/.gitignore
vendored
|
@ -1 +1,2 @@
|
|||
/depend.dep
|
||||
# DON'T REMOVE
|
||||
# This keeps the folder from disappearing
|
||||
|
|
4
objs/Linux/SDL/Debug/.gitignore
vendored
4
objs/Linux/SDL/Debug/.gitignore
vendored
|
@ -1,2 +1,2 @@
|
|||
/depend.dep
|
||||
/*.o
|
||||
# DON'T REMOVE
|
||||
# This keeps the folder from disappearing
|
||||
|
|
4
objs/Linux/SDL/Release/.gitignore
vendored
4
objs/Linux/SDL/Release/.gitignore
vendored
|
@ -1,2 +1,2 @@
|
|||
/depend.dep
|
||||
/*.o
|
||||
# DON'T REMOVE
|
||||
# This keeps the folder from disappearing
|
||||
|
|
4
objs/Linux64/SDL/Debug/.gitignore
vendored
4
objs/Linux64/SDL/Debug/.gitignore
vendored
|
@ -1,2 +1,2 @@
|
|||
/depend.dep
|
||||
/*.o
|
||||
# DON'T REMOVE
|
||||
# This keeps the folder from disappearing
|
||||
|
|
4
objs/Linux64/SDL/Release/.gitignore
vendored
4
objs/Linux64/SDL/Release/.gitignore
vendored
|
@ -1,2 +1,2 @@
|
|||
/depend.dep
|
||||
/*.o
|
||||
# DON'T REMOVE
|
||||
# This keeps the folder from disappearing
|
||||
|
|
5
objs/Mingw/Debug/.gitignore
vendored
5
objs/Mingw/Debug/.gitignore
vendored
|
@ -1,3 +1,2 @@
|
|||
/SRB2.res
|
||||
/depend.dep
|
||||
/*.o
|
||||
# DON'T REMOVE
|
||||
# This keeps the folder from disappearing
|
||||
|
|
5
objs/Mingw/Release/.gitignore
vendored
5
objs/Mingw/Release/.gitignore
vendored
|
@ -1,3 +1,2 @@
|
|||
/SRB2.res
|
||||
/depend.dep
|
||||
/*.o
|
||||
# DON'T REMOVE
|
||||
# This keeps the folder from disappearing
|
||||
|
|
5
objs/Mingw/SDL/Debug/.gitignore
vendored
5
objs/Mingw/SDL/Debug/.gitignore
vendored
|
@ -1,3 +1,2 @@
|
|||
/SRB2.res
|
||||
/depend.dep
|
||||
/*.o
|
||||
# DON'T REMOVE
|
||||
# This keeps the folder from disappearing
|
||||
|
|
5
objs/Mingw/SDL/Release/.gitignore
vendored
5
objs/Mingw/SDL/Release/.gitignore
vendored
|
@ -1,3 +1,2 @@
|
|||
/SRB2.res
|
||||
/depend.dep
|
||||
/*.o
|
||||
# DON'T REMOVE
|
||||
# This keeps the folder from disappearing
|
||||
|
|
5
objs/Mingw64/Debug/.gitignore
vendored
5
objs/Mingw64/Debug/.gitignore
vendored
|
@ -1,3 +1,2 @@
|
|||
/SRB2.res
|
||||
/depend.dep
|
||||
/*.o
|
||||
# DON'T REMOVE
|
||||
# This keeps the folder from disappearing
|
||||
|
|
5
objs/Mingw64/Release/.gitignore
vendored
5
objs/Mingw64/Release/.gitignore
vendored
|
@ -1,3 +1,2 @@
|
|||
/SRB2.res
|
||||
/depend.dep
|
||||
/*.o
|
||||
# DON'T REMOVE
|
||||
# This keeps the folder from disappearing
|
||||
|
|
5
objs/Mingw64/SDL/Debug/.gitignore
vendored
5
objs/Mingw64/SDL/Debug/.gitignore
vendored
|
@ -1,3 +1,2 @@
|
|||
/SRB2.res
|
||||
/depend.dep
|
||||
/*.o
|
||||
# DON'T REMOVE
|
||||
# This keeps the folder from disappearing
|
||||
|
|
5
objs/Mingw64/SDL/Release/.gitignore
vendored
5
objs/Mingw64/SDL/Release/.gitignore
vendored
|
@ -1,3 +1,2 @@
|
|||
/SRB2.res
|
||||
/depend.dep
|
||||
/*.o
|
||||
# DON'T REMOVE
|
||||
# This keeps the folder from disappearing
|
||||
|
|
4
objs/PS3/SDL/Debug/.gitignore
vendored
4
objs/PS3/SDL/Debug/.gitignore
vendored
|
@ -1,2 +1,2 @@
|
|||
/depend.dep
|
||||
/*.o
|
||||
# DON'T REMOVE
|
||||
# This keeps the folder from disappearing
|
||||
|
|
4
objs/PS3/SDL/Release/.gitignore
vendored
4
objs/PS3/SDL/Release/.gitignore
vendored
|
@ -1,2 +1,2 @@
|
|||
/depend.dep
|
||||
/*.o
|
||||
# DON'T REMOVE
|
||||
# This keeps the folder from disappearing
|
||||
|
|
3
objs/PSP/SDL/Release/.gitignore
vendored
3
objs/PSP/SDL/Release/.gitignore
vendored
|
@ -1 +1,2 @@
|
|||
/depend.dep
|
||||
# DON'T REMOVE
|
||||
# This keeps the folder from disappearing
|
||||
|
|
3
objs/SDL/Release/.gitignore
vendored
3
objs/SDL/Release/.gitignore
vendored
|
@ -1 +1,2 @@
|
|||
/depend.ped
|
||||
# DON'T REMOVE
|
||||
# This keeps the folder from disappearing
|
||||
|
|
2
objs/VC/.gitignore
vendored
2
objs/VC/.gitignore
vendored
|
@ -0,0 +1,2 @@
|
|||
# DON'T REMOVE
|
||||
# This keeps the folder from disappearing
|
4
objs/VC9/.gitignore
vendored
4
objs/VC9/.gitignore
vendored
|
@ -1,2 +1,2 @@
|
|||
/Win32
|
||||
/x64
|
||||
# DON'T REMOVE
|
||||
# This keeps the folder from disappearing
|
||||
|
|
4
objs/Wii/SDL/Debug/.gitignore
vendored
4
objs/Wii/SDL/Debug/.gitignore
vendored
|
@ -1,2 +1,2 @@
|
|||
/depend.dep
|
||||
/*.o
|
||||
# DON'T REMOVE
|
||||
# This keeps the folder from disappearing
|
||||
|
|
4
objs/Wii/SDL/Release/.gitignore
vendored
4
objs/Wii/SDL/Release/.gitignore
vendored
|
@ -1,2 +1,2 @@
|
|||
/depend.dep
|
||||
/*.o
|
||||
# DON'T REMOVE
|
||||
# This keeps the folder from disappearing
|
||||
|
|
3
objs/WinCE/SDL/Release/.gitignore
vendored
3
objs/WinCE/SDL/Release/.gitignore
vendored
|
@ -1 +1,2 @@
|
|||
/depend.dep
|
||||
# DON'T REMOVE
|
||||
# This keeps the folder from disappearing
|
||||
|
|
3
objs/djgppdos/Debug/.gitignore
vendored
3
objs/djgppdos/Debug/.gitignore
vendored
|
@ -1 +1,2 @@
|
|||
/depend.dep
|
||||
# DON'T REMOVE
|
||||
# This keeps the folder from disappearing
|
||||
|
|
3
objs/djgppdos/Release/.gitignore
vendored
3
objs/djgppdos/Release/.gitignore
vendored
|
@ -1 +1,2 @@
|
|||
/depend.dep
|
||||
# DON'T REMOVE
|
||||
# This keeps the folder from disappearing
|
||||
|
|
4
objs/nds/Debug/.gitignore
vendored
4
objs/nds/Debug/.gitignore
vendored
|
@ -1,2 +1,2 @@
|
|||
/depend.dep
|
||||
/*.o
|
||||
# DON'T REMOVE
|
||||
# This keeps the folder from disappearing
|
||||
|
|
4
objs/nds/Release/.gitignore
vendored
4
objs/nds/Release/.gitignore
vendored
|
@ -1,2 +1,2 @@
|
|||
/depend.dep
|
||||
/*.o
|
||||
# DON'T REMOVE
|
||||
# This keeps the folder from disappearing
|
||||
|
|
155
readme.txt
155
readme.txt
|
@ -1,155 +0,0 @@
|
|||
Here it is! SRB2 v2.1.14 source code!
|
||||
(why do we keep the version number up to date
|
||||
when everything else in this file is hilariously old?
|
||||
- Inuyasha)
|
||||
|
||||
|
||||
Win32 with Visual C (6SP6+Processor Pack OR 7)
|
||||
~~~
|
||||
|
||||
2 VC++ 6.0 project files are included:
|
||||
|
||||
Win32/DirectX/FMOD
|
||||
src\win32\wLegacy.dsw
|
||||
You'll need FMOD to compile this version (www.fmod.org)
|
||||
or
|
||||
Win32/SDL/SDL_mixer
|
||||
src\sdl\Win32SDL.dsp
|
||||
You'll need SDL and SDL_mixer for this version (www.libsdl.org)
|
||||
|
||||
Both needs NASM (http://sourceforge.net/projects/nasm)
|
||||
For PNG screenshot, libPNG, and Zlib (from http://gnuwin32.sourceforge.net/)
|
||||
|
||||
No warranty, support, etc. of any kind is offered,
|
||||
just plain old as is.
|
||||
Some bits of code are still really scary.
|
||||
Go nuts!
|
||||
|
||||
|
||||
Win32 with Dev-C++ (http://bloodshed.net/ free!)
|
||||
~~~
|
||||
2 Dev-C++ project files are included:
|
||||
|
||||
Win32/DirectX/FMOD
|
||||
src\win32\SRB2.dev
|
||||
or
|
||||
Win32/SDL/SDL_mixer
|
||||
src\sdl\Win32SDL.dev
|
||||
You'll need SDL and SDL_mixer for this version (www.libsdl.org)
|
||||
libPNG and Zlib (from http://gnuwin32.sourceforge.net/)
|
||||
Note there are precompiled libpng.a and libz.a for Mingw
|
||||
|
||||
you will need NASM for both SDL/SDL_mixer and DirectX/FMOD
|
||||
and you need DirectX 6 (or up) Dev-Paks to compile DirectX version
|
||||
|
||||
GNU/Linux
|
||||
~~~
|
||||
|
||||
Dependencies:
|
||||
SDL 1.2.7 or better (from libsdl.org)
|
||||
SDL_Mixer 1.2.2(.7 for file-less music playback) (from libsdl.org)
|
||||
Nasm (use NOASM=1 if you don't have it or have an non-i386 system, I think)
|
||||
libPNG 1.2.7
|
||||
Zlib 1.2.3
|
||||
The Xiph.org libogg and libvorbis libraries
|
||||
The OpenGL headers (from Mesa, usually shipped with your X.org or XFree
|
||||
installation, so you needn't worry, most likely)
|
||||
GCC 3.x toolchain and binutils
|
||||
GNU Make
|
||||
|
||||
Build instructions:
|
||||
|
||||
make -C src LINUX=1
|
||||
|
||||
Build instructions (64 bit):
|
||||
|
||||
make -C src LINUX64=1
|
||||
|
||||
Build instructions to build for Wii Linux/SRB2Wii on a PowerPC system,
|
||||
follow cross-compiling instructions for cross-compiling on a x86 system:
|
||||
|
||||
make -C src LINUX=1 WIILINUX=1
|
||||
|
||||
Build instructions to build for Pandora (Linux) on a ARM system,
|
||||
follow cross-compiling instructions for cross-compiling on a x86 system:
|
||||
|
||||
make -C src PANDORA=1
|
||||
|
||||
Solaris
|
||||
~~~
|
||||
|
||||
Dependencies:
|
||||
SDL 1.2.5 or better (from libsdl.org)
|
||||
SDL_Mixer 1.2.2(.7 for file-less music playback) (from libsdl.org)
|
||||
libPNG 1.2.7
|
||||
Zlib 1.2.3
|
||||
The Xiph.org libogg and libvorbis libraries
|
||||
The OpenGL headers (from Mesa, usually shipped with your X.org or XFree
|
||||
installation, so you needn't worry, most likely)
|
||||
GCC 3.x toolchain and binutils
|
||||
GNU Make
|
||||
|
||||
You can get all these programs/libraries from the Companion CD (except SDL_mixer and OpenGL)
|
||||
|
||||
Build instructions:
|
||||
|
||||
gmake -C src SOLARIS=1
|
||||
|
||||
FreeBSD
|
||||
~~~
|
||||
|
||||
Dependencies:
|
||||
SDL 1.2.7 or better (from libsdl.org)
|
||||
SDL_Mixer 1.2.2(.7 for file-less music playback) (from libsdl.org)
|
||||
Nasm (use NOASM=1 if you don't have it or have an non-i386 system, I think)
|
||||
libPNG 1.2.7
|
||||
Zlib 1.2.3
|
||||
The Xiph.org libogg and libvorbis libraries
|
||||
The OpenGL headers (from Mesa, usually shipped with your X.org or XFree
|
||||
installation, so you needn't worry, most likely)
|
||||
GCC 3.x toolchain and binutils
|
||||
GNU Make
|
||||
|
||||
Build instructions:
|
||||
|
||||
gmake -C src FREEBSD=1
|
||||
|
||||
DJGPP/DOS
|
||||
~~~
|
||||
|
||||
Dependencies:
|
||||
Allegro 3.12 game programming library, (from
|
||||
http://alleg.sourceforge.net/index.html)
|
||||
Nasm (use NOASM=1 if you don't have it)
|
||||
libsocket (from http://homepages.nildram.co.uk/~phekda/richdawe/lsck/) or
|
||||
Watt-32 (from http://www.bgnett.no/~giva/)
|
||||
GCC 3.x toolchain and binutils
|
||||
GNU Make
|
||||
|
||||
Build instructions:
|
||||
|
||||
make -C src # to link with Watt-32, add WATTCP=1
|
||||
# for remote debugging over the COM port, add RDB=1
|
||||
|
||||
Notes:
|
||||
use tools\djgpp\all313.diff to update Allegro to a "more usable" version ;)
|
||||
Example: E:\djgpp\allegro>patch -p# < D:\SRB2Code\1.1\srb2\tools\djgpp\all313.diff
|
||||
|
||||
Windows CE
|
||||
~~~
|
||||
|
||||
Dependencies:
|
||||
SDL 1.27
|
||||
|
||||
Build instructions:
|
||||
|
||||
use src\SDL\WinCE\SRB2CE.vcw
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
binaries will turn in up in bin/
|
||||
|
||||
note: read the src/makefile for more options
|
||||
|
||||
- Sonic Team Junior
|
||||
http://www.srb2.org
|
|
@ -22,6 +22,7 @@ set(SRB2_CORE_SOURCES
|
|||
i_tcp.c
|
||||
info.c
|
||||
lzf.c
|
||||
m_aatree.c
|
||||
m_anigif.c
|
||||
m_argv.c
|
||||
m_bbox.c
|
||||
|
@ -83,6 +84,7 @@ set(SRB2_CORE_HEADERS
|
|||
info.h
|
||||
keys.h
|
||||
lzf.h
|
||||
m_aatree.h
|
||||
m_anigif.h
|
||||
m_argv.h
|
||||
m_bbox.h
|
||||
|
@ -388,18 +390,25 @@ if(${SRB2_CONFIG_HWRENDER} AND ${SRB2_CONFIG_STATIC_OPENGL})
|
|||
endif()
|
||||
|
||||
if(${SRB2_CONFIG_USEASM})
|
||||
#SRB2_ASM_FLAGS can be used to pass flags to either nasm or yasm.
|
||||
if(${CMAKE_SYSTEM} MATCHES "Linux")
|
||||
set(SRB2_ASM_FLAGS "-DLINUX ${SRB2_ASM_FLAGS}")
|
||||
endif()
|
||||
|
||||
if(${SRB2_CONFIG_YASM})
|
||||
set(CMAKE_ASM_YASM_SOURCE_FILE_EXTENSIONS ${CMAKE_ASM_YASM_SOURCE_FILE_EXTENSIONS} nas)
|
||||
set(CMAKE_ASM_YASM_FLAGS "${SRB2_ASM_FLAGS}" CACHE STRING "Flags used by the assembler during all build types.")
|
||||
enable_language(ASM_YASM)
|
||||
else()
|
||||
set(CMAKE_ASM_NASM_SOURCE_FILE_EXTENSIONS ${CMAKE_ASM_NASM_SOURCE_FILE_EXTENSIONS} nas)
|
||||
set(CMAKE_ASM_NASM_FLAGS "${SRB2_ASM_FLAGS}" CACHE STRING "Flags used by the assembler during all build types.")
|
||||
enable_language(ASM_NASM)
|
||||
endif()
|
||||
set(SRB2_USEASM ON)
|
||||
add_definitions(-DUSEASM)
|
||||
else()
|
||||
set(SRB2_USEASM OFF)
|
||||
add_definitions(-DNOASM -DNONX86)
|
||||
add_definitions(-DNONX86 -DNORUSEASM)
|
||||
endif()
|
||||
|
||||
# Targets
|
||||
|
|
36
src/Makefile
36
src/Makefile
|
@ -179,6 +179,9 @@ endif
|
|||
|
||||
ifdef LINUX
|
||||
UNIXCOMMON=1
|
||||
ifndef NOGME
|
||||
HAVE_LIBGME=1
|
||||
endif
|
||||
endif
|
||||
|
||||
ifdef SOLARIS
|
||||
|
@ -189,6 +192,10 @@ ifdef FREEBSD
|
|||
UNIXCOMMON=1
|
||||
endif
|
||||
|
||||
ifdef MACOSX
|
||||
UNIXCOMMON=1
|
||||
endif
|
||||
|
||||
ifdef NDS
|
||||
NOPNG=1
|
||||
NONET=1
|
||||
|
@ -311,6 +318,13 @@ LIBS+=$(PNG_LDFLAGS)
|
|||
CFLAGS+=$(PNG_CFLAGS)
|
||||
endif
|
||||
|
||||
ZLIB_PKGCONFIG?=zlib
|
||||
ZLIB_CFLAGS?=$(shell $(PKG_CONFIG) $(ZLIB_PKGCONFIG) --cflags)
|
||||
ZLIB_LDFLAGS?=$(shell $(PKG_CONFIG) $(ZLIB_PKGCONFIG) --libs)
|
||||
|
||||
LIBS+=$(ZLIB_LDFLAGS)
|
||||
CFLAGS+=$(ZLIB_CFLAGS)
|
||||
|
||||
ifdef HAVE_LIBGME
|
||||
OPTS+=-DHAVE_LIBGME
|
||||
|
||||
|
@ -362,6 +376,14 @@ endif
|
|||
|
||||
OPTS:=-fno-exceptions $(OPTS)
|
||||
|
||||
ifdef MOBJCONSISTANCY
|
||||
OPTS+=-DMOBJCONSISTANCY
|
||||
endif
|
||||
|
||||
ifdef PACKETDROP
|
||||
OPTS+=-DPACKETDROP
|
||||
endif
|
||||
|
||||
ifdef DEBUGMODE
|
||||
|
||||
# build with debugging information
|
||||
|
@ -371,7 +393,7 @@ ifdef GCC48
|
|||
else
|
||||
CFLAGS+=-O0
|
||||
endif
|
||||
CFLAGS+= -Wall -DPARANOIA -DRANGECHECK
|
||||
CFLAGS+= -Wall -DPARANOIA -DRANGECHECK -DPACKETDROP -DMOBJCONSISTANCY
|
||||
else
|
||||
|
||||
|
||||
|
@ -429,6 +451,7 @@ OBJS:=$(i_main_o) \
|
|||
$(OBJDIR)/hu_stuff.o \
|
||||
$(OBJDIR)/y_inter.o \
|
||||
$(OBJDIR)/st_stuff.o \
|
||||
$(OBJDIR)/m_aatree.o \
|
||||
$(OBJDIR)/m_anigif.o \
|
||||
$(OBJDIR)/m_argv.o \
|
||||
$(OBJDIR)/m_bbox.o \
|
||||
|
@ -488,13 +511,11 @@ OBJS:=$(i_main_o) \
|
|||
# For reference, this is the command I use to build a srb2.pot file from the source code.
|
||||
# (The listed source files are the ones containing translated strings).
|
||||
# FILES=""; for file in `find ./ | grep "\.c" | grep -v svn`; do [ "`grep "M_GetText(" $file`" ] && FILES="$FILES $file"; done; xgettext -d srb2 -o locale/srb2.pot -kM_GetText -F --no-wrap $FILES
|
||||
ifndef NOGETTEXT
|
||||
ifdef GETTEXT
|
||||
POS:=$(BIN)/en.mo
|
||||
|
||||
OPTS+=-DGETTEXT
|
||||
endif
|
||||
endif
|
||||
|
||||
ifdef DJGPPDOS
|
||||
all: pre-build $(BIN)/$(EXENAME)
|
||||
|
@ -593,11 +614,15 @@ ifndef WINDOWSHELL
|
|||
-$(GZIP) $(GZIP_OPT2) $(BIN)/$(DBGNAME).txt
|
||||
endif
|
||||
endif
|
||||
|
||||
# mac os x lsdlsrb2 does not like objcopy
|
||||
ifndef MACOSX
|
||||
ifndef PSP
|
||||
$(OBJCOPY) $(BIN)/$(EXENAME) $(BIN)/$(DBGNAME)
|
||||
$(OBJCOPY) --strip-debug $(BIN)/$(EXENAME)
|
||||
-$(OBJCOPY) --add-gnu-debuglink=$(BIN)/$(DBGNAME) $(BIN)/$(EXENAME)
|
||||
endif
|
||||
endif
|
||||
ifndef NOUPX
|
||||
-$(UPX) $(UPX_OPTS) $(BIN)/$(EXENAME)
|
||||
endif
|
||||
|
@ -745,6 +770,11 @@ $(OBJDIR)/%.o: %.c
|
|||
$(OBJDIR)/%.o: $(INTERFACE)/%.c
|
||||
$(CC) $(CFLAGS) $(WFLAGS) -c $< -o $@
|
||||
|
||||
ifdef MACOSX
|
||||
$(OBJDIR)/%.o: sdl/macosx/%.c
|
||||
$(CC) $(CFLAGS) $(WFLAGS) -c $< -o $@
|
||||
endif
|
||||
|
||||
$(OBJDIR)/%.o: hardware/%.c
|
||||
$(CC) $(CFLAGS) $(WFLAGS) -c $< -o $@
|
||||
|
||||
|
|
|
@ -7,6 +7,23 @@
|
|||
# and other things
|
||||
#
|
||||
|
||||
|
||||
ifdef GCC63
|
||||
GCC62=1
|
||||
endif
|
||||
|
||||
ifdef GCC62
|
||||
GCC61=1
|
||||
endif
|
||||
|
||||
ifdef GCC61
|
||||
GCC54=1
|
||||
endif
|
||||
|
||||
ifdef GCC54
|
||||
GCC53=1
|
||||
endif
|
||||
|
||||
ifdef GCC53
|
||||
GCC52=1
|
||||
endif
|
||||
|
@ -164,19 +181,29 @@ ifdef GCC45
|
|||
WFLAGS+=-Wunsuffixed-float-constants
|
||||
endif
|
||||
endif
|
||||
|
||||
ifdef NOLDWARNING
|
||||
LDFLAGS+=-Wl,--as-needed
|
||||
endif
|
||||
|
||||
ifdef ERRORMODE
|
||||
WFLAGS+=-Werror
|
||||
endif
|
||||
|
||||
WFLAGS+=$(OLDWFLAGS)
|
||||
|
||||
ifdef GCC43
|
||||
#WFLAGS+=-Wno-error=clobbered
|
||||
endif
|
||||
ifdef GCC46
|
||||
WFLAGS+=-Wno-error=suggest-attribute=noreturn
|
||||
endif
|
||||
WFLAGS+=$(OLDWFLAGS)
|
||||
ifdef GCC54
|
||||
WFLAGS+=-Wno-logical-op -Wno-error=logical-op
|
||||
endif
|
||||
ifdef GCC61
|
||||
WFLAGS+=-Wno-tautological-compare -Wno-error=tautological-compare
|
||||
endif
|
||||
|
||||
|
||||
#indicate platform and what interface use with
|
||||
|
@ -256,9 +283,6 @@ else
|
|||
ifdef LINUX
|
||||
NASMFORMAT=elf -DLINUX
|
||||
SDL=1
|
||||
ifndef NOGETTEXT
|
||||
GETTEXT=1
|
||||
endif
|
||||
ifdef LINUX64
|
||||
OBJDIR:=$(OBJDIR)/Linux64
|
||||
BIN:=$(BIN)/Linux64
|
||||
|
@ -294,9 +318,6 @@ else
|
|||
ifdef MINGW64
|
||||
INTERFACE=win32
|
||||
#NASMFORMAT=win64
|
||||
ifndef NOGETTEXT
|
||||
#GETTEXT=1
|
||||
endif
|
||||
OBJDIR:=$(OBJDIR)/Mingw64
|
||||
BIN:=$(BIN)/Mingw64
|
||||
else
|
||||
|
@ -327,9 +348,6 @@ else
|
|||
ifdef MINGW
|
||||
INTERFACE=win32
|
||||
NASMFORMAT=win32
|
||||
ifndef NOGETTEXT
|
||||
GETTEXT=1
|
||||
endif
|
||||
OBJDIR:=$(OBJDIR)/Mingw
|
||||
BIN:=$(BIN)/Mingw
|
||||
else
|
||||
|
@ -406,6 +424,15 @@ else
|
|||
WINDRES=windres
|
||||
endif
|
||||
|
||||
# because Apple screws with us on this
|
||||
# need to get bintools from homebrew
|
||||
ifdef MACOSX
|
||||
CC=clang
|
||||
CXX=clang
|
||||
OBJCOPY=gobjcopy
|
||||
OBJDUMP=gobjdump
|
||||
endif
|
||||
|
||||
OBJDUMP_OPTS?=--wide --source --line-numbers
|
||||
LD=$(CC)
|
||||
|
||||
|
|
|
@ -258,6 +258,18 @@ INT32 I_PutEnv(char *variable)
|
|||
return -1;
|
||||
}
|
||||
|
||||
INT32 I_ClipboardCopy(const char *data, size_t size)
|
||||
{
|
||||
(void)data;
|
||||
(void)size;
|
||||
return -1;
|
||||
}
|
||||
|
||||
char *I_ClipboardPaste(void)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void I_RegisterSysCommands(void) {}
|
||||
|
||||
#include "../sdl/dosstr.c"
|
||||
|
|
|
@ -732,7 +732,8 @@ void luaV_execute (lua_State *L, int nexeccalls) {
|
|||
luaG_runerror(L, LUA_QL("for") " limit must be a number");
|
||||
else if (!tonumber(pstep, ra+2))
|
||||
luaG_runerror(L, LUA_QL("for") " step must be a number");
|
||||
setnvalue(ra, luai_numsub(nvalue(ra), nvalue(pstep)));
|
||||
if (ra && pstep)
|
||||
setnvalue(ra, luai_numsub(nvalue(ra), nvalue(pstep)));
|
||||
dojump(L, pc, GETARG_sBx(i));
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -966,9 +966,11 @@ void CV_RegisterVar(consvar_t *variable)
|
|||
// check net variables
|
||||
if (variable->flags & CV_NETVAR)
|
||||
{
|
||||
const consvar_t *netvar;
|
||||
variable->netid = CV_ComputeNetid(variable->name);
|
||||
if (CV_FindNetVar(variable->netid))
|
||||
I_Error("Variables %s and %s have same netid\n", variable->name, CV_FindNetVar(variable->netid)->name);
|
||||
netvar = CV_FindNetVar(variable->netid);
|
||||
if (netvar)
|
||||
I_Error("Variables %s and %s have same netid\n", variable->name, netvar->name);
|
||||
}
|
||||
|
||||
// link the variable in
|
||||
|
|
581
src/console.c
581
src/console.c
|
@ -84,19 +84,23 @@ UINT32 con_scalefactor; // text size scale factor
|
|||
|
||||
// hold 32 last lines of input for history
|
||||
#define CON_MAXPROMPTCHARS 256
|
||||
#define CON_PROMPTCHAR '>'
|
||||
#define CON_PROMPTCHAR '$'
|
||||
|
||||
static char inputlines[32][CON_MAXPROMPTCHARS]; // hold last 32 prompt lines
|
||||
|
||||
static INT32 inputline; // current input line number
|
||||
static INT32 inputhist; // line number of history input line to restore
|
||||
static size_t input_cx; // position in current input line
|
||||
static size_t input_cur; // position of cursor in line
|
||||
static size_t input_sel; // position of selection marker (I.E.: anything between this and input_cur is "selected")
|
||||
static size_t input_len; // length of current line, used to bound cursor and such
|
||||
// notice: input does NOT include the "$" at the start of the line. - 11/3/16
|
||||
|
||||
// protos.
|
||||
static void CON_InputInit(void);
|
||||
static void CON_RecalcSize(void);
|
||||
|
||||
static void CONS_hudlines_Change(void);
|
||||
static void CONS_backcolor_Change(void);
|
||||
static void CON_DrawBackpic(patch_t *pic, INT32 startx, INT32 destwidth);
|
||||
//static void CON_DrawBackpic2(pic_t *pic, INT32 startx, INT32 destwidth);
|
||||
|
||||
|
@ -129,10 +133,11 @@ static CV_PossibleValue_t backpic_cons_t[] = {{0, "translucent"}, {1, "picture"}
|
|||
// whether to use console background picture, or translucent mode
|
||||
static consvar_t cons_backpic = {"con_backpic", "translucent", CV_SAVE, backpic_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
|
||||
|
||||
static CV_PossibleValue_t backcolor_cons_t[] = {{0, "White"}, {1, "Orange"},
|
||||
{2, "Blue"}, {3, "Green"}, {4, "Gray"},
|
||||
{5, "Red"}, {0, NULL}};
|
||||
consvar_t cons_backcolor = {"con_backcolor", "3", CV_SAVE, backcolor_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
|
||||
static CV_PossibleValue_t backcolor_cons_t[] = {{0, "White"}, {1, "Gray"}, {2, "Brown"},
|
||||
{3, "Red"}, {4, "Orange"}, {5, "Yellow"},
|
||||
{6, "Green"}, {7, "Blue"}, {8, "Cyan"},
|
||||
{0, NULL}};
|
||||
consvar_t cons_backcolor = {"con_backcolor", "Green", CV_CALL|CV_SAVE, backcolor_cons_t, CONS_backcolor_Change, 0, NULL, NULL, 0, 0, NULL};
|
||||
|
||||
static void CON_Print(char *msg);
|
||||
|
||||
|
@ -219,8 +224,9 @@ static void CONS_Bind_f(void)
|
|||
// CONSOLE SETUP
|
||||
//======================================================================
|
||||
|
||||
// Prepare a colormap for GREEN ONLY translucency over background
|
||||
//
|
||||
// Font colormap colors
|
||||
// TODO: This could probably be improved somehow...
|
||||
// These colormaps are 99% identical, with just a few changed bytes
|
||||
UINT8 *yellowmap;
|
||||
UINT8 *purplemap;
|
||||
UINT8 *lgreenmap;
|
||||
|
@ -229,44 +235,49 @@ UINT8 *graymap;
|
|||
UINT8 *redmap;
|
||||
UINT8 *orangemap;
|
||||
|
||||
// Console BG colors
|
||||
UINT8 *cwhitemap;
|
||||
UINT8 *corangemap;
|
||||
UINT8 *cbluemap;
|
||||
UINT8 *cgreenmap;
|
||||
UINT8 *cgraymap;
|
||||
UINT8 *credmap;
|
||||
// Console BG color
|
||||
UINT8 *consolebgmap = NULL;
|
||||
|
||||
void CON_ReSetupBackColormap(UINT16 num)
|
||||
void CON_SetupBackColormap(void)
|
||||
{
|
||||
UINT16 i, j;
|
||||
UINT8 k;
|
||||
UINT8 *pal = W_CacheLumpName(R_GetPalname(num), PU_CACHE);
|
||||
UINT16 i, palsum;
|
||||
UINT8 j, palindex;
|
||||
UINT8 *pal = W_CacheLumpName(GetPalette(), PU_CACHE);
|
||||
|
||||
// setup the green translucent background colormaps
|
||||
for (i = 0, k = 0; i < 768; i += 3, k++)
|
||||
if (!consolebgmap)
|
||||
consolebgmap = (UINT8 *)Z_Malloc(256, PU_STATIC, NULL);
|
||||
|
||||
switch (cons_backcolor.value)
|
||||
{
|
||||
j = pal[i] + pal[i+1] + pal[i+2];
|
||||
cwhitemap[k] = (UINT8)(15 - (j>>6));
|
||||
corangemap[k] = (UINT8)(95 - (j>>6));
|
||||
cbluemap[k] = (UINT8)(239 - (j>>6));
|
||||
cgreenmap[k] = (UINT8)(175 - (j>>6));
|
||||
cgraymap[k] = (UINT8)(31 - (j>>6));
|
||||
credmap[k] = (UINT8)(143 - (j>>6));
|
||||
case 0: palindex = 15; break; // White
|
||||
case 1: palindex = 31; break; // Gray
|
||||
case 2: palindex = 63; break; // Brown
|
||||
case 3: palindex = 143; break; // Red
|
||||
case 4: palindex = 95; break; // Orange
|
||||
case 5: palindex = 111; break; // Yellow
|
||||
case 6: palindex = 175; break; // Green
|
||||
case 7: palindex = 239; break; // Blue
|
||||
case 8: palindex = 219; break; // Cyan
|
||||
// Default green
|
||||
default: palindex = 175; break;
|
||||
}
|
||||
|
||||
// setup background colormap
|
||||
for (i = 0, j = 0; i < 768; i += 3, j++)
|
||||
{
|
||||
palsum = (pal[i] + pal[i+1] + pal[i+2]) >> 6;
|
||||
consolebgmap[j] = (UINT8)(palindex - palsum);
|
||||
}
|
||||
}
|
||||
|
||||
static void CON_SetupBackColormap(void)
|
||||
static void CONS_backcolor_Change(void)
|
||||
{
|
||||
INT32 i, j, k;
|
||||
UINT8 *pal;
|
||||
CON_SetupBackColormap();
|
||||
}
|
||||
|
||||
cwhitemap = (UINT8 *)Z_Malloc(256, PU_STATIC, NULL);
|
||||
corangemap = (UINT8 *)Z_Malloc(256, PU_STATIC, NULL);
|
||||
cbluemap = (UINT8 *)Z_Malloc(256, PU_STATIC, NULL);
|
||||
cgreenmap = (UINT8 *)Z_Malloc(256, PU_STATIC, NULL);
|
||||
cgraymap = (UINT8 *)Z_Malloc(256, PU_STATIC, NULL);
|
||||
credmap = (UINT8 *)Z_Malloc(256, PU_STATIC, NULL);
|
||||
static void CON_SetupColormaps(void)
|
||||
{
|
||||
INT32 i;
|
||||
|
||||
yellowmap = (UINT8 *)Z_Malloc(256, PU_STATIC, NULL);
|
||||
graymap = (UINT8 *)Z_Malloc(256, PU_STATIC, NULL);
|
||||
|
@ -276,20 +287,6 @@ static void CON_SetupBackColormap(void)
|
|||
redmap = (UINT8 *)Z_Malloc(256, PU_STATIC, NULL);
|
||||
orangemap = (UINT8 *)Z_Malloc(256, PU_STATIC, NULL);
|
||||
|
||||
pal = W_CacheLumpName("PLAYPAL", PU_CACHE);
|
||||
|
||||
// setup the green translucent background colormaps
|
||||
for (i = 0, k = 0; i < 768; i += 3, k++)
|
||||
{
|
||||
j = pal[i] + pal[i+1] + pal[i+2];
|
||||
cwhitemap[k] = (UINT8)(15 - (j>>6));
|
||||
corangemap[k] = (UINT8)(95 - (j>>6));
|
||||
cbluemap[k] = (UINT8)(239 - (j>>6));
|
||||
cgreenmap[k] = (UINT8)(175 - (j>>6));
|
||||
cgraymap[k] = (UINT8)(31 - (j>>6));
|
||||
credmap[k] = (UINT8)(143 - (j>>6));
|
||||
}
|
||||
|
||||
// setup the other colormaps, for console text
|
||||
|
||||
// these don't need to be aligned, unless you convert the
|
||||
|
@ -320,6 +317,9 @@ static void CON_SetupBackColormap(void)
|
|||
redmap[9] = (UINT8)127;
|
||||
orangemap[3] = (UINT8)85;
|
||||
orangemap[9] = (UINT8)90;
|
||||
|
||||
// Init back colormap
|
||||
CON_SetupBackColormap();
|
||||
}
|
||||
|
||||
// Setup the console text buffer
|
||||
|
@ -343,7 +343,7 @@ void CON_Init(void)
|
|||
con_width = 0;
|
||||
CON_RecalcSize();
|
||||
|
||||
CON_SetupBackColormap();
|
||||
CON_SetupColormaps();
|
||||
|
||||
//note: CON_Ticker should always execute at least once before D_Display()
|
||||
con_clipviewtop = -1; // -1 does not clip
|
||||
|
@ -386,14 +386,10 @@ void CON_Init(void)
|
|||
//
|
||||
static void CON_InputInit(void)
|
||||
{
|
||||
INT32 i;
|
||||
|
||||
// prepare the first prompt line
|
||||
memset(inputlines, 0, sizeof (inputlines));
|
||||
for (i = 0; i < 32; i++)
|
||||
inputlines[i][0] = CON_PROMPTCHAR;
|
||||
inputline = 0;
|
||||
input_cx = 1;
|
||||
input_cur = input_sel = input_len = 0;
|
||||
}
|
||||
|
||||
//======================================================================
|
||||
|
@ -618,13 +614,91 @@ void CON_Ticker(void)
|
|||
}
|
||||
}
|
||||
|
||||
//
|
||||
// ----
|
||||
//
|
||||
// Shortcuts for adding and deleting characters, strings, and sections
|
||||
// Necessary due to moving cursor
|
||||
//
|
||||
|
||||
static void CON_InputClear(void)
|
||||
{
|
||||
memset(inputlines[inputline], 0, CON_MAXPROMPTCHARS);
|
||||
input_cur = input_sel = input_len = 0;
|
||||
}
|
||||
|
||||
static void CON_InputSetString(const char *c)
|
||||
{
|
||||
memset(inputlines[inputline], 0, CON_MAXPROMPTCHARS);
|
||||
strcpy(inputlines[inputline], c);
|
||||
input_cur = input_sel = input_len = strlen(c);
|
||||
}
|
||||
|
||||
static void CON_InputAddString(const char *c)
|
||||
{
|
||||
size_t csize = strlen(c);
|
||||
if (input_len + csize > CON_MAXPROMPTCHARS-1)
|
||||
return;
|
||||
if (input_cur != input_len)
|
||||
memmove(&inputlines[inputline][input_cur+csize], &inputlines[inputline][input_cur], input_len-input_cur);
|
||||
memcpy(&inputlines[inputline][input_cur], c, csize);
|
||||
input_len += csize;
|
||||
input_sel = (input_cur += csize);
|
||||
}
|
||||
|
||||
static void CON_InputDelSelection(void)
|
||||
{
|
||||
size_t start, end, len;
|
||||
if (input_cur > input_sel)
|
||||
{
|
||||
start = input_sel;
|
||||
end = input_cur;
|
||||
}
|
||||
else
|
||||
{
|
||||
start = input_cur;
|
||||
end = input_sel;
|
||||
}
|
||||
len = (end - start);
|
||||
|
||||
if (end != input_len)
|
||||
memmove(&inputlines[inputline][start], &inputlines[inputline][end], input_len-end);
|
||||
memset(&inputlines[inputline][input_len - len], 0, len);
|
||||
|
||||
input_len -= len;
|
||||
input_sel = input_cur = start;
|
||||
}
|
||||
|
||||
static void CON_InputAddChar(char c)
|
||||
{
|
||||
if (input_len >= CON_MAXPROMPTCHARS-1)
|
||||
return;
|
||||
if (input_cur != input_len)
|
||||
memmove(&inputlines[inputline][input_cur+1], &inputlines[inputline][input_cur], input_len-input_cur);
|
||||
inputlines[inputline][input_cur++] = c;
|
||||
inputlines[inputline][++input_len] = 0;
|
||||
input_sel = input_cur;
|
||||
}
|
||||
|
||||
static void CON_InputDelChar(void)
|
||||
{
|
||||
if (!input_cur)
|
||||
return;
|
||||
if (input_cur != input_len)
|
||||
memmove(&inputlines[inputline][input_cur-1], &inputlines[inputline][input_cur], input_len-input_cur);
|
||||
inputlines[inputline][--input_len] = 0;
|
||||
input_sel = --input_cur;
|
||||
}
|
||||
|
||||
//
|
||||
// ----
|
||||
//
|
||||
|
||||
// Handles console key input
|
||||
//
|
||||
boolean CON_Responder(event_t *ev)
|
||||
{
|
||||
static boolean consdown;
|
||||
static boolean shiftdown;
|
||||
static boolean ctrldown;
|
||||
static UINT8 consdown = false; // console is treated differently due to rare usage
|
||||
|
||||
// sequential completions a la 4dos
|
||||
static char completion[80];
|
||||
|
@ -639,13 +713,8 @@ boolean CON_Responder(event_t *ev)
|
|||
// let go keyup events, don't eat them
|
||||
if (ev->type != ev_keydown && ev->type != ev_console)
|
||||
{
|
||||
if (ev->data1 == KEY_LSHIFT || ev->data1 == KEY_RSHIFT)
|
||||
shiftdown = false;
|
||||
else if (ev->data1 == KEY_LCTRL || ev->data1 == KEY_RCTRL)
|
||||
ctrldown = false;
|
||||
else if (ev->data1 == gamecontrol[gc_console][0] || ev->data1 == gamecontrol[gc_console][1])
|
||||
if (ev->data1 == gamecontrol[gc_console][0] || ev->data1 == gamecontrol[gc_console][1])
|
||||
consdown = false;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -684,94 +753,110 @@ boolean CON_Responder(event_t *ev)
|
|||
consoletoggle = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// eat shift only if console active
|
||||
if (key == KEY_LSHIFT || key == KEY_RSHIFT)
|
||||
{
|
||||
shiftdown = true;
|
||||
// Always eat ctrl/shift/alt if console open, so the menu doesn't get ideas
|
||||
if (key == KEY_LSHIFT || key == KEY_RSHIFT
|
||||
|| key == KEY_LCTRL || key == KEY_RCTRL
|
||||
|| key == KEY_LALT || key == KEY_RALT)
|
||||
return true;
|
||||
}
|
||||
|
||||
// same for ctrl
|
||||
if (key == KEY_LCTRL || key == KEY_RCTRL)
|
||||
// ctrl modifier -- changes behavior, adds shortcuts
|
||||
if (ctrldown)
|
||||
{
|
||||
ctrldown = true;
|
||||
return true;
|
||||
// show all cvars/commands that match what we have inputted
|
||||
if (key == KEY_TAB)
|
||||
{
|
||||
size_t i, len;
|
||||
|
||||
if (!completion[0])
|
||||
{
|
||||
if (!input_len || input_len >= 40 || strchr(inputlines[inputline], ' '))
|
||||
return true;
|
||||
strcpy(completion, inputlines[inputline]);
|
||||
comskips = varskips = 0;
|
||||
}
|
||||
len = strlen(completion);
|
||||
|
||||
//first check commands
|
||||
CONS_Printf("\nCommands:\n");
|
||||
for (i = 0, cmd = COM_CompleteCommand(completion, i); cmd; cmd = COM_CompleteCommand(completion, ++i))
|
||||
CONS_Printf(" \x83" "%s" "\x80" "%s\n", completion, cmd+len);
|
||||
if (i == 0) CONS_Printf(" (none)\n");
|
||||
|
||||
//now we move on to CVARs
|
||||
CONS_Printf("Variables:\n");
|
||||
for (i = 0, cmd = CV_CompleteVar(completion, i); cmd; cmd = CV_CompleteVar(completion, ++i))
|
||||
CONS_Printf(" \x83" "%s" "\x80" "%s\n", completion, cmd+len);
|
||||
if (i == 0) CONS_Printf(" (none)\n");
|
||||
|
||||
return true;
|
||||
}
|
||||
// ---
|
||||
|
||||
if (key == KEY_HOME) // oldest text in buffer
|
||||
{
|
||||
con_scrollup = (con_totallines-((con_curlines-16)>>3));
|
||||
return true;
|
||||
}
|
||||
else if (key == KEY_END) // most recent text in buffer
|
||||
{
|
||||
con_scrollup = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (key == 'x' || key == 'X')
|
||||
{
|
||||
if (input_sel > input_cur)
|
||||
I_ClipboardCopy(&inputlines[inputline][input_cur], input_sel-input_cur);
|
||||
else
|
||||
I_ClipboardCopy(&inputlines[inputline][input_sel], input_cur-input_sel);
|
||||
CON_InputDelSelection();
|
||||
completion[0] = 0;
|
||||
return true;
|
||||
}
|
||||
else if (key == 'c' || key == 'C')
|
||||
{
|
||||
if (input_sel > input_cur)
|
||||
I_ClipboardCopy(&inputlines[inputline][input_cur], input_sel-input_cur);
|
||||
else
|
||||
I_ClipboardCopy(&inputlines[inputline][input_sel], input_cur-input_sel);
|
||||
return true;
|
||||
}
|
||||
else if (key == 'v' || key == 'V')
|
||||
{
|
||||
const char *paste = I_ClipboardPaste();
|
||||
if (input_sel != input_cur)
|
||||
CON_InputDelSelection();
|
||||
if (paste != NULL)
|
||||
CON_InputAddString(paste);
|
||||
completion[0] = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Select all
|
||||
if (key == 'a' || key == 'A')
|
||||
{
|
||||
input_sel = 0;
|
||||
input_cur = input_len;
|
||||
return true;
|
||||
}
|
||||
|
||||
// don't eat the key
|
||||
return false;
|
||||
}
|
||||
|
||||
// command completion forward (tab) and backward (shift-tab)
|
||||
if (key == KEY_TAB)
|
||||
{
|
||||
// show all cvars/commands that match what we have inputted
|
||||
if (ctrldown)
|
||||
{
|
||||
UINT32 i;
|
||||
size_t stop = input_cx - 1;
|
||||
char nameremainder[255];
|
||||
|
||||
if (input_cx < 2 || strlen(inputlines[inputline]+1) >= 80)
|
||||
return true;
|
||||
|
||||
strcpy(completion, inputlines[inputline]+1);
|
||||
|
||||
// trimming: stop at the first newline
|
||||
for (i = 0; i < input_cx - 1; ++i)
|
||||
{
|
||||
if (completion[i] == ' ')
|
||||
{
|
||||
completion[i] = '\0';
|
||||
stop = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
i = 0;
|
||||
|
||||
//first check commands
|
||||
CONS_Printf("\nCommands:\n");
|
||||
|
||||
for (cmd = COM_CompleteCommand(completion, i); cmd; cmd = COM_CompleteCommand(completion, i))
|
||||
{
|
||||
strncpy(nameremainder, cmd+(stop), strlen(cmd)-(stop));
|
||||
nameremainder[strlen(cmd)-(stop)] = '\0';
|
||||
|
||||
CONS_Printf(" \x83" "%s" "\x80" "%s\n", completion, nameremainder);
|
||||
++i;
|
||||
}
|
||||
if (i == 0)
|
||||
CONS_Printf(" (none)\n");
|
||||
|
||||
i = 0;
|
||||
|
||||
//now we move on to CVARs
|
||||
CONS_Printf("Variables:\n");
|
||||
|
||||
for (cmd = CV_CompleteVar(completion, i); cmd; cmd = CV_CompleteVar(completion, i))
|
||||
{
|
||||
strncpy(nameremainder, cmd+(stop), strlen(cmd)-(stop));
|
||||
nameremainder[strlen(cmd)-(stop)] = '\0';
|
||||
|
||||
CONS_Printf(" \x83" "%s" "\x80" "%s\n", completion, nameremainder);
|
||||
++i;
|
||||
}
|
||||
if (i == 0)
|
||||
CONS_Printf(" (none)\n");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// sequential command completion forward and backward
|
||||
|
||||
// remember typing for several completions (a-la-4dos)
|
||||
if (inputlines[inputline][input_cx-1] != ' ')
|
||||
if (!completion[0])
|
||||
{
|
||||
if (strlen(inputlines[inputline]+1) < 80)
|
||||
strcpy(completion, inputlines[inputline]+1);
|
||||
else
|
||||
completion[0] = 0;
|
||||
|
||||
if (!input_len || input_len >= 40 || strchr(inputlines[inputline], ' '))
|
||||
return true;
|
||||
strcpy(completion, inputlines[inputline]);
|
||||
comskips = varskips = 0;
|
||||
}
|
||||
else
|
||||
|
@ -783,37 +868,26 @@ boolean CON_Responder(event_t *ev)
|
|||
if (--varskips < 0)
|
||||
comskips = -comskips - 2;
|
||||
}
|
||||
else if (comskips > 0)
|
||||
comskips--;
|
||||
else if (comskips > 0) comskips--;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (comskips < 0)
|
||||
varskips++;
|
||||
else
|
||||
comskips++;
|
||||
if (comskips < 0) varskips++;
|
||||
else comskips++;
|
||||
}
|
||||
}
|
||||
|
||||
if (comskips >= 0)
|
||||
{
|
||||
cmd = COM_CompleteCommand(completion, comskips);
|
||||
if (!cmd)
|
||||
// dirty: make sure if comskips is zero, to have a neg value
|
||||
if (!cmd) // dirty: make sure if comskips is zero, to have a neg value
|
||||
comskips = -comskips - 1;
|
||||
}
|
||||
if (comskips < 0)
|
||||
cmd = CV_CompleteVar(completion, varskips);
|
||||
|
||||
if (cmd)
|
||||
{
|
||||
memset(inputlines[inputline]+1, 0, CON_MAXPROMPTCHARS-1);
|
||||
strcpy(inputlines[inputline]+1, cmd);
|
||||
input_cx = strlen(cmd) + 1;
|
||||
inputlines[inputline][input_cx] = ' ';
|
||||
input_cx++;
|
||||
inputlines[inputline][input_cx] = 0;
|
||||
}
|
||||
CON_InputSetString(va("%s ", cmd));
|
||||
else
|
||||
{
|
||||
if (comskips > 0)
|
||||
|
@ -839,47 +913,80 @@ boolean CON_Responder(event_t *ev)
|
|||
return true;
|
||||
}
|
||||
|
||||
if (key == KEY_HOME) // oldest text in buffer
|
||||
if (key == KEY_LEFTARROW)
|
||||
{
|
||||
con_scrollup = (con_totallines-((con_curlines-16)>>3));
|
||||
if (input_cur != 0)
|
||||
--input_cur;
|
||||
if (!shiftdown)
|
||||
input_sel = input_cur;
|
||||
return true;
|
||||
}
|
||||
else if (key == KEY_END) // most recent text in buffer
|
||||
else if (key == KEY_RIGHTARROW)
|
||||
{
|
||||
con_scrollup = 0;
|
||||
if (input_cur < input_len)
|
||||
++input_cur;
|
||||
if (!shiftdown)
|
||||
input_sel = input_cur;
|
||||
return true;
|
||||
}
|
||||
else if (key == KEY_HOME)
|
||||
{
|
||||
input_cur = 0;
|
||||
if (!shiftdown)
|
||||
input_sel = input_cur;
|
||||
return true;
|
||||
}
|
||||
else if (key == KEY_END)
|
||||
{
|
||||
input_cur = input_len;
|
||||
if (!shiftdown)
|
||||
input_sel = input_cur;
|
||||
return true;
|
||||
}
|
||||
|
||||
// At this point we're messing with input
|
||||
// Clear completion
|
||||
completion[0] = 0;
|
||||
|
||||
// command enter
|
||||
if (key == KEY_ENTER)
|
||||
{
|
||||
if (input_cx < 2)
|
||||
if (!input_len)
|
||||
return true;
|
||||
|
||||
// push the command
|
||||
COM_BufAddText(inputlines[inputline]+1);
|
||||
COM_BufAddText(inputlines[inputline]);
|
||||
COM_BufAddText("\n");
|
||||
|
||||
CONS_Printf("%s\n", inputlines[inputline]);
|
||||
CONS_Printf("\x86""%c""\x80""%s\n", CON_PROMPTCHAR, inputlines[inputline]);
|
||||
|
||||
inputline = (inputline+1) & 31;
|
||||
inputhist = inputline;
|
||||
|
||||
memset(inputlines[inputline], 0, CON_MAXPROMPTCHARS);
|
||||
inputlines[inputline][0] = CON_PROMPTCHAR;
|
||||
input_cx = 1;
|
||||
CON_InputClear();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// backspace command prompt
|
||||
if (key == KEY_BACKSPACE)
|
||||
// backspace and delete command prompt
|
||||
if (input_sel != input_cur)
|
||||
{
|
||||
if (input_cx > 1)
|
||||
if (key == KEY_BACKSPACE || key == KEY_DEL)
|
||||
{
|
||||
input_cx--;
|
||||
inputlines[inputline][input_cx] = 0;
|
||||
CON_InputDelSelection();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (key == KEY_BACKSPACE)
|
||||
{
|
||||
CON_InputDelChar();
|
||||
return true;
|
||||
}
|
||||
else if (key == KEY_DEL)
|
||||
{
|
||||
if (input_cur == input_len)
|
||||
return true;
|
||||
++input_cur;
|
||||
CON_InputDelChar();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -888,18 +995,15 @@ boolean CON_Responder(event_t *ev)
|
|||
{
|
||||
// copy one of the previous inputlines to the current
|
||||
do
|
||||
{
|
||||
inputhist = (inputhist - 1) & 31; // cycle back
|
||||
} while (inputhist != inputline && !inputlines[inputhist][1]);
|
||||
while (inputhist != inputline && !inputlines[inputhist][0]);
|
||||
|
||||
// stop at the last history input line, which is the
|
||||
// current line + 1 because we cycle through the 32 input lines
|
||||
if (inputhist == inputline)
|
||||
inputhist = (inputline + 1) & 31;
|
||||
|
||||
M_Memcpy(inputlines[inputline], inputlines[inputhist], CON_MAXPROMPTCHARS);
|
||||
input_cx = strlen(inputlines[inputline]);
|
||||
|
||||
CON_InputSetString(inputlines[inputhist]);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -909,23 +1013,14 @@ boolean CON_Responder(event_t *ev)
|
|||
if (inputhist == inputline)
|
||||
return true;
|
||||
do
|
||||
{
|
||||
inputhist = (inputhist + 1) & 31;
|
||||
} while (inputhist != inputline && !inputlines[inputhist][1]);
|
||||
|
||||
memset(inputlines[inputline], 0, CON_MAXPROMPTCHARS);
|
||||
while (inputhist != inputline && !inputlines[inputhist][0]);
|
||||
|
||||
// back to currentline
|
||||
if (inputhist == inputline)
|
||||
{
|
||||
inputlines[inputline][0] = CON_PROMPTCHAR;
|
||||
input_cx = 1;
|
||||
}
|
||||
CON_InputClear();
|
||||
else
|
||||
{
|
||||
strcpy(inputlines[inputline], inputlines[inputhist]);
|
||||
input_cx = strlen(inputlines[inputline]);
|
||||
}
|
||||
CON_InputSetString(inputlines[inputhist]);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -950,15 +1045,12 @@ boolean CON_Responder(event_t *ev)
|
|||
return false;
|
||||
|
||||
// add key to cmd line here
|
||||
if (input_cx < CON_MAXPROMPTCHARS)
|
||||
{
|
||||
if (key >= 'A' && key <= 'Z' && !shiftdown) //this is only really necessary for dedicated servers
|
||||
key = key + 'a' - 'A';
|
||||
if (key >= 'A' && key <= 'Z' && !shiftdown) //this is only really necessary for dedicated servers
|
||||
key = key + 'a' - 'A';
|
||||
|
||||
inputlines[inputline][input_cx] = (char)key;
|
||||
inputlines[inputline][input_cx + 1] = 0;
|
||||
input_cx++;
|
||||
}
|
||||
if (input_sel != input_cur)
|
||||
CON_InputDelSelection();
|
||||
CON_InputAddChar(key);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -1242,26 +1334,89 @@ void CONS_Error(const char *msg)
|
|||
//
|
||||
static void CON_DrawInput(void)
|
||||
{
|
||||
char *p;
|
||||
size_t c;
|
||||
INT32 x, y;
|
||||
INT32 charwidth = (INT32)con_scalefactor << 3;
|
||||
|
||||
// input line scrolls left if it gets too long
|
||||
p = inputlines[inputline];
|
||||
if (input_cx >= con_width-11)
|
||||
p += input_cx - (con_width-11) + 1;
|
||||
const char *p = inputlines[inputline];
|
||||
size_t c, clen, cend;
|
||||
UINT8 lellip = 0, rellip = 0;
|
||||
INT32 x, y, i;
|
||||
|
||||
y = con_curlines - 12 * con_scalefactor;
|
||||
x = charwidth*2;
|
||||
|
||||
for (c = 0, x = charwidth; c < con_width-11; c++, x += charwidth)
|
||||
V_DrawCharacter(x, y, p[c] | cv_constextsize.value | V_NOSCALESTART, !cv_allcaps.value);
|
||||
clen = con_width-13;
|
||||
|
||||
// draw the blinking cursor
|
||||
//
|
||||
x = ((input_cx >= con_width-11) ? (INT32)(con_width-11) : (INT32)((input_cx + 1)) * charwidth);
|
||||
if (con_tick < 4)
|
||||
V_DrawCharacter(x, y, '_' | cv_constextsize.value | V_NOSCALESTART, !cv_allcaps.value);
|
||||
if (input_len <= clen)
|
||||
{
|
||||
c = 0;
|
||||
clen = input_len;
|
||||
}
|
||||
else // input line scrolls left if it gets too long
|
||||
{
|
||||
clen -= 2; // There will always be some extra truncation -- but where is what we'll find out
|
||||
|
||||
if (input_cur <= clen/2)
|
||||
{
|
||||
// Close enough to right edge to show all
|
||||
c = 0;
|
||||
// Always will truncate right side from this position, so always draw right ellipsis
|
||||
rellip = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Cursor in the middle (or right side) of input
|
||||
// Move over for the ellipsis
|
||||
c = input_cur - (clen/2) + 2;
|
||||
x += charwidth*2;
|
||||
lellip = 1;
|
||||
|
||||
if (c + clen >= input_len)
|
||||
{
|
||||
// Cursor in the right side of input
|
||||
// We were too far over, so move back
|
||||
c = input_len - clen;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Cursor in the middle -- ellipses on both sides
|
||||
clen -= 2;
|
||||
rellip = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (lellip)
|
||||
{
|
||||
x -= charwidth*3;
|
||||
if (input_sel < c)
|
||||
V_DrawFill(x, y, charwidth*3, (10 * con_scalefactor), 107 | V_NOSCALESTART);
|
||||
for (i = 0; i < 3; ++i, x += charwidth)
|
||||
V_DrawCharacter(x, y, '.' | cv_constextsize.value | V_GRAYMAP | V_NOSCALESTART, !cv_allcaps.value);
|
||||
}
|
||||
else
|
||||
V_DrawCharacter(x-charwidth, y, CON_PROMPTCHAR | cv_constextsize.value | V_GRAYMAP | V_NOSCALESTART, !cv_allcaps.value);
|
||||
|
||||
for (cend = c + clen; c < cend; ++c, x += charwidth)
|
||||
{
|
||||
if ((input_sel > c && input_cur <= c) || (input_sel <= c && input_cur > c))
|
||||
{
|
||||
V_DrawFill(x, y, charwidth, (10 * con_scalefactor), 107 | V_NOSCALESTART);
|
||||
V_DrawCharacter(x, y, p[c] | cv_constextsize.value | V_YELLOWMAP | V_NOSCALESTART, !cv_allcaps.value);
|
||||
}
|
||||
else
|
||||
V_DrawCharacter(x, y, p[c] | cv_constextsize.value | V_NOSCALESTART, !cv_allcaps.value);
|
||||
|
||||
if (c == input_cur && con_tick >= 4)
|
||||
V_DrawCharacter(x, y + (con_scalefactor*2), '_' | cv_constextsize.value | V_NOSCALESTART, !cv_allcaps.value);
|
||||
}
|
||||
if (cend == input_cur && con_tick >= 4)
|
||||
V_DrawCharacter(x, y + (con_scalefactor*2), '_' | cv_constextsize.value | V_NOSCALESTART, !cv_allcaps.value);
|
||||
if (rellip)
|
||||
{
|
||||
if (input_sel > cend)
|
||||
V_DrawFill(x, y, charwidth*3, (10 * con_scalefactor), 107 | V_NOSCALESTART);
|
||||
for (i = 0; i < 3; ++i, x += charwidth)
|
||||
V_DrawCharacter(x, y, '.' | cv_constextsize.value | V_GRAYMAP | V_NOSCALESTART, !cv_allcaps.value);
|
||||
}
|
||||
}
|
||||
|
||||
// draw the last lines of console text to the top of the screen
|
||||
|
@ -1417,7 +1572,7 @@ static void CON_DrawConsole(void)
|
|||
{
|
||||
// inu: no more width (was always 0 and vid.width)
|
||||
if (rendermode != render_none)
|
||||
V_DrawFadeConsBack(con_curlines, cons_backcolor.value); // translucent background
|
||||
V_DrawFadeConsBack(con_curlines); // translucent background
|
||||
}
|
||||
|
||||
// draw console text lines from top to bottom
|
||||
|
|
|
@ -40,11 +40,10 @@ extern consvar_t cons_backcolor;
|
|||
|
||||
extern UINT8 *yellowmap, *purplemap, *lgreenmap, *bluemap, *graymap, *redmap, *orangemap;
|
||||
|
||||
// Console bg colors:
|
||||
extern UINT8 *cwhitemap, *corangemap, *cbluemap, *cgreenmap, *cgraymap,
|
||||
*credmap;
|
||||
// Console bg color (auto updated to match)
|
||||
extern UINT8 *consolebgmap;
|
||||
|
||||
void CON_ReSetupBackColormap(UINT16 num);
|
||||
void CON_SetupBackColormap(void);
|
||||
void CON_ClearHUD(void); // clear heads up messages
|
||||
|
||||
void CON_Ticker(void);
|
||||
|
|
2006
src/d_clisrv.c
2006
src/d_clisrv.c
File diff suppressed because it is too large
Load diff
124
src/d_clisrv.h
124
src/d_clisrv.h
|
@ -59,7 +59,7 @@ typedef enum
|
|||
// Add non-PT_CANFAIL packet types here to avoid breaking MS compatibility.
|
||||
|
||||
PT_CANFAIL, // This is kind of a priority. Anything bigger than CANFAIL
|
||||
// allows HSendPacket(,true,,) to return false.
|
||||
// allows HSendPacket(*, true, *, *) to return false.
|
||||
// In addition, this packet can't occupy all the available slots.
|
||||
|
||||
PT_FILEFRAGMENT = PT_CANFAIL, // A part of a file.
|
||||
|
@ -76,11 +76,19 @@ typedef enum
|
|||
NUMPACKETTYPE
|
||||
} packettype_t;
|
||||
|
||||
#ifdef PACKETDROP
|
||||
void Command_Drop(void);
|
||||
void Command_Droprate(void);
|
||||
#endif
|
||||
#ifdef _DEBUG
|
||||
void Command_Numnodes(void);
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma pack(1)
|
||||
#endif
|
||||
|
||||
// client to server packet
|
||||
// Client to server packet
|
||||
typedef struct
|
||||
{
|
||||
UINT8 client_tic;
|
||||
|
@ -89,7 +97,7 @@ typedef struct
|
|||
ticcmd_t cmd;
|
||||
} ATTRPACK clientcmd_pak;
|
||||
|
||||
// splitscreen packet
|
||||
// Splitscreen packet
|
||||
// WARNING: must have the same format of clientcmd_pak, for more easy use
|
||||
typedef struct
|
||||
{
|
||||
|
@ -110,16 +118,16 @@ typedef struct
|
|||
UINT8 starttic;
|
||||
UINT8 numtics;
|
||||
UINT8 numslots; // "Slots filled": Highest player number in use plus one.
|
||||
ticcmd_t cmds[45]; // normally [BACKUPTIC][MAXPLAYERS] but too large
|
||||
ticcmd_t cmds[45]; // Normally [BACKUPTIC][MAXPLAYERS] but too large
|
||||
} ATTRPACK servertics_pak;
|
||||
|
||||
// sent to client when all consistency data
|
||||
// Sent to client when all consistency data
|
||||
// for players has been restored
|
||||
typedef struct
|
||||
{
|
||||
UINT32 randomseed;
|
||||
|
||||
//ctf flag stuff
|
||||
// CTF flag stuff
|
||||
SINT8 flagplayer[2];
|
||||
INT32 flagloose[2];
|
||||
INT32 flagflags[2];
|
||||
|
@ -127,11 +135,11 @@ typedef struct
|
|||
fixed_t flagy[2];
|
||||
fixed_t flagz[2];
|
||||
|
||||
UINT32 ingame; // spectator bit for each player
|
||||
UINT32 ctfteam; // if not spectator, then which team?
|
||||
UINT32 ingame; // Spectator bit for each player
|
||||
INT32 ctfteam[MAXPLAYERS]; // Which team? (can't be 1 bit, since in regular Match there are no teams)
|
||||
|
||||
// Resynch game scores and the like all at once
|
||||
UINT32 score[MAXPLAYERS]; // Everyone's score.
|
||||
UINT32 score[MAXPLAYERS]; // Everyone's score
|
||||
INT16 numboxes[MAXPLAYERS];
|
||||
INT16 totalring[MAXPLAYERS];
|
||||
tic_t realtime[MAXPLAYERS];
|
||||
|
@ -140,14 +148,14 @@ typedef struct
|
|||
|
||||
typedef struct
|
||||
{
|
||||
//player stuff
|
||||
// Player stuff
|
||||
UINT8 playernum;
|
||||
|
||||
// Do not send anything visual related.
|
||||
// Only send data that we need to know for physics.
|
||||
UINT8 playerstate; //playerstate_t
|
||||
UINT32 pflags; //pflags_t
|
||||
UINT8 panim; //panim_t
|
||||
UINT8 playerstate; // playerstate_t
|
||||
UINT32 pflags; // pflags_t
|
||||
UINT8 panim; // panim_t
|
||||
|
||||
angle_t aiming;
|
||||
INT32 currentweapon;
|
||||
|
@ -174,9 +182,9 @@ typedef struct
|
|||
UINT8 charability;
|
||||
UINT8 charability2;
|
||||
UINT32 charflags;
|
||||
UINT32 thokitem; //mobjtype_t
|
||||
UINT32 spinitem; //mobjtype_t
|
||||
UINT32 revitem; //mobjtype_t
|
||||
UINT32 thokitem; // mobjtype_t
|
||||
UINT32 spinitem; // mobjtype_t
|
||||
UINT32 revitem; // mobjtype_t
|
||||
fixed_t actionspd;
|
||||
fixed_t mindash;
|
||||
fixed_t maxdash;
|
||||
|
@ -230,7 +238,7 @@ typedef struct
|
|||
INT32 onconveyor;
|
||||
|
||||
//player->mo stuff
|
||||
UINT8 hasmo; //boolean
|
||||
UINT8 hasmo; // Boolean
|
||||
|
||||
angle_t angle;
|
||||
fixed_t x;
|
||||
|
@ -257,10 +265,10 @@ typedef struct
|
|||
|
||||
typedef struct
|
||||
{
|
||||
UINT8 version; // different versions don't work
|
||||
UINT8 subversion; // contains build version
|
||||
UINT8 version; // Different versions don't work
|
||||
UINT8 subversion; // Contains build version
|
||||
|
||||
// server launch stuffs
|
||||
// Server launch stuffs
|
||||
UINT8 serverplayer;
|
||||
UINT8 totalslotnum; // "Slots": highest player number in use plus one.
|
||||
|
||||
|
@ -274,18 +282,18 @@ typedef struct
|
|||
|
||||
UINT8 gametype;
|
||||
UINT8 modifiedgame;
|
||||
SINT8 adminplayer; // needs to be signed
|
||||
SINT8 adminplayer; // Needs to be signed
|
||||
|
||||
char server_context[8]; // unique context id, generated at server startup.
|
||||
char server_context[8]; // Unique context id, generated at server startup.
|
||||
|
||||
UINT8 varlengthinputs[0]; // playernames and netvars
|
||||
UINT8 varlengthinputs[0]; // Playernames and netvars
|
||||
} ATTRPACK serverconfig_pak;
|
||||
|
||||
typedef struct {
|
||||
UINT8 fileid;
|
||||
UINT32 position;
|
||||
UINT16 size;
|
||||
UINT8 data[0]; // size is variable using hardware_MAXPACKETLENGTH
|
||||
UINT8 data[0]; // Size is variable using hardware_MAXPACKETLENGTH
|
||||
} ATTRPACK filetx_pak;
|
||||
|
||||
#ifdef _MSC_VER
|
||||
|
@ -294,14 +302,14 @@ typedef struct {
|
|||
|
||||
typedef struct
|
||||
{
|
||||
UINT8 version; // different versions don't work
|
||||
UINT8 subversion; // contains build version
|
||||
UINT8 version; // Different versions don't work
|
||||
UINT8 subversion; // Contains build version
|
||||
UINT8 localplayers;
|
||||
UINT8 mode;
|
||||
} ATTRPACK clientconfig_pak;
|
||||
|
||||
#define MAXSERVERNAME 32
|
||||
// this packet is too large
|
||||
// This packet is too large
|
||||
typedef struct
|
||||
{
|
||||
UINT8 version;
|
||||
|
@ -367,45 +375,45 @@ typedef struct
|
|||
} ATTRPACK plrconfig;
|
||||
|
||||
//
|
||||
// Network packet data.
|
||||
// Network packet data
|
||||
//
|
||||
typedef struct
|
||||
{
|
||||
UINT32 checksum;
|
||||
UINT8 ack; // if not null the node asks for acknowledgement, the receiver must resend the ack
|
||||
UINT8 ackreturn; // the return of the ack number
|
||||
UINT8 ack; // If not zero the node asks for acknowledgement, the receiver must resend the ack
|
||||
UINT8 ackreturn; // The return of the ack number
|
||||
|
||||
UINT8 packettype;
|
||||
UINT8 reserved; // padding
|
||||
UINT8 reserved; // Padding
|
||||
union
|
||||
{
|
||||
clientcmd_pak clientpak; // 144 bytes
|
||||
client2cmd_pak client2pak; // 200 bytes
|
||||
servertics_pak serverpak; // 132495 bytes
|
||||
serverconfig_pak servercfg; // 773 bytes
|
||||
resynchend_pak resynchend; //
|
||||
resynch_pak resynchpak; //
|
||||
UINT8 resynchgot; //
|
||||
UINT8 textcmd[MAXTEXTCMD+1]; // 66049 bytes
|
||||
filetx_pak filetxpak; // 139 bytes
|
||||
clientconfig_pak clientcfg; // 136 bytes
|
||||
serverinfo_pak serverinfo; // 1024 bytes
|
||||
serverrefuse_pak serverrefuse; // 65025 bytes
|
||||
askinfo_pak askinfo; // 61 bytes
|
||||
msaskinfo_pak msaskinfo; // 22 bytes
|
||||
plrinfo playerinfo[MAXPLAYERS]; // 1152 bytes
|
||||
plrconfig playerconfig[MAXPLAYERS]; // (up to) 896 bytes
|
||||
clientcmd_pak clientpak; // 144 bytes
|
||||
client2cmd_pak client2pak; // 200 bytes
|
||||
servertics_pak serverpak; // 132495 bytes (more around 360, no?)
|
||||
serverconfig_pak servercfg; // 773 bytes
|
||||
resynchend_pak resynchend; //
|
||||
resynch_pak resynchpak; //
|
||||
UINT8 resynchgot; //
|
||||
UINT8 textcmd[MAXTEXTCMD+1]; // 66049 bytes (wut??? 64k??? More like 257 bytes...)
|
||||
filetx_pak filetxpak; // 139 bytes
|
||||
clientconfig_pak clientcfg; // 136 bytes
|
||||
serverinfo_pak serverinfo; // 1024 bytes
|
||||
serverrefuse_pak serverrefuse; // 65025 bytes (somehow I feel like those values are garbage...)
|
||||
askinfo_pak askinfo; // 61 bytes
|
||||
msaskinfo_pak msaskinfo; // 22 bytes
|
||||
plrinfo playerinfo[MAXPLAYERS]; // 1152 bytes (I'd say 36~38)
|
||||
plrconfig playerconfig[MAXPLAYERS]; // (up to) 896 bytes (welp they ARE)
|
||||
#ifdef NEWPING
|
||||
UINT32 pingtable[MAXPLAYERS]; // 128 bytes
|
||||
UINT32 pingtable[MAXPLAYERS]; // 128 bytes
|
||||
#endif
|
||||
} u; // this is needed to pack diff packet types data together
|
||||
} u; // This is needed to pack diff packet types data together
|
||||
} ATTRPACK doomdata_t;
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma pack()
|
||||
#endif
|
||||
|
||||
#define MAXSERVERLIST 64 // depends only on the display
|
||||
#define MAXSERVERLIST 64 // Depends only on the display
|
||||
typedef struct
|
||||
{
|
||||
SINT8 node;
|
||||
|
@ -416,7 +424,7 @@ extern serverelem_t serverlist[MAXSERVERLIST];
|
|||
extern UINT32 serverlistcount;
|
||||
extern INT32 mapchangepending;
|
||||
|
||||
// points inside doomcom
|
||||
// Points inside doomcom
|
||||
extern doomdata_t *netbuffer;
|
||||
|
||||
extern consvar_t cv_playbackspeed;
|
||||
|
@ -437,26 +445,28 @@ extern consvar_t cv_playbackspeed;
|
|||
#define KICK_MSG_CUSTOM_BAN 8
|
||||
|
||||
extern boolean server;
|
||||
extern boolean dedicated; // for dedicated server
|
||||
#define client (!server)
|
||||
extern boolean dedicated; // For dedicated server
|
||||
extern UINT16 software_MAXPACKETLENGTH;
|
||||
extern boolean acceptnewnode;
|
||||
extern SINT8 servernode;
|
||||
|
||||
void Command_Ping_f(void);
|
||||
extern tic_t connectiontimeout;
|
||||
extern tic_t jointimeout;
|
||||
#ifdef NEWPING
|
||||
extern UINT16 pingmeasurecount;
|
||||
extern UINT32 realpingtable[MAXPLAYERS];
|
||||
extern UINT32 playerpingtable[MAXPLAYERS];
|
||||
#endif
|
||||
|
||||
extern consvar_t cv_joinnextround, cv_allownewplayer, cv_maxplayers, cv_resynchattempts, cv_blamecfail, cv_maxsend;
|
||||
extern consvar_t cv_joinnextround, cv_allownewplayer, cv_maxplayers, cv_resynchattempts, cv_blamecfail, cv_maxsend, cv_noticedownload, cv_downloadspeed;
|
||||
|
||||
// used in d_net, the only dependence
|
||||
// Used in d_net, the only dependence
|
||||
tic_t ExpandTics(INT32 low);
|
||||
void D_ClientServerInit(void);
|
||||
|
||||
// initialise the other field
|
||||
// Initialise the other field
|
||||
void RegisterNetXCmd(netxcmd_t id, void (*cmd_f)(UINT8 **p, INT32 playernum));
|
||||
void SendNetXCmd(netxcmd_t id, const void *param, size_t nparam);
|
||||
void SendNetXCmd2(netxcmd_t id, const void *param, size_t nparam); // splitsreen player
|
||||
|
@ -474,14 +484,14 @@ void CL_RemoveSplitscreenPlayer(void);
|
|||
void CL_Reset(void);
|
||||
void CL_ClearPlayer(INT32 playernum);
|
||||
void CL_UpdateServerList(boolean internetsearch, INT32 room);
|
||||
// is there a game running
|
||||
// Is there a game running
|
||||
boolean Playing(void);
|
||||
|
||||
// Broadcasts special packets to other players
|
||||
// to notify of game exit
|
||||
void D_QuitNetGame(void);
|
||||
|
||||
//? how many ticks to run?
|
||||
//? How many ticks to run?
|
||||
void TryRunTics(tic_t realtic);
|
||||
|
||||
// extra data for lmps
|
||||
|
|
43
src/d_main.c
43
src/d_main.c
|
@ -73,6 +73,7 @@ int snprintf(char *str, size_t n, const char *fmt, ...);
|
|||
#include "dehacked.h" // Dehacked list test
|
||||
#include "m_cond.h" // condition initialization
|
||||
#include "fastcmp.h"
|
||||
#include "keys.h"
|
||||
|
||||
#ifdef CMAKECONFIG
|
||||
#include "config.h"
|
||||
|
@ -176,6 +177,38 @@ void D_PostEvent(const event_t *ev)
|
|||
void D_PostEvent_end(void) {};
|
||||
#endif
|
||||
|
||||
// modifier keys
|
||||
UINT8 shiftdown = 0; // 0x1 left, 0x2 right
|
||||
UINT8 ctrldown = 0; // 0x1 left, 0x2 right
|
||||
UINT8 altdown = 0; // 0x1 left, 0x2 right
|
||||
//
|
||||
// D_ModifierKeyResponder
|
||||
// Sets global shift/ctrl/alt variables, never actually eats events
|
||||
//
|
||||
static inline void D_ModifierKeyResponder(event_t *ev)
|
||||
{
|
||||
if (ev->type == ev_keydown || ev->type == ev_console) switch (ev->data1)
|
||||
{
|
||||
case KEY_LSHIFT: shiftdown |= 0x1; return;
|
||||
case KEY_RSHIFT: shiftdown |= 0x2; return;
|
||||
case KEY_LCTRL: ctrldown |= 0x1; return;
|
||||
case KEY_RCTRL: ctrldown |= 0x2; return;
|
||||
case KEY_LALT: altdown |= 0x1; return;
|
||||
case KEY_RALT: altdown |= 0x2; return;
|
||||
default: return;
|
||||
}
|
||||
else if (ev->type == ev_keyup) switch (ev->data1)
|
||||
{
|
||||
case KEY_LSHIFT: shiftdown &= ~0x1; return;
|
||||
case KEY_RSHIFT: shiftdown &= ~0x2; return;
|
||||
case KEY_LCTRL: ctrldown &= ~0x1; return;
|
||||
case KEY_RCTRL: ctrldown &= ~0x2; return;
|
||||
case KEY_LALT: altdown &= ~0x1; return;
|
||||
case KEY_RALT: altdown &= ~0x2; return;
|
||||
default: return;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// D_ProcessEvents
|
||||
// Send all the events of the given timestamp down the responder chain
|
||||
|
@ -188,6 +221,9 @@ void D_ProcessEvents(void)
|
|||
{
|
||||
ev = &events[eventtail];
|
||||
|
||||
// Set global shift/ctrl/alt down variables
|
||||
D_ModifierKeyResponder(ev); // never eats events
|
||||
|
||||
// Screenshots over everything so that they can be taken anywhere.
|
||||
if (M_ScreenshotResponder(ev))
|
||||
continue; // ate the event
|
||||
|
@ -1060,10 +1096,11 @@ void D_SRB2Main(void)
|
|||
if (M_CheckParm("-warp") && M_IsNextParm())
|
||||
{
|
||||
const char *word = M_GetNextParm();
|
||||
if (fastncmp(word, "MAP", 3))
|
||||
char ch; // use this with sscanf to catch non-digits with
|
||||
if (fastncmp(word, "MAP", 3)) // MAPxx name
|
||||
pstartmap = M_MapNumber(word[3], word[4]);
|
||||
else
|
||||
pstartmap = atoi(word);
|
||||
else if (sscanf(word, "%d%c", &pstartmap, &ch) != 1) // a plain number
|
||||
I_Error("Cannot warp to map %s (invalid map name)\n", word);
|
||||
// Don't check if lump exists just yet because the wads haven't been loaded!
|
||||
// Just do a basic range check here.
|
||||
if (pstartmap < 1 || pstartmap > NUMMAPS)
|
||||
|
|
|
@ -41,7 +41,7 @@ void D_SRB2Main(void);
|
|||
// Called by IO functions when input is detected.
|
||||
void D_PostEvent(const event_t *ev);
|
||||
#ifndef DOXYGEN
|
||||
void D_PostEvent_end(void); // delimiter for locking memory
|
||||
FUNCMATH void D_PostEvent_end(void); // delimiter for locking memory
|
||||
#endif
|
||||
|
||||
void D_ProcessEvents(void);
|
||||
|
|
437
src/d_net.c
437
src/d_net.c
|
@ -31,18 +31,18 @@
|
|||
//
|
||||
// NETWORKING
|
||||
//
|
||||
// gametic is the tic about to be (or currently being) run
|
||||
// server:
|
||||
// gametic is the tic about to (or currently being) run
|
||||
// Server:
|
||||
// maketic is the tic that hasn't had control made for it yet
|
||||
// nettics: is the tic for each node
|
||||
// firsttictosend: is the lowest value of nettics
|
||||
// client:
|
||||
// neededtic: is the tic needed by the client to run the game
|
||||
// firsttictosend: is used to optimize a condition
|
||||
// normally maketic >= gametic > 0
|
||||
// nettics is the tic for each node
|
||||
// firstticstosend is the lowest value of nettics
|
||||
// Client:
|
||||
// neededtic is the tic needed by the client to run the game
|
||||
// firstticstosend is used to optimize a condition
|
||||
// Normally maketic >= gametic > 0
|
||||
|
||||
#define FORCECLOSE 0x8000
|
||||
tic_t connectiontimeout = (15*TICRATE);
|
||||
tic_t connectiontimeout = (10*TICRATE);
|
||||
|
||||
/// \brief network packet
|
||||
doomcom_t *doomcom = NULL;
|
||||
|
@ -62,7 +62,7 @@ INT32 net_bandwidth;
|
|||
/// \brief max length per packet
|
||||
INT16 hardware_MAXPACKETLENGTH;
|
||||
|
||||
void (*I_NetGet)(void) = NULL;
|
||||
boolean (*I_NetGet)(void) = NULL;
|
||||
void (*I_NetSend)(void) = NULL;
|
||||
boolean (*I_NetCanSend)(void) = NULL;
|
||||
boolean (*I_NetCanGet)(void) = NULL;
|
||||
|
@ -129,9 +129,9 @@ boolean Net_GetNetStat(void)
|
|||
// -----------------------------------------------------------------
|
||||
// Some structs and functions for acknowledgement of packets
|
||||
// -----------------------------------------------------------------
|
||||
#define MAXACKPACKETS 96 // minimum number of nodes
|
||||
#define MAXACKPACKETS 96 // Minimum number of nodes (wat)
|
||||
#define MAXACKTOSEND 96
|
||||
#define URGENTFREESLOTENUM 10
|
||||
#define URGENTFREESLOTNUM 10
|
||||
#define ACKTOSENDTIMEOUT (TICRATE/11)
|
||||
|
||||
#ifndef NONET
|
||||
|
@ -139,10 +139,10 @@ typedef struct
|
|||
{
|
||||
UINT8 acknum;
|
||||
UINT8 nextacknum;
|
||||
UINT8 destinationnode;
|
||||
tic_t senttime;
|
||||
UINT16 length;
|
||||
UINT16 resentnum;
|
||||
UINT8 destinationnode; // The node to send the ack to
|
||||
tic_t senttime; // The time when the ack was sent
|
||||
UINT16 length; // The packet size
|
||||
UINT16 resentnum; // The number of times the ack has been resent
|
||||
union {
|
||||
SINT8 raw[MAXPACKETLENGTH];
|
||||
doomdata_t data;
|
||||
|
@ -152,11 +152,12 @@ typedef struct
|
|||
|
||||
typedef enum
|
||||
{
|
||||
CLOSE = 1, // flag is set when connection is closing
|
||||
NF_CLOSE = 1, // Flag is set when connection is closing
|
||||
NF_TIMEOUT = 2, // Flag is set when the node got a timeout
|
||||
} node_flags_t;
|
||||
|
||||
#ifndef NONET
|
||||
// table of packet that was not acknowleged can be resend (the sender window)
|
||||
// Table of packets that were not acknowleged can be resent (the sender window)
|
||||
static ackpak_t ackpak[MAXACKPACKETS];
|
||||
#endif
|
||||
|
||||
|
@ -212,11 +213,16 @@ FUNCMATH static INT32 cmpack(UINT8 a, UINT8 b)
|
|||
return d;
|
||||
}
|
||||
|
||||
// return a free acknum and copy netbuffer in the ackpak table
|
||||
/** Sets freeack to a free acknum and copies the netbuffer in the ackpak table
|
||||
*
|
||||
* \param freeack The address to store the free acknum at
|
||||
* \param lowtimer ???
|
||||
* \return True if a free acknum was found
|
||||
*/
|
||||
static boolean GetFreeAcknum(UINT8 *freeack, boolean lowtimer)
|
||||
{
|
||||
node_t *node = &nodes[doomcom->remotenode];
|
||||
INT32 i, numfreeslote = 0;
|
||||
INT32 i, numfreeslot = 0;
|
||||
|
||||
if (cmpack((UINT8)((node->remotefirstack + MAXACKTOSEND) % 256), node->nextacknum) < 0)
|
||||
{
|
||||
|
@ -227,10 +233,13 @@ static boolean GetFreeAcknum(UINT8 *freeack, boolean lowtimer)
|
|||
for (i = 0; i < MAXACKPACKETS; i++)
|
||||
if (!ackpak[i].acknum)
|
||||
{
|
||||
// for low priority packet, make sure let freeslotes so urgents packets can be sent
|
||||
numfreeslote++;
|
||||
if (netbuffer->packettype >= PT_CANFAIL && numfreeslote < URGENTFREESLOTENUM)
|
||||
continue;
|
||||
// For low priority packets, make sure to let freeslots so urgent packets can be sent
|
||||
if (netbuffer->packettype >= PT_CANFAIL)
|
||||
{
|
||||
numfreeslot++;
|
||||
if (numfreeslot <= URGENTFREESLOTNUM)
|
||||
continue;
|
||||
}
|
||||
|
||||
ackpak[i].acknum = node->nextacknum;
|
||||
ackpak[i].nextacknum = node->nextacknum;
|
||||
|
@ -241,7 +250,7 @@ static boolean GetFreeAcknum(UINT8 *freeack, boolean lowtimer)
|
|||
ackpak[i].length = doomcom->datalength;
|
||||
if (lowtimer)
|
||||
{
|
||||
// lowtime mean can't be sent now so try it soon as possible
|
||||
// Lowtime means can't be sent now so try it as soon as possible
|
||||
ackpak[i].senttime = 0;
|
||||
ackpak[i].resentnum = 1;
|
||||
}
|
||||
|
@ -254,7 +263,7 @@ static boolean GetFreeAcknum(UINT8 *freeack, boolean lowtimer)
|
|||
|
||||
*freeack = ackpak[i].acknum;
|
||||
|
||||
sendackpacket++; // for stat
|
||||
sendackpacket++; // For stat
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -266,14 +275,46 @@ static boolean GetFreeAcknum(UINT8 *freeack, boolean lowtimer)
|
|||
return false;
|
||||
}
|
||||
|
||||
// Get a ack to send in the queu of this node
|
||||
/** Counts how many acks are free
|
||||
*
|
||||
* \param urgent True if the type of the packet meant to
|
||||
* use an ack is lower than PT_CANFAIL
|
||||
* If for some reason you don't want use it
|
||||
* for any packet type in particular,
|
||||
* just set to false
|
||||
* \return The number of free acks
|
||||
*
|
||||
*/
|
||||
INT32 Net_GetFreeAcks(boolean urgent)
|
||||
{
|
||||
INT32 i, numfreeslot = 0;
|
||||
INT32 n = 0; // Number of free acks found
|
||||
|
||||
for (i = 0; i < MAXACKPACKETS; i++)
|
||||
if (!ackpak[i].acknum)
|
||||
{
|
||||
// For low priority packets, make sure to let freeslots so urgent packets can be sent
|
||||
if (!urgent)
|
||||
{
|
||||
numfreeslot++;
|
||||
if (numfreeslot <= URGENTFREESLOTNUM)
|
||||
continue;
|
||||
}
|
||||
|
||||
n++;
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
// Get a ack to send in the queue of this node
|
||||
static UINT8 GetAcktosend(INT32 node)
|
||||
{
|
||||
nodes[node].lasttimeacktosend_sent = I_GetTime();
|
||||
return nodes[node].firstacktosend;
|
||||
}
|
||||
|
||||
static void Removeack(INT32 i)
|
||||
static void RemoveAck(INT32 i)
|
||||
{
|
||||
INT32 node = ackpak[i].destinationnode;
|
||||
#ifndef NEWPING
|
||||
|
@ -290,31 +331,31 @@ static void Removeack(INT32 i)
|
|||
DEBFILE(va("Remove ack %d\n",ackpak[i].acknum));
|
||||
#endif
|
||||
ackpak[i].acknum = 0;
|
||||
if (nodes[node].flags & CLOSE)
|
||||
if (nodes[node].flags & NF_CLOSE)
|
||||
Net_CloseConnection(node);
|
||||
}
|
||||
|
||||
// we have got a packet proceed the ack request and ack return
|
||||
// We have got a packet, proceed the ack request and ack return
|
||||
static boolean Processackpak(void)
|
||||
{
|
||||
INT32 i;
|
||||
boolean goodpacket = true;
|
||||
node_t *node = &nodes[doomcom->remotenode];
|
||||
|
||||
// received an ack return, so remove the ack in the list
|
||||
// Received an ack return, so remove the ack in the list
|
||||
if (netbuffer->ackreturn && cmpack(node->remotefirstack, netbuffer->ackreturn) < 0)
|
||||
{
|
||||
node->remotefirstack = netbuffer->ackreturn;
|
||||
// search the ackbuffer and free it
|
||||
// Search the ackbuffer and free it
|
||||
for (i = 0; i < MAXACKPACKETS; i++)
|
||||
if (ackpak[i].acknum && ackpak[i].destinationnode == node - nodes
|
||||
&& cmpack(ackpak[i].acknum, netbuffer->ackreturn) <= 0)
|
||||
{
|
||||
Removeack(i);
|
||||
RemoveAck(i);
|
||||
}
|
||||
}
|
||||
|
||||
// received a packet with ack, queue it to send the ack back
|
||||
// Received a packet with ack, queue it to send the ack back
|
||||
if (netbuffer->ack)
|
||||
{
|
||||
UINT8 ack = netbuffer->ack;
|
||||
|
@ -323,23 +364,23 @@ static boolean Processackpak(void)
|
|||
{
|
||||
DEBFILE(va("Discard(1) ack %d (duplicated)\n", ack));
|
||||
duppacket++;
|
||||
goodpacket = false; // discard packet (duplicate)
|
||||
goodpacket = false; // Discard packet (duplicate)
|
||||
}
|
||||
else
|
||||
{
|
||||
// check if it is not already in the queue
|
||||
// Check if it is not already in the queue
|
||||
for (i = node->acktosend_tail; i != node->acktosend_head; i = (i+1) % MAXACKTOSEND)
|
||||
if (node->acktosend[i] == ack)
|
||||
{
|
||||
DEBFILE(va("Discard(2) ack %d (duplicated)\n", ack));
|
||||
duppacket++;
|
||||
goodpacket = false; // discard packet (duplicate)
|
||||
goodpacket = false; // Discard packet (duplicate)
|
||||
break;
|
||||
}
|
||||
if (goodpacket)
|
||||
{
|
||||
// is a good packet so increment the acknowledge number,
|
||||
// then search for a "hole" in the queue
|
||||
// Is a good packet so increment the acknowledge number,
|
||||
// Then search for a "hole" in the queue
|
||||
UINT8 nextfirstack = (UINT8)(node->firstacktosend + 1);
|
||||
if (!nextfirstack)
|
||||
nextfirstack = 1;
|
||||
|
@ -383,10 +424,10 @@ static boolean Processackpak(void)
|
|||
}
|
||||
}
|
||||
}
|
||||
else // out of order packet
|
||||
else // Out of order packet
|
||||
{
|
||||
// don't increment firsacktosend, put it in asktosend queue
|
||||
// will be incremented when the nextfirstack comes (code above)
|
||||
// Don't increment firsacktosend, put it in asktosend queue
|
||||
// Will be incremented when the nextfirstack comes (code above)
|
||||
UINT8 newhead = (UINT8)((node->acktosend_head+1) % MAXACKTOSEND);
|
||||
DEBFILE(va("out of order packet (%d expected)\n", nextfirstack));
|
||||
if (newhead != node->acktosend_tail)
|
||||
|
@ -394,8 +435,8 @@ static boolean Processackpak(void)
|
|||
node->acktosend[node->acktosend_head] = ack;
|
||||
node->acktosend_head = newhead;
|
||||
}
|
||||
else // buffer full discard packet, sender will resend it
|
||||
{ // we can admit the packet but we will not detect the duplication after :(
|
||||
else // Buffer full discard packet, sender will resend it
|
||||
{ // We can admit the packet but we will not detect the duplication after :(
|
||||
DEBFILE("no more freeackret\n");
|
||||
goodpacket = false;
|
||||
}
|
||||
|
@ -430,25 +471,29 @@ static void GotAcks(void)
|
|||
if (ackpak[i].acknum && ackpak[i].destinationnode == doomcom->remotenode)
|
||||
{
|
||||
if (ackpak[i].acknum == netbuffer->u.textcmd[j])
|
||||
Removeack(i);
|
||||
else
|
||||
// nextacknum is first equal to acknum, then when receiving bigger ack
|
||||
// there is big chance the packet is lost
|
||||
// when resent, nextacknum = nodes[node].nextacknum
|
||||
// will redo the same but with different value
|
||||
if (cmpack(ackpak[i].nextacknum, netbuffer->u.textcmd[j]) <= 0
|
||||
&& ackpak[i].senttime > 0)
|
||||
{
|
||||
ackpak[i].senttime--; // hurry up
|
||||
}
|
||||
RemoveAck(i);
|
||||
// nextacknum is first equal to acknum, then when receiving bigger ack
|
||||
// there is big chance the packet is lost
|
||||
// When resent, nextacknum = nodes[node].nextacknum
|
||||
// will redo the same but with different value
|
||||
else if (cmpack(ackpak[i].nextacknum, netbuffer->u.textcmd[j]) <= 0
|
||||
&& ackpak[i].senttime > 0)
|
||||
{
|
||||
ackpak[i].senttime--; // hurry up
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline void Net_ConnectionTimeout(INT32 node)
|
||||
void Net_ConnectionTimeout(INT32 node)
|
||||
{
|
||||
// send a very special packet to self (hack the reboundstore queue)
|
||||
// main code will handle it
|
||||
// Don't timeout several times
|
||||
if (nodes[node].flags & NF_TIMEOUT)
|
||||
return;
|
||||
nodes[node].flags |= NF_TIMEOUT;
|
||||
|
||||
// Send a very special packet to self (hack the reboundstore queue)
|
||||
// Main code will handle it
|
||||
reboundstore[rebound_head].packettype = PT_NODETIMEOUT;
|
||||
reboundstore[rebound_head].ack = 0;
|
||||
reboundstore[rebound_head].ackreturn = 0;
|
||||
|
@ -456,12 +501,12 @@ static inline void Net_ConnectionTimeout(INT32 node)
|
|||
reboundsize[rebound_head] = (INT16)(BASEPACKETSIZE + 1);
|
||||
rebound_head = (rebound_head+1) % MAXREBOUND;
|
||||
|
||||
// do not redo it quickly (if we do not close connection it is
|
||||
// Do not redo it quickly (if we do not close connection it is
|
||||
// for a good reason!)
|
||||
nodes[node].lasttimepacketreceived = I_GetTime();
|
||||
}
|
||||
|
||||
// resend the data if needed
|
||||
// Resend the data if needed
|
||||
void Net_AckTicker(void)
|
||||
{
|
||||
#ifndef NONET
|
||||
|
@ -477,7 +522,7 @@ void Net_AckTicker(void)
|
|||
if (ackpak[i].acknum && ackpak[i].senttime + node->timeout < I_GetTime())
|
||||
#endif
|
||||
{
|
||||
if (ackpak[i].resentnum > 10 && (node->flags & CLOSE))
|
||||
if (ackpak[i].resentnum > 10 && (node->flags & NF_CLOSE))
|
||||
{
|
||||
DEBFILE(va("ack %d sent 10 times so connection is supposed lost: node %d\n",
|
||||
i, nodei));
|
||||
|
@ -497,7 +542,7 @@ void Net_AckTicker(void)
|
|||
ackpak[i].senttime = I_GetTime();
|
||||
ackpak[i].resentnum++;
|
||||
ackpak[i].nextacknum = node->nextacknum;
|
||||
retransmit++; // for stat
|
||||
retransmit++; // For stat
|
||||
HSendPacket((INT32)(node - nodes), false, ackpak[i].acknum,
|
||||
(size_t)(ackpak[i].length - BASEPACKETSIZE));
|
||||
}
|
||||
|
@ -505,15 +550,15 @@ void Net_AckTicker(void)
|
|||
|
||||
for (i = 1; i < MAXNETNODES; i++)
|
||||
{
|
||||
// this is something like node open flag
|
||||
// This is something like node open flag
|
||||
if (nodes[i].firstacktosend)
|
||||
{
|
||||
// we haven't sent a packet for a long time
|
||||
// acknowledge packet if needed
|
||||
// We haven't sent a packet for a long time
|
||||
// Acknowledge packet if needed
|
||||
if (nodes[i].lasttimeacktosend_sent + ACKTOSENDTIMEOUT < I_GetTime())
|
||||
Net_SendAcks(i);
|
||||
|
||||
if (!(nodes[i].flags & CLOSE)
|
||||
if (!(nodes[i].flags & NF_CLOSE)
|
||||
&& nodes[i].lasttimepacketreceived + connectiontimeout < I_GetTime())
|
||||
{
|
||||
Net_ConnectionTimeout(i);
|
||||
|
@ -523,9 +568,9 @@ void Net_AckTicker(void)
|
|||
#endif
|
||||
}
|
||||
|
||||
// remove last packet received ack before resending the ackret
|
||||
// Remove last packet received ack before resending the ackreturn
|
||||
// (the higher layer doesn't have room, or something else ....)
|
||||
void Net_UnAcknowledgPacket(INT32 node)
|
||||
void Net_UnAcknowledgePacket(INT32 node)
|
||||
{
|
||||
#ifdef NONET
|
||||
(void)node;
|
||||
|
@ -564,20 +609,29 @@ void Net_UnAcknowledgPacket(INT32 node)
|
|||
#endif
|
||||
}
|
||||
|
||||
boolean Net_AllAckReceived(void)
|
||||
{
|
||||
#ifndef NONET
|
||||
/** Checks if all acks have been received
|
||||
*
|
||||
* \return True if all acks have been received
|
||||
*
|
||||
*/
|
||||
static boolean Net_AllAcksReceived(void)
|
||||
{
|
||||
INT32 i;
|
||||
|
||||
for (i = 0; i < MAXACKPACKETS; i++)
|
||||
if (ackpak[i].acknum)
|
||||
return false;
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
// wait for all ackreturns with timeout in seconds
|
||||
/** Waits for all ackreturns
|
||||
*
|
||||
* \param timeout Timeout in seconds
|
||||
*
|
||||
*/
|
||||
void Net_WaitAllAckReceived(UINT32 timeout)
|
||||
{
|
||||
#ifdef NONET
|
||||
|
@ -587,7 +641,7 @@ void Net_WaitAllAckReceived(UINT32 timeout)
|
|||
timeout = tictac + timeout*NEWTICRATE;
|
||||
|
||||
HGetPacket();
|
||||
while (timeout > I_GetTime() && !Net_AllAckReceived())
|
||||
while (timeout > I_GetTime() && !Net_AllAcksReceived())
|
||||
{
|
||||
while (tictac == I_GetTime())
|
||||
I_Sleep();
|
||||
|
@ -598,18 +652,18 @@ void Net_WaitAllAckReceived(UINT32 timeout)
|
|||
#endif
|
||||
}
|
||||
|
||||
static void InitNode(INT32 node)
|
||||
static void InitNode(node_t *node)
|
||||
{
|
||||
nodes[node].acktosend_head = nodes[node].acktosend_tail = 0;
|
||||
node->acktosend_head = node->acktosend_tail = 0;
|
||||
#ifndef NEWPING
|
||||
nodes[node].ping = PINGDEFAULT;
|
||||
nodes[node].varping = VARPINGDEFAULT;
|
||||
nodes[node].timeout = TIMEOUT(nodes[node].ping,nodes[node].varping);
|
||||
node->ping = PINGDEFAULT;
|
||||
node->varping = VARPINGDEFAULT;
|
||||
node->timeout = TIMEOUT(node->ping, node->varping);
|
||||
#endif
|
||||
nodes[node].firstacktosend = 0;
|
||||
nodes[node].nextacknum = 1;
|
||||
nodes[node].remotefirstack = 0;
|
||||
nodes[node].flags = 0;
|
||||
node->firstacktosend = 0;
|
||||
node->nextacknum = 1;
|
||||
node->remotefirstack = 0;
|
||||
node->flags = 0;
|
||||
}
|
||||
|
||||
static void InitAck(void)
|
||||
|
@ -622,9 +676,14 @@ static void InitAck(void)
|
|||
#endif
|
||||
|
||||
for (i = 0; i < MAXNETNODES; i++)
|
||||
InitNode(i);
|
||||
InitNode(&nodes[i]);
|
||||
}
|
||||
|
||||
/** Removes all acks of a given packet type
|
||||
*
|
||||
* \param packettype The packet type to forget
|
||||
*
|
||||
*/
|
||||
void Net_AbortPacketType(UINT8 packettype)
|
||||
{
|
||||
#ifdef NONET
|
||||
|
@ -652,12 +711,25 @@ void Net_CloseConnection(INT32 node)
|
|||
#else
|
||||
INT32 i;
|
||||
boolean forceclose = (node & FORCECLOSE) != 0;
|
||||
|
||||
if (node == -1)
|
||||
{
|
||||
DEBFILE(M_GetText("Net_CloseConnection: node -1 detected!\n"));
|
||||
return; // nope, just ignore it
|
||||
}
|
||||
|
||||
node &= ~FORCECLOSE;
|
||||
|
||||
if (!node)
|
||||
return;
|
||||
|
||||
nodes[node].flags |= CLOSE;
|
||||
if (node < 0 || node >= MAXNETNODES) // prevent invalid nodes from crashing the game
|
||||
{
|
||||
DEBFILE(va(M_GetText("Net_CloseConnection: invalid node %d detected!\n"), node));
|
||||
return;
|
||||
}
|
||||
|
||||
nodes[node].flags |= NF_CLOSE;
|
||||
|
||||
// try to Send ack back (two army problem)
|
||||
if (GetAcktosend(node))
|
||||
|
@ -676,8 +748,8 @@ void Net_CloseConnection(INT32 node)
|
|||
ackpak[i].acknum = 0;
|
||||
}
|
||||
|
||||
InitNode(node);
|
||||
AbortSendFiles(node);
|
||||
InitNode(&nodes[node]);
|
||||
SV_AbortSendFiles(node);
|
||||
I_NetFreeNodenum(node);
|
||||
#endif
|
||||
}
|
||||
|
@ -729,9 +801,15 @@ static void fprintfstring(char *s, size_t len)
|
|||
}
|
||||
if (mode)
|
||||
fprintf(debugfile, "]");
|
||||
}
|
||||
|
||||
static void fprintfstringnewline(char *s, size_t len)
|
||||
{
|
||||
fprintfstring(s, len);
|
||||
fprintf(debugfile, "\n");
|
||||
}
|
||||
|
||||
/// \warning Keep this up-to-date if you add/remove/rename packet types
|
||||
static const char *packettypename[NUMPACKETTYPE] =
|
||||
{
|
||||
"NOTHING",
|
||||
|
@ -749,15 +827,22 @@ static const char *packettypename[NUMPACKETTYPE] =
|
|||
|
||||
"ASKINFO",
|
||||
"SERVERINFO",
|
||||
"PLAYERINFO",
|
||||
"REQUESTFILE",
|
||||
"ASKINFOVIAMS",
|
||||
|
||||
"PLAYERCONFIGS",
|
||||
"RESYNCHEND",
|
||||
"RESYNCHGET",
|
||||
|
||||
"FILEFRAGMENT",
|
||||
"TEXTCMD",
|
||||
"TEXTCMD2",
|
||||
"CLIENTJOIN",
|
||||
"NODETIMEOUT",
|
||||
"RESYNCHING",
|
||||
#ifdef NEWPING
|
||||
"PING"
|
||||
#endif
|
||||
};
|
||||
|
||||
static void DebugPrintpacket(const char *header)
|
||||
|
@ -770,20 +855,31 @@ static void DebugPrintpacket(const char *header)
|
|||
{
|
||||
case PT_ASKINFO:
|
||||
case PT_ASKINFOVIAMS:
|
||||
fprintf(debugfile, " time %u\n", (tic_t)LONG(netbuffer->u.askinfo.time) );
|
||||
fprintf(debugfile, " time %u\n", (tic_t)LONG(netbuffer->u.askinfo.time));
|
||||
break;
|
||||
case PT_CLIENTJOIN:
|
||||
fprintf(debugfile, " number %d mode %d\n", netbuffer->u.clientcfg.localplayers,
|
||||
netbuffer->u.clientcfg.mode);
|
||||
break;
|
||||
case PT_SERVERTICS:
|
||||
{
|
||||
servertics_pak *serverpak = &netbuffer->u.serverpak;
|
||||
UINT8 *cmd = (UINT8 *)(&serverpak->cmds[serverpak->numslots * serverpak->numtics]);
|
||||
size_t ntxtcmd = &((UINT8 *)netbuffer)[doomcom->datalength] - cmd;
|
||||
|
||||
fprintf(debugfile, " firsttic %u ply %d tics %d ntxtcmd %s\n ",
|
||||
(UINT32)ExpandTics(netbuffer->u.serverpak.starttic), netbuffer->u.serverpak.numslots,
|
||||
netbuffer->u.serverpak.numtics,
|
||||
sizeu1((size_t)(&((UINT8 *)netbuffer)[doomcom->datalength] - (UINT8 *)&netbuffer->u.serverpak.cmds[netbuffer->u.serverpak.numslots*netbuffer->u.serverpak.numtics])));
|
||||
fprintfstring((char *)&netbuffer->u.serverpak.cmds[netbuffer->u.serverpak.numslots*netbuffer->u.serverpak.numtics],(size_t)(
|
||||
&((UINT8 *)netbuffer)[doomcom->datalength] - (UINT8 *)&netbuffer->u.serverpak.cmds[netbuffer->u.serverpak.numslots*netbuffer->u.serverpak.numtics]));
|
||||
(UINT32)ExpandTics(serverpak->starttic), serverpak->numslots, serverpak->numtics, sizeu1(ntxtcmd));
|
||||
/// \todo Display more readable information about net commands
|
||||
fprintfstringnewline((char *)cmd, ntxtcmd);
|
||||
/*fprintfstring((char *)cmd, 3);
|
||||
if (ntxtcmd > 4)
|
||||
{
|
||||
fprintf(debugfile, "[%s]", netxcmdnames[*((cmd) + 3) - 1]);
|
||||
fprintfstring(((char *)cmd) + 4, ntxtcmd - 4);
|
||||
}
|
||||
fprintf(debugfile, "\n");*/
|
||||
break;
|
||||
}
|
||||
case PT_CLIENTCMD:
|
||||
case PT_CLIENT2CMD:
|
||||
case PT_CLIENTMIS:
|
||||
|
@ -797,7 +893,8 @@ static void DebugPrintpacket(const char *header)
|
|||
case PT_TEXTCMD:
|
||||
case PT_TEXTCMD2:
|
||||
fprintf(debugfile, " length %d\n ", netbuffer->u.textcmd[0]);
|
||||
fprintfstring((char *)netbuffer->u.textcmd+1, netbuffer->u.textcmd[0]);
|
||||
fprintf(debugfile, "[%s]", netxcmdnames[netbuffer->u.textcmd[1] - 1]);
|
||||
fprintfstringnewline((char *)netbuffer->u.textcmd + 2, netbuffer->u.textcmd[0] - 1);
|
||||
break;
|
||||
case PT_SERVERCFG:
|
||||
fprintf(debugfile, " playerslots %d clientnode %d serverplayer %d "
|
||||
|
@ -813,7 +910,7 @@ static void DebugPrintpacket(const char *header)
|
|||
netbuffer->u.serverinfo.maxplayer, netbuffer->u.serverinfo.mapname,
|
||||
netbuffer->u.serverinfo.fileneedednum,
|
||||
(UINT32)LONG(netbuffer->u.serverinfo.time));
|
||||
fprintfstring((char *)netbuffer->u.serverinfo.fileneeded,
|
||||
fprintfstringnewline((char *)netbuffer->u.serverinfo.fileneeded,
|
||||
(UINT8)((UINT8 *)netbuffer + doomcom->datalength
|
||||
- (UINT8 *)netbuffer->u.serverinfo.fileneeded));
|
||||
break;
|
||||
|
@ -827,20 +924,102 @@ static void DebugPrintpacket(const char *header)
|
|||
break;
|
||||
case PT_REQUESTFILE:
|
||||
default: // write as a raw packet
|
||||
fprintfstring((char *)netbuffer->u.textcmd,
|
||||
fprintfstringnewline((char *)netbuffer->u.textcmd,
|
||||
(UINT8)((UINT8 *)netbuffer + doomcom->datalength - (UINT8 *)netbuffer->u.textcmd));
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef PACKETDROP
|
||||
static INT32 packetdropquantity[NUMPACKETTYPE] = {0};
|
||||
static INT32 packetdroprate = 0;
|
||||
|
||||
void Command_Drop(void)
|
||||
{
|
||||
INT32 packetquantity;
|
||||
const char *packetname;
|
||||
size_t i;
|
||||
|
||||
if (COM_Argc() < 2)
|
||||
{
|
||||
CONS_Printf("drop <packettype> [quantity]: drop packets\n"
|
||||
"drop reset: cancel all packet drops\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(stricmp(COM_Argv(1), "reset") && stricmp(COM_Argv(1), "cancel") && stricmp(COM_Argv(1), "stop")))
|
||||
{
|
||||
memset(packetdropquantity, 0, sizeof(packetdropquantity));
|
||||
return;
|
||||
}
|
||||
|
||||
if (COM_Argc() >= 3)
|
||||
{
|
||||
packetquantity = atoi(COM_Argv(2));
|
||||
if (packetquantity <= 0 && COM_Argv(2)[0] != '0')
|
||||
{
|
||||
CONS_Printf("Invalid quantity\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
packetquantity = -1;
|
||||
|
||||
packetname = COM_Argv(1);
|
||||
|
||||
if (!(stricmp(packetname, "all") && stricmp(packetname, "any")))
|
||||
for (i = 0; i < NUMPACKETTYPE; i++)
|
||||
packetdropquantity[i] = packetquantity;
|
||||
else
|
||||
{
|
||||
for (i = 0; i < NUMPACKETTYPE; i++)
|
||||
if (!stricmp(packetname, packettypename[i]))
|
||||
{
|
||||
packetdropquantity[i] = packetquantity;
|
||||
return;
|
||||
}
|
||||
|
||||
CONS_Printf("Unknown packet name\n");
|
||||
}
|
||||
}
|
||||
|
||||
void Command_Droprate(void)
|
||||
{
|
||||
INT32 droprate;
|
||||
|
||||
if (COM_Argc() < 2)
|
||||
{
|
||||
CONS_Printf("Packet drop rate: %d%%\n", packetdroprate);
|
||||
return;
|
||||
}
|
||||
|
||||
droprate = atoi(COM_Argv(1));
|
||||
if ((droprate <= 0 && COM_Argv(1)[0] != '0') || droprate > 100)
|
||||
{
|
||||
CONS_Printf("Packet drop rate must be between 0 and 100!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
packetdroprate = droprate;
|
||||
}
|
||||
|
||||
#ifndef NONET
|
||||
static boolean ShouldDropPacket(void)
|
||||
{
|
||||
return (packetdropquantity[netbuffer->packettype])
|
||||
|| (packetdroprate != 0 && rand() < (RAND_MAX * (packetdroprate / 100.f))) || packetdroprate == 100;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
//
|
||||
// HSendPacket
|
||||
//
|
||||
boolean HSendPacket(INT32 node, boolean reliable, UINT8 acknum, size_t packetlength)
|
||||
{
|
||||
doomcom->datalength = (INT16)(packetlength + BASEPACKETSIZE);
|
||||
if (node == 0) // packet is to go back to us
|
||||
if (node == 0) // Packet is to go back to us
|
||||
{
|
||||
if ((rebound_head+1) % MAXREBOUND == rebound_tail)
|
||||
{
|
||||
|
@ -871,7 +1050,7 @@ boolean HSendPacket(INT32 node, boolean reliable, UINT8 acknum, size_t packetlen
|
|||
(void)reliable;
|
||||
(void)acknum;
|
||||
#else
|
||||
// do this before GetFreeAcknum because this function backup
|
||||
// do this before GetFreeAcknum because this function backups
|
||||
// the current packet
|
||||
doomcom->remotenode = (INT16)node;
|
||||
if (doomcom->datalength <= 0)
|
||||
|
@ -884,7 +1063,7 @@ boolean HSendPacket(INT32 node, boolean reliable, UINT8 acknum, size_t packetlen
|
|||
return false;
|
||||
}
|
||||
|
||||
if (node < MAXNETNODES) // can be a broadcast
|
||||
if (node < MAXNETNODES) // Can be a broadcast
|
||||
netbuffer->ackreturn = GetAcktosend(node);
|
||||
else
|
||||
netbuffer->ackreturn = 0;
|
||||
|
@ -905,20 +1084,30 @@ boolean HSendPacket(INT32 node, boolean reliable, UINT8 acknum, size_t packetlen
|
|||
netbuffer->ack = acknum;
|
||||
|
||||
netbuffer->checksum = NetbufferChecksum();
|
||||
sendbytes += packetheaderlength + doomcom->datalength; // for stat
|
||||
sendbytes += packetheaderlength + doomcom->datalength; // For stat
|
||||
|
||||
// simulate internet :)
|
||||
if (true || rand()<(INT32)RAND_MAX/5)
|
||||
#ifdef PACKETDROP
|
||||
// Simulate internet :)
|
||||
//if (rand() >= (INT32)(RAND_MAX * (PACKETLOSSRATE / 100.f)))
|
||||
if (!ShouldDropPacket())
|
||||
{
|
||||
#endif
|
||||
#ifdef DEBUGFILE
|
||||
if (debugfile)
|
||||
DebugPrintpacket("SEND");
|
||||
DebugPrintpacket("SENT");
|
||||
#endif
|
||||
I_NetSend();
|
||||
#ifdef PACKETDROP
|
||||
}
|
||||
else
|
||||
{
|
||||
if (packetdropquantity[netbuffer->packettype] > 0)
|
||||
packetdropquantity[netbuffer->packettype]--;
|
||||
#ifdef DEBUGFILE
|
||||
else if (debugfile)
|
||||
DebugPrintpacket("NOTSEND");
|
||||
if (debugfile)
|
||||
DebugPrintpacket("NOT SENT");
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // ndef NONET
|
||||
|
@ -933,7 +1122,9 @@ boolean HSendPacket(INT32 node, boolean reliable, UINT8 acknum, size_t packetlen
|
|||
//
|
||||
boolean HGetPacket(void)
|
||||
{
|
||||
// get a packet from self
|
||||
//boolean nodejustjoined;
|
||||
|
||||
// Get a packet from self
|
||||
if (rebound_tail != rebound_head)
|
||||
{
|
||||
M_Memcpy(netbuffer, &reboundstore[rebound_tail], reboundsize[rebound_tail]);
|
||||
|
@ -958,16 +1149,17 @@ boolean HGetPacket(void)
|
|||
|
||||
while(true)
|
||||
{
|
||||
//nodejustjoined = I_NetGet();
|
||||
I_NetGet();
|
||||
|
||||
if (doomcom->remotenode == -1)
|
||||
if (doomcom->remotenode == -1) // No packet received
|
||||
return false;
|
||||
|
||||
getbytes += packetheaderlength + doomcom->datalength; // for stat
|
||||
getbytes += packetheaderlength + doomcom->datalength; // For stat
|
||||
|
||||
if (doomcom->remotenode >= MAXNETNODES)
|
||||
{
|
||||
DEBFILE(va("receive packet from node %d !\n", doomcom->remotenode));
|
||||
DEBFILE(va("Received packet from node %d!\n", doomcom->remotenode));
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -976,6 +1168,7 @@ boolean HGetPacket(void)
|
|||
if (netbuffer->checksum != NetbufferChecksum())
|
||||
{
|
||||
DEBFILE("Bad packet checksum\n");
|
||||
//Net_CloseConnection(nodejustjoined ? (doomcom->remotenode | FORCECLOSE) : doomcom->remotenode);
|
||||
Net_CloseConnection(doomcom->remotenode);
|
||||
continue;
|
||||
}
|
||||
|
@ -985,11 +1178,26 @@ boolean HGetPacket(void)
|
|||
DebugPrintpacket("GET");
|
||||
#endif
|
||||
|
||||
// proceed the ack and ackreturn field
|
||||
/*// If a new node sends an unexpected packet, just ignore it
|
||||
if (nodejustjoined && server
|
||||
&& !(netbuffer->packettype == PT_ASKINFO
|
||||
|| netbuffer->packettype == PT_SERVERINFO
|
||||
|| netbuffer->packettype == PT_PLAYERINFO
|
||||
|| netbuffer->packettype == PT_REQUESTFILE
|
||||
|| netbuffer->packettype == PT_ASKINFOVIAMS
|
||||
|| netbuffer->packettype == PT_CLIENTJOIN))
|
||||
{
|
||||
DEBFILE(va("New node sent an unexpected %s packet\n", packettypename[netbuffer->packettype]));
|
||||
//CONS_Alert(CONS_NOTICE, "New node sent an unexpected %s packet\n", packettypename[netbuffer->packettype]);
|
||||
Net_CloseConnection(doomcom->remotenode | FORCECLOSE);
|
||||
continue;
|
||||
}*/
|
||||
|
||||
// Proceed the ack and ackreturn field
|
||||
if (!Processackpak())
|
||||
continue; // discarded (duplicated)
|
||||
|
||||
// a packet with just ackreturn
|
||||
// A packet with just ackreturn
|
||||
if (netbuffer->packettype == PT_NOTHING)
|
||||
{
|
||||
GotAcks();
|
||||
|
@ -1002,9 +1210,10 @@ boolean HGetPacket(void)
|
|||
return true;
|
||||
}
|
||||
|
||||
static void Internal_Get(void)
|
||||
static boolean Internal_Get(void)
|
||||
{
|
||||
doomcom->remotenode = -1;
|
||||
return false;
|
||||
}
|
||||
|
||||
FUNCNORETURN static ATTRNORETURN void Internal_Send(void)
|
||||
|
@ -1089,7 +1298,7 @@ boolean D_CheckNetGame(void)
|
|||
|
||||
if (netgame)
|
||||
ret = true;
|
||||
if (!server && netgame)
|
||||
if (client && netgame)
|
||||
netgame = false;
|
||||
server = true; // WTF? server always true???
|
||||
// no! The deault mode is server. Client is set elsewhere
|
||||
|
@ -1230,4 +1439,6 @@ void D_CloseConnection(void)
|
|||
netgame = false;
|
||||
addedtogame = false;
|
||||
}
|
||||
|
||||
D_ResetTiccmds();
|
||||
}
|
||||
|
|
20
src/d_net.h
20
src/d_net.h
|
@ -18,10 +18,10 @@
|
|||
#ifndef __D_NET__
|
||||
#define __D_NET__
|
||||
|
||||
// Max computers in a game.
|
||||
// Max computers in a game
|
||||
#define MAXNETNODES 32
|
||||
#define BROADCASTADDR MAXNETNODES
|
||||
#define MAXSPLITSCREENPLAYERS 2 // max number of players on a single computer
|
||||
#define MAXSPLITSCREENPLAYERS 2 // Max number of players on a single computer
|
||||
|
||||
#define STATLENGTH (TICRATE*2)
|
||||
|
||||
|
@ -32,17 +32,17 @@ extern float lostpercent, duppercent, gamelostpercent;
|
|||
extern INT32 packetheaderlength;
|
||||
boolean Net_GetNetStat(void);
|
||||
extern INT32 getbytes;
|
||||
extern INT64 sendbytes; // realtime updated
|
||||
extern INT64 sendbytes; // Realtime updated
|
||||
|
||||
extern SINT8 nodetoplayer[MAXNETNODES];
|
||||
extern SINT8 nodetoplayer2[MAXNETNODES]; // say the numplayer for this node if any (splitscreen)
|
||||
extern UINT8 playerpernode[MAXNETNODES]; // used specialy for scplitscreen
|
||||
extern boolean nodeingame[MAXNETNODES]; // set false as nodes leave game
|
||||
extern SINT8 nodetoplayer2[MAXNETNODES]; // Say the numplayer for this node if any (splitscreen)
|
||||
extern UINT8 playerpernode[MAXNETNODES]; // Used specially for splitscreen
|
||||
extern boolean nodeingame[MAXNETNODES]; // Set false as nodes leave game
|
||||
|
||||
INT32 Net_GetFreeAcks(boolean urgent);
|
||||
void Net_AckTicker(void);
|
||||
boolean Net_AllAckReceived(void);
|
||||
|
||||
// if reliable return true if packet sent, 0 else
|
||||
// If reliable return true if packet sent, 0 else
|
||||
boolean HSendPacket(INT32 node, boolean reliable, UINT8 acknum,
|
||||
size_t packetlength);
|
||||
boolean HGetPacket(void);
|
||||
|
@ -52,9 +52,11 @@ void D_SaveBan(void);
|
|||
#endif
|
||||
boolean D_CheckNetGame(void);
|
||||
void D_CloseConnection(void);
|
||||
void Net_UnAcknowledgPacket(INT32 node);
|
||||
void Net_UnAcknowledgePacket(INT32 node);
|
||||
void Net_CloseConnection(INT32 node);
|
||||
void Net_ConnectionTimeout(INT32 node);
|
||||
void Net_AbortPacketType(UINT8 packettype);
|
||||
void Net_SendAcks(INT32 node);
|
||||
void Net_WaitAllAckReceived(UINT32 timeout);
|
||||
|
||||
#endif
|
||||
|
|
128
src/d_netcmd.c
128
src/d_netcmd.c
|
@ -82,6 +82,7 @@ static void AutoBalance_OnChange(void);
|
|||
static void TeamScramble_OnChange(void);
|
||||
|
||||
static void NetTimeout_OnChange(void);
|
||||
static void JoinTimeout_OnChange(void);
|
||||
|
||||
static void Ringslinger_OnChange(void);
|
||||
static void Gravity_OnChange(void);
|
||||
|
@ -340,7 +341,9 @@ consvar_t cv_killingdead = {"killingdead", "Off", CV_NETVAR, CV_OnOff, NULL, 0,
|
|||
|
||||
consvar_t cv_netstat = {"netstat", "Off", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; // show bandwidth statistics
|
||||
static CV_PossibleValue_t nettimeout_cons_t[] = {{TICRATE/7, "MIN"}, {60*TICRATE, "MAX"}, {0, NULL}};
|
||||
consvar_t cv_nettimeout = {"nettimeout", "525", CV_CALL|CV_SAVE, nettimeout_cons_t, NetTimeout_OnChange, 0, NULL, NULL, 0, 0, NULL};
|
||||
consvar_t cv_nettimeout = {"nettimeout", "350", CV_CALL|CV_SAVE, nettimeout_cons_t, NetTimeout_OnChange, 0, NULL, NULL, 0, 0, NULL};
|
||||
static CV_PossibleValue_t jointimeout_cons_t[] = {{5*TICRATE, "MIN"}, {60*TICRATE, "MAX"}, {0, NULL}};
|
||||
consvar_t cv_jointimeout = {"jointimeout", "350", CV_CALL|CV_SAVE, jointimeout_cons_t, JoinTimeout_OnChange, 0, NULL, NULL, 0, 0, NULL};
|
||||
#ifdef NEWPING
|
||||
consvar_t cv_maxping = {"maxping", "0", CV_SAVE, CV_Unsigned, NULL, 0, NULL, NULL, 0, 0, NULL};
|
||||
#endif
|
||||
|
@ -365,6 +368,35 @@ boolean splitscreen = false;
|
|||
boolean circuitmap = false;
|
||||
INT32 adminplayer = -1;
|
||||
|
||||
/// \warning Keep this up-to-date if you add/remove/rename net text commands
|
||||
const char *netxcmdnames[MAXNETXCMD - 1] =
|
||||
{
|
||||
"NAMEANDCOLOR",
|
||||
"WEAPONPREF",
|
||||
"KICK",
|
||||
"NETVAR",
|
||||
"SAY",
|
||||
"MAP",
|
||||
"EXITLEVEL",
|
||||
"ADDFILE",
|
||||
"PAUSE",
|
||||
"ADDPLAYER",
|
||||
"TEAMCHANGE",
|
||||
"CLEARSCORES",
|
||||
"LOGIN",
|
||||
"VERIFIED",
|
||||
"RANDOMSEED",
|
||||
"RUNSOC",
|
||||
"REQADDFILE",
|
||||
"DELFILE",
|
||||
"SETMOTD",
|
||||
"SUICIDE",
|
||||
#ifdef HAVE_BLUA
|
||||
"LUACMD",
|
||||
"LUAVAR"
|
||||
#endif
|
||||
};
|
||||
|
||||
// =========================================================================
|
||||
// SERVER STARTUP
|
||||
// =========================================================================
|
||||
|
@ -517,9 +549,12 @@ void D_RegisterServerCommands(void)
|
|||
// d_clisrv
|
||||
CV_RegisterVar(&cv_maxplayers);
|
||||
CV_RegisterVar(&cv_maxsend);
|
||||
CV_RegisterVar(&cv_noticedownload);
|
||||
CV_RegisterVar(&cv_downloadspeed);
|
||||
|
||||
COM_AddCommand("ping", Command_Ping_f);
|
||||
CV_RegisterVar(&cv_nettimeout);
|
||||
CV_RegisterVar(&cv_jointimeout);
|
||||
|
||||
CV_RegisterVar(&cv_skipmapcheck);
|
||||
CV_RegisterVar(&cv_sleep);
|
||||
|
@ -976,7 +1011,7 @@ UINT8 CanChangeSkin(INT32 playernum)
|
|||
return true;
|
||||
|
||||
// Force skin in effect.
|
||||
if (!server && (cv_forceskin.value != -1) && !(adminplayer == playernum && serverplayer == -1))
|
||||
if (client && (cv_forceskin.value != -1) && !(adminplayer == playernum && serverplayer == -1))
|
||||
return false;
|
||||
|
||||
// Can change skin in intermission and whatnot.
|
||||
|
@ -1534,8 +1569,13 @@ void D_MapChange(INT32 mapnum, INT32 newgametype, boolean pultmode, boolean rese
|
|||
mapchangepending = 0;
|
||||
// spawn the server if needed
|
||||
// reset players if there is a new one
|
||||
if (!(adminplayer == consoleplayer) && SV_SpawnServer())
|
||||
buf[0] &= ~(1<<1);
|
||||
if (!(adminplayer == consoleplayer))
|
||||
{
|
||||
if (SV_SpawnServer())
|
||||
buf[0] &= ~(1<<1);
|
||||
if (!Playing()) // you failed to start a server somehow, so cancel the map change
|
||||
return;
|
||||
}
|
||||
|
||||
// Kick bot from special stages
|
||||
if (botskin)
|
||||
|
@ -1587,7 +1627,7 @@ static void Command_Map_f(void)
|
|||
return;
|
||||
}
|
||||
|
||||
if (!server && !(adminplayer == consoleplayer))
|
||||
if (client && !(adminplayer == consoleplayer))
|
||||
{
|
||||
CONS_Printf(M_GetText("Only the server or a remote admin can use this.\n"));
|
||||
return;
|
||||
|
@ -1914,7 +1954,7 @@ static void Got_Suicide(UINT8 **cp, INT32 playernum)
|
|||
// You can't suicide someone else. Nice try, there.
|
||||
if (suicideplayer != playernum || (!G_PlatformGametype()))
|
||||
{
|
||||
CONS_Alert(CONS_WARNING, M_GetText("Illegal suicide command recieved from %s\n"), player_names[playernum]);
|
||||
CONS_Alert(CONS_WARNING, M_GetText("Illegal suicide command received from %s\n"), player_names[playernum]);
|
||||
if (server)
|
||||
{
|
||||
XBOXSTATIC UINT8 buf[2];
|
||||
|
@ -2081,7 +2121,7 @@ static void Command_Teamchange_f(void)
|
|||
return;
|
||||
}
|
||||
|
||||
if (!cv_allowteamchange.value && !NetPacket.packet.newteam) // allow swapping to spectator even in locked teams.
|
||||
if (!cv_allowteamchange.value && NetPacket.packet.newteam) // allow swapping to spectator even in locked teams.
|
||||
{
|
||||
CONS_Alert(CONS_NOTICE, M_GetText("The server is not allowing team changes at the moment.\n"));
|
||||
return;
|
||||
|
@ -2178,7 +2218,7 @@ static void Command_Teamchange2_f(void)
|
|||
return;
|
||||
}
|
||||
|
||||
if (!cv_allowteamchange.value && !NetPacket.packet.newteam) // allow swapping to spectator even in locked teams.
|
||||
if (!cv_allowteamchange.value && NetPacket.packet.newteam) // allow swapping to spectator even in locked teams.
|
||||
{
|
||||
CONS_Alert(CONS_NOTICE, M_GetText("The server is not allowing team changes at the moment.\n"));
|
||||
return;
|
||||
|
@ -2629,7 +2669,7 @@ static void Command_Changepassword_f(void)
|
|||
// If we have no MD5 support then completely disable XD_LOGIN responses for security.
|
||||
CONS_Alert(CONS_NOTICE, "Remote administration commands are not supported in this build.\n");
|
||||
#else
|
||||
if (!server) // cannot change remotely
|
||||
if (client) // cannot change remotely
|
||||
{
|
||||
CONS_Printf(M_GetText("Only the server can use this.\n"));
|
||||
return;
|
||||
|
@ -2688,7 +2728,7 @@ static void Got_Login(UINT8 **cp, INT32 playernum)
|
|||
|
||||
READMEM(*cp, sentmd5, 16);
|
||||
|
||||
if (!server)
|
||||
if (client)
|
||||
return;
|
||||
|
||||
// Do the final pass to compare with the sent md5
|
||||
|
@ -2710,7 +2750,7 @@ static void Command_Verify_f(void)
|
|||
char *temp;
|
||||
INT32 playernum;
|
||||
|
||||
if (!server)
|
||||
if (client)
|
||||
{
|
||||
CONS_Printf(M_GetText("Only the server can use this.\n"));
|
||||
return;
|
||||
|
@ -2794,7 +2834,7 @@ static void Command_MotD_f(void)
|
|||
return;
|
||||
}
|
||||
|
||||
if ((netgame || multiplayer) && !server)
|
||||
if ((netgame || multiplayer) && client)
|
||||
SendNetXCmd(XD_SETMOTD, mymotd, sizeof(motd));
|
||||
else
|
||||
{
|
||||
|
@ -2932,6 +2972,7 @@ static void Command_Addfile(void)
|
|||
XBOXSTATIC char buf[256];
|
||||
char *buf_p = buf;
|
||||
INT32 i;
|
||||
int musiconly; // W_VerifyNMUSlumps isn't boolean
|
||||
|
||||
if (COM_Argc() != 2)
|
||||
{
|
||||
|
@ -2946,7 +2987,9 @@ static void Command_Addfile(void)
|
|||
if (!isprint(fn[i]) || fn[i] == ';')
|
||||
return;
|
||||
|
||||
if (!W_VerifyNMUSlumps(fn))
|
||||
musiconly = W_VerifyNMUSlumps(fn);
|
||||
|
||||
if (!musiconly)
|
||||
{
|
||||
// ... But only so long as they contain nothing more then music and sprites.
|
||||
if (netgame && !(server || adminplayer == consoleplayer))
|
||||
|
@ -2958,7 +3001,7 @@ static void Command_Addfile(void)
|
|||
}
|
||||
|
||||
// Add file on your client directly if it is trivial, or you aren't in a netgame.
|
||||
if (!(netgame || multiplayer) || W_VerifyNMUSlumps(fn))
|
||||
if (!(netgame || multiplayer) || musiconly)
|
||||
{
|
||||
P_AddWadFile(fn, NULL);
|
||||
return;
|
||||
|
@ -2978,9 +3021,7 @@ static void Command_Addfile(void)
|
|||
#else
|
||||
FILE *fhandle;
|
||||
|
||||
fhandle = fopen(fn, "rb");
|
||||
|
||||
if (fhandle)
|
||||
if ((fhandle = W_OpenWadFile(&fn, true)) != NULL)
|
||||
{
|
||||
tic_t t = I_GetTime();
|
||||
CONS_Debug(DBG_SETUP, "Making MD5 for %s\n",fn);
|
||||
|
@ -2988,11 +3029,8 @@ static void Command_Addfile(void)
|
|||
CONS_Debug(DBG_SETUP, "MD5 calc for %s took %f second\n", fn, (float)(I_GetTime() - t)/TICRATE);
|
||||
fclose(fhandle);
|
||||
}
|
||||
else
|
||||
{
|
||||
CONS_Printf(M_GetText("File %s not found.\n"), fn);
|
||||
else // file not found
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
WRITEMEM(buf_p, md5sum, 16);
|
||||
}
|
||||
|
@ -3045,13 +3083,19 @@ static void Got_RequestAddfilecmd(UINT8 **cp, INT32 playernum)
|
|||
filestatus_t ncs = FS_NOTFOUND;
|
||||
UINT8 md5sum[16];
|
||||
boolean kick = false;
|
||||
boolean toomany = false;
|
||||
INT32 i;
|
||||
size_t packetsize = 0;
|
||||
serverinfo_pak *dummycheck = NULL;
|
||||
|
||||
// Shut the compiler up.
|
||||
(void)dummycheck;
|
||||
|
||||
READSTRINGN(*cp, filename, 240);
|
||||
READMEM(*cp, md5sum, 16);
|
||||
|
||||
// Only the server processes this message.
|
||||
if (!server)
|
||||
if (client)
|
||||
return;
|
||||
|
||||
// Disallow non-printing characters and semicolons.
|
||||
|
@ -3071,13 +3115,25 @@ static void Got_RequestAddfilecmd(UINT8 **cp, INT32 playernum)
|
|||
return;
|
||||
}
|
||||
|
||||
ncs = findfile(filename,md5sum,true);
|
||||
// See W_LoadWadFile in w_wad.c
|
||||
for (i = 0; i < numwadfiles; i++)
|
||||
packetsize += nameonlylength(wadfiles[i]->filename) + 22;
|
||||
|
||||
if (ncs != FS_FOUND)
|
||||
packetsize += nameonlylength(filename) + 22;
|
||||
|
||||
if ((numwadfiles >= MAX_WADFILES)
|
||||
|| (packetsize > sizeof(dummycheck->fileneeded)))
|
||||
toomany = true;
|
||||
else
|
||||
ncs = findfile(filename,md5sum,true);
|
||||
|
||||
if (ncs != FS_FOUND || toomany)
|
||||
{
|
||||
char message[256];
|
||||
|
||||
if (ncs == FS_NOTFOUND)
|
||||
if (toomany)
|
||||
sprintf(message, M_GetText("Too many files loaded to add %s\n"), filename);
|
||||
else if (ncs == FS_NOTFOUND)
|
||||
sprintf(message, M_GetText("The server doesn't have %s\n"), filename);
|
||||
else if (ncs == FS_MD5SUMBAD)
|
||||
sprintf(message, M_GetText("Checksum mismatch on %s\n"), filename);
|
||||
|
@ -3147,10 +3203,15 @@ static void Got_Addfilecmd(UINT8 **cp, INT32 playernum)
|
|||
|
||||
ncs = findfile(filename,md5sum,true);
|
||||
|
||||
if (ncs != FS_FOUND)
|
||||
if (ncs != FS_FOUND || !P_AddWadFile(filename, NULL))
|
||||
{
|
||||
Command_ExitGame_f();
|
||||
if (ncs == FS_NOTFOUND)
|
||||
if (ncs == FS_FOUND)
|
||||
{
|
||||
CONS_Printf(M_GetText("The server tried to add %s,\nbut you have too many files added.\nRestart the game to clear loaded files\nand play on this server."), filename);
|
||||
M_StartMessage(va("The server added a file \n(%s)\nbut you have too many files added.\nRestart the game to clear loaded files.\n\nPress ESC\n",filename), NULL, MM_NOTHING);
|
||||
}
|
||||
else if (ncs == FS_NOTFOUND)
|
||||
{
|
||||
CONS_Printf(M_GetText("The server tried to add %s,\nbut you don't have this file.\nYou need to find it in order\nto play on this server."), filename);
|
||||
M_StartMessage(va("The server added a file \n(%s)\nthat you do not have.\n\nPress ESC\n",filename), NULL, MM_NOTHING);
|
||||
|
@ -3168,7 +3229,6 @@ static void Got_Addfilecmd(UINT8 **cp, INT32 playernum)
|
|||
return;
|
||||
}
|
||||
|
||||
P_AddWadFile(filename, NULL);
|
||||
G_SetGameModified(true);
|
||||
}
|
||||
|
||||
|
@ -3318,6 +3378,11 @@ static void NetTimeout_OnChange(void)
|
|||
connectiontimeout = (tic_t)cv_nettimeout.value;
|
||||
}
|
||||
|
||||
static void JoinTimeout_OnChange(void)
|
||||
{
|
||||
jointimeout = (tic_t)cv_jointimeout.value;
|
||||
}
|
||||
|
||||
UINT32 timelimitintics = 0;
|
||||
|
||||
/** Deals with a timelimit change by printing the change to the console.
|
||||
|
@ -3960,7 +4025,7 @@ static void Command_Archivetest_f(void)
|
|||
}
|
||||
|
||||
// assign mobjnum
|
||||
i = 0;
|
||||
i = 1;
|
||||
for (th = thinkercap.next; th != &thinkercap; th = th->next)
|
||||
if (th->function.acp1 == (actionf_p1)P_MobjThinker)
|
||||
((mobj_t *)th)->mobjnum = i++;
|
||||
|
@ -4063,7 +4128,7 @@ static void Skin_OnChange(void)
|
|||
return; // do whatever you want
|
||||
|
||||
if (!(cv_debug || devparm) && !(multiplayer || netgame) // In single player.
|
||||
&& (gamestate == GS_LEVEL || gamestate == GS_INTERMISSION || gamestate == GS_CONTINUING))
|
||||
&& (gamestate != GS_WAITINGPLAYERS)) // allows command line -warp x +skin y
|
||||
{
|
||||
CV_StealthSet(&cv_skin, skins[players[consoleplayer].skin].name);
|
||||
return;
|
||||
|
@ -4106,8 +4171,7 @@ static void Color_OnChange(void)
|
|||
if (!Playing())
|
||||
return; // do whatever you want
|
||||
|
||||
if (!(cv_debug || devparm) && !(multiplayer || netgame) // In single player.
|
||||
&& (gamestate == GS_LEVEL || gamestate == GS_INTERMISSION || gamestate == GS_CONTINUING))
|
||||
if (!(cv_debug || devparm) && !(multiplayer || netgame)) // In single player.
|
||||
{
|
||||
CV_StealthSet(&cv_skin, skins[players[consoleplayer].skin].name);
|
||||
return;
|
||||
|
|
|
@ -162,6 +162,8 @@ typedef enum
|
|||
MAXNETXCMD
|
||||
} netxcmd_t;
|
||||
|
||||
extern const char *netxcmdnames[MAXNETXCMD - 1];
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma pack(1)
|
||||
#endif
|
||||
|
|
527
src/d_netfil.c
527
src/d_netfil.c
|
@ -62,44 +62,49 @@
|
|||
|
||||
#include <errno.h>
|
||||
|
||||
static void SendFile(INT32 node, const char *filename, UINT8 fileid);
|
||||
// Prototypes
|
||||
static boolean SV_SendFile(INT32 node, const char *filename, UINT8 fileid);
|
||||
|
||||
// sender structure
|
||||
// Sender structure
|
||||
typedef struct filetx_s
|
||||
{
|
||||
INT32 ram;
|
||||
char *filename; // name of the file or ptr of the data in ram
|
||||
UINT32 size;
|
||||
union {
|
||||
char *filename; // Name of the file
|
||||
char *ram; // Pointer to the data in RAM
|
||||
} id;
|
||||
UINT32 size; // Size of the file
|
||||
UINT8 fileid;
|
||||
INT32 node; // destination
|
||||
struct filetx_s *next; // a queue
|
||||
INT32 node; // Destination
|
||||
struct filetx_s *next; // Next file in the list
|
||||
} filetx_t;
|
||||
|
||||
// current transfers (one for each node)
|
||||
// Current transfers (one for each node)
|
||||
typedef struct filetran_s
|
||||
{
|
||||
filetx_t *txlist;
|
||||
UINT32 position;
|
||||
FILE *currentfile;
|
||||
filetx_t *txlist; // Linked list of all files for the node
|
||||
UINT32 position; // The current position in the file
|
||||
FILE *currentfile; // The file currently being sent/received
|
||||
} filetran_t;
|
||||
static filetran_t transfer[MAXNETNODES];
|
||||
|
||||
// read time of file: stat _stmtime
|
||||
// write time of file: utime
|
||||
// Read time of file: stat _stmtime
|
||||
// Write time of file: utime
|
||||
|
||||
// receiver structure
|
||||
INT32 fileneedednum;
|
||||
fileneeded_t fileneeded[MAX_WADFILES];
|
||||
// Receiver structure
|
||||
INT32 fileneedednum; // Number of files needed to join the server
|
||||
fileneeded_t fileneeded[MAX_WADFILES]; // List of needed files
|
||||
char downloaddir[256] = "DOWNLOAD";
|
||||
|
||||
#ifdef CLIENT_LOADINGSCREEN
|
||||
// for cl loading screen
|
||||
INT32 lastfilenum = 0;
|
||||
INT32 lastfilenum = -1;
|
||||
#endif
|
||||
|
||||
/** Fills a serverinfo packet with information about wad files loaded.
|
||||
*
|
||||
* \todo Give this function a better name since it is in global scope.
|
||||
*
|
||||
*/
|
||||
UINT8 *PutFileNeeded(void)
|
||||
{
|
||||
|
@ -111,19 +116,19 @@ UINT8 *PutFileNeeded(void)
|
|||
|
||||
for (i = 0; i < numwadfiles; i++)
|
||||
{
|
||||
// if it has only music/sound lumps, mark it as unimportant
|
||||
// If it has only music/sound lumps, mark it as unimportant
|
||||
if (W_VerifyNMUSlumps(wadfiles[i]->filename))
|
||||
filestatus = 0;
|
||||
else
|
||||
filestatus = 1; // important
|
||||
filestatus = 1; // Important
|
||||
|
||||
// Store in the upper four bits
|
||||
if (!cv_downloading.value)
|
||||
filestatus += (2 << 4); // won't send
|
||||
filestatus += (2 << 4); // Won't send
|
||||
else if ((wadfiles[i]->filesize > (UINT32)cv_maxsend.value * 1024))
|
||||
filestatus += (0 << 4); // won't send
|
||||
filestatus += (0 << 4); // Won't send
|
||||
else
|
||||
filestatus += (1 << 4); // will send if requested
|
||||
filestatus += (1 << 4); // Will send if requested
|
||||
|
||||
bytesused += (nameonlylength(wadfilename) + 22);
|
||||
|
||||
|
@ -144,7 +149,12 @@ UINT8 *PutFileNeeded(void)
|
|||
return p;
|
||||
}
|
||||
|
||||
// parse the serverinfo packet and fill fileneeded table on client
|
||||
/** Parses the serverinfo packet and fills the fileneeded table on client
|
||||
*
|
||||
* \param fileneedednum_parm The number of files needed to join the server
|
||||
* \param fileneededstr The memory block containing the list of needed files
|
||||
*
|
||||
*/
|
||||
void D_ParseFileneeded(INT32 fileneedednum_parm, UINT8 *fileneededstr)
|
||||
{
|
||||
INT32 i;
|
||||
|
@ -155,14 +165,14 @@ void D_ParseFileneeded(INT32 fileneedednum_parm, UINT8 *fileneededstr)
|
|||
p = (UINT8 *)fileneededstr;
|
||||
for (i = 0; i < fileneedednum; i++)
|
||||
{
|
||||
fileneeded[i].status = FS_NOTFOUND;
|
||||
filestatus = READUINT8(p);
|
||||
fileneeded[i].status = FS_NOTFOUND; // We haven't even started looking for the file yet
|
||||
filestatus = READUINT8(p); // The first byte is the file status
|
||||
fileneeded[i].important = (UINT8)(filestatus & 3);
|
||||
fileneeded[i].willsend = (UINT8)(filestatus >> 4);
|
||||
fileneeded[i].totalsize = READUINT32(p);
|
||||
fileneeded[i].phandle = NULL;
|
||||
READSTRINGN(p, fileneeded[i].filename, MAX_WADPATH);
|
||||
READMEM(p, fileneeded[i].md5sum, 16);
|
||||
fileneeded[i].totalsize = READUINT32(p); // The four next bytes are the file size
|
||||
fileneeded[i].file = NULL; // The file isn't open yet
|
||||
READSTRINGN(p, fileneeded[i].filename, MAX_WADPATH); // The next bytes are the file name
|
||||
READMEM(p, fileneeded[i].md5sum, 16); // The last 16 bytes are the file checksum
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -171,13 +181,16 @@ void CL_PrepareDownloadSaveGame(const char *tmpsave)
|
|||
fileneedednum = 1;
|
||||
fileneeded[0].status = FS_REQUESTED;
|
||||
fileneeded[0].totalsize = UINT32_MAX;
|
||||
fileneeded[0].phandle = NULL;
|
||||
fileneeded[0].file = NULL;
|
||||
memset(fileneeded[0].md5sum, 0, 16);
|
||||
strcpy(fileneeded[0].filename, tmpsave);
|
||||
}
|
||||
|
||||
/** Checks the server to see if we CAN download all the files,
|
||||
* before starting to create them and requesting.
|
||||
*
|
||||
* \return True if we can download all the files
|
||||
*
|
||||
*/
|
||||
boolean CL_CheckDownloadable(void)
|
||||
{
|
||||
|
@ -239,8 +252,12 @@ boolean CL_CheckDownloadable(void)
|
|||
return false;
|
||||
}
|
||||
|
||||
/** Send requests for files in the ::fileneeded table with a status of
|
||||
/** Sends requests for files in the ::fileneeded table with a status of
|
||||
* ::FS_NOTFOUND.
|
||||
*
|
||||
* \return True if the packet was successfully sent
|
||||
* \note Sends a PT_REQUESTFILE packet
|
||||
*
|
||||
*/
|
||||
boolean CL_SendRequestFile(void)
|
||||
{
|
||||
|
@ -287,7 +304,8 @@ boolean CL_SendRequestFile(void)
|
|||
}
|
||||
|
||||
// get request filepak and put it on the send queue
|
||||
void Got_RequestFilePak(INT32 node)
|
||||
// returns false if a requested file was not found or cannot be sent
|
||||
boolean Got_RequestFilePak(INT32 node)
|
||||
{
|
||||
char wad[MAX_WADPATH+1];
|
||||
UINT8 *p = netbuffer->u.textcmd;
|
||||
|
@ -298,16 +316,33 @@ void Got_RequestFilePak(INT32 node)
|
|||
if (id == 0xFF)
|
||||
break;
|
||||
READSTRINGN(p, wad, MAX_WADPATH);
|
||||
SendFile(node, wad, id);
|
||||
if (!SV_SendFile(node, wad, id))
|
||||
{
|
||||
SV_AbortSendFiles(node);
|
||||
return false; // don't read the rest of the files
|
||||
}
|
||||
}
|
||||
return true; // no problems with any files
|
||||
}
|
||||
|
||||
// client check if the fileneeded aren't already loaded or on the disk
|
||||
/** Checks if the files needed aren't already loaded or on the disk
|
||||
*
|
||||
* \return 0 if some files are missing
|
||||
* 1 if all files exist
|
||||
* 2 if some already loaded files are not requested or are in a different order
|
||||
*
|
||||
*/
|
||||
INT32 CL_CheckFiles(void)
|
||||
{
|
||||
INT32 i, j;
|
||||
char wadfilename[MAX_WADPATH];
|
||||
INT32 ret = 1;
|
||||
size_t packetsize = 0;
|
||||
size_t filestoget = 0;
|
||||
serverinfo_pak *dummycheck = NULL;
|
||||
|
||||
// Shut the compiler up.
|
||||
(void)dummycheck;
|
||||
|
||||
// if (M_CheckParm("-nofiles"))
|
||||
// return 1;
|
||||
|
@ -333,7 +368,7 @@ INT32 CL_CheckFiles(void)
|
|||
}
|
||||
if (j < numwadfiles && W_VerifyNMUSlumps(wadfiles[j]->filename))
|
||||
{
|
||||
// unimportant on our side. still don't care.
|
||||
// Unimportant on our side. still don't care.
|
||||
++j;
|
||||
continue;
|
||||
}
|
||||
|
@ -343,11 +378,11 @@ INT32 CL_CheckFiles(void)
|
|||
if (i >= fileneedednum || j >= numwadfiles)
|
||||
return 2;
|
||||
|
||||
// for the sake of speed, only bother with a md5 check
|
||||
// For the sake of speed, only bother with a md5 check
|
||||
if (memcmp(wadfiles[j]->md5sum, fileneeded[i].md5sum, 16))
|
||||
return 2;
|
||||
|
||||
// it's accounted for! let's keep going.
|
||||
// It's accounted for! let's keep going.
|
||||
CONS_Debug(DBG_NETPLAY, "'%s' accounted for\n", fileneeded[i].filename);
|
||||
fileneeded[i].status = FS_OPEN;
|
||||
++i;
|
||||
|
@ -356,11 +391,15 @@ INT32 CL_CheckFiles(void)
|
|||
return 1;
|
||||
}
|
||||
|
||||
// See W_LoadWadFile in w_wad.c
|
||||
for (i = 0; i < numwadfiles; i++)
|
||||
packetsize += nameonlylength(wadfiles[i]->filename) + 22;
|
||||
|
||||
for (i = 1; i < fileneedednum; i++)
|
||||
{
|
||||
CONS_Debug(DBG_NETPLAY, "searching for '%s' ", fileneeded[i].filename);
|
||||
|
||||
// check in allready loaded files
|
||||
// Check in already loaded files
|
||||
for (j = 1; wadfiles[j]; j++)
|
||||
{
|
||||
nameonly(strcpy(wadfilename, wadfiles[j]->filename));
|
||||
|
@ -375,6 +414,14 @@ INT32 CL_CheckFiles(void)
|
|||
if (fileneeded[i].status != FS_NOTFOUND || !fileneeded[i].important)
|
||||
continue;
|
||||
|
||||
packetsize += nameonlylength(fileneeded[i].filename) + 22;
|
||||
|
||||
if ((numwadfiles+filestoget >= MAX_WADFILES)
|
||||
|| (packetsize > sizeof(dummycheck->fileneeded)))
|
||||
return 3;
|
||||
|
||||
filestoget++;
|
||||
|
||||
fileneeded[i].status = findfile(fileneeded[i].filename, fileneeded[i].md5sum, true);
|
||||
CONS_Debug(DBG_NETPLAY, "found %d\n", fileneeded[i].status);
|
||||
if (fileneeded[i].status != FS_FOUND)
|
||||
|
@ -383,7 +430,7 @@ INT32 CL_CheckFiles(void)
|
|||
return ret;
|
||||
}
|
||||
|
||||
// load it now
|
||||
// Load it now
|
||||
void CL_LoadServerFiles(void)
|
||||
{
|
||||
INT32 i;
|
||||
|
@ -394,7 +441,7 @@ void CL_LoadServerFiles(void)
|
|||
for (i = 1; i < fileneedednum; i++)
|
||||
{
|
||||
if (fileneeded[i].status == FS_OPEN)
|
||||
continue; // already loaded
|
||||
continue; // Already loaded
|
||||
else if (fileneeded[i].status == FS_FOUND)
|
||||
{
|
||||
P_AddWadFile(fileneeded[i].filename, NULL);
|
||||
|
@ -423,172 +470,270 @@ void CL_LoadServerFiles(void)
|
|||
DEBFILE(va("File %s found but with different md5sum\n", fileneeded[i].filename));
|
||||
}
|
||||
else if (fileneeded[i].important)
|
||||
I_Error("Try to load file %s with status of %d\n", fileneeded[i].filename,
|
||||
fileneeded[i].status);
|
||||
{
|
||||
const char *s;
|
||||
switch(fileneeded[i].status)
|
||||
{
|
||||
case FS_NOTFOUND:
|
||||
s = "FS_NOTFOUND";
|
||||
break;
|
||||
case FS_REQUESTED:
|
||||
s = "FS_REQUESTED";
|
||||
break;
|
||||
case FS_DOWNLOADING:
|
||||
s = "FS_DOWNLOADING";
|
||||
break;
|
||||
default:
|
||||
s = "unknown";
|
||||
break;
|
||||
}
|
||||
I_Error("Try to load file \"%s\" with status of %d (%s)\n", fileneeded[i].filename,
|
||||
fileneeded[i].status, s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// little optimization to test if there is a file in the queue
|
||||
static INT32 filetosend = 0;
|
||||
// Number of files to send
|
||||
// Little optimization to quickly test if there is a file in the queue
|
||||
static INT32 filestosend = 0;
|
||||
|
||||
static void SendFile(INT32 node, const char *filename, UINT8 fileid)
|
||||
/** Adds a file to the file list for a node
|
||||
*
|
||||
* \param node The node to send the file to
|
||||
* \param filename The file to send
|
||||
* \param fileid ???
|
||||
* \sa SV_SendRam
|
||||
*
|
||||
*/
|
||||
static boolean SV_SendFile(INT32 node, const char *filename, UINT8 fileid)
|
||||
{
|
||||
filetx_t **q;
|
||||
filetx_t *p;
|
||||
filetx_t **q; // A pointer to the "next" field of the last file in the list
|
||||
filetx_t *p; // The new file request
|
||||
INT32 i;
|
||||
char wadfilename[MAX_WADPATH];
|
||||
|
||||
if (cv_noticedownload.value)
|
||||
CONS_Printf("Sending file \"%s\" to node %d (%s)\n", filename, node, I_GetNodeAddress(node));
|
||||
|
||||
// Find the last file in the list and set a pointer to its "next" field
|
||||
q = &transfer[node].txlist;
|
||||
while (*q)
|
||||
q = &((*q)->next);
|
||||
|
||||
// Allocate a file request and append it to the file list
|
||||
p = *q = (filetx_t *)malloc(sizeof (filetx_t));
|
||||
if (p)
|
||||
memset(p, 0, sizeof (filetx_t));
|
||||
else
|
||||
I_Error("SendFile: No more ram\n");
|
||||
p->filename = (char *)malloc(MAX_WADPATH);
|
||||
if (!p->filename)
|
||||
I_Error("SendFile: No more ram\n");
|
||||
if (!p)
|
||||
I_Error("SV_SendFile: No more memory\n");
|
||||
|
||||
// a minimum of security, can get only file in srb2 direcory
|
||||
strlcpy(p->filename, filename, MAX_WADPATH);
|
||||
nameonly(p->filename);
|
||||
// Initialise with zeros
|
||||
memset(p, 0, sizeof (filetx_t));
|
||||
|
||||
// check first in wads loaded the majority of case
|
||||
// Allocate the file name
|
||||
p->id.filename = (char *)malloc(MAX_WADPATH);
|
||||
if (!p->id.filename)
|
||||
I_Error("SV_SendFile: No more memory\n");
|
||||
|
||||
// Set the file name and get rid of the path
|
||||
strlcpy(p->id.filename, filename, MAX_WADPATH);
|
||||
nameonly(p->id.filename);
|
||||
|
||||
// Look for the requested file through all loaded files
|
||||
for (i = 0; wadfiles[i]; i++)
|
||||
{
|
||||
strlcpy(wadfilename, wadfiles[i]->filename, MAX_WADPATH);
|
||||
nameonly(wadfilename);
|
||||
if (!stricmp(wadfilename, p->filename))
|
||||
if (!stricmp(wadfilename, p->id.filename))
|
||||
{
|
||||
// copy filename with full path
|
||||
strlcpy(p->filename, wadfiles[i]->filename, MAX_WADPATH);
|
||||
// Copy file name with full path
|
||||
strlcpy(p->id.filename, wadfiles[i]->filename, MAX_WADPATH);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Handle non-loaded file requests
|
||||
if (!wadfiles[i])
|
||||
{
|
||||
DEBFILE(va("%s not found in wadfiles\n", filename));
|
||||
// this formerly checked if (!findfile(p->filename, NULL, true))
|
||||
// This formerly checked if (!findfile(p->id.filename, NULL, true))
|
||||
|
||||
// not found
|
||||
// don't inform client (probably hacker)
|
||||
// Not found
|
||||
// Don't inform client (probably someone who thought they could leak 2.2 ACZ)
|
||||
DEBFILE(va("Client %d request %s: not found\n", node, filename));
|
||||
free(p->filename);
|
||||
free(p->id.filename);
|
||||
free(p);
|
||||
*q = NULL;
|
||||
return;
|
||||
return false; // cancel the rest of the requests
|
||||
}
|
||||
|
||||
// Handle huge file requests (i.e. bigger than cv_maxsend.value KB)
|
||||
if (wadfiles[i]->filesize > (UINT32)cv_maxsend.value * 1024)
|
||||
{
|
||||
// too big
|
||||
// don't inform client (client sucks, man)
|
||||
// Too big
|
||||
// Don't inform client (client sucks, man)
|
||||
DEBFILE(va("Client %d request %s: file too big, not sending\n", node, filename));
|
||||
free(p->filename);
|
||||
free(p->id.filename);
|
||||
free(p);
|
||||
*q = NULL;
|
||||
return;
|
||||
return false; // cancel the rest of the requests
|
||||
}
|
||||
|
||||
DEBFILE(va("Sending file %s (id=%d) to %d\n", filename, fileid, node));
|
||||
p->ram = SF_FILE;
|
||||
p->ram = SF_FILE; // It's a file, we need to close it and free its name once we're done sending it
|
||||
p->fileid = fileid;
|
||||
p->next = NULL; // end of list
|
||||
filetosend++;
|
||||
p->next = NULL; // End of list
|
||||
filestosend++;
|
||||
return true;
|
||||
}
|
||||
|
||||
void SendRam(INT32 node, void *data, size_t size, freemethod_t freemethod, UINT8 fileid)
|
||||
/** Adds a memory block to the file list for a node
|
||||
*
|
||||
* \param node The node to send the memory block to
|
||||
* \param data The memory block to send
|
||||
* \param size The size of the block in bytes
|
||||
* \param freemethod How to free the block after it has been sent
|
||||
* \param fileid ???
|
||||
* \sa SV_SendFile
|
||||
*
|
||||
*/
|
||||
void SV_SendRam(INT32 node, void *data, size_t size, freemethod_t freemethod, UINT8 fileid)
|
||||
{
|
||||
filetx_t **q;
|
||||
filetx_t *p;
|
||||
filetx_t **q; // A pointer to the "next" field of the last file in the list
|
||||
filetx_t *p; // The new file request
|
||||
|
||||
// Find the last file in the list and set a pointer to its "next" field
|
||||
q = &transfer[node].txlist;
|
||||
while (*q)
|
||||
q = &((*q)->next);
|
||||
|
||||
// Allocate a file request and append it to the file list
|
||||
p = *q = (filetx_t *)malloc(sizeof (filetx_t));
|
||||
if (p)
|
||||
memset(p, 0, sizeof (filetx_t));
|
||||
else
|
||||
I_Error("SendRam: No more ram\n");
|
||||
p->ram = freemethod;
|
||||
p->filename = data;
|
||||
if (!p)
|
||||
I_Error("SV_SendRam: No more memory\n");
|
||||
|
||||
// Initialise with zeros
|
||||
memset(p, 0, sizeof (filetx_t));
|
||||
|
||||
p->ram = freemethod; // Remember how to free the memory block for when we're done sending it
|
||||
p->id.ram = data;
|
||||
p->size = (UINT32)size;
|
||||
p->fileid = fileid;
|
||||
p->next = NULL; // end of list
|
||||
p->next = NULL; // End of list
|
||||
|
||||
DEBFILE(va("Sending ram %p(size:%u) to %d (id=%u)\n",p->filename,p->size,node,fileid));
|
||||
DEBFILE(va("Sending ram %p(size:%u) to %d (id=%u)\n",p->id.ram,p->size,node,fileid));
|
||||
|
||||
filetosend++;
|
||||
filestosend++;
|
||||
}
|
||||
|
||||
static void EndSend(INT32 node)
|
||||
/** Stops sending a file for a node, and removes the file request from the list,
|
||||
* either because the file has been fully sent or because the node was disconnected
|
||||
*
|
||||
* \param node The destination
|
||||
*
|
||||
*/
|
||||
static void SV_EndFileSend(INT32 node)
|
||||
{
|
||||
filetx_t *p = transfer[node].txlist;
|
||||
|
||||
// Free the file request according to the freemethod parameter used with SV_SendFile/Ram
|
||||
switch (p->ram)
|
||||
{
|
||||
case SF_FILE:
|
||||
case SF_FILE: // It's a file, close it and free its filename
|
||||
if (cv_noticedownload.value)
|
||||
CONS_Printf("Ending file transfer for node %d\n", node);
|
||||
if (transfer[node].currentfile)
|
||||
fclose(transfer[node].currentfile);
|
||||
free(p->filename);
|
||||
free(p->id.filename);
|
||||
break;
|
||||
case SF_Z_RAM:
|
||||
Z_Free(p->filename);
|
||||
case SF_Z_RAM: // It's a memory block allocated with Z_Alloc or the likes, use Z_Free
|
||||
Z_Free(p->id.ram);
|
||||
break;
|
||||
case SF_RAM:
|
||||
free(p->filename);
|
||||
case SF_NOFREERAM:
|
||||
case SF_RAM: // It's a memory block allocated with malloc, use free
|
||||
free(p->id.ram);
|
||||
case SF_NOFREERAM: // Nothing to free
|
||||
break;
|
||||
}
|
||||
|
||||
// Remove the file request from the list
|
||||
transfer[node].txlist = p->next;
|
||||
transfer[node].currentfile = NULL;
|
||||
free(p);
|
||||
filetosend--;
|
||||
|
||||
// Indicate that the transmission is over
|
||||
transfer[node].currentfile = NULL;
|
||||
|
||||
filestosend--;
|
||||
}
|
||||
|
||||
#define PACKETPERTIC net_bandwidth/(TICRATE*software_MAXPACKETLENGTH)
|
||||
|
||||
void FiletxTicker(void)
|
||||
/** Handles file transmission
|
||||
*
|
||||
* \todo Use an acknowledging method more adapted to file transmission
|
||||
* The current download speed suffers from lack of ack packets,
|
||||
* especially when the one downloading has high latency
|
||||
*
|
||||
*/
|
||||
void SV_FileSendTicker(void)
|
||||
{
|
||||
static INT32 currentnode = 0;
|
||||
filetx_pak *p;
|
||||
size_t size;
|
||||
filetx_t *f;
|
||||
INT32 packetsent = PACKETPERTIC, ram, i;
|
||||
INT32 packetsent, ram, i, j;
|
||||
INT32 maxpacketsent;
|
||||
|
||||
if (!filetosend)
|
||||
if (!filestosend) // No file to send
|
||||
return;
|
||||
if (!packetsent)
|
||||
packetsent++;
|
||||
// (((sendbytes-nowsentbyte)*TICRATE)/(I_GetTime()-starttime)<(UINT32)net_bandwidth)
|
||||
while (packetsent-- && filetosend != 0)
|
||||
|
||||
if (cv_downloadspeed.value) // New (and experimental) behavior
|
||||
{
|
||||
for (i = currentnode, ram = 0; ram < MAXNETNODES;
|
||||
i = (i+1) % MAXNETNODES, ram++)
|
||||
packetsent = cv_downloadspeed.value;
|
||||
// Don't send more packets than we have free acks
|
||||
#ifndef NONET
|
||||
maxpacketsent = Net_GetFreeAcks(false) - 5; // Let 5 extra acks just in case
|
||||
#else
|
||||
maxpacketsent = 1;
|
||||
#endif
|
||||
if (packetsent > maxpacketsent && maxpacketsent > 0) // Send at least one packet
|
||||
packetsent = maxpacketsent;
|
||||
}
|
||||
else // Old behavior
|
||||
{
|
||||
packetsent = PACKETPERTIC;
|
||||
if (!packetsent)
|
||||
packetsent = 1;
|
||||
}
|
||||
|
||||
netbuffer->packettype = PT_FILEFRAGMENT;
|
||||
|
||||
// (((sendbytes-nowsentbyte)*TICRATE)/(I_GetTime()-starttime)<(UINT32)net_bandwidth)
|
||||
while (packetsent-- && filestosend != 0)
|
||||
{
|
||||
for (i = currentnode, j = 0; j < MAXNETNODES;
|
||||
i = (i+1) % MAXNETNODES, j++)
|
||||
{
|
||||
if (transfer[i].txlist)
|
||||
goto found;
|
||||
}
|
||||
// no transfer to do
|
||||
I_Error("filetosend=%d but no filetosend found\n", filetosend);
|
||||
I_Error("filestosend=%d but no file to send found\n", filestosend);
|
||||
found:
|
||||
currentnode = (i+1) % MAXNETNODES;
|
||||
f = transfer[i].txlist;
|
||||
ram = f->ram;
|
||||
|
||||
if (!transfer[i].currentfile) // file not already open
|
||||
// Open the file if it isn't open yet, or
|
||||
if (!transfer[i].currentfile)
|
||||
{
|
||||
if (!ram)
|
||||
if (!ram) // Sending a file
|
||||
{
|
||||
long filesize;
|
||||
|
||||
transfer[i].currentfile =
|
||||
fopen(f->filename, "rb");
|
||||
fopen(f->id.filename, "rb");
|
||||
|
||||
if (!transfer[i].currentfile)
|
||||
I_Error("File %s does not exist",
|
||||
f->filename);
|
||||
f->id.filename);
|
||||
|
||||
fseek(transfer[i].currentfile, 0, SEEK_END);
|
||||
filesize = ftell(transfer[i].currentfile);
|
||||
|
@ -596,45 +741,47 @@ void FiletxTicker(void)
|
|||
// Nobody wants to transfer a file bigger
|
||||
// than 4GB!
|
||||
if (filesize >= LONG_MAX)
|
||||
I_Error("filesize of %s is too large", f->filename);
|
||||
if (-1 == filesize)
|
||||
I_Error("Error getting filesize of %s", f->filename);
|
||||
I_Error("filesize of %s is too large", f->id.filename);
|
||||
if (filesize == -1)
|
||||
I_Error("Error getting filesize of %s", f->id.filename);
|
||||
|
||||
f->size = (UINT32)filesize;
|
||||
fseek(transfer[i].currentfile, 0, SEEK_SET);
|
||||
}
|
||||
else
|
||||
transfer[i].currentfile = (FILE *)1;
|
||||
else // Sending RAM
|
||||
transfer[i].currentfile = (FILE *)1; // Set currentfile to a non-null value to indicate that it is open
|
||||
transfer[i].position = 0;
|
||||
}
|
||||
|
||||
// Build a packet containing a file fragment
|
||||
p = &netbuffer->u.filetxpak;
|
||||
size = software_MAXPACKETLENGTH - (FILETXHEADER + BASEPACKETSIZE);
|
||||
if (f->size-transfer[i].position < size)
|
||||
size = f->size-transfer[i].position;
|
||||
if (ram)
|
||||
M_Memcpy(p->data, &f->filename[transfer[i].position], size);
|
||||
M_Memcpy(p->data, &f->id.ram[transfer[i].position], size);
|
||||
else if (fread(p->data, 1, size, transfer[i].currentfile) != size)
|
||||
I_Error("FiletxTicker: can't read %s byte on %s at %d because %s", sizeu1(size), f->filename, transfer[i].position, strerror(ferror(transfer[i].currentfile)));
|
||||
I_Error("SV_FileSendTicker: can't read %s byte on %s at %d because %s", sizeu1(size), f->id.filename, transfer[i].position, strerror(ferror(transfer[i].currentfile)));
|
||||
p->position = LONG(transfer[i].position);
|
||||
// put flag so receiver know the totalsize
|
||||
// Put flag so receiver knows the total size
|
||||
if (transfer[i].position + size == f->size)
|
||||
p->position |= LONG(0x80000000);
|
||||
p->fileid = f->fileid;
|
||||
p->size = SHORT((UINT16)size);
|
||||
netbuffer->packettype = PT_FILEFRAGMENT;
|
||||
if (!HSendPacket(i, true, 0, FILETXHEADER + size)) // reliable SEND
|
||||
{ // not sent for some odd reason, retry at next call
|
||||
if (!ram)
|
||||
fseek(transfer[i].currentfile,transfer[i].position,SEEK_SET);
|
||||
// exit the while (can't send this one so why should i send the next?)
|
||||
break;
|
||||
|
||||
// Send the packet
|
||||
if (HSendPacket(i, true, 0, FILETXHEADER + size)) // Reliable SEND
|
||||
{ // Success
|
||||
transfer[i].position = (UINT32)(transfer[i].position + size);
|
||||
if (transfer[i].position == f->size) // Finish?
|
||||
SV_EndFileSend(i);
|
||||
}
|
||||
else // success
|
||||
{
|
||||
transfer[i].position = (UINT32)(size+transfer[i].position);
|
||||
if (transfer[i].position == f->size) // finish ?
|
||||
EndSend(i);
|
||||
else
|
||||
{ // Not sent for some odd reason, retry at next call
|
||||
if (!ram)
|
||||
fseek(transfer[i].currentfile,transfer[i].position, SEEK_SET);
|
||||
// Exit the while (can't send this one so why should i send the next?)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -642,55 +789,90 @@ void FiletxTicker(void)
|
|||
void Got_Filetxpak(void)
|
||||
{
|
||||
INT32 filenum = netbuffer->u.filetxpak.fileid;
|
||||
fileneeded_t *file = &fileneeded[filenum];
|
||||
char *filename = file->filename;
|
||||
static INT32 filetime = 0;
|
||||
|
||||
if (!(strcmp(filename, "srb2.srb")
|
||||
&& strcmp(filename, "srb2.wad")
|
||||
&& strcmp(filename, "zones.dta")
|
||||
&& strcmp(filename, "player.dta")
|
||||
&& strcmp(filename, "rings.dta")
|
||||
&& strcmp(filename, "patch.dta")
|
||||
&& strcmp(filename, "music.dta")
|
||||
))
|
||||
I_Error("Tried to download \"%s\"", filename);
|
||||
|
||||
if (filenum >= fileneedednum)
|
||||
{
|
||||
DEBFILE(va("fileframent not needed %d>%d\n",filenum, fileneedednum));
|
||||
DEBFILE(va("fileframent not needed %d>%d\n", filenum, fileneedednum));
|
||||
//I_Error("Received an unneeded file fragment (file id received: %d, file id needed: %d)\n", filenum, fileneedednum);
|
||||
return;
|
||||
}
|
||||
|
||||
if (fileneeded[filenum].status == FS_REQUESTED)
|
||||
if (file->status == FS_REQUESTED)
|
||||
{
|
||||
if (fileneeded[filenum].phandle) I_Error("Got_Filetxpak: allready open file\n");
|
||||
fileneeded[filenum].phandle = fopen(fileneeded[filenum].filename, "wb");
|
||||
if (!fileneeded[filenum].phandle) I_Error("Can't create file %s: %s",fileneeded[filenum].filename, strerror(errno));
|
||||
CONS_Printf("\r%s...\n",fileneeded[filenum].filename);
|
||||
fileneeded[filenum].currentsize = 0;
|
||||
fileneeded[filenum].status = FS_DOWNLOADING;
|
||||
if (file->file)
|
||||
I_Error("Got_Filetxpak: already open file\n");
|
||||
file->file = fopen(filename, "wb");
|
||||
if (!file->file)
|
||||
I_Error("Can't create file %s: %s", filename, strerror(errno));
|
||||
CONS_Printf("\r%s...\n",filename);
|
||||
file->currentsize = 0;
|
||||
file->status = FS_DOWNLOADING;
|
||||
}
|
||||
|
||||
if (fileneeded[filenum].status == FS_DOWNLOADING)
|
||||
if (file->status == FS_DOWNLOADING)
|
||||
{
|
||||
UINT32 pos = LONG(netbuffer->u.filetxpak.position);
|
||||
UINT16 size = SHORT(netbuffer->u.filetxpak.size);
|
||||
// use a special tric to know when file is finished (not allways used)
|
||||
// WARNING: filepak can arrive out of order so don't stop now !
|
||||
// Use a special trick to know when the file is complete (not always used)
|
||||
// WARNING: file fragments can arrive out of order so don't stop yet!
|
||||
if (pos & 0x80000000)
|
||||
{
|
||||
pos &= ~0x80000000;
|
||||
fileneeded[filenum].totalsize = pos + size;
|
||||
file->totalsize = pos + size;
|
||||
}
|
||||
// we can receive packet in the wrong order, anyway all os support gaped file
|
||||
fseek(fileneeded[filenum].phandle,pos,SEEK_SET);
|
||||
if (fwrite(netbuffer->u.filetxpak.data,size,1,fileneeded[filenum].phandle)!=1)
|
||||
I_Error("Can't write to %s: %s\n",fileneeded[filenum].filename, strerror(ferror(fileneeded[filenum].phandle)));
|
||||
fileneeded[filenum].currentsize += size;
|
||||
// We can receive packet in the wrong order, anyway all os support gaped file
|
||||
fseek(file->file, pos, SEEK_SET);
|
||||
if (fwrite(netbuffer->u.filetxpak.data,size,1,file->file) != 1)
|
||||
I_Error("Can't write to %s: %s\n",filename, strerror(ferror(file->file)));
|
||||
file->currentsize += size;
|
||||
|
||||
// finished?
|
||||
if (fileneeded[filenum].currentsize == fileneeded[filenum].totalsize)
|
||||
// Finished?
|
||||
if (file->currentsize == file->totalsize)
|
||||
{
|
||||
fclose(fileneeded[filenum].phandle);
|
||||
fileneeded[filenum].phandle = NULL;
|
||||
fileneeded[filenum].status = FS_FOUND;
|
||||
fclose(file->file);
|
||||
file->file = NULL;
|
||||
file->status = FS_FOUND;
|
||||
CONS_Printf(M_GetText("Downloading %s...(done)\n"),
|
||||
fileneeded[filenum].filename);
|
||||
filename);
|
||||
}
|
||||
}
|
||||
else
|
||||
I_Error("Received a file not requested\n");
|
||||
// send ack back quickly
|
||||
|
||||
{
|
||||
const char *s;
|
||||
switch(file->status)
|
||||
{
|
||||
case FS_NOTFOUND:
|
||||
s = "FS_NOTFOUND";
|
||||
break;
|
||||
case FS_FOUND:
|
||||
s = "FS_FOUND";
|
||||
break;
|
||||
case FS_OPEN:
|
||||
s = "FS_OPEN";
|
||||
break;
|
||||
case FS_MD5SUMBAD:
|
||||
s = "FS_MD5SUMBAD";
|
||||
break;
|
||||
default:
|
||||
s = "unknown";
|
||||
break;
|
||||
}
|
||||
I_Error("Received a file not requested (file id: %d, file status: %s)\n", filenum, s);
|
||||
}
|
||||
// Send ack back quickly
|
||||
if (++filetime == 3)
|
||||
{
|
||||
Net_SendAcks(servernode);
|
||||
|
@ -702,33 +884,50 @@ void Got_Filetxpak(void)
|
|||
#endif
|
||||
}
|
||||
|
||||
void AbortSendFiles(INT32 node)
|
||||
/** \brief Checks if a node is downloading a file
|
||||
*
|
||||
* \param node The node to check for
|
||||
* \return True if the node is downloading a file
|
||||
*
|
||||
*/
|
||||
boolean SV_SendingFile(INT32 node)
|
||||
{
|
||||
return transfer[node].txlist != NULL;
|
||||
}
|
||||
|
||||
/** Cancels all file requests for a node
|
||||
*
|
||||
* \param node The destination
|
||||
* \sa SV_EndFileSend
|
||||
*
|
||||
*/
|
||||
void SV_AbortSendFiles(INT32 node)
|
||||
{
|
||||
while (transfer[node].txlist)
|
||||
EndSend(node);
|
||||
SV_EndFileSend(node);
|
||||
}
|
||||
|
||||
void CloseNetFile(void)
|
||||
{
|
||||
INT32 i;
|
||||
// is sending?
|
||||
// Is sending?
|
||||
for (i = 0; i < MAXNETNODES; i++)
|
||||
AbortSendFiles(i);
|
||||
SV_AbortSendFiles(i);
|
||||
|
||||
// receiving a file?
|
||||
// Receiving a file?
|
||||
for (i = 0; i < MAX_WADFILES; i++)
|
||||
if (fileneeded[i].status == FS_DOWNLOADING && fileneeded[i].phandle)
|
||||
if (fileneeded[i].status == FS_DOWNLOADING && fileneeded[i].file)
|
||||
{
|
||||
fclose(fileneeded[i].phandle);
|
||||
// file is not complete delete it
|
||||
fclose(fileneeded[i].file);
|
||||
// File is not complete delete it
|
||||
remove(fileneeded[i].filename);
|
||||
}
|
||||
|
||||
// remove FILEFRAGMENT from acknledge list
|
||||
// Remove PT_FILEFRAGMENT from acknowledge list
|
||||
Net_AbortPacketType(PT_FILEFRAGMENT);
|
||||
}
|
||||
|
||||
// functions cut and pasted from doomatic :)
|
||||
// Functions cut and pasted from Doomatic :)
|
||||
|
||||
void nameonly(char *s)
|
||||
{
|
||||
|
|
|
@ -29,21 +29,21 @@ typedef enum
|
|||
FS_FOUND,
|
||||
FS_REQUESTED,
|
||||
FS_DOWNLOADING,
|
||||
FS_OPEN, // is opened and used in w_wad
|
||||
FS_OPEN, // Is opened and used in w_wad
|
||||
FS_MD5SUMBAD
|
||||
} filestatus_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
UINT8 important;
|
||||
UINT8 willsend; // is the server willing to send it?
|
||||
UINT8 willsend; // Is the server willing to send it?
|
||||
char filename[MAX_WADPATH];
|
||||
UINT8 md5sum[16];
|
||||
// used only for download
|
||||
FILE *phandle;
|
||||
// Used only for download
|
||||
FILE *file;
|
||||
UINT32 currentsize;
|
||||
UINT32 totalsize;
|
||||
filestatus_t status; // the value returned by recsearch
|
||||
filestatus_t status; // The value returned by recsearch
|
||||
} fileneeded_t;
|
||||
|
||||
extern INT32 fileneedednum;
|
||||
|
@ -58,28 +58,25 @@ UINT8 *PutFileNeeded(void);
|
|||
void D_ParseFileneeded(INT32 fileneedednum_parm, UINT8 *fileneededstr);
|
||||
void CL_PrepareDownloadSaveGame(const char *tmpsave);
|
||||
|
||||
// check file list in wadfiles return 0 when a file is not found
|
||||
// 1 if all file are found
|
||||
// 2 if you cannot connect (different wad version or
|
||||
// no enought space to download files)
|
||||
INT32 CL_CheckFiles(void);
|
||||
void CL_LoadServerFiles(void);
|
||||
void SendRam(INT32 node, void *data, size_t size, freemethod_t freemethod,
|
||||
void SV_SendRam(INT32 node, void *data, size_t size, freemethod_t freemethod,
|
||||
UINT8 fileid);
|
||||
|
||||
void FiletxTicker(void);
|
||||
void SV_FileSendTicker(void);
|
||||
void Got_Filetxpak(void);
|
||||
boolean SV_SendingFile(INT32 node);
|
||||
|
||||
boolean CL_CheckDownloadable(void);
|
||||
boolean CL_SendRequestFile(void);
|
||||
void Got_RequestFilePak(INT32 node);
|
||||
boolean Got_RequestFilePak(INT32 node);
|
||||
|
||||
void AbortSendFiles(INT32 node);
|
||||
void SV_AbortSendFiles(INT32 node);
|
||||
void CloseNetFile(void);
|
||||
|
||||
boolean fileexist(char *filename, time_t ptime);
|
||||
|
||||
// search a file in the wadpath, return FS_FOUND when found
|
||||
// Search a file in the wadpath, return FS_FOUND when found
|
||||
filestatus_t findfile(char *filename, const UINT8 *wantedmd5sum,
|
||||
boolean completepath);
|
||||
filestatus_t checkfilemd5(char *filename, const UINT8 *wantedmd5sum);
|
||||
|
|
|
@ -6717,12 +6717,14 @@ static const char *const MOBJEFLAG_LIST[] = {
|
|||
NULL
|
||||
};
|
||||
|
||||
#ifdef HAVE_BLUA
|
||||
static const char *const MAPTHINGFLAG_LIST[4] = {
|
||||
NULL,
|
||||
"OBJECTFLIP", // Reverse gravity flag for objects.
|
||||
"OBJECTSPECIAL", // Special flag used with certain objects.
|
||||
"AMBUSH" // Deaf monsters/do not react to sound.
|
||||
};
|
||||
#endif
|
||||
|
||||
static const char *const PLAYERFLAG_LIST[] = {
|
||||
// Flip camera angle with gravity flip prefrence.
|
||||
|
@ -6795,6 +6797,7 @@ static const char *const PLAYERFLAG_LIST[] = {
|
|||
NULL // stop loop here.
|
||||
};
|
||||
|
||||
#ifdef HAVE_BLUA
|
||||
// Linedef flags
|
||||
static const char *const ML_LIST[16] = {
|
||||
"IMPASSIBLE",
|
||||
|
@ -6814,6 +6817,7 @@ static const char *const ML_LIST[16] = {
|
|||
"BOUNCY",
|
||||
"TFERLINE"
|
||||
};
|
||||
#endif
|
||||
|
||||
// This DOES differ from r_draw's Color_Names, unfortunately.
|
||||
// Also includes Super colors
|
||||
|
@ -7762,7 +7766,7 @@ fixed_t get_number(const char *word)
|
|||
#endif
|
||||
}
|
||||
|
||||
void DEH_Check(void)
|
||||
void FUNCMATH DEH_Check(void)
|
||||
{
|
||||
#if defined(_DEBUG) || defined(PARANOIA)
|
||||
const size_t dehstates = sizeof(STATE_LIST)/sizeof(const char*);
|
||||
|
@ -8276,6 +8280,9 @@ static inline int lib_getenum(lua_State *L)
|
|||
} else if (fastcmp(word,"VERSIONSTRING")) {
|
||||
lua_pushstring(L, VERSIONSTRING);
|
||||
return 1;
|
||||
} else if (fastcmp(word, "token")) {
|
||||
lua_pushinteger(L, token);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -1721,6 +1721,18 @@ INT32 I_PutEnv(char *variable)
|
|||
return putenv(variable);
|
||||
}
|
||||
|
||||
INT32 I_ClipboardCopy(const char *data, size_t size)
|
||||
{
|
||||
(void)data;
|
||||
(void)size;
|
||||
return -1;
|
||||
}
|
||||
|
||||
char *I_ClipboardPaste(void)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const CPUInfoFlags *I_CPUInfo(void)
|
||||
{
|
||||
static CPUInfoFlags DOS_CPUInfo;
|
||||
|
|
|
@ -60,6 +60,7 @@
|
|||
#endif
|
||||
|
||||
#ifdef _WINDOWS
|
||||
#define NONET
|
||||
#if !defined (HWRENDER) && !defined (NOHW)
|
||||
#define HWRENDER
|
||||
#endif
|
||||
|
@ -149,9 +150,9 @@ extern FILE *logstream;
|
|||
// we use comprevision and compbranch instead.
|
||||
#else
|
||||
#define VERSION 201 // Game version
|
||||
#define SUBVERSION 15 // more precise version number
|
||||
#define VERSIONSTRING "v2.1.15"
|
||||
#define VERSIONSTRINGW L"v2.1.15"
|
||||
#define SUBVERSION 19 // more precise version number
|
||||
#define VERSIONSTRING "v2.1.19"
|
||||
#define VERSIONSTRINGW L"v2.1.19"
|
||||
// Hey! If you change this, add 1 to the MODVERSION below!
|
||||
// Otherwise we can't force updates!
|
||||
#endif
|
||||
|
@ -213,7 +214,7 @@ extern FILE *logstream;
|
|||
// it's only for detection of the version the player is using so the MS can alert them of an update.
|
||||
// Only set it higher, not lower, obviously.
|
||||
// Note that we use this to help keep internal testing in check; this is why v2.1.0 is not version "1".
|
||||
#define MODVERSION 20
|
||||
#define MODVERSION 24
|
||||
|
||||
// =========================================================================
|
||||
|
||||
|
@ -393,6 +394,9 @@ extern INT32 cv_debug;
|
|||
// Misc stuff for later...
|
||||
// =======================
|
||||
|
||||
// Modifier key variables, accessible anywhere
|
||||
extern UINT8 shiftdown, ctrldown, altdown;
|
||||
|
||||
// if we ever make our alloc stuff...
|
||||
#define ZZ_Alloc(x) Z_Malloc(x, PU_STATIC, NULL)
|
||||
|
||||
|
@ -431,6 +435,12 @@ extern const char *compdate, *comptime, *comprevision, *compbranch;
|
|||
/// Kalaron/Eternity Engine slope code (SRB2CB ported)
|
||||
#define ESLOPE
|
||||
|
||||
#ifdef ESLOPE
|
||||
/// Backwards compatibility with SRB2CB's slope linedef types.
|
||||
/// \note A simple shim that prints a warning.
|
||||
#define ESLOPE_TYPESHIM
|
||||
#endif
|
||||
|
||||
/// Delete file while the game is running.
|
||||
/// \note EXTREMELY buggy, tends to crash game.
|
||||
//#define DELFILE
|
||||
|
|
|
@ -92,7 +92,7 @@ typedef long ssize_t;
|
|||
#endif
|
||||
|
||||
#ifdef __APPLE_CC__
|
||||
#define DIRECTFULLSCREEN
|
||||
#define DIRECTFULLSCREEN 1
|
||||
#define DEBUG_LOG
|
||||
#define NOIPX
|
||||
#endif
|
||||
|
|
|
@ -162,6 +162,18 @@ INT32 I_PutEnv(char *variable)
|
|||
return -1;
|
||||
}
|
||||
|
||||
INT32 I_ClipboardCopy(const char *data, size_t size)
|
||||
{
|
||||
(void)data;
|
||||
(void)size;
|
||||
return -1;
|
||||
}
|
||||
|
||||
char *I_ClipboardPaste(void)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void I_RegisterSysCommands(void) {}
|
||||
|
||||
#include "../sdl/dosstr.c"
|
||||
|
|
|
@ -974,7 +974,7 @@ static const char *credits[] = {
|
|||
"Scott \"Graue\" Feeney",
|
||||
"Nathan \"Jazz\" Giroux",
|
||||
"Thomas \"Shadow Hog\" Igoe",
|
||||
"\"Monster\" Iestyn Jealous",
|
||||
"Iestyn \"Monster Iestyn\" Jealous",
|
||||
"Ronald \"Furyhunter\" Kinard", // The SDL2 port
|
||||
"John \"JTE\" Muniz",
|
||||
"Ehab \"Wolfy\" Saeed",
|
||||
|
@ -986,6 +986,8 @@ static const char *credits[] = {
|
|||
"\"chi.miru\"", // Red's secret weapon, the REAL reason slopes exist (also helped port drawing code from ZDoom)
|
||||
"Andrew \"orospakr\" Clunis",
|
||||
"Gregor \"Oogaland\" Dick",
|
||||
"Louis-Antoine \"LJSonic\" de Moulins", // for fixing 2.1's netcode (de Rochefort doesn't quite fit on the screen sorry lol)
|
||||
"Vivian \"toaster\" Grannell",
|
||||
"Julio \"Chaos Zero 64\" Guir",
|
||||
"\"Kalaron\"", // Coded some of Sryder13's collection of OpenGL fixes, especially fog
|
||||
"Matthew \"Shuffle\" Marsalko",
|
||||
|
@ -1019,7 +1021,7 @@ static const char *credits[] = {
|
|||
"Paul \"Boinciel\" Clempson",
|
||||
"Cyan Helkaraxe",
|
||||
"Kepa \"Nev3r\" Iceta",
|
||||
"\"Monster\" Iestyn Jealous",
|
||||
"Iestyn \"Monster Iestyn\" Jealous",
|
||||
"Jarel \"Arrow\" Jones",
|
||||
"Stefan \"Stuf\" Rimalia",
|
||||
"Shane Mychal Sexton",
|
||||
|
@ -1724,6 +1726,7 @@ static void F_AdvanceToNextScene(void)
|
|||
|
||||
void F_EndCutScene(void)
|
||||
{
|
||||
cutsceneover = true; // do this first, just in case Y_EndGame or something wants to turn it back false later
|
||||
if (runningprecutscene)
|
||||
{
|
||||
if (server)
|
||||
|
@ -1740,7 +1743,6 @@ void F_EndCutScene(void)
|
|||
else
|
||||
Y_EndGame();
|
||||
}
|
||||
cutsceneover = true;
|
||||
}
|
||||
|
||||
void F_StartCustomCutscene(INT32 cutscenenum, boolean precutscene, boolean resetplayer)
|
||||
|
|
|
@ -35,7 +35,7 @@ void F_CutsceneTicker(void);
|
|||
void F_TitleDemoTicker(void);
|
||||
|
||||
// Called by main loop.
|
||||
void F_GameEndDrawer(void);
|
||||
FUNCMATH void F_GameEndDrawer(void);
|
||||
void F_IntroDrawer(void);
|
||||
void F_TitleScreenDrawer(void);
|
||||
|
||||
|
|
|
@ -711,6 +711,10 @@ void G_SetGameModified(boolean silent)
|
|||
|
||||
if (!silent)
|
||||
CONS_Alert(CONS_NOTICE, M_GetText("Game must be restarted to record statistics.\n"));
|
||||
|
||||
// If in record attack recording, cancel it.
|
||||
if (modeattacking)
|
||||
M_EndModeAttackRun();
|
||||
}
|
||||
|
||||
/** Builds an original game map name from a map number.
|
||||
|
@ -2884,7 +2888,7 @@ static void G_DoCompleted(void)
|
|||
if (nextmap < NUMMAPS && !mapheaderinfo[nextmap])
|
||||
P_AllocMapHeader(nextmap);
|
||||
|
||||
if (skipstats)
|
||||
if (skipstats && !modeattacking) // Don't skip stats if we're in record attack
|
||||
G_AfterIntermission();
|
||||
else
|
||||
{
|
||||
|
@ -5575,7 +5579,7 @@ boolean G_CheckDemoStatus(void)
|
|||
WRITEUINT8(demo_p, DEMOMARKER); // add the demo end marker
|
||||
md5_buffer((char *)p+16, demo_p - (p+16), p); // make a checksum of everything after the checksum in the file.
|
||||
#endif
|
||||
saved = FIL_WriteFile(demoname, demobuffer, demo_p - demobuffer); // finally output the file.
|
||||
saved = FIL_WriteFile(va(pandf, srb2home, demoname), demobuffer, demo_p - demobuffer); // finally output the file.
|
||||
free(demobuffer);
|
||||
demorecording = false;
|
||||
|
||||
|
|
|
@ -54,7 +54,7 @@
|
|||
#endif
|
||||
#endif
|
||||
|
||||
typedef void (*I_Error_t) (const char *error, ...);
|
||||
typedef void (*I_Error_t) (const char *error, ...) FUNCIERROR;
|
||||
|
||||
// ==========================================================================
|
||||
// MATHS
|
||||
|
|
|
@ -656,6 +656,7 @@ void HWR_DrawFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 color)
|
|||
{
|
||||
FOutVector v[4];
|
||||
FSurfaceInfo Surf;
|
||||
float sdupx, sdupy;
|
||||
|
||||
if (w < 0 || h < 0)
|
||||
return; // consistency w/ software
|
||||
|
@ -664,10 +665,16 @@ void HWR_DrawFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 color)
|
|||
// | /|
|
||||
// |/ |
|
||||
// 0--1
|
||||
v[0].x = v[3].x = (x - 160.0f)/160.0f;
|
||||
v[2].x = v[1].x = ((x+w) - 160.0f)/160.0f;
|
||||
v[0].y = v[1].y = -(y - 100.0f)/100.0f;
|
||||
v[2].y = v[3].y = -((y+h) - 100.0f)/100.0f;
|
||||
sdupx = FIXED_TO_FLOAT(vid.fdupx)*2.0f;
|
||||
sdupy = FIXED_TO_FLOAT(vid.fdupy)*2.0f;
|
||||
|
||||
if (color & V_NOSCALESTART)
|
||||
sdupx = sdupy = 2.0f;
|
||||
|
||||
v[0].x = v[3].x = (x*sdupx)/vid.width - 1;
|
||||
v[2].x = v[1].x = (x*sdupx + w*sdupx)/vid.width - 1;
|
||||
v[0].y = v[1].y = 1-(y*sdupy)/vid.height;
|
||||
v[2].y = v[3].y = 1-(y*sdupy + h*sdupy)/vid.height;
|
||||
|
||||
//Hurdler: do we still use this argb color? if not, we should remove it
|
||||
v[0].argb = v[1].argb = v[2].argb = v[3].argb = 0xff00ff00; //;
|
||||
|
|
|
@ -45,7 +45,7 @@
|
|||
#include "hw_md2.h"
|
||||
|
||||
#define R_FAKEFLOORS
|
||||
//#define HWPRECIP
|
||||
#define HWPRECIP
|
||||
#define SORTING
|
||||
//#define POLYSKY
|
||||
|
||||
|
@ -66,9 +66,9 @@ static void HWR_ProjectPrecipitationSprite(precipmobj_t *thing);
|
|||
#endif
|
||||
|
||||
#ifdef SORTING
|
||||
void HWR_AddTransparentFloor(lumpnum_t lumpnum, extrasubsector_t *xsub, fixed_t fixedheight,
|
||||
void HWR_AddTransparentFloor(lumpnum_t lumpnum, extrasubsector_t *xsub, boolean isceiling, fixed_t fixedheight,
|
||||
INT32 lightlevel, INT32 alpha, sector_t *FOFSector, FBITFIELD blend, boolean fogplane, extracolormap_t *planecolormap);
|
||||
void HWR_AddTransparentPolyobjectFloor(lumpnum_t lumpnum, polyobj_t *polysector, fixed_t fixedheight,
|
||||
void HWR_AddTransparentPolyobjectFloor(lumpnum_t lumpnum, polyobj_t *polysector, boolean isceiling, fixed_t fixedheight,
|
||||
INT32 lightlevel, INT32 alpha, sector_t *FOFSector, FBITFIELD blend, extracolormap_t *planecolormap);
|
||||
#else
|
||||
static void HWR_Add3DWater(lumpnum_t lumpnum, extrasubsector_t *xsub, fixed_t fixedheight,
|
||||
|
@ -521,7 +521,7 @@ static UINT8 HWR_FogBlockAlpha(INT32 light, UINT32 color, UINT32 fadecolor) // L
|
|||
// -----------------+
|
||||
// HWR_RenderPlane : Render a floor or ceiling convex polygon
|
||||
// -----------------+
|
||||
static void HWR_RenderPlane(sector_t *sector, extrasubsector_t *xsub, fixed_t fixedheight,
|
||||
static void HWR_RenderPlane(sector_t *sector, extrasubsector_t *xsub, boolean isceiling, fixed_t fixedheight,
|
||||
FBITFIELD PolyFlags, INT32 lightlevel, lumpnum_t lumpnum, sector_t *FOFsector, UINT8 alpha, boolean fogplane, extracolormap_t *planecolormap)
|
||||
{
|
||||
polyvertex_t * pv;
|
||||
|
@ -554,17 +554,16 @@ static void HWR_RenderPlane(sector_t *sector, extrasubsector_t *xsub, fixed_t fi
|
|||
// Get the slope pointer to simplify future code
|
||||
if (FOFsector)
|
||||
{
|
||||
if (FOFsector->f_slope && FOFsector->floorheight == fixedheight)
|
||||
if (FOFsector->f_slope && !isceiling)
|
||||
slope = FOFsector->f_slope;
|
||||
else if (FOFsector->c_slope && FOFsector->ceilingheight == fixedheight)
|
||||
else if (FOFsector->c_slope && isceiling)
|
||||
slope = FOFsector->c_slope;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Use fixedheight to determine whether to check floor or ceiling because I hate my life
|
||||
if (gr_frontsector->f_slope && gr_frontsector->floorheight == fixedheight)
|
||||
if (gr_frontsector->f_slope && !isceiling)
|
||||
slope = gr_frontsector->f_slope;
|
||||
else if (gr_frontsector->c_slope && gr_frontsector->ceilingheight == fixedheight)
|
||||
else if (gr_frontsector->c_slope && isceiling)
|
||||
slope = gr_frontsector->c_slope;
|
||||
}
|
||||
|
||||
|
@ -638,12 +637,7 @@ static void HWR_RenderPlane(sector_t *sector, extrasubsector_t *xsub, fixed_t fi
|
|||
|
||||
if (FOFsector != NULL)
|
||||
{
|
||||
#ifdef ESLOPE
|
||||
if ((slope && slope == FOFsector->f_slope)
|
||||
|| fixedheight == FOFsector->floorheight) // it's a floor
|
||||
#else
|
||||
if (fixedheight == FOFsector->floorheight) // it's a floor
|
||||
#endif
|
||||
if (!isceiling) // it's a floor
|
||||
{
|
||||
scrollx = FIXED_TO_FLOAT(FOFsector->floor_xoffs)/fflatsize;
|
||||
scrolly = FIXED_TO_FLOAT(FOFsector->floor_yoffs)/fflatsize;
|
||||
|
@ -658,12 +652,7 @@ static void HWR_RenderPlane(sector_t *sector, extrasubsector_t *xsub, fixed_t fi
|
|||
}
|
||||
else if (gr_frontsector)
|
||||
{
|
||||
#ifdef ESLOPE
|
||||
if ((slope && slope == gr_frontsector->f_slope)
|
||||
|| fixedheight == gr_frontsector->floorheight) // it's a floor
|
||||
#else
|
||||
if (fixedheight < dup_viewz) // it's a floor
|
||||
#endif
|
||||
if (!isceiling) // it's a floor
|
||||
{
|
||||
scrollx = FIXED_TO_FLOAT(gr_frontsector->floor_xoffs)/fflatsize;
|
||||
scrolly = FIXED_TO_FLOAT(gr_frontsector->floor_yoffs)/fflatsize;
|
||||
|
@ -1095,9 +1084,9 @@ static void HWR_SplitWall(sector_t *sector, wallVert3D *wallVerts, INT32 texnum,
|
|||
float endheight = 0.0f, endbheight = 0.0f;
|
||||
|
||||
fixed_t v1x = FLOAT_TO_FIXED(wallVerts[0].x);
|
||||
fixed_t v1y = FLOAT_TO_FIXED(wallVerts[0].y);
|
||||
fixed_t v1y = FLOAT_TO_FIXED(wallVerts[0].z); // not a typo
|
||||
fixed_t v2x = FLOAT_TO_FIXED(wallVerts[1].x);
|
||||
fixed_t v2y = FLOAT_TO_FIXED(wallVerts[1].y);
|
||||
fixed_t v2y = FLOAT_TO_FIXED(wallVerts[1].z); // not a typo
|
||||
// compiler complains when P_GetZAt is used in FLOAT_TO_FIXED directly
|
||||
// use this as a temp var to store P_GetZAt's return value each time
|
||||
fixed_t temp;
|
||||
|
@ -1569,6 +1558,7 @@ static void HWR_StoreWallRange(double startfrac, double endfrac)
|
|||
|
||||
if (gr_backsector)
|
||||
{
|
||||
INT32 gr_toptexture, gr_bottomtexture;
|
||||
// two sided line
|
||||
if (gr_backsector->heightsec != -1)
|
||||
{
|
||||
|
@ -1619,19 +1609,22 @@ static void HWR_StoreWallRange(double startfrac, double endfrac)
|
|||
#endif
|
||||
}
|
||||
|
||||
gr_toptexture = R_GetTextureNum(gr_sidedef->toptexture);
|
||||
gr_bottomtexture = R_GetTextureNum(gr_sidedef->bottomtexture);
|
||||
|
||||
// check TOP TEXTURE
|
||||
if ((
|
||||
#ifdef ESLOPE
|
||||
worldhighslope < worldtopslope ||
|
||||
#endif
|
||||
worldhigh < worldtop
|
||||
) && texturetranslation[gr_sidedef->toptexture])
|
||||
) && gr_toptexture)
|
||||
{
|
||||
if (drawtextured)
|
||||
{
|
||||
fixed_t texturevpegtop; // top
|
||||
|
||||
grTex = HWR_GetTexture(texturetranslation[gr_sidedef->toptexture]);
|
||||
grTex = HWR_GetTexture(gr_toptexture);
|
||||
|
||||
// PEGGING
|
||||
if (gr_linedef->flags & ML_DONTPEGTOP)
|
||||
|
@ -1649,7 +1642,7 @@ static void HWR_StoreWallRange(double startfrac, double endfrac)
|
|||
texturevpegtop += gr_sidedef->rowoffset;
|
||||
|
||||
// This is so that it doesn't overflow and screw up the wall, it doesn't need to go higher than the texture's height anyway
|
||||
texturevpegtop %= SHORT(textures[texturetranslation[gr_sidedef->toptexture]]->height)<<FRACBITS;
|
||||
texturevpegtop %= SHORT(textures[gr_toptexture]->height)<<FRACBITS;
|
||||
|
||||
wallVerts[3].t = wallVerts[2].t = texturevpegtop * grTex->scaleY;
|
||||
wallVerts[0].t = wallVerts[1].t = (texturevpegtop + gr_frontsector->ceilingheight - gr_backsector->ceilingheight) * grTex->scaleY;
|
||||
|
@ -1694,9 +1687,9 @@ static void HWR_StoreWallRange(double startfrac, double endfrac)
|
|||
#endif
|
||||
|
||||
if (gr_frontsector->numlights)
|
||||
HWR_SplitWall(gr_frontsector, wallVerts, texturetranslation[gr_sidedef->toptexture], &Surf, FF_CUTSOLIDS);
|
||||
HWR_SplitWall(gr_frontsector, wallVerts, gr_toptexture, &Surf, FF_CUTSOLIDS);
|
||||
else if (grTex->mipmap.flags & TF_TRANSPARENT)
|
||||
HWR_AddTransparentWall(wallVerts, &Surf, texturetranslation[gr_sidedef->toptexture], PF_Environment, false, lightnum, colormap);
|
||||
HWR_AddTransparentWall(wallVerts, &Surf, gr_toptexture, PF_Environment, false, lightnum, colormap);
|
||||
else
|
||||
HWR_ProjectWall(wallVerts, &Surf, PF_Masked, lightnum, colormap);
|
||||
}
|
||||
|
@ -1706,13 +1699,13 @@ static void HWR_StoreWallRange(double startfrac, double endfrac)
|
|||
#ifdef ESLOPE
|
||||
worldlowslope > worldbottomslope ||
|
||||
#endif
|
||||
worldlow > worldbottom) && texturetranslation[gr_sidedef->bottomtexture]) //only if VISIBLE!!!
|
||||
worldlow > worldbottom) && gr_bottomtexture) //only if VISIBLE!!!
|
||||
{
|
||||
if (drawtextured)
|
||||
{
|
||||
fixed_t texturevpegbottom = 0; // bottom
|
||||
|
||||
grTex = HWR_GetTexture(texturetranslation[gr_sidedef->bottomtexture]);
|
||||
grTex = HWR_GetTexture(gr_bottomtexture);
|
||||
|
||||
// PEGGING
|
||||
#ifdef ESLOPE
|
||||
|
@ -1732,7 +1725,7 @@ static void HWR_StoreWallRange(double startfrac, double endfrac)
|
|||
texturevpegbottom += gr_sidedef->rowoffset;
|
||||
|
||||
// This is so that it doesn't overflow and screw up the wall, it doesn't need to go higher than the texture's height anyway
|
||||
texturevpegbottom %= SHORT(textures[texturetranslation[gr_sidedef->bottomtexture]]->height)<<FRACBITS;
|
||||
texturevpegbottom %= SHORT(textures[gr_bottomtexture]->height)<<FRACBITS;
|
||||
|
||||
wallVerts[3].t = wallVerts[2].t = texturevpegbottom * grTex->scaleY;
|
||||
wallVerts[0].t = wallVerts[1].t = (texturevpegbottom + gr_backsector->floorheight - gr_frontsector->floorheight) * grTex->scaleY;
|
||||
|
@ -1777,13 +1770,13 @@ static void HWR_StoreWallRange(double startfrac, double endfrac)
|
|||
#endif
|
||||
|
||||
if (gr_frontsector->numlights)
|
||||
HWR_SplitWall(gr_frontsector, wallVerts, texturetranslation[gr_sidedef->bottomtexture], &Surf, FF_CUTSOLIDS);
|
||||
HWR_SplitWall(gr_frontsector, wallVerts, gr_bottomtexture, &Surf, FF_CUTSOLIDS);
|
||||
else if (grTex->mipmap.flags & TF_TRANSPARENT)
|
||||
HWR_AddTransparentWall(wallVerts, &Surf, texturetranslation[gr_sidedef->bottomtexture], PF_Environment, false, lightnum, colormap);
|
||||
HWR_AddTransparentWall(wallVerts, &Surf, gr_bottomtexture, PF_Environment, false, lightnum, colormap);
|
||||
else
|
||||
HWR_ProjectWall(wallVerts, &Surf, PF_Masked, lightnum, colormap);
|
||||
}
|
||||
gr_midtexture = texturetranslation[gr_sidedef->midtexture];
|
||||
gr_midtexture = R_GetTextureNum(gr_sidedef->midtexture);
|
||||
if (gr_midtexture)
|
||||
{
|
||||
FBITFIELD blendmode;
|
||||
|
@ -2145,7 +2138,7 @@ static void HWR_StoreWallRange(double startfrac, double endfrac)
|
|||
else
|
||||
{
|
||||
// Single sided line... Deal only with the middletexture (if one exists)
|
||||
gr_midtexture = texturetranslation[gr_sidedef->midtexture];
|
||||
gr_midtexture = R_GetTextureNum(gr_sidedef->midtexture);
|
||||
if (gr_midtexture)
|
||||
{
|
||||
if (drawtextured)
|
||||
|
@ -2243,13 +2236,13 @@ static void HWR_StoreWallRange(double startfrac, double endfrac)
|
|||
if (*rover->topheight < lowcut || *rover->bottomheight > highcut)
|
||||
continue;
|
||||
|
||||
texnum = texturetranslation[sides[rover->master->sidenum[0]].midtexture];
|
||||
texnum = R_GetTextureNum(sides[rover->master->sidenum[0]].midtexture);
|
||||
|
||||
if (rover->master->flags & ML_TFERLINE)
|
||||
{
|
||||
size_t linenum = gr_curline->linedef-gr_backsector->lines[0];
|
||||
newline = rover->master->frontsector->lines[0] + linenum;
|
||||
texnum = texturetranslation[sides[newline->sidenum[0]].midtexture];
|
||||
texnum = R_GetTextureNum(sides[newline->sidenum[0]].midtexture);
|
||||
}
|
||||
|
||||
#ifdef ESLOPE
|
||||
|
@ -2377,13 +2370,13 @@ static void HWR_StoreWallRange(double startfrac, double endfrac)
|
|||
if (*rover->topheight < lowcut || *rover->bottomheight > highcut)
|
||||
continue;
|
||||
|
||||
texnum = texturetranslation[sides[rover->master->sidenum[0]].midtexture];
|
||||
texnum = R_GetTextureNum(sides[rover->master->sidenum[0]].midtexture);
|
||||
|
||||
if (rover->master->flags & ML_TFERLINE)
|
||||
{
|
||||
size_t linenum = gr_curline->linedef-gr_backsector->lines[0];
|
||||
newline = rover->master->frontsector->lines[0] + linenum;
|
||||
texnum = texturetranslation[sides[newline->sidenum[0]].midtexture];
|
||||
texnum = R_GetTextureNum(sides[newline->sidenum[0]].midtexture);
|
||||
}
|
||||
#ifdef ESLOPE //backsides
|
||||
h = *rover->t_slope ? P_GetZAt(*rover->t_slope, v1x, v1y) : *rover->topheight;
|
||||
|
@ -3111,7 +3104,7 @@ static inline void HWR_AddPolyObjectSegs(void)
|
|||
}
|
||||
|
||||
#ifdef POLYOBJECTS_PLANES
|
||||
static void HWR_RenderPolyObjectPlane(polyobj_t *polysector, fixed_t fixedheight,
|
||||
static void HWR_RenderPolyObjectPlane(polyobj_t *polysector, boolean isceiling, fixed_t fixedheight,
|
||||
FBITFIELD blendmode, UINT8 lightlevel, lumpnum_t lumpnum, sector_t *FOFsector,
|
||||
UINT8 alpha, extracolormap_t *planecolormap)
|
||||
{
|
||||
|
@ -3195,7 +3188,7 @@ static void HWR_RenderPolyObjectPlane(polyobj_t *polysector, fixed_t fixedheight
|
|||
|
||||
if (FOFsector != NULL)
|
||||
{
|
||||
if (fixedheight == FOFsector->floorheight) // it's a floor
|
||||
if (!isceiling) // it's a floor
|
||||
{
|
||||
scrollx = FIXED_TO_FLOAT(FOFsector->floor_xoffs)/fflatsize;
|
||||
scrolly = FIXED_TO_FLOAT(FOFsector->floor_yoffs)/fflatsize;
|
||||
|
@ -3210,7 +3203,7 @@ static void HWR_RenderPolyObjectPlane(polyobj_t *polysector, fixed_t fixedheight
|
|||
}
|
||||
else if (gr_frontsector)
|
||||
{
|
||||
if (fixedheight < dup_viewz) // it's a floor
|
||||
if (!isceiling) // it's a floor
|
||||
{
|
||||
scrollx = FIXED_TO_FLOAT(gr_frontsector->floor_xoffs)/fflatsize;
|
||||
scrolly = FIXED_TO_FLOAT(gr_frontsector->floor_yoffs)/fflatsize;
|
||||
|
@ -3303,13 +3296,13 @@ static void HWR_AddPolyObjectPlanes(void)
|
|||
{
|
||||
FSurfaceInfo Surf;
|
||||
FBITFIELD blendmode = HWR_TranstableToAlpha(po_ptrs[i]->translucency, &Surf);
|
||||
HWR_AddTransparentPolyobjectFloor(levelflats[polyobjsector->floorpic].lumpnum, po_ptrs[i], polyobjsector->floorheight,
|
||||
HWR_AddTransparentPolyobjectFloor(levelflats[polyobjsector->floorpic].lumpnum, po_ptrs[i], false, polyobjsector->floorheight,
|
||||
polyobjsector->lightlevel, Surf.FlatColor.s.alpha, polyobjsector, blendmode, NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
HWR_GetFlat(levelflats[polyobjsector->floorpic].lumpnum);
|
||||
HWR_RenderPolyObjectPlane(po_ptrs[i], polyobjsector->floorheight, PF_Occlude,
|
||||
HWR_RenderPolyObjectPlane(po_ptrs[i], false, polyobjsector->floorheight, PF_Occlude,
|
||||
polyobjsector->lightlevel, levelflats[polyobjsector->floorpic].lumpnum,
|
||||
polyobjsector, 255, NULL);
|
||||
}
|
||||
|
@ -3325,13 +3318,13 @@ static void HWR_AddPolyObjectPlanes(void)
|
|||
FBITFIELD blendmode;
|
||||
memset(&Surf, 0x00, sizeof(Surf));
|
||||
blendmode = HWR_TranstableToAlpha(po_ptrs[i]->translucency, &Surf);
|
||||
HWR_AddTransparentPolyobjectFloor(levelflats[polyobjsector->ceilingpic].lumpnum, po_ptrs[i], polyobjsector->ceilingheight,
|
||||
HWR_AddTransparentPolyobjectFloor(levelflats[polyobjsector->ceilingpic].lumpnum, po_ptrs[i], true, polyobjsector->ceilingheight,
|
||||
polyobjsector->lightlevel, Surf.FlatColor.s.alpha, polyobjsector, blendmode, NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
HWR_GetFlat(levelflats[polyobjsector->ceilingpic].lumpnum);
|
||||
HWR_RenderPolyObjectPlane(po_ptrs[i], polyobjsector->ceilingheight, PF_Occlude,
|
||||
HWR_RenderPolyObjectPlane(po_ptrs[i], true, polyobjsector->ceilingheight, PF_Occlude,
|
||||
polyobjsector->lightlevel, levelflats[polyobjsector->floorpic].lumpnum,
|
||||
polyobjsector, 255, NULL);
|
||||
}
|
||||
|
@ -3485,7 +3478,7 @@ static void HWR_Subsector(size_t num)
|
|||
if (sub->validcount != validcount)
|
||||
{
|
||||
HWR_GetFlat(levelflats[gr_frontsector->floorpic].lumpnum);
|
||||
HWR_RenderPlane(gr_frontsector, &extrasubsectors[num],
|
||||
HWR_RenderPlane(gr_frontsector, &extrasubsectors[num], false,
|
||||
// Hack to make things continue to work around slopes.
|
||||
locFloorHeight == cullFloorHeight ? locFloorHeight : gr_frontsector->floorheight,
|
||||
// We now return you to your regularly scheduled rendering.
|
||||
|
@ -3507,7 +3500,7 @@ static void HWR_Subsector(size_t num)
|
|||
if (sub->validcount != validcount)
|
||||
{
|
||||
HWR_GetFlat(levelflats[gr_frontsector->ceilingpic].lumpnum);
|
||||
HWR_RenderPlane(NULL, &extrasubsectors[num],
|
||||
HWR_RenderPlane(NULL, &extrasubsectors[num], true,
|
||||
// Hack to make things continue to work around slopes.
|
||||
locCeilingHeight == cullCeilingHeight ? locCeilingHeight : gr_frontsector->ceilingheight,
|
||||
// We now return you to your regularly scheduled rendering.
|
||||
|
@ -3576,6 +3569,7 @@ static void HWR_Subsector(size_t num)
|
|||
|
||||
HWR_AddTransparentFloor(0,
|
||||
&extrasubsectors[num],
|
||||
false,
|
||||
*rover->bottomheight,
|
||||
*gr_frontsector->lightlist[light].lightlevel,
|
||||
alpha, rover->master->frontsector, PF_Translucent|PF_NoTexture,
|
||||
|
@ -3593,6 +3587,7 @@ static void HWR_Subsector(size_t num)
|
|||
#else
|
||||
HWR_AddTransparentFloor(levelflats[*rover->bottompic].lumpnum,
|
||||
&extrasubsectors[num],
|
||||
false,
|
||||
*rover->bottomheight,
|
||||
*gr_frontsector->lightlist[light].lightlevel,
|
||||
rover->alpha-1 > 255 ? 255 : rover->alpha-1, rover->master->frontsector, PF_Translucent,
|
||||
|
@ -3603,7 +3598,7 @@ static void HWR_Subsector(size_t num)
|
|||
{
|
||||
HWR_GetFlat(levelflats[*rover->bottompic].lumpnum);
|
||||
light = R_GetPlaneLight(gr_frontsector, centerHeight, dup_viewz < cullHeight ? true : false);
|
||||
HWR_RenderPlane(NULL, &extrasubsectors[num], *rover->bottomheight, PF_Occlude, *gr_frontsector->lightlist[light].lightlevel, levelflats[*rover->bottompic].lumpnum,
|
||||
HWR_RenderPlane(NULL, &extrasubsectors[num], false, *rover->bottomheight, PF_Occlude, *gr_frontsector->lightlist[light].lightlevel, levelflats[*rover->bottompic].lumpnum,
|
||||
rover->master->frontsector, 255, false, gr_frontsector->lightlist[light].extra_colormap);
|
||||
}
|
||||
}
|
||||
|
@ -3637,6 +3632,7 @@ static void HWR_Subsector(size_t num)
|
|||
|
||||
HWR_AddTransparentFloor(0,
|
||||
&extrasubsectors[num],
|
||||
true,
|
||||
*rover->topheight,
|
||||
*gr_frontsector->lightlist[light].lightlevel,
|
||||
alpha, rover->master->frontsector, PF_Translucent|PF_NoTexture,
|
||||
|
@ -3654,6 +3650,7 @@ static void HWR_Subsector(size_t num)
|
|||
#else
|
||||
HWR_AddTransparentFloor(levelflats[*rover->toppic].lumpnum,
|
||||
&extrasubsectors[num],
|
||||
true,
|
||||
*rover->topheight,
|
||||
*gr_frontsector->lightlist[light].lightlevel,
|
||||
rover->alpha-1 > 255 ? 255 : rover->alpha-1, rover->master->frontsector, PF_Translucent,
|
||||
|
@ -3665,7 +3662,7 @@ static void HWR_Subsector(size_t num)
|
|||
{
|
||||
HWR_GetFlat(levelflats[*rover->toppic].lumpnum);
|
||||
light = R_GetPlaneLight(gr_frontsector, centerHeight, dup_viewz < cullHeight ? true : false);
|
||||
HWR_RenderPlane(NULL, &extrasubsectors[num], *rover->topheight, PF_Occlude, *gr_frontsector->lightlist[light].lightlevel, levelflats[*rover->toppic].lumpnum,
|
||||
HWR_RenderPlane(NULL, &extrasubsectors[num], true, *rover->topheight, PF_Occlude, *gr_frontsector->lightlist[light].lightlevel, levelflats[*rover->toppic].lumpnum,
|
||||
rover->master->frontsector, 255, false, gr_frontsector->lightlist[light].extra_colormap);
|
||||
}
|
||||
}
|
||||
|
@ -3725,6 +3722,9 @@ static void HWR_Subsector(size_t num)
|
|||
|
||||
while (count--)
|
||||
{
|
||||
#ifdef POLYOBJECTS
|
||||
if (!line->polyseg) // ignore segs that belong to polyobjects
|
||||
#endif
|
||||
HWR_AddLine(line);
|
||||
line++;
|
||||
}
|
||||
|
@ -4408,7 +4408,6 @@ static inline void HWR_DrawPrecipitationSprite(gr_vissprite_t *spr)
|
|||
FOutVector *wv;
|
||||
GLPatch_t *gpatch; // sprite patch converted to hardware
|
||||
FSurfaceInfo Surf;
|
||||
sector_t *sector;
|
||||
|
||||
if (!spr->mobj)
|
||||
return;
|
||||
|
@ -4462,19 +4461,38 @@ static inline void HWR_DrawPrecipitationSprite(gr_vissprite_t *spr)
|
|||
//Hurdler: 25/04/2000: now support colormap in hardware mode
|
||||
HWR_GetMappedPatch(gpatch, spr->colormap);
|
||||
|
||||
sector = spr->mobj->subsector->sector;
|
||||
|
||||
if (sector->ffloors)
|
||||
// colormap test
|
||||
{
|
||||
ffloor_t *caster = sector->lightlist[R_GetPlaneLight(sector, spr->mobj->z, false)].caster;
|
||||
sector = caster ? §ors[caster->secnum] : sector;
|
||||
}
|
||||
sector_t *sector = spr->mobj->subsector->sector;
|
||||
UINT8 lightlevel = 255;
|
||||
extracolormap_t *colormap = sector->extra_colormap;
|
||||
|
||||
// sprite lighting by modulating the RGB components
|
||||
if (sector->extra_colormap)
|
||||
Surf.FlatColor.rgba = HWR_Lighting(spr->sectorlight,sector->extra_colormap->rgba,sector->extra_colormap->fadergba, false, false);
|
||||
if (sector->numlights)
|
||||
{
|
||||
INT32 light;
|
||||
|
||||
light = R_GetPlaneLight(sector, spr->mobj->z + spr->mobj->height, false); // Always use the light at the top instead of whatever I was doing before
|
||||
|
||||
if (!(spr->mobj->frame & FF_FULLBRIGHT))
|
||||
lightlevel = *sector->lightlist[light].lightlevel;
|
||||
|
||||
if (sector->lightlist[light].extra_colormap)
|
||||
colormap = sector->lightlist[light].extra_colormap;
|
||||
}
|
||||
else
|
||||
Surf.FlatColor.rgba = HWR_Lighting(spr->sectorlight,NORMALFOG,FADEFOG, false, false);
|
||||
{
|
||||
if (!(spr->mobj->frame & FF_FULLBRIGHT))
|
||||
lightlevel = sector->lightlevel;
|
||||
|
||||
if (sector->extra_colormap)
|
||||
colormap = sector->extra_colormap;
|
||||
}
|
||||
|
||||
if (colormap)
|
||||
Surf.FlatColor.rgba = HWR_Lighting(lightlevel, colormap->rgba, colormap->fadergba, false, false);
|
||||
else
|
||||
Surf.FlatColor.rgba = HWR_Lighting(lightlevel, NORMALFOG, FADEFOG, false, false);
|
||||
}
|
||||
|
||||
if (spr->mobj->flags2 & MF2_SHADOW)
|
||||
{
|
||||
|
@ -4508,8 +4526,8 @@ static void HWR_SortVisSprites(void)
|
|||
gr_vissprite_t *ds, *dsprev, *dsnext, *dsfirst;
|
||||
gr_vissprite_t *best = NULL;
|
||||
gr_vissprite_t unsorted;
|
||||
float bestdist;
|
||||
INT32 bestdispoffset;
|
||||
float bestdist = 0.0f;
|
||||
INT32 bestdispoffset = 0;
|
||||
|
||||
if (!gr_visspritecount)
|
||||
return;
|
||||
|
@ -4529,7 +4547,8 @@ static void HWR_SortVisSprites(void)
|
|||
// Fix first and last. ds still points to the last one after the loop
|
||||
dsfirst->prev = &unsorted;
|
||||
unsorted.next = dsfirst;
|
||||
ds->next = &unsorted;
|
||||
if (ds)
|
||||
ds->next = &unsorted;
|
||||
unsorted.prev = ds;
|
||||
|
||||
// pull the vissprites out by scale
|
||||
|
@ -4552,10 +4571,13 @@ static void HWR_SortVisSprites(void)
|
|||
best = ds;
|
||||
}
|
||||
}
|
||||
best->next->prev = best->prev;
|
||||
best->prev->next = best->next;
|
||||
best->next = &gr_vsprsortedhead;
|
||||
best->prev = gr_vsprsortedhead.prev;
|
||||
if (best)
|
||||
{
|
||||
best->next->prev = best->prev;
|
||||
best->prev->next = best->next;
|
||||
best->next = &gr_vsprsortedhead;
|
||||
best->prev = gr_vsprsortedhead.prev;
|
||||
}
|
||||
gr_vsprsortedhead.prev->next = best;
|
||||
gr_vsprsortedhead.prev = best;
|
||||
}
|
||||
|
@ -4588,6 +4610,7 @@ static void HWR_RenderWall(wallVert3D *wallVerts, FSurfaceInfo *pSurf, FBITFIE
|
|||
typedef struct
|
||||
{
|
||||
extrasubsector_t *xsub;
|
||||
boolean isceiling;
|
||||
fixed_t fixedheight;
|
||||
INT32 lightlevel;
|
||||
lumpnum_t lumpnum;
|
||||
|
@ -4605,6 +4628,7 @@ static planeinfo_t *planeinfo = NULL;
|
|||
typedef struct
|
||||
{
|
||||
polyobj_t *polysector;
|
||||
boolean isceiling;
|
||||
fixed_t fixedheight;
|
||||
INT32 lightlevel;
|
||||
lumpnum_t lumpnum;
|
||||
|
@ -4640,7 +4664,7 @@ static INT32 drawcount = 0;
|
|||
#define MAX_TRANSPARENTFLOOR 512
|
||||
|
||||
// This will likely turn into a copy of HWR_Add3DWater and replace it.
|
||||
void HWR_AddTransparentFloor(lumpnum_t lumpnum, extrasubsector_t *xsub,
|
||||
void HWR_AddTransparentFloor(lumpnum_t lumpnum, extrasubsector_t *xsub, boolean isceiling,
|
||||
fixed_t fixedheight, INT32 lightlevel, INT32 alpha, sector_t *FOFSector, FBITFIELD blend, boolean fogplane, extracolormap_t *planecolormap)
|
||||
{
|
||||
static size_t allocedplanes = 0;
|
||||
|
@ -4655,6 +4679,7 @@ void HWR_AddTransparentFloor(lumpnum_t lumpnum, extrasubsector_t *xsub,
|
|||
Z_Realloc(planeinfo, allocedplanes * sizeof (*planeinfo), PU_LEVEL, &planeinfo);
|
||||
}
|
||||
|
||||
planeinfo[numplanes].isceiling = isceiling;
|
||||
planeinfo[numplanes].fixedheight = fixedheight;
|
||||
planeinfo[numplanes].lightlevel = lightlevel;
|
||||
planeinfo[numplanes].lumpnum = lumpnum;
|
||||
|
@ -4665,12 +4690,13 @@ void HWR_AddTransparentFloor(lumpnum_t lumpnum, extrasubsector_t *xsub,
|
|||
planeinfo[numplanes].fogplane = fogplane;
|
||||
planeinfo[numplanes].planecolormap = planecolormap;
|
||||
planeinfo[numplanes].drawcount = drawcount++;
|
||||
|
||||
numplanes++;
|
||||
}
|
||||
|
||||
// Adding this for now until I can create extrasubsector info for polyobjects
|
||||
// When that happens it'll just be done through HWR_AddTransparentFloor and HWR_RenderPlane
|
||||
void HWR_AddTransparentPolyobjectFloor(lumpnum_t lumpnum, polyobj_t *polysector,
|
||||
void HWR_AddTransparentPolyobjectFloor(lumpnum_t lumpnum, polyobj_t *polysector, boolean isceiling,
|
||||
fixed_t fixedheight, INT32 lightlevel, INT32 alpha, sector_t *FOFSector, FBITFIELD blend, extracolormap_t *planecolormap)
|
||||
{
|
||||
static size_t allocedpolyplanes = 0;
|
||||
|
@ -4685,6 +4711,7 @@ void HWR_AddTransparentPolyobjectFloor(lumpnum_t lumpnum, polyobj_t *polysector,
|
|||
Z_Realloc(polyplaneinfo, allocedpolyplanes * sizeof (*polyplaneinfo), PU_LEVEL, &polyplaneinfo);
|
||||
}
|
||||
|
||||
polyplaneinfo[numpolyplanes].isceiling = isceiling;
|
||||
polyplaneinfo[numpolyplanes].fixedheight = fixedheight;
|
||||
polyplaneinfo[numpolyplanes].lightlevel = lightlevel;
|
||||
polyplaneinfo[numpolyplanes].lumpnum = lumpnum;
|
||||
|
@ -4850,7 +4877,7 @@ static void HWR_CreateDrawNodes(void)
|
|||
|
||||
if (!(sortnode[sortindex[i]].plane->blend & PF_NoTexture))
|
||||
HWR_GetFlat(sortnode[sortindex[i]].plane->lumpnum);
|
||||
HWR_RenderPlane(NULL, sortnode[sortindex[i]].plane->xsub, sortnode[sortindex[i]].plane->fixedheight, sortnode[sortindex[i]].plane->blend, sortnode[sortindex[i]].plane->lightlevel,
|
||||
HWR_RenderPlane(NULL, sortnode[sortindex[i]].plane->xsub, sortnode[sortindex[i]].plane->isceiling, sortnode[sortindex[i]].plane->fixedheight, sortnode[sortindex[i]].plane->blend, sortnode[sortindex[i]].plane->lightlevel,
|
||||
sortnode[sortindex[i]].plane->lumpnum, sortnode[sortindex[i]].plane->FOFSector, sortnode[sortindex[i]].plane->alpha, sortnode[sortindex[i]].plane->fogplane, sortnode[sortindex[i]].plane->planecolormap);
|
||||
}
|
||||
else if (sortnode[sortindex[i]].polyplane)
|
||||
|
@ -4860,7 +4887,7 @@ static void HWR_CreateDrawNodes(void)
|
|||
|
||||
if (!(sortnode[sortindex[i]].polyplane->blend & PF_NoTexture))
|
||||
HWR_GetFlat(sortnode[sortindex[i]].polyplane->lumpnum);
|
||||
HWR_RenderPolyObjectPlane(sortnode[sortindex[i]].polyplane->polysector, sortnode[sortindex[i]].polyplane->fixedheight, sortnode[sortindex[i]].polyplane->blend, sortnode[sortindex[i]].polyplane->lightlevel,
|
||||
HWR_RenderPolyObjectPlane(sortnode[sortindex[i]].polyplane->polysector, sortnode[sortindex[i]].polyplane->isceiling, sortnode[sortindex[i]].polyplane->fixedheight, sortnode[sortindex[i]].polyplane->blend, sortnode[sortindex[i]].polyplane->lightlevel,
|
||||
sortnode[sortindex[i]].polyplane->lumpnum, sortnode[sortindex[i]].polyplane->FOFSector, sortnode[sortindex[i]].polyplane->alpha, sortnode[sortindex[i]].polyplane->planecolormap);
|
||||
}
|
||||
else if (sortnode[sortindex[i]].wall)
|
||||
|
@ -5287,6 +5314,11 @@ static void HWR_ProjectPrecipitationSprite(precipmobj_t *thing)
|
|||
//
|
||||
vis = HWR_NewVisSprite();
|
||||
vis->x1 = x1;
|
||||
#if 0
|
||||
vis->x2 = x2;
|
||||
#else
|
||||
(void)x2;
|
||||
#endif
|
||||
vis->x2 = tx;
|
||||
vis->tz = tz;
|
||||
vis->dispoffset = 0; // Monster Iestyn: 23/11/15: HARDWARE SUPPORT AT LAST
|
||||
|
@ -5299,7 +5331,6 @@ static void HWR_ProjectPrecipitationSprite(precipmobj_t *thing)
|
|||
// set top/bottom coords
|
||||
vis->ty = FIXED_TO_FLOAT(thing->z + spritecachedinfo[lumpoff].topoffset) - gr_viewz;
|
||||
|
||||
vis->sectorlight = 0xff;
|
||||
vis->precip = true;
|
||||
}
|
||||
#endif
|
||||
|
@ -6157,7 +6188,7 @@ static void HWR_Render3DWater(void)
|
|||
for (i = 0; i < numfloors; i++)
|
||||
{
|
||||
HWR_GetFlat(planeinfo[i].lumpnum);
|
||||
HWR_RenderPlane(NULL, planeinfo[i].xsub, planeinfo[i].fixedheight, PF_Translucent, planeinfo[i].lightlevel, planeinfo[i].lumpnum,
|
||||
HWR_RenderPlane(NULL, planeinfo[i].xsub, planeinfo[i].isceiling, planeinfo[i].fixedheight, PF_Translucent, planeinfo[i].lightlevel, planeinfo[i].lumpnum,
|
||||
planeinfo[i].FOFSector, planeinfo[i].alpha, planeinfo[i].fogplane, planeinfo[i].planecolormap);
|
||||
}
|
||||
numfloors = 0;
|
||||
|
|
|
@ -308,6 +308,23 @@ static md2_model_t *md2_readModel(const char *filename)
|
|||
|
||||
model->header.numSkins = 1;
|
||||
|
||||
#define MD2LIMITCHECK(field, max, msgname) \
|
||||
if (field > max) \
|
||||
{ \
|
||||
CONS_Alert(CONS_ERROR, "md2_readModel: %s has too many " msgname " (# found: %d, maximum: %d)\n", filename, field, max); \
|
||||
md2_freeModel (model); \
|
||||
return 0; \
|
||||
}
|
||||
|
||||
// Uncomment if these are actually needed
|
||||
// MD2LIMITCHECK(model->header.numSkins, MD2_MAX_SKINS, "skins")
|
||||
// MD2LIMITCHECK(model->header.numTexCoords, MD2_MAX_TEXCOORDS, "texture coordinates")
|
||||
MD2LIMITCHECK(model->header.numTriangles, MD2_MAX_TRIANGLES, "triangles")
|
||||
MD2LIMITCHECK(model->header.numFrames, MD2_MAX_FRAMES, "frames")
|
||||
MD2LIMITCHECK(model->header.numVertices, MD2_MAX_VERTICES, "vertices")
|
||||
|
||||
#undef MD2LIMITCHECK
|
||||
|
||||
// read skins
|
||||
fseek(file, model->header.offsetSkins, SEEK_SET);
|
||||
if (model->header.numSkins > 0)
|
||||
|
@ -319,8 +336,6 @@ static md2_model_t *md2_readModel(const char *filename)
|
|||
md2_freeModel (model);
|
||||
return 0;
|
||||
}
|
||||
|
||||
;
|
||||
}
|
||||
|
||||
// read texture coordinates
|
||||
|
@ -334,8 +349,6 @@ static md2_model_t *md2_readModel(const char *filename)
|
|||
md2_freeModel (model);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
// read triangles
|
||||
|
@ -769,6 +782,7 @@ void HWR_InitMD2(void)
|
|||
md2_playermodels[s].grpatch = NULL;
|
||||
md2_playermodels[s].skin = -1;
|
||||
md2_playermodels[s].notfound = true;
|
||||
md2_playermodels[s].error = false;
|
||||
}
|
||||
for (i = 0; i < NUMSPRITES; i++)
|
||||
{
|
||||
|
@ -777,6 +791,7 @@ void HWR_InitMD2(void)
|
|||
md2_models[i].grpatch = NULL;
|
||||
md2_models[i].skin = -1;
|
||||
md2_models[i].notfound = true;
|
||||
md2_models[i].error = false;
|
||||
}
|
||||
|
||||
// read the md2.dat file
|
||||
|
@ -1269,6 +1284,8 @@ void HWR_DrawMD2(gr_vissprite_t *spr)
|
|||
else
|
||||
md2 = &md2_models[spr->mobj->sprite];
|
||||
|
||||
if (md2->error)
|
||||
return; // we already failed loading this before :(
|
||||
if (!md2->model)
|
||||
{
|
||||
//CONS_Debug(DBG_RENDER, "Loading MD2... (%s)", sprnames[spr->mobj->sprite]);
|
||||
|
@ -1282,6 +1299,7 @@ void HWR_DrawMD2(gr_vissprite_t *spr)
|
|||
else
|
||||
{
|
||||
//CONS_Debug(DBG_RENDER, " FAILED\n");
|
||||
md2->error = true; // prevent endless fail
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -123,6 +123,7 @@ typedef struct
|
|||
void *blendgrpatch;
|
||||
boolean notfound;
|
||||
INT32 skin;
|
||||
boolean error;
|
||||
} md2_t;
|
||||
|
||||
extern md2_t md2_models[NUMSPRITES];
|
||||
|
|
|
@ -244,6 +244,7 @@ FUNCPRINTF void DBG_Printf(const char *lpFmt, ...)
|
|||
#define pglMaterialfv glMaterialfv
|
||||
|
||||
/* Raster functions */
|
||||
#define pglPixelStorei glPixelStorei
|
||||
#define pglReadPixels glReadPixels
|
||||
|
||||
/* Texture mapping */
|
||||
|
@ -262,15 +263,8 @@ FUNCPRINTF void DBG_Printf(const char *lpFmt, ...)
|
|||
/* texture mapping */ //GL_EXT_copy_texture
|
||||
#ifndef KOS_GL_COMPATIBILITY
|
||||
#define pglCopyTexImage2D glCopyTexImage2D
|
||||
#endif
|
||||
|
||||
/* GLU functions */
|
||||
#define pgluBuild2DMipmaps gluBuild2DMipmaps
|
||||
#endif
|
||||
#ifndef MINI_GL_COMPATIBILITY
|
||||
/* 1.3 functions for multitexturing */
|
||||
#define pglActiveTexture glActiveTexture
|
||||
#define pglMultiTexCoord2f glMultiTexCoord2f
|
||||
#endif
|
||||
#else //!STATIC_OPENGL
|
||||
|
||||
/* 1.0 functions */
|
||||
|
@ -365,6 +359,8 @@ typedef void (APIENTRY * PFNglMaterialfv) (GLint face, GLenum pname, GLfloat *pa
|
|||
static PFNglMaterialfv pglMaterialfv;
|
||||
|
||||
/* Raster functions */
|
||||
typedef void (APIENTRY * PFNglPixelStorei) (GLenum pname, GLint param);
|
||||
static PFNglPixelStorei pglPixelStorei;
|
||||
typedef void (APIENTRY * PFNglReadPixels) (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels);
|
||||
static PFNglReadPixels pglReadPixels;
|
||||
|
||||
|
@ -391,7 +387,7 @@ static PFNglBindTexture pglBindTexture;
|
|||
/* texture mapping */ //GL_EXT_copy_texture
|
||||
typedef void (APIENTRY * PFNglCopyTexImage2D) (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border);
|
||||
static PFNglCopyTexImage2D pglCopyTexImage2D;
|
||||
|
||||
#endif
|
||||
/* GLU functions */
|
||||
typedef GLint (APIENTRY * PFNgluBuild2DMipmaps) (GLenum target, GLint internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *data);
|
||||
static PFNgluBuild2DMipmaps pgluBuild2DMipmaps;
|
||||
|
@ -403,7 +399,6 @@ static PFNglActiveTexture pglActiveTexture;
|
|||
typedef void (APIENTRY *PFNglMultiTexCoord2f) (GLenum, GLfloat, GLfloat);
|
||||
static PFNglMultiTexCoord2f pglMultiTexCoord2f;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef MINI_GL_COMPATIBILITY
|
||||
/* 1.2 Parms */
|
||||
|
@ -494,6 +489,7 @@ boolean SetupGLfunc(void)
|
|||
GETOPENGLFUNC(pglLightModelfv , glLightModelfv)
|
||||
GETOPENGLFUNC(pglMaterialfv , glMaterialfv)
|
||||
|
||||
GETOPENGLFUNC(pglPixelStorei , glPixelStorei)
|
||||
GETOPENGLFUNC(pglReadPixels , glReadPixels)
|
||||
|
||||
GETOPENGLFUNC(pglTexEnvi , glTexEnvi)
|
||||
|
@ -519,35 +515,23 @@ boolean SetupGLfunc(void)
|
|||
// This has to be done after the context is created so the version number can be obtained
|
||||
boolean SetupGLFunc13(void)
|
||||
{
|
||||
#ifdef MINI_GL_COMPATIBILITY
|
||||
return false;
|
||||
#else
|
||||
const GLubyte *version = pglGetString(GL_VERSION);
|
||||
int glmajor, glminor;
|
||||
|
||||
gl13 = false;
|
||||
#ifdef MINI_GL_COMPATIBILITY
|
||||
return false;
|
||||
#else
|
||||
#ifdef STATIC_OPENGL
|
||||
gl13 = true;
|
||||
#else
|
||||
|
||||
// Parse the GL version
|
||||
if (version != NULL)
|
||||
{
|
||||
if (sscanf((const char*)version, "%d.%d", &glmajor, &glminor) == 2)
|
||||
{
|
||||
// Look, we gotta prepare for the inevitable arrival of GL 2.0 code...
|
||||
switch (glmajor)
|
||||
{
|
||||
case 1:
|
||||
if (glminor == 3) gl13 = true;
|
||||
break;
|
||||
case 2:
|
||||
case 3:
|
||||
case 4:
|
||||
gl13 = true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (glmajor == 1 && glminor >= 3)
|
||||
gl13 = true;
|
||||
else if (glmajor > 1)
|
||||
gl13 = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -568,9 +552,6 @@ boolean SetupGLFunc13(void)
|
|||
}
|
||||
else
|
||||
DBG_Printf("GL_ARB_multitexture support: disabled\n");
|
||||
#undef GETOPENGLFUNC
|
||||
|
||||
#endif
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
@ -897,7 +878,9 @@ EXPORT void HWRAPI(ReadRect) (INT32 x, INT32 y, INT32 width, INT32 height,
|
|||
GLubyte*top = (GLvoid*)dst_data, *bottom = top + dst_stride * (height - 1);
|
||||
GLubyte *row = malloc(dst_stride);
|
||||
if (!row) return;
|
||||
pglPixelStorei(GL_PACK_ALIGNMENT, 1);
|
||||
pglReadPixels(x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, dst_data);
|
||||
pglPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
for(i = 0; i < height/2; i++)
|
||||
{
|
||||
memcpy(row, top, dst_stride);
|
||||
|
@ -913,7 +896,9 @@ EXPORT void HWRAPI(ReadRect) (INT32 x, INT32 y, INT32 width, INT32 height,
|
|||
INT32 j;
|
||||
GLubyte *image = malloc(width*height*3*sizeof (*image));
|
||||
if (!image) return;
|
||||
pglPixelStorei(GL_PACK_ALIGNMENT, 1);
|
||||
pglReadPixels(x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, image);
|
||||
pglPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
for (i = height-1; i >= 0; i--)
|
||||
{
|
||||
for (j = 0; j < width; j++)
|
||||
|
@ -1815,13 +1800,11 @@ EXPORT void HWRAPI(SetSpecialState) (hwdspecialstate_t IdState, INT32 Value)
|
|||
min_filter = GL_NEAREST;
|
||||
#endif
|
||||
}
|
||||
#ifndef STATIC_OPENGL
|
||||
if (!pgluBuild2DMipmaps)
|
||||
{
|
||||
MipMap = GL_FALSE;
|
||||
min_filter = GL_LINEAR;
|
||||
}
|
||||
#endif
|
||||
Flush(); //??? if we want to change filter mode by texture, remove this
|
||||
break;
|
||||
|
||||
|
@ -1836,10 +1819,7 @@ EXPORT void HWRAPI(SetSpecialState) (hwdspecialstate_t IdState, INT32 Value)
|
|||
}
|
||||
}
|
||||
|
||||
// -----------------+
|
||||
// HWRAPI DrawMD2 : Draw an MD2 model with glcommands
|
||||
// -----------------+
|
||||
EXPORT void HWRAPI(DrawMD2i) (INT32 *gl_cmd_buffer, md2_frame_t *frame, UINT32 duration, UINT32 tics, md2_frame_t *nextframe, FTransform *pos, float scale, UINT8 flipped, UINT8 *color)
|
||||
static void DrawMD2Ex(INT32 *gl_cmd_buffer, md2_frame_t *frame, UINT32 duration, UINT32 tics, md2_frame_t *nextframe, FTransform *pos, float scale, UINT8 flipped, UINT8 *color)
|
||||
{
|
||||
INT32 val, count, pindex;
|
||||
GLfloat s, t;
|
||||
|
@ -1931,7 +1911,7 @@ EXPORT void HWRAPI(DrawMD2i) (INT32 *gl_cmd_buffer, md2_frame_t *frame, UINT32 d
|
|||
//pglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // alpha = level of transparency
|
||||
|
||||
// Remove depth mask when the model is transparent so it doesn't cut thorugh sprites // SRB2CBTODO: For all stuff too?!
|
||||
if (color[3] < 255)
|
||||
if (color && color[3] < 255)
|
||||
{
|
||||
pglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // alpha = level of transparency
|
||||
pglDepthMask(GL_FALSE);
|
||||
|
@ -2007,11 +1987,20 @@ EXPORT void HWRAPI(DrawMD2i) (INT32 *gl_cmd_buffer, md2_frame_t *frame, UINT32 d
|
|||
pglDisable(GL_CULL_FACE);
|
||||
}
|
||||
|
||||
// -----------------+
|
||||
// HWRAPI DrawMD2 : Draw an MD2 model with glcommands
|
||||
// -----------------+
|
||||
EXPORT void HWRAPI(DrawMD2i) (INT32 *gl_cmd_buffer, md2_frame_t *frame, UINT32 duration, UINT32 tics, md2_frame_t *nextframe, FTransform *pos, float scale, UINT8 flipped, UINT8 *color)
|
||||
{
|
||||
DrawMD2Ex(gl_cmd_buffer, frame, duration, tics, nextframe, pos, scale, flipped, color);
|
||||
}
|
||||
|
||||
EXPORT void HWRAPI(DrawMD2) (INT32 *gl_cmd_buffer, md2_frame_t *frame, FTransform *pos, float scale)
|
||||
{
|
||||
DrawMD2i(gl_cmd_buffer, frame, 0, 0, NULL, pos, scale, false, NULL);
|
||||
DrawMD2Ex(gl_cmd_buffer, frame, 0, 0, NULL, pos, scale, false, NULL);
|
||||
}
|
||||
|
||||
|
||||
// -----------------+
|
||||
// SetTransform :
|
||||
// -----------------+
|
||||
|
|
|
@ -470,7 +470,7 @@ static void Got_Saycmd(UINT8 **p, INT32 playernum)
|
|||
boolean action = false;
|
||||
char *ptr;
|
||||
|
||||
CONS_Debug(DBG_NETPLAY,"Recieved SAY cmd from Player %d (%s)\n", playernum+1, player_names[playernum]);
|
||||
CONS_Debug(DBG_NETPLAY,"Received SAY cmd from Player %d (%s)\n", playernum+1, player_names[playernum]);
|
||||
|
||||
target = READSINT8(*p);
|
||||
flags = READUINT8(*p);
|
||||
|
@ -757,15 +757,8 @@ void HU_clearChatChars(void)
|
|||
//
|
||||
boolean HU_Responder(event_t *ev)
|
||||
{
|
||||
static boolean shiftdown = false;
|
||||
UINT8 c;
|
||||
|
||||
if (ev->data1 == KEY_LSHIFT || ev->data1 == KEY_RSHIFT)
|
||||
{
|
||||
shiftdown = (ev->type == ev_keydown);
|
||||
return chat_on;
|
||||
}
|
||||
|
||||
if (ev->type != ev_keydown)
|
||||
return false;
|
||||
|
||||
|
@ -797,6 +790,14 @@ boolean HU_Responder(event_t *ev)
|
|||
}
|
||||
else // if chat_on
|
||||
{
|
||||
// Ignore modifier keys
|
||||
// Note that we do this here so users can still set
|
||||
// their chat keys to one of these, if they so desire.
|
||||
if (ev->data1 == KEY_LSHIFT || ev->data1 == KEY_RSHIFT
|
||||
|| ev->data1 == KEY_LCTRL || ev->data1 == KEY_RCTRL
|
||||
|| ev->data1 == KEY_LALT || ev->data1 == KEY_RALT)
|
||||
return true;
|
||||
|
||||
c = (UINT8)ev->data1;
|
||||
|
||||
// use console translations
|
||||
|
@ -1101,7 +1102,19 @@ void HU_Drawer(void)
|
|||
|
||||
// draw desynch text
|
||||
if (hu_resynching)
|
||||
V_DrawCenteredString(BASEVIDWIDTH/2, 180, V_YELLOWMAP, "Resynching...");
|
||||
{
|
||||
static UINT32 resynch_ticker = 0;
|
||||
char resynch_text[14];
|
||||
UINT32 i;
|
||||
|
||||
// Animate the dots
|
||||
resynch_ticker++;
|
||||
strcpy(resynch_text, "Resynching");
|
||||
for (i = 0; i < (resynch_ticker / 16) % 4; i++)
|
||||
strcat(resynch_text, ".");
|
||||
|
||||
V_DrawCenteredString(BASEVIDWIDTH/2, 180, V_YELLOWMAP | V_ALLOWLOWERCASE, resynch_text);
|
||||
}
|
||||
}
|
||||
|
||||
//======================================================================
|
||||
|
|
|
@ -87,7 +87,7 @@ void HU_Init(void);
|
|||
void HU_LoadGraphics(void);
|
||||
|
||||
// reset heads up when consoleplayer respawns.
|
||||
void HU_Start(void);
|
||||
FUNCMATH void HU_Start(void);
|
||||
|
||||
boolean HU_Responder(event_t *ev);
|
||||
|
||||
|
|
|
@ -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
|
||||
*/
|
||||
|
|
|
@ -296,6 +296,14 @@ char *I_GetEnv(const char *name);
|
|||
|
||||
INT32 I_PutEnv(char *variable);
|
||||
|
||||
/** \brief Put data in system clipboard
|
||||
*/
|
||||
INT32 I_ClipboardCopy(const char *data, size_t size);
|
||||
|
||||
/** \brief Retrieve data from system clipboard
|
||||
*/
|
||||
const char *I_ClipboardPaste(void);
|
||||
|
||||
void I_RegisterSysCommands(void);
|
||||
|
||||
#endif
|
||||
|
|
101
src/i_tcp.c
101
src/i_tcp.c
|
@ -56,7 +56,9 @@
|
|||
//#define NONET
|
||||
#endif
|
||||
|
||||
#ifndef NONET
|
||||
#ifdef NONET
|
||||
#undef HAVE_MINIUPNPC
|
||||
#else
|
||||
#ifdef USE_WINSOCK1
|
||||
#include <winsock.h>
|
||||
#elif !defined (SCOUW2) && !defined (SCOUW7) && !defined (__OS2__)
|
||||
|
@ -177,6 +179,7 @@ static UINT8 UPNP_support = TRUE;
|
|||
#include "i_system.h"
|
||||
#include "i_net.h"
|
||||
#include "d_net.h"
|
||||
#include "d_netfil.h"
|
||||
#include "i_tcp.h"
|
||||
#include "m_argv.h"
|
||||
|
||||
|
@ -480,21 +483,12 @@ static boolean SOCK_cmpaddr(mysockaddr_t *a, mysockaddr_t *b, UINT8 mask)
|
|||
return false;
|
||||
}
|
||||
|
||||
static SINT8 getfreenode(void)
|
||||
{
|
||||
SINT8 j;
|
||||
|
||||
for (j = 0; j < MAXNETNODES; j++)
|
||||
if (!nodeconnected[j])
|
||||
{
|
||||
nodeconnected[j] = true;
|
||||
return j;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
// This is a hack. For some reason, nodes aren't being freed properly.
|
||||
// This goes through and cleans up what nodes were supposed to be freed.
|
||||
/** \warning This function causes the file downloading to stop if someone joins.
|
||||
* How? Because it removes nodes that are connected but not in game,
|
||||
* which is exactly what clients downloading a file are.
|
||||
*/
|
||||
static void cleanupnodes(void)
|
||||
{
|
||||
SINT8 j;
|
||||
|
@ -504,13 +498,81 @@ static void cleanupnodes(void)
|
|||
|
||||
// Why can't I start at zero?
|
||||
for (j = 1; j < MAXNETNODES; j++)
|
||||
//if (!(nodeingame[j] || SV_SendingFile(j)))
|
||||
if (!nodeingame[j])
|
||||
nodeconnected[j] = false;
|
||||
}
|
||||
|
||||
static SINT8 getfreenode(void)
|
||||
{
|
||||
SINT8 j;
|
||||
|
||||
cleanupnodes();
|
||||
|
||||
for (j = 0; j < MAXNETNODES; j++)
|
||||
if (!nodeconnected[j])
|
||||
{
|
||||
nodeconnected[j] = true;
|
||||
return j;
|
||||
}
|
||||
|
||||
/** \warning No free node? Just in case a node might not have been freed properly,
|
||||
* look if there are connected nodes that aren't in game, and forget them.
|
||||
* It's dirty, and might result in a poor guy having to restart
|
||||
* downloading a needed wad, but it's better than not letting anyone join...
|
||||
*/
|
||||
/*I_Error("No more free nodes!!1!11!11!!1111\n");
|
||||
for (j = 1; j < MAXNETNODES; j++)
|
||||
if (!nodeingame[j])
|
||||
return j;*/
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef _DEBUG
|
||||
void Command_Numnodes(void)
|
||||
{
|
||||
INT32 connected = 0;
|
||||
INT32 ingame = 0;
|
||||
INT32 i;
|
||||
|
||||
for (i = 1; i < MAXNETNODES; i++)
|
||||
{
|
||||
if (!(nodeconnected[i] || nodeingame[i]))
|
||||
continue;
|
||||
|
||||
if (nodeconnected[i])
|
||||
connected++;
|
||||
if (nodeingame[i])
|
||||
ingame++;
|
||||
|
||||
CONS_Printf("%2d - ", i);
|
||||
if (nodetoplayer[i] != -1)
|
||||
CONS_Printf("player %.2d", nodetoplayer[i]);
|
||||
else
|
||||
CONS_Printf(" ");
|
||||
if (nodeconnected[i])
|
||||
CONS_Printf(" - connected");
|
||||
else
|
||||
CONS_Printf(" - ");
|
||||
if (nodeingame[i])
|
||||
CONS_Printf(" - ingame");
|
||||
else
|
||||
CONS_Printf(" - ");
|
||||
CONS_Printf(" - %s\n", I_GetNodeAddress(i));
|
||||
}
|
||||
|
||||
CONS_Printf("\n"
|
||||
"Connected: %d\n"
|
||||
"Ingame: %d\n",
|
||||
connected, ingame);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef NONET
|
||||
static void SOCK_Get(void)
|
||||
// Returns true if a packet was received from a new node, false in all other cases
|
||||
static boolean SOCK_Get(void)
|
||||
{
|
||||
size_t i, n;
|
||||
int j;
|
||||
|
@ -533,13 +595,12 @@ static void SOCK_Get(void)
|
|||
doomcom->remotenode = (INT16)j; // good packet from a game player
|
||||
doomcom->datalength = (INT16)c;
|
||||
nodesocket[j] = mysockets[n];
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// not found
|
||||
|
||||
// find a free slot
|
||||
cleanupnodes();
|
||||
j = getfreenode();
|
||||
if (j > 0)
|
||||
{
|
||||
|
@ -562,14 +623,15 @@ static void SOCK_Get(void)
|
|||
}
|
||||
if (i == numbans)
|
||||
SOCK_bannednode[j] = false;
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
DEBFILE("New node detected: No more free slots\n");
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
doomcom->remotenode = -1; // no packet
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -1254,7 +1316,6 @@ static SINT8 SOCK_NetMakeNodewPort(const char *address, const char *port)
|
|||
gaie = I_getaddrinfo(address, port, &hints, &ai);
|
||||
if (gaie == 0)
|
||||
{
|
||||
cleanupnodes();
|
||||
newnode = getfreenode();
|
||||
}
|
||||
if (newnode == -1)
|
||||
|
|
|
@ -437,6 +437,16 @@ static int lib_pMobjFlip(lua_State *L)
|
|||
return 1;
|
||||
}
|
||||
|
||||
static int lib_pGetMobjGravity(lua_State *L)
|
||||
{
|
||||
mobj_t *mobj = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
|
||||
//HUDSAFE
|
||||
if (!mobj)
|
||||
return LUA_ErrInvalid(L, "mobj_t");
|
||||
lua_pushfixed(L, P_GetMobjGravity(mobj));
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int lib_pWeaponOrPanel(lua_State *L)
|
||||
{
|
||||
mobjtype_t type = luaL_checkinteger(L, 1);
|
||||
|
@ -2008,6 +2018,7 @@ static luaL_Reg lib[] = {
|
|||
{"P_SPMAngle",lib_pSPMAngle},
|
||||
{"P_SpawnPlayerMissile",lib_pSpawnPlayerMissile},
|
||||
{"P_MobjFlip",lib_pMobjFlip},
|
||||
{"P_GetMobjGravity",lib_pGetMobjGravity},
|
||||
{"P_WeaponOrPanel",lib_pWeaponOrPanel},
|
||||
{"P_FlashPal",lib_pFlashPal},
|
||||
{"P_GetClosestAxis",lib_pGetClosestAxis},
|
||||
|
|
|
@ -60,7 +60,7 @@ UINT8 LUAh_MobjCollideHook(mobj_t *thing1, mobj_t *thing2, enum hook which);
|
|||
#define LUAh_MobjMoveCollide(thing1, thing2) LUAh_MobjCollideHook(thing1, thing2, hook_MobjMoveCollide) // Hook for PIT_CheckThing by (tmthing) mobj type
|
||||
boolean LUAh_TouchSpecial(mobj_t *special, mobj_t *toucher); // Hook for P_TouchSpecialThing by mobj type
|
||||
#define LUAh_MobjFuse(mo) LUAh_MobjHook(mo, hook_MobjFuse) // Hook for mobj->fuse == 0 by mobj type
|
||||
#define LUAh_MobjThinker(mo) LUAh_MobjHook(mo, hook_MobjThinker) // Hook for P_MobjThinker or P_SceneryThinker by mobj type
|
||||
boolean LUAh_MobjThinker(mobj_t *mo); // Hook for P_MobjThinker or P_SceneryThinker by mobj type
|
||||
#define LUAh_BossThinker(mo) LUAh_MobjHook(mo, hook_BossThinker) // Hook for P_GenericBossThinker by mobj type
|
||||
UINT8 LUAh_ShouldDamage(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 damage); // Hook for P_DamageMobj by mobj type (Should mobj take damage?)
|
||||
boolean LUAh_MobjDamage(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 damage); // Hook for P_DamageMobj by mobj type (Mobj actually takes damage!)
|
||||
|
|
|
@ -74,12 +74,30 @@ typedef struct hook_s* hook_p;
|
|||
|
||||
#define FMT_HOOKID "hook_%d"
|
||||
|
||||
// For each mobj type, a linked list to its thinker and collision hooks.
|
||||
// That way, we don't have to iterate through all the hooks.
|
||||
// We could do that with all other mobj hooks, but it would probably just be
|
||||
// a waste of memory since they are only called occasionally. Probably...
|
||||
static hook_p mobjthinkerhooks[NUMMOBJTYPES];
|
||||
static hook_p mobjcollidehooks[NUMMOBJTYPES];
|
||||
|
||||
// For each mobj type, a linked list for other mobj hooks
|
||||
static hook_p mobjhooks[NUMMOBJTYPES];
|
||||
|
||||
// A linked list for player hooks
|
||||
static hook_p playerhooks;
|
||||
|
||||
// A linked list for linedef executor hooks
|
||||
static hook_p linedefexecutorhooks;
|
||||
|
||||
// For other hooks, a unique linked list
|
||||
hook_p roothook;
|
||||
|
||||
// Takes hook, function, and additional arguments (mobj type to act on, etc.)
|
||||
static int lib_addHook(lua_State *L)
|
||||
{
|
||||
static struct hook_s hook = {NULL, 0, 0, {0}, false};
|
||||
static UINT32 nextid;
|
||||
hook_p hookp, *lastp;
|
||||
|
||||
hook.type = luaL_checkoption(L, 1, NULL, hookNames);
|
||||
|
@ -109,6 +127,7 @@ static int lib_addHook(lua_State *L)
|
|||
hook.s.mt = MT_NULL;
|
||||
if (lua_isnumber(L, 2))
|
||||
hook.s.mt = lua_tonumber(L, 2);
|
||||
luaL_argcheck(L, hook.s.mt < NUMMOBJTYPES, 2, "invalid mobjtype_t");
|
||||
break;
|
||||
case hook_BotAI:
|
||||
hook.s.skinname = NULL;
|
||||
|
@ -141,18 +160,49 @@ static int lib_addHook(lua_State *L)
|
|||
|
||||
hooksAvailable[hook.type/8] |= 1<<(hook.type%8);
|
||||
|
||||
// iterate the hook metadata structs
|
||||
// set hook.id to the highest id + 1
|
||||
// set lastp to the last hook struct's "next" pointer.
|
||||
lastp = &roothook;
|
||||
hook.id = 0;
|
||||
for (hookp = roothook; hookp; hookp = hookp->next)
|
||||
hook.id = nextid++;
|
||||
|
||||
// Special cases for some hook types (see the comments above mobjthinkerhooks declaration)
|
||||
switch(hook.type)
|
||||
{
|
||||
if (hookp->id >= hook.id)
|
||||
hook.id = hookp->id+1;
|
||||
lastp = &hookp->next;
|
||||
case hook_MobjThinker:
|
||||
lastp = &mobjthinkerhooks[hook.s.mt];
|
||||
break;
|
||||
case hook_MobjCollide:
|
||||
case hook_MobjMoveCollide:
|
||||
lastp = &mobjcollidehooks[hook.s.mt];
|
||||
break;
|
||||
case hook_MobjSpawn:
|
||||
case hook_TouchSpecial:
|
||||
case hook_MobjFuse:
|
||||
case hook_BossThinker:
|
||||
case hook_ShouldDamage:
|
||||
case hook_MobjDamage:
|
||||
case hook_MobjDeath:
|
||||
case hook_BossDeath:
|
||||
case hook_MobjRemoved:
|
||||
lastp = &mobjhooks[hook.s.mt];
|
||||
break;
|
||||
case hook_JumpSpecial:
|
||||
case hook_AbilitySpecial:
|
||||
case hook_SpinSpecial:
|
||||
case hook_JumpSpinSpecial:
|
||||
case hook_PlayerSpawn:
|
||||
lastp = &playerhooks;
|
||||
break;
|
||||
case hook_LinedefExecute:
|
||||
lastp = &linedefexecutorhooks;
|
||||
break;
|
||||
default:
|
||||
lastp = &roothook;
|
||||
break;
|
||||
}
|
||||
|
||||
// iterate the hook metadata structs
|
||||
// set lastp to the last hook struct's "next" pointer.
|
||||
for (hookp = *lastp; hookp; hookp = hookp->next)
|
||||
lastp = &hookp->next;
|
||||
// allocate a permanent memory struct to stuff hook.
|
||||
hookp = ZZ_Alloc(sizeof(struct hook_s));
|
||||
memcpy(hookp, &hook, sizeof(struct hook_s));
|
||||
|
@ -183,9 +233,29 @@ boolean LUAh_MobjHook(mobj_t *mo, enum hook which)
|
|||
|
||||
lua_settop(gL, 0);
|
||||
|
||||
for (hookp = roothook; hookp; hookp = hookp->next)
|
||||
if (hookp->type == which
|
||||
&& (hookp->s.mt == MT_NULL || hookp->s.mt == mo->type))
|
||||
// Look for all generic mobj hooks
|
||||
for (hookp = mobjhooks[MT_NULL]; hookp; hookp = hookp->next)
|
||||
if (hookp->type == which)
|
||||
{
|
||||
if (lua_gettop(gL) == 0)
|
||||
LUA_PushUserdata(gL, mo, META_MOBJ);
|
||||
lua_pushfstring(gL, FMT_HOOKID, hookp->id);
|
||||
lua_gettable(gL, LUA_REGISTRYINDEX);
|
||||
lua_pushvalue(gL, -2);
|
||||
if (lua_pcall(gL, 1, 1, 0)) {
|
||||
if (!hookp->error || cv_debug & DBG_LUA)
|
||||
CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1));
|
||||
lua_pop(gL, 1);
|
||||
hookp->error = true;
|
||||
continue;
|
||||
}
|
||||
if (lua_toboolean(gL, -1))
|
||||
hooked = true;
|
||||
lua_pop(gL, 1);
|
||||
}
|
||||
|
||||
for (hookp = mobjhooks[mo->type]; hookp; hookp = hookp->next)
|
||||
if (hookp->type == which)
|
||||
{
|
||||
if (lua_gettop(gL) == 0)
|
||||
LUA_PushUserdata(gL, mo, META_MOBJ);
|
||||
|
@ -217,7 +287,7 @@ boolean LUAh_PlayerHook(player_t *plr, enum hook which)
|
|||
|
||||
lua_settop(gL, 0);
|
||||
|
||||
for (hookp = roothook; hookp; hookp = hookp->next)
|
||||
for (hookp = playerhooks; hookp; hookp = hookp->next)
|
||||
if (hookp->type == which)
|
||||
{
|
||||
if (lua_gettop(gL) == 0)
|
||||
|
@ -338,9 +408,38 @@ UINT8 LUAh_MobjCollideHook(mobj_t *thing1, mobj_t *thing2, enum hook which)
|
|||
|
||||
lua_settop(gL, 0);
|
||||
|
||||
for (hookp = roothook; hookp; hookp = hookp->next)
|
||||
if (hookp->type == which
|
||||
&& (hookp->s.mt == MT_NULL || hookp->s.mt == thing1->type))
|
||||
// Look for all generic mobj collision hooks
|
||||
for (hookp = mobjcollidehooks[MT_NULL]; hookp; hookp = hookp->next)
|
||||
if (hookp->type == which)
|
||||
{
|
||||
if (lua_gettop(gL) == 0)
|
||||
{
|
||||
LUA_PushUserdata(gL, thing1, META_MOBJ);
|
||||
LUA_PushUserdata(gL, thing2, META_MOBJ);
|
||||
}
|
||||
lua_pushfstring(gL, FMT_HOOKID, hookp->id);
|
||||
lua_gettable(gL, LUA_REGISTRYINDEX);
|
||||
lua_pushvalue(gL, -3);
|
||||
lua_pushvalue(gL, -3);
|
||||
if (lua_pcall(gL, 2, 1, 0)) {
|
||||
if (!hookp->error || cv_debug & DBG_LUA)
|
||||
CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1));
|
||||
lua_pop(gL, 1);
|
||||
hookp->error = true;
|
||||
continue;
|
||||
}
|
||||
if (!lua_isnil(gL, -1))
|
||||
{ // if nil, leave shouldCollide = 0.
|
||||
if (lua_toboolean(gL, -1))
|
||||
shouldCollide = 1; // Force yes
|
||||
else
|
||||
shouldCollide = 2; // Force no
|
||||
}
|
||||
lua_pop(gL, 1);
|
||||
}
|
||||
|
||||
for (hookp = mobjcollidehooks[thing1->type]; hookp; hookp = hookp->next)
|
||||
if (hookp->type == which)
|
||||
{
|
||||
if (lua_gettop(gL) == 0)
|
||||
{
|
||||
|
@ -372,6 +471,59 @@ UINT8 LUAh_MobjCollideHook(mobj_t *thing1, mobj_t *thing2, enum hook which)
|
|||
return shouldCollide;
|
||||
}
|
||||
|
||||
// Hook for mobj thinkers
|
||||
boolean LUAh_MobjThinker(mobj_t *mo)
|
||||
{
|
||||
hook_p hookp;
|
||||
boolean hooked = false;
|
||||
if (!gL || !(hooksAvailable[hook_MobjThinker/8] & (1<<(hook_MobjThinker%8))))
|
||||
return false;
|
||||
|
||||
lua_settop(gL, 0);
|
||||
|
||||
// Look for all generic mobj thinker hooks
|
||||
for (hookp = mobjthinkerhooks[MT_NULL]; hookp; hookp = hookp->next)
|
||||
{
|
||||
if (lua_gettop(gL) == 0)
|
||||
LUA_PushUserdata(gL, mo, META_MOBJ);
|
||||
lua_pushfstring(gL, FMT_HOOKID, hookp->id);
|
||||
lua_gettable(gL, LUA_REGISTRYINDEX);
|
||||
lua_pushvalue(gL, -2);
|
||||
if (lua_pcall(gL, 1, 1, 0)) {
|
||||
if (!hookp->error || cv_debug & DBG_LUA)
|
||||
CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1));
|
||||
lua_pop(gL, 1);
|
||||
hookp->error = true;
|
||||
continue;
|
||||
}
|
||||
if (lua_toboolean(gL, -1))
|
||||
hooked = true;
|
||||
lua_pop(gL, 1);
|
||||
}
|
||||
|
||||
for (hookp = mobjthinkerhooks[mo->type]; hookp; hookp = hookp->next)
|
||||
{
|
||||
if (lua_gettop(gL) == 0)
|
||||
LUA_PushUserdata(gL, mo, META_MOBJ);
|
||||
lua_pushfstring(gL, FMT_HOOKID, hookp->id);
|
||||
lua_gettable(gL, LUA_REGISTRYINDEX);
|
||||
lua_pushvalue(gL, -2);
|
||||
if (lua_pcall(gL, 1, 1, 0)) {
|
||||
if (!hookp->error || cv_debug & DBG_LUA)
|
||||
CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1));
|
||||
lua_pop(gL, 1);
|
||||
hookp->error = true;
|
||||
continue;
|
||||
}
|
||||
if (lua_toboolean(gL, -1))
|
||||
hooked = true;
|
||||
lua_pop(gL, 1);
|
||||
}
|
||||
|
||||
lua_settop(gL, 0);
|
||||
return hooked;
|
||||
}
|
||||
|
||||
// Hook for P_TouchSpecialThing by mobj type
|
||||
boolean LUAh_TouchSpecial(mobj_t *special, mobj_t *toucher)
|
||||
{
|
||||
|
@ -382,9 +534,33 @@ boolean LUAh_TouchSpecial(mobj_t *special, mobj_t *toucher)
|
|||
|
||||
lua_settop(gL, 0);
|
||||
|
||||
for (hookp = roothook; hookp; hookp = hookp->next)
|
||||
if (hookp->type == hook_TouchSpecial
|
||||
&& (hookp->s.mt == MT_NULL || hookp->s.mt == special->type))
|
||||
// Look for all generic touch special hooks
|
||||
for (hookp = mobjhooks[MT_NULL]; hookp; hookp = hookp->next)
|
||||
if (hookp->type == hook_TouchSpecial)
|
||||
{
|
||||
if (lua_gettop(gL) == 0)
|
||||
{
|
||||
LUA_PushUserdata(gL, special, META_MOBJ);
|
||||
LUA_PushUserdata(gL, toucher, META_MOBJ);
|
||||
}
|
||||
lua_pushfstring(gL, FMT_HOOKID, hookp->id);
|
||||
lua_gettable(gL, LUA_REGISTRYINDEX);
|
||||
lua_pushvalue(gL, -3);
|
||||
lua_pushvalue(gL, -3);
|
||||
if (lua_pcall(gL, 2, 1, 0)) {
|
||||
if (!hookp->error || cv_debug & DBG_LUA)
|
||||
CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1));
|
||||
lua_pop(gL, 1);
|
||||
hookp->error = true;
|
||||
continue;
|
||||
}
|
||||
if (lua_toboolean(gL, -1))
|
||||
hooked = true;
|
||||
lua_pop(gL, 1);
|
||||
}
|
||||
|
||||
for (hookp = mobjhooks[special->type]; hookp; hookp = hookp->next)
|
||||
if (hookp->type == hook_TouchSpecial)
|
||||
{
|
||||
if (lua_gettop(gL) == 0)
|
||||
{
|
||||
|
@ -421,9 +597,42 @@ UINT8 LUAh_ShouldDamage(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32
|
|||
|
||||
lua_settop(gL, 0);
|
||||
|
||||
for (hookp = roothook; hookp; hookp = hookp->next)
|
||||
if (hookp->type == hook_ShouldDamage
|
||||
&& (hookp->s.mt == MT_NULL || hookp->s.mt == target->type))
|
||||
// Look for all generic should damage hooks
|
||||
for (hookp = mobjhooks[MT_NULL]; hookp; hookp = hookp->next)
|
||||
if (hookp->type == hook_ShouldDamage)
|
||||
{
|
||||
if (lua_gettop(gL) == 0)
|
||||
{
|
||||
LUA_PushUserdata(gL, target, META_MOBJ);
|
||||
LUA_PushUserdata(gL, inflictor, META_MOBJ);
|
||||
LUA_PushUserdata(gL, source, META_MOBJ);
|
||||
lua_pushinteger(gL, damage);
|
||||
}
|
||||
lua_pushfstring(gL, FMT_HOOKID, hookp->id);
|
||||
lua_gettable(gL, LUA_REGISTRYINDEX);
|
||||
lua_pushvalue(gL, -5);
|
||||
lua_pushvalue(gL, -5);
|
||||
lua_pushvalue(gL, -5);
|
||||
lua_pushvalue(gL, -5);
|
||||
if (lua_pcall(gL, 4, 1, 0)) {
|
||||
if (!hookp->error || cv_debug & DBG_LUA)
|
||||
CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1));
|
||||
lua_pop(gL, 1);
|
||||
hookp->error = true;
|
||||
continue;
|
||||
}
|
||||
if (!lua_isnil(gL, -1))
|
||||
{
|
||||
if (lua_toboolean(gL, -1))
|
||||
shouldDamage = 1; // Force yes
|
||||
else
|
||||
shouldDamage = 2; // Force no
|
||||
}
|
||||
lua_pop(gL, 1);
|
||||
}
|
||||
|
||||
for (hookp = mobjhooks[target->type]; hookp; hookp = hookp->next)
|
||||
if (hookp->type == hook_ShouldDamage)
|
||||
{
|
||||
if (lua_gettop(gL) == 0)
|
||||
{
|
||||
|
@ -469,9 +678,37 @@ boolean LUAh_MobjDamage(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32
|
|||
|
||||
lua_settop(gL, 0);
|
||||
|
||||
for (hookp = roothook; hookp; hookp = hookp->next)
|
||||
if (hookp->type == hook_MobjDamage
|
||||
&& (hookp->s.mt == MT_NULL || hookp->s.mt == target->type))
|
||||
// Look for all generic mobj damage hooks
|
||||
for (hookp = mobjhooks[MT_NULL]; hookp; hookp = hookp->next)
|
||||
if (hookp->type == hook_MobjDamage)
|
||||
{
|
||||
if (lua_gettop(gL) == 0)
|
||||
{
|
||||
LUA_PushUserdata(gL, target, META_MOBJ);
|
||||
LUA_PushUserdata(gL, inflictor, META_MOBJ);
|
||||
LUA_PushUserdata(gL, source, META_MOBJ);
|
||||
lua_pushinteger(gL, damage);
|
||||
}
|
||||
lua_pushfstring(gL, FMT_HOOKID, hookp->id);
|
||||
lua_gettable(gL, LUA_REGISTRYINDEX);
|
||||
lua_pushvalue(gL, -5);
|
||||
lua_pushvalue(gL, -5);
|
||||
lua_pushvalue(gL, -5);
|
||||
lua_pushvalue(gL, -5);
|
||||
if (lua_pcall(gL, 4, 1, 0)) {
|
||||
if (!hookp->error || cv_debug & DBG_LUA)
|
||||
CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1));
|
||||
lua_pop(gL, 1);
|
||||
hookp->error = true;
|
||||
continue;
|
||||
}
|
||||
if (lua_toboolean(gL, -1))
|
||||
hooked = true;
|
||||
lua_pop(gL, 1);
|
||||
}
|
||||
|
||||
for (hookp = mobjhooks[target->type]; hookp; hookp = hookp->next)
|
||||
if (hookp->type == hook_MobjDamage)
|
||||
{
|
||||
if (lua_gettop(gL) == 0)
|
||||
{
|
||||
|
@ -512,9 +749,35 @@ boolean LUAh_MobjDeath(mobj_t *target, mobj_t *inflictor, mobj_t *source)
|
|||
|
||||
lua_settop(gL, 0);
|
||||
|
||||
for (hookp = roothook; hookp; hookp = hookp->next)
|
||||
if (hookp->type == hook_MobjDeath
|
||||
&& (hookp->s.mt == MT_NULL || hookp->s.mt == target->type))
|
||||
// Look for all generic mobj death hooks
|
||||
for (hookp = mobjhooks[MT_NULL]; hookp; hookp = hookp->next)
|
||||
if (hookp->type == hook_MobjDeath)
|
||||
{
|
||||
if (lua_gettop(gL) == 0)
|
||||
{
|
||||
LUA_PushUserdata(gL, target, META_MOBJ);
|
||||
LUA_PushUserdata(gL, inflictor, META_MOBJ);
|
||||
LUA_PushUserdata(gL, source, META_MOBJ);
|
||||
}
|
||||
lua_pushfstring(gL, FMT_HOOKID, hookp->id);
|
||||
lua_gettable(gL, LUA_REGISTRYINDEX);
|
||||
lua_pushvalue(gL, -4);
|
||||
lua_pushvalue(gL, -4);
|
||||
lua_pushvalue(gL, -4);
|
||||
if (lua_pcall(gL, 3, 1, 0)) {
|
||||
if (!hookp->error || cv_debug & DBG_LUA)
|
||||
CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1));
|
||||
lua_pop(gL, 1);
|
||||
hookp->error = true;
|
||||
continue;
|
||||
}
|
||||
if (lua_toboolean(gL, -1))
|
||||
hooked = true;
|
||||
lua_pop(gL, 1);
|
||||
}
|
||||
|
||||
for (hookp = mobjhooks[target->type]; hookp; hookp = hookp->next)
|
||||
if (hookp->type == hook_MobjDeath)
|
||||
{
|
||||
if (lua_gettop(gL) == 0)
|
||||
{
|
||||
|
@ -652,9 +915,8 @@ boolean LUAh_LinedefExecute(line_t *line, mobj_t *mo, sector_t *sector)
|
|||
|
||||
lua_settop(gL, 0);
|
||||
|
||||
for (hookp = roothook; hookp; hookp = hookp->next)
|
||||
if (hookp->type == hook_LinedefExecute
|
||||
&& !strcmp(hookp->s.funcname, line->text))
|
||||
for (hookp = linedefexecutorhooks; hookp; hookp = hookp->next)
|
||||
if (!strcmp(hookp->s.funcname, line->text))
|
||||
{
|
||||
if (lua_gettop(gL) == 0)
|
||||
{
|
||||
|
|
|
@ -18,6 +18,9 @@ enum hud {
|
|||
hud_time,
|
||||
hud_rings,
|
||||
hud_lives,
|
||||
// Match / CTF / Tag / Ringslinger
|
||||
hud_weaponrings,
|
||||
hud_powerstones,
|
||||
// NiGHTS mode
|
||||
hud_nightslink,
|
||||
hud_nightsdrill,
|
||||
|
|
|
@ -44,6 +44,9 @@ static const char *const hud_disable_options[] = {
|
|||
"rings",
|
||||
"lives",
|
||||
|
||||
"weaponrings",
|
||||
"powerstones",
|
||||
|
||||
"nightslink",
|
||||
"nightsdrill",
|
||||
"nightsrings",
|
||||
|
@ -366,6 +369,8 @@ static int libd_drawScaled(lua_State *L)
|
|||
x = luaL_checkinteger(L, 1);
|
||||
y = luaL_checkinteger(L, 2);
|
||||
scale = luaL_checkinteger(L, 3);
|
||||
if (scale < 0)
|
||||
return luaL_error(L, "negative scale");
|
||||
patch = *((patch_t **)luaL_checkudata(L, 4, META_PATCH));
|
||||
flags = luaL_optinteger(L, 5, 0);
|
||||
if (!lua_isnoneornil(L, 6))
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -59,7 +59,11 @@
|
|||
* Unconditionally aligning does not cost very much, so do it if unsure
|
||||
*/
|
||||
#ifndef STRICT_ALIGN
|
||||
# define STRICT_ALIGN !(defined(__i386) || defined (__amd64)) || defined (__clang__)
|
||||
#if !(defined(__i386) || defined (__amd64)) || defined (__clang__)
|
||||
#define STRICT_ALIGN 1
|
||||
#else
|
||||
#define STRICT_ALIGN 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
|
167
src/m_aatree.c
Normal file
167
src/m_aatree.c
Normal file
|
@ -0,0 +1,167 @@
|
|||
// SONIC ROBO BLAST 2
|
||||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) 1993-1996 by id Software, Inc.
|
||||
// Copyright (C) 1998-2000 by DooM Legacy Team.
|
||||
// Copyright (C) 1999-2016 by Sonic Team Junior.
|
||||
//
|
||||
// This program is free software distributed under the
|
||||
// terms of the GNU General Public License, version 2.
|
||||
// See the 'LICENSE' file for more details.
|
||||
//-----------------------------------------------------------------------------
|
||||
/// \file m_aatree.h
|
||||
/// \brief AA trees code
|
||||
|
||||
#include "m_aatree.h"
|
||||
#include "z_zone.h"
|
||||
|
||||
// A partial implementation of AA trees,
|
||||
// according to the algorithms given on Wikipedia.
|
||||
// http://en.wikipedia.org/wiki/AA_tree
|
||||
|
||||
typedef struct aatree_node_s
|
||||
{
|
||||
INT32 level;
|
||||
INT32 key;
|
||||
void* value;
|
||||
|
||||
struct aatree_node_s *left, *right;
|
||||
} aatree_node_t;
|
||||
|
||||
struct aatree_s
|
||||
{
|
||||
aatree_node_t *root;
|
||||
UINT32 flags;
|
||||
};
|
||||
|
||||
aatree_t *M_AATreeAlloc(UINT32 flags)
|
||||
{
|
||||
aatree_t *aatree = Z_Malloc(sizeof (aatree_t), PU_STATIC, NULL);
|
||||
aatree->root = NULL;
|
||||
aatree->flags = flags;
|
||||
return aatree;
|
||||
}
|
||||
|
||||
static void M_AATreeFree_Node(aatree_node_t *node)
|
||||
{
|
||||
if (node->left) M_AATreeFree_Node(node->left);
|
||||
if (node->right) M_AATreeFree_Node(node->right);
|
||||
Z_Free(node);
|
||||
}
|
||||
|
||||
void M_AATreeFree(aatree_t *aatree)
|
||||
{
|
||||
if (aatree->root)
|
||||
M_AATreeFree_Node(aatree->root);
|
||||
|
||||
Z_Free(aatree);
|
||||
}
|
||||
|
||||
static aatree_node_t *M_AATreeSkew(aatree_node_t *node)
|
||||
{
|
||||
if (node && node->left && node->left->level == node->level)
|
||||
{
|
||||
// Not allowed: horizontal left-link. Reverse the
|
||||
// horizontal link and hook the orphan back in.
|
||||
aatree_node_t *oldleft = node->left;
|
||||
node->left = oldleft->right;
|
||||
oldleft->right = node;
|
||||
|
||||
return oldleft;
|
||||
}
|
||||
|
||||
// No change needed.
|
||||
return node;
|
||||
}
|
||||
|
||||
static aatree_node_t *M_AATreeSplit(aatree_node_t *node)
|
||||
{
|
||||
if (node && node->right && node->right->right && node->level == node->right->right->level)
|
||||
{
|
||||
// Not allowed: two consecutive horizontal right-links.
|
||||
// The middle one becomes the new root at this point,
|
||||
// with suitable adjustments below.
|
||||
|
||||
aatree_node_t *oldright = node->right;
|
||||
node->right = oldright->left;
|
||||
oldright->left = node;
|
||||
oldright->level++;
|
||||
|
||||
return oldright;
|
||||
}
|
||||
|
||||
// No change needed.
|
||||
return node;
|
||||
}
|
||||
|
||||
static aatree_node_t *M_AATreeSet_Node(aatree_node_t *node, UINT32 flags, INT32 key, void* value)
|
||||
{
|
||||
if (!node)
|
||||
{
|
||||
// Nothing here, so just add where we are
|
||||
|
||||
node = Z_Malloc(sizeof (aatree_node_t), PU_STATIC, NULL);
|
||||
node->level = 1;
|
||||
node->key = key;
|
||||
if (value && (flags & AATREE_ZUSER)) Z_SetUser(value, &node->value);
|
||||
else node->value = value;
|
||||
node->left = node->right = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (key < node->key)
|
||||
node->left = M_AATreeSet_Node(node->left, flags, key, value);
|
||||
else if (key > node->key)
|
||||
node->right = M_AATreeSet_Node(node->right, flags, key, value);
|
||||
else
|
||||
{
|
||||
if (value && (flags & AATREE_ZUSER)) Z_SetUser(value, &node->value);
|
||||
else node->value = value;
|
||||
}
|
||||
|
||||
node = M_AATreeSkew(node);
|
||||
node = M_AATreeSplit(node);
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
void M_AATreeSet(aatree_t *aatree, INT32 key, void* value)
|
||||
{
|
||||
aatree->root = M_AATreeSet_Node(aatree->root, aatree->flags, key, value);
|
||||
}
|
||||
|
||||
// Caveat: we don't distinguish between nodes that don't exists
|
||||
// and nodes with value == NULL.
|
||||
static void *M_AATreeGet_Node(aatree_node_t *node, INT32 key)
|
||||
{
|
||||
if (node)
|
||||
{
|
||||
if (node->key == key)
|
||||
return node->value;
|
||||
else if(node->key < key)
|
||||
return M_AATreeGet_Node(node->right, key);
|
||||
else
|
||||
return M_AATreeGet_Node(node->left, key);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void *M_AATreeGet(aatree_t *aatree, INT32 key)
|
||||
{
|
||||
return M_AATreeGet_Node(aatree->root, key);
|
||||
}
|
||||
|
||||
|
||||
static void M_AATreeIterate_Node(aatree_node_t *node, aatree_iter_t callback)
|
||||
{
|
||||
if (node->left) M_AATreeIterate_Node(node->left, callback);
|
||||
callback(node->key, node->value);
|
||||
if (node->right) M_AATreeIterate_Node(node->right, callback);
|
||||
}
|
||||
|
||||
void M_AATreeIterate(aatree_t *aatree, aatree_iter_t callback)
|
||||
{
|
||||
if (aatree->root)
|
||||
M_AATreeIterate_Node(aatree->root, callback);
|
||||
}
|
31
src/m_aatree.h
Normal file
31
src/m_aatree.h
Normal file
|
@ -0,0 +1,31 @@
|
|||
// SONIC ROBO BLAST 2
|
||||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) 1993-1996 by id Software, Inc.
|
||||
// Copyright (C) 1998-2000 by DooM Legacy Team.
|
||||
// Copyright (C) 1999-2016 by Sonic Team Junior.
|
||||
//
|
||||
// This program is free software distributed under the
|
||||
// terms of the GNU General Public License, version 2.
|
||||
// See the 'LICENSE' file for more details.
|
||||
//-----------------------------------------------------------------------------
|
||||
/// \file m_aatree.h
|
||||
/// \brief AA trees code
|
||||
|
||||
#ifndef __M_AATREE__
|
||||
#define __M_AATREE__
|
||||
|
||||
#include "doomtype.h"
|
||||
|
||||
// Flags for AA trees.
|
||||
#define AATREE_ZUSER 1 // Treat values as z_zone-allocated blocks and set their user fields
|
||||
|
||||
typedef struct aatree_s aatree_t;
|
||||
typedef void (*aatree_iter_t)(INT32 key, void *value);
|
||||
|
||||
aatree_t *M_AATreeAlloc(UINT32 flags);
|
||||
void M_AATreeFree(aatree_t *aatree);
|
||||
void M_AATreeSet(aatree_t *aatree, INT32 key, void* value);
|
||||
void *M_AATreeGet(aatree_t *aatree, INT32 key);
|
||||
void M_AATreeIterate(aatree_t *aatree, aatree_iter_t callback);
|
||||
|
||||
#endif
|
|
@ -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"));
|
||||
|
|
|
@ -46,41 +46,6 @@ typedef INT32 fixed_t;
|
|||
#define FLOAT_TO_FIXED(f) (fixed_t)((f) * ((float)FRACUNIT))
|
||||
|
||||
|
||||
/** \brief The TMulScale16 function
|
||||
|
||||
\param a a parameter of type fixed_t
|
||||
\param b a parameter of type fixed_t
|
||||
\param c a parameter of type fixed_t
|
||||
\param d a parameter of type fixed_t
|
||||
\param e a parameter of type fixed_t
|
||||
\param f a parameter of type fixed_t
|
||||
|
||||
\return fixed_t
|
||||
|
||||
|
||||
*/
|
||||
FUNCMATH FUNCINLINE static ATTRINLINE fixed_t TMulScale16(fixed_t a, fixed_t b, fixed_t c, fixed_t d, fixed_t e, fixed_t f) \
|
||||
{ \
|
||||
return (fixed_t)((((INT64)a * (INT64)b) + ((INT64)c * (INT64)d) \
|
||||
+ ((INT64)e * (INT64)f)) >> 16); \
|
||||
}
|
||||
|
||||
/** \brief The DMulScale16 function
|
||||
|
||||
\param a a parameter of type fixed_t
|
||||
\param b a parameter of type fixed_t
|
||||
\param c a parameter of type fixed_t
|
||||
\param d a parameter of type fixed_t
|
||||
|
||||
\return fixed_t
|
||||
|
||||
|
||||
*/
|
||||
FUNCMATH FUNCINLINE static ATTRINLINE fixed_t DMulScale16(fixed_t a, fixed_t b, fixed_t c, fixed_t d) \
|
||||
{ \
|
||||
return (fixed_t)((((INT64)a * (INT64)b) + ((INT64)c * (INT64)d)) >> 16); \
|
||||
}
|
||||
|
||||
#if defined (__WATCOMC__) && FRACBITS == 16
|
||||
#pragma aux FixedMul = \
|
||||
"imul ebx", \
|
||||
|
@ -283,9 +248,16 @@ FUNCMATH FUNCINLINE static ATTRINLINE fixed_t FixedFloor(fixed_t x)
|
|||
{
|
||||
const fixed_t a = abs(x); //absolute of x
|
||||
const fixed_t i = (a>>FRACBITS)<<FRACBITS; // cut out the fractional part
|
||||
const fixed_t f = i-a; // cut out the integral part
|
||||
const fixed_t f = a-i; // cut out the integral part
|
||||
if (f == 0)
|
||||
return x;
|
||||
if (x != INT32_MIN)
|
||||
return x-f; // return largest integral value not greater than argument
|
||||
{ // return rounded down to nearest whole number
|
||||
if (x > 0)
|
||||
return x-f;
|
||||
else
|
||||
return x-(FRACUNIT-f);
|
||||
}
|
||||
return INT32_MIN;
|
||||
}
|
||||
|
||||
|
@ -301,7 +273,7 @@ FUNCMATH FUNCINLINE static ATTRINLINE fixed_t FixedTrunc(fixed_t x)
|
|||
{
|
||||
const fixed_t a = abs(x); //absolute of x
|
||||
const fixed_t i = (a>>FRACBITS)<<FRACBITS; // cut out the fractional part
|
||||
const fixed_t f = i-a; // cut out the integral part
|
||||
const fixed_t f = a-i; // cut out the integral part
|
||||
if (x != INT32_MIN)
|
||||
{ // return rounded to nearest whole number, towards zero
|
||||
if (x > 0)
|
||||
|
@ -324,11 +296,18 @@ FUNCMATH FUNCINLINE static ATTRINLINE fixed_t FixedCeil(fixed_t x)
|
|||
{
|
||||
const fixed_t a = abs(x); //absolute of x
|
||||
const fixed_t i = (a>>FRACBITS)<<FRACBITS; // cut out the fractional part
|
||||
const fixed_t f = i-a; // cut out the integral part
|
||||
const fixed_t f = a-i; // cut out the integral part
|
||||
if (f == 0)
|
||||
return x;
|
||||
if (x == INT32_MIN)
|
||||
return INT32_MIN;
|
||||
else if (x < FixedFloor(INT32_MAX))
|
||||
return x+(FRACUNIT-f); // return smallest integral value not less than argument
|
||||
{ // return rounded up to nearest whole number
|
||||
if (x > 0)
|
||||
return x+(FRACUNIT-f);
|
||||
else
|
||||
return x+f;
|
||||
}
|
||||
return INT32_MAX;
|
||||
}
|
||||
|
||||
|
@ -344,7 +323,9 @@ FUNCMATH FUNCINLINE static ATTRINLINE fixed_t FixedRound(fixed_t x)
|
|||
{
|
||||
const fixed_t a = abs(x); //absolute of x
|
||||
const fixed_t i = (a>>FRACBITS)<<FRACBITS; // cut out the fractional part
|
||||
const fixed_t f = i-a; // cut out the integral part
|
||||
const fixed_t f = a-i; // cut out the integral part
|
||||
if (f == 0)
|
||||
return x;
|
||||
if (x == INT32_MIN)
|
||||
return INT32_MIN;
|
||||
else if (x < FixedFloor(INT32_MAX))
|
||||
|
|
31
src/m_menu.c
31
src/m_menu.c
|
@ -182,9 +182,6 @@ static INT32 vidm_selected = 0;
|
|||
static INT32 vidm_nummodes;
|
||||
static INT32 vidm_column_size;
|
||||
|
||||
// what a headache.
|
||||
static boolean shiftdown = false;
|
||||
|
||||
//
|
||||
// PROTOTYPES
|
||||
//
|
||||
|
@ -705,7 +702,7 @@ static menuitem_t SP_TimeAttackMenu[] =
|
|||
{IT_DISABLED, NULL, "Guest Option...", &SP_GuestReplayDef, 100},
|
||||
{IT_DISABLED, NULL, "Replay...", &SP_ReplayDef, 110},
|
||||
{IT_DISABLED, NULL, "Ghosts...", &SP_GhostDef, 120},
|
||||
{IT_WHITESTRING|IT_CALL, NULL, "Start", M_ChooseTimeAttack, 130},
|
||||
{IT_WHITESTRING|IT_CALL|IT_CALL_NOTMODIFIED, NULL, "Start", M_ChooseTimeAttack, 130},
|
||||
};
|
||||
|
||||
enum
|
||||
|
@ -797,7 +794,7 @@ static menuitem_t SP_NightsAttackMenu[] =
|
|||
{IT_DISABLED, NULL, "Guest Option...", &SP_NightsGuestReplayDef, 108},
|
||||
{IT_DISABLED, NULL, "Replay...", &SP_NightsReplayDef, 118},
|
||||
{IT_DISABLED, NULL, "Ghosts...", &SP_NightsGhostDef, 128},
|
||||
{IT_WHITESTRING|IT_CALL, NULL, "Start", M_ChooseNightsAttack, 138},
|
||||
{IT_WHITESTRING|IT_CALL|IT_CALL_NOTMODIFIED, NULL, "Start", M_ChooseNightsAttack, 138},
|
||||
};
|
||||
|
||||
enum
|
||||
|
@ -2080,11 +2077,6 @@ boolean M_Responder(event_t *ev)
|
|||
|| gamestate == GS_CREDITS || gamestate == GS_EVALUATION)
|
||||
return false;
|
||||
|
||||
if (ev->type == ev_keyup && (ev->data1 == KEY_LSHIFT || ev->data1 == KEY_RSHIFT))
|
||||
{
|
||||
shiftdown = false;
|
||||
return false;
|
||||
}
|
||||
if (noFurtherInput)
|
||||
{
|
||||
// Ignore input after enter/escape/other buttons
|
||||
|
@ -2098,10 +2090,6 @@ boolean M_Responder(event_t *ev)
|
|||
// added 5-2-98 remap virtual keys (mouse & joystick buttons)
|
||||
switch (ch)
|
||||
{
|
||||
case KEY_LSHIFT:
|
||||
case KEY_RSHIFT:
|
||||
shiftdown = true;
|
||||
break; //return false;
|
||||
case KEY_MOUSE1:
|
||||
case KEY_JOY1:
|
||||
case KEY_JOY1 + 2:
|
||||
|
@ -3702,6 +3690,11 @@ static void M_DrawMessageMenu(void)
|
|||
|
||||
mlines = currentMenu->lastOn>>8;
|
||||
max = (INT16)((UINT8)(currentMenu->lastOn & 0xFF)*8);
|
||||
|
||||
// hack: draw RA background in RA menus
|
||||
if (gamestate == GS_TIMEATTACK)
|
||||
V_DrawPatchFill(W_CachePatchName("SRB2BACK", PU_CACHE));
|
||||
|
||||
M_DrawTextBox(currentMenu->x, y - 8, (max+7)>>3, mlines);
|
||||
|
||||
while (*(msg+start))
|
||||
|
@ -3856,6 +3849,7 @@ static void M_ChangeLevel(INT32 choice)
|
|||
static void M_ConfirmSpectate(INT32 choice)
|
||||
{
|
||||
(void)choice;
|
||||
// We allow switching to spectator even if team changing is not allowed
|
||||
M_ClearMenus(true);
|
||||
COM_ImmedExecute("changeteam spectator");
|
||||
}
|
||||
|
@ -3863,6 +3857,11 @@ static void M_ConfirmSpectate(INT32 choice)
|
|||
static void M_ConfirmEnterGame(INT32 choice)
|
||||
{
|
||||
(void)choice;
|
||||
if (!cv_allowteamchange.value)
|
||||
{
|
||||
M_StartMessage(M_GetText("The server is not allowing\nteam changes at this time.\nPress a key.\n"), NULL, MM_NOTHING);
|
||||
return;
|
||||
}
|
||||
M_ClearMenus(true);
|
||||
COM_ImmedExecute("changeteam playing");
|
||||
}
|
||||
|
@ -4310,9 +4309,9 @@ static void M_SinglePlayerMenu(INT32 choice)
|
|||
{
|
||||
(void)choice;
|
||||
SP_MainMenu[sprecordattack].status =
|
||||
(M_SecretUnlocked(SECRET_RECORDATTACK)) ? IT_CALL|IT_STRING|IT_CALL_NOTMODIFIED : IT_SECRET;
|
||||
(M_SecretUnlocked(SECRET_RECORDATTACK)) ? IT_CALL|IT_STRING : IT_SECRET;
|
||||
SP_MainMenu[spnightsmode].status =
|
||||
(M_SecretUnlocked(SECRET_NIGHTSMODE)) ? IT_CALL|IT_STRING|IT_CALL_NOTMODIFIED : IT_SECRET;
|
||||
(M_SecretUnlocked(SECRET_NIGHTSMODE)) ? IT_CALL|IT_STRING : IT_SECRET;
|
||||
|
||||
M_SetupNextMenu(&SP_MainDef);
|
||||
}
|
||||
|
|
159
src/m_misc.c
159
src/m_misc.c
|
@ -585,7 +585,7 @@ static const char *Newsnapshotfile(const char *pathname, const char *ext)
|
|||
|
||||
i += add * result;
|
||||
|
||||
if (add < 0 || add > 9999)
|
||||
if (i < 0 || i > 9999)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -1675,6 +1675,7 @@ char *M_GetToken(const char *inputString)
|
|||
|| stringToUse[startPos] == '\r'
|
||||
|| stringToUse[startPos] == '\n'
|
||||
|| stringToUse[startPos] == '\0'
|
||||
|| stringToUse[startPos] == '"' // we're treating this as whitespace because SLADE likes adding it for no good reason
|
||||
|| inComment != 0)
|
||||
&& startPos < stringLength)
|
||||
{
|
||||
|
@ -1742,6 +1743,7 @@ char *M_GetToken(const char *inputString)
|
|||
&& stringToUse[endPos] != ','
|
||||
&& stringToUse[endPos] != '{'
|
||||
&& stringToUse[endPos] != '}'
|
||||
&& stringToUse[endPos] != '"' // see above
|
||||
&& inComment == 0)
|
||||
&& endPos < stringLength)
|
||||
{
|
||||
|
@ -2323,158 +2325,3 @@ void M_SetupMemcpy(void)
|
|||
M_Memcpy = cpu_cpy;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
// A partial implementation of AA trees,
|
||||
// according to the algorithms given on Wikipedia.
|
||||
// http://en.wikipedia.org/wiki/AA_tree
|
||||
|
||||
|
||||
|
||||
typedef struct aatree_node_s
|
||||
{
|
||||
INT32 level;
|
||||
INT32 key;
|
||||
void* value;
|
||||
|
||||
struct aatree_node_s *left, *right;
|
||||
} aatree_node_t;
|
||||
|
||||
struct aatree_s
|
||||
{
|
||||
aatree_node_t *root;
|
||||
UINT32 flags;
|
||||
};
|
||||
|
||||
aatree_t *M_AATreeAlloc(UINT32 flags)
|
||||
{
|
||||
aatree_t *aatree = Z_Malloc(sizeof (aatree_t), PU_STATIC, NULL);
|
||||
aatree->root = NULL;
|
||||
aatree->flags = flags;
|
||||
return aatree;
|
||||
}
|
||||
|
||||
static void M_AATreeFree_Node(aatree_node_t *node)
|
||||
{
|
||||
if (node->left) M_AATreeFree_Node(node->left);
|
||||
if (node->right) M_AATreeFree_Node(node->right);
|
||||
Z_Free(node);
|
||||
}
|
||||
|
||||
void M_AATreeFree(aatree_t *aatree)
|
||||
{
|
||||
if (aatree->root)
|
||||
M_AATreeFree_Node(aatree->root);
|
||||
|
||||
Z_Free(aatree);
|
||||
}
|
||||
|
||||
static aatree_node_t *M_AATreeSkew(aatree_node_t *node)
|
||||
{
|
||||
if (node && node->left && node->left->level == node->level)
|
||||
{
|
||||
// Not allowed: horizontal left-link. Reverse the
|
||||
// horizontal link and hook the orphan back in.
|
||||
aatree_node_t *oldleft = node->left;
|
||||
node->left = oldleft->right;
|
||||
oldleft->right = node;
|
||||
|
||||
return oldleft;
|
||||
}
|
||||
|
||||
// No change needed.
|
||||
return node;
|
||||
}
|
||||
|
||||
static aatree_node_t *M_AATreeSplit(aatree_node_t *node)
|
||||
{
|
||||
if (node && node->right && node->right->right && node->level == node->right->right->level)
|
||||
{
|
||||
// Not allowed: two consecutive horizontal right-links.
|
||||
// The middle one becomes the new root at this point,
|
||||
// with suitable adjustments below.
|
||||
|
||||
aatree_node_t *oldright = node->right;
|
||||
node->right = oldright->left;
|
||||
oldright->left = node;
|
||||
oldright->level++;
|
||||
|
||||
return oldright;
|
||||
}
|
||||
|
||||
// No change needed.
|
||||
return node;
|
||||
}
|
||||
|
||||
static aatree_node_t *M_AATreeSet_Node(aatree_node_t *node, UINT32 flags, INT32 key, void* value)
|
||||
{
|
||||
if (!node)
|
||||
{
|
||||
// Nothing here, so just add where we are
|
||||
|
||||
node = Z_Malloc(sizeof (aatree_node_t), PU_STATIC, NULL);
|
||||
node->level = 1;
|
||||
node->key = key;
|
||||
if (value && (flags & AATREE_ZUSER)) Z_SetUser(value, &node->value);
|
||||
else node->value = value;
|
||||
node->left = node->right = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (key < node->key)
|
||||
node->left = M_AATreeSet_Node(node->left, flags, key, value);
|
||||
else if (key > node->key)
|
||||
node->right = M_AATreeSet_Node(node->right, flags, key, value);
|
||||
else
|
||||
{
|
||||
if (value && (flags & AATREE_ZUSER)) Z_SetUser(value, &node->value);
|
||||
else node->value = value;
|
||||
}
|
||||
|
||||
node = M_AATreeSkew(node);
|
||||
node = M_AATreeSplit(node);
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
void M_AATreeSet(aatree_t *aatree, INT32 key, void* value)
|
||||
{
|
||||
aatree->root = M_AATreeSet_Node(aatree->root, aatree->flags, key, value);
|
||||
}
|
||||
|
||||
// Caveat: we don't distinguish between nodes that don't exists
|
||||
// and nodes with value == NULL.
|
||||
static void *M_AATreeGet_Node(aatree_node_t *node, INT32 key)
|
||||
{
|
||||
if (node)
|
||||
{
|
||||
if (node->key == key)
|
||||
return node->value;
|
||||
else if(node->key < key)
|
||||
return M_AATreeGet_Node(node->right, key);
|
||||
else
|
||||
return M_AATreeGet_Node(node->left, key);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void *M_AATreeGet(aatree_t *aatree, INT32 key)
|
||||
{
|
||||
return M_AATreeGet_Node(aatree->root, key);
|
||||
}
|
||||
|
||||
|
||||
static void M_AATreeIterate_Node(aatree_node_t *node, aatree_iter_t callback)
|
||||
{
|
||||
if (node->left) M_AATreeIterate_Node(node->left, callback);
|
||||
callback(node->key, node->value);
|
||||
if (node->right) M_AATreeIterate_Node(node->right, callback);
|
||||
}
|
||||
|
||||
void M_AATreeIterate(aatree_t *aatree, aatree_iter_t callback)
|
||||
{
|
||||
if (aatree->root)
|
||||
M_AATreeIterate_Node(aatree->root, callback);
|
||||
}
|
||||
|
|
13
src/m_misc.h
13
src/m_misc.h
|
@ -96,19 +96,6 @@ void M_SetupMemcpy(void);
|
|||
// counting bits, for weapon ammo code, usually
|
||||
FUNCMATH UINT8 M_CountBits(UINT32 num, UINT8 size);
|
||||
|
||||
// Flags for AA trees.
|
||||
#define AATREE_ZUSER 1 // Treat values as z_zone-allocated blocks and set their user fields
|
||||
|
||||
typedef struct aatree_s aatree_t;
|
||||
typedef void (*aatree_iter_t)(INT32 key, void *value);
|
||||
|
||||
aatree_t *M_AATreeAlloc(UINT32 flags);
|
||||
void M_AATreeFree(aatree_t *aatree);
|
||||
void M_AATreeSet(aatree_t *aatree, INT32 key, void* value);
|
||||
void *M_AATreeGet(aatree_t *aatree, INT32 key);
|
||||
void M_AATreeIterate(aatree_t *aatree, aatree_iter_t callback);
|
||||
|
||||
// Nasty cyclic dependency workaround. This must come after aatree stuff.
|
||||
#include "w_wad.h"
|
||||
extern char configfile[MAX_WADPATH];
|
||||
|
||||
|
|
|
@ -269,6 +269,18 @@ INT32 I_PutEnv(char *variable)
|
|||
return -1;
|
||||
}
|
||||
|
||||
INT32 I_ClipboardCopy(const char *data, size_t size)
|
||||
{
|
||||
(void)data;
|
||||
(void)size;
|
||||
return -1;
|
||||
}
|
||||
|
||||
char *I_ClipboardPaste(void)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void I_RegisterSysCommands(void) {}
|
||||
|
||||
#include "../sdl/dosstr.c"
|
||||
|
|
|
@ -1102,7 +1102,7 @@ void A_JetJawChomp(mobj_t *actor)
|
|||
if (!actor->target || !(actor->target->flags & MF_SHOOTABLE)
|
||||
|| actor->target->health <= 0 || !P_CheckSight(actor, actor->target))
|
||||
{
|
||||
P_SetMobjState(actor, actor->info->spawnstate);
|
||||
P_SetMobjStateNF(actor, actor->info->spawnstate);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -7644,7 +7644,7 @@ void A_SetObjectFlags(mobj_t *actor)
|
|||
else if (locvar2 == 1)
|
||||
locvar1 = actor->flags & ~locvar1;
|
||||
|
||||
if ((locvar1 & (MF_NOBLOCKMAP|MF_NOSECTOR)) != (actor->flags & (MF_NOBLOCKMAP|MF_NOSECTOR))) // Blockmap/sector status has changed, so reset the links
|
||||
if ((UINT32)(locvar1 & (MF_NOBLOCKMAP|MF_NOSECTOR)) != (actor->flags & (MF_NOBLOCKMAP|MF_NOSECTOR))) // Blockmap/sector status has changed, so reset the links
|
||||
unlinkthings = true;
|
||||
|
||||
if (unlinkthings) {
|
||||
|
|
|
@ -1163,7 +1163,7 @@ void T_SpikeSector(levelspecthink_t *spikes)
|
|||
|
||||
node = spikes->sector->touching_thinglist; // things touching this sector
|
||||
|
||||
for (; node; node = node->m_snext)
|
||||
for (; node; node = node->m_thinglist_next)
|
||||
{
|
||||
thing = node->m_thing;
|
||||
if (!thing->player)
|
||||
|
@ -1316,7 +1316,7 @@ void T_BridgeThinker(levelspecthink_t *bridge)
|
|||
controlsec = §ors[k];
|
||||
|
||||
// Is a player standing on me?
|
||||
for (node = sector->touching_thinglist; node; node = node->m_snext)
|
||||
for (node = sector->touching_thinglist; node; node = node->m_thinglist_next)
|
||||
{
|
||||
thing = node->m_thing;
|
||||
|
||||
|
@ -1739,7 +1739,7 @@ wegotit:
|
|||
static mobj_t *SearchMarioNode(msecnode_t *node)
|
||||
{
|
||||
mobj_t *thing = NULL;
|
||||
for (; node; node = node->m_snext)
|
||||
for (; node; node = node->m_thinglist_next)
|
||||
{
|
||||
// Things which should NEVER be ejected from a MarioBlock, by type.
|
||||
switch (node->m_thing->type)
|
||||
|
@ -2003,7 +2003,7 @@ void T_NoEnemiesSector(levelspecthink_t *nobaddies)
|
|||
goto foundenemy;
|
||||
}
|
||||
|
||||
node = node->m_snext;
|
||||
node = node->m_thinglist_next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2288,7 +2288,7 @@ void T_RaiseSector(levelspecthink_t *raise)
|
|||
sector = §ors[i];
|
||||
|
||||
// Is a player standing on me?
|
||||
for (node = sector->touching_thinglist; node; node = node->m_snext)
|
||||
for (node = sector->touching_thinglist; node; node = node->m_thinglist_next)
|
||||
{
|
||||
thing = node->m_thing;
|
||||
|
||||
|
|
|
@ -1684,7 +1684,7 @@ void P_CheckTimeLimit(void)
|
|||
return;
|
||||
|
||||
//Tagmode round end but only on the tic before the
|
||||
//XD_EXITLEVEL packet is recieved by all players.
|
||||
//XD_EXITLEVEL packet is received by all players.
|
||||
if (G_TagGametype())
|
||||
{
|
||||
if (leveltime == (timelimitintics + 1))
|
||||
|
@ -1695,7 +1695,7 @@ void P_CheckTimeLimit(void)
|
|||
|| (players[i].pflags & PF_TAGGED) || (players[i].pflags & PF_TAGIT))
|
||||
continue;
|
||||
|
||||
CONS_Printf(M_GetText("%s recieved double points for surviving the round.\n"), player_names[i]);
|
||||
CONS_Printf(M_GetText("%s received double points for surviving the round.\n"), player_names[i]);
|
||||
P_AddPlayerScore(&players[i], players[i].score);
|
||||
}
|
||||
}
|
||||
|
@ -3626,7 +3626,7 @@ void P_PlayerFlagBurst(player_t *player, boolean toss)
|
|||
// Flag text
|
||||
{
|
||||
char plname[MAXPLAYERNAME+4];
|
||||
char *flagtext;
|
||||
const char *flagtext;
|
||||
char flagcolor;
|
||||
|
||||
snprintf(plname, sizeof(plname), "%s%s%s",
|
||||
|
|
|
@ -251,7 +251,8 @@ mobj_t *P_SPMAngle(mobj_t *source, mobjtype_t type, angle_t angle, UINT8 aimtype
|
|||
#endif
|
||||
void P_ColorTeamMissile(mobj_t *missile, player_t *source);
|
||||
SINT8 P_MobjFlip(mobj_t *mobj);
|
||||
boolean P_WeaponOrPanel(mobjtype_t type);
|
||||
fixed_t P_GetMobjGravity(mobj_t *mo);
|
||||
FUNCMATH boolean P_WeaponOrPanel(mobjtype_t type);
|
||||
|
||||
boolean P_CameraThinker(player_t *player, camera_t *thiscam, boolean resetcalled);
|
||||
|
||||
|
|
170
src/p_map.c
170
src/p_map.c
|
@ -129,6 +129,10 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object)
|
|||
return false;
|
||||
}
|
||||
|
||||
#ifdef ESLOPE
|
||||
object->standingslope = NULL; // Okay, now we can't return - no launching off at silly angles for you.
|
||||
#endif
|
||||
|
||||
object->eflags |= MFE_SPRUNG; // apply this flag asap!
|
||||
spring->flags &= ~(MF_SOLID|MF_SPECIAL); // De-solidify
|
||||
|
||||
|
@ -232,20 +236,24 @@ static void P_DoFanAndGasJet(mobj_t *spring, mobj_t *object)
|
|||
if (p && object->state == &states[object->info->painstate]) // can't use fans and gas jets when player is in pain!
|
||||
return;
|
||||
|
||||
// is object below thruster's position? if not, calculate distance between their bottoms
|
||||
// is object's top below thruster's position? if not, calculate distance between their bottoms
|
||||
if (spring->eflags & MFE_VERTICALFLIP)
|
||||
{
|
||||
if (object->z + object->height > spring->z + spring->height)
|
||||
if (object->z > spring->z + spring->height)
|
||||
return;
|
||||
zdist = (spring->z + spring->height) - (object->z + object->height);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (object->z < spring->z)
|
||||
if (object->z + object->height < spring->z)
|
||||
return;
|
||||
zdist = object->z - spring->z;
|
||||
}
|
||||
|
||||
#ifdef ESLOPE
|
||||
object->standingslope = NULL; // No launching off at silly angles for you.
|
||||
#endif
|
||||
|
||||
switch (spring->type)
|
||||
{
|
||||
case MT_FAN: // fan
|
||||
|
@ -977,18 +985,24 @@ static boolean PIT_CheckThing(mobj_t *thing)
|
|||
return true;
|
||||
}
|
||||
|
||||
topz = thing->z - FixedMul(FRACUNIT, thing->scale);
|
||||
topz = thing->z - thing->scale; // FixedMul(FRACUNIT, thing->scale), but thing->scale == FRACUNIT in base scale anyways
|
||||
|
||||
// block only when jumping not high enough,
|
||||
// (dont climb max. 24units while already in air)
|
||||
// if not in air, let P_TryMove() decide if it's not too high
|
||||
// since return false doesn't handle momentum properly,
|
||||
// we lie to P_TryMove() so it's always too high
|
||||
if (tmthing->player && tmthing->z + tmthing->height > topz
|
||||
&& tmthing->z + tmthing->height < tmthing->ceilingz)
|
||||
return false; // block while in air
|
||||
|
||||
if (thing->flags & MF_SPRING)
|
||||
{
|
||||
tmfloorz = tmceilingz = topz; // block while in air
|
||||
#ifdef ESLOPE
|
||||
tmceilingslope = NULL;
|
||||
#endif
|
||||
tmfloorthing = thing; // needed for side collision
|
||||
}
|
||||
else if (thing->flags & MF_SPRING)
|
||||
;
|
||||
else if (topz < tmceilingz && tmthing->z+tmthing->height <= thing->z+thing->height)
|
||||
else if (topz < tmceilingz && tmthing->z <= thing->z+thing->height)
|
||||
{
|
||||
tmceilingz = topz;
|
||||
#ifdef ESLOPE
|
||||
|
@ -1014,17 +1028,24 @@ static boolean PIT_CheckThing(mobj_t *thing)
|
|||
return true;
|
||||
}
|
||||
|
||||
topz = thing->z + thing->height + FixedMul(FRACUNIT, thing->scale);
|
||||
topz = thing->z + thing->height + thing->scale; // FixedMul(FRACUNIT, thing->scale), but thing->scale == FRACUNIT in base scale anyways
|
||||
|
||||
// block only when jumping not high enough,
|
||||
// (dont climb max. 24units while already in air)
|
||||
// if not in air, let P_TryMove() decide if it's not too high
|
||||
if (tmthing->player && tmthing->z < topz && tmthing->z > tmthing->floorz)
|
||||
return false; // block while in air
|
||||
|
||||
if (thing->flags & MF_SPRING)
|
||||
// since return false doesn't handle momentum properly,
|
||||
// we lie to P_TryMove() so it's always too high
|
||||
if (tmthing->player && tmthing->z < topz
|
||||
&& tmthing->z > tmthing->floorz)
|
||||
{
|
||||
tmfloorz = tmceilingz = topz; // block while in air
|
||||
#ifdef ESLOPE
|
||||
tmfloorslope = NULL;
|
||||
#endif
|
||||
tmfloorthing = thing; // needed for side collision
|
||||
}
|
||||
else if (thing->flags & MF_SPRING)
|
||||
;
|
||||
else if (topz > tmfloorz && tmthing->z >= thing->z)
|
||||
else if (topz > tmfloorz && tmthing->z+tmthing->height >= thing->z)
|
||||
{
|
||||
tmfloorz = topz;
|
||||
#ifdef ESLOPE
|
||||
|
@ -1145,7 +1166,7 @@ static boolean PIT_CheckLine(line_t *ld)
|
|||
}
|
||||
|
||||
// set openrange, opentop, openbottom
|
||||
P_LineOpening(ld);
|
||||
P_LineOpening(ld, tmthing);
|
||||
|
||||
// adjust floor / ceiling heights
|
||||
if (opentop < tmceilingz)
|
||||
|
@ -1263,7 +1284,7 @@ boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y)
|
|||
topheight = P_GetFOFTopZ(thing, newsubsec->sector, rover, x, y, NULL);
|
||||
bottomheight = P_GetFOFBottomZ(thing, newsubsec->sector, rover, x, y, NULL);
|
||||
|
||||
if (rover->flags & FF_GOOWATER && !(thing->flags & MF_NOGRAVITY))
|
||||
if ((rover->flags & (FF_SWIMMABLE|FF_GOOWATER)) == (FF_SWIMMABLE|FF_GOOWATER) && !(thing->flags & MF_NOGRAVITY))
|
||||
{
|
||||
// If you're inside goowater and slowing down
|
||||
fixed_t sinklevel = FixedMul(thing->info->height/6, thing->scale);
|
||||
|
@ -1962,8 +1983,12 @@ boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff)
|
|||
}
|
||||
|
||||
// Ramp test
|
||||
if (thing->player && maxstep > 0
|
||||
&& !(P_PlayerTouchingSectorSpecial(thing->player, 1, 14) || GETSECSPECIAL(R_PointInSubsector(x, y)->sector->special, 1) == 14))
|
||||
if (maxstep > 0 && !(
|
||||
thing->player && (
|
||||
P_PlayerTouchingSectorSpecial(thing->player, 1, 14)
|
||||
|| GETSECSPECIAL(R_PointInSubsector(x, y)->sector->special, 1) == 14)
|
||||
)
|
||||
)
|
||||
{
|
||||
// If the floor difference is MAXSTEPMOVE or less, and the sector isn't Section1:14, ALWAYS
|
||||
// step down! Formerly required a Section1:13 sector for the full MAXSTEPMOVE, but no more.
|
||||
|
@ -2423,6 +2448,8 @@ isblocking:
|
|||
//
|
||||
// P_IsClimbingValid
|
||||
//
|
||||
// Unlike P_DoClimbing, don't use when up against a one-sided linedef.
|
||||
//
|
||||
static boolean P_IsClimbingValid(player_t *player, angle_t angle)
|
||||
{
|
||||
fixed_t platx, platy;
|
||||
|
@ -2571,7 +2598,7 @@ static boolean PTR_SlideTraverse(intercept_t *in)
|
|||
}
|
||||
|
||||
// set openrange, opentop, openbottom
|
||||
P_LineOpening(li);
|
||||
P_LineOpening(li, slidemo);
|
||||
|
||||
if (openrange < slidemo->height)
|
||||
goto isblocking; // doesn't fit
|
||||
|
@ -2647,6 +2674,7 @@ isblocking:
|
|||
// see about climbing on the wall
|
||||
if (!(checkline->flags & ML_NOCLIMB))
|
||||
{
|
||||
boolean canclimb;
|
||||
angle_t climbangle, climbline;
|
||||
INT32 whichside = P_PointOnLineSide(slidemo->x, slidemo->y, li);
|
||||
|
||||
|
@ -2657,9 +2685,11 @@ isblocking:
|
|||
|
||||
climbangle += (ANGLE_90 * (whichside ? -1 : 1));
|
||||
|
||||
canclimb = (li->backsector ? P_IsClimbingValid(slidemo->player, climbangle) : true);
|
||||
|
||||
if (((!slidemo->player->climbing && abs((signed)(slidemo->angle - ANGLE_90 - climbline)) < ANGLE_45)
|
||||
|| (slidemo->player->climbing == 1 && abs((signed)(slidemo->angle - climbline)) < ANGLE_135))
|
||||
&& P_IsClimbingValid(slidemo->player, climbangle))
|
||||
&& canclimb)
|
||||
{
|
||||
slidemo->angle = climbangle;
|
||||
if (!demoplayback || P_AnalogMove(slidemo->player))
|
||||
|
@ -3365,7 +3395,7 @@ boolean P_CheckSector(sector_t *sector, boolean crunch)
|
|||
for (i = 0; i < sector->numattached; i++)
|
||||
{
|
||||
sec = §ors[sector->attached[i]];
|
||||
for (n = sec->touching_thinglist; n; n = n->m_snext)
|
||||
for (n = sec->touching_thinglist; n; n = n->m_thinglist_next)
|
||||
n->visited = false;
|
||||
|
||||
sec->moved = true;
|
||||
|
@ -3377,7 +3407,7 @@ boolean P_CheckSector(sector_t *sector, boolean crunch)
|
|||
|
||||
do
|
||||
{
|
||||
for (n = sec->touching_thinglist; n; n = n->m_snext)
|
||||
for (n = sec->touching_thinglist; n; n = n->m_thinglist_next)
|
||||
if (!n->visited)
|
||||
{
|
||||
n->visited = true;
|
||||
|
@ -3398,12 +3428,12 @@ boolean P_CheckSector(sector_t *sector, boolean crunch)
|
|||
// Mark all things invalid
|
||||
sector->moved = true;
|
||||
|
||||
for (n = sector->touching_thinglist; n; n = n->m_snext)
|
||||
for (n = sector->touching_thinglist; n; n = n->m_thinglist_next)
|
||||
n->visited = false;
|
||||
|
||||
do
|
||||
{
|
||||
for (n = sector->touching_thinglist; n; n = n->m_snext) // go through list
|
||||
for (n = sector->touching_thinglist; n; n = n->m_thinglist_next) // go through list
|
||||
if (!n->visited) // unprocessed thing found
|
||||
{
|
||||
n->visited = true; // mark thing as processed
|
||||
|
@ -3427,7 +3457,7 @@ boolean P_CheckSector(sector_t *sector, boolean crunch)
|
|||
for (i = 0; i < sector->numattached; i++)
|
||||
{
|
||||
sec = §ors[sector->attached[i]];
|
||||
for (n = sec->touching_thinglist; n; n = n->m_snext)
|
||||
for (n = sec->touching_thinglist; n; n = n->m_thinglist_next)
|
||||
n->visited = false;
|
||||
|
||||
sec->moved = true;
|
||||
|
@ -3439,7 +3469,7 @@ boolean P_CheckSector(sector_t *sector, boolean crunch)
|
|||
|
||||
do
|
||||
{
|
||||
for (n = sec->touching_thinglist; n; n = n->m_snext)
|
||||
for (n = sec->touching_thinglist; n; n = n->m_thinglist_next)
|
||||
if (!n->visited)
|
||||
{
|
||||
n->visited = true;
|
||||
|
@ -3457,12 +3487,12 @@ boolean P_CheckSector(sector_t *sector, boolean crunch)
|
|||
// Mark all things invalid
|
||||
sector->moved = true;
|
||||
|
||||
for (n = sector->touching_thinglist; n; n = n->m_snext)
|
||||
for (n = sector->touching_thinglist; n; n = n->m_thinglist_next)
|
||||
n->visited = false;
|
||||
|
||||
do
|
||||
{
|
||||
for (n = sector->touching_thinglist; n; n = n->m_snext) // go through list
|
||||
for (n = sector->touching_thinglist; n; n = n->m_thinglist_next) // go through list
|
||||
if (!n->visited) // unprocessed thing found
|
||||
{
|
||||
n->visited = true; // mark thing as processed
|
||||
|
@ -3502,7 +3532,7 @@ static msecnode_t *P_GetSecnode(void)
|
|||
if (headsecnode)
|
||||
{
|
||||
node = headsecnode;
|
||||
headsecnode = headsecnode->m_snext;
|
||||
headsecnode = headsecnode->m_thinglist_next;
|
||||
}
|
||||
else
|
||||
node = Z_Calloc(sizeof (*node), PU_LEVEL, NULL);
|
||||
|
@ -3516,7 +3546,7 @@ static mprecipsecnode_t *P_GetPrecipSecnode(void)
|
|||
if (headprecipsecnode)
|
||||
{
|
||||
node = headprecipsecnode;
|
||||
headprecipsecnode = headprecipsecnode->m_snext;
|
||||
headprecipsecnode = headprecipsecnode->m_thinglist_next;
|
||||
}
|
||||
else
|
||||
node = Z_Calloc(sizeof (*node), PU_LEVEL, NULL);
|
||||
|
@ -3527,14 +3557,14 @@ static mprecipsecnode_t *P_GetPrecipSecnode(void)
|
|||
|
||||
static inline void P_PutSecnode(msecnode_t *node)
|
||||
{
|
||||
node->m_snext = headsecnode;
|
||||
node->m_thinglist_next = headsecnode;
|
||||
headsecnode = node;
|
||||
}
|
||||
|
||||
// Tails 08-25-2002
|
||||
static inline void P_PutPrecipSecnode(mprecipsecnode_t *node)
|
||||
{
|
||||
node->m_snext = headprecipsecnode;
|
||||
node->m_thinglist_next = headprecipsecnode;
|
||||
headprecipsecnode = node;
|
||||
}
|
||||
|
||||
|
@ -3555,7 +3585,7 @@ static msecnode_t *P_AddSecnode(sector_t *s, mobj_t *thing, msecnode_t *nextnode
|
|||
node->m_thing = thing; // Yes. Setting m_thing says 'keep it'.
|
||||
return nextnode;
|
||||
}
|
||||
node = node->m_tnext;
|
||||
node = node->m_sectorlist_next;
|
||||
}
|
||||
|
||||
// Couldn't find an existing node for this sector. Add one at the head
|
||||
|
@ -3568,17 +3598,17 @@ static msecnode_t *P_AddSecnode(sector_t *s, mobj_t *thing, msecnode_t *nextnode
|
|||
|
||||
node->m_sector = s; // sector
|
||||
node->m_thing = thing; // mobj
|
||||
node->m_tprev = NULL; // prev node on Thing thread
|
||||
node->m_tnext = nextnode; // next node on Thing thread
|
||||
node->m_sectorlist_prev = NULL; // prev node on Thing thread
|
||||
node->m_sectorlist_next = nextnode; // next node on Thing thread
|
||||
if (nextnode)
|
||||
nextnode->m_tprev = node; // set back link on Thing
|
||||
nextnode->m_sectorlist_prev = node; // set back link on Thing
|
||||
|
||||
// Add new node at head of sector thread starting at s->touching_thinglist
|
||||
|
||||
node->m_sprev = NULL; // prev node on sector thread
|
||||
node->m_snext = s->touching_thinglist; // next node on sector thread
|
||||
node->m_thinglist_prev = NULL; // prev node on sector thread
|
||||
node->m_thinglist_next = s->touching_thinglist; // next node on sector thread
|
||||
if (s->touching_thinglist)
|
||||
node->m_snext->m_sprev = node;
|
||||
node->m_thinglist_next->m_thinglist_prev = node;
|
||||
s->touching_thinglist = node;
|
||||
return node;
|
||||
}
|
||||
|
@ -3596,7 +3626,7 @@ static mprecipsecnode_t *P_AddPrecipSecnode(sector_t *s, precipmobj_t *thing, mp
|
|||
node->m_thing = thing; // Yes. Setting m_thing says 'keep it'.
|
||||
return nextnode;
|
||||
}
|
||||
node = node->m_tnext;
|
||||
node = node->m_sectorlist_next;
|
||||
}
|
||||
|
||||
// Couldn't find an existing node for this sector. Add one at the head
|
||||
|
@ -3609,17 +3639,17 @@ static mprecipsecnode_t *P_AddPrecipSecnode(sector_t *s, precipmobj_t *thing, mp
|
|||
|
||||
node->m_sector = s; // sector
|
||||
node->m_thing = thing; // mobj
|
||||
node->m_tprev = NULL; // prev node on Thing thread
|
||||
node->m_tnext = nextnode; // next node on Thing thread
|
||||
node->m_sectorlist_prev = NULL; // prev node on Thing thread
|
||||
node->m_sectorlist_next = nextnode; // next node on Thing thread
|
||||
if (nextnode)
|
||||
nextnode->m_tprev = node; // set back link on Thing
|
||||
nextnode->m_sectorlist_prev = node; // set back link on Thing
|
||||
|
||||
// Add new node at head of sector thread starting at s->touching_thinglist
|
||||
|
||||
node->m_sprev = NULL; // prev node on sector thread
|
||||
node->m_snext = s->touching_preciplist; // next node on sector thread
|
||||
node->m_thinglist_prev = NULL; // prev node on sector thread
|
||||
node->m_thinglist_next = s->touching_preciplist; // next node on sector thread
|
||||
if (s->touching_preciplist)
|
||||
node->m_snext->m_sprev = node;
|
||||
node->m_thinglist_next->m_thinglist_prev = node;
|
||||
s->touching_preciplist = node;
|
||||
return node;
|
||||
}
|
||||
|
@ -3641,24 +3671,24 @@ static msecnode_t *P_DelSecnode(msecnode_t *node)
|
|||
// Unlink from the Thing thread. The Thing thread begins at
|
||||
// sector_list and not from mobj_t->touching_sectorlist.
|
||||
|
||||
tp = node->m_tprev;
|
||||
tn = node->m_tnext;
|
||||
tp = node->m_sectorlist_prev;
|
||||
tn = node->m_sectorlist_next;
|
||||
if (tp)
|
||||
tp->m_tnext = tn;
|
||||
tp->m_sectorlist_next = tn;
|
||||
if (tn)
|
||||
tn->m_tprev = tp;
|
||||
tn->m_sectorlist_prev = tp;
|
||||
|
||||
// Unlink from the sector thread. This thread begins at
|
||||
// sector_t->touching_thinglist.
|
||||
|
||||
sp = node->m_sprev;
|
||||
sn = node->m_snext;
|
||||
sp = node->m_thinglist_prev;
|
||||
sn = node->m_thinglist_next;
|
||||
if (sp)
|
||||
sp->m_snext = sn;
|
||||
sp->m_thinglist_next = sn;
|
||||
else
|
||||
node->m_sector->touching_thinglist = sn;
|
||||
if (sn)
|
||||
sn->m_sprev = sp;
|
||||
sn->m_thinglist_prev = sp;
|
||||
|
||||
// Return this node to the freelist
|
||||
|
||||
|
@ -3680,24 +3710,24 @@ static mprecipsecnode_t *P_DelPrecipSecnode(mprecipsecnode_t *node)
|
|||
// Unlink from the Thing thread. The Thing thread begins at
|
||||
// sector_list and not from mobj_t->touching_sectorlist.
|
||||
|
||||
tp = node->m_tprev;
|
||||
tn = node->m_tnext;
|
||||
tp = node->m_sectorlist_prev;
|
||||
tn = node->m_sectorlist_next;
|
||||
if (tp)
|
||||
tp->m_tnext = tn;
|
||||
tp->m_sectorlist_next = tn;
|
||||
if (tn)
|
||||
tn->m_tprev = tp;
|
||||
tn->m_sectorlist_prev = tp;
|
||||
|
||||
// Unlink from the sector thread. This thread begins at
|
||||
// sector_t->touching_thinglist.
|
||||
|
||||
sp = node->m_sprev;
|
||||
sn = node->m_snext;
|
||||
sp = node->m_thinglist_prev;
|
||||
sn = node->m_thinglist_next;
|
||||
if (sp)
|
||||
sp->m_snext = sn;
|
||||
sp->m_thinglist_next = sn;
|
||||
else
|
||||
node->m_sector->touching_preciplist = sn;
|
||||
if (sn)
|
||||
sn->m_sprev = sp;
|
||||
sn->m_thinglist_prev = sp;
|
||||
|
||||
// Return this node to the freelist
|
||||
|
||||
|
@ -3812,7 +3842,7 @@ void P_CreateSecNodeList(mobj_t *thing, fixed_t x, fixed_t y)
|
|||
while (node)
|
||||
{
|
||||
node->m_thing = NULL;
|
||||
node = node->m_tnext;
|
||||
node = node->m_sectorlist_next;
|
||||
}
|
||||
|
||||
P_SetTarget(&tmthing, thing);
|
||||
|
@ -3850,11 +3880,11 @@ void P_CreateSecNodeList(mobj_t *thing, fixed_t x, fixed_t y)
|
|||
if (!node->m_thing)
|
||||
{
|
||||
if (node == sector_list)
|
||||
sector_list = node->m_tnext;
|
||||
sector_list = node->m_sectorlist_next;
|
||||
node = P_DelSecnode(node);
|
||||
}
|
||||
else
|
||||
node = node->m_tnext;
|
||||
node = node->m_sectorlist_next;
|
||||
}
|
||||
|
||||
/* cph -
|
||||
|
@ -3895,7 +3925,7 @@ void P_CreatePrecipSecNodeList(precipmobj_t *thing,fixed_t x,fixed_t y)
|
|||
while (node)
|
||||
{
|
||||
node->m_thing = NULL;
|
||||
node = node->m_tnext;
|
||||
node = node->m_sectorlist_next;
|
||||
}
|
||||
|
||||
tmprecipthing = thing;
|
||||
|
@ -3929,11 +3959,11 @@ void P_CreatePrecipSecNodeList(precipmobj_t *thing,fixed_t x,fixed_t y)
|
|||
if (!node->m_thing)
|
||||
{
|
||||
if (node == precipsector_list)
|
||||
precipsector_list = node->m_tnext;
|
||||
precipsector_list = node->m_sectorlist_next;
|
||||
node = P_DelPrecipSecnode(node);
|
||||
}
|
||||
else
|
||||
node = node->m_tnext;
|
||||
node = node->m_sectorlist_next;
|
||||
}
|
||||
|
||||
/* cph -
|
||||
|
|
115
src/p_maputl.c
115
src/p_maputl.c
|
@ -489,7 +489,7 @@ void P_CameraLineOpening(line_t *linedef)
|
|||
}
|
||||
}
|
||||
|
||||
void P_LineOpening(line_t *linedef)
|
||||
void P_LineOpening(line_t *linedef, mobj_t *mobj)
|
||||
{
|
||||
sector_t *front, *back;
|
||||
|
||||
|
@ -520,8 +520,8 @@ void P_LineOpening(line_t *linedef)
|
|||
{ // Set open and high/low values here
|
||||
fixed_t frontheight, backheight;
|
||||
|
||||
frontheight = P_GetCeilingZ(tmthing, front, tmx, tmy, linedef);
|
||||
backheight = P_GetCeilingZ(tmthing, back, tmx, tmy, linedef);
|
||||
frontheight = P_GetCeilingZ(mobj, front, tmx, tmy, linedef);
|
||||
backheight = P_GetCeilingZ(mobj, back, tmx, tmy, linedef);
|
||||
|
||||
if (frontheight < backheight)
|
||||
{
|
||||
|
@ -540,8 +540,8 @@ void P_LineOpening(line_t *linedef)
|
|||
#endif
|
||||
}
|
||||
|
||||
frontheight = P_GetFloorZ(tmthing, front, tmx, tmy, linedef);
|
||||
backheight = P_GetFloorZ(tmthing, back, tmx, tmy, linedef);
|
||||
frontheight = P_GetFloorZ(mobj, front, tmx, tmy, linedef);
|
||||
backheight = P_GetFloorZ(mobj, back, tmx, tmy, linedef);
|
||||
|
||||
if (frontheight > backheight)
|
||||
{
|
||||
|
@ -561,52 +561,65 @@ void P_LineOpening(line_t *linedef)
|
|||
}
|
||||
}
|
||||
|
||||
if (tmthing)
|
||||
if (mobj)
|
||||
{
|
||||
fixed_t thingtop = tmthing->z + tmthing->height;
|
||||
fixed_t thingtop = mobj->z + mobj->height;
|
||||
|
||||
// Check for collision with front side's midtexture if Effect 4 is set
|
||||
if (linedef->flags & ML_EFFECT4) {
|
||||
if (linedef->flags & ML_EFFECT4
|
||||
&& !linedef->polyobj // don't do anything for polyobjects! ...for now
|
||||
) {
|
||||
side_t *side = &sides[linedef->sidenum[0]];
|
||||
fixed_t textop, texbottom, texheight;
|
||||
fixed_t texmid, delta1, delta2;
|
||||
INT32 texnum = R_GetTextureNum(side->midtexture); // make sure the texture is actually valid
|
||||
|
||||
// Get the midtexture's height
|
||||
texheight = textures[texturetranslation[side->midtexture]]->height << FRACBITS;
|
||||
if (texnum) {
|
||||
// Get the midtexture's height
|
||||
texheight = textures[texnum]->height << FRACBITS;
|
||||
|
||||
// Set texbottom and textop to the Z coordinates of the texture's boundaries
|
||||
#ifdef POLYOBJECTS
|
||||
if (linedef->polyobj && (linedef->polyobj->flags & POF_TESTHEIGHT)) {
|
||||
if (linedef->flags & ML_DONTPEGBOTTOM) {
|
||||
texbottom = back->floorheight + side->rowoffset;
|
||||
textop = texbottom + texheight*(side->repeatcnt+1);
|
||||
} else {
|
||||
textop = back->ceilingheight - side->rowoffset;
|
||||
texbottom = textop - texheight*(side->repeatcnt+1);
|
||||
}
|
||||
} else
|
||||
// Set texbottom and textop to the Z coordinates of the texture's boundaries
|
||||
#if 0 // #ifdef POLYOBJECTS
|
||||
// don't remove this code unless solid midtextures
|
||||
// on non-solid polyobjects should NEVER happen in the future
|
||||
if (linedef->polyobj && (linedef->polyobj->flags & POF_TESTHEIGHT)) {
|
||||
if (linedef->flags & ML_EFFECT5 && !side->repeatcnt) { // "infinite" repeat
|
||||
texbottom = back->floorheight + side->rowoffset;
|
||||
textop = back->ceilingheight + side->rowoffset;
|
||||
} else if (!!(linedef->flags & ML_DONTPEGBOTTOM) ^ !!(linedef->flags & ML_EFFECT3)) {
|
||||
texbottom = back->floorheight + side->rowoffset;
|
||||
textop = texbottom + texheight*(side->repeatcnt+1);
|
||||
} else {
|
||||
textop = back->ceilingheight + side->rowoffset;
|
||||
texbottom = textop - texheight*(side->repeatcnt+1);
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
if (linedef->flags & ML_DONTPEGBOTTOM) {
|
||||
texbottom = openbottom + side->rowoffset;
|
||||
textop = texbottom + texheight*(side->repeatcnt+1);
|
||||
} else {
|
||||
textop = opentop - side->rowoffset;
|
||||
texbottom = textop - texheight*(side->repeatcnt+1);
|
||||
{
|
||||
if (linedef->flags & ML_EFFECT5 && !side->repeatcnt) { // "infinite" repeat
|
||||
texbottom = openbottom + side->rowoffset;
|
||||
textop = opentop + side->rowoffset;
|
||||
} else if (!!(linedef->flags & ML_DONTPEGBOTTOM) ^ !!(linedef->flags & ML_EFFECT3)) {
|
||||
texbottom = openbottom + side->rowoffset;
|
||||
textop = texbottom + texheight*(side->repeatcnt+1);
|
||||
} else {
|
||||
textop = opentop + side->rowoffset;
|
||||
texbottom = textop - texheight*(side->repeatcnt+1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
texmid = texbottom+(textop-texbottom)/2;
|
||||
texmid = texbottom+(textop-texbottom)/2;
|
||||
|
||||
delta1 = abs(tmthing->z - texmid);
|
||||
delta2 = abs(thingtop - texmid);
|
||||
delta1 = abs(mobj->z - texmid);
|
||||
delta2 = abs(thingtop - texmid);
|
||||
|
||||
if (delta1 > delta2) { // Below
|
||||
if (opentop > texbottom)
|
||||
opentop = texbottom;
|
||||
} else { // Above
|
||||
if (openbottom < textop)
|
||||
openbottom = textop;
|
||||
if (delta1 > delta2) { // Below
|
||||
if (opentop > texbottom)
|
||||
opentop = texbottom;
|
||||
} else { // Above
|
||||
if (openbottom < textop)
|
||||
openbottom = textop;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -636,16 +649,16 @@ void P_LineOpening(line_t *linedef)
|
|||
if (!(rover->flags & FF_EXISTS))
|
||||
continue;
|
||||
|
||||
if (tmthing->player && (P_CheckSolidLava(tmthing, rover) || P_CanRunOnWater(tmthing->player, rover)))
|
||||
if (mobj->player && (P_CheckSolidLava(mobj, rover) || P_CanRunOnWater(mobj->player, rover)))
|
||||
;
|
||||
else if (!((rover->flags & FF_BLOCKPLAYER && tmthing->player)
|
||||
|| (rover->flags & FF_BLOCKOTHERS && !tmthing->player)))
|
||||
else if (!((rover->flags & FF_BLOCKPLAYER && mobj->player)
|
||||
|| (rover->flags & FF_BLOCKOTHERS && !mobj->player)))
|
||||
continue;
|
||||
|
||||
topheight = P_GetFOFTopZ(tmthing, front, rover, tmx, tmy, linedef);
|
||||
bottomheight = P_GetFOFBottomZ(tmthing, front, rover, tmx, tmy, linedef);
|
||||
topheight = P_GetFOFTopZ(mobj, front, rover, tmx, tmy, linedef);
|
||||
bottomheight = P_GetFOFBottomZ(mobj, front, rover, tmx, tmy, linedef);
|
||||
|
||||
delta1 = abs(tmthing->z - (bottomheight + ((topheight - bottomheight)/2)));
|
||||
delta1 = abs(mobj->z - (bottomheight + ((topheight - bottomheight)/2)));
|
||||
delta2 = abs(thingtop - (bottomheight + ((topheight - bottomheight)/2)));
|
||||
|
||||
if (delta1 >= delta2 && !(rover->flags & FF_PLATFORM)) // thing is below FOF
|
||||
|
@ -680,16 +693,16 @@ void P_LineOpening(line_t *linedef)
|
|||
if (!(rover->flags & FF_EXISTS))
|
||||
continue;
|
||||
|
||||
if (tmthing->player && (P_CheckSolidLava(tmthing, rover) || P_CanRunOnWater(tmthing->player, rover)))
|
||||
if (mobj->player && (P_CheckSolidLava(mobj, rover) || P_CanRunOnWater(mobj->player, rover)))
|
||||
;
|
||||
else if (!((rover->flags & FF_BLOCKPLAYER && tmthing->player)
|
||||
|| (rover->flags & FF_BLOCKOTHERS && !tmthing->player)))
|
||||
else if (!((rover->flags & FF_BLOCKPLAYER && mobj->player)
|
||||
|| (rover->flags & FF_BLOCKOTHERS && !mobj->player)))
|
||||
continue;
|
||||
|
||||
topheight = P_GetFOFTopZ(tmthing, back, rover, tmx, tmy, linedef);
|
||||
bottomheight = P_GetFOFBottomZ(tmthing, back, rover, tmx, tmy, linedef);
|
||||
topheight = P_GetFOFTopZ(mobj, back, rover, tmx, tmy, linedef);
|
||||
bottomheight = P_GetFOFBottomZ(mobj, back, rover, tmx, tmy, linedef);
|
||||
|
||||
delta1 = abs(tmthing->z - (bottomheight + ((topheight - bottomheight)/2)));
|
||||
delta1 = abs(mobj->z - (bottomheight + ((topheight - bottomheight)/2)));
|
||||
delta2 = abs(thingtop - (bottomheight + ((topheight - bottomheight)/2)));
|
||||
|
||||
if (delta1 >= delta2 && !(rover->flags & FF_PLATFORM)) // thing is below FOF
|
||||
|
@ -723,7 +736,7 @@ void P_LineOpening(line_t *linedef)
|
|||
{
|
||||
const sector_t *polysec = linedef->backsector;
|
||||
|
||||
delta1 = abs(tmthing->z - (polysec->floorheight + ((polysec->ceilingheight - polysec->floorheight)/2)));
|
||||
delta1 = abs(mobj->z - (polysec->floorheight + ((polysec->ceilingheight - polysec->floorheight)/2)));
|
||||
delta2 = abs(thingtop - (polysec->floorheight + ((polysec->ceilingheight - polysec->floorheight)/2)));
|
||||
if (polysec->floorheight < lowestceiling && delta1 >= delta2) {
|
||||
lowestceiling = polysec->floorheight;
|
||||
|
|
|
@ -59,7 +59,7 @@ extern fixed_t opentop, openbottom, openrange, lowfloor, highceiling;
|
|||
extern pslope_t *opentopslope, *openbottomslope;
|
||||
#endif
|
||||
|
||||
void P_LineOpening(line_t *plinedef);
|
||||
void P_LineOpening(line_t *plinedef, mobj_t *mobj);
|
||||
|
||||
boolean P_BlockLinesIterator(INT32 x, INT32 y, boolean(*func)(line_t *));
|
||||
boolean P_BlockThingsIterator(INT32 x, INT32 y, boolean(*func)(mobj_t *));
|
||||
|
|
218
src/p_mobj.c
218
src/p_mobj.c
|
@ -1252,13 +1252,12 @@ static void P_PlayerFlip(mobj_t *mo)
|
|||
}
|
||||
|
||||
//
|
||||
// P_CheckGravity
|
||||
// P_GetMobjGravity
|
||||
//
|
||||
// Checks the current gravity state
|
||||
// of the object. If affect is true,
|
||||
// a gravity force will be applied.
|
||||
// Returns the current gravity
|
||||
// value of the object.
|
||||
//
|
||||
void P_CheckGravity(mobj_t *mo, boolean affect)
|
||||
fixed_t P_GetMobjGravity(mobj_t *mo)
|
||||
{
|
||||
fixed_t gravityadd = 0;
|
||||
boolean no3dfloorgrav = true; // Custom gravity
|
||||
|
@ -1279,25 +1278,23 @@ void P_CheckGravity(mobj_t *mo, boolean affect)
|
|||
|
||||
for (rover = mo->subsector->sector->ffloors; rover; rover = rover->next)
|
||||
{
|
||||
if (!(rover->flags & FF_EXISTS))
|
||||
if (!(rover->flags & FF_EXISTS) || !P_InsideANonSolidFFloor(mo, rover)) // P_InsideANonSolidFFloor checks for FF_EXISTS itself, but let's not always call this function
|
||||
continue;
|
||||
|
||||
if (P_InsideANonSolidFFloor(mo, rover))
|
||||
{
|
||||
if ((rover->flags & (FF_SWIMMABLE|FF_GOOWATER)) == (FF_SWIMMABLE|FF_GOOWATER))
|
||||
goopgravity = true;
|
||||
if (rover->master->frontsector->gravity)
|
||||
{
|
||||
gravityadd = -FixedMul(gravity,
|
||||
(FixedDiv(*rover->master->frontsector->gravity>>FRACBITS, 1000)));
|
||||
if ((rover->flags & (FF_SWIMMABLE|FF_GOOWATER)) == (FF_SWIMMABLE|FF_GOOWATER))
|
||||
goopgravity = true;
|
||||
|
||||
if (rover->master->frontsector->verticalflip && gravityadd > 0)
|
||||
mo->eflags |= MFE_VERTICALFLIP;
|
||||
if (!(rover->master->frontsector->gravity))
|
||||
continue;
|
||||
|
||||
no3dfloorgrav = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
gravityadd = -FixedMul(gravity,
|
||||
(FixedDiv(*rover->master->frontsector->gravity>>FRACBITS, 1000)));
|
||||
|
||||
if (rover->master->frontsector->verticalflip && gravityadd > 0)
|
||||
mo->eflags |= MFE_VERTICALFLIP;
|
||||
|
||||
no3dfloorgrav = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1317,33 +1314,22 @@ void P_CheckGravity(mobj_t *mo, boolean affect)
|
|||
if (mo->eflags & MFE_UNDERWATER && !goopgravity)
|
||||
gravityadd = gravityadd/3;
|
||||
|
||||
if (!mo->momz) // mobj at stop, no floor, so feel the push of gravity!
|
||||
gravityadd <<= 1;
|
||||
|
||||
if (mo->player)
|
||||
{
|
||||
if (mo->player->charability == CA_FLY && (mo->player->powers[pw_tailsfly]
|
||||
|| (mo->state >= &states[S_PLAY_SPC1] && mo->state <= &states[S_PLAY_SPC4])))
|
||||
gravityadd = gravityadd/3; // less gravity while flying
|
||||
if (mo->player->pflags & PF_GLIDING)
|
||||
gravityadd = gravityadd/3; // less gravity while gliding
|
||||
if (mo->player->climbing)
|
||||
gravityadd = 0;
|
||||
if (mo->player->pflags & PF_NIGHTSMODE)
|
||||
if ((mo->player->pflags & PF_GLIDING)
|
||||
|| (mo->player->charability == CA_FLY && (mo->player->powers[pw_tailsfly]
|
||||
|| (mo->state >= &states[S_PLAY_SPC1] && mo->state <= &states[S_PLAY_SPC4]))))
|
||||
gravityadd = gravityadd/3; // less gravity while flying/gliding
|
||||
if (mo->player->climbing || (mo->player->pflags & PF_NIGHTSMODE))
|
||||
gravityadd = 0;
|
||||
|
||||
if (!(mo->flags2 & MF2_OBJECTFLIP) != !(mo->player->powers[pw_gravityboots])) // negated to turn numeric into bool - would be double negated, but not needed if both would be
|
||||
{
|
||||
UINT8 bits = 0;
|
||||
if (mo->flags2 & MF2_OBJECTFLIP)
|
||||
bits ^= 1;
|
||||
if (mo->player->powers[pw_gravityboots])
|
||||
bits ^= 1;
|
||||
if (bits & 1)
|
||||
{
|
||||
gravityadd = -gravityadd;
|
||||
mo->eflags ^= MFE_VERTICALFLIP;
|
||||
}
|
||||
gravityadd = -gravityadd;
|
||||
mo->eflags ^= MFE_VERTICALFLIP;
|
||||
}
|
||||
if (wasflip == !(mo->eflags & MFE_VERTICALFLIP)) // note!! == ! is not equivalent to != here - turns numeric into bool this way
|
||||
P_PlayerFlip(mo);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1351,10 +1337,10 @@ void P_CheckGravity(mobj_t *mo, boolean affect)
|
|||
if (mo->flags2 & MF2_OBJECTFLIP)
|
||||
{
|
||||
mo->eflags |= MFE_VERTICALFLIP;
|
||||
if (gravityadd < 0) // Don't sink, only rise up
|
||||
gravityadd *= -1;
|
||||
if (mo->z + mo->height >= mo->ceilingz)
|
||||
gravityadd = 0;
|
||||
else if (gravityadd < 0) // Don't sink, only rise up
|
||||
gravityadd *= -1;
|
||||
}
|
||||
else //Otherwise, sort through the other exceptions.
|
||||
{
|
||||
|
@ -1400,11 +1386,27 @@ void P_CheckGravity(mobj_t *mo, boolean affect)
|
|||
if (goopgravity)
|
||||
gravityadd = -gravityadd/5;
|
||||
|
||||
if (affect)
|
||||
mo->momz += FixedMul(gravityadd, mo->scale);
|
||||
gravityadd = FixedMul(gravityadd, mo->scale);
|
||||
|
||||
if (mo->player && !!(mo->eflags & MFE_VERTICALFLIP) != wasflip)
|
||||
P_PlayerFlip(mo);
|
||||
return gravityadd;
|
||||
}
|
||||
|
||||
//
|
||||
// P_CheckGravity
|
||||
//
|
||||
// Checks the current gravity state
|
||||
// of the object. If affect is true,
|
||||
// a gravity force will be applied.
|
||||
//
|
||||
void P_CheckGravity(mobj_t *mo, boolean affect)
|
||||
{
|
||||
fixed_t gravityadd = P_GetMobjGravity(mo);
|
||||
|
||||
if (!mo->momz) // mobj at stop, no floor, so feel the push of gravity!
|
||||
gravityadd <<= 1;
|
||||
|
||||
if (affect)
|
||||
mo->momz += gravityadd;
|
||||
|
||||
if (mo->type == MT_SKIM && mo->z + mo->momz <= mo->watertop && mo->z >= mo->watertop)
|
||||
{
|
||||
|
@ -1480,7 +1482,7 @@ static void P_XYFriction(mobj_t *mo, fixed_t oldx, fixed_t oldy)
|
|||
&& abs(player->rmomy) < FixedMul(STOPSPEED, mo->scale)
|
||||
&& (!(player->cmd.forwardmove && !(twodlevel || mo->flags2 & MF2_TWOD)) && !player->cmd.sidemove && !(player->pflags & PF_SPINNING))
|
||||
#ifdef ESLOPE
|
||||
&& !(player->mo->standingslope && abs(player->mo->standingslope->zdelta) >= FRACUNIT/2)
|
||||
&& !(player->mo->standingslope && (!(player->mo->standingslope->flags & SL_NOPHYSICS)) && (abs(player->mo->standingslope->zdelta) >= FRACUNIT/2))
|
||||
#endif
|
||||
)
|
||||
{
|
||||
|
@ -1530,7 +1532,7 @@ static void P_PushableCheckBustables(mobj_t *mo)
|
|||
mo->y += mo->momy;
|
||||
P_SetThingPosition(mo);
|
||||
|
||||
for (node = mo->touching_sectorlist; node; node = node->m_snext)
|
||||
for (node = mo->touching_sectorlist; node; node = node->m_sectorlist_next)
|
||||
{
|
||||
if (!node->m_sector)
|
||||
break;
|
||||
|
@ -1538,6 +1540,7 @@ static void P_PushableCheckBustables(mobj_t *mo)
|
|||
if (node->m_sector->ffloors)
|
||||
{
|
||||
ffloor_t *rover;
|
||||
fixed_t topheight, bottomheight;
|
||||
|
||||
for (rover = node->m_sector->ffloors; rover; rover = rover->next)
|
||||
{
|
||||
|
@ -1550,37 +1553,39 @@ static void P_PushableCheckBustables(mobj_t *mo)
|
|||
|
||||
if (!rover->master->frontsector->crumblestate)
|
||||
{
|
||||
topheight = P_GetFOFTopZ(mo, node->m_sector, rover, mo->x, mo->y, NULL);
|
||||
bottomheight = P_GetFOFBottomZ(mo, node->m_sector, rover, mo->x, mo->y, NULL);
|
||||
// Height checks
|
||||
if (rover->flags & FF_SHATTERBOTTOM)
|
||||
{
|
||||
if (mo->z+mo->momz + mo->height < *rover->bottomheight)
|
||||
if (mo->z+mo->momz + mo->height < bottomheight)
|
||||
continue;
|
||||
|
||||
if (mo->z+mo->height > *rover->bottomheight)
|
||||
if (mo->z+mo->height > bottomheight)
|
||||
continue;
|
||||
}
|
||||
else if (rover->flags & FF_SPINBUST)
|
||||
{
|
||||
if (mo->z+mo->momz > *rover->topheight)
|
||||
if (mo->z+mo->momz > topheight)
|
||||
continue;
|
||||
|
||||
if (mo->z+mo->height < *rover->bottomheight)
|
||||
if (mo->z+mo->height < bottomheight)
|
||||
continue;
|
||||
}
|
||||
else if (rover->flags & FF_SHATTER)
|
||||
{
|
||||
if (mo->z+mo->momz > *rover->topheight)
|
||||
if (mo->z+mo->momz > topheight)
|
||||
continue;
|
||||
|
||||
if (mo->z+mo->momz + mo->height < *rover->bottomheight)
|
||||
if (mo->z+mo->momz + mo->height < bottomheight)
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (mo->z >= *rover->topheight)
|
||||
if (mo->z >= topheight)
|
||||
continue;
|
||||
|
||||
if (mo->z+mo->height < *rover->bottomheight)
|
||||
if (mo->z+mo->height < bottomheight)
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -1635,8 +1640,6 @@ void P_XYMovement(mobj_t *mo)
|
|||
I_Assert(mo != NULL);
|
||||
I_Assert(!P_MobjWasRemoved(mo));
|
||||
|
||||
moved = true;
|
||||
|
||||
// if it's stopped
|
||||
if (!mo->momx && !mo->momy)
|
||||
{
|
||||
|
@ -1693,9 +1696,9 @@ void P_XYMovement(mobj_t *mo)
|
|||
if (!P_TryMove(mo, mo->x + xmove, mo->y + ymove, true) && !(mo->eflags & MFE_SPRUNG))
|
||||
{
|
||||
// blocked move
|
||||
moved = false;
|
||||
|
||||
if (player) {
|
||||
moved = false;
|
||||
if (player->bot)
|
||||
B_MoveBlocked(player);
|
||||
}
|
||||
|
@ -1800,7 +1803,7 @@ void P_XYMovement(mobj_t *mo)
|
|||
else
|
||||
mo->momx = mo->momy = 0;
|
||||
}
|
||||
else if (player)
|
||||
else
|
||||
moved = true;
|
||||
|
||||
if (P_MobjWasRemoved(mo)) // MF_SPECIAL touched a player! O_o;;
|
||||
|
@ -2013,12 +2016,14 @@ static void P_AdjustMobjFloorZ_FFloors(mobj_t *mo, sector_t *sector, UINT8 motyp
|
|||
delta1 = mo->z - (bottomheight + ((topheight - bottomheight)/2));
|
||||
delta2 = thingtop - (bottomheight + ((topheight - bottomheight)/2));
|
||||
if (topheight > mo->floorz && abs(delta1) < abs(delta2)
|
||||
&& !(rover->flags & FF_REVERSEPLATFORM))
|
||||
&& !(rover->flags & FF_REVERSEPLATFORM)
|
||||
&& ((P_MobjFlip(mo)*mo->momz >= 0) || (!(rover->flags & FF_PLATFORM)))) // In reverse gravity, only clip for FOFs that are intangible from their bottom (the "top" you're falling through) if you're coming from above ("below" in your frame of reference)
|
||||
{
|
||||
mo->floorz = topheight;
|
||||
}
|
||||
if (bottomheight < mo->ceilingz && abs(delta1) >= abs(delta2)
|
||||
&& !(rover->flags & FF_PLATFORM))
|
||||
&& !(rover->flags & FF_PLATFORM)
|
||||
&& ((P_MobjFlip(mo)*mo->momz >= 0) || (!(rover->flags & FF_REVERSEPLATFORM)))) // In normal gravity, only clip for FOFs that are intangible from the top if you're coming from below
|
||||
{
|
||||
mo->ceilingz = bottomheight;
|
||||
}
|
||||
|
@ -2152,16 +2157,6 @@ static boolean P_ZMovement(mobj_t *mo)
|
|||
I_Assert(mo != NULL);
|
||||
I_Assert(!P_MobjWasRemoved(mo));
|
||||
|
||||
#ifdef ESLOPE
|
||||
if (mo->standingslope)
|
||||
{
|
||||
if (mo->flags & MF_NOCLIPHEIGHT)
|
||||
mo->standingslope = NULL;
|
||||
else if (!P_IsObjectOnGround(mo))
|
||||
P_SlopeLaunch(mo);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Intercept the stupid 'fall through 3dfloors' bug
|
||||
if (mo->subsector->sector->ffloors)
|
||||
P_AdjustMobjFloorZ_FFloors(mo, mo->subsector->sector, 0);
|
||||
|
@ -2176,6 +2171,16 @@ static boolean P_ZMovement(mobj_t *mo)
|
|||
}
|
||||
mo->z += mo->momz;
|
||||
|
||||
#ifdef ESLOPE
|
||||
if (mo->standingslope)
|
||||
{
|
||||
if (mo->flags & MF_NOCLIPHEIGHT)
|
||||
mo->standingslope = NULL;
|
||||
else if (!P_IsObjectOnGround(mo))
|
||||
P_SlopeLaunch(mo);
|
||||
}
|
||||
#endif
|
||||
|
||||
switch (mo->type)
|
||||
{
|
||||
case MT_THROWNBOUNCE:
|
||||
|
@ -2245,6 +2250,7 @@ static boolean P_ZMovement(mobj_t *mo)
|
|||
case MT_BLUETEAMRING:
|
||||
case MT_FLINGRING:
|
||||
case MT_FLINGCOIN:
|
||||
case MT_FLINGEMERALD:
|
||||
// Remove flinged stuff from death pits.
|
||||
if (P_CheckDeathPitCollide(mo))
|
||||
{
|
||||
|
@ -2276,7 +2282,6 @@ static boolean P_ZMovement(mobj_t *mo)
|
|||
if (!(mo->momx || mo->momy || mo->momz))
|
||||
return true;
|
||||
break;
|
||||
case MT_FLINGEMERALD:
|
||||
case MT_NIGHTSWING:
|
||||
if (!(mo->momx || mo->momy || mo->momz))
|
||||
return true;
|
||||
|
@ -2358,14 +2363,17 @@ static boolean P_ZMovement(mobj_t *mo)
|
|||
mo->z = mo->floorz;
|
||||
|
||||
#ifdef ESLOPE
|
||||
P_CheckPosition(mo, mo->x, mo->y); // Sets mo->standingslope correctly
|
||||
if ((mo->eflags & MFE_VERTICALFLIP) ? tmceilingslope : tmfloorslope) {
|
||||
mo->standingslope = (mo->eflags & MFE_VERTICALFLIP) ? tmceilingslope : tmfloorslope;
|
||||
if (!(mo->flags & MF_MISSILE) && mo->standingslope) // You're still on the ground; why are we here?
|
||||
{
|
||||
mo->momz = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Reverse quantizing might could use its own function later
|
||||
mo->standingslope->zangle = ANGLE_MAX-mo->standingslope->zangle;
|
||||
P_QuantizeMomentumToSlope(&mom, mo->standingslope);
|
||||
mo->standingslope->zangle = ANGLE_MAX-mo->standingslope->zangle;
|
||||
P_CheckPosition(mo, mo->x, mo->y); // Sets mo->standingslope correctly
|
||||
if (((mo->eflags & MFE_VERTICALFLIP) ? tmceilingslope : tmfloorslope) && (mo->type != MT_STEAM))
|
||||
{
|
||||
mo->standingslope = (mo->eflags & MFE_VERTICALFLIP) ? tmceilingslope : tmfloorslope;
|
||||
P_ReverseQuantizeMomentumToSlope(&mom, mo->standingslope);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -2518,7 +2526,7 @@ static boolean P_ZMovement(mobj_t *mo)
|
|||
mom.z = tmfloorthing->momz;
|
||||
|
||||
#ifdef ESLOPE
|
||||
if (mo->standingslope) {
|
||||
if (mo->standingslope) { // MT_STEAM will never have a standingslope, see above.
|
||||
P_QuantizeMomentumToSlope(&mom, mo->standingslope);
|
||||
}
|
||||
#endif
|
||||
|
@ -2703,7 +2711,7 @@ static void P_PlayerZMovement(mobj_t *mo)
|
|||
msecnode_t *node;
|
||||
boolean stopmovecut = false;
|
||||
|
||||
for (node = mo->touching_sectorlist; node; node = node->m_snext)
|
||||
for (node = mo->touching_sectorlist; node; node = node->m_sectorlist_next)
|
||||
{
|
||||
sector_t *sec = node->m_sector;
|
||||
subsector_t *newsubsec;
|
||||
|
@ -2880,7 +2888,7 @@ nightsdone:
|
|||
if (CheckForMarioBlocks && !(netgame && mo->player->spectator)) // Only let the player punch
|
||||
{
|
||||
// Search the touching sectors, from side-to-side...
|
||||
for (node = mo->touching_sectorlist; node; node = node->m_snext)
|
||||
for (node = mo->touching_sectorlist; node; node = node->m_sectorlist_next)
|
||||
{
|
||||
ffloor_t *rover;
|
||||
if (!node->m_sector->ffloors)
|
||||
|
@ -3648,7 +3656,7 @@ static void P_PlayerMobjThinker(mobj_t *mobj)
|
|||
if (!(netgame && mobj->player->spectator))
|
||||
{
|
||||
// Crumbling platforms
|
||||
for (node = mobj->touching_sectorlist; node; node = node->m_snext)
|
||||
for (node = mobj->touching_sectorlist; node; node = node->m_sectorlist_next)
|
||||
{
|
||||
fixed_t topheight, bottomheight;
|
||||
ffloor_t *rover;
|
||||
|
@ -3673,7 +3681,7 @@ static void P_PlayerMobjThinker(mobj_t *mobj)
|
|||
{
|
||||
boolean thereiswater = false;
|
||||
|
||||
for (node = mobj->touching_sectorlist; node; node = node->m_snext)
|
||||
for (node = mobj->touching_sectorlist; node; node = node->m_sectorlist_next)
|
||||
{
|
||||
if (node->m_sector->ffloors)
|
||||
{
|
||||
|
@ -3694,7 +3702,7 @@ static void P_PlayerMobjThinker(mobj_t *mobj)
|
|||
}
|
||||
if (thereiswater)
|
||||
{
|
||||
for (node = mobj->touching_sectorlist; node; node = node->m_snext)
|
||||
for (node = mobj->touching_sectorlist; node; node = node->m_sectorlist_next)
|
||||
{
|
||||
if (node->m_sector->ffloors)
|
||||
{
|
||||
|
@ -3807,7 +3815,7 @@ void P_RecalcPrecipInSector(sector_t *sector)
|
|||
|
||||
sector->moved = true; // Recalc lighting and things too, maybe
|
||||
|
||||
for (psecnode = sector->touching_preciplist; psecnode; psecnode = psecnode->m_snext)
|
||||
for (psecnode = sector->touching_preciplist; psecnode; psecnode = psecnode->m_thinglist_next)
|
||||
CalculatePrecipFloor(psecnode->m_thing);
|
||||
}
|
||||
|
||||
|
@ -4428,7 +4436,7 @@ static void P_Boss4MoveSpikeballs(mobj_t *mobj, angle_t angle, fixed_t fz)
|
|||
{
|
||||
INT32 s;
|
||||
mobj_t *base = mobj, *seg;
|
||||
fixed_t dist, bz = (mobj->spawnpoint->z+16)<<FRACBITS;
|
||||
fixed_t dist, bz = mobj->watertop+(16<<FRACBITS);
|
||||
while ((base = base->tracer))
|
||||
{
|
||||
for (seg = base, dist = 172*FRACUNIT, s = 9; seg; seg = seg->hnext, dist += 124*FRACUNIT, --s)
|
||||
|
@ -4442,7 +4450,7 @@ static void P_Boss4PinchSpikeballs(mobj_t *mobj, angle_t angle, fixed_t fz)
|
|||
{
|
||||
INT32 s;
|
||||
mobj_t *base = mobj, *seg;
|
||||
fixed_t dist, bz = (mobj->spawnpoint->z+16)<<FRACBITS;
|
||||
fixed_t dist, bz = mobj->watertop+(16<<FRACBITS);
|
||||
while ((base = base->tracer))
|
||||
{
|
||||
for (seg = base, dist = 112*FRACUNIT, s = 9; seg; seg = seg->hnext, dist += 132*FRACUNIT, --s)
|
||||
|
@ -4558,7 +4566,7 @@ static void P_Boss4Thinker(mobj_t *mobj)
|
|||
INT32 i, arm;
|
||||
mobj_t *seg, *base = mobj;
|
||||
// First frame init, spawn all the things.
|
||||
mobj->spawnpoint->z = mobj->z>>FRACBITS;
|
||||
mobj->watertop = mobj->z;
|
||||
z = mobj->z + mobj->height/2 - mobjinfo[MT_EGGMOBILE4_MACE].height/2;
|
||||
for (arm = 0; arm <3 ; arm++)
|
||||
{
|
||||
|
@ -4614,7 +4622,7 @@ static void P_Boss4Thinker(mobj_t *mobj)
|
|||
case 3:
|
||||
{
|
||||
fixed_t z;
|
||||
if (mobj->z < (mobj->spawnpoint->z+512)<<FRACBITS)
|
||||
if (mobj->z < mobj->watertop+(512<<FRACBITS))
|
||||
mobj->momz = 8*FRACUNIT;
|
||||
else
|
||||
{
|
||||
|
@ -4623,7 +4631,7 @@ static void P_Boss4Thinker(mobj_t *mobj)
|
|||
}
|
||||
mobj->movecount += 400<<(FRACBITS>>1);
|
||||
mobj->movecount %= 360*FRACUNIT;
|
||||
z = mobj->z - (mobj->spawnpoint->z<<FRACBITS) - mobjinfo[MT_EGGMOBILE4_MACE].height - mobj->height/2;
|
||||
z = mobj->z - mobj->watertop - mobjinfo[MT_EGGMOBILE4_MACE].height - mobj->height/2;
|
||||
if (z < 0) // We haven't risen high enough to pull the spikeballs along yet
|
||||
P_Boss4MoveSpikeballs(mobj, FixedAngle(mobj->movecount), 0); // So don't pull the spikeballs along yet.
|
||||
else
|
||||
|
@ -4633,13 +4641,13 @@ static void P_Boss4Thinker(mobj_t *mobj)
|
|||
// Pinch phase!
|
||||
case 4:
|
||||
{
|
||||
if (mobj->z < (mobj->spawnpoint->z+512+128*(mobj->info->damage-mobj->health))<<FRACBITS)
|
||||
if (mobj->z < (mobj->watertop + ((512+128*(mobj->info->damage-mobj->health))<<FRACBITS)))
|
||||
mobj->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<<FRACBITS) - mobjinfo[MT_EGGMOBILE4_MACE].height - mobj->height/2);
|
||||
P_Boss4PinchSpikeballs(mobj, FixedAngle(mobj->movecount), mobj->z - mobj->watertop - mobjinfo[MT_EGGMOBILE4_MACE].height - mobj->height/2);
|
||||
|
||||
if (!mobj->target || !mobj->target->health)
|
||||
P_SupermanLook4Players(mobj);
|
||||
|
@ -6040,6 +6048,8 @@ void P_RunOverlays(void)
|
|||
P_UnsetThingPosition(mo);
|
||||
mo->x = destx;
|
||||
mo->y = desty;
|
||||
mo->radius = mo->target->radius;
|
||||
mo->height = mo->target->height;
|
||||
if (mo->eflags & MFE_VERTICALFLIP)
|
||||
mo->z = (mo->target->z + mo->target->height - mo->height) - zoffs;
|
||||
else
|
||||
|
@ -6638,6 +6648,18 @@ void P_MobjThinker(mobj_t *mobj)
|
|||
}
|
||||
else switch (mobj->type)
|
||||
{
|
||||
case MT_FALLINGROCK:
|
||||
// Despawn rocks here in case zmovement code can't do so (blame slopes)
|
||||
if (!mobj->momx && !mobj->momy && !mobj->momz
|
||||
&& ((mobj->eflags & MFE_VERTICALFLIP) ?
|
||||
mobj->z + mobj->height >= mobj->ceilingz
|
||||
: mobj->z <= mobj->floorz))
|
||||
{
|
||||
P_RemoveMobj(mobj);
|
||||
return;
|
||||
}
|
||||
P_MobjCheckWater(mobj);
|
||||
break;
|
||||
case MT_EMERALDSPAWN:
|
||||
if (mobj->threshold)
|
||||
{
|
||||
|
@ -6917,6 +6939,7 @@ void P_MobjThinker(mobj_t *mobj)
|
|||
{
|
||||
mobj->flags &= ~MF_NOGRAVITY;
|
||||
P_SetMobjState(mobj, S_NIGHTSDRONE1);
|
||||
mobj->flags2 |= MF2_DONTDRAW;
|
||||
}
|
||||
}
|
||||
else if (mobj->tracer && mobj->tracer->player)
|
||||
|
@ -7674,6 +7697,10 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type)
|
|||
|
||||
if (mobj->type == MT_UNIDUS)
|
||||
mobj->z -= FixedMul(mobj->info->mass, mobj->scale);
|
||||
|
||||
// defaults onground
|
||||
if (mobj->z + mobj->height == mobj->ceilingz)
|
||||
mobj->eflags |= MFE_ONGROUND;
|
||||
}
|
||||
else
|
||||
mobj->z = z;
|
||||
|
@ -7780,6 +7807,7 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type)
|
|||
break;
|
||||
case MT_EGGCAPSULE:
|
||||
mobj->extravalue1 = -1; // timer for how long a player has been at the capsule
|
||||
break;
|
||||
case MT_REDTEAMRING:
|
||||
mobj->color = skincolor_redteam;
|
||||
break;
|
||||
|
|
|
@ -441,7 +441,7 @@ boolean P_SupermanLook4Players(mobj_t *actor);
|
|||
void P_DestroyRobots(void);
|
||||
void P_SnowThinker(precipmobj_t *mobj);
|
||||
void P_RainThinker(precipmobj_t *mobj);
|
||||
void P_NullPrecipThinker(precipmobj_t *mobj);
|
||||
FUNCMATH void P_NullPrecipThinker(precipmobj_t *mobj);
|
||||
void P_RemovePrecipMobj(precipmobj_t *mobj);
|
||||
void P_SetScale(mobj_t *mobj, fixed_t newscale);
|
||||
void P_XYMovement(mobj_t *mo);
|
||||
|
|
|
@ -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();
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue