Merge branch 'master' into public_flatsprite

This commit is contained in:
Alam Ed Arias 2017-05-12 20:42:55 -04:00
commit 459d8064ee
118 changed files with 4285 additions and 5687 deletions

63
.circleci/config.yml Normal file
View 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

View file

@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.0)
project(SRB2
VERSION 2.1.14
VERSION 2.1.18
LANGUAGES C)
if(${PROJECT_SOURCE_DIR} MATCHES ${PROJECT_BINARY_DIR})

23
README.md Normal file
View 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.

3002
SRB2.cbp

File diff suppressed because it is too large Load diff

View file

@ -1,4 +1,4 @@
version: 2.1.16.{branch}-{build}
version: 2.1.18.{branch}-{build}
os: MinGW
environment:
@ -47,7 +47,7 @@ before_build:
- upx -V
- ccache -V
- ccache -s
- set SRB2_MFLAGS=-C src MINGW=1 WARNINGMODE=1 GCC53=1 CCACHE=1
- set SRB2_MFLAGS=-C src MINGW=1 WARNINGMODE=1 GCC63=1 CCACHE=1
build_script:
- cmd: mingw32-make.exe %SRB2_MFLAGS% %CONFIGURATION%=1 clean

View file

@ -1,3 +1,3 @@
/srb2sdl.exe
/srb2win.exe
/r_opengl.dll
*.exe
*.mo
r_opengl.dll

View file

@ -1,3 +1,3 @@
/srb2sdl.exe
/srb2win.exe
/r_opengl.dll
*.exe
*.mo
r_opengl.dll

3
debian/docs vendored
View file

@ -1,2 +1 @@
readme.txt
readme.txt
README.md

8
objs/.gitignore vendored Normal file
View file

@ -0,0 +1,8 @@
#All folders
SRB2.res
depend.dep
depend.ped
*.o
#VC9 folder only
/VC9/Win32
/VC9/x64

View file

@ -1 +1,2 @@
/depend.dep
# DON'T REMOVE
# This keeps the folder from disappearing

View file

@ -1 +1,2 @@
/depend.dep
# DON'T REMOVE
# This keeps the folder from disappearing

View file

@ -1,2 +1,2 @@
/depend.dep
/*.o
# DON'T REMOVE
# This keeps the folder from disappearing

View file

@ -1,2 +1,2 @@
/depend.dep
/*.o
# DON'T REMOVE
# This keeps the folder from disappearing

View file

@ -1,2 +1,2 @@
/depend.dep
/*.o
# DON'T REMOVE
# This keeps the folder from disappearing

View file

@ -1,2 +1,2 @@
/depend.dep
/*.o
# DON'T REMOVE
# This keeps the folder from disappearing

View file

@ -1,3 +1,2 @@
/SRB2.res
/depend.dep
/*.o
# DON'T REMOVE
# This keeps the folder from disappearing

View file

@ -1,3 +1,2 @@
/SRB2.res
/depend.dep
/*.o
# DON'T REMOVE
# This keeps the folder from disappearing

View file

@ -1,3 +1,2 @@
/SRB2.res
/depend.dep
/*.o
# DON'T REMOVE
# This keeps the folder from disappearing

View file

@ -1,3 +1,2 @@
/SRB2.res
/depend.dep
/*.o
# DON'T REMOVE
# This keeps the folder from disappearing

View file

@ -1,3 +1,2 @@
/SRB2.res
/depend.dep
/*.o
# DON'T REMOVE
# This keeps the folder from disappearing

View file

@ -1,3 +1,2 @@
/SRB2.res
/depend.dep
/*.o
# DON'T REMOVE
# This keeps the folder from disappearing

View file

@ -1,3 +1,2 @@
/SRB2.res
/depend.dep
/*.o
# DON'T REMOVE
# This keeps the folder from disappearing

View file

@ -1,3 +1,2 @@
/SRB2.res
/depend.dep
/*.o
# DON'T REMOVE
# This keeps the folder from disappearing

View file

@ -1,2 +1,2 @@
/depend.dep
/*.o
# DON'T REMOVE
# This keeps the folder from disappearing

View file

@ -1,2 +1,2 @@
/depend.dep
/*.o
# DON'T REMOVE
# This keeps the folder from disappearing

View file

@ -1 +1,2 @@
/depend.dep
# DON'T REMOVE
# This keeps the folder from disappearing

View file

@ -1 +1,2 @@
/depend.ped
# DON'T REMOVE
# This keeps the folder from disappearing

2
objs/VC/.gitignore vendored
View file

@ -0,0 +1,2 @@
# DON'T REMOVE
# This keeps the folder from disappearing

4
objs/VC9/.gitignore vendored
View file

@ -1,2 +1,2 @@
/Win32
/x64
# DON'T REMOVE
# This keeps the folder from disappearing

View file

@ -1,2 +1,2 @@
/depend.dep
/*.o
# DON'T REMOVE
# This keeps the folder from disappearing

View file

@ -1,2 +1,2 @@
/depend.dep
/*.o
# DON'T REMOVE
# This keeps the folder from disappearing

View file

@ -1 +1,2 @@
/depend.dep
# DON'T REMOVE
# This keeps the folder from disappearing

View file

@ -1 +1,2 @@
/depend.dep
# DON'T REMOVE
# This keeps the folder from disappearing

View file

@ -1 +1,2 @@
/depend.dep
# DON'T REMOVE
# This keeps the folder from disappearing

View file

@ -1,2 +1,2 @@
/depend.dep
/*.o
# DON'T REMOVE
# This keeps the folder from disappearing

View file

@ -1,2 +1,2 @@
/depend.dep
/*.o
# DON'T REMOVE
# This keeps the folder from disappearing

View file

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

View file

@ -390,18 +390,25 @@ if(${SRB2_CONFIG_HWRENDER} AND ${SRB2_CONFIG_STATIC_OPENGL})
endif()
if(${SRB2_CONFIG_USEASM})
#SRB2_ASM_FLAGS can be used to pass flags to either nasm or yasm.
if(${CMAKE_SYSTEM} MATCHES "Linux")
set(SRB2_ASM_FLAGS "-DLINUX ${SRB2_ASM_FLAGS}")
endif()
if(${SRB2_CONFIG_YASM})
set(CMAKE_ASM_YASM_SOURCE_FILE_EXTENSIONS ${CMAKE_ASM_YASM_SOURCE_FILE_EXTENSIONS} nas)
set(CMAKE_ASM_YASM_FLAGS "${SRB2_ASM_FLAGS}" CACHE STRING "Flags used by the assembler during all build types.")
enable_language(ASM_YASM)
else()
set(CMAKE_ASM_NASM_SOURCE_FILE_EXTENSIONS ${CMAKE_ASM_NASM_SOURCE_FILE_EXTENSIONS} nas)
set(CMAKE_ASM_NASM_FLAGS "${SRB2_ASM_FLAGS}" CACHE STRING "Flags used by the assembler during all build types.")
enable_language(ASM_NASM)
endif()
set(SRB2_USEASM ON)
add_definitions(-DUSEASM)
else()
set(SRB2_USEASM OFF)
add_definitions(-DNOASM -DNONX86)
add_definitions(-DNONX86 -DNORUSEASM)
endif()
# Targets

View file

@ -179,6 +179,9 @@ endif
ifdef LINUX
UNIXCOMMON=1
ifndef NOGME
HAVE_LIBGME=1
endif
endif
ifdef SOLARIS
@ -315,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
@ -366,6 +376,14 @@ endif
OPTS:=-fno-exceptions $(OPTS)
ifdef MOBJCONSISTANCY
OPTS+=-DMOBJCONSISTANCY
endif
ifdef PACKETDROP
OPTS+=-DPACKETDROP
endif
ifdef DEBUGMODE
# build with debugging information
@ -375,7 +393,7 @@ ifdef GCC48
else
CFLAGS+=-O0
endif
CFLAGS+= -Wall -DPARANOIA -DRANGECHECK
CFLAGS+= -Wall -DPARANOIA -DRANGECHECK -DPACKETDROP -DMOBJCONSISTANCY
else

View file

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

View file

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

View file

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

View file

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

File diff suppressed because it is too large Load diff

View file

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

View file

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

View file

@ -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
@ -657,7 +716,13 @@ void Net_CloseConnection(INT32 node)
if (!node)
return;
nodes[node].flags |= CLOSE;
if (node < 0 || node >= MAXNETNODES) // prevent invalid nodes from crashing the game
{
CONS_Alert(CONS_WARNING, 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 +741,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 +794,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 +820,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 +848,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 +886,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 +903,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 +917,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 +1043,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 +1056,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 +1077,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 +1115,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 +1142,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 +1161,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 +1171,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 +1203,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 +1291,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 +1432,6 @@ void D_CloseConnection(void)
netgame = false;
addedtogame = false;
}
D_ResetTiccmds();
}

View file

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

View file

@ -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.
@ -1587,7 +1622,7 @@ static void Command_Map_f(void)
return;
}
if (!server && !(adminplayer == consoleplayer))
if (client && !(adminplayer == consoleplayer))
{
CONS_Printf(M_GetText("Only the server or a remote admin can use this.\n"));
return;
@ -1914,7 +1949,7 @@ static void Got_Suicide(UINT8 **cp, INT32 playernum)
// You can't suicide someone else. Nice try, there.
if (suicideplayer != playernum || (!G_PlatformGametype()))
{
CONS_Alert(CONS_WARNING, M_GetText("Illegal suicide command recieved from %s\n"), player_names[playernum]);
CONS_Alert(CONS_WARNING, M_GetText("Illegal suicide command received from %s\n"), player_names[playernum]);
if (server)
{
XBOXSTATIC UINT8 buf[2];
@ -2081,7 +2116,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 +2213,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 +2664,7 @@ static void Command_Changepassword_f(void)
// If we have no MD5 support then completely disable XD_LOGIN responses for security.
CONS_Alert(CONS_NOTICE, "Remote administration commands are not supported in this build.\n");
#else
if (!server) // cannot change remotely
if (client) // cannot change remotely
{
CONS_Printf(M_GetText("Only the server can use this.\n"));
return;
@ -2688,7 +2723,7 @@ static void Got_Login(UINT8 **cp, INT32 playernum)
READMEM(*cp, sentmd5, 16);
if (!server)
if (client)
return;
// Do the final pass to compare with the sent md5
@ -2710,7 +2745,7 @@ static void Command_Verify_f(void)
char *temp;
INT32 playernum;
if (!server)
if (client)
{
CONS_Printf(M_GetText("Only the server can use this.\n"));
return;
@ -2794,7 +2829,7 @@ static void Command_MotD_f(void)
return;
}
if ((netgame || multiplayer) && !server)
if ((netgame || multiplayer) && client)
SendNetXCmd(XD_SETMOTD, mymotd, sizeof(motd));
else
{
@ -2932,6 +2967,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 +2982,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 +2996,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 +3016,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 +3024,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);
}
@ -3051,7 +3084,7 @@ static void Got_RequestAddfilecmd(UINT8 **cp, INT32 playernum)
READMEM(*cp, md5sum, 16);
// Only the server processes this message.
if (!server)
if (client)
return;
// Disallow non-printing characters and semicolons.
@ -3318,6 +3351,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 +3998,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 +4101,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 +4144,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;

View file

@ -162,6 +162,8 @@ typedef enum
MAXNETXCMD
} netxcmd_t;
extern const char *netxcmdnames[MAXNETXCMD - 1];
#if defined(_MSC_VER)
#pragma pack(1)
#endif

View file

@ -62,44 +62,48 @@
#include <errno.h>
static void SendFile(INT32 node, const char *filename, UINT8 fileid);
static void 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 +115,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 +148,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 +164,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 +180,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 +251,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)
{
@ -298,11 +314,17 @@ void Got_RequestFilePak(INT32 node)
if (id == 0xFF)
break;
READSTRINGN(p, wad, MAX_WADPATH);
SendFile(node, wad, id);
SV_SendFile(node, wad, id);
}
}
// 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;
@ -333,7 +355,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 +365,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;
@ -360,7 +382,7 @@ INT32 CL_CheckFiles(void)
{
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));
@ -383,7 +405,7 @@ INT32 CL_CheckFiles(void)
return ret;
}
// load it now
// Load it now
void CL_LoadServerFiles(void)
{
INT32 i;
@ -394,7 +416,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 +445,269 @@ 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 void 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\n", filename, 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;
}
// 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;
}
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++;
}
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 +715,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 +763,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 +858,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)
{

View file

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

View file

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

View file

@ -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 16 // more precise version number
#define VERSIONSTRING "v2.1.16"
#define VERSIONSTRINGW L"v2.1.16"
#define SUBVERSION 18 // more precise version number
#define VERSIONSTRING "v2.1.18"
#define VERSIONSTRINGW L"v2.1.18"
// 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 21
#define MODVERSION 23
// =========================================================================
@ -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)

View file

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

View file

@ -974,7 +974,7 @@ static const char *credits[] = {
"Scott \"Graue\" Feeney",
"Nathan \"Jazz\" Giroux",
"Thomas \"Shadow Hog\" Igoe",
"\"Monster\" Iestyn Jealous",
"Iestyn \"Monster Iestyn\" Jealous",
"Ronald \"Furyhunter\" Kinard", // The SDL2 port
"John \"JTE\" Muniz",
"Ehab \"Wolfy\" Saeed",
@ -986,6 +986,7 @@ static const char *credits[] = {
"\"chi.miru\"", // Red's secret weapon, the REAL reason slopes exist (also helped port drawing code from ZDoom)
"Andrew \"orospakr\" Clunis",
"Gregor \"Oogaland\" Dick",
"Louis-Antoine \"LJSonic\" de Moulins", // for fixing 2.1's netcode (de Rochefort doesn't quite fit on the screen sorry lol)
"Vivian \"toaster\" Grannell",
"Julio \"Chaos Zero 64\" Guir",
"\"Kalaron\"", // Coded some of Sryder13's collection of OpenGL fixes, especially fog
@ -1020,7 +1021,7 @@ static const char *credits[] = {
"Paul \"Boinciel\" Clempson",
"Cyan Helkaraxe",
"Kepa \"Nev3r\" Iceta",
"\"Monster\" Iestyn Jealous",
"Iestyn \"Monster Iestyn\" Jealous",
"Jarel \"Arrow\" Jones",
"Stefan \"Stuf\" Rimalia",
"Shane Mychal Sexton",
@ -1725,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)
@ -1741,7 +1743,6 @@ void F_EndCutScene(void)
else
Y_EndGame();
}
cutsceneover = true;
}
void F_StartCustomCutscene(INT32 cutscenenum, boolean precutscene, boolean resetplayer)

View file

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

View file

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

View file

@ -45,7 +45,7 @@
#include "hw_md2.h"
#define R_FAKEFLOORS
//#define HWPRECIP
#define HWPRECIP
#define SORTING
//#define POLYSKY
@ -1558,6 +1558,7 @@ static void HWR_StoreWallRange(double startfrac, double endfrac)
if (gr_backsector)
{
INT32 gr_toptexture, gr_bottomtexture;
// two sided line
if (gr_backsector->heightsec != -1)
{
@ -1608,19 +1609,22 @@ static void HWR_StoreWallRange(double startfrac, double endfrac)
#endif
}
gr_toptexture = R_GetTextureNum(gr_sidedef->toptexture);
gr_bottomtexture = R_GetTextureNum(gr_sidedef->bottomtexture);
// check TOP TEXTURE
if ((
#ifdef ESLOPE
worldhighslope < worldtopslope ||
#endif
worldhigh < worldtop
) && texturetranslation[gr_sidedef->toptexture])
) && gr_toptexture)
{
if (drawtextured)
{
fixed_t texturevpegtop; // top
grTex = HWR_GetTexture(texturetranslation[gr_sidedef->toptexture]);
grTex = HWR_GetTexture(gr_toptexture);
// PEGGING
if (gr_linedef->flags & ML_DONTPEGTOP)
@ -1638,7 +1642,7 @@ static void HWR_StoreWallRange(double startfrac, double endfrac)
texturevpegtop += gr_sidedef->rowoffset;
// This is so that it doesn't overflow and screw up the wall, it doesn't need to go higher than the texture's height anyway
texturevpegtop %= SHORT(textures[texturetranslation[gr_sidedef->toptexture]]->height)<<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;
@ -1683,9 +1687,9 @@ static void HWR_StoreWallRange(double startfrac, double endfrac)
#endif
if (gr_frontsector->numlights)
HWR_SplitWall(gr_frontsector, wallVerts, texturetranslation[gr_sidedef->toptexture], &Surf, FF_CUTSOLIDS);
HWR_SplitWall(gr_frontsector, wallVerts, gr_toptexture, &Surf, FF_CUTSOLIDS);
else if (grTex->mipmap.flags & TF_TRANSPARENT)
HWR_AddTransparentWall(wallVerts, &Surf, texturetranslation[gr_sidedef->toptexture], PF_Environment, false, lightnum, colormap);
HWR_AddTransparentWall(wallVerts, &Surf, gr_toptexture, PF_Environment, false, lightnum, colormap);
else
HWR_ProjectWall(wallVerts, &Surf, PF_Masked, lightnum, colormap);
}
@ -1695,13 +1699,13 @@ static void HWR_StoreWallRange(double startfrac, double endfrac)
#ifdef ESLOPE
worldlowslope > worldbottomslope ||
#endif
worldlow > worldbottom) && texturetranslation[gr_sidedef->bottomtexture]) //only if VISIBLE!!!
worldlow > worldbottom) && gr_bottomtexture) //only if VISIBLE!!!
{
if (drawtextured)
{
fixed_t texturevpegbottom = 0; // bottom
grTex = HWR_GetTexture(texturetranslation[gr_sidedef->bottomtexture]);
grTex = HWR_GetTexture(gr_bottomtexture);
// PEGGING
#ifdef ESLOPE
@ -1721,7 +1725,7 @@ static void HWR_StoreWallRange(double startfrac, double endfrac)
texturevpegbottom += gr_sidedef->rowoffset;
// This is so that it doesn't overflow and screw up the wall, it doesn't need to go higher than the texture's height anyway
texturevpegbottom %= SHORT(textures[texturetranslation[gr_sidedef->bottomtexture]]->height)<<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;
@ -1766,13 +1770,13 @@ static void HWR_StoreWallRange(double startfrac, double endfrac)
#endif
if (gr_frontsector->numlights)
HWR_SplitWall(gr_frontsector, wallVerts, texturetranslation[gr_sidedef->bottomtexture], &Surf, FF_CUTSOLIDS);
HWR_SplitWall(gr_frontsector, wallVerts, gr_bottomtexture, &Surf, FF_CUTSOLIDS);
else if (grTex->mipmap.flags & TF_TRANSPARENT)
HWR_AddTransparentWall(wallVerts, &Surf, texturetranslation[gr_sidedef->bottomtexture], PF_Environment, false, lightnum, colormap);
HWR_AddTransparentWall(wallVerts, &Surf, gr_bottomtexture, PF_Environment, false, lightnum, colormap);
else
HWR_ProjectWall(wallVerts, &Surf, PF_Masked, lightnum, colormap);
}
gr_midtexture = texturetranslation[gr_sidedef->midtexture];
gr_midtexture = R_GetTextureNum(gr_sidedef->midtexture);
if (gr_midtexture)
{
FBITFIELD blendmode;
@ -2134,7 +2138,7 @@ static void HWR_StoreWallRange(double startfrac, double endfrac)
else
{
// Single sided line... Deal only with the middletexture (if one exists)
gr_midtexture = texturetranslation[gr_sidedef->midtexture];
gr_midtexture = R_GetTextureNum(gr_sidedef->midtexture);
if (gr_midtexture)
{
if (drawtextured)
@ -2232,13 +2236,13 @@ static void HWR_StoreWallRange(double startfrac, double endfrac)
if (*rover->topheight < lowcut || *rover->bottomheight > highcut)
continue;
texnum = texturetranslation[sides[rover->master->sidenum[0]].midtexture];
texnum = R_GetTextureNum(sides[rover->master->sidenum[0]].midtexture);
if (rover->master->flags & ML_TFERLINE)
{
size_t linenum = gr_curline->linedef-gr_backsector->lines[0];
newline = rover->master->frontsector->lines[0] + linenum;
texnum = texturetranslation[sides[newline->sidenum[0]].midtexture];
texnum = R_GetTextureNum(sides[newline->sidenum[0]].midtexture);
}
#ifdef ESLOPE
@ -2366,13 +2370,13 @@ static void HWR_StoreWallRange(double startfrac, double endfrac)
if (*rover->topheight < lowcut || *rover->bottomheight > highcut)
continue;
texnum = texturetranslation[sides[rover->master->sidenum[0]].midtexture];
texnum = R_GetTextureNum(sides[rover->master->sidenum[0]].midtexture);
if (rover->master->flags & ML_TFERLINE)
{
size_t linenum = gr_curline->linedef-gr_backsector->lines[0];
newline = rover->master->frontsector->lines[0] + linenum;
texnum = texturetranslation[sides[newline->sidenum[0]].midtexture];
texnum = R_GetTextureNum(sides[newline->sidenum[0]].midtexture);
}
#ifdef ESLOPE //backsides
h = *rover->t_slope ? P_GetZAt(*rover->t_slope, v1x, v1y) : *rover->topheight;
@ -4403,7 +4407,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;
@ -4457,19 +4460,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 ? &sectors[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)
{
@ -4503,8 +4525,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;
@ -5336,6 +5358,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
@ -5348,7 +5375,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

View file

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

View file

@ -123,6 +123,7 @@ typedef struct
void *blendgrpatch;
boolean notfound;
INT32 skin;
boolean error;
} md2_t;
extern md2_t md2_models[NUMSPRITES];

View file

@ -1836,7 +1836,7 @@ EXPORT void HWRAPI(SetSpecialState) (hwdspecialstate_t IdState, INT32 Value)
}
}
static inline void DrawMD2Ex(INT32 *gl_cmd_buffer, md2_frame_t *frame, UINT32 duration, UINT32 tics, md2_frame_t *nextframe, FTransform *pos, float scale, UINT8 flipped, UINT8 *color)
static void DrawMD2Ex(INT32 *gl_cmd_buffer, md2_frame_t *frame, UINT32 duration, UINT32 tics, md2_frame_t *nextframe, FTransform *pos, float scale, UINT8 flipped, UINT8 *color)
{
INT32 val, count, pindex;
GLfloat s, t;

View file

@ -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);
}
}
//======================================================================

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -28,4 +28,4 @@ void M_AATreeSet(aatree_t *aatree, INT32 key, void* value);
void *M_AATreeGet(aatree_t *aatree, INT32 key);
void M_AATreeIterate(aatree_t *aatree, aatree_iter_t callback);
#endif
#endif

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1052,18 +1052,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
@ -1089,17 +1095,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
@ -1231,7 +1244,7 @@ if (tmthing->flags & MF_PAPERCOLLISION) // Caution! Turning whilst up against a
}
// set openrange, opentop, openbottom
P_LineOpening(ld);
P_LineOpening(ld, tmthing);
// adjust floor / ceiling heights
if (opentop < tmceilingz)
@ -1349,7 +1362,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);
@ -2048,8 +2061,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.
@ -2659,7 +2676,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
@ -2735,7 +2752,7 @@ isblocking:
// see about climbing on the wall
if (!(checkline->flags & ML_NOCLIMB))
{
boolean canclimb; // FUCK C90
boolean canclimb;
angle_t climbangle, climbline;
INT32 whichside = P_PointOnLineSide(slidemo->x, slidemo->y, li);

View file

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

View file

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

View file

@ -1278,25 +1278,23 @@ fixed_t P_GetMobjGravity(mobj_t *mo)
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;
}
}
@ -1318,28 +1316,20 @@ fixed_t P_GetMobjGravity(mobj_t *mo)
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
{
@ -1347,10 +1337,10 @@ fixed_t P_GetMobjGravity(mobj_t *mo)
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.
{
@ -1396,9 +1386,6 @@ fixed_t P_GetMobjGravity(mobj_t *mo)
if (goopgravity)
gravityadd = -gravityadd/5;
if (mo->player && !!(mo->eflags & MFE_VERTICALFLIP) != wasflip)
P_PlayerFlip(mo);
gravityadd = FixedMul(gravityadd, mo->scale);
return gravityadd;
@ -1553,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)
{
@ -1565,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;
}
@ -1650,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)
{
@ -1708,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);
}
@ -1815,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;;
@ -2029,13 +2017,13 @@ static void P_AdjustMobjFloorZ_FFloors(mobj_t *mo, sector_t *sector, UINT8 motyp
delta2 = thingtop - (bottomheight + ((topheight - bottomheight)/2));
if (topheight > mo->floorz && abs(delta1) < abs(delta2)
&& !(rover->flags & FF_REVERSEPLATFORM)
&& ((P_MobjFlip(mo)*mo->momz > 0) || (!(rover->flags & FF_PLATFORM)))) // In reverse gravity, only clip for FOFs that are intangible from their bottom (the "top" you're falling through) if you're coming from above ("below" in your frame of reference)
&& ((P_MobjFlip(mo)*mo->momz >= 0) || (!(rover->flags & FF_PLATFORM)))) // In reverse gravity, only clip for FOFs that are intangible from their bottom (the "top" you're falling through) if you're coming from above ("below" in your frame of reference)
{
mo->floorz = topheight;
}
if (bottomheight < mo->ceilingz && abs(delta1) >= abs(delta2)
&& !(rover->flags & FF_PLATFORM)
&& ((P_MobjFlip(mo)*mo->momz > 0) || (!(rover->flags & FF_REVERSEPLATFORM)))) // In normal gravity, only clip for FOFs that are intangible from the top if you're coming from below
&& ((P_MobjFlip(mo)*mo->momz >= 0) || (!(rover->flags & FF_REVERSEPLATFORM)))) // In normal gravity, only clip for FOFs that are intangible from the top if you're coming from below
{
mo->ceilingz = bottomheight;
}
@ -2375,6 +2363,12 @@ static boolean P_ZMovement(mobj_t *mo)
mo->z = mo->floorz;
#ifdef ESLOPE
if (mo->standingslope) // You're still on the ground; why are we here?
{
mo->momz = 0;
return true;
}
P_CheckPosition(mo, mo->x, mo->y); // Sets mo->standingslope correctly
if (((mo->eflags & MFE_VERTICALFLIP) ? tmceilingslope : tmfloorslope) && (mo->type != MT_STEAM))
{
@ -4442,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)
@ -4456,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)
@ -4572,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++)
{
@ -4628,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
{
@ -4637,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
@ -4647,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);
@ -6054,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
@ -6652,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)
{
@ -6931,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)
@ -7684,6 +7693,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;

View file

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

View file

@ -574,6 +574,69 @@ INT32 P_AddLevelFlat(const char *flatname, levelflat_t *levelflat)
return (INT32)i;
}
// help function for Lua and $$$.sav reading
// same as P_AddLevelFlat, except this is not setup so we must realloc levelflats to fit in the new flat
// no longer a static func in lua_maplib.c because p_saveg.c also needs it
//
INT32 P_AddLevelFlatRuntime(const char *flatname)
{
size_t i;
levelflat_t *levelflat = levelflats;
//
// first scan through the already found flats
//
for (i = 0; i < numlevelflats; i++, levelflat++)
if (strnicmp(levelflat->name,flatname,8)==0)
break;
// that flat was already found in the level, return the id
if (i == numlevelflats)
{
// allocate new flat memory
levelflats = Z_Realloc(levelflats, (numlevelflats + 1) * sizeof(*levelflats), PU_LEVEL, NULL);
levelflat = levelflats+i;
// store the name
strlcpy(levelflat->name, flatname, sizeof (levelflat->name));
strupr(levelflat->name);
// store the flat lump number
levelflat->lumpnum = R_GetFlatNumForName(flatname);
#ifndef ZDEBUG
CONS_Debug(DBG_SETUP, "flat #%03d: %s\n", atoi(sizeu1(numlevelflats)), levelflat->name);
#endif
numlevelflats++;
}
// level flat id
return (INT32)i;
}
// help function for $$$.sav checking
// this simply returns the flat # for the name given
//
INT32 P_CheckLevelFlat(const char *flatname)
{
size_t i;
levelflat_t *levelflat = levelflats;
//
// scan through the already found flats
//
for (i = 0; i < numlevelflats; i++, levelflat++)
if (strnicmp(levelflat->name,flatname,8)==0)
break;
if (i == numlevelflats)
return 0; // ??? flat was not found, this should not happen!
// level flat id
return (INT32)i;
}
static void P_LoadSectors(lumpnum_t lumpnum)
{
UINT8 *data;
@ -614,6 +677,7 @@ static void P_LoadSectors(lumpnum_t lumpnum)
ss->special = SHORT(ms->special);
ss->tag = SHORT(ms->tag);
ss->nexttag = ss->firsttag = -1;
ss->spawn_nexttag = ss->spawn_firsttag = -1;
memset(&ss->soundorg, 0, sizeof(ss->soundorg));
ss->validcount = 0;
@ -2585,11 +2649,7 @@ boolean P_SetupLevel(boolean skipprecip)
lastloadedmaplumpnum = W_GetNumForName(maplumpname = G_BuildMapName(gamemap));
R_ReInitColormaps(mapheaderinfo[gamemap-1]->palette);
CON_ReSetupBackColormap(mapheaderinfo[gamemap-1]->palette);
// now part of level loading since in future each level may have
// its own anim texture sequences, switches etc.
P_InitPicAnims();
CON_SetupBackColormap();
// SRB2 determines the sky texture to be used depending on the map header.
P_SetupLevelSky(mapheaderinfo[gamemap-1]->skynum, true);
@ -3001,6 +3061,9 @@ boolean P_AddWadFile(const char *wadfilename, char **firstmapname)
else
R_FlushTextureCache(); // just reload it from file
// Reload ANIMATED / ANIMDEFS
P_InitPicAnims();
// Flush and reload HUD graphics
ST_UnloadGraphics();
HU_LoadGraphics();

View file

@ -47,6 +47,8 @@ typedef struct
extern size_t numlevelflats;
extern levelflat_t *levelflats;
INT32 P_AddLevelFlat(const char *flatname, levelflat_t *levelflat);
INT32 P_AddLevelFlatRuntime(const char *flatname);
INT32 P_CheckLevelFlat(const char *flatname);
extern size_t nummapthings;
extern mapthing_t *mapthings;

View file

@ -221,8 +221,8 @@ static animdef_t harddefs[] =
static animdef_t *animdefs = NULL;
// A prototype; here instead of p_spec.h, so they're "private"
void P_ParseANIMDEFSLump(INT32 wadNum, UINT16 lumpnum, INT32 *i);
void P_ParseAnimationDefintion(SINT8 istexture, INT32 *i);
void P_ParseANIMDEFSLump(INT32 wadNum, UINT16 lumpnum);
void P_ParseAnimationDefintion(SINT8 istexture);
/** Sets up texture and flat animations.
*
@ -232,24 +232,21 @@ void P_ParseAnimationDefintion(SINT8 istexture, INT32 *i);
* Issues an error if any animation cycles are invalid.
*
* \sa P_FindAnimatedFlat, P_SetupLevelFlatAnims
* \author Steven McGranahan (original), Shadow Hog (had to rewrite it to handle multiple WADs)
* \author Steven McGranahan (original), Shadow Hog (had to rewrite it to handle multiple WADs), JTE (had to rewrite it to handle multiple WADs _correctly_)
*/
void P_InitPicAnims(void)
{
// Init animation
INT32 i; // Position in the animdefs array
INT32 w; // WAD
UINT8 *wadAnimdefs; // not to be confused with animdefs, the combined total of every ANIMATED lump in every WAD, or ANIMDEFS, the ZDoom lump I intend to implement later
UINT8 *animatedLump;
UINT8 *currentPos;
size_t i;
I_Assert(animdefs == NULL);
if (W_CheckNumForName("ANIMATED") != LUMPERROR || W_CheckNumForName("ANIMDEFS") != LUMPERROR)
{
if (animdefs)
{
Z_Free(animdefs);
animdefs = NULL;
}
for (w = 0, i = 0, maxanims = 0; w < numwadfiles; w++)
for (w = numwadfiles-1, maxanims = 0; w >= 0; w--)
{
UINT16 animatedLumpNum;
UINT16 animdefsLumpNum;
@ -258,20 +255,20 @@ void P_InitPicAnims(void)
animatedLumpNum = W_CheckNumForNamePwad("ANIMATED", w, 0);
if (animatedLumpNum != INT16_MAX)
{
wadAnimdefs = (UINT8 *)W_CacheLumpNumPwad(w, animatedLumpNum, PU_STATIC);
animatedLump = (UINT8 *)W_CacheLumpNumPwad(w, animatedLumpNum, PU_STATIC);
// Get the number of animations in the file
for (currentPos = wadAnimdefs; *currentPos != UINT8_MAX; maxanims++, currentPos+=23);
i = maxanims;
for (currentPos = animatedLump; *currentPos != UINT8_MAX; maxanims++, currentPos+=23);
// Resize animdefs (or if it hasn't been created, create it)
animdefs = (animdef_t *)Z_Realloc(animdefs, sizeof(animdef_t)*(maxanims + 1), PU_STATIC, NULL);
// Sanity check it
if (!animdefs) {
if (!animdefs)
I_Error("Not enough free memory for ANIMATED data");
}
// Populate the new array
for (currentPos = wadAnimdefs; *currentPos != UINT8_MAX; i++, currentPos+=23)
for (currentPos = animatedLump; *currentPos != UINT8_MAX; i++, currentPos+=23)
{
M_Memcpy(&(animdefs[i].istexture), currentPos, 1); // istexture, 1 byte
M_Memcpy(animdefs[i].endname, (currentPos + 1), 9); // endname, 9 bytes
@ -279,15 +276,13 @@ void P_InitPicAnims(void)
M_Memcpy(&(animdefs[i].speed), (currentPos + 19), 4); // speed, 4 bytes
}
Z_Free(wadAnimdefs);
Z_Free(animatedLump);
}
// Now find ANIMDEFS
animdefsLumpNum = W_CheckNumForNamePwad("ANIMDEFS", w, 0);
if (animdefsLumpNum != INT16_MAX)
{
P_ParseANIMDEFSLump(w, animdefsLumpNum, &i);
}
P_ParseANIMDEFSLump(w, animdefsLumpNum);
}
// Define the last one
animdefs[maxanims].istexture = -1;
@ -347,16 +342,20 @@ void P_InitPicAnims(void)
lastanim->istexture = -1;
R_ClearTextureNumCache(false);
// Clear animdefs now that we're done with it.
// We'll only be using anims from now on.
if (animdefs != harddefs)
Z_ChangeTag(animdefs, PU_CACHE);
Z_Free(animdefs);
animdefs = NULL;
}
void P_ParseANIMDEFSLump(INT32 wadNum, UINT16 lumpnum, INT32 *i)
void P_ParseANIMDEFSLump(INT32 wadNum, UINT16 lumpnum)
{
char *animdefsLump;
size_t animdefsLumpLength;
char *animdefsText;
char *animdefsToken;
char *p;
// Since lumps AREN'T \0-terminated like I'd assumed they should be, I'll
// need to make a space of memory where I can ensure that it will terminate
@ -376,18 +375,19 @@ void P_ParseANIMDEFSLump(INT32 wadNum, UINT16 lumpnum, INT32 *i)
Z_Free(animdefsLump);
// Now, let's start parsing this thing
animdefsToken = M_GetToken(animdefsText);
p = animdefsText;
animdefsToken = M_GetToken(p);
while (animdefsToken != NULL)
{
if (stricmp(animdefsToken, "TEXTURE") == 0)
{
Z_Free(animdefsToken);
P_ParseAnimationDefintion(1, i);
P_ParseAnimationDefintion(1);
}
else if (stricmp(animdefsToken, "FLAT") == 0)
{
Z_Free(animdefsToken);
P_ParseAnimationDefintion(0, i);
P_ParseAnimationDefintion(0);
}
else if (stricmp(animdefsToken, "OSCILLATE") == 0)
{
@ -398,23 +398,22 @@ void P_ParseANIMDEFSLump(INT32 wadNum, UINT16 lumpnum, INT32 *i)
{
I_Error("Error parsing ANIMDEFS lump: Expected \"TEXTURE\" or \"FLAT\", got \"%s\"",animdefsToken);
}
animdefsToken = M_GetToken(NULL);
// parse next line
while (*p != '\0' && *p != '\n') ++p;
if (*p == '\n') ++p;
animdefsToken = M_GetToken(p);
}
Z_Free(animdefsToken);
Z_Free((void *)animdefsText);
}
void P_ParseAnimationDefintion(SINT8 istexture, INT32 *i)
void P_ParseAnimationDefintion(SINT8 istexture)
{
char *animdefsToken;
size_t animdefsTokenLength;
char *endPos;
INT32 animSpeed;
// Increase the size to make room for the new animation definition
maxanims++;
animdefs = (animdef_t *)Z_Realloc(animdefs, sizeof(animdef_t)*(maxanims + 1), PU_STATIC, NULL);
animdefs[*i].istexture = istexture;
size_t i;
// Startname
animdefsToken = M_GetToken(NULL);
@ -448,14 +447,39 @@ void P_ParseAnimationDefintion(SINT8 istexture, INT32 *i)
{
I_Error("Error parsing ANIMDEFS lump: lump name \"%s\" exceeds 8 characters", animdefsToken);
}
strncpy(animdefs[*i].startname, animdefsToken, 9);
// Search for existing animdef
for (i = 0; i < maxanims; i++)
if (stricmp(animdefsToken, animdefs[i].startname) == 0)
{
//CONS_Alert(CONS_NOTICE, "Duplicate animation: %s\n", animdefsToken);
// If we weren't parsing in reverse order, we would `break` here and parse the new data into the existing slot we found.
// Instead, we're just going to skip parsing the rest of this line entirely.
Z_Free(animdefsToken);
return;
}
// Not found
if (i == maxanims)
{
// Increase the size to make room for the new animation definition
maxanims++;
animdefs = (animdef_t *)Z_Realloc(animdefs, sizeof(animdef_t)*(maxanims + 1), PU_STATIC, NULL);
strncpy(animdefs[i].startname, animdefsToken, 9);
}
// animdefs[i].startname is now set to animdefsToken either way.
Z_Free(animdefsToken);
// set texture type
animdefs[i].istexture = istexture;
// "RANGE"
animdefsToken = M_GetToken(NULL);
if (animdefsToken == NULL)
{
I_Error("Error parsing ANIMDEFS lump: Unexpected end of file where \"RANGE\" after \"%s\"'s startname should be", animdefs[*i].startname);
I_Error("Error parsing ANIMDEFS lump: Unexpected end of file where \"RANGE\" after \"%s\"'s startname should be", animdefs[i].startname);
}
if (stricmp(animdefsToken, "ALLOWDECALS") == 0)
{
@ -470,7 +494,7 @@ void P_ParseAnimationDefintion(SINT8 istexture, INT32 *i)
}
if (stricmp(animdefsToken, "RANGE") != 0)
{
I_Error("Error parsing ANIMDEFS lump: Expected \"RANGE\" after \"%s\"'s startname, got \"%s\"", animdefs[*i].startname, animdefsToken);
I_Error("Error parsing ANIMDEFS lump: Expected \"RANGE\" after \"%s\"'s startname, got \"%s\"", animdefs[i].startname, animdefsToken);
}
Z_Free(animdefsToken);
@ -478,21 +502,21 @@ void P_ParseAnimationDefintion(SINT8 istexture, INT32 *i)
animdefsToken = M_GetToken(NULL);
if (animdefsToken == NULL)
{
I_Error("Error parsing ANIMDEFS lump: Unexpected end of file where \"%s\"'s end texture/flat name should be", animdefs[*i].startname);
I_Error("Error parsing ANIMDEFS lump: Unexpected end of file where \"%s\"'s end texture/flat name should be", animdefs[i].startname);
}
animdefsTokenLength = strlen(animdefsToken);
if (animdefsTokenLength>8)
{
I_Error("Error parsing ANIMDEFS lump: lump name \"%s\" exceeds 8 characters", animdefsToken);
}
strncpy(animdefs[*i].endname, animdefsToken, 9);
strncpy(animdefs[i].endname, animdefsToken, 9);
Z_Free(animdefsToken);
// "TICS"
animdefsToken = M_GetToken(NULL);
if (animdefsToken == NULL)
{
I_Error("Error parsing ANIMDEFS lump: Unexpected end of file where \"%s\"'s \"TICS\" should be", animdefs[*i].startname);
I_Error("Error parsing ANIMDEFS lump: Unexpected end of file where \"%s\"'s \"TICS\" should be", animdefs[i].startname);
}
if (stricmp(animdefsToken, "RAND") == 0)
{
@ -501,7 +525,7 @@ void P_ParseAnimationDefintion(SINT8 istexture, INT32 *i)
}
if (stricmp(animdefsToken, "TICS") != 0)
{
I_Error("Error parsing ANIMDEFS lump: Expected \"TICS\" in animation definition for \"%s\", got \"%s\"", animdefs[*i].startname, animdefsToken);
I_Error("Error parsing ANIMDEFS lump: Expected \"TICS\" in animation definition for \"%s\", got \"%s\"", animdefs[i].startname, animdefsToken);
}
Z_Free(animdefsToken);
@ -509,7 +533,7 @@ void P_ParseAnimationDefintion(SINT8 istexture, INT32 *i)
animdefsToken = M_GetToken(NULL);
if (animdefsToken == NULL)
{
I_Error("Error parsing TEXTURES lump: Unexpected end of file where \"%s\"'s animation speed should be", animdefs[*i].startname);
I_Error("Error parsing ANIMDEFS lump: Unexpected end of file where \"%s\"'s animation speed should be", animdefs[i].startname);
}
endPos = NULL;
#ifndef AVOID_ERRNO
@ -523,13 +547,10 @@ void P_ParseAnimationDefintion(SINT8 istexture, INT32 *i)
#endif
|| animSpeed < 0) // Number is not positive
{
I_Error("Error parsing TEXTURES lump: Expected a positive integer for \"%s\"'s animation speed, got \"%s\"", animdefs[*i].startname, animdefsToken);
I_Error("Error parsing ANIMDEFS lump: Expected a positive integer for \"%s\"'s animation speed, got \"%s\"", animdefs[i].startname, animdefsToken);
}
animdefs[*i].speed = animSpeed;
animdefs[i].speed = animSpeed;
Z_Free(animdefsToken);
// Increment i before we go, so this doesn't cause issues later
(*i)++;
}
@ -1188,7 +1209,12 @@ INT32 P_FindSpecialLineFromTag(INT16 special, INT16 tag, INT32 start)
{
start++;
while (lines[start].special != special)
// This redundant check stops the compiler from complaining about function expansion
// elsewhere for some reason and everything is awful
if (start >= (INT32)numlines)
return -1;
while (start < (INT32)numlines && lines[start].special != special)
start++;
if (start >= (INT32)numlines)
@ -1493,6 +1519,8 @@ static inline void P_InitTagLists(void)
size_t j = (unsigned)sectors[i].tag % numsectors;
sectors[i].nexttag = sectors[j].firsttag;
sectors[j].firsttag = (INT32)i;
sectors[i].spawn_nexttag = sectors[i].nexttag;
sectors[j].spawn_firsttag = sectors[j].firsttag;
}
for (i = numlines - 1; i != (size_t)-1; i--)
@ -3011,7 +3039,10 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec)
case 443: // Calls a named Lua function
#ifdef HAVE_BLUA
LUAh_LinedefExecute(line, mo, callsec);
if (line->text)
LUAh_LinedefExecute(line, mo, callsec);
else
CONS_Alert(CONS_WARNING, "Linedef %s is missing the hook name of the Lua function to call! (This should be given in the front texture fields)\n", sizeu1(line-lines));
#else
CONS_Alert(CONS_ERROR, "The map is trying to run a Lua script, but this exe was not compiled with Lua support!\n");
#endif
@ -5316,6 +5347,10 @@ void T_LaserFlash(laserthink_t *flash)
&& thing->flags & MF_BOSS)
continue; // Don't hurt bosses
// Don't endlessly kill egg guard shields (or anything else for that matter)
if (thing->health <= 0)
continue;
top = P_GetSpecialTopZ(thing, sourcesec, sector);
bottom = P_GetSpecialBottomZ(thing, sourcesec, sector);
@ -7423,7 +7458,7 @@ void T_Pusher(pusher_t *p)
}
else
{
if (top < thing->z || referrer->floorheight > (thing->z + (thing->height >> 1)))
if (top < thing->z || bottom > (thing->z + (thing->height >> 1)))
continue;
if (thing->z + thing->height > top)
touching = true;

View file

@ -1692,6 +1692,7 @@ static void P_CheckBustableBlocks(player_t *player)
if (node->m_sector->ffloors)
{
ffloor_t *rover;
fixed_t topheight, bottomheight;
for (rover = node->m_sector->ffloors; rover; rover = rover->next)
{
@ -1717,42 +1718,45 @@ static void P_CheckBustableBlocks(player_t *player)
if (!(rover->flags & FF_SHATTER) && (rover->flags & FF_ONLYKNUX) && !(player->charability == CA_GLIDEANDCLIMB))
continue;
topheight = P_GetFOFTopZ(player->mo, node->m_sector, rover, player->mo->x, player->mo->y, NULL);
bottomheight = P_GetFOFBottomZ(player->mo, node->m_sector, rover, player->mo->x, player->mo->y, NULL);
// Height checks
if (rover->flags & FF_SHATTERBOTTOM)
{
if (player->mo->z+player->mo->momz + player->mo->height < *rover->bottomheight)
if (player->mo->z+player->mo->momz + player->mo->height < bottomheight)
continue;
if (player->mo->z+player->mo->height > *rover->bottomheight)
if (player->mo->z+player->mo->height > bottomheight)
continue;
}
else if (rover->flags & FF_SPINBUST)
{
if (player->mo->z+player->mo->momz > *rover->topheight)
if (player->mo->z+player->mo->momz > topheight)
continue;
if (player->mo->z + player->mo->height < *rover->bottomheight)
if (player->mo->z + player->mo->height < bottomheight)
continue;
}
else if (rover->flags & FF_SHATTER)
{
if (player->mo->z + player->mo->momz > *rover->topheight)
if (player->mo->z + player->mo->momz > topheight)
continue;
if (player->mo->z+player->mo->momz + player->mo->height < *rover->bottomheight)
if (player->mo->z+player->mo->momz + player->mo->height < bottomheight)
continue;
}
else
{
if (player->mo->z >= *rover->topheight)
if (player->mo->z >= topheight)
continue;
if (player->mo->z + player->mo->height < *rover->bottomheight)
if (player->mo->z + player->mo->height < bottomheight)
continue;
}
// Impede the player's fall a bit
if (((rover->flags & FF_SPINBUST) || (rover->flags & FF_SHATTER)) && player->mo->z >= *rover->topheight)
if (((rover->flags & FF_SPINBUST) || (rover->flags & FF_SHATTER)) && player->mo->z >= topheight)
player->mo->momz >>= 1;
else if (rover->flags & FF_SHATTER)
{
@ -2284,17 +2288,15 @@ static void P_DoClimbing(player_t *player)
if (!glidesector || glidesector->sector != player->mo->subsector->sector)
{
boolean floorclimb;
boolean thrust;
boolean boostup;
boolean skyclimber;
boolean floorclimb = false;
boolean thrust = false;
boolean boostup = false;
boolean skyclimber = false;
fixed_t floorheight, ceilingheight; // ESLOPE
thrust = false;
floorclimb = false;
boostup = false;
skyclimber = false;
if (glidesector)
if (!glidesector)
floorclimb = true;
else
{
#ifdef ESLOPE
floorheight = glidesector->sector->f_slope ? P_GetZAt(glidesector->sector->f_slope, player->mo->x, player->mo->y)
@ -2589,8 +2591,6 @@ static void P_DoClimbing(player_t *player)
}
}
}
else
floorclimb = true;
if (player->lastsidehit != -1 && player->lastlinehit != -1)
{
@ -6979,6 +6979,7 @@ static void P_MovePlayer(player_t *player)
msecnode_t *node; // only place it's being used in P_MovePlayer now
fixed_t oldx;
fixed_t oldy;
fixed_t floorz, ceilingz;
oldx = player->mo->x;
oldy = player->mo->y;
@ -6996,31 +6997,34 @@ static void P_MovePlayer(player_t *player)
if (node->m_sector->ffloors)
{
ffloor_t *rover;
fixed_t topheight, bottomheight;
for (rover = node->m_sector->ffloors; rover; rover = rover->next)
{
if (!(rover->flags & FF_EXISTS)) continue;
if (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_BLOCKPLAYER))
continue;
if ((rover->flags & FF_BLOCKPLAYER))
topheight = P_GetFOFTopZ(player->mo, node->m_sector, rover, player->mo->x, player->mo->y, NULL);
bottomheight = P_GetFOFBottomZ(player->mo, node->m_sector, rover, player->mo->x, player->mo->y, NULL);
if (topheight > player->mo->z && bottomheight < player->mo->z)
{
if (*rover->topheight > player->mo->z && *rover->bottomheight < player->mo->z)
{
P_ResetPlayer(player);
S_StartSound(player->mo, sfx_s3k4a);
player->climbing = 5;
player->mo->momx = player->mo->momy = player->mo->momz = 0;
break;
}
P_ResetPlayer(player);
S_StartSound(player->mo, sfx_s3k4a);
player->climbing = 5;
player->mo->momx = player->mo->momy = player->mo->momz = 0;
break;
}
}
}
if (player->mo->z+player->mo->height > node->m_sector->ceilingheight
floorz = P_GetFloorZ(player->mo, node->m_sector, player->mo->x, player->mo->y, NULL);
ceilingz = P_GetCeilingZ(player->mo, node->m_sector, player->mo->x, player->mo->y, NULL);
if (player->mo->z+player->mo->height > ceilingz
&& node->m_sector->ceilingpic == skyflatnum)
continue;
if (node->m_sector->floorheight > player->mo->z
|| node->m_sector->ceilingheight < player->mo->z)
if (floorz > player->mo->z || ceilingz < player->mo->z)
{
P_ResetPlayer(player);
S_StartSound(player->mo, sfx_s3k4a);
@ -7053,7 +7057,6 @@ static void P_DoZoomTube(player_t *player)
mobj_t *waypoint = NULL;
fixed_t dist;
boolean reverse;
fixed_t speedx,speedy,speedz;
player->mo->height = P_GetPlayerSpinHeight(player);
@ -7074,17 +7077,17 @@ static void P_DoZoomTube(player_t *player)
if (dist < 1)
dist = 1;
speedx = FixedMul(FixedDiv(player->mo->tracer->x - player->mo->x, dist), (speed));
speedy = FixedMul(FixedDiv(player->mo->tracer->y - player->mo->y, dist), (speed));
speedz = FixedMul(FixedDiv(player->mo->tracer->z - player->mo->z, dist), (speed));
player->mo->momx = FixedMul(FixedDiv(player->mo->tracer->x - player->mo->x, dist), (speed));
player->mo->momy = FixedMul(FixedDiv(player->mo->tracer->y - player->mo->y, dist), (speed));
player->mo->momz = FixedMul(FixedDiv(player->mo->tracer->z - player->mo->z, dist), (speed));
// Calculate the distance between the player and the waypoint
// 'dist' already equals this.
// Will the player be FURTHER away if the momx/momy/momz is added to
// his current coordinates, or closer? (shift down to fracunits to avoid approximation errors)
if (dist>>FRACBITS <= P_AproxDistance(P_AproxDistance(player->mo->tracer->x - player->mo->x - speedx, player->mo->tracer->y - player->mo->y - speedy), player->mo->tracer->z - player->mo->z - speedz)>>FRACBITS)
// Will the player go past the waypoint?
if (speed > dist)
{
speed -= dist;
// If further away, set XYZ of player to waypoint location
P_UnsetThingPosition(player->mo);
player->mo->x = player->mo->tracer->x;
@ -7124,14 +7127,9 @@ static void P_DoZoomTube(player_t *player)
{
CONS_Debug(DBG_GAMELOGIC, "Found waypoint (sequence %d, number %d).\n", waypoint->threshold, waypoint->health);
// calculate MOMX/MOMY/MOMZ for next waypoint
// change angle
player->mo->angle = R_PointToAngle2(player->mo->x, player->mo->y, player->mo->tracer->x, player->mo->tracer->y);
P_SetTarget(&player->mo->tracer, waypoint);
if (player == &players[consoleplayer])
localangle = player->mo->angle;
else if (player == &players[secondarydisplayplayer])
localangle2 = player->mo->angle;
// calculate MOMX/MOMY/MOMZ for next waypoint
// change slope
dist = P_AproxDistance(P_AproxDistance(player->mo->tracer->x - player->mo->x, player->mo->tracer->y - player->mo->y), player->mo->tracer->z - player->mo->z);
@ -7142,22 +7140,14 @@ static void P_DoZoomTube(player_t *player)
player->mo->momx = FixedMul(FixedDiv(player->mo->tracer->x - player->mo->x, dist), (speed));
player->mo->momy = FixedMul(FixedDiv(player->mo->tracer->y - player->mo->y, dist), (speed));
player->mo->momz = FixedMul(FixedDiv(player->mo->tracer->z - player->mo->z, dist), (speed));
P_SetTarget(&player->mo->tracer, waypoint);
}
else
{
P_SetTarget(&player->mo->tracer, NULL); // Else, we just let him fly.
P_SetTarget(&player->mo->tracer, NULL); // Else, we just let them fly.
CONS_Debug(DBG_GAMELOGIC, "Next waypoint not found, releasing from track...\n");
}
}
else
{
player->mo->momx = speedx;
player->mo->momy = speedy;
player->mo->momz = speedz;
}
// change angle
if (player->mo->tracer)
@ -7185,24 +7175,10 @@ static void P_DoRopeHang(player_t *player)
mobj_t *mo2;
mobj_t *waypoint = NULL;
fixed_t dist;
fixed_t speedx,speedy,speedz;
fixed_t playerz;
player->mo->height = P_GetPlayerHeight(player);
if (player->cmd.buttons & BT_USE && !(player->pflags & PF_STASIS)) // Drop off of the rope
{
P_SetTarget(&player->mo->tracer, NULL);
player->pflags |= PF_JUMPED;
player->pflags &= ~PF_ROPEHANG;
if (!(player->pflags & PF_SLIDING) && (player->pflags & PF_JUMPED)
&& !(player->panim == PA_ROLL) && player->charability2 == CA2_SPINDASH)
P_SetPlayerMobjState(player->mo, S_PLAY_ATK1);
return;
}
// Play the 'clink' sound only if the player is moving.
if (!(leveltime & 7) && player->speed)
S_StartSound(player->mo, sfx_s3k55);
@ -7219,9 +7195,22 @@ static void P_DoRopeHang(player_t *player)
if (dist < 1)
dist = 1;
speedx = FixedMul(FixedDiv(player->mo->tracer->x - player->mo->x, dist), (speed));
speedy = FixedMul(FixedDiv(player->mo->tracer->y - player->mo->y, dist), (speed));
speedz = FixedMul(FixedDiv(player->mo->tracer->z - playerz, dist), (speed));
player->mo->momx = FixedMul(FixedDiv(player->mo->tracer->x - player->mo->x, dist), (speed));
player->mo->momy = FixedMul(FixedDiv(player->mo->tracer->y - player->mo->y, dist), (speed));
player->mo->momz = FixedMul(FixedDiv(player->mo->tracer->z - playerz, dist), (speed));
if (player->cmd.buttons & BT_USE && !(player->pflags & PF_STASIS)) // Drop off of the rope
{
P_SetTarget(&player->mo->tracer, NULL);
player->pflags |= PF_JUMPED;
player->pflags &= ~PF_ROPEHANG;
if (!(player->pflags & PF_SLIDING) && (player->pflags & PF_JUMPED)
&& !(player->panim == PA_ROLL) && player->charability2 == CA2_SPINDASH)
P_SetPlayerMobjState(player->mo, S_PLAY_ATK1);
return;
}
// If not allowed to move, we're done here.
if (!speed)
@ -7230,15 +7219,16 @@ static void P_DoRopeHang(player_t *player)
// Calculate the distance between the player and the waypoint
// 'dist' already equals this.
// Will the player be FURTHER away if the momx/momy/momz is added to
// his current coordinates, or closer? (shift down to fracunits to avoid approximation errors)
if (dist>>FRACBITS <= P_AproxDistance(P_AproxDistance(player->mo->tracer->x - player->mo->x - speedx, player->mo->tracer->y - player->mo->y - speedy), player->mo->tracer->z - playerz - speedz)>>FRACBITS)
// Will the player go past the waypoint?
if (speed > dist)
{
speed -= dist;
// If further away, set XYZ of player to waypoint location
P_UnsetThingPosition(player->mo);
player->mo->x = player->mo->tracer->x;
player->mo->y = player->mo->tracer->y;
player->mo->z = player->mo->tracer->z - player->mo->height;
playerz = player->mo->tracer->z;
P_SetThingPosition(player->mo);
CONS_Debug(DBG_GAMELOGIC, "Looking for next waypoint...\n");
@ -7294,6 +7284,8 @@ static void P_DoRopeHang(player_t *player)
{
CONS_Debug(DBG_GAMELOGIC, "Found waypoint (sequence %d, number %d).\n", waypoint->threshold, waypoint->health);
P_SetTarget(&player->mo->tracer, waypoint);
// calculate MOMX/MOMY/MOMZ for next waypoint
// change slope
dist = P_AproxDistance(P_AproxDistance(player->mo->tracer->x - player->mo->x, player->mo->tracer->y - player->mo->y), player->mo->tracer->z - playerz);
@ -7304,8 +7296,6 @@ static void P_DoRopeHang(player_t *player)
player->mo->momx = FixedMul(FixedDiv(player->mo->tracer->x - player->mo->x, dist), (speed));
player->mo->momy = FixedMul(FixedDiv(player->mo->tracer->y - player->mo->y, dist), (speed));
player->mo->momz = FixedMul(FixedDiv(player->mo->tracer->z - playerz, dist), (speed));
P_SetTarget(&player->mo->tracer, waypoint);
}
else
{
@ -7324,12 +7314,6 @@ static void P_DoRopeHang(player_t *player)
CONS_Debug(DBG_GAMELOGIC, "Next waypoint not found!\n");
}
}
else
{
player->mo->momx = speedx;
player->mo->momy = speedy;
player->mo->momz = speedz;
}
}
#if 0

View file

@ -210,7 +210,7 @@ void R_PortalClearClipSegs(INT32 start, INT32 end)
//
// It assumes that Doom has already ruled out a door being closed because
// of front-back closure (e.g. front floor is taller than back ceiling).
static inline INT32 R_DoorClosed(void)
static INT32 R_DoorClosed(void)
{
return
@ -859,6 +859,7 @@ static void R_Subsector(size_t num)
static sector_t tempsec; // Deep water hack
extracolormap_t *floorcolormap;
extracolormap_t *ceilingcolormap;
fixed_t floorcenterz, ceilingcenterz;
#ifdef RANGECHECK
if (num >= numsubsectors)
@ -879,6 +880,18 @@ static void R_Subsector(size_t num)
floorcolormap = ceilingcolormap = frontsector->extra_colormap;
floorcenterz =
#ifdef ESLOPE
frontsector->f_slope ? P_GetZAt(frontsector->f_slope, frontsector->soundorg.x, frontsector->soundorg.y) :
#endif
frontsector->floorheight;
ceilingcenterz =
#ifdef ESLOPE
frontsector->c_slope ? P_GetZAt(frontsector->c_slope, frontsector->soundorg.x, frontsector->soundorg.y) :
#endif
frontsector->ceilingheight;
// Check and prep all 3D floors. Set the sector floor/ceiling light levels and colormaps.
if (frontsector->ffloors)
{
@ -891,19 +904,11 @@ static void R_Subsector(size_t num)
sub->sector->moved = frontsector->moved = false;
}
light = R_GetPlaneLight(frontsector,
#ifdef ESLOPE
frontsector->f_slope ? P_GetZAt(frontsector->f_slope, frontsector->soundorg.x, frontsector->soundorg.y) :
#endif
frontsector->floorheight, false);
light = R_GetPlaneLight(frontsector, floorcenterz, false);
if (frontsector->floorlightsec == -1)
floorlightlevel = *frontsector->lightlist[light].lightlevel;
floorcolormap = frontsector->lightlist[light].extra_colormap;
light = R_GetPlaneLight(frontsector,
#ifdef ESLOPE
frontsector->c_slope ? P_GetZAt(frontsector->c_slope, frontsector->soundorg.x, frontsector->soundorg.y) :
#endif
frontsector->ceilingheight, false);
light = R_GetPlaneLight(frontsector, ceilingcenterz, false);
if (frontsector->ceilinglightsec == -1)
ceilinglightlevel = *frontsector->lightlist[light].lightlevel;
ceilingcolormap = frontsector->lightlist[light].extra_colormap;
@ -920,6 +925,9 @@ static void R_Subsector(size_t num)
{
floorplane = R_FindPlane(frontsector->floorheight, frontsector->floorpic, floorlightlevel,
frontsector->floor_xoffs, frontsector->floor_yoffs, frontsector->floorpic_angle, floorcolormap, NULL
#ifdef POLYOBJECTS_PLANES
, NULL
#endif
#ifdef ESLOPE
, frontsector->f_slope
#endif
@ -939,6 +947,9 @@ static void R_Subsector(size_t num)
ceilingplane = R_FindPlane(frontsector->ceilingheight, frontsector->ceilingpic,
ceilinglightlevel, frontsector->ceiling_xoffs, frontsector->ceiling_yoffs, frontsector->ceilingpic_angle,
ceilingcolormap, NULL
#ifdef POLYOBJECTS_PLANES
, NULL
#endif
#ifdef ESLOPE
, frontsector->c_slope
#endif
@ -956,7 +967,7 @@ static void R_Subsector(size_t num)
if (frontsector->ffloors)
{
ffloor_t *rover;
fixed_t heightcheck, planecenterz, floorcenterz, ceilingcenterz;
fixed_t heightcheck, planecenterz;
for (rover = frontsector->ffloors; rover && numffloors < MAXFFLOORS; rover = rover->next)
{
@ -975,18 +986,6 @@ static void R_Subsector(size_t num)
ffloor[numffloors].plane = NULL;
ffloor[numffloors].polyobj = NULL;
floorcenterz =
#ifdef ESLOPE
frontsector->f_slope ? P_GetZAt(frontsector->f_slope, frontsector->soundorg.x, frontsector->soundorg.y) :
#endif
frontsector->floorheight;
ceilingcenterz =
#ifdef ESLOPE
frontsector->c_slope ? P_GetZAt(frontsector->c_slope, frontsector->soundorg.x, frontsector->soundorg.y) :
#endif
frontsector->ceilingheight;
heightcheck =
#ifdef ESLOPE
*rover->b_slope ? P_GetZAt(*rover->b_slope, viewx, viewy) :
@ -1009,6 +1008,9 @@ static void R_Subsector(size_t num)
ffloor[numffloors].plane = R_FindPlane(*rover->bottomheight, *rover->bottompic,
*frontsector->lightlist[light].lightlevel, *rover->bottomxoffs,
*rover->bottomyoffs, *rover->bottomangle, frontsector->lightlist[light].extra_colormap, rover
#ifdef POLYOBJECTS_PLANES
, NULL
#endif
#ifdef ESLOPE
, *rover->b_slope
#endif
@ -1052,6 +1054,9 @@ static void R_Subsector(size_t num)
ffloor[numffloors].plane = R_FindPlane(*rover->topheight, *rover->toppic,
*frontsector->lightlist[light].lightlevel, *rover->topxoffs, *rover->topyoffs, *rover->topangle,
frontsector->lightlist[light].extra_colormap, rover
#ifdef POLYOBJECTS_PLANES
, NULL
#endif
#ifdef ESLOPE
, *rover->t_slope
#endif
@ -1093,8 +1098,8 @@ static void R_Subsector(size_t num)
polysec = po->lines[0]->backsector;
ffloor[numffloors].plane = NULL;
if (polysec->floorheight <= frontsector->ceilingheight
&& polysec->floorheight >= frontsector->floorheight
if (polysec->floorheight <= ceilingcenterz
&& polysec->floorheight >= floorcenterz
&& (viewz < polysec->floorheight))
{
fixed_t xoff, yoff;
@ -1118,11 +1123,13 @@ static void R_Subsector(size_t num)
polysec->floorpic_angle-po->angle,
NULL,
NULL
#ifdef POLYOBJECTS_PLANES
, po
#endif
#ifdef ESLOPE
, NULL // will ffloors be slopable eventually?
#endif
);
//ffloor[numffloors].plane->polyobj = po;
ffloor[numffloors].height = polysec->floorheight;
ffloor[numffloors].polyobj = po;
@ -1139,8 +1146,8 @@ static void R_Subsector(size_t num)
ffloor[numffloors].plane = NULL;
if (polysec->ceilingheight >= frontsector->floorheight
&& polysec->ceilingheight <= frontsector->ceilingheight
if (polysec->ceilingheight >= floorcenterz
&& polysec->ceilingheight <= ceilingcenterz
&& (viewz > polysec->ceilingheight))
{
fixed_t xoff, yoff;
@ -1162,11 +1169,13 @@ static void R_Subsector(size_t num)
ffloor[numffloors].plane = R_FindPlane(polysec->ceilingheight, polysec->ceilingpic,
polysec->lightlevel, xoff, yoff, polysec->ceilingpic_angle-po->angle,
NULL, NULL
#ifdef POLYOBJECTS_PLANES
, po
#endif
#ifdef ESLOPE
, NULL // will ffloors be slopable eventually?
#endif
);
//ffloor[numffloors].plane->polyobj = po;
ffloor[numffloors].polyobj = po;
ffloor[numffloors].height = polysec->ceilingheight;

View file

@ -303,6 +303,32 @@ done:
return blocktex;
}
//
// R_GetTextureNum
//
// Returns the actual texture id that we should use.
// This can either be texnum, the current frame for texnum's anim (if animated),
// or 0 if not valid.
//
INT32 R_GetTextureNum(INT32 texnum)
{
if (texnum < 0 || texnum >= numtextures)
return 0;
return texturetranslation[texnum];
}
//
// R_CheckTextureCache
//
// Use this if you need to make sure the texture is cached before R_GetColumn calls
// e.g.: midtextures and FOF walls
//
void R_CheckTextureCache(INT32 tex)
{
if (!texturecache[tex])
R_GenerateTexture(tex);
}
//
// R_GetColumn
//
@ -1499,6 +1525,9 @@ void R_InitData(void)
CONS_Printf("R_LoadTextures()...\n");
R_LoadTextures();
CONS_Printf("P_InitPicAnims()...\n");
P_InitPicAnims();
CONS_Printf("R_InitSprites()...\n");
R_InitSpriteLumps();
R_InitSprites();

View file

@ -65,6 +65,9 @@ extern CV_PossibleValue_t Color_cons_t[];
void R_LoadTextures(void);
void R_FlushTextureCache(void);
INT32 R_GetTextureNum(INT32 texnum);
void R_CheckTextureCache(INT32 tex);
// Retrieve column data for span blitting.
UINT8 *R_GetColumn(fixed_t tex, INT32 col);

View file

@ -203,6 +203,7 @@ typedef struct r_lightlist_s
fixed_t heightstep;
fixed_t botheight;
fixed_t botheightstep;
fixed_t startheight; // for repeating midtextures
INT16 lightlevel;
extracolormap_t *extra_colormap;
lighttable_t *rcolormap;
@ -224,15 +225,6 @@ typedef struct linechain_s
// ZDoom C++ to Legacy C conversion Tails 04-29-2002 (for slopes)
typedef struct secplane_t
{
// the plane is defined as a*x + b*y + c*z + d = 0
// ic is 1/c, for faster Z calculations
fixed_t a, b, c, d, ic;
} secplane_t;
// Slopes
#ifdef ESLOPE
typedef enum {
@ -392,6 +384,7 @@ typedef struct sector_s
#endif
// these are saved for netgames, so do not let Lua touch these!
INT32 spawn_nexttag, spawn_firsttag; // the actual nexttag/firsttag values may differ if the sector's tag was changed
// offsets sector spawned with (via linedef type 7)
fixed_t spawn_flr_xoffs, spawn_flr_yoffs;

View file

@ -366,69 +366,6 @@ fixed_t R_PointToDist(fixed_t x, fixed_t y)
return R_PointToDist2(viewx, viewy, x, y);
}
/***************************************
*** Zdoom C++ to Legacy C conversion ***
****************************************/
// Utility to find the Z height at an XY location in a sector (for slopes)
fixed_t R_SecplaneZatPoint(secplane_t *secplane, fixed_t x, fixed_t y)
{
return FixedMul(secplane->ic, -secplane->d - DMulScale16(secplane->a, x, secplane->b, y));
}
// Returns the value of z at (x,y) if d is equal to dist
fixed_t R_SecplaneZatPointDist (secplane_t *secplane, fixed_t x, fixed_t y, fixed_t dist)
{
return FixedMul(secplane->ic, -dist - DMulScale16(secplane->a, x, secplane->b, y));
}
// Flips the plane's vertical orientiation, so that if it pointed up,
// it will point down, and vice versa.
void R_SecplaneFlipVert(secplane_t *secplane)
{
secplane->a = -secplane->a;
secplane->b = -secplane->b;
secplane->c = -secplane->c;
secplane->d = -secplane->d;
secplane->ic = -secplane->ic;
}
// Returns true if 2 planes are the same
boolean R_ArePlanesSame(secplane_t *original, secplane_t *other)
{
return original->a == other->a && original->b == other->b
&& original->c == other->c && original->d == other->d;
}
// Returns true if 2 planes are different
boolean R_ArePlanesDifferent(secplane_t *original, secplane_t *other)
{
return original->a != other->a || original->b != other->b
|| original->c != other->c || original->d != other->d;
}
// Moves a plane up/down by hdiff units
void R_SecplaneChangeHeight(secplane_t *secplane, fixed_t hdiff)
{
secplane->d = secplane->d - FixedMul(hdiff, secplane->c);
}
// Returns how much this plane's height would change if d were set to oldd
fixed_t R_SecplaneHeightDiff(secplane_t *secplane, fixed_t oldd)
{
return FixedMul(oldd - secplane->d, secplane->ic);
}
fixed_t R_SecplanePointToDist(secplane_t *secplane, fixed_t x, fixed_t y, fixed_t z)
{
return -TMulScale16(secplane->a, x, y, secplane->b, z, secplane->c);
}
fixed_t R_SecplanePointToDist2(secplane_t *secplane, fixed_t x, fixed_t y, fixed_t z)
{
return -TMulScale16(secplane->a, x, secplane->b, y, z, secplane->c);
}
//
// R_ScaleFromGlobalAngle
// Returns the texture mapping scale for the current line (horizontal span)
@ -795,7 +732,8 @@ subsector_t *R_IsPointInSubsector(fixed_t x, fixed_t y)
ret = &subsectors[nodenum & ~NF_SUBSECTOR];
for (i = 0; i < ret->numlines; i++)
if (R_PointOnSegSide(x, y, &segs[ret->firstline + i]))
//if (R_PointOnSegSide(x, y, &segs[ret->firstline + i])) -- breaks in ogl because polyvertex_t cast over vertex pointers
if (P_PointOnLineSide(x, y, segs[ret->firstline + i].linedef) != segs[ret->firstline + i].side)
return 0;
return ret;

View file

@ -61,18 +61,6 @@ angle_t R_PointToAngle2(fixed_t px2, fixed_t py2, fixed_t px1, fixed_t py1);
fixed_t R_PointToDist(fixed_t x, fixed_t y);
fixed_t R_PointToDist2(fixed_t px2, fixed_t py2, fixed_t px1, fixed_t py1);
// ZDoom C++ to Legacy C conversion Tails 04-29-2002
fixed_t R_SecplaneZatPoint(secplane_t *secplane, fixed_t x, fixed_t y);
fixed_t R_SecplaneZatPointDist(secplane_t *secplane, fixed_t x, fixed_t y,
fixed_t dist);
void R_SecplaneFlipVert(secplane_t *secplane);
boolean R_ArePlanesSame(secplane_t *original, secplane_t *other);
boolean R_ArePlanesDifferent(secplane_t *original, secplane_t *other);
void R_SecplaneChangeHeight(secplane_t *secplane, fixed_t hdiff);
fixed_t R_SecplaneHeightDiff(secplane_t *secplane, fixed_t oldd);
fixed_t R_SecplanePointToDist(secplane_t *secplane, fixed_t x, fixed_t y, fixed_t z);
fixed_t R_SecplanePointToDist2(secplane_t *secplane, fixed_t x, fixed_t y, fixed_t z);
fixed_t R_ScaleFromGlobalAngle(angle_t visangle);
subsector_t *R_PointInSubsector(fixed_t x, fixed_t y);
subsector_t *R_IsPointInSubsector(fixed_t x, fixed_t y);

View file

@ -431,6 +431,9 @@ static visplane_t *new_visplane(unsigned hash)
visplane_t *R_FindPlane(fixed_t height, INT32 picnum, INT32 lightlevel,
fixed_t xoff, fixed_t yoff, angle_t plangle, extracolormap_t *planecolormap,
ffloor_t *pfloor
#ifdef POLYOBJECTS_PLANES
, polyobj_t *polyobj
#endif
#ifdef ESLOPE
, pslope_t *slope
#endif
@ -470,6 +473,8 @@ visplane_t *R_FindPlane(fixed_t height, INT32 picnum, INT32 lightlevel,
#ifdef POLYOBJECTS_PLANES
if (check->polyobj && pfloor)
continue;
if (polyobj != check->polyobj)
continue;
#endif
if (height == check->height && picnum == check->picnum
&& lightlevel == check->lightlevel
@ -504,7 +509,7 @@ visplane_t *R_FindPlane(fixed_t height, INT32 picnum, INT32 lightlevel,
check->viewangle = viewangle;
check->plangle = plangle;
#ifdef POLYOBJECTS_PLANES
check->polyobj = NULL;
check->polyobj = polyobj;
#endif
#ifdef ESLOPE
check->slope = slope;
@ -719,7 +724,11 @@ void R_DrawPlanes(void)
continue;
}
if (pl->ffloor != NULL)
if (pl->ffloor != NULL
#ifdef POLYOBJECTS_PLANES
|| pl->polyobj != NULL
#endif
)
continue;
R_DrawSinglePlane(pl);

View file

@ -97,6 +97,9 @@ void R_MakeSpans(INT32 x, INT32 t1, INT32 b1, INT32 t2, INT32 b2);
void R_DrawPlanes(void);
visplane_t *R_FindPlane(fixed_t height, INT32 picnum, INT32 lightlevel, fixed_t xoff, fixed_t yoff, angle_t plangle,
extracolormap_t *planecolormap, ffloor_t *ffloor
#ifdef POLYOBJECTS_PLANES
, polyobj_t *polyobj
#endif
#ifdef ESLOPE
, pslope_t *slope
#endif

View file

@ -300,7 +300,7 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2)
curline = ds->curline;
frontsector = curline->frontsector;
backsector = curline->backsector;
texnum = texturetranslation[curline->sidedef->midtexture];
texnum = R_GetTextureNum(curline->sidedef->midtexture);
windowbottom = windowtop = sprbotscreen = INT32_MAX;
// hack translucent linedef types (900-909 for transtables 1-9)
@ -344,6 +344,9 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2)
rw_scalestep = ds->scalestep;
spryscale = ds->scale1 + (x1 - ds->x1)*rw_scalestep;
// Texture must be cached before setting colfunc_2s,
// otherwise texture[texnum]->holes may be false when it shouldn't be
R_CheckTextureCache(texnum);
// handle case where multipatch texture is drawn on a 2sided wall, multi-patch textures
// are not stored per-column with post info in SRB2
if (textures[texnum]->holes)
@ -391,6 +394,7 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2)
rlight->height = (centeryfrac) - FixedMul((light->height - viewz), spryscale);
rlight->heightstep = -FixedMul(rw_scalestep, (light->height - viewz));
#endif
rlight->startheight = rlight->height; // keep starting value here to reset for each repeat
rlight->lightlevel = *light->lightlevel;
rlight->extra_colormap = light->extra_colormap;
rlight->flags = light->flags;
@ -484,6 +488,14 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2)
{
rw_scalestep = ds->scalestep;
spryscale = ds->scale1 + (x1 - ds->x1)*rw_scalestep;
if (dc_numlights)
{ // reset all lights to their starting heights
for (i = 0; i < dc_numlights; i++)
{
rlight = &dc_lightlist[i];
rlight->height = rlight->startheight;
}
}
}
#ifndef ESLOPE
@ -694,10 +706,13 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2)
// Loop through R_DrawMaskedColumn calls
static void R_DrawRepeatMaskedColumn(column_t *col)
{
do {
while (sprtopscreen < sprbotscreen) {
R_DrawMaskedColumn(col);
sprtopscreen += dc_texheight*spryscale;
} while (sprtopscreen < sprbotscreen);
if ((INT64)sprtopscreen + dc_texheight*spryscale > (INT64)INT32_MAX) // prevent overflow
sprtopscreen = INT32_MAX;
else
sprtopscreen += dc_texheight*spryscale;
}
}
//
@ -740,7 +755,7 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
curline = ds->curline;
backsector = pfloor->target;
frontsector = curline->frontsector == pfloor->target ? curline->backsector : curline->frontsector;
texnum = texturetranslation[sides[pfloor->master->sidenum[0]].midtexture];
texnum = R_GetTextureNum(sides[pfloor->master->sidenum[0]].midtexture);
colfunc = wallcolfunc;
@ -748,7 +763,7 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
{
size_t linenum = curline->linedef-backsector->lines[0];
newline = pfloor->master->frontsector->lines[0] + linenum;
texnum = texturetranslation[sides[newline->sidenum[0]].midtexture];
texnum = R_GetTextureNum(sides[newline->sidenum[0]].midtexture);
}
if (pfloor->flags & FF_TRANSLUCENT)
@ -968,6 +983,9 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
dc_texturemid += offsetvalue;
// Texture must be cached before setting colfunc_2s,
// otherwise texture[texnum]->holes may be false when it shouldn't be
R_CheckTextureCache(texnum);
//faB: handle case where multipatch texture is drawn on a 2sided wall, multi-patch textures
// are not stored per-column with post info anymore in Doom Legacy
if (textures[texnum]->holes)
@ -1878,14 +1896,16 @@ void R_StoreWallRange(INT32 start, INT32 stop)
if (!backsector)
{
fixed_t texheight;
// single sided line
midtexture = texturetranslation[sidedef->midtexture];
midtexture = R_GetTextureNum(sidedef->midtexture);
texheight = textureheight[midtexture];
// a single sided line is terminal, so it must mark ends
markfloor = markceiling = true;
#ifdef ESLOPE
if (linedef->flags & ML_EFFECT2) {
if (linedef->flags & ML_DONTPEGBOTTOM)
rw_midtexturemid = frontsector->floorheight + textureheight[sidedef->midtexture] - viewz;
rw_midtexturemid = frontsector->floorheight + texheight - viewz;
else
rw_midtexturemid = frontsector->ceilingheight - viewz;
}
@ -1894,10 +1914,10 @@ void R_StoreWallRange(INT32 start, INT32 stop)
if (linedef->flags & ML_DONTPEGBOTTOM)
{
#ifdef ESLOPE
rw_midtexturemid = worldbottom + textureheight[sidedef->midtexture];
rw_midtexturemid = worldbottom + texheight;
rw_midtextureslide = floorfrontslide;
#else
vtop = frontsector->floorheight + textureheight[sidedef->midtexture];
vtop = frontsector->floorheight + texheight;
// bottom of texture at bottom
rw_midtexturemid = vtop - viewz;
#endif
@ -2129,76 +2149,50 @@ void R_StoreWallRange(INT32 start, INT32 stop)
#endif
)
{
fixed_t texheight;
// top texture
if ((linedef->flags & (ML_DONTPEGTOP) && (linedef->flags & ML_DONTPEGBOTTOM))
&& linedef->sidenum[1] != 0xffff)
{
// Special case... use offsets from 2nd side but only if it has a texture.
side_t *def = &sides[linedef->sidenum[1]];
toptexture = texturetranslation[def->toptexture];
toptexture = R_GetTextureNum(def->toptexture);
if (!toptexture) //Second side has no texture, use the first side's instead.
toptexture = texturetranslation[sidedef->toptexture];
#ifdef ESLOPE
if (!(linedef->flags & ML_EFFECT1)) { // Ignore slopes for lower/upper textures unless flag is checked
if (linedef->flags & ML_DONTPEGTOP)
rw_toptexturemid = frontsector->ceilingheight - viewz;
else
rw_toptexturemid = backsector->ceilingheight - viewz;
} else
#endif
if (linedef->flags & ML_DONTPEGTOP)
{
// top of texture at top
rw_toptexturemid = worldtop;
#ifdef ESLOPE
rw_toptextureslide = ceilingfrontslide;
#endif
}
else
{
#ifdef ESLOPE
rw_toptexturemid = worldhigh + textureheight[def->toptexture];
rw_toptextureslide = ceilingbackslide;
#else
vtop = backsector->ceilingheight + textureheight[def->toptexture];
// bottom of texture
rw_toptexturemid = vtop - viewz;
#endif
}
toptexture = R_GetTextureNum(sidedef->toptexture);
texheight = textureheight[toptexture];
}
else
{
toptexture = texturetranslation[sidedef->toptexture];
toptexture = R_GetTextureNum(sidedef->toptexture);
texheight = textureheight[toptexture];
}
#ifdef ESLOPE
if (!(linedef->flags & ML_EFFECT1)) { // Ignore slopes for lower/upper textures unless flag is checked
if (linedef->flags & ML_DONTPEGTOP)
rw_toptexturemid = frontsector->ceilingheight - viewz;
else
rw_toptexturemid = backsector->ceilingheight - viewz;
} else
#endif
if (!(linedef->flags & ML_EFFECT1)) { // Ignore slopes for lower/upper textures unless flag is checked
if (linedef->flags & ML_DONTPEGTOP)
{
// top of texture at top
rw_toptexturemid = worldtop;
#ifdef ESLOPE
rw_toptextureslide = ceilingfrontslide;
#endif
}
rw_toptexturemid = frontsector->ceilingheight - viewz;
else
{
#ifdef ESLOPE
rw_toptexturemid = worldhigh + textureheight[sidedef->toptexture];
rw_toptextureslide = ceilingbackslide;
#else
vtop = backsector->ceilingheight + textureheight[sidedef->toptexture];
// bottom of texture
rw_toptexturemid = vtop - viewz;
rw_toptexturemid = backsector->ceilingheight - viewz;
} else
#endif
if (linedef->flags & ML_DONTPEGTOP)
{
// top of texture at top
rw_toptexturemid = worldtop;
#ifdef ESLOPE
rw_toptextureslide = ceilingfrontslide;
#endif
}
else
{
#ifdef ESLOPE
rw_toptexturemid = worldhigh + texheight;
rw_toptextureslide = ceilingbackslide;
#else
vtop = backsector->ceilingheight + texheight;
// bottom of texture
rw_toptexturemid = vtop - viewz;
#endif
}
}
}
// check BOTTOM TEXTURE
@ -2209,7 +2203,7 @@ void R_StoreWallRange(INT32 start, INT32 stop)
) //seulement si VISIBLE!!!
{
// bottom texture
bottomtexture = texturetranslation[sidedef->bottomtexture];
bottomtexture = R_GetTextureNum(sidedef->bottomtexture);
#ifdef ESLOPE
if (!(linedef->flags & ML_EFFECT1)) { // Ignore slopes for lower/upper textures unless flag is checked
@ -2494,7 +2488,7 @@ void R_StoreWallRange(INT32 start, INT32 stop)
ds_p->numthicksides = numthicksides = i;
}
if (sidedef->midtexture)
if (sidedef->midtexture > 0 && sidedef->midtexture < numtextures)
{
// masked midtexture
if (!ds_p->thicksidecol)
@ -3101,12 +3095,12 @@ void R_StoreWallRange(INT32 start, INT32 stop)
if (maskedtexture && !(ds_p->silhouette & SIL_TOP))
{
ds_p->silhouette |= SIL_TOP;
ds_p->tsilheight = sidedef->midtexture ? INT32_MIN: INT32_MAX;
ds_p->tsilheight = (sidedef->midtexture > 0 && sidedef->midtexture < numtextures) ? INT32_MIN: INT32_MAX;
}
if (maskedtexture && !(ds_p->silhouette & SIL_BOTTOM))
{
ds_p->silhouette |= SIL_BOTTOM;
ds_p->bsilheight = sidedef->midtexture ? INT32_MAX: INT32_MIN;
ds_p->bsilheight = (sidedef->midtexture > 0 && sidedef->midtexture < numtextures) ? INT32_MAX: INT32_MIN;
}
ds_p++;
}

View file

@ -943,12 +943,18 @@ static void R_DrawPrecipitationVisSprite(vissprite_t *vis)
#endif
fixed_t frac;
patch_t *patch;
INT64 overflow_test;
//Fab : R_InitSprites now sets a wad lump number
patch = W_CacheLumpNum(vis->patch, PU_CACHE);
if (!patch)
return;
// Check for overflow
overflow_test = (INT64)centeryfrac - (((INT64)vis->texturemid*vis->scale)>>FRACBITS);
if (overflow_test < 0) overflow_test = -overflow_test;
if ((UINT64)overflow_test&0xFFFFFFFF80000000ULL) return; // fixed point mult would overflow
if (vis->transmap)
{
colfunc = fuzzcolfunc;
@ -1831,21 +1837,25 @@ static void R_CreateDrawNodes(void)
entry->ffloor = ds->thicksides[i];
}
}
#ifdef POLYOBJECTS_PLANES
// Check for a polyobject plane, but only if this is a front line
if (ds->curline->polyseg && ds->curline->polyseg->visplane && !ds->curline->side) {
plane = ds->curline->polyseg->visplane;
R_PlaneBounds(plane);
if (plane->low < con_clipviewtop || plane->high > vid.height || plane->high > plane->low)
;
else {
// Put it in!
entry = R_CreateDrawNode(&nodehead);
entry->plane = plane;
entry->seg = ds;
}
ds->curline->polyseg->visplane = NULL;
}
#endif
if (ds->maskedtexturecol)
{
#ifdef POLYOBJECTS_PLANES
// Check for a polyobject plane, but only if this is a front line
if (ds->curline->polyseg && ds->curline->polyseg->visplane && !ds->curline->side) {
// Put it in!
entry = R_CreateDrawNode(&nodehead);
entry->plane = ds->curline->polyseg->visplane;
entry->seg = ds;
ds->curline->polyseg->visplane->polyobj = ds->curline->polyseg;
ds->curline->polyseg->visplane = NULL;
}
#endif
entry = R_CreateDrawNode(&nodehead);
entry->seg = ds;
}
@ -1888,6 +1898,29 @@ static void R_CreateDrawNodes(void)
}
}
#ifdef POLYOBJECTS_PLANES
// find all the remaining polyobject planes and add them on the end of the list
// probably this is a terrible idea if we wanted them to be sorted properly
// but it works getting them in for now
for (i = 0; i < numPolyObjects; i++)
{
if (!PolyObjects[i].visplane)
continue;
plane = PolyObjects[i].visplane;
R_PlaneBounds(plane);
if (plane->low < con_clipviewtop || plane->high > vid.height || plane->high > plane->low)
{
PolyObjects[i].visplane = NULL;
continue;
}
entry = R_CreateDrawNode(&nodehead);
entry->plane = plane;
// note: no seg is set, for what should be obvious reasons
PolyObjects[i].visplane = NULL;
}
#endif
if (visspritecount == 0)
return;
@ -1944,13 +1977,16 @@ static void R_CreateDrawNodes(void)
if (x1 < r2->plane->minx) x1 = r2->plane->minx;
if (x2 > r2->plane->maxx) x2 = r2->plane->maxx;
for (i = x1; i <= x2; i++)
if (r2->seg) // if no seg set, assume the whole thing is in front or something stupid
{
if (r2->seg->frontscale[i] > rover->sortscale)
break;
for (i = x1; i <= x2; i++)
{
if (r2->seg->frontscale[i] > rover->sortscale)
break;
}
if (i > x2)
continue;
}
if (i > x2)
continue;
entry = R_CreateDrawNode(NULL);
(entry->prev = r2->prev)->next = entry;

View file

@ -30,7 +30,7 @@
#include "f_finale.h"
#if defined (USEASM) //&& (!defined (_MSC_VER) || (_MSC_VER <= 1200))
#if defined (USEASM) && !defined (NORUSEASM)//&& (!defined (_MSC_VER) || (_MSC_VER <= 1200))
#define RUSEASM //MSC.NET can't patch itself
#endif

View file

@ -2647,6 +2647,47 @@ INT32 I_PutEnv(char *variable)
#endif
}
INT32 I_ClipboardCopy(const char *data, size_t size)
{
char storage[256];
if (size > 255)
size = 255;
memcpy(storage, data, size);
storage[size] = 0;
if (SDL_SetClipboardText(storage))
return 0;
return -1;
}
const char *I_ClipboardPaste(void)
{
static char clipboard_modified[256];
char *clipboard_contents, *i = clipboard_modified;
if (!SDL_HasClipboardText())
return NULL;
clipboard_contents = SDL_GetClipboardText();
memcpy(clipboard_modified, clipboard_contents, 255);
SDL_free(clipboard_contents);
clipboard_modified[255] = 0;
while (*i)
{
if (*i == '\n' || *i == '\r')
{ // End on newline
*i = 0;
break;
}
else if (*i == '\t')
*i = ' '; // Tabs become spaces
else if (*i < 32 || (unsigned)*i > 127)
*i = '?'; // Nonprintable chars become question marks
++i;
}
return (const char *)&clipboard_modified;
}
/** \brief The isWadPathOk function
\param path string path to check

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