Merge branch 'udmf-scrollers' into udmf-polyobjects

This commit is contained in:
MascaraSnake 2021-09-17 10:36:35 +02:00
commit de82afe338
83 changed files with 3730 additions and 1800 deletions

View file

@ -2,15 +2,11 @@ version: 2.2.9.{branch}-{build}
os: MinGW os: MinGW
environment: environment:
CC: ccache CC: i686-w64-mingw32-gcc
CCACHE_CC: i686-w64-mingw32-gcc
CCACHE_CC_64: x86_64-w64-mingw32-gcc
WINDRES: windres WINDRES: windres
# c:\mingw-w64 i686 has gcc 6.3.0, so use c:\msys64 7.3.0 instead # c:\mingw-w64 i686 has gcc 6.3.0, so use c:\msys64 7.3.0 instead
MINGW_SDK: c:\msys64\mingw32 MINGW_SDK: c:\msys64\mingw32
# c:\msys64 x86_64 has gcc 8.2.0, so use c:\mingw-w64 7.3.0 instead CFLAGS: -Wno-implicit-fallthrough
MINGW_SDK_64: C:\mingw-w64\x86_64-8.1.0-posix-seh-rt_v6-rev0\mingw64
CFLAGS: -Wall -W -Werror -Wno-error=implicit-fallthrough -Wimplicit-fallthrough=3 -Wno-tautological-compare -Wno-error=suggest-attribute=noreturn
NASM_ZIP: nasm-2.12.01 NASM_ZIP: nasm-2.12.01
NASM_URL: http://www.nasm.us/pub/nasm/releasebuilds/2.12.01/win64/nasm-2.12.01-win64.zip NASM_URL: http://www.nasm.us/pub/nasm/releasebuilds/2.12.01/win64/nasm-2.12.01-win64.zip
UPX_ZIP: upx391w UPX_ZIP: upx391w
@ -19,8 +15,6 @@ environment:
CCACHE_URL: http://alam.srb2.org/ccache.exe CCACHE_URL: http://alam.srb2.org/ccache.exe
CCACHE_COMPRESS: true CCACHE_COMPRESS: true
CCACHE_DIR: C:\Users\appveyor\.ccache CCACHE_DIR: C:\Users\appveyor\.ccache
# Disable UPX by default. The user can override this in their Appveyor project settings
NOUPX: 1
############################## ##############################
# DEPLOYER VARIABLES # DEPLOYER VARIABLES
# DPL_ENABLED=1 builds installers for branch names starting with `deployer`. # DPL_ENABLED=1 builds installers for branch names starting with `deployer`.
@ -53,11 +47,6 @@ cache:
- C:\Users\appveyor\srb2_cache - C:\Users\appveyor\srb2_cache
install: install:
- if [%CONFIGURATION%] == [SDL64] ( set "X86_64=1" )
- if [%CONFIGURATION%] == [SDL64] ( set "CONFIGURATION=SDL" )
- if [%X86_64%] == [1] ( set "MINGW_SDK=%MINGW_SDK_64%" )
- if [%X86_64%] == [1] ( set "CCACHE_CC=%CCACHE_CC_64%" )
- if not exist "%NASM_ZIP%.zip" appveyor DownloadFile "%NASM_URL%" -FileName "%NASM_ZIP%.zip" - if not exist "%NASM_ZIP%.zip" appveyor DownloadFile "%NASM_URL%" -FileName "%NASM_ZIP%.zip"
- 7z x -y "%NASM_ZIP%.zip" -o%TMP% >null - 7z x -y "%NASM_ZIP%.zip" -o%TMP% >null
- robocopy /S /xx /ns /nc /nfl /ndl /np /njh /njs "%TMP%\%NASM_ZIP%" "%MINGW_SDK%\bin" nasm.exe || exit 0 - robocopy /S /xx /ns /nc /nfl /ndl /np /njh /njs "%TMP%\%NASM_ZIP%" "%MINGW_SDK%\bin" nasm.exe || exit 0
@ -72,34 +61,27 @@ install:
configuration: configuration:
- SDL - SDL
- SDL64
before_build: before_build:
- set "Path=%MINGW_SDK%\bin;%Path%" - set "Path=%MINGW_SDK%\bin;%Path%"
- if [%X86_64%] == [1] ( x86_64-w64-mingw32-gcc --version ) else ( i686-w64-mingw32-gcc --version )
- mingw32-make --version - mingw32-make --version
- if not [%X86_64%] == [1] ( nasm -v ) - nasm -v
- if not [%NOUPX%] == [1] ( upx -V ) - if not [%NOUPX%] == [1] ( upx -V )
- ccache -V - ccache -V
- ccache -s - ccache -s
- if [%NOUPX%] == [1] ( set "NOUPX=NOUPX=1" ) else ( set "NOUPX=" )
- if defined [%APPVEYOR_PULL_REQUEST_HEAD_COMMIT%] ( set "COMMIT=%APPVEYOR_PULL_REQUEST_HEAD_COMMIT%" ) else ( set "COMMIT=%APPVEYOR_REPO_COMMIT%" ) - if defined [%APPVEYOR_PULL_REQUEST_HEAD_COMMIT%] ( set "COMMIT=%APPVEYOR_PULL_REQUEST_HEAD_COMMIT%" ) else ( set "COMMIT=%APPVEYOR_REPO_COMMIT%" )
- cmd: git rev-parse --short %COMMIT%>%TMP%/gitshort.txt - cmd: git rev-parse --short %COMMIT%>%TMP%/gitshort.txt
- cmd: set /P GITSHORT=<%TMP%/gitshort.txt - cmd: set /P GITSHORT=<%TMP%/gitshort.txt
# for pull requests, take the owner's name only, if this isn't the same repo of course # for pull requests, take the owner's name only, if this isn't the same repo of course
- set "REPO=%APPVEYOR_REPO_BRANCH%" - set "REPO=%APPVEYOR_REPO_BRANCH%"
- if not [%APPVEYOR_PULL_REQUEST_HEAD_REPO_NAME%] == [] ( if not [%APPVEYOR_PULL_REQUEST_HEAD_REPO_NAME%] == [%APPVEYOR_REPO_NAME%] ( for /f "delims=/" %%a in ("%APPVEYOR_PULL_REQUEST_HEAD_REPO_NAME%") do set "REPO=%%a-%APPVEYOR_PULL_REQUEST_HEAD_REPO_BRANCH%" ) ) - if not [%APPVEYOR_PULL_REQUEST_HEAD_REPO_NAME%] == [] ( if not [%APPVEYOR_PULL_REQUEST_HEAD_REPO_NAME%] == [%APPVEYOR_REPO_NAME%] ( for /f "delims=/" %%a in ("%APPVEYOR_PULL_REQUEST_HEAD_REPO_NAME%") do set "REPO=%%a-%APPVEYOR_PULL_REQUEST_HEAD_REPO_BRANCH%" ) )
- set "EXENAME=EXENAME=srb2win-%REPO%-%GITSHORT%.exe" - set "SRB2_MFLAGS=-C src NOECHOFILENAMES=1 CCACHE=1 EXENAME=srb2win-%REPO%-%GITSHORT%.exe"
- set "SRB2_MFLAGS=-C src WARNINGMODE=1 CCACHE=1 NOOBJDUMP=1 %NOUPX% %EXENAME%"
- if [%X86_64%] == [1] ( set "MINGW_FLAGS=MINGW64=1 X86_64=1 GCC81=1" ) else ( set "MINGW_FLAGS=MINGW=1 GCC91=1" )
- set "SRB2_MFLAGS=%SRB2_MFLAGS% %MINGW_FLAGS% %CONFIGURATION%=1"
build_script: build_script:
- cmd: mingw32-make.exe %SRB2_MFLAGS% clean - cmd: mingw32-make.exe %SRB2_MFLAGS% clean
- cmd: mingw32-make.exe %SRB2_MFLAGS% ERRORMODE=1 -k - cmd: mingw32-make.exe %SRB2_MFLAGS% ERRORMODE=1 -k
after_build: after_build:
- if [%X86_64%] == [1] ( set "CONFIGURATION=%CONFIGURATION%64" )
- ccache -s - ccache -s
- set BUILD_ARCHIVE=%REPO%-%GITSHORT%-%CONFIGURATION%.7z - set BUILD_ARCHIVE=%REPO%-%GITSHORT%-%CONFIGURATION%.7z
- set BUILDSARCHIVE=%REPO%-%CONFIGURATION%.7z - set BUILDSARCHIVE=%REPO%-%CONFIGURATION%.7z
@ -134,3 +116,4 @@ test: off
on_finish: on_finish:
#- cmd: echo xfreerdp /u:appveyor /cert-ignore +clipboard /v:<ip>:<port> #- cmd: echo xfreerdp /u:appveyor /cert-ignore +clipboard /v:<ip>:<port>
#- ps: $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1')) #- ps: $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))
# vim: et ts=1

View file

@ -2958,8 +2958,10 @@ linedeftypes
prefix = "(700)"; prefix = "(700)";
flags2048text = "[11] No physics"; flags2048text = "[11] No physics";
flags4096text = "[12] Dynamic"; flags4096text = "[12] Dynamic";
flags32768text = "[15] Copy to other side";
slope = "regular"; slope = "regular";
slopeargs = 1; slopeargs = 1;
copyslopeargs = 1;
} }
701 701
@ -2968,8 +2970,10 @@ linedeftypes
prefix = "(701)"; prefix = "(701)";
flags2048text = "[11] No physics"; flags2048text = "[11] No physics";
flags4096text = "[12] Dynamic"; flags4096text = "[12] Dynamic";
flags32768text = "[15] Copy to other side";
slope = "regular"; slope = "regular";
slopeargs = 2; slopeargs = 2;
copyslopeargs = 4;
} }
702 702
@ -2978,8 +2982,10 @@ linedeftypes
prefix = "(702)"; prefix = "(702)";
flags2048text = "[11] No physics"; flags2048text = "[11] No physics";
flags4096text = "[12] Dynamic"; flags4096text = "[12] Dynamic";
flags32768text = "[15] Copy to other side";
slope = "regular"; slope = "regular";
slopeargs = 3; slopeargs = 3;
copyslopeargs = 5;
} }
703 703
@ -2988,8 +2994,10 @@ linedeftypes
prefix = "(703)"; prefix = "(703)";
flags2048text = "[11] No physics"; flags2048text = "[11] No physics";
flags4096text = "[12] Dynamic"; flags4096text = "[12] Dynamic";
flags32768text = "[15] Copy to other side";
slope = "regular"; slope = "regular";
slopeargs = 9; slopeargs = 9;
copyslopeargs = 8;
} }
704 704
@ -3020,8 +3028,10 @@ linedeftypes
prefix = "(710)"; prefix = "(710)";
flags2048text = "[11] No physics"; flags2048text = "[11] No physics";
flags4096text = "[12] Dynamic"; flags4096text = "[12] Dynamic";
flags32768text = "[15] Copy to other side";
slope = "regular"; slope = "regular";
slopeargs = 4; slopeargs = 4;
copyslopeargs = 2;
} }
711 711
@ -3030,8 +3040,10 @@ linedeftypes
prefix = "(711)"; prefix = "(711)";
flags2048text = "[11] No physics"; flags2048text = "[11] No physics";
flags4096text = "[12] Dynamic"; flags4096text = "[12] Dynamic";
flags32768text = "[15] Copy to other side";
slope = "regular"; slope = "regular";
slopeargs = 8; slopeargs = 8;
copyslopeargs = 8;
} }
712 712
@ -3040,8 +3052,10 @@ linedeftypes
prefix = "(712)"; prefix = "(712)";
flags2048text = "[11] No physics"; flags2048text = "[11] No physics";
flags4096text = "[12] Dynamic"; flags4096text = "[12] Dynamic";
flags32768text = "[15] Copy to other side";
slope = "regular"; slope = "regular";
slopeargs = 12; slopeargs = 12;
copyslopeargs = 10;
} }
713 713
@ -3050,8 +3064,10 @@ linedeftypes
prefix = "(713)"; prefix = "(713)";
flags2048text = "[11] No physics"; flags2048text = "[11] No physics";
flags4096text = "[12] Dynamic"; flags4096text = "[12] Dynamic";
flags32768text = "[15] Copy to other side";
slope = "regular"; slope = "regular";
slopeargs = 6; slopeargs = 6;
copyslopeargs = 6;
} }
714 714

View file

@ -4,7 +4,7 @@ add_executable(SRB2SDL2 MACOSX_BUNDLE WIN32)
# Core sources # Core sources
target_sourcefile(c) target_sourcefile(c)
target_sources(SRB2SDL2 PRIVATE comptime.c md5.c config.h) target_sources(SRB2SDL2 PRIVATE comptime.c md5.c config.h.in)
set(SRB2_ASM_SOURCES vid_copy.s) set(SRB2_ASM_SOURCES vid_copy.s)
@ -60,7 +60,7 @@ if(${SRB2_CONFIG_HAVE_GME})
endif() endif()
if(${GME_FOUND}) if(${GME_FOUND})
set(SRB2_HAVE_GME ON) set(SRB2_HAVE_GME ON)
target_compile_definitions(SRB2SDL2 PRIVATE -DHAVE_LIBGME) target_compile_definitions(SRB2SDL2 PRIVATE -DHAVE_GME)
else() else()
message(WARNING "You have specified that GME is available but it was not found.") message(WARNING "You have specified that GME is available but it was not found.")
endif() endif()

View file

@ -132,6 +132,10 @@ goals:=$(or $(MAKECMDGOALS),all)
cleanonly:=$(filter $(clean_targets),$(goals)) cleanonly:=$(filter $(clean_targets),$(goals))
destructive:=$(filter-out info,$(cleanonly)) destructive:=$(filter-out info,$(cleanonly))
ifndef cleanonly
include Makefile.d/old.mk
endif
include Makefile.d/util.mk include Makefile.d/util.mk
ifdef PREFIX ifdef PREFIX
@ -141,7 +145,7 @@ endif
OBJDUMP_OPTS?=--wide --source --line-numbers OBJDUMP_OPTS?=--wide --source --line-numbers
OBJCOPY:=$(call Prefix,objcopy) OBJCOPY:=$(call Prefix,objcopy)
OBJDUMP:=$(call Prefix,objdump) $(OBJDUMP_OPTS) OBJDUMP:=$(call Prefix,objdump)
WINDRES:=$(call Prefix,windres) WINDRES:=$(call Prefix,windres)
ifdef YASM ifdef YASM
@ -176,11 +180,7 @@ include Makefile.d/detect.mk
# make would try to remove the implicitly made directories # make would try to remove the implicitly made directories
.PRECIOUS : %/ comptime.c .PRECIOUS : %/ comptime.c
# very sophisticated dependency sources:=
sources:=\
$(call List,Sourcefile)\
$(call List,blua/Sourcefile)\
makedir:=../make makedir:=../make
# -DCOMPVERSION: flag to use comptime.h # -DCOMPVERSION: flag to use comptime.h
@ -204,6 +204,11 @@ endif
depdir:=$(makedir)/deps depdir:=$(makedir)/deps
objdir:=$(makedir)/objs objdir:=$(makedir)/objs
# very sophisticated dependency
sources+=\
$(call List,Sourcefile)\
$(call List,blua/Sourcefile)\
depends:=$(basename $(filter %.c %.s,$(sources))) depends:=$(basename $(filter %.c %.s,$(sources)))
objects:=$(basename $(filter %.c %.s %.nas,$(sources))) objects:=$(basename $(filter %.c %.s %.nas,$(sources)))
@ -268,16 +273,18 @@ opts+=$(debug_opts)
opts+=$(foreach v,$(passthru_opts),$(if $($(v)),-D$(v))) opts+=$(foreach v,$(passthru_opts),$(if $($(v)),-D$(v)))
CFLAGS:=$(opts) $(WFLAGS) $(CPPFLAGS) $(CFLAGS) opts+=$(WFLAGS) $(CPPFLAGS) $(CFLAGS)
LDFLAGS:=$(libs) $(LDFLAGS) libs+=$(LDFLAGS)
ASFLAGS+=-x assembler-with-cpp asflags:=$(ASFLAGS) -x assembler-with-cpp
cc=$(CC)
ifdef DISTCC ifdef DISTCC
CC:=distcc $(CC) cc=distcc $(CC)
endif endif
ifdef CCACHE ifdef CCACHE
CC:=ccache $(CC) cc=ccache $(CC)
endif endif
ifndef SILENT ifndef SILENT
@ -288,11 +295,13 @@ ifndef destructive
$(shell $(CC) -v) $(shell $(CC) -v)
define flags = define flags =
CC ........ $(CC) SHELL ..... $(SHELL)
CFLAGS .... $(CFLAGS) CC ........ $(cc)
LDFLAGS ... $(LDFLAGS) CFLAGS .... $(opts)
LDFLAGS ... $(libs)
endef endef
$(info $(flags)) $(info $(flags))
@ -306,13 +315,12 @@ endif
endif endif
LD:=$(CC) LD:=$(CC)
CC:=$(CC) $(CFLAGS) cc:=$(cc) $(opts)
NASM:=$(NASM) $(NASMOPTS) -f $(nasm_format) nasm=$(NASM) $(NASMOPTS) -f $(nasm_format)
GZIP:=$(GZIP) $(GZIP_OPTS)
ifdef UPX ifdef UPX
UPX:=$(UPX) $(UPX_OPTS) upx=$(UPX) $(UPX_OPTS)
endif endif
WINDRES:=$(WINDRES) $(WINDRESFLAGS)\ windres=$(WINDRES) $(WINDRESFLAGS)\
$(debug_opts) --include-dir=win32 -O coff $(debug_opts) --include-dir=win32 -O coff
%/ : %/ :
@ -322,7 +330,7 @@ WINDRES:=$(WINDRES) $(WINDRESFLAGS)\
# prerequisites # prerequisites
.SECONDEXPANSION : .SECONDEXPANSION :
# 'UPX' is also recognized in the enviornment by upx # 'UPX' is also recognized in the environment by upx
unexport UPX unexport UPX
# executable stripped of debugging symbols # executable stripped of debugging symbols
@ -331,19 +339,19 @@ $(exe) : $(dbg) | $$(@D)/
$(.)-$(OBJCOPY) --add-gnu-debuglink=$< $@ $(.)-$(OBJCOPY) --add-gnu-debuglink=$< $@
ifdef UPX ifdef UPX
$(call Echo,Compressing final executable...) $(call Echo,Compressing final executable...)
$(.)-$(UPX) $@ $(.)-$(upx) $@
endif endif
# original executable with debugging symbols # original executable with debugging symbols
$(dbg) : $(objects) | $$(@D)/ $(dbg) : $(objects) | $$(@D)/
$(call Echo,Linking $(@F)...) $(call Echo,Linking $(@F)...)
$(.)$(LD) -o $@ $^ $(LDFLAGS) $(.)$(LD) -o $@ $^ $(libs)
# disassembly of executable # disassembly of executable
$(dbg).txt : $(dbg) $(dbg).txt : $(dbg)
$(call Echo,Dumping debugging info...) $(call Echo,Dumping debugging info...)
$(.)$(OBJDUMP) $< > $@ $(.)$(OBJDUMP) $(OBJDUMP_OPTS) $< > $@
$(.)$(GZIP) $@ $(.)$(GZIP) $(GZIP_OPTS) $@
# '::' means run unconditionally # '::' means run unconditionally
# this really updates comptime.h # this really updates comptime.h
@ -368,11 +376,11 @@ ifdef Echo_name
@printf '%-20.20s\r' $$< @printf '%-20.20s\r' $$<
endif endif
endif endif
$(.)$(CC) -MM -MF $$@ -MT $(objdir)/$$(*F).o $(2) $$< $(.)$(cc) -MM -MF $$@ -MT $(objdir)/$$*.o $(2) $$<
endef endef
$(eval $(call _recipe,c)) $(eval $(call _recipe,c))
$(eval $(call _recipe,s,$(ASFLAGS))) $(eval $(call _recipe,s,$(asflags)))
# compiling recipe template # compiling recipe template
# 1: target file suffix # 1: target file suffix
@ -384,10 +392,10 @@ $(objdir)/%.$(1) : %.$(2) | $$$$(@D)/
$(.)$(3) $(.)$(3)
endef endef
$(eval $(call _recipe,o,c,$(CC) -c -o $$@ $$<)) $(eval $(call _recipe,o,c,$(cc) -c -o $$@ $$<))
$(eval $(call _recipe,o,nas,$(NASM) -o $$@ $$<)) $(eval $(call _recipe,o,nas,$(nasm) -o $$@ $$<))
$(eval $(call _recipe,o,s,$(CC) $(ASFLAGS) -c -o $$@ $$<)) $(eval $(call _recipe,o,s,$(cc) $(asflags) -c -o $$@ $$<))
$(eval $(call _recipe,res,rc,$(WINDRES) -i $$< -o $$@)) $(eval $(call _recipe,res,rc,$(windres) -i $$< -o $$@))
_rm=$(.)$(rmrf) $(call Windows_path,$(1)) _rm=$(.)$(rmrf) $(call Windows_path,$(1))
@ -398,7 +406,7 @@ clean :
$(call _rm,$(exe) $(dbg) $(dbg).txt $(objects)) $(call _rm,$(exe) $(dbg) $(dbg).txt $(objects))
distclean : distclean :
$(call _rm,../bin ../objs ../deps comptime.h) $(call _rm,../bin ../objs ../dep ../make comptime.h)
info: info:
ifdef WINDOWSHELL ifdef WINDOWSHELL

View file

@ -29,7 +29,6 @@ $(call Print,$(_m))
# go for a 32-bit sdl mingw exe by default # go for a 32-bit sdl mingw exe by default
MINGW:=1 MINGW:=1
WINDOWSHELL:=1
else # if you on the *nix else # if you on the *nix
@ -72,13 +71,17 @@ latest_gcc_version:=10.2
# manually set. And don't bother if this is a clean only # manually set. And don't bother if this is a clean only
# run. # run.
ifeq (,$(call Wildvar,GCC% destructive)) ifeq (,$(call Wildvar,GCC% destructive))
version:=$(shell $(CC) --version)
# can't use $(CC) --version here since that uses argv[0] to display the name
# also gcc outputs the information to stderr, so I had to do 2>&1
# this program really doesn't like identifying itself
version:=$(shell $(CC) -v 2>&1)
# check if this is in fact GCC # check if this is in fact GCC
ifneq (,$(or $(findstring gcc,$(version)),\ ifneq (,$(findstring gcc version,$(version)))
$(findstring GCC,$(version))))
version:=$(shell $(CC) -dumpversion) # in stark contrast to the name, gcc will give me a nicely formatted version number for free
version:=$(shell $(CC) -dumpfullversion)
# Turn version into words of major, minor # Turn version into words of major, minor
v:=$(subst ., ,$(version)) v:=$(subst ., ,$(version))
@ -91,7 +94,7 @@ ifeq (,$(filter $(v),$(gcc_versions)))
define line = define line =
Your compiler version, GCC $(version), \ Your compiler version, GCC $(version), \
is not supported by the Makefile. is not supported by the Makefile.
The Makefile will assume GCC $(latest_gcc_version).)) The Makefile will assume GCC $(latest_gcc_version).
endef endef
$(call Print,$(line)) $(call Print,$(line))
GCC$(subst .,,$(latest_gcc_version)):=1 GCC$(subst .,,$(latest_gcc_version)):=1

16
src/Makefile.d/old.mk Normal file
View file

@ -0,0 +1,16 @@
#
# Warn about old build directories and offer to purge.
#
_old:=$(wildcard $(addprefix ../bin/,FreeBSD Linux \
Linux64 Mingw Mingw64 SDL dummy) ../objs ../dep)
ifdef _old
$(foreach v,$(_old),$(info $(abspath $(v))))
$(info )
$(info These directories are no longer\
required and should be removed.)
$(info You may remove them manually or\
by using 'make distclean')
$(error )
endif

View file

@ -7,9 +7,11 @@ PKG_CONFIG?=pkg-config
ifdef WINDOWSHELL ifdef WINDOWSHELL
rmrf=-2>NUL DEL /S /Q rmrf=-2>NUL DEL /S /Q
mkdir=-2>NUL MD mkdir=-2>NUL MD
cat=TYPE
else else
rmrf=rm -rf rmrf=rm -rf
mkdir=mkdir -p mkdir=mkdir -p
cat=cat
endif endif
ifdef LINUX64 ifdef LINUX64

View file

@ -10,7 +10,8 @@ Wildvar=$(foreach v,$(filter $(1),$(.VARIABLES)),$($(v)))
# Read a list of words from file and prepend each with the # Read a list of words from file and prepend each with the
# directory of the file. # directory of the file.
List=$(addprefix $(dir $(1)),$(file < $(1))) _cat=$(shell $(cat) $(call Windows_path,$(1)))
List=$(addprefix $(dir $(1)),$(call _cat,$(1)))
# Convert path separators to backslash on Windows. # Convert path separators to backslash on Windows.
Windows_path=$(if $(WINDOWSHELL),$(subst /,\,$(1)),$(1)) Windows_path=$(if $(WINDOWSHELL),$(subst /,\,$(1)),$(1))

View file

@ -458,7 +458,7 @@ boolean AM_Responder(event_t *ev)
{ {
if (!automapactive) if (!automapactive)
{ {
if (ev->type == ev_keydown && ev->data1 == AM_TOGGLEKEY) if (ev->type == ev_keydown && ev->key == AM_TOGGLEKEY)
{ {
//faB: prevent alt-tab in win32 version to activate automap just before //faB: prevent alt-tab in win32 version to activate automap just before
// minimizing the app; doesn't do any harm to the DOS version // minimizing the app; doesn't do any harm to the DOS version
@ -473,7 +473,7 @@ boolean AM_Responder(event_t *ev)
else if (ev->type == ev_keydown) else if (ev->type == ev_keydown)
{ {
rc = true; rc = true;
switch (ev->data1) switch (ev->key)
{ {
case AM_PANRIGHTKEY: // pan right case AM_PANRIGHTKEY: // pan right
if (!followplayer) if (!followplayer)
@ -550,7 +550,7 @@ boolean AM_Responder(event_t *ev)
else if (ev->type == ev_keyup) else if (ev->type == ev_keyup)
{ {
rc = false; rc = false;
switch (ev->data1) switch (ev->key)
{ {
case AM_PANRIGHTKEY: case AM_PANRIGHTKEY:
if (!followplayer) if (!followplayer)

View file

@ -18,29 +18,38 @@
#include "b_bot.h" #include "b_bot.h"
#include "lua_hook.h" #include "lua_hook.h"
// If you want multiple bots, variables like this will void B_UpdateBotleader(player_t *player)
// have to be stuffed in something accessible through player_t.
static boolean lastForward = false;
static boolean lastBlocked = false;
static boolean blocked = false;
static boolean jump_last = false;
static boolean spin_last = false;
static UINT8 anxiety = 0;
static boolean panic = false;
static UINT8 flymode = 0;
static boolean spinmode = false;
static boolean thinkfly = false;
static inline void B_ResetAI(void)
{ {
jump_last = false; UINT32 i;
spin_last = false; fixed_t dist;
anxiety = 0; fixed_t neardist = INT32_MAX;
panic = false; player_t *nearplayer = NULL;
flymode = 0; //Find new botleader
spinmode = false; for (i = 0; i < MAXPLAYERS; i++)
thinkfly = false; {
if (players[i].bot || players[i].playerstate != PST_LIVE || players[i].spectator || !players[i].mo)
continue;
if (!player->mo) //Can't do distance calculations if there's no player object, so we'll just take the first we find
{
player->botleader = &players[i];
return;
}
//Update best candidate based on nearest distance
dist = R_PointToDist2(player->mo->x, player->mo->y, players[i].mo->x, players[i].mo->y);
if (neardist > dist)
{
neardist = dist;
nearplayer = &players[i];
}
}
//Set botleader to best candidate (or null if none available)
player->botleader = nearplayer;
}
static inline void B_ResetAI(botmem_t *mem)
{
mem->thinkstate = AI_FOLLOW;
mem->catchup_tics = 0;
} }
static void B_BuildTailsTiccmd(mobj_t *sonic, mobj_t *tails, ticcmd_t *cmd) static void B_BuildTailsTiccmd(mobj_t *sonic, mobj_t *tails, ticcmd_t *cmd)
@ -49,39 +58,47 @@ static void B_BuildTailsTiccmd(mobj_t *sonic, mobj_t *tails, ticcmd_t *cmd)
player_t *player = sonic->player, *bot = tails->player; player_t *player = sonic->player, *bot = tails->player;
ticcmd_t *pcmd = &player->cmd; ticcmd_t *pcmd = &player->cmd;
boolean water = tails->eflags & MFE_UNDERWATER; botmem_t *mem = &bot->botmem;
boolean water = (tails->eflags & MFE_UNDERWATER);
SINT8 flip = P_MobjFlip(tails); SINT8 flip = P_MobjFlip(tails);
boolean _2d = (tails->flags2 & MF2_TWOD) || twodlevel; boolean _2d = (tails->flags2 & MF2_TWOD) || twodlevel;
fixed_t scale = tails->scale; fixed_t scale = tails->scale;
boolean jump_last = (bot->lastbuttons & BT_JUMP);
boolean spin_last = (bot->lastbuttons & BT_SPIN);
fixed_t dist = P_AproxDistance(sonic->x - tails->x, sonic->y - tails->y); fixed_t dist = P_AproxDistance(sonic->x - tails->x, sonic->y - tails->y);
fixed_t zdist = flip * (sonic->z - tails->z); fixed_t zdist = flip * (sonic->z - tails->z);
angle_t ang = sonic->angle; angle_t ang = sonic->angle;
fixed_t pmom = P_AproxDistance(sonic->momx, sonic->momy); fixed_t pmom = P_AproxDistance(sonic->momx, sonic->momy);
fixed_t bmom = P_AproxDistance(tails->momx, tails->momy); fixed_t bmom = P_AproxDistance(tails->momx, tails->momy);
fixed_t followmax = 128 * 8 * scale; // Max follow distance before AI begins to enter "panic" state fixed_t followmax = 128 * 8 * scale; // Max follow distance before AI begins to enter catchup state
fixed_t followthres = 92 * scale; // Distance that AI will try to reach fixed_t followthres = 92 * scale; // Distance that AI will try to reach
fixed_t followmin = 32 * scale; fixed_t followmin = 32 * scale;
fixed_t comfortheight = 96 * scale; fixed_t comfortheight = 96 * scale;
fixed_t touchdist = 24 * scale; fixed_t touchdist = 24 * scale;
boolean stalled = (bmom < scale >> 1) && dist > followthres; // Helps to see if the AI is having trouble catching up boolean stalled = (bmom < scale >> 1) && dist > followthres; // Helps to see if the AI is having trouble catching up
boolean samepos = (sonic->x == tails->x && sonic->y == tails->y); boolean samepos = (sonic->x == tails->x && sonic->y == tails->y);
boolean blocked = bot->blocked;
if (!samepos) if (!samepos)
ang = R_PointToAngle2(tails->x, tails->y, sonic->x, sonic->y); ang = R_PointToAngle2(tails->x, tails->y, sonic->x, sonic->y);
// We can't follow Sonic if he's not around!
if (!sonic || sonic->health <= 0)
return;
// Lua can handle it! // Lua can handle it!
if (LUA_HookBotAI(sonic, tails, cmd)) if (LUA_HookBotAI(sonic, tails, cmd))
return; return;
// We can't follow Sonic if he's not around!
if (!sonic || sonic->health <= 0)
{
mem->thinkstate = AI_STANDBY;
return;
}
else if (mem->thinkstate == AI_STANDBY)
mem->thinkstate = AI_FOLLOW;
if (tails->player->powers[pw_carry] == CR_MACESPIN || tails->player->powers[pw_carry] == CR_GENERIC) if (tails->player->powers[pw_carry] == CR_MACESPIN || tails->player->powers[pw_carry] == CR_GENERIC)
{ {
boolean isrelevant = (sonic->player->powers[pw_carry] == CR_MACESPIN || sonic->player->powers[pw_carry] == CR_GENERIC); boolean isrelevant = (sonic->player->powers[pw_carry] == CR_MACESPIN || sonic->player->powers[pw_carry] == CR_GENERIC);
dist = P_AproxDistance(tails->x-sonic->x, tails->y-sonic->y);
if (sonic->player->cmd.buttons & BT_JUMP && (sonic->player->pflags & PF_JUMPED) && isrelevant) if (sonic->player->cmd.buttons & BT_JUMP && (sonic->player->pflags & PF_JUMPED) && isrelevant)
cmd->buttons |= BT_JUMP; cmd->buttons |= BT_JUMP;
if (isrelevant) if (isrelevant)
@ -103,56 +120,57 @@ static void B_BuildTailsTiccmd(mobj_t *sonic, mobj_t *tails, ticcmd_t *cmd)
followmin = 0; followmin = 0;
followthres = 16*scale; followthres = 16*scale;
followmax >>= 1; followmax >>= 1;
thinkfly = false; if (mem->thinkstate == AI_THINKFLY)
mem->thinkstate = AI_FOLLOW;
} }
// Check anxiety // Update catchup_tics
if (spinmode) if (mem->thinkstate == AI_SPINFOLLOW)
{ {
anxiety = 0; mem-> catchup_tics = 0;
panic = false;
} }
else if (dist > followmax || zdist > comfortheight || stalled) else if (dist > followmax || zdist > comfortheight || stalled)
{ {
anxiety = min(anxiety + 2, 70); mem-> catchup_tics = min(mem-> catchup_tics + 2, 70);
if (anxiety >= 70) if (mem-> catchup_tics >= 70)
panic = true; mem->thinkstate = AI_CATCHUP;
} }
else else
{ {
anxiety = max(anxiety - 1, 0); mem-> catchup_tics = max(mem-> catchup_tics - 1, 0);
panic = false; if (mem->thinkstate == AI_CATCHUP)
mem->thinkstate = AI_FOLLOW;
} }
// Orientation // Orientation
// cmd->angleturn won't be relative to player angle, since we're not going through G_BuildTiccmd.
if (bot->pflags & (PF_SPINNING|PF_STARTDASH)) if (bot->pflags & (PF_SPINNING|PF_STARTDASH))
{ {
cmd->angleturn = (sonic->angle - tails->angle) >> 16; // NOT FRACBITS DAMNIT cmd->angleturn = (sonic->angle) >> 16; // NOT FRACBITS DAMNIT
} }
else if (flymode == 2) else if (mem->thinkstate == AI_FLYCARRY)
{ {
cmd->angleturn = sonic->player->cmd.angleturn - (tails->angle >> 16); cmd->angleturn = sonic->player->cmd.angleturn;
} }
else else
{ {
cmd->angleturn = (ang - tails->angle) >> 16; // NOT FRACBITS DAMNIT cmd->angleturn = (ang) >> 16; // NOT FRACBITS DAMNIT
} }
// ******** // ********
// FLY MODE // FLY MODE
// spinmode check // exiting check
if (spinmode || player->exiting) if (player->exiting && mem->thinkstate == AI_THINKFLY)
thinkfly = false; mem->thinkstate = AI_FOLLOW;
else else
{ {
// Activate co-op flight // Activate co-op flight
if (thinkfly && player->pflags & PF_JUMPED) if (mem->thinkstate == AI_THINKFLY && player->pflags & PF_JUMPED)
{ {
if (!jump_last) if (!jump_last)
{ {
jump = true; jump = true;
flymode = 1; mem->thinkstate = AI_FLYSTANDBY;
thinkfly = false;
bot->pflags |= PF_CANCARRY; bot->pflags |= PF_CANCARRY;
} }
} }
@ -165,20 +183,19 @@ static void B_BuildTailsTiccmd(mobj_t *sonic, mobj_t *tails, ticcmd_t *cmd)
&& P_IsObjectOnGround(sonic) && P_IsObjectOnGround(tails) && P_IsObjectOnGround(sonic) && P_IsObjectOnGround(tails)
&& !(player->pflags & PF_STASIS) && !(player->pflags & PF_STASIS)
&& bot->charability == CA_FLY) && bot->charability == CA_FLY)
thinkfly = true; mem->thinkstate = AI_THINKFLY;
else else if (mem->thinkstate == AI_THINKFLY)
thinkfly = false; mem->thinkstate = AI_FOLLOW;
// Set carried state // Set carried state
if (player->powers[pw_carry] == CR_PLAYER && sonic->tracer == tails) if (player->powers[pw_carry] == CR_PLAYER && sonic->tracer == tails)
{ {
flymode = 2; mem->thinkstate = AI_FLYCARRY;
} }
// Ready for takeoff // Ready for takeoff
if (flymode == 1) if (mem->thinkstate == AI_FLYSTANDBY)
{ {
thinkfly = false;
if (zdist < -64*scale || (flip * tails->momz) > scale) // Make sure we're not too high up if (zdist < -64*scale || (flip * tails->momz) > scale) // Make sure we're not too high up
spin = true; spin = true;
else if (!jump_last) else if (!jump_last)
@ -186,10 +203,10 @@ static void B_BuildTailsTiccmd(mobj_t *sonic, mobj_t *tails, ticcmd_t *cmd)
// Abort if the player moves away or spins // Abort if the player moves away or spins
if (dist > followthres || player->dashspeed) if (dist > followthres || player->dashspeed)
flymode = 0; mem->thinkstate = AI_FOLLOW;
} }
// Read player inputs while carrying // Read player inputs while carrying
else if (flymode == 2) else if (mem->thinkstate == AI_FLYCARRY)
{ {
cmd->forwardmove = pcmd->forwardmove; cmd->forwardmove = pcmd->forwardmove;
cmd->sidemove = pcmd->sidemove; cmd->sidemove = pcmd->sidemove;
@ -203,19 +220,19 @@ static void B_BuildTailsTiccmd(mobj_t *sonic, mobj_t *tails, ticcmd_t *cmd)
// End flymode // End flymode
if (player->powers[pw_carry] != CR_PLAYER) if (player->powers[pw_carry] != CR_PLAYER)
{ {
flymode = 0; mem->thinkstate = AI_FOLLOW;
} }
} }
} }
if (flymode && P_IsObjectOnGround(tails) && !(pcmd->buttons & BT_JUMP)) if (P_IsObjectOnGround(tails) && !(pcmd->buttons & BT_JUMP) && (mem->thinkstate == AI_FLYSTANDBY || mem->thinkstate == AI_FLYCARRY))
flymode = 0; mem->thinkstate = AI_FOLLOW;
// ******** // ********
// SPINNING // SPINNING
if (panic || flymode || !(player->pflags & PF_SPINNING) || (player->pflags & PF_JUMPED)) if (!(player->pflags & (PF_SPINNING|PF_STARTDASH)) && mem->thinkstate == AI_SPINFOLLOW)
spinmode = false; mem->thinkstate = AI_FOLLOW;
else else if (mem->thinkstate == AI_FOLLOW || mem->thinkstate == AI_SPINFOLLOW)
{ {
if (!_2d) if (!_2d)
{ {
@ -224,21 +241,21 @@ static void B_BuildTailsTiccmd(mobj_t *sonic, mobj_t *tails, ticcmd_t *cmd)
{ {
if (dist < followthres && dist > touchdist) // Do positioning if (dist < followthres && dist > touchdist) // Do positioning
{ {
cmd->angleturn = (ang - tails->angle) >> 16; // NOT FRACBITS DAMNIT cmd->angleturn = (ang) >> 16; // NOT FRACBITS DAMNIT
cmd->forwardmove = 50; cmd->forwardmove = 50;
spinmode = true; mem->thinkstate = AI_SPINFOLLOW;
} }
else if (dist < touchdist) else if (dist < touchdist)
{ {
if (!bmom && (!(bot->pflags & PF_SPINNING) || (bot->dashspeed && bot->pflags & PF_SPINNING))) if (!bmom && (!(bot->pflags & PF_SPINNING) || (bot->dashspeed && bot->pflags & PF_SPINNING)))
{ {
cmd->angleturn = (sonic->angle - tails->angle) >> 16; // NOT FRACBITS DAMNIT cmd->angleturn = (sonic->angle) >> 16; // NOT FRACBITS DAMNIT
spin = true; spin = true;
} }
spinmode = true; mem->thinkstate = AI_SPINFOLLOW;
} }
else else
spinmode = false; mem->thinkstate = AI_FOLLOW;
} }
// Spin // Spin
else if (player->dashspeed == bot->dashspeed && player->pflags & PF_SPINNING) else if (player->dashspeed == bot->dashspeed && player->pflags & PF_SPINNING)
@ -246,12 +263,12 @@ static void B_BuildTailsTiccmd(mobj_t *sonic, mobj_t *tails, ticcmd_t *cmd)
if (bot->pflags & PF_SPINNING || !spin_last) if (bot->pflags & PF_SPINNING || !spin_last)
{ {
spin = true; spin = true;
cmd->angleturn = (sonic->angle - tails->angle) >> 16; // NOT FRACBITS DAMNIT cmd->angleturn = (sonic->angle) >> 16; // NOT FRACBITS DAMNIT
cmd->forwardmove = MAXPLMOVE; cmd->forwardmove = MAXPLMOVE;
spinmode = true; mem->thinkstate = AI_SPINFOLLOW;
} }
else else
spinmode = false; mem->thinkstate = AI_FOLLOW;
} }
} }
// 2D mode // 2D mode
@ -261,17 +278,19 @@ static void B_BuildTailsTiccmd(mobj_t *sonic, mobj_t *tails, ticcmd_t *cmd)
&& ((bot->pflags & PF_SPINNING) || !spin_last)) && ((bot->pflags & PF_SPINNING) || !spin_last))
{ {
spin = true; spin = true;
spinmode = true; mem->thinkstate = AI_SPINFOLLOW;
} }
else
mem->thinkstate = AI_FOLLOW;
} }
} }
// ******** // ********
// FOLLOW // FOLLOW
if (!(flymode || spinmode)) if (mem->thinkstate == AI_FOLLOW || mem->thinkstate == AI_CATCHUP)
{ {
// Too far // Too far
if (panic || dist > followthres) if (mem->thinkstate == AI_CATCHUP || dist > followthres)
{ {
if (!_2d) if (!_2d)
cmd->forwardmove = MAXPLMOVE; cmd->forwardmove = MAXPLMOVE;
@ -281,7 +300,7 @@ static void B_BuildTailsTiccmd(mobj_t *sonic, mobj_t *tails, ticcmd_t *cmd)
cmd->sidemove = -MAXPLMOVE; cmd->sidemove = -MAXPLMOVE;
} }
// Within threshold // Within threshold
else if (!panic && dist > followmin && abs(zdist) < 192*scale) else if (dist > followmin && abs(zdist) < 192*scale)
{ {
if (!_2d) if (!_2d)
cmd->forwardmove = FixedHypot(pcmd->forwardmove, pcmd->sidemove); cmd->forwardmove = FixedHypot(pcmd->forwardmove, pcmd->sidemove);
@ -292,7 +311,7 @@ static void B_BuildTailsTiccmd(mobj_t *sonic, mobj_t *tails, ticcmd_t *cmd)
else if (dist < followmin) else if (dist < followmin)
{ {
// Copy inputs // Copy inputs
cmd->angleturn = (sonic->angle - tails->angle) >> 16; // NOT FRACBITS DAMNIT cmd->angleturn = (sonic->angle) >> 16; // NOT FRACBITS DAMNIT
bot->drawangle = ang; bot->drawangle = ang;
cmd->forwardmove = 8 * pcmd->forwardmove / 10; cmd->forwardmove = 8 * pcmd->forwardmove / 10;
cmd->sidemove = 8 * pcmd->sidemove / 10; cmd->sidemove = 8 * pcmd->sidemove / 10;
@ -301,7 +320,7 @@ static void B_BuildTailsTiccmd(mobj_t *sonic, mobj_t *tails, ticcmd_t *cmd)
// ******** // ********
// JUMP // JUMP
if (!(flymode || spinmode)) if (mem->thinkstate == AI_FOLLOW || mem->thinkstate == AI_CATCHUP || (mem->thinkstate == AI_SPINFOLLOW && player->pflags & PF_JUMPED))
{ {
// Flying catch-up // Flying catch-up
if (bot->pflags & PF_THOKKED) if (bot->pflags & PF_THOKKED)
@ -319,31 +338,30 @@ static void B_BuildTailsTiccmd(mobj_t *sonic, mobj_t *tails, ticcmd_t *cmd)
// Start jump // Start jump
else if (!jump_last && !(bot->pflags & PF_JUMPED) //&& !(player->pflags & PF_SPINNING) else if (!jump_last && !(bot->pflags & PF_JUMPED) //&& !(player->pflags & PF_SPINNING)
&& ((zdist > 32*scale && player->pflags & PF_JUMPED) // Following && ((zdist > 32*scale && player->pflags & PF_JUMPED) // Following
|| (zdist > 64*scale && panic) // Vertical catch-up || (zdist > 64*scale && mem->thinkstate == AI_CATCHUP) // Vertical catch-up
|| (stalled && anxiety > 20 && bot->powers[pw_carry] == CR_NONE) || (stalled && mem-> catchup_tics > 20 && bot->powers[pw_carry] == CR_NONE)
//|| (bmom < scale>>3 && dist > followthres && !(bot->powers[pw_carry])) // Stopped & not in carry state //|| (bmom < scale>>3 && dist > followthres && !(bot->powers[pw_carry])) // Stopped & not in carry state
|| (bot->pflags & PF_SPINNING && !(bot->pflags & PF_JUMPED)))) // Spinning || (bot->pflags & PF_SPINNING && !(bot->pflags & PF_JUMPED)))) // Spinning
jump = true; jump = true;
// Hold jump // Hold jump
else if (bot->pflags & PF_JUMPED && jump_last && tails->momz*flip > 0 && (zdist > 0 || panic)) else if (bot->pflags & PF_JUMPED && jump_last && tails->momz*flip > 0 && (zdist > 0 || mem->thinkstate == AI_CATCHUP))
jump = true; jump = true;
// Start flying // Start flying
else if (bot->pflags & PF_JUMPED && panic && !jump_last && bot->charability == CA_FLY) else if (bot->pflags & PF_JUMPED && mem->thinkstate == AI_CATCHUP && !jump_last && bot->charability == CA_FLY)
jump = true; jump = true;
} }
// ******** // ********
// HISTORY // HISTORY
jump_last = jump; //jump_last = jump;
spin_last = spin; //spin_last = spin;
// Turn the virtual keypresses into ticcmd_t. // Turn the virtual keypresses into ticcmd_t.
B_KeysToTiccmd(tails, cmd, forward, backward, left, right, false, false, jump, spin); B_KeysToTiccmd(tails, cmd, forward, backward, left, right, false, false, jump, spin);
// Update our status // Update our status
lastForward = forward; mem->lastForward = forward;
lastBlocked = blocked; mem->lastBlocked = blocked;
blocked = false;
} }
void B_BuildTiccmd(player_t *player, ticcmd_t *cmd) void B_BuildTiccmd(player_t *player, ticcmd_t *cmd)
@ -366,22 +384,25 @@ void B_BuildTiccmd(player_t *player, ticcmd_t *cmd)
if (LUA_HookTiccmd(player, cmd, HOOK(BotTiccmd))) if (LUA_HookTiccmd(player, cmd, HOOK(BotTiccmd)))
return; return;
// We don't have any main character AI, sorry. D: // Make sure we have a valid main character to follow
if (player-players == consoleplayer) B_UpdateBotleader(player);
if (!player->botleader)
return; return;
// Basic Tails AI // Single Player Tails AI
B_BuildTailsTiccmd(players[consoleplayer].mo, player->mo, cmd); //B_BuildTailsTiccmd(players[consoleplayer].mo, player->mo, cmd);
B_BuildTailsTiccmd(player->botleader->mo, player->mo, cmd);
} }
void B_KeysToTiccmd(mobj_t *mo, ticcmd_t *cmd, boolean forward, boolean backward, boolean left, boolean right, boolean strafeleft, boolean straferight, boolean jump, boolean spin) void B_KeysToTiccmd(mobj_t *mo, ticcmd_t *cmd, boolean forward, boolean backward, boolean left, boolean right, boolean strafeleft, boolean straferight, boolean jump, boolean spin)
{ {
player_t *player = mo->player;
// don't try to do stuff if your sonic is in a minecart or something // don't try to do stuff if your sonic is in a minecart or something
if (players[consoleplayer].powers[pw_carry] && players[consoleplayer].powers[pw_carry] != CR_PLAYER) if (&player->botleader && player->botleader->powers[pw_carry] && player->botleader->powers[pw_carry] != CR_PLAYER)
return; return;
// Turn the virtual keypresses into ticcmd_t. // Turn the virtual keypresses into ticcmd_t.
if (twodlevel || mo->flags2 & MF2_TWOD) { if (twodlevel || mo->flags2 & MF2_TWOD) {
if (players[consoleplayer].climbing if (player->botleader->climbing
|| mo->player->pflags & PF_GLIDING) { || mo->player->pflags & PF_GLIDING) {
// Don't mess with bot inputs during these unhandled movement conditions. // Don't mess with bot inputs during these unhandled movement conditions.
// The normal AI doesn't use abilities, so custom AI should be sending us exactly what it wants anyway. // The normal AI doesn't use abilities, so custom AI should be sending us exactly what it wants anyway.
@ -420,10 +441,10 @@ void B_KeysToTiccmd(mobj_t *mo, ticcmd_t *cmd, boolean forward, boolean backward
cmd->forwardmove += MAXPLMOVE<<FRACBITS>>16; cmd->forwardmove += MAXPLMOVE<<FRACBITS>>16;
if (backward) if (backward)
cmd->forwardmove -= MAXPLMOVE<<FRACBITS>>16; cmd->forwardmove -= MAXPLMOVE<<FRACBITS>>16;
if (left) if (left)
cmd->angleturn += 1280; cmd->angleturn += 1280;
if (right) if (right)
cmd->angleturn -= 1280; cmd->angleturn -= 1280;
if (strafeleft) if (strafeleft)
cmd->sidemove -= MAXPLMOVE<<FRACBITS>>16; cmd->sidemove -= MAXPLMOVE<<FRACBITS>>16;
if (straferight) if (straferight)
@ -447,14 +468,19 @@ void B_KeysToTiccmd(mobj_t *mo, ticcmd_t *cmd, boolean forward, boolean backward
void B_MoveBlocked(player_t *player) void B_MoveBlocked(player_t *player)
{ {
(void)player; (void)player;
blocked = true; player->blocked = true;
} }
boolean B_CheckRespawn(player_t *player) boolean B_CheckRespawn(player_t *player)
{ {
mobj_t *sonic = players[consoleplayer].mo; mobj_t *sonic;
mobj_t *tails = player->mo; mobj_t *tails = player->mo;
//We don't have a main player to spawn to!
if (!player->botleader)
return false;
sonic = player->botleader->mo;
// We can't follow Sonic if he's not around! // We can't follow Sonic if he's not around!
if (!sonic || sonic->health <= 0) if (!sonic || sonic->health <= 0)
return false; return false;
@ -505,15 +531,19 @@ void B_RespawnBot(INT32 playernum)
{ {
player_t *player = &players[playernum]; player_t *player = &players[playernum];
fixed_t x,y,z; fixed_t x,y,z;
mobj_t *sonic = players[consoleplayer].mo; mobj_t *sonic;
mobj_t *tails; mobj_t *tails;
if (!player->botleader)
return;
sonic = player->botleader->mo;
if (!sonic || sonic->health <= 0) if (!sonic || sonic->health <= 0)
return; return;
B_ResetAI(); B_ResetAI(&player->botmem);
player->bot = 1; player->bot = BOT_2PAI;
P_SpawnPlayer(playernum); P_SpawnPlayer(playernum);
tails = player->mo; tails = player->mo;
@ -540,10 +570,6 @@ void B_RespawnBot(INT32 playernum)
player->powers[pw_spacetime] = sonic->player->powers[pw_spacetime]; player->powers[pw_spacetime] = sonic->player->powers[pw_spacetime];
player->powers[pw_gravityboots] = sonic->player->powers[pw_gravityboots]; player->powers[pw_gravityboots] = sonic->player->powers[pw_gravityboots];
player->powers[pw_nocontrol] = sonic->player->powers[pw_nocontrol]; player->powers[pw_nocontrol] = sonic->player->powers[pw_nocontrol];
player->acceleration = sonic->player->acceleration;
player->accelstart = sonic->player->accelstart;
player->thrustfactor = sonic->player->thrustfactor;
player->normalspeed = sonic->player->normalspeed;
player->pflags |= PF_AUTOBRAKE|(sonic->player->pflags & PF_DIRECTIONCHAR); player->pflags |= PF_AUTOBRAKE|(sonic->player->pflags & PF_DIRECTIONCHAR);
P_TeleportMove(tails, x, y, z); P_TeleportMove(tails, x, y, z);
@ -561,11 +587,11 @@ void B_RespawnBot(INT32 playernum)
void B_HandleFlightIndicator(player_t *player) void B_HandleFlightIndicator(player_t *player)
{ {
mobj_t *tails = player->mo; mobj_t *tails = player->mo;
botmem_t *mem = &player->botmem;
if (!tails) if (!tails)
return; return;
if (thinkfly && player->bot == 1 && tails->health) if (mem->thinkstate == AI_THINKFLY && player->bot == BOT_2PAI && tails->health)
{ {
if (!tails->hnext) if (!tails->hnext)
{ {

View file

@ -10,6 +10,7 @@
/// \file b_bot.h /// \file b_bot.h
/// \brief Basic bot handling /// \brief Basic bot handling
void B_UpdateBotleader(player_t *player);
void B_BuildTiccmd(player_t *player, ticcmd_t *cmd); void B_BuildTiccmd(player_t *player, ticcmd_t *cmd);
void B_KeysToTiccmd(mobj_t *mo, ticcmd_t *cmd, boolean forward, boolean backward, boolean left, boolean right, boolean strafeleft, boolean straferight, boolean jump, boolean spin); void B_KeysToTiccmd(mobj_t *mo, ticcmd_t *cmd, boolean forward, boolean backward, boolean left, boolean right, boolean strafeleft, boolean straferight, boolean jump, boolean spin);
boolean B_CheckRespawn(player_t *player); boolean B_CheckRespawn(player_t *player);

View file

@ -274,7 +274,7 @@ static int luaB_dofile (lua_State *L) {
UINT16 lumpnum; UINT16 lumpnum;
int n = lua_gettop(L); int n = lua_gettop(L);
if (wadfiles[numwadfiles - 1]->type != RET_PK3) if (!W_FileHasFolders(wadfiles[numwadfiles - 1]))
luaL_error(L, "dofile() only works with PK3 files"); luaL_error(L, "dofile() only works with PK3 files");
snprintf(fullfilename, sizeof(fullfilename), "Lua/%s", filename); snprintf(fullfilename, sizeof(fullfilename), "Lua/%s", filename);

View file

@ -650,7 +650,7 @@ static void COM_ExecuteString(char *ptext)
else else
{ // Monster Iestyn: keep track of how many levels of recursion we're in { // Monster Iestyn: keep track of how many levels of recursion we're in
recursion++; recursion++;
COM_BufInsertText(a->value); COM_BufInsertTextEx(a->value, com_flags);
recursion--; recursion--;
} }
return; return;
@ -1738,6 +1738,8 @@ void CV_SaveVars(UINT8 **p, boolean in_demo)
static void CV_LoadVars(UINT8 **p, static void CV_LoadVars(UINT8 **p,
consvar_t *(*got)(UINT8 **p, char **ret_value, boolean *ret_stealth)) consvar_t *(*got)(UINT8 **p, char **ret_value, boolean *ret_stealth))
{ {
const boolean store = (client || demoplayback);
consvar_t *cvar; consvar_t *cvar;
UINT16 count; UINT16 count;
@ -1751,7 +1753,7 @@ static void CV_LoadVars(UINT8 **p,
{ {
if (cvar->flags & CV_NETVAR) if (cvar->flags & CV_NETVAR)
{ {
if (client && cvar->revert.v.string == NULL) if (store && cvar->revert.v.string == NULL)
{ {
cvar->revert.v.const_munge = cvar->string; cvar->revert.v.const_munge = cvar->string;
cvar->revert.allocated = ( cvar->zstring != NULL ); cvar->revert.allocated = ( cvar->zstring != NULL );
@ -2364,7 +2366,10 @@ static boolean CV_Command(void)
return false; return false;
if (( com_flags & COM_SAFE ) && ( v->flags & CV_NOLUA )) if (( com_flags & COM_SAFE ) && ( v->flags & CV_NOLUA ))
return false; {
CONS_Alert(CONS_WARNING, "Variable '%s' cannot be changed from Lua.\n", v->name);
return true;
}
// perform a variable print or set // perform a variable print or set
if (COM_Argc() == 1) if (COM_Argc() == 1)

View file

@ -221,7 +221,7 @@ static void CONS_Bind_f(void)
for (key = 0; key < NUMINPUTS; key++) for (key = 0; key < NUMINPUTS; key++)
if (bindtable[key]) if (bindtable[key])
{ {
CONS_Printf("%s : \"%s\"\n", G_KeyNumToString(key), bindtable[key]); CONS_Printf("%s : \"%s\"\n", G_KeyNumToName(key), bindtable[key]);
na = 1; na = 1;
} }
if (!na) if (!na)
@ -229,7 +229,7 @@ static void CONS_Bind_f(void)
return; return;
} }
key = G_KeyStringToNum(COM_Argv(1)); key = G_KeyNameToNum(COM_Argv(1));
if (key <= 0 || key >= NUMINPUTS) if (key <= 0 || key >= NUMINPUTS)
{ {
CONS_Alert(CONS_NOTICE, M_GetText("Invalid key name\n")); CONS_Alert(CONS_NOTICE, M_GetText("Invalid key name\n"));
@ -913,12 +913,12 @@ boolean CON_Responder(event_t *ev)
// let go keyup events, don't eat them // let go keyup events, don't eat them
if (ev->type != ev_keydown && ev->type != ev_console) if (ev->type != ev_keydown && ev->type != ev_console)
{ {
if (ev->data1 == gamecontrol[gc_console][0] || ev->data1 == gamecontrol[gc_console][1]) if (ev->key == gamecontrol[GC_CONSOLE][0] || ev->key == gamecontrol[GC_CONSOLE][1])
consdown = false; consdown = false;
return false; return false;
} }
key = ev->data1; key = ev->key;
// check for console toggle key // check for console toggle key
if (ev->type != ev_console) if (ev->type != ev_console)
@ -926,7 +926,7 @@ boolean CON_Responder(event_t *ev)
if (modeattacking || metalrecording || marathonmode) if (modeattacking || metalrecording || marathonmode)
return false; return false;
if (key == gamecontrol[gc_console][0] || key == gamecontrol[gc_console][1]) if (key == gamecontrol[GC_CONSOLE][0] || key == gamecontrol[GC_CONSOLE][1])
{ {
if (consdown) // ignore repeat if (consdown) // ignore repeat
return true; return true;
@ -1759,8 +1759,8 @@ static void CON_DrawBackpic(void)
} }
// Draw the patch. // Draw the patch.
V_DrawCroppedPatch(x << FRACBITS, 0, FRACUNIT, V_NOSCALESTART, con_backpic, V_DrawCroppedPatch(x << FRACBITS, 0, FRACUNIT, FRACUNIT, V_NOSCALESTART, con_backpic, NULL,
0, ( BASEVIDHEIGHT - h ), BASEVIDWIDTH, h); 0, (BASEVIDHEIGHT - h) << FRACBITS, BASEVIDWIDTH << FRACBITS, h << FRACBITS);
// Unlock the cached patch. // Unlock the cached patch.
W_UnlockCachedPatch(con_backpic); W_UnlockCachedPatch(con_backpic);

View file

@ -43,6 +43,7 @@
#include "lzf.h" #include "lzf.h"
#include "lua_script.h" #include "lua_script.h"
#include "lua_hook.h" #include "lua_hook.h"
#include "lua_libs.h"
#include "md5.h" #include "md5.h"
#include "m_perfstats.h" #include "m_perfstats.h"
@ -663,14 +664,14 @@ static void Snake_Handle(void)
UINT16 i; UINT16 i;
// Handle retry // Handle retry
if (snake->gameover && (PLAYER1INPUTDOWN(gc_jump) || gamekeydown[KEY_ENTER])) if (snake->gameover && (PLAYER1INPUTDOWN(GC_JUMP) || gamekeydown[KEY_ENTER]))
{ {
Snake_Initialise(); Snake_Initialise();
snake->pausepressed = true; // Avoid accidental pause on respawn snake->pausepressed = true; // Avoid accidental pause on respawn
} }
// Handle pause // Handle pause
if (PLAYER1INPUTDOWN(gc_pause) || gamekeydown[KEY_ENTER]) if (PLAYER1INPUTDOWN(GC_PAUSE) || gamekeydown[KEY_ENTER])
{ {
if (!snake->pausepressed) if (!snake->pausepressed)
snake->paused = !snake->paused; snake->paused = !snake->paused;
@ -1150,15 +1151,14 @@ static boolean CL_SendJoin(void)
CONS_Printf(M_GetText("Sending join request...\n")); CONS_Printf(M_GetText("Sending join request...\n"));
netbuffer->packettype = PT_CLIENTJOIN; netbuffer->packettype = PT_CLIENTJOIN;
netbuffer->u.clientcfg.modversion = MODVERSION;
strncpy(netbuffer->u.clientcfg.application,
SRB2APPLICATION,
sizeof netbuffer->u.clientcfg.application);
if (splitscreen || botingame) if (splitscreen || botingame)
localplayers++; localplayers++;
netbuffer->u.clientcfg.localplayers = localplayers; netbuffer->u.clientcfg.localplayers = localplayers;
netbuffer->u.clientcfg._255 = 255;
netbuffer->u.clientcfg.packetversion = PACKETVERSION;
netbuffer->u.clientcfg.version = VERSION;
netbuffer->u.clientcfg.subversion = SUBVERSION;
strncpy(netbuffer->u.clientcfg.application, SRB2APPLICATION,
sizeof netbuffer->u.clientcfg.application);
CleanupPlayerName(consoleplayer, cv_playername.zstring); CleanupPlayerName(consoleplayer, cv_playername.zstring);
if (splitscreen) if (splitscreen)
@ -1201,6 +1201,21 @@ static INT32 FindRejoinerNum(SINT8 node)
return -1; return -1;
} }
static UINT8
GetRefuseReason (INT32 node)
{
if (!node || FindRejoinerNum(node) != -1)
return 0;
else if (bannednode && bannednode[node])
return REFUSE_BANNED;
else if (!cv_allownewplayer.value)
return REFUSE_JOINS_DISABLED;
else if (D_NumPlayers() >= cv_maxplayers.value)
return REFUSE_SLOTS_FULL;
else
return 0;
}
static void SV_SendServerInfo(INT32 node, tic_t servertime) static void SV_SendServerInfo(INT32 node, tic_t servertime)
{ {
UINT8 *p; UINT8 *p;
@ -1219,14 +1234,7 @@ static void SV_SendServerInfo(INT32 node, tic_t servertime)
netbuffer->u.serverinfo.numberofplayer = (UINT8)D_NumPlayers(); netbuffer->u.serverinfo.numberofplayer = (UINT8)D_NumPlayers();
netbuffer->u.serverinfo.maxplayer = (UINT8)cv_maxplayers.value; netbuffer->u.serverinfo.maxplayer = (UINT8)cv_maxplayers.value;
if (!node || FindRejoinerNum(node) != -1) netbuffer->u.serverinfo.refusereason = GetRefuseReason(node);
netbuffer->u.serverinfo.refusereason = 0;
else if (!cv_allownewplayer.value)
netbuffer->u.serverinfo.refusereason = 1;
else if (D_NumPlayers() >= cv_maxplayers.value)
netbuffer->u.serverinfo.refusereason = 2;
else
netbuffer->u.serverinfo.refusereason = 0;
strncpy(netbuffer->u.serverinfo.gametypename, Gametype_Names[gametype], strncpy(netbuffer->u.serverinfo.gametypename, Gametype_Names[gametype],
sizeof netbuffer->u.serverinfo.gametypename); sizeof netbuffer->u.serverinfo.gametypename);
@ -1344,9 +1352,6 @@ static boolean SV_SendServerConfig(INT32 node)
netbuffer->packettype = PT_SERVERCFG; netbuffer->packettype = PT_SERVERCFG;
netbuffer->u.servercfg.version = VERSION;
netbuffer->u.servercfg.subversion = SUBVERSION;
netbuffer->u.servercfg.serverplayer = (UINT8)serverplayer; netbuffer->u.servercfg.serverplayer = (UINT8)serverplayer;
netbuffer->u.servercfg.totalslotnum = (UINT8)(doomcom->numslots); netbuffer->u.servercfg.totalslotnum = (UINT8)(doomcom->numslots);
netbuffer->u.servercfg.gametic = (tic_t)LONG(gametic); netbuffer->u.servercfg.gametic = (tic_t)LONG(gametic);
@ -1667,20 +1672,24 @@ static void SL_InsertServer(serverinfo_pak* info, SINT8 node)
if (serverlistcount >= MAXSERVERLIST) if (serverlistcount >= MAXSERVERLIST)
return; // list full return; // list full
if (info->_255 != 255) /* check it later if connecting to this one */
return;/* old packet format */ if (node != servernode)
{
if (info->_255 != 255)
return;/* old packet format */
if (info->packetversion != PACKETVERSION) if (info->packetversion != PACKETVERSION)
return;/* old new packet format */ return;/* old new packet format */
if (info->version != VERSION) if (info->version != VERSION)
return; // Not same version. return; // Not same version.
if (info->subversion != SUBVERSION) if (info->subversion != SUBVERSION)
return; // Close, but no cigar. return; // Close, but no cigar.
if (strcmp(info->application, SRB2APPLICATION)) if (strcmp(info->application, SRB2APPLICATION))
return;/* that's a different mod */ return;/* that's a different mod */
}
i = serverlistcount++; i = serverlistcount++;
} }
@ -1829,6 +1838,72 @@ void CL_UpdateServerList(boolean internetsearch, INT32 room)
#endif // ifndef NONET #endif // ifndef NONET
static const char * InvalidServerReason (INT32 i)
{
#define EOT "\nPress ESC\n"
serverinfo_pak *info = &serverlist[i].info;
/* magic number for new packet format */
if (info->_255 != 255)
{
return
"Outdated server (version unknown).\n" EOT;
}
if (strncmp(info->application, SRB2APPLICATION, sizeof
info->application))
{
return va(
"%s cannot connect\n"
"to %s servers.\n" EOT,
SRB2APPLICATION,
info->application);
}
if (
info->packetversion != PACKETVERSION ||
info->version != VERSION ||
info->subversion != SUBVERSION
){
return va(
"Incompatible %s versions.\n"
"(server version %d.%d.%d)\n" EOT,
SRB2APPLICATION,
info->version / 100,
info->version % 100,
info->subversion);
}
switch (info->refusereason)
{
case REFUSE_BANNED:
return
"You have been banned\n"
"from the server.\n" EOT;
case REFUSE_JOINS_DISABLED:
return
"The server is not accepting\n"
"joins for the moment.\n" EOT;
case REFUSE_SLOTS_FULL:
return va(
"Maximum players reached: %d\n" EOT,
info->maxplayer);
default:
if (info->refusereason)
{
return
"You can't join.\n"
"I don't know why,\n"
"but you can't join.\n" EOT;
}
}
return NULL;
#undef EOT
}
/** Called by CL_ServerConnectionTicker /** Called by CL_ServerConnectionTicker
* *
* \param asksent The last time we asked the server to join. We re-ask every second in case our request got lost in transmit. * \param asksent The last time we asked the server to join. We re-ask every second in case our request got lost in transmit.
@ -1859,23 +1934,23 @@ static boolean CL_ServerConnectionSearchTicker(tic_t *asksent)
return true; return true;
} }
// Quit here rather than downloading files and being refused later.
if (serverlist[i].info.refusereason)
{
D_QuitNetGame();
CL_Reset();
D_StartTitle();
if (serverlist[i].info.refusereason == 1)
M_StartMessage(M_GetText("The server is not accepting\njoins for the moment.\n\nPress ESC\n"), NULL, MM_NOTHING);
else if (serverlist[i].info.refusereason == 2)
M_StartMessage(va(M_GetText("Maximum players reached: %d\n\nPress ESC\n"), serverlist[i].info.maxplayer), NULL, MM_NOTHING);
else
M_StartMessage(M_GetText("You can't join.\nI don't know why,\nbut you can't join.\n\nPress ESC\n"), NULL, MM_NOTHING);
return false;
}
if (client) if (client)
{ {
const char *reason = InvalidServerReason(i);
// Quit here rather than downloading files
// and being refused later.
if (reason)
{
char *message = Z_StrDup(reason);
D_QuitNetGame();
CL_Reset();
D_StartTitle();
M_StartMessage(message, NULL, MM_NOTHING);
Z_Free(message);
return false;
}
D_ParseFileneeded(serverlist[i].info.fileneedednum, D_ParseFileneeded(serverlist[i].info.fileneedednum,
serverlist[i].info.fileneeded); serverlist[i].info.fileneeded);
CONS_Printf(M_GetText("Checking files...\n")); CONS_Printf(M_GetText("Checking files...\n"));
@ -2463,7 +2538,7 @@ void CL_ClearPlayer(INT32 playernum)
// //
// Removes a player from the current game // Removes a player from the current game
// //
static void CL_RemovePlayer(INT32 playernum, kickreason_t reason) void CL_RemovePlayer(INT32 playernum, kickreason_t reason)
{ {
// Sanity check: exceptional cases (i.e. c-fails) can cause multiple // Sanity check: exceptional cases (i.e. c-fails) can cause multiple
// kick commands to be issued for the same player. // kick commands to be issued for the same player.
@ -2599,7 +2674,6 @@ void CL_Reset(void)
doomcom->numslots = 1; doomcom->numslots = 1;
SV_StopServer(); SV_StopServer();
SV_ResetServer(); SV_ResetServer();
CV_RevertNetVars();
// make sure we don't leave any fileneeded gunk over from a failed join // make sure we don't leave any fileneeded gunk over from a failed join
fileneedednum = 0; fileneedednum = 0;
@ -3231,6 +3305,8 @@ void SV_ResetServer(void)
// clear server_context // clear server_context
memset(server_context, '-', 8); memset(server_context, '-', 8);
CV_RevertNetVars();
DEBFILE("\n-=-=-=-=-=-=-= Server Reset =-=-=-=-=-=-=-\n\n"); DEBFILE("\n-=-=-=-=-=-=-= Server Reset =-=-=-=-=-=-=-\n\n");
} }
@ -3256,6 +3332,9 @@ static inline void SV_GenContext(void)
// //
void D_QuitNetGame(void) void D_QuitNetGame(void)
{ {
mousegrabbedbylua = true;
I_UpdateMouseGrab();
if (!netgame || !netbuffer) if (!netgame || !netbuffer)
return; return;
@ -3620,6 +3699,78 @@ static size_t TotalTextCmdPerTic(tic_t tic)
return total; return total;
} }
static const char *
ConnectionRefused (SINT8 node, INT32 rejoinernum)
{
clientconfig_pak *cc = &netbuffer->u.clientcfg;
boolean rejoining = (rejoinernum != -1);
if (!node)/* server connecting to itself */
return NULL;
if (
cc->modversion != MODVERSION ||
strncmp(cc->application, SRB2APPLICATION,
sizeof cc->application)
){
return/* this is probably client's fault */
"Incompatible.";
}
else if (bannednode && bannednode[node])
{
return
"You have been banned\n"
"from the server.";
}
else if (cc->localplayers != 1)
{
return
"Wrong player count.";
}
if (!rejoining)
{
if (!cv_allownewplayer.value)
{
return
"The server is not accepting\n"
"joins for the moment.";
}
else if (D_NumPlayers() >= cv_maxplayers.value)
{
return va(
"Maximum players reached: %d",
cv_maxplayers.value);
}
}
if (luafiletransfers)
{
return
"The serveris broadcasting a file\n"
"requested by a Lua script.\n"
"Please wait a bit and then\n"
"try rejoining.";
}
if (netgame)
{
const tic_t th = 2 * cv_joindelay.value * TICRATE;
if (joindelay > th)
{
return va(
"Too many people are connecting.\n"
"Please wait %d seconds and then\n"
"try rejoining.",
(joindelay - th) / TICRATE);
}
}
return NULL;
}
/** Called when a PT_CLIENTJOIN packet is received /** Called when a PT_CLIENTJOIN packet is received
* *
* \param node The packet sender * \param node The packet sender
@ -3630,33 +3781,14 @@ static void HandleConnect(SINT8 node)
char names[MAXSPLITSCREENPLAYERS][MAXPLAYERNAME + 1]; char names[MAXSPLITSCREENPLAYERS][MAXPLAYERNAME + 1];
INT32 rejoinernum; INT32 rejoinernum;
INT32 i; INT32 i;
const char *refuse;
rejoinernum = FindRejoinerNum(node); rejoinernum = FindRejoinerNum(node);
if (bannednode && bannednode[node]) refuse = ConnectionRefused(node, rejoinernum);
SV_SendRefuse(node, M_GetText("You have been banned\nfrom the server."));
else if (netbuffer->u.clientcfg._255 != 255 || if (refuse)
netbuffer->u.clientcfg.packetversion != PACKETVERSION) SV_SendRefuse(node, refuse);
SV_SendRefuse(node, "Incompatible packet formats.");
else if (strncmp(netbuffer->u.clientcfg.application, SRB2APPLICATION,
sizeof netbuffer->u.clientcfg.application))
SV_SendRefuse(node, "Different SRB2 modifications\nare not compatible.");
else if (netbuffer->u.clientcfg.version != VERSION
|| netbuffer->u.clientcfg.subversion != SUBVERSION)
SV_SendRefuse(node, va(M_GetText("Different SRB2 versions cannot\nplay a netgame!\n(server version %d.%d.%d)"), VERSION/100, VERSION%100, SUBVERSION));
else if (!cv_allownewplayer.value && node && rejoinernum == -1)
SV_SendRefuse(node, M_GetText("The server is not accepting\njoins for the moment."));
else if (D_NumPlayers() >= cv_maxplayers.value && rejoinernum == -1)
SV_SendRefuse(node, va(M_GetText("Maximum players reached: %d"), cv_maxplayers.value));
else if (netgame && netbuffer->u.clientcfg.localplayers > 1) // Hacked client?
SV_SendRefuse(node, M_GetText("Too many players from\nthis node."));
else if (netgame && !netbuffer->u.clientcfg.localplayers) // Stealth join?
SV_SendRefuse(node, M_GetText("No players from\nthis node."));
else if (luafiletransfers)
SV_SendRefuse(node, M_GetText("The server is broadcasting a file\nrequested by a Lua script.\nPlease wait a bit and then\ntry rejoining."));
else if (netgame && joindelay > 2 * (tic_t)cv_joindelay.value * TICRATE)
SV_SendRefuse(node, va(M_GetText("Too many people are connecting.\nPlease wait %d seconds and then\ntry rejoining."),
(joindelay - 2 * cv_joindelay.value * TICRATE) / TICRATE));
else else
{ {
#ifndef NONET #ifndef NONET

View file

@ -22,11 +22,15 @@
#include "mserv.h" #include "mserv.h"
/* /*
The 'packet version' is used to distinguish packet formats. The 'packet version' is used to distinguish packet
This version is independent of VERSION and SUBVERSION. Different formats. This version is independent of VERSION and
applications may follow different packet versions. SUBVERSION. Different applications may follow different
packet versions.
If you change the struct or the meaning of a field
therein, increment this number.
*/ */
#define PACKETVERSION 3 #define PACKETVERSION 4
// Network play related stuff. // Network play related stuff.
// There is a data struct that stores network // There is a data struct that stores network
@ -141,9 +145,6 @@ typedef struct
typedef struct typedef struct
{ {
UINT8 version; // Different versions don't work
UINT8 subversion; // Contains build version
// Server launch stuffs // Server launch stuffs
UINT8 serverplayer; UINT8 serverplayer;
UINT8 totalslotnum; // "Slots": highest player number in use plus one. UINT8 totalslotnum; // "Slots": highest player number in use plus one.
@ -190,16 +191,19 @@ typedef struct
typedef struct typedef struct
{ {
UINT8 _255;/* see serverinfo_pak */ UINT8 modversion;
UINT8 packetversion;
char application[MAXAPPLICATION]; char application[MAXAPPLICATION];
UINT8 version; // Different versions don't work
UINT8 subversion; // Contains build version
UINT8 localplayers; UINT8 localplayers;
UINT8 mode; UINT8 mode;
char names[MAXSPLITSCREENPLAYERS][MAXPLAYERNAME]; char names[MAXSPLITSCREENPLAYERS][MAXPLAYERNAME];
} ATTRPACK clientconfig_pak; } ATTRPACK clientconfig_pak;
enum {
REFUSE_JOINS_DISABLED = 1,
REFUSE_SLOTS_FULL,
REFUSE_BANNED,
};
#define MAXSERVERNAME 32 #define MAXSERVERNAME 32
#define MAXFILENEEDED 915 #define MAXFILENEEDED 915
// This packet is too large // This packet is too large
@ -217,7 +221,7 @@ typedef struct
UINT8 subversion; UINT8 subversion;
UINT8 numberofplayer; UINT8 numberofplayer;
UINT8 maxplayer; UINT8 maxplayer;
UINT8 refusereason; // 0: joinable, 1: joins disabled, 2: full UINT8 refusereason; // 0: joinable, REFUSE enum
char gametypename[24]; char gametypename[24];
UINT8 modifiedgame; UINT8 modifiedgame;
UINT8 cheatsenabled; UINT8 cheatsenabled;
@ -401,6 +405,7 @@ void CL_Reset(void);
void CL_ClearPlayer(INT32 playernum); void CL_ClearPlayer(INT32 playernum);
void CL_QueryServerList(msg_server_t *list); void CL_QueryServerList(msg_server_t *list);
void CL_UpdateServerList(boolean internetsearch, INT32 room); void CL_UpdateServerList(boolean internetsearch, INT32 room);
void CL_RemovePlayer(INT32 playernum, kickreason_t reason);
// Is there a game running // Is there a game running
boolean Playing(void); boolean Playing(void);

View file

@ -33,9 +33,10 @@ typedef enum
typedef struct typedef struct
{ {
evtype_t type; evtype_t type;
INT32 data1; // keys / mouse/joystick buttons INT32 key; // keys/mouse/joystick buttons
INT32 data2; // mouse/joystick x move INT32 x; // mouse/joystick x move
INT32 data3; // mouse/joystick y move INT32 y; // mouse/joystick y move
boolean repeated; // key repeat
} event_t; } event_t;
// //

View file

@ -191,22 +191,22 @@ void D_ProcessEvents(void)
if (ev->type == ev_keydown || ev->type == ev_keyup) if (ev->type == ev_keydown || ev->type == ev_keyup)
{ {
// Mouse buttons // Mouse buttons
if ((UINT32)(ev->data1 - KEY_MOUSE1) < MOUSEBUTTONS) if ((UINT32)(ev->key - KEY_MOUSE1) < MOUSEBUTTONS)
{ {
if (ev->type == ev_keydown) if (ev->type == ev_keydown)
mouse.buttons |= 1 << (ev->data1 - KEY_MOUSE1); mouse.buttons |= 1 << (ev->key - KEY_MOUSE1);
else else
mouse.buttons &= ~(1 << (ev->data1 - KEY_MOUSE1)); mouse.buttons &= ~(1 << (ev->key - KEY_MOUSE1));
} }
else if ((UINT32)(ev->data1 - KEY_2MOUSE1) < MOUSEBUTTONS) else if ((UINT32)(ev->key - KEY_2MOUSE1) < MOUSEBUTTONS)
{ {
if (ev->type == ev_keydown) if (ev->type == ev_keydown)
mouse2.buttons |= 1 << (ev->data1 - KEY_2MOUSE1); mouse2.buttons |= 1 << (ev->key - KEY_2MOUSE1);
else else
mouse2.buttons &= ~(1 << (ev->data1 - KEY_2MOUSE1)); mouse2.buttons &= ~(1 << (ev->key - KEY_2MOUSE1));
} }
// Scroll (has no keyup event) // Scroll (has no keyup event)
else switch (ev->data1) { else switch (ev->key) {
case KEY_MOUSEWHEELUP: case KEY_MOUSEWHEELUP:
mouse.buttons |= MB_SCROLLUP; mouse.buttons |= MB_SCROLLUP;
break; break;
@ -936,10 +936,26 @@ static void D_AddFile(char **list, const char *file)
newfile = malloc(strlen(file) + 1); newfile = malloc(strlen(file) + 1);
if (!newfile) if (!newfile)
{
I_Error("No more free memory to AddFile %s",file); I_Error("No more free memory to AddFile %s",file);
}
strcpy(newfile, file); strcpy(newfile, file);
list[pnumwadfiles] = newfile;
}
static void D_AddFolder(char **list, const char *file)
{
size_t pnumwadfiles;
char *newfile;
for (pnumwadfiles = 0; list[pnumwadfiles]; pnumwadfiles++)
;
newfile = malloc(strlen(file) + 2); // Path delimiter + NULL terminator
if (!newfile)
I_Error("No more free memory to AddFolder %s",file);
strcpy(newfile, file);
strcat(newfile, PATHSEP);
list[pnumwadfiles] = newfile; list[pnumwadfiles] = newfile;
} }
@ -1237,21 +1253,25 @@ void D_SRB2Main(void)
// Do this up here so that WADs loaded through the command line can use ExecCfg // Do this up here so that WADs loaded through the command line can use ExecCfg
COM_Init(); COM_Init();
// add any files specified on the command line with -file wadfile // Add any files specified on the command line with
// to the wad list // "-file <file>" or "-folder <folder>" to the add-on list
if (!((M_GetUrlProtocolArg() || M_CheckParm("-connect")) && !M_CheckParm("-server"))) if (!((M_GetUrlProtocolArg() || M_CheckParm("-connect")) && !M_CheckParm("-server")))
{ {
if (M_CheckParm("-file")) INT32 addontype = 0;
{ INT32 i;
// the parms after p are wadfile/lump names,
// until end of parms or another - preceded parm
while (M_IsNextParm())
{
const char *s = M_GetNextParm();
if (s) // Check for NULL? for (i = 1; i < myargc; i++)
D_AddFile(startuppwads, s); {
} if (!strcasecmp(myargv[i], "-file"))
addontype = 1;
else if (!strcasecmp(myargv[i], "-folder"))
addontype = 2;
else if (myargv[i][0] == '-' || myargv[i][0] == '+')
addontype = 0;
else if (addontype == 1)
D_AddFile(startuppwads, myargv[i]);
else if (addontype == 2)
D_AddFolder(startuppwads, myargv[i]);
} }
} }

View file

@ -63,7 +63,9 @@ static void Got_WeaponPref(UINT8 **cp, INT32 playernum);
static void Got_Mapcmd(UINT8 **cp, INT32 playernum); static void Got_Mapcmd(UINT8 **cp, INT32 playernum);
static void Got_ExitLevelcmd(UINT8 **cp, INT32 playernum); static void Got_ExitLevelcmd(UINT8 **cp, INT32 playernum);
static void Got_RequestAddfilecmd(UINT8 **cp, INT32 playernum); static void Got_RequestAddfilecmd(UINT8 **cp, INT32 playernum);
static void Got_RequestAddfoldercmd(UINT8 **cp, INT32 playernum);
static void Got_Addfilecmd(UINT8 **cp, INT32 playernum); static void Got_Addfilecmd(UINT8 **cp, INT32 playernum);
static void Got_Addfoldercmd(UINT8 **cp, INT32 playernum);
static void Got_Pause(UINT8 **cp, INT32 playernum); static void Got_Pause(UINT8 **cp, INT32 playernum);
static void Got_Suicide(UINT8 **cp, INT32 playernum); static void Got_Suicide(UINT8 **cp, INT32 playernum);
static void Got_RandomSeed(UINT8 **cp, INT32 playernum); static void Got_RandomSeed(UINT8 **cp, INT32 playernum);
@ -115,6 +117,7 @@ static void Command_Map_f(void);
static void Command_ResetCamera_f(void); static void Command_ResetCamera_f(void);
static void Command_Addfile(void); static void Command_Addfile(void);
static void Command_Addfolder(void);
static void Command_ListWADS_f(void); static void Command_ListWADS_f(void);
static void Command_RunSOC(void); static void Command_RunSOC(void);
static void Command_Pause(void); static void Command_Pause(void);
@ -284,7 +287,7 @@ consvar_t cv_gravity = CVAR_INIT ("gravity", "0.5", CV_RESTRICT|CV_FLOAT|CV_CALL
consvar_t cv_soundtest = CVAR_INIT ("soundtest", "0", CV_CALL, NULL, SoundTest_OnChange); consvar_t cv_soundtest = CVAR_INIT ("soundtest", "0", CV_CALL, NULL, SoundTest_OnChange);
static CV_PossibleValue_t minitimelimit_cons_t[] = {{15, "MIN"}, {9999, "MAX"}, {0, NULL}}; static CV_PossibleValue_t minitimelimit_cons_t[] = {{1, "MIN"}, {9999, "MAX"}, {0, NULL}};
consvar_t cv_countdowntime = CVAR_INIT ("countdowntime", "60", CV_SAVE|CV_NETVAR|CV_CHEAT, minitimelimit_cons_t, NULL); consvar_t cv_countdowntime = CVAR_INIT ("countdowntime", "60", CV_SAVE|CV_NETVAR|CV_CHEAT, minitimelimit_cons_t, NULL);
consvar_t cv_touchtag = CVAR_INIT ("touchtag", "Off", CV_SAVE|CV_NETVAR, CV_OnOff, NULL); consvar_t cv_touchtag = CVAR_INIT ("touchtag", "Off", CV_SAVE|CV_NETVAR, CV_OnOff, NULL);
@ -398,16 +401,16 @@ const char *netxcmdnames[MAXNETXCMD - 1] =
"MAP", "MAP",
"EXITLEVEL", "EXITLEVEL",
"ADDFILE", "ADDFILE",
"ADDFOLDER",
"PAUSE", "PAUSE",
"ADDPLAYER", "ADDPLAYER",
"TEAMCHANGE", "TEAMCHANGE",
"CLEARSCORES", "CLEARSCORES",
"LOGIN",
"VERIFIED", "VERIFIED",
"RANDOMSEED", "RANDOMSEED",
"RUNSOC", "RUNSOC",
"REQADDFILE", "REQADDFILE",
"DELFILE", // replace next time we add an XD "REQADDFOLDER",
"SETMOTD", "SETMOTD",
"SUICIDE", "SUICIDE",
"LUACMD", "LUACMD",
@ -441,7 +444,9 @@ void D_RegisterServerCommands(void)
RegisterNetXCmd(XD_MAP, Got_Mapcmd); RegisterNetXCmd(XD_MAP, Got_Mapcmd);
RegisterNetXCmd(XD_EXITLEVEL, Got_ExitLevelcmd); RegisterNetXCmd(XD_EXITLEVEL, Got_ExitLevelcmd);
RegisterNetXCmd(XD_ADDFILE, Got_Addfilecmd); RegisterNetXCmd(XD_ADDFILE, Got_Addfilecmd);
RegisterNetXCmd(XD_ADDFOLDER, Got_Addfoldercmd);
RegisterNetXCmd(XD_REQADDFILE, Got_RequestAddfilecmd); RegisterNetXCmd(XD_REQADDFILE, Got_RequestAddfilecmd);
RegisterNetXCmd(XD_REQADDFOLDER, Got_RequestAddfoldercmd);
RegisterNetXCmd(XD_PAUSE, Got_Pause); RegisterNetXCmd(XD_PAUSE, Got_Pause);
RegisterNetXCmd(XD_SUICIDE, Got_Suicide); RegisterNetXCmd(XD_SUICIDE, Got_Suicide);
RegisterNetXCmd(XD_RUNSOC, Got_RunSOCcmd); RegisterNetXCmd(XD_RUNSOC, Got_RunSOCcmd);
@ -472,6 +477,7 @@ void D_RegisterServerCommands(void)
COM_AddCommand("showmap", Command_Showmap_f); COM_AddCommand("showmap", Command_Showmap_f);
COM_AddCommand("mapmd5", Command_Mapmd5_f); COM_AddCommand("mapmd5", Command_Mapmd5_f);
COM_AddCommand("addfolder", Command_Addfolder);
COM_AddCommand("addfile", Command_Addfile); COM_AddCommand("addfile", Command_Addfile);
COM_AddCommand("listwad", Command_ListWADS_f); COM_AddCommand("listwad", Command_ListWADS_f);
@ -1512,7 +1518,7 @@ static void Got_NameAndColor(UINT8 **cp, INT32 playernum)
{ {
illegalMask &= ~(1 << i); illegalMask &= ~(1 << i);
} }
if ((p->availabilities & illegalMask) != 0) if ((p->availabilities & illegalMask) != 0)
{ {
kick = true; kick = true;
@ -3342,9 +3348,9 @@ static void Command_Addfile(void)
++p; ++p;
// check total packet size and no of files currently loaded // check total packet size and no of files currently loaded
// See W_LoadWadFile in w_wad.c // See W_InitFile in w_wad.c
if ((numwadfiles >= MAX_WADFILES) if ((numwadfiles >= MAX_WADFILES)
|| ((packetsizetally + nameonlylength(fn) + 22) > MAXFILENEEDED*sizeof(UINT8))) || ((packetsizetally + nameonlylength(fn) + FILENEEDEDSIZE) > MAXFILENEEDED*sizeof(UINT8)))
{ {
CONS_Alert(CONS_ERROR, M_GetText("Too many files loaded to add %s\n"), fn); CONS_Alert(CONS_ERROR, M_GetText("Too many files loaded to add %s\n"), fn);
return; return;
@ -3392,6 +3398,139 @@ static void Command_Addfile(void)
} }
} }
static void Command_Addfolder(void)
{
size_t argc = COM_Argc(); // amount of arguments total
size_t curarg; // current argument index
const char *addedfolders[argc]; // list of filenames already processed
size_t numfoldersadded = 0; // the amount of filenames processed
if (argc < 2)
{
CONS_Printf(M_GetText("addfolder <path> [path2...] [...]: Load add-ons\n"));
return;
}
// start at one to skip command name
for (curarg = 1; curarg < argc; curarg++)
{
const char *fn, *p;
char *fullpath;
char buf[256];
char *buf_p = buf;
INT32 i, stat;
size_t ii;
boolean folderadded = false;
fn = COM_Argv(curarg);
// For the amount of filenames previously processed...
for (ii = 0; ii < numfoldersadded; ii++)
{
// If this is one of them, don't try to add it.
if (!strcmp(fn, addedfolders[ii]))
{
folderadded = true;
break;
}
}
// If we've added this one, skip to the next one.
if (folderadded)
{
CONS_Alert(CONS_WARNING, M_GetText("Already processed %s, skipping\n"), fn);
continue;
}
// Disallow non-printing characters and semicolons.
for (i = 0; fn[i] != '\0'; i++)
if (!isprint(fn[i]) || fn[i] == ';')
return;
// Add file on your client directly if you aren't in a netgame.
if (!(netgame || multiplayer))
{
P_AddFolder(fn);
addedfolders[numfoldersadded++] = fn;
continue;
}
p = fn+strlen(fn);
while(--p >= fn)
if (*p == '\\' || *p == '/' || *p == ':')
break;
++p;
// Don't add an empty path.
if (M_IsStringEmpty(fn))
{
CONS_Alert(CONS_WARNING, M_GetText("Folder name is empty, skipping\n"));
continue;
}
// check total packet size and no of files currently loaded
// See W_InitFile in w_wad.c
if ((numwadfiles >= MAX_WADFILES)
|| ((packetsizetally + strlen(fn) + FILENEEDEDSIZE) > MAXFILENEEDED*sizeof(UINT8)))
{
CONS_Alert(CONS_ERROR, M_GetText("Too many files loaded to add %s\n"), fn);
return;
}
// Check if the path is valid.
stat = W_IsPathToFolderValid(fn);
if (stat == 0)
{
CONS_Alert(CONS_WARNING, M_GetText("Path %s is invalid, skipping\n"), fn);
continue;
}
else if (stat < 0)
{
#ifndef AVOID_ERRNO
CONS_Alert(CONS_WARNING, M_GetText("Error accessing %s (%s), skipping\n"), fn, strerror(direrror));
#else
CONS_Alert(CONS_WARNING, M_GetText("Error accessing %s, skipping\n"), fn);
#endif
continue;
}
// Get the full path for this folder.
fullpath = W_GetFullFolderPath(fn);
if (fullpath == NULL)
{
CONS_Alert(CONS_WARNING, M_GetText("Path %s is invalid, skipping\n"), fn);
continue;
}
// Check if the folder is already added.
for (i = 0; i < numwadfiles; i++)
{
if (wadfiles[i]->type != RET_FOLDER)
continue;
if (samepaths(wadfiles[i]->path, fullpath) > 0)
{
CONS_Alert(CONS_ERROR, M_GetText("%s is already loaded\n"), fn);
continue;
}
}
Z_Free(fullpath);
addedfolders[numfoldersadded++] = fn;
WRITESTRINGN(buf_p,p,240);
if (IsPlayerAdmin(consoleplayer) && (!server)) // Request to add file
SendNetXCmd(XD_REQADDFOLDER, buf, buf_p - buf);
else
SendNetXCmd(XD_ADDFOLDER, buf, buf_p - buf);
}
}
static void Got_RequestAddfilecmd(UINT8 **cp, INT32 playernum) static void Got_RequestAddfilecmd(UINT8 **cp, INT32 playernum)
{ {
char filename[241]; char filename[241];
@ -3420,9 +3559,9 @@ static void Got_RequestAddfilecmd(UINT8 **cp, INT32 playernum)
return; return;
} }
// See W_LoadWadFile in w_wad.c // See W_InitFile in w_wad.c
if ((numwadfiles >= MAX_WADFILES) if ((numwadfiles >= MAX_WADFILES)
|| ((packetsizetally + nameonlylength(filename) + 22) > MAXFILENEEDED*sizeof(UINT8))) || ((packetsizetally + nameonlylength(filename) + FILENEEDEDSIZE) > MAXFILENEEDED*sizeof(UINT8)))
toomany = true; toomany = true;
else else
ncs = findfile(filename,md5sum,true); ncs = findfile(filename,md5sum,true);
@ -3452,6 +3591,64 @@ static void Got_RequestAddfilecmd(UINT8 **cp, INT32 playernum)
COM_BufAddText(va("addfile %s\n", filename)); COM_BufAddText(va("addfile %s\n", filename));
} }
static void Got_RequestAddfoldercmd(UINT8 **cp, INT32 playernum)
{
char path[241];
filestatus_t ncs = FS_NOTFOUND;
boolean kick = false;
boolean toomany = false;
INT32 i,j;
READSTRINGN(*cp, path, 240);
/// \todo Integrity checks.
// Only the server processes this message.
if (client)
return;
// Disallow non-printing characters and semicolons.
for (i = 0; path[i] != '\0'; i++)
if (!isprint(path[i]) || path[i] == ';')
kick = true;
if ((playernum != serverplayer && !IsPlayerAdmin(playernum)) || kick)
{
CONS_Alert(CONS_WARNING, M_GetText("Illegal addfolder command received from %s\n"), player_names[playernum]);
SendKick(playernum, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY);
return;
}
// See W_InitFile in w_wad.c
if ((numwadfiles >= MAX_WADFILES)
|| ((packetsizetally + strlen(path) + FILENEEDEDSIZE) > MAXFILENEEDED*sizeof(UINT8)))
toomany = true;
else
ncs = findfolder(path);
if (ncs != FS_FOUND || toomany)
{
char message[256];
if (toomany)
sprintf(message, M_GetText("Too many files loaded to add %s\n"), path);
else if (ncs == FS_NOTFOUND)
sprintf(message, M_GetText("The server doesn't have %s\n"), path);
else
sprintf(message, M_GetText("Unknown error finding folder (%s)\n"), path);
CONS_Printf("%s",message);
for (j = 0; j < MAXPLAYERS; j++)
if (adminplayers[j])
COM_BufAddText(va("sayto %d %s", adminplayers[j], message));
return;
}
COM_BufAddText(va("addfolder \"%s\"\n", path));
}
static void Got_Addfilecmd(UINT8 **cp, INT32 playernum) static void Got_Addfilecmd(UINT8 **cp, INT32 playernum)
{ {
char filename[241]; char filename[241];
@ -3500,6 +3697,49 @@ static void Got_Addfilecmd(UINT8 **cp, INT32 playernum)
G_SetGameModified(true); G_SetGameModified(true);
} }
static void Got_Addfoldercmd(UINT8 **cp, INT32 playernum)
{
char path[241];
filestatus_t ncs = FS_NOTFOUND;
READSTRINGN(*cp, path, 240);
/// \todo Integrity checks.
if (playernum != serverplayer)
{
CONS_Alert(CONS_WARNING, M_GetText("Illegal addfolder command received from %s\n"), player_names[playernum]);
if (server)
SendKick(playernum, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY);
return;
}
ncs = findfolder(path);
if (ncs != FS_FOUND || !P_AddFolder(path))
{
Command_ExitGame_f();
if (ncs == FS_FOUND)
{
CONS_Printf(M_GetText("The server tried to add %s,\nbut you have too many files added.\nRestart the game to clear loaded files\nand play on this server."), path);
M_StartMessage(va("The server added a folder \n(%s)\nbut you have too many files added.\nRestart the game to clear loaded files.\n\nPress ESC\n",path), NULL, MM_NOTHING);
}
else if (ncs == FS_NOTFOUND)
{
CONS_Printf(M_GetText("The server tried to add %s,\nbut you don't have this file.\nYou need to find it in order\nto play on this server."), path);
M_StartMessage(va("The server added a folder \n(%s)\nthat you do not have.\n\nPress ESC\n",path), NULL, MM_NOTHING);
}
else
{
CONS_Printf(M_GetText("Unknown error finding folder (%s) the server added.\n"), path);
M_StartMessage(va("Unknown error trying to load a folder\nthat the server added \n(%s).\n\nPress ESC\n",path), NULL, MM_NOTHING);
}
return;
}
G_SetGameModified(true);
}
static void Command_ListWADS_f(void) static void Command_ListWADS_f(void)
{ {
INT32 i = numwadfiles; INT32 i = numwadfiles;
@ -3514,6 +3754,8 @@ static void Command_ListWADS_f(void)
CONS_Printf("\x82 * %.2d\x80: %s\n", i, tempname); CONS_Printf("\x82 * %.2d\x80: %s\n", i, tempname);
else if (!wadfiles[i]->important) else if (!wadfiles[i]->important)
CONS_Printf("\x86 %.2d: %s\n", i, tempname); CONS_Printf("\x86 %.2d: %s\n", i, tempname);
else if (wadfiles[i]->type == RET_FOLDER)
CONS_Printf("\x82 * %.2d\x84: %s\n", i, tempname);
else else
CONS_Printf(" %.2d: %s\n", i, tempname); CONS_Printf(" %.2d: %s\n", i, tempname);
} }

View file

@ -128,16 +128,16 @@ typedef enum
XD_MAP, // 6 XD_MAP, // 6
XD_EXITLEVEL, // 7 XD_EXITLEVEL, // 7
XD_ADDFILE, // 8 XD_ADDFILE, // 8
XD_PAUSE, // 9 XD_ADDFOLDER, // 9
XD_ADDPLAYER, // 10 XD_PAUSE, // 10
XD_TEAMCHANGE, // 11 XD_ADDPLAYER, // 11
XD_CLEARSCORES, // 12 XD_TEAMCHANGE, // 12
// UNUSED 13 (Because I don't want to change these comments) XD_CLEARSCORES, // 13
XD_VERIFIED = 14,//14 XD_VERIFIED, // 14
XD_RANDOMSEED, // 15 XD_RANDOMSEED, // 15
XD_RUNSOC, // 16 XD_RUNSOC, // 16
XD_REQADDFILE, // 17 XD_REQADDFILE, // 17
XD_DELFILE, // 18 - replace next time we add an XD XD_REQADDFOLDER,// 18
XD_SETMOTD, // 19 XD_SETMOTD, // 19
XD_SUICIDE, // 20 XD_SUICIDE, // 20
XD_DEMOTED, // 21 XD_DEMOTED, // 21

View file

@ -116,7 +116,7 @@ char luafiledir[256 + 16] = "luafiles";
/** Fills a serverinfo packet with information about wad files loaded. /** Fills a serverinfo packet with information about wad files loaded.
* *
* \todo Give this function a better name since it is in global scope. * \todo Give this function a better name since it is in global scope.
* Used to have size limiting built in - now handled via W_LoadWadFile in w_wad.c * Used to have size limiting built in - now handled via W_InitFile in w_wad.c
* *
*/ */
UINT8 *PutFileNeeded(void) UINT8 *PutFileNeeded(void)
@ -124,7 +124,7 @@ UINT8 *PutFileNeeded(void)
size_t i, count = 0; size_t i, count = 0;
UINT8 *p = netbuffer->u.serverinfo.fileneeded; UINT8 *p = netbuffer->u.serverinfo.fileneeded;
char wadfilename[MAX_WADPATH] = ""; char wadfilename[MAX_WADPATH] = "";
UINT8 filestatus; UINT8 filestatus, folder;
for (i = 0; i < numwadfiles; i++) for (i = 0; i < numwadfiles; i++)
{ {
@ -133,9 +133,10 @@ UINT8 *PutFileNeeded(void)
continue; continue;
filestatus = 1; // Importance - not really used any more, holds 1 by default for backwards compat with MS filestatus = 1; // Importance - not really used any more, holds 1 by default for backwards compat with MS
folder = (wadfiles[i]->type == RET_FOLDER);
// Store in the upper four bits // Store in the upper four bits
if (!cv_downloading.value) if (!cv_downloading.value || folder) /// \todo Implement folder downloading.
filestatus += (2 << 4); // Won't send filestatus += (2 << 4); // Won't send
else if ((wadfiles[i]->filesize <= (UINT32)cv_maxsend.value * 1024)) else if ((wadfiles[i]->filesize <= (UINT32)cv_maxsend.value * 1024))
filestatus += (1 << 4); // Will send if requested filestatus += (1 << 4); // Will send if requested
@ -143,6 +144,7 @@ UINT8 *PutFileNeeded(void)
// filestatus += (0 << 4); -- Won't send, too big // filestatus += (0 << 4); -- Won't send, too big
WRITEUINT8(p, filestatus); WRITEUINT8(p, filestatus);
WRITEUINT8(p, folder);
count++; count++;
WRITEUINT32(p, wadfiles[i]->filesize); WRITEUINT32(p, wadfiles[i]->filesize);
@ -174,6 +176,7 @@ void D_ParseFileneeded(INT32 fileneedednum_parm, UINT8 *fileneededstr)
fileneeded[i].status = FS_NOTFOUND; // We haven't even started looking for the file yet fileneeded[i].status = FS_NOTFOUND; // We haven't even started looking for the file yet
fileneeded[i].justdownloaded = false; fileneeded[i].justdownloaded = false;
filestatus = READUINT8(p); // The first byte is the file status filestatus = READUINT8(p); // The first byte is the file status
fileneeded[i].folder = READUINT8(p); // The second byte is the folder flag
fileneeded[i].willsend = (UINT8)(filestatus >> 4); fileneeded[i].willsend = (UINT8)(filestatus >> 4);
fileneeded[i].totalsize = READUINT32(p); // The four next bytes are the file size fileneeded[i].totalsize = READUINT32(p); // The four next bytes are the file size
fileneeded[i].file = NULL; // The file isn't open yet fileneeded[i].file = NULL; // The file isn't open yet
@ -416,7 +419,7 @@ INT32 CL_CheckFiles(void)
return 1; return 1;
} }
// See W_LoadWadFile in w_wad.c // See W_InitFile in w_wad.c
packetsize = packetsizetally; packetsize = packetsizetally;
for (i = 1; i < fileneedednum; i++) for (i = 1; i < fileneedednum; i++)
@ -438,7 +441,10 @@ INT32 CL_CheckFiles(void)
if (fileneeded[i].status != FS_NOTFOUND) if (fileneeded[i].status != FS_NOTFOUND)
continue; continue;
packetsize += nameonlylength(fileneeded[i].filename) + 22; if (fileneeded[i].folder)
packetsize += strlen(fileneeded[i].filename) + FILENEEDEDSIZE;
else
packetsize += nameonlylength(fileneeded[i].filename) + FILENEEDEDSIZE;
if ((numwadfiles+filestoget >= MAX_WADFILES) if ((numwadfiles+filestoget >= MAX_WADFILES)
|| (packetsize > MAXFILENEEDED*sizeof(UINT8))) || (packetsize > MAXFILENEEDED*sizeof(UINT8)))
@ -446,7 +452,10 @@ INT32 CL_CheckFiles(void)
filestoget++; filestoget++;
fileneeded[i].status = findfile(fileneeded[i].filename, fileneeded[i].md5sum, true); if (fileneeded[i].folder)
fileneeded[i].status = findfolder(fileneeded[i].filename);
else
fileneeded[i].status = findfile(fileneeded[i].filename, fileneeded[i].md5sum, true);
CONS_Debug(DBG_NETPLAY, "found %d\n", fileneeded[i].status); CONS_Debug(DBG_NETPLAY, "found %d\n", fileneeded[i].status);
if (fileneeded[i].status != FS_FOUND) if (fileneeded[i].status != FS_FOUND)
ret = 0; ret = 0;
@ -468,7 +477,10 @@ void CL_LoadServerFiles(void)
continue; // Already loaded continue; // Already loaded
else if (fileneeded[i].status == FS_FOUND) else if (fileneeded[i].status == FS_FOUND)
{ {
P_AddWadFile(fileneeded[i].filename); if (fileneeded[i].folder)
P_AddFolder(fileneeded[i].filename);
else
P_AddWadFile(fileneeded[i].filename);
G_SetGameModified(true); G_SetGameModified(true);
fileneeded[i].status = FS_OPEN; fileneeded[i].status = FS_OPEN;
} }
@ -756,7 +768,7 @@ static boolean AddFileToSendQueue(INT32 node, const char *filename, UINT8 fileid
// This formerly checked if (!findfile(p->id.filename, NULL, true)) // This formerly checked if (!findfile(p->id.filename, NULL, true))
// Not found // Not found
// Don't inform client (probably someone who thought they could leak 2.2 ACZ) // Don't inform client
DEBFILE(va("Client %d request %s: not found\n", node, filename)); DEBFILE(va("Client %d request %s: not found\n", node, filename));
free(p->id.filename); free(p->id.filename);
free(p); free(p);
@ -1571,3 +1583,26 @@ filestatus_t findfile(char *filename, const UINT8 *wantedmd5sum, boolean complet
return (badmd5 ? FS_MD5SUMBAD : FS_NOTFOUND); // md5 sum bad or file not found return (badmd5 ? FS_MD5SUMBAD : FS_NOTFOUND); // md5 sum bad or file not found
} }
// Searches for a folder.
// This can be used with a full path, or an incomplete path.
// In the latter case, the function will try to find folders in
// srb2home, srb2path, and the current directory.
filestatus_t findfolder(const char *path)
{
// Check the path by itself first.
if (concatpaths(path, NULL) == 1)
return FS_FOUND;
#define checkpath(startpath) \
if (concatpaths(path, startpath) == 1) \
return FS_FOUND
checkpath(srb2home); // Then, look in srb2home.
checkpath(srb2path); // Now, look in srb2path.
checkpath("."); // Finally, look in the current directory.
#undef checkpath
return FS_NOTFOUND;
}

View file

@ -38,6 +38,7 @@ typedef enum
typedef struct typedef struct
{ {
UINT8 willsend; // Is the server willing to send it? UINT8 willsend; // Is the server willing to send it?
UINT8 folder; // File is a folder
char filename[MAX_WADPATH]; char filename[MAX_WADPATH];
UINT8 md5sum[16]; UINT8 md5sum[16];
filestatus_t status; // The value returned by recsearch filestatus_t status; // The value returned by recsearch
@ -54,6 +55,8 @@ typedef struct
UINT32 ackresendposition; // Used when resuming downloads UINT32 ackresendposition; // Used when resuming downloads
} fileneeded_t; } fileneeded_t;
#define FILENEEDEDSIZE 23
extern INT32 fileneedednum; extern INT32 fileneedednum;
extern fileneeded_t fileneeded[MAX_WADFILES]; extern fileneeded_t fileneeded[MAX_WADFILES];
extern char downloaddir[512]; extern char downloaddir[512];
@ -135,6 +138,9 @@ filestatus_t findfile(char *filename, const UINT8 *wantedmd5sum,
boolean completepath); boolean completepath);
filestatus_t checkfilemd5(char *filename, const UINT8 *wantedmd5sum); filestatus_t checkfilemd5(char *filename, const UINT8 *wantedmd5sum);
// Searches for a folder
filestatus_t findfolder(const char *path);
void nameonly(char *s); void nameonly(char *s);
size_t nameonlylength(const char *s); size_t nameonlylength(const char *s);

View file

@ -313,9 +313,43 @@ typedef enum
RW_RAIL = 32 RW_RAIL = 32
} ringweapons_t; } ringweapons_t;
//Bot types
typedef enum
{
BOT_NONE = 0,
BOT_2PAI,
BOT_2PHUMAN,
BOT_MPAI
} bottype_t;
//AI states
typedef enum
{
AI_STANDBY = 0,
AI_FOLLOW,
AI_CATCHUP,
AI_THINKFLY,
AI_FLYSTANDBY,
AI_FLYCARRY,
AI_SPINFOLLOW
} aistatetype_t;
// ======================================================================== // ========================================================================
// PLAYER STRUCTURE // PLAYER STRUCTURE
// ======================================================================== // ========================================================================
//Bot memory struct
typedef struct botmem_s
{
boolean lastForward;
boolean lastBlocked;
boolean blocked;
UINT8 catchup_tics;
UINT8 thinkstate;
} botmem_t;
//Main struct
typedef struct player_s typedef struct player_s
{ {
mobj_t *mo; mobj_t *mo;
@ -525,8 +559,13 @@ typedef struct player_s
boolean spectator; boolean spectator;
boolean outofcoop; boolean outofcoop;
boolean removing;
UINT8 bot; UINT8 bot;
struct player_s *botleader;
UINT16 lastbuttons;
botmem_t botmem;
boolean blocked;
tic_t jointime; // Timer when player joins game to change skin/color tic_t jointime; // Timer when player joins game to change skin/color
tic_t quittime; // Time elapsed since user disconnected, zero if connected tic_t quittime; // Time elapsed since user disconnected, zero if connected
#ifdef HWRENDER #ifdef HWRENDER

View file

@ -5170,6 +5170,12 @@ struct int_const_s const INT_CONST[] = {
{"GF_REDFLAG",GF_REDFLAG}, {"GF_REDFLAG",GF_REDFLAG},
{"GF_BLUEFLAG",GF_BLUEFLAG}, {"GF_BLUEFLAG",GF_BLUEFLAG},
// Bot types
{"BOT_NONE",BOT_NONE},
{"BOT_2PAI",BOT_2PAI},
{"BOT_2PHUMAN",BOT_2PHUMAN},
{"BOT_MPAI",BOT_MPAI},
// Customisable sounds for Skins, from sounds.h // Customisable sounds for Skins, from sounds.h
{"SKSSPIN",SKSSPIN}, {"SKSSPIN",SKSSPIN},
{"SKSPUTPUT",SKSPUTPUT}, {"SKSPUTPUT",SKSPUTPUT},
@ -5482,49 +5488,49 @@ struct int_const_s const INT_CONST[] = {
{"JOYAXISRANGE",JOYAXISRANGE}, {"JOYAXISRANGE",JOYAXISRANGE},
// Game controls // Game controls
{"gc_null",gc_null}, {"GC_NULL",GC_NULL},
{"gc_forward",gc_forward}, {"GC_FORWARD",GC_FORWARD},
{"gc_backward",gc_backward}, {"GC_BACKWARD",GC_BACKWARD},
{"gc_strafeleft",gc_strafeleft}, {"GC_STRAFELEFT",GC_STRAFELEFT},
{"gc_straferight",gc_straferight}, {"GC_STRAFERIGHT",GC_STRAFERIGHT},
{"gc_turnleft",gc_turnleft}, {"GC_TURNLEFT",GC_TURNLEFT},
{"gc_turnright",gc_turnright}, {"GC_TURNRIGHT",GC_TURNRIGHT},
{"gc_weaponnext",gc_weaponnext}, {"GC_WEAPONNEXT",GC_WEAPONNEXT},
{"gc_weaponprev",gc_weaponprev}, {"GC_WEAPONPREV",GC_WEAPONPREV},
{"gc_wepslot1",gc_wepslot1}, {"GC_WEPSLOT1",GC_WEPSLOT1},
{"gc_wepslot2",gc_wepslot2}, {"GC_WEPSLOT2",GC_WEPSLOT2},
{"gc_wepslot3",gc_wepslot3}, {"GC_WEPSLOT3",GC_WEPSLOT3},
{"gc_wepslot4",gc_wepslot4}, {"GC_WEPSLOT4",GC_WEPSLOT4},
{"gc_wepslot5",gc_wepslot5}, {"GC_WEPSLOT5",GC_WEPSLOT5},
{"gc_wepslot6",gc_wepslot6}, {"GC_WEPSLOT6",GC_WEPSLOT6},
{"gc_wepslot7",gc_wepslot7}, {"GC_WEPSLOT7",GC_WEPSLOT7},
{"gc_wepslot8",gc_wepslot8}, {"GC_WEPSLOT8",GC_WEPSLOT8},
{"gc_wepslot9",gc_wepslot9}, {"GC_WEPSLOT9",GC_WEPSLOT9},
{"gc_wepslot10",gc_wepslot10}, {"GC_WEPSLOT10",GC_WEPSLOT10},
{"gc_fire",gc_fire}, {"GC_FIRE",GC_FIRE},
{"gc_firenormal",gc_firenormal}, {"GC_FIRENORMAL",GC_FIRENORMAL},
{"gc_tossflag",gc_tossflag}, {"GC_TOSSFLAG",GC_TOSSFLAG},
{"gc_spin",gc_spin}, {"GC_SPIN",GC_SPIN},
{"gc_camtoggle",gc_camtoggle}, {"GC_CAMTOGGLE",GC_CAMTOGGLE},
{"gc_camreset",gc_camreset}, {"GC_CAMRESET",GC_CAMRESET},
{"gc_lookup",gc_lookup}, {"GC_LOOKUP",GC_LOOKUP},
{"gc_lookdown",gc_lookdown}, {"GC_LOOKDOWN",GC_LOOKDOWN},
{"gc_centerview",gc_centerview}, {"GC_CENTERVIEW",GC_CENTERVIEW},
{"gc_mouseaiming",gc_mouseaiming}, {"GC_MOUSEAIMING",GC_MOUSEAIMING},
{"gc_talkkey",gc_talkkey}, {"GC_TALKKEY",GC_TALKKEY},
{"gc_teamkey",gc_teamkey}, {"GC_TEAMKEY",GC_TEAMKEY},
{"gc_scores",gc_scores}, {"GC_SCORES",GC_SCORES},
{"gc_jump",gc_jump}, {"GC_JUMP",GC_JUMP},
{"gc_console",gc_console}, {"GC_CONSOLE",GC_CONSOLE},
{"gc_pause",gc_pause}, {"GC_PAUSE",GC_PAUSE},
{"gc_systemmenu",gc_systemmenu}, {"GC_SYSTEMMENU",GC_SYSTEMMENU},
{"gc_screenshot",gc_screenshot}, {"GC_SCREENSHOT",GC_SCREENSHOT},
{"gc_recordgif",gc_recordgif}, {"GC_RECORDGIF",GC_RECORDGIF},
{"gc_viewpoint",gc_viewpoint}, {"GC_VIEWPOINT",GC_VIEWPOINT},
{"gc_custom1",gc_custom1}, {"GC_CUSTOM1",GC_CUSTOM1},
{"gc_custom2",gc_custom2}, {"GC_CUSTOM2",GC_CUSTOM2},
{"gc_custom3",gc_custom3}, {"GC_CUSTOM3",GC_CUSTOM3},
{"num_gamecontrols",num_gamecontrols}, {"NUM_GAMECONTROLS",NUM_GAMECONTROLS},
// Mouse buttons // Mouse buttons
{"MB_BUTTON1",MB_BUTTON1}, {"MB_BUTTON1",MB_BUTTON1},

View file

@ -127,6 +127,7 @@ extern char logfilename[1024];
//#define DEVELOP // Disable this for release builds to remove excessive cheat commands and enable MD5 checking and stuff, all in one go. :3 //#define DEVELOP // Disable this for release builds to remove excessive cheat commands and enable MD5 checking and stuff, all in one go. :3
#ifdef DEVELOP #ifdef DEVELOP
#define VERSIONSTRING "Development EXE" #define VERSIONSTRING "Development EXE"
#define VERSIONSTRING_RC "Development EXE" "\0"
// most interface strings are ignored in development mode. // most interface strings are ignored in development mode.
// we use comprevision and compbranch instead. // we use comprevision and compbranch instead.
// VERSIONSTRING_RC is for the resource-definition script used by windows builds // VERSIONSTRING_RC is for the resource-definition script used by windows builds

View file

@ -41,6 +41,7 @@
#include "console.h" #include "console.h"
#include "lua_hud.h" #include "lua_hud.h"
#include "lua_hook.h"
// Stage of animation: // Stage of animation:
// 0 = text, 1 = art screen // 0 = text, 1 = art screen
@ -1011,7 +1012,7 @@ void F_IntroTicker(void)
// //
boolean F_IntroResponder(event_t *event) boolean F_IntroResponder(event_t *event)
{ {
INT32 key = event->data1; INT32 key = event->key;
// remap virtual keys (mouse & joystick buttons) // remap virtual keys (mouse & joystick buttons)
switch (key) switch (key)
@ -1089,7 +1090,6 @@ static const char *credits[] = {
"\"Hannu_Hanhi\"", // For many OpenGL performance improvements! "\"Hannu_Hanhi\"", // For many OpenGL performance improvements!
"Kepa \"Nev3r\" Iceta", "Kepa \"Nev3r\" Iceta",
"Thomas \"Shadow Hog\" Igoe", "Thomas \"Shadow Hog\" Igoe",
"\"james\"",
"Iestyn \"Monster Iestyn\" Jealous", "Iestyn \"Monster Iestyn\" Jealous",
"\"Jimita\"", "\"Jimita\"",
"\"Kaito Sinclaire\"", "\"Kaito Sinclaire\"",
@ -1102,6 +1102,7 @@ static const char *credits[] = {
"Louis-Antoine \"LJ Sonic\" de Moulins", // de Rochefort doesn't quite fit on the screen sorry lol "Louis-Antoine \"LJ Sonic\" de Moulins", // de Rochefort doesn't quite fit on the screen sorry lol
"John \"JTE\" Muniz", "John \"JTE\" Muniz",
"Colin \"Sonict\" Pfaff", "Colin \"Sonict\" Pfaff",
"James \"james\" Robert Roman",
"Sean \"Sryder13\" Ryder", "Sean \"Sryder13\" Ryder",
"Ehab \"Wolfy\" Saeed", "Ehab \"Wolfy\" Saeed",
"Tasos \"tatokis\" Sahanidis", // Corrected C FixedMul, making 64-bit builds netplay compatible "Tasos \"tatokis\" Sahanidis", // Corrected C FixedMul, making 64-bit builds netplay compatible
@ -1166,7 +1167,6 @@ static const char *credits[] = {
"Alexander \"DrTapeworm\" Moench-Ford", "Alexander \"DrTapeworm\" Moench-Ford",
"Stefan \"Stuf\" Rimalia", "Stefan \"Stuf\" Rimalia",
"Shane Mychal Sexton", "Shane Mychal Sexton",
"\"Spazzo\"",
"David \"Big Wave Dave\" Spencer Sr.", "David \"Big Wave Dave\" Spencer Sr.",
"David \"Instant Sonic\" Spencer Jr.", "David \"Instant Sonic\" Spencer Jr.",
"\"SSNTails\"", "\"SSNTails\"",
@ -1191,7 +1191,6 @@ static const char *credits[] = {
"\"Revan\"", "\"Revan\"",
"Anna \"QueenDelta\" Sandlin", "Anna \"QueenDelta\" Sandlin",
"Wessel \"sphere\" Smit", "Wessel \"sphere\" Smit",
"\"Spazzo\"",
"\"SSNTails\"", "\"SSNTails\"",
"Rob Tisdell", "Rob Tisdell",
"\"Torgo\"", "\"Torgo\"",
@ -1399,7 +1398,7 @@ void F_CreditTicker(void)
boolean F_CreditResponder(event_t *event) boolean F_CreditResponder(event_t *event)
{ {
INT32 key = event->data1; INT32 key = event->key;
// remap virtual keys (mouse & joystick buttons) // remap virtual keys (mouse & joystick buttons)
switch (key) switch (key)
@ -3423,7 +3422,7 @@ void F_TitleScreenDrawer(void)
} }
luahook: luahook:
LUAh_TitleHUD(); LUA_HUDHOOK(title);
} }
// separate animation timer for backgrounds, since we also count // separate animation timer for backgrounds, since we also count
@ -3823,7 +3822,7 @@ void F_ContinueTicker(void)
boolean F_ContinueResponder(event_t *event) boolean F_ContinueResponder(event_t *event)
{ {
INT32 key = event->data1; INT32 key = event->key;
if (keypressed) if (keypressed)
return true; return true;

View file

@ -13,6 +13,7 @@
/// FS_FOUND /// FS_FOUND
#include <stdio.h> #include <stdio.h>
#include <errno.h>
#ifdef __GNUC__ #ifdef __GNUC__
#include <dirent.h> #include <dirent.h>
#endif #endif
@ -29,10 +30,10 @@
#include "m_misc.h" #include "m_misc.h"
#include "z_zone.h" #include "z_zone.h"
#include "m_menu.h" // Addons_option_Onchange #include "m_menu.h" // Addons_option_Onchange
#include "w_wad.h"
#if defined (_WIN32) && defined (_MSC_VER) #if defined (_WIN32) && defined (_MSC_VER)
#include <errno.h>
#include <io.h> #include <io.h>
#include <tchar.h> #include <tchar.h>
@ -340,6 +341,11 @@ char *refreshdirname = NULL;
size_t packetsizetally = 0; size_t packetsizetally = 0;
size_t mainwadstally = 0; size_t mainwadstally = 0;
#define dirpathlen 1024
#define maxdirdepth 48
#define isuptree(dirent) ((dirent)[0]=='.' && ((dirent)[1]=='\0' || ((dirent)[1]=='.' && (dirent)[2]=='\0')))
filestatus_t filesearch(char *filename, const char *startpath, const UINT8 *wantedmd5sum, boolean completepath, int maxsearchdepth) filestatus_t filesearch(char *filename, const char *startpath, const UINT8 *wantedmd5sum, boolean completepath, int maxsearchdepth)
{ {
filestatus_t retval = FS_NOTFOUND; filestatus_t retval = FS_NOTFOUND;
@ -387,10 +393,7 @@ filestatus_t filesearch(char *filename, const char *startpath, const UINT8 *want
continue; continue;
} }
if (dent->d_name[0]=='.' && if (isuptree(dent->d_name))
(dent->d_name[1]=='\0' ||
(dent->d_name[1]=='.' &&
dent->d_name[2]=='\0')))
{ {
// we don't want to scan uptree // we don't want to scan uptree
continue; continue;
@ -445,6 +448,380 @@ filestatus_t filesearch(char *filename, const char *startpath, const UINT8 *want
return retval; return retval;
} }
#ifndef AVOID_ERRNO
int direrror = 0;
#endif
// Checks if the specified path is a directory.
// Returns 1 if so, 0 if not, and -1 if an error occurred.
// direrror is set if there was an error.
INT32 pathisdirectory(const char *path)
{
struct stat fsstat;
if (stat(path, &fsstat) < 0)
{
#ifndef AVOID_ERRNO
direrror = errno;
#endif
return -1;
}
else if (S_ISDIR(fsstat.st_mode))
return 1;
return 0;
}
// Concatenates two paths, and checks if it is a directory that can be opened.
// Returns 1 if so, 0 if not, and -1 if an error occurred.
INT32 concatpaths(const char *path, const char *startpath)
{
char dirpath[dirpathlen];
DIR *dirhandle;
INT32 stat;
if (startpath)
{
char basepath[dirpathlen];
snprintf(basepath, sizeof basepath, "%s" PATHSEP, startpath);
snprintf(dirpath, sizeof dirpath, "%s%s", basepath, path);
// Base path and directory path are the same? Not valid.
stat = samepaths(basepath, dirpath);
if (stat == 1)
return 0;
else if (stat < 0)
return -1;
}
else
snprintf(dirpath, sizeof dirpath, "%s", path);
// Check if the path is a directory.
// Will return -1 if there was an error.
stat = pathisdirectory(dirpath);
if (stat == 0)
return 0;
else if (stat < 0)
{
// The path doesn't exist, so it can't be a directory.
if (direrror == ENOENT)
return 0;
return -1;
}
// Open the directory.
// Will return 0 if it couldn't be opened.
dirhandle = opendir(dirpath);
if (dirhandle == NULL)
return 0;
else
closedir(dirhandle);
return 1;
}
// Checks if two paths are the same. Returns 1 if so, and 0 if not.
// Returns -1 if an error occurred with the first path,
// and returns -2 if an error occurred with the second path.
// direrror is set if there was an error.
INT32 samepaths(const char *path1, const char *path2)
{
struct stat stat1;
struct stat stat2;
if (stat(path1, &stat1) < 0)
{
#ifndef AVOID_ERRNO
direrror = errno;
#endif
return -1;
}
if (stat(path2, &stat2) < 0)
{
#ifndef AVOID_ERRNO
direrror = errno;
#endif
return -2;
}
if (stat1.st_dev == stat2.st_dev)
{
#if !defined(_WIN32)
return (stat1.st_ino == stat2.st_ino);
#else
// The above doesn't work on NTFS or FAT.
HANDLE file1 = CreateFileA(path1, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
HANDLE file2 = CreateFileA(path2, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
BY_HANDLE_FILE_INFORMATION file1info, file2info;
if (file1 == INVALID_HANDLE_VALUE)
{
#ifndef AVOID_ERRNO
direrror = ENOENT;
#endif
return -1;
}
else if (file2 == INVALID_HANDLE_VALUE)
{
CloseHandle(file1);
#ifndef AVOID_ERRNO
direrror = ENOENT;
#endif
return -2;
}
// I have no idea why GetFileInformationByHandle would fail.
// Microsoft's documentation doesn't tell me.
// I'll just use EIO...
if (!GetFileInformationByHandle(file1, &file1info))
{
#ifndef AVOID_ERRNO
direrror = EIO;
#endif
return -1;
}
else if (!GetFileInformationByHandle(file2, &file2info))
{
CloseHandle(file1);
CloseHandle(file2);
#ifndef AVOID_ERRNO
direrror = EIO;
#endif
return -2;
}
if (file1info.dwVolumeSerialNumber == file2info.dwVolumeSerialNumber
&& file1info.nFileIndexLow == file2info.nFileIndexLow
&& file1info.nFileIndexHigh == file2info.nFileIndexHigh)
{
CloseHandle(file1);
CloseHandle(file2);
return 1;
}
return 0;
#endif
}
return 0;
}
//
// Directory loading
//
static void initdirpath(char *dirpath, size_t *dirpathindex, int depthleft)
{
dirpathindex[depthleft] = strlen(dirpath) + 1;
if (dirpath[dirpathindex[depthleft]-2] != PATHSEP[0])
{
dirpath[dirpathindex[depthleft]-1] = PATHSEP[0];
dirpath[dirpathindex[depthleft]] = 0;
}
else
dirpathindex[depthleft]--;
}
lumpinfo_t *getdirectoryfiles(const char *path, UINT16 *nlmp, UINT16 *nfolders)
{
DIR **dirhandle;
struct dirent *dent;
struct stat fsstat;
int rootdir = (maxdirdepth - 1);
int depthleft = rootdir;
char dirpath[dirpathlen];
size_t *dirpathindex;
lumpinfo_t *lumpinfo, *lump_p;
UINT16 i = 0, numlumps = 0;
boolean failure = false;
dirhandle = (DIR **)malloc(maxdirdepth * sizeof (DIR*));
dirpathindex = (size_t *)malloc(maxdirdepth * sizeof(size_t));
// Open the root directory
strlcpy(dirpath, path, dirpathlen);
dirhandle[depthleft] = opendir(dirpath);
if (dirhandle[depthleft] == NULL)
{
free(dirhandle);
free(dirpathindex);
return NULL;
}
initdirpath(dirpath, dirpathindex, depthleft);
(*nfolders) = 0;
// Count files and directories
while (depthleft < maxdirdepth)
{
dirpath[dirpathindex[depthleft]] = 0;
dent = readdir(dirhandle[depthleft]);
if (!dent)
{
if (depthleft != rootdir) // Don't close the root directory
closedir(dirhandle[depthleft]);
depthleft++;
continue;
}
else if (isuptree(dent->d_name))
continue;
strcpy(&dirpath[dirpathindex[depthleft]], dent->d_name);
if (stat(dirpath, &fsstat) < 0)
;
else if (S_ISDIR(fsstat.st_mode) && depthleft)
{
dirpathindex[--depthleft] = strlen(dirpath) + 1;
dirhandle[depthleft] = opendir(dirpath);
if (dirhandle[depthleft])
(*nfolders)++;
else
depthleft++;
dirpath[dirpathindex[depthleft]-1] = '/';
dirpath[dirpathindex[depthleft]] = 0;
}
else
numlumps++;
// Failure: Too many files.
if (numlumps == UINT16_MAX)
{
(*nlmp) = UINT16_MAX;
failure = true;
break;
}
}
// Failure: No files have been found.
if (!numlumps)
{
(*nlmp) = 0;
failure = true;
}
// Close any open directories and return if something went wrong.
if (failure)
{
free(dirpathindex);
free(dirhandle);
for (; depthleft < maxdirdepth; closedir(dirhandle[depthleft++]));
return NULL;
}
// Create the files and directories as lump entries
// It's possible to create lumps and count files at the same time,
// but I didn't want to have to reallocate memory for every lump.
rewinddir(dirhandle[rootdir]);
depthleft = rootdir;
strlcpy(dirpath, path, dirpathlen);
initdirpath(dirpath, dirpathindex, depthleft);
lump_p = lumpinfo = Z_Calloc(numlumps * sizeof(lumpinfo_t), PU_STATIC, NULL);
while (depthleft < maxdirdepth)
{
char *fullname, *trimname;
dirpath[dirpathindex[depthleft]] = 0;
dent = readdir(dirhandle[depthleft]);
if (!dent)
{
closedir(dirhandle[depthleft++]);
continue;
}
else if (isuptree(dent->d_name))
continue;
strcpy(&dirpath[dirpathindex[depthleft]], dent->d_name);
if (stat(dirpath, &fsstat) < 0)
continue;
else if (S_ISDIR(fsstat.st_mode) && depthleft)
{
dirpathindex[--depthleft] = strlen(dirpath) + 1;
dirhandle[depthleft] = opendir(dirpath);
if (dirhandle[depthleft])
{
dirpath[dirpathindex[depthleft]-1] = '/';
dirpath[dirpathindex[depthleft]] = 0;
}
else
depthleft++;
continue;
}
lump_p->diskpath = Z_StrDup(dirpath); // Path in the filesystem to the file
lump_p->compression = CM_NOCOMPRESSION; // Lump is uncompressed
// Remove the directory's path.
fullname = lump_p->diskpath;
if (strstr(fullname, path))
fullname += strlen(path) + 1;
// Get the 8-character long lump name.
trimname = strrchr(fullname, '/');
if (trimname)
trimname++;
else
trimname = fullname;
if (trimname[0])
{
char *dotpos = strrchr(trimname, '.');
if (dotpos == NULL)
dotpos = fullname + strlen(fullname);
strncpy(lump_p->name, trimname, min(8, dotpos - trimname));
// The name of the file, without the extension.
lump_p->longname = Z_Calloc(dotpos - trimname + 1, PU_STATIC, NULL);
strlcpy(lump_p->longname, trimname, dotpos - trimname + 1);
}
else
lump_p->longname = Z_Calloc(1, PU_STATIC, NULL);
// The complete name of the file, with its extension,
// excluding the path of the directory where it resides.
lump_p->fullname = Z_StrDup(fullname);
lump_p++;
i++;
if (i > numlumps || i == (UINT16_MAX-1))
{
for (; depthleft < maxdirdepth; closedir(dirhandle[depthleft++])); // Close any open directories.
break;
}
}
free(dirpathindex);
free(dirhandle);
(*nlmp) = numlumps;
return lumpinfo;
}
//
// Addons menu
//
char exttable[NUM_EXT_TABLE][7] = { // maximum extension length (currently 4) plus 3 (null terminator, stop, and length including previous two) char exttable[NUM_EXT_TABLE][7] = { // maximum extension length (currently 4) plus 3 (null terminator, stop, and length including previous two)
"\5.txt", "\5.cfg", // exec "\5.txt", "\5.cfg", // exec
"\5.wad", "\5.wad",
@ -455,7 +832,6 @@ char exttable[NUM_EXT_TABLE][7] = { // maximum extension length (currently 4) pl
char filenamebuf[MAX_WADFILES][MAX_WADPATH]; char filenamebuf[MAX_WADFILES][MAX_WADPATH];
static boolean filemenucmp(char *haystack, char *needle) static boolean filemenucmp(char *haystack, char *needle)
{ {
static char localhaystack[128]; static char localhaystack[128];
@ -640,10 +1016,7 @@ boolean preparefilemenu(boolean samedepth)
if (!dent) if (!dent)
break; break;
else if (dent->d_name[0]=='.' && else if (isuptree(dent->d_name))
(dent->d_name[1]=='\0' ||
(dent->d_name[1]=='.' &&
dent->d_name[2]=='\0')))
continue; // we don't want to scan uptree continue; // we don't want to scan uptree
strcpy(&menupath[menupathindex[menudepthleft]],dent->d_name); strcpy(&menupath[menupathindex[menudepthleft]],dent->d_name);
@ -704,10 +1077,7 @@ boolean preparefilemenu(boolean samedepth)
if (!dent) if (!dent)
break; break;
else if (dent->d_name[0]=='.' && else if (isuptree(dent->d_name))
(dent->d_name[1]=='\0' ||
(dent->d_name[1]=='.' &&
dent->d_name[2]=='\0')))
continue; // we don't want to scan uptree continue; // we don't want to scan uptree
strcpy(&menupath[menupathindex[menudepthleft]],dent->d_name); strcpy(&menupath[menupathindex[menudepthleft]],dent->d_name);

View file

@ -7,6 +7,7 @@
#include "doomdef.h" #include "doomdef.h"
#include "d_netfil.h" #include "d_netfil.h"
#include "m_menu.h" // MAXSTRINGLENGTH #include "m_menu.h" // MAXSTRINGLENGTH
#include "w_wad.h"
extern consvar_t cv_addons_option, cv_addons_folder, cv_addons_md5, cv_addons_showall, cv_addons_search_case, cv_addons_search_type; extern consvar_t cv_addons_option, cv_addons_folder, cv_addons_md5, cv_addons_showall, cv_addons_search_case, cv_addons_search_type;
@ -28,6 +29,16 @@ extern consvar_t cv_addons_option, cv_addons_folder, cv_addons_md5, cv_addons_sh
filestatus_t filesearch(char *filename, const char *startpath, const UINT8 *wantedmd5sum, filestatus_t filesearch(char *filename, const char *startpath, const UINT8 *wantedmd5sum,
boolean completepath, int maxsearchdepth); boolean completepath, int maxsearchdepth);
INT32 pathisdirectory(const char *path);
INT32 samepaths(const char *path1, const char *path2);
INT32 concatpaths(const char *path, const char *startpath);
#ifndef AVOID_ERRNO
extern int direrror;
#endif
lumpinfo_t *getdirectoryfiles(const char *path, UINT16 *nlmp, UINT16 *nfolders);
#define menudepth 20 #define menudepth 20
extern char menupath[1024]; extern char menupath[1024];
@ -94,5 +105,4 @@ typedef enum
void closefilemenu(boolean validsize); void closefilemenu(boolean validsize);
void searchfilemenu(char *tempname); void searchfilemenu(char *tempname);
boolean preparefilemenu(boolean samedepth); boolean preparefilemenu(boolean samedepth);
#endif // __FILESRCH_H__ #endif // __FILESRCH_H__

View file

@ -1680,6 +1680,7 @@ UINT8 G_CmpDemoTime(char *oldname, char *newname)
switch(oldversion) // demoversion switch(oldversion) // demoversion
{ {
case DEMOVERSION: // latest always supported case DEMOVERSION: // latest always supported
case 0x000d: // The previous demoversion also supported
case 0x000c: // all that changed between then and now was longer color name case 0x000c: // all that changed between then and now was longer color name
break; break;
// too old, cannot support. // too old, cannot support.
@ -2023,7 +2024,7 @@ void G_AddGhost(char *defdemoname)
char name[17],skin[17],color[MAXCOLORNAME+1],*n,*pdemoname,md5[16]; char name[17],skin[17],color[MAXCOLORNAME+1],*n,*pdemoname,md5[16];
UINT8 cnamelen; UINT8 cnamelen;
demoghost *gh; demoghost *gh;
UINT8 flags; UINT8 flags, subversion;
UINT8 *buffer,*p; UINT8 *buffer,*p;
mapthing_t *mthing; mapthing_t *mthing;
UINT16 count, ghostversion; UINT16 count, ghostversion;
@ -2071,7 +2072,7 @@ void G_AddGhost(char *defdemoname)
return; return;
} p += 12; // DEMOHEADER } p += 12; // DEMOHEADER
p++; // VERSION p++; // VERSION
p++; // SUBVERSION subversion = READUINT8(p); // SUBVERSION
ghostversion = READUINT16(p); ghostversion = READUINT16(p);
switch(ghostversion) switch(ghostversion)
{ {
@ -2170,9 +2171,19 @@ void G_AddGhost(char *defdemoname)
count = READUINT16(p); count = READUINT16(p);
while (count--) while (count--)
{ {
SKIPSTRING(p); // In 2.2.7 netvar saving was updated
SKIPSTRING(p); if (subversion < 7)
p++; {
p += 2;
SKIPSTRING(p);
p++;
}
else
{
SKIPSTRING(p);
SKIPSTRING(p);
p++;
}
} }
if (*p == DEMOMARKER) if (*p == DEMOMARKER)

View file

@ -45,6 +45,7 @@
#include "lua_hook.h" #include "lua_hook.h"
#include "b_bot.h" #include "b_bot.h"
#include "m_cond.h" // condition sets #include "m_cond.h" // condition sets
#include "lua_script.h"
#include "lua_hud.h" #include "lua_hud.h"
@ -1071,7 +1072,7 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer)
boolean turnleft, turnright, strafelkey, straferkey, movefkey, movebkey, mouseaiming, analogjoystickmove, gamepadjoystickmove, thisjoyaiming; boolean turnleft, turnright, strafelkey, straferkey, movefkey, movebkey, mouseaiming, analogjoystickmove, gamepadjoystickmove, thisjoyaiming;
boolean strafeisturn; // Simple controls only boolean strafeisturn; // Simple controls only
player_t *player = &players[ssplayer == 2 ? secondarydisplayplayer : consoleplayer]; player_t *player = &players[ssplayer == 2 ? secondarydisplayplayer : consoleplayer];
camera_t *thiscam = ((ssplayer == 1 || player->bot == 2) ? &camera : &camera2); camera_t *thiscam = ((ssplayer == 1 || player->bot == BOT_2PHUMAN) ? &camera : &camera2);
angle_t *myangle = (ssplayer == 1 ? &localangle : &localangle2); angle_t *myangle = (ssplayer == 1 ? &localangle : &localangle2);
INT32 *myaiming = (ssplayer == 1 ? &localaiming : &localaiming2); INT32 *myaiming = (ssplayer == 1 ? &localaiming : &localaiming2);
@ -1139,13 +1140,13 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer)
return; return;
} }
turnright = PLAYERINPUTDOWN(ssplayer, gc_turnright); turnright = PLAYERINPUTDOWN(ssplayer, GC_TURNRIGHT);
turnleft = PLAYERINPUTDOWN(ssplayer, gc_turnleft); turnleft = PLAYERINPUTDOWN(ssplayer, GC_TURNLEFT);
straferkey = PLAYERINPUTDOWN(ssplayer, gc_straferight); straferkey = PLAYERINPUTDOWN(ssplayer, GC_STRAFERIGHT);
strafelkey = PLAYERINPUTDOWN(ssplayer, gc_strafeleft); strafelkey = PLAYERINPUTDOWN(ssplayer, GC_STRAFELEFT);
movefkey = PLAYERINPUTDOWN(ssplayer, gc_forward); movefkey = PLAYERINPUTDOWN(ssplayer, GC_FORWARD);
movebkey = PLAYERINPUTDOWN(ssplayer, gc_backward); movebkey = PLAYERINPUTDOWN(ssplayer, GC_BACKWARD);
if (strafeisturn) if (strafeisturn)
{ {
@ -1154,7 +1155,7 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer)
straferkey = strafelkey = false; straferkey = strafelkey = false;
} }
mouseaiming = (PLAYERINPUTDOWN(ssplayer, gc_mouseaiming)) ^ mouseaiming = (PLAYERINPUTDOWN(ssplayer, GC_MOUSEAIMING)) ^
((chasecam && !player->spectator) ? chasefreelook : alwaysfreelook); ((chasecam && !player->spectator) ? chasefreelook : alwaysfreelook);
analogjoystickmove = usejoystick && !Joystick.bGamepadStyle; analogjoystickmove = usejoystick && !Joystick.bGamepadStyle;
gamepadjoystickmove = usejoystick && Joystick.bGamepadStyle; gamepadjoystickmove = usejoystick && Joystick.bGamepadStyle;
@ -1270,11 +1271,11 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer)
// forward with key or button // forward with key or button
if (movefkey || (gamepadjoystickmove && movejoystickvector.yaxis < 0) if (movefkey || (gamepadjoystickmove && movejoystickvector.yaxis < 0)
|| ((player->powers[pw_carry] == CR_NIGHTSMODE) || ((player->powers[pw_carry] == CR_NIGHTSMODE)
&& (PLAYERINPUTDOWN(ssplayer, gc_lookup) || (gamepadjoystickmove && lookjoystickvector.yaxis > 0)))) && (PLAYERINPUTDOWN(ssplayer, GC_LOOKUP) || (gamepadjoystickmove && lookjoystickvector.yaxis > 0))))
forward = forwardmove[speed]; forward = forwardmove[speed];
if (movebkey || (gamepadjoystickmove && movejoystickvector.yaxis > 0) if (movebkey || (gamepadjoystickmove && movejoystickvector.yaxis > 0)
|| ((player->powers[pw_carry] == CR_NIGHTSMODE) || ((player->powers[pw_carry] == CR_NIGHTSMODE)
&& (PLAYERINPUTDOWN(ssplayer, gc_lookdown) || (gamepadjoystickmove && lookjoystickvector.yaxis < 0)))) && (PLAYERINPUTDOWN(ssplayer, GC_LOOKDOWN) || (gamepadjoystickmove && lookjoystickvector.yaxis < 0))))
forward -= forwardmove[speed]; forward -= forwardmove[speed];
if (analogjoystickmove && movejoystickvector.yaxis != 0) if (analogjoystickmove && movejoystickvector.yaxis != 0)
@ -1287,9 +1288,9 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer)
if (strafelkey) if (strafelkey)
side -= sidemove[speed]; side -= sidemove[speed];
if (PLAYERINPUTDOWN(ssplayer, gc_weaponnext)) if (PLAYERINPUTDOWN(ssplayer, GC_WEAPONNEXT))
cmd->buttons |= BT_WEAPONNEXT; // Next Weapon cmd->buttons |= BT_WEAPONNEXT; // Next Weapon
if (PLAYERINPUTDOWN(ssplayer, gc_weaponprev)) if (PLAYERINPUTDOWN(ssplayer, GC_WEAPONPREV))
cmd->buttons |= BT_WEAPONPREV; // Previous Weapon cmd->buttons |= BT_WEAPONPREV; // Previous Weapon
#if NUM_WEAPONS > 10 #if NUM_WEAPONS > 10
@ -1298,7 +1299,7 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer)
//use the four avaliable bits to determine the weapon. //use the four avaliable bits to determine the weapon.
cmd->buttons &= ~BT_WEAPONMASK; cmd->buttons &= ~BT_WEAPONMASK;
for (i = 0; i < NUM_WEAPONS; ++i) for (i = 0; i < NUM_WEAPONS; ++i)
if (PLAYERINPUTDOWN(ssplayer, gc_wepslot1 + i)) if (PLAYERINPUTDOWN(ssplayer, GC_WEPSLOT1 + i))
{ {
cmd->buttons |= (UINT16)(i + 1); cmd->buttons |= (UINT16)(i + 1);
break; break;
@ -1306,34 +1307,34 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer)
// fire with any button/key // fire with any button/key
axis = PlayerJoyAxis(ssplayer, JA_FIRE); axis = PlayerJoyAxis(ssplayer, JA_FIRE);
if (PLAYERINPUTDOWN(ssplayer, gc_fire) || (usejoystick && axis > 0)) if (PLAYERINPUTDOWN(ssplayer, GC_FIRE) || (usejoystick && axis > 0))
cmd->buttons |= BT_ATTACK; cmd->buttons |= BT_ATTACK;
// fire normal with any button/key // fire normal with any button/key
axis = PlayerJoyAxis(ssplayer, JA_FIRENORMAL); axis = PlayerJoyAxis(ssplayer, JA_FIRENORMAL);
if (PLAYERINPUTDOWN(ssplayer, gc_firenormal) || (usejoystick && axis > 0)) if (PLAYERINPUTDOWN(ssplayer, GC_FIRENORMAL) || (usejoystick && axis > 0))
cmd->buttons |= BT_FIRENORMAL; cmd->buttons |= BT_FIRENORMAL;
if (PLAYERINPUTDOWN(ssplayer, gc_tossflag)) if (PLAYERINPUTDOWN(ssplayer, GC_TOSSFLAG))
cmd->buttons |= BT_TOSSFLAG; cmd->buttons |= BT_TOSSFLAG;
// Lua scriptable buttons // Lua scriptable buttons
if (PLAYERINPUTDOWN(ssplayer, gc_custom1)) if (PLAYERINPUTDOWN(ssplayer, GC_CUSTOM1))
cmd->buttons |= BT_CUSTOM1; cmd->buttons |= BT_CUSTOM1;
if (PLAYERINPUTDOWN(ssplayer, gc_custom2)) if (PLAYERINPUTDOWN(ssplayer, GC_CUSTOM2))
cmd->buttons |= BT_CUSTOM2; cmd->buttons |= BT_CUSTOM2;
if (PLAYERINPUTDOWN(ssplayer, gc_custom3)) if (PLAYERINPUTDOWN(ssplayer, GC_CUSTOM3))
cmd->buttons |= BT_CUSTOM3; cmd->buttons |= BT_CUSTOM3;
// use with any button/key // use with any button/key
axis = PlayerJoyAxis(ssplayer, JA_SPIN); axis = PlayerJoyAxis(ssplayer, JA_SPIN);
if (PLAYERINPUTDOWN(ssplayer, gc_spin) || (usejoystick && axis > 0)) if (PLAYERINPUTDOWN(ssplayer, GC_SPIN) || (usejoystick && axis > 0))
cmd->buttons |= BT_SPIN; cmd->buttons |= BT_SPIN;
// Centerview can be a toggle in simple mode! // Centerview can be a toggle in simple mode!
{ {
static boolean last_centerviewdown[2], centerviewhold[2]; // detect taps for toggle behavior static boolean last_centerviewdown[2], centerviewhold[2]; // detect taps for toggle behavior
boolean down = PLAYERINPUTDOWN(ssplayer, gc_centerview); boolean down = PLAYERINPUTDOWN(ssplayer, GC_CENTERVIEW);
if (!(controlstyle == CS_SIMPLE && cv_cam_centertoggle[forplayer].value)) if (!(controlstyle == CS_SIMPLE && cv_cam_centertoggle[forplayer].value))
centerviewdown = down; centerviewdown = down;
@ -1432,7 +1433,7 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer)
if (ticcmd_centerviewdown[forplayer] && controlstyle == CS_SIMPLE) if (ticcmd_centerviewdown[forplayer] && controlstyle == CS_SIMPLE)
controlstyle = CS_LEGACY; controlstyle = CS_LEGACY;
if (PLAYERINPUTDOWN(ssplayer, gc_camreset)) if (PLAYERINPUTDOWN(ssplayer, GC_CAMRESET))
{ {
if (thiscam->chase && !resetdown[forplayer]) if (thiscam->chase && !resetdown[forplayer])
P_ResetCamera(&players[ssplayer == 1 ? displayplayer : secondarydisplayplayer], thiscam); P_ResetCamera(&players[ssplayer == 1 ? displayplayer : secondarydisplayplayer], thiscam);
@ -1445,7 +1446,7 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer)
// jump button // jump button
axis = PlayerJoyAxis(ssplayer, JA_JUMP); axis = PlayerJoyAxis(ssplayer, JA_JUMP);
if (PLAYERINPUTDOWN(ssplayer, gc_jump) || (usejoystick && axis > 0)) if (PLAYERINPUTDOWN(ssplayer, GC_JUMP) || (usejoystick && axis > 0))
cmd->buttons |= BT_JUMP; cmd->buttons |= BT_JUMP;
// player aiming shit, ahhhh... // player aiming shit, ahhhh...
@ -1475,12 +1476,12 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer)
if (!(player->powers[pw_carry] == CR_NIGHTSMODE)) if (!(player->powers[pw_carry] == CR_NIGHTSMODE))
{ {
if (PLAYERINPUTDOWN(ssplayer, gc_lookup) || (gamepadjoystickmove && lookjoystickvector.yaxis < 0)) if (PLAYERINPUTDOWN(ssplayer, GC_LOOKUP) || (gamepadjoystickmove && lookjoystickvector.yaxis < 0))
{ {
*myaiming += KB_LOOKSPEED * screen_invert; *myaiming += KB_LOOKSPEED * screen_invert;
keyboard_look[forplayer] = true; keyboard_look[forplayer] = true;
} }
else if (PLAYERINPUTDOWN(ssplayer, gc_lookdown) || (gamepadjoystickmove && lookjoystickvector.yaxis > 0)) else if (PLAYERINPUTDOWN(ssplayer, GC_LOOKDOWN) || (gamepadjoystickmove && lookjoystickvector.yaxis > 0))
{ {
*myaiming -= KB_LOOKSPEED * screen_invert; *myaiming -= KB_LOOKSPEED * screen_invert;
keyboard_look[forplayer] = true; keyboard_look[forplayer] = true;
@ -1545,23 +1546,14 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer)
cmd->forwardmove = (SINT8)(cmd->forwardmove + forward); cmd->forwardmove = (SINT8)(cmd->forwardmove + forward);
cmd->sidemove = (SINT8)(cmd->sidemove + side); cmd->sidemove = (SINT8)(cmd->sidemove + side);
if (player->bot == 1) { // Tailsbot for P2 // Note: Majority of botstuffs are handled in G_Ticker now.
if (!player->powers[pw_tailsfly] && (cmd->forwardmove || cmd->sidemove || cmd->buttons)) if (player->bot == BOT_2PHUMAN) //Player-controlled bot
{ {
player->bot = 2; // A player-controlled bot. Returns to AI when it respawns. G_CopyTiccmd(cmd, I_BaseTiccmd2(), 1); // empty, or external driver
CV_SetValue(&cv_analog[1], true);
}
else
{
G_CopyTiccmd(cmd, I_BaseTiccmd2(), 1); // empty, or external driver
B_BuildTiccmd(player, cmd);
}
B_HandleFlightIndicator(player);
}
else if (player->bot == 2)
// Fix offset angle for P2-controlled Tailsbot when P2's controls are set to non-Legacy // Fix offset angle for P2-controlled Tailsbot when P2's controls are set to non-Legacy
cmd->angleturn = (INT16)((localangle - *myangle) >> 16); cmd->angleturn = (INT16)((localangle - *myangle) >> 16);
}
*myangle += (cmd->angleturn<<16); *myangle += (cmd->angleturn<<16);
if (controlstyle == CS_LMAOGALOG) { if (controlstyle == CS_LMAOGALOG) {
@ -1968,7 +1960,7 @@ boolean G_Responder(event_t *ev)
if (gameaction == ga_nothing && !singledemo && if (gameaction == ga_nothing && !singledemo &&
((demoplayback && !modeattacking && !titledemo) || gamestate == GS_TITLESCREEN)) ((demoplayback && !modeattacking && !titledemo) || gamestate == GS_TITLESCREEN))
{ {
if (ev->type == ev_keydown && ev->data1 != 301 && !(gamestate == GS_TITLESCREEN && finalecount < TICRATE)) if (ev->type == ev_keydown && ev->key != 301 && !(gamestate == GS_TITLESCREEN && finalecount < TICRATE))
{ {
M_StartControlPanel(); M_StartControlPanel();
return true; return true;
@ -2044,7 +2036,7 @@ boolean G_Responder(event_t *ev)
// allow spy mode changes even during the demo // allow spy mode changes even during the demo
if (gamestate == GS_LEVEL && ev->type == ev_keydown if (gamestate == GS_LEVEL && ev->type == ev_keydown
&& (ev->data1 == KEY_F12 || ev->data1 == gamecontrol[gc_viewpoint][0] || ev->data1 == gamecontrol[gc_viewpoint][1])) && (ev->key == KEY_F12 || ev->key == gamecontrol[GC_VIEWPOINT][0] || ev->key == gamecontrol[GC_VIEWPOINT][1]))
{ {
// ViewpointSwitch Lua hook. // ViewpointSwitch Lua hook.
UINT8 canSwitchView = 0; UINT8 canSwitchView = 0;
@ -2117,13 +2109,13 @@ boolean G_Responder(event_t *ev)
switch (ev->type) switch (ev->type)
{ {
case ev_keydown: case ev_keydown:
if (ev->data1 == gamecontrol[gc_pause][0] if (ev->key == gamecontrol[GC_PAUSE][0]
|| ev->data1 == gamecontrol[gc_pause][1] || ev->key == gamecontrol[GC_PAUSE][1]
|| ev->data1 == KEY_PAUSE) || ev->key == KEY_PAUSE)
{ {
if (modeattacking && !demoplayback && (gamestate == GS_LEVEL)) if (modeattacking && !demoplayback && (gamestate == GS_LEVEL))
{ {
pausebreakkey = (ev->data1 == KEY_PAUSE); pausebreakkey = (ev->key == KEY_PAUSE);
if (menuactive || pausedelay < 0 || leveltime < 2) if (menuactive || pausedelay < 0 || leveltime < 2)
return true; return true;
@ -2148,8 +2140,8 @@ boolean G_Responder(event_t *ev)
} }
} }
} }
if (ev->data1 == gamecontrol[gc_camtoggle][0] if (ev->key == gamecontrol[GC_CAMTOGGLE][0]
|| ev->data1 == gamecontrol[gc_camtoggle][1]) || ev->key == gamecontrol[GC_CAMTOGGLE][1])
{ {
if (!camtoggledelay) if (!camtoggledelay)
{ {
@ -2157,8 +2149,8 @@ boolean G_Responder(event_t *ev)
CV_SetValue(&cv_chasecam, cv_chasecam.value ? 0 : 1); CV_SetValue(&cv_chasecam, cv_chasecam.value ? 0 : 1);
} }
} }
if (ev->data1 == gamecontrolbis[gc_camtoggle][0] if (ev->key == gamecontrolbis[GC_CAMTOGGLE][0]
|| ev->data1 == gamecontrolbis[gc_camtoggle][1]) || ev->key == gamecontrolbis[GC_CAMTOGGLE][1])
{ {
if (!camtoggledelay2) if (!camtoggledelay2)
{ {
@ -2194,8 +2186,20 @@ boolean G_Responder(event_t *ev)
// //
boolean G_LuaResponder(event_t *ev) boolean G_LuaResponder(event_t *ev)
{ {
return (ev->type == ev_keydown && LUA_HookKey(ev->data1, HOOK(KeyDown))) || boolean cancelled = false;
(ev->type == ev_keyup && LUA_HookKey(ev->data1, HOOK(KeyUp)));
if (ev->type == ev_keydown)
{
cancelled = LUA_HookKey(ev, HOOK(KeyDown));
LUA_InvalidateUserdata(ev);
}
else if (ev->type == ev_keyup)
{
cancelled = LUA_HookKey(ev, HOOK(KeyUp));
LUA_InvalidateUserdata(ev);
}
return cancelled;
} }
// //
@ -2207,6 +2211,23 @@ void G_Ticker(boolean run)
UINT32 i; UINT32 i;
INT32 buf; INT32 buf;
// Bot players queued for removal
for (i = MAXPLAYERS-1; i != UINT32_MAX; i--)
{
if (playeringame[i] && players[i].removing)
{
CL_RemovePlayer(i, i);
if (netgame)
{
char kickmsg[256];
strcpy(kickmsg, M_GetText("\x82*Bot %s has been removed"));
strcpy(kickmsg, va(kickmsg, player_names[i], i));
HU_AddChatText(kickmsg, false);
}
}
}
// see also SCR_DisplayMarathonInfo // see also SCR_DisplayMarathonInfo
if ((marathonmode & (MA_INIT|MA_INGAME)) == MA_INGAME && gamestate == GS_LEVEL) if ((marathonmode & (MA_INIT|MA_INGAME)) == MA_INGAME && gamestate == GS_LEVEL)
marathontime++; marathontime++;
@ -2292,23 +2313,58 @@ void G_Ticker(boolean run)
if (playeringame[i]) if (playeringame[i])
{ {
INT16 received; INT16 received;
// Save last frame's button readings
players[i].lastbuttons = players[i].cmd.buttons;
G_CopyTiccmd(&players[i].cmd, &netcmds[buf][i], 1); G_CopyTiccmd(&players[i].cmd, &netcmds[buf][i], 1);
// Bot ticcmd handling
received = (players[i].cmd.angleturn & TICCMD_RECEIVED); // Yes, ordinarily this would be handled in G_BuildTiccmd...
// ...however, bot players won't have a corresponding consoleplayer or splitscreen player 2 to send that information.
players[i].angleturn += players[i].cmd.angleturn - players[i].oldrelangleturn; // Therefore, this has to be done after ticcmd sends are received.
players[i].oldrelangleturn = players[i].cmd.angleturn; if (players[i].bot == BOT_2PAI) { // Tailsbot for P2
if (P_ControlStyle(&players[i]) == CS_LMAOGALOG) if (!players[i].powers[pw_tailsfly] && (players[i].cmd.forwardmove || players[i].cmd.sidemove || players[i].cmd.buttons))
P_ForceLocalAngle(&players[i], players[i].angleturn << 16); {
else players[i].bot = BOT_2PHUMAN; // A player-controlled bot. Returns to AI when it respawns.
players[i].cmd.angleturn = players[i].angleturn; CV_SetValue(&cv_analog[1], true);
}
players[i].cmd.angleturn &= ~TICCMD_RECEIVED; else
{
B_BuildTiccmd(&players[i], &players[i].cmd);
}
B_HandleFlightIndicator(&players[i]);
}
else if (players[i].bot == BOT_MPAI) {
B_BuildTiccmd(&players[i], &players[i].cmd);
}
// Do angle adjustments.
if (players[i].bot == BOT_NONE || players[i].bot == BOT_2PHUMAN)
{
received = (players[i].cmd.angleturn & TICCMD_RECEIVED);
players[i].angleturn += players[i].cmd.angleturn - players[i].oldrelangleturn;
players[i].oldrelangleturn = players[i].cmd.angleturn;
if (P_ControlStyle(&players[i]) == CS_LMAOGALOG)
P_ForceLocalAngle(&players[i], players[i].angleturn << 16);
else
players[i].cmd.angleturn = players[i].angleturn;
if (P_ControlStyle(&players[i]) == CS_LMAOGALOG)
P_ForceLocalAngle(&players[i], players[i].angleturn << 16);
else
players[i].cmd.angleturn = players[i].angleturn;
players[i].cmd.angleturn &= ~TICCMD_RECEIVED;
// Use the leveltime sent in the player's ticcmd to determine control lag
players[i].cmd.latency = min(((leveltime & 0xFF) - players[i].cmd.latency) & 0xFF, MAXPREDICTTICS-1);
}
else // Less work is required if we're building a bot ticcmd.
{
// Since bot TicCmd is pre-determined for both the client and server, the latency and packet checks are simplified.
received = 1;
players[i].cmd.latency = 0;
players[i].angleturn = players[i].cmd.angleturn;
players[i].oldrelangleturn = players[i].cmd.angleturn;
}
players[i].cmd.angleturn |= received; players[i].cmd.angleturn |= received;
// Use the leveltime sent in the player's ticcmd to determine control lag
players[i].cmd.latency = min(((leveltime & 0xFF) - players[i].cmd.latency) & 0xFF, MAXPREDICTTICS-1);
} }
} }
@ -2494,6 +2550,7 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
tic_t quittime; tic_t quittime;
boolean spectator; boolean spectator;
boolean outofcoop; boolean outofcoop;
boolean removing;
INT16 bot; INT16 bot;
SINT8 pity; SINT8 pity;
INT16 rings; INT16 rings;
@ -2510,6 +2567,7 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
quittime = players[player].quittime; quittime = players[player].quittime;
spectator = players[player].spectator; spectator = players[player].spectator;
outofcoop = players[player].outofcoop; outofcoop = players[player].outofcoop;
removing = players[player].removing;
pflags = (players[player].pflags & (PF_FLIPCAM|PF_ANALOGMODE|PF_DIRECTIONCHAR|PF_AUTOBRAKE|PF_TAGIT|PF_GAMETYPEOVER)); pflags = (players[player].pflags & (PF_FLIPCAM|PF_ANALOGMODE|PF_DIRECTIONCHAR|PF_AUTOBRAKE|PF_TAGIT|PF_GAMETYPEOVER));
playerangleturn = players[player].angleturn; playerangleturn = players[player].angleturn;
oldrelangleturn = players[player].oldrelangleturn; oldrelangleturn = players[player].oldrelangleturn;
@ -2586,6 +2644,7 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
p->quittime = quittime; p->quittime = quittime;
p->spectator = spectator; p->spectator = spectator;
p->outofcoop = outofcoop; p->outofcoop = outofcoop;
p->removing = removing;
p->angleturn = playerangleturn; p->angleturn = playerangleturn;
p->oldrelangleturn = oldrelangleturn; p->oldrelangleturn = oldrelangleturn;
@ -2630,8 +2689,10 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
p->totalring = totalring; p->totalring = totalring;
p->mare = mare; p->mare = mare;
if (bot) if (bot == BOT_2PHUMAN)
p->bot = 1; // reset to AI-controlled p->bot = BOT_2PAI; // reset to AI-controlled
else
p->bot = bot;
p->pity = pity; p->pity = pity;
p->rings = rings; p->rings = rings;
p->spheres = spheres; p->spheres = spheres;
@ -2977,7 +3038,8 @@ void G_DoReborn(INT32 playernum)
// Make sure objectplace is OFF when you first start the level! // Make sure objectplace is OFF when you first start the level!
OP_ResetObjectplace(); OP_ResetObjectplace();
if (player->bot && playernum != consoleplayer) // Tailsbot
if (player->bot == BOT_2PAI || player->bot == BOT_2PHUMAN)
{ // Bots respawn next to their master. { // Bots respawn next to their master.
mobj_t *oldmo = NULL; mobj_t *oldmo = NULL;
@ -2995,6 +3057,28 @@ void G_DoReborn(INT32 playernum)
return; return;
} }
// Additional players (e.g. independent bots) in Single Player
if (playernum != consoleplayer && !(netgame || multiplayer))
{
mobj_t *oldmo = NULL;
// Do nothing if out of lives
if (player->lives <= 0)
return;
// Otherwise do respawn, starting by removing the player object
if (player->mo)
{
oldmo = player->mo;
P_RemoveMobj(player->mo);
}
// Do spawning
G_SpawnPlayer(playernum);
if (oldmo)
G_ChangePlayerReferences(oldmo, players[playernum].mo);
return; //Exit function to avoid proccing other SP related mechanics
}
if (countdowntimeup || (!(netgame || multiplayer) && (gametyperules & GTR_CAMPAIGN))) if (countdowntimeup || (!(netgame || multiplayer) && (gametyperules & GTR_CAMPAIGN)))
resetlevel = true; resetlevel = true;
@ -3176,7 +3260,7 @@ void G_AddPlayer(INT32 playernum)
if (!playeringame[i]) if (!playeringame[i])
continue; continue;
if (players[i].bot) // ignore dumb, stupid tails if (players[i].bot == BOT_2PAI || players[i].bot == BOT_2PHUMAN) // ignore dumb, stupid tails
continue; continue;
countplayers++; countplayers++;
@ -3217,7 +3301,7 @@ boolean G_EnoughPlayersFinished(void)
for (i = 0; i < MAXPLAYERS; i++) for (i = 0; i < MAXPLAYERS; i++)
{ {
if (!playeringame[i] || players[i].spectator || players[i].bot) if (!playeringame[i] || players[i].spectator || players[i].bot == BOT_2PAI || players[i].bot == BOT_2PHUMAN)
continue; continue;
if (players[i].quittime > 30 * TICRATE) if (players[i].quittime > 30 * TICRATE)
continue; continue;
@ -5240,4 +5324,3 @@ INT32 G_TicsToMilliseconds(tic_t tics)
{ {
return (INT32)((tics%TICRATE) * (1000.00f/TICRATE)); return (INT32)((tics%TICRATE) * (1000.00f/TICRATE));
} }

View file

@ -41,49 +41,49 @@ INT32 joyxmove[JOYAXISSET], joyymove[JOYAXISSET], joy2xmove[JOYAXISSET], joy2ymo
UINT8 gamekeydown[NUMINPUTS]; UINT8 gamekeydown[NUMINPUTS];
// two key codes (or virtual key) per game control // two key codes (or virtual key) per game control
INT32 gamecontrol[num_gamecontrols][2]; INT32 gamecontrol[NUM_GAMECONTROLS][2];
INT32 gamecontrolbis[num_gamecontrols][2]; // secondary splitscreen player INT32 gamecontrolbis[NUM_GAMECONTROLS][2]; // secondary splitscreen player
INT32 gamecontroldefault[num_gamecontrolschemes][num_gamecontrols][2]; // default control storage, use 0 (gcs_custom) for memory retention INT32 gamecontroldefault[num_gamecontrolschemes][NUM_GAMECONTROLS][2]; // default control storage, use 0 (gcs_custom) for memory retention
INT32 gamecontrolbisdefault[num_gamecontrolschemes][num_gamecontrols][2]; INT32 gamecontrolbisdefault[num_gamecontrolschemes][NUM_GAMECONTROLS][2];
// lists of GC codes for selective operation // lists of GC codes for selective operation
const INT32 gcl_tutorial_check[num_gcl_tutorial_check] = { const INT32 gcl_tutorial_check[num_gcl_tutorial_check] = {
gc_forward, gc_backward, gc_strafeleft, gc_straferight, GC_FORWARD, GC_BACKWARD, GC_STRAFELEFT, GC_STRAFERIGHT,
gc_turnleft, gc_turnright GC_TURNLEFT, GC_TURNRIGHT
}; };
const INT32 gcl_tutorial_used[num_gcl_tutorial_used] = { const INT32 gcl_tutorial_used[num_gcl_tutorial_used] = {
gc_forward, gc_backward, gc_strafeleft, gc_straferight, GC_FORWARD, GC_BACKWARD, GC_STRAFELEFT, GC_STRAFERIGHT,
gc_turnleft, gc_turnright, GC_TURNLEFT, GC_TURNRIGHT,
gc_jump, gc_spin GC_JUMP, GC_SPIN
}; };
const INT32 gcl_tutorial_full[num_gcl_tutorial_full] = { const INT32 gcl_tutorial_full[num_gcl_tutorial_full] = {
gc_forward, gc_backward, gc_strafeleft, gc_straferight, GC_FORWARD, GC_BACKWARD, GC_STRAFELEFT, GC_STRAFERIGHT,
gc_lookup, gc_lookdown, gc_turnleft, gc_turnright, gc_centerview, GC_LOOKUP, GC_LOOKDOWN, GC_TURNLEFT, GC_TURNRIGHT, GC_CENTERVIEW,
gc_jump, gc_spin, GC_JUMP, GC_SPIN,
gc_fire, gc_firenormal GC_FIRE, GC_FIRENORMAL
}; };
const INT32 gcl_movement[num_gcl_movement] = { const INT32 gcl_movement[num_gcl_movement] = {
gc_forward, gc_backward, gc_strafeleft, gc_straferight GC_FORWARD, GC_BACKWARD, GC_STRAFELEFT, GC_STRAFERIGHT
}; };
const INT32 gcl_camera[num_gcl_camera] = { const INT32 gcl_camera[num_gcl_camera] = {
gc_turnleft, gc_turnright GC_TURNLEFT, GC_TURNRIGHT
}; };
const INT32 gcl_movement_camera[num_gcl_movement_camera] = { const INT32 gcl_movement_camera[num_gcl_movement_camera] = {
gc_forward, gc_backward, gc_strafeleft, gc_straferight, GC_FORWARD, GC_BACKWARD, GC_STRAFELEFT, GC_STRAFERIGHT,
gc_turnleft, gc_turnright GC_TURNLEFT, GC_TURNRIGHT
}; };
const INT32 gcl_jump[num_gcl_jump] = { gc_jump }; const INT32 gcl_jump[num_gcl_jump] = { GC_JUMP };
const INT32 gcl_spin[num_gcl_spin] = { gc_spin }; const INT32 gcl_spin[num_gcl_spin] = { GC_SPIN };
const INT32 gcl_jump_spin[num_gcl_jump_spin] = { const INT32 gcl_jump_spin[num_gcl_jump_spin] = {
gc_jump, gc_spin GC_JUMP, GC_SPIN
}; };
typedef struct typedef struct
@ -115,54 +115,54 @@ void G_MapEventsToControls(event_t *ev)
switch (ev->type) switch (ev->type)
{ {
case ev_keydown: case ev_keydown:
if (ev->data1 < NUMINPUTS) if (ev->key < NUMINPUTS)
gamekeydown[ev->data1] = 1; gamekeydown[ev->key] = 1;
#ifdef PARANOIA #ifdef PARANOIA
else else
{ {
CONS_Debug(DBG_GAMELOGIC, "Bad downkey input %d\n",ev->data1); CONS_Debug(DBG_GAMELOGIC, "Bad downkey input %d\n",ev->key);
} }
#endif #endif
break; break;
case ev_keyup: case ev_keyup:
if (ev->data1 < NUMINPUTS) if (ev->key < NUMINPUTS)
gamekeydown[ev->data1] = 0; gamekeydown[ev->key] = 0;
#ifdef PARANOIA #ifdef PARANOIA
else else
{ {
CONS_Debug(DBG_GAMELOGIC, "Bad upkey input %d\n",ev->data1); CONS_Debug(DBG_GAMELOGIC, "Bad upkey input %d\n",ev->key);
} }
#endif #endif
break; break;
case ev_mouse: // buttons are virtual keys case ev_mouse: // buttons are virtual keys
mouse.rdx = ev->data2; mouse.rdx = ev->x;
mouse.rdy = ev->data3; mouse.rdy = ev->y;
break; break;
case ev_joystick: // buttons are virtual keys case ev_joystick: // buttons are virtual keys
i = ev->data1; i = ev->key;
if (i >= JOYAXISSET || menuactive || CON_Ready() || chat_on) if (i >= JOYAXISSET || menuactive || CON_Ready() || chat_on)
break; break;
if (ev->data2 != INT32_MAX) joyxmove[i] = ev->data2; if (ev->x != INT32_MAX) joyxmove[i] = ev->x;
if (ev->data3 != INT32_MAX) joyymove[i] = ev->data3; if (ev->y != INT32_MAX) joyymove[i] = ev->y;
break; break;
case ev_joystick2: // buttons are virtual keys case ev_joystick2: // buttons are virtual keys
i = ev->data1; i = ev->key;
if (i >= JOYAXISSET || menuactive || CON_Ready() || chat_on) if (i >= JOYAXISSET || menuactive || CON_Ready() || chat_on)
break; break;
if (ev->data2 != INT32_MAX) joy2xmove[i] = ev->data2; if (ev->x != INT32_MAX) joy2xmove[i] = ev->x;
if (ev->data3 != INT32_MAX) joy2ymove[i] = ev->data3; if (ev->y != INT32_MAX) joy2ymove[i] = ev->y;
break; break;
case ev_mouse2: // buttons are virtual keys case ev_mouse2: // buttons are virtual keys
if (menuactive || CON_Ready() || chat_on) if (menuactive || CON_Ready() || chat_on)
break; break;
mouse2.rdx = ev->data2; mouse2.rdx = ev->x;
mouse2.rdy = ev->data3; mouse2.rdy = ev->y;
break; break;
default: default:
@ -553,9 +553,9 @@ static keyname_t keynames[] =
}; };
static const char *gamecontrolname[num_gamecontrols] = static const char *gamecontrolname[NUM_GAMECONTROLS] =
{ {
"nothing", // a key/button mapped to gc_null has no effect "nothing", // a key/button mapped to GC_NULL has no effect
"forward", "forward",
"backward", "backward",
"strafeleft", "strafeleft",
@ -613,7 +613,7 @@ void G_ClearControlKeys(INT32 (*setupcontrols)[2], INT32 control)
void G_ClearAllControlKeys(void) void G_ClearAllControlKeys(void)
{ {
INT32 i; INT32 i;
for (i = 0; i < num_gamecontrols; i++) for (i = 0; i < NUM_GAMECONTROLS; i++)
{ {
G_ClearControlKeys(gamecontrol, i); G_ClearControlKeys(gamecontrol, i);
G_ClearControlKeys(gamecontrolbis, i); G_ClearControlKeys(gamecontrolbis, i);
@ -624,7 +624,7 @@ void G_ClearAllControlKeys(void)
// Returns the name of a key (or virtual key for mouse and joy) // Returns the name of a key (or virtual key for mouse and joy)
// the input value being an keynum // the input value being an keynum
// //
const char *G_KeyNumToString(INT32 keynum) const char *G_KeyNumToName(INT32 keynum)
{ {
static char keynamestr[8]; static char keynamestr[8];
@ -648,7 +648,7 @@ const char *G_KeyNumToString(INT32 keynum)
return keynamestr; return keynamestr;
} }
INT32 G_KeyStringToNum(const char *keystr) INT32 G_KeyNameToNum(const char *keystr)
{ {
UINT32 j; UINT32 j;
@ -676,92 +676,92 @@ void G_DefineDefaultControls(void)
INT32 i; INT32 i;
// FPS game controls (WASD) // FPS game controls (WASD)
gamecontroldefault[gcs_fps][gc_forward ][0] = 'w'; gamecontroldefault[gcs_fps][GC_FORWARD ][0] = 'w';
gamecontroldefault[gcs_fps][gc_backward ][0] = 's'; gamecontroldefault[gcs_fps][GC_BACKWARD ][0] = 's';
gamecontroldefault[gcs_fps][gc_strafeleft ][0] = 'a'; gamecontroldefault[gcs_fps][GC_STRAFELEFT ][0] = 'a';
gamecontroldefault[gcs_fps][gc_straferight][0] = 'd'; gamecontroldefault[gcs_fps][GC_STRAFERIGHT][0] = 'd';
gamecontroldefault[gcs_fps][gc_lookup ][0] = KEY_UPARROW; gamecontroldefault[gcs_fps][GC_LOOKUP ][0] = KEY_UPARROW;
gamecontroldefault[gcs_fps][gc_lookdown ][0] = KEY_DOWNARROW; gamecontroldefault[gcs_fps][GC_LOOKDOWN ][0] = KEY_DOWNARROW;
gamecontroldefault[gcs_fps][gc_turnleft ][0] = KEY_LEFTARROW; gamecontroldefault[gcs_fps][GC_TURNLEFT ][0] = KEY_LEFTARROW;
gamecontroldefault[gcs_fps][gc_turnright ][0] = KEY_RIGHTARROW; gamecontroldefault[gcs_fps][GC_TURNRIGHT ][0] = KEY_RIGHTARROW;
gamecontroldefault[gcs_fps][gc_centerview ][0] = KEY_END; gamecontroldefault[gcs_fps][GC_CENTERVIEW ][0] = KEY_END;
gamecontroldefault[gcs_fps][gc_jump ][0] = KEY_SPACE; gamecontroldefault[gcs_fps][GC_JUMP ][0] = KEY_SPACE;
gamecontroldefault[gcs_fps][gc_spin ][0] = KEY_LSHIFT; gamecontroldefault[gcs_fps][GC_SPIN ][0] = KEY_LSHIFT;
gamecontroldefault[gcs_fps][gc_fire ][0] = KEY_RCTRL; gamecontroldefault[gcs_fps][GC_FIRE ][0] = KEY_RCTRL;
gamecontroldefault[gcs_fps][gc_fire ][1] = KEY_MOUSE1+0; gamecontroldefault[gcs_fps][GC_FIRE ][1] = KEY_MOUSE1+0;
gamecontroldefault[gcs_fps][gc_firenormal ][0] = 'c'; gamecontroldefault[gcs_fps][GC_FIRENORMAL ][0] = 'c';
// Platform game controls (arrow keys) // Platform game controls (arrow keys)
gamecontroldefault[gcs_platform][gc_forward ][0] = KEY_UPARROW; gamecontroldefault[gcs_platform][GC_FORWARD ][0] = KEY_UPARROW;
gamecontroldefault[gcs_platform][gc_backward ][0] = KEY_DOWNARROW; gamecontroldefault[gcs_platform][GC_BACKWARD ][0] = KEY_DOWNARROW;
gamecontroldefault[gcs_platform][gc_strafeleft ][0] = 'a'; gamecontroldefault[gcs_platform][GC_STRAFELEFT ][0] = 'a';
gamecontroldefault[gcs_platform][gc_straferight][0] = 'd'; gamecontroldefault[gcs_platform][GC_STRAFERIGHT][0] = 'd';
gamecontroldefault[gcs_platform][gc_lookup ][0] = KEY_PGUP; gamecontroldefault[gcs_platform][GC_LOOKUP ][0] = KEY_PGUP;
gamecontroldefault[gcs_platform][gc_lookdown ][0] = KEY_PGDN; gamecontroldefault[gcs_platform][GC_LOOKDOWN ][0] = KEY_PGDN;
gamecontroldefault[gcs_platform][gc_turnleft ][0] = KEY_LEFTARROW; gamecontroldefault[gcs_platform][GC_TURNLEFT ][0] = KEY_LEFTARROW;
gamecontroldefault[gcs_platform][gc_turnright ][0] = KEY_RIGHTARROW; gamecontroldefault[gcs_platform][GC_TURNRIGHT ][0] = KEY_RIGHTARROW;
gamecontroldefault[gcs_platform][gc_centerview ][0] = KEY_END; gamecontroldefault[gcs_platform][GC_CENTERVIEW ][0] = KEY_END;
gamecontroldefault[gcs_platform][gc_jump ][0] = KEY_SPACE; gamecontroldefault[gcs_platform][GC_JUMP ][0] = KEY_SPACE;
gamecontroldefault[gcs_platform][gc_spin ][0] = KEY_LSHIFT; gamecontroldefault[gcs_platform][GC_SPIN ][0] = KEY_LSHIFT;
gamecontroldefault[gcs_platform][gc_fire ][0] = 's'; gamecontroldefault[gcs_platform][GC_FIRE ][0] = 's';
gamecontroldefault[gcs_platform][gc_fire ][1] = KEY_MOUSE1+0; gamecontroldefault[gcs_platform][GC_FIRE ][1] = KEY_MOUSE1+0;
gamecontroldefault[gcs_platform][gc_firenormal ][0] = 'w'; gamecontroldefault[gcs_platform][GC_FIRENORMAL ][0] = 'w';
for (i = 1; i < num_gamecontrolschemes; i++) // skip gcs_custom (0) for (i = 1; i < num_gamecontrolschemes; i++) // skip gcs_custom (0)
{ {
gamecontroldefault[i][gc_weaponnext ][0] = KEY_MOUSEWHEELUP+0; gamecontroldefault[i][GC_WEAPONNEXT ][0] = KEY_MOUSEWHEELUP+0;
gamecontroldefault[i][gc_weaponprev ][0] = KEY_MOUSEWHEELDOWN+0; gamecontroldefault[i][GC_WEAPONPREV ][0] = KEY_MOUSEWHEELDOWN+0;
gamecontroldefault[i][gc_wepslot1 ][0] = '1'; gamecontroldefault[i][GC_WEPSLOT1 ][0] = '1';
gamecontroldefault[i][gc_wepslot2 ][0] = '2'; gamecontroldefault[i][GC_WEPSLOT2 ][0] = '2';
gamecontroldefault[i][gc_wepslot3 ][0] = '3'; gamecontroldefault[i][GC_WEPSLOT3 ][0] = '3';
gamecontroldefault[i][gc_wepslot4 ][0] = '4'; gamecontroldefault[i][GC_WEPSLOT4 ][0] = '4';
gamecontroldefault[i][gc_wepslot5 ][0] = '5'; gamecontroldefault[i][GC_WEPSLOT5 ][0] = '5';
gamecontroldefault[i][gc_wepslot6 ][0] = '6'; gamecontroldefault[i][GC_WEPSLOT6 ][0] = '6';
gamecontroldefault[i][gc_wepslot7 ][0] = '7'; gamecontroldefault[i][GC_WEPSLOT7 ][0] = '7';
gamecontroldefault[i][gc_wepslot8 ][0] = '8'; gamecontroldefault[i][GC_WEPSLOT8 ][0] = '8';
gamecontroldefault[i][gc_wepslot9 ][0] = '9'; gamecontroldefault[i][GC_WEPSLOT9 ][0] = '9';
gamecontroldefault[i][gc_wepslot10 ][0] = '0'; gamecontroldefault[i][GC_WEPSLOT10 ][0] = '0';
gamecontroldefault[i][gc_tossflag ][0] = '\''; gamecontroldefault[i][GC_TOSSFLAG ][0] = '\'';
gamecontroldefault[i][gc_camtoggle ][0] = 'v'; gamecontroldefault[i][GC_CAMTOGGLE ][0] = 'v';
gamecontroldefault[i][gc_camreset ][0] = 'r'; gamecontroldefault[i][GC_CAMRESET ][0] = 'r';
gamecontroldefault[i][gc_talkkey ][0] = 't'; gamecontroldefault[i][GC_TALKKEY ][0] = 't';
gamecontroldefault[i][gc_teamkey ][0] = 'y'; gamecontroldefault[i][GC_TEAMKEY ][0] = 'y';
gamecontroldefault[i][gc_scores ][0] = KEY_TAB; gamecontroldefault[i][GC_SCORES ][0] = KEY_TAB;
gamecontroldefault[i][gc_console ][0] = KEY_CONSOLE; gamecontroldefault[i][GC_CONSOLE ][0] = KEY_CONSOLE;
gamecontroldefault[i][gc_pause ][0] = 'p'; gamecontroldefault[i][GC_PAUSE ][0] = 'p';
gamecontroldefault[i][gc_screenshot ][0] = KEY_F8; gamecontroldefault[i][GC_SCREENSHOT ][0] = KEY_F8;
gamecontroldefault[i][gc_recordgif ][0] = KEY_F9; gamecontroldefault[i][GC_RECORDGIF ][0] = KEY_F9;
gamecontroldefault[i][gc_viewpoint ][0] = KEY_F12; gamecontroldefault[i][GC_VIEWPOINT ][0] = KEY_F12;
// Gamepad controls -- same for both schemes // Gamepad controls -- same for both schemes
gamecontroldefault[i][gc_weaponnext ][1] = KEY_JOY1+1; // B gamecontroldefault[i][GC_WEAPONNEXT ][1] = KEY_JOY1+1; // B
gamecontroldefault[i][gc_weaponprev ][1] = KEY_JOY1+2; // X gamecontroldefault[i][GC_WEAPONPREV ][1] = KEY_JOY1+2; // X
gamecontroldefault[i][gc_tossflag ][1] = KEY_JOY1+0; // A gamecontroldefault[i][GC_TOSSFLAG ][1] = KEY_JOY1+0; // A
gamecontroldefault[i][gc_spin ][1] = KEY_JOY1+4; // LB gamecontroldefault[i][GC_SPIN ][1] = KEY_JOY1+4; // LB
gamecontroldefault[i][gc_camtoggle ][1] = KEY_HAT1+0; // D-Pad Up gamecontroldefault[i][GC_CAMTOGGLE ][1] = KEY_HAT1+0; // D-Pad Up
gamecontroldefault[i][gc_camreset ][1] = KEY_JOY1+3; // Y gamecontroldefault[i][GC_CAMRESET ][1] = KEY_JOY1+3; // Y
gamecontroldefault[i][gc_centerview ][1] = KEY_JOY1+9; // Right Stick gamecontroldefault[i][GC_CENTERVIEW ][1] = KEY_JOY1+9; // Right Stick
gamecontroldefault[i][gc_talkkey ][1] = KEY_HAT1+2; // D-Pad Left gamecontroldefault[i][GC_TALKKEY ][1] = KEY_HAT1+2; // D-Pad Left
gamecontroldefault[i][gc_scores ][1] = KEY_HAT1+3; // D-Pad Right gamecontroldefault[i][GC_SCORES ][1] = KEY_HAT1+3; // D-Pad Right
gamecontroldefault[i][gc_jump ][1] = KEY_JOY1+5; // RB gamecontroldefault[i][GC_JUMP ][1] = KEY_JOY1+5; // RB
gamecontroldefault[i][gc_pause ][1] = KEY_JOY1+6; // Back gamecontroldefault[i][GC_PAUSE ][1] = KEY_JOY1+6; // Back
gamecontroldefault[i][gc_screenshot ][1] = KEY_HAT1+1; // D-Pad Down gamecontroldefault[i][GC_SCREENSHOT ][1] = KEY_HAT1+1; // D-Pad Down
gamecontroldefault[i][gc_systemmenu ][0] = KEY_JOY1+7; // Start gamecontroldefault[i][GC_SYSTEMMENU ][0] = KEY_JOY1+7; // Start
// Second player controls only have joypad defaults // Second player controls only have joypad defaults
gamecontrolbisdefault[i][gc_weaponnext][0] = KEY_2JOY1+1; // B gamecontrolbisdefault[i][GC_WEAPONNEXT][0] = KEY_2JOY1+1; // B
gamecontrolbisdefault[i][gc_weaponprev][0] = KEY_2JOY1+2; // X gamecontrolbisdefault[i][GC_WEAPONPREV][0] = KEY_2JOY1+2; // X
gamecontrolbisdefault[i][gc_tossflag ][0] = KEY_2JOY1+0; // A gamecontrolbisdefault[i][GC_TOSSFLAG ][0] = KEY_2JOY1+0; // A
gamecontrolbisdefault[i][gc_spin ][0] = KEY_2JOY1+4; // LB gamecontrolbisdefault[i][GC_SPIN ][0] = KEY_2JOY1+4; // LB
gamecontrolbisdefault[i][gc_camreset ][0] = KEY_2JOY1+3; // Y gamecontrolbisdefault[i][GC_CAMRESET ][0] = KEY_2JOY1+3; // Y
gamecontrolbisdefault[i][gc_centerview][0] = KEY_2JOY1+9; // Right Stick gamecontrolbisdefault[i][GC_CENTERVIEW][0] = KEY_2JOY1+9; // Right Stick
gamecontrolbisdefault[i][gc_jump ][0] = KEY_2JOY1+5; // RB gamecontrolbisdefault[i][GC_JUMP ][0] = KEY_2JOY1+5; // RB
//gamecontrolbisdefault[i][gc_pause ][0] = KEY_2JOY1+6; // Back //gamecontrolbisdefault[i][GC_PAUSE ][0] = KEY_2JOY1+6; // Back
//gamecontrolbisdefault[i][gc_systemmenu][0] = KEY_2JOY1+7; // Start //gamecontrolbisdefault[i][GC_SYSTEMMENU][0] = KEY_2JOY1+7; // Start
gamecontrolbisdefault[i][gc_camtoggle ][0] = KEY_2HAT1+0; // D-Pad Up gamecontrolbisdefault[i][GC_CAMTOGGLE ][0] = KEY_2HAT1+0; // D-Pad Up
gamecontrolbisdefault[i][gc_screenshot][0] = KEY_2HAT1+1; // D-Pad Down gamecontrolbisdefault[i][GC_SCREENSHOT][0] = KEY_2HAT1+1; // D-Pad Down
//gamecontrolbisdefault[i][gc_talkkey ][0] = KEY_2HAT1+2; // D-Pad Left //gamecontrolbisdefault[i][GC_TALKKEY ][0] = KEY_2HAT1+2; // D-Pad Left
//gamecontrolbisdefault[i][gc_scores ][0] = KEY_2HAT1+3; // D-Pad Right //gamecontrolbisdefault[i][GC_SCORES ][0] = KEY_2HAT1+3; // D-Pad Right
} }
} }
@ -773,7 +773,7 @@ INT32 G_GetControlScheme(INT32 (*fromcontrols)[2], const INT32 *gclist, INT32 gc
for (i = 1; i < num_gamecontrolschemes; i++) // skip gcs_custom (0) for (i = 1; i < num_gamecontrolschemes; i++) // skip gcs_custom (0)
{ {
skipscheme = false; skipscheme = false;
for (j = 0; j < (gclist && gclen ? gclen : num_gamecontrols); j++) for (j = 0; j < (gclist && gclen ? gclen : NUM_GAMECONTROLS); j++)
{ {
gc = (gclist && gclen) ? gclist[j] : j; gc = (gclist && gclen) ? gclist[j] : j;
if (((fromcontrols[gc][0] && gamecontroldefault[i][gc][0]) ? fromcontrols[gc][0] != gamecontroldefault[i][gc][0] : true) && if (((fromcontrols[gc][0] && gamecontroldefault[i][gc][0]) ? fromcontrols[gc][0] != gamecontroldefault[i][gc][0] : true) &&
@ -796,7 +796,7 @@ void G_CopyControls(INT32 (*setupcontrols)[2], INT32 (*fromcontrols)[2], const I
{ {
INT32 i, gc; INT32 i, gc;
for (i = 0; i < (gclist && gclen ? gclen : num_gamecontrols); i++) for (i = 0; i < (gclist && gclen ? gclen : NUM_GAMECONTROLS); i++)
{ {
gc = (gclist && gclen) ? gclist[i] : i; gc = (gclist && gclen) ? gclist[i] : i;
setupcontrols[gc][0] = fromcontrols[gc][0]; setupcontrols[gc][0] = fromcontrols[gc][0];
@ -808,24 +808,24 @@ void G_SaveKeySetting(FILE *f, INT32 (*fromcontrols)[2], INT32 (*fromcontrolsbis
{ {
INT32 i; INT32 i;
for (i = 1; i < num_gamecontrols; i++) for (i = 1; i < NUM_GAMECONTROLS; i++)
{ {
fprintf(f, "setcontrol \"%s\" \"%s\"", gamecontrolname[i], fprintf(f, "setcontrol \"%s\" \"%s\"", gamecontrolname[i],
G_KeyNumToString(fromcontrols[i][0])); G_KeyNumToName(fromcontrols[i][0]));
if (fromcontrols[i][1]) if (fromcontrols[i][1])
fprintf(f, " \"%s\"\n", G_KeyNumToString(fromcontrols[i][1])); fprintf(f, " \"%s\"\n", G_KeyNumToName(fromcontrols[i][1]));
else else
fprintf(f, "\n"); fprintf(f, "\n");
} }
for (i = 1; i < num_gamecontrols; i++) for (i = 1; i < NUM_GAMECONTROLS; i++)
{ {
fprintf(f, "setcontrol2 \"%s\" \"%s\"", gamecontrolname[i], fprintf(f, "setcontrol2 \"%s\" \"%s\"", gamecontrolname[i],
G_KeyNumToString(fromcontrolsbis[i][0])); G_KeyNumToName(fromcontrolsbis[i][0]));
if (fromcontrolsbis[i][1]) if (fromcontrolsbis[i][1])
fprintf(f, " \"%s\"\n", G_KeyNumToString(fromcontrolsbis[i][1])); fprintf(f, " \"%s\"\n", G_KeyNumToName(fromcontrolsbis[i][1]));
else else
fprintf(f, "\n"); fprintf(f, "\n");
} }
@ -833,11 +833,11 @@ void G_SaveKeySetting(FILE *f, INT32 (*fromcontrols)[2], INT32 (*fromcontrolsbis
INT32 G_CheckDoubleUsage(INT32 keynum, boolean modify) INT32 G_CheckDoubleUsage(INT32 keynum, boolean modify)
{ {
INT32 result = gc_null; INT32 result = GC_NULL;
if (cv_controlperkey.value == 1) if (cv_controlperkey.value == 1)
{ {
INT32 i; INT32 i;
for (i = 0; i < num_gamecontrols; i++) for (i = 0; i < NUM_GAMECONTROLS; i++)
{ {
if (gamecontrol[i][0] == keynum) if (gamecontrol[i][0] == keynum)
{ {
@ -883,11 +883,11 @@ static INT32 G_FilterKeyByVersion(INT32 numctrl, INT32 keyidx, INT32 player, INT
return -1; // skip setting control return -1; // skip setting control
if (GETMAJOREXECVERSION(cv_execversion.value) < 27 && ( // v2.1.22 if (GETMAJOREXECVERSION(cv_execversion.value) < 27 && ( // v2.1.22
numctrl == gc_weaponnext || numctrl == gc_weaponprev || numctrl == gc_tossflag || numctrl == GC_WEAPONNEXT || numctrl == GC_WEAPONPREV || numctrl == GC_TOSSFLAG ||
numctrl == gc_spin || numctrl == gc_camreset || numctrl == gc_jump || numctrl == GC_SPIN || numctrl == GC_CAMRESET || numctrl == GC_JUMP ||
numctrl == gc_pause || numctrl == gc_systemmenu || numctrl == gc_camtoggle || numctrl == GC_PAUSE || numctrl == GC_SYSTEMMENU || numctrl == GC_CAMTOGGLE ||
numctrl == gc_screenshot || numctrl == gc_talkkey || numctrl == gc_scores || numctrl == GC_SCREENSHOT || numctrl == GC_TALKKEY || numctrl == GC_SCORES ||
numctrl == gc_centerview numctrl == GC_CENTERVIEW
)) ))
{ {
INT32 keynum = 0, existingctrl = 0; INT32 keynum = 0, existingctrl = 0;
@ -895,7 +895,7 @@ static INT32 G_FilterKeyByVersion(INT32 numctrl, INT32 keyidx, INT32 player, INT
boolean defaultoverride = false; boolean defaultoverride = false;
// get the default gamecontrol // get the default gamecontrol
if (player == 0 && numctrl == gc_systemmenu) if (player == 0 && numctrl == GC_SYSTEMMENU)
defaultkey = gamecontrol[numctrl][0]; defaultkey = gamecontrol[numctrl][0];
else else
defaultkey = (player == 1 ? gamecontrolbis[numctrl][0] : gamecontrol[numctrl][1]); defaultkey = (player == 1 ? gamecontrolbis[numctrl][0] : gamecontrol[numctrl][1]);
@ -993,16 +993,16 @@ static void setcontrol(INT32 (*gc)[2])
// Update me for 2.3 // Update me for 2.3
namectrl = (stricmp(COM_Argv(1), "use")) ? COM_Argv(1) : "spin"; namectrl = (stricmp(COM_Argv(1), "use")) ? COM_Argv(1) : "spin";
for (numctrl = 0; numctrl < num_gamecontrols && stricmp(namectrl, gamecontrolname[numctrl]); for (numctrl = 0; numctrl < NUM_GAMECONTROLS && stricmp(namectrl, gamecontrolname[numctrl]);
numctrl++) numctrl++)
; ;
if (numctrl == num_gamecontrols) if (numctrl == NUM_GAMECONTROLS)
{ {
CONS_Printf(M_GetText("Control '%s' unknown\n"), namectrl); CONS_Printf(M_GetText("Control '%s' unknown\n"), namectrl);
return; return;
} }
keynum1 = G_KeyStringToNum(COM_Argv(2)); keynum1 = G_KeyNameToNum(COM_Argv(2));
keynum2 = G_KeyStringToNum(COM_Argv(3)); keynum2 = G_KeyNameToNum(COM_Argv(3));
keynum = G_FilterKeyByVersion(numctrl, 0, player, &keynum1, &keynum2, &nestedoverride); keynum = G_FilterKeyByVersion(numctrl, 0, player, &keynum1, &keynum2, &nestedoverride);
if (keynum >= 0) if (keynum >= 0)

View file

@ -58,49 +58,49 @@ typedef enum
typedef enum typedef enum
{ {
gc_null = 0, // a key/button mapped to gc_null has no effect GC_NULL = 0, // a key/button mapped to GC_NULL has no effect
gc_forward, GC_FORWARD,
gc_backward, GC_BACKWARD,
gc_strafeleft, GC_STRAFELEFT,
gc_straferight, GC_STRAFERIGHT,
gc_turnleft, GC_TURNLEFT,
gc_turnright, GC_TURNRIGHT,
gc_weaponnext, GC_WEAPONNEXT,
gc_weaponprev, GC_WEAPONPREV,
gc_wepslot1, GC_WEPSLOT1,
gc_wepslot2, GC_WEPSLOT2,
gc_wepslot3, GC_WEPSLOT3,
gc_wepslot4, GC_WEPSLOT4,
gc_wepslot5, GC_WEPSLOT5,
gc_wepslot6, GC_WEPSLOT6,
gc_wepslot7, GC_WEPSLOT7,
gc_wepslot8, GC_WEPSLOT8,
gc_wepslot9, GC_WEPSLOT9,
gc_wepslot10, GC_WEPSLOT10,
gc_fire, GC_FIRE,
gc_firenormal, GC_FIRENORMAL,
gc_tossflag, GC_TOSSFLAG,
gc_spin, GC_SPIN,
gc_camtoggle, GC_CAMTOGGLE,
gc_camreset, GC_CAMRESET,
gc_lookup, GC_LOOKUP,
gc_lookdown, GC_LOOKDOWN,
gc_centerview, GC_CENTERVIEW,
gc_mouseaiming, // mouse aiming is momentary (toggleable in the menu) GC_MOUSEAIMING, // mouse aiming is momentary (toggleable in the menu)
gc_talkkey, GC_TALKKEY,
gc_teamkey, GC_TEAMKEY,
gc_scores, GC_SCORES,
gc_jump, GC_JUMP,
gc_console, GC_CONSOLE,
gc_pause, GC_PAUSE,
gc_systemmenu, GC_SYSTEMMENU,
gc_screenshot, GC_SCREENSHOT,
gc_recordgif, GC_RECORDGIF,
gc_viewpoint, GC_VIEWPOINT,
gc_custom1, // Lua scriptable GC_CUSTOM1, // Lua scriptable
gc_custom2, // Lua scriptable GC_CUSTOM2, // Lua scriptable
gc_custom3, // Lua scriptable GC_CUSTOM3, // Lua scriptable
num_gamecontrols NUM_GAMECONTROLS
} gamecontrols_e; } gamecontrols_e;
typedef enum typedef enum
@ -146,10 +146,10 @@ extern INT32 joyxmove[JOYAXISSET], joyymove[JOYAXISSET], joy2xmove[JOYAXISSET],
extern UINT8 gamekeydown[NUMINPUTS]; extern UINT8 gamekeydown[NUMINPUTS];
// two key codes (or virtual key) per game control // two key codes (or virtual key) per game control
extern INT32 gamecontrol[num_gamecontrols][2]; extern INT32 gamecontrol[NUM_GAMECONTROLS][2];
extern INT32 gamecontrolbis[num_gamecontrols][2]; // secondary splitscreen player extern INT32 gamecontrolbis[NUM_GAMECONTROLS][2]; // secondary splitscreen player
extern INT32 gamecontroldefault[num_gamecontrolschemes][num_gamecontrols][2]; // default control storage, use 0 (gcs_custom) for memory retention extern INT32 gamecontroldefault[num_gamecontrolschemes][NUM_GAMECONTROLS][2]; // default control storage, use 0 (gcs_custom) for memory retention
extern INT32 gamecontrolbisdefault[num_gamecontrolschemes][num_gamecontrols][2]; extern INT32 gamecontrolbisdefault[num_gamecontrolschemes][NUM_GAMECONTROLS][2];
#define PLAYER1INPUTDOWN(gc) (gamekeydown[gamecontrol[gc][0]] || gamekeydown[gamecontrol[gc][1]]) #define PLAYER1INPUTDOWN(gc) (gamekeydown[gamecontrol[gc][0]] || gamekeydown[gamecontrol[gc][1]])
#define PLAYER2INPUTDOWN(gc) (gamekeydown[gamecontrolbis[gc][0]] || gamekeydown[gamecontrolbis[gc][1]]) #define PLAYER2INPUTDOWN(gc) (gamekeydown[gamecontrolbis[gc][0]] || gamekeydown[gamecontrolbis[gc][1]])
#define PLAYERINPUTDOWN(p, gc) ((p) == 2 ? PLAYER2INPUTDOWN(gc) : PLAYER1INPUTDOWN(gc)) #define PLAYERINPUTDOWN(p, gc) ((p) == 2 ? PLAYER2INPUTDOWN(gc) : PLAYER1INPUTDOWN(gc))
@ -181,8 +181,8 @@ extern const INT32 gcl_jump_spin[num_gcl_jump_spin];
void G_MapEventsToControls(event_t *ev); void G_MapEventsToControls(event_t *ev);
// returns the name of a key // returns the name of a key
const char *G_KeyNumToString(INT32 keynum); const char *G_KeyNumToName(INT32 keynum);
INT32 G_KeyStringToNum(const char *keystr); INT32 G_KeyNameToNum(const char *keystr);
// detach any keys associated to the given game control // detach any keys associated to the given game control
void G_ClearControlKeys(INT32 (*setupcontrols)[2], INT32 control); void G_ClearControlKeys(INT32 (*setupcontrols)[2], INT32 control);

View file

@ -317,7 +317,7 @@ void HWR_DrawStretchyFixedPatch(patch_t *gpatch, fixed_t x, fixed_t y, fixed_t p
} }
} }
if (pscale != FRACUNIT || (splitscreen && option & V_PERPLAYER)) if (pscale != FRACUNIT || vscale != FRACUNIT || (splitscreen && option & V_PERPLAYER))
{ {
fwidth = (float)(gpatch->width) * fscalew * dupx; fwidth = (float)(gpatch->width) * fscalew * dupx;
fheight = (float)(gpatch->height) * fscaleh * dupy; fheight = (float)(gpatch->height) * fscaleh * dupy;
@ -382,7 +382,7 @@ void HWR_DrawStretchyFixedPatch(patch_t *gpatch, fixed_t x, fixed_t y, fixed_t p
HWD.pfnDrawPolygon(NULL, v, 4, flags); HWD.pfnDrawPolygon(NULL, v, 4, flags);
} }
void HWR_DrawCroppedPatch(patch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscale, INT32 option, fixed_t sx, fixed_t sy, fixed_t w, fixed_t h) void HWR_DrawCroppedPatch(patch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscale, fixed_t vscale, INT32 option, const UINT8 *colormap, fixed_t sx, fixed_t sy, fixed_t w, fixed_t h)
{ {
FOutVector v[4]; FOutVector v[4];
FBITFIELD flags; FBITFIELD flags;
@ -395,13 +395,19 @@ void HWR_DrawCroppedPatch(patch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscale,
// | /| // | /|
// |/ | // |/ |
// 0--1 // 0--1
float dupx, dupy, fscale, fwidth, fheight; float dupx, dupy, fscalew, fscaleh, fwidth, fheight;
UINT8 perplayershuffle = 0;
if (alphalevel >= 10 && alphalevel < 13) if (alphalevel >= 10 && alphalevel < 13)
return; return;
// make patch ready in hardware cache // make patch ready in hardware cache
HWR_GetPatch(gpatch); if (!colormap)
HWR_GetPatch(gpatch);
else
HWR_GetMappedPatch(gpatch, colormap);
hwrPatch = ((GLPatch_t *)gpatch->hardware); hwrPatch = ((GLPatch_t *)gpatch->hardware);
dupx = (float)vid.dupx; dupx = (float)vid.dupx;
@ -423,12 +429,80 @@ void HWR_DrawCroppedPatch(patch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscale,
} }
dupx = dupy = (dupx < dupy ? dupx : dupy); dupx = dupy = (dupx < dupy ? dupx : dupy);
fscale = FIXED_TO_FLOAT(pscale); fscalew = fscaleh = FIXED_TO_FLOAT(pscale);
if (vscale != pscale)
fscaleh = FIXED_TO_FLOAT(vscale);
// fuck it, no GL support for croppedpatch v_perplayer right now. it's not like it's accessible to Lua or anything, and we only use it for menus... cx -= (float)(gpatch->leftoffset) * fscalew;
cy -= (float)(gpatch->topoffset) * fscaleh;
cy -= (float)(gpatch->topoffset) * fscale; if (splitscreen && (option & V_PERPLAYER))
cx -= (float)(gpatch->leftoffset) * fscale; {
float adjusty = ((option & V_NOSCALESTART) ? vid.height : BASEVIDHEIGHT)/2.0f;
fscaleh /= 2;
cy /= 2;
#ifdef QUADS
if (splitscreen > 1) // 3 or 4 players
{
float adjustx = ((option & V_NOSCALESTART) ? vid.width : BASEVIDWIDTH)/2.0f;
fscalew /= 2;
cx /= 2;
if (stplyr == &players[displayplayer])
{
if (!(option & (V_SNAPTOTOP|V_SNAPTOBOTTOM)))
perplayershuffle |= 1;
if (!(option & (V_SNAPTOLEFT|V_SNAPTORIGHT)))
perplayershuffle |= 4;
option &= ~V_SNAPTOBOTTOM|V_SNAPTORIGHT;
}
else if (stplyr == &players[secondarydisplayplayer])
{
if (!(option & (V_SNAPTOTOP|V_SNAPTOBOTTOM)))
perplayershuffle |= 1;
if (!(option & (V_SNAPTOLEFT|V_SNAPTORIGHT)))
perplayershuffle |= 8;
cx += adjustx;
option &= ~V_SNAPTOBOTTOM|V_SNAPTOLEFT;
}
else if (stplyr == &players[thirddisplayplayer])
{
if (!(option & (V_SNAPTOTOP|V_SNAPTOBOTTOM)))
perplayershuffle |= 2;
if (!(option & (V_SNAPTOLEFT|V_SNAPTORIGHT)))
perplayershuffle |= 4;
cy += adjusty;
option &= ~V_SNAPTOTOP|V_SNAPTORIGHT;
}
else if (stplyr == &players[fourthdisplayplayer])
{
if (!(option & (V_SNAPTOTOP|V_SNAPTOBOTTOM)))
perplayershuffle |= 2;
if (!(option & (V_SNAPTOLEFT|V_SNAPTORIGHT)))
perplayershuffle |= 8;
cx += adjustx;
cy += adjusty;
option &= ~V_SNAPTOTOP|V_SNAPTOLEFT;
}
}
else
#endif
// 2 players
{
if (stplyr == &players[displayplayer])
{
if (!(option & (V_SNAPTOTOP|V_SNAPTOBOTTOM)))
perplayershuffle = 1;
option &= ~V_SNAPTOBOTTOM;
}
else //if (stplyr == &players[secondarydisplayplayer])
{
if (!(option & (V_SNAPTOTOP|V_SNAPTOBOTTOM)))
perplayershuffle = 2;
cy += adjusty;
option &= ~V_SNAPTOTOP;
}
}
}
if (!(option & V_NOSCALESTART)) if (!(option & V_NOSCALESTART))
{ {
@ -447,6 +521,10 @@ void HWR_DrawCroppedPatch(patch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscale,
cx += ((float)vid.width - ((float)BASEVIDWIDTH * dupx)); cx += ((float)vid.width - ((float)BASEVIDWIDTH * dupx));
else if (!(option & V_SNAPTOLEFT)) else if (!(option & V_SNAPTOLEFT))
cx += ((float)vid.width - ((float)BASEVIDWIDTH * dupx))/2; cx += ((float)vid.width - ((float)BASEVIDWIDTH * dupx))/2;
if (perplayershuffle & 4)
cx -= ((float)vid.width - ((float)BASEVIDWIDTH * dupx))/4;
else if (perplayershuffle & 8)
cx += ((float)vid.width - ((float)BASEVIDWIDTH * dupx))/4;
} }
if (fabsf((float)vid.height - (float)BASEVIDHEIGHT * dupy) > 1.0E-36f) if (fabsf((float)vid.height - (float)BASEVIDHEIGHT * dupy) > 1.0E-36f)
{ {
@ -454,23 +532,27 @@ void HWR_DrawCroppedPatch(patch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscale,
cy += ((float)vid.height - ((float)BASEVIDHEIGHT * dupy)); cy += ((float)vid.height - ((float)BASEVIDHEIGHT * dupy));
else if (!(option & V_SNAPTOTOP)) else if (!(option & V_SNAPTOTOP))
cy += ((float)vid.height - ((float)BASEVIDHEIGHT * dupy))/2; cy += ((float)vid.height - ((float)BASEVIDHEIGHT * dupy))/2;
if (perplayershuffle & 1)
cy -= ((float)vid.height - ((float)BASEVIDHEIGHT * dupy))/4;
else if (perplayershuffle & 2)
cy += ((float)vid.height - ((float)BASEVIDHEIGHT * dupy))/4;
} }
} }
} }
fwidth = w; fwidth = FIXED_TO_FLOAT(w);
fheight = h; fheight = FIXED_TO_FLOAT(h);
if (sx + w > gpatch->width) if (sx + w > gpatch->width<<FRACBITS)
fwidth = gpatch->width - sx; fwidth = FIXED_TO_FLOAT((gpatch->width<<FRACBITS) - sx);
if (sy + h > gpatch->height) if (sy + h > gpatch->height<<FRACBITS)
fheight = gpatch->height - sy; fheight = FIXED_TO_FLOAT((gpatch->height<<FRACBITS) - sy);
if (pscale != FRACUNIT) if (pscale != FRACUNIT || vscale != FRACUNIT || (splitscreen && option & V_PERPLAYER))
{ {
fwidth *= fscale * dupx; fwidth *= fscalew * dupx;
fheight *= fscale * dupy; fheight *= fscaleh * dupy;
} }
else else
{ {
@ -495,17 +577,17 @@ void HWR_DrawCroppedPatch(patch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscale,
v[0].z = v[1].z = v[2].z = v[3].z = 1.0f; v[0].z = v[1].z = v[2].z = v[3].z = 1.0f;
v[0].s = v[3].s = ((sx)/(float)(gpatch->width))*hwrPatch->max_s; v[0].s = v[3].s = (FIXED_TO_FLOAT(sx)/(float)(gpatch->width))*hwrPatch->max_s;
if (sx + w > gpatch->width) if (sx + w > gpatch->width<<FRACBITS)
v[2].s = v[1].s = hwrPatch->max_s; v[2].s = v[1].s = hwrPatch->max_s;
else else
v[2].s = v[1].s = ((sx+w)/(float)(gpatch->width))*hwrPatch->max_s; v[2].s = v[1].s = (FIXED_TO_FLOAT(sx+w)/(float)(gpatch->width))*hwrPatch->max_s;
v[0].t = v[1].t = ((sy)/(float)(gpatch->height))*hwrPatch->max_t; v[0].t = v[1].t = (FIXED_TO_FLOAT(sy)/(float)(gpatch->height))*hwrPatch->max_t;
if (sy + h > gpatch->height) if (sy + h > gpatch->height<<FRACBITS)
v[2].t = v[3].t = hwrPatch->max_t; v[2].t = v[3].t = hwrPatch->max_t;
else else
v[2].t = v[3].t = ((sy+h)/(float)(gpatch->height))*hwrPatch->max_t; v[2].t = v[3].t = (FIXED_TO_FLOAT(sy+h)/(float)(gpatch->height))*hwrPatch->max_t;
flags = PF_Translucent|PF_NoDepthTest; flags = PF_Translucent|PF_NoDepthTest;
@ -514,6 +596,76 @@ void HWR_DrawCroppedPatch(patch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscale,
if (option & V_WRAPY) if (option & V_WRAPY)
flags |= PF_ForceWrapY; flags |= PF_ForceWrapY;
// Auto-crop at splitscreen borders!
if (splitscreen && (option & V_PERPLAYER))
{
#define flerp(a,b,amount) (((a) * (1.0f - (amount))) + ((b) * (amount))) // Float lerp
#ifdef QUADS
if (splitscreen > 1) // 3 or 4 players
{
#error Auto-cropping doesnt take quadscreen into account! Fix it!
// Hint: For player 1/2, copy player 1's code below. For player 3/4, copy player 2's code below
// For player 1/3 and 2/4, mangle the below code to apply horizontally instead of vertically
}
else
#endif
// 2 players
{
if (stplyr == &players[displayplayer]) // Player 1's screen, crop at the bottom
{
if ((cy - fheight) < 0) // If the bottom is below the border
{
if (cy <= 0) // If the whole patch is beyond the border...
return; // ...crop away the entire patch, don't draw anything
if (fheight <= 0) // Don't divide by zero
return;
v[2].y = v[3].y = 0; // Clamp the polygon edge vertex position
// Now for the UV-map... Uh-oh, math time!
// On second thought, a basic linear interpolation suffices
//float full_height = fheight;
//float cropped_height = fheight - cy;
//float remaining_height = cy;
//float cropped_percentage = (fheight - cy) / fheight;
//float remaining_percentage = cy / fheight;
//v[2].t = v[3].t = lerp(v[2].t, v[0].t, cropped_percentage);
// By swapping v[2] and v[0], we can use remaining_percentage for less operations
//v[2].t = v[3].t = lerp(v[0].t, v[2].t, remaining_percentage);
v[2].t = v[3].t = flerp(v[0].t, v[2].t, cy/fheight);
}
}
else //if (stplyr == &players[secondarydisplayplayer]) // Player 2's screen, crop at the top
{
if (cy > 0) // If the top is above the border
{
if ((cy - fheight) >= 0) // If the whole patch is beyond the border...
return; // ...crop away the entire patch, don't draw anything
if (fheight <= 0) // Don't divide by zero
return;
v[0].y = v[1].y = 0; // Clamp the polygon edge vertex position
// Now for the UV-map... Uh-oh, math time!
// On second thought, a basic linear interpolation suffices
//float full_height = fheight;
//float cropped_height = cy;
//float remaining_height = fheight - cy;
//float cropped_percentage = cy / fheight;
//float remaining_percentage = (fheight - cy) / fheight;
//v[0].t = v[1].t = lerp(v[0].t, v[2].t, cropped_percentage);
v[0].t = v[1].t = flerp(v[0].t, v[2].t, cy/fheight);
}
}
}
#undef flerp
}
// clip it since it is used for bunny scroll in doom I // clip it since it is used for bunny scroll in doom I
if (alphalevel) if (alphalevel)
{ {

View file

@ -6767,7 +6767,7 @@ void HWR_LoadAllCustomShaders(void)
// read every custom shader // read every custom shader
for (i = 0; i < numwadfiles; i++) for (i = 0; i < numwadfiles; i++)
HWR_LoadCustomShadersFromFile(i, (wadfiles[i]->type == RET_PK3)); HWR_LoadCustomShadersFromFile(i, W_FileHasFolders(wadfiles[i]));
} }
void HWR_LoadCustomShadersFromFile(UINT16 wadnum, boolean PK3) void HWR_LoadCustomShadersFromFile(UINT16 wadnum, boolean PK3)

View file

@ -39,7 +39,7 @@ void HWR_InitTextureMapping(void);
void HWR_SetViewSize(void); void HWR_SetViewSize(void);
void HWR_DrawPatch(patch_t *gpatch, INT32 x, INT32 y, INT32 option); void HWR_DrawPatch(patch_t *gpatch, INT32 x, INT32 y, INT32 option);
void HWR_DrawStretchyFixedPatch(patch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscale, fixed_t vscale, INT32 option, const UINT8 *colormap); void HWR_DrawStretchyFixedPatch(patch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscale, fixed_t vscale, INT32 option, const UINT8 *colormap);
void HWR_DrawCroppedPatch(patch_t *gpatch, fixed_t x, fixed_t y, fixed_t scale, INT32 option, fixed_t sx, fixed_t sy, fixed_t w, fixed_t h); void HWR_DrawCroppedPatch(patch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscale, fixed_t vscale, INT32 option, const UINT8 *colormap, fixed_t sx, fixed_t sy, fixed_t w, fixed_t h);
void HWR_MakePatch(const patch_t *patch, GLPatch_t *grPatch, GLMipmap_t *grMipmap, boolean makebitmap); void HWR_MakePatch(const patch_t *patch, GLPatch_t *grPatch, GLMipmap_t *grMipmap, boolean makebitmap);
void HWR_CreatePlanePolygons(INT32 bspnum); void HWR_CreatePlanePolygons(INT32 bspnum);
void HWR_CreateStaticLightmaps(INT32 bspnum); void HWR_CreateStaticLightmaps(INT32 bspnum);

View file

@ -62,6 +62,9 @@ static FBITFIELD CurrentPolyFlags;
static FTextureInfo *TexCacheTail = NULL; static FTextureInfo *TexCacheTail = NULL;
static FTextureInfo *TexCacheHead = NULL; static FTextureInfo *TexCacheHead = NULL;
static RGBA_t *textureBuffer = NULL;
static size_t textureBufferSize = 0;
RGBA_t myPaletteData[256]; RGBA_t myPaletteData[256];
GLint screen_width = 0; // used by Draw2DLine() GLint screen_width = 0; // used by Draw2DLine()
GLint screen_height = 0; GLint screen_height = 0;
@ -131,7 +134,6 @@ static const GLfloat byte2float[256] = {
// -----------------+ // -----------------+
// GL_DBG_Printf : Output debug messages to debug log if DEBUG_TO_FILE is defined, // GL_DBG_Printf : Output debug messages to debug log if DEBUG_TO_FILE is defined,
// : else do nothing // : else do nothing
// Returns :
// -----------------+ // -----------------+
#ifdef DEBUG_TO_FILE #ifdef DEBUG_TO_FILE
@ -159,8 +161,6 @@ FUNCPRINTF void GL_DBG_Printf(const char *format, ...)
// -----------------+ // -----------------+
// GL_MSG_Warning : Raises a warning. // GL_MSG_Warning : Raises a warning.
// :
// Returns :
// -----------------+ // -----------------+
static void GL_MSG_Warning(const char *format, ...) static void GL_MSG_Warning(const char *format, ...)
@ -184,8 +184,6 @@ static void GL_MSG_Warning(const char *format, ...)
// -----------------+ // -----------------+
// GL_MSG_Error : Raises an error. // GL_MSG_Error : Raises an error.
// :
// Returns :
// -----------------+ // -----------------+
static void GL_MSG_Error(const char *format, ...) static void GL_MSG_Error(const char *format, ...)
@ -1345,6 +1343,10 @@ void Flush(void)
TexCacheTail = TexCacheHead = NULL; //Hurdler: well, TexCacheHead is already NULL TexCacheTail = TexCacheHead = NULL; //Hurdler: well, TexCacheHead is already NULL
tex_downloaded = 0; tex_downloaded = 0;
free(textureBuffer);
textureBuffer = NULL;
textureBufferSize = 0;
} }
@ -1378,7 +1380,6 @@ INT32 isExtAvailable(const char *extension, const GLubyte *start)
// -----------------+ // -----------------+
// Init : Initialise the OpenGL interface API // Init : Initialise the OpenGL interface API
// Returns :
// -----------------+ // -----------------+
EXPORT boolean HWRAPI(Init) (void) EXPORT boolean HWRAPI(Init) (void)
{ {
@ -1738,37 +1739,48 @@ EXPORT void HWRAPI(SetBlend) (FBITFIELD PolyFlags)
CurrentPolyFlags = PolyFlags; CurrentPolyFlags = PolyFlags;
} }
static void AllocTextureBuffer(GLMipmap_t *pTexInfo)
{
size_t size = pTexInfo->width * pTexInfo->height;
if (size > textureBufferSize)
{
textureBuffer = realloc(textureBuffer, size * sizeof(RGBA_t));
if (textureBuffer == NULL)
I_Error("AllocTextureBuffer: out of memory allocating %s bytes", sizeu1(size * sizeof(RGBA_t)));
textureBufferSize = size;
}
}
// -----------------+ // -----------------+
// UpdateTexture : Updates the texture data. // UpdateTexture : Updates texture data.
// -----------------+ // -----------------+
EXPORT void HWRAPI(UpdateTexture) (GLMipmap_t *pTexInfo) EXPORT void HWRAPI(UpdateTexture) (GLMipmap_t *pTexInfo)
{ {
// Download a mipmap // Upload a texture
boolean updatemipmap = true; GLuint num = pTexInfo->downloaded;
static RGBA_t tex[2048*2048]; boolean update = true;
const GLvoid *ptex = tex;
INT32 w, h;
GLuint texnum = 0;
if (!pTexInfo->downloaded) INT32 w = pTexInfo->width, h = pTexInfo->height;
INT32 i, j;
const GLubyte *pImgData = (const GLubyte *)pTexInfo->data;
const GLvoid *ptex = NULL;
RGBA_t *tex = NULL;
// Generate a new texture name.
if (!num)
{ {
pglGenTextures(1, &texnum); pglGenTextures(1, &num);
pTexInfo->downloaded = texnum; pTexInfo->downloaded = num;
updatemipmap = false; update = false;
} }
else
texnum = pTexInfo->downloaded;
//GL_DBG_Printf ("DownloadMipmap %d %x\n",(INT32)texnum,pTexInfo->data); //GL_DBG_Printf("UpdateTexture %d %x\n", (INT32)num, pImgData);
w = pTexInfo->width; if ((pTexInfo->format == GL_TEXFMT_P_8) || (pTexInfo->format == GL_TEXFMT_AP_88))
h = pTexInfo->height;
if ((pTexInfo->format == GL_TEXFMT_P_8) ||
(pTexInfo->format == GL_TEXFMT_AP_88))
{ {
const GLubyte *pImgData = (const GLubyte *)pTexInfo->data; AllocTextureBuffer(pTexInfo);
INT32 i, j; ptex = tex = textureBuffer;
for (j = 0; j < h; j++) for (j = 0; j < h; j++)
{ {
@ -1799,20 +1811,18 @@ EXPORT void HWRAPI(UpdateTexture) (GLMipmap_t *pTexInfo)
tex[w*j+i].s.alpha = *pImgData; tex[w*j+i].s.alpha = *pImgData;
pImgData++; pImgData++;
} }
} }
} }
} }
else if (pTexInfo->format == GL_TEXFMT_RGBA) else if (pTexInfo->format == GL_TEXFMT_RGBA)
{ {
// corona test : passed as ARGB 8888, which is not in glide formats // Directly upload the texture data without any kind of conversion.
// Hurdler: not used for coronas anymore, just for dynamic lighting ptex = pImgData;
ptex = pTexInfo->data;
} }
else if (pTexInfo->format == GL_TEXFMT_ALPHA_INTENSITY_88) else if (pTexInfo->format == GL_TEXFMT_ALPHA_INTENSITY_88)
{ {
const GLubyte *pImgData = (const GLubyte *)pTexInfo->data; AllocTextureBuffer(pTexInfo);
INT32 i, j; ptex = tex = textureBuffer;
for (j = 0; j < h; j++) for (j = 0; j < h; j++)
{ {
@ -1829,8 +1839,8 @@ EXPORT void HWRAPI(UpdateTexture) (GLMipmap_t *pTexInfo)
} }
else if (pTexInfo->format == GL_TEXFMT_ALPHA_8) // Used for fade masks else if (pTexInfo->format == GL_TEXFMT_ALPHA_8) // Used for fade masks
{ {
const GLubyte *pImgData = (const GLubyte *)pTexInfo->data; AllocTextureBuffer(pTexInfo);
INT32 i, j; ptex = tex = textureBuffer;
for (j = 0; j < h; j++) for (j = 0; j < h; j++)
{ {
@ -1845,11 +1855,10 @@ EXPORT void HWRAPI(UpdateTexture) (GLMipmap_t *pTexInfo)
} }
} }
else else
GL_MSG_Warning ("SetTexture(bad format) %ld\n", pTexInfo->format); GL_MSG_Warning("UpdateTexture: bad format %d\n", pTexInfo->format);
// the texture number was already generated by pglGenTextures pglBindTexture(GL_TEXTURE_2D, num);
pglBindTexture(GL_TEXTURE_2D, texnum); tex_downloaded = num;
tex_downloaded = texnum;
// disable texture filtering on any texture that has holes so there's no dumb borders or blending issues // disable texture filtering on any texture that has holes so there's no dumb borders or blending issues
if (pTexInfo->flags & TF_TRANSPARENT) if (pTexInfo->flags & TF_TRANSPARENT)
@ -1878,7 +1887,7 @@ EXPORT void HWRAPI(UpdateTexture) (GLMipmap_t *pTexInfo)
} }
else else
{ {
if (updatemipmap) if (update)
pglTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, ptex); pglTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, ptex);
else else
pglTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, ptex); pglTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, ptex);
@ -1899,7 +1908,7 @@ EXPORT void HWRAPI(UpdateTexture) (GLMipmap_t *pTexInfo)
} }
else else
{ {
if (updatemipmap) if (update)
pglTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, ptex); pglTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, ptex);
else else
pglTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, ptex); pglTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, ptex);
@ -1919,7 +1928,7 @@ EXPORT void HWRAPI(UpdateTexture) (GLMipmap_t *pTexInfo)
} }
else else
{ {
if (updatemipmap) if (update)
pglTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, ptex); pglTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, ptex);
else else
pglTexImage2D(GL_TEXTURE_2D, 0, textureformatGL, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, ptex); pglTexImage2D(GL_TEXTURE_2D, 0, textureformatGL, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, ptex);

View file

@ -936,7 +936,7 @@ void HU_Ticker(void)
hu_tick++; hu_tick++;
hu_tick &= 7; // currently only to blink chat input cursor hu_tick &= 7; // currently only to blink chat input cursor
if (PLAYER1INPUTDOWN(gc_scores)) if (PLAYER1INPUTDOWN(GC_SCORES))
hu_showscores = !chat_on; hu_showscores = !chat_on;
else else
hu_showscores = false; hu_showscores = false;
@ -1111,26 +1111,26 @@ boolean HU_Responder(event_t *ev)
// (Unless if you're sharing a keyboard, since you probably establish when you start chatting that you have dibs on it...) // (Unless if you're sharing a keyboard, since you probably establish when you start chatting that you have dibs on it...)
// (Ahhh, the good ol days when I was a kid who couldn't afford an extra USB controller...) // (Ahhh, the good ol days when I was a kid who couldn't afford an extra USB controller...)
if (ev->data1 >= KEY_MOUSE1) if (ev->key >= KEY_MOUSE1)
{ {
INT32 i; INT32 i;
for (i = 0; i < num_gamecontrols; i++) for (i = 0; i < NUM_GAMECONTROLS; i++)
{ {
if (gamecontrol[i][0] == ev->data1 || gamecontrol[i][1] == ev->data1) if (gamecontrol[i][0] == ev->key || gamecontrol[i][1] == ev->key)
break; break;
} }
if (i == num_gamecontrols) if (i == NUM_GAMECONTROLS)
return false; return false;
}*/ //We don't actually care about that unless we get splitscreen netgames. :V }*/ //We don't actually care about that unless we get splitscreen netgames. :V
#ifndef NONET #ifndef NONET
c = (INT32)ev->data1; c = (INT32)ev->key;
if (!chat_on) if (!chat_on)
{ {
// enter chat mode // enter chat mode
if ((ev->data1 == gamecontrol[gc_talkkey][0] || ev->data1 == gamecontrol[gc_talkkey][1]) if ((ev->key == gamecontrol[GC_TALKKEY][0] || ev->key == gamecontrol[GC_TALKKEY][1])
&& netgame && !OLD_MUTE) // check for old chat mute, still let the players open the chat incase they want to scroll otherwise. && netgame && !OLD_MUTE) // check for old chat mute, still let the players open the chat incase they want to scroll otherwise.
{ {
chat_on = true; chat_on = true;
@ -1140,7 +1140,7 @@ boolean HU_Responder(event_t *ev)
typelines = 1; typelines = 1;
return true; return true;
} }
if ((ev->data1 == gamecontrol[gc_teamkey][0] || ev->data1 == gamecontrol[gc_teamkey][1]) if ((ev->key == gamecontrol[GC_TEAMKEY][0] || ev->key == gamecontrol[GC_TEAMKEY][1])
&& netgame && !OLD_MUTE) && netgame && !OLD_MUTE)
{ {
chat_on = true; chat_on = true;
@ -1157,12 +1157,12 @@ boolean HU_Responder(event_t *ev)
// Ignore modifier keys // Ignore modifier keys
// Note that we do this here so users can still set // Note that we do this here so users can still set
// their chat keys to one of these, if they so desire. // their chat keys to one of these, if they so desire.
if (ev->data1 == KEY_LSHIFT || ev->data1 == KEY_RSHIFT if (ev->key == KEY_LSHIFT || ev->key == KEY_RSHIFT
|| ev->data1 == KEY_LCTRL || ev->data1 == KEY_RCTRL || ev->key == KEY_LCTRL || ev->key == KEY_RCTRL
|| ev->data1 == KEY_LALT || ev->data1 == KEY_RALT) || ev->key == KEY_LALT || ev->key == KEY_RALT)
return true; return true;
c = (INT32)ev->data1; c = (INT32)ev->key;
// I know this looks very messy but this works. If it ain't broke, don't fix it! // I know this looks very messy but this works. If it ain't broke, don't fix it!
// shift LETTERS to uppercase if we have capslock or are holding shift // shift LETTERS to uppercase if we have capslock or are holding shift
@ -1234,8 +1234,8 @@ boolean HU_Responder(event_t *ev)
I_UpdateMouseGrab(); I_UpdateMouseGrab();
} }
else if (c == KEY_ESCAPE else if (c == KEY_ESCAPE
|| ((c == gamecontrol[gc_talkkey][0] || c == gamecontrol[gc_talkkey][1] || ((c == gamecontrol[GC_TALKKEY][0] || c == gamecontrol[GC_TALKKEY][1]
|| c == gamecontrol[gc_teamkey][0] || c == gamecontrol[gc_teamkey][1]) || c == gamecontrol[GC_TEAMKEY][0] || c == gamecontrol[GC_TEAMKEY][1])
&& c >= KEY_MOUSE1)) // If it's not a keyboard key, then the chat button is used as a toggle. && c >= KEY_MOUSE1)) // If it's not a keyboard key, then the chat button is used as a toggle.
{ {
chat_on = false; chat_on = false;
@ -2104,7 +2104,7 @@ void HU_Drawer(void)
} }
else else
HU_DrawCoopOverlay(); HU_DrawCoopOverlay();
LUAh_ScoresHUD(); LUA_HUDHOOK(scores);
} }
if (gamestate != GS_LEVEL) if (gamestate != GS_LEVEL)

View file

@ -29,6 +29,8 @@
#include "d_netcmd.h" // IsPlayerAdmin #include "d_netcmd.h" // IsPlayerAdmin
#include "m_menu.h" // Player Setup menu color stuff #include "m_menu.h" // Player Setup menu color stuff
#include "m_misc.h" // M_MapNumber #include "m_misc.h" // M_MapNumber
#include "b_bot.h" // B_UpdateBotleader
#include "d_clisrv.h" // CL_RemovePlayer
#include "lua_script.h" #include "lua_script.h"
#include "lua_libs.h" #include "lua_libs.h"
@ -1883,6 +1885,37 @@ static int lib_pDoSpring(lua_State *L)
return 1; return 1;
} }
static int lib_pTryCameraMove(lua_State *L)
{
camera_t *cam = *((camera_t **)luaL_checkudata(L, 1, META_CAMERA));
fixed_t x = luaL_checkfixed(L, 2);
fixed_t y = luaL_checkfixed(L, 3);
if (!cam)
return LUA_ErrInvalid(L, "camera_t");
lua_pushboolean(L, P_TryCameraMove(x, y, cam));
return 1;
}
static int lib_pTeleportCameraMove(lua_State *L)
{
camera_t *cam = *((camera_t **)luaL_checkudata(L, 1, META_CAMERA));
fixed_t x = luaL_checkfixed(L, 2);
fixed_t y = luaL_checkfixed(L, 3);
fixed_t z = luaL_checkfixed(L, 4);
if (!cam)
return LUA_ErrInvalid(L, "camera_t");
cam->x = x;
cam->y = y;
cam->z = z;
P_CheckCameraPosition(x, y, cam);
cam->subsector = R_PointInSubsector(x, y);
cam->floorz = tmfloorz;
cam->ceilingz = tmceilingz;
return 0;
}
// P_INTER // P_INTER
//////////// ////////////
@ -3397,6 +3430,111 @@ static int lib_gAddGametype(lua_State *L)
return 0; return 0;
} }
// Bot adding function!
// Partly lifted from Got_AddPlayer
static int lib_gAddPlayer(lua_State *L)
{
INT16 i, newplayernum, botcount = 1;
player_t *newplayer;
SINT8 skinnum = 0, bot;
for (i = 0; i < MAXPLAYERS; i++)
{
if (!playeringame[i])
break;
if (players[i].bot)
botcount++; // How many of us are there already?
}
if (i >= MAXPLAYERS)
{
lua_pushnil(L);
return 1;
}
newplayernum = i;
CL_ClearPlayer(newplayernum);
playeringame[newplayernum] = true;
G_AddPlayer(newplayernum);
newplayer = &players[newplayernum];
newplayer->jointime = 0;
newplayer->quittime = 0;
// Set the bot name (defaults to Bot #)
strcpy(player_names[newplayernum], va("Bot %d", botcount));
// Read the skin argument (defaults to Sonic)
if (!lua_isnoneornil(L, 1))
{
skinnum = R_SkinAvailable(luaL_checkstring(L, 1));
skinnum = skinnum < 0 ? 0 : skinnum;
}
// Read the color (defaults to skin prefcolor)
if (!lua_isnoneornil(L, 2))
newplayer->skincolor = R_GetColorByName(luaL_checkstring(L, 2));
else
newplayer->skincolor = skins[newplayer->skin].prefcolor;
// Read the bot name, if given
if (!lua_isnoneornil(L, 3))
strcpy(player_names[newplayernum], luaL_checkstring(L, 3));
bot = luaL_optinteger(L, 4, 3);
newplayer->bot = (bot >= BOT_NONE && bot <= BOT_MPAI) ? bot : BOT_MPAI;
// If our bot is a 2P type, we'll need to set its leader so it can spawn
if (newplayer->bot == BOT_2PAI || newplayer->bot == BOT_2PHUMAN)
B_UpdateBotleader(newplayer);
// Set the skin (can't do this until AFTER bot type is set!)
SetPlayerSkinByNum(newplayernum, skinnum);
if (netgame)
{
char joinmsg[256];
strcpy(joinmsg, M_GetText("\x82*Bot %s has joined the game (player %d)"));
strcpy(joinmsg, va(joinmsg, player_names[newplayernum], newplayernum));
HU_AddChatText(joinmsg, false);
}
LUA_PushUserdata(L, newplayer, META_PLAYER);
return 1;
}
// Bot removing function
static int lib_gRemovePlayer(lua_State *L)
{
UINT8 pnum = -1;
if (!lua_isnoneornil(L, 1))
pnum = luaL_checkinteger(L, 1);
else // No argument
return luaL_error(L, "argument #1 not given (expected number)");
if (pnum >= MAXPLAYERS) // Out of range
return luaL_error(L, "playernum %d out of range (0 - %d)", pnum, MAXPLAYERS-1);
if (playeringame[pnum]) // Found player
{
if (players[pnum].bot == BOT_NONE) // Can't remove clients.
return luaL_error(L, "G_RemovePlayer can only be used on players with a bot value other than BOT_NONE.");
else
{
players[pnum].removing = true;
lua_pushboolean(L, true);
return 1;
}
}
// Fell through. Invalid player
return LUA_ErrInvalid(L, "player_t");
}
static int Lcheckmapnumber (lua_State *L, int idx, const char *fun) static int Lcheckmapnumber (lua_State *L, int idx, const char *fun)
{ {
if (ISINLEVEL) if (ISINLEVEL)
@ -3881,6 +4019,8 @@ static luaL_Reg lib[] = {
{"P_FloorzAtPos",lib_pFloorzAtPos}, {"P_FloorzAtPos",lib_pFloorzAtPos},
{"P_CeilingzAtPos",lib_pCeilingzAtPos}, {"P_CeilingzAtPos",lib_pCeilingzAtPos},
{"P_DoSpring",lib_pDoSpring}, {"P_DoSpring",lib_pDoSpring},
{"P_TryCameraMove", lib_pTryCameraMove},
{"P_TeleportCameraMove", lib_pTeleportCameraMove},
// p_inter // p_inter
{"P_RemoveShield",lib_pRemoveShield}, {"P_RemoveShield",lib_pRemoveShield},
@ -3983,6 +4123,8 @@ static luaL_Reg lib[] = {
// g_game // g_game
{"G_AddGametype", lib_gAddGametype}, {"G_AddGametype", lib_gAddGametype},
{"G_AddPlayer", lib_gAddPlayer},
{"G_RemovePlayer", lib_gRemovePlayer},
{"G_BuildMapName",lib_gBuildMapName}, {"G_BuildMapName",lib_gBuildMapName},
{"G_BuildMapTitle",lib_gBuildMapTitle}, {"G_BuildMapTitle",lib_gBuildMapTitle},
{"G_FindMap",lib_gFindMap}, {"G_FindMap",lib_gFindMap},

View file

@ -433,7 +433,7 @@ static int CVarSetFunction
consvar_t *cvar = *(consvar_t **)luaL_checkudata(L, 1, META_CVAR); consvar_t *cvar = *(consvar_t **)luaL_checkudata(L, 1, META_CVAR);
if (cvar->flags & CV_NOLUA) if (cvar->flags & CV_NOLUA)
return luaL_error(L, "Variable %s cannot be set from Lua.", cvar->name); return luaL_error(L, "Variable '%s' cannot be set from Lua.", cvar->name);
switch (lua_type(L, 2)) switch (lua_type(L, 2))
{ {

View file

@ -13,6 +13,7 @@
#include "r_defs.h" #include "r_defs.h"
#include "d_player.h" #include "d_player.h"
#include "s_sound.h" #include "s_sound.h"
#include "d_event.h"
/* /*
Do you know what an 'X Macro' is? Such a macro is called over each element of Do you know what an 'X Macro' is? Such a macro is called over each element of
@ -78,6 +79,13 @@ automatically.
X (LinedefExecute),\ X (LinedefExecute),\
X (ShouldJingleContinue),/* should jingle of the given music continue playing */\ X (ShouldJingleContinue),/* should jingle of the given music continue playing */\
#define HUD_HOOK_LIST(X) \
X (game),\
X (scores),/* emblems/multiplayer list */\
X (title),/* titlescreen */\
X (titlecard),\
X (intermission),\
/* /*
I chose to access the hook enums through a macro as well. This could provide I chose to access the hook enums through a macro as well. This could provide
a hint to lookup the macro's definition instead of the enum's definition. a hint to lookup the macro's definition instead of the enum's definition.
@ -88,18 +96,26 @@ grepped and found in the lists above.
#define MOBJ_HOOK(name) mobjhook_ ## name #define MOBJ_HOOK(name) mobjhook_ ## name
#define HOOK(name) hook_ ## name #define HOOK(name) hook_ ## name
#define HUD_HOOK(name) hudhook_ ## name
#define STRING_HOOK(name) stringhook_ ## name #define STRING_HOOK(name) stringhook_ ## name
enum { MOBJ_HOOK_LIST (MOBJ_HOOK) MOBJ_HOOK(MAX) }; #define ENUM(X) enum { X ## _LIST (X) X(MAX) }
enum { HOOK_LIST (HOOK) HOOK(MAX) };
enum { STRING_HOOK_LIST (STRING_HOOK) STRING_HOOK(MAX) }; ENUM (MOBJ_HOOK);
ENUM (HOOK);
ENUM (HUD_HOOK);
ENUM (STRING_HOOK);
#undef ENUM
/* dead simple, LUA_HOOK(GameQuit) */ /* dead simple, LUA_HOOK(GameQuit) */
#define LUA_HOOK(type) LUA_HookVoid(HOOK(type)) #define LUA_HOOK(type) LUA_HookVoid(HOOK(type))
#define LUA_HUDHOOK(type) LUA_HookHUD(HUD_HOOK(type))
extern boolean hook_cmd_running; extern boolean hook_cmd_running;
void LUA_HookVoid(int hook); void LUA_HookVoid(int hook);
void LUA_HookHUD(int hook);
int LUA_HookMobj(mobj_t *, int hook); int LUA_HookMobj(mobj_t *, int hook);
int LUA_Hook2Mobj(mobj_t *, mobj_t *, int hook); int LUA_Hook2Mobj(mobj_t *, mobj_t *, int hook);
@ -107,6 +123,7 @@ void LUA_HookInt(INT32 integer, int hook);
void LUA_HookBool(boolean value, int hook); void LUA_HookBool(boolean value, int hook);
int LUA_HookPlayer(player_t *, int hook); int LUA_HookPlayer(player_t *, int hook);
int LUA_HookTiccmd(player_t *, ticcmd_t *, int hook); int LUA_HookTiccmd(player_t *, ticcmd_t *, int hook);
int LUA_HookKey(event_t *event, int hook); // Hooks for key events
void LUA_HookThinkFrame(void); void LUA_HookThinkFrame(void);
int LUA_HookMobjLineCollide(mobj_t *, line_t *); int LUA_HookMobjLineCollide(mobj_t *, line_t *);
@ -114,6 +131,7 @@ int LUA_HookTouchSpecial(mobj_t *special, mobj_t *toucher);
int LUA_HookShouldDamage(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 damage, UINT8 damagetype); int LUA_HookShouldDamage(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 damage, UINT8 damagetype);
int LUA_HookMobjDamage(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 damage, UINT8 damagetype); int LUA_HookMobjDamage(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 damage, UINT8 damagetype);
int LUA_HookMobjDeath(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damagetype); int LUA_HookMobjDeath(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damagetype);
int LUA_HookMobjMoveBlocked(mobj_t *, mobj_t *, line_t *);
int LUA_HookBotAI(mobj_t *sonic, mobj_t *tails, ticcmd_t *cmd); int LUA_HookBotAI(mobj_t *sonic, mobj_t *tails, ticcmd_t *cmd);
void LUA_HookLinedefExecute(line_t *, mobj_t *, sector_t *); void LUA_HookLinedefExecute(line_t *, mobj_t *, sector_t *);
int LUA_HookPlayerMsg(int source, int target, int flags, char *msg); int LUA_HookPlayerMsg(int source, int target, int flags, char *msg);
@ -130,4 +148,3 @@ int LUA_HookPlayerCmd(player_t *, ticcmd_t *);
int LUA_HookMusicChange(const char *oldname, struct MusicChange *); int LUA_HookMusicChange(const char *oldname, struct MusicChange *);
fixed_t LUA_HookPlayerHeight(player_t *player); fixed_t LUA_HookPlayerHeight(player_t *player);
int LUA_HookPlayerCanEnterSpinGaps(player_t *player); int LUA_HookPlayerCanEnterSpinGaps(player_t *player);
int LUA_HookKey(INT32 keycode, int hooktype); // Hooks for key events

View file

@ -31,12 +31,15 @@
ABSTRACTION ABSTRACTION
========================================================================= */ ========================================================================= */
static const char * const mobjHookNames[] = { MOBJ_HOOK_LIST (TOSTR) NULL }; #define LIST(id, M) \
static const char * const hookNames[] = { HOOK_LIST (TOSTR) NULL }; static const char * const id [] = { M (TOSTR) NULL }
static const char * const stringHookNames[] = { LIST (mobjHookNames, MOBJ_HOOK_LIST);
STRING_HOOK_LIST (TOSTR) NULL LIST (hookNames, HOOK_LIST);
}; LIST (hudHookNames, HUD_HOOK_LIST);
LIST (stringHookNames, STRING_HOOK_LIST);
#undef LIST
typedef struct { typedef struct {
int numHooks; int numHooks;
@ -49,6 +52,7 @@ typedef struct {
} stringhook_t; } stringhook_t;
static hook_t hookIds[HOOK(MAX)]; static hook_t hookIds[HOOK(MAX)];
static hook_t hudHookIds[HUD_HOOK(MAX)];
static hook_t mobjHookIds[NUMMOBJTYPES][MOBJ_HOOK(MAX)]; static hook_t mobjHookIds[NUMMOBJTYPES][MOBJ_HOOK(MAX)];
// Lua tables are used to lookup string hook ids. // Lua tables are used to lookup string hook ids.
@ -56,6 +60,7 @@ static stringhook_t stringHooks[STRING_HOOK(MAX)];
// This will be indexed by hook id, the value of which fetches the registry. // This will be indexed by hook id, the value of which fetches the registry.
static int * hookRefs; static int * hookRefs;
static int nextid;
// After a hook errors once, don't print the error again. // After a hook errors once, don't print the error again.
static UINT8 * hooksErrored; static UINT8 * hooksErrored;
@ -104,13 +109,13 @@ static void get_table(lua_State *L)
lua_remove(L, -2); lua_remove(L, -2);
} }
static void add_hook_to_table(lua_State *L, int id, int n) static void add_hook_to_table(lua_State *L, int n)
{ {
lua_pushnumber(L, id); lua_pushnumber(L, nextid);
lua_rawseti(L, -2, n); lua_rawseti(L, -2, n);
} }
static void add_string_hook(lua_State *L, int type, int id) static void add_string_hook(lua_State *L, int type)
{ {
stringhook_t * hook = &stringHooks[type]; stringhook_t * hook = &stringHooks[type];
@ -146,33 +151,54 @@ static void add_string_hook(lua_State *L, int type, int id)
{ {
lua_pushstring(L, string); lua_pushstring(L, string);
get_table(L); get_table(L);
add_hook_to_table(L, id, 1 + lua_objlen(L, -1)); add_hook_to_table(L, 1 + lua_objlen(L, -1));
} }
else else
add_hook_to_table(L, id, ++hook->numGeneric); add_hook_to_table(L, ++hook->numGeneric);
} }
static void add_hook(hook_t *map, int id) static void add_hook(hook_t *map)
{ {
Z_Realloc(map->ids, (map->numHooks + 1) * sizeof *map->ids, Z_Realloc(map->ids, (map->numHooks + 1) * sizeof *map->ids,
PU_STATIC, &map->ids); PU_STATIC, &map->ids);
map->ids[map->numHooks++] = id; map->ids[map->numHooks++] = nextid;
} }
static void add_mobj_hook(lua_State *L, int hook_type, int id) static void add_mobj_hook(lua_State *L, int hook_type)
{ {
mobjtype_t mobj_type = luaL_optnumber(L, 3, MT_NULL); mobjtype_t mobj_type = luaL_optnumber(L, 3, MT_NULL);
luaL_argcheck(L, mobj_type < NUMMOBJTYPES, 3, "invalid mobjtype_t"); luaL_argcheck(L, mobj_type < NUMMOBJTYPES, 3, "invalid mobjtype_t");
add_hook(&mobjHookIds[mobj_type][hook_type], id); add_hook(&mobjHookIds[mobj_type][hook_type]);
}
static void add_hud_hook(lua_State *L, int idx)
{
add_hook(&hudHookIds[luaL_checkoption(L,
idx, "game", hudHookNames)]);
}
static void add_hook_ref(lua_State *L, int idx)
{
if (!(nextid & 7))
{
Z_Realloc(hooksErrored,
BIT_ARRAY_SIZE (nextid + 1) * sizeof *hooksErrored,
PU_STATIC, &hooksErrored);
hooksErrored[nextid >> 3] = 0;
}
Z_Realloc(hookRefs, (nextid + 1) * sizeof *hookRefs, PU_STATIC, &hookRefs);
// set the hook function in the registry.
lua_pushvalue(L, idx);
hookRefs[nextid++] = luaL_ref(L, LUA_REGISTRYINDEX);
} }
// Takes hook, function, and additional arguments (mobj type to act on, etc.) // Takes hook, function, and additional arguments (mobj type to act on, etc.)
static int lib_addHook(lua_State *L) static int lib_addHook(lua_State *L)
{ {
static int nextid;
const char * name; const char * name;
int type; int type;
@ -185,34 +211,26 @@ static int lib_addHook(lua_State *L)
/* this is a very special case */ /* this is a very special case */
if (( type = hook_in_list(name, stringHookNames) ) < STRING_HOOK(MAX)) if (( type = hook_in_list(name, stringHookNames) ) < STRING_HOOK(MAX))
{ {
add_string_hook(L, type, nextid); add_string_hook(L, type);
} }
else if (( type = hook_in_list(name, mobjHookNames) ) < MOBJ_HOOK(MAX)) else if (( type = hook_in_list(name, mobjHookNames) ) < MOBJ_HOOK(MAX))
{ {
add_mobj_hook(L, type, nextid); add_mobj_hook(L, type);
} }
else if (( type = hook_in_list(name, hookNames) ) < HOOK(MAX)) else if (( type = hook_in_list(name, hookNames) ) < HOOK(MAX))
{ {
add_hook(&hookIds[type], nextid); add_hook(&hookIds[type]);
}
else if (strcmp(name, "HUD") == 0)
{
add_hud_hook(L, 3);
} }
else else
{ {
return luaL_argerror(L, 1, lua_pushfstring(L, "invalid hook " LUA_QS, name)); return luaL_argerror(L, 1, lua_pushfstring(L, "invalid hook " LUA_QS, name));
} }
if (!(nextid & 7)) add_hook_ref(L, 2);/* the function */
{
Z_Realloc(hooksErrored,
BIT_ARRAY_SIZE (nextid + 1) * sizeof *hooksErrored,
PU_STATIC, &hooksErrored);
hooksErrored[nextid >> 3] = 0;
}
Z_Realloc(hookRefs, (nextid + 1) * sizeof *hookRefs, PU_STATIC, &hookRefs);
// set the hook function in the registry.
lua_pushvalue(L, 2);/* the function */
hookRefs[nextid++] = luaL_ref(L, LUA_REGISTRYINDEX);
return 0; return 0;
} }
@ -227,6 +245,23 @@ int LUA_HookLib(lua_State *L)
return 0; return 0;
} }
/* TODO: remove in next backwards incompatible release */
#if MODID == 18
int lib_hudadd(lua_State *L);/* yeah compiler */
int lib_hudadd(lua_State *L)
{
if (!lua_lumploading)
return luaL_error(L, "This function cannot be called from within a hook or coroutine!");
luaL_checktype(L, 1, LUA_TFUNCTION);
add_hud_hook(L, 2);
add_hook_ref(L, 1);
return 0;
}
#endif
typedef struct Hook_State Hook_State; typedef struct Hook_State Hook_State;
typedef void (*Hook_Callback)(Hook_State *); typedef void (*Hook_Callback)(Hook_State *);
@ -259,11 +294,16 @@ static void push_string(void)
lua_pushvalue(gL, SINDEX); lua_pushvalue(gL, SINDEX);
} }
static boolean start_hook_stack(void) static boolean begin_hook_values(Hook_State *hook)
{
hook->top = lua_gettop(gL);
return true;
}
static void start_hook_stack(void)
{ {
lua_settop(gL, 0); lua_settop(gL, 0);
push_error_handler(); push_error_handler();
return true;
} }
static boolean init_hook_type static boolean init_hook_type
@ -279,10 +319,11 @@ static boolean init_hook_type
if (nonzero) if (nonzero)
{ {
start_hook_stack();
hook->hook_type = hook_type; hook->hook_type = hook_type;
hook->mobj_type = mobj_type; hook->mobj_type = mobj_type;
hook->string = string; hook->string = string;
return start_hook_stack(); return begin_hook_values(hook);
} }
else else
return false; return false;
@ -323,7 +364,7 @@ static boolean prepare_string_hook
stringHooks[hook_type].ref)) stringHooks[hook_type].ref))
{ {
lua_pushstring(gL, string); lua_pushstring(gL, string);
return true; return begin_hook_values(hook);
} }
else else
return false; return false;
@ -332,12 +373,12 @@ static boolean prepare_string_hook
static void init_hook_call static void init_hook_call
( (
Hook_State * hook, Hook_State * hook,
int values,
int results, int results,
Hook_Callback results_handler Hook_Callback results_handler
){ ){
hook->top = lua_gettop(gL); const int top = lua_gettop(gL);
hook->values = values; hook->values = (top - hook->top);
hook->top = top;
hook->results = results; hook->results = results;
hook->results_handler = results_handler; hook->results_handler = results_handler;
} }
@ -447,13 +488,12 @@ static int call_mobj_type_hooks(Hook_State *hook, mobjtype_t mobj_type)
static int call_hooks static int call_hooks
( (
Hook_State * hook, Hook_State * hook,
int values,
int results, int results,
Hook_Callback results_handler Hook_Callback results_handler
){ ){
int calls = 0; int calls = 0;
init_hook_call(hook, values, results, results_handler); init_hook_call(hook, results, results_handler);
if (hook->string) if (hook->string)
{ {
@ -514,7 +554,7 @@ int LUA_HookMobj(mobj_t *mobj, int hook_type)
if (prepare_mobj_hook(&hook, false, hook_type, mobj->type)) if (prepare_mobj_hook(&hook, false, hook_type, mobj->type))
{ {
LUA_PushUserdata(gL, mobj, META_MOBJ); LUA_PushUserdata(gL, mobj, META_MOBJ);
call_hooks(&hook, 1, 1, res_true); call_hooks(&hook, 1, res_true);
} }
return hook.status; return hook.status;
} }
@ -526,7 +566,7 @@ int LUA_Hook2Mobj(mobj_t *t1, mobj_t *t2, int hook_type)
{ {
LUA_PushUserdata(gL, t1, META_MOBJ); LUA_PushUserdata(gL, t1, META_MOBJ);
LUA_PushUserdata(gL, t2, META_MOBJ); LUA_PushUserdata(gL, t2, META_MOBJ);
call_hooks(&hook, 2, 1, res_force); call_hooks(&hook, 1, res_force);
} }
return hook.status; return hook.status;
} }
@ -535,7 +575,7 @@ void LUA_HookVoid(int type)
{ {
Hook_State hook; Hook_State hook;
if (prepare_hook(&hook, 0, type)) if (prepare_hook(&hook, 0, type))
call_hooks(&hook, 0, 0, res_none); call_hooks(&hook, 0, res_none);
} }
void LUA_HookInt(INT32 number, int hook_type) void LUA_HookInt(INT32 number, int hook_type)
@ -544,7 +584,7 @@ void LUA_HookInt(INT32 number, int hook_type)
if (prepare_hook(&hook, 0, hook_type)) if (prepare_hook(&hook, 0, hook_type))
{ {
lua_pushinteger(gL, number); lua_pushinteger(gL, number);
call_hooks(&hook, 1, 0, res_none); call_hooks(&hook, 0, res_none);
} }
} }
@ -554,7 +594,7 @@ void LUA_HookBool(boolean value, int hook_type)
if (prepare_hook(&hook, 0, hook_type)) if (prepare_hook(&hook, 0, hook_type))
{ {
lua_pushboolean(gL, value); lua_pushboolean(gL, value);
call_hooks(&hook, 1, 0, res_none); call_hooks(&hook, 0, res_none);
} }
} }
@ -564,7 +604,7 @@ int LUA_HookPlayer(player_t *player, int hook_type)
if (prepare_hook(&hook, false, hook_type)) if (prepare_hook(&hook, false, hook_type))
{ {
LUA_PushUserdata(gL, player, META_PLAYER); LUA_PushUserdata(gL, player, META_PLAYER);
call_hooks(&hook, 1, 1, res_true); call_hooks(&hook, 1, res_true);
} }
return hook.status; return hook.status;
} }
@ -580,7 +620,7 @@ int LUA_HookTiccmd(player_t *player, ticcmd_t *cmd, int hook_type)
if (hook_type == HOOK(PlayerCmd)) if (hook_type == HOOK(PlayerCmd))
hook_cmd_running = true; hook_cmd_running = true;
call_hooks(&hook, 2, 1, res_true); call_hooks(&hook, 1, res_true);
if (hook_type == HOOK(PlayerCmd)) if (hook_type == HOOK(PlayerCmd))
hook_cmd_running = false; hook_cmd_running = false;
@ -588,6 +628,35 @@ int LUA_HookTiccmd(player_t *player, ticcmd_t *cmd, int hook_type)
return hook.status; return hook.status;
} }
int LUA_HookKey(event_t *event, int hook_type)
{
Hook_State hook;
if (prepare_hook(&hook, false, hook_type))
{
LUA_PushUserdata(gL, event, META_KEYEVENT);
call_hooks(&hook, 1, res_true);
}
return hook.status;
}
void LUA_HookHUD(int hook_type)
{
const hook_t * map = &hudHookIds[hook_type];
Hook_State hook;
if (map->numHooks > 0)
{
start_hook_stack();
begin_hook_values(&hook);
LUA_SetHudHook(hook_type);
hud_running = true; // local hook
init_hook_call(&hook, 0, res_none);
call_mapped(&hook, map);
hud_running = false;
}
}
/* ========================================================================= /* =========================================================================
SPECIALIZED HOOKS SPECIALIZED HOOKS
========================================================================= */ ========================================================================= */
@ -607,7 +676,7 @@ void LUA_HookThinkFrame(void)
if (prepare_hook(&hook, 0, type)) if (prepare_hook(&hook, 0, type))
{ {
init_hook_call(&hook, 0, 0, res_none); init_hook_call(&hook, 0, res_none);
for (k = 0; k < map->numHooks; ++k) for (k = 0; k < map->numHooks; ++k)
{ {
@ -642,7 +711,7 @@ int LUA_HookMobjLineCollide(mobj_t *mobj, line_t *line)
{ {
LUA_PushUserdata(gL, mobj, META_MOBJ); LUA_PushUserdata(gL, mobj, META_MOBJ);
LUA_PushUserdata(gL, line, META_LINE); LUA_PushUserdata(gL, line, META_LINE);
call_hooks(&hook, 2, 1, res_force); call_hooks(&hook, 1, res_force);
} }
return hook.status; return hook.status;
} }
@ -654,7 +723,7 @@ int LUA_HookTouchSpecial(mobj_t *special, mobj_t *toucher)
{ {
LUA_PushUserdata(gL, special, META_MOBJ); LUA_PushUserdata(gL, special, META_MOBJ);
LUA_PushUserdata(gL, toucher, META_MOBJ); LUA_PushUserdata(gL, toucher, META_MOBJ);
call_hooks(&hook, 2, 1, res_true); call_hooks(&hook, 1, res_true);
} }
return hook.status; return hook.status;
} }
@ -667,7 +736,6 @@ static int damage_hook
INT32 damage, INT32 damage,
UINT8 damagetype, UINT8 damagetype,
int hook_type, int hook_type,
int values,
Hook_Callback results_handler Hook_Callback results_handler
){ ){
Hook_State hook; Hook_State hook;
@ -676,10 +744,10 @@ static int damage_hook
LUA_PushUserdata(gL, target, META_MOBJ); LUA_PushUserdata(gL, target, META_MOBJ);
LUA_PushUserdata(gL, inflictor, META_MOBJ); LUA_PushUserdata(gL, inflictor, META_MOBJ);
LUA_PushUserdata(gL, source, META_MOBJ); LUA_PushUserdata(gL, source, META_MOBJ);
if (values == 5) if (hook_type != MOBJ_HOOK(MobjDeath))
lua_pushinteger(gL, damage); lua_pushinteger(gL, damage);
lua_pushinteger(gL, damagetype); lua_pushinteger(gL, damagetype);
call_hooks(&hook, values, 1, results_handler); call_hooks(&hook, 1, results_handler);
} }
return hook.status; return hook.status;
} }
@ -687,19 +755,32 @@ static int damage_hook
int LUA_HookShouldDamage(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 damage, UINT8 damagetype) int LUA_HookShouldDamage(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 damage, UINT8 damagetype)
{ {
return damage_hook(target, inflictor, source, damage, damagetype, return damage_hook(target, inflictor, source, damage, damagetype,
MOBJ_HOOK(ShouldDamage), 5, res_force); MOBJ_HOOK(ShouldDamage), res_force);
} }
int LUA_HookMobjDamage(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 damage, UINT8 damagetype) int LUA_HookMobjDamage(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 damage, UINT8 damagetype)
{ {
return damage_hook(target, inflictor, source, damage, damagetype, return damage_hook(target, inflictor, source, damage, damagetype,
MOBJ_HOOK(MobjDamage), 5, res_true); MOBJ_HOOK(MobjDamage), res_true);
} }
int LUA_HookMobjDeath(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damagetype) int LUA_HookMobjDeath(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damagetype)
{ {
return damage_hook(target, inflictor, source, 0, damagetype, return damage_hook(target, inflictor, source, 0, damagetype,
MOBJ_HOOK(MobjDeath), 4, res_true); MOBJ_HOOK(MobjDeath), res_true);
}
int LUA_HookMobjMoveBlocked(mobj_t *t1, mobj_t *t2, line_t *line)
{
Hook_State hook;
if (prepare_mobj_hook(&hook, 0, MOBJ_HOOK(MobjMoveBlocked), t1->type))
{
LUA_PushUserdata(gL, t1, META_MOBJ);
LUA_PushUserdata(gL, t2, META_MOBJ);
LUA_PushUserdata(gL, line, META_LINE);
call_hooks(&hook, 1, res_true);
}
return hook.status;
} }
typedef struct { typedef struct {
@ -772,7 +853,7 @@ int LUA_HookBotAI(mobj_t *sonic, mobj_t *tails, ticcmd_t *cmd)
hook.userdata = &botai; hook.userdata = &botai;
call_hooks(&hook, 2, 8, res_botai); call_hooks(&hook, 8, res_botai);
} }
return hook.status; return hook.status;
@ -787,7 +868,7 @@ void LUA_HookLinedefExecute(line_t *line, mobj_t *mo, sector_t *sector)
LUA_PushUserdata(gL, line, META_LINE); LUA_PushUserdata(gL, line, META_LINE);
LUA_PushUserdata(gL, mo, META_MOBJ); LUA_PushUserdata(gL, mo, META_MOBJ);
LUA_PushUserdata(gL, sector, META_SECTOR); LUA_PushUserdata(gL, sector, META_SECTOR);
ps_lua_mobjhooks += call_hooks(&hook, 3, 0, res_none); ps_lua_mobjhooks += call_hooks(&hook, 0, res_none);
} }
} }
@ -811,7 +892,7 @@ int LUA_HookPlayerMsg(int source, int target, int flags, char *msg)
LUA_PushUserdata(gL, &players[target-1], META_PLAYER); // target LUA_PushUserdata(gL, &players[target-1], META_PLAYER); // target
} }
lua_pushstring(gL, msg); // msg lua_pushstring(gL, msg); // msg
call_hooks(&hook, 4, 1, res_true); call_hooks(&hook, 1, res_true);
} }
return hook.status; return hook.status;
} }
@ -825,7 +906,7 @@ int LUA_HookHurtMsg(player_t *player, mobj_t *inflictor, mobj_t *source, UINT8 d
LUA_PushUserdata(gL, inflictor, META_MOBJ); LUA_PushUserdata(gL, inflictor, META_MOBJ);
LUA_PushUserdata(gL, source, META_MOBJ); LUA_PushUserdata(gL, source, META_MOBJ);
lua_pushinteger(gL, damagetype); lua_pushinteger(gL, damagetype);
call_hooks(&hook, 4, 1, res_true); call_hooks(&hook, 1, res_true);
} }
return hook.status; return hook.status;
} }
@ -844,12 +925,14 @@ void LUA_HookNetArchive(lua_CFunction archFunc)
push_error_handler(); push_error_handler();
lua_insert(gL, EINDEX); lua_insert(gL, EINDEX);
begin_hook_values(&hook);
// tables becomes an upvalue of archFunc // tables becomes an upvalue of archFunc
lua_pushvalue(gL, -1); lua_pushvalue(gL, -1);
lua_pushcclosure(gL, archFunc, 1); lua_pushcclosure(gL, archFunc, 1);
// stack: tables, archFunc // stack: tables, archFunc
init_hook_call(&hook, 1, 0, res_none); init_hook_call(&hook, 0, res_none);
call_mapped(&hook, map); call_mapped(&hook, map);
lua_pop(gL, 1); // pop archFunc lua_pop(gL, 1); // pop archFunc
@ -865,7 +948,7 @@ int LUA_HookMapThingSpawn(mobj_t *mobj, mapthing_t *mthing)
{ {
LUA_PushUserdata(gL, mobj, META_MOBJ); LUA_PushUserdata(gL, mobj, META_MOBJ);
LUA_PushUserdata(gL, mthing, META_MAPTHING); LUA_PushUserdata(gL, mthing, META_MAPTHING);
call_hooks(&hook, 2, 1, res_true); call_hooks(&hook, 1, res_true);
} }
return hook.status; return hook.status;
} }
@ -877,7 +960,7 @@ int LUA_HookFollowMobj(player_t *player, mobj_t *mobj)
{ {
LUA_PushUserdata(gL, player, META_PLAYER); LUA_PushUserdata(gL, player, META_PLAYER);
LUA_PushUserdata(gL, mobj, META_MOBJ); LUA_PushUserdata(gL, mobj, META_MOBJ);
call_hooks(&hook, 2, 1, res_true); call_hooks(&hook, 1, res_true);
} }
return hook.status; return hook.status;
} }
@ -889,7 +972,7 @@ int LUA_HookPlayerCanDamage(player_t *player, mobj_t *mobj)
{ {
LUA_PushUserdata(gL, player, META_PLAYER); LUA_PushUserdata(gL, player, META_PLAYER);
LUA_PushUserdata(gL, mobj, META_MOBJ); LUA_PushUserdata(gL, mobj, META_MOBJ);
call_hooks(&hook, 2, 1, res_force); call_hooks(&hook, 1, res_force);
} }
return hook.status; return hook.status;
} }
@ -901,7 +984,7 @@ void LUA_HookPlayerQuit(player_t *plr, kickreason_t reason)
{ {
LUA_PushUserdata(gL, plr, META_PLAYER); // Player that quit LUA_PushUserdata(gL, plr, META_PLAYER); // Player that quit
lua_pushinteger(gL, reason); // Reason for quitting lua_pushinteger(gL, reason); // Reason for quitting
call_hooks(&hook, 2, 0, res_none); call_hooks(&hook, 0, res_none);
} }
} }
@ -915,7 +998,7 @@ int LUA_HookTeamSwitch(player_t *player, int newteam, boolean fromspectators, bo
lua_pushboolean(gL, fromspectators); lua_pushboolean(gL, fromspectators);
lua_pushboolean(gL, tryingautobalance); lua_pushboolean(gL, tryingautobalance);
lua_pushboolean(gL, tryingscramble); lua_pushboolean(gL, tryingscramble);
call_hooks(&hook, 5, 1, res_false); call_hooks(&hook, 1, res_false);
} }
return hook.status; return hook.status;
} }
@ -930,7 +1013,7 @@ int LUA_HookViewpointSwitch(player_t *player, player_t *newdisplayplayer, boolea
lua_pushboolean(gL, forced); lua_pushboolean(gL, forced);
hud_running = true; // local hook hud_running = true; // local hook
call_hooks(&hook, 3, 1, res_force); call_hooks(&hook, 1, res_force);
hud_running = false; hud_running = false;
} }
return hook.status; return hook.status;
@ -945,7 +1028,7 @@ int LUA_HookSeenPlayer(player_t *player, player_t *seenfriend)
LUA_PushUserdata(gL, seenfriend, META_PLAYER); LUA_PushUserdata(gL, seenfriend, META_PLAYER);
hud_running = true; // local hook hud_running = true; // local hook
call_hooks(&hook, 2, 1, res_false); call_hooks(&hook, 1, res_false);
hud_running = false; hud_running = false;
} }
return hook.status; return hook.status;
@ -961,7 +1044,7 @@ int LUA_HookShouldJingleContinue(player_t *player, const char *musname)
push_string(); push_string();
hud_running = true; // local hook hud_running = true; // local hook
call_hooks(&hook, 2, 1, res_true); call_hooks(&hook, 1, res_true);
hud_running = false; hud_running = false;
} }
return hook.status; return hook.status;
@ -1027,7 +1110,8 @@ int LUA_HookMusicChange(const char *oldname, struct MusicChange *param)
if (prepare_hook(&hook, false, type)) if (prepare_hook(&hook, false, type))
{ {
init_hook_call(&hook, 7, 6, res_musicchange); init_hook_call(&hook, 6, res_musicchange);
hook.values = 7;/* values pushed later */
hook.userdata = param; hook.userdata = param;
lua_pushstring(gL, oldname);/* the only constant value */ lua_pushstring(gL, oldname);/* the only constant value */
@ -1073,7 +1157,7 @@ fixed_t LUA_HookPlayerHeight(player_t *player)
if (prepare_hook(&hook, -1, HOOK(PlayerHeight))) if (prepare_hook(&hook, -1, HOOK(PlayerHeight)))
{ {
LUA_PushUserdata(gL, player, META_PLAYER); LUA_PushUserdata(gL, player, META_PLAYER);
call_hooks(&hook, 1, 1, res_playerheight); call_hooks(&hook, 1, res_playerheight);
} }
return hook.status; return hook.status;
} }
@ -1084,18 +1168,7 @@ int LUA_HookPlayerCanEnterSpinGaps(player_t *player)
if (prepare_hook(&hook, 0, HOOK(PlayerCanEnterSpinGaps))) if (prepare_hook(&hook, 0, HOOK(PlayerCanEnterSpinGaps)))
{ {
LUA_PushUserdata(gL, player, META_PLAYER); LUA_PushUserdata(gL, player, META_PLAYER);
call_hooks(&hook, 1, 1, res_force); call_hooks(&hook, 1, res_force);
}
return hook.status;
}
int LUA_HookKey(INT32 keycode, int hooktype)
{
Hook_State hook;
if (prepare_hook(&hook, 0, hooktype))
{
lua_pushinteger(gL, keycode);
call_hooks(&hook, 1, 0, res_true);
} }
return hook.status; return hook.status;
} }

View file

@ -47,8 +47,4 @@ extern boolean hud_running;
boolean LUA_HudEnabled(enum hud option); boolean LUA_HudEnabled(enum hud option);
void LUAh_GameHUD(player_t *stplyr); void LUA_SetHudHook(int hook);
void LUAh_ScoresHUD(void);
void LUAh_TitleHUD(void);
void LUAh_TitleCardHUD(player_t *stplayr);
void LUAh_IntermissionHUD(boolean failedstage);

View file

@ -23,18 +23,18 @@
#include "v_video.h" #include "v_video.h"
#include "w_wad.h" #include "w_wad.h"
#include "z_zone.h" #include "z_zone.h"
#include "y_inter.h"
#include "lua_script.h" #include "lua_script.h"
#include "lua_libs.h" #include "lua_libs.h"
#include "lua_hud.h" #include "lua_hud.h"
#include "lua_hook.h"
#define HUDONLY if (!hud_running) return luaL_error(L, "HUD rendering code should not be called outside of rendering hooks!"); #define HUDONLY if (!hud_running) return luaL_error(L, "HUD rendering code should not be called outside of rendering hooks!");
boolean hud_running = false; boolean hud_running = false;
static UINT8 hud_enabled[(hud_MAX/8)+1]; static UINT8 hud_enabled[(hud_MAX/8)+1];
static UINT8 hudAvailable; // hud hooks field
// must match enum hud in lua_hud.h // must match enum hud in lua_hud.h
static const char *const hud_disable_options[] = { static const char *const hud_disable_options[] = {
"stagetitle", "stagetitle",
@ -95,21 +95,6 @@ static const char *const patch_opt[] = {
"topoffset", "topoffset",
NULL}; NULL};
enum hudhook {
hudhook_game = 0,
hudhook_scores,
hudhook_intermission,
hudhook_title,
hudhook_titlecard
};
static const char *const hudhook_opt[] = {
"game",
"scores",
"intermission",
"title",
"titlecard",
NULL};
// alignment types for v.drawString // alignment types for v.drawString
enum align { enum align {
align_left = 0, align_left = 0,
@ -280,7 +265,7 @@ static int hudinfo_num(lua_State *L)
static int colormap_get(lua_State *L) static int colormap_get(lua_State *L)
{ {
const UINT8 *colormap = *((UINT8 **)luaL_checkudata(L, 1, META_COLORMAP)); UINT8 *colormap = *((UINT8 **)luaL_checkudata(L, 1, META_COLORMAP));
UINT32 i = luaL_checkinteger(L, 2); UINT32 i = luaL_checkinteger(L, 2);
if (i >= 256) if (i >= 256)
return luaL_error(L, "colormap index %d out of range (0 - %d)", i, 255); return luaL_error(L, "colormap index %d out of range (0 - %d)", i, 255);
@ -288,6 +273,23 @@ static int colormap_get(lua_State *L)
return 1; return 1;
} }
static int colormap_set(lua_State *L)
{
UINT8 *colormap = *((UINT8 **)luaL_checkudata(L, 1, META_COLORMAP));
UINT32 i = luaL_checkinteger(L, 2);
if (i >= 256)
return luaL_error(L, "colormap index %d out of range (0 - %d)", i, 255);
colormap[i] = (UINT8)luaL_checkinteger(L, 3);
return 0;
}
static int colormap_free(lua_State *L)
{
UINT8 *colormap = *((UINT8 **)luaL_checkudata(L, 1, META_COLORMAP));
Z_Free(colormap);
return 0;
}
static int patch_get(lua_State *L) static int patch_get(lua_State *L)
{ {
patch_t *patch = *((patch_t **)luaL_checkudata(L, 1, META_PATCH)); patch_t *patch = *((patch_t **)luaL_checkudata(L, 1, META_PATCH));
@ -384,6 +386,74 @@ static int camera_get(lua_State *L)
return 1; return 1;
} }
static int camera_set(lua_State *L)
{
camera_t *cam = *((camera_t **)luaL_checkudata(L, 1, META_CAMERA));
enum cameraf field = luaL_checkoption(L, 2, NULL, camera_opt);
I_Assert(cam != NULL);
switch(field)
{
case camera_subsector:
case camera_floorz:
case camera_ceilingz:
case camera_x:
case camera_y:
return luaL_error(L, LUA_QL("camera_t") " field " LUA_QS " should not be set directly. Use " LUA_QL("P_TryCameraMove") " or " LUA_QL("P_TeleportCameraMove") " instead.", camera_opt[field]);
case camera_chase: {
INT32 chase = luaL_checkboolean(L, 3);
if (cam == &camera)
CV_SetValue(&cv_chasecam, chase);
else if (cam == &camera2)
CV_SetValue(&cv_chasecam2, chase);
else // ??? this should never happen, but ok
cam->chase = chase;
break;
}
case camera_aiming:
cam->aiming = luaL_checkangle(L, 3);
break;
case camera_z:
cam->z = luaL_checkfixed(L, 3);
P_CheckCameraPosition(cam->x, cam->y, cam);
cam->floorz = tmfloorz;
cam->ceilingz = tmceilingz;
break;
case camera_angle:
cam->angle = luaL_checkangle(L, 3);
break;
case camera_radius:
cam->radius = luaL_checkfixed(L, 3);
if (cam->radius < 0)
cam->radius = 0;
P_CheckCameraPosition(cam->x, cam->y, cam);
cam->floorz = tmfloorz;
cam->ceilingz = tmceilingz;
break;
case camera_height:
cam->height = luaL_checkfixed(L, 3);
if (cam->height < 0)
cam->height = 0;
P_CheckCameraPosition(cam->x, cam->y, cam);
cam->floorz = tmfloorz;
cam->ceilingz = tmceilingz;
break;
case camera_momx:
cam->momx = luaL_checkfixed(L, 3);
break;
case camera_momy:
cam->momy = luaL_checkfixed(L, 3);
break;
case camera_momz:
cam->momz = luaL_checkfixed(L, 3);
break;
default:
return luaL_error(L, LUA_QL("camera_t") " has no field named " LUA_QS, camera_opt[field]);
}
return 0;
}
// //
// lib_draw // lib_draw
// //
@ -663,6 +733,45 @@ static int libd_drawStretched(lua_State *L)
return 0; return 0;
} }
static int libd_drawCropped(lua_State *L)
{
fixed_t x, y, hscale, vscale, sx, sy, w, h;
INT32 flags;
patch_t *patch;
const UINT8 *colormap = NULL;
HUDONLY
x = luaL_checkinteger(L, 1);
y = luaL_checkinteger(L, 2);
hscale = luaL_checkinteger(L, 3);
if (hscale < 0)
return luaL_error(L, "negative horizontal scale");
vscale = luaL_checkinteger(L, 4);
if (vscale < 0)
return luaL_error(L, "negative vertical scale");
patch = *((patch_t **)luaL_checkudata(L, 5, META_PATCH));
flags = luaL_checkinteger(L, 6);
if (!lua_isnoneornil(L, 7))
colormap = *((UINT8 **)luaL_checkudata(L, 7, META_COLORMAP));
sx = luaL_checkinteger(L, 8);
if (sx < 0) // Don't crash. Now, we could do "x-=sx*FRACUNIT; sx=0;" here...
return luaL_error(L, "negative crop sx");
sy = luaL_checkinteger(L, 9);
if (sy < 0) // ...but it's more truthful to just deny it, as negative values would crash
return luaL_error(L, "negative crop sy");
w = luaL_checkinteger(L, 10);
if (w < 0) // Again, don't crash
return luaL_error(L, "negative crop w");
h = luaL_checkinteger(L, 11);
if (h < 0)
return luaL_error(L, "negative crop h");
flags &= ~V_PARAMMASK; // Don't let crashes happen.
V_DrawCroppedPatch(x, y, hscale, vscale, flags, patch, colormap, sx, sy, w, h);
return 0;
}
static int libd_drawNum(lua_State *L) static int libd_drawNum(lua_State *L)
{ {
INT32 x, y, flags, num; INT32 x, y, flags, num;
@ -948,7 +1057,7 @@ static int libd_getColormap(lua_State *L)
// all was successful above, now we generate the colormap at last! // all was successful above, now we generate the colormap at last!
colormap = R_GetTranslationColormap(skinnum, color, GTC_CACHE); colormap = R_GetTranslationColormap(skinnum, color, 0);
LUA_PushUserdata(L, colormap, META_COLORMAP); // push as META_COLORMAP userdata, specifically for patches to use! LUA_PushUserdata(L, colormap, META_COLORMAP); // push as META_COLORMAP userdata, specifically for patches to use!
return 1; return 1;
} }
@ -957,10 +1066,14 @@ static int libd_getStringColormap(lua_State *L)
{ {
INT32 flags = luaL_checkinteger(L, 1); INT32 flags = luaL_checkinteger(L, 1);
UINT8* colormap = NULL; UINT8* colormap = NULL;
UINT8* lua_colormap = NULL;
HUDONLY HUDONLY
colormap = V_GetStringColormap(flags & V_CHARCOLORMASK); colormap = V_GetStringColormap(flags & V_CHARCOLORMASK);
if (colormap) { if (colormap) {
LUA_PushUserdata(L, colormap, META_COLORMAP); // push as META_COLORMAP userdata, specifically for patches to use! lua_colormap = Z_Malloc(256 * sizeof(UINT8), PU_LUA, NULL);
memcpy(lua_colormap, colormap, 256 * sizeof(UINT8));
LUA_PushUserdata(L, lua_colormap, META_COLORMAP); // push as META_COLORMAP userdata, specifically for patches to use!
return 1; return 1;
} }
return 0; return 0;
@ -1121,6 +1234,7 @@ static luaL_Reg lib_draw[] = {
{"draw", libd_draw}, {"draw", libd_draw},
{"drawScaled", libd_drawScaled}, {"drawScaled", libd_drawScaled},
{"drawStretched", libd_drawStretched}, {"drawStretched", libd_drawStretched},
{"drawCropped", libd_drawCropped},
{"drawNum", libd_drawNum}, {"drawNum", libd_drawNum},
{"drawPaddedNum", libd_drawPaddedNum}, {"drawPaddedNum", libd_drawPaddedNum},
{"drawFill", libd_drawFill}, {"drawFill", libd_drawFill},
@ -1152,6 +1266,8 @@ static luaL_Reg lib_draw[] = {
{NULL, NULL} {NULL, NULL}
}; };
static int lib_draw_ref;
// //
// lib_hud // lib_hud
// //
@ -1186,28 +1302,7 @@ static int lib_hudenabled(lua_State *L)
// add a HUD element for rendering // add a HUD element for rendering
static int lib_hudadd(lua_State *L) extern int lib_hudadd(lua_State *L);
{
enum hudhook field;
luaL_checktype(L, 1, LUA_TFUNCTION);
field = luaL_checkoption(L, 2, "game", hudhook_opt);
if (!lua_lumploading)
return luaL_error(L, "This function cannot be called from within a hook or coroutine!");
lua_getfield(L, LUA_REGISTRYINDEX, "HUD");
I_Assert(lua_istable(L, -1));
lua_rawgeti(L, -1, field+2); // HUD[2+]
I_Assert(lua_istable(L, -1));
lua_remove(L, -2);
lua_pushvalue(L, 1);
lua_rawseti(L, -2, (int)(lua_objlen(L, -2) + 1));
hudAvailable |= 1<<field;
return 0;
}
static luaL_Reg lib_hud[] = { static luaL_Reg lib_hud[] = {
{"enable", lib_hudenable}, {"enable", lib_hudenable},
@ -1225,26 +1320,9 @@ int LUA_HudLib(lua_State *L)
{ {
memset(hud_enabled, 0xff, (hud_MAX/8)+1); memset(hud_enabled, 0xff, (hud_MAX/8)+1);
lua_newtable(L); // HUD registry table lua_newtable(L);
lua_newtable(L); luaL_register(L, NULL, lib_draw);
luaL_register(L, NULL, lib_draw); lib_draw_ref = luaL_ref(L, LUA_REGISTRYINDEX);
lua_rawseti(L, -2, 1); // HUD[1] = lib_draw
lua_newtable(L);
lua_rawseti(L, -2, 2); // HUD[2] = game rendering functions array
lua_newtable(L);
lua_rawseti(L, -2, 3); // HUD[3] = scores rendering functions array
lua_newtable(L);
lua_rawseti(L, -2, 4); // HUD[4] = intermission rendering functions array
lua_newtable(L);
lua_rawseti(L, -2, 5); // HUD[5] = title rendering functions array
lua_newtable(L);
lua_rawseti(L, -2, 6); // HUD[6] = title card rendering functions array
lua_setfield(L, LUA_REGISTRYINDEX, "HUD");
luaL_newmetatable(L, META_HUDINFO); luaL_newmetatable(L, META_HUDINFO);
lua_pushcfunction(L, hudinfo_get); lua_pushcfunction(L, hudinfo_get);
@ -1270,6 +1348,12 @@ int LUA_HudLib(lua_State *L)
luaL_newmetatable(L, META_COLORMAP); luaL_newmetatable(L, META_COLORMAP);
lua_pushcfunction(L, colormap_get); lua_pushcfunction(L, colormap_get);
lua_setfield(L, -2, "__index"); lua_setfield(L, -2, "__index");
lua_pushcfunction(L, colormap_set);
lua_setfield(L, -2, "__newindex");
lua_pushcfunction(L, colormap_free);
lua_setfield(L, -2, "__gc");
lua_pop(L,1); lua_pop(L,1);
luaL_newmetatable(L, META_PATCH); luaL_newmetatable(L, META_PATCH);
@ -1283,6 +1367,9 @@ int LUA_HudLib(lua_State *L)
luaL_newmetatable(L, META_CAMERA); luaL_newmetatable(L, META_CAMERA);
lua_pushcfunction(L, camera_get); lua_pushcfunction(L, camera_get);
lua_setfield(L, -2, "__index"); lua_setfield(L, -2, "__index");
lua_pushcfunction(L, camera_set);
lua_setfield(L, -2, "__newindex");
lua_pop(L,1); lua_pop(L,1);
luaL_register(L, "hud", lib_hud); luaL_register(L, "hud", lib_hud);
@ -1296,160 +1383,29 @@ boolean LUA_HudEnabled(enum hud option)
return false; return false;
} }
// Hook for HUD rendering void LUA_SetHudHook(int hook)
void LUAh_GameHUD(player_t *stplayr)
{ {
if (!gL || !(hudAvailable & (1<<hudhook_game))) lua_getref(gL, lib_draw_ref);
return;
hud_running = true; switch (hook)
lua_settop(gL, 0); {
case HUD_HOOK(game): {
camera_t *cam = (splitscreen && stplyr ==
&players[secondarydisplayplayer])
? &camera2 : &camera;
lua_pushcfunction(gL, LUA_GetErrorMessage); LUA_PushUserdata(gL, stplyr, META_PLAYER);
LUA_PushUserdata(gL, cam, META_CAMERA);
} break;
lua_getfield(gL, LUA_REGISTRYINDEX, "HUD"); case HUD_HOOK(titlecard):
I_Assert(lua_istable(gL, -1)); LUA_PushUserdata(gL, stplyr, META_PLAYER);
lua_rawgeti(gL, -1, 2+hudhook_game); // HUD[2] = rendering funcs lua_pushinteger(gL, lt_ticker);
I_Assert(lua_istable(gL, -1)); lua_pushinteger(gL, (lt_endtime + TICRATE));
break;
lua_rawgeti(gL, -2, 1); // HUD[1] = lib_draw case HUD_HOOK(intermission):
I_Assert(lua_istable(gL, -1)); lua_pushboolean(gL, intertype == int_spec &&
lua_remove(gL, -3); // pop HUD stagefailed);
LUA_PushUserdata(gL, stplayr, META_PLAYER);
if (splitscreen && stplayr == &players[secondarydisplayplayer])
LUA_PushUserdata(gL, &camera2, META_CAMERA);
else
LUA_PushUserdata(gL, &camera, META_CAMERA);
lua_pushnil(gL);
while (lua_next(gL, -5) != 0) {
lua_pushvalue(gL, -5); // graphics library (HUD[1])
lua_pushvalue(gL, -5); // stplayr
lua_pushvalue(gL, -5); // camera
LUA_Call(gL, 3, 0, 1);
} }
lua_settop(gL, 0);
hud_running = false;
}
void LUAh_ScoresHUD(void)
{
if (!gL || !(hudAvailable & (1<<hudhook_scores)))
return;
hud_running = true;
lua_settop(gL, 0);
lua_pushcfunction(gL, LUA_GetErrorMessage);
lua_getfield(gL, LUA_REGISTRYINDEX, "HUD");
I_Assert(lua_istable(gL, -1));
lua_rawgeti(gL, -1, 2+hudhook_scores); // HUD[3] = rendering funcs
I_Assert(lua_istable(gL, -1));
lua_rawgeti(gL, -2, 1); // HUD[1] = lib_draw
I_Assert(lua_istable(gL, -1));
lua_remove(gL, -3); // pop HUD
lua_pushnil(gL);
while (lua_next(gL, -3) != 0) {
lua_pushvalue(gL, -3); // graphics library (HUD[1])
LUA_Call(gL, 1, 0, 1);
}
lua_settop(gL, 0);
hud_running = false;
}
void LUAh_TitleHUD(void)
{
if (!gL || !(hudAvailable & (1<<hudhook_title)))
return;
hud_running = true;
lua_settop(gL, 0);
lua_pushcfunction(gL, LUA_GetErrorMessage);
lua_getfield(gL, LUA_REGISTRYINDEX, "HUD");
I_Assert(lua_istable(gL, -1));
lua_rawgeti(gL, -1, 2+hudhook_title); // HUD[5] = rendering funcs
I_Assert(lua_istable(gL, -1));
lua_rawgeti(gL, -2, 1); // HUD[1] = lib_draw
I_Assert(lua_istable(gL, -1));
lua_remove(gL, -3); // pop HUD
lua_pushnil(gL);
while (lua_next(gL, -3) != 0) {
lua_pushvalue(gL, -3); // graphics library (HUD[1])
LUA_Call(gL, 1, 0, 1);
}
lua_settop(gL, 0);
hud_running = false;
}
void LUAh_TitleCardHUD(player_t *stplayr)
{
if (!gL || !(hudAvailable & (1<<hudhook_titlecard)))
return;
hud_running = true;
lua_settop(gL, 0);
lua_pushcfunction(gL, LUA_GetErrorMessage);
lua_getfield(gL, LUA_REGISTRYINDEX, "HUD");
I_Assert(lua_istable(gL, -1));
lua_rawgeti(gL, -1, 2+hudhook_titlecard); // HUD[6] = rendering funcs
I_Assert(lua_istable(gL, -1));
lua_rawgeti(gL, -2, 1); // HUD[1] = lib_draw
I_Assert(lua_istable(gL, -1));
lua_remove(gL, -3); // pop HUD
LUA_PushUserdata(gL, stplayr, META_PLAYER);
lua_pushinteger(gL, lt_ticker);
lua_pushinteger(gL, (lt_endtime + TICRATE));
lua_pushnil(gL);
while (lua_next(gL, -6) != 0) {
lua_pushvalue(gL, -6); // graphics library (HUD[1])
lua_pushvalue(gL, -6); // stplayr
lua_pushvalue(gL, -6); // lt_ticker
lua_pushvalue(gL, -6); // lt_endtime
LUA_Call(gL, 4, 0, 1);
}
lua_settop(gL, 0);
hud_running = false;
}
void LUAh_IntermissionHUD(boolean failedstage)
{
if (!gL || !(hudAvailable & (1<<hudhook_intermission)))
return;
hud_running = true;
lua_settop(gL, 0);
lua_pushcfunction(gL, LUA_GetErrorMessage);
lua_getfield(gL, LUA_REGISTRYINDEX, "HUD");
I_Assert(lua_istable(gL, -1));
lua_rawgeti(gL, -1, 2+hudhook_intermission); // HUD[4] = rendering funcs
I_Assert(lua_istable(gL, -1));
lua_rawgeti(gL, -2, 1); // HUD[1] = lib_draw
I_Assert(lua_istable(gL, -1));
lua_remove(gL, -3); // pop HUD
lua_pushboolean(gL, failedstage); // stagefailed
lua_pushnil(gL);
while (lua_next(gL, -4) != 0) {
lua_pushvalue(gL, -4); // graphics library (HUD[1])
lua_pushvalue(gL, -4); // stagefailed
LUA_Call(gL, 2, 0, 1);
}
lua_settop(gL, 0);
hud_running = false;
} }

View file

@ -19,6 +19,8 @@
#include "lua_script.h" #include "lua_script.h"
#include "lua_libs.h" #include "lua_libs.h"
boolean mousegrabbedbylua = true;
/////////////// ///////////////
// FUNCTIONS // // FUNCTIONS //
/////////////// ///////////////
@ -26,8 +28,8 @@
static int lib_gameControlDown(lua_State *L) static int lib_gameControlDown(lua_State *L)
{ {
int i = luaL_checkinteger(L, 1); int i = luaL_checkinteger(L, 1);
if (i < 0 || i >= num_gamecontrols) if (i < 0 || i >= NUM_GAMECONTROLS)
return luaL_error(L, "gc_* constant %d out of range (0 - %d)", i, num_gamecontrols-1); return luaL_error(L, "GC_* constant %d out of range (0 - %d)", i, NUM_GAMECONTROLS-1);
lua_pushinteger(L, PLAYER1INPUTDOWN(i)); lua_pushinteger(L, PLAYER1INPUTDOWN(i));
return 1; return 1;
} }
@ -35,8 +37,8 @@ static int lib_gameControlDown(lua_State *L)
static int lib_gameControl2Down(lua_State *L) static int lib_gameControl2Down(lua_State *L)
{ {
int i = luaL_checkinteger(L, 1); int i = luaL_checkinteger(L, 1);
if (i < 0 || i >= num_gamecontrols) if (i < 0 || i >= NUM_GAMECONTROLS)
return luaL_error(L, "gc_* constant %d out of range (0 - %d)", i, num_gamecontrols-1); return luaL_error(L, "GC_* constant %d out of range (0 - %d)", i, NUM_GAMECONTROLS-1);
lua_pushinteger(L, PLAYER2INPUTDOWN(i)); lua_pushinteger(L, PLAYER2INPUTDOWN(i));
return 1; return 1;
} }
@ -44,8 +46,8 @@ static int lib_gameControl2Down(lua_State *L)
static int lib_gameControlToKeyNum(lua_State *L) static int lib_gameControlToKeyNum(lua_State *L)
{ {
int i = luaL_checkinteger(L, 1); int i = luaL_checkinteger(L, 1);
if (i < 0 || i >= num_gamecontrols) if (i < 0 || i >= NUM_GAMECONTROLS)
return luaL_error(L, "gc_* constant %d out of range (0 - %d)", i, num_gamecontrols-1); return luaL_error(L, "GC_* constant %d out of range (0 - %d)", i, NUM_GAMECONTROLS-1);
lua_pushinteger(L, gamecontrol[i][0]); lua_pushinteger(L, gamecontrol[i][0]);
lua_pushinteger(L, gamecontrol[i][1]); lua_pushinteger(L, gamecontrol[i][1]);
return 2; return 2;
@ -54,8 +56,8 @@ static int lib_gameControlToKeyNum(lua_State *L)
static int lib_gameControl2ToKeyNum(lua_State *L) static int lib_gameControl2ToKeyNum(lua_State *L)
{ {
int i = luaL_checkinteger(L, 1); int i = luaL_checkinteger(L, 1);
if (i < 0 || i >= num_gamecontrols) if (i < 0 || i >= NUM_GAMECONTROLS)
return luaL_error(L, "gc_* constant %d out of range (0 - %d)", i, num_gamecontrols-1); return luaL_error(L, "GC_* constant %d out of range (0 - %d)", i, NUM_GAMECONTROLS-1);
lua_pushinteger(L, gamecontrolbis[i][0]); lua_pushinteger(L, gamecontrolbis[i][0]);
lua_pushinteger(L, gamecontrolbis[i][1]); lua_pushinteger(L, gamecontrolbis[i][1]);
return 2; return 2;
@ -75,17 +77,17 @@ static int lib_joy2Axis(lua_State *L)
return 1; return 1;
} }
static int lib_keyNumToString(lua_State *L) static int lib_keyNumToName(lua_State *L)
{ {
int i = luaL_checkinteger(L, 1); int i = luaL_checkinteger(L, 1);
lua_pushstring(L, G_KeyNumToString(i)); lua_pushstring(L, G_KeyNumToName(i));
return 1; return 1;
} }
static int lib_keyStringToNum(lua_State *L) static int lib_keyNameToNum(lua_State *L)
{ {
const char *str = luaL_checkstring(L, 1); const char *str = luaL_checkstring(L, 1);
lua_pushinteger(L, G_KeyStringToNum(str)); lua_pushinteger(L, G_KeyNameToNum(str));
return 1; return 1;
} }
@ -106,14 +108,14 @@ static int lib_shiftKeyNum(lua_State *L)
static int lib_getMouseGrab(lua_State *L) static int lib_getMouseGrab(lua_State *L)
{ {
lua_pushboolean(L, I_GetMouseGrab()); lua_pushboolean(L, mousegrabbedbylua);
return 1; return 1;
} }
static int lib_setMouseGrab(lua_State *L) static int lib_setMouseGrab(lua_State *L)
{ {
boolean grab = luaL_checkboolean(L, 1); mousegrabbedbylua = luaL_checkboolean(L, 1);
I_SetMouseGrab(grab); I_UpdateMouseGrab();
return 0; return 0;
} }
@ -127,19 +129,19 @@ static int lib_getCursorPosition(lua_State *L)
} }
static luaL_Reg lib[] = { static luaL_Reg lib[] = {
{"G_GameControlDown", lib_gameControlDown}, {"gameControlDown", lib_gameControlDown},
{"G_GameControl2Down", lib_gameControl2Down}, {"gameControl2Down", lib_gameControl2Down},
{"G_GameControlToKeyNum", lib_gameControlToKeyNum}, {"gameControlToKeyNum", lib_gameControlToKeyNum},
{"G_GameControl2ToKeyNum", lib_gameControl2ToKeyNum}, {"gameControl2ToKeyNum", lib_gameControl2ToKeyNum},
{"G_JoyAxis", lib_joyAxis}, {"joyAxis", lib_joyAxis},
{"G_Joy2Axis", lib_joy2Axis}, {"joy2Axis", lib_joy2Axis},
{"G_KeyNumToString", lib_keyNumToString}, {"keyNumToName", lib_keyNumToName},
{"G_KeyStringToNum", lib_keyStringToNum}, {"keyNameToNum", lib_keyNameToNum},
{"HU_KeyNumPrintable", lib_keyNumPrintable}, {"keyNumPrintable", lib_keyNumPrintable},
{"HU_ShiftKeyNum", lib_shiftKeyNum}, {"shiftKeyNum", lib_shiftKeyNum},
{"I_GetMouseGrab", lib_getMouseGrab}, {"getMouseGrab", lib_getMouseGrab},
{"I_SetMouseGrab", lib_setMouseGrab}, {"setMouseGrab", lib_setMouseGrab},
{"I_GetCursorPosition", lib_getCursorPosition}, {"getCursorPosition", lib_getCursorPosition},
{NULL, NULL} {NULL, NULL}
}; };
@ -172,6 +174,29 @@ static int lib_lenGameKeyDown(lua_State *L)
return 1; return 1;
} }
///////////////
// KEY EVENT //
///////////////
static int keyevent_get(lua_State *L)
{
event_t *event = *((event_t **)luaL_checkudata(L, 1, META_KEYEVENT));
const char *field = luaL_checkstring(L, 2);
I_Assert(event != NULL);
if (fastcmp(field,"name"))
lua_pushstring(L, G_KeyNumToName(event->key));
else if (fastcmp(field,"num"))
lua_pushinteger(L, event->key);
else if (fastcmp(field,"repeated"))
lua_pushboolean(L, event->repeated);
else
return luaL_error(L, "keyevent_t has no field named %s", field);
return 1;
}
/////////// ///////////
// MOUSE // // MOUSE //
/////////// ///////////
@ -227,6 +252,11 @@ int LUA_InputLib(lua_State *L)
lua_setmetatable(L, -2); lua_setmetatable(L, -2);
lua_setglobal(L, "gamekeydown"); lua_setglobal(L, "gamekeydown");
luaL_newmetatable(L, META_KEYEVENT);
lua_pushcfunction(L, keyevent_get);
lua_setfield(L, -2, "__index");
lua_pop(L, 1);
luaL_newmetatable(L, META_MOUSE); luaL_newmetatable(L, META_MOUSE);
lua_pushcfunction(L, mouse_get); lua_pushcfunction(L, mouse_get);
lua_setfield(L, -2, "__index"); lua_setfield(L, -2, "__index");
@ -235,8 +265,6 @@ int LUA_InputLib(lua_State *L)
lua_setfield(L, -2, "__len"); lua_setfield(L, -2, "__len");
lua_pop(L, 1); lua_pop(L, 1);
// Set global functions luaL_register(L, "input", lib);
lua_pushvalue(L, LUA_GLOBALSINDEX);
luaL_register(L, NULL, lib);
return 0; return 0;
} }

View file

@ -12,6 +12,8 @@
extern lua_State *gL; extern lua_State *gL;
extern boolean mousegrabbedbylua;
#define MUTABLE_TAGS #define MUTABLE_TAGS
#define LREG_VALID "VALID_USERDATA" #define LREG_VALID "VALID_USERDATA"
@ -88,6 +90,7 @@ extern lua_State *gL;
#define META_LUABANKS "LUABANKS[]*" #define META_LUABANKS "LUABANKS[]*"
#define META_KEYEVENT "KEYEVENT_T*"
#define META_MOUSE "MOUSE_T*" #define META_MOUSE "MOUSE_T*"
boolean luaL_checkboolean(lua_State *L, int narg); boolean luaL_checkboolean(lua_State *L, int narg);

View file

@ -370,6 +370,12 @@ static int player_get(lua_State *L)
lua_pushboolean(L, plr->outofcoop); lua_pushboolean(L, plr->outofcoop);
else if (fastcmp(field,"bot")) else if (fastcmp(field,"bot"))
lua_pushinteger(L, plr->bot); lua_pushinteger(L, plr->bot);
else if (fastcmp(field,"botleader"))
LUA_PushUserdata(L, plr->botleader, META_PLAYER);
else if (fastcmp(field,"lastbuttons"))
lua_pushinteger(L, plr->lastbuttons);
else if (fastcmp(field,"blocked"))
lua_pushboolean(L, plr->blocked);
else if (fastcmp(field,"jointime")) else if (fastcmp(field,"jointime"))
lua_pushinteger(L, plr->jointime); lua_pushinteger(L, plr->jointime);
else if (fastcmp(field,"quittime")) else if (fastcmp(field,"quittime"))
@ -719,6 +725,17 @@ static int player_set(lua_State *L)
plr->outofcoop = lua_toboolean(L, 3); plr->outofcoop = lua_toboolean(L, 3);
else if (fastcmp(field,"bot")) else if (fastcmp(field,"bot"))
return NOSET; return NOSET;
else if (fastcmp(field,"botleader"))
{
player_t *player = NULL;
if (!lua_isnil(L, 3))
player = *((player_t **)luaL_checkudata(L, 3, META_PLAYER));
plr->botleader = player;
}
else if (fastcmp(field,"lastbuttons"))
plr->lastbuttons = (UINT16)luaL_checkinteger(L, 3);
else if (fastcmp(field,"blocked"))
plr->blocked = (UINT8)luaL_checkinteger(L, 3);
else if (fastcmp(field,"jointime")) else if (fastcmp(field,"jointime"))
plr->jointime = (tic_t)luaL_checkinteger(L, 3); plr->jointime = (tic_t)luaL_checkinteger(L, 3);
else if (fastcmp(field,"quittime")) else if (fastcmp(field,"quittime"))

View file

@ -25,7 +25,7 @@
#include "byteptr.h" #include "byteptr.h"
#include "p_saveg.h" #include "p_saveg.h"
#include "p_local.h" #include "p_local.h"
#include "p_slopes.h" // for P_SlopeById #include "p_slopes.h" // for P_SlopeById and slopelist
#include "p_polyobj.h" // polyobj_t, PolyObjects #include "p_polyobj.h" // polyobj_t, PolyObjects
#ifdef LUA_ALLOW_BYTECODE #ifdef LUA_ALLOW_BYTECODE
#include "d_netfil.h" // for LUA_DumpFile #include "d_netfil.h" // for LUA_DumpFile
@ -393,6 +393,14 @@ int LUA_PushGlobals(lua_State *L, const char *word)
} else if (fastcmp(word, "mouse2")) { } else if (fastcmp(word, "mouse2")) {
LUA_PushUserdata(L, &mouse2, META_MOUSE); LUA_PushUserdata(L, &mouse2, META_MOUSE);
return 1; return 1;
} else if (fastcmp(word, "camera")) {
LUA_PushUserdata(L, &camera, META_CAMERA);
return 1;
} else if (fastcmp(word, "camera2")) {
if (!splitscreen)
return 0;
LUA_PushUserdata(L, &camera2, META_CAMERA);
return 1;
} }
return 0; return 0;
} }
@ -851,6 +859,8 @@ void LUA_InvalidateLevel(void)
{ {
LUA_InvalidateUserdata(&lines[i]); LUA_InvalidateUserdata(&lines[i]);
LUA_InvalidateUserdata(&lines[i].tags); LUA_InvalidateUserdata(&lines[i].tags);
LUA_InvalidateUserdata(lines[i].args);
LUA_InvalidateUserdata(lines[i].stringargs);
LUA_InvalidateUserdata(lines[i].sidenum); LUA_InvalidateUserdata(lines[i].sidenum);
} }
for (i = 0; i < numsides; i++) for (i = 0; i < numsides; i++)
@ -863,6 +873,13 @@ void LUA_InvalidateLevel(void)
LUA_InvalidateUserdata(&PolyObjects[i].vertices); LUA_InvalidateUserdata(&PolyObjects[i].vertices);
LUA_InvalidateUserdata(&PolyObjects[i].lines); LUA_InvalidateUserdata(&PolyObjects[i].lines);
} }
for (pslope_t *slope = slopelist; slope; slope = slope->next)
{
LUA_InvalidateUserdata(slope);
LUA_InvalidateUserdata(&slope->normal);
LUA_InvalidateUserdata(&slope->o);
LUA_InvalidateUserdata(&slope->d);
}
#ifdef HAVE_LUA_SEGS #ifdef HAVE_LUA_SEGS
for (i = 0; i < numsegs; i++) for (i = 0; i < numsegs; i++)
LUA_InvalidateUserdata(&segs[i]); LUA_InvalidateUserdata(&segs[i]);
@ -885,6 +902,8 @@ void LUA_InvalidateMapthings(void)
{ {
LUA_InvalidateUserdata(&mapthings[i]); LUA_InvalidateUserdata(&mapthings[i]);
LUA_InvalidateUserdata(&mapthings[i].tags); LUA_InvalidateUserdata(&mapthings[i].tags);
LUA_InvalidateUserdata(mapthings[i].args);
LUA_InvalidateUserdata(mapthings[i].stringargs);
} }
} }
@ -1373,21 +1392,13 @@ static void ArchiveTables(void)
// Write key // Write key
e = ArchiveValue(TABLESINDEX, -2); // key should be either a number or a string, ArchiveValue can handle this. e = ArchiveValue(TABLESINDEX, -2); // key should be either a number or a string, ArchiveValue can handle this.
if (e == 2) // invalid key type (function, thread, lightuserdata, or anything we don't recognise) if (e == 2) // invalid key type (function, thread, lightuserdata, or anything we don't recognise)
{ CONS_Alert(CONS_ERROR, "Index '%s' (%s) of table %d could not be archived!\n", lua_tostring(gL, -2), luaL_typename(gL, -2), i);
lua_pushvalue(gL, -2);
CONS_Alert(CONS_ERROR, "Index '%s' (%s) of table %d could not be archived!\n", lua_tostring(gL, -1), luaL_typename(gL, -1), i);
lua_pop(gL, 1);
}
// Write value // Write value
e = ArchiveValue(TABLESINDEX, -1); e = ArchiveValue(TABLESINDEX, -1);
if (e == 1) if (e == 1)
n++; // the table contained a new table we'll have to archive. :( n++; // the table contained a new table we'll have to archive. :(
else if (e == 2) // invalid value type else if (e == 2) // invalid value type
{ CONS_Alert(CONS_ERROR, "Type of value for table %d entry '%s' (%s) could not be archived!\n", i, lua_tostring(gL, -2), luaL_typename(gL, -1));
lua_pushvalue(gL, -2);
CONS_Alert(CONS_ERROR, "Type of value for table %d entry '%s' (%s) could not be archived!\n", i, lua_tostring(gL, -1), luaL_typename(gL, -1));
lua_pop(gL, 1);
}
lua_pop(gL, 1); lua_pop(gL, 1);
} }

View file

@ -203,11 +203,11 @@ boolean cht_Responder(event_t *ev)
if (ev->type != ev_keydown) if (ev->type != ev_keydown)
return false; return false;
if (ev->data1 > 0xFF) if (ev->key > 0xFF)
{ {
// map some fake (joy) inputs into keys // map some fake (joy) inputs into keys
// map joy inputs into keys // map joy inputs into keys
switch (ev->data1) switch (ev->key)
{ {
case KEY_JOY1: case KEY_JOY1:
case KEY_JOY1 + 2: case KEY_JOY1 + 2:
@ -231,7 +231,7 @@ boolean cht_Responder(event_t *ev)
} }
} }
else else
ch = (UINT8)ev->data1; ch = (UINT8)ev->key;
ret += cht_CheckCheat(&cheat_ultimate, (char)ch); ret += cht_CheckCheat(&cheat_ultimate, (char)ch);
ret += cht_CheckCheat(&cheat_ultimate_joy, (char)ch); ret += cht_CheckCheat(&cheat_ultimate_joy, (char)ch);

View file

@ -1106,55 +1106,55 @@ static menuitem_t OP_ChangeControlsMenu[] =
{ {
{IT_HEADER, NULL, "Movement", NULL, 0}, {IT_HEADER, NULL, "Movement", NULL, 0},
{IT_SPACE, NULL, NULL, NULL, 0}, // padding {IT_SPACE, NULL, NULL, NULL, 0}, // padding
{IT_CALL | IT_STRING2, NULL, "Move Forward", M_ChangeControl, gc_forward }, {IT_CALL | IT_STRING2, NULL, "Move Forward", M_ChangeControl, GC_FORWARD },
{IT_CALL | IT_STRING2, NULL, "Move Backward", M_ChangeControl, gc_backward }, {IT_CALL | IT_STRING2, NULL, "Move Backward", M_ChangeControl, GC_BACKWARD },
{IT_CALL | IT_STRING2, NULL, "Move Left", M_ChangeControl, gc_strafeleft }, {IT_CALL | IT_STRING2, NULL, "Move Left", M_ChangeControl, GC_STRAFELEFT },
{IT_CALL | IT_STRING2, NULL, "Move Right", M_ChangeControl, gc_straferight }, {IT_CALL | IT_STRING2, NULL, "Move Right", M_ChangeControl, GC_STRAFERIGHT },
{IT_CALL | IT_STRING2, NULL, "Jump", M_ChangeControl, gc_jump }, {IT_CALL | IT_STRING2, NULL, "Jump", M_ChangeControl, GC_JUMP },
{IT_CALL | IT_STRING2, NULL, "Spin", M_ChangeControl, gc_spin }, {IT_CALL | IT_STRING2, NULL, "Spin", M_ChangeControl, GC_SPIN },
{IT_HEADER, NULL, "Camera", NULL, 0}, {IT_HEADER, NULL, "Camera", NULL, 0},
{IT_SPACE, NULL, NULL, NULL, 0}, // padding {IT_SPACE, NULL, NULL, NULL, 0}, // padding
{IT_CALL | IT_STRING2, NULL, "Look Up", M_ChangeControl, gc_lookup }, {IT_CALL | IT_STRING2, NULL, "Look Up", M_ChangeControl, GC_LOOKUP },
{IT_CALL | IT_STRING2, NULL, "Look Down", M_ChangeControl, gc_lookdown }, {IT_CALL | IT_STRING2, NULL, "Look Down", M_ChangeControl, GC_LOOKDOWN },
{IT_CALL | IT_STRING2, NULL, "Look Left", M_ChangeControl, gc_turnleft }, {IT_CALL | IT_STRING2, NULL, "Look Left", M_ChangeControl, GC_TURNLEFT },
{IT_CALL | IT_STRING2, NULL, "Look Right", M_ChangeControl, gc_turnright }, {IT_CALL | IT_STRING2, NULL, "Look Right", M_ChangeControl, GC_TURNRIGHT },
{IT_CALL | IT_STRING2, NULL, "Center View", M_ChangeControl, gc_centerview }, {IT_CALL | IT_STRING2, NULL, "Center View", M_ChangeControl, GC_CENTERVIEW },
{IT_CALL | IT_STRING2, NULL, "Toggle Mouselook", M_ChangeControl, gc_mouseaiming }, {IT_CALL | IT_STRING2, NULL, "Toggle Mouselook", M_ChangeControl, GC_MOUSEAIMING },
{IT_CALL | IT_STRING2, NULL, "Toggle Third-Person", M_ChangeControl, gc_camtoggle}, {IT_CALL | IT_STRING2, NULL, "Toggle Third-Person", M_ChangeControl, GC_CAMTOGGLE},
{IT_CALL | IT_STRING2, NULL, "Reset Camera", M_ChangeControl, gc_camreset }, {IT_CALL | IT_STRING2, NULL, "Reset Camera", M_ChangeControl, GC_CAMRESET },
{IT_HEADER, NULL, "Meta", NULL, 0}, {IT_HEADER, NULL, "Meta", NULL, 0},
{IT_SPACE, NULL, NULL, NULL, 0}, // padding {IT_SPACE, NULL, NULL, NULL, 0}, // padding
{IT_CALL | IT_STRING2, NULL, "Game Status", {IT_CALL | IT_STRING2, NULL, "Game Status",
M_ChangeControl, gc_scores }, M_ChangeControl, GC_SCORES },
{IT_CALL | IT_STRING2, NULL, "Pause / Run Retry", M_ChangeControl, gc_pause }, {IT_CALL | IT_STRING2, NULL, "Pause / Run Retry", M_ChangeControl, GC_PAUSE },
{IT_CALL | IT_STRING2, NULL, "Screenshot", M_ChangeControl, gc_screenshot }, {IT_CALL | IT_STRING2, NULL, "Screenshot", M_ChangeControl, GC_SCREENSHOT },
{IT_CALL | IT_STRING2, NULL, "Toggle GIF Recording", M_ChangeControl, gc_recordgif }, {IT_CALL | IT_STRING2, NULL, "Toggle GIF Recording", M_ChangeControl, GC_RECORDGIF },
{IT_CALL | IT_STRING2, NULL, "Open/Close Menu (ESC)", M_ChangeControl, gc_systemmenu }, {IT_CALL | IT_STRING2, NULL, "Open/Close Menu (ESC)", M_ChangeControl, GC_SYSTEMMENU },
{IT_CALL | IT_STRING2, NULL, "Change Viewpoint", M_ChangeControl, gc_viewpoint }, {IT_CALL | IT_STRING2, NULL, "Change Viewpoint", M_ChangeControl, GC_VIEWPOINT },
{IT_CALL | IT_STRING2, NULL, "Console", M_ChangeControl, gc_console }, {IT_CALL | IT_STRING2, NULL, "Console", M_ChangeControl, GC_CONSOLE },
{IT_HEADER, NULL, "Multiplayer", NULL, 0}, {IT_HEADER, NULL, "Multiplayer", NULL, 0},
{IT_SPACE, NULL, NULL, NULL, 0}, // padding {IT_SPACE, NULL, NULL, NULL, 0}, // padding
{IT_CALL | IT_STRING2, NULL, "Talk", M_ChangeControl, gc_talkkey }, {IT_CALL | IT_STRING2, NULL, "Talk", M_ChangeControl, GC_TALKKEY },
{IT_CALL | IT_STRING2, NULL, "Talk (Team only)", M_ChangeControl, gc_teamkey }, {IT_CALL | IT_STRING2, NULL, "Talk (Team only)", M_ChangeControl, GC_TEAMKEY },
{IT_HEADER, NULL, "Ringslinger (Match, CTF, Tag, H&S)", NULL, 0}, {IT_HEADER, NULL, "Ringslinger (Match, CTF, Tag, H&S)", NULL, 0},
{IT_SPACE, NULL, NULL, NULL, 0}, // padding {IT_SPACE, NULL, NULL, NULL, 0}, // padding
{IT_CALL | IT_STRING2, NULL, "Fire", M_ChangeControl, gc_fire }, {IT_CALL | IT_STRING2, NULL, "Fire", M_ChangeControl, GC_FIRE },
{IT_CALL | IT_STRING2, NULL, "Fire Normal", M_ChangeControl, gc_firenormal }, {IT_CALL | IT_STRING2, NULL, "Fire Normal", M_ChangeControl, GC_FIRENORMAL },
{IT_CALL | IT_STRING2, NULL, "Toss Flag", M_ChangeControl, gc_tossflag }, {IT_CALL | IT_STRING2, NULL, "Toss Flag", M_ChangeControl, GC_TOSSFLAG },
{IT_CALL | IT_STRING2, NULL, "Next Weapon", M_ChangeControl, gc_weaponnext }, {IT_CALL | IT_STRING2, NULL, "Next Weapon", M_ChangeControl, GC_WEAPONNEXT },
{IT_CALL | IT_STRING2, NULL, "Prev Weapon", M_ChangeControl, gc_weaponprev }, {IT_CALL | IT_STRING2, NULL, "Prev Weapon", M_ChangeControl, GC_WEAPONPREV },
{IT_CALL | IT_STRING2, NULL, "Normal / Infinity", M_ChangeControl, gc_wepslot1 }, {IT_CALL | IT_STRING2, NULL, "Normal / Infinity", M_ChangeControl, GC_WEPSLOT1 },
{IT_CALL | IT_STRING2, NULL, "Automatic", M_ChangeControl, gc_wepslot2 }, {IT_CALL | IT_STRING2, NULL, "Automatic", M_ChangeControl, GC_WEPSLOT2 },
{IT_CALL | IT_STRING2, NULL, "Bounce", M_ChangeControl, gc_wepslot3 }, {IT_CALL | IT_STRING2, NULL, "Bounce", M_ChangeControl, GC_WEPSLOT3 },
{IT_CALL | IT_STRING2, NULL, "Scatter", M_ChangeControl, gc_wepslot4 }, {IT_CALL | IT_STRING2, NULL, "Scatter", M_ChangeControl, GC_WEPSLOT4 },
{IT_CALL | IT_STRING2, NULL, "Grenade", M_ChangeControl, gc_wepslot5 }, {IT_CALL | IT_STRING2, NULL, "Grenade", M_ChangeControl, GC_WEPSLOT5 },
{IT_CALL | IT_STRING2, NULL, "Explosion", M_ChangeControl, gc_wepslot6 }, {IT_CALL | IT_STRING2, NULL, "Explosion", M_ChangeControl, GC_WEPSLOT6 },
{IT_CALL | IT_STRING2, NULL, "Rail", M_ChangeControl, gc_wepslot7 }, {IT_CALL | IT_STRING2, NULL, "Rail", M_ChangeControl, GC_WEPSLOT7 },
{IT_HEADER, NULL, "Add-ons", NULL, 0}, {IT_HEADER, NULL, "Add-ons", NULL, 0},
{IT_SPACE, NULL, NULL, NULL, 0}, // padding {IT_SPACE, NULL, NULL, NULL, 0}, // padding
{IT_CALL | IT_STRING2, NULL, "Custom Action 1", M_ChangeControl, gc_custom1 }, {IT_CALL | IT_STRING2, NULL, "Custom Action 1", M_ChangeControl, GC_CUSTOM1 },
{IT_CALL | IT_STRING2, NULL, "Custom Action 2", M_ChangeControl, gc_custom2 }, {IT_CALL | IT_STRING2, NULL, "Custom Action 2", M_ChangeControl, GC_CUSTOM2 },
{IT_CALL | IT_STRING2, NULL, "Custom Action 3", M_ChangeControl, gc_custom3 }, {IT_CALL | IT_STRING2, NULL, "Custom Action 3", M_ChangeControl, GC_CUSTOM3 },
}; };
static menuitem_t OP_Joystick1Menu[] = static menuitem_t OP_Joystick1Menu[] =
@ -3229,7 +3229,7 @@ boolean M_Responder(event_t *ev)
if (ev->type == ev_keydown) if (ev->type == ev_keydown)
{ {
keydown++; keydown++;
ch = ev->data1; ch = ev->key;
// added 5-2-98 remap virtual keys (mouse & joystick buttons) // added 5-2-98 remap virtual keys (mouse & joystick buttons)
switch (ch) switch (ch)
@ -3262,44 +3262,44 @@ boolean M_Responder(event_t *ev)
break; break;
} }
} }
else if (ev->type == ev_joystick && ev->data1 == 0 && joywait < I_GetTime()) else if (ev->type == ev_joystick && ev->key == 0 && joywait < I_GetTime())
{ {
const INT32 jdeadzone = (JOYAXISRANGE * cv_digitaldeadzone.value) / FRACUNIT; const INT32 jdeadzone = (JOYAXISRANGE * cv_digitaldeadzone.value) / FRACUNIT;
if (ev->data3 != INT32_MAX) if (ev->y != INT32_MAX)
{ {
if (Joystick.bGamepadStyle || abs(ev->data3) > jdeadzone) if (Joystick.bGamepadStyle || abs(ev->y) > jdeadzone)
{ {
if (ev->data3 < 0 && pjoyy >= 0) if (ev->y < 0 && pjoyy >= 0)
{ {
ch = KEY_UPARROW; ch = KEY_UPARROW;
joywait = I_GetTime() + NEWTICRATE/7; joywait = I_GetTime() + NEWTICRATE/7;
} }
else if (ev->data3 > 0 && pjoyy <= 0) else if (ev->y > 0 && pjoyy <= 0)
{ {
ch = KEY_DOWNARROW; ch = KEY_DOWNARROW;
joywait = I_GetTime() + NEWTICRATE/7; joywait = I_GetTime() + NEWTICRATE/7;
} }
pjoyy = ev->data3; pjoyy = ev->y;
} }
else else
pjoyy = 0; pjoyy = 0;
} }
if (ev->data2 != INT32_MAX) if (ev->x != INT32_MAX)
{ {
if (Joystick.bGamepadStyle || abs(ev->data2) > jdeadzone) if (Joystick.bGamepadStyle || abs(ev->x) > jdeadzone)
{ {
if (ev->data2 < 0 && pjoyx >= 0) if (ev->x < 0 && pjoyx >= 0)
{ {
ch = KEY_LEFTARROW; ch = KEY_LEFTARROW;
joywait = I_GetTime() + NEWTICRATE/17; joywait = I_GetTime() + NEWTICRATE/17;
} }
else if (ev->data2 > 0 && pjoyx <= 0) else if (ev->x > 0 && pjoyx <= 0)
{ {
ch = KEY_RIGHTARROW; ch = KEY_RIGHTARROW;
joywait = I_GetTime() + NEWTICRATE/17; joywait = I_GetTime() + NEWTICRATE/17;
} }
pjoyx = ev->data2; pjoyx = ev->x;
} }
else else
pjoyx = 0; pjoyx = 0;
@ -3307,7 +3307,7 @@ boolean M_Responder(event_t *ev)
} }
else if (ev->type == ev_mouse && mousewait < I_GetTime()) else if (ev->type == ev_mouse && mousewait < I_GetTime())
{ {
pmousey -= ev->data3; pmousey -= ev->y;
if (pmousey < lasty-30) if (pmousey < lasty-30)
{ {
ch = KEY_DOWNARROW; ch = KEY_DOWNARROW;
@ -3321,7 +3321,7 @@ boolean M_Responder(event_t *ev)
pmousey = lasty += 30; pmousey = lasty += 30;
} }
pmousex += ev->data2; pmousex += ev->x;
if (pmousex < lastx - 30) if (pmousex < lastx - 30)
{ {
ch = KEY_LEFTARROW; ch = KEY_LEFTARROW;
@ -3339,11 +3339,11 @@ boolean M_Responder(event_t *ev)
keydown = 0; keydown = 0;
} }
else if (ev->type == ev_keydown) // Preserve event for other responders else if (ev->type == ev_keydown) // Preserve event for other responders
ch = ev->data1; ch = ev->key;
if (ch == -1) if (ch == -1)
return false; return false;
else if (ch == gamecontrol[gc_systemmenu][0] || ch == gamecontrol[gc_systemmenu][1]) // allow remappable ESC key else if (ch == gamecontrol[GC_SYSTEMMENU][0] || ch == gamecontrol[GC_SYSTEMMENU][1]) // allow remappable ESC key
ch = KEY_ESCAPE; ch = KEY_ESCAPE;
// F-Keys // F-Keys
@ -4185,7 +4185,7 @@ static void M_DrawStaticBox(fixed_t x, fixed_t y, INT32 flags, fixed_t w, fixed_
if (staticalong > pw) // simplified for base LSSTATIC if (staticalong > pw) // simplified for base LSSTATIC
staticalong -= pw; staticalong -= pw;
V_DrawCroppedPatch(x<<FRACBITS, y<<FRACBITS, FRACUNIT/2, flags, patch, staticalong, 0, sw, h*2); // FixedDiv(h, scale)); -- for scale FRACUNIT/2 V_DrawCroppedPatch(x<<FRACBITS, y<<FRACBITS, FRACUNIT/2, FRACUNIT/2, flags, patch, NULL, staticalong<<FRACBITS, 0, sw<<FRACBITS, h*2<<FRACBITS); // FixedDiv(h, scale)); -- for scale FRACUNIT/2
staticalong += sw; //M_RandomRange(sw/2, 2*sw); -- turns out less randomisation looks better because immediately adjacent frames can't end up close to each other staticalong += sw; //M_RandomRange(sw/2, 2*sw); -- turns out less randomisation looks better because immediately adjacent frames can't end up close to each other
@ -12826,13 +12826,13 @@ static void M_DrawControl(void)
else else
{ {
if (keys[0] != KEY_NULL) if (keys[0] != KEY_NULL)
strcat (tmp, G_KeyNumToString (keys[0])); strcat (tmp, G_KeyNumToName (keys[0]));
if (keys[0] != KEY_NULL && keys[1] != KEY_NULL) if (keys[0] != KEY_NULL && keys[1] != KEY_NULL)
strcat(tmp," or "); strcat(tmp," or ");
if (keys[1] != KEY_NULL) if (keys[1] != KEY_NULL)
strcat (tmp, G_KeyNumToString (keys[1])); strcat (tmp, G_KeyNumToName (keys[1]));
} }
@ -12859,7 +12859,7 @@ static void M_ChangecontrolResponse(event_t *ev)
{ {
INT32 control; INT32 control;
INT32 found; INT32 found;
INT32 ch = ev->data1; INT32 ch = ev->key;
// ESCAPE cancels; dummy out PAUSE // ESCAPE cancels; dummy out PAUSE
if (ch != KEY_ESCAPE && ch != KEY_PAUSE) if (ch != KEY_ESCAPE && ch != KEY_PAUSE)
@ -12878,7 +12878,7 @@ static void M_ChangecontrolResponse(event_t *ev)
// keypad arrows are converted for the menu in cursor arrows // keypad arrows are converted for the menu in cursor arrows
// so use the event instead of ch // so use the event instead of ch
case ev_keydown: case ev_keydown:
ch = ev->data1; ch = ev->key;
break; break;
default: default:
@ -12929,7 +12929,7 @@ static void M_ChangecontrolResponse(event_t *ev)
static char tmp[158]; static char tmp[158];
menu_t *prev = currentMenu->prevMenu; menu_t *prev = currentMenu->prevMenu;
if (controltochange == gc_pause) if (controltochange == GC_PAUSE)
sprintf(tmp, M_GetText("The \x82Pause Key \x80is enabled, but \nit cannot be used to retry runs \nduring Record Attack. \n\nHit another key for\n%s\nESC for Cancel"), sprintf(tmp, M_GetText("The \x82Pause Key \x80is enabled, but \nit cannot be used to retry runs \nduring Record Attack. \n\nHit another key for\n%s\nESC for Cancel"),
controltochangetext); controltochangetext);
else else

View file

@ -1631,14 +1631,14 @@ boolean M_ScreenshotResponder(event_t *ev)
if (dedicated || ev->type != ev_keydown) if (dedicated || ev->type != ev_keydown)
return false; return false;
ch = ev->data1; ch = ev->key;
if (ch >= KEY_MOUSE1 && menuactive) // If it's not a keyboard key, then don't allow it in the menus! if (ch >= KEY_MOUSE1 && menuactive) // If it's not a keyboard key, then don't allow it in the menus!
return false; return false;
if (ch == KEY_F8 || ch == gamecontrol[gc_screenshot][0] || ch == gamecontrol[gc_screenshot][1]) // remappable F8 if (ch == KEY_F8 || ch == gamecontrol[GC_SCREENSHOT][0] || ch == gamecontrol[GC_SCREENSHOT][1]) // remappable F8
M_ScreenShot(); M_ScreenShot();
else if (ch == KEY_F9 || ch == gamecontrol[gc_recordgif][0] || ch == gamecontrol[gc_recordgif][1]) // remappable F9 else if (ch == KEY_F9 || ch == gamecontrol[GC_RECORDGIF][0] || ch == gamecontrol[GC_RECORDGIF][1]) // remappable F9
((moviemode) ? M_StopMovie : M_StartMovie)(); ((moviemode) ? M_StopMovie : M_StartMovie)();
else else
return false; return false;
@ -2688,3 +2688,22 @@ const char * M_Ftrim (double f)
return &dig[1];/* skip the 0 */ return &dig[1];/* skip the 0 */
} }
} }
// Returns true if the string is empty.
boolean M_IsStringEmpty(const char *s)
{
const char *ch = s;
if (s == NULL || s[0] == '\0')
return true;
for (;;ch++)
{
if (!(*ch))
break;
if (!isspace((*ch)))
return false;
}
return true;
}

View file

@ -117,6 +117,9 @@ trailing zeros, or "" if the fractional part is zero.
*/ */
const char * M_Ftrim (double); const char * M_Ftrim (double);
// Returns true if the string is empty.
boolean M_IsStringEmpty(const char *s);
// counting bits, for weapon ammo code, usually // counting bits, for weapon ammo code, usually
FUNCMATH UINT8 M_CountBits(UINT32 num, UINT8 size); FUNCMATH UINT8 M_CountBits(UINT32 num, UINT8 size);

View file

@ -744,8 +744,8 @@ boolean P_LookForPlayers(mobj_t *actor, boolean allaround, boolean tracer, fixed
if (player->mo->health <= 0) if (player->mo->health <= 0)
continue; // dead continue; // dead
if (player->bot) if (player->bot == BOT_2PAI || player->bot == BOT_2PHUMAN)
continue; // ignore bots continue; // ignore followbots
if (player->quittime) if (player->quittime)
continue; // Ignore uncontrolled bodies continue; // Ignore uncontrolled bodies
@ -3591,7 +3591,7 @@ void A_1upThinker(mobj_t *actor)
for (i = 0; i < MAXPLAYERS; i++) for (i = 0; i < MAXPLAYERS; i++)
{ {
if (!playeringame[i] || players[i].bot || players[i].spectator) if (!playeringame[i] || players[i].bot == BOT_2PAI || players[i].bot == BOT_2PHUMAN || players[i].spectator)
continue; continue;
if (!players[i].mo) if (!players[i].mo)
@ -8259,7 +8259,7 @@ void A_Boss3ShockThink(mobj_t *actor)
fixed_t x0, y0, x1, y1; fixed_t x0, y0, x1, y1;
// Break the link if movements are too different // Break the link if movements are too different
if (FixedHypot(snext->momx - actor->momx, snext->momy - actor->momy) > 12*actor->scale) if (R_PointToDist2(0, 0, snext->momx - actor->momx, snext->momy - actor->momy) > 12*actor->scale)
{ {
P_SetTarget(&actor->hnext, NULL); P_SetTarget(&actor->hnext, NULL);
return; return;
@ -8270,15 +8270,21 @@ void A_Boss3ShockThink(mobj_t *actor)
y0 = actor->y; y0 = actor->y;
x1 = snext->x; x1 = snext->x;
y1 = snext->y; y1 = snext->y;
if (FixedHypot(x1 - x0, y1 - y0) > 2*actor->radius) if (R_PointToDist2(0, 0, x1 - x0, y1 - y0) > 2*actor->radius)
{ {
snew = P_SpawnMobj((x0 + x1) >> 1, (y0 + y1) >> 1, (actor->z + snext->z) >> 1, actor->type); snew = P_SpawnMobj((x0 >> 1) + (x1 >> 1),
(y0 >> 1) + (y1 >> 1),
(actor->z >> 1) + (snext->z >> 1), actor->type);
snew->momx = (actor->momx + snext->momx) >> 1; snew->momx = (actor->momx + snext->momx) >> 1;
snew->momy = (actor->momy + snext->momy) >> 1; snew->momy = (actor->momy + snext->momy) >> 1;
snew->momz = (actor->momz + snext->momz) >> 1; // is this really needed? snew->momz = (actor->momz + snext->momz) >> 1; // is this really needed?
snew->angle = (actor->angle + snext->angle) >> 1; snew->angle = (actor->angle + snext->angle) >> 1;
P_SetTarget(&snew->target, actor->target); P_SetTarget(&snew->target, actor->target);
snew->fuse = actor->fuse; snew->fuse = actor->fuse;
P_SetScale(snew, actor->scale);
snew->destscale = actor->destscale;
snew->scalespeed = actor->scalespeed;
P_SetTarget(&actor->hnext, snew); P_SetTarget(&actor->hnext, snew);
P_SetTarget(&snew->hnext, snext); P_SetTarget(&snew->hnext, snext);

View file

@ -151,7 +151,7 @@ boolean P_CanPickupItem(player_t *player, boolean weapon)
if (!player->mo || player->mo->health <= 0) if (!player->mo || player->mo->health <= 0)
return false; return false;
if (player->bot) if (player->bot && player->bot != BOT_MPAI)
{ {
if (weapon) if (weapon)
return false; return false;
@ -178,7 +178,7 @@ void P_DoNightsScore(player_t *player)
return; // Don't do any fancy shit for failures. return; // Don't do any fancy shit for failures.
dummymo = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z+player->mo->height/2, MT_NIGHTSCORE); dummymo = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z+player->mo->height/2, MT_NIGHTSCORE);
if (player->bot) if (player->bot && player->bot != BOT_MPAI)
player = &players[consoleplayer]; player = &players[consoleplayer];
if (G_IsSpecialStage(gamemap)) // Global link count? Maybe not a good idea... if (G_IsSpecialStage(gamemap)) // Global link count? Maybe not a good idea...
@ -470,14 +470,14 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
if (!(player->charability2 == CA2_MELEE && player->panim == PA_ABILITY2)) if (!(player->charability2 == CA2_MELEE && player->panim == PA_ABILITY2))
{ {
fixed_t setmomz = -toucher->momz; // Store this, momz get changed by P_DoJump within P_DoBubbleBounce fixed_t setmomz = -toucher->momz; // Store this, momz get changed by P_DoJump within P_DoBubbleBounce
if (elementalpierce == 2) // Reset bubblewrap, part 1 if (elementalpierce == 2) // Reset bubblewrap, part 1
P_DoBubbleBounce(player); P_DoBubbleBounce(player);
toucher->momz = setmomz; toucher->momz = setmomz;
if (elementalpierce == 2) // Reset bubblewrap, part 2 if (elementalpierce == 2) // Reset bubblewrap, part 2
{ {
boolean underwater = toucher->eflags & MFE_UNDERWATER; boolean underwater = toucher->eflags & MFE_UNDERWATER;
if (underwater) if (underwater)
toucher->momz /= 2; toucher->momz /= 2;
toucher->momz -= (toucher->momz/(underwater ? 8 : 4)); // Cap the height! toucher->momz -= (toucher->momz/(underwater ? 8 : 4)); // Cap the height!
@ -630,7 +630,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
// ***************************** // // ***************************** //
// Special Stage Token // Special Stage Token
case MT_TOKEN: case MT_TOKEN:
if (player->bot) if (player->bot && player->bot != BOT_MPAI)
return; return;
P_AddPlayerScore(player, 1000); P_AddPlayerScore(player, 1000);
@ -670,7 +670,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
// Emerald Hunt // Emerald Hunt
case MT_EMERHUNT: case MT_EMERHUNT:
if (player->bot) if (player->bot && player->bot != BOT_MPAI)
return; return;
if (hunt1 == special) if (hunt1 == special)
@ -701,7 +701,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
case MT_EMERALD5: case MT_EMERALD5:
case MT_EMERALD6: case MT_EMERALD6:
case MT_EMERALD7: case MT_EMERALD7:
if (player->bot) if (player->bot && player->bot != BOT_MPAI)
return; return;
if (special->threshold) if (special->threshold)
@ -738,7 +738,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
// Secret emblem thingy // Secret emblem thingy
case MT_EMBLEM: case MT_EMBLEM:
{ {
if (demoplayback || player->bot) if (demoplayback || (player->bot && player->bot != BOT_MPAI))
return; return;
emblemlocations[special->health-1].collected = true; emblemlocations[special->health-1].collected = true;
@ -751,7 +751,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
// CTF Flags // CTF Flags
case MT_REDFLAG: case MT_REDFLAG:
case MT_BLUEFLAG: case MT_BLUEFLAG:
if (player->bot) if (player->bot && player->bot != BOT_MPAI)
return; return;
if (player->powers[pw_flashing] || player->tossdelay) if (player->powers[pw_flashing] || player->tossdelay)
return; return;
@ -826,7 +826,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
{ {
boolean spec = G_IsSpecialStage(gamemap); boolean spec = G_IsSpecialStage(gamemap);
boolean cangiveemmy = false; boolean cangiveemmy = false;
if (player->bot) if (player->bot && player->bot != BOT_MPAI)
return; return;
if (player->exiting) if (player->exiting)
return; return;
@ -1072,7 +1072,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
} }
return; return;
case MT_EGGCAPSULE: case MT_EGGCAPSULE:
if (player->bot) if (player->bot && player->bot != BOT_MPAI)
return; return;
// make sure everything is as it should be, THEN take rings from players in special stages // make sure everything is as it should be, THEN take rings from players in special stages
@ -1164,7 +1164,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
} }
return; return;
case MT_NIGHTSSUPERLOOP: case MT_NIGHTSSUPERLOOP:
if (player->bot || !(player->powers[pw_carry] == CR_NIGHTSMODE)) if ((player->bot && player->bot != BOT_MPAI) || !(player->powers[pw_carry] == CR_NIGHTSMODE))
return; return;
if (!G_IsSpecialStage(gamemap)) if (!G_IsSpecialStage(gamemap))
player->powers[pw_nights_superloop] = (UINT16)special->info->speed; player->powers[pw_nights_superloop] = (UINT16)special->info->speed;
@ -1186,7 +1186,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
} }
break; break;
case MT_NIGHTSDRILLREFILL: case MT_NIGHTSDRILLREFILL:
if (player->bot || !(player->powers[pw_carry] == CR_NIGHTSMODE)) if ((player->bot && player->bot != BOT_MPAI) || !(player->powers[pw_carry] == CR_NIGHTSMODE))
return; return;
if (!G_IsSpecialStage(gamemap)) if (!G_IsSpecialStage(gamemap))
player->drillmeter = special->info->speed; player->drillmeter = special->info->speed;
@ -1208,7 +1208,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
} }
break; break;
case MT_NIGHTSHELPER: case MT_NIGHTSHELPER:
if (player->bot || !(player->powers[pw_carry] == CR_NIGHTSMODE)) if ((player->bot && player->bot != BOT_MPAI) || !(player->powers[pw_carry] == CR_NIGHTSMODE))
return; return;
if (!G_IsSpecialStage(gamemap)) if (!G_IsSpecialStage(gamemap))
{ {
@ -1240,7 +1240,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
} }
break; break;
case MT_NIGHTSEXTRATIME: case MT_NIGHTSEXTRATIME:
if (player->bot || !(player->powers[pw_carry] == CR_NIGHTSMODE)) if ((player->bot && player->bot != BOT_MPAI) || !(player->powers[pw_carry] == CR_NIGHTSMODE))
return; return;
if (!G_IsSpecialStage(gamemap)) if (!G_IsSpecialStage(gamemap))
{ {
@ -1272,7 +1272,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
} }
break; break;
case MT_NIGHTSLINKFREEZE: case MT_NIGHTSLINKFREEZE:
if (player->bot || !(player->powers[pw_carry] == CR_NIGHTSMODE)) if ((player->bot && player->bot != BOT_MPAI) || !(player->powers[pw_carry] == CR_NIGHTSMODE))
return; return;
if (!G_IsSpecialStage(gamemap)) if (!G_IsSpecialStage(gamemap))
{ {
@ -1332,7 +1332,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
if (playeringame[i] && players[i].powers[pw_carry] == CR_NIGHTSMODE) if (playeringame[i] && players[i].powers[pw_carry] == CR_NIGHTSMODE)
players[i].drillmeter += TICRATE/2; players[i].drillmeter += TICRATE/2;
} }
else if (player->bot) else if (player->bot && player->bot != BOT_MPAI)
players[consoleplayer].drillmeter += TICRATE/2; players[consoleplayer].drillmeter += TICRATE/2;
else else
player->drillmeter += TICRATE/2; player->drillmeter += TICRATE/2;
@ -1384,7 +1384,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
thinker_t *th; thinker_t *th;
mobj_t *mo2; mobj_t *mo2;
if (player->bot) if (player->bot && player->bot != BOT_MPAI)
return; return;
EV_DoElevator(LE_AXE, NULL, bridgeFall); EV_DoElevator(LE_AXE, NULL, bridgeFall);
@ -1417,7 +1417,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
return; return;
} }
case MT_FIREFLOWER: case MT_FIREFLOWER:
if (player->bot) if (player->bot && player->bot != BOT_MPAI)
return; return;
S_StartSound(toucher, sfx_mario3); S_StartSound(toucher, sfx_mario3);
@ -1611,7 +1611,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
if (special->tracer && !(special->tracer->flags2 & MF2_STRONGBOX)) if (special->tracer && !(special->tracer->flags2 & MF2_STRONGBOX))
macespin = true; macespin = true;
if (macespin ? (player->powers[pw_ignorelatch] & (1<<15)) : (player->powers[pw_ignorelatch])) if (macespin ? (player->powers[pw_ignorelatch] & (1<<15)) : (player->powers[pw_ignorelatch]))
return; return;
@ -1679,7 +1679,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
return; // Only go in the mouth return; // Only go in the mouth
// Eaten by player! // Eaten by player!
if ((!player->bot) && (player->powers[pw_underwater] && player->powers[pw_underwater] <= 12*TICRATE + 1)) if ((!player->bot || player->bot == BOT_MPAI) && (player->powers[pw_underwater] && player->powers[pw_underwater] <= 12*TICRATE + 1))
{ {
player->powers[pw_underwater] = underwatertics + 1; player->powers[pw_underwater] = underwatertics + 1;
P_RestoreMusic(player); P_RestoreMusic(player);
@ -1690,7 +1690,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
if (!player->climbing) if (!player->climbing)
{ {
if (player->bot && toucher->state-states != S_PLAY_GASP) if (player->bot && player->bot != BOT_MPAI && toucher->state-states != S_PLAY_GASP)
S_StartSound(toucher, special->info->deathsound); // Force it to play a sound for bots S_StartSound(toucher, special->info->deathsound); // Force it to play a sound for bots
P_SetPlayerMobjState(toucher, S_PLAY_GASP); P_SetPlayerMobjState(toucher, S_PLAY_GASP);
P_ResetPlayer(player); P_ResetPlayer(player);
@ -1698,7 +1698,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
toucher->momx = toucher->momy = toucher->momz = 0; toucher->momx = toucher->momy = toucher->momz = 0;
if (player->bot) if (player->bot && player->bot != BOT_MPAI)
return; return;
else else
break; break;
@ -1730,7 +1730,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
return; return;
case MT_MINECARTSPAWNER: case MT_MINECARTSPAWNER:
if (!player->bot && special->fuse <= TICRATE && player->powers[pw_carry] != CR_MINECART && !(player->powers[pw_ignorelatch] & (1<<15))) if (!player->bot && player->bot != BOT_MPAI && special->fuse <= TICRATE && player->powers[pw_carry] != CR_MINECART && !(player->powers[pw_ignorelatch] & (1<<15)))
{ {
mobj_t *mcart = P_SpawnMobj(special->x, special->y, special->z, MT_MINECART); mobj_t *mcart = P_SpawnMobj(special->x, special->y, special->z, MT_MINECART);
P_SetTarget(&mcart->target, toucher); P_SetTarget(&mcart->target, toucher);
@ -1783,7 +1783,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
} }
return; return;
default: // SOC or script pickup default: // SOC or script pickup
if (player->bot) if (player->bot && player->bot != BOT_MPAI)
return; return;
P_SetTarget(&special->target, toucher); P_SetTarget(&special->target, toucher);
break; break;
@ -1807,7 +1807,7 @@ void P_TouchStarPost(mobj_t *post, player_t *player, boolean snaptopost)
mobj_t *toucher = player->mo; mobj_t *toucher = player->mo;
mobj_t *checkbase = snaptopost ? post : toucher; mobj_t *checkbase = snaptopost ? post : toucher;
if (player->bot) if (player->bot && player->bot != BOT_MPAI)
return; return;
// In circuit, player must have touched all previous starposts // In circuit, player must have touched all previous starposts
if (circuitmap if (circuitmap
@ -2549,7 +2549,7 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget
if ((target->player->lives <= 1) && (netgame || multiplayer) && G_GametypeUsesCoopLives() && (cv_cooplives.value == 0)) if ((target->player->lives <= 1) && (netgame || multiplayer) && G_GametypeUsesCoopLives() && (cv_cooplives.value == 0))
; ;
else if (!target->player->bot && !target->player->spectator && (target->player->lives != INFLIVES) else if ((!target->player->bot || target->player->bot == BOT_MPAI) && !target->player->spectator && (target->player->lives != INFLIVES)
&& G_GametypeUsesLives()) && G_GametypeUsesLives())
{ {
if (!(target->player->pflags & PF_FINISHED)) if (!(target->player->pflags & PF_FINISHED))
@ -3469,7 +3469,7 @@ void P_SpecialStageDamage(player_t *player, mobj_t *inflictor, mobj_t *source)
if (inflictor && inflictor->type == MT_LHRT) if (inflictor && inflictor->type == MT_LHRT)
return; return;
if (player->powers[pw_shield] || player->bot) //If One-Hit Shield if (player->powers[pw_shield] || (player->bot && player->bot != BOT_MPAI)) //If One-Hit Shield
{ {
P_RemoveShield(player); P_RemoveShield(player);
S_StartSound(player->mo, sfx_shldls); // Ba-Dum! Shield loss. S_StartSound(player->mo, sfx_shldls); // Ba-Dum! Shield loss.
@ -3560,7 +3560,7 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
return false; return false;
// Make sure that boxes cannot be popped by enemies, red rings, etc. // Make sure that boxes cannot be popped by enemies, red rings, etc.
if (target->flags & MF_MONITOR && ((!source || !source->player || source->player->bot) if (target->flags & MF_MONITOR && ((!source || !source->player || (source->player->bot && source->player->bot != BOT_MPAI))
|| (inflictor && (inflictor->type == MT_REDRING || (inflictor->type >= MT_THROWNBOUNCE && inflictor->type <= MT_THROWNGRENADE))))) || (inflictor && (inflictor->type == MT_REDRING || (inflictor->type >= MT_THROWNBOUNCE && inflictor->type <= MT_THROWNGRENADE)))))
return false; return false;
} }
@ -3695,7 +3695,7 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
} }
else if (LUA_HookMobjDamage(target, inflictor, source, damage, damagetype)) else if (LUA_HookMobjDamage(target, inflictor, source, damage, damagetype))
return true; return true;
else if (player->powers[pw_shield] || (player->bot && !ultimatemode)) //If One-Hit Shield else if (player->powers[pw_shield] || (player->bot && player->bot != BOT_MPAI && !ultimatemode)) //If One-Hit Shield
{ {
P_ShieldDamage(player, inflictor, source, damage, damagetype); P_ShieldDamage(player, inflictor, source, damage, damagetype);
damage = 0; damage = 0;

View file

@ -1844,12 +1844,10 @@ void P_XYMovement(mobj_t *mo)
// blocked move // blocked move
moved = false; moved = false;
if (player) { if (player)
if (player->bot) B_MoveBlocked(player);
B_MoveBlocked(player);
}
if (LUA_HookMobj(mo, MOBJ_HOOK(MobjMoveBlocked))) if (LUA_HookMobjMoveBlocked(mo, tmhitthing, blockingline))
{ {
if (P_MobjWasRemoved(mo)) if (P_MobjWasRemoved(mo))
return; return;
@ -2554,6 +2552,10 @@ boolean P_ZMovement(mobj_t *mo)
} }
P_CheckPosition(mo, mo->x, mo->y); // Sets mo->standingslope correctly P_CheckPosition(mo, mo->x, mo->y); // Sets mo->standingslope correctly
if (P_MobjWasRemoved(mo)) // mobjs can be removed by P_CheckPosition -- Monster Iestyn 31/07/21
return false;
if (((mo->eflags & MFE_VERTICALFLIP) ? tmceilingslope : tmfloorslope) && (mo->type != MT_STEAM)) if (((mo->eflags & MFE_VERTICALFLIP) ? tmceilingslope : tmfloorslope) && (mo->type != MT_STEAM))
{ {
mo->standingslope = (mo->eflags & MFE_VERTICALFLIP) ? tmceilingslope : tmfloorslope; mo->standingslope = (mo->eflags & MFE_VERTICALFLIP) ? tmceilingslope : tmfloorslope;
@ -4141,7 +4143,7 @@ boolean P_BossTargetPlayer(mobj_t *actor, boolean closest)
player = &players[actor->lastlook]; player = &players[actor->lastlook];
if (player->pflags & PF_INVIS || player->bot || player->spectator) if (player->pflags & PF_INVIS || player->bot == BOT_2PAI || player->bot == BOT_2PHUMAN || player->spectator)
continue; // ignore notarget continue; // ignore notarget
if (!player->mo || P_MobjWasRemoved(player->mo)) if (!player->mo || P_MobjWasRemoved(player->mo))
@ -4182,7 +4184,7 @@ boolean P_SupermanLook4Players(mobj_t *actor)
if (players[c].pflags & PF_INVIS) if (players[c].pflags & PF_INVIS)
continue; // ignore notarget continue; // ignore notarget
if (!players[c].mo || players[c].bot) if (!players[c].mo || players[c].bot == BOT_2PAI || players[c].bot == BOT_2PHUMAN)
continue; continue;
if (players[c].mo->health <= 0) if (players[c].mo->health <= 0)
@ -7311,7 +7313,7 @@ static void P_RosySceneryThink(mobj_t *mobj)
continue; continue;
if (!players[i].mo) if (!players[i].mo)
continue; continue;
if (players[i].bot) if (players[i].bot == BOT_2PAI || players[i].bot == BOT_2PHUMAN)
continue; continue;
if (!players[i].mo->health) if (!players[i].mo->health)
continue; continue;
@ -10392,6 +10394,9 @@ static fixed_t P_DefaultMobjShadowScale (mobj_t *thing)
case MT_RING: case MT_RING:
case MT_FLINGRING: case MT_FLINGRING:
case MT_COIN:
case MT_FLINGCOIN:
case MT_BLUESPHERE: case MT_BLUESPHERE:
case MT_FLINGBLUESPHERE: case MT_FLINGBLUESPHERE:
@ -11056,7 +11061,7 @@ void P_SpawnPrecipitation(void)
subsector_t *precipsector = NULL; subsector_t *precipsector = NULL;
precipmobj_t *rainmo = NULL; precipmobj_t *rainmo = NULL;
if (dedicated || !(cv_drawdist_precip.value) || curWeather == PRECIP_NONE) if (dedicated || !(cv_drawdist_precip.value) || curWeather == PRECIP_NONE || curWeather == PRECIP_STORM_NORAIN)
return; return;
// Use the blockmap to narrow down our placing patterns // Use the blockmap to narrow down our placing patterns
@ -11102,22 +11107,14 @@ void P_SpawnPrecipitation(void)
continue; continue;
rainmo = P_SpawnRainMobj(x, y, height, MT_RAIN); rainmo = P_SpawnRainMobj(x, y, height, MT_RAIN);
if (curWeather == PRECIP_BLANK)
rainmo->precipflags |= PCF_INVISIBLE;
} }
// Randomly assign a height, now that floorz is set. // Randomly assign a height, now that floorz is set.
rainmo->z = M_RandomRange(rainmo->floorz>>FRACBITS, rainmo->ceilingz>>FRACBITS)<<FRACBITS; rainmo->z = M_RandomRange(rainmo->floorz>>FRACBITS, rainmo->ceilingz>>FRACBITS)<<FRACBITS;
} }
if (curWeather == PRECIP_BLANK)
{
curWeather = PRECIP_RAIN;
P_SwitchWeather(PRECIP_BLANK);
}
else if (curWeather == PRECIP_STORM_NORAIN)
{
curWeather = PRECIP_RAIN;
P_SwitchWeather(PRECIP_STORM_NORAIN);
}
} }
// //

View file

@ -193,6 +193,19 @@ static void P_NetArchivePlayers(void)
WRITEUINT32(save_p, players[i].dashmode); WRITEUINT32(save_p, players[i].dashmode);
WRITEUINT32(save_p, players[i].skidtime); WRITEUINT32(save_p, players[i].skidtime);
//////////
// Bots //
//////////
WRITEUINT8(save_p, players[i].bot);
WRITEUINT8(save_p, players[i].botmem.lastForward);
WRITEUINT8(save_p, players[i].botmem.lastBlocked);
WRITEUINT8(save_p, players[i].botmem.catchup_tics);
WRITEUINT8(save_p, players[i].botmem.thinkstate);
WRITEUINT8(save_p, players[i].removing);
WRITEUINT8(save_p, players[i].blocked);
WRITEUINT16(save_p, players[i].lastbuttons);
//////////////////////////// ////////////////////////////
// Conveyor Belt Movement // // Conveyor Belt Movement //
//////////////////////////// ////////////////////////////
@ -407,6 +420,20 @@ static void P_NetUnArchivePlayers(void)
players[i].dashmode = READUINT32(save_p); // counter for dashmode ability players[i].dashmode = READUINT32(save_p); // counter for dashmode ability
players[i].skidtime = READUINT32(save_p); // Skid timer players[i].skidtime = READUINT32(save_p); // Skid timer
//////////
// Bots //
//////////
players[i].bot = READUINT8(save_p);
players[i].botmem.lastForward = READUINT8(save_p);
players[i].botmem.lastBlocked = READUINT8(save_p);
players[i].botmem.catchup_tics = READUINT8(save_p);
players[i].botmem.thinkstate = READUINT8(save_p);
players[i].removing = READUINT8(save_p);
players[i].blocked = READUINT8(save_p);
players[i].lastbuttons = READUINT16(save_p);
//////////////////////////// ////////////////////////////
// Conveyor Belt Movement // // Conveyor Belt Movement //
//////////////////////////// ////////////////////////////

View file

@ -1501,6 +1501,22 @@ typedef struct textmap_colormap_s {
textmap_colormap_t textmap_colormap = { false, 0, 25, 0, 25, 0, 31, 0 }; textmap_colormap_t textmap_colormap = { false, 0, 25, 0, 25, 0, 31, 0 };
typedef enum
{
PD_A = 1,
PD_B = 1<<1,
PD_C = 1<<2,
PD_D = 1<<3,
} planedef_t;
typedef struct textmap_plane_s {
UINT8 defined;
fixed_t a, b, c, d;
} textmap_plane_t;
textmap_plane_t textmap_planefloor = {0, 0, 0, 0, 0};
textmap_plane_t textmap_planeceiling = {0, 0, 0, 0, 0};
static void ParseTextmapSectorParameter(UINT32 i, char *param, char *val) static void ParseTextmapSectorParameter(UINT32 i, char *param, char *val)
{ {
if (fastcmp(param, "heightfloor")) if (fastcmp(param, "heightfloor"))
@ -1539,6 +1555,46 @@ static void ParseTextmapSectorParameter(UINT32 i, char *param, char *val)
sectors[i].floorpic_angle = FixedAngle(FLOAT_TO_FIXED(atof(val))); sectors[i].floorpic_angle = FixedAngle(FLOAT_TO_FIXED(atof(val)));
else if (fastcmp(param, "rotationceiling")) else if (fastcmp(param, "rotationceiling"))
sectors[i].ceilingpic_angle = FixedAngle(FLOAT_TO_FIXED(atof(val))); sectors[i].ceilingpic_angle = FixedAngle(FLOAT_TO_FIXED(atof(val)));
else if (fastcmp(param, "floorplane_a"))
{
textmap_planefloor.defined |= PD_A;
textmap_planefloor.a = FLOAT_TO_FIXED(atof(val));
}
else if (fastcmp(param, "floorplane_b"))
{
textmap_planefloor.defined |= PD_B;
textmap_planefloor.b = FLOAT_TO_FIXED(atof(val));
}
else if (fastcmp(param, "floorplane_c"))
{
textmap_planefloor.defined |= PD_C;
textmap_planefloor.c = FLOAT_TO_FIXED(atof(val));
}
else if (fastcmp(param, "floorplane_d"))
{
textmap_planefloor.defined |= PD_D;
textmap_planefloor.d = FLOAT_TO_FIXED(atof(val));
}
else if (fastcmp(param, "ceilingplane_a"))
{
textmap_planeceiling.defined |= PD_A;
textmap_planeceiling.a = FLOAT_TO_FIXED(atof(val));
}
else if (fastcmp(param, "ceilingplane_b"))
{
textmap_planeceiling.defined |= PD_B;
textmap_planeceiling.b = FLOAT_TO_FIXED(atof(val));
}
else if (fastcmp(param, "ceilingplane_c"))
{
textmap_planeceiling.defined |= PD_C;
textmap_planeceiling.c = FLOAT_TO_FIXED(atof(val));
}
else if (fastcmp(param, "ceilingplane_d"))
{
textmap_planeceiling.defined |= PD_D;
textmap_planeceiling.d = FLOAT_TO_FIXED(atof(val));
}
else if (fastcmp(param, "lightcolor")) else if (fastcmp(param, "lightcolor"))
{ {
textmap_colormap.used = true; textmap_colormap.used = true;
@ -1868,6 +1924,10 @@ static void P_LoadTextmap(void)
textmap_colormap.fadestart = 0; textmap_colormap.fadestart = 0;
textmap_colormap.fadeend = 31; textmap_colormap.fadeend = 31;
textmap_colormap.flags = 0; textmap_colormap.flags = 0;
textmap_planefloor.defined = 0;
textmap_planeceiling.defined = 0;
TextmapParse(sectorsPos[i], i, ParseTextmapSectorParameter); TextmapParse(sectorsPos[i], i, ParseTextmapSectorParameter);
P_InitializeSector(sc); P_InitializeSector(sc);
@ -1877,6 +1937,19 @@ static void P_LoadTextmap(void)
INT32 fadergba = P_ColorToRGBA(textmap_colormap.fadecolor, textmap_colormap.fadealpha); INT32 fadergba = P_ColorToRGBA(textmap_colormap.fadecolor, textmap_colormap.fadealpha);
sc->extra_colormap = sc->spawn_extra_colormap = R_CreateColormap(rgba, fadergba, textmap_colormap.fadestart, textmap_colormap.fadeend, textmap_colormap.flags); sc->extra_colormap = sc->spawn_extra_colormap = R_CreateColormap(rgba, fadergba, textmap_colormap.fadestart, textmap_colormap.fadeend, textmap_colormap.flags);
} }
if (textmap_planefloor.defined == (PD_A|PD_B|PD_C|PD_D))
{
sc->f_slope = MakeViaEquationConstants(textmap_planefloor.a, textmap_planefloor.b, textmap_planefloor.c, textmap_planefloor.d);
sc->hasslope = true;
}
if (textmap_planeceiling.defined == (PD_A|PD_B|PD_C|PD_D))
{
sc->c_slope = MakeViaEquationConstants(textmap_planeceiling.a, textmap_planeceiling.b, textmap_planeceiling.c, textmap_planeceiling.d);
sc->hasslope = true;
}
TextmapFixFlatOffsets(sc); TextmapFixFlatOffsets(sc);
} }
@ -3909,6 +3982,12 @@ static void P_ConvertBinaryMap(void)
if (lines[i].flags & ML_NONET) if (lines[i].flags & ML_NONET)
lines[i].args[2] |= TMSL_DYNAMIC; lines[i].args[2] |= TMSL_DYNAMIC;
if (lines[i].flags & ML_TFERLINE)
{
lines[i].args[4] |= backfloor ? TMSC_BACKTOFRONTFLOOR : (frontfloor ? TMSC_FRONTTOBACKFLOOR : 0);
lines[i].args[4] |= backceil ? TMSC_BACKTOFRONTCEILING : (frontceil ? TMSC_FRONTTOBACKCEILING : 0);
}
lines[i].special = 700; lines[i].special = 700;
break; break;
} }
@ -3990,7 +4069,7 @@ static void P_ConvertBinaryMap(void)
lines[i].args[4] |= TMSC_BACKTOFRONTCEILING; lines[i].args[4] |= TMSC_BACKTOFRONTCEILING;
lines[i].special = 720; lines[i].special = 720;
break; break;
case 900: //Translucent wall (10%) case 900: //Translucent wall (10%)
case 901: //Translucent wall (20%) case 901: //Translucent wall (20%)
case 902: //Translucent wall (30%) case 902: //Translucent wall (30%)
@ -5027,6 +5106,8 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate)
P_MapStart(); // tmthing can be used starting from this point P_MapStart(); // tmthing can be used starting from this point
P_InitSlopes();
if (!P_LoadMapFromFile()) if (!P_LoadMapFromFile())
return false; return false;
@ -5238,10 +5319,9 @@ static lumpinfo_t* FindFolder(const char *folName, UINT16 *start, UINT16 *end, l
// Add a wadfile to the active wad files, // Add a wadfile to the active wad files,
// replace sounds, musics, patches, textures, sprites and maps // replace sounds, musics, patches, textures, sprites and maps
// //
boolean P_AddWadFile(const char *wadfilename) static boolean P_LoadAddon(UINT16 wadnum, UINT16 numlumps)
{ {
size_t i, j, sreplaces = 0, mreplaces = 0, digmreplaces = 0; size_t i, j, sreplaces = 0, mreplaces = 0, digmreplaces = 0;
UINT16 numlumps, wadnum;
char *name; char *name;
lumpinfo_t *lumpinfo; lumpinfo_t *lumpinfo;
@ -5262,18 +5342,10 @@ boolean P_AddWadFile(const char *wadfilename)
// UINT16 flaPos, flaNum = 0; // UINT16 flaPos, flaNum = 0;
// UINT16 mapPos, mapNum = 0; // UINT16 mapPos, mapNum = 0;
// Init file.
if ((numlumps = W_InitFile(wadfilename, false, false)) == INT16_MAX)
{
refreshdirmenu |= REFRESHDIR_NOTLOADED;
return false;
}
else
wadnum = (UINT16)(numwadfiles-1);
switch(wadfiles[wadnum]->type) switch(wadfiles[wadnum]->type)
{ {
case RET_PK3: case RET_PK3:
case RET_FOLDER:
// Look for the lumps that act as resource delimitation markers. // Look for the lumps that act as resource delimitation markers.
lumpinfo = wadfiles[wadnum]->lumpinfo; lumpinfo = wadfiles[wadnum]->lumpinfo;
for (i = 0; i < numlumps; i++, lumpinfo++) for (i = 0; i < numlumps; i++, lumpinfo++)
@ -5437,3 +5509,35 @@ boolean P_AddWadFile(const char *wadfilename)
return true; return true;
} }
boolean P_AddWadFile(const char *wadfilename)
{
UINT16 numlumps, wadnum;
// Init file.
if ((numlumps = W_InitFile(wadfilename, false, false)) == INT16_MAX)
{
refreshdirmenu |= REFRESHDIR_NOTLOADED;
return false;
}
else
wadnum = (UINT16)(numwadfiles-1);
return P_LoadAddon(wadnum, numlumps);
}
boolean P_AddFolder(const char *folderpath)
{
UINT16 numlumps, wadnum;
// Init file.
if ((numlumps = W_InitFolder(folderpath, false, false)) == INT16_MAX)
{
refreshdirmenu |= REFRESHDIR_NOTLOADED;
return false;
}
else
wadnum = (UINT16)(numwadfiles-1);
return P_LoadAddon(wadnum, numlumps);
}

View file

@ -103,6 +103,7 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate);
void HWR_LoadLevel(void); void HWR_LoadLevel(void);
#endif #endif
boolean P_AddWadFile(const char *wadfilename); boolean P_AddWadFile(const char *wadfilename);
boolean P_AddFolder(const char *folderpath);
boolean P_RunSOC(const char *socfilename); boolean P_RunSOC(const char *socfilename);
void P_LoadSoundsRange(UINT16 wadnum, UINT16 first, UINT16 num); void P_LoadSoundsRange(UINT16 wadnum, UINT16 first, UINT16 num);
void P_LoadMusicsRange(UINT16 wadnum, UINT16 first, UINT16 num); void P_LoadMusicsRange(UINT16 wadnum, UINT16 first, UINT16 num);

View file

@ -90,6 +90,36 @@ static void ReconfigureViaVertexes (pslope_t *slope, const vector3_t v1, const v
} }
} }
/// Setup slope via constants.
static void ReconfigureViaConstants (pslope_t *slope, const fixed_t a, const fixed_t b, const fixed_t c, const fixed_t d)
{
fixed_t m;
vector3_t *normal = &slope->normal;
// Set origin.
FV3_Load(&slope->o, 0, 0, c ? -FixedDiv(d, c) : 0);
// Get slope's normal.
FV3_Load(normal, a, b, c);
FV3_Normalize(normal);
// Invert normal if it's facing down.
if (normal->z < 0)
FV3_Negate(normal);
// Get direction vector
m = FixedHypot(normal->x, normal->y);
slope->d.x = -FixedDiv(normal->x, m);
slope->d.y = -FixedDiv(normal->y, m);
// Z delta
slope->zdelta = FixedDiv(m, normal->z);
// Get angles
slope->xydirection = R_PointToAngle2(0, 0, slope->d.x, slope->d.y)+ANGLE_180;
slope->zangle = InvAngle(R_PointToAngle2(0, 0, FRACUNIT, slope->zdelta));
}
/// Recalculate dynamic slopes. /// Recalculate dynamic slopes.
void T_DynamicSlopeLine (dynplanethink_t* th) void T_DynamicSlopeLine (dynplanethink_t* th)
{ {
@ -631,13 +661,20 @@ pslope_t *P_SlopeById(UINT16 id)
return ret; return ret;
} }
/// Creates a new slope from equation constants.
pslope_t *MakeViaEquationConstants(const fixed_t a, const fixed_t b, const fixed_t c, const fixed_t d)
{
pslope_t* ret = Slope_Add(0);
ReconfigureViaConstants(ret, a, b, c, d);
return ret;
}
/// Initializes and reads the slopes from the map data. /// Initializes and reads the slopes from the map data.
void P_SpawnSlopes(const boolean fromsave) { void P_SpawnSlopes(const boolean fromsave) {
size_t i; size_t i;
slopelist = NULL;
slopecount = 0;
/// Generates vertex slopes. /// Generates vertex slopes.
SpawnVertexSlopes(); SpawnVertexSlopes();
@ -664,6 +701,9 @@ void P_SpawnSlopes(const boolean fromsave) {
for (i = 0; i < numlines; i++) for (i = 0; i < numlines; i++)
switch (lines[i].special) switch (lines[i].special)
{ {
case 700:
if (lines[i].flags & ML_TFERLINE) P_CopySectorSlope(&lines[i]);
break;
case 720: case 720:
P_CopySectorSlope(&lines[i]); P_CopySectorSlope(&lines[i]);
default: default:
@ -671,6 +711,13 @@ void P_SpawnSlopes(const boolean fromsave) {
} }
} }
/// Initializes slopes.
void P_InitSlopes(void)
{
slopelist = NULL;
slopecount = 0;
}
// ============================================================================ // ============================================================================
// //
// Various utilities related to slopes // Various utilities related to slopes
@ -773,7 +820,7 @@ void P_SlopeLaunch(mobj_t *mo)
mo->momx = slopemom.x; mo->momx = slopemom.x;
mo->momy = slopemom.y; mo->momy = slopemom.y;
mo->momz = slopemom.z/2; mo->momz = slopemom.z/2;
if (mo->player) if (mo->player)
mo->player->powers[pw_justlaunched] = 1; mo->player->powers[pw_justlaunched] = 1;
} }

View file

@ -50,6 +50,7 @@ typedef enum
void P_LinkSlopeThinkers (void); void P_LinkSlopeThinkers (void);
void P_CalculateSlopeNormal(pslope_t *slope); void P_CalculateSlopeNormal(pslope_t *slope);
void P_InitSlopes(void);
void P_SpawnSlopes(const boolean fromsave); void P_SpawnSlopes(const boolean fromsave);
// //
@ -86,6 +87,7 @@ fixed_t P_GetWallTransferMomZ(mobj_t *mo, pslope_t *slope);
void P_HandleSlopeLanding(mobj_t *thing, pslope_t *slope); void P_HandleSlopeLanding(mobj_t *thing, pslope_t *slope);
void P_ButteredSlope(mobj_t *mo); void P_ButteredSlope(mobj_t *mo);
pslope_t *MakeViaEquationConstants(const fixed_t a, const fixed_t b, const fixed_t c, const fixed_t d);
/// Dynamic plane type enum for the thinker. Will have a different functionality depending on this. /// Dynamic plane type enum for the thinker. Will have a different functionality depending on this.
typedef enum { typedef enum {

View file

@ -1906,6 +1906,22 @@ void P_LinedefExecute(INT16 tag, mobj_t *actor, sector_t *caller)
} }
} }
static boolean is_rain_type (INT32 weathernum)
{
switch (weathernum)
{
case PRECIP_SNOW:
case PRECIP_RAIN:
case PRECIP_STORM:
case PRECIP_STORM_NOSTRIKES:
case PRECIP_BLANK:
return true;
default:
return false;
}
}
// //
// P_SwitchWeather // P_SwitchWeather
// //
@ -1913,53 +1929,14 @@ void P_LinedefExecute(INT16 tag, mobj_t *actor, sector_t *caller)
// //
void P_SwitchWeather(INT32 weathernum) void P_SwitchWeather(INT32 weathernum)
{ {
boolean purge = false; boolean purge = true;
INT32 swap = 0;
switch (weathernum) if (weathernum == curWeather)
{ return;
case PRECIP_NONE: // None
if (curWeather == PRECIP_NONE) if (is_rain_type(weathernum) &&
return; // Nothing to do. is_rain_type(curWeather))
purge = true; purge = false;
break;
case PRECIP_STORM: // Storm
case PRECIP_STORM_NOSTRIKES: // Storm w/ no lightning
case PRECIP_RAIN: // Rain
if (curWeather == PRECIP_SNOW || curWeather == PRECIP_BLANK || curWeather == PRECIP_STORM_NORAIN)
swap = PRECIP_RAIN;
break;
case PRECIP_SNOW: // Snow
if (curWeather == PRECIP_SNOW)
return; // Nothing to do.
if (curWeather == PRECIP_RAIN || curWeather == PRECIP_STORM || curWeather == PRECIP_STORM_NOSTRIKES || curWeather == PRECIP_BLANK || curWeather == PRECIP_STORM_NORAIN)
swap = PRECIP_SNOW; // Need to delete the other precips.
break;
case PRECIP_STORM_NORAIN: // Storm w/o rain
if (curWeather == PRECIP_SNOW
|| curWeather == PRECIP_STORM
|| curWeather == PRECIP_STORM_NOSTRIKES
|| curWeather == PRECIP_RAIN
|| curWeather == PRECIP_BLANK)
swap = PRECIP_STORM_NORAIN;
else if (curWeather == PRECIP_STORM_NORAIN)
return;
break;
case PRECIP_BLANK:
if (curWeather == PRECIP_SNOW
|| curWeather == PRECIP_STORM
|| curWeather == PRECIP_STORM_NOSTRIKES
|| curWeather == PRECIP_RAIN)
swap = PRECIP_BLANK;
else if (curWeather == PRECIP_STORM_NORAIN)
swap = PRECIP_BLANK;
else if (curWeather == PRECIP_BLANK)
return;
break;
default:
CONS_Debug(DBG_GAMELOGIC, "P_SwitchWeather: Unknown weather type %d.\n", weathernum);
break;
}
if (purge) if (purge)
{ {
@ -1976,7 +1953,7 @@ void P_SwitchWeather(INT32 weathernum)
P_RemovePrecipMobj(precipmobj); P_RemovePrecipMobj(precipmobj);
} }
} }
else if (swap && !((swap == PRECIP_BLANK && curWeather == PRECIP_STORM_NORAIN) || (swap == PRECIP_STORM_NORAIN && curWeather == PRECIP_BLANK))) // Rather than respawn all that crap, reuse it! else // Rather than respawn all that crap, reuse it!
{ {
thinker_t *think; thinker_t *think;
precipmobj_t *precipmobj; precipmobj_t *precipmobj;
@ -1988,7 +1965,7 @@ void P_SwitchWeather(INT32 weathernum)
continue; // not a precipmobj thinker continue; // not a precipmobj thinker
precipmobj = (precipmobj_t *)think; precipmobj = (precipmobj_t *)think;
if (swap == PRECIP_RAIN) // Snow To Rain if (weathernum == (PRECIP_RAIN || PRECIP_STORM || PRECIP_STORM_NOSTRIKES)) // Snow To Rain
{ {
precipmobj->flags = mobjinfo[MT_RAIN].flags; precipmobj->flags = mobjinfo[MT_RAIN].flags;
st = &states[mobjinfo[MT_RAIN].spawnstate]; st = &states[mobjinfo[MT_RAIN].spawnstate];
@ -2003,7 +1980,7 @@ void P_SwitchWeather(INT32 weathernum)
precipmobj->precipflags |= PCF_RAIN; precipmobj->precipflags |= PCF_RAIN;
//think->function.acp1 = (actionf_p1)P_RainThinker; //think->function.acp1 = (actionf_p1)P_RainThinker;
} }
else if (swap == PRECIP_SNOW) // Rain To Snow else if (weathernum == PRECIP_SNOW) // Rain To Snow
{ {
INT32 z; INT32 z;
@ -2028,7 +2005,7 @@ void P_SwitchWeather(INT32 weathernum)
//think->function.acp1 = (actionf_p1)P_SnowThinker; //think->function.acp1 = (actionf_p1)P_SnowThinker;
} }
else if (swap == PRECIP_BLANK || swap == PRECIP_STORM_NORAIN) // Remove precip, but keep it around for reuse. else // Remove precip, but keep it around for reuse.
{ {
//think->function.acp1 = (actionf_p1)P_NullPrecipThinker; //think->function.acp1 = (actionf_p1)P_NullPrecipThinker;
@ -2041,49 +2018,34 @@ void P_SwitchWeather(INT32 weathernum)
{ {
case PRECIP_SNOW: // snow case PRECIP_SNOW: // snow
curWeather = PRECIP_SNOW; curWeather = PRECIP_SNOW;
if (!swap) if (purge)
P_SpawnPrecipitation(); P_SpawnPrecipitation();
break; break;
case PRECIP_RAIN: // rain case PRECIP_RAIN: // rain
{ {
boolean dontspawn = false;
if (curWeather == PRECIP_RAIN || curWeather == PRECIP_STORM || curWeather == PRECIP_STORM_NOSTRIKES)
dontspawn = true;
curWeather = PRECIP_RAIN; curWeather = PRECIP_RAIN;
if (!dontspawn && !swap) if (purge)
P_SpawnPrecipitation(); P_SpawnPrecipitation();
break; break;
} }
case PRECIP_STORM: // storm case PRECIP_STORM: // storm
{ {
boolean dontspawn = false;
if (curWeather == PRECIP_RAIN || curWeather == PRECIP_STORM || curWeather == PRECIP_STORM_NOSTRIKES)
dontspawn = true;
curWeather = PRECIP_STORM; curWeather = PRECIP_STORM;
if (!dontspawn && !swap) if (purge)
P_SpawnPrecipitation(); P_SpawnPrecipitation();
break; break;
} }
case PRECIP_STORM_NOSTRIKES: // storm w/o lightning case PRECIP_STORM_NOSTRIKES: // storm w/o lightning
{ {
boolean dontspawn = false;
if (curWeather == PRECIP_RAIN || curWeather == PRECIP_STORM || curWeather == PRECIP_STORM_NOSTRIKES)
dontspawn = true;
curWeather = PRECIP_STORM_NOSTRIKES; curWeather = PRECIP_STORM_NOSTRIKES;
if (!dontspawn && !swap) if (purge)
P_SpawnPrecipitation(); P_SpawnPrecipitation();
break; break;
@ -2091,14 +2053,11 @@ void P_SwitchWeather(INT32 weathernum)
case PRECIP_STORM_NORAIN: // storm w/o rain case PRECIP_STORM_NORAIN: // storm w/o rain
curWeather = PRECIP_STORM_NORAIN; curWeather = PRECIP_STORM_NORAIN;
if (!swap)
P_SpawnPrecipitation();
break; break;
case PRECIP_BLANK: case PRECIP_BLANK: //preloaded
curWeather = PRECIP_BLANK; curWeather = PRECIP_BLANK;
if (!swap) if (purge)
P_SpawnPrecipitation(); P_SpawnPrecipitation();
break; break;
@ -7201,7 +7160,8 @@ void P_SpawnSpecials(boolean fromnetsave)
} }
} }
P_RunLevelLoadExecutors(); if (!fromnetsave)
P_RunLevelLoadExecutors();
} }
/** Adds 3Dfloors as appropriate based on a common control linedef. /** Adds 3Dfloors as appropriate based on a common control linedef.

View file

@ -777,7 +777,7 @@ void P_NightserizePlayer(player_t *player, INT32 nighttime)
UINT8 oldmare, oldmarelap, oldmarebonuslap; UINT8 oldmare, oldmarelap, oldmarebonuslap;
// Bots can't be NiGHTSerized, silly!1 :P // Bots can't be NiGHTSerized, silly!1 :P
if (player->bot) if (player->bot == BOT_2PAI || player->bot == BOT_2PHUMAN)
return; return;
if (player->powers[pw_carry] != CR_NIGHTSMODE) if (player->powers[pw_carry] != CR_NIGHTSMODE)
@ -969,6 +969,9 @@ pflags_t P_GetJumpFlags(player_t *player)
// //
boolean P_PlayerInPain(player_t *player) boolean P_PlayerInPain(player_t *player)
{ {
// If the player doesn't have a mobj, it can't be in pain.
if (!player->mo)
return false;
// no silly, sliding isn't pain // no silly, sliding isn't pain
if (!(player->pflags & PF_SLIDING) && player->mo->state == &states[player->mo->info->painstate] && player->powers[pw_flashing]) if (!(player->pflags & PF_SLIDING) && player->mo->state == &states[player->mo->info->painstate] && player->powers[pw_flashing])
return true; return true;
@ -1188,9 +1191,9 @@ void P_GivePlayerRings(player_t *player, INT32 num_rings)
{ {
if (!player) if (!player)
return; return;
if (player->bot) if ((player->bot == BOT_2PAI || player->bot == BOT_2PHUMAN) && player->botleader)
player = &players[consoleplayer]; player = player->botleader;
if (!player->mo) if (!player->mo)
return; return;
@ -1234,8 +1237,8 @@ void P_GivePlayerSpheres(player_t *player, INT32 num_spheres)
if (!player) if (!player)
return; return;
if (player->bot) if ((player->bot == BOT_2PAI || player->bot == BOT_2PHUMAN) && player->botleader)
player = &players[consoleplayer]; player = player->botleader;
if (!player->mo) if (!player->mo)
return; return;
@ -1261,8 +1264,8 @@ void P_GivePlayerLives(player_t *player, INT32 numlives)
if (!player) if (!player)
return; return;
if (player->bot) if ((player->bot == BOT_2PAI || player->bot == BOT_2PHUMAN) && player->botleader)
player = &players[consoleplayer]; player = player->botleader;
if (gamestate == GS_LEVEL) if (gamestate == GS_LEVEL)
{ {
@ -1367,8 +1370,8 @@ void P_AddPlayerScore(player_t *player, UINT32 amount)
{ {
UINT32 oldscore; UINT32 oldscore;
if (player->bot) if ((player->bot == BOT_2PAI || player->bot == BOT_2PHUMAN) && player->botleader)
player = &players[consoleplayer]; player = player->botleader;
// NiGHTS does it different! // NiGHTS does it different!
if (gamestate == GS_LEVEL && mapheaderinfo[gamemap-1]->typeoflevel & TOL_NIGHTS) if (gamestate == GS_LEVEL && mapheaderinfo[gamemap-1]->typeoflevel & TOL_NIGHTS)
@ -5369,9 +5372,9 @@ static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd)
// disabled because it seemed to disorient people and Z-targeting exists now // disabled because it seemed to disorient people and Z-targeting exists now
/*if (!demoplayback) /*if (!demoplayback)
{ {
if (player == &players[consoleplayer] && cv_cam_turnfacingability[0].value > 0 && !(PLAYER1INPUTDOWN(gc_turnleft) || PLAYER1INPUTDOWN(gc_turnright))) if (player == &players[consoleplayer] && cv_cam_turnfacingability[0].value > 0 && !(PLAYER1INPUTDOWN(GC_TURNLEFT) || PLAYER1INPUTDOWN(GC_TURNRIGHT)))
P_SetPlayerAngle(player, player->mo->angle);; P_SetPlayerAngle(player, player->mo->angle);;
else if (player == &players[secondarydisplayplayer] && cv_cam_turnfacingability[1].value > 0 && !(PLAYER2INPUTDOWN(gc_turnleft) || PLAYER2INPUTDOWN(gc_turnright))) else if (player == &players[secondarydisplayplayer] && cv_cam_turnfacingability[1].value > 0 && !(PLAYER2INPUTDOWN(GC_TURNLEFT) || PLAYER2INPUTDOWN(GC_TURNRIGHT)))
P_SetPlayerAngle(player, player->mo->angle); P_SetPlayerAngle(player, player->mo->angle);
}*/ }*/
} }
@ -5390,7 +5393,7 @@ static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd)
player->powers[pw_tailsfly] = tailsflytics + 1; // Set the fly timer player->powers[pw_tailsfly] = tailsflytics + 1; // Set the fly timer
player->pflags &= ~(PF_JUMPED|PF_NOJUMPDAMAGE|PF_SPINNING|PF_STARTDASH); player->pflags &= ~(PF_JUMPED|PF_NOJUMPDAMAGE|PF_SPINNING|PF_STARTDASH);
if (player->bot == 1) if (player->bot == BOT_2PAI)
player->pflags |= PF_THOKKED; player->pflags |= PF_THOKKED;
else else
player->pflags |= (PF_THOKKED|PF_CANCARRY); player->pflags |= (PF_THOKKED|PF_CANCARRY);
@ -5636,16 +5639,10 @@ INT32 P_GetPlayerControlDirection(player_t *player)
{ {
ticcmd_t *cmd = &player->cmd; ticcmd_t *cmd = &player->cmd;
angle_t controllerdirection, controlplayerdirection; angle_t controllerdirection, controlplayerdirection;
camera_t *thiscam;
angle_t dangle; angle_t dangle;
fixed_t tempx = 0, tempy = 0; fixed_t tempx = 0, tempy = 0;
angle_t tempangle, origtempangle; angle_t tempangle, origtempangle;
if (splitscreen && player == &players[secondarydisplayplayer])
thiscam = &camera2;
else
thiscam = &camera;
if (!cmd->forwardmove && !cmd->sidemove) if (!cmd->forwardmove && !cmd->sidemove)
return 0; return 0;
@ -5661,17 +5658,15 @@ INT32 P_GetPlayerControlDirection(player_t *player)
origtempangle = tempangle = 0; // relative to the axis rather than the player! origtempangle = tempangle = 0; // relative to the axis rather than the player!
controlplayerdirection = R_PointToAngle2(0, 0, player->mo->momx, player->mo->momy); controlplayerdirection = R_PointToAngle2(0, 0, player->mo->momx, player->mo->momy);
} }
else if ((P_ControlStyle(player) & CS_LMAOGALOG) && thiscam->chase) else
{ {
if (player->awayviewtics) if (player->awayviewtics)
origtempangle = tempangle = player->awayviewmobj->angle; origtempangle = tempangle = player->awayviewmobj->angle;
else if (P_ControlStyle(player) & CS_LMAOGALOG)
origtempangle = tempangle = (cmd->angleturn << 16);
else else
origtempangle = tempangle = thiscam->angle; origtempangle = tempangle = player->mo->angle;
controlplayerdirection = player->mo->angle;
}
else
{
origtempangle = tempangle = player->mo->angle;
controlplayerdirection = R_PointToAngle2(0, 0, player->mo->momx, player->mo->momy); controlplayerdirection = R_PointToAngle2(0, 0, player->mo->momx, player->mo->momy);
} }
@ -5977,22 +5972,6 @@ static void P_3dMovement(player_t *player)
acceleration = 96 + (FixedDiv(player->speed, player->mo->scale)>>FRACBITS) * 40; acceleration = 96 + (FixedDiv(player->speed, player->mo->scale)>>FRACBITS) * 40;
topspeed = normalspd; topspeed = normalspd;
} }
else if (player->bot)
{ // Bot steals player 1's stats
normalspd = FixedMul(players[consoleplayer].normalspeed, player->mo->scale);
thrustfactor = players[consoleplayer].thrustfactor;
acceleration = players[consoleplayer].accelstart + (FixedDiv(player->speed, player->mo->scale)>>FRACBITS) * players[consoleplayer].acceleration;
if (player->powers[pw_tailsfly])
topspeed = normalspd/2;
else if (player->mo->eflags & (MFE_UNDERWATER|MFE_GOOWATER))
{
topspeed = normalspd/2;
acceleration = 2*acceleration/3;
}
else
topspeed = normalspd;
}
else else
{ {
if (player->powers[pw_super] || player->powers[pw_sneakers]) if (player->powers[pw_super] || player->powers[pw_sneakers])
@ -9522,11 +9501,11 @@ static void P_DeathThink(player_t *player)
if (player->deadtimer < INT32_MAX) if (player->deadtimer < INT32_MAX)
player->deadtimer++; player->deadtimer++;
if (player->bot) // don't allow bots to do any of the below, B_CheckRespawn does all they need for respawning already if (player->bot == BOT_2PAI || player->bot == BOT_2PHUMAN) // don't allow followbots to do any of the below, B_CheckRespawn does all they need for respawning already
goto notrealplayer; goto notrealplayer;
// continue logic // continue logic
if (!(netgame || multiplayer) && player->lives <= 0) if (!(netgame || multiplayer) && player->lives <= 0 && player == &players[consoleplayer]) //Extra players in SP can't be allowed to continue or end game
{ {
if (player->deadtimer > (3*TICRATE) && (cmd->buttons & BT_SPIN || cmd->buttons & BT_JUMP) && (!continuesInSession || player->continues > 0)) if (player->deadtimer > (3*TICRATE) && (cmd->buttons & BT_SPIN || cmd->buttons & BT_JUMP) && (!continuesInSession || player->continues > 0))
G_UseContinue(); G_UseContinue();
@ -11499,6 +11478,9 @@ void P_PlayerThink(player_t *player)
I_Error("p_playerthink: players[%s].mo == NULL", sizeu1(playeri)); I_Error("p_playerthink: players[%s].mo == NULL", sizeu1(playeri));
#endif #endif
// Reset terrain blocked status for this frame
player->blocked = false;
// todo: Figure out what is actually causing these problems in the first place... // todo: Figure out what is actually causing these problems in the first place...
if (player->mo->health <= 0 && player->playerstate == PST_LIVE) //you should be DEAD! if (player->mo->health <= 0 && player->playerstate == PST_LIVE) //you should be DEAD!
{ {
@ -11506,7 +11488,7 @@ void P_PlayerThink(player_t *player)
player->playerstate = PST_DEAD; player->playerstate = PST_DEAD;
} }
if (player->bot) if (player->bot == BOT_2PAI || player->bot == BOT_2PHUMAN)
{ {
if (player->playerstate == PST_LIVE || player->playerstate == PST_DEAD) if (player->playerstate == PST_LIVE || player->playerstate == PST_DEAD)
{ {
@ -11650,7 +11632,7 @@ void P_PlayerThink(player_t *player)
for (i = 0; i < MAXPLAYERS; i++) for (i = 0; i < MAXPLAYERS; i++)
{ {
if (!playeringame[i] || players[i].spectator || players[i].bot) if (!playeringame[i] || players[i].spectator || players[i].bot == BOT_2PAI || players[i].bot == BOT_2PHUMAN)
continue; continue;
if (players[i].lives <= 0) if (players[i].lives <= 0)
continue; continue;
@ -11681,8 +11663,8 @@ void P_PlayerThink(player_t *player)
INT32 i, total = 0, exiting = 0; INT32 i, total = 0, exiting = 0;
for (i = 0; i < MAXPLAYERS; i++) for (i = 0; i < MAXPLAYERS; i++)
{ {
if (!playeringame[i] || players[i].spectator || players[i].bot) if (!playeringame[i] || players[i].spectator || players[i].bot == BOT_2PAI || players[i].bot == BOT_2PHUMAN)
continue; continue;
if (players[i].quittime > 30 * TICRATE) if (players[i].quittime > 30 * TICRATE)
continue; continue;
@ -12622,8 +12604,8 @@ void P_PlayerAfterThink(player_t *player)
player->mo->momy = tails->momy; player->mo->momy = tails->momy;
player->mo->momz = tails->momz; player->mo->momz = tails->momz;
} }
if (G_CoopGametype() && tails->player && tails->player->bot != 1) if (G_CoopGametype() && tails->player && tails->player->bot != BOT_2PAI)
{ {
player->mo->angle = tails->angle; player->mo->angle = tails->angle;

View file

@ -901,9 +901,8 @@ static png_bytep *PNG_Read(
png_colorp palette; png_colorp palette;
int palette_size; int palette_size;
png_bytep trans; png_bytep trans = NULL;
int trans_num; int num_trans = 0;
png_color_16p trans_values;
#ifdef PNG_SETJMP_SUPPORTED #ifdef PNG_SETJMP_SUPPORTED
#ifdef USE_FAR_KEYWORD #ifdef USE_FAR_KEYWORD
@ -998,12 +997,12 @@ static png_bytep *PNG_Read(
// color is present on the image, the palette flag is disabled. // color is present on the image, the palette flag is disabled.
if (usepal) if (usepal)
{ {
png_get_tRNS(png_ptr, png_info_ptr, &trans, &trans_num, &trans_values); png_uint_32 result = png_get_tRNS(png_ptr, png_info_ptr, &trans, &num_trans, NULL);
if (trans && trans_num > 0) if ((result & PNG_INFO_tRNS) && num_trans > 0 && trans != NULL)
{ {
INT32 i; INT32 i;
for (i = 0; i < trans_num; i++) for (i = 0; i < num_trans; i++)
{ {
// libpng will transform this image into RGBA even if // libpng will transform this image into RGBA even if
// the transparent index does not exist in the image, // the transparent index does not exist in the image,

View file

@ -116,9 +116,9 @@ void *Picture_PNGConvert(
size_t insize, size_t *outsize, size_t insize, size_t *outsize,
pictureflags_t flags); pictureflags_t flags);
boolean Picture_PNGDimensions(UINT8 *png, INT32 *width, INT32 *height, INT16 *topoffset, INT16 *leftoffset, size_t size); boolean Picture_PNGDimensions(UINT8 *png, INT32 *width, INT32 *height, INT16 *topoffset, INT16 *leftoffset, size_t size);
#endif
#define PICTURE_PNG_USELOOKUP #define PICTURE_PNG_USELOOKUP
#endif
// SpriteInfo // SpriteInfo
extern spriteinfo_t spriteinfo[NUMSPRITES]; extern spriteinfo_t spriteinfo[NUMSPRITES];

View file

@ -89,8 +89,6 @@ static fixed_t planeheight;
fixed_t yslopetab[MAXVIDHEIGHT*16]; fixed_t yslopetab[MAXVIDHEIGHT*16];
fixed_t *yslope; fixed_t *yslope;
fixed_t basexscale, baseyscale;
fixed_t cachedheight[MAXVIDHEIGHT]; fixed_t cachedheight[MAXVIDHEIGHT];
fixed_t cacheddistance[MAXVIDHEIGHT]; fixed_t cacheddistance[MAXVIDHEIGHT];
fixed_t cachedxstep[MAXVIDHEIGHT]; fixed_t cachedxstep[MAXVIDHEIGHT];
@ -114,7 +112,7 @@ void R_InitPlanes(void)
// Sets planeripple.xfrac and planeripple.yfrac, added to ds_xfrac and ds_yfrac, if the span is not tilted. // Sets planeripple.xfrac and planeripple.yfrac, added to ds_xfrac and ds_yfrac, if the span is not tilted.
// //
struct static struct
{ {
INT32 offset; INT32 offset;
fixed_t xfrac, yfrac; fixed_t xfrac, yfrac;
@ -143,15 +141,6 @@ static void R_UpdatePlaneRipple(void)
planeripple.offset = (leveltime * 140); planeripple.offset = (leveltime * 140);
} }
//
// R_MapPlane
//
// Uses global vars:
// planeheight
// basexscale
// baseyscale
// centerx
static void R_MapPlane(INT32 y, INT32 x1, INT32 x2) static void R_MapPlane(INT32 y, INT32 x1, INT32 x2)
{ {
angle_t angle, planecos, planesin; angle_t angle, planecos, planesin;
@ -176,16 +165,13 @@ static void R_MapPlane(INT32 y, INT32 x1, INT32 x2)
cacheddistance[y] = distance = FixedMul(planeheight, yslope[y]); cacheddistance[y] = distance = FixedMul(planeheight, yslope[y]);
span = abs(centery - y); span = abs(centery - y);
if (span) // don't divide by zero if (span) // Don't divide by zero
{ {
ds_xstep = FixedMul(planesin, planeheight) / span; ds_xstep = FixedMul(planesin, planeheight) / span;
ds_ystep = FixedMul(planecos, planeheight) / span; ds_ystep = FixedMul(planecos, planeheight) / span;
} }
else else
{ ds_xstep = ds_ystep = FRACUNIT;
ds_xstep = FixedMul(distance, basexscale);
ds_ystep = FixedMul(distance, baseyscale);
}
cachedxstep[y] = ds_xstep; cachedxstep[y] = ds_xstep;
cachedystep[y] = ds_ystep; cachedystep[y] = ds_ystep;
@ -197,6 +183,11 @@ static void R_MapPlane(INT32 y, INT32 x1, INT32 x2)
ds_ystep = cachedystep[y]; ds_ystep = cachedystep[y];
} }
// [RH] Instead of using the xtoviewangle array, I calculated the fractional values
// at the middle of the screen, then used the calculated ds_xstep and ds_ystep
// to step from those to the proper texture coordinate to start drawing at.
// That way, the texture coordinate is always calculated by its position
// on the screen and not by its position relative to the edge of the visplane.
ds_xfrac = xoffs + FixedMul(planecos, distance) + (x1 - centerx) * ds_xstep; ds_xfrac = xoffs + FixedMul(planecos, distance) + (x1 - centerx) * ds_xstep;
ds_yfrac = yoffs - FixedMul(planesin, distance) + (x1 - centerx) * ds_ystep; ds_yfrac = yoffs - FixedMul(planesin, distance) + (x1 - centerx) * ds_ystep;
@ -295,7 +286,6 @@ void R_ClearFFloorClips (void)
void R_ClearPlanes(void) void R_ClearPlanes(void)
{ {
INT32 i, p; INT32 i, p;
angle_t angle;
// opening / clipping determination // opening / clipping determination
for (i = 0; i < viewwidth; i++) for (i = 0; i < viewwidth; i++)
@ -321,13 +311,6 @@ void R_ClearPlanes(void)
// texture calculation // texture calculation
memset(cachedheight, 0, sizeof (cachedheight)); memset(cachedheight, 0, sizeof (cachedheight));
// left to right mapping
angle = (viewangle-ANGLE_90)>>ANGLETOFINESHIFT;
// scale will be unit scale at SCREENWIDTH/2 distance
basexscale = FixedDiv (FINECOSINE(angle),centerxfrac);
baseyscale = -FixedDiv (FINESINE(angle),centerxfrac);
} }
static visplane_t *new_visplane(unsigned hash) static visplane_t *new_visplane(unsigned hash)
@ -380,9 +363,11 @@ visplane_t *R_FindPlane(fixed_t height, INT32 picnum, INT32 lightlevel,
{ {
if (polyobj->angle != 0) if (polyobj->angle != 0)
{ {
angle_t fineshift = polyobj->angle >> ANGLETOFINESHIFT; float ang = ANG2RAD(polyobj->angle);
xoff -= FixedMul(FINECOSINE(fineshift), polyobj->centerPt.x)+FixedMul(FINESINE(fineshift), polyobj->centerPt.y); float x = FixedToFloat(polyobj->centerPt.x);
yoff -= FixedMul(FINESINE(fineshift), polyobj->centerPt.x)-FixedMul(FINECOSINE(fineshift), polyobj->centerPt.y); float y = FixedToFloat(polyobj->centerPt.y);
xoff -= FloatToFixed(x * cos(ang) + y * sin(ang));
yoff -= FloatToFixed(x * sin(ang) - y * cos(ang));
} }
else else
{ {
@ -530,53 +515,22 @@ visplane_t *R_CheckPlane(visplane_t *pl, INT32 start, INT32 stop)
// //
// R_ExpandPlane // R_ExpandPlane
// //
// This function basically expands the visplane or I_Errors. // This function basically expands the visplane.
// The reason for this is that when creating 3D floor planes, there is no // The reason for this is that when creating 3D floor planes, there is no
// need to create new ones with R_CheckPlane, because 3D floor planes // need to create new ones with R_CheckPlane, because 3D floor planes
// are created by subsector and there is no way a subsector can graphically // are created by subsector and there is no way a subsector can graphically
// overlap. // overlap.
void R_ExpandPlane(visplane_t *pl, INT32 start, INT32 stop) void R_ExpandPlane(visplane_t *pl, INT32 start, INT32 stop)
{ {
// INT32 unionl, unionh;
// INT32 x;
// Don't expand polyobject planes here - we do that on our own. // Don't expand polyobject planes here - we do that on our own.
if (pl->polyobj) if (pl->polyobj)
return; return;
if (pl->minx > start) pl->minx = start; if (pl->minx > start) pl->minx = start;
if (pl->maxx < stop) pl->maxx = stop; if (pl->maxx < stop) pl->maxx = stop;
/*
if (start < pl->minx)
{
unionl = start;
}
else
{
unionl = pl->minx;
}
if (stop > pl->maxx)
{
unionh = stop;
}
else
{
unionh = pl->maxx;
}
for (x = start; x <= stop; x++)
if (pl->top[x] != 0xffff || pl->bottom[x] != 0x0000)
break;
if (x <= stop)
I_Error("R_ExpandPlane: planes in same subsector overlap?!\nminx: %d, maxx: %d, start: %d, stop: %d\n", pl->minx, pl->maxx, start, stop);
pl->minx = unionl, pl->maxx = unionh;
*/
} }
static void R_MakeSpans(INT32 x, INT32 t1, INT32 b1, INT32 t2, INT32 b2) static void R_MakeSpans(void (*mapfunc)(INT32, INT32, INT32), INT32 x, INT32 t1, INT32 b1, INT32 t2, INT32 b2)
{ {
// Alam: from r_splats's R_RasterizeFloorSplat // Alam: from r_splats's R_RasterizeFloorSplat
if (t1 >= vid.height) t1 = vid.height-1; if (t1 >= vid.height) t1 = vid.height-1;
@ -587,38 +541,12 @@ static void R_MakeSpans(INT32 x, INT32 t1, INT32 b1, INT32 t2, INT32 b2)
while (t1 < t2 && t1 <= b1) while (t1 < t2 && t1 <= b1)
{ {
R_MapPlane(t1, spanstart[t1], x - 1); mapfunc(t1, spanstart[t1], x - 1);
t1++; t1++;
} }
while (b1 > b2 && b1 >= t1) while (b1 > b2 && b1 >= t1)
{ {
R_MapPlane(b1, spanstart[b1], x - 1); mapfunc(b1, spanstart[b1], x - 1);
b1--;
}
while (t2 < t1 && t2 <= b2)
spanstart[t2++] = x;
while (b2 > b1 && b2 >= t2)
spanstart[b2--] = x;
}
static void R_MakeTiltedSpans(INT32 x, INT32 t1, INT32 b1, INT32 t2, INT32 b2)
{
// Alam: from r_splats's R_RasterizeFloorSplat
if (t1 >= vid.height) t1 = vid.height-1;
if (b1 >= vid.height) b1 = vid.height-1;
if (t2 >= vid.height) t2 = vid.height-1;
if (b2 >= vid.height) b2 = vid.height-1;
if (x-1 >= vid.width) x = vid.width;
while (t1 < t2 && t1 <= b1)
{
R_MapTiltedPlane(t1, spanstart[t1], x - 1);
t1++;
}
while (b1 > b2 && b1 >= t1)
{
R_MapTiltedPlane(b1, spanstart[b1], x - 1);
b1--; b1--;
} }
@ -865,11 +793,10 @@ void R_DrawSinglePlane(visplane_t *pl)
{ {
levelflat_t *levelflat; levelflat_t *levelflat;
INT32 light = 0; INT32 light = 0;
INT32 x; INT32 x, stop;
INT32 stop, angle;
ffloor_t *rover; ffloor_t *rover;
INT32 type; INT32 type, spanfunctype = BASEDRAWFUNC;
INT32 spanfunctype = BASEDRAWFUNC; void (*mapfunc)(INT32, INT32, INT32) = R_MapPlane;
if (!(pl->minx <= pl->maxx)) if (!(pl->minx <= pl->maxx))
return; return;
@ -1021,9 +948,6 @@ void R_DrawSinglePlane(visplane_t *pl)
&& viewangle != pl->viewangle+pl->plangle) && viewangle != pl->viewangle+pl->plangle)
{ {
memset(cachedheight, 0, sizeof (cachedheight)); memset(cachedheight, 0, sizeof (cachedheight));
angle = (pl->viewangle+pl->plangle-ANGLE_90)>>ANGLETOFINESHIFT;
basexscale = FixedDiv(FINECOSINE(angle),centerxfrac);
baseyscale = -FixedDiv(FINESINE(angle),centerxfrac);
viewangle = pl->viewangle+pl->plangle; viewangle = pl->viewangle+pl->plangle;
} }
@ -1038,6 +962,8 @@ void R_DrawSinglePlane(visplane_t *pl)
if (pl->slope) if (pl->slope)
{ {
mapfunc = R_MapTiltedPlane;
if (!pl->plangle) if (!pl->plangle)
{ {
if (ds_powersoftwo) if (ds_powersoftwo)
@ -1105,16 +1031,8 @@ void R_DrawSinglePlane(visplane_t *pl)
stop = pl->maxx + 1; stop = pl->maxx + 1;
if (pl->slope) for (x = pl->minx; x <= stop; x++)
{ R_MakeSpans(mapfunc, x, pl->top[x-1], pl->bottom[x-1], pl->top[x], pl->bottom[x]);
for (x = pl->minx; x <= stop; x++)
R_MakeTiltedSpans(x, pl->top[x-1], pl->bottom[x-1], pl->top[x], pl->bottom[x]);
}
else
{
for (x = pl->minx; x <= stop; x++)
R_MakeSpans(x, pl->top[x-1], pl->bottom[x-1], pl->top[x], pl->bottom[x]);
}
/* /*
QUINCUNX anti-aliasing technique (sort of) QUINCUNX anti-aliasing technique (sort of)
@ -1181,7 +1099,7 @@ using the palette colors.
stop = pl->maxx + 1; stop = pl->maxx + 1;
for (x = pl->minx; x <= stop; x++) for (x = pl->minx; x <= stop; x++)
R_MakeSpans(x, pl->top[x-1], pl->bottom[x-1], R_MakeSpans(mapfunc, x, pl->top[x-1], pl->bottom[x-1],
pl->top[x], pl->bottom[x]); pl->top[x], pl->bottom[x]);
} }
} }

View file

@ -69,7 +69,6 @@ extern fixed_t cachedheight[MAXVIDHEIGHT];
extern fixed_t cacheddistance[MAXVIDHEIGHT]; extern fixed_t cacheddistance[MAXVIDHEIGHT];
extern fixed_t cachedxstep[MAXVIDHEIGHT]; extern fixed_t cachedxstep[MAXVIDHEIGHT];
extern fixed_t cachedystep[MAXVIDHEIGHT]; extern fixed_t cachedystep[MAXVIDHEIGHT];
extern fixed_t basexscale, baseyscale;
extern fixed_t *yslope; extern fixed_t *yslope;
extern lighttable_t **planezlight; extern lighttable_t **planezlight;

View file

@ -242,6 +242,11 @@ boolean R_SkinUsable(INT32 playernum, INT32 skinnum)
// Force 3. // Force 3.
return true; return true;
} }
if (playernum != -1 && players[playernum].bot)
{
//Force 4.
return true;
}
// We will now check if this skin is supposed to be locked or not. // We will now check if this skin is supposed to be locked or not.

View file

@ -155,7 +155,6 @@ void R_DrawFloorSplat(vissprite_t *spr)
fixed_t xscale, yscale; fixed_t xscale, yscale;
fixed_t xoffset, yoffset; fixed_t xoffset, yoffset;
fixed_t leftoffset, topoffset; fixed_t leftoffset, topoffset;
pslope_t *slope = NULL;
INT32 i; INT32 i;
boolean hflip = (spr->xiscale < 0); boolean hflip = (spr->xiscale < 0);
@ -188,7 +187,7 @@ void R_DrawFloorSplat(vissprite_t *spr)
if (spr->rotateflags & SRF_3D || renderflags & RF_NOSPLATBILLBOARD) if (spr->rotateflags & SRF_3D || renderflags & RF_NOSPLATBILLBOARD)
splatangle = mobj->angle; splatangle = mobj->angle;
else else
splatangle = spr->viewangle; splatangle = spr->viewpoint.angle;
if (!(spr->cut & SC_ISROTATED)) if (!(spr->cut & SC_ISROTATED))
splatangle += mobj->rollangle; splatangle += mobj->rollangle;
@ -218,7 +217,7 @@ void R_DrawFloorSplat(vissprite_t *spr)
splat.x = x; splat.x = x;
splat.y = y; splat.y = y;
splat.z = mobj->z; splat.z = mobj->z;
splat.tilted = false; splat.slope = NULL;
// Set positions // Set positions
@ -238,9 +237,9 @@ void R_DrawFloorSplat(vissprite_t *spr)
splat.verts[3].x = w - xoffset; splat.verts[3].x = w - xoffset;
splat.verts[3].y = -h + yoffset; splat.verts[3].y = -h + yoffset;
angle = -splat.angle; angle = -splat.angle>>ANGLETOFINESHIFT;
ca = FINECOSINE(angle>>ANGLETOFINESHIFT); ca = FINECOSINE(angle);
sa = FINESINE(angle>>ANGLETOFINESHIFT); sa = FINESINE(angle);
// Rotate // Rotate
for (i = 0; i < 4; i++) for (i = 0; i < 4; i++)
@ -255,36 +254,10 @@ void R_DrawFloorSplat(vissprite_t *spr)
// The slope that was defined for the sprite. // The slope that was defined for the sprite.
if (renderflags & RF_SLOPESPLAT) if (renderflags & RF_SLOPESPLAT)
slope = mobj->floorspriteslope; splat.slope = mobj->floorspriteslope;
if (standingslope && (renderflags & RF_OBJECTSLOPESPLAT)) if (standingslope && (renderflags & RF_OBJECTSLOPESPLAT))
slope = standingslope; splat.slope = standingslope;
// Set splat as tilted
splat.tilted = (slope != NULL);
}
if (splat.tilted)
{
pslope_t *s = &splat.slope;
s->o.x = slope->o.x;
s->o.y = slope->o.y;
s->o.z = slope->o.z;
s->d.x = slope->d.x;
s->d.y = slope->d.y;
s->normal.x = slope->normal.x;
s->normal.y = slope->normal.y;
s->normal.z = slope->normal.z;
s->zdelta = slope->zdelta;
s->zangle = slope->zangle;
s->xydirection = slope->xydirection;
s->next = NULL;
s->flags = 0;
} }
// Translate // Translate
@ -293,9 +266,9 @@ void R_DrawFloorSplat(vissprite_t *spr)
tr_x = rotated[i].x + x; tr_x = rotated[i].x + x;
tr_y = rotated[i].y + y; tr_y = rotated[i].y + y;
if (slope) if (splat.slope)
{ {
rot_z = P_GetSlopeZAt(slope, tr_x, tr_y); rot_z = P_GetSlopeZAt(splat.slope, tr_x, tr_y);
splat.verts[i].z = rot_z; splat.verts[i].z = rot_z;
} }
else else
@ -305,18 +278,23 @@ void R_DrawFloorSplat(vissprite_t *spr)
splat.verts[i].y = tr_y; splat.verts[i].y = tr_y;
} }
angle = spr->viewpoint.angle >> ANGLETOFINESHIFT;
ca = FINECOSINE(angle);
sa = FINESINE(angle);
// Project
for (i = 0; i < 4; i++) for (i = 0; i < 4; i++)
{ {
v3d = &splat.verts[i]; v3d = &splat.verts[i];
// transform the origin point // transform the origin point
tr_x = v3d->x - viewx; tr_x = v3d->x - spr->viewpoint.x;
tr_y = v3d->y - viewy; tr_y = v3d->y - spr->viewpoint.y;
// rotation around vertical y axis // rotation around vertical y axis
rot_x = FixedMul(tr_x, viewsin) - FixedMul(tr_y, viewcos); rot_x = FixedMul(tr_x, sa) - FixedMul(tr_y, ca);
rot_y = FixedMul(tr_x, viewcos) + FixedMul(tr_y, viewsin); rot_y = FixedMul(tr_x, ca) + FixedMul(tr_y, sa);
rot_z = v3d->z - viewz; rot_z = v3d->z - spr->viewpoint.z;
if (rot_y < FRACUNIT) if (rot_y < FRACUNIT)
return; return;
@ -416,31 +394,32 @@ static void R_RasterizeFloorSplat(floorsplat_t *pSplat, vector2_t *verts, visspr
if (R_CheckPowersOfTwo()) if (R_CheckPowersOfTwo())
R_CheckFlatLength(ds_flatwidth * ds_flatheight); R_CheckFlatLength(ds_flatwidth * ds_flatheight);
if (pSplat->tilted) if (pSplat->slope)
{ {
R_SetTiltedSpan(0); R_SetTiltedSpan(0);
R_SetScaledSlopePlane(&pSplat->slope, viewx, viewy, viewz, pSplat->xscale, pSplat->yscale, -pSplat->verts[0].x, pSplat->verts[0].y, vis->viewangle, pSplat->angle); R_SetScaledSlopePlane(pSplat->slope, vis->viewpoint.x, vis->viewpoint.y, vis->viewpoint.z, pSplat->xscale, pSplat->yscale, -pSplat->verts[0].x, pSplat->verts[0].y, vis->viewpoint.angle, pSplat->angle);
R_CalculateSlopeVectors(); R_CalculateSlopeVectors();
spanfunctype = SPANDRAWFUNC_TILTEDSPRITE; spanfunctype = SPANDRAWFUNC_TILTEDSPRITE;
} }
else else
{ {
planeheight = abs(pSplat->z - viewz); planeheight = abs(pSplat->z - vis->viewpoint.z);
if (pSplat->angle) if (pSplat->angle)
{ {
// Add the view offset, rotated by the plane angle.
fixed_t a = -pSplat->verts[0].x + viewx;
fixed_t b = -pSplat->verts[0].y + viewy;
angle_t angle = (pSplat->angle >> ANGLETOFINESHIFT);
offsetx = FixedMul(a, FINECOSINE(angle)) - FixedMul(b,FINESINE(angle));
offsety = -FixedMul(a, FINESINE(angle)) - FixedMul(b,FINECOSINE(angle));
memset(cachedheight, 0, sizeof(cachedheight)); memset(cachedheight, 0, sizeof(cachedheight));
// Add the view offset, rotated by the plane angle.
fixed_t a = -pSplat->verts[0].x + vis->viewpoint.x;
fixed_t b = -pSplat->verts[0].y + vis->viewpoint.y;
angle_t angle = (pSplat->angle >> ANGLETOFINESHIFT);
offsetx = FixedMul(a, FINECOSINE(angle)) - FixedMul(b, FINESINE(angle));
offsety = -FixedMul(a, FINESINE(angle)) - FixedMul(b, FINECOSINE(angle));
} }
else else
{ {
offsetx = viewx - pSplat->verts[0].x; offsetx = vis->viewpoint.x - pSplat->verts[0].x;
offsety = pSplat->verts[0].y - viewy; offsety = pSplat->verts[0].y - vis->viewpoint.y;
} }
} }
@ -461,7 +440,7 @@ static void R_RasterizeFloorSplat(floorsplat_t *pSplat, vector2_t *verts, visspr
{ {
ds_transmap = vis->transmap; ds_transmap = vis->transmap;
if (pSplat->tilted) if (pSplat->slope)
spanfunctype = SPANDRAWFUNC_TILTEDTRANSSPRITE; spanfunctype = SPANDRAWFUNC_TILTEDTRANSSPRITE;
else else
spanfunctype = SPANDRAWFUNC_TRANSSPRITE; spanfunctype = SPANDRAWFUNC_TRANSSPRITE;
@ -528,12 +507,12 @@ static void R_RasterizeFloorSplat(floorsplat_t *pSplat, vector2_t *verts, visspr
if (x2 < x1) if (x2 < x1)
continue; continue;
if (!pSplat->tilted) if (!pSplat->slope)
{ {
fixed_t xstep, ystep; fixed_t xstep, ystep;
fixed_t distance, span; fixed_t distance, span;
angle_t angle = (vis->viewangle + pSplat->angle)>>ANGLETOFINESHIFT; angle_t angle = (vis->viewpoint.angle + pSplat->angle)>>ANGLETOFINESHIFT;
angle_t planecos = FINECOSINE(angle); angle_t planecos = FINECOSINE(angle);
angle_t planesin = FINESINE(angle); angle_t planesin = FINESINE(angle);
@ -577,7 +556,7 @@ static void R_RasterizeFloorSplat(floorsplat_t *pSplat, vector2_t *verts, visspr
rastertab[y].maxx = INT32_MIN; rastertab[y].maxx = INT32_MIN;
} }
if (pSplat->angle && !pSplat->tilted) if (pSplat->angle && !pSplat->slope)
memset(cachedheight, 0, sizeof(cachedheight)); memset(cachedheight, 0, sizeof(cachedheight));
} }

View file

@ -34,8 +34,7 @@ typedef struct floorsplat_s
INT32 width, height; INT32 width, height;
fixed_t scale, xscale, yscale; fixed_t scale, xscale, yscale;
angle_t angle; angle_t angle;
boolean tilted; // Uses the tilted drawer pslope_t *slope;
pslope_t slope;
vector3_t verts[4]; // (x,y,z) as viewed from above on map vector3_t verts[4]; // (x,y,z) as viewed from above on map
fixed_t x, y, z; // position fixed_t x, y, z; // position

View file

@ -727,7 +727,7 @@ Rloadflats (INT32 i, INT32 w)
texpatch_t *patch; texpatch_t *patch;
// Yes // Yes
if (wadfiles[w]->type == RET_PK3) if (W_FileHasFolders(wadfiles[w]))
{ {
texstart = W_CheckNumForFolderStartPK3("flats/", (UINT16)w, 0); texstart = W_CheckNumForFolderStartPK3("flats/", (UINT16)w, 0);
texend = W_CheckNumForFolderEndPK3("flats/", (UINT16)w, texstart); texend = W_CheckNumForFolderEndPK3("flats/", (UINT16)w, texstart);
@ -749,7 +749,7 @@ Rloadflats (INT32 i, INT32 w)
size_t lumplength; size_t lumplength;
size_t flatsize = 0; size_t flatsize = 0;
if (wadfiles[w]->type == RET_PK3) if (W_FileHasFolders(wadfiles[w]))
{ {
if (W_IsLumpFolder(wadnum, lumpnum)) // Check if lump is a folder if (W_IsLumpFolder(wadnum, lumpnum)) // Check if lump is a folder
continue; // If it is then SKIP IT continue; // If it is then SKIP IT
@ -839,7 +839,7 @@ Rloadtextures (INT32 i, INT32 w)
texpatch_t *patch; texpatch_t *patch;
// Get the lump numbers for the markers in the WAD, if they exist. // Get the lump numbers for the markers in the WAD, if they exist.
if (wadfiles[w]->type == RET_PK3) if (W_FileHasFolders(wadfiles[w]))
{ {
texstart = W_CheckNumForFolderStartPK3("textures/", (UINT16)w, 0); texstart = W_CheckNumForFolderStartPK3("textures/", (UINT16)w, 0);
texend = W_CheckNumForFolderEndPK3("textures/", (UINT16)w, texstart); texend = W_CheckNumForFolderEndPK3("textures/", (UINT16)w, texstart);
@ -870,7 +870,7 @@ Rloadtextures (INT32 i, INT32 w)
size_t lumplength; size_t lumplength;
#endif #endif
if (wadfiles[w]->type == RET_PK3) if (W_FileHasFolders(wadfiles[w]))
{ {
if (W_IsLumpFolder(wadnum, lumpnum)) // Check if lump is a folder if (W_IsLumpFolder(wadnum, lumpnum)) // Check if lump is a folder
continue; // If it is then SKIP IT continue; // If it is then SKIP IT
@ -959,7 +959,7 @@ void R_LoadTextures(void)
{ {
#ifdef WALLFLATS #ifdef WALLFLATS
// Count flats // Count flats
if (wadfiles[w]->type == RET_PK3) if (W_FileHasFolders(wadfiles[w]))
{ {
texstart = W_CheckNumForFolderStartPK3("flats/", (UINT16)w, 0); texstart = W_CheckNumForFolderStartPK3("flats/", (UINT16)w, 0);
texend = W_CheckNumForFolderEndPK3("flats/", (UINT16)w, texstart); texend = W_CheckNumForFolderEndPK3("flats/", (UINT16)w, texstart);
@ -973,7 +973,7 @@ void R_LoadTextures(void)
if (!( texstart == INT16_MAX || texend == INT16_MAX )) if (!( texstart == INT16_MAX || texend == INT16_MAX ))
{ {
// PK3s have subfolders, so we can't just make a simple sum // PK3s have subfolders, so we can't just make a simple sum
if (wadfiles[w]->type == RET_PK3) if (W_FileHasFolders(wadfiles[w]))
{ {
for (j = texstart; j < texend; j++) for (j = texstart; j < texend; j++)
{ {
@ -997,7 +997,7 @@ void R_LoadTextures(void)
} }
// Count single-patch textures // Count single-patch textures
if (wadfiles[w]->type == RET_PK3) if (W_FileHasFolders(wadfiles[w]))
{ {
texstart = W_CheckNumForFolderStartPK3("textures/", (UINT16)w, 0); texstart = W_CheckNumForFolderStartPK3("textures/", (UINT16)w, 0);
texend = W_CheckNumForFolderEndPK3("textures/", (UINT16)w, texstart); texend = W_CheckNumForFolderEndPK3("textures/", (UINT16)w, texstart);
@ -1012,7 +1012,7 @@ void R_LoadTextures(void)
continue; continue;
// PK3s have subfolders, so we can't just make a simple sum // PK3s have subfolders, so we can't just make a simple sum
if (wadfiles[w]->type == RET_PK3) if (W_FileHasFolders(wadfiles[w]))
{ {
for (j = texstart; j < texend; j++) for (j = texstart; j < texend; j++)
{ {
@ -1553,6 +1553,7 @@ lumpnum_t R_GetFlatNumForName(const char *name)
continue; continue;
break; break;
case RET_PK3: case RET_PK3:
case RET_FOLDER:
if ((start = W_CheckNumForFolderStartPK3("Flats/", i, 0)) == INT16_MAX) if ((start = W_CheckNumForFolderStartPK3("Flats/", i, 0)) == INT16_MAX)
continue; continue;
if ((end = W_CheckNumForFolderEndPK3("Flats/", i, start)) == INT16_MAX) if ((end = W_CheckNumForFolderEndPK3("Flats/", i, start)) == INT16_MAX)

View file

@ -443,6 +443,7 @@ void R_AddSpriteDefs(UINT16 wadnum)
end = W_CheckNumForNamePwad("SS_END",wadnum,start); //deutex compatib. end = W_CheckNumForNamePwad("SS_END",wadnum,start); //deutex compatib.
break; break;
case RET_PK3: case RET_PK3:
case RET_FOLDER:
start = W_CheckNumForFolderStartPK3("Sprites/", wadnum, 0); start = W_CheckNumForFolderStartPK3("Sprites/", wadnum, 0);
end = W_CheckNumForFolderEndPK3("Sprites/", wadnum, start); end = W_CheckNumForFolderEndPK3("Sprites/", wadnum, start);
break; break;
@ -1956,9 +1957,12 @@ static void R_ProjectSprite(mobj_t *thing)
vis->paperoffset = paperoffset; vis->paperoffset = paperoffset;
vis->paperdistance = paperdistance; vis->paperdistance = paperdistance;
vis->centerangle = centerangle; vis->centerangle = centerangle;
vis->viewangle = viewangle;
vis->shear.tan = sheartan; vis->shear.tan = sheartan;
vis->shear.offset = 0; vis->shear.offset = 0;
vis->viewpoint.x = viewx;
vis->viewpoint.y = viewy;
vis->viewpoint.z = viewz;
vis->viewpoint.angle = viewangle;
vis->mobj = thing; // Easy access! Tails 06-07-2002 vis->mobj = thing; // Easy access! Tails 06-07-2002

View file

@ -164,7 +164,12 @@ typedef struct vissprite_s
fixed_t xiscale; // negative if flipped fixed_t xiscale; // negative if flipped
angle_t centerangle; // for paper sprites angle_t centerangle; // for paper sprites
angle_t viewangle; // for floor sprites, the viewpoint's current angle
// for floor sprites
struct {
fixed_t x, y, z; // the viewpoint's current position
angle_t angle; // the viewpoint's current angle
} viewpoint;
struct { struct {
fixed_t tan; // The amount to shear the sprite vertically per row fixed_t tan; // The amount to shear the sprite vertically per row
@ -185,9 +190,10 @@ typedef struct vissprite_s
extracolormap_t *extra_colormap; // global colormaps extracolormap_t *extra_colormap; // global colormaps
// Precalculated top and bottom screen coords for the sprite.
fixed_t thingheight; // The actual height of the thing (for 3D floors) fixed_t thingheight; // The actual height of the thing (for 3D floors)
sector_t *sector; // The sector containing the thing. sector_t *sector; // The sector containing the thing.
// Precalculated top and bottom screen coords for the sprite.
INT16 sz, szt; INT16 sz, szt;
spritecut_e cut; spritecut_e cut;

View file

@ -550,7 +550,7 @@ static void I_StartupConsole(void)
void I_GetConsoleEvents(void) void I_GetConsoleEvents(void)
{ {
// we use this when sending back commands // we use this when sending back commands
event_t ev = {0,0,0,0}; event_t ev = {0};
char key = 0; char key = 0;
ssize_t d; ssize_t d;
@ -572,7 +572,7 @@ void I_GetConsoleEvents(void)
tty_con.buffer[tty_con.cursor] = '\0'; tty_con.buffer[tty_con.cursor] = '\0';
tty_Back(); tty_Back();
} }
ev.data1 = KEY_BACKSPACE; ev.key = KEY_BACKSPACE;
} }
else if (key < ' ') // check if this is a control char else if (key < ' ') // check if this is a control char
{ {
@ -580,19 +580,19 @@ void I_GetConsoleEvents(void)
{ {
tty_Clear(); tty_Clear();
tty_con.cursor = 0; tty_con.cursor = 0;
ev.data1 = KEY_ENTER; ev.key = KEY_ENTER;
} }
else return; else return;
} }
else else
{ {
// push regular character // push regular character
ev.data1 = tty_con.buffer[tty_con.cursor] = key; ev.key = tty_con.buffer[tty_con.cursor] = key;
tty_con.cursor++; tty_con.cursor++;
// print the current line (this is differential) // print the current line (this is differential)
d = write(STDOUT_FILENO, &key, 1); d = write(STDOUT_FILENO, &key, 1);
} }
if (ev.data1) D_PostEvent(&ev); if (ev.key) D_PostEvent(&ev);
//tty_FlushIn(); //tty_FlushIn();
(void)d; (void)d;
} }
@ -626,18 +626,18 @@ static void Impl_HandleKeyboardConsoleEvent(KEY_EVENT_RECORD evt, HANDLE co)
{ {
case VK_ESCAPE: case VK_ESCAPE:
case VK_TAB: case VK_TAB:
event.data1 = KEY_NULL; event.key = KEY_NULL;
break; break;
case VK_RETURN: case VK_RETURN:
entering_con_command = false; entering_con_command = false;
/* FALLTHRU */ /* FALLTHRU */
default: default:
//event.data1 = MapVirtualKey(evt.wVirtualKeyCode,2); // convert in to char //event.key = MapVirtualKey(evt.wVirtualKeyCode,2); // convert in to char
event.data1 = evt.uChar.AsciiChar; event.key = evt.uChar.AsciiChar;
} }
if (co != INVALID_HANDLE_VALUE && GetFileType(co) == FILE_TYPE_CHAR && GetConsoleMode(co, &t)) if (co != INVALID_HANDLE_VALUE && GetFileType(co) == FILE_TYPE_CHAR && GetConsoleMode(co, &t))
{ {
if (event.data1 && event.data1 != KEY_LSHIFT && event.data1 != KEY_RSHIFT) if (event.key && event.key != KEY_LSHIFT && event.key != KEY_RSHIFT)
{ {
#ifdef _UNICODE #ifdef _UNICODE
WriteConsole(co, &evt.uChar.UnicodeChar, 1, &t, NULL); WriteConsole(co, &evt.uChar.UnicodeChar, 1, &t, NULL);
@ -652,7 +652,7 @@ static void Impl_HandleKeyboardConsoleEvent(KEY_EVENT_RECORD evt, HANDLE co)
} }
} }
} }
if (event.data1) D_PostEvent(&event); if (event.key) D_PostEvent(&event);
} }
void I_GetConsoleEvents(void) void I_GetConsoleEvents(void)
@ -917,7 +917,7 @@ INT32 I_GetKey (void)
ev = &events[eventtail]; ev = &events[eventtail];
if (ev->type == ev_keydown || ev->type == ev_console) if (ev->type == ev_keydown || ev->type == ev_console)
{ {
rc = ev->data1; rc = ev->key;
continue; continue;
} }
} }
@ -977,22 +977,22 @@ void I_ShutdownJoystick(void)
INT32 i; INT32 i;
event_t event; event_t event;
event.type=ev_keyup; event.type=ev_keyup;
event.data2 = 0; event.x = 0;
event.data3 = 0; event.y = 0;
lastjoybuttons = lastjoyhats = 0; lastjoybuttons = lastjoyhats = 0;
// emulate the up of all joystick buttons // emulate the up of all joystick buttons
for (i=0;i<JOYBUTTONS;i++) for (i=0;i<JOYBUTTONS;i++)
{ {
event.data1=KEY_JOY1+i; event.key=KEY_JOY1+i;
D_PostEvent(&event); D_PostEvent(&event);
} }
// emulate the up of all joystick hats // emulate the up of all joystick hats
for (i=0;i<JOYHATS*4;i++) for (i=0;i<JOYHATS*4;i++)
{ {
event.data1=KEY_HAT1+i; event.key=KEY_HAT1+i;
D_PostEvent(&event); D_PostEvent(&event);
} }
@ -1000,7 +1000,7 @@ void I_ShutdownJoystick(void)
event.type = ev_joystick; event.type = ev_joystick;
for (i=0;i<JOYAXISSET; i++) for (i=0;i<JOYAXISSET; i++)
{ {
event.data1 = i; event.key = i;
D_PostEvent(&event); D_PostEvent(&event);
} }
@ -1012,7 +1012,7 @@ void I_ShutdownJoystick(void)
void I_GetJoystickEvents(void) void I_GetJoystickEvents(void)
{ {
static event_t event = {0,0,0,0}; static event_t event = {0,0,0,0,false};
INT32 i = 0; INT32 i = 0;
UINT64 joyhats = 0; UINT64 joyhats = 0;
#if 0 #if 0
@ -1049,7 +1049,7 @@ void I_GetJoystickEvents(void)
event.type = ev_keydown; event.type = ev_keydown;
else else
event.type = ev_keyup; event.type = ev_keyup;
event.data1 = KEY_JOY1 + i; event.key = KEY_JOY1 + i;
D_PostEvent(&event); D_PostEvent(&event);
} }
} }
@ -1080,7 +1080,7 @@ void I_GetJoystickEvents(void)
event.type = ev_keydown; event.type = ev_keydown;
else else
event.type = ev_keyup; event.type = ev_keyup;
event.data1 = KEY_HAT1 + i; event.key = KEY_HAT1 + i;
D_PostEvent(&event); D_PostEvent(&event);
} }
} }
@ -1092,7 +1092,7 @@ void I_GetJoystickEvents(void)
for (i = JOYAXISSET - 1; i >= 0; i--) for (i = JOYAXISSET - 1; i >= 0; i--)
{ {
event.data1 = i; event.key = i;
if (i*2 + 1 <= JoyInfo.axises) if (i*2 + 1 <= JoyInfo.axises)
axisx = SDL_JoystickGetAxis(JoyInfo.dev, i*2 + 0); axisx = SDL_JoystickGetAxis(JoyInfo.dev, i*2 + 0);
else axisx = 0; else axisx = 0;
@ -1110,15 +1110,15 @@ void I_GetJoystickEvents(void)
{ {
// gamepad control type, on or off, live or die // gamepad control type, on or off, live or die
if (axisx < -(JOYAXISRANGE/2)) if (axisx < -(JOYAXISRANGE/2))
event.data2 = -1; event.x = -1;
else if (axisx > (JOYAXISRANGE/2)) else if (axisx > (JOYAXISRANGE/2))
event.data2 = 1; event.x = 1;
else event.data2 = 0; else event.x = 0;
if (axisy < -(JOYAXISRANGE/2)) if (axisy < -(JOYAXISRANGE/2))
event.data3 = -1; event.y = -1;
else if (axisy > (JOYAXISRANGE/2)) else if (axisy > (JOYAXISRANGE/2))
event.data3 = 1; event.y = 1;
else event.data3 = 0; else event.y = 0;
} }
else else
{ {
@ -1132,8 +1132,8 @@ void I_GetJoystickEvents(void)
#endif #endif
// analog control style , just send the raw data // analog control style , just send the raw data
event.data2 = axisx; // x axis event.x = axisx; // x axis
event.data3 = axisy; // y axis event.y = axisy; // y axis
} }
D_PostEvent(&event); D_PostEvent(&event);
} }
@ -1247,22 +1247,22 @@ void I_ShutdownJoystick2(void)
INT32 i; INT32 i;
event_t event; event_t event;
event.type = ev_keyup; event.type = ev_keyup;
event.data2 = 0; event.x = 0;
event.data3 = 0; event.y = 0;
lastjoy2buttons = lastjoy2hats = 0; lastjoy2buttons = lastjoy2hats = 0;
// emulate the up of all joystick buttons // emulate the up of all joystick buttons
for (i = 0; i < JOYBUTTONS; i++) for (i = 0; i < JOYBUTTONS; i++)
{ {
event.data1 = KEY_2JOY1 + i; event.key = KEY_2JOY1 + i;
D_PostEvent(&event); D_PostEvent(&event);
} }
// emulate the up of all joystick hats // emulate the up of all joystick hats
for (i = 0; i < JOYHATS*4; i++) for (i = 0; i < JOYHATS*4; i++)
{ {
event.data1 = KEY_2HAT1 + i; event.key = KEY_2HAT1 + i;
D_PostEvent(&event); D_PostEvent(&event);
} }
@ -1270,7 +1270,7 @@ void I_ShutdownJoystick2(void)
event.type = ev_joystick2; event.type = ev_joystick2;
for (i = 0; i < JOYAXISSET; i++) for (i = 0; i < JOYAXISSET; i++)
{ {
event.data1 = i; event.key = i;
D_PostEvent(&event); D_PostEvent(&event);
} }
@ -1282,7 +1282,7 @@ void I_ShutdownJoystick2(void)
void I_GetJoystick2Events(void) void I_GetJoystick2Events(void)
{ {
static event_t event = {0,0,0,0}; static event_t event = {0,0,0,0,false};
INT32 i = 0; INT32 i = 0;
UINT64 joyhats = 0; UINT64 joyhats = 0;
#if 0 #if 0
@ -1321,7 +1321,7 @@ void I_GetJoystick2Events(void)
event.type = ev_keydown; event.type = ev_keydown;
else else
event.type = ev_keyup; event.type = ev_keyup;
event.data1 = KEY_2JOY1 + i; event.key = KEY_2JOY1 + i;
D_PostEvent(&event); D_PostEvent(&event);
} }
} }
@ -1352,7 +1352,7 @@ void I_GetJoystick2Events(void)
event.type = ev_keydown; event.type = ev_keydown;
else else
event.type = ev_keyup; event.type = ev_keyup;
event.data1 = KEY_2HAT1 + i; event.key = KEY_2HAT1 + i;
D_PostEvent(&event); D_PostEvent(&event);
} }
} }
@ -1364,7 +1364,7 @@ void I_GetJoystick2Events(void)
for (i = JOYAXISSET - 1; i >= 0; i--) for (i = JOYAXISSET - 1; i >= 0; i--)
{ {
event.data1 = i; event.key = i;
if (i*2 + 1 <= JoyInfo2.axises) if (i*2 + 1 <= JoyInfo2.axises)
axisx = SDL_JoystickGetAxis(JoyInfo2.dev, i*2 + 0); axisx = SDL_JoystickGetAxis(JoyInfo2.dev, i*2 + 0);
else axisx = 0; else axisx = 0;
@ -1380,17 +1380,17 @@ void I_GetJoystick2Events(void)
{ {
// gamepad control type, on or off, live or die // gamepad control type, on or off, live or die
if (axisx < -(JOYAXISRANGE/2)) if (axisx < -(JOYAXISRANGE/2))
event.data2 = -1; event.x = -1;
else if (axisx > (JOYAXISRANGE/2)) else if (axisx > (JOYAXISRANGE/2))
event.data2 = 1; event.x = 1;
else else
event.data2 = 0; event.x = 0;
if (axisy < -(JOYAXISRANGE/2)) if (axisy < -(JOYAXISRANGE/2))
event.data3 = -1; event.y = -1;
else if (axisy > (JOYAXISRANGE/2)) else if (axisy > (JOYAXISRANGE/2))
event.data3 = 1; event.y = 1;
else else
event.data3 = 0; event.y = 0;
} }
else else
{ {
@ -1404,8 +1404,8 @@ void I_GetJoystick2Events(void)
#endif #endif
// analog control style , just send the raw data // analog control style , just send the raw data
event.data2 = axisx; // x axis event.x = axisx; // x axis
event.data3 = axisy; // y axis event.y = axisy; // y axis
} }
D_PostEvent(&event); D_PostEvent(&event);
} }
@ -1804,7 +1804,7 @@ void I_GetMouseEvents(void)
if (!(button & (1<<j))) //keyup if (!(button & (1<<j))) //keyup
{ {
event.type = ev_keyup; event.type = ev_keyup;
event.data1 = KEY_2MOUSE1+j; event.key = KEY_2MOUSE1+j;
D_PostEvent(&event); D_PostEvent(&event);
om2b ^= 1 << j; om2b ^= 1 << j;
} }
@ -1814,18 +1814,18 @@ void I_GetMouseEvents(void)
if (button & (1<<j)) if (button & (1<<j))
{ {
event.type = ev_keydown; event.type = ev_keydown;
event.data1 = KEY_2MOUSE1+j; event.key = KEY_2MOUSE1+j;
D_PostEvent(&event); D_PostEvent(&event);
om2b ^= 1 << j; om2b ^= 1 << j;
} }
} }
} }
event.data2 = ((SINT8)mdata[1])+((SINT8)mdata[3]); event.x = ((SINT8)mdata[1])+((SINT8)mdata[3]);
event.data3 = ((SINT8)mdata[2])+((SINT8)mdata[4]); event.y = ((SINT8)mdata[2])+((SINT8)mdata[4]);
if (event.data2 && event.data3) if (event.x && event.y)
{ {
event.type = ev_mouse2; event.type = ev_mouse2;
event.data1 = 0; event.key = 0;
D_PostEvent(&event); D_PostEvent(&event);
} }
} }
@ -1867,7 +1867,7 @@ static void I_ShutdownMouse2(void)
for (i = 0; i < MOUSEBUTTONS; i++) for (i = 0; i < MOUSEBUTTONS; i++)
{ {
event.type = ev_keyup; event.type = ev_keyup;
event.data1 = KEY_2MOUSE1+i; event.key = KEY_2MOUSE1+i;
D_PostEvent(&event); D_PostEvent(&event);
} }
@ -1958,7 +1958,7 @@ void I_GetMouseEvents(void)
event.type = ev_keydown; event.type = ev_keydown;
else else
event.type = ev_keyup; event.type = ev_keyup;
event.data1 = KEY_2MOUSE1+i; event.key = KEY_2MOUSE1+i;
D_PostEvent(&event); D_PostEvent(&event);
} }
} }
@ -1966,10 +1966,10 @@ void I_GetMouseEvents(void)
if (handlermouse2x != 0 || handlermouse2y != 0) if (handlermouse2x != 0 || handlermouse2y != 0)
{ {
event.type = ev_mouse2; event.type = ev_mouse2;
event.data1 = 0; event.key = 0;
// event.data1 = buttons; // not needed // event.key = buttons; // not needed
event.data2 = handlermouse2x << 1; event.x = handlermouse2x << 1;
event.data3 = handlermouse2y << 1; event.y = handlermouse2y << 1;
handlermouse2x = 0; handlermouse2x = 0;
handlermouse2y = 0; handlermouse2y = 0;

View file

@ -73,6 +73,8 @@
#include "../console.h" #include "../console.h"
#include "../command.h" #include "../command.h"
#include "../r_main.h" #include "../r_main.h"
#include "../lua_script.h"
#include "../lua_libs.h"
#include "../lua_hook.h" #include "../lua_hook.h"
#include "sdlmain.h" #include "sdlmain.h"
#ifdef HWRENDER #ifdef HWRENDER
@ -372,6 +374,8 @@ static boolean IgnoreMouse(void)
if (gamestate != GS_LEVEL && gamestate != GS_INTERMISSION && if (gamestate != GS_LEVEL && gamestate != GS_INTERMISSION &&
gamestate != GS_CONTINUING && gamestate != GS_CUTSCENE) gamestate != GS_CONTINUING && gamestate != GS_CUTSCENE)
return true; return true;
if (!mousegrabbedbylua)
return true;
return false; return false;
} }
@ -663,8 +667,9 @@ static void Impl_HandleKeyboardEvent(SDL_KeyboardEvent evt, Uint32 type)
{ {
return; return;
} }
event.data1 = Impl_SDL_Scancode_To_Keycode(evt.keysym.scancode); event.key = Impl_SDL_Scancode_To_Keycode(evt.keysym.scancode);
if (event.data1) D_PostEvent(&event); event.repeated = (evt.repeat != 0);
if (event.key) D_PostEvent(&event);
} }
static void Impl_HandleMouseMotionEvent(SDL_MouseMotionEvent evt) static void Impl_HandleMouseMotionEvent(SDL_MouseMotionEvent evt)
@ -742,15 +747,15 @@ static void Impl_HandleMouseButtonEvent(SDL_MouseButtonEvent evt, Uint32 type)
} }
else return; else return;
if (evt.button == SDL_BUTTON_MIDDLE) if (evt.button == SDL_BUTTON_MIDDLE)
event.data1 = KEY_MOUSE1+2; event.key = KEY_MOUSE1+2;
else if (evt.button == SDL_BUTTON_RIGHT) else if (evt.button == SDL_BUTTON_RIGHT)
event.data1 = KEY_MOUSE1+1; event.key = KEY_MOUSE1+1;
else if (evt.button == SDL_BUTTON_LEFT) else if (evt.button == SDL_BUTTON_LEFT)
event.data1 = KEY_MOUSE1; event.key = KEY_MOUSE1;
else if (evt.button == SDL_BUTTON_X1) else if (evt.button == SDL_BUTTON_X1)
event.data1 = KEY_MOUSE1+3; event.key = KEY_MOUSE1+3;
else if (evt.button == SDL_BUTTON_X2) else if (evt.button == SDL_BUTTON_X2)
event.data1 = KEY_MOUSE1+4; event.key = KEY_MOUSE1+4;
if (event.type == ev_keyup || event.type == ev_keydown) if (event.type == ev_keyup || event.type == ev_keydown)
{ {
D_PostEvent(&event); D_PostEvent(&event);
@ -766,17 +771,17 @@ static void Impl_HandleMouseWheelEvent(SDL_MouseWheelEvent evt)
if (evt.y > 0) if (evt.y > 0)
{ {
event.data1 = KEY_MOUSEWHEELUP; event.key = KEY_MOUSEWHEELUP;
event.type = ev_keydown; event.type = ev_keydown;
} }
if (evt.y < 0) if (evt.y < 0)
{ {
event.data1 = KEY_MOUSEWHEELDOWN; event.key = KEY_MOUSEWHEELDOWN;
event.type = ev_keydown; event.type = ev_keydown;
} }
if (evt.y == 0) if (evt.y == 0)
{ {
event.data1 = 0; event.key = 0;
event.type = ev_keyup; event.type = ev_keyup;
} }
if (event.type == ev_keyup || event.type == ev_keydown) if (event.type == ev_keyup || event.type == ev_keydown)
@ -795,7 +800,7 @@ static void Impl_HandleJoystickAxisEvent(SDL_JoyAxisEvent evt)
joyid[1] = SDL_JoystickInstanceID(JoyInfo2.dev); joyid[1] = SDL_JoystickInstanceID(JoyInfo2.dev);
evt.axis++; evt.axis++;
event.data1 = event.data2 = event.data3 = INT32_MAX; event.key = event.x = event.y = INT32_MAX;
if (evt.which == joyid[0]) if (evt.which == joyid[0])
{ {
@ -812,14 +817,14 @@ static void Impl_HandleJoystickAxisEvent(SDL_JoyAxisEvent evt)
//vaule //vaule
if (evt.axis%2) if (evt.axis%2)
{ {
event.data1 = evt.axis / 2; event.key = evt.axis / 2;
event.data2 = SDLJoyAxis(evt.value, event.type); event.x = SDLJoyAxis(evt.value, event.type);
} }
else else
{ {
evt.axis--; evt.axis--;
event.data1 = evt.axis / 2; event.key = evt.axis / 2;
event.data3 = SDLJoyAxis(evt.value, event.type); event.y = SDLJoyAxis(evt.value, event.type);
} }
D_PostEvent(&event); D_PostEvent(&event);
} }
@ -839,11 +844,11 @@ static void Impl_HandleJoystickHatEvent(SDL_JoyHatEvent evt)
if (evt.which == joyid[0]) if (evt.which == joyid[0])
{ {
event.data1 = KEY_HAT1 + (evt.hat*4); event.key = KEY_HAT1 + (evt.hat*4);
} }
else if (evt.which == joyid[1]) else if (evt.which == joyid[1])
{ {
event.data1 = KEY_2HAT1 + (evt.hat*4); event.key = KEY_2HAT1 + (evt.hat*4);
} }
else return; else return;
@ -862,11 +867,11 @@ static void Impl_HandleJoystickButtonEvent(SDL_JoyButtonEvent evt, Uint32 type)
if (evt.which == joyid[0]) if (evt.which == joyid[0])
{ {
event.data1 = KEY_JOY1; event.key = KEY_JOY1;
} }
else if (evt.which == joyid[1]) else if (evt.which == joyid[1])
{ {
event.data1 = KEY_2JOY1; event.key = KEY_2JOY1;
} }
else return; else return;
if (type == SDL_JOYBUTTONUP) if (type == SDL_JOYBUTTONUP)
@ -880,7 +885,7 @@ static void Impl_HandleJoystickButtonEvent(SDL_JoyButtonEvent evt, Uint32 type)
else return; else return;
if (evt.button < JOYBUTTONS) if (evt.button < JOYBUTTONS)
{ {
event.data1 += evt.button; event.key += evt.button;
} }
else return; else return;
@ -1084,9 +1089,9 @@ void I_GetEvent(void)
SDL_GetWindowSize(window, &wwidth, &wheight); SDL_GetWindowSize(window, &wwidth, &wheight);
//SDL_memset(&event, 0, sizeof(event_t)); //SDL_memset(&event, 0, sizeof(event_t));
event.type = ev_mouse; event.type = ev_mouse;
event.data1 = 0; event.key = 0;
event.data2 = (INT32)lround(mousemovex * ((float)wwidth / (float)realwidth)); event.x = (INT32)lround(mousemovex * ((float)wwidth / (float)realwidth));
event.data3 = (INT32)lround(mousemovey * ((float)wheight / (float)realheight)); event.y = (INT32)lround(mousemovey * ((float)wheight / (float)realheight));
D_PostEvent(&event); D_PostEvent(&event);
} }

View file

@ -9,7 +9,7 @@
/// \file /// \file
/// \brief SDL Mixer interface for sound /// \brief SDL Mixer interface for sound
#ifdef HAVE_LIBGME #ifdef HAVE_GME
#ifdef HAVE_ZLIB #ifdef HAVE_ZLIB
#ifndef _MSC_VER #ifndef _MSC_VER
#ifndef _LARGEFILE64_SOURCE #ifndef _LARGEFILE64_SOURCE
@ -27,7 +27,7 @@
#include <zlib.h> #include <zlib.h>
#endif // HAVE_ZLIB #endif // HAVE_ZLIB
#endif // HAVE_LIBGME #endif // HAVE_GME
#include "../doomdef.h" #include "../doomdef.h"
#include "../doomstat.h" // menuactive #include "../doomstat.h" // menuactive
@ -73,11 +73,11 @@
#define MUS_MODPLUG MUS_MODPLUG_UNUSED #define MUS_MODPLUG MUS_MODPLUG_UNUSED
#endif #endif
#ifdef HAVE_LIBGME #ifdef HAVE_GME
#include "gme/gme.h" #include "gme/gme.h"
#define GME_TREBLE 5.0f #define GME_TREBLE 5.0f
#define GME_BASS 1.0f #define GME_BASS 1.0f
#endif // HAVE_LIBGME #endif // HAVE_GME
static UINT16 BUFFERSIZE = 2048; static UINT16 BUFFERSIZE = 2048;
static UINT16 SAMPLERATE = 44100; static UINT16 SAMPLERATE = 44100;
@ -110,7 +110,7 @@ static INT32 fading_id;
static void (*fading_callback)(void); static void (*fading_callback)(void);
static boolean fading_nocleanup; static boolean fading_nocleanup;
#ifdef HAVE_LIBGME #ifdef HAVE_GME
static Music_Emu *gme; static Music_Emu *gme;
static UINT16 current_track; static UINT16 current_track;
#endif #endif
@ -220,7 +220,7 @@ static void var_cleanup(void)
internal_volume = 100; internal_volume = 100;
} }
#if defined (HAVE_LIBGME) && defined (HAVE_ZLIB) #if defined (HAVE_GME) && defined (HAVE_ZLIB)
static const char* get_zlib_error(int zErr) static const char* get_zlib_error(int zErr)
{ {
switch (zErr) switch (zErr)
@ -318,7 +318,7 @@ void I_ShutdownSound(void)
SDL_QuitSubSystem(SDL_INIT_AUDIO); SDL_QuitSubSystem(SDL_INIT_AUDIO);
#ifdef HAVE_LIBGME #ifdef HAVE_GME
if (gme) if (gme)
gme_delete(gme); gme_delete(gme);
#endif #endif
@ -453,7 +453,7 @@ void *I_GetSfx(sfxinfo_t *sfx)
void *lump; void *lump;
Mix_Chunk *chunk; Mix_Chunk *chunk;
SDL_RWops *rw; SDL_RWops *rw;
#ifdef HAVE_LIBGME #ifdef HAVE_GME
Music_Emu *emu; Music_Emu *emu;
gme_info_t *info; gme_info_t *info;
#endif #endif
@ -473,7 +473,7 @@ void *I_GetSfx(sfxinfo_t *sfx)
} }
// Not a doom sound? Try something else. // Not a doom sound? Try something else.
#ifdef HAVE_LIBGME #ifdef HAVE_GME
// VGZ format // VGZ format
if (((UINT8 *)lump)[0] == 0x1F if (((UINT8 *)lump)[0] == 0x1F
&& ((UINT8 *)lump)[1] == 0x8B) && ((UINT8 *)lump)[1] == 0x8B)
@ -729,7 +729,7 @@ static UINT32 music_fade(UINT32 interval, void *param)
} }
} }
#ifdef HAVE_LIBGME #ifdef HAVE_GME
static void mix_gme(void *udata, Uint8 *stream, int len) static void mix_gme(void *udata, Uint8 *stream, int len)
{ {
int i; int i;
@ -797,7 +797,7 @@ void I_ShutdownMusic(void)
musictype_t I_SongType(void) musictype_t I_SongType(void)
{ {
#ifdef HAVE_LIBGME #ifdef HAVE_GME
if (gme) if (gme)
return MU_GME; return MU_GME;
else else
@ -828,7 +828,7 @@ musictype_t I_SongType(void)
boolean I_SongPlaying(void) boolean I_SongPlaying(void)
{ {
return ( return (
#ifdef HAVE_LIBGME #ifdef HAVE_GME
(I_SongType() == MU_GME && gme) || (I_SongType() == MU_GME && gme) ||
#endif #endif
#ifdef HAVE_OPENMPT #ifdef HAVE_OPENMPT
@ -851,7 +851,7 @@ boolean I_SetSongSpeed(float speed)
{ {
if (speed > 250.0f) if (speed > 250.0f)
speed = 250.0f; //limit speed up to 250x speed = 250.0f; //limit speed up to 250x
#ifdef HAVE_LIBGME #ifdef HAVE_GME
if (gme) if (gme)
{ {
SDL_LockAudio(); SDL_LockAudio();
@ -893,7 +893,7 @@ UINT32 I_GetSongLength(void)
{ {
INT32 length; INT32 length;
#ifdef HAVE_LIBGME #ifdef HAVE_GME
if (gme) if (gme)
{ {
gme_info_t *info; gme_info_t *info;
@ -963,7 +963,7 @@ boolean I_SetSongLoopPoint(UINT32 looppoint)
UINT32 I_GetSongLoopPoint(void) UINT32 I_GetSongLoopPoint(void)
{ {
#ifdef HAVE_LIBGME #ifdef HAVE_GME
if (gme) if (gme)
{ {
INT32 looppoint; INT32 looppoint;
@ -992,7 +992,7 @@ UINT32 I_GetSongLoopPoint(void)
boolean I_SetSongPosition(UINT32 position) boolean I_SetSongPosition(UINT32 position)
{ {
UINT32 length; UINT32 length;
#ifdef HAVE_LIBGME #ifdef HAVE_GME
if (gme) if (gme)
{ {
// this is unstable, so fail silently // this is unstable, so fail silently
@ -1055,7 +1055,7 @@ boolean I_SetSongPosition(UINT32 position)
UINT32 I_GetSongPosition(void) UINT32 I_GetSongPosition(void)
{ {
#ifdef HAVE_LIBGME #ifdef HAVE_GME
if (gme) if (gme)
{ {
INT32 position = gme_tell(gme); INT32 position = gme_tell(gme);
@ -1124,7 +1124,7 @@ boolean I_LoadSong(char *data, size_t len)
SDL_RWops *rw; SDL_RWops *rw;
if (music if (music
#ifdef HAVE_LIBGME #ifdef HAVE_GME
|| gme || gme
#endif #endif
#ifdef HAVE_OPENMPT #ifdef HAVE_OPENMPT
@ -1136,7 +1136,7 @@ boolean I_LoadSong(char *data, size_t len)
// always do this whether or not a music already exists // always do this whether or not a music already exists
var_cleanup(); var_cleanup();
#ifdef HAVE_LIBGME #ifdef HAVE_GME
if ((UINT8)data[0] == 0x1F if ((UINT8)data[0] == 0x1F
&& (UINT8)data[1] == 0x8B) && (UINT8)data[1] == 0x8B)
{ {
@ -1271,7 +1271,7 @@ void I_UnloadSong(void)
{ {
I_StopSong(); I_StopSong();
#ifdef HAVE_LIBGME #ifdef HAVE_GME
if (gme) if (gme)
{ {
gme_delete(gme); gme_delete(gme);
@ -1294,7 +1294,7 @@ void I_UnloadSong(void)
boolean I_PlaySong(boolean looping) boolean I_PlaySong(boolean looping)
{ {
#ifdef HAVE_LIBGME #ifdef HAVE_GME
if (gme) if (gme)
{ {
gme_equalizer_t eq = {GME_TREBLE, GME_BASS, 0,0,0,0,0,0,0,0}; gme_equalizer_t eq = {GME_TREBLE, GME_BASS, 0,0,0,0,0,0,0,0};
@ -1360,7 +1360,7 @@ void I_StopSong(void)
if (!fading_nocleanup) if (!fading_nocleanup)
I_StopFadingSong(); I_StopFadingSong();
#ifdef HAVE_LIBGME #ifdef HAVE_GME
if (gme) if (gme)
{ {
Mix_HookMusic(NULL, NULL); Mix_HookMusic(NULL, NULL);
@ -1433,7 +1433,7 @@ void I_SetMusicVolume(UINT8 volume)
boolean I_SetSongTrack(int track) boolean I_SetSongTrack(int track)
{ {
#ifdef HAVE_LIBGME #ifdef HAVE_GME
// If the specified track is within the number of tracks playing, then change it // If the specified track is within the number of tracks playing, then change it
if (gme) if (gme)
{ {

View file

@ -43,6 +43,7 @@
#endif #endif
#include "lua_hud.h" #include "lua_hud.h"
#include "lua_hook.h"
UINT16 objectsdrawn = 0; UINT16 objectsdrawn = 0;
@ -1391,7 +1392,7 @@ void ST_drawTitleCard(void)
lt_lasttic = lt_ticker; lt_lasttic = lt_ticker;
luahook: luahook:
LUAh_TitleCardHUD(stplyr); LUA_HUDHOOK(titlecard);
} }
// //
@ -2732,7 +2733,7 @@ static void ST_overlayDrawer(void)
ST_drawPowerupHUD(); // same as it ever was... ST_drawPowerupHUD(); // same as it ever was...
if (!(netgame || multiplayer) || !hu_showscores) if (!(netgame || multiplayer) || !hu_showscores)
LUAh_GameHUD(stplyr); LUA_HUDHOOK(game);
// draw level title Tails // draw level title Tails
if (stagetitle && (!WipeInAction) && (!WipeStageTitle)) if (stagetitle && (!WipeInAction) && (!WipeStageTitle))

View file

@ -809,13 +809,13 @@ void V_DrawStretchyFixedPatch(fixed_t x, fixed_t y, fixed_t pscale, fixed_t vsca
} }
// Draws a patch cropped and scaled to arbitrary size. // Draws a patch cropped and scaled to arbitrary size.
void V_DrawCroppedPatch(fixed_t x, fixed_t y, fixed_t pscale, INT32 scrn, patch_t *patch, fixed_t sx, fixed_t sy, fixed_t w, fixed_t h) void V_DrawCroppedPatch(fixed_t x, fixed_t y, fixed_t pscale, fixed_t vscale, INT32 scrn, patch_t *patch, const UINT8 *colormap, fixed_t sx, fixed_t sy, fixed_t w, fixed_t h)
{ {
UINT8 (*patchdrawfunc)(const UINT8*, const UINT8*, fixed_t); UINT8 (*patchdrawfunc)(const UINT8*, const UINT8*, fixed_t);
UINT32 alphalevel = 0; UINT32 alphalevel = 0;
// boolean flip = false; // boolean flip = false;
fixed_t col, ofs, colfrac, rowfrac, fdup; fixed_t col, ofs, colfrac, rowfrac, fdup, vdup;
INT32 dupx, dupy; INT32 dupx, dupy;
const column_t *column; const column_t *column;
UINT8 *desttop, *dest; UINT8 *desttop, *dest;
@ -830,7 +830,7 @@ void V_DrawCroppedPatch(fixed_t x, fixed_t y, fixed_t pscale, INT32 scrn, patch_
//if (rendermode != render_soft && !con_startup) // Not this again //if (rendermode != render_soft && !con_startup) // Not this again
if (rendermode == render_opengl) if (rendermode == render_opengl)
{ {
HWR_DrawCroppedPatch(patch,x,y,pscale,scrn,sx,sy,w,h); HWR_DrawCroppedPatch(patch,x,y,pscale,vscale,scrn,colormap,sx,sy,w,h);
return; return;
} }
#endif #endif
@ -857,31 +857,56 @@ void V_DrawCroppedPatch(fixed_t x, fixed_t y, fixed_t pscale, INT32 scrn, patch_
} }
} }
// only use one dup, to avoid stretching (har har) v_colormap = NULL;
dupx = dupy = (vid.dupx < vid.dupy ? vid.dupx : vid.dupy); if (colormap)
fdup = FixedMul(dupx<<FRACBITS, pscale); {
colfrac = FixedDiv(FRACUNIT, fdup); v_colormap = colormap;
rowfrac = FixedDiv(FRACUNIT, fdup); patchdrawfunc = (v_translevel) ? transmappedpdraw : mappedpdraw;
}
dupx = vid.dupx;
dupy = vid.dupy;
if (scrn & V_SCALEPATCHMASK) switch ((scrn & V_SCALEPATCHMASK) >> V_SCALEPATCHSHIFT)
{
case 1: // V_NOSCALEPATCH
dupx = dupy = 1;
break;
case 2: // V_SMALLSCALEPATCH
dupx = vid.smalldupx;
dupy = vid.smalldupy;
break;
case 3: // V_MEDSCALEPATCH
dupx = vid.meddupx;
dupy = vid.meddupy;
break;
default:
break;
}
// only use one dup, to avoid stretching (har har)
dupx = dupy = (dupx < dupy ? dupx : dupy);
fdup = vdup = FixedMul(dupx<<FRACBITS, pscale);
if (vscale != pscale)
vdup = FixedMul(dupx<<FRACBITS, vscale);
colfrac = FixedDiv(FRACUNIT, fdup);
rowfrac = FixedDiv(FRACUNIT, vdup);
y -= FixedMul(patch->topoffset<<FRACBITS, pscale);
x -= FixedMul(patch->leftoffset<<FRACBITS, pscale); x -= FixedMul(patch->leftoffset<<FRACBITS, pscale);
y -= FixedMul(patch->topoffset<<FRACBITS, vscale);
if (splitscreen && (scrn & V_PERPLAYER)) if (splitscreen && (scrn & V_PERPLAYER))
{ {
fixed_t adjusty = ((scrn & V_NOSCALESTART) ? vid.height : BASEVIDHEIGHT)<<(FRACBITS-1); fixed_t adjusty = ((scrn & V_NOSCALESTART) ? vid.height : BASEVIDHEIGHT)<<(FRACBITS-1);
fdup >>= 1; vdup >>= 1;
rowfrac <<= 1; rowfrac <<= 1;
y >>= 1; y >>= 1;
sy >>= 1;
h >>= 1;
#ifdef QUADS #ifdef QUADS
if (splitscreen > 1) // 3 or 4 players if (splitscreen > 1) // 3 or 4 players
{ {
fixed_t adjustx = ((scrn & V_NOSCALESTART) ? vid.height : BASEVIDHEIGHT)<<(FRACBITS-1)); fixed_t adjustx = ((scrn & V_NOSCALESTART) ? vid.height : BASEVIDHEIGHT)<<(FRACBITS-1));
fdup >>= 1;
colfrac <<= 1; colfrac <<= 1;
x >>= 1; x >>= 1;
sx >>= 1;
w >>= 1;
if (stplyr == &players[displayplayer]) if (stplyr == &players[displayplayer])
{ {
if (!(scrn & (V_SNAPTOTOP|V_SNAPTOBOTTOM))) if (!(scrn & (V_SNAPTOTOP|V_SNAPTOBOTTOM)))
@ -897,7 +922,6 @@ void V_DrawCroppedPatch(fixed_t x, fixed_t y, fixed_t pscale, INT32 scrn, patch_
if (!(scrn & (V_SNAPTOLEFT|V_SNAPTORIGHT))) if (!(scrn & (V_SNAPTOLEFT|V_SNAPTORIGHT)))
perplayershuffle |= 8; perplayershuffle |= 8;
x += adjustx; x += adjustx;
sx += adjustx;
scrn &= ~V_SNAPTOBOTTOM|V_SNAPTOLEFT; scrn &= ~V_SNAPTOBOTTOM|V_SNAPTOLEFT;
} }
else if (stplyr == &players[thirddisplayplayer]) else if (stplyr == &players[thirddisplayplayer])
@ -907,7 +931,6 @@ void V_DrawCroppedPatch(fixed_t x, fixed_t y, fixed_t pscale, INT32 scrn, patch_
if (!(scrn & (V_SNAPTOLEFT|V_SNAPTORIGHT))) if (!(scrn & (V_SNAPTOLEFT|V_SNAPTORIGHT)))
perplayershuffle |= 4; perplayershuffle |= 4;
y += adjusty; y += adjusty;
sy += adjusty;
scrn &= ~V_SNAPTOTOP|V_SNAPTORIGHT; scrn &= ~V_SNAPTOTOP|V_SNAPTORIGHT;
} }
else //if (stplyr == &players[fourthdisplayplayer]) else //if (stplyr == &players[fourthdisplayplayer])
@ -917,9 +940,7 @@ void V_DrawCroppedPatch(fixed_t x, fixed_t y, fixed_t pscale, INT32 scrn, patch_
if (!(scrn & (V_SNAPTOLEFT|V_SNAPTORIGHT))) if (!(scrn & (V_SNAPTOLEFT|V_SNAPTORIGHT)))
perplayershuffle |= 8; perplayershuffle |= 8;
x += adjustx; x += adjustx;
sx += adjustx;
y += adjusty; y += adjusty;
sy += adjusty;
scrn &= ~V_SNAPTOTOP|V_SNAPTOLEFT; scrn &= ~V_SNAPTOTOP|V_SNAPTOLEFT;
} }
} }
@ -938,7 +959,6 @@ void V_DrawCroppedPatch(fixed_t x, fixed_t y, fixed_t pscale, INT32 scrn, patch_
if (!(scrn & (V_SNAPTOTOP|V_SNAPTOBOTTOM))) if (!(scrn & (V_SNAPTOTOP|V_SNAPTOBOTTOM)))
perplayershuffle |= 2; perplayershuffle |= 2;
y += adjusty; y += adjusty;
sy += adjusty;
scrn &= ~V_SNAPTOTOP; scrn &= ~V_SNAPTOTOP;
} }
} }
@ -951,7 +971,8 @@ void V_DrawCroppedPatch(fixed_t x, fixed_t y, fixed_t pscale, INT32 scrn, patch_
deststop = desttop + vid.rowbytes * vid.height; deststop = desttop + vid.rowbytes * vid.height;
if (scrn & V_NOSCALESTART) { if (scrn & V_NOSCALESTART)
{
x >>= FRACBITS; x >>= FRACBITS;
y >>= FRACBITS; y >>= FRACBITS;
desttop += (y*vid.width) + x; desttop += (y*vid.width) + x;
@ -999,7 +1020,38 @@ void V_DrawCroppedPatch(fixed_t x, fixed_t y, fixed_t pscale, INT32 scrn, patch_
desttop += (y*vid.width) + x; desttop += (y*vid.width) + x;
} }
for (col = sx<<FRACBITS; (col>>FRACBITS) < patch->width && ((col>>FRACBITS) - sx) < w; col += colfrac, ++x, desttop++) // Auto-crop at splitscreen borders!
if (splitscreen && (scrn & V_PERPLAYER))
{
#ifdef QUADS
if (splitscreen > 1) // 3 or 4 players
{
#error Auto-cropping doesnt take quadscreen into account! Fix it!
// Hint: For player 1/2, copy player 1's code below. For player 3/4, copy player 2's code below
// For player 1/3 and 2/4, hijack the X wrap prevention lines? That's probably easiest
}
else
#endif
// 2 players
{
if (stplyr == &players[displayplayer]) // Player 1's screen, crop at the bottom
{
// Just put a big old stop sign halfway through the screen
deststop -= vid.rowbytes * (vid.height>>1);
}
else //if (stplyr == &players[secondarydisplayplayer]) // Player 2's screen, crop at the top
{
if (y < (vid.height>>1)) // If the top is above the border
{
sy += ((vid.height>>1) - y) * rowfrac; // Start further down on the patch
h -= ((vid.height>>1) - y) * rowfrac; // Draw less downwards from the start
desttop += ((vid.height>>1) - y) * vid.width; // Start drawing at the border
}
}
}
}
for (col = sx; (col>>FRACBITS) < patch->width && (col - sx) < w; col += colfrac, ++x, desttop++)
{ {
INT32 topdelta, prevdelta = -1; INT32 topdelta, prevdelta = -1;
if (x < 0) // don't draw off the left of the screen (WRAP PREVENTION) if (x < 0) // don't draw off the left of the screen (WRAP PREVENTION)
@ -1016,15 +1068,15 @@ void V_DrawCroppedPatch(fixed_t x, fixed_t y, fixed_t pscale, INT32 scrn, patch_
prevdelta = topdelta; prevdelta = topdelta;
source = (const UINT8 *)(column) + 3; source = (const UINT8 *)(column) + 3;
dest = desttop; dest = desttop;
if (topdelta-sy > 0) if ((topdelta<<FRACBITS)-sy > 0)
{ {
dest += FixedInt(FixedMul((topdelta-sy)<<FRACBITS,fdup))*vid.width; dest += FixedInt(FixedMul((topdelta<<FRACBITS)-sy,vdup))*vid.width;
ofs = 0; ofs = 0;
} }
else else
ofs = (sy-topdelta)<<FRACBITS; ofs = sy-(topdelta<<FRACBITS);
for (; dest < deststop && (ofs>>FRACBITS) < column->length && (((ofs>>FRACBITS) - sy) + topdelta) < h; ofs += rowfrac) for (; dest < deststop && (ofs>>FRACBITS) < column->length && ((ofs - sy) + (topdelta<<FRACBITS)) < h; ofs += rowfrac)
{ {
if (dest >= screens[scrn&V_PARAMMASK]) // don't draw off the top of the screen (CRASH PREVENTION) if (dest >= screens[scrn&V_PARAMMASK]) // don't draw off the top of the screen (CRASH PREVENTION)
*dest = patchdrawfunc(dest, source, ofs); *dest = patchdrawfunc(dest, source, ofs);

View file

@ -165,7 +165,7 @@ void V_CubeApply(UINT8 *red, UINT8 *green, UINT8 *blue);
#define V_DrawSciencePatch(x,y,s,p,sc) V_DrawFixedPatch(x,y,sc,s,p,NULL) #define V_DrawSciencePatch(x,y,s,p,sc) V_DrawFixedPatch(x,y,sc,s,p,NULL)
#define V_DrawFixedPatch(x,y,sc,s,p,c) V_DrawStretchyFixedPatch(x,y,sc,sc,s,p,c) #define V_DrawFixedPatch(x,y,sc,s,p,c) V_DrawStretchyFixedPatch(x,y,sc,sc,s,p,c)
void V_DrawStretchyFixedPatch(fixed_t x, fixed_t y, fixed_t pscale, fixed_t vscale, INT32 scrn, patch_t *patch, const UINT8 *colormap); void V_DrawStretchyFixedPatch(fixed_t x, fixed_t y, fixed_t pscale, fixed_t vscale, INT32 scrn, patch_t *patch, const UINT8 *colormap);
void V_DrawCroppedPatch(fixed_t x, fixed_t y, fixed_t pscale, INT32 scrn, patch_t *patch, fixed_t sx, fixed_t sy, fixed_t w, fixed_t h); void V_DrawCroppedPatch(fixed_t x, fixed_t y, fixed_t pscale, fixed_t vscale, INT32 scrn, patch_t *patch, const UINT8 *colormap, fixed_t sx, fixed_t sy, fixed_t w, fixed_t h);
void V_DrawContinueIcon(INT32 x, INT32 y, INT32 flags, INT32 skinnum, UINT16 skincolor); void V_DrawContinueIcon(INT32 x, INT32 y, INT32 flags, INT32 skinnum, UINT16 skincolor);

View file

@ -1,6 +1,6 @@
#define SRB2VERSION "2.2.9"/* this must be the first line, for cmake !! */ #define SRB2VERSION "2.2.9"/* this must be the first line, for cmake !! */
// The Modification ID; must be obtained from a Master Server Admin ( https://mb.srb2.org/showgroups.php ). // The Modification ID; must be obtained from a Master Server Admin ( https://mb.srb2.org/members/?key=ms_admin ).
// DO NOT try to set this otherwise, or your modification will be unplayable through the Master Server. // DO NOT try to set this otherwise, or your modification will be unplayable through the Master Server.
// "18" is the default mod ID for version 2.2 // "18" is the default mod ID for version 2.2
#define MODID 18 #define MODID 18

View file

@ -50,16 +50,17 @@
#include "filesrch.h" #include "filesrch.h"
#include "i_video.h" // rendermode #include "d_main.h"
#include "d_netfil.h" #include "d_netfil.h"
#include "dehacked.h"
#include "d_clisrv.h" #include "d_clisrv.h"
#include "dehacked.h"
#include "r_defs.h" #include "r_defs.h"
#include "r_data.h" #include "r_data.h"
#include "r_textures.h" #include "r_textures.h"
#include "r_patch.h" #include "r_patch.h"
#include "r_picformats.h" #include "r_picformats.h"
#include "i_system.h" #include "i_system.h"
#include "i_video.h" // rendermode
#include "md5.h" #include "md5.h"
#include "lua_script.h" #include "lua_script.h"
#ifdef SCANTHINGS #ifdef SCANTHINGS
@ -117,10 +118,15 @@ void W_Shutdown(void)
{ {
wadfile_t *wad = wadfiles[numwadfiles]; wadfile_t *wad = wadfiles[numwadfiles];
fclose(wad->handle); if (wad->handle)
fclose(wad->handle);
Z_Free(wad->filename); Z_Free(wad->filename);
if (wad->path)
Z_Free(wad->path);
while (wad->numlumps--) while (wad->numlumps--)
{ {
if (wad->lumpinfo[wad->numlumps].diskpath)
Z_Free(wad->lumpinfo[wad->numlumps].diskpath);
Z_Free(wad->lumpinfo[wad->numlumps].longname); Z_Free(wad->lumpinfo[wad->numlumps].longname);
Z_Free(wad->lumpinfo[wad->numlumps].fullname); Z_Free(wad->lumpinfo[wad->numlumps].fullname);
} }
@ -421,6 +427,7 @@ static lumpinfo_t* ResGetLumpsWad (FILE* handle, UINT16* nlmp, const char* filen
{ {
lump_p->position = LONG(fileinfo->filepos); lump_p->position = LONG(fileinfo->filepos);
lump_p->size = lump_p->disksize = LONG(fileinfo->size); lump_p->size = lump_p->disksize = LONG(fileinfo->size);
lump_p->diskpath = NULL;
if (compressed) // wad is compressed, lump might be if (compressed) // wad is compressed, lump might be
{ {
UINT32 realsize = 0; UINT32 realsize = 0;
@ -602,6 +609,7 @@ static lumpinfo_t* ResGetLumpsZip (FILE* handle, UINT16* nlmp)
lump_p->position = zentry.offset; // NOT ACCURATE YET: we still need to read the local entry to find our true position lump_p->position = zentry.offset; // NOT ACCURATE YET: we still need to read the local entry to find our true position
lump_p->disksize = zentry.compsize; lump_p->disksize = zentry.compsize;
lump_p->diskpath = NULL;
lump_p->size = zentry.size; lump_p->size = zentry.size;
fullname = malloc(zentry.namelen + 1); fullname = malloc(zentry.namelen + 1);
@ -679,6 +687,114 @@ static lumpinfo_t* ResGetLumpsZip (FILE* handle, UINT16* nlmp)
return lumpinfo; return lumpinfo;
} }
static INT32 CheckPathsNotEqual(const char *path1, const char *path2)
{
INT32 stat = samepaths(path1, path2);
if (stat == 1)
return 0;
else if (stat < 0)
return -1;
return 1;
}
// Returns 1 if the path is valid, 0 if not, and -1 if there was an error.
INT32 W_IsPathToFolderValid(const char *path)
{
INT32 stat;
// Remove path delimiters.
const char *p = path + (strlen(path) - 1);
while (*p == '\\' || *p == '/' || *p == ':')
{
p--;
if (p < path)
return 0;
}
// Check if the path is a directory.
stat = pathisdirectory(path);
if (stat == 0)
return 0;
else if (stat < 0)
{
// The path doesn't exist, so it can't be a directory.
if (direrror == ENOENT)
return 0;
return -1;
}
// Don't add your home, you sodding tic tac.
stat = CheckPathsNotEqual(path, srb2home);
if (stat != 1)
return stat;
// Do the same checks for SRB2's path, and the current directory.
stat = CheckPathsNotEqual(path, srb2path);
if (stat != 1)
return stat;
stat = CheckPathsNotEqual(path, ".");
if (stat != 1)
return stat;
return 1;
}
// Checks if the combination of the first path and the second path are valid.
// If they are, the concatenated path is returned.
static char *CheckConcatFolderPath(const char *startpath, const char *path)
{
if (concatpaths(path, startpath) == 1)
{
char *fn;
if (startpath)
{
size_t len = strlen(startpath) + strlen(path) + strlen(PATHSEP) + 1;
fn = ZZ_Alloc(len);
snprintf(fn, len, "%s" PATHSEP "%s", startpath, path);
}
else
fn = Z_StrDup(path);
return fn;
}
return NULL;
}
// Looks for the first valid full path for a folder.
// Returns NULL if the folder doesn't exist, or it isn't valid.
char *W_GetFullFolderPath(const char *path)
{
// Check the path by itself first.
char *fn = CheckConcatFolderPath(NULL, path);
if (fn)
return fn;
#define checkpath(startpath) \
fn = CheckConcatFolderPath(startpath, path); \
if (fn) \
return fn
checkpath(srb2home); // Then, look in srb2home.
checkpath(srb2path); // Now, look in srb2path.
checkpath("."); // Finally, look in the current directory.
#undef checkpath
return NULL;
}
// Loads files from a folder into a lumpinfo structure.
static lumpinfo_t *ResGetLumpsFolder(const char *path, UINT16 *nlmp, UINT16 *nfolders)
{
return getdirectoryfiles(path, nlmp, nfolders);
}
static UINT16 W_InitFileError (const char *filename, boolean exitworthy) static UINT16 W_InitFileError (const char *filename, boolean exitworthy)
{ {
if (exitworthy) if (exitworthy)
@ -694,6 +810,19 @@ static UINT16 W_InitFileError (const char *filename, boolean exitworthy)
return INT16_MAX; return INT16_MAX;
} }
static void W_ReadFileShaders(wadfile_t *wadfile)
{
#ifdef HWRENDER
if (rendermode == render_opengl && (vid.glstate == VID_GL_LIBRARY_LOADED))
{
HWR_LoadCustomShadersFromFile(numwadfiles - 1, W_FileHasFolders(wadfile));
HWR_CompileShaders();
}
#else
(void)wadfile;
#endif
}
// Allocate a wadfile, setup the lumpinfo (directory) and // Allocate a wadfile, setup the lumpinfo (directory) and
// lumpcache, add the wadfile to the current active wadfiles // lumpcache, add the wadfile to the current active wadfiles
// //
@ -760,7 +889,7 @@ UINT16 W_InitFile(const char *filename, boolean mainfile, boolean startup)
// see PutFileNeeded in d_netfil.c // see PutFileNeeded in d_netfil.c
if ((important = !important)) if ((important = !important))
{ {
packetsize = packetsizetally + nameonlylength(filename) + 22; packetsize = packetsizetally + nameonlylength(filename) + FILENEEDEDSIZE;
if (packetsize > MAXFILENEEDED*sizeof(UINT8)) if (packetsize > MAXFILENEEDED*sizeof(UINT8))
{ {
@ -788,7 +917,7 @@ UINT16 W_InitFile(const char *filename, boolean mainfile, boolean startup)
{ {
CONS_Alert(CONS_ERROR, M_GetText("%s is already loaded\n"), filename); CONS_Alert(CONS_ERROR, M_GetText("%s is already loaded\n"), filename);
if (important) if (important)
packetsizetally -= nameonlylength(filename) + 22; packetsizetally -= nameonlylength(filename) + FILENEEDEDSIZE;
if (handle) if (handle)
fclose(handle); fclose(handle);
return W_InitFileError(filename, false); return W_InitFileError(filename, false);
@ -831,9 +960,11 @@ UINT16 W_InitFile(const char *filename, boolean mainfile, boolean startup)
// //
wadfile = Z_Malloc(sizeof (*wadfile), PU_STATIC, NULL); wadfile = Z_Malloc(sizeof (*wadfile), PU_STATIC, NULL);
wadfile->filename = Z_StrDup(filename); wadfile->filename = Z_StrDup(filename);
wadfile->path = NULL;
wadfile->type = type; wadfile->type = type;
wadfile->handle = handle; wadfile->handle = handle;
wadfile->numlumps = (UINT16)numlumps; wadfile->numlumps = numlumps;
wadfile->foldercount = 0;
wadfile->lumpinfo = lumpinfo; wadfile->lumpinfo = lumpinfo;
wadfile->important = important; wadfile->important = important;
fseek(handle, 0, SEEK_END); fseek(handle, 0, SEEK_END);
@ -856,14 +987,8 @@ UINT16 W_InitFile(const char *filename, boolean mainfile, boolean startup)
wadfiles[numwadfiles] = wadfile; wadfiles[numwadfiles] = wadfile;
numwadfiles++; // must come BEFORE W_LoadDehackedLumps, so any addfile called by COM_BufInsertText called by Lua doesn't overwrite what we just loaded numwadfiles++; // must come BEFORE W_LoadDehackedLumps, so any addfile called by COM_BufInsertText called by Lua doesn't overwrite what we just loaded
#ifdef HWRENDER
// Read shaders from file // Read shaders from file
if (rendermode == render_opengl && (vid.glstate == VID_GL_LIBRARY_LOADED)) W_ReadFileShaders(wadfile);
{
HWR_LoadCustomShadersFromFile(numwadfiles - 1, (type == RET_PK3));
HWR_CompileShaders();
}
#endif // HWRENDER
// TODO: HACK ALERT - Load Lua & SOC stuff right here. I feel like this should be out of this place, but... Let's stick with this for now. // TODO: HACK ALERT - Load Lua & SOC stuff right here. I feel like this should be out of this place, but... Let's stick with this for now.
switch (wadfile->type) switch (wadfile->type)
@ -889,6 +1014,180 @@ UINT16 W_InitFile(const char *filename, boolean mainfile, boolean startup)
return wadfile->numlumps; return wadfile->numlumps;
} }
//
// Loads a folder as a WAD.
//
UINT16 W_InitFolder(const char *path, boolean mainfile, boolean startup)
{
lumpinfo_t *lumpinfo = NULL;
wadfile_t *wadfile;
UINT16 numlumps = 0;
UINT16 foldercount;
size_t i;
char *fn, *fullpath;
const char *p;
int important;
INT32 stat;
if (!(refreshdirmenu & REFRESHDIR_ADDFILE))
refreshdirmenu = REFRESHDIR_NORMAL|REFRESHDIR_ADDFILE; // clean out cons_alerts that happened earlier
if (refreshdirname)
Z_Free(refreshdirname);
if (dirmenu)
refreshdirname = Z_StrDup(path);
else
refreshdirname = NULL;
if (numwadfiles >= MAX_WADFILES)
{
CONS_Alert(CONS_ERROR, M_GetText("Maximum wad files reached\n"));
refreshdirmenu |= REFRESHDIR_MAX;
return W_InitFileError(path, startup);
}
important = 0; // ???
/// \todo Implement a W_VerifyFolder.
if ((important = !important))
{
size_t packetsize = packetsizetally + strlen(path) + FILENEEDEDSIZE;
if (packetsize > MAXFILENEEDED*sizeof(UINT8))
{
CONS_Alert(CONS_ERROR, M_GetText("Maximum wad files reached\n"));
refreshdirmenu |= REFRESHDIR_MAX;
return W_InitFileError(path, startup);
}
packetsizetally = packetsize;
}
// Remove path delimiters.
p = path + (strlen(path) - 1);
while (*p == '\\' || *p == '/' || *p == ':')
{
p--;
if (p < path)
{
CONS_Alert(CONS_ERROR, M_GetText("Path %s is invalid\n"), path);
return W_InitFileError(path, startup);
}
}
p++;
// Allocate the new path name.
i = (p - path) + 1;
fn = ZZ_Alloc(i);
strlcpy(fn, path, i);
// Don't add an empty path.
if (M_IsStringEmpty(fn))
{
CONS_Alert(CONS_ERROR, M_GetText("Folder name is empty\n"));
Z_Free(fn);
if (startup)
return W_InitFileError("A folder", true);
else
return W_InitFileError("a folder", false);
}
// Check if the path is valid.
stat = W_IsPathToFolderValid(fn);
if (stat != 1)
{
if (stat == 0)
CONS_Alert(CONS_ERROR, M_GetText("Path %s is invalid\n"), fn);
else if (stat < 0)
{
#ifndef AVOID_ERRNO
CONS_Alert(CONS_ERROR, M_GetText("Could not stat %s: %s\n"), fn, strerror(direrror));
#else
CONS_Alert(CONS_ERROR, M_GetText("Could not stat %s\n"), fn);
#endif
}
Z_Free(fn);
return W_InitFileError(path, startup);
}
// Get the full path for this folder.
fullpath = W_GetFullFolderPath(fn);
if (fullpath == NULL)
{
CONS_Alert(CONS_ERROR, M_GetText("Path %s is invalid\n"), fn);
Z_Free(fn);
return W_InitFileError(path, startup);
}
// Check if the folder is already added.
for (i = 0; i < numwadfiles; i++)
{
if (wadfiles[i]->type != RET_FOLDER)
continue;
if (samepaths(wadfiles[i]->path, fullpath) > 0)
{
CONS_Alert(CONS_ERROR, M_GetText("%s is already loaded\n"), path);
if (important)
packetsizetally -= strlen(path) + FILENEEDEDSIZE;
Z_Free(fn);
Z_Free(fullpath);
return W_InitFileError(path, false);
}
}
lumpinfo = ResGetLumpsFolder(fullpath, &numlumps, &foldercount);
if (lumpinfo == NULL)
{
if (!numlumps)
CONS_Alert(CONS_ERROR, M_GetText("Folder %s is empty\n"), path);
else if (numlumps == UINT16_MAX)
CONS_Alert(CONS_ERROR, M_GetText("Folder %s contains too many files\n"), path);
else
CONS_Alert(CONS_ERROR, M_GetText("Unknown error enumerating files from folder %s\n"), path);
Z_Free(fn);
Z_Free(fullpath);
return W_InitFileError(path, startup);
}
if (important && !mainfile)
G_SetGameModified(true);
wadfile = Z_Malloc(sizeof (*wadfile), PU_STATIC, NULL);
wadfile->filename = fn;
wadfile->path = fullpath;
wadfile->type = RET_FOLDER;
wadfile->handle = NULL;
wadfile->numlumps = numlumps;
wadfile->foldercount = foldercount;
wadfile->lumpinfo = lumpinfo;
wadfile->important = important;
// Irrelevant.
wadfile->filesize = 0;
memset(wadfile->md5sum, 0x00, 16);
Z_Calloc(numlumps * sizeof (*wadfile->lumpcache), PU_STATIC, &wadfile->lumpcache);
Z_Calloc(numlumps * sizeof (*wadfile->patchcache), PU_STATIC, &wadfile->patchcache);
CONS_Printf(M_GetText("Added folder %s (%u files, %u folders)\n"), fn, numlumps, foldercount);
wadfiles[numwadfiles] = wadfile;
numwadfiles++;
W_ReadFileShaders(wadfile);
W_LoadDehackedLumpsPK3(numwadfiles - 1, mainfile);
W_InvalidateLumpnumCache();
return wadfile->numlumps;
}
/** Tries to load a series of files. /** Tries to load a series of files.
* All files are wads unless they have an extension of ".soc" or ".lua". * All files are wads unless they have an extension of ".soc" or ".lua".
* *
@ -900,11 +1199,18 @@ UINT16 W_InitFile(const char *filename, boolean mainfile, boolean startup)
*/ */
void W_InitMultipleFiles(char **filenames) void W_InitMultipleFiles(char **filenames)
{ {
// will be realloced as lumps are added
for (; *filenames; filenames++) for (; *filenames; filenames++)
{ {
//CONS_Debug(DBG_SETUP, "Loading %s\n", *filenames); const char *fn = (*filenames);
W_InitFile(*filenames, numwadfiles < mainwads, true); char pathsep = fn[strlen(fn) - 1];
boolean mainfile = (numwadfiles < mainwads);
//CONS_Debug(DBG_SETUP, "Loading %s\n", fn);
if (pathsep == '\\' || pathsep == '/')
W_InitFolder(fn, mainfile, true);
else
W_InitFile(fn, mainfile, true);
} }
} }
@ -1178,7 +1484,7 @@ lumpnum_t W_CheckNumForMap(const char *name)
if (!strncmp(name, (wadfiles[i]->lumpinfo + lumpNum)->name, 8)) if (!strncmp(name, (wadfiles[i]->lumpinfo + lumpNum)->name, 8))
return (i<<16) + lumpNum; return (i<<16) + lumpNum;
} }
else if (wadfiles[i]->type == RET_PK3) else if (W_FileHasFolders(wadfiles[i]))
{ {
lumpNum = W_CheckNumForFolderStartPK3("maps/", i, 0); lumpNum = W_CheckNumForFolderStartPK3("maps/", i, 0);
if (lumpNum != INT16_MAX) if (lumpNum != INT16_MAX)
@ -1276,9 +1582,46 @@ UINT8 W_LumpExists(const char *name)
size_t W_LumpLengthPwad(UINT16 wad, UINT16 lump) size_t W_LumpLengthPwad(UINT16 wad, UINT16 lump)
{ {
lumpinfo_t *l;
if (!TestValidLump(wad, lump)) if (!TestValidLump(wad, lump))
return 0; return 0;
return wadfiles[wad]->lumpinfo[lump].size;
l = wadfiles[wad]->lumpinfo + lump;
// Open the external file for this lump, if the WAD is a folder.
if (wadfiles[wad]->type == RET_FOLDER)
{
// pathisdirectory calls stat, so if anything wrong has happened,
// this is the time to be aware of it.
INT32 stat = pathisdirectory(l->diskpath);
if (stat < 0)
{
#ifndef AVOID_ERRNO
if (direrror == ENOENT)
I_Error("W_LumpLengthPwad: file %s doesn't exist", l->diskpath);
else
I_Error("W_LumpLengthPwad: could not stat %s: %s", l->diskpath, strerror(direrror));
#else
I_Error("W_LumpLengthPwad: could not access %s", l->diskpath);
#endif
}
else if (stat == 1) // Path is a folder.
return 0;
else
{
FILE *handle = fopen(l->diskpath, "rb");
if (handle == NULL)
I_Error("W_LumpLengthPwad: could not open file %s", l->diskpath);
fseek(handle, 0, SEEK_END);
l->size = l->disksize = ftell(handle);
fclose(handle);
}
}
return l->size;
} }
/** Returns the buffer size needed to load the given lump. /** Returns the buffer size needed to load the given lump.
@ -1297,7 +1640,7 @@ size_t W_LumpLength(lumpnum_t lumpnum)
// //
boolean W_IsLumpWad(lumpnum_t lumpnum) boolean W_IsLumpWad(lumpnum_t lumpnum)
{ {
if (wadfiles[WADFILENUM(lumpnum)]->type == RET_PK3) if (W_FileHasFolders(wadfiles[WADFILENUM(lumpnum)]))
{ {
const char *lumpfullName = (wadfiles[WADFILENUM(lumpnum)]->lumpinfo + LUMPNUM(lumpnum))->fullname; const char *lumpfullName = (wadfiles[WADFILENUM(lumpnum)]->lumpinfo + LUMPNUM(lumpnum))->fullname;
@ -1315,7 +1658,7 @@ boolean W_IsLumpWad(lumpnum_t lumpnum)
// //
boolean W_IsLumpFolder(UINT16 wad, UINT16 lump) boolean W_IsLumpFolder(UINT16 wad, UINT16 lump)
{ {
if (wadfiles[wad]->type == RET_PK3) if (W_FileHasFolders(wadfiles[wad]))
{ {
const char *name = wadfiles[wad]->lumpinfo[lump].fullname; const char *name = wadfiles[wad]->lumpinfo[lump].fullname;
@ -1365,17 +1708,55 @@ void zerr(int ret)
*/ */
size_t W_ReadLumpHeaderPwad(UINT16 wad, UINT16 lump, void *dest, size_t size, size_t offset) size_t W_ReadLumpHeaderPwad(UINT16 wad, UINT16 lump, void *dest, size_t size, size_t offset)
{ {
size_t lumpsize; size_t lumpsize, bytesread;
lumpinfo_t *l; lumpinfo_t *l;
FILE *handle; FILE *handle = NULL;
if (!TestValidLump(wad,lump)) if (!TestValidLump(wad, lump))
return 0; return 0;
l = wadfiles[wad]->lumpinfo + lump;
// Open the external file for this lump, if the WAD is a folder.
if (wadfiles[wad]->type == RET_FOLDER)
{
// pathisdirectory calls stat, so if anything wrong has happened,
// this is the time to be aware of it.
INT32 stat = pathisdirectory(l->diskpath);
if (stat < 0)
{
#ifndef AVOID_ERRNO
if (direrror == ENOENT)
I_Error("W_ReadLumpHeaderPwad: file %s doesn't exist", l->diskpath);
else
I_Error("W_ReadLumpHeaderPwad: could not stat %s: %s", l->diskpath, strerror(direrror));
#else
I_Error("W_ReadLumpHeaderPwad: could not access %s", l->diskpath);
#endif
}
else if (stat == 1) // Path is a folder.
return 0;
else
{
handle = fopen(l->diskpath, "rb");
if (handle == NULL)
I_Error("W_ReadLumpHeaderPwad: could not open file %s", l->diskpath);
// Find length of file
fseek(handle, 0, SEEK_END);
l->size = l->disksize = ftell(handle);
}
}
lumpsize = wadfiles[wad]->lumpinfo[lump].size; lumpsize = wadfiles[wad]->lumpinfo[lump].size;
// empty resource (usually markers like S_START, F_END ..) // empty resource (usually markers like S_START, F_END ..)
if (!lumpsize || lumpsize<offset) if (!lumpsize || lumpsize<offset)
{
if (wadfiles[wad]->type == RET_FOLDER)
fclose(handle);
return 0; return 0;
}
// zero size means read all the lump // zero size means read all the lump
if (!size || size+offset > lumpsize) if (!size || size+offset > lumpsize)
@ -1383,24 +1764,22 @@ size_t W_ReadLumpHeaderPwad(UINT16 wad, UINT16 lump, void *dest, size_t size, si
// Let's get the raw lump data. // Let's get the raw lump data.
// We setup the desired file handle to read the lump data. // We setup the desired file handle to read the lump data.
l = wadfiles[wad]->lumpinfo + lump; if (wadfiles[wad]->type != RET_FOLDER)
handle = wadfiles[wad]->handle; handle = wadfiles[wad]->handle;
fseek(handle, (long)(l->position + offset), SEEK_SET); fseek(handle, (long)(l->position + offset), SEEK_SET);
// But let's not copy it yet. We support different compression formats on lumps, so we need to take that into account. // But let's not copy it yet. We support different compression formats on lumps, so we need to take that into account.
switch(wadfiles[wad]->lumpinfo[lump].compression) switch(wadfiles[wad]->lumpinfo[lump].compression)
{ {
case CM_NOCOMPRESSION: // If it's uncompressed, we directly write the data into our destination, and return the bytes read. case CM_NOCOMPRESSION: // If it's uncompressed, we directly write the data into our destination, and return the bytes read.
bytesread = fread(dest, 1, size, handle);
if (wadfiles[wad]->type == RET_FOLDER)
fclose(handle);
#ifdef NO_PNG_LUMPS #ifdef NO_PNG_LUMPS
{ if (Picture_IsLumpPNG((UINT8 *)dest, bytesread))
size_t bytesread = fread(dest, 1, size, handle); Picture_ThrowPNGError(l->fullname, wadfiles[wad]->filename);
if (Picture_IsLumpPNG((UINT8 *)dest, bytesread))
Picture_ThrowPNGError(l->fullname, wadfiles[wad]->filename);
return bytesread;
}
#else
return fread(dest, 1, size, handle);
#endif #endif
return bytesread;
case CM_LZF: // Is it LZF compressed? Used by ZWADs. case CM_LZF: // Is it LZF compressed? Used by ZWADs.
{ {
#ifdef ZWAD #ifdef ZWAD

View file

@ -69,6 +69,7 @@ typedef struct
char name[9]; // filelump_t name[] e.g. "LongEntr" char name[9]; // filelump_t name[] e.g. "LongEntr"
char *longname; // e.g. "LongEntryName" char *longname; // e.g. "LongEntryName"
char *fullname; // e.g. "Folder/Subfolder/LongEntryName.extension" char *fullname; // e.g. "Folder/Subfolder/LongEntryName.extension"
char *diskpath; // path to the file e.g. "/usr/games/srb2/Addon/Folder/Subfolder/LongEntryName.extension"
size_t size; // real (uncompressed) size size_t size; // real (uncompressed) size
compmethod compression; // lump compression method compmethod compression; // lump compression method
} lumpinfo_t; } lumpinfo_t;
@ -109,17 +110,19 @@ typedef enum restype
RET_SOC, RET_SOC,
RET_LUA, RET_LUA,
RET_PK3, RET_PK3,
RET_FOLDER,
RET_UNKNOWN, RET_UNKNOWN,
} restype_t; } restype_t;
typedef struct wadfile_s typedef struct wadfile_s
{ {
char *filename; char *filename, *path;
restype_t type; restype_t type;
lumpinfo_t *lumpinfo; lumpinfo_t *lumpinfo;
lumpcache_t *lumpcache; lumpcache_t *lumpcache;
lumpcache_t *patchcache; lumpcache_t *patchcache;
UINT16 numlumps; // this wad's number of resources UINT16 numlumps; // this wad's number of resources
UINT16 foldercount; // folder count
FILE *handle; FILE *handle;
UINT32 filesize; // for network UINT32 filesize; // for network
UINT8 md5sum[16]; UINT8 md5sum[16];
@ -127,7 +130,7 @@ typedef struct wadfile_s
boolean important; // also network - !W_VerifyNMUSlumps boolean important; // also network - !W_VerifyNMUSlumps
} wadfile_t; } wadfile_t;
#define WADFILENUM(lumpnum) (UINT16)((lumpnum)>>16) // wad flumpnum>>16) // wad file number in upper word #define WADFILENUM(lumpnum) (UINT16)((lumpnum)>>16) // wad file number in upper word
#define LUMPNUM(lumpnum) (UINT16)((lumpnum)&0xFFFF) // lump number for this pwad #define LUMPNUM(lumpnum) (UINT16)((lumpnum)&0xFFFF) // lump number for this pwad
extern UINT16 numwadfiles; extern UINT16 numwadfiles;
@ -141,10 +144,17 @@ void W_Shutdown(void);
FILE *W_OpenWadFile(const char **filename, boolean useerrors); FILE *W_OpenWadFile(const char **filename, boolean useerrors);
// Load and add a wadfile to the active wad files, returns numbers of lumps, INT16_MAX on error // Load and add a wadfile to the active wad files, returns numbers of lumps, INT16_MAX on error
UINT16 W_InitFile(const char *filename, boolean mainfile, boolean startup); UINT16 W_InitFile(const char *filename, boolean mainfile, boolean startup);
// Adds a folder as a file
UINT16 W_InitFolder(const char *path, boolean mainfile, boolean startup);
// W_InitMultipleFiles exits if a file was not found, but not if all is okay. // W_InitMultipleFiles exits if a file was not found, but not if all is okay.
void W_InitMultipleFiles(char **filenames); void W_InitMultipleFiles(char **filenames);
#define W_FileHasFolders(wadfile) ((wadfile)->type == RET_PK3 || (wadfile)->type == RET_FOLDER)
INT32 W_IsPathToFolderValid(const char *path);
char *W_GetFullFolderPath(const char *path);
const char *W_CheckNameForNumPwad(UINT16 wad, UINT16 lump); const char *W_CheckNameForNumPwad(UINT16 wad, UINT16 lump);
const char *W_CheckNameForNum(lumpnum_t lumpnum); const char *W_CheckNameForNum(lumpnum_t lumpnum);

View file

@ -188,11 +188,11 @@ static LRESULT CALLBACK MainWndproc(HWND hWnd, UINT message, WPARAM wParam, LPAR
ev.type = ev_keydown; ev.type = ev_keydown;
handleKeyDoom: handleKeyDoom:
ev.data1 = 0; ev.key = 0;
if (wParam == VK_PAUSE) if (wParam == VK_PAUSE)
// intercept PAUSE key // intercept PAUSE key
{ {
ev.data1 = KEY_PAUSE; ev.key = KEY_PAUSE;
} }
else if (!keyboard_started) else if (!keyboard_started)
// post some keys during the game startup // post some keys during the game startup
@ -201,14 +201,14 @@ static LRESULT CALLBACK MainWndproc(HWND hWnd, UINT message, WPARAM wParam, LPAR
{ {
switch (wParam) switch (wParam)
{ {
case VK_ESCAPE: ev.data1 = KEY_ESCAPE; break; case VK_ESCAPE: ev.key = KEY_ESCAPE; break;
case VK_RETURN: ev.data1 = KEY_ENTER; break; case VK_RETURN: ev.key = KEY_ENTER; break;
case VK_SHIFT: ev.data1 = KEY_LSHIFT; break; case VK_SHIFT: ev.key = KEY_LSHIFT; break;
default: ev.data1 = MapVirtualKey((DWORD)wParam,2); // convert in to char default: ev.key = MapVirtualKey((DWORD)wParam,2); // convert in to char
} }
} }
if (ev.data1) if (ev.key)
D_PostEvent (&ev); D_PostEvent (&ev);
return 0; return 0;
@ -240,7 +240,7 @@ static LRESULT CALLBACK MainWndproc(HWND hWnd, UINT message, WPARAM wParam, LPAR
if (nodinput) if (nodinput)
{ {
ev.type = ev_keyup; ev.type = ev_keyup;
ev.data1 = KEY_MOUSE1 + 3 + HIWORD(wParam); ev.key = KEY_MOUSE1 + 3 + HIWORD(wParam);
D_PostEvent(&ev); D_PostEvent(&ev);
return TRUE; return TRUE;
} }
@ -249,7 +249,7 @@ static LRESULT CALLBACK MainWndproc(HWND hWnd, UINT message, WPARAM wParam, LPAR
if (nodinput) if (nodinput)
{ {
ev.type = ev_keydown; ev.type = ev_keydown;
ev.data1 = KEY_MOUSE1 + 3 + HIWORD(wParam); ev.key = KEY_MOUSE1 + 3 + HIWORD(wParam);
D_PostEvent(&ev); D_PostEvent(&ev);
return TRUE; return TRUE;
} }
@ -258,9 +258,9 @@ static LRESULT CALLBACK MainWndproc(HWND hWnd, UINT message, WPARAM wParam, LPAR
//I_OutputMsg("MW_WHEEL dispatched.\n"); //I_OutputMsg("MW_WHEEL dispatched.\n");
ev.type = ev_keydown; ev.type = ev_keydown;
if ((INT16)HIWORD(wParam) > 0) if ((INT16)HIWORD(wParam) > 0)
ev.data1 = KEY_MOUSEWHEELUP; ev.key = KEY_MOUSEWHEELUP;
else else
ev.data1 = KEY_MOUSEWHEELDOWN; ev.key = KEY_MOUSEWHEELDOWN;
D_PostEvent(&ev); D_PostEvent(&ev);
break; break;
@ -271,7 +271,7 @@ static LRESULT CALLBACK MainWndproc(HWND hWnd, UINT message, WPARAM wParam, LPAR
case WM_CLOSE: case WM_CLOSE:
PostQuitMessage(0); //to quit while in-game PostQuitMessage(0); //to quit while in-game
ev.data1 = KEY_ESCAPE; //to exit network synchronization ev.key = KEY_ESCAPE; //to exit network synchronization
ev.type = ev_keydown; ev.type = ev_keydown;
D_PostEvent (&ev); D_PostEvent (&ev);
return 0; return 0;

View file

@ -322,20 +322,20 @@ static inline VOID I_GetConsoleEvents(VOID)
{ {
case VK_ESCAPE: case VK_ESCAPE:
case VK_TAB: case VK_TAB:
ev.data1 = KEY_NULL; ev.key = KEY_NULL;
break; break;
case VK_SHIFT: case VK_SHIFT:
ev.data1 = KEY_LSHIFT; ev.key = KEY_LSHIFT;
break; break;
case VK_RETURN: case VK_RETURN:
entering_con_command = false; entering_con_command = false;
/* FALLTHRU */ /* FALLTHRU */
default: default:
ev.data1 = MapVirtualKey(input.Event.KeyEvent.wVirtualKeyCode,2); // convert in to char ev.key = MapVirtualKey(input.Event.KeyEvent.wVirtualKeyCode,2); // convert in to char
} }
if (co != INVALID_HANDLE_VALUE && GetFileType(co) == FILE_TYPE_CHAR && GetConsoleMode(co, &t)) if (co != INVALID_HANDLE_VALUE && GetFileType(co) == FILE_TYPE_CHAR && GetConsoleMode(co, &t))
{ {
if (ev.data1 && ev.data1 != KEY_LSHIFT && ev.data1 != KEY_RSHIFT) if (ev.key && ev.key != KEY_LSHIFT && ev.key != KEY_RSHIFT)
{ {
#ifdef UNICODE #ifdef UNICODE
WriteConsole(co, &input.Event.KeyEvent.uChar.UnicodeChar, 1, &t, NULL); WriteConsole(co, &input.Event.KeyEvent.uChar.UnicodeChar, 1, &t, NULL);
@ -356,13 +356,13 @@ static inline VOID I_GetConsoleEvents(VOID)
switch (input.Event.KeyEvent.wVirtualKeyCode) switch (input.Event.KeyEvent.wVirtualKeyCode)
{ {
case VK_SHIFT: case VK_SHIFT:
ev.data1 = KEY_LSHIFT; ev.key = KEY_LSHIFT;
break; break;
default: default:
break; break;
} }
} }
if (ev.data1) D_PostEvent(&ev); if (ev.key) D_PostEvent(&ev);
break; break;
case MOUSE_EVENT: case MOUSE_EVENT:
case WINDOW_BUFFER_SIZE_EVENT: case WINDOW_BUFFER_SIZE_EVENT:
@ -945,7 +945,7 @@ static void I_ShutdownMouse2(VOID)
for (i = 0; i < MOUSEBUTTONS; i++) for (i = 0; i < MOUSEBUTTONS; i++)
{ {
event.type = ev_keyup; event.type = ev_keyup;
event.data1 = KEY_2MOUSE1 + i; event.key = KEY_2MOUSE1 + i;
D_PostEvent(&event); D_PostEvent(&event);
} }
@ -1135,14 +1135,14 @@ VOID I_GetSysMouseEvents(INT mouse_state)
if ((mouse_state & (1 << i)) && !(old_mouse_state & (1 << i))) if ((mouse_state & (1 << i)) && !(old_mouse_state & (1 << i)))
{ {
event.type = ev_keydown; event.type = ev_keydown;
event.data1 = KEY_MOUSE1 + i; event.key = KEY_MOUSE1 + i;
D_PostEvent(&event); D_PostEvent(&event);
} }
// check if button released // check if button released
if (!(mouse_state & (1 << i)) && (old_mouse_state & (1 << i))) if (!(mouse_state & (1 << i)) && (old_mouse_state & (1 << i)))
{ {
event.type = ev_keyup; event.type = ev_keyup;
event.data1 = KEY_MOUSE1 + i; event.key = KEY_MOUSE1 + i;
D_PostEvent(&event); D_PostEvent(&event);
} }
} }
@ -1156,9 +1156,9 @@ VOID I_GetSysMouseEvents(INT mouse_state)
if (xmickeys || ymickeys) if (xmickeys || ymickeys)
{ {
event.type = ev_mouse; event.type = ev_mouse;
event.data1 = 0; event.key = 0;
event.data2 = xmickeys; event.x = xmickeys;
event.data3 = -ymickeys; event.y = -ymickeys;
D_PostEvent(&event); D_PostEvent(&event);
SetCursorPos(center_x, center_y); SetCursorPos(center_x, center_y);
} }
@ -1240,7 +1240,7 @@ static void I_ShutdownMouse(void)
for (i = 0; i < MOUSEBUTTONS; i++) for (i = 0; i < MOUSEBUTTONS; i++)
{ {
event.type = ev_keyup; event.type = ev_keyup;
event.data1 = KEY_MOUSE1 + i; event.key = KEY_MOUSE1 + i;
D_PostEvent(&event); D_PostEvent(&event);
} }
if (nodinput) if (nodinput)
@ -1281,7 +1281,7 @@ void I_GetMouseEvents(void)
event.type = ev_keydown; event.type = ev_keydown;
else else
event.type = ev_keyup; event.type = ev_keyup;
event.data1 = KEY_2MOUSE1 + i; event.key = KEY_2MOUSE1 + i;
D_PostEvent(&event); D_PostEvent(&event);
} }
} }
@ -1289,9 +1289,9 @@ void I_GetMouseEvents(void)
if (handlermouse2x || handlermouse2y) if (handlermouse2x || handlermouse2y)
{ {
event.type = ev_mouse2; event.type = ev_mouse2;
event.data1 = 0; event.key = 0;
event.data2 = handlermouse2x<<1; event.x = handlermouse2x<<1;
event.data3 = -handlermouse2y<<1; event.y = -handlermouse2y<<1;
handlermouse2x = 0; handlermouse2x = 0;
handlermouse2y = 0; handlermouse2y = 0;
@ -1330,7 +1330,7 @@ getBufferedData:
else else
event.type = ev_keyup; // Button up event.type = ev_keyup; // Button up
event.data1 = rgdod[d].dwOfs - DIMOFS_BUTTON0 + KEY_MOUSE1; event.key = rgdod[d].dwOfs - DIMOFS_BUTTON0 + KEY_MOUSE1;
D_PostEvent(&event); D_PostEvent(&event);
} }
else if (rgdod[d].dwOfs == DIMOFS_X) else if (rgdod[d].dwOfs == DIMOFS_X)
@ -1342,9 +1342,9 @@ getBufferedData:
{ {
// z-axes the wheel // z-axes the wheel
if ((int)rgdod[d].dwData > 0) if ((int)rgdod[d].dwData > 0)
event.data1 = KEY_MOUSEWHEELUP; event.key = KEY_MOUSEWHEELUP;
else else
event.data1 = KEY_MOUSEWHEELDOWN; event.key = KEY_MOUSEWHEELDOWN;
event.type = ev_keydown; event.type = ev_keydown;
D_PostEvent(&event); D_PostEvent(&event);
} }
@ -1354,9 +1354,9 @@ getBufferedData:
if (xmickeys || ymickeys) if (xmickeys || ymickeys)
{ {
event.type = ev_mouse; event.type = ev_mouse;
event.data1 = 0; event.key = 0;
event.data2 = xmickeys; event.x = xmickeys;
event.data3 = -ymickeys; event.y = -ymickeys;
D_PostEvent(&event); D_PostEvent(&event);
} }
} }
@ -2395,14 +2395,14 @@ static VOID I_ShutdownJoystick(VOID)
// emulate the up of all joystick buttons // emulate the up of all joystick buttons
for (i = 0;i < JOYBUTTONS;i++) for (i = 0;i < JOYBUTTONS;i++)
{ {
event.data1 = KEY_JOY1+i; event.key = KEY_JOY1+i;
D_PostEvent(&event); D_PostEvent(&event);
} }
// emulate the up of all joystick hats // emulate the up of all joystick hats
for (i = 0;i < JOYHATS*4;i++) for (i = 0;i < JOYHATS*4;i++)
{ {
event.data1 = KEY_HAT1+i; event.key = KEY_HAT1+i;
D_PostEvent(&event); D_PostEvent(&event);
} }
@ -2410,7 +2410,7 @@ static VOID I_ShutdownJoystick(VOID)
event.type = ev_joystick; event.type = ev_joystick;
for (i = 0;i < JOYAXISSET; i++) for (i = 0;i < JOYAXISSET; i++)
{ {
event.data1 = i; event.key = i;
D_PostEvent(&event); D_PostEvent(&event);
} }
@ -2460,14 +2460,14 @@ static VOID I_ShutdownJoystick2(VOID)
// emulate the up of all joystick buttons // emulate the up of all joystick buttons
for (i = 0;i < JOYBUTTONS;i++) for (i = 0;i < JOYBUTTONS;i++)
{ {
event.data1 = KEY_2JOY1+i; event.key = KEY_2JOY1+i;
D_PostEvent(&event); D_PostEvent(&event);
} }
// emulate the up of all joystick hats // emulate the up of all joystick hats
for (i = 0;i < JOYHATS*4;i++) for (i = 0;i < JOYHATS*4;i++)
{ {
event.data1 = KEY_2HAT1+i; event.key = KEY_2HAT1+i;
D_PostEvent(&event); D_PostEvent(&event);
} }
@ -2475,7 +2475,7 @@ static VOID I_ShutdownJoystick2(VOID)
event.type = ev_joystick2; event.type = ev_joystick2;
for (i = 0;i < JOYAXISSET; i++) for (i = 0;i < JOYAXISSET; i++)
{ {
event.data1 = i; event.key = i;
D_PostEvent(&event); D_PostEvent(&event);
} }
@ -2598,7 +2598,7 @@ acquire:
event.type = ev_keydown; event.type = ev_keydown;
else else
event.type = ev_keyup; event.type = ev_keyup;
event.data1 = KEY_JOY1 + i; event.key = KEY_JOY1 + i;
D_PostEvent(&event); D_PostEvent(&event);
} }
} }
@ -2618,7 +2618,7 @@ acquire:
event.type = ev_keydown; event.type = ev_keydown;
else else
event.type = ev_keyup; event.type = ev_keyup;
event.data1 = KEY_HAT1 + i; event.key = KEY_HAT1 + i;
D_PostEvent(&event); D_PostEvent(&event);
} }
} }
@ -2627,7 +2627,7 @@ acquire:
// send joystick axis positions // send joystick axis positions
event.type = ev_joystick; event.type = ev_joystick;
event.data1 = event.data2 = event.data3 = 0; event.key = event.x = event.y = 0;
if (Joystick.bGamepadStyle) if (Joystick.bGamepadStyle)
{ {
@ -2635,29 +2635,29 @@ acquire:
if (JoyInfo.X) if (JoyInfo.X)
{ {
if (js.lX < -(JOYAXISRANGE/2)) if (js.lX < -(JOYAXISRANGE/2))
event.data2 = -1; event.x = -1;
else if (js.lX > JOYAXISRANGE/2) else if (js.lX > JOYAXISRANGE/2)
event.data2 = 1; event.x = 1;
} }
if (JoyInfo.Y) if (JoyInfo.Y)
{ {
if (js.lY < -(JOYAXISRANGE/2)) if (js.lY < -(JOYAXISRANGE/2))
event.data3 = -1; event.y = -1;
else if (js.lY > JOYAXISRANGE/2) else if (js.lY > JOYAXISRANGE/2)
event.data3 = 1; event.y = 1;
} }
} }
else else
{ {
// analog control style, just send the raw data // analog control style, just send the raw data
if (JoyInfo.X) event.data2 = js.lX; // x axis if (JoyInfo.X) event.x = js.lX; // x axis
if (JoyInfo.Y) event.data3 = js.lY; // y axis if (JoyInfo.Y) event.y = js.lY; // y axis
} }
D_PostEvent(&event); D_PostEvent(&event);
#if JOYAXISSET > 1 #if JOYAXISSET > 1
event.data1 = 1; event.key = 1;
event.data2 = event.data3 = 0; event.x = event.y = 0;
if (Joystick.bGamepadStyle) if (Joystick.bGamepadStyle)
{ {
@ -2665,30 +2665,30 @@ acquire:
if (JoyInfo.Z) if (JoyInfo.Z)
{ {
if (js.lZ < -(JOYAXISRANGE/2)) if (js.lZ < -(JOYAXISRANGE/2))
event.data2 = -1; event.x = -1;
else if (js.lZ > JOYAXISRANGE/2) else if (js.lZ > JOYAXISRANGE/2)
event.data2 = 1; event.x = 1;
} }
if (JoyInfo.Rx) if (JoyInfo.Rx)
{ {
if (js.lRx < -(JOYAXISRANGE/2)) if (js.lRx < -(JOYAXISRANGE/2))
event.data3 = -1; event.y = -1;
else if (js.lRx > JOYAXISRANGE/2) else if (js.lRx > JOYAXISRANGE/2)
event.data3 = 1; event.y = 1;
} }
} }
else else
{ {
// analog control style, just send the raw data // analog control style, just send the raw data
if (JoyInfo.Z) event.data2 = js.lZ; // z axis if (JoyInfo.Z) event.x = js.lZ; // z axis
if (JoyInfo.Rx) event.data3 = js.lRx; // rx axis if (JoyInfo.Rx) event.y = js.lRx; // rx axis
} }
D_PostEvent(&event); D_PostEvent(&event);
#endif #endif
#if JOYAXISSET > 2 #if JOYAXISSET > 2
event.data1 = 2; event.key = 2;
event.data2 = event.data3 = 0; event.x = event.y = 0;
if (Joystick.bGamepadStyle) if (Joystick.bGamepadStyle)
{ {
@ -2696,53 +2696,53 @@ acquire:
if (JoyInfo.Rx) if (JoyInfo.Rx)
{ {
if (js.lRy < -(JOYAXISRANGE/2)) if (js.lRy < -(JOYAXISRANGE/2))
event.data2 = -1; event.x = -1;
else if (js.lRy > JOYAXISRANGE/2) else if (js.lRy > JOYAXISRANGE/2)
event.data2 = 1; event.x = 1;
} }
if (JoyInfo.Rz) if (JoyInfo.Rz)
{ {
if (js.lRz < -(JOYAXISRANGE/2)) if (js.lRz < -(JOYAXISRANGE/2))
event.data3 = -1; event.y = -1;
else if (js.lRz > JOYAXISRANGE/2) else if (js.lRz > JOYAXISRANGE/2)
event.data3 = 1; event.y = 1;
} }
} }
else else
{ {
// analog control style, just send the raw data // analog control style, just send the raw data
if (JoyInfo.Ry) event.data2 = js.lRy; // ry axis if (JoyInfo.Ry) event.x = js.lRy; // ry axis
if (JoyInfo.Rz) event.data3 = js.lRz; // rz axis if (JoyInfo.Rz) event.y = js.lRz; // rz axis
} }
D_PostEvent(&event); D_PostEvent(&event);
#endif #endif
#if JOYAXISSET > 3 #if JOYAXISSET > 3
event.data1 = 3; event.key = 3;
event.data2 = event.data3 = 0; event.x = event.y = 0;
if (Joystick.bGamepadStyle) if (Joystick.bGamepadStyle)
{ {
// gamepad control type, on or off, live or die // gamepad control type, on or off, live or die
if (JoyInfo.U) if (JoyInfo.U)
{ {
if (js.rglSlider[0] < -(JOYAXISRANGE/2)) if (js.rglSlider[0] < -(JOYAXISRANGE/2))
event.data2 = -1; event.x = -1;
else if (js.rglSlider[0] > JOYAXISRANGE/2) else if (js.rglSlider[0] > JOYAXISRANGE/2)
event.data2 = 1; event.x = 1;
} }
if (JoyInfo.V) if (JoyInfo.V)
{ {
if (js.rglSlider[1] < -(JOYAXISRANGE/2)) if (js.rglSlider[1] < -(JOYAXISRANGE/2))
event.data3 = -1; event.y = -1;
else if (js.rglSlider[1] > JOYAXISRANGE/2) else if (js.rglSlider[1] > JOYAXISRANGE/2)
event.data3 = 1; event.y = 1;
} }
} }
else else
{ {
// analog control style, just send the raw data // analog control style, just send the raw data
if (JoyInfo.U) event.data2 = js.rglSlider[0]; // U axis if (JoyInfo.U) event.x = js.rglSlider[0]; // U axis
if (JoyInfo.V) event.data3 = js.rglSlider[1]; // V axis if (JoyInfo.V) event.y = js.rglSlider[1]; // V axis
} }
D_PostEvent(&event); D_PostEvent(&event);
#endif #endif
@ -2842,7 +2842,7 @@ acquire:
event.type = ev_keydown; event.type = ev_keydown;
else else
event.type = ev_keyup; event.type = ev_keyup;
event.data1 = KEY_2JOY1 + i; event.key = KEY_2JOY1 + i;
D_PostEvent(&event); D_PostEvent(&event);
} }
} }
@ -2862,7 +2862,7 @@ acquire:
event.type = ev_keydown; event.type = ev_keydown;
else else
event.type = ev_keyup; event.type = ev_keyup;
event.data1 = KEY_2HAT1 + i; event.key = KEY_2HAT1 + i;
D_PostEvent(&event); D_PostEvent(&event);
} }
} }
@ -2871,7 +2871,7 @@ acquire:
// send joystick axis positions // send joystick axis positions
event.type = ev_joystick2; event.type = ev_joystick2;
event.data1 = event.data2 = event.data3 = 0; event.key = event.x = event.y = 0;
if (Joystick2.bGamepadStyle) if (Joystick2.bGamepadStyle)
{ {
@ -2879,29 +2879,29 @@ acquire:
if (JoyInfo2.X) if (JoyInfo2.X)
{ {
if (js.lX < -(JOYAXISRANGE/2)) if (js.lX < -(JOYAXISRANGE/2))
event.data2 = -1; event.x = -1;
else if (js.lX > JOYAXISRANGE/2) else if (js.lX > JOYAXISRANGE/2)
event.data2 = 1; event.x = 1;
} }
if (JoyInfo2.Y) if (JoyInfo2.Y)
{ {
if (js.lY < -(JOYAXISRANGE/2)) if (js.lY < -(JOYAXISRANGE/2))
event.data3 = -1; event.y = -1;
else if (js.lY > JOYAXISRANGE/2) else if (js.lY > JOYAXISRANGE/2)
event.data3 = 1; event.y = 1;
} }
} }
else else
{ {
// analog control style, just send the raw data // analog control style, just send the raw data
if (JoyInfo2.X) event.data2 = js.lX; // x axis if (JoyInfo2.X) event.x = js.lX; // x axis
if (JoyInfo2.Y) event.data3 = js.lY; // y axis if (JoyInfo2.Y) event.y = js.lY; // y axis
} }
D_PostEvent(&event); D_PostEvent(&event);
#if JOYAXISSET > 1 #if JOYAXISSET > 1
event.data1 = 1; event.key = 1;
event.data2 = event.data3 = 0; event.x = event.y = 0;
if (Joystick2.bGamepadStyle) if (Joystick2.bGamepadStyle)
{ {
@ -2909,30 +2909,30 @@ acquire:
if (JoyInfo2.Z) if (JoyInfo2.Z)
{ {
if (js.lZ < -(JOYAXISRANGE/2)) if (js.lZ < -(JOYAXISRANGE/2))
event.data2 = -1; event.x = -1;
else if (js.lZ > JOYAXISRANGE/2) else if (js.lZ > JOYAXISRANGE/2)
event.data2 = 1; event.x = 1;
} }
if (JoyInfo2.Rx) if (JoyInfo2.Rx)
{ {
if (js.lRx < -(JOYAXISRANGE/2)) if (js.lRx < -(JOYAXISRANGE/2))
event.data3 = -1; event.y = -1;
else if (js.lRx > JOYAXISRANGE/2) else if (js.lRx > JOYAXISRANGE/2)
event.data3 = 1; event.y = 1;
} }
} }
else else
{ {
// analog control style, just send the raw data // analog control style, just send the raw data
if (JoyInfo2.Z) event.data2 = js.lZ; // z axis if (JoyInfo2.Z) event.x = js.lZ; // z axis
if (JoyInfo2.Rx) event.data3 = js.lRx; // rx axis if (JoyInfo2.Rx) event.y = js.lRx; // rx axis
} }
D_PostEvent(&event); D_PostEvent(&event);
#endif #endif
#if JOYAXISSET > 2 #if JOYAXISSET > 2
event.data1 = 2; event.key = 2;
event.data2 = event.data3 = 0; event.x = event.y = 0;
if (Joystick2.bGamepadStyle) if (Joystick2.bGamepadStyle)
{ {
@ -2940,53 +2940,53 @@ acquire:
if (JoyInfo2.Rx) if (JoyInfo2.Rx)
{ {
if (js.lRy < -(JOYAXISRANGE/2)) if (js.lRy < -(JOYAXISRANGE/2))
event.data2 = -1; event.x = -1;
else if (js.lRy > JOYAXISRANGE/2) else if (js.lRy > JOYAXISRANGE/2)
event.data2 = 1; event.x = 1;
} }
if (JoyInfo2.Rz) if (JoyInfo2.Rz)
{ {
if (js.lRz < -(JOYAXISRANGE/2)) if (js.lRz < -(JOYAXISRANGE/2))
event.data3 = -1; event.y = -1;
else if (js.lRz > JOYAXISRANGE/2) else if (js.lRz > JOYAXISRANGE/2)
event.data3 = 1; event.y = 1;
} }
} }
else else
{ {
// analog control style, just send the raw data // analog control style, just send the raw data
if (JoyInfo2.Ry) event.data2 = js.lRy; // ry axis if (JoyInfo2.Ry) event.x = js.lRy; // ry axis
if (JoyInfo2.Rz) event.data3 = js.lRz; // rz axis if (JoyInfo2.Rz) event.y = js.lRz; // rz axis
} }
D_PostEvent(&event); D_PostEvent(&event);
#endif #endif
#if JOYAXISSET > 3 #if JOYAXISSET > 3
event.data1 = 3; event.key = 3;
event.data2 = event.data3 = 0; event.x = event.y = 0;
if (Joystick2.bGamepadStyle) if (Joystick2.bGamepadStyle)
{ {
// gamepad control type, on or off, live or die // gamepad control type, on or off, live or die
if (JoyInfo2.U) if (JoyInfo2.U)
{ {
if (js.rglSlider[0] < -(JOYAXISRANGE/2)) if (js.rglSlider[0] < -(JOYAXISRANGE/2))
event.data2 = -1; event.x = -1;
else if (js.rglSlider[0] > JOYAXISRANGE/2) else if (js.rglSlider[0] > JOYAXISRANGE/2)
event.data2 = 1; event.x = 1;
} }
if (JoyInfo2.V) if (JoyInfo2.V)
{ {
if (js.rglSlider[1] < -(JOYAXISRANGE/2)) if (js.rglSlider[1] < -(JOYAXISRANGE/2))
event.data3 = -1; event.y = -1;
else if (js.rglSlider[1] > JOYAXISRANGE/2) else if (js.rglSlider[1] > JOYAXISRANGE/2)
event.data3 = 1; event.y = 1;
} }
} }
else else
{ {
// analog control style, just send the raw data // analog control style, just send the raw data
if (JoyInfo2.U) event.data2 = js.rglSlider[0]; // U axis if (JoyInfo2.U) event.x = js.rglSlider[0]; // U axis
if (JoyInfo2.V) event.data3 = js.rglSlider[1]; // V axis if (JoyInfo2.V) event.y = js.rglSlider[1]; // V axis
} }
D_PostEvent(&event); D_PostEvent(&event);
#endif #endif
@ -3194,7 +3194,7 @@ INT32 I_GetKey(void)
ev = &events[eventtail]; ev = &events[eventtail];
eventtail = (eventtail+1) & (MAXEVENTS-1); eventtail = (eventtail+1) & (MAXEVENTS-1);
if (ev->type == ev_keydown || ev->type == ev_console) if (ev->type == ev_keydown || ev->type == ev_console)
return ev->data1; return ev->key;
else else
return 0; return 0;
} }
@ -3308,7 +3308,7 @@ static VOID I_GetKeyboardEvents(VOID)
if (!appActive && RepeatKeyCode) // Stop when lost focus if (!appActive && RepeatKeyCode) // Stop when lost focus
{ {
event.type = ev_keyup; event.type = ev_keyup;
event.data1 = RepeatKeyCode; event.key = RepeatKeyCode;
D_PostEvent(&event); D_PostEvent(&event);
RepeatKeyCode = 0; RepeatKeyCode = 0;
} }
@ -3363,9 +3363,9 @@ getBufferedData:
ch = rgdod[d].dwOfs & 0xFF; ch = rgdod[d].dwOfs & 0xFF;
if (ASCIINames[ch]) if (ASCIINames[ch])
event.data1 = ASCIINames[ch]; event.key = ASCIINames[ch];
else else
event.data1 = 0x80; event.key = 0x80;
D_PostEvent(&event); D_PostEvent(&event);
} }
@ -3378,7 +3378,7 @@ getBufferedData:
// delay is tripled for first repeating key // delay is tripled for first repeating key
RepeatKeyTics = hacktics + (KEY_REPEAT_DELAY*3); RepeatKeyTics = hacktics + (KEY_REPEAT_DELAY*3);
if (event.type == ev_keydown) // use the last event! if (event.type == ev_keydown) // use the last event!
RepeatKeyCode = event.data1; RepeatKeyCode = event.key;
} }
else else
{ {
@ -3386,7 +3386,7 @@ getBufferedData:
if (RepeatKeyCode && hacktics - RepeatKeyTics > KEY_REPEAT_DELAY) if (RepeatKeyCode && hacktics - RepeatKeyTics > KEY_REPEAT_DELAY)
{ {
event.type = ev_keydown; event.type = ev_keydown;
event.data1 = RepeatKeyCode; event.key = RepeatKeyCode;
D_PostEvent(&event); D_PostEvent(&event);
RepeatKeyTics = hacktics; RepeatKeyTics = hacktics;

View file

@ -212,7 +212,7 @@ static void Y_IntermissionTokenDrawer(void)
calc = (lowy - y)*2; calc = (lowy - y)*2;
if (calc > 0) if (calc > 0)
V_DrawCroppedPatch(32<<FRACBITS, y<<FRACBITS, FRACUNIT/2, 0, tokenicon, 0, 0, tokenicon->width, calc); V_DrawCroppedPatch(32<<FRACBITS, y<<FRACBITS, FRACUNIT/2, FRACUNIT/2, 0, tokenicon, NULL, 0, 0, tokenicon->width<<FRACBITS, calc<<FRACBITS);
} }
@ -430,7 +430,7 @@ void Y_IntermissionDrawer(void)
else if (bgtile) else if (bgtile)
V_DrawPatchFill(bgtile); V_DrawPatchFill(bgtile);
LUAh_IntermissionHUD(intertype == int_spec && stagefailed); LUA_HUDHOOK(intermission);
if (!LUA_HudEnabled(hud_intermissiontally)) if (!LUA_HudEnabled(hud_intermissiontally))
goto skiptallydrawer; goto skiptallydrawer;