diff --git a/appveyor.yml b/appveyor.yml index d5f76c344..b9f84f395 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -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:: #- ps: $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1')) +# vim: et ts=1 diff --git a/extras/conf/SRB2-22.cfg b/extras/conf/SRB2-22.cfg index 467856344..608fe508f 100644 --- a/extras/conf/SRB2-22.cfg +++ b/extras/conf/SRB2-22.cfg @@ -2958,8 +2958,10 @@ linedeftypes prefix = "(700)"; flags2048text = "[11] No physics"; flags4096text = "[12] Dynamic"; + flags32768text = "[15] Copy to other side"; slope = "regular"; slopeargs = 1; + copyslopeargs = 1; } 701 @@ -2968,8 +2970,10 @@ linedeftypes prefix = "(701)"; flags2048text = "[11] No physics"; flags4096text = "[12] Dynamic"; + flags32768text = "[15] Copy to other side"; slope = "regular"; slopeargs = 2; + copyslopeargs = 4; } 702 @@ -2978,8 +2982,10 @@ linedeftypes prefix = "(702)"; flags2048text = "[11] No physics"; flags4096text = "[12] Dynamic"; + flags32768text = "[15] Copy to other side"; slope = "regular"; slopeargs = 3; + copyslopeargs = 5; } 703 @@ -2988,8 +2994,10 @@ linedeftypes prefix = "(703)"; flags2048text = "[11] No physics"; flags4096text = "[12] Dynamic"; + flags32768text = "[15] Copy to other side"; slope = "regular"; slopeargs = 9; + copyslopeargs = 8; } 704 @@ -3020,8 +3028,10 @@ linedeftypes prefix = "(710)"; flags2048text = "[11] No physics"; flags4096text = "[12] Dynamic"; + flags32768text = "[15] Copy to other side"; slope = "regular"; slopeargs = 4; + copyslopeargs = 2; } 711 @@ -3030,8 +3040,10 @@ linedeftypes prefix = "(711)"; flags2048text = "[11] No physics"; flags4096text = "[12] Dynamic"; + flags32768text = "[15] Copy to other side"; slope = "regular"; slopeargs = 8; + copyslopeargs = 8; } 712 @@ -3040,8 +3052,10 @@ linedeftypes prefix = "(712)"; flags2048text = "[11] No physics"; flags4096text = "[12] Dynamic"; + flags32768text = "[15] Copy to other side"; slope = "regular"; slopeargs = 12; + copyslopeargs = 10; } 713 @@ -3050,8 +3064,10 @@ linedeftypes prefix = "(713)"; flags2048text = "[11] No physics"; flags4096text = "[12] Dynamic"; + flags32768text = "[15] Copy to other side"; slope = "regular"; slopeargs = 6; + copyslopeargs = 6; } 714 diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 4c125c4b8..ae93aac37 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -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() diff --git a/src/Makefile b/src/Makefile index 18ab524b8..9659a4994 100644 --- a/src/Makefile +++ b/src/Makefile @@ -132,6 +132,10 @@ goals:=$(or $(MAKECMDGOALS),all) cleanonly:=$(filter $(clean_targets),$(goals)) destructive:=$(filter-out info,$(cleanonly)) +ifndef cleanonly +include Makefile.d/old.mk +endif + include Makefile.d/util.mk ifdef PREFIX @@ -141,7 +145,7 @@ endif OBJDUMP_OPTS?=--wide --source --line-numbers OBJCOPY:=$(call Prefix,objcopy) -OBJDUMP:=$(call Prefix,objdump) $(OBJDUMP_OPTS) +OBJDUMP:=$(call Prefix,objdump) WINDRES:=$(call Prefix,windres) ifdef YASM @@ -176,11 +180,7 @@ include Makefile.d/detect.mk # make would try to remove the implicitly made directories .PRECIOUS : %/ comptime.c -# very sophisticated dependency -sources:=\ - $(call List,Sourcefile)\ - $(call List,blua/Sourcefile)\ - +sources:= makedir:=../make # -DCOMPVERSION: flag to use comptime.h @@ -204,6 +204,11 @@ endif depdir:=$(makedir)/deps objdir:=$(makedir)/objs +# very sophisticated dependency +sources+=\ + $(call List,Sourcefile)\ + $(call List,blua/Sourcefile)\ + depends:=$(basename $(filter %.c %.s,$(sources))) objects:=$(basename $(filter %.c %.s %.nas,$(sources))) @@ -268,16 +273,18 @@ opts+=$(debug_opts) opts+=$(foreach v,$(passthru_opts),$(if $($(v)),-D$(v))) -CFLAGS:=$(opts) $(WFLAGS) $(CPPFLAGS) $(CFLAGS) -LDFLAGS:=$(libs) $(LDFLAGS) -ASFLAGS+=-x assembler-with-cpp +opts+=$(WFLAGS) $(CPPFLAGS) $(CFLAGS) +libs+=$(LDFLAGS) +asflags:=$(ASFLAGS) -x assembler-with-cpp + +cc=$(CC) ifdef DISTCC -CC:=distcc $(CC) +cc=distcc $(CC) endif ifdef CCACHE -CC:=ccache $(CC) +cc=ccache $(CC) endif ifndef SILENT @@ -288,11 +295,13 @@ ifndef destructive $(shell $(CC) -v) define flags = -CC ........ $(CC) +SHELL ..... $(SHELL) -CFLAGS .... $(CFLAGS) +CC ........ $(cc) -LDFLAGS ... $(LDFLAGS) +CFLAGS .... $(opts) + +LDFLAGS ... $(libs) endef $(info $(flags)) @@ -306,13 +315,12 @@ endif endif LD:=$(CC) -CC:=$(CC) $(CFLAGS) -NASM:=$(NASM) $(NASMOPTS) -f $(nasm_format) -GZIP:=$(GZIP) $(GZIP_OPTS) +cc:=$(cc) $(opts) +nasm=$(NASM) $(NASMOPTS) -f $(nasm_format) ifdef UPX -UPX:=$(UPX) $(UPX_OPTS) +upx=$(UPX) $(UPX_OPTS) endif -WINDRES:=$(WINDRES) $(WINDRESFLAGS)\ +windres=$(WINDRES) $(WINDRESFLAGS)\ $(debug_opts) --include-dir=win32 -O coff %/ : @@ -322,7 +330,7 @@ WINDRES:=$(WINDRES) $(WINDRESFLAGS)\ # prerequisites .SECONDEXPANSION : -# 'UPX' is also recognized in the enviornment by upx +# 'UPX' is also recognized in the environment by upx unexport UPX # executable stripped of debugging symbols @@ -331,19 +339,19 @@ $(exe) : $(dbg) | $$(@D)/ $(.)-$(OBJCOPY) --add-gnu-debuglink=$< $@ ifdef UPX $(call Echo,Compressing final executable...) - $(.)-$(UPX) $@ + $(.)-$(upx) $@ endif # original executable with debugging symbols $(dbg) : $(objects) | $$(@D)/ $(call Echo,Linking $(@F)...) - $(.)$(LD) -o $@ $^ $(LDFLAGS) + $(.)$(LD) -o $@ $^ $(libs) # disassembly of executable $(dbg).txt : $(dbg) $(call Echo,Dumping debugging info...) - $(.)$(OBJDUMP) $< > $@ - $(.)$(GZIP) $@ + $(.)$(OBJDUMP) $(OBJDUMP_OPTS) $< > $@ + $(.)$(GZIP) $(GZIP_OPTS) $@ # '::' means run unconditionally # this really updates comptime.h @@ -368,11 +376,11 @@ 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)) -$(eval $(call _recipe,s,$(ASFLAGS))) +$(eval $(call _recipe,s,$(asflags))) # compiling recipe template # 1: target file suffix @@ -384,10 +392,10 @@ $(objdir)/%.$(1) : %.$(2) | $$$$(@D)/ $(.)$(3) endef -$(eval $(call _recipe,o,c,$(CC) -c -o $$@ $$<)) -$(eval $(call _recipe,o,nas,$(NASM) -o $$@ $$<)) -$(eval $(call _recipe,o,s,$(CC) $(ASFLAGS) -c -o $$@ $$<)) -$(eval $(call _recipe,res,rc,$(WINDRES) -i $$< -o $$@)) +$(eval $(call _recipe,o,c,$(cc) -c -o $$@ $$<)) +$(eval $(call _recipe,o,nas,$(nasm) -o $$@ $$<)) +$(eval $(call _recipe,o,s,$(cc) $(asflags) -c -o $$@ $$<)) +$(eval $(call _recipe,res,rc,$(windres) -i $$< -o $$@)) _rm=$(.)$(rmrf) $(call Windows_path,$(1)) @@ -398,7 +406,7 @@ clean : $(call _rm,$(exe) $(dbg) $(dbg).txt $(objects)) distclean : - $(call _rm,../bin ../objs ../deps comptime.h) + $(call _rm,../bin ../objs ../dep ../make comptime.h) info: ifdef WINDOWSHELL diff --git a/src/Makefile.d/detect.mk b/src/Makefile.d/detect.mk index f576bcf78..f458b044c 100644 --- a/src/Makefile.d/detect.mk +++ b/src/Makefile.d/detect.mk @@ -29,7 +29,6 @@ $(call Print,$(_m)) # go for a 32-bit sdl mingw exe by default MINGW:=1 -WINDOWSHELL:=1 else # if you on the *nix @@ -72,13 +71,17 @@ latest_gcc_version:=10.2 # manually set. And don't bother if this is a clean only # 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)) @@ -91,7 +94,7 @@ ifeq (,$(filter $(v),$(gcc_versions))) define line = Your compiler version, GCC $(version), \ is not supported by the Makefile. -The Makefile will assume GCC $(latest_gcc_version).)) +The Makefile will assume GCC $(latest_gcc_version). endef $(call Print,$(line)) GCC$(subst .,,$(latest_gcc_version)):=1 diff --git a/src/Makefile.d/old.mk b/src/Makefile.d/old.mk new file mode 100644 index 000000000..ec9b6d776 --- /dev/null +++ b/src/Makefile.d/old.mk @@ -0,0 +1,16 @@ +# +# Warn about old build directories and offer to purge. +# + +_old:=$(wildcard $(addprefix ../bin/,FreeBSD Linux \ + Linux64 Mingw Mingw64 SDL dummy) ../objs ../dep) + +ifdef _old +$(foreach v,$(_old),$(info $(abspath $(v)))) +$(info ) +$(info These directories are no longer\ + required and should be removed.) +$(info You may remove them manually or\ + by using 'make distclean') +$(error ) +endif diff --git a/src/Makefile.d/platform.mk b/src/Makefile.d/platform.mk index 531d073e9..fad4be191 100644 --- a/src/Makefile.d/platform.mk +++ b/src/Makefile.d/platform.mk @@ -7,9 +7,11 @@ PKG_CONFIG?=pkg-config ifdef WINDOWSHELL rmrf=-2>NUL DEL /S /Q mkdir=-2>NUL MD +cat=TYPE else rmrf=rm -rf mkdir=mkdir -p +cat=cat endif ifdef LINUX64 diff --git a/src/Makefile.d/util.mk b/src/Makefile.d/util.mk index e76e32422..bda68df13 100644 --- a/src/Makefile.d/util.mk +++ b/src/Makefile.d/util.mk @@ -10,7 +10,8 @@ Wildvar=$(foreach v,$(filter $(1),$(.VARIABLES)),$($(v))) # Read a list of words from file and prepend each with the # directory of the file. -List=$(addprefix $(dir $(1)),$(file < $(1))) +_cat=$(shell $(cat) $(call Windows_path,$(1))) +List=$(addprefix $(dir $(1)),$(call _cat,$(1))) # Convert path separators to backslash on Windows. Windows_path=$(if $(WINDOWSHELL),$(subst /,\,$(1)),$(1)) diff --git a/src/am_map.c b/src/am_map.c index ef0ebb88c..24379e2f1 100644 --- a/src/am_map.c +++ b/src/am_map.c @@ -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) diff --git a/src/b_bot.c b/src/b_bot.c index 9213da95e..cdd74fc07 100644 --- a/src/b_bot.c +++ b/src/b_bot.c @@ -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,10 +441,10 @@ void B_KeysToTiccmd(mobj_t *mo, ticcmd_t *cmd, boolean forward, boolean backward cmd->forwardmove += MAXPLMOVE<>16; if (backward) cmd->forwardmove -= MAXPLMOVE<>16; - if (left) + if (left) cmd->angleturn += 1280; if (right) - cmd->angleturn -= 1280; + cmd->angleturn -= 1280; if (strafeleft) cmd->sidemove -= MAXPLMOVE<>16; if (straferight) @@ -447,14 +468,19 @@ void B_KeysToTiccmd(mobj_t *mo, ticcmd_t *cmd, boolean forward, boolean backward void B_MoveBlocked(player_t *player) { (void)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) { diff --git a/src/b_bot.h b/src/b_bot.h index 9f55637d1..a89cfab19 100644 --- a/src/b_bot.h +++ b/src/b_bot.h @@ -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); diff --git a/src/blua/lbaselib.c b/src/blua/lbaselib.c index 644565c28..0fc222038 100644 --- a/src/blua/lbaselib.c +++ b/src/blua/lbaselib.c @@ -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); diff --git a/src/command.c b/src/command.c index 95b1fd67d..ae4a7178e 100644 --- a/src/command.c +++ b/src/command.c @@ -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) diff --git a/src/console.c b/src/console.c index b3c413840..f01e1824c 100644 --- a/src/console.c +++ b/src/console.c @@ -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")); @@ -913,12 +913,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 +926,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 +1759,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); diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 1549811c1..b7071320c 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -43,6 +43,7 @@ #include "lzf.h" #include "lua_script.h" #include "lua_hook.h" +#include "lua_libs.h" #include "md5.h" #include "m_perfstats.h" @@ -663,14 +664,14 @@ static void Snake_Handle(void) UINT16 i; // Handle retry - if (snake->gameover && (PLAYER1INPUTDOWN(gc_jump) || gamekeydown[KEY_ENTER])) + if (snake->gameover && (PLAYER1INPUTDOWN(GC_JUMP) || gamekeydown[KEY_ENTER])) { Snake_Initialise(); snake->pausepressed = true; // Avoid accidental pause on respawn } // Handle pause - if (PLAYER1INPUTDOWN(gc_pause) || gamekeydown[KEY_ENTER]) + if (PLAYER1INPUTDOWN(GC_PAUSE) || gamekeydown[KEY_ENTER]) { if (!snake->pausepressed) snake->paused = !snake->paused; @@ -1150,15 +1151,14 @@ static boolean CL_SendJoin(void) CONS_Printf(M_GetText("Sending join request...\n")); netbuffer->packettype = PT_CLIENTJOIN; + netbuffer->u.clientcfg.modversion = MODVERSION; + strncpy(netbuffer->u.clientcfg.application, + SRB2APPLICATION, + sizeof netbuffer->u.clientcfg.application); + if (splitscreen || botingame) localplayers++; netbuffer->u.clientcfg.localplayers = localplayers; - netbuffer->u.clientcfg._255 = 255; - netbuffer->u.clientcfg.packetversion = PACKETVERSION; - netbuffer->u.clientcfg.version = VERSION; - netbuffer->u.clientcfg.subversion = SUBVERSION; - strncpy(netbuffer->u.clientcfg.application, SRB2APPLICATION, - sizeof netbuffer->u.clientcfg.application); CleanupPlayerName(consoleplayer, cv_playername.zstring); if (splitscreen) @@ -1201,6 +1201,21 @@ static INT32 FindRejoinerNum(SINT8 node) return -1; } +static UINT8 +GetRefuseReason (INT32 node) +{ + if (!node || FindRejoinerNum(node) != -1) + return 0; + else if (bannednode && bannednode[node]) + return REFUSE_BANNED; + else if (!cv_allownewplayer.value) + return REFUSE_JOINS_DISABLED; + else if (D_NumPlayers() >= cv_maxplayers.value) + return REFUSE_SLOTS_FULL; + else + return 0; +} + static void SV_SendServerInfo(INT32 node, tic_t servertime) { UINT8 *p; @@ -1219,14 +1234,7 @@ static void SV_SendServerInfo(INT32 node, tic_t servertime) netbuffer->u.serverinfo.numberofplayer = (UINT8)D_NumPlayers(); netbuffer->u.serverinfo.maxplayer = (UINT8)cv_maxplayers.value; - if (!node || FindRejoinerNum(node) != -1) - netbuffer->u.serverinfo.refusereason = 0; - else if (!cv_allownewplayer.value) - netbuffer->u.serverinfo.refusereason = 1; - else if (D_NumPlayers() >= cv_maxplayers.value) - netbuffer->u.serverinfo.refusereason = 2; - else - netbuffer->u.serverinfo.refusereason = 0; + netbuffer->u.serverinfo.refusereason = GetRefuseReason(node); strncpy(netbuffer->u.serverinfo.gametypename, Gametype_Names[gametype], sizeof netbuffer->u.serverinfo.gametypename); @@ -1344,9 +1352,6 @@ static boolean SV_SendServerConfig(INT32 node) netbuffer->packettype = PT_SERVERCFG; - netbuffer->u.servercfg.version = VERSION; - netbuffer->u.servercfg.subversion = SUBVERSION; - netbuffer->u.servercfg.serverplayer = (UINT8)serverplayer; netbuffer->u.servercfg.totalslotnum = (UINT8)(doomcom->numslots); netbuffer->u.servercfg.gametic = (tic_t)LONG(gametic); @@ -1667,20 +1672,24 @@ static void SL_InsertServer(serverinfo_pak* info, SINT8 node) if (serverlistcount >= MAXSERVERLIST) return; // list full - if (info->_255 != 255) - return;/* old packet format */ + /* check it later if connecting to this one */ + if (node != servernode) + { + if (info->_255 != 255) + return;/* old packet format */ - if (info->packetversion != PACKETVERSION) - return;/* old new packet format */ + if (info->packetversion != PACKETVERSION) + return;/* old new packet format */ - if (info->version != VERSION) - return; // Not same version. + if (info->version != VERSION) + return; // Not same version. - if (info->subversion != SUBVERSION) - return; // Close, but no cigar. + if (info->subversion != SUBVERSION) + return; // Close, but no cigar. - if (strcmp(info->application, SRB2APPLICATION)) - return;/* that's a different mod */ + if (strcmp(info->application, SRB2APPLICATION)) + return;/* that's a different mod */ + } i = serverlistcount++; } @@ -1829,6 +1838,72 @@ void CL_UpdateServerList(boolean internetsearch, INT32 room) #endif // ifndef NONET +static const char * InvalidServerReason (INT32 i) +{ +#define EOT "\nPress ESC\n" + + serverinfo_pak *info = &serverlist[i].info; + + /* magic number for new packet format */ + if (info->_255 != 255) + { + return + "Outdated server (version unknown).\n" EOT; + } + + if (strncmp(info->application, SRB2APPLICATION, sizeof + info->application)) + { + return va( + "%s cannot connect\n" + "to %s servers.\n" EOT, + SRB2APPLICATION, + info->application); + } + + if ( + info->packetversion != PACKETVERSION || + info->version != VERSION || + info->subversion != SUBVERSION + ){ + return va( + "Incompatible %s versions.\n" + "(server version %d.%d.%d)\n" EOT, + SRB2APPLICATION, + info->version / 100, + info->version % 100, + info->subversion); + } + + switch (info->refusereason) + { + case REFUSE_BANNED: + return + "You have been banned\n" + "from the server.\n" EOT; + case REFUSE_JOINS_DISABLED: + return + "The server is not accepting\n" + "joins for the moment.\n" EOT; + case REFUSE_SLOTS_FULL: + return va( + "Maximum players reached: %d\n" EOT, + info->maxplayer); + default: + if (info->refusereason) + { + return + "You can't join.\n" + "I don't know why,\n" + "but you can't join.\n" EOT; + } + } + + return NULL; + +#undef EOT +} + /** Called by CL_ServerConnectionTicker * * \param asksent The last time we asked the server to join. We re-ask every second in case our request got lost in transmit. @@ -1859,23 +1934,23 @@ static boolean CL_ServerConnectionSearchTicker(tic_t *asksent) return true; } - // Quit here rather than downloading files and being refused later. - if (serverlist[i].info.refusereason) - { - D_QuitNetGame(); - CL_Reset(); - D_StartTitle(); - if (serverlist[i].info.refusereason == 1) - M_StartMessage(M_GetText("The server is not accepting\njoins for the moment.\n\nPress ESC\n"), NULL, MM_NOTHING); - else if (serverlist[i].info.refusereason == 2) - M_StartMessage(va(M_GetText("Maximum players reached: %d\n\nPress ESC\n"), serverlist[i].info.maxplayer), NULL, MM_NOTHING); - else - M_StartMessage(M_GetText("You can't join.\nI don't know why,\nbut you can't join.\n\nPress ESC\n"), NULL, MM_NOTHING); - return false; - } - if (client) { + const char *reason = InvalidServerReason(i); + + // Quit here rather than downloading files + // and being refused later. + if (reason) + { + char *message = Z_StrDup(reason); + D_QuitNetGame(); + CL_Reset(); + D_StartTitle(); + M_StartMessage(message, NULL, MM_NOTHING); + Z_Free(message); + return false; + } + D_ParseFileneeded(serverlist[i].info.fileneedednum, serverlist[i].info.fileneeded); CONS_Printf(M_GetText("Checking files...\n")); @@ -2463,7 +2538,7 @@ void CL_ClearPlayer(INT32 playernum) // // Removes a player from the current game // -static void CL_RemovePlayer(INT32 playernum, kickreason_t reason) +void CL_RemovePlayer(INT32 playernum, kickreason_t reason) { // Sanity check: exceptional cases (i.e. c-fails) can cause multiple // kick commands to be issued for the same player. @@ -2599,7 +2674,6 @@ void CL_Reset(void) doomcom->numslots = 1; SV_StopServer(); SV_ResetServer(); - CV_RevertNetVars(); // make sure we don't leave any fileneeded gunk over from a failed join fileneedednum = 0; @@ -3231,6 +3305,8 @@ void SV_ResetServer(void) // clear server_context memset(server_context, '-', 8); + CV_RevertNetVars(); + DEBFILE("\n-=-=-=-=-=-=-= Server Reset =-=-=-=-=-=-=-\n\n"); } @@ -3256,6 +3332,9 @@ static inline void SV_GenContext(void) // void D_QuitNetGame(void) { + mousegrabbedbylua = true; + I_UpdateMouseGrab(); + if (!netgame || !netbuffer) return; @@ -3620,6 +3699,78 @@ static size_t TotalTextCmdPerTic(tic_t tic) return total; } +static const char * +ConnectionRefused (SINT8 node, INT32 rejoinernum) +{ + clientconfig_pak *cc = &netbuffer->u.clientcfg; + + boolean rejoining = (rejoinernum != -1); + + if (!node)/* server connecting to itself */ + return NULL; + + if ( + cc->modversion != MODVERSION || + strncmp(cc->application, SRB2APPLICATION, + sizeof cc->application) + ){ + return/* this is probably client's fault */ + "Incompatible."; + } + else if (bannednode && bannednode[node]) + { + return + "You have been banned\n" + "from the server."; + } + else if (cc->localplayers != 1) + { + return + "Wrong player count."; + } + + if (!rejoining) + { + if (!cv_allownewplayer.value) + { + return + "The server is not accepting\n" + "joins for the moment."; + } + else if (D_NumPlayers() >= cv_maxplayers.value) + { + return va( + "Maximum players reached: %d", + cv_maxplayers.value); + } + } + + if (luafiletransfers) + { + return + "The serveris broadcasting a file\n" + "requested by a Lua script.\n" + "Please wait a bit and then\n" + "try rejoining."; + } + + if (netgame) + { + const tic_t th = 2 * cv_joindelay.value * TICRATE; + + if (joindelay > th) + { + return va( + "Too many people are connecting.\n" + "Please wait %d seconds and then\n" + "try rejoining.", + (joindelay - th) / TICRATE); + } + } + + return NULL; +} + /** Called when a PT_CLIENTJOIN packet is received * * \param node The packet sender @@ -3630,33 +3781,14 @@ static void HandleConnect(SINT8 node) char names[MAXSPLITSCREENPLAYERS][MAXPLAYERNAME + 1]; INT32 rejoinernum; INT32 i; + const char *refuse; rejoinernum = FindRejoinerNum(node); - if (bannednode && bannednode[node]) - SV_SendRefuse(node, M_GetText("You have been banned\nfrom the server.")); - else if (netbuffer->u.clientcfg._255 != 255 || - netbuffer->u.clientcfg.packetversion != PACKETVERSION) - SV_SendRefuse(node, "Incompatible packet formats."); - else if (strncmp(netbuffer->u.clientcfg.application, SRB2APPLICATION, - sizeof netbuffer->u.clientcfg.application)) - SV_SendRefuse(node, "Different SRB2 modifications\nare not compatible."); - else if (netbuffer->u.clientcfg.version != VERSION - || netbuffer->u.clientcfg.subversion != SUBVERSION) - SV_SendRefuse(node, va(M_GetText("Different SRB2 versions cannot\nplay a netgame!\n(server version %d.%d.%d)"), VERSION/100, VERSION%100, SUBVERSION)); - else if (!cv_allownewplayer.value && node && rejoinernum == -1) - SV_SendRefuse(node, M_GetText("The server is not accepting\njoins for the moment.")); - else if (D_NumPlayers() >= cv_maxplayers.value && rejoinernum == -1) - SV_SendRefuse(node, va(M_GetText("Maximum players reached: %d"), cv_maxplayers.value)); - else if (netgame && netbuffer->u.clientcfg.localplayers > 1) // Hacked client? - SV_SendRefuse(node, M_GetText("Too many players from\nthis node.")); - else if (netgame && !netbuffer->u.clientcfg.localplayers) // Stealth join? - SV_SendRefuse(node, M_GetText("No players from\nthis node.")); - else if (luafiletransfers) - SV_SendRefuse(node, M_GetText("The server is broadcasting a file\nrequested by a Lua script.\nPlease wait a bit and then\ntry rejoining.")); - else if (netgame && joindelay > 2 * (tic_t)cv_joindelay.value * TICRATE) - SV_SendRefuse(node, va(M_GetText("Too many people are connecting.\nPlease wait %d seconds and then\ntry rejoining."), - (joindelay - 2 * cv_joindelay.value * TICRATE) / TICRATE)); + refuse = ConnectionRefused(node, rejoinernum); + + if (refuse) + SV_SendRefuse(node, refuse); else { #ifndef NONET diff --git a/src/d_clisrv.h b/src/d_clisrv.h index f3eb52423..a89c054e1 100644 --- a/src/d_clisrv.h +++ b/src/d_clisrv.h @@ -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 @@ -141,9 +145,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 +191,19 @@ 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; +enum { + REFUSE_JOINS_DISABLED = 1, + REFUSE_SLOTS_FULL, + REFUSE_BANNED, +}; + #define MAXSERVERNAME 32 #define MAXFILENEEDED 915 // This packet is too large @@ -217,7 +221,7 @@ 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; @@ -401,6 +405,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); diff --git a/src/d_event.h b/src/d_event.h index 1fd2e3824..c30a8ced2 100644 --- a/src/d_event.h +++ b/src/d_event.h @@ -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; // diff --git a/src/d_main.c b/src/d_main.c index 1b3449ec1..b4b668f4b 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -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; @@ -936,10 +936,26 @@ static void D_AddFile(char **list, const char *file) newfile = malloc(strlen(file) + 1); if (!newfile) - { I_Error("No more free memory to AddFile %s",file); - } + strcpy(newfile, file); + list[pnumwadfiles] = newfile; +} + +static void D_AddFolder(char **list, const char *file) +{ + size_t pnumwadfiles; + char *newfile; + + for (pnumwadfiles = 0; list[pnumwadfiles]; pnumwadfiles++) + ; + + newfile = malloc(strlen(file) + 2); // Path delimiter + NULL terminator + if (!newfile) + I_Error("No more free memory to AddFolder %s",file); + + strcpy(newfile, file); + strcat(newfile, PATHSEP); list[pnumwadfiles] = newfile; } @@ -1237,21 +1253,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 " or "-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]); } } diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 0a7172b12..5eb360bef 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -63,7 +63,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 +117,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 +287,7 @@ consvar_t cv_gravity = CVAR_INIT ("gravity", "0.5", CV_RESTRICT|CV_FLOAT|CV_CALL consvar_t cv_soundtest = CVAR_INIT ("soundtest", "0", CV_CALL, NULL, SoundTest_OnChange); -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); @@ -398,16 +401,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 +444,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 +477,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); @@ -1512,7 +1518,7 @@ static void Got_NameAndColor(UINT8 **cp, INT32 playernum) { illegalMask &= ~(1 << i); } - + if ((p->availabilities & illegalMask) != 0) { kick = true; @@ -3342,9 +3348,9 @@ static void Command_Addfile(void) ++p; // check total packet size and no of files currently loaded - // See W_LoadWadFile in w_wad.c + // See W_InitFile in w_wad.c if ((numwadfiles >= MAX_WADFILES) - || ((packetsizetally + nameonlylength(fn) + 22) > MAXFILENEEDED*sizeof(UINT8))) + || ((packetsizetally + nameonlylength(fn) + FILENEEDEDSIZE) > MAXFILENEEDED*sizeof(UINT8))) { CONS_Alert(CONS_ERROR, M_GetText("Too many files loaded to add %s\n"), fn); return; @@ -3392,6 +3398,139 @@ static void Command_Addfile(void) } } +static void Command_Addfolder(void) +{ + size_t argc = COM_Argc(); // amount of arguments total + size_t curarg; // current argument index + + const char *addedfolders[argc]; // list of filenames already processed + size_t numfoldersadded = 0; // the amount of filenames processed + + if (argc < 2) + { + CONS_Printf(M_GetText("addfolder [path2...] [...]: Load add-ons\n")); + return; + } + + // start at one to skip command name + for (curarg = 1; curarg < argc; curarg++) + { + const char *fn, *p; + char *fullpath; + char buf[256]; + char *buf_p = buf; + INT32 i, stat; + size_t ii; + boolean folderadded = false; + + fn = COM_Argv(curarg); + + // For the amount of filenames previously processed... + for (ii = 0; ii < numfoldersadded; ii++) + { + // If this is one of them, don't try to add it. + if (!strcmp(fn, addedfolders[ii])) + { + folderadded = true; + break; + } + } + + // If we've added this one, skip to the next one. + if (folderadded) + { + CONS_Alert(CONS_WARNING, M_GetText("Already processed %s, skipping\n"), fn); + continue; + } + + // Disallow non-printing characters and semicolons. + for (i = 0; fn[i] != '\0'; i++) + if (!isprint(fn[i]) || fn[i] == ';') + return; + + // Add file on your client directly if you aren't in a netgame. + if (!(netgame || multiplayer)) + { + P_AddFolder(fn); + addedfolders[numfoldersadded++] = fn; + continue; + } + + p = fn+strlen(fn); + while(--p >= fn) + if (*p == '\\' || *p == '/' || *p == ':') + break; + ++p; + + // Don't add an empty path. + if (M_IsStringEmpty(fn)) + { + CONS_Alert(CONS_WARNING, M_GetText("Folder name is empty, skipping\n")); + continue; + } + + // check total packet size and no of files currently loaded + // See W_InitFile in w_wad.c + if ((numwadfiles >= MAX_WADFILES) + || ((packetsizetally + strlen(fn) + FILENEEDEDSIZE) > MAXFILENEEDED*sizeof(UINT8))) + { + CONS_Alert(CONS_ERROR, M_GetText("Too many files loaded to add %s\n"), fn); + return; + } + + // Check if the path is valid. + stat = W_IsPathToFolderValid(fn); + + if (stat == 0) + { + CONS_Alert(CONS_WARNING, M_GetText("Path %s is invalid, skipping\n"), fn); + continue; + } + else if (stat < 0) + { +#ifndef AVOID_ERRNO + CONS_Alert(CONS_WARNING, M_GetText("Error accessing %s (%s), skipping\n"), fn, strerror(direrror)); +#else + CONS_Alert(CONS_WARNING, M_GetText("Error accessing %s, skipping\n"), fn); +#endif + continue; + } + + // Get the full path for this folder. + fullpath = W_GetFullFolderPath(fn); + + if (fullpath == NULL) + { + CONS_Alert(CONS_WARNING, M_GetText("Path %s is invalid, skipping\n"), fn); + continue; + } + + // Check if the folder is already added. + for (i = 0; i < numwadfiles; i++) + { + if (wadfiles[i]->type != RET_FOLDER) + continue; + + if (samepaths(wadfiles[i]->path, fullpath) > 0) + { + CONS_Alert(CONS_ERROR, M_GetText("%s is already loaded\n"), fn); + continue; + } + } + + Z_Free(fullpath); + + addedfolders[numfoldersadded++] = fn; + + WRITESTRINGN(buf_p,p,240); + + if (IsPlayerAdmin(consoleplayer) && (!server)) // Request to add file + SendNetXCmd(XD_REQADDFOLDER, buf, buf_p - buf); + else + SendNetXCmd(XD_ADDFOLDER, buf, buf_p - buf); + } +} + static void Got_RequestAddfilecmd(UINT8 **cp, INT32 playernum) { char filename[241]; @@ -3420,9 +3559,9 @@ static void Got_RequestAddfilecmd(UINT8 **cp, INT32 playernum) return; } - // See W_LoadWadFile in w_wad.c + // See W_InitFile in w_wad.c if ((numwadfiles >= MAX_WADFILES) - || ((packetsizetally + nameonlylength(filename) + 22) > MAXFILENEEDED*sizeof(UINT8))) + || ((packetsizetally + nameonlylength(filename) + FILENEEDEDSIZE) > MAXFILENEEDED*sizeof(UINT8))) toomany = true; else ncs = findfile(filename,md5sum,true); @@ -3452,6 +3591,64 @@ 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_NOTFOUND; + boolean kick = false; + boolean toomany = false; + INT32 i,j; + + READSTRINGN(*cp, path, 240); + + /// \todo Integrity checks. + + // Only the server processes this message. + if (client) + return; + + // Disallow non-printing characters and semicolons. + for (i = 0; path[i] != '\0'; i++) + if (!isprint(path[i]) || path[i] == ';') + kick = true; + + if ((playernum != serverplayer && !IsPlayerAdmin(playernum)) || kick) + { + CONS_Alert(CONS_WARNING, M_GetText("Illegal addfolder command received from %s\n"), player_names[playernum]); + SendKick(playernum, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY); + return; + } + + // See W_InitFile in w_wad.c + if ((numwadfiles >= MAX_WADFILES) + || ((packetsizetally + strlen(path) + FILENEEDEDSIZE) > MAXFILENEEDED*sizeof(UINT8))) + toomany = true; + else + ncs = findfolder(path); + + if (ncs != FS_FOUND || toomany) + { + char message[256]; + + if (toomany) + sprintf(message, M_GetText("Too many files loaded to add %s\n"), path); + else if (ncs == FS_NOTFOUND) + sprintf(message, M_GetText("The server doesn't have %s\n"), path); + else + sprintf(message, M_GetText("Unknown error finding folder (%s)\n"), path); + + CONS_Printf("%s",message); + + for (j = 0; j < MAXPLAYERS; j++) + if (adminplayers[j]) + COM_BufAddText(va("sayto %d %s", adminplayers[j], message)); + + return; + } + + COM_BufAddText(va("addfolder \"%s\"\n", path)); +} + static void Got_Addfilecmd(UINT8 **cp, INT32 playernum) { char filename[241]; @@ -3500,6 +3697,49 @@ 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_NOTFOUND; + + READSTRINGN(*cp, path, 240); + + /// \todo Integrity checks. + + if (playernum != serverplayer) + { + CONS_Alert(CONS_WARNING, M_GetText("Illegal addfolder command received from %s\n"), player_names[playernum]); + if (server) + SendKick(playernum, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY); + return; + } + + ncs = findfolder(path); + + if (ncs != FS_FOUND || !P_AddFolder(path)) + { + Command_ExitGame_f(); + if (ncs == FS_FOUND) + { + CONS_Printf(M_GetText("The server tried to add %s,\nbut you have too many files added.\nRestart the game to clear loaded files\nand play on this server."), path); + M_StartMessage(va("The server added a folder \n(%s)\nbut you have too many files added.\nRestart the game to clear loaded files.\n\nPress ESC\n",path), NULL, MM_NOTHING); + } + else if (ncs == FS_NOTFOUND) + { + CONS_Printf(M_GetText("The server tried to add %s,\nbut you don't have this file.\nYou need to find it in order\nto play on this server."), path); + M_StartMessage(va("The server added a folder \n(%s)\nthat you do not have.\n\nPress ESC\n",path), NULL, MM_NOTHING); + } + else + { + CONS_Printf(M_GetText("Unknown error finding folder (%s) the server added.\n"), path); + M_StartMessage(va("Unknown error trying to load a folder\nthat the server added \n(%s).\n\nPress ESC\n",path), NULL, MM_NOTHING); + } + return; + } + + G_SetGameModified(true); +} + static void Command_ListWADS_f(void) { INT32 i = numwadfiles; @@ -3514,6 +3754,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); } diff --git a/src/d_netcmd.h b/src/d_netcmd.h index bc5f72209..cae32643e 100644 --- a/src/d_netcmd.h +++ b/src/d_netcmd.h @@ -128,16 +128,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 diff --git a/src/d_netfil.c b/src/d_netfil.c index 55ab4ea23..12c5ee6a2 100644 --- a/src/d_netfil.c +++ b/src/d_netfil.c @@ -116,7 +116,7 @@ char luafiledir[256 + 16] = "luafiles"; /** 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) @@ -124,7 +124,7 @@ UINT8 *PutFileNeeded(void) size_t i, count = 0; UINT8 *p = netbuffer->u.serverinfo.fileneeded; char wadfilename[MAX_WADPATH] = ""; - UINT8 filestatus; + UINT8 filestatus, folder; for (i = 0; i < numwadfiles; i++) { @@ -133,9 +133,10 @@ UINT8 *PutFileNeeded(void) continue; 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,6 +144,7 @@ UINT8 *PutFileNeeded(void) // filestatus += (0 << 4); -- Won't send, too big WRITEUINT8(p, filestatus); + WRITEUINT8(p, folder); count++; WRITEUINT32(p, wadfiles[i]->filesize); @@ -174,6 +176,7 @@ void D_ParseFileneeded(INT32 fileneedednum_parm, UINT8 *fileneededstr) fileneeded[i].status = FS_NOTFOUND; // We haven't even started looking for the file yet fileneeded[i].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 @@ -416,7 +419,7 @@ INT32 CL_CheckFiles(void) return 1; } - // See W_LoadWadFile in w_wad.c + // See W_InitFile in w_wad.c packetsize = packetsizetally; for (i = 1; i < fileneedednum; i++) @@ -438,7 +441,10 @@ INT32 CL_CheckFiles(void) if (fileneeded[i].status != FS_NOTFOUND) continue; - packetsize += nameonlylength(fileneeded[i].filename) + 22; + if (fileneeded[i].folder) + packetsize += strlen(fileneeded[i].filename) + FILENEEDEDSIZE; + else + packetsize += nameonlylength(fileneeded[i].filename) + FILENEEDEDSIZE; if ((numwadfiles+filestoget >= MAX_WADFILES) || (packetsize > MAXFILENEEDED*sizeof(UINT8))) @@ -446,7 +452,10 @@ INT32 CL_CheckFiles(void) filestoget++; - fileneeded[i].status = findfile(fileneeded[i].filename, fileneeded[i].md5sum, true); + if (fileneeded[i].folder) + fileneeded[i].status = findfolder(fileneeded[i].filename); + else + fileneeded[i].status = findfile(fileneeded[i].filename, fileneeded[i].md5sum, true); CONS_Debug(DBG_NETPLAY, "found %d\n", fileneeded[i].status); if (fileneeded[i].status != FS_FOUND) ret = 0; @@ -468,7 +477,10 @@ void CL_LoadServerFiles(void) 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; } @@ -756,7 +768,7 @@ static boolean AddFileToSendQueue(INT32 node, const char *filename, UINT8 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) + // Don't inform client DEBFILE(va("Client %d request %s: not found\n", node, filename)); free(p->id.filename); free(p); @@ -1571,3 +1583,26 @@ filestatus_t findfile(char *filename, const UINT8 *wantedmd5sum, boolean complet return (badmd5 ? FS_MD5SUMBAD : FS_NOTFOUND); // md5 sum bad or file not found } + +// 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; +} diff --git a/src/d_netfil.h b/src/d_netfil.h index ddcbcfec3..70b721bf7 100644 --- a/src/d_netfil.h +++ b/src/d_netfil.h @@ -38,6 +38,7 @@ typedef enum typedef struct { UINT8 willsend; // Is the server willing to send it? + UINT8 folder; // File is a folder char filename[MAX_WADPATH]; UINT8 md5sum[16]; filestatus_t status; // The value returned by recsearch @@ -54,6 +55,8 @@ typedef struct UINT32 ackresendposition; // Used when resuming downloads } fileneeded_t; +#define FILENEEDEDSIZE 23 + extern INT32 fileneedednum; extern fileneeded_t fileneeded[MAX_WADFILES]; extern char downloaddir[512]; @@ -135,6 +138,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); diff --git a/src/d_player.h b/src/d_player.h index 54ab34288..a0db1402d 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -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,8 +559,13 @@ 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 #ifdef HWRENDER diff --git a/src/deh_tables.c b/src/deh_tables.c index ff2639a74..f2fd38059 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -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}, @@ -5482,49 +5488,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}, diff --git a/src/doomdef.h b/src/doomdef.h index 11ca80538..37edca896 100644 --- a/src/doomdef.h +++ b/src/doomdef.h @@ -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 diff --git a/src/f_finale.c b/src/f_finale.c index e8757c18a..aecf79fc2 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -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,7 +1090,6 @@ 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\"", @@ -1102,6 +1102,7 @@ static const char *credits[] = { "Louis-Antoine \"LJ Sonic\" de Moulins", // de Rochefort doesn't quite fit on the screen sorry lol "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,7 +1167,6 @@ 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.", "\"SSNTails\"", @@ -1191,7 +1191,6 @@ static const char *credits[] = { "\"Revan\"", "Anna \"QueenDelta\" Sandlin", "Wessel \"sphere\" Smit", - "\"Spazzo\"", "\"SSNTails\"", "Rob Tisdell", "\"Torgo\"", @@ -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; diff --git a/src/filesrch.c b/src/filesrch.c index cb53d07be..b4039e526 100644 --- a/src/filesrch.c +++ b/src/filesrch.c @@ -13,6 +13,7 @@ /// FS_FOUND #include +#include #ifdef __GNUC__ #include #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 #include #include @@ -340,6 +341,11 @@ 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) { filestatus_t retval = FS_NOTFOUND; @@ -387,10 +393,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 +448,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", @@ -455,7 +832,6 @@ char exttable[NUM_EXT_TABLE][7] = { // maximum extension length (currently 4) pl char filenamebuf[MAX_WADFILES][MAX_WADPATH]; - static boolean filemenucmp(char *haystack, char *needle) { static char localhaystack[128]; @@ -640,10 +1016,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 +1077,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); diff --git a/src/filesrch.h b/src/filesrch.h index dfea8979e..9d5f31bbb 100644 --- a/src/filesrch.h +++ b/src/filesrch.h @@ -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]; @@ -94,5 +105,4 @@ typedef enum void closefilemenu(boolean validsize); void searchfilemenu(char *tempname); boolean preparefilemenu(boolean samedepth); - #endif // __FILESRCH_H__ diff --git a/src/g_demo.c b/src/g_demo.c index 701f930e5..211239bfe 100644 --- a/src/g_demo.c +++ b/src/g_demo.c @@ -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) diff --git a/src/g_game.c b/src/g_game.c index 13fdab877..de1a774f4 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -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,23 +1546,14 @@ 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) + // Note: Majority of botstuffs are handled in G_Ticker now. + if (player->bot == BOT_2PHUMAN) //Player-controlled bot + { + G_CopyTiccmd(cmd, I_BaseTiccmd2(), 1); // empty, or external driver // Fix offset angle for P2-controlled Tailsbot when P2's controls are set to non-Legacy cmd->angleturn = (INT16)((localangle - *myangle) >> 16); - + } + *myangle += (cmd->angleturn<<16); if (controlstyle == CS_LMAOGALOG) { @@ -1968,7 +1960,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 +2036,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 +2109,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 +2140,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 +2149,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 +2186,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 +2211,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 +2313,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); - - 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; - - players[i].cmd.angleturn &= ~TICCMD_RECEIVED; + // 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); + } + + // Do angle adjustments. + if (players[i].bot == BOT_NONE || players[i].bot == BOT_2PHUMAN) + { + received = (players[i].cmd.angleturn & TICCMD_RECEIVED); + players[i].angleturn += players[i].cmd.angleturn - players[i].oldrelangleturn; + players[i].oldrelangleturn = players[i].cmd.angleturn; + if (P_ControlStyle(&players[i]) == CS_LMAOGALOG) + P_ForceLocalAngle(&players[i], players[i].angleturn << 16); + else + players[i].cmd.angleturn = players[i].angleturn; + if (P_ControlStyle(&players[i]) == CS_LMAOGALOG) + P_ForceLocalAngle(&players[i], players[i].angleturn << 16); + else + players[i].cmd.angleturn = players[i].angleturn; + + players[i].cmd.angleturn &= ~TICCMD_RECEIVED; + // Use the leveltime sent in the player's ticcmd to determine control lag + players[i].cmd.latency = min(((leveltime & 0xFF) - players[i].cmd.latency) & 0xFF, MAXPREDICTTICS-1); + } + else // Less work is required if we're building a bot ticcmd. + { + // Since bot TicCmd is pre-determined for both the client and server, the latency and packet checks are simplified. + received = 1; + players[i].cmd.latency = 0; + players[i].angleturn = players[i].cmd.angleturn; + players[i].oldrelangleturn = players[i].cmd.angleturn; + } players[i].cmd.angleturn |= received; - - // Use the leveltime sent in the player's ticcmd to determine control lag - players[i].cmd.latency = min(((leveltime & 0xFF) - players[i].cmd.latency) & 0xFF, MAXPREDICTTICS-1); } } @@ -2494,6 +2550,7 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps) tic_t quittime; boolean spectator; boolean outofcoop; + boolean removing; INT16 bot; SINT8 pity; INT16 rings; @@ -2510,6 +2567,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 +2644,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 +2689,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 +3038,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; @@ -2995,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; @@ -3176,7 +3260,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 +3301,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 +5324,3 @@ INT32 G_TicsToMilliseconds(tic_t tics) { return (INT32)((tics%TICRATE) * (1000.00f/TICRATE)); } - diff --git a/src/g_input.c b/src/g_input.c index 2f7980c64..cd4536bba 100644 --- a/src/g_input.c +++ b/src/g_input.c @@ -41,49 +41,49 @@ INT32 joyxmove[JOYAXISSET], joyymove[JOYAXISSET], joy2xmove[JOYAXISSET], joy2ymo UINT8 gamekeydown[NUMINPUTS]; // two key codes (or virtual key) per game control -INT32 gamecontrol[num_gamecontrols][2]; -INT32 gamecontrolbis[num_gamecontrols][2]; // secondary splitscreen player -INT32 gamecontroldefault[num_gamecontrolschemes][num_gamecontrols][2]; // default control storage, use 0 (gcs_custom) for memory retention -INT32 gamecontrolbisdefault[num_gamecontrolschemes][num_gamecontrols][2]; +INT32 gamecontrol[NUM_GAMECONTROLS][2]; +INT32 gamecontrolbis[NUM_GAMECONTROLS][2]; // secondary splitscreen player +INT32 gamecontroldefault[num_gamecontrolschemes][NUM_GAMECONTROLS][2]; // default control storage, use 0 (gcs_custom) for memory retention +INT32 gamecontrolbisdefault[num_gamecontrolschemes][NUM_GAMECONTROLS][2]; // lists of GC codes for selective operation const INT32 gcl_tutorial_check[num_gcl_tutorial_check] = { - gc_forward, gc_backward, gc_strafeleft, gc_straferight, - gc_turnleft, gc_turnright + GC_FORWARD, GC_BACKWARD, GC_STRAFELEFT, GC_STRAFERIGHT, + GC_TURNLEFT, GC_TURNRIGHT }; const INT32 gcl_tutorial_used[num_gcl_tutorial_used] = { - gc_forward, gc_backward, gc_strafeleft, gc_straferight, - gc_turnleft, gc_turnright, - gc_jump, gc_spin + GC_FORWARD, GC_BACKWARD, GC_STRAFELEFT, GC_STRAFERIGHT, + GC_TURNLEFT, GC_TURNRIGHT, + GC_JUMP, GC_SPIN }; const INT32 gcl_tutorial_full[num_gcl_tutorial_full] = { - gc_forward, gc_backward, gc_strafeleft, gc_straferight, - gc_lookup, gc_lookdown, gc_turnleft, gc_turnright, gc_centerview, - gc_jump, gc_spin, - gc_fire, gc_firenormal + GC_FORWARD, GC_BACKWARD, GC_STRAFELEFT, GC_STRAFERIGHT, + GC_LOOKUP, GC_LOOKDOWN, GC_TURNLEFT, GC_TURNRIGHT, GC_CENTERVIEW, + GC_JUMP, GC_SPIN, + GC_FIRE, GC_FIRENORMAL }; const INT32 gcl_movement[num_gcl_movement] = { - gc_forward, gc_backward, gc_strafeleft, gc_straferight + GC_FORWARD, GC_BACKWARD, GC_STRAFELEFT, GC_STRAFERIGHT }; const INT32 gcl_camera[num_gcl_camera] = { - gc_turnleft, gc_turnright + GC_TURNLEFT, GC_TURNRIGHT }; const INT32 gcl_movement_camera[num_gcl_movement_camera] = { - gc_forward, gc_backward, gc_strafeleft, gc_straferight, - gc_turnleft, gc_turnright + GC_FORWARD, GC_BACKWARD, GC_STRAFELEFT, GC_STRAFERIGHT, + GC_TURNLEFT, GC_TURNRIGHT }; -const INT32 gcl_jump[num_gcl_jump] = { gc_jump }; +const INT32 gcl_jump[num_gcl_jump] = { GC_JUMP }; -const INT32 gcl_spin[num_gcl_spin] = { gc_spin }; +const INT32 gcl_spin[num_gcl_spin] = { GC_SPIN }; const INT32 gcl_jump_spin[num_gcl_jump_spin] = { - gc_jump, gc_spin + GC_JUMP, GC_SPIN }; typedef struct @@ -115,54 +115,54 @@ void G_MapEventsToControls(event_t *ev) switch (ev->type) { case ev_keydown: - if (ev->data1 < NUMINPUTS) - gamekeydown[ev->data1] = 1; + if (ev->key < NUMINPUTS) + gamekeydown[ev->key] = 1; #ifdef PARANOIA else { - CONS_Debug(DBG_GAMELOGIC, "Bad downkey input %d\n",ev->data1); + CONS_Debug(DBG_GAMELOGIC, "Bad downkey input %d\n",ev->key); } #endif break; case ev_keyup: - if (ev->data1 < NUMINPUTS) - gamekeydown[ev->data1] = 0; + if (ev->key < NUMINPUTS) + gamekeydown[ev->key] = 0; #ifdef PARANOIA else { - CONS_Debug(DBG_GAMELOGIC, "Bad upkey input %d\n",ev->data1); + CONS_Debug(DBG_GAMELOGIC, "Bad upkey input %d\n",ev->key); } #endif break; case ev_mouse: // buttons are virtual keys - mouse.rdx = ev->data2; - mouse.rdy = ev->data3; + mouse.rdx = ev->x; + mouse.rdy = ev->y; break; case ev_joystick: // buttons are virtual keys - i = ev->data1; + i = ev->key; if (i >= JOYAXISSET || menuactive || CON_Ready() || chat_on) break; - if (ev->data2 != INT32_MAX) joyxmove[i] = ev->data2; - if (ev->data3 != INT32_MAX) joyymove[i] = ev->data3; + if (ev->x != INT32_MAX) joyxmove[i] = ev->x; + if (ev->y != INT32_MAX) joyymove[i] = ev->y; break; case ev_joystick2: // buttons are virtual keys - i = ev->data1; + i = ev->key; if (i >= JOYAXISSET || menuactive || CON_Ready() || chat_on) break; - if (ev->data2 != INT32_MAX) joy2xmove[i] = ev->data2; - if (ev->data3 != INT32_MAX) joy2ymove[i] = ev->data3; + if (ev->x != INT32_MAX) joy2xmove[i] = ev->x; + if (ev->y != INT32_MAX) joy2ymove[i] = ev->y; break; case ev_mouse2: // buttons are virtual keys if (menuactive || CON_Ready() || chat_on) break; - mouse2.rdx = ev->data2; - mouse2.rdy = ev->data3; + mouse2.rdx = ev->x; + mouse2.rdy = ev->y; break; default: @@ -553,9 +553,9 @@ static keyname_t keynames[] = }; -static const char *gamecontrolname[num_gamecontrols] = +static const char *gamecontrolname[NUM_GAMECONTROLS] = { - "nothing", // a key/button mapped to gc_null has no effect + "nothing", // a key/button mapped to GC_NULL has no effect "forward", "backward", "strafeleft", @@ -613,7 +613,7 @@ void G_ClearControlKeys(INT32 (*setupcontrols)[2], INT32 control) void G_ClearAllControlKeys(void) { INT32 i; - for (i = 0; i < num_gamecontrols; i++) + for (i = 0; i < NUM_GAMECONTROLS; i++) { G_ClearControlKeys(gamecontrol, i); G_ClearControlKeys(gamecontrolbis, i); @@ -624,7 +624,7 @@ void G_ClearAllControlKeys(void) // Returns the name of a key (or virtual key for mouse and joy) // the input value being an keynum // -const char *G_KeyNumToString(INT32 keynum) +const char *G_KeyNumToName(INT32 keynum) { static char keynamestr[8]; @@ -648,7 +648,7 @@ const char *G_KeyNumToString(INT32 keynum) return keynamestr; } -INT32 G_KeyStringToNum(const char *keystr) +INT32 G_KeyNameToNum(const char *keystr) { UINT32 j; @@ -676,92 +676,92 @@ void G_DefineDefaultControls(void) INT32 i; // FPS game controls (WASD) - gamecontroldefault[gcs_fps][gc_forward ][0] = 'w'; - gamecontroldefault[gcs_fps][gc_backward ][0] = 's'; - gamecontroldefault[gcs_fps][gc_strafeleft ][0] = 'a'; - gamecontroldefault[gcs_fps][gc_straferight][0] = 'd'; - gamecontroldefault[gcs_fps][gc_lookup ][0] = KEY_UPARROW; - gamecontroldefault[gcs_fps][gc_lookdown ][0] = KEY_DOWNARROW; - gamecontroldefault[gcs_fps][gc_turnleft ][0] = KEY_LEFTARROW; - gamecontroldefault[gcs_fps][gc_turnright ][0] = KEY_RIGHTARROW; - gamecontroldefault[gcs_fps][gc_centerview ][0] = KEY_END; - gamecontroldefault[gcs_fps][gc_jump ][0] = KEY_SPACE; - gamecontroldefault[gcs_fps][gc_spin ][0] = KEY_LSHIFT; - gamecontroldefault[gcs_fps][gc_fire ][0] = KEY_RCTRL; - gamecontroldefault[gcs_fps][gc_fire ][1] = KEY_MOUSE1+0; - gamecontroldefault[gcs_fps][gc_firenormal ][0] = 'c'; + gamecontroldefault[gcs_fps][GC_FORWARD ][0] = 'w'; + gamecontroldefault[gcs_fps][GC_BACKWARD ][0] = 's'; + gamecontroldefault[gcs_fps][GC_STRAFELEFT ][0] = 'a'; + gamecontroldefault[gcs_fps][GC_STRAFERIGHT][0] = 'd'; + gamecontroldefault[gcs_fps][GC_LOOKUP ][0] = KEY_UPARROW; + gamecontroldefault[gcs_fps][GC_LOOKDOWN ][0] = KEY_DOWNARROW; + gamecontroldefault[gcs_fps][GC_TURNLEFT ][0] = KEY_LEFTARROW; + gamecontroldefault[gcs_fps][GC_TURNRIGHT ][0] = KEY_RIGHTARROW; + gamecontroldefault[gcs_fps][GC_CENTERVIEW ][0] = KEY_END; + gamecontroldefault[gcs_fps][GC_JUMP ][0] = KEY_SPACE; + gamecontroldefault[gcs_fps][GC_SPIN ][0] = KEY_LSHIFT; + gamecontroldefault[gcs_fps][GC_FIRE ][0] = KEY_RCTRL; + gamecontroldefault[gcs_fps][GC_FIRE ][1] = KEY_MOUSE1+0; + gamecontroldefault[gcs_fps][GC_FIRENORMAL ][0] = 'c'; // Platform game controls (arrow keys) - gamecontroldefault[gcs_platform][gc_forward ][0] = KEY_UPARROW; - gamecontroldefault[gcs_platform][gc_backward ][0] = KEY_DOWNARROW; - gamecontroldefault[gcs_platform][gc_strafeleft ][0] = 'a'; - gamecontroldefault[gcs_platform][gc_straferight][0] = 'd'; - gamecontroldefault[gcs_platform][gc_lookup ][0] = KEY_PGUP; - gamecontroldefault[gcs_platform][gc_lookdown ][0] = KEY_PGDN; - gamecontroldefault[gcs_platform][gc_turnleft ][0] = KEY_LEFTARROW; - gamecontroldefault[gcs_platform][gc_turnright ][0] = KEY_RIGHTARROW; - gamecontroldefault[gcs_platform][gc_centerview ][0] = KEY_END; - gamecontroldefault[gcs_platform][gc_jump ][0] = KEY_SPACE; - gamecontroldefault[gcs_platform][gc_spin ][0] = KEY_LSHIFT; - gamecontroldefault[gcs_platform][gc_fire ][0] = 's'; - gamecontroldefault[gcs_platform][gc_fire ][1] = KEY_MOUSE1+0; - gamecontroldefault[gcs_platform][gc_firenormal ][0] = 'w'; + gamecontroldefault[gcs_platform][GC_FORWARD ][0] = KEY_UPARROW; + gamecontroldefault[gcs_platform][GC_BACKWARD ][0] = KEY_DOWNARROW; + gamecontroldefault[gcs_platform][GC_STRAFELEFT ][0] = 'a'; + gamecontroldefault[gcs_platform][GC_STRAFERIGHT][0] = 'd'; + gamecontroldefault[gcs_platform][GC_LOOKUP ][0] = KEY_PGUP; + gamecontroldefault[gcs_platform][GC_LOOKDOWN ][0] = KEY_PGDN; + gamecontroldefault[gcs_platform][GC_TURNLEFT ][0] = KEY_LEFTARROW; + gamecontroldefault[gcs_platform][GC_TURNRIGHT ][0] = KEY_RIGHTARROW; + gamecontroldefault[gcs_platform][GC_CENTERVIEW ][0] = KEY_END; + gamecontroldefault[gcs_platform][GC_JUMP ][0] = KEY_SPACE; + gamecontroldefault[gcs_platform][GC_SPIN ][0] = KEY_LSHIFT; + gamecontroldefault[gcs_platform][GC_FIRE ][0] = 's'; + gamecontroldefault[gcs_platform][GC_FIRE ][1] = KEY_MOUSE1+0; + gamecontroldefault[gcs_platform][GC_FIRENORMAL ][0] = 'w'; for (i = 1; i < num_gamecontrolschemes; i++) // skip gcs_custom (0) { - gamecontroldefault[i][gc_weaponnext ][0] = KEY_MOUSEWHEELUP+0; - gamecontroldefault[i][gc_weaponprev ][0] = KEY_MOUSEWHEELDOWN+0; - gamecontroldefault[i][gc_wepslot1 ][0] = '1'; - gamecontroldefault[i][gc_wepslot2 ][0] = '2'; - gamecontroldefault[i][gc_wepslot3 ][0] = '3'; - gamecontroldefault[i][gc_wepslot4 ][0] = '4'; - gamecontroldefault[i][gc_wepslot5 ][0] = '5'; - gamecontroldefault[i][gc_wepslot6 ][0] = '6'; - gamecontroldefault[i][gc_wepslot7 ][0] = '7'; - gamecontroldefault[i][gc_wepslot8 ][0] = '8'; - gamecontroldefault[i][gc_wepslot9 ][0] = '9'; - gamecontroldefault[i][gc_wepslot10 ][0] = '0'; - gamecontroldefault[i][gc_tossflag ][0] = '\''; - gamecontroldefault[i][gc_camtoggle ][0] = 'v'; - gamecontroldefault[i][gc_camreset ][0] = 'r'; - gamecontroldefault[i][gc_talkkey ][0] = 't'; - gamecontroldefault[i][gc_teamkey ][0] = 'y'; - gamecontroldefault[i][gc_scores ][0] = KEY_TAB; - gamecontroldefault[i][gc_console ][0] = KEY_CONSOLE; - gamecontroldefault[i][gc_pause ][0] = 'p'; - gamecontroldefault[i][gc_screenshot ][0] = KEY_F8; - gamecontroldefault[i][gc_recordgif ][0] = KEY_F9; - gamecontroldefault[i][gc_viewpoint ][0] = KEY_F12; + gamecontroldefault[i][GC_WEAPONNEXT ][0] = KEY_MOUSEWHEELUP+0; + gamecontroldefault[i][GC_WEAPONPREV ][0] = KEY_MOUSEWHEELDOWN+0; + gamecontroldefault[i][GC_WEPSLOT1 ][0] = '1'; + gamecontroldefault[i][GC_WEPSLOT2 ][0] = '2'; + gamecontroldefault[i][GC_WEPSLOT3 ][0] = '3'; + gamecontroldefault[i][GC_WEPSLOT4 ][0] = '4'; + gamecontroldefault[i][GC_WEPSLOT5 ][0] = '5'; + gamecontroldefault[i][GC_WEPSLOT6 ][0] = '6'; + gamecontroldefault[i][GC_WEPSLOT7 ][0] = '7'; + gamecontroldefault[i][GC_WEPSLOT8 ][0] = '8'; + gamecontroldefault[i][GC_WEPSLOT9 ][0] = '9'; + gamecontroldefault[i][GC_WEPSLOT10 ][0] = '0'; + gamecontroldefault[i][GC_TOSSFLAG ][0] = '\''; + gamecontroldefault[i][GC_CAMTOGGLE ][0] = 'v'; + gamecontroldefault[i][GC_CAMRESET ][0] = 'r'; + gamecontroldefault[i][GC_TALKKEY ][0] = 't'; + gamecontroldefault[i][GC_TEAMKEY ][0] = 'y'; + gamecontroldefault[i][GC_SCORES ][0] = KEY_TAB; + gamecontroldefault[i][GC_CONSOLE ][0] = KEY_CONSOLE; + gamecontroldefault[i][GC_PAUSE ][0] = 'p'; + gamecontroldefault[i][GC_SCREENSHOT ][0] = KEY_F8; + gamecontroldefault[i][GC_RECORDGIF ][0] = KEY_F9; + gamecontroldefault[i][GC_VIEWPOINT ][0] = KEY_F12; // Gamepad controls -- same for both schemes - gamecontroldefault[i][gc_weaponnext ][1] = KEY_JOY1+1; // B - gamecontroldefault[i][gc_weaponprev ][1] = KEY_JOY1+2; // X - gamecontroldefault[i][gc_tossflag ][1] = KEY_JOY1+0; // A - gamecontroldefault[i][gc_spin ][1] = KEY_JOY1+4; // LB - gamecontroldefault[i][gc_camtoggle ][1] = KEY_HAT1+0; // D-Pad Up - gamecontroldefault[i][gc_camreset ][1] = KEY_JOY1+3; // Y - gamecontroldefault[i][gc_centerview ][1] = KEY_JOY1+9; // Right Stick - gamecontroldefault[i][gc_talkkey ][1] = KEY_HAT1+2; // D-Pad Left - gamecontroldefault[i][gc_scores ][1] = KEY_HAT1+3; // D-Pad Right - gamecontroldefault[i][gc_jump ][1] = KEY_JOY1+5; // RB - gamecontroldefault[i][gc_pause ][1] = KEY_JOY1+6; // Back - gamecontroldefault[i][gc_screenshot ][1] = KEY_HAT1+1; // D-Pad Down - gamecontroldefault[i][gc_systemmenu ][0] = KEY_JOY1+7; // Start + gamecontroldefault[i][GC_WEAPONNEXT ][1] = KEY_JOY1+1; // B + gamecontroldefault[i][GC_WEAPONPREV ][1] = KEY_JOY1+2; // X + gamecontroldefault[i][GC_TOSSFLAG ][1] = KEY_JOY1+0; // A + gamecontroldefault[i][GC_SPIN ][1] = KEY_JOY1+4; // LB + gamecontroldefault[i][GC_CAMTOGGLE ][1] = KEY_HAT1+0; // D-Pad Up + gamecontroldefault[i][GC_CAMRESET ][1] = KEY_JOY1+3; // Y + gamecontroldefault[i][GC_CENTERVIEW ][1] = KEY_JOY1+9; // Right Stick + gamecontroldefault[i][GC_TALKKEY ][1] = KEY_HAT1+2; // D-Pad Left + gamecontroldefault[i][GC_SCORES ][1] = KEY_HAT1+3; // D-Pad Right + gamecontroldefault[i][GC_JUMP ][1] = KEY_JOY1+5; // RB + gamecontroldefault[i][GC_PAUSE ][1] = KEY_JOY1+6; // Back + gamecontroldefault[i][GC_SCREENSHOT ][1] = KEY_HAT1+1; // D-Pad Down + gamecontroldefault[i][GC_SYSTEMMENU ][0] = KEY_JOY1+7; // Start // Second player controls only have joypad defaults - gamecontrolbisdefault[i][gc_weaponnext][0] = KEY_2JOY1+1; // B - gamecontrolbisdefault[i][gc_weaponprev][0] = KEY_2JOY1+2; // X - gamecontrolbisdefault[i][gc_tossflag ][0] = KEY_2JOY1+0; // A - gamecontrolbisdefault[i][gc_spin ][0] = KEY_2JOY1+4; // LB - gamecontrolbisdefault[i][gc_camreset ][0] = KEY_2JOY1+3; // Y - gamecontrolbisdefault[i][gc_centerview][0] = KEY_2JOY1+9; // Right Stick - gamecontrolbisdefault[i][gc_jump ][0] = KEY_2JOY1+5; // RB - //gamecontrolbisdefault[i][gc_pause ][0] = KEY_2JOY1+6; // Back - //gamecontrolbisdefault[i][gc_systemmenu][0] = KEY_2JOY1+7; // Start - gamecontrolbisdefault[i][gc_camtoggle ][0] = KEY_2HAT1+0; // D-Pad Up - gamecontrolbisdefault[i][gc_screenshot][0] = KEY_2HAT1+1; // D-Pad Down - //gamecontrolbisdefault[i][gc_talkkey ][0] = KEY_2HAT1+2; // D-Pad Left - //gamecontrolbisdefault[i][gc_scores ][0] = KEY_2HAT1+3; // D-Pad Right + gamecontrolbisdefault[i][GC_WEAPONNEXT][0] = KEY_2JOY1+1; // B + gamecontrolbisdefault[i][GC_WEAPONPREV][0] = KEY_2JOY1+2; // X + gamecontrolbisdefault[i][GC_TOSSFLAG ][0] = KEY_2JOY1+0; // A + gamecontrolbisdefault[i][GC_SPIN ][0] = KEY_2JOY1+4; // LB + gamecontrolbisdefault[i][GC_CAMRESET ][0] = KEY_2JOY1+3; // Y + gamecontrolbisdefault[i][GC_CENTERVIEW][0] = KEY_2JOY1+9; // Right Stick + gamecontrolbisdefault[i][GC_JUMP ][0] = KEY_2JOY1+5; // RB + //gamecontrolbisdefault[i][GC_PAUSE ][0] = KEY_2JOY1+6; // Back + //gamecontrolbisdefault[i][GC_SYSTEMMENU][0] = KEY_2JOY1+7; // Start + gamecontrolbisdefault[i][GC_CAMTOGGLE ][0] = KEY_2HAT1+0; // D-Pad Up + gamecontrolbisdefault[i][GC_SCREENSHOT][0] = KEY_2HAT1+1; // D-Pad Down + //gamecontrolbisdefault[i][GC_TALKKEY ][0] = KEY_2HAT1+2; // D-Pad Left + //gamecontrolbisdefault[i][GC_SCORES ][0] = KEY_2HAT1+3; // D-Pad Right } } @@ -773,7 +773,7 @@ INT32 G_GetControlScheme(INT32 (*fromcontrols)[2], const INT32 *gclist, INT32 gc for (i = 1; i < num_gamecontrolschemes; i++) // skip gcs_custom (0) { skipscheme = false; - for (j = 0; j < (gclist && gclen ? gclen : num_gamecontrols); j++) + for (j = 0; j < (gclist && gclen ? gclen : NUM_GAMECONTROLS); j++) { gc = (gclist && gclen) ? gclist[j] : j; if (((fromcontrols[gc][0] && gamecontroldefault[i][gc][0]) ? fromcontrols[gc][0] != gamecontroldefault[i][gc][0] : true) && @@ -796,7 +796,7 @@ void G_CopyControls(INT32 (*setupcontrols)[2], INT32 (*fromcontrols)[2], const I { INT32 i, gc; - for (i = 0; i < (gclist && gclen ? gclen : num_gamecontrols); i++) + for (i = 0; i < (gclist && gclen ? gclen : NUM_GAMECONTROLS); i++) { gc = (gclist && gclen) ? gclist[i] : i; setupcontrols[gc][0] = fromcontrols[gc][0]; @@ -808,24 +808,24 @@ void G_SaveKeySetting(FILE *f, INT32 (*fromcontrols)[2], INT32 (*fromcontrolsbis { INT32 i; - for (i = 1; i < num_gamecontrols; i++) + for (i = 1; i < NUM_GAMECONTROLS; i++) { fprintf(f, "setcontrol \"%s\" \"%s\"", gamecontrolname[i], - G_KeyNumToString(fromcontrols[i][0])); + G_KeyNumToName(fromcontrols[i][0])); if (fromcontrols[i][1]) - fprintf(f, " \"%s\"\n", G_KeyNumToString(fromcontrols[i][1])); + fprintf(f, " \"%s\"\n", G_KeyNumToName(fromcontrols[i][1])); else fprintf(f, "\n"); } - for (i = 1; i < num_gamecontrols; i++) + for (i = 1; i < NUM_GAMECONTROLS; i++) { fprintf(f, "setcontrol2 \"%s\" \"%s\"", gamecontrolname[i], - G_KeyNumToString(fromcontrolsbis[i][0])); + G_KeyNumToName(fromcontrolsbis[i][0])); if (fromcontrolsbis[i][1]) - fprintf(f, " \"%s\"\n", G_KeyNumToString(fromcontrolsbis[i][1])); + fprintf(f, " \"%s\"\n", G_KeyNumToName(fromcontrolsbis[i][1])); else fprintf(f, "\n"); } @@ -833,11 +833,11 @@ void G_SaveKeySetting(FILE *f, INT32 (*fromcontrols)[2], INT32 (*fromcontrolsbis INT32 G_CheckDoubleUsage(INT32 keynum, boolean modify) { - INT32 result = gc_null; + INT32 result = GC_NULL; if (cv_controlperkey.value == 1) { INT32 i; - for (i = 0; i < num_gamecontrols; i++) + for (i = 0; i < NUM_GAMECONTROLS; i++) { if (gamecontrol[i][0] == keynum) { @@ -883,11 +883,11 @@ static INT32 G_FilterKeyByVersion(INT32 numctrl, INT32 keyidx, INT32 player, INT return -1; // skip setting control if (GETMAJOREXECVERSION(cv_execversion.value) < 27 && ( // v2.1.22 - numctrl == gc_weaponnext || numctrl == gc_weaponprev || numctrl == gc_tossflag || - numctrl == gc_spin || numctrl == gc_camreset || numctrl == gc_jump || - numctrl == gc_pause || numctrl == gc_systemmenu || numctrl == gc_camtoggle || - numctrl == gc_screenshot || numctrl == gc_talkkey || numctrl == gc_scores || - numctrl == gc_centerview + numctrl == GC_WEAPONNEXT || numctrl == GC_WEAPONPREV || numctrl == GC_TOSSFLAG || + numctrl == GC_SPIN || numctrl == GC_CAMRESET || numctrl == GC_JUMP || + numctrl == GC_PAUSE || numctrl == GC_SYSTEMMENU || numctrl == GC_CAMTOGGLE || + numctrl == GC_SCREENSHOT || numctrl == GC_TALKKEY || numctrl == GC_SCORES || + numctrl == GC_CENTERVIEW )) { INT32 keynum = 0, existingctrl = 0; @@ -895,7 +895,7 @@ static INT32 G_FilterKeyByVersion(INT32 numctrl, INT32 keyidx, INT32 player, INT boolean defaultoverride = false; // get the default gamecontrol - if (player == 0 && numctrl == gc_systemmenu) + if (player == 0 && numctrl == GC_SYSTEMMENU) defaultkey = gamecontrol[numctrl][0]; else defaultkey = (player == 1 ? gamecontrolbis[numctrl][0] : gamecontrol[numctrl][1]); @@ -993,16 +993,16 @@ static void setcontrol(INT32 (*gc)[2]) // Update me for 2.3 namectrl = (stricmp(COM_Argv(1), "use")) ? COM_Argv(1) : "spin"; - for (numctrl = 0; numctrl < num_gamecontrols && stricmp(namectrl, gamecontrolname[numctrl]); + for (numctrl = 0; numctrl < NUM_GAMECONTROLS && stricmp(namectrl, gamecontrolname[numctrl]); numctrl++) ; - if (numctrl == num_gamecontrols) + if (numctrl == NUM_GAMECONTROLS) { CONS_Printf(M_GetText("Control '%s' unknown\n"), namectrl); return; } - keynum1 = G_KeyStringToNum(COM_Argv(2)); - keynum2 = G_KeyStringToNum(COM_Argv(3)); + keynum1 = G_KeyNameToNum(COM_Argv(2)); + keynum2 = G_KeyNameToNum(COM_Argv(3)); keynum = G_FilterKeyByVersion(numctrl, 0, player, &keynum1, &keynum2, &nestedoverride); if (keynum >= 0) diff --git a/src/g_input.h b/src/g_input.h index ffd0cb560..2e9f53dcf 100644 --- a/src/g_input.h +++ b/src/g_input.h @@ -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); diff --git a/src/hardware/hw_draw.c b/src/hardware/hw_draw.c index e83aff0d7..8223705bd 100644 --- a/src/hardware/hw_draw.c +++ b/src/hardware/hw_draw.c @@ -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<width< gpatch->height) - fheight = gpatch->height - sy; + if (sy + h > gpatch->height<height<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<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<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) { diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index d413e3bbe..e0851af85 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -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) diff --git a/src/hardware/hw_main.h b/src/hardware/hw_main.h index 218650b53..b751b2a6e 100644 --- a/src/hardware/hw_main.h +++ b/src/hardware/hw_main.h @@ -39,7 +39,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); diff --git a/src/hardware/r_opengl/r_opengl.c b/src/hardware/r_opengl/r_opengl.c index 645a3bbae..de0e8c6a6 100644 --- a/src/hardware/r_opengl/r_opengl.c +++ b/src/hardware/r_opengl/r_opengl.c @@ -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); diff --git a/src/hu_stuff.c b/src/hu_stuff.c index e0eaf8fb1..f4c5e4c3b 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -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) diff --git a/src/lua_baselib.c b/src/lua_baselib.c index d6f40846c..350c1585f 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -29,6 +29,8 @@ #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 "lua_script.h" #include "lua_libs.h" @@ -1883,6 +1885,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 +3430,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) @@ -3881,6 +4019,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 +4123,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}, diff --git a/src/lua_consolelib.c b/src/lua_consolelib.c index 414d9692a..2b8cad69b 100644 --- a/src/lua_consolelib.c +++ b/src/lua_consolelib.c @@ -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)) { diff --git a/src/lua_hook.h b/src/lua_hook.h index e3af951f5..531d16288 100644 --- a/src/lua_hook.h +++ b/src/lua_hook.h @@ -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 diff --git a/src/lua_hooklib.c b/src/lua_hooklib.c index 39aa5ea18..32b5e52fb 100644 --- a/src/lua_hooklib.c +++ b/src/lua_hooklib.c @@ -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) { @@ -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 += 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; } diff --git a/src/lua_hud.h b/src/lua_hud.h index d2f5bceca..c1d2d164b 100644 --- a/src/lua_hud.h +++ b/src/lua_hud.h @@ -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); diff --git a/src/lua_hudlib.c b/src/lua_hudlib.c index 9a3e676d5..fca832053 100644 --- a/src/lua_hudlib.c +++ b/src/lua_hudlib.c @@ -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, @@ -280,7 +265,7 @@ static int hudinfo_num(lua_State *L) static int colormap_get(lua_State *L) { - const UINT8 *colormap = *((UINT8 **)luaL_checkudata(L, 1, META_COLORMAP)); + UINT8 *colormap = *((UINT8 **)luaL_checkudata(L, 1, META_COLORMAP)); UINT32 i = luaL_checkinteger(L, 2); if (i >= 256) return luaL_error(L, "colormap index %d out of range (0 - %d)", i, 255); @@ -288,6 +273,23 @@ static int colormap_get(lua_State *L) return 1; } +static int colormap_set(lua_State *L) +{ + UINT8 *colormap = *((UINT8 **)luaL_checkudata(L, 1, META_COLORMAP)); + UINT32 i = luaL_checkinteger(L, 2); + if (i >= 256) + return luaL_error(L, "colormap index %d out of range (0 - %d)", i, 255); + colormap[i] = (UINT8)luaL_checkinteger(L, 3); + return 0; +} + +static int colormap_free(lua_State *L) +{ + UINT8 *colormap = *((UINT8 **)luaL_checkudata(L, 1, META_COLORMAP)); + Z_Free(colormap); + return 0; +} + static int patch_get(lua_State *L) { patch_t *patch = *((patch_t **)luaL_checkudata(L, 1, META_PATCH)); @@ -384,6 +386,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 +733,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; @@ -948,7 +1057,7 @@ static int libd_getColormap(lua_State *L) // all was successful above, now we generate the colormap at last! - colormap = R_GetTranslationColormap(skinnum, color, GTC_CACHE); + colormap = R_GetTranslationColormap(skinnum, color, 0); LUA_PushUserdata(L, colormap, META_COLORMAP); // push as META_COLORMAP userdata, specifically for patches to use! return 1; } @@ -957,10 +1066,14 @@ static int libd_getStringColormap(lua_State *L) { INT32 flags = luaL_checkinteger(L, 1); UINT8* colormap = NULL; + UINT8* lua_colormap = NULL; HUDONLY colormap = V_GetStringColormap(flags & V_CHARCOLORMASK); if (colormap) { - LUA_PushUserdata(L, colormap, META_COLORMAP); // push as META_COLORMAP userdata, specifically for patches to use! + lua_colormap = Z_Malloc(256 * sizeof(UINT8), PU_LUA, NULL); + memcpy(lua_colormap, colormap, 256 * sizeof(UINT8)); + + LUA_PushUserdata(L, lua_colormap, META_COLORMAP); // push as META_COLORMAP userdata, specifically for patches to use! return 1; } return 0; @@ -1121,6 +1234,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 +1266,8 @@ static luaL_Reg lib_draw[] = { {NULL, NULL} }; +static int lib_draw_ref; + // // lib_hud // @@ -1186,28 +1302,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<= 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; } diff --git a/src/lua_libs.h b/src/lua_libs.h index 668eb99b0..8903834e8 100644 --- a/src/lua_libs.h +++ b/src/lua_libs.h @@ -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); diff --git a/src/lua_playerlib.c b/src/lua_playerlib.c index 06104ff2d..1c634da45 100644 --- a/src/lua_playerlib.c +++ b/src/lua_playerlib.c @@ -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")) diff --git a/src/lua_script.c b/src/lua_script.c index 6faff8729..a1376ca2e 100644 --- a/src/lua_script.c +++ b/src/lua_script.c @@ -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); } diff --git a/src/m_cheat.c b/src/m_cheat.c index c958bb4a4..ef896c991 100644 --- a/src/m_cheat.c +++ b/src/m_cheat.c @@ -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); diff --git a/src/m_menu.c b/src/m_menu.c index db2aa09c6..7a82fd8fb 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -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[] = @@ -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 @@ -4185,7 +4185,7 @@ static void M_DrawStaticBox(fixed_t x, fixed_t y, INT32 flags, fixed_t w, fixed_ if (staticalong > pw) // simplified for base LSSTATIC staticalong -= pw; - V_DrawCroppedPatch(x<data1; + INT32 ch = ev->key; // ESCAPE cancels; dummy out PAUSE if (ch != KEY_ESCAPE && ch != KEY_PAUSE) @@ -12878,7 +12878,7 @@ static void M_ChangecontrolResponse(event_t *ev) // keypad arrows are converted for the menu in cursor arrows // so use the event instead of ch case ev_keydown: - ch = ev->data1; + ch = ev->key; break; default: @@ -12929,7 +12929,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 diff --git a/src/m_misc.c b/src/m_misc.c index ac60d49c7..59783d5d3 100644 --- a/src/m_misc.c +++ b/src/m_misc.c @@ -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; +} diff --git a/src/m_misc.h b/src/m_misc.h index fc5430f01..82ccd58c7 100644 --- a/src/m_misc.h +++ b/src/m_misc.h @@ -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); diff --git a/src/p_enemy.c b/src/p_enemy.c index 6fa653c0e..e79baa679 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -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 @@ -3591,7 +3591,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) @@ -8259,7 +8259,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; @@ -8270,15 +8270,21 @@ 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? snew->angle = (actor->angle + snext->angle) >> 1; 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); diff --git a/src/p_inter.c b/src/p_inter.c index 6689165ea..d7f0fb8a2 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -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... @@ -470,14 +470,14 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) if (!(player->charability2 == CA2_MELEE && player->panim == PA_ABILITY2)) { fixed_t setmomz = -toucher->momz; // Store this, momz get changed by P_DoJump within P_DoBubbleBounce - + if (elementalpierce == 2) // Reset bubblewrap, part 1 P_DoBubbleBounce(player); toucher->momz = setmomz; if (elementalpierce == 2) // Reset bubblewrap, part 2 { boolean underwater = toucher->eflags & MFE_UNDERWATER; - + if (underwater) toucher->momz /= 2; toucher->momz -= (toucher->momz/(underwater ? 8 : 4)); // Cap the height! @@ -630,7 +630,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) // ***************************** // // Special Stage Token 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; @@ -1384,7 +1384,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; EV_DoElevator(LE_AXE, NULL, bridgeFall); @@ -1417,7 +1417,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); @@ -1611,7 +1611,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) if (special->tracer && !(special->tracer->flags2 & MF2_STRONGBOX)) macespin = true; - + if (macespin ? (player->powers[pw_ignorelatch] & (1<<15)) : (player->powers[pw_ignorelatch])) return; @@ -1679,7 +1679,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); @@ -1690,7 +1690,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); @@ -1698,7 +1698,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; @@ -1730,7 +1730,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); @@ -1783,7 +1783,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; @@ -1807,7 +1807,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 @@ -2549,7 +2549,7 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget if ((target->player->lives <= 1) && (netgame || multiplayer) && G_GametypeUsesCoopLives() && (cv_cooplives.value == 0)) ; - 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)) @@ -3469,7 +3469,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. @@ -3560,7 +3560,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; } @@ -3695,7 +3695,7 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da } else if (LUA_HookMobjDamage(target, inflictor, source, damage, damagetype)) 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; diff --git a/src/p_mobj.c b/src/p_mobj.c index 86c237f4a..a0a48ab6d 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -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; @@ -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) @@ -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; @@ -10392,6 +10394,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: @@ -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)<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); } @@ -3800,6 +3873,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; } @@ -3881,7 +3960,7 @@ static void P_ConvertBinaryMap(void) lines[i].args[4] |= TMSC_BACKTOFRONTCEILING; lines[i].special = 720; break; - + case 900: //Translucent wall (10%) case 901: //Translucent wall (20%) case 902: //Translucent wall (30%) @@ -4918,6 +4997,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; @@ -5129,10 +5210,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; @@ -5153,18 +5233,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++) @@ -5328,3 +5400,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); +} diff --git a/src/p_setup.h b/src/p_setup.h index 9fa70d516..c3c680fdd 100644 --- a/src/p_setup.h +++ b/src/p_setup.h @@ -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); diff --git a/src/p_slopes.c b/src/p_slopes.c index 4e93e4a45..bfca153a6 100644 --- a/src/p_slopes.c +++ b/src/p_slopes.c @@ -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 @@ -773,7 +820,7 @@ void P_SlopeLaunch(mobj_t *mo) mo->momx = slopemom.x; mo->momy = slopemom.y; mo->momz = slopemom.z/2; - + if (mo->player) mo->player->powers[pw_justlaunched] = 1; } diff --git a/src/p_slopes.h b/src/p_slopes.h index ae040ae56..43cd3edb0 100644 --- a/src/p_slopes.h +++ b/src/p_slopes.h @@ -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 { diff --git a/src/p_spec.c b/src/p_spec.c index 59353e835..415a3201f 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -1980,6 +1980,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 // @@ -1987,53 +2003,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) { @@ -2050,7 +2027,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; @@ -2062,7 +2039,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 || PRECIP_STORM || PRECIP_STORM_NOSTRIKES)) // Snow To Rain { precipmobj->flags = mobjinfo[MT_RAIN].flags; st = &states[mobjinfo[MT_RAIN].spawnstate]; @@ -2077,7 +2054,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; @@ -2102,7 +2079,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; @@ -2115,49 +2092,34 @@ 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; @@ -2165,14 +2127,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; @@ -7282,7 +7241,8 @@ void P_SpawnSpecials(boolean fromnetsave) } } - P_RunLevelLoadExecutors(); + if (!fromnetsave) + P_RunLevelLoadExecutors(); } /** Adds 3Dfloors as appropriate based on a common control linedef. diff --git a/src/p_user.c b/src/p_user.c index 048f2f1f9..9f3737501 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -777,7 +777,7 @@ void P_NightserizePlayer(player_t *player, INT32 nighttime) UINT8 oldmare, oldmarelap, oldmarebonuslap; // Bots can't be NiGHTSerized, silly!1 :P - if (player->bot) + if (player->bot == BOT_2PAI || player->bot == BOT_2PHUMAN) return; if (player->powers[pw_carry] != CR_NIGHTSMODE) @@ -969,6 +969,9 @@ pflags_t P_GetJumpFlags(player_t *player) // boolean P_PlayerInPain(player_t *player) { + // If the player doesn't have a mobj, it can't be in pain. + if (!player->mo) + return false; // no silly, sliding isn't pain if (!(player->pflags & PF_SLIDING) && player->mo->state == &states[player->mo->info->painstate] && player->powers[pw_flashing]) return true; @@ -1188,9 +1191,9 @@ void P_GivePlayerRings(player_t *player, INT32 num_rings) { if (!player) return; - - if (player->bot) - player = &players[consoleplayer]; + + if ((player->bot == BOT_2PAI || player->bot == BOT_2PHUMAN) && player->botleader) + player = player->botleader; if (!player->mo) return; @@ -1234,8 +1237,8 @@ void P_GivePlayerSpheres(player_t *player, INT32 num_spheres) if (!player) return; - if (player->bot) - player = &players[consoleplayer]; + if ((player->bot == BOT_2PAI || player->bot == BOT_2PHUMAN) && player->botleader) + player = player->botleader; if (!player->mo) return; @@ -1261,8 +1264,8 @@ void P_GivePlayerLives(player_t *player, INT32 numlives) if (!player) return; - if (player->bot) - player = &players[consoleplayer]; + if ((player->bot == BOT_2PAI || player->bot == BOT_2PHUMAN) && player->botleader) + player = player->botleader; if (gamestate == GS_LEVEL) { @@ -1367,8 +1370,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) @@ -5369,9 +5372,9 @@ static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd) // disabled because it seemed to disorient people and Z-targeting exists now /*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); }*/ } @@ -5390,7 +5393,7 @@ static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd) player->powers[pw_tailsfly] = tailsflytics + 1; // Set the fly timer player->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); @@ -5636,16 +5639,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; @@ -5661,17 +5658,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); } @@ -5977,22 +5972,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]) @@ -9522,11 +9501,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(); @@ -11499,6 +11478,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! { @@ -11506,7 +11488,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) { @@ -11650,7 +11632,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; @@ -11681,8 +11663,8 @@ void P_PlayerThink(player_t *player) INT32 i, total = 0, exiting = 0; 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; @@ -12622,8 +12604,8 @@ void P_PlayerAfterThink(player_t *player) player->mo->momy = tails->momy; 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; diff --git a/src/r_picformats.c b/src/r_picformats.c index 59b1d16c5..5c81d1e02 100644 --- a/src/r_picformats.c +++ b/src/r_picformats.c @@ -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, diff --git a/src/r_picformats.h b/src/r_picformats.h index b1bb35edd..c74f8a13a 100644 --- a/src/r_picformats.h +++ b/src/r_picformats.h @@ -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]; diff --git a/src/r_plane.c b/src/r_plane.c index 40170a141..50b76abde 100644 --- a/src/r_plane.c +++ b/src/r_plane.c @@ -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) @@ -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]); } } diff --git a/src/r_plane.h b/src/r_plane.h index bdad77930..862b95069 100644 --- a/src/r_plane.h +++ b/src/r_plane.h @@ -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; diff --git a/src/r_skins.c b/src/r_skins.c index b7eb24345..86c0bbc54 100644 --- a/src/r_skins.c +++ b/src/r_skins.c @@ -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. diff --git a/src/r_splats.c b/src/r_splats.c index 4783fb640..c554e9b1f 100644 --- a/src/r_splats.c +++ b/src/r_splats.c @@ -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)); } diff --git a/src/r_splats.h b/src/r_splats.h index cab3d63b6..7e31406d1 100644 --- a/src/r_splats.h +++ b/src/r_splats.h @@ -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 diff --git a/src/r_textures.c b/src/r_textures.c index d5da69018..793e5237f 100644 --- a/src/r_textures.c +++ b/src/r_textures.c @@ -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) diff --git a/src/r_things.c b/src/r_things.c index 0283712b8..ea57e4086 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -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 diff --git a/src/r_things.h b/src/r_things.h index 9315b36e9..79dc80d94 100644 --- a/src/r_things.h +++ b/src/r_things.h @@ -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; diff --git a/src/sdl/i_system.c b/src/sdl/i_system.c index d68e3e435..2ec28ebc8 100644 --- a/src/sdl/i_system.c +++ b/src/sdl/i_system.c @@ -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= 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< 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 +800,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 +817,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 +844,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 +867,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 +885,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 +1089,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); } diff --git a/src/sdl/mixer_sound.c b/src/sdl/mixer_sound.c index 2f1a87266..35a79acc0 100644 --- a/src/sdl/mixer_sound.c +++ b/src/sdl/mixer_sound.c @@ -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 #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) { diff --git a/src/st_stuff.c b/src/st_stuff.c index af14118e3..784666ad4 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -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); } // @@ -2732,7 +2733,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)) diff --git a/src/v_video.c b/src/v_video.c index de05df2d5..c39938544 100644 --- a/src/v_video.c +++ b/src/v_video.c @@ -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<> 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<topoffset<leftoffset<topoffset<>= 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) < 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< 0) { - dest += FixedInt(FixedMul((topdelta-sy)<>FRACBITS) < column->length && (((ofs>>FRACBITS) - sy) + topdelta) < h; ofs += rowfrac) + for (; dest < deststop && (ofs>>FRACBITS) < column->length && ((ofs - sy) + (topdelta<= screens[scrn&V_PARAMMASK]) // don't draw off the top of the screen (CRASH PREVENTION) *dest = patchdrawfunc(dest, source, ofs); diff --git a/src/v_video.h b/src/v_video.h index 7184e799e..c10ab22ce 100644 --- a/src/v_video.h +++ b/src/v_video.h @@ -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); diff --git a/src/version.h b/src/version.h index 4470fbd6e..28fc71c36 100644 --- a/src/version.h +++ b/src/version.h @@ -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 diff --git a/src/w_wad.c b/src/w_wad.c index cbff5c67b..3ff301117 100644 --- a/src/w_wad.c +++ b/src/w_wad.c @@ -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 @@ -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); } @@ -421,6 +427,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 +609,7 @@ static lumpinfo_t* ResGetLumpsZip (FILE* handle, UINT16* nlmp) lump_p->position = zentry.offset; // NOT ACCURATE YET: we still need to read the local entry to find our true position lump_p->disksize = zentry.compsize; + lump_p->diskpath = NULL; lump_p->size = zentry.size; fullname = malloc(zentry.namelen + 1); @@ -679,6 +687,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 +810,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 // @@ -760,7 +889,7 @@ UINT16 W_InitFile(const char *filename, boolean mainfile, boolean startup) // see PutFileNeeded in d_netfil.c if ((important = !important)) { - packetsize = packetsizetally + nameonlylength(filename) + 22; + packetsize = packetsizetally + nameonlylength(filename) + FILENEEDEDSIZE; if (packetsize > MAXFILENEEDED*sizeof(UINT8)) { @@ -788,7 +917,7 @@ UINT16 W_InitFile(const char *filename, boolean mainfile, boolean startup) { CONS_Alert(CONS_ERROR, M_GetText("%s is already loaded\n"), filename); if (important) - packetsizetally -= nameonlylength(filename) + 22; + packetsizetally -= nameonlylength(filename) + FILENEEDEDSIZE; if (handle) fclose(handle); return W_InitFileError(filename, false); @@ -831,9 +960,11 @@ UINT16 W_InitFile(const char *filename, boolean mainfile, boolean startup) // wadfile = Z_Malloc(sizeof (*wadfile), PU_STATIC, NULL); wadfile->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); @@ -856,14 +987,8 @@ UINT16 W_InitFile(const char *filename, boolean mainfile, boolean startup) 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 +1014,180 @@ 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. + if ((important = !important)) + { + size_t packetsize = packetsizetally + strlen(path) + FILENEEDEDSIZE; + + if (packetsize > MAXFILENEEDED*sizeof(UINT8)) + { + CONS_Alert(CONS_ERROR, M_GetText("Maximum wad files reached\n")); + refreshdirmenu |= REFRESHDIR_MAX; + return W_InitFileError(path, startup); + } + + packetsizetally = packetsize; + } + + // Remove path delimiters. + p = path + (strlen(path) - 1); + + while (*p == '\\' || *p == '/' || *p == ':') + { + p--; + if (p < path) + { + CONS_Alert(CONS_ERROR, M_GetText("Path %s is invalid\n"), path); + return W_InitFileError(path, startup); + } + } + p++; + + // Allocate the new path name. + i = (p - path) + 1; + fn = ZZ_Alloc(i); + strlcpy(fn, path, i); + + // Don't add an empty path. + if (M_IsStringEmpty(fn)) + { + CONS_Alert(CONS_ERROR, M_GetText("Folder name is empty\n")); + Z_Free(fn); + + if (startup) + return W_InitFileError("A folder", true); + else + return W_InitFileError("a folder", false); + } + + // Check if the path is valid. + stat = W_IsPathToFolderValid(fn); + + if (stat != 1) + { + if (stat == 0) + CONS_Alert(CONS_ERROR, M_GetText("Path %s is invalid\n"), fn); + else if (stat < 0) + { +#ifndef AVOID_ERRNO + CONS_Alert(CONS_ERROR, M_GetText("Could not stat %s: %s\n"), fn, strerror(direrror)); +#else + CONS_Alert(CONS_ERROR, M_GetText("Could not stat %s\n"), fn); +#endif + } + + Z_Free(fn); + return W_InitFileError(path, startup); + } + + // Get the full path for this folder. + fullpath = W_GetFullFolderPath(fn); + if (fullpath == NULL) + { + CONS_Alert(CONS_ERROR, M_GetText("Path %s is invalid\n"), fn); + Z_Free(fn); + return W_InitFileError(path, startup); + } + + // Check if the folder is already added. + for (i = 0; i < numwadfiles; i++) + { + if (wadfiles[i]->type != RET_FOLDER) + continue; + + if (samepaths(wadfiles[i]->path, fullpath) > 0) + { + CONS_Alert(CONS_ERROR, M_GetText("%s is already loaded\n"), path); + if (important) + packetsizetally -= strlen(path) + FILENEEDEDSIZE; + Z_Free(fn); + Z_Free(fullpath); + return W_InitFileError(path, false); + } + } + + lumpinfo = ResGetLumpsFolder(fullpath, &numlumps, &foldercount); + + if (lumpinfo == NULL) + { + if (!numlumps) + CONS_Alert(CONS_ERROR, M_GetText("Folder %s is empty\n"), path); + else if (numlumps == UINT16_MAX) + CONS_Alert(CONS_ERROR, M_GetText("Folder %s contains too many files\n"), path); + else + CONS_Alert(CONS_ERROR, M_GetText("Unknown error enumerating files from folder %s\n"), path); + + Z_Free(fn); + Z_Free(fullpath); + + return W_InitFileError(path, startup); + } + + if (important && !mainfile) + G_SetGameModified(true); + + wadfile = Z_Malloc(sizeof (*wadfile), PU_STATIC, NULL); + wadfile->filename = fn; + wadfile->path = fullpath; + wadfile->type = RET_FOLDER; + wadfile->handle = NULL; + wadfile->numlumps = numlumps; + wadfile->foldercount = foldercount; + wadfile->lumpinfo = lumpinfo; + wadfile->important = important; + + // Irrelevant. + wadfile->filesize = 0; + memset(wadfile->md5sum, 0x00, 16); + + Z_Calloc(numlumps * sizeof (*wadfile->lumpcache), PU_STATIC, &wadfile->lumpcache); + Z_Calloc(numlumps * sizeof (*wadfile->patchcache), PU_STATIC, &wadfile->patchcache); + + CONS_Printf(M_GetText("Added folder %s (%u files, %u folders)\n"), fn, numlumps, foldercount); + wadfiles[numwadfiles] = wadfile; + numwadfiles++; + + W_ReadFileShaders(wadfile); + W_LoadDehackedLumpsPK3(numwadfiles - 1, mainfile); + W_InvalidateLumpnumCache(); + + return wadfile->numlumps; +} + /** Tries to load a series of files. * All files are wads unless they have an extension of ".soc" or ".lua". * @@ -900,11 +1199,18 @@ UINT16 W_InitFile(const char *filename, boolean mainfile, boolean startup) */ void W_InitMultipleFiles(char **filenames) { - // will be realloced as lumps are added for (; *filenames; filenames++) { - //CONS_Debug(DBG_SETUP, "Loading %s\n", *filenames); - W_InitFile(*filenames, numwadfiles < mainwads, true); + const char *fn = (*filenames); + char pathsep = fn[strlen(fn) - 1]; + boolean mainfile = (numwadfiles < mainwads); + + //CONS_Debug(DBG_SETUP, "Loading %s\n", fn); + + if (pathsep == '\\' || pathsep == '/') + W_InitFolder(fn, mainfile, true); + else + W_InitFile(fn, mainfile, true); } } @@ -1178,7 +1484,7 @@ lumpnum_t W_CheckNumForMap(const char *name) if (!strncmp(name, (wadfiles[i]->lumpinfo + lumpNum)->name, 8)) 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 +1582,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. @@ -1297,7 +1640,7 @@ size_t W_LumpLength(lumpnum_t lumpnum) // boolean W_IsLumpWad(lumpnum_t lumpnum) { - if (wadfiles[WADFILENUM(lumpnum)]->type == RET_PK3) + if (W_FileHasFolders(wadfiles[WADFILENUM(lumpnum)])) { const char *lumpfullName = (wadfiles[WADFILENUM(lumpnum)]->lumpinfo + LUMPNUM(lumpnum))->fullname; @@ -1315,7 +1658,7 @@ boolean W_IsLumpWad(lumpnum_t lumpnum) // 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; @@ -1365,17 +1708,55 @@ void zerr(int ret) */ size_t W_ReadLumpHeaderPwad(UINT16 wad, UINT16 lump, void *dest, size_t size, size_t offset) { - size_t 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 || lumpsizetype == RET_FOLDER) + fclose(handle); return 0; + } // zero size means read all the lump if (!size || size+offset > lumpsize) @@ -1383,24 +1764,22 @@ size_t W_ReadLumpHeaderPwad(UINT16 wad, UINT16 lump, void *dest, size_t size, si // Let's get the raw lump data. // 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 diff --git a/src/w_wad.h b/src/w_wad.h index 130967712..949bab9fe 100644 --- a/src/w_wad.h +++ b/src/w_wad.h @@ -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; @@ -109,17 +110,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,7 +130,7 @@ 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; @@ -141,10 +144,17 @@ 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); +#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); diff --git a/src/win32/win_main.c b/src/win32/win_main.c index e1d90881b..a5ebf3211 100644 --- a/src/win32/win_main.c +++ b/src/win32/win_main.c @@ -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; diff --git a/src/win32/win_sys.c b/src/win32/win_sys.c index da0d5b47e..ff443935f 100644 --- a/src/win32/win_sys.c +++ b/src/win32/win_sys.c @@ -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; diff --git a/src/y_inter.c b/src/y_inter.c index 6d876d7bd..afc75c8b1 100644 --- a/src/y_inter.c +++ b/src/y_inter.c @@ -212,7 +212,7 @@ static void Y_IntermissionTokenDrawer(void) calc = (lowy - y)*2; if (calc > 0) - V_DrawCroppedPatch(32<width, calc); + V_DrawCroppedPatch(32<width<