Merge branch 'next' into udmf-fofs-mkii

# Conflicts:
#	src/p_user.c
This commit is contained in:
MascaraSnake 2021-12-03 18:58:02 +01:00
commit adce427299
101 changed files with 5628 additions and 3025 deletions

View file

@ -2,15 +2,11 @@ version: 2.2.9.{branch}-{build}
os: MinGW
environment:
CC: ccache
CCACHE_CC: i686-w64-mingw32-gcc
CCACHE_CC_64: x86_64-w64-mingw32-gcc
CC: i686-w64-mingw32-gcc
WINDRES: windres
# c:\mingw-w64 i686 has gcc 6.3.0, so use c:\msys64 7.3.0 instead
MINGW_SDK: c:\msys64\mingw32
# c:\msys64 x86_64 has gcc 8.2.0, so use c:\mingw-w64 7.3.0 instead
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
CFLAGS: -Wno-implicit-fallthrough
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
UPX_ZIP: upx391w
@ -19,8 +15,6 @@ environment:
CCACHE_URL: http://alam.srb2.org/ccache.exe
CCACHE_COMPRESS: true
CCACHE_DIR: C:\Users\appveyor\.ccache
# Disable UPX by default. The user can override this in their Appveyor project settings
NOUPX: 1
##############################
# DEPLOYER VARIABLES
# DPL_ENABLED=1 builds installers for branch names starting with `deployer`.
@ -53,11 +47,6 @@ cache:
- C:\Users\appveyor\srb2_cache
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"
- 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
@ -72,34 +61,27 @@ install:
configuration:
- SDL
- SDL64
before_build:
- 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
- if not [%X86_64%] == [1] ( nasm -v )
- nasm -v
- if not [%NOUPX%] == [1] ( upx -V )
- ccache -V
- 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%" )
- cmd: git rev-parse --short %COMMIT%>%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
- 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%" ) )
- set "EXENAME=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"
- set "SRB2_MFLAGS=-C src NOECHOFILENAMES=1 CCACHE=1 EXENAME=srb2win-%REPO%-%GITSHORT%.exe"
build_script:
- cmd: mingw32-make.exe %SRB2_MFLAGS% clean
- cmd: mingw32-make.exe %SRB2_MFLAGS% ERRORMODE=1 -k
after_build:
- if [%X86_64%] == [1] ( set "CONFIGURATION=%CONFIGURATION%64" )
- ccache -s
- set BUILD_ARCHIVE=%REPO%-%GITSHORT%-%CONFIGURATION%.7z
- set BUILDSARCHIVE=%REPO%-%CONFIGURATION%.7z
@ -134,3 +116,4 @@ test: off
on_finish:
#- 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'))
# vim: et ts=1

View file

@ -78,7 +78,7 @@ NONX86 = $(shell test "`echo $(CROSS_COMPILE_HOST) | grep 'i[3-6]86'`" || echo "
MAKEARGS = $(OS) $(NONX86) $(PREFIX) EXENAME=$(EXENAME) DBGNAME=$(DBGNAME) NOOBJDUMP=1 # SDL_PKGCONFIG=sdl2 PNG_PKGCONFIG=libpng
MENUFILE1 = ?package($(PACKAGE)):needs="X11" section="$(SECTION)"
MENUFILE2 = title="$(TITLE)" command="/$(PKGDIR)/$(PACKAGE)"
BINDIR := $(DIR)/bin/Linux/Release
BINDIR := $(DIR)/bin/
# FIXME pkg-config dir hacks
# Launchpad doesn't need this; it actually makes i386 builds fail due to cross-compile

View file

@ -1998,7 +1998,7 @@ linedeftypes
title = "Set Tagged Sector's Floor Height/Texture";
prefix = "(400)";
flags8text = "[3] Set delay by backside sector";
flags64text = "[6] Keep floor flat";
flags64text = "[6] Don't change floor texture";
}
401
@ -2006,6 +2006,7 @@ linedeftypes
title = "Set Tagged Sector's Ceiling Height/Texture";
prefix = "(401)";
flags8text = "[3] Set delay by backside sector";
flags64text = "[6] Don't change ceiling texture";
}
402
@ -2096,7 +2097,7 @@ linedeftypes
prefix = "(403)";
flags2text = "[1] Trigger linedef executor";
flags8text = "[3] Set delay by backside sector";
flags64text = "[6] Change floor flat";
flags64text = "[6] Change floor texture";
}
404
@ -2105,7 +2106,7 @@ linedeftypes
prefix = "(404)";
flags2text = "[1] Trigger linedef executor";
flags8text = "[3] Set delay by backside sector";
flags64text = "[6] Change ceiling flat";
flags64text = "[6] Change ceiling texture";
}
405
@ -2956,8 +2957,10 @@ linedeftypes
prefix = "(700)";
flags2048text = "[11] No physics";
flags4096text = "[12] Dynamic";
flags32768text = "[15] Copy to other side";
slope = "regular";
slopeargs = 1;
copyslopeargs = 1;
}
701
@ -2966,8 +2969,10 @@ linedeftypes
prefix = "(701)";
flags2048text = "[11] No physics";
flags4096text = "[12] Dynamic";
flags32768text = "[15] Copy to other side";
slope = "regular";
slopeargs = 2;
copyslopeargs = 4;
}
702
@ -2976,8 +2981,10 @@ linedeftypes
prefix = "(702)";
flags2048text = "[11] No physics";
flags4096text = "[12] Dynamic";
flags32768text = "[15] Copy to other side";
slope = "regular";
slopeargs = 3;
copyslopeargs = 5;
}
703
@ -2986,8 +2993,10 @@ linedeftypes
prefix = "(703)";
flags2048text = "[11] No physics";
flags4096text = "[12] Dynamic";
flags32768text = "[15] Copy to other side";
slope = "regular";
slopeargs = 9;
copyslopeargs = 8;
}
704
@ -3018,8 +3027,10 @@ linedeftypes
prefix = "(710)";
flags2048text = "[11] No physics";
flags4096text = "[12] Dynamic";
flags32768text = "[15] Copy to other side";
slope = "regular";
slopeargs = 4;
copyslopeargs = 2;
}
711
@ -3028,8 +3039,10 @@ linedeftypes
prefix = "(711)";
flags2048text = "[11] No physics";
flags4096text = "[12] Dynamic";
flags32768text = "[15] Copy to other side";
slope = "regular";
slopeargs = 8;
copyslopeargs = 8;
}
712
@ -3038,8 +3051,10 @@ linedeftypes
prefix = "(712)";
flags2048text = "[11] No physics";
flags4096text = "[12] Dynamic";
flags32768text = "[15] Copy to other side";
slope = "regular";
slopeargs = 12;
copyslopeargs = 10;
}
713
@ -3048,8 +3063,10 @@ linedeftypes
prefix = "(713)";
flags2048text = "[11] No physics";
flags4096text = "[12] Dynamic";
flags32768text = "[15] Copy to other side";
slope = "regular";
slopeargs = 6;
copyslopeargs = 6;
}
714

View file

@ -4,7 +4,7 @@ add_executable(SRB2SDL2 MACOSX_BUNDLE WIN32)
# Core sources
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)
@ -60,7 +60,7 @@ if(${SRB2_CONFIG_HAVE_GME})
endif()
if(${GME_FOUND})
set(SRB2_HAVE_GME ON)
target_compile_definitions(SRB2SDL2 PRIVATE -DHAVE_LIBGME)
target_compile_definitions(SRB2SDL2 PRIVATE -DHAVE_GME)
else()
message(WARNING "You have specified that GME is available but it was not found.")
endif()

View file

@ -295,6 +295,8 @@ ifndef destructive
$(shell $(CC) -v)
define flags =
SHELL ..... $(SHELL)
CC ........ $(cc)
CFLAGS .... $(opts)
@ -374,7 +376,7 @@ ifdef Echo_name
@printf '%-20.20s\r' $$<
endif
endif
$(.)$(cc) -MM -MF $$@ -MT $(objdir)/$$(*F).o $(2) $$<
$(.)$(cc) -MM -MF $$@ -MT $(objdir)/$$*.o $(2) $$<
endef
$(eval $(call _recipe,c))
@ -404,7 +406,7 @@ clean :
$(call _rm,$(exe) $(dbg) $(dbg).txt $(objects))
distclean :
$(call _rm,../bin ../objs ../deps ../make comptime.h)
$(call _rm,../bin ../objs ../dep ../make comptime.h)
info:
ifdef WINDOWSHELL

View file

@ -29,10 +29,6 @@ $(call Print,$(_m))
# go for a 32-bit sdl mingw exe by default
MINGW:=1
# cmd.exe uses native Windows semicolon delimited PATH
ifneq (,$(findstring ;,$(PATH)))
WINDOWSHELL:=1
endif
else # if you on the *nix
@ -75,13 +71,17 @@ latest_gcc_version:=10.2
# manually set. And don't bother if this is a clean only
# run.
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
ifneq (,$(or $(findstring gcc,$(version)),\
$(findstring GCC,$(version))))
ifneq (,$(findstring gcc version,$(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
v:=$(subst ., ,$(version))

View file

@ -3,7 +3,7 @@
#
_old:=$(wildcard $(addprefix ../bin/,FreeBSD Linux \
Linux64 Mingw Mingw64 SDL dummy) ../objs ../deps)
Linux64 Mingw Mingw64 SDL dummy) ../objs ../dep)
ifdef _old
$(foreach v,$(_old),$(info $(abspath $(v))))

View file

@ -35,8 +35,6 @@ ifndef GCC295
WFLAGS+=-Wendif-labels
endif
ifdef GCC41
WFLAGS+=-Wdeclaration-after-statement
WFLAGS+=-Wno-error=declaration-after-statement
WFLAGS+=-Wshadow
endif
#WFLAGS+=-Wlarger-than-%len%

View file

@ -8,6 +8,11 @@ else
EXENAME?=srb2win64.exe
endif
# disable dynamicbase if under msys2
ifdef MSYSTEM
libs+=-Wl,--disable-dynamicbase
endif
sources+=win32/Srb2win.rc
opts+=-DSTDC_HEADERS
libs+=-ladvapi32 -lkernel32 -lmsvcrt -luser32

View file

@ -458,7 +458,7 @@ boolean AM_Responder(event_t *ev)
{
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
// 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)
{
rc = true;
switch (ev->data1)
switch (ev->key)
{
case AM_PANRIGHTKEY: // pan right
if (!followplayer)
@ -550,7 +550,7 @@ boolean AM_Responder(event_t *ev)
else if (ev->type == ev_keyup)
{
rc = false;
switch (ev->data1)
switch (ev->key)
{
case AM_PANRIGHTKEY:
if (!followplayer)

View file

@ -18,29 +18,38 @@
#include "b_bot.h"
#include "lua_hook.h"
// If you want multiple bots, variables like this will
// 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)
void B_UpdateBotleader(player_t *player)
{
jump_last = false;
spin_last = false;
anxiety = 0;
panic = false;
flymode = 0;
spinmode = false;
thinkfly = false;
UINT32 i;
fixed_t dist;
fixed_t neardist = INT32_MAX;
player_t *nearplayer = NULL;
//Find new botleader
for (i = 0; i < MAXPLAYERS; i++)
{
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)
@ -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;
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);
boolean _2d = (tails->flags2 & MF2_TWOD) || twodlevel;
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 zdist = flip * (sonic->z - tails->z);
angle_t ang = sonic->angle;
fixed_t pmom = P_AproxDistance(sonic->momx, sonic->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 followmin = 32 * scale;
fixed_t comfortheight = 96 * 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 samepos = (sonic->x == tails->x && sonic->y == tails->y);
boolean blocked = bot->blocked;
if (!samepos)
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!
if (LUA_HookBotAI(sonic, tails, cmd))
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)
{
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)
cmd->buttons |= BT_JUMP;
if (isrelevant)
@ -103,56 +120,57 @@ static void B_BuildTailsTiccmd(mobj_t *sonic, mobj_t *tails, ticcmd_t *cmd)
followmin = 0;
followthres = 16*scale;
followmax >>= 1;
thinkfly = false;
if (mem->thinkstate == AI_THINKFLY)
mem->thinkstate = AI_FOLLOW;
}
// Check anxiety
if (spinmode)
// Update catchup_tics
if (mem->thinkstate == AI_SPINFOLLOW)
{
anxiety = 0;
panic = false;
mem-> catchup_tics = 0;
}
else if (dist > followmax || zdist > comfortheight || stalled)
{
anxiety = min(anxiety + 2, 70);
if (anxiety >= 70)
panic = true;
mem-> catchup_tics = min(mem-> catchup_tics + 2, 70);
if (mem-> catchup_tics >= 70)
mem->thinkstate = AI_CATCHUP;
}
else
{
anxiety = max(anxiety - 1, 0);
panic = false;
mem-> catchup_tics = max(mem-> catchup_tics - 1, 0);
if (mem->thinkstate == AI_CATCHUP)
mem->thinkstate = AI_FOLLOW;
}
// 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))
{
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
{
cmd->angleturn = (ang - tails->angle) >> 16; // NOT FRACBITS DAMNIT
cmd->angleturn = (ang) >> 16; // NOT FRACBITS DAMNIT
}
// ********
// FLY MODE
// spinmode check
if (spinmode || player->exiting)
thinkfly = false;
// exiting check
if (player->exiting && mem->thinkstate == AI_THINKFLY)
mem->thinkstate = AI_FOLLOW;
else
{
// Activate co-op flight
if (thinkfly && player->pflags & PF_JUMPED)
if (mem->thinkstate == AI_THINKFLY && player->pflags & PF_JUMPED)
{
if (!jump_last)
{
jump = true;
flymode = 1;
thinkfly = false;
mem->thinkstate = AI_FLYSTANDBY;
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)
&& !(player->pflags & PF_STASIS)
&& bot->charability == CA_FLY)
thinkfly = true;
else
thinkfly = false;
mem->thinkstate = AI_THINKFLY;
else if (mem->thinkstate == AI_THINKFLY)
mem->thinkstate = AI_FOLLOW;
// Set carried state
if (player->powers[pw_carry] == CR_PLAYER && sonic->tracer == tails)
{
flymode = 2;
mem->thinkstate = AI_FLYCARRY;
}
// 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
spin = true;
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
if (dist > followthres || player->dashspeed)
flymode = 0;
mem->thinkstate = AI_FOLLOW;
}
// Read player inputs while carrying
else if (flymode == 2)
else if (mem->thinkstate == AI_FLYCARRY)
{
cmd->forwardmove = pcmd->forwardmove;
cmd->sidemove = pcmd->sidemove;
@ -203,19 +220,19 @@ static void B_BuildTailsTiccmd(mobj_t *sonic, mobj_t *tails, ticcmd_t *cmd)
// End flymode
if (player->powers[pw_carry] != CR_PLAYER)
{
flymode = 0;
mem->thinkstate = AI_FOLLOW;
}
}
}
if (flymode && P_IsObjectOnGround(tails) && !(pcmd->buttons & BT_JUMP))
flymode = 0;
if (P_IsObjectOnGround(tails) && !(pcmd->buttons & BT_JUMP) && (mem->thinkstate == AI_FLYSTANDBY || mem->thinkstate == AI_FLYCARRY))
mem->thinkstate = AI_FOLLOW;
// ********
// SPINNING
if (panic || flymode || !(player->pflags & PF_SPINNING) || (player->pflags & PF_JUMPED))
spinmode = false;
else
if (!(player->pflags & (PF_SPINNING|PF_STARTDASH)) && mem->thinkstate == AI_SPINFOLLOW)
mem->thinkstate = AI_FOLLOW;
else if (mem->thinkstate == AI_FOLLOW || mem->thinkstate == AI_SPINFOLLOW)
{
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
{
cmd->angleturn = (ang - tails->angle) >> 16; // NOT FRACBITS DAMNIT
cmd->angleturn = (ang) >> 16; // NOT FRACBITS DAMNIT
cmd->forwardmove = 50;
spinmode = true;
mem->thinkstate = AI_SPINFOLLOW;
}
else if (dist < touchdist)
{
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;
}
spinmode = true;
mem->thinkstate = AI_SPINFOLLOW;
}
else
spinmode = false;
mem->thinkstate = AI_FOLLOW;
}
// Spin
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)
{
spin = true;
cmd->angleturn = (sonic->angle - tails->angle) >> 16; // NOT FRACBITS DAMNIT
cmd->angleturn = (sonic->angle) >> 16; // NOT FRACBITS DAMNIT
cmd->forwardmove = MAXPLMOVE;
spinmode = true;
mem->thinkstate = AI_SPINFOLLOW;
}
else
spinmode = false;
mem->thinkstate = AI_FOLLOW;
}
}
// 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))
{
spin = true;
spinmode = true;
mem->thinkstate = AI_SPINFOLLOW;
}
else
mem->thinkstate = AI_FOLLOW;
}
}
// ********
// FOLLOW
if (!(flymode || spinmode))
if (mem->thinkstate == AI_FOLLOW || mem->thinkstate == AI_CATCHUP)
{
// Too far
if (panic || dist > followthres)
if (mem->thinkstate == AI_CATCHUP || dist > followthres)
{
if (!_2d)
cmd->forwardmove = MAXPLMOVE;
@ -281,7 +300,7 @@ static void B_BuildTailsTiccmd(mobj_t *sonic, mobj_t *tails, ticcmd_t *cmd)
cmd->sidemove = -MAXPLMOVE;
}
// Within threshold
else if (!panic && dist > followmin && abs(zdist) < 192*scale)
else if (dist > followmin && abs(zdist) < 192*scale)
{
if (!_2d)
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)
{
// Copy inputs
cmd->angleturn = (sonic->angle - tails->angle) >> 16; // NOT FRACBITS DAMNIT
cmd->angleturn = (sonic->angle) >> 16; // NOT FRACBITS DAMNIT
bot->drawangle = ang;
cmd->forwardmove = 8 * pcmd->forwardmove / 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
if (!(flymode || spinmode))
if (mem->thinkstate == AI_FOLLOW || mem->thinkstate == AI_CATCHUP || (mem->thinkstate == AI_SPINFOLLOW && player->pflags & PF_JUMPED))
{
// Flying catch-up
if (bot->pflags & PF_THOKKED)
@ -319,31 +338,30 @@ static void B_BuildTailsTiccmd(mobj_t *sonic, mobj_t *tails, ticcmd_t *cmd)
// Start jump
else if (!jump_last && !(bot->pflags & PF_JUMPED) //&& !(player->pflags & PF_SPINNING)
&& ((zdist > 32*scale && player->pflags & PF_JUMPED) // Following
|| (zdist > 64*scale && panic) // Vertical catch-up
|| (stalled && anxiety > 20 && bot->powers[pw_carry] == CR_NONE)
|| (zdist > 64*scale && mem->thinkstate == AI_CATCHUP) // Vertical catch-up
|| (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
|| (bot->pflags & PF_SPINNING && !(bot->pflags & PF_JUMPED)))) // Spinning
jump = true;
// 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;
// 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;
}
// ********
// HISTORY
jump_last = jump;
spin_last = spin;
//jump_last = jump;
//spin_last = spin;
// Turn the virtual keypresses into ticcmd_t.
B_KeysToTiccmd(tails, cmd, forward, backward, left, right, false, false, jump, spin);
// Update our status
lastForward = forward;
lastBlocked = blocked;
blocked = false;
mem->lastForward = forward;
mem->lastBlocked = blocked;
}
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)))
return;
// We don't have any main character AI, sorry. D:
if (player-players == consoleplayer)
// Make sure we have a valid main character to follow
B_UpdateBotleader(player);
if (!player->botleader)
return;
// Basic Tails AI
B_BuildTailsTiccmd(players[consoleplayer].mo, player->mo, cmd);
// Single Player Tails AI
//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)
{
player_t *player = mo->player;
// 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;
// Turn the virtual keypresses into ticcmd_t.
if (twodlevel || mo->flags2 & MF2_TWOD) {
if (players[consoleplayer].climbing
if (player->botleader->climbing
|| mo->player->pflags & PF_GLIDING) {
// 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.
@ -420,7 +441,7 @@ void B_KeysToTiccmd(mobj_t *mo, ticcmd_t *cmd, boolean forward, boolean backward
cmd->forwardmove += MAXPLMOVE<<FRACBITS>>16;
if (backward)
cmd->forwardmove -= MAXPLMOVE<<FRACBITS>>16;
if (left)
if (left)
cmd->angleturn += 1280;
if (right)
cmd->angleturn -= 1280;
@ -447,14 +468,19 @@ void B_KeysToTiccmd(mobj_t *mo, ticcmd_t *cmd, boolean forward, boolean backward
void B_MoveBlocked(player_t *player)
{
(void)player;
blocked = true;
player->blocked = true;
}
boolean B_CheckRespawn(player_t *player)
{
mobj_t *sonic = players[consoleplayer].mo;
mobj_t *sonic;
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!
if (!sonic || sonic->health <= 0)
return false;
@ -505,15 +531,19 @@ void B_RespawnBot(INT32 playernum)
{
player_t *player = &players[playernum];
fixed_t x,y,z;
mobj_t *sonic = players[consoleplayer].mo;
mobj_t *sonic;
mobj_t *tails;
if (!player->botleader)
return;
sonic = player->botleader->mo;
if (!sonic || sonic->health <= 0)
return;
B_ResetAI();
B_ResetAI(&player->botmem);
player->bot = 1;
player->bot = BOT_2PAI;
P_SpawnPlayer(playernum);
tails = player->mo;
@ -540,10 +570,6 @@ void B_RespawnBot(INT32 playernum)
player->powers[pw_spacetime] = sonic->player->powers[pw_spacetime];
player->powers[pw_gravityboots] = sonic->player->powers[pw_gravityboots];
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);
P_TeleportMove(tails, x, y, z);
@ -561,11 +587,11 @@ void B_RespawnBot(INT32 playernum)
void B_HandleFlightIndicator(player_t *player)
{
mobj_t *tails = player->mo;
botmem_t *mem = &player->botmem;
if (!tails)
return;
if (thinkfly && player->bot == 1 && tails->health)
if (mem->thinkstate == AI_THINKFLY && player->bot == BOT_2PAI && tails->health)
{
if (!tails->hnext)
{

View file

@ -10,6 +10,7 @@
/// \file b_bot.h
/// \brief Basic bot handling
void B_UpdateBotleader(player_t *player);
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);
boolean B_CheckRespawn(player_t *player);

View file

@ -274,7 +274,7 @@ static int luaB_dofile (lua_State *L) {
UINT16 lumpnum;
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");
snprintf(fullfilename, sizeof(fullfilename), "Lua/%s", filename);

View file

@ -650,7 +650,7 @@ static void COM_ExecuteString(char *ptext)
else
{ // Monster Iestyn: keep track of how many levels of recursion we're in
recursion++;
COM_BufInsertText(a->value);
COM_BufInsertTextEx(a->value, com_flags);
recursion--;
}
return;
@ -1738,6 +1738,8 @@ void CV_SaveVars(UINT8 **p, boolean in_demo)
static void CV_LoadVars(UINT8 **p,
consvar_t *(*got)(UINT8 **p, char **ret_value, boolean *ret_stealth))
{
const boolean store = (client || demoplayback);
consvar_t *cvar;
UINT16 count;
@ -1751,7 +1753,7 @@ static void CV_LoadVars(UINT8 **p,
{
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.allocated = ( cvar->zstring != NULL );
@ -2364,7 +2366,10 @@ static boolean CV_Command(void)
return false;
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
if (COM_Argc() == 1)

View file

@ -221,7 +221,7 @@ static void CONS_Bind_f(void)
for (key = 0; key < NUMINPUTS; 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;
}
if (!na)
@ -229,7 +229,7 @@ static void CONS_Bind_f(void)
return;
}
key = G_KeyStringToNum(COM_Argv(1));
key = G_KeyNameToNum(COM_Argv(1));
if (key <= 0 || key >= NUMINPUTS)
{
CONS_Alert(CONS_NOTICE, M_GetText("Invalid key name\n"));
@ -484,6 +484,19 @@ void CON_Init(void)
Unlock_state();
}
}
void CON_StartRefresh(void)
{
if (con_startup)
con_refresh = true;
}
void CON_StopRefresh(void)
{
if (con_startup)
con_refresh = false;
}
// Console input initialization
//
static void CON_InputInit(void)
@ -913,12 +926,12 @@ boolean CON_Responder(event_t *ev)
// let go keyup events, don't eat them
if (ev->type != ev_keydown && ev->type != ev_console)
{
if (ev->data1 == 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;
return false;
}
key = ev->data1;
key = ev->key;
// check for console toggle key
if (ev->type != ev_console)
@ -926,7 +939,7 @@ boolean CON_Responder(event_t *ev)
if (modeattacking || metalrecording || marathonmode)
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
return true;
@ -1759,8 +1772,8 @@ static void CON_DrawBackpic(void)
}
// Draw the patch.
V_DrawCroppedPatch(x << FRACBITS, 0, FRACUNIT, V_NOSCALESTART, con_backpic,
0, ( BASEVIDHEIGHT - h ), BASEVIDWIDTH, h);
V_DrawCroppedPatch(x << FRACBITS, 0, FRACUNIT, FRACUNIT, V_NOSCALESTART, con_backpic, NULL,
0, (BASEVIDHEIGHT - h) << FRACBITS, BASEVIDWIDTH << FRACBITS, h << FRACBITS);
// Unlock the cached patch.
W_UnlockCachedPatch(con_backpic);

View file

@ -16,6 +16,9 @@
void CON_Init(void);
void CON_StartRefresh(void);
void CON_StopRefresh(void);
boolean CON_Responder(event_t *ev);
#ifdef HAVE_THREADS

File diff suppressed because it is too large Load diff

View file

@ -22,11 +22,15 @@
#include "mserv.h"
/*
The 'packet version' is used to distinguish packet formats.
This version is independent of VERSION and SUBVERSION. Different
applications may follow different packet versions.
The 'packet version' is used to distinguish packet
formats. This version is independent of VERSION and
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.
// There is a data struct that stores network
@ -90,6 +94,9 @@ typedef enum
PT_LOGIN, // Login attempt from the client.
PT_TELLFILESNEEDED, // Client, to server: "what other files do I need starting from this number?"
PT_MOREFILESNEEDED, // Server, to client: "you need these (+ more on top of those)"
PT_PING, // Packet sent to tell clients the other client's latency to server.
NUMPACKETTYPE
} packettype_t;
@ -141,9 +148,6 @@ typedef struct
typedef struct
{
UINT8 version; // Different versions don't work
UINT8 subversion; // Contains build version
// Server launch stuffs
UINT8 serverplayer;
UINT8 totalslotnum; // "Slots": highest player number in use plus one.
@ -190,16 +194,22 @@ typedef struct
typedef struct
{
UINT8 _255;/* see serverinfo_pak */
UINT8 packetversion;
UINT8 modversion;
char application[MAXAPPLICATION];
UINT8 version; // Different versions don't work
UINT8 subversion; // Contains build version
UINT8 localplayers;
UINT8 mode;
char names[MAXSPLITSCREENPLAYERS][MAXPLAYERNAME];
} ATTRPACK clientconfig_pak;
#define SV_DEDICATED 0x40 // server is dedicated
#define SV_LOTSOFADDONS 0x20 // flag used to ask for full file list in d_netfil
enum {
REFUSE_JOINS_DISABLED = 1,
REFUSE_SLOTS_FULL,
REFUSE_BANNED,
};
#define MAXSERVERNAME 32
#define MAXFILENEEDED 915
// This packet is too large
@ -217,11 +227,11 @@ typedef struct
UINT8 subversion;
UINT8 numberofplayer;
UINT8 maxplayer;
UINT8 refusereason; // 0: joinable, 1: joins disabled, 2: full
UINT8 refusereason; // 0: joinable, REFUSE enum
char gametypename[24];
UINT8 modifiedgame;
UINT8 cheatsenabled;
UINT8 isdedicated;
UINT8 flags;
UINT8 fileneedednum;
tic_t time;
tic_t leveltime;
@ -275,6 +285,14 @@ typedef struct
UINT8 ctfteam;
} ATTRPACK plrconfig;
typedef struct
{
INT32 first;
UINT8 num;
UINT8 more;
UINT8 files[MAXFILENEEDED]; // is filled with writexxx (byteptr.h)
} ATTRPACK filesneededconfig_pak;
//
// Network packet data
//
@ -304,6 +322,8 @@ typedef struct
msaskinfo_pak msaskinfo; // 22 bytes
plrinfo playerinfo[MAXPLAYERS]; // 576 bytes(?)
plrconfig playerconfig[MAXPLAYERS]; // (up to) 528 bytes(?)
INT32 filesneedednum; // 4 bytes
filesneededconfig_pak filesneededcfg; // ??? bytes
UINT32 pingtable[MAXPLAYERS+1]; // 68 bytes
} u; // This is needed to pack diff packet types data together
} ATTRPACK doomdata_t;
@ -401,6 +421,7 @@ void CL_Reset(void);
void CL_ClearPlayer(INT32 playernum);
void CL_QueryServerList(msg_server_t *list);
void CL_UpdateServerList(boolean internetsearch, INT32 room);
void CL_RemovePlayer(INT32 playernum, kickreason_t reason);
// Is there a game running
boolean Playing(void);

View file

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

View file

@ -65,7 +65,7 @@
#include "m_cond.h" // condition initialization
#include "fastcmp.h"
#include "keys.h"
#include "filesrch.h" // refreshdirmenu, mainwadstally
#include "filesrch.h" // refreshdirmenu
#include "g_input.h" // tutorial mode control scheming
#include "m_perfstats.h"
@ -96,11 +96,8 @@ int SUBVERSION;
// platform independant focus loss
UINT8 window_notinfocus = false;
//
// DEMO LOOP
//
static char *startupwadfiles[MAX_WADFILES];
static char *startuppwads[MAX_WADFILES];
static addfilelist_t startupwadfiles;
static addfilelist_t startuppwads;
boolean devparm = false; // started game with -devparm
@ -119,6 +116,9 @@ boolean midi_disabled = false;
boolean sound_disabled = false;
boolean digital_disabled = false;
//
// DEMO LOOP
//
boolean advancedemo;
#ifdef DEBUGFILE
INT32 debugload = 0;
@ -191,22 +191,22 @@ void D_ProcessEvents(void)
if (ev->type == ev_keydown || ev->type == ev_keyup)
{
// Mouse buttons
if ((UINT32)(ev->data1 - KEY_MOUSE1) < MOUSEBUTTONS)
if ((UINT32)(ev->key - KEY_MOUSE1) < MOUSEBUTTONS)
{
if (ev->type == ev_keydown)
mouse.buttons |= 1 << (ev->data1 - KEY_MOUSE1);
mouse.buttons |= 1 << (ev->key - KEY_MOUSE1);
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)
mouse2.buttons |= 1 << (ev->data1 - KEY_2MOUSE1);
mouse2.buttons |= 1 << (ev->key - KEY_2MOUSE1);
else
mouse2.buttons &= ~(1 << (ev->data1 - KEY_2MOUSE1));
mouse2.buttons &= ~(1 << (ev->key - KEY_2MOUSE1));
}
// Scroll (has no keyup event)
else switch (ev->data1) {
else switch (ev->key) {
case KEY_MOUSEWHEELUP:
mouse.buttons |= MB_SCROLLUP;
break;
@ -272,7 +272,7 @@ void D_ProcessEvents(void)
if (eaten)
continue; // ate the event
if (!hooked && G_LuaResponder(ev))
if (!hooked && !CON_Ready() && G_LuaResponder(ev))
continue;
G_Responder(ev);
@ -476,7 +476,7 @@ static void D_Display(void)
if (!automapactive && !dedicated && cv_renderview.value)
{
ps_rendercalltime = I_GetPreciseTime();
PS_START_TIMING(ps_rendercalltime);
if (players[displayplayer].mo || players[displayplayer].playerstate == PST_DEAD)
{
topleft = screens[0] + viewwindowy*vid.width + viewwindowx;
@ -523,7 +523,7 @@ static void D_Display(void)
if (postimgtype2)
V_DoPostProcessor(1, postimgtype2, postimgparam2);
}
ps_rendercalltime = I_GetPreciseTime() - ps_rendercalltime;
PS_STOP_TIMING(ps_rendercalltime);
}
if (lastdraw)
@ -537,7 +537,7 @@ static void D_Display(void)
lastdraw = false;
}
ps_uitime = I_GetPreciseTime();
PS_START_TIMING(ps_uitime);
if (gamestate == GS_LEVEL)
{
@ -550,7 +550,7 @@ static void D_Display(void)
}
else
{
ps_uitime = I_GetPreciseTime();
PS_START_TIMING(ps_uitime);
}
}
@ -592,7 +592,7 @@ static void D_Display(void)
CON_Drawer();
ps_uitime = I_GetPreciseTime() - ps_uitime;
PS_STOP_TIMING(ps_uitime);
//
// wipe update
@ -678,9 +678,9 @@ static void D_Display(void)
M_DrawPerfStats();
}
ps_swaptime = I_GetPreciseTime();
PS_START_TIMING(ps_swaptime);
I_FinishUpdate(); // page flip or blit buffer
ps_swaptime = I_GetPreciseTime() - ps_swaptime;
PS_STOP_TIMING(ps_swaptime);
}
}
@ -923,35 +923,68 @@ void D_StartTitle(void)
tutorialmode = false;
}
//
// D_AddFile
//
static void D_AddFile(char **list, const char *file)
{
size_t pnumwadfiles;
char *newfile;
#define REALLOC_FILE_LIST \
if (list->files == NULL) \
{ \
list->files = calloc(sizeof(list->files), 2); \
list->numfiles = 1; \
} \
else \
{ \
index = list->numfiles; \
list->files = realloc(list->files, sizeof(list->files) * ((++list->numfiles) + 1)); \
if (list->files == NULL) \
I_Error("%s: No more free memory to add file %s", __FUNCTION__, file); \
}
for (pnumwadfiles = 0; list[pnumwadfiles]; pnumwadfiles++)
;
static void D_AddFile(addfilelist_t *list, const char *file)
{
char *newfile;
size_t index = 0;
REALLOC_FILE_LIST
newfile = malloc(strlen(file) + 1);
if (!newfile)
{
I_Error("No more free memory to AddFile %s",file);
}
strcpy(newfile, file);
I_Error("D_AddFile: No more free memory to add file %s", file);
list[pnumwadfiles] = newfile;
strcpy(newfile, file);
list->files[index] = newfile;
}
static inline void D_CleanFile(char **list)
static void D_AddFolder(addfilelist_t *list, const char *file)
{
size_t pnumwadfiles;
for (pnumwadfiles = 0; list[pnumwadfiles]; pnumwadfiles++)
char *newfile;
size_t index = 0;
REALLOC_FILE_LIST
newfile = malloc(strlen(file) + 2); // Path delimiter + NULL terminator
if (!newfile)
I_Error("D_AddFolder: No more free memory to add folder %s", file);
strcpy(newfile, file);
strcat(newfile, PATHSEP);
list->files[index] = newfile;
}
#undef REALLOC_FILE_LIST
static inline void D_CleanFile(addfilelist_t *list)
{
if (list->files)
{
free(list[pnumwadfiles]);
list[pnumwadfiles] = NULL;
size_t pnumwadfiles = 0;
for (; pnumwadfiles < list->numfiles; pnumwadfiles++)
free(list->files[pnumwadfiles]);
free(list->files);
list->files = NULL;
}
list->numfiles = 0;
}
///\brief Checks if a netgame URL is being handled, and changes working directory to the EXE's if so.
@ -1035,7 +1068,7 @@ static void IdentifyVersion(void)
// Load the IWAD
if (srb2wad != NULL && FIL_ReadFileOK(srb2wad))
D_AddFile(startupwadfiles, srb2wad);
D_AddFile(&startupwadfiles, srb2wad);
else
I_Error("srb2.pk3 not found! Expected in %s, ss file: %s\n", srb2waddir, srb2wad);
@ -1046,14 +1079,14 @@ static void IdentifyVersion(void)
// checking in D_SRB2Main
// Add the maps
D_AddFile(startupwadfiles, va(pandf,srb2waddir,"zones.pk3"));
D_AddFile(&startupwadfiles, va(pandf,srb2waddir, "zones.pk3"));
// Add the players
D_AddFile(startupwadfiles, va(pandf,srb2waddir, "player.dta"));
D_AddFile(&startupwadfiles, va(pandf,srb2waddir, "player.dta"));
#ifdef USE_PATCH_DTA
// Add our crappy patches to fix our bugs
D_AddFile(startupwadfiles, va(pandf,srb2waddir,"patch.pk3"));
D_AddFile(&startupwadfiles, va(pandf,srb2waddir, "patch.pk3"));
#endif
#if !defined (HAVE_SDL) || defined (HAVE_MIXER)
@ -1063,7 +1096,7 @@ static void IdentifyVersion(void)
const char *musicpath = va(pandf,srb2waddir,str);\
int ms = W_VerifyNMUSlumps(musicpath, false); \
if (ms == 1) \
D_AddFile(startupwadfiles, musicpath); \
D_AddFile(&startupwadfiles, musicpath); \
else if (ms == 0) \
I_Error("File "str" has been modified with non-music/sound lumps"); \
}
@ -1237,21 +1270,25 @@ void D_SRB2Main(void)
// Do this up here so that WADs loaded through the command line can use ExecCfg
COM_Init();
// add any files specified on the command line with -file wadfile
// to the wad list
// Add any files specified on the command line with
// "-file <file>" or "-folder <folder>" to the add-on list
if (!((M_GetUrlProtocolArg() || M_CheckParm("-connect")) && !M_CheckParm("-server")))
{
if (M_CheckParm("-file"))
{
// the parms after p are wadfile/lump names,
// until end of parms or another - preceded parm
while (M_IsNextParm())
{
const char *s = M_GetNextParm();
INT32 addontype = 0;
INT32 i;
if (s) // Check for NULL?
D_AddFile(startuppwads, s);
}
for (i = 1; i < myargc; i++)
{
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]);
}
}
@ -1290,8 +1327,8 @@ void D_SRB2Main(void)
// load wad, including the main wad file
CONS_Printf("W_InitMultipleFiles(): Adding IWAD and main PWADs.\n");
W_InitMultipleFiles(startupwadfiles);
D_CleanFile(startupwadfiles);
W_InitMultipleFiles(&startupwadfiles);
D_CleanFile(&startupwadfiles);
#ifndef DEVELOP // md5s last updated 22/02/20 (ddmmyy)
@ -1306,8 +1343,6 @@ void D_SRB2Main(void)
// ...except it does if they slip maps in there, and that's what W_VerifyNMUSlumps is for.
#endif //ifndef DEVELOP
mainwadstally = packetsizetally; // technically not accurate atm, remember to port the two-stage -file process from kart in 2.2.x
cht_Init();
//---------------------------------------------------- READY SCREEN
@ -1338,9 +1373,16 @@ void D_SRB2Main(void)
I_RegisterSysCommands();
CONS_Printf("W_InitMultipleFiles(): Adding extra PWADs.\n");
W_InitMultipleFiles(startuppwads);
D_CleanFile(startuppwads);
CON_StopRefresh(); // Temporarily stop refreshing the screen for wad loading
if (startuppwads.numfiles)
{
CONS_Printf("W_InitMultipleFiles(): Adding extra PWADs.\n");
W_InitMultipleFiles(&startuppwads);
D_CleanFile(&startuppwads);
}
CON_StartRefresh(); // Restart the refresh!
CONS_Printf("HU_LoadGraphics()...\n");
HU_LoadGraphics();

View file

@ -815,6 +815,8 @@ static const char *packettypename[NUMPACKETTYPE] =
"CLIENTJOIN",
"NODETIMEOUT",
"LOGIN",
"TELLFILESNEEDED",
"MOREFILESNEEDED",
"PING"
};

View file

@ -47,6 +47,7 @@
#include "m_cond.h"
#include "m_anigif.h"
#include "md5.h"
#include "m_perfstats.h"
#ifdef NETGAME_DEVMODE
#define CV_RESTRICT CV_NETVAR
@ -63,7 +64,9 @@ static void Got_WeaponPref(UINT8 **cp, INT32 playernum);
static void Got_Mapcmd(UINT8 **cp, INT32 playernum);
static void Got_ExitLevelcmd(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_Addfoldercmd(UINT8 **cp, INT32 playernum);
static void Got_Pause(UINT8 **cp, INT32 playernum);
static void Got_Suicide(UINT8 **cp, INT32 playernum);
static void Got_RandomSeed(UINT8 **cp, INT32 playernum);
@ -115,6 +118,7 @@ static void Command_Map_f(void);
static void Command_ResetCamera_f(void);
static void Command_Addfile(void);
static void Command_Addfolder(void);
static void Command_ListWADS_f(void);
static void Command_RunSOC(void);
static void Command_Pause(void);
@ -284,7 +288,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);
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_touchtag = CVAR_INIT ("touchtag", "Off", CV_SAVE|CV_NETVAR, CV_OnOff, NULL);
@ -371,7 +375,14 @@ consvar_t cv_sleep = CVAR_INIT ("cpusleep", "1", CV_SAVE, sleeping_cons_t, NULL)
static CV_PossibleValue_t perfstats_cons_t[] = {
{0, "Off"}, {1, "Rendering"}, {2, "Logic"}, {3, "ThinkFrame"}, {0, NULL}};
consvar_t cv_perfstats = CVAR_INIT ("perfstats", "Off", 0, perfstats_cons_t, NULL);
consvar_t cv_perfstats = CVAR_INIT ("perfstats", "Off", CV_CALL, perfstats_cons_t, PS_PerfStats_OnChange);
static CV_PossibleValue_t ps_samplesize_cons_t[] = {
{1, "MIN"}, {1000, "MAX"}, {0, NULL}};
consvar_t cv_ps_samplesize = CVAR_INIT ("ps_samplesize", "1", CV_CALL, ps_samplesize_cons_t, PS_SampleSize_OnChange);
static CV_PossibleValue_t ps_descriptor_cons_t[] = {
{1, "Average"}, {2, "SD"}, {3, "Minimum"}, {4, "Maximum"}, {0, NULL}};
consvar_t cv_ps_descriptor = CVAR_INIT ("ps_descriptor", "Average", 0, ps_descriptor_cons_t, NULL);
consvar_t cv_freedemocamera = CVAR_INIT("freedemocamera", "Off", CV_SAVE, CV_OnOff, NULL);
char timedemo_name[256];
@ -398,16 +409,16 @@ const char *netxcmdnames[MAXNETXCMD - 1] =
"MAP",
"EXITLEVEL",
"ADDFILE",
"ADDFOLDER",
"PAUSE",
"ADDPLAYER",
"TEAMCHANGE",
"CLEARSCORES",
"LOGIN",
"VERIFIED",
"RANDOMSEED",
"RUNSOC",
"REQADDFILE",
"DELFILE", // replace next time we add an XD
"REQADDFOLDER",
"SETMOTD",
"SUICIDE",
"LUACMD",
@ -441,7 +452,9 @@ void D_RegisterServerCommands(void)
RegisterNetXCmd(XD_MAP, Got_Mapcmd);
RegisterNetXCmd(XD_EXITLEVEL, Got_ExitLevelcmd);
RegisterNetXCmd(XD_ADDFILE, Got_Addfilecmd);
RegisterNetXCmd(XD_ADDFOLDER, Got_Addfoldercmd);
RegisterNetXCmd(XD_REQADDFILE, Got_RequestAddfilecmd);
RegisterNetXCmd(XD_REQADDFOLDER, Got_RequestAddfoldercmd);
RegisterNetXCmd(XD_PAUSE, Got_Pause);
RegisterNetXCmd(XD_SUICIDE, Got_Suicide);
RegisterNetXCmd(XD_RUNSOC, Got_RunSOCcmd);
@ -472,6 +485,7 @@ void D_RegisterServerCommands(void)
COM_AddCommand("showmap", Command_Showmap_f);
COM_AddCommand("mapmd5", Command_Mapmd5_f);
COM_AddCommand("addfolder", Command_Addfolder);
COM_AddCommand("addfile", Command_Addfile);
COM_AddCommand("listwad", Command_ListWADS_f);
@ -861,6 +875,8 @@ void D_RegisterClientCommands(void)
CV_RegisterVar(&cv_soundtest);
CV_RegisterVar(&cv_perfstats);
CV_RegisterVar(&cv_ps_samplesize);
CV_RegisterVar(&cv_ps_descriptor);
// ingame object placing
COM_AddCommand("objectplace", Command_ObjectPlace_f);
@ -3217,7 +3233,7 @@ static void Command_RunSOC(void)
static void Got_RunSOCcmd(UINT8 **cp, INT32 playernum)
{
char filename[256];
filestatus_t ncs = FS_NOTFOUND;
filestatus_t ncs = FS_NOTCHECKED;
if (playernum != serverplayer && !IsPlayerAdmin(playernum))
{
@ -3341,10 +3357,9 @@ static void Command_Addfile(void)
break;
++p;
// check total packet size and no of files currently loaded
// check no of files currently loaded
// See W_LoadWadFile in w_wad.c
if ((numwadfiles >= MAX_WADFILES)
|| ((packetsizetally + nameonlylength(fn) + 22) > MAXFILENEEDED*sizeof(UINT8)))
if (numwadfiles >= MAX_WADFILES)
{
CONS_Alert(CONS_ERROR, M_GetText("Too many files loaded to add %s\n"), fn);
return;
@ -3373,6 +3388,9 @@ static void Command_Addfile(void)
for (i = 0; i < numwadfiles; i++)
{
if (wadfiles[i]->type == RET_FOLDER)
continue;
if (!memcmp(wadfiles[i]->md5sum, md5sum, 16))
{
CONS_Alert(CONS_ERROR, M_GetText("%s is already loaded\n"), fn);
@ -3392,10 +3410,142 @@ 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 no of files currently loaded
// See W_LoadWadFile in w_wad.c
if (numwadfiles >= MAX_WADFILES)
{
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)
{
char filename[241];
filestatus_t ncs = FS_NOTFOUND;
filestatus_t ncs = FS_NOTCHECKED;
UINT8 md5sum[16];
boolean kick = false;
boolean toomany = false;
@ -3420,9 +3570,7 @@ static void Got_RequestAddfilecmd(UINT8 **cp, INT32 playernum)
return;
}
// See W_LoadWadFile in w_wad.c
if ((numwadfiles >= MAX_WADFILES)
|| ((packetsizetally + nameonlylength(filename) + 22) > MAXFILENEEDED*sizeof(UINT8)))
if (numwadfiles >= MAX_WADFILES)
toomany = true;
else
ncs = findfile(filename,md5sum,true);
@ -3452,10 +3600,66 @@ static void Got_RequestAddfilecmd(UINT8 **cp, INT32 playernum)
COM_BufAddText(va("addfile %s\n", filename));
}
static void Got_RequestAddfoldercmd(UINT8 **cp, INT32 playernum)
{
char path[241];
filestatus_t ncs = FS_NOTCHECKED;
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;
}
if (numwadfiles >= MAX_WADFILES)
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)
{
char filename[241];
filestatus_t ncs = FS_NOTFOUND;
filestatus_t ncs = FS_NOTCHECKED;
UINT8 md5sum[16];
READSTRINGN(*cp, filename, 240);
@ -3500,11 +3704,60 @@ static void Got_Addfilecmd(UINT8 **cp, INT32 playernum)
G_SetGameModified(true);
}
static void Got_Addfoldercmd(UINT8 **cp, INT32 playernum)
{
char path[241];
filestatus_t ncs = FS_NOTCHECKED;
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)
{
INT32 i = numwadfiles;
char *tempname;
CONS_Printf(M_GetText("There are %d wads loaded:\n"),numwadfiles);
#ifdef ENFORCE_WAD_LIMIT
CONS_Printf(M_GetText("There are %d/%d files loaded:\n"),numwadfiles,MAX_WADFILES);
#else
CONS_Printf(M_GetText("There are %d files loaded:\n"),numwadfiles);
#endif
for (i--; i >= 0; i--)
{
nameonly(tempname = va("%s", wadfiles[i]->filename));
@ -3514,6 +3767,8 @@ static void Command_ListWADS_f(void)
CONS_Printf("\x82 * %.2d\x80: %s\n", i, tempname);
else if (!wadfiles[i]->important)
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
CONS_Printf(" %.2d: %s\n", i, tempname);
}

View file

@ -73,6 +73,7 @@ extern consvar_t cv_teamscramble;
extern consvar_t cv_scrambleonchange;
extern consvar_t cv_netstat;
extern consvar_t cv_nettimeout;
extern consvar_t cv_countdowntime;
extern consvar_t cv_runscripts;
@ -110,6 +111,8 @@ extern consvar_t cv_skipmapcheck;
extern consvar_t cv_sleep;
extern consvar_t cv_perfstats;
extern consvar_t cv_ps_samplesize;
extern consvar_t cv_ps_descriptor;
extern char timedemo_name[256];
extern boolean timedemo_csv;
@ -128,16 +131,16 @@ typedef enum
XD_MAP, // 6
XD_EXITLEVEL, // 7
XD_ADDFILE, // 8
XD_PAUSE, // 9
XD_ADDPLAYER, // 10
XD_TEAMCHANGE, // 11
XD_CLEARSCORES, // 12
// UNUSED 13 (Because I don't want to change these comments)
XD_VERIFIED = 14,//14
XD_ADDFOLDER, // 9
XD_PAUSE, // 10
XD_ADDPLAYER, // 11
XD_TEAMCHANGE, // 12
XD_CLEARSCORES, // 13
XD_VERIFIED, // 14
XD_RANDOMSEED, // 15
XD_RUNSOC, // 16
XD_REQADDFILE, // 17
XD_DELFILE, // 18 - replace next time we add an XD
XD_REQADDFOLDER,// 18
XD_SETMOTD, // 19
XD_SUICIDE, // 20
XD_DEMOTED, // 21

View file

@ -52,7 +52,7 @@
#include <errno.h>
// Prototypes
static boolean AddFileToSendQueue(INT32 node, const char *filename, UINT8 fileid);
static boolean AddFileToSendQueue(INT32 node, UINT8 fileid);
// Sender structure
typedef struct filetx_s
@ -87,7 +87,7 @@ static filetran_t transfer[MAXNETNODES];
// Receiver structure
INT32 fileneedednum; // Number of files needed to join the server
fileneeded_t fileneeded[MAX_WADFILES]; // List of needed files
fileneeded_t *fileneeded; // List of needed files
static tic_t lasttimeackpacketsent = 0;
char downloaddir[512] = "DOWNLOAD";
@ -105,6 +105,10 @@ static pauseddownload_t *pauseddownload = NULL;
#ifndef NONET
// for cl loading screen
INT32 lastfilenum = -1;
INT32 downloadcompletednum = 0;
UINT32 downloadcompletedsize = 0;
INT32 totalfilesrequestednum = 0;
UINT32 totalfilesrequestedsize = 0;
#endif
luafiletransfer_t *luafiletransfers = NULL;
@ -113,29 +117,67 @@ boolean waitingforluafilecommand = false;
char luafiledir[256 + 16] = "luafiles";
static UINT16 GetWadNumFromFileNeededId(UINT8 id)
{
UINT16 wadnum;
for (wadnum = mainwads; wadnum < numwadfiles; wadnum++)
{
if (!wadfiles[wadnum]->important)
continue;
if (id == 0)
return wadnum;
id--;
}
return UINT16_MAX;
}
/** Fills a serverinfo packet with information about wad files loaded.
*
* \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(UINT16 firstfile)
{
size_t i, count = 0;
UINT8 *p = netbuffer->u.serverinfo.fileneeded;
size_t i;
UINT8 count = 0;
UINT8 *p_start = netbuffer->packettype == PT_MOREFILESNEEDED ? netbuffer->u.filesneededcfg.files : netbuffer->u.serverinfo.fileneeded;
UINT8 *p = p_start;
char wadfilename[MAX_WADPATH] = "";
UINT8 filestatus;
UINT8 filestatus, folder;
for (i = 0; i < numwadfiles; i++)
for (i = mainwads; i < numwadfiles; i++) //mainwads, otherwise we start on the first mainwad
{
// If it has only music/sound lumps, don't put it in the list
if (!wadfiles[i]->important)
continue;
if (firstfile)
{ // Skip files until we reach the first file.
firstfile--;
continue;
}
nameonly(strcpy(wadfilename, wadfiles[i]->filename));
// Look below at the WRITE macros to understand what these numbers mean.
if (p + 1 + 4 + min(strlen(wadfilename) + 1, MAX_WADPATH) + 16 > p_start + MAXFILENEEDED)
{
// Too many files to send all at once
if (netbuffer->packettype == PT_MOREFILESNEEDED)
netbuffer->u.filesneededcfg.more = 1;
else
netbuffer->u.serverinfo.flags |= SV_LOTSOFADDONS;
break;
}
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
if (!cv_downloading.value)
if (!cv_downloading.value || folder) /// \todo Implement folder downloading.
filestatus += (2 << 4); // Won't send
else if ((wadfiles[i]->filesize <= (UINT32)cv_maxsend.value * 1024))
filestatus += (1 << 4); // Will send if requested
@ -143,37 +185,60 @@ UINT8 *PutFileNeeded(void)
// filestatus += (0 << 4); -- Won't send, too big
WRITEUINT8(p, filestatus);
WRITEUINT8(p, folder);
count++;
WRITEUINT32(p, wadfiles[i]->filesize);
nameonly(strcpy(wadfilename, wadfiles[i]->filename));
WRITESTRINGN(p, wadfilename, MAX_WADPATH);
WRITEMEM(p, wadfiles[i]->md5sum, 16);
}
netbuffer->u.serverinfo.fileneedednum = (UINT8)count;
if (netbuffer->packettype == PT_MOREFILESNEEDED)
netbuffer->u.filesneededcfg.num = count;
else
netbuffer->u.serverinfo.fileneedednum = count;
return p;
}
void AllocFileNeeded(INT32 size)
{
if (fileneeded == NULL)
fileneeded = Z_Calloc(sizeof(fileneeded_t) * size, PU_STATIC, NULL);
else
fileneeded = Z_Realloc(fileneeded, sizeof(fileneeded_t) * size, PU_STATIC, NULL);
}
void FreeFileNeeded(void)
{
Z_Free(fileneeded);
fileneeded = NULL;
}
/** Parses the serverinfo packet and fills the fileneeded table on client
*
* \param fileneedednum_parm The number of files needed to join the server
* \param fileneededstr The memory block containing the list of needed files
*
*/
void D_ParseFileneeded(INT32 fileneedednum_parm, UINT8 *fileneededstr)
void D_ParseFileneeded(INT32 fileneedednum_parm, UINT8 *fileneededstr, UINT16 firstfile)
{
INT32 i;
UINT8 *p;
UINT8 filestatus;
fileneedednum = fileneedednum_parm;
fileneedednum = firstfile + fileneedednum_parm;
p = (UINT8 *)fileneededstr;
for (i = 0; i < fileneedednum; i++)
AllocFileNeeded(fileneedednum);
for (i = firstfile; i < fileneedednum; i++)
{
fileneeded[i].status = FS_NOTFOUND; // We haven't even started looking for the file yet
fileneeded[i].type = FILENEEDED_WAD;
fileneeded[i].status = FS_NOTCHECKED; // We haven't even started looking for the file yet
fileneeded[i].justdownloaded = false;
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].totalsize = READUINT32(p); // The four next bytes are the file size
fileneeded[i].file = NULL; // The file isn't open yet
@ -188,7 +253,11 @@ void CL_PrepareDownloadSaveGame(const char *tmpsave)
lastfilenum = -1;
#endif
FreeFileNeeded();
AllocFileNeeded(1);
fileneedednum = 1;
fileneeded[0].type = FILENEEDED_SAVEGAME;
fileneeded[0].status = FS_REQUESTED;
fileneeded[0].justdownloaded = false;
fileneeded[0].totalsize = UINT32_MAX;
@ -319,14 +388,18 @@ boolean CL_SendFileRequest(void)
if ((fileneeded[i].status == FS_NOTFOUND || fileneeded[i].status == FS_MD5SUMBAD))
{
totalfreespaceneeded += fileneeded[i].totalsize;
nameonly(fileneeded[i].filename);
WRITEUINT8(p, i); // fileid
WRITESTRINGN(p, fileneeded[i].filename, MAX_WADPATH);
// put it in download dir
nameonly(fileneeded[i].filename);
strcatbf(fileneeded[i].filename, downloaddir, "/");
fileneeded[i].status = FS_REQUESTED;
}
WRITEUINT8(p, 0xFF);
I_GetDiskFreeSpace(&availablefreespace);
if (totalfreespaceneeded > availablefreespace)
I_Error("To play on this server you must download %s KB,\n"
@ -342,21 +415,22 @@ boolean CL_SendFileRequest(void)
// returns false if a requested file was not found or cannot be sent
boolean PT_RequestFile(INT32 node)
{
char wad[MAX_WADPATH+1];
UINT8 *p = netbuffer->u.textcmd;
UINT8 id;
while (p < netbuffer->u.textcmd + MAXTEXTCMD-1) // Don't allow hacked client to overflow
{
id = READUINT8(p);
if (id == 0xFF)
break;
READSTRINGN(p, wad, MAX_WADPATH);
if (!AddFileToSendQueue(node, wad, id))
if (!AddFileToSendQueue(node, id))
{
SV_AbortSendFiles(node);
return false; // don't read the rest of the files
}
}
return true; // no problems with any files
}
@ -365,23 +439,16 @@ boolean PT_RequestFile(INT32 node)
* \return 0 if some files are missing
* 1 if all files exist
* 2 if some already loaded files are not requested or are in a different order
* 3 too many files, over WADLIMIT
* 4 still checking, continuing next tic
*
*/
INT32 CL_CheckFiles(void)
{
INT32 i, j;
char wadfilename[MAX_WADPATH];
INT32 ret = 1;
size_t packetsize = 0;
size_t filestoget = 0;
// if (M_CheckParm("-nofiles"))
// return 1;
// the first is the iwad (the main wad file)
// we don't care if it's called srb2.pk3 or not.
// Never download the IWAD, just assume it's there and identical
fileneeded[0].status = FS_OPEN;
size_t filestoload = 0;
boolean downloadrequired = false;
// Modified game handling -- check for an identical file list
// must be identical in files loaded AND in order
@ -389,7 +456,7 @@ INT32 CL_CheckFiles(void)
if (modifiedgame)
{
CONS_Debug(DBG_NETPLAY, "game is modified; only doing basic checks\n");
for (i = 1, j = 1; i < fileneedednum || j < numwadfiles;)
for (i = 0, j = mainwads; i < fileneedednum || j < numwadfiles;)
{
if (j < numwadfiles && !wadfiles[j]->important)
{
@ -416,15 +483,21 @@ INT32 CL_CheckFiles(void)
return 1;
}
// See W_LoadWadFile in w_wad.c
packetsize = packetsizetally;
for (i = 1; i < fileneedednum; i++)
for (i = 0; i < fileneedednum; i++)
{
if (fileneeded[i].status == FS_NOTFOUND || fileneeded[i].status == FS_MD5SUMBAD)
downloadrequired = true;
if (fileneeded[i].status != FS_OPEN)
filestoload++;
if (fileneeded[i].status != FS_NOTCHECKED) //since we're running this over multiple tics now, its possible for us to come across files checked in previous tics
continue;
CONS_Debug(DBG_NETPLAY, "searching for '%s' ", fileneeded[i].filename);
// Check in already loaded files
for (j = 1; wadfiles[j]; j++)
for (j = mainwads; wadfiles[j]; j++)
{
nameonly(strcpy(wadfilename, wadfiles[j]->filename));
if (!stricmp(wadfilename, fileneeded[i].filename) &&
@ -432,45 +505,46 @@ INT32 CL_CheckFiles(void)
{
CONS_Debug(DBG_NETPLAY, "already loaded\n");
fileneeded[i].status = FS_OPEN;
break;
return 4;
}
}
if (fileneeded[i].status != FS_NOTFOUND)
continue;
packetsize += nameonlylength(fileneeded[i].filename) + 22;
if (fileneeded[i].folder)
fileneeded[i].status = findfolder(fileneeded[i].filename);
else
fileneeded[i].status = findfile(fileneeded[i].filename, fileneeded[i].md5sum, true);
if ((numwadfiles+filestoget >= MAX_WADFILES)
|| (packetsize > MAXFILENEEDED*sizeof(UINT8)))
return 3;
filestoget++;
fileneeded[i].status = findfile(fileneeded[i].filename, fileneeded[i].md5sum, true);
CONS_Debug(DBG_NETPLAY, "found %d\n", fileneeded[i].status);
if (fileneeded[i].status != FS_FOUND)
ret = 0;
return 4;
}
return ret;
//now making it here means we've checked the entire list and no FS_NOTCHECKED files remain
if (numwadfiles+filestoload > MAX_WADFILES)
return 3;
else if (downloadrequired)
return 0; //some stuff is FS_NOTFOUND, needs download
else
return 1; //everything is FS_OPEN or FS_FOUND, proceed to loading
}
// Load it now
void CL_LoadServerFiles(void)
boolean CL_LoadServerFiles(void)
{
INT32 i;
// if (M_CheckParm("-nofiles"))
// return;
for (i = 1; i < fileneedednum; i++)
for (i = 0; i < fileneedednum; i++)
{
if (fileneeded[i].status == FS_OPEN)
continue; // Already loaded
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);
fileneeded[i].status = FS_OPEN;
return false;
}
else if (fileneeded[i].status == FS_MD5SUMBAD)
I_Error("Wrong version of file %s", fileneeded[i].filename);
@ -496,6 +570,7 @@ void CL_LoadServerFiles(void)
fileneeded[i].status, s);
}
}
return true;
}
void AddLuaFileTransfer(const char *filename, const char *mode)
@ -677,7 +752,11 @@ void CL_PrepareDownloadLuaFile(void)
netbuffer->packettype = PT_ASKLUAFILE;
HSendPacket(servernode, true, 0, 0);
FreeFileNeeded();
AllocFileNeeded(1);
fileneedednum = 1;
fileneeded[0].type = FILENEEDED_LUAFILE;
fileneeded[0].status = FS_REQUESTED;
fileneeded[0].justdownloaded = false;
fileneeded[0].totalsize = UINT32_MAX;
@ -704,15 +783,11 @@ static INT32 filestosend = 0;
* \sa AddLuaFileToSendQueue
*
*/
static boolean AddFileToSendQueue(INT32 node, const char *filename, UINT8 fileid)
static boolean AddFileToSendQueue(INT32 node, UINT8 fileid)
{
filetx_t **q; // A pointer to the "next" field of the last file in the list
filetx_t *p; // The new file request
INT32 i;
char wadfilename[MAX_WADPATH];
if (cv_noticedownload.value)
CONS_Printf("Sending file \"%s\" to node %d (%s)\n", filename, node, I_GetNodeAddress(node));
UINT16 wadnum;
// Find the last file in the list and set a pointer to its "next" field
q = &transfer[node].txlist;
@ -732,51 +807,43 @@ static boolean AddFileToSendQueue(INT32 node, const char *filename, UINT8 fileid
if (!p->id.filename)
I_Error("AddFileToSendQueue: No more memory\n");
// Set the file name and get rid of the path
strlcpy(p->id.filename, filename, MAX_WADPATH);
nameonly(p->id.filename);
// Look for the requested file through all loaded files
for (i = 0; wadfiles[i]; i++)
{
strlcpy(wadfilename, wadfiles[i]->filename, MAX_WADPATH);
nameonly(wadfilename);
if (!stricmp(wadfilename, p->id.filename))
{
// Copy file name with full path
strlcpy(p->id.filename, wadfiles[i]->filename, MAX_WADPATH);
break;
}
}
// Find the wad the ID refers to
wadnum = GetWadNumFromFileNeededId(fileid);
// Handle non-loaded file requests
if (!wadfiles[i])
if (wadnum == UINT16_MAX)
{
DEBFILE(va("%s not found in wadfiles\n", filename));
DEBFILE(va("fileneeded %d not found in wadfiles\n", fileid));
// This formerly checked if (!findfile(p->id.filename, NULL, true))
// Not found
// Don't inform client (probably someone who thought they could leak 2.2 ACZ)
DEBFILE(va("Client %d request %s: not found\n", node, filename));
// Don't inform client
DEBFILE(va("Client %d request fileneeded %d: not found\n", node, fileid));
free(p->id.filename);
free(p);
*q = NULL;
return false; // cancel the rest of the requests
}
// Set the file name and get rid of the path
strlcpy(p->id.filename, wadfiles[wadnum]->filename, MAX_WADPATH);
// Handle huge file requests (i.e. bigger than cv_maxsend.value KB)
if (wadfiles[i]->filesize > (UINT32)cv_maxsend.value * 1024)
if (wadfiles[wadnum]->filesize > (UINT32)cv_maxsend.value * 1024)
{
// Too big
// Don't inform client (client sucks, man)
DEBFILE(va("Client %d request %s: file too big, not sending\n", node, filename));
DEBFILE(va("Client %d request %s: file too big, not sending\n", node, p->id.filename));
free(p->id.filename);
free(p);
*q = NULL;
return false; // cancel the rest of the requests
}
DEBFILE(va("Sending file %s (id=%d) to %d\n", filename, fileid, node));
if (cv_noticedownload.value)
CONS_Printf("Sending file \"%s\" to node %d (%s)\n", p->id.filename, node, I_GetNodeAddress(node));
DEBFILE(va("Sending file %s (id=%d) to %d\n", p->id.filename, fileid, node));
p->ram = SF_FILE; // It's a file, we need to close it and free its name once we're done sending it
p->fileid = fileid;
p->next = NULL; // End of list
@ -913,7 +980,6 @@ static void SV_EndFileSend(INT32 node)
filestosend--;
}
#define PACKETPERTIC net_bandwidth/(TICRATE*software_MAXPACKETLENGTH)
#define FILEFRAGMENTSIZE (software_MAXPACKETLENGTH - (FILETXHEADER + BASEPACKETSIZE))
/** Handles file transmission
@ -946,14 +1012,7 @@ void FileSendTicker(void)
if (!filestosend) // No file to send
return;
if (cv_downloadspeed.value) // New behavior
packetsent = cv_downloadspeed.value;
else // Old behavior
{
packetsent = PACKETPERTIC;
if (!packetsent)
packetsent = 1;
}
packetsent = cv_downloadspeed.value;
netbuffer->packettype = PT_FILEFRAGMENT;
@ -1230,6 +1289,9 @@ void PT_FileFragment(void)
UINT16 boundedfragmentsize = doomcom->datalength - BASEPACKETSIZE - sizeof(netbuffer->u.filetxpak);
char *filename;
if (!file)
return;
filename = va("%s", file->filename);
nameonly(filename);
@ -1341,6 +1403,7 @@ void PT_FileFragment(void)
// Tell the server we have received the file
netbuffer->packettype = PT_HASLUAFILE;
HSendPacket(servernode, true, 0, 0);
FreeFileNeeded();
}
}
}
@ -1411,32 +1474,37 @@ void CloseNetFile(void)
SV_AbortSendFiles(i);
// Receiving a file?
for (i = 0; i < MAX_WADFILES; i++)
if (fileneeded[i].status == FS_DOWNLOADING && fileneeded[i].file)
{
fclose(fileneeded[i].file);
free(fileneeded[i].ackpacket);
if (!pauseddownload && i != 0) // 0 is either srb2.srb or the gamestate...
if (fileneeded)
{
for (i = 0; i < fileneedednum; i++)
if (fileneeded[i].status == FS_DOWNLOADING && fileneeded[i].file)
{
// Don't remove the file, save it for later in case we resume the download
pauseddownload = malloc(sizeof(*pauseddownload));
if (!pauseddownload)
I_Error("CloseNetFile: No more memory\n");
fclose(fileneeded[i].file);
free(fileneeded[i].ackpacket);
strcpy(pauseddownload->filename, fileneeded[i].filename);
memcpy(pauseddownload->md5sum, fileneeded[i].md5sum, 16);
pauseddownload->currentsize = fileneeded[i].currentsize;
pauseddownload->receivedfragments = fileneeded[i].receivedfragments;
pauseddownload->fragmentsize = fileneeded[i].fragmentsize;
if (!pauseddownload && (fileneeded[i].type == FILENEEDED_WAD || i != 0)) // 0 is the gamestate...
{
// Don't remove the file, save it for later in case we resume the download
pauseddownload = malloc(sizeof(*pauseddownload));
if (!pauseddownload)
I_Error("CloseNetFile: No more memory\n");
strcpy(pauseddownload->filename, fileneeded[i].filename);
memcpy(pauseddownload->md5sum, fileneeded[i].md5sum, 16);
pauseddownload->currentsize = fileneeded[i].currentsize;
pauseddownload->receivedfragments = fileneeded[i].receivedfragments;
pauseddownload->fragmentsize = fileneeded[i].fragmentsize;
}
else
{
// File is not complete, delete it.
free(fileneeded[i].receivedfragments);
remove(fileneeded[i].filename);
}
}
else
{
free(fileneeded[i].receivedfragments);
// File is not complete delete it
remove(fileneeded[i].filename);
}
}
}
FreeFileNeeded();
}
void Command_Downloads_f(void)
@ -1571,3 +1639,26 @@ filestatus_t findfile(char *filename, const UINT8 *wantedmd5sum, boolean complet
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

@ -27,6 +27,7 @@ typedef enum
typedef enum
{
FS_NOTCHECKED,
FS_NOTFOUND,
FS_FOUND,
FS_REQUESTED,
@ -35,12 +36,21 @@ typedef enum
FS_MD5SUMBAD
} filestatus_t;
typedef enum
{
FILENEEDED_WAD,
FILENEEDED_SAVEGAME,
FILENEEDED_LUAFILE
} fileneededtype_t;
typedef struct
{
UINT8 willsend; // Is the server willing to send it?
char filename[MAX_WADPATH];
UINT8 md5sum[16];
filestatus_t status; // The value returned by recsearch
UINT8 willsend; // Is the server willing to send it?
UINT8 folder; // File is a folder
fileneededtype_t type;
boolean justdownloaded; // To prevent late fragments from causing an I_Error
// Used only for download
@ -54,20 +64,28 @@ typedef struct
UINT32 ackresendposition; // Used when resuming downloads
} fileneeded_t;
#define FILENEEDEDSIZE 23
extern INT32 fileneedednum;
extern fileneeded_t fileneeded[MAX_WADFILES];
extern fileneeded_t *fileneeded;
extern char downloaddir[512];
#ifndef NONET
extern INT32 lastfilenum;
extern INT32 downloadcompletednum;
extern UINT32 downloadcompletedsize;
extern INT32 totalfilesrequestednum;
extern UINT32 totalfilesrequestedsize;
#endif
UINT8 *PutFileNeeded(void);
void D_ParseFileneeded(INT32 fileneedednum_parm, UINT8 *fileneededstr);
void AllocFileNeeded(INT32 size);
void FreeFileNeeded(void);
UINT8 *PutFileNeeded(UINT16 firstfile);
void D_ParseFileneeded(INT32 fileneedednum_parm, UINT8 *fileneededstr, UINT16 firstfile);
void CL_PrepareDownloadSaveGame(const char *tmpsave);
INT32 CL_CheckFiles(void);
void CL_LoadServerFiles(void);
boolean CL_LoadServerFiles(void);
void AddRamToSendQueue(INT32 node, void *data, size_t size, freemethod_t freemethod,
UINT8 fileid);
@ -135,6 +153,9 @@ filestatus_t findfile(char *filename, const UINT8 *wantedmd5sum,
boolean completepath);
filestatus_t checkfilemd5(char *filename, const UINT8 *wantedmd5sum);
// Searches for a folder
filestatus_t findfolder(const char *path);
void nameonly(char *s);
size_t nameonlylength(const char *s);

View file

@ -313,9 +313,43 @@ typedef enum
RW_RAIL = 32
} 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
// ========================================================================
//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
{
mobj_t *mo;
@ -525,7 +559,12 @@ typedef struct player_s
boolean spectator;
boolean outofcoop;
boolean removing;
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 quittime; // Time elapsed since user disconnected, zero if connected

View file

@ -5170,6 +5170,12 @@ struct int_const_s const INT_CONST[] = {
{"GF_REDFLAG",GF_REDFLAG},
{"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
{"SKSSPIN",SKSSPIN},
{"SKSPUTPUT",SKSPUTPUT},
@ -5480,49 +5486,49 @@ struct int_const_s const INT_CONST[] = {
{"JOYAXISRANGE",JOYAXISRANGE},
// Game controls
{"gc_null",gc_null},
{"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",gc_mouseaiming},
{"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",gc_custom1},
{"gc_custom2",gc_custom2},
{"gc_custom3",gc_custom3},
{"num_gamecontrols",num_gamecontrols},
{"GC_NULL",GC_NULL},
{"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",GC_MOUSEAIMING},
{"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",GC_CUSTOM1},
{"GC_CUSTOM2",GC_CUSTOM2},
{"GC_CUSTOM3",GC_CUSTOM3},
{"NUM_GAMECONTROLS",NUM_GAMECONTROLS},
// Mouse buttons
{"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
#ifdef DEVELOP
#define VERSIONSTRING "Development EXE"
#define VERSIONSTRING_RC "Development EXE" "\0"
// most interface strings are ignored in development mode.
// we use comprevision and compbranch instead.
// VERSIONSTRING_RC is for the resource-definition script used by windows builds
@ -151,6 +152,9 @@ extern char logfilename[1024];
// Comment or uncomment this as necessary.
#define USE_PATCH_DTA
// Enforce a limit of loaded WAD files.
//#define ENFORCE_WAD_LIMIT
// Use .kart extension addons
//#define USE_KART

View file

@ -41,6 +41,7 @@
#include "console.h"
#include "lua_hud.h"
#include "lua_hook.h"
// Stage of animation:
// 0 = text, 1 = art screen
@ -1011,7 +1012,7 @@ void F_IntroTicker(void)
//
boolean F_IntroResponder(event_t *event)
{
INT32 key = event->data1;
INT32 key = event->key;
// remap virtual keys (mouse & joystick buttons)
switch (key)
@ -1089,19 +1090,19 @@ static const char *credits[] = {
"\"Hannu_Hanhi\"", // For many OpenGL performance improvements!
"Kepa \"Nev3r\" Iceta",
"Thomas \"Shadow Hog\" Igoe",
"\"james\"",
"Iestyn \"Monster Iestyn\" Jealous",
"\"Jimita\"",
"\"Kaito Sinclaire\"",
"\"Kalaron\"", // Coded some of Sryder13's collection of OpenGL fixes, especially fog
"Ronald \"Furyhunter\" Kinard", // The SDL2 port
"\"Lat'\"", // SRB2-CHAT, the chat window from Kart
"\"LZA\"",
"Matthew \"Shuffle\" Marsalko",
"Steven \"StroggOnMeth\" McGranahan",
"\"Morph\"", // For SRB2Morphed stuff
"Louis-Antoine \"LJ Sonic\" de Moulins", // de Rochefort doesn't quite fit on the screen sorry lol
"John \"JTE\" Muniz",
"Colin \"Sonict\" Pfaff",
"James \"james\" Robert Roman",
"Sean \"Sryder13\" Ryder",
"Ehab \"Wolfy\" Saeed",
"Tasos \"tatokis\" Sahanidis", // Corrected C FixedMul, making 64-bit builds netplay compatible
@ -1166,9 +1167,8 @@ static const char *credits[] = {
"Alexander \"DrTapeworm\" Moench-Ford",
"Stefan \"Stuf\" Rimalia",
"Shane Mychal Sexton",
"\"Spazzo\"",
"David \"Big Wave Dave\" Spencer Sr.",
"David \"Instant Sonic\" Spencer Jr.",
"Dave \"Big Wave Dave\" Spencer",
"David \"instantSonic\" Spencer",
"\"SSNTails\"",
"",
"\1Level Design",
@ -1191,7 +1191,6 @@ static const char *credits[] = {
"\"Revan\"",
"Anna \"QueenDelta\" Sandlin",
"Wessel \"sphere\" Smit",
"\"Spazzo\"",
"\"SSNTails\"",
"Rob Tisdell",
"\"Torgo\"",
@ -1220,7 +1219,7 @@ static const char *credits[] = {
"Bill \"Tets\" Reed",
"",
"\1Special Thanks",
"iD Software",
"id Software",
"Doom Legacy Project",
"FreeDoom Project", // Used some of the mancubus and rocket launcher sprites for Brak
"Kart Krew",
@ -1399,7 +1398,7 @@ void F_CreditTicker(void)
boolean F_CreditResponder(event_t *event)
{
INT32 key = event->data1;
INT32 key = event->key;
// remap virtual keys (mouse & joystick buttons)
switch (key)
@ -3423,7 +3422,7 @@ void F_TitleScreenDrawer(void)
}
luahook:
LUAh_TitleHUD();
LUA_HUDHOOK(title);
}
// separate animation timer for backgrounds, since we also count
@ -3823,7 +3822,7 @@ void F_ContinueTicker(void)
boolean F_ContinueResponder(event_t *event)
{
INT32 key = event->data1;
INT32 key = event->key;
if (keypressed)
return true;

View file

@ -13,6 +13,7 @@
/// FS_FOUND
#include <stdio.h>
#include <errno.h>
#ifdef __GNUC__
#include <dirent.h>
#endif
@ -29,10 +30,10 @@
#include "m_misc.h"
#include "z_zone.h"
#include "m_menu.h" // Addons_option_Onchange
#include "w_wad.h"
#if defined (_WIN32) && defined (_MSC_VER)
#include <errno.h>
#include <io.h>
#include <tchar.h>
@ -337,8 +338,10 @@ size_t dir_on[menudepth];
UINT8 refreshdirmenu = 0;
char *refreshdirname = NULL;
size_t packetsizetally = 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)
{
@ -387,10 +390,7 @@ filestatus_t filesearch(char *filename, const char *startpath, const UINT8 *want
continue;
}
if (dent->d_name[0]=='.' &&
(dent->d_name[1]=='\0' ||
(dent->d_name[1]=='.' &&
dent->d_name[2]=='\0')))
if (isuptree(dent->d_name))
{
// we don't want to scan uptree
continue;
@ -445,6 +445,380 @@ filestatus_t filesearch(char *filename, const char *startpath, const UINT8 *want
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)
"\5.txt", "\5.cfg", // exec
"\5.wad",
@ -453,8 +827,7 @@ char exttable[NUM_EXT_TABLE][7] = { // maximum extension length (currently 4) pl
#endif
"\5.pk3", "\5.soc", "\5.lua"}; // addfile
char filenamebuf[MAX_WADFILES][MAX_WADPATH];
static char (*filenamebuf)[MAX_WADPATH];
static boolean filemenucmp(char *haystack, char *needle)
{
@ -640,10 +1013,7 @@ boolean preparefilemenu(boolean samedepth)
if (!dent)
break;
else if (dent->d_name[0]=='.' &&
(dent->d_name[1]=='\0' ||
(dent->d_name[1]=='.' &&
dent->d_name[2]=='\0')))
else if (isuptree(dent->d_name))
continue; // we don't want to scan uptree
strcpy(&menupath[menupathindex[menudepthleft]],dent->d_name);
@ -704,10 +1074,7 @@ boolean preparefilemenu(boolean samedepth)
if (!dent)
break;
else if (dent->d_name[0]=='.' &&
(dent->d_name[1]=='\0' ||
(dent->d_name[1]=='.' &&
dent->d_name[2]=='\0')))
else if (isuptree(dent->d_name))
continue; // we don't want to scan uptree
strcpy(&menupath[menupathindex[menudepthleft]],dent->d_name);
@ -732,6 +1099,10 @@ boolean preparefilemenu(boolean samedepth)
if (ext >= EXT_LOADSTART)
{
size_t i;
if (filenamebuf == NULL)
filenamebuf = calloc(sizeof(char) * MAX_WADPATH, numwadfiles);
for (i = 0; i < numwadfiles; i++)
{
if (!filenamebuf[i][0])
@ -781,6 +1152,12 @@ boolean preparefilemenu(boolean samedepth)
}
}
if (filenamebuf)
{
free(filenamebuf);
filenamebuf = NULL;
}
closedir(dirhandle);
if ((menudepthleft != menudepth-1) // now for UP... entry

View file

@ -7,6 +7,7 @@
#include "doomdef.h"
#include "d_netfil.h"
#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;
@ -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,
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
extern char menupath[1024];
@ -42,9 +53,6 @@ extern size_t dir_on[menudepth];
extern UINT8 refreshdirmenu;
extern char *refreshdirname;
extern size_t packetsizetally;
extern size_t mainwadstally;
typedef enum
{
EXT_FOLDER = 0,
@ -94,5 +102,4 @@ typedef enum
void closefilemenu(boolean validsize);
void searchfilemenu(char *tempname);
boolean preparefilemenu(boolean samedepth);
#endif // __FILESRCH_H__

View file

@ -1680,6 +1680,7 @@ UINT8 G_CmpDemoTime(char *oldname, char *newname)
switch(oldversion) // demoversion
{
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
break;
// 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];
UINT8 cnamelen;
demoghost *gh;
UINT8 flags;
UINT8 flags, subversion;
UINT8 *buffer,*p;
mapthing_t *mthing;
UINT16 count, ghostversion;
@ -2071,7 +2072,7 @@ void G_AddGhost(char *defdemoname)
return;
} p += 12; // DEMOHEADER
p++; // VERSION
p++; // SUBVERSION
subversion = READUINT8(p); // SUBVERSION
ghostversion = READUINT16(p);
switch(ghostversion)
{
@ -2170,9 +2171,19 @@ void G_AddGhost(char *defdemoname)
count = READUINT16(p);
while (count--)
{
SKIPSTRING(p);
SKIPSTRING(p);
p++;
// In 2.2.7 netvar saving was updated
if (subversion < 7)
{
p += 2;
SKIPSTRING(p);
p++;
}
else
{
SKIPSTRING(p);
SKIPSTRING(p);
p++;
}
}
if (*p == DEMOMARKER)
@ -2422,12 +2433,13 @@ ATTRNORETURN void FUNCNORETURN G_StopMetalRecording(boolean kill)
{
WRITEUINT8(demo_p, (kill) ? METALDEATH : DEMOMARKER); // add the demo end (or metal death) marker
WriteDemoChecksum();
saved = FIL_WriteFile(va("%sMS.LMP", G_BuildMapName(gamemap)), demobuffer, demo_p - demobuffer); // finally output the file.
sprintf(demoname, "%sMS.LMP", G_BuildMapName(gamemap));
saved = FIL_WriteFile(va(pandf, srb2home, demoname), demobuffer, demo_p - demobuffer); // finally output the file.
}
free(demobuffer);
metalrecording = false;
if (saved)
I_Error("Saved to %sMS.LMP", G_BuildMapName(gamemap));
I_Error("Saved to %s", demoname);
I_Error("Failed to save demo!");
}

View file

@ -45,6 +45,7 @@
#include "lua_hook.h"
#include "b_bot.h"
#include "m_cond.h" // condition sets
#include "lua_script.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 strafeisturn; // Simple controls only
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);
INT32 *myaiming = (ssplayer == 1 ? &localaiming : &localaiming2);
@ -1139,13 +1140,13 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer)
return;
}
turnright = PLAYERINPUTDOWN(ssplayer, gc_turnright);
turnleft = PLAYERINPUTDOWN(ssplayer, gc_turnleft);
turnright = PLAYERINPUTDOWN(ssplayer, GC_TURNRIGHT);
turnleft = PLAYERINPUTDOWN(ssplayer, GC_TURNLEFT);
straferkey = PLAYERINPUTDOWN(ssplayer, gc_straferight);
strafelkey = PLAYERINPUTDOWN(ssplayer, gc_strafeleft);
movefkey = PLAYERINPUTDOWN(ssplayer, gc_forward);
movebkey = PLAYERINPUTDOWN(ssplayer, gc_backward);
straferkey = PLAYERINPUTDOWN(ssplayer, GC_STRAFERIGHT);
strafelkey = PLAYERINPUTDOWN(ssplayer, GC_STRAFELEFT);
movefkey = PLAYERINPUTDOWN(ssplayer, GC_FORWARD);
movebkey = PLAYERINPUTDOWN(ssplayer, GC_BACKWARD);
if (strafeisturn)
{
@ -1154,7 +1155,7 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer)
straferkey = strafelkey = false;
}
mouseaiming = (PLAYERINPUTDOWN(ssplayer, gc_mouseaiming)) ^
mouseaiming = (PLAYERINPUTDOWN(ssplayer, GC_MOUSEAIMING)) ^
((chasecam && !player->spectator) ? chasefreelook : alwaysfreelook);
analogjoystickmove = 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
if (movefkey || (gamepadjoystickmove && movejoystickvector.yaxis < 0)
|| ((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];
if (movebkey || (gamepadjoystickmove && movejoystickvector.yaxis > 0)
|| ((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];
if (analogjoystickmove && movejoystickvector.yaxis != 0)
@ -1287,9 +1288,9 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer)
if (strafelkey)
side -= sidemove[speed];
if (PLAYERINPUTDOWN(ssplayer, gc_weaponnext))
if (PLAYERINPUTDOWN(ssplayer, GC_WEAPONNEXT))
cmd->buttons |= BT_WEAPONNEXT; // Next Weapon
if (PLAYERINPUTDOWN(ssplayer, gc_weaponprev))
if (PLAYERINPUTDOWN(ssplayer, GC_WEAPONPREV))
cmd->buttons |= BT_WEAPONPREV; // Previous Weapon
#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.
cmd->buttons &= ~BT_WEAPONMASK;
for (i = 0; i < NUM_WEAPONS; ++i)
if (PLAYERINPUTDOWN(ssplayer, gc_wepslot1 + i))
if (PLAYERINPUTDOWN(ssplayer, GC_WEPSLOT1 + i))
{
cmd->buttons |= (UINT16)(i + 1);
break;
@ -1306,34 +1307,34 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer)
// fire with any button/key
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;
// fire normal with any button/key
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;
if (PLAYERINPUTDOWN(ssplayer, gc_tossflag))
if (PLAYERINPUTDOWN(ssplayer, GC_TOSSFLAG))
cmd->buttons |= BT_TOSSFLAG;
// Lua scriptable buttons
if (PLAYERINPUTDOWN(ssplayer, gc_custom1))
if (PLAYERINPUTDOWN(ssplayer, GC_CUSTOM1))
cmd->buttons |= BT_CUSTOM1;
if (PLAYERINPUTDOWN(ssplayer, gc_custom2))
if (PLAYERINPUTDOWN(ssplayer, GC_CUSTOM2))
cmd->buttons |= BT_CUSTOM2;
if (PLAYERINPUTDOWN(ssplayer, gc_custom3))
if (PLAYERINPUTDOWN(ssplayer, GC_CUSTOM3))
cmd->buttons |= BT_CUSTOM3;
// use with any button/key
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;
// Centerview can be a toggle in simple mode!
{
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))
centerviewdown = down;
@ -1432,7 +1433,7 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer)
if (ticcmd_centerviewdown[forplayer] && controlstyle == CS_SIMPLE)
controlstyle = CS_LEGACY;
if (PLAYERINPUTDOWN(ssplayer, gc_camreset))
if (PLAYERINPUTDOWN(ssplayer, GC_CAMRESET))
{
if (thiscam->chase && !resetdown[forplayer])
P_ResetCamera(&players[ssplayer == 1 ? displayplayer : secondarydisplayplayer], thiscam);
@ -1445,7 +1446,7 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer)
// jump button
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;
// 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 (PLAYERINPUTDOWN(ssplayer, gc_lookup) || (gamepadjoystickmove && lookjoystickvector.yaxis < 0))
if (PLAYERINPUTDOWN(ssplayer, GC_LOOKUP) || (gamepadjoystickmove && lookjoystickvector.yaxis < 0))
{
*myaiming += KB_LOOKSPEED * screen_invert;
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;
keyboard_look[forplayer] = true;
@ -1545,22 +1546,12 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer)
cmd->forwardmove = (SINT8)(cmd->forwardmove + forward);
cmd->sidemove = (SINT8)(cmd->sidemove + side);
if (player->bot == 1) { // Tailsbot for P2
if (!player->powers[pw_tailsfly] && (cmd->forwardmove || cmd->sidemove || cmd->buttons))
{
player->bot = 2; // A player-controlled bot. Returns to AI when it respawns.
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
// Note: Majority of botstuffs are handled in G_Ticker now.
if (player->bot == BOT_2PHUMAN) //Player-controlled bot
{
// Fix offset angle for P2-controlled Tailsbot when P2's controls are set to non-Strafe
cmd->angleturn = (INT16)((localangle - *myangle) >> 16);
}
*myangle += (cmd->angleturn<<16);
@ -1968,7 +1959,7 @@ boolean G_Responder(event_t *ev)
if (gameaction == ga_nothing && !singledemo &&
((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();
return true;
@ -2044,7 +2035,7 @@ boolean G_Responder(event_t *ev)
// allow spy mode changes even during the demo
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.
UINT8 canSwitchView = 0;
@ -2117,13 +2108,13 @@ boolean G_Responder(event_t *ev)
switch (ev->type)
{
case ev_keydown:
if (ev->data1 == gamecontrol[gc_pause][0]
|| ev->data1 == gamecontrol[gc_pause][1]
|| ev->data1 == KEY_PAUSE)
if (ev->key == gamecontrol[GC_PAUSE][0]
|| ev->key == gamecontrol[GC_PAUSE][1]
|| ev->key == KEY_PAUSE)
{
if (modeattacking && !demoplayback && (gamestate == GS_LEVEL))
{
pausebreakkey = (ev->data1 == KEY_PAUSE);
pausebreakkey = (ev->key == KEY_PAUSE);
if (menuactive || pausedelay < 0 || leveltime < 2)
return true;
@ -2148,8 +2139,8 @@ boolean G_Responder(event_t *ev)
}
}
}
if (ev->data1 == gamecontrol[gc_camtoggle][0]
|| ev->data1 == gamecontrol[gc_camtoggle][1])
if (ev->key == gamecontrol[GC_CAMTOGGLE][0]
|| ev->key == gamecontrol[GC_CAMTOGGLE][1])
{
if (!camtoggledelay)
{
@ -2157,8 +2148,8 @@ boolean G_Responder(event_t *ev)
CV_SetValue(&cv_chasecam, cv_chasecam.value ? 0 : 1);
}
}
if (ev->data1 == gamecontrolbis[gc_camtoggle][0]
|| ev->data1 == gamecontrolbis[gc_camtoggle][1])
if (ev->key == gamecontrolbis[GC_CAMTOGGLE][0]
|| ev->key == gamecontrolbis[GC_CAMTOGGLE][1])
{
if (!camtoggledelay2)
{
@ -2194,8 +2185,20 @@ boolean G_Responder(event_t *ev)
//
boolean G_LuaResponder(event_t *ev)
{
return (ev->type == ev_keydown && LUA_HookKey(ev->data1, HOOK(KeyDown))) ||
(ev->type == ev_keyup && LUA_HookKey(ev->data1, HOOK(KeyUp)));
boolean cancelled = false;
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 +2210,23 @@ void G_Ticker(boolean run)
UINT32 i;
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
if ((marathonmode & (MA_INIT|MA_INGAME)) == MA_INGAME && gamestate == GS_LEVEL)
marathontime++;
@ -2292,23 +2312,58 @@ void G_Ticker(boolean run)
if (playeringame[i])
{
INT16 received;
// Save last frame's button readings
players[i].lastbuttons = players[i].cmd.buttons;
G_CopyTiccmd(&players[i].cmd, &netcmds[buf][i], 1);
// Bot ticcmd handling
// 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.
// Therefore, this has to be done after ticcmd sends are received.
if (players[i].bot == BOT_2PAI) { // Tailsbot for P2
if (!players[i].powers[pw_tailsfly] && (players[i].cmd.forwardmove || players[i].cmd.sidemove || players[i].cmd.buttons))
{
players[i].bot = BOT_2PHUMAN; // A player-controlled bot. Returns to AI when it respawns.
CV_SetValue(&cv_analog[1], true);
}
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);
}
received = (players[i].cmd.angleturn & TICCMD_RECEIVED);
// 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].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;
players[i].cmd.angleturn &= ~TICCMD_RECEIVED;
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;
// 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 +2549,7 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
tic_t quittime;
boolean spectator;
boolean outofcoop;
boolean removing;
INT16 bot;
SINT8 pity;
INT16 rings;
@ -2510,6 +2566,7 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
quittime = players[player].quittime;
spectator = players[player].spectator;
outofcoop = players[player].outofcoop;
removing = players[player].removing;
pflags = (players[player].pflags & (PF_FLIPCAM|PF_ANALOGMODE|PF_DIRECTIONCHAR|PF_AUTOBRAKE|PF_TAGIT|PF_GAMETYPEOVER));
playerangleturn = players[player].angleturn;
oldrelangleturn = players[player].oldrelangleturn;
@ -2586,6 +2643,7 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
p->quittime = quittime;
p->spectator = spectator;
p->outofcoop = outofcoop;
p->removing = removing;
p->angleturn = playerangleturn;
p->oldrelangleturn = oldrelangleturn;
@ -2630,8 +2688,10 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
p->totalring = totalring;
p->mare = mare;
if (bot)
p->bot = 1; // reset to AI-controlled
if (bot == BOT_2PHUMAN)
p->bot = BOT_2PAI; // reset to AI-controlled
else
p->bot = bot;
p->pity = pity;
p->rings = rings;
p->spheres = spheres;
@ -2977,7 +3037,8 @@ void G_DoReborn(INT32 playernum)
// Make sure objectplace is OFF when you first start the level!
OP_ResetObjectplace();
if (player->bot && playernum != consoleplayer)
// Tailsbot
if (player->bot == BOT_2PAI || player->bot == BOT_2PHUMAN)
{ // Bots respawn next to their master.
mobj_t *oldmo = NULL;
@ -2996,6 +3057,28 @@ void G_DoReborn(INT32 playernum)
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)))
resetlevel = true;
else if ((G_GametypeUsesCoopLives() || G_GametypeUsesCoopStarposts()) && (netgame || multiplayer) && !G_IsSpecialStage(gamemap))
@ -3176,7 +3259,7 @@ void G_AddPlayer(INT32 playernum)
if (!playeringame[i])
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;
countplayers++;
@ -3217,7 +3300,7 @@ boolean G_EnoughPlayersFinished(void)
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;
if (players[i].quittime > 30 * TICRATE)
continue;
@ -5240,4 +5323,3 @@ INT32 G_TicsToMilliseconds(tic_t tics)
{
return (INT32)((tics%TICRATE) * (1000.00f/TICRATE));
}

File diff suppressed because it is too large Load diff

View file

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

View file

@ -245,13 +245,16 @@ void HWR_RenderBatches(void)
currently_batching = false;// no longer collecting batches
if (!polygonArraySize)
{
ps_hw_numpolys = ps_hw_numcalls = ps_hw_numshaders = ps_hw_numtextures = ps_hw_numpolyflags = ps_hw_numcolors = 0;
ps_hw_numpolys.value.i = ps_hw_numcalls.value.i = ps_hw_numshaders.value.i
= ps_hw_numtextures.value.i = ps_hw_numpolyflags.value.i
= ps_hw_numcolors.value.i = 0;
return;// nothing to draw
}
// init stats vars
ps_hw_numpolys = polygonArraySize;
ps_hw_numcalls = ps_hw_numverts = 0;
ps_hw_numshaders = ps_hw_numtextures = ps_hw_numpolyflags = ps_hw_numcolors = 1;
ps_hw_numpolys.value.i = polygonArraySize;
ps_hw_numcalls.value.i = ps_hw_numverts.value.i = 0;
ps_hw_numshaders.value.i = ps_hw_numtextures.value.i
= ps_hw_numpolyflags.value.i = ps_hw_numcolors.value.i = 1;
// init polygonIndexArray
for (i = 0; i < polygonArraySize; i++)
{
@ -259,12 +262,12 @@ void HWR_RenderBatches(void)
}
// sort polygons
ps_hw_batchsorttime = I_GetPreciseTime();
PS_START_TIMING(ps_hw_batchsorttime);
if (cv_glshaders.value && gl_shadersavailable)
qsort(polygonIndexArray, polygonArraySize, sizeof(unsigned int), comparePolygons);
else
qsort(polygonIndexArray, polygonArraySize, sizeof(unsigned int), comparePolygonsNoShaders);
ps_hw_batchsorttime = I_GetPreciseTime() - ps_hw_batchsorttime;
PS_STOP_TIMING(ps_hw_batchsorttime);
// sort order
// 1. shader
// 2. texture
@ -272,7 +275,7 @@ void HWR_RenderBatches(void)
// 4. colors + light level
// not sure about what order of the last 2 should be, or if it even matters
ps_hw_batchdrawtime = I_GetPreciseTime();
PS_START_TIMING(ps_hw_batchdrawtime);
currentShader = polygonArray[polygonIndexArray[0]].shader;
currentTexture = polygonArray[polygonIndexArray[0]].texture;
@ -408,8 +411,8 @@ void HWR_RenderBatches(void)
// execute draw call
HWD.pfnDrawIndexedTriangles(&currentSurfaceInfo, finalVertexArray, finalIndexWritePos, currentPolyFlags, finalVertexIndexArray);
// update stats
ps_hw_numcalls++;
ps_hw_numverts += finalIndexWritePos;
ps_hw_numcalls.value.i++;
ps_hw_numverts.value.i += finalIndexWritePos;
// reset write positions
finalVertexWritePos = 0;
finalIndexWritePos = 0;
@ -426,7 +429,7 @@ void HWR_RenderBatches(void)
currentShader = nextShader;
changeShader = false;
ps_hw_numshaders++;
ps_hw_numshaders.value.i++;
}
if (changeTexture)
{
@ -435,21 +438,21 @@ void HWR_RenderBatches(void)
currentTexture = nextTexture;
changeTexture = false;
ps_hw_numtextures++;
ps_hw_numtextures.value.i++;
}
if (changePolyFlags)
{
currentPolyFlags = nextPolyFlags;
changePolyFlags = false;
ps_hw_numpolyflags++;
ps_hw_numpolyflags.value.i++;
}
if (changeSurfaceInfo)
{
currentSurfaceInfo = nextSurfaceInfo;
changeSurfaceInfo = false;
ps_hw_numcolors++;
ps_hw_numcolors.value.i++;
}
// and that should be it?
}
@ -457,7 +460,7 @@ void HWR_RenderBatches(void)
polygonArraySize = 0;
unsortedVertexArraySize = 0;
ps_hw_batchdrawtime = I_GetPreciseTime() - ps_hw_batchdrawtime;
PS_STOP_TIMING(ps_hw_batchdrawtime);
}

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;
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);
}
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];
FBITFIELD flags;
@ -395,13 +395,19 @@ void HWR_DrawCroppedPatch(patch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscale,
// | /|
// |/ |
// 0--1
float dupx, dupy, fscale, fwidth, fheight;
float dupx, dupy, fscalew, fscaleh, fwidth, fheight;
UINT8 perplayershuffle = 0;
if (alphalevel >= 10 && alphalevel < 13)
return;
// make patch ready in hardware cache
HWR_GetPatch(gpatch);
if (!colormap)
HWR_GetPatch(gpatch);
else
HWR_GetMappedPatch(gpatch, colormap);
hwrPatch = ((GLPatch_t *)gpatch->hardware);
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);
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;
cx -= (float)(gpatch->leftoffset) * fscale;
if (splitscreen && (option & V_PERPLAYER))
{
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))
{
@ -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));
else if (!(option & V_SNAPTOLEFT))
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)
{
@ -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));
else if (!(option & V_SNAPTOTOP))
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;
fheight = h;
fwidth = FIXED_TO_FLOAT(w);
fheight = FIXED_TO_FLOAT(h);
if (sx + w > gpatch->width)
fwidth = gpatch->width - sx;
if (sx + w > gpatch->width<<FRACBITS)
fwidth = FIXED_TO_FLOAT((gpatch->width<<FRACBITS) - sx);
if (sy + h > gpatch->height)
fheight = gpatch->height - sy;
if (sy + h > gpatch->height<<FRACBITS)
fheight = FIXED_TO_FLOAT((gpatch->height<<FRACBITS) - sy);
if (pscale != FRACUNIT)
if (pscale != FRACUNIT || vscale != FRACUNIT || (splitscreen && option & V_PERPLAYER))
{
fwidth *= fscale * dupx;
fheight *= fscale * dupy;
fwidth *= fscalew * dupx;
fheight *= fscaleh * dupy;
}
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].s = v[3].s = ((sx)/(float)(gpatch->width))*hwrPatch->max_s;
if (sx + w > gpatch->width)
v[0].s = v[3].s = (FIXED_TO_FLOAT(sx)/(float)(gpatch->width))*hwrPatch->max_s;
if (sx + w > gpatch->width<<FRACBITS)
v[2].s = v[1].s = hwrPatch->max_s;
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;
if (sy + h > gpatch->height)
v[0].t = v[1].t = (FIXED_TO_FLOAT(sy)/(float)(gpatch->height))*hwrPatch->max_t;
if (sy + h > gpatch->height<<FRACBITS)
v[2].t = v[3].t = hwrPatch->max_t;
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;
@ -514,6 +596,76 @@ void HWR_DrawCroppedPatch(patch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscale,
if (option & V_WRAPY)
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
if (alphalevel)
{

View file

@ -147,22 +147,22 @@ static angle_t gl_aimingangle;
static void HWR_SetTransformAiming(FTransform *trans, player_t *player, boolean skybox);
// Render stats
precise_t ps_hw_skyboxtime = 0;
precise_t ps_hw_nodesorttime = 0;
precise_t ps_hw_nodedrawtime = 0;
precise_t ps_hw_spritesorttime = 0;
precise_t ps_hw_spritedrawtime = 0;
ps_metric_t ps_hw_skyboxtime = {0};
ps_metric_t ps_hw_nodesorttime = {0};
ps_metric_t ps_hw_nodedrawtime = {0};
ps_metric_t ps_hw_spritesorttime = {0};
ps_metric_t ps_hw_spritedrawtime = {0};
// Render stats for batching
int ps_hw_numpolys = 0;
int ps_hw_numverts = 0;
int ps_hw_numcalls = 0;
int ps_hw_numshaders = 0;
int ps_hw_numtextures = 0;
int ps_hw_numpolyflags = 0;
int ps_hw_numcolors = 0;
precise_t ps_hw_batchsorttime = 0;
precise_t ps_hw_batchdrawtime = 0;
ps_metric_t ps_hw_numpolys = {0};
ps_metric_t ps_hw_numverts = {0};
ps_metric_t ps_hw_numcalls = {0};
ps_metric_t ps_hw_numshaders = {0};
ps_metric_t ps_hw_numtextures = {0};
ps_metric_t ps_hw_numpolyflags = {0};
ps_metric_t ps_hw_numcolors = {0};
ps_metric_t ps_hw_batchsorttime = {0};
ps_metric_t ps_hw_batchdrawtime = {0};
boolean gl_init = false;
boolean gl_maploaded = false;
@ -3235,7 +3235,7 @@ static void HWR_Subsector(size_t num)
}
// for render stats
ps_numpolyobjects += numpolys;
ps_numpolyobjects.value.i += numpolys;
// Sort polyobjects
R_SortPolyObjects(sub);
@ -3343,7 +3343,7 @@ static void HWR_RenderBSPNode(INT32 bspnum)
// Decide which side the view point is on
INT32 side;
ps_numbspcalls++;
ps_numbspcalls.value.i++;
// Found a subsector?
if (bspnum & NF_SUBSECTOR)
@ -4718,7 +4718,7 @@ static void HWR_CreateDrawNodes(void)
// that is already lying around. This should all be in some sort of linked list or lists.
sortindex = Z_Calloc(sizeof(size_t) * (numplanes + numpolyplanes + numwalls), PU_STATIC, NULL);
ps_hw_nodesorttime = I_GetPreciseTime();
PS_START_TIMING(ps_hw_nodesorttime);
for (i = 0; i < numplanes; i++, p++)
{
@ -4738,7 +4738,7 @@ static void HWR_CreateDrawNodes(void)
sortindex[p] = p;
}
ps_numdrawnodes = p;
ps_numdrawnodes.value.i = p;
// p is the number of stuff to sort
@ -4773,9 +4773,9 @@ static void HWR_CreateDrawNodes(void)
}
}
ps_hw_nodesorttime = I_GetPreciseTime() - ps_hw_nodesorttime;
PS_STOP_TIMING(ps_hw_nodesorttime);
ps_hw_nodedrawtime = I_GetPreciseTime();
PS_START_TIMING(ps_hw_nodedrawtime);
// Okay! Let's draw it all! Woo!
HWD.pfnSetTransform(&atransform);
@ -4812,7 +4812,7 @@ static void HWR_CreateDrawNodes(void)
}
}
ps_hw_nodedrawtime = I_GetPreciseTime() - ps_hw_nodedrawtime;
PS_STOP_TIMING(ps_hw_nodedrawtime);
numwalls = 0;
numplanes = 0;
@ -6095,10 +6095,10 @@ void HWR_RenderPlayerView(INT32 viewnumber, player_t *player)
if (viewnumber == 0) // Only do it if it's the first screen being rendered
HWD.pfnClearBuffer(true, false, &ClearColor); // Clear the Color Buffer, stops HOMs. Also seems to fix the skybox issue on Intel GPUs.
ps_hw_skyboxtime = I_GetPreciseTime();
PS_START_TIMING(ps_hw_skyboxtime);
if (skybox && drawsky) // If there's a skybox and we should be drawing the sky, draw the skybox
HWR_RenderSkyboxView(viewnumber, player); // This is drawn before everything else so it is placed behind
ps_hw_skyboxtime = I_GetPreciseTime() - ps_hw_skyboxtime;
PS_STOP_TIMING(ps_hw_skyboxtime);
{
// do we really need to save player (is it not the same)?
@ -6208,9 +6208,9 @@ void HWR_RenderPlayerView(INT32 viewnumber, player_t *player)
// Reset the shader state.
HWR_SetShaderState();
ps_numbspcalls = 0;
ps_numpolyobjects = 0;
ps_bsptime = I_GetPreciseTime();
ps_numbspcalls.value.i = 0;
ps_numpolyobjects.value.i = 0;
PS_START_TIMING(ps_bsptime);
validcount++;
@ -6248,7 +6248,7 @@ void HWR_RenderPlayerView(INT32 viewnumber, player_t *player)
}
#endif
ps_bsptime = I_GetPreciseTime() - ps_bsptime;
PS_STOP_TIMING(ps_bsptime);
if (cv_glbatching.value)
HWR_RenderBatches();
@ -6263,22 +6263,22 @@ void HWR_RenderPlayerView(INT32 viewnumber, player_t *player)
#endif
// Draw MD2 and sprites
ps_numsprites = gl_visspritecount;
ps_hw_spritesorttime = I_GetPreciseTime();
ps_numsprites.value.i = gl_visspritecount;
PS_START_TIMING(ps_hw_spritesorttime);
HWR_SortVisSprites();
ps_hw_spritesorttime = I_GetPreciseTime() - ps_hw_spritesorttime;
ps_hw_spritedrawtime = I_GetPreciseTime();
PS_STOP_TIMING(ps_hw_spritesorttime);
PS_START_TIMING(ps_hw_spritedrawtime);
HWR_DrawSprites();
ps_hw_spritedrawtime = I_GetPreciseTime() - ps_hw_spritedrawtime;
PS_STOP_TIMING(ps_hw_spritedrawtime);
#ifdef NEWCORONAS
//Hurdler: they must be drawn before translucent planes, what about gl fog?
HWR_DrawCoronas();
#endif
ps_numdrawnodes = 0;
ps_hw_nodesorttime = 0;
ps_hw_nodedrawtime = 0;
ps_numdrawnodes.value.i = 0;
ps_hw_nodesorttime.value.p = 0;
ps_hw_nodedrawtime.value.p = 0;
if (numplanes || numpolyplanes || numwalls) //Hurdler: render 3D water and transparent walls after everything
{
HWR_CreateDrawNodes();
@ -6767,7 +6767,7 @@ void HWR_LoadAllCustomShaders(void)
// read every custom shader
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)

View file

@ -20,6 +20,8 @@
#include "../d_player.h"
#include "../r_defs.h"
#include "../m_perfstats.h"
// Startup & Shutdown the hardware mode renderer
void HWR_Startup(void);
void HWR_Switch(void);
@ -39,7 +41,7 @@ void HWR_InitTextureMapping(void);
void HWR_SetViewSize(void);
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_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_CreatePlanePolygons(INT32 bspnum);
void HWR_CreateStaticLightmaps(INT32 bspnum);
@ -116,22 +118,22 @@ extern FTransform atransform;
// Render stats
extern precise_t ps_hw_skyboxtime;
extern precise_t ps_hw_nodesorttime;
extern precise_t ps_hw_nodedrawtime;
extern precise_t ps_hw_spritesorttime;
extern precise_t ps_hw_spritedrawtime;
extern ps_metric_t ps_hw_skyboxtime;
extern ps_metric_t ps_hw_nodesorttime;
extern ps_metric_t ps_hw_nodedrawtime;
extern ps_metric_t ps_hw_spritesorttime;
extern ps_metric_t ps_hw_spritedrawtime;
// Render stats for batching
extern int ps_hw_numpolys;
extern int ps_hw_numverts;
extern int ps_hw_numcalls;
extern int ps_hw_numshaders;
extern int ps_hw_numtextures;
extern int ps_hw_numpolyflags;
extern int ps_hw_numcolors;
extern precise_t ps_hw_batchsorttime;
extern precise_t ps_hw_batchdrawtime;
extern ps_metric_t ps_hw_numpolys;
extern ps_metric_t ps_hw_numverts;
extern ps_metric_t ps_hw_numcalls;
extern ps_metric_t ps_hw_numshaders;
extern ps_metric_t ps_hw_numtextures;
extern ps_metric_t ps_hw_numpolyflags;
extern ps_metric_t ps_hw_numcolors;
extern ps_metric_t ps_hw_batchsorttime;
extern ps_metric_t ps_hw_batchdrawtime;
extern boolean gl_init;
extern boolean gl_maploaded;

View file

@ -62,6 +62,9 @@ static FBITFIELD CurrentPolyFlags;
static FTextureInfo *TexCacheTail = NULL;
static FTextureInfo *TexCacheHead = NULL;
static RGBA_t *textureBuffer = NULL;
static size_t textureBufferSize = 0;
RGBA_t myPaletteData[256];
GLint screen_width = 0; // used by Draw2DLine()
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,
// : else do nothing
// Returns :
// -----------------+
#ifdef DEBUG_TO_FILE
@ -159,8 +161,6 @@ FUNCPRINTF void GL_DBG_Printf(const char *format, ...)
// -----------------+
// GL_MSG_Warning : Raises a warning.
// :
// Returns :
// -----------------+
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.
// :
// Returns :
// -----------------+
static void GL_MSG_Error(const char *format, ...)
@ -1345,6 +1343,10 @@ void Flush(void)
TexCacheTail = TexCacheHead = NULL; //Hurdler: well, TexCacheHead is already NULL
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
// Returns :
// -----------------+
EXPORT boolean HWRAPI(Init) (void)
{
@ -1738,37 +1739,48 @@ EXPORT void HWRAPI(SetBlend) (FBITFIELD 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)
{
// Download a mipmap
boolean updatemipmap = true;
static RGBA_t tex[2048*2048];
const GLvoid *ptex = tex;
INT32 w, h;
GLuint texnum = 0;
// Upload a texture
GLuint num = pTexInfo->downloaded;
boolean update = true;
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);
pTexInfo->downloaded = texnum;
updatemipmap = false;
pglGenTextures(1, &num);
pTexInfo->downloaded = num;
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;
h = pTexInfo->height;
if ((pTexInfo->format == GL_TEXFMT_P_8) ||
(pTexInfo->format == GL_TEXFMT_AP_88))
if ((pTexInfo->format == GL_TEXFMT_P_8) || (pTexInfo->format == GL_TEXFMT_AP_88))
{
const GLubyte *pImgData = (const GLubyte *)pTexInfo->data;
INT32 i, j;
AllocTextureBuffer(pTexInfo);
ptex = tex = textureBuffer;
for (j = 0; j < h; j++)
{
@ -1799,20 +1811,18 @@ EXPORT void HWRAPI(UpdateTexture) (GLMipmap_t *pTexInfo)
tex[w*j+i].s.alpha = *pImgData;
pImgData++;
}
}
}
}
else if (pTexInfo->format == GL_TEXFMT_RGBA)
{
// corona test : passed as ARGB 8888, which is not in glide formats
// Hurdler: not used for coronas anymore, just for dynamic lighting
ptex = pTexInfo->data;
// Directly upload the texture data without any kind of conversion.
ptex = pImgData;
}
else if (pTexInfo->format == GL_TEXFMT_ALPHA_INTENSITY_88)
{
const GLubyte *pImgData = (const GLubyte *)pTexInfo->data;
INT32 i, j;
AllocTextureBuffer(pTexInfo);
ptex = tex = textureBuffer;
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
{
const GLubyte *pImgData = (const GLubyte *)pTexInfo->data;
INT32 i, j;
AllocTextureBuffer(pTexInfo);
ptex = tex = textureBuffer;
for (j = 0; j < h; j++)
{
@ -1845,11 +1855,10 @@ EXPORT void HWRAPI(UpdateTexture) (GLMipmap_t *pTexInfo)
}
}
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, texnum);
tex_downloaded = texnum;
pglBindTexture(GL_TEXTURE_2D, num);
tex_downloaded = num;
// disable texture filtering on any texture that has holes so there's no dumb borders or blending issues
if (pTexInfo->flags & TF_TRANSPARENT)
@ -1878,7 +1887,7 @@ EXPORT void HWRAPI(UpdateTexture) (GLMipmap_t *pTexInfo)
}
else
{
if (updatemipmap)
if (update)
pglTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, ptex);
else
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
{
if (updatemipmap)
if (update)
pglTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, ptex);
else
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
{
if (updatemipmap)
if (update)
pglTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, ptex);
else
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 &= 7; // currently only to blink chat input cursor
if (PLAYER1INPUTDOWN(gc_scores))
if (PLAYER1INPUTDOWN(GC_SCORES))
hu_showscores = !chat_on;
else
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...)
// (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;
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;
}
if (i == num_gamecontrols)
if (i == NUM_GAMECONTROLS)
return false;
}*/ //We don't actually care about that unless we get splitscreen netgames. :V
#ifndef NONET
c = (INT32)ev->data1;
c = (INT32)ev->key;
if (!chat_on)
{
// 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.
{
chat_on = true;
@ -1140,7 +1140,7 @@ boolean HU_Responder(event_t *ev)
typelines = 1;
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)
{
chat_on = true;
@ -1157,12 +1157,12 @@ boolean HU_Responder(event_t *ev)
// Ignore modifier keys
// Note that we do this here so users can still set
// their chat keys to one of these, if they so desire.
if (ev->data1 == KEY_LSHIFT || ev->data1 == KEY_RSHIFT
|| ev->data1 == KEY_LCTRL || ev->data1 == KEY_RCTRL
|| ev->data1 == KEY_LALT || ev->data1 == KEY_RALT)
if (ev->key == KEY_LSHIFT || ev->key == KEY_RSHIFT
|| ev->key == KEY_LCTRL || ev->key == KEY_RCTRL
|| ev->key == KEY_LALT || ev->key == KEY_RALT)
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!
// shift LETTERS to uppercase if we have capslock or are holding shift
@ -1234,8 +1234,8 @@ boolean HU_Responder(event_t *ev)
I_UpdateMouseGrab();
}
else if (c == KEY_ESCAPE
|| ((c == gamecontrol[gc_talkkey][0] || c == gamecontrol[gc_talkkey][1]
|| c == gamecontrol[gc_teamkey][0] || c == gamecontrol[gc_teamkey][1])
|| ((c == gamecontrol[GC_TALKKEY][0] || c == gamecontrol[GC_TALKKEY][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.
{
chat_on = false;
@ -2104,7 +2104,7 @@ void HU_Drawer(void)
}
else
HU_DrawCoopOverlay();
LUAh_ScoresHUD();
LUA_HUDHOOK(scores);
}
if (gamestate != GS_LEVEL)

View file

@ -50,7 +50,7 @@ tic_t I_GetTime(void);
*/
precise_t I_GetPreciseTime(void);
/** \brief Returns the difference between precise times as microseconds.
/** \brief Converts a precise_t to microseconds and casts it to a 32 bit integer.
*/
int I_PreciseToMicros(precise_t);
@ -318,10 +318,6 @@ void I_RegisterSysCommands(void);
*/
void I_GetCursorPosition(INT32 *x, INT32 *y);
/** \brief Returns whether the mouse is grabbed
*/
boolean I_GetMouseGrab(void);
/** \brief Sets whether the mouse is grabbed
*/
void I_SetMouseGrab(boolean grab);

View file

@ -2069,7 +2069,7 @@ state_t states[NUMSTATES] =
{SPR_TVFL, 2, 18, {A_GiveShield}, SH_FLAMEAURA, 0, S_NULL}, // S_FLAMEAURA_ICON2
{SPR_TVBB, FF_ANIMATE|2, 18, {NULL}, 3, 4, S_BUBBLEWRAP_ICON2}, // S_BUBBLEWRAP_ICON1
{SPR_TVBB, 2, 18, {A_GiveShield}, SH_BUBBLEWRAP, 0, S_NULL}, // S_BUBBLERWAP_ICON2
{SPR_TVBB, 2, 18, {A_GiveShield}, SH_BUBBLEWRAP, 0, S_NULL}, // S_BUBBLEWRAP_ICON2
{SPR_TVZP, FF_ANIMATE|2, 18, {NULL}, 3, 4, S_THUNDERCOIN_ICON2}, // S_THUNDERCOIN_ICON1
{SPR_TVZP, 2, 18, {A_GiveShield}, SH_THUNDERCOIN, 0, S_NULL}, // S_THUNDERCOIN_ICON2
@ -5199,7 +5199,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
24*FRACUNIT, // radius
34*FRACUNIT, // height
0, // display offset
100, // mass
DMG_FIRE, // mass
0, // damage
sfx_None, // activesound
MF_NOGRAVITY|MF_NOBLOCKMAP|MF_FIRE|MF_PAIN, // flags
@ -7974,7 +7974,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
8*FRACUNIT, // radius
32*FRACUNIT, // height
0, // display offset
4, // mass
DMG_SPIKE, // mass
0, // damage
sfx_None, // activesound
MF_NOBLOCKMAP|MF_SCENERY|MF_NOCLIPHEIGHT, // flags
@ -8001,7 +8001,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
16*FRACUNIT, // radius
14*FRACUNIT, // height
0, // display offset
4, // mass
DMG_SPIKE, // mass
0, // damage
sfx_None, // activesound
MF_NOBLOCKMAP|MF_NOGRAVITY|MF_SCENERY|MF_NOCLIPHEIGHT|MF_PAPERCOLLISION, // flags
@ -11430,7 +11430,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
17*FRACUNIT, // radius
34*FRACUNIT, // height
1, // display offset
0, // mass
DMG_SPIKE, // mass
1, // damage
sfx_s3kc9s, //sfx_mswing, -- activesound
MF_SCENERY|MF_PAIN|MF_NOGRAVITY, // flags
@ -11457,7 +11457,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
34*FRACUNIT, // radius
68*FRACUNIT, // height
1, // display offset
0, // mass
DMG_SPIKE, // mass
1, // damage
sfx_s3kc9s, //sfx_mswing, -- activesound
MF_SCENERY|MF_PAIN|MF_NOGRAVITY, // flags
@ -13401,7 +13401,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
30*FRACUNIT, // radius
48*FRACUNIT, // height
0, // display offset
100, // mass
DMG_FIRE, // mass
0, // damage
sfx_None, // activesound
MF_SPECIAL|MF_PAIN|MF_NOGRAVITY|MF_FIRE, // flags
@ -13806,7 +13806,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
8*FRACUNIT, // radius
32*FRACUNIT, // height
0, // display offset
0, // mass
0, // mass
0, // damage
sfx_None, // activesound
MF_NOGRAVITY|MF_PAIN, // flags
@ -20380,7 +20380,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
18*FRACUNIT, // radius
28*FRACUNIT, // height
0, // display offset
0, // mass
DMG_SPIKE, // mass
0, // damage
sfx_None, // activesound
MF_NOGRAVITY|MF_PAIN, // flags

View file

@ -29,6 +29,9 @@
#include "d_netcmd.h" // IsPlayerAdmin
#include "m_menu.h" // Player Setup menu color stuff
#include "m_misc.h" // M_MapNumber
#include "b_bot.h" // B_UpdateBotleader
#include "d_clisrv.h" // CL_RemovePlayer
#include "i_system.h" // I_GetPreciseTime, I_PreciseToMicros
#include "lua_script.h"
#include "lua_libs.h"
@ -185,6 +188,8 @@ static const struct {
{META_MAPHEADER, "mapheader_t"},
{META_POLYOBJ, "polyobj_t"},
{META_POLYOBJVERTICES, "polyobj_t.vertices"},
{META_POLYOBJLINES, "polyobj_t.lines"},
{META_CVAR, "consvar_t"},
@ -214,6 +219,7 @@ static const struct {
{META_LUABANKS, "luabanks[]"},
{META_KEYEVENT, "keyevent_t"},
{META_MOUSE, "mouse_t"},
{NULL, NULL}
};
@ -1883,6 +1889,37 @@ static int lib_pDoSpring(lua_State *L)
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
////////////
@ -3397,6 +3434,111 @@ static int lib_gAddGametype(lua_State *L)
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)
{
if (ISINLEVEL)
@ -3738,6 +3880,12 @@ static int lib_gTicsToMilliseconds(lua_State *L)
return 1;
}
static int lib_getTimeMicros(lua_State *L)
{
lua_pushinteger(L, I_PreciseToMicros(I_GetPreciseTime()));
return 1;
}
static luaL_Reg lib[] = {
{"print", lib_print},
{"chatprint", lib_chatprint},
@ -3881,6 +4029,8 @@ static luaL_Reg lib[] = {
{"P_FloorzAtPos",lib_pFloorzAtPos},
{"P_CeilingzAtPos",lib_pCeilingzAtPos},
{"P_DoSpring",lib_pDoSpring},
{"P_TryCameraMove", lib_pTryCameraMove},
{"P_TeleportCameraMove", lib_pTeleportCameraMove},
// p_inter
{"P_RemoveShield",lib_pRemoveShield},
@ -3983,6 +4133,8 @@ static luaL_Reg lib[] = {
// g_game
{"G_AddGametype", lib_gAddGametype},
{"G_AddPlayer", lib_gAddPlayer},
{"G_RemovePlayer", lib_gRemovePlayer},
{"G_BuildMapName",lib_gBuildMapName},
{"G_BuildMapTitle",lib_gBuildMapTitle},
{"G_FindMap",lib_gFindMap},
@ -4008,6 +4160,8 @@ static luaL_Reg lib[] = {
{"G_TicsToCentiseconds",lib_gTicsToCentiseconds},
{"G_TicsToMilliseconds",lib_gTicsToMilliseconds},
{"getTimeMicros",lib_getTimeMicros},
{NULL, NULL}
};

View file

@ -433,7 +433,7 @@ static int CVarSetFunction
consvar_t *cvar = *(consvar_t **)luaL_checkudata(L, 1, META_CVAR);
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))
{

View file

@ -13,6 +13,7 @@
#include "r_defs.h"
#include "d_player.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
@ -78,6 +79,13 @@ automatically.
X (LinedefExecute),\
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
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 HOOK(name) hook_ ## name
#define HUD_HOOK(name) hudhook_ ## name
#define STRING_HOOK(name) stringhook_ ## name
enum { MOBJ_HOOK_LIST (MOBJ_HOOK) MOBJ_HOOK(MAX) };
enum { HOOK_LIST (HOOK) HOOK(MAX) };
enum { STRING_HOOK_LIST (STRING_HOOK) STRING_HOOK(MAX) };
#define ENUM(X) enum { X ## _LIST (X) X(MAX) }
ENUM (MOBJ_HOOK);
ENUM (HOOK);
ENUM (HUD_HOOK);
ENUM (STRING_HOOK);
#undef ENUM
/* dead simple, LUA_HOOK(GameQuit) */
#define LUA_HOOK(type) LUA_HookVoid(HOOK(type))
#define LUA_HUDHOOK(type) LUA_HookHUD(HUD_HOOK(type))
extern boolean hook_cmd_running;
void LUA_HookVoid(int hook);
void LUA_HookHUD(int hook);
int LUA_HookMobj(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);
int LUA_HookPlayer(player_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);
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_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_HookMobjMoveBlocked(mobj_t *, mobj_t *, line_t *);
int LUA_HookBotAI(mobj_t *sonic, mobj_t *tails, ticcmd_t *cmd);
void LUA_HookLinedefExecute(line_t *, mobj_t *, sector_t *);
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 *);
fixed_t LUA_HookPlayerHeight(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
========================================================================= */
static const char * const mobjHookNames[] = { MOBJ_HOOK_LIST (TOSTR) NULL };
static const char * const hookNames[] = { HOOK_LIST (TOSTR) NULL };
#define LIST(id, M) \
static const char * const id [] = { M (TOSTR) NULL }
static const char * const stringHookNames[] = {
STRING_HOOK_LIST (TOSTR) NULL
};
LIST (mobjHookNames, MOBJ_HOOK_LIST);
LIST (hookNames, HOOK_LIST);
LIST (hudHookNames, HUD_HOOK_LIST);
LIST (stringHookNames, STRING_HOOK_LIST);
#undef LIST
typedef struct {
int numHooks;
@ -49,6 +52,7 @@ typedef struct {
} stringhook_t;
static hook_t hookIds[HOOK(MAX)];
static hook_t hudHookIds[HUD_HOOK(MAX)];
static hook_t mobjHookIds[NUMMOBJTYPES][MOBJ_HOOK(MAX)];
// 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.
static int * hookRefs;
static int nextid;
// After a hook errors once, don't print the error again.
static UINT8 * hooksErrored;
@ -104,13 +109,13 @@ static void get_table(lua_State *L)
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);
}
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];
@ -146,33 +151,54 @@ static void add_string_hook(lua_State *L, int type, int id)
{
lua_pushstring(L, string);
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
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,
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);
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.)
static int lib_addHook(lua_State *L)
{
static int nextid;
const char * name;
int type;
@ -185,34 +211,26 @@ static int lib_addHook(lua_State *L)
/* this is a very special case */
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))
{
add_mobj_hook(L, type, nextid);
add_mobj_hook(L, type);
}
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
{
return luaL_argerror(L, 1, lua_pushfstring(L, "invalid hook " LUA_QS, name));
}
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, 2);/* the function */
hookRefs[nextid++] = luaL_ref(L, LUA_REGISTRYINDEX);
add_hook_ref(L, 2);/* the function */
return 0;
}
@ -227,6 +245,23 @@ int LUA_HookLib(lua_State *L)
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 void (*Hook_Callback)(Hook_State *);
@ -259,11 +294,16 @@ static void push_string(void)
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);
push_error_handler();
return true;
}
static boolean init_hook_type
@ -279,10 +319,11 @@ static boolean init_hook_type
if (nonzero)
{
start_hook_stack();
hook->hook_type = hook_type;
hook->mobj_type = mobj_type;
hook->string = string;
return start_hook_stack();
return begin_hook_values(hook);
}
else
return false;
@ -323,7 +364,7 @@ static boolean prepare_string_hook
stringHooks[hook_type].ref))
{
lua_pushstring(gL, string);
return true;
return begin_hook_values(hook);
}
else
return false;
@ -332,12 +373,12 @@ static boolean prepare_string_hook
static void init_hook_call
(
Hook_State * hook,
int values,
int results,
Hook_Callback results_handler
){
hook->top = lua_gettop(gL);
hook->values = values;
const int top = lua_gettop(gL);
hook->values = (top - hook->top);
hook->top = top;
hook->results = results;
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
(
Hook_State * hook,
int values,
int results,
Hook_Callback results_handler
){
int calls = 0;
init_hook_call(hook, values, results, results_handler);
init_hook_call(hook, results, results_handler);
if (hook->string)
{
@ -465,7 +505,7 @@ static int call_hooks
calls += call_mobj_type_hooks(hook, MT_NULL);
calls += call_mobj_type_hooks(hook, hook->mobj_type);
ps_lua_mobjhooks += calls;
ps_lua_mobjhooks.value.i += calls;
}
else
calls += call_mapped(hook, &hookIds[hook->hook_type]);
@ -514,7 +554,7 @@ int LUA_HookMobj(mobj_t *mobj, int hook_type)
if (prepare_mobj_hook(&hook, false, hook_type, mobj->type))
{
LUA_PushUserdata(gL, mobj, META_MOBJ);
call_hooks(&hook, 1, 1, res_true);
call_hooks(&hook, 1, res_true);
}
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, t2, META_MOBJ);
call_hooks(&hook, 2, 1, res_force);
call_hooks(&hook, 1, res_force);
}
return hook.status;
}
@ -535,7 +575,7 @@ void LUA_HookVoid(int type)
{
Hook_State hook;
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)
@ -544,7 +584,7 @@ void LUA_HookInt(INT32 number, int hook_type)
if (prepare_hook(&hook, 0, hook_type))
{
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))
{
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))
{
LUA_PushUserdata(gL, player, META_PLAYER);
call_hooks(&hook, 1, 1, res_true);
call_hooks(&hook, 1, res_true);
}
return hook.status;
}
@ -580,7 +620,7 @@ int LUA_HookTiccmd(player_t *player, ticcmd_t *cmd, int hook_type)
if (hook_type == HOOK(PlayerCmd))
hook_cmd_running = true;
call_hooks(&hook, 2, 1, res_true);
call_hooks(&hook, 1, res_true);
if (hook_type == HOOK(PlayerCmd))
hook_cmd_running = false;
@ -588,6 +628,35 @@ int LUA_HookTiccmd(player_t *player, ticcmd_t *cmd, int hook_type)
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
========================================================================= */
@ -607,7 +676,7 @@ void LUA_HookThinkFrame(void)
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)
{
@ -642,7 +711,7 @@ int LUA_HookMobjLineCollide(mobj_t *mobj, line_t *line)
{
LUA_PushUserdata(gL, mobj, META_MOBJ);
LUA_PushUserdata(gL, line, META_LINE);
call_hooks(&hook, 2, 1, res_force);
call_hooks(&hook, 1, res_force);
}
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, toucher, META_MOBJ);
call_hooks(&hook, 2, 1, res_true);
call_hooks(&hook, 1, res_true);
}
return hook.status;
}
@ -667,7 +736,6 @@ static int damage_hook
INT32 damage,
UINT8 damagetype,
int hook_type,
int values,
Hook_Callback results_handler
){
Hook_State hook;
@ -676,10 +744,10 @@ static int damage_hook
LUA_PushUserdata(gL, target, META_MOBJ);
LUA_PushUserdata(gL, inflictor, META_MOBJ);
LUA_PushUserdata(gL, source, META_MOBJ);
if (values == 5)
if (hook_type != MOBJ_HOOK(MobjDeath))
lua_pushinteger(gL, damage);
lua_pushinteger(gL, damagetype);
call_hooks(&hook, values, 1, results_handler);
call_hooks(&hook, 1, results_handler);
}
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)
{
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)
{
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)
{
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 {
@ -772,7 +853,7 @@ int LUA_HookBotAI(mobj_t *sonic, mobj_t *tails, ticcmd_t *cmd)
hook.userdata = &botai;
call_hooks(&hook, 2, 8, res_botai);
call_hooks(&hook, 8, res_botai);
}
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, mo, META_MOBJ);
LUA_PushUserdata(gL, sector, META_SECTOR);
ps_lua_mobjhooks += call_hooks(&hook, 3, 0, res_none);
ps_lua_mobjhooks.value.i += 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_pushstring(gL, msg); // msg
call_hooks(&hook, 4, 1, res_true);
call_hooks(&hook, 1, res_true);
}
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, source, META_MOBJ);
lua_pushinteger(gL, damagetype);
call_hooks(&hook, 4, 1, res_true);
call_hooks(&hook, 1, res_true);
}
return hook.status;
}
@ -844,12 +925,14 @@ void LUA_HookNetArchive(lua_CFunction archFunc)
push_error_handler();
lua_insert(gL, EINDEX);
begin_hook_values(&hook);
// tables becomes an upvalue of archFunc
lua_pushvalue(gL, -1);
lua_pushcclosure(gL, archFunc, 1);
// stack: tables, archFunc
init_hook_call(&hook, 1, 0, res_none);
init_hook_call(&hook, 0, res_none);
call_mapped(&hook, map);
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, mthing, META_MAPTHING);
call_hooks(&hook, 2, 1, res_true);
call_hooks(&hook, 1, res_true);
}
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, mobj, META_MOBJ);
call_hooks(&hook, 2, 1, res_true);
call_hooks(&hook, 1, res_true);
}
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, mobj, META_MOBJ);
call_hooks(&hook, 2, 1, res_force);
call_hooks(&hook, 1, res_force);
}
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_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, tryingautobalance);
lua_pushboolean(gL, tryingscramble);
call_hooks(&hook, 5, 1, res_false);
call_hooks(&hook, 1, res_false);
}
return hook.status;
}
@ -930,7 +1013,7 @@ int LUA_HookViewpointSwitch(player_t *player, player_t *newdisplayplayer, boolea
lua_pushboolean(gL, forced);
hud_running = true; // local hook
call_hooks(&hook, 3, 1, res_force);
call_hooks(&hook, 1, res_force);
hud_running = false;
}
return hook.status;
@ -945,7 +1028,7 @@ int LUA_HookSeenPlayer(player_t *player, player_t *seenfriend)
LUA_PushUserdata(gL, seenfriend, META_PLAYER);
hud_running = true; // local hook
call_hooks(&hook, 2, 1, res_false);
call_hooks(&hook, 1, res_false);
hud_running = false;
}
return hook.status;
@ -961,7 +1044,7 @@ int LUA_HookShouldJingleContinue(player_t *player, const char *musname)
push_string();
hud_running = true; // local hook
call_hooks(&hook, 2, 1, res_true);
call_hooks(&hook, 1, res_true);
hud_running = false;
}
return hook.status;
@ -1027,7 +1110,8 @@ int LUA_HookMusicChange(const char *oldname, struct MusicChange *param)
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;
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)))
{
LUA_PushUserdata(gL, player, META_PLAYER);
call_hooks(&hook, 1, 1, res_playerheight);
call_hooks(&hook, 1, res_playerheight);
}
return hook.status;
}
@ -1084,18 +1168,7 @@ int LUA_HookPlayerCanEnterSpinGaps(player_t *player)
if (prepare_hook(&hook, 0, HOOK(PlayerCanEnterSpinGaps)))
{
LUA_PushUserdata(gL, player, META_PLAYER);
call_hooks(&hook, 1, 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);
call_hooks(&hook, 1, res_force);
}
return hook.status;
}

View file

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

View file

@ -23,18 +23,18 @@
#include "v_video.h"
#include "w_wad.h"
#include "z_zone.h"
#include "y_inter.h"
#include "lua_script.h"
#include "lua_libs.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!");
boolean hud_running = false;
static UINT8 hud_enabled[(hud_MAX/8)+1];
static UINT8 hudAvailable; // hud hooks field
// must match enum hud in lua_hud.h
static const char *const hud_disable_options[] = {
"stagetitle",
@ -95,21 +95,6 @@ static const char *const patch_opt[] = {
"topoffset",
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
enum align {
align_left = 0,
@ -384,6 +369,74 @@ static int camera_get(lua_State *L)
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
//
@ -663,6 +716,45 @@ static int libd_drawStretched(lua_State *L)
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)
{
INT32 x, y, flags, num;
@ -1121,6 +1213,7 @@ static luaL_Reg lib_draw[] = {
{"draw", libd_draw},
{"drawScaled", libd_drawScaled},
{"drawStretched", libd_drawStretched},
{"drawCropped", libd_drawCropped},
{"drawNum", libd_drawNum},
{"drawPaddedNum", libd_drawPaddedNum},
{"drawFill", libd_drawFill},
@ -1152,6 +1245,8 @@ static luaL_Reg lib_draw[] = {
{NULL, NULL}
};
static int lib_draw_ref;
//
// lib_hud
//
@ -1186,28 +1281,7 @@ static int lib_hudenabled(lua_State *L)
// add a HUD element for rendering
static 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;
}
extern int lib_hudadd(lua_State *L);
static luaL_Reg lib_hud[] = {
{"enable", lib_hudenable},
@ -1225,26 +1299,9 @@ int LUA_HudLib(lua_State *L)
{
memset(hud_enabled, 0xff, (hud_MAX/8)+1);
lua_newtable(L); // HUD registry table
lua_newtable(L);
luaL_register(L, NULL, lib_draw);
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");
lua_newtable(L);
luaL_register(L, NULL, lib_draw);
lib_draw_ref = luaL_ref(L, LUA_REGISTRYINDEX);
luaL_newmetatable(L, META_HUDINFO);
lua_pushcfunction(L, hudinfo_get);
@ -1283,6 +1340,9 @@ int LUA_HudLib(lua_State *L)
luaL_newmetatable(L, META_CAMERA);
lua_pushcfunction(L, camera_get);
lua_setfield(L, -2, "__index");
lua_pushcfunction(L, camera_set);
lua_setfield(L, -2, "__newindex");
lua_pop(L,1);
luaL_register(L, "hud", lib_hud);
@ -1296,160 +1356,29 @@ boolean LUA_HudEnabled(enum hud option)
return false;
}
// Hook for HUD rendering
void LUAh_GameHUD(player_t *stplayr)
void LUA_SetHudHook(int hook)
{
if (!gL || !(hudAvailable & (1<<hudhook_game)))
return;
lua_getref(gL, lib_draw_ref);
hud_running = true;
lua_settop(gL, 0);
switch (hook)
{
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");
I_Assert(lua_istable(gL, -1));
lua_rawgeti(gL, -1, 2+hudhook_game); // HUD[2] = rendering funcs
I_Assert(lua_istable(gL, -1));
case HUD_HOOK(titlecard):
LUA_PushUserdata(gL, stplyr, META_PLAYER);
lua_pushinteger(gL, lt_ticker);
lua_pushinteger(gL, (lt_endtime + TICRATE));
break;
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);
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);
case HUD_HOOK(intermission):
lua_pushboolean(gL, intertype == int_spec &&
stagefailed);
}
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_libs.h"
boolean mousegrabbedbylua = true;
///////////////
// FUNCTIONS //
///////////////
@ -26,8 +28,8 @@
static int lib_gameControlDown(lua_State *L)
{
int i = luaL_checkinteger(L, 1);
if (i < 0 || i >= num_gamecontrols)
return luaL_error(L, "gc_* constant %d out of range (0 - %d)", i, num_gamecontrols-1);
if (i < 0 || i >= NUM_GAMECONTROLS)
return luaL_error(L, "GC_* constant %d out of range (0 - %d)", i, NUM_GAMECONTROLS-1);
lua_pushinteger(L, PLAYER1INPUTDOWN(i));
return 1;
}
@ -35,8 +37,8 @@ static int lib_gameControlDown(lua_State *L)
static int lib_gameControl2Down(lua_State *L)
{
int i = luaL_checkinteger(L, 1);
if (i < 0 || i >= num_gamecontrols)
return luaL_error(L, "gc_* constant %d out of range (0 - %d)", i, num_gamecontrols-1);
if (i < 0 || i >= NUM_GAMECONTROLS)
return luaL_error(L, "GC_* constant %d out of range (0 - %d)", i, NUM_GAMECONTROLS-1);
lua_pushinteger(L, PLAYER2INPUTDOWN(i));
return 1;
}
@ -44,8 +46,8 @@ static int lib_gameControl2Down(lua_State *L)
static int lib_gameControlToKeyNum(lua_State *L)
{
int i = luaL_checkinteger(L, 1);
if (i < 0 || i >= num_gamecontrols)
return luaL_error(L, "gc_* constant %d out of range (0 - %d)", i, num_gamecontrols-1);
if (i < 0 || i >= NUM_GAMECONTROLS)
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][1]);
return 2;
@ -54,8 +56,8 @@ static int lib_gameControlToKeyNum(lua_State *L)
static int lib_gameControl2ToKeyNum(lua_State *L)
{
int i = luaL_checkinteger(L, 1);
if (i < 0 || i >= num_gamecontrols)
return luaL_error(L, "gc_* constant %d out of range (0 - %d)", i, num_gamecontrols-1);
if (i < 0 || i >= NUM_GAMECONTROLS)
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][1]);
return 2;
@ -75,17 +77,17 @@ static int lib_joy2Axis(lua_State *L)
return 1;
}
static int lib_keyNumToString(lua_State *L)
static int lib_keyNumToName(lua_State *L)
{
int i = luaL_checkinteger(L, 1);
lua_pushstring(L, G_KeyNumToString(i));
lua_pushstring(L, G_KeyNumToName(i));
return 1;
}
static int lib_keyStringToNum(lua_State *L)
static int lib_keyNameToNum(lua_State *L)
{
const char *str = luaL_checkstring(L, 1);
lua_pushinteger(L, G_KeyStringToNum(str));
lua_pushinteger(L, G_KeyNameToNum(str));
return 1;
}
@ -106,14 +108,14 @@ static int lib_shiftKeyNum(lua_State *L)
static int lib_getMouseGrab(lua_State *L)
{
lua_pushboolean(L, I_GetMouseGrab());
lua_pushboolean(L, mousegrabbedbylua);
return 1;
}
static int lib_setMouseGrab(lua_State *L)
{
boolean grab = luaL_checkboolean(L, 1);
I_SetMouseGrab(grab);
mousegrabbedbylua = luaL_checkboolean(L, 1);
I_UpdateMouseGrab();
return 0;
}
@ -127,19 +129,19 @@ static int lib_getCursorPosition(lua_State *L)
}
static luaL_Reg lib[] = {
{"G_GameControlDown", lib_gameControlDown},
{"G_GameControl2Down", lib_gameControl2Down},
{"G_GameControlToKeyNum", lib_gameControlToKeyNum},
{"G_GameControl2ToKeyNum", lib_gameControl2ToKeyNum},
{"G_JoyAxis", lib_joyAxis},
{"G_Joy2Axis", lib_joy2Axis},
{"G_KeyNumToString", lib_keyNumToString},
{"G_KeyStringToNum", lib_keyStringToNum},
{"HU_KeyNumPrintable", lib_keyNumPrintable},
{"HU_ShiftKeyNum", lib_shiftKeyNum},
{"I_GetMouseGrab", lib_getMouseGrab},
{"I_SetMouseGrab", lib_setMouseGrab},
{"I_GetCursorPosition", lib_getCursorPosition},
{"gameControlDown", lib_gameControlDown},
{"gameControl2Down", lib_gameControl2Down},
{"gameControlToKeyNum", lib_gameControlToKeyNum},
{"gameControl2ToKeyNum", lib_gameControl2ToKeyNum},
{"joyAxis", lib_joyAxis},
{"joy2Axis", lib_joy2Axis},
{"keyNumToName", lib_keyNumToName},
{"keyNameToNum", lib_keyNameToNum},
{"keyNumPrintable", lib_keyNumPrintable},
{"shiftKeyNum", lib_shiftKeyNum},
{"getMouseGrab", lib_getMouseGrab},
{"setMouseGrab", lib_setMouseGrab},
{"getCursorPosition", lib_getCursorPosition},
{NULL, NULL}
};
@ -172,6 +174,29 @@ static int lib_lenGameKeyDown(lua_State *L)
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 //
///////////
@ -227,6 +252,11 @@ int LUA_InputLib(lua_State *L)
lua_setmetatable(L, -2);
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);
lua_pushcfunction(L, mouse_get);
lua_setfield(L, -2, "__index");
@ -235,8 +265,6 @@ int LUA_InputLib(lua_State *L)
lua_setfield(L, -2, "__len");
lua_pop(L, 1);
// Set global functions
lua_pushvalue(L, LUA_GLOBALSINDEX);
luaL_register(L, NULL, lib);
luaL_register(L, "input", lib);
return 0;
}

View file

@ -12,6 +12,8 @@
extern lua_State *gL;
extern boolean mousegrabbedbylua;
#define MUTABLE_TAGS
#define LREG_VALID "VALID_USERDATA"
@ -88,6 +90,7 @@ extern lua_State *gL;
#define META_LUABANKS "LUABANKS[]*"
#define META_KEYEVENT "KEYEVENT_T*"
#define META_MOUSE "MOUSE_T*"
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);
else if (fastcmp(field,"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"))
lua_pushinteger(L, plr->jointime);
else if (fastcmp(field,"quittime"))
@ -719,6 +725,17 @@ static int player_set(lua_State *L)
plr->outofcoop = lua_toboolean(L, 3);
else if (fastcmp(field,"bot"))
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"))
plr->jointime = (tic_t)luaL_checkinteger(L, 3);
else if (fastcmp(field,"quittime"))

View file

@ -25,7 +25,7 @@
#include "byteptr.h"
#include "p_saveg.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
#ifdef LUA_ALLOW_BYTECODE
#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")) {
LUA_PushUserdata(L, &mouse2, META_MOUSE);
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;
}
@ -851,6 +859,8 @@ void LUA_InvalidateLevel(void)
{
LUA_InvalidateUserdata(&lines[i]);
LUA_InvalidateUserdata(&lines[i].tags);
LUA_InvalidateUserdata(lines[i].args);
LUA_InvalidateUserdata(lines[i].stringargs);
LUA_InvalidateUserdata(lines[i].sidenum);
}
for (i = 0; i < numsides; i++)
@ -863,6 +873,13 @@ void LUA_InvalidateLevel(void)
LUA_InvalidateUserdata(&PolyObjects[i].vertices);
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
for (i = 0; i < numsegs; i++)
LUA_InvalidateUserdata(&segs[i]);
@ -885,6 +902,8 @@ void LUA_InvalidateMapthings(void)
{
LUA_InvalidateUserdata(&mapthings[i]);
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
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)
{
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);
}
CONS_Alert(CONS_ERROR, "Index '%s' (%s) of table %d could not be archived!\n", lua_tostring(gL, -2), luaL_typename(gL, -2), i);
// Write value
e = ArchiveValue(TABLESINDEX, -1);
if (e == 1)
n++; // the table contained a new table we'll have to archive. :(
else if (e == 2) // invalid value type
{
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);
}
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_pop(gL, 1);
}

View file

@ -203,11 +203,11 @@ boolean cht_Responder(event_t *ev)
if (ev->type != ev_keydown)
return false;
if (ev->data1 > 0xFF)
if (ev->key > 0xFF)
{
// map some fake (joy) inputs into keys
// map joy inputs into keys
switch (ev->data1)
switch (ev->key)
{
case KEY_JOY1:
case KEY_JOY1 + 2:
@ -231,7 +231,7 @@ boolean cht_Responder(event_t *ev)
}
}
else
ch = (UINT8)ev->data1;
ch = (UINT8)ev->key;
ret += cht_CheckCheat(&cheat_ultimate, (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_SPACE, NULL, NULL, NULL, 0}, // padding
{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 Left", M_ChangeControl, gc_strafeleft },
{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, "Spin", M_ChangeControl, gc_spin },
{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 Left", M_ChangeControl, GC_STRAFELEFT },
{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, "Spin", M_ChangeControl, GC_SPIN },
{IT_HEADER, NULL, "Camera", NULL, 0},
{IT_SPACE, NULL, NULL, NULL, 0}, // padding
{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 Left", M_ChangeControl, gc_turnleft },
{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, "Toggle Mouselook", M_ChangeControl, gc_mouseaiming },
{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, "Look Up", M_ChangeControl, GC_LOOKUP },
{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 Right", M_ChangeControl, GC_TURNRIGHT },
{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 Third-Person", M_ChangeControl, GC_CAMTOGGLE},
{IT_CALL | IT_STRING2, NULL, "Reset Camera", M_ChangeControl, GC_CAMRESET },
{IT_HEADER, NULL, "Meta", NULL, 0},
{IT_SPACE, NULL, NULL, NULL, 0}, // padding
{IT_CALL | IT_STRING2, NULL, "Game Status",
M_ChangeControl, gc_scores },
{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, "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, "Change Viewpoint", M_ChangeControl, gc_viewpoint },
{IT_CALL | IT_STRING2, NULL, "Console", M_ChangeControl, gc_console },
M_ChangeControl, GC_SCORES },
{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, "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, "Change Viewpoint", M_ChangeControl, GC_VIEWPOINT },
{IT_CALL | IT_STRING2, NULL, "Console", M_ChangeControl, GC_CONSOLE },
{IT_HEADER, NULL, "Multiplayer", NULL, 0},
{IT_SPACE, NULL, NULL, NULL, 0}, // padding
{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", M_ChangeControl, GC_TALKKEY },
{IT_CALL | IT_STRING2, NULL, "Talk (Team only)", M_ChangeControl, GC_TEAMKEY },
{IT_HEADER, NULL, "Ringslinger (Match, CTF, Tag, H&S)", NULL, 0},
{IT_SPACE, NULL, NULL, NULL, 0}, // padding
{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, "Toss Flag", M_ChangeControl, gc_tossflag },
{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, "Normal / Infinity", M_ChangeControl, gc_wepslot1 },
{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, "Scatter", M_ChangeControl, gc_wepslot4 },
{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, "Rail", M_ChangeControl, gc_wepslot7 },
{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, "Toss Flag", M_ChangeControl, GC_TOSSFLAG },
{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, "Normal / Infinity", M_ChangeControl, GC_WEPSLOT1 },
{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, "Scatter", M_ChangeControl, GC_WEPSLOT4 },
{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, "Rail", M_ChangeControl, GC_WEPSLOT7 },
{IT_HEADER, NULL, "Add-ons", NULL, 0},
{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 2", M_ChangeControl, gc_custom2 },
{IT_CALL | IT_STRING2, NULL, "Custom Action 3", M_ChangeControl, gc_custom3 },
{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 3", M_ChangeControl, GC_CUSTOM3 },
};
static menuitem_t OP_Joystick1Menu[] =
@ -3215,7 +3215,7 @@ boolean M_Responder(event_t *ev)
if (gamestate == GS_TITLESCREEN && finalecount < TICRATE)
return false;
if (CON_Ready())
if (CON_Ready() && gamestate != GS_WAITINGPLAYERS)
return false;
if (noFurtherInput)
@ -3229,7 +3229,7 @@ boolean M_Responder(event_t *ev)
if (ev->type == ev_keydown)
{
keydown++;
ch = ev->data1;
ch = ev->key;
// added 5-2-98 remap virtual keys (mouse & joystick buttons)
switch (ch)
@ -3262,44 +3262,44 @@ boolean M_Responder(event_t *ev)
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;
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;
joywait = I_GetTime() + NEWTICRATE/7;
}
else if (ev->data3 > 0 && pjoyy <= 0)
else if (ev->y > 0 && pjoyy <= 0)
{
ch = KEY_DOWNARROW;
joywait = I_GetTime() + NEWTICRATE/7;
}
pjoyy = ev->data3;
pjoyy = ev->y;
}
else
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;
joywait = I_GetTime() + NEWTICRATE/17;
}
else if (ev->data2 > 0 && pjoyx <= 0)
else if (ev->x > 0 && pjoyx <= 0)
{
ch = KEY_RIGHTARROW;
joywait = I_GetTime() + NEWTICRATE/17;
}
pjoyx = ev->data2;
pjoyx = ev->x;
}
else
pjoyx = 0;
@ -3307,7 +3307,7 @@ boolean M_Responder(event_t *ev)
}
else if (ev->type == ev_mouse && mousewait < I_GetTime())
{
pmousey -= ev->data3;
pmousey -= ev->y;
if (pmousey < lasty-30)
{
ch = KEY_DOWNARROW;
@ -3321,7 +3321,7 @@ boolean M_Responder(event_t *ev)
pmousey = lasty += 30;
}
pmousex += ev->data2;
pmousex += ev->x;
if (pmousex < lastx - 30)
{
ch = KEY_LEFTARROW;
@ -3339,11 +3339,11 @@ boolean M_Responder(event_t *ev)
keydown = 0;
}
else if (ev->type == ev_keydown) // Preserve event for other responders
ch = ev->data1;
ch = ev->key;
if (ch == -1)
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;
// F-Keys
@ -4062,14 +4062,6 @@ static void M_DrawSlider(INT32 x, INT32 y, const consvar_t *cv, boolean ontop)
for (i = 1; i < SLIDER_RANGE; i++)
V_DrawScaledPatch (x+i*8, y, 0,p);
if (ontop)
{
V_DrawCharacter(x - 6 - (skullAnimCounter/5), y,
'\x1C' | V_YELLOWMAP, false);
V_DrawCharacter(x+i*8 + 8 + (skullAnimCounter/5), y,
'\x1D' | V_YELLOWMAP, false);
}
p = W_CachePatchName("M_SLIDER", PU_PATCH);
V_DrawScaledPatch(x+i*8, y, 0, p);
@ -4105,6 +4097,16 @@ static void M_DrawSlider(INT32 x, INT32 y, const consvar_t *cv, boolean ontop)
range = 100;
V_DrawMappedPatch(x + 2 + (SLIDER_RANGE*8*range)/100, y, 0, p, yellowmap);
if (ontop)
{
V_DrawCharacter(x - 6 - (skullAnimCounter/5), y,
'\x1C' | V_YELLOWMAP, false);
V_DrawCharacter(x + 80 + (skullAnimCounter/5), y,
'\x1D' | V_YELLOWMAP, false);
V_DrawCenteredString(x + 40, y, V_30TRANS,
(cv->flags & CV_FLOAT) ? va("%.2f", FIXED_TO_FLOAT(cv->value)) : va("%d", cv->value));
}
}
//
@ -4185,7 +4187,7 @@ static void M_DrawStaticBox(fixed_t x, fixed_t y, INT32 flags, fixed_t w, fixed_
if (staticalong > pw) // simplified for base LSSTATIC
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
@ -6410,6 +6412,7 @@ static void M_Addons(INT32 choice)
M_SetupNextMenu(&MISC_AddonsDef);
}
#ifdef ENFORCE_WAD_LIMIT
#define width 4
#define vpadding 27
#define h (BASEVIDHEIGHT-(2*vpadding))
@ -6457,6 +6460,7 @@ static void M_DrawTemperature(INT32 x, fixed_t t)
#undef vpadding
#undef h
#undef NUMCOLOURS
#endif
static char *M_AddonsHeaderPath(void)
{
@ -6550,21 +6554,20 @@ static void M_DrawAddons(void)
V_DrawCenteredString(BASEVIDWIDTH/2, 5, 0, LOCATIONSTRING1);
// (recommendedflags == V_SKYMAP ? LOCATIONSTRING2 : LOCATIONSTRING1)
#ifdef ENFORCE_WAD_LIMIT
if (numwadfiles <= mainwads+1)
y = 0;
else if (numwadfiles >= MAX_WADFILES)
y = FRACUNIT;
else
{
x = FixedDiv(((ssize_t)(numwadfiles) - (ssize_t)(mainwads+1))<<FRACBITS, ((ssize_t)MAX_WADFILES - (ssize_t)(mainwads+1))<<FRACBITS);
y = FixedDiv((((ssize_t)packetsizetally-(ssize_t)mainwadstally)<<FRACBITS), ((((ssize_t)MAXFILENEEDED*sizeof(UINT8)-(ssize_t)mainwadstally)-(5+22))<<FRACBITS)); // 5+22 = (a.ext + checksum length) is minimum addition to packet size tally
if (x > y)
y = x;
y = FixedDiv(((ssize_t)(numwadfiles) - (ssize_t)(mainwads+1))<<FRACBITS, ((ssize_t)MAX_WADFILES - (ssize_t)(mainwads+1))<<FRACBITS);
if (y > FRACUNIT) // happens because of how we're shrinkin' it a little
y = FRACUNIT;
}
M_DrawTemperature(BASEVIDWIDTH - 19 - 5, y);
#endif
// DRAW MENU
x = currentMenu->x;
@ -7187,13 +7190,20 @@ static void M_HandleChecklist(INT32 choice)
static void M_DrawChecklist(void)
{
INT32 i = check_on, j = 0, y = currentMenu->y;
INT32 i = check_on, j = 0, y = currentMenu->y, emblems = numemblems+numextraemblems;
UINT32 condnum, previd, maxcond;
condition_t *cond;
// draw title (or big pic)
M_DrawMenuTitle();
// draw emblem counter
if (emblems > 0)
{
V_DrawString(42, 20, (emblems == M_CountEmblems()) ? V_GREENMAP : 0, va("%d/%d", M_CountEmblems(), emblems));
V_DrawSmallScaledPatch(28, 20, 0, W_CachePatchName("EMBLICON", PU_PATCH));
}
if (check_on)
V_DrawString(10, y-(skullAnimCounter/5), V_YELLOWMAP, "\x1A");
@ -8652,6 +8662,12 @@ static void M_DrawLoad(void)
loadgameoffset = 0;
M_DrawLoadGameData();
if (modifiedgame && !savemoddata)
{
V_DrawCenteredThinString(BASEVIDWIDTH/2, 184, 0, "\x85WARNING: \x80The game is modified.");
V_DrawCenteredThinString(BASEVIDWIDTH/2, 192, 0, "Progress will not be saved.");
}
}
//
@ -8953,7 +8969,7 @@ static void M_HandleLoadSave(INT32 choice)
break;
case KEY_ENTER:
if (ultimate_selectable && saveSlotSelected == NOSAVESLOT)
if (ultimate_selectable && saveSlotSelected == NOSAVESLOT && !savemoddata && !modifiedgame)
{
loadgamescroll = 0;
S_StartSound(NULL, sfx_skid);
@ -12826,13 +12842,13 @@ static void M_DrawControl(void)
else
{
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)
strcat(tmp," or ");
if (keys[1] != KEY_NULL)
strcat (tmp, G_KeyNumToString (keys[1]));
strcat (tmp, G_KeyNumToName (keys[1]));
}
@ -12859,7 +12875,7 @@ static void M_ChangecontrolResponse(event_t *ev)
{
INT32 control;
INT32 found;
INT32 ch = ev->data1;
INT32 ch = ev->key;
// ESCAPE cancels; dummy out PAUSE
if (ch != KEY_ESCAPE && ch != KEY_PAUSE)
@ -12878,7 +12894,7 @@ static void M_ChangecontrolResponse(event_t *ev)
// keypad arrows are converted for the menu in cursor arrows
// so use the event instead of ch
case ev_keydown:
ch = ev->data1;
ch = ev->key;
break;
default:
@ -12929,7 +12945,7 @@ static void M_ChangecontrolResponse(event_t *ev)
static char tmp[158];
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"),
controltochangetext);
else

View file

@ -1631,14 +1631,14 @@ boolean M_ScreenshotResponder(event_t *ev)
if (dedicated || ev->type != ev_keydown)
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!
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();
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)();
else
return false;
@ -2688,3 +2688,22 @@ const char * M_Ftrim (double f)
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);
// Returns true if the string is empty.
boolean M_IsStringEmpty(const char *s);
// counting bits, for weapon ammo code, usually
FUNCMATH UINT8 M_CountBits(UINT32 num, UINT8 size);

File diff suppressed because it is too large Load diff

View file

@ -16,26 +16,45 @@
#include "lua_script.h"
#include "p_local.h"
extern precise_t ps_tictime;
extern precise_t ps_playerthink_time;
extern precise_t ps_thinkertime;
extern precise_t ps_thlist_times[];
extern int ps_checkposition_calls;
extern precise_t ps_lua_thinkframe_time;
extern int ps_lua_mobjhooks;
typedef struct
{
union {
precise_t p;
INT32 i;
} value;
void *history;
} ps_metric_t;
typedef struct
{
precise_t time_taken;
ps_metric_t time_taken;
char short_src[LUA_IDSIZE];
} ps_hookinfo_t;
#define PS_START_TIMING(metric) metric.value.p = I_GetPreciseTime()
#define PS_STOP_TIMING(metric) metric.value.p = I_GetPreciseTime() - metric.value.p
extern ps_metric_t ps_tictime;
extern ps_metric_t ps_playerthink_time;
extern ps_metric_t ps_thinkertime;
extern ps_metric_t ps_thlist_times[];
extern ps_metric_t ps_checkposition_calls;
extern ps_metric_t ps_lua_thinkframe_time;
extern ps_metric_t ps_lua_mobjhooks;
extern ps_metric_t ps_otherlogictime;
void PS_SetThinkFrameHookInfo(int index, precise_t time_taken, char* short_src);
void PS_UpdateTickStats(void);
void M_DrawPerfStats(void);
void PS_PerfStats_OnChange(void);
void PS_SampleSize_OnChange(void);
#endif

View file

@ -67,7 +67,8 @@ void T_MoveCeiling(ceiling_t *ceiling)
switch (ceiling->type)
{
case instantMoveCeilingByFrontSector:
ceiling->sector->ceilingpic = ceiling->texture;
if (ceiling->texture > -1)
ceiling->sector->ceilingpic = ceiling->texture;
ceiling->sector->ceilingdata = NULL;
ceiling->sector->ceilspeed = 0;
P_RemoveThinker(&ceiling->thinker);
@ -186,7 +187,8 @@ void T_MoveCeiling(ceiling_t *ceiling)
break;
case instantMoveCeilingByFrontSector:
ceiling->sector->ceilingpic = ceiling->texture;
if (ceiling->texture > -1)
ceiling->sector->ceilingpic = ceiling->texture;
ceiling->sector->ceilingdata = NULL;
ceiling->sector->ceilspeed = 0;
P_RemoveThinker(&ceiling->thinker);
@ -512,7 +514,10 @@ INT32 EV_DoCeiling(line_t *line, ceiling_e type)
ceiling->direction = -1;
ceiling->bottomheight = line->frontsector->ceilingheight;
}
ceiling->texture = line->frontsector->ceilingpic;
if (line->flags & ML_NOCLIMB)
ceiling->texture = -1;
else
ceiling->texture = line->frontsector->ceilingpic;
break;
case moveCeilingByFrontTexture:

View file

@ -744,8 +744,8 @@ boolean P_LookForPlayers(mobj_t *actor, boolean allaround, boolean tracer, fixed
if (player->mo->health <= 0)
continue; // dead
if (player->bot)
continue; // ignore bots
if (player->bot == BOT_2PAI || player->bot == BOT_2PHUMAN)
continue; // ignore followbots
if (player->quittime)
continue; // Ignore uncontrolled bodies
@ -3518,9 +3518,7 @@ void A_Scream(mobj_t *actor)
if (LUA_CallAction(A_SCREAM, actor))
return;
if (actor->tracer && (actor->tracer->type == MT_SHELL || actor->tracer->type == MT_FIREBALL))
S_StartScreamSound(actor, sfx_mario2);
else if (actor->info->deathsound)
if (actor->info->deathsound && !S_SoundPlaying(actor, sfx_mario2))
S_StartScreamSound(actor, actor->info->deathsound);
}
@ -3591,7 +3589,7 @@ void A_1upThinker(mobj_t *actor)
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;
if (!players[i].mo)
@ -5297,7 +5295,7 @@ void A_OverlayThink(mobj_t *actor)
actor->z = actor->target->z + actor->target->height - mobjinfo[actor->type].height - ((var2>>16) ? -1 : 1)*(var2&0xFFFF)*FRACUNIT;
else
actor->z = actor->target->z + ((var2>>16) ? -1 : 1)*(var2&0xFFFF)*FRACUNIT;
actor->angle = actor->target->angle + actor->movedir;
actor->angle = (actor->target->player ? actor->target->player->drawangle : actor->target->angle) + actor->movedir;
actor->eflags = actor->target->eflags;
actor->momx = actor->target->momx;
@ -8272,7 +8270,7 @@ void A_Boss3ShockThink(mobj_t *actor)
fixed_t x0, y0, x1, y1;
// 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);
return;
@ -8283,9 +8281,11 @@ void A_Boss3ShockThink(mobj_t *actor)
y0 = actor->y;
x1 = snext->x;
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->momy = (actor->momy + snext->momy) >> 1;
snew->momz = (actor->momz + snext->momz) >> 1; // is this really needed?
@ -8293,6 +8293,10 @@ void A_Boss3ShockThink(mobj_t *actor)
P_SetTarget(&snew->target, actor->target);
snew->fuse = actor->fuse;
P_SetScale(snew, actor->scale);
snew->destscale = actor->destscale;
snew->scalespeed = actor->scalespeed;
P_SetTarget(&actor->hnext, snew);
P_SetTarget(&snew->hnext, snext);
}

View file

@ -1041,6 +1041,7 @@ static mobj_t *SearchMarioNode(msecnode_t *node)
case MT_THUNDERCOIN_ORB:
case MT_IVSP:
case MT_SUPERSPARK:
case MT_BOXSPARKLE:
case MT_RAIN:
case MT_SNOWFLAKE:
case MT_SPLISH:

View file

@ -151,7 +151,7 @@ boolean P_CanPickupItem(player_t *player, boolean weapon)
if (!player->mo || player->mo->health <= 0)
return false;
if (player->bot)
if (player->bot && player->bot != BOT_MPAI)
{
if (weapon)
return false;
@ -178,7 +178,7 @@ void P_DoNightsScore(player_t *player)
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);
if (player->bot)
if (player->bot && player->bot != BOT_MPAI)
player = &players[consoleplayer];
if (G_IsSpecialStage(gamemap)) // Global link count? Maybe not a good idea...
@ -630,7 +630,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
// ***************************** //
// Special Stage Token
case MT_TOKEN:
if (player->bot)
if (player->bot && player->bot != BOT_MPAI)
return;
P_AddPlayerScore(player, 1000);
@ -670,7 +670,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
// Emerald Hunt
case MT_EMERHUNT:
if (player->bot)
if (player->bot && player->bot != BOT_MPAI)
return;
if (hunt1 == special)
@ -701,7 +701,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
case MT_EMERALD5:
case MT_EMERALD6:
case MT_EMERALD7:
if (player->bot)
if (player->bot && player->bot != BOT_MPAI)
return;
if (special->threshold)
@ -738,7 +738,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
// Secret emblem thingy
case MT_EMBLEM:
{
if (demoplayback || player->bot)
if (demoplayback || (player->bot && player->bot != BOT_MPAI))
return;
emblemlocations[special->health-1].collected = true;
@ -751,7 +751,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
// CTF Flags
case MT_REDFLAG:
case MT_BLUEFLAG:
if (player->bot)
if (player->bot && player->bot != BOT_MPAI)
return;
if (player->powers[pw_flashing] || player->tossdelay)
return;
@ -826,7 +826,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
{
boolean spec = G_IsSpecialStage(gamemap);
boolean cangiveemmy = false;
if (player->bot)
if (player->bot && player->bot != BOT_MPAI)
return;
if (player->exiting)
return;
@ -1072,7 +1072,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
}
return;
case MT_EGGCAPSULE:
if (player->bot)
if (player->bot && player->bot != BOT_MPAI)
return;
// 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;
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;
if (!G_IsSpecialStage(gamemap))
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;
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;
if (!G_IsSpecialStage(gamemap))
player->drillmeter = special->info->speed;
@ -1208,7 +1208,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
}
break;
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;
if (!G_IsSpecialStage(gamemap))
{
@ -1240,7 +1240,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
}
break;
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;
if (!G_IsSpecialStage(gamemap))
{
@ -1272,7 +1272,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
}
break;
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;
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)
players[i].drillmeter += TICRATE/2;
}
else if (player->bot)
else if (player->bot && player->bot != BOT_MPAI)
players[consoleplayer].drillmeter += TICRATE/2;
else
player->drillmeter += TICRATE/2;
@ -1385,7 +1385,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
thinker_t *th;
mobj_t *mo2;
if (player->bot)
if (player->bot && player->bot != BOT_MPAI)
return;
// Initialize my junk
@ -1423,7 +1423,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
return;
}
case MT_FIREFLOWER:
if (player->bot)
if (player->bot && player->bot != BOT_MPAI)
return;
S_StartSound(toucher, sfx_mario3);
@ -1685,7 +1685,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
return; // Only go in the mouth
// 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;
P_RestoreMusic(player);
@ -1696,7 +1696,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
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
P_SetPlayerMobjState(toucher, S_PLAY_GASP);
P_ResetPlayer(player);
@ -1704,7 +1704,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
toucher->momx = toucher->momy = toucher->momz = 0;
if (player->bot)
if (player->bot && player->bot != BOT_MPAI)
return;
else
break;
@ -1736,7 +1736,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
return;
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);
P_SetTarget(&mcart->target, toucher);
@ -1789,7 +1789,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
}
return;
default: // SOC or script pickup
if (player->bot)
if (player->bot && player->bot != BOT_MPAI)
return;
P_SetTarget(&special->target, toucher);
break;
@ -1813,7 +1813,7 @@ void P_TouchStarPost(mobj_t *post, player_t *player, boolean snaptopost)
mobj_t *toucher = player->mo;
mobj_t *checkbase = snaptopost ? post : toucher;
if (player->bot)
if (player->bot && player->bot != BOT_MPAI)
return;
// In circuit, player must have touched all previous starposts
if (circuitmap
@ -2391,7 +2391,7 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget
mobj_t *mo;
if (inflictor && (inflictor->type == MT_SHELL || inflictor->type == MT_FIREBALL))
P_SetTarget(&target->tracer, inflictor);
S_StartScreamSound(target, sfx_mario2);
if (!(maptol & TOL_NIGHTS) && G_IsSpecialStage(gamemap) && target->player && target->player->nightstime > 6)
target->player->nightstime = 6; // Just let P_Ticker take care of the rest.
@ -2555,7 +2555,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))
;
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())
{
if (!(target->player->pflags & PF_FINISHED))
@ -3475,7 +3475,7 @@ void P_SpecialStageDamage(player_t *player, mobj_t *inflictor, mobj_t *source)
if (inflictor && inflictor->type == MT_LHRT)
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);
S_StartSound(player->mo, sfx_shldls); // Ba-Dum! Shield loss.
@ -3566,7 +3566,7 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
return false;
// 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)))))
return false;
}
@ -3651,7 +3651,7 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
return true;
}
if (!force && inflictor && inflictor->flags & MF_FIRE)
if (!force && inflictor && inflictor->flags & MF_FIRE && !(damagetype && damagetype != DMG_FIRE))
{
if (player->powers[pw_shield] & SH_PROTECTFIRE)
return false; // Invincible to fire objects
@ -3701,7 +3701,7 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
}
else if (LUA_HookMobjDamage(target, inflictor, source, damage, damagetype))
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);
damage = 0;

View file

@ -1156,7 +1156,7 @@ static boolean PIT_CheckThing(mobj_t *thing)
else
thing->z = tmthing->z + tmthing->height + FixedMul(FRACUNIT, tmthing->scale);
if (thing->flags & MF_SHOOTABLE)
P_DamageMobj(thing, tmthing, tmthing, 1, 0);
P_DamageMobj(thing, tmthing, tmthing, 1, DMG_SPIKE);
return true;
}
@ -2029,7 +2029,7 @@ boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y)
subsector_t *newsubsec;
boolean blockval = true;
ps_checkposition_calls++;
ps_checkposition_calls.value.i++;
I_Assert(thing != NULL);
#ifdef PARANOIA

View file

@ -78,7 +78,7 @@ void P_AddCachedAction(mobj_t *mobj, INT32 statenum)
//
// P_SetupStateAnimation
//
FUNCINLINE static ATTRINLINE void P_SetupStateAnimation(mobj_t *mobj, state_t *st)
static void P_SetupStateAnimation(mobj_t *mobj, state_t *st)
{
INT32 animlength = (mobj->sprite == SPR_PLAY && mobj->skin)
? (INT32)(((skin_t *)mobj->skin)->sprites[mobj->sprite2].numframes) - 1
@ -1844,12 +1844,10 @@ void P_XYMovement(mobj_t *mo)
// blocked move
moved = false;
if (player) {
if (player->bot)
B_MoveBlocked(player);
}
if (player)
B_MoveBlocked(player);
if (LUA_HookMobj(mo, MOBJ_HOOK(MobjMoveBlocked)))
if (LUA_HookMobjMoveBlocked(mo, tmhitthing, blockingline))
{
if (P_MobjWasRemoved(mo))
return;
@ -2554,6 +2552,10 @@ boolean P_ZMovement(mobj_t *mo)
}
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))
{
mo->standingslope = (mo->eflags & MFE_VERTICALFLIP) ? tmceilingslope : tmfloorslope;
@ -3239,8 +3241,8 @@ void P_MobjCheckWater(mobj_t *mobj)
|| ((rover->flags & FF_BLOCKOTHERS) && !mobj->player)))
continue;
topheight = P_GetFFloorTopZAt (rover, mobj->x, mobj->y);
bottomheight = P_GetFFloorBottomZAt(rover, mobj->x, mobj->y);
topheight = P_GetSpecialTopZ(mobj, sectors + rover->secnum, sector);
bottomheight = P_GetSpecialBottomZ(mobj, sectors + rover->secnum, sector);
if (mobj->eflags & MFE_VERTICALFLIP)
{
@ -4141,7 +4143,7 @@ boolean P_BossTargetPlayer(mobj_t *actor, boolean closest)
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
if (!player->mo || P_MobjWasRemoved(player->mo))
@ -4182,7 +4184,7 @@ boolean P_SupermanLook4Players(mobj_t *actor)
if (players[c].pflags & PF_INVIS)
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;
if (players[c].mo->health <= 0)
@ -6840,7 +6842,7 @@ void P_RunOverlays(void)
mo->eflags = (mo->eflags & ~MFE_VERTICALFLIP) | (mo->target->eflags & MFE_VERTICALFLIP);
mo->scale = mo->destscale = mo->target->scale;
mo->angle = mo->target->angle + mo->movedir;
mo->angle = (mo->target->player ? mo->target->player->drawangle : mo->target->angle) + mo->movedir;
if (!(mo->state->frame & FF_ANIMATE))
zoffs = FixedMul(((signed)mo->state->var2)*FRACUNIT, mo->scale);
@ -7311,7 +7313,7 @@ static void P_RosySceneryThink(mobj_t *mobj)
continue;
if (!players[i].mo)
continue;
if (players[i].bot)
if (players[i].bot == BOT_2PAI || players[i].bot == BOT_2PHUMAN)
continue;
if (!players[i].mo->health)
continue;
@ -10393,6 +10395,9 @@ static fixed_t P_DefaultMobjShadowScale (mobj_t *thing)
case MT_RING:
case MT_FLINGRING:
case MT_COIN:
case MT_FLINGCOIN:
case MT_BLUESPHERE:
case MT_FLINGBLUESPHERE:
case MT_BOMBSPHERE:
@ -11056,7 +11061,7 @@ void P_SpawnPrecipitation(void)
subsector_t *precipsector = 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;
// Use the blockmap to narrow down our placing patterns
@ -11102,22 +11107,14 @@ void P_SpawnPrecipitation(void)
continue;
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.
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].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 //
////////////////////////////
@ -407,6 +420,20 @@ static void P_NetUnArchivePlayers(void)
players[i].dashmode = READUINT32(save_p); // counter for dashmode ability
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 //
////////////////////////////

View file

@ -1501,6 +1501,22 @@ typedef struct textmap_colormap_s {
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)
{
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)));
else if (fastcmp(param, "rotationceiling"))
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"))
{
textmap_colormap.used = true;
@ -1868,6 +1924,10 @@ static void P_LoadTextmap(void)
textmap_colormap.fadestart = 0;
textmap_colormap.fadeend = 31;
textmap_colormap.flags = 0;
textmap_planefloor.defined = 0;
textmap_planeceiling.defined = 0;
TextmapParse(sectorsPos[i], i, ParseTextmapSectorParameter);
P_InitializeSector(sc);
@ -1877,6 +1937,19 @@ static void P_LoadTextmap(void)
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);
}
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);
}
@ -3586,6 +3659,12 @@ static void P_ConvertBinaryMap(void)
if (lines[i].flags & ML_NONET)
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;
break;
}
@ -4704,6 +4783,8 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate)
P_MapStart(); // tmthing can be used starting from this point
P_InitSlopes();
if (!P_LoadMapFromFile())
return false;
@ -4915,10 +4996,9 @@ static lumpinfo_t* FindFolder(const char *folName, UINT16 *start, UINT16 *end, l
// Add a wadfile to the active wad files,
// 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;
UINT16 numlumps, wadnum;
char *name;
lumpinfo_t *lumpinfo;
@ -4939,18 +5019,10 @@ boolean P_AddWadFile(const char *wadfilename)
// UINT16 flaPos, flaNum = 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)
{
case RET_PK3:
case RET_FOLDER:
// Look for the lumps that act as resource delimitation markers.
lumpinfo = wadfiles[wadnum]->lumpinfo;
for (i = 0; i < numlumps; i++, lumpinfo++)
@ -5114,3 +5186,35 @@ boolean P_AddWadFile(const char *wadfilename)
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);
#endif
boolean P_AddWadFile(const char *wadfilename);
boolean P_AddFolder(const char *folderpath);
boolean P_RunSOC(const char *socfilename);
void P_LoadSoundsRange(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.
void T_DynamicSlopeLine (dynplanethink_t* th)
{
@ -631,13 +661,20 @@ pslope_t *P_SlopeById(UINT16 id)
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.
void P_SpawnSlopes(const boolean fromsave) {
size_t i;
slopelist = NULL;
slopecount = 0;
/// Generates vertex slopes.
SpawnVertexSlopes();
@ -664,6 +701,9 @@ void P_SpawnSlopes(const boolean fromsave) {
for (i = 0; i < numlines; i++)
switch (lines[i].special)
{
case 700:
if (lines[i].flags & ML_TFERLINE) P_CopySectorSlope(&lines[i]);
break;
case 720:
P_CopySectorSlope(&lines[i]);
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

View file

@ -50,6 +50,7 @@ typedef enum
void P_LinkSlopeThinkers (void);
void P_CalculateSlopeNormal(pslope_t *slope);
void P_InitSlopes(void);
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_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.
typedef enum {

View file

@ -1982,6 +1982,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
//
@ -1989,53 +2005,14 @@ void P_LinedefExecute(INT16 tag, mobj_t *actor, sector_t *caller)
//
void P_SwitchWeather(INT32 weathernum)
{
boolean purge = false;
INT32 swap = 0;
boolean purge = true;
switch (weathernum)
{
case PRECIP_NONE: // None
if (curWeather == PRECIP_NONE)
return; // Nothing to do.
purge = true;
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 (weathernum == curWeather)
return;
if (is_rain_type(weathernum) &&
is_rain_type(curWeather))
purge = false;
if (purge)
{
@ -2052,7 +2029,7 @@ void P_SwitchWeather(INT32 weathernum)
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;
precipmobj_t *precipmobj;
@ -2064,7 +2041,7 @@ void P_SwitchWeather(INT32 weathernum)
continue; // not a precipmobj thinker
precipmobj = (precipmobj_t *)think;
if (swap == PRECIP_RAIN) // Snow To Rain
if (weathernum == PRECIP_RAIN || weathernum == PRECIP_STORM || weathernum == PRECIP_STORM_NOSTRIKES) // Snow To Rain
{
precipmobj->flags = mobjinfo[MT_RAIN].flags;
st = &states[mobjinfo[MT_RAIN].spawnstate];
@ -2079,7 +2056,7 @@ void P_SwitchWeather(INT32 weathernum)
precipmobj->precipflags |= PCF_RAIN;
//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;
@ -2104,7 +2081,7 @@ void P_SwitchWeather(INT32 weathernum)
//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;
@ -2118,48 +2095,33 @@ void P_SwitchWeather(INT32 weathernum)
case PRECIP_SNOW: // snow
curWeather = PRECIP_SNOW;
if (!swap)
if (purge)
P_SpawnPrecipitation();
break;
case PRECIP_RAIN: // rain
{
boolean dontspawn = false;
if (curWeather == PRECIP_RAIN || curWeather == PRECIP_STORM || curWeather == PRECIP_STORM_NOSTRIKES)
dontspawn = true;
curWeather = PRECIP_RAIN;
if (!dontspawn && !swap)
if (purge)
P_SpawnPrecipitation();
break;
}
case PRECIP_STORM: // storm
{
boolean dontspawn = false;
if (curWeather == PRECIP_RAIN || curWeather == PRECIP_STORM || curWeather == PRECIP_STORM_NOSTRIKES)
dontspawn = true;
curWeather = PRECIP_STORM;
if (!dontspawn && !swap)
if (purge)
P_SpawnPrecipitation();
break;
}
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;
if (!dontspawn && !swap)
if (purge)
P_SpawnPrecipitation();
break;
@ -2167,14 +2129,11 @@ void P_SwitchWeather(INT32 weathernum)
case PRECIP_STORM_NORAIN: // storm w/o rain
curWeather = PRECIP_STORM_NORAIN;
if (!swap)
P_SpawnPrecipitation();
break;
case PRECIP_BLANK:
case PRECIP_BLANK: //preloaded
curWeather = PRECIP_BLANK;
if (!swap)
if (purge)
P_SpawnPrecipitation();
break;
@ -7307,7 +7266,8 @@ void P_SpawnSpecials(boolean fromnetsave)
}
}
P_RunLevelLoadExecutors();
if (!fromnetsave)
P_RunLevelLoadExecutors();
}
/** Adds 3Dfloors as appropriate based on a common control linedef.

View file

@ -323,7 +323,7 @@ static inline void P_RunThinkers(void)
size_t i;
for (i = 0; i < NUM_THINKERLISTS; i++)
{
ps_thlist_times[i] = I_GetPreciseTime();
PS_START_TIMING(ps_thlist_times[i]);
for (currentthinker = thlist[i].next; currentthinker != &thlist[i]; currentthinker = currentthinker->next)
{
#ifdef PARANOIA
@ -331,7 +331,7 @@ static inline void P_RunThinkers(void)
#endif
currentthinker->function.acp1(currentthinker);
}
ps_thlist_times[i] = I_GetPreciseTime() - ps_thlist_times[i];
PS_STOP_TIMING(ps_thlist_times[i]);
}
}
@ -487,7 +487,7 @@ static inline void P_DoSpecialStageStuff(void)
continue;
// If in water, deplete timer 6x as fast.
if (players[i].mo->eflags & (MFE_TOUCHWATER|MFE_UNDERWATER) && !(players[i].powers[pw_shield] & SH_PROTECTWATER))
if (players[i].mo->eflags & (MFE_TOUCHWATER|MFE_UNDERWATER) && !(players[i].powers[pw_shield] & ((players[i].mo->eflags & MFE_TOUCHLAVA) ? SH_PROTECTFIRE : SH_PROTECTWATER)))
players[i].nightstime -= 5;
if (--players[i].nightstime > 6)
{
@ -653,16 +653,16 @@ void P_Ticker(boolean run)
}
}
ps_lua_mobjhooks = 0;
ps_checkposition_calls = 0;
ps_lua_mobjhooks.value.i = 0;
ps_checkposition_calls.value.i = 0;
LUA_HOOK(PreThinkFrame);
ps_playerthink_time = I_GetPreciseTime();
PS_START_TIMING(ps_playerthink_time);
for (i = 0; i < MAXPLAYERS; i++)
if (playeringame[i] && players[i].mo && !P_MobjWasRemoved(players[i].mo))
P_PlayerThink(&players[i]);
ps_playerthink_time = I_GetPreciseTime() - ps_playerthink_time;
PS_STOP_TIMING(ps_playerthink_time);
}
// Keep track of how long they've been playing!
@ -677,18 +677,18 @@ void P_Ticker(boolean run)
if (run)
{
ps_thinkertime = I_GetPreciseTime();
PS_START_TIMING(ps_thinkertime);
P_RunThinkers();
ps_thinkertime = I_GetPreciseTime() - ps_thinkertime;
PS_STOP_TIMING(ps_thinkertime);
// Run any "after all the other thinkers" stuff
for (i = 0; i < MAXPLAYERS; i++)
if (playeringame[i] && players[i].mo && !P_MobjWasRemoved(players[i].mo))
P_PlayerAfterThink(&players[i]);
ps_lua_thinkframe_time = I_GetPreciseTime();
PS_START_TIMING(ps_lua_thinkframe_time);
LUA_HookThinkFrame();
ps_lua_thinkframe_time = I_GetPreciseTime() - ps_lua_thinkframe_time;
PS_STOP_TIMING(ps_lua_thinkframe_time);
}
// Run shield positioning

View file

@ -1367,8 +1367,8 @@ void P_AddPlayerScore(player_t *player, UINT32 amount)
{
UINT32 oldscore;
if (player->bot)
player = &players[consoleplayer];
if ((player->bot == BOT_2PAI || player->bot == BOT_2PHUMAN) && player->botleader)
player = player->botleader;
// NiGHTS does it different!
if (gamestate == GS_LEVEL && mapheaderinfo[gamemap-1]->typeoflevel & TOL_NIGHTS)
@ -2819,7 +2819,6 @@ static void P_CheckBouncySectors(player_t *player)
player->pflags |= PF_THOKKED;
}
}
goto bouncydone;
}
}
@ -5333,9 +5332,9 @@ static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd)
// disabled because it seemed to disorient people and Z-targeting exists now
/*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);;
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);
}*/
}
@ -5354,7 +5353,7 @@ static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd)
player->powers[pw_tailsfly] = tailsflytics + 1; // Set the fly timer
player->pflags &= ~(PF_JUMPED|PF_NOJUMPDAMAGE|PF_SPINNING|PF_STARTDASH);
if (player->bot == 1)
if (player->bot == BOT_2PAI)
player->pflags |= PF_THOKKED;
else
player->pflags |= (PF_THOKKED|PF_CANCARRY);
@ -5600,16 +5599,10 @@ INT32 P_GetPlayerControlDirection(player_t *player)
{
ticcmd_t *cmd = &player->cmd;
angle_t controllerdirection, controlplayerdirection;
camera_t *thiscam;
angle_t dangle;
fixed_t tempx = 0, tempy = 0;
angle_t tempangle, origtempangle;
if (splitscreen && player == &players[secondarydisplayplayer])
thiscam = &camera2;
else
thiscam = &camera;
if (!cmd->forwardmove && !cmd->sidemove)
return 0;
@ -5625,17 +5618,15 @@ INT32 P_GetPlayerControlDirection(player_t *player)
origtempangle = tempangle = 0; // relative to the axis rather than the player!
controlplayerdirection = R_PointToAngle2(0, 0, player->mo->momx, player->mo->momy);
}
else if ((P_ControlStyle(player) & CS_LMAOGALOG) && thiscam->chase)
else
{
if (player->awayviewtics)
origtempangle = tempangle = player->awayviewmobj->angle;
else if (P_ControlStyle(player) & CS_LMAOGALOG)
origtempangle = tempangle = (cmd->angleturn << 16);
else
origtempangle = tempangle = thiscam->angle;
controlplayerdirection = player->mo->angle;
}
else
{
origtempangle = tempangle = player->mo->angle;
origtempangle = tempangle = player->mo->angle;
controlplayerdirection = R_PointToAngle2(0, 0, player->mo->momx, player->mo->momy);
}
@ -5941,22 +5932,6 @@ static void P_3dMovement(player_t *player)
acceleration = 96 + (FixedDiv(player->speed, player->mo->scale)>>FRACBITS) * 40;
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
{
if (player->powers[pw_super] || player->powers[pw_sneakers])
@ -9486,11 +9461,11 @@ static void P_DeathThink(player_t *player)
if (player->deadtimer < INT32_MAX)
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;
// 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))
G_UseContinue();
@ -11463,6 +11438,9 @@ void P_PlayerThink(player_t *player)
I_Error("p_playerthink: players[%s].mo == NULL", sizeu1(playeri));
#endif
// Reset terrain blocked status for this frame
player->blocked = false;
// 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!
{
@ -11470,7 +11448,7 @@ void P_PlayerThink(player_t *player)
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)
{
@ -11614,7 +11592,7 @@ void P_PlayerThink(player_t *player)
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;
if (players[i].lives <= 0)
continue;
@ -11646,7 +11624,7 @@ void P_PlayerThink(player_t *player)
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;
if (players[i].quittime > 30 * TICRATE)
continue;
@ -12587,7 +12565,7 @@ void P_PlayerAfterThink(player_t *player)
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;

View file

@ -804,7 +804,7 @@ static void R_AddPolyObjects(subsector_t *sub)
}
// for render stats
ps_numpolyobjects += numpolys;
ps_numpolyobjects.value.i += numpolys;
// sort polyobjects
R_SortPolyObjects(sub);
@ -1239,7 +1239,7 @@ void R_RenderBSPNode(INT32 bspnum)
node_t *bsp;
INT32 side;
ps_numbspcalls++;
ps_numbspcalls.value.i++;
while (!(bspnum & NF_SUBSECTOR)) // Found a subsector?
{

View file

@ -666,7 +666,6 @@ void R_DrawTiltedSplat_NPO2_8(void)
for (; width != 0; width--)
{
colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps);
val = source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)];
// Lactozilla: Non-powers-of-two
{
fixed_t x = (((fixed_t)u) >> FRACBITS);

View file

@ -101,21 +101,22 @@ extracolormap_t *extra_colormaps = NULL;
// Render stats
precise_t ps_prevframetime = 0;
precise_t ps_rendercalltime = 0;
precise_t ps_uitime = 0;
precise_t ps_swaptime = 0;
ps_metric_t ps_rendercalltime = {0};
ps_metric_t ps_otherrendertime = {0};
ps_metric_t ps_uitime = {0};
ps_metric_t ps_swaptime = {0};
precise_t ps_bsptime = 0;
ps_metric_t ps_bsptime = {0};
precise_t ps_sw_spritecliptime = 0;
precise_t ps_sw_portaltime = 0;
precise_t ps_sw_planetime = 0;
precise_t ps_sw_maskedtime = 0;
ps_metric_t ps_sw_spritecliptime = {0};
ps_metric_t ps_sw_portaltime = {0};
ps_metric_t ps_sw_planetime = {0};
ps_metric_t ps_sw_maskedtime = {0};
int ps_numbspcalls = 0;
int ps_numsprites = 0;
int ps_numdrawnodes = 0;
int ps_numpolyobjects = 0;
ps_metric_t ps_numbspcalls = {0};
ps_metric_t ps_numsprites = {0};
ps_metric_t ps_numdrawnodes = {0};
ps_metric_t ps_numpolyobjects = {0};
static CV_PossibleValue_t drawdist_cons_t[] = {
{256, "256"}, {512, "512"}, {768, "768"},
@ -1496,11 +1497,11 @@ void R_RenderPlayerView(player_t *player)
mytotal = 0;
ProfZeroTimer();
#endif
ps_numbspcalls = ps_numpolyobjects = ps_numdrawnodes = 0;
ps_bsptime = I_GetPreciseTime();
ps_numbspcalls.value.i = ps_numpolyobjects.value.i = ps_numdrawnodes.value.i = 0;
PS_START_TIMING(ps_bsptime);
R_RenderBSPNode((INT32)numnodes - 1);
ps_bsptime = I_GetPreciseTime() - ps_bsptime;
ps_numsprites = visspritecount;
PS_STOP_TIMING(ps_bsptime);
ps_numsprites.value.i = visspritecount;
#ifdef TIMING
RDMSR(0x10, &mycount);
mytotal += mycount; // 64bit add
@ -1510,9 +1511,9 @@ void R_RenderPlayerView(player_t *player)
//profile stuff ---------------------------------------------------------
Mask_Post(&masks[nummasks - 1]);
ps_sw_spritecliptime = I_GetPreciseTime();
PS_START_TIMING(ps_sw_spritecliptime);
R_ClipSprites(drawsegs, NULL);
ps_sw_spritecliptime = I_GetPreciseTime() - ps_sw_spritecliptime;
PS_STOP_TIMING(ps_sw_spritecliptime);
// Add skybox portals caused by sky visplanes.
@ -1520,7 +1521,7 @@ void R_RenderPlayerView(player_t *player)
Portal_AddSkyboxPortals();
// Portal rendering. Hijacks the BSP traversal.
ps_sw_portaltime = I_GetPreciseTime();
PS_START_TIMING(ps_sw_portaltime);
if (portal_base)
{
portal_t *portal;
@ -1560,17 +1561,17 @@ void R_RenderPlayerView(player_t *player)
Portal_Remove(portal);
}
}
ps_sw_portaltime = I_GetPreciseTime() - ps_sw_portaltime;
PS_STOP_TIMING(ps_sw_portaltime);
ps_sw_planetime = I_GetPreciseTime();
PS_START_TIMING(ps_sw_planetime);
R_DrawPlanes();
ps_sw_planetime = I_GetPreciseTime() - ps_sw_planetime;
PS_STOP_TIMING(ps_sw_planetime);
// draw mid texture and sprite
// And now 3D floors/sides!
ps_sw_maskedtime = I_GetPreciseTime();
PS_START_TIMING(ps_sw_maskedtime);
R_DrawMasked(masks, nummasks);
ps_sw_maskedtime = I_GetPreciseTime() - ps_sw_maskedtime;
PS_STOP_TIMING(ps_sw_maskedtime);
free(masks);
}

View file

@ -17,6 +17,7 @@
#include "d_player.h"
#include "r_data.h"
#include "r_textures.h"
#include "m_perfstats.h" // ps_metric_t
//
// POV related.
@ -79,21 +80,22 @@ boolean R_DoCulling(line_t *cullheight, line_t *viewcullheight, fixed_t vz, fixe
// Render stats
extern precise_t ps_prevframetime;// time when previous frame was rendered
extern precise_t ps_rendercalltime;
extern precise_t ps_uitime;
extern precise_t ps_swaptime;
extern ps_metric_t ps_rendercalltime;
extern ps_metric_t ps_otherrendertime;
extern ps_metric_t ps_uitime;
extern ps_metric_t ps_swaptime;
extern precise_t ps_bsptime;
extern ps_metric_t ps_bsptime;
extern precise_t ps_sw_spritecliptime;
extern precise_t ps_sw_portaltime;
extern precise_t ps_sw_planetime;
extern precise_t ps_sw_maskedtime;
extern ps_metric_t ps_sw_spritecliptime;
extern ps_metric_t ps_sw_portaltime;
extern ps_metric_t ps_sw_planetime;
extern ps_metric_t ps_sw_maskedtime;
extern int ps_numbspcalls;
extern int ps_numsprites;
extern int ps_numdrawnodes;
extern int ps_numpolyobjects;
extern ps_metric_t ps_numbspcalls;
extern ps_metric_t ps_numsprites;
extern ps_metric_t ps_numdrawnodes;
extern ps_metric_t ps_numpolyobjects;
//
// REFRESH - the actual rendering functions.

View file

@ -227,8 +227,8 @@ void RotatedPatch_DoRotation(rotsprite_t *rotsprite, patch_t *patch, INT32 angle
ox = (newwidth / 2) + (leftoffset - xpivot);
oy = (newheight / 2) + (patch->topoffset - ypivot);
width = (maxx - minx);
height = (maxy - miny);
width = (maxx+1 - minx);
height = (maxy+1 - miny);
if ((unsigned)(width * height) != size)
{

View file

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

View file

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

View file

@ -89,8 +89,6 @@ static fixed_t planeheight;
fixed_t yslopetab[MAXVIDHEIGHT*16];
fixed_t *yslope;
fixed_t basexscale, baseyscale;
fixed_t cachedheight[MAXVIDHEIGHT];
fixed_t cacheddistance[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.
//
struct
static struct
{
INT32 offset;
fixed_t xfrac, yfrac;
@ -143,15 +141,6 @@ static void R_UpdatePlaneRipple(void)
planeripple.offset = (leveltime * 140);
}
//
// R_MapPlane
//
// Uses global vars:
// planeheight
// basexscale
// baseyscale
// centerx
static void R_MapPlane(INT32 y, INT32 x1, INT32 x2)
{
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]);
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_ystep = FixedMul(planecos, planeheight) / span;
}
else
{
ds_xstep = FixedMul(distance, basexscale);
ds_ystep = FixedMul(distance, baseyscale);
}
ds_xstep = ds_ystep = FRACUNIT;
cachedxstep[y] = ds_xstep;
cachedystep[y] = ds_ystep;
@ -197,6 +183,11 @@ static void R_MapPlane(INT32 y, INT32 x1, INT32 x2)
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_yfrac = yoffs - FixedMul(planesin, distance) + (x1 - centerx) * ds_ystep;
@ -295,7 +286,6 @@ void R_ClearFFloorClips (void)
void R_ClearPlanes(void)
{
INT32 i, p;
angle_t angle;
// opening / clipping determination
for (i = 0; i < viewwidth; i++)
@ -321,13 +311,6 @@ void R_ClearPlanes(void)
// texture calculation
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)
@ -335,7 +318,7 @@ static visplane_t *new_visplane(unsigned hash)
visplane_t *check = freetail;
if (!check)
{
check = calloc(2, sizeof (*check));
check = malloc(sizeof (*check));
if (check == NULL) I_Error("%s: Out of memory", "new_visplane"); // FIXME: ugly
}
else
@ -380,9 +363,11 @@ visplane_t *R_FindPlane(fixed_t height, INT32 picnum, INT32 lightlevel,
{
if (polyobj->angle != 0)
{
angle_t fineshift = polyobj->angle >> ANGLETOFINESHIFT;
xoff -= FixedMul(FINECOSINE(fineshift), polyobj->centerPt.x)+FixedMul(FINESINE(fineshift), polyobj->centerPt.y);
yoff -= FixedMul(FINESINE(fineshift), polyobj->centerPt.x)-FixedMul(FINECOSINE(fineshift), polyobj->centerPt.y);
float ang = ANG2RAD(polyobj->angle);
float x = FixedToFloat(polyobj->centerPt.x);
float y = FixedToFloat(polyobj->centerPt.y);
xoff -= FloatToFixed(x * cos(ang) + y * sin(ang));
yoff -= FloatToFixed(x * sin(ang) - y * cos(ang));
}
else
{
@ -530,53 +515,22 @@ visplane_t *R_CheckPlane(visplane_t *pl, INT32 start, INT32 stop)
//
// 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
// 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
// overlap.
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.
if (pl->polyobj)
return;
if (pl->minx > start) pl->minx = start;
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
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)
{
R_MapPlane(t1, spanstart[t1], x - 1);
mapfunc(t1, spanstart[t1], x - 1);
t1++;
}
while (b1 > b2 && b1 >= t1)
{
R_MapPlane(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);
mapfunc(b1, spanstart[b1], x - 1);
b1--;
}
@ -865,11 +793,10 @@ void R_DrawSinglePlane(visplane_t *pl)
{
levelflat_t *levelflat;
INT32 light = 0;
INT32 x;
INT32 stop, angle;
INT32 x, stop;
ffloor_t *rover;
INT32 type;
INT32 spanfunctype = BASEDRAWFUNC;
INT32 type, spanfunctype = BASEDRAWFUNC;
void (*mapfunc)(INT32, INT32, INT32) = R_MapPlane;
if (!(pl->minx <= pl->maxx))
return;
@ -1021,9 +948,6 @@ void R_DrawSinglePlane(visplane_t *pl)
&& viewangle != pl->viewangle+pl->plangle)
{
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;
}
@ -1038,6 +962,8 @@ void R_DrawSinglePlane(visplane_t *pl)
if (pl->slope)
{
mapfunc = R_MapTiltedPlane;
if (!pl->plangle)
{
if (ds_powersoftwo)
@ -1105,16 +1031,8 @@ void R_DrawSinglePlane(visplane_t *pl)
stop = pl->maxx + 1;
if (pl->slope)
{
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]);
}
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]);
/*
QUINCUNX anti-aliasing technique (sort of)
@ -1181,7 +1099,7 @@ using the palette colors.
stop = pl->maxx + 1;
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]);
}
}

View file

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

View file

@ -242,6 +242,11 @@ boolean R_SkinUsable(INT32 playernum, INT32 skinnum)
// Force 3.
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.

View file

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

View file

@ -34,8 +34,7 @@ typedef struct floorsplat_s
INT32 width, height;
fixed_t scale, xscale, yscale;
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
fixed_t x, y, z; // position

View file

@ -727,7 +727,7 @@ Rloadflats (INT32 i, INT32 w)
texpatch_t *patch;
// Yes
if (wadfiles[w]->type == RET_PK3)
if (W_FileHasFolders(wadfiles[w]))
{
texstart = W_CheckNumForFolderStartPK3("flats/", (UINT16)w, 0);
texend = W_CheckNumForFolderEndPK3("flats/", (UINT16)w, texstart);
@ -749,7 +749,7 @@ Rloadflats (INT32 i, INT32 w)
size_t lumplength;
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
continue; // If it is then SKIP IT
@ -839,7 +839,7 @@ Rloadtextures (INT32 i, INT32 w)
texpatch_t *patch;
// 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);
texend = W_CheckNumForFolderEndPK3("textures/", (UINT16)w, texstart);
@ -870,7 +870,7 @@ Rloadtextures (INT32 i, INT32 w)
size_t lumplength;
#endif
if (wadfiles[w]->type == RET_PK3)
if (W_FileHasFolders(wadfiles[w]))
{
if (W_IsLumpFolder(wadnum, lumpnum)) // Check if lump is a folder
continue; // If it is then SKIP IT
@ -959,7 +959,7 @@ void R_LoadTextures(void)
{
#ifdef WALLFLATS
// Count flats
if (wadfiles[w]->type == RET_PK3)
if (W_FileHasFolders(wadfiles[w]))
{
texstart = W_CheckNumForFolderStartPK3("flats/", (UINT16)w, 0);
texend = W_CheckNumForFolderEndPK3("flats/", (UINT16)w, texstart);
@ -973,7 +973,7 @@ void R_LoadTextures(void)
if (!( texstart == INT16_MAX || texend == INT16_MAX ))
{
// 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++)
{
@ -997,7 +997,7 @@ void R_LoadTextures(void)
}
// Count single-patch textures
if (wadfiles[w]->type == RET_PK3)
if (W_FileHasFolders(wadfiles[w]))
{
texstart = W_CheckNumForFolderStartPK3("textures/", (UINT16)w, 0);
texend = W_CheckNumForFolderEndPK3("textures/", (UINT16)w, texstart);
@ -1012,7 +1012,7 @@ void R_LoadTextures(void)
continue;
// 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++)
{
@ -1553,6 +1553,7 @@ lumpnum_t R_GetFlatNumForName(const char *name)
continue;
break;
case RET_PK3:
case RET_FOLDER:
if ((start = W_CheckNumForFolderStartPK3("Flats/", i, 0)) == INT16_MAX)
continue;
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.
break;
case RET_PK3:
case RET_FOLDER:
start = W_CheckNumForFolderStartPK3("Sprites/", wadnum, 0);
end = W_CheckNumForFolderEndPK3("Sprites/", wadnum, start);
break;
@ -1956,9 +1957,12 @@ static void R_ProjectSprite(mobj_t *thing)
vis->paperoffset = paperoffset;
vis->paperdistance = paperdistance;
vis->centerangle = centerangle;
vis->viewangle = viewangle;
vis->shear.tan = sheartan;
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
@ -2741,7 +2745,7 @@ static drawnode_t *R_CreateDrawNode(drawnode_t *link)
node->ffloor = NULL;
node->sprite = NULL;
ps_numdrawnodes++;
ps_numdrawnodes.value.i++;
return node;
}

View file

@ -164,7 +164,12 @@ typedef struct vissprite_s
fixed_t xiscale; // negative if flipped
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 {
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
// Precalculated top and bottom screen coords for the sprite.
fixed_t thingheight; // The actual height of the thing (for 3D floors)
sector_t *sector; // The sector containing the thing.
// Precalculated top and bottom screen coords for the sprite.
INT16 sz, szt;
spritecut_e cut;

View file

@ -550,7 +550,7 @@ static void I_StartupConsole(void)
void I_GetConsoleEvents(void)
{
// we use this when sending back commands
event_t ev = {0,0,0,0};
event_t ev = {0};
char key = 0;
ssize_t d;
@ -572,7 +572,7 @@ void I_GetConsoleEvents(void)
tty_con.buffer[tty_con.cursor] = '\0';
tty_Back();
}
ev.data1 = KEY_BACKSPACE;
ev.key = KEY_BACKSPACE;
}
else if (key < ' ') // check if this is a control char
{
@ -580,19 +580,19 @@ void I_GetConsoleEvents(void)
{
tty_Clear();
tty_con.cursor = 0;
ev.data1 = KEY_ENTER;
ev.key = KEY_ENTER;
}
else return;
}
else
{
// push regular character
ev.data1 = tty_con.buffer[tty_con.cursor] = key;
ev.key = tty_con.buffer[tty_con.cursor] = key;
tty_con.cursor++;
// print the current line (this is differential)
d = write(STDOUT_FILENO, &key, 1);
}
if (ev.data1) D_PostEvent(&ev);
if (ev.key) D_PostEvent(&ev);
//tty_FlushIn();
(void)d;
}
@ -626,18 +626,18 @@ static void Impl_HandleKeyboardConsoleEvent(KEY_EVENT_RECORD evt, HANDLE co)
{
case VK_ESCAPE:
case VK_TAB:
event.data1 = KEY_NULL;
event.key = KEY_NULL;
break;
case VK_RETURN:
entering_con_command = false;
/* FALLTHRU */
default:
//event.data1 = MapVirtualKey(evt.wVirtualKeyCode,2); // convert in to char
event.data1 = evt.uChar.AsciiChar;
//event.key = MapVirtualKey(evt.wVirtualKeyCode,2); // convert in to char
event.key = evt.uChar.AsciiChar;
}
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
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)
@ -917,7 +917,7 @@ INT32 I_GetKey (void)
ev = &events[eventtail];
if (ev->type == ev_keydown || ev->type == ev_console)
{
rc = ev->data1;
rc = ev->key;
continue;
}
}
@ -977,22 +977,22 @@ void I_ShutdownJoystick(void)
INT32 i;
event_t event;
event.type=ev_keyup;
event.data2 = 0;
event.data3 = 0;
event.x = 0;
event.y = 0;
lastjoybuttons = lastjoyhats = 0;
// emulate the up of all joystick buttons
for (i=0;i<JOYBUTTONS;i++)
{
event.data1=KEY_JOY1+i;
event.key=KEY_JOY1+i;
D_PostEvent(&event);
}
// emulate the up of all joystick hats
for (i=0;i<JOYHATS*4;i++)
{
event.data1=KEY_HAT1+i;
event.key=KEY_HAT1+i;
D_PostEvent(&event);
}
@ -1000,7 +1000,7 @@ void I_ShutdownJoystick(void)
event.type = ev_joystick;
for (i=0;i<JOYAXISSET; i++)
{
event.data1 = i;
event.key = i;
D_PostEvent(&event);
}
@ -1012,7 +1012,7 @@ void I_ShutdownJoystick(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;
UINT64 joyhats = 0;
#if 0
@ -1049,7 +1049,7 @@ void I_GetJoystickEvents(void)
event.type = ev_keydown;
else
event.type = ev_keyup;
event.data1 = KEY_JOY1 + i;
event.key = KEY_JOY1 + i;
D_PostEvent(&event);
}
}
@ -1080,7 +1080,7 @@ void I_GetJoystickEvents(void)
event.type = ev_keydown;
else
event.type = ev_keyup;
event.data1 = KEY_HAT1 + i;
event.key = KEY_HAT1 + i;
D_PostEvent(&event);
}
}
@ -1092,7 +1092,7 @@ void I_GetJoystickEvents(void)
for (i = JOYAXISSET - 1; i >= 0; i--)
{
event.data1 = i;
event.key = i;
if (i*2 + 1 <= JoyInfo.axises)
axisx = SDL_JoystickGetAxis(JoyInfo.dev, i*2 + 0);
else axisx = 0;
@ -1110,15 +1110,15 @@ void I_GetJoystickEvents(void)
{
// gamepad control type, on or off, live or die
if (axisx < -(JOYAXISRANGE/2))
event.data2 = -1;
event.x = -1;
else if (axisx > (JOYAXISRANGE/2))
event.data2 = 1;
else event.data2 = 0;
event.x = 1;
else event.x = 0;
if (axisy < -(JOYAXISRANGE/2))
event.data3 = -1;
event.y = -1;
else if (axisy > (JOYAXISRANGE/2))
event.data3 = 1;
else event.data3 = 0;
event.y = 1;
else event.y = 0;
}
else
{
@ -1132,8 +1132,8 @@ void I_GetJoystickEvents(void)
#endif
// analog control style , just send the raw data
event.data2 = axisx; // x axis
event.data3 = axisy; // y axis
event.x = axisx; // x axis
event.y = axisy; // y axis
}
D_PostEvent(&event);
}
@ -1247,22 +1247,22 @@ void I_ShutdownJoystick2(void)
INT32 i;
event_t event;
event.type = ev_keyup;
event.data2 = 0;
event.data3 = 0;
event.x = 0;
event.y = 0;
lastjoy2buttons = lastjoy2hats = 0;
// emulate the up of all joystick buttons
for (i = 0; i < JOYBUTTONS; i++)
{
event.data1 = KEY_2JOY1 + i;
event.key = KEY_2JOY1 + i;
D_PostEvent(&event);
}
// emulate the up of all joystick hats
for (i = 0; i < JOYHATS*4; i++)
{
event.data1 = KEY_2HAT1 + i;
event.key = KEY_2HAT1 + i;
D_PostEvent(&event);
}
@ -1270,7 +1270,7 @@ void I_ShutdownJoystick2(void)
event.type = ev_joystick2;
for (i = 0; i < JOYAXISSET; i++)
{
event.data1 = i;
event.key = i;
D_PostEvent(&event);
}
@ -1282,7 +1282,7 @@ void I_ShutdownJoystick2(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;
UINT64 joyhats = 0;
#if 0
@ -1321,7 +1321,7 @@ void I_GetJoystick2Events(void)
event.type = ev_keydown;
else
event.type = ev_keyup;
event.data1 = KEY_2JOY1 + i;
event.key = KEY_2JOY1 + i;
D_PostEvent(&event);
}
}
@ -1352,7 +1352,7 @@ void I_GetJoystick2Events(void)
event.type = ev_keydown;
else
event.type = ev_keyup;
event.data1 = KEY_2HAT1 + i;
event.key = KEY_2HAT1 + i;
D_PostEvent(&event);
}
}
@ -1364,7 +1364,7 @@ void I_GetJoystick2Events(void)
for (i = JOYAXISSET - 1; i >= 0; i--)
{
event.data1 = i;
event.key = i;
if (i*2 + 1 <= JoyInfo2.axises)
axisx = SDL_JoystickGetAxis(JoyInfo2.dev, i*2 + 0);
else axisx = 0;
@ -1380,17 +1380,17 @@ void I_GetJoystick2Events(void)
{
// gamepad control type, on or off, live or die
if (axisx < -(JOYAXISRANGE/2))
event.data2 = -1;
event.x = -1;
else if (axisx > (JOYAXISRANGE/2))
event.data2 = 1;
event.x = 1;
else
event.data2 = 0;
event.x = 0;
if (axisy < -(JOYAXISRANGE/2))
event.data3 = -1;
event.y = -1;
else if (axisy > (JOYAXISRANGE/2))
event.data3 = 1;
event.y = 1;
else
event.data3 = 0;
event.y = 0;
}
else
{
@ -1404,8 +1404,8 @@ void I_GetJoystick2Events(void)
#endif
// analog control style , just send the raw data
event.data2 = axisx; // x axis
event.data3 = axisy; // y axis
event.x = axisx; // x axis
event.y = axisy; // y axis
}
D_PostEvent(&event);
}
@ -1804,7 +1804,7 @@ void I_GetMouseEvents(void)
if (!(button & (1<<j))) //keyup
{
event.type = ev_keyup;
event.data1 = KEY_2MOUSE1+j;
event.key = KEY_2MOUSE1+j;
D_PostEvent(&event);
om2b ^= 1 << j;
}
@ -1814,18 +1814,18 @@ void I_GetMouseEvents(void)
if (button & (1<<j))
{
event.type = ev_keydown;
event.data1 = KEY_2MOUSE1+j;
event.key = KEY_2MOUSE1+j;
D_PostEvent(&event);
om2b ^= 1 << j;
}
}
}
event.data2 = ((SINT8)mdata[1])+((SINT8)mdata[3]);
event.data3 = ((SINT8)mdata[2])+((SINT8)mdata[4]);
if (event.data2 && event.data3)
event.x = ((SINT8)mdata[1])+((SINT8)mdata[3]);
event.y = ((SINT8)mdata[2])+((SINT8)mdata[4]);
if (event.x && event.y)
{
event.type = ev_mouse2;
event.data1 = 0;
event.key = 0;
D_PostEvent(&event);
}
}
@ -1867,7 +1867,7 @@ static void I_ShutdownMouse2(void)
for (i = 0; i < MOUSEBUTTONS; i++)
{
event.type = ev_keyup;
event.data1 = KEY_2MOUSE1+i;
event.key = KEY_2MOUSE1+i;
D_PostEvent(&event);
}
@ -1958,7 +1958,7 @@ void I_GetMouseEvents(void)
event.type = ev_keydown;
else
event.type = ev_keyup;
event.data1 = KEY_2MOUSE1+i;
event.key = KEY_2MOUSE1+i;
D_PostEvent(&event);
}
}
@ -1966,10 +1966,10 @@ void I_GetMouseEvents(void)
if (handlermouse2x != 0 || handlermouse2y != 0)
{
event.type = ev_mouse2;
event.data1 = 0;
// event.data1 = buttons; // not needed
event.data2 = handlermouse2x << 1;
event.data3 = handlermouse2y << 1;
event.key = 0;
// event.key = buttons; // not needed
event.x = handlermouse2x << 1;
event.y = handlermouse2y << 1;
handlermouse2x = 0;
handlermouse2y = 0;
@ -2163,7 +2163,13 @@ precise_t I_GetPreciseTime(void)
int I_PreciseToMicros(precise_t d)
{
return (int)(d / (timer_frequency / 1000000.0));
// d is going to be converted into a double. So remove the highest bits
// to avoid loss of precision in the lower bits, for the (probably rare) case
// that the higher bits are actually used.
d &= ((precise_t)1 << 53) - 1; // The mantissa of a double can handle 53 bits at most.
// The resulting double from the calculation is converted first to UINT64 to avoid overflow,
// which is undefined behaviour when converting floating point values to integers.
return (int)(UINT64)(d / (timer_frequency / 1000000.0));
}
//

View file

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

View file

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

View file

@ -43,6 +43,7 @@
#endif
#include "lua_hud.h"
#include "lua_hook.h"
UINT16 objectsdrawn = 0;
@ -1391,7 +1392,7 @@ void ST_drawTitleCard(void)
lt_lasttic = lt_ticker;
luahook:
LUAh_TitleCardHUD(stplyr);
LUA_HUDHOOK(titlecard);
}
//
@ -2036,9 +2037,8 @@ static void ST_drawNiGHTSHUD(void)
else
numbersize = 48/2;
if ((oldspecialstage && leveltime & 2)
&& (stplyr->mo->eflags & (MFE_TOUCHWATER|MFE_UNDERWATER))
&& !(stplyr->powers[pw_shield] & SH_PROTECTWATER))
if ((oldspecialstage && leveltime & 2) &&
(stplyr->mo->eflags & (MFE_TOUCHWATER|MFE_UNDERWATER) && !(stplyr->powers[pw_shield] & ((stplyr->mo->eflags & MFE_TOUCHLAVA) ? SH_PROTECTFIRE : SH_PROTECTWATER))))
col = SKINCOLOR_ORANGE;
ST_DrawNightsOverlayNum((160 + numbersize)<<FRACBITS, 14<<FRACBITS, FRACUNIT, V_PERPLAYER|V_SNAPTOTOP, realnightstime, nightsnum, col);
@ -2187,7 +2187,7 @@ static void ST_drawMatchHUD(void)
{
sprintf(penaltystr, "-%d", stplyr->ammoremoval);
V_DrawString(offset + 8 + stplyr->ammoremovalweapon * 20, y,
V_REDMAP|V_SNAPTOBOTTOM, penaltystr);
V_REDMAP|V_SNAPTOBOTTOM|V_PERPLAYER, penaltystr);
}
}
@ -2732,7 +2732,7 @@ static void ST_overlayDrawer(void)
ST_drawPowerupHUD(); // same as it ever was...
if (!(netgame || multiplayer) || !hu_showscores)
LUAh_GameHUD(stplyr);
LUA_HUDHOOK(game);
// draw level title Tails
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.
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);
UINT32 alphalevel = 0;
// boolean flip = false;
fixed_t col, ofs, colfrac, rowfrac, fdup;
fixed_t col, ofs, colfrac, rowfrac, fdup, vdup;
INT32 dupx, dupy;
const column_t *column;
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_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;
}
#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)
dupx = dupy = (vid.dupx < vid.dupy ? vid.dupx : vid.dupy);
fdup = FixedMul(dupx<<FRACBITS, pscale);
colfrac = FixedDiv(FRACUNIT, fdup);
rowfrac = FixedDiv(FRACUNIT, fdup);
v_colormap = NULL;
if (colormap)
{
v_colormap = colormap;
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);
y -= FixedMul(patch->topoffset<<FRACBITS, vscale);
if (splitscreen && (scrn & V_PERPLAYER))
{
fixed_t adjusty = ((scrn & V_NOSCALESTART) ? vid.height : BASEVIDHEIGHT)<<(FRACBITS-1);
fdup >>= 1;
vdup >>= 1;
rowfrac <<= 1;
y >>= 1;
sy >>= 1;
h >>= 1;
#ifdef QUADS
if (splitscreen > 1) // 3 or 4 players
{
fixed_t adjustx = ((scrn & V_NOSCALESTART) ? vid.height : BASEVIDHEIGHT)<<(FRACBITS-1));
fdup >>= 1;
colfrac <<= 1;
x >>= 1;
sx >>= 1;
w >>= 1;
if (stplyr == &players[displayplayer])
{
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)))
perplayershuffle |= 8;
x += adjustx;
sx += adjustx;
scrn &= ~V_SNAPTOBOTTOM|V_SNAPTOLEFT;
}
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)))
perplayershuffle |= 4;
y += adjusty;
sy += adjusty;
scrn &= ~V_SNAPTOTOP|V_SNAPTORIGHT;
}
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)))
perplayershuffle |= 8;
x += adjustx;
sx += adjustx;
y += adjusty;
sy += adjusty;
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)))
perplayershuffle |= 2;
y += adjusty;
sy += adjusty;
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;
if (scrn & V_NOSCALESTART) {
if (scrn & V_NOSCALESTART)
{
x >>= FRACBITS;
y >>= FRACBITS;
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;
}
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;
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;
source = (const UINT8 *)(column) + 3;
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;
}
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)
*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_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_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);

View file

@ -1,6 +1,6 @@
#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.
// "18" is the default mod ID for version 2.2
#define MODID 18

View file

@ -50,16 +50,17 @@
#include "filesrch.h"
#include "i_video.h" // rendermode
#include "d_main.h"
#include "d_netfil.h"
#include "dehacked.h"
#include "d_clisrv.h"
#include "dehacked.h"
#include "r_defs.h"
#include "r_data.h"
#include "r_textures.h"
#include "r_patch.h"
#include "r_picformats.h"
#include "i_system.h"
#include "i_video.h" // rendermode
#include "md5.h"
#include "lua_script.h"
#ifdef SCANTHINGS
@ -104,7 +105,7 @@ static UINT16 lumpnumcacheindex = 0;
// GLOBALS
//===========================================================================
UINT16 numwadfiles; // number of active wadfiles
wadfile_t *wadfiles[MAX_WADFILES]; // 0 to numwadfiles-1 are valid
wadfile_t **wadfiles; // 0 to numwadfiles-1 are valid
// W_Shutdown
// Closes all of the WAD files before quitting
@ -117,10 +118,15 @@ void W_Shutdown(void)
{
wadfile_t *wad = wadfiles[numwadfiles];
fclose(wad->handle);
if (wad->handle)
fclose(wad->handle);
Z_Free(wad->filename);
if (wad->path)
Z_Free(wad->path);
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].fullname);
}
@ -128,6 +134,8 @@ void W_Shutdown(void)
Z_Free(wad->lumpinfo);
Z_Free(wad);
}
Z_Free(wadfiles);
}
//===========================================================================
@ -421,6 +429,7 @@ static lumpinfo_t* ResGetLumpsWad (FILE* handle, UINT16* nlmp, const char* filen
{
lump_p->position = LONG(fileinfo->filepos);
lump_p->size = lump_p->disksize = LONG(fileinfo->size);
lump_p->diskpath = NULL;
if (compressed) // wad is compressed, lump might be
{
UINT32 realsize = 0;
@ -602,6 +611,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->disksize = zentry.compsize;
lump_p->diskpath = NULL;
lump_p->size = zentry.size;
fullname = malloc(zentry.namelen + 1);
@ -679,6 +689,114 @@ static lumpinfo_t* ResGetLumpsZip (FILE* handle, UINT16* nlmp)
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)
{
if (exitworthy)
@ -694,6 +812,19 @@ static UINT16 W_InitFileError (const char *filename, boolean exitworthy)
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
// lumpcache, add the wadfile to the current active wadfiles
//
@ -715,7 +846,6 @@ UINT16 W_InitFile(const char *filename, boolean mainfile, boolean startup)
#ifndef NOMD5
size_t i;
#endif
size_t packetsize;
UINT8 md5sum[16];
int important;
@ -733,9 +863,8 @@ UINT16 W_InitFile(const char *filename, boolean mainfile, boolean startup)
refreshdirname = NULL;
//CONS_Debug(DBG_SETUP, "Loading %s\n", filename);
//
// check if limit of active wadfiles
//
// Check if the game reached the limit of active wadfiles.
if (numwadfiles >= MAX_WADFILES)
{
CONS_Alert(CONS_ERROR, M_GetText("Maximum wad files reached\n"));
@ -755,24 +884,7 @@ UINT16 W_InitFile(const char *filename, boolean mainfile, boolean startup)
return INT16_MAX;
}
// Check if wad files will overflow fileneededbuffer. Only the filename part
// is send in the packet; cf.
// see PutFileNeeded in d_netfil.c
if ((important = !important))
{
packetsize = packetsizetally + nameonlylength(filename) + 22;
if (packetsize > MAXFILENEEDED*sizeof(UINT8))
{
CONS_Alert(CONS_ERROR, M_GetText("Maximum wad files reached\n"));
refreshdirmenu |= REFRESHDIR_MAX;
if (handle)
fclose(handle);
return W_InitFileError(filename, startup);
}
packetsizetally = packetsize;
}
important = !important;
#ifndef NOMD5
//
@ -784,11 +896,12 @@ UINT16 W_InitFile(const char *filename, boolean mainfile, boolean startup)
for (i = 0; i < numwadfiles; i++)
{
if (wadfiles[i]->type == RET_FOLDER)
continue;
if (!memcmp(wadfiles[i]->md5sum, md5sum, 16))
{
CONS_Alert(CONS_ERROR, M_GetText("%s is already loaded\n"), filename);
if (important)
packetsizetally -= nameonlylength(filename) + 22;
if (handle)
fclose(handle);
return W_InitFileError(filename, false);
@ -831,9 +944,11 @@ UINT16 W_InitFile(const char *filename, boolean mainfile, boolean startup)
//
wadfile = Z_Malloc(sizeof (*wadfile), PU_STATIC, NULL);
wadfile->filename = Z_StrDup(filename);
wadfile->path = NULL;
wadfile->type = type;
wadfile->handle = handle;
wadfile->numlumps = (UINT16)numlumps;
wadfile->numlumps = numlumps;
wadfile->foldercount = 0;
wadfile->lumpinfo = lumpinfo;
wadfile->important = important;
fseek(handle, 0, SEEK_END);
@ -853,17 +968,12 @@ UINT16 W_InitFile(const char *filename, boolean mainfile, boolean startup)
// add the wadfile
//
CONS_Printf(M_GetText("Added file %s (%u lumps)\n"), filename, numlumps);
wadfiles = Z_Realloc(wadfiles, sizeof(wadfile_t) * (numwadfiles + 1), PU_STATIC, NULL);
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
#ifdef HWRENDER
// Read shaders from file
if (rendermode == render_opengl && (vid.glstate == VID_GL_LIBRARY_LOADED))
{
HWR_LoadCustomShadersFromFile(numwadfiles - 1, (type == RET_PK3));
HWR_CompileShaders();
}
#endif // HWRENDER
W_ReadFileShaders(wadfile);
// 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)
@ -889,6 +999,163 @@ UINT16 W_InitFile(const char *filename, boolean mainfile, boolean startup)
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.
// 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);
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.
* All files are wads unless they have an extension of ".soc" or ".lua".
*
@ -898,13 +1165,22 @@ UINT16 W_InitFile(const char *filename, boolean mainfile, boolean startup)
*
* \param filenames A null-terminated list of files to use.
*/
void W_InitMultipleFiles(char **filenames)
void W_InitMultipleFiles(addfilelist_t *list)
{
// will be realloced as lumps are added
for (; *filenames; filenames++)
size_t i = 0;
for (; i < list->numfiles; i++)
{
//CONS_Debug(DBG_SETUP, "Loading %s\n", *filenames);
W_InitFile(*filenames, numwadfiles < mainwads, true);
const char *fn = list->files[i];
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);
}
}
@ -913,7 +1189,7 @@ void W_InitMultipleFiles(char **filenames)
*/
static boolean TestValidLump(UINT16 wad, UINT16 lump)
{
I_Assert(wad < MAX_WADFILES);
I_Assert(wad < numwadfiles);
if (!wadfiles[wad]) // make sure the wad file exists
return false;
@ -1178,7 +1454,7 @@ lumpnum_t W_CheckNumForMap(const char *name)
if (!strncmp(name, (wadfiles[i]->lumpinfo + lumpNum)->name, 8))
return (i<<16) + lumpNum;
}
else if (wadfiles[i]->type == RET_PK3)
else if (W_FileHasFolders(wadfiles[i]))
{
lumpNum = W_CheckNumForFolderStartPK3("maps/", i, 0);
if (lumpNum != INT16_MAX)
@ -1276,9 +1552,46 @@ UINT8 W_LumpExists(const char *name)
size_t W_LumpLengthPwad(UINT16 wad, UINT16 lump)
{
lumpinfo_t *l;
if (!TestValidLump(wad, lump))
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.
@ -1293,11 +1606,11 @@ size_t W_LumpLength(lumpnum_t lumpnum)
//
// W_IsLumpWad
// Is the lump a WAD? (presumably in a PK3)
// Is the lump a WAD? (presumably not in a WAD)
//
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;
@ -1306,23 +1619,23 @@ boolean W_IsLumpWad(lumpnum_t lumpnum)
return !strnicmp(lumpfullName + strlen(lumpfullName) - 4, ".wad", 4);
}
return false; // WADs should never be inside non-PK3s as far as SRB2 is concerned
return false; // WADs should never be inside WADs as far as SRB2 is concerned
}
//
// W_IsLumpFolder
// Is the lump a folder? (in a PK3 obviously)
// Is the lump a folder? (not in a WAD obviously)
//
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;
return (name[strlen(name)-1] == '/'); // folders end in '/'
}
return false; // non-PK3s don't have folders
return false; // WADs don't have folders
}
#ifdef HAVE_ZLIB
@ -1365,17 +1678,55 @@ void zerr(int ret)
*/
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;
FILE *handle;
FILE *handle = NULL;
if (!TestValidLump(wad,lump))
if (!TestValidLump(wad, lump))
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;
// empty resource (usually markers like S_START, F_END ..)
if (!lumpsize || lumpsize<offset)
{
if (wadfiles[wad]->type == RET_FOLDER)
fclose(handle);
return 0;
}
// zero size means read all the lump
if (!size || size+offset > lumpsize)
@ -1383,24 +1734,22 @@ size_t W_ReadLumpHeaderPwad(UINT16 wad, UINT16 lump, void *dest, size_t size, si
// Let's get the raw lump data.
// We setup the desired file handle to read the lump data.
l = wadfiles[wad]->lumpinfo + lump;
handle = wadfiles[wad]->handle;
if (wadfiles[wad]->type != RET_FOLDER)
handle = wadfiles[wad]->handle;
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.
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.
bytesread = fread(dest, 1, size, handle);
if (wadfiles[wad]->type == RET_FOLDER)
fclose(handle);
#ifdef NO_PNG_LUMPS
{
size_t bytesread = fread(dest, 1, size, handle);
if (Picture_IsLumpPNG((UINT8 *)dest, bytesread))
Picture_ThrowPNGError(l->fullname, wadfiles[wad]->filename);
return bytesread;
}
#else
return fread(dest, 1, size, handle);
if (Picture_IsLumpPNG((UINT8 *)dest, bytesread))
Picture_ThrowPNGError(l->fullname, wadfiles[wad]->filename);
#endif
return bytesread;
case CM_LZF: // Is it LZF compressed? Used by ZWADs.
{
#ifdef ZWAD
@ -1838,7 +2187,7 @@ void W_VerifyFileMD5(UINT16 wadfilenum, const char *matchmd5)
#else
I_Error
#endif
(M_GetText("File is old, is corrupt or has been modified: %s (found md5: %s, wanted: %s)\n"), wadfiles[wadfilenum]->filename, actualmd5text, matchmd5);
(M_GetText("File is old, is corrupt or has been modified:\n%s\nFound MD5: %s\nWanted MD5: %s\n"), wadfiles[wadfilenum]->filename, actualmd5text, matchmd5);
}
#endif
}

View file

@ -69,6 +69,7 @@ typedef struct
char name[9]; // filelump_t name[] e.g. "LongEntr"
char *longname; // e.g. "LongEntryName"
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
compmethod compression; // lump compression method
} lumpinfo_t;
@ -96,9 +97,15 @@ virtlump_t* vres_Find(const virtres_t*, const char*);
// DYNAMIC WAD LOADING
// =========================================================================
// Maximum of files that can be loaded
// (there is a max of simultaneous open files anyway)
#ifdef ENFORCE_WAD_LIMIT
#define MAX_WADFILES 2048 // This cannot be any higher than UINT16_MAX.
#else
#define MAX_WADFILES UINT16_MAX
#endif
#define MAX_WADPATH 512
#define MAX_WADFILES 48 // maximum of wad files used at the same time
// (there is a max of simultaneous open files anyway, and this should be plenty)
#define lumpcache_t void *
@ -109,17 +116,19 @@ typedef enum restype
RET_SOC,
RET_LUA,
RET_PK3,
RET_FOLDER,
RET_UNKNOWN,
} restype_t;
typedef struct wadfile_s
{
char *filename;
char *filename, *path;
restype_t type;
lumpinfo_t *lumpinfo;
lumpcache_t *lumpcache;
lumpcache_t *patchcache;
UINT16 numlumps; // this wad's number of resources
UINT16 foldercount; // folder count
FILE *handle;
UINT32 filesize; // for network
UINT8 md5sum[16];
@ -127,11 +136,17 @@ typedef struct wadfile_s
boolean important; // also network - !W_VerifyNMUSlumps
} 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
extern UINT16 numwadfiles;
extern wadfile_t *wadfiles[MAX_WADFILES];
extern wadfile_t **wadfiles;
typedef struct
{
char **files;
size_t numfiles;
} addfilelist_t;
// =========================================================================
@ -141,9 +156,16 @@ void W_Shutdown(void);
FILE *W_OpenWadFile(const char **filename, boolean useerrors);
// Load and add a wadfile to the active wad files, returns numbers of lumps, INT16_MAX on error
UINT16 W_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.
void W_InitMultipleFiles(char **filenames);
void W_InitMultipleFiles(addfilelist_t *list);
#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_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;
handleKeyDoom:
ev.data1 = 0;
ev.key = 0;
if (wParam == VK_PAUSE)
// intercept PAUSE key
{
ev.data1 = KEY_PAUSE;
ev.key = KEY_PAUSE;
}
else if (!keyboard_started)
// post some keys during the game startup
@ -201,14 +201,14 @@ static LRESULT CALLBACK MainWndproc(HWND hWnd, UINT message, WPARAM wParam, LPAR
{
switch (wParam)
{
case VK_ESCAPE: ev.data1 = KEY_ESCAPE; break;
case VK_RETURN: ev.data1 = KEY_ENTER; break;
case VK_SHIFT: ev.data1 = KEY_LSHIFT; break;
default: ev.data1 = MapVirtualKey((DWORD)wParam,2); // convert in to char
case VK_ESCAPE: ev.key = KEY_ESCAPE; break;
case VK_RETURN: ev.key = KEY_ENTER; break;
case VK_SHIFT: ev.key = KEY_LSHIFT; break;
default: ev.key = MapVirtualKey((DWORD)wParam,2); // convert in to char
}
}
if (ev.data1)
if (ev.key)
D_PostEvent (&ev);
return 0;
@ -240,7 +240,7 @@ static LRESULT CALLBACK MainWndproc(HWND hWnd, UINT message, WPARAM wParam, LPAR
if (nodinput)
{
ev.type = ev_keyup;
ev.data1 = KEY_MOUSE1 + 3 + HIWORD(wParam);
ev.key = KEY_MOUSE1 + 3 + HIWORD(wParam);
D_PostEvent(&ev);
return TRUE;
}
@ -249,7 +249,7 @@ static LRESULT CALLBACK MainWndproc(HWND hWnd, UINT message, WPARAM wParam, LPAR
if (nodinput)
{
ev.type = ev_keydown;
ev.data1 = KEY_MOUSE1 + 3 + HIWORD(wParam);
ev.key = KEY_MOUSE1 + 3 + HIWORD(wParam);
D_PostEvent(&ev);
return TRUE;
}
@ -258,9 +258,9 @@ static LRESULT CALLBACK MainWndproc(HWND hWnd, UINT message, WPARAM wParam, LPAR
//I_OutputMsg("MW_WHEEL dispatched.\n");
ev.type = ev_keydown;
if ((INT16)HIWORD(wParam) > 0)
ev.data1 = KEY_MOUSEWHEELUP;
ev.key = KEY_MOUSEWHEELUP;
else
ev.data1 = KEY_MOUSEWHEELDOWN;
ev.key = KEY_MOUSEWHEELDOWN;
D_PostEvent(&ev);
break;
@ -271,7 +271,7 @@ static LRESULT CALLBACK MainWndproc(HWND hWnd, UINT message, WPARAM wParam, LPAR
case WM_CLOSE:
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;
D_PostEvent (&ev);
return 0;

View file

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

View file

@ -212,7 +212,7 @@ static void Y_IntermissionTokenDrawer(void)
calc = (lowy - y)*2;
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);
}
@ -239,12 +239,12 @@ void Y_LoadIntermissionData(void)
}
data.coop.ptotal = W_CachePatchName("YB_TOTAL", PU_PATCH);
// get background patches
bgpatch = W_CachePatchName("INTERSCR", PU_PATCH);
// grab an interscreen if appropriate
if (mapheaderinfo[gamemap-1]->interscreen[0] != '#')
interpic = W_CachePatchName(mapheaderinfo[gamemap-1]->interscreen, PU_PATCH);
else // no interscreen? use default background
bgpatch = W_CachePatchName("INTERSCR", PU_PATCH);
break;
}
case int_spec:
@ -255,12 +255,11 @@ void Y_LoadIntermissionData(void)
data.spec.pscore = W_CachePatchName("YB_SCORE", PU_PATCH);
data.spec.pcontinues = W_CachePatchName("YB_CONTI", PU_PATCH);
// get background tile
bgtile = W_CachePatchName("SPECTILE", PU_PATCH);
// grab an interscreen if appropriate
if (mapheaderinfo[gamemap-1]->interscreen[0] != '#')
interpic = W_CachePatchName(mapheaderinfo[gamemap-1]->interscreen, PU_PATCH);
else // no interscreen? use default background
bgtile = W_CachePatchName("SPECTILE", PU_PATCH);
break;
}
case int_ctf:
@ -430,7 +429,7 @@ void Y_IntermissionDrawer(void)
else if (bgtile)
V_DrawPatchFill(bgtile);
LUAh_IntermissionHUD(intertype == int_spec && stagefailed);
LUA_HUDHOOK(intermission);
if (!LUA_HudEnabled(hud_intermissiontally))
goto skiptallydrawer;

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